2520 lines
91 KiB
C++
Executable File
2520 lines
91 KiB
C++
Executable File
/**
|
||
* @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 ®Exp, const QStringList ®ExStrings, 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 ®Exp, const QString ®ExString, 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
|
||
|