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#ifdef __GNUC__
55#pragma GCC diagnostic push
56#pragma GCC diagnostic ignored "-Wunused-parameter"
57#endif
58#ifdef _MSC_VER
59#pragma warning(push)
60#pragma warning(disable: 4267 4458)
61#endif
64#ifdef _MSC_VER
65#pragma warning(pop)
66#endif
67#ifdef __GNUC__
68#pragma GCC diagnostic pop
69#endif
70
71// #define CCH_DEBUG
72
73
74// ===========================================================================
75// class definitions
76// ===========================================================================
96template<class E, class V>
97class CCHGraph {
98public:
100 typedef double (*EffortOperation)(const E* const, const V* const, double);
101
103 static const unsigned INVALID_NODE;
104
112 explicit CCHGraph(const std::vector<E*>& allEdges) {
113 // 1. dense node indexing over real (non-internal, non-taz) edges.
114 unsigned maxNumID = 0;
115 for (const E* e : allEdges) {
116 maxNumID = MAX2(maxNumID, (unsigned)e->getNumericalID());
117 }
118 myEdgeToNode.assign(maxNumID + 1, INVALID_NODE);
119 for (const E* e : allEdges) {
120 // excluded are junction-internal edges and the district STAR
121 // connectors ("<taz>-source"/"-sink", the high-degree phantom
122 // edges -- see the class documentation). Legacy net edges with
123 // function="connector" are ordinary routable geometry for the
124 // exact routers and therefore stay ordinary nodes here; only the
125 // paired district connectors (identified by their
126 // otherTazConnector link) are kept out of the hierarchy.
127 if (e->isInternal() || isStarConnector(e)) {
128 continue;
129 }
130 const unsigned node = (unsigned)myNodeToEdge.size();
131 myEdgeToNode[e->getNumericalID()] = node;
132 myNodeToEdge.push_back(e);
133 }
134 const unsigned nNodes = (unsigned)myNodeToEdge.size();
135
136 // 2. arcs from the union successors; coordinates for the orderer.
137 std::vector<float> lon(nNodes);
138 std::vector<float> lat(nNodes);
139 for (unsigned n = 0; n < nNodes; n++) {
140 const E* e = myNodeToEdge[n];
141 Position p;
142 if (!e->getLanes().empty()) {
143 p = e->getLanes()[0]->geometryPositionAtOffset(e->getLength() * 0.5);
144 } else {
145 const auto* j = e->getToJunction() != nullptr ? e->getToJunction() : e->getFromJunction();
146 p = (j != nullptr) ? j->getPosition() : Position(0., 0.);
147 }
148 if (GeoConvHelper::getFinal().usingGeoProjection()) {
150 }
151 lon[n] = (float)p.x();
152 lat[n] = (float)p.y();
153 }
154 for (unsigned n = 0; n < nNodes; n++) {
155 const E* u = myNodeToEdge[n];
156 for (const auto& follower : u->getViaSuccessors(SVC_IGNORING)) {
157 const E* to = follower.first;
158 if (to == nullptr || to->getNumericalID() >= (int)myEdgeToNode.size()) {
159 continue;
160 }
161 const unsigned toNode = myEdgeToNode[to->getNumericalID()];
162 if (toNode == INVALID_NODE) {
163 continue; // successor is internal/taz -> not a routable node
164 }
165 myArcOf[std::make_pair(n, toNode)] = (unsigned)myArcTail.size();
166 myArcTail.push_back(n);
167 myArcHead.push_back(toNode);
168 myArcVia.push_back(follower.second); // leading internal edge or nullptr
169 }
170 }
171 myArcPerm.assign(myArcTail.size(), 0);
172 myPrimedClasses = 0;
173 // 2b. reverse image for sparse re-customization: for every arc, the
174 // edges its weight reads at fill time (head edge + folded via chain;
175 // the tail edge is deliberately absent from the weight, see the arc
176 // weight convention above)
177 myEdgeToArcs.resize(myEdgeToNode.size());
178 for (unsigned a = 0; a < (unsigned)myArcHead.size(); a++) {
179 myEdgeToArcs[myNodeToEdge[myArcHead[a]]->getNumericalID()].push_back(a);
180 const E* via = myArcVia[a];
181 while (via != nullptr && via->isInternal()) {
182 if (via->getNumericalID() >= 0 && via->getNumericalID() < (int)myEdgeToArcs.size()) {
183 myEdgeToArcs[via->getNumericalID()].push_back(a);
184 }
185 const auto& vs = via->getViaSuccessors();
186 via = vs.empty() ? nullptr : vs.front().second;
187 }
188 }
189
190 // 3. TAZ member sets (query-time "phantom nodes"): successors for a
191 // source connector (entry edges), predecessors for a sink connector.
192 for (const E* e : allEdges) {
193 if (!isStarConnector(e)) {
194 continue;
195 }
196 std::vector<unsigned> srcNodes;
197 for (const auto& follower : e->getViaSuccessors(SVC_IGNORING)) {
198 const unsigned m = nodeOf(follower.first);
199 if (m != INVALID_NODE) {
200 srcNodes.push_back(m);
201 }
202 }
203 std::vector<unsigned> snkNodes;
204 for (const E* pred : e->getPredecessors()) {
205 const unsigned m = nodeOf(pred);
206 if (m != INVALID_NODE) {
207 snkNodes.push_back(m);
208 }
209 }
210 if (!srcNodes.empty()) {
211 myTazSrcNodes[e] = std::move(srcNodes);
212 }
213 if (!snkNodes.empty()) {
214 myTazSnkNodes[e] = std::move(snkNodes);
215 }
216 }
217
218 // 4. metric-independent order + CCH topology (the one-time work).
219 // @todo persist the order keyed by a network hash (recompute is fast)
221 nNodes, myArcTail, myArcHead, lat, lon);
223#ifdef CCH_DEBUG
224 std::cout << "CCH: " << nNodes << " road nodes, "
225 << arcCount() << " arcs, "
226 << myCCH.cch_arc_count() << " cch-arcs (fill x" << (double)myCCH.cch_arc_count() / MAX2((unsigned)1, arcCount())
227 << "), " << myTazSrcNodes.size() << " TAZ sources, " << myTazSnkNodes.size() << " TAZ sinks." << std::endl;
228#endif
229 }
230
231 virtual ~CCHGraph() {}
232
235 return myCCH;
236 }
237
239 unsigned arcCount() const {
240 return (unsigned)myArcTail.size();
241 }
242
245 unsigned edgeIdSpace() const {
246 return (unsigned)myEdgeToNode.size();
247 }
248
250 unsigned nodeOf(const E* e) const {
251 if (e == nullptr || e->getNumericalID() < 0 || e->getNumericalID() >= (int)myEdgeToNode.size()) {
252 return INVALID_NODE;
253 }
254 return myEdgeToNode[e->getNumericalID()];
255 }
256
258 const E* edgeOf(unsigned node) const {
259 return myNodeToEdge[node];
260 }
261
264 const std::vector<unsigned>& tazSources(const E* taz) const {
265 static const std::vector<unsigned> empty;
266 const auto it = myTazSrcNodes.find(taz);
267 return it == myTazSrcNodes.end() ? empty : it->second;
268 }
269
272 const std::vector<unsigned>& tazSinks(const E* taz) const {
273 static const std::vector<unsigned> empty;
274 const auto it = myTazSnkNodes.find(taz);
275 return it == myTazSnkNodes.end() ? empty : it->second;
276 }
277
281 const std::vector<unsigned>& arcsOfEdge(const E* e) const {
282 static const std::vector<unsigned> empty;
283 if (e == nullptr || e->getNumericalID() < 0 || e->getNumericalID() >= (int)myEdgeToArcs.size()) {
284 return empty;
285 }
286 return myEdgeToArcs[e->getNumericalID()];
287 }
288
295 void expandNodePath(const std::vector<unsigned>& nodePath,
296 std::vector<const E*>& into) const {
297 into.reserve(into.size() + nodePath.size());
298 for (unsigned node : nodePath) {
299 into.push_back(myNodeToEdge[node]);
300 }
301 }
302
305 static double viaChainEffort(const E* via, EffortOperation effort,
306 const V* veh, double time) {
307 double sum = 0.;
308 while (via != nullptr && via->isInternal()) {
309 sum += effort(via, veh, time);
310 const auto& vs = via->getViaSuccessors();
311 via = vs.empty() ? nullptr : vs.front().second;
312 }
313 return sum;
314 }
315
316public:
326 unsigned computeArcWeight(unsigned a, EffortOperation effort, SUMOVehicleClass maskClass,
327 const V* veh, double time) const {
328 if (maskClass != SVC_IGNORING
329 && (((myArcPerm[a] & maskClass) == 0)
330 || ((edgeOf(myArcHead[a])->getPermissions() & maskClass) == 0))) {
332 }
333 return computeArcWeightRaw(a, effort, veh, time);
334 }
335
348 const V* veh, double time,
349 std::vector<unsigned>& weight) const {
350 primeClassMask(maskClass);
351 weight.resize(arcCount());
352 for (unsigned a = 0; a < arcCount(); a++) {
353 weight[a] = computeArcWeight(a, effort, maskClass, veh, time);
354 }
355 }
356
365 void invalidateClassMasks() const {
366 myArcPerm.assign(myArcPerm.size(), 0);
367 myPrimedClasses = 0;
368 }
369
370private:
374 static bool isStarConnector(const E* e) {
375 return e->isTazConnector() && e->getOtherTazConnector() != nullptr;
376 }
377
388 void primeClassMask(SUMOVehicleClass vClass) const {
389 if (vClass == SVC_IGNORING || (myPrimedClasses & vClass) == vClass) {
390 return;
391 }
392 for (unsigned n = 0; n < (unsigned)myNodeToEdge.size(); n++) {
393 for (const auto& follower : myNodeToEdge[n]->getViaSuccessors(vClass)) {
394 const unsigned toNode = nodeOf(follower.first);
395 if (toNode == INVALID_NODE) {
396 continue;
397 }
398 const auto it = myArcOf.find(std::make_pair(n, toNode));
399 if (it != myArcOf.end()) {
400 myArcPerm[it->second] |= (SVCPermissions)vClass;
401 }
402 }
403 }
405 }
406
410 unsigned computeArcWeightRaw(unsigned a, EffortOperation effort,
411 const V* veh, double time) const {
412 const E* to = myNodeToEdge[myArcHead[a]];
413 const double bigEffort = (double)(RoutingKit::inf_weight - 1) / 100.0;
414 const double eff = viaChainEffort(myArcVia[a], effort, veh, time)
415 + effort(to, veh, time);
416 if (!(eff < bigEffort)) {
418 }
419 const long long cs = std::llround(eff * 100.0);
420 return (unsigned)(cs < 0 ? 0 : (cs >= (long long)RoutingKit::inf_weight
421 ? RoutingKit::inf_weight - 1 : cs));
422 }
423
425 std::vector<const E*> myNodeToEdge;
427 std::vector<unsigned> myEdgeToNode;
429 std::vector<unsigned> myArcTail;
430 std::vector<unsigned> myArcHead;
432 std::vector<const E*> myArcVia;
434 std::map<std::pair<unsigned, unsigned>, unsigned> myArcOf;
437 mutable std::vector<SVCPermissions> myArcPerm;
442 std::vector<std::vector<unsigned> > myEdgeToArcs;
444 std::map<const E*, std::vector<unsigned> > myTazSrcNodes;
446 std::map<const E*, std::vector<unsigned> > myTazSnkNodes;
449
450private:
451 CCHGraph(const CCHGraph&) = delete;
452 CCHGraph& operator=(const CCHGraph&) = delete;
453};
454
455
456template<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:97
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:245
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:374
std::vector< const E * > myArcVia
per-arc leading via/internal edge (nullptr if none) for path re-expansion
Definition CCHGraph.h:432
SVCPermissions myPrimedClasses
the classes already primed into myArcPerm
Definition CCHGraph.h:439
std::vector< SVCPermissions > myArcPerm
per-arc CONNECTION-level permission bitmask, accumulated per primed class (see primeClassMask); mutab...
Definition CCHGraph.h:437
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:250
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:295
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:272
std::vector< const E * > myNodeToEdge
node index -> backing edge
Definition CCHGraph.h:425
unsigned arcCount() const
number of input arcs (== number of mapped connections)
Definition CCHGraph.h:239
std::vector< unsigned > myArcHead
Definition CCHGraph.h:430
double(* EffortOperation)(const E *const, const V *const, double)
effort callback signature, matching SUMOAbstractRouter::Operation
Definition CCHGraph.h:100
static const unsigned INVALID_NODE
sentinel for "not a routable node"
Definition CCHGraph.h:103
void primeClassMask(SUMOVehicleClass vClass) const
Record which arcs vClass may traverse in the per-arc CONNECTION-level permission bitmask – exactly th...
Definition CCHGraph.h:388
std::vector< unsigned > myArcTail
per-arc endpoints
Definition CCHGraph.h:429
virtual ~CCHGraph()
Definition CCHGraph.h:231
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:347
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:410
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:264
void invalidateClassMasks() const
Drop every primed connection mask so the next fill re-primes from the CURRENT successor lists.
Definition CCHGraph.h:365
std::vector< unsigned > myEdgeToNode
edge numerical id -> node index (INVALID_NODE if not a node)
Definition CCHGraph.h:427
CCHGraph(const std::vector< E * > &allEdges)
Build the union line graph + CCH from the given edges.
Definition CCHGraph.h:112
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:442
const E * edgeOf(unsigned node) const
the edge backing a RoutingKit node
Definition CCHGraph.h:258
const RoutingKit::CustomizableContractionHierarchy & cch() const
the immutable CCH (share const& across clones)
Definition CCHGraph.h:234
std::map< const E *, std::vector< unsigned > > myTazSnkNodes
TAZ-sink connector edge -> its exit-edge road node ids.
Definition CCHGraph.h:446
std::map< std::pair< unsigned, unsigned >, unsigned > myArcOf
(tail node, head node) -> arc index
Definition CCHGraph.h:434
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:281
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:444
RoutingKit::CustomizableContractionHierarchy myCCH
the immutable hierarchy
Definition CCHGraph.h:448
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:326
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:305
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 &){})