1 /****************************************************************************/
2 // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.org/sumo
3 // Copyright (C) 2001-2019 German Aerospace Center (DLR) and others.
4 // This program and the accompanying materials
5 // are made available under the terms of the Eclipse Public License v2.0
6 // which accompanies this distribution, and is available at
7 // http://www.eclipse.org/legal/epl-v20.html
8 // SPDX-License-Identifier: EPL-2.0
9 /****************************************************************************/
10 /// @file GNEDetectorE2.cpp
11 /// @author Pablo Alvarez Lopez
12 /// @date Nov 2015
13 /// @version $Id$
14 ///
15 //
16 /****************************************************************************/
17
18 // ===========================================================================
19 // included modules
20 // ===========================================================================
21
22 #include <netedit/GNENet.h>
23 #include <netedit/GNEUndoList.h>
24 #include <netedit/GNEViewNet.h>
25 #include <netedit/changes/GNEChange_Attribute.h>
26 #include <netedit/changes/GNEChange_Connection.h>
27 #include <netedit/netelements/GNEConnection.h>
28 #include <netedit/netelements/GNEEdge.h>
29 #include <netedit/netelements/GNELane.h>
30 #include <utils/gui/div/GLHelper.h>
31 #include <utils/gui/globjects/GLIncludes.h>
32
33 #include "GNEDetectorE2.h"
34 #include "GNEAdditionalHandler.h"
35
36
37 // ===========================================================================
38 // member method definitions
39 // ===========================================================================
40
GNEDetectorE2(const std::string & id,GNELane * lane,GNEViewNet * viewNet,double pos,double length,double freq,const std::string & filename,const std::string & vehicleTypes,const std::string & name,const double timeThreshold,double speedThreshold,double jamThreshold,bool friendlyPos,bool blockMovement)41 GNEDetectorE2::GNEDetectorE2(const std::string& id, GNELane* lane, GNEViewNet* viewNet, double pos, double length, double freq, const std::string& filename, const std::string& vehicleTypes,
42 const std::string& name, const double timeThreshold, double speedThreshold, double jamThreshold, bool friendlyPos, bool blockMovement) :
43 GNEDetector(id, viewNet, GLO_E2DETECTOR, SUMO_TAG_E2DETECTOR, pos, freq, filename, vehicleTypes, name, friendlyPos, blockMovement, {
44 lane
45 }),
46 myLength(length),
47 myEndPositionOverLane(0.),
48 myTimeThreshold(timeThreshold),
49 mySpeedThreshold(speedThreshold),
50 myJamThreshold(jamThreshold),
51 myE2valid(true) {
52 }
53
54
GNEDetectorE2(const std::string & id,std::vector<GNELane * > lanes,GNEViewNet * viewNet,double pos,double endPos,double freq,const std::string & filename,const std::string & vehicleTypes,const std::string & name,const double timeThreshold,double speedThreshold,double jamThreshold,bool friendlyPos,bool blockMovement)55 GNEDetectorE2::GNEDetectorE2(const std::string& id, std::vector<GNELane*> lanes, GNEViewNet* viewNet, double pos, double endPos, double freq, const std::string& filename, const std::string& vehicleTypes,
56 const std::string& name, const double timeThreshold, double speedThreshold, double jamThreshold, bool friendlyPos, bool blockMovement) :
57 GNEDetector(id, viewNet, GLO_E2DETECTOR, SUMO_TAG_E2DETECTOR_MULTILANE, pos, freq, filename, vehicleTypes, name, friendlyPos, blockMovement, lanes),
58 myEndPositionOverLane(endPos),
59 myTimeThreshold(timeThreshold),
60 mySpeedThreshold(speedThreshold),
61 myJamThreshold(jamThreshold),
62 myE2valid(true) {
63 }
64
65
~GNEDetectorE2()66 GNEDetectorE2::~GNEDetectorE2() {
67 }
68
69
70 bool
isAdditionalValid() const71 GNEDetectorE2::isAdditionalValid() const {
72 if (getLaneParents().size() == 1) {
73 // with friendly position enabled position are "always fixed"
74 if (myFriendlyPosition) {
75 return true;
76 } else {
77 return (myPositionOverLane >= 0) && ((myPositionOverLane + myLength) <= getLaneParents().front()->getParentEdge().getNBEdge()->getFinalLength());
78 }
79 } else {
80 // first check if there is connection between all consecutive lanes
81 if (myE2valid) {
82 // with friendly position enabled position are "always fixed"
83 if (myFriendlyPosition) {
84 return true;
85 } else {
86 return (myPositionOverLane >= 0) && ((myPositionOverLane) <= getLaneParents().back()->getParentEdge().getNBEdge()->getFinalLength() &&
87 myEndPositionOverLane >= 0) && ((myEndPositionOverLane) <= getLaneParents().back()->getParentEdge().getNBEdge()->getFinalLength());
88 }
89 } else {
90 return false;
91 }
92 }
93 }
94
95
96 std::string
getAdditionalProblem() const97 GNEDetectorE2::getAdditionalProblem() const {
98 // declare variable for error position
99 std::string errorFirstLanePosition, separator, errorLastLanePosition;
100 if (getLaneParents().size() == 1) {
101 // check positions over lane
102 if (myPositionOverLane < 0) {
103 errorFirstLanePosition = (toString(SUMO_ATTR_POSITION) + " < 0");
104 }
105 if (myPositionOverLane > getLaneParents().front()->getParentEdge().getNBEdge()->getFinalLength()) {
106 errorFirstLanePosition = (toString(SUMO_ATTR_POSITION) + " > lanes's length");
107 }
108 if ((myPositionOverLane + myLength) > getLaneParents().front()->getParentEdge().getNBEdge()->getFinalLength()) {
109 errorFirstLanePosition = (toString(SUMO_ATTR_POSITION) + " + " + toString(SUMO_ATTR_LENGTH) + " > lanes's length");
110 }
111 } else {
112 if (myE2valid) {
113 // check positions over first lane
114 if (myPositionOverLane < 0) {
115 errorFirstLanePosition = (toString(SUMO_ATTR_POSITION) + " < 0");
116 }
117 if (myPositionOverLane > getLaneParents().front()->getParentEdge().getNBEdge()->getFinalLength()) {
118 errorFirstLanePosition = (toString(SUMO_ATTR_POSITION) + " > lanes's length");
119 }
120 // check positions over last lane
121 if (myEndPositionOverLane < 0) {
122 errorLastLanePosition = (toString(SUMO_ATTR_ENDPOS) + " < 0");
123 }
124 if (myEndPositionOverLane > getLaneParents().back()->getParentEdge().getNBEdge()->getFinalLength()) {
125 errorLastLanePosition = (toString(SUMO_ATTR_ENDPOS) + " > lanes's length");
126 }
127 } else {
128 errorFirstLanePosition = "lanes aren't consecutives";
129 }
130 }
131 // check separator
132 if ((errorFirstLanePosition.size() > 0) && (errorLastLanePosition.size() > 0)) {
133 separator = " and ";
134 }
135 // return error message
136 return errorFirstLanePosition + separator + errorLastLanePosition;
137 }
138
139
140 void
fixAdditionalProblem()141 GNEDetectorE2::fixAdditionalProblem() {
142 if (getLaneParents().size() == 1) {
143 // obtain position and lenght
144 double newPositionOverLane = myPositionOverLane;
145 double newLength = myLength;
146 // fix pos and lenght using fixE2DetectorPosition
147 GNEAdditionalHandler::fixE2DetectorPosition(newPositionOverLane, newLength, getLaneParents().at(0)->getParentEdge().getNBEdge()->getFinalLength(), true);
148 // set new position and length
149 setAttribute(SUMO_ATTR_POSITION, toString(newPositionOverLane), myViewNet->getUndoList());
150 setAttribute(SUMO_ATTR_LENGTH, toString(myLength), myViewNet->getUndoList());
151 } else {
152 if (!myE2valid) {
153 // build connections between all consecutive lanes
154 bool foundConnection = true;
155 int i = 0;
156 // iterate over all lanes, and stop if myE2valid is false
157 while (i < ((int)getLaneParents().size() - 1)) {
158 // change foundConnection to false
159 foundConnection = false;
160 // if a connection betwen "from" lane and "to" lane of connection is found, change myE2valid to true again
161 for (auto j : getLaneParents().at(i)->getParentEdge().getGNEConnections()) {
162 if (j->getLaneFrom() == getLaneParents().at(i) && j->getLaneTo() == getLaneParents().at(i + 1)) {
163 foundConnection = true;
164 }
165 }
166 // if connection wasn't found
167 if (!foundConnection) {
168 // create new connection manually
169 NBEdge::Connection newCon(getLaneParents().at(i)->getIndex(), getLaneParents().at(i + 1)->getParentEdge().getNBEdge(), getLaneParents().at(i + 1)->getIndex());
170 // allow to undo creation of new lane
171 myViewNet->getUndoList()->add(new GNEChange_Connection(&getLaneParents().at(i)->getParentEdge(), newCon, false, true), true);
172 }
173 // update lane iterator
174 i++;
175 }
176 } else {
177 // declare new position
178 double newPositionOverLane = myPositionOverLane;
179 // fix pos and lenght checkAndFixDetectorPosition
180 GNEAdditionalHandler::checkAndFixDetectorPosition(newPositionOverLane, getLaneParents().front()->getParentEdge().getNBEdge()->getFinalLength(), true);
181 // set new position
182 setAttribute(SUMO_ATTR_POSITION, toString(newPositionOverLane), myViewNet->getUndoList());
183 // declare new end position
184 double newEndPositionOverLane = myEndPositionOverLane;
185 // fix pos and lenght checkAndFixDetectorPosition
186 GNEAdditionalHandler::checkAndFixDetectorPosition(newEndPositionOverLane, getLaneParents().back()->getParentEdge().getNBEdge()->getFinalLength(), true);
187 // set new position
188 setAttribute(SUMO_ATTR_ENDPOS, toString(newEndPositionOverLane), myViewNet->getUndoList());
189 }
190 }
191 }
192
193
194 void
moveGeometry(const Position & offset)195 GNEDetectorE2::moveGeometry(const Position& offset) {
196 // Calculate new position using old position
197 Position newPosition = myMove.originalViewPosition;
198 newPosition.add(offset);
199 // filtern position using snap to active grid
200 newPosition = myViewNet->snapToActiveGrid(newPosition);
201 double offsetLane = getLaneParents().front()->getShape().nearest_offset_to_point2D(newPosition, false) - getLaneParents().front()->getShape().nearest_offset_to_point2D(myMove.originalViewPosition, false);
202 // move geometry depending of number of lanes
203 if (getLaneParents().size() == 1) {
204 // calculate new position over lane
205 double newPositionOverLane = parse<double>(myMove.firstOriginalLanePosition) + offsetLane;
206 // obtain lane length
207 double laneLenght = getLaneParents().front()->getParentEdge().getNBEdge()->getFinalLength() * getLane()->getLengthGeometryFactor();
208 if (newPositionOverLane < 0) {
209 myPositionOverLane = 0;
210 } else if (newPositionOverLane + myLength > laneLenght) {
211 myPositionOverLane = laneLenght - myLength;
212 } else {
213 myPositionOverLane = newPositionOverLane;
214 }
215 } else {
216 // calculate new start and end positions
217 double newStartPosition = parse<double>(myMove.firstOriginalLanePosition) + offsetLane;
218 double newEndPosition = parse<double>(myMove.secondOriginalPosition) + offsetLane;
219 // change start and end position of E2 detector ONLY if both extremes aren't overpassed
220 if ((newStartPosition >= 0) && (newStartPosition <= getLaneParents().front()->getLaneShapeLength()) &&
221 (newEndPosition >= 0) && (newEndPosition <= getLaneParents().back()->getLaneShapeLength())) {
222 myPositionOverLane = newStartPosition;
223 myEndPositionOverLane = newEndPosition;
224 }
225 }
226 // Update geometry
227 updateGeometry(false);
228 }
229
230
231 void
commitGeometryMoving(GNEUndoList * undoList)232 GNEDetectorE2::commitGeometryMoving(GNEUndoList* undoList) {
233 // commit geometry moving depending of number of lanes
234 if (getLaneParents().size() == 1) {
235 // commit new position allowing undo/redo
236 undoList->p_begin("position of " + getTagStr());
237 undoList->p_add(new GNEChange_Attribute(this, myViewNet->getNet(), SUMO_ATTR_POSITION, toString(myPositionOverLane), true, myMove.firstOriginalLanePosition));
238 undoList->p_end();
239 } else {
240 undoList->p_begin("position of " + getTagStr());
241 undoList->p_add(new GNEChange_Attribute(this, myViewNet->getNet(), SUMO_ATTR_POSITION, toString(myPositionOverLane), true, myMove.firstOriginalLanePosition));
242 undoList->p_add(new GNEChange_Attribute(this, myViewNet->getNet(), SUMO_ATTR_ENDPOS, toString(myEndPositionOverLane), true, myMove.secondOriginalPosition));
243 undoList->p_end();
244 }
245 }
246
247
248 void
updateGeometry(bool updateGrid)249 GNEDetectorE2::updateGeometry(bool updateGrid) {
250 // first check if object has to be removed from grid (SUMOTree)
251 if (updateGrid) {
252 myViewNet->getNet()->removeGLObjectFromGrid(this);
253 }
254
255 // Clear all containers
256 myGeometry.clearGeometry();
257
258 // declare variables for start and end positions
259 double startPosFixed, endPosFixed;
260
261 // calculate start and end positions dependin of number of lanes
262 if (getLaneParents().size() == 1) {
263 // set shape lane as detector shape
264 myGeometry.shape = getLaneParents().front()->getShape();
265
266 // set start position
267 if (myPositionOverLane < 0) {
268 startPosFixed = 0;
269 } else if (myPositionOverLane > getLaneParents().back()->getParentEdge().getNBEdge()->getFinalLength()) {
270 startPosFixed = getLaneParents().back()->getParentEdge().getNBEdge()->getFinalLength();
271 } else {
272 startPosFixed = myPositionOverLane;
273 }
274
275 // set end position
276 if ((myPositionOverLane + myLength) < 0) {
277 endPosFixed = 0;
278 } else if ((myPositionOverLane + myLength) > getLaneParents().back()->getParentEdge().getNBEdge()->getFinalLength()) {
279 endPosFixed = getLaneParents().back()->getParentEdge().getNBEdge()->getFinalLength();
280 } else {
281 endPosFixed = (myPositionOverLane + myLength);
282 }
283
284 // Cut shape using as delimitators fixed start position and fixed end position
285 myGeometry.shape = myGeometry.shape.getSubpart(startPosFixed * getLaneParents().front()->getLengthGeometryFactor(), endPosFixed * getLaneParents().back()->getLengthGeometryFactor());
286
287 // Get calculate lenghts and rotations
288 myGeometry.calculateShapeRotationsAndLengths();
289
290 // Set block icon position
291 myBlockIcon.position = myGeometry.shape.getLineCenter();
292
293 } else if (getLaneParents().size() > 1) {
294 // start with the first lane shape
295 myGeometry.multiShape.push_back(getLaneParents().front()->getShape());
296
297 // set start position
298 if (myPositionOverLane < 0) {
299 startPosFixed = 0;
300 } else if (myPositionOverLane > getLaneParents().front()->getParentEdge().getNBEdge()->getFinalLength()) {
301 startPosFixed = getLaneParents().front()->getParentEdge().getNBEdge()->getFinalLength();
302 } else {
303 startPosFixed = myPositionOverLane;
304 }
305 // Cut shape using as delimitators fixed start position and fixed end position
306 myGeometry.multiShape[0] = myGeometry.multiShape[0].getSubpart(startPosFixed * getLaneParents().front()->getLengthGeometryFactor(), getLaneParents().front()->getParentEdge().getNBEdge()->getFinalLength());
307
308 // declare last shape
309 PositionVector lastShape = getLaneParents().back()->getShape();
310
311 // set end position
312 if (myEndPositionOverLane < 0) {
313 endPosFixed = 0;
314 } else if (myEndPositionOverLane > getLaneParents().back()->getParentEdge().getNBEdge()->getFinalLength()) {
315 endPosFixed = getLaneParents().back()->getParentEdge().getNBEdge()->getFinalLength();
316 } else {
317 endPosFixed = myEndPositionOverLane;
318 }
319
320 // Cut shape using as delimitators fixed start position and fixed end position
321 lastShape = lastShape.getSubpart(0, endPosFixed * getLaneParents().back()->getLengthGeometryFactor());
322
323 // add first shape connection (if exist, in other case leave it empty)
324 myGeometry.multiShape.push_back(PositionVector{getLaneParents().at(0)->getShape().back(), getLaneParents().at(1)->getShape().front()});
325 for (auto j : getLaneParents().at(0)->getParentEdge().getGNEConnections()) {
326 if (j->getLaneTo() == getLaneParents().at(1)) {
327 myGeometry.multiShape.back() = j->getShape();
328 }
329 }
330
331 // append shapes of intermediate lanes AND connections (if exist)
332 for (int i = 1; i < ((int)getLaneParents().size() - 1); i++) {
333 // add lane shape
334 myGeometry.multiShape.push_back(getLaneParents().at(i)->getShape());
335 // add empty shape for connection
336 myGeometry.multiShape.push_back(PositionVector{getLaneParents().at(i)->getShape().back(), getLaneParents().at(i + 1)->getShape().front()});
337 // set connection shape (if exist). In other case, insert an empty shape
338 for (auto j : getLaneParents().at(i)->getParentEdge().getGNEConnections()) {
339 if (j->getLaneTo() == getLaneParents().at(i + 1)) {
340 myGeometry.multiShape.back() = j->getShape();
341 }
342 }
343 }
344
345 // append last shape
346 myGeometry.multiShape.push_back(lastShape);
347
348 // calculate multi shape rotation and lengths
349 myGeometry.calculateMultiShapeRotationsAndLengths();
350
351 // calculate unified shape
352 myGeometry.calculateMultiShapeUnified();
353
354 // Set block icon position
355 myBlockIcon.position = myGeometry.multiShape.front().getLineCenter();
356
357 // check integrity
358 checkE2MultilaneIntegrity();
359 }
360
361 // Set offset of the block icon
362 myBlockIcon.offset = Position(-0.75, 0);
363
364 // Set block icon rotation, and using their rotation for draw logo
365 myBlockIcon.setRotation(getLaneParents().front());
366
367 // last step is to check if object has to be added into grid (SUMOTree) again
368 if (updateGrid) {
369 myViewNet->getNet()->addGLObjectIntoGrid(this);
370 }
371 }
372
373
374 double
getLength() const375 GNEDetectorE2::getLength() const {
376 return myLength;
377 }
378
379
380 void
checkE2MultilaneIntegrity()381 GNEDetectorE2::checkE2MultilaneIntegrity() {
382 // we assume that E2 is valid
383 myE2valid = true;
384 int i = 0;
385 // iterate over all lanes, and stop if myE2valid is false
386 while (i < ((int)getLaneParents().size() - 1) && myE2valid) {
387 // set myE2valid to false
388 myE2valid = false;
389 // if a connection betwen "from" lane and "to" lane of connection is found, change myE2valid to true again
390 for (auto j : getLaneParents().at(i)->getParentEdge().getGNEConnections()) {
391 if (j->getLaneFrom() == getLaneParents().at(i) && j->getLaneTo() == getLaneParents().at(i + 1)) {
392 myE2valid = true;
393 }
394 }
395 // update iterator
396 i++;
397 }
398 }
399
400
401 void
drawGL(const GUIVisualizationSettings & s) const402 GNEDetectorE2::drawGL(const GUIVisualizationSettings& s) const {
403 // Start drawing adding an gl identificator
404 glPushName(getGlID());
405
406 // Add a draw matrix
407 glPushMatrix();
408
409 // Start with the drawing of the area traslating matrix to origin
410 glTranslated(0, 0, getType());
411
412 // Set color of the base
413 if (drawUsingSelectColor()) {
414 GLHelper::setColor(s.selectedAdditionalColor);
415 } else {
416 // set color depending if is or isn't valid
417 if (myE2valid) {
418 GLHelper::setColor(s.SUMO_color_E2);
419 } else {
420 GLHelper::setColor(RGBColor::RED);
421 }
422 }
423
424 // Obtain exaggeration of the draw
425 const double exaggeration = s.addSize.getExaggeration(s, this);
426
427 // check if we have to drawn a E2 single lane or a E2 multiLane
428 if (myGeometry.shape.size() > 0) {
429 // Draw the area using shape, shapeRotations, shapeLengths and value of exaggeration
430 GLHelper::drawBoxLines(myGeometry.shape, myGeometry.shapeRotations, myGeometry.shapeLengths, exaggeration);
431 } else {
432 // iterate over multishapes
433 for (int i = 0; i < (int)myGeometry.multiShape.size(); i++) {
434 // don't draw shapes over connections if "show connections" is enabled
435 if (!myViewNet->getViewOptions().showConnections() || (i % 2 == 0)) {
436 GLHelper::drawBoxLines(myGeometry.multiShape.at(i), myGeometry.multiShapeRotations.at(i), myGeometry.multiShapeLengths.at(i), exaggeration);
437 }
438 }
439 }
440
441 // Pop last matrix
442 glPopMatrix();
443
444 // Check if the distance is enougth to draw details and isn't being drawn for selecting
445 if ((s.scale * exaggeration >= 10) && !s.drawForSelecting) {
446 // draw logo depending if this is an Multilane E2 detector
447 if (myTagProperty.getTag() == SUMO_TAG_E2DETECTOR) {
448 // Push matrix
449 glPushMatrix();
450 // Traslate to center of detector
451 glTranslated(myGeometry.shape.getLineCenter().x(), myGeometry.shape.getLineCenter().y(), getType() + 0.1);
452 // Rotate depending of myBlockIcon.rotation
453 glRotated(myBlockIcon.rotation, 0, 0, -1);
454 //move to logo position
455 glTranslated(-0.75, 0, 0);
456 // draw E2 logo
457 if (drawUsingSelectColor()) {
458 GLHelper::drawText("E2", Position(), .1, 1.5, s.selectionColor);
459 } else {
460 GLHelper::drawText("E2", Position(), .1, 1.5, RGBColor::BLACK);
461 }
462 } else {
463 // Push matrix
464 glPushMatrix();
465 // Traslate to center of detector
466 glTranslated(myBlockIcon.position.x(), myBlockIcon.position.y(), getType() + 0.1);
467 // Rotate depending of myBlockIcon.rotation
468 glRotated(myBlockIcon.rotation, 0, 0, -1);
469 //move to logo position
470 glTranslated(-1.5, 0, 0);
471 // draw E2 logo
472 if (drawUsingSelectColor()) {
473 GLHelper::drawText("E2", Position(), .1, 1.5, s.selectionColor);
474 } else {
475 GLHelper::drawText("E2", Position(), .1, 1.5, RGBColor::BLACK);
476 }
477 //move to logo position
478 glTranslated(1.2, 0, 0);
479 // Rotate depending of myBlockIcon.rotation
480 glRotated(90, 0, 0, 1);
481 if (drawUsingSelectColor()) {
482 GLHelper::drawText("multi", Position(), .1, 0.9, s.selectedAdditionalColor);
483 } else {
484 GLHelper::drawText("multi", Position(), .1, 0.9, RGBColor::BLACK);
485 }
486 }
487 // pop matrix
488 glPopMatrix();
489
490 // Show Lock icon depending of the Edit mode
491 myBlockIcon.draw();
492 }
493
494 // Draw name if isn't being drawn for selecting
495 if (!s.drawForSelecting) {
496 drawName(getCenteringBoundary().getCenter(), s.scale, s.addName);
497 }
498 // check if dotted contour has to be drawn
499 if (!s.drawForSelecting && (myViewNet->getDottedAC() == this)) {
500 if (myGeometry.shape.size() > 0) {
501 GLHelper::drawShapeDottedContour(getType(), myGeometry.shape, exaggeration);
502 } else {
503 GLHelper::drawShapeDottedContour(getType(), myGeometry.multiShapeUnified, exaggeration);
504 }
505 }
506 // Pop name
507 glPopName();
508 }
509
510
511 std::string
getAttribute(SumoXMLAttr key) const512 GNEDetectorE2::getAttribute(SumoXMLAttr key) const {
513 switch (key) {
514 case SUMO_ATTR_ID:
515 return getAdditionalID();
516 case SUMO_ATTR_LANE:
517 case SUMO_ATTR_LANES:
518 return parseIDs(getLaneParents());
519 case SUMO_ATTR_POSITION:
520 return toString(myPositionOverLane);
521 case SUMO_ATTR_ENDPOS:
522 return toString(myEndPositionOverLane);
523 case SUMO_ATTR_FREQUENCY:
524 return toString(myFreq);
525 case SUMO_ATTR_LENGTH:
526 return toString(myLength);
527 case SUMO_ATTR_NAME:
528 return myAdditionalName;
529 case SUMO_ATTR_FILE:
530 return myFilename;
531 case SUMO_ATTR_VTYPES:
532 return myVehicleTypes;
533 case SUMO_ATTR_HALTING_TIME_THRESHOLD:
534 return toString(myTimeThreshold);
535 case SUMO_ATTR_HALTING_SPEED_THRESHOLD:
536 return toString(mySpeedThreshold);
537 case SUMO_ATTR_JAM_DIST_THRESHOLD:
538 return toString(myJamThreshold);
539 case SUMO_ATTR_FRIENDLY_POS:
540 return toString(myFriendlyPosition);
541 case GNE_ATTR_BLOCK_MOVEMENT:
542 return toString(myBlockMovement);
543 case GNE_ATTR_SELECTED:
544 return toString(isAttributeCarrierSelected());
545 case GNE_ATTR_GENERIC:
546 return getGenericParametersStr();
547 default:
548 throw InvalidArgument(getTagStr() + " doesn't have an attribute of type '" + toString(key) + "'");
549 }
550 }
551
552
553 void
setAttribute(SumoXMLAttr key,const std::string & value,GNEUndoList * undoList)554 GNEDetectorE2::setAttribute(SumoXMLAttr key, const std::string& value, GNEUndoList* undoList) {
555 if (value == getAttribute(key)) {
556 return; //avoid needless changes, later logic relies on the fact that attributes have changed
557 }
558 switch (key) {
559 case SUMO_ATTR_ID:
560 case SUMO_ATTR_LANE:
561 case SUMO_ATTR_LANES:
562 case SUMO_ATTR_POSITION:
563 case SUMO_ATTR_ENDPOS:
564 case SUMO_ATTR_FREQUENCY:
565 case SUMO_ATTR_LENGTH:
566 case SUMO_ATTR_NAME:
567 case SUMO_ATTR_FILE:
568 case SUMO_ATTR_VTYPES:
569 case SUMO_ATTR_HALTING_TIME_THRESHOLD:
570 case SUMO_ATTR_HALTING_SPEED_THRESHOLD:
571 case SUMO_ATTR_JAM_DIST_THRESHOLD:
572 case SUMO_ATTR_FRIENDLY_POS:
573 case GNE_ATTR_BLOCK_MOVEMENT:
574 case GNE_ATTR_SELECTED:
575 case GNE_ATTR_GENERIC:
576 undoList->p_add(new GNEChange_Attribute(this, myViewNet->getNet(), key, value));
577 break;
578 default:
579 throw InvalidArgument(getTagStr() + " doesn't have an attribute of type '" + toString(key) + "'");
580 }
581 }
582
583
584 bool
isValid(SumoXMLAttr key,const std::string & value)585 GNEDetectorE2::isValid(SumoXMLAttr key, const std::string& value) {
586 switch (key) {
587 case SUMO_ATTR_ID:
588 return isValidDetectorID(value);
589 case SUMO_ATTR_LANE:
590 if (value.empty()) {
591 return false;
592 } else {
593 return canParse<std::vector<GNELane*> >(myViewNet->getNet(), value, false);
594 }
595 case SUMO_ATTR_LANES:
596 if (value.empty()) {
597 return false;
598 } else if (canParse<std::vector<GNELane*> >(myViewNet->getNet(), value, false)) {
599 // check if lanes are consecutives
600 return lanesConsecutives(parse<std::vector<GNELane*> >(myViewNet->getNet(), value));
601 } else {
602 return false;
603 }
604 case SUMO_ATTR_POSITION:
605 return canParse<double>(value);
606 case SUMO_ATTR_ENDPOS:
607 return canParse<double>(value);
608 case SUMO_ATTR_FREQUENCY:
609 return (canParse<double>(value) && (parse<double>(value) >= 0));
610 case SUMO_ATTR_LENGTH:
611 return (canParse<double>(value) && (parse<double>(value) >= 0));
612 case SUMO_ATTR_NAME:
613 return SUMOXMLDefinitions::isValidAttribute(value);
614 case SUMO_ATTR_FILE:
615 return SUMOXMLDefinitions::isValidFilename(value);
616 case SUMO_ATTR_VTYPES:
617 if (value.empty()) {
618 return true;
619 } else {
620 return SUMOXMLDefinitions::isValidListOfTypeID(value);
621 }
622 case SUMO_ATTR_HALTING_TIME_THRESHOLD:
623 return (canParse<double>(value) && (parse<double>(value) >= 0));
624 case SUMO_ATTR_HALTING_SPEED_THRESHOLD:
625 return (canParse<double>(value) && (parse<double>(value) >= 0));
626 case SUMO_ATTR_JAM_DIST_THRESHOLD:
627 return (canParse<double>(value) && (parse<double>(value) >= 0));
628 case SUMO_ATTR_FRIENDLY_POS:
629 return canParse<bool>(value);
630 case GNE_ATTR_BLOCK_MOVEMENT:
631 return canParse<bool>(value);
632 case GNE_ATTR_SELECTED:
633 return canParse<bool>(value);
634 case GNE_ATTR_GENERIC:
635 return isGenericParametersValid(value);
636 default:
637 throw InvalidArgument(getTagStr() + " doesn't have an attribute of type '" + toString(key) + "'");
638 }
639 }
640
641 // ===========================================================================
642 // private
643 // ===========================================================================
644
645 void
setAttribute(SumoXMLAttr key,const std::string & value)646 GNEDetectorE2::setAttribute(SumoXMLAttr key, const std::string& value) {
647 switch (key) {
648 case SUMO_ATTR_ID:
649 changeAdditionalID(value);
650 break;
651 case SUMO_ATTR_LANE:
652 case SUMO_ATTR_LANES:
653 changeLaneParents(this, value);
654 checkE2MultilaneIntegrity();
655 break;
656 case SUMO_ATTR_POSITION:
657 myPositionOverLane = parse<double>(value);
658 break;
659 case SUMO_ATTR_ENDPOS:
660 myEndPositionOverLane = parse<double>(value);
661 break;
662 case SUMO_ATTR_FREQUENCY:
663 myFreq = parse<double>(value);
664 break;
665 case SUMO_ATTR_LENGTH:
666 myLength = parse<double>(value);
667 break;
668 case SUMO_ATTR_NAME:
669 myAdditionalName = value;
670 break;
671 case SUMO_ATTR_FILE:
672 myFilename = value;
673 break;
674 case SUMO_ATTR_VTYPES:
675 myVehicleTypes = value;
676 break;
677 case SUMO_ATTR_HALTING_TIME_THRESHOLD:
678 myTimeThreshold = parse<double>(value);
679 break;
680 case SUMO_ATTR_HALTING_SPEED_THRESHOLD:
681 mySpeedThreshold = parse<double>(value);
682 break;
683 case SUMO_ATTR_JAM_DIST_THRESHOLD:
684 myJamThreshold = parse<double>(value);
685 break;
686 case SUMO_ATTR_FRIENDLY_POS:
687 myFriendlyPosition = parse<bool>(value);
688 break;
689 case GNE_ATTR_BLOCK_MOVEMENT:
690 myBlockMovement = parse<bool>(value);
691 break;
692 case GNE_ATTR_SELECTED:
693 if (parse<bool>(value)) {
694 selectAttributeCarrier();
695 } else {
696 unselectAttributeCarrier();
697 }
698 break;
699 case GNE_ATTR_GENERIC:
700 setGenericParametersStr(value);
701 break;
702 default:
703 throw InvalidArgument(getTagStr() + " doesn't have an attribute of type '" + toString(key) + "'");
704 }
705 // check if updated attribute requieres update geometry
706 if (myTagProperty.hasAttribute(key) && myTagProperty.getAttributeProperties(key).requiereUpdateGeometry()) {
707 updateGeometry(true);
708 }
709 }
710
711 /****************************************************************************/
712