Eclipse SUMO - Simulation of Urban MObility
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Modules Pages
Triangle.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// A simple triangle defined in 3D
19/****************************************************************************/
20#include <config.h>
21
22#include <algorithm>
23#include "Triangle.h"
24
25
26// ===========================================================================
27// static member definitions
28// ===========================================================================
30
31
32// ===========================================================================
33// method definitions
34// ===========================================================================
36
37
38Triangle::Triangle(const Position& positionA, const Position& positionB, const Position& positionC) :
39 myA(positionA),
40 myB(positionB),
41 myC(positionC) {
42 // calculate boundary
43 myBoundary.add(positionA);
44 myBoundary.add(positionB);
45 myBoundary.add(positionC);
46}
47
48
50
51
52bool
54 return isPositionWithin(myA, myB, myC, pos);
55}
56
57
58bool
60 return isPositionWithin(Position(boundary.xmax(), boundary.ymax())) &&
61 isPositionWithin(Position(boundary.xmin(), boundary.ymin())) &&
62 isPositionWithin(Position(boundary.xmax(), boundary.ymin())) &&
63 isPositionWithin(Position(boundary.xmin(), boundary.ymax()));
64}
65
66
67bool
69 return intersectWithShape(shape, shape.getBoxBoundary());
70}
71
72
73bool
74Triangle::intersectWithShape(const PositionVector& shape, const Boundary& shapeBoundary) const {
75 // check if triangle is within shape
76 if (shape.around(myA) || shape.around(myB) || shape.around(myC)) {
77 return true;
78 }
79 // check if at leas two corners of the shape boundary are within triangle
80 const int cornerA = isPositionWithin(Position(shapeBoundary.xmax(), shapeBoundary.ymax()));
81 const int cornerB = isPositionWithin(Position(shapeBoundary.xmin(), shapeBoundary.ymin()));
82 if ((cornerA + cornerB) == 2) {
83 return true;
84 }
85 const int cornerC = isPositionWithin(Position(shapeBoundary.xmax(), shapeBoundary.ymin()));
86 if ((cornerA + cornerB + cornerC) == 2) {
87 return true;
88 }
89 const int cornerD = isPositionWithin(Position(shapeBoundary.xmin(), shapeBoundary.ymax()));
90 if ((cornerA + cornerB + cornerC + cornerD) == 2) {
91 return true;
92 }
93 // on this point, whe need to check if every shape line intersect with triangle
94 for (int i = 0; i < ((int)shape.size() - 1); i++) {
95 if (lineIntersectsTriangle(shape[i], shape[i + 1])) {
96 return true;
97 }
98 }
99 return false;
100}
101
102
103bool
104Triangle::intersectWithCircle(const Position& center, const double radius) const {
105 const auto squaredRadius = radius * radius;
106 return ((center.distanceSquaredTo2D(myA) <= squaredRadius) ||
107 (center.distanceSquaredTo2D(myB) <= squaredRadius) ||
108 (center.distanceSquaredTo2D(myC) <= squaredRadius) ||
109 isPositionWithin(center) ||
110 lineIntersectCircle(myA, myB, center, radius) ||
111 lineIntersectCircle(myB, myC, center, radius) ||
112 lineIntersectCircle(myC, myA, center, radius));
113}
114
115
116const Boundary&
118 return myBoundary;
119}
120
121
122const PositionVector
124 return PositionVector({myA, myB, myC});
125}
126
127
128std::vector<Triangle>
130 std::vector<Triangle> triangles;
131 // first open polygon
132 shape.openPolygon();
133 // we need at leas three vertex
134 if (shape.size() >= 3) {
135 // greedy algorithm
136 while (shape.size() > 3) {
137 int shapeSize = (int)shape.size();
138 int earIndex = -1;
139 // first find an "ear"
140 for (int i = 0; (i < shapeSize) && (earIndex == -1); i++) {
141 const auto& earA = shape[(i + shapeSize - 1) % shapeSize];
142 const auto& earB = shape[i];
143 const auto& earC = shape[(i + 1) % shapeSize];
144 if (isEar(earA, earB, earC, shape)) {
145 earIndex = i;
146 }
147 }
148 if (earIndex != -1) {
149 triangles.push_back(Triangle(
150 shape[(earIndex + shapeSize - 1) % shapeSize],
151 shape[earIndex],
152 shape[(earIndex + 1) % shapeSize])
153 );
154 shape.erase(shape.begin() + earIndex);
155 } else {
156 // simply remove the first three
157 triangles.push_back(Triangle(shape[0], shape[1], shape[2]));
158 shape.erase(shape.begin() + 1);
159 }
160 }
161 // add last triangle
162 triangles.push_back(Triangle(shape[0], shape[1], shape[2]));
163 }
164 return triangles;
165}
166
167
168bool
169Triangle::operator==(const Triangle& other) const {
170 return myA == other.myA && myB == other.myB && myC == other.myC;
171}
172
173
174bool
175Triangle::operator!=(const Triangle& other) const {
176 return !(*this == other);
177}
178
179
180bool
181Triangle::isPositionWithin(const Position& A, const Position& B, const Position& C, const Position& pos) {
182 // Calculate cross products for each edge of the triangle
183 const double crossAB = crossProduct(A, B, pos);
184 const double crossBC = crossProduct(B, C, pos);
185 const double crossCA = crossProduct(C, A, pos);
186 // Check if all cross products have the same sign
187 return ((crossAB >= 0) && (crossBC >= 0) && (crossCA >= 0)) ||
188 ((crossAB <= 0) && (crossBC <= 0) && (crossCA <= 0));
189}
190
191
192bool
193Triangle::isEar(const Position& a, const Position& b, const Position& c, const PositionVector& shape) {
194 // Check if triangle ABC is counter-clockwise
195 if (crossProduct(a, b, c) <= 0) {
196 return false;
197 }
198 // Check if any other point in the polygon lies inside the triangle
199 for (const auto& pos : shape) {
200 if ((pos != a) && (pos != b) && (pos != c) && isPositionWithin(a, b, c, pos)) {
201 return false;
202 }
203 }
204 return true;
205}
206
207
208double
209Triangle::crossProduct(const Position& a, const Position& b, const Position& c) {
210 return (b.x() - a.x()) * (c.y() - a.y()) - (b.y() - a.y()) * (c.x() - a.x());
211}
212
213
214int
215Triangle::orientation(const Position& p, const Position& q, const Position& r) const {
216 const double val = (q.y() - p.y()) * (r.x() - q.x()) - (q.x() - p.x()) * (r.y() - q.y());
217 if (val > 0) {
218 // Clockwise
219 return 1;
220 } else if (val < 0) {
221 // Counterclockwise
222 return -1;
223 } else {
224 // Collinear
225 return 0;
226 }
227}
228
229
230bool
231Triangle::onSegment(const Position& p, const Position& q, const Position& r) const {
232 return (q.x() >= std::min(p.x(), r.x()) && q.x() <= std::max(p.x(), r.x()) &&
233 q.y() >= std::min(p.y(), r.y()) && q.y() <= std::max(p.y(), r.y()));
234}
235
236
237bool
238Triangle::segmentsIntersect(const Position& p1, const Position& q1, const Position& p2, const Position& q2) const {
239 const int o1 = orientation(p1, q1, p2);
240 const int o2 = orientation(p1, q1, q2);
241 const int o3 = orientation(p2, q2, p1);
242 const int o4 = orientation(p2, q2, q1);
243 // General case: segments intersect if they have different orientations
244 // Special cases: checking if points are collinear and on segment
245 if ((o1 != o2) && (o3 != o4)) {
246 return true;
247 } else if ((o1 == 0) && onSegment(p1, p2, q1)) {
248 return true;
249 } else if ((o2 == 0) && onSegment(p1, q2, q1)) {
250 return true;
251 } else if ((o3 == 0) && onSegment(p2, p1, q2)) {
252 return true;
253 } else if ((o4 == 0) && onSegment(p2, q1, q2)) {
254 return true;
255 } else {
256 return false;
257 }
258}
259
260
261bool
263 return segmentsIntersect(p1, p2, myA, myB) ||
264 segmentsIntersect(p1, p2, myB, myC) ||
265 segmentsIntersect(p1, p2, myC, myA);
266}
267
268
269bool
270Triangle::lineIntersectCircle(const Position& posA, const Position& posB, const Position& center, const double radius) const {
271 // Calculate coefficients of the quadratic equation
272 const double dx = posB.x() - posA.x();
273 const double dy = posB.y() - posA.y();
274 const double a = dx * dx + dy * dy;
275 const double b = 2 * (dx * (posA.x() - center.x()) + dy * (posA.y() - center.y()));
276 const double c = (posA.x() - center.x()) * (posA.x() - center.x()) + (posA.y() - center.y()) * (posA.y() - center.y()) - radius * radius;
277 // Calculate the discriminant
278 const double discriminant = (b * b - 4 * a * c);
279 // Check the discriminant to determine the intersection
280 if (discriminant >= 0) {
281 // Calculate the two possible values of t
282 const double sqrtDiscriminant = sqrt(discriminant);
283 const double t1 = (-b + sqrtDiscriminant) / (2 * a);
284 const double t2 = (-b - sqrtDiscriminant) / (2 * a);
285 // if at least t1 or t2 is between [0,1], then intersect
286 return (t1 >= 0 && t1 <= 1) || (t2 >= 0 && t2 <= 1);
287 } else {
288 return false;
289 }
290}
291
292/****************************************************************************/
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
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
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
double x() const
Returns the x-position.
Definition Position.h:52
double y() const
Returns the y-position.
Definition Position.h:57
A list of positions.
void openPolygon()
open polygon
Boundary getBoxBoundary() const
Returns a boundary enclosing this list of lines.
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
const Boundary & getBoundary() const
get triangle boundary
Definition Triangle.cpp:117
int orientation(const Position &p, const Position &q, const Position &r) const
Definition Triangle.cpp:215
bool segmentsIntersect(const Position &p1, const Position &q1, const Position &p2, const Position &q2) const
check if two line segments (p1,q1) and (p2,q2) intersect
Definition Triangle.cpp:238
Boundary myBoundary
triangle boundary
Definition Triangle.h:123
bool operator!=(const Triangle &other) const
inequality operator
Definition Triangle.cpp:175
bool isPositionWithin(const Position &pos) const
check if the given position is within this triangle
Definition Triangle.cpp:53
const PositionVector getShape() const
get shape boundary
Definition Triangle.cpp:123
bool isBoundaryFullWithin(const Boundary &boundary) const
check if the given position is FULL within this triangle
Definition Triangle.cpp:59
~Triangle()
destructor
Definition Triangle.cpp:49
static const Triangle INVALID
invalid triangle
Definition Triangle.h:39
static bool isEar(const Position &a, const Position &b, const Position &c, const PositionVector &shape)
Check if the triangle (A, B, C) is an ear.
Definition Triangle.cpp:193
bool lineIntersectsTriangle(const Position &p1, const Position &p2) const
check if a line segment (p1, p2) intersects this triangle
Definition Triangle.cpp:262
static std::vector< Triangle > triangulate(PositionVector shape)
Definition Triangle.cpp:129
bool intersectWithShape(const PositionVector &shape) const
check if the given shape is within or intersect with this triangle
Definition Triangle.cpp:68
Position myB
second triangle position
Definition Triangle.h:117
Triangle()
default constructor
Definition Triangle.cpp:35
bool onSegment(const Position &p, const Position &q, const Position &r) const
check if point q lies on segment pr
Definition Triangle.cpp:231
Position myA
first triangle position
Definition Triangle.h:114
bool operator==(const Triangle &other) const
equalityoperators
Definition Triangle.cpp:169
Position myC
third triangle position
Definition Triangle.h:120
bool lineIntersectCircle(const Position &posA, const Position &posB, const Position &center, const double radius) const
function to check if line between posA and posB intersect circle
Definition Triangle.cpp:270
bool intersectWithCircle(const Position &center, const double radius) const
check if the given circle intersect with this triangle
Definition Triangle.cpp:104
static double crossProduct(const Position &a, const Position &b, const Position &c)
calculate cross product of the given points
Definition Triangle.cpp:209