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