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