/** * @RDE_HEADER@ * TerrainProfileProcessor * $Id$ * $HeadURL$ * $Author$ */ // Own #include "terrain_profile_processor.h" #include "map_impl.h" #include #include #include #include #include // ESRI #include #include // Qt namespace SituationMap { //----------------------------------------------------------------------------- // class ViewshedBase //----------------------------------------------------------------------------- TerrainProfileProcessor::TerrainProfileProcessor(QObject *parent) : QObject(parent) , m_logger(getLogger("TerrainProfileProcessor")) { TRACE_LOG(m_logger) << LOGFUNCTION << " START"; TRACE_LOG(m_logger) << LOGFUNCTION << " END"; } TerrainProfileProcessor::~TerrainProfileProcessor() { TRACE_LOG(m_logger) << LOGFUNCTION << " START, id=" << m_id; removeUserInput(); // maybe clear the view of m_terrainProfileDialog here? TRACE_LOG(m_logger) << LOGFUNCTION << " END, id=" << m_id; } bool TerrainProfileProcessor::init(SituationMap::MapImpl *mapImpl, long id) { TRACE_LOG(m_logger) << LOGFUNCTION << " START"; m_id = id; m_initialized = false; m_mapImpl = mapImpl; m_srMap = m_mapImpl->getEsriSpatialReference(); LayerFactoryImpl &layerFactoryImpl = m_mapImpl->layerFactoryImpl(); m_toolsLayername = layerFactoryImpl.toolLayer(); if (!m_surface) m_surface = layerFactoryImpl.baseSurface(); if (m_surface && m_surface->loadStatus() == Esri::ArcGISRuntime::LoadStatus::Loaded) m_initialized = true; else { Esri::ArcGISRuntime::LoadStatus ls = Esri::ArcGISRuntime::LoadStatus::Unknown; if (m_surface) ls = m_surface->loadStatus(); ERROR_LOG(m_logger) << LOGFUNCTION << " d->m_surface = " << m_surface << " d->m_surface->loadStatus = " << ls; } if (!m_locationToElevationBulk.init(m_mapImpl, m_surface)) { ERROR_LOG(m_logger) << LOGFUNCTION << " locationToElevationBulk.init() failed"; return false; } connect(&m_locationToElevationBulk, &LocationToElevationBulk::locationsToElevationsCompleted, this, &TerrainProfileProcessor::onLocationsToElevationsCompleted, Qt::UniqueConnection); TRACE_LOG(m_logger) << LOGFUNCTION << " END" << " m_initialized=" << m_initialized; return m_initialized; } bool TerrainProfileProcessor::start(const TerrainProfileParameter &terrainProfileParameter) { TRACE_LOG(m_logger) << LOGFUNCTION << " START" << " terrainProfileParameter=" << terrainProfileParameter << " m_srMap.wkid=" << m_srMap.wkid(); // don“t allow more than one at once: if (m_inProgress) return false; m_inProgress = true; m_terrainProfileParameter = terrainProfileParameter; removeUserInput(); displayUserInput(); // densify const Esri::ArcGISRuntime::Polyline &polylineOut_Map = densifiy(m_terrainProfileParameter); // calculate distance // bulk location to elevation const Esri::ArcGISRuntime::ImmutablePart &immutablePart = polylineOut_Map.parts().part(0); const int size = immutablePart.pointCount(); for (int i = 0; i < size; ++i) { const Esri::ArcGISRuntime::Point &esriMapLocation = immutablePart.point(i); // DEBUG_LOG(m_logger) << LOGFUNCTION << " esriMapLocation: " << QPointF(esriMapLocation.x(), esriMapLocation.y()); m_locationToElevationBulk.addLocation(esriMapLocation); } m_locationToElevationBulk.start(); TRACE_LOG(m_logger) << LOGFUNCTION << " END" << " m_viewshedInProgress=" << m_inProgress; return true; } QVector > TerrainProfileProcessor::results() const { return m_locationToElevationBulk.results(); } void TerrainProfileProcessor::setTerrainProfileDialog(QPointer &terrainProfileDialog) { TRACE_LOG(m_logger) << LOGFUNCTION << " START"; m_terrainProfileDialog = terrainProfileDialog; if (m_terrainProfileDialog) { m_terrainProfileDialog->setMap(m_mapImpl); // mousePositionChanged connect(m_terrainProfileDialog.data(), &TerrainProfileDialog::mousePositionChanged, this, &TerrainProfileProcessor::onDialogMousePositionChanged, Qt::UniqueConnection); // handle destruction of according dialog: connect(terrainProfileDialog.data(), &TerrainProfileDialog::destroyed, this, &TerrainProfileProcessor::deleteLater); } TRACE_LOG(m_logger) << LOGFUNCTION << " END"; } Esri::ArcGISRuntime::Polyline TerrainProfileProcessor::densifiy(TerrainProfileParameter &terrainProfileParameter) { TRACE_LOG(m_logger) << LOGFUNCTION << " START" << " terrainProfileParameter=" << terrainProfileParameter; // // PosCont to EsriPolyline: // Esri::ArcGISRuntime::PolylineBuilder polylineBuilder(m_srMap, this); for (const Point3D &coord : qAsConst(terrainProfileParameter.m_coordinates)) { // geo to map (polylineBuilder uses map also) const Point3D &p3D = m_mapImpl->coordTranslationFunctor()->geographicToMap(coord); polylineBuilder.addPoint(Esri::ArcGISRuntime::Point(p3D.x(), p3D.y(), p3D.z())); } const Esri::ArcGISRuntime::Polyline &polylineIn = polylineBuilder.toPolyline(); terrainProfileParameter.m_length = Esri::ArcGISRuntime::GeometryEngine::lengthGeodetic(polylineIn, Esri::ArcGISRuntime::LinearUnit::meters(), Esri::ArcGISRuntime::GeodeticCurveType::Geodesic); const int numberCoords = 50; double maxSegmenthLength = terrainProfileParameter.m_length / numberCoords; INFO_LOG(m_logger) << LOGFUNCTION << " START" << " lengthMeter=" << terrainProfileParameter.m_length << " numberCoords=" << numberCoords << " maxSegmenthLength=" << maxSegmenthLength; const Esri::ArcGISRuntime::Geometry &geometryOut = Esri::ArcGISRuntime::GeometryEngine::densifyGeodetic(polylineIn, maxSegmenthLength, Esri::ArcGISRuntime::LinearUnit::meters(), Esri::ArcGISRuntime::GeodeticCurveType::Geodesic); const Esri::ArcGISRuntime::Polyline polylineOut(geometryOut); TRACE_LOG(m_logger) << LOGFUNCTION << " START" << " lengthMeter=" << terrainProfileParameter.m_length << " numberCoords=" << numberCoords << " maxSegmenthLength=" << maxSegmenthLength << " polylineOut.parts().part(0).pointCount()=" << polylineOut.parts().part(0).pointCount(); return polylineOut; } void TerrainProfileProcessor::displayUserInput() { displayInputLine(); displayInputVertices(); } void TerrainProfileProcessor::removeUserInput() { removeInputLine(); removeInputVertices(); removeCurrentMarker(); } void TerrainProfileProcessor::displayInputLine() { // create if (!m_polyline) { m_polyline = m_mapImpl->objectFactory().create(m_toolsLayername, QStringLiteral("TerrainProfileLineId%1").arg(m_id)); m_polyline->setLineStyle(LineStyle(m_color, 3)); m_polyline->setScaleEnable(true); m_polyline->setPickable(false); } // apply data m_polyline->setPositions(m_terrainProfileParameter.m_coordinates); // update if (!m_polyline->updateView()) ERROR_LOG(m_logger) << LOGFUNCTION << " polyline::updateView failed"; } void TerrainProfileProcessor::removeInputLine() { if (m_polyline) m_polyline->removeMySelf(); m_polyline.reset(); } void TerrainProfileProcessor::displayInputVertices() { TRACE_LOG(m_logger) << LOGFUNCTION << " START"; PositionCont coordinates = m_terrainProfileParameter.m_coordinates; const int size = coordinates.size(); if (size < 1) return; m_markerCont.resize(size); int idx = 0; QMutableVectorIterator> it(m_markerCont); while (it.hasNext()) { RefPointer &marker = it.next(); if (!marker.valid()) { marker = m_mapImpl->objectFactory().create(m_toolsLayername, QStringLiteral("TerrainProfileLineId%1_idx%2").arg(m_id).arg(idx)); marker->setProxyMarker(MarkerSymbolType::Circle); marker->setProxyMarkerColor(m_color); marker->setProxyMarkerSize(7); marker->setPickable(false); } marker->setOrigin(coordinates[idx]); // update if (!marker->updateView()) ERROR_LOG(m_logger) << LOGFUNCTION << " marker::updateView failed"; ++idx; } // while TRACE_LOG(m_logger) << LOGFUNCTION << " END"; } void TerrainProfileProcessor::removeInputVertices() { QMutableVectorIterator> it(m_markerCont); while (it.hasNext()) { RefPointer &marker = it.next(); if (marker) marker->removeMySelf(); } m_markerCont.clear(); } void TerrainProfileProcessor::displayCurrentMarker(const Point3D &pointGeo) { // create if (!m_currentMarker) { m_currentMarker = m_mapImpl->objectFactory().create(m_toolsLayername, QStringLiteral("TerrainProfileLineId%1_currentMarker").arg(m_id)); m_currentMarker->setProxyMarker(MarkerSymbolType::Circle); m_currentMarker->setProxyMarkerColor(Qt::blue); m_currentMarker->setProxyMarkerSize(10); m_currentMarker->setPickable(false); } // apply data m_currentMarker->setOrigin(pointGeo); // update if (!m_currentMarker->updateView()) ERROR_LOG(m_logger) << LOGFUNCTION << " m_currentMarker::updateView failed"; } void TerrainProfileProcessor::removeCurrentMarker() { if (m_currentMarker) m_currentMarker->removeMySelf(); m_currentMarker.reset(); } void TerrainProfileProcessor::onLocationsToElevationsCompleted() { TRACE_LOG(m_logger) << LOGFUNCTION << " START" << " m_locationToElevationBulk.size()=" << m_locationToElevationBulk.size(); const QVector> &results = m_locationToElevationBulk.results(); if (m_logger.isDebugEnabled()) for (const QPair &item : qAsConst(results)) DEBUG_LOG(m_logger) << LOGFUNCTION << " location = " << item.first << " elevation = " << item.second; TRACE_LOG(m_logger) << LOGFUNCTION << " START" << " results.size()=" << results.size(); // The caller should set TerrainProfileDialog on this signal: emit locationsToElevationsCompleted(m_id); // maybe (better hopefully) the caller (via finishedCallback of TerrainProfileImpl) // has updated our m_terrainProfileParameter !?! if (m_terrainProfileDialog) { m_terrainProfileDialog->setData(this->results()); QVector marks; marks.reserve(m_terrainProfileParameter.m_coordinates.size()); for (const Point3D &coord : qAsConst(m_terrainProfileParameter.m_coordinates)) { // geo to map const Point3D &p3D = m_mapImpl->coordTranslationFunctor()->geographicToMap(coord); marks.append(p3D.toPointF()); } m_terrainProfileDialog->setMarks(marks); } else { ERROR_LOG(m_logger) << LOGFUNCTION << " no dialog"; } m_inProgress = false; } void TerrainProfileProcessor::onDialogMousePositionChanged(const QPointF &curPos) { const Point3D &curPosGeo = Point3D::fromQPointF( m_mapImpl->coordTranslationFunctor()->mapToGeographic(curPos) ); displayCurrentMarker(curPosGeo); } } // namespace SituationMap