Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
eclipse
GitHub Repository: eclipse/sumo
Path: blob/main/src/netedit/elements/additional/GNEPOI.cpp
169684 views
1
/****************************************************************************/
2
// Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
3
// Copyright (C) 2001-2025 German Aerospace Center (DLR) and others.
4
// This program and the accompanying materials are made available under the
5
// terms of the Eclipse Public License 2.0 which is available at
6
// https://www.eclipse.org/legal/epl-2.0/
7
// This Source Code may also be made available under the following Secondary
8
// Licenses when the conditions for such availability set forth in the Eclipse
9
// Public License 2.0 are satisfied: GNU General Public License, version 2
10
// or later which is available at
11
// https://www.gnu.org/licenses/old-licenses/gpl-2.0-standalone.html
12
// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-or-later
13
/****************************************************************************/
14
/// @file GNEPOI.cpp
15
/// @author Pablo Alvarez Lopez
16
/// @date Jun 2017
17
///
18
// A class for visualizing and editing POIS in netedit (adapted from
19
// GUIPointOfInterest and NLHandler)
20
/****************************************************************************/
21
#include <config.h>
22
23
#include <netedit/GNENet.h>
24
#include <netedit/GNETagProperties.h>
25
#include <netedit/GNEUndoList.h>
26
#include <netedit/GNEViewNet.h>
27
#include <netedit/GNEViewParent.h>
28
#include <netedit/changes/GNEChange_Attribute.h>
29
#include <netedit/frames/common/GNEMoveFrame.h>
30
#include <utils/gui/div/GLHelper.h>
31
#include <utils/gui/div/GUIDesigns.h>
32
#include <utils/gui/div/GUIParameterTableWindow.h>
33
#include <utils/gui/globjects/GLIncludes.h>
34
#include <utils/gui/globjects/GUIGLObjectPopupMenu.h>
35
#include <utils/gui/globjects/GUIPointOfInterest.h>
36
#include <utils/gui/div/GUIGlobalViewObjectsHandler.h>
37
#include <utils/options/OptionsCont.h>
38
#include <utils/xml/NamespaceIDs.h>
39
40
#include "GNEPOI.h"
41
#include "GNEAdditionalHandler.h"
42
43
// ===========================================================================
44
// method definitions
45
// ===========================================================================
46
47
GNEPOI::GNEPOI(SumoXMLTag tag, GNENet* net) :
48
PointOfInterest("", "", RGBColor::BLACK, Position(0, 0), false, "", 0, false, 0, SUMOXMLDefinitions::POIIcons.getString(POIIcon::NONE),
49
0, 0, "", 0, 0, "", Parameterised::Map()),
50
GNEAdditional("", net, "", tag, "") {
51
}
52
53
54
GNEPOI::GNEPOI(const std::string& id, GNENet* net, const std::string& filename, const std::string& type, const RGBColor& color, const double xLon, const double yLat,
55
const bool geo, const std::string& icon, const double layer, const double angle, const std::string& imgFile, const double width, const double height,
56
const std::string& name, const Parameterised::Map& parameters) :
57
PointOfInterest(id, type, color, Position(xLon, yLat), geo, "", 0, false, 0, icon, layer, angle, imgFile, width, height, name, parameters),
58
GNEAdditional(id, net, filename, geo ? GNE_TAG_POIGEO : SUMO_TAG_POI, "") {
59
// update position depending of GEO
60
if (geo) {
61
Position cartesian(x(), y());
62
GeoConvHelper::getFinal().x2cartesian_const(cartesian);
63
set(cartesian.x(), cartesian.y());
64
}
65
// update geometry (needed for adjust myShapeWidth and myShapeHeight)
66
updateGeometry();
67
// update centering boundary without updating grid
68
updateCenteringBoundary(false);
69
}
70
71
72
GNEPOI::GNEPOI(const std::string& id, GNENet* net, const std::string& filename, const std::string& type, const RGBColor& color, GNELane* lane, const double posOverLane,
73
const bool friendlyPos, const double posLat, const std::string& icon, const double layer, const double angle, const std::string& imgFile, const double width,
74
const double height, const std::string& name, const Parameterised::Map& parameters) :
75
PointOfInterest(id, type, color, Position(), false, lane->getID(), posOverLane, friendlyPos, posLat, icon, layer, angle, imgFile, width, height, name, parameters),
76
GNEAdditional(id, net, filename, GNE_TAG_POILANE, "") {
77
// set parents
78
setParent<GNELane*>(lane);
79
// update geometry (needed for adjust myShapeWidth and myShapeHeight)
80
updateGeometry();
81
// update centering boundary without updating grid
82
updateCenteringBoundary(false);
83
}
84
85
86
GNEPOI::~GNEPOI() {}
87
88
89
GNEMoveOperation*
90
GNEPOI::getMoveOperation() {
91
if (myNet->getViewNet()->getEditModes().isCurrentSupermodeNetwork() &&
92
(myNet->getViewNet()->getEditModes().networkEditMode == NetworkEditMode::NETWORK_MOVE) &&
93
myNet->getViewNet()->getMouseButtonKeyPressed().shiftKeyPressed()) {
94
// get snap radius
95
const double snapRadius = myNet->getViewNet()->getVisualisationSettings().neteditSizeSettings.additionalGeometryPointRadius;
96
const double snapRadiusSquared = snapRadius * snapRadius;
97
// get mouse position
98
const Position mousePosition = myNet->getViewNet()->getPositionInformation();
99
// check if we're editing width or height
100
if ((myShapeWidth.size() == 0) || (myShapeHeight.size() == 0)) {
101
return nullptr;
102
} else if (myShapeHeight.front().distanceSquaredTo2D(mousePosition) <= snapRadiusSquared) {
103
// edit height
104
return new GNEMoveOperation(this, myShapeHeight, true, GNEMoveOperation::OperationType::HEIGHT);
105
} else if (myShapeHeight.back().distanceSquaredTo2D(mousePosition) <= snapRadiusSquared) {
106
// edit height
107
return new GNEMoveOperation(this, myShapeHeight, false, GNEMoveOperation::OperationType::HEIGHT);
108
} else if (myShapeWidth.front().distanceSquaredTo2D(mousePosition) <= snapRadiusSquared) {
109
// edit width
110
return new GNEMoveOperation(this, myShapeWidth, true, GNEMoveOperation::OperationType::WIDTH);
111
} else if (myShapeWidth.back().distanceSquaredTo2D(mousePosition) <= snapRadiusSquared) {
112
// edit width
113
return new GNEMoveOperation(this, myShapeWidth, false, GNEMoveOperation::OperationType::WIDTH);
114
} else {
115
return nullptr;
116
}
117
} else if (getTagProperty()->getTag() == GNE_TAG_POILANE) {
118
// return move operation for POI placed over lane
119
return new GNEMoveOperation(this, getParentLanes().front(), myPosOverLane,
120
myNet->getViewNet()->getViewParent()->getMoveFrame()->getCommonMoveOptions()->getAllowChangeLane());
121
} else {
122
// return move operation for a position in view
123
return new GNEMoveOperation(this, *this);
124
}
125
}
126
127
128
void
129
GNEPOI::removeGeometryPoint(const Position /*clickedPosition*/, GNEUndoList* /*undoList*/) {
130
// nothing to remove
131
}
132
133
134
std::string
135
GNEPOI::generateChildID(SumoXMLTag /*childTag*/) {
136
return "";
137
}
138
139
140
CommonXMLStructure::SumoBaseObject*
141
GNEPOI::getSumoBaseObject() const {
142
CommonXMLStructure::SumoBaseObject* POIBaseObject = new CommonXMLStructure::SumoBaseObject(nullptr);
143
POIBaseObject->setTag(SUMO_TAG_POI);
144
// fill attributes
145
POIBaseObject->addStringAttribute(SUMO_ATTR_ID, myID);
146
POIBaseObject->addColorAttribute(SUMO_ATTR_COLOR, getShapeColor());
147
POIBaseObject->addStringAttribute(SUMO_ATTR_TYPE, getShapeType());
148
POIBaseObject->addStringAttribute(SUMO_ATTR_ICON, getIconStr());
149
POIBaseObject->addDoubleAttribute(SUMO_ATTR_LAYER, getShapeLayer());
150
POIBaseObject->addStringAttribute(SUMO_ATTR_IMGFILE, getShapeImgFile());
151
POIBaseObject->addDoubleAttribute(SUMO_ATTR_WIDTH, getWidth());
152
POIBaseObject->addDoubleAttribute(SUMO_ATTR_HEIGHT, getHeight());
153
POIBaseObject->addDoubleAttribute(SUMO_ATTR_ANGLE, getShapeNaviDegree());
154
POIBaseObject->addStringAttribute(SUMO_ATTR_NAME, getShapeName());
155
return POIBaseObject;
156
}
157
158
159
void
160
GNEPOI::writeAdditional(OutputDevice& device) const {
161
if (getParentLanes().size() > 0) {
162
// obtain fixed position over lane
163
double fixedPositionOverLane = myPosOverLane > getParentLanes().at(0)->getLaneShape().length() ? getParentLanes().at(0)->getLaneShape().length() : myPosOverLane < 0 ? 0 : myPosOverLane;
164
// write POILane using POI::writeXML
165
writeXML(device, false, 0, getParentLanes().at(0)->getID(), fixedPositionOverLane, myFriendlyPos, myPosLat);
166
} else {
167
writeXML(device, myGeo);
168
}
169
}
170
171
172
bool
173
GNEPOI::isAdditionalValid() const {
174
// only for POIS over lanes
175
if (getParentLanes().size() == 0) {
176
return true;
177
} else if (getFriendlyPos()) {
178
// with friendly position enabled position is "always fixed"
179
return true;
180
} else {
181
return fabs(myPosOverLane) <= getParentLanes().front()->getParentEdge()->getNBEdge()->getFinalLength();
182
}
183
}
184
185
186
std::string
187
GNEPOI::getAdditionalProblem() const {
188
// only for POIS over lanes
189
if (getParentLanes().size() > 0) {
190
// obtain final length
191
const double len = getParentLanes().front()->getParentEdge()->getNBEdge()->getFinalLength();
192
// check if detector has a problem
193
if (GNEAdditionalHandler::checkLanePosition(myPosOverLane, 0, len, getFriendlyPos())) {
194
return "";
195
} else {
196
// declare variable for error position
197
std::string errorPosition;
198
// check positions over lane
199
if (myPosOverLane < 0) {
200
errorPosition = (toString(SUMO_ATTR_POSITION) + " < 0");
201
}
202
if (myPosOverLane > len) {
203
errorPosition = (toString(SUMO_ATTR_POSITION) + TL(" > lanes's length"));
204
}
205
return errorPosition;
206
}
207
} else {
208
return "";
209
}
210
}
211
212
213
void
214
GNEPOI::fixAdditionalProblem() {
215
// only for POIS over lanes
216
if (getParentLanes().size() > 0) {
217
// declare new position
218
double newPositionOverLane = myPosOverLane;
219
// declare new length (but unsed in this context)
220
double length = 0;
221
// fix pos and length with fixLanePosition
222
GNEAdditionalHandler::fixLanePosition(newPositionOverLane, length, getParentLanes().front()->getParentEdge()->getNBEdge()->getFinalLength());
223
// set new position
224
setAttribute(SUMO_ATTR_POSITION, toString(newPositionOverLane), myNet->getViewNet()->getUndoList());
225
}
226
}
227
228
229
void
230
GNEPOI::updateGeometry() {
231
// set position
232
if (getParentLanes().size() > 0) {
233
// obtain fixed position over lane
234
double fixedPositionOverLane = myPosOverLane > getParentLanes().at(0)->getLaneShapeLength() ? getParentLanes().at(0)->getLaneShapeLength() : myPosOverLane < 0 ? 0 : myPosOverLane;
235
// set new position regarding to lane
236
set(getParentLanes().at(0)->getLaneShape().positionAtOffset(fixedPositionOverLane * getParentLanes().at(0)->getLengthGeometryFactor(), -myPosLat));
237
}
238
// check if update width and height shapes
239
if ((getWidth() > 0) && (getHeight() > 0)) {
240
// calculate shape length
241
myShapeHeight.clear();
242
myShapeHeight.push_back(Position(0, getHeight() * -0.5));
243
myShapeHeight.push_back(Position(0, getHeight() * 0.5));
244
// move
245
myShapeHeight.add(*this);
246
// calculate shape width
247
PositionVector leftShape = myShapeHeight;
248
leftShape.move2side(getWidth() * -0.5);
249
PositionVector rightShape = myShapeHeight;
250
rightShape.move2side(getWidth() * 0.5);
251
myShapeWidth = {leftShape.getCentroid(), rightShape.getCentroid()};
252
}
253
}
254
255
256
Position
257
GNEPOI::getPositionInView() const {
258
return *this;
259
}
260
261
262
double
263
GNEPOI::getExaggeration(const GUIVisualizationSettings& s) const {
264
return s.poiSize.getExaggeration(s, this);
265
}
266
267
268
void
269
GNEPOI::updateCenteringBoundary(const bool updateGrid) {
270
// Remove object from net
271
if (updateGrid) {
272
myNet->removeGLObjectFromGrid(this);
273
}
274
// reset boundary
275
myAdditionalBoundary.reset();
276
// add position (this POI)
277
myAdditionalBoundary.add(*this);
278
// grow boundary
279
myAdditionalBoundary.grow(5 + std::max(getWidth() * 0.5, getHeight() * 0.5));
280
// add object into net
281
if (updateGrid) {
282
myNet->addGLObjectIntoGrid(this);
283
}
284
}
285
286
287
void
288
GNEPOI::splitEdgeGeometry(const double /*splitPosition*/, const GNENetworkElement* /*originalElement*/, const GNENetworkElement* /*newElement*/, GNEUndoList* /*undoList*/) {
289
// nothing to split
290
}
291
292
293
GUIGlID
294
GNEPOI::getGlID() const {
295
return GUIGlObject::getGlID();
296
}
297
298
299
bool
300
GNEPOI::checkDrawMoveContour() const {
301
// get edit modes
302
const auto& editModes = myNet->getViewNet()->getEditModes();
303
// check if we're in move mode
304
if (!myNet->getViewNet()->isCurrentlyMovingElements() && editModes.isCurrentSupermodeNetwork() &&
305
!myNet->getViewNet()->getEditNetworkElementShapes().getEditedNetworkElement() &&
306
(editModes.networkEditMode == NetworkEditMode::NETWORK_MOVE) && myNet->getViewNet()->checkOverLockedElement(this, mySelected)) {
307
// only move the first element
308
return myNet->getViewNet()->getViewObjectsSelector().getGUIGlObjectFront() == this;
309
} else {
310
return false;
311
}
312
}
313
314
315
std::string
316
GNEPOI::getParentName() const {
317
if (getParentLanes().size() > 0) {
318
return getParentLanes().front()->getID();
319
} else {
320
return myNet->getMicrosimID();
321
}
322
}
323
324
325
GUIGLObjectPopupMenu*
326
GNEPOI::getPopUpMenu(GUIMainWindow& app, GUISUMOAbstractView& parent) {
327
// create popup
328
GUIGLObjectPopupMenu* ret = new GUIGLObjectPopupMenu(app, parent, this);
329
// build common options
330
buildPopUpMenuCommonOptions(ret, app, myNet->getViewNet(), myTagProperty->getTag(), mySelected);
331
// specific of non juPedSim polygons
332
if (!myTagProperty->isJuPedSimElement()) {
333
// continue depending of lane number
334
if (getParentLanes().size() > 0) {
335
// add option for convert to GNEPOI
336
GUIDesigns::buildFXMenuCommand(ret, TL("Release from lane"), GUIIconSubSys::getIcon(GUIIcon::LANE), &parent, MID_GNE_POI_TRANSFORM);
337
return ret;
338
} else {
339
// add option for convert to GNEPOI
340
GUIDesigns::buildFXMenuCommand(ret, TL("Attach to nearest lane"), GUIIconSubSys::getIcon(GUIIcon::LANE), &parent, MID_GNE_POI_TRANSFORM);
341
}
342
}
343
return ret;
344
}
345
346
347
void
348
GNEPOI::drawGL(const GUIVisualizationSettings& s) const {
349
// first check if POI can be drawn
350
if (myNet->getViewNet()->getDemandViewOptions().showShapes() &&
351
myNet->getViewNet()->getDataViewOptions().showShapes()) {
352
// draw boundaries
353
GLHelper::drawBoundary(s, getCenteringBoundary());
354
// obtain POIExaggeration
355
const double POIExaggeration = getExaggeration(s);
356
// get detail level
357
const auto d = s.getDetailLevel(POIExaggeration);
358
// check if draw moving geometry points (only if we have a defined image
359
const bool movingGeometryPoints = getShapeImgFile().empty() ? false : drawMovingGeometryPoints(false);
360
// draw geometry only if we'rent in drawForObjectUnderCursor mode
361
if (s.checkDrawPOI(getWidth(), getHeight(), d, isAttributeCarrierSelected())) {
362
// draw POI
363
drawPOI(s, d, movingGeometryPoints);
364
// draw lock icon
365
GNEViewNetHelper::LockIcon::drawLockIcon(d, this, getType(), getPositionInView(), POIExaggeration);
366
// draw dotted contours
367
if (movingGeometryPoints) {
368
// get snap radius
369
const double snapRadius = myNet->getViewNet()->getVisualisationSettings().neteditSizeSettings.additionalGeometryPointRadius;
370
const double snapRadiusSquared = snapRadius * snapRadius;
371
// get mouse position
372
const Position mousePosition = myNet->getViewNet()->getPositionInformation();
373
// check if we're editing width or height
374
if ((myShapeHeight.front().distanceSquaredTo2D(mousePosition) <= snapRadiusSquared) ||
375
(myShapeHeight.back().distanceSquaredTo2D(mousePosition) <= snapRadiusSquared)) {
376
myMovingContourUp.drawDottedContours(s, d, this, s.dottedContourSettings.segmentWidthSmall, true);
377
myMovingContourDown.drawDottedContours(s, d, this, s.dottedContourSettings.segmentWidthSmall, true);
378
} else if ((myShapeWidth.front().distanceSquaredTo2D(mousePosition) <= snapRadiusSquared) ||
379
(myShapeWidth.back().distanceSquaredTo2D(mousePosition) <= snapRadiusSquared)) {
380
myMovingContourLeft.drawDottedContours(s, d, this, s.dottedContourSettings.segmentWidthSmall, true);
381
myMovingContourRight.drawDottedContours(s, d, this, s.dottedContourSettings.segmentWidthSmall, true);
382
}
383
} else {
384
myAdditionalContour.drawDottedContours(s, d, this, s.dottedContourSettings.segmentWidth, true);
385
}
386
}
387
// calculate contour
388
calculatePOIContour(s, d, POIExaggeration, movingGeometryPoints);
389
}
390
}
391
392
393
std::string
394
GNEPOI::getAttribute(SumoXMLAttr key) const {
395
switch (key) {
396
case SUMO_ATTR_ID:
397
return myID;
398
case SUMO_ATTR_COLOR:
399
return toString(getShapeColor());
400
case SUMO_ATTR_LANE:
401
return myLane;
402
case SUMO_ATTR_POSITION:
403
if (getParentLanes().size() > 0) {
404
return toString(myPosOverLane);
405
} else {
406
return toString(*this);
407
}
408
case SUMO_ATTR_FRIENDLY_POS:
409
return toString(getFriendlyPos());
410
case SUMO_ATTR_POSITION_LAT:
411
return toString(myPosLat);
412
case SUMO_ATTR_LON:
413
if (GeoConvHelper::getFinal().getProjString() != "!") {
414
// calculate geo position
415
Position GEOPosition(x(), y());
416
GeoConvHelper::getFinal().cartesian2geo(GEOPosition);
417
// return lon
418
return toString(GEOPosition.x(), 8);
419
} else {
420
return TL("No geo-conversion defined");
421
}
422
case SUMO_ATTR_LAT:
423
if (GeoConvHelper::getFinal().getProjString() != "!") {
424
// calculate geo position
425
Position GEOPosition(x(), y());
426
GeoConvHelper::getFinal().cartesian2geo(GEOPosition);
427
// return lat
428
return toString(GEOPosition.y(), 8);
429
} else {
430
return TL("No geo-conversion defined");
431
}
432
case SUMO_ATTR_TYPE:
433
return getShapeType();
434
case SUMO_ATTR_ICON:
435
return getIconStr();
436
case SUMO_ATTR_LAYER:
437
return toString(getShapeLayer());
438
case SUMO_ATTR_IMGFILE:
439
return getShapeImgFile();
440
case SUMO_ATTR_WIDTH:
441
return toString(getWidth());
442
case SUMO_ATTR_HEIGHT:
443
return toString(getHeight());
444
case SUMO_ATTR_ANGLE:
445
return toString(getShapeNaviDegree());
446
case SUMO_ATTR_NAME:
447
return getShapeName();
448
case GNE_ATTR_SHIFTLANEINDEX:
449
return "";
450
default:
451
return getCommonAttribute(this, key);
452
}
453
}
454
455
456
double
457
GNEPOI::getAttributeDouble(SumoXMLAttr key) const {
458
throw InvalidArgument(getTagStr() + " attribute '" + toString(key) + "' not allowed");
459
}
460
461
462
const Parameterised::Map&
463
GNEPOI::getACParametersMap() const {
464
return PointOfInterest::getParametersMap();
465
}
466
467
468
void
469
GNEPOI::setAttribute(SumoXMLAttr key, const std::string& value, GNEUndoList* undoList) {
470
switch (key) {
471
case SUMO_ATTR_ID:
472
case SUMO_ATTR_COLOR:
473
case SUMO_ATTR_LANE:
474
case SUMO_ATTR_POSITION:
475
case SUMO_ATTR_FRIENDLY_POS:
476
case SUMO_ATTR_POSITION_LAT:
477
case SUMO_ATTR_LON:
478
case SUMO_ATTR_LAT:
479
case SUMO_ATTR_TYPE:
480
case SUMO_ATTR_ICON:
481
case SUMO_ATTR_LAYER:
482
case SUMO_ATTR_IMGFILE:
483
case SUMO_ATTR_WIDTH:
484
case SUMO_ATTR_HEIGHT:
485
case SUMO_ATTR_ANGLE:
486
case SUMO_ATTR_NAME:
487
case GNE_ATTR_SHIFTLANEINDEX:
488
GNEChange_Attribute::changeAttribute(this, key, value, undoList);
489
break;
490
default:
491
setCommonAttribute(key, value, undoList);
492
break;
493
}
494
}
495
496
497
bool
498
GNEPOI::isValid(SumoXMLAttr key, const std::string& value) {
499
switch (key) {
500
case SUMO_ATTR_ID:
501
return isValidAdditionalID(NamespaceIDs::POIs, value);
502
case SUMO_ATTR_COLOR:
503
return canParse<RGBColor>(value);
504
case SUMO_ATTR_LANE:
505
return (myNet->getAttributeCarriers()->retrieveLane(value, false) != nullptr);
506
case SUMO_ATTR_POSITION:
507
if (getParentLanes().size() > 0) {
508
return canParse<double>(value);
509
} else {
510
return canParse<Position>(value);
511
}
512
case SUMO_ATTR_FRIENDLY_POS:
513
return canParse<bool>(value);
514
case SUMO_ATTR_POSITION_LAT:
515
return canParse<double>(value);
516
case SUMO_ATTR_LON:
517
return canParse<double>(value);
518
case SUMO_ATTR_LAT:
519
return canParse<double>(value);
520
case SUMO_ATTR_TYPE:
521
return true;
522
case SUMO_ATTR_ICON:
523
return SUMOXMLDefinitions::POIIcons.hasString(value);
524
case SUMO_ATTR_LAYER:
525
if (value.empty()) {
526
return true;
527
} else {
528
return canParse<double>(value);
529
}
530
case SUMO_ATTR_IMGFILE:
531
if (value == "") {
532
return true;
533
} else {
534
// check that image can be loaded
535
return GUITexturesHelper::getTextureID(value) != -1;
536
}
537
case SUMO_ATTR_WIDTH:
538
return canParse<double>(value) && (parse<double>(value) > 0);
539
case SUMO_ATTR_HEIGHT:
540
return canParse<double>(value) && (parse<double>(value) > 0);
541
case SUMO_ATTR_ANGLE:
542
return canParse<double>(value);
543
case SUMO_ATTR_NAME:
544
return SUMOXMLDefinitions::isValidAttribute(value);
545
default:
546
return isCommonValid(key, value);
547
}
548
}
549
550
551
bool
552
GNEPOI::isAttributeEnabled(SumoXMLAttr key) const {
553
switch (key) {
554
case SUMO_ATTR_POSITION:
555
if (myTagProperty->getTag() == GNE_TAG_POIGEO) {
556
return (GeoConvHelper::getFinal().getProjString() != "!");
557
} else {
558
return true;
559
}
560
case SUMO_ATTR_LON:
561
case SUMO_ATTR_LAT:
562
return (GeoConvHelper::getFinal().getProjString() != "!");
563
default:
564
return true;
565
}
566
}
567
568
569
std::string
570
GNEPOI::getPopUpID() const {
571
return getTagStr() + ": " + getID();
572
}
573
574
575
std::string
576
GNEPOI::getHierarchyName() const {
577
return getTagStr();
578
}
579
580
// ===========================================================================
581
// private
582
// ===========================================================================
583
584
void
585
GNEPOI::drawPOI(const GUIVisualizationSettings& s, const GUIVisualizationSettings::Detail d,
586
const bool movingGeometryPoints) const {
587
if (GUIPointOfInterest::checkDraw(s, this)) {
588
// draw inner polygon
589
if (myDrawInFront) {
590
GUIPointOfInterest::drawInnerPOI(s, this, this, drawUsingSelectColor(), GLO_FRONTELEMENT,
591
myShapeWidth.length2D(), myShapeHeight.length2D());
592
} else {
593
GUIPointOfInterest::drawInnerPOI(s, this, this, drawUsingSelectColor(), s.poiUseCustomLayer ? s.poiCustomLayer : getShapeLayer(),
594
myShapeWidth.length2D(), myShapeHeight.length2D());
595
}
596
// draw geometry points
597
if (movingGeometryPoints) {
598
if (myShapeHeight.size() > 0) {
599
drawUpGeometryPoint(s, d, myShapeHeight.front(), 180, RGBColor::ORANGE);
600
drawDownGeometryPoint(s, d, myShapeHeight.back(), 180, RGBColor::ORANGE);
601
}
602
if (myShapeWidth.size() > 0) {
603
drawLeftGeometryPoint(s, d, myShapeWidth.back(), -90, RGBColor::ORANGE);
604
drawRightGeometryPoint(s, d, myShapeWidth.front(), -90, RGBColor::ORANGE);
605
}
606
}
607
}
608
}
609
610
611
void
612
GNEPOI::calculatePOIContour(const GUIVisualizationSettings& s, const GUIVisualizationSettings::Detail d,
613
const double exaggeration, const bool movingGeometryPoints) const {
614
// check if we're calculating the contour or the moving geometry points
615
if (movingGeometryPoints) {
616
myMovingContourUp.calculateContourCircleShape(s, d, this, myShapeHeight.front(), s.neteditSizeSettings.additionalGeometryPointRadius,
617
getShapeLayer(), exaggeration, nullptr);
618
myMovingContourDown.calculateContourCircleShape(s, d, this, myShapeHeight.back(), s.neteditSizeSettings.additionalGeometryPointRadius,
619
getShapeLayer(), exaggeration, nullptr);
620
myMovingContourLeft.calculateContourCircleShape(s, d, this, myShapeWidth.front(), s.neteditSizeSettings.additionalGeometryPointRadius,
621
getShapeLayer(), exaggeration, nullptr);
622
myMovingContourRight.calculateContourCircleShape(s, d, this, myShapeWidth.back(), s.neteditSizeSettings.additionalGeometryPointRadius,
623
getShapeLayer(), exaggeration, nullptr);
624
} else {
625
const auto parentEdgeBoundary = (getParentLanes().size() > 0) ? getParentLanes().front()->getParentEdge() : nullptr;
626
if (getShapeImgFile().empty()) {
627
const double radius = getWidth() > getHeight() ? getWidth() : getHeight();
628
myAdditionalContour.calculateContourCircleShape(s, d, this, *this, radius * 0.5, getShapeLayer(), exaggeration, parentEdgeBoundary);
629
} else {
630
myAdditionalContour.calculateContourRectangleShape(s, d, this, *this, getHeight() * 0.5, getWidth() * 0.5, getShapeLayer(), 0, 0, getShapeNaviDegree(), exaggeration, parentEdgeBoundary);
631
}
632
}
633
}
634
635
636
void
637
GNEPOI::setAttribute(SumoXMLAttr key, const std::string& value) {
638
switch (key) {
639
case SUMO_ATTR_ID: {
640
// update microsimID
641
setAdditionalID(value);
642
// set named ID
643
myID = value;
644
break;
645
}
646
case SUMO_ATTR_COLOR:
647
setShapeColor(parse<RGBColor>(value));
648
break;
649
case SUMO_ATTR_LANE:
650
myLane = value;
651
replaceAdditionalParentLanes(value);
652
break;
653
case SUMO_ATTR_POSITION: {
654
if (myTagProperty->getTag() == GNE_TAG_POILANE) {
655
myPosOverLane = parse<double>(value);
656
} else {
657
// set position
658
set(parse<Position>(value));
659
}
660
// update centering boundary
661
updateCenteringBoundary(true);
662
// update geometry
663
updateGeometry();
664
break;
665
}
666
case SUMO_ATTR_FRIENDLY_POS:
667
setFriendlyPos(parse<bool>(value));
668
break;
669
case SUMO_ATTR_POSITION_LAT:
670
myPosLat = parse<double>(value);
671
// update centering boundary
672
updateCenteringBoundary(true);
673
// update geometry
674
updateGeometry();
675
break;
676
case SUMO_ATTR_LON: {
677
// calculate cartesian
678
Position cartesian(parse<double>(value), parse<double>(getAttribute(SUMO_ATTR_LAT)));
679
GeoConvHelper::getFinal().x2cartesian_const(cartesian);
680
// set cartesian
681
set(cartesian);
682
// update centering boundary
683
updateCenteringBoundary(true);
684
// update geometry
685
updateGeometry();
686
break;
687
}
688
case SUMO_ATTR_LAT: {
689
// calculate cartesian
690
Position cartesian(parse<double>(getAttribute(SUMO_ATTR_LON)), parse<double>(value));
691
GeoConvHelper::getFinal().x2cartesian_const(cartesian);
692
// set cartesian
693
set(cartesian);
694
// update centering boundary
695
updateCenteringBoundary(true);
696
// update geometry
697
updateGeometry();
698
break;
699
}
700
case SUMO_ATTR_TYPE:
701
setShapeType(value);
702
break;
703
case SUMO_ATTR_ICON:
704
setIcon(value);
705
break;
706
case SUMO_ATTR_LAYER:
707
if (value.empty()) {
708
setShapeLayer(myTagProperty->getDefaultDoubleValue(key));
709
} else {
710
setShapeLayer(parse<double>(value));
711
}
712
break;
713
case SUMO_ATTR_IMGFILE:
714
// first remove object from grid due img file affect to boundary
715
if (getID().size() > 0) {
716
myNet->removeGLObjectFromGrid(this);
717
}
718
setShapeImgFile(value);
719
// all textures must be refresh
720
GUITexturesHelper::clearTextures();
721
// add object into grid again
722
if (getID().size() > 0) {
723
myNet->addGLObjectIntoGrid(this);
724
}
725
break;
726
case SUMO_ATTR_WIDTH:
727
// set new width
728
setWidth(parse<double>(value));
729
// update centering boundary and geometry (except for templates)
730
if (getID().size() > 0) {
731
updateCenteringBoundary(true);
732
updateGeometry();
733
}
734
break;
735
case SUMO_ATTR_HEIGHT:
736
// set new height
737
setHeight(parse<double>(value));
738
// update centering boundary and geometry (except for templates)
739
if (getID().size() > 0) {
740
updateCenteringBoundary(true);
741
updateGeometry();
742
}
743
break;
744
case SUMO_ATTR_ANGLE:
745
setShapeNaviDegree(parse<double>(value));
746
break;
747
case SUMO_ATTR_NAME:
748
setShapeName(value);
749
break;
750
case GNE_ATTR_SHIFTLANEINDEX:
751
shiftLaneIndex();
752
break;
753
default:
754
return setCommonAttribute(this, key, value);
755
}
756
}
757
758
759
void
760
GNEPOI::setMoveShape(const GNEMoveResult& moveResult) {
761
// check what are being updated
762
if (moveResult.operationType == GNEMoveOperation::OperationType::HEIGHT) {
763
myShapeHeight = moveResult.shapeToUpdate;
764
} else if (moveResult.operationType == GNEMoveOperation::OperationType::WIDTH) {
765
myShapeWidth = moveResult.shapeToUpdate;
766
} else {
767
if (getTagProperty()->getTag() == GNE_TAG_POILANE) {
768
myPosOverLane = moveResult.newFirstPos;
769
} else {
770
set(moveResult.shapeToUpdate.front());
771
}
772
// update geometry
773
updateGeometry();
774
}
775
}
776
777
778
void
779
GNEPOI::commitMoveShape(const GNEMoveResult& moveResult, GNEUndoList* undoList) {
780
// check what are being updated
781
if (moveResult.operationType == GNEMoveOperation::OperationType::HEIGHT) {
782
undoList->begin(this, "height of " + getTagStr());
783
setAttribute(SUMO_ATTR_HEIGHT, toString(moveResult.shapeToUpdate.length2D()), undoList);
784
undoList->end();
785
} else if (moveResult.operationType == GNEMoveOperation::OperationType::WIDTH) {
786
undoList->begin(this, "width of " + getTagStr());
787
setAttribute(SUMO_ATTR_WIDTH, toString(moveResult.shapeToUpdate.length2D()), undoList);
788
undoList->end();
789
} else {
790
undoList->begin(this, "position of " + getTagStr());
791
if (getTagProperty()->getTag() == GNE_TAG_POILANE) {
792
GNEChange_Attribute::changeAttribute(this, SUMO_ATTR_POSITION, toString(moveResult.newFirstPos), undoList);
793
} else {
794
GNEChange_Attribute::changeAttribute(this, SUMO_ATTR_POSITION, toString(moveResult.shapeToUpdate.front()), undoList);
795
}
796
undoList->end();
797
}
798
}
799
800
/****************************************************************************/
801
802