Eclipse SUMO - Simulation of Urban MObility
Loading...
Searching...
No Matches
GUIGeometry.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// File for geometry classes and functions
19/****************************************************************************/
25
26#include "GUIGeometry.h"
27
28#define CIRCLE_RESOLUTION (double)10 // inverse in degrees
29
30// ===========================================================================
31// static member definitions
32// ===========================================================================
34
35// ===========================================================================
36// method definitions
37// ===========================================================================
38
41
42
44 myShape(shape) {
45 // calculate shape rotation and lengths
47}
48
49
50GUIGeometry::GUIGeometry(const PositionVector& shape, const std::vector<double>& shapeRotations,
51 const std::vector<double>& shapeLengths) :
52 myShape(shape),
53 myShapeRotations(shapeRotations),
54 myShapeLengths(shapeLengths) {
55}
56
57
58void
60 // clear geometry
62 // update shape
63 myShape = shape;
64 // calculate shape rotation and lengths
66}
67
68
69void
70GUIGeometry::updateGeometry(const PositionVector& shape, const double posOverShape,
71 const double lateralOffset) {
72 // first clear geometry
74 // get shape length
75 const double shapeLength = shape.length2D();
76 // calculate position and rotation
77 if (posOverShape < 0) {
78 myShape.push_back(shape.positionAtOffset2D(0, lateralOffset));
79 myShapeRotations.push_back(shape.rotationDegreeAtOffset(0));
80 } else if (posOverShape > shapeLength) {
81 myShape.push_back(shape.positionAtOffset2D(shapeLength, lateralOffset));
82 myShapeRotations.push_back(shape.rotationDegreeAtOffset(shapeLength));
83 } else {
84 myShape.push_back(shape.positionAtOffset2D(posOverShape, lateralOffset));
85 myShapeRotations.push_back(shape.rotationDegreeAtOffset(posOverShape));
86 }
87}
88
89
90void
91GUIGeometry::updateGeometry(const PositionVector& shape, double starPosOverShape,
92 double endPosOverShape, const double lateralOffset) {
93 // first clear geometry
95 // set new shape
96 myShape = shape;
97 // set lateral offset
98 myShape.move2side(lateralOffset);
99 // get shape length
100 const double shapeLength = myShape.length2D();
101 // set initial beginTrim value
102 if (starPosOverShape < 0) {
103 endPosOverShape = 0;
104 }
105 // set initial endtrim value
106 if (starPosOverShape < 0) {
107 endPosOverShape = shapeLength;
108 }
109 // check maximum beginTrim
110 if (starPosOverShape > (shapeLength - POSITION_EPS)) {
111 endPosOverShape = (shapeLength - POSITION_EPS);
112 }
113 // check maximum endTrim
114 if ((endPosOverShape > shapeLength)) {
115 endPosOverShape = shapeLength;
116 }
117 // check sub-vector
118 if (endPosOverShape <= starPosOverShape) {
119 endPosOverShape = endPosOverShape + POSITION_EPS;
120 }
121 // trim shape
122 myShape = myShape.getSubpart2D(starPosOverShape, endPosOverShape);
123 // calculate shape rotation and lengths
125}
126
127
128void
129GUIGeometry::updateGeometry(const PositionVector& shape, double beginTrimPosition, const Position& extraFirstPosition,
130 double endTrimPosition, const Position& extraLastPosition) {
131 // first clear geometry
133 // set new shape
134 myShape = shape;
135 // check trim values
136 if ((beginTrimPosition != -1) || (endTrimPosition != -1)) {
137 // get shape length
138 const double shapeLength = myShape.length2D();
139 // set initial beginTrim value
140 if (beginTrimPosition < 0) {
141 beginTrimPosition = 0;
142 }
143 // set initial endtrim value
144 if (endTrimPosition < 0) {
145 endTrimPosition = shapeLength;
146 }
147 // check maximum beginTrim
148 if (beginTrimPosition > (shapeLength - POSITION_EPS)) {
149 beginTrimPosition = (shapeLength - POSITION_EPS);
150 }
151 // check maximum endTrim
152 if ((endTrimPosition > shapeLength)) {
153 endTrimPosition = shapeLength;
154 }
155 // check sub-vector
156 if (endTrimPosition <= beginTrimPosition) {
157 endTrimPosition = endTrimPosition + POSITION_EPS;
158 }
159 // trim shape
160 myShape = myShape.getSubpart2D(beginTrimPosition, endTrimPosition);
161 // add extra positions
162 if (extraFirstPosition != Position::INVALID) {
163 myShape.push_front_noDoublePos(extraFirstPosition);
164 }
165 if (extraLastPosition != Position::INVALID) {
166 myShape.push_back_noDoublePos(extraLastPosition);
167 }
168 }
169 // calculate shape rotation and lengths
171}
172
173
174void
175GUIGeometry::updateSinglePosGeometry(const Position& position, const double rotation) {
176 // first clear geometry
178 // set position and rotation
179 myShape.push_back(position);
180 myShapeRotations.push_back(rotation);
181}
182
183
185 // clear geometry containers
186 myShape.clear();
187 myShapeRotations.clear();
188 myShapeLengths.clear();
189}
190
191
192void
194 // move shape
195 myShape.move2side(amount);
196}
197
198
199void
200GUIGeometry::scaleGeometry(const double scale) {
201 // scale shape and lengths
202 myShape.scaleRelative(scale);
203 // scale lengths
204 for (auto& shapeLength : myShapeLengths) {
205 shapeLength *= scale;
206 }
207}
208
209
210const PositionVector&
212 return myShape;
213}
214
215
216const std::vector<double>&
220
221
222const std::vector<double>&
226
227
228double
230 // return rotation (angle) of the vector constructed by points first and second
231 return ((double)atan2((second.x() - first.x()), (first.y() - second.y())) * (double) 180.0 / (double)M_PI);
232}
233
234
235double
236GUIGeometry::calculateLength(const Position& first, const Position& second) {
237 // return 2D distance between two points
238 return first.distanceTo2D(second);
239}
240
241
242void
243GUIGeometry::adjustStartPosGeometricPath(double& startPos, const PositionVector& startLaneShape,
244 double& endPos, const PositionVector& endLaneShape) {
245 // adjust both, if start and end lane are the same
246 if ((startLaneShape.size() > 0) &&
247 (endLaneShape.size() > 0) &&
248 (startLaneShape == endLaneShape) &&
249 (startPos != -1) &&
250 (endPos != -1)) {
251 if (startPos >= endPos) {
252 endPos = (startPos + POSITION_EPS);
253 }
254 }
255 // adjust startPos
256 if ((startPos != -1) && (startLaneShape.size() > 0)) {
257 if (startPos < POSITION_EPS) {
258 startPos = POSITION_EPS;
259 }
260 if (startPos > (startLaneShape.length() - POSITION_EPS)) {
261 startPos = (startLaneShape.length() - POSITION_EPS);
262 }
263 }
264 // adjust endPos
265 if ((endPos != -1) && (endLaneShape.size() > 0)) {
266 if (endPos < POSITION_EPS) {
267 endPos = POSITION_EPS;
268 }
269 if (endPos > (endLaneShape.length() - POSITION_EPS)) {
270 endPos = (endLaneShape.length() - POSITION_EPS);
271 }
272 }
273}
274
275
276void
278 const double width, double offset) {
279 // continue depending of detail level
281 GLHelper::drawBoxLines(geometry.getShape(), geometry.getShapeRotations(), geometry.getShapeLengths(), width, 0, offset);
283 // set line width
284 glLineWidth(static_cast<float>(width));
285 // draw a simple line
286 GLHelper::drawLine(geometry.getShape());
287 // restore line width
288 glLineWidth(1);
289 } else {
290 // draw a simple line
291 GLHelper::drawLine(geometry.getShape());
292 }
293}
294
295
296void
298 const std::vector<RGBColor>& colors, const double width, double offset) {
299 // continue depending of detail level
301 GLHelper::drawBoxLines(geometry.getShape(), geometry.getShapeRotations(), geometry.getShapeLengths(), colors, width, 0, offset);
302 } else {
303 // set first color
304 GLHelper::setColor(*colors.begin());
305 // set width
307 // set line width
308 glLineWidth(static_cast<float>(width));
309 // draw a simple line
310 GLHelper::drawLine(geometry.getShape());
311 // restore line width
312 glLineWidth(1);
313 } else {
314 // draw a simple line
315 GLHelper::drawLine(geometry.getShape());
316 }
317 }
318}
319
320
321void
322GUIGeometry::drawContourGeometry(const GUIGeometry& geometry, const double width, const bool drawExtremes) {
323 // get shapes
324 PositionVector shapeA = geometry.getShape();
325 PositionVector shapeB = geometry.getShape();
326 // move both shapes
327 shapeA.move2side((width - 0.1));
328 shapeB.move2side((width - 0.1) * -1);
329 // check if we have to drawn extremes
330 if (drawExtremes) {
331 // reverse shape B
332 shapeB = shapeB.reverse();
333 // append shape B to shape A
334 shapeA.append(shapeB, 0);
335 // close shape A
336 shapeA.closePolygon();
337 // draw box lines using shapeA
338 GLHelper::drawBoxLines(shapeA, 0.1);
339 } else {
340 // draw box lines using shapeA
341 GLHelper::drawBoxLines(shapeA, 0.1);
342 // draw box lines using shapeA
343 GLHelper::drawBoxLines(shapeB, 0.1);
344 }
345}
346
347
348void
350 const RGBColor& color, const double radius, const double exaggeration,
351 const bool editingElevation) {
352 // check detail level
353 if (editingElevation || (d <= GUIVisualizationSettings::Detail::GeometryPoint)) {
354 // get exaggeratedRadio
355 const double exaggeratedRadio = (radius * exaggeration);
356 // iterate over geometryPoints
357 for (const auto& geometryPos : shape) {
358 // push geometry point matrix
360 // move to vertex
361 glTranslated(geometryPos.x(), geometryPos.y(), 0.2);
362 // set color
363 GLHelper::setColor(color);
364 // draw circle detailled
365 GLHelper::drawFilledCircleDetailled(d, exaggeratedRadio);
366 // pop geometry point matrix
368 // draw elevation or special symbols (Start, End and Block)
370 if (editingElevation) {
371 // Push Z matrix
373 // draw Z (elevation)
374 GLHelper::drawText(toString(geometryPos.z()), geometryPos, 0.3, 0.7, color.invertedColor());
375 // pop Z matrix
377 } else if (geometryPos == shape.front()) {
378 // push "S" matrix
380 // draw a "s" over first point
381 GLHelper::drawText("S", geometryPos, 0.3, 2 * exaggeratedRadio, color.invertedColor());
382 // pop "S" matrix
384 } else if (geometryPos == shape.back()) {
385 // push "E" matrix
387 // draw a "e" over last point if polygon isn't closed
388 GLHelper::drawText("E", geometryPos, 0.3, 2 * exaggeratedRadio, color.invertedColor());
389 // pop "E" matrix
391 }
392 }
393 }
394 }
395}
396
397
398void
400 const RGBColor& color, const bool drawEntire, const double lineWidth) {
402 // calculate rotation
403 const double rot = RAD2DEG(parent.angleTo2D(child)) + 90;
404 // calculate distance between origin and destination
405 const double distanceSquared = parent.distanceSquaredTo2D(child);
406 // Add a draw matrix for details
408 // move back
409 glTranslated(0, 0, -1);
410 // draw box line
411 if (drawEntire) {
412 // draw first box line
414 GLHelper::drawBoxLine(parent, rot, sqrt(distanceSquared), lineWidth);
415 // move front
416 glTranslated(0, 0, 0.1);
417 // draw second box line
418 GLHelper::setColor(color);
419 GLHelper::drawBoxLine(parent, rot, sqrt(distanceSquared), .04);
420 } else if (distanceSquared > 25) {
421 // draw first box line with length 4.9
423 GLHelper::drawBoxLine(parent, rot, 4.9, lineWidth);
424 glTranslated(0, 0, 0.1);
425 // draw second box line with length 4.9
426 GLHelper::setColor(color);
427 GLHelper::drawBoxLine(parent, rot, 4.9, .04);
428 // draw arrow depending of distanceSquared (10*10)
429 if (distanceSquared > 100) {
430 // calculate positionVector between both points
431 const PositionVector vector = {parent, child};
432 // draw first arrow at end
435 vector.positionAtOffset2D(5),
439 // move front
440 glTranslated(0, 0, 0.1);
441 // draw second arrow at end
442 GLHelper::setColor(color);
444 vector.positionAtOffset2D(5),
448 }
449 }
450 // pop draw matrix
452 }
453}
454
455
456void
458 const RGBColor& color, const bool drawEntire, const double lineWidth) {
460 // calculate distance between origin and destination
461 const double distanceSquared = child.distanceSquaredTo2D(parent);
462 // calculate subline width
463 const double sublineWidth = (lineWidth * 0.8);
464 // calculate rotation
465 const double rot = RAD2DEG(child.angleTo2D(parent)) + 90;
466 // Add a draw matrix for details
468 // move back
469 glTranslated(0, 0, -1);
470 // set color
471 GLHelper::setColor(color);
472 // draw box line
473 if (drawEntire || (distanceSquared < 25)) {
474 // set color
475 GLHelper::setColor(color);
476 // draw first box line
478 GLHelper::drawBoxLine(child, rot, sqrt(distanceSquared), lineWidth);
479 // move front
480 glTranslated(0, 0, 0.1);
481 // draw second box line
482 GLHelper::setColor(color);
483 GLHelper::drawBoxLine(child, rot, sqrt(distanceSquared), sublineWidth);
484 } else {
485 // draw first box line with length 4.9
487 GLHelper::drawBoxLine(child, rot, 4.9, lineWidth);
488 glTranslated(0, 0, 0.1);
489 // draw second box line with length
490 GLHelper::setColor(color);
491 GLHelper::drawBoxLine(child, rot, 4.9, sublineWidth);
492 // draw arrow depending of distanceSquared (10*10)
493 if (distanceSquared > 100) {
494 // calculate positionVector between both points
495 const PositionVector vector = {child, parent};
496 // draw first arrow at end
499 vector.positionAtOffset2D(5),
503 // move front
504 glTranslated(0, 0, 0.1);
505 // draw second arrow at end
506 GLHelper::setColor(color);
508 vector.positionAtOffset2D(5),
512 }
513 }
514 // pop draw matrix
516 }
517}
518
519
521GUIGeometry::getVertexCircleAroundPosition(const Position& pos, const double width, const int steps) {
522 // first check if we have to fill myCircleCoords (only once)
523 if (myCircleCoords.size() == 0) {
524 for (int i = 0; i <= (int)(360 * CIRCLE_RESOLUTION); ++i) {
525 const double x = (double) sin(DEG2RAD(i / CIRCLE_RESOLUTION));
526 const double y = (double) cos(DEG2RAD(i / CIRCLE_RESOLUTION));
527 myCircleCoords.push_back(Position(x, y));
528 }
529 }
530 PositionVector vertexCircle;
531 const double inc = 360 / (double)steps;
532 // obtain all vertices
533 for (int i = 0; i <= steps; ++i) {
534 const Position& vertex = myCircleCoords[GUIGeometry::angleLookup(i * inc)];
535 vertexCircle.push_back(Position(vertex.x() * width, vertex.y() * width));
536 }
537 // move result using position
538 vertexCircle.add(pos);
539 return vertexCircle;
540}
541
542
543void
545 // rotate using rotation calculated in PositionVector
546 glRotated((rot * -1) + 90, 0, 0, 1);
547}
548
549
550int
551GUIGeometry::angleLookup(const double angleDeg) {
552 const int numCoords = (int)myCircleCoords.size() - 1;
553 int index = ((int)(floor(angleDeg * CIRCLE_RESOLUTION + 0.5))) % numCoords;
554 if (index < 0) {
555 index += numCoords;
556 }
557 assert(index >= 0);
558 return (int)index;
559}
560
561
562void
564 // clear rotations and lengths
565 myShapeRotations.clear();
566 myShapeLengths.clear();
567 // Get number of parts of the shape
568 int numberOfSegments = (int)myShape.size() - 1;
569 // If number of segments is more than 0
570 if (numberOfSegments >= 0) {
571 // Reserve memory (To improve efficiency)
572 myShapeRotations.reserve(numberOfSegments);
573 myShapeLengths.reserve(numberOfSegments);
574 // Calculate lengths and rotations for every shape
575 for (int i = 0; i < numberOfSegments; i++) {
576 myShapeRotations.push_back(calculateRotation(myShape[i], myShape[i + 1]));
577 myShapeLengths.push_back(calculateLength(myShape[i], myShape[i + 1]));
578 }
579 }
580}
581
582/****************************************************************************/
#define CIRCLE_RESOLUTION
Definition GLHelper.cpp:50
#define DEG2RAD(x)
Definition GeomHelper.h:35
#define RAD2DEG(x)
Definition GeomHelper.h:36
std::string toString(const T &t, std::streamsize accuracy=gPrecision)
Definition ToString.h:46
static void drawLine(const Position &beg, double rot, double visLength)
Draws a thin line.
Definition GLHelper.cpp:433
static void setColor(const RGBColor &c)
Sets the gl-color to this value.
Definition GLHelper.cpp:649
static void drawTriangleAtEnd(const Position &p1, const Position &p2, double tLength, double tWidth, const double extraOffset=0)
Draws a triangle at the end of the given line.
Definition GLHelper.cpp:624
static void popMatrix()
pop matrix
Definition GLHelper.cpp:131
static void drawBoxLines(const PositionVector &geom, const std::vector< double > &rots, const std::vector< double > &lengths, double width, int cornerDetail=0, double offset=0)
Draws thick lines.
Definition GLHelper.cpp:348
static void drawBoxLine(const Position &beg, double rot, double visLength, double width, double offset=0)
Draws a thick line.
Definition GLHelper.cpp:296
static void drawFilledCircleDetailled(const GUIVisualizationSettings::Detail d, const double radius)
Draws a filled circle around (0,0) depending of level of detail.
Definition GLHelper.cpp:534
static void pushMatrix()
push matrix
Definition GLHelper.cpp:118
static void drawText(const std::string &text, const Position &pos, const double layer, const double size, const RGBColor &col=RGBColor::BLACK, const double angle=0, const int align=0, double width=-1)
Definition GLHelper.cpp:742
static void rotateOverLane(const double rot)
rotate over lane (used by Lock icons, detector logos, etc.)
void moveGeometryToSide(const double amount)
move current shape to side
const std::vector< double > & getShapeRotations() const
The rotations of the single shape parts.
static void drawGeometryPoints(const GUIVisualizationSettings::Detail d, const PositionVector &shape, const RGBColor &color, const double radius, const double exaggeration, const bool editingElevation)
draw geometry points
static PositionVector myCircleCoords
Storage for precomputed sin/cos-values describing a circle.
void scaleGeometry(const double scale)
scale geometry
static PositionVector getVertexCircleAroundPosition(const Position &pos, const double width, const int steps=8)
get a circle around the given position
void calculateShapeRotationsAndLengths()
calculate shape rotations and lengths
std::vector< double > myShapeLengths
The lengths of the shape (note: Always size = myShape.size()-1)
static void adjustStartPosGeometricPath(double &startPos, const PositionVector &startLaneShape, double &endPos, const PositionVector &endLaneShape)
adjust start and end positions in geometric path
void clearGeometry()
clear geometry
static int angleLookup(const double angleDeg)
normalize angle for lookup in myCircleCoords
static void drawContourGeometry(const GUIGeometry &geometry, const double width, const bool drawExtremes=false)
draw contour geometry
static void drawGeometry(const GUIVisualizationSettings::Detail d, const GUIGeometry &geometry, const double width, double offset=0)
draw geometry
PositionVector myShape
element shape
void updateSinglePosGeometry(const Position &position, const double rotation)
update position and rotation
static double calculateRotation(const Position &first, const Position &second)
return angle between two points (used in geometric calculations)
static void drawChildLine(const GUIVisualizationSettings &s, const Position &child, const Position &parent, const RGBColor &color, const bool drawEntire, const double lineWidth)
draw line between child and parent (used in netedit)
const PositionVector & getShape() const
The shape of the additional element.
void updateGeometry(const PositionVector &shape)
update entire geometry
const std::vector< double > & getShapeLengths() const
The lengths of the single shape parts.
std::vector< double > myShapeRotations
The rotations of the shape (note: Always size = myShape.size()-1)
GUIGeometry()
default constructor
static void drawParentLine(const GUIVisualizationSettings &s, const Position &parent, const Position &child, const RGBColor &color, const bool drawEntire, const double lineWidth)
draw line between parent and children (used in netedit)
static double calculateLength(const Position &first, const Position &second)
return length between two points (used in geometric calculations)
Stores the information about how to visualize structures.
bool drawForRectangleSelection
whether drawing is performed for the purpose of selecting objects using a rectangle
GUIVisualizationAdditionalSettings additionalSettings
Additional settings.
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
double distanceTo2D(const Position &p2) const
returns the euclidean distance in the x-y-plane
Definition Position.h:273
double x() const
Returns the x-position.
Definition Position.h:52
double angleTo2D(const Position &other) const
returns the angle in the plane of the vector pointing from here to the other position (in radians bet...
Definition Position.h:283
double y() const
Returns the y-position.
Definition Position.h:57
A list of positions.
double length2D() const
Returns the length.
void append(const PositionVector &v, double sameThreshold=2.0)
double length() const
Returns the length.
void push_front_noDoublePos(const Position &p)
insert in front a non double position
double rotationDegreeAtOffset(double pos) const
Returns the rotation at the given length.
void add(double xoff, double yoff, double zoff)
void closePolygon()
ensures that the last position equals the first
void move2side(double amount, double maxExtension=100)
move position vector to side using certain amount
PositionVector getSubpart2D(double beginOffset, double endOffset) const
get subpart of a position vector in two dimensions (Z is ignored)
Position positionAtOffset2D(double pos, double lateralOffset=0, bool extrapolateBeyond=false) const
Returns the position at the given length.
void scaleRelative(double factor)
enlarges/shrinks the polygon by a factor based at the centroid
void push_back_noDoublePos(const Position &p)
insert in back a non double position
PositionVector reverse() const
reverse position vector
RGBColor invertedColor() const
obtain inverted of current RGBColor
Definition RGBColor.cpp:183
RGBColor changedBrightness(int change, int toChange=3) const
Returns a new color with altered brightness.
Definition RGBColor.cpp:200
#define M_PI
Definition odrSpiral.cpp:45
static const double arrowLength
arrow length
static const double arrowWidth
arrow width
static const double arrowOffset
arrow offset