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