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