Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
eclipse
GitHub Repository: eclipse/sumo
Path: blob/main/src/utils/gui/div/GUIViewObjectsHandler.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 GUIViewObjectsHandler.cpp
15
/// @author Pablo Alvarez Lopez
16
/// @date Jun 22
17
///
18
// class used for handle objects over view
19
/****************************************************************************/
20
#include <config.h>
21
#include <algorithm>
22
23
#include <utils/shapes/Shape.h>
24
25
#include "GUIViewObjectsHandler.h"
26
27
28
// ===========================================================================
29
// method definitions
30
// ===========================================================================
31
32
GUIViewObjectsHandler::GUIViewObjectsHandler() {}
33
34
35
void
36
GUIViewObjectsHandler::reset() {
37
// reset recompute boundaries
38
recomputeBoundaries = GLO_NETWORK;
39
// clear objects containers
40
mySortedSelectedObjects.clear();
41
mySelectedObjects.clear();
42
myNumberOfSelectedObjects = 0;
43
myRedrawPathElements.clear();
44
// reset marked elements
45
myMergingJunctions.clear();
46
markedEdge = nullptr;
47
markedLane = nullptr;
48
markedTAZ = nullptr;
49
markedRoute = nullptr;
50
markedFirstGeometryPoint = nullptr;
51
markedSecondGeometryPoint = nullptr;
52
}
53
54
55
const Position&
56
GUIViewObjectsHandler::getSelectionPosition() const {
57
return mySelectionPosition;
58
}
59
60
61
const Triangle&
62
GUIViewObjectsHandler::getSelectionTriangle() const {
63
return mySelectionTriangle;
64
}
65
66
67
void
68
GUIViewObjectsHandler::setSelectionPosition(const Position& pos) {
69
// set position selection
70
mySelectionPosition = pos;
71
// invalidate selection triangle
72
mySelectionTriangle = Triangle::INVALID;
73
}
74
75
76
void
77
GUIViewObjectsHandler::setSelectionTriangle(const Triangle& triangle) {
78
// invalidate position selection
79
mySelectionPosition = Position::INVALID;
80
// set selection triangle
81
mySelectionTriangle = triangle;
82
}
83
84
85
bool
86
GUIViewObjectsHandler::selectingUsingRectangle() const {
87
return mySelectionTriangle != Triangle::INVALID;
88
}
89
90
91
bool
92
GUIViewObjectsHandler::checkBoundaryParentObject(const GUIGlObject* GLObject, const double layer,
93
const GUIGlObject* parent) {
94
// first check if we're selecting for boundary
95
if (mySelectionTriangle == Triangle::INVALID) {
96
return false;
97
}
98
// try to find parent in seleted object
99
auto finder = mySelectedObjects.find(parent);
100
// if parent was found and was inserted with full boundary, insert it
101
if (finder != mySelectedObjects.end() && finder->second.first && !isObjectSelected(GLObject)) {
102
// insert element with full boundary
103
return selectObject(GLObject, layer, false, true, nullptr);
104
} else {
105
return false;
106
}
107
}
108
109
110
bool
111
GUIViewObjectsHandler::checkCircleObject(const GUIVisualizationSettings::Detail d, const GUIGlObject* GLObject,
112
const Position& center, const double radius, const double layer) {
113
// first check that object doesn't exist
114
if (isObjectSelected(GLObject)) {
115
return false;
116
} else {
117
// declare squared radius
118
const double squaredRadius = (radius * radius);
119
// continue depending if we're selecting a position or a boundary
120
if (selectingUsingRectangle()) {
121
// continue depending of detail level
122
if (d <= GUIVisualizationSettings::Detail::PreciseSelection) {
123
// check if triangle intersect with circle
124
if (mySelectionTriangle.intersectWithCircle(center, radius)) {
125
return selectObject(GLObject, layer, false, false, nullptr);
126
} else {
127
return false;
128
}
129
} else {
130
// simply check if center is within triangle
131
if (mySelectionTriangle.isPositionWithin(center)) {
132
return selectObject(GLObject, layer, false, false, nullptr);
133
} else {
134
return false;
135
}
136
}
137
} else if (mySelectionPosition != Position::INVALID) {
138
// check distance between selection position and center
139
if (mySelectionPosition.distanceSquaredTo2D(center) <= squaredRadius) {
140
return selectObject(GLObject, layer, false, false, nullptr);
141
} else {
142
return false;
143
}
144
} else {
145
return false;
146
}
147
}
148
}
149
150
151
bool
152
GUIViewObjectsHandler::checkGeometryPoint(const GUIVisualizationSettings::Detail d, const GUIGlObject* GLObject,
153
const PositionVector& shape, const int index, const double layer, const double radius) {
154
// obtain geometry point pos
155
const auto geometryPointPos = shape[index];
156
// declare squared radius
157
const double squaredRadius = (radius * radius);
158
// continue depending if we're selecting a position or a boundary
159
if (selectingUsingRectangle()) {
160
// continue depending of detail level
161
if (d <= GUIVisualizationSettings::Detail::PreciseSelection) {
162
// calculate boundary for geometry point
163
Boundary geometryPointBoundary;
164
geometryPointBoundary.add(geometryPointPos);
165
// check if center is within mySelectionBoundary
166
if (mySelectionTriangle.intersectWithCircle(geometryPointPos, radius)) {
167
return selectGeometryPoint(GLObject, index, layer);
168
} else {
169
return false;
170
}
171
} else {
172
// simply check if center is within triangle
173
if (mySelectionTriangle.isPositionWithin(geometryPointPos)) {
174
return selectObject(GLObject, layer, false, false, nullptr);
175
} else {
176
return false;
177
}
178
}
179
} else if (mySelectionPosition != Position::INVALID) {
180
// check distance between selection position and center
181
if (mySelectionPosition.distanceSquaredTo2D(geometryPointPos) <= squaredRadius) {
182
return selectGeometryPoint(GLObject, index, layer);
183
} else {
184
return false;
185
}
186
} else {
187
return false;
188
}
189
}
190
191
192
bool
193
GUIViewObjectsHandler::checkPositionOverShape(const GUIVisualizationSettings::Detail d, const GUIGlObject* GLObject,
194
const PositionVector& shape, const double layer, const double distance) {
195
// only process if we're selecting a precise position
196
if ((mySelectionPosition != Position::INVALID) && (d <= GUIVisualizationSettings::Detail::PreciseSelection)) {
197
// obtain nearest position over shape
198
const auto nearestOffset = shape.nearest_offset_to_point2D(mySelectionPosition);
199
const auto nearestPos = shape.positionAtOffset2D(nearestOffset);
200
// check distance nearest position and pos
201
if (mySelectionPosition.distanceSquaredTo2D(nearestPos) <= (distance * distance)) {
202
return selectPositionOverShape(GLObject, nearestPos, layer, nearestOffset);
203
} else {
204
return false;
205
}
206
} else {
207
return false;
208
}
209
}
210
211
212
bool
213
GUIViewObjectsHandler::checkShapeObject(const GUIGlObject* GLObject, const PositionVector& shape, const Boundary& shapeBoundary,
214
const double layer, const GNESegment* segment) {
215
// first check that object doesn't exist
216
if (isObjectSelected(GLObject)) {
217
return false;
218
} else if (selectingUsingRectangle()) {
219
// avoid invalid boundaries
220
if (!shapeBoundary.isInitialised()) {
221
return false;
222
}
223
// check if triangle contains the given shape
224
if (mySelectionTriangle.intersectWithShape(shape, shapeBoundary)) {
225
return selectObject(GLObject, layer, false, true, segment);
226
}
227
// no intersection, then return false
228
return false;
229
} else if (mySelectionPosition != Position::INVALID) {
230
// check if selection position is around shape
231
if (shape.around(mySelectionPosition)) {
232
return selectObject(GLObject, layer, false, false, segment);
233
} else {
234
return false;
235
}
236
} else {
237
return false;
238
}
239
}
240
241
242
bool
243
GUIViewObjectsHandler::selectObject(const GUIGlObject* GLObject, const double layer, const bool checkDuplicated,
244
const bool fullBoundary, const GNESegment* segment) {
245
// first check that object doesn't exist
246
if (checkDuplicated && isObjectSelected(GLObject)) {
247
return false;
248
} else {
249
auto& layerContainer = mySortedSelectedObjects[layer * -1];
250
layerContainer.append(ObjectContainer(GLObject));
251
mySelectedObjects[GLObject] = std::make_pair(fullBoundary, segment);
252
myNumberOfSelectedObjects++;
253
return true;
254
}
255
}
256
257
258
bool
259
GUIViewObjectsHandler::selectGeometryPoint(const GUIGlObject* GLObject, const int newIndex,
260
const double layer) {
261
// avoid to insert duplicated elements
262
for (auto& elementLayer : mySortedSelectedObjects) {
263
for (auto& element : elementLayer.second) {
264
if (element.object == GLObject) {
265
// avoid double points
266
for (auto& index : element.geometryPoints) {
267
if (index == newIndex) {
268
return false;
269
}
270
}
271
// add new index
272
element.geometryPoints.push_back(newIndex);
273
return true;
274
}
275
}
276
}
277
// no element found then add it
278
auto& layerContainer = mySortedSelectedObjects[layer * -1];
279
layerContainer.append(ObjectContainer(GLObject));
280
layerContainer.back().geometryPoints.push_back(newIndex);
281
mySelectedObjects[GLObject] = std::make_pair(false, nullptr);
282
myNumberOfSelectedObjects++;
283
return true;
284
}
285
286
287
bool
288
GUIViewObjectsHandler::selectPositionOverShape(const GUIGlObject* GLObject, const Position& pos, const double layer,
289
const double offset) {
290
// avoid to insert duplicated elements
291
for (auto& elementLayer : mySortedSelectedObjects) {
292
for (auto& element : elementLayer.second) {
293
if (element.object == GLObject) {
294
if (element.posOverShape != Position::INVALID) {
295
return false;
296
} else {
297
// set position and offset over shape
298
element.posOverShape = pos;
299
element.offset = offset;
300
return true;
301
}
302
}
303
}
304
}
305
// no element found then add it
306
auto& layerContainer = mySortedSelectedObjects[layer * -1];
307
layerContainer.append(ObjectContainer(GLObject));
308
layerContainer.back().posOverShape = pos;
309
mySelectedObjects[GLObject] = std::make_pair(false, nullptr);
310
myNumberOfSelectedObjects++;
311
return true;
312
}
313
314
315
bool
316
GUIViewObjectsHandler::isObjectSelected(const GUIGlObject* GLObject) const {
317
return mySelectedObjects.find(GLObject) != mySelectedObjects.end();
318
}
319
320
321
bool
322
GUIViewObjectsHandler::checkRectangleSelection(const GUIVisualizationSettings& s, const GUIGlObject* GLObject,
323
const double layer, const GUIGlObject* parent) {
324
if (!s.drawForRectangleSelection) {
325
return false;
326
} else {
327
return checkBoundaryParentObject(GLObject, layer, parent);
328
}
329
}
330
331
332
const GUIViewObjectsHandler::GLObjectsSortedContainer&
333
GUIViewObjectsHandler::getSelectedObjects() const {
334
return mySortedSelectedObjects;
335
}
336
337
338
const GNESegment*
339
GUIViewObjectsHandler::getSelectedSegment(const GUIGlObject* GLObject) const {
340
auto finder = mySelectedObjects.find(GLObject);
341
if (finder != mySelectedObjects.end()) {
342
return finder->second.second;
343
} else {
344
return nullptr;
345
}
346
}
347
348
349
const std::vector<int>&
350
GUIViewObjectsHandler::getSelectedGeometryPoints(const GUIGlObject* GLObject) const {
351
// avoid to insert duplicated elements
352
for (auto& elementLayer : mySortedSelectedObjects) {
353
for (auto& element : elementLayer.second) {
354
if (element.object == GLObject) {
355
return element.geometryPoints;
356
}
357
}
358
}
359
return myEmptyGeometryPoints;
360
}
361
362
363
const Position&
364
GUIViewObjectsHandler::getSelectedPositionOverShape(const GUIGlObject* GLObject) const {
365
// avoid to insert duplicated elements
366
for (auto& elementLayer : mySortedSelectedObjects) {
367
for (auto& element : elementLayer.second) {
368
if (element.object == GLObject) {
369
return element.posOverShape;
370
}
371
}
372
}
373
return Position::INVALID;
374
}
375
376
377
int
378
GUIViewObjectsHandler::getNumberOfSelectedObjects() const {
379
return myNumberOfSelectedObjects;
380
}
381
382
383
void
384
GUIViewObjectsHandler::reverseSelectedObjects() {
385
for (auto& layerContainer : mySortedSelectedObjects) {
386
std::reverse(layerContainer.second.begin(), layerContainer.second.end());
387
}
388
}
389
390
391
const std::set<const GNEPathElement*>&
392
GUIViewObjectsHandler::getRedrawPathElements() const {
393
return myRedrawPathElements;
394
}
395
396
397
bool
398
GUIViewObjectsHandler::isPathElementMarkForRedraw(const GNEPathElement* pathElement) const {
399
if (myRedrawPathElements.empty()) {
400
return false;
401
} else {
402
return myRedrawPathElements.find(pathElement) != myRedrawPathElements.end();
403
}
404
}
405
406
407
void
408
GUIViewObjectsHandler::addToRedrawPathElements(const GNEPathElement* pathElement) {
409
myRedrawPathElements.insert(pathElement);
410
}
411
412
413
const std::vector<const GNEJunction*>&
414
GUIViewObjectsHandler::getMergingJunctions() const {
415
return myMergingJunctions;
416
}
417
418
419
bool
420
GUIViewObjectsHandler::addMergingJunctions(const GNEJunction* junction) {
421
// avoid insert duplicated junctions
422
for (const auto mergingJunctions : myMergingJunctions) {
423
if (mergingJunctions == junction) {
424
return false;
425
}
426
}
427
myMergingJunctions.push_back(junction);
428
return true;
429
}
430
431
432
void
433
GUIViewObjectsHandler::updateFrontObject(const GUIGlObject* GLObject) {
434
ObjectContainer frontElement(nullptr);
435
// extract element
436
for (auto& elementLayer : mySortedSelectedObjects) {
437
auto it = elementLayer.second.begin();
438
while (it != elementLayer.second.end()) {
439
if (it->object == GLObject) {
440
// copy element to front element
441
frontElement.object = it->object;
442
frontElement.geometryPoints = it->geometryPoints;
443
// remove element from myElementsUnderCursor
444
it = elementLayer.second.erase(it);
445
} else {
446
it++;
447
}
448
}
449
}
450
// add element again wit a new layer
451
if (frontElement.object) {
452
mySortedSelectedObjects[(double)GLO_FRONTELEMENT].append(frontElement);
453
}
454
}
455
456
457
void
458
GUIViewObjectsHandler::isolateEdgeGeometryPoints() {
459
// declare object container for edge
460
ObjectContainer edgeWithGeometryPoints(nullptr);
461
// check if there are edges with geometry points in mySortedSelectedObjects
462
for (auto& elementLayer : mySortedSelectedObjects) {
463
for (auto element : elementLayer.second) {
464
if ((element.object->getType() == GLO_EDGE) && (element.geometryPoints.size() > 0)) {
465
edgeWithGeometryPoints = element;
466
}
467
}
468
}
469
// continue if something was found
470
if (edgeWithGeometryPoints.object != nullptr) {
471
// clear all selected objects
472
mySortedSelectedObjects.clear();
473
// add edge with geometry points as front element
474
mySortedSelectedObjects[(double)GLO_FRONTELEMENT].append(edgeWithGeometryPoints);
475
}
476
}
477
478
479
void
480
GUIViewObjectsHandler::ObjectContainerLayer::append(const ObjectContainer& objectContainer) {
481
if (capacity() == size()) {
482
if (size() < 10) {
483
reserve(size() + 10);
484
} else {
485
reserve(size() + 1000);
486
}
487
}
488
push_back(objectContainer);
489
}
490
491
/****************************************************************************/
492
493