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    GNEParkingArea.cpp
11 /// @author  Pablo Alvarez Lopez
12 /// @date    Feb 2018
13 /// @version $Id$
14 ///
15 // A lane area vehicles can park at (GNE version)
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/options/OptionsCont.h>
30 #include <utils/gui/globjects/GLIncludes.h>
31 
32 #include "GNEParkingArea.h"
33 
34 
35 // ===========================================================================
36 // method definitions
37 // ===========================================================================
38 
GNEParkingArea(const std::string & id,GNELane * lane,GNEViewNet * viewNet,const std::string & startPos,const std::string & endPos,const std::string & name,bool friendlyPosition,int roadSideCapacity,bool onRoad,double width,const std::string & length,double angle,bool blockMovement)39 GNEParkingArea::GNEParkingArea(const std::string& id, GNELane* lane, GNEViewNet* viewNet, const std::string& startPos, const std::string& endPos, const std::string& name,
40                                bool friendlyPosition, int roadSideCapacity, bool onRoad, double width, const std::string& length, double angle, bool blockMovement) :
41     GNEStoppingPlace(id, viewNet, GLO_PARKING_AREA, SUMO_TAG_PARKING_AREA, lane, startPos, endPos, name, friendlyPosition, blockMovement),
42     myRoadSideCapacity(roadSideCapacity),
43     myOnRoad(onRoad),
44     myWidth(width),
45     myLength(length),
46     myAngle(angle) {
47 }
48 
49 
~GNEParkingArea()50 GNEParkingArea::~GNEParkingArea() {}
51 
52 
53 void
updateGeometry(bool updateGrid)54 GNEParkingArea::updateGeometry(bool updateGrid) {
55     // first check if object has to be removed from grid (SUMOTree)
56     if (updateGrid) {
57         myViewNet->getNet()->removeGLObjectFromGrid(this);
58     }
59 
60     // Get value of option "lefthand"
61     double offsetSign = OptionsCont::getOptions().getBool("lefthand") ? -1 : 1;
62 
63     // Update common geometry of stopping place
64     setStoppingPlaceGeometry(getLaneParents().front()->getParentEdge().getNBEdge()->getLaneWidth(getLaneParents().front()->getIndex()) / 2 + myWidth);
65 
66     // Obtain a copy of the shape
67     PositionVector tmpShape = myGeometry.shape;
68 
69     // Move shape to side
70     tmpShape.move2side(1.5 * offsetSign);
71 
72     // Get position of the sign
73     mySignPos = tmpShape.getLineCenter();
74 
75     // Set block icon position
76     myBlockIcon.position = myGeometry.shape.getLineCenter();
77 
78     // Set block icon rotation, and using their rotation for sign
79     myBlockIcon.setRotation(getLaneParents().front());
80 
81     // last step is to check if object has to be added into grid (SUMOTree) again
82     if (updateGrid) {
83         myViewNet->getNet()->addGLObjectIntoGrid(this);
84     }
85 }
86 
87 
88 void
drawGL(const GUIVisualizationSettings & s) const89 GNEParkingArea::drawGL(const GUIVisualizationSettings& s) const {
90     // obtain circle resolution
91     int circleResolution = getCircleResolution(s);
92     // Obtain exaggeration of the draw
93     const double exaggeration = s.addSize.getExaggeration(s, this);
94     // Push name
95     glPushName(getGlID());
96     // Push base matrix
97     glPushMatrix();
98     // Traslate matrix
99     glTranslated(0, 0, getType());
100     // Set Color
101     if (drawUsingSelectColor()) {
102         GLHelper::setColor(s.selectedAdditionalColor);
103     } else {
104         GLHelper::setColor(RGBColor(83, 89, 172, 255));
105     }
106     // Draw base
107     GLHelper::drawBoxLines(myGeometry.shape, myGeometry.shapeRotations, myGeometry.shapeLengths, myWidth * exaggeration);
108     // Check if the distance is enought to draw details and if is being drawn for selecting
109     if (s.drawForSelecting) {
110         // only draw circle depending of distance between sign and mouse cursor
111         if (myViewNet->getPositionInformation().distanceSquaredTo2D(mySignPos) <= (myCircleWidthSquared + 2)) {
112             // Add a draw matrix for details
113             glPushMatrix();
114             // Start drawing sign traslating matrix to signal position
115             glTranslated(mySignPos.x(), mySignPos.y(), 0);
116             // scale matrix depending of the exaggeration
117             glScaled(exaggeration, exaggeration, 1);
118             // set color
119             GLHelper::setColor(s.SUMO_color_busStop);
120             // Draw circle
121             GLHelper::drawFilledCircle(myCircleWidth, circleResolution);
122             // pop draw matrix
123             glPopMatrix();
124         }
125     } else if (s.scale * exaggeration >= 10) {
126         // Push matrix for details
127         glPushMatrix();
128         // Set position over sign
129         glTranslated(mySignPos.x(), mySignPos.y(), 0);
130         // Scale matrix
131         glScaled(exaggeration, exaggeration, 1);
132         // Set base color
133         if (drawUsingSelectColor()) {
134             GLHelper::setColor(s.selectedAdditionalColor);
135         } else {
136             GLHelper::setColor(RGBColor(83, 89, 172, 255));
137         }
138         // Draw extern
139         GLHelper::drawFilledCircle(myCircleWidth, circleResolution);
140         // Move to top
141         glTranslated(0, 0, .1);
142         // Set sign color
143         if (drawUsingSelectColor()) {
144             GLHelper::setColor(s.selectionColor);
145         } else {
146             GLHelper::setColor(RGBColor(177, 184, 186, 171));
147         }
148         // Draw internt sign
149         GLHelper::drawFilledCircle(myCircleInWidth, circleResolution);
150         // Draw sign 'C'
151         if (s.scale * exaggeration >= 4.5) {
152             if (drawUsingSelectColor()) {
153                 GLHelper::drawText("P", Position(), .1, myCircleInText, s.selectedAdditionalColor, myBlockIcon.rotation);
154             } else {
155                 GLHelper::drawText("P", Position(), .1, myCircleInText, RGBColor(83, 89, 172, 255), myBlockIcon.rotation);
156             }
157         }
158         // Pop sign matrix
159         glPopMatrix();
160         // Draw icon
161         myBlockIcon.draw();
162     }
163     // Pop base matrix
164     glPopMatrix();
165     // Draw name if isn't being drawn for selecting
166     drawName(getCenteringBoundary().getCenter(), s.scale, s.addName);
167     if (s.addFullName.show && (myAdditionalName != "") && !s.drawForSelecting) {
168         GLHelper::drawText(myAdditionalName, mySignPos, GLO_MAX - getType(), s.addFullName.scaledSize(s.scale), s.addFullName.color, myBlockIcon.rotation);
169     }
170     // check if dotted contour has to be drawn
171     if (!s.drawForSelecting && (myViewNet->getDottedAC() == this)) {
172         GLHelper::drawShapeDottedContour(getType(), myGeometry.shape, myWidth * exaggeration);
173     }
174     // Pop name matrix
175     glPopName();
176 }
177 
178 
179 std::string
getAttribute(SumoXMLAttr key) const180 GNEParkingArea::getAttribute(SumoXMLAttr key) const {
181     switch (key) {
182         case SUMO_ATTR_ID:
183             return getAdditionalID();
184         case SUMO_ATTR_LANE:
185             return getLaneParents().front()->getID();
186         case SUMO_ATTR_STARTPOS:
187             return toString(myStartPosition);
188         case SUMO_ATTR_ENDPOS:
189             return myEndPosition;
190         case SUMO_ATTR_NAME:
191             return myAdditionalName;
192         case SUMO_ATTR_FRIENDLY_POS:
193             return toString(myFriendlyPosition);
194         case SUMO_ATTR_ROADSIDE_CAPACITY:
195             return toString(myRoadSideCapacity);
196         case SUMO_ATTR_ONROAD:
197             return toString(myOnRoad);
198         case SUMO_ATTR_WIDTH:
199             return toString(myWidth);
200         case SUMO_ATTR_LENGTH:
201             return myLength;
202         case SUMO_ATTR_ANGLE:
203             return toString(myAngle);
204         case GNE_ATTR_BLOCK_MOVEMENT:
205             return toString(myBlockMovement);
206         case GNE_ATTR_SELECTED:
207             return toString(isAttributeCarrierSelected());
208         case GNE_ATTR_GENERIC:
209             return getGenericParametersStr();
210         default:
211             throw InvalidArgument(getTagStr() + " doesn't have an attribute of type '" + toString(key) + "'");
212     }
213 }
214 
215 
216 void
setAttribute(SumoXMLAttr key,const std::string & value,GNEUndoList * undoList)217 GNEParkingArea::setAttribute(SumoXMLAttr key, const std::string& value, GNEUndoList* undoList) {
218     if (value == getAttribute(key)) {
219         return; //avoid needless changes, later logic relies on the fact that attributes have changed
220     }
221     switch (key) {
222         case SUMO_ATTR_ID: {
223             // change ID of Entry
224             undoList->p_add(new GNEChange_Attribute(this, myViewNet->getNet(), key, value));
225             // Change Ids of all Parking Spaces
226             for (auto i : getAdditionalChilds()) {
227                 i->setAttribute(SUMO_ATTR_ID, generateChildID(SUMO_TAG_PARKING_SPACE), undoList);
228             }
229             break;
230         }
231         case SUMO_ATTR_LANE:
232         case SUMO_ATTR_STARTPOS:
233         case SUMO_ATTR_ENDPOS:
234         case SUMO_ATTR_NAME:
235         case SUMO_ATTR_FRIENDLY_POS:
236         case SUMO_ATTR_ROADSIDE_CAPACITY:
237         case SUMO_ATTR_ONROAD:
238         case SUMO_ATTR_WIDTH:
239         case SUMO_ATTR_LENGTH:
240         case SUMO_ATTR_ANGLE:
241         case GNE_ATTR_BLOCK_MOVEMENT:
242         case GNE_ATTR_SELECTED:
243         case GNE_ATTR_GENERIC:
244             undoList->p_add(new GNEChange_Attribute(this, myViewNet->getNet(), key, value));
245             break;
246         default:
247             throw InvalidArgument(getTagStr() + " doesn't have an attribute of type '" + toString(key) + "'");
248     }
249 }
250 
251 
252 bool
isValid(SumoXMLAttr key,const std::string & value)253 GNEParkingArea::isValid(SumoXMLAttr key, const std::string& value) {
254     switch (key) {
255         case SUMO_ATTR_ID:
256             return isValidAdditionalID(value);
257         case SUMO_ATTR_LANE:
258             if (myViewNet->getNet()->retrieveLane(value, false) != nullptr) {
259                 return true;
260             } else {
261                 return false;
262             }
263         case SUMO_ATTR_STARTPOS:
264             if (value.empty()) {
265                 return true;
266             } else if (canParse<double>(value)) {
267                 return checkStoppinPlacePosition(value, myEndPosition, getLaneParents().front()->getParentEdge().getNBEdge()->getFinalLength(), myFriendlyPosition);
268             } else {
269                 return false;
270             }
271         case SUMO_ATTR_ENDPOS:
272             if (value.empty()) {
273                 return true;
274             } else if (canParse<double>(value)) {
275                 return checkStoppinPlacePosition(myStartPosition, value, getLaneParents().front()->getParentEdge().getNBEdge()->getFinalLength(), myFriendlyPosition);
276             } else {
277                 return false;
278             }
279         case SUMO_ATTR_NAME:
280             return SUMOXMLDefinitions::isValidAttribute(value);
281         case SUMO_ATTR_FRIENDLY_POS:
282             return canParse<bool>(value);
283         case SUMO_ATTR_ROADSIDE_CAPACITY:
284             return canParse<double>(value) && (parse<double>(value) >= 0);
285         case SUMO_ATTR_ONROAD:
286             return canParse<bool>(value);
287         case SUMO_ATTR_WIDTH:
288             return canParse<double>(value) && (parse<double>(value) >= 0);
289         case SUMO_ATTR_LENGTH:
290             if (value.empty()) {
291                 return true;
292             } else {
293                 return canParse<double>(value) && (parse<double>(value) >= 0);
294             }
295         case SUMO_ATTR_ANGLE:
296             return canParse<double>(value);
297         case GNE_ATTR_BLOCK_MOVEMENT:
298             return canParse<bool>(value);
299         case GNE_ATTR_SELECTED:
300             return canParse<bool>(value);
301         case GNE_ATTR_GENERIC:
302             return isGenericParametersValid(value);
303         default:
304             throw InvalidArgument(getTagStr() + " doesn't have an attribute of type '" + toString(key) + "'");
305     }
306 }
307 
308 // ===========================================================================
309 // private
310 // ===========================================================================
311 
312 void
setAttribute(SumoXMLAttr key,const std::string & value)313 GNEParkingArea::setAttribute(SumoXMLAttr key, const std::string& value) {
314     switch (key) {
315         case SUMO_ATTR_ID:
316             changeAdditionalID(value);
317             break;
318         case SUMO_ATTR_LANE:
319             changeLaneParents(this, value);
320             break;
321         case SUMO_ATTR_STARTPOS:
322             myStartPosition = value;
323             break;
324         case SUMO_ATTR_ENDPOS:
325             myEndPosition = value;
326             break;
327         case SUMO_ATTR_NAME:
328             myAdditionalName = value;
329             break;
330         case SUMO_ATTR_FRIENDLY_POS:
331             myFriendlyPosition = parse<bool>(value);
332             break;
333         case SUMO_ATTR_ROADSIDE_CAPACITY:
334             myRoadSideCapacity = parse<int>(value);
335             break;
336         case SUMO_ATTR_ONROAD:
337             myOnRoad = parse<bool>(value);
338             break;
339         case SUMO_ATTR_WIDTH:
340             myWidth = parse<double>(value);
341             break;
342         case SUMO_ATTR_LENGTH:
343             myLength = value;
344             break;
345         case SUMO_ATTR_ANGLE:
346             myAngle = parse<double>(value);
347             break;
348         case GNE_ATTR_BLOCK_MOVEMENT:
349             myBlockMovement = parse<bool>(value);
350             break;
351         case GNE_ATTR_SELECTED:
352             if (parse<bool>(value)) {
353                 selectAttributeCarrier();
354             } else {
355                 unselectAttributeCarrier();
356             }
357             break;
358         case GNE_ATTR_GENERIC:
359             setGenericParametersStr(value);
360             break;
361         default:
362             throw InvalidArgument(getTagStr() + " doesn't have an attribute of type '" + toString(key) + "'");
363     }
364     // check if updated attribute requieres update geometry
365     if (myTagProperty.hasAttribute(key) && myTagProperty.getAttributeProperties(key).requiereUpdateGeometry()) {
366         updateGeometry(true);
367     }
368 }
369 
370 
371 /****************************************************************************/
372