199 constexpr unsigned int LCG_MULT = 1103515245u;
200 constexpr unsigned int LCG_INCR = 12345u;
201 constexpr unsigned int LCG_MASK = 0x7fffffffu;
202 unsigned int seed = 12345;
203 for (
int i = 0; i < 50; ++i)
206 int x =
static_cast<int>(
seed % 1000);
208 int y =
static_cast<int>(
seed % 1000);
232 const Point p = it.get_current_vertex();
271 EXPECT_EQ(result.kind, SegmentSegmentIntersection::Kind::NONE);
282 EXPECT_EQ(result.kind, SegmentSegmentIntersection::Kind::POINT);
294 EXPECT_EQ(result.kind, SegmentSegmentIntersection::Kind::POINT);
304 const auto result =
pair_ix(a, b);
308 scene.segments.append(b);
312 "case_segment_segment_overlap_o1",
scene,
313 "Dedicated O(1) segment-segment overlap");
315 EXPECT_EQ(result.kind, SegmentSegmentIntersection::Kind::OVERLAP);
327 EXPECT_EQ(result.kind, SegmentSegmentIntersection::Kind::OVERLAP);
339 EXPECT_EQ(result.kind, SegmentSegmentIntersection::Kind::POINT);
350 EXPECT_EQ(result.kind, SegmentSegmentIntersection::Kind::POINT);
361 EXPECT_EQ(result.kind, SegmentSegmentIntersection::Kind::NONE);
372 EXPECT_EQ(result.kind, SegmentSegmentIntersection::Kind::POINT);
382 EXPECT_EQ(result.kind, SegmentSegmentIntersection::Kind::POINT);
445 for (
size_t i = 0; i <
segs.size(); ++i)
447 for (
size_t i = 0; i < result.size(); ++i)
448 scene.highlighted_points.append(result(i).point);
450 "case_sweepline_multiple_intersections",
scene,
451 "Sweep-line / multi-intersection degeneracy");
457 for (
size_t i = 0; i < result.size(); ++i)
509 for (
size_t i = 0; i < result.size(); ++i)
819 for (
size_t i = 0; i <
rv.size(); ++i)
823 rv((i + 2) %
rv.size()));
824 if (turn == 0)
continue;
825 int s = turn > 0 ? 1 : -1;
834 return it.get_current_vertex();
853 if (
sp.intersects_with(
itq.get_current_segment()))
867 for (
size_t i = 0; i <
pv.size(); ++i)
868 for (
size_t j = 0; j <
qv.size(); ++j)
882 for (
size_t i = 0; i <
qv.size(); ++i)
883 for (
size_t j = 0; j <
pv.size(); ++j)
919 const auto r =
gjk(a, b);
923 EXPECT_EQ(
r.closest_on_first.distance_squared_to(
r.closest_on_second),
945 const auto r =
gjk(a, b);
969 const auto r =
gjk(a, b);
991 const auto ab =
gjk(a, b);
992 const auto ba =
gjk(b, a);
994 EXPECT_EQ(ab.distance_squared,
ba.distance_squared);
1033 unsigned int seed = 424242;
1034 for (
int tc = 0;
tc < 12; ++
tc)
1037 while (a.
size() < 3)
1040 for (
int i = 0; i < 16; ++i)
1042 seed = (
seed * 1103515245 + 12345) & 0x7fffffff;
1043 const int x =
static_cast<int>(
seed % 51) - 25;
1044 seed = (
seed * 1103515245 + 12345) & 0x7fffffff;
1045 const int y =
static_cast<int>(
seed % 51) - 25;
1051 while (b.
size() < 3)
1054 for (
int i = 0; i < 16; ++i)
1056 seed = (
seed * 1103515245 + 12345) & 0x7fffffff;
1057 const int x =
static_cast<int>(
seed % 51) - 25;
1058 seed = (
seed * 1103515245 + 12345) & 0x7fffffff;
1059 const int y =
static_cast<int>(
seed % 51) - 25;
1065 const auto r =
gjk(a, b);
1100 auto n =
kd.nearest(
Point(12, 12));
1104 auto n2 =
kd.nearest(
Point(48, 52));
1113 auto n =
kd.nearest(
Point(50, 50));
1121 for (
int x = 0; x < 10; ++x)
1122 for (
int y = 0;
y < 10; ++
y)
1129 for (
int x = 0; x < 10; ++x)
1130 for (
int y = 0;
y < 10; ++
y)
1133 auto n =
kd.nearest(
Point(5, 5));
1148 kd.range(5, 5, 25, 25, &
out);
1165 kd.for_each([&visited](
const Point &) { ++visited; });
1177 const auto snap =
kd.debug_snapshot();
1186 for (
size_t i = 0; i <
snap.partitions.size(); ++i)
1187 if (
snap.partitions(i).is_leaf)
1218 v.
append(it.get_current_vertex());
1247 for (
size_t t = 0; t <
r.triangles.size(); ++t)
1249 const auto & tri =
r.triangles(t);
1250 const Point & a =
r.sites(tri.i);
1251 const Point & b =
r.sites(tri.j);
1252 const Point & c =
r.sites(tri.k);
1258 for (
size_t s = 0; s <
r.sites.size(); ++s)
1260 if (s == tri.i
or s == tri.j
or s == tri.k)
1266 <<
"Site " << s <<
" violates empty-circumcircle for triangle "
1277 for (
int x = 0; x < 5; ++x)
1278 for (
int y = 0;
y < 5; ++
y)
1282 auto r = delaunay(
pts);
1286 for (
size_t t = 0; t <
r.triangles.size(); ++t)
1288 const auto & tri =
r.triangles(t);
1289 const Point & a =
r.sites(tri.i);
1290 const Point & b =
r.sites(tri.j);
1291 const Point & c =
r.sites(tri.k);
1295 for (
size_t s = 0; s <
r.sites.size(); ++s)
1297 if (s == tri.i
or s == tri.j
or s == tri.k)
1317 for (
size_t t = 0; t < dt.triangles.size(); ++t)
1319 const auto & tri = dt.triangles(t);
1320 const Point & a = dt.sites(tri.i);
1321 const Point & b = dt.sites(tri.j);
1322 const Point & c = dt.sites(tri.k);
1329 EXPECT_EQ(
da,
db) <<
"Triangle " << t <<
": circumcenter not equidistant";
1330 EXPECT_EQ(
db, dc) <<
"Triangle " << t <<
": circumcenter not equidistant";
1346 for (
size_t e = 0; e <
r.edges.size(); ++e)
1348 const auto & edge =
r.edges(e);
1356 <<
"Edge " << e <<
" src not equidistant to sites";
1361 <<
"Edge " << e <<
" tgt not equidistant to sites";
1384 auto r = delaunay(
pts);
1389 for (
size_t i = 0; i <
r.triangles.size(); ++i)
1391 const auto & t =
r.triangles(i);
1397 "case_robust_near_collinear_delaunay",
scene,
1398 "Delaunay robustness / near-collinear");
1404 for (
size_t t = 0; t <
r.triangles.size(); ++t)
1406 const auto & tri =
r.triangles(t);
1410 for (
size_t s = 0; s <
r.sites.size(); ++s)
1412 if (s == tri.i
or s == tri.j
or s == tri.k)
1442 "case_robust_near_collinear_hull",
scene,
1443 "Convex hull robustness / near-collinear");
1487 for (
size_t i = 0; i <
segs.size(); ++i)
1489 for (
size_t i = 0; i < result.size(); ++i)
1490 scene.highlighted_points.append(result(i).point);
1492 "case_robust_near_parallel_converging",
scene,
1493 "Near-parallel segments / converging intersection");
1516 auto r = delaunay(
pts);
1520 for (
size_t t = 0; t <
r.triangles.size(); ++t)
1522 const auto & tri =
r.triangles(t);
1526 for (
size_t s = 0; s <
r.sites.size(); ++s)
1528 if (s == tri.i
or s == tri.j
or s == tri.k)
1548 auto r = delaunay(
pts);
1578 auto r = delaunay(
pts);
1583 for (
size_t i = 0; i <
r.triangles.size(); ++i)
1585 const auto & t =
r.triangles(i);
1591 "case_robust_cocircular_delaunay",
scene,
1592 "Delaunay robustness / cocircular points");
1629 auto r1 = delaunay(
pts1);
1630 auto r2 = delaunay(
pts2);
1631 auto r3 = delaunay(
pts3);
1636 EXPECT_EQ(
r1.triangles.size(), r2.triangles.size());
1647 for (
size_t i = 0; i <
ct1.size(); ++i)
1683 for (
size_t i = 0; i < v1.size(); ++i)
1706 EXPECT_EQ(
r1.distance_squared, r2.distance_squared);
1718 for (
int x = 0; x < 100; ++x)
1719 for (
int y = 0;
y < 100; ++
y)
1739 for (
int x = 0; x < 50; ++x)
1740 for (
int y = 0;
y < 100; ++
y)
1754 for (
int x = 0; x < 25; ++x)
1755 for (
int y = 0;
y < 20; ++
y)
1759 auto r = delaunay(
pts);
1764 const size_t check_limit =
r.triangles.size() < 50 ?
r.triangles.size() : 50;
1767 const auto & tri =
r.triangles(t);
1771 for (
size_t s = 0; s <
r.sites.size(); ++s)
1773 if (s == tri.i
or s == tri.j
or s == tri.k)
1788 for (
int x = 0; x <= 50; ++x)
1792 for (
int x = 50; x >= 0; --x)
1797 const size_t nv = p.
size();
1844 <<
"Andrew vs Graham vertex count mismatch";
1846 <<
"Andrew vs BruteForce vertex count mismatch";
1848 <<
"Andrew vs GiftWrapping vertex count mismatch";
1850 <<
"Andrew vs QuickHull vertex count mismatch";
1853 for (
size_t i = 0; i <
v_andrew.size(); ++i)
1856 <<
"Andrew vs Graham mismatch at index " << i;
1858 <<
"Andrew vs BruteForce mismatch at index " << i;
1860 <<
"Andrew vs GiftWrapping mismatch at index " << i;
1862 <<
"Andrew vs QuickHull mismatch at index " << i;
1871 for (
int x = 0; x <= 10; ++x)
1872 for (
int y = 0;
y <= 10; ++
y)
1903 for (
size_t i = 0; i <
v_andrew.size(); ++i)
1917 for (
int x = 0; x <= 20; ++x)
1982 for (
size_t i = 0; i < 3; ++i)
2007 auto r = delaunay(
pts);
2025 auto r = delaunay(
pts);
2029 for (
size_t t = 0; t <
r.triangles.size(); ++t)
2031 const auto & tri =
r.triangles(t);
2035 for (
size_t s = 0; s <
r.sites.size(); ++s)
2037 if (s == tri.i || s == tri.j || s == tri.k)
2040 <<
"Delaunay incremental: site " << s
2041 <<
" violates circumcircle of triangle " << t;
2088 auto r = delaunay(
pts);
2104 auto r = delaunay(
pts);
2113 for (
int x = 0; x <= 4; ++x)
2114 for (
int y = 0;
y <= 4; ++
y)
2118 auto r = delaunay(
pts);
2123 for (
size_t t = 0; t <
r.triangles.size(); ++t)
2125 const auto & tri =
r.triangles(t);
2129 for (
size_t s = 0; s <
r.sites.size(); ++s)
2131 if (s == tri.i || s == tri.j || s == tri.k)
2164 for (
size_t e = 0; e <
r.edges.size(); ++e)
2166 const auto & edge =
r.edges(e);
2167 if (edge.unbounded)
continue;
2171 EXPECT_EQ(
d_u,
d_v) <<
"Voronoi edge src not equidistant for edge " << e;
2194 for (
size_t i = 0; i < cells.size(); ++i)
2254 <<
"Collinear overlapping segments were not reported";
2263 const size_t N = 10;
2264 for (
size_t i = 0; i <
N; ++i)
2277 for (
size_t i = 0; i < result.size(); ++i)
2297 for (
size_t i = 0; i < result.size(); ++i)
2308 std::mt19937
rng(999);
2309 std::uniform_real_distribution<double> coord(-100.0, 100.0);
2310 std::uniform_real_distribution<double> delta(-5.0, 5.0);
2312 const size_t N = 10000;
2313 for (
size_t i = 0; i <
N; ++i)
2315 double x = coord(
rng),
y = coord(
rng);
2316 double dx = delta(
rng), dy = delta(
rng);
2317 if (dx == 0
and dy == 0) dx = 1;
2326 const size_t check = std::min(result.size(), (
size_t) 100);
2327 for (
size_t i = 0; i <
check; ++i)
2329 const auto &
ix = result(i);
2335 <<
"seg " <<
ix.seg_i <<
" and seg " <<
ix.seg_j
2336 <<
" reported as intersecting but don't";
size_t size_t int32_t * out
Andrew's monotonic chain convex hull algorithm.
Simple dynamic array with automatic resizing and functional operations.
T & append(const T &data)
Append a copy of data
Brute force convex hull algorithm.
Closest pair of points via divide and conquer.
Decompose a simple polygon into convex parts using Hertel-Mehlhorn.
Distance between two closed convex polygons using GJK.
Polygon triangulation using the ear-cutting algorithm.
Exact Delaunay triangulation using the Bowyer-Watson incremental algorithm.
static DynList< Triangle > as_triangles(const Result &result)
Convert indexed triangulation to geometric triangles.
O(n log n) expected-time Delaunay's triangulation.
bool has_curr() const noexcept
Return true if the iterator has current item.
Iterator on the items of list.
Doubly-linked list (defined in tpl_dynList.H).
T & append(const T &item)
static Array< Point > extract_vertices(const Polygon &poly)
Extract vertices from a polygon into an array for indexed access.
Gift wrapping (Jarvis march) convex hull algorithm.
Graham scan convex hull algorithm.
bool has_curr() const noexcept
Spatial point index for O(log n) nearest-neighbor queries.
static KDTreePointSearch build(const Array< Point > &points, const Geom_Number &xmin, const Geom_Number &ymin, const Geom_Number &xmax, const Geom_Number &ymax)
Build a balanced KD-tree from a point array.
Exact Minkowski sum of two closed convex polygons.
O(n log n) triangulation of simple polygons via y-monotone partition + linear-time monotone triangula...
static bool contains(const Polygon &poly, const Point &p)
Return true if the point is inside or on the boundary.
Represents a point with rectangular coordinates in a 2D plane.
const Geom_Number & get_x() const noexcept
Gets the x-coordinate value.
const Geom_Number & get_y() const noexcept
Gets the y-coordinate value.
Geom_Number distance_squared_to(const Point &that) const
Calculates the squared Euclidean distance to another point.
Iterator over the edges (segments) of a polygon.
bool has_curr() const
Check if there is a current segment.
A general (irregular) 2D polygon defined by a sequence of vertices.
void add_vertex(const Point &point)
Add a vertex to the polygon.
void close()
Close the polygon.
const bool & is_closed() const
Check if the polygon is closed.
const size_t & size() const
Get the number of vertices.
QuickHull convex hull algorithm.
Rotating calipers metrics for convex polygons.
Dedicated exact intersection for a single pair of segments.
Represents a line segment between two points.
Point project(const Point &p) const
Orthogonal projection of a point onto this segment's infinite line, clamped to the segment's endpoint...
Report all pairwise intersection points among a set of segments.
Fortune sweep-line Voronoi construction.
Array< ClippedCell > clipped_cells(const DynList< Point > &pts, const Polygon &clip) const
Compute Voronoi cells clipped to a bounding polygon.
Voronoi diagram derived as the dual of a Delaunay triangulation.
O(n log n) Voronoi diagram construction.
static Array< Point > sorted_hull_vertices(const Polygon &p)
static Point first_vertex_of(const Polygon &poly)
static Geom_Number brute_convex_distance_squared(const Polygon &p, const Polygon &q, Point &out_p, Point &out_q)
static Geom_Number dist2(const Point &a, const Point &b)
TEST_F(GeomAlgorithmsTest, ClosestPairEmptyInputThrows)
__gmp_expr< T, __gmp_unary_expr< __gmp_expr< T, U >, __gmp_cos_function > > cos(const __gmp_expr< T, U > &expr)
__gmp_expr< T, __gmp_unary_expr< __gmp_expr< T, U >, __gmp_sin_function > > sin(const __gmp_expr< T, U > &expr)
size_t blossom_maximum_cardinality_matching(const GT &g, DynDlist< typename GT::Arc * > &matching, SA sa=SA())
Alias of compute_maximum_cardinality_general_matching().
void add_polygon_vertices(SvgScene &scene, const ::Polygon &poly, const bool as_highlight=false)
std::filesystem::path emit_case_svg(const std::string &case_id, const SvgScene &scene, const std::string ¬e="")
Geom_Number area_of_parallelogram(const Point &a, const Point &b, const Point &c)
Compute the signed area of the parallelogram defined by vectors a->b and a->c.
size_t size(Node *root) noexcept
and
Check uniqueness with explicit hash + equality functors.
mpq_class Geom_Number
Numeric type used by the geometry module.
SegmentSegmentIntersection::Result segment_segment_intersection(const Segment &s1, const Segment &s2)
Convenience free-function wrapper for SegmentSegmentIntersection.
Itor::difference_type count(const Itor &beg, const Itor &end, const T &value)
Count elements equal to a value.
void quicksort_op(C< T > &a, const Compare &cmp=Compare(), const size_t threshold=Quicksort_Threshold)
Optimized quicksort for containers using operator().
Iterator over the vertices of a polygon.
::Array<::Segment > segments