Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
eclipse
GitHub Repository: eclipse/sumo
Path: blob/main/src/netedit/elements/additional/GNEDetector.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 GNEDetector.cpp
15
/// @author Pablo Alvarez Lopez
16
/// @date Nov 2015
17
///
18
//
19
/****************************************************************************/
20
#include <config.h>
21
22
#include <netedit/GNENet.h>
23
#include <netedit/GNETagProperties.h>
24
#include <netedit/GNESegment.h>
25
#include <netedit/GNEViewNet.h>
26
#include <netedit/GNEViewParent.h>
27
#include <netedit/changes/GNEChange_Attribute.h>
28
#include <netedit/elements/additional/GNEAdditionalHandler.h>
29
#include <netedit/frames/common/GNEMoveFrame.h>
30
#include <utils/gui/div/GLHelper.h>
31
#include <utils/gui/globjects/GLIncludes.h>
32
33
#include "GNEDetector.h"
34
35
// ===========================================================================
36
// member method definitions
37
// ===========================================================================
38
39
GNEDetector::GNEDetector(GNENet* net, SumoXMLTag tag) :
40
GNEAdditional("", net, "", tag, "") {
41
}
42
43
44
GNEDetector::GNEDetector(const std::string& id, GNENet* net, const std::string& filename, SumoXMLTag tag, const double pos, const SUMOTime period,
45
GNELane* lane, const std::string& outputFilename, const std::vector<std::string>& vehicleTypes, const std::vector<std::string>& nextEdges,
46
const std::string& detectPersons, const std::string& name, const bool friendlyPos, const Parameterised::Map& parameters) :
47
GNEAdditional(id, net, filename, tag, name),
48
Parameterised(parameters),
49
myPositionOverLane(pos),
50
myPeriod(period),
51
myOutputFilename(outputFilename),
52
myVehicleTypes(vehicleTypes),
53
myNextEdges(nextEdges),
54
myDetectPersons(detectPersons),
55
myFriendlyPosition(friendlyPos) {
56
// update output filename
57
if (outputFilename.empty()) {
58
myOutputFilename = id + ".xml";
59
}
60
// set parents
61
setParent<GNELane*>(lane);
62
}
63
64
65
GNEDetector::GNEDetector(const std::string& id, GNENet* net, const std::string& filename, SumoXMLTag tag, const double pos, const SUMOTime period,
66
const std::vector<GNELane*>& lanes, const std::string& outputFilename, const std::vector<std::string>& vehicleTypes,
67
const std::vector<std::string>& nextEdges, const std::string& detectPersons, const std::string& name, const bool friendlyPos,
68
const Parameterised::Map& parameters) :
69
GNEAdditional(id, net, filename, tag, name),
70
Parameterised(parameters),
71
myPositionOverLane(pos),
72
myPeriod(period),
73
myOutputFilename(outputFilename),
74
myVehicleTypes(vehicleTypes),
75
myNextEdges(nextEdges),
76
myDetectPersons(detectPersons),
77
myFriendlyPosition(friendlyPos) {
78
// update output filename
79
if (outputFilename.empty()) {
80
myOutputFilename = id + ".xml";
81
}
82
// set parents
83
setParents<GNELane*>(lanes);
84
}
85
86
87
GNEDetector::GNEDetector(GNEAdditional* additionalParent, SumoXMLTag tag, const double pos, const SUMOTime period, GNELane* lane,
88
const std::string& outputFilename, const std::string& name, const bool friendlyPos, const Parameterised::Map& parameters) :
89
GNEAdditional(additionalParent, tag, name),
90
Parameterised(parameters),
91
myPositionOverLane(pos),
92
myPeriod(period),
93
myOutputFilename(outputFilename),
94
myFriendlyPosition(friendlyPos) {
95
// set parents
96
setParent<GNELane*>(lane);
97
setParent<GNEAdditional*>(additionalParent);
98
}
99
100
101
GNEDetector::~GNEDetector() {}
102
103
104
GNEMoveOperation*
105
GNEDetector::getMoveOperation() {
106
// check modes and detector type
107
if (!myNet->getViewNet()->getEditModes().isCurrentSupermodeNetwork() || (myNet->getViewNet()->getEditModes().networkEditMode != NetworkEditMode::NETWORK_MOVE)) {
108
return nullptr;
109
} else if (myTagProperty->getTag() == SUMO_TAG_LANE_AREA_DETECTOR) {
110
return getMoveOperationSingleLane(myPositionOverLane, getAttributeDouble(SUMO_ATTR_ENDPOS));
111
} else if (myTagProperty->getTag() == GNE_TAG_MULTI_LANE_AREA_DETECTOR) {
112
return getMoveOperationMultiLane(myPositionOverLane, getAttributeDouble(SUMO_ATTR_ENDPOS));
113
} else {
114
// return move operation for detectors with single position placed over shape (E1, EntryExits..)
115
return new GNEMoveOperation(this, getParentLanes().front(), myPositionOverLane,
116
myNet->getViewNet()->getViewParent()->getMoveFrame()->getCommonMoveOptions()->getAllowChangeLane());
117
}
118
}
119
120
121
double
122
GNEDetector::getPositionOverLane() const {
123
return myPositionOverLane;
124
}
125
126
127
bool
128
GNEDetector::checkDrawMoveContour() const {
129
// get edit modes
130
const auto& editModes = myNet->getViewNet()->getEditModes();
131
// check if we're in move mode
132
if (!myNet->getViewNet()->isCurrentlyMovingElements() && editModes.isCurrentSupermodeNetwork() &&
133
!myNet->getViewNet()->getEditNetworkElementShapes().getEditedNetworkElement() &&
134
(editModes.networkEditMode == NetworkEditMode::NETWORK_MOVE) && myNet->getViewNet()->checkOverLockedElement(this, mySelected)) {
135
// only move the first element
136
if (myNet->getViewNet()->getViewObjectsSelector().getGUIGlObjectFront() == this) {
137
// special case for multiple lane area detectors
138
if (myTagProperty->getTag() == GNE_TAG_MULTI_LANE_AREA_DETECTOR) {
139
auto segment = gViewObjectsHandler.getSelectedSegment(this);
140
if (segment && segment->getJunction()) {
141
return false;
142
} else if (segment && segment->getLane()) {
143
// ensure that is the first or the last lane
144
if (segment->getLaneIndex() == 0) {
145
return true;
146
} else if (segment->getLaneIndex() == ((int)getParentLanes().size() - 1)) {
147
return true;
148
}
149
} else {
150
// this is the start or end point
151
return true;
152
}
153
} else {
154
return true;
155
}
156
}
157
}
158
return false;
159
}
160
161
162
GNELane*
163
GNEDetector::getLane() const {
164
return getParentLanes().front();
165
}
166
167
168
Position
169
GNEDetector::getPositionInView() const {
170
return myAdditionalGeometry.getShape().getPolygonCenter();
171
}
172
173
174
void
175
GNEDetector::updateCenteringBoundary(const bool /*updateGrid*/) {
176
// nothing to update
177
}
178
179
void
180
GNEDetector::splitEdgeGeometry(const double splitPosition, const GNENetworkElement* originalElement,
181
const GNENetworkElement* newElement, GNEUndoList* undoList) {
182
// only split geometry of E2 multilane detectors
183
if (myTagProperty->getTag() == GNE_TAG_MULTI_LANE_AREA_DETECTOR) {
184
// obtain new list of E2 lanes
185
std::string newE2Lanes = getNewListOfParents(originalElement, newElement);
186
// update E2 Lanes
187
if (newE2Lanes.size() > 0) {
188
setAttribute(SUMO_ATTR_LANES, newE2Lanes, undoList);
189
}
190
} else if (splitPosition < myPositionOverLane) {
191
// change lane
192
setAttribute(SUMO_ATTR_LANE, newElement->getID(), undoList);
193
// now adjust start position
194
setAttribute(SUMO_ATTR_POSITION, toString(myPositionOverLane - splitPosition), undoList);
195
}
196
}
197
198
199
double
200
GNEDetector::getGeometryPositionOverLane() const {
201
double fixedPos = myPositionOverLane;
202
const double len = getLane()->getParentEdge()->getNBEdge()->getFinalLength();
203
double length = 0;
204
GNEAdditionalHandler::fixLanePosition(fixedPos, length, len);
205
return (fixedPos * getLane()->getLengthGeometryFactor());
206
}
207
208
209
210
std::string
211
GNEDetector::getParentName() const {
212
return getLane()->getID();
213
}
214
215
216
const Parameterised::Map&
217
GNEDetector::getACParametersMap() const {
218
return getParametersMap();
219
}
220
221
222
std::string
223
GNEDetector::getPopUpID() const {
224
return getTagStr() + ": " + getID();
225
}
226
227
228
std::string
229
GNEDetector::getHierarchyName() const {
230
return getTagStr();
231
}
232
233
234
std::string
235
GNEDetector::getDetectorAttribute(SumoXMLAttr key) const {
236
switch (key) {
237
case SUMO_ATTR_ID:
238
return getMicrosimID();
239
case SUMO_ATTR_LANE:
240
return getParentLanes().front()->getID();
241
case SUMO_ATTR_POSITION:
242
return toString(myPositionOverLane);
243
case SUMO_ATTR_PERIOD:
244
if (myPeriod == SUMOTime_MAX_PERIOD) {
245
return "";
246
} else {
247
return time2string(myPeriod);
248
}
249
case SUMO_ATTR_NAME:
250
return myAdditionalName;
251
case SUMO_ATTR_FILE:
252
return myOutputFilename;
253
case SUMO_ATTR_VTYPES:
254
return toString(myVehicleTypes);
255
case SUMO_ATTR_NEXT_EDGES:
256
return toString(myNextEdges);
257
case SUMO_ATTR_DETECT_PERSONS:
258
return toString(myDetectPersons);
259
case SUMO_ATTR_FRIENDLY_POS:
260
return toString(myFriendlyPosition);
261
case GNE_ATTR_SHIFTLANEINDEX:
262
return "";
263
default:
264
return getCommonAttribute(this, key);
265
}
266
}
267
268
269
double
270
GNEDetector::getDetectorAttributeDouble(SumoXMLAttr key) const {
271
switch (key) {
272
case SUMO_ATTR_POSITION:
273
return myPositionOverLane;
274
default:
275
throw InvalidArgument(getTagStr() + " doesn't have an attribute of type '" + toString(key) + "'");
276
}
277
}
278
279
280
void
281
GNEDetector::setDetectorAttribute(SumoXMLAttr key, const std::string& value, GNEUndoList* undoList) {
282
switch (key) {
283
case SUMO_ATTR_ID:
284
case SUMO_ATTR_LANE:
285
case SUMO_ATTR_POSITION:
286
case SUMO_ATTR_PERIOD:
287
case SUMO_ATTR_NAME:
288
case SUMO_ATTR_FILE:
289
case SUMO_ATTR_VTYPES:
290
case SUMO_ATTR_NEXT_EDGES:
291
case SUMO_ATTR_DETECT_PERSONS:
292
case SUMO_ATTR_FRIENDLY_POS:
293
case GNE_ATTR_SHIFTLANEINDEX:
294
GNEChange_Attribute::changeAttribute(this, key, value, undoList);
295
break;
296
default:
297
setCommonAttribute(key, value, undoList);
298
break;
299
}
300
}
301
302
303
304
bool
305
GNEDetector::isDetectorValid(SumoXMLAttr key, const std::string& value) {
306
switch (key) {
307
case SUMO_ATTR_ID:
308
return isValidDetectorID(value);
309
case SUMO_ATTR_LANE:
310
if (myNet->getAttributeCarriers()->retrieveLane(value, false) != nullptr) {
311
return true;
312
} else {
313
return false;
314
}
315
case SUMO_ATTR_POSITION:
316
return canParse<double>(value) && fabs(parse<double>(value)) < getParentLanes().front()->getParentEdge()->getNBEdge()->getFinalLength();
317
case SUMO_ATTR_PERIOD:
318
if (value.empty()) {
319
return true;
320
} else {
321
return (canParse<double>(value) && (parse<double>(value) >= 0));
322
}
323
case SUMO_ATTR_NAME:
324
return SUMOXMLDefinitions::isValidAttribute(value);
325
case SUMO_ATTR_FILE:
326
return SUMOXMLDefinitions::isValidFilename(value);
327
case SUMO_ATTR_VTYPES:
328
if (value.empty()) {
329
return true;
330
} else {
331
return SUMOXMLDefinitions::isValidListOfTypeID(value);
332
}
333
case SUMO_ATTR_NEXT_EDGES:
334
if (value.empty()) {
335
return true;
336
} else {
337
return SUMOXMLDefinitions::isValidListOfNetIDs(value);
338
}
339
case SUMO_ATTR_DETECT_PERSONS:
340
if (value.empty()) {
341
return true;
342
} else {
343
return SUMOXMLDefinitions::PersonModeValues.hasString(value);
344
}
345
case SUMO_ATTR_FRIENDLY_POS:
346
return canParse<bool>(value);
347
default:
348
return isCommonValid(key, value);
349
}
350
}
351
352
353
void
354
GNEDetector::writeDetectorValues(OutputDevice& device) const {
355
if ((myPeriod > 0) && (myPeriod != SUMOTime_MAX_PERIOD)) {
356
device.writeAttr(SUMO_ATTR_PERIOD, time2string(myPeriod));
357
}
358
if (myAdditionalName.size() > 0) {
359
device.writeAttr(SUMO_ATTR_NAME, StringUtils::escapeXML(myAdditionalName));
360
}
361
if (myOutputFilename.size() > 0) {
362
device.writeAttr(SUMO_ATTR_FILE, myOutputFilename);
363
}
364
if (myVehicleTypes.size() > 0) {
365
device.writeAttr(SUMO_ATTR_VTYPES, myVehicleTypes);
366
}
367
if (myNextEdges.size() > 0) {
368
device.writeAttr(SUMO_ATTR_NEXT_EDGES, myNextEdges);
369
}
370
if ((myDetectPersons.size() > 0) && (myDetectPersons != SUMOXMLDefinitions::PersonModeValues.getString(PersonMode::NONE))) {
371
device.writeAttr(SUMO_ATTR_DETECT_PERSONS, myDetectPersons);
372
}
373
if (myFriendlyPosition) {
374
device.writeAttr(SUMO_ATTR_FRIENDLY_POS, myFriendlyPosition);
375
}
376
}
377
378
379
void
380
GNEDetector::setDetectorAttribute(SumoXMLAttr key, const std::string& value) {
381
switch (key) {
382
case SUMO_ATTR_ID:
383
// update microsimID
384
setAdditionalID(value);
385
break;
386
case SUMO_ATTR_LANE:
387
replaceAdditionalParentLanes(value);
388
break;
389
case SUMO_ATTR_POSITION:
390
myPositionOverLane = parse<double>(value);
391
break;
392
case SUMO_ATTR_PERIOD:
393
if (value.empty()) {
394
myPeriod = SUMOTime_MAX_PERIOD;
395
} else {
396
myPeriod = string2time(value);
397
}
398
break;
399
case SUMO_ATTR_FILE:
400
myOutputFilename = value;
401
break;
402
case SUMO_ATTR_NAME:
403
myAdditionalName = value;
404
break;
405
case SUMO_ATTR_VTYPES:
406
myVehicleTypes = parse<std::vector<std::string> >(value);
407
break;
408
case SUMO_ATTR_NEXT_EDGES:
409
myNextEdges = parse<std::vector<std::string> >(value);
410
break;
411
case SUMO_ATTR_DETECT_PERSONS:
412
myDetectPersons = value;
413
break;
414
case SUMO_ATTR_FRIENDLY_POS:
415
myFriendlyPosition = parse<bool>(value);
416
break;
417
case GNE_ATTR_SHIFTLANEINDEX:
418
shiftLaneIndex();
419
break;
420
default:
421
setCommonAttribute(this, key, value);
422
break;
423
}
424
}
425
426
427
void
428
GNEDetector::drawE1Shape(const GUIVisualizationSettings::Detail d, const double exaggeration,
429
const RGBColor& mainColor, const RGBColor& secondColor) const {
430
// push matrix
431
GLHelper::pushMatrix();
432
// set line width
433
glLineWidth(1.0);
434
// translate to center geometry
435
glTranslated(myAdditionalGeometry.getShape().front().x(), myAdditionalGeometry.getShape().front().y(), 0);
436
// rotate over lane
437
GUIGeometry::rotateOverLane(myAdditionalGeometry.getShapeRotations().front() + 90);
438
// scale
439
glScaled(exaggeration, exaggeration, 1);
440
// set main color
441
GLHelper::setColor(mainColor);
442
// begin draw square
443
glBegin(GL_QUADS);
444
// draw square
445
glVertex2d(-1.0, 2);
446
glVertex2d(-1.0, -2);
447
glVertex2d(1.0, -2);
448
glVertex2d(1.0, 2);
449
// end draw square
450
glEnd();
451
// move top
452
glTranslated(0, 0, .01);
453
// begin draw line
454
glBegin(GL_LINES);
455
// draw lines
456
glVertex2d(0, 2 - .1);
457
glVertex2d(0, -2 + .1);
458
// end draw line
459
glEnd();
460
// draw center only in draw in level 2
461
if (d <= GUIVisualizationSettings::Detail::AdditionalDetails) {
462
// set main color
463
GLHelper::setColor(secondColor);
464
// set polygon mode
465
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
466
// begin draw square
467
glBegin(GL_QUADS);
468
// draw square
469
glVertex2f(-1.0, 2);
470
glVertex2f(-1.0, -2);
471
glVertex2f(1.0, -2);
472
glVertex2f(1.0, 2);
473
// end draw square
474
glEnd();
475
// rotate 90 degrees
476
glRotated(90, 0, 0, -1);
477
//set polygon mode
478
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
479
// begin draw line
480
glBegin(GL_LINES);
481
// draw line
482
glVertex2d(0, 1.7);
483
glVertex2d(0, -1.7);
484
// end draw line
485
glEnd();
486
//arrow
487
glTranslated(2, 0, 0);
488
GLHelper::setColor(mainColor);
489
GLHelper::drawTriangleAtEnd(Position(0, 0), Position(0.5, 0), (double) 0.5, (double) 1);
490
}
491
// pop matrix
492
GLHelper::popMatrix();
493
}
494
495
496
void
497
GNEDetector::drawE1DetectorLogo(const GUIVisualizationSettings& s, const GUIVisualizationSettings::Detail d,
498
const double exaggeration, const std::string& logo, const RGBColor& textColor) const {
499
// only draw in level 2
500
if (d <= GUIVisualizationSettings::Detail::Text) {
501
// calculate position
502
const Position pos = myAdditionalGeometry.getShape().front();
503
// calculate rotation
504
const double rot = s.getTextAngle(myAdditionalGeometry.getShapeRotations().front() + 90);
505
// Start pushing matrix
506
GLHelper::pushMatrix();
507
// Traslate to position
508
glTranslated(pos.x(), pos.y(), 0.1);
509
// scale text
510
glScaled(exaggeration, exaggeration, 1);
511
// draw E1 logo
512
GLHelper::drawText(logo + " ", Position(), .1, 1.5, textColor, rot);
513
// pop matrix
514
GLHelper::popMatrix();
515
}
516
}
517
518
519
void
520
GNEDetector::drawE2DetectorLogo(const GUIVisualizationSettings& s, const GUIVisualizationSettings::Detail d,
521
const double exaggeration, const std::string& logo, const RGBColor& textColor) const {
522
// only draw in level 2
523
if (d <= GUIVisualizationSettings::Detail::Text) {
524
// calculate middle point
525
const double middlePoint = (myAdditionalGeometry.getShape().length2D() * 0.5);
526
// calculate position
527
const Position pos = myAdditionalGeometry.getShape().positionAtOffset2D(middlePoint);
528
// calculate rotation
529
const double rot = s.getTextAngle(myAdditionalGeometry.getShape().rotationDegreeAtOffset(middlePoint) + 90);
530
// Start pushing matrix
531
GLHelper::pushMatrix();
532
// Traslate to position
533
glTranslated(pos.x(), pos.y(), 0.1);
534
// scale text
535
glScaled(exaggeration, exaggeration, 1);
536
// draw E1 logo
537
GLHelper::drawText(logo, Position(), .1, 1.5, textColor, rot);
538
// pop matrix
539
GLHelper::popMatrix();
540
}
541
}
542
543
/****************************************************************************/
544
545