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 43238 : NLTriggerBuilder::NLTriggerBuilder()
61 43238 : : myHandler(nullptr), myParkingArea(nullptr), myCurrentStop(nullptr) {}
62 :
63 :
64 43238 : NLTriggerBuilder::~NLTriggerBuilder() {}
65 :
66 : void
67 43238 : NLTriggerBuilder::setHandler(NLHandler* handler) {
68 43238 : myHandler = handler;
69 43238 : }
70 :
71 :
72 : void
73 542 : NLTriggerBuilder::buildVaporizer(const SUMOSAXAttributes& attrs) {
74 542 : WRITE_WARNING(TL("Vaporizers are deprecated. Use rerouters instead."));
75 542 : bool ok = true;
76 : // get the id, throw if not given or empty...
77 542 : std::string id = attrs.get<std::string>(SUMO_ATTR_ID, nullptr, ok);
78 542 : if (!ok) {
79 : return;
80 : }
81 530 : MSEdge* e = MSEdge::dictionary(id);
82 530 : if (e == nullptr) {
83 18 : WRITE_ERRORF(TL("Unknown edge ('%') referenced in a vaporizer."), id);
84 6 : return;
85 : }
86 524 : SUMOTime begin = attrs.getSUMOTimeReporting(SUMO_ATTR_BEGIN, nullptr, ok);
87 524 : SUMOTime end = attrs.getSUMOTimeReporting(SUMO_ATTR_END, nullptr, ok);
88 524 : if (!ok) {
89 : return;
90 : }
91 488 : if (begin < 0) {
92 18 : WRITE_ERRORF(TL("A vaporization begin time is negative (edge id='%')."), id);
93 6 : return;
94 : }
95 482 : if (begin >= end) {
96 36 : WRITE_ERRORF(TL("A vaporization ends before it starts (edge id='%')."), id);
97 12 : return;
98 : }
99 940 : if (end >= string2time(OptionsCont::getOptions().getString("begin"))) {
100 470 : Command* cb = new WrappingCommand< MSEdge >(e, &MSEdge::incVaporization);
101 470 : MSNet::getInstance()->getBeginOfTimestepEvents()->addEvent(cb, begin);
102 470 : Command* ce = new WrappingCommand< MSEdge >(e, &MSEdge::decVaporization);
103 470 : MSNet::getInstance()->getBeginOfTimestepEvents()->addEvent(ce, end);
104 : }
105 : }
106 :
107 :
108 : void
109 507 : NLTriggerBuilder::parseAndBuildLaneSpeedTrigger(MSNet& net, const SUMOSAXAttributes& attrs,
110 : const std::string& base) {
111 : // get the id, throw if not given or empty...
112 507 : bool ok = true;
113 : // get the id, throw if not given or empty...
114 507 : std::string id = attrs.get<std::string>(SUMO_ATTR_ID, nullptr, ok);
115 507 : if (!ok) {
116 : return;
117 : }
118 : // get the file name to read further definitions from
119 507 : std::string file = getFileName(attrs, base, true);
120 507 : std::string objectid = attrs.get<std::string>(SUMO_ATTR_LANES, id.c_str(), ok);
121 : std::vector<MSLane*> lanes;
122 1068 : for (const std::string& laneID : attrs.get<std::vector<std::string> >(SUMO_ATTR_LANES, id.c_str(), ok)) {
123 561 : MSLane* lane = MSLane::dictionary(laneID);
124 561 : if (lane == nullptr) {
125 0 : throw InvalidArgument("The lane '" + laneID + "' to use within MSLaneSpeedTrigger '" + id + "' is not known.");
126 : }
127 561 : lanes.push_back(lane);
128 507 : }
129 507 : if (!ok) {
130 0 : throw InvalidArgument("The lanes to use within MSLaneSpeedTrigger '" + id + "' are not known.");
131 : }
132 507 : if (lanes.size() == 0) {
133 0 : throw InvalidArgument("No lane defined for MSLaneSpeedTrigger '" + id + "'.");
134 : }
135 : try {
136 507 : MSLaneSpeedTrigger* trigger = buildLaneSpeedTrigger(net, id, lanes, file);
137 507 : if (file == "") {
138 339 : trigger->registerParent(SUMO_TAG_VSS, myHandler);
139 : }
140 0 : } catch (ProcessError& e) {
141 0 : throw InvalidArgument(e.what());
142 0 : }
143 507 : }
144 :
145 :
146 : void
147 11908 : NLTriggerBuilder::parseAndBuildChargingStation(MSNet& net, const SUMOSAXAttributes& attrs) {
148 11908 : bool ok = true;
149 :
150 : // get the id, throw if not given or empty...
151 11908 : std::string id = attrs.get<std::string>(SUMO_ATTR_ID, nullptr, ok);
152 11908 : if (!ok) {
153 0 : throw ProcessError();
154 : }
155 :
156 23816 : MSLane* const lane = getLane(attrs, "chargingStation", id);
157 11908 : double frompos = attrs.getOpt<double>(SUMO_ATTR_STARTPOS, id.c_str(), ok, 0);
158 11908 : double topos = attrs.getOpt<double>(SUMO_ATTR_ENDPOS, id.c_str(), ok, lane->getLength());
159 11908 : const double chargingPower = attrs.getOpt<double>(SUMO_ATTR_CHARGINGPOWER, id.c_str(), ok, 22000);
160 11908 : const double efficiency = attrs.getOpt<double>(SUMO_ATTR_EFFICIENCY, id.c_str(), ok, 0.95);
161 11908 : const bool chargeInTransit = attrs.getOpt<bool>(SUMO_ATTR_CHARGEINTRANSIT, id.c_str(), ok, 0);
162 11908 : const SUMOTime chargeDelay = attrs.getOptSUMOTimeReporting(SUMO_ATTR_CHARGEDELAY, id.c_str(), ok, 0);
163 23824 : const std::string chargeType = attrs.getOpt<std::string>(SUMO_ATTR_CHARGETYPE, id.c_str(), ok, "normal");
164 11908 : const SUMOTime waitingTime = attrs.getOptSUMOTimeReporting(SUMO_ATTR_WAITINGTIME, id.c_str(), ok, 900);
165 11908 : const bool friendlyPos = attrs.getOpt<bool>(SUMO_ATTR_FRIENDLY_POS, id.c_str(), ok, false);
166 11916 : const std::string name = attrs.getOpt<std::string>(SUMO_ATTR_NAME, id.c_str(), ok, "");
167 23816 : MSParkingArea* parkingArea = getParkingArea(attrs, "parkingArea", id);
168 :
169 : // check charge type
170 11908 : if ((chargeType != "normal") && (chargeType != "battery-exchange") && (chargeType != "fuel")) {
171 14 : throw InvalidArgument("The chargeType to use within MSLaneSpeedTrigger '" + id + "' is invalid.");
172 : }
173 :
174 11901 : 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 35708 : buildChargingStation(net, id, lane, frompos, topos, name, chargingPower, efficiency, chargeInTransit, chargeDelay, chargeType, waitingTime, parkingArea);
179 11900 : }
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 39247 : NLTriggerBuilder::parseAndBuildStoppingPlace(MSNet& net, const SUMOSAXAttributes& attrs, const SumoXMLTag element) {
486 39247 : bool ok = true;
487 : // get the id, throw if not given or empty...
488 39247 : std::string id = attrs.get<std::string>(SUMO_ATTR_ID, nullptr, ok);
489 39247 : if (!ok) {
490 0 : throw ProcessError();
491 : }
492 :
493 : //get the name, leave blank if not given
494 78505 : 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 39247 : RGBColor color = attrs.getOpt<RGBColor>(SUMO_ATTR_COLOR, id.c_str(), ok, RGBColor::INVISIBLE);
499 :
500 78494 : MSLane* lane = getLane(attrs, toString(element), id);
501 : // get the positions
502 39247 : double frompos = attrs.getOpt<double>(SUMO_ATTR_STARTPOS, id.c_str(), ok, 0.);
503 39247 : double topos = attrs.getOpt<double>(SUMO_ATTR_ENDPOS, id.c_str(), ok, lane->getLength());
504 39247 : const bool friendlyPos = attrs.getOpt<bool>(SUMO_ATTR_FRIENDLY_POS, id.c_str(), ok, false);
505 39247 : 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 39255 : 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 39244 : if (element != SUMO_TAG_CONTAINER_STOP) {
512 29025 : defaultCapacity = MAX2(MSStoppingPlace::getTransportablesAbreast(topos - frompos, element) * 3, 6);
513 : capacityAttr = SUMO_ATTR_PERSON_CAPACITY;
514 : } else {
515 10219 : defaultCapacity = MSStoppingPlace::getTransportablesAbreast(topos - frompos, element);
516 : capacityAttr = SUMO_ATTR_CONTAINER_CAPACITY;
517 : }
518 39244 : const int transportableCapacity = attrs.getOpt<int>(capacityAttr, id.c_str(), ok, defaultCapacity);
519 39244 : const double parkingLength = attrs.getOpt<double>(SUMO_ATTR_PARKING_LENGTH, id.c_str(), ok, 0);
520 : // build the bus stop
521 156984 : buildStoppingPlace(net, id, lines, lane, frompos, topos, element, ptStopName, transportableCapacity, parkingLength, color);
522 78480 : }
523 :
524 :
525 : void
526 2276 : NLTriggerBuilder::addAccess(MSNet& /* net */, const SUMOSAXAttributes& attrs) {
527 2276 : if (myCurrentStop == nullptr) {
528 30 : throw InvalidArgument("Could not add access outside a stopping place.");
529 : }
530 : // get the lane
531 4522 : MSLane* lane = getLane(attrs, "access", myCurrentStop->getID());
532 2261 : 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 2261 : bool ok = true;
538 2261 : const std::string accessPos = attrs.getOpt<std::string>(SUMO_ATTR_POSITION, "access", ok);
539 2261 : const bool random = accessPos == "random";
540 : MSStoppingPlace::AccessExit exit = MSStoppingPlace::AccessExit::PLATFORM;
541 2261 : if (accessPos == "doors") {
542 : exit = MSStoppingPlace::AccessExit::DOORS;
543 2229 : } else if (accessPos == "carriage") {
544 : exit = MSStoppingPlace::AccessExit::CARRIAGE;
545 : }
546 2261 : double startPos = random || exit != MSStoppingPlace::AccessExit::PLATFORM ? 0. : attrs.getOpt<double>(SUMO_ATTR_POSITION, "access", ok, 0);
547 2261 : double endPos = random || exit != MSStoppingPlace::AccessExit::PLATFORM ? lane->getLength() : startPos;
548 2261 : const double length = attrs.getOpt<double>(SUMO_ATTR_LENGTH, "access", ok, -1);
549 2261 : const bool friendlyPos = attrs.getOpt<bool>(SUMO_ATTR_FRIENDLY_POS, "access", ok, false);
550 2261 : 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 2261 : 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 13516 : NLTriggerBuilder::parseAndBeginParkingArea(MSNet& net, const SUMOSAXAttributes& attrs) {
562 13516 : bool ok = true;
563 : // get the id, throw if not given or empty...
564 13516 : std::string id = attrs.get<std::string>(SUMO_ATTR_ID, nullptr, ok);
565 13516 : if (!ok) {
566 0 : throw ProcessError();
567 : }
568 : // get the lane
569 27032 : MSLane* lane = getLane(attrs, "parkingArea", id);
570 : // get the positions
571 13516 : double frompos = attrs.getOpt<double>(SUMO_ATTR_STARTPOS, id.c_str(), ok, 0);
572 13516 : double topos = attrs.getOpt<double>(SUMO_ATTR_ENDPOS, id.c_str(), ok, lane->getLength());
573 13516 : const bool friendlyPos = attrs.getOpt<bool>(SUMO_ATTR_FRIENDLY_POS, id.c_str(), ok, false);
574 13516 : unsigned int capacity = attrs.getOpt<int>(SUMO_ATTR_ROADSIDE_CAPACITY, id.c_str(), ok, 0);
575 13516 : myParkingAreaCapacitySet = attrs.hasAttribute(SUMO_ATTR_ROADSIDE_CAPACITY);
576 13516 : bool onRoad = attrs.getOpt<bool>(SUMO_ATTR_ONROAD, id.c_str(), ok, false);
577 13516 : double width = attrs.getOpt<double>(SUMO_ATTR_WIDTH, id.c_str(), ok, 0);
578 13516 : double length = attrs.getOpt<double>(SUMO_ATTR_LENGTH, id.c_str(), ok, 0);
579 13516 : double angle = attrs.getOpt<double>(SUMO_ATTR_ANGLE, id.c_str(), ok, 0);
580 27033 : const std::string name = attrs.getOpt<std::string>(SUMO_ATTR_NAME, id.c_str(), ok);
581 27033 : const std::string departPos = attrs.getOpt<std::string>(SUMO_ATTR_DEPARTPOS, id.c_str(), ok);
582 13516 : bool lefthand = attrs.getOpt<bool>(SUMO_ATTR_LEFTHAND, id.c_str(), ok, false);
583 13517 : const std::vector<std::string>& acceptedBadges = attrs.getOpt<std::vector<std::string> >(SUMO_ATTR_ACCEPTED_BADGES, id.c_str(), ok);
584 :
585 13516 : 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 13515 : 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 13515 : beginParkingArea(net, id, lines, acceptedBadges, lane, frompos, topos, capacity, width, length, angle, name, onRoad, departPos, lefthand);
591 27031 : }
592 :
593 :
594 :
595 : void
596 670 : NLTriggerBuilder::parseAndAddLotEntry(const SUMOSAXAttributes& attrs) {
597 670 : bool ok = true;
598 : // Check for open parking area
599 670 : if (myParkingArea == nullptr) {
600 0 : throw ProcessError();
601 : }
602 : // get the positions
603 670 : double x = attrs.get<double>(SUMO_ATTR_X, "", ok);
604 670 : if (!ok) {
605 0 : throw InvalidArgument("Invalid x position for lot entry.");
606 : }
607 670 : double y = attrs.get<double>(SUMO_ATTR_Y, "", ok);
608 670 : if (!ok) {
609 0 : throw InvalidArgument("Invalid y position for lot entry.");
610 : }
611 670 : double z = attrs.getOpt<double>(SUMO_ATTR_Z, "", ok, 0.);
612 670 : double width = attrs.getOpt<double>(SUMO_ATTR_WIDTH, "", ok, myParkingArea->getWidth());
613 670 : double length = attrs.getOpt<double>(SUMO_ATTR_LENGTH, "", ok, myParkingArea->getLength());
614 670 : double angle = attrs.getOpt<double>(SUMO_ATTR_ANGLE, "", ok, myParkingArea->getAngle());
615 670 : double slope = attrs.getOpt<double>(SUMO_ATTR_SLOPE, "", ok, 0.);
616 : // add the lot entry
617 670 : addLotEntry(x, y, z, width, length, angle, slope);
618 670 : }
619 :
620 :
621 : void
622 953 : NLTriggerBuilder::parseAndBuildCalibrator(MSNet& net, const SUMOSAXAttributes& attrs,
623 : const std::string& base) {
624 953 : bool ok = true;
625 : // get the id, throw if not given or empty...
626 953 : std::string id = attrs.get<std::string>(SUMO_ATTR_ID, nullptr, ok);
627 953 : if (!ok) {
628 0 : throw ProcessError();
629 : }
630 : MSLane* lane = nullptr;
631 : MSEdge* edge = nullptr;
632 : MSJunction* node = nullptr;
633 953 : 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 939 : if (attrs.hasAttribute(SUMO_ATTR_EDGE)) {
644 479 : const std::string edgeID = attrs.get<std::string>(SUMO_ATTR_EDGE, id.c_str(), ok);
645 479 : edge = MSEdge::dictionary(edgeID);
646 479 : if (edge == nullptr) {
647 0 : throw InvalidArgument("The edge " + edgeID + " to use within the calibrator '" + id + "' is not known.");
648 : }
649 479 : 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 920 : lane = getLane(attrs, "calibrator", id);
658 : edge = &lane->getEdge();
659 : }
660 : }
661 953 : const double pos = node != nullptr ? 0 : getPosition(attrs, lane, "calibrator", id, edge);
662 952 : const SUMOTime period = attrs.getOptPeriod(id.c_str(), ok, DELTA_T); // !!! no error handling
663 953 : const std::string vTypes = attrs.getOpt<std::string>(SUMO_ATTR_VTYPES, id.c_str(), ok, "");
664 952 : const std::string file = getFileName(attrs, base, true);
665 952 : const std::string outfile = attrs.getOpt<std::string>(SUMO_ATTR_OUTPUT, id.c_str(), ok, "");
666 952 : 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 1820 : const double invalidJamThreshold = attrs.getOpt<double>(SUMO_ATTR_JAM_DIST_THRESHOLD, id.c_str(), ok, MSGlobals::gUseMesoSim ? 0.8 : 0.5);
669 952 : const bool local = attrs.getOpt<bool>(SUMO_ATTR_LOCAL, id.c_str(), ok, false);
670 : MSRouteProbe* probe = nullptr;
671 952 : 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 952 : 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 868 : MSCalibrator* trigger = buildCalibrator(id, edge, lane, node, pos, file, outfile, period, probe, invalidJamThreshold, vTypes, local);
689 868 : if (file == "") {
690 838 : trigger->registerParent(SUMO_TAG_CALIBRATOR, myHandler);
691 : }
692 : }
693 952 : }
694 :
695 :
696 : void
697 3425 : NLTriggerBuilder::parseAndBuildRerouter(MSNet& net, const SUMOSAXAttributes& attrs) {
698 3425 : bool ok = true;
699 : // get the id, throw if not given or empty...
700 3425 : std::string id = attrs.get<std::string>(SUMO_ATTR_ID, nullptr, ok);
701 3425 : 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 7970 : for (const std::string& edgeID : attrs.get<std::vector<std::string> >(SUMO_ATTR_EDGES, id.c_str(), ok)) {
709 4552 : MSEdge* edge = MSEdge::dictionary(edgeID);
710 4552 : if (edge == nullptr) {
711 0 : throw InvalidArgument("The edge '" + edgeID + "' to use within rerouter '" + id + "' is not known.");
712 : }
713 4552 : edges.push_back(edge);
714 3418 : }
715 3418 : if (!ok) {
716 0 : throw InvalidArgument("The edge to use within rerouter '" + id + "' is not known.");
717 : }
718 3418 : if (edges.size() == 0) {
719 0 : throw InvalidArgument("No edges found for rerouter '" + id + "'.");
720 : }
721 3418 : const double prob = attrs.getOpt<double>(SUMO_ATTR_PROB, id.c_str(), ok, 1);
722 3418 : const bool off = attrs.getOpt<bool>(SUMO_ATTR_OFF, id.c_str(), ok, false);
723 3418 : const bool optional = attrs.getOpt<bool>(SUMO_ATTR_OPTIONAL, id.c_str(), ok, false);
724 3418 : const SUMOTime timeThreshold = TIME2STEPS(attrs.getOpt<double>(SUMO_ATTR_HALTING_TIME_THRESHOLD, id.c_str(), ok, 0));
725 3418 : const std::string vTypes = attrs.getOpt<std::string>(SUMO_ATTR_VTYPES, id.c_str(), ok, "");
726 6836 : const std::string pos = attrs.getOpt<std::string>(SUMO_ATTR_POSITION, id.c_str(), ok, "");
727 3418 : const double radius = attrs.getOpt<double>(SUMO_ATTR_RADIUS, id.c_str(), ok, std::numeric_limits<double>::max());
728 3418 : Position p = Position::INVALID;
729 3418 : if (pos != "") {
730 699 : const std::vector<std::string> posSplit = StringTokenizer(pos, ",").getVector();
731 233 : if (posSplit.size() == 1) {
732 4 : p = edges.front()->getLanes()[0]->geometryPositionAtOffset(StringUtils::toDouble(posSplit[0]));
733 231 : } else if (posSplit.size() == 2) {
734 231 : p = Position(StringUtils::toDouble(posSplit[0]), StringUtils::toDouble(posSplit[1]));
735 0 : } else if (posSplit.size() == 3) {
736 0 : p = Position(StringUtils::toDouble(posSplit[0]), StringUtils::toDouble(posSplit[1]), StringUtils::toDouble(posSplit[2]));
737 : } else {
738 0 : throw InvalidArgument("Invalid position for rerouter '" + id + "'.");
739 : }
740 233 : }
741 3418 : if (!ok) {
742 0 : throw InvalidArgument("Could not parse rerouter '" + id + "'.");
743 : }
744 3418 : MSTriggeredRerouter* trigger = buildRerouter(net, id, edges, prob, off, optional, timeThreshold, vTypes, p, radius);
745 : // read in the trigger description
746 3418 : trigger->registerParent(SUMO_TAG_REROUTER, myHandler);
747 6836 : }
748 :
749 :
750 : // -------------------------
751 :
752 :
753 : MSLaneSpeedTrigger*
754 407 : NLTriggerBuilder::buildLaneSpeedTrigger(MSNet& /*net*/, const std::string& id,
755 : const std::vector<MSLane*>& destLanes,
756 : const std::string& file) {
757 407 : return new MSLaneSpeedTrigger(id, destLanes, file);
758 : }
759 :
760 :
761 : METriggeredCalibrator*
762 84 : NLTriggerBuilder::buildMECalibrator(const std::string& id,
763 : MSEdge* edge,
764 : double pos,
765 : const std::string& file,
766 : const std::string& outfile,
767 : const SUMOTime freq,
768 : MSRouteProbe* probe,
769 : const double invalidJamThreshold,
770 : const std::string& vTypes) {
771 : return new METriggeredCalibrator(id, edge, pos, file, outfile, freq,
772 80 : edge == nullptr ? 0. : MSGlobals::gMesoNet->getSegmentForEdge(*edge, pos)->getLength(),
773 164 : probe, invalidJamThreshold, vTypes);
774 : }
775 :
776 :
777 : MSCalibrator*
778 868 : NLTriggerBuilder::buildCalibrator(const std::string& id,
779 : MSEdge* edge,
780 : MSLane* lane,
781 : MSJunction* node,
782 : double pos,
783 : const std::string& file,
784 : const std::string& outfile,
785 : const SUMOTime freq,
786 : const MSRouteProbe* probe,
787 : const double invalidJamThreshold,
788 : const std::string& vTypes,
789 : const bool local) {
790 : return new MSCalibrator(id, edge, lane, node, pos, file, outfile, freq,
791 : edge == nullptr ? 0. : edge->getLength(),
792 1726 : probe, invalidJamThreshold, vTypes, local, true);
793 : }
794 :
795 :
796 : MSTriggeredRerouter*
797 2758 : NLTriggerBuilder::buildRerouter(MSNet&, const std::string& id,
798 : MSEdgeVector& edges, double prob, bool off, bool optional,
799 : SUMOTime timeThreshold, const std::string& vTypes, const Position& pos, const double radius) {
800 2758 : return new MSTriggeredRerouter(id, edges, prob, off, optional, timeThreshold, vTypes, pos, radius);
801 : }
802 :
803 :
804 : void
805 37543 : NLTriggerBuilder::buildStoppingPlace(MSNet& net, std::string id, std::vector<std::string> lines, MSLane* lane,
806 : double frompos, double topos, const SumoXMLTag element, std::string ptStopName,
807 : int personCapacity, double parkingLength, RGBColor& color) {
808 75086 : myCurrentStop = new MSStoppingPlace(id, element, lines, *lane, frompos, topos, ptStopName, personCapacity, parkingLength, color);
809 37543 : if (!net.addStoppingPlace(element, myCurrentStop)) {
810 5 : delete myCurrentStop;
811 5 : myCurrentStop = nullptr;
812 10 : throw InvalidArgument("Could not build " + toString(element) + " '" + id + "'; probably declared twice.");
813 : }
814 37538 : }
815 :
816 :
817 : void
818 12789 : NLTriggerBuilder::beginParkingArea(MSNet& net, const std::string& id,
819 : const std::vector<std::string>& lines,
820 : const std::vector<std::string>& badges,
821 : MSLane* lane, double frompos, double topos,
822 : unsigned int capacity,
823 : double width, double length, double angle, const std::string& name,
824 : bool onRoad,
825 : const std::string& departPos,
826 : bool lefthand) {
827 : // Close previous parking area if there are no lots inside
828 12789 : MSParkingArea* stop = new MSParkingArea(id, lines, badges, *lane, frompos, topos, capacity, width, length, angle, name, onRoad, departPos, lefthand);
829 12789 : if (!net.addStoppingPlace(SUMO_TAG_PARKING_AREA, stop)) {
830 0 : delete stop;
831 0 : throw InvalidArgument("Could not build parking area '" + id + "'; probably declared twice.");
832 : } else {
833 12789 : myParkingArea = stop;
834 : }
835 12789 : }
836 :
837 :
838 : void
839 670 : NLTriggerBuilder::addLotEntry(double x, double y, double z,
840 : double width, double length,
841 : double angle, double slope) {
842 670 : if (myParkingArea != nullptr) {
843 670 : if (!myParkingArea->parkOnRoad()) {
844 670 : myParkingArea->addLotEntry(x, y, z, width, length, angle, slope);
845 670 : myParkingAreaCapacitySet = true;
846 : } else {
847 0 : throw InvalidArgument("Cannot not add lot entry to on-road parking area.");
848 : }
849 : } else {
850 0 : throw InvalidArgument("Could not add lot entry outside a parking area.");
851 : }
852 670 : }
853 :
854 :
855 : void
856 12790 : NLTriggerBuilder::endParkingArea() {
857 12790 : if (myParkingArea != nullptr) {
858 12789 : myParkingArea = nullptr;
859 12789 : myParkingAreaCapacitySet = false;
860 : } else {
861 2 : throw InvalidArgument("Could not end a parking area that is not opened.");
862 : }
863 12789 : }
864 :
865 :
866 : void
867 49183 : NLTriggerBuilder::endStoppingPlace() {
868 49183 : if (myCurrentStop != nullptr) {
869 49167 : myCurrentStop = nullptr;
870 : } else {
871 32 : throw InvalidArgument("Could not end a stopping place that is not opened.");
872 : }
873 49167 : }
874 :
875 :
876 : void
877 11629 : NLTriggerBuilder::buildChargingStation(MSNet& net, const std::string& id, MSLane* lane, double frompos, double topos,
878 : const std::string& name, double chargingPower, double efficiency, bool chargeInTransit,
879 : SUMOTime chargeDelay, std::string chargeType, SUMOTime waitingTime, MSParkingArea* parkingArea) {
880 11629 : MSChargingStation* chargingStation = (parkingArea == nullptr) ? new MSChargingStation(id, *lane, frompos, topos, name, chargingPower, efficiency,
881 11621 : chargeInTransit, chargeDelay, chargeType, waitingTime) : new MSChargingStation(id, parkingArea, name, chargingPower, efficiency,
882 8 : chargeInTransit, chargeDelay, chargeType, waitingTime);
883 11629 : if (!net.addStoppingPlace(SUMO_TAG_CHARGING_STATION, chargingStation)) {
884 0 : delete chargingStation;
885 0 : throw InvalidArgument("Could not build charging station '" + id + "'; probably declared twice.");
886 : }
887 11629 : myCurrentStop = chargingStation;
888 11629 : }
889 :
890 :
891 : void
892 46 : NLTriggerBuilder::buildOverheadWireSegment(MSNet& net, const std::string& id, MSLane* lane, double frompos, double topos,
893 : bool voltageSource) {
894 46 : MSOverheadWire* overheadWireSegment = new MSOverheadWire(id, *lane, frompos, topos, voltageSource);
895 46 : if (!net.addStoppingPlace(SUMO_TAG_OVERHEAD_WIRE_SEGMENT, overheadWireSegment)) {
896 0 : delete overheadWireSegment;
897 0 : throw InvalidArgument("Could not build overheadWireSegment '" + id + "'; probably declared twice.");
898 : }
899 46 : }
900 :
901 : void
902 4 : NLTriggerBuilder::buildInnerOverheadWireSegments(MSNet& net, const MSLane* connection, const MSLane* frontConnection, const MSLane* behindConnection) {
903 4 : if (frontConnection == NULL && behindConnection == NULL) {
904 8 : buildOverheadWireSegment(net, "ovrhd_inner_" + connection->getID(), const_cast<MSLane*>(connection), 0, connection->getLength(), false);
905 0 : } else if (frontConnection != NULL && behindConnection == NULL) {
906 0 : buildOverheadWireSegment(net, "ovrhd_inner_" + frontConnection->getID(), const_cast<MSLane*>(frontConnection), 0, frontConnection->getLength(), false);
907 0 : buildOverheadWireSegment(net, "ovrhd_inner_" + connection->getID(), const_cast<MSLane*>(connection), 0, connection->getLength(), false);
908 0 : } else if (frontConnection == NULL && behindConnection != NULL) {
909 0 : buildOverheadWireSegment(net, "ovrhd_inner_" + behindConnection->getID(), const_cast<MSLane*>(behindConnection), 0, behindConnection->getLength(), false);
910 0 : buildOverheadWireSegment(net, "ovrhd_inner_" + connection->getID(), const_cast<MSLane*>(connection), 0, connection->getLength(), false);
911 0 : } else if (frontConnection != NULL && behindConnection != NULL) {
912 0 : buildOverheadWireSegment(net, "ovrhd_inner_" + frontConnection->getID(), const_cast<MSLane*>(frontConnection), 0, frontConnection->getLength(), false);
913 0 : buildOverheadWireSegment(net, "ovrhd_inner_" + behindConnection->getID(), const_cast<MSLane*>(behindConnection), 0, behindConnection->getLength(), false);
914 0 : buildOverheadWireSegment(net, "ovrhd_inner_" + connection->getID(), const_cast<MSLane*>(connection), 0, connection->getLength(), false);
915 : }
916 4 : }
917 :
918 : void
919 8 : NLTriggerBuilder::buildTractionSubstation(MSNet& net, std::string id, double voltage, double currentLimit) {
920 8 : MSTractionSubstation* myTractionSubstation = new MSTractionSubstation(id, voltage, currentLimit);
921 8 : if (!net.addTractionSubstation(myTractionSubstation)) {
922 0 : delete myTractionSubstation;
923 0 : throw InvalidArgument("Could not build traction substation '" + id + "'; probably declared twice.");
924 : }
925 8 : }
926 :
927 : void
928 10 : NLTriggerBuilder::buildOverheadWireClamp(MSNet& /*net*/, const std::string& /*id*/, MSLane* /*lane_start*/, MSLane* /*lane_end*/) {
929 10 : }
930 :
931 : std::string
932 1459 : NLTriggerBuilder::getFileName(const SUMOSAXAttributes& attrs,
933 : const std::string& base,
934 : const bool allowEmpty) {
935 : // get the file name to read further definitions from
936 1459 : bool ok = true;
937 1459 : std::string file = attrs.getOpt<std::string>(SUMO_ATTR_FILE, nullptr, ok, "");
938 1459 : if (file == "") {
939 1249 : if (allowEmpty) {
940 1249 : return file;
941 : }
942 0 : throw InvalidArgument("No filename given.");
943 : }
944 : // check whether absolute or relative filenames are given
945 210 : if (!FileHelpers::isAbsolute(file)) {
946 210 : return FileHelpers::getConfigurationRelative(base, file);
947 : }
948 0 : return file;
949 : }
950 :
951 :
952 : MSLane*
953 67446 : NLTriggerBuilder::getLane(const SUMOSAXAttributes& attrs,
954 : const std::string& tt,
955 : const std::string& tid) {
956 67446 : bool ok = true;
957 67446 : std::string objectid = attrs.get<std::string>(SUMO_ATTR_LANE, tid.c_str(), ok);
958 67446 : MSLane* lane = MSLane::dictionary(objectid);
959 67446 : if (lane == nullptr) {
960 : // Either a lane that is non-existent/broken, or a lane that is internal and has been ignored.
961 : // We assume that internal lane names start with ':'.
962 0 : if (objectid[0] == ':' && !MSGlobals::gUsingInternalLanes) {
963 : return nullptr;
964 : }
965 : // Throw the exception only in case that the lane really does not exist in the network file
966 : // or it is broken.
967 0 : throw InvalidArgument("The lane " + objectid + " to use within the " + tt + " '" + tid + "' is not known.");
968 : }
969 : return lane;
970 : }
971 :
972 :
973 : MSParkingArea*
974 11908 : NLTriggerBuilder::getParkingArea(const SUMOSAXAttributes& attrs, const std::string& tt, const std::string& tid) {
975 11908 : bool ok = true;
976 11908 : std::string objectID = attrs.getOpt<std::string>(SUMO_ATTR_PARKING_AREA, tid.c_str(), ok);
977 11908 : if (!ok || objectID.size() == 0) {
978 : return nullptr;
979 : }
980 11 : MSParkingArea* pa = static_cast<MSParkingArea*>(MSNet::getInstance()->getStoppingPlace(objectID, SUMO_TAG_PARKING_AREA));
981 11 : if (pa == nullptr) {
982 : // Throw the exception only in case that the lane really does not exist in the network file
983 : // or it is broken.
984 0 : throw InvalidArgument("The parkingArea " + objectID + " to use within the " + tt + " '" + tid + "' is not known.");
985 : }
986 : return pa;
987 : }
988 :
989 :
990 : double
991 939 : NLTriggerBuilder::getPosition(const SUMOSAXAttributes& attrs,
992 : MSLane* lane,
993 : const std::string& tt, const std::string& tid,
994 : MSEdge* edge) {
995 : assert(lane != nullptr || edge != nullptr);
996 939 : const double length = lane != nullptr ? lane->getLength() : edge->getLength();
997 939 : bool ok = true;
998 939 : double pos = attrs.get<double>(SUMO_ATTR_POSITION, nullptr, ok);
999 939 : const bool friendlyPos = attrs.getOpt<bool>(SUMO_ATTR_FRIENDLY_POS, nullptr, ok, false);
1000 939 : if (!ok) {
1001 0 : throw InvalidArgument("Error on parsing a position information.");
1002 : }
1003 939 : if (pos < 0) {
1004 2 : pos = length + pos;
1005 : }
1006 939 : if (pos > length) {
1007 1 : if (friendlyPos) {
1008 0 : pos = length - (double) 0.1;
1009 : } else {
1010 1 : if (lane != nullptr) {
1011 2 : throw InvalidArgument("The position of " + tt + " '" + tid + "' lies beyond the lane's '" + lane->getID() + "' length.");
1012 : } else {
1013 0 : throw InvalidArgument("The position of " + tt + " '" + tid + "' lies beyond the edge's '" + edge->getID() + "' length.");
1014 : }
1015 : }
1016 : }
1017 938 : return pos;
1018 : }
1019 :
1020 :
1021 : void
1022 13516 : NLTriggerBuilder::updateParkingAreaDefaultCapacity() {
1023 13516 : if (myParkingArea != nullptr && !myParkingAreaCapacitySet) {
1024 9709 : myParkingArea->setRoadsideCapacity(1);
1025 : }
1026 13516 : }
1027 :
1028 :
1029 : MSStoppingPlace*
1030 64651 : NLTriggerBuilder::getCurrentStop() {
1031 64651 : return myParkingArea == nullptr ? myCurrentStop : myParkingArea;
1032 : }
1033 :
1034 :
1035 : /****************************************************************************/
|