refactoring

This commit is contained in:
Patrick Brosi 2019-02-03 12:48:48 +01:00
parent 2fb157ef37
commit 4733b0c676
26 changed files with 774 additions and 406 deletions

View file

@ -7,6 +7,7 @@
#include <cmath>
#include <chrono>
#include <sstream>
#define UNUSED(expr) do { (void)(expr); } while (0)
#define TIME() std::chrono::high_resolution_clock::now()
@ -39,10 +40,18 @@ inline uint64_t atoul(const char* p) {
}
// _____________________________________________________________________________
inline float atof(const char* p, uint8_t mn) {
inline bool isFloatingPoint(const std::string& str) {
std::stringstream ss(str);
double f;
ss >> std::noskipws >> f;
return ss.eof() && ! ss.fail();
}
// _____________________________________________________________________________
inline double atof(const char* p, uint8_t mn) {
// this atof implementation works only on "normal" float strings like
// 56.445 or -345.00, but should be faster than std::atof
float ret = 0.0;
double ret = 0.0;
bool neg = false;
if (*p == '-') {
neg = true;
@ -56,14 +65,14 @@ inline float atof(const char* p, uint8_t mn) {
if (*p == '.') {
p++;
float f = 0;
double f = 0;
uint8_t n = 0;
for (; n < mn && *p >= '0' && *p <= '9'; n++, p++) {
f = f * 10.0 + (*p - '0');
}
if (n < 11)
if (n < 10)
ret += f / pow10[n];
else
ret += f / std::pow(10, n);

View file

@ -175,6 +175,18 @@ inline size_t prefixEditDist(const std::string& prefix, const std::string& s) {
return prefixEditDist(prefix, s, s.size());
}
// _____________________________________________________________________________
inline std::string toUpper(std::string str) {
std::transform(str.begin(), str.end(),str.begin(), toupper);
return str;
}
// _____________________________________________________________________________
inline std::string toLower(std::string str) {
std::transform(str.begin(), str.end(),str.begin(), tolower);
return str;
}
// _____________________________________________________________________________
template <class Iter>
inline std::string implode(Iter begin, const Iter& end, const char* del) {
@ -190,6 +202,25 @@ inline std::string implode(Iter begin, const Iter& end, const char* del) {
return ss.str();
}
// _____________________________________________________________________________
inline std::string normalizeWhiteSpace(const std::string& input) {
std::string ret;
bool ws = false;
for (size_t i = 0; i < input.size(); i++) {
if (std::isspace(input[i])) {
if (!ws) {
ret += " ";
ws = true;
}
continue;
} else {
ws = false;
ret += input[i];
}
}
return ret;
}
// _____________________________________________________________________________
template <typename T>
inline std::string implode(const std::vector<T>& vec, const char* del) {

View file

@ -13,6 +13,7 @@
#include <iostream>
#include <sstream>
#include "util/Misc.h"
#include "util/String.h"
#include "util/geo/Box.h"
#include "util/geo/Line.h"
#include "util/geo/Point.h"
@ -734,6 +735,45 @@ inline double dist(const Point<T>& p1, const Point<T>& p2) {
return dist(p1.getX(), p1.getY(), p2.getX(), p2.getY());
}
// _____________________________________________________________________________
template <typename T>
inline Point<T> pointFromWKT(std::string wkt) {
wkt = util::normalizeWhiteSpace(util::trim(wkt));
if (wkt.rfind("POINT") == 0 || wkt.rfind("MPOINT") == 0) {
size_t b = wkt.find("(") + 1;
size_t e = wkt.find(")", b);
if (b > e) throw std::runtime_error("Could not parse WKT");
auto xy = util::split(util::trim(wkt.substr(b, e - b)), ' ');
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());
return Point<T>(x, y);
}
throw std::runtime_error("Could not parse WKT");
}
// _____________________________________________________________________________
template <typename T>
inline Line<T> lineFromWKT(std::string wkt) {
wkt = util::normalizeWhiteSpace(util::trim(wkt));
if (wkt.rfind("LINESTRING") == 0 || wkt.rfind("MLINESTRING") == 0) {
Line<T> ret;
size_t b = wkt.find("(") + 1;
size_t e = wkt.find(")", b);
if (b > e) throw std::runtime_error("Could not parse WKT");
auto pairs = util::split(wkt.substr(b, e - b), ',');
for (const auto& p : pairs) {
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());
ret.push_back({x, y});
}
return ret;
}
throw std::runtime_error("Could not parse WKT");
}
// _____________________________________________________________________________
template <typename T>
inline std::string getWKT(const Point<T>& p) {
@ -1479,6 +1519,24 @@ inline double webMercMeterDist(const G1& a, const G2& b) {
return util::geo::dist(a, b) * cos((latA + latB) / 2.0);
}
// _____________________________________________________________________________
template <typename T>
inline double webMercLen(const Line<T>& g) {
double ret = 0;
for (size_t i = 1; i < g.size(); i++) ret += webMercMeterDist(g[i - 1], g[i]);
return ret;
}
// _____________________________________________________________________________
template <typename G>
inline double webMercDistFactor(const G& a) {
// euclidean distance on web mercator is in meters on equator,
// and proportional to cos(lat) in both y directions
double lat = 2 * atan(exp(a.getY() / 6378137.0)) - 1.5707965;
return cos(lat);
}
}
}

View file

@ -11,9 +11,6 @@
#include "util/geo/output/GeoJsonOutput.h"
#include "util/graph/Graph.h"
using util::toString;
using util::graph::Graph;
namespace util {
namespace geo {
namespace output {
@ -22,7 +19,7 @@ class GeoGraphJsonOutput {
public:
inline GeoGraphJsonOutput(){};
template <typename N, typename E>
void print(const Graph<N, E>& outG, std::ostream& str);
void print(const util::graph::Graph<N, E>& outG, std::ostream& str);
private:
template <typename T>

View file

@ -22,10 +22,10 @@ void GeoGraphJsonOutput::print(const util::graph::Graph<N, E>& outG,
for (util::graph::Node<N, E>* n : outG.getNds()) {
if (!n->pl().getGeom()) continue;
json::Dict props{{"id", toString(n)},
{"deg", toString(n->getDeg())},
{"deg_out", toString(n->getOutDeg())},
{"deg_in", toString(n->getInDeg())}};
json::Dict props{{"id", util::toString(n)},
{"deg", util::toString(n->getDeg())},
{"deg_out", util::toString(n->getOutDeg())},
{"deg_in", util::toString(n->getInDeg())}};
auto addProps = n->pl().getAttrs();
props.insert(addProps.begin(), addProps.end());
@ -38,9 +38,9 @@ void GeoGraphJsonOutput::print(const util::graph::Graph<N, E>& outG,
for (graph::Edge<N, E>* e : n->getAdjListOut()) {
// to avoid double output for undirected graphs
if (e->getFrom() != n) continue;
json::Dict props{{"from", toString(e->getFrom())},
{"to", toString(e->getTo())},
{"id", toString(e)}};
json::Dict props{{"from", util::toString(e->getFrom())},
{"to", util::toString(e->getTo())},
{"id", util::toString(e)}};
auto addProps = e->pl().getAttrs();
props.insert(addProps.begin(), addProps.end());

View file

@ -17,9 +17,18 @@ GeoJsonOutput::GeoJsonOutput(std::ostream& str) : _wr(&str, 10, true) {
}
// _____________________________________________________________________________
GeoJsonOutput::~GeoJsonOutput() {
flush();
GeoJsonOutput::GeoJsonOutput(std::ostream& str, json::Val attrs)
: _wr(&str, 10, true) {
_wr.obj();
_wr.keyVal("type", "FeatureCollection");
_wr.key("properties");
_wr.val(attrs);
_wr.key("features");
_wr.arr();
}
// _____________________________________________________________________________
GeoJsonOutput::~GeoJsonOutput() { flush(); }
// _____________________________________________________________________________
void GeoJsonOutput::flush() { _wr.closeAll(); }

View file

@ -19,6 +19,7 @@ namespace output {
class GeoJsonOutput {
public:
GeoJsonOutput(std::ostream& str);
GeoJsonOutput(std::ostream& str, json::Val attrs);
~GeoJsonOutput();
template <typename T>
void print(const Point<T>& p, json::Val attrs);

View file

@ -1001,9 +1001,82 @@ CASE("nullable") {
}
}},
// ___________________________________________________________________________
{
CASE("geomwkt") {
auto p = pointFromWKT<double>("POINT(10 50)");
EXPECT(p.getX() == approx(10));
EXPECT(p.getY() == approx(50));
p = pointFromWKT<double>("POINT( 10 50)");
EXPECT(p.getX() == approx(10));
EXPECT(p.getY() == approx(50));
p = pointFromWKT<double>("POINT (10 50 30)");
EXPECT(p.getX() == approx(10));
EXPECT(p.getY() == approx(50));
p = pointFromWKT<double>("POINT (10 50 30)");
EXPECT(p.getX() == approx(10));
EXPECT(p.getY() == approx(50));
p = pointFromWKT<double>("POINT(10 50 30)");
EXPECT(p.getX() == approx(10));
EXPECT(p.getY() == approx(50));
p = pointFromWKT<double>("POINT (10 50) ");
EXPECT(p.getX() == approx(10));
EXPECT(p.getY() == approx(50));
p = pointFromWKT<double>("MPOINT(10 50 30)");
EXPECT(p.getX() == approx(10));
EXPECT(p.getY() == approx(50));
p = pointFromWKT<double>("MPOINT(10 50)");
EXPECT(p.getX() == approx(10));
EXPECT(p.getY() == approx(50));
p = pointFromWKT<double>("POINT(10.05 50.05)");
EXPECT(p.getX() == approx(10.05));
EXPECT(p.getY() == approx(50.05));
auto wktl = lineFromWKT<double>("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));
wktl = lineFromWKT<double>("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));
wktl = lineFromWKT<double>("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));
}},
// ___________________________________________________________________________
{
CASE("geometry") {
geo::Point<double> a(1, 2);
geo::Point<double> b(2, 3);
geo::Point<double> c(4, 5);