mirror of https://github.com/CGAL/cgal
Fix conflicts
This commit is contained in:
commit
81a08465d3
|
|
@ -1206,5 +1206,3 @@ gmon.*
|
|||
/Stream_support/test/Stream_support/cgal_test_with_cmake
|
||||
/*.html
|
||||
/Snap_rounding_2/test/Snap_rounding_2/data/out
|
||||
/Operations_on_polyhedra/examples/Operations_on_polyhedra/cgal_test_with_cmake
|
||||
/Operations_on_polyhedra/test/Operations_on_polyhedra/cgal_test_with_cmake
|
||||
|
|
|
|||
45
.travis.yml
45
.travis.yml
|
|
@ -29,28 +29,27 @@ env:
|
|||
- PACKAGE='Mesher_level Minkowski_sum_2 Minkowski_sum_3 '
|
||||
- PACKAGE='Modifier Modular_arithmetic Nef_2 '
|
||||
- PACKAGE='Nef_3 Nef_S2 NewKernel_d '
|
||||
- PACKAGE='Number_types OpenNL Operations_on_polyhedra '
|
||||
- PACKAGE='Optimal_transportation_reconstruction_2 Optimisation_basic Partition_2 '
|
||||
- PACKAGE='Periodic_2_triangulation_2 Periodic_3_mesh_3 Periodic_3_triangulation_3 '
|
||||
- PACKAGE='Point_set_2 Point_set_3 Point_set_processing_3 '
|
||||
- PACKAGE='Point_set_shape_detection_3 Poisson_surface_reconstruction_3 Polygon '
|
||||
- PACKAGE='Polygon_mesh_processing Polyhedron Polyhedron_IO '
|
||||
- PACKAGE='Polyline_simplification_2 Polynomial Polytope_distance_d '
|
||||
- PACKAGE='Principal_component_analysis Principal_component_analysis_LGPL Profiling_tools '
|
||||
- PACKAGE='Property_map QP_solver Random_numbers '
|
||||
- PACKAGE='Ridges_3 Scale_space_reconstruction_3 Scripts '
|
||||
- PACKAGE='SearchStructures Segment_Delaunay_graph_2 Segment_Delaunay_graph_Linf_2 '
|
||||
- PACKAGE='Set_movable_separability_2 Skin_surface_3 Snap_rounding_2 '
|
||||
- PACKAGE='Solver_interface Spatial_searching Spatial_sorting '
|
||||
- PACKAGE='STL_Extension Straight_skeleton_2 Stream_lines_2 '
|
||||
- PACKAGE='Stream_support Subdivision_method_3 Surface_mesh '
|
||||
- PACKAGE='Surface_mesh_deformation Surface_mesher Surface_mesh_parameterization '
|
||||
- PACKAGE='Surface_mesh_segmentation Surface_mesh_shortest_path Surface_mesh_simplification '
|
||||
- PACKAGE='Surface_mesh_skeletonization Surface_sweep_2 TDS_2 '
|
||||
- PACKAGE='TDS_3 Testsuite Three '
|
||||
- PACKAGE='Triangulation Triangulation_2 Triangulation_3 '
|
||||
- PACKAGE='Union_find Visibility_2 Voronoi_diagram_2 '
|
||||
- PACKAGE='wininst '
|
||||
- PACKAGE='Number_types OpenNL Optimal_transportation_reconstruction_2 '
|
||||
- PACKAGE='Optimisation_basic Partition_2 Periodic_2_triangulation_2 '
|
||||
- PACKAGE='Periodic_3_mesh_3 Periodic_3_triangulation_3 Point_set_2 '
|
||||
- PACKAGE='Point_set_3 Point_set_processing_3 Point_set_shape_detection_3 '
|
||||
- PACKAGE='Poisson_surface_reconstruction_3 Polygon Polygon_mesh_processing '
|
||||
- PACKAGE='Polyhedron Polyhedron_IO Polyline_simplification_2 '
|
||||
- PACKAGE='Polynomial Polytope_distance_d Principal_component_analysis '
|
||||
- PACKAGE='Principal_component_analysis_LGPL Profiling_tools Property_map '
|
||||
- PACKAGE='QP_solver Random_numbers Ridges_3 '
|
||||
- PACKAGE='Scale_space_reconstruction_3 Scripts SearchStructures '
|
||||
- PACKAGE='Segment_Delaunay_graph_2 Segment_Delaunay_graph_Linf_2 Set_movable_separability_2 '
|
||||
- PACKAGE='Skin_surface_3 Snap_rounding_2 Solver_interface '
|
||||
- PACKAGE='Spatial_searching Spatial_sorting STL_Extension '
|
||||
- PACKAGE='Straight_skeleton_2 Stream_lines_2 Stream_support '
|
||||
- PACKAGE='Subdivision_method_3 Surface_mesh Surface_mesh_deformation '
|
||||
- PACKAGE='Surface_mesher Surface_mesh_parameterization Surface_mesh_segmentation '
|
||||
- PACKAGE='Surface_mesh_shortest_path Surface_mesh_simplification Surface_mesh_skeletonization '
|
||||
- PACKAGE='Surface_sweep_2 TDS_2 TDS_3 '
|
||||
- PACKAGE='Testsuite Three Triangulation '
|
||||
- PACKAGE='Triangulation_2 Triangulation_3 Union_find '
|
||||
- PACKAGE='Visibility_2 Voronoi_diagram_2 wininst '
|
||||
compiler: clang-3.6
|
||||
install:
|
||||
- echo "$PWD"
|
||||
|
|
@ -63,7 +62,7 @@ before_script:
|
|||
- sudo chmod +x /usr/bin/doxygen
|
||||
- mkdir -p build
|
||||
- cd build
|
||||
- cmake -DCMAKE_CXX_FLAGS="-std=c++11" -DCGAL_HEADER_ONLY=ON -DQt5_DIR="/opt/qt55/lib/cmake/Qt5" -DQt5Svg_DIR="/opt/qt55/lib/cmake/Qt5Svg" -DQt5OpenGL_DIR="/opt/qt55/lib/cmake/Qt5OpenGL" -DCMAKE_CXX_FLAGS_RELEASE=-DCGAL_NDEBUG ..
|
||||
- cmake -DCMAKE_CXX_FLAGS="-std=c++11" -DCGAL_HEADER_ONLY=ON -DQt5_DIR="/opt/qt55/lib/cmake/Qt5" -DQt5Svg_DIR="/opt/qt55/lib/cmake/Qt5Svg" -DQt5OpenGL_DIR="/opt/qt55/lib/cmake/Qt5OpenGL" -DCMAKE_CXX_FLAGS_RELEASE=-DCGAL_NDEBUG -DWITH_examples=ON -DWITH_demos=ON -DWITH_tests=ON ..
|
||||
- make
|
||||
- sudo make install &>/dev/null
|
||||
- cd ..
|
||||
|
|
|
|||
|
|
@ -69,7 +69,6 @@ Nef_S2
|
|||
NewKernel_d
|
||||
Number_types
|
||||
OpenNL
|
||||
Operations_on_polyhedra
|
||||
Optimal_transportation_reconstruction_2
|
||||
Optimisation_basic
|
||||
Partition_2
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ before_script:
|
|||
- sudo chmod +x /usr/bin/doxygen
|
||||
- mkdir -p build
|
||||
- cd build
|
||||
- cmake -DCMAKE_CXX_FLAGS="-std=c++11" -DCGAL_HEADER_ONLY=ON -DQt5_DIR="/opt/qt55/lib/cmake/Qt5" -DQt5Svg_DIR="/opt/qt55/lib/cmake/Qt5Svg" -DQt5OpenGL_DIR="/opt/qt55/lib/cmake/Qt5OpenGL" -DCMAKE_CXX_FLAGS_RELEASE=-DCGAL_NDEBUG ..
|
||||
- cmake -DCMAKE_CXX_FLAGS="-std=c++11" -DCGAL_HEADER_ONLY=ON -DQt5_DIR="/opt/qt55/lib/cmake/Qt5" -DQt5Svg_DIR="/opt/qt55/lib/cmake/Qt5Svg" -DQt5OpenGL_DIR="/opt/qt55/lib/cmake/Qt5OpenGL" -DCMAKE_CXX_FLAGS_RELEASE=-DCGAL_NDEBUG -DWITH_examples=ON -DWITH_demos=ON -DWITH_tests=ON ..
|
||||
- make
|
||||
- sudo make install &>/dev/null
|
||||
- cd ..
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
|
@ -38,16 +38,16 @@ num_edges(const EdgeListGraph& g);
|
|||
|
||||
|
||||
/*! \relates EdgeListGraph
|
||||
returns the source vertex of `h`.
|
||||
returns the source vertex of `e`.
|
||||
*/
|
||||
template <typename EdgeListGraph>
|
||||
boost::graph_traits<EdgeListGraph>::vertex_descriptor
|
||||
source(boost::graph_traits<EdgeListGraph>::halfedge_descriptor h, const EdgeListGraph& g);
|
||||
source(boost::graph_traits<EdgeListGraph>::edge_descriptor e, const EdgeListGraph& g);
|
||||
|
||||
|
||||
/*! \relates EdgeListGraph
|
||||
returns the target vertex of `h`.
|
||||
returns the target vertex of `e`.
|
||||
*/
|
||||
template <typename EdgeListGraph>
|
||||
boost::graph_traits<EdgeListGraph>::vertex_descriptor
|
||||
target(boost::graph_traits<EdgeListGraph>::halfedge_descriptor h, const EdgeListGraph& g);
|
||||
target(boost::graph_traits<EdgeListGraph>::edge_descriptor e, const EdgeListGraph& g);
|
||||
|
|
|
|||
|
|
@ -122,12 +122,12 @@ and adds the requirement for traversal of all edges in a graph.
|
|||
<td>An upper bound of the number of edges of the graph</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>`source(g)`</td>
|
||||
<td>`source(e, g)`</td>
|
||||
<td>`vertex_descriptor`</td>
|
||||
<td>The source vertex of `e`</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>`target(g)`</td>
|
||||
<td>`target(e, g)`</td>
|
||||
<td>`vertex_descriptor`</td>
|
||||
<td>The target vertex of `e`</td>
|
||||
</tr>
|
||||
|
|
|
|||
|
|
@ -973,33 +973,6 @@ make_tetrahedron(const P& p0, const P& p1, const P& p2, const P& p3, Graph& g)
|
|||
return opposite(h2,g);
|
||||
}
|
||||
|
||||
/// \cond SKIP_IN_DOC
|
||||
template <class Traits, class TriangleMesh, class VertexPointMap>
|
||||
bool is_degenerate_triangle_face(
|
||||
typename boost::graph_traits<TriangleMesh>::halfedge_descriptor hd,
|
||||
TriangleMesh& tmesh,
|
||||
const VertexPointMap& vpmap,
|
||||
const Traits& traits)
|
||||
{
|
||||
CGAL_assertion(!is_border(hd, tmesh));
|
||||
|
||||
const typename Traits::Point_3& p1 = get(vpmap, target( hd, tmesh) );
|
||||
const typename Traits::Point_3& p2 = get(vpmap, target(next(hd, tmesh), tmesh) );
|
||||
const typename Traits::Point_3& p3 = get(vpmap, source( hd, tmesh) );
|
||||
return traits.collinear_3_object()(p1, p2, p3);
|
||||
}
|
||||
|
||||
template <class Traits, class TriangleMesh, class VertexPointMap>
|
||||
bool is_degenerate_triangle_face(
|
||||
typename boost::graph_traits<TriangleMesh>::face_descriptor fd,
|
||||
TriangleMesh& tmesh,
|
||||
const VertexPointMap& vpmap,
|
||||
const Traits& traits)
|
||||
{
|
||||
return is_degenerate_triangle_face(halfedge(fd,tmesh), tmesh, vpmap, traits);
|
||||
}
|
||||
/// \endcond
|
||||
|
||||
/**
|
||||
* \ingroup PkgBGLHelperFct
|
||||
* \brief Creates a triangulated regular prism, outward oriented,
|
||||
|
|
|
|||
|
|
@ -78,6 +78,7 @@ CGAL_add_named_parameter(projection_functor_t, projection_functor, projection_fu
|
|||
CGAL_add_named_parameter(throw_on_self_intersection_t, throw_on_self_intersection, throw_on_self_intersection)
|
||||
CGAL_add_named_parameter(clip_volume_t, clip_volume, clip_volume)
|
||||
CGAL_add_named_parameter(use_compact_clipper_t, use_compact_clipper, use_compact_clipper)
|
||||
CGAL_add_named_parameter(output_iterator_t, output_iterator, output_iterator)
|
||||
|
||||
// List of named parameters that we use in the package 'Surface Mesh Simplification'
|
||||
CGAL_add_named_parameter(get_cost_policy_t, get_cost_policy, get_cost)
|
||||
|
|
|
|||
|
|
@ -101,6 +101,7 @@ void test(const NamedParameters& np)
|
|||
assert(get_param(np, CGAL::internal_np::verbosity_level).v == 41);
|
||||
assert(get_param(np, CGAL::internal_np::projection_functor).v == 42);
|
||||
assert(get_param(np, CGAL::internal_np::apply_per_connected_component).v == 46);
|
||||
assert(get_param(np, CGAL::internal_np::output_iterator).v == 47);
|
||||
|
||||
|
||||
// Test types
|
||||
|
|
@ -177,6 +178,7 @@ void test(const NamedParameters& np)
|
|||
check_same_type<41>(get_param(np, CGAL::internal_np::verbosity_level));
|
||||
check_same_type<42>(get_param(np, CGAL::internal_np::projection_functor));
|
||||
check_same_type<46>(get_param(np, CGAL::internal_np::apply_per_connected_component));
|
||||
check_same_type<47>(get_param(np, CGAL::internal_np::output_iterator));
|
||||
}
|
||||
|
||||
int main()
|
||||
|
|
@ -238,6 +240,7 @@ int main()
|
|||
.clip_volume(A<44>(44))
|
||||
.use_compact_clipper(A<45>(45))
|
||||
.apply_per_connected_component(A<46>(46))
|
||||
.output_iterator(A<47>(47))
|
||||
);
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ configure()
|
|||
{
|
||||
echo "Configuring... "
|
||||
|
||||
if eval 'cmake --no-warn-unused-cli "$CMAKE_GENERATOR" -DRUNNING_CGAL_AUTO_TEST=TRUE \
|
||||
if eval 'cmake --no-warn-unused-cli ${INIT_FILE:+"-C$INIT_FILE"} "$CMAKE_GENERATOR" -DRUNNING_CGAL_AUTO_TEST=TRUE \
|
||||
-DCGAL_DIR="$CGAL_DIR" \
|
||||
.' ; then
|
||||
|
||||
|
|
|
|||
|
|
@ -73,7 +73,7 @@ The following example shows how to use a functor of the kernel.
|
|||
|
||||
The first pieces of prototype code were comparisons of algebraic
|
||||
numbers of degree 2, written by Olivier Devillers
|
||||
\cgalCite{cgal:dfmt-amafe-00},cgal:dfmt-amafe-02.
|
||||
\cgalCite{cgal:dfmt-amafe-00},\cgalCite{cgal:dfmt-amafe-02}.
|
||||
|
||||
Some work was then done in the direction of a "kernel" for
|
||||
\cgal.\cgalFootnote{Monique Teillaud, First Prototype of a \cgal Geometric Kernel with Circular Arcs, Technical Report ECG-TR-182203-01, 2002
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@ functions that return instances of these types:
|
|||
<LI>`Traits::Less_xy_2`,
|
||||
<LI>`Traits::Less_yx_2`,
|
||||
<LI>`Traits::Left_turn_2`,
|
||||
<LI>`Traits::Orientation_2`,
|
||||
<LI>`Traits::Equal_2`.
|
||||
</UL>
|
||||
</OL>
|
||||
|
|
|
|||
|
|
@ -31,7 +31,8 @@ functions that return instances of these types:
|
|||
<LI>`Traits::Equal_2`,
|
||||
<LI>`Traits::Less_xy_2`,
|
||||
<LI>`Traits::Less_yx_2`,
|
||||
<LI>`Traits::Left_turn_2`.
|
||||
<LI>`Traits::Left_turn_2`,
|
||||
<LI>`Traits::Orientation_2`.
|
||||
</UL>
|
||||
</OL>
|
||||
|
||||
|
|
|
|||
|
|
@ -147,15 +147,8 @@ public:
|
|||
const Point_3& hp = h.p();
|
||||
const Point_3& hq = h.q();
|
||||
const Point_3& hr = h.r();
|
||||
//typename OldK::Less_signed_distance_to_plane_3
|
||||
// less_signed_distance_to_plane_3;
|
||||
// return less_signed_distance_to_plane_3(hp, hq, hr, p, q);
|
||||
return has_smaller_signed_dist_to_planeC3(hp.x(), hp.y(), hp.z(),
|
||||
hq.x(), hq.y(), hq.z(),
|
||||
hr.x(), hr.y(), hr.z(),
|
||||
p.x(), p.y(), p.z(),
|
||||
q.x(), q.y(), q.z());
|
||||
|
||||
typename K::Less_signed_distance_to_plane_3 less_signed_distance_to_plane_3;
|
||||
return less_signed_distance_to_plane_3(hp, hq, hr, p, q);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -164,35 +157,10 @@ struct GT3_for_CH3 {
|
|||
typedef typename GT::Point_3 Point_2;
|
||||
};
|
||||
|
||||
template <class R_, class Has_filtered_predicates_tag /* = Tag_false */>
|
||||
struct Convex_hull_traits_base_3 {
|
||||
typedef Point_triple_has_on_positive_side_3<R_> Has_on_positive_side_3;
|
||||
|
||||
typedef Point_triple_less_signed_distance_to_plane_3<R_>
|
||||
Less_signed_distance_to_plane_3;
|
||||
};
|
||||
|
||||
template <class R_>
|
||||
struct Convex_hull_traits_base_3<R_, Tag_true>{
|
||||
typedef Filtered_predicate<
|
||||
Point_triple_has_on_positive_side_3< typename R_::Exact_kernel_rt >,
|
||||
Point_triple_has_on_positive_side_3< typename R_::Approximate_kernel >,
|
||||
Point_triple_converter<R_,typename R_::Exact_kernel_rt>,
|
||||
Point_triple_converter<R_,typename R_::Approximate_kernel>
|
||||
> Has_on_positive_side_3;
|
||||
|
||||
typedef Filtered_predicate<
|
||||
Point_triple_less_signed_distance_to_plane_3< typename R_::Exact_kernel_rt >,
|
||||
Point_triple_less_signed_distance_to_plane_3< typename R_::Approximate_kernel >,
|
||||
Point_triple_converter<R_,typename R_::Exact_kernel_rt>,
|
||||
Point_triple_converter<R_,typename R_::Approximate_kernel>
|
||||
> Less_signed_distance_to_plane_3;
|
||||
};
|
||||
|
||||
|
||||
template <class R_, class Polyhedron = Default, class Has_filtered_predicates_tag = Tag_false>
|
||||
class Convex_hull_traits_3 :
|
||||
public Convex_hull_traits_base_3<R_, Has_filtered_predicates_tag>
|
||||
class Convex_hull_traits_3
|
||||
{
|
||||
public:
|
||||
typedef R_ R;
|
||||
|
|
@ -228,11 +196,12 @@ class Convex_hull_traits_3 :
|
|||
typedef typename R::Coplanar_3 Coplanar_3;
|
||||
typedef typename R::Less_distance_to_point_3 Less_distance_to_point_3;
|
||||
|
||||
typedef typename Convex_hull_traits_base_3<R_, Has_filtered_predicates_tag>
|
||||
::Has_on_positive_side_3 Has_on_positive_side_3;
|
||||
typedef Point_triple_has_on_positive_side_3<R> Has_on_positive_side_3;
|
||||
|
||||
typedef typename Convex_hull_traits_base_3<R_, Has_filtered_predicates_tag>
|
||||
::Less_signed_distance_to_plane_3 Less_signed_distance_to_plane_3;
|
||||
typedef Point_triple_less_signed_distance_to_plane_3<R>
|
||||
Less_signed_distance_to_plane_3;
|
||||
|
||||
|
||||
|
||||
// required for degenerate case of all points coplanar
|
||||
typedef CGAL::Projection_traits_xy_3<R> Traits_xy_3;
|
||||
|
|
|
|||
|
|
@ -138,7 +138,7 @@ public:
|
|||
public:
|
||||
Construct_plane_3(const PointPropertyMap& map, const typename Base_traits::Construct_plane_3& base):
|
||||
Base_traits::Construct_plane_3(base),vpm_(map), base(base){}
|
||||
typename Base_traits::Plane_3 operator()(const Point_3& p, const Point_3& q, const Point_3& r)const
|
||||
typename Base_traits::Plane_3 operator()(const Vertex& p, const Vertex& q, const Vertex& r)const
|
||||
{
|
||||
return base(get(vpm_,p),get(vpm_,q),get(vpm_,r));
|
||||
}
|
||||
|
|
@ -159,7 +159,7 @@ public:
|
|||
typedef bool result_type;
|
||||
|
||||
result_type
|
||||
operator()( const Plane_3& pl, const Point_3& p) const
|
||||
operator()( const Plane_3& pl, const Vertex& p) const
|
||||
{
|
||||
return base(pl, get(vpm_, p));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -182,13 +182,13 @@ struct Is_cartesian_kernel< Convex_hull_traits_3<Kernel, PolygonMesh, Tag_true>
|
|||
{
|
||||
// Rational here is that Tag_true can only be passed by us since it is not documented
|
||||
// so we can assume that Kernel is a CGAL Kernel
|
||||
typedef boost::is_same<typename Kernel::Kernal_tag, Cartesian_tag> type;
|
||||
typedef typename boost::is_same<typename Kernel::Kernel_tag, Cartesian_tag>::type type;
|
||||
};
|
||||
|
||||
// Predicate internally used as a wrapper around has_on_positive_side
|
||||
// We provide a partial specialization restricted to the case of CGAL Cartesian Kernels with inexact constructions below
|
||||
//template <class Traits,class Tag_use_advanced_filtering=typename Use_advanced_filtering<Traits>::type >
|
||||
template <class Traits, class Is_CK = Is_cartesian_kernel<Traits> >
|
||||
template <class Traits, class Is_CK = typename Is_cartesian_kernel<Traits>::type >
|
||||
class Is_on_positive_side_of_plane_3{
|
||||
typedef typename Traits::Point_3 Point_3;
|
||||
typename Traits::Plane_3 plane;
|
||||
|
|
|
|||
|
|
@ -1,6 +1,25 @@
|
|||
Release History
|
||||
===============
|
||||
|
||||
Release 4.14
|
||||
------------
|
||||
|
||||
Release date: March 2019
|
||||
|
||||
### Polygon Mesh Processing package
|
||||
- Added the following new functions to detect and repair mesh degeneracies:
|
||||
- `CGAL::Polygon_mesh_processing::degenerate_edges()`
|
||||
- `CGAL::Polygon_mesh_processing::degenerate_faces()`
|
||||
- `CGAL::Polygon_mesh_processing::is_non_manifold_vertex()`
|
||||
- `CGAL::Polygon_mesh_processing::is_degenerate_triangle_face()`
|
||||
- `CGAL::Polygon_mesh_processing::is_degenerate_edge()`
|
||||
- `CGAL::Polygon_mesh_processing::is_needle_triangle_face()`
|
||||
- `CGAL::Polygon_mesh_processing::is_cap_triangle_face()`
|
||||
- `CGAL::Polygon_mesh_processing::duplicate_non_manifold_vertices()`
|
||||
- `CGAL::Polygon_mesh_processing::extract_boundary_cycles()`
|
||||
- `CGAL::Polygon_mesh_processing::merge_duplicated_vertices_in_boundary_cycle()`
|
||||
- `CGAL::Polygon_mesh_processing::merge_duplicated_vertices_in_boundary_cycles()`
|
||||
|
||||
Release 4.13
|
||||
------------
|
||||
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ namespace CGAL {
|
|||
The class `Kernel_traits` provides access to the kernel model to
|
||||
which the argument type `T` belongs. (Provided `T` belongs to
|
||||
some kernel model.) The default implementation assumes there is a
|
||||
local type `T::Kernel` referring to the kernel model of `T`.
|
||||
local type `T::R` referring to the kernel model of `T`.
|
||||
If this type does not exist, a specialization of `Kernel_traits` can be
|
||||
used to provide the desired information.
|
||||
|
||||
|
|
|
|||
|
|
@ -722,6 +722,8 @@ public:
|
|||
\cgalHasModel `CGAL::Vector_2<Kernel>`
|
||||
|
||||
\sa `Kernel::ComputeDeterminant_2`
|
||||
\sa `Kernel::ComputeScalarProduct_2`
|
||||
\sa `Kernel::ComputeSquaredLength_2`
|
||||
\sa `Kernel::ComputeX_2`
|
||||
\sa `Kernel::ComputeY_2`
|
||||
\sa `Kernel::ComputeHx_2`
|
||||
|
|
@ -754,7 +756,10 @@ A type representing vectors in three dimensions.
|
|||
|
||||
\cgalHasModel `CGAL::Vector_3<Kernel>`
|
||||
|
||||
\sa `Kernel::ComputeDeterminant_3`
|
||||
\sa `Kernel::CompareDihedralAngle_3`
|
||||
\sa `Kernel::ComputeDeterminant_3`
|
||||
\sa `Kernel::ComputeScalarProduct_3`
|
||||
\sa `Kernel::ComputeSquaredLength_3`
|
||||
\sa `Kernel::ComputeX_3`
|
||||
\sa `Kernel::ComputeY_3`
|
||||
\sa `Kernel::ComputeZ_3`
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ configure()
|
|||
{
|
||||
echo "Configuring... "
|
||||
|
||||
if eval 'cmake --no-warn-unused-cli "$CMAKE_GENERATOR" -DRUNNING_CGAL_AUTO_TEST=TRUE \
|
||||
if eval 'cmake --no-warn-unused-cli ${INIT_FILE:+"-C${INIT_FILE}"} "$CMAKE_GENERATOR" -DRUNNING_CGAL_AUTO_TEST=TRUE \
|
||||
-DCGAL_DIR="$CGAL_DIR" \
|
||||
.' ; then
|
||||
|
||||
|
|
|
|||
|
|
@ -302,7 +302,13 @@ struct Mpzf {
|
|||
data()[-1] = mini;
|
||||
}
|
||||
void clear(){
|
||||
while(*--data()==0); // in case we skipped final zeroes
|
||||
// while(*--data()==0);
|
||||
// This line gave a misscompilation by Intel Compiler 2019
|
||||
// (19.0.0.117). I replaced it by the following two lines:
|
||||
// -- Laurent Rineau, sept. 2018
|
||||
--data();
|
||||
while(*data()==0) { --data(); } // in case we skipped final zeroes
|
||||
|
||||
#ifdef CGAL_MPZF_USE_CACHE
|
||||
if (data() == cache) return;
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -1,72 +0,0 @@
|
|||
// Copyright (c) 2011 GeometryFactory (France).
|
||||
// All rights reserved.
|
||||
//
|
||||
// This file is part of CGAL (www.cgal.org).
|
||||
// You can redistribute it and/or modify it under the terms of the GNU
|
||||
// General Public License as published by the Free Software Foundation,
|
||||
// either version 3 of the License, or (at your option) any later version.
|
||||
//
|
||||
// Licensees holding a valid commercial license may use this file in
|
||||
// accordance with the commercial license agreement provided with the software.
|
||||
//
|
||||
// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
|
||||
// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
|
||||
//
|
||||
// $URL$
|
||||
// $Id$
|
||||
// SPDX-License-Identifier: GPL-3.0+
|
||||
//
|
||||
//
|
||||
// Author(s) : Sebastien Loriot
|
||||
|
||||
|
||||
#ifndef CGAL_TRIANGLE_ACCESSOR_WITH_PPMAP_3_H
|
||||
#define CGAL_TRIANGLE_ACCESSOR_WITH_PPMAP_3_H
|
||||
|
||||
#include <CGAL/license/Polygon_mesh_processing.h>
|
||||
|
||||
|
||||
#include <CGAL/Kernel_traits.h>
|
||||
#include <CGAL/property_map.h>
|
||||
|
||||
namespace CGAL{
|
||||
|
||||
template < class Polyhedron, class PolyhedronPointPMap>
|
||||
struct Triangle_accessor_with_ppmap_3
|
||||
{
|
||||
typedef PolyhedronPointPMap Ppmap;
|
||||
typedef typename boost::property_traits< Ppmap >::value_type Point_3;
|
||||
typedef typename CGAL::Kernel_traits<Point_3>::Kernel Kernel;
|
||||
typedef typename Kernel::Triangle_3 Triangle_3;
|
||||
typedef typename Polyhedron::Facet_const_iterator Triangle_iterator;
|
||||
typedef typename Polyhedron::Facet_const_handle Triangle_handle;
|
||||
|
||||
PolyhedronPointPMap ppmap;
|
||||
|
||||
Triangle_accessor_with_ppmap_3(){}
|
||||
|
||||
Triangle_accessor_with_ppmap_3(PolyhedronPointPMap ppmap):ppmap(ppmap) {}
|
||||
|
||||
Triangle_iterator triangles_begin(const Polyhedron& p) const
|
||||
{
|
||||
return p.facets_begin();
|
||||
}
|
||||
|
||||
Triangle_iterator triangles_end(const Polyhedron& p) const
|
||||
{
|
||||
return p.facets_end();
|
||||
}
|
||||
|
||||
Triangle_3 triangle(const Triangle_handle& handle) const
|
||||
{
|
||||
typedef typename Kernel::Point_3 Point;
|
||||
const Point& a = get(ppmap, handle->halfedge()->vertex());
|
||||
const Point& b = get(ppmap, handle->halfedge()->next()->vertex());
|
||||
const Point& c = get(ppmap, handle->halfedge()->next()->next()->vertex());
|
||||
return Triangle_3(a,b,c);
|
||||
}
|
||||
};
|
||||
|
||||
} // end of namespace CGAL
|
||||
|
||||
#endif // CGAL_TRIANGLE_ACCESSOR_WITH_PPMAP_3_H
|
||||
|
|
@ -1,484 +0,0 @@
|
|||
// Copyright (c) 2011 GeometryFactory (France).
|
||||
// All rights reserved.
|
||||
//
|
||||
// This file is part of CGAL (www.cgal.org).
|
||||
// You can redistribute it and/or modify it under the terms of the GNU
|
||||
// General Public License as published by the Free Software Foundation,
|
||||
// either version 3 of the License, or (at your option) any later version.
|
||||
//
|
||||
// Licensees holding a valid commercial license may use this file in
|
||||
// accordance with the commercial license agreement provided with the software.
|
||||
//
|
||||
// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
|
||||
// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
|
||||
//
|
||||
// $URL$
|
||||
// $Id$
|
||||
// SPDX-License-Identifier: GPL-3.0+
|
||||
//
|
||||
//
|
||||
// Author(s) : Sebastien Loriot
|
||||
|
||||
#ifndef CGAL_COREFINEMENT_OPERATIONS_H
|
||||
#define CGAL_COREFINEMENT_OPERATIONS_H
|
||||
|
||||
#include <CGAL/license/Polygon_mesh_processing.h>
|
||||
|
||||
|
||||
#include <CGAL/intersection_of_Polyhedra_3.h>
|
||||
#include <CGAL/intersection_of_Polyhedra_3_refinement_visitor.h>
|
||||
#include <CGAL/internal/corefinement/Combinatorial_map_output_builder.h>
|
||||
|
||||
namespace CGAL{
|
||||
/** \cond */
|
||||
namespace internal{
|
||||
|
||||
template <class HDS>
|
||||
class Import_volume_as_polyhedron : public CGAL::Modifier_base<HDS> {
|
||||
typedef typename HDS::Halfedge_handle Halfedge_handle;
|
||||
typedef typename HDS::Vertex_handle Vertex_handle;
|
||||
typedef typename HDS::Face_handle Face_handle;
|
||||
typedef typename HDS::Vertex Vertex;
|
||||
typedef typename HDS::Halfedge Halfedge;
|
||||
typedef typename HDS::Face Face;
|
||||
|
||||
//data members
|
||||
Face_handle current_face;
|
||||
std::vector< typename Vertex::Point > points;
|
||||
std::size_t nb_edges;
|
||||
std::vector<CGAL::cpp11::tuple<unsigned,unsigned,unsigned> > faces;
|
||||
|
||||
public:
|
||||
|
||||
//to import each piece individually
|
||||
template <class Combinatorial_map_3>
|
||||
Import_volume_as_polyhedron(const Combinatorial_map_3& map,typename Combinatorial_map_3::Dart_const_handle dart):nb_edges(0)
|
||||
{
|
||||
typedef Combinatorial_map_3 CMap;
|
||||
typedef std::map<const typename Vertex::Point*,unsigned int> Vertex_map;
|
||||
Vertex_map vertex_map;
|
||||
unsigned int index=0;
|
||||
//recover all the vertices in the current volumeiterator over all the point
|
||||
//map the vertex to the index of the point in the vector
|
||||
for (typename CMap::template One_dart_per_incident_cell_const_range<0,3>::const_iterator
|
||||
it=map.template one_dart_per_incident_cell<0,3>(dart).begin(),
|
||||
itend=map.template one_dart_per_incident_cell<0,3>(dart).end();
|
||||
it!=itend; ++it)
|
||||
{
|
||||
points.push_back(map.template attribute<0>(it)->point());
|
||||
vertex_map.insert(std::make_pair(&map.template attribute<0>(it)->point(),index++));
|
||||
}
|
||||
|
||||
//count the number of edges
|
||||
nb_edges+=map.template one_dart_per_incident_cell<1,3>(dart).size();
|
||||
|
||||
//recover one dart per face
|
||||
for (typename CMap::template One_dart_per_incident_cell_const_range<2,3>::const_iterator
|
||||
it=map.template one_dart_per_incident_cell<2,3>(dart).begin(),
|
||||
itend=map.template one_dart_per_incident_cell<2,3>(dart).end();
|
||||
it!=itend; ++it)
|
||||
{
|
||||
//warning: the convention used into a polyhedron is that the normal
|
||||
// of a triangle indicates the outside of the object; thus
|
||||
// we need to reverse the orientation of the faces of the
|
||||
// combinatorial map.
|
||||
unsigned int i=vertex_map[&map.template attribute<0>(it)->point()];
|
||||
unsigned int j=vertex_map[&map.template attribute<0>(map.beta(it, 0))->point()];
|
||||
unsigned int k=vertex_map[&map.template attribute<0>(map.beta(it, 1))->point()];
|
||||
faces.push_back(CGAL::cpp11::make_tuple(i,j,k));
|
||||
}
|
||||
}
|
||||
|
||||
//for intersection and symetric difference
|
||||
template <class Combinatorial_map_3,class Iterator>
|
||||
Import_volume_as_polyhedron(const Combinatorial_map_3& map,
|
||||
Iterator dart_begin,
|
||||
Iterator dart_end):nb_edges(0)
|
||||
{
|
||||
typedef Combinatorial_map_3 CMap;
|
||||
typedef std::map<const typename Vertex::Point*,unsigned int> Vertex_map;
|
||||
Vertex_map vertex_map;
|
||||
unsigned int index=0;
|
||||
|
||||
for (Iterator it=dart_begin;it!=dart_end;++it)
|
||||
{
|
||||
typename Combinatorial_map_3::Dart_const_handle dart=*it;
|
||||
//recover all the vertices in the current volumeiterator over all the point
|
||||
//map the vertex to the index of the point in the vector
|
||||
for (typename CMap::template One_dart_per_incident_cell_const_range<0,3>::const_iterator
|
||||
it=map.template one_dart_per_incident_cell<0,3>(dart).begin(),
|
||||
itend=map.template one_dart_per_incident_cell<0,3>(dart).end();
|
||||
it!=itend; ++it)
|
||||
{
|
||||
if ( vertex_map.insert(std::make_pair(&map.template attribute<0>(it)->point(),index)).second )
|
||||
{
|
||||
points.push_back(map.template attribute<0>(it)->point());
|
||||
++index;
|
||||
}
|
||||
}
|
||||
|
||||
//count the number of edges
|
||||
nb_edges+=map.template one_dart_per_incident_cell<1,3>(dart).size();
|
||||
|
||||
//recover one dart per face
|
||||
for (typename CMap::template One_dart_per_incident_cell_const_range<2,3>::const_iterator
|
||||
it=map.template one_dart_per_incident_cell<2,3>(dart).begin(),
|
||||
itend=map.template one_dart_per_incident_cell<2,3>(dart).end();
|
||||
it!=itend; ++it)
|
||||
{
|
||||
//warning: the convention used into a polyhedron is that the normal
|
||||
// of a triangle indicates the outside of the object; thus
|
||||
// we need to reverse the orientation of the faces of the
|
||||
// combinatorial map.
|
||||
unsigned int i=vertex_map[&map.template attribute<0>(it)->point()];
|
||||
unsigned int j=vertex_map[&map.template attribute<0>(map.beta(it, 0))->point()];
|
||||
unsigned int k=vertex_map[&map.template attribute<0>(map.beta(it, 1))->point()];
|
||||
faces.push_back(CGAL::cpp11::make_tuple(i,j,k));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//for union : use the inverse of the complementary
|
||||
template <class Combinatorial_map_3,class Iterator>
|
||||
Import_volume_as_polyhedron(const Combinatorial_map_3& map,
|
||||
Iterator dart_begin,
|
||||
Iterator dart_end,bool):nb_edges(0)
|
||||
{
|
||||
typedef Combinatorial_map_3 CMap;
|
||||
typedef std::map<const typename Vertex::Point*,unsigned int> Vertex_map;
|
||||
Vertex_map vertex_map;
|
||||
unsigned int index=0;
|
||||
|
||||
for (Iterator it=dart_begin;it!=dart_end;++it)
|
||||
{
|
||||
typename Combinatorial_map_3::Dart_const_handle dart=*it;
|
||||
//recover all the vertices in the current volumeiterator over all the point
|
||||
//map the vertex to the index of the point in the vector
|
||||
for (typename CMap::template One_dart_per_incident_cell_const_range<0,3>::const_iterator
|
||||
it=map.template one_dart_per_incident_cell<0,3>(dart).begin(),
|
||||
itend=map.template one_dart_per_incident_cell<0,3>(dart).end();
|
||||
it!=itend; ++it)
|
||||
{
|
||||
if (vertex_map.insert(std::make_pair(&map.template attribute<0>(it)->point(),index)).second )
|
||||
{
|
||||
points.push_back(map.template attribute<0>(it)->point());
|
||||
++index;
|
||||
}
|
||||
}
|
||||
|
||||
//count the number of edges
|
||||
nb_edges+=map.template one_dart_per_incident_cell<1,3>(dart).size();
|
||||
|
||||
//recover one dart per face
|
||||
for (typename CMap::template One_dart_per_incident_cell_const_range<2,3>::const_iterator
|
||||
it=map.template one_dart_per_incident_cell<2,3>(dart).begin(),
|
||||
itend=map.template one_dart_per_incident_cell<2,3>(dart).end();
|
||||
it!=itend; ++it)
|
||||
{
|
||||
//warning: the convention used into a polyhedron is that the normal
|
||||
// of a triangle indicates the outside of the object; thus
|
||||
// we need to reverse the orientation of the faces of the
|
||||
// combinatorial map. Since to get the complementary we
|
||||
// also need to reverse the orientation, we finally do
|
||||
// not change it.
|
||||
unsigned int i=vertex_map[&map.template attribute<0>(it)->point()];
|
||||
unsigned int j=vertex_map[&map.template attribute<0>(map.beta(it, 1))->point()];
|
||||
unsigned int k=vertex_map[&map.template attribute<0>(map.beta(it, 0))->point()];
|
||||
faces.push_back(CGAL::cpp11::make_tuple(i,j,k));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void operator()( HDS& hds)
|
||||
{
|
||||
CGAL::Polyhedron_incremental_builder_3<HDS> B(hds, true);
|
||||
B.begin_surface( points.size(), faces.size(),2*nb_edges);
|
||||
|
||||
//insert vertices
|
||||
for (typename std::vector<typename Vertex::Point>::iterator it=points.begin();it!=points.end();++it)
|
||||
B.add_vertex(*it);
|
||||
|
||||
//create faces
|
||||
for (std::vector<CGAL::cpp11::tuple<unsigned,unsigned,unsigned> >::iterator it=faces.begin();it!=faces.end();++it)
|
||||
{
|
||||
B.begin_facet();
|
||||
B.add_vertex_to_facet(CGAL::cpp11::get<0>(*it));
|
||||
B.add_vertex_to_facet(CGAL::cpp11::get<1>(*it));
|
||||
B.add_vertex_to_facet(CGAL::cpp11::get<2>(*it));
|
||||
B.end_facet();
|
||||
}
|
||||
B.end_surface();
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
/** \endcond */
|
||||
|
||||
/*! \class Polyhedron_corefinement corefinement_operations.h CGAL/corefinement_operations.h
|
||||
* Function object to compute the decomposition of the space induced by two polyhedra.
|
||||
* @tparam Polyhedron must be an instantiation of CGAL::Polyhedron_3<Traits>.
|
||||
* @tparam Kernel must be a CGAL Kernel compatible with the underlying kernel of Polyhedron.
|
||||
* @tparam Output_polyhedron is a polyhedron type used as output. `Kernel` must be compatible with the underlying kernel of `Output_polyhedron`.
|
||||
*/
|
||||
template <class Polyhedron,class Kernel=typename Polyhedron::Traits::Kernel, class Output_polyhedron=Polyhedron>
|
||||
class Polyhedron_corefinement
|
||||
{
|
||||
typedef internal::Import_volume_as_polyhedron<typename Output_polyhedron::HalfedgeDS> Volume_import_modifier;
|
||||
|
||||
public:
|
||||
/** Enumeration of the different feature tags, listing all kind of space decomposition the functor can compute given two input polyhedra P and Q.*/
|
||||
enum Boolean_operation_tag
|
||||
{
|
||||
Join_tag=1, /*!< the union of P and Q. */
|
||||
Intersection_tag=2, /*!< the intersection of P and Q. */
|
||||
P_minus_Q_tag=4, /*!< P minus Q. */
|
||||
Q_minus_P_tag=8, /*!< Q minus P. */
|
||||
Parts_of_P_tag=32, /*!< decomposition of the volume bounded by P induced by Q. */
|
||||
Parts_of_Q_tag=64, /*!< decomposition of the volume bounded by Q induced by P. */
|
||||
Decomposition_tag=16 /*!< Both decompositions of P and Q. */
|
||||
};
|
||||
|
||||
/**
|
||||
* This computes different polyhedra according to the value of features.
|
||||
* Each input polyhedron is expected to bound a volume: the volume is bounded by the surface polyhedron with facet
|
||||
* normals pointing outside the volume. Each facet is supposed to be counterclockwise oriented, that is its vertex
|
||||
* sequence (induced by halfedges) is seen counterclockwise from the side of the facet pointed by its normal. If one or
|
||||
* both polyhedra are not closed, the algorithm will end up correctly if each intersection polyline separates each surface
|
||||
* in two components. In that case for each triangle of each surface path boundary, the interior of the volume is considered
|
||||
* to be on the side opposite of that pointed by it normals (but the orientation must be consistent on each patch).
|
||||
* the surface the volume bounded by an open surface is considered to be an infinite volume above
|
||||
* or below the surface (the side not pointed by normal vectors).
|
||||
* @tparam Polyline_output_iterator must be an output iterator of std::vector<Kernel::Point_3>.
|
||||
* @tparam Polyhedron_ptr_and_type_output_iterator an output iterator of std::pair<Polyhedron*,int>.
|
||||
* @param P is the first input triangulated polyhedron. Note that a reference is taken and P will be updated to contain the 1D intersection between the two surfaces P and Q.
|
||||
* @param Q is the second input triangulated polyhedron. Note that a reference is taken and Q will be updated to contain the 1D intersection between the two surfaces P and Q.
|
||||
* @param polyline_output is an output iterator that collects intersection polylines between P and Q.
|
||||
* @param poly_output is an output iterator that collects output polyhedra. Note that each polyhedron is allocated within this function (thus must be explicitly deleted when no longer used). The integer is a feature tag corresponding to the volume represented by the polyhedron of the pair.
|
||||
* @param features is an integer indicating what polyhedra the function must compute. If several kind of polyhedra are expected, feature tags must be combined by |. For example if features = Polyhedron_corefinement<Polyhedron,Kernel>::Join_tag | Polyhedron_corefinement<Polyhedron,Kernel>::Intersection_tag, then poly_output will collect two polyhedra, the union and the intersection of P and Q.
|
||||
*/
|
||||
template <class Polyline_output_iterator,class Polyhedron_ptr_and_type_output_iterator>
|
||||
void operator()( Polyhedron& P, Polyhedron& Q,
|
||||
Polyline_output_iterator polyline_output,
|
||||
Polyhedron_ptr_and_type_output_iterator poly_output,
|
||||
int features) const
|
||||
{
|
||||
typedef CGAL::Corefinement::Combinatorial_map_output_builder<Polyhedron> Output_builder;
|
||||
Output_builder output_builder;
|
||||
typedef CGAL::Node_visitor_refine_polyhedra<Polyhedron, Output_builder> Split_visitor;
|
||||
Split_visitor visitor(output_builder);
|
||||
CGAL::Intersection_of_Polyhedra_3<Polyhedron,
|
||||
Kernel,
|
||||
Split_visitor> polyline_intersections(visitor);
|
||||
|
||||
polyline_intersections(P, Q, polyline_output);
|
||||
|
||||
typedef typename Output_builder::Combinatorial_map_3 Combinatorial_map_3;
|
||||
typedef typename Output_builder::Volume_info Volume_info;
|
||||
typedef typename Combinatorial_map_3::Dart_const_handle Dart_const_handle;
|
||||
|
||||
const Combinatorial_map_3& final_map=output_builder.combinatorial_map();
|
||||
|
||||
typename Combinatorial_map_3::template One_dart_per_cell_const_range<3> cell_range=final_map.template one_dart_per_cell<3>();
|
||||
|
||||
std::list<Dart_const_handle> intersection;
|
||||
std::list<Dart_const_handle> union_;
|
||||
std::list<Dart_const_handle> P_minus_Q;
|
||||
std::list<Dart_const_handle> Q_minus_P;
|
||||
|
||||
for (typename Combinatorial_map_3::template One_dart_per_cell_const_range<3>::const_iterator
|
||||
it = cell_range.begin(), it_end= cell_range.end();
|
||||
it!= it_end;
|
||||
++it )
|
||||
{
|
||||
|
||||
const Volume_info& info=final_map.template attribute<3>(it)->info();
|
||||
std::size_t inside_size=info.inside.size();
|
||||
std::size_t outside_size=info.outside.size();
|
||||
|
||||
if ( inside_size + outside_size != 2){
|
||||
std::cerr << "Error: One volume cannot be represented using a polyhedron. Aborted.\n";
|
||||
break;
|
||||
}
|
||||
|
||||
switch (outside_size)
|
||||
{
|
||||
case 2:
|
||||
if (features & Join_tag) union_.push_back(it);
|
||||
break;
|
||||
case 0:
|
||||
if (features & Intersection_tag) intersection.push_back(it);
|
||||
break;
|
||||
default:
|
||||
if ( *info.inside.begin() == &P )
|
||||
{ if (features & P_minus_Q_tag) P_minus_Q.push_back(it); }
|
||||
else
|
||||
{ if (features & Q_minus_P_tag) Q_minus_P.push_back(it); }
|
||||
}
|
||||
|
||||
if ( features&Decomposition_tag )
|
||||
{
|
||||
Volume_import_modifier modifier(final_map,it);
|
||||
Output_polyhedron* new_poly=new Output_polyhedron();
|
||||
new_poly->delegate(modifier);
|
||||
*poly_output++ = std::make_pair( new_poly,static_cast<int>(Decomposition_tag) );
|
||||
}
|
||||
|
||||
if ( features&Parts_of_P_tag && info.inside.find(&P)!=info.inside.end() )
|
||||
{
|
||||
Volume_import_modifier modifier(final_map,it);
|
||||
Output_polyhedron* new_poly=new Output_polyhedron();
|
||||
new_poly->delegate(modifier);
|
||||
*poly_output++ = std::make_pair( new_poly,static_cast<int>(Parts_of_P_tag) );
|
||||
}
|
||||
|
||||
if ( features&Parts_of_Q_tag && info.inside.find(&Q)!=info.inside.end() )
|
||||
{
|
||||
Volume_import_modifier modifier(final_map,it);
|
||||
Output_polyhedron* new_poly=new Output_polyhedron();
|
||||
new_poly->delegate(modifier);
|
||||
*poly_output++ = std::make_pair( new_poly,static_cast<int>(Parts_of_Q_tag) );
|
||||
}
|
||||
}
|
||||
|
||||
if (!intersection.empty())
|
||||
{
|
||||
Volume_import_modifier modifier(final_map,intersection.begin(),intersection.end());
|
||||
Output_polyhedron* new_poly=new Output_polyhedron();
|
||||
new_poly->delegate(modifier);
|
||||
*poly_output++=std::make_pair( new_poly,static_cast<int>(Intersection_tag) );
|
||||
}
|
||||
|
||||
if (!P_minus_Q.empty())
|
||||
{
|
||||
Volume_import_modifier modifier(final_map,P_minus_Q.begin(),P_minus_Q.end());
|
||||
Output_polyhedron* new_poly=new Output_polyhedron();
|
||||
new_poly->delegate(modifier);
|
||||
*poly_output++=std::make_pair( new_poly,static_cast<int>(P_minus_Q_tag) );
|
||||
}
|
||||
|
||||
if (!Q_minus_P.empty())
|
||||
{
|
||||
Volume_import_modifier modifier(final_map,Q_minus_P.begin(),Q_minus_P.end());
|
||||
Output_polyhedron* new_poly=new Output_polyhedron();
|
||||
new_poly->delegate(modifier);
|
||||
*poly_output++=std::make_pair( new_poly,static_cast<int>(Q_minus_P_tag) );
|
||||
}
|
||||
|
||||
if (!union_.empty())
|
||||
{
|
||||
Volume_import_modifier modifier(final_map,union_.begin(),union_.end(),true);
|
||||
Output_polyhedron* new_poly=new Output_polyhedron();
|
||||
new_poly->delegate(modifier);
|
||||
*poly_output++=std::make_pair( new_poly,static_cast<int>(Join_tag) );
|
||||
}
|
||||
}
|
||||
/**
|
||||
* This updates P according to the value of features.
|
||||
* Each input polyhedron is expected to bound a volume: the volume is bounded by the surface polyhedron with facet
|
||||
* normals pointing outside the volume. Each facet is supposed to be counterclockwise oriented, that is its vertex
|
||||
* sequence (induced by halfedges) is seen counterclockwise from the side of the facet pointed by its normal. If one or
|
||||
* both polyhedra are not closed, the algorithm will end up correctly if each intersection polyline separates each surface
|
||||
* in two components. In that case for each triangle of each surface path boundary, the interior of the volume is considered
|
||||
* to be on the side opposite of that pointed by it normals (but the orientation must be consistent on each patch).
|
||||
* the surface the volume bounded by an open surface is considered to be an infinite volume above
|
||||
* or below the surface (the side not pointed by normal vectors).
|
||||
* @tparam Polyline_output_iterator must be an output iterator of std::vector<Kernel::Point_3>.
|
||||
* @param P is the first input triangulated polyhedron. Note that a reference is taken and P will be updated to contain the 1D intersection between the two surfaces P and Q.
|
||||
* @param Q is the first input triangulated polyhedron. Note that a reference is taken and Q will be updated to contain the 1D intersection between the two surfaces P and Q.
|
||||
* @param polyline_output is an output iterator that collects intersection polylines between P and Q.
|
||||
* @param features is either Join_tag, Intersection_tag, P_minus_Q_tag or Q_minus_P_tag
|
||||
*/
|
||||
template <class Polyline_output_iterator>
|
||||
void operator()( Polyhedron& P, Polyhedron& Q,
|
||||
Polyline_output_iterator polyline_output,
|
||||
Boolean_operation_tag features) const
|
||||
{
|
||||
typedef CGAL::Node_visitor_refine_polyhedra<Polyhedron> Split_visitor;
|
||||
Split_visitor visitor;
|
||||
CGAL::Intersection_of_Polyhedra_3<Polyhedron,
|
||||
Kernel,
|
||||
Split_visitor> polyline_intersections(visitor);
|
||||
|
||||
polyline_intersections(P, Q, polyline_output);
|
||||
|
||||
typedef typename Split_visitor::Combinatorial_map_3 Combinatorial_map_3;
|
||||
typedef typename Split_visitor::Volume_info Volume_info;
|
||||
typedef typename Combinatorial_map_3::Dart_const_handle Dart_const_handle;
|
||||
|
||||
const typename Split_visitor::Combinatorial_map_3& final_map=visitor.combinatorial_map();
|
||||
|
||||
typename Combinatorial_map_3::template One_dart_per_cell_const_range<3> cell_range=final_map.template one_dart_per_cell<3>();
|
||||
|
||||
std::list<Dart_const_handle> darts;
|
||||
|
||||
for (typename Combinatorial_map_3::template One_dart_per_cell_const_range<3>::const_iterator
|
||||
it = cell_range.begin(), it_end= cell_range.end();
|
||||
it!= it_end;
|
||||
++it )
|
||||
{
|
||||
|
||||
const Volume_info& info=it->template attribute<3>()->info();
|
||||
std::size_t inside_size=info.inside.size();
|
||||
std::size_t outside_size=info.outside.size();
|
||||
|
||||
if ( inside_size + outside_size != 2){
|
||||
std::cerr << "Error: One volume cannot be represented using a polyhedron. Aborted.\n";
|
||||
break;
|
||||
}
|
||||
|
||||
switch (outside_size)
|
||||
{
|
||||
case 2:
|
||||
if ( features==Join_tag ) darts.push_back(it);
|
||||
break;
|
||||
case 0:
|
||||
if ( features==Intersection_tag ) darts.push_back(it);
|
||||
break;
|
||||
default:
|
||||
if ( *info.inside.begin() == &P )
|
||||
{ if (features == P_minus_Q_tag) darts.push_back(it); }
|
||||
else
|
||||
{ if (features == Q_minus_P_tag) darts.push_back(it); }
|
||||
}
|
||||
}
|
||||
|
||||
P.clear();
|
||||
|
||||
if (!darts.empty())
|
||||
{
|
||||
Volume_import_modifier modifier=
|
||||
features==Join_tag?
|
||||
Volume_import_modifier(final_map,darts.begin(),darts.end(),true)
|
||||
: Volume_import_modifier(final_map,darts.begin(),darts.end());
|
||||
P.delegate(modifier);
|
||||
}
|
||||
}
|
||||
|
||||
/** \cond */
|
||||
static std::string get_type_str(const std::string& Pname,const std::string& Qname,int i)
|
||||
{
|
||||
switch (i)
|
||||
{
|
||||
case Join_tag:
|
||||
return Pname+std::string("_union_")+Qname;
|
||||
case P_minus_Q_tag:
|
||||
return Pname+std::string("_minus_")+Qname;
|
||||
case Q_minus_P_tag:
|
||||
return Qname+std::string("_minus_")+Pname;
|
||||
case Intersection_tag:
|
||||
return Pname+std::string("_inter_")+Qname;
|
||||
case Decomposition_tag:
|
||||
return std::string("Decomposition");
|
||||
}
|
||||
return std::string("Unknow");
|
||||
}
|
||||
/** \endcond */
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
#endif // CGAL_COREFINEMENT_OPERATIONS_H
|
||||
|
|
@ -1,115 +0,0 @@
|
|||
// Copyright (c) 2012 GeometryFactory Sarl (France)
|
||||
// All rights reserved.
|
||||
//
|
||||
// This file is part of CGAL (www.cgal.org).
|
||||
// You can redistribute it and/or modify it under the terms of the GNU
|
||||
// General Public License as published by the Free Software Foundation,
|
||||
// either version 3 of the License, or (at your option) any later version.
|
||||
//
|
||||
// Licensees holding a valid commercial license may use this file in
|
||||
// accordance with the commercial license agreement provided with the software.
|
||||
//
|
||||
// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
|
||||
// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
|
||||
//
|
||||
// $URL$
|
||||
// $Id$
|
||||
// SPDX-License-Identifier: GPL-3.0+
|
||||
//
|
||||
//
|
||||
// Author(s) : Sebastien Loriot
|
||||
|
||||
#ifndef CGAL_INTERNAL_COMBINATORIAL_MAP_FOR_COREFINEMENT_H
|
||||
#define CGAL_INTERNAL_COMBINATORIAL_MAP_FOR_COREFINEMENT_H
|
||||
|
||||
#include <CGAL/license/Polygon_mesh_processing.h>
|
||||
|
||||
|
||||
#include <CGAL/Combinatorial_map.h>
|
||||
#include <CGAL/Combinatorial_map_constructors.h>
|
||||
#include <CGAL/Cell_attribute.h>
|
||||
#include <set>
|
||||
|
||||
namespace CGAL{
|
||||
namespace internal_IOP{
|
||||
|
||||
template <class Polyhedron>
|
||||
struct Volume_info{
|
||||
std::set<Polyhedron*> outside;
|
||||
std::set<Polyhedron*> inside;
|
||||
bool is_empty;
|
||||
Volume_info():is_empty(false){}
|
||||
};
|
||||
|
||||
struct Volume_on_merge
|
||||
{
|
||||
template <class Attribute>
|
||||
void operator() (Attribute& a1,const Attribute& a2) const
|
||||
{
|
||||
CGAL_assertion(!a1.info().is_empty && !a2.info().is_empty);
|
||||
std::copy(a2.info().outside.begin(),a2.info().outside.end(),std::inserter(a1.info().outside,a1.info().outside.begin()));
|
||||
std::copy(a2.info().inside.begin(),a2.info().inside.end(),std::inserter(a1.info().inside,a1.info().inside.begin()));
|
||||
}
|
||||
};
|
||||
|
||||
#ifndef NDEBUG
|
||||
struct Point_on_merge
|
||||
{
|
||||
template <class Attribute>
|
||||
void operator() (Attribute& a1,const Attribute& a2) const
|
||||
{
|
||||
CGAL_assertion(a1.point()==a2.point() );
|
||||
CGAL_USE(a1); CGAL_USE(a2);
|
||||
}
|
||||
};
|
||||
#endif
|
||||
|
||||
|
||||
template < class Refs, class T, class Point_,
|
||||
class Functor_on_merge_=CGAL::Null_functor,
|
||||
class Functor_on_split_=CGAL::Null_functor >
|
||||
class My_cell_attribute_with_point :
|
||||
public CGAL::Cell_attribute_without_info<Refs, T, Functor_on_merge_, Functor_on_split_>
|
||||
{
|
||||
Point_ mpoint;
|
||||
public:
|
||||
typedef Point_ Point;
|
||||
typedef Functor_on_merge_ Functor_on_merge;
|
||||
typedef Functor_on_split_ Functor_on_split;
|
||||
|
||||
My_cell_attribute_with_point(){}
|
||||
My_cell_attribute_with_point(const Point& apoint) : mpoint(apoint) {}
|
||||
Point& point() { return mpoint; }
|
||||
const Point& point() const { return mpoint; }
|
||||
|
||||
};
|
||||
|
||||
template <typename Traits_,class Polyhedron>
|
||||
struct Item_with_points_and_volume_info
|
||||
{
|
||||
static const unsigned int dimension = 3;
|
||||
static const unsigned int NB_MARKS = 32;
|
||||
|
||||
template<class CMap>
|
||||
struct Dart_wrapper
|
||||
{
|
||||
typedef Traits_ Traits;
|
||||
typedef typename Traits::FT FT;
|
||||
typedef typename Traits::Point_3 Point;
|
||||
typedef typename Traits::Vector_3 Vector;
|
||||
#ifndef NDEBUG
|
||||
typedef My_cell_attribute_with_point<CMap,CGAL::Tag_true,Point,Point_on_merge> Vertex_attribute;
|
||||
#else
|
||||
typedef My_cell_attribute_with_point<CMap,CGAL::Tag_true,Point> Vertex_attribute;
|
||||
#endif
|
||||
typedef CGAL::Cell_attribute<CMap,Volume_info<Polyhedron>,CGAL::Tag_true,Volume_on_merge > Volume_attribute;
|
||||
typedef CGAL::cpp11::tuple< Vertex_attribute,
|
||||
void,
|
||||
void,
|
||||
Volume_attribute> Attributes;
|
||||
};
|
||||
};
|
||||
|
||||
} } //namespace CGAL::internal_IOP
|
||||
|
||||
#endif //CGAL_INTERNAL_COMBINATORIAL_MAP_FOR_COREFINEMENT_H
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
|
@ -1,83 +0,0 @@
|
|||
// Copyright (c) 2011 GeometryFactory (France).
|
||||
// All rights reserved.
|
||||
//
|
||||
// This file is part of CGAL (www.cgal.org).
|
||||
// You can redistribute it and/or modify it under the terms of the GNU
|
||||
// General Public License as published by the Free Software Foundation,
|
||||
// either version 3 of the License, or (at your option) any later version.
|
||||
//
|
||||
// Licensees holding a valid commercial license may use this file in
|
||||
// accordance with the commercial license agreement provided with the software.
|
||||
//
|
||||
// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
|
||||
// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
|
||||
//
|
||||
// $URL$
|
||||
// $Id$
|
||||
// SPDX-License-Identifier: GPL-3.0+
|
||||
//
|
||||
//
|
||||
// Author(s) : Sebastien Loriot
|
||||
|
||||
#ifndef CGAL_INTERNAL_POLYHEDRON_CONSTNESS_TYPES_H
|
||||
#define CGAL_INTERNAL_POLYHEDRON_CONSTNESS_TYPES_H
|
||||
|
||||
#include <CGAL/license/Polygon_mesh_processing.h>
|
||||
|
||||
|
||||
namespace CGAL {
|
||||
namespace internal_IOP{
|
||||
|
||||
template <class Polyhedron,class T>
|
||||
struct Polyhedron_types;
|
||||
|
||||
template <class Polyhedron>
|
||||
struct Polyhedron_types<Polyhedron,Tag_false>{
|
||||
typedef Polyhedron& Polyhedron_ref;
|
||||
typedef typename Polyhedron::Halfedge_handle Halfedge_handle;
|
||||
typedef typename Polyhedron::Halfedge_iterator Halfedge_iterator;
|
||||
typedef typename Polyhedron::Facet_iterator Facet_iterator;
|
||||
typedef typename Polyhedron::Facet_handle Facet_handle;
|
||||
typedef typename Polyhedron::Vertex_handle Vertex_handle;
|
||||
typedef typename Polyhedron::Vertex Vertex;
|
||||
typedef typename Polyhedron::Halfedge Halfedge;
|
||||
typedef typename Polyhedron::Facet Facet;
|
||||
};
|
||||
|
||||
template <class Polyhedron>
|
||||
struct Polyhedron_types<Polyhedron,Tag_true>{
|
||||
typedef const Polyhedron& Polyhedron_ref;
|
||||
typedef typename Polyhedron::Halfedge_const_handle Halfedge_handle;
|
||||
typedef typename Polyhedron::Halfedge_const_iterator Halfedge_iterator;
|
||||
typedef typename Polyhedron::Facet_const_iterator Facet_iterator;
|
||||
typedef typename Polyhedron::Facet_const_handle Facet_handle;
|
||||
typedef typename Polyhedron::Vertex_const_handle Vertex_handle;
|
||||
typedef const typename Polyhedron::Vertex Vertex;
|
||||
typedef const typename Polyhedron::Halfedge Halfedge;
|
||||
typedef const typename Polyhedron::Facet Facet;
|
||||
};
|
||||
|
||||
#include <boost/type_traits/is_const.hpp>
|
||||
#include <boost/type_traits/remove_const.hpp>
|
||||
#include <boost/mpl/if.hpp>
|
||||
|
||||
template <class Polyhedron_>
|
||||
struct Polyhedron_types_with_mpl
|
||||
{
|
||||
typedef typename boost::remove_const<Polyhedron_>::type Polyhedron;
|
||||
typedef typename boost::mpl::if_< boost::is_const<Polyhedron_>,
|
||||
typename Polyhedron::Face_const_handle,
|
||||
typename Polyhedron::Face_handle>::type Face_handle;
|
||||
typedef typename boost::mpl::if_< boost::is_const<Polyhedron_>,
|
||||
typename Polyhedron::Face_const_iterator,
|
||||
typename Polyhedron::Face_iterator>::type Face_iterator;
|
||||
typedef typename boost::mpl::if_< boost::is_const<Polyhedron_>,
|
||||
typename Polyhedron::Halfedge_const_handle,
|
||||
typename Polyhedron::Halfedge_handle>::type Halfedge_handle;
|
||||
typedef Face_handle Facet_handle;
|
||||
typedef Face_iterator Facet_iterator;
|
||||
};
|
||||
|
||||
} } //namespace CGAL::internal_IOP
|
||||
|
||||
#endif //CGAL_INTERNAL_POLYHEDRON_CONSTNESS_TYPES_H
|
||||
|
|
@ -1,344 +0,0 @@
|
|||
// Copyright (c) 2011, 2015 GeometryFactory (France).
|
||||
// All rights reserved.
|
||||
//
|
||||
// This file is part of CGAL (www.cgal.org).
|
||||
// You can redistribute it and/or modify it under the terms of the GNU
|
||||
// General Public License as published by the Free Software Foundation,
|
||||
// either version 3 of the License, or (at your option) any later version.
|
||||
//
|
||||
// Licensees holding a valid commercial license may use this file in
|
||||
// accordance with the commercial license agreement provided with the software.
|
||||
//
|
||||
// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
|
||||
// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
|
||||
//
|
||||
// $URL$
|
||||
// $Id$
|
||||
// SPDX-License-Identifier: GPL-3.0+
|
||||
//
|
||||
//
|
||||
// Author(s) : Sebastien Loriot and Andreas Fabri
|
||||
|
||||
#ifndef CGAL_INTERNAL_POLYHEDRON_SUBSET_EXTRACTION_H
|
||||
#define CGAL_INTERNAL_POLYHEDRON_SUBSET_EXTRACTION_H
|
||||
|
||||
#include <CGAL/license/Polygon_mesh_processing.h>
|
||||
|
||||
|
||||
#include<set>
|
||||
#include<vector>
|
||||
|
||||
#include <boost/graph/connected_components.hpp>
|
||||
|
||||
#include <CGAL/boost/graph/iterator.h>
|
||||
#include <CGAL/boost/graph/helpers.h>
|
||||
|
||||
#include <CGAL/assertions.h>
|
||||
#include <CGAL/Polyhedron_3.h>
|
||||
#include <CGAL/Polyhedron_incremental_builder_3.h>
|
||||
#include <CGAL/Union_find.h>
|
||||
#include <CGAL/internal/corefinement/Polyhedron_constness_types.h>
|
||||
|
||||
namespace CGAL {
|
||||
namespace internal{
|
||||
namespace corefinement{
|
||||
|
||||
template <typename Polyhedron>
|
||||
struct Compare_handle_ptr{
|
||||
typedef typename Polyhedron::Facet_const_handle Facet_const_handle;
|
||||
typedef typename Polyhedron::Vertex_const_handle Vertex_const_handle;
|
||||
|
||||
bool operator()(Facet_const_handle f1,Facet_const_handle f2) const {
|
||||
return &(*f1) < &(*f2);
|
||||
}
|
||||
|
||||
bool operator()(Vertex_const_handle v1,Vertex_const_handle v2) const {
|
||||
return &(*v1) < &(*v2);
|
||||
}
|
||||
};
|
||||
|
||||
struct Dummy_true{
|
||||
template <typename T>
|
||||
bool operator()(T) const {return true;}
|
||||
};
|
||||
|
||||
template <typename Polyhedron,typename HDS=typename Polyhedron::HalfedgeDS>
|
||||
class Build_polyhedron_subset : public ::CGAL::Modifier_base<HDS> {
|
||||
typedef typename Polyhedron::Facet_const_handle Facet_const_handle;
|
||||
typedef typename Polyhedron::Vertex_const_handle Vertex_const_handle;
|
||||
typedef typename Polyhedron::Halfedge_const_handle Halfedge_const_handle;
|
||||
|
||||
typedef typename HDS::Vertex::Point Point;
|
||||
std::list<Vertex_const_handle> points;
|
||||
std::list< std::vector<unsigned int> > facets;
|
||||
|
||||
template <typename Facet_iterator>
|
||||
typename Polyhedron::Halfedge_const_handle get_facet_halfedge(Facet_iterator facet_it) const
|
||||
{
|
||||
return (*facet_it)->halfedge();
|
||||
}
|
||||
|
||||
typename Polyhedron::Halfedge_const_handle get_facet_halfedge(typename Polyhedron::Facet_const_handle facet) const
|
||||
{
|
||||
return facet->halfedge();
|
||||
}
|
||||
|
||||
public:
|
||||
template <typename Facets_const_iterator>
|
||||
Build_polyhedron_subset(const Polyhedron&,Facets_const_iterator begin,Facets_const_iterator end)
|
||||
{
|
||||
typedef std::map<Vertex_const_handle,unsigned int,Compare_handle_ptr<Polyhedron> > Vertices;
|
||||
Vertices vertices;
|
||||
unsigned int index=0;
|
||||
//get vertices and get face description relatively to the restricted set of vertices
|
||||
for (Facets_const_iterator it=begin;it!=end;++it)
|
||||
{
|
||||
Halfedge_const_handle start=get_facet_halfedge(it);
|
||||
Halfedge_const_handle curr=start;
|
||||
facets.push_back(std::vector<unsigned int>());
|
||||
std::vector<unsigned int>& indices = facets.back();
|
||||
do{
|
||||
bool is_new_vertex;
|
||||
typename Vertices::iterator it_vertex;
|
||||
::CGAL::cpp11::tie(it_vertex,is_new_vertex)=vertices.insert(std::make_pair(curr->vertex(),index));
|
||||
if (is_new_vertex) {
|
||||
++index;
|
||||
points.push_back(curr->vertex());
|
||||
}
|
||||
indices.push_back(it_vertex->second);
|
||||
curr=curr->next();
|
||||
}while(curr!=start);
|
||||
}
|
||||
}
|
||||
|
||||
void operator()( HDS& hds) {
|
||||
::CGAL::Polyhedron_incremental_builder_3<HDS> B( hds, true);
|
||||
B.begin_surface( points.size(), facets.size() );
|
||||
for (typename std::list<Vertex_const_handle>::iterator it=points.begin();it!=points.end();++it)
|
||||
B.add_vertex((*it)->point());
|
||||
for (typename std::list< std::vector<unsigned int> >::iterator
|
||||
it=facets.begin();it!=facets.end();++it)
|
||||
{
|
||||
B.begin_facet();
|
||||
for (std::vector<unsigned int>::iterator it_i=it->begin();it_i!=it->end();++it_i)
|
||||
B.add_vertex_to_facet(*it_i);
|
||||
B.end_facet();
|
||||
}
|
||||
B.end_surface();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
template <typename Polyhedron,typename Adjacency_criterium,typename Face_to_UF_handle_map,typename Result>
|
||||
void extract_connected_components(
|
||||
Polyhedron& P,
|
||||
const Adjacency_criterium& adjacent,
|
||||
CGAL::Union_find<typename internal_IOP::Polyhedron_types_with_mpl<Polyhedron>::Facet_handle>& uf,
|
||||
Face_to_UF_handle_map& map_f2h,
|
||||
Result& result
|
||||
)
|
||||
{
|
||||
typedef typename internal_IOP::Polyhedron_types_with_mpl<Polyhedron>::Facet_handle Facet_handle;
|
||||
typedef typename internal_IOP::Polyhedron_types_with_mpl<Polyhedron>::Facet_iterator Facet_iterator;
|
||||
typedef typename internal_IOP::Polyhedron_types_with_mpl<Polyhedron>::Halfedge_handle Halfedge_handle;
|
||||
typedef ::CGAL::Union_find<Facet_handle> UF;
|
||||
typedef typename UF::handle UF_handle;
|
||||
typedef typename UF::iterator UF_iterator;
|
||||
|
||||
//init union-find: each facet is in its own set
|
||||
for (Facet_iterator it=P.facets_begin();it!=P.facets_end();++it){
|
||||
map_f2h.insert(std::make_pair(it,uf.make_set(it)));
|
||||
}
|
||||
//merge 2 facets if they share a common edge
|
||||
for (Facet_iterator it=P.facets_begin();it!=P.facets_end();++it){
|
||||
Facet_handle facet=it;
|
||||
|
||||
UF_handle current=map_f2h.find(it)->second;
|
||||
std::vector<Halfedge_handle> neighbors;
|
||||
Halfedge_handle hedge=facet->halfedge();
|
||||
do
|
||||
{
|
||||
neighbors.push_back( hedge->opposite() );
|
||||
hedge=hedge->next();
|
||||
}
|
||||
while(hedge!=facet->halfedge());
|
||||
|
||||
std::size_t nb_edges=neighbors.size();
|
||||
for (std::size_t i=0;i<nb_edges;++i){
|
||||
if ( neighbors[i]->is_border() ) continue;
|
||||
UF_handle neigh=map_f2h.find(neighbors[i]->facet())->second;
|
||||
if ( adjacent(neighbors[i]) && !uf.same_set(current,neigh) ){
|
||||
uf.unify_sets(current,neigh);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//recover merged sets
|
||||
for (UF_iterator it=uf.begin();it!=uf.end();++it){
|
||||
UF_handle master=uf.find(it);
|
||||
result[*master].push_back(*it);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Polyhedron,typename Adjacency_criterium,typename Output_iterator>
|
||||
void extract_connected_components(const Polyhedron& P,const Adjacency_criterium& adjacent,Output_iterator out)
|
||||
{
|
||||
typedef typename Polyhedron::Facet_const_handle Facet_const_handle;
|
||||
typedef ::CGAL::Union_find<Facet_const_handle> UF;
|
||||
typedef typename UF::handle UF_handle;
|
||||
typedef std::map<Facet_const_handle,std::list<Facet_const_handle>,Compare_handle_ptr<Polyhedron> > Result;
|
||||
typedef std::map<Facet_const_handle,UF_handle,Compare_handle_ptr<Polyhedron> > Facet_to_handle_map;
|
||||
|
||||
UF uf;
|
||||
Facet_to_handle_map map_f2h;
|
||||
Result result;
|
||||
|
||||
extract_connected_components(P,adjacent,uf,map_f2h,result);
|
||||
|
||||
for (typename Result::iterator it=result.begin();it!=result.end();++it)
|
||||
{
|
||||
typedef std::list<Facet_const_handle> Facets;
|
||||
const Facets& facets=it->second;
|
||||
Polyhedron new_poly;
|
||||
Build_polyhedron_subset<Polyhedron> modifier(new_poly,facets.begin(),facets.end());
|
||||
new_poly.delegate(modifier);
|
||||
*out++=new_poly;
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Polyhedron, typename Adjacency_criterium, typename Face_marker>
|
||||
void mark_connected_components(Polyhedron& P, const Adjacency_criterium& adjacent, Face_marker& face_marker)
|
||||
{
|
||||
typedef typename Polyhedron::Facet_handle Facet_handle;
|
||||
typedef ::CGAL::Union_find<Facet_handle> UF;
|
||||
typedef typename UF::handle UF_handle;
|
||||
typedef std::map<Facet_handle,std::list<Facet_handle>,Compare_handle_ptr<Polyhedron> > Result;
|
||||
typedef std::map<Facet_handle,UF_handle,Compare_handle_ptr<Polyhedron> > Facet_to_handle_map;
|
||||
|
||||
UF uf;
|
||||
Facet_to_handle_map map_f2h;
|
||||
Result result;
|
||||
|
||||
extract_connected_components(P,adjacent,uf,map_f2h,result);
|
||||
|
||||
for (typename Result::iterator it=result.begin();it!=result.end();++it)
|
||||
{
|
||||
face_marker.start_new_connected_component();
|
||||
typedef std::list<Facet_handle> Facets;
|
||||
const Facets& facets=it->second;
|
||||
face_marker.mark(facets.begin(),facets.end());
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Polyhedron, typename Adjacency_criterium, typename Face_marker, typename OutputIterator>
|
||||
OutputIterator
|
||||
mark_connected_components(Polyhedron& P, const Adjacency_criterium& adjacent, Face_marker& face_marker, OutputIterator out)
|
||||
{
|
||||
typedef typename Polyhedron::Facet_handle Facet_handle;
|
||||
typedef ::CGAL::Union_find<Facet_handle> UF;
|
||||
typedef typename UF::handle UF_handle;
|
||||
typedef std::map<Facet_handle,std::list<Facet_handle>,Compare_handle_ptr<Polyhedron> > Result;
|
||||
typedef std::map<Facet_handle,UF_handle,Compare_handle_ptr<Polyhedron> > Facet_to_handle_map;
|
||||
|
||||
UF uf;
|
||||
Facet_to_handle_map map_f2h;
|
||||
Result result;
|
||||
|
||||
extract_connected_components(P,adjacent,uf,map_f2h,result);
|
||||
|
||||
for (typename Result::iterator it=result.begin();it!=result.end();++it)
|
||||
{
|
||||
face_marker.start_new_connected_component();
|
||||
typedef std::list<Facet_handle> Facets;
|
||||
const Facets& facets=it->second;
|
||||
face_marker.mark(facets.begin(),facets.end());
|
||||
*out++=*facets.begin();
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
template <typename Polyhedron,typename Output_iterator>
|
||||
void extract_connected_components(const Polyhedron& P,Output_iterator out)
|
||||
{
|
||||
extract_connected_components(P,Dummy_true(),out);
|
||||
}
|
||||
|
||||
template <typename Polyhedron, typename Polyhedron_facet_index_map>
|
||||
std::size_t
|
||||
init_facet_indices(
|
||||
const Polyhedron& P,
|
||||
Polyhedron_facet_index_map facet_index_map)
|
||||
{
|
||||
//init facet indices
|
||||
std::size_t index=0;
|
||||
for (typename Polyhedron::Facet_const_iterator fit=P.facets_begin(),
|
||||
fit_end=P.facets_end();
|
||||
fit!=fit_end; ++fit)
|
||||
{
|
||||
put(facet_index_map, fit, index++);
|
||||
}
|
||||
return index;
|
||||
}
|
||||
|
||||
// alternative method by propagation
|
||||
template <typename Polyhedron, typename Adjacency_criterium, typename Polyhedron_facet_index_map>
|
||||
std::size_t
|
||||
mark_connected_components_v2(
|
||||
const Polyhedron& P,
|
||||
const Adjacency_criterium& adjacent,
|
||||
Polyhedron_facet_index_map facet_index_map,
|
||||
std::vector<std::size_t>& patch_ids,
|
||||
std::vector<std::size_t>& patch_sizes)
|
||||
{
|
||||
typedef typename Polyhedron::Halfedge_const_handle Halfedge_handle;
|
||||
|
||||
std::size_t max_id=(std::numeric_limits<std::size_t>::max)();
|
||||
patch_ids.clear();
|
||||
patch_ids.resize(P.size_of_facets(), max_id);
|
||||
|
||||
//traversal of the facets to discover connected components
|
||||
std::size_t patch_id=0;
|
||||
for (typename Polyhedron::Facet_const_iterator fit=P.facets_begin(),
|
||||
fit_end=P.facets_end();
|
||||
fit!=fit_end; ++fit)
|
||||
{
|
||||
std::size_t index=get(facet_index_map, fit);
|
||||
if ( patch_ids[index]==max_id )
|
||||
{
|
||||
patch_sizes.push_back(0);
|
||||
patch_ids[index]=patch_id;// set patch id
|
||||
++(patch_sizes.back());
|
||||
std::vector<typename Polyhedron::Halfedge_const_handle> queue;
|
||||
if ( adjacent(fit->halfedge()) )
|
||||
queue.push_back( fit->halfedge()->opposite() );
|
||||
if ( adjacent(fit->halfedge()->next()) )
|
||||
queue.push_back( fit->halfedge()->next()->opposite() );
|
||||
if ( adjacent(fit->halfedge()->next()->next()) )
|
||||
queue.push_back( fit->halfedge()->next()->next()->opposite() );
|
||||
while (!queue.empty())
|
||||
{
|
||||
Halfedge_handle h=queue.back();
|
||||
queue.pop_back();
|
||||
index=get(facet_index_map, h->facet());
|
||||
if ( patch_ids[index]!=max_id ) continue;
|
||||
patch_ids[index]=patch_id;
|
||||
++(patch_sizes.back());
|
||||
if ( adjacent(h->next()) )
|
||||
queue.push_back( h->next()->opposite() );
|
||||
if ( adjacent(h->next()->next()) )
|
||||
queue.push_back( h->next()->next()->opposite() );
|
||||
}
|
||||
++patch_id;
|
||||
}
|
||||
}
|
||||
|
||||
return patch_id;
|
||||
}
|
||||
|
||||
} } // end of namespace internal::corefinement
|
||||
|
||||
|
||||
} // namespace CGAL
|
||||
|
||||
#endif //CGAL_INTERNAL_POLYHEDRON_SUBSET_EXTRACTION_H
|
||||
|
|
@ -1,334 +0,0 @@
|
|||
// Copyright (c) 2011 GeometryFactory (France).
|
||||
// All rights reserved.
|
||||
//
|
||||
// This file is part of CGAL (www.cgal.org).
|
||||
// You can redistribute it and/or modify it under the terms of the GNU
|
||||
// General Public License as published by the Free Software Foundation,
|
||||
// either version 3 of the License, or (at your option) any later version.
|
||||
//
|
||||
// Licensees holding a valid commercial license may use this file in
|
||||
// accordance with the commercial license agreement provided with the software.
|
||||
//
|
||||
// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
|
||||
// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
|
||||
//
|
||||
// $URL$
|
||||
// $Id$
|
||||
// SPDX-License-Identifier: GPL-3.0+
|
||||
//
|
||||
//
|
||||
// Author(s) : Sebastien Loriot
|
||||
|
||||
#ifndef CGAL_INTERNAL_INTERSECTION_COPLANAR_TRIANGLES_3_H
|
||||
#define CGAL_INTERNAL_INTERSECTION_COPLANAR_TRIANGLES_3_H
|
||||
|
||||
#include <CGAL/license/Polygon_mesh_processing.h>
|
||||
|
||||
|
||||
#include <CGAL/internal/corefinement/intersection_triangle_segment_3.h> //for Intersection_type
|
||||
#include <CGAL/Exact_predicates_exact_constructions_kernel.h>
|
||||
#include <CGAL/Cartesian_converter.h>
|
||||
#include <bitset>
|
||||
|
||||
//TODO rename this file when doing proper integration
|
||||
namespace CGAL{
|
||||
namespace internal_IOP{
|
||||
|
||||
|
||||
//intersection point of two coplanar triangles that keeps track of
|
||||
//the location of that point onto the triangles.
|
||||
template <class IK,class Halfedge_handle, class PolyhedronPointPMap>
|
||||
struct Intersection_point_with_info
|
||||
{
|
||||
typedef CGAL::Exact_predicates_exact_constructions_kernel Exact_kernel;
|
||||
typedef IK Input_kernel;
|
||||
typedef CGAL::Cartesian_converter<Input_kernel,Exact_kernel> Converter;
|
||||
|
||||
Intersection_type type_1,type_2; //intersection type for 1st and 2nd facets
|
||||
Halfedge_handle info_1,info_2; //halfedge providing primitive indicated by type_1 and type_2
|
||||
typename Exact_kernel::Point_3 point; //the geometric embedding of the intersection
|
||||
PolyhedronPointPMap ppmap; // extract the point from a vertex. Only needed to be stored in the class for is_valid
|
||||
|
||||
//constructor from a vertex of first triangle initialized inside the second triangle
|
||||
Intersection_point_with_info(Halfedge_handle info1,Halfedge_handle info2, PolyhedronPointPMap ppmap):
|
||||
type_1(VERTEX),type_2(FACET),info_1(info1),info_2(info2),ppmap(ppmap)
|
||||
{
|
||||
Converter converter;
|
||||
point=converter(get(ppmap,info_1->vertex()));
|
||||
}
|
||||
|
||||
//constructor for intersection of edges. prev and curr are two points on an edge of the first facet (preserving the
|
||||
//orientation of the facet). This edge is intersected by info2 from the second facet.
|
||||
//
|
||||
//The rational is the following: we first check whether curr and prev are on the same edge. I so we create
|
||||
//an intersection point between two edges. Otherwise, the point is a vertex of the second facet included into
|
||||
//the first facet.
|
||||
//
|
||||
//(V,F) : point initialy constructed
|
||||
//(V,E) : (V,F) updated by get_orientation_and_update_info_2 (i.e lies on one edge)
|
||||
//(V,V) : (V,E) updated by get_orientation_and_update_info_2 (i.e lies on two edges)
|
||||
//(E,E) : created in the following function when prev and curr lie on the same edge
|
||||
//(E,V) : (E,E) updated by get_orientation_and_update_info_2 (always done as lies on two edges)
|
||||
//(E,F) : impossible
|
||||
//(F,V) : detected when curr and prev and not on the same edge
|
||||
//(F,E) : impossible
|
||||
//(F,F) : impossible
|
||||
//
|
||||
Intersection_point_with_info(Intersection_point_with_info prev,Intersection_point_with_info curr,
|
||||
Halfedge_handle info1,Halfedge_handle info2, PolyhedronPointPMap ppmap):
|
||||
type_2(EDGE),info_2(info2),ppmap(ppmap)
|
||||
{
|
||||
#ifdef CGAL_DEBUG_COPLANAR_TRIANGLE_INTERSECTION
|
||||
std::cout << "prev: "; prev.print_debug();
|
||||
std::cout << "curr: "; curr.print_debug(); std::cout << std::endl;
|
||||
#endif //CGAL_DEBUG_COPLANAR_TRIANGLE_INTERSECTION
|
||||
Converter converter;
|
||||
if (prev.type_1==VERTEX && prev.info_1->next() == curr.info_1){
|
||||
CGAL_assertion(curr.type_1!=FACET);
|
||||
type_1=EDGE;
|
||||
info_1=curr.info_1;
|
||||
}
|
||||
else{
|
||||
if(curr.type_1==VERTEX && prev.info_1 == curr.info_1){
|
||||
CGAL_assertion(prev.type_1!=FACET);
|
||||
type_1=EDGE;
|
||||
info_1=curr.info_1;
|
||||
}
|
||||
else{
|
||||
if (curr.type_1==EDGE && prev.type_1==EDGE && curr.info_1==prev.info_1){
|
||||
type_1=EDGE;
|
||||
info_1=curr.info_1;
|
||||
}
|
||||
else{
|
||||
//curr and prev are not on the same edge of the first facet.
|
||||
//The intersection point to be computed is a VERTEX of the second facet
|
||||
type_1=FACET;
|
||||
info_1=info1;
|
||||
type_2=VERTEX;
|
||||
|
||||
//this is used to select the correct endpoint of the edge of the second facet
|
||||
typename Exact_kernel::Collinear_3 is_collinear = Exact_kernel().collinear_3_object();
|
||||
if ( !is_collinear(prev.point,curr.point,converter(get(ppmap,info_2->vertex()) ) ) ){
|
||||
info_2=info_2->next()->next();
|
||||
CGAL_assertion( is_collinear(prev.point,curr.point,converter(get(ppmap,info_2->vertex())) ) );
|
||||
}
|
||||
point = converter( get(ppmap, info_2->vertex()) );
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//handle degenerate case when two edges overlap
|
||||
//at least one of the two vertex has already been found as a vertex of a facet. Here we set it for the second point
|
||||
if(prev.type_2!=FACET && curr.type_2!=FACET && (prev.type_1==VERTEX || prev.type_2==VERTEX) && (curr.type_1==VERTEX || curr.type_2==VERTEX)){
|
||||
typename Exact_kernel::Collinear_3 is_collinear = Exact_kernel().collinear_3_object();
|
||||
if ( is_collinear(prev.point,curr.point,converter(get(ppmap, info_2->opposite()->vertex())) ) ){
|
||||
info_2=info_2->next()->next();
|
||||
type_2=VERTEX;
|
||||
point = converter( get(ppmap, info_2->vertex()) );
|
||||
return;
|
||||
}
|
||||
if ( is_collinear(prev.point,curr.point,converter(get(ppmap, info_2->vertex())) ) ){
|
||||
type_2=VERTEX;
|
||||
point = converter( get(ppmap, info_2->vertex()) );
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
//handle regular intersection of two edges
|
||||
typename Exact_kernel::Construct_line_3 line_3=Exact_kernel().construct_line_3_object();
|
||||
typename Exact_kernel::Line_3 l1=
|
||||
line_3(converter(get(ppmap, info_2->vertex())),converter(get(ppmap, info_2->opposite()->vertex())));
|
||||
typename Exact_kernel::Line_3 l2=line_3(prev.point,curr.point);
|
||||
CGAL::Object res=Exact_kernel().intersect_3_object()(l1,l2);
|
||||
const typename Exact_kernel::Point_3* ptptr=CGAL::object_cast<typename Exact_kernel::Point_3>(&res);
|
||||
CGAL_assertion(ptptr!=NULL);
|
||||
point=*ptptr;
|
||||
}
|
||||
|
||||
void print_debug() const{
|
||||
std::cout << " (";
|
||||
if (type_1==VERTEX) std::cout << "V";
|
||||
if (type_1==EDGE) std::cout << "E";
|
||||
if (type_1==FACET) std::cout << "F";
|
||||
if (type_1==EMPTY) std::cout << "?";
|
||||
std::cout << "-" << &(*info_1);
|
||||
std::cout << ";";
|
||||
if (type_2==VERTEX) std::cout << "V";
|
||||
if (type_2==EDGE) std::cout << "E";
|
||||
if (type_2==FACET) std::cout << "F";
|
||||
if (type_2==EMPTY) std::cout << "?";
|
||||
std::cout << ")" << "[" << CGAL::to_double(point.x()) << "," << CGAL::to_double(point.y()) << "," << CGAL::to_double(point.z()) << "]";
|
||||
}
|
||||
|
||||
int debug_unique_type_int() const{
|
||||
int res=0;
|
||||
switch (type_1){
|
||||
case VERTEX: res+=1; break;
|
||||
case EDGE: res+=3; break;
|
||||
case FACET: res+=7; break;
|
||||
default: break;
|
||||
}
|
||||
switch (type_2){
|
||||
case VERTEX: res+=1; break;
|
||||
case EDGE: res+=3; break;
|
||||
case FACET: res+=7; break;
|
||||
default: break;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
bool is_valid(Intersection_type type,Halfedge_handle info){
|
||||
bool valid=true;
|
||||
Converter converter;
|
||||
switch (type){
|
||||
case VERTEX: valid&= converter(get(ppmap, info->vertex()))==point; break;
|
||||
case EDGE:{
|
||||
typename Exact_kernel::Segment_3 seg=
|
||||
Exact_kernel().construct_segment_3_object()( converter(get(ppmap,info->vertex())),
|
||||
converter(get(ppmap,info->opposite()->vertex())) );
|
||||
valid&= Exact_kernel().has_on_3_object()(seg,point);
|
||||
}
|
||||
break;
|
||||
case FACET:{
|
||||
typename Exact_kernel::Coplanar_orientation_3 orient=Exact_kernel().coplanar_orientation_3_object();
|
||||
typename Exact_kernel::Point_3 p=converter(get(ppmap,info->vertex()));
|
||||
typename Exact_kernel::Point_3 q=converter(get(ppmap,info->next()->vertex()));
|
||||
typename Exact_kernel::Point_3 r=converter(get(ppmap,info->opposite()->vertex()));
|
||||
valid &= orient(p,q,r,point)==POSITIVE;
|
||||
valid &= orient(q,r,p,point)==POSITIVE;
|
||||
valid &= orient(r,p,q,point)==POSITIVE;
|
||||
}
|
||||
break;
|
||||
default: valid=false;
|
||||
}
|
||||
return valid;
|
||||
}
|
||||
|
||||
bool is_valid(){
|
||||
return is_valid(type_1,info_1) && is_valid(type_2,info_2);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
template<class Halfedge_handle,class Inter_pt, class PolyhedronPointPMap>
|
||||
CGAL::Orientation get_orientation_and_update_info_2(Halfedge_handle h,Inter_pt& p, PolyhedronPointPMap ppmap)
|
||||
{
|
||||
typename Inter_pt::Exact_kernel::Coplanar_orientation_3 orient=
|
||||
typename Inter_pt::Exact_kernel().coplanar_orientation_3_object();
|
||||
typename Inter_pt::Converter converter;
|
||||
|
||||
CGAL::Orientation res = orient(converter(get(ppmap,h->opposite()->vertex())),
|
||||
converter(get(ppmap,h->vertex())),
|
||||
converter(get(ppmap,h->next()->vertex())),
|
||||
p.point);
|
||||
|
||||
if ( (p.type_1==VERTEX || p.type_1==EDGE) && res==COLLINEAR){
|
||||
if (p.type_2==FACET){ //detect a case (VERTEX,EDGE)
|
||||
p.type_2=EDGE;
|
||||
p.info_2=h;
|
||||
}
|
||||
else{
|
||||
//detect a case (VERTEX,VERTEX) or (EDGE,VERTEX)
|
||||
CGAL_assertion(p.type_2==EDGE);
|
||||
p.type_2=VERTEX;
|
||||
if (p.info_2->next()!=h){
|
||||
CGAL_assertion(h->next()==p.info_2);
|
||||
p.info_2=h;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
template <class Facet_handle,class Inter_pt,class PolyhedronPointPMap>
|
||||
void intersection_coplanar_facets_cutoff(Facet_handle f,std::list<Inter_pt>& inter_pts,Facet_handle other,PolyhedronPointPMap ppmap)
|
||||
{
|
||||
#ifdef CGAL_DEBUG_COPLANAR_TRIANGLE_INTERSECTION
|
||||
std::cout << "cutoff: " << f->opposite()->vertex()->point() << " " << f->vertex()->point() << std::endl;
|
||||
#endif //CGAL_DEBUG_COPLANAR_TRIANGLE_INTERSECTION
|
||||
if ( inter_pts.empty() ) return;
|
||||
typedef typename std::list<Inter_pt>::iterator Iterator;
|
||||
|
||||
std::map<Inter_pt*,Orientation> orientations;
|
||||
for (Iterator it=inter_pts.begin();it!=inter_pts.end();++it){
|
||||
#ifdef CGAL_DEBUG_COPLANAR_TRIANGLE_INTERSECTION
|
||||
it->print_debug();
|
||||
#endif //CGAL_DEBUG_COPLANAR_TRIANGLE_INTERSECTION
|
||||
orientations[ &(*it) ]=get_orientation_and_update_info_2(f,*it,ppmap);
|
||||
}
|
||||
#ifdef CGAL_DEBUG_COPLANAR_TRIANGLE_INTERSECTION
|
||||
std::cout << std::endl;
|
||||
#endif //CGAL_DEBUG_COPLANAR_TRIANGLE_INTERSECTION
|
||||
|
||||
int pt_added=0;
|
||||
|
||||
Inter_pt* prev = &(*boost::prior(inter_pts.end()));
|
||||
bool inter_pts_size_g_2 = inter_pts.size() > 2;
|
||||
Iterator stop = inter_pts_size_g_2 ? inter_pts.end() : boost::prior(inter_pts.end());
|
||||
for (Iterator it=inter_pts.begin();it!=stop;++it)
|
||||
{
|
||||
Inter_pt* curr=&(*it);
|
||||
if (!inter_pts_size_g_2) std::swap(prev,curr);
|
||||
Orientation or_prev=orientations[prev],or_curr=orientations[curr];
|
||||
if ( (or_prev==POSITIVE && or_curr==NEGATIVE) || (or_prev==NEGATIVE && or_curr==POSITIVE) )
|
||||
{
|
||||
Iterator it_curr = inter_pts_size_g_2 ? it:boost::next(it);
|
||||
prev=&(* inter_pts.insert( it_curr,Inter_pt(*prev,*curr,other,f,ppmap) ) );
|
||||
orientations[prev]=COLLINEAR;
|
||||
++pt_added;
|
||||
}
|
||||
prev=&(*it);
|
||||
}
|
||||
|
||||
CGAL_kernel_assertion(pt_added<3);
|
||||
Iterator it=inter_pts.begin();
|
||||
std::size_t nb_interpt=inter_pts.size();
|
||||
//this boolean allows to reverse order of intersection points in case there were 3 remaining intersection points
|
||||
//and the point in the middle was removed. In that case the order must be reversed to preserve the orientations
|
||||
//of the last edge:
|
||||
// A---X---B --> AB to be consistent with the other cases this should be BA!
|
||||
// X---B---A --> BA
|
||||
// B---A---X --> BA
|
||||
//
|
||||
bool should_revert_list=false;
|
||||
|
||||
while(it!=inter_pts.end())
|
||||
{
|
||||
if (orientations[&(*it)]==NEGATIVE){
|
||||
inter_pts.erase(it++);
|
||||
if (--nb_interpt == 2 && it!=inter_pts.end() && boost::next(it)==inter_pts.end()) should_revert_list=true;
|
||||
}
|
||||
else
|
||||
++it;
|
||||
}
|
||||
if (should_revert_list && nb_interpt==2) inter_pts.reverse();
|
||||
}
|
||||
|
||||
template <class Input_kernel,class Halfedge_handle,class PolyhedronPointPMap>
|
||||
void
|
||||
intersection_coplanar_facets(
|
||||
Halfedge_handle f1,
|
||||
Halfedge_handle f2,
|
||||
PolyhedronPointPMap ppmap,
|
||||
std::list<Intersection_point_with_info<Input_kernel,Halfedge_handle,PolyhedronPointPMap> >& output )
|
||||
{
|
||||
typedef Intersection_point_with_info<Input_kernel,Halfedge_handle,PolyhedronPointPMap> Inter_pt;
|
||||
output.push_back( Inter_pt(f1,f2,ppmap) );
|
||||
output.push_back( Inter_pt(f1->next(),f2,ppmap) );
|
||||
output.push_back( Inter_pt(f1->next()->next(),f2,ppmap) );
|
||||
|
||||
//intersect f2 with the three half planes which intersection defines f1
|
||||
intersection_coplanar_facets_cutoff(f2,output,f1,ppmap);
|
||||
intersection_coplanar_facets_cutoff(f2->next(),output,f1,ppmap);
|
||||
intersection_coplanar_facets_cutoff(f2->next()->next(),output,f1,ppmap);
|
||||
}
|
||||
|
||||
|
||||
|
||||
} } //namespace CGAL::internal_IOP
|
||||
|
||||
|
||||
#endif //CGAL_INTERNAL_INTERSECTION_COPLANAR_TRIANGLES_3_H
|
||||
|
||||
|
|
@ -1,172 +0,0 @@
|
|||
// Copyright (c) 2011 GeometryFactory (France).
|
||||
// All rights reserved.
|
||||
//
|
||||
// This file is part of CGAL (www.cgal.org).
|
||||
// You can redistribute it and/or modify it under the terms of the GNU
|
||||
// General Public License as published by the Free Software Foundation,
|
||||
// either version 3 of the License, or (at your option) any later version.
|
||||
//
|
||||
// Licensees holding a valid commercial license may use this file in
|
||||
// accordance with the commercial license agreement provided with the software.
|
||||
//
|
||||
// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
|
||||
// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
|
||||
//
|
||||
// $URL$
|
||||
// $Id$
|
||||
// SPDX-License-Identifier: GPL-3.0+
|
||||
//
|
||||
//
|
||||
// Author(s) : Sebastien Loriot
|
||||
|
||||
#ifndef CGAL_INTERNAL_INTERSECTION_TRIANGLE_SEGMENT_3_H
|
||||
#define CGAL_INTERNAL_INTERSECTION_TRIANGLE_SEGMENT_3_H
|
||||
|
||||
#include <CGAL/license/Polygon_mesh_processing.h>
|
||||
|
||||
|
||||
//TODO rename this file when doing proper integration
|
||||
#include <CGAL/internal/corefinement/Polyhedron_constness_types.h>
|
||||
#include <CGAL/internal/Intersections_3/Triangle_3_Segment_3_intersection.h>
|
||||
namespace CGAL{
|
||||
namespace internal_IOP{
|
||||
|
||||
enum Intersection_type {FACET,EDGE,VERTEX,EMPTY,COPLNR};
|
||||
|
||||
|
||||
//define shortcut for intersection result types
|
||||
template <class Polyhedron,class Is_const>
|
||||
struct Intersection_types{
|
||||
typedef typename Polyhedron_types<Polyhedron,Is_const>::Halfedge_handle Intersection_info;
|
||||
typedef cpp11::tuple<Intersection_type,Intersection_info,bool,bool> Intersection_result;
|
||||
};
|
||||
|
||||
|
||||
template<class Polyhedron,class Kernel,class Is_const>
|
||||
typename Intersection_types<Polyhedron,Is_const>::Intersection_result
|
||||
find_intersection(const typename Kernel::Point_3& p, const typename Kernel::Point_3& q,
|
||||
const typename Kernel::Point_3& a, const typename Kernel::Point_3& b, const typename Kernel::Point_3& c,
|
||||
typename Polyhedron_types<Polyhedron,Is_const>::Halfedge_handle /*hh*/,
|
||||
typename Polyhedron_types<Polyhedron,Is_const>::Facet_handle fh,
|
||||
bool is_vertex_coplanar=false,bool is_vertex_opposite_coplanar=false)
|
||||
{
|
||||
typedef typename Intersection_types<Polyhedron,Is_const>::Intersection_info Intersection_info;
|
||||
typedef typename Intersection_types<Polyhedron,Is_const>::Intersection_result Intersection_result;
|
||||
|
||||
Orientation ab=orientation(p,q,a,b);
|
||||
Orientation bc=orientation(p,q,b,c);
|
||||
Orientation ca=orientation(p,q,c,a);
|
||||
|
||||
if ( ab==POSITIVE || bc==POSITIVE || ca==POSITIVE )
|
||||
return Intersection_result(EMPTY,Intersection_info(),false,false);
|
||||
|
||||
int nb_coplanar=(ab==COPLANAR?1:0) + (bc==COPLANAR?1:0) + (ca==COPLANAR?1:0);
|
||||
|
||||
if ( nb_coplanar==0 )
|
||||
return cpp11::make_tuple(FACET,Intersection_info(fh->halfedge()),is_vertex_coplanar,is_vertex_opposite_coplanar);
|
||||
|
||||
if (nb_coplanar==1){
|
||||
if (ab==COPLANAR)
|
||||
return cpp11::make_tuple(EDGE,Intersection_info(fh->halfedge()->next()),is_vertex_coplanar,is_vertex_opposite_coplanar);
|
||||
if (bc==COPLANAR)
|
||||
return cpp11::make_tuple(EDGE,Intersection_info(fh->halfedge()->next()->next()),is_vertex_coplanar,is_vertex_opposite_coplanar);
|
||||
CGAL_assertion(ca==COPLANAR);
|
||||
return cpp11::make_tuple(EDGE,Intersection_info(fh->halfedge()),is_vertex_coplanar,is_vertex_opposite_coplanar);
|
||||
}
|
||||
|
||||
CGAL_assertion(nb_coplanar==2);
|
||||
|
||||
if (ab!=COPLANAR)
|
||||
return cpp11::make_tuple(VERTEX,Intersection_info(fh->halfedge()->next()->next()),is_vertex_coplanar,is_vertex_opposite_coplanar);
|
||||
if (bc!=COPLANAR)
|
||||
return cpp11::make_tuple(VERTEX,Intersection_info(fh->halfedge()),is_vertex_coplanar,is_vertex_opposite_coplanar);
|
||||
CGAL_assertion(ca!=COPLANAR);
|
||||
return cpp11::make_tuple(VERTEX,Intersection_info(fh->halfedge()->next()),is_vertex_coplanar,is_vertex_opposite_coplanar);
|
||||
}
|
||||
|
||||
|
||||
template<class Polyhedron, class Kernel, class Is_const, class PolyhedronPointPmap>
|
||||
typename Intersection_types<Polyhedron,Is_const>::Intersection_result
|
||||
do_intersect(typename Polyhedron_types<Polyhedron,Is_const>::Halfedge_handle hh,
|
||||
typename Polyhedron_types<Polyhedron,Is_const>::Facet_handle fh,
|
||||
PolyhedronPointPmap ppmap)
|
||||
{
|
||||
typedef typename Intersection_types<Polyhedron,Is_const>::Intersection_info Intersection_info;
|
||||
typedef typename Intersection_types<Polyhedron,Is_const>::Intersection_result Intersection_result;
|
||||
|
||||
const typename Kernel::Point_3 & a = get(ppmap, fh->halfedge()->vertex() );
|
||||
const typename Kernel::Point_3 & b = get(ppmap, fh->halfedge()->next()->vertex() );
|
||||
const typename Kernel::Point_3 & c = get(ppmap, fh->halfedge()->next()->next()->vertex() );
|
||||
const typename Kernel::Point_3 & p = get(ppmap, hh->vertex() );
|
||||
const typename Kernel::Point_3 & q = get(ppmap, hh->opposite()->vertex() );
|
||||
|
||||
|
||||
const Orientation abcp = orientation(a,b,c,p);
|
||||
const Orientation abcq = orientation(a,b,c,q);
|
||||
|
||||
|
||||
switch ( abcp ) {
|
||||
case POSITIVE:
|
||||
switch ( abcq ) {
|
||||
case POSITIVE:
|
||||
// the segment lies in the positive open halfspaces defined by the
|
||||
// triangle's supporting plane
|
||||
return Intersection_result(EMPTY,Intersection_info(),false,false);
|
||||
case NEGATIVE:
|
||||
// p sees the triangle in counterclockwise order
|
||||
return find_intersection<Polyhedron,Kernel,Is_const>(p,q,a,b,c,hh,fh);
|
||||
case COPLANAR:
|
||||
// q belongs to the triangle's supporting plane
|
||||
// p sees the triangle in counterclockwise order
|
||||
return find_intersection<Polyhedron,Kernel,Is_const>(p,q,a,b,c,hh,fh,false,true);
|
||||
|
||||
default: // should not happen.
|
||||
CGAL_assertion(false);
|
||||
return Intersection_result(EMPTY,Intersection_info(),false,false);
|
||||
}
|
||||
case NEGATIVE:
|
||||
switch ( abcq ) {
|
||||
case POSITIVE:
|
||||
// q sees the triangle in counterclockwise order
|
||||
return find_intersection<Polyhedron,Kernel,Is_const>(q,p,a,b,c,hh,fh);
|
||||
case NEGATIVE:
|
||||
// the segment lies in the negative open halfspaces defined by the
|
||||
// triangle's supporting plane
|
||||
return Intersection_result(EMPTY,Intersection_info(),false,false);
|
||||
case COPLANAR:
|
||||
// q belongs to the triangle's supporting plane
|
||||
// p sees the triangle in clockwise order
|
||||
return find_intersection<Polyhedron,Kernel,Is_const>(q,p,a,b,c,hh,fh,false,true);
|
||||
default: // should not happen.
|
||||
CGAL_assertion(false);
|
||||
return Intersection_result(EMPTY,Intersection_info(),false,false);
|
||||
}
|
||||
case COPLANAR: // p belongs to the triangle's supporting plane
|
||||
switch ( abcq ) {
|
||||
case POSITIVE:
|
||||
// q sees the triangle in counterclockwise order
|
||||
return find_intersection<Polyhedron,Kernel,Is_const>(q,p,a,b,c,hh,fh,true,false);
|
||||
case NEGATIVE:
|
||||
// q sees the triangle in clockwise order
|
||||
return find_intersection<Polyhedron,Kernel,Is_const>(p,q,a,b,c,hh,fh,true,false);
|
||||
case COPLANAR:
|
||||
// the segment is coplanar with the triangle's supporting plane
|
||||
// we test whether the segment intersects the triangle in the common
|
||||
// supporting plane
|
||||
if ( ::CGAL::internal::do_intersect_coplanar(a,b,c,p,q,Kernel()) )
|
||||
return Intersection_result(COPLNR,Intersection_info(),true,true);
|
||||
return Intersection_result(EMPTY,Intersection_info(),true,true);
|
||||
|
||||
default: // should not happen.
|
||||
CGAL_assertion(false);
|
||||
return Intersection_result(EMPTY,Intersection_info(),false,false);
|
||||
}
|
||||
default: // should not happen.
|
||||
CGAL_assertion(false);
|
||||
return Intersection_result(EMPTY,Intersection_info(),false,false);
|
||||
}
|
||||
}
|
||||
|
||||
}} //namespace CGAL::internal_IOP
|
||||
|
||||
#endif //CGAL_INTERNAL_INTERSECTION_TRIANGLE_SEGMENT_3_H
|
||||
|
|
@ -1,400 +0,0 @@
|
|||
// Copyright (c) 2011 GeometryFactory (France).
|
||||
// All rights reserved.
|
||||
//
|
||||
// This file is part of CGAL (www.cgal.org).
|
||||
// You can redistribute it and/or modify it under the terms of the GNU
|
||||
// General Public License as published by the Free Software Foundation,
|
||||
// either version 3 of the License, or (at your option) any later version.
|
||||
//
|
||||
// Licensees holding a valid commercial license may use this file in
|
||||
// accordance with the commercial license agreement provided with the software.
|
||||
//
|
||||
// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
|
||||
// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
|
||||
//
|
||||
// $URL$
|
||||
// $Id$
|
||||
// SPDX-License-Identifier: GPL-3.0+
|
||||
//
|
||||
//
|
||||
// Author(s) : Sebastien Loriot
|
||||
|
||||
#ifndef CGAL_INTERNAL_INTERSECTION_TRIANGLE_SEGMENT_3_COPLANAR_H
|
||||
#define CGAL_INTERNAL_INTERSECTION_TRIANGLE_SEGMENT_3_COPLANAR_H
|
||||
|
||||
#include <CGAL/license/Polygon_mesh_processing.h>
|
||||
|
||||
|
||||
|
||||
namespace CGAL{
|
||||
namespace internal_IOP{
|
||||
|
||||
//enum Intersection_type {FACET,EDGE,VERTEX,EMPTY,COPLNR};
|
||||
|
||||
template<class Polyhedron,class Is_const>
|
||||
struct Intersection_point_coplanar{
|
||||
typedef typename Polyhedron_types<Polyhedron,Is_const>::Halfedge_handle Halfedge_handle;
|
||||
|
||||
Intersection_type type;
|
||||
Halfedge_handle info;
|
||||
Halfedge_handle segment_vertex;
|
||||
|
||||
Intersection_point_coplanar(){};
|
||||
|
||||
Intersection_point_coplanar(Intersection_type type_,
|
||||
Halfedge_handle info_,
|
||||
Halfedge_handle segment_vertex_
|
||||
) :type(type_),info(info_),segment_vertex(segment_vertex_){}
|
||||
};
|
||||
|
||||
//test q vs segment bc
|
||||
template<class Inter_pt_coplanar,class Halfedge_handle>
|
||||
void point_vs_segment(Inter_pt_coplanar& pt,
|
||||
Halfedge_handle bc, Halfedge_handle ab,
|
||||
const Orientation& pqc, const Orientation& pqb)
|
||||
{
|
||||
if (pqb==COLLINEAR){
|
||||
pt.type=VERTEX;
|
||||
pt.info=ab;
|
||||
}
|
||||
else{
|
||||
if (pqc==COLLINEAR){
|
||||
pt.type=VERTEX;
|
||||
pt.info=bc;
|
||||
}
|
||||
else{
|
||||
pt.type=EDGE;
|
||||
pt.info=bc;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
// c
|
||||
// / \
|
||||
// ___/___\____ with q-------p
|
||||
// / \
|
||||
// a_______b
|
||||
//supporting line of segment pq intersects ac and bc
|
||||
*/
|
||||
|
||||
template<class Inter_pt_coplanar,class Point_3,class Halfedge_handle>
|
||||
std::pair<Inter_pt_coplanar,Inter_pt_coplanar>
|
||||
decision_tree(const Point_3* a,const Point_3* b,const Point_3* c,
|
||||
const Point_3* p,const Point_3* q,
|
||||
const Orientation& pqa,const Orientation& pqb,const Orientation& pqc,
|
||||
Halfedge_handle pq,
|
||||
Halfedge_handle ca,Halfedge_handle ab,Halfedge_handle bc)
|
||||
{
|
||||
CGAL_precondition(pqa!=NEGATIVE);
|
||||
CGAL_precondition(pqb!=NEGATIVE);
|
||||
CGAL_precondition(pqc!=POSITIVE);
|
||||
|
||||
Inter_pt_coplanar pt1(EMPTY,NULL,NULL),pt2(EMPTY,NULL,NULL);
|
||||
|
||||
//the segment supporting line intersects ac and bc
|
||||
const Orientation bcq = coplanar_orientation(*b,*c,*q);
|
||||
switch(bcq){
|
||||
case NEGATIVE: //segment does not intersect the triangle
|
||||
return std::make_pair(pt1,pt2);
|
||||
case COLLINEAR: //q \in [bc]
|
||||
point_vs_segment(pt1,bc,ab,pqc,pqb);
|
||||
pt1.segment_vertex=pq;
|
||||
return std::make_pair(pt1,pt2);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
//===> q is to the left of bc
|
||||
|
||||
const Orientation cap = coplanar_orientation(*c,*a,*p);
|
||||
switch(cap){
|
||||
case NEGATIVE: //segment does not intersect the triangle
|
||||
return false;
|
||||
case COLLINEAR: //p \in [ca]
|
||||
point_vs_segment(pt1,ca,bc,pqa,pqc);
|
||||
pt1.segment_vertex=pq->opposite();
|
||||
return std::make_pair(pt1,pt2);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
//===> p is to the right of ac
|
||||
|
||||
|
||||
const Orientation cqa = coplanar_orientation(*c,*q,*a);
|
||||
const Orientation cbp = coplanar_orientation(*c,*b,*p);
|
||||
|
||||
if (pqc==COLLINEAR && cqa==POSITIVE && cbp==POSITIVE){
|
||||
//special case when c is inside the segment pq
|
||||
pt1.type=VERTEX;
|
||||
pt1.info=bc;
|
||||
return std::make_pair(pt1,pt2);
|
||||
}
|
||||
|
||||
//where is located q?
|
||||
switch (cqa){
|
||||
case POSITIVE: //q is outside the triangle
|
||||
point_vs_segment(pt1,ca,bc,pqa,pqc);
|
||||
break;
|
||||
case NEGATIVE: //q is inside the triangle
|
||||
pt1.type=FACET;
|
||||
pt1.info=pq;
|
||||
break;
|
||||
case COLLINEAR: //q \in [ca]
|
||||
point_vs_segment(pt1,ca,bc,pqa,pqc);
|
||||
pt1.segment_vertex=pq;
|
||||
break;
|
||||
}
|
||||
|
||||
//where is located p?
|
||||
switch (cbp){
|
||||
case POSITIVE: //p is outside the triangle
|
||||
point_vs_segment(pt2,bc,ab,pqc,pqb);
|
||||
break;
|
||||
case NEGATIVE: //p is inside the triangle
|
||||
pt2.type=FACET;
|
||||
pt2.info=pq->opposite();
|
||||
break;
|
||||
case COLLINEAR: //p \in [bc]
|
||||
point_vs_segment(pt2,bc,ab,pqc,pqb);
|
||||
pt2.segment_vertex=pq->opposite();
|
||||
break;
|
||||
}
|
||||
return std::make_pair(pt1,pt2);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
// c
|
||||
// / \
|
||||
// / \
|
||||
// / \
|
||||
// ____a_______b______ with q-------p
|
||||
//supporting lines of segments pq and ab are the same.
|
||||
*/
|
||||
|
||||
template<class Inter_pt_coplanar,class Point_3,class Halfedge_handle>
|
||||
std::pair<Inter_pt_coplanar,Inter_pt_coplanar>
|
||||
collinear_decision_tree(const Point_3* a,const Point_3* b,const Point_3* c,
|
||||
const Point_3* p,const Point_3* q,
|
||||
const Orientation& pqa,const Orientation& pqb,const Orientation& pqc,
|
||||
Halfedge_handle pq,
|
||||
Halfedge_handle ca,Halfedge_handle ab,Halfedge_handle bc)
|
||||
{
|
||||
CGAL_precondition(pqa==COLLINEAR);
|
||||
CGAL_precondition(pqb==COLLINEAR);
|
||||
CGAL_precondition(pqc==NEGATIVE);
|
||||
|
||||
Inter_pt_coplanar pt1(EMPTY,NULL,NULL),pt2(EMPTY,NULL,NULL);
|
||||
|
||||
//the segment supporting line intersects ac and bc
|
||||
const Orientation bcq = coplanar_orientation(*b,*c,*q);
|
||||
switch(bcq){
|
||||
case NEGATIVE: //segment does not intersect the triangle
|
||||
return std::make_pair(pt1,pt2);
|
||||
case COLLINEAR: // q = b
|
||||
pt1.type=VERTEX;
|
||||
pt1.info=ab;
|
||||
pt1.segment_vertex=pq;
|
||||
return std::make_pair(pt1,pt2);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
//===> q is to the left of b
|
||||
|
||||
const Orientation cap = coplanar_orientation(*c,*a,*p);
|
||||
switch(cap){
|
||||
case NEGATIVE: //segment does not intersect the triangle
|
||||
return false;
|
||||
case COLLINEAR: //p = a
|
||||
pt1.type=VERTEX;
|
||||
pt1.info=ca;
|
||||
pt1.segment_vertex=pq->opposite();
|
||||
return std::make_pair(pt1,pt2);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
//===> p is to the right of a
|
||||
|
||||
|
||||
const Orientation cqa = coplanar_orientation(*c,*q,*a);
|
||||
const Orientation cbp = coplanar_orientation(*c,*b,*p);
|
||||
|
||||
//where is located q?
|
||||
switch (cqa){
|
||||
case POSITIVE: //q is to the left of a
|
||||
pt1.type=VERTEX;
|
||||
pt1.info=ca;
|
||||
break;
|
||||
case NEGATIVE: //q is to the right of a
|
||||
pt1.type=EDGE;
|
||||
pt1.info=ab;
|
||||
pt1.segment_vertex=pq;
|
||||
break;
|
||||
case COLLINEAR: //q = a
|
||||
pt1.type=VERTEX;
|
||||
pt1.info=ca;
|
||||
pt1.segment_vertex=pq;
|
||||
break;
|
||||
}
|
||||
|
||||
//where is located p?
|
||||
switch (cbp){
|
||||
case POSITIVE: //p is to the right of b
|
||||
{
|
||||
pt2.type=VERTEX;
|
||||
pt2.info=ab;
|
||||
}
|
||||
break;
|
||||
case NEGATIVE: //p is to the left of b
|
||||
{
|
||||
pt2.type=EDGE;
|
||||
pt2.info=ab;
|
||||
pt2.segment_vertex=pq->opposite();
|
||||
}
|
||||
break;
|
||||
case COLLINEAR: //p = b
|
||||
pt2.type=VERTEX;
|
||||
pt2.info=ab;
|
||||
pt2.segment_vertex=pq->opposite();
|
||||
break;
|
||||
}
|
||||
|
||||
return std::make_pair(pt1,pt2);
|
||||
}
|
||||
|
||||
//std::pair<Intersection_point_coplanar<Polyhedron,Is_const>,Intersection_point_coplanar<Polyhedron,Is_const> >
|
||||
template<class Polyhedron,class Kernel,class Is_const>
|
||||
std::pair<Intersection_point_coplanar<Polyhedron,Is_const>,Intersection_point_coplanar<Polyhedron,Is_const> >
|
||||
do_intersect_coplanar(typename Polyhedron_types<Polyhedron,Is_const>::Halfedge_handle pq,
|
||||
typename Polyhedron_types<Polyhedron,Is_const>::Face_handle fh)
|
||||
{
|
||||
typedef Intersection_point_coplanar<Polyhedron,Is_const> Inter_pt_coplanar;
|
||||
typedef std::pair<Inter_pt_coplanar,Inter_pt_coplanar> Return_type;
|
||||
|
||||
|
||||
typedef typename Polyhedron_types<Polyhedron,Is_const>::Halfedge_handle Halfedge_handle;
|
||||
|
||||
const typename Kernel::Point_3 & A = fh->halfedge()->vertex()->point();
|
||||
const typename Kernel::Point_3 & B = fh->halfedge()->next()->vertex()->point();
|
||||
const typename Kernel::Point_3 & C = fh->halfedge()->next()->next()->vertex()->point();
|
||||
const typename Kernel::Point_3 & P = pq->vertex()->point();
|
||||
const typename Kernel::Point_3 & Q = pq->opposite()->vertex()->point();
|
||||
|
||||
const typename Kernel::Point_3 * a = &A;
|
||||
const typename Kernel::Point_3 * b = &B;
|
||||
const typename Kernel::Point_3 * c = &C;
|
||||
|
||||
const typename Kernel::Point_3* p = &P;
|
||||
const typename Kernel::Point_3* q = &Q;
|
||||
|
||||
Halfedge_handle ca=fh->halfedge();
|
||||
Halfedge_handle ab=fh->halfedge()->next();
|
||||
Halfedge_handle bc=fh->halfedge()->next()->next();
|
||||
|
||||
|
||||
// Determine the orientation of the triangle in the common plane
|
||||
|
||||
if (coplanar_orientation(A,B,C) != POSITIVE){
|
||||
// The triangle is not counterclockwise oriented swap two vertices.
|
||||
b = &C;
|
||||
c = &B;
|
||||
std::swap(bc,ab);
|
||||
}
|
||||
|
||||
// Test whether the segment's supporting line intersects the
|
||||
// triangle in the common plane
|
||||
|
||||
Orientation pqa = coplanar_orientation(*p,*q,*a);
|
||||
|
||||
//ensure pqa >= 0
|
||||
if (pqa == NEGATIVE){
|
||||
std::swap(p,q);
|
||||
pqa=POSITIVE;
|
||||
pq=pq->opposite();
|
||||
}
|
||||
|
||||
const Orientation pqb = coplanar_orientation(*p,*q,*b);
|
||||
const Orientation pqc = coplanar_orientation(*p,*q,*c);
|
||||
|
||||
|
||||
|
||||
//Handle first case pq collinear with a triangle edge
|
||||
if (pqa == COLLINEAR){
|
||||
if (pqb == COLLINEAR){
|
||||
//ab and pq are on the same line
|
||||
if (pqc == NEGATIVE)
|
||||
return collinear_decision_tree<Inter_pt_coplanar>
|
||||
(a,b,c,p,q,pqa,pqb,pqc,pq,ca,ab,bc);
|
||||
else
|
||||
return collinear_decision_tree<Inter_pt_coplanar>
|
||||
(a,b,c,q,p,pqa,pqb,NEGATIVE,pq->opposite(),ca,ab,bc);
|
||||
}
|
||||
if (pqc == COLLINEAR){
|
||||
//ac and pq are on the same line
|
||||
if (pqb == NEGATIVE)
|
||||
return collinear_decision_tree<Inter_pt_coplanar>
|
||||
(c,a,b,p,q,pqc,pqa,pqb,pq,bc,ca,ab);
|
||||
else
|
||||
return collinear_decision_tree<Inter_pt_coplanar>
|
||||
(c,a,b,q,p,pqc,pqa,NEGATIVE,pq->opposite(),bc,ca,ab);
|
||||
}
|
||||
}
|
||||
else
|
||||
if(pqb ==COLLINEAR && pqc == COLLINEAR){
|
||||
//bc and pq are on the same line
|
||||
return collinear_decision_tree<Inter_pt_coplanar>
|
||||
(b,c,a,q,p,pqb,pqc,NEGATIVE,pq->opposite(),ab,bc,ca);
|
||||
}
|
||||
|
||||
|
||||
CGAL_assertion(pqa!=NEGATIVE);
|
||||
|
||||
switch ( pqa ) {
|
||||
case POSITIVE:
|
||||
switch ( pqb ) {
|
||||
case POSITIVE:
|
||||
if (pqc == POSITIVE)
|
||||
return std::make_pair(Inter_pt_coplanar(EMPTY,NULL,NULL),Inter_pt_coplanar(EMPTY,NULL,NULL));
|
||||
return decision_tree<Inter_pt_coplanar>(a,b,c,p,q,pqa,pqb,pqc,pq,ca,ab,bc);
|
||||
|
||||
case COLLINEAR:
|
||||
case NEGATIVE:
|
||||
if (pqc == POSITIVE) // b is isolated on the negative side
|
||||
return decision_tree<Inter_pt_coplanar>(c,a,b,p,q,pqc,pqa,pqb,pq,bc,ca,ab);
|
||||
return decision_tree<Inter_pt_coplanar>
|
||||
(b,c,a,q,p,POSITIVE,opposite(pqc),NEGATIVE,pq->opposite(),ab,bc,ca);
|
||||
default:// should not happen.
|
||||
CGAL_assertion(false);
|
||||
return std::make_pair(Inter_pt_coplanar(EMPTY,NULL,NULL),Inter_pt_coplanar(EMPTY,NULL,NULL));
|
||||
}
|
||||
case COLLINEAR:
|
||||
switch ( pqb ) {
|
||||
case POSITIVE:
|
||||
if (pqc == POSITIVE) // a is isolated on the negative side
|
||||
return decision_tree<Inter_pt_coplanar>(b,c,a,p,q,pqb,pqc,pqa,pq,ab,bc,ca);
|
||||
return decision_tree<Inter_pt_coplanar>(a,b,c,p,q,pqa,pqb,pqc,pq,ca,ab,bc);
|
||||
|
||||
case NEGATIVE:
|
||||
if (pqc == NEGATIVE) // a is isolated on the positive side
|
||||
return decision_tree<Inter_pt_coplanar>
|
||||
(b,c,a,q,p,POSITIVE,POSITIVE,pqa,pq->opposite(),ab,bc,ca);
|
||||
return decision_tree<Inter_pt_coplanar>(c,a,b,p,q,pqc,pqa,pqb,pq,bc,ca,ab);
|
||||
|
||||
default:// should not happen.
|
||||
CGAL_assertion(false);
|
||||
return std::make_pair(Inter_pt_coplanar(EMPTY,NULL,NULL),Inter_pt_coplanar(EMPTY,NULL,NULL));
|
||||
}
|
||||
default:// should not happen.
|
||||
CGAL_assertion(false);
|
||||
return std::make_pair(Inter_pt_coplanar(EMPTY,NULL,NULL),Inter_pt_coplanar(EMPTY,NULL,NULL));
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}}//namespace CGAL::internal_IOP
|
||||
|
||||
#endif //CGAL_INTERNAL_INTERSECTION_TRIANGLE_SEGMENT_3_COPLANAR_H
|
||||
|
|
@ -1,131 +0,0 @@
|
|||
// Copyright (c) 2011 GeometryFactory (France).
|
||||
// All rights reserved.
|
||||
//
|
||||
// This file is part of CGAL (www.cgal.org).
|
||||
// You can redistribute it and/or modify it under the terms of the GNU
|
||||
// General Public License as published by the Free Software Foundation,
|
||||
// either version 3 of the License, or (at your option) any later version.
|
||||
//
|
||||
// Licensees holding a valid commercial license may use this file in
|
||||
// accordance with the commercial license agreement provided with the software.
|
||||
//
|
||||
// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
|
||||
// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
|
||||
//
|
||||
// $URL$
|
||||
// $Id$
|
||||
// SPDX-License-Identifier: GPL-3.0+
|
||||
//
|
||||
//
|
||||
// Author(s) : Sebastien Loriot
|
||||
|
||||
#ifndef CGAL_INTERNAL_COREFINEMENT_PREDICATES_H
|
||||
#define CGAL_INTERNAL_COREFINEMENT_PREDICATES_H
|
||||
|
||||
#include <CGAL/license/Polygon_mesh_processing.h>
|
||||
|
||||
|
||||
namespace CGAL{
|
||||
|
||||
namespace Corefinement{
|
||||
|
||||
namespace OOP{
|
||||
//Considering the plane with normal vector [O_prime,O] and containing O.
|
||||
//We define the counterclockwise order around O when looking from
|
||||
//the side of the plane into which the vector [O_prime,O] is pointing.
|
||||
//We consider the portion of the plane defined by rotating a ray starting at O
|
||||
//from the planar projection of P1 to the planar projection of P2 in
|
||||
//counterclockwise order.
|
||||
//The predicates indicates whether the planar projection of point Q lies in this
|
||||
//portion of the plane.
|
||||
//Preconditions:
|
||||
// O_prime,O,P1 are not collinear
|
||||
// O_prime,O,P2 are not collinear
|
||||
// O_prime,O,Q are not collinear
|
||||
// O_prime,O,P1,Q are not coplanar or coplanar_orientation(O,O_prime,P1,Q)==NEGATIVE
|
||||
// O_prime,O,P2,Q are not coplanar or coplanar_orientation(O,O_prime,P2,Q)==NEGATIVE
|
||||
template <class Kernel>
|
||||
bool sorted_around_edge(
|
||||
const typename Kernel::Point_3& O_prime,const typename Kernel::Point_3& O,
|
||||
const typename Kernel::Point_3& P1,const typename Kernel::Point_3& P2,
|
||||
const typename Kernel::Point_3& Q)
|
||||
{
|
||||
//guarantee to have non-flat triangles
|
||||
CGAL_precondition( !collinear(O_prime,O,P1) );
|
||||
CGAL_precondition( !collinear(O_prime,O,P2) );
|
||||
CGAL_precondition( !collinear(O_prime,O,Q) );
|
||||
|
||||
//no two triangles are coplanar and on the same side of their common edge
|
||||
CGAL_precondition( !coplanar(O_prime,O,P1,Q)
|
||||
|| coplanar_orientation(O,O_prime,P1,Q)==NEGATIVE );
|
||||
CGAL_precondition( !coplanar(O_prime,O,P2,Q)
|
||||
|| coplanar_orientation(O,O_prime,P2,Q)==NEGATIVE );
|
||||
|
||||
Sign s0 = CGAL::sign( determinant(O-O_prime,P1-O,P2-O) );
|
||||
|
||||
if ( s0==ZERO ) {
|
||||
//O, O_prime, P1 and P2 are coplanar
|
||||
Orientation o=orientation(O_prime,O,P1,Q);
|
||||
CGAL_precondition(o!=COPLANAR);
|
||||
return o==POSITIVE;
|
||||
}
|
||||
|
||||
//O, O_prime, P1 and P2 are not coplanar
|
||||
Sign s1 = CGAL::sign( determinant(O-O_prime,P1-O,Q -O) );
|
||||
Sign s2 = CGAL::sign( determinant(O-O_prime,Q -O,P2-O) );
|
||||
|
||||
if (s0 == POSITIVE) // the angle P1,O,P2 is smaller that Pi.
|
||||
return ( s1 == POSITIVE )
|
||||
&& ( s2 ==POSITIVE ); //true if the angles P1,O,Q and Q,O,P2 are smaller than Pi
|
||||
else
|
||||
return ( s1 != NEGATIVE )
|
||||
|| ( s2 !=
|
||||
NEGATIVE ); //true if the angle P1,O,Q or the angle Q,O,P2 is smaller than or equal to Pi
|
||||
}
|
||||
|
||||
template <class PolyhedronPointPMap,class Nodes_vector, class Vertex_handle>
|
||||
bool sorted_around_edge_filtered( int O_prime_index,
|
||||
int O_index,
|
||||
int P1_index,
|
||||
int P2_index,
|
||||
int Q_index,
|
||||
Vertex_handle P1,
|
||||
Vertex_handle P2,
|
||||
Vertex_handle Q,
|
||||
const Nodes_vector& nodes,
|
||||
PolyhedronPointPMap ppmap)
|
||||
{
|
||||
typename Nodes_vector::Protector p;
|
||||
try {
|
||||
CGAL_USE(p);
|
||||
return sorted_around_edge<typename Nodes_vector::Ikernel>(
|
||||
nodes.interval_node(O_prime_index),
|
||||
nodes.interval_node(O_index),
|
||||
P1_index == -1 ? nodes.to_interval(get(ppmap,P1))
|
||||
: nodes.interval_node(P1_index),
|
||||
P2_index == -1 ? nodes.to_interval(get(ppmap,P2))
|
||||
: nodes.interval_node(P2_index),
|
||||
Q_index == -1 ? nodes.to_interval(get(ppmap,Q))
|
||||
: nodes.interval_node(Q_index )
|
||||
);
|
||||
} catch(Uncertain_conversion_exception&) {
|
||||
return sorted_around_edge<typename Nodes_vector::Exact_kernel>(
|
||||
nodes.exact_node(O_prime_index),
|
||||
nodes.exact_node(O_index),
|
||||
P1_index == -1 ? nodes.to_exact(get(ppmap,P1))
|
||||
: nodes.exact_node(P1_index),
|
||||
P2_index == -1 ? nodes.to_exact(get(ppmap,P2))
|
||||
: nodes.exact_node(P2_index),
|
||||
Q_index == -1 ? nodes.to_exact(get(ppmap,Q))
|
||||
: nodes.exact_node(Q_index )
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
} // end of namespace CGAL::Corefinement::OOP
|
||||
|
||||
#endif //CGAL_INTERNAL_COREFINEMENT_PREDICATES_H
|
||||
|
|
@ -1,133 +0,0 @@
|
|||
// Copyright (c) 2011 GeometryFactory (France).
|
||||
// All rights reserved.
|
||||
//
|
||||
// This file is part of CGAL (www.cgal.org).
|
||||
// You can redistribute it and/or modify it under the terms of the GNU
|
||||
// General Public License as published by the Free Software Foundation,
|
||||
// either version 3 of the License, or (at your option) any later version.
|
||||
//
|
||||
// Licensees holding a valid commercial license may use this file in
|
||||
// accordance with the commercial license agreement provided with the software.
|
||||
//
|
||||
// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
|
||||
// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
|
||||
//
|
||||
// $URL$
|
||||
// $Id$
|
||||
// SPDX-License-Identifier: GPL-3.0+
|
||||
//
|
||||
//
|
||||
// Author(s) : Sebastien Loriot
|
||||
|
||||
#ifndef CGAL_INTERNAL_COREFINEMENT_UTILS_H
|
||||
#define CGAL_INTERNAL_COREFINEMENT_UTILS_H
|
||||
|
||||
#include <CGAL/license/Polygon_mesh_processing.h>
|
||||
|
||||
|
||||
namespace CGAL{
|
||||
|
||||
namespace internal_IOP {
|
||||
|
||||
template <class Polyhedron>
|
||||
struct Compare_unik_address{
|
||||
typedef typename Polyhedron::Halfedge_handle Halfedge_handle;
|
||||
typedef typename Polyhedron::Halfedge_const_handle Halfedge_const_handle;
|
||||
typedef typename Polyhedron::Halfedge Halfedge;
|
||||
|
||||
bool operator()(Halfedge_handle h1,Halfedge_handle h2) const {
|
||||
Halfedge* ph1=&(*h1) < &(*h1->opposite()) ? &(*h1) : &(*h1->opposite());
|
||||
Halfedge* ph2=&(*h2) < &(*h2->opposite()) ? &(*h2) : &(*h2->opposite());
|
||||
return ph1 < ph2;
|
||||
}
|
||||
|
||||
bool operator()(Halfedge_const_handle h1,Halfedge_const_handle h2) const {
|
||||
const Halfedge* ph1=&(*h1) < &(*h1->opposite()) ? &(*h1) : &(*h1->opposite());
|
||||
const Halfedge* ph2=&(*h2) < &(*h2->opposite()) ? &(*h2) : &(*h2->opposite());
|
||||
return ph1 < ph2;
|
||||
}
|
||||
};
|
||||
|
||||
template <class Polyhedron>
|
||||
struct Compare_address{
|
||||
typedef typename Polyhedron::Halfedge_handle Halfedge_handle;
|
||||
typedef typename Polyhedron::Halfedge_const_handle Halfedge_const_handle;
|
||||
typedef typename Polyhedron::Halfedge Halfedge;
|
||||
|
||||
bool operator()(Halfedge_handle h1,Halfedge_handle h2) const {
|
||||
return &(*h1) < &(*h2);
|
||||
}
|
||||
|
||||
bool operator()(Halfedge_const_handle h1,Halfedge_const_handle h2) const {
|
||||
return &(*h1) < &(*h2);
|
||||
}
|
||||
};
|
||||
|
||||
template <class Polyhedron>
|
||||
class Non_intersection_halfedge{
|
||||
typedef std::map< typename Polyhedron::Halfedge_const_handle,
|
||||
std::pair<int,int>,
|
||||
Compare_unik_address<Polyhedron>
|
||||
> Intersection_hedges_set;
|
||||
Intersection_hedges_set intersection_hedges_;
|
||||
public:
|
||||
Non_intersection_halfedge(const Intersection_hedges_set& the_set) : intersection_hedges_(the_set){}
|
||||
|
||||
|
||||
bool operator()(typename Polyhedron::Halfedge_const_handle h) const
|
||||
{
|
||||
if (h->is_border_edge()) return false;
|
||||
return intersection_hedges_.find(h)==intersection_hedges_.end();
|
||||
}
|
||||
};
|
||||
|
||||
} //end of namespace internal_IOP
|
||||
|
||||
namespace Corefinement{
|
||||
|
||||
template<class Polyhedron>
|
||||
struct Dummy_edge_mark_property_map{
|
||||
typedef bool value_type;
|
||||
typedef value_type reference;
|
||||
typedef std::pair<typename Polyhedron::Halfedge_handle,Polyhedron*> key_type;
|
||||
typedef boost::read_write_property_map_tag category;
|
||||
|
||||
Dummy_edge_mark_property_map(){}
|
||||
|
||||
friend reference get(Dummy_edge_mark_property_map,key_type) {return false;}
|
||||
friend void put(Dummy_edge_mark_property_map,key_type,value_type) {}
|
||||
};
|
||||
|
||||
|
||||
template <class Halfedge_const_handle, class Border_halfedges_map>
|
||||
int node_index_of_incident_vertex(Halfedge_const_handle h,
|
||||
const Border_halfedges_map& border_halfedges)
|
||||
{
|
||||
//WARNING this may be expensive
|
||||
Halfedge_const_handle start=h;
|
||||
Halfedge_const_handle curr=start;
|
||||
do {
|
||||
typename Border_halfedges_map::const_iterator it_border =
|
||||
border_halfedges.find(curr );
|
||||
if (it_border!=border_halfedges.end())
|
||||
return it_border->first==curr?it_border->second.second
|
||||
:it_border->second.first;
|
||||
curr=curr->next()->opposite();
|
||||
} while(curr!=start);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
template <class Vertex_handle, class Vertex_to_node_id>
|
||||
int get_node_id(Vertex_handle vh,
|
||||
const Vertex_to_node_id& vertex_to_node_id)
|
||||
{
|
||||
typename Vertex_to_node_id::const_iterator it=vertex_to_node_id.find(vh);
|
||||
if (it==vertex_to_node_id.end())
|
||||
return -1;
|
||||
return it->second;
|
||||
}
|
||||
|
||||
} } //end of namespace CGAL::Corefinement
|
||||
|
||||
#endif // CGAL_INTERNAL_COREFINEMENT_UTILS_H
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
|
@ -1,2 +0,0 @@
|
|||
GeometryFactory
|
||||
INRIA Sophia-Antipolis
|
||||
|
|
@ -1,3 +0,0 @@
|
|||
Package gathering non-documented functionalities used in a polyhedron demo plugin
|
||||
and some other packages. At some point, we might decide to document them properly.
|
||||
|
||||
|
|
@ -1 +0,0 @@
|
|||
GPL (v3 or later)
|
||||
|
|
@ -1 +0,0 @@
|
|||
Sébastien Loriot <sebastien.loriot@cgal.org>
|
||||
|
|
@ -1,26 +0,0 @@
|
|||
#ifndef _RANDOM_
|
||||
#define _RANDOM_ 1
|
||||
|
||||
inline
|
||||
double random_double(const double min, const double max)
|
||||
{
|
||||
double range = max - min;
|
||||
return min + (double(rand()) / double(RAND_MAX)) * range;
|
||||
}
|
||||
|
||||
inline
|
||||
int random_int(const int min, const int max)
|
||||
{
|
||||
int range = max - min;
|
||||
return min + int((double(rand())/double(RAND_MAX)) * range);
|
||||
}
|
||||
|
||||
template <class Vector>
|
||||
Vector random_vec(const double scale)
|
||||
{
|
||||
double dx = random_double(-scale, scale);
|
||||
double dy = random_double(-scale, scale);
|
||||
return Vector(dx, dy);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
@ -18,7 +18,7 @@
|
|||
#define cimg_display 0 // To avoid X11 or Windows-GDI dependency
|
||||
#include <CImg.h>
|
||||
#endif
|
||||
#include "random.h"
|
||||
#include <CGAL/Random.h>
|
||||
#include <utility> // std::pair
|
||||
#include <vector>
|
||||
#include <CGAL/property_map.h>
|
||||
|
|
@ -104,7 +104,17 @@ private:
|
|||
double m_bbox_x;
|
||||
double m_bbox_y;
|
||||
double m_bbox_size;
|
||||
|
||||
|
||||
//Random
|
||||
CGAL::Random random;
|
||||
|
||||
template <class Vector>
|
||||
Vector random_vec(const double scale)
|
||||
{
|
||||
double dx = random.get_double(-scale, scale);
|
||||
double dy = random.get_double(-scale, scale);
|
||||
return Vector(dx, dy);
|
||||
}
|
||||
|
||||
public:
|
||||
Scene() {
|
||||
|
|
@ -523,7 +533,7 @@ public:
|
|||
|
||||
std::vector<Sample_>::iterator it;
|
||||
for (it = m_samples.begin(); it != m_samples.end(); it++) {
|
||||
const double rd = random_double(0.0, 1.0);
|
||||
const double rd = random.get_double(0.0, 1.0);
|
||||
if (rd >= percentage)
|
||||
selected.push_back(*it);
|
||||
}
|
||||
|
|
@ -542,7 +552,7 @@ public:
|
|||
Sample_& s = *it;
|
||||
|
||||
samples.push_back(&s);
|
||||
FT rv = random_double(0.0, 1.0);
|
||||
FT rv = random.get_double(0.0, 1.0);
|
||||
if (rv <= percentage)
|
||||
vertices.push_back(&s);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -781,6 +781,13 @@ void regularize_planes (const PointRange& points,
|
|||
|
||||
/// \cond SKIP_IN_MANUAL
|
||||
|
||||
// Workaround for bug reported here:
|
||||
// https://developercommunity.visualstudio.com/content/problem/340310/unaccepted-typename-that-other-compilers-require.html
|
||||
#if _MSC_VER == 1915
|
||||
#define CGAL_TYPENAME_FOR_MSC
|
||||
#else
|
||||
#define CGAL_TYPENAME_FOR_MSC typename
|
||||
#endif
|
||||
|
||||
// This variant deduces the kernel from the point property map.
|
||||
template <typename PointRange,
|
||||
|
|
@ -802,16 +809,17 @@ void regularize_planes (const PointRange& points,
|
|||
typename Kernel_traits
|
||||
<typename boost::property_traits
|
||||
<PointMap>::value_type>::Kernel::Vector_3 symmetry_direction
|
||||
= typename Kernel_traits
|
||||
= CGAL_TYPENAME_FOR_MSC Kernel_traits
|
||||
<typename boost::property_traits
|
||||
<PointMap>::value_type>::Kernel::Vector_3
|
||||
(typename Kernel_traits
|
||||
(
|
||||
CGAL_TYPENAME_FOR_MSC Kernel_traits
|
||||
<typename boost::property_traits
|
||||
<PointMap>::value_type>::Kernel::FT(0.),
|
||||
typename Kernel_traits
|
||||
CGAL_TYPENAME_FOR_MSC Kernel_traits
|
||||
<typename boost::property_traits
|
||||
<PointMap>::value_type>::Kernel::FT(0.),
|
||||
typename Kernel_traits
|
||||
CGAL_TYPENAME_FOR_MSC Kernel_traits
|
||||
<typename boost::property_traits
|
||||
<PointMap>::value_type>::Kernel::FT(1.)))
|
||||
{
|
||||
|
|
@ -824,6 +832,10 @@ void regularize_planes (const PointRange& points,
|
|||
tolerance_angle, tolerance_coplanarity, symmetry_direction);
|
||||
}
|
||||
|
||||
#ifdef CGAL_TYPENAME_FOR_MSC
|
||||
#undef CGAL_TYPENAME_FOR_MSC
|
||||
#endif
|
||||
|
||||
|
||||
/// \endcond
|
||||
|
||||
|
|
|
|||
|
|
@ -49,7 +49,7 @@ configure()
|
|||
{
|
||||
echo "Configuring... "
|
||||
|
||||
if eval 'cmake --no-warn-unused-cli "$CMAKE_GENERATOR" -DRUNNING_CGAL_AUTO_TEST=TRUE \
|
||||
if eval 'cmake --no-warn-unused-cli ${INIT_FILE:+"-C${INIT_FILE}"} "$CMAKE_GENERATOR" -DRUNNING_CGAL_AUTO_TEST=TRUE \
|
||||
-DCGAL_DIR="$CGAL_DIR" \
|
||||
.' ; then
|
||||
|
||||
|
|
|
|||
|
|
@ -49,7 +49,7 @@ configure()
|
|||
{
|
||||
echo "Configuring... "
|
||||
|
||||
if eval 'cmake --no-warn-unused-cli "$CMAKE_GENERATOR" -DRUNNING_CGAL_AUTO_TEST=TRUE \
|
||||
if eval 'cmake --no-warn-unused-cli ${INIT_FILE:+"-C${INIT_FILE}"} "$CMAKE_GENERATOR" -DRUNNING_CGAL_AUTO_TEST=TRUE \
|
||||
-DCGAL_DIR="$CGAL_DIR" \
|
||||
.' ; then
|
||||
|
||||
|
|
|
|||
|
|
@ -337,7 +337,7 @@ of a mesh independently.\n
|
|||
Parameter used to pass a visitor class to a function. Its type and behavior depend on the visited function.
|
||||
\n
|
||||
\b Type : `A class` \n
|
||||
\b Default Specific to the function visited
|
||||
\b Default : Specific to the function visited
|
||||
\cgalNPEnd
|
||||
|
||||
\cgalNPBegin{throw_on_self_intersection} \anchor PMP_throw_on_self_intersection
|
||||
|
|
@ -364,6 +364,12 @@ should be considered as part of the clipping volume or not.
|
|||
\b Default value is `true`
|
||||
\cgalNPEnd
|
||||
|
||||
\cgalNPBegin{output_iterator} \anchor PMP_output_iterator
|
||||
Parameter to pass an output iterator.
|
||||
\n
|
||||
\b Type : a model of `OutputIterator` \n
|
||||
\b Default : `Emptyset_iterator`
|
||||
\cgalNPEnd
|
||||
|
||||
\cgalNPTableEnd
|
||||
|
||||
|
|
|
|||
|
|
@ -113,19 +113,29 @@ and provides a list of the parameters that are used in this package.
|
|||
- `CGAL::Polygon_mesh_processing::self_intersections()`
|
||||
- \link PMP_predicates_grp `CGAL::Polygon_mesh_processing::do_intersect()` \endlink
|
||||
- `CGAL::Polygon_mesh_processing::intersecting_meshes()`
|
||||
- `CGAL::Polygon_mesh_processing::is_degenerate_edge()`
|
||||
- `CGAL::Polygon_mesh_processing::degenerate_edges()`
|
||||
- `CGAL::Polygon_mesh_processing::is_degenerate_triangle_face()`
|
||||
- `CGAL::Polygon_mesh_processing::degenerate_faces()`
|
||||
- `CGAL::Polygon_mesh_processing::is_needle_triangle_face()`
|
||||
- `CGAL::Polygon_mesh_processing::is_cap_triangle_face()`
|
||||
|
||||
## Orientation Functions ##
|
||||
- `CGAL::Polygon_mesh_processing::is_outward_oriented()`
|
||||
- `CGAL::Polygon_mesh_processing::reverse_face_orientations()`
|
||||
- `CGAL::Polygon_mesh_processing::orient_polygon_soup()`
|
||||
- `CGAL::Polygon_mesh_processing::orient()`
|
||||
- `CGAL::Polygon_mesh_processing::orient_to_bound_a_volume()`
|
||||
- `CGAL::Polygon_mesh_processing::is_outward_oriented()`
|
||||
- `CGAL::Polygon_mesh_processing::reverse_face_orientations()`
|
||||
|
||||
## Combinatorial Repairing Functions ##
|
||||
- \link PMP_repairing_grp `CGAL::Polygon_mesh_processing::stitch_borders()` \endlink
|
||||
- `CGAL::Polygon_mesh_processing::is_polygon_soup_a_polygon_mesh()`
|
||||
- `CGAL::Polygon_mesh_processing::polygon_soup_to_polygon_mesh()`
|
||||
- `CGAL::Polygon_mesh_processing::remove_isolated_vertices()`
|
||||
- `CGAL::Polygon_mesh_processing::is_non_manifold_vertex()`
|
||||
- `CGAL::Polygon_mesh_processing::duplicate_non_manifold_vertices()`
|
||||
- `CGAL::Polygon_mesh_processing::merge_duplicated_vertices_in_boundary_cycle()`
|
||||
- `CGAL::Polygon_mesh_processing::merge_duplicated_vertices_in_boundary_cycles()`
|
||||
|
||||
## Normal Computation Functions ##
|
||||
- `CGAL::Polygon_mesh_processing::compute_face_normal()`
|
||||
|
|
@ -179,6 +189,7 @@ and provides a list of the parameters that are used in this package.
|
|||
- `CGAL::Polygon_mesh_processing::edge_bbox()`
|
||||
- `CGAL::Polygon_mesh_processing::face_bbox()`
|
||||
- `CGAL::Polygon_mesh_processing::border_halfedges()`
|
||||
- `CGAL::Polygon_mesh_processing::extract_boundary_cycles()`
|
||||
- `CGAL::Polygon_mesh_processing::transform()`
|
||||
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -43,14 +43,14 @@ meshes, refinement, optimization by fairing, and isotropic remeshing of triangul
|
|||
- \ref Coref_section : methods to corefine triangle meshes and to compute
|
||||
boolean operations out of corefined closed triangle meshes.
|
||||
- \ref PMPHoleFilling : available hole filling algorithms, which can possibly be combined with refinement and fairing.
|
||||
- \ref PMPPredicates : predicates that can be evaluated on the processed polygon
|
||||
- \ref PMPPredicates : predicates that can be evaluated on the processed polygon.
|
||||
mesh, which includes point location and self intersection tests.
|
||||
- \ref PMPOrientation : checking or fixing the \ref PMPOrientation of a polygon soup.
|
||||
- \ref PMPRepairing : reparation of polygon meshes and polygon soups.
|
||||
- \ref PMPOrientation : checking or fixing the orientation of a polygon soup.
|
||||
- \ref PMPRepairing : repair of polygon meshes and polygon soups.
|
||||
- \ref PMPNormalComp : normal computation at vertices and on faces of a polygon mesh.
|
||||
- \ref PMPSlicer : functor able to compute the intersections of a polygon mesh with arbitrary planes (slicer).
|
||||
- \ref PMPConnectedComponents : methods to deal with connected
|
||||
components of a polygon mesh (extraction, marks, removal, ...)
|
||||
components of a polygon mesh (extraction, marks, removal, ...).
|
||||
|
||||
****************************************
|
||||
\section PMPMeshing Meshing
|
||||
|
|
@ -309,7 +309,7 @@ This package provides an algorithm for filling one closed hole that is either in
|
|||
or defined by a sequence of points that describe a polyline.
|
||||
The main steps of the algorithm are described in \cgalCite{liepa2003filling} and can be summarized as follows.
|
||||
|
||||
First, the largest patch triangulating the boundary of the hole is generated without introducing any new vertex.
|
||||
First, the largest patch triangulating the boundary of the hole is generated without introducing any new vertex.
|
||||
The patch is selected so as to minimize a quality function evaluated for all possible triangular patches.
|
||||
The quality function first minimizes the worst dihedral angle between patch triangles,
|
||||
then the total surface area of the patch as a tiebreaker.
|
||||
|
|
@ -335,10 +335,10 @@ From left to right: (a) the hole,
|
|||
\subsection HoleFillingAPI API
|
||||
|
||||
This package provides four functions for hole filling:
|
||||
- `triangulate_hole_polyline()` : given a sequence of points defining the hole, triangulates the hole.
|
||||
- `triangulate_hole()` : given a border halfedge on the boundary of the hole on a mesh, triangulates the hole.
|
||||
- `triangulate_and_refine_hole()` : in addition to `triangulate_hole()` the generated patch is refined.
|
||||
- `triangulate_refine_and_fair_hole()` : in addition to `triangulate_and_refine_hole()` the generated patch is also faired.
|
||||
- `triangulate_hole_polyline()` : given a sequence of points defining the hole, triangulates the hole.
|
||||
- `triangulate_hole()` : given a border halfedge on the boundary of the hole on a mesh, triangulates the hole.
|
||||
- `triangulate_and_refine_hole()` : in addition to `triangulate_hole()` the generated patch is refined.
|
||||
- `triangulate_refine_and_fair_hole()` : in addition to `triangulate_and_refine_hole()` the generated patch is also faired.
|
||||
|
||||
\subsection HFExamples Examples
|
||||
|
||||
|
|
@ -372,51 +372,65 @@ iteratively filled, refined and faired to get a faired mesh with no hole.
|
|||
The hole filling algorithm has a complexity which depends on the
|
||||
number of vertices. While \cgalCite{liepa2003filling} has a running
|
||||
time of \f$ O(n^3)\f$ , \cgalCite{zou2013algorithm} in most cases has
|
||||
running time of \f$ O(n \log n)\f$. We were running
|
||||
`triangulate_refine_and_fair_hole()` for the below meshes (and two
|
||||
more meshes with smaller holes). The machine used is a PC running
|
||||
Windows 10 with an Intel Core i7 CPU clocked at 2.70 GHz.
|
||||
The program has been compiled with Visual C++ 2013 compiler with the O2
|
||||
option which maximizes speed.
|
||||
running time of \f$ O(n \log n)\f$. We benchmarked the function
|
||||
`triangulate_refine_and_fair_hole()` for the two meshes below (as well as two
|
||||
more meshes with smaller holes). The machine used was a PC running
|
||||
Windows 10 with an Intel Core i7 CPU clocked at 2.70 GHz.
|
||||
The program was compiled with the Visual C++ 2013 compiler with the O2
|
||||
option, which maximizes speed.
|
||||
|
||||
\cgalFigureBegin{Elephants, elephants-with-holes.png}
|
||||
The elephant on the left/right has a hole with 963/7657 vertices.
|
||||
\cgalFigureEnd
|
||||
|
||||
This takes time
|
||||
The following running times were observed:
|
||||
|
||||
<center>
|
||||
| # vertices | without Delaunay (sec.) | with Delaunay (sec.)|
|
||||
| ----: | ----: | ----: |
|
||||
| ----: | ----: | ----: |
|
||||
565 | 8.5 | 0.03 |
|
||||
774 | 21 | 0.035 |
|
||||
967 | 43 | 0.06 |
|
||||
7657 | na | 0.4 |
|
||||
|
||||
</center>
|
||||
|
||||
***************************************
|
||||
\section PMPPredicates Predicates
|
||||
|
||||
This packages provides several predicates to be evaluated with respect to a triangle mesh.
|
||||
|
||||
\subsection PMPSelIntersections Self Intersections
|
||||
\subsection PMPDoIntersect Intersections Detection
|
||||
Intersection tests between triangle meshes and/or polylines can be done using
|
||||
\link PMP_predicates_grp `CGAL::Polygon_mesh_processing::do_intersect()` \endlink.
|
||||
Additionally, the function `CGAL::Polygon_mesh_processing::intersecting_meshes()`
|
||||
records all pairs of intersecting meshes in a range.
|
||||
|
||||
Self intersections can be detected from a triangle mesh, by calling the predicate
|
||||
\subsubsection PMPSelIntersections Self Intersections
|
||||
|
||||
Self intersections within a triangle mesh can be detected by calling the function
|
||||
`CGAL::Polygon_mesh_processing::does_self_intersect()`.
|
||||
Additionally, the function `CGAL::Polygon_mesh_processing::self_intersections()`
|
||||
reports all pairs of intersecting triangles.
|
||||
|
||||
\cgalFigureBegin{SelfIntersections, selfintersections.jpg}
|
||||
Detecting self-intersections on a triangle mesh.
|
||||
The intersecting triangles are displayed in dark grey on the right image.
|
||||
\cgalFigureEnd
|
||||
|
||||
\subsubsection SIExample Self Intersections Example
|
||||
|
||||
The following example illustrates the detection of self intersection in the `pig.off` mesh.
|
||||
The detected self-intersection is illustrated on Figure \cgalFigureRef{SelfIntersections}.
|
||||
|
||||
\cgalExample{Polygon_mesh_processing/self_intersections_example.cpp}
|
||||
|
||||
\cgalFigureAnchor{SelfIntersections}
|
||||
<center>
|
||||
<img src="selfintersections.jpg" style="max-width:70%;"/>
|
||||
</center>
|
||||
\cgalFigureCaptionBegin{SelfIntersections}
|
||||
Detecting self-intersections on a triangle mesh.
|
||||
The intersecting triangles are displayed in dark grey and red on the right image.
|
||||
\cgalFigureCaptionEnd
|
||||
|
||||
\subsection PMPInsideTest Side of Triangle Mesh
|
||||
|
||||
The class `CGAL::Side_of_triangle_mesh` provides a functor that tests whether a query point is
|
||||
The class `CGAL::Side_of_triangle_mesh` provides a functor that tests whether a query point is
|
||||
inside, outside, or on the boundary of the domain bounded by a given closed triangle mesh.
|
||||
|
||||
A point is said to be on the bounded side of the domain bounded by the input triangle mesh
|
||||
|
|
@ -435,39 +449,88 @@ input triangle mesh.
|
|||
\subsubsection InsideExample Inside Test Example
|
||||
\cgalExample{Polygon_mesh_processing/point_inside_example.cpp}
|
||||
|
||||
\subsection PMPDoIntersect Intersections Detection
|
||||
Intersection tests between triangle meshes and/or polylines can be done using
|
||||
\link PMP_predicates_grp `CGAL::Polygon_mesh_processing::do_intersect()` \endlink.
|
||||
Additionally, the function `CGAL::Polygon_mesh_processing::intersecting_meshes()`
|
||||
records all pairs of intersecting meshes in a range.
|
||||
\subsection PMPShapePredicates Shape Predicates
|
||||
|
||||
Badly shaped or, even worse, completely degenerate elements of a polygon mesh are problematic
|
||||
in many algorithms which one might want to use on the mesh.
|
||||
This package offers a toolkit of functions to detect such undesirable elements.
|
||||
- `CGAL::Polygon_mesh_processing::is_degenerate_edge()`, to detect if an edge is degenerate
|
||||
(that is, if its two vertices share the same geometric location).
|
||||
- `CGAL::Polygon_mesh_processing::is_degenerate_triangle_face()`, to detect if a face is
|
||||
degenerate (that is, if its three vertices are collinear).
|
||||
- `CGAL::Polygon_mesh_processing::degenerate_edges()`, to collect degenerate edges within a range of edges.
|
||||
- `CGAL::Polygon_mesh_processing::degenerate_faces()`, to collect degenerate faces within a range of faces.
|
||||
- `CGAL::Polygon_mesh_processing::is_cap_triangle_face()`
|
||||
- `CGAL::Polygon_mesh_processing::is_needle_triangle_face()`
|
||||
|
||||
****************************************
|
||||
\section PMPOrientation Orientation
|
||||
|
||||
This package offers multiple functions to compute consistent face orientations for set of faces
|
||||
(Section \ref PolygonSoups) and polygon meshes (Section \ref OrientingPolygonMeshes).
|
||||
Section \ref PolygonSoupExample offers an example of combination of these functions.
|
||||
|
||||
\subsection PolygonSoups Polygon Soups
|
||||
|
||||
When the faces of a polygon mesh are given but the connectivity is unknown,
|
||||
this set of faces is called a \e polygon \e soup.
|
||||
|
||||
Before running any of the algorithms on a polygon soup,
|
||||
one should ensure that the polygons are consistently oriented.
|
||||
To do so, this package provides the function
|
||||
`CGAL::Polygon_mesh_processing::orient_polygon_soup()`,
|
||||
described in \cgalCite{gueziec2001cutting}.
|
||||
|
||||
To deal with polygon soups that cannot be converted to a
|
||||
combinatorially manifold surface, some points must be duplicated.
|
||||
Because a polygon soup does not have any connectivity (each point
|
||||
has as many occurences as the number of polygons it belongs to),
|
||||
duplicating one point (or a pair of points)
|
||||
amounts to duplicating the polygon to which it belongs.
|
||||
The duplicated points are either an endpoint of an edge incident to more
|
||||
than two polygons, an endpoint of an edge between
|
||||
two polygons with incompatible orientations (during the re-orientation process),
|
||||
or more generally a point \a p at which the intersection
|
||||
of an infinitesimally small ball centered at \a p
|
||||
with the polygons incident to it is not a topological disk.
|
||||
|
||||
Once the polygon soup is consistently oriented,
|
||||
with possibly duplicated (or more) points,
|
||||
the connectivity can be recovered and made consistent
|
||||
to build a valid polygon mesh.
|
||||
The function `CGAL::Polygon_mesh_processing::polygon_soup_to_polygon_mesh()`
|
||||
performs this mesh construction step.
|
||||
|
||||
\subsection OrientingPolygonMeshes Polygon Meshes
|
||||
|
||||
This package provides functions dealing with the orientation of faces in a closed polygon mesh.
|
||||
|
||||
The function `CGAL::Polygon_mesh_processing::is_outward_oriented()` checks whether
|
||||
- The function `CGAL::Polygon_mesh_processing::orient()` makes each connected component
|
||||
of a closed polygon mesh outward- or inward-oriented.
|
||||
- The function `CGAL::Polygon_mesh_processing::orient_to_bound_a_volume()` orients
|
||||
the connected components of a closed polygon mesh so that it bounds a volume
|
||||
(see \ref coref_def_subsec for the precise definition).
|
||||
- The function `CGAL::Polygon_mesh_processing::is_outward_oriented()` checks whether
|
||||
an oriented polygon mesh is oriented such that the normals to all faces are oriented towards the
|
||||
outside of the domain bounded by the input polygon mesh.
|
||||
|
||||
The function
|
||||
`CGAL::Polygon_mesh_processing::reverse_face_orientations()` reverses the orientation
|
||||
- The function `CGAL::Polygon_mesh_processing::reverse_face_orientations()` reverses the orientation
|
||||
of halfedges around faces.
|
||||
As a consequence, the normal computed for each face (see Section
|
||||
\ref PMPNormalComp) is also reversed.
|
||||
|
||||
The \ref PolygonSoupExample puts these functions at work on a polygon soup.
|
||||
\subsection PolygonSoupExample Orientation Example
|
||||
|
||||
The function `CGAL::Polygon_mesh_processing::orient()` makes each connected component
|
||||
of a closed polygon mesh outward or inward oriented.
|
||||
|
||||
The function `CGAL::Polygon_mesh_processing::orient_to_bound_a_volume()` orients
|
||||
the connected components of a closed polygon mesh so that it bounds a volume
|
||||
(see \ref coref_def_subsec for the precise definition).
|
||||
This example shows how to generate a mesh from a polygon soup.
|
||||
The first step is to get a soup of consistently oriented faces, before
|
||||
rebuilding the connectivity.
|
||||
In this example, some orientation tests are performed on the output
|
||||
polygon mesh to illustrate
|
||||
Section \ref PMPOrientation.
|
||||
|
||||
\cgalExample{Polygon_mesh_processing/orient_polygon_soup_example.cpp}
|
||||
|
||||
****************************************
|
||||
\section PMPRepairing Combinatorial Repairing
|
||||
\section PMPRepairing Combinatorial Repairing
|
||||
*******************
|
||||
\subsection Stitching
|
||||
|
||||
|
|
@ -490,16 +553,14 @@ with duplicated border edges.
|
|||
|
||||
\cgalExample{Polygon_mesh_processing/stitch_borders_example.cpp}
|
||||
|
||||
*******************
|
||||
\if READY_TO_PUBLISH
|
||||
|
||||
\subsection DegenerateFaces Removing Degenerate Faces
|
||||
|
||||
Some degenerate faces may be part of a given triangle mesh.
|
||||
A face is considered \e degenerate if two of its vertices
|
||||
share the same location,
|
||||
or in general if its three vertices are collinear.
|
||||
The function
|
||||
`CGAL::Polygon_mesh_processing::remove_degenerate_faces()`
|
||||
share the same location, or more generally if its three vertices are collinear.
|
||||
The function `CGAL::Polygon_mesh_processing::remove_degenerate_faces()`
|
||||
removes those faces and fixes the connectivity of the newly cleaned up mesh.
|
||||
It is also possible to remove isolated vertices from any polygon mesh, using the function
|
||||
`CGAL::Polygon_mesh_processing::remove_isolated_vertices()`.
|
||||
|
|
@ -512,52 +573,33 @@ is output.
|
|||
|
||||
\cgalExample{Polygon_mesh_processing/remove_degeneracies_example.cpp}
|
||||
\endif
|
||||
*******************
|
||||
\subsection PolygonSoups Polygon Soups
|
||||
|
||||
When the faces of a polygon mesh are given but the connectivity is unknown,
|
||||
we must deal with of a \e polygon \e soup.
|
||||
\subsection PMPManifoldness Polygon Mesh Manifoldness
|
||||
|
||||
Before running any of the algorithms on the so-called
|
||||
polygon soup, one should ensure that the polygons are consistently oriented.
|
||||
To do so, this package provides the function
|
||||
`CGAL::Polygon_mesh_processing::orient_polygon_soup()`,
|
||||
described in \cgalCite{gueziec2001cutting}.
|
||||
Non-manifold vertices can be detected using the function `CGAL::Polygon_mesh_processing::is_non_manifold_vertex()`.
|
||||
The function `CGAL::Polygon_mesh_processing::duplicate_non_manifold_vertices()` can be used
|
||||
to attempt to create a combinatorially manifold surface mesh by splitting any non-manifold vertex
|
||||
into as many vertices as there are manifold sheets at this geometric position.
|
||||
Note however that the mesh will still not be manifold from a geometric
|
||||
point of view, as the positions of the new vertices introduced at a non-manifold vertex are identical
|
||||
to the input non-manifold vertex.
|
||||
|
||||
To deal with polygon soups that cannot be converted to a
|
||||
combinatorial manifold surface, some points are duplicated.
|
||||
Because a polygon soup does not have any connectivity (each point
|
||||
has as many occurrences as the number of polygons it belongs to),
|
||||
duplicating one point (or a pair of points)
|
||||
amounts to duplicate the polygon to which it belongs.
|
||||
\subsubsection FixNMVerticeExample Manifoldness Repair Example
|
||||
|
||||
The duplicated points are either an endpoint of an edge incident to more
|
||||
than two polygons, an endpoint of an edge between
|
||||
two polygons with incompatible orientations (during the re-orientation process),
|
||||
or more generally a point \a p at which the intersection
|
||||
of an infinitesimally small ball centered at \a p
|
||||
with the polygons incident to it is not a topological disk.
|
||||
In the following example, a non-manifold configuration is artifically created and
|
||||
fixed with the help of the functions described above.
|
||||
|
||||
Once the polygon soup is consistently oriented,
|
||||
with possibly duplicated (or more) points,
|
||||
the connectivity can be recovered and made consistent
|
||||
to build a valid polygon mesh.
|
||||
The function `CGAL::Polygon_mesh_processing::polygon_soup_to_polygon_mesh()`
|
||||
performs this mesh construction step.
|
||||
|
||||
|
||||
\subsubsection PolygonSoupExample Polygon Soup Example
|
||||
|
||||
This example shows how to generate a mesh from a polygon soup.
|
||||
The first step is to get a soup of consistently oriented faces, before
|
||||
rebuilding the connectivity.
|
||||
In this example, some orientation tests are performed on the output
|
||||
polygon mesh to illustrate
|
||||
Section \ref PMPOrientation.
|
||||
|
||||
\cgalExample{Polygon_mesh_processing/polygon_soup_example.cpp}
|
||||
\cgalExample{Polygon_mesh_processing/manifoldness_repair_example.cpp}
|
||||
|
||||
\subsection PMPDuplicateVertexBoundaryCycle Duplicated Vertices in Boundary Cycles
|
||||
|
||||
Similarly to the problematic configuration described in the previous section, another issue that can be present
|
||||
in a polygon mesh is the occurrence of a "pinched" hole, that is the configuration where, when
|
||||
starting from a border halfedge and walking the halfedges of this border, a geometric position appears
|
||||
more than once (although, with different vertices) before reaching the initial border halfedge again. The functions
|
||||
`CGAL::Polygon_mesh_processing::merge_duplicated_vertices_in_boundary_cycle()` and
|
||||
`CGAL::Polygon_mesh_processing::merge_duplicated_vertices_in_boundary_cycle()`, which merge
|
||||
vertices at identical positions, can be used to repair this configuration.
|
||||
|
||||
****************************************
|
||||
\section PMPNormalComp Computing Normals
|
||||
|
|
@ -569,7 +611,7 @@ These computations are performed with :
|
|||
- `CGAL::Polygon_mesh_processing::compute_face_normal()`
|
||||
- `CGAL::Polygon_mesh_processing::compute_vertex_normal()`
|
||||
|
||||
We further provide functions to compute all the normals to faces,
|
||||
Furthermore, we provide functions to compute all the normals to faces,
|
||||
or to vertices, or to both :
|
||||
- `CGAL::Polygon_mesh_processing::compute_face_normals()`
|
||||
- `CGAL::Polygon_mesh_processing::compute_vertex_normals()`
|
||||
|
|
@ -577,14 +619,12 @@ or to vertices, or to both :
|
|||
|
||||
Property maps are used to record the computed normals.
|
||||
|
||||
|
||||
\subsection NormalsExample Normals Computation Examples
|
||||
|
||||
Property maps are an API introduced in the boost library, that allows to
|
||||
Property maps are an API introduced in the boost library that allows to
|
||||
associate values to keys. In the following examples we associate
|
||||
a normal vector to each vertex and to each face.
|
||||
|
||||
|
||||
\subsubsection NormalsExampleSM Normals Computation for a Surface Mesh
|
||||
|
||||
The following example illustrates how to
|
||||
|
|
@ -728,7 +768,7 @@ that respectively detect the sharp edges, compute the patch indices, and give ea
|
|||
|
||||
\subsection DetectFeaturesExample Feature Detection Example
|
||||
In the following example, we count how many edges of `pmesh` are incident to two faces
|
||||
which normals form an angle smaller than 90 degrees,
|
||||
whose normals form an angle smaller than 90 degrees,
|
||||
and the number of surface patches that are separated by these edges.
|
||||
|
||||
\cgalExample{Polygon_mesh_processing/detect_features_example.cpp}
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@
|
|||
\example Polygon_mesh_processing/triangulate_faces_example.cpp
|
||||
\example Polygon_mesh_processing/connected_components_example.cpp
|
||||
\example Polygon_mesh_processing/face_filtered_graph_example.cpp
|
||||
\example Polygon_mesh_processing/polygon_soup_example.cpp
|
||||
\example Polygon_mesh_processing/orient_polygon_soup_example.cpp
|
||||
\example Polygon_mesh_processing/triangulate_polyline_example.cpp
|
||||
\example Polygon_mesh_processing/refine_fair_example.cpp
|
||||
\example Polygon_mesh_processing/mesh_slicer_example.cpp
|
||||
|
|
@ -21,4 +21,5 @@
|
|||
\example Polygon_mesh_processing/corefinement_mesh_union_and_intersection.cpp
|
||||
\example Polygon_mesh_processing/corefinement_consecutive_bool_op.cpp
|
||||
\example Polygon_mesh_processing/detect_features_example.cpp
|
||||
\example Polygon_mesh_processing/manifoldness_repair_example.cpp
|
||||
*/
|
||||
|
|
|
|||
Binary file not shown.
|
Before Width: | Height: | Size: 44 KiB After Width: | Height: | Size: 186 KiB |
|
|
@ -86,7 +86,7 @@ create_single_source_cgal_program( "point_inside_example.cpp")
|
|||
create_single_source_cgal_program( "triangulate_faces_example.cpp")
|
||||
create_single_source_cgal_program( "connected_components_example.cpp")
|
||||
create_single_source_cgal_program( "face_filtered_graph_example.cpp")
|
||||
create_single_source_cgal_program( "polygon_soup_example.cpp")
|
||||
create_single_source_cgal_program( "orient_polygon_soup_example.cpp")
|
||||
create_single_source_cgal_program( "triangulate_polyline_example.cpp")
|
||||
create_single_source_cgal_program( "mesh_slicer_example.cpp")
|
||||
#create_single_source_cgal_program( "remove_degeneracies_example.cpp")
|
||||
|
|
@ -104,6 +104,7 @@ create_single_source_cgal_program( "random_perturbation_SM_example.cpp" )
|
|||
create_single_source_cgal_program( "corefinement_LCC.cpp")
|
||||
create_single_source_cgal_program( "hole_filling_example_LCC.cpp" )
|
||||
create_single_source_cgal_program( "detect_features_example.cpp" )
|
||||
create_single_source_cgal_program( "manifoldness_repair_example.cpp" )
|
||||
|
||||
if(OpenMesh_FOUND)
|
||||
create_single_source_cgal_program( "compute_normals_example_OM.cpp" )
|
||||
|
|
|
|||
|
|
@ -0,0 +1,82 @@
|
|||
#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
|
||||
|
||||
#include <CGAL/boost/graph/iterator.h>
|
||||
#include <CGAL/Polygon_mesh_processing/repair.h>
|
||||
#include <CGAL/Surface_mesh.h>
|
||||
#include <CGAL/IO/OFF_reader.h>
|
||||
|
||||
#include <boost/foreach.hpp>
|
||||
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <iterator>
|
||||
#include <vector>
|
||||
|
||||
namespace PMP = CGAL::Polygon_mesh_processing;
|
||||
namespace NP = CGAL::parameters;
|
||||
|
||||
typedef CGAL::Exact_predicates_inexact_constructions_kernel K;
|
||||
typedef CGAL::Surface_mesh<K::Point_3> Mesh;
|
||||
|
||||
typedef boost::graph_traits<Mesh>::vertex_descriptor vertex_descriptor;
|
||||
typedef boost::graph_traits<Mesh>::halfedge_descriptor halfedge_descriptor;
|
||||
|
||||
void merge_vertices(vertex_descriptor v_keep, vertex_descriptor v_rm, Mesh& mesh)
|
||||
{
|
||||
std::cout << "merging vertices " << v_keep << " and " << v_rm << std::endl;
|
||||
|
||||
BOOST_FOREACH(halfedge_descriptor h, CGAL::halfedges_around_target(v_rm, mesh)){
|
||||
set_target(h, v_keep, mesh); // to ensure that no halfedge points at the deleted vertex
|
||||
}
|
||||
|
||||
remove_vertex(v_rm, mesh);
|
||||
}
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
const char* filename = (argc > 1) ? argv[1] : "data/blobby.off";
|
||||
std::ifstream input(filename);
|
||||
|
||||
Mesh mesh;
|
||||
if(!input || !(input >> mesh) || num_vertices(mesh) == 0)
|
||||
{
|
||||
std::cerr << filename << " is not a valid off file.\n";
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
// Artificially create non-manifoldness for the sake of the example by merging some vertices
|
||||
vertex_descriptor v0 = *(vertices(mesh).begin());
|
||||
vertex_descriptor v1 = *(--(vertices(mesh).end()));
|
||||
merge_vertices(v0, v1, mesh);
|
||||
|
||||
// Count non manifold vertices
|
||||
int counter = 0;
|
||||
BOOST_FOREACH(vertex_descriptor v, vertices(mesh))
|
||||
{
|
||||
if(PMP::is_non_manifold_vertex(v, mesh))
|
||||
{
|
||||
std::cout << "vertex " << v << " is non-manifold" << std::endl;
|
||||
++counter;
|
||||
}
|
||||
}
|
||||
|
||||
std::cout << counter << " non-manifold occurrence(s)" << std::endl;
|
||||
|
||||
// Fix manifoldness by splitting non-manifold vertices
|
||||
std::vector<std::vector<vertex_descriptor> > duplicated_vertices;
|
||||
std::size_t new_vertices_nb = PMP::duplicate_non_manifold_vertices(mesh,
|
||||
NP::output_iterator(
|
||||
std::back_inserter(duplicated_vertices)));
|
||||
|
||||
std::cout << new_vertices_nb << " vertices have been added to fix mesh manifoldness" << std::endl;
|
||||
|
||||
for(std::size_t i=0; i<duplicated_vertices.size(); ++i)
|
||||
{
|
||||
std::cout << "Non-manifold vertex " << duplicated_vertices[i].front() << " was fixed by creating";
|
||||
for(std::size_t j=1; j<duplicated_vertices[i].size(); ++j)
|
||||
std::cout << " " << duplicated_vertices[i][j];
|
||||
std::cout << std::endl;
|
||||
}
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
|
@ -1,34 +1,33 @@
|
|||
#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
|
||||
|
||||
#include <CGAL/Polyhedron_3.h>
|
||||
#include <CGAL/IO/OFF_reader.h>
|
||||
#include <CGAL/Polyhedron_items_with_id_3.h>
|
||||
|
||||
#include <CGAL/Polygon_mesh_processing/orient_polygon_soup.h>
|
||||
#include <CGAL/Polygon_mesh_processing/polygon_soup_to_polygon_mesh.h>
|
||||
#include <CGAL/Polygon_mesh_processing/orientation.h>
|
||||
|
||||
#include <CGAL/IO/OFF_reader.h>
|
||||
|
||||
#include <vector>
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
|
||||
typedef CGAL::Exact_predicates_inexact_constructions_kernel K;
|
||||
typedef CGAL::Polyhedron_3<K> Polyhedron;
|
||||
typedef CGAL::Exact_predicates_inexact_constructions_kernel K;
|
||||
typedef CGAL::Polyhedron_3<K, CGAL::Polyhedron_items_with_id_3> Polyhedron;
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
const char* filename = (argc > 1) ? argv[1] : "data/tet-shuffled.off";
|
||||
std::ifstream input(filename);
|
||||
|
||||
if (!input)
|
||||
std::vector<K::Point_3> points;
|
||||
std::vector<std::vector<std::size_t> > polygons;
|
||||
|
||||
if(!input || !CGAL::read_OFF(input, points, polygons) || points.empty())
|
||||
{
|
||||
std::cerr << "Cannot open file " << std::endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
std::vector<K::Point_3> points;
|
||||
std::vector< std::vector<std::size_t> > polygons;
|
||||
if (!CGAL::read_OFF(input, points, polygons))
|
||||
{
|
||||
std::cerr << "Error parsing the OFF file " << std::endl;
|
||||
return 1;
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
CGAL::Polygon_mesh_processing::orient_polygon_soup(points, polygons);
|
||||
|
|
@ -36,8 +35,13 @@ int main(int argc, char* argv[])
|
|||
Polyhedron mesh;
|
||||
CGAL::Polygon_mesh_processing::polygon_soup_to_polygon_mesh(points, polygons, mesh);
|
||||
|
||||
if (CGAL::is_closed(mesh) && (!CGAL::Polygon_mesh_processing::is_outward_oriented(mesh)))
|
||||
CGAL::Polygon_mesh_processing::reverse_face_orientations(mesh);
|
||||
// Number the faces because 'orient_to_bound_a_volume' needs a face <--> index map
|
||||
int index = 0;
|
||||
for(Polyhedron::Face_iterator fb=mesh.facets_begin(), fe=mesh.facets_end(); fb!=fe; ++fb)
|
||||
fb->id() = index++;
|
||||
|
||||
if(CGAL::is_closed(mesh))
|
||||
CGAL::Polygon_mesh_processing::orient_to_bound_a_volume(mesh);
|
||||
|
||||
std::ofstream out("tet-oriented1.off");
|
||||
out << mesh;
|
||||
|
|
@ -48,5 +52,5 @@ int main(int argc, char* argv[])
|
|||
out2 << mesh;
|
||||
out2.close();
|
||||
|
||||
return 0;
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
|
@ -24,16 +24,16 @@
|
|||
|
||||
#include <CGAL/license/Polygon_mesh_processing/miscellaneous.h>
|
||||
|
||||
#include <CGAL/algorithm.h>
|
||||
#include <CGAL/boost/graph/iterator.h>
|
||||
#include <CGAL/Polygon_mesh_processing/internal/named_function_params.h>
|
||||
#include <CGAL/Polygon_mesh_processing/internal/named_params_helper.h>
|
||||
|
||||
#include <boost/graph/graph_traits.hpp>
|
||||
#include <boost/foreach.hpp>
|
||||
#include <boost/type_traits/is_same.hpp>
|
||||
#include <boost/unordered_set.hpp>
|
||||
|
||||
#include <CGAL/Polygon_mesh_processing/internal/named_function_params.h>
|
||||
#include <CGAL/Polygon_mesh_processing/internal/named_params_helper.h>
|
||||
#include <CGAL/algorithm.h>
|
||||
|
||||
#include <set>
|
||||
|
||||
namespace CGAL{
|
||||
|
|
@ -257,6 +257,38 @@ namespace Polygon_mesh_processing {
|
|||
|
||||
return border_counter;
|
||||
}
|
||||
|
||||
/// @ingroup PkgPolygonMeshProcessing
|
||||
/// extracts boundary cycles as a list of halfedges, with one halfedge per border.
|
||||
///
|
||||
/// @tparam PolygonMesh a model of `HalfedgeListGraph`
|
||||
/// @tparam OutputIterator a model of `OutputIterator` holding objects of type
|
||||
/// `boost::graph_traits<PolygonMesh>::%halfedge_descriptor`
|
||||
///
|
||||
/// @param pm a polygon mesh
|
||||
/// @param out an output iterator where the border halfedges will be put
|
||||
///
|
||||
/// @todo It could make sense to also return the length of each cycle.
|
||||
/// @todo It should probably go into BGL package (like the rest of this file).
|
||||
template <typename PolygonMesh, typename OutputIterator>
|
||||
OutputIterator extract_boundary_cycles(PolygonMesh& pm,
|
||||
OutputIterator out)
|
||||
{
|
||||
typedef typename boost::graph_traits<PolygonMesh>::halfedge_descriptor halfedge_descriptor;
|
||||
|
||||
boost::unordered_set<halfedge_descriptor> hedge_handled;
|
||||
BOOST_FOREACH(halfedge_descriptor h, halfedges(pm))
|
||||
{
|
||||
if(is_border(h, pm) && hedge_handled.insert(h).second)
|
||||
{
|
||||
*out++ = h;
|
||||
BOOST_FOREACH(halfedge_descriptor h2, halfedges_around_face(h, pm))
|
||||
hedge_handled.insert(h2);
|
||||
}
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
} // end of namespace Polygon_mesh_processing
|
||||
} // end of namespace CGAL
|
||||
|
||||
|
|
|
|||
|
|
@ -30,6 +30,7 @@
|
|||
#include <CGAL/Polygon_mesh_processing/repair.h>
|
||||
#include <CGAL/Polygon_mesh_processing/measure.h>
|
||||
#include <CGAL/Polygon_mesh_processing/connected_components.h>
|
||||
#include <CGAL/Polygon_mesh_processing/shape_predicates.h>
|
||||
|
||||
#include <CGAL/AABB_tree.h>
|
||||
#include <CGAL/AABB_traits.h>
|
||||
|
|
@ -90,21 +91,6 @@ namespace internal {
|
|||
};
|
||||
|
||||
// A property map
|
||||
template<typename Descriptor>
|
||||
struct No_constraint_pmap
|
||||
{
|
||||
public:
|
||||
typedef Descriptor key_type;
|
||||
typedef bool value_type;
|
||||
typedef value_type& reference;
|
||||
typedef boost::read_write_property_map_tag category;
|
||||
|
||||
friend bool get(const No_constraint_pmap& , const key_type& ) {
|
||||
return false;
|
||||
}
|
||||
friend void put(No_constraint_pmap& , const key_type& , const bool ) {}
|
||||
};
|
||||
|
||||
template <typename PM, typename FaceIndexMap>
|
||||
struct Border_constraint_pmap
|
||||
{
|
||||
|
|
@ -325,6 +311,7 @@ namespace internal {
|
|||
public:
|
||||
Incremental_remesher(PolygonMesh& pmesh
|
||||
, VertexPointMap& vpmap
|
||||
, const GeomTraits& gt
|
||||
, const bool protect_constraints
|
||||
, EdgeIsConstrainedMap ecmap
|
||||
, VertexIsConstrainedMap vcmap
|
||||
|
|
@ -333,6 +320,7 @@ namespace internal {
|
|||
, const bool build_tree = true)//built by the remesher
|
||||
: mesh_(pmesh)
|
||||
, vpmap_(vpmap)
|
||||
, gt_(gt)
|
||||
, build_tree_(build_tree)
|
||||
, has_border_(false)
|
||||
, input_triangles_()
|
||||
|
|
@ -364,9 +352,10 @@ namespace internal {
|
|||
|
||||
BOOST_FOREACH(face_descriptor f, face_range)
|
||||
{
|
||||
if (is_degenerate_triangle_face(halfedge(f,mesh_),mesh_,vpmap_,GeomTraits())){
|
||||
if(is_degenerate_triangle_face(f, mesh_, parameters::vertex_point_map(vpmap_)
|
||||
.geom_traits(gt_)))
|
||||
continue;
|
||||
}
|
||||
|
||||
Patch_id pid = get_patch_id(f);
|
||||
input_triangles_.push_back(triangle(f));
|
||||
input_patch_ids_.push_back(pid);
|
||||
|
|
@ -828,7 +817,8 @@ namespace internal {
|
|||
debug_status_map();
|
||||
debug_self_intersections();
|
||||
CGAL_assertion(0 == PMP::remove_degenerate_faces(mesh_,
|
||||
PMP::parameters::vertex_point_map(vpmap_).geom_traits(GeomTraits())));
|
||||
parameters::vertex_point_map(vpmap_)
|
||||
.geom_traits(gt_)));
|
||||
#endif
|
||||
}
|
||||
|
||||
|
|
@ -933,7 +923,7 @@ namespace internal {
|
|||
debug_status_map();
|
||||
CGAL_assertion(0 == PMP::remove_degenerate_faces(mesh_
|
||||
, PMP::parameters::vertex_point_map(vpmap_)
|
||||
.geom_traits(GeomTraits())));
|
||||
.geom_traits(gt_)));
|
||||
debug_self_intersections();
|
||||
#endif
|
||||
|
||||
|
|
@ -975,9 +965,9 @@ namespace internal {
|
|||
|
||||
else if (is_on_patch(v))
|
||||
{
|
||||
Vector_3 vn = PMP::compute_vertex_normal(v, mesh_
|
||||
, PMP::parameters::vertex_point_map(vpmap_)
|
||||
.geom_traits(GeomTraits()));
|
||||
Vector_3 vn = PMP::compute_vertex_normal(v, mesh_,
|
||||
parameters::vertex_point_map(vpmap_)
|
||||
.geom_traits(gt_));
|
||||
put(propmap_normals, v, vn);
|
||||
|
||||
Vector_3 move = CGAL::NULL_VECTOR;
|
||||
|
|
@ -1469,20 +1459,8 @@ private:
|
|||
if (f == boost::graph_traits<PM>::null_face())
|
||||
return CGAL::NULL_VECTOR;
|
||||
|
||||
halfedge_descriptor hd = halfedge(f, mesh_);
|
||||
typename boost::property_traits<VertexPointMap>::reference
|
||||
p = get(vpmap_, target(hd, mesh_));
|
||||
hd = next(hd,mesh_);
|
||||
typename boost::property_traits<VertexPointMap>::reference
|
||||
q = get(vpmap_, target(hd, mesh_));
|
||||
hd = next(hd,mesh_);
|
||||
typename boost::property_traits<VertexPointMap>::reference
|
||||
r =get(vpmap_, target(hd, mesh_));
|
||||
|
||||
if (GeomTraits().collinear_3_object()(p,q,r))
|
||||
return CGAL::NULL_VECTOR;
|
||||
else
|
||||
return PMP::compute_face_normal(f, mesh_, parameters::vertex_point_map(vpmap_));
|
||||
return PMP::compute_face_normal(f, mesh_, parameters::vertex_point_map(vpmap_)
|
||||
.geom_traits(gt_));
|
||||
}
|
||||
|
||||
template<typename FaceRange>
|
||||
|
|
@ -1524,7 +1502,7 @@ private:
|
|||
|
||||
// update status using constrained edge map
|
||||
if (!boost::is_same<EdgeIsConstrainedMap,
|
||||
No_constraint_pmap<edge_descriptor> >::value)
|
||||
Constant_property_map<edge_descriptor, bool> >::value)
|
||||
{
|
||||
BOOST_FOREACH(edge_descriptor e, edges(mesh_))
|
||||
{
|
||||
|
|
@ -1598,27 +1576,31 @@ private:
|
|||
const bool collapse_constraints)
|
||||
{
|
||||
CGAL_assertion_code(std::size_t nb_done = 0);
|
||||
|
||||
boost::unordered_set<halfedge_descriptor> degenerate_faces;
|
||||
BOOST_FOREACH(halfedge_descriptor h,
|
||||
halfedges_around_target(halfedge(v, mesh_), mesh_))
|
||||
{
|
||||
if (is_border(h, mesh_))
|
||||
continue;
|
||||
if (is_degenerate_triangle_face(h, mesh_, vpmap_, GeomTraits()))
|
||||
if(!is_border(h, mesh_) &&
|
||||
is_degenerate_triangle_face(face(h, mesh_), mesh_,
|
||||
parameters::vertex_point_map(vpmap_)
|
||||
.geom_traits(gt_)))
|
||||
degenerate_faces.insert(h);
|
||||
}
|
||||
|
||||
while(!degenerate_faces.empty())
|
||||
{
|
||||
halfedge_descriptor h = *(degenerate_faces.begin());
|
||||
degenerate_faces.erase(degenerate_faces.begin());
|
||||
|
||||
if (!is_degenerate_triangle_face(h, mesh_, vpmap_, GeomTraits()))
|
||||
if (!is_degenerate_triangle_face(face(h, mesh_), mesh_,
|
||||
parameters::vertex_point_map(vpmap_)
|
||||
.geom_traits(gt_)))
|
||||
//this can happen when flipping h has consequences further in the mesh
|
||||
continue;
|
||||
|
||||
//check that opposite is not also degenerate
|
||||
if (degenerate_faces.find(opposite(h, mesh_)) != degenerate_faces.end())
|
||||
degenerate_faces.erase(opposite(h, mesh_));
|
||||
degenerate_faces.erase(opposite(h, mesh_));
|
||||
|
||||
if(is_border(h, mesh_))
|
||||
continue;
|
||||
|
|
@ -1664,11 +1646,15 @@ private:
|
|||
short_edges.insert(typename Bimap::value_type(hf, sqlen));
|
||||
}
|
||||
|
||||
if (!is_border(hf, mesh_)
|
||||
&& is_degenerate_triangle_face(hf, mesh_, vpmap_, GeomTraits()))
|
||||
if(!is_border(hf, mesh_) &&
|
||||
is_degenerate_triangle_face(face(hf, mesh_), mesh_,
|
||||
parameters::vertex_point_map(vpmap_)
|
||||
.geom_traits(gt_)))
|
||||
degenerate_faces.insert(hf);
|
||||
if (!is_border(hfo, mesh_)
|
||||
&& is_degenerate_triangle_face(hfo, mesh_, vpmap_, GeomTraits()))
|
||||
if(!is_border(hfo, mesh_) &&
|
||||
is_degenerate_triangle_face(face(hfo, mesh_), mesh_,
|
||||
parameters::vertex_point_map(vpmap_)
|
||||
.geom_traits(gt_)))
|
||||
degenerate_faces.insert(hfo);
|
||||
|
||||
break;
|
||||
|
|
@ -1685,9 +1671,10 @@ private:
|
|||
BOOST_FOREACH(halfedge_descriptor h,
|
||||
halfedges_around_target(he, mesh_))
|
||||
{
|
||||
if (is_border(h, mesh_))
|
||||
continue;
|
||||
if (is_degenerate_triangle_face(h, mesh_, vpmap_, GeomTraits()))
|
||||
if(!is_border(h, mesh_) &&
|
||||
is_degenerate_triangle_face(face(h, mesh_), mesh_,
|
||||
parameters::vertex_point_map(vpmap_)
|
||||
.geom_traits(gt_)))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
|
@ -1828,10 +1815,10 @@ private:
|
|||
{
|
||||
std::cout << "Test self intersections...";
|
||||
std::vector<std::pair<face_descriptor, face_descriptor> > facets;
|
||||
PMP::self_intersections(
|
||||
mesh_,
|
||||
std::back_inserter(facets),
|
||||
PMP::parameters::vertex_point_map(vpmap_));
|
||||
PMP::self_intersections(mesh_,
|
||||
std::back_inserter(facets),
|
||||
PMP::parameters::vertex_point_map(vpmap_)
|
||||
.geom_traits(gt_));
|
||||
//CGAL_assertion(facets.empty());
|
||||
std::cout << "done ("<< facets.size() <<" facets)." << std::endl;
|
||||
}
|
||||
|
|
@ -1840,11 +1827,11 @@ private:
|
|||
{
|
||||
std::cout << "Test self intersections...";
|
||||
std::vector<std::pair<face_descriptor, face_descriptor> > facets;
|
||||
PMP::self_intersections(
|
||||
faces_around_target(halfedge(v, mesh_), mesh_),
|
||||
mesh_,
|
||||
std::back_inserter(facets),
|
||||
PMP::parameters::vertex_point_map(vpmap_));
|
||||
PMP::self_intersections(faces_around_target(halfedge(v, mesh_), mesh_),
|
||||
mesh_,
|
||||
std::back_inserter(facets),
|
||||
PMP::parameters::vertex_point_map(vpmap_)
|
||||
.geom_traits(gt_));
|
||||
//CGAL_assertion(facets.empty());
|
||||
std::cout << "done ("<< facets.size() <<" facets)." << std::endl;
|
||||
}
|
||||
|
|
@ -1926,6 +1913,7 @@ private:
|
|||
private:
|
||||
PolygonMesh& mesh_;
|
||||
VertexPointMap& vpmap_;
|
||||
const GeomTraits& gt_;
|
||||
bool build_tree_;
|
||||
bool has_border_;
|
||||
std::vector<AABB_tree*> trees;
|
||||
|
|
|
|||
|
|
@ -0,0 +1,293 @@
|
|||
// Copyright (c) 2018 GeometryFactory (France).
|
||||
// All rights reserved.
|
||||
//
|
||||
// This file is part of CGAL (www.cgal.org).
|
||||
// You can redistribute it and/or modify it under the terms of the GNU
|
||||
// General Public License as published by the Free Software Foundation,
|
||||
// either version 3 of the License, or (at your option) any later version.
|
||||
//
|
||||
// Licensees holding a valid commercial license may use this file in
|
||||
// accordance with the commercial license agreement provided with the software.
|
||||
//
|
||||
// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
|
||||
// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
|
||||
//
|
||||
// $URL$
|
||||
// $Id$
|
||||
// SPDX-License-Identifier: GPL-3.0+
|
||||
//
|
||||
//
|
||||
// Author(s) : Sebastien Loriot
|
||||
|
||||
#ifndef CGAL_POLYGON_MESH_PROCESSING_MERGE_BORDER_VERTICES_H
|
||||
#define CGAL_POLYGON_MESH_PROCESSING_MERGE_BORDER_VERTICES_H
|
||||
|
||||
#include <CGAL/license/Polygon_mesh_processing/repair.h>
|
||||
|
||||
#include <CGAL/boost/graph/helpers.h>
|
||||
#include <CGAL/boost/graph/properties.h>
|
||||
#include <CGAL/Polygon_mesh_processing/border.h>
|
||||
#include <CGAL/Polygon_mesh_processing/internal/named_function_params.h>
|
||||
#include <CGAL/Polygon_mesh_processing/internal/named_params_helper.h>
|
||||
#include <CGAL/Polygon_mesh_processing/stitch_borders.h>
|
||||
|
||||
#include <boost/unordered_set.hpp>
|
||||
#include <boost/bind.hpp>
|
||||
|
||||
namespace CGAL {
|
||||
|
||||
namespace Polygon_mesh_processing {
|
||||
|
||||
namespace internal {
|
||||
|
||||
template <typename PM, typename VertexPointMap>
|
||||
struct Less_on_point_of_target
|
||||
{
|
||||
typedef typename boost::graph_traits<PM>::halfedge_descriptor
|
||||
halfedge_descriptor;
|
||||
typedef typename boost::property_traits<VertexPointMap>::reference Point;
|
||||
|
||||
Less_on_point_of_target(const PM& pm,
|
||||
const VertexPointMap& vpm)
|
||||
: pm(pm),
|
||||
vpm(vpm)
|
||||
{}
|
||||
|
||||
bool operator()(const std::pair<halfedge_descriptor, std::size_t>& h1,
|
||||
const std::pair<halfedge_descriptor, std::size_t>& h2) const
|
||||
{
|
||||
if ( get(vpm, target(h1.first, pm)) < get(vpm, target(h2.first, pm)) )
|
||||
return true;
|
||||
if ( get(vpm, target(h1.first, pm)) > get(vpm, target(h2.first, pm)) )
|
||||
return false;
|
||||
return h1.second < h2.second;
|
||||
}
|
||||
|
||||
const PM& pm;
|
||||
const VertexPointMap& vpm;
|
||||
};
|
||||
|
||||
|
||||
// warning: cycle_hedges will be altered (sorted)
|
||||
template <class PolygonMesh, class Vpm, class halfedge_descriptor>
|
||||
void detect_identical_mergeable_vertices(
|
||||
std::vector< std::pair<halfedge_descriptor, std::size_t> >& cycle_hedges,
|
||||
std::vector< std::vector<halfedge_descriptor> >& hedges_with_identical_point_target,
|
||||
const PolygonMesh& pm,
|
||||
Vpm vpm)
|
||||
{
|
||||
// sort vertices using their point to ease the detection
|
||||
// of vertices with identical points
|
||||
Less_on_point_of_target<PolygonMesh, Vpm> less(pm, vpm);
|
||||
std::sort( cycle_hedges.begin(), cycle_hedges.end(), less);
|
||||
|
||||
std::size_t nbv=cycle_hedges.size();
|
||||
std::size_t i=1;
|
||||
|
||||
std::set< std::pair<std::size_t, std::size_t> > intervals;
|
||||
|
||||
while(i!=nbv)
|
||||
{
|
||||
if ( get(vpm, target(cycle_hedges[i].first, pm)) ==
|
||||
get(vpm, target(cycle_hedges[i-1].first, pm)) )
|
||||
{
|
||||
hedges_with_identical_point_target.push_back( std::vector<halfedge_descriptor>() );
|
||||
hedges_with_identical_point_target.back().push_back(cycle_hedges[i-1].first);
|
||||
hedges_with_identical_point_target.back().push_back(cycle_hedges[i].first);
|
||||
intervals.insert( std::make_pair(cycle_hedges[i-1].second, cycle_hedges[i].second) );
|
||||
std::size_t previous = cycle_hedges[i].second;
|
||||
while(++i!=nbv)
|
||||
{
|
||||
if ( get(vpm, target(cycle_hedges[i].first, pm)) ==
|
||||
get(vpm, target(cycle_hedges[i-1].first, pm)) )
|
||||
{
|
||||
hedges_with_identical_point_target.back().push_back(cycle_hedges[i].first);
|
||||
intervals.insert( std::make_pair(previous, cycle_hedges[i].second) );
|
||||
previous = cycle_hedges[i].second;
|
||||
}
|
||||
else
|
||||
{
|
||||
++i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
++i;
|
||||
}
|
||||
|
||||
// check that intervals are disjoint or strictly nested
|
||||
// if there is only one issue we drop the whole cycle.
|
||||
/// \todo shall we try to be more conservative?
|
||||
if (hedges_with_identical_point_target.empty()) return;
|
||||
std::set< std::pair<std::size_t, std::size_t> >::iterator it1 = intervals.begin(),
|
||||
end2 = intervals.end(),
|
||||
end1 = cpp11::prev(end2),
|
||||
it2;
|
||||
for (; it1!=end1; ++it1)
|
||||
for(it2=cpp11::next(it1); it2!= end2; ++it2 )
|
||||
{
|
||||
CGAL_assertion(it1->first<it2->first);
|
||||
CGAL_assertion(it1->first < it1->second && it2->first < it2->second);
|
||||
if (it1->second > it2->first && it2->second > it1->second)
|
||||
{
|
||||
std::cerr << "Merging is skipt to avoid bad cycle connections\n";
|
||||
hedges_with_identical_point_target.clear();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// \ingroup PMP_repairing_grp
|
||||
// merges target vertices of a list of halfedges.
|
||||
// Halfedges must be sorted in the list.
|
||||
//
|
||||
// @tparam PolygonMesh a model of `FaceListGraph` and `MutableFaceGraph`.
|
||||
// @tparam HalfedgeRange a range of halfedge descriptors of `PolygonMesh`, model of `Range`.
|
||||
//
|
||||
// @param sorted_hedges a sorted list of halfedges.
|
||||
// @param pm the polygon mesh which contains the list of halfedges.
|
||||
//
|
||||
template <typename PolygonMesh, class HalfedgeRange>
|
||||
void merge_vertices_in_range(const HalfedgeRange& sorted_hedges,
|
||||
PolygonMesh& pm)
|
||||
{
|
||||
typedef typename boost::graph_traits<PolygonMesh>::halfedge_descriptor halfedge_descriptor;
|
||||
typedef typename boost::graph_traits<PolygonMesh>::vertex_descriptor vertex_descriptor;
|
||||
|
||||
halfedge_descriptor in_h_kept = *boost::begin(sorted_hedges);
|
||||
halfedge_descriptor out_h_kept = next(in_h_kept, pm);
|
||||
vertex_descriptor v_kept = target(in_h_kept, pm);
|
||||
|
||||
std::vector<vertex_descriptor> vertices_to_rm;
|
||||
|
||||
BOOST_FOREACH(halfedge_descriptor in_h_rm, sorted_hedges)
|
||||
{
|
||||
vertex_descriptor vd = target(in_h_rm, pm);
|
||||
if (vd==v_kept) continue; // skip identical vertices (in particular this skips the first halfedge)
|
||||
if (edge(vd, v_kept, pm).second) continue; // skip null edges
|
||||
bool shall_continue=false;
|
||||
BOOST_FOREACH(halfedge_descriptor h, halfedges_around_target(v_kept, pm))
|
||||
{
|
||||
if (edge(vd, source(h, pm), pm).second)
|
||||
{
|
||||
shall_continue=true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (shall_continue) continue; // skip vertices already incident to the same vertex
|
||||
// update the vertex of the halfedges incident to the vertex to remove
|
||||
internal::update_target_vertex(in_h_rm, v_kept, pm);
|
||||
// update next/prev pointers around the 2 vertices to be merged
|
||||
halfedge_descriptor out_h_rm = next(in_h_rm, pm);
|
||||
set_next(in_h_kept, out_h_rm, pm);
|
||||
set_next(in_h_rm, out_h_kept, pm);
|
||||
vertices_to_rm.push_back(vd);
|
||||
out_h_kept=out_h_rm;
|
||||
}
|
||||
|
||||
BOOST_FOREACH(vertex_descriptor vd, vertices_to_rm)
|
||||
remove_vertex(vd, pm);
|
||||
}
|
||||
|
||||
} // end of internal
|
||||
|
||||
/// \ingroup PMP_repairing_grp
|
||||
/// merges identical vertices around a cycle of boundary edges.
|
||||
///
|
||||
/// @tparam PolygonMesh a model of `FaceListGraph` and `MutableFaceGraph`.
|
||||
/// @tparam NamedParameter a sequence of \ref pmp_namedparameters "Named Parameters".
|
||||
///
|
||||
/// @param h a halfedge that belongs to a boundary cycle.
|
||||
/// @param pm the polygon mesh which contains the boundary cycle.
|
||||
/// @param np optional parameter of \ref pmp_namedparameters "Named Parameters" listed below.
|
||||
///
|
||||
/// \cgalNamedParamsBegin
|
||||
/// \cgalParamBegin{vertex_point_map}
|
||||
/// the property map with the points associated to the vertices of `pm`.
|
||||
/// If this parameter is omitted, an internal property map for
|
||||
/// `CGAL::vertex_point_t` should be available in `PolygonMesh`
|
||||
/// \cgalParamEnd
|
||||
/// \cgalNamedParamsEnd
|
||||
template <class PolygonMesh, class NamedParameter>
|
||||
void merge_duplicated_vertices_in_boundary_cycle(
|
||||
typename boost::graph_traits<PolygonMesh>::halfedge_descriptor h,
|
||||
PolygonMesh& pm,
|
||||
const NamedParameter& np)
|
||||
{
|
||||
typedef typename boost::graph_traits<PolygonMesh>::halfedge_descriptor halfedge_descriptor;
|
||||
typedef typename GetVertexPointMap<PolygonMesh, NamedParameter>::const_type Vpm;
|
||||
|
||||
Vpm vpm = choose_param(get_param(np, internal_np::vertex_point),
|
||||
get_const_property_map(vertex_point, pm));
|
||||
|
||||
// collect all the halfedges of the cycle
|
||||
std::vector< std::pair<halfedge_descriptor, std::size_t> > cycle_hedges;
|
||||
halfedge_descriptor start=h;
|
||||
std::size_t index=0;
|
||||
do{
|
||||
cycle_hedges.push_back( std::make_pair(h, index) );
|
||||
h=next(h, pm);
|
||||
++index;
|
||||
}while(start!=h);
|
||||
|
||||
std::vector< std::vector<halfedge_descriptor> > hedges_with_identical_point_target;
|
||||
internal::detect_identical_mergeable_vertices(cycle_hedges, hedges_with_identical_point_target, pm, vpm);
|
||||
|
||||
BOOST_FOREACH(const std::vector<halfedge_descriptor>& hedges,
|
||||
hedges_with_identical_point_target)
|
||||
{
|
||||
start=hedges.front();
|
||||
// hedges are sorted along the cycle
|
||||
internal::merge_vertices_in_range(hedges, pm);
|
||||
}
|
||||
}
|
||||
|
||||
/// \ingroup PMP_repairing_grp
|
||||
/// extracts boundary cycles and merges the duplicated vertices of each cycle.
|
||||
///
|
||||
/// @tparam PolygonMesh a model of `FaceListGraph` and `MutableFaceGraph`.
|
||||
/// @tparam NamedParameter a sequence of \ref pmp_namedparameters "Named Parameters".
|
||||
///
|
||||
/// @param pm the polygon mesh which contains the cycles.
|
||||
/// @param np optional parameter of \ref pmp_namedparameters "Named Parameters" listed below.
|
||||
///
|
||||
/// \cgalNamedParamsBegin
|
||||
/// \cgalParamBegin{vertex_point_map}
|
||||
/// the property map with the points associated to the vertices of `pm`.
|
||||
/// If this parameter is omitted, an internal property map for
|
||||
/// `CGAL::vertex_point_t` should be available in `PolygonMesh`
|
||||
/// \cgalParamEnd
|
||||
/// \cgalNamedParamsEnd
|
||||
///
|
||||
/// \sa `merge_duplicated_vertices_in_boundary_cycle()`
|
||||
template <class PolygonMesh, class NamedParameter>
|
||||
void merge_duplicated_vertices_in_boundary_cycles( PolygonMesh& pm,
|
||||
const NamedParameter& np)
|
||||
{
|
||||
typedef typename boost::graph_traits<PolygonMesh>::halfedge_descriptor halfedge_descriptor;
|
||||
|
||||
std::vector<halfedge_descriptor> cycles;
|
||||
extract_boundary_cycles(pm, std::back_inserter(cycles));
|
||||
|
||||
BOOST_FOREACH(halfedge_descriptor h, cycles)
|
||||
merge_duplicated_vertices_in_boundary_cycle(h, pm, np);
|
||||
}
|
||||
|
||||
template <class PolygonMesh>
|
||||
void merge_duplicated_vertices_in_boundary_cycles(PolygonMesh& pm)
|
||||
{
|
||||
merge_duplicated_vertices_in_boundary_cycles(pm, parameters::all_default());
|
||||
}
|
||||
|
||||
template <class PolygonMesh>
|
||||
void merge_duplicated_vertices_in_boundary_cycle(
|
||||
typename boost::graph_traits<PolygonMesh>::halfedge_descriptor h,
|
||||
PolygonMesh& pm)
|
||||
{
|
||||
merge_duplicated_vertices_in_boundary_cycle(h, pm, parameters::all_default());
|
||||
}
|
||||
|
||||
} } // end of CGAL::Polygon_mesh_processing
|
||||
|
||||
#endif //CGAL_POLYGON_MESH_PROCESSING_MERGE_BORDER_VERTICES_H
|
||||
|
|
@ -174,10 +174,10 @@ void random_perturbation(VertexRange vertices
|
|||
typedef typename boost::lookup_named_param_def <
|
||||
internal_np::vertex_is_constrained_t,
|
||||
NamedParameters,
|
||||
internal::No_constraint_pmap<vertex_descriptor>//default
|
||||
Constant_property_map<vertex_descriptor, bool> // default
|
||||
> ::type VCMap;
|
||||
VCMap vcmap = choose_param(get_param(np, internal_np::vertex_is_constrained),
|
||||
internal::No_constraint_pmap<vertex_descriptor>());
|
||||
Constant_property_map<vertex_descriptor, bool>(false));
|
||||
|
||||
unsigned int seed = choose_param(get_param(np, internal_np::random_seed), -1);
|
||||
bool do_project = choose_param(get_param(np, internal_np::do_project), true);
|
||||
|
|
|
|||
|
|
@ -163,6 +163,7 @@ void isotropic_remeshing(const FaceRange& faces
|
|||
boost::is_default_param(get_param(np, internal_np::projection_functor));
|
||||
|
||||
typedef typename GetGeomTraits<PM, NamedParameters>::type GT;
|
||||
GT gt = choose_param(get_param(np, internal_np::geom_traits), GT());
|
||||
|
||||
typedef typename GetVertexPointMap<PM, NamedParameters>::type VPMap;
|
||||
VPMap vpmap = choose_param(get_param(np, internal_np::vertex_point),
|
||||
|
|
@ -175,18 +176,18 @@ void isotropic_remeshing(const FaceRange& faces
|
|||
typedef typename boost::lookup_named_param_def <
|
||||
internal_np::edge_is_constrained_t,
|
||||
NamedParameters,
|
||||
internal::No_constraint_pmap<edge_descriptor>//default
|
||||
Constant_property_map<edge_descriptor, bool> // default (no constraint pmap)
|
||||
> ::type ECMap;
|
||||
ECMap ecmap = choose_param(get_param(np, internal_np::edge_is_constrained)
|
||||
, internal::No_constraint_pmap<edge_descriptor>());
|
||||
ECMap ecmap = choose_param(get_param(np, internal_np::edge_is_constrained),
|
||||
Constant_property_map<edge_descriptor, bool>(false));
|
||||
|
||||
typedef typename boost::lookup_named_param_def <
|
||||
internal_np::vertex_is_constrained_t,
|
||||
NamedParameters,
|
||||
internal::No_constraint_pmap<vertex_descriptor>//default
|
||||
Constant_property_map<vertex_descriptor, bool> // default (no constraint pmap)
|
||||
> ::type VCMap;
|
||||
VCMap vcmap = choose_param(get_param(np, internal_np::vertex_is_constrained),
|
||||
internal::No_constraint_pmap<vertex_descriptor>());
|
||||
Constant_property_map<vertex_descriptor, bool>(false));
|
||||
|
||||
bool protect = choose_param(get_param(np, internal_np::protect_constraints), false);
|
||||
typedef typename boost::lookup_named_param_def <
|
||||
|
|
@ -227,7 +228,7 @@ void isotropic_remeshing(const FaceRange& faces
|
|||
#endif
|
||||
|
||||
typename internal::Incremental_remesher<PM, VPMap, GT, ECMap, VCMap, FPMap, FIMap>
|
||||
remesher(pmesh, vpmap, protect, ecmap, vcmap, fpmap, fimap, need_aabb_tree);
|
||||
remesher(pmesh, vpmap, gt, protect, ecmap, vcmap, fpmap, fimap, need_aabb_tree);
|
||||
remesher.init_remeshing(faces);
|
||||
|
||||
#ifdef CGAL_PMP_REMESHING_VERBOSE
|
||||
|
|
@ -340,6 +341,8 @@ void split_long_edges(const EdgeRange& edges
|
|||
using boost::get_param;
|
||||
|
||||
typedef typename GetGeomTraits<PM, NamedParameters>::type GT;
|
||||
GT gt = choose_param(get_param(np, internal_np::geom_traits), GT());
|
||||
|
||||
typedef typename GetVertexPointMap<PM, NamedParameters>::type VPMap;
|
||||
VPMap vpmap = choose_param(get_param(np, internal_np::vertex_point),
|
||||
get_property_map(vertex_point, pmesh));
|
||||
|
|
@ -351,22 +354,21 @@ void split_long_edges(const EdgeRange& edges
|
|||
typedef typename boost::lookup_named_param_def <
|
||||
internal_np::edge_is_constrained_t,
|
||||
NamedParameters,
|
||||
internal::No_constraint_pmap<edge_descriptor>//default
|
||||
Constant_property_map<edge_descriptor, bool> // default (no constraint pmap)
|
||||
> ::type ECMap;
|
||||
ECMap ecmap = choose_param(get_param(np, internal_np::edge_is_constrained),
|
||||
internal::No_constraint_pmap<edge_descriptor>());
|
||||
Constant_property_map<edge_descriptor, bool>(false));
|
||||
|
||||
typename internal::Incremental_remesher<PM, VPMap, GT, ECMap,
|
||||
internal::No_constraint_pmap<vertex_descriptor>,
|
||||
Constant_property_map<vertex_descriptor, bool>, // no constraint pmap
|
||||
internal::Connected_components_pmap<PM, FIMap>,
|
||||
FIMap
|
||||
>
|
||||
remesher(pmesh, vpmap, false/*protect constraints*/
|
||||
, ecmap
|
||||
, internal::No_constraint_pmap<vertex_descriptor>()
|
||||
, internal::Connected_components_pmap<PM, FIMap>(faces(pmesh), pmesh, ecmap, fimap, false)
|
||||
, fimap
|
||||
, false/*need aabb_tree*/);
|
||||
remesher(pmesh, vpmap, gt, false/*protect constraints*/, ecmap,
|
||||
Constant_property_map<vertex_descriptor, bool>(false),
|
||||
internal::Connected_components_pmap<PM, FIMap>(faces(pmesh), pmesh, ecmap, fimap, false),
|
||||
fimap,
|
||||
false/*need aabb_tree*/);
|
||||
|
||||
remesher.split_long_edges(edges, max_length);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -24,12 +24,9 @@
|
|||
|
||||
#include <CGAL/license/Polygon_mesh_processing/repair.h>
|
||||
|
||||
|
||||
#include <set>
|
||||
#include <vector>
|
||||
#include <boost/algorithm/minmax_element.hpp>
|
||||
#include <CGAL/boost/graph/Euler_operations.h>
|
||||
#include <CGAL/Union_find.h>
|
||||
#include <CGAL/property_map.h>
|
||||
#include <CGAL/algorithm.h>
|
||||
#include <CGAL/array.h>
|
||||
|
||||
|
|
@ -40,21 +37,33 @@
|
|||
|
||||
#include <CGAL/Polygon_mesh_processing/connected_components.h>
|
||||
#include <CGAL/Polygon_mesh_processing/border.h>
|
||||
#include <CGAL/Polygon_mesh_processing/shape_predicates.h>
|
||||
|
||||
#include <CGAL/Polygon_mesh_processing/internal/named_function_params.h>
|
||||
#include <CGAL/Polygon_mesh_processing/internal/named_params_helper.h>
|
||||
|
||||
#include <boost/range/has_range_iterator.hpp>
|
||||
|
||||
#ifdef CGAL_PMP_REMOVE_DEGENERATE_FACES_DEBUG
|
||||
#include <CGAL/Polygon_mesh_processing/polygon_soup_to_polygon_mesh.h>
|
||||
#include <CGAL/IO/OFF_reader.h>
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#endif
|
||||
|
||||
#include <boost/algorithm/minmax_element.hpp>
|
||||
#include <boost/type_traits/is_same.hpp>
|
||||
#include <boost/utility/enable_if.hpp>
|
||||
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <map>
|
||||
#include <set>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
namespace CGAL{
|
||||
namespace Polygon_mesh_processing {
|
||||
|
||||
namespace debug{
|
||||
|
||||
template <class TriangleMesh, class VertexPointMap>
|
||||
std::ostream& dump_edge_neighborhood(
|
||||
typename boost::graph_traits<TriangleMesh>::edge_descriptor ed,
|
||||
|
|
@ -142,8 +151,11 @@ namespace debug{
|
|||
<< vids[ target(next(next(halfedge(f, tm), tm), tm), tm) ] << "\n";
|
||||
}
|
||||
}
|
||||
|
||||
} //end of namespace debug
|
||||
|
||||
namespace internal {
|
||||
|
||||
template <class HalfedgeGraph, class VertexPointMap, class Traits>
|
||||
struct Less_vertex_point{
|
||||
typedef typename boost::graph_traits<HalfedgeGraph>::vertex_descriptor vertex_descriptor;
|
||||
|
|
@ -157,33 +169,158 @@ struct Less_vertex_point{
|
|||
}
|
||||
};
|
||||
|
||||
///\cond SKIP_IN_MANUAL
|
||||
} // end namespace internal
|
||||
|
||||
template <class Traits, class TriangleMesh, class VertexPointMap, class OutputIterator>
|
||||
OutputIterator
|
||||
degenerate_faces(const TriangleMesh& tm,
|
||||
const VertexPointMap& vpmap,
|
||||
const Traits& traits,
|
||||
OutputIterator out)
|
||||
/// \ingroup PMP_repairing_grp
|
||||
/// collects the degenerate edges within a given range of edges.
|
||||
///
|
||||
/// @tparam EdgeRange a model of `Range` with value type `boost::graph_traits<TriangleMesh>::%edge_descriptor`
|
||||
/// @tparam TriangleMesh a model of `HalfedgeGraph`
|
||||
/// @tparam NamedParameters a sequence of \ref pmp_namedparameters "Named Parameters"
|
||||
///
|
||||
/// @param edges a subset of edges of `tm`
|
||||
/// @param tm a triangle mesh
|
||||
/// @param out an output iterator in which the degenerate edges are written
|
||||
/// @param np optional \ref pmp_namedparameters "Named Parameters" described below
|
||||
///
|
||||
/// \cgalNamedParamsBegin
|
||||
/// \cgalParamBegin{vertex_point_map} the property map with the points associated to the vertices of `tm`.
|
||||
/// The type of this map is model of `ReadWritePropertyMap`.
|
||||
/// If this parameter is omitted, an internal property map for
|
||||
/// `CGAL::vertex_point_t` should be available in `TriangleMesh`
|
||||
/// \cgalParamEnd
|
||||
/// \cgalParamBegin{geom_traits} a geometric traits class instance.
|
||||
/// The traits class must provide the nested type `Point_3`,
|
||||
/// and the nested functor `Equal_3` to check whether two points are identical.
|
||||
/// \cgalParamEnd
|
||||
/// \cgalNamedParamsEnd
|
||||
template <class EdgeRange, class TriangleMesh, class OutputIterator, class NamedParameters>
|
||||
OutputIterator degenerate_edges(const EdgeRange& edges,
|
||||
const TriangleMesh& tm,
|
||||
OutputIterator out,
|
||||
const NamedParameters& np)
|
||||
{
|
||||
typedef typename boost::graph_traits<TriangleMesh>::face_descriptor face_descriptor;
|
||||
BOOST_FOREACH(face_descriptor fd, faces(tm))
|
||||
typedef typename boost::graph_traits<TriangleMesh>::edge_descriptor edge_descriptor;
|
||||
|
||||
BOOST_FOREACH(edge_descriptor ed, edges)
|
||||
{
|
||||
if ( is_degenerate_triangle_face(fd, tm, vpmap, traits) )
|
||||
*out++=fd;
|
||||
if(is_degenerate_edge(ed, tm, np))
|
||||
*out++ = ed;
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
template <class EdgeRange, class TriangleMesh, class OutputIterator>
|
||||
OutputIterator degenerate_edges(const EdgeRange& edges,
|
||||
const TriangleMesh& tm,
|
||||
OutputIterator out,
|
||||
typename boost::enable_if<
|
||||
typename boost::has_range_iterator<EdgeRange>
|
||||
>::type* = 0)
|
||||
{
|
||||
return degenerate_edges(edges, tm, out, CGAL::parameters::all_default());
|
||||
}
|
||||
|
||||
/// \ingroup PMP_repairing_grp
|
||||
/// calls the function `degenerate_edges()` with the range: `edges(tm)`.
|
||||
///
|
||||
/// See above for the comprehensive description of the parameters.
|
||||
///
|
||||
template <class TriangleMesh, class OutputIterator, class NamedParameters>
|
||||
OutputIterator degenerate_edges(const TriangleMesh& tm,
|
||||
OutputIterator out,
|
||||
const NamedParameters& np
|
||||
#ifndef DOXYGEN_RUNNING
|
||||
, typename boost::disable_if<
|
||||
boost::has_range_iterator<TriangleMesh>
|
||||
>::type* = 0
|
||||
#endif
|
||||
)
|
||||
{
|
||||
return degenerate_edges(edges(tm), tm, out, np);
|
||||
}
|
||||
|
||||
template <class TriangleMesh, class OutputIterator>
|
||||
OutputIterator
|
||||
degenerate_faces(const TriangleMesh& tm, OutputIterator out)
|
||||
degenerate_edges(const TriangleMesh& tm, OutputIterator out)
|
||||
{
|
||||
typedef typename boost::property_map<TriangleMesh, CGAL::vertex_point_t>::type Vpm;
|
||||
typedef typename boost::property_traits<Vpm>::value_type Point;
|
||||
typedef typename Kernel_traits<Point>::Kernel Kernel;
|
||||
return degenerate_edges(edges(tm), tm, out, CGAL::parameters::all_default());
|
||||
}
|
||||
|
||||
return degenerate_faces(tm, get(vertex_point, tm), Kernel(), out);
|
||||
/// \ingroup PMP_repairing_grp
|
||||
/// collects the degenerate faces within a given range of faces.
|
||||
///
|
||||
/// @tparam FaceRange a model of `Range` with value type `boost::graph_traits<TriangleMesh>::%face_descriptor`
|
||||
/// @tparam TriangleMesh a model of `FaceGraph`
|
||||
/// @tparam NamedParameters a sequence of \ref pmp_namedparameters "Named Parameters"
|
||||
///
|
||||
/// @param faces a subset of faces of `tm`
|
||||
/// @param tm a triangle mesh
|
||||
/// @param out an output iterator in which the degenerate faces are put
|
||||
/// @param np optional \ref pmp_namedparameters "Named Parameters" described below
|
||||
///
|
||||
/// \cgalNamedParamsBegin
|
||||
/// \cgalParamBegin{vertex_point_map} the property map with the points associated to the vertices of `tm`.
|
||||
/// The type of this map is model of `ReadWritePropertyMap`.
|
||||
/// If this parameter is omitted, an internal property map for
|
||||
/// `CGAL::vertex_point_t` should be available in `TriangleMesh`
|
||||
/// \cgalParamEnd
|
||||
/// \cgalParamBegin{geom_traits} a geometric traits class instance.
|
||||
/// The traits class must provide the nested functor `Collinear_3`
|
||||
/// to check whether three points are collinear.
|
||||
/// \cgalParamEnd
|
||||
/// \cgalNamedParamsEnd
|
||||
///
|
||||
template <class FaceRange, class TriangleMesh, class OutputIterator, class NamedParameters>
|
||||
OutputIterator degenerate_faces(const FaceRange& faces,
|
||||
const TriangleMesh& tm,
|
||||
OutputIterator out,
|
||||
const NamedParameters& np)
|
||||
{
|
||||
typedef typename boost::graph_traits<TriangleMesh>::face_descriptor face_descriptor;
|
||||
|
||||
BOOST_FOREACH(face_descriptor fd, faces)
|
||||
{
|
||||
if(is_degenerate_triangle_face(fd, tm, np))
|
||||
*out++ = fd;
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
template <class FaceRange, class TriangleMesh, class OutputIterator>
|
||||
OutputIterator degenerate_faces(const FaceRange& faces,
|
||||
const TriangleMesh& tm,
|
||||
OutputIterator out,
|
||||
typename boost::enable_if<
|
||||
boost::has_range_iterator<FaceRange>
|
||||
>::type* = 0)
|
||||
{
|
||||
return degenerate_faces(faces, tm, out, CGAL::parameters::all_default());
|
||||
}
|
||||
|
||||
/// \ingroup PMP_repairing_grp
|
||||
/// calls the function `degenerate_faces()` with the range: `faces(tm)`.
|
||||
///
|
||||
/// See above for the comprehensive description of the parameters.
|
||||
///
|
||||
template <class TriangleMesh, class OutputIterator, class NamedParameters>
|
||||
OutputIterator degenerate_faces(const TriangleMesh& tm,
|
||||
OutputIterator out,
|
||||
const NamedParameters& np
|
||||
#ifndef DOXYGEN_RUNNING
|
||||
, typename boost::disable_if<
|
||||
boost::has_range_iterator<TriangleMesh>
|
||||
>::type* = 0
|
||||
#endif
|
||||
)
|
||||
{
|
||||
return degenerate_faces(faces(tm), tm, out, np);
|
||||
}
|
||||
|
||||
template <class TriangleMesh, class OutputIterator>
|
||||
OutputIterator degenerate_faces(const TriangleMesh& tm, OutputIterator out)
|
||||
{
|
||||
return degenerate_faces(faces(tm), tm, out, CGAL::parameters::all_default());
|
||||
}
|
||||
|
||||
// this function remove a border edge even if it does not satisfy the link condition.
|
||||
|
|
@ -365,10 +502,9 @@ remove_a_border_edge(typename boost::graph_traits<TriangleMesh>::edge_descriptor
|
|||
}
|
||||
|
||||
template <class EdgeRange, class TriangleMesh, class NamedParameters>
|
||||
std::size_t remove_null_edges(
|
||||
const EdgeRange& edge_range,
|
||||
TriangleMesh& tmesh,
|
||||
const NamedParameters& np)
|
||||
bool remove_degenerate_edges(const EdgeRange& edge_range,
|
||||
TriangleMesh& tmesh,
|
||||
const NamedParameters& np)
|
||||
{
|
||||
CGAL_assertion(CGAL::is_triangle_mesh(tmesh));
|
||||
|
||||
|
|
@ -385,27 +521,25 @@ std::size_t remove_null_edges(
|
|||
typedef typename GetVertexPointMap<TM, NamedParameters>::type VertexPointMap;
|
||||
VertexPointMap vpmap = choose_param(get_param(np, internal_np::vertex_point),
|
||||
get_property_map(vertex_point, tmesh));
|
||||
|
||||
typedef typename GetGeomTraits<TM, NamedParameters>::type Traits;
|
||||
Traits traits = choose_param(get_param(np, internal_np::geom_traits), Traits());
|
||||
|
||||
std::size_t nb_deg_faces = 0;
|
||||
bool all_removed=true;
|
||||
|
||||
// collect edges of length 0
|
||||
std::set<edge_descriptor> null_edges_to_remove;
|
||||
BOOST_FOREACH(edge_descriptor ed, edge_range)
|
||||
{
|
||||
if ( traits.equal_3_object()(get(vpmap, target(ed, tmesh)), get(vpmap, source(ed, tmesh))) )
|
||||
null_edges_to_remove.insert(ed);
|
||||
}
|
||||
std::set<edge_descriptor> degenerate_edges_to_remove;
|
||||
degenerate_edges(edge_range, tmesh, std::inserter(degenerate_edges_to_remove,
|
||||
degenerate_edges_to_remove.end()));
|
||||
|
||||
#ifdef CGAL_PMP_REMOVE_DEGENERATE_FACES_DEBUG
|
||||
std::cout << "Found " << null_edges_to_remove.size() << " null edges.\n";
|
||||
#endif
|
||||
#ifdef CGAL_PMP_REMOVE_DEGENERATE_FACES_DEBUG
|
||||
std::cout << "Found " << degenerate_edges_to_remove.size() << " null edges.\n";
|
||||
#endif
|
||||
|
||||
while (!null_edges_to_remove.empty())
|
||||
while (!degenerate_edges_to_remove.empty())
|
||||
{
|
||||
edge_descriptor ed = *null_edges_to_remove.begin();
|
||||
null_edges_to_remove.erase(null_edges_to_remove.begin());
|
||||
edge_descriptor ed = *degenerate_edges_to_remove.begin();
|
||||
degenerate_edges_to_remove.erase(degenerate_edges_to_remove.begin());
|
||||
|
||||
halfedge_descriptor h = halfedge(ed, tmesh);
|
||||
|
||||
|
|
@ -415,12 +549,12 @@ std::size_t remove_null_edges(
|
|||
if ( face(h, tmesh)!=GT::null_face() )
|
||||
{
|
||||
++nb_deg_faces;
|
||||
null_edges_to_remove.erase(edge(prev(h, tmesh), tmesh));
|
||||
degenerate_edges_to_remove.erase(edge(prev(h, tmesh), tmesh));
|
||||
}
|
||||
if (face(opposite(h, tmesh), tmesh)!=GT::null_face())
|
||||
{
|
||||
++nb_deg_faces;
|
||||
null_edges_to_remove.erase(edge(prev(opposite(h, tmesh), tmesh), tmesh));
|
||||
degenerate_edges_to_remove.erase(edge(prev(opposite(h, tmesh), tmesh), tmesh));
|
||||
}
|
||||
//now remove the edge
|
||||
CGAL::Euler::collapse_edge(ed, tmesh);
|
||||
|
|
@ -435,10 +569,40 @@ std::size_t remove_null_edges(
|
|||
if (is_triangle(hd, tmesh))
|
||||
{
|
||||
Euler::fill_hole(hd, tmesh);
|
||||
null_edges_to_remove.insert(ed);
|
||||
degenerate_edges_to_remove.insert(ed);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
halfedge_descriptor hd = halfedge(ed,tmesh);
|
||||
// if both vertices are boundary vertices we can't do anything
|
||||
bool impossible = false;
|
||||
BOOST_FOREACH(halfedge_descriptor h, halfedges_around_target(hd, tmesh))
|
||||
{
|
||||
if (is_border(h, tmesh))
|
||||
{
|
||||
impossible = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (impossible)
|
||||
{
|
||||
BOOST_FOREACH(halfedge_descriptor h, halfedges_around_source(hd, tmesh))
|
||||
{
|
||||
if (is_border(h, tmesh))
|
||||
{
|
||||
impossible = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (impossible)
|
||||
{
|
||||
all_removed=false;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// When the edge does not satisfy the link condition, it means that it cannot be
|
||||
// collapsed as is. In the following we assume that there is no topological issue
|
||||
|
|
@ -621,7 +785,7 @@ std::size_t remove_null_edges(
|
|||
// remove edges
|
||||
BOOST_FOREACH(edge_descriptor ed, edges_to_remove)
|
||||
{
|
||||
null_edges_to_remove.erase(ed);
|
||||
degenerate_edges_to_remove.erase(ed);
|
||||
remove_edge(ed, tmesh);
|
||||
}
|
||||
|
||||
|
|
@ -641,61 +805,60 @@ std::size_t remove_null_edges(
|
|||
put(vpmap, target(new_hd, tmesh), pt);
|
||||
|
||||
BOOST_FOREACH(halfedge_descriptor hd, halfedges_around_target(new_hd, tmesh))
|
||||
if ( traits.equal_3_object()(get(vpmap, target(hd, tmesh)), get(vpmap, source(hd, tmesh))) )
|
||||
null_edges_to_remove.insert(edge(hd, tmesh));
|
||||
if(is_degenerate_edge(edge(hd, tmesh), tmesh, np))
|
||||
degenerate_edges_to_remove.insert(edge(hd, tmesh));
|
||||
|
||||
CGAL_assertion( is_valid_polygon_mesh(tmesh) );
|
||||
}
|
||||
}
|
||||
|
||||
return nb_deg_faces;
|
||||
return all_removed;
|
||||
}
|
||||
|
||||
template <class EdgeRange, class TriangleMesh>
|
||||
std::size_t remove_null_edges(
|
||||
const EdgeRange& edge_range,
|
||||
TriangleMesh& tmesh)
|
||||
bool remove_degenerate_edges(const EdgeRange& edge_range,
|
||||
TriangleMesh& tmesh)
|
||||
{
|
||||
return remove_null_edges(edge_range, tmesh,
|
||||
parameters::all_default());
|
||||
return remove_degenerate_edges(edge_range, tmesh, parameters::all_default());
|
||||
}
|
||||
|
||||
/// \ingroup PMP_repairing_grp
|
||||
/// removes the degenerate faces from a triangulated surface mesh.
|
||||
/// A face is considered degenerate if two of its vertices share the same location,
|
||||
/// or more generally if all its vertices are collinear.
|
||||
///
|
||||
/// @pre `CGAL::is_triangle_mesh(tmesh)`
|
||||
///
|
||||
/// @tparam TriangleMesh a model of `FaceListGraph` and `MutableFaceGraph`
|
||||
/// @tparam NamedParameters a sequence of \ref pmp_namedparameters "Named Parameters"
|
||||
///
|
||||
/// @param tmesh the triangulated surface mesh to be repaired
|
||||
/// @param np optional \ref pmp_namedparameters "Named Parameters" described below
|
||||
///
|
||||
/// \cgalNamedParamsBegin
|
||||
/// \cgalParamBegin{vertex_point_map} the property map with the points associated to the vertices of `pmesh`. The type of this map is model of `ReadWritePropertyMap`.
|
||||
/// If this parameter is omitted, an internal property map for
|
||||
/// `CGAL::vertex_point_t` must be available in `TriangleMesh`
|
||||
/// \cgalParamEnd
|
||||
/// \cgalParamBegin{geom_traits} a geometric traits class instance.
|
||||
/// The traits class must provide the nested type `Point_3`,
|
||||
/// and the nested functors :
|
||||
/// - `Compare_distance_3` to compute the distance between 2 points
|
||||
/// - `Collinear_are_ordered_along_line_3` to check whether 3 collinear points are ordered
|
||||
/// - `Collinear_3` to check whether 3 points are collinear
|
||||
/// - `Less_xyz_3` to compare lexicographically two points
|
||||
/// - `Equal_3` to check whether 2 points are identical
|
||||
/// - for each functor Foo, a function `Foo foo_object()`
|
||||
/// \cgalParamEnd
|
||||
/// \cgalNamedParamsEnd
|
||||
///
|
||||
/// \todo the function might not be able to remove all degenerate faces.
|
||||
/// We should probably do something with the return type.
|
||||
/// \return number of removed degenerate faces
|
||||
// \ingroup PMP_repairing_grp
|
||||
// removes the degenerate faces from a triangulated surface mesh.
|
||||
// A face is considered degenerate if two of its vertices share the same location,
|
||||
// or more generally if all its vertices are collinear.
|
||||
//
|
||||
// @pre `CGAL::is_triangle_mesh(tmesh)`
|
||||
//
|
||||
// @tparam TriangleMesh a model of `FaceListGraph` and `MutableFaceGraph`
|
||||
// @tparam NamedParameters a sequence of \ref pmp_namedparameters "Named Parameters"
|
||||
//
|
||||
// @param tmesh the triangulated surface mesh to be repaired
|
||||
// @param np optional \ref pmp_namedparameters "Named Parameters" described below
|
||||
//
|
||||
// \cgalNamedParamsBegin
|
||||
// \cgalParamBegin{vertex_point_map} the property map with the points associated to the vertices of `pmesh`.
|
||||
// The type of this map is model of `ReadWritePropertyMap`.
|
||||
// If this parameter is omitted, an internal property map for
|
||||
// `CGAL::vertex_point_t` must be available in `TriangleMesh`
|
||||
// \cgalParamEnd
|
||||
// \cgalParamBegin{geom_traits} a geometric traits class instance.
|
||||
// The traits class must provide the nested type `Point_3`,
|
||||
// and the nested functors :
|
||||
// - `Compare_distance_3` to compute the distance between 2 points
|
||||
// - `Collinear_3` to check whether 3 points are collinear
|
||||
// - `Less_xyz_3` to compare lexicographically two points
|
||||
// - `Equal_3` to check whether 2 points are identical
|
||||
// For each functor `Foo`, a function `Foo foo_object()`
|
||||
// \cgalParamEnd
|
||||
// \cgalNamedParamsEnd
|
||||
//
|
||||
// \todo the function might not be able to remove all degenerate faces.
|
||||
// We should probably do something with the return type.
|
||||
//
|
||||
/// \return `true` if all degenerate faces were successfully removed, and `false` otherwise.
|
||||
template <class TriangleMesh, class NamedParameters>
|
||||
std::size_t remove_degenerate_faces(TriangleMesh& tmesh,
|
||||
const NamedParameters& np)
|
||||
bool remove_degenerate_faces( TriangleMesh& tmesh,
|
||||
const NamedParameters& np)
|
||||
{
|
||||
CGAL_assertion(CGAL::is_triangle_mesh(tmesh));
|
||||
|
||||
|
|
@ -717,8 +880,9 @@ std::size_t remove_degenerate_faces(TriangleMesh& tmesh,
|
|||
|
||||
typedef typename boost::property_traits<VertexPointMap>::value_type Point_3;
|
||||
typedef typename boost::property_traits<VertexPointMap>::reference Point_ref;
|
||||
|
||||
// First remove edges of length 0
|
||||
std::size_t nb_deg_faces = remove_null_edges(edges(tmesh), tmesh, np);
|
||||
bool all_removed = remove_degenerate_edges(edges(tmesh), tmesh, np);
|
||||
|
||||
#ifdef CGAL_PMP_REMOVE_DEGENERATE_FACES_DEBUG
|
||||
{
|
||||
|
|
@ -731,10 +895,21 @@ std::size_t remove_degenerate_faces(TriangleMesh& tmesh,
|
|||
|
||||
// Then, remove triangles made of 3 collinear points
|
||||
std::set<face_descriptor> degenerate_face_set;
|
||||
BOOST_FOREACH(face_descriptor fd, faces(tmesh))
|
||||
if ( is_degenerate_triangle_face(fd, tmesh, vpmap, traits) )
|
||||
degenerate_face_set.insert(fd);
|
||||
nb_deg_faces+=degenerate_face_set.size();
|
||||
degenerate_faces(tmesh, std::inserter(degenerate_face_set, degenerate_face_set.begin()), np);
|
||||
// Ignore faces with null edges
|
||||
if (!all_removed)
|
||||
{
|
||||
BOOST_FOREACH(edge_descriptor ed, edges(tmesh))
|
||||
{
|
||||
if ( traits.equal_3_object()(get(vpmap, target(ed, tmesh)), get(vpmap, source(ed, tmesh))) )
|
||||
{
|
||||
halfedge_descriptor h = halfedge(ed, tmesh);
|
||||
if (!is_border(h, tmesh)) degenerate_face_set.erase(face(h, tmesh));
|
||||
h=opposite(h, tmesh);
|
||||
if (!is_border(h, tmesh)) degenerate_face_set.erase(face(h, tmesh));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// first remove degree 3 vertices that are part of a cap
|
||||
// (only the vertex in the middle of the opposite edge)
|
||||
|
|
@ -747,7 +922,7 @@ std::size_t remove_degenerate_faces(TriangleMesh& tmesh,
|
|||
BOOST_FOREACH(halfedge_descriptor hd, halfedges_around_face(halfedge(fd, tmesh), tmesh))
|
||||
{
|
||||
vertex_descriptor vd = target(hd, tmesh);
|
||||
if (degree(vd, tmesh) == 3)
|
||||
if (degree(vd, tmesh) == 3 && is_border(vd, tmesh)==GT::null_halfedge())
|
||||
{
|
||||
vertices_to_remove.insert(vd);
|
||||
break;
|
||||
|
|
@ -763,7 +938,7 @@ std::size_t remove_degenerate_faces(TriangleMesh& tmesh,
|
|||
degenerate_face_set.erase( face(hd2, tmesh) );
|
||||
// remove the central vertex and check if the new face is degenerated
|
||||
hd=CGAL::Euler::remove_center_vertex(hd, tmesh);
|
||||
if (is_degenerate_triangle_face(face(hd, tmesh), tmesh, vpmap, traits))
|
||||
if (is_degenerate_triangle_face(face(hd, tmesh), tmesh, np))
|
||||
{
|
||||
degenerate_face_set.insert( face(hd, tmesh) );
|
||||
}
|
||||
|
|
@ -855,15 +1030,17 @@ std::size_t remove_degenerate_faces(TriangleMesh& tmesh,
|
|||
{
|
||||
Euler::flip_edge(edge_to_flip, tmesh);
|
||||
}
|
||||
else
|
||||
{
|
||||
all_removed=false;
|
||||
#ifdef CGAL_PMP_REMOVE_DEGENERATE_FACES_DEBUG
|
||||
else{
|
||||
std::cout << " WARNING: flip is not possible\n";
|
||||
// \todo Let p and q be the vertices opposite to `edge_to_flip`, and let
|
||||
// r be the vertex of `edge_to_flip` that is the furthest away from
|
||||
// the edge `pq`. In that case I think we should remove all the triangles
|
||||
// so that the triangle pqr is in the mesh.
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
|
|
@ -964,7 +1141,7 @@ std::size_t remove_degenerate_faces(TriangleMesh& tmesh,
|
|||
// preliminary step to check if the operation is possible
|
||||
// sort the boundary points along the common supporting line
|
||||
// we first need a reference point
|
||||
typedef Less_vertex_point<TriangleMesh, VertexPointMap, Traits> Less_vertex;
|
||||
typedef internal::Less_vertex_point<TriangleMesh, VertexPointMap, Traits> Less_vertex;
|
||||
std::pair<
|
||||
typename std::set<vertex_descriptor>::iterator,
|
||||
typename std::set<vertex_descriptor>::iterator > ref_vertices =
|
||||
|
|
@ -1278,10 +1455,9 @@ std::size_t remove_degenerate_faces(TriangleMesh& tmesh,
|
|||
}
|
||||
}
|
||||
|
||||
return nb_deg_faces;
|
||||
return all_removed;
|
||||
}
|
||||
|
||||
|
||||
template<class TriangleMesh>
|
||||
std::size_t remove_degenerate_faces(TriangleMesh& tmesh)
|
||||
{
|
||||
|
|
@ -1289,52 +1465,207 @@ std::size_t remove_degenerate_faces(TriangleMesh& tmesh)
|
|||
CGAL::Polygon_mesh_processing::parameters::all_default());
|
||||
}
|
||||
|
||||
template <class TriangleMesh, class Vpm>
|
||||
std::size_t duplicate_non_manifold_vertices(TriangleMesh& tm, Vpm vpm)
|
||||
namespace internal {
|
||||
|
||||
template <typename G, typename OutputIterator>
|
||||
struct Vertex_collector
|
||||
{
|
||||
typedef typename boost::graph_traits<G>::vertex_descriptor vertex_descriptor;
|
||||
|
||||
void collect_vertices(vertex_descriptor v1, vertex_descriptor v2)
|
||||
{
|
||||
std::vector<vertex_descriptor>& verts = collections[v1];
|
||||
if(verts.empty())
|
||||
verts.push_back(v1);
|
||||
verts.push_back(v2);
|
||||
}
|
||||
|
||||
void dump(OutputIterator out)
|
||||
{
|
||||
typedef std::pair<const vertex_descriptor, std::vector<vertex_descriptor> > Pair_type;
|
||||
BOOST_FOREACH(const Pair_type& p, collections) {
|
||||
*out++ = p.second;
|
||||
}
|
||||
}
|
||||
|
||||
std::map<vertex_descriptor, std::vector<vertex_descriptor> > collections;
|
||||
};
|
||||
|
||||
template <typename G>
|
||||
struct Vertex_collector<G, Emptyset_iterator>
|
||||
{
|
||||
typedef typename boost::graph_traits<G>::vertex_descriptor vertex_descriptor;
|
||||
void collect_vertices(vertex_descriptor, vertex_descriptor)
|
||||
{}
|
||||
|
||||
void dump(Emptyset_iterator)
|
||||
{}
|
||||
};
|
||||
|
||||
} // end namespace internal
|
||||
|
||||
/// \ingroup PMP_repairing_grp
|
||||
/// checks whether a vertex of a polygon mesh is non-manifold.
|
||||
///
|
||||
/// @tparam PolygonMesh a model of `HalfedgeListGraph`
|
||||
///
|
||||
/// @param v a vertex of `pm`
|
||||
/// @param pm a triangle mesh containing `v`
|
||||
///
|
||||
/// \sa `duplicate_non_manifold_vertices()`
|
||||
///
|
||||
/// \return `true` if the vertex is non-manifold, `false` otherwise.
|
||||
template <typename PolygonMesh>
|
||||
bool is_non_manifold_vertex(typename boost::graph_traits<PolygonMesh>::vertex_descriptor v,
|
||||
const PolygonMesh& pm)
|
||||
{
|
||||
typedef typename boost::graph_traits<PolygonMesh>::halfedge_descriptor halfedge_descriptor;
|
||||
boost::unordered_set<halfedge_descriptor> halfedges_handled;
|
||||
|
||||
std::size_t incident_null_faces_counter = 0;
|
||||
BOOST_FOREACH(halfedge_descriptor h, halfedges_around_target(v, pm))
|
||||
{
|
||||
halfedges_handled.insert(h);
|
||||
if(CGAL::is_border(h, pm))
|
||||
++incident_null_faces_counter;
|
||||
}
|
||||
|
||||
if(incident_null_faces_counter > 1)
|
||||
{
|
||||
// The vertex is the sole connection between two connected components --> non-manifold
|
||||
return true;
|
||||
}
|
||||
|
||||
BOOST_FOREACH(halfedge_descriptor h, halfedges(pm))
|
||||
{
|
||||
if(v == target(h, pm))
|
||||
{
|
||||
// More than one umbrella incident to 'v' --> non-manifold
|
||||
if(halfedges_handled.count(h) == 0)
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/// \ingroup PMP_repairing_grp
|
||||
/// duplicates all the non-manifold vertices of the input mesh.
|
||||
///
|
||||
/// @tparam TriangleMesh a model of `HalfedgeListGraph` and `MutableHalfedgeGraph`
|
||||
/// @tparam NamedParameters a sequence of \ref pmp_namedparameters "Named Parameters"
|
||||
///
|
||||
/// @param tm the triangulated surface mesh to be repaired
|
||||
/// @param np optional \ref pmp_namedparameters "Named Parameters" described below
|
||||
///
|
||||
/// \cgalNamedParamsBegin
|
||||
/// \cgalParamBegin{vertex_point_map} the property map with the points associated to the vertices of `pmesh`.
|
||||
/// The type of this map is model of `ReadWritePropertyMap`.
|
||||
/// If this parameter is omitted, an internal property map for
|
||||
/// `CGAL::vertex_point_t` should be available in `TriangleMesh`
|
||||
/// \cgalParamEnd
|
||||
/// \cgalParamBegin{vertex_is_constrained_map} a writable property map with `vertex_descriptor`
|
||||
/// as key and `bool` as `value_type`. `put(pmap, v, true)` will be called for each duplicated
|
||||
/// vertices, as well as the original non-manifold vertex in the input mesh.
|
||||
/// \cgalParamEnd
|
||||
/// \cgalParamBegin{output_iterator} a model of `OutputIterator` with value type
|
||||
/// `std::vector<vertex_descriptor>`. The first vertex of each vector is a non-manifold vertex
|
||||
/// of the input mesh, followed by the new vertices that were created to fix this precise
|
||||
/// non-manifold configuration.
|
||||
/// \cgalParamEnd
|
||||
/// \cgalNamedParamsEnd
|
||||
///
|
||||
/// \return the number of vertices created.
|
||||
template <typename TriangleMesh, typename NamedParameters>
|
||||
std::size_t duplicate_non_manifold_vertices(TriangleMesh& tm,
|
||||
const NamedParameters& np)
|
||||
{
|
||||
CGAL_assertion(CGAL::is_triangle_mesh(tm));
|
||||
|
||||
using boost::get_param;
|
||||
using boost::choose_param;
|
||||
|
||||
typedef boost::graph_traits<TriangleMesh> GT;
|
||||
typedef typename GT::vertex_descriptor vertex_descriptor;
|
||||
typedef typename GT::halfedge_descriptor halfedge_descriptor;
|
||||
|
||||
typedef typename GetVertexPointMap<TriangleMesh, NamedParameters>::type VertexPointMap;
|
||||
VertexPointMap vpm = choose_param(get_param(np, internal_np::vertex_point),
|
||||
get_property_map(vertex_point, tm));
|
||||
|
||||
typedef typename boost::lookup_named_param_def <
|
||||
internal_np::vertex_is_constrained_t,
|
||||
NamedParameters,
|
||||
Constant_property_map<vertex_descriptor, bool> // default (no constraint pmap)
|
||||
> ::type VerticesMap;
|
||||
VerticesMap cmap
|
||||
= choose_param(get_param(np, internal_np::vertex_is_constrained),
|
||||
Constant_property_map<vertex_descriptor, bool>(false));
|
||||
|
||||
typedef typename boost::lookup_named_param_def <
|
||||
internal_np::output_iterator_t,
|
||||
NamedParameters,
|
||||
Emptyset_iterator
|
||||
> ::type Output_iterator;
|
||||
Output_iterator out
|
||||
= choose_param(get_param(np, internal_np::output_iterator),
|
||||
Emptyset_iterator());
|
||||
|
||||
internal::Vertex_collector<TriangleMesh, Output_iterator> dmap;
|
||||
boost::unordered_set<vertex_descriptor> vertices_handled;
|
||||
boost::unordered_set<halfedge_descriptor> halfedges_handled;
|
||||
|
||||
std::size_t nb_new_vertices=0;
|
||||
std::size_t nb_new_vertices = 0;
|
||||
|
||||
std::vector<halfedge_descriptor> non_manifold_cones;
|
||||
BOOST_FOREACH(halfedge_descriptor h, halfedges(tm))
|
||||
{
|
||||
if (halfedges_handled.insert(h).second)
|
||||
// If 'h' is not visited yet, we walk around the target of 'h' and mark these
|
||||
// halfedges as visited. Thus, if we are here and the target is already marked as visited,
|
||||
// it means that the vertex is non manifold.
|
||||
if(halfedges_handled.insert(h).second)
|
||||
{
|
||||
vertex_descriptor vd = target(h, tm);
|
||||
if ( !vertices_handled.insert(vd).second )
|
||||
if(!vertices_handled.insert(vd).second)
|
||||
{
|
||||
put(cmap, vd, true); // store the originals
|
||||
non_manifold_cones.push_back(h);
|
||||
}
|
||||
else
|
||||
{
|
||||
set_halfedge(vd, h, tm);
|
||||
halfedge_descriptor start=opposite(next(h, tm), tm);
|
||||
h=start;
|
||||
do{
|
||||
}
|
||||
|
||||
halfedge_descriptor start = opposite(next(h, tm), tm);
|
||||
h = start;
|
||||
do
|
||||
{
|
||||
halfedges_handled.insert(h);
|
||||
h=opposite(next(h, tm), tm);
|
||||
}while(h!=start);
|
||||
h = opposite(next(h, tm), tm);
|
||||
}
|
||||
while(h != start);
|
||||
}
|
||||
}
|
||||
|
||||
if (!non_manifold_cones.empty()) {
|
||||
if(!non_manifold_cones.empty())
|
||||
{
|
||||
BOOST_FOREACH(halfedge_descriptor h, non_manifold_cones)
|
||||
{
|
||||
halfedge_descriptor start = h;
|
||||
vertex_descriptor new_vd = add_vertex(tm);
|
||||
++nb_new_vertices;
|
||||
put(cmap, new_vd, true); // store the duplicates
|
||||
dmap.collect_vertices(target(h, tm), new_vd);
|
||||
put(vpm, new_vd, get(vpm, target(h, tm)));
|
||||
set_halfedge(new_vd, h, tm);
|
||||
do{
|
||||
do
|
||||
{
|
||||
set_target(h, new_vd, tm);
|
||||
h=opposite(next(h, tm), tm);
|
||||
} while(h!=start);
|
||||
h = opposite(next(h, tm), tm);
|
||||
}
|
||||
while(h != start);
|
||||
}
|
||||
dmap.dump(out);
|
||||
}
|
||||
|
||||
return nb_new_vertices;
|
||||
|
|
@ -1343,12 +1674,9 @@ std::size_t duplicate_non_manifold_vertices(TriangleMesh& tm, Vpm vpm)
|
|||
template <class TriangleMesh>
|
||||
std::size_t duplicate_non_manifold_vertices(TriangleMesh& tm)
|
||||
{
|
||||
return duplicate_non_manifold_vertices(tm, get(vertex_point, tm));
|
||||
return duplicate_non_manifold_vertices(tm, parameters::all_default());
|
||||
}
|
||||
|
||||
/// \endcond
|
||||
|
||||
|
||||
/// \ingroup PMP_repairing_grp
|
||||
/// removes the isolated vertices from any polygon mesh.
|
||||
/// A vertex is considered isolated if it is not incident to any simplex
|
||||
|
|
|
|||
|
|
@ -0,0 +1,358 @@
|
|||
// Copyright (c) 2015, 2018 GeometryFactory (France).
|
||||
// All rights reserved.
|
||||
//
|
||||
// This file is part of CGAL (www.cgal.org).
|
||||
// You can redistribute it and/or modify it under the terms of the GNU
|
||||
// General Public License as published by the Free Software Foundation,
|
||||
// either version 3 of the License, or (at your option) any later version.
|
||||
//
|
||||
// Licensees holding a valid commercial license may use this file in
|
||||
// accordance with the commercial license agreement provided with the software.
|
||||
//
|
||||
// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
|
||||
// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
|
||||
//
|
||||
// $URL$
|
||||
// $Id$
|
||||
// SPDX-License-Identifier: GPL-3.0+
|
||||
//
|
||||
//
|
||||
// Author(s) : Konstantinos Katrioplas,
|
||||
// Mael Rouxel-Labbé
|
||||
|
||||
#ifndef CGAL_POLYGON_MESH_PROCESSING_SHAPE_PREDICATES_H
|
||||
#define CGAL_POLYGON_MESH_PROCESSING_SHAPE_PREDICATES_H
|
||||
|
||||
#include <CGAL/license/Polygon_mesh_processing/repair.h>
|
||||
|
||||
#include <CGAL/Polygon_mesh_processing/internal/named_function_params.h>
|
||||
#include <CGAL/Polygon_mesh_processing/internal/named_params_helper.h>
|
||||
|
||||
#include <CGAL/array.h>
|
||||
#include <CGAL/boost/graph/iterator.h>
|
||||
#include <CGAL/boost/graph/helpers.h>
|
||||
|
||||
#include <boost/foreach.hpp>
|
||||
#include <boost/graph/graph_traits.hpp>
|
||||
|
||||
#include <limits>
|
||||
#include <map>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
namespace CGAL {
|
||||
|
||||
namespace Polygon_mesh_processing {
|
||||
|
||||
/// \ingroup PMP_repairing_grp
|
||||
/// checks whether an edge is degenerate.
|
||||
/// An edge is considered degenerate if the geometric positions of its two extremities are identical.
|
||||
///
|
||||
/// @tparam PolygonMesh a model of `HalfedgeGraph`
|
||||
/// @tparam NamedParameters a sequence of \ref pmp_namedparameters "Named Parameters"
|
||||
///
|
||||
/// @param e an edge of `pm`
|
||||
/// @param pm polygon mesh containing `e`
|
||||
/// @param np optional \ref pmp_namedparameters "Named Parameters" described below
|
||||
///
|
||||
/// \cgalNamedParamsBegin
|
||||
/// \cgalParamBegin{vertex_point_map} the property map with the points associated to the vertices of `pm`.
|
||||
/// The type of this map is model of `ReadWritePropertyMap`.
|
||||
/// If this parameter is omitted, an internal property map for
|
||||
/// `CGAL::vertex_point_t` should be available in `PolygonMesh`
|
||||
/// \cgalParamEnd
|
||||
/// \cgalParamBegin{geom_traits} a geometric traits class instance.
|
||||
/// The traits class must provide the nested type `Point_3`,
|
||||
/// and the nested functor `Equal_3` to check whether two points are identical.
|
||||
/// \cgalParamEnd
|
||||
/// \cgalNamedParamsEnd
|
||||
///
|
||||
/// \sa `degenerate_edges()`
|
||||
///
|
||||
/// \return `true` if the edge `e` is degenerate, `false` otherwise.
|
||||
template <typename PolygonMesh, typename NamedParameters>
|
||||
bool is_degenerate_edge(typename boost::graph_traits<PolygonMesh>::edge_descriptor e,
|
||||
const PolygonMesh& pm,
|
||||
const NamedParameters& np)
|
||||
{
|
||||
using boost::get_param;
|
||||
using boost::choose_param;
|
||||
|
||||
typedef typename GetVertexPointMap<PolygonMesh, NamedParameters>::const_type VertexPointMap;
|
||||
VertexPointMap vpmap = choose_param(get_param(np, internal_np::vertex_point),
|
||||
get_const_property_map(vertex_point, pm));
|
||||
|
||||
typedef typename GetGeomTraits<PolygonMesh, NamedParameters>::type Traits;
|
||||
Traits traits = choose_param(get_param(np, internal_np::geom_traits), Traits());
|
||||
|
||||
return traits.equal_3_object()(get(vpmap, source(e, pm)), get(vpmap, target(e, pm)));
|
||||
}
|
||||
|
||||
template <typename PolygonMesh>
|
||||
bool is_degenerate_edge(typename boost::graph_traits<PolygonMesh>::edge_descriptor e,
|
||||
const PolygonMesh& pm)
|
||||
{
|
||||
return is_degenerate_edge(e, pm, parameters::all_default());
|
||||
}
|
||||
|
||||
/// \ingroup PMP_repairing_grp
|
||||
/// checks whether a triangle face is degenerate.
|
||||
/// A triangle face is considered degenerate if the geometric positions of its vertices are collinear.
|
||||
///
|
||||
/// @tparam TriangleMesh a model of `FaceGraph`
|
||||
/// @tparam NamedParameters a sequence of \ref pmp_namedparameters "Named Parameters"
|
||||
///
|
||||
/// @param f a triangle face of `tm`
|
||||
/// @param tm a triangle mesh containing `f`
|
||||
/// @param np optional \ref pmp_namedparameters "Named Parameters" described below
|
||||
///
|
||||
/// \cgalNamedParamsBegin
|
||||
/// \cgalParamBegin{vertex_point_map} the property map with the points associated to the vertices of `tm`.
|
||||
/// The type of this map is model of `ReadWritePropertyMap`.
|
||||
/// If this parameter is omitted, an internal property map for
|
||||
/// `CGAL::vertex_point_t` should be available in `TriangleMesh`
|
||||
/// \cgalParamEnd
|
||||
/// \cgalParamBegin{geom_traits} a geometric traits class instance.
|
||||
/// The traits class must provide the nested functor `Collinear_3`
|
||||
/// to check whether three points are collinear.
|
||||
/// \cgalParamEnd
|
||||
/// \cgalNamedParamsEnd
|
||||
///
|
||||
/// \sa `degenerate_faces()`
|
||||
///
|
||||
/// \return `true` if the face `f` is degenerate, `false` otherwise.
|
||||
template <typename TriangleMesh, typename NamedParameters>
|
||||
bool is_degenerate_triangle_face(typename boost::graph_traits<TriangleMesh>::face_descriptor f,
|
||||
const TriangleMesh& tm,
|
||||
const NamedParameters& np)
|
||||
{
|
||||
CGAL_precondition(CGAL::is_triangle(halfedge(f, tm), tm));
|
||||
|
||||
using boost::get_param;
|
||||
using boost::choose_param;
|
||||
|
||||
typedef typename GetVertexPointMap<TriangleMesh, NamedParameters>::const_type VertexPointMap;
|
||||
VertexPointMap vpmap = choose_param(get_param(np, internal_np::vertex_point),
|
||||
get_const_property_map(vertex_point, tm));
|
||||
|
||||
typedef typename GetGeomTraits<TriangleMesh, NamedParameters>::type Traits;
|
||||
Traits traits = choose_param(get_param(np, internal_np::geom_traits), Traits());
|
||||
|
||||
typename boost::graph_traits<TriangleMesh>::halfedge_descriptor h = halfedge(f, tm);
|
||||
|
||||
return traits.collinear_3_object()(get(vpmap, source(h, tm)),
|
||||
get(vpmap, target(h, tm)),
|
||||
get(vpmap, target(next(h, tm), tm)));
|
||||
}
|
||||
|
||||
template <typename TriangleMesh>
|
||||
bool is_degenerate_triangle_face(typename boost::graph_traits<TriangleMesh>::face_descriptor f,
|
||||
const TriangleMesh& tm)
|
||||
{
|
||||
return CGAL::Polygon_mesh_processing::is_degenerate_triangle_face(f, tm, parameters::all_default());
|
||||
}
|
||||
|
||||
/// \ingroup PMP_repairing_grp
|
||||
/// checks whether a triangle face is needle.
|
||||
/// A triangle is said to be a <i>needle</i> if its longest edge is much longer than its shortest edge.
|
||||
///
|
||||
/// @tparam TriangleMesh a model of `FaceGraph`
|
||||
/// @tparam NamedParameters a sequence of \ref pmp_namedparameters "Named Parameters"
|
||||
///
|
||||
/// @param f a triangle face of `tm`
|
||||
/// @param tm triangle mesh containing `f`
|
||||
/// @param threshold a bound on the ratio of the longest edge length and the shortest edge length
|
||||
/// @param np optional \ref pmp_namedparameters "Named Parameters" described below
|
||||
///
|
||||
/// \cgalNamedParamsBegin
|
||||
/// \cgalParamBegin{vertex_point_map} the property map with the points associated to the vertices of `tm`.
|
||||
/// The type of this map is model of `ReadWritePropertyMap`.
|
||||
/// If this parameter is omitted, an internal property map for
|
||||
/// `CGAL::vertex_point_t` should be available in `TriangleMesh`
|
||||
/// \cgalParamEnd
|
||||
/// \cgalParamBegin{geom_traits} a geometric traits class instance.
|
||||
/// The traits class must provide the nested type `FT` and
|
||||
/// the nested functor `Compute_squared_distance_3`.
|
||||
/// \cgalParamEnd
|
||||
/// \cgalNamedParamsEnd
|
||||
///
|
||||
/// \return the shortest halfedge if the triangle face is a needle, and a null halfedge otherwise.
|
||||
/// If the face contains degenerate edges, a halfedge corresponding to one of these edges is returned.
|
||||
template <typename TriangleMesh, typename NamedParameters>
|
||||
typename boost::graph_traits<TriangleMesh>::halfedge_descriptor
|
||||
is_needle_triangle_face(typename boost::graph_traits<TriangleMesh>::face_descriptor f,
|
||||
const TriangleMesh& tm,
|
||||
const double threshold,
|
||||
const NamedParameters& np)
|
||||
{
|
||||
CGAL_precondition(threshold >= 1.);
|
||||
|
||||
using boost::get_param;
|
||||
using boost::choose_param;
|
||||
|
||||
typedef typename boost::graph_traits<TriangleMesh>::halfedge_descriptor halfedge_descriptor;
|
||||
|
||||
typedef typename GetVertexPointMap<TriangleMesh, NamedParameters>::const_type VertexPointMap;
|
||||
VertexPointMap vpmap = choose_param(get_param(np, internal_np::vertex_point),
|
||||
get_const_property_map(vertex_point, tm));
|
||||
|
||||
typedef typename GetGeomTraits<TriangleMesh, NamedParameters>::type Traits;
|
||||
Traits traits = choose_param(get_param(np, internal_np::geom_traits), Traits());
|
||||
|
||||
typedef typename Traits::FT FT;
|
||||
|
||||
CGAL::Halfedge_around_face_iterator<TriangleMesh> hit, hend;
|
||||
boost::tie(hit, hend) = CGAL::halfedges_around_face(halfedge(f, tm), tm);
|
||||
CGAL_precondition(std::distance(hit, hend) == 3);
|
||||
|
||||
const halfedge_descriptor h0 = *hit++;
|
||||
FT sq_length = traits.compute_squared_distance_3_object()(get(vpmap, source(h0, tm)),
|
||||
get(vpmap, target(h0, tm)));
|
||||
|
||||
FT min_sq_length = sq_length, max_sq_length = sq_length;
|
||||
halfedge_descriptor min_h = h0;
|
||||
|
||||
for(; hit!=hend; ++hit)
|
||||
{
|
||||
const halfedge_descriptor h = *hit;
|
||||
sq_length = traits.compute_squared_distance_3_object()(get(vpmap, source(h, tm)),
|
||||
get(vpmap, target(h, tm)));
|
||||
|
||||
if(max_sq_length < sq_length)
|
||||
max_sq_length = sq_length;
|
||||
|
||||
if(min_sq_length > sq_length)
|
||||
{
|
||||
min_h = h;
|
||||
min_sq_length = sq_length;
|
||||
}
|
||||
}
|
||||
|
||||
if(min_sq_length == 0)
|
||||
return min_h;
|
||||
|
||||
const FT sq_threshold = threshold * threshold;
|
||||
if(max_sq_length / min_sq_length >= sq_threshold)
|
||||
{
|
||||
CGAL_assertion(min_h != boost::graph_traits<TriangleMesh>::null_halfedge());
|
||||
return min_h;
|
||||
}
|
||||
else
|
||||
return boost::graph_traits<TriangleMesh>::null_halfedge();
|
||||
}
|
||||
|
||||
template <typename TriangleMesh>
|
||||
typename boost::graph_traits<TriangleMesh>::halfedge_descriptor
|
||||
is_needle_triangle_face(typename boost::graph_traits<TriangleMesh>::face_descriptor f,
|
||||
const TriangleMesh& tm,
|
||||
const double threshold)
|
||||
{
|
||||
return is_needle_triangle_face(f, tm, threshold, parameters::all_default());
|
||||
}
|
||||
|
||||
/// \ingroup PMP_repairing_grp
|
||||
/// checks whether a triangle face is a cap.
|
||||
/// A triangle is said to be a <i>cap</i> if one of the its angles is close to `180` degrees.
|
||||
///
|
||||
/// @tparam TriangleMesh a model of `FaceGraph`
|
||||
/// @tparam NamedParameters a sequence of \ref pmp_namedparameters "Named Parameters"
|
||||
///
|
||||
/// @param f a triangle face of `tm`
|
||||
/// @param tm triangle mesh containing `f`
|
||||
/// @param threshold the cosine of a minimum angle such that if `f` has an angle greater than this bound,
|
||||
/// it is a cap. The threshold is in range `[-1 0]` and corresponds to an angle
|
||||
/// between `90` and `180` degrees.
|
||||
/// @param np optional \ref pmp_namedparameters "Named Parameters" described below
|
||||
///
|
||||
/// \cgalNamedParamsBegin
|
||||
/// \cgalParamBegin{vertex_point_map} the property map with the points associated to the vertices of `tm`.
|
||||
/// The type of this map is model of `ReadWritePropertyMap`.
|
||||
/// If this parameter is omitted, an internal property map for
|
||||
/// `CGAL::vertex_point_t` should be available in `TriangleMesh`
|
||||
/// \cgalParamEnd
|
||||
/// \cgalParamBegin{geom_traits} a geometric traits class instance.
|
||||
/// The traits class must provide the nested type `Point_3` and
|
||||
/// the nested functors `Compute_squared_distance_3`, `Construct_vector_3`,
|
||||
/// and `Compute_scalar_product_3`.
|
||||
/// \cgalParamEnd
|
||||
/// \cgalNamedParamsEnd
|
||||
///
|
||||
/// \return the halfedge opposite of the largest angle if the face is a cap, and a null halfedge otherwise.
|
||||
template <typename TriangleMesh, typename NamedParameters>
|
||||
typename boost::graph_traits<TriangleMesh>::halfedge_descriptor
|
||||
is_cap_triangle_face(typename boost::graph_traits<TriangleMesh>::face_descriptor f,
|
||||
const TriangleMesh& tm,
|
||||
const double threshold,
|
||||
const NamedParameters& np)
|
||||
{
|
||||
CGAL_precondition(CGAL::is_triangle_mesh(tm));
|
||||
CGAL_precondition(threshold >= -1.);
|
||||
CGAL_precondition(threshold <= 0.);
|
||||
|
||||
using boost::get_param;
|
||||
using boost::choose_param;
|
||||
|
||||
typedef typename boost::graph_traits<TriangleMesh>::vertex_descriptor vertex_descriptor;
|
||||
typedef typename boost::graph_traits<TriangleMesh>::halfedge_descriptor halfedge_descriptor;
|
||||
|
||||
typedef typename GetVertexPointMap<TriangleMesh, NamedParameters>::const_type VertexPointMap;
|
||||
VertexPointMap vpmap = choose_param(get_param(np, internal_np::vertex_point),
|
||||
get_const_property_map(vertex_point, tm));
|
||||
|
||||
typedef typename GetGeomTraits<TriangleMesh, NamedParameters>::type Traits;
|
||||
Traits traits = choose_param(get_param(np, internal_np::geom_traits), Traits());
|
||||
|
||||
typedef typename Traits::FT FT;
|
||||
typedef typename Traits::Vector_3 Vector_3;
|
||||
|
||||
const FT sq_threshold = threshold * threshold;
|
||||
const halfedge_descriptor h0 = halfedge(f, tm);
|
||||
|
||||
cpp11::array<FT, 3> sq_lengths;
|
||||
int pos = 0;
|
||||
BOOST_FOREACH(halfedge_descriptor h, halfedges_around_face(h0, tm))
|
||||
{
|
||||
const FT sq_d = traits.compute_squared_distance_3_object()(get(vpmap, source(h, tm)),
|
||||
get(vpmap, target(h, tm)));
|
||||
|
||||
// If even one edge is degenerate, it cannot be a cap
|
||||
if(sq_d == 0)
|
||||
return boost::graph_traits<TriangleMesh>::null_halfedge();
|
||||
|
||||
sq_lengths[pos++] = sq_d;
|
||||
}
|
||||
|
||||
pos = 0;
|
||||
BOOST_FOREACH(halfedge_descriptor h, halfedges_around_face(h0, tm))
|
||||
{
|
||||
const vertex_descriptor v0 = source(h, tm);
|
||||
const vertex_descriptor v1 = target(h, tm);
|
||||
const vertex_descriptor v2 = target(next(h, tm), tm);
|
||||
const Vector_3 a = traits.construct_vector_3_object()(get(vpmap, v1), get(vpmap, v2));
|
||||
const Vector_3 b = traits.construct_vector_3_object()(get(vpmap, v1), get(vpmap, v0));
|
||||
const FT dot_ab = traits.compute_scalar_product_3_object()(a, b);
|
||||
const bool neg_sp = (dot_ab <= 0);
|
||||
const FT sq_a = sq_lengths[(pos+1)%3];
|
||||
const FT sq_b = sq_lengths[pos];
|
||||
const FT sq_cos = dot_ab * dot_ab / (sq_a * sq_b);
|
||||
|
||||
if(neg_sp && sq_cos >= sq_threshold)
|
||||
return prev(h, tm);
|
||||
|
||||
++pos;
|
||||
}
|
||||
return boost::graph_traits<TriangleMesh>::null_halfedge();
|
||||
}
|
||||
|
||||
template <typename TriangleMesh>
|
||||
typename boost::graph_traits<TriangleMesh>::halfedge_descriptor
|
||||
is_cap_triangle_face(typename boost::graph_traits<TriangleMesh>::face_descriptor f,
|
||||
const TriangleMesh& tm,
|
||||
const double threshold)
|
||||
{
|
||||
return is_cap_triangle_face(f, tm, threshold, parameters::all_default());
|
||||
}
|
||||
|
||||
} } // end namespaces CGAL and PMP
|
||||
|
||||
#endif // CGAL_POLYGON_MESH_PROCESSING_SHAPE_PREDICATES_H
|
||||
|
|
@ -49,6 +49,8 @@
|
|||
#include <CGAL/Polygon_mesh_processing/distance.h>
|
||||
#include <CGAL/Polygon_mesh_processing/intersection.h>
|
||||
#include <CGAL/Polygon_mesh_processing/transform.h>
|
||||
#include <CGAL/Polygon_mesh_processing/shape_predicates.h>
|
||||
#include <CGAL/Polygon_mesh_processing/merge_border_vertices.h>
|
||||
|
||||
// the named parameter header being not documented the doc is put here for now
|
||||
#ifdef DOXYGEN_RUNNING
|
||||
|
|
|
|||
|
|
@ -101,6 +101,8 @@ endif()
|
|||
create_single_source_cgal_program("test_orient_cc.cpp")
|
||||
create_single_source_cgal_program("test_pmp_transform.cpp")
|
||||
create_single_source_cgal_program("extrude_test.cpp")
|
||||
create_single_source_cgal_program("test_merging_border_vertices.cpp")
|
||||
create_single_source_cgal_program("test_shape_predicates.cpp")
|
||||
|
||||
if( TBB_FOUND )
|
||||
CGAL_target_use_TBB(test_pmp_distance)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,95 @@
|
|||
OFF
|
||||
47 45 0
|
||||
|
||||
-0.026804100000000001 -0.30492799999999998 0.142542
|
||||
-0.018234400000000001 -0.28125499999999998 0.15192700000000001
|
||||
-0.074329900000000004 -0.27701599999999998 0.17852999999999999
|
||||
-0.075232300000000002 -0.238787 0.19677600000000001
|
||||
-0.092496499999999995 -0.26196000000000003 0.18681900000000001
|
||||
-0.107975 -0.220055 0.202264
|
||||
-0.098042799999999999 -0.24015500000000001 0.197738
|
||||
-0.076830499999999996 -0.20389099999999999 0.20217599999999999
|
||||
-0.10664999999999999 -0.18507100000000001 0.204627
|
||||
-0.048507700000000001 -0.30671799999999999 0.14971999999999999
|
||||
-0.10985300000000001 -0.27012399999999998 0.16877500000000001
|
||||
0.020159400000000001 -0.26358599999999999 0.11985899999999999
|
||||
-0.0820192 -0.303394 0.145977
|
||||
-0.11151800000000001 -0.28692499999999999 0.148566
|
||||
0.033791700000000001 -0.209923 0.115845
|
||||
0.019949499999999998 -0.19298699999999999 0.125832
|
||||
0.00080011299999999997 -0.19967099999999999 0.13874900000000001
|
||||
0.0102764 -0.16375000000000001 0.13344700000000001
|
||||
0.015325999999999999 -0.12934699999999999 0.14213100000000001
|
||||
0.043303899999999999 -0.239647 0.099889199999999997
|
||||
-0.010328800000000001 -0.10643 0.14183100000000001
|
||||
-0.032521000000000001 -0.10838299999999999 0.13683899999999999
|
||||
-0.085985000000000006 -0.101282 0.15809300000000001
|
||||
-0.108849 -0.11043600000000001 0.16941700000000001
|
||||
-0.052558500000000001 -0.097836599999999996 0.13975499999999999
|
||||
-0.10316599999999999 -0.15746599999999999 0.19631499999999999
|
||||
-0.112763 -0.133107 0.183753
|
||||
-0.063495300000000005 -0.15489 0.17952499999999999
|
||||
-0.064211199999999996 -0.12604799999999999 0.16286
|
||||
-0.086169300000000004 -0.13996600000000001 0.183699
|
||||
-0.063495300000000005 -0.15489 0.17952499999999999
|
||||
-0.023309900000000001 -0.17152600000000001 0.15354100000000001
|
||||
-0.0254547 -0.133829 0.14063300000000001
|
||||
-0.079254099999999994 -0.17391000000000001 0.197354
|
||||
-0.0458796 -0.210094 0.18626999999999999
|
||||
-0.063495300000000005 -0.15489 0.17952499999999999
|
||||
-0.0097084900000000002 -0.22793099999999999 0.15407299999999999
|
||||
-0.0458796 -0.210094 0.18626999999999999
|
||||
-0.0458796 -0.210094 0.18626999999999999
|
||||
-0.075232300000000002 -0.238787 0.19677600000000001
|
||||
-0.049308200000000003 -0.25528899999999999 0.18343899999999999
|
||||
-0.0218198 -0.25775500000000001 0.16445000000000001
|
||||
-0.049308200000000003 -0.25528899999999999 0.18343899999999999
|
||||
-0.041782300000000001 -0.28198800000000002 0.16825000000000001
|
||||
0.00026201499999999999 -0.25824399999999997 0.14286599999999999
|
||||
0.015174200000000001 -0.229959 0.128466
|
||||
-0.0097084900000000002 -0.22793099999999999 0.15407299999999999
|
||||
3 43 0 1
|
||||
3 2 3 4
|
||||
3 5 6 3
|
||||
3 7 5 3
|
||||
3 5 7 8
|
||||
3 0 43 9
|
||||
3 10 2 4
|
||||
3 1 44 41
|
||||
3 11 45 44
|
||||
3 12 9 2
|
||||
3 13 12 2
|
||||
3 14 15 45
|
||||
3 16 45 15
|
||||
3 43 1 41
|
||||
3 17 16 15
|
||||
3 16 31 36
|
||||
3 31 16 17
|
||||
3 17 18 32
|
||||
3 11 19 45
|
||||
3 43 2 9
|
||||
3 18 20 32
|
||||
3 20 21 32
|
||||
3 13 2 10
|
||||
3 29 28 22
|
||||
3 45 19 14
|
||||
3 23 29 22
|
||||
3 24 22 28
|
||||
3 21 24 28
|
||||
3 32 21 28
|
||||
3 33 29 25
|
||||
3 8 33 25
|
||||
3 8 7 33
|
||||
3 26 29 23
|
||||
3 34 33 7
|
||||
3 25 29 26
|
||||
3 4 3 6
|
||||
3 31 17 32
|
||||
3 29 27 28
|
||||
3 32 30 31
|
||||
3 34 35 33
|
||||
3 31 37 36
|
||||
3 40 38 39
|
||||
3 41 42 43
|
||||
3 45 46 44
|
||||
3 44 46 41
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
OFF
|
||||
8 8 0
|
||||
0 1 0
|
||||
1 0 0
|
||||
0 0 0
|
||||
0 0 1
|
||||
2 1 0
|
||||
2 0 0
|
||||
2 0 -1
|
||||
1 0 0
|
||||
3 0 1 2
|
||||
3 2 3 0
|
||||
3 1 3 2
|
||||
3 0 3 1
|
||||
3 7 5 4
|
||||
3 7 6 5
|
||||
3 4 6 7
|
||||
3 5 6 4
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
OFF
|
||||
9 3 0
|
||||
0 0 0
|
||||
1 0 0
|
||||
1 1 0
|
||||
0 0 1
|
||||
1 0 1
|
||||
10 10 1
|
||||
0 0 2
|
||||
1 0 2
|
||||
-0.99619469809 0.08715574274 2
|
||||
3 0 1 2
|
||||
3 3 4 5
|
||||
3 6 7 8
|
||||
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
OFF
|
||||
3 1 0
|
||||
0 0 0
|
||||
1 0 0
|
||||
0 0 0
|
||||
3 0 1 2
|
||||
|
|
@ -11,11 +11,34 @@
|
|||
//the last test (on trihole.off) does not terminate
|
||||
//
|
||||
|
||||
typedef CGAL::Exact_predicates_inexact_constructions_kernel K;
|
||||
namespace PMP = CGAL::Polygon_mesh_processing;
|
||||
|
||||
typedef CGAL::Surface_mesh<K::Point_3> Surface_mesh;
|
||||
typedef CGAL::Exact_predicates_inexact_constructions_kernel K;
|
||||
|
||||
void fix(const char* fname)
|
||||
typedef CGAL::Surface_mesh<K::Point_3> Surface_mesh;
|
||||
|
||||
typedef boost::graph_traits<Surface_mesh>::edge_descriptor edge_descriptor;
|
||||
typedef boost::graph_traits<Surface_mesh>::face_descriptor face_descriptor;
|
||||
|
||||
void detect_degeneracies(const Surface_mesh& mesh)
|
||||
{
|
||||
std::vector<face_descriptor> dfaces;
|
||||
|
||||
PMP::degenerate_faces(mesh, std::back_inserter(dfaces));
|
||||
PMP::degenerate_faces(faces(mesh), mesh, std::back_inserter(dfaces));
|
||||
PMP::degenerate_faces(mesh, std::back_inserter(dfaces), CGAL::parameters::all_default());
|
||||
PMP::degenerate_faces(faces(mesh), mesh, std::back_inserter(dfaces), CGAL::parameters::all_default());
|
||||
assert(!dfaces.empty());
|
||||
|
||||
std::set<edge_descriptor> dedges;
|
||||
PMP::degenerate_edges(mesh, std::inserter(dedges, dedges.end()));
|
||||
PMP::degenerate_edges(edges(mesh), mesh, std::inserter(dedges, dedges.begin()));
|
||||
PMP::degenerate_edges(mesh, std::inserter(dedges, dedges.end()), CGAL::parameters::all_default());
|
||||
PMP::degenerate_edges(edges(mesh), mesh, std::inserter(dedges, dedges.begin()), CGAL::parameters::all_default());
|
||||
assert(dedges.empty());
|
||||
}
|
||||
|
||||
void fix_degeneracies(const char* fname)
|
||||
{
|
||||
std::ifstream input(fname);
|
||||
|
||||
|
|
@ -24,20 +47,22 @@ void fix(const char* fname)
|
|||
std::cerr << fname << " is not a valid off file.\n";
|
||||
exit(1);
|
||||
}
|
||||
CGAL::Polygon_mesh_processing::remove_degenerate_faces(mesh);
|
||||
|
||||
detect_degeneracies(mesh);
|
||||
|
||||
CGAL::Polygon_mesh_processing::remove_degenerate_faces(mesh);
|
||||
assert( CGAL::is_valid_polygon_mesh(mesh) );
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
fix("data_degeneracies/degtri_2dt_1edge_split_twice.off");
|
||||
fix("data_degeneracies/degtri_four-2.off");
|
||||
fix("data_degeneracies/degtri_four.off");
|
||||
fix("data_degeneracies/degtri_on_border.off");
|
||||
fix("data_degeneracies/degtri_three.off");
|
||||
fix("data_degeneracies/degtri_single.off");
|
||||
fix("data_degeneracies/trihole.off");
|
||||
fix_degeneracies("data_degeneracies/degtri_2dt_1edge_split_twice.off");
|
||||
fix_degeneracies("data_degeneracies/degtri_four-2.off");
|
||||
fix_degeneracies("data_degeneracies/degtri_four.off");
|
||||
fix_degeneracies("data_degeneracies/degtri_on_border.off");
|
||||
fix_degeneracies("data_degeneracies/degtri_three.off");
|
||||
fix_degeneracies("data_degeneracies/degtri_single.off");
|
||||
fix_degeneracies("data_degeneracies/trihole.off");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,27 +4,19 @@ GREEN="\\033[1;32m"
|
|||
NORMAL="\\033[0;39m"
|
||||
RED="\\033[1;31m"
|
||||
|
||||
METHOD="SM"
|
||||
|
||||
if [ ! -e $1 ""]; then
|
||||
METHOD=$1
|
||||
fi
|
||||
|
||||
echo "Testing with $METHOD"
|
||||
|
||||
k=`wc -l test_corefinement_bool_op_full.cmd | awk '{print $1}'`
|
||||
|
||||
for i in `seq 1 $k`; do
|
||||
files=`head -n $i test_corefinement_bool_op_full.cmd | tail -n 1`
|
||||
f1=`echo $files | awk '{print $1}'`
|
||||
f2=`echo $files | awk '{print $2}'`
|
||||
ru=`echo $files | awk '{print $5}'`
|
||||
ri=`echo $files | awk '{print $6}'`
|
||||
rm=`echo $files | awk '{print $7}'`
|
||||
rmr=`echo $files | awk '{print $8}'`
|
||||
ru=`echo $files | awk '{print $4}'`
|
||||
ri=`echo $files | awk '{print $5}'`
|
||||
rm=`echo $files | awk '{print $6}'`
|
||||
rmr=`echo $files | awk '{print $7}'`
|
||||
echo -n "==== " $f1 $f2 " "
|
||||
|
||||
if (./test_corefinement_bool_op $f1 $f2 $METHOD ALL $ru $ri $rm $rmr|| false ) > /dev/null 2>&1; then
|
||||
if (./test_corefinement_bool_op $f1 $f2 ALL $ru $ri $rm $rmr|| false ) > /dev/null 2>&1; then
|
||||
echo -e " ==> $GREEN SUCCEED"
|
||||
echo -e -n "$NORMAL"
|
||||
else
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
data-coref/elephant.off data-coref/sphere.off SM ALL 1 1 1 1
|
||||
data-coref/elephant.off data-coref/sphere.off ALL 1 1 1 1
|
||||
|
|
|
|||
|
|
@ -1,23 +1,15 @@
|
|||
// #define CGAL_COREFINEMENT_POLYHEDRA_DEBUG
|
||||
// #define CGAL_COREFINEMENT_DEBUG
|
||||
// #define CGAL_TODO_WARNINGS
|
||||
|
||||
#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
|
||||
#include <CGAL/Surface_mesh.h>
|
||||
#include <CGAL/Polygon_mesh_processing/corefinement.h>
|
||||
|
||||
#include <CGAL/Polyhedron_3.h>
|
||||
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
#include <fstream>
|
||||
#include <sstream>
|
||||
|
||||
// includes for Operations on polyhedra
|
||||
#include <CGAL/intersection_of_Polyhedra_3.h>
|
||||
#include <CGAL/intersection_of_Polyhedra_3_refinement_visitor.h>
|
||||
#include <CGAL/internal/corefinement/Polyhedra_output_builder.h>
|
||||
|
||||
#include <CGAL/iterator.h>
|
||||
#include <CGAL/array.h>
|
||||
|
||||
|
|
@ -28,16 +20,6 @@ typedef CGAL::Surface_mesh<Kernel::Point_3> Surface_mesh;
|
|||
namespace PMP = CGAL::Polygon_mesh_processing;
|
||||
namespace CFR = PMP::Corefinement;
|
||||
|
||||
//includes typedefs for Operations on polyhedra
|
||||
typedef CGAL::Polyhedron_3<Kernel> Polyhedron;
|
||||
typedef std::map<Polyhedron::Facet_const_handle,std::size_t> Facet_id_map;
|
||||
typedef boost::associative_property_map<Facet_id_map> Facet_id_pmap;
|
||||
typedef CGAL::Corefinement
|
||||
::Polyhedra_output_builder< Polyhedron,
|
||||
Facet_id_pmap> Output_builder;
|
||||
typedef CGAL::Node_visitor_refine_polyhedra<Polyhedron,
|
||||
Output_builder&> Split_visitor;
|
||||
|
||||
struct Result_checking
|
||||
{
|
||||
bool check;
|
||||
|
|
@ -49,111 +31,6 @@ struct Result_checking
|
|||
Result_checking() : check(false) {}
|
||||
};
|
||||
|
||||
void run_boolean_operations(
|
||||
Polyhedron& P,
|
||||
Polyhedron& Q,
|
||||
Polyhedron& union_,
|
||||
Polyhedron& inter,
|
||||
Polyhedron& P_minus_Q,
|
||||
Polyhedron& Q_minus_P,
|
||||
std::string scenario,
|
||||
std::size_t id,
|
||||
const Result_checking& rc)
|
||||
{
|
||||
std::cout << "Scenario #" << id << " - " << scenario << "\n";
|
||||
|
||||
CGAL::Emptyset_iterator output_it;
|
||||
Facet_id_map P_facet_id_map, Q_facet_id_map;
|
||||
|
||||
CGAL::cpp11::array<boost::optional<Polyhedron*>, 4 > output;
|
||||
|
||||
output[Output_builder::P_UNION_Q]=boost::make_optional( &union_ );
|
||||
output[Output_builder::P_INTER_Q]=boost::make_optional( &inter );
|
||||
output[Output_builder::P_MINUS_Q]=boost::make_optional( &P_minus_Q );
|
||||
output[Output_builder::Q_MINUS_P]=boost::make_optional( &Q_minus_P );
|
||||
|
||||
Output_builder output_builder(P, Q,
|
||||
output,
|
||||
Facet_id_pmap(P_facet_id_map),
|
||||
Facet_id_pmap(Q_facet_id_map) );
|
||||
Split_visitor visitor(output_builder);
|
||||
|
||||
CGAL::Intersection_of_Polyhedra_3<Polyhedron,Kernel,Split_visitor> polyline_intersections(visitor);
|
||||
std::cout << " Vertices before " << P.size_of_vertices()
|
||||
<< " " << Q.size_of_vertices() << std::endl;
|
||||
polyline_intersections(P, Q, output_it);
|
||||
std::cout << " Vertices after " << P.size_of_vertices()
|
||||
<< " " << Q.size_of_vertices() << std::endl;
|
||||
|
||||
|
||||
if ( output_builder.union_valid() ){
|
||||
std::cout << " Union is a valid operation\n";
|
||||
assert(union_.is_valid());
|
||||
#ifdef CGAL_COREFINEMENT_DEBUG
|
||||
std::stringstream fname;
|
||||
fname << scenario << "_P_union_Q.off";
|
||||
std::ofstream output(fname.str().c_str());
|
||||
output << std::setprecision(17) << union_;
|
||||
#endif
|
||||
}
|
||||
else
|
||||
std::cout << " Union is invalid\n";
|
||||
|
||||
if ( output_builder.intersection_valid() ){
|
||||
std::cout << " Intersection is a valid operation\n";
|
||||
assert(inter.is_valid());
|
||||
#ifdef CGAL_COREFINEMENT_DEBUG
|
||||
std::stringstream fname;
|
||||
fname << scenario << "_P_inter_Q.off";
|
||||
std::ofstream output(fname.str().c_str());
|
||||
output << std::setprecision(17) << inter;
|
||||
#endif
|
||||
}
|
||||
else
|
||||
std::cout << " Intersection is invalid\n";
|
||||
|
||||
if ( output_builder.P_minus_Q_valid() ){
|
||||
std::cout << " P-Q is a valid operation\n";
|
||||
assert(P_minus_Q.is_valid());
|
||||
#ifdef CGAL_COREFINEMENT_DEBUG
|
||||
std::stringstream fname;
|
||||
fname << scenario << "_P_minus_Q.off";
|
||||
std::ofstream output(fname.str().c_str());
|
||||
output << std::setprecision(17) << P_minus_Q;
|
||||
#endif
|
||||
}
|
||||
else
|
||||
std::cout << " P-Q is invalid\n";
|
||||
|
||||
if ( output_builder.Q_minus_P_valid() ){
|
||||
std::cout << " Q-P is a valid operation\n";
|
||||
assert(Q_minus_P.is_valid());
|
||||
#ifdef CGAL_COREFINEMENT_DEBUG
|
||||
std::stringstream fname;
|
||||
fname << scenario << "_Q_minus_P.off";
|
||||
std::ofstream output(fname.str().c_str());
|
||||
output << std::setprecision(17) << Q_minus_P;
|
||||
#endif
|
||||
}
|
||||
else
|
||||
std::cout << " Q-P is invalid\n";
|
||||
|
||||
if (rc.check)
|
||||
{
|
||||
if(output_builder.union_valid()!=rc.union_res ||
|
||||
output_builder.intersection_valid()!=rc.inter_res ||
|
||||
output_builder.P_minus_Q_valid()!=rc.P_minus_Q_res ||
|
||||
output_builder.Q_minus_P_valid()!=rc.Q_minus_P_res)
|
||||
{
|
||||
std::cerr << " ERROR: at least one operation is not as expected!\n";
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
else
|
||||
std::cout << " All operations are as expected.\n";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void run_boolean_operations(
|
||||
Surface_mesh& tm1,
|
||||
Surface_mesh& tm2,
|
||||
|
|
@ -344,34 +221,26 @@ void run(char* P_fname, char* Q_fname, int k,
|
|||
int main(int argc,char** argv)
|
||||
{
|
||||
if (argc<3){
|
||||
std::cerr << "Usage "<< argv[0] << " file1.off file2.off [SM/POLY] [scenario_id/ALL] [0/1 0/1 0/1 0/1 (expected valid operations U I P-Q Q-P)]\n";
|
||||
std::cerr << "Usage "<< argv[0] << " file1.off file2.off [scenario_id/ALL] [0/1 0/1 0/1 0/1 (expected valid operations U I P-Q Q-P)]\n";
|
||||
return 1;
|
||||
}
|
||||
|
||||
Result_checking rc;
|
||||
|
||||
if (argc==9)
|
||||
if (argc==8)
|
||||
{
|
||||
rc.check=true;
|
||||
rc.union_res = atoi(argv[5])!=0;
|
||||
rc.inter_res = atoi(argv[6])!=0;
|
||||
rc.P_minus_Q_res = atoi(argv[7])!=0;
|
||||
rc.Q_minus_P_res = atoi(argv[8])!=0;
|
||||
rc.union_res = atoi(argv[4])!=0;
|
||||
rc.inter_res = atoi(argv[5])!=0;
|
||||
rc.P_minus_Q_res = atoi(argv[6])!=0;
|
||||
rc.Q_minus_P_res = atoi(argv[7])!=0;
|
||||
}
|
||||
|
||||
int scenario = -1;
|
||||
if (argc>=5 && std::string(argv[4])!=std::string("ALL"))
|
||||
if (argc>=5 && std::string(argv[3])!=std::string("ALL"))
|
||||
scenario = atoi(argv[4]);
|
||||
|
||||
if ( argc==3 || std::string(argv[3])==std::string("SM") )
|
||||
run<Surface_mesh>(argv[1], argv[2], scenario, rc);
|
||||
else
|
||||
if ( std::string(argv[3])==std::string("POLY") )
|
||||
run<Polyhedron>(argv[1], argv[2], scenario, rc);
|
||||
else
|
||||
{
|
||||
std::cout <<"Invalid value, only SM or POLY can be given\n";
|
||||
return 1;
|
||||
}
|
||||
run<Surface_mesh>(argv[1], argv[2], scenario, rc);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,49 +1,49 @@
|
|||
data-coref/sphere.off data-coref/sphere-2.off SM ALL 1 1 1 1
|
||||
data-coref/cube.off data-coref/coplanar_with_cube.off SM ALL 1 1 1 1
|
||||
data-coref/cube.off data-coref/coplanar_with_cube1.off SM ALL 1 1 1 1
|
||||
data-coref/cube.off data-coref/coplanar_with_cube2.off SM ALL 1 1 1 1
|
||||
data-coref/cube.off data-coref/with_cube.off SM ALL 1 1 1 0
|
||||
data-coref/open_large_cube.off data-coref/open_small_cube.off SM ALL 1 1 1 1
|
||||
data-coref/open_large_cube.off data-coref/open_small_cube_inout.off SM ALL 0 0 0 0
|
||||
data-coref/elephant.off data-coref/elephant_plane/plane_1.off SM ALL 1 1 1 1
|
||||
data-coref/elephant.off data-coref/elephant_plane/plane_2.off SM ALL 1 1 1 1
|
||||
data-coref/elephant.off data-coref/elephant_plane/plane_3.off SM ALL 1 1 1 1
|
||||
data-coref/open_tet_1.off data-coref/open_tet_2.off SM ALL 1 1 1 1
|
||||
data-coref/small_cube_coplanar_inside.off data-coref/small_cube_coplanar_outside.off SM ALL 1 1 1 1
|
||||
data-coref/large_cube_coplanar.off data-coref/small_cube_coplanar_inside.off SM ALL 1 1 1 1
|
||||
data-coref/large_cube_coplanar.off data-coref/small_cube_coplanar_outside.off SM ALL 1 1 1 1
|
||||
data-coref/P7.off data-coref/Q7.off SM ALL 1 1 1 1
|
||||
data-coref/square1.off data-coref/square2.off SM ALL 1 1 1 1
|
||||
data-coref/square_pair.off data-coref/square2.off SM ALL 1 1 1 1
|
||||
data-coref/elephant.off data-coref/sphere.off SM ALL 1 1 1 1
|
||||
data-coref/elephant_split_1.off data-coref/elephant_split_2.off SM ALL 1 1 1 1
|
||||
data-coref/cube.off data-coref/cube_on_cube_edge.off SM ALL 0 1 1 1
|
||||
data-coref/cube.off data-coref/cube_on_cube_corner.off SM ALL 1 1 1 1
|
||||
data-coref/cow.off data-coref/cross.off SM ALL 1 1 1 1
|
||||
data-coref/sphere.off data-coref/sphere_trans_cut.off SM ALL 0 0 0 0
|
||||
data-coref/open_t11.off data-coref/open_t12.off SM ALL 1 1 1 1
|
||||
data-coref/cube.off data-coref/coplanar_with_cube3.off SM ALL 1 1 1 1
|
||||
data-coref/cube.off data-coref/coplanar_with_cube4.off SM ALL 1 1 1 1
|
||||
data-coref/square1.off data-coref/square_pair.off SM ALL 1 1 1 1
|
||||
data-coref/cube_meshed.off data-coref/cube.off SM ALL 1 1 1 1
|
||||
data-coref/cube.off data-coref/cube_interior_tgt.off SM ALL 1 1 1 1
|
||||
data-coref/cube.off data-coref/edge_tangent_to_cube.off SM ALL 1 1 0 1
|
||||
data-coref/cube_dig.off data-coref/wedge.off SM ALL 1 1 1 1
|
||||
data-coref/star_tgt1-0.off data-coref/star_tgt2-0.off SM ALL 1 1 1 0
|
||||
data-coref/star_tgt1-0.off data-coref/star_tgt2-1.off SM ALL 1 1 1 0
|
||||
data-coref/star_tgt1-0.off data-coref/star_tgt2-2.off SM ALL 0 1 1 1
|
||||
data-coref/star_tgt1-0.off data-coref/star_tgt2-3.off SM ALL 1 1 1 0
|
||||
data-coref/star_tgt1-0.off data-coref/star_tgt2-4.off SM ALL 0 1 1 1
|
||||
data-coref/star_tgt1-0.off data-coref/star_tgt2-5.off SM ALL 1 1 1 0
|
||||
data-coref/star_tgt1-1.off data-coref/star_tgt2-0.off SM ALL 1 1 1 0
|
||||
data-coref/star_tgt1-1.off data-coref/star_tgt2-1.off SM ALL 1 1 1 0
|
||||
data-coref/star_tgt1-1.off data-coref/star_tgt2-2.off SM ALL 0 1 1 1
|
||||
data-coref/star_tgt1-1.off data-coref/star_tgt2-3.off SM ALL 1 1 1 0
|
||||
data-coref/star_tgt1-1.off data-coref/star_tgt2-4.off SM ALL 0 1 1 1
|
||||
data-coref/star_tgt1-1.off data-coref/star_tgt2-5.off SM ALL 1 1 1 0
|
||||
data-coref/star_tgt1-2.off data-coref/star_tgt2-0.off SM ALL 1 1 1 0
|
||||
data-coref/star_tgt1-2.off data-coref/star_tgt2-1.off SM ALL 1 1 1 0
|
||||
data-coref/star_tgt1-2.off data-coref/star_tgt2-2.off SM ALL 0 1 1 1
|
||||
data-coref/star_tgt1-2.off data-coref/star_tgt2-3.off SM ALL 1 1 1 1
|
||||
data-coref/star_tgt1-2.off data-coref/star_tgt2-4.off SM ALL 0 1 1 1
|
||||
data-coref/star_tgt1-2.off data-coref/star_tgt2-5.off SM ALL 1 1 1 1
|
||||
data-coref/sphere.off data-coref/sphere-2.off ALL 1 1 1 1
|
||||
data-coref/cube.off data-coref/coplanar_with_cube.off ALL 1 1 1 1
|
||||
data-coref/cube.off data-coref/coplanar_with_cube1.off ALL 1 1 1 1
|
||||
data-coref/cube.off data-coref/coplanar_with_cube2.off ALL 1 1 1 1
|
||||
data-coref/cube.off data-coref/with_cube.off ALL 1 1 1 0
|
||||
data-coref/open_large_cube.off data-coref/open_small_cube.off ALL 1 1 1 1
|
||||
data-coref/open_large_cube.off data-coref/open_small_cube_inout.off ALL 0 0 0 0
|
||||
data-coref/elephant.off data-coref/elephant_plane/plane_1.off ALL 1 1 1 1
|
||||
data-coref/elephant.off data-coref/elephant_plane/plane_2.off ALL 1 1 1 1
|
||||
data-coref/elephant.off data-coref/elephant_plane/plane_3.off ALL 1 1 1 1
|
||||
data-coref/open_tet_1.off data-coref/open_tet_2.off ALL 1 1 1 1
|
||||
data-coref/small_cube_coplanar_inside.off data-coref/small_cube_coplanar_outside.off ALL 1 1 1 1
|
||||
data-coref/large_cube_coplanar.off data-coref/small_cube_coplanar_inside.off ALL 1 1 1 1
|
||||
data-coref/large_cube_coplanar.off data-coref/small_cube_coplanar_outside.off ALL 1 1 1 1
|
||||
data-coref/P7.off data-coref/Q7.off ALL 1 1 1 1
|
||||
data-coref/square1.off data-coref/square2.off ALL 1 1 1 1
|
||||
data-coref/square_pair.off data-coref/square2.off ALL 1 1 1 1
|
||||
data-coref/elephant.off data-coref/sphere.off ALL 1 1 1 1
|
||||
data-coref/elephant_split_1.off data-coref/elephant_split_2.off ALL 1 1 1 1
|
||||
data-coref/cube.off data-coref/cube_on_cube_edge.off ALL 0 1 1 1
|
||||
data-coref/cube.off data-coref/cube_on_cube_corner.off ALL 1 1 1 1
|
||||
data-coref/cow.off data-coref/cross.off ALL 1 1 1 1
|
||||
data-coref/sphere.off data-coref/sphere_trans_cut.off ALL 0 0 0 0
|
||||
data-coref/open_t11.off data-coref/open_t12.off ALL 1 1 1 1
|
||||
data-coref/cube.off data-coref/coplanar_with_cube3.off ALL 1 1 1 1
|
||||
data-coref/cube.off data-coref/coplanar_with_cube4.off ALL 1 1 1 1
|
||||
data-coref/square1.off data-coref/square_pair.off ALL 1 1 1 1
|
||||
data-coref/cube_meshed.off data-coref/cube.off ALL 1 1 1 1
|
||||
data-coref/cube.off data-coref/cube_interior_tgt.off ALL 1 1 1 1
|
||||
data-coref/cube.off data-coref/edge_tangent_to_cube.off ALL 1 1 0 1
|
||||
data-coref/cube_dig.off data-coref/wedge.off ALL 1 1 1 1
|
||||
data-coref/star_tgt1-0.off data-coref/star_tgt2-0.off ALL 1 1 1 0
|
||||
data-coref/star_tgt1-0.off data-coref/star_tgt2-1.off ALL 1 1 1 0
|
||||
data-coref/star_tgt1-0.off data-coref/star_tgt2-2.off ALL 0 1 1 1
|
||||
data-coref/star_tgt1-0.off data-coref/star_tgt2-3.off ALL 1 1 1 0
|
||||
data-coref/star_tgt1-0.off data-coref/star_tgt2-4.off ALL 0 1 1 1
|
||||
data-coref/star_tgt1-0.off data-coref/star_tgt2-5.off ALL 1 1 1 0
|
||||
data-coref/star_tgt1-1.off data-coref/star_tgt2-0.off ALL 1 1 1 0
|
||||
data-coref/star_tgt1-1.off data-coref/star_tgt2-1.off ALL 1 1 1 0
|
||||
data-coref/star_tgt1-1.off data-coref/star_tgt2-2.off ALL 0 1 1 1
|
||||
data-coref/star_tgt1-1.off data-coref/star_tgt2-3.off ALL 1 1 1 0
|
||||
data-coref/star_tgt1-1.off data-coref/star_tgt2-4.off ALL 0 1 1 1
|
||||
data-coref/star_tgt1-1.off data-coref/star_tgt2-5.off ALL 1 1 1 0
|
||||
data-coref/star_tgt1-2.off data-coref/star_tgt2-0.off ALL 1 1 1 0
|
||||
data-coref/star_tgt1-2.off data-coref/star_tgt2-1.off ALL 1 1 1 0
|
||||
data-coref/star_tgt1-2.off data-coref/star_tgt2-2.off ALL 0 1 1 1
|
||||
data-coref/star_tgt1-2.off data-coref/star_tgt2-3.off ALL 1 1 1 1
|
||||
data-coref/star_tgt1-2.off data-coref/star_tgt2-4.off ALL 0 1 1 1
|
||||
data-coref/star_tgt1-2.off data-coref/star_tgt2-5.off ALL 1 1 1 1
|
||||
|
|
|
|||
|
|
@ -0,0 +1,54 @@
|
|||
#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
|
||||
#include <CGAL/Surface_mesh.h>
|
||||
|
||||
#include <CGAL/Polygon_mesh_processing/merge_border_vertices.h>
|
||||
#include <CGAL/boost/graph/graph_traits_Surface_mesh.h>
|
||||
|
||||
#include <fstream>
|
||||
|
||||
|
||||
typedef CGAL::Exact_predicates_inexact_constructions_kernel K;
|
||||
typedef CGAL::Surface_mesh<K::Point_3> Surface_mesh;
|
||||
|
||||
|
||||
void test_merge_duplicated_vertices_in_boundary_cycles(const char* fname,
|
||||
std::size_t expected_nb_vertices)
|
||||
{
|
||||
std::ifstream input(fname);
|
||||
|
||||
Surface_mesh mesh;
|
||||
if (!input || !(input >> mesh) || mesh.is_empty()) {
|
||||
std::cerr << fname << " is not a valid off file.\n";
|
||||
exit(1);
|
||||
}
|
||||
|
||||
std::cout << "Testing merging in cycles " << fname << "\n";
|
||||
std::cout << " input mesh has " << vertices(mesh).size() << " vertices.\n";
|
||||
CGAL::Polygon_mesh_processing::merge_duplicated_vertices_in_boundary_cycles(mesh);
|
||||
std::cout << " output mesh has " << vertices(mesh).size() << " vertices.\n";
|
||||
|
||||
assert(expected_nb_vertices==0 ||
|
||||
expected_nb_vertices == vertices(mesh).size());
|
||||
if (expected_nb_vertices==0)
|
||||
{
|
||||
std::cout << "writting output to out1.off\n";
|
||||
std::ofstream output("out1.off");
|
||||
output << std::setprecision(17);
|
||||
output << mesh;
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
if (argc==1)
|
||||
{
|
||||
test_merge_duplicated_vertices_in_boundary_cycles("data/merge_points.off", 43);
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i=1; i< argc; ++i)
|
||||
test_merge_duplicated_vertices_in_boundary_cycles(argv[i], 0);
|
||||
}
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
|
@ -0,0 +1,251 @@
|
|||
#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
|
||||
|
||||
#include <CGAL/Surface_mesh.h>
|
||||
|
||||
#include <CGAL/Polygon_mesh_processing/repair.h>
|
||||
#include <CGAL/Polygon_mesh_processing/shape_predicates.h>
|
||||
|
||||
#include <CGAL/number_type_config.h>
|
||||
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
|
||||
typedef CGAL::Exact_predicates_inexact_constructions_kernel K;
|
||||
typedef K::FT FT;
|
||||
typedef K::Point_3 Point_3;
|
||||
typedef CGAL::Surface_mesh<Point_3> Surface_mesh;
|
||||
|
||||
void check_edge_degeneracy(const char* fname)
|
||||
{
|
||||
std::cout << "test edge degeneracy...";
|
||||
|
||||
typedef boost::graph_traits<Surface_mesh>::edge_descriptor edge_descriptor;
|
||||
|
||||
std::ifstream input(fname);
|
||||
Surface_mesh mesh;
|
||||
if (!input || !(input >> mesh) || mesh.is_empty()) {
|
||||
std::cerr << fname << " is not a valid off file.\n";
|
||||
std::exit(1);
|
||||
}
|
||||
std::vector<edge_descriptor> all_edges(edges(mesh).begin(), edges(mesh).end());
|
||||
|
||||
assert(!CGAL::Polygon_mesh_processing::is_degenerate_edge(all_edges[0], mesh));
|
||||
assert(!CGAL::Polygon_mesh_processing::is_degenerate_edge(all_edges[1], mesh));
|
||||
assert(CGAL::Polygon_mesh_processing::is_degenerate_edge(all_edges[2], mesh));
|
||||
std::cout << "done" << std::endl;
|
||||
}
|
||||
|
||||
void check_triangle_face_degeneracy(const char* fname)
|
||||
{
|
||||
std::cout << "test face degeneracy...";
|
||||
|
||||
typedef boost::graph_traits<Surface_mesh>::face_descriptor face_descriptor;
|
||||
|
||||
std::ifstream input(fname);
|
||||
Surface_mesh mesh;
|
||||
if (!input || !(input >> mesh) || mesh.is_empty()) {
|
||||
std::cerr << fname << " is not a valid off file.\n";
|
||||
std::exit(1);
|
||||
}
|
||||
|
||||
std::vector<face_descriptor> all_faces(faces(mesh).begin(), faces(mesh).end());
|
||||
assert(CGAL::Polygon_mesh_processing::is_degenerate_triangle_face(all_faces[0], mesh));
|
||||
assert(!CGAL::Polygon_mesh_processing::is_degenerate_triangle_face(all_faces[1], mesh));
|
||||
assert(!CGAL::Polygon_mesh_processing::is_degenerate_triangle_face(all_faces[2], mesh));
|
||||
assert(!CGAL::Polygon_mesh_processing::is_degenerate_triangle_face(all_faces[3], mesh));
|
||||
|
||||
std::cout << "done" << std::endl;
|
||||
}
|
||||
|
||||
// tests merge_and_duplication
|
||||
template <typename PolygonMesh>
|
||||
void merge_identical_points(typename boost::graph_traits<PolygonMesh>::vertex_descriptor v_keep,
|
||||
typename boost::graph_traits<PolygonMesh>::vertex_descriptor v_rm,
|
||||
PolygonMesh& mesh)
|
||||
{
|
||||
typedef typename boost::graph_traits<PolygonMesh>::halfedge_descriptor halfedge_descriptor;
|
||||
|
||||
halfedge_descriptor h = halfedge(v_rm, mesh);
|
||||
halfedge_descriptor start = h;
|
||||
|
||||
do
|
||||
{
|
||||
set_target(h, v_keep, mesh);
|
||||
h = opposite(next(h, mesh), mesh);
|
||||
}
|
||||
while( h != start );
|
||||
|
||||
remove_vertex(v_rm, mesh);
|
||||
}
|
||||
|
||||
void test_vertex_non_manifoldness(const char* fname)
|
||||
{
|
||||
std::cout << "test vertex non manifoldness...";
|
||||
|
||||
typedef boost::graph_traits<Surface_mesh>::vertex_descriptor vertex_descriptor;
|
||||
typedef boost::graph_traits<Surface_mesh>::vertices_size_type size_type;
|
||||
|
||||
std::ifstream input(fname);
|
||||
Surface_mesh mesh;
|
||||
if (!input || !(input >> mesh) || mesh.is_empty()) {
|
||||
std::cerr << fname << " is not a valid off file.\n";
|
||||
std::exit(1);
|
||||
}
|
||||
|
||||
size_type ini_nv = num_vertices(mesh);
|
||||
|
||||
// create non-manifold vertex
|
||||
Surface_mesh::Vertex_index vertex_to_merge_onto(1);
|
||||
Surface_mesh::Vertex_index vertex_to_merge(7);
|
||||
merge_identical_points(vertex_to_merge_onto, vertex_to_merge, mesh);
|
||||
mesh.collect_garbage();
|
||||
|
||||
assert(num_vertices(mesh) == ini_nv - 1);
|
||||
|
||||
BOOST_FOREACH(vertex_descriptor v, vertices(mesh))
|
||||
{
|
||||
if(v == vertex_to_merge_onto)
|
||||
assert(CGAL::Polygon_mesh_processing::is_non_manifold_vertex(v, mesh));
|
||||
else
|
||||
assert(!CGAL::Polygon_mesh_processing::is_non_manifold_vertex(v, mesh));
|
||||
}
|
||||
|
||||
std::cout << "done" << std::endl;
|
||||
}
|
||||
|
||||
void test_vertices_merge_and_duplication(const char* fname)
|
||||
{
|
||||
std::cout << "test non manifold vertex duplication...";
|
||||
|
||||
typedef boost::graph_traits<Surface_mesh>::vertex_descriptor vertex_descriptor;
|
||||
|
||||
std::ifstream input(fname);
|
||||
Surface_mesh mesh;
|
||||
if (!input || !(input >> mesh) || mesh.is_empty()) {
|
||||
std::cerr << fname << " is not a valid off file.\n";
|
||||
std::exit(1);
|
||||
}
|
||||
const std::size_t initial_vertices = num_vertices(mesh);
|
||||
|
||||
// create non-manifold vertex
|
||||
Surface_mesh::Vertex_index vertex_to_merge_onto(1);
|
||||
Surface_mesh::Vertex_index vertex_to_merge(7);
|
||||
Surface_mesh::Vertex_index vertex_to_merge_2(14);
|
||||
Surface_mesh::Vertex_index vertex_to_merge_3(21);
|
||||
|
||||
Surface_mesh::Vertex_index vertex_to_merge_onto_2(2);
|
||||
Surface_mesh::Vertex_index vertex_to_merge_4(8);
|
||||
|
||||
merge_identical_points(vertex_to_merge_onto, vertex_to_merge, mesh);
|
||||
merge_identical_points(vertex_to_merge_onto, vertex_to_merge_2, mesh);
|
||||
merge_identical_points(vertex_to_merge_onto, vertex_to_merge_3, mesh);
|
||||
merge_identical_points(vertex_to_merge_onto_2, vertex_to_merge_4, mesh);
|
||||
mesh.collect_garbage();
|
||||
|
||||
const std::size_t vertices_after_merge = num_vertices(mesh);
|
||||
assert(vertices_after_merge == initial_vertices - 4);
|
||||
|
||||
std::vector<std::vector<vertex_descriptor> > duplicated_vertices;
|
||||
std::size_t new_vertices_nb =
|
||||
CGAL::Polygon_mesh_processing::duplicate_non_manifold_vertices(mesh,
|
||||
CGAL::parameters::output_iterator(std::back_inserter(duplicated_vertices)));
|
||||
|
||||
const std::size_t final_vertices_size = vertices(mesh).size();
|
||||
assert(final_vertices_size == initial_vertices);
|
||||
assert(new_vertices_nb == 4);
|
||||
assert(duplicated_vertices.size() == 2); // two non-manifold vertex
|
||||
assert(duplicated_vertices.front().size() == 4);
|
||||
assert(duplicated_vertices.back().size() == 2);
|
||||
|
||||
std::cout << "done" << std::endl;
|
||||
}
|
||||
|
||||
void test_needles_and_caps(const char* fname)
|
||||
{
|
||||
std::cout << "test needles&caps...";
|
||||
|
||||
namespace PMP = CGAL::Polygon_mesh_processing;
|
||||
|
||||
typedef boost::graph_traits<Surface_mesh>::halfedge_descriptor halfedge_descriptor;
|
||||
typedef boost::graph_traits<Surface_mesh>::face_iterator face_iterator;
|
||||
typedef boost::graph_traits<Surface_mesh>::face_descriptor face_descriptor;
|
||||
|
||||
std::ifstream input(fname);
|
||||
Surface_mesh mesh;
|
||||
if (!input || !(input >> mesh) || mesh.is_empty()) {
|
||||
std::cerr << fname << " is not a valid off file.\n";
|
||||
std::exit(1);
|
||||
}
|
||||
|
||||
const FT eps = std::numeric_limits<FT>::epsilon();
|
||||
|
||||
face_iterator fit, fend;
|
||||
boost::tie(fit, fend) = faces(mesh);
|
||||
|
||||
// (0 0 0) -- (1 0 0) -- (1 1 0) (90° cap angle)
|
||||
face_descriptor f = *fit;
|
||||
halfedge_descriptor res = PMP::is_needle_triangle_face(f, mesh, 2/*needle_threshold*/);
|
||||
assert(res == boost::graph_traits<Surface_mesh>::null_halfedge()); // not a needle
|
||||
res = PMP::is_needle_triangle_face(f, mesh, CGAL::sqrt(FT(2) - eps)/*needle_threshold*/);
|
||||
assert(res != boost::graph_traits<Surface_mesh>::null_halfedge()); // is a needle
|
||||
|
||||
res = PMP::is_cap_triangle_face(f, mesh, 0./*cos(pi/2)*/);
|
||||
assert(mesh.point(target(res, mesh)) == CGAL::ORIGIN);
|
||||
res = PMP::is_cap_triangle_face(f, mesh, std::cos(91 * CGAL_PI / 180));
|
||||
assert(res == boost::graph_traits<Surface_mesh>::null_halfedge());
|
||||
res = PMP::is_cap_triangle_face(f, mesh, std::cos(2 * CGAL_PI / 3));
|
||||
assert(res == boost::graph_traits<Surface_mesh>::null_halfedge());
|
||||
++ fit;
|
||||
|
||||
// (0 0 1) -- (1 0 1) -- (10 10 1)
|
||||
f = *fit;
|
||||
res = PMP::is_needle_triangle_face(f, mesh, 20);
|
||||
assert(res == boost::graph_traits<Surface_mesh>::null_halfedge());
|
||||
res = PMP::is_needle_triangle_face(f, mesh, 10 * CGAL::sqrt(FT(2) - eps));
|
||||
assert(mesh.point(target(res, mesh)) == Point_3(1,0,1));
|
||||
res = PMP::is_needle_triangle_face(f, mesh, 1);
|
||||
assert(mesh.point(target(res, mesh)) == Point_3(1,0,1));
|
||||
|
||||
res = PMP::is_cap_triangle_face(f, mesh, 0./*cos(pi/2)*/);
|
||||
assert(mesh.point(target(res, mesh)) == Point_3(0,0,1));
|
||||
res = PMP::is_cap_triangle_face(f, mesh, std::cos(2 * CGAL_PI / 3));
|
||||
assert(mesh.point(target(res, mesh)) == Point_3(0,0,1));
|
||||
res = PMP::is_cap_triangle_face(f, mesh, std::cos(0.75 * CGAL_PI));
|
||||
assert(res == boost::graph_traits<Surface_mesh>::null_halfedge());
|
||||
++ fit;
|
||||
|
||||
// (0 0 2) -- (1 0 2) -- (-0.99619469809 0.08715574274 2) (175° cap angle)
|
||||
f = *fit;
|
||||
res = PMP::is_needle_triangle_face(f, mesh, 2);
|
||||
assert(res == boost::graph_traits<Surface_mesh>::null_halfedge());
|
||||
res = PMP::is_needle_triangle_face(f, mesh, 1.9);
|
||||
assert(mesh.point(target(res, mesh)) == Point_3(0,0,2) ||
|
||||
mesh.point(target(res, mesh)) == Point_3(1,0,2));
|
||||
res = PMP::is_needle_triangle_face(f, mesh, 1);
|
||||
assert(mesh.point(target(res, mesh)) == Point_3(0,0,2) ||
|
||||
mesh.point(target(res, mesh)) == Point_3(1,0,2));
|
||||
|
||||
res = PMP::is_cap_triangle_face(f, mesh, 0./*cos(pi/2)*/);
|
||||
assert(res != boost::graph_traits<Surface_mesh>::null_halfedge() &&
|
||||
mesh.point(target(res, mesh)) != Point_3(0,0,2) &&
|
||||
mesh.point(target(res, mesh)) != Point_3(1,0,2));
|
||||
res = PMP::is_cap_triangle_face(f, mesh, std::cos(2 * CGAL_PI / 3));
|
||||
assert(res != boost::graph_traits<Surface_mesh>::null_halfedge());
|
||||
res = PMP::is_cap_triangle_face(f, mesh, std::cos(175 * CGAL_PI / 180));
|
||||
assert(res != boost::graph_traits<Surface_mesh>::null_halfedge());
|
||||
res = PMP::is_cap_triangle_face(f, mesh, std::cos(176 * CGAL_PI / 180));
|
||||
assert(res == boost::graph_traits<Surface_mesh>::null_halfedge());
|
||||
|
||||
std::cout << "done" << std::endl;
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
check_edge_degeneracy("data_degeneracies/degtri_edge.off");
|
||||
check_triangle_face_degeneracy("data_degeneracies/degtri_four.off");
|
||||
test_vertex_non_manifoldness("data/blobby.off");
|
||||
test_vertices_merge_and_duplication("data/blobby.off");
|
||||
test_needles_and_caps("data_degeneracies/caps_and_needles.off");
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
|
@ -1468,7 +1468,7 @@ void MainWindow::readSettings()
|
|||
CGAL::Three::Three::s_defaultSMRM = CGAL::Three::Three::modeFromName(
|
||||
settings.value("default_sm_rm", "flat+edges").toString());
|
||||
CGAL::Three::Three::s_defaultPSRM = CGAL::Three::Three::modeFromName(
|
||||
settings.value("default_ps_rm", "points").toString());
|
||||
settings.value("default_ps_rm", "shaded points").toString());
|
||||
// read plugin blacklist
|
||||
QStringList blacklist=settings.value("plugin_blacklist",QStringList()).toStringList();
|
||||
Q_FOREACH(QString name,blacklist){ plugin_blacklist.insert(name); }
|
||||
|
|
|
|||
|
|
@ -541,8 +541,13 @@ void Cluster_classification::compute_features (std::size_t nb_scales)
|
|||
std::cerr << "Computing pointwise features with " << nb_scales << " scale(s)" << std::endl;
|
||||
m_features.clear();
|
||||
|
||||
Point_set::Vector_map normal_map;
|
||||
bool normals = m_points->point_set()->has_normal_map();
|
||||
if (normals)
|
||||
normal_map = m_points->point_set()->normal_map();
|
||||
|
||||
bool colors = (m_color != Point_set::Property_map<Color>());
|
||||
|
||||
Point_set::Property_map<boost::uint8_t> echo_map;
|
||||
bool echo;
|
||||
boost::tie (echo_map, echo) = m_points->point_set()->template property_map<boost::uint8_t>("echo");
|
||||
|
|
@ -562,7 +567,7 @@ void Cluster_classification::compute_features (std::size_t nb_scales)
|
|||
|
||||
generator.generate_point_based_features(pointwise_features);
|
||||
if (normals)
|
||||
generator.generate_normal_based_features (pointwise_features, m_points->point_set()->normal_map());
|
||||
generator.generate_normal_based_features (pointwise_features, normal_map);
|
||||
if (colors)
|
||||
generator.generate_color_based_features (pointwise_features, m_color);
|
||||
if (echo)
|
||||
|
|
|
|||
|
|
@ -442,8 +442,13 @@ void Point_set_item_classification::compute_features (std::size_t nb_scales)
|
|||
std::cerr << "Computing features with " << nb_scales << " scale(s)" << std::endl;
|
||||
m_features.clear();
|
||||
|
||||
Point_set::Vector_map normal_map;
|
||||
bool normals = m_points->point_set()->has_normal_map();
|
||||
if (normals)
|
||||
normal_map = m_points->point_set()->normal_map();
|
||||
|
||||
bool colors = (m_color != Point_set::Property_map<Color>());
|
||||
|
||||
Point_set::Property_map<boost::uint8_t> echo_map;
|
||||
bool echo;
|
||||
boost::tie (echo_map, echo) = m_points->point_set()->template property_map<boost::uint8_t>("echo");
|
||||
|
|
@ -461,7 +466,7 @@ void Point_set_item_classification::compute_features (std::size_t nb_scales)
|
|||
|
||||
m_generator->generate_point_based_features(m_features);
|
||||
if (normals)
|
||||
m_generator->generate_normal_based_features (m_features, m_points->point_set()->normal_map());
|
||||
m_generator->generate_normal_based_features (m_features, normal_map);
|
||||
if (colors)
|
||||
m_generator->generate_color_based_features (m_features, m_color);
|
||||
if (echo)
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@
|
|||
#include <CGAL/Three/Scene_item_rendering_helper.h>
|
||||
#include <CGAL/Three/Three.h>
|
||||
#include <CGAL/Three/Point_container.h>
|
||||
#include <CGAL/Polygon_mesh_processing/transform.h>
|
||||
#include "Scene_surface_mesh_item.h"
|
||||
|
||||
#include "Scene_facegraph_transform_item.h"
|
||||
|
|
@ -17,6 +18,7 @@
|
|||
#include <QMenu>
|
||||
#include <QMainWindow>
|
||||
#include <QDockWidget>
|
||||
#include <QDialog>
|
||||
#include <QApplication>
|
||||
#include <QTime>
|
||||
#include <QMessageBox>
|
||||
|
|
@ -25,7 +27,7 @@
|
|||
using namespace CGAL::Three;
|
||||
typedef Viewer_interface Vi;
|
||||
typedef Point_container Pc;
|
||||
|
||||
#include "ui_MeshOnGrid_dialog.h"
|
||||
typedef Scene_surface_mesh_item Facegraph_item;
|
||||
|
||||
|
||||
|
|
@ -165,15 +167,20 @@ public:
|
|||
Polyhedron_demo_affine_transform_plugin():started(false){}
|
||||
|
||||
QList<QAction*> actions() const {
|
||||
return QList<QAction*>() << actionTransformPolyhedron;
|
||||
return QList<QAction*>() << actionTransformPolyhedron
|
||||
<< actionMeshOnGrid;
|
||||
}
|
||||
|
||||
bool applicable(QAction*) const {
|
||||
return qobject_cast<Facegraph_item*>(scene->item(scene->mainSelectionIndex()))
|
||||
|| qobject_cast<Scene_facegraph_transform_item*>(scene->item(scene->mainSelectionIndex()))
|
||||
|| qobject_cast<Scene_points_with_normal_item*>(scene->item(scene->mainSelectionIndex()))
|
||||
|| qobject_cast<Scene_transform_point_set_item*>(scene->item(scene->mainSelectionIndex()))
|
||||
;
|
||||
|
||||
bool applicable(QAction* a) const {
|
||||
if(a == actionMeshOnGrid)
|
||||
{
|
||||
return qobject_cast<Facegraph_item*>(scene->item(scene->mainSelectionIndex()));
|
||||
}
|
||||
else
|
||||
return qobject_cast<Facegraph_item*>(scene->item(scene->mainSelectionIndex()))
|
||||
|| qobject_cast<Scene_facegraph_transform_item*>(scene->item(scene->mainSelectionIndex()))
|
||||
|| qobject_cast<Scene_points_with_normal_item*>(scene->item(scene->mainSelectionIndex()))
|
||||
|| qobject_cast<Scene_transform_point_set_item*>(scene->item(scene->mainSelectionIndex()));
|
||||
}
|
||||
|
||||
void init(QMainWindow* _mw, CGAL::Three::Scene_interface* scene_interface, Messages_interface*) {
|
||||
|
|
@ -186,6 +193,12 @@ public:
|
|||
mw = _mw;
|
||||
this->scene = scene_interface;
|
||||
|
||||
actionMeshOnGrid = new QAction(
|
||||
tr("Create a Grid of Surface Meshes")
|
||||
, mw);
|
||||
if(actionMeshOnGrid) {
|
||||
connect(actionMeshOnGrid, SIGNAL(triggered()),this, SLOT(grid()));
|
||||
}
|
||||
|
||||
actionTransformPolyhedron = new QAction(
|
||||
tr("Affine Transformation")
|
||||
|
|
@ -235,10 +248,10 @@ public:
|
|||
}
|
||||
|
||||
private:
|
||||
|
||||
QDockWidget* dock_widget;
|
||||
Ui::TransformationWidget ui;
|
||||
QAction* actionTransformPolyhedron;
|
||||
QAction* actionMeshOnGrid;
|
||||
Scene_facegraph_transform_item* transform_item;
|
||||
Scene_transform_point_set_item* transform_points_item;
|
||||
CGAL::Three::Scene_interface::Item_id tr_item_index;
|
||||
|
|
@ -282,6 +295,7 @@ private:
|
|||
template<class Item>
|
||||
void normalize(Item*);
|
||||
public Q_SLOTS:
|
||||
void grid();
|
||||
void go();
|
||||
void transformed_killed();
|
||||
|
||||
|
|
@ -364,6 +378,75 @@ public Q_SLOTS:
|
|||
|
||||
}; // end class Polyhedron_demo_affine_transform_plugin
|
||||
|
||||
class GridDialog :
|
||||
public QDialog,
|
||||
public Ui::GridDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
GridDialog(QWidget* =0)
|
||||
{
|
||||
setupUi(this);
|
||||
}
|
||||
};
|
||||
|
||||
void Polyhedron_demo_affine_transform_plugin::grid()
|
||||
{
|
||||
Facegraph_item* item =
|
||||
qobject_cast<Facegraph_item*>(scene->item(scene->mainSelectionIndex()));
|
||||
if(!item)
|
||||
return;
|
||||
|
||||
|
||||
FaceGraph m = *item->face_graph();
|
||||
|
||||
Scene_item::Bbox b = item->bbox();
|
||||
|
||||
|
||||
double x_t(CGAL::sqrt(CGAL::squared_distance(Kernel::Point_3(b.min(0), b.min(1), b.min(2)),
|
||||
Kernel::Point_3(b.max(0), b.min(1), b.min(2))))),
|
||||
y_t(CGAL::sqrt(CGAL::squared_distance(Kernel::Point_3(b.min(0), b.min(1), b.min(2)),
|
||||
Kernel::Point_3(b.min(0), b.max(1), b.min(2))))),
|
||||
z_t(CGAL::sqrt(CGAL::squared_distance(Kernel::Point_3(b.min(0), b.min(1), b.min(2)),
|
||||
Kernel::Point_3(b.min(0), b.min(1), b.max(2)))));
|
||||
|
||||
GridDialog dialog(mw);
|
||||
dialog.x_space_doubleSpinBox->setValue(x_t);
|
||||
dialog.y_space_doubleSpinBox->setValue(y_t);
|
||||
dialog.z_space_doubleSpinBox->setValue(z_t);
|
||||
if(!dialog.exec())
|
||||
return;
|
||||
QApplication::setOverrideCursor(Qt::WaitCursor);
|
||||
int i_max=dialog.x_spinBox->value(),
|
||||
j_max=dialog.y_spinBox->value(),
|
||||
k_max=dialog.z_spinBox->value();
|
||||
x_t = dialog.x_space_doubleSpinBox->value();
|
||||
y_t = dialog.y_space_doubleSpinBox->value();
|
||||
z_t = dialog.z_space_doubleSpinBox->value();
|
||||
|
||||
for(int i = 0; i < i_max; ++i)
|
||||
{
|
||||
for(int j = 0; j< j_max; ++j)
|
||||
{
|
||||
for(int k = 0; k< k_max; ++k)
|
||||
{
|
||||
FaceGraph e;
|
||||
CGAL::copy_face_graph(m,e);
|
||||
|
||||
Kernel::Aff_transformation_3 trans(CGAL::TRANSLATION, Kernel::Vector_3(i*x_t,j*y_t,k*z_t));
|
||||
CGAL::Polygon_mesh_processing::transform(trans, e);
|
||||
Facegraph_item* t_item = new Facegraph_item(e);
|
||||
t_item->setName(tr("%1 %2%3%4")
|
||||
.arg(item->name())
|
||||
.arg(i)
|
||||
.arg(j)
|
||||
.arg(k));
|
||||
scene->addItem(t_item);
|
||||
}
|
||||
}
|
||||
}
|
||||
QApplication::restoreOverrideCursor();
|
||||
}
|
||||
void Polyhedron_demo_affine_transform_plugin::go(){
|
||||
if (!started){
|
||||
Scene_item* item = scene->item(scene->mainSelectionIndex());
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ include( polyhedron_demo_macros )
|
|||
polyhedron_demo_plugin(pca_plugin Pca_plugin)
|
||||
target_link_libraries(pca_plugin PUBLIC scene_surface_mesh_item scene_points_with_normal_item scene_basic_objects)
|
||||
|
||||
qt5_wrap_ui( transformUI_FILES Transformation_widget.ui )
|
||||
qt5_wrap_ui( transformUI_FILES Transformation_widget.ui MeshOnGrid_dialog.ui)
|
||||
|
||||
polyhedron_demo_plugin(affine_transform_plugin Affine_transform_plugin ${transformUI_FILES})
|
||||
target_link_libraries(affine_transform_plugin PUBLIC scene_surface_mesh_item scene_transform_item scene_points_with_normal_item)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,203 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>GridDialog</class>
|
||||
<widget class="QDialog" name="GridDialog">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>330</width>
|
||||
<height>394</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Dialog</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<widget class="QGroupBox" name="groupBox">
|
||||
<property name="title">
|
||||
<string>Along X</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout_2">
|
||||
<item row="1" column="1">
|
||||
<widget class="QDoubleSpinBox" name="x_space_doubleSpinBox">
|
||||
<property name="maximum">
|
||||
<double>99999999999999999475366575191804932315794610450682175621941694731908308538307845136842752.000000000000000</double>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="label_4">
|
||||
<property name="text">
|
||||
<string>Spacing:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
<string>Number of items : </string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QSpinBox" name="x_spinBox">
|
||||
<property name="maximum">
|
||||
<number>999</number>
|
||||
</property>
|
||||
<property name="value">
|
||||
<number>2</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="groupBox_2">
|
||||
<property name="title">
|
||||
<string>Along Y</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout_3">
|
||||
<item row="1" column="1">
|
||||
<widget class="QDoubleSpinBox" name="y_space_doubleSpinBox">
|
||||
<property name="maximum">
|
||||
<double>99999999999999999475366575191804932315794610450682175621941694731908308538307845136842752.000000000000000</double>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="label_5">
|
||||
<property name="text">
|
||||
<string>Spacing:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QSpinBox" name="y_spinBox">
|
||||
<property name="maximum">
|
||||
<number>999</number>
|
||||
</property>
|
||||
<property name="value">
|
||||
<number>2</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label_2">
|
||||
<property name="text">
|
||||
<string>Number of items : </string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="groupBox_3">
|
||||
<property name="title">
|
||||
<string>Along Z</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<item row="1" column="1">
|
||||
<widget class="QDoubleSpinBox" name="z_space_doubleSpinBox">
|
||||
<property name="maximum">
|
||||
<double>99999999999999999475366575191804932315794610450682175621941694731908308538307845136842752.000000000000000</double>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label_3">
|
||||
<property name="text">
|
||||
<string>Number of items : </string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="label_6">
|
||||
<property name="text">
|
||||
<string>Spacing:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QSpinBox" name="z_spinBox">
|
||||
<property name="maximum">
|
||||
<number>999</number>
|
||||
</property>
|
||||
<property name="value">
|
||||
<number>2</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="verticalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>40</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QDialogButtonBox" name="buttonBox">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="standardButtons">
|
||||
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections>
|
||||
<connection>
|
||||
<sender>buttonBox</sender>
|
||||
<signal>accepted()</signal>
|
||||
<receiver>GridDialog</receiver>
|
||||
<slot>accept()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>248</x>
|
||||
<y>254</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>157</x>
|
||||
<y>274</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>buttonBox</sender>
|
||||
<signal>rejected()</signal>
|
||||
<receiver>GridDialog</receiver>
|
||||
<slot>reject()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>316</x>
|
||||
<y>260</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>286</x>
|
||||
<y>274</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
</connections>
|
||||
</ui>
|
||||
|
|
@ -14,6 +14,8 @@
|
|||
#include <CGAL/box_intersection_d.h>
|
||||
#include <CGAL/Make_triangle_soup.h>
|
||||
#include <CGAL/Kernel_traits.h>
|
||||
#include <CGAL/Polygon_mesh_processing/shape_predicates.h>
|
||||
|
||||
typedef Scene_surface_mesh_item Scene_facegraph_item;
|
||||
typedef Scene_facegraph_item::Face_graph Face_graph;
|
||||
using namespace CGAL::Three;
|
||||
|
|
@ -71,14 +73,12 @@ template<class Mesh>
|
|||
bool isDegen(Mesh* mesh, std::vector<typename boost::graph_traits<Mesh>::face_descriptor> &out_faces)
|
||||
{
|
||||
typedef typename boost::graph_traits<Mesh>::face_descriptor FaceDescriptor;
|
||||
typedef typename boost::property_map<Mesh, CGAL::vertex_point_t>::type Vpm;
|
||||
typedef typename boost::property_traits<Vpm>::value_type Point;
|
||||
typedef typename CGAL::Kernel_traits<Point>::Kernel Kernel;
|
||||
|
||||
//filter non-triangle_faces
|
||||
BOOST_FOREACH(FaceDescriptor f, faces(*mesh))
|
||||
{
|
||||
if(is_triangle(halfedge(f, *mesh), *mesh)
|
||||
&& is_degenerate_triangle_face(f, *mesh, get(boost::vertex_point, *mesh), Kernel()) )
|
||||
&& CGAL::Polygon_mesh_processing::is_degenerate_triangle_face(f, *mesh) )
|
||||
out_faces.push_back(f);
|
||||
}
|
||||
return !out_faces.empty();
|
||||
|
|
|
|||
|
|
@ -56,7 +56,7 @@ public:
|
|||
actionStitchCloseBorderHalfedges->setProperty("subMenuName", "Polygon Mesh Processing/Repair/Experimental");
|
||||
actionRemoveSelfIntersections->setProperty("subMenuName", "Polygon Mesh Processing/Repair/Experimental");
|
||||
actionRemoveIsolatedVertices->setProperty("subMenuName", "Polygon Mesh Processing/Repair");
|
||||
actionDuplicateNMVertices->setProperty("subMenuName", "Polygon Mesh Processing/Repair/Experimental");
|
||||
actionDuplicateNMVertices->setProperty("subMenuName", "Polygon Mesh Processing/Repair");
|
||||
actionAutorefine->setProperty("subMenuName", "Polygon Mesh Processing/Repair/Experimental");
|
||||
actionAutorefineAndRMSelfIntersections->setProperty("subMenuName", "Polygon Mesh Processing/Repair/Experimental");
|
||||
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@
|
|||
#include <CGAL/boost/graph/split_graph_into_polylines.h>
|
||||
#include <CGAL/Polygon_mesh_processing/border.h>
|
||||
#include <CGAL/Polygon_mesh_processing/repair.h>
|
||||
#include <CGAL/Polygon_mesh_processing/shape_predicates.h>
|
||||
#include <Scene.h>
|
||||
typedef Scene_surface_mesh_item Scene_face_graph_item;
|
||||
|
||||
|
|
@ -724,14 +725,10 @@ public Q_SLOTS:
|
|||
//Edition mode
|
||||
case 1:
|
||||
{
|
||||
VPmap vpmap = get(CGAL::vertex_point, *selection_item->polyhedron());
|
||||
bool is_valid = true;
|
||||
BOOST_FOREACH(boost::graph_traits<Face_graph>::face_descriptor fd, faces(*selection_item->polyhedron()))
|
||||
{
|
||||
if (CGAL::is_degenerate_triangle_face(fd,
|
||||
*selection_item->polyhedron(),
|
||||
vpmap,
|
||||
CGAL::Kernel_traits< boost::property_traits<VPmap>::value_type >::Kernel()))
|
||||
if (CGAL::Polygon_mesh_processing::is_degenerate_triangle_face(fd, *selection_item->polyhedron()))
|
||||
{
|
||||
is_valid = false;
|
||||
break;
|
||||
|
|
|
|||
|
|
@ -275,8 +275,8 @@ void Polyhedron_demo_point_set_normal_estimation_plugin::on_actionNormalEstimati
|
|||
<< (memory>>20) << " Mb allocated"
|
||||
<< std::endl;
|
||||
}
|
||||
|
||||
item->setRenderingMode(PointsPlusNormals);
|
||||
item->resetMenu();
|
||||
item->setRenderingMode(ShadedPoints);
|
||||
|
||||
//***************************************
|
||||
// normal orientation
|
||||
|
|
|
|||
|
|
@ -680,6 +680,7 @@ protected:
|
|||
// mouse events
|
||||
if(shift_pressing && event->type() == QEvent::MouseButtonPress)
|
||||
{
|
||||
background = static_cast<CGAL::Three::Viewer_interface*>(*CGAL::QGLViewer::QGLViewerPool().begin())->grabFramebuffer();
|
||||
QMouseEvent *mouseEvent = static_cast<QMouseEvent*>(event);
|
||||
Viewer_interface* viewer = qobject_cast<Viewer_interface*>(
|
||||
Three::mainWindow()->childAt(QCursor::pos()));
|
||||
|
|
|
|||
|
|
@ -357,6 +357,7 @@ private:
|
|||
++ nb_colored_pts;
|
||||
colored_item->point_set()->set_color(*it, r, g, b);
|
||||
}
|
||||
colored_item->invalidateOpenGLBuffers();
|
||||
}
|
||||
|
||||
// Providing a useful name consisting of the order of detection, name of type and number of inliers
|
||||
|
|
@ -399,27 +400,28 @@ private:
|
|||
ss << "(" << ref << ")_";
|
||||
|
||||
if (dialog.generate_alpha ())
|
||||
{
|
||||
// If plane, build alpha shape
|
||||
Scene_surface_mesh_item* sm_item = NULL;
|
||||
sm_item = new Scene_surface_mesh_item;
|
||||
{
|
||||
// If plane, build alpha shape
|
||||
Scene_surface_mesh_item* sm_item = NULL;
|
||||
sm_item = new Scene_surface_mesh_item;
|
||||
|
||||
|
||||
build_alpha_shape (*(point_item->point_set()), pshape,
|
||||
sm_item, dialog.cluster_epsilon());
|
||||
|
||||
if(sm_item){
|
||||
sm_item->setColor(point_item->color ());
|
||||
sm_item->setName(QString("%1%2_alpha_shape").arg(QString::fromStdString(ss.str()))
|
||||
.arg (QString::number (shape->indices_of_assigned_points().size())));
|
||||
sm_item->setRenderingMode (Flat);
|
||||
|
||||
|
||||
build_alpha_shape (*(point_item->point_set()), pshape,
|
||||
sm_item, dialog.cluster_epsilon());
|
||||
if(sm_item){
|
||||
sm_item->setColor(point_item->color ());
|
||||
sm_item->setName(QString("%1%2_alpha_shape").arg(QString::fromStdString(ss.str()))
|
||||
.arg (QString::number (shape->indices_of_assigned_points().size())));
|
||||
sm_item->setRenderingMode (Flat);
|
||||
|
||||
scene->addItem(sm_item);
|
||||
if(scene->item_id(groups[0]) == -1)
|
||||
scene->addItem(groups[0]);
|
||||
scene->changeGroup(sm_item, groups[0]);
|
||||
}
|
||||
scene->addItem(sm_item);
|
||||
if(scene->item_id(groups[0]) == -1)
|
||||
scene->addItem(groups[0]);
|
||||
scene->changeGroup(sm_item, groups[0]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (dynamic_cast<CGAL::Shape_detection_3::Cone<Traits> *>(shape.get()))
|
||||
ss << item->name().toStdString() << "_cone_";
|
||||
else if (dynamic_cast<CGAL::Shape_detection_3::Torus<Traits> *>(shape.get()))
|
||||
|
|
@ -435,6 +437,7 @@ private:
|
|||
point_item->setRenderingMode(item->renderingMode());
|
||||
|
||||
if (dialog.generate_subset()){
|
||||
point_item->invalidateOpenGLBuffers();
|
||||
scene->addItem(point_item);
|
||||
if (dynamic_cast<CGAL::Shape_detection_3::Cylinder<Traits> *>(shape.get()))
|
||||
{
|
||||
|
|
@ -452,6 +455,7 @@ private:
|
|||
|
||||
if(scene->item_id(groups[0]) == -1)
|
||||
scene->addItem(groups[0]);
|
||||
point_item->invalidateOpenGLBuffers();
|
||||
scene->changeGroup(point_item, groups[0]);
|
||||
}
|
||||
else if (dynamic_cast<CGAL::Shape_detection_3::Cone<Traits> *>(shape.get()))
|
||||
|
|
@ -506,6 +510,7 @@ private:
|
|||
pts_full->setName(tr("%1 (structured)").arg(item->name()));
|
||||
pts_full->setRenderingMode(PointsPlusNormals);
|
||||
pts_full->setColor(Qt::blue);
|
||||
pts_full->invalidateOpenGLBuffers();
|
||||
scene->addItem (pts_full);
|
||||
}
|
||||
std::cerr << "done" << std::endl;
|
||||
|
|
|
|||
|
|
@ -865,7 +865,6 @@ private:
|
|||
local_timer.start();
|
||||
|
||||
Priority_with_structure_coherence<Structuring> priority (structuring, 10. * op.cluster_epsilon);
|
||||
|
||||
Scene_surface_mesh_item* reco_item = new Scene_surface_mesh_item(SMesh());
|
||||
SMesh& P = * const_cast<SMesh*>(reco_item->polyhedron());
|
||||
Construct<SMesh, Traits> construct(P,structured->point_set()->points().begin(),structured->point_set()->points().end());
|
||||
|
|
@ -881,7 +880,6 @@ private:
|
|||
reco_item->setColor(Qt::magenta);
|
||||
reco_item->setRenderingMode(FlatPlusEdges);
|
||||
scene->addItem(reco_item);
|
||||
|
||||
if (dialog.generate_structured ())
|
||||
{
|
||||
structured->setName(tr("%1 (structured)").arg(point_set_item->name()));
|
||||
|
|
@ -1050,7 +1048,6 @@ void Polyhedron_demo_surface_reconstruction_plugin::automatic_reconstruction
|
|||
{
|
||||
std::cerr << "Advancing front reconstruction... ";
|
||||
time.restart();
|
||||
|
||||
Scene_surface_mesh_item* reco_item = new Scene_surface_mesh_item(SMesh());
|
||||
SurfaceReconstruction::advancing_front (*points, reco_item, 10. * (std::max)(noise_size, aniso_size));
|
||||
|
||||
|
|
@ -1059,8 +1056,8 @@ void Polyhedron_demo_surface_reconstruction_plugin::automatic_reconstruction
|
|||
reco_item->setRenderingMode(FlatPlusEdges);
|
||||
scene->addItem(reco_item);
|
||||
std::cerr << "ok (" << time.elapsed() << " ms)" << std::endl;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -1068,7 +1065,6 @@ void Polyhedron_demo_surface_reconstruction_plugin::automatic_reconstruction
|
|||
{
|
||||
std::cerr << "Advancing front reconstruction... ";
|
||||
time.restart();
|
||||
|
||||
Scene_surface_mesh_item* reco_item = new Scene_surface_mesh_item(SMesh());
|
||||
SurfaceReconstruction::advancing_front (*points, reco_item, 10. * (std::max)(noise_size, aniso_size));
|
||||
|
||||
|
|
@ -1077,7 +1073,6 @@ void Polyhedron_demo_surface_reconstruction_plugin::automatic_reconstruction
|
|||
reco_item->setRenderingMode(FlatPlusEdges);
|
||||
scene->addItem(reco_item);
|
||||
|
||||
|
||||
std::cerr << "ok (" << time.elapsed() << " ms)" << std::endl;
|
||||
}
|
||||
else
|
||||
|
|
@ -1097,13 +1092,12 @@ void Polyhedron_demo_surface_reconstruction_plugin::automatic_reconstruction
|
|||
|
||||
std::cerr << "Poisson reconstruction... ";
|
||||
time.restart();
|
||||
SMesh* smRemesh = NULL;
|
||||
|
||||
smRemesh = poisson_reconstruct_sm(*points,
|
||||
20,
|
||||
100 * (std::max)(noise_size, aniso_size),
|
||||
(std::max)(noise_size, aniso_size),
|
||||
QString ("Eigen - built-in CG"), false, false);
|
||||
SMesh* smRemesh =
|
||||
poisson_reconstruct_sm(*points,
|
||||
20,
|
||||
100 * (std::max)(noise_size, aniso_size),
|
||||
(std::max)(noise_size, aniso_size),
|
||||
QString ("Eigen - built-in CG"), false, false);
|
||||
if(smRemesh)
|
||||
{
|
||||
// Add polyhedron to scene
|
||||
|
|
@ -1160,6 +1154,7 @@ void Polyhedron_demo_surface_reconstruction_plugin::advancing_front_reconstructi
|
|||
reco_item->setColor(Qt::lightGray);
|
||||
reco_item->setRenderingMode(FlatPlusEdges);
|
||||
scene->addItem(reco_item);
|
||||
|
||||
QApplication::restoreOverrideCursor();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@
|
|||
#include "Scene_edit_polyhedron_item.h"
|
||||
#include "Scene_polyhedron_selection_item.h"
|
||||
#include <CGAL/Polygon_mesh_processing/repair.h>
|
||||
#include <CGAL/Polygon_mesh_processing/shape_predicates.h>
|
||||
#include <QAction>
|
||||
#include <QMainWindow>
|
||||
#include <QFileDialog>
|
||||
|
|
@ -392,10 +393,7 @@ void Polyhedron_demo_edit_polyhedron_plugin::dock_widget_visibility_changed(bool
|
|||
bool is_valid = true;
|
||||
BOOST_FOREACH(boost::graph_traits<Face_graph>::face_descriptor fd, faces(*poly_item->face_graph()))
|
||||
{
|
||||
if (CGAL::is_degenerate_triangle_face(fd,
|
||||
*poly_item->face_graph(),
|
||||
get(boost::vertex_point,
|
||||
*poly_item->face_graph()), EPICK()))
|
||||
if (CGAL::Polygon_mesh_processing::is_degenerate_triangle_face(fd, *poly_item->face_graph()))
|
||||
{
|
||||
is_valid = false;
|
||||
break;
|
||||
|
|
|
|||
|
|
@ -30,7 +30,21 @@ bool Scene_group_item::isEmpty() const {
|
|||
|
||||
Scene_group_item::Bbox Scene_group_item::bbox() const
|
||||
{
|
||||
return Bbox(0, 0, 0, 0, 0,0);
|
||||
Scene_item* first_non_empty = nullptr;
|
||||
Q_FOREACH(Scene_interface::Item_id id, children)
|
||||
if(!getChild(id)->isEmpty())
|
||||
{
|
||||
first_non_empty = getChild(id);
|
||||
}
|
||||
|
||||
if(first_non_empty)
|
||||
{
|
||||
Bbox b =first_non_empty->bbox();
|
||||
Q_FOREACH(Scene_interface::Item_id id, children)
|
||||
b+=getChild(id)->bbox();
|
||||
return b;
|
||||
}
|
||||
return Bbox(0,0,0,0,0,0);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -112,6 +112,11 @@ QMenu* CGAL::Three::Scene_item::contextMenu()
|
|||
return defaultContextMenu;
|
||||
}
|
||||
|
||||
void CGAL::Three::Scene_item::resetMenu()
|
||||
{
|
||||
delete defaultContextMenu;
|
||||
defaultContextMenu = nullptr;
|
||||
}
|
||||
CGAL::Three::Scene_group_item* CGAL::Three::Scene_item::parentGroup() const {
|
||||
return parent_group;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -251,7 +251,6 @@ Scene_points_with_normal_item::Scene_points_with_normal_item(const SMesh& input_
|
|||
invalidateOpenGLBuffers();
|
||||
}
|
||||
|
||||
|
||||
Scene_points_with_normal_item::~Scene_points_with_normal_item()
|
||||
{
|
||||
delete d;
|
||||
|
|
@ -558,7 +557,7 @@ bool Scene_points_with_normal_item::read_las_point_set(std::istream& stream)
|
|||
!isEmpty();
|
||||
|
||||
std::cerr << d->m_points->info();
|
||||
|
||||
|
||||
if (!d->m_points->has_normal_map())
|
||||
{
|
||||
setRenderingMode(Points);
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
#include "Scene_polyhedron_selection_item.h"
|
||||
#include <CGAL/Polygon_mesh_processing/compute_normal.h>
|
||||
#include <CGAL/Polygon_mesh_processing/repair.h>
|
||||
#include <CGAL/Polygon_mesh_processing/shape_predicates.h>
|
||||
#include <CGAL/boost/graph/dijkstra_shortest_paths.h>
|
||||
#include <CGAL/boost/graph/helpers.h>
|
||||
#include <CGAL/property_map.h>
|
||||
|
|
@ -1868,8 +1869,9 @@ bool Scene_polyhedron_selection_item_priv::canAddFace(fg_halfedge_descriptor hc,
|
|||
found = true;
|
||||
fg_halfedge_descriptor res =
|
||||
CGAL::Euler::add_face_to_border(t,hc, *item->polyhedron());
|
||||
fg_face_descriptor resf = face(res, *item->polyhedron());
|
||||
|
||||
if(CGAL::is_degenerate_triangle_face(res, *item->polyhedron(), get(CGAL::vertex_point, *item->polyhedron()), EPICK()))
|
||||
if(CGAL::Polygon_mesh_processing::is_degenerate_triangle_face(resf, *item->polyhedron()))
|
||||
{
|
||||
CGAL::Euler::remove_face(res, *item->polyhedron());
|
||||
tempInstructions("Edge not selected : resulting facet is degenerated.",
|
||||
|
|
|
|||
|
|
@ -218,7 +218,7 @@ public:
|
|||
bool printVertexIds() const;
|
||||
bool printEdgeIds() const;
|
||||
bool printFaceIds() const;
|
||||
void printAllIds(CGAL::Three::Viewer_interface*);
|
||||
void printAllIds();
|
||||
bool testDisplayId(double, double, double, CGAL::Three::Viewer_interface*)const;
|
||||
bool shouldDisplayIds(CGAL::Three::Scene_item *current_item) const;
|
||||
QString defaultSaveName() const
|
||||
|
|
|
|||
|
|
@ -28,6 +28,7 @@
|
|||
#include <CGAL/Polygon_mesh_processing/connected_components.h>
|
||||
#include <CGAL/Polygon_mesh_processing/compute_normal.h>
|
||||
#include <CGAL/Polygon_mesh_processing/self_intersections.h>
|
||||
#include <CGAL/Polygon_mesh_processing/shape_predicates.h>
|
||||
#include <CGAL/Polygon_mesh_processing/orient_polygon_soup.h>
|
||||
#include <CGAL/Polygon_mesh_processing/polygon_soup_to_polygon_mesh.h>
|
||||
#include "triangulate_primitive.h"
|
||||
|
|
@ -838,9 +839,6 @@ void Scene_surface_mesh_item_priv::triangulate_convex_facet(face_descriptor fd,
|
|||
Scene_item_rendering_helper::Gl_data_names name,
|
||||
bool index) const
|
||||
{
|
||||
const CGAL::qglviewer::Vec v_offset = static_cast<CGAL::Three::Viewer_interface*>(CGAL::QGLViewer::QGLViewerPool().first())->offset();
|
||||
EPICK::Vector_3 offset = EPICK::Vector_3(v_offset.x, v_offset.y, v_offset.z);
|
||||
|
||||
Point p0,p1,p2;
|
||||
SMesh::Halfedge_around_face_circulator he(halfedge(fd, *smesh_), *smesh_);
|
||||
SMesh::Halfedge_around_face_circulator he_end = he;
|
||||
|
|
@ -851,9 +849,9 @@ void Scene_surface_mesh_item_priv::triangulate_convex_facet(face_descriptor fd,
|
|||
vertex_descriptor v0(target(*he_end, *smesh_)),
|
||||
v1(target(*he, *smesh_)),
|
||||
v2(target(next(*he, *smesh_), *smesh_));
|
||||
p0 = smesh_->point(v0) + offset;
|
||||
p1 = smesh_->point(v1) + offset;
|
||||
p2 = smesh_->point(v2) + offset;
|
||||
p0 = smesh_->point(v0);
|
||||
p1 = smesh_->point(v1);
|
||||
p2 = smesh_->point(v2);
|
||||
if(!index)
|
||||
{
|
||||
CGAL::Color* color;
|
||||
|
|
@ -1076,7 +1074,7 @@ void* Scene_surface_mesh_item_priv::get_aabb_tree()
|
|||
BOOST_FOREACH( face_descriptor f, faces(*sm))
|
||||
{
|
||||
//if face is degenerate, skip it
|
||||
if (CGAL::is_degenerate_triangle_face(f, *sm, get(CGAL::vertex_point, *sm), EPICK()))
|
||||
if (CGAL::Polygon_mesh_processing::is_degenerate_triangle_face(f, *sm))
|
||||
continue;
|
||||
//if face not triangle, triangulate corresponding primitive before adding it to the tree
|
||||
if(!CGAL::is_triangle(halfedge(f, *sm), *sm))
|
||||
|
|
@ -1562,7 +1560,7 @@ QString Scene_surface_mesh_item::computeStats(int type)
|
|||
if(is_triangle_mesh(*d->smesh_))
|
||||
{
|
||||
if (d->number_of_degenerated_faces == (unsigned int)(-1))
|
||||
d->number_of_degenerated_faces = nb_degenerate_faces(d->smesh_, get(CGAL::vertex_point, *(d->smesh_)));
|
||||
d->number_of_degenerated_faces = nb_degenerate_faces(d->smesh_);
|
||||
return QString::number(d->number_of_degenerated_faces);
|
||||
}
|
||||
else
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ configure()
|
|||
{
|
||||
echo "Configuring... "
|
||||
|
||||
if eval 'cmake --no-warn-unused-cli "$CMAKE_GENERATOR" -DRUNNING_CGAL_AUTO_TEST=TRUE \
|
||||
if eval 'cmake --no-warn-unused-cli ${INIT_FILE:+"-C${INIT_FILE}"} "$CMAKE_GENERATOR" -DRUNNING_CGAL_AUTO_TEST=TRUE \
|
||||
-DCGAL_DIR="$CGAL_DIR" \
|
||||
.' ; then
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,8 @@
|
|||
#ifndef POLYHEDRON_DEMO_STATISTICS_HELPERS_H
|
||||
#define POLYHEDRON_DEMO_STATISTICS_HELPERS_H
|
||||
|
||||
#include <cmath>
|
||||
#include <CGAL/squared_distance_3_0.h>
|
||||
#include <CGAL/Polygon_mesh_processing/repair.h>
|
||||
|
||||
#include <boost/accumulators/accumulators.hpp>
|
||||
#include <boost/accumulators/statistics/stats.hpp>
|
||||
|
|
@ -9,10 +10,13 @@
|
|||
#include <boost/accumulators/statistics/min.hpp>
|
||||
#include <boost/accumulators/statistics/max.hpp>
|
||||
#include <boost/accumulators/statistics/median.hpp>
|
||||
#include <CGAL/squared_distance_3_0.h>
|
||||
#include <map>
|
||||
#include <boost/property_map/property_map.hpp>
|
||||
|
||||
#include <cmath>
|
||||
#include <iterator>
|
||||
#include <limits>
|
||||
#include <map>
|
||||
#include <vector>
|
||||
|
||||
template<typename Mesh>
|
||||
void angles(Mesh* poly, double& mini, double& maxi, double& ave)
|
||||
|
|
@ -81,19 +85,15 @@ void edges_length(Mesh* poly,
|
|||
mid = extract_result< tag::median >(acc);
|
||||
}
|
||||
|
||||
template<typename Mesh, typename VPmap>
|
||||
unsigned int nb_degenerate_faces(Mesh* poly, VPmap vpmap)
|
||||
template<typename Mesh>
|
||||
unsigned int nb_degenerate_faces(Mesh* poly)
|
||||
{
|
||||
typedef typename boost::graph_traits<Mesh>::face_descriptor face_descriptor;
|
||||
typedef typename CGAL::Kernel_traits< typename boost::property_traits<VPmap>::value_type >::Kernel Traits;
|
||||
|
||||
unsigned int nb = 0;
|
||||
BOOST_FOREACH(face_descriptor f, faces(*poly))
|
||||
{
|
||||
if (CGAL::is_degenerate_triangle_face(f, *poly, vpmap, Traits()))
|
||||
++nb;
|
||||
}
|
||||
return nb;
|
||||
std::vector<face_descriptor> degenerate_faces;
|
||||
CGAL::Polygon_mesh_processing::degenerate_faces(*poly, std::back_inserter(degenerate_faces));
|
||||
|
||||
return static_cast<unsigned int>(degenerate_faces.size());
|
||||
}
|
||||
|
||||
template<typename Mesh>
|
||||
|
|
|
|||
|
|
@ -463,10 +463,11 @@ make_property_map(const std::vector<T>& v)
|
|||
template<class KeyType, class ValueType>
|
||||
struct Constant_property_map
|
||||
{
|
||||
const ValueType default_value;
|
||||
ValueType default_value;
|
||||
|
||||
typedef KeyType key_type;
|
||||
typedef ValueType value_type;
|
||||
typedef value_type& reference;
|
||||
typedef boost::read_write_property_map_tag category;
|
||||
|
||||
Constant_property_map(const value_type& default_value = value_type()) : default_value (default_value) { }
|
||||
|
|
|
|||
|
|
@ -0,0 +1,8 @@
|
|||
#!/bin/bash
|
||||
if [ "$1" == '--help' ]; then
|
||||
echo "Usage: $0 <path to CGAL release> <path to output> <number of cores to dedicate>"
|
||||
echo "Builds and packages the Polyhedron demo form the CGAL dir."
|
||||
exit 0
|
||||
fi
|
||||
docker run --rm -v "$2":/results:Z -v "$1":/cgal:ro docker.io/cgal/bundle-3d-demo "/scripts/build.sh -j$3 && /scripts/deploy.sh"
|
||||
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
#!/bin/sh
|
||||
#!/bin/bash
|
||||
# ----------------------------------------------------
|
||||
# ----------------------------------------------------
|
||||
# autotest_cgal: a script to automagically install and
|
||||
|
|
@ -525,7 +525,7 @@ export MAKE_CMD;
|
|||
export CGAL_BINARY_DIR;
|
||||
export CGAL_REFERENCE_CACHE_DIR;
|
||||
cd '${CGAL_BINARY_DIR}';
|
||||
cmake '${CMAKE_GENERATOR}' -DRUNNING_CGAL_AUTO_TEST=TRUE \\
|
||||
cmake \${INIT_FILE:+"-C\${INIT_FILE}"} '${CMAKE_GENERATOR}' -DRUNNING_CGAL_AUTO_TEST=TRUE \\
|
||||
-DCGAL_REFERENCE_CACHE_DIR="\$CGAL_REFERENCE_CACHE_DIR" \\
|
||||
VERBOSE=1 \\
|
||||
../../..;
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue