Skip to content

Commit f9e1cc1

Browse files
committed
merged r-tree from develop_delaunay feature branch. adapted code to updated linear_algebra module
2 parents 3e7d833 + 37942f6 commit f9e1cc1

10 files changed

Lines changed: 1355 additions & 255 deletions

File tree

fdaPDE/geometry.h

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -34,9 +34,8 @@
3434
#include "src/geometry/tetrahedron.h"
3535
// algorithms
3636
/* #include "src/geometry/kd_tree.h" */
37-
/* #include "src/geometry/tree_search.h" */
38-
/* #include "src/geometry/walk_search.h" */
39-
/* #include "src/geometry/projection.h" */
37+
#include "src/geometry/r_tree.h"
38+
/* #include "src/geometry/walk.h" */
4039
// data structures
4140
#include "src/geometry/triangulation.h"
4241
/* #include "src/geometry/interval.h" */

fdaPDE/src/geometry/kd_tree.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ template <int K> class KDTree {
6868
if (point_set.end - (median + 1) > 0) stack.emplace(median + 1, point_set.end, split_dim);
6969
}
7070
}
71-
// range for over node ids, you can recover the node coordinates by for(auto p : kdtree) { data_.row(p); }
71+
// iterators
7272
iterator begin() { return kdtree_.begin(); }
7373
iterator end() { return kdtree_.end(); }
7474

@@ -115,7 +115,7 @@ template <int K> class KDTree {
115115
struct RangeType {
116116
Matrix<double, K, 1> ll, ur; // lower-left and upper-right corner
117117
};
118-
// returns a set of iterators to the nodes contained in the query
118+
// returns the set of nodes contained in the query
119119
std::unordered_set<int> range_search(const RangeType& query) const {
120120
std::unordered_set<int> result;
121121
std::stack<iterator> stack; // auxiliary stack for tree visiting

fdaPDE/src/geometry/primitives.h

Lines changed: 150 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -48,39 +48,29 @@ constexpr bool are_2d_counterclockwise_sorted(const PointT& a, const PointT& b,
4848
return signed_measure_2d_tri(a, b, c) > 0;
4949
}
5050
// area of 2D polygon given counterclockwise sorted vertices v_0, v_1, \ldots, v_{n - 1} (lemma 1.3.3 of (1))
51-
template <typename PointList>
52-
requires(internals::is_eigen_dense_xpr_v<PointList> || internals::is_subscriptable<PointList, int>)
53-
constexpr double signed_measure_2d_polygon(const PointList& points) {
51+
template <typename PolygonT>
52+
requires(internals::is_matrix_like_v<PolygonT>)
53+
constexpr double signed_measure_2d_polygon(const PolygonT& points) {
5454
double area = 0;
55-
if constexpr (internals::is_eigen_dense_xpr_v<PointList>) {
56-
fdapde_assert(points.rows() > 0 && points.cols() == 2);
57-
int n_points = points.rows();
58-
for (int i = 0; i < n_points - 1; ++i) {
59-
area += (points(i, 0) + points(i + 1, 0)) * (points(i + 1, 1) - points(i, 1));
60-
}
61-
area += (points(n_points - 1, 0) + points(0, 0)) * (points(0, 1) - points(n_points - 1, 1));
62-
} else if (internals::is_subscriptable<PointList, int>) {
63-
// assume points to be a RowMajor expansion of the polygon nodes' coordinates
64-
fdapde_assert(points.size() % 2 == 0);
65-
int n_points = points.size() / 2;
66-
for (int i = 0; i < n_points - 1; ++i) {
67-
area += (points[i] + points[i + 2]) * (points[i + 3] - points[i + 1]);
68-
}
69-
area += (points[n_points - 2] + points[0]) * (points[1] - points[n_points - 1]);
55+
fdapde_assert(points.rows() > 0 && points.cols() == 2);
56+
int n_points = points.rows();
57+
for (int i = 0; i < n_points - 1; ++i) {
58+
area += (points(i, 0) + points(i + 1, 0)) * (points(i + 1, 1) - points(i, 1));
7059
}
60+
area += (points(n_points - 1, 0) + points(0, 0)) * (points(0, 1) - points(n_points - 1, 1));
7161
return area;
7262
}
73-
template <typename PointList> constexpr bool are_2d_counterclockwise_sorted(const PointList& points) {
63+
template <typename PolygonT> constexpr bool are_2d_counterclockwise_sorted(const PolygonT& points) {
7464
return signed_measure_2d_polygon(points) > 0;
7565
}
76-
template <typename PointList> constexpr bool are_2d_clockwise_sorted(const PointList& points) {
66+
template <typename PolygonT> constexpr bool are_2d_clockwise_sorted(const PolygonT& points) {
7767
return signed_measure_2d_polygon(points) < 0;
7868
}
7969

8070
// 2D point-line orientation test
8171

82-
// finds whether a 2D point p is on the positive side (left), negative side (right) or is collinear to the 2D directed
83-
// line identified by points (a, b)
72+
// finds whether point p is on the positive side (left), negative side (right) or is collinear to the directed line
73+
// identified by points (a, b)
8474
enum Orientation { LEFT = 0, RIGHT = 1, COLLINEAR = 2 };
8575
template <typename PointT>
8676
requires(internals::is_subscriptable<PointT, int>)
@@ -105,10 +95,10 @@ template <typename point_t> bool reflex_turn(const point_t& a, const point_t& b,
10595
return !convex_turn(a, b, c); // reflex turn \iff not convex turn
10696
}
10797

108-
// test whether a point a belongs to the 2D segment identified by points b and c
98+
// test whether point a belongs to the 2D segment identified by points b and c
10999
template <typename PointT>
110100
requires(internals::is_subscriptable<PointT, int>)
111-
constexpr bool contains(const PointT& a, const PointT& b, const PointT& c) {
101+
constexpr bool contains(const PointT& a, const PointT& b, const PointT& c) { // -------------------- rename in point_in_2d_segment
112102
if (!collinear(a, b, c)) return false;
113103
// if bc is not vertical, check x coordinates, otherwise check y coordinates
114104
if (b[0] != c[0]) {
@@ -121,18 +111,28 @@ constexpr bool contains(const PointT& a, const PointT& b, const PointT& c) {
121111
// 2D segment-segment intersection test
122112
template <typename PointT>
123113
requires(internals::is_subscriptable<PointT, int>)
124-
constexpr bool intersect(const PointT& a, const PointT& b, const PointT& c, const PointT& d) {
114+
constexpr bool segment_proper_intersect_2d_segment(const PointT& a, const PointT& b, const PointT& c, const PointT& d) {
125115
// check proper intersection (points {c, d} lies on opposite sides of ab and points {a, b} on opposite sides of cd)
126116
if (
127117
(orientation(c, a, b) == Orientation::LEFT ^ orientation(d, a, b) == Orientation::LEFT) &&
128118
(orientation(a, c, d) == Orientation::LEFT ^ orientation(b, c, d) == Orientation::LEFT)) {
129119
return true;
130120
}
121+
return false;
122+
}
123+
124+
template <typename PointT>
125+
requires(internals::is_subscriptable<PointT, int>)
126+
constexpr bool intersect(const PointT& a, const PointT& b, const PointT& c, const PointT& d) {
127+
// check proper intersection
128+
if (segment_proper_intersect_2d_segment(a, b, c, d)) { return true; }
131129
// check if an endpoint of a segment lies on the other segment
132-
if (contains(c, a, b) || contains(d, a, b) || contains(a, c, d) || contains(b, c, d)) { return true; }
130+
if (contains(c, a, b) || contains(d, a, b) || contains(a, c, d) || contains(b, c, d)) {
131+
return true; }
133132
return false;
134133
}
135134

135+
// 2D point in triangle test
136136
template <typename PointT>
137137
requires(internals::is_subscriptable<PointT, int>)
138138
constexpr bool point_in_2d_tri(const PointT& a, const PointT& t1, const PointT& t2, const PointT& t3) {
@@ -141,7 +141,130 @@ constexpr bool point_in_2d_tri(const PointT& a, const PointT& t1, const PointT&
141141
(t2[0] - a[0]) * (t3[1] - a[1]) >= (t3[0] - a[0]) * (t2[1] - a[1]);
142142
}
143143

144-
// then we can detect if a diagonal is fully contained in a polygon
144+
// 2D point in polygon (closed simple chain of points) test. ray-casting algorithm
145+
template <typename PolygonT, typename PointT>
146+
requires(internals::is_matrix_like_v<PolygonT> && internals::is_vector_like_v<PointT>)
147+
constexpr bool point_in_2d_polygon(const PolygonT& points, const PointT& p) {
148+
bool inside = false;
149+
fdapde_assert(points.rows() > 0 && points.cols() == 2);
150+
int n = points.rows();
151+
for (int i = 0, j = n - 1; i < n; j = i++) {
152+
if (
153+
((points(i, 1) > p[1]) != (points(j, 1) > p[1])) &&
154+
(p[0] <
155+
(points(j, 0) - points(i, 0)) * (p[1] - points(i, 1)) / (points(j, 1) - points(i, 1)) + points(i, 0))) {
156+
inside = !inside;
157+
}
158+
}
159+
return inside;
160+
}
161+
162+
// 2D polygon in polygon test
163+
template <typename InnerPolygonT, typename OuterPolygonT>
164+
requires(internals::is_matrix_like_v<InnerPolygonT> && internals::is_matrix_like_v<OuterPolygonT>)
165+
constexpr bool polygon_in_2d_polygon(const InnerPolygonT& P, const OuterPolygonT& Q) {
166+
fdapde_assert(P.rows() > 0 && P.cols() == 2 && Q.rows() > 0 && Q.cols() == 2);
167+
// check if all points of P are inside Q
168+
for (int i = 0, n = P.rows(); i < n; ++i) {
169+
if (!point_in_2d_polygon(Q, P.row(i))) { return false; }
170+
}
171+
// check if all edges of P do not properly intersect any edge of Q
172+
for (int i = 0, n = P.rows() - 1; i < n; ++i) {
173+
int h = i + 1 % n;
174+
for (int j = 0, m = Q.rows() - 1; j < m; ++j) {
175+
if (segment_proper_intersect_2d_segment(P.row(i), P.row(h), Q.row(j), Q.row(j + 1 % m))) { return false; }
176+
}
177+
}
178+
return true;
179+
}
180+
181+
// checks if point D is inside the circumcircle of the triangle (A, B, C) (Delaunay criterion)
182+
// template <typename PointT>
183+
// requires(internals::is_subscriptable<PointT, int>)
184+
// constexpr bool in_circle(const PointT& A, const PointT& B, const PointT& C, const PointT& D) {
185+
// double Ax = A[0] - D[0], Ay = A[1] - D[1];
186+
// double Bx = B[0] - D[0], By = B[1] - D[1];
187+
// double Cx = C[0] - D[0], Cy = C[1] - D[1];
188+
189+
// double det = Ax * (By * (Cx * Cx + Cy * Cy) - Cy * (Bx * Bx + By * By)) -
190+
// Ay * (Bx * (Cx * Cx + Cy * Cy) - Cx * (Bx * Bx + By * By)) +
191+
// (Ax * Ax + Ay * Ay) * (Bx * Cy - By * Cx);
192+
193+
// return det > 0; // D is inside the circumcircle if determinant is positive
194+
// }
195+
196+
// // computes circumcenter of triangle given its 2D coordinates
197+
// template <typename PointT>
198+
// requires(internals::is_subscriptable<PointT, int>)
199+
// constexpr PointT circumcenter(const PointT& A, const PointT& B, const PointT& C) {
200+
// double x1 = A[0], y1 = A[1];
201+
// double x2 = B[0], y2 = B[1];
202+
// double x3 = C[0], y3 = C[1];
203+
204+
// double D = 2.0 * (x1*(y2 - y3) + x2*(y3 - y1) + x3*(y1 - y2));
205+
206+
// double x1sq = x1 * x1 + y1 * y1;
207+
// double x2sq = x2 * x2 + y2 * y2;
208+
// double x3sq = x3 * x3 + y3 * y3;
209+
210+
// double Ux = (x1sq*(y2 - y3) + x2sq*(y3 - y1) + x3sq*(y1 - y2)) / D;
211+
// double Uy = (x1sq*(x3 - x2) + x2sq*(x1 - x3) + x3sq*(x2 - x1)) / D;
212+
213+
// return PointT(Ux, Uy);
214+
// }
215+
216+
// // detects if p is inside circle of diameter ab
217+
// template <typename PointT>
218+
// requires(internals::is_subscriptable<PointT, int>)
219+
// constexpr bool is_encroached(const PointT& p, const PointT& a, const PointT& b) {
220+
// PointT m = 0.5 * (a + b); // midpoint
221+
// double radius_sq = 0.25 * (a - b).squaredNorm();
222+
// double dist_sq = (p - m).squaredNorm();
223+
// return dist_sq < radius_sq - machine_epsilon;
224+
// }
225+
226+
// // computes the angle between two segments that share vertex p in 2D (counterclockwise)
227+
// // the angle is in degrees
228+
// template <typename PointT>
229+
// requires(internals::is_subscriptable<PointT, int>)
230+
// constexpr double angle_between(const PointT& a, const PointT& p, const PointT& b) {
231+
// PointT v1 = a - p;
232+
// PointT v2 = b - p;
233+
// double dot = v1.dot(v2);
234+
// double norm1 = std::sqrt(v1.squaredNorm());
235+
// double norm2 = std::sqrt(v2.squaredNorm());
236+
237+
// double cos_theta = dot / (norm1 * norm2);
238+
// cos_theta = std::fmax(-1.0, std::fmin(1.0, cos_theta));
239+
240+
// double angle_rad = std::acos(cos_theta);
241+
// // 2D vector product to dtermine orientation
242+
// double cross = v1[0] * v2[1] - v1[1] * v2[0];
243+
// // if cross > 0: angle is clockwise, so we need to subtract from 2 * pi since boundary is counterclockwise oriented
244+
// if (cross > 0)
245+
// angle_rad = 2 * M_PI - angle_rad;
246+
247+
// return angle_rad * 180.0 / M_PI;
248+
// }
249+
250+
// // checks if the angle between two segments that share vertex p in 2D is acute
251+
// template <typename PointT>
252+
// requires(internals::is_subscriptable<PointT, int>)
253+
// constexpr bool is_angle_acute(const PointT& a, const PointT& p, const PointT& b) {
254+
// return angle_between(a, p, b) < 90.0 - machine_epsilon;
255+
// }
256+
257+
// // calculates segment ab's length (2D)
258+
// template <typename PointT>
259+
// requires(internals::is_subscriptable<PointT, int>)
260+
// constexpr double segment_length(const PointT& a, const PointT& b) {
261+
// const double dx = a[0] - b[0];
262+
// const double dy = a[1] - b[1];
263+
// return std::sqrt(dx * dx + dy * dy);
264+
// }
265+
266+
267+
// then we can detect if a diagonal is fully contained in a polygon
145268

146269
// 3D geometry
147270

fdaPDE/src/geometry/projection.h

Lines changed: 0 additions & 79 deletions
This file was deleted.

0 commit comments

Comments
 (0)