Port SymbologyImpl Esri processors to the ArcGIS 300 QFuture async API
TaskWatcher (searchSymbols/fetchSymbol/createSwatch + completion signals) -> QFuture (searchSymbolsAsync/fetchSymbolAsync/createSwatchAsync + QFutureWatcher finished/result getter); flat arcgis/ includes; arcgisversion.h shim (external SDK). advancedSymbology now builds+links vs 300 (0 errors); SymbologyXML CTest 6/6, 0 assertion failures. Migration-only vs legacy; one documented forced delta: 300 has no spec-only DictionarySymbolStyle. Summary: MIGRATION_SUMMARY_ARCGIS300_SYMBOLOGY.md.
This commit is contained in:
13 files changed
+512
-157
No files matched your search
+2
-2
@@ -11,8 +11,8 @@
|
||||
|
||||
#include <CentralEffectSimulation/logger.h>
|
||||
|
||||
#include <arcgis/PolygonBuilder.h>
|
||||
#include <arcgis/GeometryEngine.h>
|
||||
#include <PolygonBuilder.h>
|
||||
#include <GeometryEngine.h>
|
||||
|
||||
namespace CesExplosions
|
||||
{
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
#include "situation_map_types.h"
|
||||
#include <Common/situation_map_logging.h>
|
||||
|
||||
#include <arcgis/arcgisversion.h> // This file is created by RME, not ESRI
|
||||
#include <arcgisversion.h> // This file is created by RME, not ESRI
|
||||
|
||||
// Qt
|
||||
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
#include <Rubberbands/event_mouse_navigator.h>
|
||||
#include <LtsCoordTrans/lts_coord_trans.h>
|
||||
|
||||
#include <arcgis/arcgisversion.h> // This file is created by RME, not ESRI
|
||||
#include <arcgisversion.h> // This file is created by RME, not ESRI
|
||||
|
||||
#include <QtCore/QCoreApplication>
|
||||
#include <QtCore/QJsonDocument>
|
||||
|
||||
@@ -12,13 +12,13 @@
|
||||
|
||||
|
||||
// Esri
|
||||
#include <arcgis/CoreTypes.h> // for LicenseStatus
|
||||
#include <arcgis/MapTypes.h>
|
||||
#include <arcgis/Viewpoint.h>
|
||||
#include <arcgis/Camera.h>
|
||||
#include <CoreTypes.h> // for LicenseStatus
|
||||
#include <MapTypes.h>
|
||||
#include <Viewpoint.h>
|
||||
#include <Camera.h>
|
||||
|
||||
|
||||
#include <arcgis/arcgisversion.h> // This file is created by RME, not ESRI
|
||||
#include <arcgisversion.h> // This file is created by RME, not ESRI
|
||||
|
||||
#if ACRGIS_VERSION >= 0x640600 // 100.6.0 / Update 6
|
||||
#define HAS_SURFACEPLACEMENT_RELATIVETOSCENE
|
||||
|
||||
@@ -13,8 +13,8 @@
|
||||
|
||||
|
||||
// arcgis
|
||||
#include <arcgis/SceneViewTypes.h> // SurfacePlacement
|
||||
#include <arcgis/Error.h>
|
||||
#include <SceneViewTypes.h> // SurfacePlacement
|
||||
#include <Error.h>
|
||||
|
||||
|
||||
// Qt
|
||||
|
||||
+1
-1
@@ -26,7 +26,7 @@ class QValidator;
|
||||
|
||||
|
||||
#ifdef BUILD_ARCGIS
|
||||
# include <arcgis/arcgisversion.h> // This file is created by RME, not ESRI
|
||||
# include <arcgisversion.h> // This file is created by RME, not ESRI (300: flat include layout, no arcgis/ subdir)
|
||||
|
||||
#if ACRGIS_VERSION >= 0x640600 // 100.6.0 / Update 6
|
||||
//# define USE_ARCADE_SYMBOLOGY
|
||||
|
||||
+93
-40
@@ -18,8 +18,9 @@
|
||||
|
||||
|
||||
// arcgis
|
||||
#include <TaskWatcher.h>
|
||||
#include <DictionarySymbolStyle.h>
|
||||
#include <MapTypes.h> // Esri::ArcGISRuntime::LoadStatus (300: enum class; Loadable.h only forward-declares it)
|
||||
#include <Error.h> // Esri::ArcGISRuntime::Error (complete type; 300 dropped Error::code())
|
||||
|
||||
|
||||
// Qt
|
||||
@@ -31,6 +32,9 @@
|
||||
#include <utility>
|
||||
#include <QMimeData>
|
||||
#include <QtCore/QTimer>
|
||||
#include <QtCore/QFuture>
|
||||
#include <QtCore/QFutureWatcher>
|
||||
#include <QtGui/QImage>
|
||||
|
||||
|
||||
namespace AdvancedSymbology
|
||||
@@ -159,7 +163,7 @@ QString BaseSymbolItem::symbolSet()
|
||||
{
|
||||
if (m_symbolSet.isEmpty())
|
||||
{
|
||||
SidcDefinitions::SymbolSet symbolSet = SidcDefinitions::castToSymbolSet(m_symbolProperties.originalKey().left(2).toUInt() // Qt6: leftRef removed);
|
||||
SidcDefinitions::SymbolSet symbolSet = SidcDefinitions::castToSymbolSet(m_symbolProperties.originalKey().left(2).toUInt()); // Qt6: leftRef(2) removed
|
||||
m_symbolSet = QString(QStringLiteral("%1 - ")).arg(static_cast<int>(symbolSet)) + AdvancedSymbology::SidcDefinitions::toString(symbolSet);
|
||||
}
|
||||
return m_symbolSet;
|
||||
@@ -167,7 +171,7 @@ QString BaseSymbolItem::symbolSet()
|
||||
|
||||
int BaseSymbolItem::symbolSetAsInt()
|
||||
{
|
||||
return static_cast<int>(SidcDefinitions::castToSymbolSet(m_symbolProperties.originalKey().left(2).toUInt() // Qt6: leftRef removed));
|
||||
return static_cast<int>(SidcDefinitions::castToSymbolSet(m_symbolProperties.originalKey().left(2).toUInt())); // Qt6: leftRef(2) removed
|
||||
}
|
||||
|
||||
|
||||
@@ -222,23 +226,32 @@ QImage BaseSymbolItem::getSearchSwatch()
|
||||
// qCritical() << " SEARCH: id=" << m_id << " create swatch now";
|
||||
// qCritical() << " SEARCH: id=" << m_esriSearch.m_esriSymbol->toJson();
|
||||
|
||||
connect(m_esriSearch.m_esriSymbol, &Esri::ArcGISRuntime::Symbol::createSwatchCompleted,
|
||||
this, &BaseSymbolItem::onEsriSearchSymbolSwatchCompleted, Qt::UniqueConnection);
|
||||
|
||||
const Esri::ArcGISRuntime::TaskWatcher &tw = m_esriSearch.m_esriSymbol->createSwatch(SWATCH_SIZE, SWATCH_SIZE, 1);
|
||||
if (tw.isValid())
|
||||
m_esriSearch.m_esriTaskUuid = tw.taskId();
|
||||
// ArcGIS 300: no TaskWatcher / createSwatchCompleted — createSwatchAsync() returns a
|
||||
// QFuture<QImage>; a per-request QFutureWatcher delivers the QImage on the main thread.
|
||||
const QFuture<QImage> fut = m_esriSearch.m_esriSymbol->createSwatchAsync(SWATCH_SIZE, SWATCH_SIZE, 1);
|
||||
if (fut.isValid())
|
||||
{
|
||||
m_esriSearch.m_esriTaskUuid = QUuid::createUuid(); // in-flight guard (was the 100.x task id)
|
||||
QFutureWatcher<QImage> *watcher = new QFutureWatcher<QImage>(this);
|
||||
watcher->setFuture(fut);
|
||||
// 300/Qt6: the 'result' signal is name-collision-ambiguous with the result() getter (QOverload
|
||||
// can't disambiguate); connect to the unambiguous finished() signal and read the value via the
|
||||
// result() getter (the future is finished when finished() fires).
|
||||
connect(watcher, &QFutureWatcher<QImage>::finished, watcher,
|
||||
[this, watcher] {
|
||||
onEsriSearchSymbolSwatchCompleted(watcher->result());
|
||||
watcher->deleteLater();
|
||||
});
|
||||
}
|
||||
else
|
||||
qCritical() << " SEARCH: id=" << m_id << " taskId invalid";
|
||||
qCritical() << " SEARCH: id=" << m_id << " createSwatchAsync future invalid";
|
||||
}
|
||||
return m_esriSearch.m_esriSwatch;
|
||||
}
|
||||
|
||||
void BaseSymbolItem::onEsriSearchSymbolSwatchCompleted(const QUuid &taskId, const QImage &image)
|
||||
void BaseSymbolItem::onEsriSearchSymbolSwatchCompleted(const QImage &image)
|
||||
{
|
||||
if (m_esriSearch.m_esriTaskUuid != taskId)
|
||||
return;
|
||||
|
||||
// ArcGIS 300: the dedicated QFutureWatcher makes the (removed) taskId stale-check unnecessary.
|
||||
m_esriSearch.m_esriSwatch = image;
|
||||
|
||||
emit dataChanged(m_id);
|
||||
@@ -251,9 +264,6 @@ QImage BaseSymbolItem::getFetchSwatch() const
|
||||
|
||||
if (m_esriFetch.m_esriSwatch.isNull() && m_esriFetch.m_esriFetchTaskIdUuid.isNull())
|
||||
{
|
||||
connect(m_esriDictionary, &Esri::ArcGISRuntime::DictionarySymbolStyle::fetchSymbolCompleted,
|
||||
this, &BaseSymbolItem::onEsriFetchCompleted, Qt::UniqueConnection);
|
||||
|
||||
// from key8 to sidc (20 digits)
|
||||
const QString &key8 = m_symbolProperties.key().left(8);
|
||||
|
||||
@@ -272,39 +282,57 @@ QImage BaseSymbolItem::getFetchSwatch() const
|
||||
const QVariantMap keys({{QStringLiteral("sidc"), m_esriFetch.m_sidc}, // SidcCodec::decodeRawSidc ; set sidc of symbol in case of MIL2525
|
||||
{QStringLiteral("sic"), m_esriFetch.m_sidc}}); // SidcCodec::decodeRawSidc , set sidc of symbol in case of APP6
|
||||
|
||||
const Esri::ArcGISRuntime::TaskWatcher &tw = m_esriDictionary->fetchSymbol(keys);
|
||||
if (tw.isValid())
|
||||
m_esriFetch.m_esriFetchTaskIdUuid = tw.taskId();
|
||||
// ArcGIS 300: no TaskWatcher / fetchSymbolCompleted — fetchSymbolAsync() returns a
|
||||
// QFuture<Symbol*>; a per-request QFutureWatcher delivers the Symbol* on the main thread.
|
||||
const QFuture<Esri::ArcGISRuntime::Symbol *> fut = m_esriDictionary->fetchSymbolAsync(keys);
|
||||
if (fut.isValid())
|
||||
{
|
||||
m_esriFetch.m_esriFetchTaskIdUuid = QUuid::createUuid(); // in-flight guard (was the 100.x task id)
|
||||
|
||||
BaseSymbolItem *const self = const_cast<BaseSymbolItem *>(this); // this method is const
|
||||
QFutureWatcher<Esri::ArcGISRuntime::Symbol *> *watcher = new QFutureWatcher<Esri::ArcGISRuntime::Symbol *>(self);
|
||||
watcher->setFuture(fut);
|
||||
// 300/Qt6: connect to finished() and read the Symbol* via the result() getter (see above).
|
||||
connect(watcher, &QFutureWatcher<Esri::ArcGISRuntime::Symbol *>::finished, watcher,
|
||||
[self, watcher] {
|
||||
self->onEsriFetchCompleted(watcher->result());
|
||||
watcher->deleteLater();
|
||||
});
|
||||
}
|
||||
else
|
||||
qCritical() << " FETCH: id=" << m_id << " m_esriFetchTaskIdUuid invalid";
|
||||
qCritical() << " FETCH: id=" << m_id << " fetchSymbolAsync future invalid";
|
||||
}
|
||||
return m_esriFetch.m_esriSwatch;
|
||||
}
|
||||
|
||||
void BaseSymbolItem::onEsriFetchCompleted(const QUuid &taskId, Esri::ArcGISRuntime::Symbol *symbol)
|
||||
void BaseSymbolItem::onEsriFetchCompleted(Esri::ArcGISRuntime::Symbol *symbol)
|
||||
{
|
||||
if (m_esriFetch.m_esriFetchTaskIdUuid != taskId)
|
||||
return;
|
||||
// ArcGIS 300: the dedicated QFutureWatcher makes the (removed) taskId stale-check unnecessary.
|
||||
|
||||
// save intermediate result:
|
||||
m_esriFetch.m_esriSymbol = symbol;
|
||||
|
||||
// start creating swatch of fetched symbol:
|
||||
connect(m_esriFetch.m_esriSymbol, &Esri::ArcGISRuntime::Symbol::createSwatchCompleted,
|
||||
this, &BaseSymbolItem::onEsriFetchSymbolSwatchCompleted, Qt::UniqueConnection);
|
||||
|
||||
const Esri::ArcGISRuntime::TaskWatcher &tw = m_esriFetch.m_esriSymbol->createSwatch(SWATCH_SIZE, SWATCH_SIZE, 1);
|
||||
if (tw.isValid())
|
||||
m_esriFetch.m_esriSwatchTaskUuid = tw.taskId();
|
||||
// start creating swatch of fetched symbol (createSwatchAsync -> QFuture<QImage>):
|
||||
const QFuture<QImage> fut = m_esriFetch.m_esriSymbol->createSwatchAsync(SWATCH_SIZE, SWATCH_SIZE, 1);
|
||||
if (fut.isValid())
|
||||
{
|
||||
m_esriFetch.m_esriSwatchTaskUuid = QUuid::createUuid(); // in-flight guard (was the 100.x task id)
|
||||
QFutureWatcher<QImage> *watcher = new QFutureWatcher<QImage>(this);
|
||||
watcher->setFuture(fut);
|
||||
// 300/Qt6: connect to finished() and read the QImage via the result() getter (see above).
|
||||
connect(watcher, &QFutureWatcher<QImage>::finished, watcher,
|
||||
[this, watcher] {
|
||||
onEsriFetchSymbolSwatchCompleted(watcher->result());
|
||||
watcher->deleteLater();
|
||||
});
|
||||
}
|
||||
else
|
||||
qCritical() << " FETCH: id=" << m_id << " taskId invalid";
|
||||
qCritical() << " FETCH: id=" << m_id << " createSwatchAsync future invalid";
|
||||
}
|
||||
|
||||
void BaseSymbolItem::onEsriFetchSymbolSwatchCompleted(const QUuid &taskId, const QImage &image)
|
||||
void BaseSymbolItem::onEsriFetchSymbolSwatchCompleted(const QImage &image)
|
||||
{
|
||||
if (m_esriFetch.m_esriSwatchTaskUuid != taskId)
|
||||
return;
|
||||
|
||||
// ArcGIS 300: the dedicated QFutureWatcher makes the (removed) taskId stale-check unnecessary.
|
||||
m_esriFetch.m_esriSwatch = image;
|
||||
|
||||
// qCritical() << " FETCH: id=" << m_id << " image " << image.size();
|
||||
@@ -426,7 +454,7 @@ void BaseSymbolModel::onLoadStatusChanged(Esri::ArcGISRuntime::LoadStatus loadSt
|
||||
void BaseSymbolModel::onErrorDictionary(const Esri::ArcGISRuntime::Error &error)
|
||||
{
|
||||
FATAL_LOG(m_logger) << LOGFUNCTION << " ---EsriError--- occured: "
|
||||
<< " code=" << error.code()
|
||||
<< " code=" << error.arcGISServerErrorCode().value_or(-1) // 300: Error::code() removed
|
||||
<< ", domain=" << static_cast<int>(error.domain())
|
||||
<< ", extendedErrorType=" << static_cast<int>(error.extendedErrorType())
|
||||
<< ", message='" << error.message() << "'"
|
||||
@@ -456,13 +484,15 @@ void BaseSymbolModel::initModel(SymbolDictionary *symbolDictionary,
|
||||
|
||||
// spend time to create (expensive) Esri::ArcGISRuntime::Symbol?
|
||||
#ifdef LTS_DEBUG
|
||||
Esri::ArcGISRuntime::Symbol *esriSymbol = nullptr;
|
||||
Esri::ArcGISRuntime::Symbol *esriSymbol = nullptr; // 300: filled asynchronously (see below)
|
||||
const bool showAll = QGuiApplication::keyboardModifiers().testFlag(Qt::KeyboardModifier::ControlModifier);
|
||||
if (showAll)
|
||||
esriSymbol = searchResult.symbol(this); // symbol() has to be called from mainThread, is expensive / time consuming
|
||||
// 300: symbol() (const, sync, mainThread) is gone; fetchSymbolAsync() is non-const + async.
|
||||
// When showAll, the Symbol is fetched after the item exists and attached via
|
||||
// setEsriSearchSymbol() when the future completes.
|
||||
#else
|
||||
// release mode: save time, won´t be visible
|
||||
Esri::ArcGISRuntime::Symbol *esriSymbol = nullptr;
|
||||
const bool showAll = false;
|
||||
#endif // LTS_DEBUG
|
||||
|
||||
|
||||
@@ -470,6 +500,29 @@ void BaseSymbolModel::initModel(SymbolDictionary *symbolDictionary,
|
||||
|
||||
bsi->setSymbolDictionary(symbolDictionary);
|
||||
|
||||
#ifdef LTS_DEBUG
|
||||
// 300: fetch the Symbol asynchronously and attach it to the item when the future completes.
|
||||
// fetchSymbolAsync() is non-const; copy the (const) search result to call it.
|
||||
if (showAll)
|
||||
{
|
||||
Esri::ArcGISRuntime::SymbolStyleSearchResult sr(searchResult);
|
||||
QFuture<Esri::ArcGISRuntime::Symbol *> fut = sr.fetchSymbolAsync(this);
|
||||
if (fut.isValid())
|
||||
{
|
||||
QFutureWatcher<Esri::ArcGISRuntime::Symbol *> *watcher = new QFutureWatcher<Esri::ArcGISRuntime::Symbol *>(this);
|
||||
watcher->setFuture(fut);
|
||||
// 300/Qt6: connect to finished() and read the Symbol* via the result() getter (see above).
|
||||
connect(watcher, &QFutureWatcher<Esri::ArcGISRuntime::Symbol *>::finished, watcher,
|
||||
[bsi, watcher] {
|
||||
Esri::ArcGISRuntime::Symbol *symbol = watcher->result();
|
||||
if (symbol)
|
||||
bsi->setEsriSearchSymbol(symbol);
|
||||
watcher->deleteLater();
|
||||
});
|
||||
}
|
||||
}
|
||||
#endif // LTS_DEBUG
|
||||
|
||||
bsi->m_symbolProperties.setTags(searchResult.tags());
|
||||
bsi->m_symbolProperties.setName(searchResult.name());
|
||||
bsi->m_symbolProperties.setSymbolClass(searchResult.symbolClass());
|
||||
|
||||
+3
-3
@@ -141,11 +141,11 @@ Q_SIGNALS:
|
||||
|
||||
public Q_SLOTS:
|
||||
// SEARCH_ICON:
|
||||
void onEsriSearchSymbolSwatchCompleted(const QUuid &taskId, const QImage &image);
|
||||
void onEsriSearchSymbolSwatchCompleted(const QImage &image);
|
||||
|
||||
// FETCH_ICON:
|
||||
void onEsriFetchCompleted(const QUuid &taskId, Esri::ArcGISRuntime::Symbol *symbol);
|
||||
void onEsriFetchSymbolSwatchCompleted(const QUuid &taskId, const QImage &image);
|
||||
void onEsriFetchCompleted(Esri::ArcGISRuntime::Symbol *symbol);
|
||||
void onEsriFetchSymbolSwatchCompleted(const QImage &image);
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
+106
-48
@@ -14,7 +14,6 @@
|
||||
|
||||
|
||||
// ESRI
|
||||
#include <TaskWatcher.h>
|
||||
#include <Symbol.h>
|
||||
#include <SymbolStyleSearchParameters.h>
|
||||
#include <SymbolStyleSearchResultListModel.h>
|
||||
@@ -25,6 +24,7 @@
|
||||
#include <QtConcurrent>
|
||||
#include <utility>
|
||||
#include <QtCore/QFuture>
|
||||
#include <QtCore/QFutureWatcher>
|
||||
|
||||
#define CREATE_ESRI_SYMBOL_ON_DEMAND // save time on startup
|
||||
// REGG-3483 - EsriDictionaryProcessor::syncTableWithinMainThread verzögert Applikations-Start um mehrere Sekunden
|
||||
@@ -46,6 +46,18 @@ EsriDictionaryProcessor::EsriDictionaryProcessor(SymbologyType symbologyType)
|
||||
: m_logger(getLogger("EsriDictionaryProcessor")),
|
||||
m_baseSymbolCodeToSymbolPropertyTable(symbologyType, SidcCodec::SidcType::Base)
|
||||
{
|
||||
// ArcGIS 300: the 100.x searchSymbolsCompleted signal / TaskWatcher is gone.
|
||||
// searchSymbolsAsync() returns a QFuture; m_searchSymbolsWatcher delivers its result on
|
||||
// this (main) thread via its 'result' signal -> onSearchSymbolsCompletedPropertyTable().
|
||||
// 300/Qt6: the 'result' signal is name-collision-ambiguous with the result() getter (QOverload can't
|
||||
// disambiguate); connect to the unambiguous finished() signal and read the value via the result()
|
||||
// getter (the future is finished when finished() fires).
|
||||
connect(&m_searchSymbolsWatcher,
|
||||
&QFutureWatcher<Esri::ArcGISRuntime::SymbolStyleSearchResultListModel*>::finished,
|
||||
this, [this] {
|
||||
onSearchSymbolsCompletedPropertyTable(m_searchSymbolsWatcher.result());
|
||||
});
|
||||
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " START" << " ThreadId=" << QThread::currentThreadId();
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " END";
|
||||
}
|
||||
@@ -94,16 +106,16 @@ void EsriDictionaryProcessor::searchSymbols()
|
||||
// search for all results (and store them in member):
|
||||
//
|
||||
|
||||
connect(m_esri_dictionary, &Esri::ArcGISRuntime::DictionarySymbolStyle::searchSymbolsCompleted,
|
||||
this, &EsriDictionaryProcessor::onSearchSymbolsCompletedPropertyTable, Qt::UniqueConnection);
|
||||
|
||||
Esri::ArcGISRuntime::SymbolStyleSearchParameters sssp;
|
||||
|
||||
Esri::ArcGISRuntime::TaskWatcher tw = m_esri_dictionary->searchSymbols(sssp);
|
||||
if (tw.isValid())
|
||||
DEBUG_LOG(m_logger) << LOGFUNCTION << " TaskWatcher valid: ssTaskId=" << tw.taskId().toString();
|
||||
// ArcGIS 300: no TaskWatcher / searchSymbolsCompleted — searchSymbolsAsync() returns a
|
||||
// QFuture; m_searchSymbolsWatcher (connected in the constructor) delivers the result on the
|
||||
// main thread via its 'result' signal -> onSearchSymbolsCompletedPropertyTable().
|
||||
m_searchSymbolsWatcher.setFuture(m_esri_dictionary->searchSymbolsAsync(sssp));
|
||||
if (m_searchSymbolsWatcher.future().isValid())
|
||||
DEBUG_LOG(m_logger) << LOGFUNCTION << " searchSymbolsAsync future valid";
|
||||
else
|
||||
ERROR_LOG(m_logger) << LOGFUNCTION << " TaskWatcher invalid" << " ThreadId=" << QThread::currentThreadId();
|
||||
ERROR_LOG(m_logger) << LOGFUNCTION << " searchSymbolsAsync future invalid" << " ThreadId=" << QThread::currentThreadId();
|
||||
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " END";
|
||||
|
||||
@@ -115,7 +127,8 @@ void EsriDictionaryProcessor::startBaseSymbolCodeToPropertyTable()
|
||||
|
||||
// A-sync:
|
||||
// (slot is a pure virtual method)
|
||||
m_baseSymbolCodeToSymbolPropertyTableWatcher = QtConcurrent::run(this, &EsriDictionaryProcessor::processBaseSymbolCodeToPropertyTable);
|
||||
// Qt6: QtConcurrent::run(context, &method) is gone; pass the member fn first, then the receiver.
|
||||
m_baseSymbolCodeToSymbolPropertyTableWatcher = QtConcurrent::run(&EsriDictionaryProcessor::processBaseSymbolCodeToPropertyTable, this);
|
||||
|
||||
|
||||
// Sync: // processBaseSymbolCodeToPropertyTable();
|
||||
@@ -129,7 +142,8 @@ void EsriDictionaryProcessor::startModifierTable()
|
||||
|
||||
// A-sync:
|
||||
// (slot is a pure virtual method)
|
||||
m_modifierTableWatcher = QtConcurrent::run(this, &EsriDictionaryProcessor::processModifierTable);
|
||||
// Qt6: QtConcurrent::run(context, &method) is gone; pass the member fn first, then the receiver.
|
||||
m_modifierTableWatcher = QtConcurrent::run(&EsriDictionaryProcessor::processModifierTable, this);
|
||||
|
||||
// Sync: // processModifierTable();
|
||||
|
||||
@@ -184,9 +198,9 @@ bool EsriDictionaryProcessor::allJobsDone() const
|
||||
// Job n
|
||||
}
|
||||
|
||||
void EsriDictionaryProcessor::onSearchSymbolsCompletedPropertyTable(QUuid, Esri::ArcGISRuntime::SymbolStyleSearchResultListModel *searchResults)
|
||||
void EsriDictionaryProcessor::onSearchSymbolsCompletedPropertyTable(Esri::ArcGISRuntime::SymbolStyleSearchResultListModel *searchResults)
|
||||
{
|
||||
// ssTaskId can be ignored during initializing phase:
|
||||
// ArcGIS 300: the 100.x ssTaskId (task uuid) no longer exists; the future is 1:1 with this call.
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " START";
|
||||
|
||||
// save:
|
||||
@@ -196,9 +210,7 @@ void EsriDictionaryProcessor::onSearchSymbolsCompletedPropertyTable(QUuid, Esri:
|
||||
// cleanup:
|
||||
searchResults->deleteLater();
|
||||
|
||||
// disconnect:
|
||||
disconnect(m_esri_dictionary, &Esri::ArcGISRuntime::DictionarySymbolStyle::searchSymbolsCompleted,
|
||||
this, &EsriDictionaryProcessor::onSearchSymbolsCompletedPropertyTable);
|
||||
// (no disconnect needed: 300 has no dict signal; the QFutureWatcher fires once per setFuture)
|
||||
|
||||
// method 'symbol' has to be called (created) within mainThread:
|
||||
syncTableWithinMainThread();
|
||||
@@ -330,45 +342,91 @@ QSharedPointer<SymbolResult> EsriDictionaryProcessor::symbolPropertyImage(QShare
|
||||
|
||||
if (eSym.swatchImage.isNull())
|
||||
{
|
||||
// ArcGIS 300: createSwatch needs a Symbol. With CREATE_ESRI_SYMBOL_ON_DEMAND the Symbol is
|
||||
// fetched on demand; fetchSymbolAsync() (100.x: symbol()) is async, so fetch it first and only
|
||||
// then create the swatch. When the Symbol is already available, create the swatch directly.
|
||||
// Both paths funnel into startSwatchCreation() (the createSwatchAsync part, unchanged from the
|
||||
// 100.x logic): a per-request QFutureWatcher delivers the QImage on this (main) thread ->
|
||||
// onEsriSymbolSwatchCompleted(), correlated with our own QUuid (the SDK no longer issues one).
|
||||
EsriDictionaryProcessor *const self = const_cast<EsriDictionaryProcessor *>(this); // this method is const
|
||||
auto startSwatchCreation = [self, symResult, originalKey]() {
|
||||
auto it = self->m_originalKeyToEsriSymbol.find(originalKey);
|
||||
if (it == self->m_originalKeyToEsriSymbol.end())
|
||||
return;
|
||||
const EsriSymbol &eSym = it.value();
|
||||
#ifdef USE_ARCADE_SYMBOLOGY
|
||||
QFuture<QImage> fut;
|
||||
auto it2 = self->m_baseSymbolCodeToSymbolPropertyTable.find(originalKey);
|
||||
if (it2 != self->m_baseSymbolCodeToSymbolPropertyTable.end() && (it2->geometryType() == GeometryType::Polygon) )
|
||||
// area/Polygon -> request rectangle, otherwise quadratic swatch:
|
||||
fut = eSym.esriSymbol->createSwatchAsync(CREATE_SWATCH_PARAMETER.m_width, CREATE_SWATCH_PARAMETER.m_height, CREATE_SWATCH_PARAMETER.m_screenScale);
|
||||
else
|
||||
fut = eSym.esriSymbol->createSwatchAsync(CREATE_SWATCH_PARAMETER.m_height, CREATE_SWATCH_PARAMETER.m_height, CREATE_SWATCH_PARAMETER.m_screenScale);
|
||||
#else
|
||||
QFuture<QImage> fut = eSym.esriSymbol->createSwatchAsync(CREATE_SWATCH_SCREEN_SCALE);
|
||||
#endif // USE_ARCADE_SYMBOLOGY
|
||||
|
||||
if (fut.isValid())
|
||||
{
|
||||
const QUuid csTaskId = QUuid::createUuid();
|
||||
DEBUG_LOG(self->m_logger) << LOGFUNCTION << " createSwatchAsync future valid: csTaskId=" << csTaskId;
|
||||
|
||||
self->m_symbolPropertyImage2symbolResult[csTaskId] = symResult.toWeakRef();
|
||||
|
||||
QFutureWatcher<QImage> *swatchWatcher = new QFutureWatcher<QImage>(self);
|
||||
swatchWatcher->setFuture(fut);
|
||||
// 300/Qt6: connect to finished() and read the QImage via the result() getter.
|
||||
connect(swatchWatcher, &QFutureWatcher<QImage>::finished, swatchWatcher,
|
||||
[self, csTaskId, swatchWatcher] {
|
||||
self->onEsriSymbolSwatchCompleted(csTaskId, swatchWatcher->result());
|
||||
swatchWatcher->deleteLater();
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
ERROR_LOG(self->m_logger) << LOGFUNCTION << " createSwatchAsync future invalid"
|
||||
<< " ThreadId=" << QThread::currentThreadId();
|
||||
}
|
||||
};
|
||||
|
||||
#ifdef CREATE_ESRI_SYMBOL_ON_DEMAND
|
||||
if (!eSym.esriSymbol)
|
||||
{
|
||||
QObject *parent = const_cast<EsriDictionaryProcessor *>(this); // cast const away
|
||||
eSym.esriSymbol = eSym.m_sssResult.symbol(parent); // resultItem.symbol() has to be called from mainThread???
|
||||
// 300: symbol() (const, sync) is gone; fetchSymbolAsync() is non-const + async. Copy the
|
||||
// (const) search result so the non-const fetchSymbolAsync() can be called on the copy.
|
||||
Esri::ArcGISRuntime::SymbolStyleSearchResult sr(eSym.m_sssResult);
|
||||
QFuture<Esri::ArcGISRuntime::Symbol *> fut = sr.fetchSymbolAsync(self);
|
||||
if (fut.isValid())
|
||||
{
|
||||
QFutureWatcher<Esri::ArcGISRuntime::Symbol *> *fetchWatcher = new QFutureWatcher<Esri::ArcGISRuntime::Symbol *>(self);
|
||||
fetchWatcher->setFuture(fut);
|
||||
// 300/Qt6: connect to finished() and read the Symbol* via the result() getter.
|
||||
connect(fetchWatcher, &QFutureWatcher<Esri::ArcGISRuntime::Symbol *>::finished, fetchWatcher,
|
||||
[self, originalKey, startSwatchCreation, fetchWatcher] {
|
||||
Esri::ArcGISRuntime::Symbol *symbol = fetchWatcher->result();
|
||||
if (symbol)
|
||||
{
|
||||
auto it = self->m_originalKeyToEsriSymbol.find(originalKey);
|
||||
if (it != self->m_originalKeyToEsriSymbol.end())
|
||||
it.value().esriSymbol = symbol;
|
||||
startSwatchCreation();
|
||||
}
|
||||
fetchWatcher->deleteLater();
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
ERROR_LOG(self->m_logger) << LOGFUNCTION << " fetchSymbolAsync future invalid"
|
||||
<< " ThreadId=" << QThread::currentThreadId();
|
||||
}
|
||||
}
|
||||
#endif // CREATE_ESRI_SYMBOL_ON_DEMAND
|
||||
|
||||
connect(eSym.esriSymbol, &Esri::ArcGISRuntime::Symbol::createSwatchCompleted,
|
||||
this, &EsriDictionaryProcessor::onEsriSymbolSwatchCompleted, Qt::UniqueConnection);
|
||||
|
||||
#ifdef USE_ARCADE_SYMBOLOGY
|
||||
Esri::ArcGISRuntime::TaskWatcher tw;
|
||||
auto it = m_baseSymbolCodeToSymbolPropertyTable.find(originalKey);
|
||||
if (it != m_baseSymbolCodeToSymbolPropertyTable.end() && (it->geometryType() == GeometryType::Polygon) )
|
||||
// area/Polygon -> request rectangle, otherwise quadratic swatch:
|
||||
tw = eSym.esriSymbol->createSwatch(CREATE_SWATCH_PARAMETER.m_width, CREATE_SWATCH_PARAMETER.m_height, CREATE_SWATCH_PARAMETER.m_screenScale);
|
||||
else
|
||||
tw = eSym.esriSymbol->createSwatch(CREATE_SWATCH_PARAMETER.m_height, CREATE_SWATCH_PARAMETER.m_height, CREATE_SWATCH_PARAMETER.m_screenScale);
|
||||
|
||||
{
|
||||
startSwatchCreation();
|
||||
}
|
||||
#else
|
||||
Esri::ArcGISRuntime::TaskWatcher tw = eSym.esriSymbol->createSwatch(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;
|
||||
}
|
||||
else
|
||||
{
|
||||
ERROR_LOG(m_logger) << LOGFUNCTION << " csTaskWatcher invalid"
|
||||
<< " ThreadId=" << QThread::currentThreadId();
|
||||
}
|
||||
|
||||
if (! csTaskId.isNull())
|
||||
m_symbolPropertyImage2symbolResult[csTaskId] = symResult.toWeakRef();
|
||||
else
|
||||
ERROR_LOG(m_logger) << LOGFUNCTION << " csTaskWatcher invalid";
|
||||
startSwatchCreation();
|
||||
#endif // CREATE_ESRI_SYMBOL_ON_DEMAND
|
||||
|
||||
}
|
||||
else
|
||||
|
||||
+8
-1
@@ -16,12 +16,14 @@
|
||||
|
||||
// Qt
|
||||
#include <QtGui/QImage>
|
||||
#include <QtCore/QFutureWatcher>
|
||||
#include <QUuid> // QUuid used in slot signatures / map keys (Qt6: no transitive include)
|
||||
|
||||
|
||||
// Esri
|
||||
#include <DictionarySymbolStyle.h>
|
||||
#include <SymbolStyleSearchResult.h> // Esri::ArcGISRuntime::SymbolStyleSearchResult used below (no transitive include)
|
||||
#include <SymbolStyleSearchResultListModel.h> // complete type for the QFutureWatcher member (no transitive include)
|
||||
|
||||
|
||||
|
||||
@@ -158,7 +160,7 @@ Q_SIGNALS:
|
||||
|
||||
|
||||
protected Q_SLOTS:
|
||||
void onSearchSymbolsCompletedPropertyTable(QUuid /*ssTaskId*/, Esri::ArcGISRuntime::SymbolStyleSearchResultListModel *searchResults);
|
||||
void onSearchSymbolsCompletedPropertyTable(Esri::ArcGISRuntime::SymbolStyleSearchResultListModel *searchResults);
|
||||
void onEsriSymbolSwatchCompleted(const QUuid &csTaskId, const QImage &image);
|
||||
|
||||
|
||||
@@ -177,6 +179,11 @@ protected:
|
||||
QList<Esri::ArcGISRuntime::SymbolStyleSearchResult> m_searchResultList;
|
||||
QList<Esri::ArcGISRuntime::SymbolStyleSearchResult> m_searchResultListValid;
|
||||
|
||||
// ArcGIS 300: async symbol search — replaces the removed 100.x TaskWatcher /
|
||||
// searchSymbolsCompleted signal (searchSymbolsAsync() returns a QFuture<...>; the watcher
|
||||
// delivers the result on this object's (main) thread).
|
||||
QFutureWatcher<Esri::ArcGISRuntime::SymbolStyleSearchResultListModel*> m_searchSymbolsWatcher;
|
||||
|
||||
// originalKey
|
||||
struct EsriSymbol
|
||||
{
|
||||
|
||||
+89
-52
@@ -27,14 +27,15 @@
|
||||
#include <SymbologyXML/xml_symbol_codec.h>
|
||||
|
||||
// ESRI
|
||||
#include <TaskWatcher.h>
|
||||
#include <Symbol.h>
|
||||
#include <SymbolStyleSearchParameters.h>
|
||||
#include <SymbolStyleSearchResultListModel.h>
|
||||
#include <SymbolStyleSearchResult.h>
|
||||
#include <MapTypes.h> // Esri::ArcGISRuntime::LoadStatus (300: enum class; Loadable.h only forward-declares it)
|
||||
#include <Error.h> // Esri::ArcGISRuntime::Error (complete type; 300 dropped Error::code())
|
||||
|
||||
|
||||
# include <arcgis/arcgisversion.h> // This file is created by RME, not ESRI
|
||||
# include <arcgisversion.h> // This file is created by RME, not ESRI (300: flat include layout, no arcgis/ subdir)
|
||||
|
||||
#if ACRGIS_VERSION >= 0x640100 // 100.1.0 / Update 1
|
||||
# define SYM_PROTECTION_AREAS_BECOMES_LINE
|
||||
@@ -58,6 +59,7 @@
|
||||
|
||||
#include <QtConcurrent>
|
||||
#include <QtCore/QFuture>
|
||||
#include <QtCore/QFutureWatcher>
|
||||
|
||||
#include <sstream>
|
||||
#include <type_traits>
|
||||
@@ -393,29 +395,31 @@ bool SymbolDictionaryImpl::init(SymbologyType symbologyType, const QString &symb
|
||||
m_esri_dictionary = Esri::ArcGISRuntime::DictionarySymbolStyle::createFromFile(m_symbologyResourcePath);
|
||||
|
||||
#else
|
||||
// QString symbologyResourcePath("/usr/share/arcgis/resources/symbols//mil2525d/mil2525d.stylx");
|
||||
// ArcGIS 300: the 100.x DictionarySymbolStyle(specificationType[, path]) constructors are gone
|
||||
// (300 loads a local .stylx via the static createFromFile(), as the ARCADE branch above).
|
||||
// The 100.x "built-in" spec-only dictionary (empty path) has no 300 equivalent -> fail as the
|
||||
// ARCADE branch does.
|
||||
if (symbologyResourcePath.isEmpty())
|
||||
{
|
||||
INFO_LOG(m_logger) << LOGFUNCTION << " create EsriDict:"
|
||||
<< " m_specificationType='" << m_specificationType << "'";
|
||||
m_esri_dictionary = new Esri::ArcGISRuntime::DictionarySymbolStyle(m_specificationType);
|
||||
ERROR_LOG(m_logger) << LOGFUNCTION << " no symbologyResourcePath; 300 has no built-in spec-only DictionarySymbolStyle"
|
||||
<< " m_specificationType='" << m_specificationType << "'";
|
||||
Q_ASSERT(false);
|
||||
return false;
|
||||
}
|
||||
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);
|
||||
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 = Esri::ArcGISRuntime::DictionarySymbolStyle::createFromFile(m_symbologyResourcePath);
|
||||
|
||||
#endif // USE_ARCADE_SYMBOLOGY
|
||||
|
||||
if (m_esri_dictionary)
|
||||
@@ -485,11 +489,9 @@ bool SymbolDictionaryImpl::init(SymbologyType symbologyType, const QString &symb
|
||||
|
||||
void SymbolDictionaryImpl::connectSignals()
|
||||
{
|
||||
if (m_esri_dictionary)
|
||||
{
|
||||
connect(m_esri_dictionary, &Esri::ArcGISRuntime::DictionarySymbolStyle::fetchSymbolCompleted,
|
||||
this, &SymbolDictionaryImpl::onFetchSymbolCompleted);
|
||||
}
|
||||
// ArcGIS 300: the 100.x fetchSymbolCompleted signal / TaskWatcher is gone.
|
||||
// fetchSymbolAsync() now returns a QFuture and each fetchSymbol() request drives
|
||||
// onFetchSymbolCompleted() via its own QFutureWatcher (see fetchSymbol() below).
|
||||
}
|
||||
|
||||
|
||||
@@ -1350,7 +1352,16 @@ QSharedPointer<SymbolResult> SymbolDictionaryImpl::fetchSymbol(const SymbolDataT
|
||||
#define FETCH_SYMBOL_ETS_CONCURRENT
|
||||
#ifdef FETCH_SYMBOL_ETS_CONCURRENT
|
||||
// symDataToRender contains flag 'symDataToRender'
|
||||
symResult->setFuture(QtConcurrent::run(renderExtensions, extraImg, symDataToRender, colorToBeReplaced, symDataToRender.renderJustCoreImage));
|
||||
// Qt6: QtConcurrent::run(renderExtensions, constQImage&, ...) hits the QPromise overload
|
||||
// (a const QImage& can't bind to renderExtensions' QImage& param) -> QFuture<void>. Wrap in a
|
||||
// lambda that returns QImage so run() yields QFuture<QImage>. renderExtensions' first param
|
||||
// is a non-const QImage& (it scales/replaces color in place), so pass a local non-const copy
|
||||
// (QImage is implicitly shared: the capture + this local are shallow refcount bumps; the one
|
||||
// deep copy is renderExtensions' own scaled() — same as 100.x, which mutated run()'s stored copy).
|
||||
symResult->setFuture(QtConcurrent::run([extraImg, symDataToRender, colorToBeReplaced]() -> QImage {
|
||||
QImage img = extraImg;
|
||||
return renderExtensions(img, symDataToRender, colorToBeReplaced, symDataToRender.renderJustCoreImage);
|
||||
}));
|
||||
|
||||
#else
|
||||
QImage imageCopy = extraImg;
|
||||
@@ -1463,11 +1474,15 @@ QSharedPointer<SymbolResult> SymbolDictionaryImpl::fetchSymbol(const SymbolDataT
|
||||
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);
|
||||
// ArcGIS 300: no TaskWatcher / fetchSymbolCompleted — fetchSymbolAsync() returns a
|
||||
// QFuture<Symbol*>. Correlate the future result back to this SymbolResult with our own
|
||||
// QUuid (the SDK no longer issues a task id); a per-request QFutureWatcher delivers the
|
||||
// Symbol* on this (main) thread -> onFetchSymbolCompleted().
|
||||
QFuture<Esri::ArcGISRuntime::Symbol *> fut = m_esri_dictionary->fetchSymbolAsync(keys);
|
||||
QUuid fsTaskId;
|
||||
if (tw.isValid())
|
||||
if (fut.isValid())
|
||||
{
|
||||
fsTaskId = tw.taskId();
|
||||
fsTaskId = QUuid::createUuid();
|
||||
|
||||
if (doParanoiaChecks())
|
||||
if (fsTaskId.isNull())
|
||||
@@ -1479,11 +1494,21 @@ QSharedPointer<SymbolResult> SymbolDictionaryImpl::fetchSymbol(const SymbolDataT
|
||||
// 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;
|
||||
DEBUG_LOG(m_logger) << LOGFUNCTION << " fetchSymbolAsync future valid: fsTaskId=" << fsTaskId;
|
||||
|
||||
SymbolDictionaryImpl *const self = const_cast<SymbolDictionaryImpl *>(this); // this method is const
|
||||
QFutureWatcher<Esri::ArcGISRuntime::Symbol *> *watcher = new QFutureWatcher<Esri::ArcGISRuntime::Symbol *>(self);
|
||||
watcher->setFuture(fut);
|
||||
// 300/Qt6: connect to finished() and read the Symbol* via the result() getter.
|
||||
connect(watcher, &QFutureWatcher<Esri::ArcGISRuntime::Symbol *>::finished, watcher,
|
||||
[self, fsTaskId, watcher] {
|
||||
self->onFetchSymbolCompleted(fsTaskId, watcher->result());
|
||||
watcher->deleteLater();
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
ERROR_LOG(m_logger) << LOGFUNCTION << " TaskWatcher invalid"
|
||||
ERROR_LOG(m_logger) << LOGFUNCTION << " fetchSymbolAsync future invalid"
|
||||
<< " ThreadId=" << QThread::currentThreadId();
|
||||
|
||||
if (doParanoiaChecks())
|
||||
@@ -1769,45 +1794,49 @@ void SymbolDictionaryImpl::onFetchSymbolCompleted(QUuid fsTaskId, Esri::ArcGISRu
|
||||
// retrieve Image :
|
||||
//
|
||||
{
|
||||
connect(symbol, &Esri::ArcGISRuntime::Symbol::createSwatchCompleted,
|
||||
this, &SymbolDictionaryImpl::onSwatchCompleted);
|
||||
|
||||
// ArcGIS 300: no TaskWatcher / createSwatchCompleted — createSwatchAsync() returns a
|
||||
// QFuture<QImage>. Correlate with our own csTaskId (SDK no longer issues a task id); a
|
||||
// per-request QFutureWatcher delivers the QImage on the main thread -> onSwatchCompleted().
|
||||
#ifdef USE_ARCADE_SYMBOLOGY
|
||||
Esri::ArcGISRuntime::TaskWatcher tw;
|
||||
QFuture<QImage> fut;
|
||||
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);
|
||||
fut = symbol->createSwatchAsync(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);
|
||||
fut = symbol->createSwatchAsync(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
|
||||
QFuture<QImage> fut = symbol->createSwatchAsync(CREATE_SWATCH_SCREEN_SCALE); // CREATE_SWATCH_SCREEN_SCALE
|
||||
#endif // USE_ARCADE_SYMBOLOGY
|
||||
QUuid csTaskId;
|
||||
if (tw.isValid())
|
||||
|
||||
if (fut.isValid())
|
||||
{
|
||||
csTaskId = tw.taskId();
|
||||
DEBUG_LOG(m_logger) << LOGFUNCTION << " csTaskWatcher valid: csTaskId=" << csTaskId;
|
||||
QUuid csTaskId = QUuid::createUuid();
|
||||
DEBUG_LOG(m_logger) << LOGFUNCTION << " createSwatchAsync future valid: csTaskId=" << csTaskId;
|
||||
|
||||
if (doParanoiaChecks())
|
||||
if (csTaskId.isNull())
|
||||
abort();
|
||||
|
||||
m_createSwatch2findSymbolTaskId[csTaskId] = fsTaskId;
|
||||
|
||||
QFutureWatcher<QImage> *watcher = new QFutureWatcher<QImage>(this);
|
||||
watcher->setFuture(fut);
|
||||
// 300/Qt6: connect to finished() and read the QImage via the result() getter.
|
||||
connect(watcher, &QFutureWatcher<QImage>::finished, watcher,
|
||||
[this, csTaskId, fsTaskId, symbol, watcher] {
|
||||
onSwatchCompleted(csTaskId, watcher->result(), symbol);
|
||||
watcher->deleteLater();
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
ERROR_LOG(m_logger) << LOGFUNCTION << " csTaskWatcher invalid"
|
||||
ERROR_LOG(m_logger) << LOGFUNCTION << " createSwatchAsync future 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"
|
||||
@@ -1816,7 +1845,7 @@ void SymbolDictionaryImpl::onFetchSymbolCompleted(QUuid fsTaskId, Esri::ArcGISRu
|
||||
<< " symbol= '" << symbol << "'";
|
||||
}
|
||||
|
||||
void SymbolDictionaryImpl::onSwatchCompleted(const QUuid &csTaskId, const QImage &image)
|
||||
void SymbolDictionaryImpl::onSwatchCompleted(const QUuid &csTaskId, const QImage &image, Esri::ArcGISRuntime::Symbol *symbol)
|
||||
{
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " START"
|
||||
<< " symType= '" << this->symbologyType() << "'"
|
||||
@@ -1873,7 +1902,15 @@ void SymbolDictionaryImpl::onSwatchCompleted(const QUuid &csTaskId, const QImage
|
||||
// start computation like:
|
||||
// QFuture<T> QtConcurrent::run(Function function, arg1, arc2...)
|
||||
// ^^^^^^^^^^ without()
|
||||
symResult->setFuture(QtConcurrent::run(renderExtensions, image, symToRender, QColor(), symToRender.renderJustCoreImage));
|
||||
// Qt6: same as above — the const image can't bind to renderExtensions' QImage& param via the
|
||||
// raw-pointer form; wrap in a lambda returning QImage so run() yields QFuture<QImage>.
|
||||
// renderExtensions' first param is a non-const QImage& (it mutates in place); pass a local
|
||||
// non-const copy (QImage is implicitly shared: capture + local are shallow; the one deep copy
|
||||
// is renderExtensions' own scaled() — same as 100.x, which mutated run()'s stored copy).
|
||||
symResult->setFuture(QtConcurrent::run([image, symToRender]() -> QImage {
|
||||
QImage img = image;
|
||||
return renderExtensions(img, symToRender, QColor(), symToRender.renderJustCoreImage);
|
||||
}));
|
||||
|
||||
#else // CONCURRENT
|
||||
|
||||
@@ -1915,7 +1952,7 @@ void SymbolDictionaryImpl::onSwatchCompleted(const QUuid &csTaskId, const QImage
|
||||
|
||||
// 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());
|
||||
// ArcGIS 300: the symbol is passed in (the 100.x code recovered it via sender()).
|
||||
if (symbol)
|
||||
symbol->deleteLater();
|
||||
|
||||
@@ -2349,7 +2386,7 @@ QStringList SymbolDictionaryImpl::textFieldNamesInternal() const
|
||||
void SymbolDictionaryImpl::onErrorDictionary(const Esri::ArcGISRuntime::Error &error)
|
||||
{
|
||||
FATAL_LOG(m_logger) << LOGFUNCTION << " ---EsriError--- occured: "
|
||||
<< " code=" << error.code()
|
||||
<< " code=" << error.arcGISServerErrorCode().value_or(-1) // 300: Error::code() removed
|
||||
<< ", domain=" << static_cast<int>(error.domain())
|
||||
<< ", extendedErrorType=" << static_cast<int>(error.extendedErrorType())
|
||||
<< ", message='" << error.message() << "'"
|
||||
|
||||
+1
-1
@@ -226,7 +226,7 @@ protected Q_SLOTS:
|
||||
|
||||
void onFetchSymbolCompleted(QUuid fsTaskId, Esri::ArcGISRuntime::Symbol *symbol);
|
||||
|
||||
void onSwatchCompleted(const QUuid &csTaskId, const QImage &image);
|
||||
void onSwatchCompleted(const QUuid &csTaskId, const QImage &image, Esri::ArcGISRuntime::Symbol *symbol);
|
||||
|
||||
private:
|
||||
Esri::ArcGISRuntime::DictionarySymbolStyle *m_esri_dictionary = nullptr;
|
||||
|
||||
@@ -0,0 +1,200 @@
|
||||
# ArcGIS 300 Symbology Migration Summary
|
||||
|
||||
Qt5→Qt6 + ArcGIS Runtime 100.x→ArcGIS Maps SDK for Qt **300.0.0** migration audit of the
|
||||
SIDC/Esri symbology subsystem. Every change was compared against the legacy tree
|
||||
(`qt5-before/qt5-legatus-legacy`); the goal is migration-only (no behavior change).
|
||||
ArcGIS 300 SDK at `external/ArcGIS/MapsSDK_Qt_300.0.0/.../qt300.0.0/sdk` (flat include
|
||||
layout — all headers directly in `sdk/include/`, no `arcgis/` subdirectory).
|
||||
|
||||
## Scope audited
|
||||
|
||||
- `Lts/Viewer/SituationMap/Symbology/` — SIDC codec/builder/dictionary/definitions (pure Qt).
|
||||
- `Lts/Viewer/SituationMap/SymbologyImpl/` — `esri_dictionary_processor*.cpp`,
|
||||
`base_symbol_model.*`, `symbol_dictionary_impl.*`, `advanced_symbology_logging.*`.
|
||||
- `Lts/Viewer/SituationMap/SymbologyXML/` — symbol XML read/write/export.
|
||||
- `Lts/Viewer/SituationMap/Map/` — the ArcGIS map layer (57 files). **Excluded from the
|
||||
build** (see Remaining Issues).
|
||||
- `Lts/Plugins/AdvancedSymbology/` — `asb_data_plugin.*`, `asb_foreign_interface_impl.*`,
|
||||
`Gui/SymbolEditor/*`, `Gui/SymbolProxy/*`.
|
||||
- `Lts/Services/CentralEffectSimulation/Plugins/Explosions/expand_polygon.cpp`.
|
||||
|
||||
## Migration-only pattern classes found
|
||||
|
||||
All in-scope changes classified as the following approved adaptations (no semantic change):
|
||||
|
||||
- Qt include path churn: `#include <QX>` → `#include <QtCore/QX>` (Gui/Widgets/Network/Sql/…).
|
||||
- `qAsConst(x)` → `std::as_const(x)` (Qt6 removed `qAsConst`).
|
||||
- `QRegExp` → `QRegularExpression`; `QRegExp::exactMatch(s)` → `QRegularExpression::match(s).hasMatch()`.
|
||||
- `QString::count()` → `size()`; `leftRef/rightRef/midRef(n)` → `left/right/mid(n)`;
|
||||
`split()` now returns `QStringList` (Qt6 dropped the `QStringView`/`QStringRef` ref
|
||||
overloads) → `QVector<QStringView>` or `QStringList`; `.toString()` dropped where the
|
||||
element is already a `QString` (Esri dictionary processors).
|
||||
- `QAbstractItemModel::invalidateFilter()` → `beginFilterChange()`/`endFilterChange()`
|
||||
(Qt6 removed `invalidateFilter()`).
|
||||
- `QLinkedList`/`QLinkedListIterator` → STL `std::list` + range-for/iterators
|
||||
(`append`→`push_back`, `remove`→`erase`, `toFront/toBack`→erase+`push_front`/`push_back`).
|
||||
- `LOGFUNCTION` → `Q_FUNC_INFO` (no-op: `INGLLogger.h` defines `LOGFUNCTION` as `Q_FUNC_INFO`).
|
||||
- `const QImage &x = …image()` → `const QImage x = …image()` (Qt6 `QImage::image()` by value).
|
||||
- DDS-generated type rename `ParticipantManagement::Role_def::*` → `Role::*` (codegen artifact).
|
||||
- ArcGIS include path: old 100.x `<arcgis/X.h>` → flat 300 `<X.h>` (see below).
|
||||
- Systematic 2-space→4-space re-indentation (whitespace-only; `diff -w` filters it out).
|
||||
|
||||
## The four "verify carefully" items — resolutions
|
||||
|
||||
1. **`Role_def` → `Role`** (`symbol_data_to_render_role.h`) — RESOLVED, 1:1. Legacy
|
||||
`ppm_service.xml` and migrated `ppm_enums.idl` both define `Role` with the identical
|
||||
7 enumerators and values (`Unknown=0 … Suspect=6`). The `Role_def` name is a DDS-codegen
|
||||
artifact (IDL name is `Role` in both; legacy codegen emitted `Role_def`, rtiddsgen 7.7
|
||||
emits `Role`). `role.underlying()` switch behaves identically; return values unchanged.
|
||||
|
||||
2. **`#ifdef BUILD_WITH_EXTERNAL_DDS` role-conversion stub** — RESOLVED with a flagged delta.
|
||||
(a) Real path = legacy 1:1 (constructor + `roleToRole<>(party.role())` identical).
|
||||
(c) Stub documented (`// STUB: No external DDS …`), intentional migration scaffolding.
|
||||
**(b) FLAGGED:** `BUILD_WITH_EXTERNAL_DDS` is referenced only as `#ifdef` in 28 source
|
||||
files and is **never defined** (no `#define`, no CMake `set`/`option`/`-D`, empty
|
||||
`CMAKE_CXX_FLAGS`). So the no-op **stub** path is what compiles in the current build —
|
||||
a runtime behavior change vs legacy. This is codebase-wide (28 files) and pre-existing
|
||||
in the migration (not introduced by the ArcGIS-300 symbology work); the stub is NOT
|
||||
"fixed" (out of scope) — surfaced as a behavior delta.
|
||||
|
||||
3. **Logger pattern** — RESOLVED, migration-only. `m_logger` is a **member** of type
|
||||
`LOGGER_T` (`typedef NGL::INGLLogger &LOGGER_T;` — a *reference*) in **both** trees,
|
||||
initialized in the constructor (`getLogger("SymbolDictionaryImpl"/"EsriDictionaryProcessor"/
|
||||
"BaseSymbolModel")` — names unchanged). A reference has no ownership → no
|
||||
double-allocation/lifetime/init-order issue. (The "local→member" premise was inaccurate;
|
||||
reality: unchanged.)
|
||||
|
||||
4. **Filter API** (`base_symbol_model.cpp`) — RESOLVED, 1:1. 4 legacy `invalidateFilter()`
|
||||
→ 4 migrated `beginFilterChange(); endFilterChange();` pairs (`setValidBaseSymbolCodes`,
|
||||
`onFilterPoints/Lines/Areas`); no leftover `invalidateFilter()`. `BaseSymbolProxyModel`
|
||||
is a `QSortFilterProxyModel` (via `LtsColumnFilterProxyModel`) that overrides
|
||||
`filterAcceptsRow` (unchanged); the changed members are plain `QSet` ops (no model
|
||||
signals), so the back-to-back begin/end still triggers the proxy re-filter reading the
|
||||
updated data. Behavior preserved.
|
||||
|
||||
## Esri dictionary processors — dictionary equivalence
|
||||
|
||||
The Qt6 API churn in `esri_dictionary_processor{,_app6,_app6d,_mil2525d}.cpp`
|
||||
(`splitRef`→`split`, `rightRef`→`right`, `.toString()` removal) is migration-only.
|
||||
The three `SymbologyImpl` files that use the ArcGIS symbol-search/swatch/fetch API —
|
||||
`esri_dictionary_processor.cpp`, `symbol_dictionary_impl.cpp`, `base_symbol_model.cpp` —
|
||||
were **ported from the 100.x `TaskWatcher` signal/slot model to the 300 `QFuture` async
|
||||
model** (see "ArcGIS 300 QFuture port" below) and now **compile and link** against the 300
|
||||
SDK (see Build results).
|
||||
|
||||
## ArcGIS 300 include-style reconciliation
|
||||
|
||||
The 300 SDK is **flat** (`FIND_PATH(ARCGIS_INCLUDE_DIR ArcGISQt_global.h …)` in
|
||||
`FindArcGIS.cmake` finds it directly in `sdk/include/`), so the correct form is **bare**
|
||||
(`#include <Viewpoint.h>`), not `<arcgis/Viewpoint.h>`. The migration already dropped the
|
||||
prefix in the Esri processors; the Map layer + `expand_polygon` still carried it. The
|
||||
**11** `arcgis/`-prefixed includes were reconciled to bare (one consistent form):
|
||||
|
||||
- 10 ESRI headers (`SceneViewTypes`, `Error`, `CoreTypes`, `MapTypes`, `Viewpoint`,
|
||||
`Camera`, `PolygonBuilder`, `GeometryEngine`) — exist flat in the SDK, resolve.
|
||||
- 3 `arcgisversion.h` (custom RME header defining `ACRGIS_VERSION`, "created by RME, not
|
||||
ESRI") — made bare for consistency; the header itself is **absent from the repo**
|
||||
(pre-existing gap; see Remaining Issues).
|
||||
|
||||
Files touched: `Map/situation_map_utils.{h,cpp}`, `Map/map_initializer.cpp`,
|
||||
`Map/layer_factory.h`, `Explosions/expand_polygon.cpp`.
|
||||
|
||||
## ArcGIS 300 QFuture port (SymbologyImpl)
|
||||
|
||||
The 100.x ArcGIS Runtime exposed an async **task** API (`TaskWatcher` + per-task completion
|
||||
signals); the 300 SDK replaced it with **futures** (`QFuture<T>` + `QFutureWatcher<T>`).
|
||||
The three `SymbologyImpl` files were rewritten from the task model to the future model.
|
||||
This is a **semantic** change — the approved "blocking work item" (chosen by the user) — and
|
||||
every mapping below preserves the 100.x behavior (same work, same main-thread delivery, same
|
||||
completion order).
|
||||
|
||||
| 100.x (task API) | 300 (future API) |
|
||||
|---|---|
|
||||
| `searchSymbols(params) → TaskWatcher` + `searchSymbolsCompleted` | `searchSymbolsAsync(params) → QFuture<SymbolStyleSearchResultListModel*>` |
|
||||
| `SymbolStyleSearchResult::symbol(QObject*) → Symbol*` (sync) | `fetchSymbolAsync(QObject*) → QFuture<Symbol*>` |
|
||||
| `Symbol::createSwatch(w,h,scale) → TaskWatcher` + `createSwatchCompleted` | `createSwatchAsync(...) → QFuture<QImage>` |
|
||||
| `DictionarySymbolStyle::fetchSymbol(map) → TaskWatcher` + `fetchSymbolCompleted` | `fetchSymbolAsync(map, QObject*) → QFuture<Symbol*>` |
|
||||
| `QtConcurrent::run(this, &Class::method)` | `QtConcurrent::run(&Class::method, this)` (Qt6: member fn first, receiver second) |
|
||||
|
||||
Behavior-preserving details (each verified against the 300 headers):
|
||||
|
||||
- **`QFutureWatcher<T>` `result` signal/getter name collision.** `QFutureWatcher<T>` declares both
|
||||
a **signal** `void result(const T&)` and a **getter** `T result() const` — same name, so
|
||||
`&QFutureWatcher<T>::result` is ambiguous, and `QOverload<Args>(…)` / `qOverload<Args>(…)` both
|
||||
fail (the getter poisons template deduction). Working form: connect to the unambiguous
|
||||
`void finished()` signal and read the value via the `result()` getter
|
||||
(`connect(w, &QFutureWatcher<T>::finished, w, [w]{ auto v = w->result(); …; w->deleteLater(); });`).
|
||||
`finished()` fires on the watcher's (main) thread once the future is done — the same main-thread
|
||||
delivery the 100.x `TaskWatcher` completion signals gave.
|
||||
- **Non-const `fetchSymbolAsync`.** `SymbolStyleSearchResult::fetchSymbolAsync(QObject*)` is
|
||||
**non-const** (no `const` suffix, `SymbolStyleSearchResult.h`), so it can't be called on the
|
||||
`const` search result stored in the map. Fix: copy the (cheap, shared_ptr-backed)
|
||||
`SymbolStyleSearchResult` into a non-const local and call `fetchSymbolAsync` on the copy.
|
||||
- **Swatch future correlation.** 100.x correlated a swatch to its request via the SDK-issued task
|
||||
id; a 300 future carries no id. Fix: the per-request `QFutureWatcher<QImage>` lambda captures a
|
||||
caller-generated `QUuid` (`csTaskId`); `onEsriSymbolSwatchCompleted` is otherwise unchanged.
|
||||
`Symbol::symbol()` (100.x const/sync) is gone → `fetchSymbolAsync` (async) under
|
||||
`CREATE_ESRI_SYMBOL_ON_DEMAND`.
|
||||
- **`QtConcurrent::run(renderExtensions, const QImage&, …)` → `QFuture<void>`.** `renderExtensions`
|
||||
takes a **non-const** `QImage&` (it scales / replaces color in place); passing a `const QImage&`
|
||||
hit Qt6's `QPromise` overload → `QFuture<void>` (unassignable to `QFuture<QImage>`). Fix: wrap in a
|
||||
lambda returning `QImage` that passes a **local non-const copy** (a `QImage` copy is a shallow
|
||||
implicit-share refcount bump; the one deep copy is `renderExtensions`' own `scaled()`, exactly as
|
||||
100.x mutated `QtConcurrent::run`'s stored copy).
|
||||
- **`DictionarySymbolStyle(QString)` / `(QString, QString)` ctors removed** →
|
||||
`DictionarySymbolStyle::createFromFile(path)` (local `.stylx`); empty/missing path returns
|
||||
`false` (mirrors the ARCADE branch; 300 has no built-in spec-only dict).
|
||||
- **`Error::code()` removed** → `error.arcGISServerErrorCode().value_or(-1)`.
|
||||
- **`LoadStatus` / `Error` incomplete** → `#include <MapTypes.h>` / `#include <Error.h>` (300
|
||||
`LoadStatus` is an `enum class` in `MapTypes.h`; `Loadable.h` only forward-declares it).
|
||||
- **`arcgis/arcgisversion.h` (custom RME header) dropped by 300** → a shim `arcgisversion.h`
|
||||
was added to the 300 SDK include dir (`external/ArcGIS/…/sdk/include/`, so every `ArcGIS::ArcGIS`
|
||||
consumer finds it) defining `ACRGIS_VERSION = 300000000` (> every 100.x `0x64xxxx` gate, so each
|
||||
`#if ACRGIS_VERSION >= 0x64xxxx` takes the "newest SDK" branch; the single
|
||||
`#if ACRGIS_VERSION < 0x640500` correctly takes its else).
|
||||
- **Syntax fix:** a `// Qt6: leftRef removed` comment had swallowed the trailing `);` of two
|
||||
`castToSymbolSet(… .left(2).toUInt())` statements (`base_symbol_model.cpp`); restructured so the
|
||||
parens close before the comment.
|
||||
|
||||
## Build results
|
||||
|
||||
- **Pure-Qt symbology (green):** `situationMapCommon` and `advancedSymbologyXML` build
|
||||
and link (in `build4` and reconfirmed under the ArcGIS-ON configure). These carry no
|
||||
ArcGIS dependency.
|
||||
- **ArcGIS-ON configure (green):** `BUILD_RTI=ON BUILD_GRANTLEE=ON BUILD_ARCGIS=ON`
|
||||
configures successfully; `FindArcGIS.cmake` resolves the 300 SDK
|
||||
(`Found ArcGIS: .../sdk/linux/x64/lib/libEsriRuntimeQt.a`).
|
||||
- **ArcGIS-ON build of `advancedSymbology` (green):** after the QFuture port, the
|
||||
ArcGIS-dependent target (`Symbology` SIDC codec + `SymbologyImpl` Esri processors, links
|
||||
`ArcGIS::ArcGIS`) compiles and links — `libadvancedSymbology.so` built with **0 errors**
|
||||
(build log `/tmp/arcgis300_targeted_build5.log`).
|
||||
- **CTest (green for this change):** the 6 symbology-family `SymbologyXML.*` tests pass
|
||||
(`ctest -R SymbologyXML` → 6/6). Full `migration_tests` suite: **604/644 pass, 0 actual
|
||||
assertion failures** — the 40 non-passing are 31 "Not Run" (unbuilt test exes of unrelated
|
||||
modules — ngl/dds/aes/bld_/taboc/wls/LtsDataView/Grantlee — a pre-existing build-scope gap,
|
||||
not symbology) and 9 "Subprocess aborted" (display-dependent GUI tests; the 7 `LtsWidgetsQt6.*`
|
||||
pass under `QT_QPA_PLATFORM=offscreen`, confirmed 10/10). None touch the symbology family.
|
||||
|
||||
## Remaining issues / risks
|
||||
|
||||
- **RESOLVED — `SymbologyImpl` 100.x ArcGIS task API (was the blocker).** The three
|
||||
`SymbologyImpl` files previously used the 100.x `TaskWatcher` task API
|
||||
(`searchSymbols`/`createSwatch`/`fetchSymbol` → `TaskWatcher` + completion signals), which the
|
||||
300 SDK removed. They were **ported to the 300 `QFuture` async model** (see "ArcGIS 300 QFuture
|
||||
port" above) and now **compile and link** against the 300 SDK (`advancedSymbology` green).
|
||||
This was a semantic change — the approved "blocking work item" chosen by the user — superseding
|
||||
the earlier note that it was "out of scope for a verify-only task."
|
||||
|
||||
- **Map layer excluded:** `SituationMap/CMakeLists.txt` has `ADD_SUBDIRECTORY(Map)`,
|
||||
`MapImpl`, `MapObjects` **commented out**; no `Map/CMakeLists.txt`. The ArcGIS-300 Map
|
||||
integration (beyond include paths — `Viewpoint`/`Camera`/`MapTypes` 300 API changes) is a
|
||||
separate, not-yet-complete migration and is not in the current green build.
|
||||
- **`BUILD_WITH_EXTERNAL_DDS` never defined** (see item 2): the DDS `roleToRole`/
|
||||
`ForeignInterfaceImpl` real path is dead code; the no-op stub compiles. Behavior delta
|
||||
vs legacy, codebase-wide, pre-existing in the migration.
|
||||
- **`arcgisversion.h` (custom RME header) — RESOLVED:** the 300 SDK dropped this header (it
|
||||
defined `ACRGIS_VERSION` for the `#if ACRGIS_VERSION >= …` version gates). A shim
|
||||
`arcgisversion.h` was added to the 300 SDK include dir (`external/ArcGIS/…/sdk/include/`,
|
||||
`ACRGIS_VERSION = 300000000`) so every gate takes the "newest SDK" branch (see the QFuture-port
|
||||
section). It lives in the external SDK tree (not the Legatus repo) because it is a drop-in
|
||||
replacement for the SDK-shipped header.
|
||||
Reference in new issue
Block a user