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

2520 lines
91 KiB
C++
Executable File
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* @RDE_HEADER@
* Interface-Implementation of SymbolDictionaryImpl
* $Id$
* $HeadURL$
* $Author$
*/
// Own
#include "symbol_dictionary_impl.h"
#include "symbol_dictionary.h" // Interface (enums)
#include "symbol_extension_renderer.h"
#include "esri_dictionary_processor_mil2525d.h"
#include "esri_dictionary_processor_app6.h"
#include "esri_dictionary_processor_app6d.h"
#include "sidc_builder_base.h"
#include "base_symbol_model.h"
#include <Common/resource_path.h>
#include <Common/situation_map_logging.h>
#include <Symbology/symbol_properties.h>
#include <SymbologyXML/symbol.h>
#include <SymbologyXML/symbol_table.h>
#include <SymbologyXML/symbol_reader.h>
#include <SymbologyXML/pixmap_symbol_cache.h>
#include <SymbologyXML/xml_symbol_codec.h>
// ESRI
#include <arcgis/TaskWatcher.h>
#include <arcgis/Symbol.h>
#include <arcgis/SymbolStyleSearchParameters.h>
#include <arcgis/SymbolStyleSearchResultListModel.h>
#include <arcgis/SymbolStyleSearchResult.h>
# include <arcgis/arcgisversion.h> // This file is created by RME, not ESRI
#if ACRGIS_VERSION >= 0x640100 // 100.1.0 / Update 1
# define SYM_PROTECTION_AREAS_BECOMES_LINE
#endif
// Qt
#include <QHash>
#include <QStringList>
#include <QStandardItemModel>
#include <QTreeView>
#include <QHBoxLayout>
#include <QDialog>
#include <QRegExp>
#include <QDir>
#include <QThread>
#include <QPainter>
#include <QTime>
#include <QtConcurrent>
#include <QFuture>
#include <sstream>
#include <type_traits>
// findSymbol and createSwatch :
// Lucas Danzinger: these are both async, and will both run in worker threads.
// https://earlyadopter.esri.com/project/forum/thread.html.... - Title: 'SymbolDictionary - createSwatch'
// : findSymbol and createSwatch
namespace AdvancedSymbology
{
// make sure, that both enums have identical values assigned and a static_cast works fine:
static_assert(static_cast<int>(AdvancedSymbology::LoadStatus::Loaded) == static_cast<int>(Esri::ArcGISRuntime::LoadStatus::Loaded), "LoadStatus mismatch");
static_assert(static_cast<int>(AdvancedSymbology::LoadStatus::Loading) == static_cast<int>(Esri::ArcGISRuntime::LoadStatus::Loading), "LoadStatus mismatch");
static_assert(static_cast<int>(AdvancedSymbology::LoadStatus::FailedToLoad) == static_cast<int>(Esri::ArcGISRuntime::LoadStatus::FailedToLoad), "LoadStatus mismatch");
static_assert(static_cast<int>(AdvancedSymbology::LoadStatus::NotLoaded) == static_cast<int>(Esri::ArcGISRuntime::LoadStatus::NotLoaded), "LoadStatus mismatch");
static_assert(static_cast<int>(AdvancedSymbology::LoadStatus::Unknown) == static_cast<int>(Esri::ArcGISRuntime::LoadStatus::Unknown), "LoadStatus mismatch");
} // namespace AdvancedSymbology
namespace AdvancedSymbology
{
QStringList listOfEtsPointSidcs_Internal()
{
QStringList sidcs;
sidcs += SidcCodec::encodeCivilEts("PersFueAllg");
sidcs += SidcCodec::encodeCivilEts("Polizei_Person");
sidcs += SidcCodec::encodeCivilEts("Pers_FW_BerFue");
return sidcs;
}
QStringList listOfPointSidcs_Internal()
{
QStringList sidcs;
sidcs += SidcCodec::encodeComplete(SymbologyType::MIL2525D, "10011500002102000000"); // mine_impl
sidcs += SidcCodec::encodeComplete(SymbologyType::MIL2525D, "10012500002108000000"); // single_fire_impl
sidcs += SidcCodec::encodeComplete(SymbologyType::MIL2525D, "10012500002707050000"); // 25270705 -> Protection Areas : Minefield : Dummy
// SymbolSet 01 == air
sidcs += SidcCodec::encodeComplete(SymbologyType::MIL2525D, "10030100001101000000"); // differs in APP6(D)
sidcs += SidcCodec::encodeComplete(SymbologyType::MIL2525D, "10030100001201000000");
// SymbolSet 10 == Land Unit
sidcs += SidcCodec::encodeComplete(SymbologyType::MIL2525D, "10031000001100000000");
sidcs += SidcCodec::encodeComplete(SymbologyType::MIL2525D, "10031000001101000000");
sidcs += SidcCodec::encodeComplete(SymbologyType::MIL2525D, "10031000001102000000");
sidcs += SidcCodec::encodeComplete(SymbologyType::MIL2525D, "10031000001103000000");
sidcs += SidcCodec::encodeComplete(SymbologyType::MIL2525D, "10031000001104000000");
sidcs += SidcCodec::encodeComplete(SymbologyType::MIL2525D, "10031000001105000000");
sidcs += SidcCodec::encodeComplete(SymbologyType::MIL2525D, "10031000001106000000");
// SymbolSet 15 == Land Equipment
sidcs += SidcCodec::encodeComplete(SymbologyType::MIL2525D, "10031500001110000000"); // baseSymbolCode = 15 111000 Missle Launcher
sidcs += SidcCodec::encodeComplete(SymbologyType::MIL2525D, "10031500001100000000");
sidcs += SidcCodec::encodeComplete(SymbologyType::MIL2525D, "10031500001101000000");
sidcs += SidcCodec::encodeComplete(SymbologyType::MIL2525D, "10031500001101010000");
sidcs += SidcCodec::encodeComplete(SymbologyType::MIL2525D, "10031500001101020000");
sidcs += SidcCodec::encodeComplete(SymbologyType::MIL2525D, "10031500001101030000");
sidcs += SidcCodec::encodeComplete(SymbologyType::MIL2525D, "10011000001213030000"); // Movement and Maneuver : Reconnaissance 10 121303 (FULL_FRAME, but no real MainIcon)
sidcs += SidcCodec::encodeComplete(SymbologyType::MIL2525D, "10031500001202000000"); // Vehicle : Tank 15 120200
// Guez-IEDs
sidcs += SidcCodec::encodeComplete(SymbologyType::MIL2525D, "10011500002104000000"); // LAND MINE - IED
sidcs += SidcCodec::encodeComplete(SymbologyType::MIL2525D, "10013500001202000000"); // Weapon - IED
sidcs += SidcCodec::encodeComplete(SymbologyType::MIL2525D, "10014000001103000000"); // IED SUICIDE BOMBER (OHNE ZickZack)
sidcs += SidcCodec::encodeComplete(SymbologyType::MIL2525D, "10014000001103010000"); // IED SUICIDE BOMBER (MIT ZickZack)
// ^
sidcs += SidcCodec::encodeComplete(SymbologyType::MIL2525D, "10014000001103040000"); // IED suicide bomber
sidcs += SidcCodec::encodeComplete(SymbologyType::MIL2525D, "10014000001101110000"); // BOOBY TRAP (replaced by 'IED suicide bomber')
return sidcs;
}
QStringList listOfLineSidcs_Internal()
{
QStringList sidcs;
sidcs += SidcCodec::encodeComplete(SymbologyType::MIL2525D, "10032500001406030000"); // hit_line_impl
sidcs += SidcCodec::encodeComplete(SymbologyType::MIL2525D, "10012500001402000000"); // 25140200_6 == "Maneuver Lines : Line of Contact" (no key8-Entry)
#ifdef SYM_PROTECTION_AREAS_BECOMES_LINE
sidcs += SidcCodec::encodeComplete(SymbologyType::MIL2525D, "10012500002711000000"); // Control Measure: Protection Areas :
sidcs += SidcCodec::encodeComplete(SymbologyType::MIL2525D, "10012500002713000000"); // Control Measure: Protection Areas : Assult Crossing (former GeometryType::area, now GeometryType::Line)
sidcs += SidcCodec::encodeComplete(SymbologyType::MIL2525D, "10012500002714000000"); // Control Measure: Protection Areas : Bridge
#endif // SYM_PROTECTION_AREAS_BECOMES_LINE
return sidcs;
}
QStringList listOfAreaSidcs_Internal()
{
QStringList sidcs;
sidcs += SidcCodec::encodeComplete(SymbologyType::MIL2525D, "10012500002408010000"); // area_fire_impl
sidcs += SidcCodec::encodeComplete(SymbologyType::MIL2525D, "10012500002717000000"); // biological_agent_impl
sidcs += SidcCodec::encodeComplete(SymbologyType::MIL2525D, "10042500002701000000"); // building_outline_impl
sidcs += SidcCodec::encodeComplete(SymbologyType::MIL2525D, "10012500002718000000"); // chemical_agent_impl
sidcs += SidcCodec::encodeComplete(SymbologyType::MIL2525D, "10012500001511000000"); // danger_area_impl
// sidcs += SidcCodec::encodeComplete(SymbologyType::MIL2525D,"10012500002707010000"); // MineField
sidcs += SidcCodec::encodeComplete(SymbologyType::MIL2525D, "10012500002707060000"); // mine_field_impl
sidcs += SidcCodec::encodeComplete(SymbologyType::MIL2525D, "10012500002719000000"); // nuclear_agent_impl
#ifndef SYM_PROTECTION_AREAS_BECOMES_LINE
sidcs += SidcCodec::encodeComplete(SymbologyType::MIL2525D, "10012500002711000000"); // Control Measure: Protection Areas :
sidcs += SidcCodec::encodeComplete(SymbologyType::MIL2525D, "10012500002713000000"); // Control Measure: Protection Areas : Assult Crossing (former GeometryType::area, now GeometryType::Line)
sidcs += SidcCodec::encodeComplete(SymbologyType::MIL2525D, "10012500002714000000"); // Control Measure: Protection Areas : Bridge
#endif // SYM_PROTECTION_AREAS_BECOMES_LINE
return sidcs;
}
QStringList listOfPlanEditorSidcs_Internal()
{
QStringList sidcs;
sidcs += SidcCodec::encodeBaseSymbolCode(SymbologyType::MIL2525D, "25342300");
sidcs += SidcCodec::encodeBaseSymbolCode(SymbologyType::MIL2525D, "25140500");
sidcs += SidcCodec::encodeBaseSymbolCode(SymbologyType::MIL2525D, "25152100");
sidcs += SidcCodec::encodeBaseSymbolCode(SymbologyType::MIL2525D, "25141400");
sidcs += SidcCodec::encodeBaseSymbolCode(SymbologyType::MIL2525D, "25141700");
sidcs += SidcCodec::encodeBaseSymbolCode(SymbologyType::MIL2525D, "25290500");
sidcs += SidcCodec::encodeBaseSymbolCode(SymbologyType::MIL2525D, "25270503");
sidcs += SidcCodec::encodeBaseSymbolCode(SymbologyType::MIL2525D, "25341900");
sidcs += SidcCodec::encodeBaseSymbolCode(SymbologyType::MIL2525D, "25270504");
sidcs += SidcCodec::encodeBaseSymbolCode(SymbologyType::MIL2525D, "25230100");
sidcs += SidcCodec::encodeBaseSymbolCode(SymbologyType::MIL2525D, "25271100");
sidcs += SidcCodec::encodeBaseSymbolCode(SymbologyType::MIL2525D, "25341500");
sidcs += SidcCodec::encodeBaseSymbolCode(SymbologyType::MIL2525D, "25241202");
sidcs += SidcCodec::encodeBaseSymbolCode(SymbologyType::MIL2525D, "25241602");
sidcs += SidcCodec::encodeBaseSymbolCode(SymbologyType::MIL2525D, "25340800");
sidcs += SidcCodec::encodeBaseSymbolCode(SymbologyType::MIL2525D, "25270502");
sidcs += SidcCodec::encodeBaseSymbolCode(SymbologyType::MIL2525D, "25342201");
sidcs += SidcCodec::encodeBaseSymbolCode(SymbologyType::MIL2525D, "25271204");
sidcs += SidcCodec::encodeBaseSymbolCode(SymbologyType::MIL2525D, "25240103");
sidcs += SidcCodec::encodeBaseSymbolCode(SymbologyType::MIL2525D, "25240802");
sidcs += SidcCodec::encodeBaseSymbolCode(SymbologyType::MIL2525D, "25270501");
sidcs += SidcCodec::encodeBaseSymbolCode(SymbologyType::MIL2525D, "25271600");
return sidcs;
}
// helper function
bool check(QRegExp &regExp, const QStringList &regExStrings, const QString &token)
{
for (const QString &rgExStr : regExStrings)
{
regExp.setPattern(rgExStr);
if (regExp.exactMatch(token))
return true;
if (token.contains(rgExStr, Qt::CaseInsensitive))
return true;
} // foreach
return false;
}
// helper function
bool check(QRegExp &regExp, const QString &regExString, const QString &token)
{
regExp.setPattern(regExString);
if (regExp.exactMatch(token))
return true;
if (token.contains(regExString))
return true;
return false;
}
SymbolDictionaryImpl::SymbolDictionaryImpl(SymbologyType symbologyType,
const QString &symbologyResourcePath)
: SymbolDictionary() // Interface
, m_baseSymbolCodeToSymbolPropertyTable()
, m_etsSidcSymbolProperties(SymbologyType::None)
, m_etsSidcImages(SymbologyType::None)
, m_xmlSidcSymbolProperties(SymbologyType::None)
, m_xmlSymbols(SymbologyType::None,SidcCodec::SidcType::CivilXml)
, m_xmlSymbolCache()
, m_esriBaseSymbolModel(new BaseSymbolModel(this))
, m_xmlBaseSymbolModel(new BaseSymbolModel(this))
, m_etsBaseSymbolModel(new BaseSymbolModel(this))
, m_changedDelayTimer(new QTimer(this))
, m_isLoading(false)
, m_logger(getLogger("SymbolDictionaryImpl"))
{
TRACE_LOG(m_logger) << LOGFUNCTION << " START"
<< " symbologyType=" << symbologyType
<< " resPath='" << symbologyResourcePath << "'"
<< " ThreadId=" << QThread::currentThreadId();
DEBUG_LOG(m_logger) << LOGFUNCTION << " symbologyType=" << symbologyType << ", resPath='" << symbologyResourcePath << "'";
switch (symbologyType) {
case SymbologyType::APP6B:
m_esriDictionaryProcessor = new EsriDictionaryProcessorApp6; // not full supported yet
break;
case SymbologyType::APP6D:
m_esriDictionaryProcessor = new EsriDictionaryProcessorApp6D; // not full supported yet
break;
case SymbologyType::MIL2525C:
m_esriDictionaryProcessor = nullptr; // not supported yet
break;
case SymbologyType::MIL2525D:
m_esriDictionaryProcessor = new EsriDictionaryProcessorMil2525D;
break;
case SymbologyType::None:
m_esriDictionaryProcessor = nullptr;
break;
}
if (!m_esriDictionaryProcessor)
{
FATAL_LOG(m_logger) << LOGFUNCTION << " !!! no EsriDictionaryProcessor !!!";
FATAL_LOG(m_logger) << LOGFUNCTION << " symbologyType=" << symbologyType << ", resPath='" << symbologyResourcePath << "'";
}
m_changedDelayTimer->setSingleShot(true);
m_changedDelayTimer->setInterval(500);
connect(m_changedDelayTimer, &QTimer::timeout, this, &SymbolDictionaryImpl::changedDelayed);
m_initOk = init(symbologyType, symbologyResourcePath);
// QTimer *timer = new QTimer(this);
// timer->setInterval(5000);
// connect(timer, &QTimer::timeout, this, [this]() {
// qCritical() << " ----------------------------------------------";
// qCritical() << " m_findSymbol2symbolResult.size() = " << m_findSymbol2symbolResult.size();
// qCritical() << " m_createSwatch2findSymbolTaskId.size() = " << m_createSwatch2findSymbolTaskId.size();
// });
// timer->start();
TRACE_LOG(m_logger) << LOGFUNCTION << " END";
}
SymbolDictionaryImpl::~SymbolDictionaryImpl()
{
TRACE_LOG(m_logger) << LOGFUNCTION << " START";
m_changedDelayTimer->stop();
if (m_esriDictionaryProcessor)
{
m_esriDictionaryProcessor->cancel();
m_esriDictionaryProcessor->waitForFinished();
}
delete m_esri_dictionary;
delete m_esriDictionaryProcessor;
TRACE_LOG(m_logger) << LOGFUNCTION << " END";
}
bool SymbolDictionaryImpl::isOk() const
{
return m_initOk && (nullptr != m_esri_dictionary);
} // bool SymbolDictionaryImpl::isOk() const
bool SymbolDictionaryImpl::init(SymbologyType symbologyType, const QString &symbologyResourcePath)
{
TRACE_LOG(m_logger) << LOGFUNCTION << " START";
// cleanup :
delete m_esri_dictionary;
clearEtsSymbols();
m_createSwatch2findSymbolTaskId.clear();
m_findSymbol2propertyResult.clear();
m_findSymbol2symbolResult.clear();
// clear EsriDictProcessor!?
// : cleanup
m_symbolDictionaryType_own = symbologyType;
m_symbologyResourcePath = symbologyResourcePath;
switch (m_symbolDictionaryType_own)
{
case SymbologyType::MIL2525D:
m_specificationType = QStringLiteral("mil2525d"); // 'mil2525d' - fixed string for QuartzRelease
break;
case SymbologyType::MIL2525C:
m_specificationType = QStringLiteral("mil2525c");
break;
case SymbologyType::APP6B:
m_specificationType = QStringLiteral("app6b");
break;
case SymbologyType::APP6D:
m_specificationType = QStringLiteral("app6d");
break;
case SymbologyType::None:
// empty
break;
} // switch
if (m_symbolDictionaryType_own != SymbologyType::None)
{
#ifdef USE_ARCADE_SYMBOLOGY
// m_specificationType = QStringLiteral("/usr/share/arcgis/resources/symbols//mil2525d/mil2525d.stylx");
// m_specificationType = QStringLiteral("/usr/share/arcgis/resources/symbols_arcade//mil2525d/mil2525d.stylx");
QFile resFile(m_symbologyResourcePath);
if (m_symbologyResourcePath.isEmpty() || !resFile.exists())
{
ERROR_LOG(m_logger) << LOGFUNCTION << " path is empty or does not exist: " << " m_symbologyResourcePath='" << m_symbologyResourcePath << "'";
Q_ASSERT(false);
return false;
}
NOTICE_LOG(m_logger) << LOGFUNCTION << " create EsriDict:"
<< " m_specificationType='" << m_specificationType << "'"
<< " m_symbologyResourcePath='" << m_symbologyResourcePath << "'";
// use ESRIs new static method introduced with V100.6:
m_esri_dictionary = Esri::ArcGISRuntime::DictionarySymbolStyle::createFromFile(m_symbologyResourcePath);
#else
// QString symbologyResourcePath("/usr/share/arcgis/resources/symbols//mil2525d/mil2525d.stylx");
if (symbologyResourcePath.isEmpty())
{
INFO_LOG(m_logger) << LOGFUNCTION << " create EsriDict:"
<< " m_specificationType='" << m_specificationType << "'";
m_esri_dictionary = new Esri::ArcGISRuntime::DictionarySymbolStyle(m_specificationType);
}
else
{
QFile resFile(symbologyResourcePath);
if (!resFile.exists())
{
ERROR_LOG(m_logger) << LOGFUNCTION << " path does not exist: " << " symbologyResourcePath='" << symbologyResourcePath << "'";
Q_ASSERT(false);
return false;
}
NOTICE_LOG(m_logger) << LOGFUNCTION << " create EsriDict:"
<< " m_specificationType='" << m_specificationType << "'"
<< " m_symbologyResourcePath='" << m_symbologyResourcePath << "'";
m_esri_dictionary = new Esri::ArcGISRuntime::DictionarySymbolStyle(m_specificationType, m_symbologyResourcePath);
}
#endif // USE_ARCADE_SYMBOLOGY
if (m_esri_dictionary)
{
connect(m_esri_dictionary, &Esri::ArcGISRuntime::DictionarySymbolStyle::loadStatusChanged,
this, &SymbolDictionaryImpl::onLoadStatusChanged);
connect(m_esri_dictionary, &Esri::ArcGISRuntime::DictionarySymbolStyle::errorOccurred,
this, &SymbolDictionaryImpl::onErrorDictionary);
}
}
m_xmlSymbolCache = SymbologyXML::PixmapSymbolCache::instance();
if (m_xmlSymbolCache && !m_xmlSymbolCache->symbolTablesAlreadySet())
{
SymbologyXML::SymbolTable *symbolFrames; ///< SymbolTable with Symbol-Frames
SymbologyXML::SymbolTable *mobilitySymbols; ///< SymbolTable with Mobility-Symbols
SymbologyXML::SymbolTable *bcdabSymbols; ///< SymbolTable with BCDAB-Symbols
SymbologyXML::SymbolTable *commandLevelSymbols; ///< SymbolTable with CommandLevel-Symbols
SymbologyXML::SymbolTable *branchSymbols; ///< SymbolTable with Branch (Truppengattung)-Symbols
SymbologyXML::SymbolTable *vehicleSymbols; ///< SymbolTable with Vehicle-Symbols
SymbologyXML::SymbolTable *intrinsicMobilitySymbols; ///< SymbolTable with Intrinsic-Mobility-Symbols
SymbologyXML::SymbolTable *armingSymbols; ///< SymbolTable with Arming-Symbols
SymbologyXML::SymbolTable *miscSymbols; ///< SymbolTable with Misc-Symbols
SymbologyXML::SymbolTable *addOnSymbols; ///< SymbolTable with addOn-Symbols
SymbologyXML::SymbolTable *sectorIcons; ///< SymbolTable with Sector-Icons
m_xmlSymbolCache->setSymbolTables( symbolFrames = new SymbologyXML::SymbolTable() /* SymbolTable *frames, */
, mobilitySymbols = new SymbologyXML::SymbolTable() /* SymbolTable *mobility, */
, bcdabSymbols = new SymbologyXML::SymbolTable() /* SymbolTable *bcdab, */
, commandLevelSymbols = new SymbologyXML::SymbolTable() /* SymbolTable *commandLevel, */
, branchSymbols = new SymbologyXML::SymbolTable() /* SymbolTable *branches, */
, vehicleSymbols = new SymbologyXML::SymbolTable() /* SymbolTable *vehicle, */
, intrinsicMobilitySymbols = new SymbologyXML::SymbolTable() /* SymbolTable *intrinsicMobility, */
, armingSymbols = new SymbologyXML::SymbolTable() /* SymbolTable *arming, */
, miscSymbols = new SymbologyXML::SymbolTable() /* SymbolTable *misc, */
, addOnSymbols = new SymbologyXML::SymbolTable() /* SymbolTable *addOnSymbole, */
, sectorIcons = new SymbologyXML::SymbolTable() /* SymbolTable *sectorIcon */ );
auto setDirectory = [this](SymbologyXML::SymbolTable * symTab, const QString &path, const char *errMsg)
{
if (!symTab->setDirectory(path, QStringList(QStringLiteral("*.xml"))))
{
ERROR_LOG(m_logger) << errMsg;
}
};
setDirectory( symbolFrames , QStringLiteral(":/Symbole/Attributes/symbolframes") , "Error while reading SymbolFrame-XML-Files!" );
setDirectory( branchSymbols , QStringLiteral(":/Symbole/Attributes/branch") , "Error while reading Branch/Truppengattung-XML-Files!" );
setDirectory( mobilitySymbols , QStringLiteral(":/Symbole/Attributes/mobility") , "Error while reading Mobility-XML-Files!" );
setDirectory( bcdabSymbols , QStringLiteral(":/Symbole/Attributes/bcdab") , "Error while reading BCDAB-XML-Files!" );
setDirectory( commandLevelSymbols , QStringLiteral(":/Symbole/Attributes/commandlevel") , "Error while reading CommandLevel-XML-Files!" );
setDirectory( vehicleSymbols , QStringLiteral(":/Symbole/Attributes/vehicle") , "Error while reading vehicle-XML-Files!" );
setDirectory( intrinsicMobilitySymbols, QStringLiteral(":/Symbole/Attributes/intrinsicmobility"), "Error while reading Intrinsic-Mobility-XML-Files!" );
setDirectory( armingSymbols , QStringLiteral(":/Symbole/Attributes/arming") , "Error while reading arming-XML-Files!" );
setDirectory( miscSymbols , QStringLiteral(":/Symbole/Attributes/misc") , "Error while reading misc-XML-Files!" );
setDirectory( addOnSymbols , QStringLiteral(":/Symbole/AddOnSymbole") , "Error while reading AddOn-Symbol-XML-Files!" );
setDirectory( sectorIcons , QStringLiteral(":/Symbole/Attributes/sectoricon") , "Error while reading sectoricon-XML-Files!" );
// ToDo: delete SymbolTables at program end to avoid warning because mem leak
}
TRACE_LOG(m_logger) << LOGFUNCTION << " END";
return true;
}
void SymbolDictionaryImpl::connectSignals()
{
if (m_esri_dictionary)
{
connect(m_esri_dictionary, &Esri::ArcGISRuntime::DictionarySymbolStyle::fetchSymbolCompleted,
this, &SymbolDictionaryImpl::onFetchSymbolCompleted);
}
}
SymbologyType SymbolDictionaryImpl::symbologyType() const
{
return m_symbolDictionaryType_own;
}
QString SymbolDictionaryImpl::specificationType() const
{
return m_specificationType;
}
QString SymbolDictionaryImpl::symbologyResourcePath() const
{
return m_symbologyResourcePath;
}
const Esri::ArcGISRuntime::DictionarySymbolStyle *SymbolDictionaryImpl::getEsriSymbolDictionary() const
{
return m_esri_dictionary;
}
QImage SymbolDictionaryImpl::temporaryImage(int sizeL)
{
QImage image = ExtensionRenderer::createFullImage(sizeL, QColor(27, 27, 27, 127));
QPainter painter(&image);
QPen pen(Qt::black);
pen.setWidth(2.0);
painter.setPen(pen);
const QRect &rect = image.rect();
painter.drawRect(image.rect());
pen.setColor(Qt::darkGray);
pen.setWidth(5.0);
painter.setPen(pen);
painter.drawLine( rect.topLeft(), QPointF(rect.width() / 2.0, rect.height() * 0.75));
painter.drawLine(QPointF(rect.width() / 2.0, rect.height() * 0.75), QPointF(rect.width() / 2.0, rect.height() * 0.25));
painter.drawLine(QPointF(rect.width() / 2.0, rect.height() * 0.25), rect.bottomRight());
return image;
}
QImage SymbolDictionaryImpl::notFoundImage(int sizeL, const QColor &fillColor)
{
QImage image = ExtensionRenderer::createFullImage(sizeL);
QPainter painter(&image);
painter.setPen(QPen(Qt::transparent));
painter.setBrush(QBrush(fillColor));
const int minLength = std::min<int>(image.rect().width(), image.rect().height()) * 0.42;
painter.drawEllipse(QPointF(image.rect().center()), minLength, minLength);
painter.setPen(QPen(Qt::black));
QFont font = painter.font();
font.setBold(true);
font.setPixelSize(static_cast<int>(sizeL * 1.4));
painter.setFont(font);
QPointF pos(image.width() * 0.30,
image.height() * 0.80);
painter.drawText(pos, QLatin1String("?"));
return image;
}
QSharedPointer<SymbolResult> SymbolDictionaryImpl::notFoundSymbolResult(const SymbolDataToRender &symDataToRender)
{
QSharedPointer<SymbolResult> symResultNotFound = QSharedPointer<SymbolResult>(new SymbolResult);
SymbolImage symImage;
QColor finalFillColor = Qt::yellow; // maybe AdvancedSymbology::SymbolDataToRender::unknownColor();
if (symDataToRender.fillColorReplace && symDataToRender.fillColor.isValid())
finalFillColor.setAlpha(symDataToRender.fillColor.alpha());
symImage.setImage(notFoundImage(symDataToRender.sizeL, finalFillColor));
symResultNotFound->setSymbolDataToRender(symDataToRender);
symResultNotFound->setSymbolImage(symImage);
symResultNotFound->fireResultReady(); // ToDo: maybe async!?!?
return symResultNotFound;
}
QSharedPointer<SymbolResult> SymbolDictionaryImpl::notFoundSymbolResult(int sizeL)
{
SymbolDataToRender symDataToRender;
symDataToRender.sizeL = sizeL;
symDataToRender.fillColorReplace = false;
return notFoundSymbolResult(symDataToRender);
}
QStringList SymbolDictionaryImpl::symbologyAttributeKeyList() const
{
QStringList result = m_esri_dictionary->symbologyFieldNames() << m_esri_dictionary->textFieldNames();
result.removeDuplicates();
return result;
} // QStringList SymbolDictionaryImpl::symbologyAttributeKeyList() const
void SymbolDictionaryImpl::load()
{
TRACE_LOG(m_logger) << LOGFUNCTION << " START"
<< " ThreadId=" << QThread::currentThreadId();
if (m_isLoading)
return;
m_isLoading = true;
if (!m_esri_dictionary || isLoaded())
return;
m_esri_dictionary->load();
TRACE_LOG(m_logger) << LOGFUNCTION << " END";
}
bool SymbolDictionaryImpl::isLoaded() const
{
TRACE_LOG(m_logger) << LOGFUNCTION << " START" << " ThreadId=" << QThread::currentThreadId();
bool isLoaded = loadStatus() == LoadStatus::Loaded;
TRACE_LOG(m_logger) << LOGFUNCTION << " END" << " isLoaded=" << isLoaded << " (loadStatus()=" << loadStatus() << ")";
return isLoaded;
}
LoadStatus SymbolDictionaryImpl::loadStatus() const
{
TRACE_LOG(m_logger) << LOGFUNCTION << " START";
// LoadStatus for Esri:
Esri::ArcGISRuntime::LoadStatus esriLoadStatus = Esri::ArcGISRuntime::LoadStatus::Unknown;
// SHOULD we have an esriDict or not? If not, it´s already loaded:
if (m_symbolDictionaryType_own == SymbologyType::None)
esriLoadStatus = Esri::ArcGISRuntime::LoadStatus::Loaded;
else
{
// Do we really have an esriDict?
if (m_esri_dictionary)
esriLoadStatus = m_esri_dictionary->loadStatus();
else
esriLoadStatus = Esri::ArcGISRuntime::LoadStatus::Unknown;
if (esriLoadStatus == Esri::ArcGISRuntime::LoadStatus::Loaded)
{
if (m_esriDictionaryProcessor && (! m_esriDictionaryProcessor->allJobsDone()))
esriLoadStatus = Esri::ArcGISRuntime::LoadStatus::Loading;
}
}
LoadStatus finalLoadStatus = static_cast<LoadStatus>(esriLoadStatus);
TRACE_LOG(m_logger) << LOGFUNCTION << " END"
<< " finalLoadStatus=" << finalLoadStatus
<< " (esriLoadStatus=" << static_cast<int>(esriLoadStatus);
return finalLoadStatus;
}
bool SymbolDictionaryImpl::setEtsSymbol(int fileId,
const QString &encodedSidc,
const SymbolProperties &properties,
const QImage &image)
{
TRACE_LOG(m_logger) << LOGFUNCTION << " START"
<< " fileId=" << fileId
<< " sidc='" << encodedSidc << "'"
<< " props.name='" << properties.name() << "'";
// some checks:
if (encodedSidc.isEmpty())
{
ERROR_LOG(m_logger) << LOGFUNCTION << " sidc is empty";
return false;
}
if (properties.name().isEmpty())
{
ERROR_LOG(m_logger) << LOGFUNCTION << " properties.name() is empty, "
<< " sidc='" << encodedSidc << "'";
return false;
}
if (!SidcCodec::isEncoded(encodedSidc))
{
ERROR_LOG(m_logger) << LOGFUNCTION << "sidc is not encoded, sidc='" << encodedSidc << "'";
return false;
}
if (!SidcCodec::checkSidcSyntax(encodedSidc))
{
ERROR_LOG(m_logger) << LOGFUNCTION << "wrong encoding in sidc, sidc='" << encodedSidc << "'";
return false;
}
if (SidcCodec::decodeSidcType(encodedSidc) != SidcCodec::SidcType::CivilEts)
{
ERROR_LOG(m_logger) << LOGFUNCTION << "wrong sidc type, sidc='" << encodedSidc << "'. Type must be CivilEts!";
return false;
}
// 1: add to m_etsSidcSymbolProperties
m_etsSidcSymbolProperties[encodedSidc] = properties;
// 2: add to m_etsSidcImages
m_etsSidcImages[encodedSidc] = image;
// 3: add to m_etsSidcOrdered
if (!m_etsSidcOrdered.contains(encodedSidc))
m_etsSidcOrdered.append(encodedSidc);
// m_etsBaseSymbolModel :
m_etsBaseSymbolModel->insertEtsSymbol(fileId, encodedSidc, properties, image);
// : m_etsBaseSymbolModel
// 4. emit signal to update view:
// emit nearly immediately
// QTimer::singleShot(0, [this]() { emit changed(); });
emit changed();
// emit delayed
m_changedDelayTimer->start(); // is restart timer if already running
TRACE_LOG(m_logger) << LOGFUNCTION << " END"
<< " sidc='" << encodedSidc << "'";
return true;
}
void SymbolDictionaryImpl::removeEtsSymbol(int fileId)
{
// m_etsBaseSymbolModel :
m_etsBaseSymbolModel->removeEtsSymbol(fileId);
// : m_etsBaseSymbolModel
}
void SymbolDictionaryImpl::removeEtsSymbol(const QString &encodedSidc)
{
m_etsSidcSymbolProperties.remove(encodedSidc);
m_etsSidcImages.remove(encodedSidc);
m_etsSidcOrdered.removeAll(encodedSidc);
emit changed();
m_changedDelayTimer->start(); // is restart timer if already running
}
void SymbolDictionaryImpl::clearEtsSymbols()
{
m_etsSidcSymbolProperties.clear();
m_etsSidcImages.clear();
m_etsSidcOrdered.clear();
emit changed();
m_changedDelayTimer->start(); // is restart timer if already running
}
int SymbolDictionaryImpl::addEtsSymbols(const QString &path)
{
TRACE_LOG(m_logger) << LOGFUNCTION << " START" << " path ='" << path << "'"
<< " current etsSymbolCount=" << this->etsSymbolCount();
if (path.isEmpty())
return -1; // use qrc path!?
int addedFiles = 0;
QDir rootDir(path);
// real work:
DEBUG_LOG(m_logger) << "Searching in path '" << path << "'";
QStringList slFilePaths;
QDirIterator dir(path,
QDir::Files | QDir::Readable, QDirIterator::Subdirectories);
const QString gif(QStringLiteral(".gif"));
while (dir.hasNext())
{
const QString &filePath = dir.next();
if (!filePath.endsWith(gif))
continue;
slFilePaths.append(filePath);
} // while
// sort:
slFilePaths.sort();
// iterate over sorted files:
int fileId_substitute = 0;
for (const auto &filePath : qAsConst(slFilePaths))
{
++fileId_substitute;
// DEBUG_LOG(m_logger) << LOGFUNCTION << " found file= '" << filePath << "'";
QFileInfo fileInfo(filePath);
const QString &curFilename = fileInfo.baseName(); // without suffix
const QString &humanReadableName = curFilename;
const QString key = curFilename;
AdvancedSymbology::SymbolProperties symProps;
// resultItem.key ='25152000_3' (mpl/symbol_dictionary_impl.cpp:418)
// resultItem.name ='Maneuver Areas : Attack by Fire Position : Friend' (mpl/symbol_dictionary_impl.cpp:419)
// resultItem.category ='Control Measure : Line' (mpl/symbol_dictionary_impl.cpp:420)
// resultItem.symbolClass ='4' (mpl/symbol_dictionary_impl.cpp:421)
// resultItem.tags ='Control Measure;Maneuver Areas;Attack by Fire Position;gct_arrow_with_tail;G*GPOAF---****X;MAIN;Line;Maneuver Areas : Attack by Fire Position;25152000' (mpl/symbol_dictionary_impl.cpp:422)
// 1 key
symProps.setKey(key);
// 2 name
symProps.setName(humanReadableName);
symProps.setSidc(SidcCodec::encodeCivilEts(key));
// 3 category
// eg: 3_Person (1_GIFs_Aktuell/WRett/3_Person/xy.gif
// rootDir.absolutePath(): ':/advancedSymbology/CivilSymbols'
// filepath : ':/advancedSymbology/CivilSymbols/Sonstige/Bundeswehr_Stelle.gif'
// remove path from filePath:
QStringRef filePathReduced = filePath.midRef(rootDir.absolutePath().size() + 1);
// filepath 'Sonstige/Bundeswehr_Stelle.gif'
QVector<QStringRef> parts = filePathReduced.split(QLatin1Char('/'));
// remove filename (to get dirname's as tags:
parts.removeLast();
if (!parts.isEmpty())
{
const QString &dirName = parts.last().toString(); // eg: 3_Person (1_GIFs_Aktuell/WRett/3_Person/xy.gif
symProps.setCategory(dirName);
}
// 4 symbolClass
symProps.setSymbolClass(QLatin1String("3")); // 18.10.2016, N.Thoden: 3 == PointSymbol (mil2525d.stylx - QuartzRelease)
// 5 tags
QStringList tags;
tags.reserve(parts.size() + 2);
tags.append(ETS_SYMBOL_KEYWORD); // 'ETS'
for (const auto &item : qAsConst(parts))
tags.append(item.toString());
tags.append(humanReadableName);
symProps.setTags(tags);
// 6 GeometryType
symProps.setGeometryType(GeometryType::Point); // ETS-Symbols are always Points
// Image
QImage image(filePath);
if (!image.isNull())
{
if (this->setEtsSymbol(fileId_substitute, symProps.sidc(), symProps, image))
++addedFiles;
else
ERROR_LOG(m_logger) << LOGFUNCTION << " error proccessing1 " << filePath << "'";
}
else
ERROR_LOG(m_logger) << LOGFUNCTION << " error proccessing2 " << filePath << "'";
}
DEBUG_LOG(m_logger) << LOGFUNCTION << " path ='" << path << "'," << " addedFiles ='" << addedFiles << "'";
TRACE_LOG(m_logger) << LOGFUNCTION << " END" << " path ='" << path << "'"
<< " addedFiles ='" << addedFiles << "'"
<< " current etsSymbolCount=" << this->etsSymbolCount();
return addedFiles;
}
int AdvancedSymbology::SymbolDictionaryImpl::etsSymbolCount() const
{
return m_etsSidcSymbolProperties.count();
}
QStringList SymbolDictionaryImpl::etsSymbols() const
{
return m_etsSidcOrdered;
}
bool SymbolDictionaryImpl::containsXmlSymbol(const QString &encodedSidc) const
{
return m_xmlSymbols.containsSidc(encodedSidc);
} // bool SymbolDictionaryImpl::containsXmlSymbol(const QString &sidc) const
bool SymbolDictionaryImpl::setXmlSymbol(int fileId, const QString &name, const QString &operatorName, qint64 lastModified, const QString &xmlSymbol, const SymbolProperties &properties)
{
SymbologyXML::SymbolReader xmlReader;
SymbologyXML::Symbol symbol;
if (!xmlReader.read(xmlSymbol, symbol))
{
ERROR_LOG(m_logger) << LOGFUNCTION << " read symbol failed";
return false;
}
// maybe xmlSymbol has an internal name. updated:
symbol.setName(name);
symbol.setID(fileId);
if (!setXmlSymbol(fileId, name, operatorName, lastModified, symbol, properties))
{
ERROR_LOG(m_logger) << LOGFUNCTION << " setXmlSymbol failed";
return false;
}
return true;
}
bool SymbolDictionaryImpl::setXmlSymbol(int fileId, const QString &name, const QString &operatorName, qint64 lastModified, const SymbologyXML::Symbol &symbol, const SymbolProperties &properties)
{
TRACE_LOG(m_logger) << LOGFUNCTION << " START"
<< " fileId=" << fileId
<< " name= '" << name << "'"
<< " operatorName='" << operatorName << "'"
<< " lastModified=" << lastModified
<< " symbol.id=" << symbol.id()
<< " symbol.getName()= '" << symbol.getName() << "'"
<< " properties.name= '" << properties.name() << "'";
const int symbolId = fileId; // decision: we use the fileId as symbolId
const QString &skey = QString::number(symbolId);
const QString &sidc = SidcCodec::encodeCivilXml(skey);
if (m_xmlSymbols.containsSidc(sidc))
DEBUG_LOG(m_logger) << LOGFUNCTION << " symbol to insert is already defined, update... (id=" << symbol.id() << ")";
m_xmlSymbols[sidc] = symbol;
SymbolProperties propsCopy = properties;
propsCopy.setName(name);
propsCopy.setSidc(sidc);
propsCopy.setKey(skey);
propsCopy.setGeometryType( GeometryType::Point );
propsCopy.setSymbolClass(QStringLiteral("3"));
m_xmlSidcSymbolProperties[sidc] = propsCopy;
// clear cache:
if (m_xmlSymbolCache)
{
m_xmlSymbolCache->clearCache(SymbologyXML::PixmapSymbolCache::CacheType::CacheMainSymbols);
m_xmlSymbolCache->clearCache(SymbologyXML::PixmapSymbolCache::CacheType::CacheFullSymbols);
}
// m_xmlBaseSymbolModel :
if (!m_xmlBaseSymbolModel->insertXmlSymbol(fileId, operatorName, lastModified, symbol, propsCopy))
ERROR_LOG(m_logger) << LOGFUNCTION << " insertXmlSymbol failed, fileId=" << fileId;
// : m_xmlBaseSymbolModel
emit changed();
m_changedDelayTimer->start(); // is restart timer if already running
return true;
}
void SymbolDictionaryImpl::removeXmlSymbol(int fileId)
{
// m_xmlBaseSymbolModel :
if (!m_xmlBaseSymbolModel->removeXmlSymbol(fileId))
ERROR_LOG(m_logger) << LOGFUNCTION << " removeXmlSymbol failed: fileId= '" << fileId
<< " (m_xmlBaseSymbolModel->rowCount()=" << m_xmlBaseSymbolModel->rowCount();
}
void SymbolDictionaryImpl::removeXmlSymbol(const QString &encodedSidc)
{
TRACE_LOG(m_logger) << LOGFUNCTION << " START"
<< ", sidc= '" << encodedSidc << "'"
<< ", m_xmlSymbols.size= " << m_xmlSymbols.size()
<< ", m_xmlSidcSymbolProperties.size= " << m_xmlSidcSymbolProperties.size();
const SidcCodec::SidcType sidcType = SidcCodec::decodeSidcType(encodedSidc);
if (SidcCodec::SidcType::CivilXml == sidcType)
{
m_xmlSymbols.remove(encodedSidc);
m_xmlSidcSymbolProperties.remove(encodedSidc);
if (m_xmlSymbols.empty())
{
if (m_xmlSymbolCache)
{
m_xmlSymbolCache->clearCache( SymbologyXML::PixmapSymbolCache::CacheMainSymbols );
m_xmlSymbolCache->clearCache( SymbologyXML::PixmapSymbolCache::CacheFullSymbols );
}
}
DEBUG_LOG(m_logger) << LOGFUNCTION << " emit CHANGED, sidc= '" << encodedSidc << "'"
<< ", sidcType= '" << static_cast<int>(sidcType);
emit changed();
m_changedDelayTimer->start(); // is restart timer if already running
} else {
WARNING_LOG(m_logger) << LOGFUNCTION << " Wrong sidc/sidcType: sidc= '" << encodedSidc << "'"
<< ", sidcType= '" << static_cast<int>(sidcType);
}
TRACE_LOG(m_logger) << LOGFUNCTION << " END"
<< ", sidc= '" << encodedSidc << "'"
<< ", m_xmlSymbols.size= " << m_xmlSymbols.size()
<< ", m_xmlSidcSymbolProperties.size= " << m_xmlSidcSymbolProperties.size();
}
void SymbolDictionaryImpl::clearXmlSymbols()
{
// m_xmlBaseSymbolModel :
m_xmlBaseSymbolModel->clear();
m_xmlSymbols.clear();
m_xmlSidcSymbolProperties.clear();
if (nullptr == m_xmlSymbolCache) return;
m_xmlSymbolCache->clearCache( SymbologyXML::PixmapSymbolCache::CacheMainSymbols );
m_xmlSymbolCache->clearCache( SymbologyXML::PixmapSymbolCache::CacheFullSymbols );
emit changed();
m_changedDelayTimer->start(); // is restart timer if already running
}
void SymbolDictionaryImpl::clearXmlSymbolCache()
{
if (!m_xmlSymbolCache)
return;
m_xmlSymbolCache->clearCache( SymbologyXML::PixmapSymbolCache::CacheMainSymbols );
m_xmlSymbolCache->clearCache( SymbologyXML::PixmapSymbolCache::CacheFullSymbols );
m_xmlSymbolCache->clearCache( SymbologyXML::PixmapSymbolCache::CacheAddOn );
}
int SymbolDictionaryImpl::xmlSymbolCount() const
{
return m_xmlSymbols.count();
} // int SymbolDictionaryImpl::xmlSymbolCount() const
QStringList SymbolDictionaryImpl::xmlSymbols() const
{
return m_xmlSymbols.keys();
} // QStringList SymbolDictionaryImpl::xmlSymbols() const
QString SymbolDictionaryImpl::xmlSidc(const QString &xmlSymbol) const
{
SymbologyXML::SymbolReader xmlReader;
SymbologyXML::Symbol symbol;
if (xmlReader.read(xmlSymbol, symbol))
{
return xmlSidc(symbol);
}
return QString();
} // QString xmlSidc(const QString &xmlSymbol) const
QString SymbolDictionaryImpl::xmlSidc(const SymbologyXML::Symbol &symbol) const
{
return symbol.isValid() ? SidcCodec::encodeCivilXml(QString::number(symbol.id())) : QString();
} // QString SymbolDictionaryImpl::xmlSidc(const SymbologyXML::Symbol &symbol) const
SymbologyXML::Symbol SymbolDictionaryImpl::xmlSymbol(const QString &encodedSidc) const
{
const SidcCodec::SidcType sidcType = SidcCodec::decodeSidcType(encodedSidc);
if (SidcCodec::SidcType::CivilXml == sidcType)
{
if (m_xmlSymbols.contains(encodedSidc))
{
return m_xmlSymbols[encodedSidc];
}
}
return SymbologyXML::Symbol();
} // SymbologyXML::Symbol SymbolDictionaryImpl::xmlSymbol(const QString &sidc) const
SymbolProperties SymbolDictionaryImpl::xmlSymbolProps(const QString &encodedSidc) const
{
const SidcCodec::SidcType sidcType = SidcCodec::decodeSidcType(encodedSidc);
if (SidcCodec::SidcType::CivilXml == sidcType)
{
if (m_xmlSidcSymbolProperties.contains(encodedSidc))
{
return m_xmlSidcSymbolProperties[encodedSidc];
}
}
return SymbolProperties();
} // SymbolProperties SymbolDictionaryImpl::xmlSymbolProps(const QString &sidc) const
void SymbolDictionaryImpl::onLoadStatusChanged(Esri::ArcGISRuntime::LoadStatus loadStatus)
{
DEBUG_LOG(m_logger) << LOGFUNCTION << " m_esri_dictionary(" << m_esri_dictionary << ")"
<< " symType= '" << this->symbologyType() << "'"
<< " loadStatus changes to " << static_cast<int>(loadStatus)
<< " ThreadId=" << QThread::currentThreadId();
if (!m_esriDictionaryProcessor)
return;
if (loadStatus == Esri::ArcGISRuntime::LoadStatus::Loaded)
{
DEBUG_LOG(m_logger) << LOGFUNCTION << " ***** m_esri_dictionary " << m_esri_dictionary
<< " loading done ";
m_esriDictionaryProcessor->init(m_esri_dictionary);
m_esriDictionaryProcessor->prepare();
// continue if main job is finished:
connect(m_esriDictionaryProcessor, &EsriDictionaryProcessor::allIsDone,
this, &SymbolDictionaryImpl::onProcessorAllIsDone);
}
}
void SymbolDictionaryImpl::onProcessorAllIsDone()
{
if (!m_esriDictionaryProcessor)
return;
// take results into own member (to have easy access)
m_baseSymbolCodeToSymbolPropertyTable = m_esriDictionaryProcessor->baseSymbolCodeToSymbolPropertyTable();
// connect typical signals after main job of esriDictionaryProcessor is done:
connectSignals();
INFO_LOG(m_logger) << LOGFUNCTION << " SymbolDictionaryImpl: m_baseSymbolCodeToSymbolPropertyTable.size=" << m_baseSymbolCodeToSymbolPropertyTable.size();
TRACE_LOG(m_logger) << LOGFUNCTION << " ***** emit loaded";
// setup some items to new symbol_model_esri:
m_esriBaseSymbolModel->clear();
INFO_LOG(m_logger) << LOGFUNCTION << " ######### m_BaseSymbolModel.rowCount = " << m_esriBaseSymbolModel->rowCount();
emit loaded();
}
BaseSymbolModel* SymbolDictionaryImpl::getBaseSymbolModelEsri()
{
if (m_esriBaseSymbolModel->rowCount() == 0)
{
// Note: 14.01. 2020, N. Thoden
// initModel with the vecData does not really work.
// The m_vecData of m_baseSymbolModel contains a Esri::ArcGISRuntime::Symbol*.
// This object has to be created using the mainThread (V100.0 .. V100.6)
// That could be done by the EsriDictionaryProcessorXYZ, but that increases
// the startup time :-(
// So it (Esri::ArcGISRuntime::Symbol) has to be created on demand.
// That means if required (columns SEARCH_ICON, FETCH_ICON) within the model.
// That possibility is choosen:
const QList<Esri::ArcGISRuntime::SymbolStyleSearchResult> &searchResultList
= m_esriDictionaryProcessor->getSearchResultListValid();
m_esriBaseSymbolModel->initModel(this, searchResultList, m_baseSymbolCodeToSymbolPropertyTable);
}
return m_esriBaseSymbolModel;
}
bool SymbolDictionaryImpl::searchResultIsValid(const QHash<QString, int> &key8LookupTable,
const Esri::ArcGISRuntime::SymbolStyleSearchResult &resultItem,
QString *toBeRemovedFromName)
{
if (!m_esriDictionaryProcessor)
return false;
return m_esriDictionaryProcessor->searchResultIsValid(key8LookupTable, resultItem, toBeRemovedFromName);
}
QSharedPointer<SymbolResult> SymbolDictionaryImpl::symbolPropertyImage(QSharedPointer<SymbolResult> symResult, const SymbolProperties &symbolProperties, int sizeL) const
{
const QString &sidc = symbolProperties.sidc();
const QString &originalKey = symbolProperties.originalKey();
TRACE_LOG(m_logger) << LOGFUNCTION << " START"
<< " sidc='" << sidc << "'"
<< " originalKey='" << originalKey << "'"
<< " symbolProperties.name='" << symbolProperties.name() << "'"
<< " sizeL=" << sizeL;
if (symResult.isNull())
{
ERROR_LOG(m_logger) << LOGFUNCTION
<< " symResult is null!!!"
<< " props.name= '" << symbolProperties.name() << "'";
return notFoundSymbolResult(sizeL);
}
if (!SidcCodec::isEncoded(sidc))
{
ERROR_LOG(m_logger) << LOGFUNCTION << " sidc not encoded: sidc= '" << sidc << "'";
return notFoundSymbolResult(sizeL);
}
if (originalKey.isEmpty())
{
// ExtraSymbols: originalKey can be empty.
if (!SidcCodec::isCivil(sidc))
ERROR_LOG(m_logger) << LOGFUNCTION << " originalKey is empty" << " props.name= '" << symbolProperties.name() << "'";
return notFoundSymbolResult(sizeL);
}
if (! m_esriDictionaryProcessor)
{
ERROR_LOG(m_logger) << LOGFUNCTION
<< " originalKey= '" << originalKey << "' no esriDictionaryProcessor";
return notFoundSymbolResult(sizeL);
}
if (! m_esriDictionaryProcessor->symbolPropertyImageContains(originalKey))
{
ERROR_LOG(m_logger) << LOGFUNCTION
<< " originalKey= '" << originalKey << "' not found";
return notFoundSymbolResult(sizeL);
}
// transfer GeometryType:
symResult->setGeometryType(symbolProperties.geometryType());
// transfer spiOriginalKey, spiSizeL - used at onEsriSymbolSwatchCompleted (save image in cache etc)
SymbolDataToRender symDataToRender = symResult->symbolDataToRender();
symDataToRender.spiOriginalKey = originalKey;
symDataToRender.spiSizeL = sizeL;
symResult->setSymbolDataToRender(symDataToRender);
symResult = m_esriDictionaryProcessor->symbolPropertyImage(symResult, originalKey);
TRACE_LOG(m_logger) << LOGFUNCTION << " END"
<< " originalKey='" << originalKey << "'"
<< " symbolProperties.name='" << symbolProperties.name() << "'"
<< " sizeL=" << sizeL;
return symResult;
}
QSharedPointer<SymbolResult> SymbolDictionaryImpl::symbolPropertyImage(const SymbolProperties &symbolProperties, int sizeL) const
{
return symbolPropertyImage(QSharedPointer<SymbolResult>(new SymbolResult), symbolProperties, sizeL);
}
QStringList SymbolDictionaryImpl::cachedBaseSymbolCodes() const
{
return QStringList() << m_baseSymbolCodeToSymbolPropertyTable.keys() << m_etsSidcOrdered;
} // QStringList SymbolDictionaryImpl::cachedBaseSymbolCodes() const
SymbolProperties SymbolDictionaryImpl::symbolProperties(const QString &baseSymbolCode) const
{
auto it = m_baseSymbolCodeToSymbolPropertyTable.find(baseSymbolCode);
if (it != m_baseSymbolCodeToSymbolPropertyTable.end())
{
return it.value();
}
// try ets:
auto itEts = m_etsSidcSymbolProperties.find(baseSymbolCode);
if (itEts != m_etsSidcSymbolProperties.end())
{
return itEts.value();
}
// try xml
auto itXml = m_xmlSidcSymbolProperties.find(baseSymbolCode);
if (itXml != m_xmlSidcSymbolProperties.end())
{
return itXml.value();
}
return SymbolProperties();
}
QSharedPointer<SymbolResult> SymbolDictionaryImpl::fetchSymbol(const QString &sidc,
int sizeL) const
{
SymbolDataToRender symDataToRender;
symDataToRender.sidc = sidc;
symDataToRender.sizeL = sizeL;
return fetchSymbol(symDataToRender);
}
QSharedPointer<SymbolResult> SymbolDictionaryImpl::fetchSymbol(const SymbolDataToRender &symDataToRender) const
{
TRACE_LOG(m_logger) << LOGFUNCTION << " START"
<< " symDataToRender=" << symDataToRender.toString();
// const QString &sidc = symDataToRender.sidc;
const QString &sidc = symDataToRender.sidcAccordingRole();
if (!SidcCodec::isEncoded(sidc))
{
WARNING_LOG(m_logger) << LOGFUNCTION << " sidc not encoded: sidc= '" << sidc << "'";
return notFoundSymbolResult(symDataToRender);
}
// if (!SidcCodec::isEncoded(sidc))
// {
// if (!SidcCodec::compatibilityMode())
// {
// ERROR_LOG(m_logger) << LOGFUNCTION << " Wrong sidc codec" << " sidc= '" << sidc;
// return notFoundSymbolResult(symDataToRender.sizeL);
// }
// sidc = SidcCodec::compatibilityIsM25DSymbol(sidc) ? SidcCodec::encodeComplete(SymbologyType::MIL2525D,sidc) : SidcCodec::encodeCivilEts(sidc); // just for backwards compatibility
// }
const SidcCodec::SidcType sidcType = SidcCodec::decodeSidcType(sidc);
switch (sidcType)
{
case SidcCodec::SidcType::CivilEts :
{
//
// handle ETS Symbols
//
auto it = m_etsSidcImages.find(sidc);
if (it != m_etsSidcImages.end())
{
// Create SymbolResult as ret-value
QSharedPointer<SymbolResult> symResult = QSharedPointer<SymbolResult>(new SymbolResult);
// save some values from caller:
symResult->setSymbolDataToRender(symDataToRender);
// ETS-Symbols are always Points
symResult->setGeometryType(GeometryType::Point);
const QImage &extraImg = it.value(); // Ets -> scaling is done in renderExtensions
QColor colorToBeReplaced;
auto itSymbolProps = m_etsSidcSymbolProperties.find(sidc);
if (itSymbolProps != m_etsSidcSymbolProperties.end())
{
const SymbolProperties &symProps = itSymbolProps.value();
colorToBeReplaced = symProps.colorToBeReplaced();
}
#define FETCH_SYMBOL_ETS_CONCURRENT
#ifdef FETCH_SYMBOL_ETS_CONCURRENT
// symDataToRender contains flag 'symDataToRender'
symResult->setFuture(QtConcurrent::run(renderExtensions, extraImg, symDataToRender, colorToBeReplaced, symDataToRender.renderJustCoreImage));
#else
QImage imageCopy = extraImg;
imageCopy = renderExtensions(imageCopy, symDataToRender, colorToBeReplaced, symDataToRender.renderJustCoreImage);
SymbolImage symImage;
symImage.setImage(imageCopy);
symImage.setValid(true);
symResult->setSymbolImage(symImage);
symResult->fireResultReady(); // ToDo: maybe async!?!?
#endif // FETCH_SYMBOL_ETS_CONCURRENT
return symResult;
} // if (m_extraSidcImages.contains(sidc))
} break;
case SidcCodec::SidcType::CivilXml :
{
//
// OR XML Symbols
//
if (m_xmlSymbolCache)
{
if (m_xmlSymbols.containsSidc(SidcCodec::extractCivilXmlBaseSidc(sidc))) //// use only base-sidc to lookup symbol
{
QSharedPointer<SymbolResult> symResult = QSharedPointer<SymbolResult>(new SymbolResult);
symResult->setSymbolDataToRender(symDataToRender);
symResult->setGeometryType(GeometryType::Point);
/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
* Don't use async rendering here, because the image will be drawn with QGraphicsItems. This must
* be done in main thread othwise the application can crash.
* JT 2017/12/14
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
QImage image = renderXML_Symbol(m_xmlSymbolCache,
m_xmlSymbols,
symDataToRender,
symDataToRender.renderJustCoreImage);
SymbolImage symImage;
symImage.setImage(image);
symImage.setValid(!image.isNull());
symResult->setSymbolImage(symImage);
symResult->fireResultReady();
return symResult;
}
else
ERROR_LOG(m_logger) << LOGFUNCTION << " symbol must be inserted before usage (sidc=" << sidc << ")";
}
else
ERROR_LOG(m_logger) << LOGFUNCTION << " get instance of SymbologyXML::SymbolCacheWithTables failed.";
} break;
default:
{
//
// handle Esri-Dictionary
//
if (! m_esri_dictionary)
{
ERROR_LOG(m_logger) << LOGFUNCTION << " no esri_dictionary";
return notFoundSymbolResult(symDataToRender);
}
if (! isLoaded())
{
ERROR_LOG(m_logger) << LOGFUNCTION << " esri_dictionary not loaded";
return notFoundSymbolResult(symDataToRender);
}
const SymbologyType requestedSymType = SidcCodec::decodeSymbologyType(sidc);
if (requestedSymType != m_symbolDictionaryType_own)
{
ERROR_LOG(m_logger) << LOGFUNCTION << " requested SymbologyType is not available"
<< " (sidc = '" << sidc << "'"
<< ", symbolDictionaryType_own=" << m_symbolDictionaryType_own
<< ", decodeSymbologyType=" << SidcCodec::decodeSymbologyType(sidc) << ")";
// return notFoundSymbolResult(symDataToRender);
}
if (SidcCodec::SidcType::Complete != SidcCodec::decodeSidcType(sidc))
{
ERROR_LOG(m_logger) << LOGFUNCTION << " Sidc is not complete " << " sidc= '" << sidc;
return notFoundSymbolResult(symDataToRender);
}
// linear search - maybe optimize. But how many different icons are really rendered in parallel?
for (const QWeakPointer<SymbolResult> &res : qAsConst(m_findSymbol2symbolResult))
{
auto sp = res.toStrongRef();
if (!sp)
continue;
if (sp->symbolDataToRender() == symDataToRender)
{
DEBUG_LOG(m_logger) << "Found render request: " << sp.data();
return sp;
}
}
// Create SymbolResult as ret-value
QSharedPointer<SymbolResult> symResult = QSharedPointer<SymbolResult>(new SymbolResult);
symResult->setSymbolDataToRender(symDataToRender);
const QVariantMap keys({{QStringLiteral("sidc"), SidcCodec::decodeRawSidc(sidc)}, // set sidc of symbol in case of MIL2525
{QStringLiteral("sic"), SidcCodec::decodeRawSidc(sidc)}}); // set sidc of symbol in case of APP6
Esri::ArcGISRuntime::TaskWatcher tw = m_esri_dictionary->fetchSymbol(keys);
QUuid fsTaskId;
if (tw.isValid())
{
fsTaskId = tw.taskId();
if (doParanoiaChecks())
if (fsTaskId.isNull())
abort();
// store taskId in symResult:
symResult->setTaskId(fsTaskId);
// and put into map to be able to inform customer if swatch is completed:
m_findSymbol2symbolResult[fsTaskId] = symResult.toWeakRef();
DEBUG_LOG(m_logger) << LOGFUNCTION << " TaskWatcher valid: fsTaskId=" << fsTaskId;
}
else
{
ERROR_LOG(m_logger) << LOGFUNCTION << " TaskWatcher invalid"
<< " ThreadId=" << QThread::currentThreadId();
if (doParanoiaChecks())
abort();
}
TRACE_LOG(m_logger) << LOGFUNCTION << " END"
<< " symDataToRender=" << symDataToRender.toString()
<< " fsTaskId=" << fsTaskId;
return symResult;
}
} // switch(sidcType)
return notFoundSymbolResult(symDataToRender);
}
QSharedPointer<SymbolResult> SymbolDictionaryImpl::findImage(const SymbolDataToRender &symDataToRender) const
{
TRACE_LOG(m_logger) << LOGFUNCTION << " START"
<< " symDataToRender=" << symDataToRender.toString();
const QString &sidc = symDataToRender.sidc;
if (!SidcCodec::isEncoded(sidc))
{
WARNING_LOG(m_logger) << LOGFUNCTION << " sidc not encoded: sidc= '" << sidc << "'";
return notFoundSymbolResult(symDataToRender);
}
const QString &baseSymbolCode = SidcBuilderBase::concreteSidcToBaseSymbolCode(sidc);
//
// !isCivil && m_baseSymbolCodeToSymbolPropertyTable.contains(baseSymbolCode) &&
// (geoType == GeometryType::Polygon) || (geoType == GeometryType::Polyline)
// -> createSwatch()
//
if ((!SidcCodec::isCivil(sidc)) && m_baseSymbolCodeToSymbolPropertyTable.contains(baseSymbolCode))
{
const SymbolProperties &symbolProperties = m_baseSymbolCodeToSymbolPropertyTable[baseSymbolCode];
const GeometryType geoType = symbolProperties.geometryType();
if ((geoType == GeometryType::Polygon) || (geoType == GeometryType::Polyline))
{
// prepare SymbolResult as ret-value
QSharedPointer<SymbolResult> preparedSymResult = QSharedPointer<SymbolResult>(new SymbolResult);
// save some values from caller:
preparedSymResult->setSymbolDataToRender(symDataToRender);
QSharedPointer<SymbolResult> symResult = symbolPropertyImage(preparedSymResult, symbolProperties, symDataToRender.sizeL); // including GeometryType
return symResult;
}
}
TRACE_LOG(m_logger) << LOGFUNCTION << " END"
<< " symDataToRender=" << symDataToRender.toString();
return fetchSymbol(symDataToRender);
}
QSharedPointer<SymbolResult> SymbolDictionaryImpl::findPreview(const QString &sidc, int sizeL) const
{
TRACE_LOG(m_logger) << LOGFUNCTION << " START"
<< " sidc='" << sidc << "'";
SymbolDataToRender symDataToRender;
symDataToRender.role = Role::Neutral;
symDataToRender.fillColor = Qt::yellow; // for XML
symDataToRender.fillColor.setAlpha(128); // for XML
symDataToRender.sidc = sidc;
symDataToRender.sizeL = sizeL;
symDataToRender.renderJustCoreImage = true;
TRACE_LOG(m_logger) << LOGFUNCTION << " END"
<< " sidc='" << sidc << "'";
return findImage(symDataToRender); // maybe avoid to surrounding area (for Injury, NoPosition etc) for PointSymbols!?
}
QSharedPointer<SymbolResult> SymbolDictionaryImpl::findBaseSymbol(const QString &sidc) const
{
TRACE_LOG(m_logger) << LOGFUNCTION << " START"
<< " sidc_8or20chars='" << sidc << "'";
if (!SidcCodec::isEncoded(sidc))
{
WARNING_LOG(m_logger) << LOGFUNCTION << " sidc not encoded: sidc= '" << sidc << "'";
return notFoundSymbolResult();
}
SidcCodec::SidcType sidcType = SidcCodec::decodeSidcType(sidc);
switch(sidcType)
{
case SidcCodec::SidcType::CivilEts :
{
//
// handle ExtraDir
//
auto it = m_etsSidcImages.find(sidc);
if (it != m_etsSidcImages.end())
{
// Create SymbolResult as ret-value
QSharedPointer<SymbolResult> symResult = notFoundSymbolResult();
// save some values from caller:
symResult->setSymbolDataToRender(SymbolDataToRender(it.key()));
// ETS-Symbols are always Points
symResult->setGeometryType(GeometryType::Point);
const QImage &image = it.value();
SymbolImage symImage;
symImage.setImage(image);
symImage.setValid(true);
symResult->setSymbolImage(symImage);
symResult->fireResultReady(); // ToDo: maybe async!?!?
return symResult;
} // if (m_extraSidcImages.contains(sidc))
} break;
case SidcCodec::SidcType::CivilXml :
{
//
// OR handle XML symbols
//
if (m_xmlSymbolCache)
{
if (m_xmlSymbols.containsSidc(sidc))
{
SymbolDataToRender symRender(sidc);
int symWidth = qRound(symRender.sizeL*1.7);
int symHeight = qRound(symRender.sizeL*1.7);
QSharedPointer<SymbolResult> symResult = notFoundSymbolResult();
symResult->setSymbolDataToRender(symRender);
symResult->setGeometryType(GeometryType::Point);
const QImage image =
m_xmlSymbolCache-> getComponentPixmap(m_xmlSymbols[sidc],
SymbologyXML::PixmapSymbolCache::CacheType::CacheMainSymbols,
SymbologyXML::SymbolTypes::AdditionalSymbolData(),
QSize(symWidth,symHeight),
QColor(), /* const QColor& rgbaLine */
QColor() /* rgbaRole */ );
if (!image.isNull())
{
SymbolImage symImage;
QTransform flipVertical;
flipVertical.scale(1.0, -1.0);
symImage.setImage(image.transformed(flipVertical));
symImage.setValid(true);
symResult->setSymbolImage(symImage);
symResult->fireResultReady();
TRACE_LOG(m_logger) << LOGFUNCTION << " END" << " sidc='" << sidc << "'";
return symResult;
}
ERROR_LOG(m_logger) << LOGFUNCTION << "creating base symbol im from xml symbol failed (sidc=" << sidc << ")";
}
else ERROR_LOG(m_logger) << LOGFUNCTION << "symbol must be inserted before usage (sidc=" << sidc << ")";
}
else ERROR_LOG(m_logger) << LOGFUNCTION << "get instance of SymbologyXML::SymbolCacheWithTables failed.";
} break;
default:
{
//
// OR handle Esri-Dictionary
//
// If requested (encoded) sidc is CMPL, so convert to BASE:
QString baseSymbolCode = sidc;
if (SidcCodec::decodeSidcType(sidc) == SidcCodec::SidcType::Complete)
baseSymbolCode = SidcBuilderBase::concreteSidcToBaseSymbolCode(sidc);
if (m_baseSymbolCodeToSymbolPropertyTable.contains(baseSymbolCode))
{
const SymbolProperties &symbolProperties = m_baseSymbolCodeToSymbolPropertyTable[baseSymbolCode];
// prepare SymbolResult
QSharedPointer<SymbolResult> preparedSymResult = QSharedPointer<SymbolResult>(new SymbolResult);
// save some values from caller:
preparedSymResult->setSymbolDataToRender(SymbolDataToRender(baseSymbolCode));
// Create SymbolResult as ret-value
QSharedPointer<SymbolResult> symResult = symbolPropertyImage(preparedSymResult, symbolProperties); // including GeometryType
return symResult;
} // if (m_baseSymbolCodeToSymbolPropertyTable.contains(baseSymbolCode))
else
{
ERROR_LOG(m_logger) << LOGFUNCTION << " not found:"
<< " sidc='" << sidc << "'"
<< " baseSymbolCode='" << baseSymbolCode << "'";
}
} break;
} // switch(sidcType)
TRACE_LOG(m_logger) << LOGFUNCTION << " END"
<< " sidc='" << sidc << "'";
return notFoundSymbolResult();
}
void SymbolDictionaryImpl::onFetchSymbolCompleted(QUuid fsTaskId, Esri::ArcGISRuntime::Symbol *symbol)
{
TRACE_LOG(m_logger) << LOGFUNCTION << " START"
<< " symType= '" << this->symbologyType() << "'"
<< " fsTaskId= '" << fsTaskId << "'"
<< " symbol= '" << symbol << "'"
<< " ThreadId=" << QThread::currentThreadId();
if (! symbol)
{
ERROR_LOG(m_logger) << LOGFUNCTION << " START"
<< " symType= '" << this->symbologyType() << "'"
<< " fsTaskId= '" << fsTaskId << "'"
<< " no symbol!!!";
if (doParanoiaChecks())
abort();
return;
}
QSharedPointer<SymbolResult> symResult = m_findSymbol2symbolResult.value(fsTaskId);
if (!symResult)
{
// it´s legal, that the result does not exist anymore.
// Example: if used in a model::data(), the request occur very quickly.
// So the second request may be done before the first can be answered.
// So just a Debug msg:
DEBUG_LOG(m_logger) << LOGFUNCTION << " SymbolResult not found or already been deleted"
<< " fsTaskId= '" << fsTaskId << "'";
return;
}
//
// retrieve GeometryType :
//
const QString &sidc = symResult->symbolDataToRender().sidc;
// try baseSymbolCode
const QString &baseSymbolCode = SidcBuilderBase::concreteSidcToBaseSymbolCode(sidc);
DEBUG_LOG(m_logger) << LOGFUNCTION << " baseSymbolCode = '" << baseSymbolCode << "'";
if (m_baseSymbolCodeToSymbolPropertyTable.contains(baseSymbolCode))
{
const SymbolProperties &symbolProperties = m_baseSymbolCodeToSymbolPropertyTable[baseSymbolCode];
symResult->setGeometryType(symbolProperties.geometryType());
}
else
{
ERROR_LOG(m_logger) << LOGFUNCTION << " baseSymbolCode not found for sidc='" << sidc << "'"
<< ", baseSymbolCode= '" << baseSymbolCode << "'"
<< ", fsTaskId= '" << fsTaskId << "'";
}
// : retrieve GeometryType
// FATAL_LOG(m_logger) << LOGFUNCTION << " XXXXXXXXXX geometryType = " << symResult->geometryType();
//
// retrieve Image :
//
{
connect(symbol, &Esri::ArcGISRuntime::Symbol::createSwatchCompleted,
this, &SymbolDictionaryImpl::onSwatchCompleted);
#ifdef USE_ARCADE_SYMBOLOGY
Esri::ArcGISRuntime::TaskWatcher tw;
if (symResult->geometryType() == GeometryType::Polygon)
// area/Polygon -> request rectangle, otherwise quadratic swatch:
tw = symbol->createSwatch(CREATE_SWATCH_PARAMETER.m_width, CREATE_SWATCH_PARAMETER.m_height, CREATE_SWATCH_PARAMETER.m_screenScale);
else
tw = symbol->createSwatch(CREATE_SWATCH_PARAMETER.m_height, CREATE_SWATCH_PARAMETER.m_height, CREATE_SWATCH_PARAMETER.m_screenScale);
#else
Esri::ArcGISRuntime::TaskWatcher tw = symbol->createSwatch(CREATE_SWATCH_SCREEN_SCALE); // CREATE_SWATCH_SCREEN_SCALE
#endif // USE_ARCADE_SYMBOLOGY
QUuid csTaskId;
if (tw.isValid())
{
csTaskId = tw.taskId();
DEBUG_LOG(m_logger) << LOGFUNCTION << " csTaskWatcher valid: csTaskId=" << csTaskId;
if (doParanoiaChecks())
if (csTaskId.isNull())
abort();
}
else
{
ERROR_LOG(m_logger) << LOGFUNCTION << " csTaskWatcher invalid"
<< " ThreadId=" << QThread::currentThreadId();
if (doParanoiaChecks())
abort();
}
if (! csTaskId.isNull())
m_createSwatch2findSymbolTaskId[csTaskId] = fsTaskId;
else
ERROR_LOG(m_logger) << LOGFUNCTION << " csTaskWatcher invalid";
} // retrieve Image
TRACE_LOG(m_logger) << LOGFUNCTION << " END"
<< " fs-taskId= '" << fsTaskId << "'"
// << " cs-taskId= '" << csTaskId << "'"
<< " symbol= '" << symbol << "'";
}
void SymbolDictionaryImpl::onSwatchCompleted(const QUuid &csTaskId, const QImage &image)
{
TRACE_LOG(m_logger) << LOGFUNCTION << " START"
<< " symType= '" << this->symbologyType() << "'"
<< " csTaskId= '" << csTaskId << "'"
<< " image.isNull= '" << image.isNull() << "'"
<< " image.size()= '" << image.size().width() << " - " << image.size().height()
<< " image.colorTable().size()= '" << image.colorTable().size() << "'"
<< " ThreadId=" << QThread::currentThreadId();
auto it = m_createSwatch2findSymbolTaskId.find(csTaskId);
if (it == m_createSwatch2findSymbolTaskId.end())
{
ERROR_LOG(m_logger) << LOGFUNCTION << " no taskIdMapping"
<< " csTaskId= '" << csTaskId << "'";
if (doParanoiaChecks())
abort();
return;
}
// map to external (findSymbol) taskId
const QUuid &fsTaskId = it.value();
DEBUG_LOG(m_logger) << LOGFUNCTION << " START"
<< " fsTaskId= '" << fsTaskId << "'"
<< " csTaskId= '" << csTaskId << "'";
//// emit findSymbolCompleted(fsTaskId, image);
if (m_findSymbol2symbolResult.contains(fsTaskId))
{
DEBUG_LOG(m_logger) << LOGFUNCTION << " SymbolResult found..." << " fsTaskId= '" << fsTaskId << "'";
QSharedPointer<SymbolResult> symResult = m_findSymbol2symbolResult[fsTaskId];
if (symResult)
{
DEBUG_LOG(m_logger) << LOGFUNCTION << " SymbolResult found and still valid..."
<< " fsTaskId= '" << fsTaskId << "'";
const SymbolDataToRender &symToRender = symResult->symbolDataToRender();
// DEBUG_LOG(m_logger) << LOGFUNCTION << " sidc=" << symToRender.sidc << " image.size=" << image.width() << " - " << image.height();
// 'renderExtensions': maybe transfer to workerThread:
// N. Thoden, 2016-08-18:
// On my maschine (AS502541 with i7;3.5GHz;octa-core) 100 calls took ~60ms
// -> one call tooks ~0.6ms
#define CONCURRENT
#ifdef CONCURRENT
// start computation like:
// QFuture<T> QtConcurrent::run(Function function, arg1, arc2...)
// ^^^^^^^^^^ without()
symResult->setFuture(QtConcurrent::run(renderExtensions, image, symToRender, QColor(), symToRender.renderJustCoreImage));
#else // CONCURRENT
image = renderExtensions(image, symToRender, QColor(), symToRender.renderJustCoreImage);
SymbolImage symImage;
symImage.setImage(image);
symImage.setValid(true);
symResult->setSymbolImage(symImage);
symResult->fireResultReady(); // ToDo: maybe async!?!?
#endif // CONCURRENT
}
// else
// {
// // THis can happen in case of high number of request...
// DEBUG_LOG(m_logger) << LOGFUNCTION << " SymbolResult has already been deleted" << " fsTaskId= '" << fsTaskId << "'";
// }
// cleanup
m_findSymbol2symbolResult.remove(fsTaskId);
}
else
{
ERROR_LOG(m_logger) << LOGFUNCTION << " no taskIdMapping"
<< " csTaskId= '" << csTaskId << "'";
if (doParanoiaChecks())
abort();
}
// cleanup
m_createSwatch2findSymbolTaskId.erase(it);
// see also: "SymbolDictionary - findSymbolCompleted without taskId"
// https://earlyadopter.esri.com/project/forum/thread.html?cap=FA3A32558952489280FB472D26FA8192&forid={A612A2F3-E344-4BD0-A1EA-0CE2DA5E694E}&topid={432F3A6B-E323-4628-BF39-77DB7BAAC9A1}
Esri::ArcGISRuntime::Symbol *symbol = qobject_cast<Esri::ArcGISRuntime::Symbol *>(sender());
if (symbol)
symbol->deleteLater();
TRACE_LOG(m_logger) << LOGFUNCTION << " END"
<< " symType= '" << this->symbologyType() << "'"
<< " csTaskId= '" << csTaskId << "'";
}
QImage renderXML_Symbol(const QSharedPointer<SymbologyXML::PixmapSymbolCache> &xmlSymbolCache,
const SidcCodec::SidcHashTable<SymbologyXML::Symbol> &xmlSymbols,
const SymbolDataToRender &symbolDataToRender,
bool renderJustCoreImage)
{
const QString &sidc = symbolDataToRender.sidc;
const QColor &roleColor = symbolDataToRender.fillColor;
const QColor &injuryColor = symbolDataToRender.injuryColor;
SymbologyXML::SymbolTypes::t_state state = SymbologyXML::SymbolTypes::STATE_UNDEFINED;
SymbologyXML::SymbolTypes::t_uncertainty uncertainty = SymbologyXML::SymbolTypes::UNCERTAINTY_UNDEFINED;
SymbologyXML::SymbolTypes::t_affil affil = SymbologyXML::SymbolTypes::AFFIL_UNDEFINED;
SymbologyXML::SymbolTypes::t_mob mob = SymbologyXML::SymbolTypes::MOB_UNDEFINED;
SymbologyXML::SymbolTypes::AdditionalSymbolData additionalSymbolData;
const QString & rawSidc = SidcCodec::decodeRawSidc(sidc);
QString symbolId;
SymbologyXML::Symbol xmlSymbol;
if (SymbologyXML::xmlSymbolDecodeId(rawSidc,symbolId,state,uncertainty,affil,mob))
{
xmlSymbol = xmlSymbols[SidcCodec::encodeCivilXml(symbolId)];
xmlSymbol.setAffil( affil );
xmlSymbol.setMob( mob );
additionalSymbolData.m_state = state;
additionalSymbolData.m_uncertainty = uncertainty;
}
else
{
xmlSymbol = xmlSymbols[sidc]; // use base symbol
additionalSymbolData.m_state = SymbologyXML::SymbolTypes::STATE_PRESENT;
additionalSymbolData.m_uncertainty = SymbologyXML::SymbolTypes::UNCERTAINTY_UNDEFINED;
}
double symbolScale = symbolDataToRender.sizeL * 1.7 * ((xmlSymbol.getScale() > 0) ? xmlSymbol.getScale() : 1.0);
const QSize &imgSize = QSize(symbolScale, symbolScale);
// transfer symbolDataToRender.role to xmlSymbol.affiliation:
// ToDo: distinguish using role from Sidc or from symbolDataToRender
if (SymbologyXML::SymbolTypes::AFFIL_UNDEFINED == affil)
{
xmlSymbol.setAffil( SymbologyXML::Symbol::roleToAffiliation(symbolDataToRender.role) );
}
additionalSymbolData.m_filltype = SymbologyXML::SymbolTypes::FILLTYPE_FILLED;
additionalSymbolData.m_scale = SymbologyXML::SymbolTypes::SCALE_UNDEFINED;
if (!renderJustCoreImage)
{
switch(symbolDataToRender.injury)
{
case Injury::Hit : additionalSymbolData.m_vbg.vbg = SymbologyXML::SymbolTypes::vbg_et::MITTLERER_TREFFER; break;
case Injury::MobilityKill : additionalSymbolData.m_vbg.vbg = SymbologyXML::SymbolTypes::vbg_et::BEWEGUNGSUNFAEHIG; break;
case Injury::WeaponKill : additionalSymbolData.m_vbg.vbg = SymbologyXML::SymbolTypes::vbg_et::AUSFALL_WAFFENANLAGE; break;
case Injury::TotalKill : additionalSymbolData.m_vbg.vbg = SymbologyXML::SymbolTypes::vbg_et::TOTALAUSFALL; break;
case Injury::NoInjury :
default : additionalSymbolData.m_vbg.vbg = SymbologyXML::SymbolTypes::vbg_et::EINSATZBEREIT; break;
}
additionalSymbolData.m_vbg.color = injuryColor;
for (const AdditionalSymbolType additionalSymbolType : qAsConst(symbolDataToRender.additionalSymbols))
{
switch (additionalSymbolType)
{
case AdditionalSymbolType::Manipulation : additionalSymbolData.m_modifier.setManipulation(true); break;
case AdditionalSymbolType::NoPosition : additionalSymbolData.m_modifier.setNoPosition(true); break;
case AdditionalSymbolType::BiteError : additionalSymbolData.m_modifier.setByteError(true); break;
case AdditionalSymbolType::NbcProtection : additionalSymbolData.m_modifier.setNbcProtection(true); break;
default : break;
}
}
}
QImage image = xmlSymbolCache->getPixmap(xmlSymbol,
additionalSymbolData,
imgSize,
QColor(0,0,0), /* const QColor& rgbaLine */
roleColor, /* rgbaRole */
true, true);
if (image.isNull())
{
LOGGER_T m_logger = getLogger("SymbolDictionaryImpl");
ERROR_LOG(m_logger) << LOGFUNCTION << " render XML symbol (sidc='" << sidc <<"') failed.";
return QImage();
}
if (symbolDataToRender.marking)
{
QImage fullImage(image.width(), image.height(), QImage::Format_ARGB32);
fullImage.fill(Qt::transparent);
// TODO: check
ExtensionRenderer::renderMarking(fullImage, roleColor);
QPainter painter(&fullImage);
painter.drawImage(image.rect(), image, image.rect());
painter.end();
return fullImage;
}
return image;
} // QImage renderXML_Symbol(...)
QImage renderExtensions(QImage &coreImage,
const SymbolDataToRender &symbolDataToRender,
const QColor &colorToBeReplaced,
bool renderJustCoreImage)
{
LOGGER_T m_logger = getLogger("SymbolDictionaryImpl");
TRACE_LOG(m_logger) << LOGFUNCTION << " START"
<< " ThreadId=" << QThread::currentThreadId()
<< " symbolDataToRender= " << symbolDataToRender.toString();
if (coreImage.isNull())
WARNING_LOG(m_logger) << LOGFUNCTION << " coreImage.isNull";
if (symbolDataToRender.sizeL <= 0)
WARNING_LOG(m_logger) << LOGFUNCTION << " sizeL is <= 0! sizeL=" << symbolDataToRender.sizeL;
// manual delay :
//QThread::msleep(1000);
// : manual delay
const QString &sidc = symbolDataToRender.sidcAccordingRole();
//
// Prepare FullImage
//
QImage fullImage = ExtensionRenderer::createFullImage(symbolDataToRender.sizeL);
bool isEts = (SidcCodec::SidcType::CivilEts == SidcCodec::decodeSidcType(sidc));
//
// CoreImage
//
//
// CoreImage: replace Color:
//
if (symbolDataToRender.fillColorReplace)
{
// oldColor
QVector<QColor> oldColorVec;
if (isEts)
{
if (colorToBeReplaced.isValid())
oldColorVec.append(colorToBeReplaced);
else
ERROR_LOG(m_logger) << LOGFUNCTION << " colorToBeReplaced is invalid"
<< " sidc=" << symbolDataToRender.sidc;
}
else
oldColorVec = ExtensionRenderer::identityToColor(sidc);
// coreImage.save(QLatin1String("/tmp/dummy.png"));
for (const QColor &oldColor : qAsConst(oldColorVec))
{
if (oldColor.isValid())
{
if (ExtensionRenderer::replaceColor(coreImage,
oldColor.rgba(),
symbolDataToRender.fillColor.rgba()))
break; // finish loop, if first oldColor was found (and image is modfied)
}
else
{
ERROR_LOG(m_logger) << LOGFUNCTION
<< " sidc='" << symbolDataToRender.sidc << "', identityToColor failed";
}
}
} // if (symbolDataToRender.fillColorReplace)
//
// CoreImage: Scale coreImage (to fit into fullImage):
//
QSize newSize;
if (isEts)
{
newSize = fullImage.size(); // ETS has more height then width
}
else
{
#ifdef USE_ARCADE_SYMBOLOGY
newSize = fullImage.size();
#else
Q_DECL_CONSTEXPR double esriL = (CREATE_SWATCH_SCREEN_SCALE * 20) * 1.3; // to let the big clover&diamond (incl. echelon) fit into the marking rect
// ( 5 * 20) * 1.15 = 115
newSize = coreImage.size() * static_cast<double>(symbolDataToRender.sizeL) / esriL;
#endif // USE_ARCADE_SYMBOLOGY
// replace honoring the hotSpot by simple scaling :
int hqFdTf = QStringRef(&sidc, 7, 1).toInt();
// int amplifierDescriptor = QStringRef(&sidc, 8, 2).toInt();
if (((hqFdTf > 0) && ((hqFdTf < 8)))) // HeadQuarter/FeintDummy/TaskFore have more height then width
newSize = fullImage.size();
// : replace honoring the hotSpot by simple scaling
} // if (isEts)
// scale
coreImage = coreImage.scaled(newSize, Qt::KeepAspectRatio, Qt::SmoothTransformation);
if (coreImage.isNull())
WARNING_LOG(m_logger) << LOGFUNCTION << " image isNull ";
// Just CoreImage?
if (renderJustCoreImage)
return coreImage;
//
// FullImage: 1. create Marking:
//
if (symbolDataToRender.marking)
ExtensionRenderer::renderMarking(fullImage, symbolDataToRender.fillColor);
//
// FullImage: 2. merge CoreImage
//
ExtensionRenderer::mergeCoreImageIntoFullImage(fullImage, coreImage);
//
// FullImage: 5. Injury and AddOns:
//
ExtensionRenderer::renderInjuryAddSymbols(fullImage,
symbolDataToRender.injury,
symbolDataToRender.injuryColor,
symbolDataToRender.additionalSymbols,
symbolDataToRender.fillColor);
if (fullImage.isNull())
WARNING_LOG(m_logger) << LOGFUNCTION << " fullImage is Null!";
TRACE_LOG(m_logger) << LOGFUNCTION << " END"
<< " ThreadId=" << QThread::currentThreadId()
<< " symbolDataToRender= " << symbolDataToRender.toString();
return fullImage;
}
QStringList SymbolDictionaryImpl::symbolModifierKeys() const
{
if (!m_esriDictionaryProcessor)
return QStringList();
return m_esriDictionaryProcessor->symbolModifierKeys();
}
bool SymbolDictionaryImpl::symbolModifierData(const QString &key, ModifierData &data) const
{
if (!m_esriDictionaryProcessor)
return false;
return m_esriDictionaryProcessor->symbolModifierData(key, data);
}
QList<ModifierData> SymbolDictionaryImpl::symbolModifierList(SidcDefinitions::SymbolSet symbolSet, unsigned int modifierSector) const
{
if (!m_esriDictionaryProcessor)
return QList<ModifierData>();
return m_esriDictionaryProcessor->symbolModifierList(symbolSet, modifierSector).toList();
}
QList<ModifierData> SymbolDictionaryImpl::symbolModifierList(const QString &baseSymbolCode, unsigned int modifierSector) const
{
if (!m_esriDictionaryProcessor)
return QList<ModifierData>();
// check baseSymbolCode, must contains 8 digits
if (!QRegExp(QStringLiteral("^[0-9]{8,8}$")).exactMatch(baseSymbolCode))
{
ERROR_LOG(m_logger) << LOGFUNCTION << " Invalid baseSymbolCode \"" << baseSymbolCode << "\". Must be made up of 8 digits.";
return QList<ModifierData>();
}
SidcDefinitions::SymbolSet symbolSetBaseCode = SidcDefinitions::castToSymbolSet(baseSymbolCode.midRef(0, 2).toUInt());
return m_esriDictionaryProcessor->symbolModifierList(symbolSetBaseCode, modifierSector).toList();
}
int SymbolDictionaryImpl::symbologySpecificCount() const
{
TRACE_LOG(m_logger) << LOGFUNCTION << " START";
int count = m_baseSymbolCodeToSymbolPropertyTable.size();
TRACE_LOG(m_logger) << LOGFUNCTION << " END" << " count=" << count;
return count;
}
bool SymbolDictionaryImpl::insertXmlTestSymbol(const SymbolProperties &symbolProps)
{
QString xmlString = QString::fromUtf8
( R"XML(<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE symboltable SYSTEM "symbole.dtd">
<symbol version="2.0" id="4711" dimen="undefined" affil="undefined" transformed="0" bcdab="undefined" command_level="undefined" headquarter="false" mob="undefined" vehicle="undefined" intrinsicmob="undefined" arming="undefined" >
<name>test_lines</name>
<app6class classname="" classhierarchy="" classcodeid="" />
<text3 maxdatalength="6">
<data align="center"></data>
<data align="center"></data>
<data align="center"></data>
</text3>
<graphic scale="4">
<line transform="false" rotate="0" color="#ff0000ff" linewidth="0.2" linestyle="solid">
<point x="-1" y="0"/>
<point x="-1" y="1"/>
</line>
<line transform="false" rotate="0" color="#00ff00ff" linewidth="0.2" linestyle="solid">
<point x="-1" y="0"/>
<point x="1" y="0"/>
</line>
<line transform="false" rotate="0" color="#0000ffff" linewidth="0.2" linestyle="solid">
<point x="-1" y="-1"/>
<point x="1" y="1"/>
</line>
<line transform="false" rotate="0" color="#000000ff" linewidth="0.2" linestyle="solid">
<point x="-1.5" y="-1.5"/>
<point x="1.5" y="-1.5"/>
</line>
<line transform="false" rotate="0" color="#000000ff" linewidth="0.2" linestyle="solid">
<point x="1.5" y="-1.5"/>
<point x="1.5" y="-1.5"/>
</line>
<line transform="false" rotate="0" color="#000000ff" linewidth="0.2" linestyle="solid">
<point x="1.5" y="1.5"/>
<point x="-1.5" y="1.5"/>
</line>
<line transform="false" rotate="0" color="#000000ff" linewidth="0.2" linestyle="solid">
<point x="-1.5" y="1.5"/>
<point x="-1.5" y="-1.5"/>
</line>
</graphic>
</symbol>)XML" );
return setXmlSymbol(4711,
QLatin1String("Name"),
QLatin1String("OperatorTestSymbol"),
0,
xmlString,
symbolProps);
}
bool SymbolDictionaryImpl::insertXmlComplexTestSymbol(const SymbolProperties &symbolProps)
{
QString xmlString = QString::fromUtf8
( R"XML(<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE symboltable SYSTEM "symbole.dtd">
<symbol version="2.0" id="815" dimen="land_units" affil="friend" transformed="0" bcdab="bcdab_task_force_company" command_level="undefined" headquarter="false" mob="mob_wheel_all_terrain" vehicle="undefined" intrinsicmob="undefined" arming="undefined" >
<name>test complex symbol</name>
<app6class classname="" classhierarchy="" classcodeid="" />
<branch class="branch_theatre_echelons_above_corps" />
<text3 maxdatalength="6">
<data align="center"></data>
<data align="center"></data>
<data align="center"></data>
</text3>
<graphic scale="4">
<icon transform="false" rotate="0" color="#000000ff" linewidth="0.1" linestyle="solid" position="sectorMain" rectpos="large" id="8" icon_type="icon_type_vehicle">
</icon>
<ellipse transform="false" rotate="0" color="#0000ffff" linewidth="0.08" linestyle="solid" closed="1" start="0" extent="360" fill="0">
<point x="-1" y="0.991379"/>
<point x="1" y="-1.00862"/>
</ellipse>
<icon transform="false" rotate="0" color="#000000ff" linewidth="0.1" linestyle="solid" position="sectorMain" id="266244" icon_type="icon_type_secicon">
</icon>
<icon transform="false" rotate="0" color="#000000ff" linewidth="0.008" linestyle="solid" position="sector1" id="135177" icon_type="icon_type_secicon">
<point x="-0.7" y="0.572414"/>
<point x="0.7" y="0.872414"/>
</icon>
</graphic>
</symbol>
)XML" );
return setXmlSymbol(4712, QLatin1String("Name"), QLatin1String("OperatorComplexSymbol"), 0, xmlString, symbolProps);
}
int SymbolDictionaryImpl::count() const
{
return symbologySpecificCount() + etsSymbolCount() + xmlSymbolCount();
}
QString SymbolDictionaryImpl::toString() const
{
QString str;
str.append(QStringLiteral(" m_specificationType='%1'").arg(m_specificationType));
str.append(QStringLiteral(" SymbologyType=%1").arg(AdvancedSymbology::toString(m_symbolDictionaryType_own)));
str.append(QStringLiteral(" m_symbologyResourcePath='%1'").arg(m_symbologyResourcePath));
str.append(QStringLiteral(" m_createSwatch2findSymbolTaskId.size=%1").arg(m_createSwatch2findSymbolTaskId.size()));
str.append(QStringLiteral(" m_findSymbol2symbolResult.size=%1").arg(m_findSymbol2symbolResult.size()));
return str;
}
QStringList SymbolDictionaryImpl::symbologyFieldNamesInternal() const
{
if (!m_esri_dictionary)
return QStringList();
return m_esri_dictionary->symbologyFieldNames();
}
QStringList SymbolDictionaryImpl::textFieldNamesInternal() const
{
if (!m_esri_dictionary)
return QStringList();
return m_esri_dictionary->textFieldNames();
}
void SymbolDictionaryImpl::onErrorDictionary(const Esri::ArcGISRuntime::Error &error)
{
FATAL_LOG(m_logger) << LOGFUNCTION << " ---EsriError--- occured: "
<< " code=" << error.code()
<< ", domain=" << static_cast<int>(error.domain())
<< ", extendedErrorType=" << static_cast<int>(error.extendedErrorType())
<< ", message='" << error.message() << "'"
<< ", additionalMessage='" << error.additionalMessage() << "'";
}
int minNumberOfPoints(GeometryType gt)
{
switch (gt)
{
case GeometryType::Undefined:
return -1;
case GeometryType::Point:
return 1;
case GeometryType::Polyline:
return 2;
case GeometryType::Polygon:
return 3;
}
return -1;
}
//-----------------------------------------------------------------------------
// output operator:
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
QString toString(LoadStatus type)
{
switch (type)
{
case LoadStatus::Loaded:
return QLatin1String("Loaded");
case LoadStatus::Loading:
return QLatin1String("Loading");
case LoadStatus::FailedToLoad:
return QLatin1String("FailedToLoad");
case LoadStatus::NotLoaded:
return QLatin1String("NotLoaded");
case LoadStatus::Unknown:
return QLatin1String("Unknown");
} // switch
return QLatin1String("LoadStatusToStringERROR");
}
//-----------------------------------------------------------------------------
QString toString(SymbologyType type)
{
switch (type)
{
case SymbologyType::None:
return QLatin1String("None");
case SymbologyType::MIL2525C:
return QLatin1String("MIL2525C");
case SymbologyType::APP6B:
return QLatin1String("APP-6(B)");
case SymbologyType::APP6D:
return QLatin1String("APP-6(D)");
case SymbologyType::MIL2525D:
return QLatin1String("MIL2525D");
} // switch
return QLatin1String("symbologyToStringERROR");
}
bool fromString(SymbologyType &symbologyType, const QString &str)
{
if (str.compare(QLatin1String("NONE"), Qt::CaseInsensitive) == 0)
{
symbologyType = SymbologyType::None;
return true;
}
if (str.compare(QLatin1String("APP6B"), Qt::CaseInsensitive) == 0)
{
symbologyType = SymbologyType::APP6B;
return true;
}
if (str.compare(QLatin1String("APP6D"), Qt::CaseInsensitive) == 0)
{
symbologyType = SymbologyType::APP6D;
return true;
}
if (str.compare(QLatin1String("MIL2525C"), Qt::CaseInsensitive) == 0)
{
symbologyType = SymbologyType::MIL2525C;
return true;
}
if (str.compare(QLatin1String("MIL2525D"), Qt::CaseInsensitive) == 0)
{
symbologyType = SymbologyType::MIL2525D;
return true;
}
return false;
}
QString toString(AdvancedSymbology::GeometryType gt)
{
switch (gt)
{
case GeometryType::Undefined:
return QLatin1String("Undefined");
case GeometryType::Point:
return QLatin1String("Point");
case GeometryType::Polyline:
return QLatin1String("Polyline");
case GeometryType::Polygon:
return QLatin1String("Polygon");
}
return QLatin1String("geometryTypeToStringERROR");
}
//-----------------------------------------------------------------------------
QString toString(AdvancedSymbology::Role value)
{
switch (value)
{
case Role::Pending:
return QLatin1String("Pending");
case Role::Unknown:
return QLatin1String("Unknown");
case Role::AssumedFriend:
return QLatin1String("AssumedFriend");
case Role::Friend:
return QLatin1String("Friend");
case Role::Neutral:
return QLatin1String("Neutral");
case Role::SuspectJoker:
return QLatin1String("SuspectJoker");
case Role::HostileFaker:
return QLatin1String("HostileFaker");
} // switch
return QLatin1String("ERROR-Role");
}
std::ostream &operator<<(std::ostream &stream, const AdvancedSymbology::Role &value)
{
stream << AdvancedSymbology::toString(value);
return stream;
}
std::ostream &operator<<(std::ostream &stream, const AdvancedSymbology::LoadStatus &value)
{
stream << AdvancedSymbology::toString(value);
return stream;
}
std::ostream &operator<<(std::ostream &stream, const AdvancedSymbology::GeometryType &value)
{
stream << AdvancedSymbology::toString(value);
return stream;
}
std::ostream &operator<<(std::ostream &stream, const AdvancedSymbology::SymbologyType &value)
{
stream << AdvancedSymbology::toString(value);
return stream;
}
} // namespace AdvancedSymbology