diff --git a/BGL/test/BGL/test_Prefix.h b/BGL/test/BGL/test_Prefix.h index a08af579147..da69842a562 100644 --- a/BGL/test/BGL/test_Prefix.h +++ b/BGL/test/BGL/test_Prefix.h @@ -227,7 +227,8 @@ Triangulation_hierarchy_2 t2h_data() { return build_dummy_triangulation_with_ids template struct Surface_fixture_1 { Surface_fixture_1() { - assert(read_a_mesh(m, "data/fixture1.off")); + const bool is_reading_successful = read_a_mesh(m, "data/fixture1.off"); + assert(is_reading_successful); assert(CGAL::is_valid_polygon_mesh(m)); typename boost::property_map::const_type pm = get(CGAL::vertex_point, const_cast(m)); @@ -276,7 +277,8 @@ struct Surface_fixture_1 { template struct Surface_fixture_2 { Surface_fixture_2() { - assert(read_a_mesh(m, "data/fixture2.off")); + const bool is_reading_successful = read_a_mesh(m, "data/fixture2.off"); + assert(is_reading_successful); assert(CGAL::is_valid_polygon_mesh(m)); typename boost::property_map::const_type @@ -337,7 +339,8 @@ struct Surface_fixture_2 { template struct Surface_fixture_3 { Surface_fixture_3() { - assert(read_a_mesh(m, "data/fixture3.off")); + const bool is_reading_successful = read_a_mesh(m, "data/fixture3.off"); + assert(is_reading_successful); assert(CGAL::is_valid_polygon_mesh(m)); typename boost::property_map::const_type @@ -383,7 +386,8 @@ struct Surface_fixture_3 { template struct Surface_fixture_4 { Surface_fixture_4() { - assert(read_a_mesh(m, "data/fixture4.off")); + const bool is_reading_successful = read_a_mesh(m, "data/fixture4.off"); + assert(is_reading_successful); assert(CGAL::is_valid_polygon_mesh(m)); typename boost::property_map::const_type @@ -418,7 +422,8 @@ struct Surface_fixture_4 { template struct Surface_fixture_5 { Surface_fixture_5() { - assert(read_a_mesh(m, "data/add_face_to_border.off")); + const bool is_reading_successful = read_a_mesh(m, "data/add_face_to_border.off"); + assert(is_reading_successful); assert(CGAL::is_valid_polygon_mesh(m)); typename boost::property_map::const_type @@ -448,7 +453,8 @@ struct Surface_fixture_5 { template struct Surface_fixture_6 { Surface_fixture_6() { - assert(read_a_mesh(m, "data/quad.off")); + const bool is_reading_successful = read_a_mesh(m, "data/quad.off"); + assert(is_reading_successful); assert(CGAL::is_valid_polygon_mesh(m)); typename boost::graph_traits::halfedge_descriptor h; @@ -467,7 +473,8 @@ struct Surface_fixture_6 { template struct Surface_fixture_7 { Surface_fixture_7() { - assert(read_a_mesh(m, "data/cube.off")); + const bool is_reading_successful = read_a_mesh(m, "data/cube.off"); + assert(is_reading_successful); assert(CGAL::is_valid_polygon_mesh(m)); h = *(halfedges(m).first); @@ -480,7 +487,8 @@ struct Surface_fixture_7 { template struct Surface_fixture_8 { Surface_fixture_8() { - assert(read_a_mesh(m, "data/fixture5.off")); + const bool is_reading_successful = read_a_mesh(m, "data/fixture5.off"); + assert(is_reading_successful); assert(CGAL::is_valid_polygon_mesh(m)); typename boost::property_map::const_type diff --git a/Documentation/doc/resources/1.8.14/BaseDoxyfile.in b/Documentation/doc/resources/1.8.14/BaseDoxyfile.in index a10d17a4158..455b3f2b6a4 100644 --- a/Documentation/doc/resources/1.8.14/BaseDoxyfile.in +++ b/Documentation/doc/resources/1.8.14/BaseDoxyfile.in @@ -311,12 +311,6 @@ ALIASES = "sc{1}=\1Extra: \1" \ "cgalParamNEnd= \htmlonly[block] \endhtmlonly " -# This tag can be used to specify a number of word-keyword mappings (TCL only). -# A mapping has the form "name=value". For example adding "class=itcl::class" -# will allow you to use the command class in the itcl::class meaning. - -TCL_SUBST = - # Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources # only. Doxygen will then generate output that is more tailored for C. For # instance, some of the names that are used will be different. The list of all @@ -2197,12 +2191,6 @@ EXTERNAL_GROUPS = NO EXTERNAL_PAGES = NO -# The PERL_PATH should be the absolute path and name of the perl script -# interpreter (i.e. the result of 'which perl'). -# The default file (with absolute path) is: /usr/bin/perl. - -PERL_PATH = /usr/bin/perl - #--------------------------------------------------------------------------- # Configuration options related to the dot tool #--------------------------------------------------------------------------- @@ -2216,15 +2204,6 @@ PERL_PATH = /usr/bin/perl CLASS_DIAGRAMS = NO -# You can define message sequence charts within doxygen comments using the \msc -# command. Doxygen will then run the mscgen tool (see: -# http://www.mcternan.me.uk/mscgen/)) to produce the chart and insert it in the -# documentation. The MSCGEN_PATH tag allows you to specify the directory where -# the mscgen tool resides. If left empty the tool is assumed to be found in the -# default search path. - -MSCGEN_PATH = - # You can include diagrams made with dia in doxygen documentation. Doxygen will # then run dia to produce the diagram and insert it in the documentation. The # DIA_PATH tag allows you to specify the directory where the dia binary resides. diff --git a/Installation/CHANGES.md b/Installation/CHANGES.md index b7da527361a..8b4d67730cf 100644 --- a/Installation/CHANGES.md +++ b/Installation/CHANGES.md @@ -8,6 +8,12 @@ Release History the signed distance of two points to a line, or the line passing through two given points. Corresponding functors in the model (`Compare_signed_distance_to_line_2`) are also added. +### 2D Triangulations + - Add function `split_subconstraint_graph_into_constraints()` to + `Constrained_triangulation_plus_2` to initialize the constraints + from a soup of disconnected segments that should first be split + into polylines. + Release 5.0 ----------- @@ -90,6 +96,16 @@ Release date: June 2020 does not allow any intersection, except for the configuration of two constraints having a single common endpoints, for convience. +### 3D Triangulations +- The free function `CGAL::file_input()` and the member function `CGAL::Triangulation_3::file_input()` + have been added. The first allows to load a `Triangulation_3` from an input stream, using functors to create vertices and cells. + The second is simply the member function version of the first one. + +### 3D Triangulation Data Structure +- The free function `CGAL::file_input()` and the member function `CGAL::TDS_3::file_input()` + have been added. The first allows to load a `TDS_3` from an input stream, using functors to create vertices and cells. + The second is simply the member function version of the first one. + ### dD Spatial Searching - Improved the performance of the kd-tree in some cases: diff --git a/Point_set_processing_3/include/CGAL/jet_smooth_point_set.h b/Point_set_processing_3/include/CGAL/jet_smooth_point_set.h index cbd69080e8f..126726e1659 100644 --- a/Point_set_processing_3/include/CGAL/jet_smooth_point_set.h +++ b/Point_set_processing_3/include/CGAL/jet_smooth_point_set.h @@ -28,6 +28,8 @@ #include #include +#include + #include #include @@ -193,7 +195,6 @@ jet_smooth_point_set( // basic geometric types typedef typename PointRange::iterator iterator; - typedef typename iterator::value_type value_type; typedef typename CGAL::GetPointMap::type PointMap; typedef typename Point_set_processing_3::GetK::Kernel Kernel; typedef typename GetSvdTraits::type SvdTraits; @@ -232,26 +233,42 @@ jet_smooth_point_set( Point_set_processing_3::internal::Callback_wrapper callback_wrapper (callback, nb_points); + std::vector smoothed (points.size()); + + typedef boost::zip_iterator + ::iterator> > Zip_iterator; + CGAL::for_each - (points, - [&](value_type vt) + (CGAL::make_range (boost::make_zip_iterator (boost::make_tuple (points.begin(), smoothed.begin())), + boost::make_zip_iterator (boost::make_tuple (points.end(), smoothed.end()))), + [&](const typename Zip_iterator::reference& t) { if (callback_wrapper.interrupted()) return false; - put (point_map, vt, - CGAL::internal::jet_smooth_point - (get (point_map, vt), neighbor_query, - k, - neighbor_radius, - degree_fitting, - degree_monge)); + get<1>(t) = CGAL::internal::jet_smooth_point + (get (point_map, get<0>(t)), neighbor_query, + k, + neighbor_radius, + degree_fitting, + degree_monge); ++ callback_wrapper.advancement(); return true; }); callback_wrapper.join(); + + // Finally, update points + CGAL::for_each + (CGAL::make_range (boost::make_zip_iterator (boost::make_tuple (points.begin(), smoothed.begin())), + boost::make_zip_iterator (boost::make_tuple (points.end(), smoothed.end()))), + [&](const typename Zip_iterator::reference& t) + { + put (point_map, get<0>(t), get<1>(t)); + return true; + }); } diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/clip.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/clip.h index 4fb319f11fb..2fc1347a98e 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/clip.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/clip.h @@ -596,6 +596,65 @@ bool clip(TriangleMesh& tm, return clip(tm, clipper, np, parameters::all_default()); } +/** + * \ingroup PMP_corefinement_grp + * clips `tm` by keeping the part that is inside `iso_cuboid`. + * 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. `Iso_cuboid_3` must be + * from the same %Kernel as the point of the vertex point map. + * \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`. + * 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 iso_cuboid iso-cuboid used to clip `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 `iso_cuboid` 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 `is_cuboid` + * 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 `iso_cuboid`. + */ +template +bool clip(TriangleMesh& tm, +#ifdef DOXYGEN_RUNNING + const Iso_cuboid_3& iso_cuboid, +#else + const typename GetGeomTraits::type::Iso_cuboid_3& iso_cuboid, +#endif + const NamedParameters& np) +{ + if(boost::begin(faces(tm))==boost::end(faces(tm))) return true; + TriangleMesh clipper; + + make_hexahedron(iso_cuboid[0], iso_cuboid[1], iso_cuboid[2], iso_cuboid[3], + iso_cuboid[4], iso_cuboid[5], iso_cuboid[6], iso_cuboid[7], + clipper); + triangulate_faces(clipper); + + return clip(tm, clipper, np, parameters::all_default()); +} /*! * \ingroup PMP_corefinement_grp @@ -752,24 +811,23 @@ void split(TriangleMesh& tm, //else nothing to do, no intersection. } + /** * \ingroup PMP_corefinement_grp - * clips `tm` by keeping the part that is inside `iso_cuboid`. - * 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. + * adds intersection edges of `iso_cuboid` and `tm` in `tm` and duplicates those edges. * - * \note In the current implementation it is not possible to set the vertex point map and the default will be used. `Iso_cuboid_3` must be - * from the same %Kernel as the point of the vertex point map. + * \note In the current implementation it is not possible to set the vertex point map and the default will be used. + * \note `Iso_cuboid_3` must be from the same %Kernel as the point of the vertex point map. * * \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`. + * @tparam TriangleMesh a model of `MutableFaceGraph`, `HalfedgeListGraph` and `FaceListGraph` * An internal property map for `CGAL::vertex_point_t` must be available. * * @tparam NamedParameters a sequence of \ref bgl_namedparameters "Named Parameters" * * @param tm input triangulated surface mesh - * @param iso_cuboid iso-cuboid used to clip `tm`. + * @param iso_cuboid iso-cuboid used to split `tm`. * @param np an optional sequence of \ref bgl_namedparameters "Named Parameters" among the ones listed below * * \cgalNamedParamsBegin @@ -810,29 +868,25 @@ void split(TriangleMesh& tm, * \cgalParamNEnd * * \cgalNamedParamsEnd - * - * @return `true` if the output surface mesh is manifold. - * If `false` is returned `tm` is only refined by the intersection with `iso_cuboid`. */ template -bool clip(TriangleMesh& tm, -#ifdef DOXYGEN_RUNNING - const Iso_cuboid_3& iso_cuboid, -#else - const typename GetGeomTraits::type::Iso_cuboid_3& iso_cuboid, -#endif - const NamedParameters& np) +void split(TriangleMesh& tm, + #ifdef DOXYGEN_RUNNING + const Iso_cuboid_3& iso_cuboid, + #else + const typename GetGeomTraits::type::Iso_cuboid_3& iso_cuboid, + #endif + const NamedParameters& np) { - if(boost::begin(faces(tm))==boost::end(faces(tm))) return true; - TriangleMesh clipper; + TriangleMesh splitter; make_hexahedron(iso_cuboid[0], iso_cuboid[1], iso_cuboid[2], iso_cuboid[3], - iso_cuboid[4], iso_cuboid[5], iso_cuboid[6], iso_cuboid[7], - clipper); - triangulate_faces(clipper); + iso_cuboid[4], iso_cuboid[5], iso_cuboid[6], iso_cuboid[7], + splitter); + triangulate_faces(splitter); - return clip(tm, clipper, np, parameters::all_default()); + split(tm, splitter, np, parameters::all_default()); } /// \cond SKIP_IN_MANUAL @@ -901,6 +955,13 @@ void split(TriangleMesh& tm, split(tm, plane, parameters::all_default()); } +template +void split(TriangleMesh& tm, + const typename GetGeomTraits::type::Iso_cuboid_3& iso_cuboid) +{ + split(tm, iso_cuboid, parameters::all_default()); +} + /// \endcond } } //end of namespace CGAL::Polygon_mesh_processing diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/connected_components.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/connected_components.h index aa867900cc9..2f29d3d77b5 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/connected_components.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/connected_components.h @@ -324,7 +324,8 @@ template Face_property_tag; + typedef typename boost::graph_traits::faces_size_type faces_size_type; + typedef CGAL::dynamic_face_property_t Face_property_tag; typedef typename boost::property_map::const_type Patch_ids_map; Patch_ids_map patch_ids_map = get(Face_property_tag(), pmesh); @@ -1050,23 +1051,49 @@ struct No_mark template < class PolygonMesh, class PolygonMeshRange, class FIMap, class VIMap, - class HIMap, class Ecm > + class HIMap, class Ecm, class NamedParameters > void split_connected_components_impl(FIMap fim, HIMap him, VIMap vim, Ecm ecm, PolygonMeshRange& range, - const PolygonMesh& tm) + const PolygonMesh& tm, + const NamedParameters& np) { - typename boost::template property_map< - PolygonMesh, CGAL::dynamic_face_property_t >::const_type - pidmap = get(CGAL::dynamic_face_property_t(), tm); + typedef typename boost::graph_traits::faces_size_type faces_size_type; + typedef typename internal_np::Lookup_named_param_def < + internal_np::face_patch_t, + NamedParameters, + typename boost::template property_map< + PolygonMesh, CGAL::dynamic_face_property_t >::const_type> ::type + Fpm; - int nb_patches = CGAL::Polygon_mesh_processing::connected_components( - tm, pidmap, CGAL::parameters::face_index_map(fim) - .edge_is_constrained_map(ecm)); + using parameters::choose_parameter; + using parameters::get_parameter; + using parameters::is_default_parameter; - for(int i=0; i(), tm)); + + faces_size_type nb_patches = 0; + if(is_default_parameter(get_parameter(np, internal_np::face_patch))) + { + nb_patches = CGAL::Polygon_mesh_processing::connected_components( + tm, pidmap, CGAL::parameters::face_index_map(fim) + .edge_is_constrained_map(ecm)); + } + else + { + for(const auto& f : faces(tm)) + { + faces_size_type patch_id = get(pidmap, f); + if(patch_id > nb_patches) + nb_patches = patch_id; + } + nb_patches+=1; + } + + for(faces_size_type i=0; i filter_graph(tm, i, pidmap, CGAL::parameters::face_index_map(fim) @@ -1104,6 +1131,11 @@ void split_connected_components_impl(FIMap fim, * \cgalParamNBegin{vertex_index_map} * \cgalParamDescription{a property map associating to each vertex of `pmesh` a unique index between `0` and `num_vertices(pmesh) - 1`} * \cgalParamType{a class model of `ReadablePropertyMap` with `boost::graph_traits::%vertex_descriptor` + * \cgalParamBegin{face_patch_map} a property map with the patch id's associated to the + faces of `pm`. Instance of a class model of `ReadPropertyMap`. + If not provided, an internal map will be filled with a call to + `connected_components()` with `edge_is_constrained_map()` (if provided). +* \cgalParamEnd * as key type and `std::size_t` as value type} * \cgalParamDefault{an automatically indexed internal map} * \cgalParamNEnd @@ -1144,7 +1176,7 @@ void split_connected_components(const PolygonMesh& pmesh, internal::split_connected_components_impl(CGAL::get_initialized_face_index_map(pmesh, np), CGAL::get_initialized_halfedge_index_map(pmesh, np), CGAL::get_initialized_vertex_index_map(pmesh, np), - ecm, cc_meshes, pm); + ecm, cc_meshes, pm, np); } template diff --git a/Polygon_mesh_processing/test/Polygon_mesh_processing/test_pmp_clip.cpp b/Polygon_mesh_processing/test/Polygon_mesh_processing/test_pmp_clip.cpp index 512724ba23d..a20745227b7 100644 --- a/Polygon_mesh_processing/test/Polygon_mesh_processing/test_pmp_clip.cpp +++ b/Polygon_mesh_processing/test/Polygon_mesh_processing/test_pmp_clip.cpp @@ -528,9 +528,16 @@ void test_split() std::vector meshes; PMP::split(tm1, tm2); + //try with np + typedef typename boost::graph_traits::faces_size_type faces_size_type; + typename boost::template property_map< + TriangleMesh, CGAL::dynamic_face_property_t >::type + pidmap = get(CGAL::dynamic_face_property_t(), tm1); + CGAL::Polygon_mesh_processing::connected_components( + tm1, pidmap, CGAL::parameters::all_default()); PMP::split_connected_components(tm1, meshes, - params::all_default()); + params::face_patch_map(pidmap)); CGAL_assertion(meshes.size() == 5); //if the order is not deterministc, put the num_vertices in a list and check @@ -540,6 +547,7 @@ void test_split() CGAL_assertion(num_vertices(meshes[2]) == 142); CGAL_assertion(num_vertices(meshes[3]) == 83); CGAL_assertion(num_vertices(meshes[4]) == 104); + CGAL_assertion(tm1.is_valid()); CGAL::clear(tm1); CGAL::clear(tm2); @@ -580,14 +588,59 @@ void test_split() //if the list does contain all those numbers. CGAL_assertion(num_vertices(meshes[0]) == 588); CGAL_assertion(num_vertices(meshes[1]) == 50); + CGAL_assertion(tm1.is_valid()); CGAL::clear(tm1); CGAL::clear(tm2); meshes.clear(); } +template +void test_isocuboid() +{ + TriangleMesh tm; + //closed intersection curves + std::ifstream input("data-coref/elephant.off"); + input >> tm; + + if(!input) + { + std::cerr<<"File not found. Aborting."< meshes; + K::Iso_cuboid_3 splitter(K::Point_3(-0.3, -0.45, -0.25), + K::Point_3( 0.3, 0.45, 0.25)); + PMP::split(tm, splitter); + + PMP::split_connected_components(tm, + meshes); + + CGAL_assertion(meshes.size() == 10); + //if the order is not deterministc, put the num_vertices in a list and check + //if the list does contain all those numbers. + CGAL_assertion(num_vertices(meshes[0]) == 2657); + CGAL_assertion(num_vertices(meshes[1]) == 131 ); + CGAL_assertion(num_vertices(meshes[2]) == 32 ); + CGAL_assertion(num_vertices(meshes[3]) == 123 ); + CGAL_assertion(num_vertices(meshes[4]) == 220 ); + CGAL_assertion(num_vertices(meshes[5]) == 107 ); + CGAL_assertion(num_vertices(meshes[6]) == 121 ); + CGAL_assertion(num_vertices(meshes[7]) == 56 ); + CGAL_assertion(num_vertices(meshes[8]) == 49 ); + CGAL_assertion(num_vertices(meshes[9]) == 13 ); + CGAL_assertion(tm.is_valid()); + + CGAL::clear(tm); + meshes.clear(); +} int main() { + std::cout << "Surface Mesh" << std::endl; test(); @@ -597,6 +650,9 @@ int main() std::cout << "running test_split with Surface_mesh\n"; test_split(); + std::cout << "running test_iso_cuboid with Surface_mesh\n"; + test_isocuboid(); + std::cout << "running test_split_plane with Surface_mesh\n"; test_split_plane(); @@ -606,6 +662,8 @@ int main() std::cout << "running test_split_plane with Polyhedron\n"; test_split_plane(); + std::cout << "running test_iso_cuboid with Polyhedron\n"; + test_isocuboid(); std::cout << "Done!" << std::endl; return EXIT_SUCCESS; diff --git a/Polyhedron/demo/Polyhedron/Plugins/Mesh_3/C3t3_io_plugin.cpp b/Polyhedron/demo/Polyhedron/Plugins/Mesh_3/C3t3_io_plugin.cpp index 4a85cb13b7e..d2232c11dd4 100644 --- a/Polyhedron/demo/Polyhedron/Plugins/Mesh_3/C3t3_io_plugin.cpp +++ b/Polyhedron/demo/Polyhedron/Plugins/Mesh_3/C3t3_io_plugin.cpp @@ -406,6 +406,11 @@ struct Update_vertex typedef typename Tr2::Vertex V2; typedef typename Tr2::Point Point; + V2 operator()(const V1&) + { + return V2(); + } + bool operator()(const V1& v1, V2& v2) { v2.set_point(Point(v1.point())); @@ -418,7 +423,7 @@ struct Update_vertex const Sp_index sp_index = boost::get(index); v2.set_index((std::max)(sp_index.first, sp_index.second)); } - break; + break; default:// -1, 0, 1, 3 v2.set_index(boost::get(v1.index())); } @@ -427,7 +432,9 @@ struct Update_vertex }; // end struct Update_vertex struct Update_cell { + typedef Fake_mesh_domain::Surface_patch_index Sp_index; + template bool operator()(const C1& c1, C2& c2) { c2.set_subdomain_index(c1.subdomain_index()); @@ -442,7 +449,6 @@ struct Update_cell { } }; // end struct Update_cell -#include template struct Update_vertex_from_CDT_3 { @@ -452,24 +458,28 @@ struct Update_vertex_from_CDT_3 { typedef typename Tr2::Vertex V2; typedef typename Tr2::Point Point; - bool operator()(const V1& v1, V2& v2) + V2 operator()(const V1&) + { + return V2(); + } + void operator()(const V1& v1, V2& v2) { v2.set_point(Point(v1.point())); v2.set_dimension(2); v2.set_special(false); - return true; } }; // end struct Update_vertex struct Update_cell_from_CDT_3 { + typedef Fake_mesh_domain::Surface_patch_index Sp_index; - template - bool operator()(const C1& c1, C2& c2) { + + template + void operator()(const C1& c1, C2& c2) { c2.set_subdomain_index(1); for(int i = 0; i < 4; ++i) { c2.set_surface_patch_index(i, c1.constrained_facet[i]); } - return true; } }; // end struct Update_cell @@ -500,11 +510,10 @@ try_load_a_cdt_3(std::istream& is, C3t3& c3t3) } } if(binary) CGAL::set_binary_mode(is); - if(CGAL::file_input< + if(c3t3.triangulation().file_input< Fake_CDT_3, - C3t3::Triangulation, Update_vertex_from_CDT_3, - Update_cell_from_CDT_3>(is, c3t3.triangulation())) + Update_cell_from_CDT_3>(is)) { c3t3.rescan_after_load_of_triangulation(); std::cerr << "Try load a CDT_3... DONE"; @@ -544,11 +553,10 @@ try_load_other_binary_format(std::istream& is, C3t3& c3t3) } if(binary) CGAL::set_binary_mode(is); else CGAL::set_ascii_mode(is); - std::istream& f_is = CGAL::file_input< + std::istream& f_is = c3t3.triangulation().file_input< Fake_c3t3::Triangulation, - C3t3::Triangulation, Update_vertex, - Update_cell>(is, c3t3.triangulation()); + Update_cell>(is); c3t3.rescan_after_load_of_triangulation(); return f_is.good(); diff --git a/Polyhedron/demo/Polyhedron/Scene.cpp b/Polyhedron/demo/Polyhedron/Scene.cpp index d664cb9d707..2fcc276a1ce 100644 --- a/Polyhedron/demo/Polyhedron/Scene.cpp +++ b/Polyhedron/demo/Polyhedron/Scene.cpp @@ -598,6 +598,10 @@ void Scene::renderWireScene(const QList &items, || item.renderingMode() == PointsPlusNormals || item.renderingMode() == GouraudPlusEdges) { + if(with_names) { + viewer->glClearDepthf(1.0); + viewer->glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + } viewer->setGlPointSize(2.f); item.drawEdges(viewer); } @@ -656,6 +660,10 @@ void Scene::renderPointScene(const QList &items, (item.renderingMode() == PointsPlusNormals) || (item.renderingMode() == ShadedPoints)) { + if(with_names) { + viewer->glClearDepthf(1.0); + viewer->glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + } viewer->setGlPointSize(3.0f); item.drawPoints(viewer); } diff --git a/Polyhedron/demo/Polyhedron/include/CGAL/Triangulation_file_input.h b/Polyhedron/demo/Polyhedron/include/CGAL/Triangulation_file_input.h deleted file mode 100644 index 9385f5b693f..00000000000 --- a/Polyhedron/demo/Polyhedron/include/CGAL/Triangulation_file_input.h +++ /dev/null @@ -1,103 +0,0 @@ -// Copyright (c) 1997-2010 INRIA Sophia-Antipolis (France). -// Copyright (c) 2011 GeometryFactory Sarl (France) -// All rights reserved. -// -// This file is part of CGAL (www.cgal.org); you may redistribute it under -// the terms of the Q Public License version 1.0. -// See the file LICENSE.QPL distributed with CGAL. -// -// 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$ -// -// Author(s) : Laurent Rineau -// - -// Adapted from operator>>(std::istream&, Triangulation_3&) from -// - -#ifndef CGAL_TRIANGULATION_FILE_INPUT_3_H -#define CGAL_TRIANGULATION_FILE_INPUT_3_H - -#include - -namespace CGAL { - -template -std::istream& file_input(std::istream& is, Tr2 &tr, - Update_vertex update_vertex = Update_vertex(), - Update_cell update_cell = Update_cell()) - // reads - // the dimension - // the number of finite vertices - // the non combinatorial information on vertices (point, etc) - // the number of cells - // the cells by the indices of their vertices in the preceding list - // of vertices, plus the non combinatorial information on each cell - // the neighbors of each cell by their index in the preceding list of cells - // when dimension < 3 : the same with faces of maximal dimension -{ - typedef Tr2 Triangulation; - typedef typename Triangulation::Vertex_handle Vertex_handle; - typedef typename Triangulation::Cell_handle Cell_handle; - - typedef typename Tr1::Vertex Vertex1; - typedef typename Tr1::Cell Cell1; - - tr.clear(); - tr.tds().cells().clear(); - - std::size_t n; - int d; - if(is_ascii(is)) - is >> d >> n; - else { - read(is, d); - read(is, n); - } - if(!is) return is; - tr.tds().set_dimension(d); - - std::vector< Vertex_handle > V(n+1); - V[0] = tr.infinite_vertex(); - // the infinite vertex is numbered 0 - - for (std::size_t i=1; i <= n; i++) { - V[i] = tr.tds().create_vertex(); - Vertex1 v; - if(!(is >> v)) return is; - if(!update_vertex(v, *V[i])) { - is.setstate(std::ios_base::failbit); - return is; - } - } - - std::vector< Cell_handle > C; - - std::size_t m; - tr.tds().read_cells(is, V, m, C); - - for (std::size_t j=0 ; j < m; j++) { - Cell1 c; - if(!(is >> c)) return is; - if(!update_cell(c, *(C[j]))) { - is.setstate(std::ios_base::failbit); - return is; - } - } - - CGAL_triangulation_assertion( tr.is_valid(false) ); - return is; -} - -} // end namespace CGAL - -#endif // CGAL_TRIANGULATION_FILE_INPUT_3_H diff --git a/Property_map/doc/Property_map/Doxyfile.in b/Property_map/doc/Property_map/Doxyfile.in index 2167dbca4fe..a079ae055f4 100644 --- a/Property_map/doc/Property_map/Doxyfile.in +++ b/Property_map/doc/Property_map/Doxyfile.in @@ -3,4 +3,4 @@ PROJECT_NAME = "CGAL ${CGAL_DOC_VERSION} - CGAL and Boost Property Maps" INPUT += ${CGAL_PACKAGE_INCLUDE_DIR}/CGAL/property_map.h EXCLUDE += ${CGAL_PACKAGE_INCLUDE_DIR}/CGAL/Dynamic_property_map.h -EXAMPLE_PATH = ${CGAL_Point_set_processing_3_EXAMPLE_DIR} +EXAMPLE_PATH += ${CGAL_Point_set_processing_3_EXAMPLE_DIR} diff --git a/Property_map/doc/Property_map/Property_map.txt b/Property_map/doc/Property_map/Property_map.txt index fef8999a0c6..d2ecf66d1df 100644 --- a/Property_map/doc/Property_map/Property_map.txt +++ b/Property_map/doc/Property_map/Property_map.txt @@ -6,6 +6,8 @@ namespace CGAL { \anchor chapterProperty_map +\cgalAutoToc + \authors Andreas Fabri and Laurent Saboret \section Property_mapA A Short Introduction to the Boost Property Maps Library @@ -55,6 +57,20 @@ The following example reads a point set from an input file and writes it to a fi The following example reads a point set in the `xyz` format and computes the average spacing. %Index, position and color are stored in a tuple and accessed through property maps. \cgalExample{Point_set_processing_3/average_spacing_example.cpp} +\section Property_mapCustom Writing Custom Property Maps + +Property maps are especially useful when using predefined data +structures that are not part of the \cgal library: algorithms written +with property maps can be called on these data structures provided the +user writes the required property maps, without the need to create +deep copies of potentially large data into \cgal formats. + +The following example shows how to write a readable point map and a +read-write normal map to run \cgal normal estimation and orientation +algorithm on raw `double` arrays: +\cgalExample{Property_map/custom_property_map.cpp} + + */ } /* namespace CGAL */ diff --git a/Property_map/doc/Property_map/examples.txt b/Property_map/doc/Property_map/examples.txt index fe5b9e2f71c..30870650f01 100644 --- a/Property_map/doc/Property_map/examples.txt +++ b/Property_map/doc/Property_map/examples.txt @@ -2,4 +2,5 @@ \example Point_set_processing_3/remove_outliers_example.cpp \example Point_set_processing_3/read_write_xyz_point_set_example.cpp \example Point_set_processing_3/average_spacing_example.cpp +\example Property_map/custom_property_map.cpp */ diff --git a/Property_map/examples/Property_map/CMakeLists.txt b/Property_map/examples/Property_map/CMakeLists.txt index 9b183930b64..d5717d3f5d2 100644 --- a/Property_map/examples/Property_map/CMakeLists.txt +++ b/Property_map/examples/Property_map/CMakeLists.txt @@ -32,4 +32,10 @@ endif() create_single_source_cgal_program( "dynamic_properties.cpp" ) +find_package(Eigen3 3.1.0) #(requires 3.1.0 or greater) +if (EIGEN3_FOUND) + create_single_source_cgal_program( "custom_property_map.cpp" ) + CGAL_target_use_Eigen(custom_property_map) +endif() + diff --git a/Property_map/examples/Property_map/custom_property_map.cpp b/Property_map/examples/Property_map/custom_property_map.cpp new file mode 100644 index 00000000000..540bec3cd2d --- /dev/null +++ b/Property_map/examples/Property_map/custom_property_map.cpp @@ -0,0 +1,112 @@ +#include +#include +#include +#include + +using Kernel = CGAL::Exact_predicates_inexact_constructions_kernel; +using Point_3 = Kernel::Point_3; +using Vector_3 = Kernel::Vector_3; +using Generator = CGAL::Random_points_on_sphere_3; + +// Example of readable property map to get CGAL::Point_3 objects from +// 3 coordinate arrays +struct Custom_point_map +{ + using key_type = std::size_t; // The iterator's value type is an index + using value_type = Point_3; // The object manipulated by the algorithm is a Point_3 + using reference = Point_3; // The object does not exist in memory, so there's no reference + using category = boost::readable_property_map_tag; // The property map is only used for reading + + double *x, *y, *z; + + Custom_point_map (double* x = nullptr, double* y = nullptr, double* z = nullptr) + : x(x), y(y), z(z) { } + + // The get() function returns the object expected by the algorithm (here, Point_3) + friend Point_3 get (const Custom_point_map& map, std::size_t idx) + { + return Point_3 (map.x[idx], map.y[idx], map.z[idx]); + } +}; + +// Example of read-write property map to get CGAL::Vector_3 objects from +// a buffer array and put CGAL::Vector_3 values in this buffer +struct Custom_normal_map +{ + using key_type = std::size_t; // The iterator's value type is an index + using value_type = Vector_3; // The object manipulated by the algorithm is a Vector_3 + using reference = Vector_3; // The object does not exist in memory, so there's no reference + using category = boost::read_write_property_map_tag; // The property map is used both + // for reading and writing data + double *buffer; + + Custom_normal_map (double* buffer = nullptr) + : buffer (buffer) { } + + // The get() function returns the object expected by the algorithm (here, Vector_3) + friend Vector_3 get (const Custom_normal_map& map, std::size_t idx) + { + return Vector_3 (map.buffer[idx * 3 ], + map.buffer[idx * 3 + 1], + map.buffer[idx * 3 + 2]); + } + + // The put() function updated the user's data structure from the + // object handled by the algorithm (here Vector_3) + friend void put (const Custom_normal_map& map, std::size_t idx, const Vector_3& vector_3) + { + map.buffer[idx * 3 ] = vector_3.x(); + map.buffer[idx * 3 + 1] = vector_3.y(); + map.buffer[idx * 3 + 2] = vector_3.z(); + } +}; + + +int main() +{ + constexpr std::size_t nb_points = 1000; + + // in this example, points are stored as separate coordinate arrays + double x[nb_points]; + double y[nb_points]; + double z[nb_points]; + + // generate random points + Generator generator; + for (std::size_t i = 0; i < nb_points; ++ i) + { + Point_3 p = *(generator ++ ); + x[i] = p.x(); + y[i] = p.y(); + z[i] = p.z(); + } + + // normals are stored as a contiguous double array + double normals[3 *nb_points]; + + // we use a vector of indices to access arrays + std::vector indices; + indices.reserve (nb_points); + for (std::size_t i = 0; i < nb_points; ++ i) + indices.push_back(i); + + // estimate and orient normals using directly user's data structure + // instead of creating deep copies using Point_3 and Vector_3 + CGAL::jet_estimate_normals + (indices, 12, + CGAL::parameters::point_map (Custom_point_map(x,y,z)). + normal_map (Custom_normal_map(normals))); + + CGAL::mst_orient_normals + (indices, 12, + CGAL::parameters::point_map (Custom_point_map(x,y,z)). + normal_map (Custom_normal_map(normals))); + + // Display first 10 points+normals + for (std::size_t i = 0; i < 10; ++ i) + std::cerr << "Point(" << i << ") = " << x[i] << " " << y[i] << " " << z[i] + << "\tNormal(" << i << ") = " + << normals[3*i] << " " << normals[3*i+1] << " " << normals[3*i+2] << std::endl; + + return EXIT_SUCCESS; +} diff --git a/Spatial_searching/include/CGAL/Euclidean_distance.h b/Spatial_searching/include/CGAL/Euclidean_distance.h index c10be1a806c..60fde16c20b 100644 --- a/Spatial_searching/include/CGAL/Euclidean_distance.h +++ b/Spatial_searching/include/CGAL/Euclidean_distance.h @@ -132,7 +132,7 @@ namespace CGAL { // Note: the concept SearchTraits specifies that Cartesian_const_iterator_d // must be a random-access iterator typename SearchTraits::Cartesian_const_iterator_d qe_minus_5 = qe; - std::advance(qe, -5); + std::advance(qe_minus_5, -5); for (;;) { FT diff = (*qit) - (*it_coord_begin); diff --git a/TDS_3/doc/TDS_3/Concepts/TriangulationDataStructure_3.h b/TDS_3/doc/TDS_3/Concepts/TriangulationDataStructure_3.h index 8cdc8c934d2..081f9f98513 100644 --- a/TDS_3/doc/TDS_3/Concepts/TriangulationDataStructure_3.h +++ b/TDS_3/doc/TDS_3/Concepts/TriangulationDataStructure_3.h @@ -254,10 +254,10 @@ otherwise `Vertex_handle()` is returned. - A model of `ConvertVertex` must provide two operator()'s that are responsible for converting the source vertex `v_src` into the target vertex: - `Vertex operator()(const TDS_src::Vertex& v_src) const;` This operator is used to create the vertex from `v_src`. - - `void operator()(const TDS_src::Vertex& v_src, Vertex& v_tgt) const;` This operator is meant to be used in case heavy data should transferred to `v_tgt`. + - `void operator()(const TDS_src::Vertex& v_src, Vertex& v_tgt) const;` This operator is meant to be used in case heavy data should be transferred to `v_tgt`. - A model of ConvertCell must provide two operator()'s that are responsible for converting the source cell `c_src` into the target cell: - `Cell operator()(const TDS_src::Cell& c_src) const;` This operator is used to create the cell from `c_src`. - - `void operator()(const TDS_src::Cell& c_src, Cell& c_tgt) const;` This operator is meant to be used in case heavy data should transferred to `c_tgt`. + - `void operator()(const TDS_src::Cell& c_src, Cell& c_tgt) const;` This operator is meant to be used in case heavy data should be transferred to `c_tgt`. \pre The optional argument `v` is a vertex of `tds_src` or is `Vertex_handle()`. */ @@ -1024,17 +1024,52 @@ a precise indication on the kind of invalidity encountered. \cgalDebugEnd */ bool is_valid(Cell_handle c, bool verbose = false) const; +/// @} + +/// \name I/O +/// @{ /*! + \ingroup PkgIOTDS3 Reads a combinatorial triangulation from `is` and assigns it to `tds` */ istream& operator>> (istream& is, TriangulationDataStructure_3 & tds); -/*! +/*! \ingroup PkgIOTDS3 Writes `tds` into the stream `os` */ ostream& operator<< (ostream& os, const TriangulationDataStructure_3 & tds); +/*! \ingroup PkgIOTDS3 +The tds streamed in `is`, of original type `TDS_src`, is written into the triangulation data structure. As the vertex and cell + types might be different and incompatible, the creation of new cells and vertices +is made thanks to the functors `convert_vertex` and `convert_cell`, that convert +vertex and cell types. For each vertex `v_src` in `is`, the corresponding +vertex `v_tgt` in the triangulation data structure is a copy of the vertex returned by `convert_vertex(v_src)`. +The same operations are done for cells with the functor convert_cell, except cells +in the triangulation data structure are created using the default constructor, and then filled with the data +contained in the stream. + + - A model of `ConvertVertex` must provide two `operator()`s that are responsible + for converting the source vertex `v_src` into the target vertex: + - `Vertex operator()(const TDS_src::Vertex& v_src) const;` This operator is +used to create the vertex from `v_src`. + - `void operator()(const TDS_src::Vertex& v_src, Vertex& v_tgt) const;` This + operator is meant to be used in case heavy data should be transferred to `v_tgt`. + - A model of ConvertCell must provide an operator() that is responsible for +converting the source cell `c_src` into the target cell: + - `void operator()(const TDS_src::Cell& c_src, Cell& c_tgt) const;` This operator + is meant to be used in case heavy data should be transferred to `c_tgt`. + +\note The triangulation data structure contained in `is` can be obtained with the `operator>>` of a `TriangulationDataStructure_3`. +*/ +template +std::istream& file_input(std::istream& is, + ConvertVertex convert_vertex, + ConvertCell convert_cell); + /// @} }; /* end TriangulationDataStructure_3 */ diff --git a/TDS_3/doc/TDS_3/PackageDescription.txt b/TDS_3/doc/TDS_3/PackageDescription.txt index ee9b560977d..34f5d1acb1c 100644 --- a/TDS_3/doc/TDS_3/PackageDescription.txt +++ b/TDS_3/doc/TDS_3/PackageDescription.txt @@ -6,6 +6,8 @@ /// \defgroup PkgTDS3Classes Classes /// \ingroup PkgTDS3Ref +/// \defgroup PkgIOTDS3 I/O for a Triangulation_data_structure_3 +/// \ingroup PkgTDS3Ref /*! \addtogroup PkgTDS3Ref \todo check generated documentation diff --git a/TDS_3/include/CGAL/Triangulation_data_structure_3.h b/TDS_3/include/CGAL/Triangulation_data_structure_3.h index 968da3301ca..6e154098cb5 100644 --- a/TDS_3/include/CGAL/Triangulation_data_structure_3.h +++ b/TDS_3/include/CGAL/Triangulation_data_structure_3.h @@ -189,6 +189,7 @@ public: return hf ^ 419 * hs; } + }; static const int maximal_nb_of_facets_of_small_hole = 128; @@ -1521,6 +1522,73 @@ public: return s <= maximal_nb_of_facets_of_small_hole; } + //IO + template + std::istream& file_input(std::istream& is, + ConvertVertex convert_vertex = ConvertVertex(), + ConvertCell convert_cell = ConvertCell()) + { + // reads + // the dimension + // the number of finite vertices + // the non combinatorial information on vertices (point, etc) + // the number of cells + // the cells by the indices of their vertices in the preceding list + // of vertices, plus the non combinatorial information on each cell + // the neighbors of each cell by their index in the preceding list of cells + // when dimension < 3 : the same with faces of maximal dimension + + // If this is used for a TDS, the vertices are processed from 0 to n. + // Else, we make V[0] the infinite vertex and work from 1 to n+1. + + typedef typename Tds::Vertex_handle Vertex_handle; + typedef typename Tds::Cell_handle Cell_handle; + + typedef typename TDS_src::Vertex Vertex1; + typedef typename TDS_src::Cell Cell1; + clear(); + cells().clear(); + + std::size_t n; + int d; + if(is_ascii(is)) + is >> d >> n; + else { + read(is, d); + read(is, n); + } + if(!is) return is; + set_dimension(d); + + std::size_t V_size = n; + std::vector< Vertex_handle > V(V_size); + + // the infinite vertex is numbered 0 + for (std::size_t i=0 ; i < V_size; ++i) { + Vertex1 v; + if(!(is >> v)) return is; + Vertex_handle vh=create_vertex( convert_vertex(v) ); + V[i] = vh; + convert_vertex(v, *V[i]); + } + + std::vector< Cell_handle > C; + + std::size_t m; + read_cells(is, V, m, C); + + for (std::size_t j=0 ; j < m; j++) { + Cell1 c; + if(!(is >> c)) return is; + convert_cell(c, *C[j]); + } + + CGAL_triangulation_assertion(is_valid(false)); + return is; + } + private: // Change the orientation of the cell by swapping indices 0 and 1. @@ -1550,6 +1618,7 @@ private: // counts but does not check bool count_cells(size_type &i, bool verbose = false, int level = 0) const; // counts AND checks the validity + }; #ifdef CGAL_TDS_USE_RECURSIVE_CREATE_STAR_3 diff --git a/TDS_3/test/TDS_3/CMakeLists.txt b/TDS_3/test/TDS_3/CMakeLists.txt index 0253c40548c..b21488fe951 100644 --- a/TDS_3/test/TDS_3/CMakeLists.txt +++ b/TDS_3/test/TDS_3/CMakeLists.txt @@ -10,6 +10,7 @@ if ( CGAL_FOUND ) find_package( TBB QUIET ) create_single_source_cgal_program( "test_triangulation_tds_3.cpp" ) + create_single_source_cgal_program( "test_io_tds3.cpp" ) if(TBB_FOUND) CGAL_target_use_TBB(test_triangulation_tds_3) endif() diff --git a/TDS_3/test/TDS_3/test_io_tds3.cpp b/TDS_3/test/TDS_3/test_io_tds3.cpp new file mode 100644 index 00000000000..10bfcedc030 --- /dev/null +++ b/TDS_3/test/TDS_3/test_io_tds3.cpp @@ -0,0 +1,78 @@ +#include +#include +#include +#include +#include +#include +#include + +typedef CGAL::Triangulation_data_structure_3<> Tds; +typedef Tds::size_type size_type; +typedef Tds::Cell_handle Cell_handle; +typedef Tds::Vertex_handle Vertex_handle; + +template +struct Update_vertex +{ + typedef typename T1::Vertex V1; + typedef typename T2::Vertex V2; + + V2 operator()(const V1&) + { + return V2(); + } + + void operator()(const V1&, V2&) + { + + } + + +}; // end struct Update_vertex + +template +struct Update_cell +{ + typedef typename T1::Cell C1; + typedef typename T2::Cell C2; + + C2 operator()(const C1&) + { + return C2(); + } + + void operator()(const C1&, C2&) + { + + } + + +}; // end struct Update_vertex + +int main() +{ + Tds T; + std::vector PV(7); + PV[0] = T.insert_increase_dimension(); + // each of the following insertions of vertices increases the dimension + for ( int i=1; i<5; i++ ) { + PV[i] = T.insert_increase_dimension(PV[0]); + } + // we now have a simplex in dimension 4 + // cell incident to PV[0] + Cell_handle c = PV[0]->cell(); + int ind=0; + // PV[0] is the vertex of index ind in c + // insertion of a new vertex in the facet opposite to PV[0] + PV[5] = T.insert_in_facet(c, ind); + // insertion of a new vertex in c + PV[6] = T.insert_in_cell(c); + std::ofstream out("tr"); + out << T; + out.close(); + Tds T2; + std::ifstream in("tr"); + T2.file_input, Update_cell >(in); + in.close(); + return 0; +} diff --git a/Triangulation_2/test/Triangulation_2/include/CGAL/_test_cls_constrained_triangulation_2.h b/Triangulation_2/test/Triangulation_2/include/CGAL/_test_cls_constrained_triangulation_2.h index 344d9b858c9..fbe4b9ae725 100644 --- a/Triangulation_2/test/Triangulation_2/include/CGAL/_test_cls_constrained_triangulation_2.h +++ b/Triangulation_2/test/Triangulation_2/include/CGAL/_test_cls_constrained_triangulation_2.h @@ -280,7 +280,8 @@ _test_cls_constrained_triangulation(const Triang &) vha = fh->vertex(li); fh = T1_2.locate(Point(3,2),lt,li); assert( lt == Triang::VERTEX ); vhb = fh->vertex(li); - assert(T1_2.is_edge(vha,vhb, fh, ih)); + bool check = T1_2.is_edge(vha,vhb, fh, ih); + assert(check); assert(fh->is_constrained(ih)); T1_2.remove_constrained_edge(fh,ih); assert(!fh->is_constrained(ih)); @@ -313,7 +314,7 @@ _test_cls_constrained_triangulation(const Triang &) vha = fh->vertex(li); fh = T2_2.locate(lpt[m+1],lt,li); assert( lt == Triang::VERTEX ); vhb = fh->vertex(li); - bool check = T2_2.is_edge(vha,vhb, fh, ih); + check = T2_2.is_edge(vha,vhb, fh, ih); assert(check); assert(fh->is_constrained(ih)); T2_2.remove_constrained_edge(fh,ih); diff --git a/Triangulation_2/test/Triangulation_2/include/CGAL/_test_cls_delaunay_triangulation_2.h b/Triangulation_2/test/Triangulation_2/include/CGAL/_test_cls_delaunay_triangulation_2.h index 7c5907160d0..d5088cb094d 100644 --- a/Triangulation_2/test/Triangulation_2/include/CGAL/_test_cls_delaunay_triangulation_2.h +++ b/Triangulation_2/test/Triangulation_2/include/CGAL/_test_cls_delaunay_triangulation_2.h @@ -293,7 +293,8 @@ _test_cls_delaunay_triangulation_2( const Del & ) assert(TM_0.tds().is_valid()); assert(TM_0.is_valid()); assert(TM_0.dimension() == 2); - assert(TM_0.move_if_no_collision(tmv1, Point(3, 0)) != tmv1); + Vertex_handle mtmv1 = TM_0.move_if_no_collision(tmv1, Point(3, 0)); + assert(mtmv1 != tmv1); TM_0.move_if_no_collision(tmv1, Point(0, 1)); assert(TM_0.tds().is_valid()); @@ -340,7 +341,8 @@ _test_cls_delaunay_triangulation_2( const Del & ) // A simple test to see if move return the good vertex // when there is a collision - assert(TM_1.move(TM_1.finite_vertices_begin(), vTM_1->point()) == vTM_1); + Vertex_handle mvTM_1 = TM_1.move(TM_1.finite_vertices_begin(), vTM_1->point()); + assert(mvTM_1 == vTM_1); } diff --git a/Triangulation_2/test/Triangulation_2/include/CGAL/_test_cls_triangulation_2.h b/Triangulation_2/test/Triangulation_2/include/CGAL/_test_cls_triangulation_2.h index 8beb8650271..096b6bc5d7a 100644 --- a/Triangulation_2/test/Triangulation_2/include/CGAL/_test_cls_triangulation_2.h +++ b/Triangulation_2/test/Triangulation_2/include/CGAL/_test_cls_triangulation_2.h @@ -270,11 +270,13 @@ _test_cls_triangulation_2( const Triangul & ) assert( T2_3.is_valid() ); // make sure inserting on a previous point does not insert it again - assert( T2_3.insert(p10) == v2_3_10 ); + Vertex_handle vp10 = T2_3.insert(p10); + assert( vp10 == v2_3_10 ); assert( T2_3.number_of_vertices() == 11 ); // make sure push_back exists and does the same thing as insert - assert( T2_3.push_back(p10) == v2_3_10 ); + vp10 = T2_3.push_back(p10); + assert( vp10 == v2_3_10 ); assert( T2_3.number_of_vertices() == 11 ); // test generic iterator insert @@ -288,14 +290,16 @@ _test_cls_triangulation_2( const Triangul & ) // test list iterator insert Triangul T2_5; - assert( T2_5.insert(l.begin(), l.end()) == 10 ); + std::ptrdiff_t T2_5_nv = T2_5.insert(l.begin(), l.end()); + assert( T2_5_nv == 10 ); assert( T2_5.dimension() == 2 ); assert( T2_5.number_of_vertices() == 10 ); assert( T2_5.is_valid() ); // test list iterator insert Triangul T2_6; - assert( T2_6.insert(v.begin(), v.end()) == 10 ); + std::ptrdiff_t T2_6_nv = T2_6.insert(v.begin(), v.end()); + assert( T2_6_nv == 10 ); assert( T2_6.dimension() == 2 ); assert( T2_6.number_of_vertices() == 10 ); assert( T2_6.is_valid() ); @@ -451,7 +455,8 @@ _test_cls_triangulation_2( const Triangul & ) // A simple test to see if move returns the good vertex // when there is a collision - assert(TM_1.move(TM_1.finite_vertices_begin(), vTM_1->point()) == vTM_1); + Vertex_handle mvTM_1 = TM_1.move(TM_1.finite_vertices_begin(), vTM_1->point()); + assert(mvTM_1 == vTM_1); /****************************/ /***** CONSTRUCTORS (2) *****/ diff --git a/Triangulation_3/doc/Triangulation_3/CGAL/Triangulation_3.h b/Triangulation_3/doc/Triangulation_3/CGAL/Triangulation_3.h index f419717feb1..e86c542c60d 100644 --- a/Triangulation_3/doc/Triangulation_3/CGAL/Triangulation_3.h +++ b/Triangulation_3/doc/Triangulation_3/CGAL/Triangulation_3.h @@ -1538,6 +1538,7 @@ for faces of maximal dimension instead of cells. /// @{ /*! +\ingroup PkgIOTriangulation3 Reads the underlying combinatorial triangulation from `is` by calling the corresponding input operator of the triangulation data structure class (note that the infinite vertex is numbered 0), and the @@ -1550,12 +1551,44 @@ of the vertex and cell types. Assigns the resulting triangulation to istream& operator>> (istream& is, Triangulation_3 &t); /*! + * \ingroup PkgIOTriangulation3 Writes the triangulation `t` into `os`. */ ostream& operator<< (ostream& os, const Triangulation_3 &t); -/// @} +/*! +\ingroup PkgIOTriangulation3 +The triangulation streamed in `is`, of original type `Tr_src`, is written into the triangulation. As the vertex and cell + types might be different and incompatible, the creation of new cells and vertices +is made thanks to the functors `convert_vertex` and `convert_cell`, that convert +vertex and cell types. For each vertex `v_src` in `is`, the corresponding +vertex `v_tgt` in the triangulation is a copy of the vertex returned by `convert_vertex(v_src)`. +The same operations are done for cells with the functor convert_cell, except cells +in the triangulation are created using the default constructor, and then filled with the data +contained in the stream. + - A model of `ConvertVertex` must provide two `operator()`s that are responsible + for converting the source vertex `v_src` into the target vertex: + - `Vertex operator()(const Tr_src::Vertex& v_src) const;` This operator is +used to create the vertex from `v_src`. + - `void operator()(const Tr_src::Vertex& v_src, Vertex& v_tgt) const;` This + operator is meant to be used in case heavy data should be transferred to `v_tgt`. + - A model of ConvertCell must provide an operator() that is responsible for +converting the source cell `c_src` into the target cell: + - `void operator()(const Tr_src::Cell& c_src, Cell& c_tgt) const;` This operator + is meant to be used in case data should be transferred to `c_tgt`. + +\note The triangulation contained in `is` can be obtained with the `operator>>` of a `Triangulation_3`. +*/ +template +std::istream& file_input(std::istream& is, + ConvertVertex convert_vertex = ConvertVertex(), + ConvertCell convert_cell = ConvertCell()); + +/// @} +/// /// \name Concurrency /// @{ diff --git a/Triangulation_3/doc/Triangulation_3/PackageDescription.txt b/Triangulation_3/doc/Triangulation_3/PackageDescription.txt index c401bad36c0..87cdc2aa9f7 100644 --- a/Triangulation_3/doc/Triangulation_3/PackageDescription.txt +++ b/Triangulation_3/doc/Triangulation_3/PackageDescription.txt @@ -21,6 +21,9 @@ /// \defgroup PkgDrawTriangulation3 Draw a Triangulation 3 /// \ingroup PkgTriangulation3Ref +/// \defgroup PkgIOTriangulation3 I/O for a Triangulation 3 +/// \ingroup PkgTriangulation3Ref + /*! \addtogroup PkgTriangulation3Ref \cgalPkgDescriptionBegin{3D Triangulations,PkgTriangulation3} @@ -121,5 +124,8 @@ is opposite to the vertex with the same index. See - \link PkgDrawTriangulation3 CGAL::draw() \endlink +\cgalCRPSection{I/O} + - \link PkgIOTriangulation3 CGAL:Triangulation_3::file_input()\endlink + - \link PkgIOTriangulation3 CGAL::file_input()\endlink */ diff --git a/Triangulation_3/include/CGAL/Triangulation_3.h b/Triangulation_3/include/CGAL/Triangulation_3.h index 5341859314a..c3f6e310f44 100644 --- a/Triangulation_3/include/CGAL/Triangulation_3.h +++ b/Triangulation_3/include/CGAL/Triangulation_3.h @@ -2196,8 +2196,80 @@ public: bool is_valid(bool verbose = false, int level = 0) const; bool is_valid(Cell_handle c, bool verbose = false, int level = 0) const; bool is_valid_finite(Cell_handle c, bool verbose = false, int level=0) const; + + //IO + template + std::istream& file_input(std::istream& is, + ConvertVertex convert_vertex = ConvertVertex(), + ConvertCell convert_cell = ConvertCell()) + { + // reads + // the dimension + // the number of finite vertices + // the non combinatorial information on vertices (point, etc) + // the number of cells + // the cells by the indices of their vertices in the preceding list + // of vertices, plus the non combinatorial information on each cell + // the neighbors of each cell by their index in the preceding list of cells + // when dimension < 3 : the same with faces of maximal dimension + + // If this is used for a TDS, the vertices are processed from 0 to n. + // Else, we make V[0] the infinite vertex and work from 1 to n+1. + + typedef Self Triangulation; + typedef typename Triangulation::Vertex_handle Vertex_handle; + typedef typename Triangulation::Cell_handle Cell_handle; + + typedef typename Tr_src::Vertex Vertex1; + typedef typename Tr_src::Cell Cell1; + + clear(); + tds().cells().clear(); + + std::size_t n; + int d; + if(is_ascii(is)) + is >> d >> n; + else { + read(is, d); + read(is, n); + } + if(!is) return is; + tds().set_dimension(d); + + std::size_t V_size = n+1; + std::vector< Vertex_handle > V(V_size); + + // the infinite vertex is numbered 0 + V[0] = infinite_vertex(); + + for (std::size_t i = 1; i < V_size; ++i) { + Vertex1 v; + if(!(is >> v)) return is; + Vertex_handle vh=tds().create_vertex( convert_vertex(v) ); + V[i] = vh; + convert_vertex(v, *V[i]); + } + + std::vector< Cell_handle > C; + + std::size_t m; + tds().read_cells(is, V, m, C); + + for (std::size_t j=0 ; j < m; j++) { + Cell1 c; + if(!(is >> c)) return is; + convert_cell(c, *C[j]); + } + + CGAL_triangulation_assertion( is_valid(false) ); + return is; + } }; + template < class GT, class Tds, class Lds > std::istream& operator>> (std::istream& is, Triangulation_3& tr) { diff --git a/Triangulation_3/test/Triangulation_3/CMakeLists.txt b/Triangulation_3/test/Triangulation_3/CMakeLists.txt index c4813394fc9..a2d10b47143 100644 --- a/Triangulation_3/test/Triangulation_3/CMakeLists.txt +++ b/Triangulation_3/test/Triangulation_3/CMakeLists.txt @@ -28,6 +28,7 @@ if ( CGAL_FOUND ) create_single_source_cgal_program( "test_simplex_3.cpp" ) create_single_source_cgal_program( "test_static_filters.cpp" ) create_single_source_cgal_program( "test_triangulation_3.cpp" ) + create_single_source_cgal_program( "test_io_triangulation_3.cpp" ) if(TBB_FOUND) foreach(target diff --git a/Triangulation_3/test/Triangulation_3/test_io_triangulation_3.cpp b/Triangulation_3/test/Triangulation_3/test_io_triangulation_3.cpp new file mode 100644 index 00000000000..a6e4694e5e1 --- /dev/null +++ b/Triangulation_3/test/Triangulation_3/test_io_triangulation_3.cpp @@ -0,0 +1,66 @@ + + +#include +#include +#include +#include +#include +#include + +typedef CGAL::Simple_cartesian K1; +typedef CGAL::Exact_predicates_inexact_constructions_kernel K2; +typedef CGAL::Triangulation_3 Tr1; +typedef CGAL::Triangulation_3 Tr2; + + +template +struct Update_vertex +{ + typedef typename T1::Vertex V1; + typedef typename T2::Vertex V2; + typedef typename T2::Point Point; + + V2 operator()(const V1&) + { + return V2(); + } + + void operator()(const V1& v1, V2& v2) + { + CGAL::Cartesian_converter c; + v2.set_point(Point(c(v1.point()))); + } +}; // end struct Update_vertex + +struct Update_cell { + template + void operator()(const C1&, C2&) {} +}; // end struct Update_cell +int main() +{ + // construction from a list of points : + std::list L; + L.push_back(Tr1::Point(0,0,0)); + L.push_back(Tr1::Point(1,0,0)); + L.push_back(Tr1::Point(0,1,0)); + L.push_back(Tr1::Point(0,0,1)); + Tr1 T1(L.begin(), L.end()); + std::ofstream out("tr"); + out << T1; + out.close(); + + Tr2 T2; + std::ifstream in("tr"); + T2.file_input, Update_cell>(in); + in.close(); + assert(T2.is_valid()); + Tr2::Point_iterator pit = T2.points_begin(); + assert(*(pit)++ == Tr2::Point(0,0,0)); + assert(*(pit)++ == Tr2::Point(1,0,0)); + assert(*(pit)++ == Tr2::Point(0,1,0)); + assert(*(pit)++ == Tr2::Point(0,0,1)); + + + std::cout << "done" << std::endl; + return 0; +}