Eclipse SUMO - Simulation of Urban MObility
Loading...
Searching...
No Matches
GUIViewObjectsHandler.cpp
Go to the documentation of this file.
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/****************************************************************************/
18// class used for handle objects over view
19/****************************************************************************/
20#include <config.h>
21#include <algorithm>
22
23#include <utils/shapes/Shape.h>
24
26
27
28// ===========================================================================
29// method definitions
30// ===========================================================================
31
33
34
35void
37 // reset recompute boundaries
39 // clear objects containers
41 mySelectedObjects.clear();
44 // reset marked elements
45 myMergingJunctions.clear();
46 markedEdge = nullptr;
47 markedLane = nullptr;
48 markedTAZ = nullptr;
49 markedRoute = nullptr;
52}
53
54
55const Position&
59
60
61const Triangle&
65
66
67void
69 // set position selection
71 // invalidate selection triangle
73}
74
75
76void
78 // invalidate position selection
80 // set selection triangle
81 mySelectionTriangle = triangle;
82}
83
84
85bool
89
90
91bool
93 const GUIGlObject* parent) {
94 // first check if we're selecting for boundary
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 && !isObjectSelected(GLObject)) {
102 // insert element with full boundary
103 return selectObject(GLObject, layer, false, nullptr);
104 } else {
105 return false;
106 }
107}
108
109
110bool
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
121 // continue depending of detail level
123 // check if triangle intersect with circle
124 if (mySelectionTriangle.intersectWithCircle(center, radius)) {
125 return selectObject(GLObject, layer, false, nullptr);
126 } else {
127 return false;
128 }
129 } else {
130 // simply check if center is within triangle
132 return selectObject(GLObject, layer, false, nullptr);
133 } else {
134 return false;
135 }
136 }
138 // check distance between selection position and center
139 if (mySelectionPosition.distanceSquaredTo2D(center) <= squaredRadius) {
140 return selectObject(GLObject, layer, false, nullptr);
141 } else {
142 return false;
143 }
144 } else {
145 return false;
146 }
147 }
148}
149
150
151bool
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
160 // continue depending of detail level
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, nullptr);
175 } else {
176 return false;
177 }
178 }
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
192bool
194 const PositionVector& shape, const double layer, const double distance) {
195 // only process if we're selecting a precise position
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
212bool
213GUIViewObjectsHandler::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, segment);
226 }
227 // no intersection, then return false
228 return false;
230 // check if selection position is around shape
231 if (shape.around(mySelectionPosition)) {
232 return selectObject(GLObject, layer, false, segment);
233 } else {
234 return false;
235 }
236 } else {
237 return false;
238 }
239}
240
241
242bool
243GUIViewObjectsHandler::selectObject(const GUIGlObject* GLObject, const double layer, const bool checkDuplicated,
244 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] = segment;
253 return true;
254 }
255}
256
257
258bool
259GUIViewObjectsHandler::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] = nullptr;
283 return true;
284}
285
286
287bool
288GUIViewObjectsHandler::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] = nullptr;
311 return true;
312}
313
314
315bool
317 return mySelectedObjects.find(GLObject) != mySelectedObjects.end();
318}
319
320
321bool
323 const double layer, const GUIGlObject* parent) {
325 return false;
326 } else {
327 return checkBoundaryParentObject(GLObject, layer, parent);
328 }
329}
330
331
336
337
338const GNESegment*
340 auto finder = mySelectedObjects.find(GLObject);
341 if (finder != mySelectedObjects.end()) {
342 return finder->second;
343 } else {
344 return nullptr;
345 }
346}
347
348
349const std::vector<int>&
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 }
360}
361
362
363const Position&
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
377int
381
382
383void
385 for (auto& layerContainer : mySortedSelectedObjects) {
386 std::reverse(layerContainer.second.begin(), layerContainer.second.end());
387 }
388}
389
390
391const std::set<const GNEPathElement*>&
395
396
397bool
399 if (myRedrawPathElements.empty()) {
400 return false;
401 } else {
402 return myRedrawPathElements.find(pathElement) != myRedrawPathElements.end();
403 }
404}
405
406
407void
411
412
413const std::vector<const GNEJunction*>&
417
418
419bool
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
432void
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
457void
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
473 // add edge with geometry points as front element
474 mySortedSelectedObjects[(double)GLO_FRONTELEMENT].append(edgeWithGeometryPoints);
475 }
476}
477
478
479void
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/****************************************************************************/
@ GLO_FRONTELEMENT
front element (used in netedit)
@ GLO_EDGE
an edge
@ GLO_NETWORK
The network - empty.
A class that stores a 2D geometrical boundary.
Definition Boundary.h:39
void add(double x, double y, double z=0)
Makes the boundary include the given coordinate.
Definition Boundary.cpp:75
bool isInitialised() const
check if Boundary is Initialised
Definition Boundary.cpp:256
bool checkShapeObject(const GUIGlObject *GLObject, const PositionVector &shape, const Boundary &shapeBoundary, const double layer, const GNESegment *segment)
check (closed) shape element
Triangle mySelectionTriangle
selection triangle
void setSelectionPosition(const Position &pos)
set selection position
void addToRedrawPathElements(const GNEPathElement *pathElement)
add path element to redrawing set
std::unordered_map< const GUIGlObject *, const GNESegment * > mySelectedObjects
map with selected elements and if was selected with full boundary (used only to avoid double selectio...
bool checkBoundaryParentObject(const GUIGlObject *GLObject, const double layer, const GUIGlObject *parent)
const GNERoute * markedRoute
marked route (used in create vehicle mode)
bool selectGeometryPoint(const GUIGlObject *GLObject, const int newIndex, const double layer)
add geometryPoint into list of elements under cursor
int getNumberOfSelectedObjects() const
get number of selected objects
std::vector< const GNEJunction * > myMergingJunctions
merging junctions
const Position & getSelectionPosition() const
const Triangle & getSelectionTriangle() const
get selection triangle
void reverseSelectedObjects()
reverse selected objects
void isolateEdgeGeometryPoints()
isolate edge geometry points (used for moving)
void reset()
reset view objects handler
const GUIGlObject * markedTAZ
marked TAZ (used in create TAZRel mode)
const Position & getSelectedPositionOverShape(const GUIGlObject *GLObject) const
get position over shape
bool addMergingJunctions(const GNEJunction *junction)
add to merging junctions (used for marking junctions to merge)
std::map< double, ObjectContainerLayer > GLObjectsSortedContainer
typedef for pack elements sorted by layer
void setSelectionTriangle(const Triangle &triangle)
set selection triangle
GUIGlObjectType recomputeBoundaries
recompute boundaries
const GLObjectsSortedContainer & getSelectedObjects() const
get all elements under cursor sorted by layer
const GNEEdge * markedEdge
marked edge (used in create edge mode, for splitting)
int myNumberOfSelectedObjects
number of selected objects
const GNELane * markedLane
marked lane (used in create edge mode, for splitting)
Position mySelectionPosition
position
bool isPathElementMarkForRedraw(const GNEPathElement *pathElement) const
check if the given path element has to be redraw again
const GUIGlObject * markedSecondGeometryPoint
marked first geometry point (used for moving/delete geometry points)
bool isObjectSelected(const GUIGlObject *GLObject) const
check if element was already selected
const std::vector< int > & getSelectedGeometryPoints(const GUIGlObject *GLObject) const
get geometry points for the given glObject
void updateFrontObject(const GUIGlObject *GLObject)
move the given object to the front (currently used only in netedit)
bool checkGeometryPoint(const GUIVisualizationSettings::Detail d, const GUIGlObject *GLObject, const PositionVector &shape, const int index, const double layer, const double radius)
check if mouse is within geometry point
bool checkPositionOverShape(const GUIVisualizationSettings::Detail d, const GUIGlObject *GLObject, const PositionVector &shape, const double layer, const double distance)
check if mouse is within geometry point
std::set< const GNEPathElement * > myRedrawPathElements
set with path elements marked for redrawing
const GNESegment * getSelectedSegment(const GUIGlObject *GLObject) const
get segment associated with the given GLObject (if exist)
GLObjectsSortedContainer mySortedSelectedObjects
selected element sorted by layer
bool selectingUsingRectangle() const
return true if we're selecting using a triangle
std::vector< int > myEmptyGeometryPoints
empty geometry points
bool checkRectangleSelection(const GUIVisualizationSettings &s, const GUIGlObject *GLObject, const double layer, const GUIGlObject *parent)
check rectangle selection
const GUIGlObject * markedFirstGeometryPoint
marked first geometry point (used for moving/delete geometry points)
bool selectObject(const GUIGlObject *GLObject, const double layer, const bool checkDuplicated, const GNESegment *segment)
const std::set< const GNEPathElement * > & getRedrawPathElements() const
bool checkCircleObject(const GUIVisualizationSettings::Detail d, const GUIGlObject *GLObject, const Position &center, const double radius, const double layer)
check if mouse is within elements geometry (for circles)
bool selectPositionOverShape(const GUIGlObject *GLObject, const Position &pos, const double layer, const double offset)
select position over shape (for example, the position over a lane shape)
const std::vector< const GNEJunction * > & getMergingJunctions() const
Stores the information about how to visualize structures.
bool drawForRectangleSelection
whether drawing is performed for the purpose of selecting objects using a rectangle
A point in 2D or 3D with translation and scaling methods.
Definition Position.h:37
double distanceSquaredTo2D(const Position &p2) const
returns the square of the distance to another position (Only using x and y positions)
Definition Position.h:278
static const Position INVALID
used to indicate that a position is valid
Definition Position.h:323
A list of positions.
double nearest_offset_to_point2D(const Position &p, bool perpendicular=true) const
return the nearest offest to point 2D
Position positionAtOffset2D(double pos, double lateralOffset=0, bool extrapolateBeyond=false) const
Returns the position at the given length.
bool around(const Position &p, double offset=0) const
Returns the information whether the position vector describes a polygon lying around the given point.
A simple triangle defined in 3D.
Definition Triangle.h:35
bool isPositionWithin(const Position &pos) const
check if the given position is within this triangle
Definition Triangle.cpp:53
static const Triangle INVALID
invalid triangle
Definition Triangle.h:39
bool intersectWithShape(const PositionVector &shape) const
check if the given shape is within or intersect with this triangle
Definition Triangle.cpp:68
bool intersectWithCircle(const Position &center, const double radius) const
check if the given circle intersect with this triangle
Definition Triangle.cpp:104
std::vector< int > geometryPoints
vector with geometry points
void append(const ObjectContainer &objectContainer)