be a bit less verbose

This commit is contained in:
Patrick Brosi 2018-07-24 19:33:18 +02:00
parent 45027d5496
commit 7f0443243c
12 changed files with 210 additions and 45 deletions

View file

@ -26,7 +26,7 @@ else()
message(WARNING "Configuring without OpenMP!") message(WARNING "Configuring without OpenMP!")
set(CMAKE_CXX_FLAGS "-Ofast -fno-signed-zeros -fno-trapping-math -Wall -Wno-format-extra-args -Wextra -Wformat-nonliteral -Wformat-security -Wformat=2 -Wfatal-errors -Wextra -Wno-implicit-fallthrough -pedantic") set(CMAKE_CXX_FLAGS "-Ofast -fno-signed-zeros -fno-trapping-math -Wall -Wno-format-extra-args -Wextra -Wformat-nonliteral -Wformat-security -Wformat=2 -Wfatal-errors -Wextra -Wno-implicit-fallthrough -pedantic")
endif() endif()
set(CMAKE_CXX_FLAGS_DEBUG "-Og -g -DLOGLEVEL=3") set(CMAKE_CXX_FLAGS_DEBUG "-Og -g -DLOGLEVEL=3 -DPFAEDLE_DBG=1")
set(CMAKE_CXX_FLAGS_MINSIZEREL "${CMAKE_CXX_FLAGS} -DLOGLEVEL=2") set(CMAKE_CXX_FLAGS_MINSIZEREL "${CMAKE_CXX_FLAGS} -DLOGLEVEL=2")
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS} -DLOGLEVEL=2") set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS} -DLOGLEVEL=2")
set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS} -g -DLOGLEVEL=3") set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS} -g -DLOGLEVEL=3")
@ -77,10 +77,10 @@ add_custom_target(
# handles install target # handles install target
install( install(
FILES README.md pfaedle.cfg DESTINATION share/${PROJECT_NAME} PERMISSIONS WORLD_READ FILES pfaedle.cfg DESTINATION etc/${PROJECT_NAME} COMPONENT config PERMISSIONS WORLD_READ
) )
install( install(
FILES build/pfaedle DESTINATION bin FILES build/pfaedle DESTINATION bin
PERMISSIONS WORLD_EXECUTE PERMISSIONS WORLD_EXECUTE COMPONENT binaries
) )

View file

@ -56,14 +56,19 @@ int main(int argc, char** argv) {
motCfgReader.parse(cfg.configPaths); motCfgReader.parse(cfg.configPaths);
if (cfg.osmPath.empty()) {
std::cerr << "No OSM input file specified (-x), see --help." << std::endl;
exit(5);
}
if (cfg.feedPaths.size() == 1) { if (cfg.feedPaths.size() == 1) {
LOG(INFO) << "Reading " << cfg.feedPaths[0] << " ..."; LOG(INFO) << "Reading " << cfg.feedPaths[0] << " ...";
ad::cppgtfs::Parser p; ad::cppgtfs::Parser p;
p.parse(&gtfs, cfg.feedPaths[0]); p.parse(&gtfs, cfg.feedPaths[0]);
LOG(INFO) << "Done."; LOG(INFO) << "Done.";
} else if (cfg.feedPaths.size() > 1) { } else if (cfg.feedPaths.size() > 1) {
LOG(ERROR) << "Maximal one input feed allowed."; std::cerr << "Maximally one input feed allowed." << std::endl;
exit(1); exit(2);
} }
LOG(DEBUG) << "Read " << motCfgReader.getConfigs().size() LOG(DEBUG) << "Read " << motCfgReader.getConfigs().size()
@ -75,7 +80,7 @@ int main(int argc, char** argv) {
singleTrip = gtfs.getTrips().get(cfg.shapeTripId); singleTrip = gtfs.getTrips().get(cfg.shapeTripId);
if (!singleTrip) { if (!singleTrip) {
LOG(ERROR) << "Trip #" << cfg.shapeTripId << " not found."; LOG(ERROR) << "Trip #" << cfg.shapeTripId << " not found.";
exit(1); exit(3);
} }
} }
@ -84,7 +89,7 @@ int main(int argc, char** argv) {
BBoxIdx box(2500); BBoxIdx box(2500);
if (cfg.feedPaths.size()) { if (cfg.feedPaths.size()) {
box = ShapeBuilder::getPaddedGtfsBox(&gtfs, 2500, cmdCfgMots, box = ShapeBuilder::getPaddedGtfsBox(&gtfs, 2500, cmdCfgMots,
cfg.shapeTripId); cfg.shapeTripId, true);
} }
OsmBuilder osmBuilder; OsmBuilder osmBuilder;
std::vector<pfaedle::osm::OsmReadOpts> opts; std::vector<pfaedle::osm::OsmReadOpts> opts;
@ -96,6 +101,13 @@ int main(int argc, char** argv) {
} }
osmBuilder.filterWrite(cfg.osmPath, cfg.writeOsm, opts, box); osmBuilder.filterWrite(cfg.osmPath, cfg.writeOsm, opts, box);
exit(0); exit(0);
} else if (!cfg.feedPaths.size()) {
std::cout << "No input feed specified, see --help" << std::endl;
exit(1);
}
if (motCfgReader.getConfigs().size() == 0) {
LOG(WARN) << "No MOT configurations specified, see --help.";
} }
std::vector<double> dfBins; std::vector<double> dfBins;

View file

@ -18,15 +18,21 @@ using std::string;
using std::exception; using std::exception;
using std::vector; using std::vector;
static const char* YEAR = __DATE__ + 7;
static const char* COPY =
"University of Freiburg - Chair of Algorithms and Data Structures";
static const char* AUTHORS = "Patrick Brosi <brosi@informatik.uni-freiburg.de>";
// _____________________________________________________________________________ // _____________________________________________________________________________
void ConfigReader::help() { void ConfigReader::help(const char* bin) {
std::cout std::cout
<< std::setfill(' ') << std::left << std::setfill(' ') << std::left
<< "\033[1mpfaedle GTFS map matcher \033[22m\n" << "pfaedle GTFS map matcher\n"
<< VERSION_FULL << " (built " << __DATE__ << " " << __TIME__ << ")\n\n" << VERSION_FULL << " (built " << __DATE__ << " " << __TIME__ << ")\n\n"
<< "(C) 2018 University of Freiburg\n" << "(C) " << YEAR << " " << COPY << "\n"
<< "Author: Patrick Brosi <brosi@informatik.uni-freiburg.de>\n\n" << "Authors: " << AUTHORS << "\n\n"
<< "Usage: " << "Usage: "
<< bin
<< " -x <OSM FILE> -c <CFG FILE> <GTFS FEED>\n\n" << " -x <OSM FILE> -c <CFG FILE> <GTFS FEED>\n\n"
<< "Allowed options:\n\n" << "Allowed options:\n\n"
<< "General:\n" << "General:\n"
@ -163,14 +169,17 @@ void ConfigReader::read(Config* cfg, int argc, char** argv) {
cfg->dbgOutputPath = optarg; cfg->dbgOutputPath = optarg;
break; break;
case 'v': case 'v':
std::cout << VERSION_FULL << " (built " << __DATE__ << " " << __TIME__ std::cout << "pfaedle " << VERSION_FULL << " (built " << __DATE__ << " "
<< ")\n\n"; << __TIME__ << ")\n"
<< "(C) " << YEAR << " " << COPY << "\n"
<< "Authors: " << AUTHORS << "\nGNU General Public "
"License v3.0\n";
exit(0); exit(0);
case 'p': case 'p':
printOpts = true; printOpts = true;
break; break;
case 'h': case 'h':
help(); help(argv[0]);
exit(0); exit(0);
case ':': case ':':
std::cerr << argv[optind - 1]; std::cerr << argv[optind - 1];

View file

@ -14,7 +14,7 @@ namespace config {
class ConfigReader { class ConfigReader {
public: public:
static void read(Config* targetConfig, int argc, char** argv); static void read(Config* targetConfig, int argc, char** argv);
static void help(); static void help(const char* bin);
}; };
} }
} }

View file

@ -54,6 +54,8 @@ void OsmBuilder::read(const std::string& path, const OsmReadOpts& opts,
if (!bbox.size()) return; if (!bbox.size()) return;
if (!fs->size()) return; if (!fs->size()) return;
LOG(INFO) << "Reading OSM file " << path << " ... ";
NodeSet orphanStations; NodeSet orphanStations;
EdgTracks eTracks; EdgTracks eTracks;
{ {
@ -210,7 +212,7 @@ void OsmBuilder::read(const std::string& path, const OsmReadOpts& opts,
LOG(VDEBUG) << "Write dummy node self-edges..."; LOG(VDEBUG) << "Write dummy node self-edges...";
writeSelfEdgs(g); writeSelfEdgs(g);
LOG(INFO) << "Graph has " << g->getNds()->size() << " nodes and " << comps LOG(DEBUG) << "Graph has " << g->getNds()->size() << " nodes and " << comps
<< " connected component(s)"; << " connected component(s)";
} }

View file

@ -187,9 +187,9 @@ pfaedle::router::Shape ShapeBuilder::shape(Trip* trip) {
void ShapeBuilder::shape(pfaedle::netgraph::Graph* ng) { void ShapeBuilder::shape(pfaedle::netgraph::Graph* ng) {
TrGraphEdgs gtfsGraph; TrGraphEdgs gtfsGraph;
LOG(INFO) << "Clustering trips..."; LOG(DEBUG) << "Clustering trips...";
Clusters clusters = clusterTrips(_feed, _mots); Clusters clusters = clusterTrips(_feed, _mots);
LOG(INFO) << "Clustered trips into " << clusters.size() << " clusters."; LOG(DEBUG) << "Clustered trips into " << clusters.size() << " clusters.";
std::map<ad::cppgtfs::gtfs::Shape*, size_t> shpUsage; std::map<ad::cppgtfs::gtfs::Shape*, size_t> shpUsage;
for (auto t : _feed->getTrips()) { for (auto t : _feed->getTrips()) {
@ -218,11 +218,18 @@ void ShapeBuilder::shape(pfaedle::netgraph::Graph* ng) {
{ {
LOG(INFO) << "@ " << j << " / " << clusters.size() << " (" LOG(INFO) << "@ " << j << " / " << clusters.size() << " ("
<< (static_cast<int>((j * 1.0) / clusters.size() * 100)) << (static_cast<int>((j * 1.0) / clusters.size() * 100))
<< "%, " << (EDijkstra::ITERS - oiters) << " iters, tput " << "%, "
<< (EDijkstra::ITERS - oiters) << " iters, "
/**
TODO: this is actually misleading. We are counting the
Dijkstra iterations, but the measuring them against
the total running time (including all overhead + HMM solve)
<< tput "
<< (static_cast<double>(EDijkstra::ITERS - oiters)) / << (static_cast<double>(EDijkstra::ITERS - oiters)) /
TOOK(t1, TIME()) TOOK(t1, TIME())
<< " iters/ms" << " iters/ms, "
<< ", " << (10.0 / (TOOK(t1, TIME()) / 1000)) **/
<< "matching " << (10.0 / (TOOK(t1, TIME()) / 1000))
<< " trips/sec)"; << " trips/sec)";
oiters = EDijkstra::ITERS; oiters = EDijkstra::ITERS;
@ -265,19 +272,18 @@ void ShapeBuilder::shape(pfaedle::netgraph::Graph* ng) {
} }
} }
LOG(INFO) << "Done.";
LOG(INFO) << "Matched " << totNumTrips << " trips in " << clusters.size() LOG(INFO) << "Matched " << totNumTrips << " trips in " << clusters.size()
<< " clusters."; << " clusters.";
LOG(INFO) << "Took " << (EDijkstra::ITERS - totiters) LOG(DEBUG) << "Took " << (EDijkstra::ITERS - totiters)
<< " iterations in total."; << " iterations in total.";
LOG(INFO) << "Took " << TOOK(t2, TIME()) << " ms in total."; LOG(DEBUG) << "Took " << TOOK(t2, TIME()) << " ms in total.";
LOG(INFO) << "Total avg. tput " LOG(DEBUG) << "Total avg. tput "
<< (static_cast<double>(EDijkstra::ITERS - totiters)) / << (static_cast<double>(EDijkstra::ITERS - totiters)) /
TOOK(t2, TIME()) TOOK(t2, TIME())
<< " iters/sec"; << " iters/sec";
LOG(INFO) << "Total avg. trip tput " LOG(DEBUG) << "Total avg. trip tput "
<< (clusters.size() / (TOOK(t2, TIME()) / 1000)) << " trips/sec"; << (clusters.size() / (TOOK(t2, TIME()) / 1000)) << " trips/sec";
LOG(INFO) << "Avg hop distance was " LOG(DEBUG) << "Avg hop distance was "
<< (totAvgDist / static_cast<double>(clusters.size())) << " meters"; << (totAvgDist / static_cast<double>(clusters.size())) << " meters";
if (_cfg.buildTransitGraph) { if (_cfg.buildTransitGraph) {
@ -438,11 +444,13 @@ const RoutingAttrs& ShapeBuilder::getRAttrs(const Trip* trip) const {
// _____________________________________________________________________________ // _____________________________________________________________________________
BBoxIdx ShapeBuilder::getPaddedGtfsBox(const Feed* feed, double pad, BBoxIdx ShapeBuilder::getPaddedGtfsBox(const Feed* feed, double pad,
const MOTs& mots, const MOTs& mots, const std::string& tid,
const std::string& tid) { bool dropShapes) {
osm::BBoxIdx box(pad); osm::BBoxIdx box(pad);
for (const auto& t : feed->getTrips()) { for (const auto& t : feed->getTrips()) {
if (!tid.empty() && t.second->getId() != tid) continue; if (!tid.empty() && t.second->getId() != tid) continue;
if (tid.empty() && t.second->getShape() && !dropShapes) continue;
if (t.second->getStopTimes().size() < 2) continue;
if (mots.count(t.second->getRoute()->getType())) { if (mots.count(t.second->getRoute()->getType())) {
Box<float> cur = minbox<float>(); Box<float> cur = minbox<float>();
for (const auto& st : t.second->getStopTimes()) { for (const auto& st : t.second->getStopTimes()) {
@ -458,10 +466,11 @@ BBoxIdx ShapeBuilder::getPaddedGtfsBox(const Feed* feed, double pad,
// _____________________________________________________________________________ // _____________________________________________________________________________
void ShapeBuilder::buildGraph() { void ShapeBuilder::buildGraph() {
LOG(INFO) << "Reading " << _cfg.osmPath << " ... ";
osm::OsmBuilder osmBuilder; osm::OsmBuilder osmBuilder;
osm::BBoxIdx box = getPaddedGtfsBox(_feed, 2500, _mots, _cfg.shapeTripId); osm::BBoxIdx box =
getPaddedGtfsBox(_feed, 2500, _mots, _cfg.shapeTripId, _cfg.dropShapes);
osmBuilder.read(_cfg.osmPath, _motCfg.osmBuildOpts, &_g, box, _cfg.gridSize, osmBuilder.read(_cfg.osmPath, _motCfg.osmBuildOpts, &_g, box, _cfg.gridSize,
getFeedStops(), &_restr); getFeedStops(), &_restr);
@ -475,8 +484,6 @@ void ShapeBuilder::buildGraph() {
_motCfg.routingOpts.nonOsmPen); _motCfg.routingOpts.nonOsmPen);
} }
} }
LOG(INFO) << "Done.";
} }
// _____________________________________________________________________________ // _____________________________________________________________________________
@ -525,7 +532,6 @@ Clusters ShapeBuilder::clusterTrips(Feed* f, MOTs mots) {
Clusters ret; Clusters ret;
for (const auto& trip : f->getTrips()) { for (const auto& trip : f->getTrips()) {
// if (trip.second->getId() != "L5Cvl_T01") continue;
if (trip.second->getShape() && !_cfg.dropShapes) continue; if (trip.second->getShape() && !_cfg.dropShapes) continue;
if (trip.second->getStopTimes().size() < 2) continue; if (trip.second->getStopTimes().size() < 2) continue;
if (!mots.count(trip.second->getRoute()->getType()) || if (!mots.count(trip.second->getRoute()->getType()) ||

View file

@ -66,7 +66,8 @@ class ShapeBuilder {
static osm::BBoxIdx getPaddedGtfsBox(const Feed* feed, double pad, static osm::BBoxIdx getPaddedGtfsBox(const Feed* feed, double pad,
const MOTs& mots, const MOTs& mots,
const std::string& tid); const std::string& tid,
bool dropShapes);
private: private:
Feed* _feed; Feed* _feed;

View file

@ -21,21 +21,52 @@ StatInfo NodePL::_blockerSI = StatInfo();
std::unordered_map<const Component*, size_t> NodePL::_comps; std::unordered_map<const Component*, size_t> NodePL::_comps;
// _____________________________________________________________________________ // _____________________________________________________________________________
NodePL::NodePL() : _geom(0, 0), _si(0), _component(0), _vis(0) {} NodePL::NodePL()
: _geom(0, 0),
_si(0),
_component(0)
#ifdef PFAEDLE_DBG
,
_vis(0)
#endif
{
}
// _____________________________________________________________________________ // _____________________________________________________________________________
NodePL::NodePL(const NodePL& pl) NodePL::NodePL(const NodePL& pl)
: _geom(pl._geom), _si(0), _component(pl._component), _vis(pl._vis) { : _geom(pl._geom),
_si(0),
_component(pl._component)
#ifdef PFAEDLE_DBG
,
_vis(pl._vis)
#endif
{
if (pl._si) setSI(*(pl._si)); if (pl._si) setSI(*(pl._si));
} }
// _____________________________________________________________________________ // _____________________________________________________________________________
NodePL::NodePL(const util::geo::FPoint& geom) NodePL::NodePL(const util::geo::FPoint& geom)
: _geom(geom), _si(0), _component(0), _vis(0) {} : _geom(geom),
_si(0),
_component(0)
#ifdef PFAEDLE_DBG
,
_vis(0)
#endif
{
}
// _____________________________________________________________________________ // _____________________________________________________________________________
NodePL::NodePL(const util::geo::FPoint& geom, const StatInfo& si) NodePL::NodePL(const util::geo::FPoint& geom, const StatInfo& si)
: _geom(geom), _si(0), _component(0), _vis(0) { : _geom(geom),
_si(0),
_component(0)
#ifdef PFAEDLE_DBG
,
_vis(0)
#endif
{
setSI(si); setSI(si);
} }
@ -52,7 +83,11 @@ NodePL::~NodePL() {
} }
// _____________________________________________________________________________ // _____________________________________________________________________________
void NodePL::setVisited() const { _vis = true; } void NodePL::setVisited() const {
#ifdef PFAEDLE_DBG
_vis = true;
#endif
}
// _____________________________________________________________________________ // _____________________________________________________________________________
void NodePL::setNoStat() { _si = 0; } void NodePL::setNoStat() { _si = 0; }
@ -81,7 +116,9 @@ void NodePL::setGeom(const util::geo::FPoint& geom) { _geom = geom; }
// _____________________________________________________________________________ // _____________________________________________________________________________
void NodePL::getAttrs(std::map<std::string, std::string>* obj) const { void NodePL::getAttrs(std::map<std::string, std::string>* obj) const {
(*obj)["component"] = std::to_string(reinterpret_cast<size_t>(_component)); (*obj)["component"] = std::to_string(reinterpret_cast<size_t>(_component));
#ifdef PFAEDLE_DBG
(*obj)["dijkstra_vis"] = _vis ? "yes" : "no"; (*obj)["dijkstra_vis"] = _vis ? "yes" : "no";
#endif
if (getSI()) { if (getSI()) {
(*obj)["station_info_ptr"] = util::toString(_si); (*obj)["station_info_ptr"] = util::toString(_si);
(*obj)["station_name"] = _si->getName(); (*obj)["station_name"] = _si->getName();

View file

@ -62,19 +62,20 @@ class NodePL : public GeoNodePL<float> {
bool isBlocker() const; bool isBlocker() const;
// Mark this node as visited (usefull for counting search space in Dijkstra) // Mark this node as visited (usefull for counting search space in Dijkstra)
// (only works for DEBUG build type)
void setVisited() const; void setVisited() const;
private: private:
std::string _b;
// 32bit floats are enough here // 32bit floats are enough here
util::geo::FPoint _geom; util::geo::FPoint _geom;
StatInfo* _si; StatInfo* _si;
const Component* _component; const Component* _component;
static StatInfo _blockerSI; #ifdef PFAEDLE_DBG
mutable bool _vis; mutable bool _vis;
#endif
static StatInfo _blockerSI;
static std::unordered_map<const Component*, size_t> _comps; static std::unordered_map<const Component*, size_t> _comps;
}; };
} // namespace trgraph } // namespace trgraph

View file

@ -403,6 +403,14 @@ inline bool intersects(const LineSegment<T>& ls1, const LineSegment<T>& ls2) {
((crossProd(ls2.first, ls1) < 0) ^ (crossProd(ls2.second, ls1) < 0))); ((crossProd(ls2.first, ls1) < 0) ^ (crossProd(ls2.second, ls1) < 0)));
} }
// _____________________________________________________________________________
template <typename T>
inline bool intersects(const Point<T>& a, const Point<T>& b, const Point<T>& c,
const Point<T>& d) {
// legacy function
return intersects(LineSegment<T>(a, b), LineSegment<T>(c, d));
}
// _____________________________________________________________________________ // _____________________________________________________________________________
template <typename T> template <typename T>
inline bool intersects(const Line<T>& ls1, const Line<T>& ls2) { inline bool intersects(const Line<T>& ls1, const Line<T>& ls2) {
@ -605,6 +613,78 @@ inline double dist(double x1, double y1, double x2, double y2) {
return sqrt((x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1)); return sqrt((x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1));
} }
// _____________________________________________________________________________
template <typename T>
inline double dist(const LineSegment<T>& ls, const Point<T>& p) {
return distToSegment(ls, p);
}
// _____________________________________________________________________________
template <typename T>
inline double dist(const Point<T>& p, const LineSegment<T>& ls) {
return dist(ls, p);
}
// _____________________________________________________________________________
template <typename T>
inline double dist(const LineSegment<T>& ls1, const LineSegment<T>& ls2) {
if (intersects(ls1, ls2)) return 0;
double d1 = dist(ls1.first, ls2);
double d2 = dist(ls1.second, ls2);
double d3 = dist(ls2.first, ls1);
double d4 = dist(ls2.second, ls1);
return std::min(d1, std::min(d2, (std::min(d3, d4))));
}
// _____________________________________________________________________________
template <typename T>
inline double dist(const Point<T>& p, const Line<T>& l) {
double d = std::numeric_limits<double>::infinity();
for (size_t i = 1; i < l.size(); i++) {
double dTmp = distToSegment(l[i-1], l[i], p);
if (dTmp < EPSILON) return 0;
if (dTmp < d) d = dTmp;
}
return d;
}
// _____________________________________________________________________________
template <typename T>
inline double dist(const Line<T>& l, const Point<T>& p) {
return dist(p, l);
}
// _____________________________________________________________________________
template <typename T>
inline double dist(const LineSegment<T>& ls, const Line<T>& l) {
double d = std::numeric_limits<double>::infinity();
for (size_t i = 1; i < l.size(); i++) {
double dTmp = dist(ls, LineSegment<T>(l[i-1], l[i]));
if (dTmp < EPSILON) return 0;
if (dTmp < d) d = dTmp;
}
return d;
}
// _____________________________________________________________________________
template <typename T>
inline double dist(const Line<T>& l, const LineSegment<T>& ls) {
return dist(ls, l);
}
// _____________________________________________________________________________
template <typename T>
inline double dist(const Line<T>& la, const Line<T>& lb) {
double d = std::numeric_limits<double>::infinity();
for (size_t i = 1; i < la.size(); i++) {
double dTmp = dist(LineSegment<T>(la[i-1], la[i]), lb);
if (dTmp < EPSILON) return 0;
if (dTmp < d) d = dTmp;
}
return d;
}
// _____________________________________________________________________________ // _____________________________________________________________________________
inline double innerProd(double x1, double y1, double x2, double y2, double x3, inline double innerProd(double x1, double y1, double x2, double y2, double x3,
double y3) { double y3) {

View file

@ -33,7 +33,7 @@ class Polygon {
}; };
template <typename T> template <typename T>
using MultiPolyon = std::vector<Polygon<T>>; using MultiPolygon = std::vector<Polygon<T>>;
} // namespace geo } // namespace geo
} // namespace util } // namespace util

View file

@ -1024,7 +1024,7 @@ CASE("geometry") {
EXPECT(geo::dist(geo::centroid(Polygon<double>({{0, 0}, {3, 4}, {4,3}})), Point<double>(7.0/3.0,7.0/3.0)) == approx(0)); EXPECT(geo::dist(geo::centroid(Polygon<double>({{0, 0}, {3, 4}, {4,3}})), Point<double>(7.0/3.0,7.0/3.0)) == approx(0));
auto polyy = Polygon<double>({{0, 0}, {3, 4}, {4,3}}); auto polyy = Polygon<double>({{0, 0}, {3, 4}, {4,3}});
MultiPolyon<double> mpoly{polyy, polyy}; MultiPolygon<double> mpoly{polyy, polyy};
EXPECT(geo::getWKT(polyy) == "POLYGON ((0 0, 3 4, 4 3, 0 0))"); 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)))"); EXPECT(geo::getWKT(mpoly) == "MULTIPOLYGON (((0 0, 3 4, 4 3, 0 0)), ((0 0, 3 4, 4 3, 0 0)))");
@ -1209,6 +1209,23 @@ CASE("geometry") {
auto obox = geo::getOrientedEnvelope(geo::Line<double>{{0, 0}, {1, 1}, {1.5, 0.5}}); auto obox = geo::getOrientedEnvelope(geo::Line<double>{{0, 0}, {1, 1}, {1.5, 0.5}});
EXPECT(geo::contains(geo::convexHull(obox), geo::Polygon<double>({{0.0, 0.0}, {1.0, 1.0}, {1.5, 0.5}, {0.5, -0.5}}))); EXPECT(geo::contains(geo::convexHull(obox), geo::Polygon<double>({{0.0, 0.0}, {1.0, 1.0}, {1.5, 0.5}, {0.5, -0.5}})));
EXPECT(geo::contains(geo::Polygon<double>({{0.0, 0.0}, {1.0, 1.0}, {1.5, 0.5}, {0.5, -0.5}}), geo::convexHull(obox))); EXPECT(geo::contains(geo::Polygon<double>({{0.0, 0.0}, {1.0, 1.0}, {1.5, 0.5}, {0.5, -0.5}}), geo::convexHull(obox)));
EXPECT(geo::dist(geo::LineSegment<double>{{1, 1}, {3, 1}}, geo::LineSegment<double>{{2, 2}, {2, 0}}) == approx(0));
EXPECT(geo::dist(geo::LineSegment<double>{{1, 1}, {3, 1}}, geo::LineSegment<double>{{2, 4}, {2, 2}}) == approx(1));
EXPECT(geo::dist(geo::LineSegment<double>{{1, 1}, {3, 1}}, geo::LineSegment<double>{{1, 1}, {3, 1}}) == approx(0));
EXPECT(geo::dist(geo::LineSegment<double>{{1, 1}, {3, 1}}, geo::LineSegment<double>{{1, 2}, {3, 2}}) == approx(1));
EXPECT(geo::dist(geo::LineSegment<double>{{1, 1}, {3, 1}}, geo::LineSegment<double>{{1, 2}, {3, 5}}) == approx(1));
EXPECT(geo::dist(geo::Line<double>{{1, 1}, {3, 1}}, geo::Point<double>{2, 1}) == approx(0));
EXPECT(geo::dist(geo::Line<double>{{1, 1}, {3, 1}}, geo::Point<double>{2, 2}) == approx(1));
EXPECT(geo::dist(geo::Line<double>{{1, 1}, {3, 1}}, geo::Point<double>{3, 1}) == approx(0));
EXPECT(geo::dist(geo::Line<double>{{1, 1}, {3, 1}}, geo::Point<double>{1, 1}) == approx(0));
EXPECT(geo::dist(Line<double>{{7, 7}, {7, -7}, {-7, -7}, {-7, 7}, {9, 0}, {-9, 0}, {0, 9}, {0, -9}}, Line<double>{{7, 7}, {7, -7}, {-7, -7}, {-7, 7}, {9, 0}, {-9, 0}, {0, 9}, {0, -9}}) == approx(0));
EXPECT(geo::dist(Line<double>{{7, 7}, {7, -7}, {-7, -7}, {-7, 7}, {9, 0}, {-9, 0}, {0, 9}, {0, -9}}, LineSegment<double>{{6, 7}, {8, -7}}) == approx(0));
EXPECT(geo::dist(Line<double>{{7, 7}, {7, -7}, {-7, -7}, {-7, 7}, {9, 0}, {-9, 0}, {0, 9}, {0, -9}}, Point<double>{7, 4}) == approx(0));
EXPECT(geo::dist(Line<double>{{0, 0}, {1, 1}, {2, 0}}, Line<double>{{1.5, 0.5}, {1.5, 100}}) == approx(0));
EXPECT(geo::dist(Line<double>{{0, 0}, {1, 1}, {2, 0}}, Line<double>{{2, 0.5}, {2, 100}}) == approx(0.353553));
} }
}}; }};