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