initial commit
This commit is contained in:
commit
efcd3e1892
106 changed files with 27000 additions and 0 deletions
80
src/pfaedle/osm/BBoxIdx.cpp
Normal file
80
src/pfaedle/osm/BBoxIdx.cpp
Normal file
|
|
@ -0,0 +1,80 @@
|
|||
// Copyright 2018, University of Freiburg,
|
||||
// Chair of Algorithms and Data Structures.
|
||||
// Authors: Patrick Brosi <brosi@informatik.uni-freiburg.de>
|
||||
|
||||
#include "pfaedle/osm/BBoxIdx.h"
|
||||
|
||||
using pfaedle::osm::BBoxIdx;
|
||||
|
||||
// _____________________________________________________________________________
|
||||
BBoxIdx::BBoxIdx(float padding) : _padding(padding), _size(0) {}
|
||||
|
||||
// _____________________________________________________________________________
|
||||
void BBoxIdx::add(Box<float> box) {
|
||||
// division by 83.000m is only correct here around a latitude deg of 25,
|
||||
// but should be a good heuristic. 1 deg is around 63km at latitude deg of 44,
|
||||
// and 110 at deg=0, since we usually dont do map matching in the arctic,
|
||||
// its okay to use 83km here.
|
||||
box = util::geo::pad(box, _padding / 83000);
|
||||
addToTree(box, &_root, 0);
|
||||
_size++;
|
||||
}
|
||||
|
||||
// _____________________________________________________________________________
|
||||
size_t BBoxIdx::size() const { return _size; }
|
||||
|
||||
// _____________________________________________________________________________
|
||||
bool BBoxIdx::contains(const Point<float>& p) const {
|
||||
return treeHas(p, _root);
|
||||
}
|
||||
|
||||
// _____________________________________________________________________________
|
||||
util::geo::Box<float> BBoxIdx::getFullWebMercBox() const {
|
||||
return util::geo::FBox(
|
||||
util::geo::latLngToWebMerc<float>(_root.box.min_corner().get<1>(),
|
||||
_root.box.min_corner().get<0>()),
|
||||
util::geo::latLngToWebMerc<float>(_root.box.max_corner().get<1>(),
|
||||
_root.box.max_corner().get<0>()));
|
||||
}
|
||||
|
||||
// _____________________________________________________________________________
|
||||
bool BBoxIdx::treeHas(const Point<float>& p, const BBoxIdxNd& nd) const {
|
||||
if (!nd.childs.size()) return util::geo::contains(p, nd.box);
|
||||
for (const auto& child : nd.childs) {
|
||||
if (util::geo::contains(p, child.box)) return treeHas(p, child);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// _____________________________________________________________________________
|
||||
void BBoxIdx::addToTree(const Box<float>& box, BBoxIdxNd* nd, size_t lvl) {
|
||||
double bestCommonArea = 0;
|
||||
ssize_t bestChild = -1;
|
||||
|
||||
// 1. update the bbox of this node
|
||||
nd->box = util::geo::extendBox(box, nd->box);
|
||||
|
||||
if (lvl == MAX_LVL) return;
|
||||
|
||||
// 2. find best candidate
|
||||
for (size_t i = 0; i < nd->childs.size(); i++) {
|
||||
double cur = util::geo::commonArea(box, nd->childs[i].box);
|
||||
if (cur > MIN_COM_AREA && cur > bestCommonArea) {
|
||||
bestChild = i;
|
||||
bestCommonArea = cur;
|
||||
}
|
||||
}
|
||||
|
||||
if (bestChild < 0) {
|
||||
// 3. add a new node with the inserted bbox
|
||||
nd->childs.push_back(BBoxIdxNd(box));
|
||||
addToTree(box, &nd->childs.back(), lvl + 1);
|
||||
} else {
|
||||
// 3. add to best node
|
||||
addToTree(box, &nd->childs[bestChild], lvl + 1);
|
||||
}
|
||||
|
||||
// TODO(patrick): some tree balancing by mergin overlapping bboxes in
|
||||
// non-leafs
|
||||
}
|
||||
58
src/pfaedle/osm/BBoxIdx.h
Normal file
58
src/pfaedle/osm/BBoxIdx.h
Normal file
|
|
@ -0,0 +1,58 @@
|
|||
// Copyright 2018, University of Freiburg,
|
||||
// Chair of Algorithms and Data Structures.
|
||||
// Authors: Patrick Brosi <brosi@informatik.uni-freiburg.de>
|
||||
|
||||
#ifndef PFAEDLE_OSM_BBOXIDX_H_
|
||||
#define PFAEDLE_OSM_BBOXIDX_H_
|
||||
|
||||
#include <vector>
|
||||
#include "util/geo/Geo.h"
|
||||
|
||||
namespace pfaedle {
|
||||
namespace osm {
|
||||
|
||||
using util::geo::Box;
|
||||
using util::geo::Point;
|
||||
|
||||
struct BBoxIdxNd {
|
||||
BBoxIdxNd() : box(util::geo::minbox<float>()) {}
|
||||
explicit BBoxIdxNd(const Box<float>& box) : box(box) {}
|
||||
Box<float> box;
|
||||
std::vector<BBoxIdxNd> childs;
|
||||
};
|
||||
|
||||
/*
|
||||
* Poor man's R-tree
|
||||
*/
|
||||
class BBoxIdx {
|
||||
public:
|
||||
explicit BBoxIdx(float padding);
|
||||
|
||||
// Add a bounding box to this index
|
||||
void add(Box<float> box);
|
||||
|
||||
// Check if a point is contained in this index
|
||||
bool contains(const Point<float>& box) const;
|
||||
|
||||
// Return the full total bounding box of this index
|
||||
util::geo::Box<float> getFullWebMercBox() const;
|
||||
|
||||
// Return the size of this index
|
||||
size_t size() const;
|
||||
|
||||
private:
|
||||
double _padding;
|
||||
size_t _size;
|
||||
|
||||
BBoxIdxNd _root;
|
||||
|
||||
void addToTree(const Box<float>& box, BBoxIdxNd* nd, size_t lvl);
|
||||
bool treeHas(const Point<float>& p, const BBoxIdxNd& nd) const;
|
||||
|
||||
static const size_t MAX_LVL = 5;
|
||||
static constexpr double MIN_COM_AREA = 0.0;
|
||||
};
|
||||
} // namespace osm
|
||||
} // namespace pfaedle
|
||||
|
||||
#endif // PFAEDLE_OSM_BBOXIDX_H_
|
||||
70
src/pfaedle/osm/Osm.h
Normal file
70
src/pfaedle/osm/Osm.h
Normal file
|
|
@ -0,0 +1,70 @@
|
|||
// Copyright 2018, University of Freiburg,
|
||||
// Chair of Algorithms and Data Structures.
|
||||
// Authors: Patrick Brosi <brosi@informatik.uni-freiburg.de>
|
||||
|
||||
#ifndef PFAEDLE_OSM_OSM_H_
|
||||
#define PFAEDLE_OSM_OSM_H_
|
||||
|
||||
#include <set>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
namespace pfaedle {
|
||||
namespace osm {
|
||||
|
||||
typedef uint64_t osmid;
|
||||
|
||||
typedef std::unordered_map<std::string, std::string> AttrMap;
|
||||
typedef std::pair<std::string, std::string> Attr;
|
||||
typedef std::vector<osmid> OsmIdList;
|
||||
|
||||
struct OsmRel {
|
||||
OsmRel() : id(0) {}
|
||||
osmid id;
|
||||
AttrMap attrs;
|
||||
std::vector<osmid> nodes;
|
||||
std::vector<osmid> ways;
|
||||
|
||||
std::vector<std::string> nodeRoles;
|
||||
std::vector<std::string> wayRoles;
|
||||
|
||||
uint64_t keepFlags;
|
||||
uint64_t dropFlags;
|
||||
};
|
||||
|
||||
struct OsmWay {
|
||||
OsmWay() : id(0) {}
|
||||
osmid id;
|
||||
AttrMap attrs;
|
||||
std::vector<osmid> nodes;
|
||||
|
||||
uint64_t keepFlags;
|
||||
uint64_t dropFlags;
|
||||
};
|
||||
|
||||
struct OsmNode {
|
||||
OsmNode() : id(0) {}
|
||||
osmid id;
|
||||
double lat;
|
||||
double lng;
|
||||
AttrMap attrs;
|
||||
|
||||
uint64_t keepFlags;
|
||||
uint64_t dropFlags;
|
||||
};
|
||||
|
||||
struct Restriction {
|
||||
osmid eFrom, eTo;
|
||||
};
|
||||
|
||||
typedef std::unordered_map<osmid, std::vector<Restriction>> RestrMap;
|
||||
|
||||
struct Restrictions {
|
||||
RestrMap pos;
|
||||
RestrMap neg;
|
||||
};
|
||||
} // namespace osm
|
||||
} // namespace pfaedle
|
||||
#endif // PFAEDLE_OSM_OSM_H_
|
||||
1711
src/pfaedle/osm/OsmBuilder.cpp
Normal file
1711
src/pfaedle/osm/OsmBuilder.cpp
Normal file
File diff suppressed because it is too large
Load diff
252
src/pfaedle/osm/OsmBuilder.h
Normal file
252
src/pfaedle/osm/OsmBuilder.h
Normal file
|
|
@ -0,0 +1,252 @@
|
|||
// Copyright 2018, University of Freiburg,
|
||||
// Chair of Algorithms and Data Structures.
|
||||
// Authors: Patrick Brosi <brosi@informatik.uni-freiburg.de>
|
||||
|
||||
#ifndef PFAEDLE_OSM_OSMBUILDER_H_
|
||||
#define PFAEDLE_OSM_OSMBUILDER_H_
|
||||
|
||||
#include <queue>
|
||||
#include <set>
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
#include "ad/cppgtfs/gtfs/Feed.h"
|
||||
#include "pfaedle/osm/BBoxIdx.h"
|
||||
#include "pfaedle/osm/OsmFilter.h"
|
||||
#include "pfaedle/osm/OsmIdSet.h"
|
||||
#include "pfaedle/osm/OsmReadOpts.h"
|
||||
#include "pfaedle/osm/Restrictor.h"
|
||||
#include "pfaedle/router/Router.h"
|
||||
#include "pfaedle/trgraph/Graph.h"
|
||||
#include "pfaedle/trgraph/Normalizer.h"
|
||||
#include "pfaedle/trgraph/StatInfo.h"
|
||||
#include "util/Nullable.h"
|
||||
#include "util/xml/XmlWriter.h"
|
||||
#include "xml/File.h"
|
||||
|
||||
namespace pfaedle {
|
||||
namespace osm {
|
||||
|
||||
using pfaedle::trgraph::EdgeGrid;
|
||||
using pfaedle::trgraph::NodeGrid;
|
||||
using pfaedle::trgraph::Normalizer;
|
||||
using pfaedle::trgraph::Graph;
|
||||
using pfaedle::trgraph::Node;
|
||||
using pfaedle::trgraph::NodePL;
|
||||
using pfaedle::trgraph::Edge;
|
||||
using pfaedle::trgraph::EdgePL;
|
||||
using pfaedle::trgraph::TransitEdgeLine;
|
||||
using pfaedle::trgraph::StatInfo;
|
||||
using pfaedle::trgraph::StatGroup;
|
||||
using pfaedle::trgraph::Component;
|
||||
using pfaedle::router::NodeSet;
|
||||
using ad::cppgtfs::gtfs::Stop;
|
||||
using util::Nullable;
|
||||
|
||||
struct NodeCand {
|
||||
double dist;
|
||||
Node* node;
|
||||
const Edge* fromEdge;
|
||||
int fullTurns;
|
||||
};
|
||||
|
||||
struct SearchFunc {
|
||||
virtual bool operator()(const Node* n, const StatInfo* si) const = 0;
|
||||
};
|
||||
|
||||
struct EqSearch : public SearchFunc {
|
||||
double minSimi = 0.9;
|
||||
bool operator()(const Node* cand, const StatInfo* si) const {
|
||||
return cand->pl().getSI() && cand->pl().getSI()->simi(si) > minSimi;
|
||||
}
|
||||
};
|
||||
|
||||
struct BlockSearch : public SearchFunc {
|
||||
bool operator()(const Node* n, const StatInfo* si) const {
|
||||
if (n->pl().getSI() && n->pl().getSI()->simi(si) < 0.5) return true;
|
||||
return n->pl().isBlocker();
|
||||
}
|
||||
};
|
||||
|
||||
inline bool operator<(const NodeCand& a, const NodeCand& b) {
|
||||
return a.fullTurns > b.fullTurns || a.dist > b.dist;
|
||||
}
|
||||
|
||||
typedef std::priority_queue<NodeCand> NodeCandPQ;
|
||||
|
||||
/*
|
||||
* Builds a physical transit network graph from OSM data
|
||||
*/
|
||||
class OsmBuilder {
|
||||
public:
|
||||
OsmBuilder();
|
||||
|
||||
// Read the OSM file at path, and write a graph to g. Only elements
|
||||
// inside the bounding box will be read
|
||||
void read(const std::string& path, const OsmReadOpts& opts, Graph* g,
|
||||
const BBoxIdx& box, size_t gridSize, router::FeedStops* fs,
|
||||
Restrictor* res);
|
||||
|
||||
|
||||
// Based on the list of options, read an OSM file from in and output an
|
||||
// OSM file to out which contains exactly the entities that are needed
|
||||
// from the file at in
|
||||
void filterWrite(const std::string& in, const std::string& out,
|
||||
const std::vector<OsmReadOpts>& opts, const BBoxIdx& box);
|
||||
|
||||
private:
|
||||
xml::ParserState readBBoxNds(xml::File* xml, OsmIdSet* nodes,
|
||||
OsmIdSet* noHupNodes, const OsmFilter& filter,
|
||||
const BBoxIdx& bbox) const;
|
||||
|
||||
void readRels(xml::File* f, RelLst* rels, RelMap* nodeRels, RelMap* wayRels,
|
||||
const OsmFilter& filter, const AttrKeySet& keepAttrs,
|
||||
Restrictions* rests) const;
|
||||
|
||||
void readRestr(const OsmRel& rel, Restrictions* rests,
|
||||
const OsmFilter& filter) const;
|
||||
|
||||
void readNodes(xml::File* f, Graph* g, const RelLst& rels,
|
||||
const RelMap& nodeRels, const OsmFilter& filter,
|
||||
const OsmIdSet& bBoxNodes, NIdMap* nodes,
|
||||
NIdMultMap* multNodes, NodeSet* orphanStations,
|
||||
const AttrKeySet& keepAttrs, const FlatRels& flatRels,
|
||||
const OsmReadOpts& opts) const;
|
||||
|
||||
void readWriteNds(xml::File* i, util::xml::XmlWriter* o,
|
||||
const RelMap& nodeRels, const OsmFilter& filter,
|
||||
const OsmIdSet& bBoxNodes, NIdMap* nodes,
|
||||
const AttrKeySet& keepAttrs, const FlatRels& f) const;
|
||||
|
||||
void readWriteWays(xml::File* i, util::xml::XmlWriter* o, OsmIdList* ways,
|
||||
const AttrKeySet& keepAttrs) const;
|
||||
|
||||
void readWriteRels(xml::File* i, util::xml::XmlWriter* o, OsmIdList* ways,
|
||||
NIdMap* nodes, const OsmFilter& filter,
|
||||
const AttrKeySet& keepAttrs);
|
||||
|
||||
void readEdges(xml::File* xml, Graph* g, const RelLst& rels,
|
||||
const RelMap& wayRels, const OsmFilter& filter,
|
||||
const OsmIdSet& bBoxNodes, NIdMap* nodes,
|
||||
NIdMultMap* multNodes, const OsmIdSet& noHupNodes,
|
||||
const AttrKeySet& keepAttrs, const Restrictions& rest,
|
||||
Restrictor* restor, const FlatRels& flatRels,
|
||||
EdgTracks* etracks, const OsmReadOpts& opts);
|
||||
|
||||
void readEdges(xml::File* xml, const RelMap& wayRels, const OsmFilter& filter,
|
||||
const OsmIdSet& bBoxNodes, const AttrKeySet& keepAttrs,
|
||||
OsmIdList* ret, NIdMap* nodes, const FlatRels& flatRels);
|
||||
|
||||
OsmWay nextWay(xml::File* xml, const RelMap& wayRels, const OsmFilter& filter,
|
||||
const OsmIdSet& bBoxNodes, const AttrKeySet& keepAttrs,
|
||||
const FlatRels& flatRels) const;
|
||||
|
||||
bool keepWay(const OsmWay& w, const RelMap& wayRels, const OsmFilter& filter,
|
||||
const OsmIdSet& bBoxNodes, const FlatRels& fl) const;
|
||||
|
||||
OsmWay nextWayWithId(xml::File* xml, osmid wid,
|
||||
const AttrKeySet& keepAttrs) const;
|
||||
|
||||
OsmNode nextNode(xml::File* xml, NIdMap* nodes, NIdMultMap* multNodes,
|
||||
const RelMap& nodeRels, const OsmFilter& filter,
|
||||
const OsmIdSet& bBoxNodes, const AttrKeySet& keepAttrs,
|
||||
const FlatRels& flatRels) const;
|
||||
|
||||
bool keepNode(const OsmNode& n, const NIdMap& nodes,
|
||||
const NIdMultMap& multNodes, const RelMap& nodeRels,
|
||||
const OsmIdSet& bBoxNodes, const OsmFilter& filter,
|
||||
const FlatRels& fl) const;
|
||||
|
||||
OsmRel nextRel(xml::File* xml, const OsmFilter& filter,
|
||||
const AttrKeySet& keepAttrs) const;
|
||||
|
||||
Nullable<StatInfo> getStatInfo(Node* node, osmid nid, const FPoint& pos,
|
||||
const AttrMap& m, StAttrGroups* groups,
|
||||
const RelMap& nodeRels, const RelLst& rels,
|
||||
const OsmReadOpts& ops) const;
|
||||
|
||||
void writeGeoms(Graph* g) const;
|
||||
void deleteOrphNds(Graph* g) const;
|
||||
void deleteOrphEdgs(Graph* g) const;
|
||||
double dist(const Node* a, const Node* b) const;
|
||||
double webMercDist(const Node* a, const Node* b) const;
|
||||
double webMercDistFactor(const FPoint& a) const;
|
||||
|
||||
NodeGrid buildNodeIdx(Graph* g, size_t size,
|
||||
const util::geo::Box<float>& webMercBox,
|
||||
bool which) const;
|
||||
|
||||
EdgeGrid buildEdgeIdx(Graph* g, size_t size,
|
||||
const util::geo::Box<float>& webMercBox) const;
|
||||
|
||||
void fixGaps(Graph* g, NodeGrid* ng) const;
|
||||
void collapseEdges(Graph* g) const;
|
||||
void writeODirEdgs(Graph* g, Restrictor* restor) const;
|
||||
void writeSelfEdgs(Graph* g) const;
|
||||
void writeEdgeTracks(const EdgTracks& tracks) const;
|
||||
void simplifyGeoms(Graph* g) const;
|
||||
uint32_t writeComps(Graph* g) const;
|
||||
bool edgesSim(const Edge* a, const Edge* b) const;
|
||||
const EdgePL& mergeEdgePL(Edge* a, Edge* b) const;
|
||||
void getEdgCands(const FPoint& s, EdgeCandPQ* ret, EdgeGrid* eg,
|
||||
double d) const;
|
||||
|
||||
std::set<Node*> getMatchingNds(const NodePL& s, NodeGrid* ng, double d) const;
|
||||
|
||||
Node* getMatchingNd(const NodePL& s, NodeGrid* ng, double d) const;
|
||||
|
||||
NodeSet snapStation(Graph* g, NodePL* s, EdgeGrid* eg, NodeGrid* sng,
|
||||
const OsmReadOpts& opts, Restrictor* restor, bool surHeur,
|
||||
double maxD) const;
|
||||
|
||||
// Checks if from the edge e, a station similar to si can be reach with less
|
||||
// than maxD distance and less or equal to "maxFullTurns" full turns. If
|
||||
// such a station exists, it is returned. If not, 0 is returned.
|
||||
Node* eqStatReach(const Edge* e, const StatInfo* si, const FPoint& p,
|
||||
double maxD, int maxFullTurns, double maxAng) const;
|
||||
|
||||
Node* depthSearch(const Edge* e, const StatInfo* si,
|
||||
const util::geo::FPoint& p, double maxD, int maxFullTurns,
|
||||
double minAngle, const SearchFunc& sfunc) const;
|
||||
|
||||
bool isBlocked(const Edge* e, const StatInfo* si, const FPoint& p,
|
||||
double maxD, int maxFullTurns, double minAngle) const;
|
||||
|
||||
StatGroup* groupStats(const NodeSet& s) const;
|
||||
|
||||
std::vector<TransitEdgeLine*> getLines(const std::vector<size_t>& edgeRels,
|
||||
const RelLst& rels,
|
||||
const OsmReadOpts& ops);
|
||||
|
||||
NodePL plFromGtfs(const Stop* s, const OsmReadOpts& ops) const;
|
||||
|
||||
void getKeptAttrKeys(const OsmReadOpts& opts, AttrKeySet sets[3]) const;
|
||||
|
||||
void skipUntil(xml::File* xml, const std::string& s) const;
|
||||
|
||||
void processRestr(osmid nid, osmid wid, const Restrictions& rawRests, Edge* e,
|
||||
Node* n, Restrictor* restor) const;
|
||||
|
||||
std::string getAttrByFirstMatch(const DeepAttrLst& rule, osmid id,
|
||||
const AttrMap& attrs, const RelMap& entRels,
|
||||
const RelLst& rels,
|
||||
const Normalizer& norm) const;
|
||||
std::vector<std::string> getAttrMatchRanked(const DeepAttrLst& rule, osmid id,
|
||||
const AttrMap& attrs,
|
||||
const RelMap& entRels,
|
||||
const RelLst& rels,
|
||||
const Normalizer& norm) const;
|
||||
|
||||
std::string getAttr(const DeepAttrRule& s, osmid id, const AttrMap& attrs,
|
||||
const RelMap& entRels, const RelLst& rels) const;
|
||||
|
||||
bool relKeep(osmid id, const RelMap& rels, const FlatRels& fl) const;
|
||||
|
||||
std::map<TransitEdgeLine, TransitEdgeLine*> _lines;
|
||||
std::map<size_t, TransitEdgeLine*> _relLines;
|
||||
};
|
||||
} // namespace osm
|
||||
} // namespace pfaedle
|
||||
#endif // PFAEDLE_OSM_OSMBUILDER_H_
|
||||
260
src/pfaedle/osm/OsmFilter.cpp
Normal file
260
src/pfaedle/osm/OsmFilter.cpp
Normal file
|
|
@ -0,0 +1,260 @@
|
|||
// Copyright 2018, University of Freiburg,
|
||||
// Chair of Algorithms and Data Structures.
|
||||
// Authors: Patrick Brosi <brosi@informatik.uni-freiburg.de>
|
||||
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include "pfaedle/osm/OsmFilter.h"
|
||||
|
||||
using pfaedle::osm::OsmFilter;
|
||||
|
||||
// _____________________________________________________________________________
|
||||
OsmFilter::OsmFilter(const MultAttrMap& keep, const MultAttrMap& drop)
|
||||
: _keep(keep), _drop(drop) {}
|
||||
|
||||
// _____________________________________________________________________________
|
||||
OsmFilter::OsmFilter(const OsmReadOpts& o)
|
||||
: _keep(o.keepFilter),
|
||||
_drop(o.dropFilter),
|
||||
_nohup(o.noHupFilter),
|
||||
_oneway(o.oneWayFilter),
|
||||
_onewayrev(o.oneWayFilterRev),
|
||||
_twoway(o.twoWayFilter),
|
||||
_station(o.stationFilter),
|
||||
_blocker(o.stationBlockerFilter),
|
||||
_posRestr(o.restrPosRestr),
|
||||
_negRestr(o.restrNegRestr),
|
||||
_noRestr(o.noRestrFilter),
|
||||
_levels(o.levelFilters) {}
|
||||
|
||||
// _____________________________________________________________________________
|
||||
uint64_t OsmFilter::keep(const AttrMap& attrs, Type t) const {
|
||||
return contained(attrs, _keep, t);
|
||||
}
|
||||
|
||||
// _____________________________________________________________________________
|
||||
uint64_t OsmFilter::drop(const AttrMap& attrs, Type t) const {
|
||||
return contained(attrs, _drop, t);
|
||||
}
|
||||
|
||||
// _____________________________________________________________________________
|
||||
uint64_t OsmFilter::nohup(const char* key, const char* v) const {
|
||||
const auto& dkv = _nohup.find(key);
|
||||
if (dkv != _nohup.end()) {
|
||||
for (const auto& val : dkv->second) {
|
||||
if (valMatches(v, val.first)) return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// _____________________________________________________________________________
|
||||
uint64_t OsmFilter::oneway(const AttrMap& attrs) const {
|
||||
if (contained(attrs, _twoway, WAY)) return false;
|
||||
return contained(attrs, _oneway, WAY);
|
||||
}
|
||||
|
||||
// _____________________________________________________________________________
|
||||
uint64_t OsmFilter::onewayrev(const AttrMap& attrs) const {
|
||||
if (contained(attrs, _twoway, WAY)) return false;
|
||||
return contained(attrs, _onewayrev, WAY);
|
||||
}
|
||||
|
||||
// _____________________________________________________________________________
|
||||
uint64_t OsmFilter::station(const AttrMap& attrs) const {
|
||||
return contained(attrs, _station, NODE);
|
||||
}
|
||||
|
||||
// _____________________________________________________________________________
|
||||
uint64_t OsmFilter::blocker(const AttrMap& attrs) const {
|
||||
return contained(attrs, _blocker, NODE);
|
||||
}
|
||||
|
||||
// _____________________________________________________________________________
|
||||
uint64_t OsmFilter::contained(const AttrMap& attrs, const MultAttrMap& map,
|
||||
Type t) {
|
||||
for (const auto& kv : attrs) {
|
||||
const auto& dkv = map.find(kv.first);
|
||||
|
||||
if (dkv != map.end()) {
|
||||
for (const auto& val : dkv->second) {
|
||||
bool multValMatch = val.second & osm::MULT_VAL_MATCH;
|
||||
if (val.second & t) continue;
|
||||
if (valMatches(kv.second, val.first, multValMatch)) return val.second;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// _____________________________________________________________________________
|
||||
uint64_t OsmFilter::contained(const AttrMap& attrs, const Attr& attr) {
|
||||
for (const auto& kv : attrs) {
|
||||
if (kv.first == attr.first) return valMatches(kv.second, attr.second);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// _____________________________________________________________________________
|
||||
uint8_t OsmFilter::level(const AttrMap& attrs) const {
|
||||
// the best matching level is always returned
|
||||
for (int16_t i = 0; i < 7; i++) {
|
||||
for (const auto& kv : attrs) {
|
||||
const auto& lkv = (_levels + i)->find(kv.first);
|
||||
if (lkv != (_levels + i)->end()) {
|
||||
for (const auto& val : lkv->second) {
|
||||
if (valMatches(kv.second, val.first)) return i + 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// _____________________________________________________________________________
|
||||
bool OsmFilter::valMatches(const std::string& a, const std::string& b) {
|
||||
return valMatches(a, b, false);
|
||||
}
|
||||
|
||||
// _____________________________________________________________________________
|
||||
bool OsmFilter::valMatches(const std::string& a, const std::string& b, bool m) {
|
||||
if (b == "*") return true;
|
||||
|
||||
if (m) {
|
||||
// search for occurances in semicolon separated list
|
||||
if (a.find(std::string(";") + b) != std::string::npos) return true;
|
||||
if (a.find(b + ";") != std::string::npos) return true;
|
||||
if (a.find(std::string("; ") + b) != std::string::npos) return true;
|
||||
if (a.find(b + " ;") != std::string::npos) return true;
|
||||
}
|
||||
|
||||
return a == b;
|
||||
}
|
||||
|
||||
// _____________________________________________________________________________
|
||||
std::vector<std::string> OsmFilter::getAttrKeys() const {
|
||||
std::vector<std::string> ret;
|
||||
for (const auto& kv : _keep) {
|
||||
ret.push_back(kv.first);
|
||||
}
|
||||
for (const auto& kv : _drop) {
|
||||
ret.push_back(kv.first);
|
||||
}
|
||||
for (const auto& kv : _nohup) {
|
||||
ret.push_back(kv.first);
|
||||
}
|
||||
for (const auto& kv : _oneway) {
|
||||
ret.push_back(kv.first);
|
||||
}
|
||||
for (const auto& kv : _twoway) {
|
||||
ret.push_back(kv.first);
|
||||
}
|
||||
for (const auto& kv : _station) {
|
||||
ret.push_back(kv.first);
|
||||
}
|
||||
for (const auto& kv : _blocker) {
|
||||
ret.push_back(kv.first);
|
||||
}
|
||||
for (const auto& kv : _posRestr) {
|
||||
ret.push_back(kv.first);
|
||||
}
|
||||
for (const auto& kv : _negRestr) {
|
||||
ret.push_back(kv.first);
|
||||
}
|
||||
for (const auto& kv : _noRestr) {
|
||||
ret.push_back(kv.first);
|
||||
}
|
||||
for (uint8_t i = 0; i < 7; i++) {
|
||||
for (const auto& kv : *(_levels + i)) {
|
||||
ret.push_back(kv.first);
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
// _____________________________________________________________________________
|
||||
OsmFilter OsmFilter::merge(const OsmFilter& other) const {
|
||||
MultAttrMap keep;
|
||||
MultAttrMap drop;
|
||||
|
||||
for (const auto& kv : _keep) {
|
||||
keep[kv.first].insert(kv.second.begin(), kv.second.end());
|
||||
}
|
||||
|
||||
for (const auto& kv : other._keep) {
|
||||
keep[kv.first].insert(kv.second.begin(), kv.second.end());
|
||||
}
|
||||
|
||||
// TODO(patrick): multi-level combination for filters. otherwise
|
||||
// filter drop filters meant as a refinement for keep filters
|
||||
// interfere with other keeps
|
||||
|
||||
// const auto* d = &_drop;
|
||||
|
||||
// for (size_t i = 0; i < 2; i++) {
|
||||
// for (const auto& kv : *d) {
|
||||
// if (keep.find(kv.first) != keep.end()) {
|
||||
// for (const auto& val : kv.second) {
|
||||
// if (keep[kv.first].find(val.first) == keep[kv.first].end()) {
|
||||
// drop[kv.first].insert(val);
|
||||
// }
|
||||
// }
|
||||
// } else {
|
||||
// drop[kv.first].insert(kv.second.begin(), kv.second.end());
|
||||
// }
|
||||
// }
|
||||
// d = &other._drop;
|
||||
// }
|
||||
|
||||
return OsmFilter(keep, drop);
|
||||
}
|
||||
|
||||
// _____________________________________________________________________________
|
||||
std::string OsmFilter::toString() const {
|
||||
std::stringstream ss;
|
||||
ss << "[KEEP]\n\n";
|
||||
|
||||
for (const auto& kv : _keep) {
|
||||
ss << " " << kv.first << "=";
|
||||
bool first = false;
|
||||
for (const auto& v : kv.second) {
|
||||
if (first) ss << ",";
|
||||
first = true;
|
||||
ss << v.first;
|
||||
}
|
||||
ss << "\n";
|
||||
}
|
||||
|
||||
ss << "\n[DROP]\n\n";
|
||||
|
||||
for (const auto& kv : _drop) {
|
||||
ss << " " << kv.first << "=";
|
||||
bool first = false;
|
||||
for (const auto& v : kv.second) {
|
||||
if (first) ss << ",";
|
||||
first = true;
|
||||
ss << v.first;
|
||||
}
|
||||
ss << "\n";
|
||||
}
|
||||
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
// _____________________________________________________________________________
|
||||
uint64_t OsmFilter::negRestr(const AttrMap& attrs) const {
|
||||
if (contained(attrs, _noRestr, ALL)) return false;
|
||||
return (contained(attrs, _negRestr, ALL));
|
||||
}
|
||||
|
||||
// _____________________________________________________________________________
|
||||
uint64_t OsmFilter::posRestr(const AttrMap& attrs) const {
|
||||
if (contained(attrs, _noRestr, ALL)) return false;
|
||||
return (contained(attrs, _posRestr, ALL));
|
||||
}
|
||||
51
src/pfaedle/osm/OsmFilter.h
Normal file
51
src/pfaedle/osm/OsmFilter.h
Normal file
|
|
@ -0,0 +1,51 @@
|
|||
// Copyright 2018, University of Freiburg,
|
||||
// Chair of Algorithms and Data Structures.
|
||||
// Authors: Patrick Brosi <brosi@informatik.uni-freiburg.de>
|
||||
|
||||
#ifndef PFAEDLE_OSM_OSMFILTER_H_
|
||||
#define PFAEDLE_OSM_OSMFILTER_H_
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include "pfaedle/osm/Osm.h"
|
||||
#include "pfaedle/osm/OsmReadOpts.h"
|
||||
|
||||
namespace pfaedle {
|
||||
namespace osm {
|
||||
|
||||
class OsmFilter {
|
||||
public:
|
||||
enum Type : uint64_t { NODE = 16, WAY = 8, REL = 4, ALL = 0 };
|
||||
OsmFilter() {}
|
||||
OsmFilter(const MultAttrMap& keep, const MultAttrMap& drop);
|
||||
explicit OsmFilter(const OsmReadOpts& o);
|
||||
uint64_t keep(const AttrMap& attrs, Type t) const;
|
||||
uint64_t drop(const AttrMap& attrs, Type t) const;
|
||||
uint64_t nohup(const char* key, const char* val) const;
|
||||
uint8_t level(const AttrMap& attrs) const;
|
||||
uint64_t oneway(const AttrMap& attrs) const;
|
||||
uint64_t onewayrev(const AttrMap& attrs) const;
|
||||
uint64_t station(const AttrMap& attrs) const;
|
||||
uint64_t blocker(const AttrMap& attrs) const;
|
||||
uint64_t negRestr(const AttrMap& attrs) const;
|
||||
uint64_t posRestr(const AttrMap& attrs) const;
|
||||
std::vector<std::string> getAttrKeys() const;
|
||||
|
||||
OsmFilter merge(const OsmFilter& other) const;
|
||||
|
||||
std::string toString() const;
|
||||
|
||||
static bool valMatches(const std::string& a, const std::string& b, bool m);
|
||||
static bool valMatches(const std::string& a, const std::string& b);
|
||||
static uint64_t contained(const AttrMap& attrs, const MultAttrMap& map,
|
||||
Type t);
|
||||
static uint64_t contained(const AttrMap& attrs, const Attr& map);
|
||||
|
||||
private:
|
||||
MultAttrMap _keep, _drop, _nohup, _oneway, _onewayrev, _twoway, _station,
|
||||
_blocker, _posRestr, _negRestr, _noRestr;
|
||||
const MultAttrMap* _levels;
|
||||
};
|
||||
} // namespace osm
|
||||
} // namespace pfaedle
|
||||
#endif // PFAEDLE_OSM_OSMFILTER_H_
|
||||
302
src/pfaedle/osm/OsmIdSet.cpp
Normal file
302
src/pfaedle/osm/OsmIdSet.cpp
Normal file
|
|
@ -0,0 +1,302 @@
|
|||
// Copyright 2018, University of Freiburg,
|
||||
// Chair of Algorithms and Data Structures.
|
||||
// Authors: Patrick Brosi <brosi@informatik.uni-freiburg.de>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <string>
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
#include <climits>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <exception>
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include "pfaedle/osm/OsmIdSet.h"
|
||||
|
||||
using pfaedle::osm::OsmIdSet;
|
||||
|
||||
size_t OsmIdSet::LOOKUPS = 0;
|
||||
size_t OsmIdSet::FLOOKUPS = 0;
|
||||
|
||||
// _____________________________________________________________________________
|
||||
OsmIdSet::OsmIdSet()
|
||||
: _closed(false),
|
||||
_sorted(true),
|
||||
_last(0),
|
||||
_smallest(-1),
|
||||
_biggest(0),
|
||||
_obufpos(0),
|
||||
_curBlock(-1),
|
||||
_fsize(0) {
|
||||
_bitset = new std::bitset<BLOOMF_BITS>();
|
||||
_file = openTmpFile();
|
||||
|
||||
_buffer = new unsigned char[BUFFER_S];
|
||||
_outBuffer = new unsigned char[OBUFFER_S];
|
||||
}
|
||||
|
||||
// _____________________________________________________________________________
|
||||
OsmIdSet::~OsmIdSet() {
|
||||
delete _bitset;
|
||||
delete[] _buffer;
|
||||
if (!_closed) delete[] _outBuffer;
|
||||
}
|
||||
|
||||
// _____________________________________________________________________________
|
||||
void OsmIdSet::add(osmid id) {
|
||||
if (_closed) throw std::exception();
|
||||
diskAdd(id);
|
||||
// _set.insert(id);
|
||||
|
||||
if (_last > id) _sorted = false;
|
||||
_last = id;
|
||||
if (id < _smallest) _smallest = id;
|
||||
if (id > _biggest) _biggest = id;
|
||||
|
||||
for (int i = 0; i < 10; i++) (*_bitset)[hash(id, i)] = 1;
|
||||
}
|
||||
|
||||
// _____________________________________________________________________________
|
||||
void OsmIdSet::diskAdd(osmid id) {
|
||||
memcpy(_outBuffer + _obufpos, &id, 8);
|
||||
|
||||
_obufpos += 8;
|
||||
|
||||
if (_obufpos % BUFFER_S == 0) {
|
||||
// this is the last value in this block
|
||||
_blockEnds.push_back(id);
|
||||
}
|
||||
|
||||
if (_obufpos >= OBUFFER_S) {
|
||||
ssize_t w = cwrite(_file, _outBuffer, OBUFFER_S);
|
||||
_fsize += w;
|
||||
_obufpos = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// _____________________________________________________________________________
|
||||
size_t OsmIdSet::getBlock(osmid id) const {
|
||||
auto it = std::upper_bound(_blockEnds.begin(), _blockEnds.end(), id);
|
||||
return (it - _blockEnds.begin());
|
||||
}
|
||||
|
||||
// _____________________________________________________________________________
|
||||
bool OsmIdSet::diskHas(osmid id) const {
|
||||
assert(_sorted);
|
||||
|
||||
if (std::find(_blockEnds.begin(), _blockEnds.end(), id) != _blockEnds.end()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
size_t block = getBlock(id);
|
||||
|
||||
if (block != _curBlock) {
|
||||
lseek(_file, block * BUFFER_S, SEEK_SET);
|
||||
|
||||
ssize_t n = cread(_file, _buffer, BUFFER_S);
|
||||
_curBlockSize = n;
|
||||
FLOOKUPS++;
|
||||
_curBlock = block;
|
||||
}
|
||||
|
||||
if (_curBlockSize <= 7) return false;
|
||||
if (*(reinterpret_cast<uint64_t*>(_buffer)) > id) return false;
|
||||
|
||||
ssize_t l = 0;
|
||||
ssize_t r = _curBlockSize - 8;
|
||||
|
||||
while (l <= r) {
|
||||
unsigned char* p = _buffer + (l + ((r - l) / 16) * 8);
|
||||
osmid cur = *(reinterpret_cast<uint64_t*>(p));
|
||||
if (cur == id) return true;
|
||||
if (cur < id)
|
||||
l = (p - _buffer) + 8;
|
||||
else
|
||||
r = (p - _buffer) - 8;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// _____________________________________________________________________________
|
||||
bool OsmIdSet::has(osmid id) const {
|
||||
LOOKUPS++;
|
||||
if (!_closed) close();
|
||||
|
||||
if (id < _smallest || id > _biggest) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (int i = 0; i < 10; i++) {
|
||||
if ((*_bitset)[hash(id, i)] == 0) return false;
|
||||
}
|
||||
|
||||
bool has = diskHas(id);
|
||||
// assert(has == (bool)_set.count(id));
|
||||
return has;
|
||||
}
|
||||
|
||||
// _____________________________________________________________________________
|
||||
void OsmIdSet::close() const {
|
||||
ssize_t w = cwrite(_file, _outBuffer, _obufpos);
|
||||
_fsize += w;
|
||||
_blockEnds.push_back(_biggest);
|
||||
delete[] _outBuffer;
|
||||
_closed = true;
|
||||
|
||||
// if order was not sorted, sort now
|
||||
if (!_sorted) sort();
|
||||
}
|
||||
|
||||
// _____________________________________________________________________________
|
||||
void OsmIdSet::sort() const {
|
||||
// sort file via an external merge sort
|
||||
|
||||
_blockEnds.clear();
|
||||
size_t parts = _fsize / SORT_BUFFER_S + 1;
|
||||
size_t partsBufSize = ((SORT_BUFFER_S / 8) / parts + 1) * 8;
|
||||
|
||||
unsigned char* buf = new unsigned char[SORT_BUFFER_S];
|
||||
unsigned char** partbufs = new unsigned char*[parts];
|
||||
size_t* partpos = new size_t[parts];
|
||||
size_t* partsize = new size_t[parts];
|
||||
|
||||
// sort the 'parts' number of file parts independently
|
||||
for (size_t i = 0; i < parts; i++) {
|
||||
partbufs[i] = new unsigned char[partsBufSize];
|
||||
partpos[i] = 0;
|
||||
partsize[i] = 0;
|
||||
lseek(_file, SORT_BUFFER_S * i, SEEK_SET);
|
||||
ssize_t n = read(_file, buf, SORT_BUFFER_S);
|
||||
if (n < 0) continue;
|
||||
qsort(buf, n / 8, 8, qsortCmp);
|
||||
lseek(_file, SORT_BUFFER_S * i, SEEK_SET);
|
||||
cwrite(_file, buf, n);
|
||||
|
||||
memcpy(partbufs[i], buf, std::min<size_t>(n, partsBufSize));
|
||||
partsize[i] = n;
|
||||
}
|
||||
|
||||
// now the individial parts are sorted
|
||||
int newFile = openTmpFile();
|
||||
|
||||
for (size_t i = 0; i < _fsize; i += 8) {
|
||||
uint64_t smallest = UINT64_MAX;
|
||||
ssize_t smallestP = -1;
|
||||
|
||||
// look for smallest element (not optimal, but running time is not
|
||||
// really critical here)
|
||||
for (size_t j = 0; j < parts; j++) {
|
||||
if (partpos[j] == partsize[j]) continue; // bucket already empty
|
||||
if (*reinterpret_cast<uint64_t*>(
|
||||
&partbufs[j][partpos[j] % partsBufSize]) <= smallest) {
|
||||
smallestP = j;
|
||||
smallest = *reinterpret_cast<uint64_t*>(
|
||||
&partbufs[j][partpos[j] % partsBufSize]);
|
||||
}
|
||||
}
|
||||
|
||||
assert(smallestP > -1);
|
||||
|
||||
memcpy(buf + (i % SORT_BUFFER_S), &smallest, 8);
|
||||
|
||||
if ((i + 8) % BUFFER_S == 0) _blockEnds.push_back(smallest);
|
||||
|
||||
if ((i % SORT_BUFFER_S) == SORT_BUFFER_S - 8 || i == _fsize - 8) {
|
||||
// write to output file
|
||||
cwrite(newFile, buf, i % SORT_BUFFER_S + 8);
|
||||
}
|
||||
|
||||
partpos[smallestP] += 8;
|
||||
|
||||
if (partpos[smallestP] % partsBufSize == 0) {
|
||||
lseek(_file, SORT_BUFFER_S * smallestP + partpos[smallestP], SEEK_SET);
|
||||
cread(_file, partbufs[smallestP], partsBufSize);
|
||||
}
|
||||
}
|
||||
|
||||
// cleanup
|
||||
delete[] buf;
|
||||
for (size_t j = 0; j < parts; j++) delete[] partbufs[j];
|
||||
delete[] partbufs;
|
||||
delete[] partpos;
|
||||
delete[] partsize;
|
||||
|
||||
_file = newFile;
|
||||
_sorted = true;
|
||||
}
|
||||
|
||||
// _____________________________________________________________________________
|
||||
size_t OsmIdSet::cwrite(int f, const void* buf, size_t n) const {
|
||||
ssize_t w = write(f, buf, n);
|
||||
if (w < 0) {
|
||||
throw std::runtime_error("OSMIDSET: could not write to tmp file.\n");
|
||||
}
|
||||
|
||||
return w;
|
||||
}
|
||||
|
||||
// _____________________________________________________________________________
|
||||
size_t OsmIdSet::cread(int f, void* buf, size_t n) const {
|
||||
ssize_t w = read(f, buf, n);
|
||||
if (w < 0) {
|
||||
throw std::runtime_error("OSMIDSET: could not read from tmp file.\n");
|
||||
}
|
||||
|
||||
return w;
|
||||
}
|
||||
|
||||
// _____________________________________________________________________________
|
||||
uint32_t OsmIdSet::knuth(uint32_t in) const {
|
||||
const uint32_t prime = 2654435769;
|
||||
return (in * prime) >> 2;
|
||||
}
|
||||
|
||||
// _____________________________________________________________________________
|
||||
uint32_t OsmIdSet::jenkins(uint32_t in) const {
|
||||
in = (in + 0x7ed55d16) + (in << 12);
|
||||
in = (in ^ 0xc761c23c) ^ (in >> 19);
|
||||
in = (in + 0x165667b1) + (in << 5);
|
||||
in = (in + 0xd3a2646c) ^ (in << 9);
|
||||
in = (in + 0xfd7046c5) + (in << 3);
|
||||
in = (in ^ 0xb55a4f09) ^ (in >> 16);
|
||||
return in >> 2;
|
||||
}
|
||||
|
||||
// _____________________________________________________________________________
|
||||
uint32_t OsmIdSet::hash(uint32_t in, int i) const {
|
||||
return (knuth(in) + jenkins(in) * i) % BLOOMF_BITS;
|
||||
}
|
||||
|
||||
// _____________________________________________________________________________
|
||||
int OsmIdSet::openTmpFile() const {
|
||||
const std::string& fname = getFName();
|
||||
int file = open(fname.c_str(), O_RDWR | O_CREAT, 0666);
|
||||
|
||||
// immediately unlink
|
||||
unlink(fname.c_str());
|
||||
|
||||
if (file < 0) {
|
||||
std::cerr << "Could not open temporary file " << fname << std::endl;
|
||||
exit(1);
|
||||
}
|
||||
|
||||
posix_fadvise(file, 0, 0, POSIX_FADV_SEQUENTIAL);
|
||||
return file;
|
||||
}
|
||||
|
||||
// _____________________________________________________________________________
|
||||
std::string OsmIdSet::getFName() const {
|
||||
std::string f = ".pfaedle-tmp";
|
||||
|
||||
while (access(f.c_str(), F_OK) != -1) {
|
||||
std::stringstream ss;
|
||||
ss << ".pfaedle-tmp-";
|
||||
ss << std::rand();
|
||||
f = ss.str().c_str();
|
||||
}
|
||||
|
||||
return f;
|
||||
}
|
||||
91
src/pfaedle/osm/OsmIdSet.h
Normal file
91
src/pfaedle/osm/OsmIdSet.h
Normal file
|
|
@ -0,0 +1,91 @@
|
|||
// Copyright 2018, University of Freiburg,
|
||||
// Chair of Algorithms and Data Structures.
|
||||
// Authors: Patrick Brosi <brosi@informatik.uni-freiburg.de>
|
||||
|
||||
#ifndef PFAEDLE_OSM_OSMIDSET_H_
|
||||
#define PFAEDLE_OSM_OSMIDSET_H_
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <bitset>
|
||||
#include <set>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include "pfaedle/osm/Osm.h"
|
||||
|
||||
namespace pfaedle {
|
||||
namespace osm {
|
||||
|
||||
// buffer sizes _must_ be multiples of 8
|
||||
static const size_t BUFFER_S = 8 * 64 * 1024;
|
||||
static const size_t SORT_BUFFER_S = 8 * 64 * 1024;
|
||||
static const size_t OBUFFER_S = 8 * 1024 * 1024;
|
||||
|
||||
#define BLOOMF_BITS 400000000
|
||||
|
||||
/*
|
||||
* A disk-based set for OSM ids. Read-access for checking the presence is
|
||||
* reduced by a bloom filter
|
||||
*/
|
||||
class OsmIdSet {
|
||||
public:
|
||||
OsmIdSet();
|
||||
~OsmIdSet();
|
||||
|
||||
// Add an OSM id
|
||||
void add(osmid id);
|
||||
|
||||
// Check if an OSM id is contained
|
||||
bool has(osmid id) const;
|
||||
|
||||
// Count the number of lookups and file lookups for debugging
|
||||
static size_t LOOKUPS;
|
||||
static size_t FLOOKUPS;
|
||||
|
||||
private:
|
||||
std::set<osmid> _set;
|
||||
mutable bool _closed;
|
||||
mutable int _file;
|
||||
unsigned char* _buffer;
|
||||
unsigned char* _outBuffer;
|
||||
mutable bool _sorted;
|
||||
osmid _last;
|
||||
osmid _smallest;
|
||||
osmid _biggest;
|
||||
|
||||
size_t _obufpos;
|
||||
mutable size_t _curBlock;
|
||||
mutable ssize_t _curBlockSize;
|
||||
|
||||
// bloom filter
|
||||
std::bitset<BLOOMF_BITS>* _bitset;
|
||||
|
||||
mutable std::vector<osmid> _blockEnds;
|
||||
|
||||
mutable size_t _fsize;
|
||||
|
||||
uint32_t knuth(uint32_t in) const;
|
||||
uint32_t jenkins(uint32_t in) const;
|
||||
uint32_t hash(uint32_t in, int i) const;
|
||||
void diskAdd(osmid id);
|
||||
void close() const;
|
||||
void sort() const;
|
||||
bool diskHas(osmid id) const;
|
||||
std::string getFName() const;
|
||||
size_t getBlock(osmid id) const;
|
||||
int openTmpFile() const;
|
||||
size_t cwrite(int f, const void* buf, size_t n) const;
|
||||
size_t cread(int f, void* buf, size_t n) const;
|
||||
|
||||
static int qsortCmp(const void* a, const void* b) {
|
||||
if (*static_cast<const uint64_t*>(a) < *static_cast<const uint64_t*>(b))
|
||||
return -1;
|
||||
if (*static_cast<const uint64_t*>(a) > *static_cast<const uint64_t*>(b))
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
} // namespace osm
|
||||
} // namespace pfaedle
|
||||
|
||||
#endif // PFAEDLE_OSM_OSMIDSET_H_
|
||||
197
src/pfaedle/osm/OsmReadOpts.h
Normal file
197
src/pfaedle/osm/OsmReadOpts.h
Normal file
|
|
@ -0,0 +1,197 @@
|
|||
// Copyright 2018, University of Freiburg,
|
||||
// Chair of Algorithms and Data Structures.
|
||||
// Authors: Patrick Brosi <brosi@informatik.uni-freiburg.de>
|
||||
|
||||
#ifndef PFAEDLE_OSM_OSMREADOPTS_H_
|
||||
#define PFAEDLE_OSM_OSMREADOPTS_H_
|
||||
|
||||
#include <queue>
|
||||
#include <unordered_set>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <map>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
#include <set>
|
||||
#include "pfaedle/osm/Osm.h"
|
||||
#include "pfaedle/trgraph/Graph.h"
|
||||
#include "pfaedle/trgraph/Normalizer.h"
|
||||
|
||||
namespace pfaedle {
|
||||
namespace osm {
|
||||
|
||||
typedef std::unordered_set<std::string> AttrKeySet;
|
||||
typedef std::unordered_map<osmid, trgraph::Node*> NIdMap;
|
||||
typedef std::unordered_map<osmid, std::set<trgraph::Node*>> NIdMultMap;
|
||||
typedef std::pair<double, trgraph::Edge*> EdgeCand;
|
||||
typedef std::priority_queue<EdgeCand> EdgeCandPQ;
|
||||
typedef std::unordered_map<osmid, std::vector<size_t>> RelMap;
|
||||
typedef std::vector<AttrMap> RelVec;
|
||||
typedef std::vector<std::string> AttrLst;
|
||||
|
||||
typedef std::pair<std::string, uint64_t> AttrFlagPair;
|
||||
typedef std::unordered_map<std::string, std::map<std::string, uint64_t>>
|
||||
MultAttrMap;
|
||||
|
||||
typedef std::pair<std::string, std::string> KeyVal;
|
||||
typedef std::set<size_t> FlatRels;
|
||||
|
||||
typedef std::unordered_map<const trgraph::Edge*, std::string> EdgTracks;
|
||||
|
||||
struct RelLst {
|
||||
RelVec rels;
|
||||
FlatRels flat;
|
||||
};
|
||||
|
||||
enum FilterFlags : uint64_t {
|
||||
USE = 1, // dummy value
|
||||
REL_NO_DOWN = 2,
|
||||
NO_RELATIONS = 4,
|
||||
NO_WAYS = 8,
|
||||
NO_NODES = 16,
|
||||
MULT_VAL_MATCH = 32
|
||||
};
|
||||
|
||||
struct FilterRule {
|
||||
FilterRule() : kv(KeyVal("", "")) {}
|
||||
KeyVal kv;
|
||||
std::set<std::string> flags;
|
||||
};
|
||||
|
||||
inline bool operator==(const FilterRule& a, const FilterRule& b) {
|
||||
return a.kv == b.kv && a.flags == b.flags;
|
||||
}
|
||||
|
||||
struct DeepAttrRule {
|
||||
std::string attr;
|
||||
FilterRule relRule;
|
||||
};
|
||||
|
||||
inline bool operator==(const DeepAttrRule& a, const DeepAttrRule& b) {
|
||||
return a.attr == b.attr && a.relRule == b.relRule;
|
||||
}
|
||||
|
||||
typedef std::vector<DeepAttrRule> DeepAttrLst;
|
||||
|
||||
struct RelLineRules {
|
||||
AttrLst sNameRule;
|
||||
AttrLst fromNameRule;
|
||||
AttrLst toNameRule;
|
||||
};
|
||||
|
||||
inline bool operator==(const RelLineRules& a, const RelLineRules& b) {
|
||||
return a.sNameRule == b.sNameRule && a.fromNameRule == b.fromNameRule &&
|
||||
a.toNameRule == b.toNameRule;
|
||||
}
|
||||
|
||||
struct StationAttrRules {
|
||||
DeepAttrLst nameRule;
|
||||
DeepAttrLst platformRule;
|
||||
};
|
||||
|
||||
inline bool operator==(const StationAttrRules& a, const StationAttrRules& b) {
|
||||
return a.nameRule == b.nameRule && a.platformRule == b.platformRule;
|
||||
}
|
||||
|
||||
struct StatGroupNAttrRule {
|
||||
DeepAttrRule attr;
|
||||
double maxDist;
|
||||
};
|
||||
|
||||
inline bool operator==(const StatGroupNAttrRule& a,
|
||||
const StatGroupNAttrRule& b) {
|
||||
return a.attr == b.attr && a.maxDist == b.maxDist;
|
||||
}
|
||||
|
||||
typedef std::unordered_map<
|
||||
std::string,
|
||||
std::unordered_map<std::string, std::vector<trgraph::StatGroup*>>>
|
||||
StAttrGroups;
|
||||
|
||||
struct OsmReadOpts {
|
||||
OsmReadOpts() {}
|
||||
|
||||
MultAttrMap noHupFilter;
|
||||
MultAttrMap keepFilter;
|
||||
MultAttrMap levelFilters[7];
|
||||
MultAttrMap dropFilter;
|
||||
MultAttrMap oneWayFilter;
|
||||
MultAttrMap oneWayFilterRev;
|
||||
MultAttrMap twoWayFilter;
|
||||
MultAttrMap stationFilter;
|
||||
MultAttrMap stationBlockerFilter;
|
||||
std::vector<StatGroupNAttrRule> statGroupNAttrRules;
|
||||
|
||||
trgraph::Normalizer statNormzer;
|
||||
trgraph::Normalizer lineNormzer;
|
||||
trgraph::Normalizer trackNormzer;
|
||||
|
||||
RelLineRules relLinerules;
|
||||
StationAttrRules statAttrRules;
|
||||
|
||||
DeepAttrLst edgePlatformRules;
|
||||
|
||||
uint8_t maxSnapLevel;
|
||||
|
||||
double maxAngleSnapReach;
|
||||
std::vector<double> maxSnapDistances;
|
||||
double maxSnapFallbackHeurDistance;
|
||||
double maxGroupSearchDistance;
|
||||
double maxBlockDistance;
|
||||
|
||||
double maxOsmStationDistance;
|
||||
|
||||
// TODO(patrick): this is not implemented yet
|
||||
double levelSnapPunishFac[7] = {0, 0, 0, 0, 0, 0, 0};
|
||||
|
||||
// restriction system
|
||||
MultAttrMap restrPosRestr;
|
||||
MultAttrMap restrNegRestr;
|
||||
MultAttrMap noRestrFilter;
|
||||
};
|
||||
|
||||
inline bool operator==(const OsmReadOpts& a, const OsmReadOpts& b) {
|
||||
if (a.maxSnapDistances.size() != b.maxSnapDistances.size()) return false;
|
||||
for (size_t i = 0; i < a.maxSnapDistances.size(); i++) {
|
||||
if (fabs(a.maxSnapDistances[i] - b.maxSnapDistances[i]) >= 0.1)
|
||||
return false;
|
||||
}
|
||||
|
||||
return a.noHupFilter == b.noHupFilter && a.keepFilter == b.keepFilter &&
|
||||
a.levelFilters[0] == b.levelFilters[0] &&
|
||||
a.levelFilters[1] == b.levelFilters[1] &&
|
||||
a.levelFilters[2] == b.levelFilters[2] &&
|
||||
a.levelFilters[3] == b.levelFilters[3] &&
|
||||
a.levelFilters[4] == b.levelFilters[4] &&
|
||||
a.levelFilters[5] == b.levelFilters[5] &&
|
||||
a.levelFilters[6] == b.levelFilters[6] &&
|
||||
a.dropFilter == b.dropFilter && a.oneWayFilter == b.oneWayFilter &&
|
||||
a.oneWayFilterRev == b.oneWayFilterRev &&
|
||||
a.twoWayFilter == b.twoWayFilter &&
|
||||
a.stationFilter == b.stationFilter &&
|
||||
a.stationBlockerFilter == b.stationBlockerFilter &&
|
||||
a.statGroupNAttrRules == b.statGroupNAttrRules &&
|
||||
a.statNormzer == b.statNormzer && a.lineNormzer == b.lineNormzer &&
|
||||
a.trackNormzer == b.trackNormzer && a.relLinerules == b.relLinerules &&
|
||||
a.statAttrRules == b.statAttrRules &&
|
||||
a.maxSnapLevel == b.maxSnapLevel &&
|
||||
fabs(a.maxAngleSnapReach - b.maxAngleSnapReach) < 0.1 &&
|
||||
fabs(a.maxOsmStationDistance - b.maxOsmStationDistance) < 0.1 &&
|
||||
fabs(a.maxSnapFallbackHeurDistance - b.maxSnapFallbackHeurDistance) <
|
||||
0.1 &&
|
||||
fabs(a.maxGroupSearchDistance - b.maxGroupSearchDistance) < 0.1 &&
|
||||
fabs(a.maxBlockDistance - b.maxBlockDistance) < 0.1 &&
|
||||
fabs(a.levelSnapPunishFac[0] - b.levelSnapPunishFac[0]) < 0.1 &&
|
||||
fabs(a.levelSnapPunishFac[1] - b.levelSnapPunishFac[1]) < 0.1 &&
|
||||
fabs(a.levelSnapPunishFac[2] - b.levelSnapPunishFac[2]) < 0.1 &&
|
||||
fabs(a.levelSnapPunishFac[3] - b.levelSnapPunishFac[3]) < 0.1 &&
|
||||
fabs(a.levelSnapPunishFac[4] - b.levelSnapPunishFac[4]) < 0.1 &&
|
||||
fabs(a.levelSnapPunishFac[5] - b.levelSnapPunishFac[5]) < 0.1 &&
|
||||
fabs(a.levelSnapPunishFac[6] - b.levelSnapPunishFac[6]) < 0.1 &&
|
||||
a.restrPosRestr == b.restrPosRestr &&
|
||||
a.restrNegRestr == b.restrNegRestr &&
|
||||
a.noRestrFilter == b.noRestrFilter;
|
||||
}
|
||||
} // namespace osm
|
||||
} // namespace pfaedle
|
||||
#endif // PFAEDLE_OSM_OSMREADOPTS_H_
|
||||
155
src/pfaedle/osm/Restrictor.cpp
Normal file
155
src/pfaedle/osm/Restrictor.cpp
Normal file
|
|
@ -0,0 +1,155 @@
|
|||
// Copyright 2018, University of Freiburg,
|
||||
// Chair of Algorithms and Data Structures.
|
||||
// Authors: Patrick Brosi <brosi@informatik.uni-freiburg.de>
|
||||
|
||||
#include "pfaedle/osm/Restrictor.h"
|
||||
#include "util/log/Log.h"
|
||||
|
||||
using pfaedle::osm::Restrictor;
|
||||
|
||||
// _____________________________________________________________________________
|
||||
void Restrictor::relax(osmid wid, const trgraph::Node* n,
|
||||
const trgraph::Edge* e) {
|
||||
// the wid is not unique here, because the OSM ways are split into
|
||||
// multiple edges. They are only unique as a pair with a "from-via" point.
|
||||
_rlx[NodeOsmIdP(n, wid)] = e;
|
||||
auto i = _posDangling.find(NodeOsmIdP(n, wid));
|
||||
if (i != _posDangling.end()) {
|
||||
for (const auto& path : i->second) {
|
||||
_pos[path.first][path.second].second = e;
|
||||
assert(path.first->hasEdge(e));
|
||||
}
|
||||
}
|
||||
|
||||
auto j = _negDangling.find(NodeOsmIdP(n, wid));
|
||||
if (j != _negDangling.end()) {
|
||||
for (const auto& path : j->second) {
|
||||
_neg[path.first][path.second].second = e;
|
||||
assert(path.first->hasEdge(e));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// _____________________________________________________________________________
|
||||
void Restrictor::add(const trgraph::Edge* from, osmid to,
|
||||
const trgraph::Node* via, bool pos) {
|
||||
const trgraph::Edge* toE = 0;
|
||||
if (_rlx.count(NodeOsmIdP(via, to)))
|
||||
toE = _rlx.find(NodeOsmIdP(via, to))->second;
|
||||
if (pos) {
|
||||
_pos[via].push_back(RulePair(from, toE));
|
||||
if (!toE)
|
||||
_posDangling[NodeOsmIdP(via, to)].push_back(
|
||||
DanglPath(via, _pos[via].size() - 1));
|
||||
} else {
|
||||
_neg[via].push_back(RulePair(from, toE));
|
||||
if (!toE)
|
||||
_negDangling[NodeOsmIdP(via, to)].push_back(
|
||||
DanglPath(via, _neg[via].size() - 1));
|
||||
}
|
||||
}
|
||||
|
||||
// _____________________________________________________________________________
|
||||
bool Restrictor::may(const trgraph::Edge* from, const trgraph::Edge* to,
|
||||
const trgraph::Node* via) const {
|
||||
auto posI = _pos.find(via);
|
||||
auto negI = _neg.find(via);
|
||||
|
||||
if (posI != _pos.end()) {
|
||||
for (const auto& r : posI->second) {
|
||||
if (r.first == from && r.second && r.second != to)
|
||||
return false;
|
||||
else if (r.first == from && r.second == to)
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if (negI != _neg.end()) {
|
||||
for (const auto& r : negI->second) {
|
||||
if (r.first == from && r.second == to) return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// _____________________________________________________________________________
|
||||
void Restrictor::replaceEdge(const trgraph::Edge* old,
|
||||
const trgraph::Edge* newA,
|
||||
const trgraph::Edge* newB) {
|
||||
const trgraph::Edge* newFrom;
|
||||
const trgraph::Edge* newTo;
|
||||
if (old->getFrom() == newA->getFrom() || old->getFrom() == newA->getTo()) {
|
||||
newFrom = newA;
|
||||
newTo = newB;
|
||||
} else {
|
||||
newFrom = newB;
|
||||
newTo = newA;
|
||||
}
|
||||
replaceEdge(old, old->getFrom(), newFrom);
|
||||
replaceEdge(old, old->getTo(), newTo);
|
||||
}
|
||||
|
||||
// _____________________________________________________________________________
|
||||
void Restrictor::duplicateEdge(const trgraph::Edge* old,
|
||||
const trgraph::Edge* newE) {
|
||||
duplicateEdge(old, old->getFrom(), newE);
|
||||
duplicateEdge(old, old->getTo(), newE);
|
||||
}
|
||||
|
||||
// _____________________________________________________________________________
|
||||
void Restrictor::duplicateEdge(const trgraph::Edge* old,
|
||||
const trgraph::Node* via,
|
||||
const trgraph::Edge* newE) {
|
||||
auto posI = _pos.find(via);
|
||||
auto negI = _neg.find(via);
|
||||
|
||||
assert(old->getFrom() == newE->getTo() && old->getTo() == newE->getFrom());
|
||||
|
||||
if (posI != _pos.end()) {
|
||||
for (auto& r : posI->second) {
|
||||
if (r.first == old) {
|
||||
if (r.first->getTo() != via) {
|
||||
r.first = newE;
|
||||
}
|
||||
}
|
||||
if (r.second == old) {
|
||||
if (r.second->getFrom() != via) {
|
||||
r.second = newE;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (negI != _neg.end()) {
|
||||
for (auto& r : negI->second) {
|
||||
if (r.first == old) {
|
||||
if (r.first->getTo() != via) {
|
||||
r.first = newE;
|
||||
}
|
||||
}
|
||||
if (r.second == old) {
|
||||
if (r.second->getFrom() != via) {
|
||||
r.second = newE;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// _____________________________________________________________________________
|
||||
void Restrictor::replaceEdge(const trgraph::Edge* old, const trgraph::Node* via,
|
||||
const trgraph::Edge* newE) {
|
||||
auto posI = _pos.find(via);
|
||||
auto negI = _neg.find(via);
|
||||
|
||||
if (posI != _pos.end()) {
|
||||
for (auto& r : posI->second) {
|
||||
if (r.first == old) r.first = newE;
|
||||
if (r.second == old) r.second = newE;
|
||||
}
|
||||
}
|
||||
if (negI != _neg.end()) {
|
||||
for (auto& r : negI->second) {
|
||||
if (r.first == old) r.first = newE;
|
||||
if (r.second == old) r.second = newE;
|
||||
}
|
||||
}
|
||||
}
|
||||
60
src/pfaedle/osm/Restrictor.h
Normal file
60
src/pfaedle/osm/Restrictor.h
Normal file
|
|
@ -0,0 +1,60 @@
|
|||
// Copyright 2018, University of Freiburg,
|
||||
// Chair of Algorithms and Data Structures.
|
||||
// Authors: Patrick Brosi <brosi@informatik.uni-freiburg.de>
|
||||
|
||||
#ifndef PFAEDLE_OSM_RESTRICTOR_H_
|
||||
#define PFAEDLE_OSM_RESTRICTOR_H_
|
||||
|
||||
#include <unordered_map>
|
||||
#include <map>
|
||||
#include <vector>
|
||||
#include <utility>
|
||||
#include "pfaedle/osm/Osm.h"
|
||||
#include "pfaedle/trgraph/Graph.h"
|
||||
|
||||
namespace pfaedle {
|
||||
namespace osm {
|
||||
|
||||
typedef std::pair<const trgraph::Edge*, const trgraph::Edge*> RulePair;
|
||||
typedef std::vector<RulePair> RuleVec;
|
||||
typedef std::pair<const trgraph::Node*, size_t> DanglPath;
|
||||
// very seldom, there are more than a handful of rules for a node. Use a
|
||||
// vector here, should have lesser overhead and be faster for such small
|
||||
// numbers
|
||||
typedef std::unordered_map<const trgraph::Node*, RuleVec> Rules;
|
||||
typedef std::pair<const trgraph::Node*, osmid> NodeOsmIdP;
|
||||
|
||||
/*
|
||||
* Stores restrictions between edges
|
||||
*/
|
||||
class Restrictor {
|
||||
public:
|
||||
Restrictor() {}
|
||||
|
||||
void relax(osmid wid, const trgraph::Node* n, const trgraph::Edge* e);
|
||||
void add(const trgraph::Edge* from, osmid to, const trgraph::Node* via,
|
||||
bool pos);
|
||||
bool may(const trgraph::Edge* from, const trgraph::Edge* to,
|
||||
const trgraph::Node* via) const;
|
||||
void replaceEdge(const trgraph::Edge* old, const trgraph::Edge* newA,
|
||||
const trgraph::Edge* newB);
|
||||
void duplicateEdge(const trgraph::Edge* old, const trgraph::Node* via,
|
||||
const trgraph::Edge* newE);
|
||||
void duplicateEdge(const trgraph::Edge* old, const trgraph::Edge* newE);
|
||||
|
||||
private:
|
||||
Rules _pos;
|
||||
Rules _neg;
|
||||
|
||||
std::map<NodeOsmIdP, const trgraph::Edge*> _rlx;
|
||||
|
||||
std::map<NodeOsmIdP, std::vector<DanglPath>> _posDangling;
|
||||
std::map<NodeOsmIdP, std::vector<DanglPath>> _negDangling;
|
||||
|
||||
void replaceEdge(const trgraph::Edge* old, const trgraph::Node* via,
|
||||
const trgraph::Edge* newE);
|
||||
};
|
||||
} // namespace osm
|
||||
} // namespace pfaedle
|
||||
|
||||
#endif // PFAEDLE_OSM_RESTRICTOR_H_
|
||||
Loading…
Add table
Add a link
Reference in a new issue