Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
eclipse
GitHub Repository: eclipse/sumo
Path: blob/main/src/utils/common/MapMatcher.h
169678 views
1
/****************************************************************************/
2
// Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
3
// Copyright (C) 2001-2025 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
/****************************************************************************/
14
/// @file MapMatcher.h
15
/// @author Jakob Erdmann
16
/// @date Thu, 7 March 2024
17
///
18
// Utility functions for matching locations to edges (during route parsing)
19
/****************************************************************************/
20
#pragma once
21
#include <config.h>
22
23
#include <utils/geom/GeoConvHelper.h>
24
#include <utils/vehicle/SUMOVTypeParameter.h>
25
#include "NamedRTree.h"
26
#include "RandHelper.h"
27
#include "SUMOVehicleClass.h"
28
#include "MsgHandler.h"
29
30
#define JUNCTION_TAZ_MISSING_HELP "\nSet option '--junction-taz' or load a TAZ-file"
31
32
// ===========================================================================
33
// class declarations
34
// ===========================================================================
35
36
// ===========================================================================
37
// class definitions
38
// ===========================================================================
39
/**
40
* @class MapMatcher
41
* @brief Provides utility functions for matching locations to edges (during route parsing)
42
*/
43
44
template<class E, class L, class N>
45
class MapMatcher {
46
47
public:
48
void parseGeoEdges(const PositionVector& positions, bool geo, SUMOVehicleClass vClass,
49
std::vector<const E*>& into, const std::string& rid, bool isFrom, bool& ok, bool forceEdge = false) {
50
if (geo && !GeoConvHelper::getFinal().usingGeoProjection()) {
51
WRITE_ERROR(TL("Cannot convert geo-positions because the network has no geo-reference"));
52
ok = false;
53
return;
54
}
55
for (Position pos : positions) {
56
Position orig = pos;
57
if (geo) {
58
GeoConvHelper::getFinal().x2cartesian_const(pos);
59
}
60
double dist = MIN2(10.0, myMapMatchingDistance);
61
const L* best = getClosestLane(pos, vClass, dist);
62
while (best == nullptr && dist < myMapMatchingDistance) {
63
dist = MIN2(dist * 2, myMapMatchingDistance);
64
best = getClosestLane(pos, vClass, dist);
65
}
66
if (best == nullptr) {
67
myErrorOutput->inform("No edge found near position " + toString(orig, geo ? gPrecisionGeo : gPrecision) + " within the route " + rid + ".");
68
ok = false;
69
} else {
70
const E* bestEdge = &best->getEdge();
71
while (bestEdge->isInternal()) {
72
bestEdge = bestEdge->getSuccessors().front();
73
}
74
if ((myMapMatchJunctions || myMapMatchTAZ) && !forceEdge) {
75
if (myMapMatchTAZ) {
76
bestEdge = getTaz(pos, bestEdge, isFrom);
77
} else {
78
bestEdge = getJunctionTaz(pos, bestEdge, vClass, isFrom);
79
}
80
if (bestEdge != nullptr) {
81
into.push_back(bestEdge);
82
} else {
83
ok = false;
84
}
85
} else {
86
// handle multiple via locations on the same edge without loops
87
if (positions.size() == 1 || into.empty() || into.back() != bestEdge) {
88
into.push_back(bestEdge);
89
}
90
}
91
}
92
}
93
}
94
95
96
97
protected:
98
MapMatcher(bool matchJunctions, bool matchTAZ, double matchDistance, MsgHandler* errorOutput):
99
myMapMatchTAZ(matchTAZ),
100
myLaneTree(nullptr),
101
myMapMatchJunctions(matchJunctions),
102
myMapMatchingDistance(matchDistance),
103
myErrorOutput(errorOutput) {}
104
105
virtual ~MapMatcher() {
106
delete myLaneTree;
107
}
108
109
/// @brief find closest lane within distance for the given position or nullptr
110
const L* getClosestLane(const Position& pos, SUMOVehicleClass vClass, double distance = -1.) {
111
NamedRTree* t = getLaneTree();
112
Boundary b;
113
b.add(pos);
114
b.grow(distance < 0 ? myMapMatchingDistance : distance);
115
const float cmin[2] = {(float) b.xmin(), (float) b.ymin()};
116
const float cmax[2] = {(float) b.xmax(), (float) b.ymax()};
117
std::set<const Named*> lanes;
118
Named::StoringVisitor sv(lanes);
119
t->Search(cmin, cmax, sv);
120
// use closest
121
double minDist = std::numeric_limits<double>::max();
122
const L* best = nullptr;
123
for (const Named* o : lanes) {
124
const L* cand = static_cast<const L*>(o);
125
if (!cand->allowsVehicleClass(vClass)) {
126
continue;
127
}
128
double dist = cand->getShape().distance2D(pos);
129
if (dist < minDist) {
130
minDist = dist;
131
best = cand;
132
}
133
}
134
return best;
135
}
136
137
/// @brief find closest junction taz given the closest edge
138
const E* getJunctionTaz(const Position& pos, const E* closestEdge, SUMOVehicleClass vClass, bool isFrom) {
139
if (closestEdge == nullptr) {
140
return nullptr;
141
} else {
142
const N* fromJunction = closestEdge->getFromJunction();
143
const N* toJunction = closestEdge->getToJunction();
144
const bool fromCloser = (fromJunction->getPosition().distanceSquaredTo2D(pos) <
145
toJunction->getPosition().distanceSquaredTo2D(pos));
146
const E* fromSource = retrieveEdge(fromJunction->getID() + "-source");
147
const E* fromSink = retrieveEdge(fromJunction->getID() + "-sink");
148
const E* toSource = retrieveEdge(toJunction->getID() + "-source");
149
const E* toSink = retrieveEdge(toJunction->getID() + "-sink");
150
if (fromSource == nullptr || fromSink == nullptr) {
151
myErrorOutput->inform("Junction-taz '" + fromJunction->getID() + "' not found when mapping position " + toString(pos) + "." + JUNCTION_TAZ_MISSING_HELP);
152
return nullptr;
153
}
154
if (toSource == nullptr || toSink == nullptr) {
155
myErrorOutput->inform("Junction-taz '" + toJunction->getID() + "' not found when mapping position " + toString(pos) + "." + JUNCTION_TAZ_MISSING_HELP);
156
return nullptr;
157
}
158
const bool fromPossible = isFrom ? fromSource->getSuccessors(vClass).size() > 0 : fromSink->getPredecessors().size() > 0;
159
const bool toPossible = isFrom ? toSource->getSuccessors(vClass).size() > 0 : toSink->getPredecessors().size() > 0;
160
//std::cout << "getJunctionTaz pos=" << pos << " isFrom=" << isFrom << " closest=" << closestEdge->getID() << " fromPossible=" << fromPossible << " toPossible=" << toPossible << "\n";
161
if (fromCloser && fromPossible) {
162
// return closest if possible
163
return isFrom ? fromSource : fromSink;
164
} else if (!fromCloser && toPossible) {
165
// return closest if possible
166
return isFrom ? toSource : toSink;
167
} else {
168
// return possible
169
if (fromPossible) {
170
return isFrom ? fromSource : fromSink;
171
} else {
172
return isFrom ? toSource : toSink;
173
}
174
}
175
}
176
}
177
178
/// @brief find closest junction taz given the closest edge
179
const E* getTaz(const Position& pos, const E* closestEdge, bool isFrom) {
180
if (closestEdge == nullptr) {
181
return nullptr;
182
} else {
183
std::vector<const E*> cands;
184
if (isFrom) {
185
for (const E* e : closestEdge->getPredecessors()) {
186
if (e->isTazConnector()) {
187
cands.push_back(e);
188
}
189
}
190
} else {
191
for (const E* e : closestEdge->getSuccessors()) {
192
if (e->isTazConnector()) {
193
cands.push_back(e);
194
}
195
}
196
}
197
if (cands.size() == 0) {
198
myErrorOutput->inform("Taz for edge '" + closestEdge->getID() + "' not found when mapping position " + toString(pos) + "." + JUNCTION_TAZ_MISSING_HELP);
199
return nullptr;
200
}
201
if (cands.size() > 1) {
202
return cands[RandHelper::rand((int)cands.size(), getRNG())];
203
} else {
204
return cands.front();
205
}
206
}
207
}
208
209
virtual SumoRNG* getRNG() {
210
return nullptr;
211
}
212
213
virtual void initLaneTree(NamedRTree* tree) = 0;
214
215
virtual E* retrieveEdge(const std::string& id) = 0;
216
217
bool myMapMatchTAZ;
218
219
private:
220
/// @brief initialize lane-RTree
221
NamedRTree* getLaneTree() {
222
if (myLaneTree == nullptr) {
223
myLaneTree = new NamedRTree();
224
initLaneTree(myLaneTree);
225
}
226
return myLaneTree;
227
}
228
229
/// @brief RTree for finding lanes
230
NamedRTree* myLaneTree;
231
bool myMapMatchJunctions;
232
double myMapMatchingDistance;
233
MsgHandler* myErrorOutput;
234
235
236
private:
237
/// @brief Invalidated copy constructor
238
MapMatcher(const MapMatcher& s) = delete;
239
240
/// @brief Invalidated assignment operator
241
MapMatcher& operator=(const MapMatcher& s) = delete;
242
};
243
244