Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
55 commits
Select commit Hold shift + click to select a range
9226618
fix(Intersection): handle degenerated segments as points
BotellaA Oct 13, 2026
f0170a3
fix(Distance): skip degenerated edges in triangle_triangle_distance
BotellaA Oct 13, 2026
0cb2680
perf(Distance): test each triangle edge once in triangle_triangle_dis…
BotellaA Oct 13, 2026
7520d0f
fix(Distance): avoid out-of-bounds access on NaN in point_triangle_di…
BotellaA Oct 13, 2026
9954a5a
fix(Distance): handle flat triangles in 2D point_triangle_distance
BotellaA Oct 13, 2026
277d418
fix(Triangle): base is_degenerated on the minimum height
BotellaA Oct 13, 2026
11e0f3f
fix(Polygon): use the farthest vertex in minimum_height
BotellaA Oct 13, 2026
0b5c331
fix(NNSearch): handle empty point sets and zero neighbor requests
BotellaA Oct 13, 2026
31d436f
fix(SquareMatrix): implement 1x1 determinant and inverse
BotellaA Oct 13, 2026
eb10fd2
fix(Rotation): avoid infinite loop on huge angles in rotate
BotellaA Oct 13, 2026
e583f38
fix(Intersection): fix line_cylinder_intersection perpendicular case
BotellaA Oct 13, 2026
bb4e8c4
fix(Intersection): keep correctness in sync with filtered results
BotellaA Oct 13, 2026
dd78ca3
fix(Intersection): stable discriminant in line_sphere_intersection
BotellaA Oct 13, 2026
60154c7
fix(Circle): fix bounding_box for normals opposite to an axis
BotellaA Oct 13, 2026
e56031e
fix(BoundingBox): scale-independent triangle epsilon_intersects
BotellaA Oct 13, 2026
dfbb566
fix(BoundingBox): fix 1D ray and line intersections
BotellaA Oct 13, 2026
c49c47f
fix(Quality): scale-invariant degeneracy in tetrahedron qualities
BotellaA Oct 13, 2026
7693197
fix(IsPointInside): exact predicates and consistent boundary handling
BotellaA Oct 13, 2026
feb1afc
fix(Distance): compute point-line/segment distances by projection
BotellaA Oct 13, 2026
a47191e
fix(Point): combine coordinates hashes with absl::Hash
BotellaA Oct 13, 2026
e2f5223
fix(Predicates): statically initialize expansion constants
BotellaA Oct 13, 2026
f164ce5
fix(Predicates): disable FP contraction for exact predicates
BotellaA Oct 13, 2026
5fff17c
test(Geometry): add tier2-robustness benchmark
BotellaA Oct 13, 2026
956ec85
refactor(Distance): reuse Triangle::is_degenerated in 2D point_triang…
BotellaA Oct 14, 2026
c96cb56
fix(Intersection): report the closest cylinder point for degenerated …
BotellaA Oct 14, 2026
f87d684
fix(Intersection): length tolerances in line_cylinder_intersection
BotellaA Oct 14, 2026
157faa9
fix(Rotation): throw on non-finite angle in rotate
BotellaA Oct 14, 2026
dcad44c
perf(IsPointInside): run exact orientation only on edges spanning the…
BotellaA Oct 14, 2026
221eac0
test(Geometry): remove tier2-robustness benchmark
BotellaA Oct 14, 2026
5fa318e
fix(Tetrahedron): include opposite edges in is_degenerated
BotellaA Oct 14, 2026
eaeaaed
perf(Geometry): add zero-filter and missing filters to exact predicates
BotellaA Oct 14, 2026
667f3ed
fix(Geometry): exact predicates no longer depend on library initializ…
BotellaA Oct 14, 2026
6bc6f70
perf(Geometry): add Shewchuk adaptive stages to orient_2d and orient_3d
BotellaA Oct 14, 2026
f79047f
perf(Geometry): add Shewchuk stage D to orient_2d and orient_3d
BotellaA Oct 14, 2026
f3667b0
test(Geometry): exhaustive non-regression tests for exact predicates
BotellaA Oct 14, 2026
9e4d1ad
fix(Geometry): adaptive predicates return zero on a zero estimate
BotellaA Oct 14, 2026
085e6a2
fix(Geometry): export exact predicates for Windows test linking
BotellaA Oct 14, 2026
fd73a33
refactor(Geometry): move exact predicates out of internal
BotellaA Oct 14, 2026
8eb88c4
refactor(Geometry): move exact predicates to detail
BotellaA Oct 14, 2026
047c437
refactor(Distance): iterate edge vertex pairs with geode::Range
BotellaA Oct 14, 2026
6586706
refactor(IsPointInside): check collinearity inside is_point_on_edge
BotellaA Oct 14, 2026
712b5a9
test(Geometry): check is_degenerated against vertex order
BotellaA Oct 14, 2026
fe632c8
test(Geometry): express tolerances with GLOBAL_EPSILON
BotellaA Oct 14, 2026
9720b70
test(Intersection): split degenerated segment tests by object
BotellaA Oct 14, 2026
feb062d
Merge pull request #1352 from Geode-solutions/perf/predicates-zero-fi…
BotellaA Oct 14, 2026
4210ba5
Merge branch 'next' of https://github.com/Geode-solutions/OpenGeode i…
BotellaA Oct 14, 2026
d361d07
Replace internal predicates include with detail predicates
BotellaA Oct 14, 2026
b23aac1
Refactor double initialization in predicates.cpp
BotellaA Oct 14, 2026
7ba2fbc
Merge branch 'fix/geometry-robustness-tier1' into fix/geometry-robust…
BotellaA Oct 14, 2026
082b75e
Apply prepare changes
BotellaA Oct 14, 2026
2c94610
Add test_set_point function to test-triangle.cpp
BotellaA Oct 14, 2026
3782a94
Apply prepare changes
BotellaA Oct 14, 2026
f54694f
Add test for point skewed tetrahedron distance
BotellaA Oct 14, 2026
bbf3d60
Apply prepare changes
BotellaA Oct 14, 2026
4427dd8
fix
BotellaA Oct 14, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions include/geode/geometry/basic_objects/tetrahedron.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -43,12 +43,12 @@
namespace geode
{
template < typename PointType >
class GenericTetrahedron

Check warning on line 46 in include/geode/geometry/basic_objects/tetrahedron.hpp

View workflow job for this annotation

GitHub Actions / test / tidy

include/geode/geometry/basic_objects/tetrahedron.hpp:46:11 [cppcoreguidelines-special-member-functions]

class 'GenericTetrahedron' defines a copy constructor, a copy assignment operator, a move constructor and a move assignment operator but does not define a destructor
{
public:
static constexpr auto dim = 3;
static constexpr inline std::array< std::array< index_t, 3 >, 4 >

Check warning on line 50 in include/geode/geometry/basic_objects/tetrahedron.hpp

View workflow job for this annotation

GitHub Actions / test / tidy

include/geode/geometry/basic_objects/tetrahedron.hpp:50:26 [readability-redundant-inline-specifier]

variable 'tetrahedron_facet_vertex' has inline specifier but is implicitly inlined
tetrahedron_facet_vertex{ { { { 1, 3, 2 } }, { { 0, 2, 3 } },

Check warning on line 51 in include/geode/geometry/basic_objects/tetrahedron.hpp

View workflow job for this annotation

GitHub Actions / test / tidy

include/geode/geometry/basic_objects/tetrahedron.hpp:51:13 [readability-identifier-naming]

invalid case style for constexpr variable 'tetrahedron_facet_vertex'
{ { 3, 1, 0 } }, { { 0, 1, 2 } } } };

GenericTetrahedron( PointType point0,
Expand All @@ -66,6 +66,10 @@
void set_point( local_index_t vertex, PointType point );
[[nodiscard]] const std::array< PointType, 4 >& vertices() const;
[[nodiscard]] BoundingBox3D bounding_box() const;
/*!
* A tetrahedron is degenerated if all its vertices lie in a slab
* (thick plane) of thickness GLOBAL_EPSILON.
*/
[[nodiscard]] bool is_degenerated() const;
[[nodiscard]] std::string string() const;

Expand All @@ -73,7 +77,7 @@
std::array< PointType, 4 > vertices_;
};

class opengeode_geometry_api OwnerTetrahedron

Check warning on line 80 in include/geode/geometry/basic_objects/tetrahedron.hpp

View workflow job for this annotation

GitHub Actions / test / tidy

include/geode/geometry/basic_objects/tetrahedron.hpp:80:34 [cppcoreguidelines-special-member-functions]

class 'OwnerTetrahedron' defines a copy constructor, a copy assignment operator, a move constructor and a move assignment operator but does not define a destructor
: public GenericTetrahedron< Point3D >
{
using Base = GenericTetrahedron< Point3D >;
Expand All @@ -84,14 +88,14 @@
Point3D point2,
Point3D point3 ) noexcept;

OwnerTetrahedron( const Tetrahedron& other ) noexcept;

Check warning on line 91 in include/geode/geometry/basic_objects/tetrahedron.hpp

View workflow job for this annotation

GitHub Actions / test / tidy

include/geode/geometry/basic_objects/tetrahedron.hpp:91:9 [google-explicit-constructor]

single-argument constructors must be marked explicit to avoid unintentional implicit conversions
OwnerTetrahedron( const OwnerTetrahedron& other ) noexcept;
OwnerTetrahedron& operator=( const OwnerTetrahedron& other ) noexcept;
OwnerTetrahedron( OwnerTetrahedron&& other ) noexcept;
OwnerTetrahedron& operator=( OwnerTetrahedron&& other ) noexcept;
};

class opengeode_geometry_api Tetrahedron

Check warning on line 98 in include/geode/geometry/basic_objects/tetrahedron.hpp

View workflow job for this annotation

GitHub Actions / test / tidy

include/geode/geometry/basic_objects/tetrahedron.hpp:98:34 [cppcoreguidelines-special-member-functions]

class 'Tetrahedron' defines a copy constructor, a copy assignment operator, a move constructor and a move assignment operator but does not define a destructor
: public GenericTetrahedron< RefPoint3D >
{
using Base = GenericTetrahedron< RefPoint3D >;
Expand All @@ -103,7 +107,7 @@
const Point3D& point3 ) noexcept;

Tetrahedron( const Tetrahedron& other ) noexcept;
Tetrahedron( const OwnerTetrahedron& other ) noexcept;

Check warning on line 110 in include/geode/geometry/basic_objects/tetrahedron.hpp

View workflow job for this annotation

GitHub Actions / test / tidy

include/geode/geometry/basic_objects/tetrahedron.hpp:110:9 [google-explicit-constructor]

single-argument constructors must be marked explicit to avoid unintentional implicit conversions
Tetrahedron& operator=( const Tetrahedron& other ) noexcept;
Tetrahedron( Tetrahedron&& other ) noexcept;
Tetrahedron& operator=( Tetrahedron&& other ) noexcept;
Expand Down
5 changes: 5 additions & 0 deletions include/geode/geometry/basic_objects/triangle.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@
} // namespace internal

template < typename PointType, index_t dimension >
class GenericTriangle

Check warning on line 59 in include/geode/geometry/basic_objects/triangle.hpp

View workflow job for this annotation

GitHub Actions / test / tidy

include/geode/geometry/basic_objects/triangle.hpp:59:11 [cppcoreguidelines-special-member-functions]

class 'GenericTriangle' defines a copy constructor, a copy assignment operator, a move constructor and a move assignment operator but does not define a destructor
{
public:
static constexpr auto dim = dimension;
Expand Down Expand Up @@ -98,6 +98,11 @@
[[nodiscard]] local_index_t longest_edge_index() const;
[[nodiscard]] local_index_t smallest_edge_index() const;
[[nodiscard]] double minimum_height() const;
/*!
* A triangle is degenerated if all its vertices lie in a strip
* (thick line) of thickness GLOBAL_EPSILON, i.e. if its minimum
* height is below GLOBAL_EPSILON.
*/
[[nodiscard]] bool is_degenerated() const;
[[nodiscard]] std::string string() const;

Expand All @@ -108,7 +113,7 @@
};

template < index_t dimension >
class OwnerTriangle

Check warning on line 116 in include/geode/geometry/basic_objects/triangle.hpp

View workflow job for this annotation

GitHub Actions / test / tidy

include/geode/geometry/basic_objects/triangle.hpp:116:11 [cppcoreguidelines-special-member-functions]

class 'OwnerTriangle' defines a copy constructor, a copy assignment operator, a move constructor and a move assignment operator but does not define a destructor
: public GenericTriangle< Point< dimension >, dimension >
{
using Base = GenericTriangle< Point< dimension >, dimension >;
Expand All @@ -127,7 +132,7 @@
};
ALIAS_2D_AND_3D( OwnerTriangle );
template < index_t dimension >
class Triangle : public GenericTriangle< RefPoint< dimension >, dimension >

Check warning on line 135 in include/geode/geometry/basic_objects/triangle.hpp

View workflow job for this annotation

GitHub Actions / test / tidy

include/geode/geometry/basic_objects/triangle.hpp:135:11 [cppcoreguidelines-special-member-functions]

class 'Triangle' defines a copy constructor, a copy assignment operator, a move constructor and a move assignment operator but does not define a destructor
{
using Base = GenericTriangle< RefPoint< dimension >, dimension >;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -561,32 +561,32 @@ namespace GEO
{
namespace PCK
{
SIGN orient_2d( const geode::Point2D& p0,
opengeode_geometry_api SIGN orient_2d( const geode::Point2D& p0,
const geode::Point2D& p1,
const geode::Point2D& p2 );

SIGN orient_3d( const geode::Point3D& p0,
opengeode_geometry_api SIGN orient_3d( const geode::Point3D& p0,
const geode::Point3D& p1,
const geode::Point3D& p2,
const geode::Point3D& p3 );

SIGN det_3d( const geode::Vector3D& p0,
opengeode_geometry_api SIGN det_3d( const geode::Vector3D& p0,
const geode::Vector3D& p1,
const geode::Vector3D& p2 );

bool aligned_3d( const geode::Point3D& p0,
opengeode_geometry_api bool aligned_3d( const geode::Point3D& p0,
const geode::Point3D& p1,
const geode::Point3D& p2 );

SIGN dot_3d( const geode::Point3D& p0,
opengeode_geometry_api SIGN dot_3d( const geode::Point3D& p0,
const geode::Point3D& p1,
const geode::Point3D& p2 );

SIGN dot_2d( const geode::Point2D& p0,
opengeode_geometry_api SIGN dot_2d( const geode::Point2D& p0,
const geode::Point2D& p1,
const geode::Point2D& p2 );

void initialize();
opengeode_geometry_api void initialize();
} // namespace PCK
} // namespace GEO

Expand Down
14 changes: 14 additions & 0 deletions include/geode/geometry/distance.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ namespace geode
class Plane;
class Tetrahedron;
class Circle;
class Cylinder;
template < index_t dimension >
using Ball = Sphere< dimension >;
using Disk = Circle;
Expand Down Expand Up @@ -261,6 +262,19 @@ namespace geode
[[nodiscard]] std::tuple< double, Point3D > opengeode_geometry_api
point_disk_distance( const Point3D& point, const Disk& disk );

/*!
* Compute the smallest distance between a point and a cylinder surface,
* i.e. its wall and its two end disks
* @return a tuple containing:
* - the smallest distance.
* - the closest point on the cylinder surface.
* @details Result is always positive or null, even if the point is inside
* the cylinder.
*/
[[nodiscard]] std::tuple< double, Point3D >
opengeode_geometry_api point_cylinder_distance(
const Point3D& point, const Cylinder& cylinder );

/*!
* Compute the smallest distance between a point and an ellipse
* @return a tuple containing:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@

#pragma once

#include <geode/geometry/internal/predicates.hpp>
#include <geode/geometry/detail/predicates.hpp>

namespace geode
{
Expand Down
2 changes: 1 addition & 1 deletion include/geode/geometry/internal/position_from_sides.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@

#pragma once

#include <geode/geometry/internal/predicates.hpp>
#include <geode/geometry/detail/predicates.hpp>

namespace geode
{
Expand Down
3 changes: 2 additions & 1 deletion include/geode/geometry/is_point_inside.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,8 @@ namespace geode
{
/*!
* Find if point is inside a polygon.
* @param[in] point The point to rotate.
* Points on the polygon boundary are considered inside.
* @param[in] point The point to test.
*/
[[nodiscard]] bool opengeode_geometry_api is_point_inside_polygon(
const Point2D& point, const Polygon2D& polygon );
Expand Down
2 changes: 1 addition & 1 deletion include/geode/geometry/nn_search.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ namespace geode
/*!
* Get the closest neighbor from the given point
* @param[in] point The requested point
* @return the index of the closest point
* @return the index of the closest point, NO_ID if there is no point
*/
[[nodiscard]] index_t closest_neighbor(
const Point< dimension >& point ) const;
Expand Down
15 changes: 13 additions & 2 deletions src/geode/geometry/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ add_geode_library(
"perpendicular.cpp"
"points_sort.cpp"
"position.cpp"
"internal/predicates.cpp"
"detail/predicates.cpp"
"point.cpp"
"projection.cpp"
"quality.cpp"
Expand Down Expand Up @@ -105,11 +105,12 @@ add_geode_library(
ADVANCED_HEADERS
"detail/aabb_impl.hpp"
"detail/bitsery_archive.hpp"
"detail/predicates.hpp"
INTERNAL_HEADERS
"internal/intersection_from_sides.hpp"
"internal/position_from_sides.hpp"
"internal/predicates.hpp"
SKIP_UNITY
"internal/predicates.cpp"
"position.cpp"
PUBLIC_DEPENDENCIES
Bitsery::bitsery
Expand All @@ -120,3 +121,13 @@ add_geode_library(
earcut_hpp::earcut_hpp
nanoflann::nanoflann
)

# Exact predicates rely on exact floating-point rounding of each operation:
# forbid contraction of a*b+c into fused multiply-add instructions.
if(CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang")
set_source_files_properties(
"${PROJECT_SOURCE_DIR}/src/geode/geometry/internal/predicates.cpp"
PROPERTIES
COMPILE_OPTIONS "-ffp-contract=off"
)
endif()
6 changes: 1 addition & 5 deletions src/geode/geometry/basic_objects/circle.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -60,11 +60,7 @@ namespace geode
{
const auto sin_angle = [this]( Vector3D direction ) {
const auto dP = plane_.normal().dot( direction );
if( dP <= -1.0 )
{
return M_PI;
}
if( dP >= 1.0 )
if( std::fabs( dP ) >= 1.0 )
{
return 0.;
}
Expand Down
9 changes: 5 additions & 4 deletions src/geode/geometry/basic_objects/polygon.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -304,17 +304,18 @@ namespace geode
geode::Segment< dimension >{
vertices_[max_length_edge], vertices_[next] }
};
index_t opposite_vertex{ 0 };
double max_distance{ 0. };
for( const auto vertex : geode::Range{ nb_vertices } )
{
if( vertex == max_length_edge || vertex == next )
{
continue;
}
opposite_vertex = vertex;
const geode::Point< dimension >& point = vertices_[vertex];
max_distance = std::max(
max_distance, geode::point_line_distance( point, line ) );
}
const geode::Point< dimension >& point = vertices_[opposite_vertex];
return geode::point_line_distance( point, line );
return max_distance;
}

template < typename PointType, index_t dimension >
Expand Down
37 changes: 25 additions & 12 deletions src/geode/geometry/basic_objects/tetrahedron.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
#include <geode/geometry/basic_objects/triangle.hpp>
#include <geode/geometry/bounding_box.hpp>
#include <geode/geometry/distance.hpp>
#include <geode/geometry/vector.hpp>

namespace geode
{
Expand Down Expand Up @@ -85,18 +86,30 @@ namespace geode
template < typename PointType >
bool GenericTetrahedron< PointType >::is_degenerated() const
{
const Point3D& point0 = vertices_.at( 0 );
const Point3D& point1 = vertices_.at( 1 );
const Point3D& point2 = vertices_.at( 2 );
const Triangle3D triangle{ point0, point1, point2 };
if( triangle.is_degenerated() )
{
return true;
}
const Point3D& point3 = vertices_.at( 3 );
return std::get< 0 >(
point_plane_distance( point3, Plane{ triangle } ) )
<= GLOBAL_EPSILON;
// The tetrahedron is degenerated if all its vertices lie in a slab of
// thickness GLOBAL_EPSILON. The thinnest slab is either bounded by a
// facet plane (width = 6 * volume / facet double area) or by two
// parallel planes containing opposite edges (width = 6 * volume /
// |edge cross product|): the largest of these denominators gives the
// minimum width.
const Point3D& point0 = vertices_[0];
const Point3D& point1 = vertices_[1];
const Point3D& point2 = vertices_[2];
const Point3D& point3 = vertices_[3];
const Vector3D edge01{ point0, point1 };
const Vector3D edge02{ point0, point2 };
const Vector3D edge03{ point0, point3 };
const Vector3D edge12{ point1, point2 };
const Vector3D edge13{ point1, point3 };
const Vector3D edge23{ point2, point3 };
const auto six_volume = edge01.dot( edge02.cross( edge03 ) );
Comment thread
panquez marked this conversation as resolved.
const auto max_cross2 = std::max( { edge01.cross( edge02 ).length2(),
edge01.cross( edge03 ).length2(), edge02.cross( edge03 ).length2(),
edge12.cross( edge13 ).length2(), edge01.cross( edge23 ).length2(),
edge02.cross( edge13 ).length2(),
edge03.cross( edge12 ).length2() } );
return six_volume * six_volume
<= GLOBAL_EPSILON * GLOBAL_EPSILON * max_cross2;
}

template < typename PointType >
Expand Down
37 changes: 27 additions & 10 deletions src/geode/geometry/basic_objects/triangle.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@
#include <geode/geometry/basic_objects/segment.hpp>
#include <geode/geometry/bounding_box.hpp>
#include <geode/geometry/distance.hpp>
#include <geode/geometry/perpendicular.hpp>
#include <geode/geometry/vector.hpp>

namespace
{
Expand Down Expand Up @@ -73,6 +75,19 @@ namespace
}
return result;
}

double squared_double_area(
const geode::Vector2D& edge0, const geode::Vector2D& edge1 )
{
const auto double_area = geode::dot_perpendicular( edge0, edge1 );
return double_area * double_area;
}

double squared_double_area(
const geode::Vector3D& edge0, const geode::Vector3D& edge1 )
{
return edge0.cross( edge1 ).length2();
}
} // namespace

namespace geode
Expand Down Expand Up @@ -295,16 +310,18 @@ namespace geode
template < typename PointType, index_t dimension >
bool GenericTriangle< PointType, dimension >::is_degenerated() const
{
const Point< dimension >& point0 = vertices_.at( 0 );
const Point< dimension >& point1 = vertices_.at( 1 );
const Segment< dimension > edge{ point0, point1 };
if( edge.is_degenerated() )
{
return true;
}
const Point< dimension >& point2 = vertices_.at( 2 );
return point_line_distance( point2, InfiniteLine< dimension >{ edge } )
<= GLOBAL_EPSILON;
// The triangle is degenerated if its minimum height, i.e. twice its
// area divided by its longest edge length, is below GLOBAL_EPSILON.
const Point< dimension >& point0 = vertices_[0];
const Point< dimension >& point1 = vertices_[1];
const Point< dimension >& point2 = vertices_[2];
const Vector< dimension > edge01{ point0, point1 };
const Vector< dimension > edge02{ point0, point2 };
const Vector< dimension > edge12{ point1, point2 };
const auto max_length2 = std::max(
{ edge01.length2(), edge02.length2(), edge12.length2() } );
return squared_double_area( edge01, edge02 )

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same question than for tetrahedron. is it possible to have different response depending on which edges is given to squared_double_area. You need to check limit cases.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same answer as for the tetrahedron. |cross(e01, e02)| is the same for any pair of edges in exact arithmetic, and max_length2 is taken over all three edges. Rounding contributes about u·L² against a threshold of GLOBAL_EPSILON·L, so the result is the same whichever edges are used unless L ≳ 1e10.

test_degenerated_triangle_vertex_order (712b5a9) checks caps, obtuse triangles and needles with a minimum height of 0.5, 0.9, 1.1 and 2 × GLOBAL_EPSILON. They sit in a rotated frame offset by up to 1e6, and all 6 vertex permutations must give the expected answer.

<= GLOBAL_EPSILON * GLOBAL_EPSILON * max_length2;
}

template < typename PointType, index_t dimension >
Expand Down
Loading
Loading