297 "case_andrew_collinear_endpoints",
scene,
298 "Andrew monotonic chain / collinear input");
351 "case_graham_collinear_endpoints",
scene,
352 "Graham scan / collinear input");
411 scene.highlighted_points.append(
res.first);
412 scene.highlighted_points.append(
res.second);
414 "case_closest_pair_duplicate_zero",
scene,
415 "Closest pair / duplicate points");
561 PointInPolygonWinding::Location::Inside);
563 PointInPolygonWinding::Location::Boundary);
565 PointInPolygonWinding::Location::Outside);
585 PointInPolygonWinding::Location::Inside);
587 PointInPolygonWinding::Location::Outside);
589 PointInPolygonWinding::Location::Boundary);
708 "case_convex_polygon_intersection_touching_edge",
scene,
709 "Convex intersection / touching edge");
829 for (
size_t i = 0; i <
hs2.size(); ++i)
853 for (
size_t i = 0; i <
hs.size(); ++i)
857 "case_halfplane_inconsistent_empty",
scene,
858 "Half-plane intersection / inconsistent constraints");
885 const auto & t =
r.triangles(0);
899 for (
size_t i = 0; i <
r.triangles.size(); ++i)
901 const auto & t =
r.triangles(i);
906 Orientation::COLLINEAR);
945 for (
size_t i = 0; i <
r1.sites.size(); ++i)
947 for (
size_t i = 0; i <
r1.triangles.size(); ++i)
949 const auto & t =
r1.triangles(i);
955 "case_delaunay_cocircular_deterministic",
scene,
956 "Delaunay cocircular tie-break");
959 ASSERT_EQ(
r1.triangles.size(), r2.triangles.size());
961 for (
size_t i = 0; i <
r1.sites.size(); ++i)
967 for (
size_t i = 0; i <
t1.size(); ++i)
986 size_t unbounded = 0;
987 for (
size_t i = 0; i <
r.edges.size(); ++i)
988 if (
r.edges(i).unbounded)
995 for (
size_t i = 0; i <
r.cells.size(); ++i)
1013 size_t unbounded = 0;
1014 for (
size_t i = 0; i <
r.edges.size(); ++i)
1015 if (
r.edges(i).unbounded)
1023 for (
size_t i = 0; i <
r.cells.size(); ++i)
1039 for (
size_t e = 0; e <
r.edges.size(); ++e)
1041 const auto & edge =
r.edges(e);
1049 for (
size_t t = 0; t <
dt.triangles.size(); ++t)
1051 const auto & tri =
dt.triangles(t);
1052 const bool has_u = tri.i == edge.site_u
or tri.j == edge.site_u
or
1053 tri.k == edge.site_u;
1054 const bool has_v = tri.i == edge.site_v
or tri.j == edge.site_v
or
1055 tri.k == edge.site_v;
1065 Orientation::COLLINEAR);
1067 Orientation::COLLINEAR);
1095 for (
size_t i = 0; i < cells.
size(); ++i)
1121 for (
size_t i = 0; i < cells.
size(); ++i)
1166 for (
size_t i = 0; i < cells.
size(); ++i)
1209 for (
int i = 0; i <
N; ++i)
1210 for (
int j = 0; j < 3; ++j)
1211 points.
append(
Point(i * 7 + j * 3, j * 11 + i * 5));
1214 auto r = delaunay(points);
1220 for (
size_t t = 0; t <
r.triangles.size(); ++t)
1222 const auto & tri =
r.triangles(t);
1226 for (
size_t s = 0; s <
r.sites.size(); ++s)
1228 if (s == tri.i
or s == tri.j
or s == tri.k)
1242 for (
int x = 0; x < 10; ++x)
1243 for (
int y = 0;
y < 10; ++
y)
1247 auto r = delaunay(points);
1254 for (
size_t t = 0; t <
r.triangles.size(); ++t)
1256 const auto & tri =
r.triangles(t);
1258 Orientation::COLLINEAR);
1279 for (
size_t s = 0; s <
r.cells.size(); ++s)
1283 for (
size_t t = 0; t <
dt.triangles.size(); ++t)
1285 const auto & tri =
dt.triangles(t);
1286 if (tri.i == s
or tri.j == s
or tri.k == s)
1295 <<
"Mismatch for site " << s;
1297 for (
size_t v = 0; v <
cell_verts.size(); ++v)
1300 for (
size_t e = 0; e <
expected.size(); ++e)
1306 EXPECT_TRUE(found) <<
"Cell " << s <<
" has unexpected vertex";
1316 for (
int i = 0; i < 8; ++i)
1317 for (
int j = 0; j < 8; ++j)
1318 points.
append(
Point(i * 3 + (j % 2), j * 3 + (i % 2)));
1321 auto dt = delaunay(points);
1329 for (
size_t s = 0; s <
r.cells.size(); ++s)
1331 if (
r.cells(s).bounded)
1485 auto r = delaunay(empty);
1495 auto r = delaunay({
Point(5, 5)});
1603 for (
auto it = triangles.get_it(); it.has_curr(); it.next_ne())
1613 const size_t N = 200;
1615 for (
size_t i = 0; i <
N; ++i)
1633 for (
auto it = triangles.get_it(); it.has_curr(); it.next_ne())
1643 <<
"Triangulation area (" <<
total_area.get_d()
1654 for (
size_t i = 0; i <
spikes; ++i)
1670 const size_t n = 2 *
spikes;
1678 for (
auto it = triangles.get_it(); it.has_curr(); it.next_ne())
1693 const size_t N = 100;
1695 for (
size_t i = 0; i <
N; ++i)
1734 {0, 0}, {100, 0}, {200, 0}, {50, 100}, {150, 100}
1737 std::mt19937
rng(42);
1738 std::uniform_real_distribution<double>
offset(-5.0, 5.0);
1740 for (
size_t c = 0; c < 5; ++c)
1741 for (
size_t i = 0; i < 2000; ++i)
1765 std::mt19937
rng(123);
1766 std::uniform_real_distribution<double> dist(-1000.0, 1000.0);
1768 for (
size_t i = 0; i < 100000; ++i)
1792 for (
size_t i = 0; i <
N; ++i)
1807 for (
size_t t = 0; t <
r.triangles.size(); ++t)
1809 const auto & tri =
r.triangles(t);
1811 Orientation::COLLINEAR);
1833 for (
size_t t = 0; t <
r.triangles.size(); ++t)
1835 const auto & tri =
r.triangles(t);
1836 const Point & a =
r.sites(tri.i);
1837 const Point & b =
r.sites(tri.j);
1838 const Point & c =
r.sites(tri.k);
1840 if (
orientation(a, b, c) == Orientation::COLLINEAR)
1846 for (
size_t s = 0; s <
r.sites.size(); ++s)
1848 if (s == tri.i
or s == tri.j
or s == tri.k)
1853 <<
"Site " << s <<
" is strictly inside circumcircle of triangle " << t;
1864 std::mt19937
rng(77);
1865 std::uniform_real_distribution<double> dist(-500.0, 500.0);
1867 const size_t N = 2000;
1868 for (
size_t i = 0; i <
N; ++i)
1879 for (
size_t t = 0; t <
r.triangles.size(); ++t)
1881 const auto & tri =
r.triangles(t);
1882 const Point & a =
r.sites(tri.i);
1883 const Point & b =
r.sites(tri.j);
1884 const Point & c =
r.sites(tri.k);
1886 if (
orientation(a, b, c) == Orientation::COLLINEAR)
1892 for (
size_t s = 0; s <
r.sites.size(); ++s)
1894 if (s == tri.i
or s == tri.j
or s == tri.k)
1903 <<
violations <<
" Delaunay circumcircle violations found";
Andrew's monotonic chain convex hull algorithm.
Simple dynamic array with automatic resizing and functional operations.
constexpr size_t size() const noexcept
Return the number of elements stored in the stack.
T & append(const T &data)
Append a copy of data
void reserve(size_t cap)
Reserves cap cells into the array.
Brute force convex hull algorithm.
Closest pair of points via divide and conquer.
Basic exact intersection for closed convex polygons.
Polygon triangulation using the ear-cutting algorithm.
Exact Delaunay triangulation using the Bowyer-Watson incremental algorithm.
Iterator on the items of list.
Dynamic singly linked list with functional programming support.
T & append(const T &item)
Gift wrapping (Jarvis march) convex hull algorithm.
Graham scan convex hull algorithm.
bool has_curr() const noexcept
Exact bounded intersection of half-planes.
static Array< HalfPlane > from_convex_polygon(const Polygon &poly)
Build half-planes from the edges of a closed convex polygon.
Exact point-in-polygon classification via winding number.
Represents a point with rectangular coordinates in a 2D plane.
A general (irregular) 2D polygon defined by a sequence of vertices.
void append(const Point &point)
Append a vertex (Aleph container protocol).
void add_vertex(const Point &point)
Add a vertex to the polygon.
void close()
Close the polygon.
QuickHull convex hull algorithm.
Rotating calipers metrics for convex polygons.
static DiameterResult diameter(const Polygon &poly)
Compute convex polygon diameter (farthest vertex pair).
static WidthResult minimum_width(const Polygon &poly)
Compute the minimum width of a closed convex polygon.
Represents a line segment between two points.
const Point & get_tgt_point() const noexcept
Gets the target point of the segment.
const Point & get_src_point() const noexcept
Gets the source point of the segment.
Voronoi diagram derived as the dual of a Delaunay triangulation.
TEST_F(GeomAlgorithmsTest, TriangulateTriangle)
double triangle_area(const Triangle &t)
Calculate area of a triangle using cross product.
__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)
const long double offset[]
Offset values indexed by symbol string length (bounded by MAX_OFFSET_INDEX)
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="")
and
Check uniqueness with explicit hash + equality functors.
size_t size(Node *root) noexcept
Divide_Conquer_DP_Result< Cost > divide_and_conquer_partition_dp(const size_t groups, const size_t n, Transition_Cost_Fn transition_cost, const Cost inf=dp_optimization_detail::default_inf< Cost >())
Optimize partition DP using divide-and-conquer optimization.
Orientation orientation(const Point &a, const Point &b, const Point &c)
Return the orientation of the triple (a, b, c).
mpq_class Geom_Number
Numeric type used by the geometry module.
static Geom_Number polygon_area(const Polygon &poly)
static Geom_Number poly_area(const Polygon &p)
::Array<::Polygon > polygons
::Array<::Segment > segments