Gamp v0.0.7-36-g24b1eb6
Gamp: Graphics, Audio, Multimedia and Processing
Loading...
Searching...
No Matches
geom3f2D.hpp
Go to the documentation of this file.
1/*
2 * Author: Sven Gothel <sgothel@jausoft.com>
3 * Copyright Gothel Software e.K.
4 *
5 * SPDX-License-Identifier: MIT
6 *
7 * This Source Code Form is subject to the terms of the MIT License
8 * If a copy of the MIT was not distributed with this file,
9 * you can obtain one at https://opensource.org/license/mit/.
10 */
11#ifndef JAU_MATH_GEOM_GEOM3F2D_HPP_
12#define JAU_MATH_GEOM_GEOM3F2D_HPP_
13
14#include <limits>
15#include "jau/int_types.hpp"
16#include <jau/darray.hpp>
17#include <jau/math/vec3f.hpp>
20
21namespace jau::math::geom {
22
23 /** \addtogroup Math
24 *
25 * @{
26 */
27
28 //
29 // 2D geom using 3D data, ignoring Z and avoiding expensive polymorphism
30 //
31
33
34 /**
35 * Computes the area of a list of vertices via shoelace formula.
36 *
37 * This method is utilized e.g. to reliably compute the {@link Winding} of complex shapes.
38 *
39 * Implementation uses double precision.
40 *
41 * @param vertices
42 * @return positive area if ccw else negative area value
43 * @see #getWinding()
44 */
45 constexpr double area2D(const Vec3fList& vertices) noexcept {
46 size_t n = vertices.size();
47 double area = 0.0;
48 for (size_t p = n - 1, q = 0; q < n; p = q++) {
49 const Vec3f& pCoord = vertices[p];
50 const Vec3f& qCoord = vertices[q];
51 area += (double)pCoord.x * (double)qCoord.y - (double)qCoord.x * (double)pCoord.y;
52 }
53 return area;
54 }
55
56 /**
57 * Compute the winding using the area2D() function over all vertices for complex shapes.
58 *
59 * Uses the {@link #area(List)} function over all points
60 * on complex shapes for a reliable result!
61 *
62 * Implementation uses double precision.
63 *
64 * @param vertices array of Vertices
65 * @return Winding::CCW or Winding::CLW
66 * @see area2D()
67 */
68 constexpr Winding getArea2DWinding(const Vec3fList& vertices) noexcept {
69 return area2D(vertices) >= 0 ? Winding::CCW : Winding::CW ;
70 }
71
72
73 constexpr double sqlend(double x, double y) noexcept {
74 return x*x + y*y;
75 }
76 constexpr double triArea(double ax, double ay, double bx, double by, double cx, double cy) noexcept {
77 return (bx - ax) * (cy - ay) - (by - ay) * (cx - ax);
78 }
79 constexpr double triArea(float ax, float ay, float bx, float by, float cx, float cy) noexcept {
80 return (bx - ax) * (cy - ay) - (by - ay) * (cx - ax);
81 }
82 /**
83 * Computes oriented double area of a triangle,
84 * i.e. the 2x2 determinant with b-a and c-a per column.
85 * <pre>
86 * | bx-ax, cx-ax |
87 * det = | by-ay, cy-ay |
88 * </pre>
89 * @param a first vertex
90 * @param b second vertex
91 * @param c third vertex
92 * @return area > 0 CCW, ..
93 */
94 constexpr double triArea2D(const Vec3f& a, const Vec3f& b, const Vec3f& c) noexcept {
95 return triArea(a.x, a.y, b.x, b.y, c.x, c.y);
96 }
97 constexpr double inCircle2DVal(const Vec3f& a, const Vec3f& b, const Vec3f& c, const Vec3f& d) noexcept {
98 // Operation costs:
99 // - 4x (triAreaVec2: 5+, 2*) -> 20+, 8*
100 // - plus 7+, 12* -> 27+, 20*
101 return sqlend(a.x, a.y) * triArea2D(b, c, d) -
102 sqlend(b.x, b.y) * triArea2D(a, c, d) +
103 sqlend(c.x, c.y) * triArea2D(a, b, d) -
104 sqlend(d.x, d.y) * triArea2D(a, b, c);
105 }
106 /**
107 * Check if vertices in triangle circumcircle given {@code d} vertex, from paper by Guibas and Stolfi (1985).
108 * <p>
109 * Implementation uses double precision.
110 * </p>
111 * @param a triangle vertex 1
112 * @param b triangle vertex 2
113 * @param c triangle vertex 3
114 * @param d vertex in question
115 * @return true if the vertex d is inside the circle defined by the vertices a, b, c.
116 */
117 constexpr bool isInCircle2D(const Vec3f& a, const Vec3f& b, const Vec3f& c, const Vec3f& d) noexcept {
118 return inCircle2DVal(a, b, c, d) > std::numeric_limits<double>::epsilon();
119 }
120
121 /**
122 * Check if points are in ccw order
123 * <p>
124 * Consider using {@link #getWinding(List)} using the {@link #area(List)} function over all points
125 * on complex shapes for a reliable result!
126 * </p>
127 * @param a first vertex
128 * @param b second vertex
129 * @param c third vertex
130 * @return true if the points a,b,c are in a ccw order
131 * @see #getWinding(List)
132 */
133 constexpr bool is2DCCW(const Vec3f& a, const Vec3f& b, const Vec3f& c) noexcept {
134 return triArea2D(a,b,c) > std::numeric_limits<double>::epsilon();
135 }
136
137 /**
138 * Compute the winding of the 3 given points
139 * <p>
140 * Consider using {@link #getWinding(List)} using the {@link #area(List)} function over all points
141 * on complex shapes for a reliable result!
142 * </p>
143 * @param a first vertex
144 * @param b second vertex
145 * @param c third vertex
146 * @return {@link Winding#CCW} or {@link Winding#CW}
147 * @see #getWinding(List)
148 */
149 constexpr Winding get2DWinding(const Vec3f& a, const Vec3f& b, const Vec3f& c) noexcept {
150 return is2DCCW(a,b,c) ? Winding::CCW : Winding::CW ;
151 }
152
153 /**
154 * 2D line segment intersection test w/o considering collinear-case
155 * <p>
156 * See [p + t r = q + u s](https://stackoverflow.com/questions/563198/how-do-you-detect-where-two-line-segments-intersect/565282#565282)
157 * and [its terse C# implementation](https://www.codeproject.com/tips/862988/find-the-intersection-point-of-two-line-segments)
158 * </p>
159 * <p>
160 * Implementation uses float precision.
161 * </p>
162 * @param p vertex 1 of first segment
163 * @param p2 vertex 2 of first segment
164 * @param q vertex 1 of second segment
165 * @param q2 vertex 2 of second segment
166 * @return true if line segments are intersecting, otherwise false
167 */
168 constexpr bool testSeg2SegIntersection2D(const Vec3f& p, const Vec3f& p2, const Vec3f& q, const Vec3f& q2) noexcept
169 {
170 // Operations: 11+, 8*, 2 branches
171 const float rx = p2.x - p.x; // p2.minus(p)
172 const float ry = p2.y - p.y;
173 const float sx = q2.x - q.x; // q2.minus(q)
174 const float sy = q2.y - q.y;
175 const float rxs = rx * sy - ry * sx; // r.cross(s)
176
177 constexpr float eps = std::numeric_limits<float>::epsilon();
178
179 if ( jau::is_zero(rxs, eps) ) {
180 // Not considering collinear case as an intersection
181 return false;
182 } else {
183 // r x s != 0
184 const float q_px = q.x - p.x; // q.minus(p)
185 const float q_py = q.y - p.y;
186 const float qpxr = q_px * ry - q_py * rx; // q_p.cross(r)
187
188 // p + t r = q + u s
189 // (p + t r) × s = (q + u s) × s
190 // t (r × s) = (q − p) × s, with s x s = 0
191 // t = (q - p) x s / (r x s)
192 const float t = ( q_px * sy - q_py * sx ) / rxs; // q_p.cross(s) / rxs
193
194 // u = (p − q) × r / (s × r) = (q - p) x r / (r x s), with s × r = − r × s
195 const float u = qpxr / rxs;
196
197 // if ( (0 <= t && t <= 1) && (0 <= u && u <= 1) )
198 if ( (eps <= t && t - 1 <= eps) && (eps <= u && u - 1 <= eps) )
199 {
200 // 3) r × s ≠ 0 and 0 ≤ t ≤ 1 and 0 ≤ u ≤ 1, the two line segments meet at the point p + t * r = q + u * s.
201 return true;
202 }
203 }
204 return false;
205 }
206
207 /**
208 * Check if a segment intersects with a triangle using {@link FloatUtil#EPSILON} w/o considering collinear-case
209 * <p>
210 * Implementation uses float precision.
211 * </p>
212 * @param a vertex 1 of the triangle
213 * @param b vertex 2 of the triangle
214 * @param c vertex 3 of the triangle
215 * @param d vertex 1 of first segment
216 * @param e vertex 2 of first segment
217 * @return true if the segment intersects at least one segment of the triangle, false otherwise
218 * @see #testSeg2SegIntersection(Vert2fImmutable, Vert2fImmutable, Vert2fImmutable, Vert2fImmutable, float, boolean)
219 */
220 constexpr bool testTri2SegIntersection2D(const Vec3f& a, const Vec3f& b, const Vec3f& c,
221 const Vec3f& d, const Vec3f& e) {
222 return testSeg2SegIntersection2D(a, b, d, e) ||
223 testSeg2SegIntersection2D(b, c, d, e) ||
224 testSeg2SegIntersection2D(a, c, d, e) ;
225 }
226
227 /**@}*/
228
229} // namespace jau::math::geom
230
231#endif /* JAU_MATH_GEOM_GEOM3F2D_HPP_ */
Implementation of a dynamic linear array storage, aka vector, including relative positional access.
Definition darray.hpp:153
value_type x
Definition vec3f.hpp:69
value_type y
Definition vec3f.hpp:70
std::enable_if_t< std::is_floating_point_v< T >, bool > constexpr is_zero(const T &a, const T &epsilon=std::numeric_limits< T >::epsilon()) noexcept
Returns true if the given value is less than epsilon, w/ epsilon > 0.
constexpr double sqlend(double x, double y) noexcept
Definition geom3f2D.hpp:73
constexpr double triArea2D(const Vec3f &a, const Vec3f &b, const Vec3f &c) noexcept
Computes oriented double area of a triangle, i.e.
Definition geom3f2D.hpp:94
constexpr bool is2DCCW(const Vec3f &a, const Vec3f &b, const Vec3f &c) noexcept
Check if points are in ccw order.
Definition geom3f2D.hpp:133
constexpr bool testSeg2SegIntersection2D(Vec2f *result, const Vec2f &p, const Vec2f &p2, const Vec2f &q, const Vec2f &q2, const bool do_collinear=false) noexcept
See p + t r = q + u s and its terse C# implementation
Definition geom2f.hpp:61
constexpr double triArea(double ax, double ay, double bx, double by, double cx, double cy) noexcept
Definition geom3f2D.hpp:76
jau::darray< Vec3f, jau::nsize_t > Vec3fList
Definition geom3f2D.hpp:32
constexpr Winding get2DWinding(const Vec3f &a, const Vec3f &b, const Vec3f &c) noexcept
Compute the winding of the 3 given points.
Definition geom3f2D.hpp:149
constexpr double area2D(const Vec3fList &vertices) noexcept
Computes the area of a list of vertices via shoelace formula.
Definition geom3f2D.hpp:45
constexpr Winding getArea2DWinding(const Vec3fList &vertices) noexcept
Compute the winding using the area2D() function over all vertices for complex shapes.
Definition geom3f2D.hpp:68
Vector3F< float > Vec3f
Definition vec3f.hpp:436
constexpr bool testTri2SegIntersection2D(const Vec3f &a, const Vec3f &b, const Vec3f &c, const Vec3f &d, const Vec3f &e)
Check if a segment intersects with a triangle using FloatUtil#EPSILON w/o considering collinear-case.
Definition geom3f2D.hpp:220
constexpr bool isInCircle2D(const Vec3f &a, const Vec3f &b, const Vec3f &c, const Vec3f &d) noexcept
Check if vertices in triangle circumcircle given d vertex, from paper by Guibas and Stolfi (1985).
Definition geom3f2D.hpp:117
constexpr double inCircle2DVal(const Vec3f &a, const Vec3f &b, const Vec3f &c, const Vec3f &d) noexcept
Definition geom3f2D.hpp:97
@ CCW
Counter-Clockwise.
Definition geom.hpp:39