Fix conflicts

This commit is contained in:
Maxime Gimeno 2018-10-09 10:59:54 +02:00
commit 81a08465d3
110 changed files with 4417 additions and 12165 deletions

2
.gitignore vendored
View File

@ -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

View File

@ -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 ..

View File

@ -69,7 +69,6 @@ Nef_S2
NewKernel_d
Number_types
OpenNL
Operations_on_polyhedra
Optimal_transportation_reconstruction_2
Optimisation_basic
Partition_2

View File

@ -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 ..

View File

@ -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);

View File

@ -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>

View File

@ -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,

View File

@ -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)

View File

@ -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;

View File

@ -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

View File

@ -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

View File

@ -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>

View File

@ -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>

View File

@ -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 Point_triple_less_signed_distance_to_plane_3<R>
Less_signed_distance_to_plane_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;
// required for degenerate case of all points coplanar
typedef CGAL::Projection_traits_xy_3<R> Traits_xy_3;

View File

@ -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));
}

View File

@ -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;

View File

@ -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
------------

View File

@ -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.

View File

@ -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::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`

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -1,2 +0,0 @@
GeometryFactory
INRIA Sophia-Antipolis

View File

@ -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.

View File

@ -1 +0,0 @@
Sébastien Loriot <sebastien.loriot@cgal.org>

View File

@ -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

View File

@ -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>
@ -105,6 +105,16 @@ private:
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);
}

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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()`
*/

View File

@ -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
@ -372,47 +372,61 @@ 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
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 has been compiled with Visual C++ 2013 compiler with the O2
option which maximizes speed.
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
@ -435,36 +449,85 @@ 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
@ -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}

View File

@ -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

View File

@ -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" )

View File

@ -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;
}

View File

@ -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::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::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))
if(!input || !CGAL::read_OFF(input, points, polygons) || points.empty())
{
std::cerr << "Error parsing the OFF file " << std::endl;
return 1;
std::cerr << "Cannot open file " << std::endl;
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;
}

View File

@ -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

View File

@ -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,26 +1576,30 @@ 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_));
if(is_border(h, mesh_))
@ -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_,
PMP::self_intersections(mesh_,
std::back_inserter(facets),
PMP::parameters::vertex_point_map(vpmap_));
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_),
PMP::self_intersections(faces_around_target(halfedge(v, mesh_), mesh_),
mesh_,
std::back_inserter(facets),
PMP::parameters::vertex_point_map(vpmap_));
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;

View File

@ -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

View File

@ -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);

View File

@ -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);
}

View File

@ -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>
/// \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>::edge_descriptor edge_descriptor;
BOOST_FOREACH(edge_descriptor ed, edges)
{
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,
const VertexPointMap& vpmap,
const Traits& traits,
OutputIterator out)
degenerate_edges(const TriangleMesh& tm, OutputIterator out)
{
return degenerate_edges(edges(tm), tm, out, CGAL::parameters::all_default());
}
/// \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(tm))
BOOST_FOREACH(face_descriptor fd, faces)
{
if ( is_degenerate_triangle_face(fd, tm, vpmap, traits) )
if(is_degenerate_triangle_face(fd, tm, np))
*out++ = fd;
}
return out;
}
template <class TriangleMesh, class OutputIterator>
OutputIterator
degenerate_faces(const TriangleMesh& tm, OutputIterator 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)
{
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_faces(faces, tm, out, CGAL::parameters::all_default());
}
return degenerate_faces(tm, get(vertex_point, tm), Kernel(), out);
/// \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,8 +502,7 @@ 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,
bool remove_degenerate_edges(const EdgeRange& edge_range,
TriangleMesh& tmesh,
const NamedParameters& np)
{
@ -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";
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,60 +805,59 @@ 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,
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,
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,17 +1030,19 @@ 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
{
// Process a connected component of degenerate faces
@ -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,13 +1465,153 @@ 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;
@ -1304,37 +1620,52 @@ std::size_t duplicate_non_manifold_vertices(TriangleMesh& tm, Vpm vpm)
std::vector<halfedge_descriptor> non_manifold_cones;
BOOST_FOREACH(halfedge_descriptor h, halfedges(tm))
{
// 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)
{
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{
do
{
halfedges_handled.insert(h);
h = opposite(next(h, tm), tm);
}while(h!=start);
}
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);
}
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

View File

@ -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

View File

@ -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

View File

@ -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)

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -0,0 +1,6 @@
OFF
3 1 0
0 0 0
1 0 0
0 0 0
3 0 1 2

View File

@ -11,11 +11,34 @@
//the last test (on trihole.off) does not terminate
//
namespace PMP = CGAL::Polygon_mesh_processing;
typedef CGAL::Exact_predicates_inexact_constructions_kernel K;
typedef CGAL::Surface_mesh<K::Point_3> Surface_mesh;
void fix(const char* fname)
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;
}

View File

@ -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

View File

@ -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

View File

@ -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;
}
return 0;
}

View File

@ -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

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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); }

View File

@ -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)

View File

@ -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)

View File

@ -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 {
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()))
;
|| 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());

View File

@ -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)

View File

@ -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>

View File

@ -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();

View File

@ -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");

View File

@ -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;

View File

@ -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

View File

@ -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()));

View File

@ -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
@ -407,6 +408,7 @@ private:
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()))
@ -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;

View File

@ -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,16 +1056,15 @@ 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
{
if (dialog.boundaries())
{
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,9 +1092,8 @@ void Polyhedron_demo_surface_reconstruction_plugin::automatic_reconstruction
std::cerr << "Poisson reconstruction... ";
time.restart();
SMesh* smRemesh = NULL;
smRemesh = poisson_reconstruct_sm(*points,
SMesh* smRemesh =
poisson_reconstruct_sm(*points,
20,
100 * (std::max)(noise_size, aniso_size),
(std::max)(noise_size, aniso_size),
@ -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();
}
}

View File

@ -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;

View File

@ -30,6 +30,20 @@ bool Scene_group_item::isEmpty() const {
Scene_group_item::Bbox Scene_group_item::bbox() const
{
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);
}

View File

@ -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;
}

View File

@ -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;

View File

@ -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.",

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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>

View File

@ -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) { }

View File

@ -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"

View File

@ -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