/** * @RDE_HEADER@ * Interface-Implementation of EsriDictionaryProcessorMil2525D * $Id$ * $HeadURL$ * $Author$ */ // Own #include "esri_dictionary_processor_mil2525d.h" // ESRI // Qt #include namespace AdvancedSymbology { EsriDictionaryProcessorMil2525D::EsriDictionaryProcessorMil2525D() : BaseClass(AdvancedSymbology::SymbologyType::MIL2525D) { TRACE_LOG(m_logger) << LOGFUNCTION << " START" << " ThreadId=" << QThread::currentThreadId(); TRACE_LOG(m_logger) << LOGFUNCTION << " END"; } EsriDictionaryProcessorMil2525D::~EsriDictionaryProcessorMil2525D() { TRACE_LOG(m_logger) << LOGFUNCTION << " START"; this->cancel(); this->waitForFinished(); TRACE_LOG(m_logger) << LOGFUNCTION << " END"; } void EsriDictionaryProcessorMil2525D::cancel() { BaseClass::cancel(); // add specific here: } void EsriDictionaryProcessorMil2525D::waitForFinished() { BaseClass::waitForFinished(); // add specific here: } bool EsriDictionaryProcessorMil2525D::searchResultIsValid(const QHash &key8LookupTable, const Esri::ArcGISRuntime::SymbolStyleSearchResult &resultItem, QString *toBeRemovedFromName) { const QString &originalKey = resultItem.key(); TRACE_LOG(m_logger) << LOGFUNCTION << " originalKey='" << originalKey << "'"; // check symbolClass: (to reduce empty keys, check symboClass first) int symbolClass = resultItem.symbolClass().toInt(); if ((symbolClass == 6) || // symbolClass ( 6) == TextSymbol (symbolClass == 10) // symbolClass (10) == MaplexLabelPlacement ) { DEBUG_LOG(m_logger) << LOGFUNCTION << " symbolClass does not match " << " originalKey='" << originalKey << "'" << " name='" << resultItem.name() << "'"; return false; } // // check if empty: [V100.0, ! V100.1] // #ifdef CHECK_HAS_EMPTY_KEY if (originalKey.isEmpty()) { DEBUG_LOG(m_logger) << LOGFUNCTION << " empty key, " << " name='" << resultItem.name() << "'"; return false; } #endif // CHECK_HAS_EMPTY_KEY // // size (25270100 || 25270100_4) [V100.0, V100.1] // const int keySize = originalKey.size(); if (!((keySize == 8) || (keySize == 10))) { DEBUG_LOG(m_logger) << LOGFUNCTION << " keySize does not match," << " originalKey='" << originalKey << "'" << " name='" << resultItem.name() << "'"; return false; } // // isFrame (key like '0_110_1c') [V100.0, V100.1] // if (originalKey.at(1) == QLatin1Char('_')) { DEBUG_LOG(m_logger) << LOGFUNCTION << " isFrame," << " originalKey='" << originalKey << "'" << " name='" << resultItem.name() << "'"; return false; } // // isCharlie (key like '46120203_C') [V100.0, V100.1] // if ((keySize == 10) && (originalKey.rightRef(2).compare(QLatin1String("_C")) == 0)) { DEBUG_LOG(m_logger) << LOGFUNCTION << " isCharlie," << " originalKey='" << originalKey << "'" << " name='" << resultItem.name() << "'"; return false; } // // reduce key to base (e.g. 25270100_4 -> 25270100) [V100.0, V100.1] // const QString &key8 = originalKey.left(8); bool ok = false; key8.toInt(&ok); // check for being an integer if (!ok) { DEBUG_LOG(m_logger) << LOGFUNCTION << " chars, " << " originalKey='" << originalKey << "'" << " name='" << resultItem.name() << "'"; return false; } // V100.0: For these the key exists twice! (SymbolClass '3' and '5') // -> prefer item with SymbolClass '3' static const QSet listOfKnownDoubleEntries({QStringLiteral("25140103"), QStringLiteral("25140606"), QStringLiteral("25140607"), QStringLiteral("25151407"), QStringLiteral("25151408"), QStringLiteral("25140104"), QStringLiteral("25140102"), QStringLiteral("25150101"), QStringLiteral("25150102"), QStringLiteral("25150103"), QStringLiteral("25150104"), QStringLiteral("25151802"), QStringLiteral("25200500"), QStringLiteral("25200600"), QStringLiteral("25241403"), QStringLiteral("25270703"), QStringLiteral("25270704"), QStringLiteral("25200400"), QStringLiteral("25272100"), }); if (listOfKnownDoubleEntries.contains(key8)) { const QString &symClass = resultItem.symbolClass(); if (!symClass.compare(QLatin1String("3"))) { DEBUG_LOG(m_logger) << LOGFUNCTION << " listOfKnownDoubleEntries" << " originalKey='" << originalKey << "'" << " name='" << resultItem.name() << "'" << " symbolClass='" << symClass << "'"; return false; // use other/proper with better SymbolClass instead } } // // use key8 instead of key10 [V100.0, V100.1] // if (keySize == 10) { // // there are entries with postfix (_1) and AND proper key8 // (e.g. '25271800_3' ; ... ; and proper 25271800: // bool useOtherKey8 = key8LookupTable.contains(key8); if (useOtherKey8) { DEBUG_LOG(m_logger) << LOGFUNCTION << " useOtherKey8_a" << " originalKey='" << originalKey << "'" << " name='" << resultItem.name() << "'"; return false; // use other/proper key8 item instead } // // there are entries with postfix (_1) and AND NO proper key8 // (e.g. '10120100_0' ; '10120100_1' ; '10120100_2' ; '10120100_3' ; but no '10120100' // 10120100 = Movement And Maneuver ; Air Assult with Organic Lift - FullFrame // // Most of the times these are the FULL_FRAME symbols. (except "Maneuver Lines : Line of Contact" = 25140200_6) // // use neutral item instead // const QString &name = resultItem.name(); if (name.contains(QStringLiteral("Neutral"))) { if (toBeRemovedFromName) *toBeRemovedFromName = QStringLiteral("Neutral"); } else { DEBUG_LOG(m_logger) << LOGFUNCTION << " useOtherKey8_bb" << " originalKey='" << originalKey << "'" << " name='" << resultItem.name() << "'"; return false; // wait for Neutral item } } // if (keySize == 10) return true; } bool EsriDictionaryProcessorMil2525D::processBaseSymbolCodeToPropertyTable() { TRACE_LOG(m_logger) << LOGFUNCTION << " START"; if (m_searchResultList.isEmpty()) { ERROR_LOG(m_logger) << LOGFUNCTION << " m_searchResultList.isEmpty"; return false; } QHash key8LookupTable; for (int i = 0; i < m_searchResultList.size(); ++i) { const Esri::ArcGISRuntime::SymbolStyleSearchResult &resultItem = m_searchResultList.at(i); if (resultItem.key().size() == 8) key8LookupTable[resultItem.key()] = i; } int resultItemCounter = 0; int gctStringEmptyCounter = 0; for (const Esri::ArcGISRuntime::SymbolStyleSearchResult &resultItem : qAsConst(m_searchResultList)) { // canceled? // 2017-09-07, Qt5.9, N. Thoden // A default initialized QFuture seems to have an inconsistent state: // -> isStarted=1 <---!!! // -> isRunning=0 // -> isCanceled=1 <---!!! // so check isCanceled() && isRunning() // 2017-10-09, Qt5.9.1, N.Thoden // Problöem still arises, so perform at a least a couple: if (m_baseSymbolCodeToSymbolPropertyTableWatcher.isCanceled() && m_baseSymbolCodeToSymbolPropertyTableWatcher.isRunning() && (resultItemCounter >= 10)) { ERROR_LOG(m_logger) << LOGFUNCTION << " m_baseSymbolCodeToSymbolPropertyTableWatcher.isCanceled"; ERROR_LOG(m_logger) << LOGFUNCTION << " m_baseSymbolCodeToSymbolPropertyTableWatcher.isStarted=" << m_baseSymbolCodeToSymbolPropertyTableWatcher.isStarted(); ERROR_LOG(m_logger) << LOGFUNCTION << " m_baseSymbolCodeToSymbolPropertyTableWatcher.isRunning=" << m_baseSymbolCodeToSymbolPropertyTableWatcher.isRunning(); ERROR_LOG(m_logger) << LOGFUNCTION << " m_baseSymbolCodeToSymbolPropertyTableWatcher.isCanceled=" << m_baseSymbolCodeToSymbolPropertyTableWatcher.isCanceled(); ERROR_LOG(m_logger) << LOGFUNCTION << " m_baseSymbolCodeToSymbolPropertyTableWatcher.isFinished=" << m_baseSymbolCodeToSymbolPropertyTableWatcher.isFinished(); return false; } if (resultItemCounter == 0) INFO_LOG(m_logger) << LOGFUNCTION << " counter=" << resultItemCounter; ++resultItemCounter; if ((resultItemCounter % 500) == 0) INFO_LOG(m_logger) << LOGFUNCTION << " counter=" << resultItemCounter; // INFO_LOG(m_logger) << LOGFUNCTION << " resultItem.key ='" << resultItem.key() << "'"; // INFO_LOG(m_logger) << LOGFUNCTION << " resultItem.name ='" << resultItem.name() << "'"; // INFO_LOG(m_logger) << LOGFUNCTION << " resultItem.category ='" << resultItem.category() << "'"; // INFO_LOG(m_logger) << LOGFUNCTION << " resultItem.symbolClass ='" << resultItem.symbolClass() << "'"; // INFO_LOG(m_logger) << LOGFUNCTION << " resultItem.tags ='" << resultItem.tags().join(QLatin1String(";")) << "'"; bool isValid = searchResultIsValid(key8LookupTable, resultItem); if (!isValid) { DEBUG_LOG(m_logger) << LOGFUNCTION << " continue:: not valid " << " key='" << resultItem.key() << "'" << " name='" << resultItem.name() << "'"; continue; } const QString &originalKey = resultItem.key(); const QString &key8 = originalKey.left(8); if (m_baseSymbolCodeToSymbolPropertyTable.contains(key8)) { FATAL_LOG(m_logger) << LOGFUNCTION << " continue:: already EXISTS!!!" << " key8='" << key8 << "'" << " originalKey='" << originalKey << "'"; continue; } SymbolProperties symProps; symProps.setKey(key8); symProps.setName(resultItem.name()); symProps.setCategory(resultItem.category()); symProps.setSymbolClass(resultItem.symbolClass()); symProps.setTags(resultItem.tags()); symProps.setOriginalKey(originalKey); symProps.setSidc(SidcCodec::encodeBaseSymbolCode(m_baseSymbolCodeToSymbolPropertyTable.symbologyType(), key8)); // retrieve GeometryType const QString cat = resultItem.category(); const QVector &slCategory = cat.splitRef(QLatin1Char(':')); if (!slCategory.isEmpty()) { const QStringRef &geometryStr = slCategory.last().trimmed(); bool isPoint = geometryStr.compare(QLatin1String("Point"), Qt::CaseInsensitive) == 0; bool isMainIcon = geometryStr.compare(QLatin1String("Main Icon"), Qt::CaseInsensitive) == 0; bool isLine = geometryStr.compare(QLatin1String("Line"), Qt::CaseInsensitive) == 0; bool isArea = geometryStr.compare(QLatin1String("Area"), Qt::CaseInsensitive) == 0; if (isPoint || isMainIcon) symProps.setGeometryType(GeometryType::Point); else if (isLine) symProps.setGeometryType(GeometryType::Polyline); else if (isArea) symProps.setGeometryType(GeometryType::Polygon); } DEBUG_LOG(m_logger) << LOGFUNCTION << " XXXXXXXXX GeometryType:" << " key8='" << key8 << "'" << " originalKey='" << originalKey << "'" << "' slLast='" << slCategory.last().toString() << "'" << " geoType= " << symProps.geometryType(); // check for gct_-String: if (symProps.geometryType() == GeometryType::Polyline || symProps.geometryType() == GeometryType::Polygon) { const QString gctString = symProps.gctString(); if (gctString.isEmpty()) { DEBUG_LOG(m_logger) << LOGFUNCTION << " gctString empty: key8='" << key8 << "'" << " geoType= " << symProps.geometryType() << " tags=" << resultItem.tags().join(QLatin1String(";")); ++gctStringEmptyCounter; } } m_baseSymbolCodeToSymbolPropertyTable[key8] = symProps; // For modelNG m_searchResultListValid.append(resultItem); } // for m_baseSymbolCodeToSymbolPropertyTableFilled = true; NOTICE_LOG(m_logger) << LOGFUNCTION << " ##### resultItemCounter=" << resultItemCounter << " m_baseSymbolCodeToSymbolPropertyTable.size=" << m_baseSymbolCodeToSymbolPropertyTable.size() << " gctStringEmptyCounter=" << gctStringEmptyCounter << " threadId: " << QThread::currentThreadId(); emit baseSymbolCodeToPropertyTableDone(); checkIfAllAreDone(); // will potentially emit signal 'allIsDone' TRACE_LOG(m_logger) << LOGFUNCTION << " END"; return true; } bool EsriDictionaryProcessorMil2525D::processModifierTable() { TRACE_LOG(m_logger) << LOGFUNCTION << " START"; if (m_searchResultList.isEmpty()) return false; int counter = 0; for (const Esri::ArcGISRuntime::SymbolStyleSearchResult &resultItem : qAsConst(m_searchResultList)) { ++counter; // canceled? if (m_modifierTableWatcher.isCanceled() && m_modifierTableWatcher.isRunning()) { ERROR_LOG(m_logger) << LOGFUNCTION << " m_modifierTableWatcher.isCanceled"; ERROR_LOG(m_logger) << LOGFUNCTION << " m_modifierTableWatcher.isStarted=" << m_modifierTableWatcher.isStarted(); ERROR_LOG(m_logger) << LOGFUNCTION << " m_modifierTableWatcher.isRunning=" << m_modifierTableWatcher.isRunning(); ERROR_LOG(m_logger) << LOGFUNCTION << " m_modifierTableWatcher.isCanceled=" << m_modifierTableWatcher.isCanceled(); ERROR_LOG(m_logger) << LOGFUNCTION << " m_modifierTableWatcher.isFinished=" << m_modifierTableWatcher.isFinished(); return false; } const QString &originalKey = resultItem.key(); // INFO_LOG(m_logger) << LOGFUNCTION << " resultItem.key ='" << originalKey << "'"; // INFO_LOG(m_logger) << LOGFUNCTION << " resultItem.name ='" << resultItem.name() << "'"; // INFO_LOG(m_logger) << LOGFUNCTION << " resultItem.category ='" << resultItem.category() << "'"; // INFO_LOG(m_logger) << LOGFUNCTION << " resultItem.symbolClass ='" << resultItem.symbolClass() << "'"; // INFO_LOG(m_logger) << LOGFUNCTION << " resultItem.tags ='" << resultItem.tags().join(QLatin1String(";")) << "'"; if (originalKey.length() == 5) // ToDo: check contraint? { bool isDigit = false; originalKey.toInt(&isDigit); // check for being an integer if (isDigit) { const QString &resultItemName = resultItem.name(); // store result item name locally to guaranty following splitRef const QVector &sl = resultItemName.splitRef(QLatin1String(" : ")); // otherwise ("resultItem.name().splitRef(...)") unpredictable results are possible // log multiple keys: if (m_modifierTable.contains(originalKey)) ERROR_LOG(m_logger) << LOGFUNCTION << " originalKey already in cont: key='" << originalKey << "'" << " resultItem.name() ='" << resultItem.name() << "'"; ModifierData modData; modData.m_modifierKey = originalKey; SidcDefinitions::SymbolSet symbolSetEnum = static_cast(originalKey.midRef(0, 2).toUInt()); if (!SidcDefinitions::symbolSets().contains(symbolSetEnum)) { ERROR_LOG(m_logger) << LOGFUNCTION << " Unknown symbol set code found, symbol set code = '" << symbolSetEnum << "'" << " originalKey = '" << originalKey << "'"; symbolSetEnum = SidcDefinitions::SymbolSet::Unknown; } modData.m_symbolSet = symbolSetEnum; modData.m_modifierSector = originalKey.midRef(4, 1).toUInt(); modData.m_modifierValue = originalKey.midRef(2, 2).toUInt(); modData.m_modifierName = (sl.size() == 2) ? sl.last().toString() : resultItem.name(); m_modifierTable[originalKey] = modData; DEBUG_LOG(m_logger) << LOGFUNCTION << " originalKey ='" << originalKey << "'" << " sector = " << modData.m_modifierSector << " modifierName ='" << modData.m_modifierName << "'"; } } } // for m_modifierTableFilled = true; DEBUG_LOG(m_logger) << LOGFUNCTION << " ##### counter=" << counter << " m_modifierTable.size=" << m_modifierTable.size() << " threadId: " << QThread::currentThreadId(); emit modifierTableDone(); checkIfAllAreDone(); // will potentially emit signal 'allIsDone' TRACE_LOG(m_logger) << LOGFUNCTION << " END"; return true; } } // namespace AdvancedSymbology