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 GNEDetectorEntryExit.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/netelements/GNEEdge.h>
27 #include <netedit/netelements/GNELane.h>
28 #include <utils/gui/div/GLHelper.h>
29 #include <utils/gui/globjects/GLIncludes.h>
30
31 #include "GNEDetectorEntryExit.h"
32 #include "GNEAdditionalHandler.h"
33
34
35 // ===========================================================================
36 // member method definitions
37 // ===========================================================================
38
GNEDetectorEntryExit(SumoXMLTag entryExitTag,GNEViewNet * viewNet,GNEAdditional * parent,GNELane * lane,double pos,bool friendlyPos,bool blockMovement)39 GNEDetectorEntryExit::GNEDetectorEntryExit(SumoXMLTag entryExitTag, GNEViewNet* viewNet, GNEAdditional* parent, GNELane* lane, double pos, bool friendlyPos, bool blockMovement) :
40 GNEDetector(parent, viewNet, GLO_DET_ENTRY, entryExitTag, pos, 0, "", "", friendlyPos, blockMovement, {
41 lane
42 }) {
43 //check that this is a TAZ Source OR a TAZ Sink
44 if ((entryExitTag != SUMO_TAG_DET_ENTRY) && (entryExitTag != SUMO_TAG_DET_EXIT)) {
45 throw InvalidArgument("Invalid E3 Child Tag");
46 }
47 }
48
49
~GNEDetectorEntryExit()50 GNEDetectorEntryExit::~GNEDetectorEntryExit() {}
51
52
53 bool
isAdditionalValid() const54 GNEDetectorEntryExit::isAdditionalValid() const {
55 // with friendly position enabled position are "always fixed"
56 if (myFriendlyPosition) {
57 return true;
58 } else {
59 return fabs(myPositionOverLane) <= getLaneParents().front()->getParentEdge().getNBEdge()->getFinalLength();
60 }
61 }
62
63
64 std::string
getAdditionalProblem() const65 GNEDetectorEntryExit::getAdditionalProblem() const {
66 // declare variable for error position
67 std::string errorPosition;
68 const double len = getLaneParents().front()->getParentEdge().getNBEdge()->getFinalLength();
69 // check positions over lane
70 if (myPositionOverLane < -len) {
71 errorPosition = (toString(SUMO_ATTR_POSITION) + " < 0");
72 }
73 if (myPositionOverLane > len) {
74 errorPosition = (toString(SUMO_ATTR_POSITION) + " > lanes's length");
75 }
76 return errorPosition;
77 }
78
79
80 void
fixAdditionalProblem()81 GNEDetectorEntryExit::fixAdditionalProblem() {
82 // declare new position
83 double newPositionOverLane = myPositionOverLane;
84 // fix pos and lenght checkAndFixDetectorPosition
85 GNEAdditionalHandler::checkAndFixDetectorPosition(newPositionOverLane, getLaneParents().front()->getParentEdge().getNBEdge()->getFinalLength(), true);
86 // set new position
87 setAttribute(SUMO_ATTR_POSITION, toString(newPositionOverLane), myViewNet->getUndoList());
88 }
89
90
91 void
moveGeometry(const Position & offset)92 GNEDetectorEntryExit::moveGeometry(const Position& offset) {
93 // Calculate new position using old position
94 Position newPosition = myMove.originalViewPosition;
95 newPosition.add(offset);
96 // filtern position using snap to active grid
97 newPosition = myViewNet->snapToActiveGrid(newPosition);
98 const bool storeNegative = myPositionOverLane < 0;
99 myPositionOverLane = getLaneParents().front()->getShape().nearest_offset_to_point2D(newPosition, false);
100 if (storeNegative) {
101 myPositionOverLane -= getLaneParents().front()->getParentEdge().getNBEdge()->getFinalLength();
102 }
103 // Update geometry
104 updateGeometry(false);
105 }
106
107
108 void
commitGeometryMoving(GNEUndoList * undoList)109 GNEDetectorEntryExit::commitGeometryMoving(GNEUndoList* undoList) {
110 // commit new position allowing undo/redo
111 undoList->p_begin("position of " + getTagStr());
112 undoList->p_add(new GNEChange_Attribute(this, myViewNet->getNet(), SUMO_ATTR_POSITION, toString(myPositionOverLane), true, myMove.firstOriginalLanePosition));
113 undoList->p_end();
114 }
115
116
117 void
updateGeometry(bool updateGrid)118 GNEDetectorEntryExit::updateGeometry(bool updateGrid) {
119 // first check if object has to be removed from grid (SUMOTree)
120 if (updateGrid) {
121 myViewNet->getNet()->removeGLObjectFromGrid(this);
122 }
123
124 // Clear all containers
125 myGeometry.clearGeometry();
126
127 // obtain position over lane
128 myGeometry.shape.push_back(getPositionInView());
129
130 // Obtain first position
131 Position f = myGeometry.shape[0] - Position(1, 0);
132
133 // Obtain next position
134 Position s = myGeometry.shape[0] + Position(1, 0);
135
136 // Save rotation (angle) of the vector constructed by points f and s
137 myGeometry.shapeRotations.push_back(getLaneParents().front()->getShape().rotationDegreeAtOffset(getGeometryPositionOverLane()) * -1);
138
139 // Set block icon position
140 myBlockIcon.position = myGeometry.shape.getLineCenter();
141
142 // Set offset of the block icon
143 myBlockIcon.offset = Position(-1, 0);
144
145 // Set block icon rotation, and using their rotation for logo
146 myBlockIcon.setRotation(getLaneParents().front());
147
148 // last step is to check if object has to be added into grid (SUMOTree) again
149 if (updateGrid) {
150 myViewNet->getNet()->addGLObjectIntoGrid(this);
151 }
152
153 // update E3 parent Geometry
154 getAdditionalParents().at(0)->updateGeometry(updateGrid);
155 }
156
157
158 void
drawGL(const GUIVisualizationSettings & s) const159 GNEDetectorEntryExit::drawGL(const GUIVisualizationSettings& s) const {
160 // Start drawing adding gl identificator
161 glPushName(getGlID());
162
163 // Push detector matrix
164 glPushMatrix();
165 glTranslated(0, 0, getType());
166
167 // Set color
168 if (drawUsingSelectColor()) {
169 GLHelper::setColor(s.selectedAdditionalColor);
170 } else if (myTagProperty.getTag() == SUMO_TAG_DET_ENTRY) {
171 GLHelper::setColor(s.SUMO_color_E3Entry);
172 } else if (myTagProperty.getTag() == SUMO_TAG_DET_EXIT) {
173 GLHelper::setColor(s.SUMO_color_E3Exit);
174 }
175
176 // Set initial values
177 const double exaggeration = s.addSize.getExaggeration(s, this);
178 glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
179
180 // Push polygon matrix
181 glPushMatrix();
182 glScaled(exaggeration, exaggeration, 1);
183 glTranslated(myGeometry.shape[0].x(), myGeometry.shape[0].y(), 0);
184 glRotated(myGeometry.shapeRotations[0], 0, 0, 1);
185
186 // draw details if isn't being drawn for selecting
187 if (!s.drawForSelecting) {
188 // Draw polygon
189 glBegin(GL_LINES);
190 glVertex2d(1.7, 0);
191 glVertex2d(-1.7, 0);
192 glEnd();
193 glBegin(GL_QUADS);
194 glVertex2d(-1.7, .5);
195 glVertex2d(-1.7, -.5);
196 glVertex2d(1.7, -.5);
197 glVertex2d(1.7, .5);
198 glEnd();
199
200 // first Arrow
201 glTranslated(1.5, 0, 0);
202 GLHelper::drawBoxLine(Position(0, 4), 0, 2, .05);
203 GLHelper::drawTriangleAtEnd(Position(0, 4), Position(0, 1), (double) 1, (double) .25);
204
205 // second Arrow
206 glTranslated(-3, 0, 0);
207 GLHelper::drawBoxLine(Position(0, 4), 0, 2, .05);
208 GLHelper::drawTriangleAtEnd(Position(0, 4), Position(0, 1), (double) 1, (double) .25);
209 } else {
210 // Draw square in drawy for selecting mode
211 glBegin(GL_QUADS);
212 glVertex2d(-1.7, 4.3);
213 glVertex2d(-1.7, -.5);
214 glVertex2d(1.7, -.5);
215 glVertex2d(1.7, 4.3);
216 glEnd();
217 }
218
219 // Pop polygon matrix
220 glPopMatrix();
221
222 // Pop detector matrix
223 glPopMatrix();
224
225 // Check if the distance is enought to draw details
226 if (!s.drawForSelecting && ((s.scale * exaggeration) >= 10)) {
227 // Push matrix
228 glPushMatrix();
229 // Traslate to center of detector
230 glTranslated(myGeometry.shape.getLineCenter().x(), myGeometry.shape.getLineCenter().y(), getType() + 0.1);
231 // Rotate depending of myBlockIcon.rotation
232 glRotated(myBlockIcon.rotation, 0, 0, -1);
233 //move to logo position
234 glTranslated(1.9, 0, 0);
235 // draw Entry or Exit logo if isn't being drawn for selecting
236 if (s.drawForSelecting) {
237 GLHelper::setColor(s.SUMO_color_E3Entry);
238 GLHelper::drawBoxLine(Position(0, 1), 0, 2, 1);
239 } else if (drawUsingSelectColor()) {
240 GLHelper::drawText("E3", Position(), .1, 2.8, s.selectedAdditionalColor);
241 } else if (myTagProperty.getTag() == SUMO_TAG_DET_ENTRY) {
242 GLHelper::drawText("E3", Position(), .1, 2.8, s.SUMO_color_E3Entry);
243 } else if (myTagProperty.getTag() == SUMO_TAG_DET_EXIT) {
244 GLHelper::drawText("E3", Position(), .1, 2.8, s.SUMO_color_E3Exit);
245 }
246 //move to logo position
247 glTranslated(1.7, 0, 0);
248 // Rotate depending of myBlockIcon.rotation
249 glRotated(90, 0, 0, 1);
250 // draw Entry or Exit text if isn't being drawn for selecting
251 if (s.drawForSelecting) {
252 GLHelper::setColor(s.SUMO_color_E3Entry);
253 GLHelper::drawBoxLine(Position(0, 1), 0, 2, 1);
254 } else if (drawUsingSelectColor()) {
255 if (myTagProperty.getTag() == SUMO_TAG_DET_ENTRY) {
256 GLHelper::drawText("Entry", Position(), .1, 1, s.selectedAdditionalColor);
257 } else if (myTagProperty.getTag() == SUMO_TAG_DET_EXIT) {
258 GLHelper::drawText("Exit", Position(), .1, 1, s.selectedAdditionalColor);
259 }
260 } else {
261 if (myTagProperty.getTag() == SUMO_TAG_DET_ENTRY) {
262 GLHelper::drawText("Entry", Position(), .1, 1, s.SUMO_color_E3Entry);
263 } else if (myTagProperty.getTag() == SUMO_TAG_DET_EXIT) {
264 GLHelper::drawText("Exit", Position(), .1, 1, s.SUMO_color_E3Exit);
265 }
266 }
267 // pop matrix
268 glPopMatrix();
269 // Show Lock icon depending of the Edit mode and if isn't being drawn for selecting
270 if (!s.drawForSelecting) {
271 myBlockIcon.draw(0.4);
272 }
273 }
274 // Draw name if isn't being drawn for selecting
275 if (!s.drawForSelecting) {
276 drawName(getCenteringBoundary().getCenter(), s.scale, s.addName);
277 }
278 // check if dotted contour has to be drawn
279 if (!s.drawForSelecting && (myViewNet->getDottedAC() == this)) {
280 GLHelper::drawShapeDottedContour(getType(), myGeometry.shape[0], 3.4, 5, myGeometry.shapeRotations[0], 0, 2);
281 }
282 // pop gl identificator
283 glPopName();
284 }
285
286
287 std::string
getAttribute(SumoXMLAttr key) const288 GNEDetectorEntryExit::getAttribute(SumoXMLAttr key) const {
289 switch (key) {
290 case SUMO_ATTR_ID:
291 return getAdditionalID();
292 case SUMO_ATTR_LANE:
293 return getLaneParents().front()->getID();
294 case SUMO_ATTR_POSITION:
295 return toString(myPositionOverLane);
296 case SUMO_ATTR_FRIENDLY_POS:
297 return toString(myFriendlyPosition);
298 case GNE_ATTR_BLOCK_MOVEMENT:
299 return toString(myBlockMovement);
300 case GNE_ATTR_PARENT:
301 return getAdditionalParents().at(0)->getID();
302 case GNE_ATTR_SELECTED:
303 return toString(isAttributeCarrierSelected());
304 case GNE_ATTR_GENERIC:
305 return getGenericParametersStr();
306 default:
307 throw InvalidArgument(getTagStr() + " doesn't have an attribute of type '" + toString(key) + "'");
308 }
309 }
310
311
312 void
setAttribute(SumoXMLAttr key,const std::string & value,GNEUndoList * undoList)313 GNEDetectorEntryExit::setAttribute(SumoXMLAttr key, const std::string& value, GNEUndoList* undoList) {
314 if (value == getAttribute(key)) {
315 return; //avoid needless changes, later logic relies on the fact that attributes have changed
316 }
317 switch (key) {
318 case SUMO_ATTR_ID:
319 case SUMO_ATTR_LANE:
320 case SUMO_ATTR_POSITION:
321 case SUMO_ATTR_FRIENDLY_POS:
322 case GNE_ATTR_BLOCK_MOVEMENT:
323 case GNE_ATTR_PARENT:
324 case GNE_ATTR_SELECTED:
325 case GNE_ATTR_GENERIC:
326 undoList->p_add(new GNEChange_Attribute(this, myViewNet->getNet(), key, value));
327 break;
328 default:
329 throw InvalidArgument(getTagStr() + " doesn't have an attribute of type '" + toString(key) + "'");
330 }
331 }
332
333
334 bool
isValid(SumoXMLAttr key,const std::string & value)335 GNEDetectorEntryExit::isValid(SumoXMLAttr key, const std::string& value) {
336 switch (key) {
337 case SUMO_ATTR_ID:
338 return isValidAdditionalID(value);
339 case SUMO_ATTR_LANE:
340 return (myViewNet->getNet()->retrieveLane(value, false) != nullptr);
341 case SUMO_ATTR_POSITION:
342 return canParse<double>(value) && fabs(parse<double>(value)) < getLaneParents().front()->getParentEdge().getNBEdge()->getFinalLength();
343 case SUMO_ATTR_FRIENDLY_POS:
344 return canParse<bool>(value);
345 case GNE_ATTR_BLOCK_MOVEMENT:
346 return canParse<bool>(value);
347 case GNE_ATTR_PARENT:
348 return (myViewNet->getNet()->retrieveAdditional(SUMO_TAG_E3DETECTOR, value, false) != nullptr);
349 case GNE_ATTR_SELECTED:
350 return canParse<bool>(value);
351 case GNE_ATTR_GENERIC:
352 return isGenericParametersValid(value);
353 default:
354 throw InvalidArgument(getTagStr() + " doesn't have an attribute of type '" + toString(key) + "'");
355 }
356 }
357
358 void
setAttribute(SumoXMLAttr key,const std::string & value)359 GNEDetectorEntryExit::setAttribute(SumoXMLAttr key, const std::string& value) {
360 switch (key) {
361 case SUMO_ATTR_ID:
362 changeAdditionalID(value);
363 break;
364 case SUMO_ATTR_LANE:
365 changeLaneParents(this, value);
366 break;
367 case SUMO_ATTR_POSITION:
368 myPositionOverLane = parse<double>(value);
369 break;
370 case SUMO_ATTR_FRIENDLY_POS:
371 myFriendlyPosition = parse<bool>(value);
372 break;
373 case GNE_ATTR_BLOCK_MOVEMENT:
374 myBlockMovement = parse<bool>(value);
375 break;
376 case GNE_ATTR_PARENT:
377 changeAdditionalParent(this, value, 0);
378 break;
379 case GNE_ATTR_SELECTED:
380 if (parse<bool>(value)) {
381 selectAttributeCarrier();
382 } else {
383 unselectAttributeCarrier();
384 }
385 break;
386 case GNE_ATTR_GENERIC:
387 setGenericParametersStr(value);
388 break;
389 default:
390 throw InvalidArgument(getTagStr() + " doesn't have an attribute of type '" + toString(key) + "'");
391 }
392 // check if updated attribute requieres update geometry
393 if (myTagProperty.hasAttribute(key) && myTagProperty.getAttributeProperties(key).requiereUpdateGeometry()) {
394 updateGeometry(true);
395 }
396 }
397
398 /****************************************************************************/
399