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    GNERouteProbe.cpp
11 /// @author  Pablo Alvarez Lopez
12 /// @date    May 2016
13 /// @version $Id$
14 ///
15 //
16 /****************************************************************************/
17 
18 // ===========================================================================
19 // included modules
20 // ===========================================================================
21 #include <config.h>
22 
23 #include <utils/gui/images/GUITextureSubSys.h>
24 #include <utils/gui/div/GLHelper.h>
25 #include <netedit/GNEViewNet.h>
26 #include <netedit/netelements/GNEEdge.h>
27 #include <netedit/netelements/GNELane.h>
28 #include <netedit/GNEUndoList.h>
29 #include <netedit/GNENet.h>
30 #include <netedit/changes/GNEChange_Attribute.h>
31 #include <utils/gui/globjects/GLIncludes.h>
32 
33 #include "GNERouteProbe.h"
34 
35 
36 // ===========================================================================
37 // member method definitions
38 // ===========================================================================
39 
GNERouteProbe(const std::string & id,GNEViewNet * viewNet,GNEEdge * edge,const std::string & frequency,const std::string & name,const std::string & filename,double begin)40 GNERouteProbe::GNERouteProbe(const std::string& id, GNEViewNet* viewNet, GNEEdge* edge, const std::string& frequency, const std::string& name, const std::string& filename, double begin) :
41     GNEAdditional(id, viewNet, GLO_ROUTEPROBE, SUMO_TAG_ROUTEPROBE, name, false, {
42     edge
43 }, {}, {}, {}, {}, {}, {}, {}, {}, {}),
44 myFrequency(frequency),
45 myFilename(filename),
46 myBegin(begin),
47 myRelativePositionY(0) {
48 }
49 
50 
~GNERouteProbe()51 GNERouteProbe::~GNERouteProbe() {
52 }
53 
54 
55 void
updateGeometry(bool updateGrid)56 GNERouteProbe::updateGeometry(bool updateGrid) {
57     // first check if object has to be removed from grid (SUMOTree)
58     if (updateGrid) {
59         myViewNet->getNet()->removeGLObjectFromGrid(this);
60     }
61 
62     // Clear all containers
63     myGeometry.clearGeometry();
64 
65     // obtain relative position of routeProbe in edge
66     myRelativePositionY = 2 * getEdgeParents().front()->getRouteProbeRelativePosition(this);
67 
68     // get lanes of edge
69     GNELane* firstLane = getEdgeParents().front()->getLanes().at(0);
70 
71     // Get shape of lane parent
72     double offset = firstLane->getShape().length() < 0.5 ? firstLane->getShape().length() : 0.5;
73     myGeometry.shape.push_back(firstLane->getShape().positionAtOffset(offset));
74 
75     // Save rotation (angle) of the vector constructed by points f and s
76     myGeometry.shapeRotations.push_back(firstLane->getShape().rotationDegreeAtOffset(offset) * -1);
77 
78     // Set block icon position
79     myBlockIcon.position = myGeometry.shape.getLineCenter();
80 
81     // Set offset of the block icon
82     myBlockIcon.offset = Position(1.1, (-3.06) - myRelativePositionY);
83 
84     // Set block icon rotation, and using their rotation for logo
85     myBlockIcon.setRotation(firstLane);
86 
87     // last step is to check if object has to be added into grid (SUMOTree) again
88     if (updateGrid) {
89         myViewNet->getNet()->addGLObjectIntoGrid(this);
90     }
91 }
92 
93 
94 Position
getPositionInView() const95 GNERouteProbe::getPositionInView() const {
96     if (getEdgeParents().front()->getLanes().front()->getShape().length() < 0.5) {
97         return getEdgeParents().front()->getLanes().front()->getShape().front();
98     } else {
99         Position A = getEdgeParents().front()->getLanes().front()->getShape().positionAtOffset(0.5);
100         Position B = getEdgeParents().front()->getLanes().back()->getShape().positionAtOffset(0.5);
101 
102         // return Middle point
103         return Position((A.x() + B.x()) / 2, (A.y() + B.y()) / 2);
104     }
105 }
106 
107 
108 void
moveGeometry(const Position &)109 GNERouteProbe::moveGeometry(const Position&) {
110     // This additional cannot be moved
111 }
112 
113 
114 void
commitGeometryMoving(GNEUndoList *)115 GNERouteProbe::commitGeometryMoving(GNEUndoList*) {
116     // This additional cannot be moved
117 }
118 
119 
120 std::string
getParentName() const121 GNERouteProbe::getParentName() const {
122     return getEdgeParents().front()->getMicrosimID();
123 }
124 
125 
126 void
drawGL(const GUIVisualizationSettings & s) const127 GNERouteProbe::drawGL(const GUIVisualizationSettings& s) const {
128     // get values
129     glPushName(getGlID());
130     double width = (double) 2.0 * s.scale;
131     glLineWidth(1.0);
132     const double exaggeration = s.addSize.getExaggeration(s, this);
133     const int numberOfLanes = int(getEdgeParents().front()->getLanes().size());
134 
135     // set color
136     if (drawUsingSelectColor()) {
137         GLHelper::setColor(s.selectedAdditionalColor);
138     } else {
139         GLHelper::setColor(RGBColor(255, 216, 0));
140     }
141 
142     // draw shape
143     glPushMatrix();
144     glTranslated(0, 0, getType());
145     glTranslated(myGeometry.shape[0].x(), myGeometry.shape[0].y(), 0);
146     glRotated(myGeometry.shapeRotations[0], 0, 0, 1);
147     glScaled(exaggeration, exaggeration, 1);
148     glTranslated(-1.6, -1.6, 0);
149     glBegin(GL_QUADS);
150     glVertex2d(0,  0.25);
151     glVertex2d(0, -0.25);
152     glVertex2d((numberOfLanes * 3.3), -0.25);
153     glVertex2d((numberOfLanes * 3.3),  0.25);
154     glEnd();
155     glTranslated(0, 0, .01);
156     glBegin(GL_LINES);
157     glVertex2d(0, 0.25 - .1);
158     glVertex2d(0, -0.25 + .1);
159     glEnd();
160 
161     // position indicator (White)
162     if ((width * exaggeration > 1) && !s.drawForSelecting) {
163         if (drawUsingSelectColor()) {
164             GLHelper::setColor(s.selectionColor);
165         } else {
166             GLHelper::setColor(RGBColor::WHITE);
167         }
168         glRotated(90, 0, 0, -1);
169         glBegin(GL_LINES);
170         glVertex2d(0, 0);
171         glVertex2d(0, (numberOfLanes * 3.3));
172         glEnd();
173     }
174 
175     // Pop shape matrix
176     glPopMatrix();
177 
178     // Add a draw matrix for drawing logo
179     glPushMatrix();
180     glTranslated(myGeometry.shape[0].x(), myGeometry.shape[0].y(), getType());
181     glRotated(myGeometry.shapeRotations[0], 0, 0, 1);
182     glTranslated((-2.56) - myRelativePositionY, (-1.6), 0);
183 
184     // Draw icon depending of Route Probe is selected and if isn't being drawn for selecting
185     if (s.drawForSelecting) {
186         GLHelper::setColor(RGBColor::YELLOW);
187         GLHelper::drawBoxLine(Position(0, 1), 0, 2, 1);
188     } else {
189         glColor3d(1, 1, 1);
190         glRotated(-90, 0, 0, 1);
191         if (drawUsingSelectColor()) {
192             GUITexturesHelper::drawTexturedBox(GUITextureSubSys::getTexture(GNETEXTURE_ROUTEPROBESELECTED), 1);
193         } else {
194             GUITexturesHelper::drawTexturedBox(GUITextureSubSys::getTexture(GNETEXTURE_ROUTEPROBE), 1);
195         }
196     }
197 
198     // Pop logo matrix
199     glPopMatrix();
200 
201     // Check if the distance is enought to draw details
202     if ((s.scale * exaggeration >= 10) && !s.drawForSelecting) {
203         // Show Lock icon depending of the Edit mode
204         myBlockIcon.draw(0.4);
205     }
206 
207     // draw name
208     drawName(getCenteringBoundary().getCenter(), s.scale, s.addName);
209 
210     // check if dotted contour has to be drawn
211     if (!s.drawForSelecting && (myViewNet->getDottedAC() == this)) {
212         GLHelper::drawShapeDottedContour(getType(), myGeometry.shape[0], 2, 2, myGeometry.shapeRotations[0], (-2.56) - myRelativePositionY, -1.6);
213     }
214 
215     // pop name
216     glPopName();
217 }
218 
219 
220 std::string
getAttribute(SumoXMLAttr key) const221 GNERouteProbe::getAttribute(SumoXMLAttr key) const {
222     switch (key) {
223         case SUMO_ATTR_ID:
224             return getAdditionalID();
225         case SUMO_ATTR_EDGE:
226             return getEdgeParents().front()->getID();
227         case SUMO_ATTR_NAME:
228             return myAdditionalName;
229         case SUMO_ATTR_FILE:
230             return myFilename;
231         case SUMO_ATTR_FREQUENCY:
232             return toString(myFrequency);
233         case SUMO_ATTR_BEGIN:
234             return toString(myBegin);
235         case GNE_ATTR_SELECTED:
236             return toString(isAttributeCarrierSelected());
237         case GNE_ATTR_GENERIC:
238             return getGenericParametersStr();
239         default:
240             throw InvalidArgument(getTagStr() + " doesn't have an attribute of type '" + toString(key) + "'");
241     }
242 }
243 
244 
245 void
setAttribute(SumoXMLAttr key,const std::string & value,GNEUndoList * undoList)246 GNERouteProbe::setAttribute(SumoXMLAttr key, const std::string& value, GNEUndoList* undoList) {
247     if (value == getAttribute(key)) {
248         return; //avoid needless changes, later logic relies on the fact that attributes have changed
249     }
250     switch (key) {
251         case SUMO_ATTR_ID:
252         case SUMO_ATTR_EDGE:
253         case SUMO_ATTR_NAME:
254         case SUMO_ATTR_FILE:
255         case SUMO_ATTR_FREQUENCY:
256         case SUMO_ATTR_BEGIN:
257         case GNE_ATTR_SELECTED:
258         case GNE_ATTR_GENERIC:
259             undoList->p_add(new GNEChange_Attribute(this, myViewNet->getNet(), key, value));
260             break;
261         default:
262             throw InvalidArgument(getTagStr() + " doesn't have an attribute of type '" + toString(key) + "'");
263     }
264 }
265 
266 
267 std::string
getPopUpID() const268 GNERouteProbe::getPopUpID() const {
269     return getTagStr();
270 }
271 
272 
273 std::string
getHierarchyName() const274 GNERouteProbe::getHierarchyName() const {
275     return getTagStr() + ": " + getAttribute(SUMO_ATTR_BEGIN);
276 }
277 
278 // ===========================================================================
279 // private
280 // ===========================================================================
281 
282 bool
isValid(SumoXMLAttr key,const std::string & value)283 GNERouteProbe::isValid(SumoXMLAttr key, const std::string& value) {
284     switch (key) {
285         case SUMO_ATTR_ID:
286             return isValidAdditionalID(value);
287         case SUMO_ATTR_EDGE:
288             if (myViewNet->getNet()->retrieveEdge(value, false) != nullptr) {
289                 return true;
290             } else {
291                 return false;
292             }
293         case SUMO_ATTR_NAME:
294             return SUMOXMLDefinitions::isValidAttribute(value);
295         case SUMO_ATTR_FILE:
296             return SUMOXMLDefinitions::isValidFilename(value);
297         case SUMO_ATTR_FREQUENCY:
298             if (value.empty()) {
299                 return true;
300             } else {
301                 return canParse<double>(value) && (parse<double>(value) >= 0);
302             }
303         case SUMO_ATTR_BEGIN:
304             return canParse<double>(value) && (parse<double>(value) >= 0);
305         case GNE_ATTR_SELECTED:
306             return canParse<bool>(value);
307         case GNE_ATTR_GENERIC:
308             return isGenericParametersValid(value);
309         default:
310             throw InvalidArgument(getTagStr() + " doesn't have an attribute of type '" + toString(key) + "'");
311     }
312 }
313 
314 
315 void
setAttribute(SumoXMLAttr key,const std::string & value)316 GNERouteProbe::setAttribute(SumoXMLAttr key, const std::string& value) {
317     switch (key) {
318         case SUMO_ATTR_ID:
319             changeAdditionalID(value);
320             break;
321         case SUMO_ATTR_EDGE:
322             changeEdgeParents(this, value);
323             break;
324         case SUMO_ATTR_NAME:
325             myAdditionalName = value;
326             break;
327         case SUMO_ATTR_FILE:
328             myFilename = value;
329             break;
330         case SUMO_ATTR_FREQUENCY:
331             myFrequency = value;
332             break;
333         case SUMO_ATTR_BEGIN:
334             myBegin = parse<double>(value);
335             break;
336         case GNE_ATTR_SELECTED:
337             if (parse<bool>(value)) {
338                 selectAttributeCarrier();
339             } else {
340                 unselectAttributeCarrier();
341             }
342             break;
343         case GNE_ATTR_GENERIC:
344             setGenericParametersStr(value);
345             break;
346         default:
347             throw InvalidArgument(getTagStr() + " doesn't have an attribute of type '" + toString(key) + "'");
348     }
349     // check if updated attribute requieres update geometry
350     if (myTagProperty.hasAttribute(key) && myTagProperty.getAttributeProperties(key).requiereUpdateGeometry()) {
351         updateGeometry(true);
352     }
353 }
354 
355 /****************************************************************************/
356