#ifndef CGAL_SURFACE_MESH_APPROXIMATION_VSA_TRAITS_H #define CGAL_SURFACE_MESH_APPROXIMATION_VSA_TRAITS_H #include #include #include #include #include namespace CGAL { /** * @brief Plane proxy class for the Variational Shape Approximation algorithm. * * It is simply a class containing few proxy parameters. * It is used as the default proxy for the `L21Metric` and `L2Metric` * * @tparam TriangleMesh a triangle `FaceGraph` * @tparam GeomTraits geometric traits */ template class PlaneProxy { typedef typename GeomTraits::Vector_3 Vector_3; typedef typename GeomTraits::Plane_3 Plane_3; typedef typename boost::graph_traits::face_descriptor face_descriptor; public: // The proxy seed. face_descriptor seed; // The proxy normal used in the `L21Metric`. Vector_3 normal; // The fitting plane of the proxy used in the `L2Metric`. Plane_3 fit_plane; }; /** * @brief L21 metric class for the Variational Shape Approximation algorithm. * * It is simply a functor that takes a facet and a proxy, returns the L21 error between them. * * @tparam TriangleMesh a triangle `FaceGraph` * @tparam FacetNormalMap a property map containing the facet normals, and `boost::graph_traits::%face_descriptor` as key type, GeomTraits::Vector_3 as value type * @tparam FacetAreaMap a property map containing the facet areas, and `boost::graph_traits::%face_descriptor` as key type, GeomTraits::FT as value type * @tparam GeomTraits geometric traits * @tparam PlaneProxy a model of `PlaneProxy` */ template > class L21Metric { typedef typename GeomTraits::FT FT; typedef typename GeomTraits::Vector_3 Vector_3; typedef typename GeomTraits::Construct_scaled_vector_3 Construct_scaled_vector_3; typedef typename GeomTraits::Construct_sum_of_vectors_3 Construct_sum_of_vectors_3; typedef typename GeomTraits::Compute_scalar_product_3 Compute_scalar_product_3; typedef typename FacetAreaMap::key_type face_descriptor; public: // The type define required by the `ErrorMetric` concept typedef PlaneProxy Proxy; // default constructor L21Metric() { GeomTraits traits; scalar_product_functor = traits.compute_scalar_product_3_object(); sum_functor = traits.construct_sum_of_vectors_3_object(); scale_functor = traits.construct_scaled_vector_3_object(); } // construct L21 metric functor from a facet normal map and a facet area map. L21Metric(const FacetNormalMap &normal_pmap, const FacetAreaMap &area_pmap) : normal_pmap(normal_pmap), area_pmap(area_pmap) { GeomTraits traits; scalar_product_functor = traits.compute_scalar_product_3_object(); sum_functor = traits.construct_sum_of_vectors_3_object(); scale_functor = traits.construct_scaled_vector_3_object(); } // returns L21 error of a facet f to a proxy px. FT operator()(const face_descriptor &f, const Proxy &px) const { Vector_3 v = sum_functor(normal_pmap[f], scale_functor(px.normal, FT(-1))); return area_pmap[f] * scalar_product_functor(v, v); } private: const FacetNormalMap normal_pmap; const FacetAreaMap area_pmap; Construct_scaled_vector_3 scale_functor; Compute_scalar_product_3 scalar_product_functor; Construct_sum_of_vectors_3 sum_functor; }; /** * @brief L21 proxy fitting class for the Variational Shape Approximation algorithm. * * It is simply a functor that takes a range of facets, fitting the proxy parameters. * * @tparam TriangleMesh a triangle `FaceGraph` * @tparam FacetNormalMap a property map containing the facet normals, and `boost::graph_traits::%face_descriptor` as key type, GeomTraits::Vector_3 as value type * @tparam FacetAreaMap a property map containing the facet areas, and `boost::graph_traits::%face_descriptor` as key type, GeomTraits::FT as value type * @tparam GeomTraits geometric traits * @tparam PlaneProxy a model of `PlaneProxy` */ template > class L21ProxyFitting { typedef typename GeomTraits::FT FT; typedef typename GeomTraits::Vector_3 Vector_3; typedef typename GeomTraits::Construct_scaled_vector_3 Construct_scaled_vector_3; typedef typename GeomTraits::Construct_sum_of_vectors_3 Construct_sum_of_vectors_3; public: // The type define required by the `ErrorMetric` concept typedef PlaneProxy Proxy; // default constructor L21ProxyFitting() { GeomTraits traits; sum_functor = traits.construct_sum_of_vectors_3_object(); scale_functor = traits.construct_scaled_vector_3_object(); } // construct L21 proxy fitting functor from a facet normal map and a facet area map. L21ProxyFitting(const FacetNormalMap &normal_pmap, const FacetAreaMap &area_pmap) : normal_pmap(normal_pmap), area_pmap(area_pmap) { GeomTraits traits; sum_functor = traits.construct_sum_of_vectors_3_object(); scale_functor = traits.construct_scaled_vector_3_object(); } // returns the proxy fitted from the facets from beg to end. template Proxy operator()(const FacetIterator beg, const FacetIterator end) const { CGAL_assertion(beg != end); // fitting normal Vector_3 norm = CGAL::NULL_VECTOR; for (FacetIterator fitr = beg; fitr != end; ++fitr) { norm = sum_functor(norm, scale_functor(normal_pmap[*fitr], area_pmap[*fitr])); } norm = scale_functor(norm, FT(1.0 / std::sqrt(CGAL::to_double(norm.squared_length())))); // construct proxy Proxy px; px.normal = norm; return px; } private: const FacetNormalMap normal_pmap; const FacetAreaMap area_pmap; Construct_scaled_vector_3 scale_functor; Construct_sum_of_vectors_3 sum_functor; }; /** * @brief Area weighted plane fitting class for the Variational Shape Approximation algorithm. * * It is simply a functor class that fits a plane from a range of facets. * * @tparam TriangleMesh a triangle `FaceGraph` * @tparam VertexPointMap a property map containing the vertex points, and `boost::graph_traits::%vertex_descriptor` as key type, GeomTraits::Point_3 as value type * @tparam GeomTraits geometric traits */ template::type, typename GeomTraits = typename TriangleMesh::Traits> class PlaneFitting { typedef typename GeomTraits::FT FT; typedef typename GeomTraits::Point_3 Point_3; typedef typename GeomTraits::Vector_3 Vector_3; typedef typename GeomTraits::Plane_3 Plane_3; typedef typename GeomTraits::Construct_vector_3 Construct_vector_3; typedef typename GeomTraits::Construct_scaled_vector_3 Construct_scaled_vector_3; typedef typename GeomTraits::Construct_sum_of_vectors_3 Construct_sum_of_vectors_3; typedef typename boost::graph_traits::halfedge_descriptor halfedge_descriptor; public: // construct plane fitting functor from a triangle mesh and its vertex point map. PlaneFitting(const TriangleMesh &_mesh, const VertexPointMap &_point_pmap) : mesh(_mesh), point_pmap(_point_pmap) { GeomTraits traits; vector_functor = traits.construct_vector_3_object(); sum_functor = traits.construct_sum_of_vectors_3_object(); scale_functor = traits.construct_scaled_vector_3_object(); } // construct plane fitting functor from a triangle mesh. PlaneFitting(const TriangleMesh &_mesh) : mesh(_mesh), point_pmap(get(boost::vertex_point, const_cast(_mesh))) { GeomTraits traits; vector_functor = traits.construct_vector_3_object(); sum_functor = traits.construct_sum_of_vectors_3_object(); scale_functor = traits.construct_scaled_vector_3_object(); } // fitting a plane from facets in range beg to end. template Plane_3 operator()(const FacetIterator &beg, const FacetIterator &end) const { CGAL_assertion(beg != end); // area average normal and centroid Vector_3 norm = CGAL::NULL_VECTOR; Vector_3 cent = CGAL::NULL_VECTOR; FT sum_area(0); for (FacetIterator fitr = beg; fitr != end; ++fitr) { const halfedge_descriptor he = halfedge(*fitr, mesh); const Point_3 p0 = point_pmap[source(he, mesh)]; const Point_3 p1 = point_pmap[target(he, mesh)]; const Point_3 p2 = point_pmap[target(next(he, mesh), mesh)]; Vector_3 vec = vector_functor(CGAL::ORIGIN, CGAL::centroid(p0, p1, p2)); FT farea(std::sqrt(CGAL::to_double(CGAL::squared_area(p0, p1, p2)))); Vector_3 fnorm = CGAL::unit_normal(p0, p1, p2); norm = sum_functor(norm, scale_functor(fnorm, farea)); cent = sum_functor(cent, scale_functor(vec, farea)); sum_area += farea; } norm = scale_functor(norm, FT(1.0 / std::sqrt(CGAL::to_double(norm.squared_length())))); cent = scale_functor(cent, FT(1) / sum_area); return Plane_3(CGAL::ORIGIN + cent, norm); } private: const TriangleMesh &mesh; const VertexPointMap point_pmap; Construct_vector_3 vector_functor; Construct_scaled_vector_3 scale_functor; Construct_sum_of_vectors_3 sum_functor; }; /** * @brief L2 metric class for the Variational Shape Approximation algorithm. * * It is simply a functor that takes a facet and a proxy, returns the L2 error between them. * * @tparam TriangleMesh a triangle `FaceGraph` * @tparam FacetAreaMap a property map containing the facet areas, and `boost::graph_traits::%face_descriptor` as key type, GeomTraits::FT as value type * @tparam VertexPointMap a property map containing the vertex points, and `boost::graph_traits::%vertex_descriptor` as key type, GeomTraits::Point_3 as value type * @tparam GeomTraits geometric traits * @tparam PlaneProxy a model of `PlaneProxy` */ template::type, typename GeomTraits = typename TriangleMesh::Traits, typename PlaneProxy = CGAL::PlaneProxy > class L2Metric { typedef typename GeomTraits::FT FT; typedef typename GeomTraits::Point_3 Point_3; typedef typename boost::graph_traits::face_descriptor face_descriptor; typedef typename boost::graph_traits::halfedge_descriptor halfedge_descriptor; public: // The type define required by the `ErrorMetric` concept typedef PlaneProxy Proxy; // default constructor L2Metric() : mesh(nullptr) {} // construct L2 metric functor from a triangle mesh, a facet area map and the vertex point map. L2Metric(const TriangleMesh &_mesh, const FacetAreaMap &_area_pmap, const VertexPointMap &_point_pmap) : mesh(&_mesh), area_pmap(_area_pmap), point_pmap(_point_pmap) {} // construct L2 metric functor from a triangle mesh and a facet area map. L2Metric(const TriangleMesh &_mesh, const FacetAreaMap &_area_pmap) : mesh(&_mesh), area_pmap(_area_pmap), point_pmap(get(boost::vertex_point, const_cast(_mesh))) {} // returns the l2 fitting error of a facet f to proxy px. FT operator()(const face_descriptor &f, const PlaneProxy &px) const { halfedge_descriptor he = halfedge(f, *mesh); const Point_3 &p0 = point_pmap[source(he, *mesh)]; const Point_3 &p1 = point_pmap[target(he, *mesh)]; const Point_3 &p2 = point_pmap[target(next(he, *mesh), *mesh)]; FT sq_d0 = CGAL::squared_distance(p0, px.fit_plane); FT sq_d1 = CGAL::squared_distance(p1, px.fit_plane); FT sq_d2 = CGAL::squared_distance(p2, px.fit_plane); FT d0(std::sqrt(CGAL::to_double(sq_d0))); FT d1(std::sqrt(CGAL::to_double(sq_d1))); FT d2(std::sqrt(CGAL::to_double(sq_d2))); return (sq_d0 + sq_d1 + sq_d2 + d0 * d1 + d1 * d2 + d2 * d0) * area_pmap[f] / FT(6); } private: const FacetAreaMap area_pmap; const VertexPointMap point_pmap; const TriangleMesh *mesh; }; /** * @brief L2 proxy fitting class for the Variational Shape Approximation algorithm. * * It is simply a functor that takes a range of facets, fitting the L2 proxy parameters. * It uses the PCA algorithm to fit the proxy parameters. * * @tparam TriangleMesh a triangle `FaceGraph` * @tparam VertexPointMap a property map containing the vertex points, and `boost::graph_traits::%vertex_descriptor` as key type, GeomTraits::Point_3 as value type * @tparam GeomTraits geometric traits * @tparam PlaneProxy a model of `PlaneProxy` */ template::type, typename GeomTraits = typename TriangleMesh::Traits, typename PlaneProxy = CGAL::PlaneProxy > class L2ProxyFitting { private: typedef typename GeomTraits::Point_3 Point_3; typedef typename GeomTraits::Triangle_3 Triangle_3; typedef typename boost::graph_traits::halfedge_descriptor halfedge_descriptor; public: // The type define required by the `ErrorMetric` concept typedef PlaneProxy Proxy; // default constructor L2ProxyFitting() : mesh(nullptr) {} // construct L2 proxy fitting functor from a triangle mesh and the vertex point map. L2ProxyFitting(const TriangleMesh &_mesh, const VertexPointMap &_point_pmap) : mesh(&_mesh), point_pmap(_point_pmap) {} // construct L2 proxy fitting functor from a triangle mesh. L2ProxyFitting(const TriangleMesh &_mesh) : mesh(&_mesh), point_pmap(get(boost::vertex_point, const_cast(_mesh))) {} // returns the proxy fitted from a range of facets. template Proxy operator()(const FacetIterator beg, const FacetIterator end) const { CGAL_assertion(beg != end); std::list tris; for (FacetIterator fitr = beg; fitr != end; ++fitr) { halfedge_descriptor he = halfedge(*fitr, *mesh); const Point_3 &p0 = point_pmap[source(he, *mesh)]; const Point_3 &p1 = point_pmap[target(he, *mesh)]; const Point_3 &p2 = point_pmap[target(next(he, *mesh), *mesh)]; tris.push_back(Triangle_3(p0, p1, p2)); } // construct and fit proxy plane Proxy px; CGAL::linear_least_squares_fitting_3( tris.begin(), tris.end(), px.fit_plane, CGAL::Dimension_tag<2>()); return px; } private: const TriangleMesh *mesh; const VertexPointMap point_pmap; }; /** * @brief PCA plane fitting class. * * It is simply a functor class that uses the PCA algorithm to fit a plane from a range of facets. * * @tparam TriangleMesh a triangle `FaceGraph` * @tparam VertexPointMap a property map containing the vertex points, and `boost::graph_traits::%vertex_descriptor` as key type, GeomTraits::Point_3 as value type * @tparam GeomTraits geometric traits */ template::type, typename GeomTraits = typename TriangleMesh::Traits> class PCAPlaneFitting { typedef typename GeomTraits::Point_3 Point_3; typedef typename GeomTraits::Plane_3 Plane_3; typedef typename GeomTraits::Triangle_3 Triangle_3; typedef typename boost::graph_traits::halfedge_descriptor halfedge_descriptor; public: // construct PCA plane fitting functor from a triangle mesh and the vertex point map. PCAPlaneFitting(const TriangleMesh &_mesh, const VertexPointMap &_point_pmap) : mesh(_mesh), point_pmap(_point_pmap) {} // construct PCA plane fitting functor from a triangle mesh. PCAPlaneFitting(const TriangleMesh &_mesh) : mesh(_mesh), point_pmap(get(boost::vertex_point, const_cast(_mesh))) {} // returns a plane fitted from facets in range beg to end by the PCA algorithm. template Plane_3 operator()(const FacetIterator beg, const FacetIterator end) const { CGAL_assertion(beg != end); std::list tris; for (FacetIterator fitr = beg; fitr != end; ++fitr) { halfedge_descriptor he = halfedge(*fitr, mesh); const Point_3 &p0 = point_pmap[source(he, mesh)]; const Point_3 &p1 = point_pmap[target(he, mesh)]; const Point_3 &p2 = point_pmap[target(next(he, mesh), mesh)]; tris.push_back(Triangle_3(p0, p1, p2)); } // construct and fit proxy plane Plane_3 fit_plane; CGAL::linear_least_squares_fitting_3( tris.begin(), tris.end(), fit_plane, CGAL::Dimension_tag<2>()); return fit_plane; } private: const TriangleMesh &mesh; const VertexPointMap point_pmap; }; } // end namespace CGAL #endif // CGAL_SURFACE_MESH_APPROXIMATION_VSA_TRAITS_H