Line data Source code
1 : /****************************************************************************/
2 : // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
3 : // Copyright (C) 2002-2026 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 1433 : 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 1433 : int detectPersons, bool openEntry, bool expectArrival) :
70 1433 : myID(id), myDevice(device),
71 1433 : myHaltingSpeedThreshold(haltingSpeedThreshold),
72 1433 : myHaltingTimeThreshold(haltingTimeThreshold),
73 1433 : mySampleInterval(splInterval),
74 1433 : myName(name),
75 1433 : myVehicleTypes(vTypes),
76 1433 : myNextEdges(nextEdges),
77 1433 : myDetectPersons(detectPersons),
78 1433 : myOpenEntry(openEntry),
79 1433 : myExpectArrival(expectArrival) {
80 1433 : }
81 :
82 :
83 2866 : NLDetectorBuilder::E3DetectorDefinition::~E3DetectorDefinition() {}
84 :
85 :
86 : /* -------------------------------------------------------------------------
87 : * NLDetectorBuilder-methods
88 : * ----------------------------------------------------------------------- */
89 42965 : NLDetectorBuilder::NLDetectorBuilder(MSNet& net)
90 42965 : : myNet(net), myE3Definition(nullptr) {}
91 :
92 :
93 42965 : NLDetectorBuilder::~NLDetectorBuilder() {
94 42965 : delete myE3Definition;
95 42965 : }
96 :
97 :
98 : Parameterised*
99 24631 : 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 : bool mesoTLS,
106 : int detectPersons) {
107 24631 : checkSampleInterval(splInterval, SUMO_TAG_E1DETECTOR, id);
108 : // get and check the lane
109 24625 : MSLane* clane = getLaneChecking(lane, SUMO_TAG_E1DETECTOR, id);
110 : // get and check the position
111 24619 : pos = getPositionChecking(pos, clane, friendlyPos, SUMO_TAG_E1DETECTOR, id);
112 24613 : if (length < 0) {
113 0 : throw InvalidArgument("The length of " + toString(SUMO_TAG_E1DETECTOR) + " '" + id + "' cannot be negative");
114 24613 : } else if (length > 0 && pos + length > clane->getLength()) {
115 6 : if (friendlyPos) {
116 : length = MIN2(length, clane->getLength());
117 6 : pos = clane->getLength() - length;
118 : } else {
119 0 : throw InvalidArgument("The length of " + toString(SUMO_TAG_E1DETECTOR) + " '" + id + "' puts it beyond the lane's '" + clane->getID() + "' end.");
120 : }
121 : }
122 : // build the loop
123 24613 : MSDetectorFileOutput* loop = createInductLoop(id, clane, pos, length, name, vTypes, nextEdges, detectPersons, true, mesoTLS);
124 : // add the file output
125 24607 : myNet.getDetectorControl().add(SUMO_TAG_INDUCTION_LOOP, loop, device, splInterval);
126 24601 : return loop;
127 : }
128 :
129 :
130 : Parameterised*
131 1096 : NLDetectorBuilder::buildInstantInductLoop(const std::string& id,
132 : const std::string& lane, double pos,
133 : const std::string& device, bool friendlyPos,
134 : const std::string name,
135 : const std::string& vTypes,
136 : const std::string& nextEdges,
137 : int detectPersons) {
138 : // get and check the lane
139 1096 : MSLane* clane = getLaneChecking(lane, SUMO_TAG_INSTANT_INDUCTION_LOOP, id);
140 : // get and check the position
141 1092 : pos = getPositionChecking(pos, clane, friendlyPos, SUMO_TAG_INSTANT_INDUCTION_LOOP, id);
142 : // build the loop
143 1088 : MSDetectorFileOutput* loop = createInstantInductLoop(id, clane, pos, device, name, vTypes, nextEdges, detectPersons);
144 : // add the file output
145 1084 : myNet.getDetectorControl().add(SUMO_TAG_INSTANT_INDUCTION_LOOP, loop);
146 1084 : return loop;
147 : }
148 :
149 :
150 : Parameterised*
151 3865 : NLDetectorBuilder::buildE2Detector(const std::string& id, MSLane* lane, double pos, double endPos, double length,
152 : const std::string& device, SUMOTime frequency,
153 : SUMOTime haltingTimeThreshold, double haltingSpeedThreshold, double jamDistThreshold,
154 : const std::string name, const std::string& vTypes,
155 : const std::string& nextEdges,
156 : int detectPersons, bool friendlyPos, bool showDetector,
157 : MSTLLogicControl::TLSLogicVariants* tlls, MSLane* toLane) {
158 :
159 : bool tlsGiven = tlls != nullptr;
160 : bool toLaneGiven = toLane != nullptr;
161 : bool posGiven = pos != std::numeric_limits<double>::max();
162 : bool endPosGiven = endPos != std::numeric_limits<double>::max();
163 :
164 : assert(posGiven || endPosGiven);
165 :
166 : // Check positioning
167 3865 : if (posGiven) {
168 2759 : if (pos >= lane->getLength() || (pos < 0 && -pos > lane->getLength())) {
169 5 : std::stringstream ss;
170 : ss << "The given position (=" << pos << ") for detector '" << id
171 : << "' does not lie on the given lane '" << lane->getID()
172 : << "' with length " << lane->getLength();
173 5 : if (friendlyPos) {
174 1 : double newPos = pos > 0 ? lane->getLength() - POSITION_EPS : 0.;
175 : ss << " (adjusting to new position " << newPos;
176 1 : WRITE_WARNING(ss.str());
177 : pos = newPos;
178 : } else {
179 4 : ss << " (0 <= pos < lane->getLength() is required)";
180 12 : throw InvalidArgument(ss.str());
181 : }
182 5 : }
183 : }
184 3861 : if (endPosGiven) {
185 1141 : if (endPos > lane->getLength() || (endPos <= 0 && -endPos >= lane->getLength())) {
186 0 : std::stringstream ss;
187 : ss << "The given end position (=" << endPos << ") for detector '" << id
188 : << "' does not lie on the given lane '" << lane->getID()
189 : << "' with length " << lane->getLength();
190 0 : if (friendlyPos) {
191 0 : double newEndPos = endPos > 0 ? lane->getLength() : POSITION_EPS;
192 : ss << " (adjusting to new position " << newEndPos;
193 0 : WRITE_WARNING(ss.str());
194 : pos = newEndPos;
195 : } else {
196 0 : ss << " (0 <= pos < lane->getLength() is required)";
197 0 : throw InvalidArgument(ss.str());
198 : }
199 0 : }
200 : }
201 :
202 : MSE2Collector* det = nullptr;
203 3861 : if (tlsGiven) {
204 : // Detector connected to TLS
205 554 : det = createE2Detector(id, DU_USER_DEFINED, lane, pos, endPos, length, haltingTimeThreshold, haltingSpeedThreshold, jamDistThreshold, name, vTypes, nextEdges, detectPersons, showDetector);
206 554 : myNet.getDetectorControl().add(SUMO_TAG_LANE_AREA_DETECTOR, det);
207 : // add the file output (XXX: Where's the corresponding delete?)
208 554 : if (toLaneGiven) {
209 : // Detector also associated to specific link
210 : const MSLane* const lastLane = det->getLastLane();
211 8 : const MSLink* const link = lastLane->getLinkTo(toLane);
212 8 : if (link == nullptr) {
213 : throw InvalidArgument(
214 0 : "The detector '" + id + "' cannot be build as no connection between lanes '"
215 0 : + lastLane->getID() + "' and '" + toLane->getID() + "' exists.");
216 : }
217 8 : new Command_SaveTLCoupledLaneDet(*tlls, det, myNet.getCurrentTimeStep(), OutputDevice::getDevice(device), link);
218 : } else {
219 : // detector for tls but without specific link
220 546 : new Command_SaveTLCoupledDet(*tlls, det, myNet.getCurrentTimeStep(), OutputDevice::getDevice(device));
221 : }
222 : } else {
223 : // User specified detector for xml-output
224 3307 : checkSampleInterval(frequency, SUMO_TAG_E2DETECTOR, id);
225 3303 : det = createE2Detector(id, DU_USER_DEFINED, lane, pos, endPos, length, haltingTimeThreshold, haltingSpeedThreshold, jamDistThreshold, name, vTypes, nextEdges, detectPersons, showDetector);
226 3303 : myNet.getDetectorControl().add(SUMO_TAG_LANE_AREA_DETECTOR, det, device, frequency);
227 : }
228 3853 : return det;
229 : }
230 :
231 :
232 : Parameterised*
233 252 : NLDetectorBuilder::buildE2Detector(const std::string& id, std::vector<MSLane*> lanes, double pos, double endPos,
234 : const std::string& device, SUMOTime frequency,
235 : SUMOTime haltingTimeThreshold, double haltingSpeedThreshold, double jamDistThreshold,
236 : const std::string name, const std::string& vTypes,
237 : const std::string& nextEdges,
238 : int detectPersons, bool friendlyPos, bool showDetector,
239 : MSTLLogicControl::TLSLogicVariants* tlls, MSLane* toLane) {
240 :
241 : bool tlsGiven = tlls != nullptr;
242 : bool toLaneGiven = toLane != nullptr;
243 : assert(pos != std::numeric_limits<double>::max());
244 : assert(endPos != std::numeric_limits<double>::max());
245 : assert(lanes.size() != 0);
246 :
247 252 : const MSLane* const firstLane = lanes[0];
248 252 : const MSLane* const lastLane = lanes.back();
249 :
250 : // Check positioning
251 252 : if (pos >= firstLane->getLength() || (pos < 0 && -pos > firstLane->getLength())) {
252 1 : std::stringstream ss;
253 : ss << "The given position (=" << pos << ") for detector '" << id
254 : << "' does not lie on the given lane '" << firstLane->getID()
255 : << "' with length " << firstLane->getLength();
256 1 : if (friendlyPos) {
257 1 : double newPos = pos > 0 ? firstLane->getLength() - POSITION_EPS : 0.;
258 : ss << " (adjusting to new position " << newPos;
259 1 : WRITE_WARNING(ss.str());
260 : pos = newPos;
261 : } else {
262 0 : ss << " (0 <= pos < lane->getLength() is required)";
263 0 : throw InvalidArgument(ss.str());
264 : }
265 1 : }
266 252 : if (endPos > lastLane->getLength() || (endPos <= 0 && -endPos >= lastLane->getLength())) {
267 1 : std::stringstream ss;
268 : ss << "The given end position (=" << endPos << ") for detector '" << id
269 : << "' does not lie on the given lane '" << lastLane->getID()
270 : << "' with length " << lastLane->getLength();
271 1 : if (friendlyPos) {
272 1 : double newEndPos = endPos > 0 ? lastLane->getLength() : POSITION_EPS;
273 : ss << " (adjusting to new position " << newEndPos;
274 1 : WRITE_WARNING(ss.str());
275 : pos = newEndPos;
276 : } else {
277 0 : ss << " (0 <= pos < lane->getLength() is required)";
278 0 : throw InvalidArgument(ss.str());
279 : }
280 1 : }
281 :
282 : MSE2Collector* det = nullptr;
283 252 : if (tlsGiven) {
284 : // Detector connected to TLS
285 3 : det = createE2Detector(id, DU_USER_DEFINED, lanes, pos, endPos, haltingTimeThreshold, haltingSpeedThreshold, jamDistThreshold, name, vTypes, nextEdges, detectPersons, showDetector);
286 3 : myNet.getDetectorControl().add(SUMO_TAG_LANE_AREA_DETECTOR, det);
287 : // add the file output (XXX: Where's the corresponding delete?)
288 3 : if (toLaneGiven) {
289 : // Detector also associated to specific link
290 : const MSLane* const lastDetLane = det->getLastLane();
291 0 : const MSLink* const link = lastDetLane->getLinkTo(toLane);
292 0 : if (link == nullptr) {
293 : throw InvalidArgument(
294 0 : "The detector '" + id + "' cannot be build as no connection between lanes '"
295 0 : + lastDetLane->getID() + "' and '" + toLane->getID() + "' exists.");
296 : }
297 0 : new Command_SaveTLCoupledLaneDet(*tlls, det, myNet.getCurrentTimeStep(), OutputDevice::getDevice(device), link);
298 : } else {
299 : // detector for tls but without specific link
300 3 : new Command_SaveTLCoupledDet(*tlls, det, myNet.getCurrentTimeStep(), OutputDevice::getDevice(device));
301 : }
302 : } else {
303 : // User specified detector for xml-output
304 249 : checkSampleInterval(frequency, SUMO_TAG_E2DETECTOR, id);
305 :
306 255 : det = createE2Detector(id, DU_USER_DEFINED, lanes, pos, endPos, haltingTimeThreshold, haltingSpeedThreshold, jamDistThreshold, name, vTypes, nextEdges, detectPersons, showDetector);
307 243 : myNet.getDetectorControl().add(SUMO_TAG_LANE_AREA_DETECTOR, det, device, frequency);
308 : }
309 246 : return det;
310 : }
311 :
312 :
313 :
314 : Parameterised*
315 1437 : NLDetectorBuilder::beginE3Detector(const std::string& id,
316 : const std::string& device, SUMOTime splInterval,
317 : double haltingSpeedThreshold,
318 : SUMOTime haltingTimeThreshold,
319 : const std::string name,
320 : const std::string& vTypes,
321 : const std::string& nextEdges,
322 : int detectPersons, bool openEntry, bool expectArrival) {
323 1437 : checkSampleInterval(splInterval, SUMO_TAG_E3DETECTOR, id);
324 2866 : myE3Definition = new E3DetectorDefinition(id, device, haltingSpeedThreshold, haltingTimeThreshold, splInterval, name, vTypes, nextEdges, detectPersons, openEntry, expectArrival);
325 1433 : return myE3Definition;
326 : }
327 :
328 :
329 : void
330 1795 : NLDetectorBuilder::addE3Entry(const std::string& lane,
331 : double pos, bool friendlyPos) {
332 1795 : if (myE3Definition == nullptr) {
333 : return;
334 : }
335 1767 : MSLane* clane = getLaneChecking(lane, SUMO_TAG_E3DETECTOR, myE3Definition->myID);
336 : // get and check the position
337 1763 : pos = getPositionChecking(pos, clane, friendlyPos, SUMO_TAG_DET_ENTRY, myE3Definition->myID);
338 : // build and save the entry
339 1759 : myE3Definition->myEntries.push_back(MSCrossSection(clane, pos));
340 : }
341 :
342 :
343 : void
344 1763 : NLDetectorBuilder::addE3Exit(const std::string& lane,
345 : double pos, bool friendlyPos) {
346 1763 : if (myE3Definition == nullptr) {
347 : return;
348 : }
349 1735 : MSLane* clane = getLaneChecking(lane, SUMO_TAG_E3DETECTOR, myE3Definition->myID);
350 : // get and check the position
351 1731 : pos = getPositionChecking(pos, clane, friendlyPos, SUMO_TAG_DET_EXIT, myE3Definition->myID);
352 : // build and save the exit
353 1727 : myE3Definition->myExits.push_back(MSCrossSection(clane, pos));
354 : }
355 :
356 :
357 : std::string
358 10794 : NLDetectorBuilder::getCurrentE3ID() const {
359 10794 : if (myE3Definition == nullptr) {
360 168 : return "<unknown>";
361 : }
362 : return myE3Definition->myID;
363 : }
364 :
365 :
366 : void
367 1461 : NLDetectorBuilder::endE3Detector() {
368 1461 : if (myE3Definition == nullptr) {
369 : return;
370 : }
371 : // If E3 own entry or exit detectors
372 1433 : if (myE3Definition->myEntries.size() > 0 || myE3Definition->myExits.size() > 0) {
373 : // create E3 detector
374 4275 : MSDetectorFileOutput* det = createE3Detector(myE3Definition->myID,
375 1425 : myE3Definition->myEntries, myE3Definition->myExits,
376 1425 : myE3Definition->myHaltingSpeedThreshold, myE3Definition->myHaltingTimeThreshold,
377 : myE3Definition->myName,
378 1425 : myE3Definition->myVehicleTypes,
379 1425 : myE3Definition->myNextEdges,
380 : myE3Definition->myDetectPersons,
381 1425 : myE3Definition->myOpenEntry,
382 1425 : myE3Definition->myExpectArrival);
383 1425 : det->updateParameters(myE3Definition->getParametersMap());
384 : // add to net
385 1425 : myNet.getDetectorControl().add(SUMO_TAG_ENTRY_EXIT_DETECTOR, det, myE3Definition->myDevice, myE3Definition->mySampleInterval);
386 : } else {
387 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)")
388 : }
389 : // clean up
390 1425 : delete myE3Definition;
391 1425 : myE3Definition = nullptr;
392 : }
393 :
394 :
395 : void
396 108 : NLDetectorBuilder::buildVTypeProbe(const std::string& id,
397 : const std::string& vtype, SUMOTime frequency,
398 : const std::string& device) {
399 108 : checkSampleInterval(frequency, SUMO_TAG_VTYPEPROBE, id);
400 96 : new MSVTypeProbe(id, vtype, OutputDevice::getDevice(device), frequency);
401 90 : }
402 :
403 :
404 : void
405 478 : NLDetectorBuilder::buildRouteProbe(const std::string& id, const std::string& edge,
406 : SUMOTime frequency, SUMOTime begin,
407 : const std::string& device,
408 : const std::string& vTypes) {
409 478 : checkSampleInterval(frequency, SUMO_TAG_ROUTEPROBE, id);
410 478 : MSEdge* e = getEdgeChecking(edge, SUMO_TAG_ROUTEPROBE, id);
411 1434 : MSRouteProbe* probe = new MSRouteProbe(id, e, id + "_" + toString(begin), id + "_" + toString(begin - frequency), vTypes);
412 : // add the file output
413 478 : myNet.getDetectorControl().add(SUMO_TAG_ROUTEPROBE, probe, device, frequency, begin);
414 478 : }
415 :
416 :
417 : MSDetectorFileOutput*
418 27931 : NLDetectorBuilder::createInductLoop(const std::string& id,
419 : MSLane* lane, double pos,
420 : double length,
421 : const std::string name,
422 : const std::string& vTypes,
423 : const std::string& nextEdges,
424 : int detectPersons,
425 : bool /*show*/,
426 : bool forceMicro) {
427 27931 : if (MSGlobals::gUseMesoSim && !forceMicro) {
428 627 : return new MEInductLoop(id, MSGlobals::gMesoNet->getSegmentForEdge(lane->getEdge(), pos), pos, name, vTypes, nextEdges, detectPersons);
429 : }
430 55447 : return new MSInductLoop(id, lane, pos, length, name, vTypes, nextEdges, detectPersons, false);
431 : }
432 :
433 :
434 : MSDetectorFileOutput*
435 965 : NLDetectorBuilder::createInstantInductLoop(const std::string& id,
436 : MSLane* lane, double pos, const std::string& od,
437 : const std::string name, const std::string& vTypes,
438 : const std::string& nextEdges,
439 : int detectPersons) {
440 1933 : return new MSInstantInductLoop(id, OutputDevice::getDevice(od), lane, pos, name, vTypes, nextEdges, detectPersons);
441 : }
442 :
443 :
444 : MSE2Collector*
445 5721 : NLDetectorBuilder::createE2Detector(const std::string& id,
446 : DetectorUsage usage, MSLane* lane, double pos, double endPos, double length,
447 : SUMOTime haltingTimeThreshold, double haltingSpeedThreshold, double jamDistThreshold,
448 : const std::string name, const std::string& vTypes,
449 : const std::string& nextEdges,
450 : int detectPersons, bool /* showDetector */) {
451 17163 : return new MSE2Collector(id, usage, lane, pos, endPos, length, haltingTimeThreshold, haltingSpeedThreshold, jamDistThreshold, name, vTypes, nextEdges, detectPersons);
452 : }
453 :
454 : MSE2Collector*
455 246 : NLDetectorBuilder::createE2Detector(const std::string& id,
456 : DetectorUsage usage, std::vector<MSLane*> lanes, double pos, double endPos,
457 : SUMOTime haltingTimeThreshold, double haltingSpeedThreshold, double jamDistThreshold,
458 : const std::string name, const std::string& vTypes,
459 : const std::string& nextEdges,
460 : int detectPersons, bool /* showDetector */) {
461 502 : return new MSE2Collector(id, usage, lanes, pos, endPos, haltingTimeThreshold, haltingSpeedThreshold, jamDistThreshold, name, vTypes, nextEdges, detectPersons);
462 : }
463 :
464 : MSDetectorFileOutput*
465 1254 : NLDetectorBuilder::createE3Detector(const std::string& id,
466 : const CrossSectionVector& entries,
467 : const CrossSectionVector& exits,
468 : double haltingSpeedThreshold,
469 : SUMOTime haltingTimeThreshold,
470 : const std::string name, const std::string& vTypes,
471 : const std::string& nextEdges,
472 : int detectPersons,
473 : bool openEntry,
474 : bool expectArrival) {
475 3762 : return new MSE3Collector(id, entries, exits, haltingSpeedThreshold, haltingTimeThreshold, name, vTypes, nextEdges, detectPersons, openEntry, expectArrival);
476 : }
477 :
478 :
479 : double
480 29205 : NLDetectorBuilder::getPositionChecking(double pos, MSLane* lane, bool friendlyPos,
481 : SumoXMLTag tag,
482 : const std::string& detid) {
483 : // check whether it is given from the end
484 29205 : if (pos < 0) {
485 2382 : pos += lane->getLength();
486 : }
487 : // check whether it is on the lane
488 29205 : if (pos > lane->getLength()) {
489 525 : if (friendlyPos) {
490 : pos = lane->getLength();
491 : } else {
492 54 : throw InvalidArgument("The position of " + toString(tag) + " '" + detid + "' lies beyond the lane's '" + lane->getID() + "' end.");
493 : }
494 : }
495 29187 : if (pos < 0) {
496 178 : if (friendlyPos) {
497 : pos = 0.;
498 : } else {
499 0 : throw InvalidArgument("The position of " + toString(tag) + " '" + detid + "' lies before the lane's '" + lane->getID() + "' begin.");
500 : }
501 : }
502 29187 : return pos;
503 : }
504 :
505 :
506 : void
507 23426 : NLDetectorBuilder::createEdgeLaneMeanData(const std::string& id, SUMOTime frequency,
508 : SUMOTime begin, SUMOTime end, const std::string& type,
509 : const bool useLanes, const std::string& excludeEmpty,
510 : const bool withInternal, const bool trackVehicles, const int detectPersons,
511 : const double maxTravelTime, const double minSamples,
512 : const double haltSpeed, const double haltSpeedRel, const std::string& vTypes,
513 : const std::string& writeAttributes,
514 : std::vector<MSEdge*> edges,
515 : AggregateType aggregate,
516 : const std::string& device) {
517 23426 : if (begin < 0) {
518 108 : throw InvalidArgument("Negative begin time for meandata dump '" + id + "'.");
519 : }
520 23390 : if (end < 0) {
521 : end = SUMOTime_MAX;
522 : }
523 23390 : if (end <= begin) {
524 108 : throw InvalidArgument("End before or at begin for meandata dump '" + id + "'.");
525 : }
526 70062 : checkStepLengthMultiple(begin, " for meandata dump '" + id + "'");
527 : std::vector<MeanDataType> types;
528 23354 : if (type == SUMOXMLDefinitions::MeanDataTypes.getString(MeanDataType::DEFAULT)) {
529 87672 : const SumoXMLAttrMask attrs = OutputDevice::parseWrittenAttributes(StringTokenizer(writeAttributes).getVector(), "meandata '" + id + "'");
530 21918 : if (attrs.none()) {
531 21823 : types.push_back(MeanDataType::TRAFFIC);
532 : } else {
533 95 : if (MSMeanData_Net::supports(attrs)) {
534 85 : types.push_back(MeanDataType::TRAFFIC);
535 : }
536 95 : if (MSMeanData_Emissions::supports(attrs)) {
537 6 : types.push_back(MeanDataType::EMISSIONS);
538 : }
539 95 : if (MSMeanData_Harmonoise::supports(attrs)) {
540 0 : types.push_back(MeanDataType::HARMONOISE);
541 : }
542 : }
543 : } else {
544 4308 : for (const std::string& t : StringTokenizer(type).getVector()) {
545 : if (SUMOXMLDefinitions::MeanDataTypes.hasString(t)) {
546 1424 : types.push_back(SUMOXMLDefinitions::MeanDataTypes.get(t));
547 12 : } else if (t == "performance") {
548 0 : types.push_back(MeanDataType::TRAFFIC);
549 12 : } else if (t == "hbefa") {
550 12 : WRITE_WARNING(TL("The meandata type 'hbefa' is deprecated. Please use the type 'emissions' instead."));
551 12 : types.push_back(MeanDataType::EMISSIONS);
552 : } else {
553 0 : throw InvalidArgument("Invalid type '" + t + "' for meandata dump '" + id + "'.");
554 : }
555 1436 : }
556 : }
557 23354 : if (frequency < 0) {
558 19613 : frequency = end - begin;
559 : } else {
560 11223 : checkStepLengthMultiple(frequency, " for meandata dump '" + id + "'");
561 : }
562 : MSMeanData* first = nullptr;
563 : MSMeanData* parent = nullptr;
564 46704 : for (const MeanDataType t : types) {
565 : MSMeanData* det = nullptr;
566 23350 : if (t == MeanDataType::TRAFFIC) {
567 : det = new MSMeanData_Net(id, begin, end, useLanes, excludeEmpty,
568 22017 : withInternal, trackVehicles, detectPersons, maxTravelTime, minSamples, haltSpeed, haltSpeedRel, vTypes, writeAttributes, edges, aggregate);
569 1333 : } else if (t == MeanDataType::EMISSIONS) {
570 : det = new MSMeanData_Emissions(id, begin, end, useLanes, excludeEmpty,
571 897 : withInternal, trackVehicles, maxTravelTime, minSamples, vTypes, writeAttributes, edges, aggregate);
572 436 : } else if (t == MeanDataType::HARMONOISE) {
573 : det = new MSMeanData_Harmonoise(id, begin, end, useLanes, excludeEmpty,
574 410 : withInternal, trackVehicles, maxTravelTime, minSamples, vTypes, writeAttributes, edges, aggregate);
575 26 : } else if (t == MeanDataType::AMITRAN) {
576 : det = new MSMeanData_Amitran(id, begin, end, useLanes, excludeEmpty,
577 26 : withInternal, trackVehicles, detectPersons, maxTravelTime, minSamples, haltSpeed, vTypes, writeAttributes, edges, aggregate);
578 : }
579 : if (det != nullptr) {
580 23350 : if (first == nullptr) {
581 : first = det;
582 : }
583 23350 : if (parent != nullptr) {
584 : parent->setSubData(det);
585 : }
586 : parent = det;
587 : }
588 : }
589 23354 : if (first != nullptr) {
590 : // needs to be delayed because it might call init for the subdata
591 23344 : MSNet::getInstance()->getDetectorControl().add(first, device, frequency, begin);
592 : }
593 23354 : }
594 :
595 :
596 :
597 :
598 : // ------ Value checking/adapting methods ------
599 : MSEdge*
600 478 : NLDetectorBuilder::getEdgeChecking(const std::string& edgeID, SumoXMLTag type,
601 : const std::string& detid) {
602 : // get and check the lane
603 478 : MSEdge* edge = MSEdge::dictionary(edgeID);
604 478 : if (edge == nullptr) {
605 0 : throw InvalidArgument("The lane with the id '" + edgeID + "' is not known (while building " + toString(type) + " '" + detid + "').");
606 : }
607 478 : return edge;
608 : }
609 :
610 :
611 : MSLane*
612 32723 : NLDetectorBuilder::getLaneChecking(const std::string& laneID, SumoXMLTag type,
613 : const std::string& detid) {
614 : // get and check the lane
615 32723 : MSLane* lane = MSLane::dictionary(laneID);
616 32723 : if (lane == nullptr) {
617 104 : throw InvalidArgument("The lane with the id '" + laneID + "' is not known (while building " + toString(type) + " '" + detid + "').");
618 : }
619 32697 : return lane;
620 : }
621 :
622 :
623 : void
624 30210 : NLDetectorBuilder::checkSampleInterval(SUMOTime splInterval, SumoXMLTag type, const std::string& id) {
625 30210 : if (splInterval < 0) {
626 60 : throw InvalidArgument("Negative sampling frequency (in " + toString(type) + " '" + id + "').");
627 : }
628 30190 : if (splInterval == 0) {
629 18 : throw InvalidArgument("Sampling frequency must not be zero (in " + toString(type) + " '" + id + "').");
630 : }
631 60368 : checkStepLengthMultiple(splInterval, " (in " + toString(type) + " '" + id + "')");
632 30184 : }
633 :
634 :
635 : /****************************************************************************/
|