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 <microsim/MSEventControl.h>
30 : #include <microsim/MSLane.h>
31 : #include <microsim/MSEdge.h>
32 : #include <microsim/MSGlobals.h>
33 : #include <microsim/MSParkingArea.h>
34 : #include <microsim/output/MSDetectorControl.h>
35 : #include <microsim/output/MSRouteProbe.h>
36 : #include <microsim/trigger/MSLaneSpeedTrigger.h>
37 : #include <microsim/trigger/MSTriggeredRerouter.h>
38 : #include <microsim/trigger/MSCalibrator.h>
39 : #include <microsim/MSStoppingPlace.h>
40 : #include <microsim/trigger/MSChargingStation.h>
41 : #include <microsim/trigger/MSOverheadWire.h>
42 : #include <utils/common/StringTokenizer.h>
43 : #include <utils/common/FileHelpers.h>
44 : #include <utils/common/UtilExceptions.h>
45 : #include <utils/common/WrappingCommand.h>
46 : #include <utils/common/RGBColor.h>
47 : #include <utils/options/OptionsCont.h>
48 : #include "NLHandler.h"
49 : #include "NLTriggerBuilder.h"
50 : #include <utils/xml/SUMOXMLDefinitions.h>
51 : #include <utils/xml/XMLSubSys.h>
52 :
53 :
54 : #include <mesosim/MELoop.h>
55 : #include <mesosim/METriggeredCalibrator.h>
56 :
57 :
58 : // ===========================================================================
59 : // method definitions
60 : // ===========================================================================
61 35454 : NLTriggerBuilder::NLTriggerBuilder()
62 35454 : : myHandler(nullptr), myParkingArea(nullptr), myCurrentStop(nullptr) {}
63 :
64 :
65 35454 : NLTriggerBuilder::~NLTriggerBuilder() {}
66 :
67 : void
68 35454 : NLTriggerBuilder::setHandler(NLHandler* handler) {
69 35454 : myHandler = handler;
70 35454 : }
71 :
72 :
73 : void
74 232 : NLTriggerBuilder::buildVaporizer(const SUMOSAXAttributes& attrs) {
75 232 : WRITE_WARNING(TL("Vaporizers are deprecated. Use rerouters instead."));
76 232 : bool ok = true;
77 : // get the id, throw if not given or empty...
78 232 : std::string id = attrs.get<std::string>(SUMO_ATTR_ID, nullptr, ok);
79 232 : if (!ok) {
80 : return;
81 : }
82 220 : MSEdge* e = MSEdge::dictionary(id);
83 220 : if (e == nullptr) {
84 18 : WRITE_ERRORF(TL("Unknown edge ('%') referenced in a vaporizer."), id);
85 6 : return;
86 : }
87 214 : SUMOTime begin = attrs.getSUMOTimeReporting(SUMO_ATTR_BEGIN, nullptr, ok);
88 214 : SUMOTime end = attrs.getSUMOTimeReporting(SUMO_ATTR_END, nullptr, ok);
89 214 : if (!ok) {
90 : return;
91 : }
92 178 : if (begin < 0) {
93 18 : WRITE_ERRORF(TL("A vaporization begin time is negative (edge id='%')."), id);
94 6 : return;
95 : }
96 172 : if (begin >= end) {
97 36 : WRITE_ERRORF(TL("A vaporization ends before it starts (edge id='%')."), id);
98 12 : return;
99 : }
100 320 : if (end >= string2time(OptionsCont::getOptions().getString("begin"))) {
101 160 : Command* cb = new WrappingCommand< MSEdge >(e, &MSEdge::incVaporization);
102 160 : MSNet::getInstance()->getBeginOfTimestepEvents()->addEvent(cb, begin);
103 160 : Command* ce = new WrappingCommand< MSEdge >(e, &MSEdge::decVaporization);
104 160 : MSNet::getInstance()->getBeginOfTimestepEvents()->addEvent(ce, end);
105 : }
106 : }
107 :
108 :
109 : void
110 386 : NLTriggerBuilder::parseAndBuildLaneSpeedTrigger(MSNet& net, const SUMOSAXAttributes& attrs,
111 : const std::string& base) {
112 : // get the id, throw if not given or empty...
113 386 : bool ok = true;
114 : // get the id, throw if not given or empty...
115 386 : std::string id = attrs.get<std::string>(SUMO_ATTR_ID, nullptr, ok);
116 386 : if (!ok) {
117 : return;
118 : }
119 : // get the file name to read further definitions from
120 386 : std::string file = getFileName(attrs, base, true);
121 386 : std::string objectid = attrs.get<std::string>(SUMO_ATTR_LANES, id.c_str(), ok);
122 : std::vector<MSLane*> lanes;
123 924 : for (const std::string& laneID : attrs.get<std::vector<std::string> >(SUMO_ATTR_LANES, id.c_str(), ok)) {
124 538 : MSLane* lane = MSLane::dictionary(laneID);
125 538 : if (lane == nullptr) {
126 0 : throw InvalidArgument("The lane '" + laneID + "' to use within MSLaneSpeedTrigger '" + id + "' is not known.");
127 : }
128 538 : lanes.push_back(lane);
129 386 : }
130 386 : if (!ok) {
131 0 : throw InvalidArgument("The lanes to use within MSLaneSpeedTrigger '" + id + "' are not known.");
132 : }
133 386 : if (lanes.size() == 0) {
134 0 : throw InvalidArgument("No lane defined for MSLaneSpeedTrigger '" + id + "'.");
135 : }
136 : try {
137 386 : MSLaneSpeedTrigger* trigger = buildLaneSpeedTrigger(net, id, lanes, file);
138 386 : if (file == "") {
139 218 : trigger->registerParent(SUMO_TAG_VSS, myHandler);
140 : }
141 0 : } catch (ProcessError& e) {
142 0 : throw InvalidArgument(e.what());
143 0 : }
144 : }
145 :
146 :
147 : void
148 5960 : NLTriggerBuilder::parseAndBuildChargingStation(MSNet& net, const SUMOSAXAttributes& attrs) {
149 5960 : bool ok = true;
150 :
151 : // get the id, throw if not given or empty...
152 5960 : std::string id = attrs.get<std::string>(SUMO_ATTR_ID, nullptr, ok);
153 5960 : if (!ok) {
154 0 : throw ProcessError();
155 : }
156 :
157 11920 : MSLane* const lane = getLane(attrs, "chargingStation", id);
158 5960 : double frompos = attrs.getOpt<double>(SUMO_ATTR_STARTPOS, id.c_str(), ok, 0);
159 5960 : double topos = attrs.getOpt<double>(SUMO_ATTR_ENDPOS, id.c_str(), ok, lane->getLength());
160 5960 : const double chargingPower = attrs.getOpt<double>(SUMO_ATTR_CHARGINGPOWER, id.c_str(), ok, 0);
161 5960 : const double efficiency = attrs.getOpt<double>(SUMO_ATTR_EFFICIENCY, id.c_str(), ok, 0.95);
162 5960 : const bool chargeInTransit = attrs.getOpt<bool>(SUMO_ATTR_CHARGEINTRANSIT, id.c_str(), ok, 0);
163 5960 : const SUMOTime chargeDelay = attrs.getOptSUMOTimeReporting(SUMO_ATTR_CHARGEDELAY, id.c_str(), ok, 0);
164 11921 : const std::string chargeType = attrs.getOpt<std::string>(SUMO_ATTR_CHARGETYPE, id.c_str(), ok, "normal");
165 5960 : const SUMOTime waitingTime = attrs.getOptSUMOTimeReporting(SUMO_ATTR_WAITINGTIME, id.c_str(), ok, 900);
166 5960 : const bool friendlyPos = attrs.getOpt<bool>(SUMO_ATTR_FRIENDLY_POS, id.c_str(), ok, false);
167 5961 : const std::string name = attrs.getOpt<std::string>(SUMO_ATTR_NAME, id.c_str(), ok, "");
168 11920 : MSParkingArea* parkingArea = getParkingArea(attrs, "parkingArea", id);
169 :
170 : // check charge type
171 5981 : if ((chargeType != "normal") && (chargeType != "electric") && (chargeType != "fuel")) {
172 0 : throw InvalidArgument("The chargeType to use within MSLaneSpeedTrigger '" + id + "' is invalid.");
173 : }
174 :
175 5960 : if (!ok || (myHandler->checkStopPos(frompos, topos, lane->getLength(), POSITION_EPS, friendlyPos) != SUMORouteHandler::StopPos::STOPPOS_VALID)) {
176 2 : throw InvalidArgument("Invalid position for charging station '" + id + "'.");
177 : }
178 :
179 17878 : buildChargingStation(net, id, lane, frompos, topos, name, chargingPower, efficiency, chargeInTransit, chargeDelay, chargeType, waitingTime, parkingArea);
180 5959 : }
181 :
182 :
183 : void
184 56 : NLTriggerBuilder::parseAndBuildOverheadWireSegment(MSNet& net, const SUMOSAXAttributes& attrs) {
185 56 : bool ok = true;
186 :
187 : // get the id, throw if not given or empty...
188 56 : std::string id = attrs.get<std::string>(SUMO_ATTR_ID, 0, ok);
189 56 : 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 56 : MSLane* const lane = getLane(attrs, "overheadWireSegment", id);
198 56 : 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 56 : 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 56 : double frompos = attrs.getOpt<double>(SUMO_ATTR_STARTPOS, id.c_str(), ok, 0);
209 56 : double topos = attrs.getOpt<double>(SUMO_ATTR_ENDPOS, id.c_str(), ok, lane->getLength());
210 56 : const bool voltageSource = attrs.getOpt<bool>(SUMO_ATTR_VOLTAGESOURCE, id.c_str(), ok, false);
211 56 : const bool friendlyPos = attrs.getOpt<bool>(SUMO_ATTR_FRIENDLY_POS, id.c_str(), ok, false);
212 :
213 56 : 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 56 : 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 76 : 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 : }
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 8 : NLTriggerBuilder::parseAndBuildTractionSubstation(MSNet& net, const SUMOSAXAttributes& attrs) {
412 8 : bool ok = true;
413 :
414 : // get the id, throw if not given or empty...
415 8 : std::string id = attrs.get<std::string>(SUMO_ATTR_ID, 0, ok);
416 8 : if (!ok) {
417 0 : throw ProcessError();
418 : }
419 :
420 : // RICE_TODO Limits are fixed, change them to some predefined constants ...
421 8 : const double voltage = attrs.getOpt<double>(SUMO_ATTR_VOLTAGE, id.c_str(), ok, 600);
422 8 : const double currentLimit = attrs.getOpt<double>(SUMO_ATTR_CURRENTLIMIT, id.c_str(), ok, 400);
423 16 : buildTractionSubstation(net, id, voltage, currentLimit);
424 8 : }
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 25346 : NLTriggerBuilder::parseAndBuildStoppingPlace(MSNet& net, const SUMOSAXAttributes& attrs, const SumoXMLTag element) {
487 25346 : bool ok = true;
488 : // get the id, throw if not given or empty...
489 25346 : std::string id = attrs.get<std::string>(SUMO_ATTR_ID, nullptr, ok);
490 25346 : if (!ok) {
491 0 : throw ProcessError();
492 : }
493 :
494 : //get the name, leave blank if not given
495 50703 : 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 25346 : RGBColor color = attrs.getOpt<RGBColor>(SUMO_ATTR_COLOR, id.c_str(), ok, RGBColor::INVISIBLE);
500 :
501 50692 : MSLane* lane = getLane(attrs, toString(element), id);
502 : // get the positions
503 25346 : double frompos = attrs.getOpt<double>(SUMO_ATTR_STARTPOS, id.c_str(), ok, 0.);
504 25346 : double topos = attrs.getOpt<double>(SUMO_ATTR_ENDPOS, id.c_str(), ok, lane->getLength());
505 25346 : const bool friendlyPos = attrs.getOpt<bool>(SUMO_ATTR_FRIENDLY_POS, id.c_str(), ok, false);
506 25346 : if (!ok || (myHandler->checkStopPos(frompos, topos, lane->getLength(), POSITION_EPS, friendlyPos) != SUMORouteHandler::StopPos::STOPPOS_VALID)) {
507 6 : throw InvalidArgument("Invalid position for " + toString(element) + " '" + id + "'.");
508 : }
509 25354 : const std::vector<std::string>& lines = attrs.getOpt<std::vector<std::string> >(SUMO_ATTR_LINES, id.c_str(), ok);
510 : int defaultCapacity;
511 : SumoXMLAttr capacityAttr;
512 25343 : if (element != SUMO_TAG_CONTAINER_STOP) {
513 19662 : defaultCapacity = MAX2(MSStoppingPlace::getTransportablesAbreast(topos - frompos, element) * 3, 6);
514 : capacityAttr = SUMO_ATTR_PERSON_CAPACITY;
515 : } else {
516 5681 : defaultCapacity = MSStoppingPlace::getTransportablesAbreast(topos - frompos, element);
517 : capacityAttr = SUMO_ATTR_CONTAINER_CAPACITY;
518 : }
519 25343 : const int transportableCapacity = attrs.getOpt<int>(capacityAttr, id.c_str(), ok, defaultCapacity);
520 25343 : const double parkingLength = attrs.getOpt<double>(SUMO_ATTR_PARKING_LENGTH, id.c_str(), ok, 0);
521 : // build the bus stop
522 101380 : buildStoppingPlace(net, id, lines, lane, frompos, topos, element, ptStopName, transportableCapacity, parkingLength, color);
523 50678 : }
524 :
525 :
526 : void
527 3016 : NLTriggerBuilder::addAccess(MSNet& /* net */, const SUMOSAXAttributes& attrs) {
528 3016 : if (myCurrentStop == nullptr) {
529 30 : throw InvalidArgument("Could not add access outside a stopping place.");
530 : }
531 : // get the lane
532 6002 : MSLane* lane = getLane(attrs, "access", myCurrentStop->getID());
533 3001 : if (!lane->allowsVehicleClass(SVC_PEDESTRIAN)) {
534 0 : WRITE_WARNINGF(TL("Ignoring invalid access from non-pedestrian lane '%' in busStop '%'."), lane->getID(), myCurrentStop->getID());
535 0 : return;
536 : }
537 : // get the positions
538 3001 : bool ok = true;
539 6002 : const bool random = attrs.getOpt<std::string>(SUMO_ATTR_POSITION, "access", ok) == "random";
540 6002 : const bool useDoors = attrs.getOpt<std::string>(SUMO_ATTR_POSITION, "access", ok) == "doors";
541 3001 : double startPos = random || useDoors ? 0. : attrs.getOpt<double>(SUMO_ATTR_POSITION, "access", ok, 0);
542 3001 : double endPos = random || useDoors ? lane->getLength() : startPos;
543 3001 : const double length = attrs.getOpt<double>(SUMO_ATTR_LENGTH, "access", ok, -1);
544 3001 : const bool friendlyPos = attrs.getOpt<bool>(SUMO_ATTR_FRIENDLY_POS, "access", ok, false);
545 3001 : if (!ok || (myHandler->checkStopPos(startPos, endPos, lane->getLength(), 0, friendlyPos) != SUMORouteHandler::StopPos::STOPPOS_VALID)) {
546 0 : throw InvalidArgument("Invalid position " + attrs.getString(SUMO_ATTR_POSITION) + " for access on lane '" + lane->getID() + "' in stop '" + myCurrentStop->getID() + "'.");
547 : }
548 : // add bus stop access
549 3001 : if (!myCurrentStop->addAccess(lane, startPos, endPos, length, useDoors)) {
550 14 : throw InvalidArgument("Duplicate access on lane '" + lane->getID() + "' for stop '" + myCurrentStop->getID() + "'");
551 : }
552 : }
553 :
554 :
555 : void
556 8703 : NLTriggerBuilder::parseAndBeginParkingArea(MSNet& net, const SUMOSAXAttributes& attrs) {
557 8703 : bool ok = true;
558 : // get the id, throw if not given or empty...
559 8703 : std::string id = attrs.get<std::string>(SUMO_ATTR_ID, nullptr, ok);
560 8703 : if (!ok) {
561 0 : throw ProcessError();
562 : }
563 : // get the lane
564 17406 : MSLane* lane = getLane(attrs, "parkingArea", id);
565 : // get the positions
566 8703 : double frompos = attrs.getOpt<double>(SUMO_ATTR_STARTPOS, id.c_str(), ok, 0);
567 8703 : double topos = attrs.getOpt<double>(SUMO_ATTR_ENDPOS, id.c_str(), ok, lane->getLength());
568 8703 : const bool friendlyPos = attrs.getOpt<bool>(SUMO_ATTR_FRIENDLY_POS, id.c_str(), ok, false);
569 8703 : unsigned int capacity = attrs.getOpt<int>(SUMO_ATTR_ROADSIDE_CAPACITY, id.c_str(), ok, 0);
570 8703 : bool onRoad = attrs.getOpt<bool>(SUMO_ATTR_ONROAD, id.c_str(), ok, false);
571 8703 : double width = attrs.getOpt<double>(SUMO_ATTR_WIDTH, id.c_str(), ok, 0);
572 8703 : double length = attrs.getOpt<double>(SUMO_ATTR_LENGTH, id.c_str(), ok, 0);
573 8703 : double angle = attrs.getOpt<double>(SUMO_ATTR_ANGLE, id.c_str(), ok, 0);
574 17407 : const std::string name = attrs.getOpt<std::string>(SUMO_ATTR_NAME, id.c_str(), ok);
575 17407 : const std::string departPos = attrs.getOpt<std::string>(SUMO_ATTR_DEPARTPOS, id.c_str(), ok);
576 8703 : bool lefthand = attrs.getOpt<bool>(SUMO_ATTR_LEFTHAND, id.c_str(), ok, false);
577 8704 : const std::vector<std::string>& acceptedBadges = attrs.getOpt<std::vector<std::string> >(SUMO_ATTR_ACCEPTED_BADGES, id.c_str(), ok);
578 :
579 8703 : if (!ok || (myHandler->checkStopPos(frompos, topos, lane->getLength(), POSITION_EPS, friendlyPos) != SUMORouteHandler::StopPos::STOPPOS_VALID)) {
580 2 : throw InvalidArgument("Invalid position for parking area '" + id + "'.");
581 : }
582 8702 : const std::vector<std::string>& lines = attrs.getOpt<std::vector<std::string> >(SUMO_ATTR_LINES, id.c_str(), ok);
583 : // build the parking area
584 8702 : beginParkingArea(net, id, lines, acceptedBadges, lane, frompos, topos, capacity, width, length, angle, name, onRoad, departPos, lefthand);
585 17405 : }
586 :
587 :
588 :
589 : void
590 277 : NLTriggerBuilder::parseAndAddLotEntry(const SUMOSAXAttributes& attrs) {
591 277 : bool ok = true;
592 : // Check for open parking area
593 277 : if (myParkingArea == nullptr) {
594 0 : throw ProcessError();
595 : }
596 : // get the positions
597 277 : double x = attrs.get<double>(SUMO_ATTR_X, "", ok);
598 277 : if (!ok) {
599 0 : throw InvalidArgument("Invalid x position for lot entry.");
600 : }
601 277 : double y = attrs.get<double>(SUMO_ATTR_Y, "", ok);
602 277 : if (!ok) {
603 0 : throw InvalidArgument("Invalid y position for lot entry.");
604 : }
605 277 : double z = attrs.getOpt<double>(SUMO_ATTR_Z, "", ok, 0.);
606 277 : double width = attrs.getOpt<double>(SUMO_ATTR_WIDTH, "", ok, myParkingArea->getWidth());
607 277 : double length = attrs.getOpt<double>(SUMO_ATTR_LENGTH, "", ok, myParkingArea->getLength());
608 277 : double angle = attrs.getOpt<double>(SUMO_ATTR_ANGLE, "", ok, myParkingArea->getAngle());
609 277 : double slope = attrs.getOpt<double>(SUMO_ATTR_SLOPE, "", ok, 0.);
610 : // add the lot entry
611 277 : addLotEntry(x, y, z, width, length, angle, slope);
612 277 : }
613 :
614 :
615 : void
616 477 : NLTriggerBuilder::parseAndBuildCalibrator(MSNet& net, const SUMOSAXAttributes& attrs,
617 : const std::string& base) {
618 477 : bool ok = true;
619 : // get the id, throw if not given or empty...
620 477 : std::string id = attrs.get<std::string>(SUMO_ATTR_ID, nullptr, ok);
621 477 : if (!ok) {
622 0 : throw ProcessError();
623 : }
624 : MSLane* lane = nullptr;
625 : MSEdge* edge = nullptr;
626 : // get the file name to read further definitions from
627 477 : if (attrs.hasAttribute(SUMO_ATTR_EDGE)) {
628 182 : std::string edgeID = attrs.get<std::string>(SUMO_ATTR_EDGE, id.c_str(), ok);
629 182 : edge = MSEdge::dictionary(edgeID);
630 182 : if (edge == nullptr) {
631 0 : throw InvalidArgument("The edge " + edgeID + " to use within the calibrator '" + id + "' is not known.");
632 : }
633 182 : if (attrs.hasAttribute(SUMO_ATTR_LANE)) {
634 0 : lane = getLane(attrs, "calibrator", id);
635 0 : if (&lane->getEdge() != edge) {
636 0 : throw InvalidArgument("The edge " + edgeID + " to use within the calibrator '" + id
637 0 : + "' does not match the calibrator lane '" + lane->getID() + ".");
638 : }
639 : }
640 : } else {
641 590 : lane = getLane(attrs, "calibrator", id);
642 : edge = &lane->getEdge();
643 : }
644 477 : const double pos = getPosition(attrs, lane, "calibrator", id, edge);
645 477 : const SUMOTime period = attrs.getOptPeriod(id.c_str(), ok, DELTA_T); // !!! no error handling
646 477 : const std::string vTypes = attrs.getOpt<std::string>(SUMO_ATTR_VTYPES, id.c_str(), ok, "");
647 477 : std::string file = getFileName(attrs, base, true);
648 477 : std::string outfile = attrs.getOpt<std::string>(SUMO_ATTR_OUTPUT, id.c_str(), ok, "");
649 477 : std::string routeProbe = attrs.getOpt<std::string>(SUMO_ATTR_ROUTEPROBE, id.c_str(), ok, "");
650 : // differing defaults for backward compatibility, values are dimensionless
651 878 : double invalidJamThreshold = attrs.getOpt<double>(SUMO_ATTR_JAM_DIST_THRESHOLD, id.c_str(), ok, MSGlobals::gUseMesoSim ? 0.8 : 0.5);
652 : MSRouteProbe* probe = nullptr;
653 477 : if (routeProbe != "") {
654 72 : probe = dynamic_cast<MSRouteProbe*>(net.getDetectorControl().getTypedDetectors(SUMO_TAG_ROUTEPROBE).get(routeProbe));
655 36 : if (probe == nullptr) {
656 0 : throw InvalidArgument("The routeProbe '" + routeProbe + "' to use within the calibrator '" + id + "' is not known.");
657 : }
658 : }
659 477 : if (MSGlobals::gUseMesoSim) {
660 76 : if (lane != nullptr && edge->getLanes().size() > 1) {
661 18 : WRITE_WARNING("Meso calibrator '" + id
662 : + "' defined for lane '" + lane->getID()
663 : + "' will collect data for all lanes of edge '" + edge->getID() + "'.");
664 : }
665 76 : METriggeredCalibrator* trigger = buildMECalibrator(net, id, edge, pos, file, outfile, period, probe, invalidJamThreshold, vTypes);
666 76 : if (file == "") {
667 64 : trigger->registerParent(SUMO_TAG_CALIBRATOR, myHandler);
668 : }
669 : } else {
670 401 : MSCalibrator* trigger = buildCalibrator(net, id, edge, lane, pos, file, outfile, period, probe, invalidJamThreshold, vTypes);
671 401 : if (file == "") {
672 371 : trigger->registerParent(SUMO_TAG_CALIBRATOR, myHandler);
673 : }
674 : }
675 477 : }
676 :
677 :
678 : void
679 3345 : NLTriggerBuilder::parseAndBuildRerouter(MSNet& net, const SUMOSAXAttributes& attrs) {
680 3345 : bool ok = true;
681 : // get the id, throw if not given or empty...
682 3345 : std::string id = attrs.get<std::string>(SUMO_ATTR_ID, nullptr, ok);
683 3345 : if (!ok) {
684 0 : throw ProcessError();
685 : }
686 : if (MSTriggeredRerouter::getInstances().count(id) > 0) {
687 14 : throw InvalidArgument("Could not build rerouter '" + id + "'; probably declared twice.");
688 : }
689 : MSEdgeVector edges;
690 7771 : for (const std::string& edgeID : attrs.get<std::vector<std::string> >(SUMO_ATTR_EDGES, id.c_str(), ok)) {
691 4433 : MSEdge* edge = MSEdge::dictionary(edgeID);
692 4433 : if (edge == nullptr) {
693 0 : throw InvalidArgument("The edge '" + edgeID + "' to use within rerouter '" + id + "' is not known.");
694 : }
695 4433 : edges.push_back(edge);
696 3338 : }
697 3338 : if (!ok) {
698 0 : throw InvalidArgument("The edge to use within rerouter '" + id + "' is not known.");
699 : }
700 3338 : if (edges.size() == 0) {
701 0 : throw InvalidArgument("No edges found for rerouter '" + id + "'.");
702 : }
703 3338 : const double prob = attrs.getOpt<double>(SUMO_ATTR_PROB, id.c_str(), ok, 1);
704 3338 : const bool off = attrs.getOpt<bool>(SUMO_ATTR_OFF, id.c_str(), ok, false);
705 3338 : const bool optional = attrs.getOpt<bool>(SUMO_ATTR_OPTIONAL, id.c_str(), ok, false);
706 3338 : const SUMOTime timeThreshold = TIME2STEPS(attrs.getOpt<double>(SUMO_ATTR_HALTING_TIME_THRESHOLD, id.c_str(), ok, 0));
707 3338 : const std::string vTypes = attrs.getOpt<std::string>(SUMO_ATTR_VTYPES, id.c_str(), ok, "");
708 3338 : const std::string pos = attrs.getOpt<std::string>(SUMO_ATTR_POSITION, id.c_str(), ok, "");
709 3338 : Position p = Position::INVALID;
710 3338 : if (pos != "") {
711 402 : const std::vector<std::string> posSplit = StringTokenizer(pos, ",").getVector();
712 134 : if (posSplit.size() == 1) {
713 4 : p = edges.front()->getLanes()[0]->geometryPositionAtOffset(StringUtils::toDouble(posSplit[0]));
714 132 : } else if (posSplit.size() == 2) {
715 132 : p = Position(StringUtils::toDouble(posSplit[0]), StringUtils::toDouble(posSplit[1]));
716 0 : } else if (posSplit.size() == 3) {
717 0 : p = Position(StringUtils::toDouble(posSplit[0]), StringUtils::toDouble(posSplit[1]), StringUtils::toDouble(posSplit[2]));
718 : } else {
719 0 : throw InvalidArgument("Invalid position for rerouter '" + id + "'.");
720 : }
721 134 : }
722 3338 : if (!ok) {
723 0 : throw InvalidArgument("Could not parse rerouter '" + id + "'.");
724 : }
725 3338 : MSTriggeredRerouter* trigger = buildRerouter(net, id, edges, prob, off, optional, timeThreshold, vTypes, p);
726 : // read in the trigger description
727 3338 : trigger->registerParent(SUMO_TAG_REROUTER, myHandler);
728 3338 : }
729 :
730 :
731 : // -------------------------
732 :
733 :
734 : MSLaneSpeedTrigger*
735 289 : NLTriggerBuilder::buildLaneSpeedTrigger(MSNet& /*net*/, const std::string& id,
736 : const std::vector<MSLane*>& destLanes,
737 : const std::string& file) {
738 289 : return new MSLaneSpeedTrigger(id, destLanes, file);
739 : }
740 :
741 :
742 : METriggeredCalibrator*
743 76 : NLTriggerBuilder::buildMECalibrator(MSNet& /*net*/, const std::string& id,
744 : const MSEdge* edge,
745 : double pos,
746 : const std::string& file,
747 : const std::string& outfile,
748 : const SUMOTime freq,
749 : MSRouteProbe* probe,
750 : const double invalidJamThreshold,
751 : const std::string& vTypes) {
752 76 : return new METriggeredCalibrator(id, edge, pos, file, outfile, freq, MSGlobals::gMesoNet->getSegmentForEdge(*edge, pos)->getLength(), probe, invalidJamThreshold, vTypes);
753 : }
754 :
755 :
756 : MSCalibrator*
757 401 : NLTriggerBuilder::buildCalibrator(MSNet& /*net*/, const std::string& id,
758 : MSEdge* edge,
759 : MSLane* lane,
760 : double pos,
761 : const std::string& file,
762 : const std::string& outfile,
763 : const SUMOTime freq,
764 : const MSRouteProbe* probe,
765 : const double invalidJamThreshold,
766 : const std::string& vTypes) {
767 401 : return new MSCalibrator(id, edge, lane, pos, file, outfile, freq, edge->getLength(), probe, invalidJamThreshold, vTypes);
768 : }
769 :
770 :
771 : MSTriggeredRerouter*
772 2702 : NLTriggerBuilder::buildRerouter(MSNet&, const std::string& id,
773 : MSEdgeVector& edges, double prob, bool off, bool optional,
774 : SUMOTime timeThreshold, const std::string& vTypes, const Position& pos) {
775 2702 : return new MSTriggeredRerouter(id, edges, prob, off, optional, timeThreshold, vTypes, pos);
776 : }
777 :
778 :
779 : void
780 23744 : NLTriggerBuilder::buildStoppingPlace(MSNet& net, std::string id, std::vector<std::string> lines, MSLane* lane,
781 : double frompos, double topos, const SumoXMLTag element, std::string ptStopName,
782 : int personCapacity, double parkingLength, RGBColor& color) {
783 23744 : myCurrentStop = new MSStoppingPlace(id, element, lines, *lane, frompos, topos, ptStopName, personCapacity, parkingLength, color);
784 23744 : if (!net.addStoppingPlace(element, myCurrentStop)) {
785 5 : delete myCurrentStop;
786 5 : myCurrentStop = nullptr;
787 10 : throw InvalidArgument("Could not build " + toString(element) + " '" + id + "'; probably declared twice.");
788 : }
789 23739 : }
790 :
791 :
792 : void
793 8043 : NLTriggerBuilder::beginParkingArea(MSNet& net, const std::string& id,
794 : const std::vector<std::string>& lines,
795 : const std::vector<std::string>& badges,
796 : MSLane* lane, double frompos, double topos,
797 : unsigned int capacity,
798 : double width, double length, double angle, const std::string& name,
799 : bool onRoad,
800 : const std::string& departPos,
801 : bool lefthand) {
802 : // Close previous parking area if there are no lots inside
803 8043 : MSParkingArea* stop = new MSParkingArea(id, lines, badges, *lane, frompos, topos, capacity, width, length, angle, name, onRoad, departPos, lefthand);
804 8043 : if (!net.addStoppingPlace(SUMO_TAG_PARKING_AREA, stop)) {
805 0 : delete stop;
806 0 : throw InvalidArgument("Could not build parking area '" + id + "'; probably declared twice.");
807 : } else {
808 8043 : myParkingArea = stop;
809 : }
810 8043 : }
811 :
812 :
813 : void
814 277 : NLTriggerBuilder::addLotEntry(double x, double y, double z,
815 : double width, double length,
816 : double angle, double slope) {
817 277 : if (myParkingArea != nullptr) {
818 277 : if (!myParkingArea->parkOnRoad()) {
819 277 : myParkingArea->addLotEntry(x, y, z, width, length, angle, slope);
820 : } else {
821 0 : throw InvalidArgument("Cannot not add lot entry to on-road parking area.");
822 : }
823 : } else {
824 0 : throw InvalidArgument("Could not add lot entry outside a parking area.");
825 : }
826 277 : }
827 :
828 :
829 : void
830 8044 : NLTriggerBuilder::endParkingArea() {
831 8044 : if (myParkingArea != nullptr) {
832 8043 : myParkingArea = nullptr;
833 : } else {
834 2 : throw InvalidArgument("Could not end a parking area that is not opened.");
835 : }
836 8043 : }
837 :
838 :
839 : void
840 29542 : NLTriggerBuilder::endStoppingPlace() {
841 29542 : if (myCurrentStop != nullptr) {
842 29533 : myCurrentStop = nullptr;
843 : } else {
844 18 : throw InvalidArgument("Could not end a stopping place that is not opened.");
845 : }
846 29533 : }
847 :
848 :
849 : void
850 5794 : NLTriggerBuilder::buildChargingStation(MSNet& net, const std::string& id, MSLane* lane, double frompos, double topos,
851 : const std::string& name, double chargingPower, double efficiency, bool chargeInTransit,
852 : SUMOTime chargeDelay, std::string chargeType, SUMOTime waitingTime, MSParkingArea* parkingArea) {
853 5794 : MSChargingStation* chargingStation = (parkingArea == nullptr) ? new MSChargingStation(id, *lane, frompos, topos, name, chargingPower, efficiency,
854 5794 : chargeInTransit, chargeDelay, chargeType, waitingTime) : new MSChargingStation(id, parkingArea, name, chargingPower, efficiency,
855 0 : chargeInTransit, chargeDelay, chargeType, waitingTime);
856 5794 : if (!net.addStoppingPlace(SUMO_TAG_CHARGING_STATION, chargingStation)) {
857 0 : delete chargingStation;
858 0 : throw InvalidArgument("Could not build charging station '" + id + "'; probably declared twice.");
859 : }
860 5794 : myCurrentStop = chargingStation;
861 5794 : }
862 :
863 :
864 : void
865 48 : NLTriggerBuilder::buildOverheadWireSegment(MSNet& net, const std::string& id, MSLane* lane, double frompos, double topos,
866 : bool voltageSource) {
867 48 : MSOverheadWire* overheadWireSegment = new MSOverheadWire(id, *lane, frompos, topos, voltageSource);
868 48 : if (!net.addStoppingPlace(SUMO_TAG_OVERHEAD_WIRE_SEGMENT, overheadWireSegment)) {
869 0 : delete overheadWireSegment;
870 0 : throw InvalidArgument("Could not build overheadWireSegment '" + id + "'; probably declared twice.");
871 : }
872 48 : }
873 :
874 : void
875 4 : NLTriggerBuilder::buildInnerOverheadWireSegments(MSNet& net, const MSLane* connection, const MSLane* frontConnection, const MSLane* behindConnection) {
876 4 : if (frontConnection == NULL && behindConnection == NULL) {
877 8 : buildOverheadWireSegment(net, "ovrhd_inner_" + connection->getID(), const_cast<MSLane*>(connection), 0, connection->getLength(), false);
878 0 : } else if (frontConnection != NULL && behindConnection == NULL) {
879 0 : buildOverheadWireSegment(net, "ovrhd_inner_" + frontConnection->getID(), const_cast<MSLane*>(frontConnection), 0, frontConnection->getLength(), false);
880 0 : buildOverheadWireSegment(net, "ovrhd_inner_" + connection->getID(), const_cast<MSLane*>(connection), 0, connection->getLength(), false);
881 0 : } else if (frontConnection == NULL && behindConnection != NULL) {
882 0 : buildOverheadWireSegment(net, "ovrhd_inner_" + behindConnection->getID(), const_cast<MSLane*>(behindConnection), 0, behindConnection->getLength(), false);
883 0 : buildOverheadWireSegment(net, "ovrhd_inner_" + connection->getID(), const_cast<MSLane*>(connection), 0, connection->getLength(), false);
884 0 : } else if (frontConnection != NULL && behindConnection != NULL) {
885 0 : buildOverheadWireSegment(net, "ovrhd_inner_" + frontConnection->getID(), const_cast<MSLane*>(frontConnection), 0, frontConnection->getLength(), false);
886 0 : buildOverheadWireSegment(net, "ovrhd_inner_" + behindConnection->getID(), const_cast<MSLane*>(behindConnection), 0, behindConnection->getLength(), false);
887 0 : buildOverheadWireSegment(net, "ovrhd_inner_" + connection->getID(), const_cast<MSLane*>(connection), 0, connection->getLength(), false);
888 : }
889 4 : }
890 :
891 : void
892 8 : NLTriggerBuilder::buildTractionSubstation(MSNet& net, std::string id, double voltage, double currentLimit) {
893 8 : MSTractionSubstation* myTractionSubstation = new MSTractionSubstation(id, voltage, currentLimit);
894 8 : if (!net.addTractionSubstation(myTractionSubstation)) {
895 0 : delete myTractionSubstation;
896 0 : throw InvalidArgument("Could not build traction substation '" + id + "'; probably declared twice.");
897 : }
898 8 : }
899 :
900 : void
901 10 : NLTriggerBuilder::buildOverheadWireClamp(MSNet& /*net*/, const std::string& /*id*/, MSLane* /*lane_start*/, MSLane* /*lane_end*/) {
902 10 : }
903 :
904 : std::string
905 863 : NLTriggerBuilder::getFileName(const SUMOSAXAttributes& attrs,
906 : const std::string& base,
907 : const bool allowEmpty) {
908 : // get the file name to read further definitions from
909 863 : bool ok = true;
910 1726 : std::string file = attrs.getOpt<std::string>(SUMO_ATTR_FILE, nullptr, ok, "");
911 863 : if (file == "") {
912 653 : if (allowEmpty) {
913 : return file;
914 : }
915 0 : throw InvalidArgument("No filename given.");
916 : }
917 : // check whether absolute or relative filenames are given
918 210 : if (!FileHelpers::isAbsolute(file)) {
919 210 : return FileHelpers::getConfigurationRelative(base, file);
920 : }
921 : return file;
922 : }
923 :
924 :
925 : MSLane*
926 43361 : NLTriggerBuilder::getLane(const SUMOSAXAttributes& attrs,
927 : const std::string& tt,
928 : const std::string& tid) {
929 43361 : bool ok = true;
930 43361 : std::string objectid = attrs.get<std::string>(SUMO_ATTR_LANE, tid.c_str(), ok);
931 43361 : MSLane* lane = MSLane::dictionary(objectid);
932 43361 : if (lane == nullptr) {
933 : // Either a lane that is non-existent/broken, or a lane that is internal and has been ignored.
934 : // We assume that internal lane names start with ':'.
935 0 : if (objectid[0] == ':' && !MSGlobals::gUsingInternalLanes) {
936 : return nullptr;
937 : }
938 : // Throw the exception only in case that the lane really does not exist in the network file
939 : // or it is broken.
940 0 : throw InvalidArgument("The lane " + objectid + " to use within the " + tt + " '" + tid + "' is not known.");
941 : }
942 : return lane;
943 : }
944 :
945 :
946 : MSParkingArea*
947 5960 : NLTriggerBuilder::getParkingArea(const SUMOSAXAttributes& attrs, const std::string& tt, const std::string& tid) {
948 5960 : bool ok = true;
949 5960 : std::string objectID = attrs.getOpt<std::string>(SUMO_ATTR_PARKING_AREA, tid.c_str(), ok);
950 5960 : if (!ok || objectID.size() == 0) {
951 : return nullptr;
952 : }
953 0 : MSParkingArea* pa = static_cast<MSParkingArea*>(MSNet::getInstance()->getStoppingPlace(objectID, SUMO_TAG_PARKING_AREA));
954 0 : if (pa == nullptr) {
955 : // Throw the exception only in case that the lane really does not exist in the network file
956 : // or it is broken.
957 0 : throw InvalidArgument("The parkingArea " + objectID + " to use within the " + tt + " '" + tid + "' is not known.");
958 : }
959 : return pa;
960 : }
961 :
962 :
963 : double
964 477 : NLTriggerBuilder::getPosition(const SUMOSAXAttributes& attrs,
965 : MSLane* lane,
966 : const std::string& tt, const std::string& tid,
967 : MSEdge* edge) {
968 : assert(lane != 0 || edge != 0);
969 477 : const double length = lane != nullptr ? lane->getLength() : edge->getLength();
970 477 : bool ok = true;
971 477 : double pos = attrs.get<double>(SUMO_ATTR_POSITION, nullptr, ok);
972 477 : const bool friendlyPos = attrs.getOpt<bool>(SUMO_ATTR_FRIENDLY_POS, nullptr, ok, false);
973 477 : if (!ok) {
974 0 : throw InvalidArgument("Error on parsing a position information.");
975 : }
976 477 : if (pos < 0) {
977 2 : pos = length + pos;
978 : }
979 477 : if (pos > length) {
980 0 : if (friendlyPos) {
981 0 : pos = length - (double) 0.1;
982 : } else {
983 0 : if (lane != nullptr) {
984 0 : throw InvalidArgument("The position of " + tt + " '" + tid + "' lies beyond the lane's '" + lane->getID() + "' length.");
985 : } else {
986 0 : throw InvalidArgument("The position of " + tt + " '" + tid + "' lies beyond the edges's '" + edge->getID() + "' length.");
987 : }
988 : }
989 : }
990 477 : return pos;
991 : }
992 :
993 : MSStoppingPlace*
994 39996 : NLTriggerBuilder::getCurrentStop() {
995 39996 : return myParkingArea == nullptr ? myCurrentStop : myParkingArea;
996 : }
997 :
998 :
999 : /****************************************************************************/
|