From 79303f12f232f3e565860191977a39538b214db6 Mon Sep 17 00:00:00 2001 From: Patrick Brosi Date: Fri, 28 Jun 2019 15:10:15 +0200 Subject: [PATCH] update /util --- src/pfaedle/PfaedleMain.cpp | 24 +- src/util/geo/BezierCurve.h | 3 +- src/util/geo/Geo.h | 138 +- src/util/tests/TestMain.cpp | 2763 +++++++++++++++++++---------------- src/util/tests/lest.h | 145 +- 5 files changed, 1719 insertions(+), 1354 deletions(-) diff --git a/src/pfaedle/PfaedleMain.cpp b/src/pfaedle/PfaedleMain.cpp index 6a81f88..4c6e309 100644 --- a/src/pfaedle/PfaedleMain.cpp +++ b/src/pfaedle/PfaedleMain.cpp @@ -32,23 +32,11 @@ #include "util/log/Log.h" #include "util/Misc.h" -#ifndef HOME_VAR -#define HOME_VAR "HOME" +#ifndef CFG_HOME_SUFFIX +#define CFG_HOME_SUFFIX "/.config" #endif -#ifndef XDG_DATA_HOME_SUFFIX -#define XDG_DATA_HOME_SUFFIX "/.local/share" -#endif -#ifndef XDG_CONFIG_HOME_SUFFIX -#define XDG_CONFIG_HOME_SUFFIX "/.config" -#endif -#ifndef XDG_CACHE_HOME_SUFFIX -#define XDG_CACHE_HOME_SUFFIX "/.cache" -#endif -#ifndef XDG_DATA_DIRS_DEFAULT -#define XDG_DATA_DIRS_DEFAULT "/usr/local/share" -#endif -#ifndef XDG_CONFIG_DIRS_DEFAULT -#define XDG_CONFIG_DIRS_DEFAULT "/etc" +#ifndef CFG_DIR +#define CFG_DIR "/etc" #endif #ifndef CFG_FILE_NAME #define CFG_FILE_NAME "pfaedle.cfg" @@ -343,7 +331,7 @@ std::vector getCfgPaths(const Config& cfg) { // install prefix global configuration path, if available { auto path = std::string(INSTALL_PREFIX) + - std::string(XDG_CONFIG_DIRS_DEFAULT) + "/" + "pfaedle" + "/" + + std::string(CFG_DIR) + "/" + "pfaedle" + "/" + CFG_FILE_NAME; std::ifstream is(path); @@ -356,7 +344,7 @@ std::vector getCfgPaths(const Config& cfg) { // local user configuration path, if available { - auto path = util::getHomeDir() + XDG_CONFIG_HOME_SUFFIX + "/" + + auto path = util::getHomeDir() + CFG_HOME_SUFFIX + "/" + "pfaedle" + "/" + CFG_FILE_NAME; std::ifstream is(path); diff --git a/src/util/geo/BezierCurve.h b/src/util/geo/BezierCurve.h index f3d25c5..23f3263 100644 --- a/src/util/geo/BezierCurve.h +++ b/src/util/geo/BezierCurve.h @@ -27,7 +27,8 @@ struct CubicPolynom { template class BezierCurve { public: - BezierCurve(const Point& a, const Point& b, const Point& c, const Point& d); + BezierCurve(const Point& a, const Point& b, const Point& c, + const Point& d); const PolyLine& render(double d); diff --git a/src/util/geo/Geo.h b/src/util/geo/Geo.h index 679d9cd..1cb696e 100644 --- a/src/util/geo/Geo.h +++ b/src/util/geo/Geo.h @@ -243,15 +243,21 @@ inline bool doubleEq(double a, double b) { return fabs(a - b) < EPSILON; } // _____________________________________________________________________________ template inline bool contains(const Point& p, const Box& box) { - return p.getX() >= box.getLowerLeft().getX() && - p.getX() <= box.getUpperRight().getX() && - p.getY() >= box.getLowerLeft().getY() && - p.getY() <= box.getUpperRight().getY(); + // check if point lies in box + return (fabs(p.getX() - box.getLowerLeft().getX()) < EPSILON || + p.getX() > box.getLowerLeft().getX()) && + (fabs(p.getX() - box.getUpperRight().getX()) < EPSILON || + p.getX() < box.getUpperRight().getX()) && + (fabs(p.getY() - box.getLowerLeft().getY()) < EPSILON || + p.getY() > box.getLowerLeft().getY()) && + (fabs(p.getY() - box.getUpperRight().getY()) < EPSILON || + p.getY() < box.getUpperRight().getY()); } // _____________________________________________________________________________ template inline bool contains(const Line& l, const Box& box) { + // check if line lies in box for (const auto& p : l) if (!contains(p, box)) return false; return true; @@ -260,24 +266,35 @@ inline bool contains(const Line& l, const Box& box) { // _____________________________________________________________________________ template inline bool contains(const LineSegment& l, const Box& box) { + // check if line segment lies in box return contains(l.first, box) && contains(l.second, box); } // _____________________________________________________________________________ template inline bool contains(const Box& b, const Box& box) { + // check if box b lies in box return contains(b.getLowerLeft(), box) && contains(b.getUpperRight(), box); } // _____________________________________________________________________________ template inline bool contains(const Point& p, const LineSegment& ls) { + // check if point p lies in (on) line segment ls return fabs(crossProd(p, ls)) < EPSILON && contains(p, getBoundingBox(ls)); } +// _____________________________________________________________________________ +template +inline bool contains(const LineSegment& a, const LineSegment& b) { + // check if line segment a is contained in line segment b + return contains(a.first, b) && contains(a.second, b); +} + // _____________________________________________________________________________ template inline bool contains(const Point& p, const Line& l) { + // check if point p lies in line l for (size_t i = 1; i < l.size(); i++) { if (contains(p, LineSegment(l[i - 1], l[i]))) return true; } @@ -287,6 +304,8 @@ inline bool contains(const Point& p, const Line& l) { // _____________________________________________________________________________ template inline bool contains(const Point& p, const Polygon& poly) { + // check if point p lies in polygon + // see https://de.wikipedia.org/wiki/Punkt-in-Polygon-Test_nach_Jordan int8_t c = -1; @@ -328,19 +347,53 @@ inline int8_t polyContCheck(const Point& a, Point b, Point c) { // _____________________________________________________________________________ template inline bool contains(const Polygon& polyC, const Polygon& poly) { - for (const auto& p : polyC.getOuter()) { - if (!contains(p, poly)) { + // check if polygon polyC lies in polygon poly + + for (size_t i = 1; i < polyC.getOuter().size(); i++) { + if (!contains(LineSegment(polyC.getOuter()[i - 1], polyC.getOuter()[i]), + poly)) + return false; + } + + // also check the last hop + if (!contains(LineSegment(polyC.getOuter().back(), polyC.getOuter().front()), + poly)) + return false; + + return true; +} + +// _____________________________________________________________________________ +template +inline bool contains(const LineSegment& ls, const Polygon& p) { + // check if linesegment ls lies in polygon poly + + // if one of the endpoints lies outside, abort + if (!contains(ls.first, p)) return false; + if (!contains(ls.second, p)) return false; + + for (size_t i = 1; i < p.getOuter().size(); i++) { + auto seg = LineSegment(p.getOuter()[i - 1], p.getOuter()[i]); + if (!(contains(ls.first, seg) || contains(ls.second, seg)) && + intersects(seg, ls)) { return false; } } + + auto seg = LineSegment(p.getOuter().back(), p.getOuter().front()); + if (!(contains(ls.first, seg) || contains(ls.second, seg)) && + intersects(seg, ls)) { + return false; + } + return true; } // _____________________________________________________________________________ template inline bool contains(const Line& l, const Polygon& poly) { - for (const auto& p : l) { - if (!contains(p, poly)) { + for (size_t i = 1; i < l.size(); i++) { + if (!contains(LineSegment(l[i - 1], l[i]), poly)) { return false; } } @@ -351,9 +404,7 @@ inline bool contains(const Line& l, const Polygon& poly) { template inline bool contains(const Line& l, const Line& other) { for (const auto& p : l) { - if (!contains(p, other)) { - return false; - } + if (!contains(p, other)) return false; } return true; } @@ -361,17 +412,13 @@ inline bool contains(const Line& l, const Line& other) { // _____________________________________________________________________________ template inline bool contains(const Box& b, const Polygon& poly) { - return contains(b.getLowerLeft(), poly) && - contains(b.getUpperRight(), poly) && - contains(Point(b.getUpperRight().getX(), b.getLowerLeft().getY()), - poly) && - contains(Point(b.getLowerLeft().getX(), b.getUpperRight().getY()), - poly); + return contains(convexHull(b), poly); } // _____________________________________________________________________________ template inline bool contains(const Polygon& poly, const Box& b) { + // check of poly lies in box for (const auto& p : poly.getOuter()) { if (!contains(p, b)) return false; } @@ -400,6 +447,8 @@ inline bool contains(const std::vector>& multigeo, // _____________________________________________________________________________ template inline bool intersects(const LineSegment& ls1, const LineSegment& ls2) { + // check if two linesegments intersect + // two line segments intersect of there is a single, well-defined intersection // point between them. If more than 1 endpoint is colinear with any line, // the segments have infinite intersections. We handle this case as non- @@ -468,6 +517,39 @@ inline bool intersects(const Box& b1, const Box& b2) { b1.getUpperRight().getY() >= b2.getLowerLeft().getY(); } +// _____________________________________________________________________________ +template +inline bool intersects(const Box& b, const Polygon& poly) { + return intersects(b, poly); +} + +// _____________________________________________________________________________ +template +inline bool intersects(const Polygon& poly, const Box& b) { + if (intersects( + LineSegment(b.getLowerLeft(), Point(b.getUpperRight().getX(), + b.getLowerLeft().getY())), + poly)) + return true; + if (intersects( + LineSegment(b.getLowerLeft(), Point(b.getLowerLeft().getX(), + b.getUpperRight().getY())), + poly)) + return true; + if (intersects( + LineSegment(b.getUpperRight(), Point(b.getLowerLeft().getX(), + b.getUpperRight().getY())), + poly)) + return true; + if (intersects( + LineSegment(b.getUpperRight(), Point(b.getUpperRight().getX(), + b.getLowerLeft().getY())), + poly)) + return true; + + return contains(poly, b) || contains(b, poly); +} + // _____________________________________________________________________________ template inline bool intersects(const LineSegment& ls, const Box& b) { @@ -499,6 +581,7 @@ inline bool intersects(const LineSegment& ls, const Polygon& p) { return true; } + // also check the last hop if (intersects(LineSegment(p.getOuter().back(), p.getOuter().front()), ls)) return true; @@ -1186,7 +1269,7 @@ inline Polygon convexHull(const RotatedBox& b) { // _____________________________________________________________________________ template inline size_t convexHullImpl(const MultiPoint& a, size_t p1, size_t p2, - Line* h, uint8_t d) { + Line* h) { // quickhull by Barber, Dobkin & Huhdanpaa Point pa; bool found = false; @@ -1194,7 +1277,7 @@ inline size_t convexHullImpl(const MultiPoint& a, size_t p1, size_t p2, for (const auto& p : a) { double tmpDist = distToSegment((*h)[p1], (*h)[p2], p); double cp = crossProd(p, LineSegment((*h)[p1], (*h)[p2])); - if (((cp > 0 && !d) || (cp < 0 && d)) && tmpDist >= maxDist + EPSILON) { + if ((cp > 0) && tmpDist > maxDist) { pa = p; found = true; maxDist = tmpDist; @@ -1203,9 +1286,9 @@ inline size_t convexHullImpl(const MultiPoint& a, size_t p1, size_t p2, if (!found) return 0; - h->insert(h->begin() + p2 + !d, pa); - size_t in = 1 + convexHullImpl(a, p1, p2 + !d, h, d); - return in + convexHullImpl(a, p2 + in * d + 1 - 2 * d, p2 + in * d, h, d); + h->insert(h->begin() + p2, pa); + size_t in = 1 + convexHullImpl(a, p1, p2, h); + return in + convexHullImpl(a, p2 + in - 1, p2 + in, h); } // _____________________________________________________________________________ @@ -1217,13 +1300,16 @@ inline Polygon convexHull(const MultiPoint& l) { Point left(std::numeric_limits::max(), 0); Point right(std::numeric_limits::lowest(), 0); for (const auto& p : l) { - if (p.getX() <= left.getX()) left = p; - if (p.getX() >= right.getX()) right = p; + if (p.getX() < left.getX()) left = p; + if (p.getX() > right.getX()) right = p; } Line hull{left, right}; - convexHullImpl(l, 0, 1, &hull, 1); - convexHullImpl(l, 0, hull.size() - 1, &hull, 0); + convexHullImpl(l, 0, 1, &hull); + hull.push_back(hull.front()); + convexHullImpl(l, hull.size() - 2, hull.size() - 1, &hull); + hull.pop_back(); + return Polygon(hull); } diff --git a/src/util/tests/TestMain.cpp b/src/util/tests/TestMain.cpp index d7590d3..f03285b 100644 --- a/src/util/tests/TestMain.cpp +++ b/src/util/tests/TestMain.cpp @@ -3,1328 +3,1400 @@ // #include -#include "lest.h" +#include "util/Misc.h" #include "util/Nullable.h" #include "util/String.h" #include "util/geo/Geo.h" -#include "util/json/Writer.h" -#include "util/graph/Algorithm.h" -#include "util/graph/DirGraph.h" -#include "util/graph/UndirGraph.h" -#include "util/graph/Dijkstra.h" -#include "util/graph/EDijkstra.h" #include "util/geo/Grid.h" -#include "util/Misc.h" +#include "util/graph/Algorithm.h" +#include "util/graph/Dijkstra.h" +#include "util/graph/DirGraph.h" +#include "util/graph/EDijkstra.h" +#include "util/graph/UndirGraph.h" +#include "util/json/Writer.h" -using lest::approx; using namespace util; using namespace util::geo; using namespace util::graph; -// define LEST cases -const lest::test specification[] = { +class approx { + public: + explicit approx(double magnitude) + : _epsilon{std::numeric_limits::epsilon() * 100}, + _magnitude{magnitude} {} -// ___________________________________________________________________________ -{ -CASE("atof") { - EXPECT(util::atof("45.534215") == approx(45.534215)); - EXPECT(util::atof("5.534") == approx(5.534)); - EXPECT(util::atof("534") == approx(534)); - EXPECT(util::atof("-534") == approx(-534)); - EXPECT(util::atof("-45.534215") == approx(-45.534215)); - EXPECT(util::atof("-45.534215", 2) == approx(-45.53)); - - - // TODO: more test cases -}}, - -// ___________________________________________________________________________ -{ -CASE("json") { - std::stringstream ss; - util::json::Writer wr(&ss, 2, false); - - util::json::Val a("bla"); - util::json::Val b(1); - util::json::Val c(1.0); - util::json::Val d("a"); - util::json::Val e({"a", "b", "c"}); - - util::json::Val f({1, json::Array{2, 3, 4}, 3}); - - ss.str(""); - wr = util::json::Writer(&ss, 2, false); - util::json::Val i({1, json::Array{2, json::Null(), 4}, true}); - wr.val(i); - wr.closeAll(); - EXPECT(ss.str() == "[1,[2,null,4],true]"); - - ss.str(""); - wr = util::json::Writer(&ss, 2, false); - i = util::json::Val({1, json::Array{2, json::Null(), 4}, false}); - wr.val(i); - wr.closeAll(); - EXPECT(ss.str() == "[1,[2,null,4],false]"); - - ss.str(""); - wr = util::json::Writer(&ss, 2, false); - i = util::json::Val({1, json::Array{2, json::Null(), 4}, false}); - wr.val(i); - wr.closeAll(); - EXPECT(ss.str() == "[1,[2,null,4],false]"); - - ss.str(""); - wr = util::json::Writer(&ss, 2, false); - i = util::json::Val({1, json::Array{2.13, "", 4}, 0}); - wr.val(i); - wr.closeAll(); - EXPECT(ss.str() == "[1,[2.13,\"\",4],0]"); - - ss.str(""); - wr = util::json::Writer(&ss, 2, false); - i = util::json::Val({1, json::Array{2.13, json::Dict{{"a", 1}, {"B", 2.123}}, 4}, 0}); - wr.val(i); - wr.closeAll(); - EXPECT((ss.str() == "[1,[2.13,{\"a\":1,\"B\":2.12},4],0]" || ss.str() == "[1,[2.13,{\"B\":2.12,\"a\":1},4],0]")); -}}, - -// ___________________________________________________________________________ -{ -CASE("dirgraph") { - DirGraph g; - - DirNode* a = new DirNode(0); - DirNode* b = new DirNode(0); - g.addNd(a); - EXPECT(g.getNds()->size() == (size_t)1); - g.addNd(b); - EXPECT(g.getNds()->size() == (size_t)2); - - g.addEdg(a, b); - EXPECT(a->getDeg() == (size_t)1); - EXPECT(b->getDeg() == (size_t)0); - - auto c = g.addNd(); - - g.addEdg(a, c); - g.addEdg(c, b); - EXPECT(a->getDeg() == (size_t)2); - EXPECT(b->getDeg() == (size_t)0); - EXPECT(c->getDeg() == (size_t)1); - - g.delEdg(a, c); - - EXPECT(a->getDeg() == (size_t)1); - EXPECT(b->getDeg() == (size_t)0); - EXPECT(c->getDeg() == (size_t)1); - - g.addEdg(a, a); - EXPECT(a->getDeg() == (size_t)2); - - g.delEdg(a, a); - EXPECT(a->getDeg() == (size_t)1); - - g.delEdg(a, a); - EXPECT(a->getDeg() == (size_t)1); - - // TODO: more test cases -}}, - -// ___________________________________________________________________________ -{ -CASE("unddirgraph") { - UndirGraph g; - - UndirNode* a = new UndirNode(0); - UndirNode* b = new UndirNode(0); - g.addNd(a); - EXPECT(g.getNds()->size() == (size_t)1); - g.addNd(b); - EXPECT(g.getNds()->size() == (size_t)2); - - g.addEdg(a, b); - EXPECT(a->getDeg() == (size_t)1); - EXPECT(b->getDeg() == (size_t)1); - - auto c = g.addNd(); - - g.addEdg(a, c); - g.addEdg(c, b); - EXPECT(a->getDeg() == (size_t)2); - EXPECT(b->getDeg() == (size_t)2); - EXPECT(c->getDeg() == (size_t)2); - - g.delEdg(a, c); - - EXPECT(a->getDeg() == (size_t)1); - EXPECT(b->getDeg() == (size_t)2); - EXPECT(c->getDeg() == (size_t)1); - - g.delNd(b); - - EXPECT(a->getDeg() == (size_t)0); - EXPECT(c->getDeg() == (size_t)0); - - g.addEdg(a, a); - EXPECT(a->getDeg() == (size_t)1); - - g.delEdg(a, a); - EXPECT(a->getDeg() == (size_t)0); - - // TODO: more test cases - -}}, - -// ___________________________________________________________________________ -{ -CASE("grid") { - Grid g(.5, .5, Box(Point(0, 0), Point(3, 3))); - - Line l; - l.push_back(Point(0, 0)); - l.push_back(Point(1.5, 2)); - - Line l2; - l2.push_back(Point(2.5, 1)); - l2.push_back(Point(2.5, 2)); - - g.add(l, 1); - g.add(l2, 2); - - std::set ret; - - Box req(Point(.5, 1), Point(1, 1.5)); - g.get(req, &ret); - EXPECT(ret.size() == (size_t)1); - - ret.clear(); - g.getNeighbors(1, 0, &ret); - EXPECT(ret.size() == (size_t)1); - - ret.clear(); - g.getNeighbors(1, 0.55, &ret); - EXPECT(ret.size() == (size_t)2); - - - // TODO: more test cases -}}, - -// ___________________________________________________________________________ -{ -CASE("densify") { - Line a; - a.push_back(Point(1, 1)); - a.push_back(Point(10, 1)); - - auto dense = util::geo::densify(a, 1); - - EXPECT(dense.size() == (size_t)10); - - for (int i = 0; i < 10; i++) { - EXPECT(dense[i].getX() == approx(i + 1.0)); + friend bool operator==(double lhs, approx const& rhs) { + return std::abs(lhs - rhs._magnitude) < rhs._epsilon; } - dense = util::geo::simplify(dense, 0.1); - EXPECT(dense.size() == (size_t)2); - - Line b; - b.push_back(Point(1, 1)); - b.push_back(Point(5, 7)); - b.push_back(Point(10, 3)); - - dense = util::geo::densify(b, 1); - - dense = util::geo::simplify(dense, 0.1); - EXPECT(dense.size() == (size_t)3); -}}, - -// ___________________________________________________________________________ -{ -CASE("summed frechet distance") { - Line a; - a.push_back(Point(1, 1)); - a.push_back(Point(2, 1)); - a.push_back(Point(3, 1)); - a.push_back(Point(3, 2)); - a.push_back(Point(4, 2)); - a.push_back(Point(4, 1)); - a.push_back(Point(5, 1)); - a.push_back(Point(6, 1)); - - Line b; - b.push_back(Point(1, 1)); - b.push_back(Point(2, 1)); - b.push_back(Point(3, 1)); - b.push_back(Point(4, 1)); - b.push_back(Point(5, 1)); - b.push_back(Point(6, 1)); - - double fd = util::geo::accFrechetDistC(a, b, 0.1); - EXPECT(fd == approx(2)); -}}, - -// ___________________________________________________________________________ -{ -CASE("frechet distance") { - Line e; - e.push_back(Point(1, 1)); - e.push_back(Point(1, 2)); - - Line f; - f.push_back(Point(1, 1)); - f.push_back(Point(1, 2)); - - double fd = util::geo::frechetDist(e, f, 0.1); - - EXPECT(fd == approx(0)); - - Line a; - a.push_back(Point(1, 1)); - a.push_back(Point(2, 1)); - a.push_back(Point(3, 2)); - a.push_back(Point(4, 2)); - a.push_back(Point(5, 1)); - a.push_back(Point(6, 1)); - - Line b; - b.push_back(Point(1, 1)); - b.push_back(Point(2, 1)); - b.push_back(Point(3, 1)); - b.push_back(Point(4, 1)); - b.push_back(Point(5, 1)); - b.push_back(Point(6, 1)); - - auto adense = util::geo::densify(a, 0.1); - auto bdense = util::geo::densify(b, 0.1); - - fd = util::geo::frechetDist(a, b, 0.1); - - EXPECT(fd == approx(1)); - - Line c; - c.push_back(Point(1, 1)); - c.push_back(Point(2, 1)); - - Line d; - d.push_back(Point(3, 1)); - d.push_back(Point(4, 1)); - - fd = util::geo::frechetDist(c, d, 0.1); - - EXPECT(fd == approx(2)); - - - Line g; - g.push_back(Point(1, 1)); - g.push_back(Point(10, 1)); - - Line h; - h.push_back(Point(1, 1)); - h.push_back(Point(3, 2)); - h.push_back(Point(3, 1)); - h.push_back(Point(10, 1)); - - fd = util::geo::frechetDist(g, h, 0.1); - - EXPECT(fd == approx(1)); -}}, - -// ___________________________________________________________________________ -{ -CASE("geo box alignment") { - Line a; - a.push_back(Point(1, 1)); - a.push_back(Point(1, 2)); - - Line b; - b.push_back(Point(1, 2)); - b.push_back(Point(2, 2)); - - Line c; - c.push_back(Point(2, 2)); - c.push_back(Point(2, 1)); - - Line d; - d.push_back(Point(2, 1)); - d.push_back(Point(1, 1)); - - Box box(Point(2, 3), Point(5, 4)); - MultiLine ml; - ml.push_back(a); - ml.push_back(b); - ml.push_back(c); - ml.push_back(d); - - EXPECT(parallelity(box, ml) == approx(1)); - ml = rotate(ml, 45); - EXPECT(parallelity(box, ml) == approx(0)); - ml = rotate(ml, 45); - EXPECT(parallelity(box, ml) == approx(1)); - ml = rotate(ml, 45); - EXPECT(parallelity(box, ml) == approx(0)); - ml = rotate(ml, 45); - EXPECT(parallelity(box, ml) == approx(1)); -}}, - -// ___________________________________________________________________________ -{ -CASE("url decode") { - EXPECT("zürich" == util::urlDecode("z%C3%BCrich")); - EXPECT("!@$%^*()" == util::urlDecode("!%40%24%25%5E*()")); - EXPECT("Løkken" == util::urlDecode("L%C3%B8kken")); - EXPECT("á é" == util::urlDecode("%C3%A1%20%C3%A9")); - EXPECT("á é" == util::urlDecode("%C3%A1+%C3%A9")); -}}, - -// ___________________________________________________________________________ -{ -CASE("json escape") { - EXPECT("Hello\\\\Goodbye!" == util::jsonStringEscape("Hello\\Goodbye!")); - EXPECT("\\\"Hello\\\"" == util::jsonStringEscape("\"Hello\"")); -}}, - -// ___________________________________________________________________________ -{ -CASE("split") { - EXPECT(util::split("hello,again", ',').size() == (size_t)2); - EXPECT(util::split("hello,,again", ',').size() == (size_t)3); - EXPECT(util::split("hello", ',').size() == (size_t)1); - EXPECT(util::split("", ',').size() == (size_t)0); -}}, - -// ___________________________________________________________________________ -{ -CASE("editdist") { - EXPECT(util::editDist("hello", "mello") == (size_t)1); - EXPECT(util::editDist("mello", "hello") == (size_t)1); - EXPECT(util::editDist("abcde", "abfde") == (size_t)1); - EXPECT(util::editDist("abcd", "abcde") == (size_t)1); - EXPECT(util::editDist("xabcd", "abcde") == (size_t)2); - EXPECT(util::editDist("abcd", "abcdes") == (size_t)2); - EXPECT(util::editDist("hello", "hello") == (size_t)0); -}}, - -// ___________________________________________________________________________ -{ -CASE("prefixeditdist") { - EXPECT(util::prefixEditDist("hello", "hello", 0) == (size_t)0); - EXPECT(util::prefixEditDist("hello", "hello", 100) == (size_t)0); - EXPECT(util::prefixEditDist("hello", "hello") == (size_t)0); - EXPECT(util::prefixEditDist("hel", "hello") == (size_t)0); - EXPECT(util::prefixEditDist("hel", "hello", 0) == (size_t)0); - EXPECT(util::prefixEditDist("hel", "hello", 1) == (size_t)0); - EXPECT(util::prefixEditDist("hel", "hello", 2) == (size_t)0); - EXPECT(util::prefixEditDist("hal", "hello", 2) == (size_t)1); - EXPECT(util::prefixEditDist("hal", "hello", 1) == (size_t)1); - EXPECT(util::prefixEditDist("hal", "hello", 0) > (size_t)0); - EXPECT(util::prefixEditDist("fel", "hello", 0) > (size_t)0); - EXPECT(util::prefixEditDist("fel", "hello", 1) == (size_t)1); - EXPECT(util::prefixEditDist("fel", "hello", 2) == (size_t)1); - EXPECT(util::prefixEditDist("fal", "hello", 2) == (size_t)2); - EXPECT(util::prefixEditDist("fal", "hello", 1) > (size_t)1); - EXPECT(util::prefixEditDist("fal", "hello", 0) > (size_t)0); - EXPECT(util::prefixEditDist("far", "hello", 0) > (size_t)0); - EXPECT(util::prefixEditDist("far", "hello", 1) > (size_t)1); - EXPECT(util::prefixEditDist("far", "hello", 2) > (size_t)2); - EXPECT(util::prefixEditDist("far", "hello", 3) == (size_t)3); - EXPECT(util::prefixEditDist("far", "hello", 4) == (size_t)3); - EXPECT(util::prefixEditDist("far", "hello") == (size_t)3); - EXPECT(util::prefixEditDist("hefar", "hello") == (size_t)3); - EXPECT(util::prefixEditDist("hefaree", "hello") == (size_t)5); - EXPECT(util::prefixEditDist("helloo", "hello") == (size_t)1); - EXPECT(util::prefixEditDist("helloo", "hello", 0) > (size_t)0); - EXPECT(util::prefixEditDist("helloo", "hello", 1) == (size_t)1); - EXPECT(util::prefixEditDist("helloo", "hello", 2) == (size_t)1); - EXPECT(util::prefixEditDist("", "hello", 2) == (size_t)0); - EXPECT(util::prefixEditDist("e", "hello", 2) == (size_t)1); - EXPECT(util::prefixEditDist("el", "hello", 2) == (size_t)1); - EXPECT(util::prefixEditDist("ello", "hello", 2) == (size_t)1); - EXPECT(util::prefixEditDist("hell", "hello", 2) == (size_t)0); - EXPECT(util::prefixEditDist("hell", "", 2) > (size_t)2); - EXPECT(util::prefixEditDist("hell", "") == (size_t)4); -}}, - -// ___________________________________________________________________________ -{ -CASE("toString") { - EXPECT(util::toString(34) == "34"); - EXPECT(util::toString("34") == "34"); -}}, - -// ___________________________________________________________________________ -{ -CASE("replace") { - std::string a("lorem ipsum ipsum lorem"); - - EXPECT(util::replace(a, "ips", "aa")); - EXPECT(a == "lorem aaum ipsum lorem"); - - EXPECT(!util::replace(a, "blablabla", "")); - EXPECT(a == "lorem aaum ipsum lorem"); - - EXPECT(util::replace(a, "m", "")); - EXPECT(a == "lore aaum ipsum lorem"); - - EXPECT(!util::replace(a, "", "")); - EXPECT(a == "lore aaum ipsum lorem"); - - std::string b("lorem ipsum ipsum lorem"); - EXPECT(util::replaceAll(b, "ips", "aa")); - EXPECT(b == "lorem aaum aaum lorem"); - - EXPECT(util::replaceAll(b, "m", "")); - EXPECT(b == "lore aau aau lore"); - - EXPECT(util::replaceAll(b, "a", "aa")); - EXPECT(b == "lore aaaau aaaau lore"); - - EXPECT(util::replaceAll(b, "e", "e")); - EXPECT(b == "lore aaaau aaaau lore"); - - EXPECT(util::replaceAll(b, "e", "ee")); - EXPECT(b == "loree aaaau aaaau loree"); - - EXPECT(!util::replaceAll(b, "", "ee")); - EXPECT(b == "loree aaaau aaaau loree"); -}}, - -// ___________________________________________________________________________ -{ -CASE("Connected components undirected") { - UndirGraph g; - - auto a = g.addNd("A"); - auto b = g.addNd("B"); - auto c = g.addNd("C"); - auto d = g.addNd("D"); - auto e = g.addNd("E"); - - g.addEdg(a, c, 1); - g.addEdg(a, b, 5); - g.addEdg(d, c, 1); - g.addEdg(d, b, 3); - g.addEdg(e, d, 1); - g.addEdg(e, b, 1); - - auto comps = util::graph::Algorithm::connectedComponents(g); - - EXPECT(comps.size() == static_cast(1)); - EXPECT(comps[0].count(a)); - EXPECT(comps[0].count(b)); - EXPECT(comps[0].count(c)); - EXPECT(comps[0].count(d)); - EXPECT(comps[0].count(e)); - - auto f = g.addNd("F"); - comps = util::graph::Algorithm::connectedComponents(g); - EXPECT(comps.size() == static_cast(2)); - - auto gn = g.addNd("G"); - comps = util::graph::Algorithm::connectedComponents(g); - EXPECT(comps.size() == static_cast(3)); - - g.addEdg(f, gn, 1); - comps = util::graph::Algorithm::connectedComponents(g); - EXPECT(comps.size() == static_cast(2)); - - g.addEdg(f, a, 1); - comps = util::graph::Algorithm::connectedComponents(g); - EXPECT(comps.size() == static_cast(1)); - -}}, - -// ___________________________________________________________________________ -{ -CASE("Edge-based Dijkstra directed, 1 to all") { - DirGraph g; - - auto a = g.addNd("A"); - auto b = g.addNd("B"); - auto c = g.addNd("C"); - auto d = g.addNd("D"); - auto e = g.addNd("E"); - - auto eAC = g.addEdg(a, c, 1); - auto eAB = g.addEdg(a, b, 5); - auto eDC = g.addEdg(d, c, 1); - auto eDB = g.addEdg(d, b, 3); - auto eED = g.addEdg(e, d, 1); - auto eEB = g.addEdg(e, b, 1); - - - UNUSED(eAC); - UNUSED(eDC); - UNUSED(eDB); - UNUSED(eED); - UNUSED(eEB); - - struct CostFunc : public EDijkstra::CostFunc { - int operator()(const Edge* from, - const Node* n, - const Edge* to) const { - UNUSED(from); - - // dont count cost of start edge - if (n) return to->pl(); - return 0; - }; - int inf() const { return 999; }; - }; - - CostFunc cFunc; - - auto cost = EDijkstra::shortestPath(eAB, cFunc); - - for (auto u : cost) { - int single = EDijkstra::shortestPath(eAB, u.first, cFunc); - EXPECT(single == u.second); + friend bool operator==(approx const& lhs, double rhs) { + return operator==(rhs, lhs); + } + friend bool operator!=(double lhs, approx const& rhs) { + return !operator==(lhs, rhs); + } + friend bool operator!=(approx const& lhs, double rhs) { + return !operator==(rhs, lhs); } - // all to 1 - auto eBC = g.addEdg(b, c, 10); - - auto costb = EDijkstra::shortestPathRev(eBC, cFunc); - for (auto u : costb) { - int single = EDijkstra::shortestPath(u.first, eBC, cFunc); - EXPECT(single == u.second); + friend bool operator<=(double lhs, approx const& rhs) { + return lhs < rhs._magnitude || lhs == rhs; } -}}, - -// ___________________________________________________________________________ -{ -CASE("Edge-based Dijkstra undirected, edge 1 to 1") { - UndirGraph g; - - auto a = g.addNd("A"); - auto b = g.addNd("B"); - auto c = g.addNd("C"); - auto d = g.addNd("D"); - auto e = g.addNd("E"); - - auto eAC = g.addEdg(a, c, 1); - auto eAB = g.addEdg(a, b, 5); - auto eDC = g.addEdg(d, c, 1); - auto eDB = g.addEdg(d, b, 3); - auto eED = g.addEdg(e, d, 1); - auto eEB = g.addEdg(e, b, 1); - - UNUSED(eAC); - UNUSED(eDC); - UNUSED(eDB); - UNUSED(eED); - UNUSED(eEB); - - struct CostFunc : public EDijkstra::CostFunc { - int operator()(const Edge* from, - const Node* n, - const Edge* to) const { - UNUSED(from); - - // dont count cost of start edge - if (n) return to->pl(); - return 0; - }; - int inf() const { return 999; }; - }; - - CostFunc cFunc; - - EDijkstra::NList res; - EDijkstra::EList resE; - int cost = EDijkstra::shortestPath(eAB, d, cFunc, &resE, &res); - - EXPECT(cost == 2); - - EXPECT(resE.size() == (size_t)3); - EXPECT(res.size() == (size_t)3); - EXPECT((*(res.rbegin()))->pl() == "A"); - EXPECT((*(++res.rbegin()))->pl() == "C"); - EXPECT((*(++++res.rbegin()))->pl() == "D"); - - EXPECT((*(resE.rbegin())) == eAB); - EXPECT((*(++resE.rbegin())) == eAC); - EXPECT((*(++++resE.rbegin())) == eDC); - - cost = EDijkstra::shortestPath(eAB, b, cFunc, &resE, &res); - EXPECT(cost == 0); -}}, - -// ___________________________________________________________________________ -{ -CASE("Edge-based Dijkstra undirected, edge 1 to n") { - UndirGraph g; - - auto a = g.addNd("A"); - auto b = g.addNd("B"); - auto c = g.addNd("C"); - auto d = g.addNd("D"); - auto e = g.addNd("E"); - - auto eAC = g.addEdg(a, c, 1); - auto eAB = g.addEdg(a, b, 5); - auto eDC = g.addEdg(d, c, 1); - auto eDB = g.addEdg(d, b, 3); - auto eED = g.addEdg(e, d, 1); - auto eEB = g.addEdg(e, b, 1); - - UNUSED(eAC); - UNUSED(eDC); - UNUSED(eDB); - UNUSED(eED); - UNUSED(eEB); - - struct CostFunc : public EDijkstra::CostFunc { - int operator()(const Edge* from, const Node* n, - const Edge* to) const { - UNUSED(from); - - // dont count cost of start edge - if (n) return to->pl(); - return 0; - }; - int inf() const { return 999; }; - }; - - CostFunc cFunc; - - std::set*> tos; - tos.insert(d); - tos.insert(b); - tos.insert(b); - - EDijkstra::NList res; - EDijkstra::EList resE; - int cost = EDijkstra::shortestPath(eAB, tos, cFunc, &resE, &res); - EXPECT(cost == 0); -}}, - -// ___________________________________________________________________________ -{ -CASE("Edge-based Dijkstra undirected, 1 to n") { - UndirGraph g; - - auto a = g.addNd("A"); - auto b = g.addNd("B"); - auto c = g.addNd("C"); - auto d = g.addNd("D"); - auto e = g.addNd("E"); - - g.addEdg(a, c, 1); - auto eAB = g.addEdg(a, b, 5); - auto eDC = g.addEdg(d, c, 1); - g.addEdg(d, b, 3); - auto eED = g.addEdg(e, d, 1); - g.addEdg(e, b, 1); - - struct CostFunc : public EDijkstra::CostFunc { - int operator()(const Edge* from, const Node* n, - const Edge* to) const { - UNUSED(from); - - // dont count cost of start edge - if (n) return to->pl(); - return 0; - }; - int inf() const { return 999; }; - }; - - CostFunc cFunc; - - std::set*> tos; - tos.insert(eDC); - tos.insert(eED); - - std::unordered_map*, EDijkstra::EList*> resE; - resE[eDC] = new EDijkstra::EList(); - resE[eED] = new EDijkstra::EList(); - std::unordered_map*, EDijkstra::NList*> res; - res[eDC] = new EDijkstra::NList(); - res[eED] = new EDijkstra::NList(); - auto hFunc = EDijkstra::ZeroHeurFunc(); - std::unordered_map*, int> cost = EDijkstra::shortestPath(eAB, tos, cFunc, hFunc, resE, res); - - EXPECT(cost[eDC] == 2); - EXPECT(cost[eED] == 2); - - EXPECT(resE[eDC]->size() == (size_t)3); - EXPECT(res[eED]->size() == (size_t)3); - - EXPECT(resE[eDC]->size() == (size_t)3); - EXPECT(res[eED]->size() == (size_t)3); -}}, - -// ___________________________________________________________________________ -{ -CASE("Edge-based Dijkstra undirected") { - UndirGraph g; - - auto a = g.addNd("A"); - auto b = g.addNd("B"); - auto c = g.addNd("C"); - auto d = g.addNd("D"); - auto e = g.addNd("E"); - - g.addEdg(a, c, 1); - g.addEdg(a, b, 5); - g.addEdg(d, c, 1); - g.addEdg(d, b, 3); - g.addEdg(e, d, 1); - g.addEdg(e, b, 1); - - struct CostFunc : public EDijkstra::CostFunc { - int operator()(const Edge* fr, const Node* n, - const Edge* to) const { - UNUSED(fr); - UNUSED(n); - return to->pl(); - }; - int inf() const { return 999; }; - }; - - CostFunc cFunc; - - EDijkstra::NList res; - EDijkstra::EList resE; - int cost = EDijkstra::shortestPath(a, b, cFunc, &resE, &res); - - EXPECT(res.size() == (size_t)5); - EXPECT((*(res.rbegin()))->pl() == "A"); - EXPECT((*(++res.rbegin()))->pl() == "C"); - EXPECT((*(++++res.rbegin()))->pl() == "D"); - EXPECT((*(++++++res.rbegin()))->pl() == "E"); - EXPECT((*(++++++++res.rbegin()))->pl() == "B"); - EXPECT(cost == 4); - EXPECT((*(resE.rbegin()))->getFrom()->pl() == "A"); - EXPECT((*(++resE.rbegin()))->getFrom()->pl() == "D"); - EXPECT((*(++++resE.rbegin()))->getFrom()->pl() == "E"); - EXPECT((*(++++++resE.rbegin()))->getTo()->pl() == "B"); - - EXPECT(resE.size() == (size_t)4); - - cost = EDijkstra::shortestPath(d, b, cFunc, &res); - EXPECT(cost == 2); - - cost = EDijkstra::shortestPath(b, d, cFunc, &res); - EXPECT(cost == 2); - - cost = EDijkstra::shortestPath(e, b, cFunc, &res); - EXPECT(cost == 1); - - cost = EDijkstra::shortestPath(b, e, cFunc, &res); - EXPECT(cost == 1); - - cost = EDijkstra::shortestPath(b, a, cFunc, &res); - EXPECT(cost == 4); - - cost = EDijkstra::shortestPath(c, a, cFunc, &res); - EXPECT(cost == 1); - - cost = EDijkstra::shortestPath(a, c, cFunc, &res); - EXPECT(cost == 1); - - cost = EDijkstra::shortestPath(a, d, cFunc, &res); - EXPECT(cost == 2); -}}, - -// ___________________________________________________________________________ -{ -CASE("Edge-based Dijkstra") { - DirGraph g; - - DirNode* a = new DirNode(1); - DirNode* b = new DirNode(4); - g.addNd(a); - g.addNd(b); - - auto c = g.addNd(2); - auto d = g.addNd(3); - auto x = g.addNd(); - - g.addEdg(a, d, 4); - g.addEdg(a, c, 1); - g.addEdg(c, b, 1); - g.addEdg(b, d, 1); - - struct CostFunc : public EDijkstra::CostFunc { - int operator()(const Edge* fr, const Node* n, - const Edge* to) const { - UNUSED(fr); - UNUSED(n); - return to->pl(); - }; - int inf() const { return 999; }; - }; - - CostFunc cFunc; - - EDijkstra::NList res; - int cost = EDijkstra::shortestPath(a, d, cFunc, &res); - - EXPECT(cost == 3); - - g.addEdg(c, d, 3); - cost = EDijkstra::shortestPath(a, d, cFunc, &res); - - EXPECT(cost == 3); - - g.addEdg(a, b, 1); - g.addEdg(x, a, 1); - cost = EDijkstra::shortestPath(a, d, cFunc, &res); - - EXPECT(cost == 2); -}}, - -// ___________________________________________________________________________ -{ -CASE("Dijkstra") { - DirGraph g; - - DirNode* a = new DirNode(1); - DirNode* b = new DirNode(0); - g.addNd(a); - g.addNd(b); - - auto c = g.addNd(); - auto d = g.addNd(4); - auto x = g.addNd(); - - g.addEdg(a, d, 4); - g.addEdg(a, c, 1); - g.addEdg(c, b, 1); - g.addEdg(b, d, 1); - - struct CostFunc : public Dijkstra::CostFunc { - int operator()(const Node* fr, const Edge* e, - const Node* to) const { - UNUSED(fr); - UNUSED(to); - return e->pl(); - }; - int inf() const { return 999; }; - }; - - CostFunc cFunc; - - Dijkstra::NList res; - int cost = Dijkstra::shortestPath(a, d, cFunc, &res); - - EXPECT(cost == 3); - EXPECT(res.size() == (size_t)4); - - g.addEdg(c, d, 3); - cost = Dijkstra::shortestPath(a, d, cFunc, &res); - - EXPECT(cost == 3); - - g.addEdg(a, b, 1); - g.addEdg(x, a, 1); - cost = Dijkstra::shortestPath(a, d, cFunc, &res); - - EXPECT(cost == 2); - - const std::set*> to{b, c, d, x}; - std::unordered_map*, Dijkstra::EList*> resEdges; - std::unordered_map*, Dijkstra::NList*> resNodes; - - for (auto n : to) { - resEdges[n] = new Dijkstra::EList(); - resNodes[n] = new Dijkstra::NList(); + friend bool operator<=(approx const& lhs, double rhs) { + return lhs._magnitude < rhs || lhs == rhs; + } + friend bool operator>=(double lhs, approx const& rhs) { + return lhs > rhs._magnitude || lhs == rhs; + } + friend bool operator>=(approx const& lhs, double rhs) { + return lhs._magnitude > rhs || lhs == rhs; } - auto costs = Dijkstra::shortestPath(a, to, cFunc, resEdges, resNodes); + private: + double _epsilon; + double _magnitude; +}; - EXPECT(costs[b] == 1); - EXPECT(costs[c] == 1); - EXPECT(costs[d] == 2); - EXPECT(costs[x] == 999); -}}, +// _____________________________________________________________________________ +int main(int argc, char** argv) { + UNUSED(argc); + UNUSED(argv); -// ___________________________________________________________________________ -{ -CASE("nullable") { + // ___________________________________________________________________________ { - util::Nullable nullable; - EXPECT(nullable.isNull()); + assert(util::atof("45.534215") == approx(45.534215)); + assert(util::atof("5.534") == approx(5.534)); + assert(util::atof("534") == approx(534)); + assert(util::atof("-534") == approx(-534)); + assert(util::atof("-45.534215") == approx(-45.534215)); + assert(util::atof("-45.534215", 2) == approx(-45.53)); + + // TODO: more test cases } + // ___________________________________________________________________________ { - util::Nullable nullable(0); - EXPECT(nullable.isNull()); + std::stringstream ss; + util::json::Writer wr(&ss, 2, false); + + util::json::Val a("bla"); + util::json::Val b(1); + util::json::Val c(1.0); + util::json::Val d("a"); + util::json::Val e({"a", "b", "c"}); + + util::json::Val f({1, json::Array{2, 3, 4}, 3}); + + ss.str(""); + wr = util::json::Writer(&ss, 2, false); + util::json::Val i({1, json::Array{2, json::Null(), 4}, true}); + wr.val(i); + wr.closeAll(); + assert(ss.str() == "[1,[2,null,4],true]"); + + ss.str(""); + wr = util::json::Writer(&ss, 2, false); + i = util::json::Val({1, json::Array{2, json::Null(), 4}, false}); + wr.val(i); + wr.closeAll(); + assert(ss.str() == "[1,[2,null,4],false]"); + + ss.str(""); + wr = util::json::Writer(&ss, 2, false); + i = util::json::Val({1, json::Array{2, json::Null(), 4}, false}); + wr.val(i); + wr.closeAll(); + assert(ss.str() == "[1,[2,null,4],false]"); + + ss.str(""); + wr = util::json::Writer(&ss, 2, false); + i = util::json::Val({1, json::Array{2.13, "", 4}, 0}); + wr.val(i); + wr.closeAll(); + assert(ss.str() == "[1,[2.13,\"\",4],0]"); + + ss.str(""); + wr = util::json::Writer(&ss, 2, false); + i = util::json::Val( + {1, json::Array{2.13, json::Dict{{"a", 1}, {"B", 2.123}}, 4}, 0}); + wr.val(i); + wr.closeAll(); + assert((ss.str() == "[1,[2.13,{\"a\":1,\"B\":2.12},4],0]" || + ss.str() == "[1,[2.13,{\"B\":2.12,\"a\":1},4],0]")); } + // ___________________________________________________________________________ { - std::string str = "aa"; - util::Nullable nullable(&str); - EXPECT(!nullable.isNull()); + DirGraph g; - EXPECT(nullable == "aa"); - EXPECT(!(nullable == "aaa")); - EXPECT(!(nullable != "aa")); - EXPECT(nullable == "aa"); + DirNode* a = new DirNode(0); + DirNode* b = new DirNode(0); + g.addNd(a); + assert(g.getNds()->size() == (size_t)1); + g.addNd(b); + assert(g.getNds()->size() == (size_t)2); - EXPECT(nullable.get() == "aa"); - EXPECT(std::string(nullable) == "aa"); + g.addEdg(a, b); + assert(a->getDeg() == (size_t)1); + assert(b->getDeg() == (size_t)0); + + auto c = g.addNd(); + + g.addEdg(a, c); + g.addEdg(c, b); + assert(a->getDeg() == (size_t)2); + assert(b->getDeg() == (size_t)0); + assert(c->getDeg() == (size_t)1); + + g.delEdg(a, c); + + assert(a->getDeg() == (size_t)1); + assert(b->getDeg() == (size_t)0); + assert(c->getDeg() == (size_t)1); + + g.addEdg(a, a); + assert(a->getDeg() == (size_t)2); + + g.delEdg(a, a); + assert(a->getDeg() == (size_t)1); + + g.delEdg(a, a); + assert(a->getDeg() == (size_t)1); + + // TODO: more test cases } + // ___________________________________________________________________________ { - int a = 23; - util::Nullable nullable(a); - util::Nullable nullable2(24); - EXPECT(!nullable.isNull()); + UndirGraph g; - EXPECT(nullable == 23); - EXPECT(nullable >= 23); - EXPECT(nullable <= 23); - EXPECT(nullable < 24); - EXPECT(nullable < 24); - EXPECT(!(nullable < 22)); - EXPECT(nullable != nullable2); - EXPECT(nullable < nullable2); - EXPECT(nullable2 > nullable); + UndirNode* a = new UndirNode(0); + UndirNode* b = new UndirNode(0); + g.addNd(a); + assert(g.getNds()->size() == (size_t)1); + g.addNd(b); + assert(g.getNds()->size() == (size_t)2); - util::Nullable nullable3(nullable); - EXPECT(nullable == nullable3); + g.addEdg(a, b); + assert(a->getDeg() == (size_t)1); + assert(b->getDeg() == (size_t)1); - nullable3 = nullable2; - EXPECT(nullable2 == nullable3); - EXPECT(nullable3 == 24); - EXPECT(nullable2 == 24); - EXPECT(nullable2 == nullable2.get()); - EXPECT(int(nullable2) == nullable2.get()); - EXPECT(!nullable3.isNull()); - EXPECT(!nullable2.isNull()); + auto c = g.addNd(); - util::Nullable voidnull; - EXPECT(voidnull.isNull()); + g.addEdg(a, c); + g.addEdg(c, b); + assert(a->getDeg() == (size_t)2); + assert(b->getDeg() == (size_t)2); + assert(c->getDeg() == (size_t)2); - EXPECT_THROWS(nullable == voidnull); + g.delEdg(a, c); + + assert(a->getDeg() == (size_t)1); + assert(b->getDeg() == (size_t)2); + assert(c->getDeg() == (size_t)1); + + g.delNd(b); + + assert(a->getDeg() == (size_t)0); + assert(c->getDeg() == (size_t)0); + + g.addEdg(a, a); + assert(a->getDeg() == (size_t)1); + + g.delEdg(a, a); + assert(a->getDeg() == (size_t)0); + + // TODO: more test cases } -}}, + + // ___________________________________________________________________________ + { + Grid g( + .5, .5, Box(Point(0, 0), Point(3, 3))); + + Line l; + l.push_back(Point(0, 0)); + l.push_back(Point(1.5, 2)); + + Line l2; + l2.push_back(Point(2.5, 1)); + l2.push_back(Point(2.5, 2)); + + g.add(l, 1); + g.add(l2, 2); + + std::set ret; + + Box req(Point(.5, 1), Point(1, 1.5)); + g.get(req, &ret); + assert(ret.size() == (size_t)1); + + ret.clear(); + g.getNeighbors(1, 0, &ret); + assert(ret.size() == (size_t)1); + + ret.clear(); + g.getNeighbors(1, 0.55, &ret); + assert(ret.size() == (size_t)2); + + // TODO: more test cases + } + + // ___________________________________________________________________________ + { + Line a; + a.push_back(Point(1, 1)); + a.push_back(Point(10, 1)); + + auto dense = util::geo::densify(a, 1); + + assert(dense.size() == (size_t)10); + + for (int i = 0; i < 10; i++) { + assert(dense[i].getX() == approx(i + 1.0)); + } + + dense = util::geo::simplify(dense, 0.1); + assert(dense.size() == (size_t)2); + + Line b; + b.push_back(Point(1, 1)); + b.push_back(Point(5, 7)); + b.push_back(Point(10, 3)); + + dense = util::geo::densify(b, 1); + + dense = util::geo::simplify(dense, 0.1); + assert(dense.size() == (size_t)3); + } + + // ___________________________________________________________________________ + { + Line a; + a.push_back(Point(1, 1)); + a.push_back(Point(2, 1)); + a.push_back(Point(3, 1)); + a.push_back(Point(3, 2)); + a.push_back(Point(4, 2)); + a.push_back(Point(4, 1)); + a.push_back(Point(5, 1)); + a.push_back(Point(6, 1)); + + Line b; + b.push_back(Point(1, 1)); + b.push_back(Point(2, 1)); + b.push_back(Point(3, 1)); + b.push_back(Point(4, 1)); + b.push_back(Point(5, 1)); + b.push_back(Point(6, 1)); + + double fd = util::geo::accFrechetDistC(a, b, 0.1); + assert(fd == approx(2)); + } + + // ___________________________________________________________________________ + { + Line e; + e.push_back(Point(1, 1)); + e.push_back(Point(1, 2)); + + Line f; + f.push_back(Point(1, 1)); + f.push_back(Point(1, 2)); + + double fd = util::geo::frechetDist(e, f, 0.1); + + assert(fd == approx(0)); + + Line a; + a.push_back(Point(1, 1)); + a.push_back(Point(2, 1)); + a.push_back(Point(3, 2)); + a.push_back(Point(4, 2)); + a.push_back(Point(5, 1)); + a.push_back(Point(6, 1)); + + Line b; + b.push_back(Point(1, 1)); + b.push_back(Point(2, 1)); + b.push_back(Point(3, 1)); + b.push_back(Point(4, 1)); + b.push_back(Point(5, 1)); + b.push_back(Point(6, 1)); + + auto adense = util::geo::densify(a, 0.1); + auto bdense = util::geo::densify(b, 0.1); + + fd = util::geo::frechetDist(a, b, 0.1); + + assert(fd == approx(1)); + + Line c; + c.push_back(Point(1, 1)); + c.push_back(Point(2, 1)); + + Line d; + d.push_back(Point(3, 1)); + d.push_back(Point(4, 1)); + + fd = util::geo::frechetDist(c, d, 0.1); + + assert(fd == approx(2)); + + Line g; + g.push_back(Point(1, 1)); + g.push_back(Point(10, 1)); + + Line h; + h.push_back(Point(1, 1)); + h.push_back(Point(3, 2)); + h.push_back(Point(3, 1)); + h.push_back(Point(10, 1)); + + fd = util::geo::frechetDist(g, h, 0.1); + + assert(fd == approx(1)); + } + + // ___________________________________________________________________________ + { + Line a; + a.push_back(Point(1, 1)); + a.push_back(Point(1, 2)); + + Line b; + b.push_back(Point(1, 2)); + b.push_back(Point(2, 2)); + + Line c; + c.push_back(Point(2, 2)); + c.push_back(Point(2, 1)); + + Line d; + d.push_back(Point(2, 1)); + d.push_back(Point(1, 1)); + + Box box(Point(2, 3), Point(5, 4)); + MultiLine ml; + ml.push_back(a); + ml.push_back(b); + ml.push_back(c); + ml.push_back(d); + + assert(parallelity(box, ml) == approx(1)); + ml = rotate(ml, 45); + assert(parallelity(box, ml) == approx(0)); + ml = rotate(ml, 45); + assert(parallelity(box, ml) == approx(1)); + ml = rotate(ml, 45); + assert(parallelity(box, ml) == approx(0)); + ml = rotate(ml, 45); + assert(parallelity(box, ml) == approx(1)); + } + + // ___________________________________________________________________________ + { + assert("zürich" == util::urlDecode("z%C3%BCrich")); + assert("!@$%^*()" == util::urlDecode("!%40%24%25%5E*()")); + assert("Løkken" == util::urlDecode("L%C3%B8kken")); + assert("á é" == util::urlDecode("%C3%A1%20%C3%A9")); + assert("á é" == util::urlDecode("%C3%A1+%C3%A9")); + } + + // ___________________________________________________________________________ + { + assert("Hello\\\\Goodbye!" == util::jsonStringEscape("Hello\\Goodbye!")); + assert("\\\"Hello\\\"" == util::jsonStringEscape("\"Hello\"")); + } + + // ___________________________________________________________________________ + { + assert(util::split("hello,again", ',').size() == (size_t)2); + assert(util::split("hello,,again", ',').size() == (size_t)3); + assert(util::split("hello", ',').size() == (size_t)1); + assert(util::split("", ',').size() == (size_t)0); + } + + // ___________________________________________________________________________ + { + assert(util::editDist("hello", "mello") == (size_t)1); + assert(util::editDist("mello", "hello") == (size_t)1); + assert(util::editDist("abcde", "abfde") == (size_t)1); + assert(util::editDist("abcd", "abcde") == (size_t)1); + assert(util::editDist("xabcd", "abcde") == (size_t)2); + assert(util::editDist("abcd", "abcdes") == (size_t)2); + assert(util::editDist("hello", "hello") == (size_t)0); + } + + // ___________________________________________________________________________ + { + assert(util::prefixEditDist("hello", "hello", 0) == (size_t)0); + assert(util::prefixEditDist("hello", "hello", 100) == (size_t)0); + assert(util::prefixEditDist("hello", "hello") == (size_t)0); + assert(util::prefixEditDist("hel", "hello") == (size_t)0); + assert(util::prefixEditDist("hel", "hello", 0) == (size_t)0); + assert(util::prefixEditDist("hel", "hello", 1) == (size_t)0); + assert(util::prefixEditDist("hel", "hello", 2) == (size_t)0); + assert(util::prefixEditDist("hal", "hello", 2) == (size_t)1); + assert(util::prefixEditDist("hal", "hello", 1) == (size_t)1); + assert(util::prefixEditDist("hal", "hello", 0) > (size_t)0); + assert(util::prefixEditDist("fel", "hello", 0) > (size_t)0); + assert(util::prefixEditDist("fel", "hello", 1) == (size_t)1); + assert(util::prefixEditDist("fel", "hello", 2) == (size_t)1); + assert(util::prefixEditDist("fal", "hello", 2) == (size_t)2); + assert(util::prefixEditDist("fal", "hello", 1) > (size_t)1); + assert(util::prefixEditDist("fal", "hello", 0) > (size_t)0); + assert(util::prefixEditDist("far", "hello", 0) > (size_t)0); + assert(util::prefixEditDist("far", "hello", 1) > (size_t)1); + assert(util::prefixEditDist("far", "hello", 2) > (size_t)2); + assert(util::prefixEditDist("far", "hello", 3) == (size_t)3); + assert(util::prefixEditDist("far", "hello", 4) == (size_t)3); + assert(util::prefixEditDist("far", "hello") == (size_t)3); + assert(util::prefixEditDist("hefar", "hello") == (size_t)3); + assert(util::prefixEditDist("hefaree", "hello") == (size_t)5); + assert(util::prefixEditDist("helloo", "hello") == (size_t)1); + assert(util::prefixEditDist("helloo", "hello", 0) > (size_t)0); + assert(util::prefixEditDist("helloo", "hello", 1) == (size_t)1); + assert(util::prefixEditDist("helloo", "hello", 2) == (size_t)1); + assert(util::prefixEditDist("", "hello", 2) == (size_t)0); + assert(util::prefixEditDist("e", "hello", 2) == (size_t)1); + assert(util::prefixEditDist("el", "hello", 2) == (size_t)1); + assert(util::prefixEditDist("ello", "hello", 2) == (size_t)1); + assert(util::prefixEditDist("hell", "hello", 2) == (size_t)0); + assert(util::prefixEditDist("hell", "", 2) > (size_t)2); + assert(util::prefixEditDist("hell", "") == (size_t)4); + } + + // ___________________________________________________________________________ + { + assert(util::toString(34) == "34"); + assert(util::toString("34") == "34"); + } + + // ___________________________________________________________________________ + { + std::string a("lorem ipsum ipsum lorem"); + + assert(util::replace(a, "ips", "aa")); + assert(a == "lorem aaum ipsum lorem"); + + assert(!util::replace(a, "blablabla", "")); + assert(a == "lorem aaum ipsum lorem"); + + assert(util::replace(a, "m", "")); + assert(a == "lore aaum ipsum lorem"); + + assert(!util::replace(a, "", "")); + assert(a == "lore aaum ipsum lorem"); + + std::string b("lorem ipsum ipsum lorem"); + assert(util::replaceAll(b, "ips", "aa")); + assert(b == "lorem aaum aaum lorem"); + + assert(util::replaceAll(b, "m", "")); + assert(b == "lore aau aau lore"); + + assert(util::replaceAll(b, "a", "aa")); + assert(b == "lore aaaau aaaau lore"); + + assert(util::replaceAll(b, "e", "e")); + assert(b == "lore aaaau aaaau lore"); + + assert(util::replaceAll(b, "e", "ee")); + assert(b == "loree aaaau aaaau loree"); + + assert(!util::replaceAll(b, "", "ee")); + assert(b == "loree aaaau aaaau loree"); + } + + // ___________________________________________________________________________ + { + UndirGraph g; + + auto a = g.addNd("A"); + auto b = g.addNd("B"); + auto c = g.addNd("C"); + auto d = g.addNd("D"); + auto e = g.addNd("E"); + + g.addEdg(a, c, 1); + g.addEdg(a, b, 5); + g.addEdg(d, c, 1); + g.addEdg(d, b, 3); + g.addEdg(e, d, 1); + g.addEdg(e, b, 1); + + auto comps = util::graph::Algorithm::connectedComponents(g); + + assert(comps.size() == static_cast(1)); + assert(comps[0].count(a)); + assert(comps[0].count(b)); + assert(comps[0].count(c)); + assert(comps[0].count(d)); + assert(comps[0].count(e)); + + auto f = g.addNd("F"); + comps = util::graph::Algorithm::connectedComponents(g); + assert(comps.size() == static_cast(2)); + + auto gn = g.addNd("G"); + comps = util::graph::Algorithm::connectedComponents(g); + assert(comps.size() == static_cast(3)); + + g.addEdg(f, gn, 1); + comps = util::graph::Algorithm::connectedComponents(g); + assert(comps.size() == static_cast(2)); + + g.addEdg(f, a, 1); + comps = util::graph::Algorithm::connectedComponents(g); + assert(comps.size() == static_cast(1)); + } + + // ___________________________________________________________________________ + { + DirGraph g; + + auto a = g.addNd("A"); + auto b = g.addNd("B"); + auto c = g.addNd("C"); + auto d = g.addNd("D"); + auto e = g.addNd("E"); + + auto eAC = g.addEdg(a, c, 1); + auto eAB = g.addEdg(a, b, 5); + auto eDC = g.addEdg(d, c, 1); + auto eDB = g.addEdg(d, b, 3); + auto eED = g.addEdg(e, d, 1); + auto eEB = g.addEdg(e, b, 1); + + UNUSED(eAC); + UNUSED(eDC); + UNUSED(eDB); + UNUSED(eED); + UNUSED(eEB); + + struct CostFunc : public EDijkstra::CostFunc { + int operator()(const Edge* from, + const Node* n, + const Edge* to) const { + UNUSED(from); + + // dont count cost of start edge + if (n) return to->pl(); + return 0; + }; + int inf() const { return 999; }; + }; + + CostFunc cFunc; + + auto cost = EDijkstra::shortestPath(eAB, cFunc); + + for (auto u : cost) { + int single = EDijkstra::shortestPath(eAB, u.first, cFunc); + assert(single == u.second); + } + + // all to 1 + auto eBC = g.addEdg(b, c, 10); + + auto costb = EDijkstra::shortestPathRev(eBC, cFunc); + for (auto u : costb) { + int single = EDijkstra::shortestPath(u.first, eBC, cFunc); + assert(single == u.second); + } + } + + // ___________________________________________________________________________ + { + UndirGraph g; + + auto a = g.addNd("A"); + auto b = g.addNd("B"); + auto c = g.addNd("C"); + auto d = g.addNd("D"); + auto e = g.addNd("E"); + + auto eAC = g.addEdg(a, c, 1); + auto eAB = g.addEdg(a, b, 5); + auto eDC = g.addEdg(d, c, 1); + auto eDB = g.addEdg(d, b, 3); + auto eED = g.addEdg(e, d, 1); + auto eEB = g.addEdg(e, b, 1); + + UNUSED(eAC); + UNUSED(eDC); + UNUSED(eDB); + UNUSED(eED); + UNUSED(eEB); + + struct CostFunc : public EDijkstra::CostFunc { + int operator()(const Edge* from, + const Node* n, + const Edge* to) const { + UNUSED(from); + + // dont count cost of start edge + if (n) return to->pl(); + return 0; + }; + int inf() const { return 999; }; + }; + + CostFunc cFunc; + + EDijkstra::NList res; + EDijkstra::EList resE; + int cost = EDijkstra::shortestPath(eAB, d, cFunc, &resE, &res); + + assert(cost == 2); + + assert(resE.size() == (size_t)3); + assert(res.size() == (size_t)3); + assert((*(res.rbegin()))->pl() == "A"); + assert((*(++res.rbegin()))->pl() == "C"); + assert((*(++++res.rbegin()))->pl() == "D"); + + assert((*(resE.rbegin())) == eAB); + assert((*(++resE.rbegin())) == eAC); + assert((*(++++resE.rbegin())) == eDC); + + cost = EDijkstra::shortestPath(eAB, b, cFunc, &resE, &res); + assert(cost == 0); + } + + // ___________________________________________________________________________ + { + UndirGraph g; + + auto a = g.addNd("A"); + auto b = g.addNd("B"); + auto c = g.addNd("C"); + auto d = g.addNd("D"); + auto e = g.addNd("E"); + + auto eAC = g.addEdg(a, c, 1); + auto eAB = g.addEdg(a, b, 5); + auto eDC = g.addEdg(d, c, 1); + auto eDB = g.addEdg(d, b, 3); + auto eED = g.addEdg(e, d, 1); + auto eEB = g.addEdg(e, b, 1); + + UNUSED(eAC); + UNUSED(eDC); + UNUSED(eDB); + UNUSED(eED); + UNUSED(eEB); + + struct CostFunc : public EDijkstra::CostFunc { + int operator()(const Edge* from, + const Node* n, + const Edge* to) const { + UNUSED(from); + + // dont count cost of start edge + if (n) return to->pl(); + return 0; + }; + int inf() const { return 999; }; + }; + + CostFunc cFunc; + + std::set*> tos; + tos.insert(d); + tos.insert(b); + tos.insert(b); + + EDijkstra::NList res; + EDijkstra::EList resE; + int cost = EDijkstra::shortestPath(eAB, tos, cFunc, &resE, &res); + assert(cost == 0); + } + + // ___________________________________________________________________________ + { + UndirGraph g; + + auto a = g.addNd("A"); + auto b = g.addNd("B"); + auto c = g.addNd("C"); + auto d = g.addNd("D"); + auto e = g.addNd("E"); + + g.addEdg(a, c, 1); + auto eAB = g.addEdg(a, b, 5); + auto eDC = g.addEdg(d, c, 1); + g.addEdg(d, b, 3); + auto eED = g.addEdg(e, d, 1); + g.addEdg(e, b, 1); + + struct CostFunc : public EDijkstra::CostFunc { + int operator()(const Edge* from, + const Node* n, + const Edge* to) const { + UNUSED(from); + + // dont count cost of start edge + if (n) return to->pl(); + return 0; + }; + int inf() const { return 999; }; + }; + + CostFunc cFunc; + + std::set*> tos; + tos.insert(eDC); + tos.insert(eED); + + std::unordered_map*, + EDijkstra::EList*> + resE; + resE[eDC] = new EDijkstra::EList(); + resE[eED] = new EDijkstra::EList(); + std::unordered_map*, + EDijkstra::NList*> + res; + res[eDC] = new EDijkstra::NList(); + res[eED] = new EDijkstra::NList(); + auto hFunc = EDijkstra::ZeroHeurFunc(); + std::unordered_map*, int> cost = + EDijkstra::shortestPath(eAB, tos, cFunc, hFunc, resE, res); + + assert(cost[eDC] == 2); + assert(cost[eED] == 2); + + assert(resE[eDC]->size() == (size_t)3); + assert(res[eED]->size() == (size_t)3); + + assert(resE[eDC]->size() == (size_t)3); + assert(res[eED]->size() == (size_t)3); + } + + // ___________________________________________________________________________ + { + UndirGraph g; + + auto a = g.addNd("A"); + auto b = g.addNd("B"); + auto c = g.addNd("C"); + auto d = g.addNd("D"); + auto e = g.addNd("E"); + + g.addEdg(a, c, 1); + g.addEdg(a, b, 5); + g.addEdg(d, c, 1); + g.addEdg(d, b, 3); + g.addEdg(e, d, 1); + g.addEdg(e, b, 1); + + struct CostFunc : public EDijkstra::CostFunc { + int operator()(const Edge* fr, + const Node* n, + const Edge* to) const { + UNUSED(fr); + UNUSED(n); + return to->pl(); + }; + int inf() const { return 999; }; + }; + + CostFunc cFunc; + + EDijkstra::NList res; + EDijkstra::EList resE; + int cost = EDijkstra::shortestPath(a, b, cFunc, &resE, &res); + + assert(res.size() == (size_t)5); + assert((*(res.rbegin()))->pl() == "A"); + assert((*(++res.rbegin()))->pl() == "C"); + assert((*(++++res.rbegin()))->pl() == "D"); + assert((*(++++++res.rbegin()))->pl() == "E"); + assert((*(++++++++res.rbegin()))->pl() == "B"); + assert(cost == 4); + assert((*(resE.rbegin()))->getFrom()->pl() == "A"); + assert((*(++resE.rbegin()))->getFrom()->pl() == "D"); + assert((*(++++resE.rbegin()))->getFrom()->pl() == "E"); + assert((*(++++++resE.rbegin()))->getTo()->pl() == "B"); + + assert(resE.size() == (size_t)4); + + cost = EDijkstra::shortestPath(d, b, cFunc, &res); + assert(cost == 2); + + cost = EDijkstra::shortestPath(b, d, cFunc, &res); + assert(cost == 2); + + cost = EDijkstra::shortestPath(e, b, cFunc, &res); + assert(cost == 1); + + cost = EDijkstra::shortestPath(b, e, cFunc, &res); + assert(cost == 1); + + cost = EDijkstra::shortestPath(b, a, cFunc, &res); + assert(cost == 4); + + cost = EDijkstra::shortestPath(c, a, cFunc, &res); + assert(cost == 1); + + cost = EDijkstra::shortestPath(a, c, cFunc, &res); + assert(cost == 1); + + cost = EDijkstra::shortestPath(a, d, cFunc, &res); + assert(cost == 2); + } + + // ___________________________________________________________________________ + { + DirGraph g; + + DirNode* a = new DirNode(1); + DirNode* b = new DirNode(4); + g.addNd(a); + g.addNd(b); + + auto c = g.addNd(2); + auto d = g.addNd(3); + auto x = g.addNd(); + + g.addEdg(a, d, 4); + g.addEdg(a, c, 1); + g.addEdg(c, b, 1); + g.addEdg(b, d, 1); + + struct CostFunc : public EDijkstra::CostFunc { + int operator()(const Edge* fr, const Node* n, + const Edge* to) const { + UNUSED(fr); + UNUSED(n); + return to->pl(); + }; + int inf() const { return 999; }; + }; + + CostFunc cFunc; + + EDijkstra::NList res; + int cost = EDijkstra::shortestPath(a, d, cFunc, &res); + + assert(cost == 3); + + g.addEdg(c, d, 3); + cost = EDijkstra::shortestPath(a, d, cFunc, &res); + + assert(cost == 3); + + g.addEdg(a, b, 1); + g.addEdg(x, a, 1); + cost = EDijkstra::shortestPath(a, d, cFunc, &res); + + assert(cost == 2); + } + + // ___________________________________________________________________________ + { + DirGraph g; + + DirNode* a = new DirNode(1); + DirNode* b = new DirNode(0); + g.addNd(a); + g.addNd(b); + + auto c = g.addNd(); + auto d = g.addNd(4); + auto x = g.addNd(); + + g.addEdg(a, d, 4); + g.addEdg(a, c, 1); + g.addEdg(c, b, 1); + g.addEdg(b, d, 1); + + struct CostFunc : public Dijkstra::CostFunc { + int operator()(const Node* fr, const Edge* e, + const Node* to) const { + UNUSED(fr); + UNUSED(to); + return e->pl(); + }; + int inf() const { return 999; }; + }; + + CostFunc cFunc; + + Dijkstra::NList res; + int cost = Dijkstra::shortestPath(a, d, cFunc, &res); + + assert(cost == 3); + assert(res.size() == (size_t)4); + + g.addEdg(c, d, 3); + cost = Dijkstra::shortestPath(a, d, cFunc, &res); + + assert(cost == 3); + + g.addEdg(a, b, 1); + g.addEdg(x, a, 1); + cost = Dijkstra::shortestPath(a, d, cFunc, &res); + + assert(cost == 2); + + const std::set*> to{b, c, d, x}; + std::unordered_map*, Dijkstra::EList*> resEdges; + std::unordered_map*, Dijkstra::NList*> resNodes; + + for (auto n : to) { + resEdges[n] = new Dijkstra::EList(); + resNodes[n] = new Dijkstra::NList(); + } + + auto costs = Dijkstra::shortestPath(a, to, cFunc, resEdges, resNodes); + + assert(costs[b] == 1); + assert(costs[c] == 1); + assert(costs[d] == 2); + assert(costs[x] == 999); + } + + // ___________________________________________________________________________ + {{util::Nullable nullable; + assert(nullable.isNull()); +} + +{ + util::Nullable nullable(0); + assert(nullable.isNull()); +} + +{ + std::string str = "aa"; + util::Nullable nullable(&str); + assert(!nullable.isNull()); + + assert(nullable == "aa"); + assert(!(nullable == "aaa")); + assert(!(nullable != "aa")); + assert(nullable == "aa"); + + assert(nullable.get() == "aa"); + assert(std::string(nullable) == "aa"); +} + +{ + int a = 23; + util::Nullable nullable(a); + util::Nullable nullable2(24); + assert(!nullable.isNull()); + + assert(nullable == 23); + assert(nullable >= 23); + assert(nullable <= 23); + assert(nullable < 24); + assert(nullable < 24); + assert(!(nullable < 22)); + assert(nullable != nullable2); + assert(nullable < nullable2); + assert(nullable2 > nullable); + + util::Nullable nullable3(nullable); + assert(nullable == nullable3); + + nullable3 = nullable2; + assert(nullable2 == nullable3); + assert(nullable3 == 24); + assert(nullable2 == 24); + assert(nullable2 == nullable2.get()); + assert(int(nullable2) == nullable2.get()); + assert(!nullable3.isNull()); + assert(!nullable2.isNull()); + + util::Nullable voidnull; + assert(voidnull.isNull()); +} +} // ___________________________________________________________________________ { -CASE("geomwkt") { auto p = pointFromWKT("POINT(10 50)"); - EXPECT(p.getX() == approx(10)); - EXPECT(p.getY() == approx(50)); + assert(p.getX() == approx(10)); + assert(p.getY() == approx(50)); p = pointFromWKT("POINT( 10 50)"); - EXPECT(p.getX() == approx(10)); - EXPECT(p.getY() == approx(50)); + assert(p.getX() == approx(10)); + assert(p.getY() == approx(50)); p = pointFromWKT("POINT (10 50 30)"); - EXPECT(p.getX() == approx(10)); - EXPECT(p.getY() == approx(50)); + assert(p.getX() == approx(10)); + assert(p.getY() == approx(50)); p = pointFromWKT("POINT (10 50 30)"); - EXPECT(p.getX() == approx(10)); - EXPECT(p.getY() == approx(50)); + assert(p.getX() == approx(10)); + assert(p.getY() == approx(50)); p = pointFromWKT("POINT(10 50 30)"); - EXPECT(p.getX() == approx(10)); - EXPECT(p.getY() == approx(50)); + assert(p.getX() == approx(10)); + assert(p.getY() == approx(50)); p = pointFromWKT("POINT (10 50) "); - EXPECT(p.getX() == approx(10)); - EXPECT(p.getY() == approx(50)); + assert(p.getX() == approx(10)); + assert(p.getY() == approx(50)); p = pointFromWKT("MPOINT(10 50 30)"); - EXPECT(p.getX() == approx(10)); - EXPECT(p.getY() == approx(50)); + assert(p.getX() == approx(10)); + assert(p.getY() == approx(50)); p = pointFromWKT("MPOINT(10 50)"); - EXPECT(p.getX() == approx(10)); - EXPECT(p.getY() == approx(50)); + assert(p.getX() == approx(10)); + assert(p.getY() == approx(50)); p = pointFromWKT("POINT(10.05 50.05)"); - EXPECT(p.getX() == approx(10.05)); - EXPECT(p.getY() == approx(50.05)); + assert(p.getX() == approx(10.05)); + assert(p.getY() == approx(50.05)); auto wktl = lineFromWKT("LINESTRING(0 0, 1 1,2 3, 0 1)"); - EXPECT(wktl.size() == (size_t)4); - EXPECT(wktl[0].getX() == approx(0)); - EXPECT(wktl[0].getY() == approx(0)); - EXPECT(wktl[1].getX() == approx(1)); - EXPECT(wktl[1].getY() == approx(1)); - EXPECT(wktl[2].getX() == approx(2)); - EXPECT(wktl[2].getY() == approx(3)); - EXPECT(wktl[3].getX() == approx(0)); - EXPECT(wktl[3].getY() == approx(1)); + assert(wktl.size() == (size_t)4); + assert(wktl[0].getX() == approx(0)); + assert(wktl[0].getY() == approx(0)); + assert(wktl[1].getX() == approx(1)); + assert(wktl[1].getY() == approx(1)); + assert(wktl[2].getX() == approx(2)); + assert(wktl[2].getY() == approx(3)); + assert(wktl[3].getX() == approx(0)); + assert(wktl[3].getY() == approx(1)); wktl = lineFromWKT("MLINESTRING(0 0, 1 1,2 3, 0 1)"); - EXPECT(wktl.size() == (size_t)4); - EXPECT(wktl[0].getX() == approx(0)); - EXPECT(wktl[0].getY() == approx(0)); - EXPECT(wktl[1].getX() == approx(1)); - EXPECT(wktl[1].getY() == approx(1)); - EXPECT(wktl[2].getX() == approx(2)); - EXPECT(wktl[2].getY() == approx(3)); - EXPECT(wktl[3].getX() == approx(0)); - EXPECT(wktl[3].getY() == approx(1)); + assert(wktl.size() == (size_t)4); + assert(wktl[0].getX() == approx(0)); + assert(wktl[0].getY() == approx(0)); + assert(wktl[1].getX() == approx(1)); + assert(wktl[1].getY() == approx(1)); + assert(wktl[2].getX() == approx(2)); + assert(wktl[2].getY() == approx(3)); + assert(wktl[3].getX() == approx(0)); + assert(wktl[3].getY() == approx(1)); wktl = lineFromWKT("MLINESTRING (0 0, 1 1,2 3, 0 1 )"); - EXPECT(wktl.size() == (size_t)4); - EXPECT(wktl[0].getX() == approx(0)); - EXPECT(wktl[0].getY() == approx(0)); - EXPECT(wktl[1].getX() == approx(1)); - EXPECT(wktl[1].getY() == approx(1)); - EXPECT(wktl[2].getX() == approx(2)); - EXPECT(wktl[2].getY() == approx(3)); - EXPECT(wktl[3].getX() == approx(0)); - EXPECT(wktl[3].getY() == approx(1)); -}}, + assert(wktl.size() == (size_t)4); + assert(wktl[0].getX() == approx(0)); + assert(wktl[0].getY() == approx(0)); + assert(wktl[1].getX() == approx(1)); + assert(wktl[1].getY() == approx(1)); + assert(wktl[2].getX() == approx(2)); + assert(wktl[2].getY() == approx(3)); + assert(wktl[3].getX() == approx(0)); + assert(wktl[3].getY() == approx(1)); +} // ___________________________________________________________________________ { -CASE("geometry") { - geo::Point a(1, 2); geo::Point b(2, 3); geo::Point c(4, 5); - EXPECT(a.getX() == approx(1)); - EXPECT(a.getY() == approx(2)); + assert(a.getX() == approx(1)); + assert(a.getY() == approx(2)); a.setX(3); - EXPECT(a.getX() == approx(3)); - EXPECT(a.getY() == approx(2)); + assert(a.getX() == approx(3)); + assert(a.getY() == approx(2)); a.setY(4); - EXPECT(a.getX() == approx(3)); - EXPECT(a.getY() == approx(4)); + assert(a.getX() == approx(3)); + assert(a.getY() == approx(4)); auto d = a + b; - EXPECT(d.getX() == approx(5)); - EXPECT(d.getY() == approx(7)); + assert(d.getX() == approx(5)); + assert(d.getY() == approx(7)); a.setX(1); a.setY(2); - EXPECT(geo::dist(a, a) == approx(0)); - EXPECT(geo::dist(a, b) == approx(sqrt(2))); + assert(geo::dist(a, a) == approx(0)); + assert(geo::dist(a, b) == approx(sqrt(2))); d = d + d; geo::Box box(a, c); - EXPECT(geo::contains(a, box)); - EXPECT(geo::contains(b, box)); - EXPECT(geo::contains(c, box)); - EXPECT(!geo::contains(d, box)); + assert(geo::contains(a, box)); + assert(geo::contains(b, box)); + assert(geo::contains(c, box)); + assert(!geo::contains(d, box)); geo::Line line{a, b, c}; - EXPECT(geo::contains(line, box)); + assert(geo::contains(line, box)); line.push_back(d); - EXPECT(!geo::contains(line, box)); + assert(!geo::contains(line, box)); geo::LineSegment ls{a, b}; - EXPECT(geo::contains(a, ls)); - EXPECT(geo::contains(b, ls)); - EXPECT(!geo::contains(c, ls)); - EXPECT(geo::contains(a + geo::Point(.5, .5), ls)); - EXPECT(!geo::contains(a + geo::Point(1.5, 1.5), ls)); + assert(geo::contains(a, ls)); + assert(geo::contains(b, ls)); + assert(!geo::contains(c, ls)); + assert(geo::contains(a + geo::Point(.5, .5), ls)); + assert(!geo::contains(a + geo::Point(1.5, 1.5), ls)); - geo::LineSegment lsa{geo::Point(1, 1), geo::Point(2, 2)}; - geo::LineSegment lsb{geo::Point(1, 2), geo::Point(2, 1)}; - geo::LineSegment lsc{geo::Point(2.1, 2), geo::Point(3, 3)}; + geo::LineSegment lsa{geo::Point(1, 1), + geo::Point(2, 2)}; + geo::LineSegment lsb{geo::Point(1, 2), + geo::Point(2, 1)}; + geo::LineSegment lsc{geo::Point(2.1, 2), + geo::Point(3, 3)}; - EXPECT(geo::crossProd(lsa.first, lsb) == approx(-1)); - EXPECT(geo::crossProd(lsa.second, lsb) == approx(1)); + assert(geo::crossProd(lsa.first, lsb) == approx(-1)); + assert(geo::crossProd(lsa.second, lsb) == approx(1)); - EXPECT(geo::intersects(lsa, lsb)); + assert(geo::intersects(lsa, lsb)); - EXPECT(!geo::intersects(lsa, lsa)); - EXPECT(!geo::intersects(lsb, lsb)); - EXPECT(!geo::intersects(lsa, lsc)); + assert(!geo::intersects(lsa, lsa)); + assert(!geo::intersects(lsb, lsb)); + assert(!geo::intersects(lsa, lsc)); - EXPECT(!geo::intersects(geo::Point(871569.2, 6104550.4), geo::Point(871581.2, 6104536), geo::Point(871580.3, 6104541.3), geo::Point(871625.7, 6104510.1))); + assert(!geo::intersects(geo::Point(871569.2, 6104550.4), + geo::Point(871581.2, 6104536), + geo::Point(871580.3, 6104541.3), + geo::Point(871625.7, 6104510.1))); - EXPECT(!geo::intersects(geo::Point(0, 0), geo::Point(1, 1), geo::Point(0.5, 0.5), geo::Point(1.5, 1.5))); + assert(!geo::intersects(geo::Point(0, 0), geo::Point(1, 1), + geo::Point(0.5, 0.5), + geo::Point(1.5, 1.5))); - geo::Line l{geo::Point(1, 1), geo::Point(2, 2), geo::Point(2, 4)}; - EXPECT(!geo::contains(geo::Point(1, 2), l)); - EXPECT(geo::contains(geo::Point(2, 2), l)); - EXPECT(geo::contains(geo::Point(2, 3), l)); + geo::Line l{geo::Point(1, 1), geo::Point(2, 2), + geo::Point(2, 4)}; + assert(!geo::contains(geo::Point(1, 2), l)); + assert(geo::contains(geo::Point(2, 2), l)); + assert(geo::contains(geo::Point(2, 3), l)); geo::Box bbox(geo::Point(1, 1), geo::Point(3, 3)); - EXPECT(geo::intersects(l, bbox)); + assert(geo::intersects(l, bbox)); geo::Line ll{geo::Point(0, 0), geo::Point(4, 4)}; - EXPECT(geo::intersects(ll, bbox)); + assert(geo::intersects(ll, bbox)); geo::Line lll{geo::Point(0, 0), geo::Point(0, 4)}; - EXPECT(!geo::intersects(lll, bbox)); + assert(!geo::intersects(lll, bbox)); geo::Line llll{geo::Point(1.2, 0), geo::Point(1, 2)}; - EXPECT(geo::intersects(llll, bbox)); + assert(geo::intersects(llll, bbox)); Line l5new; l5new.push_back(Point(-10, -5)); l5new.push_back(Point(-8, -4)); - EXPECT(geo::getBoundingBox(l5new).getUpperRight().getX() == approx(-8)); - EXPECT(geo::getBoundingBox(l5new).getUpperRight().getY() == approx(-4)); + assert(geo::getBoundingBox(l5new).getUpperRight().getX() == approx(-8)); + assert(geo::getBoundingBox(l5new).getUpperRight().getY() == approx(-4)); Line l5; l5.push_back(Point(0, 0)); l5.push_back(Point(1.5, 2)); Box req(Point(.5, 1), Point(1, 1.5)); - EXPECT(geo::getBoundingBox(l5[0]).getLowerLeft().getX() == approx(0)); - EXPECT(geo::getBoundingBox(l5[0]).getLowerLeft().getY() == approx(0)); + assert(geo::getBoundingBox(l5[0]).getLowerLeft().getX() == approx(0)); + assert(geo::getBoundingBox(l5[0]).getLowerLeft().getY() == approx(0)); - EXPECT(geo::getBoundingBox(l5).getLowerLeft().getX() == approx(0)); - EXPECT(geo::getBoundingBox(l5).getLowerLeft().getY() == approx(0)); - EXPECT(geo::getBoundingBox(l5).getUpperRight().getX() == approx(1.5)); - EXPECT(geo::getBoundingBox(l5).getUpperRight().getY() == approx(2)); - EXPECT(geo::intersects(geo::getBoundingBox(l5), geo::getBoundingBox(Line{Point(.5, 1), Point(1, 1)}))); - EXPECT(geo::intersects(l5, Line{Point(.5, 1), Point(1, 1)})); - EXPECT(geo::intersects(l5, req)); + assert(geo::getBoundingBox(l5).getLowerLeft().getX() == approx(0)); + assert(geo::getBoundingBox(l5).getLowerLeft().getY() == approx(0)); + assert(geo::getBoundingBox(l5).getUpperRight().getX() == approx(1.5)); + assert(geo::getBoundingBox(l5).getUpperRight().getY() == approx(2)); + assert(geo::intersects(geo::getBoundingBox(l5), + geo::getBoundingBox(Line{ + Point(.5, 1), Point(1, 1)}))); + assert(geo::intersects( + l5, Line{Point(.5, 1), Point(1, 1)})); + assert(geo::intersects(l5, req)); Box boxa(Point(1, 1), Point(2, 2)); - EXPECT(geo::intersects(boxa, Box(Point(1.5, 1.5), Point(1.7, 1.7)))); - EXPECT(geo::intersects(boxa, Box(Point(0, 0), Point(3, 3)))); - EXPECT(geo::intersects(boxa, Box(Point(1.5, 1.5), Point(3, 3)))); - EXPECT(geo::intersects(boxa, Box(Point(0, 0), Point(1.5, 1.5)))); + assert(geo::intersects( + boxa, Box(Point(1.5, 1.5), Point(1.7, 1.7)))); + assert(geo::intersects( + boxa, Box(Point(0, 0), Point(3, 3)))); + assert(geo::intersects( + boxa, Box(Point(1.5, 1.5), Point(3, 3)))); + assert(geo::intersects( + boxa, Box(Point(0, 0), Point(1.5, 1.5)))); - EXPECT(geo::intersects(Box(Point(1.5, 1.5), Point(1.7, 1.7)), boxa)); - EXPECT(geo::intersects(Box(Point(0, 0), Point(3, 3)), boxa)); - EXPECT(geo::intersects(Box(Point(1.5, 1.5), Point(3, 3)), boxa)); - EXPECT(geo::intersects(Box(Point(0, 0), Point(1.5, 1.5)), boxa)); + assert(geo::intersects( + Box(Point(1.5, 1.5), Point(1.7, 1.7)), boxa)); + assert(geo::intersects(Box(Point(0, 0), Point(3, 3)), + boxa)); + assert(geo::intersects( + Box(Point(1.5, 1.5), Point(3, 3)), boxa)); + assert(geo::intersects( + Box(Point(0, 0), Point(1.5, 1.5)), boxa)); - Polygon poly({Point(1, 1), Point(3, 2), Point(4, 3), Point(6, 3), Point(5, 1)}); - EXPECT(geo::getWKT(poly) == "POLYGON ((1 1, 3 2, 4 3, 6 3, 5 1, 1 1))"); - EXPECT(geo::contains(Point(4, 2), poly)); - EXPECT(!geo::contains(Point(3, 3), poly)); - EXPECT(geo::contains(Point(1, 1), poly)); - EXPECT(geo::contains(Point(3, 2), poly)); - EXPECT(geo::contains(Point(4, 3), poly)); - EXPECT(geo::contains(Point(6, 3), poly)); - EXPECT(geo::contains(Point(5, 1), poly)); + Polygon poly({Point(1, 1), Point(3, 2), + Point(4, 3), Point(6, 3), + Point(5, 1)}); + assert(geo::getWKT(poly) == "POLYGON ((1 1, 3 2, 4 3, 6 3, 5 1, 1 1))"); + assert(geo::contains(Point(4, 2), poly)); + assert(!geo::contains(Point(3, 3), poly)); + assert(geo::contains(Point(1, 1), poly)); + assert(geo::contains(Point(3, 2), poly)); + assert(geo::contains(Point(4, 3), poly)); + assert(geo::contains(Point(6, 3), poly)); + assert(geo::contains(Point(5, 1), poly)); - EXPECT(geo::contains(Line{Point(6, 3), Point(5, 1)}, poly)); - EXPECT(!geo::contains(Line{Point(6, 3), Point(50, 1)}, poly)); - EXPECT(geo::contains(Line{Point(4, 2), Point(4.5, 2)}, poly)); - EXPECT(geo::contains(Line{Point(4, 2), Point(5, 1)}, poly)); + assert(geo::contains(Line{Point(6, 3), Point(5, 1)}, + poly)); + assert(!geo::contains(Line{Point(6, 3), Point(50, 1)}, + poly)); + assert(geo::contains(Line{Point(4, 2), Point(4.5, 2)}, + poly)); + assert(geo::contains(Line{Point(4, 2), Point(5, 1)}, + poly)); Box polybox(Point(1, 1), Point(6, 4)); - EXPECT(geo::centroid(polybox).getX() == approx(3.5)); - EXPECT(geo::centroid(polybox).getY() == approx(2.5)); - EXPECT(geo::contains(poly, polybox)); - EXPECT(!geo::contains(polybox, poly)); + assert(geo::centroid(polybox).getX() == approx(3.5)); + assert(geo::centroid(polybox).getY() == approx(2.5)); + assert(geo::contains(poly, polybox)); + assert(!geo::contains(polybox, poly)); Box polybox2(Point(4, 1), Point(5, 2)); - EXPECT(geo::contains(polybox2, poly)); - EXPECT(geo::contains(poly, getBoundingBox(poly))); + assert(geo::contains(polybox2, poly)); + assert(geo::contains(poly, getBoundingBox(poly))); Point rotP(2, 2); - EXPECT(geo::dist(geo::rotate(rotP, 180, Point(1, 1)), Point(0, 0)) == approx(0)); - EXPECT(geo::dist(geo::rotate(rotP, 360, Point(1, 1)), rotP) == approx(0)); + assert(geo::dist(geo::rotate(rotP, 180, Point(1, 1)), + Point(0, 0)) == approx(0)); + assert(geo::dist(geo::rotate(rotP, 360, Point(1, 1)), rotP) == + approx(0)); Line rotLine({{1, 1}, {3, 3}}); - EXPECT(geo::rotate(rotLine, 90, Point(2, 2))[0].getX() == approx(1)); - EXPECT(geo::rotate(rotLine, 90, Point(2, 2))[0].getY() == approx(3)); - EXPECT(geo::rotate(rotLine, 90, Point(2, 2))[1].getX() == approx(3)); - EXPECT(geo::rotate(rotLine, 90, Point(2, 2))[1].getY() == approx(1)); + assert(geo::rotate(rotLine, 90, Point(2, 2))[0].getX() == approx(1)); + assert(geo::rotate(rotLine, 90, Point(2, 2))[0].getY() == approx(3)); + assert(geo::rotate(rotLine, 90, Point(2, 2))[1].getX() == approx(3)); + assert(geo::rotate(rotLine, 90, Point(2, 2))[1].getY() == approx(1)); MultiLine multiRotLine({{{1, 1}, {3, 3}}, {{1, 3}, {3, 1}}}); - EXPECT(geo::rotate(multiRotLine, 90, Point(2, 2))[0][0].getX() == approx(1)); - EXPECT(geo::rotate(multiRotLine, 90, Point(2, 2))[0][0].getY() == approx(3)); - EXPECT(geo::rotate(multiRotLine, 90, Point(2, 2))[0][1].getX() == approx(3)); - EXPECT(geo::rotate(multiRotLine, 90, Point(2, 2))[0][1].getY() == approx(1)); - EXPECT(geo::rotate(multiRotLine, 90, Point(2, 2))[1][0].getX() == approx(3)); - EXPECT(geo::rotate(multiRotLine, 90, Point(2, 2))[1][0].getY() == approx(3)); - EXPECT(geo::rotate(multiRotLine, 90, Point(2, 2))[1][1].getX() == approx(1)); - EXPECT(geo::rotate(multiRotLine, 90, Point(2, 2))[1][1].getY() == approx(1)); + assert(geo::rotate(multiRotLine, 90, Point(2, 2))[0][0].getX() == + approx(1)); + assert(geo::rotate(multiRotLine, 90, Point(2, 2))[0][0].getY() == + approx(3)); + assert(geo::rotate(multiRotLine, 90, Point(2, 2))[0][1].getX() == + approx(3)); + assert(geo::rotate(multiRotLine, 90, Point(2, 2))[0][1].getY() == + approx(1)); + assert(geo::rotate(multiRotLine, 90, Point(2, 2))[1][0].getX() == + approx(3)); + assert(geo::rotate(multiRotLine, 90, Point(2, 2))[1][0].getY() == + approx(3)); + assert(geo::rotate(multiRotLine, 90, Point(2, 2))[1][1].getX() == + approx(1)); + assert(geo::rotate(multiRotLine, 90, Point(2, 2))[1][1].getY() == + approx(1)); - EXPECT(geo::getWKT(multiRotLine) == "MULTILINESTRING ((1 1, 3 3), (1 3, 3 1))"); + assert(geo::getWKT(multiRotLine) == + "MULTILINESTRING ((1 1, 3 3), (1 3, 3 1))"); - EXPECT(geo::contains(multiRotLine[0], geo::move(geo::move(multiRotLine, 1.0, 2.0), -1.0, -2.0)[0])); - EXPECT(geo::contains(multiRotLine, geo::getBoundingBox(Line{{1, 1}, {3, 3}, {1, 3}, {3, 1}}))); + assert(geo::contains( + multiRotLine[0], + geo::move(geo::move(multiRotLine, 1.0, 2.0), -1.0, -2.0)[0])); + assert(geo::contains(multiRotLine, geo::getBoundingBox(Line{ + {1, 1}, {3, 3}, {1, 3}, {3, 1}}))); - EXPECT(geo::contains(getBoundingBox(multiRotLine), geo::getBoundingBox(Line{{1, 1}, {3, 3}, {1, 3}, {3, 1}}))); - EXPECT(geo::contains(geo::getBoundingBox(Line{{1, 1}, {3, 3}, {1, 3}, {3, 1}}), getBoundingBox(multiRotLine))); + assert(geo::contains( + getBoundingBox(multiRotLine), + geo::getBoundingBox(Line{{1, 1}, {3, 3}, {1, 3}, {3, 1}}))); + assert(geo::contains( + geo::getBoundingBox(Line{{1, 1}, {3, 3}, {1, 3}, {3, 1}}), + getBoundingBox(multiRotLine))); - EXPECT(geo::dist(geo::centroid(rotP), rotP) == approx(0)); - EXPECT(geo::dist(geo::centroid(rotLine), rotP) == approx(0)); - EXPECT(geo::dist(geo::centroid(polybox), Point(3.5, 2.5)) == approx(0)); - EXPECT(geo::dist(geo::centroid(Polygon({{0, 0}, {3, 4}, {4,3}})), Point(7.0/3.0,7.0/3.0)) == approx(0)); + assert(geo::dist(geo::centroid(rotP), rotP) == approx(0)); + assert(geo::dist(geo::centroid(rotLine), rotP) == approx(0)); + assert(geo::dist(geo::centroid(polybox), Point(3.5, 2.5)) == + approx(0)); + assert(geo::dist(geo::centroid(Polygon({{0, 0}, {3, 4}, {4, 3}})), + Point(7.0 / 3.0, 7.0 / 3.0)) == approx(0)); - auto polyy = Polygon({{0, 0}, {3, 4}, {4,3}}); + auto polyy = Polygon({{0, 0}, {3, 4}, {4, 3}}); MultiPolygon mpoly{polyy, polyy}; - EXPECT(geo::getWKT(polyy) == "POLYGON ((0 0, 3 4, 4 3, 0 0))"); - EXPECT(geo::getWKT(mpoly) == "MULTIPOLYGON (((0 0, 3 4, 4 3, 0 0)), ((0 0, 3 4, 4 3, 0 0)))"); + assert(geo::getWKT(polyy) == "POLYGON ((0 0, 3 4, 4 3, 0 0))"); + assert(geo::getWKT(mpoly) == + "MULTIPOLYGON (((0 0, 3 4, 4 3, 0 0)), ((0 0, 3 4, 4 3, 0 0)))"); - auto hull = geo::convexHull(Line{{0.1, 3}, {1, 1}, {2, 2}, {4, 4}, {0, 0}, {1, 2}, {3, 1}, {3, 3}}); - EXPECT(hull.getOuter().size() == size_t(4)); - EXPECT(hull.getOuter()[0].getX() == approx(0)); - EXPECT(hull.getOuter()[0].getY() == approx(0)); - EXPECT(hull.getOuter()[1].getX() == approx(3)); - EXPECT(hull.getOuter()[1].getY() == approx(1)); - EXPECT(hull.getOuter()[2].getX() == approx(4)); - EXPECT(hull.getOuter()[2].getY() == approx(4)); - EXPECT(hull.getOuter()[3].getX() == approx(0.1)); - EXPECT(hull.getOuter()[3].getY() == approx(3)); - EXPECT(geo::contains(geo::convexHull(geo::getBoundingBox(poly)), geo::getBoundingBox(poly))); - EXPECT(geo::contains(geo::getBoundingBox(poly), geo::convexHull(geo::getBoundingBox(poly)))); + auto hull = geo::convexHull(Line{ + {0.1, 3}, {1, 1}, {2, 2}, {4, 4}, {0, 0}, {1, 2}, {3, 1}, {3, 3}}); + assert(hull.getOuter().size() == size_t(4)); + assert(hull.getOuter()[0].getX() == approx(0)); + assert(hull.getOuter()[0].getY() == approx(0)); + assert(hull.getOuter()[1].getX() == approx(0.1)); + assert(hull.getOuter()[1].getY() == approx(3)); + assert(hull.getOuter()[2].getX() == approx(4)); + assert(hull.getOuter()[2].getY() == approx(4)); + assert(hull.getOuter()[3].getX() == approx(3)); + assert(hull.getOuter()[3].getY() == approx(1)); + assert(geo::contains(geo::convexHull(geo::getBoundingBox(poly)), + geo::getBoundingBox(poly))); + assert(geo::contains(geo::getBoundingBox(poly), + geo::convexHull(geo::getBoundingBox(poly)))); - auto hull2 = geo::convexHull(Line{{0.1, 3}, {1, 1}, {2, 2}, {4, 4}, {0, 0}, {1, 2}, {3, 1}, {3, 3}, {-0.1, 1}}); - EXPECT(hull2.getOuter().size() == size_t(5)); - EXPECT(hull2.getOuter()[0].getX() == approx(-.1)); - EXPECT(hull2.getOuter()[0].getY() == approx(1)); - EXPECT(hull2.getOuter()[1].getX() == approx(0)); - EXPECT(hull2.getOuter()[1].getY() == approx(0)); - EXPECT(hull2.getOuter()[2].getX() == approx(3)); - EXPECT(hull2.getOuter()[2].getY() == approx(1)); - EXPECT(hull2.getOuter()[3].getX() == approx(4)); - EXPECT(hull2.getOuter()[3].getY() == approx(4)); - EXPECT(hull2.getOuter()[4].getX() == approx(0.1)); - EXPECT(hull2.getOuter()[4].getY() == approx(3)); + auto hull2 = geo::convexHull(Line{{0.1, 3}, + {1, 1}, + {2, 2}, + {4, 4}, + {0, 0}, + {1, 2}, + {3, 1}, + {3, 3}, + {-0.1, 1}}); + assert(hull2.getOuter().size() == size_t(5)); + assert(hull2.getOuter()[0].getX() == approx(-.1)); + assert(hull2.getOuter()[0].getY() == approx(1)); + assert(hull2.getOuter()[1].getX() == approx(0.1)); + assert(hull2.getOuter()[1].getY() == approx(3)); + assert(hull2.getOuter()[2].getX() == approx(4)); + assert(hull2.getOuter()[2].getY() == approx(4)); + assert(hull2.getOuter()[3].getX() == approx(3)); + assert(hull2.getOuter()[3].getY() == approx(1)); + assert(hull2.getOuter()[4].getX() == approx(0)); + assert(hull2.getOuter()[4].getY() == approx(0)); - auto hull3 = geo::convexHull(Line{{0.1, 3}, {4, 4}, {0, 0}, {1, 2}, {3, 1}}); - EXPECT(hull3.getOuter().size() == size_t(4)); - EXPECT(hull3.getOuter()[0].getX() == approx(0)); - EXPECT(hull3.getOuter()[0].getY() == approx(0)); - EXPECT(hull3.getOuter()[1].getX() == approx(3)); - EXPECT(hull3.getOuter()[1].getY() == approx(1)); - EXPECT(hull3.getOuter()[2].getX() == approx(4)); - EXPECT(hull3.getOuter()[2].getY() == approx(4)); - EXPECT(hull3.getOuter()[3].getX() == approx(0.1)); - EXPECT(hull3.getOuter()[3].getY() == approx(3)); + auto hull3 = + geo::convexHull(Line{{0.1, 3}, {4, 4}, {0, 0}, {1, 2}, {3, 1}}); + assert(hull3.getOuter().size() == size_t(4)); + assert(hull3.getOuter()[0].getX() == approx(0)); + assert(hull3.getOuter()[0].getY() == approx(0)); + assert(hull3.getOuter()[3].getX() == approx(3)); + assert(hull3.getOuter()[3].getY() == approx(1)); + assert(hull3.getOuter()[2].getX() == approx(4)); + assert(hull3.getOuter()[2].getY() == approx(4)); + assert(hull3.getOuter()[1].getX() == approx(0.1)); + assert(hull3.getOuter()[1].getY() == approx(3)); - hull3 = geo::convexHull(Line{{0.1, 3}, {4, 4}, {2, 1}, {3, 2}, {0, 0}, {1, 2}, {3, 1}}); - EXPECT(hull3.getOuter().size() == size_t(4)); - EXPECT(hull3.getOuter()[0].getX() == approx(0)); - EXPECT(hull3.getOuter()[0].getY() == approx(0)); - EXPECT(hull3.getOuter()[1].getX() == approx(3)); - EXPECT(hull3.getOuter()[1].getY() == approx(1)); - EXPECT(hull3.getOuter()[2].getX() == approx(4)); - EXPECT(hull3.getOuter()[2].getY() == approx(4)); - EXPECT(hull3.getOuter()[3].getX() == approx(0.1)); - EXPECT(hull3.getOuter()[3].getY() == approx(3)); + hull3 = geo::convexHull( + Line{{0.1, 3}, {4, 4}, {2, 1}, {3, 2}, {0, 0}, {1, 2}, {3, 1}}); + assert(hull3.getOuter().size() == size_t(4)); + assert(hull3.getOuter()[0].getX() == approx(0)); + assert(hull3.getOuter()[0].getY() == approx(0)); + assert(hull3.getOuter()[3].getX() == approx(3)); + assert(hull3.getOuter()[3].getY() == approx(1)); + assert(hull3.getOuter()[2].getX() == approx(4)); + assert(hull3.getOuter()[2].getY() == approx(4)); + assert(hull3.getOuter()[1].getX() == approx(0.1)); + assert(hull3.getOuter()[1].getY() == approx(3)); - hull3 = geo::convexHull(Line{{4, 4}, {1, 2}, {2, 1}, {3, 2}, {0.1, 3}, {0, 0}, {1, 2}, {3, 1}}); - EXPECT(hull3.getOuter().size() == size_t(4)); - EXPECT(hull3.getOuter()[0].getX() == approx(0)); - EXPECT(hull3.getOuter()[0].getY() == approx(0)); - EXPECT(hull3.getOuter()[1].getX() == approx(3)); - EXPECT(hull3.getOuter()[1].getY() == approx(1)); - EXPECT(hull3.getOuter()[2].getX() == approx(4)); - EXPECT(hull3.getOuter()[2].getY() == approx(4)); - EXPECT(hull3.getOuter()[3].getX() == approx(0.1)); - EXPECT(hull3.getOuter()[3].getY() == approx(3)); + hull3 = geo::convexHull(Line{ + {4, 4}, {1, 2}, {2, 1}, {3, 2}, {0.1, 3}, {0, 0}, {1, 2}, {3, 1}}); + assert(hull3.getOuter().size() == size_t(4)); + assert(hull3.getOuter()[0].getX() == approx(0)); + assert(hull3.getOuter()[0].getY() == approx(0)); + assert(hull3.getOuter()[3].getX() == approx(3)); + assert(hull3.getOuter()[3].getY() == approx(1)); + assert(hull3.getOuter()[2].getX() == approx(4)); + assert(hull3.getOuter()[2].getY() == approx(4)); + assert(hull3.getOuter()[1].getX() == approx(0.1)); + assert(hull3.getOuter()[1].getY() == approx(3)); hull3 = geo::convexHull(Line{{4, 4}, {1, 2}, {3, 1}}); - EXPECT(hull3.getOuter().size() == size_t(3)); - EXPECT(hull3.getOuter()[0].getX() == approx(1)); - EXPECT(hull3.getOuter()[0].getY() == approx(2)); - EXPECT(hull3.getOuter()[1].getX() == approx(3)); - EXPECT(hull3.getOuter()[1].getY() == approx(1)); - EXPECT(hull3.getOuter()[2].getX() == approx(4)); - EXPECT(hull3.getOuter()[2].getY() == approx(4)); + assert(hull3.getOuter().size() == size_t(3)); + assert(hull3.getOuter()[0].getX() == approx(1)); + assert(hull3.getOuter()[0].getY() == approx(2)); + assert(hull3.getOuter()[2].getX() == approx(3)); + assert(hull3.getOuter()[2].getY() == approx(1)); + assert(hull3.getOuter()[1].getX() == approx(4)); + assert(hull3.getOuter()[1].getY() == approx(4)); hull3 = geo::convexHull(Line{{4, 4}, {1, 2}, {3, 10}}); - EXPECT(hull3.getOuter().size() == size_t(3)); - EXPECT(hull3.getOuter()[0].getX() == approx(1)); - EXPECT(hull3.getOuter()[0].getY() == approx(2)); - EXPECT(hull3.getOuter()[1].getX() == approx(4)); - EXPECT(hull3.getOuter()[1].getY() == approx(4)); - EXPECT(hull3.getOuter()[2].getX() == approx(3)); - EXPECT(hull3.getOuter()[2].getY() == approx(10)); + assert(hull3.getOuter().size() == size_t(3)); + assert(hull3.getOuter()[0].getX() == approx(1)); + assert(hull3.getOuter()[0].getY() == approx(2)); + assert(hull3.getOuter()[2].getX() == approx(4)); + assert(hull3.getOuter()[2].getY() == approx(4)); + assert(hull3.getOuter()[1].getX() == approx(3)); + assert(hull3.getOuter()[1].getY() == approx(10)); Line test{{0.3215348546593775, 0.03629583077160248}, {0.02402358131857918, -0.2356728797179394}, @@ -1369,88 +1441,269 @@ CASE("geometry") { }; hull3 = geo::convexHull(test); - EXPECT(geo::contains(test, hull3)); - EXPECT(hull3.getOuter().size() == size_t(8)); - EXPECT(geo::contains(Polygon({{-0.161920957418085, -0.4055339716426413}, - {0.05054295812784038, 0.4754929463150845}, - {0.4823896228171788, -0.4776170002088109}, - {0.4932166845474547, 0.4928094162538735}, - {-0.3521487911717489, 0.4352656197131292}, - {-0.4907368011686362, 0.1865826865533206}, - {0.4916198379282093, -0.345391701297268}, - {-0.4404289572876217, - -0.2894855991839297}}), hull3)); - EXPECT(geo::contains(hull3, Polygon({{-0.161920957418085, -0.4055339716426413}, - {0.05054295812784038, 0.4754929463150845}, - {0.4823896228171788, -0.4776170002088109}, - {0.4932166845474547, 0.4928094162538735}, - {-0.3521487911717489, 0.4352656197131292}, - {-0.4907368011686362, 0.1865826865533206}, - {0.4916198379282093, -0.345391701297268}, - {-0.4404289572876217, - -0.2894855991839297}}))); + assert(geo::contains(test, hull3)); + assert(hull3.getOuter().size() == size_t(8)); + assert(geo::contains( + Polygon({{-0.161920957418085, -0.4055339716426413}, + {0.05054295812784038, 0.4754929463150845}, + {0.4823896228171788, -0.4776170002088109}, + {0.4932166845474547, 0.4928094162538735}, + {-0.3521487911717489, 0.4352656197131292}, + {-0.4907368011686362, 0.1865826865533206}, + {0.4916198379282093, -0.345391701297268}, + {-0.4404289572876217, -0.2894855991839297}}), + hull3)); + assert(geo::contains( + hull3, Polygon({{-0.161920957418085, -0.4055339716426413}, + {0.05054295812784038, 0.4754929463150845}, + {0.4823896228171788, -0.4776170002088109}, + {0.4932166845474547, 0.4928094162538735}, + {-0.3521487911717489, 0.4352656197131292}, + {-0.4907368011686362, 0.1865826865533206}, + {0.4916198379282093, -0.345391701297268}, + {-0.4404289572876217, -0.2894855991839297}}))); - hull3 = geo::convexHull(Line{{3, 6}, {8, 10}, {3, 5}, {20, -10}, {-4, 5}, {10, 2}, {5, 1}, {45, 1}, {30, -9}, {3, 14}, {25, -5.5}}); - EXPECT(hull3.getOuter().size() == size_t(5)); - EXPECT(hull3.getOuter()[0].getX() == approx(-4)); - EXPECT(hull3.getOuter()[0].getY() == approx(5)); - EXPECT(hull3.getOuter()[1].getX() == approx(20)); - EXPECT(hull3.getOuter()[1].getY() == approx(-10)); - EXPECT(hull3.getOuter()[2].getX() == approx(30)); - EXPECT(hull3.getOuter()[2].getY() == approx(-9)); - EXPECT(hull3.getOuter()[3].getX() == approx(45)); - EXPECT(hull3.getOuter()[3].getY() == approx(1)); - EXPECT(hull3.getOuter()[4].getX() == approx(3)); - EXPECT(hull3.getOuter()[4].getY() == approx(14)); + hull3 = geo::convexHull(Line{{3, 6}, + {8, 10}, + {3, 5}, + {20, -10}, + {-4, 5}, + {10, 2}, + {5, 1}, + {45, 1}, + {30, -9}, + {3, 14}, + {25, -5.5}}); + assert(hull3.getOuter().size() == size_t(5)); + assert(hull3.getOuter()[0].getX() == approx(-4)); + assert(hull3.getOuter()[0].getY() == approx(5)); + assert(hull3.getOuter()[4].getX() == approx(20)); + assert(hull3.getOuter()[4].getY() == approx(-10)); + assert(hull3.getOuter()[3].getX() == approx(30)); + assert(hull3.getOuter()[3].getY() == approx(-9)); + assert(hull3.getOuter()[2].getX() == approx(45)); + assert(hull3.getOuter()[2].getY() == approx(1)); + assert(hull3.getOuter()[1].getX() == approx(3)); + assert(hull3.getOuter()[1].getY() == approx(14)); - hull3 = geo::convexHull(Line{{7, 7}, {7, -7}, {-7, -7}, {-7, 7}, {9, 0}, {-9, 0}, {0, 9}, {0, -9}}); - EXPECT(hull3.getOuter().size() == size_t(8)); - EXPECT(geo::contains(geo::Polygon({{-9, 0}, {-7, -7}, {0, -9}, {7, -7}, {9, 0}, {7, 7}, {0, 9}, {-7, 7}}), hull3)); - EXPECT(geo::contains(hull3, geo::Polygon({{-9, 0}, {-7, -7}, {0, -9}, {7, -7}, {9, 0}, {7, 7}, {0, 9}, {-7, 7}}))); + hull3 = geo::convexHull(Line{ + {7, 7}, {7, -7}, {-7, -7}, {-7, 7}, {9, 0}, {-9, 0}, {0, 9}, {0, -9}}); + assert(hull3.getOuter().size() == size_t(8)); + assert(geo::contains(geo::Polygon({{-9, 0}, + {-7, -7}, + {0, -9}, + {7, -7}, + {9, 0}, + {7, 7}, + {0, 9}, + {-7, 7}}), + hull3)); + assert(geo::contains(hull3, geo::Polygon({{-9, 0}, + {-7, -7}, + {0, -9}, + {7, -7}, + {9, 0}, + {7, 7}, + {0, 9}, + {-7, 7}}))); - hull3 = geo::convexHull(Line{{7, 7}, {7, -7}, {-7, -7}, {-7, 7}, {9, 0}, {-9, 0}, {0, 9}, {0, -9}, {0, 0}, {1, 2}, {-2, 1}, {-1, -1}, {3, 4}, {4, 3}, {-5, 4}, {6, 5}}); - EXPECT(hull3.getOuter().size() == size_t(8)); - EXPECT(geo::contains(geo::Polygon({{-9, 0}, {-7, -7}, {0, -9}, {7, -7}, {9, 0}, {7, 7}, {0, 9}, {-7, 7}}), hull3)); - EXPECT(geo::contains(hull3, geo::Polygon({{-9, 0}, {-7, -7}, {0, -9}, {7, -7}, {9, 0}, {7, 7}, {0, 9}, {-7, 7}}))); + hull3 = geo::convexHull(Line{{7, 7}, + {7, -7}, + {-7, -7}, + {-7, 7}, + {9, 0}, + {-9, 0}, + {0, 9}, + {0, -9}, + {0, 0}, + {1, 2}, + {-2, 1}, + {-1, -1}, + {3, 4}, + {4, 3}, + {-5, 4}, + {6, 5}}); + assert(hull3.getOuter().size() == size_t(8)); + assert(geo::contains(geo::Polygon({{-9, 0}, + {-7, -7}, + {0, -9}, + {7, -7}, + {9, 0}, + {7, 7}, + {0, 9}, + {-7, 7}}), + hull3)); + assert(geo::contains(hull3, geo::Polygon({{-9, 0}, + {-7, -7}, + {0, -9}, + {7, -7}, + {9, 0}, + {7, 7}, + {0, 9}, + {-7, 7}}))); - hull3 = geo::convexHull(Line{{0, 0}, {1, 2}, {-2, 1}, {-1, -1}, {3, 4}, {4, 3}, {-5, 4}, {6, 5}, {7, 7}, {7, -7}, {-7, -7}, {-7, 7}, {9, 0}, {-9, 0}, {0, 9}, {0, -9}, {-8, 0}, {8, 0}, {-7, 0}, {7, 0}, {-6, 0}, {6, 0}, {-5, 0}, {5, 0}, {-4, 0}, {4, 0}, {-3, 0}, {3, 0}, {-2, 0}, {2, 0}, {-1, 0}, {1, 0}, {0, -8}, {0, 8}, {0, -7}, {0, 7}, {0, -6}, {0, 6}, {0, -5}, {0, 5}, {0, -4}, {0, 4}, {0, -3}, {0, 3}, {0, -2}, {0, 2}, {0, -1}, {0, 1}, {1, 1}, {2, 2}, {3, 3}, {4, 4}, {5, 5}, {6, 6}, {1, -1}, {2, -2}, {3, -3}, {4, -4}, {5, -5}, {6, -6}, {-1, 1}, {-2, 2}, {-3, 3}, {-4, 4}, {-5, 5}, {-6, 6}, {-1, -1}, {-2, -2}, {-3, -3}, {-4, -4}, {-5, -5}, {-6, -6}}); - EXPECT(hull3.getOuter().size() == size_t(8)); - EXPECT(geo::contains(geo::Polygon({{-9, 0}, {-7, -7}, {0, -9}, {7, -7}, {9, 0}, {7, 7}, {0, 9}, {-7, 7}}), hull3)); - EXPECT(geo::contains(hull3, geo::Polygon({{-9, 0}, {-7, -7}, {0, -9}, {7, -7}, {9, 0}, {7, 7}, {0, 9}, {-7, 7}}))); + hull3 = geo::convexHull(Line{ + {0, 0}, {1, 2}, {-2, 1}, {-1, -1}, {3, 4}, {4, 3}, {-5, 4}, + {6, 5}, {7, 7}, {7, -7}, {-7, -7}, {-7, 7}, {9, 0}, {-9, 0}, + {0, 9}, {0, -9}, {-8, 0}, {8, 0}, {-7, 0}, {7, 0}, {-6, 0}, + {6, 0}, {-5, 0}, {5, 0}, {-4, 0}, {4, 0}, {-3, 0}, {3, 0}, + {-2, 0}, {2, 0}, {-1, 0}, {1, 0}, {0, -8}, {0, 8}, {0, -7}, + {0, 7}, {0, -6}, {0, 6}, {0, -5}, {0, 5}, {0, -4}, {0, 4}, + {0, -3}, {0, 3}, {0, -2}, {0, 2}, {0, -1}, {0, 1}, {1, 1}, + {2, 2}, {3, 3}, {4, 4}, {5, 5}, {6, 6}, {1, -1}, {2, -2}, + {3, -3}, {4, -4}, {5, -5}, {6, -6}, {-1, 1}, {-2, 2}, {-3, 3}, + {-4, 4}, {-5, 5}, {-6, 6}, {-1, -1}, {-2, -2}, {-3, -3}, {-4, -4}, + {-5, -5}, {-6, -6}}); + assert(hull3.getOuter().size() == size_t(8)); + assert(geo::contains(geo::Polygon({{-9, 0}, + {-7, -7}, + {0, -9}, + {7, -7}, + {9, 0}, + {7, 7}, + {0, 9}, + {-7, 7}}), + hull3)); + assert(geo::contains(hull3, geo::Polygon({{-9, 0}, + {-7, -7}, + {0, -9}, + {7, -7}, + {9, 0}, + {7, 7}, + {0, 9}, + {-7, 7}}))); - EXPECT(geo::area(geo::Point(1, 2)) == approx(0)); - EXPECT(geo::area(geo::Line{{1, 2}, {2, 5}}) == approx(0)); - EXPECT(geo::area(geo::Box({0, 0}, {1, 1})) == approx(1)); - EXPECT(geo::area(geo::Box({1, 1}, {1, 1})) == approx(0)); - EXPECT(geo::area(geo::Box({0, 0}, {2, 2})) == approx(4)); - EXPECT(geo::area(geo::Polygon({{0, 0}, {1, 0}, {1, 1}, {0, 1}})) == approx(1)); - EXPECT(geo::area(geo::Polygon({{0, 0}, {1, 0}, {1, 1}})) == approx(0.5)); + assert(geo::area(geo::Point(1, 2)) == approx(0)); + assert(geo::area(geo::Line{{1, 2}, {2, 5}}) == approx(0)); + assert(geo::area(geo::Box({0, 0}, {1, 1})) == approx(1)); + assert(geo::area(geo::Box({1, 1}, {1, 1})) == approx(0)); + assert(geo::area(geo::Box({0, 0}, {2, 2})) == approx(4)); + assert(geo::area(geo::Polygon({{0, 0}, {1, 0}, {1, 1}, {0, 1}})) == + approx(1)); + assert(geo::area(geo::Polygon({{0, 0}, {1, 0}, {1, 1}})) == + approx(0.5)); - auto obox = geo::getOrientedEnvelope(geo::Line{{0, 0}, {1, 1}, {1.5, 0.5}}); - EXPECT(geo::contains(geo::convexHull(obox), geo::Polygon({{0.0, 0.0}, {1.0, 1.0}, {1.5, 0.5}, {0.5, -0.5}}))); - EXPECT(geo::contains(geo::Polygon({{0.0, 0.0}, {1.0, 1.0}, {1.5, 0.5}, {0.5, -0.5}}), geo::convexHull(obox))); + auto obox = + geo::getOrientedEnvelope(geo::Line{{0, 0}, {1, 1}, {1.5, 0.5}}); + assert(geo::contains( + geo::convexHull(obox), + geo::Polygon({{0.0, 0.0}, {1.0, 1.0}, {1.5, 0.5}, {0.5, -0.5}}))); + assert(geo::contains( + geo::Polygon({{0.0, 0.0}, {1.0, 1.0}, {1.5, 0.5}, {0.5, -0.5}}), + geo::convexHull(obox))); - EXPECT(geo::dist(geo::LineSegment{{1, 1}, {3, 1}}, geo::LineSegment{{2, 2}, {2, 0}}) == approx(0)); - EXPECT(geo::dist(geo::LineSegment{{1, 1}, {3, 1}}, geo::LineSegment{{2, 4}, {2, 2}}) == approx(1)); - EXPECT(geo::dist(geo::LineSegment{{1, 1}, {3, 1}}, geo::LineSegment{{1, 1}, {3, 1}}) == approx(0)); - EXPECT(geo::dist(geo::LineSegment{{1, 1}, {3, 1}}, geo::LineSegment{{1, 2}, {3, 2}}) == approx(1)); - EXPECT(geo::dist(geo::LineSegment{{1, 1}, {3, 1}}, geo::LineSegment{{1, 2}, {3, 5}}) == approx(1)); + assert(geo::dist(geo::LineSegment{{1, 1}, {3, 1}}, + geo::LineSegment{{2, 2}, {2, 0}}) == approx(0)); + assert(geo::dist(geo::LineSegment{{1, 1}, {3, 1}}, + geo::LineSegment{{2, 4}, {2, 2}}) == approx(1)); + assert(geo::dist(geo::LineSegment{{1, 1}, {3, 1}}, + geo::LineSegment{{1, 1}, {3, 1}}) == approx(0)); + assert(geo::dist(geo::LineSegment{{1, 1}, {3, 1}}, + geo::LineSegment{{1, 2}, {3, 2}}) == approx(1)); + assert(geo::dist(geo::LineSegment{{1, 1}, {3, 1}}, + geo::LineSegment{{1, 2}, {3, 5}}) == approx(1)); - EXPECT(geo::dist(geo::Line{{1, 1}, {3, 1}}, geo::Point{2, 1}) == approx(0)); - EXPECT(geo::dist(geo::Line{{1, 1}, {3, 1}}, geo::Point{2, 2}) == approx(1)); - EXPECT(geo::dist(geo::Line{{1, 1}, {3, 1}}, geo::Point{3, 1}) == approx(0)); - EXPECT(geo::dist(geo::Line{{1, 1}, {3, 1}}, geo::Point{1, 1}) == approx(0)); + assert(geo::dist(geo::Line{{1, 1}, {3, 1}}, + geo::Point{2, 1}) == approx(0)); + assert(geo::dist(geo::Line{{1, 1}, {3, 1}}, + geo::Point{2, 2}) == approx(1)); + assert(geo::dist(geo::Line{{1, 1}, {3, 1}}, + geo::Point{3, 1}) == approx(0)); + assert(geo::dist(geo::Line{{1, 1}, {3, 1}}, + geo::Point{1, 1}) == approx(0)); - EXPECT(geo::dist(Line{{7, 7}, {7, -7}, {-7, -7}, {-7, 7}, {9, 0}, {-9, 0}, {0, 9}, {0, -9}}, Line{{7, 7}, {7, -7}, {-7, -7}, {-7, 7}, {9, 0}, {-9, 0}, {0, 9}, {0, -9}}) == approx(0)); - EXPECT(geo::dist(Line{{7, 7}, {7, -7}, {-7, -7}, {-7, 7}, {9, 0}, {-9, 0}, {0, 9}, {0, -9}}, LineSegment{{6, 7}, {8, -7}}) == approx(0)); - EXPECT(geo::dist(Line{{7, 7}, {7, -7}, {-7, -7}, {-7, 7}, {9, 0}, {-9, 0}, {0, 9}, {0, -9}}, Point{7, 4}) == approx(0)); - EXPECT(geo::dist(Line{{0, 0}, {1, 1}, {2, 0}}, Line{{1.5, 0.5}, {1.5, 100}}) == approx(0)); - EXPECT(geo::dist(Line{{0, 0}, {1, 1}, {2, 0}}, Line{{2, 0.5}, {2, 100}}) == approx(0.353553)); + assert(geo::dist(Line{{7, 7}, + {7, -7}, + {-7, -7}, + {-7, 7}, + {9, 0}, + {-9, 0}, + {0, 9}, + {0, -9}}, + Line{{7, 7}, + {7, -7}, + {-7, -7}, + {-7, 7}, + {9, 0}, + {-9, 0}, + {0, 9}, + {0, -9}}) == approx(0)); + assert(geo::dist(Line{{7, 7}, + {7, -7}, + {-7, -7}, + {-7, 7}, + {9, 0}, + {-9, 0}, + {0, 9}, + {0, -9}}, + LineSegment{{6, 7}, {8, -7}}) == approx(0)); + assert(geo::dist(Line{{7, 7}, + {7, -7}, + {-7, -7}, + {-7, 7}, + {9, 0}, + {-9, 0}, + {0, 9}, + {0, -9}}, + Point{7, 4}) == approx(0)); + assert(geo::dist(Line{{0, 0}, {1, 1}, {2, 0}}, + Line{{1.5, 0.5}, {1.5, 100}}) == approx(0)); + assert(geo::dist(Line{{0, 0}, {1, 1}, {2, 0}}, + Line{{2, 0.5}, {2, 100}}) == approx(0.353553)); + + assert(geo::contains(util::geo::Point{1.5, 0.5}, + util::geo::LineSegment{{1, 1}, {1.5, 0.5}})); + assert(geo::contains(util::geo::Point{1.5, 0.5}, + util::geo::LineSegment{{1, 1}, {1.5, 0.5}})); + + auto polyTest = + geo::Polygon({{1, 1}, {3, 1}, {2, 2}, {3, 3}, {1, 3}}); + assert(!geo::contains(util::geo::LineSegment({2.5, 1.3}, {2.5, 2.6}), + polyTest)); + + assert(!geo::contains(util::geo::LineSegment{{2.5, 1.3}, {2.5, 2.6}}, + polyTest)); + assert(geo::contains(util::geo::LineSegment{{2.5, 2.6}, {1.5, 2}}, + polyTest)); + assert(!geo::contains( + util::geo::Line{{2.5, 1.3}, {2.5, 2.6}, {1.5, 2}}, polyTest)); + assert(geo::contains( + util::geo::Line{{2.5, 1.3}, {1.5, 2}, {2.5, 2.6}}, polyTest)); + + assert(!geo::contains(util::geo::Box{{1, 1}, {2.5, 2.6}}, polyTest)); + + assert( + geo::intersects(Box(Point(0, 0), Point(10, 10)), + Box(Point(2, 2), Point(8, 8)))); + assert( + geo::intersects(Box(Point(0, 0), Point(10, 10)), + Box(Point(-2, -2), Point(8, 8)))); + assert(geo::intersects( + Box(Point(0, 0), Point(10, 10)), + Box(Point(-2, -2), Point(12, 12)))); + assert( + geo::intersects(Box(Point(0, 0), Point(10, 10)), + Box(Point(5, 5), Point(12, 12)))); + + assert(!geo::intersects( + Box(Point(0, 0), Point(10, 10)), + Box(Point(15, 15), Point(12, 12)))); + + double rad = 10.0; + int n = 20; + util::geo::MultiPoint mp; + + for (int i = 0; i < n; i++) { + double x = rad * cos((2.0 * M_PI / static_cast(n)) * + static_cast(i)); + double y = rad * sin((2.0 * M_PI / static_cast(n)) * + static_cast(i)); + + mp.push_back(util::geo::DPoint(x, y)); + } + + auto h = util::geo::convexHull(mp); + + assert(geo::contains(mp, h)); } - -}}; - -// _____________________________________________________________________________ -int main(int argc, char** argv) { - return(lest::run(specification, argc, argv)); } diff --git a/src/util/tests/lest.h b/src/util/tests/lest.h index 71db282..f3c9f49 100644 --- a/src/util/tests/lest.h +++ b/src/util/tests/lest.h @@ -31,7 +31,11 @@ #include #include -#define lest_VERSION "1.33.1" +#define lest_MAJOR 1 +#define lest_MINOR 35 +#define lest_PATCH 1 + +#define lest_VERSION lest_STRINGIFY(lest_MAJOR) "." lest_STRINGIFY(lest_MINOR) "." lest_STRINGIFY(lest_PATCH) #ifndef lest_FEATURE_AUTO_REGISTER # define lest_FEATURE_AUTO_REGISTER 0 @@ -49,50 +53,55 @@ # define lest_FEATURE_REGEX_SEARCH 0 #endif -#ifndef lest_FEATURE_TIME_PRECISION -#define lest_FEATURE_TIME_PRECISION 0 +#ifndef lest_FEATURE_TIME_PRECISION +# define lest_FEATURE_TIME_PRECISION 0 #endif -#ifndef lest_FEATURE_WSTRING -#define lest_FEATURE_WSTRING 1 +#ifndef lest_FEATURE_WSTRING +# define lest_FEATURE_WSTRING 1 #endif -#ifdef lest_FEATURE_RTTI -# define lest__cpp_rtti lest_FEATURE_RTTI +#ifdef lest_FEATURE_RTTI +# define lest__cpp_rtti lest_FEATURE_RTTI #elif defined(__cpp_rtti) -# define lest__cpp_rtti __cpp_rtti +# define lest__cpp_rtti __cpp_rtti #elif defined(__GXX_RTTI) || defined (_CPPRTTI) -# define lest__cpp_rtti 1 +# define lest__cpp_rtti 1 #else -# define lest__cpp_rtti 0 +# define lest__cpp_rtti 0 #endif #if lest_FEATURE_REGEX_SEARCH # include #endif +// Stringify: + +#define lest_STRINGIFY( x ) lest_STRINGIFY_( x ) +#define lest_STRINGIFY_( x ) #x + // Compiler warning suppression: -#ifdef __clang__ +#if defined (__clang__) # pragma clang diagnostic ignored "-Waggregate-return" # pragma clang diagnostic ignored "-Woverloaded-shift-op-parentheses" # pragma clang diagnostic push # pragma clang diagnostic ignored "-Wunused-comparison" -#elif defined __GNUC__ +#elif defined (__GNUC__) # pragma GCC diagnostic ignored "-Waggregate-return" # pragma GCC diagnostic push #endif // Suppress shadow and unused-value warning for sections: -#if defined __clang__ +#if defined (__clang__) # define lest_SUPPRESS_WSHADOW _Pragma( "clang diagnostic push" ) \ _Pragma( "clang diagnostic ignored \"-Wshadow\"" ) # define lest_SUPPRESS_WUNUSED _Pragma( "clang diagnostic push" ) \ _Pragma( "clang diagnostic ignored \"-Wunused-value\"" ) # define lest_RESTORE_WARNINGS _Pragma( "clang diagnostic pop" ) -#elif defined __GNUC__ +#elif defined (__GNUC__) # define lest_SUPPRESS_WSHADOW _Pragma( "GCC diagnostic push" ) \ _Pragma( "GCC diagnostic ignored \"-Wshadow\"" ) # define lest_SUPPRESS_WUNUSED _Pragma( "GCC diagnostic push" ) \ @@ -104,12 +113,22 @@ # define lest_RESTORE_WARNINGS /*empty*/ #endif -#ifdef _MSVC_LANG -# define lest_CPP17_OR_GREATER_MS ( _MSVC_LANG >= 201703L ) -#else -# define lest_CPP17_OR_GREATER_MS 0 +// C++ language version detection (C++20 is speculative): +// Note: VC14.0/1900 (VS2015) lacks too much from C++14. + +#ifndef lest_CPLUSPLUS +# if defined(_MSVC_LANG ) && !defined(__clang__) +# define lest_CPLUSPLUS (_MSC_VER == 1900 ? 201103L : _MSVC_LANG ) +# else +# define lest_CPLUSPLUS __cplusplus +# endif #endif -# define lest_CPP17_OR_GREATER ( __cplusplus >= 201703L || lest_CPP17_OR_GREATER_MS ) + +#define lest_CPP98_OR_GREATER ( lest_CPLUSPLUS >= 199711L ) +#define lest_CPP11_OR_GREATER ( lest_CPLUSPLUS >= 201103L ) +#define lest_CPP14_OR_GREATER ( lest_CPLUSPLUS >= 201402L ) +#define lest_CPP17_OR_GREATER ( lest_CPLUSPLUS >= 201703L ) +#define lest_CPP20_OR_GREATER ( lest_CPLUSPLUS >= 202000L ) #if ! defined( lest_NO_SHORT_MACRO_NAMES ) && ! defined( lest_NO_SHORT_ASSERTION_NAMES ) # define MODULE lest_MODULE @@ -186,7 +205,7 @@ if ( lest::result score = lest_DECOMPOSE( expr ) ) \ throw lest::failure{ lest_LOCATION, #expr, score.decomposition }; \ else if ( lest_env.pass() ) \ - lest::report( lest_env.os, lest::passing{ lest_LOCATION, #expr, score.decomposition }, lest_env.context() ); \ + lest::report( lest_env.os, lest::passing{ lest_LOCATION, #expr, score.decomposition, lest_env.zen() }, lest_env.context() ); \ } \ catch(...) \ { \ @@ -201,7 +220,7 @@ if ( lest::result score = lest_DECOMPOSE( expr ) ) \ { \ if ( lest_env.pass() ) \ - lest::report( lest_env.os, lest::passing{ lest_LOCATION, lest::not_expr( #expr ), lest::not_expr( score.decomposition ) }, lest_env.context() ); \ + lest::report( lest_env.os, lest::passing{ lest_LOCATION, lest::not_expr( #expr ), lest::not_expr( score.decomposition ), lest_env.zen() }, lest_env.context() ); \ } \ else \ throw lest::failure{ lest_LOCATION, lest::not_expr( #expr ), lest::not_expr( score.decomposition ) }; \ @@ -381,8 +400,8 @@ struct success : message struct passing : success { - passing( location where_, text expr_, text decomposition_ ) - : success( "passed", where_, expr_ + " for " + decomposition_) {} + passing( location where_, text expr_, text decomposition_, bool zen ) + : success( "passed", where_, expr_ + (zen ? "":" for " + decomposition_) ) {} }; struct got_none : success @@ -524,14 +543,45 @@ inline char const * sfx( char const * txt ) { return txt; } inline char const * sfx( char const * ) { return ""; } #endif -inline std::string to_string( std::nullptr_t ) { return "nullptr"; } -inline std::string to_string( std::string const & txt ) { return "\"" + txt + "\"" ; } +inline std::string transformed( char chr ) +{ + struct Tr { char chr; char const * str; } table[] = + { + {'\\', "\\\\" }, + {'\r', "\\r" }, {'\f', "\\f" }, + {'\n', "\\n" }, {'\t', "\\t" }, + }; + + for ( auto tr : table ) + { + if ( chr == tr.chr ) + return tr.str; + } + + auto unprintable = [](char c){ return 0 <= c && c < ' '; }; + + auto to_hex_string = [](char c) + { + std::ostringstream os; + os << "\\x" << std::hex << std::setw(2) << std::setfill('0') << static_cast( static_cast(c) ); + return os.str(); + }; + + return unprintable( chr ) ? to_hex_string( chr ) : std::string( 1, chr ); +} + +inline std::string make_tran_string( std::string const & txt ) { std::ostringstream os; for(auto c:txt) os << transformed(c); return os.str(); } +inline std::string make_strg_string( std::string const & txt ) { return "\"" + make_tran_string( txt ) + "\"" ; } +inline std::string make_char_string( char chr ) { return "\'" + make_tran_string( std::string( 1, chr ) ) + "\'" ; } + +inline std::string to_string( std::nullptr_t ) { return "nullptr"; } +inline std::string to_string( std::string const & txt ) { return make_strg_string( txt ); } #if lest_FEATURE_WSTRING inline std::string to_string( std::wstring const & txt ) ; #endif -inline std::string to_string( char const * const txt ) { return txt ? to_string( std::string ( txt ) ) : "{null string}"; } -inline std::string to_string( char * const txt ) { return txt ? to_string( std::string ( txt ) ) : "{null string}"; } +inline std::string to_string( char const * const txt ) { return txt ? make_strg_string( txt ) : "{null string}"; } +inline std::string to_string( char * const txt ) { return txt ? make_strg_string( txt ) : "{null string}"; } #if lest_FEATURE_WSTRING inline std::string to_string( wchar_t const * const txt ) { return txt ? to_string( std::wstring( txt ) ) : "{null string}"; } inline std::string to_string( wchar_t * const txt ) { return txt ? to_string( std::wstring( txt ) ) : "{null string}"; } @@ -550,29 +600,9 @@ inline std::string to_string( unsigned long long value ) { return make_value_ inline std::string to_string( double value ) { return make_value_string( value ) ; } inline std::string to_string( float value ) { return make_value_string( value ) + sfx("f" ); } -inline std::string to_string( signed char chr ) { return to_string( static_cast( chr ) ); } -inline std::string to_string( unsigned char chr ) { return to_string( static_cast( chr ) ); } - -inline std::string to_string( char chr ) -{ - struct Tr { char chr; char const * str; } table[] = - { - {'\r', "'\\r'" }, {'\f', "'\\f'" }, - {'\n', "'\\n'" }, {'\t', "'\\t'" }, - }; - - for ( auto tr : table ) - { - if ( chr == tr.chr ) - return tr.str; - } - - auto unprintable = [](char c){ return 0 <= c && c < ' '; }; - - return unprintable( chr ) - ? to_string( static_cast( chr ) ) - : "\'" + std::string( 1, chr ) + "\'" ; -} +inline std::string to_string( signed char chr ) { return make_char_string( static_cast( chr ) ); } +inline std::string to_string( unsigned char chr ) { return make_char_string( static_cast( chr ) ); } +inline std::string to_string( char chr ) { return make_char_string( chr ); } template< typename T > struct is_streamable @@ -968,7 +998,7 @@ inline bool select( text name, texts include ) inline int indefinite( int repeat ) { return repeat == -1; } -using seed_t = unsigned long; +using seed_t = std::mt19937::result_type; struct options { @@ -979,6 +1009,7 @@ struct options bool tags = false; bool time = false; bool pass = false; + bool zen = false; bool lexical = false; bool random = false; bool verbose = false; @@ -999,12 +1030,14 @@ struct env env & operator()( text test ) { - testing = test; return *this; + clear(); testing = test; return *this; } bool abort() { return opt.abort; } bool pass() { return opt.pass; } + bool zen() { return opt.zen; } + void clear() { ctx.clear(); } void pop() { ctx.pop_back(); } void push( text proposition ) { ctx.emplace_back( proposition ); } @@ -1311,6 +1344,7 @@ inline auto split_arguments( texts args ) -> std::tuple else if ( opt == "-l" || "--list-tests" == opt ) { option.list = true; continue; } else if ( opt == "-t" || "--time" == opt ) { option.time = true; continue; } else if ( opt == "-p" || "--pass" == opt ) { option.pass = true; continue; } + else if ( opt == "-z" || "--pass-zen" == opt ) { option.zen = true; continue; } else if ( opt == "-v" || "--verbose" == opt ) { option.verbose = true; continue; } else if ( "--version" == opt ) { option.version = true; continue; } else if ( opt == "--order" && "declared" == val ) { /* by definition */ ; continue; } @@ -1322,6 +1356,8 @@ inline auto split_arguments( texts args ) -> std::tuple } in.push_back( arg ); } + option.pass = option.pass || option.zen; + return std::make_tuple( option, in ); } @@ -1337,6 +1373,7 @@ inline int usage( std::ostream & os ) " -g, --list-tags list tags of selected tests\n" " -l, --list-tests list selected tests\n" " -p, --pass also report passing tests\n" + " -z, --pass-zen ... without expansion\n" " -t, --time list duration of selected tests\n" " -v, --verbose also report passing or failing sections\n" " --order=declared use source code test order (default)\n" @@ -1437,9 +1474,9 @@ int run( test const (&specification)[N], int argc, char * argv[], std::ostream & } // namespace lest -#ifdef __clang__ +#if defined (__clang__) # pragma clang diagnostic pop -#elif defined __GNUC__ +#elif defined (__GNUC__) # pragma GCC diagnostic pop #endif