Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
eclipse
GitHub Repository: eclipse/sumo
Path: blob/main/src/netedit/elements/additional/GNEPoly.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 GNEPoly.cpp
15
/// @author Pablo Alvarez Lopez
16
/// @date Jun 2017
17
///
18
// A class for visualizing and editing POIS in netedit (adapted from
19
// GUIPolygon 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/GUIGlobalViewObjectsHandler.h>
33
#include <utils/gui/div/GUIParameterTableWindow.h>
34
#include <utils/gui/globjects/GUIGLObjectPopupMenu.h>
35
#include <utils/xml/NamespaceIDs.h>
36
37
#include "GNEPoly.h"
38
39
// ===========================================================================
40
// method definitions
41
// ===========================================================================
42
43
GNEPoly::GNEPoly(SumoXMLTag tag, GNENet* net) :
44
TesselatedPolygon("", "", RGBColor::BLACK, {}, false, false, 0, 0, 0, "", "", Parameterised::Map()),
45
GNEAdditional("", net, "", tag, "") {
46
}
47
48
49
GNEPoly::GNEPoly(const std::string& id, GNENet* net, const std::string& filename, const std::string& type, const PositionVector& shape,
50
bool geo, bool fill, double lineWidth, const RGBColor& color, double layer, double angle, const std::string& imgFile,
51
const std::string& name, const Parameterised::Map& parameters) :
52
TesselatedPolygon(id, type, color, shape, geo, fill, lineWidth, layer, angle, imgFile, name, parameters),
53
GNEAdditional(id, net, filename, SUMO_TAG_POLY, ""),
54
myClosedShape(shape.isClosed()) {
55
// check if imgFile is valid
56
if (!imgFile.empty() && GUITexturesHelper::getTextureID(imgFile) == -1) {
57
setShapeImgFile("");
58
}
59
// set GEO shape
60
myGeoShape = myShape;
61
if (geo) {
62
for (int i = 0; i < (int) myGeoShape.size(); i++) {
63
GeoConvHelper::getFinal().x2cartesian_const(myShape[i]);
64
}
65
} else {
66
for (int i = 0; i < (int) myGeoShape.size(); i++) {
67
GeoConvHelper::getFinal().cartesian2geo(myGeoShape[i]);
68
}
69
}
70
// update centering boundary without updating grid
71
updateCenteringBoundary(false);
72
// update geometry
73
updateGeometry();
74
}
75
76
77
GNEPoly::GNEPoly(SumoXMLTag tag, const std::string& id, GNENet* net, const std::string& filename, const PositionVector& shape,
78
bool geo, const std::string& name, const Parameterised::Map& parameters) :
79
TesselatedPolygon(id, getJuPedSimType(tag), getJuPedSimColor(tag), shape, geo, getJuPedSimFill(tag), 1,
80
getJuPedSimLayer(tag), 0, "", name, parameters),
81
GNEAdditional(id, net, filename, tag, ""),
82
myClosedShape(shape.isClosed()),
83
mySimplifiedShape(false) {
84
// set GEO shape
85
myGeoShape = myShape;
86
if (geo) {
87
for (int i = 0; i < (int) myGeoShape.size(); i++) {
88
GeoConvHelper::getFinal().x2cartesian_const(myShape[i]);
89
}
90
} else {
91
for (int i = 0; i < (int) myGeoShape.size(); i++) {
92
GeoConvHelper::getFinal().cartesian2geo(myGeoShape[i]);
93
}
94
}
95
// update centering boundary without updating grid
96
updateCenteringBoundary(false);
97
// update geometry
98
updateGeometry();
99
}
100
101
102
GNEPoly::~GNEPoly() {}
103
104
105
GNEMoveOperation*
106
GNEPoly::getMoveOperation() {
107
// edit depending if shape is blocked
108
if (myNet->getViewNet()->getViewParent()->getMoveFrame()->getNetworkMoveOptions()->getMoveWholePolygons()) {
109
// move entire shape
110
return new GNEMoveOperation(this, myShape);
111
} else {
112
// continue depending of tag
113
switch (getTagProperty()->getTag()) {
114
case GNE_TAG_JPS_WALKABLEAREA:
115
case GNE_TAG_JPS_OBSTACLE:
116
// calculate move shape operation maintain shape closed
117
return calculateMoveShapeOperation(this, myShape, true);
118
default:
119
// calculate move shape operation
120
return calculateMoveShapeOperation(this, myShape, false);
121
}
122
}
123
}
124
125
126
void
127
GNEPoly::removeGeometryPoint(const Position clickedPosition, GNEUndoList* undoList) {
128
// get original shape
129
PositionVector shape = myShape;
130
// check shape size
131
if (shape.size() > 2) {
132
// obtain index
133
int index = shape.indexOfClosest(clickedPosition);
134
// get snap radius
135
const double snap_radius = myNet->getViewNet()->getVisualisationSettings().neteditSizeSettings.polygonGeometryPointRadius;
136
// check if we have to create a new index
137
if ((index != -1) && shape[index].distanceSquaredTo2D(clickedPosition) < (snap_radius * snap_radius)) {
138
// remove geometry point
139
shape.erase(shape.begin() + index);
140
// commit new shape
141
undoList->begin(this, "remove geometry point of " + getTagStr());
142
GNEChange_Attribute::changeAttribute(this, SUMO_ATTR_SHAPE, toString(shape), undoList);
143
undoList->end();
144
}
145
}
146
}
147
148
149
std::string
150
GNEPoly::generateChildID(SumoXMLTag /*childTag*/) {
151
return "";
152
}
153
154
155
void
156
GNEPoly::updateGeometry() {
157
// just update polygon geometry
158
myAdditionalGeometry.updateGeometry(myShape);
159
myTesselation.clear();
160
}
161
162
163
Position
164
GNEPoly::getPositionInView() const {
165
return myAdditionalBoundary.getCenter();
166
}
167
168
169
double
170
GNEPoly::getExaggeration(const GUIVisualizationSettings& s) const {
171
return s.polySize.getExaggeration(s, this);
172
}
173
174
175
void
176
GNEPoly::updateCenteringBoundary(const bool updateGrid) {
177
// Remove object from net
178
if (updateGrid) {
179
myNet->removeGLObjectFromGrid(this);
180
}
181
// use shape as boundary
182
myAdditionalBoundary = myShape.getBoxBoundary();
183
// grow boundary
184
myAdditionalBoundary.grow(5);
185
// add object into net
186
if (updateGrid) {
187
myNet->addGLObjectIntoGrid(this);
188
}
189
}
190
191
192
void
193
GNEPoly::splitEdgeGeometry(const double /*splitPosition*/, const GNENetworkElement* /*originalElement*/, const GNENetworkElement* /*newElement*/, GNEUndoList* /*undoList*/) {
194
// nothing to split
195
}
196
197
198
void
199
GNEPoly::writeAdditional(OutputDevice& device) const {
200
writeXML(device, myGEO);
201
}
202
203
204
bool
205
GNEPoly::isAdditionalValid() const {
206
return true;
207
}
208
209
210
std::string
211
GNEPoly::getAdditionalProblem() const {
212
return "";
213
}
214
215
216
void
217
GNEPoly::fixAdditionalProblem() {
218
// nothing to fix
219
}
220
221
222
GUIGlID
223
GNEPoly::getGlID() const {
224
return GUIGlObject::getGlID();
225
}
226
227
228
bool
229
GNEPoly::checkDrawMoveContour() const {
230
// get edit modes
231
const auto& editModes = myNet->getViewNet()->getEditModes();
232
// check if we're in move mode
233
if (!myNet->getViewNet()->isCurrentlyMovingElements() && editModes.isCurrentSupermodeNetwork() &&
234
!myNet->getViewNet()->getEditNetworkElementShapes().getEditedNetworkElement() &&
235
(editModes.networkEditMode == NetworkEditMode::NETWORK_MOVE) && myNet->getViewNet()->checkOverLockedElement(this, mySelected)) {
236
// only move the first element
237
return myNet->getViewNet()->getViewObjectsSelector().getGUIGlObjectFront() == this;
238
} else {
239
return false;
240
}
241
}
242
243
244
std::string
245
GNEPoly::getParentName() const {
246
return myNet->getMicrosimID();
247
}
248
249
250
GUIGLObjectPopupMenu*
251
GNEPoly::getPopUpMenu(GUIMainWindow& app, GUISUMOAbstractView& parent) {
252
// create popup
253
GUIGLObjectPopupMenu* ret = new GUIGLObjectPopupMenu(app, parent, this);
254
// build common options
255
buildPopUpMenuCommonOptions(ret, app, myNet->getViewNet(), myTagProperty->getTag(), mySelected);
256
FXMenuCommand* simplifyShape = GUIDesigns::buildFXMenuCommand(ret, TL("Simplify Shape"), TL("Replace current shape with a rectangle"), nullptr, &parent, MID_GNE_POLYGON_SIMPLIFY_SHAPE);
257
// disable simplify shape if polygon was already simplified
258
if (mySimplifiedShape || myShape.size() <= 2) {
259
simplifyShape->disable();
260
}
261
// only allow open/close for non juPedSim polygons
262
if (!myTagProperty->isJuPedSimElement()) {
263
if (myShape.isClosed()) {
264
GUIDesigns::buildFXMenuCommand(ret, TL("Open shape"), TL("Open polygon's shape"), nullptr, &parent, MID_GNE_POLYGON_OPEN);
265
} else {
266
GUIDesigns::buildFXMenuCommand(ret, TL("Close shape"), TL("Close polygon's shape"), nullptr, &parent, MID_GNE_POLYGON_CLOSE);
267
}
268
}
269
GUIDesigns::buildFXMenuCommand(ret, TL("Select elements within polygon"), TL("Select elements within polygon boundary"), nullptr, &parent, MID_GNE_POLYGON_SELECT);
270
if (myShape.size() > 3) {
271
GUIDesigns::buildFXMenuCommand(ret, TL("Triangulate polygon"), TL("Convert the current polygon in triangles"), nullptr, &parent, MID_GNE_POLYGON_TRIANGULATE);
272
}
273
// create a extra FXMenuCommand if mouse is over a vertex
274
const int index = getVertexIndex(myNet->getViewNet()->getPositionInformation(), false);
275
if (index != -1) {
276
// add separator
277
new FXMenuSeparator(ret);
278
// check if we're in network mode
279
if (myNet->getViewNet()->getEditModes().networkEditMode == NetworkEditMode::NETWORK_MOVE) {
280
GUIDesigns::buildFXMenuCommand(ret, "Set custom Geometry Point", nullptr, &parent, MID_GNE_CUSTOM_GEOMETRYPOINT);
281
}
282
FXMenuCommand* removeGeometryPoint = GUIDesigns::buildFXMenuCommand(ret, TL("Remove geometry point"), TL("Remove geometry point under mouse"), nullptr, &parent, MID_GNE_POLYGON_DELETE_GEOMETRY_POINT);
283
FXMenuCommand* setFirstPoint = GUIDesigns::buildFXMenuCommand(ret, TL("Set first geometry point"), TL("Set first geometry point"), nullptr, &parent, MID_GNE_POLYGON_SET_FIRST_POINT);
284
// disable setFirstPoint if shape only have three points
285
if ((myShape.isClosed() && (myShape.size() <= 4)) || (!myShape.isClosed() && (myShape.size() <= 2))) {
286
removeGeometryPoint->disable();
287
}
288
// disable setFirstPoint if mouse is over first point
289
if (index == 0) {
290
setFirstPoint->disable();
291
}
292
}
293
return ret;
294
}
295
296
297
void
298
GNEPoly::drawGL(const GUIVisualizationSettings& s) const {
299
// first check if poly can be drawn
300
if (myNet->getViewNet()->getDemandViewOptions().showShapes() &&
301
myNet->getViewNet()->getDataViewOptions().showShapes() &&
302
GUIPolygon::checkDraw(s, this, this)) {
303
// draw boundary
304
const auto boundary = getCenteringBoundary();
305
GLHelper::drawBoundary(s, getCenteringBoundary());
306
// get exaggeration
307
const double polyExaggeration = getExaggeration(s);
308
// get detail level
309
const auto d = s.getDetailLevel(polyExaggeration);
310
// draw geometry only if we'rent in drawForObjectUnderCursor mode
311
if (s.checkDrawPoly(boundary, isAttributeCarrierSelected())) {
312
// get colors
313
const RGBColor color = isAttributeCarrierSelected() ? s.colorSettings.selectionColor : getShapeColor();
314
// push layer matrix
315
GLHelper::pushMatrix();
316
// translate to front
317
drawInLayer(s.polyUseCustomLayer ? s.polyCustomLayer : getShapeLayer());
318
// draw polygon
319
drawPolygon(s, d, color, polyExaggeration);
320
// draw contour if don't move whole polygon
321
if (!myNet->getViewNet()->getViewParent()->getMoveFrame()->getNetworkMoveOptions()->getMoveWholePolygons()) {
322
// get darker color
323
const RGBColor darkerColor = color.changedBrightness(-32);
324
// draw contour
325
drawPolygonContour(s, d, darkerColor, polyExaggeration);
326
// draw geometry points
327
drawGeometryPoints(s, d, darkerColor, polyExaggeration);
328
}
329
// pop layer matrix
330
GLHelper::popMatrix();
331
// draw name and type
332
drawPolygonNameAndType(s);
333
// draw lock icon
334
GNEViewNetHelper::LockIcon::drawLockIcon(d, this, getType(), getPositionInView(), polyExaggeration);
335
// draw dotted contour
336
myAdditionalContour.drawDottedContours(s, d, this, s.dottedContourSettings.segmentWidth, true);
337
}
338
// calculate contour
339
calculateContourPolygons(s, d, getShapeLayer(), polyExaggeration, getFill());
340
}
341
}
342
343
344
int
345
GNEPoly::getVertexIndex(Position pos, bool snapToGrid) {
346
// check if position has to be snapped to grid
347
if (snapToGrid) {
348
pos = myNet->getViewNet()->snapToActiveGrid(pos);
349
}
350
// first check if vertex already exists
351
for (const auto& shapePosition : myShape) {
352
if (shapePosition.distanceTo2D(pos) < myNet->getViewNet()->getVisualisationSettings().neteditSizeSettings.polygonGeometryPointRadius) {
353
return myShape.indexOfClosest(shapePosition);
354
}
355
}
356
return -1;
357
}
358
359
360
void
361
GNEPoly::deleteGeometryPoint(const Position& pos, bool allowUndo) {
362
if (myShape.size() > 1) {
363
// obtain index
364
PositionVector modifiedShape = myShape;
365
int index = modifiedShape.indexOfClosest(pos);
366
// remove point dependending of
367
if (myShape.isClosed() && (index == 0 || index == (int)modifiedShape.size() - 1) && (myShape.size() > 2)) {
368
modifiedShape.erase(modifiedShape.begin());
369
modifiedShape.erase(modifiedShape.end() - 1);
370
modifiedShape.push_back(modifiedShape.front());
371
} else {
372
modifiedShape.erase(modifiedShape.begin() + index);
373
}
374
// set new shape depending of allowUndo
375
if (allowUndo) {
376
myNet->getViewNet()->getUndoList()->begin(this, "delete geometry point");
377
setAttribute(SUMO_ATTR_SHAPE, toString(modifiedShape), myNet->getViewNet()->getUndoList());
378
myNet->getViewNet()->getUndoList()->end();
379
} else {
380
// first remove object from grid due shape is used for boundary
381
myNet->removeGLObjectFromGrid(this);
382
// set new shape
383
myShape = modifiedShape;
384
// disable simplified shape flag
385
mySimplifiedShape = false;
386
// add object into grid again
387
myNet->addGLObjectIntoGrid(this);
388
}
389
myTesselation.clear();
390
} else {
391
WRITE_WARNING(TL("Number of remaining points insufficient"))
392
}
393
}
394
395
396
bool
397
GNEPoly::isPolygonClosed() const {
398
return myShape.isClosed();
399
}
400
401
402
void
403
GNEPoly::openPolygon(bool allowUndo) {
404
// only open if shape is closed
405
if (myShape.isClosed()) {
406
if (allowUndo) {
407
myNet->getViewNet()->getUndoList()->begin(this, "open polygon");
408
setAttribute(GNE_ATTR_CLOSE_SHAPE, "false", myNet->getViewNet()->getUndoList());
409
myNet->getViewNet()->getUndoList()->end();
410
} else {
411
myShape.pop_back();
412
// disable simplified shape flag
413
mySimplifiedShape = false;
414
// update geometry to avoid grabbing Problems
415
updateGeometry();
416
}
417
} else {
418
WRITE_WARNING(TL("Polygon already opened"))
419
}
420
}
421
422
423
void
424
GNEPoly::closePolygon(bool allowUndo) {
425
// only close if shape is opened
426
if (!myShape.isClosed()) {
427
if (allowUndo) {
428
myNet->getViewNet()->getUndoList()->begin(this, "close shape");
429
setAttribute(GNE_ATTR_CLOSE_SHAPE, "true", myNet->getViewNet()->getUndoList());
430
myNet->getViewNet()->getUndoList()->end();
431
} else {
432
myShape.closePolygon();
433
// disable simplified shape flag
434
mySimplifiedShape = false;
435
// update geometry to avoid grabbing Problems
436
updateGeometry();
437
}
438
} else {
439
WRITE_WARNING(TL("Polygon already closed"))
440
}
441
}
442
443
444
void
445
GNEPoly::changeFirstGeometryPoint(int oldIndex, bool allowUndo) {
446
// check that old index is correct
447
if (oldIndex >= (int)myShape.size()) {
448
throw InvalidArgument("Invalid old Index");
449
} else if (oldIndex == 0) {
450
WRITE_WARNING(TL("Selected point must be different of the first point"))
451
} else {
452
// Configure new shape
453
PositionVector newShape;
454
for (int i = oldIndex; i < (int)myShape.size(); i++) {
455
newShape.push_back(myShape[i]);
456
}
457
if (myShape.isClosed()) {
458
for (int i = 1; i < oldIndex; i++) {
459
newShape.push_back(myShape[i]);
460
}
461
newShape.push_back(newShape.front());
462
} else {
463
for (int i = 0; i < oldIndex; i++) {
464
newShape.push_back(myShape[i]);
465
}
466
}
467
// set new rotated shape
468
if (allowUndo) {
469
myNet->getViewNet()->getUndoList()->begin(this, "change first geometry point");
470
setAttribute(SUMO_ATTR_SHAPE, toString(newShape), myNet->getViewNet()->getUndoList());
471
myNet->getViewNet()->getUndoList()->end();
472
} else {
473
// set new shape
474
myShape = newShape;
475
// disable simplified shape flag
476
mySimplifiedShape = false;
477
// update geometry to avoid grabbing Problems
478
updateGeometry();
479
}
480
}
481
}
482
483
484
void
485
GNEPoly::simplifyShape(bool allowUndo) {
486
if (!mySimplifiedShape && myShape.size() > 2) {
487
const Boundary b = myShape.getBoxBoundary();
488
// create a square as simplified shape
489
PositionVector simplifiedShape;
490
simplifiedShape.push_back(Position(b.xmin(), b.ymin()));
491
simplifiedShape.push_back(Position(b.xmin(), b.ymax()));
492
simplifiedShape.push_back(Position(b.xmax(), b.ymax()));
493
simplifiedShape.push_back(Position(b.xmax(), b.ymin()));
494
if (myShape.isClosed()) {
495
simplifiedShape.push_back(simplifiedShape[0]);
496
}
497
// set new shape depending of allowUndo
498
if (allowUndo) {
499
myNet->getViewNet()->getUndoList()->begin(this, "simplify shape");
500
setAttribute(SUMO_ATTR_SHAPE, toString(simplifiedShape), myNet->getViewNet()->getUndoList());
501
myNet->getViewNet()->getUndoList()->end();
502
} else {
503
// set new shape
504
myShape = simplifiedShape;
505
// update geometry to avoid grabbing Problems
506
updateGeometry();
507
}
508
// change flag after setting simplified shape
509
mySimplifiedShape = true;
510
} else {
511
WRITE_WARNING(TL("Polygon already simplified"))
512
}
513
}
514
515
516
CommonXMLStructure::SumoBaseObject*
517
GNEPoly::getSumoBaseObject() const {
518
CommonXMLStructure::SumoBaseObject* polygonBaseObject = new CommonXMLStructure::SumoBaseObject(nullptr);
519
polygonBaseObject->setTag(myTagProperty->getTag());
520
// fill attributes
521
polygonBaseObject->addStringAttribute(SUMO_ATTR_ID, myID);
522
polygonBaseObject->addPositionVectorAttribute(SUMO_ATTR_SHAPE, myShape);
523
polygonBaseObject->addBoolAttribute(SUMO_ATTR_GEO, myGEO);
524
polygonBaseObject->addBoolAttribute(SUMO_ATTR_FILL, myFill);
525
polygonBaseObject->addDoubleAttribute(SUMO_ATTR_LINEWIDTH, myLineWidth);
526
polygonBaseObject->addColorAttribute(SUMO_ATTR_COLOR, getShapeColor());
527
polygonBaseObject->addStringAttribute(SUMO_ATTR_TYPE, getShapeType());
528
polygonBaseObject->addDoubleAttribute(SUMO_ATTR_LAYER, getShapeLayer());
529
polygonBaseObject->addStringAttribute(SUMO_ATTR_IMGFILE, getShapeImgFile());
530
polygonBaseObject->addDoubleAttribute(SUMO_ATTR_ANGLE, getShapeNaviDegree());
531
polygonBaseObject->addStringAttribute(SUMO_ATTR_NAME, getShapeName());
532
return polygonBaseObject;
533
}
534
535
536
std::string
537
GNEPoly::getAttribute(SumoXMLAttr key) const {
538
switch (key) {
539
case SUMO_ATTR_ID:
540
return myID;
541
case SUMO_ATTR_SHAPE:
542
if ((GeoConvHelper::getFinal().getProjString() != "!") && myGEO) {
543
return TL("Using GEO Shape");
544
} else {
545
return toString(myShape);
546
}
547
case SUMO_ATTR_GEOSHAPE:
548
if (GeoConvHelper::getFinal().getProjString() != "!") {
549
return toString(myGeoShape, gPrecisionGeo);
550
} else {
551
return TL("No geo-conversion defined");
552
}
553
case SUMO_ATTR_COLOR:
554
return toString(getShapeColor());
555
case SUMO_ATTR_FILL:
556
return toString(myFill);
557
case SUMO_ATTR_LINEWIDTH:
558
return toString(myLineWidth);
559
case SUMO_ATTR_LAYER:
560
return toString(getShapeLayer());
561
case SUMO_ATTR_TYPE:
562
return getShapeType();
563
case SUMO_ATTR_IMGFILE:
564
return getShapeImgFile();
565
case SUMO_ATTR_ANGLE:
566
return toString(getShapeNaviDegree());
567
case SUMO_ATTR_GEO:
568
return toString(myGEO);
569
case SUMO_ATTR_NAME:
570
return getShapeName();
571
case GNE_ATTR_CLOSE_SHAPE:
572
return toString(myClosedShape);
573
default:
574
return getCommonAttribute(this, key);
575
}
576
}
577
578
579
double
580
GNEPoly::getAttributeDouble(SumoXMLAttr key) const {
581
throw InvalidArgument(getTagStr() + " attribute '" + toString(key) + "' not allowed");
582
}
583
584
585
const Parameterised::Map&
586
GNEPoly::getACParametersMap() const {
587
return SUMOPolygon::getParametersMap();
588
}
589
590
591
void
592
GNEPoly::setAttribute(SumoXMLAttr key, const std::string& value, GNEUndoList* undoList) {
593
if (value == getAttribute(key)) {
594
return; //avoid needless changes, later logic relies on the fact that attributes have changed
595
}
596
switch (key) {
597
case SUMO_ATTR_ID:
598
case SUMO_ATTR_SHAPE:
599
case SUMO_ATTR_GEOSHAPE:
600
case SUMO_ATTR_COLOR:
601
case SUMO_ATTR_FILL:
602
case SUMO_ATTR_LINEWIDTH:
603
case SUMO_ATTR_LAYER:
604
case SUMO_ATTR_TYPE:
605
case SUMO_ATTR_IMGFILE:
606
case SUMO_ATTR_ANGLE:
607
case SUMO_ATTR_GEO:
608
case SUMO_ATTR_NAME:
609
case GNE_ATTR_CLOSE_SHAPE:
610
GNEChange_Attribute::changeAttribute(this, key, value, undoList);
611
break;
612
default:
613
setCommonAttribute(key, value, undoList);
614
break;
615
}
616
}
617
618
619
bool
620
GNEPoly::isValid(SumoXMLAttr key, const std::string& value) {
621
switch (key) {
622
case SUMO_ATTR_ID:
623
return isValidAdditionalID(NamespaceIDs::polygons, value);
624
case SUMO_ATTR_SHAPE:
625
case SUMO_ATTR_GEOSHAPE:
626
// empty shapes AREN'T allowed
627
if (value.empty()) {
628
return false;
629
} else {
630
return canParse<PositionVector>(value);
631
}
632
case SUMO_ATTR_COLOR:
633
return canParse<RGBColor>(value);
634
case SUMO_ATTR_FILL:
635
return canParse<bool>(value);
636
case SUMO_ATTR_LINEWIDTH:
637
return canParse<double>(value) && (parse<double>(value) >= 0);
638
case SUMO_ATTR_LAYER:
639
if (value.empty()) {
640
return true;
641
} else {
642
return canParse<double>(value);
643
}
644
case SUMO_ATTR_TYPE:
645
return true;
646
case SUMO_ATTR_IMGFILE:
647
if (value == "") {
648
return true;
649
} else {
650
// check that image can be loaded
651
return GUITexturesHelper::getTextureID(value) != -1;
652
}
653
case SUMO_ATTR_ANGLE:
654
return canParse<double>(value);
655
case SUMO_ATTR_GEO:
656
return canParse<bool>(value);
657
case SUMO_ATTR_NAME:
658
return SUMOXMLDefinitions::isValidAttribute(value);
659
case GNE_ATTR_CLOSE_SHAPE:
660
return canParse<bool>(value);
661
default:
662
return isCommonValid(key, value);
663
}
664
}
665
666
667
bool
668
GNEPoly::isAttributeEnabled(SumoXMLAttr key) const {
669
switch (key) {
670
case SUMO_ATTR_SHAPE:
671
if (GeoConvHelper::getFinal().getProjString() != "!") {
672
return myGEO == false;
673
} else {
674
return true;
675
}
676
case SUMO_ATTR_GEO:
677
return GeoConvHelper::getFinal().getProjString() != "!";
678
case SUMO_ATTR_GEOSHAPE:
679
if (GeoConvHelper::getFinal().getProjString() != "!") {
680
return myGEO == true;
681
} else {
682
return false;
683
}
684
case GNE_ATTR_CLOSE_SHAPE:
685
if (isTemplate()) {
686
return true;
687
} else {
688
return myShape.size() > 1;
689
}
690
default:
691
return true;
692
}
693
}
694
695
696
std::string
697
GNEPoly::getPopUpID() const {
698
return getTagStr() + ": " + getID();
699
}
700
701
702
std::string
703
GNEPoly::getHierarchyName() const {
704
return getTagStr();
705
}
706
707
// ===========================================================================
708
// private
709
// ===========================================================================
710
711
void
712
GNEPoly::setAttribute(SumoXMLAttr key, const std::string& value) {
713
switch (key) {
714
case SUMO_ATTR_ID: {
715
// update microsimID
716
setAdditionalID(value);
717
// set named ID
718
myID = value;
719
break;
720
}
721
case SUMO_ATTR_SHAPE: {
722
// set new shape
723
myShape = parse<PositionVector>(value);
724
// set GEO shape
725
myGeoShape = myShape;
726
for (int i = 0; i < (int) myGeoShape.size(); i++) {
727
GeoConvHelper::getFinal().cartesian2geo(myGeoShape[i]);
728
}
729
// disable simplified shape flag
730
mySimplifiedShape = false;
731
// update geometry
732
updateGeometry();
733
// update centering boundary
734
updateCenteringBoundary(true);
735
break;
736
}
737
case SUMO_ATTR_GEOSHAPE: {
738
// set new GEO shape
739
myGeoShape = parse<PositionVector>(value);
740
// set shape
741
myShape = myGeoShape ;
742
for (int i = 0; i < (int) myShape.size(); i++) {
743
GeoConvHelper::getFinal().x2cartesian_const(myShape[i]);
744
}
745
// disable simplified shape flag
746
mySimplifiedShape = false;
747
// update geometry
748
updateGeometry();
749
// update centering boundary
750
updateCenteringBoundary(true);
751
break;
752
}
753
case SUMO_ATTR_COLOR:
754
setShapeColor(parse<RGBColor>(value));
755
break;
756
case SUMO_ATTR_FILL:
757
myFill = parse<bool>(value);
758
myAdditionalContour.clearContour();
759
break;
760
case SUMO_ATTR_LINEWIDTH:
761
myLineWidth = parse<double>(value);
762
break;
763
case SUMO_ATTR_LAYER:
764
if (value.empty()) {
765
setShapeLayer(myTagProperty->getDefaultDoubleValue(key));
766
} else {
767
setShapeLayer(parse<double>(value));
768
}
769
break;
770
case SUMO_ATTR_TYPE:
771
setShapeType(value);
772
break;
773
case SUMO_ATTR_IMGFILE:
774
setShapeImgFile(value);
775
// all textures must be refresh
776
GUITexturesHelper::clearTextures();
777
break;
778
case SUMO_ATTR_ANGLE:
779
setShapeNaviDegree(parse<double>(value));
780
break;
781
case SUMO_ATTR_GEO:
782
myGEO = parse<bool>(value);
783
// update centering boundary
784
updateCenteringBoundary(true);
785
break;
786
case SUMO_ATTR_NAME:
787
setShapeName(value);
788
break;
789
case GNE_ATTR_CLOSE_SHAPE:
790
myClosedShape = parse<bool>(value);
791
if (!isTemplate()) {
792
if (myClosedShape) {
793
myShape.closePolygon();
794
myGeoShape.closePolygon();
795
796
} else {
797
myShape.openPolygon();
798
myGeoShape.openPolygon();
799
}
800
// disable simplified shape flag
801
mySimplifiedShape = false;
802
// update geometry
803
updateGeometry();
804
// update centering boundary
805
updateCenteringBoundary(true);
806
}
807
break;
808
default:
809
setCommonAttribute(this, key, value);
810
break;
811
}
812
}
813
814
815
void
816
GNEPoly::setMoveShape(const GNEMoveResult& moveResult) {
817
// update new shape
818
myShape = moveResult.shapeToUpdate;
819
// update geometry
820
myAdditionalGeometry.updateGeometry(myShape);
821
}
822
823
824
void
825
GNEPoly::commitMoveShape(const GNEMoveResult& moveResult, GNEUndoList* undoList) {
826
// commit new shape
827
undoList->begin(this, "moving " + toString(SUMO_ATTR_SHAPE) + " of " + getTagStr());
828
GNEChange_Attribute::changeAttribute(this, SUMO_ATTR_SHAPE, toString(moveResult.shapeToUpdate), undoList);
829
undoList->end();
830
}
831
832
833
void
834
GNEPoly::drawPolygon(const GUIVisualizationSettings& s, const GUIVisualizationSettings::Detail d,
835
const RGBColor& color, const double exaggeration) const {
836
// check if we're drawing a polygon or a polyline
837
if (getFill()) {
838
// draw inner polygon
839
GUIPolygon::drawInnerPolygon(s, this, this, myAdditionalGeometry.getShape(), 0, getFill(), myTagProperty->isJuPedSimElement() ? false : drawUsingSelectColor());
840
} else {
841
// push matrix
842
GLHelper::pushMatrix();
843
// set color
844
GLHelper::setColor(color);
845
// draw geometry (polyline)
846
GUIGeometry::drawGeometry(d, myAdditionalGeometry, s.neteditSizeSettings.polylineWidth * exaggeration);
847
// pop matrix
848
GLHelper::popMatrix();
849
}
850
}
851
852
853
void
854
GNEPoly::drawPolygonContour(const GUIVisualizationSettings& s, const GUIVisualizationSettings::Detail d,
855
const RGBColor& color, const double exaggeration) const {
856
// push contour matrix
857
GLHelper::pushMatrix();
858
// translate to front
859
glTranslated(0, 0, 0.1);
860
// set color
861
GLHelper::setColor(color);
862
// draw polygon contour
863
GUIGeometry::drawGeometry(d, myAdditionalGeometry, s.neteditSizeSettings.polygonContourWidth * exaggeration);
864
// pop contour matrix
865
GLHelper::popMatrix();
866
}
867
868
869
void
870
GNEPoly::drawGeometryPoints(const GUIVisualizationSettings& s, const GUIVisualizationSettings::Detail d,
871
const RGBColor& color, const double exaggeration) const {
872
// draw shape points only in supermode network
873
if (myNet->getViewNet()->getEditModes().isCurrentSupermodeNetwork()) {
874
// check if we're in move mode
875
const bool moveMode = (myNet->getViewNet()->getEditModes().networkEditMode == NetworkEditMode::NETWORK_MOVE);
876
// get geometry point sizes
877
const double geometryPointSize = s.neteditSizeSettings.polygonGeometryPointRadius * (moveMode ? 1 : 0.5);
878
// draw geometry points
879
GUIGeometry::drawGeometryPoints(d, myAdditionalGeometry.getShape(), color, geometryPointSize, exaggeration,
880
myNet->getViewNet()->getNetworkViewOptions().editingElevation());
881
// draw dotted contours for geometry points if we're in move mode
882
if (moveMode) {
883
myAdditionalContour.drawDottedContourGeometryPoints(s, d, this, myAdditionalGeometry.getShape(), geometryPointSize,
884
exaggeration, s.dottedContourSettings.segmentWidthSmall);
885
}
886
}
887
}
888
889
890
void
891
GNEPoly::drawPolygonNameAndType(const GUIVisualizationSettings& s) const {
892
// get name position
893
const Position& namePos = myAdditionalGeometry.getShape().getPolygonCenter();
894
// draw name
895
drawName(namePos, s.scale, s.polyName, s.angle);
896
// check if draw poly type
897
if (s.polyType.show(this)) {
898
const Position p = namePos + Position(0, -0.6 * s.polyType.size / s.scale);
899
GLHelper::drawTextSettings(s.polyType, getShapeType(), p, s.scale, s.angle);
900
}
901
}
902
903
/****************************************************************************/
904
905