38 #include <geogram/mesh/mesh.h> 40 #include <geogram/numerics/predicates.h> 53 bool is_almost_zero(
double value )
55 return value < global_epsilon && value > -global_epsilon;
58 bool point_inside_segment_exact(
59 const Geometry::Point3D& point,
const Geometry::Segment3D& segment )
62 point, { segment.direction(), segment.p0 } ) };
64 point, { segment.direction(), segment.p1 } ) };
65 return s1 ==
ZERO || s2 ==
ZERO || s1 != s2;
68 bool point_inside_segment_approx(
69 const Geometry::Point3D& point,
const Geometry::Segment3D& segment )
72 std::tie( distance, std::ignore ) =
74 if( distance > global_epsilon )
78 double half_length{ segment.length() / 2. };
79 vec3 segment_center{ segment.barycenter() };
80 double point_distance{ length( point - segment_center ) };
81 if( point_distance < half_length - global_epsilon )
85 if( point_distance > half_length + global_epsilon )
89 return point_inside_segment_exact( point, segment );
92 bool point_inside_triangle_exact(
93 const Geometry::Point2D& point,
const Geometry::Triangle2D& triangle )
96 point, { triangle.p0, triangle.p1 } ) };
98 point, { triangle.p1, triangle.p2 } ) };
100 point, { triangle.p2, triangle.p0 } ) };
127 return s1 == s2 && s2 == s3;
130 bool point_inside_triangle_approx(
131 const Geometry::Point2D& point,
const Geometry::Triangle2D& triangle )
134 point, triangle.p0, triangle.p1 ) };
135 if( is_almost_zero( area1 ) )
137 return point_inside_triangle_exact( point, triangle );
141 point, triangle.p1, triangle.p2 ) };
142 if( is_almost_zero( area2 ) )
144 return point_inside_triangle_exact( point, triangle );
148 point, triangle.p2, triangle.p0 ) };
149 if( is_almost_zero( area3 ) )
151 return point_inside_triangle_exact( point, triangle );
154 return s1 == s2 && s2 == s3;
160 return { cross( normal, normalize( e1 - e0 ) ), e0 };
163 bool point_inside_triangle_exact(
164 const Geometry::Point3D& point,
const Geometry::Triangle3D& triangle )
166 vec3 triangle_normal{ triangle.plane().
normal };
168 point, plane_from_triangle_normal_and_edge(
169 triangle_normal, triangle.p0, triangle.p1 ) ) };
171 point, plane_from_triangle_normal_and_edge(
172 triangle_normal, triangle.p1, triangle.p2 ) ) };
174 point, plane_from_triangle_normal_and_edge(
175 triangle_normal, triangle.p2, triangle.p0 ) ) };
202 return s1 == s2 && s2 == s3;
205 bool point_inside_triangle_approx(
206 const Geometry::Point3D& point,
const Geometry::Triangle3D& triangle )
209 vec3 translated_point{ point + triangle.plane().normal };
211 double vol1{ GEO::Geom::tetra_signed_volume(
212 point, translated_point, triangle.p0, triangle.p1 ) };
213 if( is_almost_zero( vol1 ) )
215 return point_inside_triangle_exact( point, triangle );
218 double vol2{ GEO::Geom::tetra_signed_volume(
219 point, translated_point, triangle.p1, triangle.p2 ) };
220 if( is_almost_zero( vol2 ) )
222 return point_inside_triangle_exact( point, triangle );
225 double vol3{ GEO::Geom::tetra_signed_volume(
226 point, translated_point, triangle.p2, triangle.p0 ) };
227 if( is_almost_zero( vol3 ) )
229 return point_inside_triangle_exact( point, triangle );
232 return s1 == s2 && s2 == s3;
235 bool point_inside_tetra_exact(
236 const vec3& p, std::array< vec3, 4 >& vertices )
238 std::array< Sign, 4 > signs;
239 for(
auto f :
range( 4 ) )
241 signs[f] =
sign( GEO::PCK::orient_3d( p.data(),
242 vertices[GEO::MeshCellDescriptors::tet_descriptor
245 vertices[GEO::MeshCellDescriptors::tet_descriptor
248 vertices[GEO::MeshCellDescriptors::tet_descriptor
252 return ( signs[0] >= 0 && signs[1] >= 0 && signs[2] >= 0
254 || ( signs[0] <= 0 && signs[1] <= 0 && signs[2] <= 0
258 bool point_inside_tetra_approx(
259 const vec3& p, std::array< vec3, 4 >& vertices )
261 std::array< Sign, 4 > signs;
262 for(
const index_t f :
range( 4 ) )
264 double volume{ GEO::Geom::tetra_signed_volume( p,
265 vertices[GEO::MeshCellDescriptors::tet_descriptor
266 .facet_vertex[f][0]],
267 vertices[GEO::MeshCellDescriptors::tet_descriptor
268 .facet_vertex[f][1]],
269 vertices[GEO::MeshCellDescriptors::tet_descriptor
270 .facet_vertex[f][2]] ) };
271 if( is_almost_zero( volume ) )
273 return point_inside_tetra_exact( p, vertices );
275 signs[f] =
sign( volume );
277 return ( signs[0] >= 0 && signs[1] >= 0 && signs[2] >= 0
279 || ( signs[0] <= 0 && signs[1] <= 0 && signs[2] <= 0
291 std::array< vec3, 4 > vertices{ { tetra.
p0, tetra.
p1, tetra.
p2,
293 return point_inside_tetra_approx( point, vertices );
296 template < index_t DIMENSION >
300 return point_inside_triangle_approx( point, triangle );
304 const Geometry::Point3D& point,
const Geometry::Segment3D& segment )
306 return point_inside_segment_approx( point, segment );
310 const Geometry::Point2D& point,
const Geometry::Segment2D& segment )
312 return sign( GEO::PCK::orient_2d( point, segment.p0, segment.p1 ) );
319 vec3 projected_point;
320 std::tie( distance, projected_point ) =
323 vec3 point_on_plane{ projected_point };
324 double translation{ std::max( 1.0, distance ) };
325 for(
auto d :
range( 3 ) )
327 if( std::fabs( plane.
normal[d] ) > global_epsilon )
329 index_t d1{ ( d + 1 ) % 3 };
330 index_t d2{ ( d + 2 ) % 3 };
331 point_on_plane[d1] += translation;
332 point_on_plane[d2] += translation;
336 + plane.
normal[d1] * point_on_plane[d1]
337 + plane.
normal[d2] * point_on_plane[d2] )
344 vec3 u{ normalize( point_on_plane ) };
347 vec3 p0{ projected_point + distance * u };
348 vec3 p1{ projected_point
349 + distance * ( std::cos( 2 * M_PI / 3 ) * u
350 - std::sin( 2 * M_PI / 3 ) * v ) };
351 vec3 p2{ projected_point
352 + distance * ( std::cos( 2 * M_PI / 3 ) * u
353 + std::sin( 2 * M_PI / 3 ) * v ) };
355 return sign( GEO::PCK::orient_3d(
356 point.data(), p0.data(), p1.data(), p2.data() ) );
double RINGMESH_API triangle_signed_area(const vec3 &p0, const vec3 &p1, const vec3 &p2, const vec3 &triangle_normal)
bool RINGMESH_API point_inside_segment(const Geometry::Point3D &point, const Geometry::Segment3D &segment)
Tests if a point is on a segment.
Sign RINGMESH_API point_side_to_segment(const Geometry::Point2D &point, const Geometry::Segment2D &segment)
std::tuple< double, vec3 > RINGMESH_API point_to_plane(const Geometry::Point3D &point, const Geometry::Plane &plane)
Sign RINGMESH_API point_side_to_plane(const Geometry::Point3D &point, const Geometry::Plane &plane)
double plane_constant() const
bool point_inside_triangle(const Geometry::Point< DIMENSION > &point, const Geometry::Triangle< DIMENSION > &triangle)
Tests if a point is inside a triangle.
#define ringmesh_assert(x)
Classes to build GeoModel from various inputs.
bool RINGMESH_API point_inside_tetra(const Geometry::Point3D &point, const Geometry::Tetra &tetra)
std::tuple< double, vecn< DIMENSION > > point_to_segment(const Geometry::Point< DIMENSION > &point, const Geometry::Segment< DIMENSION > &segment)