// Copyright (c) 2015 GeometryFactory (France). All rights reserved. // // This file is part of CGAL (www.cgal.org); you can redistribute it and/or // modify it under the terms of the GNU Lesser 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: LGPL-3.0+ // // // Author(s) : Andreas Fabri #ifndef CGAL_BOOST_GRAPH_COPY_FACE_GRAPH_H #define CGAL_BOOST_GRAPH_COPY_FACE_GRAPH_H #include #include #include #include #include #include #include #include #include namespace CGAL { namespace internal { template void copy_face_graph_impl(const SourceMesh& sm, TargetMesh& tm, Hmap hmap, V2V v2v, H2H h2h, F2F f2f, Src_vpm sm_vpm, Tgt_vpm tm_vpm ) { typedef typename boost::graph_traits::vertex_descriptor sm_vertex_descriptor; typedef typename boost::graph_traits::vertex_descriptor tm_vertex_descriptor; typedef typename boost::graph_traits::vertex_iterator tm_vertex_iterator; typedef typename boost::graph_traits::face_descriptor sm_face_descriptor; typedef typename boost::graph_traits::face_descriptor tm_face_descriptor; typedef typename boost::graph_traits::halfedge_descriptor sm_halfedge_descriptor; typedef typename boost::graph_traits::halfedge_descriptor tm_halfedge_descriptor; typedef typename boost::graph_traits::edge_descriptor sm_edge_descriptor; typedef typename boost::graph_traits::edge_descriptor tm_edge_descriptor; Cartesian_converter::value_type>::type, typename Kernel_traits::value_type>::type > conv; std::vector tm_border_halfedges; std::vector sm_border_halfedges; tm_face_descriptor tm_null_face = boost::graph_traits::null_face(); //insert halfedges and create each vertex when encountering its halfedge BOOST_FOREACH(sm_edge_descriptor sm_e, edges(sm)) { tm_edge_descriptor tm_e = add_edge(tm); sm_halfedge_descriptor sm_h = halfedge(sm_e, sm), sm_h_opp = opposite(sm_h, sm); tm_halfedge_descriptor tm_h = halfedge(tm_e, tm), tm_h_opp = opposite(tm_h, tm); // set next pointers to itself (in case previous garbage is present) set_next( tm_h, tm_h, tm ); set_next( tm_h_opp, tm_h_opp, tm ); put(hmap, sm_h, tm_h); put(hmap, sm_h_opp, tm_h_opp); *h2h++=std::make_pair(sm_h, tm_h); *h2h++=std::make_pair(sm_h_opp, tm_h_opp); if ( is_border(sm_h, sm) ){ tm_border_halfedges.push_back( tm_h ); sm_border_halfedges.push_back( sm_h ); set_face(tm_h, tm_null_face, tm); CGAL_assertion(next(tm_h, tm) == tm_h ); } if( is_border(sm_h_opp, sm) ){ tm_border_halfedges.push_back( tm_h_opp ); sm_border_halfedges.push_back( sm_h_opp ); set_face(tm_h_opp, tm_null_face, tm); CGAL_assertion(next(tm_h_opp, tm) == tm_h_opp ); } //create a copy of interior vertices only once sm_vertex_descriptor sm_h_src = source(sm_h,sm), sm_h_tgt = target(sm_h,sm); if ( halfedge(sm_h_tgt,sm)==sm_h ) { tm_vertex_descriptor tm_h_tgt = add_vertex(tm); *v2v++=std::make_pair(sm_h_tgt, tm_h_tgt); set_halfedge(tm_h_tgt, tm_h, tm); set_target(tm_h, tm_h_tgt, tm); put(tm_vpm, tm_h_tgt, conv(get(sm_vpm, sm_h_tgt))); } if ( halfedge(sm_h_src,sm)==sm_h_opp ) { tm_vertex_descriptor tm_h_src = add_vertex(tm); *v2v++=std::make_pair(sm_h_src, tm_h_src); set_halfedge(tm_h_src, tm_h_opp, tm); set_target(tm_h_opp, tm_h_src, tm); put(tm_vpm, tm_h_src, conv(get(sm_vpm, sm_h_src))); } } //create faces and connect halfedges BOOST_FOREACH(sm_face_descriptor sm_f, faces(sm)) { tm_face_descriptor tm_f = add_face(tm); *f2f++=std::make_pair(sm_f, tm_f); sm_halfedge_descriptor sm_h_i=halfedge(sm_f, sm); tm_halfedge_descriptor tm_h_prev = get(hmap, prev(sm_h_i, sm)); set_halfedge(tm_f, tm_h_prev, tm); CGAL_precondition(*halfedges_around_face(sm_h_i, sm).first == sm_h_i); BOOST_FOREACH(sm_halfedge_descriptor sm_h, halfedges_around_face(sm_h_i, sm)) { tm_halfedge_descriptor tm_h = get(hmap, sm_h); set_next(tm_h_prev, tm_h, tm); set_face(tm_h, tm_f, tm); tm_h_prev=tm_h; } } // update next/prev of tm border halfedges std::size_t nb_border_hedges = tm_border_halfedges.size(); for (std::size_t i=0; i< nb_border_hedges; ++i) { tm_halfedge_descriptor tm_h = tm_border_halfedges[i]; if ( next(tm_h, tm) != tm_h ) continue; //already set tm_halfedge_descriptor tm_h_prev = tm_h; CGAL_precondition(*halfedges_around_face(sm_border_halfedges[i], sm).first == sm_border_halfedges[i]); BOOST_FOREACH(sm_halfedge_descriptor sm_h, halfedges_around_face(next(sm_border_halfedges[i], sm), sm)) { CGAL_assertion(next(tm_h_prev, tm) == tm_h_prev); tm_h = get(hmap, sm_h); set_next(tm_h_prev, tm_h, tm); tm_h_prev=tm_h; } } // update halfedge vertex of all but the vertex halfedge for(tm_vertex_iterator vit = vertices(tm).first; vit != vertices(tm).second; ++vit) { tm_vertex_descriptor v = *vit; tm_halfedge_descriptor h = halfedge(v, tm); tm_halfedge_descriptor next_around_vertex=h; do{ next_around_vertex=opposite(next(next_around_vertex, tm), tm); set_target(next_around_vertex, v, tm); }while(h != next_around_vertex); } } template void copy_face_graph(const SourceMesh& sm, TargetMesh& tm, Tag_false, V2V v2v, H2H h2h, F2F f2f, Src_vpm sm_vpm, Tgt_vpm tm_vpm ) { typedef typename boost::graph_traits::halfedge_descriptor sm_halfedge_descriptor; typedef typename boost::graph_traits::halfedge_descriptor tm_halfedge_descriptor; boost::unordered_map hash_map(num_halfedges(sm)); copy_face_graph_impl(sm, tm, boost::make_assoc_property_map(hash_map), v2v, h2h, f2f, sm_vpm, tm_vpm); } template void copy_face_graph(const SourceMesh& sm, TargetMesh& tm, Tag_true, V2V v2v, H2H h2h, F2F f2f, Src_vpm sm_vpm, Tgt_vpm tm_vpm ) { typedef typename boost::graph_traits::halfedge_descriptor tm_halfedge_descriptor; std::vector hedges(num_halfedges(sm)); // init halfedge index map /// \TODO shall we keep that? helpers::init_halfedge_indices(const_cast(sm), get(boost::halfedge_index, sm)); copy_face_graph_impl(sm, tm, bind_property_maps(get(boost::halfedge_index, sm), make_property_map(hedges)), v2v, h2h, f2f, sm_vpm, tm_vpm); } } // end of namespace internal /*! \ingroup PkgBGLHelperFct copies a source model of `FaceListGraph` into a target model of a `FaceListGraph`. `OutputIterators` can be provided to produce a mapping between source and target elements. The target graph is not cleared. \tparam SourceMesh a model of `FaceListGraph`. The descriptor types `boost::graph_traits::%vertex_descriptor` and `boost::graph_traits::%face_descriptor` must be models of `Hashable`. \tparam TargetMesh a model of `FaceListGraph` \tparam V2V a model of `OutputIterator` accepting `std::pair` \tparam H2H a model of `OutputIterator` accepting `std::pair` \tparam F2F a model of `OutputIterator` accepting `std::pair` \tparam Src_vpm a model of `ReadablePropertyMap` with `sm_vertex_descriptor` as key \tparam Tgt_vpm a model of `WritablePropertyMap` with `tm_vertex_descriptor` as key where the prefix `sm_` and `tm_` mean belonging to the source and target mesh respectively. The types `sm_vertex_descriptor` and `sm_face_descriptor` must be models of the concept `Hashable`. \param sm the source mesh \param tm the target mesh \param v2v pairs of `vertex_descriptors` from `sm` and corresponding `vertex_descriptors` in `tm` are added to `v2v` \param h2h pairs of `halfedge_descriptors` from `sm` and corresponding `halfedge_descriptors` in `tm` are added to `h2h` \param f2f pairs of `face_descriptors` from `sm` and corresponding `face_descriptors` in `tm` are added to `f2f` \param sm_vpm vertex point map for `sm` \param tm_vpm vertex point map for `tm` The points from `sm` to `tm` are converted using `CGAL::Cartesian_converter`. `SourceKernel` and `TargetKernel` are deduced using `CGAL::Kernel_traits` from the value types of `Src_vpm` and `Tgt_vpm`. Other properties are not copied. */ #if defined(DOXYGEN_RUNNING) // Use template default arguments template ::const_type, typename Tgt_vpm = typename boost::property_map::type> void copy_face_graph(const SourceMesh& sm, TargetMesh& tm, V2V v2v = V2V(), H2H h2h = H2H(), F2F f2f = F2F(), Src_vpm sm_vpm = get(vertex_point, sm), Tgt_vpm tm_vpm = get(vertex_point, tm) ) #else // use the overloads template void copy_face_graph(const SourceMesh& sm, TargetMesh& tm, V2V v2v, H2H h2h, F2F f2f, Src_vpm sm_vpm, Tgt_vpm tm_vpm ) #endif { internal::copy_face_graph(sm, tm, CGAL::graph_has_property(), v2v, h2h, f2f, sm_vpm, tm_vpm); } #if !defined(DOXYGEN_RUNNING) template void copy_face_graph(const SourceMesh& sm, TargetMesh& tm) { copy_face_graph(sm, tm, Emptyset_iterator(), Emptyset_iterator(), Emptyset_iterator(), get(vertex_point, sm), get(vertex_point, tm)); } template void copy_face_graph(const SourceMesh& sm, TargetMesh& tm, V2V v2v) { copy_face_graph(sm, tm, v2v, Emptyset_iterator(), Emptyset_iterator(), get(vertex_point, sm), get(vertex_point, tm)); } template void copy_face_graph(const SourceMesh& sm, TargetMesh& tm, V2V v2v, H2H h2h) { copy_face_graph(sm, tm, v2v, h2h, Emptyset_iterator(), get(vertex_point, sm), get(vertex_point, tm)); } template void copy_face_graph(const SourceMesh& sm, TargetMesh& tm, V2V v2v, H2H h2h, F2F f2f) { copy_face_graph(sm, tm, v2v, h2h, f2f, get(vertex_point, sm), get(vertex_point, tm)); } template void copy_face_graph(const SourceMesh& sm, TargetMesh& tm, V2V v2v, H2H h2h, F2F f2f, Src_vpm sm_vpm) { copy_face_graph(sm, tm, v2v, h2h, f2f, sm_vpm, get(vertex_point, tm)); } #endif } // namespace CGAL #endif // CGAL_BOOST_GRAPH_COPY_FACE_GRAPH_H