update util

This commit is contained in:
Patrick Brosi 2023-10-06 12:13:25 +02:00
parent a8c23b2c02
commit 580f1807f3
29 changed files with 2762 additions and 81 deletions

View file

@ -410,7 +410,8 @@ void RouterImpl<TW>::hops(const EdgeCandGroup& froms, const EdgeCandGroup& tos,
if (c < maxCost) { if (c < maxCost) {
rCosts->push_back({{frId, toId}, c}); rCosts->push_back({{frId, toId}, c});
if (TW::NEED_DIST) dists->push_back({{frId, toId}, dist}); if (TW::NEED_DIST)
dists->push_back({{frId, toId}, static_cast<uint32_t>(dist)});
} }
} }
} }

1700
src/util/3rdparty/RTree.h vendored Normal file

File diff suppressed because it is too large Load diff

View file

@ -19,6 +19,7 @@
#include <map> #include <map>
#include <thread> #include <thread>
#include "3rdparty/dtoa_milo.h" #include "3rdparty/dtoa_milo.h"
#include "util/String.h"
#define UNUSED(expr) do { (void)(expr); } while (0) #define UNUSED(expr) do { (void)(expr); } while (0)
#define TIME() std::chrono::high_resolution_clock::now() #define TIME() std::chrono::high_resolution_clock::now()
@ -55,6 +56,156 @@
namespace util { namespace util {
const static std::map<std::string, std::string> HTML_COLOR_NAMES = {
{"aliceblue","F0F8FF"},
{"antiquewhite","FAEBD7"},
{"aqua","00FFFF"},
{"aquamarine","7FFFD4"},
{"azure","F0FFFF"},
{"beige","F5F5DC"},
{"bisque","FFE4C4"},
{"black","000000"},
{"blanchedalmond","FFEBCD"},
{"blue","0000FF"},
{"blueviolet","8A2BE2"},
{"brown","A52A2A"},
{"burlywood","DEB887"},
{"cadetblue","5F9EA0"},
{"chartreuse","7FFF00"},
{"chocolate","D2691E"},
{"coral","FF7F50"},
{"cornflowerblue","6495ED"},
{"cornsilk","FFF8DC"},
{"crimson","DC143C"},
{"cyan","00FFFF"},
{"darkblue","00008B"},
{"darkcyan","008B8B"},
{"darkgoldenrod","B8860B"},
{"darkgray","A9A9A9"},
{"darkgreen","006400"},
{"darkgrey","A9A9A9"},
{"darkkhaki","BDB76B"},
{"darkmagenta","8B008B"},
{"darkolivegreen","556B2F"},
{"darkorange","FF8C00"},
{"darkorchid","9932CC"},
{"darkred","8B0000"},
{"darksalmon","E9967A"},
{"darkseagreen","8FBC8F"},
{"darkslateblue","483D8B"},
{"darkslategray","2F4F4F"},
{"darkslategrey","2F4F4F"},
{"darkturquoise","00CED1"},
{"darkviolet","9400D3"},
{"deeppink","FF1493"},
{"deepskyblue","00BFFF"},
{"dimgray","696969"},
{"dimgrey","696969"},
{"dodgerblue","1E90FF"},
{"firebrick","B22222"},
{"floralwhite","FFFAF0"},
{"forestgreen","228B22"},
{"fuchsia","FF00FF"},
{"gainsboro","DCDCDC"},
{"ghostwhite","F8F8FF"},
{"gold","FFD700"},
{"goldenrod","DAA520"},
{"gray","808080"},
{"green","008000"},
{"greenyellow","ADFF2F"},
{"grey","808080"},
{"honeydew","F0FFF0"},
{"hotpink","FF69B4"},
{"indianred","CD5C5C"},
{"indigo","4B0082"},
{"ivory","FFFFF0"},
{"khaki","F0E68C"},
{"lavender","E6E6FA"},
{"lavenderblush","FFF0F5"},
{"lawngreen","7CFC00"},
{"lemonchiffon","FFFACD"},
{"lightblue","ADD8E6"},
{"lightcoral","F08080"},
{"lightcyan","E0FFFF"},
{"lightgoldenrodyellow","FAFAD2"},
{"lightgray","D3D3D3"},
{"lightgreen","90EE90"},
{"lightgrey","D3D3D3"},
{"lightpink","FFB6C1"},
{"lightsalmon","FFA07A"},
{"lightseagreen","20B2AA"},
{"lightskyblue","87CEFA"},
{"lightslategray","778899"},
{"lightslategrey","778899"},
{"lightsteelblue","B0C4DE"},
{"lightyellow","FFFFE0"},
{"lime","00FF00"},
{"limegreen","32CD32"},
{"linen","FAF0E6"},
{"magenta","FF00FF"},
{"maroon","800000"},
{"mediumaquamarine","66CDAA"},
{"mediumblue","0000CD"},
{"mediumorchid","BA55D3"},
{"mediumpurple","9370DB"},
{"mediumseagreen","3CB371"},
{"mediumslateblue","7B68EE"},
{"mediumspringgreen","00FA9A"},
{"mediumturquoise","48D1CC"},
{"mediumvioletred","C71585"},
{"midnightblue","191970"},
{"mintcream","F5FFFA"},
{"mistyrose","FFE4E1"},
{"moccasin","FFE4B5"},
{"navajowhite","FFDEAD"},
{"navy","000080"},
{"oldlace","FDF5E6"},
{"olive","808000"},
{"olivedrab","6B8E23"},
{"orange","FFA500"},
{"orangered","FF4500"},
{"orchid","DA70D6"},
{"palegoldenrod","EEE8AA"},
{"palegreen","98FB98"},
{"paleturquoise","AFEEEE"},
{"palevioletred","DB7093"},
{"papayawhip","FFEFD5"},
{"peachpuff","FFDAB9"},
{"peru","CD853F"},
{"pink","FFC0CB"},
{"plum","DDA0DD"},
{"powderblue","B0E0E6"},
{"purple","800080"},
{"red","FF0000"},
{"rosybrown","BC8F8F"},
{"royalblue","4169E1"},
{"saddlebrown","8B4513"},
{"salmon","FA8072"},
{"sandybrown","F4A460"},
{"seagreen","2E8B57"},
{"seashell","FFF5EE"},
{"sienna","A0522D"},
{"silver","C0C0C0"},
{"skyblue","87CEEB"},
{"slateblue","6A5ACD"},
{"slategray","708090"},
{"slategrey","708090"},
{"snow","FFFAFA"},
{"springgreen","00FF7F"},
{"steelblue","4682B4"},
{"tan","D2B48C"},
{"teal","008080"},
{"thistle","D8BFD8"},
{"tomato","FF6347"},
{"turquoise","40E0D0"},
{"violet","EE82EE"},
{"wheat","F5DEB3"},
{"white","FFFFFF"},
{"whitesmoke","F5F5F5"},
{"yellow","FFFF00"},
{"yellowgreen","9ACD32"}
};
struct hashPair { struct hashPair {
template <class T1, class T2> template <class T1, class T2>
size_t operator()(const std::pair<T1, T2>& p) const { size_t operator()(const std::pair<T1, T2>& p) const {
@ -270,24 +421,6 @@ inline std::string getHomeDir() {
return ret; return ret;
} }
// _____________________________________________________________________________
inline char* readableSize(double size, size_t n, char* buf) {
int i = 0;
const char* units[] = {"B", "kB", "MB", "GB", "TB", "PB"};
while (size > 1024 && i < 5) {
size /= 1024;
i++;
}
snprintf(buf, n, "%.*f %s", i, size, units[i]);
return buf;
}
// _____________________________________________________________________________
inline std::string readableSize(double size) {
char buffer[30];
return readableSize(size, 30, buffer);
}
// _____________________________________________________________________________ // _____________________________________________________________________________
inline std::string getTmpDir() { inline std::string getTmpDir() {
// first, check if an env variable is set // first, check if an env variable is set
@ -330,6 +463,100 @@ inline std::string getTmpFName(std::string dir, std::string name,
return f; return f;
} }
// ___________________________________________________________________________
inline std::string rgbToHex(int r, int g, int b) {
char hexcol[16];
snprintf(hexcol, sizeof hexcol, "%02x%02x%02x", r, g, b);
return hexcol;
}
// ___________________________________________________________________________
inline void hsvToRgb(float* r, float* g, float* b, float h, float s, float v) {
int i;
float f, p, q, t;
if (s == 0) {
*r = *g = *b = v;
return;
}
h /= 60;
i = floor(h);
f = h - i;
p = v * (1 - s);
q = v * (1 - s * f);
t = v * (1 - s * (1 - f));
switch (i) {
case 0:
*r = v;
*g = t;
*b = p;
break;
case 1:
*r = q;
*g = v;
*b = p;
break;
case 2:
*r = p;
*g = v;
*b = t;
break;
case 3:
*r = p;
*g = q;
*b = v;
break;
case 4:
*r = t;
*g = p;
*b = v;
break;
default:
*r = v;
*g = p;
*b = q;
break;
}
}
// ___________________________________________________________________________
inline std::string normHtmlColor(const std::string& col) {
auto i = HTML_COLOR_NAMES.find(toLower(col));
if (i != HTML_COLOR_NAMES.end()) return i->second;
return col;
}
// ___________________________________________________________________________
inline std::string randomHtmlColor() {
double goldenRatio = 0.618033988749895;
double h = static_cast<double>(rand()) / static_cast<double>(RAND_MAX);
h += goldenRatio;
h = fmod(h, 1.0);
float r, g, b;
hsvToRgb(&r, &g, &b, h * 360, 0.95, 0.95);
return rgbToHex(r * 256, g * 256, b * 256);
}
// _____________________________________________________________________________
inline char* readableSize(double size, size_t n, char* buf) {
int i = 0;
const char* units[] = {"B", "kB", "MB", "GB", "TB", "PB"};
while (size > 1024 && i < 5) {
size /= 1024;
i++;
}
snprintf(buf, n, "%.*f %s", i, size, units[i]);
return buf;
}
// _____________________________________________________________________________
inline std::string readableSize(double size) {
char buffer[30];
return readableSize(size, 30, buffer);
}
// _____________________________________________________________________________ // _____________________________________________________________________________
class approx { class approx {
public: public:

View file

@ -22,6 +22,12 @@
namespace util { namespace util {
// _____________________________________________________________________________
inline bool endsWith(const std::string& a, const std::string& suff) {
if (suff.size() > a.size()) return false;
return a.compare(a.length() - suff.length(), suff.length(), suff) == 0;
}
// _____________________________________________________________________________ // _____________________________________________________________________________
inline std::string urlDecode(const std::string& encoded) { inline std::string urlDecode(const std::string& encoded) {
std::string decoded; std::string decoded;
@ -139,19 +145,30 @@ inline std::vector<std::string> split(std::string in, char sep) {
} }
// _____________________________________________________________________________ // _____________________________________________________________________________
inline std::string ltrim(std::string str) { inline std::string ltrim(std::string str, std::string c) {
str.erase(0, str.find_first_not_of(" \t\n\v\f\r")); str.erase(0, str.find_first_not_of(c));
return str; return str;
} }
// _____________________________________________________________________________ // _____________________________________________________________________________
inline std::string rtrim(std::string str) { inline std::string rtrim(std::string str, std::string c) {
str.erase(str.find_last_not_of(" \t\n\v\f\r") + 1); str.erase(str.find_last_not_of(c) + 1);
return str; return str;
} }
// _____________________________________________________________________________ // _____________________________________________________________________________
inline std::string trim(std::string str) { return ltrim(rtrim(str)); } inline std::string trim(std::string str, std::string c) {
return ltrim(rtrim(str, c), c);
}
// _____________________________________________________________________________
inline std::string ltrim(std::string str) { return ltrim(str, " \t\n\v\f\r"); }
// _____________________________________________________________________________
inline std::string rtrim(std::string str) { return rtrim(str, " \t\n\v\f\r"); }
// _____________________________________________________________________________
inline std::string trim(std::string str) { return trim(str, " \t\n\v\f\r"); }
// _____________________________________________________________________________ // _____________________________________________________________________________
inline size_t editDist(const std::string& s1, const std::string& s2) { inline size_t editDist(const std::string& s1, const std::string& s2) {

View file

@ -707,6 +707,55 @@ inline Point<T> intersection(const LineSegment<T>& s1,
return intersection(s1.first, s1.second, s2.first, s2.second); return intersection(s1.first, s1.second, s2.first, s2.second);
} }
// _____________________________________________________________________________
template <typename T>
inline std::vector<Point<T>> intersection(const Line<T>& l1,
const Line<T>& l2) {
std::vector<Point<T>> ret;
// TODO: better implementation than this naive baseline
for (size_t i = 1; i < l1.size(); i++) {
for (size_t j = 1; j < l2.size(); j++) {
LineSegment<T> a = {l1[i-1], l1[i]};
LineSegment<T> b = {l2[j-1], l2[j]};
if (intersects(a, b)) ret.push_back(intersection(a, b));
}
}
return ret;
}
// _____________________________________________________________________________
template <typename T>
inline Box<T> intersection(const Box<T>& b1, const Box<T>& b2) {
if (!intersects(b1, b2)) return Box<T>();
T llx, lly, urx, ury;
if (b1.getLowerLeft().getX() > b2.getLowerLeft().getX())
llx = b1.getLowerLeft().getX();
else
llx = b2.getLowerLeft().getX();
if (b1.getLowerLeft().getY() > b2.getLowerLeft().getY())
lly = b1.getLowerLeft().getY();
else
lly = b2.getLowerLeft().getY();
if (b1.getUpperRight().getX() < b2.getUpperRight().getX())
urx = b1.getUpperRight().getX();
else
urx = b2.getUpperRight().getX();
if (b1.getUpperRight().getY() < b2.getUpperRight().getY())
ury = b1.getUpperRight().getY();
else
ury = b2.getUpperRight().getY();
return Box<T>{{llx, lly}, {urx, ury}};
}
// _____________________________________________________________________________ // _____________________________________________________________________________
template <typename T> template <typename T>
inline bool lineIntersects(T p1x, T p1y, T q1x, T q1y, T p2x, T p2y, T q2x, inline bool lineIntersects(T p1x, T p1y, T q1x, T q1y, T p2x, T p2y, T q2x,
@ -898,6 +947,27 @@ inline double crossProd(const Point<T>& p, const LineSegment<T>& ls) {
Point<T>(p.getX() - ls.first.getX(), p.getY() - ls.first.getY())); Point<T>(p.getX() - ls.first.getX(), p.getY() - ls.first.getY()));
} }
// _____________________________________________________________________________
template <typename T>
inline double dist(const Polygon<T>& poly1, const Polygon<T>& poly2) {
if (contains(poly1, poly2) || contains(poly2, poly1)) return 0;
return dist(poly1.getOuter(), poly2.getOuter());
}
// _____________________________________________________________________________
template <typename T>
inline double dist(const Line<T>& l, const Polygon<T>& poly) {
if (contains(l, poly)) return 0;
return dist(l, poly.getOuter());
}
// _____________________________________________________________________________
template <typename T>
inline double dist(const Point<T>& p, const Polygon<T>& poly) {
if (contains(p, poly)) return 0;
return dist(p, poly.getOuter());
}
// _____________________________________________________________________________ // _____________________________________________________________________________
template <typename T> template <typename T>
inline double dist(const Point<T>& p1, const Point<T>& p2) { inline double dist(const Point<T>& p1, const Point<T>& p2) {
@ -908,6 +978,7 @@ inline double dist(const Point<T>& p1, const Point<T>& p2) {
template <typename T> template <typename T>
inline Point<T> pointFromWKT(std::string wkt) { inline Point<T> pointFromWKT(std::string wkt) {
wkt = util::normalizeWhiteSpace(util::trim(wkt)); wkt = util::normalizeWhiteSpace(util::trim(wkt));
for (size_t i = 0; i < 6;i++) wkt[i] = toupper(wkt[i]);
if (wkt.rfind("POINT") == 0 || wkt.rfind("MPOINT") == 0) { if (wkt.rfind("POINT") == 0 || wkt.rfind("MPOINT") == 0) {
size_t b = wkt.find("(") + 1; size_t b = wkt.find("(") + 1;
size_t e = wkt.find(")", b); size_t e = wkt.find(")", b);
@ -925,6 +996,7 @@ inline Point<T> pointFromWKT(std::string wkt) {
template <typename T> template <typename T>
inline Line<T> lineFromWKT(std::string wkt) { inline Line<T> lineFromWKT(std::string wkt) {
wkt = util::normalizeWhiteSpace(util::trim(wkt)); wkt = util::normalizeWhiteSpace(util::trim(wkt));
for (size_t i = 0; i < 11;i++) wkt[i] = toupper(wkt[i]);
if (wkt.rfind("LINESTRING") == 0 || wkt.rfind("MLINESTRING") == 0) { if (wkt.rfind("LINESTRING") == 0 || wkt.rfind("MLINESTRING") == 0) {
Line<T> ret; Line<T> ret;
size_t b = wkt.find("(") + 1; size_t b = wkt.find("(") + 1;
@ -943,6 +1015,96 @@ inline Line<T> lineFromWKT(std::string wkt) {
throw std::runtime_error("Could not parse WKT"); throw std::runtime_error("Could not parse WKT");
} }
// _____________________________________________________________________________
template <typename T>
inline MultiPolygon<T> multiPolygonFromWKT(std::string wkt) {
wkt = util::normalizeWhiteSpace(util::trim(wkt));
for (size_t i = 0; i < 13;i++) wkt[i] = toupper(wkt[i]);
util::replaceAll(wkt, "))", ")!");
util::replaceAll(wkt, ") )", ")!");
if (wkt.rfind("MULTIPOLYGON") == 0 || wkt.rfind("MMULTIPOLYGON") == 0) {
MultiPolygon<T> ret;
size_t b = wkt.find("(") + 1;
size_t e = wkt.rfind(")");
if (b > e) throw std::runtime_error("Could not parse WKT");
auto polyPairs = util::split(wkt.substr(b, e - b), '!');
for (const auto& polyPair : polyPairs) {
size_t b = polyPair.find("(") + 1;
size_t e = polyPair.rfind(")");
auto pairs = util::split(polyPair.substr(b, e - b), ')');
ret.push_back({});
for (size_t i = 0; i < pairs.size(); i++) {
size_t b = pairs[i].find("(") + 1;
size_t e = pairs[i].rfind(")", b);
auto pairsLoc = util::split(pairs[i].substr(b, e - b), ',');
if (i > 0) {
ret.back().getInners().push_back({});
}
for (const auto& p : pairsLoc) {
auto xy = util::split(util::trim(p), ' ');
if (xy.size() < 2) throw std::runtime_error("Could not parse WKT");
double x = atof(xy[0].c_str());
double y = atof(xy[1].c_str());
if (i == 0) {
ret.back().getOuter().push_back({x, y});
} else {
ret.back().getInners().back().push_back({x, y});
}
}
}
}
return ret;
}
throw std::runtime_error("Could not parse WKT");
}
// _____________________________________________________________________________
template <typename T>
inline Polygon<T> polygonFromWKT(std::string wkt) {
wkt = util::normalizeWhiteSpace(util::trim(wkt));
for (size_t i = 0; i < 8;i++) wkt[i] = toupper(wkt[i]);
if (wkt.rfind("POLYGON") == 0 || wkt.rfind("MPOLYGON") == 0) {
Polygon<T> ret;
size_t b = wkt.find("(") + 1;
size_t e = wkt.rfind(")");
if (b > e) throw std::runtime_error("Could not parse WKT");
auto pairs = util::split(wkt.substr(b, e - b), ')');
for (size_t i = 0; i < pairs.size(); i++) {
size_t b = pairs[i].find("(") + 1;
size_t e = pairs[i].rfind(")", b);
auto pairsLoc = util::split(pairs[i].substr(b, e - b), ',');
if (i > 0) {
ret.getInners().push_back({});
}
for (const auto& p : pairsLoc) {
auto xy = util::split(util::trim(p), ' ');
if (xy.size() < 2) throw std::runtime_error("Could not parse WKT");
double x = atof(xy[0].c_str());
double y = atof(xy[1].c_str());
if (i == 0) {
ret.getOuter().push_back({x, y});
} else {
ret.getInners().back().push_back({x, y});
}
}
}
return ret;
}
throw std::runtime_error("Could not parse WKT");
}
// _____________________________________________________________________________ // _____________________________________________________________________________
template <typename T> template <typename T>
inline std::string getWKT(const Point<T>& p) { inline std::string getWKT(const Point<T>& p) {
@ -1075,6 +1237,43 @@ inline double len(const Line<T>& g) {
return ret; return ret;
} }
// _____________________________________________________________________________
template <typename T>
inline bool shorterThan(const Line<T>& g, double d) {
double ret = 0;
for (size_t i = 1; i < g.size(); i++) {
ret += dist(g[i - 1], g[i]);
if (ret >= d) return false;
}
return true;
}
// _____________________________________________________________________________
template <typename T>
inline bool longerThan(const Line<T>& g, double d) {
double ret = 0;
for (size_t i = 1; i < g.size(); i++) {
ret += dist(g[i - 1], g[i]);
if (ret > d) return true;
}
return false;
}
// _____________________________________________________________________________
template <typename T>
inline bool longerThan(const Line<T>& a, const Line<T>& b, double d) {
double ret = 0;
for (size_t i = 1; i < a.size(); i++) {
ret += dist(a[i - 1], a[i]);
if (ret > d) return true;
}
for (size_t i = 1; i < b.size(); i++) {
ret += dist(b[i - 1], b[i]);
if (ret > d) return true;
}
return false;
}
// _____________________________________________________________________________ // _____________________________________________________________________________
template <typename T> template <typename T>
inline Point<T> simplify(const Point<T>& g, double d) { inline Point<T> simplify(const Point<T>& g, double d) {
@ -1317,6 +1516,9 @@ inline Polygon<T> buffer(const Polygon<T>& pol, double d, size_t points) {
// _____________________________________________________________________________ // _____________________________________________________________________________
template <typename T> template <typename T>
inline Box<T> extendBox(const Box<T>& a, Box<T> b) { inline Box<T> extendBox(const Box<T>& a, Box<T> b) {
if (a.getLowerLeft().getX() > a.getUpperRight().getX()) return b;
if (a.getLowerLeft().getY() > a.getUpperRight().getY()) return b;
b = extendBox(a.getLowerLeft(), b); b = extendBox(a.getLowerLeft(), b);
b = extendBox(a.getUpperRight(), b); b = extendBox(a.getUpperRight(), b);
return b; return b;
@ -1458,10 +1660,14 @@ inline Polygon<T> convexHull(const RotatedBox<T>& b) {
template <typename T> template <typename T>
inline size_t convexHullImpl(const MultiPoint<T>& a, size_t p1, size_t p2, inline size_t convexHullImpl(const MultiPoint<T>& a, size_t p1, size_t p2,
Line<T>* h) { Line<T>* h) {
// emergency stop
if (h->size() >= a.size() + 1) return 0;
// quickhull by Barber, Dobkin & Huhdanpaa // quickhull by Barber, Dobkin & Huhdanpaa
Point<T> pa; Point<T> pa;
bool found = false; bool found = false;
double maxDist = 0; double maxDist = 0;
for (const auto& p : a) { for (const auto& p : a) {
double tmpDist = distToSegment((*h)[p1], (*h)[p2], p); double tmpDist = distToSegment((*h)[p1], (*h)[p2], p);
double cp = crossProd(p, LineSegment<T>((*h)[p1], (*h)[p2])); double cp = crossProd(p, LineSegment<T>((*h)[p1], (*h)[p2]));
@ -1485,11 +1691,11 @@ inline Polygon<T> convexHull(const MultiPoint<T>& l) {
if (l.size() == 2) return convexHull(LineSegment<T>(l[0], l[1])); if (l.size() == 2) return convexHull(LineSegment<T>(l[0], l[1]));
if (l.size() == 1) return convexHull(l[0]); if (l.size() == 1) return convexHull(l[0]);
Point<T> left(std::numeric_limits<T>::max(), 0); Point<T> left(std::numeric_limits<T>::max(), std::numeric_limits<T>::max());
Point<T> right(std::numeric_limits<T>::lowest(), 0); Point<T> right(std::numeric_limits<T>::lowest(), std::numeric_limits<T>::lowest());
for (const auto& p : l) { for (const auto& p : l) {
if (p.getX() < left.getX()) left = p; if (p.getX() < left.getX() || (p.getX() == left.getX() && p.getY() < left.getY())) left = p;
if (p.getX() > right.getX()) right = p; if (p.getX() > right.getX() || (p.getX() == right.getX() && p.getY() > right.getY())) right = p;
} }
Line<T> hull{left, right}; Line<T> hull{left, right};

View file

@ -82,10 +82,18 @@ class Grid {
void add(size_t x, size_t y, V val); void add(size_t x, size_t y, V val);
void get(const Box<T>& btbox, std::set<V>* s) const; void get(const Box<T>& btbox, std::set<V>* s) const;
void get(const G<T>& geom, double d, std::set<V>* s) const;
template <template <typename> class GG>
void get(const GG<T>& geom, double d, std::set<V>* s) const;
template <template <typename> class GG>
void get(const std::vector<GG<T>>& geom, double d, std::set<V>* s) const;
void get(size_t x, size_t y, std::set<V>* s) const; void get(size_t x, size_t y, std::set<V>* s) const;
void remove(V val); void remove(V val);
const std::set<V>& getCell(size_t x, size_t y) const;
void getNeighbors(const V& val, double d, std::set<V>* s) const; void getNeighbors(const V& val, double d, std::set<V>* s) const;
void getCellNeighbors(const V& val, size_t d, std::set<V>* s) const; void getCellNeighbors(const V& val, size_t d, std::set<V>* s) const;
void getCellNeighbors(size_t x, size_t y, size_t xPerm, size_t yPerm, void getCellNeighbors(size_t x, size_t y, size_t xPerm, size_t yPerm,
@ -99,6 +107,9 @@ class Grid {
size_t getCellXFromX(double lon) const; size_t getCellXFromX(double lon) const;
size_t getCellYFromY(double lat) const; size_t getCellYFromY(double lat) const;
Box<T> getBox(size_t x, size_t y) const;
Box<T> getBBox() const { return _bb; };
private: private:
double _width; double _width;
double _height; double _height;
@ -117,8 +128,6 @@ class Grid {
std::set<V>** _grid; std::set<V>** _grid;
std::map<V, std::set<std::pair<size_t, size_t> > > _index; std::map<V, std::set<std::pair<size_t, size_t> > > _index;
std::set<V> _removed; std::set<V> _removed;
Box<T> getBox(size_t x, size_t y) const;
}; };
#include "util/geo/Grid.tpp" #include "util/geo/Grid.tpp"

View file

@ -95,7 +95,20 @@ void Grid<V, G, T>::get(const Box<T>& box, std::set<V>* s) const {
// _____________________________________________________________________________ // _____________________________________________________________________________
template <typename V, template <typename> class G, typename T> template <typename V, template <typename> class G, typename T>
void Grid<V, G, T>::get(const G<T>& geom, double d, std::set<V>* s) const { template <template <typename> class GG>
void Grid<V, G, T>::get(const GG<T>& geom, double d, std::set<V>* s) const {
Box<T> a = getBoundingBox(geom);
Box<T> b(
Point<T>(a.getLowerLeft().getX() - d, a.getLowerLeft().getY() - d),
Point<T>(a.getUpperRight().getX() + d, a.getUpperRight().getY() + d));
return get(b, s);
}
// _____________________________________________________________________________
template <typename V, template <typename> class G, typename T>
template <template <typename> class GG>
void Grid<V, G, T>::get(const std::vector<GG<T>>& geom, double d,
std::set<V>* s) const {
Box<T> a = getBoundingBox(geom); Box<T> a = getBoundingBox(geom);
Box<T> b( Box<T> b(
Point<T>(a.getLowerLeft().getX() - d, a.getLowerLeft().getY() - d), Point<T>(a.getLowerLeft().getX() - d, a.getLowerLeft().getY() - d),
@ -117,6 +130,12 @@ void Grid<V, G, T>::get(size_t x, size_t y, std::set<V>* s) const {
} }
} }
// _____________________________________________________________________________
template <typename V, template <typename> class G, typename T>
const std::set<V>& Grid<V, G, T>::getCell(size_t x, size_t y) const {
return _grid[x][y];
}
// _____________________________________________________________________________ // _____________________________________________________________________________
template <typename V, template <typename> class G, typename T> template <typename V, template <typename> class G, typename T>
void Grid<V, G, T>::remove(V val) { void Grid<V, G, T>::remove(V val) {
@ -182,7 +201,7 @@ void Grid<V, G, T>::getCellNeighbors(size_t cx, size_t cy, size_t xPerm,
// _____________________________________________________________________________ // _____________________________________________________________________________
template <typename V, template <typename> class G, typename T> template <typename V, template <typename> class G, typename T>
std::set<std::pair<size_t, size_t> > Grid<V, G, T>::getCells( std::set<std::pair<size_t, size_t>> Grid<V, G, T>::getCells(
const V& val) const { const V& val) const {
if (!_hasValIdx) throw GridException("No value index build!"); if (!_hasValIdx) throw GridException("No value index build!");
return _index.find(val)->second; return _index.find(val)->second;

View file

@ -29,14 +29,22 @@ class Point {
return Point<T>(_x - p.getX(), _y - p.getY()); return Point<T>(_x - p.getX(), _y - p.getY());
} }
// bool operator==(const Point<T>& p) const {
// return p.getX() == _x && p.getY() == _y;
// }
bool operator==(const Point<T>& p) const { bool operator==(const Point<T>& p) const {
return p.getX() == _x && p.getY() == _y; return fabs(p.getX() - _x) < 0.00001 && fabs(p.getY() - _y) < 0.00001;
} }
bool operator!=(const Point<T>& p) const { bool operator!=(const Point<T>& p) const {
return !(*this == p); return !(*this == p);
} }
bool operator<(const Point<T>& p) const {
return _x < p.getX() || (_x == p.getX() && _y < p.getY());
}
private: private:
T _x, _y; T _x, _y;
}; };

View file

@ -55,6 +55,18 @@ class PolyLine {
PolyLine(); PolyLine();
PolyLine(const Point<T>& from, const Point<T>& to); PolyLine(const Point<T>& from, const Point<T>& to);
PolyLine(const Line<T>& l); PolyLine(const Line<T>& l);
PolyLine(const PolyLine<T>& l);
PolyLine(PolyLine<T>&& l);
PolyLine& operator=(PolyLine<T>&& other) {
_line = std::move(other._line);
return *this;
}
PolyLine& operator=(const PolyLine<T>& other) {
_line = other._line;
return *this;
}
PolyLine& operator<<(const Point<T>& p); PolyLine& operator<<(const Point<T>& p);
PolyLine& operator>>(const Point<T>& p); PolyLine& operator>>(const Point<T>& p);
@ -67,11 +79,14 @@ class PolyLine {
PolyLine offsetted(double units) const; PolyLine offsetted(double units) const;
const Line<T>& getLine() const; const Line<T>& getLine() const;
Line<T>& getLine();
double distTo(const PolyLine<T>& g) const; double distTo(const PolyLine<T>& g) const;
double distTo(const Point<T>& p) const; double distTo(const Point<T>& p) const;
double getLength() const; double getLength() const;
bool shorterThan(double d) const;
bool longerThan(double d) const;
// return point at dist // return point at dist
LinePoint<T> getPointAtDist(double dist) const; LinePoint<T> getPointAtDist(double dist) const;
@ -117,6 +132,7 @@ class PolyLine {
std::string getWKT() const; std::string getWKT() const;
PolyLine getOrthoLineAtDist(double d, double lengt) const; PolyLine getOrthoLineAtDist(double d, double lengt) const;
PolyLine getOrthoLineAt(double d, double lengt) const;
Point<T> interpolate(const Point<T>& a, const Point<T>& b, double p) const; Point<T> interpolate(const Point<T>& a, const Point<T>& b, double p) const;

View file

@ -12,6 +12,16 @@ PolyLine<T>::PolyLine(const Point<T>& from, const Point<T>& to) {
*this << from << to; *this << from << to;
} }
// _____________________________________________________________________________
template <typename T>
PolyLine<T>::PolyLine(const PolyLine<T>& l) : _line(l._line) {
}
// _____________________________________________________________________________
template <typename T>
PolyLine<T>::PolyLine(PolyLine<T>&& l) : _line(std::move(l._line)) {
}
// _____________________________________________________________________________ // _____________________________________________________________________________
template <typename T> template <typename T>
PolyLine<T>::PolyLine(const Line<T>& l) : _line(l) {} PolyLine<T>::PolyLine(const Line<T>& l) : _line(l) {}
@ -50,6 +60,12 @@ const Line<T>& PolyLine<T>::getLine() const {
return _line; return _line;
} }
// _____________________________________________________________________________
template <typename T>
Line<T>& PolyLine<T>::getLine() {
return _line;
}
// _____________________________________________________________________________ // _____________________________________________________________________________
template <typename T> template <typename T>
PolyLine<T> PolyLine<T>::offsetted(double units) const { PolyLine<T> PolyLine<T>::offsetted(double units) const {
@ -73,9 +89,10 @@ void PolyLine<T>::offsetPerp(double units) {
if (_line.size() < 2) return; if (_line.size() < 2) return;
Line<T> ret; Line<T> ret;
ret.reserve(_line.size());
Point<T> lastP = _line.front(); Point<T> lastP = _line.front();
Point<T> *lastIns = 0, *befLastIns = 0; Point<T>*lastIns = 0, *befLastIns = 0;
for (size_t i = 1; i < _line.size(); i++) { for (size_t i = 1; i < _line.size(); i++) {
Point<T> curP = _line[i]; Point<T> curP = _line[i];
@ -99,22 +116,28 @@ void PolyLine<T>::offsetPerp(double units) {
if (lastIns && befLastIns && if (lastIns && befLastIns &&
lineIntersects(*lastIns, *befLastIns, lastP, curP)) { lineIntersects(*lastIns, *befLastIns, lastP, curP)) {
*lastIns = intersection(*lastIns, *befLastIns, lastP, curP); auto iSect = intersection(*lastIns, *befLastIns, lastP, curP);
double d = dist(lastP, *lastIns); double d = fmax(dist(lastP, iSect), dist(*lastIns, iSect));
double d2 = distToSegment(*lastIns, *befLastIns, lastP); double d2 = distToSegment(iSect, *befLastIns, lastP);
if (d > fabs(units) * 2 && d2 < d - (fabs(units))) { if (d > fabs(units) * 2.0 && d2 < d - (fabs(units))) {
PolyLine pl(*lastIns, *befLastIns); PolyLine pl(iSect, *befLastIns);
PolyLine pll(*lastIns, curP); PolyLine pll(iSect, curP);
pl = pl.getSegment(0, (d - (fabs(units))) / pl.getLength()); pl = pl.getSegment(0, (d - (fabs(units))) / pl.getLength());
pll = pll.getSegment(0, (d - (fabs(units))) / pll.getLength()); pll = pll.getSegment(0, (d - (fabs(units))) / pll.getLength());
ret.push_back(pll.back()); // careful, after push_back() below, lastIns might point to another
// point because of reallocation
*lastIns = pl.back(); *lastIns = pl.back();
ret.push_back(pll.back());
ret.push_back(curP); ret.push_back(curP);
} else { } else {
// careful, after push_back() below, lastIns might point to another
// point because of reallocation
*lastIns = iSect;
ret.push_back(curP); ret.push_back(curP);
} }
} else { } else {
@ -249,8 +272,7 @@ Point<T> PolyLine<T>::interpolate(const Point<T>& a, const Point<T>& b,
double n = sqrt(n1 * n1 + n2 * n2); double n = sqrt(n1 * n1 + n2 * n2);
n1 = n1 / n; n1 = n1 / n;
n2 = n2 / n; n2 = n2 / n;
return Point<T>(a.getX() + (n1 * p), return Point<T>(a.getX() + (n1 * p), a.getY() + (n2 * p));
a.getY() + (n2 * p));
} }
// _____________________________________________________________________________ // _____________________________________________________________________________
@ -271,11 +293,39 @@ double PolyLine<T>::getLength() const {
return len(_line); return len(_line);
} }
// _____________________________________________________________________________
template <typename T>
bool PolyLine<T>::shorterThan(double d) const {
return util::geo::shorterThan(_line, d);
}
// _____________________________________________________________________________
template <typename T>
bool PolyLine<T>::longerThan(double d) const {
return util::geo::longerThan(_line, d);
}
// _____________________________________________________________________________ // _____________________________________________________________________________
template <typename T> template <typename T>
PolyLine<T> PolyLine<T>::average(const std::vector<const PolyLine<T>*>& lines, PolyLine<T> PolyLine<T>::average(const std::vector<const PolyLine<T>*>& lines,
const std::vector<double>& weights) { const std::vector<double>& weights) {
bool weighted = lines.size() == weights.size(); bool weighted = lines.size() == weights.size();
if (!weighted && lines.size() == 2 && lines[0]->getLine().size() == 2 &&
lines[1]->getLine().size() == 2) {
// simple case
util::geo::Line<T> avg(2);
const auto& a = lines[0]->getLine();
const auto& b = lines[1]->getLine();
avg[0] = {(a[0].getX() + b[0].getX()) / 2.0,
(a[0].getY() + b[0].getY()) / 2.0};
avg[1] = {(a[1].getX() + b[1].getX()) / 2.0,
(a[1].getY() + b[1].getY()) / 2.0};
return avg;
}
double stepSize; double stepSize;
double longestLength = DBL_MIN; // avoid recalc of length on each comparision double longestLength = DBL_MIN; // avoid recalc of length on each comparision
@ -320,7 +370,7 @@ PolyLine<T> PolyLine<T>::average(const std::vector<const PolyLine<T>*>& lines,
ret << Point<T>(x / total, y / total); ret << Point<T>(x / total, y / total);
} }
ret.simplify(0); ret.simplify(0.0001);
return ret; return ret;
} }
@ -516,6 +566,12 @@ std::set<LinePoint<T>, LinePointCmp<T>> PolyLine<T>::getIntersections(
return ret; return ret;
} }
// _____________________________________________________________________________
template <typename T>
PolyLine<T> PolyLine<T>::getOrthoLineAt(double d, double length) const {
return getOrthoLineAtDist(getLength() * d, length);
}
// _____________________________________________________________________________ // _____________________________________________________________________________
template <typename T> template <typename T>
PolyLine<T> PolyLine<T>::getOrthoLineAtDist(double d, double length) const { PolyLine<T> PolyLine<T>::getOrthoLineAtDist(double d, double length) const {
@ -610,12 +666,10 @@ void PolyLine<T>::applyChaikinSmooth(size_t depth) {
Point<T> pA = _line[i - 1]; Point<T> pA = _line[i - 1];
Point<T> pB = _line[i]; Point<T> pB = _line[i];
smooth.push_back( smooth.push_back(Point<T>(0.75 * pA.getX() + 0.25 * pB.getX(),
Point<T>(0.75 * pA.getX() + 0.25 * pB.getX(), 0.75 * pA.getY() + 0.25 * pB.getY()));
0.75 * pA.getY() + 0.25 * pB.getY())); smooth.push_back(Point<T>(0.25 * pA.getX() + 0.75 * pB.getX(),
smooth.push_back( 0.25 * pA.getY() + 0.75 * pB.getY()));
Point<T>(0.25 * pA.getX() + 0.75 * pB.getX(),
0.25 * pA.getY() + 0.75 * pB.getY()));
} }
smooth.push_back(_line.back()); smooth.push_back(_line.back());

View file

@ -29,8 +29,12 @@ class Polygon {
const Line<T>& getOuter() const { return _outer; } const Line<T>& getOuter() const { return _outer; }
Line<T>& getOuter() { return _outer; } Line<T>& getOuter() { return _outer; }
const std::vector<Line<T>>& getInners() const { return _inners; }
std::vector<Line<T>>& getInners() { return _inners; }
private: private:
Line<T> _outer; Line<T> _outer;
std::vector<Line<T>> _inners;
}; };
template <typename T> template <typename T>

82
src/util/geo/RTree.h Normal file
View file

@ -0,0 +1,82 @@
// Copyright 2023, University of Freiburg,
// Chair of Algorithms and Data Structures.
// Author: Patrick Brosi <brosi@informatik.uni-freiburg.de>
#ifndef UTIL_GEO_RTREE_H_
#define UTIL_GEO_RTREE_H_
#include <unordered_map>
#include <set>
#include <vector>
#include "util/3rdparty/RTree.h"
namespace util {
namespace geo {
class RTreeException : public std::runtime_error {
public:
RTreeException(std::string const& msg) : std::runtime_error(msg) {}
};
template <typename V, template <typename> class G, typename T>
class RTree {
public:
// RTree(const RTree<V, G, T>&) = delete;
// RTree(RTree<V, G, T>&& o) = delete;
// the empty RTree
RTree() : _rtree(new DA::RTree<V, T, 2, T>()) {};
~RTree() {if (_rtree) delete _rtree;};
RTree(const RTree<V, G, T>&) = delete;
RTree(RTree<V, G, T>&& o) {
_valIdx = std::move(o._valIdx);
_rtree = o._rtree;
o._rtree = 0;
}
RTree<V, G, T>& operator=(RTree<V, G, T>&& o) {
_valIdx = std::move(o._valIdx);
_rtree = o._rtree;
o._rtree = 0;
return *this;
};
// add object t to this RTree
void add(G<T> geom, V val);
void get(const Box<T>& btbox, std::set<V>* s) const;
template <template <typename> class GG>
void get(const GG<T>& geom, double d, std::set<V>* s) const;
template <template <typename> class GG>
void get(const std::vector<GG<T>>& geom, double d, std::set<V>* s) const;
void get(const Box<T>& btbox, std::vector<V>* s) const;
template <template <typename> class GG>
void get(const GG<T>& geom, double d, std::vector<V>* s) const;
template <template <typename> class GG>
void get(const std::vector<GG<T>>& geom, double d, std::vector<V>* s) const;
void remove(V val);
void getNeighbors(const V& val, double d, std::set<V>* s) const;
private:
DA::RTree<V, T, 2, T>* _rtree = 0;
std::unordered_map<V, util::geo::Box<T>> _valIdx;
static bool searchCb(V val, void* arg);
};
#include "util/geo/RTree.tpp"
} // namespace geo
} // namespace util
#endif // UTIL_GEO_RTREE_H_

134
src/util/geo/RTree.tpp Normal file
View file

@ -0,0 +1,134 @@
// Copyright 2023, University of Freiburg,
// Chair of Algorithms and Data Structures.
// Author: Patrick Brosi <brosip@informatik.uni-freiburg.de>
// _____________________________________________________________________________
template <typename V, template <typename> class G, typename T>
void RTree<V, G, T>::add(G<T> geom, V val) {
Box<T> box = getBoundingBox(geom);
T minCoords[2];
T maxCoords[2];
minCoords[0] = box.getLowerLeft().getX();
minCoords[1] = box.getLowerLeft().getY();
maxCoords[0] = box.getUpperRight().getX();
maxCoords[1] = box.getUpperRight().getY();
if (_valIdx.count(val)) assert(false);
_valIdx[val] = box;
_rtree->Insert(minCoords, maxCoords, val);
}
// _____________________________________________________________________________
template <typename V, template <typename> class G, typename T>
bool RTree<V, G, T>::searchCb(V val, void* s) {
static_cast<std::set<V>*>(s)->insert(val);
return true;
}
// _____________________________________________________________________________
template <typename V, template <typename> class G, typename T>
void RTree<V, G, T>::get(const Box<T>& box, std::set<V>* s) const {
T minCoords[2];
T maxCoords[2];
minCoords[0] = box.getLowerLeft().getX();
minCoords[1] = box.getLowerLeft().getY();
maxCoords[0] = box.getUpperRight().getX();
maxCoords[1] = box.getUpperRight().getY();
std::function<bool(const V&)> f = [s](const V& val) {
s->insert(val);
return true;
};
_rtree->Search(minCoords, maxCoords, f);
}
// _____________________________________________________________________________
template <typename V, template <typename> class G, typename T>
void RTree<V, G, T>::get(const Box<T>& box, std::vector<V>* s) const {
T minCoords[2];
T maxCoords[2];
minCoords[0] = box.getLowerLeft().getX();
minCoords[1] = box.getLowerLeft().getY();
maxCoords[0] = box.getUpperRight().getX();
maxCoords[1] = box.getUpperRight().getY();
std::function<bool(const V&)> f = [s](const V& val) {
s->push_back(val);
return true;
};
_rtree->Search(minCoords, maxCoords, f);
}
// _____________________________________________________________________________
template <typename V, template <typename> class G, typename T>
void RTree<V, G, T>::remove(V val) {
auto bit = _valIdx.find(val);
if (bit == _valIdx.end()) return;
Box<T> box = bit->second;
T minCoords[2];
T maxCoords[2];
minCoords[0] = box.getLowerLeft().getX();
minCoords[1] = box.getLowerLeft().getY();
maxCoords[0] = box.getUpperRight().getX();
maxCoords[1] = box.getUpperRight().getY();
_valIdx.erase(bit);
bool notFound = _rtree->Remove(minCoords, maxCoords, val);
assert(!notFound);
}
// _____________________________________________________________________________
template <typename V, template <typename> class G, typename T>
template <template <typename> class GG>
void RTree<V, G, T>::get(const GG<T>& geom, double d, std::set<V>* s) const {
return get(util::geo::pad(getBoundingBox(geom), d), s);
}
// _____________________________________________________________________________
template <typename V, template <typename> class G, typename T>
template <template <typename> class GG>
void RTree<V, G, T>::get(const std::vector<GG<T>>& geom, double d,
std::set<V>* s) const {
return get(util::geo::pad(getBoundingBox(geom), d), s);
}
// _____________________________________________________________________________
template <typename V, template <typename> class G, typename T>
template <template <typename> class GG>
void RTree<V, G, T>::get(const GG<T>& geom, double d, std::vector<V>* s) const {
return get(util::geo::pad(getBoundingBox(geom), d), s);
}
// _____________________________________________________________________________
template <typename V, template <typename> class G, typename T>
template <template <typename> class GG>
void RTree<V, G, T>::get(const std::vector<GG<T>>& geom, double d,
std::vector<V>* s) const {
return get(util::geo::pad(getBoundingBox(geom), d), s);
}
// _____________________________________________________________________________
template <typename V, template <typename> class G, typename T>
void RTree<V, G, T>::getNeighbors(const V& val, double d,
std::set<V>* s) const {
auto bit = _valIdx.find(val);
if (bit == _valIdx.end()) return;
Box<T> box = util::geo::pad(bit->second, d);
return get(box, s);
}

View file

@ -36,6 +36,15 @@ class GeoGraphJsonOutput {
void printLatLng(const util::graph::Graph<N, E>& outG, std::ostream& str, void printLatLng(const util::graph::Graph<N, E>& outG, std::ostream& str,
json::Val attrs); json::Val attrs);
// print a graph to the provided GeoJsonOutput, but treat coordinates as Web Mercator
// coordinates and reproject to WGS84
template <typename N, typename E>
void printLatLng(const util::graph::Graph<N, E>& outG, GeoJsonOutput* out);
// print a graph to the provided GeoJsonOutput
template <typename N, typename E>
void print(const util::graph::Graph<N, E>& outG, GeoJsonOutput* out);
private: private:
template <typename T> template <typename T>
Line<T> createLine(const util::geo::Point<T>& a, Line<T> createLine(const util::geo::Point<T>& a,
@ -45,6 +54,11 @@ class GeoGraphJsonOutput {
template <typename N, typename E> template <typename N, typename E>
void printImpl(const util::graph::Graph<N, E>& outG, std::ostream& str, void printImpl(const util::graph::Graph<N, E>& outG, std::ostream& str,
bool proj, json::Val attrs); bool proj, json::Val attrs);
// print a graph to the provided path
template <typename N, typename E>
void printImpl(const util::graph::Graph<N, E>& outG,
bool proj, GeoJsonOutput* out);
}; };
#include "util/geo/output/GeoGraphJsonOutput.tpp" #include "util/geo/output/GeoGraphJsonOutput.tpp"

View file

@ -22,7 +22,7 @@ void GeoGraphJsonOutput::print(const util::graph::Graph<N, E>& outG,
// _____________________________________________________________________________ // _____________________________________________________________________________
template <typename N, typename E> template <typename N, typename E>
void GeoGraphJsonOutput::printLatLng(const util::graph::Graph<N, E>& outG, void GeoGraphJsonOutput::printLatLng(const util::graph::Graph<N, E>& outG,
std::ostream& str) { std::ostream& str) {
printImpl(outG, str, true, {}); printImpl(outG, str, true, {});
} }
@ -36,17 +36,38 @@ void GeoGraphJsonOutput::print(const util::graph::Graph<N, E>& outG,
// _____________________________________________________________________________ // _____________________________________________________________________________
template <typename N, typename E> template <typename N, typename E>
void GeoGraphJsonOutput::printLatLng(const util::graph::Graph<N, E>& outG, void GeoGraphJsonOutput::printLatLng(const util::graph::Graph<N, E>& outG,
std::ostream& str, json::Val attrs) { std::ostream& str, json::Val attrs) {
printImpl(outG, str, true, attrs); printImpl(outG, str, true, attrs);
} }
// _____________________________________________________________________________
template <typename N, typename E>
void GeoGraphJsonOutput::printLatLng(const util::graph::Graph<N, E>& outG,
GeoJsonOutput* out) {
printImpl(outG, true, out);
}
// _____________________________________________________________________________
template <typename N, typename E>
void GeoGraphJsonOutput::print(const util::graph::Graph<N, E>& outG,
GeoJsonOutput* out) {
printImpl(outG, false, out);
}
// _____________________________________________________________________________ // _____________________________________________________________________________
template <typename N, typename E> template <typename N, typename E>
void GeoGraphJsonOutput::printImpl(const util::graph::Graph<N, E>& outG, void GeoGraphJsonOutput::printImpl(const util::graph::Graph<N, E>& outG,
std::ostream& str, bool proj, json::Val attrs) { std::ostream& str, bool proj,
json::Val attrs) {
GeoJsonOutput _out(str, attrs); GeoJsonOutput out(str, attrs);
printImpl(outG, proj, &out);
out.flush();
}
// _____________________________________________________________________________
template <typename N, typename E>
void GeoGraphJsonOutput::printImpl(const util::graph::Graph<N, E>& outG,
bool proj, GeoJsonOutput* out) {
// first pass, nodes // first pass, nodes
for (util::graph::Node<N, E>* n : outG.getNds()) { for (util::graph::Node<N, E>* n : outG.getNds()) {
if (!n->pl().getGeom()) continue; if (!n->pl().getGeom()) continue;
@ -60,9 +81,9 @@ void GeoGraphJsonOutput::printImpl(const util::graph::Graph<N, E>& outG,
props.insert(addProps.begin(), addProps.end()); props.insert(addProps.begin(), addProps.end());
if (proj) { if (proj) {
_out.printLatLng(*n->pl().getGeom(), props); out->printLatLng(*n->pl().getGeom(), props);
} else { } else {
_out.print(*n->pl().getGeom(), props); out->print(*n->pl().getGeom(), props);
} }
} }
@ -84,21 +105,19 @@ void GeoGraphJsonOutput::printImpl(const util::graph::Graph<N, E>& outG,
if (e->getTo()->pl().getGeom()) { if (e->getTo()->pl().getGeom()) {
auto b = *e->getTo()->pl().getGeom(); auto b = *e->getTo()->pl().getGeom();
if (proj) { if (proj) {
_out.printLatLng(createLine(a, b), props); out->printLatLng(createLine(a, b), props);
} else { } else {
_out.print(createLine(a, b), props); out->print(createLine(a, b), props);
} }
} }
} }
} else { } else {
if (proj) { if (proj) {
_out.printLatLng(*e->pl().getGeom(), props); out->printLatLng(*e->pl().getGeom(), props);
} else { } else {
_out.print(*e->pl().getGeom(), props); out->print(*e->pl().getGeom(), props);
} }
} }
} }
} }
_out.flush();
} }

View file

@ -9,11 +9,16 @@ using namespace geo;
using namespace output; using namespace output;
// _____________________________________________________________________________ // _____________________________________________________________________________
GeoJsonOutput::GeoJsonOutput(std::ostream& str) : _wr(&str, 10, true) { GeoJsonOutput::GeoJsonOutput(std::ostream& str) : GeoJsonOutput(str, false) {}
_wr.obj();
_wr.keyVal("type", "FeatureCollection"); // _____________________________________________________________________________
_wr.key("features"); GeoJsonOutput::GeoJsonOutput(std::ostream& str, bool raw) : _wr(&str, 10, true) {
_wr.arr(); if (!raw) {
_wr.obj();
_wr.keyVal("type", "FeatureCollection");
_wr.key("features");
_wr.arr();
}
} }
// _____________________________________________________________________________ // _____________________________________________________________________________

View file

@ -19,12 +19,16 @@ namespace output {
class GeoJsonOutput { class GeoJsonOutput {
public: public:
GeoJsonOutput(std::ostream& str); GeoJsonOutput(std::ostream& str);
GeoJsonOutput(std::ostream& str, bool raw);
GeoJsonOutput(std::ostream& str, json::Val attrs); GeoJsonOutput(std::ostream& str, json::Val attrs);
~GeoJsonOutput(); ~GeoJsonOutput();
template <typename T> template <typename T>
void print(const Point<T>& p, json::Val attrs); void print(const Point<T>& p, json::Val attrs);
template <typename T>
void print(const MultiPoint<T>& ps, json::Val attrs);
template <typename T> template <typename T>
void print(const Line<T>& l, json::Val attrs); void print(const Line<T>& l, json::Val attrs);
@ -40,6 +44,9 @@ class GeoJsonOutput {
template <typename T> template <typename T>
void printLatLng(const Point<T>& p, json::Val attrs); void printLatLng(const Point<T>& p, json::Val attrs);
template <typename T>
void printLatLng(const MultiPoint<T>& ps, json::Val attrs);
template <typename T> template <typename T>
void printLatLng(const Line<T>& l, json::Val attrs); void printLatLng(const Line<T>& l, json::Val attrs);

View file

@ -22,6 +22,31 @@ void GeoJsonOutput::print(const Point<T>& p, json::Val attrs) {
_wr.close(); _wr.close();
} }
// _____________________________________________________________________________
template <typename T>
void GeoJsonOutput::print(const MultiPoint<T>& ps, json::Val attrs) {
if (!ps.size()) return;
_wr.obj();
_wr.keyVal("type", "Feature");
_wr.key("geometry");
_wr.obj();
_wr.keyVal("type", "MultiPoint");
_wr.key("coordinates");
_wr.arr();
for (auto p : ps) {
_wr.arr();
_wr.val(p.getX());
_wr.val(p.getY());
_wr.close();
}
_wr.close();
_wr.close();
_wr.key("properties");
_wr.val(attrs);
_wr.close();
}
// _____________________________________________________________________________ // _____________________________________________________________________________
template <typename T> template <typename T>
void GeoJsonOutput::print(const Line<T>& line, json::Val attrs) { void GeoJsonOutput::print(const Line<T>& line, json::Val attrs) {
@ -65,6 +90,7 @@ void GeoJsonOutput::print(const Polygon<T>& poly, json::Val attrs) {
_wr.keyVal("type", "Polygon"); _wr.keyVal("type", "Polygon");
_wr.key("coordinates"); _wr.key("coordinates");
_wr.arr(); _wr.arr();
_wr.arr(); _wr.arr();
for (auto p : poly.getOuter()) { for (auto p : poly.getOuter()) {
_wr.arr(); _wr.arr();
@ -72,8 +98,19 @@ void GeoJsonOutput::print(const Polygon<T>& poly, json::Val attrs) {
_wr.val(p.getY()); _wr.val(p.getY());
_wr.close(); _wr.close();
} }
_wr.close(); _wr.close();
for (const auto& inner : poly.getInners()) {
_wr.arr();
for (auto p : inner) {
_wr.arr();
_wr.val(p.getX());
_wr.val(p.getY());
_wr.close();
}
_wr.close();
}
_wr.close(); _wr.close();
_wr.close(); _wr.close();
_wr.key("properties"); _wr.key("properties");
@ -90,16 +127,26 @@ void GeoJsonOutput::print(const MultiPolygon<T>& mpoly, json::Val attrs) {
// _____________________________________________________________________________ // _____________________________________________________________________________
template <typename T> template <typename T>
void GeoJsonOutput::printLatLng(const Point<T>& p, json::Val attrs) { void GeoJsonOutput::printLatLng(const Point<T>& p, json::Val attrs) {
auto projP = util::geo::webMercToLatLng<double>(p.getX(), p.getY()); auto projP = util::geo::webMercToLatLng<T>(p.getX(), p.getY());
print(projP, attrs); print(projP, attrs);
} }
// _____________________________________________________________________________
template <typename T>
void GeoJsonOutput::printLatLng(const MultiPoint<T>& ps, json::Val attrs) {
MultiPoint<T> projPs;
for (auto p : ps)
projPs.push_back(util::geo::webMercToLatLng<T>(p.getX(), p.getY()));
print(projPs, attrs);
}
// _____________________________________________________________________________ // _____________________________________________________________________________
template <typename T> template <typename T>
void GeoJsonOutput::printLatLng(const Line<T>& line, json::Val attrs) { void GeoJsonOutput::printLatLng(const Line<T>& line, json::Val attrs) {
Line<T> projL; Line<T> projL;
for (auto p : line) for (auto p : line)
projL.push_back(util::geo::webMercToLatLng<double>(p.getX(), p.getY())); projL.push_back(util::geo::webMercToLatLng<T>(p.getX(), p.getY()));
print(projL, attrs); print(projL, attrs);
} }
@ -114,8 +161,8 @@ void GeoJsonOutput::printLatLng(const MultiLine<T>& mline, json::Val attrs) {
template <typename T> template <typename T>
void GeoJsonOutput::printLatLng(const Polygon<T>& poly, json::Val attrs) { void GeoJsonOutput::printLatLng(const Polygon<T>& poly, json::Val attrs) {
Polygon<T> projP; Polygon<T> projP;
for (auto p : poly) for (auto p : poly.getOuter())
projP.push_back(util::geo::webMercToLatLng<double>(p.getX(), p.getY())); projP.getOuter().push_back(util::geo::webMercToLatLng<T>(p.getX(), p.getY()));
print(projP, attrs); print(projP, attrs);
} }

View file

@ -27,6 +27,7 @@ class DirGraph : public Graph<N, E> {
Node<N, E>* addNd(DirNode<N, E>* n); Node<N, E>* addNd(DirNode<N, E>* n);
Node<N, E>* addNd(const N& pl); Node<N, E>* addNd(const N& pl);
Edge<N, E>* addEdg(Node<N, E>* from, Node<N, E>* to, const E& p); Edge<N, E>* addEdg(Node<N, E>* from, Node<N, E>* to, const E& p);
Edge<N, E>* addEdg(Node<N, E>* from, Node<N, E>* to, E&& p);
virtual Node<N, E>* mergeNds(Node<N, E>* a, Node<N, E>* b); virtual Node<N, E>* mergeNds(Node<N, E>* a, Node<N, E>* b);

View file

@ -24,7 +24,19 @@ Node<N, E>* DirGraph<N, E>::addNd(DirNode<N, E>* n) {
// _____________________________________________________________________________ // _____________________________________________________________________________
template <typename N, typename E> template <typename N, typename E>
Edge<N, E>* DirGraph<N, E>::addEdg(Node<N, E>* from, Node<N, E>* to, Edge<N, E>* DirGraph<N, E>::addEdg(Node<N, E>* from, Node<N, E>* to,
const E& p) { const E& p) {
Edge<N, E>* e = Graph<N, E>::getEdg(from, to);
if (!e) {
e = new Edge<N, E>(from, to, p);
from->addEdge(e);
to->addEdge(e);
}
return e;
}
// _____________________________________________________________________________
template <typename N, typename E>
Edge<N, E>* DirGraph<N, E>::addEdg(Node<N, E>* from, Node<N, E>* to, E&& p) {
Edge<N, E>* e = Graph<N, E>::getEdg(from, to); Edge<N, E>* e = Graph<N, E>::getEdg(from, to);
if (!e) { if (!e) {
e = new Edge<N, E>(from, to, p); e = new Edge<N, E>(from, to, p);

View file

@ -6,6 +6,7 @@
#define UTIL_GRAPH_EDGE_H_ #define UTIL_GRAPH_EDGE_H_
#include <vector> #include <vector>
#include <iostream>
#include "util/graph/Node.h" #include "util/graph/Node.h"
namespace util { namespace util {
@ -15,6 +16,7 @@ template <typename N, typename E>
class Edge { class Edge {
public: public:
Edge(Node<N, E>* from, Node<N, E>* to, const E& pl); Edge(Node<N, E>* from, Node<N, E>* to, const E& pl);
Edge(Node<N, E>* from, Node<N, E>* to, E&& pl);
Node<N, E>* getFrom() const; Node<N, E>* getFrom() const;
Node<N, E>* getTo() const; Node<N, E>* getTo() const;

View file

@ -5,8 +5,13 @@
// _____________________________________________________________________________ // _____________________________________________________________________________
template <typename N, typename E> template <typename N, typename E>
Edge<N, E>::Edge(Node<N, E>* from, Node<N, E>* to, const E& pl) Edge<N, E>::Edge(Node<N, E>* from, Node<N, E>* to, const E& pl)
: _from(from), _to(to), _pl(pl) { : _from(from), _to(to), _pl(pl) {
}
// _____________________________________________________________________________
template <typename N, typename E>
Edge<N, E>::Edge(Node<N, E>* from, Node<N, E>* to, E&& pl)
: _from(from), _to(to), _pl(std::move(pl)) {
} }
// _____________________________________________________________________________ // _____________________________________________________________________________

View file

@ -19,11 +19,17 @@ namespace graph {
template <typename N, typename E> template <typename N, typename E>
class Graph { class Graph {
public: public:
Graph() {} ;
Graph(const Graph& g) = delete;
Graph(Graph& g) = delete;
void operator=(const Graph& other) = delete;
void operator=(Graph& other) = delete;
virtual ~Graph(); virtual ~Graph();
virtual Node<N, E>* addNd() = 0; virtual Node<N, E>* addNd() = 0;
virtual Node<N, E>* addNd(const N& pl) = 0; virtual Node<N, E>* addNd(const N& pl) = 0;
Edge<N, E>* addEdg(Node<N, E>* from, Node<N, E>* to); Edge<N, E>* addEdg(Node<N, E>* from, Node<N, E>* to);
virtual Edge<N, E>* addEdg(Node<N, E>* from, Node<N, E>* to, const E& p) = 0; virtual Edge<N, E>* addEdg(Node<N, E>* from, Node<N, E>* to, const E& p) = 0;
virtual Edge<N, E>* addEdg(Node<N, E>* from, Node<N, E>* to, E&& p) = 0;
Edge<N, E>* getEdg(Node<N, E>* from, Node<N, E>* to); Edge<N, E>* getEdg(Node<N, E>* from, Node<N, E>* to);
const Edge<N, E>* getEdg(const Node<N, E>* from, const Node<N, E>* to) const; const Edge<N, E>* getEdg(const Node<N, E>* from, const Node<N, E>* to) const;

View file

@ -29,6 +29,7 @@ class UndirGraph : public Graph<N, E> {
Node<N, E>* addNd(UndirNode<N, E>* n); Node<N, E>* addNd(UndirNode<N, E>* n);
Node<N, E>* addNd(const N& pl); Node<N, E>* addNd(const N& pl);
Edge<N, E>* addEdg(Node<N, E>* from, Node<N, E>* to, const E& p); Edge<N, E>* addEdg(Node<N, E>* from, Node<N, E>* to, const E& p);
Edge<N, E>* addEdg(Node<N, E>* from, Node<N, E>* to, E&& p);
virtual Node<N, E>* mergeNds(Node<N, E>* a, Node<N, E>* b); virtual Node<N, E>* mergeNds(Node<N, E>* a, Node<N, E>* b);

View file

@ -38,6 +38,19 @@ Edge<N, E>* UndirGraph<N, E>::addEdg(Node<N, E>* from, Node<N, E>* to,
return e; return e;
} }
// _____________________________________________________________________________
template <typename N, typename E>
Edge<N, E>* UndirGraph<N, E>::addEdg(Node<N, E>* from, Node<N, E>* to,
E&& p) {
Edge<N, E>* e = Graph<N, E>::getEdg(from, to);
if (!e) {
e = new Edge<N, E>(from, to, std::move(p));
from->addEdge(e);
to->addEdge(e);
}
return e;
}
// _____________________________________________________________________________ // _____________________________________________________________________________
template <typename N, typename E> template <typename N, typename E>
Node<N, E>* UndirGraph<N, E>::mergeNds(Node<N, E>* a, Node<N, E>* b) { Node<N, E>* UndirGraph<N, E>::mergeNds(Node<N, E>* a, Node<N, E>* b) {

View file

@ -22,7 +22,6 @@
#endif #endif
#include <vector> #include <vector>
#include "Server.h" #include "Server.h"
#include "util/Misc.h"
#include "util/String.h" #include "util/String.h"
#include "util/log/Log.h" #include "util/log/Log.h"
@ -110,7 +109,11 @@ void HttpServer::handle() {
try { try {
Req req = getReq(connection); Req req = getReq(connection);
answ = _handler->handle(req, connection); answ = _handler->handle(req, connection);
answ.gzip = gzipSupport(req); if (answ.raw) {
close(connection); // the handle did everything
continue;
}
answ.gzip = req.gzip;
} catch (const HttpErr& err) { } catch (const HttpErr& err) {
answ = Answer(err.what(), err.what()); answ = Answer(err.what(), err.what());
} catch (...) { } catch (...) {
@ -277,6 +280,7 @@ Req HttpServer::getReq(int connection) {
} }
} }
ret.gzip = gzipSupport(ret);
return ret; return ret;
} }

View file

@ -29,7 +29,7 @@ namespace http {
// socket backlog size // socket backlog size
const static size_t BLOG = 128; const static size_t BLOG = 128;
// socket read buffer size // socket read buffer size
const static size_t BSIZE = 4 * 1024; const static size_t BSIZE = 16 * 1024;
// zlib compression buffer size // zlib compression buffer size
const size_t BSIZE_C = 128 * 1024; const size_t BSIZE_C = 128 * 1024;
@ -56,6 +56,7 @@ class HttpErr : public std::exception {
struct Req { struct Req {
std::string cmd, url, ver, payload; std::string cmd, url, ver, payload;
std::unordered_map<std::string, std::string> params; std::unordered_map<std::string, std::string> params;
bool gzip = false;
}; };
/* /*
@ -68,7 +69,8 @@ struct Answer {
Answer(const std::string& status, const std::string& pl, bool gz) Answer(const std::string& status, const std::string& pl, bool gz)
: status(status), pl(pl), gzip(gz) {} : status(status), pl(pl), gzip(gz) {}
std::string status, pl; std::string status, pl;
bool gzip; bool gzip = false;
bool raw = false;
std::unordered_map<std::string, std::string> params; std::unordered_map<std::string, std::string> params;
}; };

View file

@ -3,6 +3,7 @@
// Authors: Patrick Brosi <brosi@informatik.uni-freiburg.de> // Authors: Patrick Brosi <brosi@informatik.uni-freiburg.de>
#include <iomanip> #include <iomanip>
#include <limits>
#include "Writer.h" #include "Writer.h"
#include "util/String.h" #include "util/String.h"
using namespace util; using namespace util;
@ -95,7 +96,13 @@ void Writer::val(uint64_t v) {
// _____________________________________________________________________________ // _____________________________________________________________________________
void Writer::val(double v) { void Writer::val(double v) {
valCheck(); valCheck();
*_out << std::fixed << std::setprecision(_floatPrec) << v; if (v > std::numeric_limits<double>::max())
*_out << std::numeric_limits<double>::max();
else if (std::isnan(v))
*_out << "NaN";
else {
*_out << std::fixed << std::setprecision(_floatPrec) << v;
}
} }
// _____________________________________________________________________________ // _____________________________________________________________________________

View file

@ -10,6 +10,7 @@
#include "util/tests/QuadTreeTest.h" #include "util/tests/QuadTreeTest.h"
#include "util/geo/Geo.h" #include "util/geo/Geo.h"
#include "util/geo/Grid.h" #include "util/geo/Grid.h"
#include "util/geo/RTree.h"
#include "util/graph/Algorithm.h" #include "util/graph/Algorithm.h"
#include "util/graph/Dijkstra.h" #include "util/graph/Dijkstra.h"
#include "util/graph/BiDijkstra.h" #include "util/graph/BiDijkstra.h"
@ -265,6 +266,64 @@ int main(int argc, char** argv) {
g.getNeighbors(1, 0.55, &ret); g.getNeighbors(1, 0.55, &ret);
TEST(ret.size(), ==, (size_t)2); TEST(ret.size(), ==, (size_t)2);
g.remove(1);
ret.clear();
g.getNeighbors(1, 0, &ret);
TEST(ret.size(), ==, (size_t)0);
g.remove(2);
ret.clear();
g.getNeighbors(1, 10, &ret);
TEST(ret.size(), ==, (size_t)0);
// TODO: more test cases
}
// ___________________________________________________________________________
{
RTree<int, Line, double> g;
Line<double> l;
l.push_back(Point<double>(0, 0));
l.push_back(Point<double>(1.5, 2));
Line<double> l2;
l2.push_back(Point<double>(2.5, 1));
l2.push_back(Point<double>(2.5, 2));
g.add(l, 1);
g.add(l2, 2);
std::set<int> ret;
Box<double> req(Point<double>(.5, 1), Point<double>(1, 1.5));
g.get(req, &ret);
TEST(ret.size(), ==, (size_t)1);
ret.clear();
Box<double> req2(Point<double>(.5, 1), Point<double>(2.5, 2));
g.get(req2, &ret);
TEST(ret.size(), ==, (size_t)2);
ret.clear();
g.getNeighbors(1, 0, &ret);
TEST(ret.size(), ==, (size_t)1);
ret.clear();
g.getNeighbors(1, 1.55, &ret);
TEST(ret.size(), ==, (size_t)2);
g.remove(1);
ret.clear();
g.getNeighbors(1, 0, &ret);
TEST(ret.size(), ==, (size_t)0);
g.remove(2);
ret.clear();
g.getNeighbors(1, 10, &ret);
TEST(ret.size(), ==, (size_t)0);
// TODO: more test cases // TODO: more test cases
} }