Eclipse SUMO - Simulation of Urban MObility
Loading...
Searching...
No Matches
GeomHelper.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/****************************************************************************/
22// Some static methods performing geometrical operations
23/****************************************************************************/
24#include <config.h>
25
26#include <cmath>
27#include <limits>
28#include <algorithm>
29#include <iostream>
33#include "Boundary.h"
34#include "GeomHelper.h"
35
36// ===========================================================================
37// static members
38// ===========================================================================
39const double GeomHelper::INVALID_OFFSET = -1;
40
41
42// ===========================================================================
43// method definitions
44// ===========================================================================
45
46void
47GeomHelper::findLineCircleIntersections(const Position& c, double radius, const Position& p1, const Position& p2,
48 std::vector<double>& into) {
49 const double dx = p2.x() - p1.x();
50 const double dy = p2.y() - p1.y();
51
52 const double A = dx * dx + dy * dy;
53 const double B = 2 * (dx * (p1.x() - c.x()) + dy * (p1.y() - c.y()));
54 const double C = (p1.x() - c.x()) * (p1.x() - c.x()) + (p1.y() - c.y()) * (p1.y() - c.y()) - radius * radius;
55
56 const double det = B * B - 4 * A * C;
57 if ((A <= 0.0000001) || (det < 0)) {
58 // No real solutions.
59 return;
60 }
61 if (det == 0) {
62 // One solution.
63 const double t = -B / (2 * A);
64 if (t >= 0. && t <= 1.) {
65 into.push_back(t);
66 }
67 } else {
68 // Two solutions.
69 const double t = (double)((-B + sqrt(det)) / (2 * A));
70 Position intersection(p1.x() + t * dx, p1.y() + t * dy);
71 if (t >= 0. && t <= 1.) {
72 into.push_back(t);
73 }
74 const double t2 = (double)((-B - sqrt(det)) / (2 * A));
75 if (t2 >= 0. && t2 <= 1.) {
76 into.push_back(t2);
77 }
78 }
79}
80
81
82double
83GeomHelper::angle2D(const Position& p1, const Position& p2) {
84 return angleDiff(atan2(p1.y(), p1.x()), atan2(p2.y(), p2.x()));
85}
86
87
88double
90 const Position& lineEnd,
91 const Position& p, bool perpendicular) {
92 const double lineLength2D = lineStart.distanceTo2D(lineEnd);
93 if (lineLength2D == 0.) {
94 return 0.;
95 }
96 // scalar product equals length of orthogonal projection times length of vector being projected onto
97 // dividing the scalar product by the distance gives the relative position
98 const double u = (((p.x() - lineStart.x()) * (lineEnd.x() - lineStart.x())) +
99 ((p.y() - lineStart.y()) * (lineEnd.y() - lineStart.y()))
100 ) / lineLength2D;
101 if (u < 0. || u > lineLength2D) { // closest point does not fall within the line segment
102 if (perpendicular) {
103 return INVALID_OFFSET;
104 }
105 if (u < 0.) {
106 return 0.;
107 }
108 return lineLength2D;
109 }
110 return u;
111}
112
113
114double
116 const Position& lineEnd,
117 const Position& p, bool perpendicular) {
118 double result = nearest_offset_on_line_to_point2D(lineStart, lineEnd, p, perpendicular);
119 if (result != INVALID_OFFSET) {
120 const double lineLength2D = lineStart.distanceTo2D(lineEnd);
121 const double lineLength = lineStart.distanceTo(lineEnd);
122 result *= (lineLength / lineLength2D);
123 }
124 return result;
125}
126
129 if (v.intersects(Position(b.xmin(), b.ymin()), Position(b.xmin(), b.ymax()))) {
130 return v.intersectionPosition2D(
131 Position(b.xmin(), b.ymin()),
132 Position(b.xmin(), b.ymax()));
133 }
134 if (v.intersects(Position(b.xmax(), b.ymin()), Position(b.xmax(), b.ymax()))) {
135 return v.intersectionPosition2D(
136 Position(b.xmax(), b.ymin()),
137 Position(b.xmax(), b.ymax()));
138 }
139 if (v.intersects(Position(b.xmin(), b.ymin()), Position(b.xmax(), b.ymin()))) {
140 return v.intersectionPosition2D(
141 Position(b.xmin(), b.ymin()),
142 Position(b.xmax(), b.ymin()));
143 }
144 if (v.intersects(Position(b.xmin(), b.ymax()), Position(b.xmax(), b.ymax()))) {
145 return v.intersectionPosition2D(
146 Position(b.xmin(), b.ymax()),
147 Position(b.xmax(), b.ymax()));
148 }
149 throw 1;
150}
151
152double
153GeomHelper::getCCWAngleDiff(double angle1, double angle2) {
154 double v = angle2 - angle1;
155 if (v < 0) {
156 v = 360 + v;
157 }
158 return v;
159}
160
161
162double
163GeomHelper::getCWAngleDiff(double angle1, double angle2) {
164 double v = angle1 - angle2;
165 if (v < 0) {
166 v = 360 + v;
167 }
168 return v;
169}
170
171
172double
173GeomHelper::getMinAngleDiff(double angle1, double angle2) {
174 return MIN2(getCWAngleDiff(angle1, angle2), getCCWAngleDiff(angle1, angle2));
175}
176
177
178double
179GeomHelper::angleDiff(const double angle1, const double angle2) {
180 double dtheta = angle2 - angle1;
181 while (dtheta > (double) M_PI) {
182 dtheta -= (double)(2.0 * M_PI);
183 }
184 while (dtheta < (double) - M_PI) {
185 dtheta += (double)(2.0 * M_PI);
186 }
187 return dtheta;
188}
189
190
191double
192GeomHelper::naviDegree(const double angle) {
193 double degree = RAD2DEG(M_PI / 2. - angle);
194 if (std::isinf(degree)) {
195 //assert(false);
196 return 0;
197 }
198 while (degree >= 360.) {
199 degree -= 360.;
200 }
201 while (degree < 0.) {
202 degree += 360.;
203 }
204 return degree;
205}
206
207
208double
209GeomHelper::fromNaviDegree(const double angle) {
210 return M_PI / 2. - DEG2RAD(angle);
211}
212
213
214double
215GeomHelper::legacyDegree(const double angle, const bool positive) {
216 double degree = -RAD2DEG(M_PI / 2. + angle);
217 if (positive) {
218 while (degree >= 360.) {
219 degree -= 360.;
220 }
221 while (degree < 0.) {
222 degree += 360.;
223 }
224 } else {
225 while (degree >= 180.) {
226 degree -= 360.;
227 }
228 while (degree < -180.) {
229 degree += 360.;
230 }
231 }
232 return degree;
233}
234
236GeomHelper::makeCircle(const double radius, const Position& center, unsigned int nPoints) {
237 if (nPoints < 3) {
238 WRITE_ERROR(TL("GeomHelper::makeCircle() requires nPoints>=3"));
239 }
240 PositionVector circle;
241 circle.push_back({radius, 0});
242 for (unsigned int i = 1; i < nPoints; ++i) {
243 const double a = 2.0 * M_PI * (double)i / (double) nPoints;
244 circle.push_back({radius * cos(a), radius * sin(a)});
245 }
246 circle.push_back({radius, 0});
247 circle.add(center);
248 return circle;
249}
250
251
253GeomHelper::makeRing(const double radius1, const double radius2, const Position& center, unsigned int nPoints) {
254 if (nPoints < 3) {
255 WRITE_ERROR("GeomHelper::makeRing() requires nPoints>=3");
256 }
257 if (radius1 >= radius2) {
258 WRITE_ERROR("GeomHelper::makeRing() requires radius2>radius1");
259 }
260 PositionVector ring;
261 ring.push_back({radius1, 0});
262 ring.push_back({radius2, 0});
263 for (unsigned int i = 1; i < nPoints; ++i) {
264 const double a = 2.0 * M_PI * (double)i / (double) nPoints;
265 ring.push_back({radius2 * cos(a), radius2 * sin(a)});
266 }
267 ring.push_back({radius2, 0});
268 ring.push_back({radius1, 0});
269 for (unsigned int i = 1; i < nPoints; ++i) {
270 const double a = -2.0 * M_PI * (double)i / (double) nPoints;
271 ring.push_back({radius1 * cos(a), radius1 * sin(a)});
272 }
273 ring.push_back({radius1, 0});
274 ring.add(center);
275 return ring;
276}
277
278
279
280const Position
281GeomHelper::calculateLotSpacePosition(const PositionVector& shape, const int index, const double spaceDim, const double angle,
282 const double width, const double length) {
283 //declare pos
284 Position pos;
285 // declare shape offsets
286 const Position startOffset = shape.positionAtOffset(spaceDim * (index));
287 const Position endOffset = shape.positionAtOffset(spaceDim * (index + 1));
288 // continue depending of nagle
289 if (angle == 0) {
290 // parking parallel to the road
291 pos = endOffset;
292 } else {
293 // angled parking
294 double normAngle = angle;
295 while (normAngle < 0) {
296 normAngle += 360.;
297 }
298 normAngle = fmod(normAngle, 360);
299 const double radianAngle = normAngle / 180 * M_PI;
300 double spaceExtension = width * sin(radianAngle) + length * cos(radianAngle);
301 const double hlp_angle = fabs(((double)atan2((endOffset.y() - startOffset.y()), (endOffset.x() - startOffset.x()))));
302 Position offset;
303 double xOffset = 0.5 * width * sin(radianAngle) - 0.5 * (spaceExtension - spaceDim);
304 pos.setx(startOffset.x() + xOffset + length * cos(radianAngle));
305 if (normAngle <= 90) {
306 pos.sety((startOffset.y() + 0.5 * width * (1 - cos(radianAngle)) - length * sin(radianAngle)));
307 } else if (normAngle <= 180) {
308 pos.sety(startOffset.y() + 0.5 * width * (1 + cos(radianAngle)) - length * sin(radianAngle));
309 } else if (angle <= 270) {
310 pos.sety(startOffset.y() + 0.5 * width * (1 - cos(radianAngle - M_PI)));
311 } else {
312 pos.sety(startOffset.y() + 0.5 * width * (1 + cos(radianAngle - M_PI)));
313 }
314 pos.setz((startOffset.z() + endOffset.z()) / 2);
315 pos = pos.rotateAround2D(hlp_angle, startOffset);
316 }
317 return pos;
318}
319
320
321double
322GeomHelper::calculateLotSpaceAngle(const PositionVector& shape, const int index, const double spaceDim, const double angle) {
323 // declare shape offsets
324 const Position startOffset = shape.positionAtOffset(spaceDim * (index));
325 const Position endOffset = shape.positionAtOffset(spaceDim * (index + 1));
326 // return angle
327 return ((double)atan2((endOffset.x() - startOffset.x()), (startOffset.y() - endOffset.y())) * (double)180.0 / (double)M_PI) - angle;
328}
329
330
331double
332GeomHelper::calculateLotSpaceSlope(const PositionVector& shape, const int index, const double spaceDim) {
333 return shape.slopeDegreeAtOffset(spaceDim * (index + 1));
334}
335
336/****************************************************************************/
#define DEG2RAD(x)
Definition GeomHelper.h:35
#define M_PI
Definition GeomHelper.h:32
#define RAD2DEG(x)
Definition GeomHelper.h:36
#define WRITE_ERROR(msg)
Definition MsgHandler.h:296
#define TL(string)
Definition MsgHandler.h:305
T MIN2(T a, T b)
Definition StdDefs.h:80
A class that stores a 2D geometrical boundary.
Definition Boundary.h:39
double ymin() const
Returns minimum y-coordinate.
Definition Boundary.cpp:127
double xmin() const
Returns minimum x-coordinate.
Definition Boundary.cpp:115
double ymax() const
Returns maximum y-coordinate.
Definition Boundary.cpp:133
double xmax() const
Returns maximum x-coordinate.
Definition Boundary.cpp:121
static double getCCWAngleDiff(double angle1, double angle2)
Returns the distance of second angle from first angle counter-clockwise.
static void findLineCircleIntersections(const Position &c, double radius, const Position &p1, const Position &p2, std::vector< double > &into)
Returns the positions the given circle is crossed by the given line.
static double nearest_offset_on_line_to_point25D(const Position &lineStart, const Position &lineEnd, const Position &p, bool perpendicular=true)
static const Position calculateLotSpacePosition(const PositionVector &shape, const int index, const double spaceDim, const double angle, const double width, const double length)
calculate lotSpace position
static double calculateLotSpaceAngle(const PositionVector &shape, const int index, const double spaceDim, const double angle)
calculate lotSpace angle
static Position crossPoint(const Boundary &b, const PositionVector &v)
static double angle2D(const Position &p1, const Position &p2)
Returns the angle between two vectors on a plane The angle is from vector 1 to vector 2,...
static PositionVector makeRing(const double radius1, const double radius2, const Position &center, unsigned int nPoints)
static const double INVALID_OFFSET
a value to signify offsets outside the range of [0, Line.length()]
Definition GeomHelper.h:50
static double getCWAngleDiff(double angle1, double angle2)
Returns the distance of second angle from first angle clockwise.
static double calculateLotSpaceSlope(const PositionVector &shape, const int index, const double spaceDim)
calculate lotSpace slope
static double nearest_offset_on_line_to_point2D(const Position &lineStart, const Position &lineEnd, const Position &p, bool perpendicular=true)
static PositionVector makeCircle(const double radius, const Position &center, unsigned int nPoints)
static double naviDegree(const double angle)
static double fromNaviDegree(const double angle)
static double legacyDegree(const double angle, const bool positive=false)
static double angleDiff(const double angle1, const double angle2)
Returns the difference of the second angle to the first angle in radiants.
static double getMinAngleDiff(double angle1, double angle2)
Returns the minimum distance (clockwise/counter-clockwise) between both angles.
A point in 2D or 3D with translation and scaling methods.
Definition Position.h:37
void setx(double x)
set position x
Definition Position.h:67
double distanceTo2D(const Position &p2) const
returns the euclidean distance in the x-y-plane
Definition Position.h:273
double distanceTo(const Position &p2) const
returns the euclidean distance in 3 dimensions
Definition Position.h:263
double x() const
Returns the x-position.
Definition Position.h:52
void setz(double z)
set position z
Definition Position.h:77
Position rotateAround2D(double rad, const Position &origin)
rotate this position by rad around origin and return the result
Definition Position.cpp:42
double z() const
Returns the z-position.
Definition Position.h:62
void sety(double y)
set position y
Definition Position.h:72
double y() const
Returns the y-position.
Definition Position.h:57
A list of positions.
Position intersectionPosition2D(const Position &p1, const Position &p2, const double withinDist=0.) const
Returns the position of the intersection.
Position positionAtOffset(double pos, double lateralOffset=0) const
Returns the position at the given length.
void add(double xoff, double yoff, double zoff)
double slopeDegreeAtOffset(double pos) const
Returns the slope at the given length.
bool intersects(const Position &p1, const Position &p2) const
Returns the information whether this list of points interesects the given line.