Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
eclipse
GitHub Repository: eclipse/sumo
Path: blob/main/src/netedit/elements/additional/GNELaneAreaDetector.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 GNELaneAreaDetector.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/GNESegment.h>
24
#include <netedit/GNETagProperties.h>
25
#include <netedit/GNEUndoList.h>
26
#include <netedit/GNEViewNet.h>
27
#include <netedit/GNEViewParent.h>
28
#include <netedit/changes/GNEChange_Attribute.h>
29
#include <netedit/changes/GNEChange_Connection.h>
30
#include <netedit/elements/network/GNEConnection.h>
31
#include <netedit/frames/network/GNETLSEditorFrame.h>
32
#include <utils/gui/div/GLHelper.h>
33
#include <utils/gui/div/GUIGlobalViewObjectsHandler.h>
34
#include <utils/gui/globjects/GLIncludes.h>
35
#include <utils/xml/NamespaceIDs.h>
36
37
#include "GNELaneAreaDetector.h"
38
#include "GNEAdditionalHandler.h"
39
40
// ===========================================================================
41
// member method definitions
42
// ===========================================================================
43
44
GNELaneAreaDetector::GNELaneAreaDetector(SumoXMLTag tag, GNENet* net) :
45
GNEDetector(net, tag) {
46
}
47
48
49
GNELaneAreaDetector::GNELaneAreaDetector(const std::string& id, GNENet* net, const std::string& filename, GNELane* lane, double pos, double length, const SUMOTime freq,
50
const std::string& trafficLight, const std::string& outputFilename, const std::vector<std::string>& vehicleTypes, const std::vector<std::string>& nextEdges,
51
const std::string& detectPersons, const std::string& name, const SUMOTime timeThreshold, double speedThreshold, const double jamThreshold, const bool friendlyPos,
52
const bool show, const Parameterised::Map& parameters) :
53
GNEDetector(id, net, filename, SUMO_TAG_LANE_AREA_DETECTOR, pos, freq, lane, outputFilename, vehicleTypes, nextEdges,
54
detectPersons, name, friendlyPos, parameters),
55
myEndPositionOverLane(pos + length),
56
myTimeThreshold(timeThreshold),
57
mySpeedThreshold(speedThreshold),
58
myJamThreshold(jamThreshold),
59
myTrafficLight(trafficLight),
60
myShow(show) {
61
}
62
63
64
GNELaneAreaDetector::GNELaneAreaDetector(const std::string& id, GNENet* net, const std::string& filename, std::vector<GNELane*> lanes, double pos, double endPos, const SUMOTime freq,
65
const std::string& trafficLight, const std::string& outputFilename, const std::vector<std::string>& vehicleTypes, const std::vector<std::string>& nextEdges,
66
const std::string& detectPersons, const std::string& name, const SUMOTime timeThreshold, double speedThreshold, const double jamThreshold, const bool friendlyPos, const bool show,
67
const Parameterised::Map& parameters) :
68
GNEDetector(id, net, filename, GNE_TAG_MULTI_LANE_AREA_DETECTOR, pos, freq, lanes, outputFilename, vehicleTypes, nextEdges,
69
detectPersons, name, friendlyPos, parameters),
70
myEndPositionOverLane(endPos),
71
myTimeThreshold(timeThreshold),
72
mySpeedThreshold(speedThreshold),
73
myJamThreshold(jamThreshold),
74
myTrafficLight(trafficLight),
75
myShow(show) {
76
}
77
78
79
GNELaneAreaDetector::~GNELaneAreaDetector() {
80
}
81
82
83
void
84
GNELaneAreaDetector::writeAdditional(OutputDevice& device) const {
85
device.openTag(SUMO_TAG_LANE_AREA_DETECTOR);
86
device.writeAttr(SUMO_ATTR_ID, getID());
87
// continue depending of E2 type
88
if (myTagProperty->getTag() == SUMO_TAG_LANE_AREA_DETECTOR) {
89
device.writeAttr(SUMO_ATTR_LANE, getParentLanes().front()->getID());
90
device.writeAttr(SUMO_ATTR_POSITION, myPositionOverLane);
91
device.writeAttr(SUMO_ATTR_LENGTH, toString(myEndPositionOverLane - myPositionOverLane));
92
} else {
93
device.writeAttr(SUMO_ATTR_LANES, getAttribute(SUMO_ATTR_LANES));
94
device.writeAttr(SUMO_ATTR_POSITION, myPositionOverLane);
95
device.writeAttr(SUMO_ATTR_ENDPOS, myEndPositionOverLane);
96
}
97
// write common detector parameters
98
writeDetectorValues(device);
99
// write specific attributes
100
if (myTrafficLight.size() > 0) {
101
device.writeAttr(SUMO_ATTR_TLID, myTrafficLight);
102
}
103
if (myTimeThreshold != myTagProperty->getDefaultTimeValue(SUMO_ATTR_HALTING_TIME_THRESHOLD)) {
104
device.writeAttr(SUMO_ATTR_HALTING_TIME_THRESHOLD, time2string(myTimeThreshold));
105
}
106
if (mySpeedThreshold != myTagProperty->getDefaultDoubleValue(SUMO_ATTR_HALTING_SPEED_THRESHOLD)) {
107
device.writeAttr(SUMO_ATTR_HALTING_SPEED_THRESHOLD, mySpeedThreshold);
108
}
109
if (myJamThreshold != myTagProperty->getDefaultDoubleValue(SUMO_ATTR_JAM_DIST_THRESHOLD)) {
110
device.writeAttr(SUMO_ATTR_JAM_DIST_THRESHOLD, myJamThreshold);
111
}
112
if (myShow != myTagProperty->getDefaultBoolValue(SUMO_ATTR_SHOW_DETECTOR)) {
113
device.writeAttr(SUMO_ATTR_SHOW_DETECTOR, myShow);
114
}
115
// write parameters (Always after children to avoid problems with additionals.xsd)
116
writeParams(device);
117
device.closeTag();
118
}
119
120
121
bool
122
GNELaneAreaDetector::isAdditionalValid() const {
123
if (getParentLanes().size() == 1) {
124
// with friendly position enabled position are "always fixed"
125
if (myFriendlyPosition) {
126
return true;
127
} else {
128
return (myPositionOverLane >= 0) && (myEndPositionOverLane <= getParentLanes().front()->getParentEdge()->getNBEdge()->getFinalLength());
129
}
130
} else {
131
// first check if there is connection between all consecutive lanes
132
if (areLaneConnected(getParentLanes())) {
133
// with friendly position enabled position are "always fixed"
134
if (myFriendlyPosition) {
135
return true;
136
} else {
137
return (myPositionOverLane >= 0) &&
138
(myEndPositionOverLane >= 0) &&
139
(myPositionOverLane <= getParentLanes().front()->getParentEdge()->getNBEdge()->getFinalLength()) &&
140
(myEndPositionOverLane <= getParentLanes().back()->getParentEdge()->getNBEdge()->getFinalLength());
141
}
142
} else {
143
return false;
144
}
145
}
146
}
147
148
149
std::string
150
GNELaneAreaDetector::getAdditionalProblem() const {
151
// declare variable for error position
152
std::string errorFirstLanePosition, separator, errorLastLanePosition;
153
if (getParentLanes().size() == 1) {
154
// check positions over lane
155
if (myPositionOverLane < 0) {
156
errorFirstLanePosition = (toString(SUMO_ATTR_POSITION) + " < 0");
157
}
158
if (myPositionOverLane > getParentLanes().front()->getParentEdge()->getNBEdge()->getFinalLength()) {
159
errorFirstLanePosition = (toString(SUMO_ATTR_POSITION) + TL(" > lanes's length"));
160
}
161
} else {
162
// abort if lanes aren't consecutives
163
if (!areLaneConsecutives(getParentLanes())) {
164
return TL("lanes aren't consecutives");
165
}
166
// abort if lanes aren't connected
167
if (!areLaneConnected(getParentLanes())) {
168
return TL("lanes aren't connected");
169
}
170
// check positions over first lane
171
if (myPositionOverLane < 0) {
172
errorFirstLanePosition = (toString(SUMO_ATTR_POSITION) + " < 0");
173
}
174
if (myPositionOverLane > getParentLanes().front()->getParentEdge()->getNBEdge()->getFinalLength()) {
175
errorFirstLanePosition = (toString(SUMO_ATTR_POSITION) + TL(" > lanes's length"));
176
}
177
// check positions over last lane
178
if (myEndPositionOverLane < 0) {
179
errorLastLanePosition = (toString(SUMO_ATTR_ENDPOS) + " < 0");
180
}
181
if (myEndPositionOverLane > getParentLanes().back()->getParentEdge()->getNBEdge()->getFinalLength()) {
182
errorLastLanePosition = (toString(SUMO_ATTR_ENDPOS) + TL(" > lanes's length"));
183
}
184
}
185
// check separator
186
if ((errorFirstLanePosition.size() > 0) && (errorLastLanePosition.size() > 0)) {
187
separator = TL(" and ");
188
}
189
// return error message
190
return errorFirstLanePosition + separator + errorLastLanePosition;
191
}
192
193
194
void
195
GNELaneAreaDetector::fixAdditionalProblem() {
196
if (getParentLanes().size() == 1) {
197
// obtain position and length
198
double newPositionOverLane = myPositionOverLane;
199
double newLength = (myEndPositionOverLane - myPositionOverLane);
200
// fix pos and length using fixE2DetectorPosition
201
GNEAdditionalHandler::fixLanePosition(newPositionOverLane, newLength, getParentLanes().at(0)->getParentEdge()->getNBEdge()->getFinalLength());
202
// set new position and length
203
setAttribute(SUMO_ATTR_POSITION, toString(newPositionOverLane), myNet->getViewNet()->getUndoList());
204
setAttribute(SUMO_ATTR_LENGTH, toString(newLength), myNet->getViewNet()->getUndoList());
205
} else {
206
if (!areLaneConsecutives(getParentLanes())) {
207
// build connections between all consecutive lanes
208
bool foundConnection = true;
209
int i = 0;
210
// iterate over all lanes, and stop if myE2valid is false
211
while (i < ((int)getParentLanes().size() - 1)) {
212
// change foundConnection to false
213
foundConnection = false;
214
// if a connection between "from" lane and "to" lane of connection is found, change myE2valid to true again
215
for (const auto& connection : getParentLanes().at(i)->getParentEdge()->getGNEConnections()) {
216
if ((connection->getLaneFrom() == getParentLanes().at(i)) && (connection->getLaneTo() == getParentLanes().at(i + 1))) {
217
foundConnection = true;
218
}
219
}
220
// if connection wasn't found
221
if (!foundConnection) {
222
// create new connection manually
223
NBEdge::Connection newCon(getParentLanes().at(i)->getIndex(), getParentLanes().at(i + 1)->getParentEdge()->getNBEdge(), getParentLanes().at(i + 1)->getIndex());
224
// allow to undo creation of new lane
225
myNet->getViewNet()->getUndoList()->add(new GNEChange_Connection(getParentLanes().at(i)->getParentEdge(), newCon, false, true), true);
226
}
227
// update lane iterator
228
i++;
229
}
230
} else {
231
// declare new positions
232
double newPositionOverLane = myPositionOverLane;
233
double newEndPositionOverLane = myEndPositionOverLane;
234
// fix pos and length checkAndFixDetectorPosition
235
GNEAdditionalHandler::fixMultiLanePosition(
236
newPositionOverLane, getParentLanes().front()->getParentEdge()->getNBEdge()->getFinalLength(),
237
newEndPositionOverLane, getParentLanes().back()->getParentEdge()->getNBEdge()->getFinalLength());
238
// set new position and endPosition
239
setAttribute(SUMO_ATTR_POSITION, toString(newPositionOverLane), myNet->getViewNet()->getUndoList());
240
setAttribute(SUMO_ATTR_ENDPOS, toString(newEndPositionOverLane), myNet->getViewNet()->getUndoList());
241
}
242
}
243
}
244
245
246
void
247
GNELaneAreaDetector::updateGeometry() {
248
// check E2 detector
249
if (myTagProperty->getTag() == GNE_TAG_MULTI_LANE_AREA_DETECTOR) {
250
// compute path
251
computePathElement();
252
} else {
253
// Cut shape using as delimitators fixed start position and fixed end position
254
myAdditionalGeometry.updateGeometry(getParentLanes().front()->getLaneShape(), getStartGeometryPositionOverLane(), getEndGeometryPositionOverLane(), myMoveElementLateralOffset);
255
}
256
}
257
258
259
void
260
GNELaneAreaDetector::drawGL(const GUIVisualizationSettings& s) const {
261
// check drawing conditions
262
if ((myTagProperty->getTag() == SUMO_TAG_LANE_AREA_DETECTOR) &&
263
myNet->getViewNet()->getDataViewOptions().showAdditionals() &&
264
!myNet->getViewNet()->selectingDetectorsTLSMode()) {
265
// Obtain exaggeration of the draw
266
const double E2Exaggeration = getExaggeration(s);
267
// get detail level
268
const auto d = s.getDetailLevel(E2Exaggeration);
269
// draw geometry only if we'rent in drawForObjectUnderCursor mode
270
if (s.checkDrawAdditional(d, isAttributeCarrierSelected())) {
271
// draw E2
272
drawE2(s, d, E2Exaggeration);
273
// draw lock icon
274
GNEViewNetHelper::LockIcon::drawLockIcon(d, this, getType(), myAdditionalGeometry.getShape().getCentroid(), E2Exaggeration);
275
// Draw additional ID
276
drawAdditionalID(s);
277
// draw additional name
278
drawAdditionalName(s);
279
// draw dotted contour
280
myAdditionalContour.drawDottedContours(s, d, this, s.dottedContourSettings.segmentWidth, true);
281
}
282
// calculate contour and draw dotted geometry
283
myAdditionalContour.calculateContourExtrudedShape(s, d, this, myAdditionalGeometry.getShape(), getType(), s.detectorSettings.E2Width,
284
E2Exaggeration, true, true, 0, nullptr, getParentLanes().front()->getParentEdge());
285
}
286
}
287
288
289
void
290
GNELaneAreaDetector::computePathElement() {
291
// calculate path
292
myNet->getNetworkPathManager()->calculateConsecutivePathLanes(this, getParentLanes());
293
}
294
295
296
void
297
GNELaneAreaDetector::drawLanePartialGL(const GUIVisualizationSettings& s, const GNESegment* segment, const double offsetFront) const {
298
// check if E2 can be drawn
299
if (segment->getLane() && (myTagProperty->getTag() == GNE_TAG_MULTI_LANE_AREA_DETECTOR) &&
300
myNet->getViewNet()->getDataViewOptions().showAdditionals() && !myNet->getViewNet()->selectingDetectorsTLSMode()) {
301
const bool movingGeometryPoints = drawMovingGeometryPoints(false);
302
// Obtain exaggeration of the draw
303
const double E2Exaggeration = getExaggeration(s);
304
// get detail level
305
const auto d = s.getDetailLevel(E2Exaggeration);
306
// calculate startPos
307
const double geometryDepartPos = getAttributeDouble(SUMO_ATTR_POSITION);
308
// get endPos
309
const double geometryEndPos = getAttributeDouble(SUMO_ATTR_ENDPOS);
310
// declare path geometry
311
GUIGeometry E2Geometry;
312
// update pathGeometry depending of first and last segment
313
if (segment->isFirstSegment() && segment->isLastSegment()) {
314
E2Geometry.updateGeometry(segment->getLane()->getLaneGeometry().getShape(),
315
geometryDepartPos,
316
Position::INVALID,
317
geometryEndPos,
318
Position::INVALID);
319
} else if (segment->isFirstSegment()) {
320
E2Geometry.updateGeometry(segment->getLane()->getLaneGeometry().getShape(),
321
geometryDepartPos,
322
Position::INVALID,
323
-1,
324
Position::INVALID);
325
} else if (segment->isLastSegment()) {
326
E2Geometry.updateGeometry(segment->getLane()->getLaneGeometry().getShape(),
327
-1,
328
Position::INVALID,
329
geometryEndPos,
330
Position::INVALID);
331
} else {
332
E2Geometry = segment->getLane()->getLaneGeometry();
333
}
334
// draw geometry only if we'rent in drawForObjectUnderCursor mode
335
if (s.checkDrawAdditional(d, isAttributeCarrierSelected())) {
336
// draw E2 partial
337
drawE2PartialLane(s, d, segment, offsetFront, E2Geometry, E2Exaggeration, movingGeometryPoints);
338
// draw additional ID
339
drawName(getCenteringBoundary().getCenter(), s.scale, s.addName);
340
// draw dotted contour
341
if (movingGeometryPoints) {
342
// get mouse position
343
const Position mousePosition = myNet->getViewNet()->getPositionInformation();
344
// get snap radius
345
const double snap_radius = myNet->getViewNet()->getVisualisationSettings().neteditSizeSettings.additionalGeometryPointRadius;
346
if (segment->getFromContour() && E2Geometry.getShape().front().distanceSquaredTo2D(mousePosition) <= (snap_radius * snap_radius)) {
347
segment->getFromContour()->drawDottedContours(s, d, this, s.dottedContourSettings.segmentWidthSmall, true);
348
} else if (segment->getToContour() && E2Geometry.getShape().back().distanceSquaredTo2D(mousePosition) <= (snap_radius * snap_radius)) {
349
segment->getToContour()->drawDottedContours(s, d, this, s.dottedContourSettings.segmentWidthSmall, true);
350
}
351
} else {
352
segment->getContour()->drawDottedContours(s, d, this, s.dottedContourSettings.segmentWidth, true);
353
}
354
}
355
// calculate contour and draw dotted geometry
356
segment->getContour()->calculateContourExtrudedShape(s, d, this, E2Geometry.getShape(), getType(), s.detectorSettings.E2Width,
357
E2Exaggeration, segment->isFirstSegment(), segment->isLastSegment(), 0, segment, segment->getLane()->getParentEdge());
358
// check if create from-to contours
359
if (segment->getFromContour()) {
360
segment->getFromContour()->calculateContourCircleShape(s, d, this, E2Geometry.getShape().front(),
361
s.neteditSizeSettings.additionalGeometryPointRadius, getType(), E2Exaggeration, segment->getLane()->getParentEdge());
362
} else if (segment->getToContour()) {
363
segment->getToContour()->calculateContourCircleShape(s, d, this, E2Geometry.getShape().back(),
364
s.neteditSizeSettings.additionalGeometryPointRadius, getType(), E2Exaggeration, segment->getLane()->getParentEdge());
365
}
366
// check if add this path element to redraw buffer
367
if (!gViewObjectsHandler.isPathElementMarkForRedraw(this) && segment->getContour()->checkDrawPathContour(s, d, this)) {
368
gViewObjectsHandler.addToRedrawPathElements(this);
369
}
370
}
371
}
372
373
374
void
375
GNELaneAreaDetector::drawJunctionPartialGL(const GUIVisualizationSettings& s, const GNESegment* segment, const double offsetFront) const {
376
// check if E2 can be drawn
377
if ((myTagProperty->getTag() == GNE_TAG_MULTI_LANE_AREA_DETECTOR) && segment->getPreviousLane() && segment->getNextLane() &&
378
myNet->getViewNet()->getDataViewOptions().showAdditionals() && !myNet->getViewNet()->selectingDetectorsTLSMode()) {
379
// Obtain exaggeration of the draw
380
const double E2Exaggeration = getExaggeration(s);
381
// get detail level
382
const auto d = s.getDetailLevel(E2Exaggeration);
383
// get flag for show only contour
384
const bool onlyContour = myNet->getViewNet()->getEditModes().isCurrentSupermodeNetwork() ? myNet->getViewNet()->getNetworkViewOptions().showConnections() : false;
385
// check if connection to next lane exist
386
const bool connectionExist = segment->getPreviousLane()->getLane2laneConnections().exist(segment->getNextLane());
387
// get geometry
388
const GUIGeometry& E2Geometry = connectionExist ? segment->getPreviousLane()->getLane2laneConnections().getLane2laneGeometry(segment->getNextLane()) :
389
GUIGeometry({segment->getPreviousLane()->getLaneShape().back(), segment->getNextLane()->getLaneShape().front()});
390
// draw geometry only if we'rent in drawForObjectUnderCursor mode
391
if (s.checkDrawAdditional(d, isAttributeCarrierSelected())) {
392
// draw E2 partial
393
drawE2PartialJunction(s, d, onlyContour, offsetFront, E2Geometry, E2Exaggeration);
394
// draw dotted contour
395
if (!drawMovingGeometryPoints(false)) {
396
segment->getContour()->drawDottedContours(s, d, this, s.dottedContourSettings.segmentWidth, true);
397
}
398
}
399
// calculate contour
400
segment->getContour()->calculateContourExtrudedShape(s, d, this, E2Geometry.getShape(), getType(), s.detectorSettings.E2Width, E2Exaggeration,
401
false, false, 0, segment, segment->getJunction());
402
// check if add this path element to redraw buffer
403
if (!gViewObjectsHandler.isPathElementMarkForRedraw(this) && segment->getContour()->checkDrawPathContour(s, d, this)) {
404
gViewObjectsHandler.addToRedrawPathElements(this);
405
}
406
}
407
}
408
409
410
std::string
411
GNELaneAreaDetector::getAttribute(SumoXMLAttr key) const {
412
switch (key) {
413
case SUMO_ATTR_LANES:
414
return parseIDs(getParentLanes());
415
case SUMO_ATTR_STARTPOS:
416
return toString(myPositionOverLane);
417
case SUMO_ATTR_ENDPOS:
418
return toString(myEndPositionOverLane);
419
case SUMO_ATTR_TLID:
420
return myTrafficLight;
421
case SUMO_ATTR_LENGTH:
422
return toString(myEndPositionOverLane - myPositionOverLane);
423
case SUMO_ATTR_HALTING_TIME_THRESHOLD:
424
return time2string(myTimeThreshold);
425
case SUMO_ATTR_HALTING_SPEED_THRESHOLD:
426
return toString(mySpeedThreshold);
427
case SUMO_ATTR_JAM_DIST_THRESHOLD:
428
return toString(myJamThreshold);
429
case SUMO_ATTR_SHOW_DETECTOR:
430
return toString(myShow);
431
default:
432
return getDetectorAttribute(key);
433
}
434
}
435
436
437
double
438
GNELaneAreaDetector::getAttributeDouble(SumoXMLAttr key) const {
439
switch (key) {
440
case SUMO_ATTR_LENGTH:
441
return (myEndPositionOverLane - myPositionOverLane);
442
case SUMO_ATTR_ENDPOS:
443
return myEndPositionOverLane;
444
default:
445
return getDetectorAttributeDouble(key);
446
}
447
}
448
449
450
void
451
GNELaneAreaDetector::setAttribute(SumoXMLAttr key, const std::string& value, GNEUndoList* undoList) {
452
switch (key) {
453
case SUMO_ATTR_LANES:
454
case SUMO_ATTR_ENDPOS:
455
case SUMO_ATTR_TLID:
456
case SUMO_ATTR_LENGTH:
457
case SUMO_ATTR_HALTING_TIME_THRESHOLD:
458
case SUMO_ATTR_HALTING_SPEED_THRESHOLD:
459
case SUMO_ATTR_JAM_DIST_THRESHOLD:
460
case SUMO_ATTR_SHOW_DETECTOR:
461
GNEChange_Attribute::changeAttribute(this, key, value, undoList);
462
break;
463
default:
464
setDetectorAttribute(key, value, undoList);
465
break;
466
}
467
}
468
469
470
bool
471
GNELaneAreaDetector::isValid(SumoXMLAttr key, const std::string& value) {
472
switch (key) {
473
case SUMO_ATTR_LANES:
474
if (value.empty()) {
475
return false;
476
} else {
477
return canParse<std::vector<GNELane*> >(myNet, value, true);
478
}
479
case SUMO_ATTR_ENDPOS:
480
return canParse<double>(value);
481
case SUMO_ATTR_TLID:
482
// temporal
483
return SUMOXMLDefinitions::isValidNetID(value);
484
case SUMO_ATTR_LENGTH:
485
return (canParse<double>(value) && (parse<double>(value) >= 0));
486
case SUMO_ATTR_HALTING_TIME_THRESHOLD:
487
return canParse<SUMOTime>(value) && (parse<SUMOTime>(value) >= 0);
488
case SUMO_ATTR_HALTING_SPEED_THRESHOLD:
489
return (canParse<double>(value) && (parse<double>(value) >= 0));
490
case SUMO_ATTR_JAM_DIST_THRESHOLD:
491
return (canParse<double>(value) && (parse<double>(value) >= 0));
492
case SUMO_ATTR_SHOW_DETECTOR:
493
return canParse<bool>(value);
494
default:
495
return isDetectorValid(key, value);
496
}
497
}
498
499
// ===========================================================================
500
// private
501
// ===========================================================================
502
503
void
504
GNELaneAreaDetector::drawE2(const GUIVisualizationSettings& s, const GUIVisualizationSettings::Detail d,
505
const double exaggeration) const {
506
// declare color
507
RGBColor E2Color, textColor;
508
// set color
509
if (drawUsingSelectColor()) {
510
E2Color = s.colorSettings.selectedAdditionalColor;
511
textColor = E2Color.changedBrightness(-32);
512
} else if (areLaneConsecutives(getParentLanes())) {
513
E2Color = s.detectorSettings.E2Color;
514
textColor = RGBColor::BLACK;
515
}
516
// draw parent and child lines
517
drawParentChildLines(s, s.additionalSettings.connectionColor);
518
// push layer matrix
519
GLHelper::pushMatrix();
520
// translate to front
521
drawInLayer(GLO_E2DETECTOR);
522
// set color
523
GLHelper::setColor(E2Color);
524
// draw geometry
525
GUIGeometry::drawGeometry(d, myAdditionalGeometry, s.detectorSettings.E2Width * exaggeration);
526
// draw arrow
527
if (myAdditionalGeometry.getShape().size() > 1) {
528
glTranslated(0, 0, 0.1);
529
GLHelper::drawTriangleAtEnd(myAdditionalGeometry.getShape()[-2], myAdditionalGeometry.getShape()[-1], (double) 0.5, (double) 1, 0.5);
530
}
531
// draw E2 Logo
532
drawE2DetectorLogo(s, d, exaggeration, "E2", textColor);
533
// draw geometry points
534
drawLeftGeometryPoint(s, d, myAdditionalGeometry.getShape().front(), myAdditionalGeometry.getShapeRotations().front(), E2Color);
535
drawRightGeometryPoint(s, d, myAdditionalGeometry.getShape().back(), myAdditionalGeometry.getShapeRotations().back(), E2Color);
536
// pop layer matrix
537
GLHelper::popMatrix();
538
}
539
540
541
void
542
GNELaneAreaDetector::drawE2PartialLane(const GUIVisualizationSettings& s, const GUIVisualizationSettings::Detail d,
543
const GNESegment* segment, const double offsetFront,
544
const GUIGeometry& geometry, const double exaggeration, const bool movingGeometryPoints) const {
545
// obtain color
546
const RGBColor E2Color = drawUsingSelectColor() ? s.colorSettings.selectedAdditionalColor : s.detectorSettings.E2Color;
547
// push layer matrix
548
GLHelper::pushMatrix();
549
// Start with the drawing of the area traslating matrix to origin
550
glTranslated(0, 0, getType() + offsetFront);
551
// Set color
552
GLHelper::setColor(E2Color);
553
// draw geometry
554
GUIGeometry::drawGeometry(d, geometry, s.detectorSettings.E2Width * exaggeration);
555
// check if draw moving geometry points
556
if (movingGeometryPoints) {
557
if (segment->isFirstSegment() && segment->isLastSegment()) {
558
drawLeftGeometryPoint(s, d, geometry.getShape().front(), geometry.getShapeRotations().front(), E2Color, true);
559
drawRightGeometryPoint(s, d, geometry.getShape().back(), geometry.getShapeRotations().back(), E2Color, true);
560
} else if (segment->isFirstSegment()) {
561
drawLeftGeometryPoint(s, d, geometry.getShape().front(), geometry.getShapeRotations().front(), E2Color, true);
562
} else if (segment->isLastSegment()) {
563
drawRightGeometryPoint(s, d, geometry.getShape().back(), geometry.getShapeRotations().back(), E2Color, true);
564
// draw arrow
565
if (geometry.getShape().size() > 1) {
566
glTranslated(0, 0, 0.1);
567
GLHelper::drawTriangleAtEnd(geometry.getShape()[-2], geometry.getShape()[-1], (double) 0.5, (double) 1, 0.5);
568
}
569
}
570
}
571
// Pop layer matrix
572
GLHelper::popMatrix();
573
// check if this is the label segment
574
if (segment->isLabelSegment()) {
575
// calculate middle point
576
const double middlePoint = (geometry.getShape().length2D() * 0.5);
577
// calculate position
578
const Position pos = geometry.getShape().positionAtOffset2D(middlePoint);
579
// calculate rotation
580
const double rot = s.getTextAngle((geometry.getShape().rotationDegreeAtOffset(middlePoint) * -1) + 90);
581
// Start pushing matrix
582
GLHelper::pushMatrix();
583
// Traslate to position
584
glTranslated(pos.x(), pos.y(), getType() + offsetFront + 0.1);
585
// rotate
586
glRotated(rot, 0, 0, 1);
587
// move
588
glTranslated(-1, 0, 0);
589
// scale text
590
glScaled(exaggeration, exaggeration, 1);
591
// draw E1 logo
592
GLHelper::drawText("E2 Multilane", Position(), .1, 1.5, RGBColor::BLACK);
593
// pop matrix
594
GLHelper::popMatrix();
595
}
596
597
}
598
599
600
void
601
GNELaneAreaDetector::drawE2PartialJunction(const GUIVisualizationSettings& s, const GUIVisualizationSettings::Detail d,
602
const bool onlyContour, const double offsetFront, const GUIGeometry& geometry,
603
const double exaggeration) const {
604
const bool invalid = geometry.getShape().length() == 2;
605
const double width = s.detectorSettings.E2Width * exaggeration * (invalid ? 0.5 : 1);
606
// Add a draw matrix
607
GLHelper::pushMatrix();
608
// Start with the drawing of the area traslating matrix to origin
609
glTranslated(0, 0, getType() + offsetFront);
610
// Set color of the base
611
if (drawUsingSelectColor()) {
612
GLHelper::setColor(s.colorSettings.selectedAdditionalColor);
613
} else if (invalid) {
614
GLHelper::setColor(RGBColor::RED);
615
} else {
616
GLHelper::setColor(s.detectorSettings.E2Color);
617
}
618
// check if draw only contour
619
if (onlyContour) {
620
GUIGeometry::drawContourGeometry(geometry, width);
621
} else {
622
GUIGeometry::drawGeometry(d, geometry, width);
623
}
624
// Pop last matrix
625
GLHelper::popMatrix();
626
}
627
628
629
void
630
GNELaneAreaDetector::setAttribute(SumoXMLAttr key, const std::string& value) {
631
switch (key) {
632
case SUMO_ATTR_LANES:
633
replaceAdditionalParentLanes(value);
634
break;
635
case SUMO_ATTR_ENDPOS:
636
myEndPositionOverLane = parse<double>(value);
637
// update geometry (except for template)
638
if (getParentLanes().size() > 0) {
639
updateGeometry();
640
}
641
break;
642
case SUMO_ATTR_TLID:
643
myTrafficLight = value;
644
break;
645
case SUMO_ATTR_LENGTH:
646
myEndPositionOverLane = (myPositionOverLane + parse<double>(value));
647
// update geometry (except for template)
648
if (getParentLanes().size() > 0) {
649
updateGeometry();
650
}
651
break;
652
case SUMO_ATTR_HALTING_TIME_THRESHOLD:
653
myTimeThreshold = TIME2STEPS(parse<double>(value));
654
break;
655
case SUMO_ATTR_HALTING_SPEED_THRESHOLD:
656
mySpeedThreshold = parse<double>(value);
657
break;
658
case SUMO_ATTR_JAM_DIST_THRESHOLD:
659
myJamThreshold = parse<double>(value);
660
break;
661
case SUMO_ATTR_SHOW_DETECTOR:
662
myShow = parse<bool>(value);
663
break;
664
default:
665
setDetectorAttribute(key, value);
666
break;
667
}
668
}
669
670
671
void
672
GNELaneAreaDetector::setMoveShape(const GNEMoveResult& moveResult) {
673
if ((moveResult.operationType == GNEMoveOperation::OperationType::SINGLE_LANE_MOVE_FIRST) ||
674
(moveResult.operationType == GNEMoveOperation::OperationType::MULTIPLE_LANES_MOVE_FIRST)) {
675
// change only start position
676
myPositionOverLane = moveResult.newFirstPos;
677
} else if ((moveResult.operationType == GNEMoveOperation::OperationType::SINGLE_LANE_MOVE_LAST) ||
678
(moveResult.operationType == GNEMoveOperation::OperationType::MULTIPLE_LANES_MOVE_LAST)) {
679
// change only end position
680
myEndPositionOverLane = moveResult.newFirstPos;
681
} else {
682
if (moveResult.operationType == GNEMoveOperation::OperationType::MULTIPLE_LANES_MOVE_BOTH_FIRST) {
683
const auto difference = moveResult.newFirstPos - myPositionOverLane;
684
// change start position
685
myPositionOverLane = moveResult.newFirstPos;
686
myEndPositionOverLane += difference;
687
} else if (moveResult.operationType == GNEMoveOperation::OperationType::MULTIPLE_LANES_MOVE_BOTH_LAST) {
688
const auto difference = moveResult.newFirstPos - myEndPositionOverLane;
689
// change end position
690
myPositionOverLane += difference;
691
myEndPositionOverLane = moveResult.newFirstPos;
692
}
693
// end position over lane
694
if (myPositionOverLane < 0) {
695
myPositionOverLane = 0;
696
} else if (myPositionOverLane > getParentLanes().front()->getLaneShapeLength()) {
697
myPositionOverLane = getParentLanes().front()->getLaneShapeLength();
698
}
699
// adjust position over lane
700
if (myEndPositionOverLane < 0) {
701
myEndPositionOverLane = 0;
702
} else if (myEndPositionOverLane > getParentLanes().back()->getLaneShapeLength()) {
703
myEndPositionOverLane = getParentLanes().back()->getLaneShapeLength();
704
}
705
}
706
// update geometry
707
updateGeometry();
708
}
709
710
711
void
712
GNELaneAreaDetector::commitMoveShape(const GNEMoveResult& moveResult, GNEUndoList* undoList) {
713
// begin change attribute
714
undoList->begin(this, "position of " + getTagStr());
715
// set attributes depending of operation type
716
if ((moveResult.operationType == GNEMoveOperation::OperationType::SINGLE_LANE_MOVE_FIRST) ||
717
(moveResult.operationType == GNEMoveOperation::OperationType::MULTIPLE_LANES_MOVE_FIRST)) {
718
// set only start position
719
setAttribute(SUMO_ATTR_POSITION, toString(moveResult.newFirstPos), undoList);
720
} else if ((moveResult.operationType == GNEMoveOperation::OperationType::SINGLE_LANE_MOVE_LAST) ||
721
(moveResult.operationType == GNEMoveOperation::OperationType::MULTIPLE_LANES_MOVE_LAST)) {
722
// set only end position
723
setAttribute(SUMO_ATTR_ENDPOS, toString(moveResult.newFirstPos), undoList);
724
} else {
725
double startPos = myPositionOverLane;
726
double endPos = myEndPositionOverLane;
727
// set positions
728
if (moveResult.operationType == GNEMoveOperation::OperationType::MULTIPLE_LANES_MOVE_BOTH_FIRST) {
729
const auto difference = moveResult.newFirstPos - myPositionOverLane;
730
// change start position
731
startPos = moveResult.newFirstPos;
732
endPos += difference;
733
} else if (moveResult.operationType == GNEMoveOperation::OperationType::MULTIPLE_LANES_MOVE_BOTH_LAST) {
734
const auto difference = moveResult.newFirstPos - myEndPositionOverLane;
735
// change end position
736
startPos += difference;
737
endPos = moveResult.newFirstPos;
738
}
739
// end position over lane
740
if (startPos < 0) {
741
startPos = 0;
742
} else if (startPos > getParentLanes().front()->getLaneShapeLength()) {
743
startPos = getParentLanes().front()->getLaneShapeLength();
744
}
745
// adjust position over lane
746
if (endPos < 0) {
747
endPos = 0;
748
} else if (endPos > getParentLanes().back()->getLaneShapeLength()) {
749
endPos = getParentLanes().back()->getLaneShapeLength();
750
}
751
// set only end position
752
setAttribute(SUMO_ATTR_POSITION, toString(startPos), undoList);
753
setAttribute(SUMO_ATTR_ENDPOS, toString(endPos), undoList);
754
}
755
// end change attribute
756
undoList->end();
757
}
758
759
760
double
761
GNELaneAreaDetector::getStartGeometryPositionOverLane() const {
762
// get lane final and shape length
763
const double laneLength = getParentLanes().front()->getParentEdge()->getNBEdge()->getFinalLength();
764
// get startPosition
765
double fixedPos = myPositionOverLane;
766
// adjust fixedPos
767
if (fixedPos < 0) {
768
fixedPos += laneLength;
769
}
770
fixedPos *= getParentLanes().front()->getLengthGeometryFactor();
771
// return depending of fixedPos
772
if (fixedPos < 0) {
773
return 0;
774
} else if (fixedPos > (getParentLanes().front()->getLaneShapeLength() - POSITION_EPS)) {
775
return (getParentLanes().front()->getLaneShapeLength() - POSITION_EPS);
776
} else {
777
return fixedPos;
778
}
779
}
780
781
782
double
783
GNELaneAreaDetector::getEndGeometryPositionOverLane() const {
784
// get lane final and shape length
785
const double laneLength = getParentLanes().back()->getParentEdge()->getNBEdge()->getFinalLength();
786
// get endPosition
787
double fixedPos = myEndPositionOverLane;
788
// adjust fixedPos
789
if (fixedPos < 0) {
790
fixedPos += laneLength;
791
}
792
fixedPos *= getParentLanes().back()->getLengthGeometryFactor();
793
// return depending of fixedPos
794
if (fixedPos < POSITION_EPS) {
795
return POSITION_EPS;
796
} else if (fixedPos > getParentLanes().back()->getLaneShapeLength()) {
797
return getParentLanes().back()->getLaneShapeLength();
798
} else {
799
return fixedPos;
800
}
801
}
802
803
/****************************************************************************/
804
805