#pragma once #include #include #include #include #include constexpr auto DOUBLE_MAX = std::numeric_limits::max(); constexpr auto DOUBLE_MIN = std::numeric_limits::min(); constexpr auto EARTH_EQUATOR_RADIUS = 6378137.0; // 赤道半径 m constexpr auto EARTH_POLAR_RADIUS = 6356725.0; // 极半径 m // template::value, bool>::type = true> bool equal(const Integer& val1, const Integer& val2, const Integer& eps = 0) { return val1 == val2; } template::value, bool>::type = true> bool equal(const Floating& val1, const Floating& val2, const Floating& eps = std::numeric_limits::min()) { return std::abs(val1 - val2) < eps; } template struct PointT { T x; T y; T z; PointT() { x = std::numeric_limits::infinity(); y = std::numeric_limits::infinity(); z = std::numeric_limits::infinity(); } PointT(const T& _x, const T& _y, const T& _z = std::numeric_limits::infinity()) { x = _x; y = _y; z = _z; } template PointT cast() const { return PointT(static_cast(x), static_cast(y), static_cast(z)); } bool operator==(const PointT& other) const { if (is3D()) return equal(this->x, other.x) && equal(this->y, other.y) && equal(this->z, other.z); else return equal(this->x, other.x) && equal(this->y, other.y); } T distance(const PointT& other) const { return std::hypot(this->x - other.x, this->y - other.y); } bool is3D() const { return !(std::isinf(z) || std::isnan(z)); } bool isValid() const { return !std::isinf(x) && !std::isinf(y); } }; using PointD = PointT; template struct RectT { T minX; T maxX; T minY; T maxY; T minZ; T maxZ; RectT() { minX = minY = minZ = std::numeric_limits::infinity(); maxX = maxY = maxZ = -std::numeric_limits::infinity(); } RectT(const T& minx, const T& maxx, const T& miny, const T& maxy, const T& minz = std::numeric_limits::infinity(), const T& maxz = -std::numeric_limits::infinity()) { minX = minx; maxX = maxx; minY = miny; maxY = maxy; minZ = minz; maxZ = maxz; } template RectT cast() const { return RectT(static_cast(minX), static_cast(maxX), static_cast(minY), static_cast(maxY), static_cast(minZ), static_cast(maxZ)); } bool isInvalid() const { return this->minX >= this->maxX || this->minY >= this->maxY; } bool is3D() const { return !std::isinf(minZ) && !std::isinf(maxZ); } bool operator==(const RectT& other) const { if (is3D() && other.is3D()) return equal(this->minX, other.minX) && equal(this->minY, other.minY) && equal(this->minX, other.minX) && equal(this->maxY, other.maxY) && equal(this->minZ, other.minZ) && equal(this->maxZ, other.maxZ); else return equal(this->minX, other.minX) && equal(this->minY, other.minY) && equal(this->minX, other.minX) && equal(this->maxY, other.maxY); } bool contain(const PointT& pt) const { return pt.x <= this->maxX && pt.x >= this->minX && pt.y <= this->maxY && pt.y >= this->minY; } bool contain(const RectT& other) const { return this->minX < other.minX && this->minY <= other.minY && this->maxX >= other.maxX && this->maxY >= other.maxY; } bool intersection(const RectT& other) const { return std::max(this->minX, other.minX) <= std::min(this->maxX, other.maxX) && std::max(this->minY, other.minY) <= std::min(this->maxY, other.maxY); } bool contain3d(const PointT& pt) const { return pt.x <= this->maxX && pt.x >= this->minX && pt.y <= this->maxY && pt.y >= this->minY && pt.z <= this->maxZ && pt.z >= this->minZ; } bool contain3d(const RectT& other) const { return this->minX < other.minX && this->minY <= other.minY && this->maxX >= other.maxX && this->maxY >= other.maxY && this->minZ < other.minZ && this->maxZ >= other.maxZ; } void clip(const RectT& other) { this->minX = std::max(this->minX, other.minX); this->minY = std::max(this->minY, other.minY); this->minZ = std::max(this->minZ, other.minZ); this->maxX = std::min(this->maxX, other.maxX); this->maxY = std::min(this->maxY, other.maxY); this->maxZ = std::min(this->maxZ, other.maxZ); } void combine(const RectT& other) { this->minX = std::min(this->minX, other.minX); this->minY = std::min(this->minY, other.minY); this->minZ = std::min(this->minZ, other.minZ); this->maxX = std::max(this->maxX, other.maxX); this->maxY = std::max(this->maxY, other.maxY); this->maxZ = std::max(this->maxZ, other.maxZ); } void combine(const PointT& other) { this->minX = std::min(this->minX, other.x); this->minY = std::min(this->minY, other.y); this->minZ = std::min(this->minZ, other.z); this->maxX = std::max(this->maxX, other.x); this->maxY = std::max(this->maxY, other.y); this->maxZ = std::max(this->maxZ, other.z); } void expand(const T& dis) { this->minX -= dis; this->maxX += dis; this->minY -= dis; this->maxY += dis; } }; using RectD = RectT; namespace nds { // intN转换为int32,主要注意负数情况下前面的符号位 #define INT_N_2_INT32(v, n) (((v) << (32 - (n))) >> (32 - (n))) // Navinfo mesh id // see "tile id" in NDS specification or "Mesh" in Navinfo HAD mifg specification using MeshId = std::uint32_t; // NDS level id, see NDS specification using LevelId = std::uint32_t; // NDS grid id, see NDS specification using NdsGridId = std::uint32_t; // In NDS, a coordinate unit corresponds to 360°/(2^32) degrees of longitude or latitude. // Longitudes range: (-180°, 180°] <==> (–2^31, 2^31] // Latitudes range: [-90°, 90°] <==> [-2^30, 2^30] using NdsPoint = std::tuple; ///< Invalid NDS related id constexpr auto NDS_INVALID_ID = std::numeric_limits::max(); constexpr auto NDS_INVALID_VALUE = std::numeric_limits::infinity(); // The latitude and longitude value corresponding to the NDS coordinate unit // 360 / math.pow(2, 32) constexpr auto NDS_PRECISION = 0.00000008381903171539306640625; constexpr auto MIN_LON = -180.0; constexpr auto MAX_LON = 180 - NDS_PRECISION; constexpr auto MIN_LAT = -90.0; constexpr auto MAX_LAT = 90.0 - NDS_PRECISION; // NDS level number, highest: 0, lowest: 15, total: 16 constexpr auto NDS_LEVEL_COUNT = 16; /** * @brief get the width of the grid at the specified level in latitude and * longitude coordinate, unit: degree * * @param level * @return grid width in degree */ double getGridSize(uint32_t level); /** * @brief convert (lon.lat) into NDS point * * @param lon * @param lat * @return NdsPoint */ NdsPoint lonLat2NdsPoint(double lon, double lat); /** * @brief convert NDS point into (lon,lat) * * @param ndsPoint * @return std::tuple: (x,y) */ std::tuple ndsPoint2lonLat(const NdsPoint& ndsPoint); /** * @brief Get the Mesh Id object * * @param lon * @param lat * @param level * @return MeshId */ MeshId getMeshId(double lon, double lat, uint32_t level); MeshId getMeshId(const NdsPoint& ndsPt, uint32_t level); NdsGridId getGridId(MeshId meshId, uint32_t level); /** * @brief Get the Grid Id object * * @param lon * @param lat * @param level * @return NdsGridId */ NdsGridId getGridId(double lon, double lat, uint32_t level); NdsGridId getGridId(const NdsPoint& ndsPt, uint32_t level); // 获取和线段p1-->p2相交的meshids std::vector getSegmentMeshIds(const PointD& p1, const PointD& p2, uint32_t level); std::tuple gridId2MeshIdAndLevel(NdsGridId gridId); /** * @brief Get left/top/right/bottom longitude or latitude of specified grid * * @param gridId * @return basic::RectD */ RectD getGridRect(NdsGridId gridId); RectD getMeshRect(MeshId meshId, uint32_t level); PointD getMeshCenter(MeshId meshId, uint32_t level); /** * @brief 给定一系列NDS grid id,获取所有瓦片的外接矩形 * * @param gridIds * @return basic::RectD */ RectD getGridsRect(std::vector gridIds); /** * @brief 给定一系列mesh ids,获取这些meshs的外接矩形 * * @param meshIds * @return basic::RectD */ RectD getMeshsRect(std::vector meshIds, uint32_t level); /** * @brief given a rectangle, get all NDS grid ids of the specified level that * intersect with it * * @param rct 左/下边界为闭区间, 右/上边界为开区间(右上边界值不用来计算meshid) * @param level * @return std::vector: NDS grid ids of specified level */ std::vector getGridIdInRect(const RectD& rct, uint32_t level); /** * @brief 获取和指定经纬度矩形框相交的mesh ids * * @param rct 左/下边界为闭区间, 右/上边界为开区间(右上边界值不用来计算meshid) * @param level * @return std::vector */ std::vector getMeshIdInRect(const RectD& rct, uint32_t level); /** * @brief 获取以指定mesh id为中心的 (2n+1)*(2n+1) 的mesh id * 注意:返回的顺序从左到右从上到下,即经度从小到大,但是纬度是从大到小 * @param id * @param level * @param n * @return std::vector */ std::vector getAdjacentMeshIds(MeshId id, uint32_t level, uint32_t n); /** * @brief Given a Mesh id and it's level, return 8 mesh ids of the same level * around id * * @param meshId * @param level * @return std::vector */ std::vector get8AroundMeshId(MeshId meshId, uint32_t level); /** * @brief Given a NDS grid id, get 8 grid ids around it * (not valid for level 0 and 1) * Note:: around NDS grid is sequence: * 0 1 2 * 7 gridId 3 * 6 5 4 * * @param gridId * @return std::vector: if level ==0 or 1, return all NDS_INVALID_ID */ std::vector get8AroundGridId(NdsGridId gridId); } // namespace nds