diff --git a/geo/Geo.cpp b/geo/Geo.cpp index 1f41593..03f40de 100644 --- a/geo/Geo.cpp +++ b/geo/Geo.cpp @@ -110,16 +110,16 @@ util::geo::CRSType util::geo::getCRSType(const char* c, const char** endr) { return CRS84; // Default. } - if (strncicmp("", c, 46) == 0) { - if (endr) (*endr) = c + 46; + if (strncicmp(crs84Iri, c, crs84IriLen) == 0) { + if (endr) (*endr) = c + crs84IriLen; return CRS84; } - if (strncicmp("", c, 44) == 0) { - if (endr) (*endr) = c + 44; + if (strncicmp(wgs84Iri, c, wgs84IriLen) == 0) { + if (endr) (*endr) = c + wgs84IriLen; return WGS84; } - if (strncicmp("", c, 44) == 0) { - if (endr) (*endr) = c + 44; + if (strncicmp(webMercIri, c, webMercIriLen) == 0) { + if (endr) (*endr) = c + webMercIriLen; return WEB_MERCATOR; } @@ -127,6 +127,22 @@ util::geo::CRSType util::geo::getCRSType(const char* c, const char** endr) { return UNSUPPORTED; } +// _____________________________________________________________________________ +std::string util::geo::getCrsIri(util::geo::CRSType targetCRS) { + switch (targetCRS) + { + case CRS84: + // Not attaching IRI as CRS84 is the default. + return ""; + case WGS84: + return std::string{wgs84Iri} + " "; + case WEB_MERCATOR: + return std::string{webMercIri} + " "; + default: + throw std::runtime_error("Trying to get CRS IRI for unsupported CRS type."); + } +} + // _____________________________________________________________________________ double util::geo::distToSegment(double lax, double lay, double lbx, double lby, double px, double py) { diff --git a/geo/Geo.h b/geo/Geo.h index 518229d..8723928 100644 --- a/geo/Geo.h +++ b/geo/Geo.h @@ -163,6 +163,13 @@ enum CRSType : uint8_t { WEB_MERCATOR = 3, }; +constexpr const char crs84Iri[] = ""; +constexpr size_t crs84IriLen = sizeof(crs84Iri) - 1; +constexpr const char wgs84Iri[] = ""; +constexpr size_t wgs84IriLen = sizeof(wgs84Iri) - 1; +constexpr const char webMercIri[] = ""; +constexpr size_t webMercIriLen = sizeof(webMercIri) - 1; + uint8_t boolArrToInt8(const std::array arr); template @@ -298,29 +305,36 @@ RotatedBox shrink(const RotatedBox& b, double d); bool doubleEq(double a, double b); +// This is used by 'getWKT' to attach the CRS IRI for a specified CRS. +std::string getCrsIri(CRSType targetCRS); + +// The 'getWKT' functions now attach a given CRS IRI (specified by 'targetCRS'). +// By default or for 'targetCRS == CRS84' no IRI will be attached. +// The point will also be projected from 'currentCRS' to the 'targetCRS'. +// As the collection uses the 'getWKT' function of the subgeometries, the IRIs for these geometries are hidden (via 'hideIri'). template -std::string getWKT(const Point& p, uint16_t prec); +std::string getWKT(const Point& p, uint16_t prec, CRSType currentCRS = CRS84, CRSType targetCRS = CRS84, bool hideIri = false); template -std::string getWKT(const Point& p); +std::string getWKT(const Point& p, CRSType currentCRS = CRS84, CRSType targetCRS = CRS84, bool hideIri = false); template -std::string getWKT(const std::vector>& p, uint16_t prec); +std::string getWKT(const std::vector>& p, uint16_t prec, CRSType currentCRS = CRS84, CRSType targetCRS = CRS84, bool hideIri = false); template -std::string getWKT(const std::vector>& p); +std::string getWKT(const std::vector>& p, CRSType currentCRS = CRS84, CRSType targetCRS = CRS84, bool hideIri = false); template -std::string getWKT(const Line& l, uint16_t prec); +std::string getWKT(const Line& l, uint16_t prec, CRSType currentCRS = CRS84, CRSType targetCRS = CRS84, bool hideIri = false); template -std::string getWKT(const Line& l); +std::string getWKT(const Line& l, CRSType currentCRS = CRS84, CRSType targetCRS = CRS84, bool hideIri = false); template -std::string getWKT(const std::vector>& ls, uint16_t prec); +std::string getWKT(const std::vector>& ls, uint16_t prec, CRSType currentCRS = CRS84, CRSType targetCRS = CRS84, bool hideIri = false); template -std::string getWKT(const std::vector>& ls); +std::string getWKT(const std::vector>& ls, CRSType currentCRS = CRS84, CRSType targetCRS = CRS84, bool hideIri = false); template std::string getWKT(const XSortedPolygon& ls, uint16_t prec); @@ -341,22 +355,22 @@ template std::string getWKT(const Box& l); template -std::string getWKT(const Polygon& p, uint16_t prec); +std::string getWKT(const Polygon& p, uint16_t prec, CRSType currentCRS = CRS84, CRSType targetCRS = CRS84, bool hideIri = false); template -std::string getWKT(const Polygon& p); +std::string getWKT(const Polygon& p, CRSType currentCRS = CRS84, CRSType targetCRS = CRS84, bool hideIri = false); template -std::string getWKT(const std::vector>& ls, uint16_t prec); +std::string getWKT(const std::vector>& ls, uint16_t prec, CRSType currentCRS = CRS84, CRSType targetCRS = CRS84, bool hideIri = false); template -std::string getWKT(const std::vector>& ls); +std::string getWKT(const std::vector>& ls, CRSType currentCRS = CRS84, CRSType targetCRS = CRS84, bool hideIri = false); template -std::string getWKT(const Collection& coll, uint16_t prec); +std::string getWKT(const Collection& coll, uint16_t prec, CRSType currentCRS = CRS84, CRSType targetCRS = CRS84, bool hideIri = false); template -std::string getWKT(const Collection& coll); +std::string getWKT(const Collection& coll, CRSType currentCRS = CRS84, CRSType targetCRS = CRS84, bool hideIri = false); template bool contains(const Point& p, const Box& box); diff --git a/geo/Geo.tpp b/geo/Geo.tpp index 529e59c..27c6f7d 100644 --- a/geo/Geo.tpp +++ b/geo/Geo.tpp @@ -483,33 +483,35 @@ RotatedBox shrink(const RotatedBox& b, double d) { // _____________________________________________________________________________ template -std::string getWKT(const Point& p, uint16_t prec) { +std::string getWKT(const Point& p, uint16_t prec, CRSType currentCRS, CRSType targetCRS, bool hideIri) { + auto proj = projectToCRS(p, currentCRS, targetCRS); std::string ret; - ret = "POINT("; + ret = hideIri ? "POINT(" : getCrsIri(targetCRS) + "POINT("; ret.reserve(6 + prec + 3 + prec + 3 + 1); - ret.append(formatFloat(p.getX(), prec)); + ret.append(formatFloat(proj.getX(), prec)); ret.push_back(' '); - ret.append(formatFloat(p.getY(), prec)); + ret.append(formatFloat(proj.getY(), prec)); ret.push_back(')'); return ret; } // _____________________________________________________________________________ template -std::string getWKT(const Point& p) { - return getWKT(p, 6); +std::string getWKT(const Point& p, CRSType currentCRS, CRSType targetCRS, bool hideIri) { + return getWKT(p, 6, currentCRS, targetCRS, hideIri); } // _____________________________________________________________________________ template -std::string getWKT(const std::vector>& p, uint16_t prec) { - std::string ret = "MULTIPOINT("; +std::string getWKT(const std::vector>& p, uint16_t prec, CRSType currentCRS, CRSType targetCRS, bool hideIri) { + std::string ret = hideIri ? "MULTIPOINT(" : getCrsIri(targetCRS) + "MULTIPOINT("; ret.reserve(10 + 1 + p.size() * (prec + 3) * 2 + 1); for (size_t i = 0; i < p.size(); i++) { if (i) ret.push_back(','); - ret.append(formatFloat(p[i].getX(), prec)); + auto point = projectToCRS(p[i], currentCRS, targetCRS); + ret.append(formatFloat(point.getX(), prec)); ret.push_back(' '); - ret.append(formatFloat(p[i].getY(), prec)); + ret.append(formatFloat(point.getY(), prec)); } ret.push_back(')'); return ret; @@ -517,20 +519,21 @@ std::string getWKT(const std::vector>& p, uint16_t prec) { // _____________________________________________________________________________ template -std::string getWKT(const std::vector>& p) { - return getWKT(p, 6); +std::string getWKT(const std::vector>& p, CRSType currentCRS, CRSType targetCRS, bool hideIri) { + return getWKT(p, 6, currentCRS, targetCRS, hideIri); } // _____________________________________________________________________________ template -std::string getWKT(const Line& l, uint16_t prec) { - std::string ret = "LINESTRING("; +std::string getWKT(const Line& l, uint16_t prec, CRSType currentCRS, CRSType targetCRS, bool hideIri) { + std::string ret = hideIri ? "LINESTRING(" : getCrsIri(targetCRS) + "LINESTRING("; ret.reserve(10 + 1 + l.size() * (prec + 3) * 2 + 1); for (size_t i = 0; i < l.size(); i++) { if (i) ret.push_back(','); - ret.append(formatFloat(l[i].getX(), prec)); + auto point = projectToCRS(l[i], currentCRS, targetCRS); + ret.append(formatFloat(point.getX(), prec)); ret.push_back(' '); - ret.append(formatFloat(l[i].getY(), prec)); + ret.append(formatFloat(point.getY(), prec)); } ret.push_back(')'); return ret; @@ -538,14 +541,14 @@ std::string getWKT(const Line& l, uint16_t prec) { // _____________________________________________________________________________ template -std::string getWKT(const Line& l) { - return getWKT(l, 6); +std::string getWKT(const Line& l, CRSType currentCRS, CRSType targetCRS, bool hideIri) { + return getWKT(l, 6, currentCRS, targetCRS, hideIri); } // _____________________________________________________________________________ template -std::string getWKT(const std::vector>& ls, uint16_t prec) { - std::string ret = "MULTILINESTRING("; +std::string getWKT(const std::vector>& ls, uint16_t prec, CRSType currentCRS, CRSType targetCRS, bool hideIri) { + std::string ret = hideIri ? "MULTILINESTRING(" : getCrsIri(targetCRS) + "MULTILINESTRING("; if (ls.size()) ret.reserve(15 + 2 + ls[0].size() * (prec + 3) * 2 + 2); @@ -554,9 +557,10 @@ std::string getWKT(const std::vector>& ls, uint16_t prec) { ret.push_back('('); for (size_t i = 0; i < ls[j].size(); i++) { if (i) ret.push_back(','); - ret.append(formatFloat(ls[j][i].getX(), prec)); + auto point = projectToCRS(ls[j][i], currentCRS, targetCRS); + ret.append(formatFloat(point.getX(), prec)); ret.push_back(' '); - ret.append(formatFloat(ls[j][i].getY(), prec)); + ret.append(formatFloat(point.getY(), prec)); } ret.push_back(')'); } @@ -567,8 +571,8 @@ std::string getWKT(const std::vector>& ls, uint16_t prec) { // _____________________________________________________________________________ template -std::string getWKT(const std::vector>& ls) { - return getWKT(ls, 6); +std::string getWKT(const std::vector>& ls, CRSType currentCRS, CRSType targetCRS, bool hideIri) { + return getWKT(ls, 6, currentCRS, targetCRS, hideIri); } // _____________________________________________________________________________ @@ -654,23 +658,26 @@ std::string getWKT(const Box& l) { // _____________________________________________________________________________ template -std::string getWKT(const Polygon& p, uint16_t prec) { +std::string getWKT(const Polygon& p, uint16_t prec, CRSType currentCRS, CRSType targetCRS, bool hideIri) { if (p.getOuter().size() == 0) return "POLYGON()"; - std::string ret = "POLYGON(("; + std::string ret = hideIri ? "POLYGON((" : getCrsIri(targetCRS) + "POLYGON(("; ret.reserve(7 + 2 + p.getOuter().size() * (prec + 3) * 2 + 2); + util::geo::Point front; for (size_t i = 0; i < p.getOuter().size(); i++) { if (i > 0) ret.push_back(','); - ret.append(formatFloat(p.getOuter()[i].getX(), prec)); + auto point = projectToCRS(p.getOuter()[i], currentCRS, targetCRS); + if (i == 0) front = point; + ret.append(formatFloat(point.getX(), prec)); ret.push_back(' '); - ret.append(formatFloat(p.getOuter()[i].getY(), prec)); + ret.append(formatFloat(point.getY(), prec)); } if (p.getOuter().front() != p.getOuter().back()) { ret.push_back(','); - ret.append(formatFloat(p.getOuter().front().getX(), prec)); + ret.append(formatFloat(front.getX(), prec)); ret.push_back(' '); - ret.append(formatFloat(p.getOuter().front().getY(), prec)); + ret.append(formatFloat(front.getY(), prec)); } ret.push_back(')'); @@ -678,16 +685,18 @@ std::string getWKT(const Polygon& p, uint16_t prec) { ret.append(",("); for (size_t i = 0; i < inner.size(); i++) { if (i > 0) ret.push_back(','); - ret.append(formatFloat(inner[i].getX(), prec)); + auto point = projectToCRS(inner[i], currentCRS, targetCRS); + if (i == 0) front = point; + ret.append(formatFloat(point.getX(), prec)); ret.push_back(' '); - ret.append(formatFloat(inner[i].getY(), prec)); + ret.append(formatFloat(point.getY(), prec)); } if (inner.front() != inner.back()) { ret.push_back(','); - ret.append(formatFloat(inner.front().getX(), prec)); + ret.append(formatFloat(front.getX(), prec)); ret.push_back(' '); - ret.append(formatFloat(inner.front().getY(), prec)); + ret.append(formatFloat(front.getY(), prec)); } ret.push_back(')'); } @@ -697,14 +706,14 @@ std::string getWKT(const Polygon& p, uint16_t prec) { // _____________________________________________________________________________ template -std::string getWKT(const Polygon& p) { - return getWKT(p, 6); +std::string getWKT(const Polygon& p, CRSType currentCRS, CRSType targetCRS, bool hideIri) { + return getWKT(p, 6, currentCRS, targetCRS, hideIri); } // _____________________________________________________________________________ template -std::string getWKT(const std::vector>& ls, uint16_t prec) { - std::string ret = "MULTIPOLYGON("; +std::string getWKT(const std::vector>& ls, uint16_t prec, CRSType currentCRS, CRSType targetCRS, bool hideIri) { + std::string ret = hideIri ? "MULTIPOLYGON(" : getCrsIri(targetCRS) + "MULTIPOLYGON("; if (ls.size()) ret.reserve(12 + 2 + ls[0].getOuter().size() * (prec + 3) * 2 + 2); @@ -712,18 +721,22 @@ std::string getWKT(const std::vector>& ls, uint16_t prec) { if (j) ret.push_back(','); ret.push_back('('); ret.push_back('('); + + util::geo::Point front; for (size_t i = 0; i < ls[j].getOuter().size(); i++) { if (i > 0) ret.push_back(','); - ret.append(formatFloat(ls[j].getOuter()[i].getX(), prec)); + auto point = projectToCRS(ls[j].getOuter()[i], currentCRS, targetCRS); + if (i == 0) front = point; + ret.append(formatFloat(point.getX(), prec)); ret.push_back(' '); - ret.append(formatFloat(ls[j].getOuter()[i].getY(), prec)); + ret.append(formatFloat(point.getY(), prec)); } if (ls[j].getOuter().front() != ls[j].getOuter().back()) { ret.push_back(','); - ret.append(formatFloat(ls[j].getOuter().front().getX(), prec)); + ret.append(formatFloat(front.getX(), prec)); ret.push_back(' '); - ret.append(formatFloat(ls[j].getOuter().front().getY(), prec)); + ret.append(formatFloat(front.getY(), prec)); } ret.push_back(')'); @@ -732,15 +745,17 @@ std::string getWKT(const std::vector>& ls, uint16_t prec) { ret.push_back('('); for (size_t i = 0; i < inner.size(); i++) { if (i > 0) ret.push_back(','); - ret.append(formatFloat(inner[i].getX(), prec)); + auto point = projectToCRS(inner[i], currentCRS, targetCRS); + if (i == 0) front = point; + ret.append(formatFloat(point.getX(), prec)); ret.push_back(' '); - ret.append(formatFloat(inner[i].getY(), prec)); + ret.append(formatFloat(point.getY(), prec)); } if (inner.front() != inner.back()) { ret.push_back(','); - ret.append(formatFloat(inner.front().getX(), prec)); + ret.append(formatFloat(front.getX(), prec)); ret.push_back(' '); - ret.append(formatFloat(inner.front().getY(), prec)); + ret.append(formatFloat(front.getY(), prec)); } ret.push_back(')'); } @@ -753,27 +768,27 @@ std::string getWKT(const std::vector>& ls, uint16_t prec) { // _____________________________________________________________________________ template -std::string getWKT(const std::vector>& ls) { - return getWKT(ls, 6); +std::string getWKT(const std::vector>& ls, CRSType currentCRS, CRSType targetCRS, bool hideIri) { + return getWKT(ls, 6, currentCRS, targetCRS, hideIri); } // _____________________________________________________________________________ template -std::string getWKT(const Collection& coll, uint16_t prec) { - std::string ret = "GEOMETRYCOLLECTION("; +std::string getWKT(const Collection& coll, uint16_t prec, CRSType currentCRS, CRSType targetCRS, bool hideIri) { + std::string ret = hideIri ? "GEOMETRYCOLLECTION(" : getCrsIri(targetCRS) + "GEOMETRYCOLLECTION("; std::string delim = ""; for (const auto& g : coll) { ret += delim; delim = ","; - if (g.getType() == 0) ret += util::geo::getWKT(g.getPoint(), prec); - if (g.getType() == 1) ret += util::geo::getWKT(g.getLine(), prec); - if (g.getType() == 2) ret += util::geo::getWKT(g.getPolygon(), prec); - if (g.getType() == 3) ret += util::geo::getWKT(g.getMultiLine(), prec); - if (g.getType() == 4) ret += util::geo::getWKT(g.getMultiPolygon(), prec); - if (g.getType() == 5) ret += util::geo::getWKT(g.getCollection(), prec); - if (g.getType() == 6) ret += util::geo::getWKT(g.getMultiPoint(), prec); + if (g.getType() == 0) ret += util::geo::getWKT(g.getPoint(), prec, currentCRS, targetCRS, true); + if (g.getType() == 1) ret += util::geo::getWKT(g.getLine(), prec, currentCRS, targetCRS, true); + if (g.getType() == 2) ret += util::geo::getWKT(g.getPolygon(), prec, currentCRS, targetCRS, true); + if (g.getType() == 3) ret += util::geo::getWKT(g.getMultiLine(), prec, currentCRS, targetCRS, true); + if (g.getType() == 4) ret += util::geo::getWKT(g.getMultiPolygon(), prec, currentCRS, targetCRS, true); + if (g.getType() == 5) ret += util::geo::getWKT(g.getCollection(), prec, currentCRS, targetCRS, true); + if (g.getType() == 6) ret += util::geo::getWKT(g.getMultiPoint(), prec, currentCRS, targetCRS, true); } return ret + ")"; @@ -781,8 +796,8 @@ std::string getWKT(const Collection& coll, uint16_t prec) { // _____________________________________________________________________________ template -std::string getWKT(const Collection& coll) { - return getWKT(coll, 6); +std::string getWKT(const Collection& coll, CRSType currentCRS, CRSType targetCRS, bool hideIri) { + return getWKT(coll, 6, currentCRS, targetCRS, hideIri); } // _____________________________________________________________________________ diff --git a/tests/GeoTestCRS.cpp b/tests/GeoTestCRS.cpp index c8e8b9c..b2f30ad 100644 --- a/tests/GeoTestCRS.cpp +++ b/tests/GeoTestCRS.cpp @@ -543,4 +543,276 @@ void GeoTest::testCRS() { "GEOMETRYCOLLECTION(MULTIPOINT(7 47,8 48),MULTIPOLYGON(((7 47,8 47,8 48,7 48,7 47))," "((8 48,9 48,9 49,8 49,8 48))),MULTILINESTRING((7 47,8 47),(8 48,7 48)))"); } + + { + // Test correct reattaching of CRS IRIs. + + // POINT + auto projCRS84 = util::geo::pointFromWKT( + " POINT(2 3)"); + TEST(getWKT(projCRS84, util::geo::CRSType::CRS84, util::geo::CRSType::CRS84), ==, "POINT(2 3)"); + + auto projWGS84 = util::geo::pointFromWKT( + " POINT(3 2)"); + TEST(getWKT(projWGS84, util::geo::CRSType::CRS84, util::geo::CRSType::WGS84), ==, " POINT(3 2)"); + + auto projWebMerc = util::geo::pointFromWKT( + " POINT(222638.98158654 334111.17140195)"); + // The point will change a bit due to the reprojecting. + TEST(getWKT(projWebMerc, util::geo::CRSType::CRS84, util::geo::CRSType::WEB_MERCATOR), ==, " POINT(222638.981587 334111.171402)"); + + // POINT (from WGS84) + util::geo::DPoint pWGS84{3, 2}; + TEST(getWKT(pWGS84, util::geo::CRSType::WGS84, util::geo::CRSType::CRS84), ==, "POINT(2 3)"); + TEST(getWKT(pWGS84, util::geo::CRSType::WGS84, util::geo::CRSType::WGS84), ==, " POINT(3 2)"); + TEST(getWKT(pWGS84, util::geo::CRSType::WGS84, util::geo::CRSType::WEB_MERCATOR), ==, " POINT(222638.981587 334111.171402)"); + + // POINT (from WebMerc) + util::geo::DPoint pWebMerc{222638.981587, 334111.171402}; + TEST(getWKT(pWebMerc, util::geo::CRSType::WEB_MERCATOR, util::geo::CRSType::CRS84), ==, "POINT(2 3)"); + TEST(getWKT(pWebMerc, util::geo::CRSType::WEB_MERCATOR, util::geo::CRSType::WGS84), ==, " POINT(3 2)"); + TEST(getWKT(pWebMerc, util::geo::CRSType::WEB_MERCATOR, util::geo::CRSType::WEB_MERCATOR), ==, " POINT(222638.981587 334111.171402)"); + + // MULTIPOINT + auto projCRS84_2 = util::geo::multiPointFromWKT( + " MULTIPOINT((7 47), (8 48))"); + TEST(getWKT(projCRS84_2, util::geo::CRSType::CRS84, util::geo::CRSType::CRS84), ==, "MULTIPOINT(7 47,8 48)"); + + auto projWGS84_2 = util::geo::multiPointFromWKT( + " MULTIPOINT((47 7), (48 8))"); + TEST(getWKT(projWGS84_2, util::geo::CRSType::CRS84, util::geo::CRSType::WGS84), ==, " MULTIPOINT(47 7,48 8)"); + + auto projWebMerc_2 = util::geo::multiPointFromWKT( + " MULTIPOINT((779236.435552915 5942074.072431109)," + " (890555.9263461885 6106854.834885074))"); + TEST(getWKT(projWebMerc_2, util::geo::CRSType::CRS84, util::geo::CRSType::WEB_MERCATOR), ==, + " MULTIPOINT(779236.435553 5942074.072431," + "890555.926346 6106854.834885)"); + + // MULTIPOINT (from WGS84) + util::geo::DMultiPoint mpWGS84{util::geo::DPoint{47, 7}, util::geo::DPoint{48, 8}}; + TEST(getWKT(mpWGS84, util::geo::CRSType::WGS84, util::geo::CRSType::CRS84), ==, "MULTIPOINT(7 47,8 48)"); + TEST(getWKT(mpWGS84, util::geo::CRSType::WGS84, util::geo::CRSType::WGS84), ==, " MULTIPOINT(47 7,48 8)"); + TEST(getWKT(mpWGS84, util::geo::CRSType::WGS84, util::geo::CRSType::WEB_MERCATOR), ==, + " MULTIPOINT(779236.435553 5942074.072431," + "890555.926346 6106854.834885)"); + + // MULTIPOINT (from WebMerc) + util::geo::DMultiPoint mpWebMerc{util::geo::DPoint{779236.435553, 5942074.072431}, util::geo::DPoint{890555.926346, 6106854.834885}}; + TEST(getWKT(mpWebMerc, util::geo::CRSType::WEB_MERCATOR, util::geo::CRSType::CRS84), ==, "MULTIPOINT(7 47,8 48)"); + TEST(getWKT(mpWebMerc, util::geo::CRSType::WEB_MERCATOR, util::geo::CRSType::WGS84), ==, " MULTIPOINT(47 7,48 8)"); + TEST(getWKT(mpWebMerc, util::geo::CRSType::WEB_MERCATOR, util::geo::CRSType::WEB_MERCATOR), ==, + " MULTIPOINT(779236.435553 5942074.072431," + "890555.926346 6106854.834885)"); + + // Line + auto projCRS84_3 = util::geo::lineFromWKT( + " LINESTRING(7 47, 7 48)"); + TEST(getWKT(projCRS84_3, util::geo::CRSType::CRS84, util::geo::CRSType::CRS84), ==, "LINESTRING(7 47,7 48)"); + + auto projWGS84_3 = util::geo::lineFromWKT( + " LINESTRING(47 7, 48 7)"); + TEST(getWKT(projWGS84_3, util::geo::CRSType::CRS84, util::geo::CRSType::WGS84), ==, " LINESTRING(47 7,48 7)"); + + + auto projWebMerc_3 = util::geo::lineFromWKT( + " LINESTRING(779236.435552915 " + "5942074.072431109, 779236.435552915 6106854.834885074)"); + TEST(getWKT(projWebMerc_3, util::geo::CRSType::CRS84, util::geo::CRSType::WEB_MERCATOR), ==, + " LINESTRING(779236.435553 " + "5942074.072431,779236.435553 6106854.834885)"); + + // LINE (from WGS84) + util::geo::DLine lWGS84{util::geo::DPoint{47, 7}, util::geo::DPoint{48, 7}}; + TEST(getWKT(lWGS84, util::geo::CRSType::WGS84, util::geo::CRSType::CRS84), ==, "LINESTRING(7 47,7 48)"); + TEST(getWKT(lWGS84, util::geo::CRSType::WGS84, util::geo::CRSType::WGS84), ==, " LINESTRING(47 7,48 7)"); + TEST(getWKT(lWGS84, util::geo::CRSType::WGS84, util::geo::CRSType::WEB_MERCATOR), ==, + " LINESTRING(779236.435553 " + "5942074.072431,779236.435553 6106854.834885)"); + + // LINE (from WebMerc) + util::geo::DLine lWebMerc{util::geo::DPoint{779236.435553, 5942074.072431}, util::geo::DPoint{779236.435553, 6106854.834885}}; + TEST(getWKT(lWebMerc, util::geo::CRSType::WEB_MERCATOR, util::geo::CRSType::CRS84), ==, "LINESTRING(7 47,7 48)"); + TEST(getWKT(lWebMerc, util::geo::CRSType::WEB_MERCATOR, util::geo::CRSType::WGS84), ==, " LINESTRING(47 7,48 7)"); + TEST(getWKT(lWebMerc, util::geo::CRSType::WEB_MERCATOR, util::geo::CRSType::WEB_MERCATOR), ==, + " LINESTRING(779236.435553 " + "5942074.072431,779236.435553 6106854.834885)"); + + // MULTILINESTRING + auto projCRS8_4 = util::geo::multiLineFromWKT( + " MULTILINESTRING((7 47, 8 47), (8 48, 7 48))"); + TEST(getWKT(projCRS8_4, util::geo::CRSType::CRS84, util::geo::CRSType::CRS84), ==, "MULTILINESTRING((7 47,8 47),(8 48,7 48))"); + + auto projWGS8_4 = util::geo::multiLineFromWKT( + " MULTILINESTRING((47 7, 47 8), (48 8, 48 7))"); + TEST(getWKT(projWGS8_4, util::geo::CRSType::CRS84, util::geo::CRSType::WGS84), ==, " MULTILINESTRING((47 7,47 8),(48 8,48 7))"); + + auto projWebMerc_4 = util::geo::multiLineFromWKT( + " MULTILINESTRING((779236.435552915 5942074.072431109," + " 890555.9263461885 5942074.072431109), (890555.9263461885 6106854.834885074, 779236.435552915 6106854.834885074))"); + TEST(getWKT(projWebMerc_4, util::geo::CRSType::CRS84, util::geo::CRSType::WEB_MERCATOR), ==, + " MULTILINESTRING((779236.435553 5942074.072431," + "890555.926346 5942074.072431),(890555.926346 6106854.834885,779236.435553 6106854.834885))"); + + // MULTILINESTRING (from WGS84) + util::geo::DMultiLine mlWGS84{util::geo::DLine{util::geo::DPoint{47, 7}, util::geo::DPoint{47, 8}}, + util::geo::DLine{util::geo::DPoint{48, 8}, util::geo::DPoint{48, 7}}}; + TEST(getWKT(mlWGS84, util::geo::CRSType::WGS84, util::geo::CRSType::CRS84), ==, "MULTILINESTRING((7 47,8 47),(8 48,7 48))"); + TEST(getWKT(mlWGS84, util::geo::CRSType::WGS84, util::geo::CRSType::WGS84), ==, " MULTILINESTRING((47 7,47 8),(48 8,48 7))"); + TEST(getWKT(mlWGS84, util::geo::CRSType::WGS84, util::geo::CRSType::WEB_MERCATOR), ==, + " MULTILINESTRING((779236.435553 5942074.072431," + "890555.926346 5942074.072431),(890555.926346 6106854.834885,779236.435553 6106854.834885))"); + + // MULTILINESTRING (from WebMerc) + util::geo::DMultiLine mlWebMerc{util::geo::DLine{util::geo::DPoint{779236.435553, 5942074.072431}, util::geo::DPoint{890555.926346, 5942074.072431}}, + util::geo::DLine{util::geo::DPoint{890555.926346, 6106854.834885}, util::geo::DPoint{779236.435553, 6106854.834885}}}; + TEST(getWKT(mlWebMerc, util::geo::CRSType::WEB_MERCATOR, util::geo::CRSType::CRS84), ==, "MULTILINESTRING((7 47,8 47),(8 48,7 48))"); + TEST(getWKT(mlWebMerc, util::geo::CRSType::WEB_MERCATOR, util::geo::CRSType::WGS84), ==, " MULTILINESTRING((47 7,47 8),(48 8,48 7))"); + TEST(getWKT(mlWebMerc, util::geo::CRSType::WEB_MERCATOR, util::geo::CRSType::WEB_MERCATOR), ==, + " MULTILINESTRING((779236.435553 5942074.072431," + "890555.926346 5942074.072431),(890555.926346 6106854.834885,779236.435553 6106854.834885))"); + + // POLYGON + auto projCRS84_5 = util::geo::polygonFromWKT( + " POLYGON((7 47, 8 47, 8 48, 7 48, 7 47))"); + TEST(getWKT(projCRS84_5, util::geo::CRSType::CRS84, util::geo::CRSType::CRS84), ==, "POLYGON((7 47,8 47,8 48,7 48,7 47))"); + + auto projWGS84_5 = util::geo::polygonFromWKT( + " POLYGON((47 7, 47 8, 48 8, 48 7, 47 7))"); + TEST(getWKT(projWGS84_5, util::geo::CRSType::CRS84, util::geo::CRSType::WGS84), ==, " POLYGON((47 7,47 8,48 8,48 7,47 7))"); + + auto projWebMerc_5 = util::geo::polygonFromWKT( + " POLYGON((779236.435552915 5942074.072431109," + " 890555.9263461885 5942074.072431109, 890555.9263461885 6106854.834885074, 779236.435552915" + " 6106854.834885074, 779236.435552915 5942074.072431109))"); + TEST(getWKT(projWebMerc_5, util::geo::CRSType::CRS84, util::geo::CRSType::WEB_MERCATOR), ==, + " POLYGON((779236.435553 5942074.072431," + "890555.926346 5942074.072431,890555.926346 6106854.834885,779236.435553" + " 6106854.834885,779236.435553 5942074.072431))"); + + // POLYGON (from WGS84) + util::geo::DPolygon polyWGS84{util::geo::DLine{util::geo::DPoint{48, 7}, util::geo::DPoint{48, 8}, + util::geo::DPoint{47, 8}, util::geo::DPoint{47, 7}, util::geo::DPoint{48, 7}}}; + TEST(getWKT(polyWGS84, util::geo::CRSType::WGS84, util::geo::CRSType::CRS84), ==, "POLYGON((7 48,8 48,8 47,7 47,7 48))"); + TEST(getWKT(polyWGS84, util::geo::CRSType::WGS84, util::geo::CRSType::WGS84), ==, " POLYGON((48 7,48 8,47 8,47 7,48 7))"); + TEST(getWKT(polyWGS84, util::geo::CRSType::WGS84, util::geo::CRSType::WEB_MERCATOR), ==, + " POLYGON((779236.435553 6106854.834885,890555.926346 6106854.834885," + "890555.926346 5942074.072431,779236.435553 5942074.072431,779236.435553 6106854.834885))"); + + // POLYGON (from WebMerc) + util::geo::DPolygon polyWebMerc{util::geo::DLine{util::geo::DPoint{779236.435553, 5942074.072431}, util::geo::DPoint{890555.926346, 5942074.072431}, + util::geo::DPoint{890555.926346, 6106854.834885}, util::geo::DPoint{779236.435553, 6106854.834885}, util::geo::DPoint{779236.435553, 5942074.072431}}}; + TEST(getWKT(polyWebMerc, util::geo::CRSType::WEB_MERCATOR, util::geo::CRSType::CRS84), ==, "POLYGON((7 47,8 47,8 48,7 48,7 47))"); + TEST(getWKT(polyWebMerc, util::geo::CRSType::WEB_MERCATOR, util::geo::CRSType::WGS84), ==, " POLYGON((47 7,47 8,48 8,48 7,47 7))"); + TEST(getWKT(polyWebMerc, util::geo::CRSType::WEB_MERCATOR, util::geo::CRSType::WEB_MERCATOR), ==, + " POLYGON((779236.435553 5942074.072431," + "890555.926346 5942074.072431,890555.926346 6106854.834885,779236.435553" + " 6106854.834885,779236.435553 5942074.072431))"); + + // MULTIPOLYGON + auto projCRS84_6 = util::geo::multiPolygonFromWKT( + " MULTIPOLYGON(((7 47, 8 47, 8 48, 7 48, 7 47))," + " ((8 48, 9 48, 9 49, 8 49, 8 48)))"); + TEST(getWKT(projCRS84_6, util::geo::CRSType::CRS84, util::geo::CRSType::CRS84), ==, "MULTIPOLYGON(((7 47,8 47,8 48,7 48,7 47)),((8 48,9 48,9 49,8 49,8 48)))"); + + auto projWGS84_6 = util::geo::multiPolygonFromWKT( + " MULTIPOLYGON(((47 7, 47 8, 48 8, 48 7, 47 7))," + " ((48 8, 48 9, 49 9, 49 8, 48 8)))"); + TEST(getWKT(projWGS84_6, util::geo::CRSType::CRS84, util::geo::CRSType::WGS84), ==, + " MULTIPOLYGON(((47 7,47 8,48 8,48 7,47 7))," + "((48 8,48 9,49 9,49 8,48 8)))"); + + auto projWebMerc_6 = util::geo::multiPolygonFromWKT( + " MULTIPOLYGON(((779236.435552915 5942074.072431109," + " 890555.9263461885 5942074.072431109, 890555.9263461885 6106854.834885074, 779236.435552915 6106854.834885074," + " 779236.435552915 5942074.072431109)), ((890555.9263461885 6106854.834885074, 1001875.4171394621 6106854.834885074," + " 1001875.4171394621 6274861.394006576, 890555.9263461885 6274861.394006576, 890555.9263461885 6106854.834885074)))"); + TEST(getWKT(projWebMerc_6, util::geo::CRSType::CRS84, util::geo::CRSType::WEB_MERCATOR), ==, + " MULTIPOLYGON(((779236.435553 5942074.072431," + "890555.926346 5942074.072431,890555.926346 6106854.834885,779236.435553 6106854.834885," + "779236.435553 5942074.072431)),((890555.926346 6106854.834885,1001875.417139 6106854.834885," + "1001875.417139 6274861.394007,890555.926346 6274861.394007,890555.926346 6106854.834885)))"); + + // MULTIPOLYGON (from WGS84) + util::geo::DMultiPolygon mpolyWGS84{util::geo::DPolygon{util::geo::DLine{util::geo::DPoint{48, 7}, util::geo::DPoint{48, 8}, + util::geo::DPoint{47, 8}, util::geo::DPoint{47, 7}, util::geo::DPoint{48, 7}}}, + util::geo::DPolygon{util::geo::DLine{util::geo::DPoint{49, 8}, util::geo::DPoint{49, 9}, + util::geo::DPoint{48, 9}, util::geo::DPoint{48, 8}, util::geo::DPoint{49, 8}}}}; + TEST(getWKT(mpolyWGS84, util::geo::CRSType::WGS84, util::geo::CRSType::CRS84), ==, "MULTIPOLYGON(((7 48,8 48,8 47,7 47,7 48)),((8 49,9 49,9 48,8 48,8 49)))"); + TEST(getWKT(mpolyWGS84, util::geo::CRSType::WGS84, util::geo::CRSType::WGS84), ==, + " MULTIPOLYGON(((48 7,48 8,47 8,47 7,48 7)),((49 8,49 9,48 9,48 8,49 8)))"); + TEST(getWKT(mpolyWGS84, util::geo::CRSType::WGS84, util::geo::CRSType::WEB_MERCATOR), ==, + " MULTIPOLYGON(((779236.435553 6106854.834885,890555.926346 6106854.834885,890555.926346 5942074.072431," + "779236.435553 5942074.072431,779236.435553 6106854.834885)),((890555.926346 6274861.394007,1001875.417139 6274861.394007,1001875.417139 6106854.834885," + "890555.926346 6106854.834885,890555.926346 6274861.394007)))"); + + // MULTIPOLYGON (from WebMerc) + util::geo::DMultiPolygon mpolyWebMerc{util::geo::DPolygon{util::geo::DLine{util::geo::DPoint{779236.435553, 5942074.072431}, util::geo::DPoint{890555.926346, 5942074.072431}, + util::geo::DPoint{890555.926346, 6106854.834885}, util::geo::DPoint{779236.435553, 6106854.834885}, util::geo::DPoint{779236.435553, 5942074.072431}}}, + util::geo::DPolygon{util::geo::DLine{util::geo::DPoint{890555.926346, 6106854.834885}, util::geo::DPoint{1001875.417139, 6106854.834885}, + util::geo::DPoint{1001875.417139, 6274861.394007}, util::geo::DPoint{890555.926346, 6274861.394007}, util::geo::DPoint{890555.926346, 6106854.834885}}}}; + TEST(getWKT(mpolyWebMerc, util::geo::CRSType::WEB_MERCATOR, util::geo::CRSType::CRS84), ==, "MULTIPOLYGON(((7 47,8 47,8 48,7 48,7 47)),((8 48,9 48,9 49,8 49,8 48)))"); + TEST(getWKT(mpolyWebMerc, util::geo::CRSType::WEB_MERCATOR, util::geo::CRSType::WGS84), ==, + " MULTIPOLYGON(((47 7,47 8,48 8,48 7,47 7))," + "((48 8,48 9,49 9,49 8,48 8)))"); + TEST(getWKT(mpolyWebMerc, util::geo::CRSType::WEB_MERCATOR, util::geo::CRSType::WEB_MERCATOR), ==, + " MULTIPOLYGON(((779236.435553 5942074.072431," + "890555.926346 5942074.072431,890555.926346 6106854.834885,779236.435553 6106854.834885," + "779236.435553 5942074.072431)),((890555.926346 6106854.834885,1001875.417139 6106854.834885," + "1001875.417139 6274861.394007,890555.926346 6274861.394007,890555.926346 6106854.834885)))"); + + // COLLECTION + auto projCRS84_7 = util::geo::collectionFromWKT( + " GEOMETRYCOLLECTION(POINT(7 47)," + " LINESTRING(7 47, 8 48), POLYGON((7 47, 8 47, 8 48, 7 48, 7 47)))"); + TEST(getWKT(projCRS84_7, util::geo::CRSType::CRS84, util::geo::CRSType::CRS84), ==, + "GEOMETRYCOLLECTION(POINT(7 47),LINESTRING(7 47,8 48),POLYGON((7 47,8 47,8 48,7 48,7 47)))"); + + auto projWGS84_7 = util::geo::collectionFromWKT( + " GEOMETRYCOLLECTION(POINT(47 7), " + "LINESTRING(47 7, 48 8), POLYGON((47 7, 47 8, 48 8, 48 7, 47 7)))"); + TEST(getWKT(projWGS84_7, util::geo::CRSType::CRS84, util::geo::CRSType::WGS84), ==, + " GEOMETRYCOLLECTION(POINT(47 7)," + "LINESTRING(47 7,48 8),POLYGON((47 7,47 8,48 8,48 7,47 7)))"); + + auto projWebMerc_7 = util::geo::collectionFromWKT( + " GEOMETRYCOLLECTION(POINT(779236.435552915 5942074.072431109)," + " LINESTRING(779236.435552915 5942074.072431109, 890555.9263461885 6106854.834885074), POLYGON((779236.435552915" + " 5942074.072431109, 890555.9263461885 5942074.072431109, 890555.9263461885 6106854.834885074, 779236.435552915 " + "6106854.834885074, 779236.435552915 5942074.072431109)))"); + TEST(getWKT(projWebMerc_7, util::geo::CRSType::CRS84, util::geo::CRSType::WEB_MERCATOR), ==, + " GEOMETRYCOLLECTION(POINT(779236.435553 5942074.072431)," + "LINESTRING(779236.435553 5942074.072431,890555.926346 6106854.834885),POLYGON((779236.435553 5942074.072431," + "890555.926346 5942074.072431,890555.926346 6106854.834885,779236.435553 6106854.834885," + "779236.435553 5942074.072431)))"); + + // COLLECTION (from WGS84) + util::geo::DCollection colWGS84{util::geo::DPoint{47, 7}, util::geo::DLine{util::geo::DPoint{47, 7}, util::geo::DPoint{48, 8}}, + util::geo::DPolygon{util::geo::DLine{util::geo::DPoint{48, 7}, util::geo::DPoint{48, 8}, + util::geo::DPoint{47, 8}, util::geo::DPoint{47, 7}, util::geo::DPoint{48, 7}}}}; + TEST(getWKT(colWGS84, util::geo::CRSType::WGS84, util::geo::CRSType::CRS84), ==, + "GEOMETRYCOLLECTION(POINT(7 47),LINESTRING(7 47,8 48),POLYGON((7 48,8 48,8 47,7 47,7 48)))"); + TEST(getWKT(colWGS84, util::geo::CRSType::WGS84, util::geo::CRSType::WGS84), ==, + " GEOMETRYCOLLECTION(POINT(47 7)," + "LINESTRING(47 7,48 8),POLYGON((48 7,48 8,47 8,47 7,48 7)))"); + TEST(getWKT(colWGS84, util::geo::CRSType::WGS84, util::geo::CRSType::WEB_MERCATOR), ==, + " GEOMETRYCOLLECTION(POINT(779236.435553 5942074.072431)," + "LINESTRING(779236.435553 5942074.072431,890555.926346 6106854.834885),POLYGON((779236.435553 6106854.834885," + "890555.926346 6106854.834885,890555.926346 5942074.072431,779236.435553 5942074.072431,779236.435553 6106854.834885)))"); + + // COLLECTION (from WebMerc) + util::geo::DCollection colWebMerc{util::geo::DPoint{779236.435553, 5942074.072431}, util::geo::DLine{util::geo::DPoint{779236.435553, 5942074.072431}, util::geo::DPoint{890555.926346, 6106854.834885}}, + util::geo::DPolygon{util::geo::DLine{util::geo::DPoint{779236.435553, 5942074.072431}, util::geo::DPoint{890555.926346, 5942074.072431}, + util::geo::DPoint{890555.926346, 6106854.834885}, util::geo::DPoint{779236.435553, 6106854.834885}, util::geo::DPoint{779236.435553, 5942074.072431}}}}; + TEST(getWKT(colWebMerc, util::geo::CRSType::WEB_MERCATOR, util::geo::CRSType::CRS84), ==, + "GEOMETRYCOLLECTION(POINT(7 47),LINESTRING(7 47,8 48),POLYGON((7 47,8 47,8 48,7 48,7 47)))"); + TEST(getWKT(colWebMerc, util::geo::CRSType::WEB_MERCATOR, util::geo::CRSType::WGS84), ==, + " GEOMETRYCOLLECTION(POINT(47 7)," + "LINESTRING(47 7,48 8),POLYGON((47 7,47 8,48 8,48 7,47 7)))"); + TEST(getWKT(colWebMerc, util::geo::CRSType::WEB_MERCATOR, util::geo::CRSType::WEB_MERCATOR), ==, + " GEOMETRYCOLLECTION(POINT(779236.435553 5942074.072431)," + "LINESTRING(779236.435553 5942074.072431,890555.926346 6106854.834885),POLYGON((779236.435553 5942074.072431," + "890555.926346 5942074.072431,890555.926346 6106854.834885,779236.435553 6106854.834885," + "779236.435553 5942074.072431)))"); + } }