3040 lines
106 KiB
C++
Executable File
3040 lines
106 KiB
C++
Executable File
/**
|
||
* @RDE_HEADER@
|
||
* Interface-Implementation of LayerFactory
|
||
* $Id$
|
||
* $HeadURL$
|
||
* $Author$
|
||
*/
|
||
|
||
// Own
|
||
#include "layer_factory_impl.h"
|
||
#include "map_impl.h"
|
||
#include "abstract_map_object_impl.h"
|
||
#include <Map/situation_map_utils.h>
|
||
#include "logical_layer.h"
|
||
#include "location_to_elevation_helper.h"
|
||
//#include "tms_layer.h"
|
||
#include <Common/resource_path.h> // for getResourcePath
|
||
#include <SymbologyImpl/symbol_dictionary_impl.h>
|
||
|
||
#include <ElevationMap/elevation_map_manager.h>
|
||
|
||
// ESRI
|
||
#include <arcgis/arcgisversion.h> // This file is created by RME, not ESRI
|
||
#include <arcgis/Map.h>
|
||
#include <arcgis/Layer.h>
|
||
#include <arcgis/TileCache.h>
|
||
#include <arcgis/ArcGISTiledLayer.h>
|
||
#include <arcgis/Raster.h>
|
||
#include <arcgis/RasterLayer.h>
|
||
#include <arcgis/Scene.h>
|
||
#include <arcgis/ArcGISSceneLayer.h>
|
||
#include <arcgis/RasterElevationSource.h>
|
||
#include <arcgis/ArcGISTiledElevationSource.h>
|
||
#include <arcgis/GraphicsOverlay.h>
|
||
#include <arcgis/MapGraphicsView.h>
|
||
#include <arcgis/SimpleFillSymbol.h>
|
||
#include <arcgis/SimpleMarkerSymbol.h>
|
||
#include <arcgis/PictureMarkerSymbol.h>
|
||
#include <arcgis/SimpleMarkerSceneSymbol.h>
|
||
#include <arcgis/UniqueValueRenderer.h>
|
||
|
||
#include <arcgis/ArcGISVectorTiledLayer.h>
|
||
#include <arcgis/ArcGISMapImageLayer.h>
|
||
|
||
|
||
// Qt
|
||
#include <QDir>
|
||
#include <QEventLoop>
|
||
#include <QFileInfo>
|
||
#include <QNetworkProxy>
|
||
#include <QVector>
|
||
#include <QCoreApplication>
|
||
|
||
#include <iostream>
|
||
|
||
// FORCE_CREATION_GRAPHICSOVERLAY :
|
||
// N.Thoden, 10.02.2017
|
||
// Esri Case #01887547 - [BOS] Dictionary Symbol crasches
|
||
// deals with order of creation of GraphicalOverlay and adding them to MapView.
|
||
// Although the reordering of the GraphicalOverlay is not included in the case,
|
||
// it seems to be relevant in this application.
|
||
// To find a quick solution, GraphicalOverlays are created as soon as possible
|
||
// (EsriDict must be loaded).
|
||
//
|
||
static bool s_forceCreationOfGraphicsOverlay = true;
|
||
// : FORCE_CREATION_GRAPHICSOVERLAY
|
||
|
||
|
||
namespace SituationMap
|
||
{
|
||
|
||
static const QLatin1String LayerNameJumpPoints("JumpPoints");
|
||
static const QLatin1String LayerNameRubberband("RubberbandLayer");
|
||
static const QLatin1String LayerNameTools("Tools");
|
||
static const QLatin1String LayerNameSnapshotOverlay("SnaphotOverlay");
|
||
static const QLatin1String LayerNameEmergencyCall("EmergencyCall");
|
||
|
||
// #define USE_ARCGIS_SCENE_LAYER_CACHE
|
||
#ifdef USE_ARCGIS_SCENE_LAYER_CACHE
|
||
|
||
class ArcGISSceneLayerCache;
|
||
static ArcGISSceneLayerCache *s_arcGisSceneLayerCache = nullptr;
|
||
|
||
/*!
|
||
* \brief The ArcGISSceneLayerCache class reduces the number of loading processes
|
||
* We are caching here to avoid numerous loading and unloading.
|
||
* At least at linux the ArcGISSceneLayerCache tends to alloc a hugh amount of data.
|
||
* Additionally allocation is influenced by the viewpoint choosen by the operator.
|
||
* And with other allocations (dds data, GBViewer of similar) at the same time
|
||
* the heap memory gets fragemented.
|
||
* So we try to reduce the number of loading processes.
|
||
*/
|
||
class ArcGISSceneLayerCache
|
||
{
|
||
public:
|
||
static ArcGISSceneLayerCache *getInstance()
|
||
{
|
||
if (!s_arcGisSceneLayerCache)
|
||
{
|
||
s_arcGisSceneLayerCache = new ArcGISSceneLayerCache;
|
||
qAddPostRoutine(&ArcGISSceneLayerCache::cleanup);
|
||
}
|
||
return s_arcGisSceneLayerCache;
|
||
}
|
||
|
||
struct Item
|
||
{
|
||
QPointer<Esri::ArcGISRuntime::ArcGISSceneLayer> m_sceneLayer;
|
||
QPointer<Esri::ArcGISRuntime::Scene> m_hostingScene;
|
||
};
|
||
|
||
Item& getFreeItemRef(const QString &itemName)
|
||
{
|
||
//Qt: If the map contains no item with key key, the function inserts a default-constructed value into the map with key key, and returns a reference to it.
|
||
QVector<Item> &vec = m_arcGISSceneLayerCache[itemName];
|
||
|
||
// search free item:
|
||
QMutableVectorIterator<Item> it(vec);
|
||
while (it.hasNext())
|
||
{
|
||
Item& itemRef = it.next();
|
||
if (itemRef.m_hostingScene.isNull())
|
||
return itemRef;
|
||
}
|
||
|
||
// Not found -> create:
|
||
vec.append(Item());
|
||
return vec.last();
|
||
}
|
||
|
||
static void cleanup()
|
||
{
|
||
delete s_arcGisSceneLayerCache;
|
||
}
|
||
|
||
~ArcGISSceneLayerCache()
|
||
{
|
||
for (auto vec : m_arcGISSceneLayerCache)
|
||
{
|
||
for (auto item : vec)
|
||
{
|
||
std::cerr << " m_arcGISSceneLayerCache: delete " << item.m_sceneLayer << std::endl;
|
||
delete item.m_sceneLayer; // delete nullptr is ok
|
||
}
|
||
}
|
||
}
|
||
|
||
void dump()
|
||
{
|
||
std::cerr << " ArcGISSceneLayer CacheSize = " << m_arcGISSceneLayerCache.size() << std::endl;
|
||
|
||
for (auto vec : m_arcGISSceneLayerCache)
|
||
{
|
||
std::cerr << " ArcGISSceneLayer VectorSize: " << vec.size() << std::endl;
|
||
for (auto item : vec)
|
||
{
|
||
std::cerr << " ArcGISSceneLayer ITEM = "
|
||
<< " m_hostingScene=" << item.m_hostingScene
|
||
<< " m_sceneLayer=" << item.m_sceneLayer
|
||
<< std::endl;
|
||
} // for
|
||
} // for
|
||
}
|
||
|
||
private:
|
||
// slpk-name, ....
|
||
QMap<QString, QVector<Item>> m_arcGISSceneLayerCache;
|
||
}; // class ArcGISSceneLayerCache
|
||
|
||
#endif // USE_ARCGIS_SCENE_LAYER_CACHE
|
||
|
||
|
||
class LayerFactoryImpl::Private
|
||
{
|
||
public:
|
||
Private() = default;
|
||
~Private() = default;
|
||
|
||
|
||
// ESRI data:
|
||
Esri::ArcGISRuntime::Basemap *m_basemap = nullptr;
|
||
|
||
Esri::ArcGISRuntime::GraphicsOverlayListModel *getEsriGraphicsOverlayListModel()
|
||
{
|
||
if (m_mapImpl && m_mapImpl->getEsriGeoView())
|
||
return m_mapImpl->getEsriGeoView()->graphicsOverlays();
|
||
else
|
||
return nullptr;
|
||
}
|
||
|
||
|
||
Esri::ArcGISRuntime::GraphicsOverlay *m_functionDialogGraphicsLayer = nullptr;
|
||
|
||
|
||
// Own data:
|
||
SituationMap::MapImpl *m_mapImpl = nullptr;
|
||
QStringList m_mapServiceUrlList;
|
||
QVector<QUrl> m_sceneObjectUrlCont;
|
||
Esri::ArcGISRuntime::Surface *m_baseSurface = nullptr;
|
||
bool m_isSceneObjectLayerVisible = true;
|
||
|
||
QTimer *reCalculateMinMaxScaleTimer = nullptr;
|
||
|
||
MapLayerOrderedList m_orderedMapLayer; // store order of basemap and logical Layernames
|
||
|
||
bool hasLogicalLayer(const QString &logicalName)
|
||
{
|
||
return m_logicalLayerCont.contains(logicalName);
|
||
}
|
||
|
||
// create and initalize LogicalLayer:
|
||
void createLogicalLayer(const QString &logicalName)
|
||
{
|
||
// LayerListModel
|
||
Esri::ArcGISRuntime::LayerListModel *layerListModel = nullptr;
|
||
if (m_basemap)
|
||
layerListModel = m_basemap->baseLayers();
|
||
|
||
// GraphicsOverlayListModel
|
||
Esri::ArcGISRuntime::GraphicsOverlayListModel *graphicsOverlayListModel = this->getEsriGraphicsOverlayListModel();
|
||
|
||
#ifdef LTS_DEBUG
|
||
if (!graphicsOverlayListModel)
|
||
qCritical() << " graphicsOverlayListModel"
|
||
<< " logicalName='" << logicalName << "'"
|
||
<< " m_mapImpl=" << m_mapImpl
|
||
<< " m_mapImpl->getEsriGeoView()=" << m_mapImpl->getEsriGeoView()
|
||
<< " m_mapImpl->isReady=" << m_mapImpl->isReady()
|
||
<< " graphicsOverlayListModel=" << graphicsOverlayListModel;
|
||
Q_ASSERT(graphicsOverlayListModel);
|
||
#endif // LTS_DEBUG
|
||
|
||
QSharedPointer<LogicalLayer> ll = QSharedPointer<LogicalLayer>(new LogicalLayer(logicalName));
|
||
ll->init(m_mapImpl, layerListModel, graphicsOverlayListModel);
|
||
m_logicalLayerCont[logicalName] = ll;
|
||
}
|
||
|
||
QSharedPointer<LogicalLayer> getLogicalLayer(const QString &logicalName) const
|
||
{
|
||
if (m_logicalLayerCont.contains(logicalName))
|
||
return m_logicalLayerCont[logicalName];
|
||
return QSharedPointer<LogicalLayer>();
|
||
}
|
||
void removeLogicalLayer(const QString &logicalName)
|
||
{
|
||
m_logicalLayerCont.remove(logicalName);
|
||
}
|
||
|
||
QMap<QString, QSharedPointer<LogicalLayer>> m_logicalLayerCont; // store logical layer without order
|
||
|
||
QString m_basemapLayernamePrefix = QLatin1String("ArcGISTiledLayer_URL_");
|
||
|
||
QString m_participantLayername = QLatin1String("Participants");
|
||
RenderingMode m_participantLayerRenderingMode = RenderingMode::Dynamic;
|
||
SurfacePlacement m_participantLayerSurfacePlacement = SurfacePlacement::Relative;
|
||
|
||
|
||
QString m_logicalLayerNameForCubes;
|
||
|
||
#if ACRGIS_VERSION < 0x640500 // 100.5.0 / Update 5
|
||
QColor m_selectionColor = Qt::magenta;
|
||
#endif // ACRGIS_VERSION
|
||
|
||
|
||
}; // class LayerFactoryImpl::Private
|
||
//-----------------------------------------------------------------------------
|
||
|
||
//
|
||
// class LayerFactoryImpl;
|
||
//
|
||
LayerFactoryImpl::LayerFactoryImpl(QObject *parent, SituationMap::MapImpl *mapImpl)
|
||
: LayerFactory()
|
||
, BaseClass(parent)
|
||
, m_logger(getLogger("LayerFactoryImpl"))
|
||
, d(new Private)
|
||
{
|
||
TRACE_LOG(m_logger) << LOGFUNCTION << " START";
|
||
|
||
d->m_mapImpl = mapImpl;
|
||
if (d->m_mapImpl)
|
||
d->m_basemap = d->m_mapImpl->getEsriBasemap();
|
||
|
||
d->reCalculateMinMaxScaleTimer = new QTimer(this);
|
||
d->reCalculateMinMaxScaleTimer->setInterval(500);
|
||
d->reCalculateMinMaxScaleTimer->setSingleShot(true);
|
||
connect(d->reCalculateMinMaxScaleTimer, &QTimer::timeout,
|
||
this, &LayerFactoryImpl::reCalculateMinMaxScaleBasedOnLayers);
|
||
|
||
INFO_LOG(m_logger) << LOGFUNCTION << " Resource Path = '" << SituationMap::getResourcePath() << "'";
|
||
|
||
TRACE_LOG(m_logger) << LOGFUNCTION << " END";
|
||
}
|
||
|
||
|
||
LayerFactoryImpl::~LayerFactoryImpl()
|
||
{
|
||
TRACE_LOG(m_logger) << LOGFUNCTION << " START";
|
||
delete d;
|
||
TRACE_LOG(m_logger) << LOGFUNCTION << " END";
|
||
}
|
||
|
||
bool LayerFactoryImpl::initializeBasemapBuiltIn(const QString &tpkFile)
|
||
{
|
||
TRACE_LOG(m_logger) << LOGFUNCTION << " START"
|
||
<< " tpkFile='" << tpkFile << "'";
|
||
|
||
QString tiledBaseMapLayer;
|
||
if (tpkFile.isEmpty())
|
||
tiledBaseMapLayer = SituationMap::getResourcePath() + QLatin1String("Topographic.tpk");
|
||
else
|
||
{
|
||
QFileInfo fi(tpkFile);
|
||
if (fi.isAbsolute())
|
||
tiledBaseMapLayer = tpkFile;
|
||
else
|
||
{
|
||
tiledBaseMapLayer = SituationMap::getResourcePath() + tpkFile;
|
||
if (fi.suffix().isEmpty())
|
||
tiledBaseMapLayer += QLatin1String(".tpk");
|
||
}
|
||
}
|
||
|
||
DEBUG_LOG(m_logger) << LOGFUNCTION << " tiledBaseMapLayer='" << tiledBaseMapLayer << "'";
|
||
|
||
//-----------------------------------
|
||
// Local Tiled Basemap Layer using: sdk/samples/data/tpks/Topographic.tpk
|
||
//-----------------------------------
|
||
Esri::ArcGISRuntime::TileCache *tpkCache = new Esri::ArcGISRuntime::TileCache(tiledBaseMapLayer, this);
|
||
tpkCache->setObjectName(QLatin1String("TPK-tpkCache"));
|
||
|
||
Esri::ArcGISRuntime::ArcGISTiledLayer *tiledLayer = new Esri::ArcGISRuntime::ArcGISTiledLayer(tpkCache, this);
|
||
tiledLayer->setName(QLatin1String("TPK-tiledLayer"));
|
||
|
||
|
||
// loadStatusChanged ->
|
||
connect(tpkCache, &Esri::ArcGISRuntime::TileCache::loadStatusChanged, this, [this](Esri::ArcGISRuntime::LoadStatus loadStatus)
|
||
{
|
||
DEBUG_LOG(m_logger) << LOGFUNCTION << " TileCache: " << "loadStatus changed to: " << loadStatus;
|
||
});
|
||
connect(tiledLayer, &Esri::ArcGISRuntime::ArcGISTiledLayer::loadStatusChanged, this, [this](Esri::ArcGISRuntime::LoadStatus loadStatus)
|
||
{
|
||
DEBUG_LOG(m_logger) << LOGFUNCTION << " ArcGISTiledLayer: " << "loadStatus changed to: " << loadStatus;
|
||
});
|
||
|
||
|
||
QString logicalLayerName = QStringLiteral("%1%2").arg(d->m_basemapLayernamePrefix).arg(0);
|
||
tiledLayer->setName(logicalLayerName);
|
||
tiledLayer->setObjectName(tiledLayer->name());
|
||
|
||
QSharedPointer<LogicalLayer> logicalLayer = addLayerToMgnt(logicalLayerName, LayerType::Basemap);
|
||
if (logicalLayer.isNull())
|
||
ERROR_LOG(m_logger) << LOGFUNCTION << " getLogicalLayer invalid'" << logicalLayerName << "'";
|
||
else
|
||
{
|
||
// update LayerParameter first:
|
||
LayerParameter lp = logicalLayer->layerParameter();
|
||
lp.url = QUrl(tiledBaseMapLayer);
|
||
lp.displayName = logicalLayerName;
|
||
logicalLayer->setLayerParameter(lp);
|
||
|
||
logicalLayer->setLayer(tiledLayer);
|
||
logicalLayer->setLayerType(LayerType::Basemap);
|
||
logicalLayer->setBasemapType(BasemapType::Topographic); // basemapType -> aerial, topo...
|
||
}
|
||
|
||
|
||
int basemapCount = -1;
|
||
if (d->m_basemap->baseLayers())
|
||
basemapCount = d->m_basemap->baseLayers()->size();
|
||
|
||
INFO_LOG(m_logger) << LOGFUNCTION << " basemapCount = " << basemapCount;
|
||
|
||
d->m_basemap->baseLayers()->append(tiledLayer);
|
||
|
||
TRACE_LOG(m_logger) << LOGFUNCTION << " END";
|
||
return true;
|
||
}
|
||
|
||
bool LayerFactoryImpl::isUsingBaseMapBuiltIn() const
|
||
{
|
||
return d->m_mapServiceUrlList.isEmpty();
|
||
}
|
||
|
||
bool LayerFactoryImpl::addOperationalLayer(const QString &logicalLayerName,
|
||
const QString &displayName,
|
||
RenderingMode renderMode,
|
||
SurfacePlacement surfacePlacement)
|
||
{
|
||
TRACE_LOG(m_logger) << LOGFUNCTION << " START"
|
||
<< " logicalLayerName='" << logicalLayerName << "'"
|
||
<< " displayName='" << displayName << "'"
|
||
<< " renderMode=" << renderMode
|
||
<< " surfacePlacement=" << surfacePlacement;
|
||
|
||
if (s_forceCreationOfGraphicsOverlay && !logicalLayerName.startsWith(QLatin1String("Participant"), Qt::CaseInsensitive))
|
||
{
|
||
// First, wait until esriDict is load, second force creation of esriLayer:
|
||
|
||
// wait until esriDict is load:
|
||
AdvancedSymbology::SymbolDictionary &dict = d->m_mapImpl->symbolDictionary();
|
||
AdvancedSymbology::SymbolDictionaryImpl &dictImpl = static_cast<AdvancedSymbology::SymbolDictionaryImpl &>(dict);
|
||
|
||
// keep SymbologyType::None in mind:
|
||
Esri::ArcGISRuntime::DictionarySymbolStyle *esriDict = const_cast<Esri::ArcGISRuntime::DictionarySymbolStyle *>(dictImpl.getEsriSymbolDictionary());
|
||
|
||
if (esriDict)
|
||
{
|
||
if (esriDict->loadStatus() != Esri::ArcGISRuntime::LoadStatus::Loaded)
|
||
{
|
||
QEventLoop loop;
|
||
connect(esriDict, &Esri::ArcGISRuntime::DictionarySymbolStyle::doneLoading,
|
||
&loop, &QEventLoop::quit);
|
||
QTimer::singleShot(2000, &loop, &QEventLoop::quit);
|
||
loop.exec();
|
||
}
|
||
|
||
DEBUG_LOG(m_logger) << LOGFUNCTION << " FORCE_CREATION_GRAPHICSOVERLAY: "
|
||
<< " esriDict: loadStatus=" << esriDict->loadStatus();
|
||
}
|
||
} // if (s_forceCreationOfGraphicsOverlay)
|
||
|
||
const LayerType layerType = LayerType::Operational;
|
||
|
||
if (! layerExistsInMngt(logicalLayerName, layerType))
|
||
{
|
||
QSharedPointer<LogicalLayer> logicalLayer = addLayerToMgnt(logicalLayerName, layerType);
|
||
if (logicalLayer.isNull())
|
||
{
|
||
ERROR_LOG(m_logger) << LOGFUNCTION << " addLayer failed: '"
|
||
<< logicalLayerName << "'";
|
||
return false;
|
||
}
|
||
LayerParameter lp = logicalLayer->layerParameter();
|
||
lp.displayName = displayName;
|
||
logicalLayer->setLayerParameter(lp);
|
||
logicalLayer->setRenderingMode(renderMode);
|
||
logicalLayer->setSurfacePlacement(surfacePlacement);
|
||
}
|
||
|
||
|
||
//
|
||
// the real Esri-Layers will be create later on demand :-)
|
||
//
|
||
|
||
//#ifdef FORCE_CREATION_GRAPHICSOVERLAY
|
||
if (s_forceCreationOfGraphicsOverlay && !logicalLayerName.startsWith(QLatin1String("Participant"), Qt::CaseInsensitive))
|
||
{
|
||
QSharedPointer<LogicalLayer> logicalLayer = d->getLogicalLayer(logicalLayerName);
|
||
if (logicalLayer)
|
||
{
|
||
logicalLayer->getCreateGraphicalOverlay(TechnicalLayerType::GraphicsLayer);
|
||
if (d->m_mapImpl->symbologyType() != AdvancedSymbology::SymbologyType::None)
|
||
logicalLayer->getCreateGraphicalOverlay(TechnicalLayerType::GraphicsLayer_Dict);
|
||
DEBUG_LOG(m_logger) << LOGFUNCTION << " FORCE_CREATION_GRAPHICSOVERLAY";
|
||
}
|
||
} // if (s_forceCreationOfGraphicsOverlay)
|
||
//#endif // FORCE_CREATION_GRAPHICSOVERLAY
|
||
|
||
|
||
TRACE_LOG(m_logger) << LOGFUNCTION << " END"
|
||
<< " logicalLayerName='" << logicalLayerName << "'"
|
||
<< " success=" << true;
|
||
return true;
|
||
}
|
||
|
||
|
||
bool LayerFactoryImpl::removeOperationalLayer(const QString &logicalLayerName)
|
||
{
|
||
TRACE_LOG(m_logger) << LOGFUNCTION << " START"
|
||
<< " logicalLayerName='" << logicalLayerName << "'";
|
||
|
||
if (logicalLayerName.isEmpty())
|
||
{
|
||
ERROR_LOG(m_logger) << LOGFUNCTION << " logicalLayerName empty"
|
||
<< logicalLayerName;
|
||
return false;
|
||
}
|
||
|
||
const LayerType layerType = LayerType::Operational;
|
||
|
||
if (! d->m_orderedMapLayer.contains(logicalLayerName, layerType))
|
||
{
|
||
ERROR_LOG(m_logger) << LOGFUNCTION << " logicalLayerName does not exist: '"
|
||
<< logicalLayerName << "'";
|
||
return false;
|
||
}
|
||
|
||
if (removeLayerInternal(layerType, logicalLayerName))
|
||
d->m_mapImpl->emitLayerOrderChanged();
|
||
|
||
|
||
TRACE_LOG(m_logger) << LOGFUNCTION << " END"
|
||
<< " logicalLayerName='" << logicalLayerName << "'";
|
||
return true;
|
||
}
|
||
|
||
bool LayerFactoryImpl::hasOperationalLayer(const QString &logicalLayerName) const
|
||
{
|
||
if (logicalLayerName.isEmpty())
|
||
{
|
||
ERROR_LOG(m_logger) << LOGFUNCTION << " logicalLayerName empty"
|
||
<< logicalLayerName;
|
||
return false;
|
||
}
|
||
return layerExistsInMngt(logicalLayerName, LayerType::Operational);
|
||
}
|
||
|
||
|
||
bool LayerFactoryImpl::addOverlayLayer(const QString &logicalLayerName, const QString &displayName, bool isSnaphot)
|
||
{
|
||
TRACE_LOG(m_logger) << LOGFUNCTION << " START"
|
||
<< " logicalLayerName='" << logicalLayerName << "'"
|
||
<< " displayName='" << displayName << "'"
|
||
<< " isSnaphot='" << isSnaphot;
|
||
|
||
const LayerType layerType = (isSnaphot) ? LayerType::SnapshotOverlay : LayerType::Overlay;
|
||
|
||
if (! layerExistsInMngt(logicalLayerName, layerType))
|
||
{
|
||
QSharedPointer<LogicalLayer> logicalLayer = addLayerToMgnt(logicalLayerName, layerType);
|
||
if (logicalLayer.isNull())
|
||
{
|
||
ERROR_LOG(m_logger) << LOGFUNCTION << " addLayer failed: '"
|
||
<< logicalLayerName << "'";
|
||
return false;
|
||
}
|
||
// logicalLayer->setRenderingMode(RenderingMode::Dynamic);
|
||
}
|
||
|
||
// update displayName:
|
||
QSharedPointer<LogicalLayer> logicalLayer = d->getLogicalLayer(logicalLayerName);
|
||
if (logicalLayer.isNull())
|
||
{
|
||
WARNING_LOG(m_logger) << LOGFUNCTION << " getLogicalLayer failed: '"
|
||
<< logicalLayerName << "'";
|
||
} else {
|
||
LayerParameter lp = logicalLayer->layerParameter();
|
||
lp.displayName = displayName;
|
||
logicalLayer->setLayerParameter(lp);
|
||
}
|
||
|
||
|
||
//
|
||
// the real Esri-Layers will be create later on demand :-)
|
||
//
|
||
|
||
TRACE_LOG(m_logger) << LOGFUNCTION << " END";
|
||
return true;
|
||
}
|
||
|
||
QString LayerFactoryImpl::technicalNameOfOverlayLayer(const QString &logicalLayerName)
|
||
{
|
||
// By default, our overlays are displayed on just one GraphicsLayer:
|
||
return createInternalLayerName(TechnicalLayerType::GraphicsLayer, logicalLayerName);
|
||
}
|
||
|
||
|
||
QSharedPointer<LogicalLayer> LayerFactoryImpl::addLayerToMgnt(const QString &logicalLayerName, const LayerType &layerType)
|
||
{
|
||
TRACE_LOG(m_logger) << LOGFUNCTION << " START"
|
||
<< " layerType=" << layerType
|
||
<< " logicalLayerName='" << logicalLayerName << "'";
|
||
|
||
QSharedPointer<LogicalLayer> logicalLayer;
|
||
|
||
if (logicalLayerName.isEmpty())
|
||
{
|
||
ERROR_LOG(m_logger) << LOGFUNCTION << " logicalLayerName empty"
|
||
<< logicalLayerName;
|
||
return logicalLayer;
|
||
}
|
||
if (d->m_orderedMapLayer.contains(logicalLayerName, LayerType::Undefined))
|
||
{
|
||
ERROR_LOG(m_logger) << LOGFUNCTION << " logicalLayerName already exists: '"
|
||
<< logicalLayerName << "'";
|
||
return logicalLayer;
|
||
}
|
||
|
||
// 1. add to orderedList:
|
||
|
||
if (! d->m_orderedMapLayer.addLayer(logicalLayerName, layerType))
|
||
{
|
||
ERROR_LOG(m_logger) << LOGFUNCTION << " addLayer failed: '"
|
||
<< logicalLayerName << "'"
|
||
<< " layerType=" << layerType;
|
||
return logicalLayer;
|
||
}
|
||
|
||
// getLogicalLayer will
|
||
// - initialize
|
||
// - do errorHandling
|
||
// - update LayerParameter on doneLoading
|
||
// - and add layer to LayerlistModel of basemap:
|
||
logicalLayer = this->getCreateLogicalLayer(logicalLayerName);
|
||
if (logicalLayer.isNull())
|
||
{
|
||
ERROR_LOG(m_logger) << LOGFUNCTION
|
||
<< " getLogicalLayer invalid'" << logicalLayerName << "'";
|
||
return logicalLayer;
|
||
}
|
||
logicalLayer->setLayerType(layerType);
|
||
|
||
|
||
DEBUG_LOG(m_logger) << LOGFUNCTION << " handleEmergencySpecials ...";
|
||
handleEmergencyCallSpecials();
|
||
DEBUG_LOG(m_logger) << LOGFUNCTION << " handleEmergencySpecials ...DONE";
|
||
|
||
// trigger gui update:
|
||
d->m_mapImpl->emitLayerOrderChanged();
|
||
|
||
TRACE_LOG(m_logger) << LOGFUNCTION << " END"
|
||
<< " layerType=" << layerType
|
||
<< " logicalLayerName='" << logicalLayerName << "'";
|
||
return logicalLayer;
|
||
}
|
||
|
||
bool LayerFactoryImpl::layerExistsInMngt(const QString &logicalLayerName, const LayerType &layerType) const
|
||
{
|
||
TRACE_LOG(m_logger) << LOGFUNCTION << " START"
|
||
<< " layerType=" << layerType
|
||
<< " logicalLayerName='" << logicalLayerName << "'";
|
||
|
||
bool exists = d->m_orderedMapLayer.contains(logicalLayerName, layerType);
|
||
|
||
TRACE_LOG(m_logger) << LOGFUNCTION << " END"
|
||
<< " layerType=" << layerType
|
||
<< " logicalLayerName='" << logicalLayerName << "'"
|
||
<< " exists=" << exists;
|
||
return exists;
|
||
}
|
||
|
||
bool LayerFactoryImpl::removeOverlayLayer(const QString &logicalLayerName)
|
||
{
|
||
TRACE_LOG(m_logger) << LOGFUNCTION << " START"
|
||
<< " layername='" << logicalLayerName << "'";
|
||
|
||
if (logicalLayerName.isEmpty())
|
||
{
|
||
ERROR_LOG(m_logger) << LOGFUNCTION << " logicalLayerName empty"
|
||
<< logicalLayerName;
|
||
return false;
|
||
}
|
||
const MapLayer &mapLayer = d->m_orderedMapLayer.getLayer(logicalLayerName);
|
||
if (!mapLayer.isValid())
|
||
{
|
||
ERROR_LOG(m_logger) << LOGFUNCTION << " logicalLayerName does not exist: '"
|
||
<< logicalLayerName << "'";
|
||
return false;
|
||
}
|
||
|
||
const LayerType type = mapLayer.type();
|
||
const bool isOverlayLayer = (type == LayerType::Overlay) || (type == LayerType::SnapshotOverlay);
|
||
if (!isOverlayLayer)
|
||
{
|
||
ERROR_LOG(m_logger) << LOGFUNCTION << " logicalLayerName has wrong type: '"
|
||
<< logicalLayerName << "'"
|
||
<< " type = " << type;
|
||
return false;
|
||
}
|
||
|
||
if (removeLayerInternal(type, logicalLayerName))
|
||
{
|
||
DEBUG_LOG(m_logger) << LOGFUNCTION << " remove..."
|
||
<< " layername='" << logicalLayerName << "'";
|
||
d->m_mapImpl->emitLayerOrderChanged();
|
||
}
|
||
|
||
|
||
TRACE_LOG(m_logger) << LOGFUNCTION << " END"
|
||
<< " logicalLayerName='" << logicalLayerName << "'";
|
||
return true;
|
||
}
|
||
|
||
QString LayerFactoryImpl::snapshotOverlayLayername() const
|
||
{
|
||
return LayerNameSnapshotOverlay;
|
||
}
|
||
|
||
QString LayerFactoryImpl::layernameForCubes() const
|
||
{
|
||
return d->m_logicalLayerNameForCubes;
|
||
}
|
||
|
||
void LayerFactoryImpl::setLayernameForCubes(const QString &logicalName)
|
||
{
|
||
d->m_logicalLayerNameForCubes = logicalName;
|
||
}
|
||
|
||
bool LayerFactoryImpl::hasLayernameForCubes() const
|
||
{
|
||
return !d->m_logicalLayerNameForCubes.isEmpty();
|
||
}
|
||
|
||
|
||
bool LayerFactoryImpl::assignUniqueValueRendererForCubes()
|
||
{
|
||
TRACE_LOG(m_logger) << LOGFUNCTION << " START"
|
||
<< " m_logicalLayerNameForCubes='" << d->m_logicalLayerNameForCubes << "'";
|
||
|
||
if (d->m_mapImpl->mode() != Mode::Mode_3D)
|
||
{
|
||
ERROR_LOG(m_logger) << LOGFUNCTION << " not in 3Dmode";
|
||
return false;
|
||
}
|
||
|
||
if (d->m_logicalLayerNameForCubes.isEmpty())
|
||
{
|
||
ERROR_LOG(m_logger) << LOGFUNCTION << " no m_logicalLayerNameForCubes configured";
|
||
return false;
|
||
}
|
||
|
||
|
||
|
||
Esri::ArcGISRuntime::GraphicsOverlay *graphicsOverlay = this->getGraphicsLayer(d->m_logicalLayerNameForCubes);
|
||
if (!graphicsOverlay)
|
||
{
|
||
ERROR_LOG(m_logger) << LOGFUNCTION << " graphicsOverlay not found, d->m_logicalLayerNameForCubes='" << d->m_logicalLayerNameForCubes << "'";
|
||
return false;
|
||
}
|
||
|
||
|
||
const PartyIdToColorFunctor::ColorMap &colorMap = d->m_mapImpl->partyIdToColorFunctor().colorMap();
|
||
if (colorMap.isEmpty())
|
||
{
|
||
ERROR_LOG(m_logger) << LOGFUNCTION << " colorMap is empty";
|
||
return false;
|
||
}
|
||
|
||
|
||
|
||
// prepare UniqueValues
|
||
Esri::ArcGISRuntime::SimpleFillSymbol *sls;
|
||
QList<Esri::ArcGISRuntime::UniqueValue *> uvList;
|
||
|
||
QObject *parent = graphicsOverlay;
|
||
|
||
for (const PartyIdToColorFunctor::PartyData &partyData : colorMap)
|
||
{
|
||
const QString &partyName = partyData.m_name;
|
||
const QColor &partyColor = partyData.m_color;
|
||
|
||
INFO_LOG(m_logger) << LOGFUNCTION
|
||
<< " partyName=" << partyName << "'"
|
||
<< " partyColor=" << partyColor.name() << "'";
|
||
|
||
sls = new Esri::ArcGISRuntime::SimpleFillSymbol(Esri::ArcGISRuntime::SimpleFillSymbolStyle::Solid, partyColor, parent);
|
||
|
||
Esri::ArcGISRuntime::UniqueValue *uv =
|
||
new Esri::ArcGISRuntime::UniqueValue(partyName, // more or less relevant
|
||
QStringLiteral("Party '%1'").arg(partyName),
|
||
QVariantList() << partyColor.name(), // (was in former times: partyName)
|
||
sls, parent);
|
||
uvList.append(uv);
|
||
} // for
|
||
|
||
//qt build in
|
||
// static QVector<QColor> addColors = {Qt::darkGray, Qt::gray, Qt::lightGray,
|
||
// Qt::red, Qt::green, Qt::blue,
|
||
// Qt::cyan, Qt::magenta, Qt::yellow,
|
||
// Qt::darkRed, Qt::darkGreen, Qt::darkBlue,
|
||
// Qt::darkCyan, Qt::darkMagenta, Qt::darkYellow, Qt::white};
|
||
static QVector<QColor> addColors = {
|
||
Qt::yellow
|
||
};
|
||
uvList.reserve(uvList.size() + addColors.size());
|
||
|
||
for (const QColor &addColor : qAsConst(addColors))
|
||
{
|
||
sls = new Esri::ArcGISRuntime::SimpleFillSymbol(Esri::ArcGISRuntime::SimpleFillSymbolStyle::Solid, addColor.name(), parent);
|
||
|
||
Esri::ArcGISRuntime::UniqueValue *uv =
|
||
new Esri::ArcGISRuntime::UniqueValue(addColor.name(), // more or less relevant
|
||
QStringLiteral("Party '%1'").arg(addColor.name()),
|
||
QVariantList() << addColor.name(), // (was in former times: partyName)
|
||
sls, parent);
|
||
uvList.append(uv);
|
||
} //for
|
||
|
||
// setup UniqueValueRenderer:
|
||
|
||
// setup default:
|
||
sls = new Esri::ArcGISRuntime::SimpleFillSymbol(Esri::ArcGISRuntime::SimpleFillSymbolStyle::Solid, Qt::white, this);
|
||
|
||
|
||
Esri::ArcGISRuntime::UniqueValueRenderer *uniqueRenderer =
|
||
new Esri::ArcGISRuntime::UniqueValueRenderer(QStringLiteral("UnknownParty"),
|
||
sls, // default
|
||
QStringList() << QStringLiteral("Extrusion_Color"), // fieldNames (was in former times: "PartyName")
|
||
uvList, parent);
|
||
static long s_counter = 0;
|
||
uniqueRenderer->setObjectName(QStringLiteral("UniqueValueRenderer_ForCubes_%1").arg(s_counter++));
|
||
connect(uniqueRenderer, &Esri::ArcGISRuntime::UniqueValueRenderer::errorOccurred, this, [this] (const Esri::ArcGISRuntime::Error &error)
|
||
{
|
||
FATAL_LOG(m_logger) << LOGFUNCTION << " ---EsriError--- assignUniqueValueRendererForCubes occured: ";
|
||
FATAL_LOG(m_logger) << LOGFUNCTION << " ---EsriError--- occured: " << error;
|
||
});
|
||
connect(uniqueRenderer, &Esri::ArcGISRuntime::UniqueValueRenderer::destroyed, this, [this, uniqueRenderer] () {
|
||
INFO_LOG(m_logger) << " UniqueValueRenderer is destroyed , objectName='" << uniqueRenderer->objectName() << "'";
|
||
});
|
||
|
||
|
||
// set sceneProperties:
|
||
Esri::ArcGISRuntime::RendererSceneProperties props = uniqueRenderer->sceneProperties();
|
||
props.setExtrusionMode(Esri::ArcGISRuntime::ExtrusionMode::AbsoluteHeight); // see BuildingOwnership::retrieveBuildingAbsHeight
|
||
props.setExtrusionExpression(QStringLiteral("[height]")); // <-- keyword
|
||
uniqueRenderer->setSceneProperties(props);
|
||
|
||
|
||
// take care that the old one is deleted:
|
||
Esri::ArcGISRuntime::Renderer *oldRenderer = graphicsOverlay->renderer();
|
||
delete oldRenderer; // delete nullptr is safe!
|
||
|
||
// assign new:
|
||
graphicsOverlay->setRenderer(uniqueRenderer);
|
||
|
||
return true;
|
||
}
|
||
|
||
bool LayerFactoryImpl::assignUniqueValueRenderer(const QString &layername,
|
||
const QString &fieldName,
|
||
const QVector<UniqueValueData> &uvDataCont)
|
||
{
|
||
TRACE_LOG(m_logger) << LOGFUNCTION << " START, layername='" << layername << "'"
|
||
<< ", fieldName='" << fieldName << "'"
|
||
<< ", uvDataCont.size()=" << uvDataCont.size();
|
||
|
||
// ensure existence:
|
||
getCreateLogicalLayer(layername);
|
||
|
||
Esri::ArcGISRuntime::GraphicsOverlay *graphicsOverlay = this->getGraphicsLayer(layername);
|
||
if (!graphicsOverlay)
|
||
{
|
||
ERROR_LOG(m_logger) << LOGFUNCTION << " graphicsOverlay not found, layername='" << layername << "'";
|
||
return false;
|
||
}
|
||
|
||
|
||
// prepare UniqueValues
|
||
Esri::ArcGISRuntime::PictureMarkerSymbol *pms;
|
||
QList<Esri::ArcGISRuntime::UniqueValue *> uvList;
|
||
QObject *parent = graphicsOverlay;
|
||
|
||
for (const UniqueValueData &uvData : qAsConst(uvDataCont))
|
||
{
|
||
INFO_LOG(m_logger) << LOGFUNCTION
|
||
<< " uvData.value=" << uvData.value << "'";
|
||
|
||
pms = new Esri::ArcGISRuntime::PictureMarkerSymbol(uvData.img, parent);
|
||
|
||
Esri::ArcGISRuntime::UniqueValue *uv =
|
||
new Esri::ArcGISRuntime::UniqueValue(uvData.value,
|
||
QStringLiteral("GenericUniqueValue '%1'").arg(uvData.value),
|
||
QVariantList() << uvData.value, pms, parent);
|
||
uvList.append(uv);
|
||
} // for
|
||
|
||
// setup default:
|
||
Esri::ArcGISRuntime::SimpleMarkerSymbol *sms;
|
||
sms = new Esri::ArcGISRuntime::SimpleMarkerSymbol(Esri::ArcGISRuntime::SimpleMarkerSymbolStyle::X, Qt::white, 5, parent);
|
||
|
||
// Finally, setup Renderer:
|
||
Esri::ArcGISRuntime::UniqueValueRenderer* uniqueRenderer =
|
||
new Esri::ArcGISRuntime::UniqueValueRenderer(QStringLiteral("GenericUniqueValueRenderer"),
|
||
sms, // default
|
||
QStringList() << fieldName,
|
||
uvList, parent);
|
||
static long s_counter = 0;
|
||
uniqueRenderer->setObjectName(QStringLiteral("UniqueValueRenderer_assignUniqueValueRenderer_%1").arg(s_counter++));
|
||
connect(uniqueRenderer, &Esri::ArcGISRuntime::UniqueValueRenderer::errorOccurred, this, [this] (const Esri::ArcGISRuntime::Error &error)
|
||
{
|
||
FATAL_LOG(m_logger) << LOGFUNCTION << " ---EsriError--- assignUniqueValueRenderer occured: ";
|
||
FATAL_LOG(m_logger) << LOGFUNCTION << " ---EsriError--- occured: " << error;
|
||
});
|
||
connect(uniqueRenderer, &Esri::ArcGISRuntime::UniqueValueRenderer::destroyed, this, [this, uniqueRenderer] () {
|
||
INFO_LOG(m_logger) << " UniqueValueRenderer is destroyed , objectName='" << uniqueRenderer->objectName() << "'";
|
||
});
|
||
|
||
// take care that the old one is deleted:
|
||
Esri::ArcGISRuntime::Renderer *oldRenderer = graphicsOverlay->renderer();
|
||
delete oldRenderer; // delete nullptr is safe!
|
||
|
||
// assign new:
|
||
graphicsOverlay->setRenderer(uniqueRenderer);
|
||
|
||
TRACE_LOG(m_logger) << LOGFUNCTION << " END, layername='" << layername << "'"
|
||
<< ", fieldName='" << fieldName << "'"
|
||
<< ", uvDataCont.size()=" << uvDataCont.size();
|
||
return true;
|
||
}
|
||
|
||
bool LayerFactoryImpl::assignUniqueValueRendererAesCentral(const QString &layername,
|
||
const QStringList &fieldNames,
|
||
const QVector<UniqueValueDataAesCentral> &uvDataCont)
|
||
{
|
||
TRACE_LOG(m_logger) << LOGFUNCTION << " START, layername='" << layername << "'"
|
||
<< ", fieldNames='" << fieldNames.join(QStringLiteral(";")) << "'"
|
||
<< ", uvDataCont.size()=" << uvDataCont.size();
|
||
|
||
// ensure existence:
|
||
getCreateLogicalLayer(layername);
|
||
|
||
Esri::ArcGISRuntime::GraphicsOverlay *graphicsOverlay = this->getGraphicsLayer(layername);
|
||
if (!graphicsOverlay)
|
||
{
|
||
ERROR_LOG(m_logger) << LOGFUNCTION << " graphicsOverlay not found, layername='" << layername << "'";
|
||
return false;
|
||
}
|
||
|
||
// prepare UniqueValues
|
||
QList<Esri::ArcGISRuntime::UniqueValue *> uvList;
|
||
QObject *parent = graphicsOverlay;
|
||
for (const UniqueValueDataAesCentral &uvData : qAsConst(uvDataCont))
|
||
{
|
||
INFO_LOG(m_logger) << LOGFUNCTION
|
||
// << " uvData.value=" << uvData.values << "'"
|
||
<< ", type " << toString(uvData.type)
|
||
<< ", col " << uvData.col
|
||
<< ", col.name " << uvData.col.name()
|
||
<< ", uvData.radius " << uvData.radius;
|
||
Esri::ArcGISRuntime::SimpleMarkerSceneSymbol *symbol = nullptr;
|
||
|
||
switch (uvData.type) {
|
||
case UniqueValueDataAesCentral::TYPE::CONE:
|
||
symbol = Esri::ArcGISRuntime::SimpleMarkerSceneSymbol::cone(uvData.col,
|
||
// extent should be similar to sphere
|
||
uvData.radius, // V100.8: cone: diameter is interpreted as radius
|
||
uvData.height,
|
||
parent);
|
||
symbol->setAnchorPosition(Esri::ArcGISRuntime::SceneSymbolAnchorPosition::Top);
|
||
break;
|
||
case UniqueValueDataAesCentral::TYPE::SPHERE:
|
||
symbol = Esri::ArcGISRuntime::SimpleMarkerSceneSymbol::sphere(uvData.col,
|
||
uvData.radius*2.0, // diameter
|
||
parent);
|
||
symbol->setAnchorPosition(Esri::ArcGISRuntime::SceneSymbolAnchorPosition::Center);
|
||
default:
|
||
break;
|
||
}
|
||
|
||
Esri::ArcGISRuntime::UniqueValue *uv =
|
||
new Esri::ArcGISRuntime::UniqueValue(QStringLiteral("uvData.value"),
|
||
QStringLiteral("AesCentralUniqueValue '%%%1'"),
|
||
uvData.values, symbol, parent);
|
||
uvList.append(uv);
|
||
} // for
|
||
|
||
// setup default:
|
||
Esri::ArcGISRuntime::SimpleMarkerSymbol *sms;
|
||
sms = new Esri::ArcGISRuntime::SimpleMarkerSymbol(Esri::ArcGISRuntime::SimpleMarkerSymbolStyle::X, Qt::white, 25, parent);
|
||
|
||
// Finally, setup Renderer:
|
||
Esri::ArcGISRuntime::UniqueValueRenderer* uniqueRenderer =
|
||
new Esri::ArcGISRuntime::UniqueValueRenderer(QStringLiteral("AesCentralUniqueValueRenderer"),
|
||
sms, // default
|
||
fieldNames,
|
||
uvList, parent);
|
||
static long s_counter = 0;
|
||
uniqueRenderer->setObjectName(QStringLiteral("UniqueValueRenderer_assignUniqueValueRendererAesCentral_%1").arg(s_counter++));
|
||
connect(uniqueRenderer, &Esri::ArcGISRuntime::UniqueValueRenderer::errorOccurred, this, [this] (const Esri::ArcGISRuntime::Error &error)
|
||
{
|
||
FATAL_LOG(m_logger) << LOGFUNCTION << " ---EsriError--- UniqueValueRendererAesCentral occured: ";
|
||
FATAL_LOG(m_logger) << LOGFUNCTION << " ---EsriError--- occured: " << error;
|
||
});
|
||
connect(uniqueRenderer, &Esri::ArcGISRuntime::UniqueValueRenderer::destroyed, this, [this, uniqueRenderer] () {
|
||
INFO_LOG(m_logger) << " UniqueValueRenderer is destroyed , objectName='" << uniqueRenderer->objectName() << "'";
|
||
});
|
||
|
||
// setup SceneProperties
|
||
Esri::ArcGISRuntime::RendererSceneProperties sceneProps;
|
||
sceneProps.setHeadingExpression(QStringLiteral("[HEADING]")); // Expression with "[]", later on without "[]"
|
||
sceneProps.setPitchExpression(QStringLiteral("[PITCH]")); // Expression with "[]", later on without "[]"
|
||
sceneProps.setRollExpression(QStringLiteral("[ROLL]")); // Expression with "[]", later on without "[]"
|
||
uniqueRenderer->setSceneProperties(sceneProps);
|
||
|
||
// take care that the old one is deleted:
|
||
Esri::ArcGISRuntime::Renderer *oldRenderer = graphicsOverlay->renderer();
|
||
delete oldRenderer; // delete nullptr is safe!
|
||
|
||
// assign new:
|
||
graphicsOverlay->setRenderer(uniqueRenderer);
|
||
|
||
TRACE_LOG(m_logger) << LOGFUNCTION << " END, layername='" << layername << "'"
|
||
<< ", fieldNames='" << fieldNames.join(QStringLiteral(";")) << "'"
|
||
<< ", uvDataCont.size()=" << uvDataCont.size();
|
||
return true;
|
||
}
|
||
|
||
bool LayerFactoryImpl::assignUniqueValueRendererAesCentral3DExtrusion(const QString &layername,
|
||
const QStringList &fieldNames,
|
||
const QVector<LayerFactory::UniqueValueDataAesCentral> &uvDataCont)
|
||
{
|
||
TRACE_LOG(m_logger) << LOGFUNCTION << " START, layername='" << layername << "'"
|
||
<< ", fieldNames='" << fieldNames.join(QStringLiteral(";")) << "'"
|
||
<< ", uvDataCont.size()=" << uvDataCont.size();
|
||
|
||
// ensure existence:
|
||
getCreateLogicalLayer(layername);
|
||
|
||
Esri::ArcGISRuntime::GraphicsOverlay *graphicsOverlay = this->getGraphicsLayer3DExtrusion(layername);
|
||
if (!graphicsOverlay)
|
||
{
|
||
ERROR_LOG(m_logger) << LOGFUNCTION << " graphicsOverlay not found, layername='" << layername << "'";
|
||
return false;
|
||
}
|
||
|
||
// prepare UniqueValues
|
||
QList<Esri::ArcGISRuntime::UniqueValue *> uvList;
|
||
QObject *parent = graphicsOverlay;
|
||
for (const UniqueValueDataAesCentral &uvData : qAsConst(uvDataCont))
|
||
{
|
||
INFO_LOG(m_logger) << LOGFUNCTION
|
||
// << " uvData.value=" << uvData.values << "'"
|
||
<< ", type " << toString(uvData.type)
|
||
<< ", col " << uvData.col
|
||
<< ", col.name " << uvData.col.name()
|
||
<< ", uvData.radius " << uvData.radius;
|
||
|
||
Esri::ArcGISRuntime::SimpleFillSymbol *symbol =
|
||
new Esri::ArcGISRuntime::SimpleFillSymbol(Esri::ArcGISRuntime::SimpleFillSymbolStyle::Solid, uvData.col, parent);
|
||
|
||
Esri::ArcGISRuntime::UniqueValue *uv =
|
||
new Esri::ArcGISRuntime::UniqueValue(uvData.label,
|
||
QString(QStringLiteral("Description '%1'")).arg(uvData.col.name()),
|
||
uvData.values, symbol, parent);
|
||
uvList.append(uv);
|
||
} // for
|
||
|
||
// setup default:
|
||
Esri::ArcGISRuntime::SimpleFillSymbol *defaultSymbol =
|
||
new Esri::ArcGISRuntime::SimpleFillSymbol(Esri::ArcGISRuntime::SimpleFillSymbolStyle::Solid, Qt::white, parent);
|
||
|
||
// Finally, setup Renderer:
|
||
Esri::ArcGISRuntime::UniqueValueRenderer* uniqueRenderer =
|
||
new Esri::ArcGISRuntime::UniqueValueRenderer(QStringLiteral("assignUniqueValueRendererAesCentral3DUNKNOWN"),
|
||
defaultSymbol, // default
|
||
fieldNames,
|
||
uvList, parent);
|
||
static long s_counter = 0;
|
||
uniqueRenderer->setObjectName(QStringLiteral("UniqueValueRenderer_assignUniqueValueRendererAesCentral3D_%1").arg(s_counter++));
|
||
connect(uniqueRenderer, &Esri::ArcGISRuntime::UniqueValueRenderer::errorOccurred, this, [this] (const Esri::ArcGISRuntime::Error &error)
|
||
{
|
||
FATAL_LOG(m_logger) << LOGFUNCTION << " ---EsriError--- UniqueValueRendererAesCentral3DExtrusion occured: ";
|
||
FATAL_LOG(m_logger) << LOGFUNCTION << " ---EsriError--- occured: " << error;
|
||
});
|
||
connect(uniqueRenderer, &Esri::ArcGISRuntime::UniqueValueRenderer::destroyed, this, [this, uniqueRenderer] () {
|
||
INFO_LOG(m_logger) << " UniqueValueRenderer is destroyed , objectName='" << uniqueRenderer->objectName() << "'";
|
||
});
|
||
|
||
Esri::ArcGISRuntime::RendererSceneProperties props = uniqueRenderer->sceneProperties();
|
||
props.setExtrusionMode(Esri::ArcGISRuntime::ExtrusionMode::BaseHeight);
|
||
props.setExtrusionExpression(QStringLiteral("[height]")); // <-- keyword
|
||
uniqueRenderer->setSceneProperties(props);
|
||
|
||
// take care that the old one is deleted:
|
||
Esri::ArcGISRuntime::Renderer *oldRenderer = graphicsOverlay->renderer();
|
||
delete oldRenderer; // delete nullptr is safe!
|
||
|
||
// assign new:
|
||
graphicsOverlay->setRenderer(uniqueRenderer);
|
||
|
||
TRACE_LOG(m_logger) << LOGFUNCTION << " END, layername='" << layername << "'"
|
||
<< ", fieldNames='" << fieldNames.join(QStringLiteral(";")) << "'"
|
||
<< ", uvDataCont.size()=" << uvDataCont.size();
|
||
return true;
|
||
}
|
||
|
||
bool LayerFactoryImpl::initializeUnitTestLayer()
|
||
{
|
||
TRACE_LOG(m_logger) << LOGFUNCTION << " START";
|
||
|
||
QUrl mapUrl(QLatin1String("http://DOES_NOT_EXISTS")); // wkid = 102100/3857
|
||
|
||
this->addBasemap(QLatin1String("DummyLayerName"), mapUrl, BasemapType::Aerial);
|
||
|
||
//-----------------------------------
|
||
// Layer:
|
||
//-----------------------------------
|
||
|
||
QStringList layerNames;
|
||
layerNames << QLatin1String("AES");
|
||
layerNames << QLatin1String("Participants");
|
||
bool success = true;
|
||
for (const QString &layername : qAsConst(layerNames))
|
||
if (!addOperationalLayer(layername, layername))
|
||
success = false;
|
||
|
||
if (!success)
|
||
ERROR_LOG(m_logger) << LOGFUNCTION << " initializeOperationalLayers failed";
|
||
|
||
// enableFunctionDialog();
|
||
|
||
TRACE_LOG(m_logger) << LOGFUNCTION << " END";
|
||
return success;
|
||
|
||
}
|
||
|
||
bool LayerFactoryImpl::addBasemap(const QString &layername,
|
||
const QUrl &mapServiceUrl,
|
||
const BasemapType basemapType,
|
||
const double minScale,
|
||
const double maxScale,
|
||
const QString &displayName,
|
||
const QString &description,
|
||
const QImage &previewImage)
|
||
{
|
||
TRACE_LOG(m_logger) << LOGFUNCTION << " START"
|
||
<< " layername='" << layername << "'"
|
||
<< " mapServiceUrl='" << mapServiceUrl.toString() << "'"
|
||
<< " basemapType='" << basemapType << "'"
|
||
<< " minScale='" << minScale << "'"
|
||
<< " maxScale='" << maxScale << "'"
|
||
<< " displayName='" << displayName << "'"
|
||
<< " description='" << description << "'"
|
||
<< " previewImage.isNull()=" << previewImage.isNull()
|
||
<< " wkid=" << d->m_mapImpl->getEsriSpatialReference().wkid();
|
||
|
||
bool success = addBasemapInternal(layername, mapServiceUrl, basemapType,
|
||
minScale, maxScale,
|
||
displayName, description);
|
||
|
||
// reOrder
|
||
success = success && reOrderLayer();
|
||
|
||
TRACE_LOG(m_logger) << LOGFUNCTION << " END"
|
||
<< " layername='" << layername << "'"
|
||
<< " mapServiceUrl='" << mapServiceUrl.toString() << "'"
|
||
<< " displayName='" << displayName << "'"
|
||
<< " success =" << success;
|
||
return success;
|
||
}
|
||
|
||
bool LayerFactoryImpl::removeBasemap(const QString &layername)
|
||
{
|
||
TRACE_LOG(m_logger) << LOGFUNCTION << " START"
|
||
<< " layername='" << layername << "'";
|
||
if (!d->m_orderedMapLayer.contains(layername, LayerType::Basemap))
|
||
{
|
||
ERROR_LOG(m_logger) << LOGFUNCTION << " layername='" << layername << "' not found";
|
||
return false;
|
||
}
|
||
|
||
bool success = false;
|
||
|
||
if (d->m_orderedMapLayer.removeLayer(layername) && d->m_basemap)
|
||
{
|
||
Esri::ArcGISRuntime::Layer *layer = this->getEsriBasemapLayer(layername);
|
||
if (layer && d->m_basemap->baseLayers())
|
||
{
|
||
d->m_basemap->baseLayers()->removeOne(layer);
|
||
success = true;
|
||
INFO_LOG(m_logger) << LOGFUNCTION << " layer"
|
||
<< " layername='" << layername << "' removed";
|
||
|
||
d->m_mapImpl->emitLayerOrderChanged();
|
||
}
|
||
else
|
||
ERROR_LOG(m_logger) << LOGFUNCTION << " layername='" << layername << "' can`t be found";
|
||
}
|
||
else
|
||
ERROR_LOG(m_logger) << LOGFUNCTION << " layername='" << layername << "' can`t be removed";
|
||
|
||
TRACE_LOG(m_logger) << LOGFUNCTION << " END"
|
||
<< " layername='" << layername << "'"
|
||
<< " success='" << success << "'";
|
||
return success;
|
||
}
|
||
|
||
Esri::ArcGISRuntime::Envelope LayerFactoryImpl::fullExtentOfBasemaps(double margin_zeroToOne) const
|
||
{
|
||
TRACE_LOG(m_logger) << LOGFUNCTION << " START";
|
||
|
||
Esri::ArcGISRuntime::LayerListModel *model = d->m_basemap->baseLayers();
|
||
if (!model || model->isEmpty())
|
||
return Esri::ArcGISRuntime::Envelope();
|
||
|
||
double xmin = std::numeric_limits<double>::max();
|
||
double ymin = std::numeric_limits<double>::max();
|
||
double xmax = std::numeric_limits<double>::lowest();
|
||
double ymax = std::numeric_limits<double>::lowest();
|
||
|
||
Esri::ArcGISRuntime::SpatialReference sr;
|
||
|
||
for (int idx = 0; idx < model->size(); ++idx)
|
||
{
|
||
Esri::ArcGISRuntime::Layer *layer = model->at(idx);
|
||
// 12.12.2018, N. Thoden, V100.4:
|
||
// Do not call fullExtent if layer is not loaded.
|
||
// Envelope contains nan and will not changed on further calls...
|
||
if (!layer || (layer->loadStatus() != Esri::ArcGISRuntime::LoadStatus::Loaded))
|
||
continue;
|
||
|
||
const Esri::ArcGISRuntime::Envelope singleEnv = layer->fullExtent();
|
||
|
||
DEBUG_LOG(m_logger) << LOGFUNCTION
|
||
<< " layer->loadStatus()" << layer->loadStatus()
|
||
<< ", singleEnv.toJson()" << singleEnv.toJson();
|
||
|
||
sr = singleEnv.spatialReference();
|
||
|
||
if (!std::isnan(singleEnv.xMin()))
|
||
xmin = std::min(singleEnv.xMin(), xmin);
|
||
if (!std::isnan(singleEnv.yMin()))
|
||
ymin = std::min(singleEnv.yMin(), ymin);
|
||
|
||
if (!std::isnan(singleEnv.xMax()))
|
||
xmax = std::max(singleEnv.xMax(), xmax);
|
||
if (!std::isnan(singleEnv.yMax()))
|
||
ymax = std::max(singleEnv.yMax(), ymax);
|
||
} // for
|
||
|
||
if (qFuzzyCompare(xmin, std::numeric_limits<double>::max()) || sr.isEmpty())
|
||
return Esri::ArcGISRuntime::Envelope();
|
||
|
||
if (margin_zeroToOne < 0.0)
|
||
margin_zeroToOne = 0.0;
|
||
|
||
if (margin_zeroToOne > 1.0)
|
||
margin_zeroToOne = 1.0;
|
||
|
||
if (margin_zeroToOne > 0)
|
||
{
|
||
double width = xmax - xmin;
|
||
double height = ymax - ymin;
|
||
|
||
xmin -= width * margin_zeroToOne;
|
||
xmax += width * margin_zeroToOne;
|
||
|
||
ymin -= height * margin_zeroToOne;
|
||
ymax += height * margin_zeroToOne;
|
||
}
|
||
|
||
DEBUG_LOG(m_logger) << LOGFUNCTION << " return.x " << xmin << " - " << xmax;
|
||
DEBUG_LOG(m_logger) << LOGFUNCTION << " return.y " << ymin << " - " << ymax;
|
||
|
||
TRACE_LOG(m_logger) << LOGFUNCTION << " END";
|
||
return Esri::ArcGISRuntime::Envelope(xmin, ymin, xmax, ymax, sr);
|
||
}
|
||
|
||
bool LayerFactoryImpl::addSceneObjectLayer(const QString &layername, const QUrl &sceneLayerServiceUrl, const double altitudeOffset, const QString &displayName, const QString &description, const QImage &previewImage)
|
||
{
|
||
TRACE_LOG(m_logger) << LOGFUNCTION << " START"
|
||
<< " layername='" << layername << "'"
|
||
<< " sceneLayerServiceUrl='" << sceneLayerServiceUrl.toString() << "'"
|
||
<< " altitudeOffset='" << altitudeOffset << "'"
|
||
<< " displayName='" << displayName << "'"
|
||
<< " description='" << description << "'"
|
||
<< " previewImage.isNull()=" << previewImage.isNull();
|
||
|
||
if (d->m_mapImpl->mode() != Mode::Mode_3D)
|
||
{
|
||
ERROR_LOG(m_logger) << LOGFUNCTION << " not allowd in Mode3D";
|
||
return false;
|
||
}
|
||
|
||
if (sceneLayerServiceUrl.isEmpty())
|
||
{
|
||
ERROR_LOG(m_logger) << LOGFUNCTION << " sceneLayerServiceUrl empty, can not add layer";
|
||
return false;
|
||
}
|
||
|
||
if (d->m_orderedMapLayer.contains(layername, LayerType::Undefined))
|
||
{
|
||
ERROR_LOG(m_logger) << LOGFUNCTION << " layername '" << layername << "' already in use";
|
||
return false;
|
||
}
|
||
|
||
//-----------------------------------
|
||
// ArcGIS ArcGISSceneLayer
|
||
//-----------------------------------
|
||
//-----------------------------------------------------------------
|
||
// Attention:
|
||
// local URLS -> do NOT specify any userCredentials (main)
|
||
// external URLS -> DO specify userCredentials (main)
|
||
//-----------------------------------------------------------------
|
||
|
||
QUrl finalUrl = this->completeUrl(QLatin1String("SCENE_OBJ"),
|
||
sceneLayerServiceUrl,
|
||
QLatin1String("slpk/"));
|
||
INFO_LOG(m_logger) << LOGFUNCTION << " SCENE_OBJ finalUrl '" << finalUrl.toString() << "'";
|
||
|
||
Esri::ArcGISRuntime::Scene *esriScene = d->m_mapImpl->getEsriScene();
|
||
|
||
#ifdef USE_ARCGIS_SCENE_LAYER_CACHE
|
||
ArcGISSceneLayerCache::Item& aslCacheItem = ArcGISSceneLayerCache::getInstance()->getFreeItemRef(sceneLayerServiceUrl.toString());
|
||
|
||
if (m_logger.isInfoEnabled())
|
||
ArcGISSceneLayerCache::getInstance()->dump();
|
||
|
||
|
||
// const bool reUse = aslCacheItem.m_hostingScene.isNull() && aslCacheItem.m_sceneLayer;
|
||
// aslCacheItem.m_hostingScene is always null. See getItemRef
|
||
const bool reUse = aslCacheItem.m_sceneLayer;
|
||
|
||
ERROR_LOG(m_logger) << LOGFUNCTION << " ArcGISSceneLayer -> reUse = "<< reUse
|
||
<< " itemName = '" << sceneLayerServiceUrl.toString() << "'"
|
||
<< " layername='" << layername << "'"
|
||
<< " aslCacheItem.m_hostingScene.data() = " << aslCacheItem.m_hostingScene.data()
|
||
<< " aslCacheItem.m_sceneLayer.data() = " << aslCacheItem.m_sceneLayer.data();
|
||
|
||
Esri::ArcGISRuntime::ArcGISSceneLayer *sceneLayer = nullptr;
|
||
|
||
if (!reUse)
|
||
{
|
||
INFO_LOG(m_logger) << LOGFUNCTION << " ArcGISSceneLayer -> CREATE"
|
||
<< " (itemName = '" << sceneLayerServiceUrl.toString() << "', layername='" << layername << "')";
|
||
|
||
sceneLayer = new Esri::ArcGISRuntime::ArcGISSceneLayer(finalUrl); // ArcGISSceneLayer should live longer than the scene: -> no parent here :-)
|
||
sceneLayer->setName(layername);
|
||
sceneLayer->setObjectName(sceneLayer->name());
|
||
|
||
connect(sceneLayer, &Esri::ArcGISRuntime::ArcGISSceneLayer::errorOccurred, this, [this](const Esri::ArcGISRuntime::Error &error)
|
||
{
|
||
ERROR_LOG(m_logger) << LOGFUNCTION << " ArcGISSceneLayer -> EsriError occured: " << error;
|
||
});
|
||
connect(sceneLayer, &Esri::ArcGISRuntime::ArcGISSceneLayer::doneLoading, this, [this]()
|
||
{
|
||
Esri::ArcGISRuntime::ArcGISSceneLayer *sceneLayer = qobject_cast<Esri::ArcGISRuntime::ArcGISSceneLayer *>(sender());
|
||
if (!sceneLayer)
|
||
{
|
||
ERROR_LOG(m_logger) << LOGFUNCTION << " qobject_cast failed to get sender!?";
|
||
return;
|
||
}
|
||
|
||
QString senderName = sceneLayer->objectName();
|
||
INFO_LOG(m_logger) << LOGFUNCTION << " ArcGISSceneLayer -> doneLoading"
|
||
<< " ,sendername= '" << senderName << "'"
|
||
<< " ,URL= '" << sceneLayer->url().toString() << "'";
|
||
});
|
||
|
||
connect(sceneLayer, &Esri::ArcGISRuntime::ArcGISSceneLayer::destroyed, this, [this]()
|
||
{
|
||
ERROR_LOG(m_logger) << LOGFUNCTION << " ArcGISSceneLayer -> destroyed";
|
||
});
|
||
|
||
aslCacheItem.m_hostingScene = esriScene; // update cache
|
||
aslCacheItem.m_sceneLayer = sceneLayer; // update cache
|
||
|
||
} else {
|
||
INFO_LOG(m_logger) << LOGFUNCTION << " ArcGISSceneLayer -> TAKE FROM STATIC"
|
||
<< " (itemName = '" << sceneLayerServiceUrl.toString() << "', layername='" << layername << "')";
|
||
|
||
aslCacheItem.m_hostingScene = esriScene; // update cache
|
||
sceneLayer = aslCacheItem.m_sceneLayer;
|
||
}
|
||
#else
|
||
Esri::ArcGISRuntime::ArcGISSceneLayer *sceneLayer = new Esri::ArcGISRuntime::ArcGISSceneLayer(finalUrl, d->m_mapImpl);
|
||
sceneLayer->setName(layername);
|
||
sceneLayer->setObjectName(sceneLayer->name());
|
||
sceneLayer->setAltitudeOffset(altitudeOffset);
|
||
|
||
connect(sceneLayer, &Esri::ArcGISRuntime::ArcGISSceneLayer::errorOccurred, this, [this](const Esri::ArcGISRuntime::Error &error)
|
||
{
|
||
ERROR_LOG(m_logger) << LOGFUNCTION << " ArcGISSceneLayer -> EsriError occured: " << error;
|
||
});
|
||
connect(sceneLayer, &Esri::ArcGISRuntime::ArcGISSceneLayer::doneLoading, this, [this]()
|
||
{
|
||
Esri::ArcGISRuntime::ArcGISSceneLayer *sceneLayer = qobject_cast<Esri::ArcGISRuntime::ArcGISSceneLayer *>(sender());
|
||
if (!sceneLayer)
|
||
{
|
||
ERROR_LOG(m_logger) << LOGFUNCTION << " qobject_cast failed to get sender!?";
|
||
return;
|
||
}
|
||
|
||
QString senderName = sceneLayer->objectName();
|
||
DEBUG_LOG(m_logger) << LOGFUNCTION << " ArcGISSceneLayer -> doneLoading"
|
||
<< " ,sendername= '" << senderName << "'"
|
||
<< " ,URL= '" << sceneLayer->url().toString() << "'";
|
||
});
|
||
#endif // USE_ARCGIS_SCENE_LAYER_CACHE
|
||
|
||
|
||
if (esriScene)
|
||
{
|
||
esriScene->operationalLayers()->append(sceneLayer);
|
||
}
|
||
else
|
||
{
|
||
ERROR_LOG(m_logger) << LOGFUNCTION << " no scene";
|
||
return false;
|
||
}
|
||
|
||
#ifdef USE_ARCGIS_SCENE_LAYER_CACHE
|
||
if (m_logger.isInfoEnabled())
|
||
ArcGISSceneLayerCache::getInstance()->dump();
|
||
#endif // USE_ARCGIS_SCENE_LAYER_CACHE
|
||
|
||
d->m_sceneObjectUrlCont += sceneLayerServiceUrl;
|
||
|
||
TRACE_LOG(m_logger) << LOGFUNCTION << " END"
|
||
<< " sceneLayerServiceUrl='" << sceneLayerServiceUrl.toString() << "'";
|
||
return true;
|
||
}
|
||
|
||
bool LayerFactoryImpl::isSceneObjectLayerVisible() const
|
||
{
|
||
return d->m_isSceneObjectLayerVisible;
|
||
}
|
||
|
||
void LayerFactoryImpl::setSceneObjectLayerVisible(bool visible)
|
||
{
|
||
d->m_isSceneObjectLayerVisible = visible;
|
||
|
||
if ( (!d->m_mapImpl) || d->m_mapImpl->mode() != Mode::Mode_3D)
|
||
return;
|
||
|
||
Esri::ArcGISRuntime::Scene *esriScene = d->m_mapImpl->getEsriScene();
|
||
if (!esriScene)
|
||
{
|
||
ERROR_LOG(m_logger) << LOGFUNCTION << " no scene";
|
||
return;
|
||
}
|
||
|
||
Esri::ArcGISRuntime::LayerListModel *layerListModel = esriScene->operationalLayers();
|
||
if (!layerListModel)
|
||
return;
|
||
|
||
const int size = layerListModel->size();
|
||
for (int idx=0; idx<size; ++idx)
|
||
{
|
||
Esri::ArcGISRuntime::Layer *objLayer = layerListModel->at(idx);
|
||
if (!objLayer)
|
||
continue;
|
||
objLayer->setVisible(d->m_isSceneObjectLayerVisible);
|
||
} // for
|
||
|
||
|
||
|
||
}
|
||
|
||
bool LayerFactoryImpl::initializeElevationSources(const QStringList &sceneElevationServiceUrls)
|
||
{
|
||
TRACE_LOG(m_logger) << LOGFUNCTION << " START"
|
||
<< " sceneElevationServiceUrls='" << sceneElevationServiceUrls.join(QLatin1String(";")) << "'";
|
||
|
||
const Mode mode = d->m_mapImpl->mode();
|
||
|
||
switch (mode)
|
||
{
|
||
case Mode::Mode_2D:
|
||
this->initializeElevationSources2D(sceneElevationServiceUrls);
|
||
break;
|
||
case Mode::Mode_3D:
|
||
this->initializeElevationSources3D(sceneElevationServiceUrls);
|
||
break;
|
||
default:
|
||
ERROR_LOG(m_logger) << LOGFUNCTION << " unknown mode";
|
||
return false;
|
||
} // switch
|
||
|
||
TRACE_LOG(m_logger) << LOGFUNCTION << " END";
|
||
return true;
|
||
}
|
||
|
||
bool LayerFactoryImpl::initializeElevationSources2D(const QStringList &sceneElevationServiceUrls)
|
||
{
|
||
if (sceneElevationServiceUrls.isEmpty())
|
||
{
|
||
ERROR_LOG(m_logger) << LOGFUNCTION << " sceneObjectServiceUrls is Empty";
|
||
return false;
|
||
}
|
||
|
||
if (d->m_mapImpl->mode() != Mode::Mode_2D)
|
||
{
|
||
ERROR_LOG(m_logger) << LOGFUNCTION << " wrong mode";
|
||
return false;
|
||
}
|
||
|
||
//
|
||
// append to 'own' esri (base) surface:
|
||
//
|
||
delete d->m_baseSurface;
|
||
d->m_baseSurface = new Esri::ArcGISRuntime::Surface(this);
|
||
d->m_baseSurface->setName(QLatin1String("BaseSurface2D"));
|
||
d->m_baseSurface->setObjectName(d->m_baseSurface->name());
|
||
|
||
connect(d->m_baseSurface, &Esri::ArcGISRuntime::Surface::errorOccurred, this, &LayerFactoryImpl::onSurfaceErrorOccured2D, Qt::UniqueConnection);
|
||
connect(d->m_baseSurface, &Esri::ArcGISRuntime::Surface::doneLoading, this, &LayerFactoryImpl::onSurfaceDoneLoading2D, Qt::UniqueConnection);
|
||
|
||
const QList<Esri::ArcGISRuntime::ElevationSource*> &elevationSources =
|
||
initializeElevationSourcesInternal(sceneElevationServiceUrls);
|
||
|
||
for (auto elevationSource : qAsConst(elevationSources))
|
||
d->m_baseSurface->elevationSources()->append(elevationSource);
|
||
|
||
|
||
// trigger loading:
|
||
// As Luke suggested: load surface if first elevation entry is loaded:
|
||
// https://community.esri.com/thread/206757-elevation-in-2d
|
||
if (!elevationSources.isEmpty())
|
||
{
|
||
Esri::ArcGISRuntime::ElevationSource* elevationSourcesFirst = elevationSources.first();
|
||
if (elevationSourcesFirst)
|
||
{
|
||
connect(elevationSourcesFirst, &Esri::ArcGISRuntime::ElevationSource::doneLoading, this, [this](const Esri::ArcGISRuntime::Error&)
|
||
{
|
||
d->m_baseSurface->load();
|
||
});
|
||
elevationSourcesFirst->load();
|
||
}
|
||
}
|
||
|
||
return true;
|
||
}
|
||
|
||
bool LayerFactoryImpl::initializeElevationSources3D(const QStringList &sceneElevationServiceUrls)
|
||
{
|
||
if (sceneElevationServiceUrls.isEmpty())
|
||
{
|
||
ERROR_LOG(m_logger) << LOGFUNCTION << " sceneObjectServiceUrls is Empty";
|
||
return false;
|
||
}
|
||
|
||
if (d->m_mapImpl->mode() != Mode::Mode_3D)
|
||
{
|
||
ERROR_LOG(m_logger) << LOGFUNCTION << " wrong mode";
|
||
return false;
|
||
}
|
||
|
||
Esri::ArcGISRuntime::Scene *esriScene = d->m_mapImpl->getEsriScene();
|
||
if (!esriScene)
|
||
{
|
||
ERROR_LOG(m_logger) << LOGFUNCTION << " no scene";
|
||
return false;
|
||
}
|
||
|
||
if (!esriScene->baseSurface() || !esriScene->baseSurface()->elevationSources())
|
||
{
|
||
ERROR_LOG(m_logger) << LOGFUNCTION << " no ElevationSourceListModel";
|
||
return false;
|
||
}
|
||
|
||
//
|
||
// append to esri scene:
|
||
//
|
||
const QList<Esri::ArcGISRuntime::ElevationSource*> elevationSources =
|
||
initializeElevationSourcesInternal(sceneElevationServiceUrls);
|
||
|
||
for (auto item : elevationSources)
|
||
esriScene->baseSurface()->elevationSources()->append(item);
|
||
|
||
return true;
|
||
}
|
||
|
||
QList<Esri::ArcGISRuntime::ElevationSource*> LayerFactoryImpl::initializeElevationSourcesInternal(const QStringList &sceneElevationServiceUrls)
|
||
{
|
||
if (sceneElevationServiceUrls.isEmpty())
|
||
return {};
|
||
|
||
Esri::ArcGISRuntime::RasterElevationSource* rasterElevationSource =
|
||
initializeRasterElevationSourceInternal(sceneElevationServiceUrls);
|
||
|
||
QList<Esri::ArcGISRuntime::ElevationSource*> elevationSources;
|
||
elevationSources.append(rasterElevationSource);
|
||
|
||
return elevationSources;
|
||
}
|
||
|
||
Esri::ArcGISRuntime::RasterElevationSource *LayerFactoryImpl::initializeRasterElevationSourceInternal(const QStringList &filePaths)
|
||
{
|
||
DEBUG_LOG(m_logger) << LOGFUNCTION << " filePaths = " << filePaths.join(QStringLiteral(";")) << "'";
|
||
|
||
QStringList absFilePaths_rough_to_fine;
|
||
absFilePaths_rough_to_fine.reserve(filePaths.size());
|
||
|
||
for (const QString &filePath : filePaths)
|
||
{
|
||
QUrl finalUrl = this->completeUrl(QLatin1String("ELEVATION"),
|
||
QUrl(filePath),
|
||
QLatin1String("elevation/"));
|
||
|
||
INFO_LOG(m_logger) << LOGFUNCTION << " ELEVATION finalUrl '" << finalUrl.toString() << "'";
|
||
absFilePaths_rough_to_fine.append(finalUrl.toLocalFile());
|
||
} // for
|
||
|
||
if (absFilePaths_rough_to_fine.isEmpty())
|
||
{
|
||
WARNING_LOG(m_logger) << LOGFUNCTION << " filePaths are empty!!!";
|
||
return nullptr;
|
||
}
|
||
DEBUG_LOG(m_logger) << LOGFUNCTION << " absFilePaths_rough_to_fine = " << absFilePaths_rough_to_fine.join(QStringLiteral(";")) << "'";
|
||
|
||
//
|
||
// init ElevationMapManager
|
||
//
|
||
if (!d->m_mapImpl->getElevationMapManager())
|
||
{
|
||
if (!d->m_mapImpl->initElevationMapManager(absFilePaths_rough_to_fine))
|
||
ERROR_LOG(m_logger) << LOGFUNCTION << " initElevationMapManager failed";
|
||
}
|
||
|
||
//
|
||
// Esri::ArcGISRuntime::RasterElevationSource with several files
|
||
//
|
||
Esri::ArcGISRuntime::RasterElevationSource *rasterElevationSource =
|
||
new Esri::ArcGISRuntime::RasterElevationSource(absFilePaths_rough_to_fine, this);
|
||
|
||
const QString &elevationSourceName = QStringLiteral("RasterElevationSources_((%1))").arg(absFilePaths_rough_to_fine.size());
|
||
rasterElevationSource->setName(elevationSourceName);
|
||
rasterElevationSource->setObjectName(rasterElevationSource->name());
|
||
|
||
// 2017-09-18; N.Thoden, V100.1:
|
||
// Following message occures very often. Therefore don`t connect to errorOccurred
|
||
// 'code=404 domain=0 extendedErrorType=0, message='Error transferring http://excgeo21.sl .. - server replied: Not Found'
|
||
connect(rasterElevationSource, &Esri::ArcGISRuntime::ElevationSource::errorOccurred, this, &LayerFactoryImpl::onElevationSourceErrorOccured);
|
||
connect(rasterElevationSource, &Esri::ArcGISRuntime::ElevationSource::doneLoading,
|
||
this, &LayerFactoryImpl::onElevationSourceDoneLoading);
|
||
return rasterElevationSource;
|
||
}
|
||
|
||
|
||
void LayerFactoryImpl::setForceCreationOfGraphicsOverlay(bool onOff)
|
||
{
|
||
s_forceCreationOfGraphicsOverlay = onOff;
|
||
}
|
||
|
||
|
||
QString LayerFactoryImpl::basemapLayernamePrefix() const
|
||
{
|
||
return d->m_basemapLayernamePrefix;
|
||
}
|
||
void LayerFactoryImpl::setBasemapLayernamePrefix(const QString &basemapLayernamePrefix)
|
||
{
|
||
d->m_basemapLayernamePrefix = basemapLayernamePrefix;
|
||
}
|
||
|
||
QString LayerFactoryImpl::participantLayername() const
|
||
{
|
||
return d->m_participantLayername;
|
||
}
|
||
RenderingMode LayerFactoryImpl::participantLayerRenderingMode() const
|
||
{
|
||
return d->m_participantLayerRenderingMode;
|
||
}
|
||
SurfacePlacement LayerFactoryImpl::participantLayerSurfacePlacement() const
|
||
{
|
||
return d->m_participantLayerSurfacePlacement;
|
||
}
|
||
|
||
void LayerFactoryImpl::setParticipantLayer(const QString &participantLayername,
|
||
RenderingMode renderingMode,
|
||
SurfacePlacement surfacePlacement)
|
||
{
|
||
d->m_participantLayername = participantLayername;
|
||
d->m_participantLayerRenderingMode = renderingMode;
|
||
d->m_participantLayerSurfacePlacement = surfacePlacement;
|
||
}
|
||
|
||
QString LayerFactoryImpl::jumpPointLayer()
|
||
{
|
||
TRACE_LOG(m_logger) << LOGFUNCTION << " START";
|
||
|
||
const QString &logicalLayerName = LayerNameJumpPoints;
|
||
const LayerType layerType = LayerType::JumpPoint;
|
||
|
||
if (! layerExistsInMngt(logicalLayerName, layerType))
|
||
{
|
||
QSharedPointer<LogicalLayer> logicalLayer = addLayerToMgnt(logicalLayerName, layerType);
|
||
if (logicalLayer.isNull())
|
||
{
|
||
ERROR_LOG(m_logger) << LOGFUNCTION << " addLayer failed: '"
|
||
<< logicalLayerName << "'";
|
||
return QString();
|
||
}
|
||
LayerParameter lp = logicalLayer->layerParameter();
|
||
lp.displayName = tr("JumpPoints"); // dt. Sprungmarken
|
||
logicalLayer->setLayerParameter(lp);
|
||
}
|
||
|
||
|
||
//
|
||
// the real Esri-Layers will be create later on demand :-)
|
||
//
|
||
|
||
TRACE_LOG(m_logger) << LOGFUNCTION << " END";
|
||
return logicalLayerName; // == LayerNameJumpPoints;
|
||
}
|
||
|
||
|
||
bool LayerFactoryImpl::jumpPointLayerExists() const
|
||
{
|
||
const QString &logicalLayerName = LayerNameJumpPoints;
|
||
return (d->m_orderedMapLayer.contains(logicalLayerName, SituationMap::LayerType::JumpPoint));
|
||
}
|
||
|
||
|
||
|
||
QString LayerFactoryImpl::toolLayer()
|
||
{
|
||
TRACE_LOG(m_logger) << LOGFUNCTION << " START";
|
||
|
||
const QString &logicalLayerName = LayerNameTools;
|
||
const LayerType layerType = LayerType::Tools;
|
||
|
||
if (! layerExistsInMngt(logicalLayerName, layerType))
|
||
{
|
||
QSharedPointer<LogicalLayer> logicalLayer = addLayerToMgnt(logicalLayerName, layerType);
|
||
if (logicalLayer.isNull())
|
||
{
|
||
ERROR_LOG(m_logger) << LOGFUNCTION << " addLayer failed: '"
|
||
<< logicalLayerName << "'";
|
||
return QString();
|
||
}
|
||
LayerParameter lp = logicalLayer->layerParameter();
|
||
lp.displayName = tr("Tools"); // dt. Werkzeuge (?)
|
||
logicalLayer->setLayerParameter(lp);
|
||
}
|
||
|
||
TRACE_LOG(m_logger) << LOGFUNCTION << " END";
|
||
|
||
//
|
||
// the real Esri-Layers will be create later on demand :-)
|
||
//
|
||
|
||
TRACE_LOG(m_logger) << LOGFUNCTION << " END";
|
||
return logicalLayerName; // == LayerNameTools;
|
||
}
|
||
|
||
bool LayerFactoryImpl::toolLayerExists() const
|
||
{
|
||
const QString &logicalLayerName = LayerNameTools;
|
||
return (d->m_orderedMapLayer.contains(logicalLayerName, SituationMap::LayerType::Tools));
|
||
}
|
||
|
||
|
||
QString LayerFactoryImpl::rubberbandLayer() const
|
||
{
|
||
TRACE_LOG(m_logger) << LOGFUNCTION << " START";
|
||
|
||
const QString &logicalLayerName = LayerNameRubberband;
|
||
const LayerType layerType = LayerType::Rubberband;
|
||
|
||
if (! layerExistsInMngt(logicalLayerName, layerType))
|
||
{
|
||
LayerFactoryImpl *THIS = const_cast<LayerFactoryImpl *>(this);
|
||
QSharedPointer<LogicalLayer> logicalLayer = THIS->addLayerToMgnt(logicalLayerName, layerType);
|
||
if (logicalLayer.isNull())
|
||
{
|
||
ERROR_LOG(m_logger) << LOGFUNCTION << " addLayer failed: '"
|
||
<< logicalLayerName << "'";
|
||
return QString();
|
||
}
|
||
}
|
||
|
||
//
|
||
// the real Esri-Layers will be create later on demand :-)
|
||
//
|
||
|
||
TRACE_LOG(m_logger) << LOGFUNCTION << " END";
|
||
return logicalLayerName; // == LayerNameRubberband;
|
||
}
|
||
bool LayerFactoryImpl::rubberbandLayerExists() const
|
||
{
|
||
const QString &logicalLayerName = LayerNameRubberband;
|
||
return (d->m_orderedMapLayer.contains(logicalLayerName, SituationMap::LayerType::Rubberband));
|
||
}
|
||
|
||
QString LayerFactoryImpl::emergencyCallLayer(bool getJustTheName)
|
||
{
|
||
TRACE_LOG(m_logger) << LOGFUNCTION << " START";
|
||
const QString &logicalLayerName = LayerNameEmergencyCall;
|
||
|
||
if (getJustTheName)
|
||
{
|
||
TRACE_LOG(m_logger) << LOGFUNCTION << " END";
|
||
return logicalLayerName;
|
||
}
|
||
|
||
const LayerType layerType = LayerType::EmergencyCall;
|
||
|
||
if (! layerExistsInMngt(logicalLayerName, layerType))
|
||
{
|
||
QSharedPointer<LogicalLayer> logicalLayer = addLayerToMgnt(logicalLayerName, layerType);
|
||
if (logicalLayer.isNull())
|
||
{
|
||
ERROR_LOG(m_logger) << LOGFUNCTION << " addLayer failed: '"
|
||
<< logicalLayerName << "'";
|
||
return QString();
|
||
}
|
||
LayerParameter lp = logicalLayer->layerParameter();
|
||
lp.displayName = tr("EmergencyCalls"); // dt. Notrufe/SOS (?)
|
||
logicalLayer->setLayerParameter(lp);
|
||
}
|
||
|
||
{
|
||
Esri::ArcGISRuntime::GraphicsOverlay *graphicsOverlay = this->getGraphicsLayer(logicalLayerName);
|
||
if (!graphicsOverlay)
|
||
{
|
||
FATAL_LOG(m_logger) << LOGFUNCTION << " graphicsOverlay not found, logicalLayerName'" << logicalLayerName<< "'";
|
||
return QString();
|
||
}
|
||
// set SurfacePlacement // EmergencyCalls have a pin/needle
|
||
Esri::ArcGISRuntime::LayerSceneProperties lsp = graphicsOverlay->sceneProperties();
|
||
lsp.setSurfacePlacement(static_cast<Esri::ArcGISRuntime::SurfacePlacement>(Esri::ArcGISRuntime::SurfacePlacement::Relative));
|
||
graphicsOverlay->setSceneProperties(lsp);
|
||
}
|
||
|
||
TRACE_LOG(m_logger) << LOGFUNCTION << " END";
|
||
return logicalLayerName; // == LayerNameEmergencyCall;
|
||
}
|
||
|
||
bool LayerFactoryImpl::emergencyCallLayerExists() const
|
||
{
|
||
const QString &emergencyCallLayername = LayerNameEmergencyCall;
|
||
return (d->m_orderedMapLayer.contains(emergencyCallLayername, SituationMap::LayerType::EmergencyCall));
|
||
}
|
||
|
||
bool LayerFactoryImpl::switchEmergencyCallLayerOn()
|
||
{
|
||
TRACE_LOG(m_logger) << LOGFUNCTION << " START";
|
||
const QString &emergencyCallLayername = LayerNameEmergencyCall;
|
||
|
||
if (!(d->m_orderedMapLayer.contains(emergencyCallLayername, SituationMap::LayerType::EmergencyCall)))
|
||
{
|
||
ERROR_LOG(m_logger) << LOGFUNCTION << " EmergencyCallLayer does not exists, can´t be switched on.";
|
||
TRACE_LOG(m_logger) << LOGFUNCTION << " END";
|
||
return false;
|
||
}
|
||
|
||
LayerParameter lp = this->layerParameter(emergencyCallLayername);
|
||
lp.visible = true;
|
||
lp.opacity = 100;
|
||
lp.minScale = -1;
|
||
lp.maxScale = -1;
|
||
|
||
const bool success = this->setLayerParameter(emergencyCallLayername, lp);
|
||
if (!success) {
|
||
ERROR_LOG(m_logger) << LOGFUNCTION << " setLayerParameter failed for '" << emergencyCallLayername << "'";
|
||
TRACE_LOG(m_logger) << LOGFUNCTION << " END";
|
||
return false;
|
||
}
|
||
|
||
TRACE_LOG(m_logger) << LOGFUNCTION << " END";
|
||
return true;
|
||
}
|
||
|
||
bool LayerFactoryImpl::switchEmergencyCallLayerOff()
|
||
{
|
||
TRACE_LOG(m_logger) << LOGFUNCTION << " START";
|
||
const QString &emergencyCallLayername = LayerNameEmergencyCall;
|
||
|
||
if (!(d->m_orderedMapLayer.contains(emergencyCallLayername, SituationMap::LayerType::EmergencyCall)))
|
||
{
|
||
ERROR_LOG(m_logger) << LOGFUNCTION << " EmergencyCallLayer does not exists, can´t be switched off.";
|
||
TRACE_LOG(m_logger) << LOGFUNCTION << " END";
|
||
return false;
|
||
}
|
||
|
||
LayerParameter lp = this->layerParameter(emergencyCallLayername);
|
||
lp.visible = false;
|
||
lp.opacity = 100;
|
||
lp.minScale = -1;
|
||
lp.maxScale = -1;
|
||
|
||
const bool success = this->setLayerParameter(emergencyCallLayername, lp);
|
||
if (!success) {
|
||
ERROR_LOG(m_logger) << LOGFUNCTION << " setLayerParameter failed for '" << emergencyCallLayername << "'";
|
||
TRACE_LOG(m_logger) << LOGFUNCTION << " END";
|
||
return false;
|
||
}
|
||
|
||
TRACE_LOG(m_logger) << LOGFUNCTION << " END";
|
||
return true;
|
||
|
||
}
|
||
|
||
void LayerFactoryImpl::handleEmergencyCallSpecials()
|
||
{
|
||
const QString &emergencyCallLayername = LayerNameEmergencyCall;
|
||
const bool bEmergencyCallLayerExists = emergencyCallLayerExists();
|
||
TRACE_LOG(m_logger) << LOGFUNCTION << " START, emergencyCallLayerExists() = " << bEmergencyCallLayerExists;
|
||
|
||
if (!bEmergencyCallLayerExists)
|
||
return;
|
||
|
||
// ensure to be on top:
|
||
QStringList slLayerNamesOrdered = d->m_orderedMapLayer.layerNamesOrdered();
|
||
if (slLayerNamesOrdered.isEmpty())
|
||
return;
|
||
|
||
const QString &lastNameTOP = slLayerNamesOrdered.last();
|
||
|
||
if (lastNameTOP == emergencyCallLayer())
|
||
{
|
||
DEBUG_LOG(m_logger) << LOGFUNCTION << " emergencyCallLayer already on top";
|
||
return;
|
||
}
|
||
|
||
slLayerNamesOrdered.removeAll(emergencyCallLayername);
|
||
slLayerNamesOrdered.push_back(emergencyCallLayername);
|
||
orderLayerTo(slLayerNamesOrdered);
|
||
|
||
{
|
||
QStringList slLayerNamesOrderedLocal = d->m_orderedMapLayer.layerNamesOrdered();
|
||
if (slLayerNamesOrderedLocal.isEmpty())
|
||
return;
|
||
|
||
const QString &lastNameTOPLocal = slLayerNamesOrderedLocal.last();
|
||
if (lastNameTOPLocal == emergencyCallLayer())
|
||
DEBUG_LOG(m_logger) << LOGFUNCTION << " emergencyCallLayer is now on top";
|
||
}
|
||
TRACE_LOG(m_logger) << LOGFUNCTION << " END";
|
||
}
|
||
|
||
Map *LayerFactoryImpl::map() const
|
||
{
|
||
return d->m_mapImpl;
|
||
}
|
||
|
||
int LayerFactoryImpl::count() const
|
||
{
|
||
return d->m_orderedMapLayer.count();
|
||
}
|
||
|
||
QStringList LayerFactoryImpl::layernames() const
|
||
{
|
||
return d->m_orderedMapLayer.layerNamesOrdered();
|
||
}
|
||
|
||
QStringList LayerFactoryImpl::layernames(const LayerType &layerType) const
|
||
{
|
||
return d->m_orderedMapLayer.layerNamesOrdered(layerType);
|
||
}
|
||
|
||
bool SituationMap::LayerFactoryImpl::checkLayerOrder(const QStringList &orderedLayernames)
|
||
{
|
||
bool requestedOrderIsValid = false;
|
||
bool success = d->m_orderedMapLayer.orderLayerTo(orderedLayernames, &requestedOrderIsValid);
|
||
|
||
if (success)
|
||
return requestedOrderIsValid;
|
||
else
|
||
return false;
|
||
}
|
||
|
||
bool LayerFactoryImpl::orderLayerTo(const QStringList &orderedLayernames)
|
||
{
|
||
DEBUG_LOG(m_logger) << LOGFUNCTION << " START"
|
||
<< ", orderedLayername= " << orderedLayernames.join(QLatin1String(";"));
|
||
|
||
if (orderedLayernames.isEmpty())
|
||
{
|
||
ERROR_LOG(m_logger) << LOGFUNCTION << " orderedLayername is empty";
|
||
return false;
|
||
}
|
||
|
||
bool success = true;
|
||
|
||
const QStringList &orderedLayernamesCurrent = d->m_orderedMapLayer.layerNamesOrdered();
|
||
DEBUG_LOG(m_logger) << LOGFUNCTION << " START"
|
||
<< ", orderedLayernamesCurrent=" << orderedLayernamesCurrent.join(QLatin1String(";"));
|
||
|
||
if (orderedLayernamesCurrent != orderedLayernames)
|
||
{
|
||
if ((success = d->m_orderedMapLayer.orderLayerTo(orderedLayernames)))
|
||
reOrderLayer();
|
||
else
|
||
{
|
||
ERROR_LOG(m_logger) << LOGFUNCTION << " orderLayerTo failed";
|
||
ERROR_LOG(m_logger) << LOGFUNCTION << " orderLayerTo failed, cur =" << d->m_orderedMapLayer.layerNamesOrdered().join(QLatin1String(";"));
|
||
ERROR_LOG(m_logger) << LOGFUNCTION << " orderLayerTo failed, should=" << orderedLayernames.join(QLatin1String(";"));
|
||
}
|
||
d->m_mapImpl->emitLayerOrderChanged();
|
||
}
|
||
|
||
DEBUG_LOG(m_logger) << LOGFUNCTION << " END, success=" << success
|
||
<< ", orderedLayernamesCurrent=" << orderedLayernamesCurrent.join(QLatin1String(";"));
|
||
return success;
|
||
}
|
||
|
||
LayerType LayerFactoryImpl::layerType(const QString &layername) const
|
||
{
|
||
LayerType layerType = LayerType::Undefined;
|
||
|
||
MapLayer mapLayer = d->m_orderedMapLayer.getLayer(layername);
|
||
if (mapLayer.isValid())
|
||
layerType = mapLayer.type();
|
||
else
|
||
{
|
||
ERROR_LOG(m_logger) << LOGFUNCTION << " layer not found"
|
||
<< " layername='" << layername << "'";
|
||
}
|
||
|
||
return layerType;
|
||
}
|
||
|
||
LayerParameter LayerFactoryImpl::layerParameter(const QString &layername) const
|
||
{
|
||
LayerParameter lp;
|
||
|
||
QSharedPointer<LogicalLayer> logicalLayer = this->getLogicalLayer(layername);
|
||
if (logicalLayer)
|
||
lp = logicalLayer->layerParameter();
|
||
else
|
||
{
|
||
ERROR_LOG(m_logger) << LOGFUNCTION << " not found"
|
||
<< " layername=" << layername;
|
||
}
|
||
|
||
return lp;
|
||
}
|
||
|
||
bool LayerFactoryImpl::setLayerParameter(const QString &layername, const LayerParameter &layerParameter)
|
||
{
|
||
TRACE_LOG(m_logger) << LOGFUNCTION << " START"
|
||
<< " layername=" << layername;
|
||
|
||
bool success = false;
|
||
|
||
QSharedPointer<LogicalLayer> logicalLayer = this->getLogicalLayer(layername);
|
||
if (logicalLayer)
|
||
{
|
||
logicalLayer->setLayerParameter(layerParameter);
|
||
success = true;
|
||
}
|
||
else
|
||
{
|
||
ERROR_LOG(m_logger) << LOGFUNCTION << " not found"
|
||
<< " layername=" << layername;
|
||
}
|
||
|
||
TRACE_LOG(m_logger) << LOGFUNCTION << " END"
|
||
<< " success=" << success;
|
||
return success;
|
||
}
|
||
|
||
|
||
bool LayerFactoryImpl::setLayerParameter(LayerType layerType, int value, int LayerParameter::*memberPtr)
|
||
{
|
||
TRACE_LOG(m_logger) << LOGFUNCTION << " START"
|
||
<< " layer type=" << int(layerType) << " layer parameter member=" << memberPtr << " value=" << value;
|
||
|
||
const QStringList &layerNameList = d->m_orderedMapLayer.layerNamesOrdered(layerType);
|
||
bool success = true;
|
||
|
||
for (const QString &layername : layerNameList)
|
||
{
|
||
QSharedPointer<LogicalLayer> logicalLayer = this->getLogicalLayer(layername);
|
||
if (logicalLayer)
|
||
{
|
||
LayerParameter layerParamTmp = logicalLayer->layerParameter();
|
||
layerParamTmp.*memberPtr = value;
|
||
logicalLayer->setLayerParameter(layerParamTmp);
|
||
|
||
}
|
||
else
|
||
{
|
||
success = false;
|
||
ERROR_LOG(m_logger) << LOGFUNCTION << " not found"
|
||
<< ", layername='" << layername << "'";
|
||
}
|
||
}
|
||
|
||
TRACE_LOG(m_logger) << LOGFUNCTION << " END"
|
||
<< " success=" << success;
|
||
return success;
|
||
}
|
||
|
||
bool LayerFactoryImpl::setLayerOpacity(LayerType layerType, int opacity) { return setLayerParameter(layerType, opacity, &LayerParameter::opacity); }
|
||
bool LayerFactoryImpl::setLayerBrightness(LayerType layerType, int brightness) { return setLayerParameter(layerType, brightness, &LayerParameter::brightness); }
|
||
bool LayerFactoryImpl::setLayerContrast(LayerType layerType, int contrast) { return setLayerParameter(layerType, contrast, &LayerParameter::contrast); }
|
||
bool LayerFactoryImpl::setLayerGamma(LayerType layerType, int gamma) { return setLayerParameter(layerType, gamma, &LayerParameter::gamma); }
|
||
|
||
void LayerFactoryImpl::setLayersVisible(const QVector<LayerType> &layerTypes, bool visible)
|
||
{
|
||
for (auto &logicalLayer : d->m_logicalLayerCont)
|
||
{
|
||
if (!layerTypes.contains(logicalLayer->layerType()))
|
||
continue;
|
||
LayerParameter layerParamTmp = logicalLayer->layerParameter();
|
||
layerParamTmp.visible = visible;
|
||
logicalLayer->setLayerParameter(layerParamTmp);
|
||
}
|
||
}
|
||
|
||
#if ACRGIS_VERSION < 0x640500 // 100.5.0 / Update 5
|
||
// deprecated in V100.5, replaced by GeoView::setSelectionProperties()
|
||
QColor LayerFactoryImpl::selectionColor() const
|
||
{
|
||
return d->m_selectionColor;
|
||
}
|
||
void LayerFactoryImpl::setSelectionColor(const QColor &selectionColor)
|
||
{
|
||
d->m_selectionColor = selectionColor;
|
||
}
|
||
#endif // ACRGIS_VERSION
|
||
|
||
bool LayerFactoryImpl::elevationAvailable() const
|
||
{
|
||
if (!d->m_mapImpl)
|
||
return false;
|
||
return this->elevationSourcesCount() > 0;
|
||
}
|
||
|
||
Esri::ArcGISRuntime::Surface *LayerFactoryImpl::baseSurface() const
|
||
{
|
||
if (!elevationAvailable())
|
||
return nullptr;
|
||
|
||
Esri::ArcGISRuntime::Surface *baseSurface = nullptr;
|
||
|
||
switch (d->m_mapImpl->mode())
|
||
{
|
||
case Mode::Mode_2D:
|
||
baseSurface = d->m_baseSurface;
|
||
break;
|
||
case Mode::Mode_3D:
|
||
{
|
||
Esri::ArcGISRuntime::Scene *esriScene = d->m_mapImpl->getEsriScene();
|
||
if (esriScene &&
|
||
esriScene->baseSurface()
|
||
)
|
||
baseSurface = esriScene->baseSurface();
|
||
}
|
||
break;
|
||
default:
|
||
break;
|
||
} // switch
|
||
|
||
|
||
// Verify:
|
||
if (!baseSurface)
|
||
{
|
||
ERROR_LOG(m_logger) << LOGFUNCTION << " no baseSurface";
|
||
return nullptr;
|
||
}
|
||
|
||
if (baseSurface->loadStatus() != Esri::ArcGISRuntime::LoadStatus::Loaded)
|
||
{
|
||
ERROR_LOG(m_logger) << LOGFUNCTION << " baseSurface not loaded yet";
|
||
return nullptr;
|
||
}
|
||
|
||
int elevationSourcesCount = -1;
|
||
Esri::ArcGISRuntime::ElevationSourceListModel* eslm = baseSurface->elevationSources();
|
||
if (eslm)
|
||
elevationSourcesCount = eslm->size();
|
||
|
||
if (elevationSourcesCount <= 0)
|
||
{
|
||
ERROR_LOG(m_logger) << LOGFUNCTION << " no elevationSourcesCount";
|
||
return nullptr;
|
||
}
|
||
|
||
return baseSurface;
|
||
}
|
||
|
||
int LayerFactoryImpl::elevationSourcesCount(bool checkIfLoaded) const
|
||
{
|
||
if (!d->m_mapImpl)
|
||
return -1;
|
||
|
||
Esri::ArcGISRuntime::ElevationSourceListModel* elevationSourceListModel = nullptr;
|
||
|
||
switch (d->m_mapImpl->mode())
|
||
{
|
||
case Mode::Mode_2D:
|
||
{
|
||
if (d->m_baseSurface && d->m_baseSurface->elevationSources())
|
||
elevationSourceListModel = d->m_baseSurface->elevationSources();
|
||
}
|
||
|
||
break;
|
||
case Mode::Mode_3D:
|
||
{
|
||
if (d->m_mapImpl->getEsriScene() &&
|
||
d->m_mapImpl->getEsriScene()->baseSurface() &&
|
||
d->m_mapImpl->getEsriScene()->baseSurface()->elevationSources()
|
||
)
|
||
elevationSourceListModel = d->m_mapImpl->getEsriScene()->baseSurface()->elevationSources();
|
||
}
|
||
break;
|
||
default:
|
||
return false;
|
||
} // switch
|
||
|
||
if (!elevationSourceListModel)
|
||
return -1;
|
||
|
||
int elevationSourcesCount = -1;
|
||
|
||
if (checkIfLoaded)
|
||
{
|
||
elevationSourcesCount = 0;
|
||
|
||
int idx = 0;
|
||
const int esmSize = elevationSourceListModel->size();
|
||
for (; idx < esmSize; ++idx)
|
||
{
|
||
Esri::ArcGISRuntime::ElevationSource *es = elevationSourceListModel->at(idx);
|
||
|
||
if (es && (es->loadStatus() == Esri::ArcGISRuntime::LoadStatus::Loaded))
|
||
++elevationSourcesCount;
|
||
} // for
|
||
|
||
INFO_LOG(m_logger) << LOGFUNCTION << " elevationSourcesCount = " << esmSize
|
||
<< ", loaded = " << elevationSourcesCount;
|
||
}
|
||
else
|
||
{
|
||
elevationSourcesCount = elevationSourceListModel->size();
|
||
}
|
||
|
||
return elevationSourcesCount;
|
||
}
|
||
|
||
bool LayerFactoryImpl::elevationSourcesLoaded()
|
||
{
|
||
TRACE_LOG(m_logger) << LOGFUNCTION << " START";
|
||
const int elevationSourcesCount = this->elevationSourcesCount();
|
||
const int elevationSourcesCountLoaded = this->elevationSourcesCount(true);
|
||
return (elevationSourcesCount == elevationSourcesCountLoaded);
|
||
}
|
||
|
||
QPointer<LocationToElevationHelper> LayerFactoryImpl::locationToElevation() const
|
||
{
|
||
QPointer<LocationToElevationHelper> locationToElevationHelper;
|
||
|
||
if (!elevationAvailable())
|
||
{
|
||
ERROR_LOG(m_logger) << LOGFUNCTION << " no elevation available";
|
||
return locationToElevationHelper;
|
||
}
|
||
|
||
Esri::ArcGISRuntime::Surface *baseSurface = this->baseSurface();
|
||
|
||
if (!baseSurface)
|
||
{
|
||
ERROR_LOG(m_logger) << LOGFUNCTION << " no baseSurface";
|
||
return locationToElevationHelper;
|
||
}
|
||
|
||
LayerFactoryImpl *THIS = const_cast<LayerFactoryImpl*>(this);
|
||
locationToElevationHelper = new LocationToElevationHelper(THIS); // QPointer -> parent is ok!
|
||
|
||
if (!locationToElevationHelper->init(d->m_mapImpl,
|
||
baseSurface,
|
||
d->m_mapImpl->getEsriSpatialReference()))
|
||
{
|
||
ERROR_LOG(m_logger) << LOGFUNCTION << " locationToElevationHelper->init failed";
|
||
delete locationToElevationHelper;
|
||
return nullptr;
|
||
}
|
||
|
||
return locationToElevationHelper;
|
||
}
|
||
|
||
Esri::ArcGISRuntime::GraphicsOverlay *LayerFactoryImpl::getGraphicsLayer(const QString &logicalName)
|
||
{
|
||
TRACE_LOG(m_logger) << LOGFUNCTION << " START, logicalName='" << logicalName << "'";
|
||
|
||
Esri::ArcGISRuntime::GraphicsOverlay *graphicsLayer = nullptr;
|
||
|
||
QSharedPointer<LogicalLayer> logicalLayer = d->getLogicalLayer(logicalName);
|
||
if (d->m_orderedMapLayer.contains(logicalName, LayerType::Undefined) && logicalLayer)
|
||
graphicsLayer = logicalLayer->getCreateGraphicalOverlay(TechnicalLayerType::GraphicsLayer);
|
||
|
||
TRACE_LOG(m_logger) << LOGFUNCTION << " END, logicalName='" << logicalName << "'"
|
||
<< " graphicsLayer=" << graphicsLayer;
|
||
return graphicsLayer;
|
||
}
|
||
|
||
Esri::ArcGISRuntime::GraphicsOverlay *LayerFactoryImpl::getGraphicsLayerDict(const QString &logicalName)
|
||
{
|
||
TRACE_LOG(m_logger) << LOGFUNCTION << " START, logicalName='" << logicalName << "'";
|
||
|
||
Esri::ArcGISRuntime::GraphicsOverlay *graphicsLayer = nullptr;
|
||
|
||
QSharedPointer<LogicalLayer> logicalLayer = d->getLogicalLayer(logicalName);
|
||
if (d->m_orderedMapLayer.contains(logicalName, LayerType::Undefined) && logicalLayer)
|
||
graphicsLayer = logicalLayer->getCreateGraphicalOverlay(TechnicalLayerType::GraphicsLayer_Dict);
|
||
|
||
TRACE_LOG(m_logger) << LOGFUNCTION << " END, logicalName='" << logicalName << "'"
|
||
<< " graphicsLayer=" << graphicsLayer;
|
||
return graphicsLayer;
|
||
}
|
||
|
||
Esri::ArcGISRuntime::GraphicsOverlay *LayerFactoryImpl::getGraphicsLayer3DExtrusion(const QString &logicalName)
|
||
{
|
||
TRACE_LOG(m_logger) << LOGFUNCTION << " START, logicalName='" << logicalName << "'";
|
||
|
||
Esri::ArcGISRuntime::GraphicsOverlay *graphicsLayer = nullptr;
|
||
|
||
// getGraphicsLayer3DExtrusion -> SurfacePlacement::Relative
|
||
|
||
QSharedPointer<LogicalLayer> logicalLayer = d->getLogicalLayer(logicalName);
|
||
if (d->m_orderedMapLayer.contains(logicalName, LayerType::Undefined) && logicalLayer)
|
||
graphicsLayer = logicalLayer->getCreateGraphicalOverlay(TechnicalLayerType::GraphicsLayer_3D_Extrusion);
|
||
|
||
TRACE_LOG(m_logger) << LOGFUNCTION << " END, logicalName='" << logicalName << "'"
|
||
<< " graphicsLayer=" << graphicsLayer;
|
||
return graphicsLayer;
|
||
}
|
||
|
||
Esri::ArcGISRuntime::GraphicsOverlay *LayerFactoryImpl::getGraphicsLayer3D_SpAbsolute(const QString &logicalName)
|
||
{
|
||
TRACE_LOG(m_logger) << LOGFUNCTION << " START, logicalName='" << logicalName << "'";
|
||
|
||
Esri::ArcGISRuntime::GraphicsOverlay *graphicsLayer = nullptr;
|
||
|
||
// getGraphicsLayer3D_SpAbsolute -> SurfacePlacement::Absolute
|
||
|
||
QSharedPointer<LogicalLayer> logicalLayer = d->getLogicalLayer(logicalName);
|
||
if (d->m_orderedMapLayer.contains(logicalName, LayerType::Undefined) && logicalLayer)
|
||
graphicsLayer = logicalLayer->getCreateGraphicalOverlay(TechnicalLayerType::GraphicsLayer_3D_Absolute);
|
||
|
||
TRACE_LOG(m_logger) << LOGFUNCTION << " END, logicalName='" << logicalName << "'"
|
||
<< " graphicsLayer=" << graphicsLayer;
|
||
return graphicsLayer;
|
||
}
|
||
|
||
|
||
|
||
QString LayerFactoryImpl::createInternalLayerName(const TechnicalLayerType &technicalLayerType,
|
||
const QString &logicalLayerName) const
|
||
{
|
||
return LogicalLayer::createInternalLayerName(logicalLayerName, technicalLayerType);
|
||
}
|
||
|
||
QSharedPointer<LogicalLayer> LayerFactoryImpl::getLogicalLayer(const QString &logicalName) const
|
||
{
|
||
return d->getLogicalLayer(logicalName);
|
||
}
|
||
|
||
QSharedPointer<LogicalLayer> LayerFactoryImpl::getCreateLogicalLayer(const QString &logicalName)
|
||
{
|
||
if (! d->hasLogicalLayer(logicalName))
|
||
d->createLogicalLayer(logicalName);
|
||
|
||
QSharedPointer<LogicalLayer> logicalLayer = d->getLogicalLayer(logicalName);
|
||
if (logicalLayer)
|
||
{
|
||
connect(logicalLayer.data(), &LogicalLayer::layerParameterChanged,
|
||
this, &LayerFactoryImpl::onLayerParameterChanged);
|
||
|
||
connect(logicalLayer.data(), &LogicalLayer::layerCreatedOnDemand,
|
||
this, &LayerFactoryImpl::onLayerCreatedOnDemand);
|
||
|
||
connect(logicalLayer.data(), &LogicalLayer::layerDoneLoading,
|
||
this, &LayerFactoryImpl::onLayerDoneLoading);
|
||
}
|
||
else
|
||
ERROR_LOG(m_logger) << LOGFUNCTION << " getLogicalLayer failed";
|
||
return logicalLayer;
|
||
}
|
||
|
||
bool LayerFactoryImpl::addBasemapInternal(const QString &layername,
|
||
const QUrl &mapServiceUrl,
|
||
const BasemapType basemapType,
|
||
const double minScale,
|
||
const double maxScale,
|
||
const QString &displayName,
|
||
const QString &description,
|
||
const QImage &previewImage)
|
||
{
|
||
if (mapServiceUrl.isEmpty())
|
||
{
|
||
ERROR_LOG(m_logger) << LOGFUNCTION << " mapServiceUrl empty, can not add layer "
|
||
<< layername << " basemap type: " << basemapType;
|
||
return false;
|
||
}
|
||
|
||
if (d->m_orderedMapLayer.contains(layername, LayerType::Undefined))
|
||
{
|
||
ERROR_LOG(m_logger) << LOGFUNCTION << " layername '" << layername << "' already in use";
|
||
return false;
|
||
}
|
||
|
||
//-----------------------------------
|
||
// ArcGIS Tiled Basemap Layer
|
||
//-----------------------------------
|
||
//-----------------------------------------------------------------
|
||
// Attention:
|
||
// local URLS -> do NOT specify any userCredentials (main)
|
||
// external URLS -> DO specify userCredentials (main)
|
||
//-----------------------------------------------------------------
|
||
|
||
Esri::ArcGISRuntime::Layer *layer = nullptr;
|
||
|
||
|
||
if (mapServiceUrl.isLocalFile())
|
||
{
|
||
QUrl finalUrl = this->completeUrl(QLatin1String("BASEMAP"),
|
||
mapServiceUrl,
|
||
QLatin1String("/"));
|
||
INFO_LOG(m_logger) << LOGFUNCTION
|
||
<< " TileCache: finalUrl '" << finalUrl.toString() << "'"
|
||
<< ", finalUrltoLocalFile '" << finalUrl.toLocalFile() << "'";
|
||
QString tcFileAbs = finalUrl.toLocalFile();
|
||
|
||
QFileInfo fi(tcFileAbs);
|
||
|
||
if (!fi.exists(tcFileAbs))
|
||
{
|
||
ERROR_LOG(m_logger) << LOGFUNCTION << " file '" << tcFileAbs << "' doesn't exists";
|
||
return false;
|
||
}
|
||
|
||
if (fi.isDir() || // TileCacheFolder
|
||
fi.suffix().compare(QLatin1String("tpk"))==0) // TilePackage
|
||
{
|
||
Esri::ArcGISRuntime::TileCache *tileCache = new Esri::ArcGISRuntime::TileCache(tcFileAbs, d->m_mapImpl);
|
||
tileCache->setObjectName(QLatin1String("BasemapTileCache-")+layername);
|
||
layer = new Esri::ArcGISRuntime::ArcGISTiledLayer(tileCache, d->m_mapImpl);
|
||
}
|
||
else if (fi.suffix().compare(QLatin1String("vtpk"))==0) // VectorTilePackage
|
||
{
|
||
Esri::ArcGISRuntime::VectorTileCache *vectorTileCache = new Esri::ArcGISRuntime::VectorTileCache(tcFileAbs, d->m_mapImpl);
|
||
vectorTileCache->setObjectName(QLatin1String("BasemapVectorTileCache-")+layername);
|
||
layer = new Esri::ArcGISRuntime::ArcGISVectorTiledLayer(vectorTileCache, d->m_mapImpl);
|
||
}
|
||
else
|
||
{
|
||
// geotiff (often '.tif')
|
||
Esri::ArcGISRuntime::Raster* raster = new Esri::ArcGISRuntime::Raster(tcFileAbs, d->m_mapImpl);
|
||
layer = new Esri::ArcGISRuntime::RasterLayer(raster, d->m_mapImpl);
|
||
|
||
// loading of the geotiff may take a while (tile by tile)
|
||
}
|
||
}
|
||
else
|
||
{
|
||
INFO_LOG(m_logger) << LOGFUNCTION << " loading url '" << mapServiceUrl.toString() << "'";
|
||
layer = new Esri::ArcGISRuntime::ArcGISTiledLayer(mapServiceUrl, d->m_mapImpl);
|
||
}
|
||
|
||
layer->setName(layername);
|
||
layer->setObjectName(layer->name());
|
||
|
||
if (!d->m_orderedMapLayer.addLayer(layer->name(), SituationMap::LayerType::Basemap))
|
||
{
|
||
ERROR_LOG(m_logger) << LOGFUNCTION
|
||
<< " addLayer failed'" << layer->name() << "'";
|
||
}
|
||
|
||
QImage previewImageFinal = previewImage;
|
||
if (previewImageFinal.isNull())
|
||
{
|
||
switch (basemapType)
|
||
{
|
||
case BasemapType::Undefined:
|
||
case BasemapType::Aerial:
|
||
previewImageFinal = QImage(QLatin1String(":/situationMap/preview_aerial.png"));
|
||
break;
|
||
case BasemapType::Topographic:
|
||
previewImageFinal = QImage(QLatin1String(":/situationMap/preview_topographic.png"));
|
||
break;
|
||
} // switch
|
||
}
|
||
|
||
if (! d->m_basemap)
|
||
{
|
||
ERROR_LOG(m_logger) << LOGFUNCTION << " no basemap!!!";
|
||
return false;
|
||
}
|
||
|
||
|
||
int basemapCount = -1;
|
||
if (d->m_basemap->baseLayers())
|
||
basemapCount = d->m_basemap->baseLayers()->size();
|
||
|
||
INFO_LOG(m_logger) << LOGFUNCTION << " basemapCount = " << basemapCount;
|
||
|
||
d->m_basemap->baseLayers()->append(layer);
|
||
|
||
|
||
// getLogicalLayer will
|
||
// - initialize
|
||
// - do errorHandling
|
||
// - update Layerparamter on doneLoading
|
||
// - and add layer to LayerListModel of basemap:
|
||
QSharedPointer<LogicalLayer> logicalLayer = this->getCreateLogicalLayer(layername);
|
||
if (logicalLayer.isNull())
|
||
{
|
||
ERROR_LOG(m_logger) << LOGFUNCTION
|
||
<< " getLogicalLayer invalid'" << layername << "'";
|
||
}
|
||
else
|
||
{
|
||
// update LayerParameter first:
|
||
LayerParameter lp = logicalLayer->layerParameter();
|
||
lp.url = mapServiceUrl;
|
||
lp.minScale = minScale;
|
||
lp.maxScale = maxScale;
|
||
lp.basemapType = basemapType;
|
||
lp.displayName = displayName;
|
||
lp.description = description;
|
||
lp.previewImage = previewImageFinal;
|
||
logicalLayer->setLayerParameter(lp);
|
||
|
||
logicalLayer->setLayer(layer);
|
||
logicalLayer->setLayerType(LayerType::Basemap);
|
||
logicalLayer->setBasemapType(basemapType); // basemapType -> aerial, topo...
|
||
}
|
||
|
||
|
||
// // load / retryLoad:
|
||
// if (d->m_esriMap->loadStatus() == Esri::ArcGISRuntime::LoadStatus::FailedToLoad)
|
||
// d->m_esriMap->retryLoad();
|
||
// else
|
||
// d->m_esriMap->load();
|
||
|
||
return true;
|
||
}
|
||
|
||
bool LayerFactoryImpl::removeLayerInternal(const LayerType &layerType, const QString &logicalLayerName)
|
||
{
|
||
TRACE_LOG(m_logger) << LOGFUNCTION << " START"
|
||
<< " layerType=" << layerType
|
||
<< " logicalLayerName=" << logicalLayerName;
|
||
|
||
if (logicalLayerName.isEmpty())
|
||
{
|
||
ERROR_LOG(m_logger) << LOGFUNCTION << " logicalLayerName empty"
|
||
<< logicalLayerName;
|
||
return false;
|
||
}
|
||
if (! d->m_orderedMapLayer.contains(logicalLayerName, layerType))
|
||
{
|
||
ERROR_LOG(m_logger) << LOGFUNCTION << " does not exist: '"
|
||
<< " layerType=" << layerType
|
||
<< " logicalLayerName='" << logicalLayerName << "'";
|
||
return false;
|
||
}
|
||
|
||
if (! d->hasLogicalLayer(logicalLayerName))
|
||
{
|
||
ERROR_LOG(m_logger) << LOGFUNCTION << " does not exist: '"
|
||
<< " layerType=" << layerType
|
||
<< " logicalLayerName='" << logicalLayerName << "'";
|
||
}
|
||
|
||
if (! d->m_orderedMapLayer.removeLayer(logicalLayerName))
|
||
{
|
||
ERROR_LOG(m_logger) << LOGFUNCTION << " remove failed: '"
|
||
<< " layerType=" << layerType;
|
||
return false;
|
||
}
|
||
|
||
d->removeLogicalLayer(logicalLayerName);
|
||
|
||
TRACE_LOG(m_logger) << LOGFUNCTION << " END"
|
||
<< " logicalLayerName='" << logicalLayerName << "'";
|
||
return true;
|
||
}
|
||
|
||
bool LayerFactoryImpl::reOrderLayer()
|
||
{
|
||
TRACE_LOG(m_logger) << LOGFUNCTION << " START";
|
||
|
||
DEBUG_LOG(m_logger) << LOGFUNCTION << " orderedList 1: " << d->m_orderedMapLayer.layerNamesOrdered().join(QLatin1String(";"));
|
||
|
||
reOrderLayerBasemap();
|
||
reOrderLayerGraphicOverlays();
|
||
|
||
DEBUG_LOG(m_logger) << LOGFUNCTION << " orderedList 2: " << d->m_orderedMapLayer.layerNamesOrdered().join(QLatin1String(";"));
|
||
|
||
TRACE_LOG(m_logger) << LOGFUNCTION << " END";
|
||
return true;
|
||
}
|
||
|
||
bool LayerFactoryImpl::reOrderLayerBasemap()
|
||
{
|
||
TRACE_LOG(m_logger) << LOGFUNCTION << " START";
|
||
|
||
if (!(d->m_basemap &&
|
||
d->m_basemap->baseLayers() &&
|
||
! d->m_basemap->baseLayers()->isEmpty())
|
||
)
|
||
return false;
|
||
|
||
const QStringList &allLogicalLayerNames = d->m_orderedMapLayer.layerNamesOrdered();
|
||
DEBUG_LOG(m_logger) << LOGFUNCTION << " orderedListAll: " << allLogicalLayerNames.join(QLatin1String(";"));
|
||
|
||
const QStringList &basemapLogicalNames = d->m_orderedMapLayer.layerNamesOrdered(LayerType::Basemap);
|
||
DEBUG_LOG(m_logger) << LOGFUNCTION << " orderedListBasemap: " << basemapLogicalNames.join(QLatin1String(";"));
|
||
|
||
int newIdx = 0;
|
||
Esri::ArcGISRuntime::LayerListModel *model = d->m_basemap->baseLayers();
|
||
for (const QString &basemapName : basemapLogicalNames)
|
||
{
|
||
int curIdx = getEsriBasemapLayerIndex(basemapName);
|
||
|
||
if (curIdx != newIdx)
|
||
{
|
||
DEBUG_LOG(m_logger) << LOGFUNCTION
|
||
<< " move"
|
||
<< " basemapName ='" << basemapName << "'"
|
||
<< " from " << curIdx
|
||
<< " to " << newIdx << "...";
|
||
model->move(curIdx, newIdx);
|
||
}
|
||
++newIdx;
|
||
} // for
|
||
|
||
TRACE_LOG(m_logger) << LOGFUNCTION << " END"
|
||
<< " orderedList: " << d->m_orderedMapLayer.layerNamesOrdered().join(QLatin1String(";"));
|
||
return true;
|
||
}
|
||
|
||
bool LayerFactoryImpl::reOrderLayerGraphicOverlays()
|
||
{
|
||
TRACE_LOG(m_logger) << LOGFUNCTION << " START"
|
||
<< " orderedList: " << d->m_orderedMapLayer.layerNamesOrdered().join(QLatin1String(";"));
|
||
|
||
if (! d->getEsriGraphicsOverlayListModel())
|
||
return false;
|
||
|
||
if (d->getEsriGraphicsOverlayListModel()->isEmpty())
|
||
return false;
|
||
|
||
const QStringList &layernamesOrdered = d->m_orderedMapLayer.layerNamesOrdered();
|
||
|
||
//
|
||
// reOrder all GraphicOverlays:
|
||
//
|
||
DEBUG_LOG(m_logger) << LOGFUNCTION << " layernamesOrdered: " << layernamesOrdered.join(QLatin1String(";"));
|
||
|
||
Esri::ArcGISRuntime::GraphicsOverlayListModel *model = d->getEsriGraphicsOverlayListModel();
|
||
DEBUG_LOG(m_logger) << LOGFUNCTION << " model.size() 1= " << model->size();
|
||
|
||
|
||
// N. Thoden, 28.03.2018, V100.2.1 - Consulting with Luke Smallwood:
|
||
// Using the testFix for the crashOnStartup, the approach of
|
||
// model->clear();
|
||
// // re-append in required new order:
|
||
// foreach (auto l, newOrderedGraphicsOverlayList)
|
||
// model->append(l)
|
||
// fails. -> go back to the initial (move) approach
|
||
// ==> use MOVE_APPROACH
|
||
#define MOVE_APPROACH
|
||
|
||
// N. Thoden, 06.04.2018, V100.2.1 - AFTER Consulting with Luke Smallwood:
|
||
// Scenario:
|
||
// - start opApp,
|
||
// - add simple plan/overlay (one ETS point symbol) via Overlay Dialag
|
||
// (participants can be picked and MapObjectSelection is opened)
|
||
// - remove plan/overlay via Overlay Dialag
|
||
// (participants can no longer be picked and MapObjectSelection is opened)
|
||
// -> EventMouseNavigator::onGetPickingResult gets empty list from ESRI...
|
||
// ==> toogle back to NOT using MOVE_APPROACH
|
||
#undef MOVE_APPROACH
|
||
|
||
// N. Thoden, 30.08.2018, V100.3.0 - behaviour is now:
|
||
// Using the MOVE_APPROACH the picking is working
|
||
#if ACRGIS_VERSION >= 0x640300 // 100.3.0 / Update 3
|
||
# define MOVE_APPROACH
|
||
#endif
|
||
|
||
|
||
#ifdef MOVE_APPROACH
|
||
//
|
||
// model->move(curIdx, newIdx); seems to be buggy
|
||
// (N. Thoden, 29.09.2016, QuartzBeta1)
|
||
//
|
||
int newIdx = 0;
|
||
for (const QString &logicalname : layernamesOrdered)
|
||
{
|
||
QSharedPointer<LogicalLayer> ll = d->getLogicalLayer(logicalname);
|
||
if (ll && ll->basemapType() == BasemapType::Undefined) //BasemapType::Undefined -> GraphicsOverlay
|
||
{
|
||
QList<QPair<QString, Esri::ArcGISRuntime::GraphicsOverlay*> > pairs =
|
||
ll->getCurrentGraphicalOverlaysOrderedWithName();
|
||
|
||
QListIterator< QPair<QString, Esri::ArcGISRuntime::GraphicsOverlay*> > it(pairs);
|
||
|
||
while (it.hasNext())
|
||
{
|
||
const QPair<QString, Esri::ArcGISRuntime::GraphicsOverlay*> &pair = it.next();
|
||
|
||
const QString &esriLayername = pair.first;
|
||
Esri::ArcGISRuntime::GraphicsOverlay *graphicalOverlay = pair.second;
|
||
|
||
DEBUG_LOG(m_logger) << LOGFUNCTION
|
||
<< " handle"
|
||
<< " esriLayername='" << esriLayername << "':";
|
||
|
||
int curIdx = model->indexOf(graphicalOverlay);
|
||
|
||
DEBUG_LOG(m_logger) << LOGFUNCTION
|
||
<< " handle"
|
||
<< " esriLayername='" << esriLayername << "':"
|
||
<< " curIdx=" << curIdx << " -> newIdx="<< newIdx;
|
||
|
||
if (curIdx < 0)
|
||
{
|
||
FATAL_LOG(m_logger) << LOGFUNCTION
|
||
<< " esriLayername='" << esriLayername << "':"
|
||
<< " not found";
|
||
abort();
|
||
// continue;
|
||
}
|
||
|
||
if (curIdx != newIdx)
|
||
{
|
||
DEBUG_LOG(m_logger) << LOGFUNCTION
|
||
<< " move"
|
||
<< " GraphicOverlays ="
|
||
<< " from " << curIdx
|
||
<< " to " << newIdx << "..." ;
|
||
DEBUG_LOG(m_logger) << LOGFUNCTION << " model.size() 2= " << model->size();
|
||
model->move(curIdx, newIdx);
|
||
DEBUG_LOG(m_logger) << LOGFUNCTION << " model.size() 3= " << model->size();
|
||
|
||
int retIdx = model->indexOf(graphicalOverlay);
|
||
|
||
if (retIdx != newIdx)
|
||
{
|
||
FATAL_LOG(m_logger) << LOGFUNCTION
|
||
<< " esriLayername='" << esriLayername << "':"
|
||
<< " move failed"
|
||
<< " curIdx='" << curIdx
|
||
<< " newIdx='" << newIdx
|
||
<< " retIdx='" << retIdx;
|
||
abort();
|
||
}
|
||
}
|
||
++newIdx;
|
||
} // while
|
||
} // if
|
||
} // for
|
||
|
||
#else
|
||
|
||
// build new order of GraphicsOverlays :
|
||
QList<Esri::ArcGISRuntime::GraphicsOverlay *> newOrderedGraphicsOverlayList;
|
||
|
||
foreach (const QString &logicalname, layernamesOrdered)
|
||
{
|
||
QSharedPointer<LogicalLayer> ll = d->getLogicalLayer(logicalname);
|
||
if (ll && ll->basemapType() == BasemapType::Undefined) //BasemapType::Undefined -> GraphicsOverlay
|
||
{
|
||
QList<QPair<QString, Esri::ArcGISRuntime::GraphicsOverlay *> > pairs =
|
||
ll->getCurrentGraphicalOverlaysOrderedWithName();
|
||
|
||
QListIterator< QPair<QString, Esri::ArcGISRuntime::GraphicsOverlay *> > it(pairs);
|
||
|
||
while (it.hasNext())
|
||
{
|
||
const QPair<QString, Esri::ArcGISRuntime::GraphicsOverlay *> &pair = it.next();
|
||
|
||
QString esriLayername = pair.first;
|
||
Esri::ArcGISRuntime::GraphicsOverlay *graphicalOverlay = pair.second;
|
||
|
||
DEBUG_LOG(m_logger) << LOGFUNCTION
|
||
<< " handle"
|
||
<< " esriLayername='" << esriLayername << "'";
|
||
newOrderedGraphicsOverlayList.append(graphicalOverlay);
|
||
} // while
|
||
} // if
|
||
} // foreach
|
||
// : build new order of GraphicsOverlays
|
||
|
||
// clear model:
|
||
model->clear();
|
||
|
||
// re-append in required new order:
|
||
foreach (auto l, newOrderedGraphicsOverlayList)
|
||
model->append(l);
|
||
|
||
#endif // MOVE_APPROACH
|
||
|
||
DEBUG_LOG(m_logger) << LOGFUNCTION << " model.size() 4= " << model->size();
|
||
|
||
TRACE_LOG(m_logger) << LOGFUNCTION << " END"
|
||
<< " orderedList: " << d->m_orderedMapLayer.layerNamesOrdered().join(QLatin1String(";"));
|
||
return true;
|
||
}
|
||
|
||
int LayerFactoryImpl::getEsriBasemapLayerIndex(const QString &esriLayername) const
|
||
{
|
||
if (!(d->m_basemap && d->m_basemap->baseLayers()))
|
||
return -1;
|
||
|
||
const Esri::ArcGISRuntime::LayerListModel *model = d->m_basemap->baseLayers();
|
||
for (int i = 0; i < model->size(); ++i)
|
||
{
|
||
const Esri::ArcGISRuntime::Layer *curLayer = model->at(i);
|
||
const QString &curName = curLayer->name();
|
||
if (QString::compare(esriLayername, curName) == 0)
|
||
return i;
|
||
}
|
||
return -1;
|
||
}
|
||
|
||
Esri::ArcGISRuntime::Layer *LayerFactoryImpl::getEsriBasemapLayer(const QString &esriLayername) const
|
||
{
|
||
int idx = getEsriBasemapLayerIndex(esriLayername);
|
||
if (idx < 0)
|
||
return nullptr;
|
||
// d->m_basemap already checked within 'getEsriBasemapLayerIndex'
|
||
Esri::ArcGISRuntime::Layer *layerFound = d->m_basemap->baseLayers()->at(idx);
|
||
return layerFound;
|
||
}
|
||
|
||
QUrl LayerFactoryImpl::completeUrl(const QString &context,
|
||
const QUrl &urlIn,
|
||
const QString &resourceSubdir)
|
||
{
|
||
DEBUG_LOG(m_logger) << LOGFUNCTION << " START"
|
||
<< " context='" << context << "'"
|
||
<< ", urlIn='" << urlIn.toString()
|
||
<< " resourceSubdir='" << resourceSubdir << "'";
|
||
|
||
if (!urlIn.isLocalFile())
|
||
{
|
||
DEBUG_LOG(m_logger) << LOGFUNCTION << " http -> return"
|
||
<< ", url ='" << urlIn.toString();
|
||
return urlIn;
|
||
}
|
||
|
||
// assume it´s a file url:
|
||
// make absolute path according resourcePath:
|
||
QString filePathAbs = urlIn.toLocalFile();
|
||
if (QDir::isRelativePath(filePathAbs))
|
||
filePathAbs = SituationMap::getResourcePath() + resourceSubdir + filePathAbs;
|
||
|
||
if (!QFileInfo::exists(filePathAbs))
|
||
{
|
||
ERROR_LOG(m_logger) << LOGFUNCTION
|
||
<< " context='" << context << "'"
|
||
<< " file '" << filePathAbs << "' doesn't exists";
|
||
return urlIn;
|
||
}
|
||
|
||
DEBUG_LOG(m_logger) << LOGFUNCTION << " END"
|
||
<< " context='" << context << "'"
|
||
<< ", filePathAbs='" << filePathAbs << "'";
|
||
return QUrl::fromLocalFile(filePathAbs);
|
||
}
|
||
|
||
|
||
void LayerFactoryImpl::onLayerParameterChanged(const QString &layername, const LayerParameter &newLayerParameter)
|
||
{
|
||
TRACE_LOG(m_logger) << LOGFUNCTION << " START"
|
||
<< " layername='" << layername << "'"
|
||
<< ", newLayerParameter='" << newLayerParameter;
|
||
d->m_mapImpl->emitLayerParameterChanged(layername, newLayerParameter);
|
||
}
|
||
|
||
void LayerFactoryImpl::onLayerCreatedOnDemand(const QString &logicalName)
|
||
{
|
||
TRACE_LOG(m_logger) << LOGFUNCTION << " START"
|
||
<< " logicalName='" << logicalName << "'";
|
||
this->reOrderLayer();
|
||
TRACE_LOG(m_logger) << LOGFUNCTION << " END"
|
||
<< " logicalName='" << logicalName << "'";
|
||
}
|
||
|
||
void LayerFactoryImpl::onLayerDoneLoading(const QString &logicalName)
|
||
{
|
||
TRACE_LOG(m_logger) << LOGFUNCTION << " START"
|
||
<< " logicalName='" << logicalName << "'";
|
||
|
||
MapLayer mapLayer = d->m_orderedMapLayer.getLayer(logicalName);
|
||
if (!mapLayer.isValid())
|
||
{
|
||
ERROR_LOG(m_logger) << LOGFUNCTION << " mapLayer not found"
|
||
<< " layername='" << logicalName << "'";
|
||
}
|
||
|
||
if (mapLayer.type() != LayerType::Basemap)
|
||
return;
|
||
|
||
QSharedPointer<LogicalLayer> layer = d->getLogicalLayer(logicalName);
|
||
if (!layer)
|
||
{
|
||
ERROR_LOG(m_logger) << LOGFUNCTION << " no layer, "
|
||
<< " layername='" << logicalName << "'";
|
||
return;
|
||
}
|
||
|
||
// Bugfix :
|
||
// REGG-5350 - mit dem normalen Zoom ( Mausrad ) kann man 6 Stufen ansteuern.
|
||
// Erst nach der Ums...
|
||
// REGG-5338 - In der Live-Lage ist die Zoomstufe nicht
|
||
// vollständig nutzbar, das letzte Viertel...
|
||
// REGG-5317 - Die Lagekarte der 1. Lageanwendung lässt sich nicht bis
|
||
// zur untersten Begrenzung...
|
||
|
||
// (Hinein)Zoomen nur bis Scale 4000 moeglich...
|
||
// Tritt mit TA Letzlingen und User OHNE Settings sgelgentlich auf.
|
||
// Loesungsansatz: Slot-Methoden von synchronen Aufruf zu
|
||
// reCalculateMinMaxScaleBasedOnLayers befreien und per Timer aufrufen.
|
||
// // reCalculate minMaxScale even if there is just one Basemap:
|
||
// // calulcate and set values direct:
|
||
// reCalculateMinMaxScaleBasedOnLayers();
|
||
// : Bugfix
|
||
|
||
// do via timer:
|
||
d->reCalculateMinMaxScaleTimer->start(); // start == restart
|
||
|
||
TRACE_LOG(m_logger) << LOGFUNCTION << " END"
|
||
<< " logicalName='" << logicalName << "'";
|
||
}
|
||
|
||
void LayerFactoryImpl::onElevationSourceDoneLoading()
|
||
{
|
||
Esri::ArcGISRuntime::ElevationSource *elevationSource = qobject_cast<Esri::ArcGISRuntime::ElevationSource *>(sender());
|
||
if (elevationSource)
|
||
{
|
||
INFO_LOG(m_logger) << LOGFUNCTION << " ElevationSource -> doneLoading: "
|
||
<< " sender= '" << elevationSource->objectName() << "'"
|
||
<< " loadStatus= '" << elevationSource->loadStatus() << "'"
|
||
<< " elevationSourceType= " << elevationSource->elevationSourceType();
|
||
|
||
INFO_LOG(m_logger) << LOGFUNCTION << " ElevationSources " << elevationSourcesLoaded();
|
||
|
||
if (elevationSourcesLoaded())
|
||
{
|
||
INFO_LOG(m_logger) << LOGFUNCTION << " ElevationSources completed";
|
||
d->m_mapImpl->emitAllElevationSourcesLoaded();
|
||
}
|
||
}
|
||
else
|
||
INFO_LOG(m_logger) << LOGFUNCTION << " ElevationSource -> doneLoading";
|
||
|
||
}
|
||
|
||
void LayerFactoryImpl::onElevationSourceErrorOccured(const Esri::ArcGISRuntime::Error &error)
|
||
{
|
||
QString senderName;
|
||
Esri::ArcGISRuntime::ElevationSource *elevationSource = qobject_cast<Esri::ArcGISRuntime::ElevationSource *>(sender());
|
||
if (elevationSource)
|
||
senderName = elevationSource->objectName();
|
||
|
||
ERROR_LOG(m_logger) << LOGFUNCTION << " ElevationSource -> EsriError occured: " << error
|
||
<< ", sender= '" << senderName << "'";
|
||
}
|
||
|
||
void LayerFactoryImpl::onSurfaceDoneLoading2D()
|
||
{
|
||
QString senderName;
|
||
Esri::ArcGISRuntime::Surface *surface = qobject_cast<Esri::ArcGISRuntime::Surface *>(sender());
|
||
if (surface)
|
||
senderName = surface->objectName();
|
||
|
||
INFO_LOG(m_logger) << LOGFUNCTION << " Surface -> doneLoading: "
|
||
<< " sender= '" << senderName << "'";
|
||
}
|
||
|
||
void LayerFactoryImpl::onSurfaceErrorOccured2D(const Esri::ArcGISRuntime::Error &error)
|
||
{
|
||
QString senderName;
|
||
Esri::ArcGISRuntime::Surface *surface = qobject_cast<Esri::ArcGISRuntime::Surface *>(sender());
|
||
if (surface)
|
||
senderName = surface->objectName();
|
||
|
||
ERROR_LOG(m_logger) << LOGFUNCTION << " Surface -> EsriError occured: " << error
|
||
<< ", sender= '" << senderName << "'";
|
||
}
|
||
|
||
void LayerFactoryImpl::reCalculateMinMaxScaleBasedOnLayers()
|
||
{
|
||
TRACE_LOG(m_logger) << LOGFUNCTION << " START";
|
||
|
||
const QStringList &layernames = d->m_orderedMapLayer.layerNamesOrdered(LayerType::Basemap);
|
||
|
||
double minScale = 0;
|
||
double maxScale = 0;
|
||
|
||
QList<int> minScales;
|
||
QList<int> maxScales;
|
||
|
||
|
||
bool initial = true;
|
||
|
||
for (const QString &layername : layernames)
|
||
{
|
||
DEBUG_LOG(m_logger) << LOGFUNCTION << " layername" << layername;
|
||
|
||
QSharedPointer<LogicalLayer> layer = d->getLogicalLayer(layername);
|
||
if (!layer)
|
||
{
|
||
ERROR_LOG(m_logger) << LOGFUNCTION << " no layer, "
|
||
<< " layername='" << layername << "'";
|
||
continue;
|
||
}
|
||
|
||
const LayerParameter &layerParameter = layer->layerParameter();
|
||
|
||
DEBUG_LOG(m_logger) << LOGFUNCTION
|
||
<< " layername='" << layername << "'"
|
||
<< " minScale=" << layerParameter.minScale
|
||
<< " maxScale=" << layerParameter.maxScale;
|
||
|
||
|
||
// already loaded? (
|
||
if (!layerParameter.minMaxScaleValid())
|
||
{
|
||
DEBUG_LOG(m_logger) << LOGFUNCTION << " layername" << layername
|
||
<< " not valid";
|
||
continue;
|
||
}
|
||
|
||
double localMinScale = layerParameter.minScale;
|
||
double localMaxScale = layerParameter.maxScale;
|
||
|
||
minScales.append(static_cast<int>(localMinScale));
|
||
maxScales.append(static_cast<int>(localMaxScale));
|
||
|
||
// first time: set initial values:
|
||
if (initial)
|
||
{
|
||
initial = false;
|
||
minScale = localMinScale;
|
||
maxScale = localMaxScale;
|
||
}
|
||
else
|
||
{
|
||
minScale = std::max(minScale, localMinScale); // use std::max for minScale!!!
|
||
maxScale = std::min(maxScale, localMaxScale); // use std::min for maxScale!!!
|
||
}
|
||
} // for
|
||
|
||
DEBUG_LOG(m_logger) << LOGFUNCTION
|
||
<< " a minScale=" << minScale
|
||
<< " maxScale=" << maxScale;
|
||
|
||
// OGC: scales are optional. In this case use '0':
|
||
// For MinScale:
|
||
if (minScales.contains(0))
|
||
minScale = 0;
|
||
|
||
// For MaxScale:
|
||
if (maxScales.contains(0))
|
||
maxScale = 0;
|
||
|
||
DEBUG_LOG(m_logger) << LOGFUNCTION
|
||
<< " apply "
|
||
<< " minScale=" << minScale
|
||
<< " maxScale=" << maxScale;
|
||
// d->m_mapImpl->setMinScale(minScale+1); // why did i wrote this?
|
||
// d->m_mapImpl->setMaxScale(maxScale+1); // why did i wrote this?
|
||
d->m_mapImpl->setMinScale(minScale);
|
||
d->m_mapImpl->setMaxScale(maxScale);
|
||
}
|
||
|
||
|
||
} // namespace SituationMap
|