Files
qt5-legatus-legacy/Lts/Viewer/SituationMap/SymbologyImpl/esri_dictionary_processor_app6d.cpp
T
2026-08-13 18:33:10 +02:00

470 lines
18 KiB
C++
Executable File

/**
**
** @RDE_HEADER@
** Interface-Implementation of EsriDictionaryProcessorApp6d
** $Id$
** $HeadURL$
** $Author: turla
**
** -----------------------------------------------------------------------------------------------
**
** Hardware-Environment: Intel-PC
** Software-Environment: Windows 7, Qt 5.4. ArcGIS 10.2.5
**
** Language ........: C++ 11
**
** -----------------------------------------------------------------------------------------------
**
** Author ...........: Jörg Turla, SPD G, Tel. 3132
**
** -----------------------------------------------------------------------------------------------
**
** Notes .........:
**
** 09.05.2018, JT : First edition for use with Qt5
**
** -----------------------------------------------------------------------------------------------
*/
// Own
#include "esri_dictionary_processor_app6d.h"
// ESRI
// Qt
#include <QThread>
#include <arcgis/arcgisversion.h> // This file is created by RME, not ESRI
namespace AdvancedSymbology
{
EsriDictionaryProcessorApp6D::EsriDictionaryProcessorApp6D()
: BaseClass(AdvancedSymbology::SymbologyType::APP6D)
{
TRACE_LOG(m_logger) << LOGFUNCTION << " START" << " ThreadId=" << QThread::currentThreadId();
TRACE_LOG(m_logger) << LOGFUNCTION << " END";
}
EsriDictionaryProcessorApp6D::~EsriDictionaryProcessorApp6D()
{
TRACE_LOG(m_logger) << LOGFUNCTION << " START";
this->cancel();
this->waitForFinished();
TRACE_LOG(m_logger) << LOGFUNCTION << " END";
}
void EsriDictionaryProcessorApp6D::cancel()
{
BaseClass::cancel();
// add specific here:
}
void EsriDictionaryProcessorApp6D::waitForFinished()
{
BaseClass::waitForFinished();
// add specific here:
}
bool EsriDictionaryProcessorApp6D::searchResultIsValid(const QHash<QString, int> &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;
}
//
// 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;
}
//
// 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<QString> 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 EsriDictionaryProcessorApp6D::processBaseSymbolCodeToPropertyTable()
{
TRACE_LOG(m_logger) << LOGFUNCTION << " START";
if (m_searchResultList.isEmpty())
{
ERROR_LOG(m_logger) << LOGFUNCTION << " m_searchResultList.isEmpty";
return false;
}
QHash<QString, int> 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
// Problem 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<QStringRef> &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;
INFO_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 EsriDictionaryProcessorApp6D::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<QStringRef> &sl = resultItemName.splitRef(QLatin1String(" : ")); // otherwise ("resultItem.name().splitRef(...)") unpredictable results are possible
// log multiple keys:
if (m_modifierTable.contains(originalKey))
{
WARNING_LOG(m_logger) << LOGFUNCTION << " originalKey already in cont: key='" << originalKey << "'" << " resultItem.name() ='" << resultItem.name() << "'";
}
ModifierData modData;
modData.m_modifierKey = originalKey;
QStringRef symbolSetStringRef = originalKey.midRef(0, 2);
SidcDefinitions::SymbolSet symbolSetEnum = static_cast<SidcDefinitions::SymbolSet>(symbolSetStringRef.toUInt());
if (!SidcDefinitions::symbolSets().contains(symbolSetEnum))
{
ERROR_LOG(m_logger) << LOGFUNCTION << " Unknown symbol set code found, symbol set code = '" << symbolSetStringRef.toString() << "'"
<< " 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