Update from master

This commit is contained in:
Sébastien Loriot 2020-08-12 16:05:45 +02:00
commit 9e3345f68f
10 changed files with 615 additions and 33 deletions

View File

@ -101,6 +101,7 @@ CGAL_add_named_parameter(area_threshold_t, area_threshold, area_threshold)
CGAL_add_named_parameter(halfedges_keeper_t, halfedges_keeper, halfedges_keeper)
CGAL_add_named_parameter(volume_threshold_t, volume_threshold, volume_threshold)
CGAL_add_named_parameter(dry_run_t, dry_run, dry_run)
CGAL_add_named_parameter(do_not_modify_t, do_not_modify, do_not_modify)
// List of named parameters that we use in the package 'Surface Mesh Simplification'
CGAL_add_named_parameter(get_cost_policy_t, get_cost_policy, get_cost)

View File

@ -97,6 +97,7 @@ void test(const NamedParameters& np)
assert(get_parameter(np, CGAL::internal_np::do_lock_mesh).v == 61);
assert(get_parameter(np, CGAL::internal_np::halfedges_keeper).v == 62);
assert(get_parameter(np, CGAL::internal_np::do_simplify_border).v == 64);
assert(get_parameter(np, CGAL::internal_np::do_not_modify).v == 65);
assert(get_parameter(np, CGAL::internal_np::maximum_number_of_faces).v == 78910);
// Named parameters that we use in the package 'Surface Mesh Simplification'
@ -184,6 +185,7 @@ void test(const NamedParameters& np)
check_same_type<54>(get_parameter(np, CGAL::internal_np::use_area_smoothing));
check_same_type<55>(get_parameter(np, CGAL::internal_np::use_Delaunay_flips));
check_same_type<56>(get_parameter(np, CGAL::internal_np::use_safety_constraints));
check_same_type<65>(get_parameter(np, CGAL::internal_np::do_not_modify));
check_same_type<12340>(get_parameter(np, CGAL::internal_np::do_self_intersection_tests));
check_same_type<12341>(get_parameter(np, CGAL::internal_np::do_orientation_tests));
@ -353,6 +355,7 @@ int main()
.halfedges_keeper(A<62>(62))
.use_convex_hull(A<63>(63))
.do_simplify_border(A<64>(64))
.do_not_modify(A<65>(65))
.point_map(A<9000>(9000))
.query_point_map(A<9001>(9001))
.normal_map(A<9002>(9002))

View File

@ -23,6 +23,7 @@
#include <CGAL/Polygon_mesh_processing/triangulate_hole.h>
#include <CGAL/Polygon_mesh_processing/border.h>
#include <CGAL/Polygon_mesh_processing/repair.h>
#include <CGAL/Polygon_mesh_processing/internal/Corefinement/Generic_clip_output_builder.h>
#include <CGAL/iterator.h>
#include <CGAL/AABB_triangle_primitive.h>
@ -400,6 +401,97 @@ void split_along_edges(TriangleMesh& tm,
CGAL_assertion(is_valid_polygon_mesh(tm));
}
template <class TriangleMesh,
class NamedParameters1,
class NamedParameters2>
void
generic_clip_impl(
TriangleMesh& tm1,
TriangleMesh& tm2,
const NamedParameters1& np1,
const NamedParameters2& np2)
{
using parameters::choose_parameter;
using parameters::get_parameter;
// Vertex point maps
//for input meshes
typedef typename GetVertexPointMap<TriangleMesh,
NamedParameters1>::type Vpm;
typedef typename GetVertexPointMap<TriangleMesh,
NamedParameters2>::type Vpm2;
CGAL_USE_TYPE(Vpm2);
CGAL_assertion_code(
static const bool same_vpm = (boost::is_same<Vpm,Vpm2>::value); )
CGAL_static_assertion(same_vpm);
Vpm vpm1 = choose_parameter(get_parameter(np1, internal_np::vertex_point),
get_property_map(boost::vertex_point, tm1));
Vpm vpm2 = choose_parameter(get_parameter(np2, internal_np::vertex_point),
get_property_map(boost::vertex_point, tm2));
if (&tm1==&tm2)
{
// TODO mark all edges
return;
}
// handle case of empty meshes (isolated vertices are ignored)
if (faces(tm1).empty())
return;
// Edge is-constrained maps
//for input meshes
typedef typename internal_np::Lookup_named_param_def <
internal_np::edge_is_constrained_t,
NamedParameters1,
Corefinement::No_mark<TriangleMesh>//default
> ::type User_ecm1;
// User and internal edge is-constrained map
typedef typename boost::template property_map<TriangleMesh, CGAL::dynamic_edge_property_t<bool> >::type Algo_ecm1;
typedef Corefinement::No_mark<TriangleMesh> Ecm2;
typedef OR_property_map<Algo_ecm1, User_ecm1> Ecm1;
typedef Corefinement::Ecm_bind<TriangleMesh, Ecm1, Ecm2> Ecm_in;
Algo_ecm1 algo_ecm1 = get(CGAL::dynamic_edge_property_t<bool>(), tm1);
Ecm1 ecm1 = Ecm1(algo_ecm1, choose_parameter<User_ecm1>(get_parameter(np1, internal_np::edge_is_constrained)));
Ecm2 ecm2;
// Face index point maps
typedef typename CGAL::GetInitializedFaceIndexMap<TriangleMesh, NamedParameters1>::type FaceIndexMap1;
FaceIndexMap1 fid_map1 = get_initialized_face_index_map(tm1, np1);
const bool use_compact_clipper =
choose_parameter(get_parameter(np1, internal_np::use_compact_clipper), true);
// User visitor
typedef typename internal_np::Lookup_named_param_def <
internal_np::graph_visitor_t,
NamedParameters1,
Corefinement::Default_visitor<TriangleMesh>//default
> ::type User_visitor;
User_visitor uv(choose_parameter<User_visitor>(get_parameter(np1, internal_np::graph_visitor)));
// surface intersection algorithm call
typedef Corefinement::Generic_clip_output_builder<TriangleMesh,
Vpm,
Algo_ecm1,
FaceIndexMap1,
Default> Ob;
typedef Corefinement::Surface_intersection_visitor_for_corefinement<
TriangleMesh, Vpm, Ob, Ecm_in, User_visitor> Algo_visitor;
Ecm_in ecm_in(tm1,tm2,ecm1,ecm2);
Ob ob(tm1, tm2, vpm1, vpm2, algo_ecm1, fid_map1, use_compact_clipper);
Corefinement::Intersection_of_triangle_meshes<TriangleMesh, Vpm, Algo_visitor >
functor(tm1, tm2, vpm1, vpm2, Algo_visitor(uv,ob,ecm_in,&tm2));
functor(CGAL::Emptyset_iterator(), false, true);
}
} // end of internal namespace
/**
@ -426,6 +518,7 @@ void split_along_edges(TriangleMesh& tm,
*
*
* \cgalNamedParamsBegin
<<<<<<< HEAD
* \cgalParamNBegin{vertex_point_map}
* \cgalParamDescription{a property map associating points to the vertices of `tm` (resp. `clipper`)}
* \cgalParamType{a class model of `ReadWritePropertyMap` with `boost::graph_traits<TriangleMesh>::%vertex_descriptor`
@ -473,6 +566,14 @@ void split_along_edges(TriangleMesh& tm,
* \cgalParamExtra{This option has an effect only if a surface and not a volume is clipped,
* (i.e., if `clip_volume` is `false` or if `tm` is open).}
* \cgalParamNEnd
* \cgalParamNBegin{do_not_modify}
* \cgalParamDescription{(`np_c` only) if `true`, `clipper` will not be modified.}
* \cgalParamType{Boolean}
* \cgalParamDefault{`false`}
* \cgalParamExtra{If this option is set to `true`, `tm` is no longer required to be without self-intersection.
* Setting this option to `true` will automatically set `throw_on_self_intersection` to `false`
* and `clip_volume` to `false`.}
* \cgalParamNEnd
* \cgalNamedParamsEnd
*
* @return `true` if the output surface mesh is manifold.
@ -487,6 +588,14 @@ clip(TriangleMesh& tm,
const NamedParameters1& np_tm,
const NamedParameters2& np_c)
{
if (parameters::choose_parameter(parameters::get_parameter(np_c, internal_np::do_not_modify), false))
{
CGAL_assertion(is_closed(clipper));
internal::generic_clip_impl(tm, clipper, np_tm, np_c);
return true;
}
const bool clip_volume =
parameters::choose_parameter(parameters::get_parameter(np_tm, internal_np::clip_volume), false);
@ -710,6 +819,14 @@ bool clip(TriangleMesh& tm,
* will be thrown if at least one self-intersection is found.}
* \cgalParamType{Boolean}
* \cgalParamDefault{`false`}
* \cgalParamNBegin{do_not_modify}
* \cgalParamDescription{(`np_s` only) if `true`, `splitter` will not be modified.}
* \cgalParamType{Boolean}
* \cgalParamDefault{`false`}
* \cgalParamExtra{If this option is set to `true`, `tm` is no longer required to be without self-intersection.
* Setting this option to `true` will automatically set `throw_on_self_intersection` to `false`
* and `clip_volume` to `false`.}
* \cgalParamNEnd
* \cgalParamNEnd
*
* \cgalNamedParamsEnd
@ -742,9 +859,11 @@ void split(TriangleMesh& tm,
// create a constrained edge map and corefine input mesh with the splitter,
// and mark edges
const bool do_not_modify_splitter = choose_parameter(get_parameter(np_s, internal_np::do_not_modify), false);
PMP::corefine(tm, splitter,
CGAL::parameters::vertex_point_map(vpm_tm).edge_is_constrained_map(ecm),
CGAL::parameters::vertex_point_map(vpm_s));
CGAL::parameters::vertex_point_map(vpm_s).do_not_modify(do_not_modify_splitter));
//split mesh along marked edges
internal::split_along_edges(tm, ecm, vpm_tm);

View File

@ -695,6 +695,19 @@ corefine_and_compute_difference( TriangleMesh& tm1,
* \cgalParamDefault{`false`}
* \cgalParamExtra{`np1` only}
* \cgalParamNEnd
* \cgalParamNBegin{do_not_modify}
* \cgalParamDescription{if `true`, the corresponding mesh will not be updated.}
* \cgalParamType{Boolean}
* \cgalParamDefault{`false`}
* \cgalParamExtra{If this parameter is set to `true` for both meshes nothing will be done.
* If this option is set to `true` for one mesh,
* the other mesh is no longer required to be without self-intersection.}
* \cgalParamNEnd
* \cgalParamBegin{do_not_modify}
* If this parameter is set to `true` for both meshes nothing will be done.
* If this option is set to `true` for one mesh,
* the other mesh is no longer required to be without self-intersection.
* \cgalParamEnd
* \cgalNamedParamsEnd
*
*/
@ -710,6 +723,19 @@ corefine( TriangleMesh& tm1,
using parameters::choose_parameter;
using parameters::get_parameter;
TriangleMesh* const_mesh_ptr=nullptr;
if (choose_parameter(get_parameter(np1, internal_np::do_not_modify), false))
{
if (choose_parameter(get_parameter(np2, internal_np::do_not_modify), false))
return;
const_mesh_ptr=&tm1;
}
else
{
if (choose_parameter(get_parameter(np2, internal_np::do_not_modify), false))
const_mesh_ptr=&tm2;
}
const bool throw_on_self_intersection =
choose_parameter(get_parameter(np1, internal_np::throw_on_self_intersection), false);
@ -769,7 +795,7 @@ corefine( TriangleMesh& tm1,
Ob ob;
Ecm ecm(tm1,tm2,ecm1,ecm2);
Corefinement::Intersection_of_triangle_meshes<TriangleMesh, Vpm, Algo_visitor>
functor(tm1, tm2, vpm1, vpm2, Algo_visitor(uv,ob,ecm));
functor(tm1, tm2, vpm1, vpm2, Algo_visitor(uv,ob,ecm,const_mesh_ptr));
functor(CGAL::Emptyset_iterator(), throw_on_self_intersection, true);
}

View File

@ -0,0 +1,241 @@
// Copyright (c) 2020 GeometryFactory (France).
// All rights reserved.
//
// This file is part of CGAL (www.cgal.org).
//
// $URL$
// $Id$
// SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-Commercial
//
//
// Author(s) : Sebastien Loriot
#ifndef CGAL_POLYGON_MESH_PROCESSING_INTERNAL_GENERIC_CLIP_OUTPUT_BUILDER_H
#define CGAL_POLYGON_MESH_PROCESSING_INTERNAL_GENERIC_CLIP_OUTPUT_BUILDER_H
#include <CGAL/license/Polygon_mesh_processing/corefinement.h>
#include <CGAL/Polygon_mesh_processing/internal/Corefinement/face_graph_utils.h>
#include <CGAL/Polygon_mesh_processing/orientation.h>
#include <CGAL/Polygon_mesh_processing/connected_components.h>
#include <CGAL/Side_of_triangle_mesh.h>
#include <CGAL/property_map.h>
#include <CGAL/Default.h>
#include <boost/dynamic_bitset.hpp>
namespace CGAL {
namespace Polygon_mesh_processing {
namespace Corefinement {
namespace PMP=Polygon_mesh_processing;
namespace params=PMP::parameters;
template <class TriangleMesh,
class VertexPointMap,
class Ecm1,
class FaceIdMap1,
class Kernel_=Default>
class Generic_clip_output_builder
{
//Default typedefs
typedef typename Default::Get<
Kernel_,
typename Kernel_traits<
typename boost::property_traits<VertexPointMap>::value_type
>::Kernel >::type Kernel;
// graph_traits typedefs
typedef TriangleMesh TM;
typedef boost::graph_traits<TM> GT;
typedef typename GT::edge_descriptor edge_descriptor;
typedef typename GT::face_descriptor face_descriptor;
typedef typename GT::halfedge_descriptor halfedge_descriptor;
typedef typename GT::vertex_descriptor vertex_descriptor;
// Internal typedefs
typedef std::size_t Node_id;
typedef std::pair<Node_id,Node_id> Node_id_pair;
// to maintain a halfedge on each polyline per TriangleMesh + pair<bool,size_t>
// with first = "is the key (pair<Node_id,Node_id>) was reversed?" and
// second is the number of edges -1 in the polyline
typedef std::map< Node_id_pair,
std::pair< std::map<TriangleMesh*,
halfedge_descriptor>,
std::pair<bool,std::size_t> > >
An_edge_per_polyline_map;
typedef boost::unordered_map<vertex_descriptor, Node_id> Node_id_map;
typedef boost::unordered_map<edge_descriptor,
edge_descriptor> Edge_map;
//Data members
TriangleMesh &tm1, &tm2;
// property maps of input meshes
const VertexPointMap vpm1;
const VertexPointMap vpm2;
Ecm1 ecm1;
FaceIdMap1 fids1;
bool use_compact_clipper;
// mapping vertex to node id
Node_id_map vertex_to_node_id1;
// orientation of input surface meshes
bool is_tm2_inside_out;
// constants
const Node_id NID;
typename An_edge_per_polyline_map::iterator last_polyline;
Node_id get_node_id(vertex_descriptor v,
const Node_id_map& node_ids)
{
typename Node_id_map::const_iterator it = node_ids.find(v);
if (it == node_ids.end())
return NID;
return it->second;
}
public:
Generic_clip_output_builder(TriangleMesh& tm1,
TriangleMesh& tm2,
const VertexPointMap vpm1,
const VertexPointMap vpm2,
const Ecm1& ecm1,
FaceIdMap1 fids1,
bool use_compact_clipper)
: tm1(tm1), tm2(tm2)
, vpm1(vpm1), vpm2(vpm2)
, ecm1(ecm1)
, fids1(fids1)
, use_compact_clipper(use_compact_clipper)
, is_tm2_inside_out( !PMP::is_outward_oriented(tm2, parameters::vertex_point_map(vpm2)) )
, NID((std::numeric_limits<Node_id>::max)())
{}
// functions called by the intersection visitor
void start_new_polyline(Node_id, Node_id) {}
void add_node_to_polyline(Node_id) {}
void set_edge_per_polyline(TriangleMesh&, Node_id_pair, halfedge_descriptor){}
void set_vertex_id(vertex_descriptor v, Node_id node_id, const TriangleMesh& tm)
{
CGAL_assertion(&tm == &tm1);
vertex_to_node_id1.insert( std::make_pair(v, node_id) );
}
template <class Nodes_vector, class Mesh_to_map_node>
void operator()(
const Nodes_vector& nodes,
bool /* input_have_coplanar_faces */,
const boost::dynamic_bitset<>& /* is_node_of_degree_one */,
const Mesh_to_map_node&)
{
// The property map must be either writable or well-initialized
if( CGAL::internal::Is_writable_property_map<FaceIdMap1>::value &&
!BGL::internal::is_index_map_valid(fids1, num_faces(tm1), faces(tm1)) )
{
BGL::internal::initialize_face_index_map(fids1, tm1);
}
CGAL_assertion(BGL::internal::is_index_map_valid(fids1, num_faces(tm1), faces(tm1)));
// (1) Assign a patch id to each face indicating in which connected
// component limited by intersection edges of the surface they are.
std::vector<std::size_t> tm1_patch_ids( num_faces(tm1),NID );
std::size_t nb_patches_tm1 =
PMP::connected_components(tm1,
bind_property_maps(fids1,make_property_map(&tm1_patch_ids[0])),
params::edge_is_constrained_map(ecm1)
.face_index_map(fids1));
std::vector <std::size_t> tm1_patch_sizes(nb_patches_tm1, 0);
for(std::size_t i : tm1_patch_ids)
if(i!=NID)
++tm1_patch_sizes[i];
// Use the class Side_of_triangle_mesh to classify each patch
boost::dynamic_bitset<> patch_status_not_set_tm1(nb_patches_tm1);
patch_status_not_set_tm1.set();
typedef Side_of_triangle_mesh<TriangleMesh,
Kernel,
VertexPointMap> Inside_poly_test;
CGAL::Bounded_side in_tm2 = is_tm2_inside_out
? ON_UNBOUNDED_SIDE : ON_BOUNDED_SIDE;
Inside_poly_test inside_tm2(tm2, vpm2);
std::size_t nb_classified=0;
std::vector<std::size_t> cc_to_keep;
for(face_descriptor f : faces(tm1))
{
const std::size_t f_id = get(fids1, f);
const std::size_t patch_id = tm1_patch_ids[ f_id ];
if ( patch_status_not_set_tm1.test( patch_id ) )
{
patch_status_not_set_tm1.reset( patch_id );
halfedge_descriptor h = halfedge(f, tm1);
Node_id index_p1 = get_node_id(target(h, tm1), vertex_to_node_id1);
std::array<Node_id, 3> fnids = { index_p1, index_p1, index_p1 };
if (index_p1 != NID)
{
h=next(h, tm1);
index_p1 = get_node_id(target(h, tm1), vertex_to_node_id1);
fnids[1]=index_p1;
if (index_p1 != NID)
{
h=next(h, tm1);
index_p1 = get_node_id(target(h, tm1), vertex_to_node_id1);
fnids[2]=index_p1;
}
}
if (index_p1 != NID)
{
typename Nodes_vector::Exact_kernel ek;
typedef typename Nodes_vector::Exact_kernel::Point_3 Exact_point_3;
Exact_point_3 e_centroid = centroid(nodes.exact_node(fnids[0]),
nodes.exact_node(fnids[1]),
nodes.exact_node(fnids[2]));
Bounded_side position = inside_tm2(e_centroid, ek);
if ( position==ON_BOUNDARY )
{
if (use_compact_clipper)
{
cc_to_keep.push_back(patch_id);
}
}
else
if ( position == in_tm2 )
{
cc_to_keep.push_back(patch_id);
}
}
else
{
Bounded_side position = inside_tm2( get(vpm1, target(h, tm1)));
CGAL_assertion( position != ON_BOUNDARY);
if ( position == in_tm2 )
{
cc_to_keep.push_back(patch_id);
}
}
if ( ++nb_classified==nb_patches_tm1) break;
}
}
PMP::keep_connected_components(tm1, cc_to_keep, bind_property_maps(fids1,make_property_map(&tm1_patch_ids[0])));
}
};
} } } // CGAL::Polygon_mesh_processing::Corefinement
#undef CGAL_COREF_FUNCTION_CALL
#endif // CGAL_POLYGON_MESH_PROCESSING_INTERNAL_GENERIC_CLIP_OUTPUT_BUILDER_H

View File

@ -170,6 +170,7 @@ private:
OutputBuilder& output_builder;
EdgeMarkMapBind marks_on_edges;
bool input_with_coplanar_faces;
TriangleMesh* const_mesh_ptr;
template <class Ecm1, class Ecm2>
void call_put(Ecm_bind<TriangleMesh, Ecm1, Ecm2>& ecm,
@ -200,12 +201,13 @@ private:
// visitor public functions
public:
Surface_intersection_visitor_for_corefinement(
UserVisitor& uv, OutputBuilder& o, const EdgeMarkMapBind& emm)
UserVisitor& uv, OutputBuilder& o, const EdgeMarkMapBind& emm, TriangleMesh* const_mesh_ptr=nullptr)
: number_coplanar_vertices(0)
, user_visitor(uv)
, output_builder(o)
, marks_on_edges(emm)
, input_with_coplanar_faces(false)
, const_mesh_ptr(const_mesh_ptr)
{}
template<class Graph_node>
@ -332,34 +334,39 @@ public:
//forward to the visitor
// user_visitor.new_node_added(node_id, type, h_1, h_2, is_target_coplanar, is_source_coplanar); // NODE_VISITOR_TAG
switch(type)
if (tm2_ptr!=const_mesh_ptr)
{
case ON_FACE: //Face intersected by an edge
on_face[tm2_ptr][face(h_2,tm2)].push_back(node_id);
break;
case ON_EDGE: //Edge intersected by an edge
switch(type)
{
on_edge[tm2_ptr][edge(h_2,tm2)].push_back(node_id);
// check_node_on_non_manifold_edge(node_id,h_2,tm2);
case ON_FACE: //Face intersected by an edge
on_face[tm2_ptr][face(h_2,tm2)].push_back(node_id);
break;
case ON_EDGE: //Edge intersected by an edge
{
on_edge[tm2_ptr][edge(h_2,tm2)].push_back(node_id);
// check_node_on_non_manifold_edge(node_id,h_2,tm2);
}
break;
case ON_VERTEX:
{
//grab original vertex that is on commom intersection
mesh_to_vertices_on_inter[tm2_ptr].insert(std::make_pair(node_id,h_2));
Node_id_to_vertex& node_id_to_vertex=mesh_to_node_id_to_vertex[tm2_ptr];
if (node_id_to_vertex.size()<=node_id)
node_id_to_vertex.resize(node_id+1,Graph_traits::null_vertex());
node_id_to_vertex[node_id]=target(h_2,tm2);
all_incident_faces_got_a_node_as_vertex(h_2,node_id,*tm2_ptr);
// check_node_on_non_manifold_vertex(node_id,h_2,tm2);
output_builder.set_vertex_id(target(h_2, tm2), node_id, tm2);
}
break;
default:
return;
}
break;
case ON_VERTEX:
{
//grab original vertex that is on commom intersection
mesh_to_vertices_on_inter[tm2_ptr].insert(std::make_pair(node_id,h_2));
Node_id_to_vertex& node_id_to_vertex=mesh_to_node_id_to_vertex[tm2_ptr];
if (node_id_to_vertex.size()<=node_id)
node_id_to_vertex.resize(node_id+1,Graph_traits::null_vertex());
node_id_to_vertex[node_id]=target(h_2,tm2);
all_incident_faces_got_a_node_as_vertex(h_2,node_id,*tm2_ptr);
// check_node_on_non_manifold_vertex(node_id,h_2,tm2);
output_builder.set_vertex_id(target(h_2, tm2), node_id, tm2);
}
break;
default:
return;
}
if (tm1_ptr==const_mesh_ptr) return;
CGAL_assertion(!is_target_coplanar || !is_source_coplanar); //coplanar edge are not forwarded
if ( is_target_coplanar )
@ -624,6 +631,7 @@ public:
++it)
{
TriangleMesh& tm=*it->first;
CGAL_assertion(&tm!=const_mesh_ptr);
// Face_boundaries& face_boundaries=mesh_to_face_boundaries[&tm];
Node_to_target_of_hedge_map& nodes_to_hedge=it->second;
@ -693,6 +701,7 @@ public:
it=on_edge.begin(); it!=on_edge.end(); ++it)
{
TriangleMesh& tm=*it->first;
CGAL_assertion(&tm!=const_mesh_ptr);
const VertexPointMap& vpm=vpms[&tm];
On_edge_map& on_edge_map=it->second;
On_face_map& on_face_map=on_face[&tm];
@ -788,6 +797,7 @@ public:
it=on_face.begin(); it!=on_face.end(); ++it)
{
TriangleMesh& tm=*it->first;
CGAL_assertion(&tm!=const_mesh_ptr);
const VertexPointMap& vpm=vpms[&tm];
On_face_map& on_face_map=it->second;
Face_boundaries& face_boundaries=mesh_to_face_boundaries[&tm];

View File

@ -75,13 +75,6 @@ public:
{
typename Traits::Bounding_box bbox = m_helper.get_tree_bbox(tree);
if( point.x() < bbox.xmin() || point.x() > bbox.xmax()
|| point.y() < bbox.ymin() || point.y() > bbox.ymax()
|| point.z() < bbox.zmin() || point.z() > bbox.zmax() )
{
return ON_UNBOUNDED_SIDE;
}
//the direction of the vertical ray depends on the position of the point in the bbox
//in order to limit the expected number of nodes visited.
Ray query = ray_functor(point, vector_functor(0,0,(2*point.z() < bbox.zmax()+bbox.zmin()?-1:1)));

View File

@ -216,6 +216,60 @@ public:
}
};
//special case when ray query is from another Kernel K1 is the kernel compatible with the AABB-tree
template<typename AABBTraits, class K1, class K2, class Helper>
class K2_Ray_3_K1_Triangle_3_traversal_traits
{
//the status indicates whether the query point is strictly inside the polyhedron, and the number of intersected triangles if yes
std::pair<boost::logic::tribool,std::size_t>& m_status;
bool m_stop;
const AABBTraits& m_aabb_traits;
typedef typename AABBTraits::Primitive Primitive;
typedef CGAL::AABB_node<AABBTraits> Node;
Helper m_helper;
CGAL::Cartesian_converter<K1,K2> to_K2;
public:
K2_Ray_3_K1_Triangle_3_traversal_traits(std::pair<boost::logic::tribool,std::size_t>& status,
const AABBTraits& aabb_traits,
const Helper& h)
:m_status(status), m_stop(false), m_aabb_traits(aabb_traits), m_helper(h)
{m_status.first=true;}
bool go_further() const { return !m_stop; }
template<class Query>
void intersection(const Query& query, const Primitive& primitive)
{
Intersections::internal::r3t3_do_intersect_endpoint_position_visitor visitor;
std::pair<bool,Intersections::internal::R3T3_intersection::type> res=
Intersections::internal::do_intersect(to_K2(m_helper.get_primitive_datum(primitive, m_aabb_traits)),
query, K2(), visitor);
if (res.first){
switch (res.second){
case Intersections::internal::R3T3_intersection::CROSS_FACET:
++m_status.second;
break;
case Intersections::internal::R3T3_intersection::ENDPOINT_IN_TRIANGLE:
m_status.first=false;
m_stop=true;
break;
default:
m_status.first=boost::logic::indeterminate;
m_stop=true;
}
}
}
template<class Query>
bool do_intersect(const Query& query, const Node& node) const
{
return CGAL::do_intersect(query, m_helper.get_node_bbox(node));
}
};
}// namespace internal
}// namespace CGAL

View File

@ -242,6 +242,81 @@ public:
}
}
#ifndef DOXYGEN_RUNNING
template <class K2>
Bounded_side operator()(const typename K2::Point_3& point, const K2& k2) const
{
if(point.x() < box.xmin()
|| point.x() > box.xmax()
|| point.y() < box.ymin()
|| point.y() > box.ymax()
|| point.z() < box.zmin()
|| point.z() > box.zmax())
{
return CGAL::ON_UNBOUNDED_SIDE;
}
#ifdef CGAL_HAS_THREADS
AABB_tree_* tree_ptr =
const_cast<AABB_tree_*>(atomic_tree_ptr.load(std::memory_order_acquire));
#endif
// Lazily build the tree only when needed
if (tree_ptr==nullptr)
{
#ifdef CGAL_HAS_THREADS
CGAL_SCOPED_LOCK(tree_mutex);
tree_ptr = const_cast<AABB_tree_*>(atomic_tree_ptr.load(std::memory_order_relaxed));
#endif
CGAL_assertion(tm_ptr != nullptr && opt_vpm!=boost::none);
if (tree_ptr==nullptr)
{
tree_ptr = new AABB_tree(faces(*tm_ptr).first,
faces(*tm_ptr).second,
*tm_ptr, *opt_vpm);
const_cast<AABB_tree_*>(tree_ptr)->build();
#ifdef CGAL_HAS_THREADS
atomic_tree_ptr.store(tree_ptr, std::memory_order_release);
#endif
}
}
typedef typename Kernel_traits<Point>::Kernel K1;
typedef typename AABB_tree::AABB_traits AABB_traits;
typedef internal::Default_tree_helper<AABB_tree> Helper;
Helper helper;
typename AABB_traits::Bounding_box bbox = helper.get_tree_bbox(*tree_ptr);
static const unsigned int seed = 1340818006;
CGAL::Random rg(seed); // seed some value for make it easy to debug
Random_points_on_sphere_3<typename K2::Point_3> random_point(1.,rg);
typename K2::Construct_ray_3 ray = k2.construct_ray_3_object();
typename K2::Construct_vector_3 vector = k2.construct_vector_3_object();
do { //retry with a random ray
typename K2::Ray_3 query = ray(point, vector(CGAL::ORIGIN,*random_point++));
std::pair<boost::logic::tribool,std::size_t>
status( boost::logic::tribool(boost::logic::indeterminate), 0);
internal::K2_Ray_3_K1_Triangle_3_traversal_traits<AABB_traits, K1, K2, Helper>
traversal_traits(status, tree_ptr->traits(), helper);
tree_ptr->traversal(query, traversal_traits);
if ( !boost::logic::indeterminate(status.first) )
{
if (status.first)
return (status.second&1) == 1 ? ON_BOUNDED_SIDE : ON_UNBOUNDED_SIDE;
//otherwise the point is on the facet
return ON_BOUNDARY;
}
} while (true);
return ON_BOUNDARY; // should never be reached
}
#endif
};
} // namespace CGAL

View File

@ -71,11 +71,71 @@ void test(const char* f1, const char* f2)
assert(P.is_valid());
assert(Q.is_valid());
}
void test_no_modifications(const char* f1, const char* f2)
{
std::cout << "Corefining " << f1
<< " and " << f2 << "\n";
std::cout << " with Surface_mesh\n";
Surface_mesh sm1, sm2;
std::ifstream input(f1);
assert(input);
input >> sm1;
input.close();
input.open(f2);
assert(input);
input >> sm2;
input.close();
My_visitor<Surface_mesh> sm_v;
std::size_t nb_v_before1 = vertices(sm1).size();
std::size_t nb_v_before2 = vertices(sm2).size();
CGAL::Polygon_mesh_processing::corefine(sm1, sm2,
CGAL::parameters::visitor(sm_v),
CGAL::parameters::do_not_modify(true));
std::size_t nb_v_after1 = vertices(sm1).size();
std::size_t nb_v_after2 = vertices(sm2).size();
assert(sm1.is_valid());
assert(sm2.is_valid());
assert(nb_v_after2==nb_v_before2);
assert((*(sm_v.i) != 0) == (nb_v_before1!=nb_v_after1));
std::cout << " with Polyhedron_3\n";
Polyhedron_3 P, Q;
input.open(f1);
assert(input);
input >> P;
input.close();
input.open(f2);
assert(input);
input >> Q;
My_visitor<Polyhedron_3> sm_p;
nb_v_before1 = vertices(P).size();
nb_v_before2 = vertices(Q).size();
CGAL::Polygon_mesh_processing::corefine(P, Q,
CGAL::parameters::visitor(sm_p).do_not_modify(true));
nb_v_after1 = vertices(P).size();
nb_v_after2 = vertices(Q).size();
assert(nb_v_after1==nb_v_before1);
assert((*(sm_p.i) != 0) == (nb_v_before2!=nb_v_after2));
assert(P.is_valid());
assert(Q.is_valid());
}
int main(int argc, char** argv)
{
for(int i=0; i< (argc-1)/2;++i)
{
test(argv[2*i+1], argv[2*(i+1)]);
test(argv[2*(i+1)], argv[2*i+1]);
test_no_modifications(argv[2*(i+1)], argv[2*i+1]);
}
}