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 GNEDetectorE1.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/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 "GNEDetectorE1.h"
32 #include "GNEAdditionalHandler.h"
33
34
35 // ===========================================================================
36 // member method definitions
37 // ===========================================================================
38
GNEDetectorE1(const std::string & id,GNELane * lane,GNEViewNet * viewNet,double pos,double freq,const std::string & filename,const std::string & vehicleTypes,const std::string & name,bool friendlyPos,bool blockMovement)39 GNEDetectorE1::GNEDetectorE1(const std::string& id, GNELane* lane, GNEViewNet* viewNet, double pos, double freq, const std::string& filename, const std::string& vehicleTypes, const std::string& name, bool friendlyPos, bool blockMovement) :
40 GNEDetector(id, viewNet, GLO_E1DETECTOR, SUMO_TAG_E1DETECTOR, pos, freq, filename, vehicleTypes, name, friendlyPos, blockMovement, {
41 lane
42 }) {
43 }
44
45
~GNEDetectorE1()46 GNEDetectorE1::~GNEDetectorE1() {
47 }
48
49
50 bool
isAdditionalValid() const51 GNEDetectorE1::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 GNEDetectorE1::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 GNEDetectorE1::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 GNEDetectorE1::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 GNEDetectorE1::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 GNEDetectorE1::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 GNEDetectorE1::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_E1);
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
247 // check if dotted contour has to be drawn
248 if (!s.drawForSelecting && (myViewNet->getDottedAC() == this)) {
249 GLHelper::drawShapeDottedContour(getType(), myGeometry.shape[0], 2, 4, myGeometry.shapeRotations[0]);
250 }
251
252 // pop name
253 glPopName();
254 }
255
256
257 std::string
getAttribute(SumoXMLAttr key) const258 GNEDetectorE1::getAttribute(SumoXMLAttr key) const {
259 switch (key) {
260 case SUMO_ATTR_ID:
261 return getAdditionalID();
262 case SUMO_ATTR_LANE:
263 return getLaneParents().front()->getID();
264 case SUMO_ATTR_POSITION:
265 return toString(myPositionOverLane);
266 case SUMO_ATTR_FREQUENCY:
267 return toString(myFreq);
268 case SUMO_ATTR_NAME:
269 return myAdditionalName;
270 case SUMO_ATTR_FILE:
271 return myFilename;
272 case SUMO_ATTR_VTYPES:
273 return myVehicleTypes;
274 case SUMO_ATTR_FRIENDLY_POS:
275 return toString(myFriendlyPosition);
276 case GNE_ATTR_BLOCK_MOVEMENT:
277 return toString(myBlockMovement);
278 case GNE_ATTR_SELECTED:
279 return toString(isAttributeCarrierSelected());
280 case GNE_ATTR_GENERIC:
281 return getGenericParametersStr();
282 default:
283 throw InvalidArgument(getTagStr() + " doesn't have an attribute of type '" + toString(key) + "'");
284 }
285 }
286
287
288 void
setAttribute(SumoXMLAttr key,const std::string & value,GNEUndoList * undoList)289 GNEDetectorE1::setAttribute(SumoXMLAttr key, const std::string& value, GNEUndoList* undoList) {
290 if (value == getAttribute(key)) {
291 return; //avoid needless changes, later logic relies on the fact that attributes have changed
292 }
293 switch (key) {
294 case SUMO_ATTR_ID:
295 case SUMO_ATTR_LANE:
296 case SUMO_ATTR_POSITION:
297 case SUMO_ATTR_FREQUENCY:
298 case SUMO_ATTR_NAME:
299 case SUMO_ATTR_FILE:
300 case SUMO_ATTR_VTYPES:
301 case SUMO_ATTR_FRIENDLY_POS:
302 case GNE_ATTR_BLOCK_MOVEMENT:
303 case GNE_ATTR_SELECTED:
304 case GNE_ATTR_GENERIC:
305 undoList->p_add(new GNEChange_Attribute(this, myViewNet->getNet(), key, value));
306 break;
307 default:
308 throw InvalidArgument(getTagStr() + " doesn't have an attribute of type '" + toString(key) + "'");
309 }
310
311 }
312
313
314 bool
isValid(SumoXMLAttr key,const std::string & value)315 GNEDetectorE1::isValid(SumoXMLAttr key, const std::string& value) {
316 switch (key) {
317 case SUMO_ATTR_ID:
318 return isValidDetectorID(value);
319 case SUMO_ATTR_LANE:
320 if (myViewNet->getNet()->retrieveLane(value, false) != nullptr) {
321 return true;
322 } else {
323 return false;
324 }
325 case SUMO_ATTR_POSITION:
326 return canParse<double>(value) && fabs(parse<double>(value)) < getLaneParents().front()->getParentEdge().getNBEdge()->getFinalLength();
327 case SUMO_ATTR_FREQUENCY:
328 return (canParse<double>(value) && (parse<double>(value) >= 0));
329 case SUMO_ATTR_NAME:
330 return SUMOXMLDefinitions::isValidAttribute(value);
331 case SUMO_ATTR_FILE:
332 return SUMOXMLDefinitions::isValidFilename(value);
333 case SUMO_ATTR_VTYPES:
334 if (value.empty()) {
335 return true;
336 } else {
337 return SUMOXMLDefinitions::isValidListOfTypeID(value);
338 }
339 case SUMO_ATTR_FRIENDLY_POS:
340 return canParse<bool>(value);
341 case GNE_ATTR_BLOCK_MOVEMENT:
342 return canParse<bool>(value);
343 case GNE_ATTR_SELECTED:
344 return canParse<bool>(value);
345 case GNE_ATTR_GENERIC:
346 return isGenericParametersValid(value);
347 default:
348 throw InvalidArgument(getTagStr() + " doesn't have an attribute of type '" + toString(key) + "'");
349 }
350 }
351
352 // ===========================================================================
353 // private
354 // ===========================================================================
355
356 void
setAttribute(SumoXMLAttr key,const std::string & value)357 GNEDetectorE1::setAttribute(SumoXMLAttr key, const std::string& value) {
358 switch (key) {
359 case SUMO_ATTR_ID:
360 changeAdditionalID(value);
361 break;
362 case SUMO_ATTR_LANE:
363 changeLaneParents(this, value);
364 break;
365 case SUMO_ATTR_POSITION:
366 myPositionOverLane = parse<double>(value);
367 break;
368 case SUMO_ATTR_FREQUENCY:
369 myFreq = parse<double>(value);
370 break;
371 case SUMO_ATTR_FILE:
372 myFilename = value;
373 break;
374 case SUMO_ATTR_NAME:
375 myAdditionalName = value;
376 break;
377 case SUMO_ATTR_VTYPES:
378 myVehicleTypes = value;
379 break;
380 case SUMO_ATTR_FRIENDLY_POS:
381 myFriendlyPosition = parse<bool>(value);
382 break;
383 case GNE_ATTR_BLOCK_MOVEMENT:
384 myBlockMovement = parse<bool>(value);
385 break;
386 case GNE_ATTR_SELECTED:
387 if (parse<bool>(value)) {
388 selectAttributeCarrier();
389 } else {
390 unselectAttributeCarrier();
391 }
392 break;
393 case GNE_ATTR_GENERIC:
394 setGenericParametersStr(value);
395 break;
396 default:
397 throw InvalidArgument(getTagStr() + " doesn't have an attribute of type '" + toString(key) + "'");
398 }
399 // check if updated attribute requieres update geometry
400 if (myTagProperty.hasAttribute(key) && myTagProperty.getAttributeProperties(key).requiereUpdateGeometry()) {
401 updateGeometry(true);
402 }
403 }
404
405 /****************************************************************************/
406