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    GNECalibrator.cpp
11 /// @author  Pablo Alvarez Lopez
12 /// @date    Nov 2015
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/dialogs/GNECalibratorDialog.h>
27 #include <netedit/netelements/GNEEdge.h>
28 #include <netedit/netelements/GNELane.h>
29 #include <utils/gui/div/GLHelper.h>
30 #include <utils/gui/globjects/GLIncludes.h>
31 
32 #include "GNECalibrator.h"
33 
34 
35 // ===========================================================================
36 // member method definitions
37 // ===========================================================================
38 
GNECalibrator(const std::string & id,GNEViewNet * viewNet,GNEEdge * edge,double pos,double frequency,const std::string & name,const std::string & output,const std::string & routeprobe)39 GNECalibrator::GNECalibrator(const std::string& id, GNEViewNet* viewNet, GNEEdge* edge, double pos, double frequency, const std::string& name, const std::string& output, const std::string& routeprobe) :
40     GNEAdditional(id, viewNet, GLO_CALIBRATOR, SUMO_TAG_CALIBRATOR, name, false, {
41     edge
42 }, {}, {}, {}, {}, {}, {}, {}, {}, {}),
43 myPositionOverLane(pos),
44 myFrequency(frequency),
45 myOutput(output),
46 myRouteProbe(routeprobe) {
47 }
48 
49 
GNECalibrator(const std::string & id,GNEViewNet * viewNet,GNELane * lane,double pos,double frequency,const std::string & name,const std::string & output,const std::string & routeprobe)50 GNECalibrator::GNECalibrator(const std::string& id, GNEViewNet* viewNet, GNELane* lane, double pos, double frequency, const std::string& name, const std::string& output, const std::string& routeprobe) :
51     GNEAdditional(id, viewNet, GLO_CALIBRATOR, SUMO_TAG_LANECALIBRATOR, name, false, {}, {lane}, {}, {}, {}, {}, {}, {}, {}, {}),
52 myPositionOverLane(pos),
53 myFrequency(frequency),
54 myOutput(output),
55 myRouteProbe(routeprobe) {
56 }
57 
58 
~GNECalibrator()59 GNECalibrator::~GNECalibrator() {}
60 
61 
62 void
moveGeometry(const Position &)63 GNECalibrator::moveGeometry(const Position&) {
64     // This additional cannot be moved
65 }
66 
67 
68 void
commitGeometryMoving(GNEUndoList *)69 GNECalibrator::commitGeometryMoving(GNEUndoList*) {
70     // This additional cannot be moved
71 }
72 
73 
74 void
updateGeometry(bool updateGrid)75 GNECalibrator::updateGeometry(bool updateGrid) {
76     // first check if object has to be removed from grid (SUMOTree)
77     if (updateGrid) {
78         myViewNet->getNet()->removeGLObjectFromGrid(this);
79     }
80 
81     // Clear all containers
82     myGeometry.clearGeometry();
83 
84     // get shape depending of we have a edge or a lane
85     if (getLaneParents().size() > 0) {
86         // Get shape of lane parent
87         myGeometry.shape.push_back(getLaneParents().front()->getShape().positionAtOffset(myPositionOverLane));
88         // Save rotation (angle) of the vector constructed by points f and s
89         myGeometry.shapeRotations.push_back(getLaneParents().front()->getShape().rotationDegreeAtOffset(myPositionOverLane) * -1);
90     } else if (getEdgeParents().size() > 0) {
91         for (auto i : getEdgeParents().front()->getLanes()) {
92             // Get shape of lane parent
93             myGeometry.shape.push_back(i->getShape().positionAtOffset(myPositionOverLane));
94             // Save rotation (angle) of the vector constructed by points f and s
95             myGeometry.shapeRotations.push_back(getEdgeParents().front()->getLanes().at(0)->getShape().rotationDegreeAtOffset(myPositionOverLane) * -1);
96         }
97     } else {
98         throw ProcessError("Both myEdge and myLane aren't defined");
99     }
100 
101     // last step is to check if object has to be added into grid (SUMOTree) again
102     if (updateGrid) {
103         myViewNet->getNet()->addGLObjectIntoGrid(this);
104     }
105 }
106 
107 
108 Position
getPositionInView() const109 GNECalibrator::getPositionInView() const {
110     PositionVector shape = (getLaneParents().size() > 0) ? getLaneParents().front()->getShape() : getEdgeParents().front()->getLanes().at(0)->getShape();
111     if (myPositionOverLane < 0) {
112         return shape.front();
113     } else if (myPositionOverLane > shape.length()) {
114         return shape.back();
115     } else {
116         return shape.positionAtOffset(myPositionOverLane);
117     }
118 }
119 
120 
121 std::string
getParentName() const122 GNECalibrator::getParentName() const {
123     // get parent name depending of we have a edge or a lane
124     if (getLaneParents().size() > 0) {
125         return getLaneParents().front()->getMicrosimID();
126     } else if (getEdgeParents().size() > 0) {
127         return getEdgeParents().front()->getLanes().at(0)->getMicrosimID();
128     } else {
129         throw ProcessError("Both myEdge and myLane aren't defined");
130     }
131 }
132 
133 
134 void
drawGL(const GUIVisualizationSettings & s) const135 GNECalibrator::drawGL(const GUIVisualizationSettings& s) const {
136     // get values
137     glPushName(getGlID());
138     glLineWidth(1.0);
139     const double exaggeration = s.addSize.getExaggeration(s, this);
140 
141     // iterate over every Calibrator symbol
142     for (int i = 0; i < (int)myGeometry.shape.size(); ++i) {
143         const Position& pos = myGeometry.shape[i];
144         double rot = myGeometry.shapeRotations[i];
145         glPushMatrix();
146         glTranslated(pos.x(), pos.y(), getType());
147         glRotated(rot, 0, 0, 1);
148         glTranslated(0, 0, getType());
149         glScaled(exaggeration, exaggeration, 1);
150         glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
151 
152         if (drawUsingSelectColor()) {
153             GLHelper::setColor(s.selectedAdditionalColor);
154         } else {
155             GLHelper::setColor(RGBColor(255, 204, 0));
156         }
157         // base
158         glBegin(GL_TRIANGLES);
159         glVertex2d(0 - 1.4, 0);
160         glVertex2d(0 - 1.4, 6);
161         glVertex2d(0 + 1.4, 6);
162         glVertex2d(0 + 1.4, 0);
163         glVertex2d(0 - 1.4, 0);
164         glVertex2d(0 + 1.4, 6);
165         glEnd();
166 
167         // draw text if isn't being drawn for selecting
168         if ((s.scale * exaggeration >= 1.) && !s.drawForSelecting) {
169             // set color depending of selection status
170             RGBColor textColor = drawUsingSelectColor() ? s.selectionColor : RGBColor::BLACK;
171             // draw "C"
172             GLHelper::drawText("C", Position(0, 1.5), 0.1, 3, textColor, 180);
173             // draw "edge" or "lane "
174             if (getLaneParents().size() > 0) {
175                 GLHelper::drawText("lane", Position(0, 3), .1, 1, textColor, 180);
176             } else if (getEdgeParents().size() > 0) {
177                 GLHelper::drawText("edge", Position(0, 3), .1, 1, textColor, 180);
178             } else {
179                 throw ProcessError("Both myEdge and myLane aren't defined");
180             }
181         }
182         glPopMatrix();
183         // check if dotted contour has to be drawn
184         if (!s.drawForSelecting && (myViewNet->getDottedAC() == this)) {
185             GLHelper::drawShapeDottedContour(getType(), pos, 2.8, 6, rot, 0, 3);
186         }
187     }
188     // draw name
189     drawName(getCenteringBoundary().getCenter(), s.scale, s.addName);
190 
191     // pop name
192     glPopName();
193 }
194 
195 
196 void
openAdditionalDialog()197 GNECalibrator::openAdditionalDialog() {
198     // Open calibrator dialog
199     GNECalibratorDialog calibratorDialog(this);
200 }
201 
202 
203 std::string
getAttribute(SumoXMLAttr key) const204 GNECalibrator::getAttribute(SumoXMLAttr key) const {
205     switch (key) {
206         case SUMO_ATTR_ID:
207             return getAdditionalID();
208         case SUMO_ATTR_EDGE:
209             return getEdgeParents().front()->getID();
210         case SUMO_ATTR_LANE:
211             return getLaneParents().front()->getID();
212         case SUMO_ATTR_POSITION:
213             return toString(myPositionOverLane);
214         case SUMO_ATTR_FREQUENCY:
215             return toString(myFrequency);
216         case SUMO_ATTR_NAME:
217             return myAdditionalName;
218         case SUMO_ATTR_OUTPUT:
219             return myOutput;
220         case SUMO_ATTR_ROUTEPROBE:
221             return myRouteProbe;
222         case GNE_ATTR_SELECTED:
223             return toString(isAttributeCarrierSelected());
224         case GNE_ATTR_GENERIC:
225             return getGenericParametersStr();
226         default:
227             throw InvalidArgument(getTagStr() + " doesn't have an attribute of type '" + toString(key) + "'");
228     }
229 }
230 
231 
232 void
setAttribute(SumoXMLAttr key,const std::string & value,GNEUndoList * undoList)233 GNECalibrator::setAttribute(SumoXMLAttr key, const std::string& value, GNEUndoList* undoList) {
234     if (value == getAttribute(key)) {
235         return; //avoid needless changes, later logic relies on the fact that attributes have changed
236     }
237     switch (key) {
238         case SUMO_ATTR_ID:
239         case SUMO_ATTR_EDGE:
240         case SUMO_ATTR_LANE:
241         case SUMO_ATTR_POSITION:
242         case SUMO_ATTR_FREQUENCY:
243         case SUMO_ATTR_NAME:
244         case SUMO_ATTR_OUTPUT:
245         case SUMO_ATTR_ROUTEPROBE:
246         case GNE_ATTR_SELECTED:
247         case GNE_ATTR_GENERIC:
248             undoList->p_add(new GNEChange_Attribute(this, myViewNet->getNet(), key, value));
249             break;
250         default:
251             throw InvalidArgument(getTagStr() + " doesn't have an attribute of type '" + toString(key) + "'");
252     }
253 
254 }
255 
256 
257 bool
isValid(SumoXMLAttr key,const std::string & value)258 GNECalibrator::isValid(SumoXMLAttr key, const std::string& value) {
259     switch (key) {
260         case SUMO_ATTR_ID:
261             return isValidAdditionalID(value);
262         case SUMO_ATTR_EDGE:
263             if (myViewNet->getNet()->retrieveEdge(value, false) != nullptr) {
264                 return true;
265             } else {
266                 return false;
267             }
268         case SUMO_ATTR_LANE:
269             if (myViewNet->getNet()->retrieveLane(value, false) != nullptr) {
270                 return true;
271             } else {
272                 return false;
273             }
274         case SUMO_ATTR_POSITION:
275             if (canParse<double>(value)) {
276                 // obtain position and check if is valid
277                 double newPosition = parse<double>(value);
278                 PositionVector shape = (getLaneParents().size() > 0) ? getLaneParents().front()->getShape() : getEdgeParents().front()->getLanes().at(0)->getShape();
279                 if ((newPosition < 0) || (newPosition > shape.length())) {
280                     return false;
281                 } else {
282                     return true;
283                 }
284             } else {
285                 return false;
286             }
287         case SUMO_ATTR_FREQUENCY:
288             return (canParse<double>(value) && parse<double>(value) >= 0);
289         case SUMO_ATTR_NAME:
290             return SUMOXMLDefinitions::isValidAttribute(value);
291         case SUMO_ATTR_OUTPUT:
292             return SUMOXMLDefinitions::isValidFilename(value);
293         case SUMO_ATTR_ROUTEPROBE:
294             return SUMOXMLDefinitions::isValidNetID(value);
295         case GNE_ATTR_SELECTED:
296             return canParse<bool>(value);
297         case GNE_ATTR_GENERIC:
298             return isGenericParametersValid(value);
299         default:
300             throw InvalidArgument(getTagStr() + " doesn't have an attribute of type '" + toString(key) + "'");
301     }
302 }
303 
304 
305 std::string
getPopUpID() const306 GNECalibrator::getPopUpID() const {
307     return getTagStr() + ": " + getID();
308 }
309 
310 
311 std::string
getHierarchyName() const312 GNECalibrator::getHierarchyName() const {
313     return getTagStr();
314 }
315 
316 // ===========================================================================
317 // private
318 // ===========================================================================
319 
320 void
setAttribute(SumoXMLAttr key,const std::string & value)321 GNECalibrator::setAttribute(SumoXMLAttr key, const std::string& value) {
322     switch (key) {
323         case SUMO_ATTR_ID:
324             changeAdditionalID(value);
325             break;
326         case SUMO_ATTR_EDGE:
327             changeEdgeParents(this, value);
328             break;
329         case SUMO_ATTR_LANE:
330             changeLaneParents(this, value);
331             break;
332         case SUMO_ATTR_POSITION:
333             myPositionOverLane = parse<double>(value);
334             break;
335         case SUMO_ATTR_FREQUENCY:
336             myFrequency = parse<double>(value);
337             break;
338         case SUMO_ATTR_NAME:
339             myAdditionalName = value;
340             break;
341         case SUMO_ATTR_OUTPUT:
342             myOutput = value;
343             break;
344         case SUMO_ATTR_ROUTEPROBE:
345             myRouteProbe = value;
346             break;
347         case GNE_ATTR_SELECTED:
348             if (parse<bool>(value)) {
349                 selectAttributeCarrier();
350             } else {
351                 unselectAttributeCarrier();
352             }
353             break;
354         case GNE_ATTR_GENERIC:
355             setGenericParametersStr(value);
356             break;
357         default:
358             throw InvalidArgument(getTagStr() + " doesn't have an attribute of type '" + toString(key) + "'");
359     }
360     // check if updated attribute requieres update geometry
361     if (myTagProperty.hasAttribute(key) && myTagProperty.getAttributeProperties(key).requiereUpdateGeometry()) {
362         updateGeometry(true);
363     }
364 }
365 
366 /****************************************************************************/
367