Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
eclipse
GitHub Repository: eclipse/sumo
Path: blob/main/src/netedit/elements/network/GNENetworkElement.cpp
185790 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 GNENetworkElement.cpp
15
/// @author Pablo Alvarez Lopez
16
/// @date Jun 2016
17
///
18
// A abstract class for networkElements
19
/****************************************************************************/
20
21
#include <netedit/frames/common/GNESelectorFrame.h>
22
#include <netedit/GNEApplicationWindow.h>
23
#include <netedit/GNENet.h>
24
#include <netedit/GNETagPropertiesDatabase.h>
25
#include <netedit/GNEViewParent.h>
26
#include <utils/foxtools/MFXMenuHeader.h>
27
#include <utils/gui/div/GUIDesigns.h>
28
#include <utils/gui/div/GUIParameterTableWindow.h>
29
#include <utils/gui/globjects/GUIGLObjectPopupMenu.h>
30
#include <utils/gui/windows/GUIMainWindow.h>
31
#include <utils/options/OptionsCont.h>
32
33
#include "GNENetworkElement.h"
34
35
// ===========================================================================
36
// method definitions
37
// ===========================================================================
38
39
GNENetworkElement::GNENetworkElement(GNENet* net, SumoXMLTag tag) :
40
GNEAttributeCarrier(tag, net, net->getGNEApplicationWindow()->getFileBucketHandler()->getDefaultBucket(FileBucket::Type::NETWORK)),
41
GUIGlObject(myTagProperty->getGLType(), "", GUIIconSubSys::getIcon(myTagProperty->getGUIIcon())),
42
myShapeEdited(false) {
43
}
44
45
46
GNENetworkElement::GNENetworkElement(GNENet* net, const std::string& id, SumoXMLTag tag) :
47
GNEAttributeCarrier(tag, net, net->getGNEApplicationWindow()->getFileBucketHandler()->getDefaultBucket(FileBucket::Type::NETWORK)),
48
GUIGlObject(myTagProperty->getGLType(), id,
49
GUIIconSubSys::getIcon(myTagProperty->getGUIIcon())),
50
myShapeEdited(false) {
51
}
52
53
54
GNENetworkElement::~GNENetworkElement() {}
55
56
57
GNEHierarchicalElement*
58
GNENetworkElement::getHierarchicalElement() {
59
return this;
60
}
61
62
63
GUIGlObject*
64
GNENetworkElement::getGUIGlObject() {
65
return this;
66
}
67
68
69
const GUIGlObject*
70
GNENetworkElement::getGUIGlObject() const {
71
return this;
72
}
73
74
75
FileBucket*
76
GNENetworkElement::getFileBucket() const {
77
return myFileBucket;
78
}
79
80
81
bool
82
GNENetworkElement::GNENetworkElement::isNetworkElementValid() const {
83
// implement in children
84
return true;
85
}
86
87
88
std::string
89
GNENetworkElement::GNENetworkElement::getNetworkElementProblem() const {
90
// implement in children
91
return "";
92
}
93
94
95
GUIParameterTableWindow*
96
GNENetworkElement::getParameterWindow(GUIMainWindow& app, GUISUMOAbstractView&) {
97
// Create table
98
GUIParameterTableWindow* ret = new GUIParameterTableWindow(app, *this);
99
// Iterate over attributes
100
for (const auto& attributeProperty : myTagProperty->getAttributeProperties()) {
101
// Add attribute and set it dynamic if aren't unique
102
if (attributeProperty->isUnique()) {
103
ret->mkItem(attributeProperty->getAttrStr().c_str(), false, getAttribute(attributeProperty->getAttr()));
104
} else {
105
ret->mkItem(attributeProperty->getAttrStr().c_str(), true, getAttribute(attributeProperty->getAttr()));
106
}
107
}
108
// close building
109
ret->closeBuilding();
110
return ret;
111
}
112
113
114
bool
115
GNENetworkElement::isGLObjectLocked() const {
116
if (myNet->getViewNet()->getEditModes().isCurrentSupermodeNetwork()) {
117
return myNet->getViewNet()->getLockManager().isObjectLocked(getType(), isAttributeCarrierSelected());
118
} else {
119
return true;
120
}
121
}
122
123
124
void
125
GNENetworkElement::markAsFrontElement() {
126
markForDrawingFront();
127
}
128
129
130
void
131
GNENetworkElement::selectGLObject() {
132
if (isAttributeCarrierSelected()) {
133
unselectAttributeCarrier();
134
} else {
135
selectAttributeCarrier();
136
}
137
// update information label
138
myNet->getViewParent()->getSelectorFrame()->getSelectionInformation()->updateInformationLabel();
139
}
140
141
142
const std::string
143
GNENetworkElement::getOptionalName() const {
144
try {
145
return getAttribute(SUMO_ATTR_NAME);
146
} catch (InvalidArgument&) {
147
return "";
148
}
149
}
150
151
152
std::string
153
GNENetworkElement::getPopUpID() const {
154
if (myTagProperty->getTag() == SUMO_TAG_CONNECTION) {
155
return getAttribute(SUMO_ATTR_FROM) + "_" + getAttribute(SUMO_ATTR_FROM_LANE) + " -> " + getAttribute(SUMO_ATTR_TO) + "_" + getAttribute(SUMO_ATTR_TO_LANE);
156
} else {
157
return getTagStr() + ": " + getID();
158
}
159
}
160
161
162
std::string
163
GNENetworkElement::getHierarchyName() const {
164
if (myTagProperty->getTag() == SUMO_TAG_LANE) {
165
return toString(SUMO_TAG_LANE) + " " + getAttribute(SUMO_ATTR_INDEX);
166
} else if (myTagProperty->getTag() == SUMO_TAG_CONNECTION) {
167
return getAttribute(SUMO_ATTR_FROM_LANE) + " -> " + getAttribute(SUMO_ATTR_TO_LANE);
168
} else if ((myTagProperty->getTag() == SUMO_TAG_EDGE) || (myTagProperty->getTag() == SUMO_TAG_CROSSING)) {
169
return getPopUpID();
170
} else {
171
return getTagStr();
172
}
173
}
174
175
176
void
177
GNENetworkElement::setShapeEdited(const bool value) {
178
myShapeEdited = value;
179
}
180
181
182
bool
183
GNENetworkElement::isShapeEdited() const {
184
return myShapeEdited;
185
}
186
187
188
int
189
GNENetworkElement::getGeometryPointUnderCursorShapeEdited() const {
190
const auto& s = myNet->getViewNet()->getVisualisationSettings();
191
// calculate squared geometry point radius depending of edited item
192
double geometryPointRadius = s.neteditSizeSettings.polygonGeometryPointRadius;
193
if (myTagProperty->getTag() == SUMO_TAG_JUNCTION) {
194
geometryPointRadius = s.neteditSizeSettings.junctionGeometryPointRadius;
195
} else if (myTagProperty->getTag() == SUMO_TAG_EDGE) {
196
geometryPointRadius = s.neteditSizeSettings.edgeGeometryPointRadius;
197
} else if (myTagProperty->getTag() == SUMO_TAG_LANE) {
198
geometryPointRadius = s.neteditSizeSettings.laneGeometryPointRadius;
199
} else if (myTagProperty->getTag() == SUMO_TAG_CONNECTION) {
200
geometryPointRadius = s.neteditSizeSettings.connectionGeometryPointRadius;
201
} else if (myTagProperty->getTag() == SUMO_TAG_CROSSING) {
202
geometryPointRadius = s.neteditSizeSettings.crossingGeometryPointRadius;
203
}
204
const auto geometryPointRadiusSquared = (geometryPointRadius * geometryPointRadius);
205
const auto shape = getAttributePositionVector(SUMO_ATTR_SHAPE);
206
const auto mousePos = myNet->getViewNet()->getPositionInformation();
207
for (int i = 0; i < (int)shape.size(); i++) {
208
if (shape[i].distanceSquaredTo2D(mousePos) < geometryPointRadiusSquared) {
209
return i;
210
}
211
}
212
return -1;
213
}
214
215
216
void
217
GNENetworkElement::simplifyShapeEdited(GNEUndoList* undoList) {
218
auto shape = getAttributePositionVector(SUMO_ATTR_SHAPE);
219
const Boundary b = shape.getBoxBoundary();
220
// create a square as simplified shape
221
PositionVector simplifiedShape;
222
simplifiedShape.push_back(Position(b.xmin(), b.ymin()));
223
simplifiedShape.push_back(Position(b.xmin(), b.ymax()));
224
simplifiedShape.push_back(Position(b.xmax(), b.ymax()));
225
simplifiedShape.push_back(Position(b.xmax(), b.ymin()));
226
if (shape.isClosed()) {
227
simplifiedShape.push_back(simplifiedShape[0]);
228
}
229
setAttribute(SUMO_ATTR_SHAPE, toString(simplifiedShape), undoList);
230
}
231
232
233
void
234
GNENetworkElement::straigthenShapeEdited(GNEUndoList* undoList) {
235
const auto shape = getAttributePositionVector(SUMO_ATTR_SHAPE);
236
PositionVector straigthenShape;
237
straigthenShape.push_front(shape.front());
238
straigthenShape.push_back(shape.back());
239
setAttribute(SUMO_ATTR_SHAPE, toString(straigthenShape), undoList);
240
}
241
242
243
void
244
GNENetworkElement::closeShapeEdited(GNEUndoList* undoList) {
245
auto shape = getAttributePositionVector(SUMO_ATTR_SHAPE);
246
shape.closePolygon();
247
setAttribute(SUMO_ATTR_SHAPE, toString(shape), undoList);
248
}
249
250
251
void
252
GNENetworkElement::openShapeEdited(GNEUndoList* undoList) {
253
auto shape = getAttributePositionVector(SUMO_ATTR_SHAPE);
254
shape.pop_back();
255
setAttribute(SUMO_ATTR_SHAPE, toString(shape), undoList);
256
}
257
258
259
void
260
GNENetworkElement::setFirstGeometryPointShapeEdited(int index, GNEUndoList* undoList) {
261
const auto shape = getAttributePositionVector(SUMO_ATTR_SHAPE);
262
PositionVector newShape;
263
for (int i = index; i < (int)shape.size(); i++) {
264
newShape.push_back(shape[i]);
265
}
266
for (int i = 0; i < index; i++) {
267
newShape.push_back(shape[i]);
268
}
269
setAttribute(SUMO_ATTR_SHAPE, toString(newShape), undoList);
270
}
271
272
273
void
274
GNENetworkElement::deleteGeometryPointShapeEdited(int index, GNEUndoList* undoList) {
275
const auto shape = getAttributePositionVector(SUMO_ATTR_SHAPE);
276
PositionVector newShape;
277
for (int i = 0; i < (int)shape.size(); i++) {
278
if (i != index) {
279
newShape.push_back(shape[i]);
280
}
281
}
282
setAttribute(SUMO_ATTR_SHAPE, toString(newShape), undoList);
283
}
284
285
286
void
287
GNENetworkElement::resetShapeEdited(GNEUndoList* /*undoList*/) {
288
289
}
290
291
292
void
293
GNENetworkElement::setNetworkElementID(const std::string& newID) {
294
// set microsim ID
295
setMicrosimID(newID);
296
// enable save add elements if this network element has children
297
if ((getChildAdditionals().size() > 0) || (getChildTAZSourceSinks().size() > 0)) {
298
myNet->getSavingStatus()->requireSaveAdditionals();
299
}
300
// enable save demand elements if this network element has children
301
if (getChildDemandElements().size() > 0) {
302
myNet->getSavingStatus()->requireSaveDemandElements();
303
}
304
// enable save data elements if this network element has children
305
if (getChildGenericDatas().size() > 0) {
306
myNet->getSavingStatus()->requireSaveDataElements();
307
}
308
}
309
310
311
bool
312
GNENetworkElement::checkDrawingBoundarySelection() const {
313
if (!gViewObjectsHandler.selectingUsingRectangle()) {
314
return true;
315
} else if (!gViewObjectsHandler.isObjectSelected(this)) {
316
return true;
317
} else {
318
return false;
319
}
320
}
321
322
323
GUIGLObjectPopupMenu*
324
GNENetworkElement::getShapeEditedPopUpMenu(GUIMainWindow& app, GUISUMOAbstractView& parent, const PositionVector& shape) {
325
GUIGLObjectPopupMenu* ret = new GUIGLObjectPopupMenu(app, parent, this);
326
const std::string headerName = TLF("% (Edited shape)", getFullName());
327
new MFXMenuHeader(ret, app.getBoldFont(), headerName.c_str(), getGLIcon(), nullptr, 0);
328
if (OptionsCont::getOptions().getBool("gui-testing")) {
329
GUIDesigns::buildFXMenuCommand(ret, TL("Copy test coordinates to clipboard"), nullptr, ret, MID_COPY_TEST_COORDINATES);
330
}
331
// add separator
332
new FXMenuSeparator(ret);
333
// only allow open/close for junctions
334
if (myTagProperty->getTag() == SUMO_TAG_JUNCTION) {
335
FXMenuCommand* simplifyShape = GUIDesigns::buildFXMenuCommand(ret, TL("Simplify shape"), TL("Replace current shape with a rectangle"), nullptr, &parent, MID_GNE_SHAPEEDITED_SIMPLIFY);
336
// disable simplify shape if polygon is only a line
337
if (shape.size() <= 2) {
338
simplifyShape->disable();
339
}
340
if (shape.isClosed()) {
341
GUIDesigns::buildFXMenuCommand(ret, TL("Open shape"), TL("Open junction's shape"), nullptr, &parent, MID_GNE_SHAPEEDITED_OPEN);
342
} else {
343
GUIDesigns::buildFXMenuCommand(ret, TL("Close shape"), TL("Close junction's shape"), nullptr, &parent, MID_GNE_SHAPEEDITED_CLOSE);
344
}
345
} else {
346
FXMenuCommand* straightenShape = GUIDesigns::buildFXMenuCommand(ret, TL("Straighten shape"), TL("Replace current shape with a rectangle"), nullptr, &parent, MID_GNE_SHAPEEDITED_STRAIGHTEN);
347
// disable straighten shape if polygon is already straight
348
if (shape.size() <= 2) {
349
straightenShape->disable();
350
}
351
}
352
// create a extra FXMenuCommand if mouse is over a vertex
353
const int index = getGeometryPointUnderCursorShapeEdited();
354
if (index != -1) {
355
FXMenuCommand* removeGeometryPoint = GUIDesigns::buildFXMenuCommand(ret, TL("Remove geometry point (shift+click)"), TL("Remove geometry point under mouse"), nullptr, &parent, MID_GNE_SHAPEEDITED_DELETE_GEOMETRY_POINT);
356
FXMenuCommand* setFirstPoint = GUIDesigns::buildFXMenuCommand(ret, TL("Set first geometry point"), TL("Set first geometry point"), nullptr, &parent, MID_GNE_SHAPEEDITED_SET_FIRST_POINT);
357
// disable setFirstPoint if shape only have three points
358
if ((shape.isClosed() && (shape.size() <= 4)) || (!shape.isClosed() && (shape.size() <= 2))) {
359
removeGeometryPoint->disable();
360
}
361
// disable setFirstPoint if mouse is over first point
362
if (index == 0) {
363
setFirstPoint->disable();
364
}
365
}
366
// add separator
367
new FXMenuSeparator(ret);
368
// add finish
369
GUIDesigns::buildFXMenuCommand(ret, TL("Finish editing (Enter)"), nullptr, &parent, MID_GNE_SHAPEEDITED_FINISH);
370
return ret;
371
}
372
373
374
int
375
GNENetworkElement::getVertexIndex(const PositionVector& shape, const Position& pos) {
376
// first check if vertex already exists
377
for (const auto& shapePosition : shape) {
378
if (shapePosition.distanceTo2D(pos) < myNet->getViewNet()->getVisualisationSettings().neteditSizeSettings.polygonGeometryPointRadius) {
379
return shape.indexOfClosest(shapePosition);
380
}
381
}
382
return -1;
383
}
384
385
/****************************************************************************/
386
387