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();
43 // reset marked elements
44 myMergingJunctions.clear();
45 markedEdge = nullptr;
46 markedLane = nullptr;
47 markedTAZ = nullptr;
48 markedRoute = nullptr;
51}
52
53
54const Position&
58
59
60const Boundary&
64
65
66void
68 // set position selection
70 // invalidate selection boundary
73}
74
75
76void
78 // invalidate position selection
80 // set selection boundary
81 mySelectionBoundary = boundary;
82 mySelectionBoundaryShape = boundary.getShape(false);
83}
84
85
86bool
88 const double layer) {
89 // first check if we're selecting for boundary
91 return false;
92 }
93 // try to find parent in seleted object
94 auto finder = mySelectedObjects.find(parent);
95 // if parent was found and was inserted with full boundary, insert it
96 if (finder != mySelectedObjects.end() && finder->second.first && !isObjectSelected(GLObject)) {
97 // insert element with full boundary
98 return selectObject(GLObject, layer, false, true, nullptr);
99 } else {
100 return false;
101 }
102}
103
104
105bool
107 const Position& center, const double radius, const Boundary& circleBoundary, const double layer) {
108 // first check that object doesn't exist
109 if (isObjectSelected(GLObject)) {
110 return false;
111 } else {
112 // declare squared radius
113 const double squaredRadius = (radius * radius);
114 // continue depending if we're selecting a position or a boundary
116 // continue depending of detail level
118 // avoid empty boundaries
119 if (!circleBoundary.isInitialised()) {
120 return false;
121 }
122 // check if selection boundary contains the centering boundary of object
124 return selectObject(GLObject, layer, false, true, nullptr);
125 }
126 // check if boundary overlaps
127 if (mySelectionBoundary.overlapsWith(circleBoundary)) {
128 return selectObject(GLObject, layer, false, false, nullptr);
129 }
130 // check if the four boundary vertex are within circle
131 for (const auto& vertex : mySelectionBoundaryShape) {
132 if (vertex.distanceSquaredTo2D(center) <= squaredRadius) {
133 return selectObject(GLObject, layer, false, false, nullptr);
134 }
135 }
136 // no intersection, then return false
137 return false;
138 } else {
139 // check if center is within mySelectionBoundary
140 if (mySelectionBoundary.around2D(center)) {
141 return selectObject(GLObject, layer, false, false, nullptr);
142 } else {
143 return false;
144 }
145 }
147 // check distance between selection position and center
148 if (mySelectionPosition.distanceSquaredTo2D(center) <= squaredRadius) {
149 return selectObject(GLObject, layer, false, false, nullptr);
150 } else {
151 return false;
152 }
153 } else {
154 return false;
155 }
156 }
157}
158
159
160bool
162 const PositionVector& shape, const int index, const double layer, const double radius) {
163 // obtain geometry point pos
164 const auto geometryPointPos = shape[index];
165 // declare squared radius
166 const double squaredRadius = (radius * radius);
167 // continue depending if we're selecting a position or a boundary
169 // continue depending of detail level
171 // make a boundary using center and radius
172 Boundary geometryPointBoundary;
173 geometryPointBoundary.add(geometryPointPos);
174 geometryPointBoundary.grow(radius);
175 // check if boundary is whithin selection boundary
176 if (mySelectionBoundary.contains2D(geometryPointBoundary)) {
177 return selectGeometryPoint(GLObject, index, layer);
178 } else if (mySelectionBoundary.overlapsWith(geometryPointBoundary)) {
179 return selectGeometryPoint(GLObject, index, layer);
180 } else {
181 // check if the four boundary vertex are within circle
182 for (const auto& vertex : mySelectionBoundaryShape) {
183 if (vertex.distanceSquaredTo2D(geometryPointPos) <= squaredRadius) {
184 return selectGeometryPoint(GLObject, index, layer);
185 }
186 }
187 // no intersection, then return false
188 return false;
189 }
190 } else {
191 // check if center is within mySelectionBoundary
192 if (mySelectionBoundary.around2D(geometryPointPos)) {
193 return selectGeometryPoint(GLObject, index, layer);
194 } else {
195 return false;
196 }
197 }
199 // check distance between selection position and center
200 if (mySelectionPosition.distanceSquaredTo2D(geometryPointPos) <= squaredRadius) {
201 return selectGeometryPoint(GLObject, index, layer);
202 } else {
203 return false;
204 }
205 } else {
206 return false;
207 }
208}
209
210
211bool
213 const PositionVector& shape, const double layer, const double distance) {
214 // only process if we're selecting a precise position
216 // obtain nearest position over shape
217 const auto nearestOffset = shape.nearest_offset_to_point2D(mySelectionPosition);
218 const auto nearestPos = shape.positionAtOffset2D(nearestOffset);
219 // check distance nearest position and pos
220 if (mySelectionPosition.distanceSquaredTo2D(nearestPos) <= (distance * distance)) {
221 return selectPositionOverShape(GLObject, nearestPos, layer, nearestOffset);
222 } else {
223 return false;
224 }
225 } else {
226 return false;
227 }
228}
229
230
231bool
232GUIViewObjectsHandler::checkShapeObject(const GUIGlObject* GLObject, const PositionVector& shape, const Boundary& shapeBoundary,
233 const double layer, const GNESegment* segment) {
234 // first check that object doesn't exist
235 if (isObjectSelected(GLObject)) {
236 return false;
237 } else if (mySelectionBoundary.isInitialised()) {
238 // avoid invalid boundaries
239 if (!shapeBoundary.isInitialised()) {
240 return false;
241 }
242 // check if selection boundary contains the centering boundary of object
243 if (mySelectionBoundary.contains2D(shapeBoundary)) {
244 return selectObject(GLObject, layer, false, true, segment);
245 }
246 // check if shape crosses to selection boundary
247 for (int i = 1; i < (int)shape.size(); i++) {
248 if (mySelectionBoundary.crosses(shape[i - 1], shape[i])) {
249 return selectObject(GLObject, layer, false, false, segment);
250 }
251 }
252 // no intersection, then return false
253 return false;
255 // check if selection position is around shape
256 if (shape.around(mySelectionPosition)) {
257 return selectObject(GLObject, layer, false, false, segment);
258 } else {
259 return false;
260 }
261 } else {
262 return false;
263 }
264}
265
266
267bool
268GUIViewObjectsHandler::selectObject(const GUIGlObject* GLObject, const double layer, const bool checkDuplicated,
269 const bool fullBoundary, const GNESegment* segment) {
270 // first check that object doesn't exist
271 if (checkDuplicated && isObjectSelected(GLObject)) {
272 return false;
273 } else {
274 auto& layerContainer = mySortedSelectedObjects[layer * -1];
275 layerContainer.insert(layerContainer.begin(), ObjectContainer(GLObject));
276 mySelectedObjects[GLObject] = std::make_pair(fullBoundary, segment);
277 return true;
278 }
279}
280
281
282bool
283GUIViewObjectsHandler::selectGeometryPoint(const GUIGlObject* GLObject, const int newIndex,
284 const double layer) {
285 // avoid to insert duplicated elements
286 for (auto& elementLayer : mySortedSelectedObjects) {
287 for (auto& element : elementLayer.second) {
288 if (element.object == GLObject) {
289 // avoid double points
290 for (auto& index : element.geometryPoints) {
291 if (index == newIndex) {
292 return false;
293 }
294 }
295 // add new index
296 element.geometryPoints.push_back(newIndex);
297 return true;
298 }
299 }
300 }
301 // no element found then add it
302 auto& layerContainer = mySortedSelectedObjects[layer * -1];
303 auto it = layerContainer.insert(layerContainer.begin(), ObjectContainer(GLObject));
304 it->geometryPoints.push_back(newIndex);
305 mySelectedObjects[GLObject] = std::make_pair(false, nullptr);
306 return true;
307}
308
309
310bool
311GUIViewObjectsHandler::selectPositionOverShape(const GUIGlObject* GLObject, const Position& pos, const double layer,
312 const double offset) {
313 // avoid to insert duplicated elements
314 for (auto& elementLayer : mySortedSelectedObjects) {
315 for (auto& element : elementLayer.second) {
316 if (element.object == GLObject) {
317 if (element.posOverShape != Position::INVALID) {
318 return false;
319 } else {
320 // set position and offset over shape
321 element.posOverShape = pos;
322 element.offset = offset;
323 return true;
324 }
325 }
326 }
327 }
328 // no element found then add it
329 auto& layerContainer = mySortedSelectedObjects[layer * -1];
330 auto it = layerContainer.insert(layerContainer.begin(), ObjectContainer(GLObject));
331 it->posOverShape = pos;
332 mySelectedObjects[GLObject] = std::make_pair(false, nullptr);
333 return true;
334}
335
336
337bool
339 return mySelectedObjects.find(GLObject) != mySelectedObjects.end();
340}
341
342
347
348
349const GNESegment*
351 auto finder = mySelectedObjects.find(GLObject);
352 if (finder != mySelectedObjects.end()) {
353 return finder->second.second;
354 } else {
355 return nullptr;
356 }
357}
358
359
360const std::vector<int>&
362 // avoid to insert duplicated elements
363 for (auto& elementLayer : mySortedSelectedObjects) {
364 for (auto& element : elementLayer.second) {
365 if (element.object == GLObject) {
366 return element.geometryPoints;
367 }
368 }
369 }
371}
372
373
374const Position&
376 // avoid to insert duplicated elements
377 for (auto& elementLayer : mySortedSelectedObjects) {
378 for (auto& element : elementLayer.second) {
379 if (element.object == GLObject) {
380 return element.posOverShape;
381 }
382 }
383 }
384 return Position::INVALID;
385}
386
387
388
389const std::set<const GNEPathElement*>&
393
394
395bool
397 if (myRedrawPathElements.empty()) {
398 return false;
399 } else {
400 return myRedrawPathElements.find(pathElement) != myRedrawPathElements.end();
401 }
402}
403
404
405void
409
410
411const std::vector<const GNEJunction*>&
415
416
417bool
419 // avoid insert duplicated junctions
420 for (const auto mergingJunctions : myMergingJunctions) {
421 if (mergingJunctions == junction) {
422 return false;
423 }
424 }
425 myMergingJunctions.push_back(junction);
426 return true;
427}
428
429
430void
432 ObjectContainer frontElement(nullptr);
433 // extract element
434 for (auto& elementLayer : mySortedSelectedObjects) {
435 auto it = elementLayer.second.begin();
436 while (it != elementLayer.second.end()) {
437 if (it->object == GLObject) {
438 // copy element to front element
439 frontElement.object = it->object;
440 frontElement.geometryPoints = it->geometryPoints;
441 // remove element from myElementsUnderCursor
442 it = elementLayer.second.erase(it);
443 } else {
444 it++;
445 }
446 }
447 }
448 // add element again wit a new layer
449 if (frontElement.object) {
450 mySortedSelectedObjects[(double)GLO_FRONTELEMENT].push_back(frontElement);
451 }
452}
453
454
455void
457 // declare object container for edge
458 ObjectContainer edgeWithGeometryPoints(nullptr);
459 // check if there are edges with geometry points in mySortedSelectedObjects
460 for (auto& elementLayer : mySortedSelectedObjects) {
461 for (auto element : elementLayer.second) {
462 if ((element.object->getType() == GLO_EDGE) && (element.geometryPoints.size() > 0)) {
463 edgeWithGeometryPoints = element;
464 }
465 }
466 }
467 // continue if something was found
468 if (edgeWithGeometryPoints.object != nullptr) {
469 // clear all selected objects
471 // add edge with geometry points as front element
472 mySortedSelectedObjects[(double)GLO_FRONTELEMENT].push_back(edgeWithGeometryPoints);
473 }
474}
475
476/****************************************************************************/
@ 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
std::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...
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
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)
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
bool checkBoundaryParentObject(const GUIGlObject *GLObject, const GUIGlObject *parent, const double layer)
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
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
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