mirror of https://github.com/CGAL/cgal
Merge pull request #3111 from sloriot/PMP-coref_preserve_face_attributes
Add a visitor to track the creation of faces in corefinement functions
This commit is contained in:
commit
2d9000efde
|
|
@ -20,4 +20,4 @@
|
|||
|
||||
// List the named parameters imported from boost we are using in CGAL
|
||||
CGAL_add_named_parameter(vertex_index_t, vertex_index, vertex_index_map)
|
||||
CGAL_add_named_parameter(graph_visitor_t, visitor, visitor)
|
||||
CGAL_add_named_parameter(graph_visitor_t, graph_visitor, visitor)
|
||||
|
|
|
|||
|
|
@ -88,7 +88,7 @@ enum all_default_t { all_default }; //cannot use macro because it takes no argum
|
|||
using boost::vertex_index_t;
|
||||
using boost::vertex_index;
|
||||
using boost::graph_visitor_t;
|
||||
using boost::visitor;
|
||||
using boost::graph_visitor;
|
||||
|
||||
// define enum types and values for new named parameters
|
||||
#define CGAL_add_named_parameter(X, Y, Z) \
|
||||
|
|
|
|||
|
|
@ -67,6 +67,9 @@ CGAL_add_named_parameter(overlap_test_t, overlap_test, do_overlap_test_of_bounde
|
|||
CGAL_add_named_parameter(preserve_genus_t, preserve_genus, preserve_genus)
|
||||
CGAL_add_named_parameter(apply_per_connected_component_t, apply_per_connected_component, apply_per_connected_component)
|
||||
CGAL_add_named_parameter(projection_functor_t, projection_functor, projection_functor)
|
||||
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)
|
||||
|
||||
// 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)
|
||||
|
|
|
|||
|
|
@ -73,6 +73,9 @@ void test(const NamedParameters& np)
|
|||
assert(get_param(np, CGAL::internal_np::number_of_points_on_edges).v == 31);
|
||||
assert(get_param(np, CGAL::internal_np::nb_points_per_area_unit).v == 32);
|
||||
assert(get_param(np, CGAL::internal_np::nb_points_per_distance_unit).v == 33);
|
||||
assert(get_param(np, CGAL::internal_np::throw_on_self_intersection).v == 43);
|
||||
assert(get_param(np, CGAL::internal_np::clip_volume).v == 44);
|
||||
assert(get_param(np, CGAL::internal_np::use_compact_clipper).v == 45);
|
||||
|
||||
// Named parameters that we use in the package 'Surface Mesh Simplification'
|
||||
assert(get_param(np, CGAL::internal_np::get_cost_policy).v == 34);
|
||||
|
|
@ -87,8 +90,8 @@ void test(const NamedParameters& np)
|
|||
assert(get_param(np, CGAL::internal_np::weight_calculator).v == 39);
|
||||
assert(get_param(np, CGAL::internal_np::preserve_genus).v == 40);
|
||||
assert(get_param(np, CGAL::internal_np::verbosity_level).v == 41);
|
||||
assert(get_param(np, CGAL::internal_np::apply_per_connected_component).v == 42);
|
||||
assert(get_param(np, CGAL::internal_np::projection_functor).v == 43);
|
||||
assert(get_param(np, CGAL::internal_np::projection_functor).v == 42);
|
||||
assert(get_param(np, CGAL::internal_np::apply_per_connected_component).v == 46);
|
||||
|
||||
|
||||
// Test types
|
||||
|
|
@ -140,6 +143,9 @@ void test(const NamedParameters& np)
|
|||
check_same_type<31>(get_param(np, CGAL::internal_np::number_of_points_on_edges));
|
||||
check_same_type<32>(get_param(np, CGAL::internal_np::nb_points_per_area_unit));
|
||||
check_same_type<33>(get_param(np, CGAL::internal_np::nb_points_per_distance_unit));
|
||||
check_same_type<43>(get_param(np, CGAL::internal_np::throw_on_self_intersection));
|
||||
check_same_type<44>(get_param(np, CGAL::internal_np::clip_volume));
|
||||
check_same_type<45>(get_param(np, CGAL::internal_np::use_compact_clipper));
|
||||
|
||||
// Named parameters that we use in the package 'Surface Mesh Simplification'
|
||||
check_same_type<34>(get_param(np, CGAL::internal_np::get_cost_policy));
|
||||
|
|
@ -154,8 +160,8 @@ void test(const NamedParameters& np)
|
|||
check_same_type<39>(get_param(np, CGAL::internal_np::weight_calculator));
|
||||
check_same_type<40>(get_param(np, CGAL::internal_np::preserve_genus));
|
||||
check_same_type<41>(get_param(np, CGAL::internal_np::verbosity_level));
|
||||
check_same_type<42>(get_param(np, CGAL::internal_np::apply_per_connected_component));
|
||||
check_same_type<43>(get_param(np, CGAL::internal_np::projection_functor));
|
||||
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));
|
||||
}
|
||||
|
||||
int main()
|
||||
|
|
@ -206,8 +212,11 @@ int main()
|
|||
.weight_calculator(A<39>(39))
|
||||
.preserve_genus(A<40>(40))
|
||||
.verbosity_level(A<41>(41))
|
||||
.apply_per_connected_component(A<42>(42))
|
||||
.projection_functor(A<43>(43))
|
||||
.projection_functor(A<42>(42))
|
||||
.throw_on_self_intersection(A<43>(43))
|
||||
.clip_volume(A<44>(44))
|
||||
.use_compact_clipper(A<45>(45))
|
||||
.apply_per_connected_component(A<46>(46))
|
||||
);
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
|
|
|
|||
|
|
@ -68,6 +68,17 @@ Release date: September 2018
|
|||
|
||||
- Added a function to apply a transformation to a mesh:
|
||||
- `CGAL::Polygon_mesh_processing::transform()`
|
||||
- Added in corefinement-related functions a new named parameter `visitor`
|
||||
that makes it possible to pass a visitor to the function in order to track
|
||||
the creation of new faces.
|
||||
- Added in all corefinement-related functions a named parameter `throw_on_self_intersection`
|
||||
(that replaces the `bool` parameter in `corefine()`) that enables to check for
|
||||
self-intersecting faces involved in the intersection before trying to corefine the
|
||||
input meshes.
|
||||
- Added the function `corefine_and_compute_boolean_operations()` that can be used to
|
||||
compute the result of several Boolean operations between 2 volumes at the same time.
|
||||
- Added the function `clip()` that can be used to clip a triangulated surface mesh
|
||||
by a plane or a clipping volume.
|
||||
|
||||
- Fix a bug in `isotropic_remeshing()` making constrained vertices missing in the output
|
||||
- Guarantee that constrained vertices are kept in the mesh after calling `isotropic_remeshing()`
|
||||
|
|
|
|||
|
|
@ -2049,6 +2049,20 @@ namespace CommonKernelFunctors {
|
|||
CGAL_assertion(e_pt!=NULL);
|
||||
return *e_pt;
|
||||
}
|
||||
|
||||
Point
|
||||
operator()(const Plane& plane,
|
||||
const Point& l1, const Point& l2) const
|
||||
{
|
||||
Line line = construct_line( l1, l2 );
|
||||
|
||||
typename cpp11::result_of<typename K::Intersect_3(Plane,Line)>::type
|
||||
res = typename K::Intersect_3()(plane,line);
|
||||
CGAL_assertion(res!=boost::none);
|
||||
const Point* e_pt = boost::get<Point>(&(*res));
|
||||
CGAL_assertion(e_pt!=NULL);
|
||||
return *e_pt;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename K>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,45 @@
|
|||
/// \ingroup PkgPolygonMeshProcessingConcepts
|
||||
/// \cgalConcept
|
||||
///
|
||||
/// The concept `PMPCorefinementVisitor` defines the requirements for the visitor
|
||||
/// used in \link PMP_corefinement_grp corefinement-related functions \endlink to track
|
||||
/// the creation of new faces.
|
||||
///
|
||||
/// \cgalRefines `CopyConstructible`
|
||||
/// \cgalHasModel `CGAL::Polygon_mesh_processing::Corefinement::Default_visitor`.
|
||||
|
||||
|
||||
class PMPCorefinementVisitor{
|
||||
public:
|
||||
/// Mesh type
|
||||
typedef unspecified_type Triangle_mesh;
|
||||
/// Face decriptor type
|
||||
typedef unspecified_type face_descriptor;
|
||||
|
||||
/// @name Functions used by corefine()
|
||||
/// @{
|
||||
/// called before the triangulation of `f_split` in `tm`. Note that `f_split`
|
||||
/// will be one of the faces of the triangulation. Each subsequent call to
|
||||
/// `before_subface_created()`/`after_subface_created()` will correspond to
|
||||
/// the creation of a new face of the triangulation of `f_split`.
|
||||
void before_subface_creations(face_descriptor f_split, Triangle_mesh& tm);
|
||||
/// called when the triangulation of a face in `tm` is finished
|
||||
void after_subface_creations(Triangle_mesh& tm);
|
||||
/// called before creating a new triangle face in `tm` to triangulate the face passed to `before_subface_creations()`
|
||||
void before_subface_created(Triangle_mesh& tm);
|
||||
/// called after creating a new triangle face `f_new` in `tm` to triangulate the face passed to `before_subface_creations()`.
|
||||
/// Note that the call is placed just after a call to `add_face()` so the halfedge pointer is not set yet.
|
||||
void after_subface_created(face_descriptor f_new, Triangle_mesh& tm);
|
||||
/// @}
|
||||
|
||||
/// @name Functions used by Boolean operations functions using corefinement.
|
||||
/// These functions are not needed if you only call `corefine()`.
|
||||
/// @{
|
||||
/// called before importing the face `f_src` of `tm_src` in `tm_tgt`
|
||||
void before_face_copy(face_descriptor f_src, Triangle_mesh& tm_src, Triangle_mesh& tm_tgt);
|
||||
/// called after importing the face `f_src` of `tm_src` in `tm_tgt`. The new face is `f_tgt`.
|
||||
/// Note that the call is placed just after a call to `add_face()` so the halfedge pointer is not set yet.
|
||||
void after_face_copy(face_descriptor f_src, Triangle_mesh& tm_src,
|
||||
face_descriptor f_tgt, Triangle_mesh& tm_tgt);
|
||||
/// @}
|
||||
};
|
||||
|
|
@ -332,6 +332,39 @@ of a mesh independently.\n
|
|||
\b Type : `bool` \n
|
||||
\b Default value is `false`
|
||||
\cgalNPEnd
|
||||
|
||||
\cgalNPBegin{visitor} \anchor PMP_visitor
|
||||
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
|
||||
\cgalNPEnd
|
||||
|
||||
\cgalNPBegin{throw_on_self_intersection} \anchor PMP_throw_on_self_intersection
|
||||
Parameter used in corefinement-related functions to make the functions throw an exception in
|
||||
case some faces involved in the intersection of the input are self-intersecting
|
||||
and make the operation impossible with the current version of the code.
|
||||
\n
|
||||
\b Type : `bool` \n
|
||||
\b Default value is `false`
|
||||
\cgalNPEnd
|
||||
|
||||
\cgalNPBegin{clip_volume} \anchor PMP_clip_volume
|
||||
Parameter used in `clip()` functions to clip a volume rather than a surface.
|
||||
\n
|
||||
\b Type : `bool` \n
|
||||
\b Default value is `false`
|
||||
\cgalNPEnd
|
||||
|
||||
\cgalNPBegin{use_compact_clipper} \anchor PMP_use_compact_clipper
|
||||
Parameter used in `clip()` functions to indicate whether the boundary of the clipper
|
||||
should be considered as part of the clipping volume or not.
|
||||
\n
|
||||
\b Type : `bool` \n
|
||||
\b Default value is `true`
|
||||
\cgalNPEnd
|
||||
|
||||
|
||||
\cgalNPTableEnd
|
||||
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -145,8 +145,10 @@ and provides a list of the parameters that are used in this package.
|
|||
- `CGAL::Polygon_mesh_processing::corefine_and_compute_union()`
|
||||
- `CGAL::Polygon_mesh_processing::corefine_and_compute_difference()`
|
||||
- `CGAL::Polygon_mesh_processing::corefine_and_compute_intersection()`
|
||||
- `CGAL::Polygon_mesh_processing::corefine_and_compute_boolean_operations()`
|
||||
- `CGAL::Polygon_mesh_processing::corefine()`
|
||||
- `CGAL::Polygon_mesh_processing::surface_intersection()`
|
||||
- `CGAL::Polygon_mesh_processing::clip()`
|
||||
- `CGAL::Polygon_mesh_processing::does_bound_a_volume()`
|
||||
|
||||
## Geometric Measure Functions ##
|
||||
|
|
@ -178,6 +180,4 @@ and provides a list of the parameters that are used in this package.
|
|||
- `CGAL::Polygon_mesh_processing::border_halfedges()`
|
||||
- `CGAL::Polygon_mesh_processing::transform()`
|
||||
|
||||
\todo add `clip_triangle_mesh()` using the code of `Polyhedron_place_clipping.h` and `PMP::corefine()`
|
||||
\todo fix and restore remove_degenerate_faces in the user and the reference manual
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -215,9 +215,10 @@ Considering two triangulated surface meshes, each bounding
|
|||
a volume, the functions `CGAL::Polygon_mesh_processing::corefine_and_compute_union()`,
|
||||
`CGAL::Polygon_mesh_processing::corefine_and_compute_intersection()` and
|
||||
`CGAL::Polygon_mesh_processing::corefine_and_compute_difference()` respectively compute the union,
|
||||
the intersection and the difference of the two volumes.
|
||||
Note that there is no restriction on the topology of the input volumes.
|
||||
the intersection and the difference of the two volumes. If several Boolean operations must be
|
||||
computed at the same time, the function `corefine_and_compute_boolean_operations()` should be used.
|
||||
|
||||
There is no restriction on the topology of the input volumes.
|
||||
However, there are some requirements on the input to guarantee that
|
||||
the operation is possible. First, the input meshes must not self-intersect.
|
||||
Second, the operation is possible only if the output
|
||||
|
|
@ -252,6 +253,28 @@ edges will be split at each intersection with a triangle but the
|
|||
position of the intersection point might create self-intersections due to
|
||||
the limited precision of floating point numbers.
|
||||
|
||||
\subsection coref_clip Clipping
|
||||
|
||||
As a natural extension, some clipping functionalities with a volume bounded by a closed mesh
|
||||
and a halfspace (defined by the negative side of a plane to be consistent with
|
||||
the outward normal convention) are offered. The functions `CGAL::Polygon_mesh_processing::clip()`
|
||||
have some options to select whether the clipping should be done at the volume or surface
|
||||
level, and also if the clipper should be considered as compact or not. This is illustrated on
|
||||
\cgalFigureRef{coref_clip_close_open} and \cgalFigureRef{coref_clip_compact}.
|
||||
|
||||
\cgalFigureBegin{coref_clip_close_open, clip_open_close.png}
|
||||
Clipping a cube with a halfspace. From left to right: (i) initial cube and the plane
|
||||
defining the clipping halfspace; (ii) `close_volumes=false`: clipping of the surface mesh (boundary edges
|
||||
depicted in red); (iii) `close_volumes=true`: clipping of the volume bounded by the surface mesh.
|
||||
\cgalFigureEnd
|
||||
|
||||
\cgalFigureBegin{coref_clip_compact, clip_compact.png}
|
||||
Clipping a cube with a halfspace: compacity of the clipper (`close_volumes=false` in both cases).
|
||||
From left to right: (i) initial cube and the plane defining the clipping halfspace,
|
||||
note that a whole face of the cube (2 triangles) is exactly contained in the plane;
|
||||
(ii) `use_compact_clipper=true`: clipping of the surface mesh with a compact halfspace: coplanar faces are part of the output;
|
||||
(iii) `use_compact_clipper=false`: clipping of the surface mesh with a non-compact halfspace: coplanar faces are not part of the output.
|
||||
\cgalFigureEnd
|
||||
|
||||
\subsection coref_ex_subsec Examples
|
||||
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@
|
|||
\example Poisson_surface_reconstruction_3/poisson_reconstruction_example.cpp
|
||||
\example Polygon_mesh_processing/corefinement_difference_remeshed.cpp
|
||||
\example Polygon_mesh_processing/corefinement_mesh_union.cpp
|
||||
\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
|
||||
*/
|
||||
|
|
|
|||
Binary file not shown.
|
After Width: | Height: | Size: 55 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 56 KiB |
|
|
@ -97,6 +97,8 @@ create_single_source_cgal_program( "corefinement_SM.cpp")
|
|||
create_single_source_cgal_program( "corefinement_consecutive_bool_op.cpp" )
|
||||
create_single_source_cgal_program( "corefinement_difference_remeshed.cpp" )
|
||||
create_single_source_cgal_program( "corefinement_mesh_union.cpp" )
|
||||
create_single_source_cgal_program( "corefinement_mesh_union_and_intersection.cpp" )
|
||||
create_single_source_cgal_program( "corefinement_mesh_union_with_attributes.cpp" )
|
||||
create_single_source_cgal_program( "corefinement_polyhedron_union.cpp" )
|
||||
create_single_source_cgal_program( "random_perturbation_SM_example.cpp" )
|
||||
create_single_source_cgal_program( "corefinement_LCC.cpp")
|
||||
|
|
|
|||
|
|
@ -0,0 +1,73 @@
|
|||
#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
|
||||
#include <CGAL/Surface_mesh.h>
|
||||
|
||||
#include <CGAL/Polygon_mesh_processing/corefinement.h>
|
||||
|
||||
#include <fstream>
|
||||
|
||||
typedef CGAL::Exact_predicates_inexact_constructions_kernel K;
|
||||
typedef CGAL::Surface_mesh<K::Point_3> Mesh;
|
||||
|
||||
namespace PMP = CGAL::Polygon_mesh_processing;
|
||||
namespace params = CGAL::Polygon_mesh_processing::parameters;
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
const char* filename1 = (argc > 1) ? argv[1] : "data/blobby.off";
|
||||
const char* filename2 = (argc > 2) ? argv[2] : "data/eight.off";
|
||||
std::ifstream input(filename1);
|
||||
|
||||
Mesh mesh1, mesh2;
|
||||
if (!input || !(input >> mesh1))
|
||||
{
|
||||
std::cerr << "First mesh is not a valid off file." << std::endl;
|
||||
return 1;
|
||||
}
|
||||
input.close();
|
||||
input.open(filename2);
|
||||
if (!input || !(input >> mesh2))
|
||||
{
|
||||
std::cerr << "Second mesh is not a valid off file." << std::endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
Mesh out_union, out_intersection;
|
||||
CGAL::cpp11::array<boost::optional<Mesh*>, 4> output;
|
||||
output[PMP::Corefinement::UNION] = &out_union;
|
||||
output[PMP::Corefinement::INTERSECTION] = &out_intersection;
|
||||
|
||||
// for the example, we explicit the named parameters, this is identical to
|
||||
// PMP::corefine_and_compute_boolean_operations(mesh1, mesh2, output)
|
||||
CGAL::cpp11::array<bool, 4> res =
|
||||
PMP::corefine_and_compute_boolean_operations(
|
||||
mesh1, mesh2,
|
||||
output,
|
||||
params::all_default(), // mesh1 named parameters
|
||||
params::all_default(), // mesh2 named parameters
|
||||
CGAL::cpp11::make_tuple(
|
||||
params::vertex_point_map(get(boost::vertex_point, out_union)), // named parameters for out_union
|
||||
params::vertex_point_map(get(boost::vertex_point, out_intersection)), // named parameters for out_intersection
|
||||
params::all_default(), // named parameters for mesh1-mesh2 not used
|
||||
params::all_default() )// named parameters for mesh2-mesh1 not used)
|
||||
);
|
||||
|
||||
if (res[PMP::Corefinement::UNION])
|
||||
{
|
||||
std::cout << "Union was successfully computed\n";
|
||||
std::ofstream output("union.off");
|
||||
output << out_union;
|
||||
}
|
||||
else
|
||||
std::cout << "Union could not be computed\n";
|
||||
|
||||
if (res[PMP::Corefinement::INTERSECTION])
|
||||
{
|
||||
std::cout << "Intersection was successfully computed\n";
|
||||
std::ofstream output("intersection.off");
|
||||
output << out_intersection;
|
||||
}
|
||||
else
|
||||
std::cout << "Intersection could not be computed\n";
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -0,0 +1,103 @@
|
|||
#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
|
||||
#include <CGAL/Surface_mesh.h>
|
||||
#include <boost/container/flat_map.hpp>
|
||||
#include <CGAL/Polygon_mesh_processing/corefinement.h>
|
||||
|
||||
#include <fstream>
|
||||
|
||||
typedef CGAL::Exact_predicates_inexact_constructions_kernel K;
|
||||
typedef CGAL::Surface_mesh<K::Point_3> Mesh;
|
||||
|
||||
namespace PMP = CGAL::Polygon_mesh_processing;
|
||||
|
||||
struct Visitor :
|
||||
public PMP::Corefinement::Default_visitor<Mesh>
|
||||
{
|
||||
typedef Mesh::Face_index face_descriptor;
|
||||
|
||||
boost::container::flat_map<const Mesh*, Mesh::Property_map<Mesh::Face_index, int> > properties;
|
||||
int face_id;
|
||||
|
||||
Visitor()
|
||||
{
|
||||
properties.reserve(3);
|
||||
face_id=-1;
|
||||
}
|
||||
|
||||
// visitor API overloaded
|
||||
void before_subface_creations(face_descriptor f_split,Mesh& tm)
|
||||
{
|
||||
face_id = properties[&tm][f_split];
|
||||
}
|
||||
|
||||
void after_subface_created(face_descriptor f_new,Mesh& tm)
|
||||
{
|
||||
properties[&tm][f_new] = face_id;
|
||||
}
|
||||
|
||||
void after_face_copy(face_descriptor f_src, Mesh& tm_src,
|
||||
face_descriptor f_tgt, Mesh& tm_tgt)
|
||||
{
|
||||
properties[&tm_tgt][f_tgt] = properties[&tm_src][f_src];
|
||||
}
|
||||
};
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
const char* filename1 = (argc > 1) ? argv[1] : "data/blobby.off";
|
||||
const char* filename2 = (argc > 2) ? argv[2] : "data/eight.off";
|
||||
std::ifstream input(filename1);
|
||||
|
||||
Mesh mesh1, mesh2;
|
||||
if (!input || !(input >> mesh1))
|
||||
{
|
||||
std::cerr << "First mesh is not a valid off file." << std::endl;
|
||||
return 1;
|
||||
}
|
||||
input.close();
|
||||
input.open(filename2);
|
||||
if (!input || !(input >> mesh2))
|
||||
{
|
||||
std::cerr << "Second mesh is not a valid off file." << std::endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
Mesh out;
|
||||
|
||||
// add a property in each mesh to track the parent mesh for each face of the output
|
||||
Mesh::Property_map<Mesh::Face_index, int>
|
||||
mesh1_id = mesh1.add_property_map<Mesh::Face_index, int>("f:id", -1).first,
|
||||
mesh2_id = mesh2.add_property_map<Mesh::Face_index, int>("f:id", -1).first,
|
||||
out_id = out.add_property_map<Mesh::Face_index, int>("f:id", -1).first;
|
||||
|
||||
// init the face ids (for the purpose of the example but choosing 1 (2) as default value of the map would avoid the loop)
|
||||
BOOST_FOREACH(Mesh::Face_index f, faces(mesh1))
|
||||
mesh1_id[f] = 1;
|
||||
BOOST_FOREACH(Mesh::Face_index f, faces(mesh2))
|
||||
mesh2_id[f] = 2;
|
||||
|
||||
Visitor visitor;
|
||||
visitor.properties[&mesh1] = mesh1_id;
|
||||
visitor.properties[&mesh2] = mesh2_id;
|
||||
visitor.properties[&out] = out_id;
|
||||
|
||||
bool valid_union = PMP::corefine_and_compute_union(mesh1, mesh2, out, PMP::parameters::visitor(visitor));
|
||||
|
||||
BOOST_FOREACH(Mesh::Face_index f, faces(mesh1))
|
||||
assert( mesh1_id[f] == 1 );
|
||||
BOOST_FOREACH(Mesh::Face_index f, faces(mesh2))
|
||||
assert( mesh2_id[f] == 2 );
|
||||
BOOST_FOREACH(Mesh::Face_index f, faces(out))
|
||||
assert( out_id[f]==1 || out_id[f]==2);
|
||||
|
||||
if (valid_union)
|
||||
{
|
||||
std::cout << "Union was successfully computed\n";
|
||||
std::ofstream output("union.off");
|
||||
output << out;
|
||||
return 0;
|
||||
}
|
||||
|
||||
std::cout << "Union could not be computed\n";
|
||||
return 1;
|
||||
}
|
||||
|
|
@ -0,0 +1,589 @@
|
|||
// Copyright (c) 2016 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_CLIP_H
|
||||
#define CGAL_POLYGON_MESH_PROCESSING_CLIP_H
|
||||
|
||||
#include <CGAL/license/Polygon_mesh_processing/corefinement.h>
|
||||
|
||||
|
||||
#include <CGAL/Polygon_mesh_processing/corefinement.h>
|
||||
#include <CGAL/Polygon_mesh_processing/connected_components.h>
|
||||
#include <CGAL/Polygon_mesh_processing/bbox.h>
|
||||
#include <CGAL/Polygon_mesh_processing/triangulate_faces.h>
|
||||
|
||||
#include <CGAL/AABB_triangle_primitive.h>
|
||||
|
||||
namespace CGAL{
|
||||
namespace Polygon_mesh_processing {
|
||||
|
||||
namespace internal
|
||||
{
|
||||
template <class TriangleMesh,
|
||||
class NamedParameters1,
|
||||
class NamedParameters2>
|
||||
bool
|
||||
clip_open_impl( TriangleMesh& tm,
|
||||
TriangleMesh& clipper,
|
||||
const NamedParameters1& np_tm,
|
||||
const NamedParameters2& np_c)
|
||||
{
|
||||
typedef typename GetVertexPointMap<TriangleMesh,
|
||||
NamedParameters1>::type Vpm;
|
||||
typedef typename GetGeomTraits<TriangleMesh, NamedParameters2>::type GeomTraits;
|
||||
typedef boost::graph_traits<TriangleMesh> GT;
|
||||
typedef typename GT::halfedge_descriptor halfedge_descriptor;
|
||||
typedef typename GT::face_descriptor face_descriptor;
|
||||
|
||||
// First build an AABB-tree of the clipper triangles as it will be modified
|
||||
typedef std::vector<typename GeomTraits::Triangle_3> Clipper_triangles;
|
||||
typedef typename Clipper_triangles::iterator Tr_iterator;
|
||||
typedef CGAL::AABB_triangle_primitive<GeomTraits, Tr_iterator> Primitive;
|
||||
typedef CGAL::AABB_traits<GeomTraits, Primitive> AABB_triangle_traits;
|
||||
typedef CGAL::AABB_tree<AABB_triangle_traits> Clipper_tree;
|
||||
|
||||
// vector of clipper triangles
|
||||
Clipper_triangles clipper_triangles;
|
||||
clipper_triangles.reserve( num_faces(clipper) );
|
||||
Vpm vpm_c = boost::choose_param(boost::get_param(np_c, internal_np::vertex_point),
|
||||
get_property_map(vertex_point, clipper));
|
||||
BOOST_FOREACH(face_descriptor f, faces(clipper))
|
||||
{
|
||||
halfedge_descriptor h = halfedge(f, clipper);
|
||||
clipper_triangles.push_back( typename GeomTraits::Triangle_3(
|
||||
get(vpm_c, source(h, clipper)),
|
||||
get(vpm_c, target(h, clipper)),
|
||||
get(vpm_c, target(next(h, clipper), clipper)) ) );
|
||||
}
|
||||
// tree
|
||||
Clipper_tree clipper_tree(clipper_triangles.begin(), clipper_triangles.end());
|
||||
// predicate functor
|
||||
Side_of_triangle_mesh<TriangleMesh, GeomTraits, Vpm, Clipper_tree> side_of(clipper_tree);
|
||||
|
||||
// Second corefine the meshes
|
||||
typedef CGAL::dynamic_edge_property_t<bool> Ecm_tag;
|
||||
typedef typename boost::property_map<TriangleMesh, Ecm_tag>::type Ecm;
|
||||
Ecm ecm = get(Ecm_tag(), tm);
|
||||
|
||||
corefine(tm, clipper, np_tm.edge_is_constrained_map(ecm), np_c);
|
||||
|
||||
// Extract connected components
|
||||
typedef typename GetFaceIndexMap<TriangleMesh,
|
||||
NamedParameters1>::type Fid_map;
|
||||
|
||||
Fid_map fid_map = boost::choose_param(boost::get_param(np_tm, internal_np::face_index),
|
||||
get_property_map(boost::face_index, tm));
|
||||
Vpm vpm1 = boost::choose_param(boost::get_param(np_tm, internal_np::vertex_point),
|
||||
get_property_map(vertex_point, tm));
|
||||
|
||||
typedef CGAL::dynamic_vertex_property_t<std::size_t> Vid_tag;
|
||||
typedef typename boost::property_map<TriangleMesh, Vid_tag>::type Vid_map;
|
||||
Vid_map vid_map = get(Vid_tag(), tm);
|
||||
|
||||
// init indices if needed
|
||||
helpers::init_face_indices(tm, fid_map);
|
||||
helpers::init_vertex_indices(tm, vid_map);
|
||||
|
||||
// set the connected component id of each face
|
||||
std::vector<std::size_t> face_cc(num_faces(tm), std::size_t(-1));
|
||||
std::size_t nb_cc =
|
||||
connected_components(tm,
|
||||
bind_property_maps(fid_map, make_property_map(face_cc)),
|
||||
parameters::face_index_map(fid_map).
|
||||
edge_is_constrained_map(ecm));
|
||||
|
||||
|
||||
boost::dynamic_bitset<> cc_not_handled(nb_cc);
|
||||
cc_not_handled.set();
|
||||
std::vector <std::size_t> ccs_to_remove;
|
||||
|
||||
BOOST_FOREACH(face_descriptor f, faces(tm))
|
||||
{
|
||||
std::size_t cc_id = face_cc[ get(fid_map, f) ];
|
||||
if ( !cc_not_handled.test(cc_id) ) continue;
|
||||
|
||||
halfedge_descriptor h=halfedge(f, tm);
|
||||
for(int i=0;i<3;++i)
|
||||
{
|
||||
// look for a vertex not on a constrained edge
|
||||
bool no_marked_edge=true;
|
||||
BOOST_FOREACH(halfedge_descriptor h2, halfedges_around_target(h, tm))
|
||||
if ( get(ecm, edge(h2, tm)) ){
|
||||
no_marked_edge=false;
|
||||
break;
|
||||
}
|
||||
if (no_marked_edge){
|
||||
if ( side_of( get(vpm1, target(h, tm) ) ) == ON_UNBOUNDED_SIDE )
|
||||
ccs_to_remove.push_back(cc_id);
|
||||
cc_not_handled.reset(cc_id);
|
||||
break;
|
||||
}
|
||||
h=next(h, tm);
|
||||
}
|
||||
if (!cc_not_handled.any()) break;
|
||||
}
|
||||
|
||||
if (cc_not_handled.any())
|
||||
{
|
||||
// A patch without no vertex incident to a non-constrained edges
|
||||
// is a coplanar patch: drop it or keep it!
|
||||
if (!boost::choose_param(boost::get_param(np_tm, internal_np::use_compact_clipper), true))
|
||||
{
|
||||
for (std::size_t cc_id = cc_not_handled.find_first();
|
||||
cc_id < cc_not_handled.npos;
|
||||
cc_id = cc_not_handled.find_next(cc_id))
|
||||
{
|
||||
ccs_to_remove.push_back(cc_id);
|
||||
}
|
||||
}
|
||||
}
|
||||
// Filter out the cc
|
||||
remove_connected_components(tm,
|
||||
ccs_to_remove,
|
||||
bind_property_maps(fid_map, make_property_map(face_cc)),
|
||||
parameters::vertex_index_map(vid_map));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
template <class Geom_traits, class Plane_3, class Point_3>
|
||||
int
|
||||
inter_pt_index(int i, int j,
|
||||
const Plane_3& plane,
|
||||
std::vector<Point_3>& points,
|
||||
std::map<std::pair<int,int>, int>& id_map)
|
||||
{
|
||||
std::pair<std::map<std::pair<int,int>, int>::iterator, bool> res =
|
||||
id_map.insert(std::make_pair(make_sorted_pair(i,j),
|
||||
static_cast<int> (points.size())));
|
||||
if (res.second)
|
||||
points.push_back(
|
||||
typename Geom_traits::Construct_plane_line_intersection_point_3()
|
||||
(plane, points[i], points[j]) );
|
||||
|
||||
return res.first->second;
|
||||
}
|
||||
|
||||
template <class Plane_3,
|
||||
class TriangleMesh,
|
||||
class NamedParameters>
|
||||
Oriented_side
|
||||
clip_to_bbox(const Plane_3& plane,
|
||||
const Bbox_3& bbox,
|
||||
TriangleMesh& tm_out,
|
||||
const NamedParameters& np )
|
||||
{
|
||||
typedef typename GetGeomTraits<TriangleMesh, NamedParameters>::type Geom_traits;
|
||||
typedef typename Geom_traits::Point_3 Point_3;
|
||||
typedef typename GetVertexPointMap<TriangleMesh,
|
||||
NamedParameters>::type Vpm;
|
||||
|
||||
Vpm vpm_out = boost::choose_param(boost::get_param(np, internal_np::vertex_point),
|
||||
get_property_map(boost::vertex_point, tm_out));
|
||||
|
||||
|
||||
std::vector<Point_3> corners(8);
|
||||
corners[0] = Point_3(bbox.xmin(),bbox.ymin(),bbox.zmin());
|
||||
corners[1] = Point_3(bbox.xmin(),bbox.ymax(),bbox.zmin());
|
||||
corners[2] = Point_3(bbox.xmax(),bbox.ymax(),bbox.zmin());
|
||||
corners[3] = Point_3(bbox.xmax(),bbox.ymin(),bbox.zmin());
|
||||
corners[4] = Point_3(bbox.xmin(),bbox.ymin(),bbox.zmax());
|
||||
corners[5] = Point_3(bbox.xmin(),bbox.ymax(),bbox.zmax());
|
||||
corners[6] = Point_3(bbox.xmax(),bbox.ymax(),bbox.zmax());
|
||||
corners[7] = Point_3(bbox.xmax(),bbox.ymin(),bbox.zmax());
|
||||
|
||||
cpp11::array<CGAL::Oriented_side,8> orientations = {{
|
||||
plane.oriented_side(corners[0]),
|
||||
plane.oriented_side(corners[1]),
|
||||
plane.oriented_side(corners[2]),
|
||||
plane.oriented_side(corners[3]),
|
||||
plane.oriented_side(corners[4]),
|
||||
plane.oriented_side(corners[5]),
|
||||
plane.oriented_side(corners[6]),
|
||||
plane.oriented_side(corners[7])
|
||||
}};
|
||||
|
||||
// description of faces of the bbox
|
||||
cpp11::array<int, 24> face_indices =
|
||||
{{ 0, 1, 2, 3,
|
||||
2, 1, 5, 6,
|
||||
3, 2, 6, 7,
|
||||
1, 0, 4, 5,
|
||||
4, 0, 3, 7,
|
||||
6, 5, 4, 7 }};
|
||||
|
||||
std::map<std::pair<int,int>, int> id_map;
|
||||
std::vector< std::vector<int> > output_faces(6);
|
||||
bool all_in = true;
|
||||
bool all_out = true;
|
||||
std::set<int> in_point_ids; // to collect the set of points in the clipped bbox
|
||||
|
||||
// for each face of the bbox, we look for intersection of the plane with its edges
|
||||
for (int i=0; i<6; ++i)
|
||||
{
|
||||
for (int k=0; k< 4; ++k)
|
||||
{
|
||||
int current_id = face_indices[4*i + k];
|
||||
int next_id = face_indices[4*i + (k+1)%4];
|
||||
|
||||
if ( orientations[ current_id ] != ON_POSITIVE_SIDE )
|
||||
{
|
||||
all_out=false;
|
||||
// point on or on the negative side
|
||||
output_faces[i].push_back( current_id );
|
||||
in_point_ids.insert( output_faces[i].back() );
|
||||
// check for intersection of the edge
|
||||
if (orientations[ current_id ] == ON_NEGATIVE_SIDE &&
|
||||
orientations[ next_id ] == ON_POSITIVE_SIDE)
|
||||
{
|
||||
output_faces[i].push_back(
|
||||
inter_pt_index<Geom_traits>(current_id, next_id, plane, corners, id_map) );
|
||||
in_point_ids.insert( output_faces[i].back() );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
all_in = false;
|
||||
// check for intersection of the edge
|
||||
if ( orientations[ next_id ] == ON_NEGATIVE_SIDE )
|
||||
{
|
||||
output_faces[i].push_back(
|
||||
inter_pt_index<Geom_traits>(current_id, next_id, plane, corners, id_map) );
|
||||
in_point_ids.insert( output_faces[i].back() );
|
||||
}
|
||||
}
|
||||
}
|
||||
CGAL_assertion( output_faces[i].empty() || output_faces[i].size() >= 3 );
|
||||
}
|
||||
|
||||
// the intersection is the full bbox
|
||||
if (all_in) return ON_NEGATIVE_SIDE;
|
||||
if (all_out) return ON_POSITIVE_SIDE;
|
||||
|
||||
// build the clipped bbox
|
||||
typedef boost::graph_traits<TriangleMesh> graph_traits;
|
||||
typedef typename graph_traits::vertex_descriptor vertex_descriptor;
|
||||
typedef typename graph_traits::halfedge_descriptor halfedge_descriptor;
|
||||
typedef typename graph_traits::face_descriptor face_descriptor;
|
||||
|
||||
std::map<int, vertex_descriptor> out_vertices;
|
||||
BOOST_FOREACH(int i, in_point_ids)
|
||||
{
|
||||
vertex_descriptor v = add_vertex(tm_out);
|
||||
out_vertices.insert( std::make_pair(i, v ) );
|
||||
put(vpm_out, v, corners[i]);
|
||||
}
|
||||
|
||||
std::map< std::pair<int,int>, halfedge_descriptor> hedge_map;
|
||||
const halfedge_descriptor null_hedge = graph_traits::null_halfedge();
|
||||
const face_descriptor null_fd = graph_traits::null_face();
|
||||
BOOST_FOREACH( const std::vector<int>& findices, output_faces)
|
||||
{
|
||||
if (findices.empty()) continue;
|
||||
const face_descriptor fd=add_face(tm_out);
|
||||
int prev_id = findices.back();
|
||||
|
||||
// create of recover face boundary halfedges
|
||||
std::vector<halfedge_descriptor> hedges;
|
||||
hedges.reserve(findices.size());
|
||||
BOOST_FOREACH( int current_id, findices)
|
||||
{
|
||||
vertex_descriptor src = out_vertices[prev_id], tgt = out_vertices[current_id];
|
||||
|
||||
std::pair<typename std::map< std::pair<int,int>,
|
||||
halfedge_descriptor>::iterator, bool> res =
|
||||
hedge_map.insert( std::make_pair(std::make_pair(prev_id, current_id), null_hedge) );
|
||||
if (res.second)
|
||||
{
|
||||
res.first->second = halfedge( add_edge(tm_out), tm_out);
|
||||
hedge_map.insert( std::make_pair(std::make_pair(current_id, prev_id),
|
||||
opposite(res.first->second, tm_out) ) );
|
||||
set_face(opposite(res.first->second, tm_out), null_fd, tm_out);
|
||||
|
||||
}
|
||||
hedges.push_back(res.first->second);
|
||||
// set edge source and target
|
||||
set_target(hedges.back(), tgt, tm_out);
|
||||
set_target(opposite(hedges.back(), tm_out), src, tm_out);
|
||||
// set face pointer of halfedges
|
||||
set_face(hedges.back(), fd, tm_out);
|
||||
// set vertex halfedge
|
||||
set_halfedge(src, opposite(hedges.back(), tm_out), tm_out);
|
||||
set_halfedge(tgt, hedges.back(), tm_out);
|
||||
|
||||
if (current_id==findices.front())
|
||||
set_halfedge(fd, hedges.back(), tm_out);
|
||||
|
||||
prev_id = current_id;
|
||||
}
|
||||
CGAL_assertion(hedges.size() == findices.size());
|
||||
|
||||
// set next/prev relationship
|
||||
halfedge_descriptor prev_h=hedges.back();
|
||||
BOOST_FOREACH(halfedge_descriptor h, hedges)
|
||||
{
|
||||
set_next(prev_h, h, tm_out);
|
||||
prev_h = h;
|
||||
}
|
||||
}
|
||||
|
||||
// handle the face of the plane:
|
||||
// look for a border halfedge and reconstruct the face of the plane
|
||||
// by turning around vertices inside the mesh constructed above
|
||||
// until we reach another border halfedge
|
||||
BOOST_FOREACH(halfedge_descriptor h, halfedges(tm_out))
|
||||
{
|
||||
if (face(h, tm_out) == null_fd)
|
||||
{
|
||||
face_descriptor fd = add_face(tm_out);
|
||||
set_halfedge(fd, h, tm_out);
|
||||
|
||||
halfedge_descriptor h_prev=h;
|
||||
halfedge_descriptor h_curr=h;
|
||||
do{
|
||||
h_curr=opposite(h_curr, tm_out);
|
||||
do{
|
||||
h_curr=opposite(prev(h_curr, tm_out), tm_out);
|
||||
} while(face(h_curr, tm_out) != null_fd && h_curr!=h);
|
||||
set_face(h_prev, fd, tm_out);
|
||||
set_next(h_prev, h_curr, tm_out);
|
||||
if (h_curr==h)
|
||||
break;
|
||||
h_prev=h_curr;
|
||||
} while(true);
|
||||
break;
|
||||
}
|
||||
}
|
||||
CGAL_assertion(is_valid_polygon_mesh(tm_out));
|
||||
|
||||
// triangulate the faces
|
||||
CGAL::Polygon_mesh_processing::triangulate_faces(tm_out, np);
|
||||
|
||||
return ON_ORIENTED_BOUNDARY;
|
||||
}
|
||||
|
||||
} // end of internal namespace
|
||||
|
||||
/**
|
||||
* \ingroup PMP_corefinement_grp
|
||||
* clips `tm` by keeping the part that is inside the volume \link coref_def_subsec bounded \endlink
|
||||
* by `clipper`.
|
||||
* If `tm` is closed, the clipped part can be closed too if the named parameter `clip_volume` is set to `true`.
|
||||
* See subsection \ref coref_clip for more details.
|
||||
* \attention With the current implementation, `clipper` will be modified (refined with the intersection with `tm`).
|
||||
*
|
||||
* \pre \link CGAL::Polygon_mesh_processing::does_self_intersect() `!CGAL::Polygon_mesh_processing::does_self_intersect(tm1)` \endlink
|
||||
* \pre \link CGAL::Polygon_mesh_processing::does_self_intersect() `!CGAL::Polygon_mesh_processing::does_self_intersect(clipper)` \endlink
|
||||
* \pre \link CGAL::Polygon_mesh_processing::does_bound_a_volume() `CGAL::Polygon_mesh_processing::does_bound_a_volume(clipper)` \endlink
|
||||
*
|
||||
* @tparam TriangleMesh a model of `MutableFaceGraph`, `HalfedgeListGraph` and `FaceListGraph`.
|
||||
* If `TriangleMesh` has an internal property map for `CGAL::face_index_t`,
|
||||
* as a named parameter, then it must be initialized.
|
||||
*
|
||||
* @tparam NamedParameters1 a sequence of \ref pmp_namedparameters "Named Parameters"
|
||||
* @tparam NamedParameters2 a sequence of \ref pmp_namedparameters "Named Parameters"
|
||||
*
|
||||
* @param tm input triangulated surface mesh
|
||||
* @param clipper triangulated surface mesh used to clip `tm`
|
||||
* @param np_tm optional sequence of \ref pmp_namedparameters "Named Parameters" among the ones listed below
|
||||
* @param np_c optional sequence of \ref pmp_namedparameters "Named Parameters" among the ones listed below
|
||||
*
|
||||
* \cgalNamedParamsBegin
|
||||
* \cgalParamBegin{vertex_point_map}
|
||||
* the property map with the points associated to the vertices of `tm` (`clipper`).
|
||||
* If this parameter is omitted, an internal property map for
|
||||
* `CGAL::vertex_point_t` must be available in `TriangleMesh`
|
||||
* \cgalParamEnd
|
||||
* \cgalParamBegin{face_index_map} a property map containing the index of each face of `tm` (`clipper`).
|
||||
* Note that if the property map is writable, the indices of the faces
|
||||
* of `tm` and `clipper` will be set after the refining `tm` with the intersection with `plane`.
|
||||
* \cgalParamEnd
|
||||
* \cgalParamBegin{visitor} a class model of `PMPCorefinementVisitor`
|
||||
* that is used to track the creation of new faces.
|
||||
* \cgalParamEnd
|
||||
* \cgalParamBegin{throw_on_self_intersection} if `true`,
|
||||
* the set of triangles closed to the intersection of `tm` and `clipper` will be
|
||||
* checked for self-intersections and `CGAL::Polygon_mesh_processing::Corefinement::Self_intersection_exception`
|
||||
* will be thrown if at least one is found.
|
||||
* \cgalParamEnd
|
||||
* \cgalParamBegin{clip_volume} if `true` and `tm` is closed, the clipping will be done on
|
||||
* the volume \link coref_def_subsec bounded \endlink by `tm` rather than on its surface
|
||||
* (i.e. `tm` will be kept closed).
|
||||
* \cgalParamEnd
|
||||
* \cgalParamBegin{use_compact_clipper} if `false` and `clip_volume` is `false` and `tm` is open, the parts of `tm` coplanar with `clipper`
|
||||
* will not be part of the output.
|
||||
* \cgalParamEnd
|
||||
* \cgalNamedParamsEnd
|
||||
*
|
||||
* @return `true` if the output surface mesh is manifold.
|
||||
* If `false` is returned `tm` and `clipper` are only corefined.
|
||||
*/
|
||||
template <class TriangleMesh,
|
||||
class NamedParameters1,
|
||||
class NamedParameters2>
|
||||
bool
|
||||
clip( TriangleMesh& tm,
|
||||
TriangleMesh& clipper,
|
||||
const NamedParameters1& np_tm,
|
||||
const NamedParameters2& np_c)
|
||||
{
|
||||
const bool close =
|
||||
boost::choose_param(boost::get_param(np_tm, internal_np::clip_volume), false);
|
||||
|
||||
if (close && is_closed(tm))
|
||||
return corefine_and_compute_intersection(tm, clipper, tm, np_tm, np_c);
|
||||
|
||||
return internal::clip_open_impl(tm, clipper, np_tm, np_c);
|
||||
}
|
||||
|
||||
namespace internal{
|
||||
template <class TriangleMesh, class NamedParameters>
|
||||
bool dispatch_clip_call(TriangleMesh& tm, TriangleMesh& clipper,
|
||||
const NamedParameters& np, Tag_false)
|
||||
{
|
||||
return clip(tm, clipper,
|
||||
np.face_index_map(get(CGAL::dynamic_face_property_t<std::size_t>(), tm)),
|
||||
parameters::face_index_map(get(CGAL::dynamic_face_property_t<std::size_t>(), clipper)));
|
||||
}
|
||||
|
||||
template <class TriangleMesh, class NamedParameters>
|
||||
bool dispatch_clip_call(TriangleMesh& tm, TriangleMesh& clipper,
|
||||
const NamedParameters& np, Tag_true)
|
||||
{
|
||||
return clip(tm, clipper,
|
||||
np.face_index_map(get(face_index, tm)),
|
||||
parameters::face_index_map(get(face_index, clipper)));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* \ingroup PMP_corefinement_grp
|
||||
* clips `tm` by keeping the part that is on the negative side of `plane` (side opposite to its normal vector).
|
||||
* If `tm` is closed, the clipped part can be closed too if the named parameter `clip_volume` is set to `true`.
|
||||
* See subsection \ref coref_clip for more details.
|
||||
*
|
||||
* \note In the current implementation it is not possible to set the vertex point map and the default will be used.
|
||||
* \pre \link CGAL::Polygon_mesh_processing::does_self_intersect() `!CGAL::Polygon_mesh_processing::does_self_intersect(tm)` \endlink
|
||||
*
|
||||
* @tparam TriangleMesh a model of `MutableFaceGraph`, `HalfedgeListGraph` and `FaceListGraph`.
|
||||
* If `TriangleMesh` has an internal property map for `CGAL::face_index_t`,
|
||||
* as a named parameter, then it must be initialized.
|
||||
* An internal property map for `CGAL::vertex_point_t` must be available.
|
||||
*
|
||||
* @tparam NamedParameters a sequence of \ref pmp_namedparameters "Named Parameters"
|
||||
*
|
||||
* @param tm input triangulated surface mesh
|
||||
* @param plane plane whose negative side defines the half-space to intersect `tm` with.
|
||||
* `Plane_3` is the plane type for the same CGAL kernel as the point of the vertex point map of `tm`.
|
||||
* @param np optional sequence of \ref pmp_namedparameters "Named Parameters" among the ones listed below
|
||||
*
|
||||
* \cgalNamedParamsBegin
|
||||
* \cgalParamBegin{visitor} a class model of `PMPCorefinementVisitor`
|
||||
* that is used to track the creation of new faces.
|
||||
* \cgalParamEnd
|
||||
* \cgalParamBegin{throw_on_self_intersection} if `true`,
|
||||
* the set of triangles closed to the intersection of `tm` and `plane` will be
|
||||
* checked for self-intersections and `CGAL::Polygon_mesh_processing::Corefinement::Self_intersection_exception`
|
||||
* will be thrown if at least one is found.
|
||||
* \cgalParamEnd
|
||||
* \cgalParamBegin{clip_volume} if `true` and `tm` is closed, the clipping will be done on
|
||||
* the volume \link coref_def_subsec bounded \endlink by `tm` rather than on its surface
|
||||
* (i.e. `tm` will be kept closed).
|
||||
* \cgalParamEnd
|
||||
* \cgalParamBegin{use_compact_clipper} if `false` and `clip_volume` is `false` and `tm` is open, the parts of `tm` coplanar with `plane`
|
||||
* will not be part of the output.
|
||||
* \cgalNamedParamsEnd
|
||||
*
|
||||
* @return `true` if the output surface mesh is manifold.
|
||||
* If `false` is returned `tm` is only refined by the intersection with `plane`.
|
||||
*/
|
||||
template <class TriangleMesh,
|
||||
class NamedParameters>
|
||||
bool clip( TriangleMesh& tm,
|
||||
#ifdef DOXYGEN_RUNNING
|
||||
const Plane_3& plane,
|
||||
#else
|
||||
const typename GetGeomTraits<TriangleMesh, NamedParameters>::type::Plane_3& plane,
|
||||
#endif
|
||||
const NamedParameters& np)
|
||||
{
|
||||
if( boost::begin(faces(tm))==boost::end(faces(tm)) ) return true;
|
||||
|
||||
CGAL::Bbox_3 bbox = ::CGAL::Polygon_mesh_processing::bbox(tm);
|
||||
|
||||
//extend the bbox a bit to avoid border cases
|
||||
double xd=(bbox.xmax()-bbox.xmin())/100;
|
||||
double yd=(bbox.ymax()-bbox.ymin())/100;
|
||||
double zd=(bbox.zmax()-bbox.zmin())/100;
|
||||
bbox=CGAL::Bbox_3(bbox.xmin()-xd, bbox.ymin()-yd, bbox.zmin()-zd,
|
||||
bbox.xmax()+xd, bbox.ymax()+yd, bbox.zmax()+zd);
|
||||
TriangleMesh clipper;
|
||||
Oriented_side os = internal::clip_to_bbox(plane, bbox, clipper, parameters::all_default());
|
||||
|
||||
switch(os)
|
||||
{
|
||||
case ON_NEGATIVE_SIDE:
|
||||
return true; // nothing to clip, the full mesh is on the negative side
|
||||
case ON_POSITIVE_SIDE:
|
||||
clear(tm); // clear the mesh that is fully on the positive side
|
||||
return true;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
// dispatch is needed because face index map for tm and clipper have to be of the same time
|
||||
return internal::dispatch_clip_call(tm, clipper,
|
||||
np, CGAL::graph_has_property<TriangleMesh, CGAL::face_index_t>());
|
||||
}
|
||||
|
||||
/// \cond SKIP_IN_MANUAL
|
||||
|
||||
// convenience overloads
|
||||
template <class TriangleMesh>
|
||||
bool clip( TriangleMesh& tm,
|
||||
const typename GetGeomTraits<TriangleMesh>::type::Plane_3& plane)
|
||||
{
|
||||
return clip(tm, plane, parameters::all_default());
|
||||
}
|
||||
|
||||
// convenience overload
|
||||
template <class TriangleMesh,
|
||||
class NamedParameters1>
|
||||
bool
|
||||
clip( TriangleMesh& tm,
|
||||
TriangleMesh& clipper,
|
||||
const NamedParameters1& np_tm)
|
||||
{
|
||||
return clip(tm, clipper, np_tm, parameters::all_default());
|
||||
}
|
||||
|
||||
// convenience overload
|
||||
template <class TriangleMesh>
|
||||
bool
|
||||
clip( TriangleMesh& tm,
|
||||
TriangleMesh& clipper)
|
||||
{
|
||||
return clip(tm, clipper, parameters::all_default());
|
||||
}
|
||||
/// \endcond
|
||||
|
||||
} } //end of namespace CGAL::Polygon_mesh_processing
|
||||
|
||||
#endif // CGAL_POLYGON_MESH_PROCESSING_CLIP_H
|
||||
|
|
@ -34,6 +34,13 @@
|
|||
#include <CGAL/iterator.h>
|
||||
|
||||
namespace CGAL {
|
||||
|
||||
#if !defined(CGAL_NO_DEPRECATED_CODE) && !defined(DOXYGEN_RUNNING)
|
||||
namespace Corefinement {
|
||||
using Polygon_mesh_processing::Corefinement::Self_intersection_exception;
|
||||
}
|
||||
#endif
|
||||
|
||||
namespace Polygon_mesh_processing {
|
||||
|
||||
namespace internal {
|
||||
|
|
@ -125,14 +132,32 @@ bool recursive_does_bound_a_volume(const TriangleMesh& tm,
|
|||
|
||||
} //end of namespace internal
|
||||
|
||||
namespace Corefinement
|
||||
{
|
||||
/** \ingroup PMP_corefinement_grp
|
||||
* Default new-face visitor model of `PMPCorefinementVisitor`.
|
||||
* All of its functions have an empty body. This class can be used as a
|
||||
* base class if only some of the functions of the concept require to be
|
||||
* overridden.
|
||||
*/
|
||||
template <class TriangleMesh>
|
||||
struct Default_visitor;
|
||||
|
||||
#ifdef DOXYGEN_RUNNING
|
||||
/** \ingroup PMP_corefinement_grp
|
||||
* Integer identifiers to refer to a particular Boolean operation in the function `corefine_and_compute_boolean_operations()`.
|
||||
*/
|
||||
enum Boolean_operation_type {UNION = 0, INTERSECTION=1,
|
||||
TM1_MINUS_TM2=2, TM2_MINUS_TM1=3, NONE };
|
||||
#endif
|
||||
}
|
||||
|
||||
/** \ingroup PMP_corefinement_grp
|
||||
*
|
||||
* indicates if `tm` bounds a volume.
|
||||
* See \ref coref_def_subsec for details.
|
||||
*
|
||||
* @tparam TriangleMesh a model of `MutableFaceGraph`, `HalfedgeListGraph` and `FaceListGraph`.
|
||||
* If `TriangleMesh` has an internal property map for `CGAL::face_index_t`,
|
||||
* as a named parameter, then it must be initialized.
|
||||
* @tparam NamedParameters a sequence of \ref pmp_namedparameters "Named Parameters"
|
||||
*
|
||||
* @param tm a closed triangulated surface mesh
|
||||
|
|
@ -168,10 +193,10 @@ bool does_bound_a_volume(const TriangleMesh& tm, const NamedParameters& np)
|
|||
if (!is_closed(tm)) return false;
|
||||
if (!is_triangle_mesh(tm)) return false;
|
||||
|
||||
Vpm vpm = boost::choose_param(get_param(np, internal_np::vertex_point),
|
||||
Vpm vpm = boost::choose_param(boost::get_param(np, internal_np::vertex_point),
|
||||
get_const_property_map(boost::vertex_point, tm));
|
||||
|
||||
Fid_map fid_map = boost::choose_param(get_param(np, internal_np::face_index),
|
||||
Fid_map fid_map = boost::choose_param(boost::get_param(np, internal_np::face_index),
|
||||
get_const_property_map(boost::face_index, tm));
|
||||
|
||||
std::vector<std::size_t> face_cc(num_faces(tm), std::size_t(-1));
|
||||
|
|
@ -221,17 +246,7 @@ bool does_bound_a_volume(const TriangleMesh& tm)
|
|||
{
|
||||
return does_bound_a_volume(tm, parameters::all_default());
|
||||
}
|
||||
|
||||
#define CGAL_COREF_SET_OUTPUT_VERTEX_POINT_MAP(i) \
|
||||
if (desired_output[i]!=boost::none) \
|
||||
{ \
|
||||
vpm_out.push_back( \
|
||||
boost::choose_param(get_param(cpp11::get<i>(nps_out), internal_np::vertex_point), \
|
||||
get_property_map(boost::vertex_point, *(*desired_output[i])))); \
|
||||
output_vpms[i]=&vpm_out.back(); \
|
||||
} \
|
||||
else \
|
||||
output_vpms[i]=NULL;
|
||||
/// \endcond
|
||||
|
||||
#define CGAL_COREF_SET_OUTPUT_EDGE_MARK_MAP(I) \
|
||||
typedef typename boost::lookup_named_param_def < \
|
||||
|
|
@ -240,13 +255,92 @@ bool does_bound_a_volume(const TriangleMesh& tm)
|
|||
Corefinement::No_mark<TriangleMesh> \
|
||||
> ::type Ecm_out_##I; \
|
||||
Ecm_out_##I ecm_out_##I = \
|
||||
boost::choose_param( get_param(cpp11::get<I>(nps_out), internal_np::edge_is_constrained), \
|
||||
boost::choose_param( boost::get_param(cpp11::get<I>(nps_out), internal_np::edge_is_constrained), \
|
||||
Corefinement::No_mark<TriangleMesh>() );
|
||||
|
||||
|
||||
/**
|
||||
\todo document me
|
||||
*/
|
||||
* \ingroup PMP_corefinement_grp
|
||||
* \link coref_def_subsec corefines \endlink `tm1` and `tm2` and for each triangle mesh `tm_out` passed
|
||||
* as an optional in `output` different from `boost::none`, the triangulated surface mesh
|
||||
* \link coref_def_subsec bounding \endlink the result of a particular Boolean operation
|
||||
* between the volumes bounded by `tm1` and `tm2` will be put in the corresponding triangle mesh.
|
||||
* The positions of the meshes in the array `output` are specific to the Boolean operation to compute
|
||||
* and `Corefinement::Boolean_operation_type` encodes and describes the ordering. Constructing the default array
|
||||
* means that no Boolean operation will be done. Overwriting a default value will trigger the corresponding
|
||||
* operation. In such a case, the address to a valid surface mesh must be provided.
|
||||
* The optional named parameters for all output meshes are provided as a `tuple` and follow the same
|
||||
* order as the array `output`. A call to `corefine_and_compute_boolean_operations()` with optional
|
||||
* named parameters passed for output meshes should be done using `make_tuple()` as the types of
|
||||
* named parameters are unspecified.
|
||||
*
|
||||
* If `tm1` and/or `tm2` are part of the output surface meshes, they will be updated to
|
||||
* contain the output (in-place operation), in any other case, the corresponding result will
|
||||
* be inserted into the mesh without clearing it first.
|
||||
* \pre \link CGAL::Polygon_mesh_processing::does_self_intersect() `!CGAL::Polygon_mesh_processing::does_self_intersect(tm1)` \endlink
|
||||
* \pre \link CGAL::Polygon_mesh_processing::does_self_intersect() `!CGAL::Polygon_mesh_processing::does_self_intersect(tm2)` \endlink
|
||||
* \pre \link CGAL::Polygon_mesh_processing::does_bound_a_volume() `CGAL::Polygon_mesh_processing::does_bound_a_volume(tm1)` \endlink
|
||||
* \pre \link CGAL::Polygon_mesh_processing::does_bound_a_volume() `CGAL::Polygon_mesh_processing::does_bound_a_volume(tm2)` \endlink
|
||||
*
|
||||
* @tparam TriangleMesh a model of `MutableFaceGraph`, `HalfedgeListGraph` and `FaceListGraph`
|
||||
* @tparam NamedParameters1 a sequence of \ref pmp_namedparameters "Named Parameters"
|
||||
* @tparam NamedParameters2 a sequence of \ref pmp_namedparameters "Named Parameters"
|
||||
* @tparam NamedParametersOut0 a sequence of \ref pmp_namedparameters "Named Parameters" for computing the union of the volumes bounded by `tm1` and `tm2`
|
||||
* @tparam NamedParametersOut1 a sequence of \ref pmp_namedparameters "Named Parameters" for computing the intersection of the volumes bounded by `tm1` and `tm2`
|
||||
* @tparam NamedParametersOut2 a sequence of \ref pmp_namedparameters "Named Parameters" for computing the difference of the volumes bounded by `tm1` and `tm2`
|
||||
* @tparam NamedParametersOut3 a sequence of \ref pmp_namedparameters "Named Parameters" for computing the difference of the volumes bounded by `tm2` and `tm1`
|
||||
*
|
||||
* @param tm1 first input triangulated surface mesh
|
||||
* @param tm2 second input triangulated surface mesh
|
||||
* @param output an array of output surface meshes
|
||||
* @param np1 optional sequence of \ref pmp_namedparameters "Named Parameters" among the ones listed below
|
||||
* @param np2 optional sequence of \ref pmp_namedparameters "Named Parameters" among the ones listed below
|
||||
*
|
||||
* \cgalNamedParamsBegin
|
||||
* \cgalParamBegin{vertex_point_map}
|
||||
* the property map with the points associated to the vertices of `tm1` (`tm2`).
|
||||
* If this parameter is omitted, an internal property map for
|
||||
* `CGAL::vertex_point_t` should be available in `TriangleMesh`
|
||||
* \cgalParamEnd
|
||||
* \cgalParamBegin{edge_is_constrained_map} a property map containing the
|
||||
* constrained-or-not status of each edge of `tm1` (`tm2`).
|
||||
* \cgalParamEnd
|
||||
* \cgalParamBegin{face_index_map} a property map containing the index of each face of `tm1` (`tm2`).
|
||||
* Note that if the property map is writable, the indices of the faces
|
||||
* of `tm1` and `tm2` will be set after the corefinement is done.
|
||||
* \cgalParamEnd
|
||||
* \cgalParamBegin{visitor} a class model of `PMPCorefinementVisitor`
|
||||
* that is used to track the creation of new faces (`np1` only)
|
||||
* \cgalParamEnd
|
||||
* \cgalParamBegin{throw_on_self_intersection} if `true`, for each input triangle mesh,
|
||||
* the set of triangles close to the intersection of `tm1` and `tm2` will be
|
||||
* checked for self-intersection and `CGAL::Polygon_mesh_processing::Corefinement::Self_intersection_exception`
|
||||
* will be thrown if at least one is found (`np1` only).
|
||||
* \cgalParamEnd
|
||||
* \cgalNamedParamsEnd
|
||||
*
|
||||
* @param nps_out tuple of optional sequences of \ref pmp_namedparameters "Named Parameters" each among the ones listed below
|
||||
* (`tm_out` being used to refer to the output surface mesh in `output` corresponding to a given named parameter sequence)
|
||||
*
|
||||
* \cgalNamedParamsBegin
|
||||
* \cgalParamBegin{vertex_point_map}
|
||||
* the property map with the points associated to the vertices of `tm_out`.
|
||||
* If this parameter is omitted, an internal property map for
|
||||
* `CGAL::vertex_point_t` must be available in `TriangleMesh`
|
||||
* \cgalParamEnd
|
||||
* \cgalParamBegin{edge_is_constrained_map} a property map containing the
|
||||
* constrained-or-not status of each edge of `tm_out`. An edge of `tm_out` is constrained
|
||||
* if it is on the intersection of `tm1` and `tm2`, or if the edge corresponds to a
|
||||
* constrained edge in `tm1` or `tm2`.
|
||||
* \cgalParamEnd
|
||||
* \cgalNamedParamsEnd
|
||||
*
|
||||
* @return an array filled as follows: for each operation computed, the position in the array
|
||||
* will contain `true` iff the output surface mesh is manifold, and it is put in the surface mesh
|
||||
* at the same position as in `output`. Note that if an output surface mesh also was
|
||||
* an input mesh but the output operation was generating a non-manifold mesh, the surface mesh
|
||||
* will only be corefined.
|
||||
*/
|
||||
template <class TriangleMesh,
|
||||
class NamedParameters1,
|
||||
class NamedParameters2,
|
||||
|
|
@ -255,17 +349,19 @@ template <class TriangleMesh,
|
|||
class NamedParametersOut2,
|
||||
class NamedParametersOut3>
|
||||
cpp11::array<bool,4>
|
||||
boolean_operation( TriangleMesh& tm1,
|
||||
TriangleMesh& tm2,
|
||||
const cpp11::array< boost::optional<TriangleMesh*>,4>& desired_output,
|
||||
const NamedParameters1& np1,
|
||||
const NamedParameters2& np2,
|
||||
const cpp11::tuple<NamedParametersOut0,
|
||||
NamedParametersOut1,
|
||||
NamedParametersOut2,
|
||||
NamedParametersOut3>& nps_out,
|
||||
const bool throw_on_self_intersection = false )
|
||||
corefine_and_compute_boolean_operations(
|
||||
TriangleMesh& tm1,
|
||||
TriangleMesh& tm2,
|
||||
const cpp11::array< boost::optional<TriangleMesh*>,4>& output,
|
||||
const NamedParameters1& np1,
|
||||
const NamedParameters2& np2,
|
||||
const cpp11::tuple<NamedParametersOut0,
|
||||
NamedParametersOut1,
|
||||
NamedParametersOut2,
|
||||
NamedParametersOut3>& nps_out)
|
||||
{
|
||||
const bool throw_on_self_intersection =
|
||||
boost::choose_param(boost::get_param(np1, internal_np::throw_on_self_intersection), false);
|
||||
|
||||
// Vertex point maps
|
||||
//for input meshes
|
||||
|
|
@ -278,52 +374,74 @@ boolean_operation( TriangleMesh& tm1,
|
|||
static const bool same_vpm = (boost::is_same<Vpm,Vpm2>::value); )
|
||||
CGAL_static_assertion(same_vpm);
|
||||
|
||||
Vpm vpm1 = boost::choose_param(get_param(np1, internal_np::vertex_point),
|
||||
Vpm vpm1 = boost::choose_param(boost::get_param(np1, internal_np::vertex_point),
|
||||
get_property_map(boost::vertex_point, tm1));
|
||||
|
||||
Vpm vpm2 = boost::choose_param(get_param(np2, internal_np::vertex_point),
|
||||
Vpm vpm2 = boost::choose_param(boost::get_param(np2, internal_np::vertex_point),
|
||||
get_property_map(boost::vertex_point, tm2));
|
||||
|
||||
//for output meshes
|
||||
cpp11::array<Vpm*, 4> output_vpms;
|
||||
std::vector<Vpm> vpm_out;
|
||||
vpm_out.reserve(4);
|
||||
CGAL_COREF_SET_OUTPUT_VERTEX_POINT_MAP(0)
|
||||
CGAL_COREF_SET_OUTPUT_VERTEX_POINT_MAP(1)
|
||||
CGAL_COREF_SET_OUTPUT_VERTEX_POINT_MAP(2)
|
||||
CGAL_COREF_SET_OUTPUT_VERTEX_POINT_MAP(3)
|
||||
typedef typename boost::property_traits<Vpm>::value_type Point_3;
|
||||
|
||||
// for output meshes: here we have to use a trick so that if for a specific output
|
||||
// that is not requested, the default vpm does not have the same value type as the
|
||||
// input map, a dummy default vpm is used so that calls to get/put can be compiled
|
||||
// (even if not used).
|
||||
typedef cpp11::tuple<
|
||||
Corefinement::TweakedGetVertexPointMap<Point_3, NamedParametersOut0, TriangleMesh>,
|
||||
Corefinement::TweakedGetVertexPointMap<Point_3, NamedParametersOut1, TriangleMesh>,
|
||||
Corefinement::TweakedGetVertexPointMap<Point_3, NamedParametersOut2, TriangleMesh>,
|
||||
Corefinement::TweakedGetVertexPointMap<Point_3, NamedParametersOut3, TriangleMesh>
|
||||
> Vpm_out_tuple_helper;
|
||||
|
||||
typedef cpp11::tuple<
|
||||
boost::optional< typename cpp11::tuple_element<0, Vpm_out_tuple_helper>::type::type >,
|
||||
boost::optional< typename cpp11::tuple_element<1, Vpm_out_tuple_helper>::type::type >,
|
||||
boost::optional< typename cpp11::tuple_element<2, Vpm_out_tuple_helper>::type::type >,
|
||||
boost::optional< typename cpp11::tuple_element<3, Vpm_out_tuple_helper>::type::type >
|
||||
> Vpm_out_tuple;
|
||||
|
||||
Vpm_out_tuple vpm_out_tuple(
|
||||
Corefinement::get_vpm<Point_3>(cpp11::get<0>(nps_out), output[0],
|
||||
typename cpp11::tuple_element<0, Vpm_out_tuple_helper>::type::Use_default_tag()),
|
||||
Corefinement::get_vpm<Point_3>(cpp11::get<1>(nps_out), output[1],
|
||||
typename cpp11::tuple_element<1, Vpm_out_tuple_helper>::type::Use_default_tag()),
|
||||
Corefinement::get_vpm<Point_3>(cpp11::get<2>(nps_out), output[2],
|
||||
typename cpp11::tuple_element<2, Vpm_out_tuple_helper>::type::Use_default_tag()),
|
||||
Corefinement::get_vpm<Point_3>(cpp11::get<3>(nps_out), output[3],
|
||||
typename cpp11::tuple_element<3, Vpm_out_tuple_helper>::type::Use_default_tag())
|
||||
);
|
||||
|
||||
if (&tm1==&tm2)
|
||||
{
|
||||
// for now edges in a coplanar patch are not constrained so there is nothing to constrained here
|
||||
// \todo marked edges from input to output are not ported
|
||||
|
||||
if (desired_output[Corefinement::UNION] != boost::none)
|
||||
if (&tm1 != *desired_output[Corefinement::UNION])
|
||||
if (output[Corefinement::UNION] != boost::none)
|
||||
if (&tm1 != *output[Corefinement::UNION])
|
||||
copy_face_graph(tm1,
|
||||
*(*desired_output[Corefinement::UNION]),
|
||||
*(*output[Corefinement::UNION]),
|
||||
Emptyset_iterator(),
|
||||
Emptyset_iterator(),
|
||||
Emptyset_iterator(),
|
||||
vpm1,
|
||||
vpm_out[Corefinement::UNION]);
|
||||
*cpp11::get<Corefinement::UNION>(vpm_out_tuple));
|
||||
|
||||
if (desired_output[Corefinement::INTER] != boost::none)
|
||||
if (&tm1 != *desired_output[Corefinement::INTER])
|
||||
if (output[Corefinement::INTERSECTION] != boost::none)
|
||||
if (&tm1 != *output[Corefinement::INTERSECTION])
|
||||
copy_face_graph(tm1,
|
||||
*(*desired_output[Corefinement::INTER]),
|
||||
*(*output[Corefinement::INTERSECTION]),
|
||||
Emptyset_iterator(),
|
||||
Emptyset_iterator(),
|
||||
Emptyset_iterator(),
|
||||
vpm1,
|
||||
vpm_out[Corefinement::INTER]);
|
||||
*cpp11::get<Corefinement::INTERSECTION>(vpm_out_tuple));
|
||||
|
||||
if (desired_output[Corefinement::TM1_MINUS_TM2] != boost::none)
|
||||
if (&tm1 == *desired_output[Corefinement::TM1_MINUS_TM2])
|
||||
if (output[Corefinement::TM1_MINUS_TM2] != boost::none)
|
||||
if (&tm1 == *output[Corefinement::TM1_MINUS_TM2])
|
||||
clear(tm1);
|
||||
|
||||
if (desired_output[Corefinement::TM2_MINUS_TM1] != boost::none)
|
||||
if (&tm1 == *desired_output[Corefinement::TM2_MINUS_TM1])
|
||||
if (output[Corefinement::TM2_MINUS_TM1] != boost::none)
|
||||
if (&tm1 == *output[Corefinement::TM2_MINUS_TM1])
|
||||
clear(tm1);
|
||||
|
||||
return CGAL::make_array(true, true, true, true);
|
||||
|
|
@ -370,30 +488,38 @@ boolean_operation( TriangleMesh& tm1,
|
|||
static const bool same_fidmap = (boost::is_same<Fid_map,Fid_map2>::value);)
|
||||
CGAL_static_assertion(same_fidmap);
|
||||
|
||||
Fid_map fid_map1 = boost::choose_param(get_param(np1, internal_np::face_index),
|
||||
Fid_map fid_map1 = boost::choose_param(boost::get_param(np1, internal_np::face_index),
|
||||
get_property_map(boost::face_index, tm1));
|
||||
Fid_map fid_map2 = boost::choose_param(get_param(np2, internal_np::face_index),
|
||||
Fid_map fid_map2 = boost::choose_param(boost::get_param(np2, internal_np::face_index),
|
||||
get_property_map(boost::face_index, tm2));
|
||||
// User visitor
|
||||
typedef typename boost::lookup_named_param_def <
|
||||
internal_np::graph_visitor_t,
|
||||
NamedParameters1,
|
||||
Corefinement::Default_visitor<TriangleMesh>//default
|
||||
> ::type User_visitor;
|
||||
User_visitor uv( boost::choose_param( boost::get_param(np1, internal_np::graph_visitor),
|
||||
Corefinement::Default_visitor<TriangleMesh>() ) );
|
||||
|
||||
// surface intersection algorithm call
|
||||
typedef Corefinement::Default_node_visitor<TriangleMesh> Dnv;
|
||||
typedef Corefinement::Default_face_visitor<TriangleMesh> Dfv;
|
||||
typedef Corefinement::Face_graph_output_builder<TriangleMesh,
|
||||
Vpm,
|
||||
Vpm_out_tuple,
|
||||
Fid_map,
|
||||
Default,
|
||||
Ecm_in,
|
||||
Edge_mark_map_tuple > Ob;
|
||||
Edge_mark_map_tuple,
|
||||
User_visitor> Ob;
|
||||
|
||||
typedef Corefinement::Visitor<TriangleMesh,Vpm,Ob,Ecm_in> Visitor;
|
||||
Dnv dnv;
|
||||
Dfv dfv;
|
||||
typedef Corefinement::Surface_intersection_visitor_for_corefinement<
|
||||
TriangleMesh, Vpm, Ob, Ecm_in, User_visitor> Algo_visitor;
|
||||
Ecm_in ecm_in(tm1,tm2,ecm1,ecm2);
|
||||
Edge_mark_map_tuple ecms_out(ecm_out_0, ecm_out_1, ecm_out_2, ecm_out_3);
|
||||
Ob ob(tm1, tm2, vpm1, vpm2, fid_map1, fid_map2, ecm_in,
|
||||
output_vpms, ecms_out, desired_output);
|
||||
vpm_out_tuple, ecms_out, uv, output);
|
||||
|
||||
Corefinement::Intersection_of_triangle_meshes<TriangleMesh,Vpm,Visitor >
|
||||
functor(tm1, tm2, vpm1, vpm2, Visitor(dnv,dfv,ob,ecm_in));
|
||||
Corefinement::Intersection_of_triangle_meshes<TriangleMesh, Vpm, Algo_visitor >
|
||||
functor(tm1, tm2, vpm1, vpm2, Algo_visitor(uv,ob,ecm_in));
|
||||
functor(CGAL::Emptyset_iterator(), throw_on_self_intersection, true);
|
||||
|
||||
|
||||
|
|
@ -405,22 +531,52 @@ boolean_operation( TriangleMesh& tm1,
|
|||
|
||||
template <class TriangleMesh>
|
||||
cpp11::array<bool,4>
|
||||
boolean_operation( TriangleMesh& tm1,
|
||||
TriangleMesh& tm2,
|
||||
const cpp11::array< boost::optional<TriangleMesh*>,4>& desired_output,
|
||||
const bool throw_on_self_intersection = false )
|
||||
corefine_and_compute_boolean_operations(
|
||||
TriangleMesh& tm1,
|
||||
TriangleMesh& tm2,
|
||||
const cpp11::array< boost::optional<TriangleMesh*>,4>& output)
|
||||
{
|
||||
using namespace CGAL::Polygon_mesh_processing::parameters;
|
||||
return boolean_operation(tm1, tm2, desired_output,
|
||||
all_default(), all_default(),
|
||||
cpp11::make_tuple(all_default(), all_default(),
|
||||
all_default(), all_default()),
|
||||
throw_on_self_intersection);
|
||||
return corefine_and_compute_boolean_operations(tm1, tm2, output,
|
||||
all_default(), all_default(),
|
||||
cpp11::make_tuple(all_default(), all_default(),
|
||||
all_default(), all_default()));
|
||||
}
|
||||
|
||||
template <class TriangleMesh, class NamedParameters1>
|
||||
cpp11::array<bool,4>
|
||||
corefine_and_compute_boolean_operations(
|
||||
TriangleMesh& tm1,
|
||||
TriangleMesh& tm2,
|
||||
const cpp11::array< boost::optional<TriangleMesh*>,4>& output,
|
||||
const NamedParameters1& np1)
|
||||
{
|
||||
using namespace CGAL::Polygon_mesh_processing::parameters;
|
||||
return corefine_and_compute_boolean_operations(tm1, tm2, output,
|
||||
np1, all_default(),
|
||||
cpp11::make_tuple(all_default(), all_default(),
|
||||
all_default(), all_default()));
|
||||
}
|
||||
|
||||
template <class TriangleMesh, class NamedParameters1, class NamedParameters2>
|
||||
cpp11::array<bool,4>
|
||||
corefine_and_compute_boolean_operations(
|
||||
TriangleMesh& tm1,
|
||||
TriangleMesh& tm2,
|
||||
const cpp11::array< boost::optional<TriangleMesh*>,4>& output,
|
||||
const NamedParameters1& np1,
|
||||
const NamedParameters2& np2)
|
||||
{
|
||||
using namespace CGAL::Polygon_mesh_processing::parameters;
|
||||
return corefine_and_compute_boolean_operations(tm1, tm2, output,
|
||||
np1, np2,
|
||||
cpp11::make_tuple(all_default(), all_default(),
|
||||
all_default(), all_default()));
|
||||
}
|
||||
|
||||
#undef CGAL_COREF_SET_OUTPUT_VERTEX_POINT_MAP
|
||||
#undef CGAL_COREF_SET_OUTPUT_EDGE_MARK_MAP
|
||||
/// \endcond
|
||||
|
||||
|
||||
/**
|
||||
* \ingroup PMP_corefinement_grp
|
||||
|
|
@ -435,10 +591,7 @@ boolean_operation( TriangleMesh& tm1,
|
|||
* \pre \link CGAL::Polygon_mesh_processing::does_bound_a_volume() `CGAL::Polygon_mesh_processing::does_bound_a_volume(tm1)` \endlink
|
||||
* \pre \link CGAL::Polygon_mesh_processing::does_bound_a_volume() `CGAL::Polygon_mesh_processing::does_bound_a_volume(tm2)` \endlink
|
||||
*
|
||||
* @tparam TriangleMesh a model of `MutableFaceGraph`, `HalfedgeListGraph` and `FaceListGraph`.
|
||||
* If `TriangleMesh` has an internal property map for `CGAL::face_index_t`,
|
||||
* as a named parameter, then it must be initialized.
|
||||
*
|
||||
* @tparam TriangleMesh a model of `MutableFaceGraph`, `HalfedgeListGraph` and `FaceListGraph`
|
||||
* @tparam NamedParameters1 a sequence of \ref pmp_namedparameters "Named Parameters"
|
||||
* @tparam NamedParameters2 a sequence of \ref pmp_namedparameters "Named Parameters"
|
||||
* @tparam NamedParametersOut a sequence of \ref pmp_namedparameters "Named Parameters"
|
||||
|
|
@ -462,6 +615,14 @@ boolean_operation( TriangleMesh& tm1,
|
|||
* Note that if the property map is writable, the indices of the faces
|
||||
* of `tm1` and `tm2` will be set after the corefinement is done.
|
||||
* \cgalParamEnd
|
||||
* \cgalParamBegin{visitor} a class model of `PMPCorefinementVisitor`
|
||||
* that is used to track the creation of new faces (`np1` only)
|
||||
* \cgalParamEnd
|
||||
* \cgalParamBegin{throw_on_self_intersection} if `true`, for each input triangle mesh,
|
||||
* the set of triangles close to the intersection of `tm1` and `tm2` will be
|
||||
* checked for self-intersection and `CGAL::Polygon_mesh_processing::Corefinement::Self_intersection_exception`
|
||||
* will be thrown if at least one is found (`np1` only).
|
||||
* \cgalParamEnd
|
||||
* \cgalNamedParamsEnd
|
||||
*
|
||||
* @param np_out optional sequence of \ref pmp_namedparameters "Named Parameters" among the ones listed below
|
||||
|
|
@ -495,16 +656,16 @@ corefine_and_compute_union( TriangleMesh& tm1,
|
|||
const NamedParametersOut& np_out)
|
||||
{
|
||||
using namespace CGAL::Polygon_mesh_processing::parameters;
|
||||
cpp11::array< boost::optional<TriangleMesh*>,4> desired_output;
|
||||
desired_output[Corefinement::UNION]=&tm_out;
|
||||
cpp11::array< boost::optional<TriangleMesh*>,4> output;
|
||||
output[Corefinement::UNION]=&tm_out;
|
||||
|
||||
return
|
||||
boolean_operation(tm1, tm2, desired_output, np1, np2,
|
||||
cpp11::make_tuple(np_out,
|
||||
no_parameters(np_out),
|
||||
no_parameters(np_out),
|
||||
no_parameters(np_out)))
|
||||
[Corefinement::UNION];
|
||||
corefine_and_compute_boolean_operations(tm1, tm2, output, np1, np2,
|
||||
cpp11::make_tuple(np_out,
|
||||
all_default(),
|
||||
all_default(),
|
||||
all_default()))
|
||||
[Corefinement::UNION];
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -527,16 +688,16 @@ corefine_and_compute_intersection( TriangleMesh& tm1,
|
|||
const NamedParametersOut& np_out)
|
||||
{
|
||||
using namespace CGAL::Polygon_mesh_processing::parameters;
|
||||
cpp11::array< boost::optional<TriangleMesh*>,4> desired_output;
|
||||
desired_output[Corefinement::INTER]=&tm_out;
|
||||
cpp11::array< boost::optional<TriangleMesh*>,4> output;
|
||||
output[Corefinement::INTERSECTION]=&tm_out;
|
||||
|
||||
return
|
||||
boolean_operation(tm1, tm2, desired_output, np1, np2,
|
||||
cpp11::make_tuple(no_parameters(np_out),
|
||||
np_out,
|
||||
no_parameters(np_out),
|
||||
no_parameters(np_out)))
|
||||
[Corefinement::INTER];
|
||||
corefine_and_compute_boolean_operations(tm1, tm2, output, np1, np2,
|
||||
cpp11::make_tuple(all_default(),
|
||||
np_out,
|
||||
all_default(),
|
||||
all_default()))
|
||||
[Corefinement::INTERSECTION];
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -559,16 +720,17 @@ corefine_and_compute_difference( TriangleMesh& tm1,
|
|||
const NamedParametersOut& np_out)
|
||||
{
|
||||
using namespace CGAL::Polygon_mesh_processing::parameters;
|
||||
using namespace CGAL::Corefinement;
|
||||
cpp11::array< boost::optional<TriangleMesh*>,4> desired_output;
|
||||
desired_output[TM1_MINUS_TM2]=&tm_out;
|
||||
using namespace CGAL::Polygon_mesh_processing::Corefinement;
|
||||
cpp11::array< boost::optional<TriangleMesh*>,4> output;
|
||||
output[TM1_MINUS_TM2]=&tm_out;
|
||||
|
||||
return
|
||||
boolean_operation(tm1, tm2, desired_output, np1, np2,
|
||||
cpp11::make_tuple(no_parameters(np_out),
|
||||
no_parameters(np_out),
|
||||
np_out,
|
||||
no_parameters(np_out)))[TM1_MINUS_TM2];
|
||||
corefine_and_compute_boolean_operations(tm1, tm2, output, np1, np2,
|
||||
cpp11::make_tuple(all_default(),
|
||||
all_default(),
|
||||
np_out,
|
||||
all_default()))
|
||||
[TM1_MINUS_TM2];
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -589,10 +751,7 @@ corefine_and_compute_difference( TriangleMesh& tm1,
|
|||
* @param tm2 second input triangulated surface mesh
|
||||
* @param np1 optional sequence of \ref pmp_namedparameters "Named Parameters" among the ones listed below
|
||||
* @param np2 optional sequence of \ref pmp_namedparameters "Named Parameters" among the ones listed below
|
||||
* @param throw_on_self_intersection if `true`, for each input triangle mesh,
|
||||
* the set of triangles closed to the intersection of `tm1` and `tm2` will be
|
||||
* checked for self-intersection and `CGAL::Corefinement::Self_intersection_exception`
|
||||
* will be thrown if at least one is found.
|
||||
*
|
||||
* \cgalNamedParamsBegin
|
||||
* \cgalParamBegin{vertex_point_map}
|
||||
* the property map with the points associated to the vertices of `tm1` (`tm2`).
|
||||
|
|
@ -602,6 +761,14 @@ corefine_and_compute_difference( TriangleMesh& tm1,
|
|||
* \cgalParamBegin{edge_is_constrained_map} a property map containing the
|
||||
* constrained-or-not status of each edge of `tm1` (`tm2`)
|
||||
* \cgalParamEnd
|
||||
* \cgalParamBegin{visitor} a class model of `PMPCorefinementVisitor`
|
||||
* that is used to track the creation of new faces (`np1` only)
|
||||
* \cgalParamEnd
|
||||
* \cgalParamBegin{throw_on_self_intersection} if `true`, for each input triangle mesh,
|
||||
* the set of triangles close to the intersection of `tm1` and `tm2` will be
|
||||
* checked for self-intersection and `CGAL::Polygon_mesh_processing::Corefinement::Self_intersection_exception`
|
||||
* will be thrown if at least one is found (`np1` only).
|
||||
* \cgalParamEnd
|
||||
* \cgalNamedParamsEnd
|
||||
*
|
||||
*/
|
||||
|
|
@ -612,9 +779,11 @@ corefine_and_compute_difference( TriangleMesh& tm1,
|
|||
corefine( TriangleMesh& tm1,
|
||||
TriangleMesh& tm2,
|
||||
const NamedParameters1& np1,
|
||||
const NamedParameters2& np2,
|
||||
const bool throw_on_self_intersection = false)
|
||||
const NamedParameters2& np2)
|
||||
{
|
||||
const bool throw_on_self_intersection =
|
||||
boost::choose_param(boost::get_param(np1, internal_np::throw_on_self_intersection), false);
|
||||
|
||||
// Vertex point maps
|
||||
typedef typename GetVertexPointMap<TriangleMesh,
|
||||
NamedParameters1>::type Vpm;
|
||||
|
|
@ -625,10 +794,10 @@ corefine_and_compute_difference( TriangleMesh& tm1,
|
|||
static const bool same_vpm = (boost::is_same<Vpm,Vpm2>::value);)
|
||||
CGAL_static_assertion(same_vpm);
|
||||
|
||||
Vpm vpm1 = boost::choose_param(get_param(np1, internal_np::vertex_point),
|
||||
Vpm vpm1 = boost::choose_param(boost::get_param(np1, internal_np::vertex_point),
|
||||
get_property_map(boost::vertex_point, tm1));
|
||||
|
||||
Vpm vpm2 = boost::choose_param(get_param(np2, internal_np::vertex_point),
|
||||
Vpm vpm2 = boost::choose_param(boost::get_param(np2, internal_np::vertex_point),
|
||||
get_property_map(boost::vertex_point, tm2));
|
||||
|
||||
// Edge is-constrained maps
|
||||
|
|
@ -644,9 +813,9 @@ corefine_and_compute_difference( TriangleMesh& tm1,
|
|||
Corefinement::No_mark<TriangleMesh>//default
|
||||
> ::type Ecm2;
|
||||
|
||||
Ecm1 ecm1 = boost::choose_param( get_param(np1, internal_np::edge_is_constrained),
|
||||
Ecm1 ecm1 = boost::choose_param( boost::get_param(np1, internal_np::edge_is_constrained),
|
||||
Corefinement::No_mark<TriangleMesh>() );
|
||||
Ecm2 ecm2 = boost::choose_param( get_param(np2, internal_np::edge_is_constrained),
|
||||
Ecm2 ecm2 = boost::choose_param( boost::get_param(np2, internal_np::edge_is_constrained),
|
||||
Corefinement::No_mark<TriangleMesh>() );
|
||||
|
||||
typedef Corefinement::Ecm_bind<TriangleMesh, Ecm1, Ecm2> Ecm;
|
||||
|
|
@ -658,17 +827,23 @@ corefine_and_compute_difference( TriangleMesh& tm1,
|
|||
return;
|
||||
}
|
||||
|
||||
// User visitor
|
||||
typedef typename boost::lookup_named_param_def <
|
||||
internal_np::graph_visitor_t,
|
||||
NamedParameters1,
|
||||
Corefinement::Default_visitor<TriangleMesh>//default
|
||||
> ::type User_visitor;
|
||||
User_visitor uv( boost::choose_param( boost::get_param(np1, internal_np::graph_visitor),
|
||||
Corefinement::Default_visitor<TriangleMesh>() ) );
|
||||
|
||||
// surface intersection algorithm call
|
||||
typedef Corefinement::Default_node_visitor<TriangleMesh> Dnv;
|
||||
typedef Corefinement::Default_face_visitor<TriangleMesh> Dfv;
|
||||
typedef Corefinement::No_extra_output_from_corefinement<TriangleMesh> Ob;
|
||||
typedef Corefinement::Visitor<TriangleMesh,Vpm,Ob,Ecm> Visitor;
|
||||
Dnv dnv;
|
||||
Dfv dfv;
|
||||
typedef Corefinement::Surface_intersection_visitor_for_corefinement<
|
||||
TriangleMesh, Vpm, Ob, Ecm, User_visitor> Algo_visitor;
|
||||
Ob ob;
|
||||
Ecm ecm(tm1,tm2,ecm1,ecm2);
|
||||
Corefinement::Intersection_of_triangle_meshes<TriangleMesh,Vpm,Visitor >
|
||||
functor(tm1, tm2, vpm1, vpm2, Visitor(dnv,dfv,ob,ecm));
|
||||
Corefinement::Intersection_of_triangle_meshes<TriangleMesh, Vpm, Algo_visitor>
|
||||
functor(tm1, tm2, vpm1, vpm2, Algo_visitor(uv,ob,ecm));
|
||||
functor(CGAL::Emptyset_iterator(), throw_on_self_intersection, true);
|
||||
}
|
||||
|
||||
|
|
@ -695,6 +870,9 @@ namespace experimental {
|
|||
* \cgalParamBegin{edge_is_constrained_map} a property map containing the
|
||||
* constrained-or-not status of each edge of `tm`
|
||||
* \cgalParamEnd
|
||||
* \cgalParamBegin{visitor} a class model of `PMPCorefinementVisitor`
|
||||
* that is used to track the creation of new faces
|
||||
* \cgalParamEnd
|
||||
* \cgalNamedParamsEnd
|
||||
*
|
||||
*/
|
||||
|
|
@ -708,7 +886,7 @@ namespace experimental {
|
|||
typedef typename GetVertexPointMap<TriangleMesh,
|
||||
NamedParameters>::type Vpm;
|
||||
|
||||
Vpm vpm = boost::choose_param(get_param(np, internal_np::vertex_point),
|
||||
Vpm vpm = boost::choose_param(boost::get_param(np, internal_np::vertex_point),
|
||||
get_property_map(boost::vertex_point, tm));
|
||||
|
||||
// Edge is-constrained maps
|
||||
|
|
@ -719,21 +897,27 @@ namespace experimental {
|
|||
> ::type Ecm;
|
||||
|
||||
|
||||
Ecm ecm = boost::choose_param( get_param(np, internal_np::edge_is_constrained),
|
||||
Ecm ecm = boost::choose_param( boost::get_param(np, internal_np::edge_is_constrained),
|
||||
Corefinement::No_mark<TriangleMesh>() );
|
||||
|
||||
// User visitor
|
||||
typedef typename boost::lookup_named_param_def <
|
||||
internal_np::graph_visitor_t,
|
||||
NamedParameters,
|
||||
Corefinement::Default_visitor<TriangleMesh>//default
|
||||
> ::type User_visitor;
|
||||
User_visitor uv( boost::choose_param( boost::get_param(np, internal_np::graph_visitor),
|
||||
Corefinement::Default_visitor<TriangleMesh>() ) );
|
||||
|
||||
|
||||
// surface intersection algorithm call
|
||||
typedef Corefinement::Default_node_visitor<TriangleMesh> Dnv;
|
||||
typedef Corefinement::Default_face_visitor<TriangleMesh> Dfv;
|
||||
typedef Corefinement::No_extra_output_from_corefinement<TriangleMesh> Ob;
|
||||
typedef Default D;
|
||||
typedef Corefinement::Visitor<TriangleMesh,Vpm,Ob,Ecm,D,D,true> Visitor;
|
||||
Dnv dnv;
|
||||
Dfv dfv;
|
||||
typedef Corefinement::Surface_intersection_visitor_for_corefinement<
|
||||
TriangleMesh, Vpm, Ob, Ecm, User_visitor,true> Algo_visitor;
|
||||
Ob ob;
|
||||
|
||||
Corefinement::Intersection_of_triangle_meshes<TriangleMesh,Vpm,Visitor >
|
||||
functor(tm, vpm, Visitor(dnv,dfv,ob,ecm) );
|
||||
Corefinement::Intersection_of_triangle_meshes<TriangleMesh, Vpm, Algo_visitor>
|
||||
functor(tm, vpm, Algo_visitor(uv,ob,ecm) );
|
||||
|
||||
functor(CGAL::Emptyset_iterator(), true);
|
||||
}
|
||||
|
|
@ -761,7 +945,10 @@ namespace experimental {
|
|||
* \cgalParamBegin{edge_is_constrained_map} a property map containing the
|
||||
* constrained-or-not status of each edge of `tm`
|
||||
* \cgalParamEnd
|
||||
* \cgalParamBegin{face_index_map} a property map containing the index of each face of `tm` \cgalParamEnd
|
||||
* \cgalParamBegin{face_index_map} a property map containing the index of each face of `tm` \cgalParamEnd
|
||||
* \cgalParamBegin{visitor} a class model of `PMPCorefinementVisitor`
|
||||
* that is used to track the creation of new faces
|
||||
* \cgalParamEnd
|
||||
* \cgalNamedParamsEnd
|
||||
*
|
||||
*/
|
||||
|
|
@ -774,12 +961,12 @@ namespace experimental {
|
|||
// Vertex point maps
|
||||
typedef typename GetVertexPointMap<TriangleMesh,
|
||||
NamedParameters>::type Vpm;
|
||||
Vpm vpm = boost::choose_param(get_param(np, internal_np::vertex_point),
|
||||
Vpm vpm = boost::choose_param(boost::get_param(np, internal_np::vertex_point),
|
||||
get_property_map(boost::vertex_point, tm));
|
||||
// Face index map
|
||||
typedef typename GetFaceIndexMap<TriangleMesh,
|
||||
NamedParameters>::type Fid_map;
|
||||
Fid_map fid_map = boost::choose_param(get_param(np, internal_np::face_index),
|
||||
Fid_map fid_map = boost::choose_param(boost::get_param(np, internal_np::face_index),
|
||||
get_property_map(boost::face_index, tm));
|
||||
// Edge is-constrained maps
|
||||
typedef typename boost::lookup_named_param_def <
|
||||
|
|
@ -787,26 +974,30 @@ namespace experimental {
|
|||
NamedParameters,
|
||||
Corefinement::No_mark<TriangleMesh>//default
|
||||
> ::type Ecm;
|
||||
Ecm ecm = boost::choose_param( get_param(np, internal_np::edge_is_constrained),
|
||||
Ecm ecm = boost::choose_param( boost::get_param(np, internal_np::edge_is_constrained),
|
||||
Corefinement::No_mark<TriangleMesh>() );
|
||||
// User visitor
|
||||
typedef typename boost::lookup_named_param_def <
|
||||
internal_np::graph_visitor_t,
|
||||
NamedParameters,
|
||||
Corefinement::Default_visitor<TriangleMesh>//default
|
||||
> ::type User_visitor;
|
||||
User_visitor uv( boost::choose_param( boost::get_param(np, internal_np::graph_visitor),
|
||||
Corefinement::Default_visitor<TriangleMesh>() ) );
|
||||
|
||||
// surface intersection algorithm call
|
||||
typedef Corefinement::Default_node_visitor<TriangleMesh> Dnv;
|
||||
typedef Corefinement::Default_face_visitor<TriangleMesh> Dfv;
|
||||
typedef Corefinement::Output_builder_for_autorefinement<TriangleMesh,
|
||||
Vpm,
|
||||
Fid_map,
|
||||
Ecm,
|
||||
Default > Ob;
|
||||
|
||||
typedef Default D;
|
||||
typedef Corefinement::Visitor<TriangleMesh,Vpm,Ob,Ecm,D,D,true> Visitor;
|
||||
Dnv dnv;
|
||||
Dfv dfv;
|
||||
typedef Corefinement::Surface_intersection_visitor_for_corefinement<
|
||||
TriangleMesh, Vpm, Ob, Ecm, User_visitor,true> Algo_visitor;
|
||||
Ob ob(tm, vpm, fid_map, ecm);
|
||||
|
||||
Corefinement::Intersection_of_triangle_meshes<TriangleMesh,Vpm,Visitor >
|
||||
functor(tm, vpm, Visitor(dnv,dfv,ob,ecm) );
|
||||
Corefinement::Intersection_of_triangle_meshes<TriangleMesh, Vpm, Algo_visitor>
|
||||
functor(tm, vpm, Algo_visitor(uv,ob,ecm) );
|
||||
|
||||
functor(CGAL::Emptyset_iterator(), true);
|
||||
|
||||
|
|
@ -941,22 +1132,60 @@ template <class TriangleMesh, class NamedParameters1>
|
|||
void
|
||||
corefine( TriangleMesh& tm1,
|
||||
TriangleMesh& tm2,
|
||||
const NamedParameters1& np1,
|
||||
const bool throw_on_self_intersection = false)
|
||||
const NamedParameters1& np1)
|
||||
{
|
||||
using namespace CGAL::Polygon_mesh_processing::parameters;
|
||||
corefine(tm1, tm2, np1, all_default(), throw_on_self_intersection);
|
||||
corefine(tm1, tm2, np1, all_default());
|
||||
}
|
||||
|
||||
template <class TriangleMesh>
|
||||
void
|
||||
corefine( TriangleMesh& tm1,
|
||||
TriangleMesh& tm2)
|
||||
{
|
||||
using namespace CGAL::Polygon_mesh_processing::parameters;
|
||||
corefine(tm1, tm2, all_default(), all_default());
|
||||
}
|
||||
|
||||
#ifndef CGAL_NO_DEPRECATED_CODE
|
||||
template <class TriangleMesh,
|
||||
class NamedParameters1,
|
||||
class NamedParameters2>
|
||||
void
|
||||
corefine( TriangleMesh& tm1,
|
||||
TriangleMesh& tm2,
|
||||
const NamedParameters1& np1,
|
||||
const NamedParameters2& np2,
|
||||
const bool throw_on_self_intersection)
|
||||
{
|
||||
corefine(tm1, tm2, np1.throw_on_self_intersection(throw_on_self_intersection), np2);
|
||||
}
|
||||
|
||||
template <class TriangleMesh, class NamedParameters1>
|
||||
void
|
||||
corefine( TriangleMesh& tm1,
|
||||
TriangleMesh& tm2,
|
||||
const NamedParameters1& np1,
|
||||
const bool throw_on_self_intersection)
|
||||
{
|
||||
namespace params = CGAL::Polygon_mesh_processing::parameters;
|
||||
corefine(tm1, tm2,
|
||||
np1.throw_on_self_intersection(throw_on_self_intersection),
|
||||
params::all_default());
|
||||
}
|
||||
|
||||
template <class TriangleMesh>
|
||||
void
|
||||
corefine( TriangleMesh& tm1,
|
||||
TriangleMesh& tm2,
|
||||
const bool throw_on_self_intersection = false)
|
||||
const bool throw_on_self_intersection)
|
||||
{
|
||||
using namespace CGAL::Polygon_mesh_processing::parameters;
|
||||
corefine(tm1, tm2, all_default(), all_default(), throw_on_self_intersection);
|
||||
namespace params = CGAL::Polygon_mesh_processing::parameters;
|
||||
corefine(tm1, tm2,
|
||||
params::throw_on_self_intersection(throw_on_self_intersection),
|
||||
params::all_default());
|
||||
}
|
||||
#endif
|
||||
|
||||
///// autorefine /////
|
||||
namespace experimental {
|
||||
|
|
|
|||
|
|
@ -36,29 +36,44 @@
|
|||
|
||||
#include <boost/dynamic_bitset.hpp>
|
||||
|
||||
|
||||
#define CGAL_COREF_SELECT_OUT_ECM(I) \
|
||||
(I == 0 ? cpp11::get<0>(out_edge_mark_maps) \
|
||||
: I == 1 ? cpp11::get<1>(out_edge_mark_maps) \
|
||||
: I == 2 ? cpp11::get<2>(out_edge_mark_maps) \
|
||||
: cpp11::get<3>(out_edge_mark_maps))
|
||||
// required to handle the multiple types of edge constrained maps
|
||||
// for the different output types. CGAL_COREF_FUNCTION_CALL_DEF
|
||||
// must be defined prior to using this macro.
|
||||
#define CGAL_COREF_FUNCTION_CALL(BO_type) \
|
||||
switch(BO_type) \
|
||||
{ \
|
||||
case UNION: \
|
||||
CGAL_COREF_FUNCTION_CALL_DEF(UNION); \
|
||||
break; \
|
||||
case INTERSECTION: \
|
||||
CGAL_COREF_FUNCTION_CALL_DEF(INTERSECTION); \
|
||||
break; \
|
||||
case TM1_MINUS_TM2: \
|
||||
CGAL_COREF_FUNCTION_CALL_DEF(TM1_MINUS_TM2); \
|
||||
break; \
|
||||
default: \
|
||||
CGAL_assertion( BO_type == TM2_MINUS_TM1 ); \
|
||||
CGAL_COREF_FUNCTION_CALL_DEF(TM2_MINUS_TM1); \
|
||||
}
|
||||
|
||||
namespace CGAL {
|
||||
namespace Polygon_mesh_processing {
|
||||
namespace Corefinement {
|
||||
|
||||
enum Boolean_operation {UNION = 0, INTER,
|
||||
TM1_MINUS_TM2, TM2_MINUS_TM1,
|
||||
NONE };
|
||||
enum Boolean_operation_type {UNION = 0, INTERSECTION,
|
||||
TM1_MINUS_TM2, TM2_MINUS_TM1, NONE };
|
||||
|
||||
namespace PMP=Polygon_mesh_processing;
|
||||
namespace params=PMP::parameters;
|
||||
|
||||
template <class TriangleMesh,
|
||||
class VertexPointMap,
|
||||
class VpmOutTuple,
|
||||
class FaceIdMap,
|
||||
class Kernel_=Default,
|
||||
class EdgeMarkMapBind_=Default,
|
||||
class EdgeMarkMapTuple_=Default >
|
||||
class EdgeMarkMapBind_ = Default,
|
||||
class EdgeMarkMapTuple_ = Default,
|
||||
class UserVisitor_ = Default>
|
||||
class Face_graph_output_builder
|
||||
{
|
||||
//Default typedefs
|
||||
|
|
@ -75,6 +90,8 @@ class Face_graph_output_builder
|
|||
No_mark<TriangleMesh>,
|
||||
No_mark<TriangleMesh>,
|
||||
No_mark<TriangleMesh> > >::type EdgeMarkMapTuple;
|
||||
typedef typename Default::Get<
|
||||
UserVisitor_, Default_visitor<TriangleMesh> >::type UserVisitor;
|
||||
|
||||
// graph_traits typedefs
|
||||
typedef TriangleMesh TM;
|
||||
|
|
@ -107,10 +124,11 @@ class Face_graph_output_builder
|
|||
const FaceIdMap &fids1, &fids2;
|
||||
EdgeMarkMapBind& marks_on_input_edges;
|
||||
// property maps of output meshes
|
||||
const cpp11::array<VertexPointMap*, 4 >& output_vpms;
|
||||
const VpmOutTuple& output_vpms;
|
||||
EdgeMarkMapTuple& out_edge_mark_maps;
|
||||
UserVisitor& user_visitor;
|
||||
// output meshes
|
||||
const cpp11::array<boost::optional<TriangleMesh*>, 4>& desired_output;
|
||||
const cpp11::array<boost::optional<TriangleMesh*>, 4>& requested_output;
|
||||
// input meshes closed ?
|
||||
/// \todo do we really need this?
|
||||
bool is_tm1_closed;
|
||||
|
|
@ -251,14 +269,14 @@ class Face_graph_output_builder
|
|||
|
||||
template<class EdgeMarkMap>
|
||||
void mark_edges(const EdgeMarkMap& edge_mark_map,
|
||||
const std::vector<edge_descriptor>& edges)
|
||||
const std::vector<edge_descriptor>& edges)
|
||||
{
|
||||
BOOST_FOREACH(edge_descriptor ed, edges)
|
||||
put(edge_mark_map, ed, true);
|
||||
}
|
||||
|
||||
void mark_edges(const No_mark<TriangleMesh>&,
|
||||
const std::vector<edge_descriptor>&)
|
||||
const std::vector<edge_descriptor>&)
|
||||
{} //nothing to do
|
||||
|
||||
template<class EdgeMarkMapTuple>
|
||||
|
|
@ -336,17 +354,19 @@ public:
|
|||
const FaceIdMap& fids1,
|
||||
const FaceIdMap& fids2,
|
||||
EdgeMarkMapBind& marks_on_input_edges,
|
||||
const cpp11::array<VertexPointMap*, 4>& output_vpms,
|
||||
const VpmOutTuple& output_vpms,
|
||||
EdgeMarkMapTuple& out_edge_mark_maps,
|
||||
UserVisitor& user_visitor,
|
||||
const cpp11::array<
|
||||
boost::optional<TriangleMesh*>, 4 >& desired_output)
|
||||
boost::optional<TriangleMesh*>, 4 >& requested_output)
|
||||
: tm1(tm1), tm2(tm2)
|
||||
, vpm1(vpm1), vpm2(vpm2)
|
||||
, fids1(fids1), fids2(fids2)
|
||||
, marks_on_input_edges(marks_on_input_edges)
|
||||
, output_vpms(output_vpms)
|
||||
, out_edge_mark_maps(out_edge_mark_maps)
|
||||
, desired_output(desired_output)
|
||||
, user_visitor(user_visitor)
|
||||
, requested_output(requested_output)
|
||||
, is_tm1_closed( is_closed(tm1))
|
||||
, is_tm2_closed( is_closed(tm2))
|
||||
, is_tm1_inside_out( is_tm1_closed && !PMP::is_outward_oriented(tm1) )
|
||||
|
|
@ -361,7 +381,7 @@ public:
|
|||
}
|
||||
bool intersection_is_valid() const
|
||||
{
|
||||
return !impossible_operation[INTER];
|
||||
return !impossible_operation[INTERSECTION];
|
||||
}
|
||||
bool tm1_minus_tm2_is_valid() const
|
||||
{
|
||||
|
|
@ -852,7 +872,7 @@ public:
|
|||
// opposite( poly_first U poly_second ) = {O}
|
||||
is_patch_inside_tm2.set(patch_id_p1);
|
||||
is_patch_inside_tm2.set(patch_id_p2);
|
||||
impossible_operation.set(INTER); // tm1 n tm2 is non-manifold
|
||||
impossible_operation.set(INTERSECTION); // tm1 n tm2 is non-manifold
|
||||
}
|
||||
}
|
||||
else
|
||||
|
|
@ -1103,7 +1123,7 @@ public:
|
|||
std::vector< boost::dynamic_bitset<> > patches_of_tm2_used(4);
|
||||
|
||||
/// handle the bitset for the union
|
||||
if ( !impossible_operation.test(UNION) && desired_output[UNION] )
|
||||
if ( !impossible_operation.test(UNION) && requested_output[UNION] )
|
||||
{
|
||||
//define patches to import from P
|
||||
patches_of_tm1_used[UNION] = ~is_patch_inside_tm2 - coplanar_patches_of_tm1;
|
||||
|
|
@ -1112,7 +1132,7 @@ public:
|
|||
//handle coplanar patches
|
||||
if (coplanar_patches_of_tm1.any())
|
||||
{
|
||||
if (desired_output[UNION]==&tm2)
|
||||
if (requested_output[UNION]==&tm2)
|
||||
patches_of_tm2_used[UNION] |= coplanar_patches_of_tm2_for_union_and_intersection;
|
||||
else
|
||||
patches_of_tm1_used[UNION] |= coplanar_patches_of_tm1_for_union_and_intersection;
|
||||
|
|
@ -1120,24 +1140,24 @@ public:
|
|||
}
|
||||
|
||||
/// handle the bitset for the intersection
|
||||
if ( !impossible_operation.test(INTER) && desired_output[INTER] )
|
||||
if ( !impossible_operation.test(INTERSECTION) && requested_output[INTERSECTION] )
|
||||
{
|
||||
//define patches to import from P
|
||||
patches_of_tm1_used[INTER] = is_patch_inside_tm2;
|
||||
patches_of_tm1_used[INTERSECTION] = is_patch_inside_tm2;
|
||||
//define patches to import from Q
|
||||
patches_of_tm2_used[INTER] = is_patch_inside_tm1;
|
||||
patches_of_tm2_used[INTERSECTION] = is_patch_inside_tm1;
|
||||
//handle coplanar patches
|
||||
if (coplanar_patches_of_tm1.any())
|
||||
{
|
||||
if (desired_output[INTER]==&tm2)
|
||||
patches_of_tm2_used[INTER] |= coplanar_patches_of_tm2_for_union_and_intersection;
|
||||
if (requested_output[INTERSECTION]==&tm2)
|
||||
patches_of_tm2_used[INTERSECTION] |= coplanar_patches_of_tm2_for_union_and_intersection;
|
||||
else
|
||||
patches_of_tm1_used[INTER] |= coplanar_patches_of_tm1_for_union_and_intersection;
|
||||
patches_of_tm1_used[INTERSECTION] |= coplanar_patches_of_tm1_for_union_and_intersection;
|
||||
}
|
||||
}
|
||||
|
||||
/// handle the bitset for P-Q
|
||||
if ( !impossible_operation.test(TM1_MINUS_TM2) && desired_output[TM1_MINUS_TM2] )
|
||||
if ( !impossible_operation.test(TM1_MINUS_TM2) && requested_output[TM1_MINUS_TM2] )
|
||||
{
|
||||
//define patches to import from P
|
||||
patches_of_tm1_used[TM1_MINUS_TM2] = (~is_patch_inside_tm2 - coplanar_patches_of_tm1);
|
||||
|
|
@ -1146,7 +1166,7 @@ public:
|
|||
//handle coplanar patches
|
||||
if (coplanar_patches_of_tm1.any())
|
||||
{
|
||||
if (desired_output[TM1_MINUS_TM2]==&tm2)
|
||||
if (requested_output[TM1_MINUS_TM2]==&tm2)
|
||||
patches_of_tm2_used[TM1_MINUS_TM2] |= ~coplanar_patches_of_tm2_for_union_and_intersection & coplanar_patches_of_tm2;
|
||||
else
|
||||
patches_of_tm1_used[TM1_MINUS_TM2] |= ~coplanar_patches_of_tm1_for_union_and_intersection & coplanar_patches_of_tm1;
|
||||
|
|
@ -1154,7 +1174,7 @@ public:
|
|||
}
|
||||
|
||||
/// handle the bitset for Q-P
|
||||
if ( !impossible_operation.test(TM2_MINUS_TM1) && desired_output[TM2_MINUS_TM1] )
|
||||
if ( !impossible_operation.test(TM2_MINUS_TM1) && requested_output[TM2_MINUS_TM1] )
|
||||
{
|
||||
//define patches to import from P
|
||||
patches_of_tm1_used[TM2_MINUS_TM1] = is_patch_inside_tm2;
|
||||
|
|
@ -1163,7 +1183,7 @@ public:
|
|||
//handle coplanar patches
|
||||
if (coplanar_patches_of_tm1.any())
|
||||
{
|
||||
if (desired_output[TM2_MINUS_TM1]==&tm2)
|
||||
if (requested_output[TM2_MINUS_TM1]==&tm2)
|
||||
patches_of_tm2_used[TM2_MINUS_TM1] |= ~coplanar_patches_of_tm2_for_union_and_intersection & coplanar_patches_of_tm2;
|
||||
else
|
||||
patches_of_tm1_used[TM2_MINUS_TM1] |= ~coplanar_patches_of_tm1_for_union_and_intersection & coplanar_patches_of_tm1;
|
||||
|
|
@ -1174,8 +1194,8 @@ public:
|
|||
#ifdef CGAL_COREFINEMENT_DEBUG
|
||||
std::cout << "patches_of_tm1_used[UNION] " << patches_of_tm1_used[UNION] << "\n";
|
||||
std::cout << "patches_of_tm2_used[UNION] " << patches_of_tm2_used[UNION] << "\n";
|
||||
std::cout << "patches_of_tm1_used[INTER] " << patches_of_tm1_used[INTER] << "\n";
|
||||
std::cout << "patches_of_tm2_used[INTER] " << patches_of_tm2_used[INTER] << "\n";
|
||||
std::cout << "patches_of_tm1_used[INTERSECTION] " << patches_of_tm1_used[INTERSECTION] << "\n";
|
||||
std::cout << "patches_of_tm2_used[INTERSECTION] " << patches_of_tm2_used[INTERSECTION] << "\n";
|
||||
std::cout << "patches_of_tm1_used[TM1_MINUS_TM2] " << patches_of_tm1_used[TM1_MINUS_TM2] << "\n";
|
||||
std::cout << "patches_of_tm2_used[TM1_MINUS_TM2] " << patches_of_tm2_used[TM1_MINUS_TM2] << "\n";
|
||||
std::cout << "patches_of_tm1_used[TM2_MINUS_TM1] " << patches_of_tm1_used[TM2_MINUS_TM1] << "\n";
|
||||
|
|
@ -1185,29 +1205,29 @@ public:
|
|||
// should be done. First operations are those filling meshes
|
||||
// different from tm1 and tm2, then the one modifying tm1 and
|
||||
// finally the one modifying tm2.
|
||||
std::vector<Boolean_operation> out_of_place_operations;
|
||||
Boolean_operation inplace_operation_tm1=NONE,
|
||||
inplace_operation_tm2=NONE;
|
||||
std::vector<Boolean_operation_type> out_of_place_operations;
|
||||
Boolean_operation_type inplace_operation_tm1=NONE,
|
||||
inplace_operation_tm2=NONE;
|
||||
for (int i=0;i<4;++i)
|
||||
{
|
||||
Boolean_operation operation=enum_cast<Boolean_operation>(i);
|
||||
Boolean_operation_type operation=enum_cast<Boolean_operation_type>(i);
|
||||
|
||||
if (!desired_output[operation] || impossible_operation.test(operation))
|
||||
if (!requested_output[operation] || impossible_operation.test(operation))
|
||||
continue;
|
||||
|
||||
if (desired_output[operation]==&tm1)
|
||||
if (requested_output[operation]==&tm1)
|
||||
inplace_operation_tm1=operation;
|
||||
else
|
||||
if (desired_output[operation]==&tm2)
|
||||
if (requested_output[operation]==&tm2)
|
||||
inplace_operation_tm2=operation;
|
||||
else
|
||||
out_of_place_operations.push_back(operation);
|
||||
}
|
||||
|
||||
/// first handle operations in a mesh that is neither tm1 nor tm2
|
||||
BOOST_FOREACH(Boolean_operation operation, out_of_place_operations)
|
||||
BOOST_FOREACH(Boolean_operation_type operation, out_of_place_operations)
|
||||
{
|
||||
TriangleMesh& output = *(*desired_output[operation]);
|
||||
TriangleMesh& output = *(*requested_output[operation]);
|
||||
CGAL_assertion(&tm1!=&output && &tm2!=&output);
|
||||
|
||||
Intersection_polylines polylines(tm1_polylines,
|
||||
|
|
@ -1222,19 +1242,24 @@ public:
|
|||
);
|
||||
|
||||
std::vector<edge_descriptor> shared_edges;
|
||||
fill_new_triangle_mesh(
|
||||
output,
|
||||
patches_of_tm1_used[operation], patches_of_tm2_used[operation],
|
||||
patches_of_tm1, patches_of_tm2,
|
||||
operation == TM2_MINUS_TM1, operation == TM1_MINUS_TM2,
|
||||
polylines,
|
||||
intersection_edges1, intersection_edges2,
|
||||
vpm1, vpm2, *output_vpms[operation],
|
||||
marks_on_input_edges.ecm1,
|
||||
marks_on_input_edges.ecm2,
|
||||
CGAL_COREF_SELECT_OUT_ECM(operation),
|
||||
shared_edges
|
||||
);
|
||||
|
||||
#define CGAL_COREF_FUNCTION_CALL_DEF(BO_type) \
|
||||
fill_new_triangle_mesh( \
|
||||
output, \
|
||||
patches_of_tm1_used[BO_type], patches_of_tm2_used[BO_type], \
|
||||
patches_of_tm1, patches_of_tm2, \
|
||||
BO_type == TM2_MINUS_TM1, BO_type == TM1_MINUS_TM2, \
|
||||
polylines, \
|
||||
intersection_edges1, intersection_edges2, \
|
||||
vpm1, vpm2, *cpp11::get<BO_type>(output_vpms), \
|
||||
marks_on_input_edges.ecm1, \
|
||||
marks_on_input_edges.ecm2, \
|
||||
cpp11::get<BO_type>(out_edge_mark_maps), \
|
||||
shared_edges, \
|
||||
user_visitor \
|
||||
)
|
||||
CGAL_COREF_FUNCTION_CALL(operation)
|
||||
#undef CGAL_COREF_FUNCTION_CALL_DEF
|
||||
mark_edges(out_edge_mark_maps, shared_edges, operation);
|
||||
}
|
||||
|
||||
|
|
@ -1248,7 +1273,7 @@ public:
|
|||
mesh_to_intersection_edges[&tm1],
|
||||
inplace_operation_tm1);
|
||||
|
||||
CGAL_assertion( *desired_output[inplace_operation_tm1] == &tm1 );
|
||||
CGAL_assertion( *requested_output[inplace_operation_tm1] == &tm1 );
|
||||
|
||||
if ( inplace_operation_tm2!=NONE)
|
||||
{
|
||||
|
|
@ -1299,34 +1324,44 @@ public:
|
|||
patches_of_tm1[i];
|
||||
}
|
||||
// Operation in tm1: disconnect patches not use and append the one from tm2
|
||||
compute_inplace_operation_delay_removal_and_insideout(
|
||||
tm1,
|
||||
tm2,
|
||||
patches_of_tm1_used[inplace_operation_tm1],
|
||||
patches_of_tm2_used[inplace_operation_tm1],
|
||||
patches_of_tm1, patches_of_tm2,
|
||||
inplace_operation_tm1 == TM1_MINUS_TM2 ||
|
||||
inplace_operation_tm1 == TM2_MINUS_TM1,
|
||||
polylines_in_tm1,
|
||||
vpm1, vpm2,
|
||||
marks_on_input_edges.ecm1,
|
||||
marks_on_input_edges.ecm2,
|
||||
CGAL_COREF_SELECT_OUT_ECM(inplace_operation_tm1),
|
||||
disconnected_patches_edge_to_tm2_edge);
|
||||
#define CGAL_COREF_FUNCTION_CALL_DEF(BO_type)\
|
||||
compute_inplace_operation_delay_removal_and_insideout( \
|
||||
tm1, \
|
||||
tm2, \
|
||||
patches_of_tm1_used[BO_type], \
|
||||
patches_of_tm2_used[BO_type], \
|
||||
patches_of_tm1, patches_of_tm2, \
|
||||
BO_type == TM1_MINUS_TM2 || \
|
||||
BO_type == TM2_MINUS_TM1, \
|
||||
polylines_in_tm1, \
|
||||
vpm1, vpm2, \
|
||||
marks_on_input_edges.ecm1, \
|
||||
marks_on_input_edges.ecm2, \
|
||||
cpp11::get<BO_type>(out_edge_mark_maps), \
|
||||
disconnected_patches_edge_to_tm2_edge, \
|
||||
user_visitor)
|
||||
CGAL_COREF_FUNCTION_CALL(inplace_operation_tm1)
|
||||
#undef CGAL_COREF_FUNCTION_CALL_DEF
|
||||
// Operation in tm2: discard patches and append the one from tm2
|
||||
CGAL_assertion( *desired_output[inplace_operation_tm2] == &tm2 );
|
||||
compute_inplace_operation( tm2, tm1,
|
||||
patches_of_tm2_used[inplace_operation_tm2],
|
||||
patches_of_tm1_used[inplace_operation_tm2],
|
||||
patches_of_tm2, patches_of_tm1,
|
||||
inplace_operation_tm2==TM1_MINUS_TM2,
|
||||
inplace_operation_tm2==TM2_MINUS_TM1,
|
||||
vpm2,
|
||||
vpm1,
|
||||
marks_on_input_edges.ecm2,
|
||||
marks_on_input_edges.ecm1,
|
||||
CGAL_COREF_SELECT_OUT_ECM(inplace_operation_tm2),
|
||||
disconnected_patches_edge_to_tm2_edge);
|
||||
CGAL_assertion( *requested_output[inplace_operation_tm2] == &tm2 );
|
||||
|
||||
#define CGAL_COREF_FUNCTION_CALL_DEF(BO_type)\
|
||||
compute_inplace_operation( tm2, tm1, \
|
||||
patches_of_tm2_used[BO_type], \
|
||||
patches_of_tm1_used[BO_type], \
|
||||
patches_of_tm2, patches_of_tm1, \
|
||||
BO_type==TM1_MINUS_TM2, \
|
||||
BO_type==TM2_MINUS_TM1, \
|
||||
vpm2, \
|
||||
vpm1, \
|
||||
marks_on_input_edges.ecm2, \
|
||||
marks_on_input_edges.ecm1, \
|
||||
cpp11::get<BO_type>(out_edge_mark_maps), \
|
||||
disconnected_patches_edge_to_tm2_edge, \
|
||||
user_visitor)
|
||||
CGAL_COREF_FUNCTION_CALL(inplace_operation_tm2)
|
||||
#undef CGAL_COREF_FUNCTION_CALL_DEF
|
||||
|
||||
// remove polylines only on the border of patches not kept in tm2
|
||||
if (polylines_in_tm2.to_skip.any())
|
||||
remove_unused_polylines(tm2,
|
||||
|
|
@ -1339,8 +1374,12 @@ public:
|
|||
marks_on_input_edges.ecm1);
|
||||
|
||||
// transfer marks of edges of patches kept to the output edge mark property
|
||||
copy_edge_mark<TriangleMesh>(
|
||||
tm1, marks_on_input_edges.ecm1, CGAL_COREF_SELECT_OUT_ECM(inplace_operation_tm1));
|
||||
#define CGAL_COREF_FUNCTION_CALL_DEF(BO_type) \
|
||||
copy_edge_mark<TriangleMesh>( \
|
||||
tm1, marks_on_input_edges.ecm1, \
|
||||
cpp11::get<BO_type>(out_edge_mark_maps))
|
||||
CGAL_COREF_FUNCTION_CALL(inplace_operation_tm1)
|
||||
#undef CGAL_COREF_FUNCTION_CALL_DEF
|
||||
|
||||
// remove polylines only on the border of patches not kept in tm1
|
||||
if (polylines_in_tm1.to_skip.any())
|
||||
|
|
@ -1353,7 +1392,7 @@ public:
|
|||
}
|
||||
else{
|
||||
/// handle the operation updating only tm1
|
||||
CGAL_assertion( *desired_output[inplace_operation_tm1] == &tm1 );
|
||||
CGAL_assertion( *requested_output[inplace_operation_tm1] == &tm1 );
|
||||
Intersection_polylines polylines(
|
||||
tm1_polylines, tm2_polylines, polyline_lengths);
|
||||
fill_polylines_to_skip(
|
||||
|
|
@ -1361,21 +1400,24 @@ public:
|
|||
patches_of_tm1_used[inplace_operation_tm1],
|
||||
patches_of_tm2_used[inplace_operation_tm1],
|
||||
fids1, fids2, tm1, tm2);
|
||||
|
||||
compute_inplace_operation(
|
||||
tm1, tm2,
|
||||
patches_of_tm1_used[inplace_operation_tm1],
|
||||
patches_of_tm2_used[inplace_operation_tm1],
|
||||
patches_of_tm1, patches_of_tm2,
|
||||
inplace_operation_tm1 == TM2_MINUS_TM1,
|
||||
inplace_operation_tm1 == TM1_MINUS_TM2,
|
||||
vpm1,
|
||||
vpm2,
|
||||
marks_on_input_edges.ecm1,
|
||||
marks_on_input_edges.ecm2,
|
||||
CGAL_COREF_SELECT_OUT_ECM(inplace_operation_tm1),
|
||||
polylines
|
||||
);
|
||||
#define CGAL_COREF_FUNCTION_CALL_DEF(BO_type) \
|
||||
compute_inplace_operation( \
|
||||
tm1, tm2, \
|
||||
patches_of_tm1_used[BO_type], \
|
||||
patches_of_tm2_used[BO_type], \
|
||||
patches_of_tm1, patches_of_tm2, \
|
||||
BO_type == TM2_MINUS_TM1, \
|
||||
BO_type == TM1_MINUS_TM2, \
|
||||
vpm1, \
|
||||
vpm2, \
|
||||
marks_on_input_edges.ecm1, \
|
||||
marks_on_input_edges.ecm2, \
|
||||
cpp11::get<BO_type>(out_edge_mark_maps), \
|
||||
polylines, \
|
||||
user_visitor \
|
||||
)
|
||||
CGAL_COREF_FUNCTION_CALL(inplace_operation_tm1)
|
||||
#undef CGAL_COREF_FUNCTION_CALL_DEF
|
||||
// remove polylines only on the border of patches not kept
|
||||
if (polylines.to_skip.any())
|
||||
remove_unused_polylines(tm1,
|
||||
|
|
@ -1392,7 +1434,7 @@ public:
|
|||
inplace_operation_tm2);
|
||||
|
||||
/// handle the operation updating only tm2
|
||||
CGAL_assertion( *desired_output[inplace_operation_tm2] == &tm2 );
|
||||
CGAL_assertion( *requested_output[inplace_operation_tm2] == &tm2 );
|
||||
Intersection_polylines polylines(
|
||||
tm2_polylines, tm1_polylines, polyline_lengths);
|
||||
fill_polylines_to_skip(
|
||||
|
|
@ -1401,20 +1443,22 @@ public:
|
|||
patches_of_tm1_used[inplace_operation_tm2],
|
||||
fids2, fids1, tm2, tm1
|
||||
);
|
||||
|
||||
compute_inplace_operation( tm2, tm1,
|
||||
patches_of_tm2_used[inplace_operation_tm2],
|
||||
patches_of_tm1_used[inplace_operation_tm2],
|
||||
patches_of_tm2, patches_of_tm1,
|
||||
inplace_operation_tm2==TM1_MINUS_TM2,
|
||||
inplace_operation_tm2==TM2_MINUS_TM1,
|
||||
vpm2,
|
||||
vpm1,
|
||||
marks_on_input_edges.ecm2,
|
||||
marks_on_input_edges.ecm1,
|
||||
CGAL_COREF_SELECT_OUT_ECM(inplace_operation_tm2),
|
||||
polylines);
|
||||
|
||||
#define CGAL_COREF_FUNCTION_CALL_DEF(BO_type) \
|
||||
compute_inplace_operation( tm2, tm1, \
|
||||
patches_of_tm2_used[BO_type], \
|
||||
patches_of_tm1_used[BO_type], \
|
||||
patches_of_tm2, patches_of_tm1, \
|
||||
BO_type==TM1_MINUS_TM2, \
|
||||
BO_type==TM2_MINUS_TM1, \
|
||||
vpm2, \
|
||||
vpm1, \
|
||||
marks_on_input_edges.ecm2, \
|
||||
marks_on_input_edges.ecm1, \
|
||||
cpp11::get<BO_type>(out_edge_mark_maps), \
|
||||
polylines, \
|
||||
user_visitor);
|
||||
CGAL_COREF_FUNCTION_CALL(inplace_operation_tm2)
|
||||
#undef CGAL_COREF_FUNCTION_CALL_DEF
|
||||
// remove polylines only on the border of patches not kept
|
||||
if (polylines.to_skip.any())
|
||||
remove_unused_polylines(tm2,
|
||||
|
|
@ -1425,8 +1469,7 @@ public:
|
|||
};
|
||||
|
||||
|
||||
} } // CGAL::Corefinement
|
||||
|
||||
#undef CGAL_COREF_SELECT_OUT_ECM
|
||||
} } } // CGAL::Polygon_mesh_processing::Corefinement
|
||||
|
||||
#undef CGAL_COREF_FUNCTION_CALL
|
||||
#endif // CGAL_POLYGON_MESH_PROCESSING_INTERNAL_FACE_GRAPH_OUTPUT_BUILDER_H
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@
|
|||
#include <CGAL/property_map.h>
|
||||
|
||||
namespace CGAL{
|
||||
namespace Polygon_mesh_processing {
|
||||
namespace Corefinement{
|
||||
|
||||
enum Intersection_type {ON_FACE,ON_EDGE,ON_VERTEX,EMPTY,COPLANAR_TRIANGLES};
|
||||
|
|
@ -50,6 +51,6 @@ struct Coplanar_intersection{
|
|||
|
||||
};
|
||||
|
||||
} } // CGAL::Corefinement
|
||||
} } } // CGAL::Polygon_mesh_processing::Corefinement
|
||||
|
||||
#endif // CGAL_PMP_INTERNAL_COREFINEMENT_INTERSECTION_TYPE_H
|
||||
|
|
|
|||
|
|
@ -40,6 +40,7 @@
|
|||
#include <boost/dynamic_bitset.hpp>
|
||||
|
||||
namespace CGAL {
|
||||
namespace Polygon_mesh_processing {
|
||||
namespace Corefinement {
|
||||
|
||||
namespace PMP=Polygon_mesh_processing;
|
||||
|
|
@ -1012,7 +1013,7 @@ public:
|
|||
};
|
||||
|
||||
|
||||
} } // CGAL::Corefinement
|
||||
} } } // CGAL::Corefinement
|
||||
|
||||
#include <CGAL/enable_warnings.h>
|
||||
|
||||
|
|
|
|||
|
|
@ -36,46 +36,11 @@
|
|||
#include <CGAL/Triangulation_vertex_base_with_info_2.h>
|
||||
|
||||
namespace CGAL{
|
||||
namespace Polygon_mesh_processing {
|
||||
namespace Corefinement{
|
||||
|
||||
// TODO option to ignore internal edges for patches of coplanar faces
|
||||
|
||||
template <class TriangleMesh>
|
||||
struct Default_node_visitor{
|
||||
typedef boost::graph_traits<TriangleMesh> GT;
|
||||
typedef typename GT::halfedge_descriptor halfedge_descriptor;
|
||||
typedef typename GT::face_descriptor face_descriptor;
|
||||
typedef typename GT::vertex_descriptor vertex_descriptor;
|
||||
|
||||
void new_node_added( std::size_t /* node_id */,
|
||||
Intersection_type /* type */,
|
||||
halfedge_descriptor /* principal_edge */,
|
||||
halfedge_descriptor /* additional_edge */,
|
||||
bool /* is_target_coplanar */,
|
||||
bool /* is_source_coplanar */ )
|
||||
{}
|
||||
|
||||
void new_node_added_triple_face(std::size_t /* node_id */,
|
||||
face_descriptor /* f1 */,
|
||||
face_descriptor /* f2 */,
|
||||
face_descriptor /* f3 */,
|
||||
const TriangleMesh& /* tm */)
|
||||
{}
|
||||
|
||||
void new_vertex_added(std::size_t /* node_id */,
|
||||
vertex_descriptor /* vh */,
|
||||
TriangleMesh& /*tm*/){}
|
||||
};
|
||||
|
||||
template <class TriangleMesh>
|
||||
struct Default_face_visitor{
|
||||
typedef boost::graph_traits<TriangleMesh> GT;
|
||||
typedef typename GT::face_descriptor face_descriptor;
|
||||
|
||||
void before_subface_creations(face_descriptor /*f_old*/,TriangleMesh&){}
|
||||
void after_subface_created(face_descriptor /*f_new*/,TriangleMesh&){}
|
||||
};
|
||||
|
||||
//binds two edge constrained pmaps
|
||||
template <class G, class Ecm1, class Ecm2=Ecm1>
|
||||
struct Ecm_bind{
|
||||
|
|
@ -147,19 +112,16 @@ template< class TriangleMesh,
|
|||
class VertexPointMap,
|
||||
class OutputBuilder_ = Default,
|
||||
class EdgeMarkMapBind_ = Default,
|
||||
class NewNodeVisitor_ = Default,
|
||||
class NewFaceVisitor_ = Default,
|
||||
class UserVisitor_ = Default,
|
||||
bool doing_autorefinement = false >
|
||||
class Visitor{
|
||||
class Surface_intersection_visitor_for_corefinement{
|
||||
//default template parameters
|
||||
typedef typename Default::Get<EdgeMarkMapBind_,
|
||||
Ecm_bind<TriangleMesh, No_mark<TriangleMesh> > >::type EdgeMarkMapBind;
|
||||
typedef typename Default::Get<OutputBuilder_,
|
||||
No_extra_output_from_corefinement<TriangleMesh> >::type OutputBuilder;
|
||||
typedef typename Default::Get<
|
||||
NewNodeVisitor_, Default_node_visitor<TriangleMesh> >::type NewNodeVisitor;
|
||||
typedef typename Default::Get<
|
||||
NewFaceVisitor_, Default_face_visitor<TriangleMesh> >::type NewFaceVisitor;
|
||||
UserVisitor_, Default_visitor<TriangleMesh> >::type UserVisitor;
|
||||
|
||||
// config flags
|
||||
public:
|
||||
|
|
@ -211,8 +173,7 @@ private:
|
|||
std::map< Node_id,std::set<Node_id> > coplanar_constraints;
|
||||
|
||||
//data members that require initialization in the constructor
|
||||
NewNodeVisitor& new_node_visitor;
|
||||
NewFaceVisitor& new_face_visitor;
|
||||
UserVisitor& user_visitor;
|
||||
OutputBuilder& output_builder;
|
||||
EdgeMarkMapBind marks_on_edges;
|
||||
bool input_with_coplanar_faces;
|
||||
|
|
@ -245,10 +206,9 @@ private:
|
|||
|
||||
// visitor public functions
|
||||
public:
|
||||
Visitor(NewNodeVisitor& v, NewFaceVisitor& f,
|
||||
OutputBuilder& o, const EdgeMarkMapBind& emm)
|
||||
: new_node_visitor(v)
|
||||
, new_face_visitor(f)
|
||||
Surface_intersection_visitor_for_corefinement(
|
||||
UserVisitor& uv, OutputBuilder& o, const EdgeMarkMapBind& emm)
|
||||
: user_visitor(uv)
|
||||
, output_builder(o)
|
||||
, marks_on_edges(emm)
|
||||
, input_with_coplanar_faces(false)
|
||||
|
|
@ -353,7 +313,7 @@ public:
|
|||
{
|
||||
CGAL_assertion(f1!=f2 && f1!=f3 && f2!=f3);
|
||||
TriangleMesh* tm_ptr = const_cast<TriangleMesh*>(&tm);
|
||||
new_node_visitor.new_node_added_triple_face(node_id, f1, f2, f3, tm);
|
||||
// user_visitor.new_node_added_triple_face(node_id, f1, f2, f3, tm); // NODE_VISITOR_TAG
|
||||
#ifdef CGAL_DEBUG_AUTOREFINEMENT
|
||||
std::cout << "adding node " << node_id << " " << f1 << " " << f2 << " " << f3 << "\n";
|
||||
#endif
|
||||
|
|
@ -377,7 +337,7 @@ public:
|
|||
TriangleMesh* tm2_ptr = const_cast<TriangleMesh*>(&tm2);
|
||||
|
||||
//forward to the visitor
|
||||
new_node_visitor.new_node_added(node_id, type, h_1, h_2, is_target_coplanar, is_source_coplanar);
|
||||
// user_visitor.new_node_added(node_id, type, h_1, h_2, is_target_coplanar, is_source_coplanar); // NODE_VISITOR_TAG
|
||||
switch(type)
|
||||
{
|
||||
case ON_FACE: //Face intersected by an edge
|
||||
|
|
@ -790,7 +750,7 @@ public:
|
|||
halfedge_descriptor hnew = Euler::split_edge(hedge, tm);
|
||||
CGAL_assertion(expected_src==source(hnew,tm));
|
||||
vertex_descriptor vnew=target(hnew,tm);
|
||||
new_node_visitor.new_vertex_added(node_id, vnew, tm);
|
||||
// user_visitor.new_vertex_added(node_id, vnew, tm); // NODE_VISITOR_TAG
|
||||
nodes.call_put(vpm, vnew, node_id, tm);
|
||||
|
||||
node_id_to_vertex[node_id]=vnew;
|
||||
|
|
@ -1036,7 +996,7 @@ public:
|
|||
|
||||
// import the triangle in `cdt` in the face `f` of `tm`
|
||||
triangulate_a_face(f, tm, nodes, node_ids, node_id_to_vertex,
|
||||
edge_to_hedge, cdt, vpm, new_node_visitor, new_face_visitor);
|
||||
edge_to_hedge, cdt, vpm, user_visitor);
|
||||
|
||||
// TODO Here we do the update only for internal edges.
|
||||
// Update for border halfedges could be done during the split
|
||||
|
|
@ -1080,7 +1040,7 @@ public:
|
|||
}
|
||||
};
|
||||
|
||||
} } //end of namespace CGAL::Corefinement
|
||||
} } } // CGAL::Polygon_mesh_processing::Corefinement
|
||||
|
||||
#include <CGAL/enable_warnings.h>
|
||||
|
||||
|
|
|
|||
|
|
@ -28,11 +28,14 @@
|
|||
#include <CGAL/Polygon_mesh_processing/orientation.h>
|
||||
#include <CGAL/property_map.h>
|
||||
#include <boost/type_traits/is_const.hpp>
|
||||
#include <boost/type_traits/is_same.hpp>
|
||||
#include <boost/type_traits/remove_reference.hpp>
|
||||
#include <boost/mpl/if.hpp>
|
||||
#include <fstream>
|
||||
#include <sstream>
|
||||
#include <set>
|
||||
namespace CGAL {
|
||||
namespace Polygon_mesh_processing {
|
||||
namespace Corefinement {
|
||||
|
||||
template <typename G>
|
||||
|
|
@ -152,13 +155,115 @@ void copy_edge_mark(G&,
|
|||
No_mark<G>&)
|
||||
{} // nothing to do
|
||||
|
||||
// Parts to get default property maps for output meshes based on the value type
|
||||
// of input vertex point maps.
|
||||
template <typename Point_3, typename vertex_descriptor>
|
||||
struct Dummy_default_vertex_point_map
|
||||
{
|
||||
typedef vertex_descriptor key_type;
|
||||
typedef Point_3 value_type;
|
||||
typedef Point_3 reference;
|
||||
typedef boost::read_write_property_map_tag category;
|
||||
|
||||
inline friend
|
||||
value_type
|
||||
get(Dummy_default_vertex_point_map, key_type)
|
||||
{
|
||||
CGAL_assertion(false ||
|
||||
!"This property map should not be used."
|
||||
"Check the value type of the output vpm vs that of input");
|
||||
return Point_3();
|
||||
}
|
||||
|
||||
inline friend
|
||||
void
|
||||
put(Dummy_default_vertex_point_map, key_type, value_type)
|
||||
{
|
||||
CGAL_assertion(false ||
|
||||
!"This property map should not be used."
|
||||
"Check the value type of the output vpm vs that of input");
|
||||
}
|
||||
};
|
||||
|
||||
template <class Point_3, class NamedParameter, class PolygonMesh>
|
||||
struct TweakedGetVertexPointMap
|
||||
{
|
||||
typedef typename GetVertexPointMap<PolygonMesh,
|
||||
NamedParameter>::type Default_map;
|
||||
typedef typename boost::is_same<Point_3,
|
||||
typename boost::property_traits<Default_map>::value_type>::type Use_default_tag;
|
||||
|
||||
typedef typename boost::mpl::if_<
|
||||
Use_default_tag,
|
||||
Default_map,
|
||||
Dummy_default_vertex_point_map<Point_3,
|
||||
typename boost::graph_traits<PolygonMesh>::vertex_descriptor >
|
||||
>::type type;
|
||||
};
|
||||
|
||||
template <class PT, class NP, class PM>
|
||||
boost::optional< typename TweakedGetVertexPointMap<PT, NP, PM>::type >
|
||||
get_vpm(const NP& np, boost::optional<PM*> opm, boost::true_type)
|
||||
{
|
||||
if (boost::none == opm) return boost::none;
|
||||
return boost::choose_param(
|
||||
boost::get_param(np, internal_np::vertex_point),
|
||||
get_property_map(boost::vertex_point, *(*opm)) );
|
||||
}
|
||||
|
||||
template <class PT, class NP, class PM>
|
||||
boost::optional< typename TweakedGetVertexPointMap<PT, NP, PM>::type >
|
||||
get_vpm(const NP&, boost::optional<PM*> opm, boost::false_type)
|
||||
{
|
||||
if (boost::none == opm) return boost::none;
|
||||
return typename TweakedGetVertexPointMap<PT, NP, PM>::type();
|
||||
}
|
||||
//
|
||||
|
||||
template <class TriangleMesh>
|
||||
struct Default_visitor{
|
||||
typedef boost::graph_traits<TriangleMesh> GT;
|
||||
typedef typename GT::face_descriptor face_descriptor;
|
||||
|
||||
void before_subface_creations(face_descriptor /*f_old*/,TriangleMesh&){}
|
||||
void after_subface_creations(TriangleMesh&){}
|
||||
void before_subface_created(TriangleMesh&){}
|
||||
void after_subface_created(face_descriptor /*f_new*/,TriangleMesh&){}
|
||||
void before_face_copy(face_descriptor /*f_old*/, TriangleMesh&, TriangleMesh&){}
|
||||
void after_face_copy(face_descriptor /*f_old*/, TriangleMesh&,
|
||||
face_descriptor /* f_new */, TriangleMesh&){}
|
||||
|
||||
// calls commented in the code and probably incomplete due to the migration
|
||||
// see NODE_VISITOR_TAG
|
||||
/*
|
||||
void new_node_added( std::size_t node_id,
|
||||
Intersection_type type,
|
||||
halfedge_descriptor principal_edge,
|
||||
halfedge_descriptor additional_edge,
|
||||
bool is_target_coplanar,
|
||||
bool is_source_coplanar)
|
||||
{}
|
||||
|
||||
// autorefinement only
|
||||
void new_node_added_triple_face(std::size_t node_id,
|
||||
face_descriptor f1,
|
||||
face_descriptor f2,
|
||||
face_descriptor f3,
|
||||
const TriangleMesh& tm)
|
||||
{}
|
||||
|
||||
void new_vertex_added(std::size_tnode_id,
|
||||
vertex_descriptor vh,
|
||||
TriangleMesh& tm){}
|
||||
*/
|
||||
};
|
||||
|
||||
template < class TriangleMesh,
|
||||
class VertexPointMap,
|
||||
class Node_id,
|
||||
class Node_vector,
|
||||
class CDT,
|
||||
class NewNodeVisitor,
|
||||
class NewFaceVisitor >
|
||||
class UserVisitor>
|
||||
void
|
||||
triangulate_a_face(
|
||||
typename boost::graph_traits<TriangleMesh>::face_descriptor current_face,
|
||||
|
|
@ -172,8 +277,7 @@ triangulate_a_face(
|
|||
::halfedge_descriptor>& edge_to_hedge,
|
||||
const CDT& cdt,
|
||||
const VertexPointMap& vpm,
|
||||
NewNodeVisitor& new_node_visitor,
|
||||
NewFaceVisitor& new_face_visitor)
|
||||
UserVisitor& user_visitor)
|
||||
{
|
||||
typedef boost::graph_traits<TriangleMesh> GT;
|
||||
typedef typename GT::vertex_descriptor vertex_descriptor;
|
||||
|
|
@ -186,7 +290,7 @@ triangulate_a_face(
|
|||
BOOST_FOREACH(Node_id node_id, node_ids)
|
||||
{
|
||||
vertex_descriptor v=add_vertex(tm);
|
||||
new_node_visitor.new_vertex_added(node_id, v, tm);
|
||||
// user_visitor.new_vertex_added(node_id, v, tm); // NODE_VISITOR_TAG
|
||||
nodes.call_put(vpm, v, node_id, tm);
|
||||
CGAL_assertion(node_id_to_vertex.size()>node_id);
|
||||
node_id_to_vertex[node_id]=v;
|
||||
|
|
@ -226,7 +330,7 @@ triangulate_a_face(
|
|||
}
|
||||
|
||||
//grab triangles.
|
||||
new_face_visitor.before_subface_creations(current_face,tm);
|
||||
user_visitor.before_subface_creations(current_face,tm);
|
||||
for (typename CDT::Finite_faces_iterator it=cdt.finite_faces_begin(),
|
||||
it_end=cdt.finite_faces_end();;)
|
||||
{
|
||||
|
|
@ -262,12 +366,14 @@ triangulate_a_face(
|
|||
|
||||
if ( ++it!=it_end )
|
||||
{
|
||||
user_visitor.before_subface_created(tm);
|
||||
current_face=add_face(tm);
|
||||
new_face_visitor.before_subface_creations(current_face,tm);
|
||||
user_visitor.after_subface_created(current_face,tm);
|
||||
}
|
||||
else
|
||||
break;
|
||||
}
|
||||
user_visitor.after_subface_creations(tm);
|
||||
}
|
||||
|
||||
template <class PolygonMesh>
|
||||
|
|
@ -484,6 +590,7 @@ template <class PolygonMesh,
|
|||
class EdgeMap,
|
||||
class VertexMap,
|
||||
class VertexPointMap,
|
||||
class VertexPointMapOut,
|
||||
class IntersectionEdgeMap>
|
||||
void import_polyline(
|
||||
PolygonMesh& output,
|
||||
|
|
@ -499,7 +606,7 @@ void import_polyline(
|
|||
const IntersectionEdgeMap& intersection_edges2,
|
||||
const VertexPointMap& vpm1,
|
||||
const VertexPointMap& /*vpm2*/,
|
||||
const VertexPointMap& vpm_out,
|
||||
const VertexPointMapOut& vpm_out,
|
||||
std::vector<typename boost::graph_traits<PolygonMesh>
|
||||
::edge_descriptor>& output_shared_edges)
|
||||
{
|
||||
|
|
@ -696,20 +803,23 @@ template < bool reverse_patch_orientation,
|
|||
class TriangleMesh,
|
||||
class PatchContainer,
|
||||
class VertexPointMap,
|
||||
class VertexPointMapOut,
|
||||
class EdgeMarkMapOut,
|
||||
class EdgeMarkMapIn >
|
||||
class EdgeMarkMapIn ,
|
||||
class UserVisitor>
|
||||
void append_patches_to_triangle_mesh(
|
||||
TriangleMesh& output,
|
||||
const boost::dynamic_bitset<>& patches_to_append,
|
||||
PatchContainer& patches,
|
||||
const VertexPointMap& vpm_out,
|
||||
const VertexPointMapOut& vpm_out,
|
||||
const VertexPointMap& vpm_tm,
|
||||
EdgeMarkMapOut& edge_mark_map_out,
|
||||
const EdgeMarkMapIn& edge_mark_map_in,
|
||||
boost::unordered_map<
|
||||
typename boost::graph_traits<TriangleMesh>::edge_descriptor,
|
||||
typename boost::graph_traits<TriangleMesh>::edge_descriptor
|
||||
>& tm_to_output_edges)
|
||||
>& tm_to_output_edges,
|
||||
UserVisitor& user_visitor)
|
||||
{
|
||||
typedef boost::graph_traits<TriangleMesh> GT;
|
||||
typedef typename GT::halfedge_descriptor halfedge_descriptor;
|
||||
|
|
@ -781,7 +891,9 @@ void append_patches_to_triangle_mesh(
|
|||
{
|
||||
cpp11::array<halfedge_descriptor,3> hedges = helper.halfedges(f);
|
||||
|
||||
user_visitor.before_face_copy(f, patches.pm, output);
|
||||
face_descriptor new_f = add_face(output);
|
||||
user_visitor.after_face_copy(f, patches.pm, new_f, output);
|
||||
set_halfedge(new_f, hedges[0], output);
|
||||
|
||||
for (int i=0;i<3;++i)
|
||||
|
|
@ -899,11 +1011,13 @@ void append_patches_to_triangle_mesh(
|
|||
template < class TriangleMesh,
|
||||
class IntersectionEdgeMap,
|
||||
class VertexPointMap,
|
||||
class VertexPointMapOut,
|
||||
class EdgeMarkMap1,
|
||||
class EdgeMarkMap2,
|
||||
class EdgeMarkMapOut,
|
||||
class IntersectionPolylines,
|
||||
class PatchContainer>
|
||||
class PatchContainer,
|
||||
class UserVisitor>
|
||||
void fill_new_triangle_mesh(
|
||||
TriangleMesh& output,
|
||||
const boost::dynamic_bitset<>& patches_of_tm1_to_import,
|
||||
|
|
@ -917,12 +1031,13 @@ void fill_new_triangle_mesh(
|
|||
const IntersectionEdgeMap& intersection_edges2,
|
||||
const VertexPointMap& vpm1,
|
||||
const VertexPointMap& vpm2,
|
||||
const VertexPointMap& vpm_out,
|
||||
const VertexPointMapOut& vpm_out,
|
||||
const EdgeMarkMap1& edge_mark_map1,
|
||||
const EdgeMarkMap2& edge_mark_map2,
|
||||
EdgeMarkMapOut& edge_mark_map_out,
|
||||
std::vector< typename boost::graph_traits<TriangleMesh>::edge_descriptor>&
|
||||
output_shared_edges)
|
||||
output_shared_edges,
|
||||
UserVisitor& user_visitor)
|
||||
{
|
||||
typedef boost::graph_traits<TriangleMesh> GT;
|
||||
typedef typename GT::vertex_descriptor vertex_descriptor;
|
||||
|
|
@ -961,7 +1076,8 @@ void fill_new_triangle_mesh(
|
|||
vpm1,
|
||||
edge_mark_map_out,
|
||||
edge_mark_map1,
|
||||
tm1_to_output_edges);
|
||||
tm1_to_output_edges,
|
||||
user_visitor);
|
||||
else
|
||||
append_patches_to_triangle_mesh<false>(output,
|
||||
patches_of_tm1_to_import,
|
||||
|
|
@ -970,7 +1086,8 @@ void fill_new_triangle_mesh(
|
|||
vpm1,
|
||||
edge_mark_map_out,
|
||||
edge_mark_map1,
|
||||
tm1_to_output_edges);
|
||||
tm1_to_output_edges,
|
||||
user_visitor);
|
||||
|
||||
//import patches from tm2
|
||||
if (reverse_orientation_of_patches_from_tm2)
|
||||
|
|
@ -981,7 +1098,8 @@ void fill_new_triangle_mesh(
|
|||
vpm2,
|
||||
edge_mark_map_out,
|
||||
edge_mark_map2,
|
||||
tm2_to_output_edges);
|
||||
tm2_to_output_edges,
|
||||
user_visitor);
|
||||
else
|
||||
append_patches_to_triangle_mesh<false>(output,
|
||||
patches_of_tm2_to_import,
|
||||
|
|
@ -990,7 +1108,8 @@ void fill_new_triangle_mesh(
|
|||
vpm2,
|
||||
edge_mark_map_out,
|
||||
edge_mark_map2,
|
||||
tm2_to_output_edges);
|
||||
tm2_to_output_edges,
|
||||
user_visitor);
|
||||
}
|
||||
|
||||
template <class TriangleMesh,
|
||||
|
|
@ -1149,7 +1268,8 @@ template <class TriangleMesh,
|
|||
class VertexPointMap,
|
||||
class EdgeMarkMapIn1,
|
||||
class EdgeMarkMapIn2,
|
||||
class EdgeMarkMapOut>
|
||||
class EdgeMarkMapOut,
|
||||
class UserVisitor>
|
||||
void compute_inplace_operation_delay_removal_and_insideout(
|
||||
TriangleMesh& tm1,
|
||||
TriangleMesh& tm2,
|
||||
|
|
@ -1164,7 +1284,8 @@ void compute_inplace_operation_delay_removal_and_insideout(
|
|||
EdgeMarkMapIn1&,
|
||||
const EdgeMarkMapIn2& edge_mark_map2,
|
||||
const EdgeMarkMapOut& edge_mark_map_out1,
|
||||
EdgeMap& disconnected_patches_edge_to_tm2_edge)
|
||||
EdgeMap& disconnected_patches_edge_to_tm2_edge,
|
||||
UserVisitor& user_visitor)
|
||||
{
|
||||
typedef boost::graph_traits<TriangleMesh> GT;
|
||||
typedef typename GT::edge_descriptor edge_descriptor;
|
||||
|
|
@ -1214,7 +1335,8 @@ void compute_inplace_operation_delay_removal_and_insideout(
|
|||
vpm2,
|
||||
edge_mark_map_out1,
|
||||
edge_mark_map2,
|
||||
tm2_edge_to_tm1_edge);
|
||||
tm2_edge_to_tm1_edge,
|
||||
user_visitor);
|
||||
else
|
||||
append_patches_to_triangle_mesh<false>(tm1,
|
||||
patches_of_tm2_to_import,
|
||||
|
|
@ -1223,7 +1345,8 @@ void compute_inplace_operation_delay_removal_and_insideout(
|
|||
vpm2,
|
||||
edge_mark_map_out1,
|
||||
edge_mark_map2,
|
||||
tm2_edge_to_tm1_edge);
|
||||
tm2_edge_to_tm1_edge,
|
||||
user_visitor);
|
||||
}
|
||||
|
||||
template <class TriangleMesh,
|
||||
|
|
@ -1303,7 +1426,8 @@ template <class TriangleMesh,
|
|||
class VertexPointMap,
|
||||
class EdgeMarkMapIn1,
|
||||
class EdgeMarkMapIn2,
|
||||
class EdgeMarkMapOut1>
|
||||
class EdgeMarkMapOut1,
|
||||
class UserVisitor>
|
||||
void compute_inplace_operation(
|
||||
TriangleMesh& tm1,
|
||||
const TriangleMesh& /*tm2*/,
|
||||
|
|
@ -1321,7 +1445,8 @@ void compute_inplace_operation(
|
|||
boost::unordered_map<
|
||||
typename boost::graph_traits<TriangleMesh>::edge_descriptor,
|
||||
typename boost::graph_traits<TriangleMesh>::edge_descriptor
|
||||
>& tm2_edge_to_tm1_edge)
|
||||
>& tm2_edge_to_tm1_edge,
|
||||
UserVisitor& user_visitor)
|
||||
{
|
||||
typedef boost::unordered_map<
|
||||
typename boost::graph_traits<TriangleMesh>::edge_descriptor,
|
||||
|
|
@ -1350,7 +1475,8 @@ void compute_inplace_operation(
|
|||
vpm2,
|
||||
edge_mark_map_out1,
|
||||
edge_mark_map_in2,
|
||||
tm2_edge_to_tm1_edge);
|
||||
tm2_edge_to_tm1_edge,
|
||||
user_visitor);
|
||||
else
|
||||
append_patches_to_triangle_mesh<false>(tm1,
|
||||
patches_of_tm2_to_import,
|
||||
|
|
@ -1359,7 +1485,8 @@ void compute_inplace_operation(
|
|||
vpm2,
|
||||
edge_mark_map_out1,
|
||||
edge_mark_map_in2,
|
||||
tm2_edge_to_tm1_edge);
|
||||
tm2_edge_to_tm1_edge,
|
||||
user_visitor);
|
||||
}
|
||||
|
||||
template <class TriangleMesh,
|
||||
|
|
@ -1404,7 +1531,8 @@ template <class TriangleMesh,
|
|||
class VertexPointMap,
|
||||
class EdgeMarkMapIn1,
|
||||
class EdgeMarkMapIn2,
|
||||
class EdgeMarkMapOut1>
|
||||
class EdgeMarkMapOut1,
|
||||
class UserVisitor>
|
||||
void compute_inplace_operation(
|
||||
TriangleMesh& tm1,
|
||||
const TriangleMesh& tm2,
|
||||
|
|
@ -1419,7 +1547,8 @@ void compute_inplace_operation(
|
|||
const EdgeMarkMapIn1& edge_mark_map_in1,
|
||||
const EdgeMarkMapIn2& edge_mark_map_in2,
|
||||
const EdgeMarkMapOut1& edge_mark_map_out1,
|
||||
const IntersectionPolylines& polylines)
|
||||
const IntersectionPolylines& polylines,
|
||||
UserVisitor& user_visitor)
|
||||
{
|
||||
typedef boost::graph_traits<TriangleMesh> GT;
|
||||
typedef typename GT::edge_descriptor edge_descriptor;
|
||||
|
|
@ -1442,7 +1571,8 @@ void compute_inplace_operation(
|
|||
edge_mark_map_in1,
|
||||
edge_mark_map_in2,
|
||||
edge_mark_map_out1,
|
||||
tm2_edge_to_tm1_edge);
|
||||
tm2_edge_to_tm1_edge,
|
||||
user_visitor);
|
||||
}
|
||||
|
||||
// function used to remove polylines imported or kept that are incident only
|
||||
|
|
@ -1539,6 +1669,6 @@ void remove_disconnected_patches(
|
|||
}
|
||||
}
|
||||
|
||||
} } // end of namespace CGAL::Corefinement
|
||||
} } } // CGAL::Polygon_mesh_processing::Corefinement
|
||||
|
||||
#endif // CGAL_POLYGON_MESH_PROCESSING_INTERNAL_FACE_GRAPH_UTILS_H
|
||||
|
|
|
|||
|
|
@ -31,6 +31,7 @@
|
|||
#include <CGAL/property_map.h>
|
||||
|
||||
namespace CGAL{
|
||||
namespace Polygon_mesh_processing {
|
||||
namespace Corefinement{
|
||||
|
||||
|
||||
|
|
@ -178,6 +179,6 @@ intersection_type(
|
|||
}
|
||||
}
|
||||
|
||||
}} //namespace CGAL::internal_IOP
|
||||
} } } // CGAL::Polygon_mesh_processing::Corefinement
|
||||
|
||||
#endif //CGAL_INTERNAL_PMP_INTERSECT_TRIANGLE_AND_SEGMENT_3_H
|
||||
|
|
|
|||
|
|
@ -34,6 +34,7 @@
|
|||
#include <set>
|
||||
|
||||
namespace CGAL {
|
||||
namespace Polygon_mesh_processing {
|
||||
namespace Corefinement {
|
||||
|
||||
template<class TriangleMesh, class EdgeToFaces>
|
||||
|
|
@ -344,6 +345,6 @@ public:
|
|||
}
|
||||
};
|
||||
|
||||
} } // end of namespace CGAL::Corefinement
|
||||
} } } // CGAL::Polygon_mesh_processing::Corefinement
|
||||
|
||||
#endif // CGAL_POLYGON_MESH_PROCESSING_INTERNAL_COREFINEMENT_INTERSECTION_CALLBACK_H
|
||||
|
|
|
|||
|
|
@ -41,6 +41,7 @@
|
|||
#include <boost/dynamic_bitset.hpp>
|
||||
|
||||
namespace CGAL{
|
||||
namespace Polygon_mesh_processing {
|
||||
namespace Corefinement {
|
||||
|
||||
struct Self_intersection_exception{};
|
||||
|
|
@ -1364,6 +1365,6 @@ public:
|
|||
|
||||
};
|
||||
|
||||
} } // end of namespace CGAL::Corefinement
|
||||
} } } // CGAL::Polygon_mesh_processing::Corefinement
|
||||
|
||||
#endif //CGAL_POLYGON_MESH_PROCESSING_INTERNAL_COREFINEMENT_INTERSECTION_IMPL_H
|
||||
|
|
|
|||
|
|
@ -30,6 +30,7 @@
|
|||
#include <CGAL/Kernel_traits.h>
|
||||
|
||||
namespace CGAL {
|
||||
namespace Polygon_mesh_processing {
|
||||
namespace Corefinement {
|
||||
|
||||
// A class responsible for storing the intersection nodes of the intersection
|
||||
|
|
@ -418,6 +419,6 @@ public:
|
|||
}; // end specialization
|
||||
|
||||
|
||||
} } // end of namespace CGAL::Corefinement
|
||||
} } } // CGAL::Polygon_mesh_processing::Corefinement
|
||||
|
||||
#endif // CGAL_POLYGON_MESH_PROCESSING_INTERNAL_COREFINEMENT_INTERSECTION_NODES_H
|
||||
|
|
|
|||
|
|
@ -33,6 +33,7 @@
|
|||
#include <bitset>
|
||||
|
||||
namespace CGAL{
|
||||
namespace Polygon_mesh_processing {
|
||||
namespace Corefinement{
|
||||
|
||||
template <class TriangleMesh, class VertexPointMap>
|
||||
|
|
@ -320,7 +321,7 @@ void intersection_coplanar_faces(
|
|||
intersect_cpln.cutoff_face(next(next(h2,tm2),tm2),inter_pts,h1);
|
||||
}
|
||||
|
||||
} } //namespace CGAL::Corefinement
|
||||
} } } // CGAL::Polygon_mesh_processing::Corefinement
|
||||
|
||||
|
||||
#endif //CGAL_PMP_INTERNAL_COREFINEMENT_INTERSECTION_OF_COPLANAR_TRIANGLES_3_H
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@
|
|||
#include <CGAL/use.h>
|
||||
|
||||
namespace CGAL {
|
||||
namespace Polygon_mesh_processing {
|
||||
namespace Corefinement {
|
||||
|
||||
|
||||
|
|
@ -176,6 +177,6 @@ bool sorted_around_edge( Node_id o_prime_index,
|
|||
}
|
||||
|
||||
|
||||
} } // end of namespace CGAL::Corefinement
|
||||
} } } // CGAL::Polygon_mesh_processing::Corefinement
|
||||
|
||||
#endif // CGAL_POLYGON_MESH_PROCESSING_INTERNAL_COREFINEMENT_PREDICATES_H
|
||||
|
|
|
|||
|
|
@ -1,371 +0,0 @@
|
|||
// Copyright (c) 2016 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_CLIP_H
|
||||
#define CGAL_POLYGON_MESH_PROCESSING_CLIP_H
|
||||
|
||||
#include <CGAL/license/Polygon_mesh_processing/corefinement.h>
|
||||
|
||||
|
||||
#include <CGAL/Polygon_mesh_processing/corefinement.h>
|
||||
#include <CGAL/Polygon_mesh_processing/connected_components.h>
|
||||
#include <CGAL/Polygon_mesh_processing/bbox.h>
|
||||
|
||||
#include <CGAL/convex_hull_3.h>
|
||||
|
||||
namespace CGAL{
|
||||
namespace Polygon_mesh_processing {
|
||||
|
||||
namespace internal
|
||||
{
|
||||
template <class TriangleMesh,
|
||||
class Ecm,
|
||||
class NamedParameters1,
|
||||
class NamedParameters2>
|
||||
bool
|
||||
clip_open_impl( TriangleMesh& tm,
|
||||
TriangleMesh& clipper,
|
||||
Ecm ecm,
|
||||
const NamedParameters1& np_tm,
|
||||
const NamedParameters2& np_c)
|
||||
{
|
||||
// first corefine the meshes
|
||||
corefine(tm, clipper, np_tm, np_c);
|
||||
|
||||
typedef typename GetVertexPointMap<TriangleMesh,
|
||||
NamedParameters1>::type Vpm;
|
||||
typedef typename GetFaceIndexMap<TriangleMesh,
|
||||
NamedParameters1>::type Fid_map;
|
||||
typedef typename GetVertexIndexMap<TriangleMesh,
|
||||
NamedParameters1>::type Vid_map;
|
||||
|
||||
typedef boost::graph_traits<TriangleMesh> GT;
|
||||
typedef typename GetGeomTraits<TriangleMesh, NamedParameters2>::type GeomTraits;
|
||||
typedef typename GT::halfedge_descriptor halfedge_descriptor;
|
||||
typedef typename GT::face_descriptor face_descriptor;
|
||||
|
||||
Fid_map fid_map = boost::choose_param(get_param(np_tm, internal_np::face_index),
|
||||
get_property_map(boost::face_index, tm));
|
||||
Vid_map vid_map = boost::choose_param(get_param(np_tm, internal_np::vertex_index),
|
||||
get_property_map(boost::vertex_index, tm));
|
||||
Vpm vpm1 = boost::choose_param(get_param(np_tm, internal_np::vertex_point),
|
||||
get_property_map(vertex_point, tm));
|
||||
Vpm vpm_c = boost::choose_param(get_param(np_c, internal_np::vertex_point),
|
||||
get_property_map(vertex_point, clipper));
|
||||
|
||||
// init indices if needed
|
||||
helpers::init_face_indices(tm, fid_map);
|
||||
helpers::init_vertex_indices(tm, vid_map);
|
||||
|
||||
// set the connected component id of each face
|
||||
std::vector<std::size_t> face_cc(num_faces(tm), std::size_t(-1));
|
||||
std::size_t nb_cc =
|
||||
connected_components(tm,
|
||||
bind_property_maps(fid_map, make_property_map(face_cc)),
|
||||
parameters::face_index_map(fid_map).
|
||||
edge_is_constrained_map(ecm));
|
||||
|
||||
|
||||
boost::dynamic_bitset<> cc_not_handled(nb_cc);
|
||||
cc_not_handled.set();
|
||||
std::vector <std::size_t> ccs_to_remove;
|
||||
/// \todo clipper has been modified, this is not robust if inexact constructions are used
|
||||
CGAL::Side_of_triangle_mesh<TriangleMesh, GeomTraits, Vpm>
|
||||
side_of(clipper, vpm_c);
|
||||
BOOST_FOREACH(face_descriptor f, faces(tm))
|
||||
{
|
||||
std::size_t cc_id = face_cc[ get(fid_map, f) ];
|
||||
if ( !cc_not_handled.test(cc_id) ) continue;
|
||||
|
||||
halfedge_descriptor h=halfedge(f, tm);
|
||||
for(int i=0;i<3;++i)
|
||||
{
|
||||
bool no_marked_edge=true;
|
||||
BOOST_FOREACH(halfedge_descriptor h2, halfedges_around_target(h, tm))
|
||||
if ( get(ecm, edge(h2, tm)) ){
|
||||
no_marked_edge=false;
|
||||
break;
|
||||
}
|
||||
if (no_marked_edge){
|
||||
if ( side_of( get(vpm1, target(h, tm) ) ) == ON_UNBOUNDED_SIDE )
|
||||
ccs_to_remove.push_back(cc_id);
|
||||
cc_not_handled.reset(cc_id);
|
||||
break;
|
||||
}
|
||||
h=next(h, tm);
|
||||
}
|
||||
if (!cc_not_handled.any()) break;
|
||||
}
|
||||
|
||||
if (cc_not_handled.any())
|
||||
{
|
||||
///\todo handle using barycenters? won't work for coplanar faces
|
||||
}
|
||||
//now remove the cc
|
||||
remove_connected_components(tm,
|
||||
ccs_to_remove,
|
||||
bind_property_maps(fid_map, make_property_map(face_cc)),
|
||||
np_tm);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// \TODO move this to property_map.h?
|
||||
template <class Set>
|
||||
struct Constrained_edge_map
|
||||
{
|
||||
typedef boost::read_write_property_map_tag category;
|
||||
typedef bool value_type;
|
||||
typedef bool reference;
|
||||
typedef typename Set::value_type key_type;
|
||||
|
||||
Constrained_edge_map()
|
||||
: edge_set(NULL)
|
||||
{}
|
||||
|
||||
Constrained_edge_map(Set& set)
|
||||
: edge_set(&set)
|
||||
{}
|
||||
|
||||
friend bool get(const Constrained_edge_map<Set>& map, key_type k)
|
||||
{
|
||||
return map.edge_set->count(k)!=0;
|
||||
}
|
||||
|
||||
friend void put(Constrained_edge_map<Set>& map, key_type k, bool b)
|
||||
{
|
||||
if (b)
|
||||
map.edge_set->insert(k);
|
||||
else
|
||||
map.edge_set->erase(k);
|
||||
}
|
||||
private:
|
||||
Set* edge_set;
|
||||
};
|
||||
|
||||
template <class TriangleMesh,
|
||||
class NamedParameters1,
|
||||
class NamedParameters2>
|
||||
bool
|
||||
clip_open_impl( TriangleMesh& tm,
|
||||
TriangleMesh& clipper,
|
||||
boost::param_not_found,
|
||||
const NamedParameters1& np_tm,
|
||||
const NamedParameters2& np_c)
|
||||
{
|
||||
typedef typename boost::graph_traits<TriangleMesh>
|
||||
::edge_descriptor edge_descriptor;
|
||||
boost::unordered_set<edge_descriptor> constrained_edges;
|
||||
Constrained_edge_map<boost::unordered_set<edge_descriptor> >
|
||||
cst_map(constrained_edges);
|
||||
|
||||
return clip_open_impl(tm, clipper,
|
||||
cst_map,
|
||||
np_tm.edge_is_constrained_map(cst_map),
|
||||
np_c);
|
||||
}
|
||||
|
||||
} // end of internal namespace
|
||||
|
||||
#ifndef DOXYGEN_RUNNING
|
||||
|
||||
///\todo clipper const!
|
||||
/// requires face_index_map, vertex_index_map for np_tm
|
||||
/// requires face_index_map for np_c
|
||||
/// if edge_is_constrained_map is not provided in np_tm a default one is
|
||||
/// provided using boost::unordered_set<edge_descriptor>
|
||||
template <class TriangleMesh,
|
||||
class NamedParameters1,
|
||||
class NamedParameters2>
|
||||
bool
|
||||
clip( TriangleMesh& tm,
|
||||
/*const*/ TriangleMesh& clipper,
|
||||
bool close,
|
||||
const NamedParameters1& np_tm,
|
||||
const NamedParameters2& np_c)
|
||||
{
|
||||
if (close && is_closed(tm))
|
||||
return corefine_and_compute_intersection(tm, clipper, tm, np_tm, np_c);
|
||||
|
||||
return internal::clip_open_impl(tm, clipper,
|
||||
get_param(np_tm, internal_np::edge_is_constrained), np_tm, np_c);
|
||||
}
|
||||
|
||||
/// \todo document me
|
||||
template <class Plane_3,
|
||||
class TriangleMesh,
|
||||
class NamedParameters>
|
||||
Oriented_side
|
||||
clip_to_bbox(const Plane_3& plane,
|
||||
const Bbox_3& bbox,
|
||||
TriangleMesh& tm_out,
|
||||
const NamedParameters& np )
|
||||
{
|
||||
typedef typename GetGeomTraits<TriangleMesh, NamedParameters>::type Geom_traits;
|
||||
typedef typename Geom_traits::Point_3 Point_3;
|
||||
typedef typename Geom_traits::Segment_3 Segment_3;
|
||||
typedef typename GetVertexPointMap<TriangleMesh,
|
||||
NamedParameters>::type Vpm;
|
||||
|
||||
Vpm vpm_out = boost::choose_param(get_param(np, internal_np::vertex_point),
|
||||
get_property_map(boost::vertex_point, tm_out));
|
||||
|
||||
|
||||
cpp11::array<Point_3,8> corners= {{
|
||||
Point_3(bbox.xmin(),bbox.ymin(),bbox.zmin()),
|
||||
Point_3(bbox.xmin(),bbox.ymax(),bbox.zmin()),
|
||||
Point_3(bbox.xmax(),bbox.ymax(),bbox.zmin()),
|
||||
Point_3(bbox.xmax(),bbox.ymin(),bbox.zmin()),
|
||||
Point_3(bbox.xmin(),bbox.ymin(),bbox.zmax()),
|
||||
Point_3(bbox.xmin(),bbox.ymax(),bbox.zmax()),
|
||||
Point_3(bbox.xmax(),bbox.ymax(),bbox.zmax()),
|
||||
Point_3(bbox.xmax(),bbox.ymin(),bbox.zmax())
|
||||
}};
|
||||
|
||||
cpp11::array<CGAL::Oriented_side,8> orientations = {{
|
||||
plane.oriented_side(corners[0]),
|
||||
plane.oriented_side(corners[1]),
|
||||
plane.oriented_side(corners[2]),
|
||||
plane.oriented_side(corners[3]),
|
||||
plane.oriented_side(corners[4]),
|
||||
plane.oriented_side(corners[5]),
|
||||
plane.oriented_side(corners[6]),
|
||||
plane.oriented_side(corners[7])
|
||||
}};
|
||||
|
||||
std::vector<Point_3> points;
|
||||
|
||||
// look for intersections on edges
|
||||
cpp11::array<int,24> edge_indices = {{ // 2 *12 edges
|
||||
0,1, 1,2, 2,3, 3,0, // bottom face edges
|
||||
4,5, 5,6, 6,7, 7,4, // top face edges
|
||||
0,4, 1,5, 2,6, 3,7
|
||||
}};
|
||||
|
||||
for (int i=0; i<12; ++i)
|
||||
{
|
||||
int i1=edge_indices[2*i], i2=edge_indices[2*i+1];
|
||||
if (orientations[i1]==ON_ORIENTED_BOUNDARY) continue;
|
||||
if (orientations[i2]==ON_ORIENTED_BOUNDARY) continue;
|
||||
if (orientations[i1]!=orientations[i2])
|
||||
points.push_back(
|
||||
boost::get<Point_3>(
|
||||
*intersection(plane, Segment_3(corners[i1], corners[i2]) )
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
Oriented_side last_os = ON_ORIENTED_BOUNDARY;
|
||||
for (int i=0; i<8; ++i)
|
||||
if (orientations[i]!=ON_ORIENTED_BOUNDARY)
|
||||
{
|
||||
if (last_os==ON_ORIENTED_BOUNDARY)
|
||||
last_os=orientations[i];
|
||||
else
|
||||
{
|
||||
if(last_os!=orientations[i])
|
||||
{
|
||||
last_os=ON_ORIENTED_BOUNDARY;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// the intersection is the full bbox
|
||||
if (last_os!=ON_ORIENTED_BOUNDARY)
|
||||
return last_os;
|
||||
|
||||
//add points on negative side and on the plane
|
||||
for (int i=0; i<8; ++i)
|
||||
if (orientations[i]!=ON_POSITIVE_SIDE)
|
||||
points.push_back(corners[i]);
|
||||
|
||||
// take the convex hull of the points on the negative side+intersection points
|
||||
// overkill...
|
||||
Polyhedron_3<Geom_traits> P;
|
||||
CGAL::convex_hull_3(points.begin(), points.end(), P);
|
||||
copy_face_graph(P, tm_out,
|
||||
Emptyset_iterator(), Emptyset_iterator(), Emptyset_iterator(),
|
||||
get(vertex_point, P), vpm_out);
|
||||
return ON_ORIENTED_BOUNDARY;
|
||||
}
|
||||
|
||||
|
||||
// convenience overload
|
||||
template <class TriangleMesh,
|
||||
class NamedParameters1>
|
||||
bool
|
||||
clip( TriangleMesh& tm,
|
||||
/*const*/ TriangleMesh& clipper,
|
||||
bool close,
|
||||
const NamedParameters1& np_tm)
|
||||
{
|
||||
return clip(tm, clipper, close, np_tm, parameters::all_default());
|
||||
}
|
||||
|
||||
// convenience overload
|
||||
template <class TriangleMesh>
|
||||
bool
|
||||
clip( TriangleMesh& tm,
|
||||
/*const*/ TriangleMesh& clipper,
|
||||
bool close)
|
||||
{
|
||||
return clip(tm, clipper, close, parameters::all_default());
|
||||
}
|
||||
|
||||
// works only with the default point map, for more complex use cases, use
|
||||
// clip_to_bbox first and the other overload of clip with two meshes
|
||||
/// \todo document me
|
||||
template <class TriangleMesh,
|
||||
class Plane_3>
|
||||
void clip( TriangleMesh& tm,
|
||||
const Plane_3& plane,
|
||||
bool close)
|
||||
{
|
||||
if( boost::begin(faces(tm))==boost::end(faces(tm)) ) return;
|
||||
CGAL::Bbox_3 bbox = ::CGAL::Polygon_mesh_processing::bbox(tm);
|
||||
//extend the bbox a bit to avoid border cases
|
||||
double xd=(bbox.xmax()-bbox.xmin())/100;
|
||||
double yd=(bbox.ymax()-bbox.ymin())/100;
|
||||
double zd=(bbox.zmax()-bbox.zmin())/100;
|
||||
bbox=CGAL::Bbox_3(bbox.xmin()-xd, bbox.ymin()-yd, bbox.zmin()-zd,
|
||||
bbox.xmax()+xd, bbox.ymax()+yd, bbox.zmax()+zd);
|
||||
TriangleMesh clipper;
|
||||
Oriented_side os = clip_to_bbox(plane, bbox, clipper, parameters::all_default());
|
||||
|
||||
switch(os)
|
||||
{
|
||||
case ON_NEGATIVE_SIDE:
|
||||
return; // nothing to clip, the full mesh is on the negative side
|
||||
case ON_POSITIVE_SIDE:
|
||||
clear(tm); // clear the mesh that is fully on the positive side
|
||||
return;
|
||||
default:
|
||||
clip(tm, clipper, close);
|
||||
}
|
||||
}
|
||||
|
||||
#endif // !DOXYGEN_RUNNING
|
||||
|
||||
} } //end of namespace CGAL::Polygon_mesh_processing
|
||||
|
||||
#endif // CGAL_POLYGON_MESH_PROCESSING_CLIP_H
|
||||
|
|
@ -1640,10 +1640,6 @@ OutputIterator intersecting_meshes(const TriangleMeshRange& range,
|
|||
* @param tm2 second input triangulated surface mesh
|
||||
* @param polyline_output output iterator of polylines. Each polyline will be
|
||||
* given as a vector of points
|
||||
* @param throw_on_self_intersection if `true`, for each input triangle mesh,
|
||||
* the set of triangles closed to the intersection of `tm1` and `tm2` will be
|
||||
* checked for self-intersection and `CGAL::Corefinement::Self_intersection_exception`
|
||||
* will be thrown if at least one is found.
|
||||
* @param np1 optional sequence of \ref pmp_namedparameters "Named Parameters" among the ones listed below
|
||||
* @param np2 optional sequence of \ref pmp_namedparameters "Named Parameters" among the ones listed below
|
||||
*
|
||||
|
|
@ -1652,6 +1648,11 @@ OutputIterator intersecting_meshes(const TriangleMeshRange& range,
|
|||
* a property map with the points associated to the vertices of `tm1`
|
||||
* (`tm2`). The two property map types must be the same.
|
||||
* \cgalParamEnd
|
||||
* \cgalParamBegin{throw_on_self_intersection} if `true`, for each input triangle mesh,
|
||||
* the set of triangles close to the intersection of `tm1` and `tm2` will be
|
||||
* checked for self-intersection and `CGAL::Polygon_mesh_processing::Corefinement::Self_intersection_exception`
|
||||
* will be thrown if at least one is found (`np1` only).
|
||||
* \cgalParamEnd
|
||||
* \cgalNamedParamsEnd
|
||||
*
|
||||
*/
|
||||
|
|
@ -1664,9 +1665,11 @@ surface_intersection(const TriangleMesh& tm1,
|
|||
const TriangleMesh& tm2,
|
||||
OutputIterator polyline_output,
|
||||
const NamedParameters1& np1,
|
||||
const NamedParameters2& np2,
|
||||
const bool throw_on_self_intersection=false)
|
||||
const NamedParameters2& np2)
|
||||
{
|
||||
const bool throw_on_self_intersection =
|
||||
boost::choose_param(get_param(np1, internal_np::throw_on_self_intersection), false);
|
||||
|
||||
typedef typename GetVertexPointMap<TriangleMesh,
|
||||
NamedParameters1>::const_type Vpm;
|
||||
typedef typename GetVertexPointMap<TriangleMesh,
|
||||
|
|
@ -1747,16 +1750,57 @@ template <class OutputIterator,
|
|||
OutputIterator
|
||||
surface_intersection(const TriangleMesh& tm1,
|
||||
const TriangleMesh& tm2,
|
||||
OutputIterator polyline_output,
|
||||
const bool throw_on_self_intersection=false)
|
||||
OutputIterator polyline_output)
|
||||
{
|
||||
return surface_intersection(tm1, tm2, polyline_output,
|
||||
CGAL::Polygon_mesh_processing::parameters::all_default(),
|
||||
CGAL::Polygon_mesh_processing::parameters::all_default(),
|
||||
throw_on_self_intersection
|
||||
);
|
||||
CGAL::Polygon_mesh_processing::parameters::all_default());
|
||||
}
|
||||
|
||||
template <class OutputIterator,
|
||||
class TriangleMesh,
|
||||
class NamedParameters1>
|
||||
OutputIterator
|
||||
surface_intersection(const TriangleMesh& tm1,
|
||||
const TriangleMesh& tm2,
|
||||
OutputIterator polyline_output,
|
||||
const NamedParameters1& np)
|
||||
{
|
||||
return surface_intersection(tm1, tm2, polyline_output, np,
|
||||
CGAL::Polygon_mesh_processing::parameters::all_default());
|
||||
}
|
||||
|
||||
#ifndef CGAL_NO_DEPRECATED_CODE
|
||||
template <class OutputIterator,
|
||||
class TriangleMesh,
|
||||
class NamedParameters1,
|
||||
class NamedParameters2 >
|
||||
OutputIterator
|
||||
surface_intersection(const TriangleMesh& tm1,
|
||||
const TriangleMesh& tm2,
|
||||
OutputIterator polyline_output,
|
||||
const NamedParameters1& np1,
|
||||
const NamedParameters2& np2,
|
||||
const bool throw_on_self_intersection)
|
||||
{
|
||||
return surface_intersection(tm1, tm2, polyline_output,
|
||||
np1.throw_on_self_intersection(throw_on_self_intersection), np2);
|
||||
}
|
||||
|
||||
template <class OutputIterator,
|
||||
class TriangleMesh >
|
||||
OutputIterator
|
||||
surface_intersection(const TriangleMesh& tm1,
|
||||
const TriangleMesh& tm2,
|
||||
OutputIterator polyline_output,
|
||||
const bool throw_on_self_intersection)
|
||||
{
|
||||
return surface_intersection(tm1, tm2, polyline_output,
|
||||
CGAL::Polygon_mesh_processing::parameters::throw_on_self_intersection(throw_on_self_intersection),
|
||||
CGAL::Polygon_mesh_processing::parameters::all_default());
|
||||
}
|
||||
#endif
|
||||
|
||||
namespace experimental {
|
||||
template <class OutputIterator,
|
||||
class TriangleMesh >
|
||||
|
|
|
|||
|
|
@ -12,6 +12,19 @@ typedef CGAL::Surface_mesh<K::Point_3> Mesh;
|
|||
|
||||
namespace PMP = CGAL::Polygon_mesh_processing;
|
||||
|
||||
template <class TriangleMesh>
|
||||
struct My_visitor :
|
||||
public CGAL::Polygon_mesh_processing::Corefinement::Default_visitor<TriangleMesh>
|
||||
{
|
||||
void after_subface_creations(TriangleMesh&){++(*i);}
|
||||
|
||||
My_visitor()
|
||||
: i (new int(0) )
|
||||
{}
|
||||
|
||||
boost::shared_ptr<int> i;
|
||||
};
|
||||
|
||||
void test(const char* fname, std::size_t nb_polylines, std::size_t total_nb_points,
|
||||
std::size_t nb_vertices_after_autorefine, bool all_fixed, std::size_t nb_vertices_after_fix)
|
||||
{
|
||||
|
|
@ -25,6 +38,7 @@ void test(const char* fname, std::size_t nb_polylines, std::size_t total_nb_poin
|
|||
exit(EXIT_FAILURE);
|
||||
}
|
||||
input.close();
|
||||
std::size_t nb_vertices_before_autorefine = num_vertices(mesh);
|
||||
|
||||
// Testing surface_self_intersection()
|
||||
std::vector< std::vector<K::Point_3> >polylines;
|
||||
|
|
@ -36,8 +50,11 @@ void test(const char* fname, std::size_t nb_polylines, std::size_t total_nb_poin
|
|||
assert(total_nb_points == total_nb_pt);
|
||||
|
||||
// Testing autorefine()
|
||||
PMP::experimental::autorefine(mesh);
|
||||
My_visitor<Mesh> visitor;
|
||||
PMP::experimental::autorefine(mesh,
|
||||
PMP::parameters::visitor(visitor));
|
||||
assert( nb_vertices_after_autorefine==num_vertices(mesh));
|
||||
assert( (nb_vertices_before_autorefine!=nb_vertices_after_autorefine)== (*(visitor.i) != 0) );
|
||||
|
||||
// Testing autorefine_and_remove_self_intersections()
|
||||
input.open(fname);
|
||||
|
|
|
|||
|
|
@ -10,6 +10,18 @@ typedef CGAL::Exact_predicates_inexact_constructions_kernel K;
|
|||
typedef CGAL::Surface_mesh<K::Point_3> Surface_mesh;
|
||||
typedef CGAL::Polyhedron_3<K> Polyhedron_3;
|
||||
|
||||
template <class TriangleMesh>
|
||||
struct My_visitor :
|
||||
public CGAL::Polygon_mesh_processing::Corefinement::Default_visitor<TriangleMesh>
|
||||
{
|
||||
void after_subface_creations(TriangleMesh&){++(*i);}
|
||||
|
||||
My_visitor()
|
||||
: i (new int(0) )
|
||||
{}
|
||||
|
||||
boost::shared_ptr<int> i;
|
||||
};
|
||||
|
||||
void test(const char* f1, const char* f2)
|
||||
{
|
||||
|
|
@ -26,11 +38,16 @@ void test(const char* f1, const char* f2)
|
|||
assert(input);
|
||||
input >> sm2;
|
||||
input.close();
|
||||
My_visitor<Surface_mesh> sm_v;
|
||||
|
||||
CGAL::Polygon_mesh_processing::corefine(sm1, sm2);
|
||||
std::size_t nb_v_before = num_vertices(sm1) + num_vertices(sm2);
|
||||
CGAL::Polygon_mesh_processing::corefine(sm1, sm2,
|
||||
CGAL::Polygon_mesh_processing::parameters::visitor(sm_v));
|
||||
std::size_t nb_v_after = num_vertices(sm1) + num_vertices(sm2);
|
||||
|
||||
assert(sm1.is_valid());
|
||||
assert(sm2.is_valid());
|
||||
assert((*(sm_v.i) != 0) == (nb_v_before!=nb_v_after));
|
||||
|
||||
std::cout << " with Polyhedron_3\n";
|
||||
Polyhedron_3 P, Q;
|
||||
|
|
@ -41,9 +58,16 @@ void test(const char* f1, const char* f2)
|
|||
input.open(f2);
|
||||
assert(input);
|
||||
input >> Q;
|
||||
My_visitor<Polyhedron_3> sm_p;
|
||||
|
||||
CGAL::Polygon_mesh_processing::corefine(P, Q);
|
||||
nb_v_before = num_vertices(P) + num_vertices(Q);
|
||||
CGAL::Polygon_mesh_processing::corefine(P, Q,
|
||||
CGAL::Polygon_mesh_processing::parameters::visitor(sm_p));
|
||||
nb_v_after = num_vertices(P) + num_vertices(Q);
|
||||
|
||||
assert((*(sm_p.i) != 0) == (nb_v_before!=nb_v_after));
|
||||
|
||||
assert(*(sm_v.i) == *(sm_p.i));
|
||||
assert(P.is_valid());
|
||||
assert(Q.is_valid());
|
||||
}
|
||||
|
|
|
|||
|
|
@ -166,24 +166,24 @@ void test_bool_op_no_copy(
|
|||
|
||||
typedef boost::optional<Triangle_mesh*> OTM;
|
||||
OTM none;
|
||||
const CGAL::cpp11::array<OTM,4> desired_output =
|
||||
const CGAL::cpp11::array<OTM,4> output =
|
||||
reverse ? CGAL::make_array(OTM(&tm2), OTM(&tm1), none, none)
|
||||
: CGAL::make_array(OTM(&tm1), OTM(&tm2), none, none);
|
||||
PMP::boolean_operation(tm1,
|
||||
tm2,
|
||||
desired_output,
|
||||
params::edge_is_constrained_map(ecm1),
|
||||
params::edge_is_constrained_map(ecm2),
|
||||
CGAL::cpp11::make_tuple(params::edge_is_constrained_map(ecm_out_union),
|
||||
params::edge_is_constrained_map(ecm_out_inter),
|
||||
params::no_parameters(params::edge_is_constrained_map(ecm_out_union)),
|
||||
params::no_parameters(params::edge_is_constrained_map(ecm_out_union))));
|
||||
PMP::corefine_and_compute_boolean_operations(tm1,
|
||||
tm2,
|
||||
output,
|
||||
params::edge_is_constrained_map(ecm1),
|
||||
params::edge_is_constrained_map(ecm2),
|
||||
CGAL::cpp11::make_tuple(params::edge_is_constrained_map(ecm_out_union),
|
||||
params::edge_is_constrained_map(ecm_out_inter),
|
||||
params::no_parameters(params::edge_is_constrained_map(ecm_out_union)),
|
||||
params::no_parameters(params::edge_is_constrained_map(ecm_out_union))));
|
||||
|
||||
// dump_constrained_edges(*(*desired_output[0]), ecm_out_union, "out_cst_union.cgal");
|
||||
// dump_constrained_edges(*(*desired_output[1]), ecm_out_inter, "out_cst_inter.cgal");
|
||||
// dump_constrained_edges(*(*output[0]), ecm_out_union, "out_cst_union.cgal");
|
||||
// dump_constrained_edges(*(*output[1]), ecm_out_inter, "out_cst_inter.cgal");
|
||||
|
||||
assert( count_constrained_edges(*(*desired_output[0]), ecm_out_union)==838 );
|
||||
assert( count_constrained_edges(*(*desired_output[1]), ecm_out_inter)==475 );
|
||||
assert( count_constrained_edges(*(*output[0]), ecm_out_union)==838 );
|
||||
assert( count_constrained_edges(*(*output[1]), ecm_out_inter)==475 );
|
||||
}
|
||||
|
||||
void test_bool_op(Triangle_mesh tm1, Triangle_mesh tm2, bool reverse, const char* outname)
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ typedef CGAL::Exact_predicates_inexact_constructions_kernel Kernel;
|
|||
typedef CGAL::Surface_mesh<Kernel::Point_3> Surface_mesh;
|
||||
|
||||
namespace PMP = CGAL::Polygon_mesh_processing;
|
||||
namespace CFR = CGAL::Corefinement;
|
||||
namespace CFR = PMP::Corefinement;
|
||||
|
||||
//includes typedefs for Operations on polyhedra
|
||||
typedef CGAL::Polyhedron_3<Kernel> Polyhedron;
|
||||
|
|
@ -65,15 +65,15 @@ void run_boolean_operations(
|
|||
CGAL::Emptyset_iterator output_it;
|
||||
Facet_id_map P_facet_id_map, Q_facet_id_map;
|
||||
|
||||
CGAL::cpp11::array<boost::optional<Polyhedron*>, 4 > desired_output;
|
||||
CGAL::cpp11::array<boost::optional<Polyhedron*>, 4 > output;
|
||||
|
||||
desired_output[Output_builder::P_UNION_Q]=boost::make_optional( &union_ );
|
||||
desired_output[Output_builder::P_INTER_Q]=boost::make_optional( &inter );
|
||||
desired_output[Output_builder::P_MINUS_Q]=boost::make_optional( &P_minus_Q );
|
||||
desired_output[Output_builder::Q_MINUS_P]=boost::make_optional( &Q_minus_P );
|
||||
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,
|
||||
desired_output,
|
||||
output,
|
||||
Facet_id_pmap(P_facet_id_map),
|
||||
Facet_id_pmap(Q_facet_id_map) );
|
||||
Split_visitor visitor(output_builder);
|
||||
|
|
@ -169,17 +169,17 @@ void run_boolean_operations(
|
|||
|
||||
typedef boost::optional<Surface_mesh*> OSM;
|
||||
|
||||
CGAL::cpp11::array<OSM,4> desired_output;
|
||||
CGAL::cpp11::array<OSM,4> output;
|
||||
|
||||
desired_output[CFR::UNION]=OSM( &union_ );
|
||||
desired_output[CFR::INTER]=OSM( &inter );
|
||||
desired_output[CFR::TM1_MINUS_TM2]=OSM( &tm1_minus_tm2 );
|
||||
desired_output[CFR::TM2_MINUS_TM1]=OSM( &tm2_minus_tm1 );
|
||||
output[CFR::UNION]=OSM( &union_ );
|
||||
output[CFR::INTERSECTION]=OSM( &inter );
|
||||
output[CFR::TM1_MINUS_TM2]=OSM( &tm1_minus_tm2 );
|
||||
output[CFR::TM2_MINUS_TM1]=OSM( &tm2_minus_tm1 );
|
||||
|
||||
std::cout << " Vertices before " << tm1.number_of_vertices()
|
||||
<< " " << tm2.number_of_vertices() << std::endl;
|
||||
|
||||
CGAL::cpp11::array<bool,4> res = PMP::boolean_operation(tm1, tm2, desired_output);
|
||||
CGAL::cpp11::array<bool,4> res = PMP::corefine_and_compute_boolean_operations(tm1, tm2, output);
|
||||
|
||||
std::cout << " Vertices after " << tm1.number_of_vertices()
|
||||
<< " " << tm2.number_of_vertices() << std::endl;
|
||||
|
|
@ -197,7 +197,7 @@ void run_boolean_operations(
|
|||
else
|
||||
std::cout << " Union is invalid\n";
|
||||
|
||||
if ( res[CFR::INTER] ){
|
||||
if ( res[CFR::INTERSECTION] ){
|
||||
std::cout << " Intersection is a valid operation\n";
|
||||
assert(inter.is_valid());
|
||||
#ifdef CGAL_COREFINEMENT_DEBUG
|
||||
|
|
@ -239,7 +239,7 @@ void run_boolean_operations(
|
|||
if ( rc.check )
|
||||
{
|
||||
if (res[CFR::UNION]!=rc.union_res ||
|
||||
res[CFR::INTER]!=rc.inter_res ||
|
||||
res[CFR::INTERSECTION]!=rc.inter_res ||
|
||||
res[CFR::TM1_MINUS_TM2]!=rc.P_minus_Q_res ||
|
||||
res[CFR::TM2_MINUS_TM1]!=rc.Q_minus_P_res)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
|
||||
#include <CGAL/Polygon_mesh_processing/internal/clip.h>
|
||||
#include <CGAL/Polygon_mesh_processing/clip.h>
|
||||
#include <CGAL/Surface_mesh.h>
|
||||
#include <CGAL/Polyhedron_3.h>
|
||||
|
||||
|
|
@ -10,56 +10,98 @@ namespace PMP = CGAL::Polygon_mesh_processing;
|
|||
namespace params = PMP::parameters;
|
||||
|
||||
typedef CGAL::Exact_predicates_inexact_constructions_kernel K;
|
||||
typedef CGAL::Surface_mesh<K::Point_3> Triangle_mesh;
|
||||
typedef CGAL::Surface_mesh<K::Point_3> Surface_mesh;
|
||||
typedef CGAL::Polyhedron_3<K> Polyhedron;
|
||||
typedef Triangle_mesh::Property_map<Triangle_mesh::Edge_index,bool> Constrained_edge_map;
|
||||
|
||||
template <class TriangleMesh>
|
||||
void test()
|
||||
{
|
||||
// test with a clipper mesh
|
||||
TriangleMesh tm1, tm2;
|
||||
std::ifstream input("data-coref/elephant.off");
|
||||
input >> tm1;
|
||||
input.close();
|
||||
input.open("data-coref/sphere.off");
|
||||
input >> tm2;
|
||||
input.close();
|
||||
|
||||
PMP::clip(tm1, tm2,
|
||||
params::clip_volume(false)
|
||||
.face_index_map(get(CGAL::dynamic_face_property_t<std::size_t>(), tm1)),
|
||||
params::face_index_map(get(CGAL::dynamic_face_property_t<std::size_t>(), tm2))
|
||||
);
|
||||
assert(!CGAL::is_closed(tm1));
|
||||
|
||||
CGAL::clear(tm1);
|
||||
CGAL::clear(tm2);
|
||||
|
||||
input.open("data-coref/elephant.off");
|
||||
input >> tm1;
|
||||
input.close();
|
||||
input.open("data-coref/sphere.off");
|
||||
input >> tm2;
|
||||
input.close();
|
||||
|
||||
PMP::clip(tm1, tm2, params::clip_volume(true)
|
||||
.face_index_map(get(CGAL::dynamic_face_property_t<std::size_t>(), tm1)),
|
||||
params::face_index_map(get(CGAL::dynamic_face_property_t<std::size_t>(), tm2)));
|
||||
assert(CGAL::is_closed(tm1));
|
||||
|
||||
// test with a plane
|
||||
CGAL::clear(tm1);
|
||||
input.open("data-coref/cube.off");
|
||||
input >> tm1;
|
||||
input.close();
|
||||
|
||||
K::Plane_3 plane(0, 0, 1, -1);
|
||||
|
||||
PMP::clip(tm1, plane, params::clip_volume(true));
|
||||
assert(CGAL::is_closed(tm1));
|
||||
CGAL::clear(tm1);
|
||||
|
||||
input.open("data-coref/cube.off");
|
||||
input >> tm1;
|
||||
input.close();
|
||||
PMP::clip(tm1, plane, params::clip_volume(false)
|
||||
.use_compact_clipper(false));
|
||||
assert(!CGAL::is_closed(tm1));
|
||||
CGAL::clear(tm1);
|
||||
|
||||
input.open("data-coref/cube.off");
|
||||
input >> tm1;
|
||||
input.close();
|
||||
PMP::clip(tm1, plane, params::clip_volume(false)
|
||||
.use_compact_clipper(true));
|
||||
assert(CGAL::is_closed(tm1));
|
||||
CGAL::clear(tm1);
|
||||
|
||||
input.open("data-coref/cube.off");
|
||||
input >> tm1;
|
||||
input.close();
|
||||
PMP::clip(tm1, K::Plane_3(-0.236474, 0.437732, 0.867451, -0.838791), params::clip_volume(true));
|
||||
assert(CGAL::is_closed(tm1));
|
||||
assert(!CGAL::is_empty(tm1));
|
||||
CGAL::clear(tm1);
|
||||
|
||||
input.open("data-coref/cube.off");
|
||||
input >> tm1;
|
||||
input.close();
|
||||
PMP::clip(tm1, K::Plane_3(0, 0, 1, 2));
|
||||
assert(CGAL::is_empty(tm1));
|
||||
CGAL::clear(tm1);
|
||||
|
||||
input.open("data-coref/cube.off");
|
||||
input >> tm1;
|
||||
input.close();
|
||||
PMP::clip(tm1, K::Plane_3(0, 0, 1, -2));
|
||||
assert(!CGAL::is_empty(tm1));
|
||||
CGAL::clear(tm1);
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
{
|
||||
// test open clipping with Surface_mesh
|
||||
Triangle_mesh tm1, tm2;
|
||||
std::ifstream input("data-coref/elephant.off");
|
||||
input >> tm1;
|
||||
input.close();
|
||||
input.open("data-coref/sphere.off");
|
||||
input >> tm2;
|
||||
input.close();
|
||||
|
||||
Constrained_edge_map ecm1 =
|
||||
tm1.add_property_map<Triangle_mesh::Edge_index,bool>("e:cst", false).first;
|
||||
|
||||
PMP::clip(tm1, tm2, false, params::edge_is_constrained_map(ecm1));
|
||||
std::ofstream output("clipped_opened.off");
|
||||
output << tm1;
|
||||
|
||||
// test open clipping with Polyhedron
|
||||
Polyhedron P, Q;
|
||||
input.open("data-coref/elephant.off");
|
||||
input >> P;
|
||||
input.close();
|
||||
input.open("data-coref/sphere.off");
|
||||
input >> Q;
|
||||
|
||||
PMP::clip(P, Q, false,
|
||||
params::face_index_map(get(CGAL::face_external_index, P)).
|
||||
vertex_index_map(get(CGAL::vertex_external_index, P)),
|
||||
params::face_index_map(get(CGAL::face_external_index, Q)));
|
||||
assert(P.size_of_vertices() == tm1.number_of_vertices());
|
||||
}
|
||||
{
|
||||
Triangle_mesh tm1, tm2;
|
||||
std::ifstream input("data-coref/elephant.off");
|
||||
input >> tm1;
|
||||
input.close();
|
||||
input.open("data-coref/sphere.off");
|
||||
input >> tm2;
|
||||
|
||||
PMP::clip(tm1, tm2, true);
|
||||
std::ofstream output("clipped_closed.off");
|
||||
output << tm1;
|
||||
}
|
||||
test<Surface_mesh>();
|
||||
test<Polyhedron>();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@
|
|||
#include "Scene_plane_item.h"
|
||||
#include <CGAL/Three/Viewer_interface.h>
|
||||
#include <CGAL/Three/Polyhedron_demo_plugin_interface.h>
|
||||
#include <CGAL/Polygon_mesh_processing/internal/clip.h>
|
||||
#include <CGAL/Polygon_mesh_processing/clip.h>
|
||||
|
||||
#include "ui_Clip_polyhedron_plugin.h"
|
||||
#include "Viewer.h"
|
||||
|
|
@ -105,7 +105,7 @@ public :
|
|||
plane = NULL;
|
||||
//creates and link the actions
|
||||
actionClipPolyhedra = new QAction("Clip Polyhedra", mw);
|
||||
actionClipPolyhedra->setProperty("subMenuName","Operations on Polyhedra");
|
||||
actionClipPolyhedra->setProperty("subMenuName","Polygon Mesh Processing/Corefinement");
|
||||
dock_widget = new QDockWidget("Polyhedra Clipping", mw);
|
||||
dock_widget->setVisible(false); // do not show at the beginning
|
||||
ui_widget.setupUi(dock_widget);
|
||||
|
|
@ -139,28 +139,39 @@ public :
|
|||
{
|
||||
Mesh* neg_side = new Mesh(*item->face_graph());
|
||||
|
||||
CGAL::Polygon_mesh_processing::clip(*neg_side,
|
||||
plane->plane(),
|
||||
ui_widget.close_checkBox->isChecked());
|
||||
Item* new_item = new Item(neg_side);
|
||||
new_item->setName(QString("%1 on %2").arg(item->name()).arg("negative side"));
|
||||
new_item->setColor(item->color());
|
||||
new_item->setRenderingMode(item->renderingMode());
|
||||
new_item->setVisible(item->visible());
|
||||
scene->addItem(new_item);
|
||||
new_item->invalidateOpenGLBuffers();
|
||||
// part on the positive side
|
||||
Mesh* pos_side = new Mesh(*item->face_graph());
|
||||
CGAL::Polygon_mesh_processing::clip(*pos_side,
|
||||
plane->plane().opposite(),
|
||||
ui_widget.close_checkBox->isChecked());
|
||||
new_item = new Item(pos_side);
|
||||
new_item->setName(QString("%1 on %2").arg(item->name()).arg("positive side"));
|
||||
new_item->setColor(item->color());
|
||||
new_item->setRenderingMode(item->renderingMode());
|
||||
new_item->setVisible(item->visible());
|
||||
scene->addItem(new_item);
|
||||
new_item->invalidateOpenGLBuffers();
|
||||
try {
|
||||
CGAL::Polygon_mesh_processing::clip(*neg_side,
|
||||
plane->plane(),
|
||||
CGAL::Polygon_mesh_processing::parameters::clip_volume(
|
||||
ui_widget.close_checkBox->isChecked()).
|
||||
throw_on_self_intersection(true));
|
||||
Item* new_item = new Item(neg_side);
|
||||
new_item->setName(QString("%1 on %2").arg(item->name()).arg("negative side"));
|
||||
new_item->setColor(item->color());
|
||||
new_item->setRenderingMode(item->renderingMode());
|
||||
new_item->setVisible(item->visible());
|
||||
scene->addItem(new_item);
|
||||
new_item->invalidateOpenGLBuffers();
|
||||
// part on the positive side
|
||||
Mesh* pos_side = new Mesh(*item->face_graph());
|
||||
CGAL::Polygon_mesh_processing::clip(*pos_side,
|
||||
plane->plane().opposite(),
|
||||
CGAL::Polygon_mesh_processing::parameters::clip_volume(
|
||||
ui_widget.close_checkBox->isChecked()).
|
||||
throw_on_self_intersection(true));
|
||||
|
||||
new_item = new Item(pos_side);
|
||||
new_item->setName(QString("%1 on %2").arg(item->name()).arg("positive side"));
|
||||
new_item->setColor(item->color());
|
||||
new_item->setRenderingMode(item->renderingMode());
|
||||
new_item->setVisible(item->visible());
|
||||
scene->addItem(new_item);
|
||||
new_item->invalidateOpenGLBuffers();
|
||||
}
|
||||
catch(CGAL::Polygon_mesh_processing::Corefinement::Self_intersection_exception)
|
||||
{
|
||||
messages->warning(tr("The requested operation is not possible due to the presence of self-intersections in the region handled."));
|
||||
}
|
||||
}
|
||||
public Q_SLOTS:
|
||||
void on_plane_destroyed()
|
||||
|
|
@ -230,17 +241,28 @@ public Q_SLOTS:
|
|||
|
||||
if (ui_widget.clip_radioButton->isChecked())
|
||||
{
|
||||
if(sm_item)
|
||||
{
|
||||
CGAL::Polygon_mesh_processing::clip(*(sm_item->face_graph()),
|
||||
plane->plane(),
|
||||
ui_widget.close_checkBox->isChecked());
|
||||
try{
|
||||
if(sm_item)
|
||||
{
|
||||
CGAL::Polygon_mesh_processing::clip(*(sm_item->face_graph()),
|
||||
plane->plane(),
|
||||
CGAL::Polygon_mesh_processing::parameters::clip_volume(
|
||||
ui_widget.close_checkBox->isChecked()).
|
||||
throw_on_self_intersection(true));
|
||||
}
|
||||
else
|
||||
{
|
||||
CGAL::Polygon_mesh_processing::clip(*(poly_item->face_graph()),
|
||||
plane->plane(),
|
||||
CGAL::Polygon_mesh_processing::parameters::clip_volume(
|
||||
ui_widget.close_checkBox->isChecked()).
|
||||
throw_on_self_intersection(true));
|
||||
|
||||
}
|
||||
}
|
||||
else
|
||||
catch(CGAL::Polygon_mesh_processing::Corefinement::Self_intersection_exception)
|
||||
{
|
||||
CGAL::Polygon_mesh_processing::clip(*(poly_item->face_graph()),
|
||||
plane->plane(),
|
||||
ui_widget.close_checkBox->isChecked());
|
||||
messages->warning(tr("The requested operation is not possible due to the presence of self-intersections in the region handled."));
|
||||
}
|
||||
item->invalidateOpenGLBuffers();
|
||||
viewer->update();
|
||||
|
|
|
|||
|
|
@ -12,6 +12,8 @@
|
|||
using namespace CGAL::Three;
|
||||
|
||||
namespace PMP = CGAL::Polygon_mesh_processing;
|
||||
namespace params = PMP::parameters;
|
||||
|
||||
class Polyhedron_demo_corefinement_sm_plugin :
|
||||
public QObject,
|
||||
public Polyhedron_demo_plugin_helper
|
||||
|
|
@ -165,11 +167,17 @@ private:
|
|||
}
|
||||
|
||||
QApplication::setOverrideCursor(Qt::WaitCursor);
|
||||
PMP::corefine(*item1->face_graph(), *item2->face_graph());
|
||||
item1->invalidateOpenGLBuffers();
|
||||
item2->invalidateOpenGLBuffers();
|
||||
scene->itemChanged(item2);
|
||||
scene->itemChanged(item1);
|
||||
try{
|
||||
PMP::corefine(*item1->face_graph(), *item2->face_graph(), params::throw_on_self_intersection(true));
|
||||
item1->invalidateOpenGLBuffers();
|
||||
item2->invalidateOpenGLBuffers();
|
||||
scene->itemChanged(item2);
|
||||
scene->itemChanged(item1);
|
||||
}
|
||||
catch(CGAL::Polygon_mesh_processing::Corefinement::Self_intersection_exception)
|
||||
{
|
||||
messages->warning(tr("The requested operation is not possible due to the presence of self-intersections in the neighborhood of the intersection."));
|
||||
}
|
||||
// default cursor
|
||||
QApplication::restoreOverrideCursor();
|
||||
}
|
||||
|
|
@ -193,46 +201,53 @@ private:
|
|||
FaceGraph* new_poly = new FaceGraph();
|
||||
QString str_op;
|
||||
FaceGraph P, Q;
|
||||
switch(op)
|
||||
try{
|
||||
switch(op)
|
||||
{
|
||||
case CRF_UNION:
|
||||
P = *first_item->face_graph(), Q = *item->face_graph();
|
||||
if (! PMP::corefine_and_compute_union(P, Q, *new_poly, params::throw_on_self_intersection(true)) )
|
||||
{
|
||||
delete new_poly;
|
||||
messages->warning(tr("The result of the requested operation is not manifold and has not been computed."));
|
||||
// default cursor
|
||||
QApplication::restoreOverrideCursor();
|
||||
return;
|
||||
}
|
||||
str_op = "Union";
|
||||
break;
|
||||
case CRF_INTER:
|
||||
P = *first_item->polyhedron(), Q = *item->polyhedron();
|
||||
if (! PMP::corefine_and_compute_intersection(P, Q, *new_poly, params::throw_on_self_intersection(true)) )
|
||||
{
|
||||
delete new_poly;
|
||||
messages->warning(tr("The result of the requested operation is not manifold and has not been computed."));
|
||||
// default cursor
|
||||
QApplication::restoreOverrideCursor();
|
||||
return;
|
||||
}
|
||||
str_op = "Intersection";
|
||||
break;
|
||||
case CRF_MINUS_OP:
|
||||
std::swap(first_item, item);
|
||||
CGAL_FALLTHROUGH;
|
||||
case CRF_MINUS:
|
||||
P = *first_item->polyhedron(), Q = *item->polyhedron();
|
||||
if (! PMP::corefine_and_compute_difference(P, Q, *new_poly, params::throw_on_self_intersection(true)) )
|
||||
{
|
||||
delete new_poly;
|
||||
messages->warning(tr("The result of the requested operation is not manifold and has not been computed."));
|
||||
// default cursor
|
||||
QApplication::restoreOverrideCursor();
|
||||
return;
|
||||
}
|
||||
str_op = "Difference";
|
||||
}
|
||||
}
|
||||
catch(CGAL::Polygon_mesh_processing::Corefinement::Self_intersection_exception)
|
||||
{
|
||||
case CRF_UNION:
|
||||
P = *first_item->face_graph(), Q = *item->face_graph();
|
||||
if (! PMP::corefine_and_compute_union(P, Q, *new_poly) )
|
||||
{
|
||||
delete new_poly;
|
||||
messages->warning(tr("The result of the requested operation is not manifold and has not been computed."));
|
||||
// default cursor
|
||||
QApplication::restoreOverrideCursor();
|
||||
return;
|
||||
}
|
||||
str_op = "Union";
|
||||
break;
|
||||
case CRF_INTER:
|
||||
P = *first_item->polyhedron(), Q = *item->polyhedron();
|
||||
if (! PMP::corefine_and_compute_intersection(P, Q, *new_poly) )
|
||||
{
|
||||
delete new_poly;
|
||||
messages->warning(tr("The result of the requested operation is not manifold and has not been computed."));
|
||||
// default cursor
|
||||
QApplication::restoreOverrideCursor();
|
||||
return;
|
||||
}
|
||||
str_op = "Intersection";
|
||||
break;
|
||||
case CRF_MINUS_OP:
|
||||
std::swap(first_item, item);
|
||||
CGAL_FALLTHROUGH;
|
||||
case CRF_MINUS:
|
||||
P = *first_item->polyhedron(), Q = *item->polyhedron();
|
||||
if (! PMP::corefine_and_compute_difference(P, Q, *new_poly) )
|
||||
{
|
||||
delete new_poly;
|
||||
messages->warning(tr("The result of the requested operation is not manifold and has not been computed."));
|
||||
// default cursor
|
||||
QApplication::restoreOverrideCursor();
|
||||
return;
|
||||
}
|
||||
str_op = "Difference";
|
||||
messages->warning(tr("The requested operation is not possible due to the presence of self-intersections in the neighborhood of the intersection."));
|
||||
QApplication::restoreOverrideCursor();
|
||||
}
|
||||
|
||||
first_item->invalidateOpenGLBuffers();
|
||||
|
|
|
|||
|
|
@ -203,7 +203,13 @@ void Polyhedron_demo_repair_polyhedron_plugin::on_actionAutorefine_triggered(Sce
|
|||
qobject_cast<Item*>(scene->item(index));
|
||||
if (poly_item)
|
||||
{
|
||||
CGAL::Polygon_mesh_processing::experimental::autorefine(*poly_item->polyhedron());
|
||||
try{
|
||||
CGAL::Polygon_mesh_processing::experimental::autorefine(*poly_item->polyhedron());
|
||||
}
|
||||
catch(CGAL::Polygon_mesh_processing::Corefinement::Triple_intersection_exception)
|
||||
{
|
||||
messages->warning(tr("The result of the requested operation is not handled (triple intersection)."));
|
||||
}
|
||||
poly_item->invalidateOpenGLBuffers();
|
||||
Q_EMIT poly_item->itemChanged();
|
||||
}
|
||||
|
|
@ -225,11 +231,17 @@ void Polyhedron_demo_repair_polyhedron_plugin::on_actionAutorefineAndRMSelfInter
|
|||
qobject_cast<Item*>(scene->item(index));
|
||||
if (poly_item)
|
||||
{
|
||||
bool solved =
|
||||
CGAL::Polygon_mesh_processing::experimental::
|
||||
autorefine_and_remove_self_intersections(*poly_item->polyhedron());
|
||||
if (!solved)
|
||||
messages->information(tr("Self-intersection could not be removed due to non-manifold edges in the output"));
|
||||
try{
|
||||
bool solved =
|
||||
CGAL::Polygon_mesh_processing::experimental::
|
||||
autorefine_and_remove_self_intersections(*poly_item->polyhedron());
|
||||
if (!solved)
|
||||
messages->information(tr("Self-intersection could not be removed due to non-manifold edges in the output"));
|
||||
}
|
||||
catch(CGAL::Polygon_mesh_processing::Corefinement::Triple_intersection_exception)
|
||||
{
|
||||
messages->warning(tr("The result of the requested operation is not handled (triple intersection)."));
|
||||
}
|
||||
poly_item->invalidateOpenGLBuffers();
|
||||
Q_EMIT poly_item->itemChanged();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -148,9 +148,9 @@ void Polyhedron_demo_intersection_plugin::intersectionSurfaces()
|
|||
PMP::surface_intersection(*itemA->polyhedron(),
|
||||
*itemB->polyhedron(),
|
||||
std::back_inserter(new_item->polylines),
|
||||
true);
|
||||
PMP::parameters::throw_on_self_intersection(true));
|
||||
}
|
||||
catch(CGAL::Corefinement::Self_intersection_exception)
|
||||
catch(CGAL::Polygon_mesh_processing::Corefinement::Self_intersection_exception)
|
||||
{
|
||||
QMessageBox::warning((QWidget*)NULL,
|
||||
tr("Self-intersections Found"),
|
||||
|
|
|
|||
Loading…
Reference in New Issue