Wildmeshing Toolkit
Loading...
Searching...
No Matches
GeoUtils.h
1#pragma once
2
3
4#include <Eigen/Core>
5#include <Eigen/Dense>
6#include <optional>
7
8
9#include <array>
10
11namespace wmtk {
12
13
14template <typename T>
15int orient3d_t(
16 const Eigen::Matrix<T, 3, 1>& p1,
17 const Eigen::Matrix<T, 3, 1>& p2,
18 const Eigen::Matrix<T, 3, 1>& p3,
19 const Eigen::Matrix<T, 3, 1>& p4)
20{
21 const auto v = ((p2 - p1).cross(p3 - p1)).dot(p4 - p1);
22 return v == 0 ? 0 : (v < 0 ? -1 : 1);
23}
24
25template <>
26int orient3d_t(
27 const Eigen::Matrix<double, 3, 1>& p1,
28 const Eigen::Matrix<double, 3, 1>& p2,
29 const Eigen::Matrix<double, 3, 1>& p3,
30 const Eigen::Matrix<double, 3, 1>& p4);
31
32
33template <typename T>
34T cross_2d(const Eigen::Matrix<T, 2, 1>& p1, const Eigen::Matrix<T, 2, 1>& p2)
35{
36 return p1.homogeneous().cross(p2.homogeneous()).z();
37}
38
39
40template <typename T>
41int orient2d_t(
42 const Eigen::Matrix<T, 2, 1>& p1,
43 const Eigen::Matrix<T, 2, 1>& p2,
44 const Eigen::Matrix<T, 2, 1>& p3)
45{
46 const auto det = cross_2d<T>(p2 - p1, p3 - p1);
47 return det == 0 ? 0 : (det < 0 ? -1 : 1);
48}
49
50template <>
51int orient2d_t(
52 const Eigen::Matrix<double, 2, 1>& p1,
53 const Eigen::Matrix<double, 2, 1>& p2,
54 const Eigen::Matrix<double, 2, 1>& p3);
55
56template <typename T, bool EarlyOut = false>
57std::optional<std::tuple<Eigen::Matrix<T, 3, 1>, bool>> open_segment_triangle_intersection_3d(
58 const std::array<Eigen::Matrix<T, 3, 1>, 2>& seg,
59 const std::array<Eigen::Matrix<T, 3, 1>, 3>& tri)
60{
61 std::optional<std::tuple<Eigen::Matrix<T, 3, 1>, bool>> ret_value = std::nullopt;
62 const auto& [e0, e1] = seg;
63 const auto& [t0, t1, t2] = tri;
64
65 // Note: could potentially cache cofactors to reduce redundant ops
66
67 auto det = [](const auto& u, const auto& v, const auto& w) -> T { return u.cross(v).dot(w); };
68 auto detsum = [det](const auto& E, const auto& a, const auto& b, const auto& c) -> T {
69 return det(E, a, b) + det(E, c, a) + det(E, b, c);
70 };
71
72 const T d_0 = detsum(e0, t0, t1, t2);
73 const T d_1 = detsum(e1, t0, t1, t2);
74 const T d = d_0 - d_1;
75 const T D = det(t0, t1, t2);
76
77
78 // Coplanar
79 if (d == 0) return ret_value;
80
81
82 const T t = (d_0 - D) / d;
83
84 const bool t_outside = t <= 0 || t >= 1;
85 if (t_outside) return ret_value;
86
87 const T u = (detsum(e0, e1, t0, t2) + det(e1, t0, t2)) / d;
88
89 const bool u_outside = u < 0 || u > 1;
90 if constexpr (EarlyOut)
91 if (u_outside) return ret_value;
92
93 const T v = (detsum(e0, e1, t0, t1) - det(e1, t0, t1)) / d;
94 const bool v_outside = v < 0 || v > 1;
95 if constexpr (EarlyOut)
96 if (v_outside) return ret_value;
97 const bool uv_outside = u + v > 1;
98 if constexpr (EarlyOut)
99 if (uv_outside) return ret_value;
100
101
102 auto& [p, is_inside] = ret_value.emplace();
103 p = (1 - t) * e0 + t * e1;
104 is_inside = u_outside || v_outside || uv_outside;
105
106 return ret_value;
107}
108
109template <typename T>
110bool open_segment_triangle_intersection_3d(
111 const std::array<Eigen::Matrix<T, 3, 1>, 2>& seg,
112 const std::array<Eigen::Matrix<T, 3, 1>, 3>& tri,
113 Eigen::Matrix<T, 3, 1>& p)
114{
115 auto ret_opt = open_segment_triangle_intersection_3d<T, true>(seg, tri);
116 if (!ret_opt.has_value()) {
117 return false;
118 }
119 p = std::get<0>(ret_opt.value());
120 return true;
121}
122
123template <typename T>
124bool open_segment_plane_intersection_3d(
125 const std::array<Eigen::Matrix<T, 3, 1>, 2>& seg,
126 const std::array<Eigen::Matrix<T, 3, 1>, 3>& tri,
127 Eigen::Matrix<T, 3, 1>& p,
128 bool& is_inside)
129{
130 auto ret_opt = open_segment_triangle_intersection_3d<T, false>(seg, tri);
131 if (!ret_opt.has_value()) {
132 return false;
133 }
134 std::tie(p, is_inside) = ret_opt.value();
135 return true;
136}
137
138template <typename T>
139bool segment_triangle_coplanar_3d(
140 const std::array<Eigen::Matrix<T, 3, 1>, 2>& seg,
141 const std::array<Eigen::Matrix<T, 3, 1>, 3>& tri)
142{
143 const auto o1 = orient3d_t(seg[0], tri[0], tri[1], tri[2]);
144 const auto o2 = orient3d_t(seg[1], tri[0], tri[1], tri[2]);
145
146 return o1 == 0 && o2 == 0;
147}
148
149// note: t1 is for seg1, intersection point: (1 - t1) * seg1[0] + t1 * seg1[1]
150template <typename T>
151bool open_segment_open_segment_intersection_2d(
152 const std::array<Eigen::Matrix<T, 2, 1>, 2>& seg_1,
153 const std::array<Eigen::Matrix<T, 2, 1>, 2>& seg_2,
154 T& t1)
155{
156 const auto o1 = orient2d_t(seg_1[0], seg_2[0], seg_2[1]);
157 const auto o2 = orient2d_t(seg_1[1], seg_2[0], seg_2[1]);
158 t1 = -1;
159
160 if (o1 == 0 && o2 == 0) // Collinear
161 {
162 // If they overlap we return false, if they dont we return false
163 return false;
164 }
165
166 if (o1 * o2 >= 0) // two vertices of seg1 are on the same side, or on
167 return false;
168
169 const auto o3 = orient2d_t(seg_2[0], seg_1[0], seg_1[1]);
170 const auto o4 = orient2d_t(seg_2[1], seg_1[0], seg_1[1]);
171
172 if (o3 * o4 >= 0) // two vertices of seg1 are on the same side, or on
173 return false;
174
175 const Eigen::Matrix<T, 2, 1> e1 = seg_1[1] - seg_1[0];
176 const Eigen::Matrix<T, 2, 1> e2 = seg_2[1] - seg_2[0];
177 t1 = cross_2d<T>(seg_2[0] - seg_1[0], e2) / cross_2d(e1, e2);
178
179 // TODO add t
180 return true;
181}
182
183// note: use the first 3 points to construct the plane
184template <typename T>
185int project_to_2d_by_normal(const Eigen::Matrix<T, 3, 1>& n)
186{
187 int J = 0;
188 T max = abs(n[J]); // delete max
189 for (int j = 0; j < 3; j++) {
190 if (abs(n[j]) > max) {
191 max = abs(n[j]);
192 J = j;
193 }
194 }
195
196 return J;
197}
198
199template <typename T>
200int project_triangle_to_2d(
201 const std::array<Eigen::Matrix<T, 3, 1>, 3>& points3,
202 std::array<Eigen::Matrix<T, 2, 1>, 3>& points2)
203{
204 const auto& p1 = points3[0];
205 const auto& p2 = points3[1];
206 const auto& p3 = points3[2];
207
208 Eigen::Matrix<T, 3, 1> n = (p2 - p1).cross(p3 - p1);
209
210 int J = project_to_2d_by_normal(n);
211
212 for (int i = 0; i < points3.size(); i++) {
213 if (J == 0) {
214 points2[i] = Eigen::Matrix<T, 2, 1>(points3[i][1], points3[i][2]);
215 } else if (J == 1) {
216 points2[i] = Eigen::Matrix<T, 2, 1>(points3[i][0], points3[i][2]);
217 } else {
218 points2[i] = Eigen::Matrix<T, 2, 1>(points3[i][0], points3[i][1]);
219 }
220 }
221
222 return J;
223}
224
225template <typename T>
226Eigen::Matrix<T, 2, 1> project_point_to_2d(const Eigen::Matrix<T, 3, 1>& p, int t)
227{
228 if (t == 0)
229 return Eigen::Matrix<T, 2, 1>(p[1], p[2]);
230 else if (t == 1)
231 return Eigen::Matrix<T, 2, 1>(p[0], p[2]);
232 else
233 return Eigen::Matrix<T, 2, 1>(p[0], p[1]);
234}
235
236template <typename T>
237bool is_point_inside_triangle( // closed triangle
238 const Eigen::Matrix<T, 2, 1>& p,
239 const std::array<Eigen::Matrix<T, 2, 1>, 3>& tri)
240{
241 // auto res = orient2d_t(p, tri[0], tri[1]);
242 // if (res < 0) return false;
243 //
244 // res = orient2d_t(p, tri[1], tri[2]);
245 // if (res < 0) return false;
246 //
247 // res = orient2d_t(p, tri[2], tri[0]);
248 // if (res < 0) return false;
249
250 auto res1 = orient2d_t(p, tri[0], tri[1]);
251 auto res2 = orient2d_t(p, tri[1], tri[2]);
252 auto res3 = orient2d_t(p, tri[2], tri[0]);
253
254 if (res1 == 0 && res2 == 0) return true;
255 if (res1 == 0 && res3 == 0) return true;
256 if (res2 == 0 && res3 == 0) return true;
257
258 if ((res1 == res2 && res2 == res3) || (res1 == 0 && res2 == res3) ||
259 (res2 == 0 && res3 == res1) || (res3 == 0 && res2 == res1))
260 return true;
261 return false;
262}
263
264} // namespace wmtk