Line data Source code
1 : /****************************************************************************/
2 : // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
3 : // Copyright (C) 2001-2024 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 NBNetBuilder.cpp
15 : /// @author Daniel Krajzewicz
16 : /// @author Jakob Erdmann
17 : /// @author Thimor Bohn
18 : /// @author Sascha Krieg
19 : /// @author Michael Behrisch
20 : /// @author Walter Bamberger
21 : /// @date 20 Nov 2001
22 : ///
23 : // Instance responsible for building networks
24 : /****************************************************************************/
25 : #include <config.h>
26 :
27 : #include <string>
28 : #include <fstream>
29 : #include <utils/options/OptionsCont.h>
30 : #include <utils/common/MsgHandler.h>
31 : #include <utils/common/UtilExceptions.h>
32 : #include <utils/common/StringTokenizer.h>
33 : #include <utils/common/SUMOVehicleClass.h>
34 : #include <utils/common/SysUtils.h>
35 : #include <utils/common/ToString.h>
36 : #include <utils/geom/GeoConvHelper.h>
37 : #include "NBAlgorithms.h"
38 : #include "NBAlgorithms_Ramps.h"
39 : #include "NBAlgorithms_Railway.h"
40 : #include "NBHeightMapper.h"
41 : #include "NBNodeCont.h"
42 : #include "NBEdgeCont.h"
43 : #include "NBPTStop.h"
44 : #include "NBTrafficLightLogicCont.h"
45 : #include "NBDistrictCont.h"
46 : #include "NBDistrict.h"
47 : #include "NBRequest.h"
48 : #include "NBTypeCont.h"
49 : #include "NBNetBuilder.h"
50 :
51 :
52 : // ===========================================================================
53 : // method definitions
54 : // ===========================================================================
55 2337 : NBNetBuilder::NBNetBuilder() :
56 2337 : myEdgeCont(myTypeCont),
57 4674 : myNetworkHaveCrossings(false) {
58 2337 : }
59 :
60 :
61 4674 : NBNetBuilder::~NBNetBuilder() {}
62 :
63 :
64 : void
65 2337 : NBNetBuilder::applyOptions(OptionsCont& oc) {
66 : // apply options to type control
67 14022 : myTypeCont.setEdgeTypeDefaults(oc.getInt("default.lanenumber"), oc.getFloat("default.lanewidth"), oc.getFloat("default.speed"), oc.getFloat("default.friction"),
68 7013 : oc.getInt("default.priority"), parseVehicleClasses(oc.getString("default.allow"), oc.getString("default.disallow")),
69 4674 : SUMOXMLDefinitions::LaneSpreadFunctions.get(oc.getString("default.spreadtype")));
70 : // apply options to edge control
71 2337 : myEdgeCont.applyOptions(oc);
72 : // apply options to traffic light logics control
73 2327 : myTLLCont.applyOptions(oc);
74 2327 : NBEdge::setDefaultConnectionLength(oc.getFloat("default.connection-length"));
75 2327 : }
76 :
77 :
78 : void
79 1837 : NBNetBuilder::compute(OptionsCont& oc, const std::set<std::string>& explicitTurnarounds, bool mayAddOrRemove) {
80 : // reset shapes and angles for stable netedit computation
81 1837 : if (myNodeCont.resetNodeShapes()) {
82 0 : myEdgeCont.computeAngles();
83 : }
84 :
85 : GeoConvHelper& geoConvHelper = GeoConvHelper::getProcessing();
86 :
87 1837 : const bool lefthand = oc.getBool("lefthand");
88 1837 : if (lefthand) {
89 23 : mirrorX();
90 : }
91 :
92 : // MODIFYING THE SETS OF NODES AND EDGES
93 : // Removes edges that are connecting the same node
94 3674 : long before = PROGRESS_BEGIN_TIME_MESSAGE(TL("Removing self-loops"));
95 1837 : myNodeCont.removeSelfLoops(myDistrictCont, myEdgeCont, myTLLCont);
96 1837 : PROGRESS_TIME_MESSAGE(before);
97 7162 : if (mayAddOrRemove && oc.exists("remove-edges.isolated") && oc.getBool("remove-edges.isolated")) {
98 8 : before = PROGRESS_BEGIN_TIME_MESSAGE(TL("Finding isolated roads"));
99 4 : myNodeCont.removeIsolatedRoads(myDistrictCont, myEdgeCont);
100 4 : PROGRESS_TIME_MESSAGE(before);
101 : }
102 7143 : if (mayAddOrRemove && oc.exists("keep-edges.components") && oc.getInt("keep-edges.components") > 0) {
103 46 : before = PROGRESS_BEGIN_TIME_MESSAGE(TL("Finding largest components"));
104 46 : const bool hasStops = oc.exists("ptstop-output") && oc.isSet("ptstop-output") && !myPTStopCont.getStops().empty();
105 23 : myNodeCont.removeComponents(myDistrictCont, myEdgeCont, oc.getInt("keep-edges.components"), hasStops);
106 23 : PROGRESS_TIME_MESSAGE(before);
107 : }
108 7162 : if (mayAddOrRemove && oc.exists("keep-edges.postload") && oc.getBool("keep-edges.postload")) {
109 : // pre-process lines to set permissions
110 4 : if (!myPTLineCont.getLines().empty()) {
111 2 : before = PROGRESS_BEGIN_TIME_MESSAGE(TL("Revising public transport stops based on pt lines"));
112 1 : myPTLineCont.process(myEdgeCont, myPTStopCont);
113 1 : PROGRESS_TIME_MESSAGE(before);
114 : }
115 12 : if (oc.isSet("keep-edges.explicit") || oc.isSet("keep-edges.input-file")) {
116 4 : before = PROGRESS_BEGIN_TIME_MESSAGE(TL("Removing unwished edges"));
117 2 : myEdgeCont.removeUnwishedEdges(myDistrictCont);
118 2 : PROGRESS_TIME_MESSAGE(before);
119 : }
120 4 : const int removed = myEdgeCont.removeEdgesBySpeed(myDistrictCont);
121 4 : if (removed > 0) {
122 0 : WRITE_MESSAGEF(TL(" Removed % edges because by minimum speed."), removed);
123 : }
124 4 : const int removed2 = myEdgeCont.removeEdgesByPermissions(myDistrictCont);
125 4 : if (removed2 > 0) {
126 2 : WRITE_MESSAGEF(TL(" Removed % edges based on vClass."), removed2);
127 : }
128 : }
129 : // Processing pt stops and lines
130 1837 : if (!myPTStopCont.getStops().empty()) {
131 306 : before = PROGRESS_BEGIN_TIME_MESSAGE(TL("Processing public transport stops"));
132 459 : if (!(oc.exists("ptline-output") && oc.isSet("ptline-output"))
133 414 : && !oc.getBool("ptstop-output.no-bidi")) {
134 106 : myPTStopCont.localizePTStops(myEdgeCont);
135 : }
136 153 : myPTStopCont.assignEdgeForFloatingStops(myEdgeCont, 20);
137 153 : myPTStopCont.assignLanes(myEdgeCont);
138 153 : PROGRESS_TIME_MESSAGE(before);
139 : }
140 7143 : if (mayAddOrRemove && oc.exists("keep-edges.components") && oc.getInt("keep-edges.components") > 0) {
141 : // post process rail components unless they have stops
142 23 : myNodeCont.removeRailComponents(myDistrictCont, myEdgeCont, myPTStopCont);
143 : }
144 :
145 1837 : if (!myPTLineCont.getLines().empty()) {
146 204 : before = PROGRESS_BEGIN_TIME_MESSAGE(TL("Revising public transport stops based on pt lines"));
147 102 : myPTLineCont.process(myEdgeCont, myPTStopCont);
148 102 : PROGRESS_TIME_MESSAGE(before);
149 : }
150 :
151 5327 : if (oc.exists("ptline-clean-up") && oc.getBool("ptline-clean-up")) {
152 4 : before = PROGRESS_BEGIN_TIME_MESSAGE(TL("Cleaning up public transport stops that are not served by any line"));
153 2 : myPTStopCont.postprocess(myPTLineCont.getServedPTStops());
154 2 : PROGRESS_TIME_MESSAGE(before);
155 : } else {
156 1835 : int numDeletedStops = myPTStopCont.cleanupDeleted(myEdgeCont);
157 1835 : if (numDeletedStops > 0) {
158 48 : WRITE_WARNINGF(TL("Removed % pt stops because they could not be assigned to the network"), toString(numDeletedStops));
159 : }
160 : }
161 :
162 1979 : if (!myPTStopCont.getStops().empty() && !oc.getBool("ptstop-output.no-bidi")) {
163 276 : before = PROGRESS_BEGIN_TIME_MESSAGE(TL("Align pt stop id signs with corresponding edge id signs"));
164 138 : myPTStopCont.alignIdSigns();
165 138 : PROGRESS_TIME_MESSAGE(before);
166 : }
167 : // analyze and fix railway topology
168 : int numAddedBidi = 0;
169 7160 : if (oc.exists("railway.topology.all-bidi") && oc.getBool("railway.topology.all-bidi")) {
170 6 : NBTurningDirectionsComputer::computeTurnDirections(myNodeCont, false);
171 6 : numAddedBidi = NBRailwayTopologyAnalyzer::makeAllBidi(myEdgeCont);
172 7105 : } else if (oc.exists("railway.topology.repair") && oc.getBool("railway.topology.repair")) {
173 : // correct railway angles for angle-based connectivity heuristic
174 74 : myEdgeCont.checkGeometries(0,
175 : oc.getFloat("geometry.min-radius"), false,
176 37 : oc.getBool("geometry.min-radius.fix.railways"), true);
177 37 : NBTurningDirectionsComputer::computeTurnDirections(myNodeCont, false);
178 37 : numAddedBidi = NBRailwayTopologyAnalyzer::repairTopology(myEdgeCont, myPTStopCont, myPTLineCont);
179 : }
180 1837 : NBRailwaySignalGuesser::guessRailSignals(myEdgeCont, myPTStopCont);
181 1837 : if (numAddedBidi > 0) {
182 : // update routes
183 38 : myPTLineCont.process(myEdgeCont, myPTStopCont, true);
184 : }
185 7165 : if (oc.exists("railway.topology.direction-priority") && oc.getBool("railway.topology.direction-priority")) {
186 1 : NBTurningDirectionsComputer::computeTurnDirections(myNodeCont, false); // recompute after new edges were added
187 1 : NBRailwayTopologyAnalyzer::extendDirectionPriority(myEdgeCont, true);
188 7159 : } else if (oc.exists("railway.topology.extend-priority") && oc.getBool("railway.topology.extend-priority")) {
189 3 : NBTurningDirectionsComputer::computeTurnDirections(myNodeCont, false); // recompute after new edges were added
190 3 : NBRailwayTopologyAnalyzer::extendDirectionPriority(myEdgeCont, false);
191 : }
192 7137 : if (oc.exists("railway.topology.output") && oc.isSet("railway.topology.output")) {
193 29 : NBTurningDirectionsComputer::computeTurnDirections(myNodeCont, false); // recompute after new edges were added
194 29 : NBRailwayTopologyAnalyzer::analyzeTopology(myEdgeCont);
195 : }
196 :
197 :
198 7160 : if (mayAddOrRemove && oc.exists("edges.join-tram-dist") && oc.getFloat("edges.join-tram-dist") >= 0) {
199 : // should come before joining junctions
200 12 : before = PROGRESS_BEGIN_TIME_MESSAGE(TL("Joining tram edges"));
201 6 : int numJoinedTramEdges = myEdgeCont.joinTramEdges(myDistrictCont, myPTStopCont, myPTLineCont, oc.getFloat("edges.join-tram-dist"));
202 6 : PROGRESS_TIME_MESSAGE(before);
203 6 : if (numJoinedTramEdges > 0) {
204 12 : WRITE_MESSAGEF(TL(" Joined % tram edges into roads."), toString(numJoinedTramEdges));
205 : }
206 : }
207 3674 : if (oc.getBool("junctions.join")
208 5293 : || (oc.exists("ramps.guess") && oc.getBool("ramps.guess"))
209 3535 : || oc.getBool("tls.guess.joining")
210 6868 : || (oc.exists("tls.guess-signals") && oc.getBool("tls.guess-signals"))) {
211 : // preliminary geometry computations to determine the length of edges
212 : // This depends on turning directions and sorting of edge list
213 : // in case junctions are joined geometry computations have to be repeated
214 : // preliminary roundabout computations to avoid damaging roundabouts via junctions.join or ramps.guess
215 149 : NBTurningDirectionsComputer::computeTurnDirections(myNodeCont, false);
216 149 : NBNodesEdgesSorter::sortNodesEdges(myNodeCont);
217 149 : myEdgeCont.computeLaneShapes();
218 149 : myNodeCont.computeNodeShapes();
219 149 : myEdgeCont.computeEdgeShapes();
220 298 : if (oc.getBool("roundabouts.guess")) {
221 149 : myEdgeCont.guessRoundabouts();
222 : }
223 149 : const std::set<EdgeSet>& roundabouts = myEdgeCont.getRoundabouts();
224 149 : for (std::set<EdgeSet>::const_iterator it_round = roundabouts.begin();
225 163 : it_round != roundabouts.end(); ++it_round) {
226 : std::vector<std::string> nodeIDs;
227 111 : for (EdgeSet::const_iterator it_edge = it_round->begin(); it_edge != it_round->end(); ++it_edge) {
228 97 : nodeIDs.push_back((*it_edge)->getToNode()->getID());
229 : }
230 14 : myNodeCont.addJoinExclusion(nodeIDs);
231 14 : }
232 149 : NBNodeTypeComputer::validateRailCrossings(myNodeCont, myTLLCont);
233 1688 : } else if (myEdgeCont.hasGuessedRoundabouts() && oc.getBool("roundabouts.guess")) {
234 0 : myEdgeCont.guessRoundabouts();
235 : }
236 : // join junctions (may create new "geometry"-nodes so it needs to come before removing these
237 7165 : if (mayAddOrRemove && oc.exists("junctions.join-exclude") && oc.isSet("junctions.join-exclude")) {
238 2 : myNodeCont.addJoinExclusion(oc.getStringVector("junctions.join-exclude"));
239 : }
240 1837 : int numJoined = myNodeCont.joinLoadedClusters(myDistrictCont, myEdgeCont, myTLLCont);
241 5402 : if (mayAddOrRemove && oc.getBool("junctions.join")) {
242 218 : before = PROGRESS_BEGIN_TIME_MESSAGE(TL("Joining junction clusters"));
243 109 : numJoined += myNodeCont.joinJunctions(oc.getFloat("junctions.join-dist"), myDistrictCont, myEdgeCont, myTLLCont, myPTStopCont);
244 109 : PROGRESS_TIME_MESSAGE(before);
245 : }
246 1837 : if (numJoined > 0) {
247 194 : WRITE_MESSAGEF(TL(" Joined % junction cluster(s)."), toString(numJoined));
248 : }
249 7338 : if (mayAddOrRemove && oc.exists("junctions.join-same") && oc.getBool("junctions.join-same")) {
250 20 : before = PROGRESS_BEGIN_TIME_MESSAGE(TL("Joining junctions with identical coordinates"));
251 10 : int numJoined2 = myNodeCont.joinSameJunctions(myDistrictCont, myEdgeCont, myTLLCont);
252 10 : PROGRESS_TIME_MESSAGE(before);
253 10 : if (numJoined2 > 0) {
254 6 : WRITE_MESSAGEF(TL(" Joined % junctions."), toString(numJoined2));
255 : }
256 : }
257 : //
258 7165 : if (mayAddOrRemove && oc.exists("join-lanes") && oc.getBool("join-lanes")) {
259 2 : before = PROGRESS_BEGIN_TIME_MESSAGE(TL("Joining lanes"));
260 1 : const int num = myEdgeCont.joinLanes(SVC_IGNORING) + myEdgeCont.joinLanes(SVC_PEDESTRIAN);
261 1 : PROGRESS_TIME_MESSAGE(before);
262 2 : WRITE_MESSAGEF(TL(" Joined lanes on % edges."), toString(num));
263 : }
264 : //
265 1837 : if (mayAddOrRemove) {
266 5404 : const bool removeGeometryNodes = oc.exists("geometry.remove") && oc.getBool("geometry.remove");
267 5404 : before = PROGRESS_BEGIN_TIME_MESSAGE("Removing empty nodes" + std::string(removeGeometryNodes ? " and geometry nodes" : ""));
268 : // removeUnwishedNodes needs turnDirections. @todo: try to call this less often
269 1837 : NBTurningDirectionsComputer::computeTurnDirections(myNodeCont, false);
270 1837 : const int numRemoved = myNodeCont.removeUnwishedNodes(myDistrictCont, myEdgeCont, myTLLCont, myPTStopCont, myPTLineCont, myParkingCont, removeGeometryNodes);
271 1837 : PROGRESS_TIME_MESSAGE(before);
272 3674 : WRITE_MESSAGEF(TL(" % nodes removed."), toString(numRemoved));
273 : }
274 :
275 : // MOVE TO ORIGIN
276 : // compute new boundary after network modifications have taken place
277 1837 : Boundary boundary;
278 73539 : for (std::map<std::string, NBNode*>::const_iterator it = myNodeCont.begin(); it != myNodeCont.end(); ++it) {
279 71702 : boundary.add(it->second->getPosition());
280 : }
281 129862 : for (std::map<std::string, NBEdge*>::const_iterator it = myEdgeCont.begin(); it != myEdgeCont.end(); ++it) {
282 128025 : boundary.add(it->second->getGeometry().getBoxBoundary());
283 : }
284 : geoConvHelper.setConvBoundary(boundary);
285 :
286 6219 : if (!oc.getBool("offset.disable-normalization") && oc.isDefault("offset.x") && oc.isDefault("offset.y")) {
287 1270 : moveToOrigin(geoConvHelper, lefthand);
288 : }
289 1837 : geoConvHelper.computeFinal(lefthand); // information needed for location element fixed at this point
290 :
291 7163 : if (oc.exists("geometry.min-dist") && !oc.isDefault("geometry.min-dist")) {
292 6 : before = PROGRESS_BEGIN_TIME_MESSAGE(TL("Reducing geometries"));
293 3 : myEdgeCont.reduceGeometries(oc.getFloat("geometry.min-dist"));
294 3 : PROGRESS_TIME_MESSAGE(before);
295 : }
296 : // @note: removing geometry can create similar edges so joinSimilarEdges must come afterwards
297 : // @note: likewise splitting can destroy similarities so joinSimilarEdges must come before
298 5492 : if (mayAddOrRemove && oc.getBool("edges.join")) {
299 38 : before = PROGRESS_BEGIN_TIME_MESSAGE(TL("Joining similar edges"));
300 52 : const bool removeDuplicates = oc.exists("junctions.join-same") && oc.getBool("junctions.join-same");
301 19 : myNodeCont.joinSimilarEdges(myDistrictCont, myEdgeCont, myTLLCont, removeDuplicates);
302 : // now we may have new chances to remove geometry if wished
303 56 : if (oc.exists("geometry.remove") && oc.getBool("geometry.remove")) {
304 1 : myNodeCont.removeUnwishedNodes(myDistrictCont, myEdgeCont, myTLLCont, myPTStopCont, myPTLineCont, myParkingCont, true);
305 : }
306 19 : PROGRESS_TIME_MESSAGE(before);
307 : }
308 3674 : if (oc.getBool("opposites.guess")) {
309 26 : PROGRESS_BEGIN_MESSAGE(TL("guessing opposite direction edges"));
310 13 : myEdgeCont.guessOpposites();
311 13 : PROGRESS_DONE_MESSAGE();
312 : }
313 : //
314 7345 : if (mayAddOrRemove && oc.exists("geometry.split") && oc.getBool("geometry.split")) {
315 6 : before = PROGRESS_BEGIN_TIME_MESSAGE(TL("Splitting geometry edges"));
316 3 : myEdgeCont.splitGeometry(myDistrictCont, myNodeCont);
317 : // newly split junctions might also be joinable
318 3 : PROGRESS_TIME_MESSAGE(before);
319 6 : if (oc.getBool("junctions.join-same")) {
320 1 : int numJoined3 = myNodeCont.joinSameJunctions(myDistrictCont, myEdgeCont, myTLLCont);
321 1 : if (numJoined3 > 0) {
322 2 : WRITE_MESSAGEF(TL(" Joined % junctions after splitting geometry."), toString(numJoined3));
323 : }
324 : }
325 : }
326 : // turning direction
327 3674 : before = PROGRESS_BEGIN_TIME_MESSAGE(TL("Computing turning directions"));
328 1837 : NBTurningDirectionsComputer::computeTurnDirections(myNodeCont);
329 1837 : PROGRESS_TIME_MESSAGE(before);
330 : // correct edge geometries to avoid overlap
331 5447 : if (oc.exists("geometry.avoid-overlap") && oc.getBool("geometry.avoid-overlap")) {
332 1719 : myNodeCont.avoidOverlap();
333 : }
334 :
335 : // GUESS TLS POSITIONS
336 3674 : before = PROGRESS_BEGIN_TIME_MESSAGE(TL("Assigning nodes to traffic lights"));
337 3674 : if (oc.isSet("tls.set")) {
338 8 : std::vector<std::string> tlControlledNodes = oc.getStringVector("tls.set");
339 24 : TrafficLightType type = SUMOXMLDefinitions::TrafficLightTypes.get(oc.getString("tls.default-type"));
340 16 : for (std::vector<std::string>::const_iterator i = tlControlledNodes.begin(); i != tlControlledNodes.end(); ++i) {
341 8 : NBNode* node = myNodeCont.retrieve(*i);
342 8 : if (node == nullptr) {
343 0 : WRITE_WARNING("Building a tl-logic for junction '" + *i + "' is not possible." + "\n The junction '" + *i + "' is not known.");
344 : } else {
345 16 : myNodeCont.setAsTLControlled(node, myTLLCont, type);
346 : }
347 : }
348 8 : }
349 1837 : myNodeCont.guessTLs(oc, myTLLCont);
350 1837 : PROGRESS_TIME_MESSAGE(before);
351 :
352 : // guess ramps (after guessing tls because ramps should not be build at traffic lights)
353 3674 : const bool modifyRamps = mayAddOrRemove && (
354 5420 : (oc.exists("ramps.guess") && oc.getBool("ramps.guess"))
355 5316 : || (oc.exists("ramps.set") && oc.isSet("ramps.set")));
356 6974 : if (modifyRamps || (oc.exists("ramps.guess-acceleration-lanes") && oc.getBool("ramps.guess-acceleration-lanes"))) {
357 1746 : before = SysUtils::getCurrentMillis();
358 1746 : if (modifyRamps) {
359 128 : PROGRESS_BEGIN_MESSAGE(TL("Guessing and setting on-/off-ramps"));
360 : }
361 1746 : NBNodesEdgesSorter::sortNodesEdges(myNodeCont);
362 1746 : NBRampsComputer::computeRamps(*this, oc, mayAddOrRemove);
363 1746 : if (modifyRamps) {
364 64 : PROGRESS_TIME_MESSAGE(before);
365 : }
366 : }
367 : // guess bike lanes
368 5507 : if (mayAddOrRemove && ((oc.getBool("bikelanes.guess") || oc.getBool("bikelanes.guess.from-permissions")))) {
369 30 : const int bikelanes = myEdgeCont.guessSpecialLanes(SVC_BICYCLE, oc.getFloat("default.bikelane-width"),
370 : oc.getFloat("bikelanes.guess.min-speed"),
371 : oc.getFloat("bikelanes.guess.max-speed"),
372 12 : oc.getBool("bikelanes.guess.from-permissions"),
373 : "bikelanes.guess.exclude",
374 6 : myTLLCont);
375 12 : WRITE_MESSAGEF(TL("Guessed % bike lanes."), toString(bikelanes));
376 : }
377 :
378 : // guess sidewalks
379 5502 : if (mayAddOrRemove && ((oc.getBool("sidewalks.guess") || oc.getBool("sidewalks.guess.from-permissions")))) {
380 65 : const int sidewalks = myEdgeCont.guessSpecialLanes(SVC_PEDESTRIAN, oc.getFloat("default.sidewalk-width"),
381 : oc.getFloat("sidewalks.guess.min-speed"),
382 : oc.getFloat("sidewalks.guess.max-speed"),
383 26 : oc.getBool("sidewalks.guess.from-permissions"),
384 : "sidewalks.guess.exclude",
385 13 : myTLLCont);
386 26 : WRITE_MESSAGEF(TL("Guessed % sidewalks."), toString(sidewalks));
387 : }
388 : // check whether any not previously setable connections may be set now
389 1837 : myEdgeCont.recheckPostProcessConnections();
390 :
391 : // remap ids if wished
392 1837 : if (mayAddOrRemove) {
393 1837 : int numChangedEdges = myEdgeCont.remapIDs(oc.getBool("numerical-ids"), oc.isSet("reserved-ids"), oc.getString("prefix"), myPTStopCont);
394 1837 : int numChangedNodes = myNodeCont.remapIDs(oc.getBool("numerical-ids"), oc.isSet("reserved-ids"), oc.getString("prefix"), myTLLCont);
395 1837 : if (numChangedEdges + numChangedNodes > 0) {
396 60 : WRITE_MESSAGEF(TL("Remapped % edge IDs and % node IDs."), toString(numChangedEdges), toString(numChangedNodes));
397 : }
398 : }
399 :
400 : //
401 3674 : if (oc.exists("geometry.max-angle")) {
402 3492 : myEdgeCont.checkGeometries(
403 3492 : DEG2RAD(oc.getFloat("geometry.max-angle")),
404 : oc.getFloat("geometry.min-radius"),
405 3492 : oc.getBool("geometry.min-radius.fix"),
406 3492 : oc.getBool("geometry.min-radius.fix.railways"));
407 : }
408 :
409 : // GEOMETRY COMPUTATION
410 : //
411 3674 : before = PROGRESS_BEGIN_TIME_MESSAGE(TL("Sorting nodes' edges"));
412 1837 : NBNodesEdgesSorter::sortNodesEdges(myNodeCont);
413 1837 : PROGRESS_TIME_MESSAGE(before);
414 1837 : myEdgeCont.computeLaneShapes();
415 : //
416 3674 : before = PROGRESS_BEGIN_TIME_MESSAGE(TL("Computing node shapes"));
417 3674 : if (oc.exists("geometry.junction-mismatch-threshold")) {
418 3492 : myNodeCont.computeNodeShapes(oc.getFloat("geometry.junction-mismatch-threshold"));
419 : } else {
420 91 : myNodeCont.computeNodeShapes();
421 : }
422 1837 : PROGRESS_TIME_MESSAGE(before);
423 : //
424 3674 : before = PROGRESS_BEGIN_TIME_MESSAGE(TL("Computing edge shapes"));
425 3117 : myEdgeCont.computeEdgeShapes(oc.getBool("geometry.max-grade.fix") ? oc.getFloat("geometry.max-grade") / 100 : -1);
426 1837 : PROGRESS_TIME_MESSAGE(before);
427 : // resort edges based on the node and edge shapes
428 1837 : NBNodesEdgesSorter::sortNodesEdges(myNodeCont, true);
429 1837 : NBTurningDirectionsComputer::computeTurnDirections(myNodeCont, false);
430 :
431 : // APPLY SPEED MODIFICATIONS
432 3674 : if (oc.exists("speed.offset")) {
433 1746 : const double speedOffset = oc.getFloat("speed.offset");
434 1746 : const double speedFactor = oc.getFloat("speed.factor");
435 1746 : const double speedMin = oc.getFloat("speed.minimum");
436 1746 : if (speedOffset != 0 || speedFactor != 1 || speedMin > 0) {
437 4 : before = PROGRESS_BEGIN_TIME_MESSAGE(TL("Applying speed modifications"));
438 7 : for (const auto& it : myEdgeCont) {
439 5 : NBEdge* const e = it.second;
440 10 : for (int i = 0; i < e->getNumLanes(); i++) {
441 6 : e->setSpeed(i, MAX2(e->getLaneSpeed(i) * speedFactor + speedOffset, speedMin));
442 : }
443 : }
444 2 : PROGRESS_TIME_MESSAGE(before);
445 : }
446 : }
447 :
448 : // CONNECTIONS COMPUTATION
449 : //
450 3674 : before = PROGRESS_BEGIN_TIME_MESSAGE(TL("Computing node types"));
451 1837 : NBNodeTypeComputer::computeNodeTypes(myNodeCont, myTLLCont);
452 1837 : PROGRESS_TIME_MESSAGE(before);
453 : //
454 1837 : myNetworkHaveCrossings = oc.getBool("walkingareas");
455 5454 : if (mayAddOrRemove && oc.getBool("crossings.guess")) {
456 57 : myNetworkHaveCrossings = true;
457 57 : int crossings = 0;
458 5876 : for (std::map<std::string, NBNode*>::const_iterator i = myNodeCont.begin(); i != myNodeCont.end(); ++i) {
459 5819 : crossings += (*i).second->guessCrossings();
460 : }
461 114 : WRITE_MESSAGEF(TL("Guessed % pedestrian crossings."), toString(crossings));
462 : }
463 1837 : if (!myNetworkHaveCrossings) {
464 : bool haveValidCrossings = false;
465 : // recheck whether we had crossings in the input
466 67132 : for (std::map<std::string, NBNode*>::const_iterator i = myNodeCont.begin(); i != myNodeCont.end(); ++i) {
467 130910 : if (i->second->getCrossings().size() > 0) {
468 95 : myNetworkHaveCrossings = true;
469 : haveValidCrossings = true;
470 95 : break;
471 65360 : } else if (i->second->getCrossingsIncludingInvalid().size() > 0) {
472 0 : myNetworkHaveCrossings = true;
473 : }
474 : }
475 1772 : if (myNetworkHaveCrossings && !haveValidCrossings) {
476 : // initial crossings removed or invalidated, keep walkingareas
477 0 : oc.resetWritable();
478 0 : oc.set("walkingareas", "true");
479 : }
480 : }
481 :
482 1837 : if (!mayAddOrRemove && myNetworkHaveCrossings) {
483 : // crossings added via netedit
484 0 : oc.resetWritable();
485 0 : oc.set("no-internal-links", "false");
486 : }
487 :
488 : //
489 3674 : before = PROGRESS_BEGIN_TIME_MESSAGE(TL("Computing priorities"));
490 1837 : NBEdgePriorityComputer::computeEdgePriorities(myNodeCont);
491 1837 : PROGRESS_TIME_MESSAGE(before);
492 : //
493 3674 : before = PROGRESS_BEGIN_TIME_MESSAGE(TL("Computing approached edges"));
494 1837 : myEdgeCont.computeEdge2Edges(oc.getBool("no-left-connections"));
495 1837 : PROGRESS_TIME_MESSAGE(before);
496 : //
497 3674 : if (oc.getBool("roundabouts.guess")) {
498 3568 : before = PROGRESS_BEGIN_TIME_MESSAGE(TL("Guessing and setting roundabouts"));
499 1784 : const int numGuessed = myEdgeCont.guessRoundabouts();
500 1784 : if (numGuessed > 0) {
501 28 : WRITE_MESSAGEF(TL(" Guessed % roundabout(s)."), toString(numGuessed));
502 : }
503 1784 : PROGRESS_TIME_MESSAGE(before);
504 : }
505 1837 : myEdgeCont.markRoundabouts();
506 : //
507 3674 : before = PROGRESS_BEGIN_TIME_MESSAGE(TL("Computing approaching lanes"));
508 1837 : myEdgeCont.computeLanes2Edges();
509 1837 : PROGRESS_TIME_MESSAGE(before);
510 : //
511 3674 : before = PROGRESS_BEGIN_TIME_MESSAGE(TL("Dividing of lanes on approached lanes"));
512 1837 : myNodeCont.computeLanes2Lanes();
513 1837 : myEdgeCont.sortOutgoingLanesConnections();
514 1837 : PROGRESS_TIME_MESSAGE(before);
515 : //
516 3674 : if (oc.getBool("fringe.guess")) {
517 4 : before = PROGRESS_BEGIN_TIME_MESSAGE(TL("Guessing Network fringe"));
518 2 : const int numGuessed = myNodeCont.guessFringe();
519 2 : if (numGuessed > 0) {
520 4 : WRITE_MESSAGEF(TL(" Guessed % fringe nodes."), toString(numGuessed));
521 : }
522 2 : PROGRESS_TIME_MESSAGE(before);
523 : }
524 : //
525 3674 : before = PROGRESS_BEGIN_TIME_MESSAGE(TL("Processing turnarounds"));
526 3674 : if (!oc.getBool("no-turnarounds")) {
527 1038 : myEdgeCont.appendTurnarounds(
528 2076 : oc.getBool("no-turnarounds.tls"),
529 2076 : oc.getBool("no-turnarounds.fringe"),
530 2076 : oc.getBool("no-turnarounds.except-deadend"),
531 2076 : oc.getBool("no-turnarounds.except-turnlane"),
532 2076 : oc.getBool("no-turnarounds.geometry"));
533 : } else {
534 1598 : myEdgeCont.appendTurnarounds(explicitTurnarounds, oc.getBool("no-turnarounds.tls"));
535 : }
536 7292 : if (oc.exists("railway.topology.repair.stop-turn") && oc.getBool("railway.topology.repair.stop-turn")
537 1872 : && myPTStopCont.getStops().size() > 0) {
538 : // allow direction reversal at all bidi-edges with stops
539 27 : myEdgeCont.appendRailwayTurnarounds(myPTStopCont);
540 : }
541 1837 : PROGRESS_TIME_MESSAGE(before);
542 : //
543 3674 : before = PROGRESS_BEGIN_TIME_MESSAGE(TL("Rechecking of lane endings"));
544 1837 : myEdgeCont.recheckLanes();
545 1836 : PROGRESS_TIME_MESSAGE(before);
546 :
547 1998 : if (myNetworkHaveCrossings && !oc.getBool("no-internal-links")) {
548 6658 : for (std::map<std::string, NBNode*>::const_iterator i = myNodeCont.begin(); i != myNodeCont.end(); ++i) {
549 6500 : i->second->buildCrossingsAndWalkingAreas();
550 : }
551 : } else {
552 66988 : for (std::map<std::string, NBNode*>::const_iterator i = myNodeCont.begin(); i != myNodeCont.end(); ++i) {
553 : // needed by netedit if the last crossings was deleted from the network
554 : // and walkingareas have been invalidated since the last call to compute()
555 65310 : i->second->discardWalkingareas();
556 : }
557 3356 : if (oc.getBool("no-internal-links")) {
558 34048 : for (std::map<std::string, NBNode*>::const_iterator i = myNodeCont.begin(); i != myNodeCont.end(); ++i) {
559 33401 : i->second->discardAllCrossings(false);
560 : }
561 : }
562 : }
563 : // join traffic lights (after building connections)
564 3672 : if (oc.getBool("tls.join")) {
565 86 : before = PROGRESS_BEGIN_TIME_MESSAGE(TL("Joining traffic light nodes"));
566 43 : myNodeCont.joinTLS(myTLLCont, oc.getFloat("tls.join-dist"));
567 43 : PROGRESS_TIME_MESSAGE(before);
568 : }
569 :
570 : // COMPUTING RIGHT-OF-WAY AND TRAFFIC LIGHT PROGRAMS
571 : //
572 3672 : before = PROGRESS_BEGIN_TIME_MESSAGE(TL("Computing traffic light control information"));
573 1836 : myTLLCont.setTLControllingInformation(myEdgeCont, myNodeCont);
574 5301 : if (oc.exists("opendrive-files") && oc.isSet("opendrive-files")) {
575 22 : myTLLCont.setOpenDriveSignalParameters();
576 : }
577 1835 : PROGRESS_TIME_MESSAGE(before);
578 : //
579 3670 : before = PROGRESS_BEGIN_TIME_MESSAGE(TL("Computing node logics"));
580 1835 : myNodeCont.computeLogics(myEdgeCont);
581 1835 : PROGRESS_TIME_MESSAGE(before);
582 :
583 : //
584 3670 : before = PROGRESS_BEGIN_TIME_MESSAGE(TL("Computing traffic light logics"));
585 1835 : std::pair<int, int> numbers = myTLLCont.computeLogics(oc);
586 1835 : PROGRESS_TIME_MESSAGE(before);
587 1835 : std::string progCount = "";
588 1835 : if (numbers.first != numbers.second) {
589 18 : progCount = "(" + toString(numbers.second) + " programs) ";
590 : }
591 5505 : WRITE_MESSAGEF(TL(" % traffic light(s) %computed."), toString(numbers.first), progCount);
592 3623 : if (oc.exists("opendrive-files") && oc.isSet("opendrive-files") && oc.getBool("opendrive.signal-groups")) {
593 0 : myTLLCont.applyOpenDriveControllers(oc);
594 : }
595 :
596 129950 : for (std::map<std::string, NBEdge*>::const_iterator i = myEdgeCont.begin(); i != myEdgeCont.end(); ++i) {
597 128115 : (*i).second->sortOutgoingConnectionsByIndex();
598 : }
599 : // FINISHING INNER EDGES
600 : std::set<NBTrafficLightDefinition*> largeNodeTLS;
601 3670 : if (!oc.getBool("no-internal-links")) {
602 2376 : before = PROGRESS_BEGIN_TIME_MESSAGE(TL("Building inner edges"));
603 : // walking areas shall only be built if crossings are wished as well
604 39593 : for (const auto& item : myNodeCont) {
605 38405 : if (item.second->buildInnerEdges() > NBTrafficLightDefinition::MIN_YELLOW_SECONDS) {
606 5943 : const std::set<NBTrafficLightDefinition*>& tlDefs = item.second->getControllingTLS();
607 5943 : largeNodeTLS.insert(tlDefs.begin(), tlDefs.end());
608 : }
609 : }
610 1188 : PROGRESS_TIME_MESSAGE(before);
611 : }
612 : // PATCH NODE SHAPES
613 3670 : if (oc.getFloat("junctions.scurve-stretch") > 0) {
614 : // @note: nodes have collected correction hints in buildInnerEdges()
615 4 : before = PROGRESS_BEGIN_TIME_MESSAGE(TL("stretching junctions to smooth geometries"));
616 2 : myEdgeCont.computeLaneShapes();
617 2 : myNodeCont.computeNodeShapes();
618 5 : myEdgeCont.computeEdgeShapes(oc.getBool("geometry.max-grade.fix") ? oc.getFloat("geometry.max-grade") / 100 : -1);
619 15 : for (const auto& item : myNodeCont) {
620 13 : item.second->buildInnerEdges();
621 : }
622 2 : PROGRESS_TIME_MESSAGE(before);
623 : }
624 2022 : if (myEdgeCont.getNumEdgeSplits() > 0 && !oc.getBool("no-internal-links")) {
625 : // edges with custom lengths were split, this has to take into account
626 : // internal edge lengths (after geometry computation)
627 79 : myEdgeCont.fixSplitCustomLength();
628 : }
629 : // recheck phases for large junctions
630 2764 : for (NBTrafficLightDefinition* def : largeNodeTLS) {
631 929 : myTLLCont.computeSingleLogic(oc, def);
632 : }
633 : // compute lane-to-lane node logics (require traffic lights and inner edges to be done)
634 1835 : myNodeCont.computeLogics2(myEdgeCont, oc);
635 :
636 : // remove guessed traffic lights at junctions without conflicts (requires computeLogics2)
637 1835 : myNodeCont.recheckGuessedTLS(myTLLCont);
638 :
639 : // compute keepClear status (requires computeLogics2)
640 1835 : myNodeCont.computeKeepClear();
641 :
642 : //
643 3670 : if (oc.isSet("street-sign-output")) {
644 2 : before = PROGRESS_BEGIN_TIME_MESSAGE(TL("Generating street signs"));
645 1 : myEdgeCont.generateStreetSigns();
646 1 : PROGRESS_TIME_MESSAGE(before);
647 : }
648 :
649 :
650 3670 : if (lefthand != oc.getBool("flip-y-axis")) {
651 23 : mirrorX();
652 : }
653 :
654 7158 : if (oc.exists("geometry.check-overlap") && oc.getFloat("geometry.check-overlap") > 0) {
655 0 : before = PROGRESS_BEGIN_TIME_MESSAGE(TL("Checking overlapping edges"));
656 0 : myEdgeCont.checkOverlap(oc.getFloat("geometry.check-overlap"), oc.getFloat("geometry.check-overlap.vertical-threshold"));
657 0 : PROGRESS_TIME_MESSAGE(before);
658 : }
659 1858 : if (geoConvHelper.getConvBoundary().getZRange() > 0 && oc.getFloat("geometry.max-grade") > 0) {
660 46 : before = PROGRESS_BEGIN_TIME_MESSAGE(TL("Checking edge grade"));
661 : // user input is in %
662 23 : myEdgeCont.checkGrade(oc.getFloat("geometry.max-grade") / 100);
663 23 : PROGRESS_TIME_MESSAGE(before);
664 : }
665 :
666 : // find accesses for pt rail stops and add bidi-stops
667 1835 : if (!myPTStopCont.getStops().empty()) {
668 : // re-adapt stop lanes after adding special lanes and cutting edge shapes at junction
669 140 : myPTStopCont.assignLanes(myEdgeCont);
670 140 : before = SysUtils::getCurrentMillis();
671 : int numBidiStops = 0;
672 140 : if (!oc.getBool("ptstop-output.no-bidi")) {
673 138 : numBidiStops = myPTStopCont.generateBidiStops(myEdgeCont);
674 : }
675 280 : PROGRESS_BEGIN_MESSAGE(TL("Find accesses for pt rail stops"));
676 140 : double maxRadius = oc.getFloat("railway.access-distance");
677 140 : double accessFactor = oc.getFloat("railway.access-factor");
678 140 : int maxCount = oc.getInt("railway.max-accesses");
679 140 : myPTStopCont.findAccessEdgesForRailStops(myEdgeCont, maxRadius, maxCount, accessFactor);
680 140 : PROGRESS_TIME_MESSAGE(before);
681 140 : if (numBidiStops > 0) {
682 69 : myPTLineCont.fixBidiStops(myEdgeCont);
683 : }
684 : }
685 1835 : myPTLineCont.removeInvalidEdges(myEdgeCont);
686 : // ensure that all turning lanes have sufficient permissions
687 1835 : myPTLineCont.fixPermissions();
688 :
689 7155 : if (oc.exists("ignore-change-restrictions") && !oc.isDefault("ignore-change-restrictions")) {
690 3 : SVCPermissions ignoring = parseVehicleClasses(oc.getStringVector("ignore-change-restrictions"));
691 3 : myEdgeCont.updateAllChangeRestrictions(ignoring);
692 : }
693 :
694 1835 : NBRequest::reportWarnings();
695 : // report on very large networks
696 5503 : if (MAX2(geoConvHelper.getConvBoundary().xmax(), geoConvHelper.getConvBoundary().ymax()) > 1000000 ||
697 1833 : MIN2(geoConvHelper.getConvBoundary().xmin(), geoConvHelper.getConvBoundary().ymin()) < -1000000) {
698 4 : WRITE_WARNING(TL("Network contains very large coordinates and will probably flicker in the GUI. Check for outlying nodes and make sure the network is shifted to the coordinate origin"));
699 : }
700 :
701 : // clean up OSM processing params
702 5152 : if (oc.exists("osm-files") && oc.isSet("osm-files")) {
703 50706 : for (auto item : myEdgeCont) {
704 50535 : item.second->unsetParameter(NBTrafficLightDefinition::OSM_DIRECTION);
705 : }
706 : }
707 1837 : }
708 :
709 :
710 : void
711 1270 : NBNetBuilder::moveToOrigin(GeoConvHelper& geoConvHelper, bool lefthand) {
712 2540 : long before = PROGRESS_BEGIN_TIME_MESSAGE(TL("Moving network to origin"));
713 1270 : Boundary boundary = geoConvHelper.getConvBoundary();
714 1270 : const double x = -boundary.xmin();
715 1270 : const double y = -(lefthand ? boundary.ymax() : boundary.ymin());
716 : //if (lefthand) {
717 : // y = boundary.ymax();
718 : //}
719 51222 : for (std::map<std::string, NBNode*>::const_iterator i = myNodeCont.begin(); i != myNodeCont.end(); ++i) {
720 49952 : (*i).second->reshiftPosition(x, y);
721 : }
722 91133 : for (std::map<std::string, NBEdge*>::const_iterator i = myEdgeCont.begin(); i != myEdgeCont.end(); ++i) {
723 89863 : (*i).second->reshiftPosition(x, y);
724 : }
725 1320 : for (std::map<std::string, NBDistrict*>::const_iterator i = myDistrictCont.begin(); i != myDistrictCont.end(); ++i) {
726 50 : (*i).second->reshiftPosition(x, y);
727 : }
728 3499 : for (const auto& stopIt : myPTStopCont.getStops()) {
729 2229 : stopIt.second->reshiftPosition(x, y);
730 : }
731 1270 : geoConvHelper.moveConvertedBy(x, y);
732 1270 : PROGRESS_TIME_MESSAGE(before);
733 1270 : }
734 :
735 :
736 : void
737 46 : NBNetBuilder::mirrorX() {
738 : // mirror the network along the X-axis
739 888 : for (std::map<std::string, NBNode*>::const_iterator i = myNodeCont.begin(); i != myNodeCont.end(); ++i) {
740 842 : (*i).second->mirrorX();
741 : }
742 1190 : for (std::map<std::string, NBEdge*>::const_iterator i = myEdgeCont.begin(); i != myEdgeCont.end(); ++i) {
743 1144 : (*i).second->mirrorX();
744 : }
745 46 : for (std::map<std::string, NBDistrict*>::const_iterator i = myDistrictCont.begin(); i != myDistrictCont.end(); ++i) {
746 0 : (*i).second->mirrorX();
747 : }
748 105 : for (const auto& stopIt : myPTStopCont.getStops()) {
749 59 : stopIt.second->mirrorX();
750 : }
751 46 : }
752 :
753 :
754 : bool
755 659465 : NBNetBuilder::transformCoordinate(Position& from, bool includeInBoundary, GeoConvHelper* from_srs) {
756 659465 : Position orig(from);
757 : bool ok = true;
758 : if (GeoConvHelper::getNumLoaded() > 1
759 2505 : && GeoConvHelper::getLoaded().usingGeoProjection()
760 2326 : && from_srs != nullptr
761 2326 : && from_srs->usingGeoProjection()
762 661791 : && *from_srs != GeoConvHelper::getLoaded()) {
763 2326 : from_srs->cartesian2geo(from);
764 2326 : ok &= GeoConvHelper::getLoaded().x2cartesian(from, false);
765 : }
766 659465 : if (from_srs == nullptr || !GeoConvHelper::getProcessing().usingGeoProjection()) {
767 : // if getProcessing is not a geo-projection, assume it a cartesian transformation (i.e. shift)
768 659399 : ok &= GeoConvHelper::getProcessing().x2cartesian(from, includeInBoundary);
769 :
770 267733 : if (from_srs == nullptr && GeoConvHelper::getProcessing().usingGeoProjection()
771 228623 : && GeoConvHelper::getNumLoaded() > 0
772 659435 : && GeoConvHelper::getLoaded().usingGeoProjection()) {
773 : // apply geo patch to loaded geo-network (offset must match)
774 36 : from = from + GeoConvHelper::getLoaded().getOffset();
775 : }
776 : }
777 659465 : if (ok) {
778 659465 : const NBHeightMapper& hm = NBHeightMapper::get();
779 659465 : if (hm.ready()) {
780 604 : if (from_srs != nullptr && from_srs->usingGeoProjection()) {
781 600 : from_srs->cartesian2geo(orig);
782 : }
783 604 : from.setz(hm.getZ(orig));
784 : }
785 : }
786 : const double eps = 1e-6;
787 659465 : from.set(std::round(from.x() / eps) * eps, std::round(from.y() / eps) * eps, std::round(from.z() / eps) * eps);
788 659465 : return ok;
789 : }
790 :
791 :
792 : bool
793 229326 : NBNetBuilder::transformCoordinates(PositionVector& from, bool includeInBoundary, GeoConvHelper* from_srs) {
794 229326 : const double maxLength = OptionsCont::getOptions().getFloat("geometry.max-segment-length");
795 229326 : if (maxLength > 0 && from.size() > 1) {
796 : // transformation to cartesian coordinates must happen before we can check segment length
797 : PositionVector copy = from;
798 118 : for (int i = 0; i < (int) from.size(); i++) {
799 85 : transformCoordinate(copy[i], false);
800 : }
801 33 : addGeometrySegments(from, copy, maxLength);
802 33 : }
803 : bool ok = true;
804 792920 : for (int i = 0; i < (int) from.size(); i++) {
805 563594 : ok = ok && transformCoordinate(from[i], includeInBoundary, from_srs);
806 : }
807 229326 : return ok;
808 : }
809 :
810 :
811 : int
812 71 : NBNetBuilder::addGeometrySegments(PositionVector& from, const PositionVector& cartesian, const double maxLength) {
813 : // check lengths and insert new points where needed (in the original
814 : // coordinate system)
815 : int inserted = 0;
816 161 : for (int i = 0; i < (int)cartesian.size() - 1; i++) {
817 90 : Position start = from[i + inserted];
818 90 : Position end = from[i + inserted + 1];
819 90 : double length = cartesian[i].distanceTo(cartesian[i + 1]);
820 90 : const Position step = (end - start) * (maxLength / length);
821 : int steps = 0;
822 312 : while (length > maxLength) {
823 222 : length -= maxLength;
824 222 : steps++;
825 222 : from.insert(from.begin() + i + inserted + 1, start + (step * steps));
826 222 : inserted++;
827 : }
828 : }
829 71 : return inserted;
830 : }
831 :
832 :
833 : bool
834 974 : NBNetBuilder::runningNetedit() {
835 : // see GNELoadThread::fillOptions
836 1948 : return OptionsCont::getOptions().exists("new");
837 : }
838 :
839 :
840 : /****************************************************************************/
|