diff --git a/native-apps/urban-heat-analyzer/UrbanHeatAnalyzer/Android/res/drawable-hdpi/icon.png b/native-apps/urban-heat-analyzer/UrbanHeatAnalyzer/Android/res/drawable-hdpi/icon.png new file mode 100644 index 0000000..ad4a8f1 Binary files /dev/null and b/native-apps/urban-heat-analyzer/UrbanHeatAnalyzer/Android/res/drawable-hdpi/icon.png differ diff --git a/native-apps/urban-heat-analyzer/UrbanHeatAnalyzer/Android/res/drawable-ldpi/icon.png b/native-apps/urban-heat-analyzer/UrbanHeatAnalyzer/Android/res/drawable-ldpi/icon.png new file mode 100644 index 0000000..5073d05 Binary files /dev/null and b/native-apps/urban-heat-analyzer/UrbanHeatAnalyzer/Android/res/drawable-ldpi/icon.png differ diff --git a/native-apps/urban-heat-analyzer/UrbanHeatAnalyzer/Android/res/drawable-mdpi/icon.png b/native-apps/urban-heat-analyzer/UrbanHeatAnalyzer/Android/res/drawable-mdpi/icon.png new file mode 100644 index 0000000..6b8144e Binary files /dev/null and b/native-apps/urban-heat-analyzer/UrbanHeatAnalyzer/Android/res/drawable-mdpi/icon.png differ diff --git a/native-apps/urban-heat-analyzer/UrbanHeatAnalyzer/Android/res/drawable-xhdpi/icon.png b/native-apps/urban-heat-analyzer/UrbanHeatAnalyzer/Android/res/drawable-xhdpi/icon.png new file mode 100644 index 0000000..591b4e0 Binary files /dev/null and b/native-apps/urban-heat-analyzer/UrbanHeatAnalyzer/Android/res/drawable-xhdpi/icon.png differ diff --git a/native-apps/urban-heat-analyzer/UrbanHeatAnalyzer/Android/res/drawable-xxhdpi/icon.png b/native-apps/urban-heat-analyzer/UrbanHeatAnalyzer/Android/res/drawable-xxhdpi/icon.png new file mode 100644 index 0000000..77eda0a Binary files /dev/null and b/native-apps/urban-heat-analyzer/UrbanHeatAnalyzer/Android/res/drawable-xxhdpi/icon.png differ diff --git a/native-apps/urban-heat-analyzer/UrbanHeatAnalyzer/CMakeLists.txt b/native-apps/urban-heat-analyzer/UrbanHeatAnalyzer/CMakeLists.txt new file mode 100644 index 0000000..c260613 --- /dev/null +++ b/native-apps/urban-heat-analyzer/UrbanHeatAnalyzer/CMakeLists.txt @@ -0,0 +1,126 @@ +#------------------------------------------------- +# Copyright 2024 ESRI +# +# All rights reserved under the copyright laws of the United States +# and applicable international laws, treaties, and conventions. +# +# You may freely redistribute and use this sample code, with or +# without modification, provided you include the original copyright +# notice and use restrictions. +# +# See the Sample code usage restrictions document for further information. +#------------------------------------------------- +cmake_minimum_required(VERSION 3.5) + +project(UrbanHeatAnalyzer LANGUAGES CXX) + +set(CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/cmake" ${CMAKE_MODULE_PATH}) + +set(CMAKE_INCLUDE_CURRENT_DIR ON) + +set(CMAKE_AUTOUIC OFF) +set(CMAKE_AUTOMOC ON) +set(CMAKE_AUTORCC ON) + +set(CMAKE_CXX_STANDARD 17) +set(CMAKE_CXX_STANDARD_REQUIRED ON) + +if(IOS) + set(CMAKE_BUILD_WITH_INSTALL_RPATH TRUE) + set(CMAKE_OSX_DEPLOYMENT_TARGET "16.0" CACHE STRING "Minimum iOS deployment version" FORCE) +elseif(APPLE) + set(CMAKE_OSX_DEPLOYMENT_TARGET "13.0" CACHE STRING "Minimum macOS deployment version" FORCE) +endif() + +find_package(Qt6 COMPONENTS REQUIRED Core Quick Multimedia Positioning Sensors WebSockets) +if (Qt6Core_VERSION VERSION_LESS 6.5.6) + message(FATAL_ERROR "This version of the ArcGIS Maps SDK for Qt requires at least Qt 6.5.6") +endif() +if(ANDROID OR IOS) + find_package(Qt6 COMPONENTS REQUIRED Bluetooth) +endif() +find_package(ArcGISRuntime 200.5.0 COMPONENTS REQUIRED Cpp) + +set(SOURCE_FILES + main.cpp + UrbanHeatAnalyzer.cpp + UrbanHeatAnalyzer.h + HeatRiskListModel.cpp + HeatRiskListModel.h + qml/qml.qrc + Resources/Resources.qrc + $<$:Win/Resources.rc> + $<$:Mac/AppIcon.icns>) + +if(ANDROID) + qt_add_executable(${PROJECT_NAME} ${SOURCE_FILES}) +else() + qt_add_executable(${PROJECT_NAME} MACOSX_BUNDLE ${SOURCE_FILES}) + # IOS uses static Runtimecore Framework + if(IOS) + set_target_properties(${PROJECT_NAME} PROPERTIES INSTALL_RPATH @executable_path/Frameworks + XCODE_EMBED_FRAMEWORKS ${ArcGISRuntime_runtimecore_LIB} + XCODE_EMBED_FRAMEWORKS_CODE_SIGN_ON_COPY TRUE) + endif() + # On MacOSX add icon to app bundle. + set(MACOSX_BUNDLE_ICON_FILE AppIcon.icns) + set_source_files_properties(Mac/AppIcon.icns + PROPERTIES MACOSX_PACKAGE_LOCATION "Resources") + + # Copy required dynamic libraries to the build folder as a post-build step. + if(DEFINED ArcGISRuntime_LIBRARIES) + add_custom_command(TARGET ${PROJECT_NAME} POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy_if_different + ${ArcGISRuntime_LIBRARIES} + $) + endif() +endif() + +target_compile_definitions(${PROJECT_NAME} + PRIVATE $<$,$>:QT_QML_DEBUG>) + +target_link_libraries(${PROJECT_NAME} PRIVATE + Qt6::Core + Qt6::Quick + Qt6::Multimedia + Qt6::Positioning + Qt6::Sensors + Qt6::WebSockets + ArcGISRuntime::Cpp) + +# To integrate the toolkit, copy the `toolkitcpp` subdirectory from the toolkit +# into your project's directory. Then uncomment the following lines to add it to your project. +# See https://github.com/Esri/arcgis-maps-sdk-toolkit-qt for details +# add_subdirectory(toolkitcpp) +# target_link_libraries(${PROJECT_NAME} PRIVATE libtoolkitcpp) + +if(ANDROID OR IOS) + target_link_libraries(${PROJECT_NAME} PRIVATE Qt6::Bluetooth) +endif() + +if(ANDROID) + target_link_libraries(${PROJECT_NAME} PRIVATE Qt::CorePrivate) + + set(PROJECT_DEPLOYABLE_LIBS + ${ArcGISRuntime_LIBRARIES}) + + list(JOIN PROJECT_DEPLOYABLE_LIBS , PROJECT_DEPLOYABLE_LIBS_STRING) + + # Setup openssl by cloning the repo https://github.com/KDAB/android_openssl More info at https://doc.qt.io/qt-6/android-openssl-support.html + # QtCreator can also be used to install openssl https://doc.qt.io/qtcreator/creator-developing-android.html#specifying-android-device-settings + # Uncomment line below and point to your openssl path. + + #include(/CMakeLists.txt) + + # QtCreator supports the following variables for Android, which are identical + # to qmake Android variables. + # Check http://doc.qt.io/qt-6/deployment-android.html for more information. + # Setting this property changed at Qt6 see doc below. + # https://doc.qt.io/qt-6/cmake-target-property-qt-android-extra-libs.html + + set_property(TARGET ${PROJECT_NAME} PROPERTY QT_ANDROID_EXTRA_LIBS ${PROJECT_DEPLOYABLE_LIBS_STRING} ${ANDROID_EXTRA_LIBS}) + get_property(EXTRA_LIBS TARGET ${PROJECT_NAME} PROPERTY QT_ANDROID_EXTRA_LIBS) + if(NOT EXTRA_LIBS MATCHES "libssl" OR NOT EXTRA_LIBS MATCHES "libcrypto") + message(WARNING "openssl libraries are missing, check the project CMakeLists.txt and set up openssl environment") + endif() +endif() diff --git a/native-apps/urban-heat-analyzer/UrbanHeatAnalyzer/HeatRiskListModel.cpp b/native-apps/urban-heat-analyzer/UrbanHeatAnalyzer/HeatRiskListModel.cpp new file mode 100644 index 0000000..2496495 --- /dev/null +++ b/native-apps/urban-heat-analyzer/UrbanHeatAnalyzer/HeatRiskListModel.cpp @@ -0,0 +1,89 @@ +// "Urban Heat Analyzer" +// Copyright (C) 2024 Esri Deutschland GmbH +// Jan Tschada (j.tschada@esri.de) +// +// SPDX-License-Identifier: GPL-3.0-only +// +// Additional permission under GNU GPL version 3 section 7 +// +// If you modify this Program, or any covered work, by linking or combining +// it with ArcGIS Maps SDK for Qt (or a modified version of that library), +// containing parts covered by the terms of ArcGIS Maps SDK for Qt, +// the licensors of this Program grant you additional permission to convey the resulting work. +// See for further information. + +#include "HeatRiskListModel.h" + +#include "AttributeListModel.h" +#include "Feature.h" + +using namespace Esri::ArcGISRuntime; + + +HeatRiskAnalysisGroup::HeatRiskAnalysisGroup(double heatRiskIndex) + : m_heatRiskIndex(heatRiskIndex) +{ + +} + +QString HeatRiskAnalysisGroup::name() const +{ + if (m_heatRiskFeatures.empty()) + { + return "Unknown"; + } + + auto heatRiskFeatureAttributes = m_heatRiskFeatures.first()->attributes(); + return heatRiskFeatureAttributes->attributeValue("GRID_ID").toString(); +} + +double HeatRiskAnalysisGroup::heatRiskIndex() const +{ + return m_heatRiskIndex; +} + +void HeatRiskAnalysisGroup::addFeature(Feature *heatRiskFeature) +{ + m_heatRiskFeatures.append(heatRiskFeature); +} + + +HeatRiskListModel::HeatRiskListModel(QObject *parent) + : QAbstractListModel{parent} +{ + +} + +void HeatRiskListModel::loadAnalysisGroups(const QList &analysisGroups) +{ + beginResetModel(); + m_analysisGroups = analysisGroups; + endResetModel(); + + // Emit that the full data has changed + emit dataChanged(index(0,0), index(rowCount() - 1)); +} + +int HeatRiskListModel::rowCount(const QModelIndex & parent) const { + Q_UNUSED(parent); + return m_analysisGroups.count(); +} + +QVariant HeatRiskListModel::data(const QModelIndex & index, int role) const { + if (index.row() < 0 || index.row() >= m_analysisGroups.count()) + return QVariant(); + + const HeatRiskAnalysisGroup &analysisGroup = m_analysisGroups[index.row()]; + if (role == NameRole) + return analysisGroup.name(); + else if (role == RiskRole) + return analysisGroup.heatRiskIndex(); + return QVariant(); +} + +QHash HeatRiskListModel::roleNames() const { + QHash roles; + roles[NameRole] = "name"; + roles[RiskRole] = "risk"; + return roles; +} diff --git a/native-apps/urban-heat-analyzer/UrbanHeatAnalyzer/HeatRiskListModel.h b/native-apps/urban-heat-analyzer/UrbanHeatAnalyzer/HeatRiskListModel.h new file mode 100644 index 0000000..b7f4b08 --- /dev/null +++ b/native-apps/urban-heat-analyzer/UrbanHeatAnalyzer/HeatRiskListModel.h @@ -0,0 +1,65 @@ +// "Urban Heat Analyzer" +// Copyright (C) 2024 Esri Deutschland GmbH +// Jan Tschada (j.tschada@esri.de) +// +// SPDX-License-Identifier: GPL-3.0-only +// +// Additional permission under GNU GPL version 3 section 7 +// +// If you modify this Program, or any covered work, by linking or combining +// it with ArcGIS Maps SDK for Qt (or a modified version of that library), +// containing parts covered by the terms of ArcGIS Maps SDK for Qt, +// the licensors of this Program grant you additional permission to convey the resulting work. +// See for further information. + +#ifndef HEATRISKLISTMODEL_H +#define HEATRISKLISTMODEL_H + +#include +#include + +namespace Esri::ArcGISRuntime { +class Feature; +} // namespace Esri::ArcGISRuntime + + +class HeatRiskAnalysisGroup +{ +public: + HeatRiskAnalysisGroup(double heatRiskIndex); + + QString name() const; + double heatRiskIndex() const; + + void addFeature(Esri::ArcGISRuntime::Feature *heatRiskFeature); + +private: + double m_heatRiskIndex; + QList m_heatRiskFeatures; +}; + + +class HeatRiskListModel : public QAbstractListModel +{ + Q_OBJECT +public: + enum HeatRiskRoles { + NameRole = Qt::UserRole + 1, + RiskRole + }; + + explicit HeatRiskListModel(QObject *parent = nullptr); + + void loadAnalysisGroups(const QList &analysisGroups); + + int rowCount(const QModelIndex & parent = QModelIndex()) const; + QVariant data(const QModelIndex & index, int role = Qt::DisplayRole) const; + +protected: + QHash roleNames() const; + +private: + QList m_analysisGroups; +}; + +#endif // HEATRISKLISTMODEL_H diff --git a/native-apps/urban-heat-analyzer/UrbanHeatAnalyzer/Mac/AppIcon.icns b/native-apps/urban-heat-analyzer/UrbanHeatAnalyzer/Mac/AppIcon.icns new file mode 100644 index 0000000..42e175a Binary files /dev/null and b/native-apps/urban-heat-analyzer/UrbanHeatAnalyzer/Mac/AppIcon.icns differ diff --git a/native-apps/urban-heat-analyzer/UrbanHeatAnalyzer/Resources/AppIcon.png b/native-apps/urban-heat-analyzer/UrbanHeatAnalyzer/Resources/AppIcon.png new file mode 100644 index 0000000..184bdd2 Binary files /dev/null and b/native-apps/urban-heat-analyzer/UrbanHeatAnalyzer/Resources/AppIcon.png differ diff --git a/native-apps/urban-heat-analyzer/UrbanHeatAnalyzer/Resources/Resources.qrc b/native-apps/urban-heat-analyzer/UrbanHeatAnalyzer/Resources/Resources.qrc new file mode 100644 index 0000000..b84cbba --- /dev/null +++ b/native-apps/urban-heat-analyzer/UrbanHeatAnalyzer/Resources/Resources.qrc @@ -0,0 +1,5 @@ + + + AppIcon.png + + diff --git a/native-apps/urban-heat-analyzer/UrbanHeatAnalyzer/UrbanHeatAnalyzer.cpp b/native-apps/urban-heat-analyzer/UrbanHeatAnalyzer/UrbanHeatAnalyzer.cpp new file mode 100644 index 0000000..8875524 --- /dev/null +++ b/native-apps/urban-heat-analyzer/UrbanHeatAnalyzer/UrbanHeatAnalyzer.cpp @@ -0,0 +1,225 @@ +// Copyright 2024 ESRI +// +// All rights reserved under the copyright laws of the United States +// and applicable international laws, treaties, and conventions. +// +// You may freely redistribute and use this sample code, with or +// without modification, provided you include the original copyright +// notice and use restrictions. +// +// See the Sample code usage restrictions document for further information. +// +// This "Urban Heat Analyzer" sample app is licensed as +// SPDX-License-Identifier: GPL-3.0-or-later +// +// Additional permission under GNU GPL version 3 section 4 and 5 +// If you modify this Program, or any covered work, by linking or combining +// it with ArcGIS Runtime for Qt (or a modified version of that library), +// containing parts covered by the terms of ArcGIS Runtime for Qt, +// the licensors of this Program grant you additional permission to convey the resulting work. +// See for further information. +// + +#include "HeatRiskListModel.h" +#include "UrbanHeatAnalyzer.h" + +#include "ArcGISSceneLayer.h" +#include "ArcGISTiledElevationSource.h" +#include "ArcGISVectorTiledLayer.h" +#include "AttributeListModel.h" +#include "Camera.h" +#include "CoreTypes.h" +#include "ElevationSourceListModel.h" +#include "Envelope.h" +#include "Feature.h" +#include "FeatureIterator.h" +#include "FeatureQueryResult.h" +#include "Geodatabase.h" +#include "GeodatabaseFeatureTable.h" +#include "LayerListModel.h" +#include "MapTypes.h" +#include "OrderBy.h" +#include "Point.h" +#include "QueryParameters.h" +#include "Scene.h" +#include "SceneQuickView.h" +#include "ServiceFeatureTable.h" +#include "SpatialReference.h" +#include "Surface.h" +#include "VectorTileCache.h" +#include "Viewpoint.h" + +#include +#include + +#include + +using namespace Esri::ArcGISRuntime; + +UrbanHeatAnalyzer::UrbanHeatAnalyzer(QObject *parent /* = nullptr */) + : QObject(parent) + , m_scene(new Scene(BasemapStyle::OsmStandard, this)) +{ + // create a new scene layer from OSM Buildings rest service + ArcGISSceneLayer *osmSceneLayer = new ArcGISSceneLayer( + QUrl("https://basemaps3d.arcgis.com/arcgis/rest/services/" + "OpenStreetMap3D_Buildings_v1/SceneServer"), + this); + osmSceneLayer->setOpacity(0.75f); + + // add the scene layer to the scene + m_scene->operationalLayers()->append(osmSceneLayer); + + // create a new elevation source from Terrain3D rest service + ArcGISTiledElevationSource *elevationSource = new ArcGISTiledElevationSource( + QUrl("https://elevation3d.arcgis.com/arcgis/rest/services/" + "WorldElevation3D/Terrain3D/ImageServer"), + this); + + // add the elevation source to the scene to display elevation + m_scene->baseSurface()->elevationSources()->append(elevationSource); + + // create a new vector tile cache from the exported vector tile package + VectorTileCache *tileCache = new VectorTileCache( + "/data/Germany/Bonn/heat_risk_index_bonn.vtpk", + this); + + // add the vector tile layer + ArcGISVectorTiledLayer *tiledLayer = new ArcGISVectorTiledLayer( + tileCache, + this); + tiledLayer->setOpacity(0.33f); + + connect(tiledLayer, &ArcGISVectorTiledLayer::doneLoading, this, [tiledLayer, this]() + { + //Envelope layerExtent = tiledLayer->fullExtent(); + //Viewpoint viewpoint = Viewpoint(layerExtent); + //m_sceneView->setViewpointAsync(viewpoint, 2.5); + //m_sceneView->currentViewpointCamera(); + //m_sceneView->setViewpointCameraAsync() + + // Set the viewpoint on a specific target + Point targetLocation(7.11661 , 50.718 , 343.663, SpatialReference(4326)); + Camera targetCamera(targetLocation, 93.2121 , 60.7764 , -5.68434e-14); + Viewpoint targetViewpoint(targetLocation, targetCamera); + if (m_sceneView) + { + m_sceneView->setViewpointAsync(targetViewpoint, 10); + } + + loadHeatRiskFeatures(); + }); + m_scene->operationalLayers()->append(tiledLayer); +} + +UrbanHeatAnalyzer::~UrbanHeatAnalyzer() {} + +SceneQuickView *UrbanHeatAnalyzer::sceneView() const +{ + return m_sceneView; +} + +// Set the view (created in QML) +void UrbanHeatAnalyzer::setSceneView(SceneQuickView *sceneView) +{ + if (!sceneView || sceneView == m_sceneView) + { + return; + } + + m_sceneView = sceneView; + m_sceneView->setArcGISScene(m_scene); + + emit sceneViewChanged(); +} + +void UrbanHeatAnalyzer::setHeatRiskListModel(HeatRiskListModel *heatRiskListModel) +{ + if (!heatRiskListModel) + { + return; + } + + m_heatRiskListModel = heatRiskListModel; +} + +void UrbanHeatAnalyzer::loadHeatRiskFeatures() +{ + // add the features + Geodatabase *gdb = new Geodatabase( + "/data/Germany/Bonn/HRI Bonn.geodatabase", + this); + connect(gdb, &Geodatabase::doneLoading, this, [gdb, this]() + { + GeodatabaseFeatureTable *featureTable = gdb->geodatabaseFeatureTable("HRI_Bonn"); + connect(featureTable, &GeodatabaseFeatureTable::doneLoading, this, [featureTable, this]() + { + qint64 featureCount = featureTable->numberOfFeatures(); + qDebug() << featureCount; + + // Execute the analysis + QueryParameters analysisParameters; + QList orderByFields; + orderByFields.append(OrderBy("HRI", SortOrder::Descending)); + analysisParameters.setOrderByFields(orderByFields); + analysisParameters.setWhereClause("HRI > 9"); + featureTable->queryFeaturesAsync(analysisParameters, this) + .then(this, [this](FeatureQueryResult *rawQueryResult) + { + // Reference raw pointer + auto queryResult = std::unique_ptr(rawQueryResult); + if (queryResult && !queryResult->iterator().hasNext()) + { + // No results or invalid pointer + return; + } + + QList analysisGroups; + HeatRiskAnalysisGroup *currentGroup = nullptr; + + // iterate over the result object + double lastValue = 9999; + while (queryResult->iterator().hasNext()) + { + Feature *feature = queryResult->iterator().next(this); + + // add every feature to the results view + double heatRiskIndexValue = round(feature->attributes()->attributeValue("HRI").toDouble()); + if (lastValue == heatRiskIndexValue) + { + // add to the last group + if (currentGroup) + { + currentGroup->addFeature(feature); + } + } + else if (heatRiskIndexValue < lastValue) + { + // create a new group + HeatRiskAnalysisGroup newGroup(heatRiskIndexValue); + newGroup.addFeature(feature); + analysisGroups.append(newGroup); + currentGroup = &analysisGroups.last(); + } + lastValue = heatRiskIndexValue; + } + + // Load the features into the model + if (m_heatRiskListModel) + { + m_heatRiskListModel->loadAnalysisGroups(analysisGroups); + } + }); + }); + featureTable->load(); + }); + gdb->load(); +} + +void UrbanHeatAnalyzer::printCamera() +{ + auto camera = m_sceneView->currentViewpointCamera(); + auto location = camera.location(); + qDebug() << location.x() << "," << location.y() << "," << location.z(); + qDebug() << camera.heading() << "," << camera.pitch() << "," << camera.roll(); +} diff --git a/native-apps/urban-heat-analyzer/UrbanHeatAnalyzer/UrbanHeatAnalyzer.h b/native-apps/urban-heat-analyzer/UrbanHeatAnalyzer/UrbanHeatAnalyzer.h new file mode 100644 index 0000000..27cd4db --- /dev/null +++ b/native-apps/urban-heat-analyzer/UrbanHeatAnalyzer/UrbanHeatAnalyzer.h @@ -0,0 +1,70 @@ +// Copyright 2024 ESRI +// +// All rights reserved under the copyright laws of the United States +// and applicable international laws, treaties, and conventions. +// +// You may freely redistribute and use this sample code, with or +// without modification, provided you include the original copyright +// notice and use restrictions. +// +// See the Sample code usage restrictions document for further information. +// +// This "Urban Heat Analyzer" sample app is licensed as +// SPDX-License-Identifier: GPL-3.0-or-later +// +// Additional permission under GNU GPL version 3 section 4 and 5 +// If you modify this Program, or any covered work, by linking or combining +// it with ArcGIS Runtime for Qt (or a modified version of that library), +// containing parts covered by the terms of ArcGIS Runtime for Qt, +// the licensors of this Program grant you additional permission to convey the resulting work. +// See for further information. +// + +#ifndef URBANHEATANALYZER_H +#define URBANHEATANALYZER_H + +class HeatRiskListModel; + +namespace Esri::ArcGISRuntime { +class Scene; +class SceneQuickView; +} // namespace Esri::ArcGISRuntime + +#include + +Q_MOC_INCLUDE("SceneQuickView.h") + + +class UrbanHeatAnalyzer : public QObject +{ + Q_OBJECT + + Q_PROPERTY(Esri::ArcGISRuntime::SceneQuickView *sceneView + READ sceneView WRITE setSceneView + NOTIFY sceneViewChanged) + Q_PROPERTY(HeatRiskListModel *heatRiskListModel + WRITE setHeatRiskListModel) + +public: + explicit UrbanHeatAnalyzer(QObject *parent = nullptr); + ~UrbanHeatAnalyzer() override; + + Q_INVOKABLE void printCamera(); + +signals: + void sceneViewChanged(); + +private: + void loadHeatRiskFeatures(); + + Esri::ArcGISRuntime::SceneQuickView *sceneView() const; + void setSceneView(Esri::ArcGISRuntime::SceneQuickView *sceneView); + + void setHeatRiskListModel(HeatRiskListModel *heatRiskListModel); + + Esri::ArcGISRuntime::Scene *m_scene = nullptr; + Esri::ArcGISRuntime::SceneQuickView *m_sceneView = nullptr; + HeatRiskListModel *m_heatRiskListModel = nullptr; +}; + +#endif // URBANHEATANALYZER_H diff --git a/native-apps/urban-heat-analyzer/UrbanHeatAnalyzer/Win/AppIcon.ico b/native-apps/urban-heat-analyzer/UrbanHeatAnalyzer/Win/AppIcon.ico new file mode 100644 index 0000000..095a36f Binary files /dev/null and b/native-apps/urban-heat-analyzer/UrbanHeatAnalyzer/Win/AppIcon.ico differ diff --git a/native-apps/urban-heat-analyzer/UrbanHeatAnalyzer/Win/Resources.rc b/native-apps/urban-heat-analyzer/UrbanHeatAnalyzer/Win/Resources.rc new file mode 100644 index 0000000..d081914 --- /dev/null +++ b/native-apps/urban-heat-analyzer/UrbanHeatAnalyzer/Win/Resources.rc @@ -0,0 +1 @@ +IDI_ICON1 ICON DISCARDABLE "AppIcon.ico" diff --git a/native-apps/urban-heat-analyzer/UrbanHeatAnalyzer/cmake/FindArcGISRuntime.cmake b/native-apps/urban-heat-analyzer/UrbanHeatAnalyzer/cmake/FindArcGISRuntime.cmake new file mode 100644 index 0000000..c6adbef --- /dev/null +++ b/native-apps/urban-heat-analyzer/UrbanHeatAnalyzer/cmake/FindArcGISRuntime.cmake @@ -0,0 +1,62 @@ +#------------------------------------------------- +# Copyright 2024 ESRI +# +# All rights reserved under the copyright laws of the United States +# and applicable international laws, treaties, and conventions. +# +# You may freely redistribute and use this sample code, with or +# without modification, provided you include the original copyright +# notice and use restrictions. +# +# See the Sample code usage restrictions document for further information. +#------------------------------------------------- +#[================================================[.rst + +Find the native ArcGISRuntime includes and libraries. + +Hints +^^^^^ + +A user may set ``ArcGISRuntime_ROOT`` to override the default search path. +See "ArcGISRuntime.cmake" for additional information. + +#]================================================] + +function(GET_INSTALL_DIR OUT_VAR DESC_VAR) + # Discover the INI file with an install location (if it exists). + set(VER_MAJ_MIN ${ArcGISRuntime_FIND_VERSION_MAJOR}.${ArcGISRuntime_FIND_VERSION_MINOR}.${ArcGISRuntime_FIND_VERSION_PATCH} CACHE STRING "Major Minor version ArcGISRuntime" FORCE) + if(${CMAKE_HOST_SYSTEM_NAME} STREQUAL Windows) + set(INI_PATH $ENV{ALLUSERSPROFILE}/EsriRuntimeQt/ArcGIS\ Runtime\ SDK\ for\ Qt\ ${VER_MAJ_MIN}.ini) + else() + set(INI_PATH $ENV{HOME}/.config/EsriRuntimeQt/ArcGIS\ Runtime\ SDK\ for\ Qt\ ${VER_MAJ_MIN}.ini) + endif() + + # If there is an INI path we attempt to extract the install location from it. + if(EXISTS ${INI_PATH}) + message("Found configuration file at " ${INI_PATH}) + # Finds the `InstallDir="/path/to/arcgis"` string and extracts the path. + file(STRINGS ${INI_PATH} INSTALL_INI REGEX InstallDir=) + string(REGEX REPLACE "^InstallDir=\"(.*)\"$" "\\1" INSTALL_DIR ${INSTALL_INI}) # " + if(INSTALL_DIR) + message("Found ArcGISRuntime installation at ${INSTALL_DIR}") + set(${OUT_VAR} "${INSTALL_DIR}" CACHE STRING ${DESC_VAR}) + else() + message("Missing ArcGIS Runtime install location in configuration file.") + endif() + endif() +endfunction() + +message("") + +get_install_dir(ArcGISRuntime_INSTALL_DIR "Install directory of ArcGISRuntime") + +set(RUNTIME_CMAKE_PATH + "${ArcGISRuntime_INSTALL_DIR}/sdk/ideintegration/ArcGISRuntime.cmake") + +if(EXISTS "${RUNTIME_CMAKE_PATH}") + include("${RUNTIME_CMAKE_PATH}") +else() + message(FATAL_ERROR "module ${RUNTIME_CMAKE_PATH} does not exist.") +endif() + +message("") diff --git a/native-apps/urban-heat-analyzer/UrbanHeatAnalyzer/main.cpp b/native-apps/urban-heat-analyzer/UrbanHeatAnalyzer/main.cpp new file mode 100644 index 0000000..46c8544 --- /dev/null +++ b/native-apps/urban-heat-analyzer/UrbanHeatAnalyzer/main.cpp @@ -0,0 +1,110 @@ +// Copyright 2024 ESRI +// +// All rights reserved under the copyright laws of the United States +// and applicable international laws, treaties, and conventions. +// +// You may freely redistribute and use this sample code, with or +// without modification, provided you include the original copyright +// notice and use restrictions. +// +// See the Sample code usage restrictions document for further information. +// +// This "Urban Heat Analyzer" sample app is licensed as +// SPDX-License-Identifier: GPL-3.0-or-later +// +// Additional permission under GNU GPL version 3 section 4 and 5 +// If you modify this Program, or any covered work, by linking or combining +// it with ArcGIS Runtime for Qt (or a modified version of that library), +// containing parts covered by the terms of ArcGIS Runtime for Qt, +// the licensors of this Program grant you additional permission to convey the resulting work. +// See for further information. +// + +#include "HeatRiskListModel.h" +#include "UrbanHeatAnalyzer.h" + +#include "ArcGISRuntimeEnvironment.h" +#include "SceneQuickView.h" + +#include +#include +#include +#include +#include + +//------------------------------------------------------------------------------ + +using namespace Esri::ArcGISRuntime; + +int main(int argc, char *argv[]) +{ +#if defined(Q_OS_LINUX) && !defined(Q_OS_ANDROID) + // Linux requires 3.2 OpenGL Context + // in order to instance 3D symbols + QSurfaceFormat fmt = QSurfaceFormat::defaultFormat(); + fmt.setVersion(3, 2); + QSurfaceFormat::setDefaultFormat(fmt); +#endif + + QGuiApplication app(argc, argv); + + // Use of ArcGIS location services, such as basemap styles, geocoding, and routing services, + // requires an access token. For more information see + // https://links.esri.com/arcgis-runtime-security-auth. + + // The following methods grant an access token: + + // 1. User authentication: Grants a temporary access token associated with a user's ArcGIS account. + // To generate a token, a user logs in to the app with an ArcGIS account that is part of an + // organization in ArcGIS Online or ArcGIS Enterprise. + + // 2. API key authentication: Get a long-lived access token that gives your application access to + // ArcGIS location services. Go to the tutorial at https://links.esri.com/create-an-api-key. + // Copy the API Key access token. + QString accessToken; + QString apiKeyName = "ARCGIS_API_KEY"; + QProcessEnvironment systemEnvironment = QProcessEnvironment::systemEnvironment(); + if (systemEnvironment.contains(apiKeyName)) + { + accessToken = systemEnvironment.value(apiKeyName); + } + + if (accessToken.isEmpty()) + { + qWarning() + << "Use of ArcGIS location services, such as the basemap styles service, requires" + << "you to authenticate with an ArcGIS account or set the API Key property."; + } + else + { + ArcGISRuntimeEnvironment::setApiKey(accessToken); + } + + // Production deployment of applications built with ArcGIS Maps SDK requires you to + // license ArcGIS Maps SDK functionality. For more information see + // https://links.esri.com/arcgis-runtime-license-and-deploy. + + // ArcGISRuntimeEnvironment::setLicense("Place license string in here"); + + // Register the scene view for QML + qmlRegisterType("Esri.UrbanHeatAnalyzer", 1, 0, "SceneView"); + + // Register the UrbanHeatAnalyzer (QQuickItem) for QML + qmlRegisterType("Esri.UrbanHeatAnalyzer", 1, 0, "UrbanHeatAnalyzer"); + + // Register the HeatRiskListModel for QML + qmlRegisterType("Esri.UrbanHeatAnalyzer", 1, 0, "HeatRiskListModel"); + + // Initialize application view + QQmlApplicationEngine engine; + + // Add the import Path + engine.addImportPath(QDir(QCoreApplication::applicationDirPath()).filePath("qml")); + + // Set the source + engine.load(QUrl("qrc:/qml/main.qml")); + + return app.exec(); +} + +//------------------------------------------------------------------------------ diff --git a/native-apps/urban-heat-analyzer/UrbanHeatAnalyzer/qml/UrbanHeatAnalyzerForm.qml b/native-apps/urban-heat-analyzer/UrbanHeatAnalyzer/qml/UrbanHeatAnalyzerForm.qml new file mode 100644 index 0000000..0ab2aff --- /dev/null +++ b/native-apps/urban-heat-analyzer/UrbanHeatAnalyzer/qml/UrbanHeatAnalyzerForm.qml @@ -0,0 +1,53 @@ +// Copyright 2024 ESRI +// +// All rights reserved under the copyright laws of the United States +// and applicable international laws, treaties, and conventions. +// +// You may freely redistribute and use this sample code, with or +// without modification, provided you include the original copyright +// notice and use restrictions. +// +// See the Sample code usage restrictions document for further information. +// +// This "Urban Heat Analyzer" sample app is licensed as +// SPDX-License-Identifier: GPL-3.0-or-later +// +// Additional permission under GNU GPL version 3 section 4 and 5 +// If you modify this Program, or any covered work, by linking or combining +// it with ArcGIS Runtime for Qt (or a modified version of that library), +// containing parts covered by the terms of ArcGIS Runtime for Qt, +// the licensors of this Program grant you additional permission to convey the resulting work. +// See for further information. +// + +import QtQuick +import QtQuick.Controls +import Esri.UrbanHeatAnalyzer + +Item { + + // Define a property for HeatRiskListModel + property HeatRiskListModel heatRiskListModel: riskModel + + function printCamera() { + model.printCamera(); + } + + // Create HeatRiskListModel here + HeatRiskListModel { + id: riskModel + } + + // Create SceneQuickView here, and create its Scene etc. in C++ code + SceneView { + id: view + anchors.fill: parent + } + + // Declare the C++ instance which creates the scene etc. and supply the view + UrbanHeatAnalyzer { + id: model + sceneView: view + heatRiskListModel: riskModel + } +} diff --git a/native-apps/urban-heat-analyzer/UrbanHeatAnalyzer/qml/main.qml b/native-apps/urban-heat-analyzer/UrbanHeatAnalyzer/qml/main.qml new file mode 100644 index 0000000..8889cb4 --- /dev/null +++ b/native-apps/urban-heat-analyzer/UrbanHeatAnalyzer/qml/main.qml @@ -0,0 +1,121 @@ +// Copyright 2024 ESRI +// +// All rights reserved under the copyright laws of the United States +// and applicable international laws, treaties, and conventions. +// +// You may freely redistribute and use this sample code, with or +// without modification, provided you include the original copyright +// notice and use restrictions. +// +// See the Sample code usage restrictions document for further information. +// +// This "Urban Heat Analyzer" sample app is licensed as +// SPDX-License-Identifier: GPL-3.0-or-later +// +// Additional permission under GNU GPL version 3 section 4 and 5 +// If you modify this Program, or any covered work, by linking or combining +// it with ArcGIS Runtime for Qt (or a modified version of that library), +// containing parts covered by the terms of ArcGIS Runtime for Qt, +// the licensors of this Program grant you additional permission to convey the resulting work. +// See for further information. +// + +import QtQuick +import QtQuick.Controls +import QtQuick.Controls.Material +import QtQuick.Layouts + +import Esri.UrbanHeatAnalyzer + +ApplicationWindow { + visible: true + width: 800 + height: 600 + + Material.theme: Material.Dark + Material.accent: "#C9F2FF" + Material.background: "#0289C3" + Material.foreground: "#FFFFFF" + Material.primary: "#035799" + + font.pixelSize: 14 + + header: ToolBar { + id: toolbar + + RowLayout { + anchors.fill: parent + + Rectangle { + Layout.fillWidth: true + Layout.fillHeight: true + color: Material.background + + Component { + id: riskDelegate + + Item { + width: 200 + height: toolbar.height + + ColumnLayout { + anchors.verticalCenter: parent.verticalCenter + + Text { + Layout.alignment: Qt.AlignLeft + Layout.leftMargin: 10 + color: Material.foreground + text: "Name:" + name + } + Text { + Layout.alignment: Qt.AlignLeft + Layout.leftMargin: 10 + color: Material.foreground + text: "Risk:" + risk + } + } + + MouseArea { + anchors.fill: parent + onClicked: { + riskView.currentIndex = index; + console.log(name); + } + } + } + } + + ListView { + id: riskView + anchors.fill: parent + orientation: Qt.Horizontal + + model: mapForm.heatRiskListModel + delegate: riskDelegate + highlight: Rectangle { color: Material.primary; radius: 5 } + focus: false + } + } + } + } + + footer: ToolBar { + + RowLayout { + anchors.fill: parent + + Label { + id: messageLabel + horizontalAlignment: Qt.AlignLeft + Layout.leftMargin: 15 + Layout.fillWidth: true + text: qsTr("Analyzing urban heat risks...") + } + } + } + + UrbanHeatAnalyzerForm { + id: mapForm + anchors.fill: parent + } +} diff --git a/native-apps/urban-heat-analyzer/UrbanHeatAnalyzer/qml/qml.qrc b/native-apps/urban-heat-analyzer/UrbanHeatAnalyzer/qml/qml.qrc new file mode 100644 index 0000000..3d7bc4d --- /dev/null +++ b/native-apps/urban-heat-analyzer/UrbanHeatAnalyzer/qml/qml.qrc @@ -0,0 +1,6 @@ + + + main.qml + UrbanHeatAnalyzerForm.qml + + diff --git a/spatial-data-science/scripts/Heat Risk Index.pyt b/spatial-data-science/scripts/Heat Risk Index.pyt index dfa0013..ee87c89 100644 --- a/spatial-data-science/scripts/Heat Risk Index.pyt +++ b/spatial-data-science/scripts/Heat Risk Index.pyt @@ -1,7 +1,8 @@ # -*- coding: utf-8 -*- import arcpy -from heat_risk_index import initialize_arcpy +from arcgis.geometry import Envelope +from heatri import calculate_heat_risk_index_using_extent class Toolbox: @@ -19,13 +20,28 @@ class HRITool: def __init__(self): """Define the tool (tool name is the name of the class).""" self.label = "HRI" - self.description = "" - initialize_arcpy() + self.description = "Calculates the heat risk index of an urban region." def getParameterInfo(self): """Define the tool parameters.""" - params = None + params = [ + # Extent parameter + arcpy.Parameter( + displayName="Input envelope", + name="in_envelope", + datatype="GPEnvelope", + parameterType="Required", + direction="Input"), + + # Derived output spatial bins + arcpy.Parameter( + displayName="Output features", + name="out_features", + datatype="GPFeatureLayer", + parameterType="Derived", + direction="Output") + ] return params def isLicensed(self): @@ -45,7 +61,22 @@ class HRITool: def execute(self, parameters, messages): """The source code of the tool.""" - return + envelope = parameters[0].value + + # Get current map spatial reference + focus_map = arcpy.mp.ArcGISProject("current").activeMap + map_sr = focus_map.spatialReference + envelope_of_interest = Envelope({ + "xmin": envelope.XMin, + "ymin": envelope.YMin, + "xmax": envelope.XMax, + "ymax": envelope.YMax, + "spatialReference": { + "wkid": map_sr.factoryCode + } + }) + heat_risk_index_features = calculate_heat_risk_index_using_extent(envelope_of_interest) + parameters[1].value = heat_risk_index_features def postExecute(self, parameters): """This method takes place after outputs are processed and diff --git a/spatial-data-science/scripts/Heat Risk Index.pyt.xml b/spatial-data-science/scripts/Heat Risk Index.pyt.xml index 4794642..eee553c 100644 --- a/spatial-data-science/scripts/Heat Risk Index.pyt.xml +++ b/spatial-data-science/scripts/Heat Risk Index.pyt.xml @@ -1,2 +1,2 @@ -20240918145913001.0TRUE20240918150839c:\program files\arcgis\pro\Resources\Help\gpHeat Risk IndexArcToolbox Toolbox +20240918145913001.0TRUE20241121135037c:\program files\arcgis\pro\Resources\Help\gpHeat Risk IndexArcToolbox Toolbox