Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
eclipse
GitHub Repository: eclipse/sumo
Path: blob/main/src/netedit/elements/additional/GNEMultiEntryExitDetector.cpp
169684 views
1
/****************************************************************************/
2
// Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
3
// Copyright (C) 2001-2025 German Aerospace Center (DLR) and others.
4
// This program and the accompanying materials are made available under the
5
// terms of the Eclipse Public License 2.0 which is available at
6
// https://www.eclipse.org/legal/epl-2.0/
7
// This Source Code may also be made available under the following Secondary
8
// Licenses when the conditions for such availability set forth in the Eclipse
9
// Public License 2.0 are satisfied: GNU General Public License, version 2
10
// or later which is available at
11
// https://www.gnu.org/licenses/old-licenses/gpl-2.0-standalone.html
12
// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-or-later
13
/****************************************************************************/
14
/// @file GNEMultiEntryExitDetector.cpp
15
/// @author Pablo Alvarez Lopez
16
/// @date Nov 2015
17
///
18
// multi entry-exit (E3) detector
19
/****************************************************************************/
20
#include <config.h>
21
22
#include <netedit/GNENet.h>
23
#include <netedit/GNETagProperties.h>
24
#include <netedit/GNEUndoList.h>
25
#include <netedit/GNEViewNet.h>
26
#include <netedit/GNEViewParent.h>
27
#include <netedit/changes/GNEChange_Attribute.h>
28
#include <netedit/frames/network/GNETLSEditorFrame.h>
29
30
#include "GNEMultiEntryExitDetector.h"
31
32
// ===========================================================================
33
// member method definitions
34
// ===========================================================================
35
36
GNEMultiEntryExitDetector::GNEMultiEntryExitDetector(GNENet* net) :
37
GNEAdditional("", net, "", SUMO_TAG_ENTRY_EXIT_DETECTOR, "") {
38
}
39
40
41
GNEMultiEntryExitDetector::GNEMultiEntryExitDetector(const std::string& id, GNENet* net, const std::string& filename, const Position pos, const SUMOTime freq,
42
const std::string& outputFilename, const std::vector<std::string>& vehicleTypes, const std::vector<std::string>& nextEdges, const std::string& detectPersons,
43
const std::string& name, const SUMOTime timeThreshold, const double speedThreshold, const bool openEntry, const bool expectedArrival, const Parameterised::Map& parameters) :
44
GNEAdditional(id, net, filename, SUMO_TAG_ENTRY_EXIT_DETECTOR, name),
45
Parameterised(parameters),
46
myPosition(pos),
47
myPeriod(freq),
48
myOutputFilename(outputFilename),
49
myVehicleTypes(vehicleTypes),
50
myNextEdges(nextEdges),
51
myDetectPersons(detectPersons),
52
myTimeThreshold(timeThreshold),
53
mySpeedThreshold(speedThreshold),
54
myOpenEntry(openEntry),
55
myExpectedArrival(expectedArrival) {
56
// update centering boundary without updating grid
57
updateCenteringBoundary(false);
58
// set default output filename
59
if (outputFilename.empty()) {
60
myOutputFilename = id + ".xml";
61
}
62
}
63
64
65
GNEMultiEntryExitDetector::~GNEMultiEntryExitDetector() {}
66
67
68
GNEMoveOperation*
69
GNEMultiEntryExitDetector::getMoveOperation() {
70
// return move operation for additional placed in view
71
return new GNEMoveOperation(this, myPosition);
72
}
73
74
75
void
76
GNEMultiEntryExitDetector::writeAdditional(OutputDevice& device) const {
77
bool entry = false;
78
bool exit = false;
79
// first check if E3 has at least one entry and one exit
80
for (const auto& additionalChild : getChildAdditionals()) {
81
if (additionalChild->getTagProperty()->getTag() == SUMO_TAG_DET_ENTRY) {
82
entry = true;
83
} else if (additionalChild->getTagProperty()->getTag() == SUMO_TAG_DET_EXIT) {
84
exit = true;
85
}
86
}
87
// check entry/exits
88
if (entry && exit) {
89
device.openTag(getTagProperty()->getTag());
90
device.writeAttr(SUMO_ATTR_ID, getID());
91
if (!myAdditionalName.empty()) {
92
device.writeAttr(SUMO_ATTR_NAME, StringUtils::escapeXML(myAdditionalName));
93
}
94
device.writeAttr(SUMO_ATTR_POSITION, myPosition);
95
if (getAttribute(SUMO_ATTR_PERIOD).size() > 0) {
96
device.writeAttr(SUMO_ATTR_PERIOD, time2string(myPeriod));
97
}
98
if (myOutputFilename.size() > 0) {
99
device.writeAttr(SUMO_ATTR_FILE, myOutputFilename);
100
}
101
if (myVehicleTypes.size() > 0) {
102
device.writeAttr(SUMO_ATTR_VTYPES, myVehicleTypes);
103
}
104
if (myTimeThreshold != myTagProperty->getDefaultTimeValue(SUMO_ATTR_HALTING_TIME_THRESHOLD)) {
105
device.writeAttr(SUMO_ATTR_HALTING_TIME_THRESHOLD, time2string(myTimeThreshold));
106
}
107
if (mySpeedThreshold != myTagProperty->getDefaultDoubleValue(SUMO_ATTR_HALTING_SPEED_THRESHOLD)) {
108
device.writeAttr(SUMO_ATTR_HALTING_SPEED_THRESHOLD, mySpeedThreshold);
109
}
110
if (myExpectedArrival != myTagProperty->getDefaultBoolValue(SUMO_ATTR_EXPECT_ARRIVAL)) {
111
device.writeAttr(SUMO_ATTR_EXPECT_ARRIVAL, myExpectedArrival);
112
}
113
if (myOpenEntry != myTagProperty->getDefaultBoolValue(SUMO_ATTR_OPEN_ENTRY)) {
114
device.writeAttr(SUMO_ATTR_OPEN_ENTRY, myOpenEntry);
115
}
116
// write all entry/exits
117
for (const auto& access : getChildAdditionals()) {
118
access->writeAdditional(device);
119
}
120
// write parameters (Always after children to avoid problems with additionals.xsd)
121
writeParams(device);
122
device.closeTag();
123
} else {
124
WRITE_WARNING("E3 '" + getID() + TL("' needs at least one entry and one exit"));
125
}
126
}
127
128
129
bool
130
GNEMultiEntryExitDetector::isAdditionalValid() const {
131
return true;
132
}
133
134
135
std::string
136
GNEMultiEntryExitDetector::getAdditionalProblem() const {
137
return "";
138
}
139
140
141
void
142
GNEMultiEntryExitDetector::fixAdditionalProblem() {
143
// nothing to fix
144
}
145
146
147
bool
148
GNEMultiEntryExitDetector::checkDrawMoveContour() const {
149
// get edit modes
150
const auto& editModes = myNet->getViewNet()->getEditModes();
151
// check if we're in move mode
152
if (!myNet->getViewNet()->isCurrentlyMovingElements() && editModes.isCurrentSupermodeNetwork() &&
153
!myNet->getViewNet()->getEditNetworkElementShapes().getEditedNetworkElement() &&
154
(editModes.networkEditMode == NetworkEditMode::NETWORK_MOVE) && myNet->getViewNet()->checkOverLockedElement(this, mySelected)) {
155
// only move the first element
156
return myNet->getViewNet()->getViewObjectsSelector().getGUIGlObjectFront() == this;
157
} else {
158
return false;
159
}
160
}
161
162
163
void
164
GNEMultiEntryExitDetector::updateGeometry() {
165
// update additional geometry
166
myAdditionalGeometry.updateSinglePosGeometry(myPosition, 0);
167
}
168
169
170
Position
171
GNEMultiEntryExitDetector::getPositionInView() const {
172
return myPosition;
173
}
174
175
176
void
177
GNEMultiEntryExitDetector::updateCenteringBoundary(const bool updateGrid) {
178
// remove additional from grid
179
if (updateGrid) {
180
myNet->removeGLObjectFromGrid(this);
181
}
182
// now update geometry
183
updateGeometry();
184
// add shape boundary
185
myAdditionalBoundary = myAdditionalGeometry.getShape().getBoxBoundary();
186
// grow
187
myAdditionalBoundary.grow(5);
188
// add additional into RTREE again
189
if (updateGrid) {
190
myNet->addGLObjectIntoGrid(this);
191
}
192
}
193
194
195
void
196
GNEMultiEntryExitDetector::splitEdgeGeometry(const double /*splitPosition*/, const GNENetworkElement* /*originalElement*/, const GNENetworkElement* /*newElement*/, GNEUndoList* /*undoList*/) {
197
// geometry of this element cannot be splitted
198
}
199
200
201
std::string
202
GNEMultiEntryExitDetector::getParentName() const {
203
return myNet->getMicrosimID();
204
}
205
206
207
void
208
GNEMultiEntryExitDetector::drawGL(const GUIVisualizationSettings& s) const {
209
// first check if additional has to be drawn
210
if (myNet->getViewNet()->getDataViewOptions().showAdditionals() &&
211
!myNet->getViewNet()->selectingDetectorsTLSMode()) {
212
// draw parent and child lines
213
drawParentChildLines(s, s.additionalSettings.connectionColor);
214
// draw E3
215
drawSquaredAdditional(s, myPosition, s.detectorSettings.E3Size, GUITexture::E3, GUITexture::E3_SELECTED);
216
}
217
}
218
219
220
std::string
221
GNEMultiEntryExitDetector::getAttribute(SumoXMLAttr key) const {
222
switch (key) {
223
case SUMO_ATTR_ID:
224
return getMicrosimID();
225
case SUMO_ATTR_POSITION:
226
return toString(myPosition);
227
case SUMO_ATTR_PERIOD:
228
if (myPeriod == SUMOTime_MAX_PERIOD) {
229
return "";
230
} else {
231
return time2string(myPeriod);
232
}
233
case SUMO_ATTR_NAME:
234
return myAdditionalName;
235
case SUMO_ATTR_FILE:
236
return myOutputFilename;
237
case SUMO_ATTR_VTYPES:
238
return toString(myVehicleTypes);
239
case SUMO_ATTR_NEXT_EDGES:
240
return toString(myNextEdges);
241
case SUMO_ATTR_DETECT_PERSONS:
242
return toString(myDetectPersons);
243
case SUMO_ATTR_HALTING_TIME_THRESHOLD:
244
return time2string(myTimeThreshold);
245
case SUMO_ATTR_HALTING_SPEED_THRESHOLD:
246
return toString(mySpeedThreshold);
247
case SUMO_ATTR_OPEN_ENTRY:
248
return toString(myOpenEntry);
249
case SUMO_ATTR_EXPECT_ARRIVAL:
250
return toString(myExpectedArrival);
251
default:
252
return getCommonAttribute(this, key);
253
}
254
}
255
256
257
double
258
GNEMultiEntryExitDetector::getAttributeDouble(SumoXMLAttr key) const {
259
throw InvalidArgument(getTagStr() + " doesn't have a double attribute of type '" + toString(key) + "'");
260
}
261
262
263
const Parameterised::Map&
264
GNEMultiEntryExitDetector::getACParametersMap() const {
265
return getParametersMap();
266
}
267
268
269
void
270
GNEMultiEntryExitDetector::setAttribute(SumoXMLAttr key, const std::string& value, GNEUndoList* undoList) {
271
if (value == getAttribute(key)) {
272
return; //avoid needless changes, later logic relies on the fact that attributes have changed
273
}
274
switch (key) {
275
case SUMO_ATTR_ID:
276
case SUMO_ATTR_PERIOD:
277
case SUMO_ATTR_POSITION:
278
case SUMO_ATTR_NAME:
279
case SUMO_ATTR_FILE:
280
case SUMO_ATTR_VTYPES:
281
case SUMO_ATTR_NEXT_EDGES:
282
case SUMO_ATTR_DETECT_PERSONS:
283
case SUMO_ATTR_HALTING_TIME_THRESHOLD:
284
case SUMO_ATTR_HALTING_SPEED_THRESHOLD:
285
case SUMO_ATTR_OPEN_ENTRY:
286
case SUMO_ATTR_EXPECT_ARRIVAL:
287
GNEChange_Attribute::changeAttribute(this, key, value, undoList);
288
break;
289
default:
290
setCommonAttribute(key, value, undoList);
291
break;
292
}
293
}
294
295
296
bool
297
GNEMultiEntryExitDetector::isValid(SumoXMLAttr key, const std::string& value) {
298
switch (key) {
299
case SUMO_ATTR_ID:
300
return isValidDetectorID(value);
301
case SUMO_ATTR_POSITION:
302
return canParse<Position>(value);
303
case SUMO_ATTR_PERIOD:
304
if (value.empty()) {
305
return true;
306
} else {
307
return (canParse<double>(value) && (parse<double>(value) >= 0));
308
}
309
case SUMO_ATTR_NAME:
310
return SUMOXMLDefinitions::isValidAttribute(value);
311
case SUMO_ATTR_FILE:
312
return SUMOXMLDefinitions::isValidFilename(value);
313
case SUMO_ATTR_VTYPES:
314
if (value.empty()) {
315
return true;
316
} else {
317
return SUMOXMLDefinitions::isValidListOfTypeID(value);
318
}
319
case SUMO_ATTR_NEXT_EDGES:
320
if (value.empty()) {
321
return true;
322
} else {
323
return SUMOXMLDefinitions::isValidListOfNetIDs(value);
324
}
325
case SUMO_ATTR_DETECT_PERSONS:
326
if (value.empty()) {
327
return true;
328
} else {
329
return SUMOXMLDefinitions::PersonModeValues.hasString(value);
330
}
331
case SUMO_ATTR_HALTING_TIME_THRESHOLD:
332
case SUMO_ATTR_HALTING_SPEED_THRESHOLD:
333
return canParse<double>(value) && (parse<double>(value) >= 0);
334
case SUMO_ATTR_OPEN_ENTRY:
335
case SUMO_ATTR_EXPECT_ARRIVAL:
336
return canParse<bool>(value);
337
default:
338
return isCommonValid(key, value);
339
}
340
}
341
342
343
bool
344
GNEMultiEntryExitDetector::checkChildAdditionalRestriction() const {
345
int numEntrys = 0;
346
int numExits = 0;
347
// iterate over additional chidls and obtain number of entrys and exits
348
for (auto i : getChildAdditionals()) {
349
if (i->getTagProperty()->getTag() == SUMO_TAG_DET_ENTRY) {
350
numEntrys++;
351
} else if (i->getTagProperty()->getTag() == SUMO_TAG_DET_EXIT) {
352
numExits++;
353
}
354
}
355
// write warnings
356
if (numEntrys == 0) {
357
WRITE_WARNING(TL("An entry-exit detector needs at least one entry detector"));
358
}
359
if (numExits == 0) {
360
WRITE_WARNING(TL("An entry-exit detector needs at least one exit detector"));
361
}
362
// return false depending of number of Entrys and Exits
363
return ((numEntrys != 0) && (numExits != 0));
364
}
365
366
367
std::string
368
GNEMultiEntryExitDetector::getPopUpID() const {
369
return getTagStr() + ":" + getID();
370
}
371
372
373
std::string
374
GNEMultiEntryExitDetector::getHierarchyName() const {
375
return getTagStr();
376
}
377
378
// ===========================================================================
379
// private
380
// ===========================================================================
381
382
void
383
GNEMultiEntryExitDetector::setAttribute(SumoXMLAttr key, const std::string& value) {
384
switch (key) {
385
case SUMO_ATTR_ID:
386
// update microsimID
387
setAdditionalID(value);
388
break;
389
case SUMO_ATTR_POSITION:
390
myPosition = parse<Position>(value);
391
// update boundary (except for template)
392
if (getID().size() > 0) {
393
updateCenteringBoundary(true);
394
}
395
break;
396
case SUMO_ATTR_PERIOD:
397
if (value.empty()) {
398
myPeriod = SUMOTime_MAX_PERIOD;
399
} else {
400
myPeriod = string2time(value);
401
}
402
break;
403
case SUMO_ATTR_NAME:
404
myAdditionalName = value;
405
break;
406
case SUMO_ATTR_FILE:
407
myOutputFilename = value;
408
break;
409
case SUMO_ATTR_VTYPES:
410
myVehicleTypes = parse<std::vector<std::string> >(value);
411
break;
412
case SUMO_ATTR_NEXT_EDGES:
413
myNextEdges = parse<std::vector<std::string> >(value);
414
break;
415
case SUMO_ATTR_DETECT_PERSONS:
416
myDetectPersons = value;
417
break;
418
case SUMO_ATTR_HALTING_TIME_THRESHOLD:
419
myTimeThreshold = parse<SUMOTime>(value);
420
break;
421
case SUMO_ATTR_HALTING_SPEED_THRESHOLD:
422
mySpeedThreshold = parse<double>(value);
423
break;
424
case SUMO_ATTR_OPEN_ENTRY:
425
myOpenEntry = parse<bool>(value);
426
break;
427
case SUMO_ATTR_EXPECT_ARRIVAL:
428
myExpectedArrival = parse<bool>(value);
429
break;
430
default:
431
setCommonAttribute(this, key, value);
432
break;
433
}
434
}
435
436
437
void
438
GNEMultiEntryExitDetector::setMoveShape(const GNEMoveResult& moveResult) {
439
// update position
440
myPosition = moveResult.shapeToUpdate.front();
441
// update geometry
442
updateGeometry();
443
}
444
445
446
void
447
GNEMultiEntryExitDetector::commitMoveShape(const GNEMoveResult& moveResult, GNEUndoList* undoList) {
448
undoList->begin(this, "position of " + getTagStr());
449
GNEChange_Attribute::changeAttribute(this, SUMO_ATTR_POSITION, toString(moveResult.shapeToUpdate.front()), undoList);
450
undoList->end();
451
}
452
453
454
/****************************************************************************/
455
456