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-2024 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 Boundary&
65
66
67void
69 // set position selection
71 // invalidate selection boundary
74}
75
76
77void
79 // invalidate position selection
81 // set selection boundary
82 mySelectionBoundary = boundary;
83 mySelectionBoundaryShape = boundary.getShape(false);
84}
85
86
87bool
89 const GUIGlObject* parent) {
90 // first check if we're selecting for boundary
92 return false;
93 }
94 // try to find parent in seleted object
95 auto finder = mySelectedObjects.find(parent);
96 // if parent was found and was inserted with full boundary, insert it
97 if (finder != mySelectedObjects.end() && finder->second.first && !isObjectSelected(GLObject)) {
98 // insert element with full boundary
99 return selectObject(GLObject, layer, false, true, nullptr);
100 } else {
101 return false;
102 }
103}
104
105
106bool
108 const Position& center, const double radius, const Boundary& circleBoundary, const double layer) {
109 // first check that object doesn't exist
110 if (isObjectSelected(GLObject)) {
111 return false;
112 } else {
113 // declare squared radius
114 const double squaredRadius = (radius * radius);
115 // continue depending if we're selecting a position or a boundary
117 // continue depending of detail level
119 // avoid empty boundaries
120 if (!circleBoundary.isInitialised()) {
121 return false;
122 }
123 // check if selection boundary contains the centering boundary of object
125 return selectObject(GLObject, layer, false, true, nullptr);
126 }
127 // check if boundary overlaps
128 if (mySelectionBoundary.overlapsWith(circleBoundary)) {
129 return selectObject(GLObject, layer, false, false, nullptr);
130 }
131 // check if the four boundary vertex are within circle
132 for (const auto& vertex : mySelectionBoundaryShape) {
133 if (vertex.distanceSquaredTo2D(center) <= squaredRadius) {
134 return selectObject(GLObject, layer, false, false, nullptr);
135 }
136 }
137 // no intersection, then return false
138 return false;
139 } else {
140 // check if center is within mySelectionBoundary
141 if (mySelectionBoundary.around2D(center)) {
142 return selectObject(GLObject, layer, false, false, nullptr);
143 } else {
144 return false;
145 }
146 }
148 // check distance between selection position and center
149 if (mySelectionPosition.distanceSquaredTo2D(center) <= squaredRadius) {
150 return selectObject(GLObject, layer, false, false, nullptr);
151 } else {
152 return false;
153 }
154 } else {
155 return false;
156 }
157 }
158}
159
160
161bool
163 const PositionVector& shape, const int index, const double layer, const double radius) {
164 // obtain geometry point pos
165 const auto geometryPointPos = shape[index];
166 // declare squared radius
167 const double squaredRadius = (radius * radius);
168 // continue depending if we're selecting a position or a boundary
170 // continue depending of detail level
172 // make a boundary using center and radius
173 Boundary geometryPointBoundary;
174 geometryPointBoundary.add(geometryPointPos);
175 geometryPointBoundary.grow(radius);
176 // check if boundary is whithin selection boundary
177 if (mySelectionBoundary.contains2D(geometryPointBoundary)) {
178 return selectGeometryPoint(GLObject, index, layer);
179 } else if (mySelectionBoundary.overlapsWith(geometryPointBoundary)) {
180 return selectGeometryPoint(GLObject, index, layer);
181 } else {
182 // check if the four boundary vertex are within circle
183 for (const auto& vertex : mySelectionBoundaryShape) {
184 if (vertex.distanceSquaredTo2D(geometryPointPos) <= squaredRadius) {
185 return selectGeometryPoint(GLObject, index, layer);
186 }
187 }
188 // no intersection, then return false
189 return false;
190 }
191 } else {
192 // check if center is within mySelectionBoundary
193 if (mySelectionBoundary.around2D(geometryPointPos)) {
194 return selectGeometryPoint(GLObject, index, layer);
195 } else {
196 return false;
197 }
198 }
200 // check distance between selection position and center
201 if (mySelectionPosition.distanceSquaredTo2D(geometryPointPos) <= squaredRadius) {
202 return selectGeometryPoint(GLObject, index, layer);
203 } else {
204 return false;
205 }
206 } else {
207 return false;
208 }
209}
210
211
212bool
214 const PositionVector& shape, const double layer, const double distance) {
215 // only process if we're selecting a precise position
217 // obtain nearest position over shape
218 const auto nearestOffset = shape.nearest_offset_to_point2D(mySelectionPosition);
219 const auto nearestPos = shape.positionAtOffset2D(nearestOffset);
220 // check distance nearest position and pos
221 if (mySelectionPosition.distanceSquaredTo2D(nearestPos) <= (distance * distance)) {
222 return selectPositionOverShape(GLObject, nearestPos, layer, nearestOffset);
223 } else {
224 return false;
225 }
226 } else {
227 return false;
228 }
229}
230
231
232bool
233GUIViewObjectsHandler::checkShapeObject(const GUIGlObject* GLObject, const PositionVector& shape, const Boundary& shapeBoundary,
234 const double layer, const GNESegment* segment) {
235 // first check that object doesn't exist
236 if (isObjectSelected(GLObject)) {
237 return false;
238 } else if (mySelectionBoundary.isInitialised()) {
239 // avoid invalid boundaries
240 if (!shapeBoundary.isInitialised()) {
241 return false;
242 }
243 // check if selection boundary contains the centering boundary of object
244 if (mySelectionBoundary.contains2D(shapeBoundary)) {
245 return selectObject(GLObject, layer, false, true, segment);
246 }
247 // check if shape crosses to selection boundary
248 for (int i = 1; i < (int)shape.size(); i++) {
249 if (mySelectionBoundary.crosses(shape[i - 1], shape[i])) {
250 return selectObject(GLObject, layer, false, false, segment);
251 }
252 }
253 // no intersection, then return false
254 return false;
256 // check if selection position is around shape
257 if (shape.around(mySelectionPosition)) {
258 return selectObject(GLObject, layer, false, false, segment);
259 } else {
260 return false;
261 }
262 } else {
263 return false;
264 }
265}
266
267
268bool
269GUIViewObjectsHandler::selectObject(const GUIGlObject* GLObject, const double layer, const bool checkDuplicated,
270 const bool fullBoundary, const GNESegment* segment) {
271 // first check that object doesn't exist
272 if (checkDuplicated && isObjectSelected(GLObject)) {
273 return false;
274 } else {
275 auto& layerContainer = mySortedSelectedObjects[layer * -1];
276 layerContainer.insert(layerContainer.begin(), ObjectContainer(GLObject));
277 mySelectedObjects[GLObject] = std::make_pair(fullBoundary, segment);
279 return true;
280 }
281}
282
283
284bool
285GUIViewObjectsHandler::selectGeometryPoint(const GUIGlObject* GLObject, const int newIndex,
286 const double layer) {
287 // avoid to insert duplicated elements
288 for (auto& elementLayer : mySortedSelectedObjects) {
289 for (auto& element : elementLayer.second) {
290 if (element.object == GLObject) {
291 // avoid double points
292 for (auto& index : element.geometryPoints) {
293 if (index == newIndex) {
294 return false;
295 }
296 }
297 // add new index
298 element.geometryPoints.push_back(newIndex);
299 return true;
300 }
301 }
302 }
303 // no element found then add it
304 auto& layerContainer = mySortedSelectedObjects[layer * -1];
305 auto it = layerContainer.insert(layerContainer.begin(), ObjectContainer(GLObject));
306 it->geometryPoints.push_back(newIndex);
307 mySelectedObjects[GLObject] = std::make_pair(false, nullptr);
309 return true;
310}
311
312
313bool
314GUIViewObjectsHandler::selectPositionOverShape(const GUIGlObject* GLObject, const Position& pos, const double layer,
315 const double offset) {
316 // avoid to insert duplicated elements
317 for (auto& elementLayer : mySortedSelectedObjects) {
318 for (auto& element : elementLayer.second) {
319 if (element.object == GLObject) {
320 if (element.posOverShape != Position::INVALID) {
321 return false;
322 } else {
323 // set position and offset over shape
324 element.posOverShape = pos;
325 element.offset = offset;
326 return true;
327 }
328 }
329 }
330 }
331 // no element found then add it
332 auto& layerContainer = mySortedSelectedObjects[layer * -1];
333 auto it = layerContainer.insert(layerContainer.begin(), ObjectContainer(GLObject));
334 it->posOverShape = pos;
335 mySelectedObjects[GLObject] = std::make_pair(false, nullptr);
337 return true;
338}
339
340
341bool
343 return mySelectedObjects.find(GLObject) != mySelectedObjects.end();
344}
345
346
347bool
349 const double layer, const GUIGlObject* parent) {
351 return false;
352 } else {
353 return checkBoundaryParentObject(GLObject, layer, parent);
354 }
355}
356
357
362
363
364const GNESegment*
366 auto finder = mySelectedObjects.find(GLObject);
367 if (finder != mySelectedObjects.end()) {
368 return finder->second.second;
369 } else {
370 return nullptr;
371 }
372}
373
374
375const std::vector<int>&
377 // avoid to insert duplicated elements
378 for (auto& elementLayer : mySortedSelectedObjects) {
379 for (auto& element : elementLayer.second) {
380 if (element.object == GLObject) {
381 return element.geometryPoints;
382 }
383 }
384 }
386}
387
388
389const Position&
391 // avoid to insert duplicated elements
392 for (auto& elementLayer : mySortedSelectedObjects) {
393 for (auto& element : elementLayer.second) {
394 if (element.object == GLObject) {
395 return element.posOverShape;
396 }
397 }
398 }
399 return Position::INVALID;
400}
401
402
403int
407
408
409const std::set<const GNEPathElement*>&
413
414
415bool
417 if (myRedrawPathElements.empty()) {
418 return false;
419 } else {
420 return myRedrawPathElements.find(pathElement) != myRedrawPathElements.end();
421 }
422}
423
424
425void
429
430
431const std::vector<const GNEJunction*>&
435
436
437bool
439 // avoid insert duplicated junctions
440 for (const auto mergingJunctions : myMergingJunctions) {
441 if (mergingJunctions == junction) {
442 return false;
443 }
444 }
445 myMergingJunctions.push_back(junction);
446 return true;
447}
448
449
450void
452 ObjectContainer frontElement(nullptr);
453 // extract element
454 for (auto& elementLayer : mySortedSelectedObjects) {
455 auto it = elementLayer.second.begin();
456 while (it != elementLayer.second.end()) {
457 if (it->object == GLObject) {
458 // copy element to front element
459 frontElement.object = it->object;
460 frontElement.geometryPoints = it->geometryPoints;
461 // remove element from myElementsUnderCursor
462 it = elementLayer.second.erase(it);
463 } else {
464 it++;
465 }
466 }
467 }
468 // add element again wit a new layer
469 if (frontElement.object) {
470 mySortedSelectedObjects[(double)GLO_FRONTELEMENT].push_back(frontElement);
471 }
472}
473
474
475void
477 // declare object container for edge
478 ObjectContainer edgeWithGeometryPoints(nullptr);
479 // check if there are edges with geometry points in mySortedSelectedObjects
480 for (auto& elementLayer : mySortedSelectedObjects) {
481 for (auto element : elementLayer.second) {
482 if ((element.object->getType() == GLO_EDGE) && (element.geometryPoints.size() > 0)) {
483 edgeWithGeometryPoints = element;
484 }
485 }
486 }
487 // continue if something was found
488 if (edgeWithGeometryPoints.object != nullptr) {
489 // clear all selected objects
491 // add edge with geometry points as front element
492 mySortedSelectedObjects[(double)GLO_FRONTELEMENT].push_back(edgeWithGeometryPoints);
493 }
494}
495
496/****************************************************************************/
@ 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:78
bool isInitialised() const
check if Boundary is Initialised
Definition Boundary.cpp:259
void reset()
Resets the boundary.
Definition Boundary.cpp:66
Boundary & grow(double by)
extends the boundary by the given amount
Definition Boundary.cpp:343
bool overlapsWith(const AbstractPoly &poly, double offset=0) const
Returns whether the boundary overlaps with the given polygon.
Definition Boundary.cpp:197
bool contains2D(const Boundary &b) const
return true if this boundary contains the given boundary (only X-Y)
Definition Boundary.cpp:232
PositionVector getShape(const bool closeShape) const
get position vector (shape) based on this boundary
Definition Boundary.cpp:447
bool around2D(const Position &p, double offset=0) const
Returns whether the boundary contains the given 2D coordinate (position)
Definition Boundary.cpp:181
bool crosses(const Position &p1, const Position &p2) const
Returns whether the boundary crosses the given line.
Definition Boundary.cpp:218
virtual Boundary getCenteringBoundary() const =0
Boundary mySelectionBoundary
selection boundary
bool checkShapeObject(const GUIGlObject *GLObject, const PositionVector &shape, const Boundary &shapeBoundary, const double layer, const GNESegment *segment)
check (closed) shape element
PositionVector mySelectionBoundaryShape
selection boundary (shape)
bool checkCircleObject(const GUIVisualizationSettings::Detail d, const GUIGlObject *GLObject, const Position &center, const double radius, const Boundary &circleBoundary, const double layer)
check if mouse is within elements geometry (for circles)
const Boundary & getSelectionBoundary() const
get selection boundary
void setSelectionPosition(const Position &pos)
set selection position
void addToRedrawPathElements(const GNEPathElement *pathElement)
add path element to redrawing set
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
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
std::map< double, std::vector< ObjectContainer > > GLObjectsSortedContainer
typedef for pack elements sorted by layer
bool selectObject(const GUIGlObject *GLObject, const double layer, const bool checkDuplicated, const bool fullBoundary, const GNESegment *segment)
bool addMergingJunctions(const GNEJunction *junction)
add to merging junctions (used for marking junctions to merge)
void setSelectionBoundary(const Boundary &boundary)
set selection boundary
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)
std::unordered_map< const GUIGlObject *, std::pair< bool, const GNESegment * > > mySelectedObjects
map with selected elements and if was selected with full boundary (used only to avoid double selectio...
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
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)
const std::set< const GNEPathElement * > & getRedrawPathElements() const
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:281
static const Position INVALID
used to indicate that a position is valid
Definition Position.h:322
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) 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.
std::vector< int > geometryPoints
vector with geometry points