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 NLTriggerBuilder.cpp
15 : /// @author Daniel Krajzewicz
16 : /// @author Tino Morenz
17 : /// @author Jakob Erdmann
18 : /// @author Eric Nicolay
19 : /// @author Sascha Krieg
20 : /// @author Michael Behrisch
21 : /// @author Johannes Rummel
22 : /// @date Thu, 17 Oct 2002
23 : ///
24 : // Builds trigger objects for microsim
25 : /****************************************************************************/
26 : #include <config.h>
27 :
28 : #include <string>
29 : #include <mesosim/MELoop.h>
30 : #include <mesosim/METriggeredCalibrator.h>
31 : #include <microsim/MSEventControl.h>
32 : #include <microsim/MSJunctionControl.h>
33 : #include <microsim/MSLane.h>
34 : #include <microsim/MSEdge.h>
35 : #include <microsim/MSGlobals.h>
36 : #include <microsim/MSParkingArea.h>
37 : #include <microsim/MSStoppingPlace.h>
38 : #include <microsim/output/MSDetectorControl.h>
39 : #include <microsim/output/MSRouteProbe.h>
40 : #include <microsim/trigger/MSLaneSpeedTrigger.h>
41 : #include <microsim/trigger/MSTriggeredRerouter.h>
42 : #include <microsim/trigger/MSCalibrator.h>
43 : #include <microsim/trigger/MSChargingStation.h>
44 : #include <microsim/trigger/MSOverheadWire.h>
45 : #include <utils/common/StringTokenizer.h>
46 : #include <utils/common/FileHelpers.h>
47 : #include <utils/common/UtilExceptions.h>
48 : #include <utils/common/WrappingCommand.h>
49 : #include <utils/common/RGBColor.h>
50 : #include <utils/options/OptionsCont.h>
51 : #include <utils/xml/SUMOXMLDefinitions.h>
52 : #include <utils/xml/XMLSubSys.h>
53 : #include "NLHandler.h"
54 : #include "NLTriggerBuilder.h"
55 :
56 :
57 : // ===========================================================================
58 : // method definitions
59 : // ===========================================================================
60 42766 : NLTriggerBuilder::NLTriggerBuilder()
61 42766 : : myHandler(nullptr), myParkingArea(nullptr), myCurrentStop(nullptr) {}
62 :
63 :
64 42766 : NLTriggerBuilder::~NLTriggerBuilder() {}
65 :
66 : void
67 42766 : NLTriggerBuilder::setHandler(NLHandler* handler) {
68 42766 : myHandler = handler;
69 42766 : }
70 :
71 :
72 : void
73 482 : NLTriggerBuilder::buildVaporizer(const SUMOSAXAttributes& attrs) {
74 482 : WRITE_WARNING(TL("Vaporizers are deprecated. Use rerouters instead."));
75 482 : bool ok = true;
76 : // get the id, throw if not given or empty...
77 482 : std::string id = attrs.get<std::string>(SUMO_ATTR_ID, nullptr, ok);
78 482 : if (!ok) {
79 : return;
80 : }
81 470 : MSEdge* e = MSEdge::dictionary(id);
82 470 : if (e == nullptr) {
83 18 : WRITE_ERRORF(TL("Unknown edge ('%') referenced in a vaporizer."), id);
84 6 : return;
85 : }
86 464 : SUMOTime begin = attrs.getSUMOTimeReporting(SUMO_ATTR_BEGIN, nullptr, ok);
87 464 : SUMOTime end = attrs.getSUMOTimeReporting(SUMO_ATTR_END, nullptr, ok);
88 464 : if (!ok) {
89 : return;
90 : }
91 428 : if (begin < 0) {
92 18 : WRITE_ERRORF(TL("A vaporization begin time is negative (edge id='%')."), id);
93 6 : return;
94 : }
95 422 : if (begin >= end) {
96 36 : WRITE_ERRORF(TL("A vaporization ends before it starts (edge id='%')."), id);
97 12 : return;
98 : }
99 820 : if (end >= string2time(OptionsCont::getOptions().getString("begin"))) {
100 410 : Command* cb = new WrappingCommand< MSEdge >(e, &MSEdge::incVaporization);
101 410 : MSNet::getInstance()->getBeginOfTimestepEvents()->addEvent(cb, begin);
102 410 : Command* ce = new WrappingCommand< MSEdge >(e, &MSEdge::decVaporization);
103 410 : MSNet::getInstance()->getBeginOfTimestepEvents()->addEvent(ce, end);
104 : }
105 : }
106 :
107 :
108 : void
109 477 : NLTriggerBuilder::parseAndBuildLaneSpeedTrigger(MSNet& net, const SUMOSAXAttributes& attrs,
110 : const std::string& base) {
111 : // get the id, throw if not given or empty...
112 477 : bool ok = true;
113 : // get the id, throw if not given or empty...
114 477 : std::string id = attrs.get<std::string>(SUMO_ATTR_ID, nullptr, ok);
115 477 : if (!ok) {
116 : return;
117 : }
118 : // get the file name to read further definitions from
119 477 : std::string file = getFileName(attrs, base, true);
120 477 : std::string objectid = attrs.get<std::string>(SUMO_ATTR_LANES, id.c_str(), ok);
121 : std::vector<MSLane*> lanes;
122 1008 : for (const std::string& laneID : attrs.get<std::vector<std::string> >(SUMO_ATTR_LANES, id.c_str(), ok)) {
123 531 : MSLane* lane = MSLane::dictionary(laneID);
124 531 : if (lane == nullptr) {
125 0 : throw InvalidArgument("The lane '" + laneID + "' to use within MSLaneSpeedTrigger '" + id + "' is not known.");
126 : }
127 531 : lanes.push_back(lane);
128 477 : }
129 477 : if (!ok) {
130 0 : throw InvalidArgument("The lanes to use within MSLaneSpeedTrigger '" + id + "' are not known.");
131 : }
132 477 : if (lanes.size() == 0) {
133 0 : throw InvalidArgument("No lane defined for MSLaneSpeedTrigger '" + id + "'.");
134 : }
135 : try {
136 477 : MSLaneSpeedTrigger* trigger = buildLaneSpeedTrigger(net, id, lanes, file);
137 477 : if (file == "") {
138 309 : trigger->registerParent(SUMO_TAG_VSS, myHandler);
139 : }
140 0 : } catch (ProcessError& e) {
141 0 : throw InvalidArgument(e.what());
142 0 : }
143 477 : }
144 :
145 :
146 : void
147 11686 : NLTriggerBuilder::parseAndBuildChargingStation(MSNet& net, const SUMOSAXAttributes& attrs) {
148 11686 : bool ok = true;
149 :
150 : // get the id, throw if not given or empty...
151 11686 : std::string id = attrs.get<std::string>(SUMO_ATTR_ID, nullptr, ok);
152 11686 : if (!ok) {
153 0 : throw ProcessError();
154 : }
155 :
156 23372 : MSLane* const lane = getLane(attrs, "chargingStation", id);
157 11686 : double frompos = attrs.getOpt<double>(SUMO_ATTR_STARTPOS, id.c_str(), ok, 0);
158 11686 : double topos = attrs.getOpt<double>(SUMO_ATTR_ENDPOS, id.c_str(), ok, lane->getLength());
159 11686 : const double chargingPower = attrs.getOpt<double>(SUMO_ATTR_CHARGINGPOWER, id.c_str(), ok, 22000);
160 11686 : const double efficiency = attrs.getOpt<double>(SUMO_ATTR_EFFICIENCY, id.c_str(), ok, 0.95);
161 11686 : const bool chargeInTransit = attrs.getOpt<bool>(SUMO_ATTR_CHARGEINTRANSIT, id.c_str(), ok, 0);
162 11686 : const SUMOTime chargeDelay = attrs.getOptSUMOTimeReporting(SUMO_ATTR_CHARGEDELAY, id.c_str(), ok, 0);
163 23373 : const std::string chargeType = attrs.getOpt<std::string>(SUMO_ATTR_CHARGETYPE, id.c_str(), ok, "normal");
164 11686 : const SUMOTime waitingTime = attrs.getOptSUMOTimeReporting(SUMO_ATTR_WAITINGTIME, id.c_str(), ok, 900);
165 11686 : const bool friendlyPos = attrs.getOpt<bool>(SUMO_ATTR_FRIENDLY_POS, id.c_str(), ok, false);
166 11687 : const std::string name = attrs.getOpt<std::string>(SUMO_ATTR_NAME, id.c_str(), ok, "");
167 23372 : MSParkingArea* parkingArea = getParkingArea(attrs, "parkingArea", id);
168 :
169 : // check charge type
170 11686 : if ((chargeType != "normal") && (chargeType != "electric") && (chargeType != "fuel")) {
171 0 : throw InvalidArgument("The chargeType to use within MSLaneSpeedTrigger '" + id + "' is invalid.");
172 : }
173 :
174 11686 : if (!ok || (myHandler->checkStopPos(frompos, topos, lane->getLength(), POSITION_EPS, friendlyPos) != SUMORouteHandler::StopPos::STOPPOS_VALID)) {
175 2 : throw InvalidArgument("Invalid position for charging station '" + id + "'.");
176 : }
177 :
178 35056 : buildChargingStation(net, id, lane, frompos, topos, name, chargingPower, efficiency, chargeInTransit, chargeDelay, chargeType, waitingTime, parkingArea);
179 11685 : }
180 :
181 :
182 : void
183 54 : NLTriggerBuilder::parseAndBuildOverheadWireSegment(MSNet& net, const SUMOSAXAttributes& attrs) {
184 54 : bool ok = true;
185 :
186 : // get the id, throw if not given or empty...
187 54 : std::string id = attrs.get<std::string>(SUMO_ATTR_ID, 0, ok);
188 54 : if (!ok) {
189 0 : throw ProcessError();
190 : }
191 :
192 : /* The following call may either throw InvalidArgument exeption or return NULL:
193 : NULL is returned in case when the overhead wire segment should be built over an already
194 : ignored internal lane of an intersection, the exeption is thrown in case that
195 : the overhead wire segment references a non-existent lane. */
196 54 : MSLane* const lane = getLane(attrs, "overheadWireSegment", id);
197 54 : if (lane == nullptr) {
198 0 : WRITE_MESSAGEF(TL("The overheadWireSegment '%' was not created as it is attached to internal lane. It will be build automatically."), id);
199 0 : return;
200 : }
201 :
202 54 : if (lane->isInternal()) {
203 0 : WRITE_MESSAGEF(TL("The overheadWireSegment '%' not built as it is attached to internal lane. It will be build automatically."), id);
204 0 : return;
205 : }
206 :
207 54 : double frompos = attrs.getOpt<double>(SUMO_ATTR_STARTPOS, id.c_str(), ok, 0);
208 54 : double topos = attrs.getOpt<double>(SUMO_ATTR_ENDPOS, id.c_str(), ok, lane->getLength());
209 54 : const bool voltageSource = attrs.getOpt<bool>(SUMO_ATTR_VOLTAGESOURCE, id.c_str(), ok, false);
210 54 : const bool friendlyPos = attrs.getOpt<bool>(SUMO_ATTR_FRIENDLY_POS, id.c_str(), ok, false);
211 :
212 54 : if (!ok || myHandler->checkStopPos(frompos, topos, lane->getLength(), POSITION_EPS, friendlyPos) != SUMORouteHandler::StopPos::STOPPOS_VALID) {
213 0 : frompos = 0;
214 0 : topos = lane->getLength();
215 0 : WRITE_MESSAGEF(TL("The overheadWireSegment '%' has wrong position. Automatically set from 0 to the length of the lane."), id);
216 : //throw InvalidArgument("Invalid position for overheadWireSegment'" + id + "'.");
217 : }
218 :
219 54 : buildOverheadWireSegment(net, id, lane, frompos, topos, voltageSource);
220 : #ifndef HAVE_EIGEN
221 : if (MSGlobals::gOverheadWireSolver && !myHaveWarnedAboutEigen) {
222 : myHaveWarnedAboutEigen = true;
223 : WRITE_WARNING(TL("Overhead wire solver (Eigen) not compiled in, expect errors in overhead wire simulation"))
224 : }
225 : #endif // !HAVE_EIGEN
226 : }
227 :
228 : void
229 8 : NLTriggerBuilder::parseAndBuildOverheadWireSection(MSNet& net, const SUMOSAXAttributes& attrs) {
230 8 : bool ok = true;
231 8 : std::string substationId = attrs.get<std::string>(SUMO_ATTR_SUBSTATIONID, 0, ok);
232 8 : if (!ok) {
233 0 : throw ProcessError();
234 : }
235 :
236 8 : MSTractionSubstation* substation = MSNet::getInstance()->findTractionSubstation(substationId);
237 8 : if (substation == nullptr) {
238 0 : throw InvalidArgument("Traction substation '" + substationId + "' refereced by an OverheadWire Section is not known.");
239 8 : } else if (substation->isAnySectionPreviouslyDefined()) {
240 0 : throw InvalidArgument("Traction substation '" + substationId + "' refereced by an OverheadWire Section is probably referenced twice (a known limitation of the actual version of overhead wire simulation).");
241 : }
242 :
243 : // @todo This may be a relict of older approach to processing the attributes ...
244 8 : std::string segmentStrings = attrs.get<std::string>(SUMO_ATTR_OVERHEAD_WIRE_SEGMENTS, substationId.c_str(), ok);
245 8 : if (!ok) {
246 0 : throw InvalidArgument("Segments referenced by Traction substation '" + substationId + "' are not declared .");
247 : }
248 :
249 : // process forbidden internal lanes
250 8 : const std::vector<std::string>& forbiddenInnerLanesIDs = attrs.getOpt<std::vector<std::string> >(SUMO_ATTR_OVERHEAD_WIRE_FORBIDDEN, substationId.c_str(), ok);
251 : /// @todo for cycle abbreviation?
252 8 : for (const std::string& laneID : forbiddenInnerLanesIDs) {
253 0 : MSLane* lane = MSLane::dictionary(laneID);
254 0 : if (lane != nullptr) {
255 0 : substation->addForbiddenLane(lane);
256 : } else {
257 0 : throw InvalidArgument("Unknown lane '" + laneID + "' in Traction substation '" + substationId + "'.");
258 : }
259 : }
260 :
261 : // @todo Check this as well ...
262 : // Original version from 2018
263 : // std::vector<std::string> segmentIDs;
264 : // SUMOSAXAttributes::parseStringVector(segmentStrings, segmentIDs);
265 8 : const std::vector<std::string>& segmentIDs = attrs.get<std::vector<std::string> >(SUMO_ATTR_OVERHEAD_WIRE_SEGMENTS, substationId.c_str(), ok);
266 : std::vector<MSOverheadWire*> segments;
267 :
268 : // ----------------------------------------------
269 : // Add overhead wire segments over internal lanes
270 : // ----------------------------------------------
271 :
272 : // Adding internal overhead wire segments (segments on neighboring inner lanes if a connection between two regular lane with overhead wire segment exists)
273 46 : for (const std::string& segmentID : segmentIDs) {
274 : const MSLane* connection = nullptr;
275 38 : MSOverheadWire* ovrhdSegment = dynamic_cast<MSOverheadWire*>(MSNet::getInstance()->getStoppingPlace(segmentID, SUMO_TAG_OVERHEAD_WIRE_SEGMENT));
276 : std::string neigboringOvrhdSegmentID;
277 : MSOverheadWire* neigboringOvrhdSegment;
278 : MSTractionSubstation* neigboringOvrhdSegmentTractionSubstation;
279 38 : if (ovrhdSegment == nullptr) {
280 0 : throw InvalidArgument("The OverheadWireSegment with id='" + segmentID + "' referenced by OverheadWireSegment for substation '" + substationId + "' was not defined.");
281 : }
282 :
283 : MSTractionSubstation* ts = ovrhdSegment->getTractionSubstation();
284 38 : if (!(ts == substation || ts == nullptr)) {
285 : std::string tsName = ts->getID();
286 0 : throw InvalidArgument("The OverheadWireSegment '" + segmentID + "' referenced by OverheadWireSegment for substation '" + substationId + "' is already assigned to substation '" + tsName + "'.");
287 : }
288 : ovrhdSegment->setTractionSubstation(substation);
289 :
290 38 : const MSLane* lane = &(ovrhdSegment->getLane());
291 :
292 : /* in version before SUMO 1.0.1 the function getOutgoingLanes() returning MSLane* exists,
293 : in new version of SUMO the funciton getOutgoingViaLanes() returning MSLane* and MSEdge* pair exists */
294 38 : const std::vector<std::pair<const MSLane*, const MSEdge*> > outgoingLanesAndEdges = lane->getOutgoingViaLanes();
295 : std::vector<const MSLane*> neigboringInnerLanes;
296 38 : neigboringInnerLanes.reserve(outgoingLanesAndEdges.size());
297 89 : for (size_t it = 0; it < outgoingLanesAndEdges.size(); ++it) {
298 51 : neigboringInnerLanes.push_back(outgoingLanesAndEdges[it].first);
299 : }
300 :
301 : // Check if an outgoing lane has an overhead wire segment. If not, do nothing, otherwise find connnecting internal lanes and
302 : // add overhead wire segments over all detected internal lanes
303 89 : for (std::vector<const MSLane*>::iterator it = neigboringInnerLanes.begin(); it != neigboringInnerLanes.end(); ++it) {
304 : // If the overhead wire segment is over the outgoing (not internal) lane
305 102 : neigboringOvrhdSegmentID = MSNet::getInstance()->getStoppingPlaceID(*it, NUMERICAL_EPS, SUMO_TAG_OVERHEAD_WIRE_SEGMENT);
306 51 : if (neigboringOvrhdSegmentID != "") {
307 25 : neigboringOvrhdSegment = dynamic_cast<MSOverheadWire*>(MSNet::getInstance()->getStoppingPlace(neigboringOvrhdSegmentID, SUMO_TAG_OVERHEAD_WIRE_SEGMENT));
308 : neigboringOvrhdSegmentTractionSubstation = neigboringOvrhdSegment->getTractionSubstation();
309 : } else {
310 : neigboringOvrhdSegment = nullptr;
311 : neigboringOvrhdSegmentTractionSubstation = nullptr;
312 : }
313 :
314 51 : if (neigboringOvrhdSegmentTractionSubstation == substation && !(*it)->isInternal()) {
315 2 : connection = lane->getInternalFollowingLane(*it);
316 2 : if (connection != nullptr) {
317 : //is connection forbidden?
318 2 : if (!(substation->isForbidden(connection) || substation->isForbidden(lane->getInternalFollowingLane(connection)) || substation->isForbidden(connection->getInternalFollowingLane(*it)))) {
319 2 : buildInnerOverheadWireSegments(net, connection, lane->getInternalFollowingLane(connection), connection->getInternalFollowingLane(*it));
320 : }
321 : }
322 : }
323 : }
324 :
325 : // Check if an incoming lane has an overhead wire segment. If not, do nothing, otherwise find connnecting internal lanes and
326 : // add overhead wire segments over all detected internal lanes
327 38 : neigboringInnerLanes = lane->getNormalIncomingLanes();
328 111 : for (std::vector<const MSLane*>::iterator it = neigboringInnerLanes.begin(); it != neigboringInnerLanes.end(); ++it) {
329 : // If the overhead wire segment is over the incoming (not internal) lane
330 146 : neigboringOvrhdSegmentID = MSNet::getInstance()->getStoppingPlaceID(*it, (*it)->getLength() - NUMERICAL_EPS, SUMO_TAG_OVERHEAD_WIRE_SEGMENT);
331 73 : if (neigboringOvrhdSegmentID != "") {
332 19 : neigboringOvrhdSegment = dynamic_cast<MSOverheadWire*>(MSNet::getInstance()->getStoppingPlace(neigboringOvrhdSegmentID, SUMO_TAG_OVERHEAD_WIRE_SEGMENT));
333 : neigboringOvrhdSegmentTractionSubstation = neigboringOvrhdSegment->getTractionSubstation();
334 : } else {
335 : neigboringOvrhdSegment = nullptr;
336 : neigboringOvrhdSegmentTractionSubstation = nullptr;
337 : }
338 :
339 73 : if (neigboringOvrhdSegmentTractionSubstation == substation && !(*it)->isInternal()) {
340 17 : connection = (*it)->getInternalFollowingLane(lane);
341 17 : if (connection != nullptr) {
342 : //is connection forbidden?
343 2 : if (!(substation->isForbidden(connection) || substation->isForbidden((*it)->getInternalFollowingLane(connection)) || substation->isForbidden(connection->getInternalFollowingLane(lane)))) {
344 2 : buildInnerOverheadWireSegments(net, connection, (*it)->getInternalFollowingLane(connection), connection->getInternalFollowingLane(lane));
345 : }
346 : }
347 : }
348 : }
349 38 : }
350 :
351 :
352 : // ----- *** adding segments into the electric circuit*** -----
353 :
354 : // setting nullptr for substation (a fragment from old version of adding segments into the circuit)
355 46 : for (const std::string& segmentID : segmentIDs) {
356 38 : MSOverheadWire* ovrhdSegment = dynamic_cast<MSOverheadWire*>(MSNet::getInstance()->getStoppingPlace(segmentID, SUMO_TAG_OVERHEAD_WIRE_SEGMENT));
357 : ovrhdSegment->setTractionSubstation(nullptr);
358 : }
359 :
360 46 : for (const std::string& segmentID : segmentIDs) {
361 38 : if (segmentID == "") {
362 0 : continue;
363 : }
364 38 : MSOverheadWire* ovrhdSegment = dynamic_cast<MSOverheadWire*>(MSNet::getInstance()->getStoppingPlace(segmentID, SUMO_TAG_OVERHEAD_WIRE_SEGMENT));
365 38 : substation->addOverheadWireSegmentToCircuit(ovrhdSegment);
366 38 : segments.push_back(ovrhdSegment);
367 : }
368 :
369 : // adding overhead wire clamp
370 16 : std::string clampsString = attrs.getOpt<std::string>(SUMO_ATTR_OVERHEAD_WIRE_CLAMPS, nullptr, ok, "");
371 8 : if (clampsString != "" && MSGlobals::gOverheadWireSolver) {
372 : #ifdef HAVE_EIGEN
373 5 : const std::vector<std::string>& clampIDs = attrs.get<std::vector<std::string> >(SUMO_ATTR_OVERHEAD_WIRE_CLAMPS, nullptr, ok);
374 16 : for (const std::string& clampID : clampIDs) {
375 11 : MSTractionSubstation::OverheadWireClamp* clamp = substation->findClamp(clampID);
376 11 : if (clamp != nullptr) {
377 11 : if (clamp->start->getTractionSubstation() == substation && clamp->end->getTractionSubstation() == substation) {
378 11 : substation->addOverheadWireClampToCircuit(clamp->id, clamp->start, clamp->end);
379 11 : buildOverheadWireClamp(net, clamp->id, const_cast<MSLane*>(&clamp->start->getLane()), const_cast<MSLane*>(&clamp->end->getLane()));
380 11 : clamp->usage = true;
381 : } else {
382 0 : if (clamp->start->getTractionSubstation() != substation) {
383 0 : WRITE_WARNINGF(TL("A connecting overhead wire start segment '%' defined for overhead wire clamp '%' is not assigned to the traction substation '%'."), clamp->start->getID(), clampID, substationId);
384 : } else {
385 0 : WRITE_WARNINGF(TL("A connecting overhead wire end segment '%' defined for overhead wire clamp '%' is not assigned to the traction substation '%'."), clamp->end->getID(), clampID, substationId);
386 : }
387 : }
388 : } else {
389 0 : WRITE_WARNINGF(TL("The overhead wire clamp '%' defined in an overhead wire section was not assigned to the substation '%'. Please define proper <overheadWireClamp .../> in additional files before defining overhead wire section."), clampID, substationId);
390 : }
391 : }
392 : #else
393 : WRITE_WARNING(TL("Overhead circuit solver requested, but solver support (Eigen) not compiled in."));
394 : #endif
395 5 : }
396 :
397 8 : if (segments.size() == 0) {
398 0 : throw InvalidArgument("No segments found for overHeadWireSection '" + substationId + "'.");
399 8 : } else if (MSGlobals::gOverheadWireSolver) {
400 : #ifdef HAVE_EIGEN
401 : // check that the electric circuit makes sense
402 24 : segments[0]->getCircuit()->checkCircuit(substationId);
403 : #else
404 : WRITE_WARNING(TL("Cannot check circuit, overhead circuit solver support (Eigen) not compiled in."));
405 : #endif
406 : }
407 16 : }
408 :
409 : void
410 8 : NLTriggerBuilder::parseAndBuildTractionSubstation(MSNet& net, const SUMOSAXAttributes& attrs) {
411 8 : bool ok = true;
412 :
413 : // get the id, throw if not given or empty...
414 8 : std::string id = attrs.get<std::string>(SUMO_ATTR_ID, 0, ok);
415 8 : if (!ok) {
416 0 : throw ProcessError();
417 : }
418 :
419 : // RICE_TODO Limits are fixed, change them to some predefined constants ...
420 8 : const double voltage = attrs.getOpt<double>(SUMO_ATTR_VOLTAGE, id.c_str(), ok, 600);
421 8 : const double currentLimit = attrs.getOpt<double>(SUMO_ATTR_CURRENTLIMIT, id.c_str(), ok, 400);
422 16 : buildTractionSubstation(net, id, voltage, currentLimit);
423 8 : }
424 :
425 : void
426 11 : NLTriggerBuilder::parseAndBuildOverheadWireClamp(MSNet& /*net*/, const SUMOSAXAttributes& attrs) {
427 11 : if (MSGlobals::gOverheadWireSolver) {
428 : #ifdef HAVE_EIGEN
429 11 : bool ok = true;
430 11 : std::string id = attrs.get<std::string>(SUMO_ATTR_ID, 0, ok);
431 11 : if (!ok) {
432 0 : throw ProcessError();
433 : }
434 :
435 11 : std::string substationId = attrs.get<std::string>(SUMO_ATTR_SUBSTATIONID, 0, ok);
436 11 : if (!ok) {
437 0 : throw ProcessError();
438 : }
439 11 : MSTractionSubstation* substation = MSNet::getInstance()->findTractionSubstation(substationId);
440 11 : if (substation == nullptr) {
441 0 : throw InvalidArgument("Traction substation '" + substationId + "' using within an overheadWireClamp '" + id + "' is not known.");
442 : }
443 :
444 11 : std::string overhead_fromItsStart = attrs.get<std::string>(SUMO_ATTR_OVERHEAD_WIRE_CLAMP_START, 0, ok);
445 11 : if (!ok) {
446 0 : throw ProcessError();
447 : }
448 11 : MSOverheadWire* ovrhdSegment_fromItsStart = dynamic_cast<MSOverheadWire*>(MSNet::getInstance()->getStoppingPlace(overhead_fromItsStart, SUMO_TAG_OVERHEAD_WIRE_SEGMENT));
449 11 : if (ovrhdSegment_fromItsStart == nullptr) {
450 0 : throw InvalidArgument("The overheadWireSegment '" + overhead_fromItsStart + "' to use within overheadWireClamp '" + id + "' is not known.");
451 : }
452 : /*if (ovrhdSegment_fromItsStart->getTractionSubstation() != substation) {
453 : throw InvalidArgument("The overheadWireSegment '" + overhead_fromItsStart + "' to use within overheadWireClamp is assign to a different overhead wire section or substation.");
454 : }
455 : */
456 11 : std::string overhead_fromItsEnd = attrs.get<std::string>(SUMO_ATTR_OVERHEAD_WIRE_CLAMP_END, 0, ok);
457 11 : if (!ok) {
458 0 : throw ProcessError();
459 : }
460 11 : MSOverheadWire* ovrhdSegment_fromItsEnd = dynamic_cast<MSOverheadWire*>(MSNet::getInstance()->getStoppingPlace(overhead_fromItsEnd, SUMO_TAG_OVERHEAD_WIRE_SEGMENT));
461 11 : if (ovrhdSegment_fromItsEnd == nullptr) {
462 0 : throw InvalidArgument("The overheadWireSegment '" + overhead_fromItsEnd + "' to use within overheadWireClamp '" + id + "' is not known.");
463 : }
464 : /*
465 : if (ovrhdSegment_fromItsEnd->getTractionSubstation() != substation) {
466 : throw InvalidArgument("The overheadWireSegment '" + overhead_fromItsEnd + "' to use within overheadWireClamp is assign to a different overhead wire section or substation.");
467 : }
468 : */
469 22 : if (substation->findClamp(id) == nullptr) {
470 11 : substation->addClamp(id, ovrhdSegment_fromItsStart, ovrhdSegment_fromItsEnd);
471 : } else {
472 0 : WRITE_ERROR("The overhead wire clamp '" + id + "' is probably declared twice.")
473 : }
474 : #else
475 : UNUSED_PARAMETER(attrs);
476 : WRITE_WARNING(TL("Not building overhead wire clamps, overhead wire solver support (Eigen) not compiled in."));
477 : #endif
478 : } else {
479 0 : WRITE_WARNING(TL("Ignoring overhead wire clamps, they make no sense when overhead wire circuit solver is off."));
480 : }
481 11 : }
482 :
483 :
484 : void
485 38722 : NLTriggerBuilder::parseAndBuildStoppingPlace(MSNet& net, const SUMOSAXAttributes& attrs, const SumoXMLTag element) {
486 38722 : bool ok = true;
487 : // get the id, throw if not given or empty...
488 38722 : std::string id = attrs.get<std::string>(SUMO_ATTR_ID, nullptr, ok);
489 38722 : if (!ok) {
490 0 : throw ProcessError();
491 : }
492 :
493 : //get the name, leave blank if not given
494 77455 : const std::string ptStopName = attrs.getOpt<std::string>(SUMO_ATTR_NAME, id.c_str(), ok, "");
495 :
496 : //get the color, use default if not given
497 : // default color, copy from GUIVisualizationStoppingPlaceSettings::busStopColor / containerStopColor
498 38722 : RGBColor color = attrs.getOpt<RGBColor>(SUMO_ATTR_COLOR, id.c_str(), ok, RGBColor::INVISIBLE);
499 :
500 77444 : MSLane* lane = getLane(attrs, toString(element), id);
501 : // get the positions
502 38722 : double frompos = attrs.getOpt<double>(SUMO_ATTR_STARTPOS, id.c_str(), ok, 0.);
503 38722 : double topos = attrs.getOpt<double>(SUMO_ATTR_ENDPOS, id.c_str(), ok, lane->getLength());
504 38722 : const bool friendlyPos = attrs.getOpt<bool>(SUMO_ATTR_FRIENDLY_POS, id.c_str(), ok, false);
505 38722 : if (!ok || (myHandler->checkStopPos(frompos, topos, lane->getLength(), POSITION_EPS, friendlyPos) != SUMORouteHandler::StopPos::STOPPOS_VALID)) {
506 6 : throw InvalidArgument("Invalid position for " + toString(element) + " '" + id + "'.");
507 : }
508 38730 : const std::vector<std::string>& lines = attrs.getOpt<std::vector<std::string> >(SUMO_ATTR_LINES, id.c_str(), ok);
509 : int defaultCapacity;
510 : SumoXMLAttr capacityAttr;
511 38719 : if (element != SUMO_TAG_CONTAINER_STOP) {
512 28644 : defaultCapacity = MAX2(MSStoppingPlace::getTransportablesAbreast(topos - frompos, element) * 3, 6);
513 : capacityAttr = SUMO_ATTR_PERSON_CAPACITY;
514 : } else {
515 10075 : defaultCapacity = MSStoppingPlace::getTransportablesAbreast(topos - frompos, element);
516 : capacityAttr = SUMO_ATTR_CONTAINER_CAPACITY;
517 : }
518 38719 : const int transportableCapacity = attrs.getOpt<int>(capacityAttr, id.c_str(), ok, defaultCapacity);
519 38719 : const double parkingLength = attrs.getOpt<double>(SUMO_ATTR_PARKING_LENGTH, id.c_str(), ok, 0);
520 : // build the bus stop
521 154884 : buildStoppingPlace(net, id, lines, lane, frompos, topos, element, ptStopName, transportableCapacity, parkingLength, color);
522 77430 : }
523 :
524 :
525 : void
526 2184 : NLTriggerBuilder::addAccess(MSNet& /* net */, const SUMOSAXAttributes& attrs) {
527 2184 : if (myCurrentStop == nullptr) {
528 30 : throw InvalidArgument("Could not add access outside a stopping place.");
529 : }
530 : // get the lane
531 4338 : MSLane* lane = getLane(attrs, "access", myCurrentStop->getID());
532 2169 : if (!lane->allowsVehicleClass(SVC_PEDESTRIAN)) {
533 0 : WRITE_WARNINGF(TL("Ignoring invalid access from non-pedestrian lane '%' in busStop '%'."), lane->getID(), myCurrentStop->getID());
534 0 : return;
535 : }
536 : // get the positions
537 2169 : bool ok = true;
538 2169 : const std::string accessPos = attrs.getOpt<std::string>(SUMO_ATTR_POSITION, "access", ok);
539 2169 : const bool random = accessPos == "random";
540 : MSStoppingPlace::AccessExit exit = MSStoppingPlace::AccessExit::PLATFORM;
541 2169 : if (accessPos == "doors") {
542 : exit = MSStoppingPlace::AccessExit::DOORS;
543 2137 : } else if (accessPos == "carriage") {
544 : exit = MSStoppingPlace::AccessExit::CARRIAGE;
545 : }
546 2169 : double startPos = random || exit != MSStoppingPlace::AccessExit::PLATFORM ? 0. : attrs.getOpt<double>(SUMO_ATTR_POSITION, "access", ok, 0);
547 2169 : double endPos = random || exit != MSStoppingPlace::AccessExit::PLATFORM ? lane->getLength() : startPos;
548 2169 : const double length = attrs.getOpt<double>(SUMO_ATTR_LENGTH, "access", ok, -1);
549 2169 : const bool friendlyPos = attrs.getOpt<bool>(SUMO_ATTR_FRIENDLY_POS, "access", ok, false);
550 2169 : if (!ok || (myHandler->checkStopPos(startPos, endPos, lane->getLength(), 0, friendlyPos) != SUMORouteHandler::StopPos::STOPPOS_VALID)) {
551 0 : throw InvalidArgument("Invalid position " + attrs.getString(SUMO_ATTR_POSITION) + " for access on lane '" + lane->getID() + "' in stop '" + myCurrentStop->getID() + "'.");
552 : }
553 : // add bus stop access
554 2169 : if (!myCurrentStop->addAccess(lane, startPos, endPos, length, exit)) {
555 14 : throw InvalidArgument("Duplicate access on lane '" + lane->getID() + "' for stop '" + myCurrentStop->getID() + "'");
556 : }
557 : }
558 :
559 :
560 : void
561 13285 : NLTriggerBuilder::parseAndBeginParkingArea(MSNet& net, const SUMOSAXAttributes& attrs) {
562 13285 : bool ok = true;
563 : // get the id, throw if not given or empty...
564 13285 : std::string id = attrs.get<std::string>(SUMO_ATTR_ID, nullptr, ok);
565 13285 : if (!ok) {
566 0 : throw ProcessError();
567 : }
568 : // get the lane
569 26570 : MSLane* lane = getLane(attrs, "parkingArea", id);
570 : // get the positions
571 13285 : double frompos = attrs.getOpt<double>(SUMO_ATTR_STARTPOS, id.c_str(), ok, 0);
572 13285 : double topos = attrs.getOpt<double>(SUMO_ATTR_ENDPOS, id.c_str(), ok, lane->getLength());
573 13285 : const bool friendlyPos = attrs.getOpt<bool>(SUMO_ATTR_FRIENDLY_POS, id.c_str(), ok, false);
574 13285 : unsigned int capacity = attrs.getOpt<int>(SUMO_ATTR_ROADSIDE_CAPACITY, id.c_str(), ok, 0);
575 13285 : myParkingAreaCapacitySet = attrs.hasAttribute(SUMO_ATTR_ROADSIDE_CAPACITY);
576 13285 : bool onRoad = attrs.getOpt<bool>(SUMO_ATTR_ONROAD, id.c_str(), ok, false);
577 13285 : double width = attrs.getOpt<double>(SUMO_ATTR_WIDTH, id.c_str(), ok, 0);
578 13285 : double length = attrs.getOpt<double>(SUMO_ATTR_LENGTH, id.c_str(), ok, 0);
579 13285 : double angle = attrs.getOpt<double>(SUMO_ATTR_ANGLE, id.c_str(), ok, 0);
580 26571 : const std::string name = attrs.getOpt<std::string>(SUMO_ATTR_NAME, id.c_str(), ok);
581 26571 : const std::string departPos = attrs.getOpt<std::string>(SUMO_ATTR_DEPARTPOS, id.c_str(), ok);
582 13285 : bool lefthand = attrs.getOpt<bool>(SUMO_ATTR_LEFTHAND, id.c_str(), ok, false);
583 13286 : const std::vector<std::string>& acceptedBadges = attrs.getOpt<std::vector<std::string> >(SUMO_ATTR_ACCEPTED_BADGES, id.c_str(), ok);
584 :
585 13285 : if (!ok || (myHandler->checkStopPos(frompos, topos, lane->getLength(), POSITION_EPS, friendlyPos) != SUMORouteHandler::StopPos::STOPPOS_VALID)) {
586 2 : throw InvalidArgument("Invalid position for parking area '" + id + "'.");
587 : }
588 13284 : const std::vector<std::string>& lines = attrs.getOpt<std::vector<std::string> >(SUMO_ATTR_LINES, id.c_str(), ok);
589 : // build the parking area
590 13284 : beginParkingArea(net, id, lines, acceptedBadges, lane, frompos, topos, capacity, width, length, angle, name, onRoad, departPos, lefthand);
591 26569 : }
592 :
593 :
594 :
595 : void
596 600 : NLTriggerBuilder::parseAndAddLotEntry(const SUMOSAXAttributes& attrs) {
597 600 : bool ok = true;
598 : // Check for open parking area
599 600 : if (myParkingArea == nullptr) {
600 0 : throw ProcessError();
601 : }
602 : // get the positions
603 600 : double x = attrs.get<double>(SUMO_ATTR_X, "", ok);
604 600 : if (!ok) {
605 0 : throw InvalidArgument("Invalid x position for lot entry.");
606 : }
607 600 : double y = attrs.get<double>(SUMO_ATTR_Y, "", ok);
608 600 : if (!ok) {
609 0 : throw InvalidArgument("Invalid y position for lot entry.");
610 : }
611 600 : double z = attrs.getOpt<double>(SUMO_ATTR_Z, "", ok, 0.);
612 600 : double width = attrs.getOpt<double>(SUMO_ATTR_WIDTH, "", ok, myParkingArea->getWidth());
613 600 : double length = attrs.getOpt<double>(SUMO_ATTR_LENGTH, "", ok, myParkingArea->getLength());
614 600 : double angle = attrs.getOpt<double>(SUMO_ATTR_ANGLE, "", ok, myParkingArea->getAngle());
615 600 : double slope = attrs.getOpt<double>(SUMO_ATTR_SLOPE, "", ok, 0.);
616 : // add the lot entry
617 600 : addLotEntry(x, y, z, width, length, angle, slope);
618 600 : }
619 :
620 :
621 : void
622 863 : NLTriggerBuilder::parseAndBuildCalibrator(MSNet& net, const SUMOSAXAttributes& attrs,
623 : const std::string& base) {
624 863 : bool ok = true;
625 : // get the id, throw if not given or empty...
626 863 : std::string id = attrs.get<std::string>(SUMO_ATTR_ID, nullptr, ok);
627 863 : if (!ok) {
628 0 : throw ProcessError();
629 : }
630 : MSLane* lane = nullptr;
631 : MSEdge* edge = nullptr;
632 : MSJunction* node = nullptr;
633 863 : if (attrs.hasAttribute(SUMO_ATTR_NODE)) {
634 14 : if (attrs.hasAttribute(SUMO_ATTR_LANE) || attrs.hasAttribute(SUMO_ATTR_EDGE)) {
635 0 : throw InvalidArgument("The node calibrator '" + id + "' cannot define an edge or lane as well.");
636 : }
637 14 : const std::string nodeID = attrs.get<std::string>(SUMO_ATTR_NODE, id.c_str(), ok);
638 : node = net.getJunctionControl().get(nodeID);
639 14 : if (node == nullptr) {
640 0 : throw InvalidArgument("The node " + nodeID + " to use within the calibrator '" + id + "' is not known.");
641 : }
642 : } else {
643 849 : if (attrs.hasAttribute(SUMO_ATTR_EDGE)) {
644 419 : const std::string edgeID = attrs.get<std::string>(SUMO_ATTR_EDGE, id.c_str(), ok);
645 419 : edge = MSEdge::dictionary(edgeID);
646 419 : if (edge == nullptr) {
647 0 : throw InvalidArgument("The edge " + edgeID + " to use within the calibrator '" + id + "' is not known.");
648 : }
649 419 : if (attrs.hasAttribute(SUMO_ATTR_LANE)) {
650 0 : lane = getLane(attrs, "calibrator", id);
651 0 : if (&lane->getEdge() != edge) {
652 0 : throw InvalidArgument("The edge " + edgeID + " to use within the calibrator '" + id
653 0 : + "' does not match the calibrator lane '" + lane->getID() + ".");
654 : }
655 : }
656 : } else {
657 860 : lane = getLane(attrs, "calibrator", id);
658 : edge = &lane->getEdge();
659 : }
660 : }
661 863 : const double pos = node != nullptr ? 0 : getPosition(attrs, lane, "calibrator", id, edge);
662 862 : const SUMOTime period = attrs.getOptPeriod(id.c_str(), ok, DELTA_T); // !!! no error handling
663 863 : const std::string vTypes = attrs.getOpt<std::string>(SUMO_ATTR_VTYPES, id.c_str(), ok, "");
664 862 : const std::string file = getFileName(attrs, base, true);
665 862 : const std::string outfile = attrs.getOpt<std::string>(SUMO_ATTR_OUTPUT, id.c_str(), ok, "");
666 862 : const std::string routeProbe = attrs.getOpt<std::string>(SUMO_ATTR_ROUTEPROBE, id.c_str(), ok, "");
667 : // differing defaults for backward compatibility, values are dimensionless
668 1640 : const double invalidJamThreshold = attrs.getOpt<double>(SUMO_ATTR_JAM_DIST_THRESHOLD, id.c_str(), ok, MSGlobals::gUseMesoSim ? 0.8 : 0.5);
669 862 : const bool local = attrs.getOpt<bool>(SUMO_ATTR_LOCAL, id.c_str(), ok, false);
670 : MSRouteProbe* probe = nullptr;
671 862 : if (routeProbe != "") {
672 72 : probe = dynamic_cast<MSRouteProbe*>(net.getDetectorControl().getTypedDetectors(SUMO_TAG_ROUTEPROBE).get(routeProbe));
673 36 : if (probe == nullptr) {
674 0 : throw InvalidArgument("The routeProbe '" + routeProbe + "' to use within the calibrator '" + id + "' is not known.");
675 : }
676 : }
677 862 : if (MSGlobals::gUseMesoSim) {
678 84 : if (lane != nullptr && edge->getLanes().size() > 1) {
679 27 : WRITE_WARNING("Meso calibrator '" + id
680 : + "' defined for lane '" + lane->getID()
681 : + "' will collect data for all lanes of edge '" + edge->getID() + "'.");
682 : }
683 84 : METriggeredCalibrator* trigger = buildMECalibrator(id, edge, pos, file, outfile, period, probe, invalidJamThreshold, vTypes);
684 84 : if (file == "") {
685 72 : trigger->registerParent(SUMO_TAG_CALIBRATOR, myHandler);
686 : }
687 : } else {
688 778 : MSCalibrator* trigger = buildCalibrator(id, edge, lane, node, pos, file, outfile, period, probe, invalidJamThreshold, vTypes, local);
689 778 : if (file == "") {
690 748 : trigger->registerParent(SUMO_TAG_CALIBRATOR, myHandler);
691 : }
692 : }
693 862 : }
694 :
695 :
696 : void
697 3384 : NLTriggerBuilder::parseAndBuildRerouter(MSNet& net, const SUMOSAXAttributes& attrs) {
698 3384 : bool ok = true;
699 : // get the id, throw if not given or empty...
700 3384 : std::string id = attrs.get<std::string>(SUMO_ATTR_ID, nullptr, ok);
701 3384 : if (!ok) {
702 0 : throw ProcessError();
703 : }
704 : if (MSTriggeredRerouter::getInstances().count(id) > 0) {
705 14 : throw InvalidArgument("Could not build rerouter '" + id + "'; probably declared twice.");
706 : }
707 : MSEdgeVector edges;
708 7888 : for (const std::string& edgeID : attrs.get<std::vector<std::string> >(SUMO_ATTR_EDGES, id.c_str(), ok)) {
709 4511 : MSEdge* edge = MSEdge::dictionary(edgeID);
710 4511 : if (edge == nullptr) {
711 0 : throw InvalidArgument("The edge '" + edgeID + "' to use within rerouter '" + id + "' is not known.");
712 : }
713 4511 : edges.push_back(edge);
714 3377 : }
715 3377 : if (!ok) {
716 0 : throw InvalidArgument("The edge to use within rerouter '" + id + "' is not known.");
717 : }
718 3377 : if (edges.size() == 0) {
719 0 : throw InvalidArgument("No edges found for rerouter '" + id + "'.");
720 : }
721 3377 : const double prob = attrs.getOpt<double>(SUMO_ATTR_PROB, id.c_str(), ok, 1);
722 3377 : const bool off = attrs.getOpt<bool>(SUMO_ATTR_OFF, id.c_str(), ok, false);
723 3377 : const bool optional = attrs.getOpt<bool>(SUMO_ATTR_OPTIONAL, id.c_str(), ok, false);
724 3377 : const SUMOTime timeThreshold = TIME2STEPS(attrs.getOpt<double>(SUMO_ATTR_HALTING_TIME_THRESHOLD, id.c_str(), ok, 0));
725 3377 : const std::string vTypes = attrs.getOpt<std::string>(SUMO_ATTR_VTYPES, id.c_str(), ok, "");
726 3377 : const std::string pos = attrs.getOpt<std::string>(SUMO_ATTR_POSITION, id.c_str(), ok, "");
727 3377 : Position p = Position::INVALID;
728 3377 : if (pos != "") {
729 609 : const std::vector<std::string> posSplit = StringTokenizer(pos, ",").getVector();
730 203 : if (posSplit.size() == 1) {
731 4 : p = edges.front()->getLanes()[0]->geometryPositionAtOffset(StringUtils::toDouble(posSplit[0]));
732 201 : } else if (posSplit.size() == 2) {
733 201 : p = Position(StringUtils::toDouble(posSplit[0]), StringUtils::toDouble(posSplit[1]));
734 0 : } else if (posSplit.size() == 3) {
735 0 : p = Position(StringUtils::toDouble(posSplit[0]), StringUtils::toDouble(posSplit[1]), StringUtils::toDouble(posSplit[2]));
736 : } else {
737 0 : throw InvalidArgument("Invalid position for rerouter '" + id + "'.");
738 : }
739 203 : }
740 3377 : if (!ok) {
741 0 : throw InvalidArgument("Could not parse rerouter '" + id + "'.");
742 : }
743 3377 : MSTriggeredRerouter* trigger = buildRerouter(net, id, edges, prob, off, optional, timeThreshold, vTypes, p);
744 : // read in the trigger description
745 3377 : trigger->registerParent(SUMO_TAG_REROUTER, myHandler);
746 6754 : }
747 :
748 :
749 : // -------------------------
750 :
751 :
752 : MSLaneSpeedTrigger*
753 377 : NLTriggerBuilder::buildLaneSpeedTrigger(MSNet& /*net*/, const std::string& id,
754 : const std::vector<MSLane*>& destLanes,
755 : const std::string& file) {
756 377 : return new MSLaneSpeedTrigger(id, destLanes, file);
757 : }
758 :
759 :
760 : METriggeredCalibrator*
761 84 : NLTriggerBuilder::buildMECalibrator(const std::string& id,
762 : MSEdge* edge,
763 : double pos,
764 : const std::string& file,
765 : const std::string& outfile,
766 : const SUMOTime freq,
767 : MSRouteProbe* probe,
768 : const double invalidJamThreshold,
769 : const std::string& vTypes) {
770 : return new METriggeredCalibrator(id, edge, pos, file, outfile, freq,
771 80 : edge == nullptr ? 0. : MSGlobals::gMesoNet->getSegmentForEdge(*edge, pos)->getLength(),
772 164 : probe, invalidJamThreshold, vTypes);
773 : }
774 :
775 :
776 : MSCalibrator*
777 778 : NLTriggerBuilder::buildCalibrator(const std::string& id,
778 : MSEdge* edge,
779 : MSLane* lane,
780 : MSJunction* node,
781 : double pos,
782 : const std::string& file,
783 : const std::string& outfile,
784 : const SUMOTime freq,
785 : const MSRouteProbe* probe,
786 : const double invalidJamThreshold,
787 : const std::string& vTypes,
788 : const bool local) {
789 : return new MSCalibrator(id, edge, lane, node, pos, file, outfile, freq,
790 : edge == nullptr ? 0. : edge->getLength(),
791 1546 : probe, invalidJamThreshold, vTypes, local, true);
792 : }
793 :
794 :
795 : MSTriggeredRerouter*
796 2716 : NLTriggerBuilder::buildRerouter(MSNet&, const std::string& id,
797 : MSEdgeVector& edges, double prob, bool off, bool optional,
798 : SUMOTime timeThreshold, const std::string& vTypes, const Position& pos) {
799 2716 : return new MSTriggeredRerouter(id, edges, prob, off, optional, timeThreshold, vTypes, pos);
800 : }
801 :
802 :
803 : void
804 37034 : NLTriggerBuilder::buildStoppingPlace(MSNet& net, std::string id, std::vector<std::string> lines, MSLane* lane,
805 : double frompos, double topos, const SumoXMLTag element, std::string ptStopName,
806 : int personCapacity, double parkingLength, RGBColor& color) {
807 74068 : myCurrentStop = new MSStoppingPlace(id, element, lines, *lane, frompos, topos, ptStopName, personCapacity, parkingLength, color);
808 37034 : if (!net.addStoppingPlace(element, myCurrentStop)) {
809 5 : delete myCurrentStop;
810 5 : myCurrentStop = nullptr;
811 10 : throw InvalidArgument("Could not build " + toString(element) + " '" + id + "'; probably declared twice.");
812 : }
813 37029 : }
814 :
815 :
816 : void
817 12577 : NLTriggerBuilder::beginParkingArea(MSNet& net, const std::string& id,
818 : const std::vector<std::string>& lines,
819 : const std::vector<std::string>& badges,
820 : MSLane* lane, double frompos, double topos,
821 : unsigned int capacity,
822 : double width, double length, double angle, const std::string& name,
823 : bool onRoad,
824 : const std::string& departPos,
825 : bool lefthand) {
826 : // Close previous parking area if there are no lots inside
827 12577 : MSParkingArea* stop = new MSParkingArea(id, lines, badges, *lane, frompos, topos, capacity, width, length, angle, name, onRoad, departPos, lefthand);
828 12577 : if (!net.addStoppingPlace(SUMO_TAG_PARKING_AREA, stop)) {
829 0 : delete stop;
830 0 : throw InvalidArgument("Could not build parking area '" + id + "'; probably declared twice.");
831 : } else {
832 12577 : myParkingArea = stop;
833 : }
834 12577 : }
835 :
836 :
837 : void
838 600 : NLTriggerBuilder::addLotEntry(double x, double y, double z,
839 : double width, double length,
840 : double angle, double slope) {
841 600 : if (myParkingArea != nullptr) {
842 600 : if (!myParkingArea->parkOnRoad()) {
843 600 : myParkingArea->addLotEntry(x, y, z, width, length, angle, slope);
844 600 : myParkingAreaCapacitySet = true;
845 : } else {
846 0 : throw InvalidArgument("Cannot not add lot entry to on-road parking area.");
847 : }
848 : } else {
849 0 : throw InvalidArgument("Could not add lot entry outside a parking area.");
850 : }
851 600 : }
852 :
853 :
854 : void
855 12578 : NLTriggerBuilder::endParkingArea() {
856 12578 : if (myParkingArea != nullptr) {
857 12577 : myParkingArea = nullptr;
858 12577 : myParkingAreaCapacitySet = false;
859 : } else {
860 2 : throw InvalidArgument("Could not end a parking area that is not opened.");
861 : }
862 12577 : }
863 :
864 :
865 : void
866 48475 : NLTriggerBuilder::endStoppingPlace() {
867 48475 : if (myCurrentStop != nullptr) {
868 48466 : myCurrentStop = nullptr;
869 : } else {
870 18 : throw InvalidArgument("Could not end a stopping place that is not opened.");
871 : }
872 48466 : }
873 :
874 :
875 : void
876 11437 : NLTriggerBuilder::buildChargingStation(MSNet& net, const std::string& id, MSLane* lane, double frompos, double topos,
877 : const std::string& name, double chargingPower, double efficiency, bool chargeInTransit,
878 : SUMOTime chargeDelay, std::string chargeType, SUMOTime waitingTime, MSParkingArea* parkingArea) {
879 11437 : MSChargingStation* chargingStation = (parkingArea == nullptr) ? new MSChargingStation(id, *lane, frompos, topos, name, chargingPower, efficiency,
880 11437 : chargeInTransit, chargeDelay, chargeType, waitingTime) : new MSChargingStation(id, parkingArea, name, chargingPower, efficiency,
881 0 : chargeInTransit, chargeDelay, chargeType, waitingTime);
882 11437 : if (!net.addStoppingPlace(SUMO_TAG_CHARGING_STATION, chargingStation)) {
883 0 : delete chargingStation;
884 0 : throw InvalidArgument("Could not build charging station '" + id + "'; probably declared twice.");
885 : }
886 11437 : myCurrentStop = chargingStation;
887 11437 : }
888 :
889 :
890 : void
891 46 : NLTriggerBuilder::buildOverheadWireSegment(MSNet& net, const std::string& id, MSLane* lane, double frompos, double topos,
892 : bool voltageSource) {
893 46 : MSOverheadWire* overheadWireSegment = new MSOverheadWire(id, *lane, frompos, topos, voltageSource);
894 46 : if (!net.addStoppingPlace(SUMO_TAG_OVERHEAD_WIRE_SEGMENT, overheadWireSegment)) {
895 0 : delete overheadWireSegment;
896 0 : throw InvalidArgument("Could not build overheadWireSegment '" + id + "'; probably declared twice.");
897 : }
898 46 : }
899 :
900 : void
901 4 : NLTriggerBuilder::buildInnerOverheadWireSegments(MSNet& net, const MSLane* connection, const MSLane* frontConnection, const MSLane* behindConnection) {
902 4 : if (frontConnection == NULL && behindConnection == NULL) {
903 8 : buildOverheadWireSegment(net, "ovrhd_inner_" + connection->getID(), const_cast<MSLane*>(connection), 0, connection->getLength(), false);
904 0 : } else if (frontConnection != NULL && behindConnection == NULL) {
905 0 : buildOverheadWireSegment(net, "ovrhd_inner_" + frontConnection->getID(), const_cast<MSLane*>(frontConnection), 0, frontConnection->getLength(), false);
906 0 : buildOverheadWireSegment(net, "ovrhd_inner_" + connection->getID(), const_cast<MSLane*>(connection), 0, connection->getLength(), false);
907 0 : } else if (frontConnection == NULL && behindConnection != NULL) {
908 0 : buildOverheadWireSegment(net, "ovrhd_inner_" + behindConnection->getID(), const_cast<MSLane*>(behindConnection), 0, behindConnection->getLength(), false);
909 0 : buildOverheadWireSegment(net, "ovrhd_inner_" + connection->getID(), const_cast<MSLane*>(connection), 0, connection->getLength(), false);
910 0 : } else if (frontConnection != NULL && behindConnection != NULL) {
911 0 : buildOverheadWireSegment(net, "ovrhd_inner_" + frontConnection->getID(), const_cast<MSLane*>(frontConnection), 0, frontConnection->getLength(), false);
912 0 : buildOverheadWireSegment(net, "ovrhd_inner_" + behindConnection->getID(), const_cast<MSLane*>(behindConnection), 0, behindConnection->getLength(), false);
913 0 : buildOverheadWireSegment(net, "ovrhd_inner_" + connection->getID(), const_cast<MSLane*>(connection), 0, connection->getLength(), false);
914 : }
915 4 : }
916 :
917 : void
918 8 : NLTriggerBuilder::buildTractionSubstation(MSNet& net, std::string id, double voltage, double currentLimit) {
919 8 : MSTractionSubstation* myTractionSubstation = new MSTractionSubstation(id, voltage, currentLimit);
920 8 : if (!net.addTractionSubstation(myTractionSubstation)) {
921 0 : delete myTractionSubstation;
922 0 : throw InvalidArgument("Could not build traction substation '" + id + "'; probably declared twice.");
923 : }
924 8 : }
925 :
926 : void
927 10 : NLTriggerBuilder::buildOverheadWireClamp(MSNet& /*net*/, const std::string& /*id*/, MSLane* /*lane_start*/, MSLane* /*lane_end*/) {
928 10 : }
929 :
930 : std::string
931 1339 : NLTriggerBuilder::getFileName(const SUMOSAXAttributes& attrs,
932 : const std::string& base,
933 : const bool allowEmpty) {
934 : // get the file name to read further definitions from
935 1339 : bool ok = true;
936 1339 : std::string file = attrs.getOpt<std::string>(SUMO_ATTR_FILE, nullptr, ok, "");
937 1339 : if (file == "") {
938 1129 : if (allowEmpty) {
939 1129 : return file;
940 : }
941 0 : throw InvalidArgument("No filename given.");
942 : }
943 : // check whether absolute or relative filenames are given
944 210 : if (!FileHelpers::isAbsolute(file)) {
945 210 : return FileHelpers::getConfigurationRelative(base, file);
946 : }
947 0 : return file;
948 : }
949 :
950 :
951 : MSLane*
952 66346 : NLTriggerBuilder::getLane(const SUMOSAXAttributes& attrs,
953 : const std::string& tt,
954 : const std::string& tid) {
955 66346 : bool ok = true;
956 66346 : std::string objectid = attrs.get<std::string>(SUMO_ATTR_LANE, tid.c_str(), ok);
957 66346 : MSLane* lane = MSLane::dictionary(objectid);
958 66346 : if (lane == nullptr) {
959 : // Either a lane that is non-existent/broken, or a lane that is internal and has been ignored.
960 : // We assume that internal lane names start with ':'.
961 0 : if (objectid[0] == ':' && !MSGlobals::gUsingInternalLanes) {
962 : return nullptr;
963 : }
964 : // Throw the exception only in case that the lane really does not exist in the network file
965 : // or it is broken.
966 0 : throw InvalidArgument("The lane " + objectid + " to use within the " + tt + " '" + tid + "' is not known.");
967 : }
968 : return lane;
969 : }
970 :
971 :
972 : MSParkingArea*
973 11686 : NLTriggerBuilder::getParkingArea(const SUMOSAXAttributes& attrs, const std::string& tt, const std::string& tid) {
974 11686 : bool ok = true;
975 11686 : std::string objectID = attrs.getOpt<std::string>(SUMO_ATTR_PARKING_AREA, tid.c_str(), ok);
976 11686 : if (!ok || objectID.size() == 0) {
977 : return nullptr;
978 : }
979 0 : MSParkingArea* pa = static_cast<MSParkingArea*>(MSNet::getInstance()->getStoppingPlace(objectID, SUMO_TAG_PARKING_AREA));
980 0 : if (pa == nullptr) {
981 : // Throw the exception only in case that the lane really does not exist in the network file
982 : // or it is broken.
983 0 : throw InvalidArgument("The parkingArea " + objectID + " to use within the " + tt + " '" + tid + "' is not known.");
984 : }
985 : return pa;
986 : }
987 :
988 :
989 : double
990 849 : NLTriggerBuilder::getPosition(const SUMOSAXAttributes& attrs,
991 : MSLane* lane,
992 : const std::string& tt, const std::string& tid,
993 : MSEdge* edge) {
994 : assert(lane != nullptr || edge != nullptr);
995 849 : const double length = lane != nullptr ? lane->getLength() : edge->getLength();
996 849 : bool ok = true;
997 849 : double pos = attrs.get<double>(SUMO_ATTR_POSITION, nullptr, ok);
998 849 : const bool friendlyPos = attrs.getOpt<bool>(SUMO_ATTR_FRIENDLY_POS, nullptr, ok, false);
999 849 : if (!ok) {
1000 0 : throw InvalidArgument("Error on parsing a position information.");
1001 : }
1002 849 : if (pos < 0) {
1003 2 : pos = length + pos;
1004 : }
1005 849 : if (pos > length) {
1006 1 : if (friendlyPos) {
1007 0 : pos = length - (double) 0.1;
1008 : } else {
1009 1 : if (lane != nullptr) {
1010 2 : throw InvalidArgument("The position of " + tt + " '" + tid + "' lies beyond the lane's '" + lane->getID() + "' length.");
1011 : } else {
1012 0 : throw InvalidArgument("The position of " + tt + " '" + tid + "' lies beyond the edge's '" + edge->getID() + "' length.");
1013 : }
1014 : }
1015 : }
1016 848 : return pos;
1017 : }
1018 :
1019 :
1020 : void
1021 13285 : NLTriggerBuilder::updateParkingAreaDefaultCapacity() {
1022 13285 : if (myParkingArea != nullptr && !myParkingAreaCapacitySet) {
1023 9625 : myParkingArea->setRoadsideCapacity(1);
1024 : }
1025 13285 : }
1026 :
1027 :
1028 : MSStoppingPlace*
1029 63680 : NLTriggerBuilder::getCurrentStop() {
1030 63680 : return myParkingArea == nullptr ? myCurrentStop : myParkingArea;
1031 : }
1032 :
1033 :
1034 : /****************************************************************************/
|