#pragma once #include #include #include #include #include #include #include #include #include namespace LtsCoordTrans { using UtmCoordinate2D = LtsCoordTrans::UtmCoordinate; using QPoint3D = LtsUtils::QPoint3D; class LTSCOORDINATE_EXPORT LtsCoordinate { public: explicit LtsCoordinate(double lon = 0, double lat = 0, double z = std::nan("")) : m_geo(Core::GeoPosition(lon, lat, z)) {} explicit LtsCoordinate(const QPointF &lonLat, double z = std::nan("")) : m_geo(Core::GeoPosition(lonLat.x(), lonLat.y(), z)) {} explicit LtsCoordinate(const Core::GeoPosition &geoPos) : m_geo(geoPos) {} explicit LtsCoordinate(const Core::GeoPosition2D &geoPos2D) : m_geo(geoPos2D.lon(), geoPos2D.lat(), std::nan("")) {} LtsCoordinate(const LtsCoordTrans::UtmCoordinate &utm2D, double zValue) = delete; static LtsCoordinate fromGeoPosition(double lon, double lat, double z = std::nan("")) { return LtsCoordinate(lon, lat, z); } static LtsCoordinate fromUtmCoordinate(const LtsCoordTrans::UtmCoordinate &utm2D, double zValue) { Q_ASSERT_X(utm2D.zone > 0, "LtsCoordinate", "zone has to be set"); const QPointF &geoPnt = utm2D.geographic(); return LtsCoordinate(geoPnt.x(), geoPnt.y(), zValue); } static LtsCoordinate fromUtm(const QPointF &utm2d, int zone, double zValue) { const LtsCoordTrans::UtmCoordinate utmCoord(zone, utm2d.x(), utm2d.y()); const QPointF &geoPnt = utmCoord.geographic(); return LtsCoordinate(geoPnt.x(), geoPnt.y(), zValue); } bool isValid() const { return hasGeo() || hasUtm(); } bool hasGeo() const { return !(valueIsNullOrNan(m_geo.lon()) || valueIsNullOrNan(m_geo.lat())); } bool hasUtm() const { return m_utm2D.isValid(); } static bool valueIsNullOrNan(double value) { return qFuzzyIsNull(value) || std::isnan(value); } QString mgrs(int prec = 5, bool withSpaces = true) const; QString mgrsWithZ(int prec = 5, bool withSpaces = true) const; QString toString(bool fullAndExpensive = false) const; static void resetConversionCounter(); static long getConversionCounter(); const Core::GeoPosition &geoPosition() const { return m_geo; } const Core::GeoPosition2D &geoPosition2D() const { return m_geo; } const LtsCoordTrans::UtmCoordinate &utmCoordinate() const { if (!hasUtm()) convertGeoToUtm(); return m_utm2D; } double &rz() { return m_geo.z(); } double z() const { return m_geo.z(); } void setZ(double value) { m_geo.z(value); } LtsCoordTrans::UtmCoordinate utmCoordinateDiffZone(int zone) const { m_utm2D_differentZone = LtsCoordTrans::UtmCoordinate::fromGeographic(m_geo.lon(), m_geo.lat(), zone); return m_utm2D_differentZone; } template T toUtm(int zone = -1) const { T obj; helperToUtm(obj, zone); return obj; } QPointF toUtmPointF() const { return toUtm(); } QPoint3D toUtmPoint3D() const { return toUtm(); } QPointF toGeoPointF() const { return QPointF (m_geo.lon(), m_geo.lat()); } QPoint3D toGeoPoint3D() const { return QPoint3D(m_geo.lon(), m_geo.lat(), m_geo.z() ); } UtmCoordinate3D toUtmCoordinate3D() const { return UtmCoordinate3D(utmCoordinate(), m_geo.z()); } using elevationCbFunc = std::function; static void setElevationCallback(const elevationCbFunc &elevationCB); static bool hasElevationCallback(); double elevationAt(double defaultElevation = 0.0, bool *bIsCovered = nullptr) const; void setZValueAccordingElevation(double defaultElevation = 0.0); static double elevationAt(const LtsCoordinate &coordinate, double defaultElevation = 0.0, bool *bIsCovered = nullptr); void replaceZValueByElevationIfValue(double zValueToBeReplaced = std::nan(""), double defaultElevation = 0.0); double heightOverElevation() const { return m_geo.z() - elevationAt(); } double distanceUtm2D(const LtsCoordinate &other) const { const LtsCoordTrans::UtmCoordinate &thisUtm2D = utmCoordinate(); const LtsCoordTrans::UtmCoordinate &otherUtm2D = other.utmCoordinateDiffZone(m_utm2D.zone); return LtsCoordTrans::distance(thisUtm2D, otherUtm2D); } double distanceUtm3D(const LtsCoordinate &other) const { const QPoint3D &thisUtm3D = toUtm(); const QPoint3D &otherUtm3D = other.toUtm(m_utm2D.zone); const double dist3D = (thisUtm3D - otherUtm3D).length(); Q_ASSERT_X(!std::isnan(dist3D), "LtsCoordinate", "ERROR, distance3D is NaN"); return dist3D; } static double angleDegreeUtm2D(const LtsCoordinate &coord1, const LtsCoordinate &coord2); protected: void clearGeo() const { clearGeoLonLat(); m_geo.z(std::nan("")); } void clearGeoLonLat() const { m_geo.lon(0); m_geo.lat(0); } void clearUtm() const { m_utm2D = m_utm2D_differentZone = UtmCoordinate2D(); } void clearElevation() const { m_elevation = std::nan(""); } void clear() const { clearGeo(); clearUtm(); clearElevation(); } const LtsCoordTrans::UtmCoordinate &utmCoordinateInternal(int zone = -1) const; void convertGeoToUtm() const; protected: void helperToUtm(QPointF &pntRef, int zone = -1) const { const auto &utmTemp = utmCoordinateInternal(zone); pntRef.rx() = utmTemp.x; pntRef.ry() = utmTemp.y; } void helperToUtm(QPoint3D &pntRef, int zone = -1) const { const auto &utmTemp = utmCoordinateInternal(zone); pntRef.rx() = utmTemp.x; pntRef.ry() = utmTemp.y; pntRef.rz() = m_geo.z(); } protected: mutable Core::GeoPosition m_geo; mutable UtmCoordinate2D m_utm2D; mutable UtmCoordinate2D m_utm2D_differentZone; mutable double m_elevation{std::nan("")}; static elevationCbFunc m_getElevationCB; }; class LTSCOORDINATE_EXPORT LtsCoordinateNoImplicitCopy : public LtsCoordinate { public: using BaseClass = LtsCoordinate; LtsCoordinateNoImplicitCopy() = default; explicit LtsCoordinateNoImplicitCopy (const LtsCoordinateNoImplicitCopy &) = default; ~LtsCoordinateNoImplicitCopy() = default; explicit LtsCoordinateNoImplicitCopy(const QPointF &lonLat, double z = std::nan("")) : BaseClass(Core::GeoPosition(lonLat.x(), lonLat.y(), z)) {} explicit LtsCoordinateNoImplicitCopy(const Core::GeoPosition &geoPos) : BaseClass(geoPos) {} explicit LtsCoordinateNoImplicitCopy(const Core::GeoPosition2D &geoPos2D) : BaseClass(geoPos2D) {} void updateGeoPosition(const Core::GeoPosition &geoPos) const { clear(); m_geo = geoPos; } }; template T_OUT convert(const T_IN& contIn) { T_OUT out; out.reserve(contIn.size()); for (const Core::GeoPosition &posGeo : qAsConst(contIn)) out.push_back(LtsCoordinate(posGeo)); return out; } LTSCOORDINATE_EXPORT std::ostream &operator<< (std::ostream &stream, const LtsCoordinate &value); }