Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
eclipse
GitHub Repository: eclipse/sumo
Path: blob/main/src/netgen/NGNet.cpp
169665 views
1
/****************************************************************************/
2
// Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
3
// Copyright (C) 2003-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 NGNet.cpp
15
/// @author Markus Hartinger
16
/// @author Daniel Krajzewicz
17
/// @author Michael Behrisch
18
/// @author Jakob Erdmann
19
/// @date Mar, 2003
20
///
21
// The class storing the generated network
22
/****************************************************************************/
23
#include <config.h>
24
25
#include <iostream>
26
#include <stdlib.h>
27
#include <stdio.h>
28
#include <string.h>
29
#include <cmath>
30
#include <netbuild/NBNode.h>
31
#include <netbuild/NBNodeCont.h>
32
#include <netbuild/NBEdge.h>
33
#include <netbuild/NBEdgeCont.h>
34
#include <netbuild/NBNetBuilder.h>
35
#include <utils/common/ToString.h>
36
#include <utils/common/RandHelper.h>
37
#include <utils/common/StringUtils.h>
38
#include <utils/options/OptionsCont.h>
39
#include <utils/distribution/Distribution_Parameterized.h>
40
#include "NGNet.h"
41
42
43
// ===========================================================================
44
// method definitions
45
// ===========================================================================
46
NGNet::NGNet(NBNetBuilder& nb) :
47
myLastID(0),
48
myAlphaIDs(OptionsCont::getOptions().getBool("alphanumerical-ids")),
49
myNetBuilder(nb) {
50
}
51
52
53
NGNet::~NGNet() {
54
for (NGEdgeList::iterator ni = myEdgeList.begin(); ni != myEdgeList.end(); ++ni) {
55
delete *ni;
56
}
57
for (NGNodeList::iterator ni = myNodeList.begin(); ni != myNodeList.end(); ++ni) {
58
delete *ni;
59
}
60
}
61
62
63
std::string
64
NGNet::getNextFreeID() {
65
return toString<int>(++myLastID);
66
}
67
68
69
NGNode*
70
NGNet::findNode(int xID, int yID) {
71
for (NGNodeList::iterator ni = myNodeList.begin(); ni != myNodeList.end(); ++ni) {
72
if ((*ni)->samePos(xID, yID)) {
73
return *ni;
74
}
75
}
76
return nullptr;
77
}
78
79
std::string
80
NGNet::alphabeticalCode(int i, int iMax) {
81
// lazy mans 26th root to determine number of characters for x-label
82
int xn = 1;
83
for (; std::pow(26, xn) < iMax; xn++) {};
84
std::string result = "";
85
for (int j = 0; j < xn; j++) {
86
result = char('A' + (i % 26)) + result;
87
i /= 26;
88
}
89
return result;
90
}
91
92
void
93
NGNet::createChequerBoard(int numX, int numY, double spaceX, double spaceY, double xAttachLength, double yAttachLength) {
94
95
for (int ix = 0; ix < numX; ix++) {
96
const std::string nodeIDStart = (myAlphaIDs ? alphabeticalCode(ix, numX) : toString<int>(ix) + "/");
97
for (int iy = 0; iy < numY; iy++) {
98
// create Node
99
NGNode* node = new NGNode(nodeIDStart + toString(iy), ix, iy);
100
node->setX(ix * spaceX + xAttachLength);
101
node->setY(iy * spaceY + yAttachLength);
102
myNodeList.push_back(node);
103
// create Links
104
if (ix > 0) {
105
connect(findNode(ix - 1, iy), node);
106
}
107
if (iy > 0) {
108
connect(findNode(ix, iy - 1), node);
109
}
110
}
111
}
112
if (yAttachLength > 0.0) {
113
for (int ix = 0; ix < numX; ix++) {
114
// create nodes
115
NGNode* topNode = new NGNode("top" + toString<int>(ix), ix, numY);
116
NGNode* bottomNode = new NGNode("bottom" + toString<int>(ix), ix, numY + 1);
117
topNode->setX(ix * spaceX + xAttachLength);
118
bottomNode->setX(ix * spaceX + xAttachLength);
119
topNode->setY((numY - 1) * spaceY + 2 * yAttachLength);
120
bottomNode->setY(0);
121
topNode->setFringe();
122
bottomNode->setFringe();
123
myNodeList.push_back(topNode);
124
myNodeList.push_back(bottomNode);
125
// create links
126
connect(findNode(ix, numY - 1), topNode);
127
connect(bottomNode, findNode(ix, 0));
128
}
129
}
130
if (xAttachLength > 0.0) {
131
for (int iy = 0; iy < numY; iy++) {
132
// create nodes
133
NGNode* leftNode = new NGNode("left" + toString<int>(iy), numX, iy);
134
NGNode* rightNode = new NGNode("right" + toString<int>(iy), numX + 1, iy);
135
leftNode->setX(0);
136
rightNode->setX((numX - 1) * spaceX + 2 * xAttachLength);
137
leftNode->setY(iy * spaceY + yAttachLength);
138
rightNode->setY(iy * spaceY + yAttachLength);
139
leftNode->setFringe();
140
rightNode->setFringe();
141
myNodeList.push_back(leftNode);
142
myNodeList.push_back(rightNode);
143
// create links
144
connect(leftNode, findNode(0, iy));
145
connect(findNode(numX - 1, iy), rightNode);
146
}
147
}
148
}
149
150
151
double
152
NGNet::radialToX(double radius, double phi) {
153
return cos(phi) * radius;
154
}
155
156
157
double
158
NGNet::radialToY(double radius, double phi) {
159
return sin(phi) * radius;
160
}
161
162
163
void
164
NGNet::createSpiderWeb(int numRadDiv, int numCircles, double spaceRad, bool hasCenter, double attachLength) {
165
if (numRadDiv < 3) {
166
numRadDiv = 3;
167
}
168
if (numCircles < 1) {
169
numCircles = 1;
170
}
171
172
int ir, ic;
173
double angle = (double)(2 * M_PI / numRadDiv); // angle between radial divisions
174
NGNode* node;
175
int attachCircle = -1;
176
if (attachLength > 0) {
177
numCircles += 1;
178
attachCircle = numCircles;
179
}
180
for (ic = 1; ic < numCircles + 1; ic++) {
181
const std::string nodeIDStart = alphabeticalCode(ic, numCircles);
182
if (ic == attachCircle) {
183
spaceRad = attachLength;
184
}
185
for (ir = 1; ir < numRadDiv + 1; ir++) {
186
// create Node
187
const std::string nodeID = (myAlphaIDs ?
188
nodeIDStart + toString<int>(ir) :
189
toString<int>(ir) + "/" + toString<int>(ic));
190
node = new NGNode(nodeID, ir, ic);
191
node->setX(radialToX((ic) * spaceRad, (ir - 1) * angle));
192
node->setY(radialToY((ic) * spaceRad, (ir - 1) * angle));
193
myNodeList.push_back(node);
194
// create Links
195
if (ir > 1 && ic != attachCircle) {
196
connect(findNode(ir - 1, ic), node);
197
}
198
if (ic > 1) {
199
connect(findNode(ir, ic - 1), node);
200
}
201
if (ir == numRadDiv && ic != attachCircle) {
202
connect(node, findNode(1, ic));
203
}
204
}
205
}
206
if (hasCenter) {
207
// node
208
node = new NGNode(myAlphaIDs ? "A1" : "1", 0, 0, true);
209
node->setX(0);
210
node->setY(0);
211
myNodeList.push_back(node);
212
// links
213
for (ir = 1; ir < numRadDiv + 1; ir++) {
214
connect(node, findNode(ir, 1));
215
}
216
}
217
}
218
219
220
void
221
NGNet::connect(NGNode* node1, NGNode* node2) {
222
std::string id1 = node1->getID() + (myAlphaIDs ? "" : "to") + node2->getID();
223
std::string id2 = node2->getID() + (myAlphaIDs ? "" : "to") + node1->getID();
224
NGEdge* link1 = new NGEdge(id1, node1, node2, id2);
225
myEdgeList.push_back(link1);
226
}
227
228
Distribution_Parameterized
229
NGNet::getDistribution(const std::string& option) {
230
const std::string& val = OptionsCont::getOptions().getString(option);
231
try {
232
return Distribution_Parameterized(option, 0, StringUtils::toDouble(val));
233
} catch (NumberFormatException&) {
234
return Distribution_Parameterized(val);
235
}
236
}
237
238
239
void
240
NGNet::toNB() const {
241
Distribution_Parameterized perturbx = getDistribution("perturb-x");
242
Distribution_Parameterized perturby = getDistribution("perturb-y");
243
Distribution_Parameterized perturbz = getDistribution("perturb-z");
244
for (const NGNode* const ngNode : myNodeList) {
245
// we need to sample in separate instructions because evaluation order is compiler dependent
246
Position perturb(perturbx.sample(), 0.);
247
perturb.sety(perturby.sample());
248
perturb.setz(perturbz.sample());
249
myNetBuilder.getNodeCont().insert(ngNode->buildNBNode(myNetBuilder, perturb));
250
}
251
const std::string type = OptionsCont::getOptions().getString("default.type");
252
const double bidiProb = OptionsCont::getOptions().getFloat("bidi-probability");
253
for (const NGEdge* const ngEdge : myEdgeList) {
254
myNetBuilder.getEdgeCont().insert(ngEdge->buildNBEdge(myNetBuilder, type));
255
// now, let's append the reverse directions...
256
if (!ngEdge->getEndNode()->connected(ngEdge->getStartNode(), true) && RandHelper::rand() <= bidiProb) {
257
myNetBuilder.getEdgeCont().insert(ngEdge->buildNBEdge(myNetBuilder, type, true));
258
}
259
}
260
// add splits depending on turn-lane options
261
const int turnLanes = OptionsCont::getOptions().getInt("turn-lanes");
262
const bool lefthand = OptionsCont::getOptions().getBool("lefthand");
263
if (turnLanes > 0) {
264
const double turnLaneLength = OptionsCont::getOptions().getFloat("turn-lanes.length");
265
NBEdgeCont& ec = myNetBuilder.getEdgeCont();
266
EdgeVector allEdges;
267
for (auto it = ec.begin(); it != ec.end(); ++it) {
268
allEdges.push_back(it->second);
269
}
270
for (NBEdge* e : allEdges) {
271
if (e->getToNode()->geometryLike()) {
272
continue;
273
}
274
std::vector<NBEdgeCont::Split> splits;
275
NBEdgeCont::Split split;
276
for (int i = 0; i < e->getNumLanes() + turnLanes; ++i) {
277
split.lanes.push_back(i);
278
}
279
split.pos = MAX2(0.0, e->getLength() - turnLaneLength);
280
split.speed = e->getSpeed();
281
split.node = new NBNode(e->getID() + "." + toString(split.pos), e->getGeometry().positionAtOffset(split.pos));
282
split.idBefore = e->getID();
283
split.idAfter = split.node->getID();
284
split.offsetFactor = lefthand ? -1 : 1;
285
if (turnLaneLength <= e->getLength() / 2) {
286
split.offset = -0.5 * split.offsetFactor * turnLanes * e->getLaneWidth(0);
287
if (e->getFromNode()->geometryLike()) {
288
// shift the reverse direction explicitly as it will not get a turn lane
289
NBEdge* reverse = nullptr;
290
for (NBEdge* reverseCand : e->getFromNode()->getIncomingEdges()) {
291
if (reverseCand->getFromNode() == e->getToNode()) {
292
reverse = reverseCand;
293
}
294
}
295
if (reverse != nullptr) {
296
PositionVector g = reverse->getGeometry();
297
g.move2side(-split.offset);
298
reverse->setGeometry(g);
299
}
300
}
301
}
302
splits.push_back(split);
303
ec.processSplits(e, splits,
304
myNetBuilder.getNodeCont(),
305
myNetBuilder.getDistrictCont(),
306
myNetBuilder.getTLLogicCont());
307
}
308
}
309
}
310
311
312
void
313
NGNet::add(NGNode* node) {
314
myNodeList.push_back(node);
315
}
316
317
318
void
319
NGNet::add(NGEdge* edge) {
320
myEdgeList.push_back(edge);
321
}
322
323
324
int
325
NGNet::nodeNo() const {
326
return (int)myNodeList.size();
327
}
328
329
330
/****************************************************************************/
331
332