/****************************************************************************/1// Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo2// Copyright (C) 2011-2025 German Aerospace Center (DLR) and others.3// This program and the accompanying materials are made available under the4// terms of the Eclipse Public License 2.0 which is available at5// https://www.eclipse.org/legal/epl-2.0/6// This Source Code may also be made available under the following Secondary7// Licenses when the conditions for such availability set forth in the Eclipse8// Public License 2.0 are satisfied: GNU General Public License, version 29// or later which is available at10// https://www.gnu.org/licenses/old-licenses/gpl-2.0-standalone.html11// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-or-later12/****************************************************************************/13/// @file NBHeightMapper.h14/// @author Jakob Erdmann15/// @author Laura Bieker16/// @author Michael Behrisch17/// @date Sept 201118///19// Set z-values for all network positions based on data from a height map20/****************************************************************************/21#pragma once22#include <config.h>2324#ifdef WIN3225typedef __int16 int16_t;26#else27#include <stdint.h>28#endif2930#include <string>31#include <foreign/rtree/RTree.h>32#include <utils/geom/PositionVector.h>33#include <utils/geom/Boundary.h>34#include <utils/common/UtilExceptions.h>3536#define TRIANGLE_RTREE_QUAL RTree<NBHeightMapper::Triangle*, NBHeightMapper::Triangle, float, 2, NBHeightMapper::QueryResult>3738// ===========================================================================39// class declarations40// ===========================================================================41class OptionsCont;424344// ===========================================================================45// class definitions46// ===========================================================================47/**48* @class NBHeightMapper49* @brief Set z-values for all network positions based on data from a height map50*51* Importing data from '.shp'-files works only if SUMO was compiled with GDAL-support.52* If not, an error message is generated.53*/54class NBHeightMapper {5556friend class NBHeightMapperTest;5758public:59/** @brief loads height map data if any loading options are set60*61* @param[in] oc The options container to get further options from62* @exception ProcessError if something fails63*/64static void loadIfSet(OptionsCont& oc);6566/// @brief return the singleton instance (maybe 0)67static const NBHeightMapper& get();6869/// @brief returns whether the NBHeightMapper has data70bool ready() const;7172/// @brief returns the convex boundary of all known triangles73const Boundary& getBoundary() {74return myInstance.myBoundary;75}7677/// @brief returns height for the given geo coordinate (WGS84)78double getZ(const Position& geo) const;7980class QueryResult;81/* @brief content class for the rtree. Since we wish to be able to use the82* rtree for spatial querying we have to jump through some minor hoops:83* We let each found triangle callback the NBHeightMapper and add itself the84* the query result85* */86class Triangle {8788public:89Triangle(const PositionVector& corners);90~Triangle() {};9192/// @brief callback for RTree search93void addSelf(const QueryResult& queryResult) const;9495/// @brief checks whether pos lies within triangle (only checks x,y)96bool contains(const Position& pos) const;9798/// @brief returns the projection of the give geoCoordinate (WGS84) onto triangle plane99double getZ(const Position& geo) const;100101/// @brief returns the normal vector for this triangles plane102Position normalVector() const;103104/// @brief the corners of the triangle105PositionVector myCorners;106107};108109typedef std::vector<const Triangle*> Triangles;110111/// @brief class for cirumventing the const-restriction of RTree::Search-context112class QueryResult {113public:114QueryResult() {};115~QueryResult() {};116// @brief method not realy const117void add(Triangle* triangle) const {118triangles.push_back(triangle);119};120mutable Triangles triangles;121};122123private:124125struct RasterData {126int16_t* raster;127Boundary boundary;128int xSize;129int ySize;130};131132/// @brief the singleton instance133static NBHeightMapper myInstance;134135Triangles myTriangles;136137/// @brief The RTree for spatial queries138TRIANGLE_RTREE_QUAL myRTree;139140/// @brief raster height information in m for all loaded files141std::vector<RasterData> myRasters;142143/// @brief dimensions of one pixel in raster data144Position mySizeOfPixel;145146/// @brief convex boundary of all known triangles;147Boundary myBoundary;148149private:150/// @brief private constructor and destructor (Singleton)151NBHeightMapper();152~NBHeightMapper();153154/// @brief adds one triangles worth of height data155void addTriangle(PositionVector corners);156157/** @brief load height data from Arcgis-shape file and returns the number of parsed features158* @return The number of parsed features159* @throws ProcessError160*/161int loadShapeFile(const std::string& file);162163/** @brief load height data from GeoTIFF file and returns the number of non void pixels164* @return The number of valid pixels165* @throws ProcessError166*/167int loadTiff(const std::string& file);168169/// @brief clears loaded data170void clearData();171172/// @brief Invalidated copy constructor.173NBHeightMapper(const NBHeightMapper&);174175/// @brief Invalidated assignment operator.176NBHeightMapper& operator=(const NBHeightMapper&);177178};179180181// ===========================================================================182// RTree specialization for speedup and avoiding warnings (ripped from SUMORTree.h)183// ===========================================================================184template<>185inline float TRIANGLE_RTREE_QUAL::RectSphericalVolume(Rect* a_rect) {186ASSERT(a_rect);187const float extent0 = a_rect->m_max[0] - a_rect->m_min[0];188const float extent1 = a_rect->m_max[1] - a_rect->m_min[1];189return .78539816f * (extent0 * extent0 + extent1 * extent1);190}191192template<>193inline TRIANGLE_RTREE_QUAL::Rect TRIANGLE_RTREE_QUAL::CombineRect(Rect* a_rectA, Rect* a_rectB) {194ASSERT(a_rectA && a_rectB);195Rect newRect;196newRect.m_min[0] = rtree_min(a_rectA->m_min[0], a_rectB->m_min[0]);197newRect.m_max[0] = rtree_max(a_rectA->m_max[0], a_rectB->m_max[0]);198newRect.m_min[1] = rtree_min(a_rectA->m_min[1], a_rectB->m_min[1]);199newRect.m_max[1] = rtree_max(a_rectA->m_max[1], a_rectB->m_max[1]);200return newRect;201}202203204