Line data Source code
1 : /****************************************************************************/
2 : // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
3 : // Copyright (C) 2002-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 NLDetectorBuilder.cpp
15 : /// @author Daniel Krajzewicz
16 : /// @author Laura Bieker
17 : /// @author Clemens Honomichl
18 : /// @author Michael Behrisch
19 : /// @author Christian Roessel
20 : /// @author Jakob Erdmann
21 : /// @date Mon, 15 Apr 2002
22 : ///
23 : // Builds detectors for microsim
24 : /****************************************************************************/
25 : #include <config.h>
26 :
27 : #include <string>
28 : #include <iostream>
29 : #include <microsim/MSNet.h>
30 : #include <microsim/MSLane.h>
31 : #include <microsim/MSEdge.h>
32 : #include <microsim/output/MSInductLoop.h>
33 : #include <microsim/output/MSE2Collector.h>
34 : // #include <microsim/output/MSMultiLaneE2Collector.h>
35 : #include <microsim/output/MSVTypeProbe.h>
36 : #include <microsim/output/MSRouteProbe.h>
37 : #include <microsim/output/MSMeanData_Net.h>
38 : #include <microsim/output/MSMeanData_Emissions.h>
39 : #include <microsim/output/MSMeanData_Harmonoise.h>
40 : #include <microsim/output/MSMeanData_Amitran.h>
41 : #include <microsim/output/MSInstantInductLoop.h>
42 : #include <microsim/MSGlobals.h>
43 : #include <microsim/actions/Command_SaveTLCoupledDet.h>
44 : #include <microsim/actions/Command_SaveTLCoupledLaneDet.h>
45 : #include <utils/common/UtilExceptions.h>
46 : #include <utils/common/FileHelpers.h>
47 : #include <utils/common/StringUtils.h>
48 : #include <utils/common/StringTokenizer.h>
49 : #include <utils/common/StringUtils.h>
50 : #include "NLDetectorBuilder.h"
51 : #include <microsim/output/MSDetectorControl.h>
52 :
53 : #include <mesosim/MEInductLoop.h>
54 : #include <mesosim/MELoop.h>
55 : #include <mesosim/MESegment.h>
56 :
57 :
58 : // ===========================================================================
59 : // method definitions
60 : // ===========================================================================
61 : /* -------------------------------------------------------------------------
62 : * NLDetectorBuilder::E3DetectorDefinition-methods
63 : * ----------------------------------------------------------------------- */
64 1553 : NLDetectorBuilder::E3DetectorDefinition::E3DetectorDefinition(const std::string& id,
65 : const std::string& device, double haltingSpeedThreshold,
66 : SUMOTime haltingTimeThreshold, SUMOTime splInterval,
67 : const std::string name, const std::string& vTypes,
68 : const std::string& nextEdges,
69 1553 : int detectPersons, bool openEntry, bool expectArrival) :
70 1553 : myID(id), myDevice(device),
71 1553 : myHaltingSpeedThreshold(haltingSpeedThreshold),
72 1553 : myHaltingTimeThreshold(haltingTimeThreshold),
73 1553 : mySampleInterval(splInterval),
74 1553 : myName(name),
75 1553 : myVehicleTypes(vTypes),
76 1553 : myNextEdges(nextEdges),
77 1553 : myDetectPersons(detectPersons),
78 1553 : myOpenEntry(openEntry),
79 1553 : myExpectArrival(expectArrival) {
80 1553 : }
81 :
82 :
83 3106 : NLDetectorBuilder::E3DetectorDefinition::~E3DetectorDefinition() {}
84 :
85 :
86 : /* -------------------------------------------------------------------------
87 : * NLDetectorBuilder-methods
88 : * ----------------------------------------------------------------------- */
89 39058 : NLDetectorBuilder::NLDetectorBuilder(MSNet& net)
90 39058 : : myNet(net), myE3Definition(nullptr) {}
91 :
92 :
93 39058 : NLDetectorBuilder::~NLDetectorBuilder() {
94 39058 : delete myE3Definition;
95 39058 : }
96 :
97 :
98 : Parameterised*
99 21550 : NLDetectorBuilder::buildInductLoop(const std::string& id,
100 : const std::string& lane, double pos, double length, SUMOTime splInterval,
101 : const std::string& device, bool friendlyPos,
102 : const std::string name,
103 : const std::string& vTypes,
104 : const std::string& nextEdges,
105 : int detectPersons) {
106 21550 : checkSampleInterval(splInterval, SUMO_TAG_E1DETECTOR, id);
107 : // get and check the lane
108 21544 : MSLane* clane = getLaneChecking(lane, SUMO_TAG_E1DETECTOR, id);
109 : // get and check the position
110 21525 : pos = getPositionChecking(pos, clane, friendlyPos, SUMO_TAG_E1DETECTOR, id);
111 21519 : if (length < 0) {
112 0 : throw InvalidArgument("The length of " + toString(SUMO_TAG_E1DETECTOR) + " '" + id + "' cannot be negative");
113 21519 : } else if (length > 0 && pos + length > clane->getLength()) {
114 6 : if (friendlyPos) {
115 : length = MIN2(length, clane->getLength());
116 6 : pos = clane->getLength() - length;
117 : } else {
118 0 : throw InvalidArgument("The length of " + toString(SUMO_TAG_E1DETECTOR) + " '" + id + "' puts it beyond the lane's '" + clane->getID() + "' end.");
119 : }
120 : }
121 : // build the loop
122 21519 : MSDetectorFileOutput* loop = createInductLoop(id, clane, pos, length, name, vTypes, nextEdges, detectPersons, true);
123 : // add the file output
124 21513 : myNet.getDetectorControl().add(SUMO_TAG_INDUCTION_LOOP, loop, device, splInterval);
125 21507 : return loop;
126 : }
127 :
128 :
129 : Parameterised*
130 1169 : NLDetectorBuilder::buildInstantInductLoop(const std::string& id,
131 : const std::string& lane, double pos,
132 : const std::string& device, bool friendlyPos,
133 : const std::string name,
134 : const std::string& vTypes,
135 : const std::string& nextEdges) {
136 : // get and check the lane
137 1169 : MSLane* clane = getLaneChecking(lane, SUMO_TAG_INSTANT_INDUCTION_LOOP, id);
138 : // get and check the position
139 1165 : pos = getPositionChecking(pos, clane, friendlyPos, SUMO_TAG_INSTANT_INDUCTION_LOOP, id);
140 : // build the loop
141 1161 : MSDetectorFileOutput* loop = createInstantInductLoop(id, clane, pos, device, name, vTypes, nextEdges);
142 : // add the file output
143 1157 : myNet.getDetectorControl().add(SUMO_TAG_INSTANT_INDUCTION_LOOP, loop);
144 1157 : return loop;
145 : }
146 :
147 :
148 : Parameterised*
149 3745 : NLDetectorBuilder::buildE2Detector(const std::string& id, MSLane* lane, double pos, double endPos, double length,
150 : const std::string& device, SUMOTime frequency,
151 : SUMOTime haltingTimeThreshold, double haltingSpeedThreshold, double jamDistThreshold,
152 : const std::string name, const std::string& vTypes,
153 : const std::string& nextEdges,
154 : int detectPersons, bool friendlyPos, bool showDetector,
155 : MSTLLogicControl::TLSLogicVariants* tlls, MSLane* toLane) {
156 :
157 : bool tlsGiven = tlls != nullptr;
158 : bool toLaneGiven = toLane != nullptr;
159 : bool posGiven = pos != std::numeric_limits<double>::max();
160 : bool endPosGiven = endPos != std::numeric_limits<double>::max();
161 :
162 : assert(posGiven || endPosGiven);
163 :
164 : // Check positioning
165 3745 : if (posGiven) {
166 2769 : if (pos >= lane->getLength() || (pos < 0 && -pos > lane->getLength())) {
167 8 : std::stringstream ss;
168 : ss << "The given position (=" << pos << ") for detector '" << id
169 : << "' does not lie on the given lane '" << lane->getID()
170 : << "' with length " << lane->getLength();
171 8 : if (friendlyPos) {
172 4 : double newPos = pos > 0 ? lane->getLength() - POSITION_EPS : 0.;
173 : ss << " (adjusting to new position " << newPos;
174 4 : WRITE_WARNING(ss.str());
175 : pos = newPos;
176 : } else {
177 4 : ss << " (0 <= pos < lane->getLength() is required)";
178 12 : throw InvalidArgument(ss.str());
179 : }
180 8 : }
181 : }
182 3741 : if (endPosGiven) {
183 998 : if (endPos > lane->getLength() || (endPos <= 0 && -endPos >= lane->getLength())) {
184 0 : std::stringstream ss;
185 : ss << "The given end position (=" << endPos << ") for detector '" << id
186 : << "' does not lie on the given lane '" << lane->getID()
187 : << "' with length " << lane->getLength();
188 0 : if (friendlyPos) {
189 0 : double newEndPos = endPos > 0 ? lane->getLength() : POSITION_EPS;
190 : ss << " (adjusting to new position " << newEndPos;
191 0 : WRITE_WARNING(ss.str());
192 : pos = newEndPos;
193 : } else {
194 0 : ss << " (0 <= pos < lane->getLength() is required)";
195 0 : throw InvalidArgument(ss.str());
196 : }
197 0 : }
198 : }
199 :
200 : MSE2Collector* det = nullptr;
201 3741 : if (tlsGiven) {
202 : // Detector connected to TLS
203 554 : det = createE2Detector(id, DU_USER_DEFINED, lane, pos, endPos, length, haltingTimeThreshold, haltingSpeedThreshold, jamDistThreshold, name, vTypes, nextEdges, detectPersons, showDetector);
204 554 : myNet.getDetectorControl().add(SUMO_TAG_LANE_AREA_DETECTOR, det);
205 : // add the file output (XXX: Where's the corresponding delete?)
206 554 : if (toLaneGiven) {
207 : // Detector also associated to specific link
208 : const MSLane* const lastLane = det->getLastLane();
209 8 : const MSLink* const link = lastLane->getLinkTo(toLane);
210 8 : if (link == nullptr) {
211 : throw InvalidArgument(
212 0 : "The detector '" + id + "' cannot be build as no connection between lanes '"
213 0 : + lastLane->getID() + "' and '" + toLane->getID() + "' exists.");
214 : }
215 8 : new Command_SaveTLCoupledLaneDet(*tlls, det, myNet.getCurrentTimeStep(), OutputDevice::getDevice(device), link);
216 : } else {
217 : // detector for tls but without specific link
218 546 : new Command_SaveTLCoupledDet(*tlls, det, myNet.getCurrentTimeStep(), OutputDevice::getDevice(device));
219 : }
220 : } else {
221 : // User specified detector for xml-output
222 3187 : checkSampleInterval(frequency, SUMO_TAG_E2DETECTOR, id);
223 3183 : det = createE2Detector(id, DU_USER_DEFINED, lane, pos, endPos, length, haltingTimeThreshold, haltingSpeedThreshold, jamDistThreshold, name, vTypes, nextEdges, detectPersons, showDetector);
224 3183 : myNet.getDetectorControl().add(SUMO_TAG_LANE_AREA_DETECTOR, det, device, frequency);
225 : }
226 3733 : return det;
227 : }
228 :
229 :
230 : Parameterised*
231 331 : NLDetectorBuilder::buildE2Detector(const std::string& id, std::vector<MSLane*> lanes, double pos, double endPos,
232 : const std::string& device, SUMOTime frequency,
233 : SUMOTime haltingTimeThreshold, double haltingSpeedThreshold, double jamDistThreshold,
234 : const std::string name, const std::string& vTypes,
235 : const std::string& nextEdges,
236 : int detectPersons, bool friendlyPos, bool showDetector,
237 : MSTLLogicControl::TLSLogicVariants* tlls, MSLane* toLane) {
238 :
239 : bool tlsGiven = tlls != nullptr;
240 : bool toLaneGiven = toLane != nullptr;
241 : assert(pos != std::numeric_limits<double>::max());
242 : assert(endPos != std::numeric_limits<double>::max());
243 : assert(lanes.size() != 0);
244 :
245 331 : const MSLane* const firstLane = lanes[0];
246 331 : const MSLane* const lastLane = lanes.back();
247 :
248 : // Check positioning
249 331 : if (pos >= firstLane->getLength() || (pos < 0 && -pos > firstLane->getLength())) {
250 1 : std::stringstream ss;
251 : ss << "The given position (=" << pos << ") for detector '" << id
252 : << "' does not lie on the given lane '" << firstLane->getID()
253 : << "' with length " << firstLane->getLength();
254 1 : if (friendlyPos) {
255 1 : double newPos = pos > 0 ? firstLane->getLength() - POSITION_EPS : 0.;
256 : ss << " (adjusting to new position " << newPos;
257 1 : WRITE_WARNING(ss.str());
258 : pos = newPos;
259 : } else {
260 0 : ss << " (0 <= pos < lane->getLength() is required)";
261 0 : throw InvalidArgument(ss.str());
262 : }
263 1 : }
264 331 : if (endPos > lastLane->getLength() || (endPos <= 0 && -endPos >= lastLane->getLength())) {
265 1 : std::stringstream ss;
266 : ss << "The given end position (=" << endPos << ") for detector '" << id
267 : << "' does not lie on the given lane '" << lastLane->getID()
268 : << "' with length " << lastLane->getLength();
269 1 : if (friendlyPos) {
270 1 : double newEndPos = endPos > 0 ? lastLane->getLength() : POSITION_EPS;
271 : ss << " (adjusting to new position " << newEndPos;
272 1 : WRITE_WARNING(ss.str());
273 : pos = newEndPos;
274 : } else {
275 0 : ss << " (0 <= pos < lane->getLength() is required)";
276 0 : throw InvalidArgument(ss.str());
277 : }
278 1 : }
279 :
280 : MSE2Collector* det = nullptr;
281 331 : if (tlsGiven) {
282 : // Detector connected to TLS
283 5 : det = createE2Detector(id, DU_USER_DEFINED, lanes, pos, endPos, haltingTimeThreshold, haltingSpeedThreshold, jamDistThreshold, name, vTypes, nextEdges, detectPersons, showDetector);
284 5 : myNet.getDetectorControl().add(SUMO_TAG_LANE_AREA_DETECTOR, det);
285 : // add the file output (XXX: Where's the corresponding delete?)
286 5 : if (toLaneGiven) {
287 : // Detector also associated to specific link
288 : const MSLane* const lastDetLane = det->getLastLane();
289 0 : const MSLink* const link = lastDetLane->getLinkTo(toLane);
290 0 : if (link == nullptr) {
291 : throw InvalidArgument(
292 0 : "The detector '" + id + "' cannot be build as no connection between lanes '"
293 0 : + lastDetLane->getID() + "' and '" + toLane->getID() + "' exists.");
294 : }
295 0 : new Command_SaveTLCoupledLaneDet(*tlls, det, myNet.getCurrentTimeStep(), OutputDevice::getDevice(device), link);
296 : } else {
297 : // detector for tls but without specific link
298 5 : new Command_SaveTLCoupledDet(*tlls, det, myNet.getCurrentTimeStep(), OutputDevice::getDevice(device));
299 : }
300 : } else {
301 : // User specified detector for xml-output
302 326 : checkSampleInterval(frequency, SUMO_TAG_E2DETECTOR, id);
303 :
304 332 : det = createE2Detector(id, DU_USER_DEFINED, lanes, pos, endPos, haltingTimeThreshold, haltingSpeedThreshold, jamDistThreshold, name, vTypes, nextEdges, detectPersons, showDetector);
305 320 : myNet.getDetectorControl().add(SUMO_TAG_LANE_AREA_DETECTOR, det, device, frequency);
306 : }
307 325 : return det;
308 : }
309 :
310 :
311 :
312 : Parameterised*
313 1557 : NLDetectorBuilder::beginE3Detector(const std::string& id,
314 : const std::string& device, SUMOTime splInterval,
315 : double haltingSpeedThreshold,
316 : SUMOTime haltingTimeThreshold,
317 : const std::string name,
318 : const std::string& vTypes,
319 : const std::string& nextEdges,
320 : int detectPersons, bool openEntry, bool expectArrival) {
321 1557 : checkSampleInterval(splInterval, SUMO_TAG_E3DETECTOR, id);
322 3106 : myE3Definition = new E3DetectorDefinition(id, device, haltingSpeedThreshold, haltingTimeThreshold, splInterval, name, vTypes, nextEdges, detectPersons, openEntry, expectArrival);
323 1553 : return myE3Definition;
324 : }
325 :
326 :
327 : void
328 1883 : NLDetectorBuilder::addE3Entry(const std::string& lane,
329 : double pos, bool friendlyPos) {
330 1883 : if (myE3Definition == nullptr) {
331 : return;
332 : }
333 1855 : MSLane* clane = getLaneChecking(lane, SUMO_TAG_E3DETECTOR, myE3Definition->myID);
334 : // get and check the position
335 1851 : pos = getPositionChecking(pos, clane, friendlyPos, SUMO_TAG_DET_ENTRY, myE3Definition->myID);
336 : // build and save the entry
337 1847 : myE3Definition->myEntries.push_back(MSCrossSection(clane, pos));
338 : }
339 :
340 :
341 : void
342 1847 : NLDetectorBuilder::addE3Exit(const std::string& lane,
343 : double pos, bool friendlyPos) {
344 1847 : if (myE3Definition == nullptr) {
345 : return;
346 : }
347 1819 : MSLane* clane = getLaneChecking(lane, SUMO_TAG_E3DETECTOR, myE3Definition->myID);
348 : // get and check the position
349 1815 : pos = getPositionChecking(pos, clane, friendlyPos, SUMO_TAG_DET_EXIT, myE3Definition->myID);
350 : // build and save the exit
351 1811 : myE3Definition->myExits.push_back(MSCrossSection(clane, pos));
352 : }
353 :
354 :
355 : std::string
356 11310 : NLDetectorBuilder::getCurrentE3ID() const {
357 11310 : if (myE3Definition == nullptr) {
358 168 : return "<unknown>";
359 : }
360 : return myE3Definition->myID;
361 : }
362 :
363 :
364 : void
365 1581 : NLDetectorBuilder::endE3Detector() {
366 1581 : if (myE3Definition == nullptr) {
367 : return;
368 : }
369 : // If E3 own entry or exit detectors
370 1553 : if (myE3Definition->myEntries.size() > 0 || myE3Definition->myExits.size() > 0) {
371 : // create E3 detector
372 4635 : MSDetectorFileOutput* det = createE3Detector(myE3Definition->myID,
373 1545 : myE3Definition->myEntries, myE3Definition->myExits,
374 1545 : myE3Definition->myHaltingSpeedThreshold, myE3Definition->myHaltingTimeThreshold,
375 : myE3Definition->myName,
376 1545 : myE3Definition->myVehicleTypes,
377 1545 : myE3Definition->myNextEdges,
378 : myE3Definition->myDetectPersons,
379 1545 : myE3Definition->myOpenEntry,
380 1545 : myE3Definition->myExpectArrival);
381 1545 : det->updateParameters(myE3Definition->getParametersMap());
382 : // add to net
383 1545 : myNet.getDetectorControl().add(SUMO_TAG_ENTRY_EXIT_DETECTOR, det, myE3Definition->myDevice, myE3Definition->mySampleInterval);
384 : } else {
385 40 : WRITE_WARNING(toString(SUMO_TAG_E3DETECTOR) + " with id = '" + myE3Definition->myID + "' will not be created because is empty (no " + toString(SUMO_TAG_DET_ENTRY) + " or " + toString(SUMO_TAG_DET_EXIT) + " was defined)")
386 : }
387 : // clean up
388 1545 : delete myE3Definition;
389 1545 : myE3Definition = nullptr;
390 : }
391 :
392 :
393 : void
394 108 : NLDetectorBuilder::buildVTypeProbe(const std::string& id,
395 : const std::string& vtype, SUMOTime frequency,
396 : const std::string& device) {
397 108 : checkSampleInterval(frequency, SUMO_TAG_VTYPEPROBE, id);
398 96 : new MSVTypeProbe(id, vtype, OutputDevice::getDevice(device), frequency);
399 90 : }
400 :
401 :
402 : void
403 643 : NLDetectorBuilder::buildRouteProbe(const std::string& id, const std::string& edge,
404 : SUMOTime frequency, SUMOTime begin,
405 : const std::string& device,
406 : const std::string& vTypes) {
407 643 : checkSampleInterval(frequency, SUMO_TAG_ROUTEPROBE, id);
408 643 : MSEdge* e = getEdgeChecking(edge, SUMO_TAG_ROUTEPROBE, id);
409 1929 : MSRouteProbe* probe = new MSRouteProbe(id, e, id + "_" + toString(begin), id + "_" + toString(begin - frequency), vTypes);
410 : // add the file output
411 643 : myNet.getDetectorControl().add(SUMO_TAG_ROUTEPROBE, probe, device, frequency, begin);
412 643 : }
413 :
414 :
415 : MSDetectorFileOutput*
416 24147 : NLDetectorBuilder::createInductLoop(const std::string& id,
417 : MSLane* lane, double pos,
418 : double length,
419 : const std::string name,
420 : const std::string& vTypes,
421 : const std::string& nextEdges,
422 : int detectPersons,
423 : bool /*show*/) {
424 24147 : if (MSGlobals::gUseMesoSim) {
425 567 : return new MEInductLoop(id, MSGlobals::gMesoNet->getSegmentForEdge(lane->getEdge(), pos), pos, name, vTypes, nextEdges, detectPersons);
426 : }
427 47919 : return new MSInductLoop(id, lane, pos, length, name, vTypes, nextEdges, detectPersons, false);
428 : }
429 :
430 :
431 : MSDetectorFileOutput*
432 1039 : NLDetectorBuilder::createInstantInductLoop(const std::string& id,
433 : MSLane* lane, double pos, const std::string& od,
434 : const std::string name, const std::string& vTypes,
435 : const std::string& nextEdges) {
436 2081 : return new MSInstantInductLoop(id, OutputDevice::getDevice(od), lane, pos, name, vTypes, nextEdges);
437 : }
438 :
439 :
440 : MSE2Collector*
441 5800 : NLDetectorBuilder::createE2Detector(const std::string& id,
442 : DetectorUsage usage, MSLane* lane, double pos, double endPos, double length,
443 : SUMOTime haltingTimeThreshold, double haltingSpeedThreshold, double jamDistThreshold,
444 : const std::string name, const std::string& vTypes,
445 : const std::string& nextEdges,
446 : int detectPersons, bool /* showDetector */) {
447 17400 : return new MSE2Collector(id, usage, lane, pos, endPos, length, haltingTimeThreshold, haltingSpeedThreshold, jamDistThreshold, name, vTypes, nextEdges, detectPersons);
448 : }
449 :
450 : MSE2Collector*
451 325 : NLDetectorBuilder::createE2Detector(const std::string& id,
452 : DetectorUsage usage, std::vector<MSLane*> lanes, double pos, double endPos,
453 : SUMOTime haltingTimeThreshold, double haltingSpeedThreshold, double jamDistThreshold,
454 : const std::string name, const std::string& vTypes,
455 : const std::string& nextEdges,
456 : int detectPersons, bool /* showDetector */) {
457 660 : return new MSE2Collector(id, usage, lanes, pos, endPos, haltingTimeThreshold, haltingSpeedThreshold, jamDistThreshold, name, vTypes, nextEdges, detectPersons);
458 : }
459 :
460 : MSDetectorFileOutput*
461 1378 : NLDetectorBuilder::createE3Detector(const std::string& id,
462 : const CrossSectionVector& entries,
463 : const CrossSectionVector& exits,
464 : double haltingSpeedThreshold,
465 : SUMOTime haltingTimeThreshold,
466 : const std::string name, const std::string& vTypes,
467 : const std::string& nextEdges,
468 : int detectPersons,
469 : bool openEntry,
470 : bool expectArrival) {
471 4134 : return new MSE3Collector(id, entries, exits, haltingSpeedThreshold, haltingTimeThreshold, name, vTypes, nextEdges, detectPersons, openEntry, expectArrival);
472 : }
473 :
474 :
475 : double
476 26356 : NLDetectorBuilder::getPositionChecking(double pos, MSLane* lane, bool friendlyPos,
477 : SumoXMLTag tag,
478 : const std::string& detid) {
479 : // check whether it is given from the end
480 26356 : if (pos < 0) {
481 2227 : pos += lane->getLength();
482 : }
483 : // check whether it is on the lane
484 26356 : if (pos > lane->getLength()) {
485 540 : if (friendlyPos) {
486 : pos = lane->getLength();
487 : } else {
488 54 : throw InvalidArgument("The position of " + toString(tag) + " '" + detid + "' lies beyond the lane's '" + lane->getID() + "' end.");
489 : }
490 : }
491 26338 : if (pos < 0) {
492 178 : if (friendlyPos) {
493 : pos = 0.;
494 : } else {
495 0 : throw InvalidArgument("The position of " + toString(tag) + " '" + detid + "' lies before the lane's '" + lane->getID() + "' begin.");
496 : }
497 : }
498 26338 : return pos;
499 : }
500 :
501 :
502 : void
503 20305 : NLDetectorBuilder::createEdgeLaneMeanData(const std::string& id, SUMOTime frequency,
504 : SUMOTime begin, SUMOTime end, const std::string& type,
505 : const bool useLanes, const bool withEmpty, const bool printDefaults,
506 : const bool withInternal, const bool trackVehicles, const int detectPersons,
507 : const double maxTravelTime, const double minSamples,
508 : const double haltSpeed, const std::string& vTypes,
509 : const std::string& writeAttributes,
510 : std::vector<MSEdge*> edges,
511 : bool aggregate,
512 : const std::string& device) {
513 20305 : if (begin < 0) {
514 108 : throw InvalidArgument("Negative begin time for meandata dump '" + id + "'.");
515 : }
516 20269 : if (end < 0) {
517 : end = SUMOTime_MAX;
518 : }
519 20269 : if (end <= begin) {
520 108 : throw InvalidArgument("End before or at begin for meandata dump '" + id + "'.");
521 : }
522 40466 : checkStepLengthMultiple(begin, " for meandata dump '" + id + "'");
523 : MSMeanData* det = nullptr;
524 20233 : if ((type == SUMOXMLDefinitions::MeanDataTypes.getString(MeanDataType::DEFAULT)) ||
525 20233 : (type == SUMOXMLDefinitions::MeanDataTypes.getString(MeanDataType::TRAFFIC)) ||
526 20164 : (type == "performance")) {
527 : det = new MSMeanData_Net(id, begin, end, useLanes, withEmpty,
528 18913 : printDefaults, withInternal, trackVehicles, detectPersons, maxTravelTime, minSamples, haltSpeed, vTypes, writeAttributes, edges, aggregate);
529 1320 : } else if ((type == SUMOXMLDefinitions::MeanDataTypes.getString(MeanDataType::EMISSIONS)) || (type == "hbefa")) {
530 888 : if (type == "hbefa") {
531 24 : WRITE_WARNING(TL("The netstate type 'hbefa' is deprecated. Please use the type 'emissions' instead."));
532 : }
533 : det = new MSMeanData_Emissions(id, begin, end, useLanes, withEmpty,
534 888 : printDefaults, withInternal, trackVehicles, maxTravelTime, minSamples, vTypes, writeAttributes, edges, aggregate);
535 432 : } else if (type == SUMOXMLDefinitions::MeanDataTypes.getString(MeanDataType::HARMONOISE)) {
536 : det = new MSMeanData_Harmonoise(id, begin, end, useLanes, withEmpty,
537 408 : printDefaults, withInternal, trackVehicles, maxTravelTime, minSamples, vTypes, writeAttributes, edges, aggregate);
538 24 : } else if (type == SUMOXMLDefinitions::MeanDataTypes.getString(MeanDataType::AMITRAN)) {
539 : det = new MSMeanData_Amitran(id, begin, end, useLanes, withEmpty,
540 24 : printDefaults, withInternal, trackVehicles, detectPersons, maxTravelTime, minSamples, haltSpeed, vTypes, writeAttributes, edges, aggregate);
541 : } else {
542 0 : throw InvalidArgument("Invalid type '" + type + "' for meandata dump '" + id + "'.");
543 : }
544 : if (det != nullptr) {
545 20233 : if (frequency < 0) {
546 16561 : frequency = end - begin;
547 : } else {
548 11016 : checkStepLengthMultiple(frequency, " for meandata dump '" + id + "'");
549 : }
550 20233 : MSNet::getInstance()->getDetectorControl().add(det, device, frequency, begin);
551 : }
552 20233 : }
553 :
554 :
555 :
556 :
557 : // ------ Value checking/adapting methods ------
558 : MSEdge*
559 643 : NLDetectorBuilder::getEdgeChecking(const std::string& edgeID, SumoXMLTag type,
560 : const std::string& detid) {
561 : // get and check the lane
562 643 : MSEdge* edge = MSEdge::dictionary(edgeID);
563 643 : if (edge == nullptr) {
564 0 : throw InvalidArgument("The lane with the id '" + edgeID + "' is not known (while building " + toString(type) + " '" + detid + "').");
565 : }
566 643 : return edge;
567 : }
568 :
569 :
570 : MSLane*
571 30049 : NLDetectorBuilder::getLaneChecking(const std::string& laneID, SumoXMLTag type,
572 : const std::string& detid) {
573 : // get and check the lane
574 30049 : MSLane* lane = MSLane::dictionary(laneID);
575 30049 : if (lane == nullptr) {
576 160 : throw InvalidArgument("The lane with the id '" + laneID + "' is not known (while building " + toString(type) + " '" + detid + "').");
577 : }
578 30009 : return lane;
579 : }
580 :
581 :
582 : void
583 27371 : NLDetectorBuilder::checkSampleInterval(SUMOTime splInterval, SumoXMLTag type, const std::string& id) {
584 27371 : if (splInterval < 0) {
585 60 : throw InvalidArgument("Negative sampling frequency (in " + toString(type) + " '" + id + "').");
586 : }
587 27351 : if (splInterval == 0) {
588 18 : throw InvalidArgument("Sampling frequency must not be zero (in " + toString(type) + " '" + id + "').");
589 : }
590 54690 : checkStepLengthMultiple(splInterval, " (in " + toString(type) + " '" + id + "')");
591 27345 : }
592 :
593 :
594 : /****************************************************************************/
|