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    GNEDetectorE1Instant.cpp
11 /// @author  Pablo Alvarez Lopez
12 /// @date    Jun 2018
13 /// @version $Id$
14 ///
15 //
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/gui/globjects/GLIncludes.h>
30 
31 #include "GNEDetectorE1Instant.h"
32 #include "GNEAdditionalHandler.h"
33 
34 
35 // ===========================================================================
36 // member method definitions
37 // ===========================================================================
38 
GNEDetectorE1Instant(const std::string & id,GNELane * lane,GNEViewNet * viewNet,double pos,const std::string & filename,const std::string & vehicleTypes,const std::string & name,bool friendlyPos,bool blockMovement)39 GNEDetectorE1Instant::GNEDetectorE1Instant(const std::string& id, GNELane* lane, GNEViewNet* viewNet, double pos, const std::string& filename, const std::string& vehicleTypes, const std::string& name, bool friendlyPos, bool blockMovement) :
40     GNEDetector(id, viewNet, GLO_E1DETECTOR_INSTANT, SUMO_TAG_INSTANT_INDUCTION_LOOP, pos, 0, filename, vehicleTypes, name, friendlyPos, blockMovement, {
41     lane
42 }) {
43 }
44 
45 
~GNEDetectorE1Instant()46 GNEDetectorE1Instant::~GNEDetectorE1Instant() {
47 }
48 
49 
50 bool
isAdditionalValid() const51 GNEDetectorE1Instant::isAdditionalValid() const {
52     // with friendly position enabled position are "always fixed"
53     if (myFriendlyPosition) {
54         return true;
55     } else {
56         return fabs(myPositionOverLane) <= getLaneParents().front()->getParentEdge().getNBEdge()->getFinalLength();
57     }
58 }
59 
60 
61 std::string
getAdditionalProblem() const62 GNEDetectorE1Instant::getAdditionalProblem() const {
63     // declare variable for error position
64     std::string errorPosition;
65     const double len = getLaneParents().front()->getParentEdge().getNBEdge()->getFinalLength();
66     // check positions over lane
67     if (myPositionOverLane < -len) {
68         errorPosition = (toString(SUMO_ATTR_POSITION) + " < 0");
69     }
70     if (myPositionOverLane > len) {
71         errorPosition = (toString(SUMO_ATTR_POSITION) + " > lanes's length");
72     }
73     return errorPosition;
74 }
75 
76 
77 void
fixAdditionalProblem()78 GNEDetectorE1Instant::fixAdditionalProblem() {
79     // declare new position
80     double newPositionOverLane = myPositionOverLane;
81     // fix pos and lenght  checkAndFixDetectorPosition
82     GNEAdditionalHandler::checkAndFixDetectorPosition(newPositionOverLane, getLaneParents().front()->getParentEdge().getNBEdge()->getFinalLength(), true);
83     // set new position
84     setAttribute(SUMO_ATTR_POSITION, toString(newPositionOverLane), myViewNet->getUndoList());
85 }
86 
87 
88 void
moveGeometry(const Position & offset)89 GNEDetectorE1Instant::moveGeometry(const Position& offset) {
90     // Calculate new position using old position
91     Position newPosition = myMove.originalViewPosition;
92     newPosition.add(offset);
93     // filtern position using snap to active grid
94     newPosition = myViewNet->snapToActiveGrid(newPosition);
95     const bool storeNegative = myPositionOverLane < 0;
96     myPositionOverLane = getLaneParents().front()->getShape().nearest_offset_to_point2D(newPosition, false);
97     if (storeNegative) {
98         myPositionOverLane -= getLaneParents().front()->getParentEdge().getNBEdge()->getFinalLength();
99     }
100     // Update geometry
101     updateGeometry(false);
102 }
103 
104 
105 void
commitGeometryMoving(GNEUndoList * undoList)106 GNEDetectorE1Instant::commitGeometryMoving(GNEUndoList* undoList) {
107     // commit new position allowing undo/redo
108     undoList->p_begin("position of " + getTagStr());
109     undoList->p_add(new GNEChange_Attribute(this, myViewNet->getNet(), SUMO_ATTR_POSITION, toString(myPositionOverLane), true, myMove.firstOriginalLanePosition));
110     undoList->p_end();
111 }
112 
113 
114 void
updateGeometry(bool updateGrid)115 GNEDetectorE1Instant::updateGeometry(bool updateGrid) {
116     // first check if object has to be removed from grid (SUMOTree)
117     if (updateGrid) {
118         myViewNet->getNet()->removeGLObjectFromGrid(this);
119     }
120 
121     // Clear all containers
122     myGeometry.clearGeometry();
123 
124     // obtain position over lane
125     myGeometry.shape.push_back(getPositionInView());
126 
127     // Obtain first position
128     Position f = myGeometry.shape[0] - Position(1, 0);
129 
130     // Obtain next position
131     Position s = myGeometry.shape[0] + Position(1, 0);
132 
133     // Save rotation (angle) of the vector constructed by points f and s
134     myGeometry.shapeRotations.push_back(getLaneParents().front()->getShape().rotationDegreeAtOffset(getGeometryPositionOverLane()) * -1);
135 
136     // Set block icon position
137     myBlockIcon.position = myGeometry.shape.getLineCenter();
138 
139     // Set offset of the block icon
140     myBlockIcon.offset = Position(-1, 0);
141 
142     // Set block icon rotation, and using their rotation for logo
143     myBlockIcon.setRotation(getLaneParents().front());
144 
145     // last step is to check if object has to be added into grid (SUMOTree) again
146     if (updateGrid) {
147         myViewNet->getNet()->addGLObjectIntoGrid(this);
148     }
149 }
150 
151 
152 void
drawGL(const GUIVisualizationSettings & s) const153 GNEDetectorE1Instant::drawGL(const GUIVisualizationSettings& s) const {
154     // get values
155     glPushName(getGlID());
156     double width = (double) 2.0 * s.scale;
157     glLineWidth(1.0);
158     const double exaggeration = s.addSize.getExaggeration(s, this);
159 
160     // set color
161     if (drawUsingSelectColor()) {
162         GLHelper::setColor(s.selectedAdditionalColor);
163     } else {
164         GLHelper::setColor(s.SUMO_color_E1Instant);
165     }
166     // draw shape
167     glPushMatrix();
168     glTranslated(0, 0, getType());
169     glTranslated(myGeometry.shape[0].x(), myGeometry.shape[0].y(), 0);
170     glRotated(myGeometry.shapeRotations[0], 0, 0, 1);
171     glScaled(exaggeration, exaggeration, 1);
172     glBegin(GL_QUADS);
173     glVertex2d(-1.0,  2);
174     glVertex2d(-1.0, -2);
175     glVertex2d(1.0, -2);
176     glVertex2d(1.0,  2);
177     glEnd();
178     glTranslated(0, 0, .01);
179     glBegin(GL_LINES);
180     glVertex2d(0, 2 - .1);
181     glVertex2d(0, -2 + .1);
182     glEnd();
183 
184     // outline if isn't being drawn for selecting
185     if ((width * exaggeration > 1) && !s.drawForSelecting) {
186         // set color
187         if (drawUsingSelectColor()) {
188             GLHelper::setColor(s.selectionColor);
189         } else {
190             GLHelper::setColor(RGBColor::WHITE);
191         }
192         glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
193         glBegin(GL_QUADS);
194         glVertex2f(-1.0,  2);
195         glVertex2f(-1.0, -2);
196         glVertex2f(1.0, -2);
197         glVertex2f(1.0,  2);
198         glEnd();
199         glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
200     }
201 
202     // position indicator if isn't being drawn for selecting
203     if ((width * exaggeration > 1) && !s.drawForSelecting) {
204         // set color
205         if (drawUsingSelectColor()) {
206             GLHelper::setColor(s.selectionColor);
207         } else {
208             GLHelper::setColor(RGBColor::WHITE);
209         }
210         glRotated(90, 0, 0, -1);
211         glBegin(GL_LINES);
212         glVertex2d(0, 1.7);
213         glVertex2d(0, -1.7);
214         glEnd();
215     }
216 
217     // Pop shape matrix
218     glPopMatrix();
219 
220     // Check if the distance is enought to draw details and isn't being drawn for selecting
221     if ((s.scale * exaggeration >= 10) && !s.drawForSelecting) {
222         // Push matrix
223         glPushMatrix();
224         // Traslate to center of detector
225         glTranslated(myGeometry.shape.getLineCenter().x(), myGeometry.shape.getLineCenter().y(), getType() + 0.1);
226         // Rotate depending of myBlockIcon.rotation
227         glRotated(myBlockIcon.rotation, 0, 0, -1);
228         //move to logo position
229         glTranslated(-1, 0, 0);
230         // draw E1 logo
231         if (drawUsingSelectColor()) {
232             GLHelper::drawText("E1", Position(), .1, 1.5, s.selectionColor);
233         } else {
234             GLHelper::drawText("E1", Position(), .1, 1.5, RGBColor::BLACK);
235         }
236         // pop matrix
237         glPopMatrix();
238         // Show Lock icon depending of the Edit mode
239         myBlockIcon.draw();
240     }
241 
242     // Finish draw if isn't being drawn for selecting
243     if (!s.drawForSelecting) {
244         drawName(getCenteringBoundary().getCenter(), s.scale, s.addName);
245     }
246     glPopName();
247 }
248 
249 
250 std::string
getAttribute(SumoXMLAttr key) const251 GNEDetectorE1Instant::getAttribute(SumoXMLAttr key) const {
252     switch (key) {
253         case SUMO_ATTR_ID:
254             return getAdditionalID();
255         case SUMO_ATTR_LANE:
256             return getLaneParents().front()->getID();
257         case SUMO_ATTR_POSITION:
258             return toString(myPositionOverLane);
259         case SUMO_ATTR_NAME:
260             return myAdditionalName;
261         case SUMO_ATTR_FILE:
262             return myFilename;
263         case SUMO_ATTR_VTYPES:
264             return myVehicleTypes;
265         case SUMO_ATTR_FRIENDLY_POS:
266             return toString(myFriendlyPosition);
267         case GNE_ATTR_BLOCK_MOVEMENT:
268             return toString(myBlockMovement);
269         case GNE_ATTR_SELECTED:
270             return toString(isAttributeCarrierSelected());
271         case GNE_ATTR_GENERIC:
272             return getGenericParametersStr();
273         default:
274             throw InvalidArgument(getTagStr() + " doesn't have an attribute of type '" + toString(key) + "'");
275     }
276 }
277 
278 
279 void
setAttribute(SumoXMLAttr key,const std::string & value,GNEUndoList * undoList)280 GNEDetectorE1Instant::setAttribute(SumoXMLAttr key, const std::string& value, GNEUndoList* undoList) {
281     if (value == getAttribute(key)) {
282         return; //avoid needless changes, later logic relies on the fact that attributes have changed
283     }
284     switch (key) {
285         case SUMO_ATTR_ID:
286         case SUMO_ATTR_LANE:
287         case SUMO_ATTR_POSITION:
288         case SUMO_ATTR_NAME:
289         case SUMO_ATTR_FILE:
290         case SUMO_ATTR_VTYPES:
291         case SUMO_ATTR_FRIENDLY_POS:
292         case GNE_ATTR_BLOCK_MOVEMENT:
293         case GNE_ATTR_SELECTED:
294         case GNE_ATTR_GENERIC:
295             undoList->p_add(new GNEChange_Attribute(this, myViewNet->getNet(), key, value));
296             break;
297         default:
298             throw InvalidArgument(getTagStr() + " doesn't have an attribute of type '" + toString(key) + "'");
299     }
300 
301 }
302 
303 
304 bool
isValid(SumoXMLAttr key,const std::string & value)305 GNEDetectorE1Instant::isValid(SumoXMLAttr key, const std::string& value) {
306     switch (key) {
307         case SUMO_ATTR_ID:
308             return isValidDetectorID(value);
309         case SUMO_ATTR_LANE:
310             if (myViewNet->getNet()->retrieveLane(value, false) != nullptr) {
311                 return true;
312             } else {
313                 return false;
314             }
315         case SUMO_ATTR_POSITION:
316             return canParse<double>(value) && fabs(parse<double>(value)) < getLaneParents().front()->getParentEdge().getNBEdge()->getFinalLength();
317         case SUMO_ATTR_NAME:
318             return SUMOXMLDefinitions::isValidAttribute(value);
319         case SUMO_ATTR_FILE:
320             return SUMOXMLDefinitions::isValidFilename(value);
321         case SUMO_ATTR_VTYPES:
322             if (value.empty()) {
323                 return true;
324             } else {
325                 return SUMOXMLDefinitions::isValidListOfTypeID(value);
326             }
327         case SUMO_ATTR_FRIENDLY_POS:
328             return canParse<bool>(value);
329         case GNE_ATTR_BLOCK_MOVEMENT:
330             return canParse<bool>(value);
331         case GNE_ATTR_SELECTED:
332             return canParse<bool>(value);
333         case GNE_ATTR_GENERIC:
334             return isGenericParametersValid(value);
335         default:
336             throw InvalidArgument(getTagStr() + " doesn't have an attribute of type '" + toString(key) + "'");
337     }
338 }
339 
340 // ===========================================================================
341 // private
342 // ===========================================================================
343 
344 void
setAttribute(SumoXMLAttr key,const std::string & value)345 GNEDetectorE1Instant::setAttribute(SumoXMLAttr key, const std::string& value) {
346     switch (key) {
347         case SUMO_ATTR_ID:
348             changeAdditionalID(value);
349             break;
350         case SUMO_ATTR_LANE:
351             changeLaneParents(this, value);
352             break;
353         case SUMO_ATTR_POSITION:
354             myPositionOverLane = parse<double>(value);
355             break;
356         case SUMO_ATTR_NAME:
357             myAdditionalName = value;
358             break;
359         case SUMO_ATTR_FILE:
360             myFilename = value;
361             break;
362         case SUMO_ATTR_VTYPES:
363             myVehicleTypes = value;
364             break;
365         case SUMO_ATTR_FRIENDLY_POS:
366             myFriendlyPosition = parse<bool>(value);
367             break;
368         case GNE_ATTR_BLOCK_MOVEMENT:
369             myBlockMovement = parse<bool>(value);
370             break;
371         case GNE_ATTR_SELECTED:
372             if (parse<bool>(value)) {
373                 selectAttributeCarrier();
374             } else {
375                 unselectAttributeCarrier();
376             }
377             break;
378         case GNE_ATTR_GENERIC:
379             setGenericParametersStr(value);
380             break;
381         default:
382             throw InvalidArgument(getTagStr() + " doesn't have an attribute of type '" + toString(key) + "'");
383     }
384     // check if updated attribute requieres update geometry
385     if (myTagProperty.hasAttribute(key) && myTagProperty.getAttributeProperties(key).requiereUpdateGeometry()) {
386         updateGeometry(true);
387     }
388 }
389 
390 /****************************************************************************/
391