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    GNEContainerStop.cpp
11 /// @author  Pablo Alvarez Lopez
12 /// @date    Jun 2016
13 /// @version $Id$
14 ///
15 // A lane area vehicles can halt at (GNE version)
16 /****************************************************************************/
17 
18 // ===========================================================================
19 // included modules
20 // ===========================================================================
21 
22 #include <foreign/fontstash/fontstash.h>
23 #include <netedit/GNENet.h>
24 #include <netedit/GNEUndoList.h>
25 #include <netedit/GNEViewNet.h>
26 #include <netedit/changes/GNEChange_Attribute.h>
27 #include <netedit/netelements/GNEEdge.h>
28 #include <netedit/netelements/GNELane.h>
29 #include <utils/gui/div/GLHelper.h>
30 #include <utils/options/OptionsCont.h>
31 #include <utils/gui/globjects/GLIncludes.h>
32 
33 #include "GNEContainerStop.h"
34 
35 // ===========================================================================
36 // method definitions
37 // ===========================================================================
38 
GNEContainerStop(const std::string & id,GNELane * lane,GNEViewNet * viewNet,const std::string & startPos,const std::string & endPos,const std::string & name,const std::vector<std::string> & lines,bool friendlyPosition,bool blockMovement)39 GNEContainerStop::GNEContainerStop(const std::string& id, GNELane* lane, GNEViewNet* viewNet, const std::string& startPos, const std::string& endPos, const std::string& name, const std::vector<std::string>& lines, bool friendlyPosition, bool blockMovement) :
40     GNEStoppingPlace(id, viewNet, GLO_CONTAINER_STOP, SUMO_TAG_CONTAINER_STOP, lane, startPos, endPos, name, friendlyPosition, blockMovement),
41     myLines(lines) {
42 }
43 
44 
~GNEContainerStop()45 GNEContainerStop::~GNEContainerStop() {}
46 
47 
48 void
updateGeometry(bool updateGrid)49 GNEContainerStop::updateGeometry(bool updateGrid) {
50     // first check if object has to be removed from grid (SUMOTree)
51     if (updateGrid) {
52         myViewNet->getNet()->removeGLObjectFromGrid(this);
53     }
54 
55     // Get value of option "lefthand"
56     double offsetSign = OptionsCont::getOptions().getBool("lefthand") ? -1 : 1;
57 
58     // Update common geometry of stopping place
59     setStoppingPlaceGeometry(getLaneParents().front()->getParentEdge().getNBEdge()->getLaneWidth(getLaneParents().front()->getIndex()) / 2);
60 
61     // Obtain a copy of the shape
62     PositionVector tmpShape = myGeometry.shape;
63 
64     // Move shape to side
65     tmpShape.move2side(1.5 * offsetSign);
66 
67     // Get position of the sign
68     mySignPos = tmpShape.getLineCenter();
69 
70     // Set block icon position
71     myBlockIcon.position = myGeometry.shape.getLineCenter();
72 
73     // Set block icon rotation, and using their rotation for sign
74     myBlockIcon.setRotation(getLaneParents().front());
75 
76     // last step is to check if object has to be added into grid (SUMOTree) again
77     if (updateGrid) {
78         myViewNet->getNet()->addGLObjectIntoGrid(this);
79     }
80 }
81 
82 
83 void
drawGL(const GUIVisualizationSettings & s) const84 GNEContainerStop::drawGL(const GUIVisualizationSettings& s) const {
85     // obtain circle resolution
86     int circleResolution = getCircleResolution(s);
87     // Obtain exaggeration of the draw
88     const double exaggeration = s.addSize.getExaggeration(s, this);
89     // Start drawing adding an gl identificator
90     glPushName(getGlID());
91     // Add a draw matrix
92     glPushMatrix();
93     // Start with the drawing of the area traslating matrix to origin
94     glTranslated(0, 0, getType());
95     // Set color of the base
96     if (drawUsingSelectColor()) {
97         GLHelper::setColor(s.selectedAdditionalColor);
98     } else {
99         GLHelper::setColor(s.SUMO_color_containerStop);
100     }
101     // Draw the area using shape, shapeRotations, shapeLengths and value of exaggeration
102     GLHelper::drawBoxLines(myGeometry.shape, myGeometry.shapeRotations, myGeometry.shapeLengths, exaggeration);
103     // Check if the distance is enought to draw details and if is being drawn for selecting
104     if (s.drawForSelecting) {
105         // only draw circle depending of distance between sign and mouse cursor
106         if (myViewNet->getPositionInformation().distanceSquaredTo2D(mySignPos) <= (myCircleWidthSquared + 2)) {
107             // Add a draw matrix for details
108             glPushMatrix();
109             // Start drawing sign traslating matrix to signal position
110             glTranslated(mySignPos.x(), mySignPos.y(), 0);
111             // scale matrix depending of the exaggeration
112             glScaled(exaggeration, exaggeration, 1);
113             // set color
114             GLHelper::setColor(s.SUMO_color_containerStop);
115             // Draw circle
116             GLHelper::drawFilledCircle(myCircleWidth, circleResolution);
117             // pop draw matrix
118             glPopMatrix();
119         }
120     } else if (s.scale * exaggeration >= 10) {
121         // Add a draw matrix for details
122         glPushMatrix();
123         // Iterate over every line
124         for (int i = 0; i < (int)myLines.size(); ++i) {
125             // push a new matrix for every line
126             glPushMatrix();
127             // Rotate and traslaste
128             glTranslated(mySignPos.x(), mySignPos.y(), 0);
129             glRotated(-1 * myBlockIcon.rotation, 0, 0, 1);
130             // draw line with a color depending of the selection status
131             if (drawUsingSelectColor()) {
132                 GLHelper::drawText(myLines[i].c_str(), Position(1.2, (double)i), .1, 1.f, s.selectionColor, 0, FONS_ALIGN_LEFT);
133             } else {
134                 GLHelper::drawText(myLines[i].c_str(), Position(1.2, (double)i), .1, 1.f, s.SUMO_color_containerStop, 0, FONS_ALIGN_LEFT);
135             }
136             // pop matrix for every line
137             glPopMatrix();
138         }
139         // Start drawing sign traslating matrix to signal position
140         glTranslated(mySignPos.x(), mySignPos.y(), 0);
141         // scale matrix depending of the exaggeration
142         glScaled(exaggeration, exaggeration, 1);
143         // Set color of the externe circle
144         if (drawUsingSelectColor()) {
145             GLHelper::setColor(s.selectedAdditionalColor);
146         } else {
147             GLHelper::setColor(s.SUMO_color_containerStop);
148         }
149         // Draw circle
150         GLHelper::drawFilledCircle(myCircleWidth, circleResolution);
151         // Traslate to front
152         glTranslated(0, 0, .1);
153         // Set color of the inner circle
154         if (drawUsingSelectColor()) {
155             GLHelper::setColor(s.selectionColor);
156         } else {
157             GLHelper::setColor(s.SUMO_color_containerStop_sign);
158         }
159         // draw another circle in the same position, but a little bit more small
160         GLHelper::drawFilledCircle(myCircleInWidth, circleResolution);
161         // If the scale * exageration is equal or more than 4.5, draw H
162         if (s.scale * exaggeration >= 4.5) {
163             if (drawUsingSelectColor()) {
164                 GLHelper::drawText("C", Position(), .1, myCircleInText, s.selectedAdditionalColor, myBlockIcon.rotation);
165             } else {
166                 GLHelper::drawText("C", Position(), .1, myCircleInText, s.SUMO_color_containerStop, myBlockIcon.rotation);
167             }
168         }
169         // pop draw matrix
170         glPopMatrix();
171         // Show Lock icon depending of the Edit mode
172         myBlockIcon.draw();
173     }
174     // pop draw matrix
175     glPopMatrix();
176     // Draw name if isn't being drawn for selecting
177     if (!s.drawForSelecting) {
178         drawName(getCenteringBoundary().getCenter(), s.scale, s.addName);
179     }
180     // check if dotted contour has to be drawn
181     if (!s.drawForSelecting && (myViewNet->getDottedAC() == this)) {
182         GLHelper::drawShapeDottedContour(getType(), myGeometry.shape, exaggeration);
183     }
184     // Pop name
185     glPopName();
186 }
187 
188 
189 std::string
getAttribute(SumoXMLAttr key) const190 GNEContainerStop::getAttribute(SumoXMLAttr key) const {
191     switch (key) {
192         case SUMO_ATTR_ID:
193             return getAdditionalID();
194         case SUMO_ATTR_LANE:
195             return getLaneParents().front()->getID();
196         case SUMO_ATTR_STARTPOS:
197             return toString(myStartPosition);
198         case SUMO_ATTR_ENDPOS:
199             return myEndPosition;
200         case SUMO_ATTR_NAME:
201             return myAdditionalName;
202         case SUMO_ATTR_FRIENDLY_POS:
203             return toString(myFriendlyPosition);
204         case SUMO_ATTR_LINES:
205             return joinToString(myLines, " ");
206         case GNE_ATTR_BLOCK_MOVEMENT:
207             return toString(myBlockMovement);
208         case GNE_ATTR_SELECTED:
209             return toString(isAttributeCarrierSelected());
210         case GNE_ATTR_GENERIC:
211             return getGenericParametersStr();
212         default:
213             throw InvalidArgument(getTagStr() + " doesn't have an attribute of type '" + toString(key) + "'");
214     }
215 }
216 
217 
218 void
setAttribute(SumoXMLAttr key,const std::string & value,GNEUndoList * undoList)219 GNEContainerStop::setAttribute(SumoXMLAttr key, const std::string& value, GNEUndoList* undoList) {
220     if (value == getAttribute(key)) {
221         return; //avoid needless changes, later logic relies on the fact that attributes have changed
222     }
223     switch (key) {
224         case SUMO_ATTR_ID:
225         case SUMO_ATTR_LANE:
226         case SUMO_ATTR_STARTPOS:
227         case SUMO_ATTR_ENDPOS:
228         case SUMO_ATTR_NAME:
229         case SUMO_ATTR_FRIENDLY_POS:
230         case SUMO_ATTR_LINES:
231         case GNE_ATTR_BLOCK_MOVEMENT:
232         case GNE_ATTR_SELECTED:
233         case GNE_ATTR_GENERIC:
234             undoList->p_add(new GNEChange_Attribute(this, myViewNet->getNet(), key, value));
235             break;
236         default:
237             throw InvalidArgument(getTagStr() + " doesn't have an attribute of type '" + toString(key) + "'");
238     }
239 }
240 
241 
242 bool
isValid(SumoXMLAttr key,const std::string & value)243 GNEContainerStop::isValid(SumoXMLAttr key, const std::string& value) {
244     switch (key) {
245         case SUMO_ATTR_ID:
246             return isValidAdditionalID(value);
247         case SUMO_ATTR_LANE:
248             if (myViewNet->getNet()->retrieveLane(value, false) != nullptr) {
249                 return true;
250             } else {
251                 return false;
252             }
253         case SUMO_ATTR_STARTPOS:
254             if (value.empty()) {
255                 return true;
256             } else if (canParse<double>(value)) {
257                 return checkStoppinPlacePosition(value, myEndPosition, getLaneParents().front()->getParentEdge().getNBEdge()->getFinalLength(), myFriendlyPosition);
258             } else {
259                 return false;
260             }
261         case SUMO_ATTR_ENDPOS:
262             if (value.empty()) {
263                 return true;
264             } else if (canParse<double>(value)) {
265                 return checkStoppinPlacePosition(myStartPosition, value, getLaneParents().front()->getParentEdge().getNBEdge()->getFinalLength(), myFriendlyPosition);
266             } else {
267                 return false;
268             }
269         case SUMO_ATTR_NAME:
270             return SUMOXMLDefinitions::isValidAttribute(value);
271         case SUMO_ATTR_FRIENDLY_POS:
272             return canParse<bool>(value);
273         case SUMO_ATTR_LINES:
274             return canParse<std::vector<std::string> >(value);
275         case GNE_ATTR_BLOCK_MOVEMENT:
276             return canParse<bool>(value);
277         case GNE_ATTR_SELECTED:
278             return canParse<bool>(value);
279         case GNE_ATTR_GENERIC:
280             return isGenericParametersValid(value);
281         default:
282             throw InvalidArgument(getTagStr() + " doesn't have an attribute of type '" + toString(key) + "'");
283     }
284 }
285 
286 // ===========================================================================
287 // private
288 // ===========================================================================
289 
290 void
setAttribute(SumoXMLAttr key,const std::string & value)291 GNEContainerStop::setAttribute(SumoXMLAttr key, const std::string& value) {
292     switch (key) {
293         case SUMO_ATTR_ID:
294             changeAdditionalID(value);
295             break;
296         case SUMO_ATTR_LANE:
297             changeLaneParents(this, value);
298             break;
299         case SUMO_ATTR_STARTPOS:
300             myStartPosition = value;
301             break;
302         case SUMO_ATTR_ENDPOS:
303             myEndPosition = value;
304             break;
305         case SUMO_ATTR_NAME:
306             myAdditionalName = value;
307             break;
308         case SUMO_ATTR_FRIENDLY_POS:
309             myFriendlyPosition = parse<bool>(value);
310             break;
311         case SUMO_ATTR_LINES:
312             myLines = GNEAttributeCarrier::parse<std::vector<std::string> >(value);
313             break;
314         case GNE_ATTR_BLOCK_MOVEMENT:
315             myBlockMovement = parse<bool>(value);
316             break;
317         case GNE_ATTR_SELECTED:
318             if (parse<bool>(value)) {
319                 selectAttributeCarrier();
320             } else {
321                 unselectAttributeCarrier();
322             }
323             break;
324         case GNE_ATTR_GENERIC:
325             setGenericParametersStr(value);
326             break;
327         default:
328             throw InvalidArgument(getTagStr() + " doesn't have an attribute of type '" + toString(key) + "'");
329     }
330     // check if updated attribute requieres update geometry
331     if (myTagProperty.hasAttribute(key) && myTagProperty.getAttributeProperties(key).requiereUpdateGeometry()) {
332         updateGeometry(true);
333     }
334 }
335 
336 /****************************************************************************/
337