Eclipse SUMO - Simulation of Urban MObility
Loading...
Searching...
No Matches
CCHGraph.h
Go to the documentation of this file.
1/****************************************************************************/
2// Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
3// Copyright (C) 2001-2026 German Aerospace Center (DLR) and others.
4// This program and the accompanying materials are made available under the
5// terms of the Eclipse Public License 2.0 which is available at
6// https://www.eclipse.org/legal/epl-2.0/
7// This Source Code may also be made available under the following Secondary
8// Licenses when the conditions for such availability set forth in the Eclipse
9// Public License 2.0 are satisfied: GNU General Public License, version 2
10// or later which is available at
11// https://www.gnu.org/licenses/old-licenses/gpl-2.0-standalone.html
12// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-or-later
13/****************************************************************************/
18// Edge-graph <-> RoutingKit CCH graph mapping, shared between the
19// simulation (CCHGraph over MSEdge) and duarouter (RODUACCHGraph over
20// ROEdge) -- the GRAPH template argument of CCHRouter.
21//
22// RoutingKit node = one non-internal, non-taz edge (densely re-indexed).
23// RoutingKit arc = one edge-to-edge connection (u -> to) from
24// getViaSuccessors, with any internal/via edge chain
25// between them folded into the arc weight.
26//
27// The topology (arcs/order/CCH) is metric-INDEPENDENT and built once from
28// the class-union successor sets. Weights are metric-DEPENDENT centisecond
29// integers recomputed from the caller's effort function (fillInputWeights /
30// computeArcWeight); forbidden arcs get exactly RoutingKit::inf_weight so
31// the arc set (topology) never changes.
32//
33// ARC WEIGHT CONVENTION (load-bearing):
34// w(u -> to) = round(100 * ( viaEffort(u..to) + effort(to) )) [centiseconds]
35// so a path u0->u1->...->uk sums arc weights = via + effort(u1..uk), and the
36// FULL route cost equals query_distance + effort(u0) (the source edge's
37// own effort, added back by the caller as the source seed). This is NOT
38// round(100*recomputeCosts({u,to})): that would double-count effort(u) on
39// every hop of a multi-edge path.
40/****************************************************************************/
41#pragma once
42#include <config.h>
43
44#include <cmath>
45#include <limits>
46#include <map>
47#include <vector>
53#include <utils/geom/Position.h>
54#pragma GCC diagnostic push
55#pragma GCC diagnostic ignored "-Wunused-parameter"
58#pragma GCC diagnostic pop
59
60// #define CCH_DEBUG
61
62
63// ===========================================================================
64// class definitions
65// ===========================================================================
85template<class E, class V>
86class CCHGraph {
87public:
89 typedef double (*EffortOperation)(const E* const, const V* const, double);
90
92 static const unsigned INVALID_NODE;
93
101 explicit CCHGraph(const std::vector<E*>& allEdges) {
102 // 1. dense node indexing over real (non-internal, non-taz) edges.
103 unsigned maxNumID = 0;
104 for (const E* e : allEdges) {
105 maxNumID = MAX2(maxNumID, (unsigned)e->getNumericalID());
106 }
107 myEdgeToNode.assign(maxNumID + 1, INVALID_NODE);
108 for (const E* e : allEdges) {
109 // excluded are junction-internal edges and the district STAR
110 // connectors ("<taz>-source"/"-sink", the high-degree phantom
111 // edges -- see the class documentation). Legacy net edges with
112 // function="connector" are ordinary routable geometry for the
113 // exact routers and therefore stay ordinary nodes here; only the
114 // paired district connectors (identified by their
115 // otherTazConnector link) are kept out of the hierarchy.
116 if (e->isInternal() || isStarConnector(e)) {
117 continue;
118 }
119 const unsigned node = (unsigned)myNodeToEdge.size();
120 myEdgeToNode[e->getNumericalID()] = node;
121 myNodeToEdge.push_back(e);
122 }
123 const unsigned nNodes = (unsigned)myNodeToEdge.size();
124
125 // 2. arcs from the union successors; coordinates for the orderer.
126 std::vector<float> lon(nNodes);
127 std::vector<float> lat(nNodes);
128 for (unsigned n = 0; n < nNodes; n++) {
129 const E* e = myNodeToEdge[n];
130 Position p;
131 if (!e->getLanes().empty()) {
132 p = e->getLanes()[0]->geometryPositionAtOffset(e->getLength() * 0.5);
133 } else {
134 const auto* j = e->getToJunction() != nullptr ? e->getToJunction() : e->getFromJunction();
135 p = (j != nullptr) ? j->getPosition() : Position(0., 0.);
136 }
137 if (GeoConvHelper::getFinal().usingGeoProjection()) {
139 }
140 lon[n] = (float)p.x();
141 lat[n] = (float)p.y();
142 }
143 for (unsigned n = 0; n < nNodes; n++) {
144 const E* u = myNodeToEdge[n];
145 for (const auto& follower : u->getViaSuccessors(SVC_IGNORING)) {
146 const E* to = follower.first;
147 if (to == nullptr || to->getNumericalID() >= (int)myEdgeToNode.size()) {
148 continue;
149 }
150 const unsigned toNode = myEdgeToNode[to->getNumericalID()];
151 if (toNode == INVALID_NODE) {
152 continue; // successor is internal/taz -> not a routable node
153 }
154 myArcOf[std::make_pair(n, toNode)] = (unsigned)myArcTail.size();
155 myArcTail.push_back(n);
156 myArcHead.push_back(toNode);
157 myArcVia.push_back(follower.second); // leading internal edge or nullptr
158 }
159 }
160 myArcPerm.assign(myArcTail.size(), 0);
161 myPrimedClasses = 0;
162 // 2b. reverse image for sparse re-customization: for every arc, the
163 // edges its weight reads at fill time (head edge + folded via chain;
164 // the tail edge is deliberately absent from the weight, see the arc
165 // weight convention above)
166 myEdgeToArcs.resize(myEdgeToNode.size());
167 for (unsigned a = 0; a < (unsigned)myArcHead.size(); a++) {
168 myEdgeToArcs[myNodeToEdge[myArcHead[a]]->getNumericalID()].push_back(a);
169 const E* via = myArcVia[a];
170 while (via != nullptr && via->isInternal()) {
171 if (via->getNumericalID() >= 0 && via->getNumericalID() < (int)myEdgeToArcs.size()) {
172 myEdgeToArcs[via->getNumericalID()].push_back(a);
173 }
174 const auto& vs = via->getViaSuccessors();
175 via = vs.empty() ? nullptr : vs.front().second;
176 }
177 }
178
179 // 3. TAZ member sets (query-time "phantom nodes"): successors for a
180 // source connector (entry edges), predecessors for a sink connector.
181 unsigned nTazSrc = 0, nTazSnk = 0;
182 for (const E* e : allEdges) {
183 if (!isStarConnector(e)) {
184 continue;
185 }
186 std::vector<unsigned> srcNodes;
187 for (const auto& follower : e->getViaSuccessors(SVC_IGNORING)) {
188 const unsigned m = nodeOf(follower.first);
189 if (m != INVALID_NODE) {
190 srcNodes.push_back(m);
191 }
192 }
193 std::vector<unsigned> snkNodes;
194 for (const E* pred : e->getPredecessors()) {
195 const unsigned m = nodeOf(pred);
196 if (m != INVALID_NODE) {
197 snkNodes.push_back(m);
198 }
199 }
200 if (!srcNodes.empty()) {
201 myTazSrcNodes[e] = std::move(srcNodes);
202 nTazSrc++;
203 }
204 if (!snkNodes.empty()) {
205 myTazSnkNodes[e] = std::move(snkNodes);
206 nTazSnk++;
207 }
208 }
209
210 // 4. metric-independent order + CCH topology (the one-time work).
211 // @todo persist the order keyed by a network hash (recompute is fast)
213 nNodes, myArcTail, myArcHead, lat, lon);
215#ifdef CCH_DEBUG
216 std::cout << "CCH: " << nNodes << " road nodes, "
217 << arcCount() << " arcs, "
218 << myCCH.cch_arc_count() << " cch-arcs (fill x" << (double)myCCH.cch_arc_count() / MAX2((unsigned)1, arcCount())
219 << "), " << nTazSrc<< " TAZ sources, " << nTazSnk << " TAZ sinks." << std::endl;
220#endif
221 }
222
223 virtual ~CCHGraph() {}
224
227 return myCCH;
228 }
229
231 unsigned arcCount() const {
232 return (unsigned)myArcTail.size();
233 }
234
237 unsigned edgeIdSpace() const {
238 return (unsigned)myEdgeToNode.size();
239 }
240
242 unsigned nodeOf(const E* e) const {
243 if (e == nullptr || e->getNumericalID() < 0 || e->getNumericalID() >= (int)myEdgeToNode.size()) {
244 return INVALID_NODE;
245 }
246 return myEdgeToNode[e->getNumericalID()];
247 }
248
250 const E* edgeOf(unsigned node) const {
251 return myNodeToEdge[node];
252 }
253
256 const std::vector<unsigned>& tazSources(const E* taz) const {
257 static const std::vector<unsigned> empty;
258 const auto it = myTazSrcNodes.find(taz);
259 return it == myTazSrcNodes.end() ? empty : it->second;
260 }
261
264 const std::vector<unsigned>& tazSinks(const E* taz) const {
265 static const std::vector<unsigned> empty;
266 const auto it = myTazSnkNodes.find(taz);
267 return it == myTazSnkNodes.end() ? empty : it->second;
268 }
269
273 const std::vector<unsigned>& arcsOfEdge(const E* e) const {
274 static const std::vector<unsigned> empty;
275 if (e == nullptr || e->getNumericalID() < 0 || e->getNumericalID() >= (int)myEdgeToArcs.size()) {
276 return empty;
277 }
278 return myEdgeToArcs[e->getNumericalID()];
279 }
280
287 void expandNodePath(const std::vector<unsigned>& nodePath,
288 std::vector<const E*>& into) const {
289 into.reserve(into.size() + nodePath.size());
290 for (unsigned node : nodePath) {
291 into.push_back(myNodeToEdge[node]);
292 }
293 }
294
297 static double viaChainEffort(const E* via, EffortOperation effort,
298 const V* veh, double time) {
299 double sum = 0.;
300 while (via != nullptr && via->isInternal()) {
301 sum += effort(via, veh, time);
302 const auto& vs = via->getViaSuccessors();
303 via = vs.empty() ? nullptr : vs.front().second;
304 }
305 return sum;
306 }
307
308public:
318 unsigned computeArcWeight(unsigned a, EffortOperation effort, SUMOVehicleClass maskClass,
319 const V* veh, double time) const {
320 if (maskClass != SVC_IGNORING
321 && (((myArcPerm[a] & maskClass) == 0)
322 || ((edgeOf(myArcHead[a])->getPermissions() & maskClass) == 0))) {
324 }
325 return computeArcWeightRaw(a, effort, veh, time);
326 }
327
340 const V* veh, double time,
341 std::vector<unsigned>& weight) const {
342 primeClassMask(maskClass);
343 weight.resize(arcCount());
344 for (unsigned a = 0; a < arcCount(); a++) {
345 weight[a] = computeArcWeight(a, effort, maskClass, veh, time);
346 }
347 }
348
357 void invalidateClassMasks() const {
358 myArcPerm.assign(myArcPerm.size(), 0);
359 myPrimedClasses = 0;
360 }
361
362private:
366 static bool isStarConnector(const E* e) {
367 return e->isTazConnector() && e->getOtherTazConnector() != nullptr;
368 }
369
380 void primeClassMask(SUMOVehicleClass vClass) const {
381 if (vClass == SVC_IGNORING || (myPrimedClasses & vClass) == vClass) {
382 return;
383 }
384 for (unsigned n = 0; n < (unsigned)myNodeToEdge.size(); n++) {
385 for (const auto& follower : myNodeToEdge[n]->getViaSuccessors(vClass)) {
386 const unsigned toNode = nodeOf(follower.first);
387 if (toNode == INVALID_NODE) {
388 continue;
389 }
390 const auto it = myArcOf.find(std::make_pair(n, toNode));
391 if (it != myArcOf.end()) {
392 myArcPerm[it->second] |= (SVCPermissions)vClass;
393 }
394 }
395 }
397 }
398
402 unsigned computeArcWeightRaw(unsigned a, EffortOperation effort,
403 const V* veh, double time) const {
404 const E* to = myNodeToEdge[myArcHead[a]];
405 const double bigEffort = (double)(RoutingKit::inf_weight - 1) / 100.0;
406 const double eff = viaChainEffort(myArcVia[a], effort, veh, time)
407 + effort(to, veh, time);
408 if (!(eff < bigEffort)) {
410 }
411 const long long cs = std::llround(eff * 100.0);
412 return (unsigned)(cs < 0 ? 0 : (cs >= (long long)RoutingKit::inf_weight
413 ? RoutingKit::inf_weight - 1 : cs));
414 }
415
417 std::vector<const E*> myNodeToEdge;
419 std::vector<unsigned> myEdgeToNode;
421 std::vector<unsigned> myArcTail;
422 std::vector<unsigned> myArcHead;
424 std::vector<const E*> myArcVia;
426 std::map<std::pair<unsigned, unsigned>, unsigned> myArcOf;
429 mutable std::vector<SVCPermissions> myArcPerm;
434 std::vector<std::vector<unsigned> > myEdgeToArcs;
436 std::map<const E*, std::vector<unsigned> > myTazSrcNodes;
438 std::map<const E*, std::vector<unsigned> > myTazSnkNodes;
441
442private:
443 CCHGraph(const CCHGraph&) = delete;
444 CCHGraph& operator=(const CCHGraph&) = delete;
445};
446
447
448template<class E, class V>
long long int SVCPermissions
bitset where each bit declares whether a certain SVC may use this edge/lane
SUMOVehicleClass
Definition of vehicle classes to differ between different lane usage and authority types.
@ SVC_IGNORING
vehicles ignoring classes
T MAX2(T a, T b)
Definition StdDefs.h:86
Metric-independent RoutingKit CCH topology over the PURE road graph.
Definition CCHGraph.h:86
unsigned edgeIdSpace() const
size of the edge numerical-id space the graph was built over (for callers keeping per-edge-id side ar...
Definition CCHGraph.h:237
static bool isStarConnector(const E *e)
whether the edge is a district star connector (the paired "<taz>-source"/"-sink" phantom edge) as opp...
Definition CCHGraph.h:366
std::vector< const E * > myArcVia
per-arc leading via/internal edge (nullptr if none) for path re-expansion
Definition CCHGraph.h:424
SVCPermissions myPrimedClasses
the classes already primed into myArcPerm
Definition CCHGraph.h:431
std::vector< SVCPermissions > myArcPerm
per-arc CONNECTION-level permission bitmask, accumulated per primed class (see primeClassMask); mutab...
Definition CCHGraph.h:429
CCHGraph & operator=(const CCHGraph &)=delete
unsigned nodeOf(const E *e) const
RoutingKit node index for an edge, or INVALID_NODE if not a node.
Definition CCHGraph.h:242
void expandNodePath(const std::vector< unsigned > &nodePath, std::vector< const E * > &into) const
Map a RoutingKit node path back to the edge sequence.
Definition CCHGraph.h:287
const std::vector< unsigned > & tazSinks(const E *taz) const
road member nodes of a TAZ-sink connector (its exit edges), to seed multi-TARGET queries; empty if ta...
Definition CCHGraph.h:264
std::vector< const E * > myNodeToEdge
node index -> backing edge
Definition CCHGraph.h:417
unsigned arcCount() const
number of input arcs (== number of mapped connections)
Definition CCHGraph.h:231
std::vector< unsigned > myArcHead
Definition CCHGraph.h:422
double(* EffortOperation)(const E *const, const V *const, double)
effort callback signature, matching SUMOAbstractRouter::Operation
Definition CCHGraph.h:89
static const unsigned INVALID_NODE
sentinel for "not a routable node"
Definition CCHGraph.h:92
void primeClassMask(SUMOVehicleClass vClass) const
Record which arcs vClass may traverse in the per-arc CONNECTION-level permission bitmask – exactly th...
Definition CCHGraph.h:380
std::vector< unsigned > myArcTail
per-arc endpoints
Definition CCHGraph.h:421
virtual ~CCHGraph()
Definition CCHGraph.h:223
void fillInputWeights(EffortOperation effort, SUMOVehicleClass maskClass, const V *veh, double time, std::vector< unsigned > &weight) const
Fill a centisecond input-weight buffer for one vehicle class.
Definition CCHGraph.h:339
unsigned computeArcWeightRaw(unsigned a, EffortOperation effort, const V *veh, double time) const
The unmasked weight of one arc: via-chain effort + head-edge effort, rounded to centiseconds and clam...
Definition CCHGraph.h:402
const std::vector< unsigned > & tazSources(const E *taz) const
road member nodes of a TAZ-source connector (its entry edges), to seed multi-SOURCE queries; empty if...
Definition CCHGraph.h:256
void invalidateClassMasks() const
Drop every primed connection mask so the next fill re-primes from the CURRENT successor lists.
Definition CCHGraph.h:357
std::vector< unsigned > myEdgeToNode
edge numerical id -> node index (INVALID_NODE if not a node)
Definition CCHGraph.h:419
CCHGraph(const std::vector< E * > &allEdges)
Build the union line graph + CCH from the given edges.
Definition CCHGraph.h:101
std::vector< std::vector< unsigned > > myEdgeToArcs
edge numerical id -> arcs whose weight reads that edge (head + folded via edges); the reverse image o...
Definition CCHGraph.h:434
const E * edgeOf(unsigned node) const
the edge backing a RoutingKit node
Definition CCHGraph.h:250
const RoutingKit::CustomizableContractionHierarchy & cch() const
the immutable CCH (share const& across clones)
Definition CCHGraph.h:226
std::map< const E *, std::vector< unsigned > > myTazSnkNodes
TAZ-sink connector edge -> its exit-edge road node ids.
Definition CCHGraph.h:438
std::map< std::pair< unsigned, unsigned >, unsigned > myArcOf
(tail node, head node) -> arc index
Definition CCHGraph.h:426
const std::vector< unsigned > & arcsOfEdge(const E *e) const
the arcs whose weight depends on the given edge (arcs it heads plus arcs whose folded via chain conta...
Definition CCHGraph.h:273
CCHGraph(const CCHGraph &)=delete
std::map< const E *, std::vector< unsigned > > myTazSrcNodes
TAZ-source connector edge -> its entry-edge road node ids.
Definition CCHGraph.h:436
RoutingKit::CustomizableContractionHierarchy myCCH
the immutable hierarchy
Definition CCHGraph.h:440
unsigned computeArcWeight(unsigned a, EffortOperation effort, SUMOVehicleClass maskClass, const V *veh, double time) const
Recompute the input weight of one arc – the exact per-arc body of fillInputWeights (same masking,...
Definition CCHGraph.h:318
static double viaChainEffort(const E *via, EffortOperation effort, const V *veh, double time)
effort accumulated crossing the internal/via chain that leads from one real edge onto its successor (...
Definition CCHGraph.h:297
static const GeoConvHelper & getFinal()
the coordinate transformation for writing the location element and for tracking the original coordina...
void cartesian2geo(Position &cartesian) const
Converts the given cartesian (shifted) position to its geo (lat/long) representation.
A point in 2D or 3D with translation and scaling methods.
Definition Position.h:37
double x() const
Returns the x-position.
Definition Position.h:52
double y() const
Returns the y-position.
Definition Position.h:57
unsigned node
unsigned weight
std::vector< unsigned > compute_nested_node_dissection_order_using_inertial_flow(unsigned node_count, const std::vector< unsigned > &tail, const std::vector< unsigned > &head, const std::vector< float > &latitude, const std::vector< float > &longitude, const std::function< void(const std::string &)> &log_message=[](const std::string &){})