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