diff --git a/Barycentric_coordinates_2/include/CGAL/Barycentric_coordinates_2/Harmonic_coordinates_2.h b/Barycentric_coordinates_2/include/CGAL/Barycentric_coordinates_2/Harmonic_coordinates_2.h index 8e7efbd5fc3..164861dc6aa 100644 --- a/Barycentric_coordinates_2/include/CGAL/Barycentric_coordinates_2/Harmonic_coordinates_2.h +++ b/Barycentric_coordinates_2/include/CGAL/Barycentric_coordinates_2/Harmonic_coordinates_2.h @@ -587,8 +587,7 @@ namespace Barycentric_coordinates { const auto& p0 = m_domain.vertex(neighbors[jm]); const auto& p1 = m_domain.vertex(neighbors[j]); const auto& p2 = m_domain.vertex(neighbors[jp]); - const FT w = -Weights::cotangent_weight( - p0, p1, p2, query, m_traits) / FT(2); + const FT w = -Weights::cotangent_weight(p0, p1, p2, query, m_traits) / FT(2); W -= w; if (m_domain.is_on_boundary(idx)) { diff --git a/Heat_method_3/include/CGAL/Heat_method_3/Surface_mesh_geodesic_distances_3.h b/Heat_method_3/include/CGAL/Heat_method_3/Surface_mesh_geodesic_distances_3.h index b257c53843d..0dead11c3ca 100644 --- a/Heat_method_3/include/CGAL/Heat_method_3/Surface_mesh_geodesic_distances_3.h +++ b/Heat_method_3/include/CGAL/Heat_method_3/Surface_mesh_geodesic_distances_3.h @@ -529,22 +529,19 @@ private: pj = p_j; pk = p_k; - const double cotan_i = CGAL::to_double( - CGAL::Weights::cotangent(pk, pi, pj, traits)); + const double cotan_i = CGAL::to_double(CGAL::Weights::cotangent(pk, pi, pj, traits)); m_cotan_matrix.add_coef(j, k, -(1./2) * cotan_i); m_cotan_matrix.add_coef(k, j, -(1./2) * cotan_i); m_cotan_matrix.add_coef(j, j, (1./2) * cotan_i); m_cotan_matrix.add_coef(k, k, (1./2) * cotan_i); - const double cotan_j = CGAL::to_double( - CGAL::Weights::cotangent(pk, pj, pi, traits)); + const double cotan_j = CGAL::to_double(CGAL::Weights::cotangent(pk, pj, pi, traits)); m_cotan_matrix.add_coef(i, k, -(1./2) * cotan_j); m_cotan_matrix.add_coef(k, i, -(1./2) * cotan_j); m_cotan_matrix.add_coef(i, i, (1./2) * cotan_j); m_cotan_matrix.add_coef(k, k, (1./2) * cotan_j); - const double cotan_k = CGAL::to_double( - CGAL::Weights::cotangent(pj, pk, pi, traits)); + const double cotan_k = CGAL::to_double(CGAL::Weights::cotangent(pj, pk, pi, traits)); m_cotan_matrix.add_coef(i, j, -(1./2) * cotan_k); m_cotan_matrix.add_coef(j, i, -(1./2) * cotan_k); m_cotan_matrix.add_coef(i, i, (1./2) * cotan_k); @@ -553,8 +550,7 @@ private: const Vector_3 v_ij = construct_vector(p_i, p_j); const Vector_3 v_ik = construct_vector(p_i, p_k); const Vector_3 cross = cross_product(v_ij, v_ik); - const double norm_cross = CGAL::sqrt( - CGAL::to_double(scalar_product(cross, cross))); + const double norm_cross = CGAL::sqrt(CGAL::to_double(scalar_product(cross, cross))); //double area_face = CGAL::Polygon_mesh_processing::face_area(f,tm); //cross is 2*area diff --git a/Mesh_3/include/CGAL/Mesh_3/vertex_perturbation.h b/Mesh_3/include/CGAL/Mesh_3/vertex_perturbation.h index 93b4119a1b1..1b1e53c9305 100644 --- a/Mesh_3/include/CGAL/Mesh_3/vertex_perturbation.h +++ b/Mesh_3/include/CGAL/Mesh_3/vertex_perturbation.h @@ -1058,7 +1058,7 @@ private: */ FT cotangent(const FT& value) const { - return FT(1/std::tan(CGAL::to_double(value))); + return FT(1./std::tan(CGAL::to_double(value))); } /** diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/fair.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/fair.h index d02ef3a9023..0260d314619 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/fair.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/fair.h @@ -41,18 +41,18 @@ namespace internal { typename TriangleMesh, typename VertexRange, typename VertexPointMap> - bool fair(TriangleMesh& tmesh, - const VertexRange& vertices, - SparseLinearSolver solver, - WeightCalculator weight_calculator, - unsigned int continuity, - VertexPointMap vpmap) - { - CGAL::Polygon_mesh_processing::internal::Fair_Polyhedron_3 - - fair_functor(tmesh, vpmap, weight_calculator); - return fair_functor.fair(vertices, solver, continuity); - } +bool fair(TriangleMesh& tmesh, + const VertexRange& vertices, + SparseLinearSolver solver, + WeightCalculator weight_calculator, + unsigned int continuity, + VertexPointMap vpmap) +{ + CGAL::Polygon_mesh_processing::internal::Fair_Polyhedron_3 + + fair_functor(tmesh, vpmap, weight_calculator); + return fair_functor.fair(vertices, solver, continuity); +} } //end namespace internal @@ -161,25 +161,27 @@ namespace internal { #endif typedef typename GetVertexPointMap < TriangleMesh, NamedParameters>::type VPMap; + VPMap vpmap = choose_parameter(get_parameter(np, internal_np::vertex_point), + get_property_map(vertex_point, tmesh)); + + typedef typename GetGeomTraits < TriangleMesh, NamedParameters>::type GT; + GT gt = choose_parameter(get_parameter(np, internal_np::geom_traits)); // Cotangent_weight_with_voronoi_area_fairing has been changed to the version: - // Cotangent_weight_with_voronoi_area_fairing_secure to avoid imprecisions from + // Secure_cotangent_weight_with_voronoi_area to avoid imprecisions from // the issue #4706 - https://github.com/CGAL/cgal/issues/4706. - typedef CGAL::Weights::Secure_cotangent_weight_with_voronoi_area Default_weight_calculator; - - VPMap vpmap_ = choose_parameter(get_parameter(np, internal_np::vertex_point), - get_property_map(vertex_point, tmesh)); + typedef CGAL::Weights::Secure_cotangent_weight_with_voronoi_area Default_weight_calculator; return internal::fair(tmesh, vertices, choose_parameter(get_parameter(np, internal_np::sparse_linear_solver)), - choose_parameter(get_parameter(np, internal_np::weight_calculator), Default_weight_calculator(tmesh, vpmap_)), + choose_parameter(get_parameter(np, internal_np::weight_calculator), Default_weight_calculator(tmesh, vpmap, gt)), choose_parameter(get_parameter(np, internal_np::fairing_continuity), 1), - vpmap_); + vpmap); } -} //end namespace Polygon_mesh_processing +} // namespace Polygon_mesh_processing -} //end namespace CGAL +} // namespace CGAL #include diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Hole_filling/Triangulate_hole_polyline.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Hole_filling/Triangulate_hole_polyline.h index 3af5e28b102..15846998d96 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Hole_filling/Triangulate_hole_polyline.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Hole_filling/Triangulate_hole_polyline.h @@ -383,9 +383,9 @@ class Weight_incomplete private: template Weight_incomplete(const std::vector& P, - const std::vector& Q, - int i, int j, int k, - const LookupTable& lambda) + const std::vector& Q, + int i, int j, int k, + const LookupTable& lambda) : weight(P,Q,i,j,k,lambda), patch_size(1) { } @@ -442,9 +442,9 @@ struct Weight_calculator template Weight operator()(const std::vector& P, - const std::vector& Q, - int i, int j, int k, - const LookupTable& lambda) const + const std::vector& Q, + int i, int j, int k, + const LookupTable& lambda) const { if( !is_valid(P,i,j,k) ) { return Weight::NOT_VALID(); } diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Smoothing/curvature_flow_impl.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Smoothing/curvature_flow_impl.h index 3757f23f7d6..411117ab751 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Smoothing/curvature_flow_impl.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Smoothing/curvature_flow_impl.h @@ -78,7 +78,7 @@ public: vimap_(get(Vertex_local_index(), mesh_)), scale_volume_after_smoothing(true), traits_(traits), - weight_calculator_(mesh, vpmap) + weight_calculator_(mesh_, vpmap_, traits_, false /*no clamping*/, false /*no bounding from below*/) { } template @@ -177,7 +177,8 @@ public: if(is_source_constrained && is_target_constrained) continue; - const FT Lij = weight_calculator_(hi); + // Cotangent_weight returns (cot(beta) + cot(gamma)) / 2 + const FT Lij = FT(2) * weight_calculator_(hi); const std::size_t i_source = get(vimap_, v_source); const std::size_t i_target = get(vimap_, v_target); @@ -185,14 +186,14 @@ public: // note that these constraints create asymmetry in the matrix if(!is_source_constrained) { - stiffness_elements.push_back(Triplet(i_source, i_target, Lij)); - diag_coeff.insert(std::make_pair(i_source, 0)).first->second -= Lij; + stiffness_elements.emplace_back(i_source, i_target, Lij); + diag_coeff.emplace(i_source, 0).first->second -= Lij; } if(!is_target_constrained) { - stiffness_elements.push_back(Triplet(i_target, i_source, Lij)); - diag_coeff.insert(std::make_pair(i_target, 0)).first->second -= Lij; + stiffness_elements.emplace_back(i_target, i_source, Lij); + diag_coeff.emplace(i_target, 0).first->second -= Lij; } } } @@ -200,7 +201,7 @@ public: typename std::unordered_map::iterator it = diag_coeff.begin(), end = diag_coeff.end(); for(; it!=end; ++it) - stiffness_elements.push_back(Triplet(it->first, it->first, it->second)); + stiffness_elements.emplace_back(it->first, it->first, it->second); } void update_mesh_no_scaling(const Eigen_vector& Xx, const Eigen_vector& Xy, const Eigen_vector& Xz) @@ -368,8 +369,8 @@ private: std::vector diagonal_; // index of vector -> index of vimap_ std::vector constrained_flags_; - const GeomTraits& traits_; - const CGAL::Weights::Edge_cotangent_weight weight_calculator_; + GeomTraits traits_; + const CGAL::Weights::Cotangent_weight weight_calculator_; }; } // internal diff --git a/Polyhedron/demo/Polyhedron/Plugins/PMP/Hole_filling_plugin.cpp b/Polyhedron/demo/Polyhedron/Plugins/PMP/Hole_filling_plugin.cpp index 94300e439fa..82c807ea335 100644 --- a/Polyhedron/demo/Polyhedron/Plugins/PMP/Hole_filling_plugin.cpp +++ b/Polyhedron/demo/Polyhedron/Plugins/PMP/Hole_filling_plugin.cpp @@ -725,14 +725,15 @@ bool Polyhedron_demo_hole_filling_plugin::fill use_delaunay_triangulation(use_DT))); } else { - auto pmap = get_property_map(CGAL::vertex_point, poly); + auto vpm = get_property_map(CGAL::vertex_point, poly); + auto weight_calc = CGAL::Weights::Secure_cotangent_weight_with_voronoi_area(poly, vpm, EPICK()); + success = std::get<0>(CGAL::Polygon_mesh_processing::triangulate_refine_and_fair_hole(poly, it, std::back_inserter(patch), CGAL::Emptyset_iterator(), - CGAL::parameters:: - weight_calculator(CGAL::Weights::Secure_cotangent_weight_with_voronoi_area(poly, pmap)). - density_control_factor(alpha). - fairing_continuity(continuity). - use_delaunay_triangulation(use_DT))); + CGAL::parameters::weight_calculator(weight_calc). + density_control_factor(alpha). + fairing_continuity(continuity). + use_delaunay_triangulation(use_DT))); } if(!success) { print_message("Error: fairing is not successful, only triangulation and refinement are applied!"); } diff --git a/Surface_mesh_deformation/include/CGAL/Surface_mesh_deformation.h b/Surface_mesh_deformation/include/CGAL/Surface_mesh_deformation.h index c267c49b808..a715accf733 100644 --- a/Surface_mesh_deformation/include/CGAL/Surface_mesh_deformation.h +++ b/Surface_mesh_deformation/include/CGAL/Surface_mesh_deformation.h @@ -55,49 +55,72 @@ enum Deformation_algorithm_tag /// @cond CGAL_DOCUMENT_INTERNAL namespace internal { -template +// property map that create a Simple_cartesian::Point_3 +// on the fly in order the deformation class to be used +// with points with minimal requirements +template +struct SC_on_the_fly_pmap + : public Vertex_point_map +{ + typedef boost::readable_property_map_tag category; + typedef CGAL::Simple_cartesian::Point_3 value_type; + typedef value_type reference; + typedef typename boost::property_traits::key_type key_type; + + SC_on_the_fly_pmap(Vertex_point_map base): + Vertex_point_map(base) {} + + friend value_type + get(const SC_on_the_fly_pmap map, key_type k) + { + typename boost::property_traits::reference base= + get(static_cast(map), k); + return value_type(base[0], base[1], base[2]); + } +}; + +template struct Types_selectors; -template -struct Types_selectors { +template +struct Types_selectors +{ + typedef SC_on_the_fly_pmap Wrapped_VertexPointMap; + typedef CGAL::Weights::Single_cotangent_weight Weight_calculator; - // Get weight from the weight interface. - typedef CGAL::Weights::Single_cotangent_weight Weight_calculator; - - struct ARAP_visitor{ - template + struct ARAP_visitor + { void init(TriangleMesh, VertexPointMap){} - void rotation_matrix_pre( - typename boost::graph_traits::vertex_descriptor, - TriangleMesh&){} + void rotation_matrix_pre(typename boost::graph_traits::vertex_descriptor, + TriangleMesh&){} template - void update_covariance_matrix( - Square_matrix_3&, - const Square_matrix_3&){} + void update_covariance_matrix(Square_matrix_3&, + const Square_matrix_3&){} void set_sre_arap_alpha(double){} }; }; -template -struct Types_selectors { +template +struct Types_selectors +{ + typedef SC_on_the_fly_pmap Wrapped_VertexPointMap; + typedef CGAL::Weights::Cotangent_weight Weight_calculator; - // Get weight from the weight interface. - typedef CGAL::Weights::Cotangent_weight Weight_calculator; - - typedef typename Types_selectors - ::ARAP_visitor ARAP_visitor; + typedef typename Types_selectors::ARAP_visitor ARAP_visitor; }; -template -struct Types_selectors { +template +struct Types_selectors +{ + typedef SC_on_the_fly_pmap Wrapped_VertexPointMap; + typedef CGAL::Weights::Cotangent_weight Weight_calculator; - // Get weight from the weight interface. - typedef CGAL::Weights::Cotangent_weight Weight_calculator; - - class ARAP_visitor{ + class ARAP_visitor + { double m_nb_edges_incident; double m_area; double m_alpha; @@ -105,7 +128,6 @@ struct Types_selectors { public: ARAP_visitor(): m_alpha(0.02) {} - template void init(TriangleMesh triangle_mesh, const VertexPointMap& vpmap) { // calculate area @@ -144,31 +166,6 @@ struct Types_selectors { }; }; -// property map that create a Simple_cartesian::Point_3 -// on the fly in order the deformation class to be used -// with points with minimal requirements -template -struct SC_on_the_fly_pmap - : public Vertex_point_map -{ - typedef boost::readable_property_map_tag category; - typedef CGAL::Simple_cartesian::Point_3 value_type; - typedef value_type reference; - typedef typename boost::property_traits::key_type key_type; - - SC_on_the_fly_pmap(Vertex_point_map base): - Vertex_point_map(base) {} - - friend value_type - get(const SC_on_the_fly_pmap map, key_type k) - { - typename boost::property_traits::reference base= - get(static_cast(map), k); - return value_type(base[0], base[1], base[2]); - } -}; - - }//namespace internal /// @endcond @@ -235,17 +232,6 @@ public: typedef HIM Hedge_index_map; #endif -// weight calculator -#ifndef DOXYGEN_RUNNING - typedef typename Default::Get< - WC, - typename internal::Types_selectors::Weight_calculator - >::type Weight_calculator; -#else - /// weight calculator functor type - typedef WC Weight_calculator; -#endif - // sparse linear solver #ifndef DOXYGEN_RUNNING typedef typename Default::Get< @@ -290,6 +276,17 @@ public: typedef VPM Vertex_point_map; #endif +// weight calculator +#ifndef DOXYGEN_RUNNING + typedef typename Default::Get< + WC, + typename internal::Types_selectors::Weight_calculator + >::type Weight_calculator; +#else + /// weight calculator functor type + typedef WC Weight_calculator; +#endif + /// The type for vertex descriptor typedef typename boost::graph_traits::vertex_descriptor vertex_descriptor; /// The type for halfedge descriptor @@ -304,8 +301,6 @@ public: private: typedef Surface_mesh_deformation Self; // Repeat Triangle_mesh types - typedef typename boost::graph_traits::vertex_iterator vertex_iterator; - typedef typename boost::graph_traits::halfedge_iterator halfedge_iterator; typedef typename boost::graph_traits::in_edge_iterator in_edge_iterator; typedef typename boost::graph_traits::out_edge_iterator out_edge_iterator; @@ -340,12 +335,11 @@ private: bool last_preprocess_successful; ///< stores the result of last call to preprocess() + Vertex_point_map vertex_point_map; Weight_calculator weight_calculator; - Vertex_point_map vertex_point_map; - public: - typename internal::Types_selectors::ARAP_visitor arap_visitor; + typename internal::Types_selectors::ARAP_visitor arap_visitor; private: #ifdef CGAL_DEFORM_MESH_USE_EXPERIMENTAL_SCALE @@ -359,68 +353,13 @@ public: public: /// \cond SKIP_FROM_MANUAL - //vertex_point_map set by default - Surface_mesh_deformation(Triangle_mesh& triangle_mesh, - Vertex_index_map vertex_index_map, - Hedge_index_map hedge_index_map) - : m_triangle_mesh(triangle_mesh), - vertex_index_map(vertex_index_map), - hedge_index_map(hedge_index_map), - ros_id_map(std::vector(num_vertices(triangle_mesh), (std::numeric_limits::max)() )), - is_roi_map(std::vector(num_vertices(triangle_mesh), false)), - is_ctrl_map(std::vector(num_vertices(triangle_mesh), false)), - m_iterations(5), m_tolerance(1e-4), - need_preprocess_factorization(true), - need_preprocess_region_of_solution(true), - last_preprocess_successful(false), - weight_calculator(Weight_calculator()), - vertex_point_map(get(vertex_point, triangle_mesh)) - { - init(); - } - - //vertex_point_map and hedge_index_map set by default - Surface_mesh_deformation(Triangle_mesh& triangle_mesh, - Vertex_index_map vertex_index_map) - : m_triangle_mesh(triangle_mesh), - vertex_index_map(vertex_index_map), - hedge_index_map(CGAL::get_initialized_halfedge_index_map(triangle_mesh)), - ros_id_map(std::vector(num_vertices(triangle_mesh), (std::numeric_limits::max)() )), - is_roi_map(std::vector(num_vertices(triangle_mesh), false)), - is_ctrl_map(std::vector(num_vertices(triangle_mesh), false)), - m_iterations(5), m_tolerance(1e-4), - need_preprocess_factorization(true), - need_preprocess_region_of_solution(true), - last_preprocess_successful(false), - weight_calculator(Weight_calculator()), - vertex_point_map(get(vertex_point, triangle_mesh)) - { - init(); - } - //vertex_point_map, hedge_index_map and vertex_index_map set by default - Surface_mesh_deformation(Triangle_mesh& triangle_mesh) - : m_triangle_mesh(triangle_mesh), - vertex_index_map(CGAL::get_initialized_vertex_index_map(triangle_mesh)), - hedge_index_map(CGAL::get_initialized_halfedge_index_map(triangle_mesh)), - ros_id_map(std::vector(num_vertices(triangle_mesh), (std::numeric_limits::max)() )), - is_roi_map(std::vector(num_vertices(triangle_mesh), false)), - is_ctrl_map(std::vector(num_vertices(triangle_mesh), false)), - m_iterations(5), m_tolerance(1e-4), - need_preprocess_factorization(true), - need_preprocess_region_of_solution(true), - last_preprocess_successful(false), - weight_calculator(Weight_calculator()), - vertex_point_map(get(vertex_point, triangle_mesh)) - { - init(); - } // Constructor with all the parameters provided Surface_mesh_deformation(Triangle_mesh& triangle_mesh, Vertex_index_map vertex_index_map, Hedge_index_map hedge_index_map, Vertex_point_map vertex_point_map, - Weight_calculator weight_calculator = Weight_calculator()) + Weight_calculator weight_calculator) : m_triangle_mesh(triangle_mesh), vertex_index_map(vertex_index_map), hedge_index_map(hedge_index_map), @@ -431,13 +370,47 @@ public: need_preprocess_factorization(true), need_preprocess_region_of_solution(true), last_preprocess_successful(false), - weight_calculator(weight_calculator), - vertex_point_map(vertex_point_map) + vertex_point_map(vertex_point_map), + weight_calculator(weight_calculator) { init(); } + + Surface_mesh_deformation(Triangle_mesh& triangle_mesh, + Vertex_index_map vertex_index_map, + Hedge_index_map hedge_index_map, + Vertex_point_map vertex_point_map) + : Surface_mesh_deformation(triangle_mesh, + vertex_index_map, + hedge_index_map, + vertex_point_map, + Weight_calculator(triangle_mesh, internal::SC_on_the_fly_pmap(vertex_point_map))) + { } + + Surface_mesh_deformation(Triangle_mesh& triangle_mesh, + Vertex_index_map vertex_index_map, + Hedge_index_map hedge_index_map) + : Surface_mesh_deformation(triangle_mesh, + vertex_index_map, + hedge_index_map, + get(vertex_point, triangle_mesh)) + { } + + Surface_mesh_deformation(Triangle_mesh& triangle_mesh, + Vertex_index_map vertex_index_map) + : Surface_mesh_deformation(triangle_mesh, + vertex_index_map, + CGAL::get_initialized_halfedge_index_map(triangle_mesh)) + { } + + Surface_mesh_deformation(Triangle_mesh& triangle_mesh) + : Surface_mesh_deformation(triangle_mesh, + CGAL::get_initialized_vertex_index_map(triangle_mesh)) + { } + /// \endcond - #if DOXYGEN_RUNNING + +#if DOXYGEN_RUNNING /// \name Construction /// @{ /** @@ -457,21 +430,17 @@ public: Vertex_index_map vertex_index_map = unspecified_internal_vertex_index_map, Hedge_index_map hedge_index_map = unspecified_internal_halfedge_index_map, Vertex_point_map vertex_point_map = get(boost::vertex_point, triangle_mesh), - Weight_calculator weight_calculator = Weight_calculator()); + Weight_calculator weight_calculator = Weight_calculator(triangle_mesh, vertex_point_map)); /// @} #endif private: - void init() { - typedef internal::SC_on_the_fly_pmap Wrapper; - // compute halfedge weights - halfedge_iterator eb, ee; - hedge_weight.reserve(2*num_edges(m_triangle_mesh)); - for(std::tie(eb, ee) = halfedges(m_triangle_mesh); eb != ee; ++eb) - { - hedge_weight.push_back( - this->weight_calculator(*eb, m_triangle_mesh, Wrapper(vertex_point_map))); - } + void init() + { + hedge_weight.reserve(num_halfedges(m_triangle_mesh)); + for(halfedge_descriptor he : halfedges(m_triangle_mesh)) + hedge_weight.push_back(this->weight_calculator(he)); + arap_visitor.init(m_triangle_mesh, vertex_point_map); } @@ -854,7 +823,6 @@ public: */ void overwrite_initial_geometry() { - typedef internal::SC_on_the_fly_pmap Wrapper; if(roi.empty()) { return; } // no ROI to overwrite region_of_solution(); // the roi should be preprocessed since we are using original_position vec @@ -875,13 +843,13 @@ public: std::size_t id_e = id(he); if(is_weight_computed[id_e]) { continue; } - hedge_weight[id_e] = weight_calculator(he, m_triangle_mesh, Wrapper(vertex_point_map)); + hedge_weight[id_e] = weight_calculator(he); is_weight_computed[id_e] = true; halfedge_descriptor e_opp = opposite(he, m_triangle_mesh); std::size_t id_e_opp = id(e_opp); - hedge_weight[id_e_opp] = weight_calculator(e_opp, m_triangle_mesh, Wrapper(vertex_point_map)); + hedge_weight[id_e_opp] = weight_calculator(e_opp); is_weight_computed[id_e_opp] = true; } } diff --git a/Surface_mesh_parameterization/include/CGAL/Surface_mesh_parameterization/ARAP_parameterizer_3.h b/Surface_mesh_parameterization/include/CGAL/Surface_mesh_parameterization/ARAP_parameterizer_3.h index 65bd6659902..21d42cf360d 100644 --- a/Surface_mesh_parameterization/include/CGAL/Surface_mesh_parameterization/ARAP_parameterizer_3.h +++ b/Surface_mesh_parameterization/include/CGAL/Surface_mesh_parameterization/ARAP_parameterizer_3.h @@ -458,6 +458,7 @@ private: const Faces_vector& faces, Cot_map ctmap) const { + // Since we loop faces, we are implicitely defining the weight of border halfedges as 0... for(face_descriptor fd : faces) { halfedge_descriptor hd = halfedge(fd, mesh), hdb = hd; diff --git a/Surface_mesh_parameterization/include/CGAL/Surface_mesh_parameterization/Discrete_authalic_parameterizer_3.h b/Surface_mesh_parameterization/include/CGAL/Surface_mesh_parameterization/Discrete_authalic_parameterizer_3.h index ec6df820e80..a6c7b410a57 100644 --- a/Surface_mesh_parameterization/include/CGAL/Surface_mesh_parameterization/Discrete_authalic_parameterizer_3.h +++ b/Surface_mesh_parameterization/include/CGAL/Surface_mesh_parameterization/Discrete_authalic_parameterizer_3.h @@ -187,7 +187,7 @@ protected: ++next_vertex_v_l; const Point_3& position_v_l = get(ppmap, *next_vertex_v_l); - return CGAL::Weights::authalic_weight(position_v_k, position_v_j, position_v_l, position_v_i) / NT(2); + return CGAL::Weights::authalic_weight(position_v_l, position_v_j, position_v_k, position_v_i) / NT(2); } }; diff --git a/Surface_mesh_parameterization/include/CGAL/Surface_mesh_parameterization/Discrete_conformal_map_parameterizer_3.h b/Surface_mesh_parameterization/include/CGAL/Surface_mesh_parameterization/Discrete_conformal_map_parameterizer_3.h index 554ce4bf65b..7787476e654 100644 --- a/Surface_mesh_parameterization/include/CGAL/Surface_mesh_parameterization/Discrete_conformal_map_parameterizer_3.h +++ b/Surface_mesh_parameterization/include/CGAL/Surface_mesh_parameterization/Discrete_conformal_map_parameterizer_3.h @@ -183,7 +183,7 @@ protected: ++next_vertex_v_l; const Point_3& position_v_l = get(ppmap, *next_vertex_v_l); - return CGAL::Weights::cotangent_weight(position_v_k, position_v_j, position_v_l, position_v_i) / NT(2); + return CGAL::Weights::cotangent_weight(position_v_l, position_v_j, position_v_k, position_v_i) / NT(2); } }; diff --git a/Surface_mesh_parameterization/include/CGAL/Surface_mesh_parameterization/Iterative_authalic_parameterizer_3.h b/Surface_mesh_parameterization/include/CGAL/Surface_mesh_parameterization/Iterative_authalic_parameterizer_3.h index 24cf892b964..a8f1941a189 100644 --- a/Surface_mesh_parameterization/include/CGAL/Surface_mesh_parameterization/Iterative_authalic_parameterizer_3.h +++ b/Surface_mesh_parameterization/include/CGAL/Surface_mesh_parameterization/Iterative_authalic_parameterizer_3.h @@ -454,7 +454,7 @@ private: double weight; }; - NT determinant(Point_2& v0, Point_2& v1) const + NT determinant(const Point_2& v0, const Point_2& v1) const { return (v0.x() * v1.y() - v1.x() * v0.y()); } @@ -465,8 +465,8 @@ private: const NT det0 = determinant(uv1, uv2); const NT det1 = determinant(uv2, uv0); const NT det2 = determinant(uv0, uv1); - const NT det3 = CGAL::determinant(Vector_2(uv1.x()-uv0.x(), uv1.y()-uv0.y()), - Vector_2(uv2.x()-uv0.x(), uv2.y()-uv0.y())); + NT det3 = CGAL::determinant(Vector_2(uv1.x()-uv0.x(), uv1.y()-uv0.y()), + Vector_2(uv2.x()-uv0.x(), uv2.y()-uv0.y())); CGAL_assertion(det3 > NT(0)); if(det3 <= NT(0)) det3 = NT(1); @@ -503,7 +503,7 @@ private: { Neighbor_list NL; NL.vertex = *v_j; - NL.vector = Vector_3(get(ppmap, v), tmesh.point(*v_j)); + NL.vector = Vector_3(get(ppmap, v), get(ppmap, *v_j)); NL.length = sqrt(NL.vector.squared_length()); neighbor_list.push_back(NL); ++neighborsCounter; @@ -617,9 +617,6 @@ private: const PPM_ref position_v_i = get(ppmap, main_vertex_v_i); const PPM_ref position_v_j = get(ppmap, *neighbor_vertex_v_j); - const Vector_3 edge = position_v_i - position_v_j; - const NT squared_length = edge * edge; - vertex_around_target_circulator previous_vertex_v_k = neighbor_vertex_v_j; --previous_vertex_v_k; const PPM_ref position_v_k = get(ppmap, *previous_vertex_v_k); @@ -628,14 +625,10 @@ private: ++next_vertex_v_l; const PPM_ref position_v_l = get(ppmap, *next_vertex_v_l); - NT weight = NT(0); - CGAL_assertion(squared_length > NT(0)); // two points are identical! - if(squared_length != NT(0)) { - // This version was commented out to be an alternative weight - // in the original code by authors. - // weight = CGAL::Weights::authalic_weight(position_v_k, position_v_j, position_v_l, position_v_i) / NT(2); - weight = CGAL::Weights::cotangent_weight(position_v_k, position_v_j, position_v_l, position_v_i) / NT(2); - } + // This version was commented out to be an alternative weight in the original code by authors. +// NT weight = CGAL::Weights::authalic_weight(position_v_l, position_v_j, position_v_k, position_v_i) / NT(2); + NT weight = CGAL::Weights::cotangent_weight(position_v_l, position_v_j, position_v_k, position_v_i) / NT(2); + return weight; } @@ -699,7 +692,7 @@ private: VertexIndexMap& vimap) const { auto vpm = get_const_property_map(CGAL::vertex_point, tmesh); - const CGAL::Weights::Edge_tangent_weight compute_mvc(tmesh, vpm); + const CGAL::Weights::Edge_tangent_weight weight_calc(tmesh, vpm, Kernel()); const int i = get(vimap, v); @@ -709,7 +702,7 @@ private: for(halfedge_descriptor h : CGAL::halfedges_around_target(v, tmesh)) { - NT w_ij = NT(-1) * compute_mvc(h); + NT w_ij = NT(-1) * weight_calc(h); // w_ii = - sum of w_ijs w_ii -= w_ij; diff --git a/Surface_mesh_parameterization/include/CGAL/Surface_mesh_parameterization/Mean_value_coordinates_parameterizer_3.h b/Surface_mesh_parameterization/include/CGAL/Surface_mesh_parameterization/Mean_value_coordinates_parameterizer_3.h index 019fcb20262..bacdd2ea12c 100644 --- a/Surface_mesh_parameterization/include/CGAL/Surface_mesh_parameterization/Mean_value_coordinates_parameterizer_3.h +++ b/Surface_mesh_parameterization/include/CGAL/Surface_mesh_parameterization/Mean_value_coordinates_parameterizer_3.h @@ -206,7 +206,7 @@ protected: ++next_vertex_v_l; const Point_3& position_v_l = get(ppmap, *next_vertex_v_l); - return CGAL::Weights::tangent_weight(position_v_k, position_v_j, position_v_l, position_v_i) / NT(2); + return CGAL::Weights::tangent_weight(position_v_l, position_v_j, position_v_k, position_v_i) / NT(2); } }; diff --git a/Surface_mesh_parameterization/include/CGAL/Surface_mesh_parameterization/Orbifold_Tutte_parameterizer_3.h b/Surface_mesh_parameterization/include/CGAL/Surface_mesh_parameterization/Orbifold_Tutte_parameterizer_3.h index 39070956d64..10639df65e6 100644 --- a/Surface_mesh_parameterization/include/CGAL/Surface_mesh_parameterization/Orbifold_Tutte_parameterizer_3.h +++ b/Surface_mesh_parameterization/include/CGAL/Surface_mesh_parameterization/Orbifold_Tutte_parameterizer_3.h @@ -782,9 +782,13 @@ private: const int i = get(vimap, vi); const int j = get(vimap, vj); - if (i > j) continue; - const CGAL::Weights::Cotangent_weight cotangent_weight; - const NT w_ij = NT(2) * cotangent_weight(hd, mesh, pmap); + if (i > j) + continue; + + const CGAL::Weights::Cotangent_weight cotangent_weight(mesh, pmap); + + // x2 because Cotangent_weight returns 0.5 * (cot alpha + cot beta)... + const NT w_ij = NT(2) * cotangent_weight(hd); // ij M.set_coef(2*i, 2*j, w_ij, true /* new coef */); diff --git a/Surface_mesh_skeletonization/include/CGAL/Mean_curvature_flow_skeletonization.h b/Surface_mesh_skeletonization/include/CGAL/Mean_curvature_flow_skeletonization.h index 3c11f859619..cdf6e6f940b 100644 --- a/Surface_mesh_skeletonization/include/CGAL/Mean_curvature_flow_skeletonization.h +++ b/Surface_mesh_skeletonization/include/CGAL/Mean_curvature_flow_skeletonization.h @@ -235,7 +235,7 @@ public: typedef typename boost::graph_traits::edge_iterator edge_iterator; // Get weight from the weight interface. - typedef CGAL::Weights::Cotangent_weight Weight_calculator; + typedef CGAL::Weights::Cotangent_weight Weight_calculator; typedef internal::Curve_skeleton Vertex_pair; std::vector v2v; copy_face_graph(tmesh, m_tmesh, - CGAL::parameters::vertex_to_vertex_output_iterator( - std::back_inserter(v2v)).vertex_point_map(vpm)); + CGAL::parameters::vertex_to_vertex_output_iterator(std::back_inserter(v2v)) + .vertex_point_map(vpm)); // copy input vertices to keep correspondence for(const Vertex_pair& vp : v2v) @@ -919,11 +921,9 @@ private: void compute_edge_weight() { m_edge_weight.clear(); - m_edge_weight.reserve(2 * num_edges(m_tmesh)); + m_edge_weight.reserve(num_halfedges(m_tmesh)); for(halfedge_descriptor hd : halfedges(m_tmesh)) - { - m_edge_weight.push_back(m_weight_calculator(hd, m_tmesh, m_tmesh_point_pmap)); - } + m_edge_weight.push_back(m_weight_calculator(hd)); } /// Assemble the left hand side. diff --git a/Weights/doc/Weights/PackageDescription.txt b/Weights/doc/Weights/PackageDescription.txt index e4b66502338..a2cd0632d19 100644 --- a/Weights/doc/Weights/PackageDescription.txt +++ b/Weights/doc/Weights/PackageDescription.txt @@ -101,7 +101,7 @@ a model of `AnalyticWeightTraits_3` for 3D points \endverbatim This weight is computed as -\f$w = \frac{d_2^a A_1 - d^a B + d_1^a A_2}{A_1 A_2}\f$ +\f$w = \frac{d_2^a A_0 - d^a B + d_0^a A_2}{A_0 A_2}\f$ with notations shown in the figure below and \f$a\f$ any real number being the power parameter. @@ -142,7 +142,7 @@ a model of `AnalyticWeightTraits_3` for 3D points \endverbatim This weight is computed as -\f$w = \frac{C}{A_1 A_2}\f$ +\f$w = \frac{C}{A_0 A_2}\f$ with notations shown in the figure below. Here, `q` is a query point and the points `p0`, `p1`, and `p2` are its neighbors. @@ -207,10 +207,10 @@ a model of `AnalyticWeightTraits_3` for 3D points \endverbatim This weight is computed as -\f$w = \pm 2 \sqrt{\frac{2 (d_1 d_2 - D)}{(d d_1 + D_1)(d d_2 + D_2)}}\f$ +\f$w = \pm 2 \sqrt{\frac{2 (d_0 d_2 - D)}{(d d_0 + D_0)(d d_2 + D_2)}}\f$ with notations shown in the figure below and dot products -\f$D_1 = (p_0 - q) \cdot (p_1 - q)\f$, +\f$D_0 = (p_0 - q) \cdot (p_1 - q)\f$, \f$D_2 = (p_1 - q) \cdot (p_2 - q)\f$, and \f$D = (p_0 - q) \cdot (p_2 - q)\f$. @@ -247,11 +247,11 @@ a model of `AnalyticWeightTraits_3` for 3D points This weight is computed as \f$w = 2 \frac{t_1 + t_2}{d}\f$, where -\f$t_1 = \frac{2 A_1}{d d_1 + D_1}\f$ and +\f$t_1 = \frac{2 A_0}{d d_0 + D_0}\f$ and \f$t_2 = \frac{2 A_2}{d d_2 + D_2}\f$ with notations shown in the figure below and dot products -\f$D_1 = (p_0 - q) \cdot (p_1 - q)\f$ and +\f$D_0 = (p_0 - q) \cdot (p_1 - q)\f$ and \f$D_2 = (p_1 - q) \cdot (p_2 - q)\f$. Here, `q` is a query point and the points `p0`, `p1`, and `p2` are its neighbors. @@ -283,7 +283,7 @@ a model of `AnalyticWeightTraits_3` for 3D points \endverbatim This weight is computed as -\f$w = \frac{d_2^2 A_1 - d^2 B + d_1^2 A_2}{A_1 A_2}\f$ +\f$w = \frac{d_2^2 A_0 - d^2 B + d_0^2 A_2}{A_0 A_2}\f$ with notations shown in the figure below. Here, `q` is a query point and the points `p0`, `p1`, and `p2` are its neighbors. diff --git a/Weights/doc/Weights/fig/discrete_harmonic.svg b/Weights/doc/Weights/fig/discrete_harmonic.svg index 21fdafc5cd7..08c74518014 100644 --- a/Weights/doc/Weights/fig/discrete_harmonic.svg +++ b/Weights/doc/Weights/fig/discrete_harmonic.svg @@ -1,235 +1,439 @@ - + - - diff --git a/Weights/doc/Weights/fig/mean_value.svg b/Weights/doc/Weights/fig/mean_value.svg index 0e40e87eaef..d102c8d130f 100644 --- a/Weights/doc/Weights/fig/mean_value.svg +++ b/Weights/doc/Weights/fig/mean_value.svg @@ -1,79 +1,163 @@ - + - - diff --git a/Weights/doc/Weights/fig/tangent.svg b/Weights/doc/Weights/fig/tangent.svg index a52fcf03170..9ee59f419e8 100644 --- a/Weights/doc/Weights/fig/tangent.svg +++ b/Weights/doc/Weights/fig/tangent.svg @@ -1,93 +1,174 @@ - + - - diff --git a/Weights/doc/Weights/fig/three_point_family.svg b/Weights/doc/Weights/fig/three_point_family.svg index 21fdafc5cd7..079ce8129b1 100644 --- a/Weights/doc/Weights/fig/three_point_family.svg +++ b/Weights/doc/Weights/fig/three_point_family.svg @@ -1,235 +1,433 @@ - + - - diff --git a/Weights/doc/Weights/fig/wachspress.svg b/Weights/doc/Weights/fig/wachspress.svg index cc751743d65..2b79da2a60b 100644 --- a/Weights/doc/Weights/fig/wachspress.svg +++ b/Weights/doc/Weights/fig/wachspress.svg @@ -1,244 +1,439 @@ - + - - diff --git a/Weights/examples/Weights/convergence.cpp b/Weights/examples/Weights/convergence.cpp index 8cc85915531..83bb06ebe83 100644 --- a/Weights/examples/Weights/convergence.cpp +++ b/Weights/examples/Weights/convergence.cpp @@ -1,5 +1,4 @@ #include -#include #include // Typedefs. diff --git a/Weights/examples/Weights/weighted_laplacian.cpp b/Weights/examples/Weights/weighted_laplacian.cpp index bd44f1fb0ea..af3e4345b41 100644 --- a/Weights/examples/Weights/weighted_laplacian.cpp +++ b/Weights/examples/Weights/weighted_laplacian.cpp @@ -20,18 +20,18 @@ using HD = boost::graph_traits::halfedge_descriptor; template FT get_w_ij(const Mesh& mesh, const HD he, const PointMap pmap) { - const auto v0 = target(he, mesh); - const auto v1 = source(he, mesh); + const VD v0 = target(he, mesh); + const VD v1 = source(he, mesh); const auto& q = get(pmap, v0); // query const auto& p1 = get(pmap, v1); // neighbor j if (is_border_edge(he, mesh)) { - const auto he_cw = opposite(next(he, mesh), mesh); - auto v2 = source(he_cw, mesh); + const HD he_cw = opposite(next(he, mesh), mesh); + VD v2 = source(he_cw, mesh); if (is_border_edge(he_cw, mesh)) { - const auto he_ccw = prev(opposite(he, mesh), mesh); + const HD he_ccw = prev(opposite(he, mesh), mesh); v2 = source(he_ccw, mesh); const auto& p2 = get(pmap, v2); // neighbor jp @@ -42,10 +42,10 @@ FT get_w_ij(const Mesh& mesh, const HD he, const PointMap pmap) { } } - const auto he_cw = opposite(next(he, mesh), mesh); - const auto v2 = source(he_cw, mesh); - const auto he_ccw = prev(opposite(he, mesh), mesh); - const auto v3 = source(he_ccw, mesh); + const HD he_cw = opposite(next(he, mesh), mesh); + const VD v2 = source(he_cw, mesh); + const HD he_ccw = prev(opposite(he, mesh), mesh); + const VD v3 = source(he_ccw, mesh); const auto& p0 = get(pmap, v2); // neighbor jm const auto& p2 = get(pmap, v3); // neighbor jp @@ -56,14 +56,14 @@ template FT get_w_i(const Mesh& mesh, const VD v_i, const PointMap pmap) { FT A_i = 0.0; - const auto v0 = v_i; - const auto init = halfedge(v_i, mesh); - for (const auto& he : halfedges_around_target(init, mesh)) { + const VD v0 = v_i; + const HD init = halfedge(v_i, mesh); + for (const HD he : halfedges_around_target(init, mesh)) { assert(v0 == target(he, mesh)); if (is_border(he, mesh)) { continue; } - const auto v1 = source(he, mesh); - const auto v2 = target(next(he, mesh), mesh); + const VD v1 = source(he, mesh); + const VD v2 = target(next(he, mesh), mesh); const auto& p = get(pmap, v0); const auto& q = get(pmap, v1); @@ -81,14 +81,14 @@ void set_laplacian_matrix(const Mesh& mesh, Matrix& L) { // Precompute Voronoi areas. std::map w_i; - for (const auto& v_i : vertices(mesh)) { + for (const VD v_i : vertices(mesh)) { w_i[get(imap, v_i)] = get_w_i(mesh, v_i, pmap); } // Fill the matrix. - for (const auto& he : halfedges(mesh)) { - const auto vi = source(he, mesh); - const auto vj = target(he, mesh); + for (const HD he : halfedges(mesh)) { + const VD vi = source(he, mesh); + const VD vj = target(he, mesh); const std::size_t i = get(imap, vi); const std::size_t j = get(imap, vj); @@ -106,11 +106,11 @@ int main() { // Create mesh. Mesh mesh; - const auto v0 = mesh.add_vertex(Point_3(0, 2, 0)); - const auto v1 = mesh.add_vertex(Point_3(2, 2, 0)); - const auto v2 = mesh.add_vertex(Point_3(0, 0, 0)); - const auto v3 = mesh.add_vertex(Point_3(2, 0, 0)); - const auto v4 = mesh.add_vertex(Point_3(1, 1, 1)); + const VD v0 = mesh.add_vertex(Point_3(0, 2, 0)); + const VD v1 = mesh.add_vertex(Point_3(2, 2, 0)); + const VD v2 = mesh.add_vertex(Point_3(0, 0, 0)); + const VD v3 = mesh.add_vertex(Point_3(2, 0, 0)); + const VD v4 = mesh.add_vertex(Point_3(1, 1, 1)); mesh.add_face(v0, v2, v4); mesh.add_face(v2, v3, v4); mesh.add_face(v3, v1, v4); diff --git a/Weights/include/CGAL/Weights/authalic_weights.h b/Weights/include/CGAL/Weights/authalic_weights.h index 5b76f7a9480..8c3eede9a25 100644 --- a/Weights/include/CGAL/Weights/authalic_weights.h +++ b/Weights/include/CGAL/Weights/authalic_weights.h @@ -14,186 +14,147 @@ #ifndef CGAL_AUTHALIC_WEIGHTS_H #define CGAL_AUTHALIC_WEIGHTS_H -// Internal includes. -#include +#include + +#include +#include namespace CGAL { namespace Weights { - /// \cond SKIP_IN_MANUAL - namespace authalic_ns { +/// \cond SKIP_IN_MANUAL - template - FT half_weight(const FT cot, const FT r2) { +namespace authalic_ns { - FT w = FT(0); - CGAL_precondition(r2 != FT(0)); - if (r2 != FT(0)) { - const FT inv = FT(2) / r2; - w = cot * inv; - } - return w; - } +template +FT half_weight(const FT cot, const FT r2) +{ + FT w = FT(0); + CGAL_precondition(!is_zero(r2)); + if (!is_zero(r2)) + w = FT(2) * cot / r2; - template - FT weight(const FT cot_gamma, const FT cot_beta, const FT r2) { + return w; +} - FT w = FT(0); - CGAL_precondition(r2 != FT(0)); - if (r2 != FT(0)) { - const FT inv = FT(2) / r2; - w = (cot_gamma + cot_beta) * inv; - } - return w; - } - } - /// \endcond +template +FT weight(const FT cot_gamma, const FT cot_beta, const FT r2) +{ + FT w = FT(0); + CGAL_precondition(!is_zero(r2)); + if (!is_zero(r2)) + w = FT(2) * (cot_gamma + cot_beta) / r2; - /*! - \ingroup PkgWeightsRefAuthalicWeights + return w; +} - \brief computes the half value of the authalic weight. +} // namespace authalic_ns - This function constructs the half of the authalic weight using the precomputed - cotangent and squared distance values. The returned value is - \f$\frac{2\textbf{cot}}{\textbf{d2}}\f$. +/// \endcond - \tparam FT - a model of `FieldNumberType` +/*! + \ingroup PkgWeightsRefAuthalicWeights - \param cot - the cotangent value + \brief computes the half value of the authalic weight. - \param d2 - the squared distance value + This function computes the half of the authalic weight using the precomputed + cotangent and squared distance values. The returned value is + \f$\frac{2\textbf{cot}}{\textbf{sq_d}}\f$. - \pre d2 != 0 + \tparam FT a model of `FieldNumberType` - \sa `authalic_weight()` - */ - template - FT half_authalic_weight(const FT cot, const FT d2) { - return authalic_ns::half_weight(cot, d2); - } + \param cot the cotangent value + \param sq_d the squared distance value - #if defined(DOXYGEN_RUNNING) + \pre sq_d != 0 - /*! - \ingroup PkgWeightsRefAuthalicWeights + \sa `authalic_weight()` +*/ +template +FT half_authalic_weight(const FT cot, const FT sq_d) +{ + return authalic_ns::half_weight(cot, sq_d); +} - \brief computes the authalic weight in 2D at `q` using the points `p0`, `p1`, - and `p2`, given a traits class `traits` with geometric objects, predicates, and constructions. - */ - template - typename GeomTraits::FT authalic_weight( - const typename GeomTraits::Point_2& p0, - const typename GeomTraits::Point_2& p1, - const typename GeomTraits::Point_2& p2, - const typename GeomTraits::Point_2& q, - const GeomTraits& traits) { } +// 2D ============================================================================================== - /*! - \ingroup PkgWeightsRefAuthalicWeights +/*! + \ingroup PkgWeightsRefAuthalicWeights + \brief computes the authalic weight in 2D at `q` using the points `p0`, `p1`, and `p2`. + \tparam GeomTraits a model of `AnalyticWeightTraits_2` +*/ +template +typename GeomTraits::FT authalic_weight(const typename GeomTraits::Point_2& p0, + const typename GeomTraits::Point_2& p1, + const typename GeomTraits::Point_2& p2, + const typename GeomTraits::Point_2& q, + const GeomTraits& traits) +{ + using FT = typename GeomTraits::FT; - \brief computes the authalic weight in 3D at `q` using the points `p0`, `p1`, - and `p2`, given a traits class `traits` with geometric objects, predicates, and constructions. - */ - template - typename GeomTraits::FT authalic_weight( - const typename GeomTraits::Point_3& p0, - const typename GeomTraits::Point_3& p1, - const typename GeomTraits::Point_3& p2, - const typename GeomTraits::Point_3& q, - const GeomTraits& traits) { } + const FT cot_gamma = cotangent_2(p0, p1, q, traits); + const FT cot_beta = cotangent_2(q, p1, p2, traits); - /*! - \ingroup PkgWeightsRefAuthalicWeights + auto squared_distance_2 = traits.compute_squared_distance_2_object(); + const FT sq_d = squared_distance_2(q, p1); - \brief computes the authalic weight in 2D at `q` using the points `p0`, `p1`, - and `p2` which are parameterized by a `Kernel` K. - */ - template - typename K::FT authalic_weight( - const CGAL::Point_2& p0, - const CGAL::Point_2& p1, - const CGAL::Point_2& p2, - const CGAL::Point_2& q) { } + return authalic_ns::weight(cot_gamma, cot_beta, sq_d); +} - /*! - \ingroup PkgWeightsRefAuthalicWeights +/*! + \ingroup PkgWeightsRefAuthalicWeights + \brief computes the authalic weight in 2D at `q` using the points `p0`, `p1`, and `p2`. + \tparam Kernel a model of `Kernel` +*/ +template +typename Kernel::FT authalic_weight(const CGAL::Point_2& p0, + const CGAL::Point_2& p1, + const CGAL::Point_2& p2, + const CGAL::Point_2& q) +{ + const Kernel traits; + return authalic_weight(p0, p1, p2, q, traits); +} - \brief computes the authalic weight in 3D at `q` using the points `p0`, `p1`, - and `p2` which are parameterized by a `Kernel` K. - */ - template - typename K::FT authalic_weight( - const CGAL::Point_3& p0, - const CGAL::Point_3& p1, - const CGAL::Point_3& p2, - const CGAL::Point_3& q) { } +// 3D ============================================================================================== - #endif // DOXYGEN_RUNNING +/*! + \ingroup PkgWeightsRefAuthalicWeights + \brief computes the authalic weight in 3D at `q` using the points `p0`, `p1`, and `p2`. + \tparam GeomTraits a model of `AnalyticWeightTraits_3` +*/ +template +typename GeomTraits::FT authalic_weight(const typename GeomTraits::Point_3& p0, + const typename GeomTraits::Point_3& p1, + const typename GeomTraits::Point_3& p2, + const typename GeomTraits::Point_3& q, + const GeomTraits& traits) +{ + using FT = typename GeomTraits::FT; - /// \cond SKIP_IN_MANUAL - // Overloads! - template - typename GeomTraits::FT authalic_weight( - const typename GeomTraits::Point_2& t, - const typename GeomTraits::Point_2& r, - const typename GeomTraits::Point_2& p, - const typename GeomTraits::Point_2& q, - const GeomTraits& traits) { + const FT cot_gamma = cotangent_3(p0, p1, q, traits); + const FT cot_beta = cotangent_3(q, p1, p2, traits); - using FT = typename GeomTraits::FT; - const FT cot_gamma = internal::cotangent_2(traits, t, r, q); - const FT cot_beta = internal::cotangent_2(traits, q, r, p); + auto squared_distance_3 = traits.compute_squared_distance_3_object(); + const FT sq_d = squared_distance_3(q, p1); - const auto squared_distance_2 = - traits.compute_squared_distance_2_object(); - const FT d2 = squared_distance_2(q, r); - return authalic_ns::weight(cot_gamma, cot_beta, d2); - } + return authalic_ns::weight(cot_gamma, cot_beta, sq_d); +} - template - typename GeomTraits::FT authalic_weight( - const CGAL::Point_2& t, - const CGAL::Point_2& r, - const CGAL::Point_2& p, - const CGAL::Point_2& q) { - - const GeomTraits traits; - return authalic_weight(t, r, p, q, traits); - } - - template - typename GeomTraits::FT authalic_weight( - const typename GeomTraits::Point_3& t, - const typename GeomTraits::Point_3& r, - const typename GeomTraits::Point_3& p, - const typename GeomTraits::Point_3& q, - const GeomTraits& traits) { - - using FT = typename GeomTraits::FT; - const FT cot_gamma = internal::cotangent_3(traits, t, r, q); - const FT cot_beta = internal::cotangent_3(traits, q, r, p); - - const auto squared_distance_3 = - traits.compute_squared_distance_3_object(); - const FT d2 = squared_distance_3(q, r); - return authalic_ns::weight(cot_gamma, cot_beta, d2); - } - - template - typename GeomTraits::FT authalic_weight( - const CGAL::Point_3& t, - const CGAL::Point_3& r, - const CGAL::Point_3& p, - const CGAL::Point_3& q) { - - const GeomTraits traits; - return authalic_weight(t, r, p, q, traits); - } - /// \endcond +/*! + \ingroup PkgWeightsRefAuthalicWeights + \brief computes the authalic weight in 3D at `q` using the points `p0`, `p1`, and `p2`. + \tparam Kernel a model of `Kernel` +*/ +template +typename Kernel::FT authalic_weight(const CGAL::Point_3& p0, + const CGAL::Point_3& p1, + const CGAL::Point_3& p2, + const CGAL::Point_3& q) +{ + const Kernel traits; + return authalic_weight(p0, p1, p2, q, traits); +} } // namespace Weights } // namespace CGAL diff --git a/Weights/include/CGAL/Weights/barycentric_region_weights.h b/Weights/include/CGAL/Weights/barycentric_region_weights.h index 46fe69bcfa4..7d9f0bf2feb 100644 --- a/Weights/include/CGAL/Weights/barycentric_region_weights.h +++ b/Weights/include/CGAL/Weights/barycentric_region_weights.h @@ -14,131 +14,97 @@ #ifndef CGAL_BARYCENTRIC_REGION_WEIGHTS_H #define CGAL_BARYCENTRIC_REGION_WEIGHTS_H -// Internal includes. -#include +#include + +#include +#include namespace CGAL { namespace Weights { - #if defined(DOXYGEN_RUNNING) +// 2D ============================================================================================== - /*! - \ingroup PkgWeightsRefBarycentricRegionWeights +/*! + \ingroup PkgWeightsRefBarycentricRegionWeights + \brief computes the area of the barycentric cell in 2D using the points `p`, `q`, and `r`. + \tparam GeomTraits a model of `AnalyticWeightTraits_2` +*/ +template +typename GeomTraits::FT barycentric_area(const typename GeomTraits::Point_2& p, + const typename GeomTraits::Point_2& q, + const typename GeomTraits::Point_2& r, + const GeomTraits& traits) +{ + using FT = typename GeomTraits::FT; + using Point_2 = typename GeomTraits::Point_2; - \brief computes the area of the barycentric cell in 2D using the points `p`, `q` - and `r`, given a traits class `traits` with geometric objects, predicates, and constructions. - */ - template - typename GeomTraits::FT barycentric_area( - const typename GeomTraits::Point_2& p, - const typename GeomTraits::Point_2& q, - const typename GeomTraits::Point_2& r, - const GeomTraits& traits) { } + auto midpoint_2 = traits.construct_midpoint_2_object(); + auto centroid_2 = traits.construct_centroid_2_object(); - /*! - \ingroup PkgWeightsRefBarycentricRegionWeights + const Point_2 center = centroid_2(p, q, r); + const Point_2 m1 = midpoint_2(q, r); + const Point_2 m2 = midpoint_2(q, p); - \brief computes the area of the barycentric cell in 3D using the points `p`, `q` - and `r`, given a traits class `traits` with geometric objects, predicates, and constructions. - */ - template - typename GeomTraits::FT barycentric_area( - const typename GeomTraits::Point_3& p, - const typename GeomTraits::Point_3& q, - const typename GeomTraits::Point_3& r, - const GeomTraits& traits) { } + const FT A1 = internal::positive_area_2(q, m1, center, traits); + const FT A2 = internal::positive_area_2(q, center, m2, traits); + return A1 + A2; +} - /*! - \ingroup PkgWeightsRefBarycentricRegionWeights +/*! + \ingroup PkgWeightsRefBarycentricRegionWeights + \brief computes the area of the barycentric cell in 2D using the points `p`, `q`, and `r`. + \tparam Kernel a model of `Kernel` +*/ +template +typename Kernel::FT barycentric_area(const CGAL::Point_2& p, + const CGAL::Point_2& q, + const CGAL::Point_2& r) +{ + const Kernel traits; + return barycentric_area(p, q, r, traits); +} - \brief computes the area of the barycentric cell in 2D using the points `p`, `q` - and `r` which are parameterized by a `Kernel` K. - */ - template - typename K::FT barycentric_area( - const CGAL::Point_2& p, - const CGAL::Point_2& q, - const CGAL::Point_2& r) { } +// 3D ============================================================================================== - /*! - \ingroup PkgWeightsRefBarycentricRegionWeights +/*! + \ingroup PkgWeightsRefBarycentricRegionWeights + \brief computes the area of the barycentric cell in 3D using the points `p`, `q`, and `r`. + \tparam GeomTraits a model of `AnalyticWeightTraits_3` +*/ +template +typename GeomTraits::FT barycentric_area(const typename GeomTraits::Point_3& p, + const typename GeomTraits::Point_3& q, + const typename GeomTraits::Point_3& r, + const GeomTraits& traits) +{ + using FT = typename GeomTraits::FT; + using Point_3 = typename GeomTraits::Point_3; - \brief computes the area of the barycentric cell in 3D using the points `p`, `q` - and `r` which are parameterized by a `Kernel` K. - */ - template - typename K::FT barycentric_area( - const CGAL::Point_3& p, - const CGAL::Point_3& q, - const CGAL::Point_3& r) { } + auto midpoint_3 = traits.construct_midpoint_3_object(); + auto centroid_3 = traits.construct_centroid_3_object(); - #endif // DOXYGEN_RUNNING + const Point_3 center = centroid_3(p, q, r); + const Point_3 m1 = midpoint_3(q, r); + const Point_3 m2 = midpoint_3(q, p); - /// \cond SKIP_IN_MANUAL - template - typename GeomTraits::FT barycentric_area( - const typename GeomTraits::Point_2& p, - const typename GeomTraits::Point_2& q, - const typename GeomTraits::Point_2& r, - const GeomTraits& traits) { + const FT A1 = internal::positive_area_3(q, m1, center, traits); + const FT A2 = internal::positive_area_3(q, center, m2, traits); + return A1 + A2; +} - using FT = typename GeomTraits::FT; - const auto midpoint_2 = - traits.construct_midpoint_2_object(); - const auto centroid_2 = - traits.construct_centroid_2_object(); - - const auto center = centroid_2(p, q, r); - const auto m1 = midpoint_2(q, r); - const auto m2 = midpoint_2(q, p); - - const FT A1 = internal::positive_area_2(traits, q, m1, center); - const FT A2 = internal::positive_area_2(traits, q, center, m2); - return A1 + A2; - } - - template - typename GeomTraits::FT barycentric_area( - const CGAL::Point_2& p, - const CGAL::Point_2& q, - const CGAL::Point_2& r) { - - const GeomTraits traits; - return barycentric_area(p, q, r, traits); - } - - template - typename GeomTraits::FT barycentric_area( - const typename GeomTraits::Point_3& p, - const typename GeomTraits::Point_3& q, - const typename GeomTraits::Point_3& r, - const GeomTraits& traits) { - - using FT = typename GeomTraits::FT; - const auto midpoint_3 = - traits.construct_midpoint_3_object(); - const auto centroid_3 = - traits.construct_centroid_3_object(); - - const auto center = centroid_3(p, q, r); - const auto m1 = midpoint_3(q, r); - const auto m2 = midpoint_3(q, p); - - const FT A1 = internal::positive_area_3(traits, q, m1, center); - const FT A2 = internal::positive_area_3(traits, q, center, m2); - return A1 + A2; - } - - template - typename GeomTraits::FT barycentric_area( - const CGAL::Point_3& p, - const CGAL::Point_3& q, - const CGAL::Point_3& r) { - - const GeomTraits traits; - return barycentric_area(p, q, r, traits); - } - /// \endcond +/*! + \ingroup PkgWeightsRefBarycentricRegionWeights + \brief computes the area of the barycentric cell in 3D using the points `p`, `q`, and `r`. + \tparam Kernel a model of `Kernel` +*/ +template +typename Kernel::FT barycentric_area(const CGAL::Point_3& p, + const CGAL::Point_3& q, + const CGAL::Point_3& r) +{ + const Kernel traits; + return barycentric_area(p, q, r, traits); +} } // namespace Weights } // namespace CGAL diff --git a/Weights/include/CGAL/Weights/cotangent_weights.h b/Weights/include/CGAL/Weights/cotangent_weights.h index 0591d105d0d..d462c3f5174 100644 --- a/Weights/include/CGAL/Weights/cotangent_weights.h +++ b/Weights/include/CGAL/Weights/cotangent_weights.h @@ -14,482 +14,356 @@ #ifndef CGAL_COTANGENT_WEIGHTS_H #define CGAL_COTANGENT_WEIGHTS_H -// Internal includes. -#include +#include + +#include +#include +#include +#include +#include namespace CGAL { namespace Weights { - /// \cond SKIP_IN_MANUAL - namespace cotangent_ns { +/// \cond SKIP_IN_MANUAL - template - FT half_weight(const FT cot) { - return FT(2) * cot; - } +namespace cotangent_ns { - template - FT weight(const FT cot_beta, const FT cot_gamma) { - return FT(2) * (cot_beta + cot_gamma); - } +template +FT half_weight(const FT cot) +{ + return FT(2) * cot; +} + +template +FT weight(const FT cot_beta, const FT cot_gamma) +{ + return FT(2) * (cot_beta + cot_gamma); +} + +} // namespace cotangent_ns + +/// \endcond + +/*! + \ingroup PkgWeightsRefCotangentWeights + + \brief computes the half value of the cotangent weight. + + This function constructs the half of the cotangent weight using the precomputed + cotangent value. The returned value is \f$2\textbf{cot}\f$. + + \tparam FT a model of `FieldNumberType` + + \param cot the cotangent value + + \sa `cotangent_weight()` +*/ +template +FT half_cotangent_weight(const FT cot) +{ + return cotangent_ns::half_weight(cot); +} + +/*! + \ingroup PkgWeightsRefCotangentWeights + \brief computes the cotangent weight in 2D at `q` using the points `p0`, `p1`, and `p2`. + \tparam GeomTraits a model of `AnalyticWeightTraits_2` +*/ +template +typename GeomTraits::FT cotangent_weight(const typename GeomTraits::Point_2& p0, + const typename GeomTraits::Point_2& p1, + const typename GeomTraits::Point_2& p2, + const typename GeomTraits::Point_2& q, + const GeomTraits& traits) +{ + using FT = typename GeomTraits::FT; + + const FT cot_beta = cotangent_2(q, p0, p1, traits); + const FT cot_gamma = cotangent_2(p1, p2, q, traits); + + return cotangent_ns::weight(cot_beta, cot_gamma); +} + +/*! + \ingroup PkgWeightsRefCotangentWeights + \brief computes the cotangent weight in 2D at `q` using the points `p0`, `p1`, and `p2`. + \tparam Kernel a model of `Kernel` +*/ +template +typename Kernel::FT cotangent_weight(const CGAL::Point_2& p0, + const CGAL::Point_2& p1, + const CGAL::Point_2& p2, + const CGAL::Point_2& q) +{ + Kernel traits; + return cotangent_weight(p0, p1, p2, q, traits); +} + +// 3D ============================================================================================== + +/*! + \ingroup PkgWeightsRefCotangentWeights + \brief computes the cotangent weight in 3D at `q` using the points `p0`, `p1`, and `p2`. + \tparam GeomTraits a model of `AnalyticWeightTraits_3` +*/ +template +typename GeomTraits::FT cotangent_weight(const typename GeomTraits::Point_3& p0, + const typename GeomTraits::Point_3& p1, + const typename GeomTraits::Point_3& p2, + const typename GeomTraits::Point_3& q, + const GeomTraits& traits) +{ + using FT = typename GeomTraits::FT; + + const FT cot_beta = cotangent_3(q, p0, p1, traits); + const FT cot_gamma = cotangent_3(p1, p2, q, traits); + + return cotangent_ns::weight(cot_beta, cot_gamma); +} + +/*! + \ingroup PkgWeightsRefCotangentWeights + \brief computes the cotangent weight in 3D at `q` using the points `p0`, `p1`, and `p2`. + \tparam Kernel a model of `Kernel` +*/ +template +typename Kernel::FT cotangent_weight(const CGAL::Point_3& p0, + const CGAL::Point_3& p1, + const CGAL::Point_3& p2, + const CGAL::Point_3& q) +{ + Kernel traits; + return cotangent_weight(p0, p1, p2, q, traits); +} + +/// \cond SKIP_IN_MANUAL + +// Undocumented cotangent weight class. +// Returns: cot(beta) +// +// Returns a single cotangent weight, its operator() is defined based on the +// halfedge_descriptor, polygon mesh, and vertex to point map. +// For border edges it returns zero. +// This version is currently used in: +// Surface_mesh_deformation -> Surface_mesh_deformation.h +template::value_type>::type> +class Single_cotangent_weight +{ + using vertex_descriptor = typename boost::graph_traits::vertex_descriptor; + using halfedge_descriptor = typename boost::graph_traits::halfedge_descriptor; + + using Point_ref = typename boost::property_traits::reference; + using FT = typename GeomTraits::FT; + +private: + const PolygonMesh& m_pmesh; + const VertexPointMap m_vpm; + const GeomTraits m_traits; + +public: + Single_cotangent_weight(const PolygonMesh& pmesh, + const VertexPointMap vpm, + const GeomTraits& traits = GeomTraits()) + : m_pmesh(pmesh), m_vpm(vpm), m_traits(traits) + { } + + decltype(auto) operator()(const halfedge_descriptor he) const + { + if (is_border(he, m_pmesh)) + return FT{0}; + + const vertex_descriptor v0 = target(he, m_pmesh); + const vertex_descriptor v1 = source(he, m_pmesh); + const vertex_descriptor v2 = target(next(he, m_pmesh), m_pmesh); + + const Point_ref p0 = get(m_vpm, v0); + const Point_ref p1 = get(m_vpm, v1); + const Point_ref p2 = get(m_vpm, v2); + + return cotangent_3(p0, p2, p1, m_traits); } - /// \endcond +}; - /*! - \ingroup PkgWeightsRefCotangentWeights +// Undocumented cotangent weight class. +// Returns: 0.5 * (cot(beta) + cot(gamma)) +// +// Its constructor takes a boolean flag to choose between default and clamped +// versions of the cotangent weights and its operator() is defined based on the +// halfedge_descriptor, polygon mesh, and vertex to point map. +// This version is currently used in: +// Polygon_mesh_processing -> curvature_flow_impl.h (no clamping, no bounding) +// Surface_mesh_deformation -> Surface_mesh_deformation.h (default version) +// Surface_mesh_parameterizer -> Orbifold_Tutte_parameterizer_3.h (default version) +// Surface_mesh_skeletonization -> Mean_curvature_flow_skeletonization.h (clamped version) +template::value_type>::type> +class Cotangent_weight +{ + using vertex_descriptor = typename boost::graph_traits::vertex_descriptor; + using halfedge_descriptor = typename boost::graph_traits::halfedge_descriptor; - \brief computes the half value of the cotangent weight. + using Point_ref = typename boost::property_traits::reference; + using FT = typename GeomTraits::FT; - This function constructs the half of the cotangent weight using the precomputed - cotangent value. The returned value is - \f$2\textbf{cot}\f$. +private: + const PolygonMesh& m_pmesh; + const VertexPointMap m_vpm; + const GeomTraits m_traits; - \tparam FT - a model of `FieldNumberType` + bool m_use_clamped_version; + bool m_bound_from_below; - \param cot - the cotangent value +public: + Cotangent_weight(const PolygonMesh& pmesh, + const VertexPointMap vpm, + const GeomTraits& traits = GeomTraits(), + const bool use_clamped_version = false, + const bool bound_from_below = true) + : m_pmesh(pmesh), m_vpm(vpm), m_traits(traits), + m_use_clamped_version(use_clamped_version), + m_bound_from_below(bound_from_below) + { } - \sa `cotangent_weight()` - */ - template - FT half_cotangent_weight(const FT cot) { - return cotangent_ns::half_weight(cot); + decltype(auto) operator()(const halfedge_descriptor he) const + { + if(is_border(he, m_pmesh)) + return FT{0}; + + auto half_weight = [&] (const halfedge_descriptor he) -> FT + { + if(is_border(he, m_pmesh)) + return FT{0}; + + const vertex_descriptor v0 = target(he, m_pmesh); + const vertex_descriptor v1 = source(he, m_pmesh); + const vertex_descriptor v2 = target(next(he, m_pmesh), m_pmesh); + + const Point_ref p0 = get(m_vpm, v0); + const Point_ref p1 = get(m_vpm, v1); + const Point_ref p2 = get(m_vpm, v2); + + FT weight = 0; + if (m_use_clamped_version) + weight = cotangent_3_clamped(p1, p2, p0, m_traits); + else + weight = cotangent_3(p1, p2, p0, m_traits); + + if(m_bound_from_below) + weight = (CGAL::max)(FT(0), weight); + + return weight / FT(2); + }; + + FT weight = half_weight(he) + half_weight(opposite(he, m_pmesh)); + return weight; + } +}; + +// Undocumented cotangent weight class. +// +// Its constructor takes a polygon mesh and a vertex to point map +// and its operator() is defined based on the halfedge_descriptor only. +// This class is using a special clamped version of the cotangent weights. +// This version is currently used in: +// Polygon_mesh_processing -> fair.h +// Polyhedron demo -> Hole_filling_plugin.cpp +template +class Secure_cotangent_weight_with_voronoi_area +{ + using vertex_descriptor = typename boost::graph_traits::vertex_descriptor; + using halfedge_descriptor = typename boost::graph_traits::halfedge_descriptor; + + using Point_ref = typename boost::property_traits::reference; + using FT = typename GeomTraits::FT; + using Vector_3 = typename GeomTraits::Vector_3; + +private: + const PolygonMesh& m_pmesh; + const VertexPointMap m_vpm; + GeomTraits m_traits; + + Cotangent_weight cotangent_weight_calculator; + +public: + Secure_cotangent_weight_with_voronoi_area(const PolygonMesh& pmesh, + const VertexPointMap vpm, + const GeomTraits& traits = GeomTraits()) + : m_pmesh(pmesh), m_vpm(vpm), m_traits(traits), + cotangent_weight_calculator(m_pmesh, m_vpm, m_traits, + true /*clamp*/, true /*bound from below*/) + { } + + FT w_i(const vertex_descriptor v_i) const + { + return FT(1) / (FT(2) * voronoi(v_i)); } - #if defined(DOXYGEN_RUNNING) - - /*! - \ingroup PkgWeightsRefCotangentWeights - - \brief computes the cotangent weight in 2D at `q` using the points `p0`, `p1`, - and `p2`, given a traits class `traits` with geometric objects, predicates, and constructions. - */ - template - typename GeomTraits::FT cotangent_weight( - const typename GeomTraits::Point_2& p0, - const typename GeomTraits::Point_2& p1, - const typename GeomTraits::Point_2& p2, - const typename GeomTraits::Point_2& q, - const GeomTraits& traits) { } - - /*! - \ingroup PkgWeightsRefCotangentWeights - - \brief computes the cotangent weight in 3D at `q` using the points `p0`, `p1`, - and `p2`, given a traits class `traits` with geometric objects, predicates, and constructions. - */ - template - typename GeomTraits::FT cotangent_weight( - const typename GeomTraits::Point_3& p0, - const typename GeomTraits::Point_3& p1, - const typename GeomTraits::Point_3& p2, - const typename GeomTraits::Point_3& q, - const GeomTraits& traits) { } - - /*! - \ingroup PkgWeightsRefCotangentWeights - - \brief computes the cotangent weight in 2D at `q` using the points `p0`, `p1`, - and `p2` which are parameterized by a `Kernel` K. - */ - template - typename K::FT cotangent_weight( - const CGAL::Point_2& p0, - const CGAL::Point_2& p1, - const CGAL::Point_2& p2, - const CGAL::Point_2& q) { } - - /*! - \ingroup PkgWeightsRefCotangentWeights - - \brief computes the cotangent weight in 3D at `q` using the points `p0`, `p1`, - and `p2` which are parameterized by a `Kernel` K. - */ - template - typename K::FT cotangent_weight( - const CGAL::Point_3& p0, - const CGAL::Point_3& p1, - const CGAL::Point_3& p2, - const CGAL::Point_3& q) { } - - #endif // DOXYGEN_RUNNING - - /// \cond SKIP_IN_MANUAL - template - typename GeomTraits::FT cotangent_weight( - const typename GeomTraits::Point_2& t, - const typename GeomTraits::Point_2& r, - const typename GeomTraits::Point_2& p, - const typename GeomTraits::Point_2& q, - const GeomTraits& traits) { - - using FT = typename GeomTraits::FT; - const FT cot_beta = internal::cotangent_2(traits, q, t, r); - const FT cot_gamma = internal::cotangent_2(traits, r, p, q); - return cotangent_ns::weight(cot_beta, cot_gamma); + FT w_ij(const halfedge_descriptor he) const + { + return cotangent_weight_calculator(he); } - template - typename GeomTraits::FT cotangent_weight( - const CGAL::Point_2& t, - const CGAL::Point_2& r, - const CGAL::Point_2& p, - const CGAL::Point_2& q) { - GeomTraits traits; - return cotangent_weight(t, r, p, q, traits); - } +private: + FT voronoi(const vertex_descriptor v0) const + { + auto squared_length_3 = m_traits.compute_squared_length_3_object(); + auto vector_3 = m_traits.construct_vector_3_object(); - template - typename GeomTraits::FT cotangent_weight( - const typename GeomTraits::Point_3& t, - const typename GeomTraits::Point_3& r, - const typename GeomTraits::Point_3& p, - const typename GeomTraits::Point_3& q, - const GeomTraits& traits) { + FT voronoi_area = FT(0); + for (const halfedge_descriptor he : halfedges_around_target(halfedge(v0, m_pmesh), m_pmesh)) + { + CGAL_assertion(v0 == target(he, m_pmesh)); + CGAL_assertion(CGAL::is_triangle(he, m_pmesh)); - using FT = typename GeomTraits::FT; - const FT cot_beta = internal::cotangent_3(traits, q, t, r); - const FT cot_gamma = internal::cotangent_3(traits, r, p, q); - return cotangent_ns::weight(cot_beta, cot_gamma); - } + if (is_border(he, m_pmesh)) + continue; - template - typename GeomTraits::FT cotangent_weight( - const CGAL::Point_3& t, - const CGAL::Point_3& r, - const CGAL::Point_3& p, - const CGAL::Point_3& q) { + const vertex_descriptor v1 = source(he, m_pmesh); + const vertex_descriptor v2 = target(next(he, m_pmesh), m_pmesh); - GeomTraits traits; - return cotangent_weight(t, r, p, q, traits); - } + const Point_ref p0 = get(m_vpm, v0); + const Point_ref p1 = get(m_vpm, v1); + const Point_ref p2 = get(m_vpm, v2); - // Undocumented cotangent weight class. - // Its constructor takes a polygon mesh and a vertex to point map - // and its operator() is defined based on the halfedge_descriptor only. - // This version is currently used in: - // Polygon_mesh_processing -> curvature_flow_impl.h - template< - typename PolygonMesh, - typename VertexPointMap = typename boost::property_map::type> - class Edge_cotangent_weight { - - using GeomTraits = typename CGAL::Kernel_traits< - typename boost::property_traits::value_type>::type; - using FT = typename GeomTraits::FT; - - const PolygonMesh& m_pmesh; - const VertexPointMap m_pmap; - GeomTraits m_traits; - - public: - using vertex_descriptor = typename boost::graph_traits::vertex_descriptor; - using halfedge_descriptor = typename boost::graph_traits::halfedge_descriptor; - - Edge_cotangent_weight(const PolygonMesh& pmesh, const VertexPointMap pmap) : - m_pmesh(pmesh), m_pmap(pmap), m_traits() { } - - FT operator()(const halfedge_descriptor he) const { - - FT weight = FT(0); - if (is_border_edge(he, m_pmesh)) { - const auto h1 = next(he, m_pmesh); - - const auto v0 = target(he, m_pmesh); - const auto v1 = source(he, m_pmesh); - const auto v2 = target(h1, m_pmesh); - - const auto& p0 = get(m_pmap, v0); - const auto& p1 = get(m_pmap, v1); - const auto& p2 = get(m_pmap, v2); - - weight = internal::cotangent_3(m_traits, p0, p2, p1); - - } else { - const auto h1 = next(he, m_pmesh); - const auto h2 = prev(opposite(he, m_pmesh), m_pmesh); - - const auto v0 = target(he, m_pmesh); - const auto v1 = source(he, m_pmesh); - const auto v2 = target(h1, m_pmesh); - const auto v3 = source(h2, m_pmesh); - - const auto& p0 = get(m_pmap, v0); - const auto& p1 = get(m_pmap, v1); - const auto& p2 = get(m_pmap, v2); - const auto& p3 = get(m_pmap, v3); - - weight = cotangent_weight(p2, p1, p3, p0) / FT(2); + const CGAL::Angle angle0 = CGAL::angle(p1, p0, p2); + if((angle0 == CGAL::OBTUSE) || + (CGAL::angle(p2, p1, p0) == CGAL::OBTUSE) || + (CGAL::angle(p0, p2, p1) == CGAL::OBTUSE)) + { + const FT A = internal::positive_area_3(p0, p1, p2, m_traits); + if (angle0 == CGAL::OBTUSE) + voronoi_area += A / FT(2); + else + voronoi_area += A / FT(4); } - return weight; - } - }; + else + { + const FT cot_p1 = cotangent_3_clamped(p2, p1, p0, m_traits); + const FT cot_p2 = cotangent_3_clamped(p0, p2, p1, m_traits); - // Undocumented cotangent weight class. - // Returns a single cotangent weight, its operator() is defined based on the - // halfedge_descriptor, polygon mesh, and vertex to point map. - // For border edges it returns zero. - // This version is currently used in: - // Surface_mesh_deformation -> Surface_mesh_deformation.h - template - class Single_cotangent_weight { + const Vector_3 v1 = vector_3(p0, p1); + const Vector_3 v2 = vector_3(p0, p2); - public: - using vertex_descriptor = typename boost::graph_traits::vertex_descriptor; - using halfedge_descriptor = typename boost::graph_traits::halfedge_descriptor; - - template - decltype(auto) operator()(const halfedge_descriptor he, - const PolygonMesh& pmesh, const VertexPointMap pmap) const { - - using GeomTraits = typename CGAL::Kernel_traits< - typename boost::property_traits::value_type>::type; - using FT = typename GeomTraits::FT; - GeomTraits traits; - - if (is_border(he, pmesh)) { - return FT(0); + const FT t1 = cot_p1 * squared_length_3(v2); + const FT t2 = cot_p2 * squared_length_3(v1); + voronoi_area += (t1 + t2) / FT(8); } - - const vertex_descriptor v0 = target(he, pmesh); - const vertex_descriptor v1 = source(he, pmesh); - const vertex_descriptor v2 = target(next(he, pmesh), pmesh); - - const auto& p0 = get(pmap, v0); - const auto& p1 = get(pmap, v1); - const auto& p2 = get(pmap, v2); - - return internal::cotangent_3(traits, p0, p2, p1); - } - }; - - // Undocumented cotangent weight class. - // Its constructor takes a boolean flag to choose between default and clamped - // versions of the cotangent weights and its operator() is defined based on the - // halfedge_descriptor, polygon mesh, and vertex to point map. - // This version is currently used in: - // Surface_mesh_deformation -> Surface_mesh_deformation.h (default version) - // Surface_mesh_parameterizer -> Orbifold_Tutte_parameterizer_3.h (default version) - // Surface_mesh_skeletonization -> Mean_curvature_flow_skeletonization.h (clamped version) - template - class Cotangent_weight { - bool m_use_clamped_version; - - public: - using vertex_descriptor = typename boost::graph_traits::vertex_descriptor; - using halfedge_descriptor = typename boost::graph_traits::halfedge_descriptor; - - Cotangent_weight(const bool use_clamped_version = false) : - m_use_clamped_version(use_clamped_version) { } - - template - decltype(auto) operator()(const halfedge_descriptor he, - const PolygonMesh& pmesh, const VertexPointMap pmap) const { - - using GeomTraits = typename CGAL::Kernel_traits< - typename boost::property_traits::value_type>::type; - using FT = typename GeomTraits::FT; - GeomTraits traits; - - const auto v0 = target(he, pmesh); - const auto v1 = source(he, pmesh); - - const auto& p0 = get(pmap, v0); - const auto& p1 = get(pmap, v1); - - FT weight = FT(0); - if (is_border_edge(he, pmesh)) { - const auto he_cw = opposite(next(he, pmesh), pmesh); - auto v2 = source(he_cw, pmesh); - - if (is_border_edge(he_cw, pmesh)) { - const auto he_ccw = prev(opposite(he, pmesh), pmesh); - v2 = source(he_ccw, pmesh); - - const auto& p2 = get(pmap, v2); - if (m_use_clamped_version) { - weight = internal::cotangent_3_clamped(traits, p1, p2, p0); - } else { - weight = internal::cotangent_3(traits, p1, p2, p0); - } - weight = (CGAL::max)(FT(0), weight); - weight /= FT(2); - } else { - const auto& p2 = get(pmap, v2); - if (m_use_clamped_version) { - weight = internal::cotangent_3_clamped(traits, p0, p2, p1); - } else { - weight = internal::cotangent_3(traits, p0, p2, p1); - } - weight = (CGAL::max)(FT(0), weight); - weight /= FT(2); - } - - } else { - const auto he_cw = opposite(next(he, pmesh), pmesh); - const auto v2 = source(he_cw, pmesh); - const auto he_ccw = prev(opposite(he, pmesh), pmesh); - const auto v3 = source(he_ccw, pmesh); - - const auto& p2 = get(pmap, v2); - const auto& p3 = get(pmap, v3); - FT cot_beta = FT(0), cot_gamma = FT(0); - - if (m_use_clamped_version) { - cot_beta = internal::cotangent_3_clamped(traits, p0, p2, p1); - } else { - cot_beta = internal::cotangent_3(traits, p0, p2, p1); - } - - if (m_use_clamped_version) { - cot_gamma = internal::cotangent_3_clamped(traits, p1, p3, p0); - } else { - cot_gamma = internal::cotangent_3(traits, p1, p3, p0); - } - - cot_beta = (CGAL::max)(FT(0), cot_beta); cot_beta /= FT(2); - cot_gamma = (CGAL::max)(FT(0), cot_gamma); cot_gamma /= FT(2); - weight = cot_beta + cot_gamma; - } - return weight; - } - }; - - // Undocumented cotangent weight class. - // Its constructor takes a polygon mesh and a vertex to point map - // and its operator() is defined based on the halfedge_descriptor only. - // This class is using a special clamped version of the cotangent weights. - // This version is currently used in: - // Polygon_mesh_processing -> fair.h - // Polyhedron demo -> Hole_filling_plugin.cpp - template< - typename PolygonMesh, - typename VertexPointMap = typename boost::property_map::type> - class Secure_cotangent_weight_with_voronoi_area { - - using GeomTraits = typename CGAL::Kernel_traits< - typename boost::property_traits::value_type>::type; - using FT = typename GeomTraits::FT; - - const PolygonMesh& m_pmesh; - const VertexPointMap m_pmap; - GeomTraits m_traits; - - public: - using vertex_descriptor = typename boost::graph_traits::vertex_descriptor; - using halfedge_descriptor = typename boost::graph_traits::halfedge_descriptor; - - Secure_cotangent_weight_with_voronoi_area(const PolygonMesh& pmesh, const VertexPointMap pmap) : - m_pmesh(pmesh), m_pmap(pmap), m_traits() { } - - FT w_i(const vertex_descriptor v_i) const { - return FT(1) / (FT(2) * voronoi(v_i)); } - FT w_ij(const halfedge_descriptor he) const { - return cotangent_clamped(he); - } + CGAL_assertion(!is_zero(voronoi_area)); + return voronoi_area; + } +}; - private: - FT cotangent_clamped(const halfedge_descriptor he) const { - - const auto v0 = target(he, m_pmesh); - const auto v1 = source(he, m_pmesh); - - const auto& p0 = get(m_pmap, v0); - const auto& p1 = get(m_pmap, v1); - - FT weight = FT(0); - if (is_border_edge(he, m_pmesh)) { - const auto he_cw = opposite(next(he, m_pmesh), m_pmesh); - auto v2 = source(he_cw, m_pmesh); - - if (is_border_edge(he_cw, m_pmesh)) { - const auto he_ccw = prev(opposite(he, m_pmesh), m_pmesh); - v2 = source(he_ccw, m_pmesh); - - const auto& p2 = get(m_pmap, v2); - weight = internal::cotangent_3_clamped(m_traits, p1, p2, p0); - } else { - const auto& p2 = get(m_pmap, v2); - weight = internal::cotangent_3_clamped(m_traits, p0, p2, p1); - } - - } else { - const auto he_cw = opposite(next(he, m_pmesh), m_pmesh); - const auto v2 = source(he_cw, m_pmesh); - const auto he_ccw = prev(opposite(he, m_pmesh), m_pmesh); - const auto v3 = source(he_ccw, m_pmesh); - - const auto& p2 = get(m_pmap, v2); - const auto& p3 = get(m_pmap, v3); - - const FT cot_beta = internal::cotangent_3_clamped(m_traits, p0, p2, p1); - const FT cot_gamma = internal::cotangent_3_clamped(m_traits, p1, p3, p0); - weight = cot_beta + cot_gamma; - } - return weight; - } - - FT voronoi(const vertex_descriptor v0) const { - - const auto squared_length_3 = - m_traits.compute_squared_length_3_object(); - const auto construct_vector_3 = - m_traits.construct_vector_3_object(); - - FT voronoi_area = FT(0); - CGAL_assertion(CGAL::is_triangle_mesh(m_pmesh)); - for (const auto& he : halfedges_around_target(halfedge(v0, m_pmesh), m_pmesh)) { - CGAL_assertion(v0 == target(he, m_pmesh)); - if (is_border(he, m_pmesh)) { - continue; - } - - const auto v1 = source(he, m_pmesh); - const auto v2 = target(next(he, m_pmesh), m_pmesh); - - const auto& p0 = get(m_pmap, v0); - const auto& p1 = get(m_pmap, v1); - const auto& p2 = get(m_pmap, v2); - - const auto angle0 = CGAL::angle(p1, p0, p2); - const auto angle1 = CGAL::angle(p2, p1, p0); - const auto angle2 = CGAL::angle(p0, p2, p1); - - const bool obtuse = - (angle0 == CGAL::OBTUSE) || - (angle1 == CGAL::OBTUSE) || - (angle2 == CGAL::OBTUSE); - - if (!obtuse) { - const FT cot_p1 = internal::cotangent_3(m_traits, p2, p1, p0); - const FT cot_p2 = internal::cotangent_3(m_traits, p0, p2, p1); - - const auto v1 = construct_vector_3(p0, p1); - const auto v2 = construct_vector_3(p0, p2); - - const FT t1 = cot_p1 * squared_length_3(v2); - const FT t2 = cot_p2 * squared_length_3(v1); - voronoi_area += (t1 + t2) / FT(8); - - } else { - - const FT A = internal::positive_area_3(m_traits, p0, p1, p2); - if (angle0 == CGAL::OBTUSE) { - voronoi_area += A / FT(2); - } else { - voronoi_area += A / FT(4); - } - } - } - CGAL_assertion(voronoi_area != FT(0)); - return voronoi_area; - } - }; - - /// \endcond +/// \endcond } // namespace Weights } // namespace CGAL diff --git a/Weights/include/CGAL/Weights/discrete_harmonic_weights.h b/Weights/include/CGAL/Weights/discrete_harmonic_weights.h index 42a7056afc2..6faa6f189c4 100644 --- a/Weights/include/CGAL/Weights/discrete_harmonic_weights.h +++ b/Weights/include/CGAL/Weights/discrete_harmonic_weights.h @@ -14,429 +14,379 @@ #ifndef CGAL_DISCRETE_HARMONIC_WEIGHTS_H #define CGAL_DISCRETE_HARMONIC_WEIGHTS_H -// Internal includes. #include #include +#include +#include +#include + +#include + namespace CGAL { namespace Weights { - /// \cond SKIP_IN_MANUAL - namespace discrete_harmonic_ns { +/// \cond SKIP_IN_MANUAL - template - FT weight( - const FT r1, const FT r2, const FT r3, - const FT A1, const FT A2, const FT B) { +namespace discrete_harmonic_ns { - FT w = FT(0); - CGAL_precondition(A1 != FT(0) && A2 != FT(0)); - const FT prod = A1 * A2; - if (prod != FT(0)) { - const FT inv = FT(1) / prod; - w = (r3 * A1 - r2 * B + r1 * A2) * inv; - } - return w; - } - } - /// \endcond +template +FT weight(const FT d0, const FT d2, const FT d, + const FT A0, const FT A2, const FT B) +{ + FT w = FT(0); + CGAL_precondition(!is_zero(A0) && !is_zero(A2)); + const FT prod = A0 * A2; + if (!is_zero(prod)) + w = (d2 * A0 - d * B + d0 * A2) / prod; - #if defined(DOXYGEN_RUNNING) + return w; +} - /*! - \ingroup PkgWeightsRefDiscreteHarmonicWeights +} // namespace discrete_harmonic_ns - \brief computes the discrete harmonic weight in 2D at `q` using the points `p0`, `p1`, - and `p2`, given a traits class `traits` with geometric objects, predicates, and constructions. - */ - template - typename GeomTraits::FT discrete_harmonic_weight( - const typename GeomTraits::Point_2& p0, - const typename GeomTraits::Point_2& p1, - const typename GeomTraits::Point_2& p2, - const typename GeomTraits::Point_2& q, - const GeomTraits& traits) { } +/// \endcond - /*! - \ingroup PkgWeightsRefDiscreteHarmonicWeights +// 2D ============================================================================================== - \brief computes the discrete harmonic weight in 2D at `q` using the points `p0`, `p1`, - and `p2` which are parameterized by a `Kernel` K. - */ - template - typename K::FT discrete_harmonic_weight( - const CGAL::Point_2& p0, - const CGAL::Point_2& p1, - const CGAL::Point_2& p2, - const CGAL::Point_2& q) { } +/*! + \ingroup PkgWeightsRefDiscreteHarmonicWeights + \brief computes the discrete harmonic weight in 2D at `q` using the points `p0`, `p1`, and `p2`. + \tparam GeomTraits a model of `AnalyticWeightTraits_2` +*/ +template +typename GeomTraits::FT discrete_harmonic_weight(const typename GeomTraits::Point_2& p0, + const typename GeomTraits::Point_2& p1, + const typename GeomTraits::Point_2& p2, + const typename GeomTraits::Point_2& q, + const GeomTraits& traits) +{ + using FT = typename GeomTraits::FT; - #endif // DOXYGEN_RUNNING + auto squared_distance_2 = traits.compute_squared_distance_2_object(); + auto area_2 = traits.compute_area_2_object(); + + const FT d0 = squared_distance_2(q, p0); + const FT d = squared_distance_2(q, p1); + const FT d2 = squared_distance_2(q, p2); + + const FT A0 = area_2(p1, q, p0); + const FT A2 = area_2(p2, q, p1); + const FT B = area_2(p2, q, p0); + + return discrete_harmonic_ns::weight(d0, d2, d, A0, A2, B); +} + +/*! + \ingroup PkgWeightsRefDiscreteHarmonicWeights + \brief computes the discrete harmonic weight in 2D at `q` using the points `p0`, `p1`, and `p2`. + \tparam Kernel a model of `Kernel` +*/ +template +typename Kernel::FT discrete_harmonic_weight(const CGAL::Point_2& p0, + const CGAL::Point_2& p1, + const CGAL::Point_2& p2, + const CGAL::Point_2& q) +{ + const Kernel traits; + return discrete_harmonic_weight(p0, p1, p2, q, traits); +} + +// 3D ============================================================================================== + +/// \cond SKIP_IN_MANUAL + +template +typename GeomTraits::FT discrete_harmonic_weight(const typename GeomTraits::Point_3& p0, + const typename GeomTraits::Point_3& p1, + const typename GeomTraits::Point_3& p2, + const typename GeomTraits::Point_3& q, + const GeomTraits& traits) +{ + using Point_2 = typename GeomTraits::Point_2; + + Point_2 p0f, p1f, p2f, qf; + internal::flatten(p0, p1, p2, q, + p0f, p1f, p2f, qf, + traits); + return discrete_harmonic_weight(p0f, p1f, p2f, qf, traits); +} + +template +typename Kernel::FT discrete_harmonic_weight(const CGAL::Point_3& p0, + const CGAL::Point_3& p1, + const CGAL::Point_3& p2, + const CGAL::Point_3& q) +{ + const Kernel traits; + return discrete_harmonic_weight(p0, p1, p2, q, traits); +} + +/// \endcond + +/*! + \ingroup PkgWeightsRefBarycentricDiscreteHarmonicWeights + + \brief 2D discrete harmonic weights for polygons. + + This class implements 2D discrete harmonic weights (\cite cgal:bc:eddhls-maam-95, + \cite cgal:bc:fhk-gcbcocp-06, \cite cgal:pp-cdmsc-93) which can be computed + at any point inside a strictly convex polygon. + + Discrete harmonic weights are well-defined inside a strictly convex polygon + but they are not necessarily positive. These weights are computed analytically + using the formulation from the `discrete_harmonic_weight()`. + + \tparam VertexRange a model of `ConstRange` whose iterator type is `RandomAccessIterator` + \tparam GeomTraits a model of `AnalyticWeightTraits_2` + \tparam PointMap a model of `ReadablePropertyMap` whose key type is `VertexRange::value_type` and + value type is `Point_2`. The default is `CGAL::Identity_property_map`. + + \cgalModels `BarycentricWeights_2` +*/ +template > +class Discrete_harmonic_weights_2 +{ +public: + /// \name Types + /// @{ /// \cond SKIP_IN_MANUAL - template - typename GeomTraits::FT discrete_harmonic_weight( - const typename GeomTraits::Point_2& t, - const typename GeomTraits::Point_2& r, - const typename GeomTraits::Point_2& p, - const typename GeomTraits::Point_2& q, - const GeomTraits& traits) { - - using FT = typename GeomTraits::FT; - const auto squared_distance_2 = - traits.compute_squared_distance_2_object(); - - const FT d1 = squared_distance_2(q, t); - const FT d2 = squared_distance_2(q, r); - const FT d3 = squared_distance_2(q, p); - - const FT A1 = internal::area_2(traits, r, q, t); - const FT A2 = internal::area_2(traits, p, q, r); - const FT B = internal::area_2(traits, p, q, t); - - return discrete_harmonic_ns::weight( - d1, d2, d3, A1, A2, B); - } - - template - typename GeomTraits::FT discrete_harmonic_weight( - const CGAL::Point_2& t, - const CGAL::Point_2& r, - const CGAL::Point_2& p, - const CGAL::Point_2& q) { - - const GeomTraits traits; - return discrete_harmonic_weight(t, r, p, q, traits); - } - - namespace internal { - - template - typename GeomTraits::FT discrete_harmonic_weight( - const typename GeomTraits::Point_3& t, - const typename GeomTraits::Point_3& r, - const typename GeomTraits::Point_3& p, - const typename GeomTraits::Point_3& q, - const GeomTraits& traits) { - - using Point_2 = typename GeomTraits::Point_2; - Point_2 tf, rf, pf, qf; - internal::flatten( - traits, - t, r, p, q, - tf, rf, pf, qf); - return CGAL::Weights:: - discrete_harmonic_weight(tf, rf, pf, qf, traits); - } - - template - typename GeomTraits::FT discrete_harmonic_weight( - const CGAL::Point_3& t, - const CGAL::Point_3& r, - const CGAL::Point_3& p, - const CGAL::Point_3& q) { - - const GeomTraits traits; - return discrete_harmonic_weight(t, r, p, q, traits); - } - - } // namespace internal + using Vertex_range = VertexRange; + using Geom_traits = GeomTraits; + using Point_map = PointMap; + using Area_2 = typename GeomTraits::Compute_area_2; + using Squared_distance_2 = typename GeomTraits::Compute_squared_distance_2; /// \endcond - /*! - \ingroup PkgWeightsRefBarycentricDiscreteHarmonicWeights + /// Number type. + typedef typename GeomTraits::FT FT; - \brief 2D discrete harmonic weights for polygons. + /// Point type. + typedef typename GeomTraits::Point_2 Point_2; - This class implements 2D discrete harmonic weights ( \cite cgal:bc:fhk-gcbcocp-06, - \cite cgal:pp-cdmsc-93, \cite cgal:bc:eddhls-maam-95 ) which can be computed - at any point inside a strictly convex polygon. + /// @} - Discrete harmonic weights are well-defined inside a strictly convex polygon - but they are not necessarily positive. These weights are computed analytically - using the formulation from the `discrete_harmonic_weight()`. - - \tparam VertexRange - a model of `ConstRange` whose iterator type is `RandomAccessIterator` - - \tparam GeomTraits - a model of `AnalyticWeightTraits_2` - - \tparam PointMap - a model of `ReadablePropertyMap` whose key type is `VertexRange::value_type` and - value type is `Point_2`. The default is `CGAL::Identity_property_map`. - - \cgalModels `BarycentricWeights_2` - */ - template< - typename VertexRange, - typename GeomTraits, - typename PointMap = CGAL::Identity_property_map > - class Discrete_harmonic_weights_2 { - - public: - - /// \name Types - /// @{ - - /// \cond SKIP_IN_MANUAL - using Vertex_range = VertexRange; - using Geom_traits = GeomTraits; - using Point_map = PointMap; - - using Area_2 = typename GeomTraits::Compute_area_2; - using Squared_distance_2 = typename GeomTraits::Compute_squared_distance_2; - /// \endcond - - /// Number type. - typedef typename GeomTraits::FT FT; - - /// Point type. - typedef typename GeomTraits::Point_2 Point_2; - - /// @} - - /// \name Initialization - /// @{ - - /*! - \brief initializes all internal data structures. - - This class implements the behavior of discrete harmonic weights - for 2D query points inside strictly convex polygons. - - \param polygon - an instance of `VertexRange` with the vertices of a strictly convex polygon - - \param traits - a traits class with geometric objects, predicates, and constructions; - the default initialization is provided - - \param point_map - an instance of `PointMap` that maps a vertex from `polygon` to `Point_2`; - the default initialization is provided - - \pre polygon.size() >= 3 - \pre polygon is simple - \pre polygon is strictly convex - */ - Discrete_harmonic_weights_2( - const VertexRange& polygon, - const GeomTraits traits = GeomTraits(), - const PointMap point_map = PointMap()) : - m_polygon(polygon), - m_traits(traits), - m_point_map(point_map), - m_area_2(m_traits.compute_area_2_object()), - m_squared_distance_2(m_traits.compute_squared_distance_2_object()) { - - CGAL_precondition( - polygon.size() >= 3); - CGAL_precondition( - internal::is_simple_2(polygon, traits, point_map)); - CGAL_precondition( - internal::polygon_type_2(polygon, traits, point_map) == - internal::Polygon_type::STRICTLY_CONVEX); - resize(); - } - - /// @} - - /// \name Access - /// @{ - - /*! - \brief computes 2D discrete harmonic weights. - - This function fills a destination range with 2D discrete harmonic weights - computed at the `query` point with respect to the vertices of the input polygon. - - The number of computed weights is equal to the number of polygon vertices. - - \tparam OutIterator - a model of `OutputIterator` whose value type is `FT` - - \param query - a query point - - \param w_begin - the beginning of the destination range with the computed weights - - \return an output iterator to the element in the destination range, - one past the last weight stored - */ - template - OutIterator operator()(const Point_2& query, OutIterator w_begin) { - const bool normalize = false; - return operator()(query, w_begin, normalize); - } - - /// @} - - /// \cond SKIP_IN_MANUAL - template - OutIterator operator()(const Point_2& query, OutIterator w_begin, const bool normalize) { - return optimal_weights(query, w_begin, normalize); - } - /// \endcond - - private: - - // Fields. - const VertexRange& m_polygon; - const GeomTraits m_traits; - const PointMap m_point_map; - - const Area_2 m_area_2; - const Squared_distance_2 m_squared_distance_2; - - std::vector r; - std::vector A; - std::vector B; - std::vector w; - - // Functions. - void resize() { - r.resize(m_polygon.size()); - A.resize(m_polygon.size()); - B.resize(m_polygon.size()); - w.resize(m_polygon.size()); - } - - template - OutputIterator optimal_weights( - const Point_2& query, OutputIterator weights, const bool normalize) { - - // Get the number of vertices in the polygon. - const std::size_t n = m_polygon.size(); - - // Compute areas A, B, and distances r following the notation from [1]. - // Split the loop to make this computation faster. - const auto& p1 = get(m_point_map, *(m_polygon.begin() + 0)); - const auto& p2 = get(m_point_map, *(m_polygon.begin() + 1)); - const auto& pn = get(m_point_map, *(m_polygon.begin() + (n - 1))); - - r[0] = m_squared_distance_2(p1, query); - A[0] = m_area_2(p1, p2, query); - B[0] = m_area_2(pn, p2, query); - - for (std::size_t i = 1; i < n - 1; ++i) { - const auto& pi0 = get(m_point_map, *(m_polygon.begin() + (i - 1))); - const auto& pi1 = get(m_point_map, *(m_polygon.begin() + (i + 0))); - const auto& pi2 = get(m_point_map, *(m_polygon.begin() + (i + 1))); - - r[i] = m_squared_distance_2(pi1, query); - A[i] = m_area_2(pi1, pi2, query); - B[i] = m_area_2(pi0, pi2, query); - } - - const auto& pm = get(m_point_map, *(m_polygon.begin() + (n - 2))); - r[n - 1] = m_squared_distance_2(pn, query); - A[n - 1] = m_area_2(pn, p1, query); - B[n - 1] = m_area_2(pm, p1, query); - - // Compute unnormalized weights following the formula (25) with p = 2 from [1]. - CGAL_assertion(A[n - 1] != FT(0) && A[0] != FT(0)); - w[0] = (r[1] * A[n - 1] - r[0] * B[0] + r[n - 1] * A[0]) / (A[n - 1] * A[0]); - - for (std::size_t i = 1; i < n - 1; ++i) { - CGAL_assertion(A[i - 1] != FT(0) && A[i] != FT(0)); - w[i] = (r[i + 1] * A[i - 1] - r[i] * B[i] + r[i - 1] * A[i]) / (A[i - 1] * A[i]); - } - - CGAL_assertion(A[n - 2] != FT(0) && A[n - 1] != FT(0)); - w[n - 1] = (r[0] * A[n - 2] - r[n - 1] * B[n - 1] + r[n - 2] * A[n - 1]) / (A[n - 2] * A[n - 1]); - - // Normalize if necessary. - if (normalize) { - internal::normalize(w); - } - - // Return weights. - for (std::size_t i = 0; i < n; ++i) { - *(weights++) = w[i]; - } - return weights; - } - }; + /// \name Initialization + /// @{ /*! - \ingroup PkgWeightsRefBarycentricDiscreteHarmonicWeights + \brief initializes all internal data structures. - \brief computes 2D discrete harmonic weights for polygons. + This class implements the behavior of discrete harmonic weights + for 2D query points inside strictly convex polygons. - This function computes 2D discrete harmonic weights at a given `query` point - with respect to the vertices of a strictly convex `polygon`, that is one - weight per vertex. The weights are stored in a destination range - beginning at `w_begin`. - - Internally, the class `Discrete_harmonic_weights_2` is used. If one wants to process - multiple query points, it is better to use that class. When using the free function, - internal memory is allocated for each query point, while when using the class, - it is allocated only once which is much more efficient. However, for a few query - points, it is easier to use this function. It can also be used when the processing - time is not a concern. - - \tparam PointRange - a model of `ConstRange` whose iterator type is `RandomAccessIterator` - and value type is `GeomTraits::Point_2` - - \tparam OutIterator - a model of `OutputIterator` whose value type is `GeomTraits::FT` - - \tparam GeomTraits - a model of `AnalyticWeightTraits_2` - - \param polygon - an instance of `PointRange` with 2D points which form a strictly convex polygon - - \param query - a query point - - \param w_begin - the beginning of the destination range with the computed weights - - \param traits - a traits class with geometric objects, predicates, and constructions; - this parameter can be omitted if the traits class can be deduced from the point type - - \return an output iterator to the element in the destination range, - one past the last weight stored + \param polygon an instance of `VertexRange` with the vertices of a strictly convex polygon + \param traits a traits class with geometric objects, predicates, and constructions; + the default initialization is provided + \param point_map an instance of `PointMap` that maps a vertex from `polygon` to `Point_2`; + the default initialization is provided \pre polygon.size() >= 3 \pre polygon is simple \pre polygon is strictly convex */ - template< - typename PointRange, - typename OutIterator, - typename GeomTraits> - OutIterator discrete_harmonic_weights_2( - const PointRange& polygon, const typename GeomTraits::Point_2& query, - OutIterator w_begin, const GeomTraits& traits) { + Discrete_harmonic_weights_2(const VertexRange& polygon, + const GeomTraits traits = GeomTraits(), + const PointMap point_map = PointMap()) + : m_polygon(polygon), + m_traits(traits), + m_point_map(point_map), + m_area_2(m_traits.compute_area_2_object()), + m_squared_distance_2(m_traits.compute_squared_distance_2_object()) + { + CGAL_precondition(polygon.size() >= 3); + CGAL_precondition(internal::is_simple_2(polygon, traits, point_map)); + CGAL_precondition(internal::polygon_type_2(polygon, traits, point_map) == internal::Polygon_type::STRICTLY_CONVEX); - Discrete_harmonic_weights_2 - discrete_harmonic(polygon, traits); - return discrete_harmonic(query, w_begin); + resize(); } + /// @} + + /// \name Access + /// @{ + + /*! + \brief computes 2D discrete harmonic weights. + + This function fills a destination range with 2D discrete harmonic weights + computed at the `query` point with respect to the vertices of the input polygon. + + The number of computed weights is equal to the number of polygon vertices. + + \tparam OutIterator a model of `OutputIterator` whose value type is `FT` + + \param query a query point + \param w_begin the beginning of the destination range with the computed weights + + \return an output iterator to the element in the destination range, one past the last weight stored + */ + template + OutIterator operator()(const Point_2& query, + OutIterator w_begin) + { + const bool normalize = false; + return operator()(query, w_begin, normalize); + } + + /// @} + /// \cond SKIP_IN_MANUAL - template< - typename PointRange, - typename OutIterator> - OutIterator discrete_harmonic_weights_2( - const PointRange& polygon, - const typename PointRange::value_type& query, - OutIterator w_begin) { - - using Point_2 = typename PointRange::value_type; - using GeomTraits = typename Kernel_traits::Kernel; - const GeomTraits traits; - return discrete_harmonic_weights_2( - polygon, query, w_begin, traits); + template + OutIterator operator()(const Point_2& query, + OutIterator w_begin, + const bool normalize) + { + return optimal_weights(query, w_begin, normalize); } + /// \endcond +private: + const VertexRange& m_polygon; + const GeomTraits m_traits; + const PointMap m_point_map; + + const Area_2 m_area_2; + const Squared_distance_2 m_squared_distance_2; + + std::vector r; + std::vector A; + std::vector B; + std::vector w; + + void resize() + { + r.resize(m_polygon.size()); + A.resize(m_polygon.size()); + B.resize(m_polygon.size()); + w.resize(m_polygon.size()); + } + + template + OutputIterator optimal_weights(const Point_2& query, + OutputIterator weights, + const bool normalize) + { + // Get the number of vertices in the polygon. + const std::size_t n = m_polygon.size(); + + // Compute areas A, B, and distances r following the notation from [1]. + // Split the loop to make this computation faster. + const auto& p1 = get(m_point_map, *(m_polygon.begin() + 0)); + const auto& p2 = get(m_point_map, *(m_polygon.begin() + 1)); + const auto& pn = get(m_point_map, *(m_polygon.begin() + (n - 1))); + + r[0] = m_squared_distance_2(p1, query); + A[0] = m_area_2(p1, p2, query); + B[0] = m_area_2(pn, p2, query); + + for (std::size_t i = 1; i < n - 1; ++i) + { + const auto& pi0 = get(m_point_map, *(m_polygon.begin() + (i - 1))); + const auto& pi1 = get(m_point_map, *(m_polygon.begin() + (i + 0))); + const auto& pi2 = get(m_point_map, *(m_polygon.begin() + (i + 1))); + + r[i] = m_squared_distance_2(pi1, query); + A[i] = m_area_2(pi1, pi2, query); + B[i] = m_area_2(pi0, pi2, query); + } + + const auto& pm = get(m_point_map, *(m_polygon.begin() + (n - 2))); + r[n - 1] = m_squared_distance_2(pn, query); + A[n - 1] = m_area_2(pn, p1, query); + B[n - 1] = m_area_2(pm, p1, query); + + // Compute unnormalized weights following the formula (25) with p = 2 from [1]. + CGAL_assertion(A[n - 1] != FT(0) && A[0] != FT(0)); + w[0] = (r[1] * A[n - 1] - r[0] * B[0] + r[n - 1] * A[0]) / (A[n - 1] * A[0]); + + for (std::size_t i = 1; i < n - 1; ++i) + { + CGAL_assertion(A[i - 1] != FT(0) && A[i] != FT(0)); + w[i] = (r[i + 1] * A[i - 1] - r[i] * B[i] + r[i - 1] * A[i]) / (A[i - 1] * A[i]); + } + + CGAL_assertion(A[n - 2] != FT(0) && A[n - 1] != FT(0)); + w[n - 1] = (r[0] * A[n - 2] - r[n - 1] * B[n - 1] + r[n - 2] * A[n - 1]) / (A[n - 2] * A[n - 1]); + + // Normalize if necessary. + if (normalize) + internal::normalize(w); + + // Return weights. + for (std::size_t i = 0; i < n; ++i) + *(weights++) = w[i]; + + return weights; + } +}; + +/*! + \ingroup PkgWeightsRefBarycentricDiscreteHarmonicWeights + + \brief computes 2D discrete harmonic weights for polygons. + + This function computes 2D discrete harmonic weights at a given `query` point + with respect to the vertices of a strictly convex `polygon`, that is one + weight per vertex. The weights are stored in a destination range + beginning at `w_begin`. + + Internally, the class `Discrete_harmonic_weights_2` is used. If one wants to process + multiple query points, it is better to use that class. When using the free function, + internal memory is allocated for each query point, while when using the class, + it is allocated only once which is much more efficient. However, for a few query + points, it is easier to use this function. It can also be used when the processing + time is not a concern. + + \tparam PointRange a model of `ConstRange` whose iterator type is `RandomAccessIterator` + and value type is `GeomTraits::Point_2` + \tparam OutIterator a model of `OutputIterator` whose value type is `GeomTraits::FT` + \tparam GeomTraits a model of `AnalyticWeightTraits_2` + + \param polygon an instance of `PointRange` with 2D points which form a strictly convex polygon + \param query a query point + \param w_begin the beginning of the destination range with the computed weights + \param traits a traits class with geometric objects, predicates, and constructions; + this parameter can be omitted if the traits class can be deduced from the point type + + \return an output iterator to the element in the destination range, one past the last weight stored + + \pre `polygon.size() >= 3` + \pre `polygon` is simple + \pre `polygon` is strictly convex +*/ +template +OutIterator discrete_harmonic_weights_2(const PointRange& polygon, + const typename GeomTraits::Point_2& query, + OutIterator w_begin, + const GeomTraits& traits) +{ + Discrete_harmonic_weights_2 discrete_harmonic(polygon, traits); + return discrete_harmonic(query, w_begin); +} + +/// \cond SKIP_IN_MANUAL +template +OutIterator discrete_harmonic_weights_2(const PointRange& polygon, + const typename PointRange::value_type& query, + OutIterator w_begin) +{ + using Point_2 = typename PointRange::value_type; + using GeomTraits = typename Kernel_traits::Kernel; + + const GeomTraits traits; + return discrete_harmonic_weights_2(polygon, query, w_begin, traits); +} +/// \endcond + } // namespace Weights } // namespace CGAL diff --git a/Weights/include/CGAL/Weights/internal/pmp_weights_deprecated.h b/Weights/include/CGAL/Weights/internal/pmp_weights_deprecated.h index 0170e812d1f..7a7cd14a4c2 100644 --- a/Weights/include/CGAL/Weights/internal/pmp_weights_deprecated.h +++ b/Weights/include/CGAL/Weights/internal/pmp_weights_deprecated.h @@ -19,8 +19,10 @@ "This part of the package is deprecated since the version 5.4 of CGAL!" #include +#ifndef CGAL_NO_DEPRECATED_CODE + // README: -// This header collects all weights, which have been in CGAL before unifying them +// This header collects all weights which have been in CGAL before unifying them // into the new package Weights. This header is for information purpose only. It // will be removed in the next release. @@ -41,17 +43,16 @@ namespace deprecated { // (i.e. for v0, v1, v2 and v2, v1, v0 the returned cot weights can be slightly different). // This one provides stable results. template -struct Cotangent_value_Meyer_impl { - +struct Cotangent_value_Meyer_impl +{ typedef typename boost::graph_traits::vertex_descriptor vertex_descriptor; template - double operator()( - vertex_descriptor v0, - vertex_descriptor v1, - vertex_descriptor v2, - const VertexPointMap& ppmap) { - + double operator()(vertex_descriptor v0, + vertex_descriptor v1, + vertex_descriptor v2, + const VertexPointMap& ppmap) + { typedef typename Kernel_traits< typename boost::property_traits::value_type >::Kernel::Vector_3 Vector; @@ -66,28 +67,27 @@ struct Cotangent_value_Meyer_impl { // double divider = CGAL::sqrt(dot_aa * dot_bb - dot_ab * dot_ab); const Vector cross_ab = CGAL::cross_product(a, b); - const double divider = CGAL::to_double( - CGAL::approximate_sqrt(cross_ab * cross_ab)); + const double divider = CGAL::to_double(CGAL::approximate_sqrt(cross_ab * cross_ab)); - if (divider == 0.0 /* || divider != divider */) { + if (divider == 0.0 /* || divider != divider */) + { CGAL::collinear(get(ppmap, v0), get(ppmap, v1), get(ppmap, v2)) ? CGAL_warning_msg(false, "Infinite Cotangent value with the degenerate triangle!") : CGAL_warning_msg(false, "Infinite Cotangent value due to the floating point arithmetic!"); - return dot_ab > 0.0 ? - (std::numeric_limits::max)() : - -(std::numeric_limits::max)(); + return dot_ab > 0.0 ? (std::numeric_limits::max)() : + -(std::numeric_limits::max)(); } + return dot_ab / divider; } }; // Same as above but with a different API. -template< -typename PolygonMesh, -typename VertexPointMap = typename boost::property_map::type> -class Cotangent_value_Meyer { - +template::type> +class Cotangent_value_Meyer +{ protected: typedef VertexPointMap Point_property_map; typedef typename boost::graph_traits::vertex_descriptor vertex_descriptor; @@ -98,36 +98,27 @@ protected: Point_property_map ppmap_; public: - Cotangent_value_Meyer( - PolygonMesh& pmesh_, - VertexPointMap vpmap_) : - pmesh_(pmesh_), - ppmap_(vpmap_) + Cotangent_value_Meyer(PolygonMesh& pmesh_, + VertexPointMap vpmap_) + : pmesh_(pmesh_), ppmap_(vpmap_) { } - PolygonMesh& pmesh() { - return pmesh_; - } - - Point_property_map& ppmap() { - return ppmap_; - } - - double operator()( - vertex_descriptor v0, - vertex_descriptor v1, - vertex_descriptor v2) { + PolygonMesh& pmesh() { return pmesh_; } + Point_property_map& ppmap() { return ppmap_; } + double operator()(vertex_descriptor v0, + vertex_descriptor v1, + vertex_descriptor v2) + { return Cotangent_value_Meyer_impl()(v0, v1, v2, ppmap()); } }; // Imported from skeletonization. -template< -typename PolygonMesh, -typename VertexPointMap = typename boost::property_map::type> -class Cotangent_value_Meyer_secure { - +template::type> +class Cotangent_value_Meyer_secure +{ typedef VertexPointMap Point_property_map; typedef typename boost::graph_traits::vertex_descriptor vertex_descriptor; typedef typename boost::property_traits::value_type Point; @@ -137,26 +128,18 @@ class Cotangent_value_Meyer_secure { Point_property_map ppmap_; public: - Cotangent_value_Meyer_secure( - PolygonMesh& pmesh_, - VertexPointMap vpmap_) : - pmesh_(pmesh_), - ppmap_(vpmap_) + Cotangent_value_Meyer_secure(PolygonMesh& pmesh_, + VertexPointMap vpmap_) + : pmesh_(pmesh_), ppmap_(vpmap_) { } - PolygonMesh& pmesh() { - return pmesh_; - } - - Point_property_map& ppmap() { - return ppmap_; - } - - double operator()( - vertex_descriptor v0, - vertex_descriptor v1, - vertex_descriptor v2) { + PolygonMesh& pmesh() { return pmesh_; } + Point_property_map& ppmap() { return ppmap_; } + double operator()(vertex_descriptor v0, + vertex_descriptor v1, + vertex_descriptor v2) + { const Vector a = get(ppmap(), v0) - get(ppmap(), v1); const Vector b = get(ppmap(), v2) - get(ppmap(), v1); @@ -174,37 +157,28 @@ public: // Returns the cotangent value of the half angle [v0, v1, v2] by clamping between // [1, 89] degrees as suggested by -[Friedel] Unconstrained Spherical Parameterization-. -template< -typename PolygonMesh, -typename VertexPointMap = typename boost::property_map::type, +template::type, typename CotangentValue = Cotangent_value_Meyer > -class Cotangent_value_clamped : CotangentValue { - - Cotangent_value_clamped() - { } +class Cotangent_value_clamped : CotangentValue +{ + Cotangent_value_clamped() { } public: - Cotangent_value_clamped( - PolygonMesh& pmesh_, - VertexPointMap vpmap_) : - CotangentValue(pmesh_, vpmap_) + Cotangent_value_clamped(PolygonMesh& pmesh_, + VertexPointMap vpmap_) + : CotangentValue(pmesh_, vpmap_) { } - PolygonMesh& pmesh() { - return CotangentValue::pmesh(); - } - - VertexPointMap& ppmap() { - return CotangentValue::ppmap(); - } + PolygonMesh& pmesh() { return CotangentValue::pmesh(); } + VertexPointMap& ppmap() { return CotangentValue::ppmap(); } typedef typename boost::graph_traits::vertex_descriptor vertex_descriptor; - double operator()( - vertex_descriptor v0, - vertex_descriptor v1, - vertex_descriptor v2) { - + double operator()(vertex_descriptor v0, + vertex_descriptor v1, + vertex_descriptor v2) + { const double cot_1 = 57.289962; const double cot_89 = 0.017455; const double value = CotangentValue::operator()(v0, v1, v2); @@ -212,37 +186,28 @@ public: } }; -template< -typename PolygonMesh, -typename VertexPointMap = typename boost::property_map::type, +template::type, typename CotangentValue = Cotangent_value_Meyer > -class Cotangent_value_clamped_2 : CotangentValue { - - Cotangent_value_clamped_2() - { } +class Cotangent_value_clamped_2 : CotangentValue +{ + Cotangent_value_clamped_2() { } public: - Cotangent_value_clamped_2( - PolygonMesh& pmesh_, - VertexPointMap vpmap_) : - CotangentValue(pmesh_, vpmap_) + Cotangent_value_clamped_2(PolygonMesh& pmesh_, + VertexPointMap vpmap_) + : CotangentValue(pmesh_, vpmap_) { } - PolygonMesh& pmesh() { - return CotangentValue::pmesh(); - } - - VertexPointMap& ppmap() { - return CotangentValue::ppmap(); - } + PolygonMesh& pmesh() { return CotangentValue::pmesh(); } + VertexPointMap& ppmap() { return CotangentValue::ppmap(); } typedef typename boost::graph_traits::vertex_descriptor vertex_descriptor; - double operator()( - vertex_descriptor v0, - vertex_descriptor v1, - vertex_descriptor v2) { - + double operator()(vertex_descriptor v0, + vertex_descriptor v1, + vertex_descriptor v2) + { const double cot_5 = 5.671282; const double cot_175 = -cot_5; const double value = CotangentValue::operator()(v0, v1, v2); @@ -250,80 +215,66 @@ public: } }; -template< -typename PolygonMesh, -typename CotangentValue = Cotangent_value_Meyer_impl > -struct Cotangent_value_minimum_zero_impl : CotangentValue { - +template > +struct Cotangent_value_minimum_zero_impl + : CotangentValue +{ typedef typename boost::graph_traits::vertex_descriptor vertex_descriptor; template - double operator()( - vertex_descriptor v0, - vertex_descriptor v1, - vertex_descriptor v2, - const VertexPointMap ppmap) { - + double operator()(vertex_descriptor v0, + vertex_descriptor v1, + vertex_descriptor v2, + const VertexPointMap ppmap) + { const double value = CotangentValue::operator()(v0, v1, v2, ppmap); return (std::max)(0.0, value); } }; -template< -typename PolygonMesh, -typename VertexPointMap = typename boost::property_map::type, +template::type, typename CotangentValue = Cotangent_value_Meyer > -class Cotangent_value_minimum_zero : CotangentValue { - +class Cotangent_value_minimum_zero : CotangentValue +{ Cotangent_value_minimum_zero() { } public: - Cotangent_value_minimum_zero( - PolygonMesh& pmesh_, - VertexPointMap vpmap_) : - CotangentValue(pmesh_, vpmap_) + Cotangent_value_minimum_zero(PolygonMesh& pmesh_, + VertexPointMap vpmap_) + : CotangentValue(pmesh_, vpmap_) { } - PolygonMesh& pmesh() { - return CotangentValue::pmesh(); - } - - VertexPointMap& ppmap() { - return CotangentValue::ppmap(); - } + PolygonMesh& pmesh() { return CotangentValue::pmesh(); } + VertexPointMap& ppmap() { return CotangentValue::ppmap(); } typedef typename boost::graph_traits::vertex_descriptor vertex_descriptor; - double operator()( - vertex_descriptor v0, - vertex_descriptor v1, - vertex_descriptor v2) { + double operator()(vertex_descriptor v0, + vertex_descriptor v1, + vertex_descriptor v2) + { const double value = CotangentValue::operator()(v0, v1, v2); return (std::max)(0.0, value); } }; -template< -typename PolygonMesh, -typename VertexPointMap = typename boost::property_map::type, -typename CotangentValue = Cotangent_value_Meyer > -class Voronoi_area : CotangentValue { - +template::type, + typename CotangentValue = Cotangent_value_Meyer > +class Voronoi_area + : CotangentValue +{ public: - Voronoi_area( - PolygonMesh& pmesh_, - VertexPointMap vpmap_) : - CotangentValue(pmesh_, vpmap_) + Voronoi_area(PolygonMesh& pmesh_, + VertexPointMap vpmap_) + : CotangentValue(pmesh_, vpmap_) { } - PolygonMesh& pmesh() { - return CotangentValue::pmesh(); - } - - VertexPointMap& ppmap() { - return CotangentValue::ppmap(); - } + PolygonMesh& pmesh() { return CotangentValue::pmesh(); } + VertexPointMap& ppmap() { return CotangentValue::ppmap(); } typedef typename boost::graph_traits::vertex_descriptor vertex_descriptor; typedef typename boost::graph_traits::in_edge_iterator in_edge_iterator; @@ -333,13 +284,13 @@ public: typedef typename boost::property_traits::value_type Point; typedef typename Kernel_traits::Kernel::Vector_3 Vector; - double operator()(vertex_descriptor v0) { - + double operator()(vertex_descriptor v0) + { // return 1.0; double voronoi_area = 0.0; for (const halfedge_descriptor he : - halfedges_around_target(halfedge(v0, pmesh()), pmesh())) { - + halfedges_around_target(halfedge(v0, pmesh()), pmesh())) + { if (is_border(he, pmesh()) ) { continue; } CGAL_assertion(CGAL::is_triangle_mesh(pmesh())); @@ -356,12 +307,12 @@ public: const CGAL::Angle angle1 = CGAL::angle(v_op_p, v1_p, v0_p); const CGAL::Angle angle_op = CGAL::angle(v0_p, v_op_p, v1_p); - bool obtuse = - (angle0 == CGAL::OBTUSE) || - (angle1 == CGAL::OBTUSE) || - (angle_op == CGAL::OBTUSE); + bool obtuse = (angle0 == CGAL::OBTUSE) || + (angle1 == CGAL::OBTUSE) || + (angle_op == CGAL::OBTUSE); - if (!obtuse) { + if (!obtuse) + { const double cot_v1 = CotangentValue::operator()(v_op, v1, v0); const double cot_v_op = CotangentValue::operator()(v0, v_op, v1); @@ -369,18 +320,18 @@ public: const double term2 = cot_v_op * to_double((v1_p - v0_p).squared_length()); voronoi_area += (1.0 / 8.0) * (term1 + term2); - } else { - const double area_t = to_double( - CGAL::approximate_sqrt( - CGAL::squared_area(v0_p, v1_p, v_op_p))); + } + else + { + const double area_t = to_double(CGAL::approximate_sqrt(CGAL::squared_area(v0_p, v1_p, v_op_p))); - if (angle0 == CGAL::OBTUSE) { + if (angle0 == CGAL::OBTUSE) voronoi_area += area_t / 2.0; - } else { + else voronoi_area += area_t / 4.0; - } } } + CGAL_warning_msg(voronoi_area != 0.0, "Zero Voronoi area!"); return voronoi_area; } @@ -388,118 +339,103 @@ public: // Returns the cotangent value of the half angle [v0, v1, v2] by dividing the triangle area // as suggested by -[Mullen08] Spectral Conformal Parameterization-. -template< -typename PolygonMesh, -typename VertexPointMap = typename boost::property_map::type, -typename CotangentValue = Cotangent_value_Meyer > -class Cotangent_value_area_weighted : CotangentValue { - - Cotangent_value_area_weighted() - { } +template::type, + typename CotangentValue = Cotangent_value_Meyer > +class Cotangent_value_area_weighted + : CotangentValue +{ + Cotangent_value_area_weighted() { } public: - Cotangent_value_area_weighted( - PolygonMesh& pmesh_, - VertexPointMap vpmap_) : - CotangentValue(pmesh_, vpmap_) + Cotangent_value_area_weighted(PolygonMesh& pmesh_, + VertexPointMap vpmap_) : + CotangentValue(pmesh_, vpmap_) { } - PolygonMesh& pmesh() { - return CotangentValue::pmesh(); - } - - VertexPointMap& ppmap() { - return CotangentValue::ppmap(); - } + PolygonMesh& pmesh() { return CotangentValue::pmesh(); } + VertexPointMap& ppmap() { return CotangentValue::ppmap(); } typedef typename boost::graph_traits::vertex_descriptor vertex_descriptor; - double operator()( - vertex_descriptor v0, - vertex_descriptor v1, - vertex_descriptor v2) { - + double operator()(vertex_descriptor v0, + vertex_descriptor v1, + vertex_descriptor v2) + { return CotangentValue::operator()(v0, v1, v2) / - CGAL::sqrt(CGAL::squared_area( - get(this->ppmap(), v0), - get(this->ppmap(), v1), - get(this->ppmap(), v2))); + CGAL::sqrt(CGAL::squared_area(get(this->ppmap(), v0), + get(this->ppmap(), v1), + get(this->ppmap(), v2))); } }; // Cotangent weight calculator: // Cotangent_value: as suggested by -[Sorkine07] ARAP Surface Modeling-. // Cotangent_value_area_weighted: as suggested by -[Mullen08] Spectral Conformal Parameterization-. -template< -typename PolygonMesh, -typename CotangentValue = Cotangent_value_minimum_zero_impl > -struct Cotangent_weight_impl : CotangentValue { - +template > +struct Cotangent_weight_impl + : CotangentValue +{ typedef typename boost::graph_traits::halfedge_descriptor halfedge_descriptor; typedef typename boost::graph_traits::vertex_descriptor vertex_descriptor; // Returns the cotangent weight of the specified halfedge_descriptor. // Edge orientation is trivial. template - double operator()( - halfedge_descriptor he, - PolygonMesh& pmesh, - const VertexPointMap& ppmap) { - + double operator()(halfedge_descriptor he, + PolygonMesh& pmesh, + const VertexPointMap& ppmap) + { const vertex_descriptor v0 = target(he, pmesh); const vertex_descriptor v1 = source(he, pmesh); // Only one triangle for border edges. - if (is_border_edge(he, pmesh)) { - + if (is_border_edge(he, pmesh)) + { const halfedge_descriptor he_cw = opposite(next(he, pmesh), pmesh); vertex_descriptor v2 = source(he_cw, pmesh); - if (is_border_edge(he_cw, pmesh)) { + if (is_border_edge(he_cw, pmesh)) + { const halfedge_descriptor he_ccw = prev(opposite(he, pmesh), pmesh); v2 = source(he_ccw, pmesh); } - return (CotangentValue::operator()(v0, v2, v1, ppmap) / 2.0); - } else { + return (CotangentValue::operator()(v0, v2, v1, ppmap) / 2.0); + } + else + { const halfedge_descriptor he_cw = opposite(next(he, pmesh), pmesh); const vertex_descriptor v2 = source(he_cw, pmesh); const halfedge_descriptor he_ccw = prev(opposite(he, pmesh), pmesh); const vertex_descriptor v3 = source(he_ccw, pmesh); - return ( - CotangentValue::operator()(v0, v2, v1, ppmap) / 2.0 + - CotangentValue::operator()(v0, v3, v1, ppmap) / 2.0 ); + return (CotangentValue::operator()(v0, v2, v1, ppmap) / 2.0 + + CotangentValue::operator()(v0, v3, v1, ppmap) / 2.0 ); } } }; -template< -typename PolygonMesh, -typename VertexPointMap = typename boost::property_map::type, -typename CotangentValue = Cotangent_value_minimum_zero > -class Cotangent_weight : CotangentValue { - - Cotangent_weight() - { } +template::type, + typename CotangentValue = Cotangent_value_minimum_zero > +class Cotangent_weight + : CotangentValue +{ + Cotangent_weight() { } public: - Cotangent_weight( - PolygonMesh& pmesh_, - VertexPointMap vpmap_) : - CotangentValue(pmesh_, vpmap_) + Cotangent_weight(PolygonMesh& pmesh_, + VertexPointMap vpmap_) + : CotangentValue(pmesh_, vpmap_) { } - Cotangent_weight(PolygonMesh& pmesh_) : - CotangentValue(pmesh_, get(CGAL::vertex_point, pmesh_)) + Cotangent_weight(PolygonMesh& pmesh_) + : CotangentValue(pmesh_, get(CGAL::vertex_point, pmesh_)) { } - PolygonMesh& pmesh() { - return CotangentValue::pmesh(); - } - - VertexPointMap& ppmap() { - return CotangentValue::ppmap(); - } + PolygonMesh& pmesh() { return CotangentValue::pmesh(); } + VertexPointMap& ppmap() { return CotangentValue::ppmap(); } typedef typename boost::graph_traits::halfedge_descriptor halfedge_descriptor; typedef typename boost::graph_traits::vertex_descriptor vertex_descriptor; @@ -510,52 +446,55 @@ public: // Returns the cotangent weight of the specified halfedge_descriptor. // Edge orientation is trivial. - double operator()(halfedge_descriptor he) { + double operator()(halfedge_descriptor he) + { const vertex_descriptor v0 = target(he, pmesh()); const vertex_descriptor v1 = source(he, pmesh()); // Only one triangle for border edges. - if (is_border_edge(he, pmesh())) { - + if (is_border_edge(he, pmesh())) + { const halfedge_descriptor he_cw = opposite(next(he, pmesh()), pmesh()); vertex_descriptor v2 = source(he_cw, pmesh()); - if (is_border_edge(he_cw, pmesh())) { + if (is_border_edge(he_cw, pmesh())) + { const halfedge_descriptor he_ccw = prev(opposite(he, pmesh()), pmesh()); v2 = source(he_ccw, pmesh()); } - return (CotangentValue::operator()(v0, v2, v1) / 2.0); - } else { + return (CotangentValue::operator()(v0, v2, v1) / 2.0); + } + else + { const halfedge_descriptor he_cw = opposite(next(he, pmesh()), pmesh()); const vertex_descriptor v2 = source(he_cw, pmesh()); const halfedge_descriptor he_ccw = prev(opposite(he, pmesh()), pmesh()); const vertex_descriptor v3 = source(he_ccw, pmesh()); - return ( - CotangentValue::operator()(v0, v2, v1) / 2.0 + - CotangentValue::operator()(v0, v3, v1) / 2.0 ); - } + return (CotangentValue::operator()(v0, v2, v1) / 2.0 + + CotangentValue::operator()(v0, v3, v1) / 2.0 ); + } } }; // Single cotangent from -[Chao10] Simple Geometric Model for Elastic Deformation. -template< -typename PolygonMesh, -typename CotangentValue = Cotangent_value_Meyer_impl > -struct Single_cotangent_weight_impl : CotangentValue { - +template > +struct Single_cotangent_weight_impl + : CotangentValue +{ typedef typename boost::graph_traits::halfedge_descriptor halfedge_descriptor; typedef typename boost::graph_traits::vertex_descriptor vertex_descriptor; // Returns the cotangent of the opposite angle of the edge // 0 for border edges (which does not have an opposite angle). template - double operator()( - halfedge_descriptor he, - PolygonMesh& pmesh, - const VertexPointMap& ppmap) { - - if (is_border(he, pmesh)) { return 0.0; } + double operator()(halfedge_descriptor he, + PolygonMesh& pmesh, + const VertexPointMap& ppmap) + { + if (is_border(he, pmesh)) + return 0.0; const vertex_descriptor v0 = target(he, pmesh); const vertex_descriptor v1 = source(he, pmesh); @@ -564,29 +503,22 @@ struct Single_cotangent_weight_impl : CotangentValue { } }; -template< -typename PolygonMesh, -typename VertexPointMap = typename boost::property_map::type, -typename CotangentValue = Cotangent_value_Meyer > -class Single_cotangent_weight : CotangentValue { - - Single_cotangent_weight() - { } +template::type, + typename CotangentValue = Cotangent_value_Meyer > +class Single_cotangent_weight + : CotangentValue +{ + Single_cotangent_weight() { } public: - Single_cotangent_weight( - PolygonMesh& pmesh_, - VertexPointMap vpmap_) : - CotangentValue(pmesh_, vpmap_) + Single_cotangent_weight(PolygonMesh& pmesh_, + VertexPointMap vpmap_) + : CotangentValue(pmesh_, vpmap_) { } - PolygonMesh& pmesh() { - return CotangentValue::pmesh(); - } - - VertexPointMap& ppmap() { - return CotangentValue::ppmap(); - } + PolygonMesh& pmesh() { return CotangentValue::pmesh(); } + VertexPointMap& ppmap() { return CotangentValue::ppmap(); } typedef typename boost::graph_traits::halfedge_descriptor halfedge_descriptor; typedef typename boost::graph_traits::vertex_descriptor vertex_descriptor; @@ -597,9 +529,10 @@ public: // Returns the cotangent of the opposite angle of the edge // 0 for border edges (which does not have an opposite angle). - double operator()(halfedge_descriptor he) { - - if (is_border(he, pmesh())) { return 0.0; } + double operator()(halfedge_descriptor he) + { + if (is_border(he, pmesh())) + return 0.0; const vertex_descriptor v0 = target(he, pmesh()); const vertex_descriptor v1 = source(he, pmesh()); @@ -608,12 +541,12 @@ public: } }; -template< -typename PolygonMesh, -typename VertexPointMap = typename boost::property_map::type, -typename CotangentValue = Cotangent_value_Meyer > -class Cotangent_weight_with_triangle_area : CotangentValue { - +template::type, + typename CotangentValue = Cotangent_value_Meyer > +class Cotangent_weight_with_triangle_area + : CotangentValue +{ typedef PolygonMesh PM; typedef VertexPointMap VPMap; typedef typename boost::property_traits::value_type Point; @@ -621,33 +554,29 @@ class Cotangent_weight_with_triangle_area : CotangentValue { typedef typename boost::graph_traits::halfedge_descriptor halfedge_descriptor; typedef typename boost::graph_traits::vertex_descriptor vertex_descriptor; - Cotangent_weight_with_triangle_area() - { } + Cotangent_weight_with_triangle_area() { } public: - Cotangent_weight_with_triangle_area( - PolygonMesh& pmesh_, - VertexPointMap vpmap_) : - CotangentValue(pmesh_, vpmap_) + Cotangent_weight_with_triangle_area(PolygonMesh& pmesh_, + VertexPointMap vpmap_) + : CotangentValue(pmesh_, vpmap_) { } - PolygonMesh& pmesh() { - return CotangentValue::pmesh(); - } + PolygonMesh& pmesh() { return CotangentValue::pmesh(); } + VertexPointMap& ppmap() { return CotangentValue::ppmap(); } - VertexPointMap& ppmap() { - return CotangentValue::ppmap(); - } - - double operator()(halfedge_descriptor he) { + double operator()(halfedge_descriptor he) + { const vertex_descriptor v0 = target(he, pmesh()); const vertex_descriptor v1 = source(he, pmesh()); // Only one triangle for border edges. - if (is_border_edge(he, pmesh())) { + if (is_border_edge(he, pmesh())) + { const halfedge_descriptor he_cw = opposite(next(he, pmesh()), pmesh()); vertex_descriptor v2 = source(he_cw, pmesh()); - if (is_border_edge(he_cw, pmesh())) { + if (is_border_edge(he_cw, pmesh())) + { const halfedge_descriptor he_ccw = prev(opposite(he, pmesh()), pmesh()); v2 = source(he_ccw, pmesh()); } @@ -655,11 +584,11 @@ public: const Point& v0_p = get(ppmap(), v0); const Point& v1_p = get(ppmap(), v1); const Point& v2_p = get(ppmap(), v2); - const double area_t = to_double( - CGAL::sqrt(CGAL::squared_area(v0_p, v1_p, v2_p))); + const double area_t = to_double(CGAL::sqrt(CGAL::squared_area(v0_p, v1_p, v2_p))); return (CotangentValue::operator()(v0, v2, v1) / area_t); - - } else { + } + else + { const halfedge_descriptor he_cw = opposite(next(he, pmesh()), pmesh()); const vertex_descriptor v2 = source(he_cw, pmesh()); const halfedge_descriptor he_ccw = prev(opposite(he, pmesh()), pmesh()); @@ -672,37 +601,31 @@ public: const double area_t1 = to_double(CGAL::sqrt(CGAL::squared_area(v0_p, v1_p, v2_p))); const double area_t2 = to_double(CGAL::sqrt(CGAL::squared_area(v0_p, v1_p, v3_p))); - return ( - CotangentValue::operator()(v0, v2, v1) / area_t1 + - CotangentValue::operator()(v0, v3, v1) / area_t2 ); + return (CotangentValue::operator()(v0, v2, v1) / area_t1 + + CotangentValue::operator()(v0, v3, v1) / area_t2 ); } + return 0.0; } }; // Mean value calculator described in -[Floater04] Mean Value Coordinates- -template< -typename PolygonMesh, -typename VertexPointMap = typename boost::property_map::type> -class Mean_value_weight { - - // Mean_value_weight() - // {} +template::type> +class Mean_value_weight +{ + // Mean_value_weight() {} PolygonMesh& pmesh_; VertexPointMap vpmap_; public: - Mean_value_weight( - PolygonMesh& pmesh_, - VertexPointMap vpmap) : - pmesh_(pmesh_), - vpmap_(vpmap) + Mean_value_weight(PolygonMesh& pmesh_, + VertexPointMap vpmap) + : pmesh_(pmesh_), vpmap_(vpmap) { } - PolygonMesh& pmesh() { - return pmesh_; - } + PolygonMesh& pmesh() { return pmesh_; } typedef typename boost::graph_traits::halfedge_descriptor halfedge_descriptor; typedef typename boost::graph_traits::vertex_descriptor vertex_descriptor; @@ -714,42 +637,43 @@ public: // Returns the mean-value coordinate of the specified halfedge_descriptor. // Returns different value for different edge orientation (which is a normal // behavior according to the formula). - double operator()(halfedge_descriptor he) { - + double operator()(halfedge_descriptor he) + { const vertex_descriptor v0 = target(he, pmesh()); const vertex_descriptor v1 = source(he, pmesh()); const Vector vec = get(vpmap_, v0) - get(vpmap_, v1); const double norm = CGAL::sqrt(vec.squared_length()); // Only one triangle for border edges. - if (is_border_edge(he, pmesh())) { - + if (is_border_edge(he, pmesh())) + { const halfedge_descriptor he_cw = opposite(next(he, pmesh()), pmesh()); vertex_descriptor v2 = source(he_cw, pmesh()); - if (is_border_edge(he_cw, pmesh())) { + if (is_border_edge(he_cw, pmesh())) + { const halfedge_descriptor he_ccw = prev(opposite(he, pmesh()), pmesh()); v2 = source(he_ccw, pmesh()); } - return (half_tan_value_2(v1, v0, v2) / norm); - } else { + return (half_tan_value_2(v1, v0, v2) / norm); + } + else + { const halfedge_descriptor he_cw = opposite(next(he, pmesh()), pmesh()); const vertex_descriptor v2 = source(he_cw, pmesh()); const halfedge_descriptor he_ccw = prev(opposite(he, pmesh()), pmesh()); const vertex_descriptor v3 = source(he_ccw, pmesh()); - return ( - half_tan_value_2(v1, v0, v2) / norm + - half_tan_value_2(v1, v0, v3) / norm); + return (half_tan_value_2(v1, v0, v2) / norm + + half_tan_value_2(v1, v0, v3) / norm); } } private: // Returns the tangent value of the half angle v0_v1_v2 / 2. - double half_tan_value( - vertex_descriptor v0, - vertex_descriptor v1, - vertex_descriptor v2) { - + double half_tan_value(vertex_descriptor v0, + vertex_descriptor v1, + vertex_descriptor v2) + { const Vector vec0 = get(vpmap_, v1) - get(vpmap_, v2); const Vector vec1 = get(vpmap_, v2) - get(vpmap_, v0); const Vector vec2 = get(vpmap_, v0) - get(vpmap_, v1); @@ -765,11 +689,10 @@ private: } // My deviation built on Meyer_02. - double half_tan_value_2( - vertex_descriptor v0, - vertex_descriptor v1, - vertex_descriptor v2) { - + double half_tan_value_2(vertex_descriptor v0, + vertex_descriptor v1, + vertex_descriptor v2) + { const Vector a = get(vpmap_, v0) - get(vpmap_, v1); const Vector b = get(vpmap_, v2) - get(vpmap_, v1); const double dot_ab = a[0] * b[0] + a[1] * b[1] + a[2] * b[2]; @@ -787,32 +710,28 @@ private: } }; -template< -typename PolygonMesh, -typename PrimaryWeight = Cotangent_weight, -typename SecondaryWeight = Mean_value_weight > -class Hybrid_weight : public PrimaryWeight, SecondaryWeight { - +template, + typename SecondaryWeight = Mean_value_weight > +class Hybrid_weight + : public PrimaryWeight, SecondaryWeight +{ PrimaryWeight primary; SecondaryWeight secondary; - Hybrid_weight() - { } + Hybrid_weight() { } public: - Hybrid_weight(PolygonMesh& pmesh_) : - primary(pmesh_), - secondary(pmesh_) + Hybrid_weight(PolygonMesh& pmesh_) + : primary(pmesh_), secondary(pmesh_) { } - PolygonMesh& pmesh() { - return primary.pmesh(); - } + PolygonMesh& pmesh() { return primary.pmesh(); } typedef typename boost::graph_traits::halfedge_descriptor halfedge_descriptor; - double operator()(halfedge_descriptor he) { - + double operator()(halfedge_descriptor he) + { const double weight = primary(he); // if (weight < 0.0) { std::cout << "Negative weight!" << std::endl; } return (weight >= 0.0) ? weight : secondary(he); @@ -821,27 +740,25 @@ public: // Trivial uniform weights (created for test purposes). template -class Uniform_weight { +class Uniform_weight +{ public: typedef typename boost::graph_traits::halfedge_descriptor halfedge_descriptor; - double operator()(halfedge_descriptor /* e */) - { return 1.0; } + double operator()(halfedge_descriptor /* e */) { return 1.0; } }; template -class Scale_dependent_weight_fairing { - +class Scale_dependent_weight_fairing +{ PolygonMesh& pmesh_; public: - Scale_dependent_weight_fairing(PolygonMesh& pmesh_) : - pmesh_(pmesh_) + Scale_dependent_weight_fairing(PolygonMesh& pmesh_) + : pmesh_(pmesh_) { } - PolygonMesh& pmesh() { - return pmesh_; - } + PolygonMesh& pmesh() { return pmesh_; } typedef typename boost::graph_traits::halfedge_descriptor halfedge_descriptor; typedef typename boost::graph_traits::vertex_descriptor vertex_descriptor; @@ -852,53 +769,53 @@ public: double w_i(vertex_descriptor /* v_i */) { return 1.0; } - double w_ij(halfedge_descriptor he) { - + double w_ij(halfedge_descriptor he) + { const Vector v = target(he, pmesh())->point() - source(he, pmesh())->point(); const double divider = CGAL::sqrt(v.squared_length()); - if (divider == 0.0) { + if (divider == 0.0) + { CGAL_warning_msg(false, "Scale dependent weight - zero length edge."); return (std::numeric_limits::max)(); } + return 1.0 / divider; } }; -template< -typename PolygonMesh, -typename VertexPointMap = typename boost::property_map::type> -class Cotangent_weight_with_voronoi_area_fairing { - +template::type> +class Cotangent_weight_with_voronoi_area_fairing +{ typedef PolygonMesh PM; typedef VertexPointMap VPMap; Voronoi_area voronoi_functor; Cotangent_weight > cotangent_functor; public: - Cotangent_weight_with_voronoi_area_fairing(PM& pmesh_) : - voronoi_functor(pmesh_, get(CGAL::vertex_point, pmesh_)), - cotangent_functor(pmesh_, get(CGAL::vertex_point, pmesh_)) + Cotangent_weight_with_voronoi_area_fairing(PM& pmesh_) + : voronoi_functor(pmesh_, get(CGAL::vertex_point, pmesh_)), + cotangent_functor(pmesh_, get(CGAL::vertex_point, pmesh_)) { } - Cotangent_weight_with_voronoi_area_fairing( - PM& pmesh_, - VPMap vpmap_) : - voronoi_functor(pmesh_, vpmap_), - cotangent_functor(pmesh_, vpmap_) + Cotangent_weight_with_voronoi_area_fairing(PM& pmesh_, + VPMap vpmap_) + : voronoi_functor(pmesh_, vpmap_), + cotangent_functor(pmesh_, vpmap_) { } - PM& pmesh() { - return voronoi_functor.pmesh(); - } + PM& pmesh() { return voronoi_functor.pmesh(); } typedef typename boost::graph_traits::halfedge_descriptor halfedge_descriptor; typedef typename boost::graph_traits::vertex_descriptor vertex_descriptor; - double w_i(vertex_descriptor v_i) { + double w_i(vertex_descriptor v_i) + { return 0.5 / voronoi_functor(v_i); } - double w_ij(halfedge_descriptor he) { + double w_ij(halfedge_descriptor he) + { return cotangent_functor(he) * 2.0; } }; @@ -906,54 +823,51 @@ public: // Cotangent_value_Meyer has been changed to the version: // Cotangent_value_Meyer_secure to avoid imprecisions from // the issue #4706 - https://github.com/CGAL/cgal/issues/4706. -template< -typename PolygonMesh, -typename VertexPointMap = typename boost::property_map::type> -class Cotangent_weight_with_voronoi_area_fairing_secure { - +template::type> +class Cotangent_weight_with_voronoi_area_fairing_secure +{ typedef PolygonMesh PM; typedef VertexPointMap VPMap; Voronoi_area voronoi_functor; Cotangent_weight > cotangent_functor; public: - Cotangent_weight_with_voronoi_area_fairing_secure(PM& pmesh_) : - voronoi_functor(pmesh_, get(CGAL::vertex_point, pmesh_)), - cotangent_functor(pmesh_, get(CGAL::vertex_point, pmesh_)) + Cotangent_weight_with_voronoi_area_fairing_secure(PM& pmesh_) + : voronoi_functor(pmesh_, get(CGAL::vertex_point, pmesh_)), + cotangent_functor(pmesh_, get(CGAL::vertex_point, pmesh_)) { } - Cotangent_weight_with_voronoi_area_fairing_secure( - PM& pmesh_, - VPMap vpmap_) : - voronoi_functor(pmesh_, vpmap_), - cotangent_functor(pmesh_, vpmap_) + Cotangent_weight_with_voronoi_area_fairing_secure(PM& pmesh_, + VPMap vpmap_) + : voronoi_functor(pmesh_, vpmap_), + cotangent_functor(pmesh_, vpmap_) { } - PM& pmesh() { - return voronoi_functor.pmesh(); - } + PM& pmesh() { return voronoi_functor.pmesh(); } typedef typename boost::graph_traits::halfedge_descriptor halfedge_descriptor; typedef typename boost::graph_traits::vertex_descriptor vertex_descriptor; - double w_i(vertex_descriptor v_i) { + double w_i(vertex_descriptor v_i) + { return 0.5 / voronoi_functor(v_i); } - double w_ij(halfedge_descriptor he) { + double w_ij(halfedge_descriptor he) + { return cotangent_functor(he) * 2.0; } }; template -class Uniform_weight_fairing { - +class Uniform_weight_fairing +{ public: typedef typename boost::graph_traits::halfedge_descriptor halfedge_descriptor; typedef typename boost::graph_traits::vertex_descriptor vertex_descriptor; - Uniform_weight_fairing(PolygonMesh&) - { } + Uniform_weight_fairing(PolygonMesh&) { } double w_ij(halfedge_descriptor /* e */) { return 1.0; } double w_i(vertex_descriptor /* v_i */) { return 1.0; } @@ -965,4 +879,6 @@ public: } // namespace Weights } // namespace CGAL +#endif // CGAL_NO_DEPRECATED_CODE + #endif // CGAL_WEIGHTS_PMP_DEPRECATED_H diff --git a/Weights/include/CGAL/Weights/internal/polygon_utils_2.h b/Weights/include/CGAL/Weights/internal/polygon_utils_2.h index b65ed49828c..8b2bb361673 100644 --- a/Weights/include/CGAL/Weights/internal/polygon_utils_2.h +++ b/Weights/include/CGAL/Weights/internal/polygon_utils_2.h @@ -14,7 +14,12 @@ #ifndef CGAL_WEIGHTS_INTERNAL_POLYGON_UTILS_2_H #define CGAL_WEIGHTS_INTERNAL_POLYGON_UTILS_2_H -// STL includes. +#include +#include +#include +#include +#include + #include #include #include @@ -23,345 +28,329 @@ #include #include -// CGAL includes. -#include -#include -#include -#include -#include - namespace CGAL { namespace Weights { namespace internal { - enum class Edge_case { +enum class Edge_case { - EXTERIOR = 0, // exterior part of the polygon - BOUNDARY = 1, // boundary part of the polygon - INTERIOR = 2 // interior part of the polygon - }; + EXTERIOR = 0, // exterior part of the polygon + BOUNDARY = 1, // boundary part of the polygon + INTERIOR = 2 // interior part of the polygon +}; - // VertexRange type enum. - enum class Polygon_type { +// VertexRange type enum. +enum class Polygon_type +{ + CONCAVE = 0, // Concave polygon = non-convex polygon. + WEAKLY_CONVEX = 1, // This is a convex polygon with collinear vertices. + STRICTLY_CONVEX = 2 // This is a convex polygon without collinear vertices. +}; - // Concave polygon = non-convex polygon. - CONCAVE = 0, +// This function is taken from the Polygon_2_algorithms.h header. +// But it is updated to support property maps. +template +int which_side_in_slab_2(const Point_2& query, + const Point_2& low, const Point_2& high, + const Orientation_2& orientation_2, + const CompareX_2& compare_x_2) +{ + const Comparison_result low_x_comp_res = compare_x_2(query, low); + const Comparison_result high_x_comp_res = compare_x_2(query, high); - // This is a convex polygon with collinear vertices. - WEAKLY_CONVEX = 1, - - // This is a convex polygon without collinear vertices. - STRICTLY_CONVEX = 2 - }; - - // This function is taken from the Polygon_2_algorithms.h header. - // But it is updated to support property maps. - template< - class Point_2, - class Orientation_2, - class CompareX_2> - int which_side_in_slab_2( - const Point_2& query, const Point_2& low, const Point_2& high, - const Orientation_2& orientation_2, const CompareX_2& compare_x_2) { - - const auto low_x_comp_res = compare_x_2(query, low); - const auto high_x_comp_res = compare_x_2(query, high); - if (low_x_comp_res == CGAL::SMALLER) { - if (high_x_comp_res == CGAL::SMALLER) { - return -1; - } - } else { - switch (high_x_comp_res) { - case CGAL::LARGER: return 1; - case CGAL::SMALLER: break; - case CGAL::EQUAL: return (low_x_comp_res == CGAL::EQUAL) ? 0 : 1; - } + if (low_x_comp_res == CGAL::SMALLER) { + if (high_x_comp_res == CGAL::SMALLER) { + return -1; } - switch (orientation_2(low, query, high)) { - case CGAL::LEFT_TURN: return 1; - case CGAL::RIGHT_TURN: return -1; - default: return 0; + } else { + switch (high_x_comp_res) { + case CGAL::LARGER: return 1; + case CGAL::SMALLER: break; + case CGAL::EQUAL: return (low_x_comp_res == CGAL::EQUAL) ? 0 : 1; } } - // This function is taken from the Polygon_2_algorithms.h header. - // But it is updated to support property maps. - template< - typename VertexRange, - typename GeomTraits, - typename PointMap> - Edge_case bounded_side_2( - const VertexRange& polygon, const typename GeomTraits::Point_2& query, - const GeomTraits& traits, const PointMap point_map) { - - const auto first = polygon.begin(); - const auto last = polygon.end(); - - auto curr = first; - if (curr == last) { - return Edge_case::EXTERIOR; - } - - auto next = curr; ++next; - if (next == last) { - return Edge_case::EXTERIOR; - } - - const auto compare_x_2 = traits.compare_x_2_object(); - const auto compare_y_2 = traits.compare_y_2_object(); - const auto orientation_2 = traits.orientation_2_object(); - - bool is_inside = false; - auto curr_y_comp_res = compare_y_2(get(point_map, *curr), query); - - // Check if the segment (curr, next) intersects - // the ray { (t, query.y()) | t >= query.x() }. - do { - const auto& currp = get(point_map, *curr); - const auto& nextp = get(point_map, *next); - - auto next_y_comp_res = compare_y_2(nextp, query); - switch (curr_y_comp_res) { - case CGAL::SMALLER: - switch (next_y_comp_res) { - case CGAL::SMALLER: - break; - case CGAL::EQUAL: - switch (compare_x_2(query, nextp)) { - case CGAL::SMALLER: is_inside = !is_inside; break; - case CGAL::EQUAL: return Edge_case::BOUNDARY; - case CGAL::LARGER: break; - } - break; - case CGAL::LARGER: - switch (which_side_in_slab_2( - query, currp, nextp, orientation_2, compare_x_2)) { - case -1: is_inside = !is_inside; break; - case 0: return Edge_case::BOUNDARY; - } - break; - } - break; - case CGAL::EQUAL: - switch (next_y_comp_res) { - case CGAL::SMALLER: - switch (compare_x_2(query, currp)) { - case CGAL::SMALLER: is_inside = !is_inside; break; - case CGAL::EQUAL: return Edge_case::BOUNDARY; - case CGAL::LARGER: break; - } - break; - case CGAL::EQUAL: - switch (compare_x_2(query, currp)) { - case CGAL::SMALLER: - if (compare_x_2(query, nextp) != CGAL::SMALLER) { - return Edge_case::BOUNDARY; - } - break; - case CGAL::EQUAL: return Edge_case::BOUNDARY; - case CGAL::LARGER: - if (compare_x_2(query, nextp) != CGAL::LARGER) { - return Edge_case::BOUNDARY; - } - break; - } - break; - case CGAL::LARGER: - if (compare_x_2(query, currp) == CGAL::EQUAL) { - return Edge_case::BOUNDARY; - } - break; - } - break; - case CGAL::LARGER: - switch (next_y_comp_res) { - case CGAL::SMALLER: - switch (which_side_in_slab_2( - query, nextp, currp, orientation_2, compare_x_2)) { - case -1: is_inside = !is_inside; break; - case 0: return Edge_case::BOUNDARY; - } - break; - case CGAL::EQUAL: - if (compare_x_2(query, nextp) == CGAL::EQUAL) { - return Edge_case::BOUNDARY; - } - break; - case CGAL::LARGER: - break; - } - break; - } - - curr = next; - curr_y_comp_res = next_y_comp_res; - ++next; - if (next == last) { - next = first; - } - } while (curr != first); - return is_inside ? Edge_case::INTERIOR : Edge_case::EXTERIOR; + switch (orientation_2(low, query, high)) { + case CGAL::LEFT_TURN: return 1; + case CGAL::RIGHT_TURN: return -1; + default: return 0; } +} - // This function is taken from the Polygon_2_algorithms.h header. - // But it is updated to support property maps. - template< - typename VertexRange, - typename GeomTraits, - typename PointMap> - bool is_convex_2( - const VertexRange& polygon, const GeomTraits traits, const PointMap point_map) { +// This function is taken from the Polygon_2_algorithms.h header. +// But it is updated to support property maps. +template +Edge_case bounded_side_2(const VertexRange& polygon, + const typename GeomTraits::Point_2& query, + const GeomTraits& traits, + const PointMap point_map) +{ + const auto first = polygon.begin(); + const auto last = polygon.end(); - auto first = polygon.begin(); - const auto last = polygon.end(); + auto curr = first; + if (curr == last) + return Edge_case::EXTERIOR; - auto prev = first; - if (prev == last) { - return true; - } + auto next = curr; + ++next; + if (next == last) + return Edge_case::EXTERIOR; - auto curr = prev; ++curr; - if (curr == last) { - return true; - } + auto compare_x_2 = traits.compare_x_2_object(); + auto compare_y_2 = traits.compare_y_2_object(); + auto orientation_2 = traits.orientation_2_object(); - auto next = curr; ++next; - if (next == last) { - return true; - } + bool is_inside = false; + Comparison_result curr_y_comp_res = compare_y_2(get(point_map, *curr), query); - const auto equal_2 = traits.equal_2_object(); - while (equal_2(get(point_map, *prev), get(point_map, *curr))) { - curr = next; ++next; - if (next == last) { - return true; - } - } + // Check if the segment (curr, next) intersects + // the ray { (t, query.y()) | t >= query.x() }. + do { + const auto& currp = get(point_map, *curr); + const auto& nextp = get(point_map, *next); - const auto less_xy_2 = traits.less_xy_2_object(); - const auto orientation_2 = traits.orientation_2_object(); - - bool has_clockwise_triplets = false; - bool has_counterclockwise_triplets = false; - bool order = less_xy_2( - get(point_map, *prev), get(point_map, *curr)); - int num_order_changes = 0; - - do { - switch_orient: - switch (orientation_2( - get(point_map, *prev), get(point_map, *curr), get(point_map, *next))) { - - case CGAL::CLOCKWISE: - has_clockwise_triplets = true; - break; - case CGAL::COUNTERCLOCKWISE: - has_counterclockwise_triplets = true; - break; - case CGAL::ZERO: { - if (equal_2( - get(point_map, *curr), - get(point_map, *next))) { - - if (next == first) { - first = curr; + Comparison_result next_y_comp_res = compare_y_2(nextp, query); + switch (curr_y_comp_res) { + case CGAL::SMALLER: + switch (next_y_comp_res) { + case CGAL::SMALLER: + break; + case CGAL::EQUAL: + switch (compare_x_2(query, nextp)) { + case CGAL::SMALLER: is_inside = !is_inside; break; + case CGAL::EQUAL: return Edge_case::BOUNDARY; + case CGAL::LARGER: break; } - ++next; - if (next == last) { - next = first; + break; + case CGAL::LARGER: + switch (which_side_in_slab_2( + query, currp, nextp, orientation_2, compare_x_2)) { + case -1: is_inside = !is_inside; break; + case 0: return Edge_case::BOUNDARY; } - goto switch_orient; - } - break; + break; } - } + break; + case CGAL::EQUAL: + switch (next_y_comp_res) { + case CGAL::SMALLER: + switch (compare_x_2(query, currp)) { + case CGAL::SMALLER: is_inside = !is_inside; break; + case CGAL::EQUAL: return Edge_case::BOUNDARY; + case CGAL::LARGER: break; + } + break; + case CGAL::EQUAL: + switch (compare_x_2(query, currp)) { + case CGAL::SMALLER: + if (compare_x_2(query, nextp) != CGAL::SMALLER) { + return Edge_case::BOUNDARY; + } + break; + case CGAL::EQUAL: return Edge_case::BOUNDARY; + case CGAL::LARGER: + if (compare_x_2(query, nextp) != CGAL::LARGER) { + return Edge_case::BOUNDARY; + } + break; + } + break; + case CGAL::LARGER: + if (compare_x_2(query, currp) == CGAL::EQUAL) { + return Edge_case::BOUNDARY; + } + break; + } + break; + case CGAL::LARGER: + switch (next_y_comp_res) { + case CGAL::SMALLER: + switch (which_side_in_slab_2( + query, nextp, currp, orientation_2, compare_x_2)) { + case -1: is_inside = !is_inside; break; + case 0: return Edge_case::BOUNDARY; + } + break; + case CGAL::EQUAL: + if (compare_x_2(query, nextp) == CGAL::EQUAL) { + return Edge_case::BOUNDARY; + } + break; + case CGAL::LARGER: + break; + } + break; + } - const bool new_order = less_xy_2( - get(point_map, *curr), get(point_map, *next)); + curr = next; + curr_y_comp_res = next_y_comp_res; + ++next; + if (next == last) { + next = first; + } + } while (curr != first); - if (order != new_order) { - num_order_changes++; - } + return is_inside ? Edge_case::INTERIOR : Edge_case::EXTERIOR; +} - if (num_order_changes > 2) { - return false; - } +// This function is taken from the Polygon_2_algorithms.h header. +// But it is updated to support property maps. +template +bool is_convex_2(const VertexRange& polygon, + const GeomTraits traits, + const PointMap point_map) +{ + auto first = polygon.begin(); + const auto last = polygon.end(); - if (has_clockwise_triplets && has_counterclockwise_triplets) { - return false; - } - - prev = curr; - curr = next; - ++next; - if (next == last) { - next = first; - } - order = new_order; - } while (prev != first); + auto prev = first; + if (prev == last) return true; - } - // This function is taken from the Polygon_2_algorithms.h header. - // But it is updated to support property maps. - template< - typename VertexRange, - typename GeomTraits, - typename PointMap> - bool is_simple_2( - const VertexRange& polygon, const GeomTraits traits, const PointMap point_map) { + auto curr = prev; + ++curr; + if (curr == last) + return true; - const auto first = polygon.begin(); - const auto last = polygon.end(); - if (first == last) { + auto next = curr; + ++next; + if (next == last) + return true; + + auto equal_2 = traits.equal_2_object(); + while (equal_2(get(point_map, *prev), get(point_map, *curr))) + { + curr = next; ++next; + if (next == last) return true; - } - - std::vector poly; - poly.reserve(polygon.size()); - for (const auto& vertex : polygon) { - poly.push_back(get(point_map, vertex)); - } - return CGAL::is_simple_2(poly.begin(), poly.end(), traits); } - template< - typename VertexRange, - typename GeomTraits, - typename PointMap> - Polygon_type polygon_type_2( - const VertexRange& polygon, const GeomTraits traits, const PointMap point_map) { + auto less_xy_2 = traits.less_xy_2_object(); + auto orientation_2 = traits.orientation_2_object(); - const auto collinear_2 = - traits.collinear_2_object(); - CGAL_precondition(polygon.size() >= 3); + bool has_clockwise_triplets = false; + bool has_counterclockwise_triplets = false; + bool order = less_xy_2(get(point_map, *prev), get(point_map, *curr)); + int num_order_changes = 0; - // First, test the polygon on convexity. - if (is_convex_2(polygon, traits, point_map)) { + do + { +switch_orient: + switch (orientation_2(get(point_map, *prev), get(point_map, *curr), get(point_map, *next))) + { + case CGAL::CLOCKWISE: + has_clockwise_triplets = true; + break; + case CGAL::COUNTERCLOCKWISE: + has_counterclockwise_triplets = true; + break; + case CGAL::ZERO: { + if (equal_2(get(point_map, *curr), + get(point_map, *next))) + { + if (next == first) + first = curr; - // Test all the consequent triplets of polygon vertices on collinearity. - // In case we find at least one, return WEAKLY_CONVEX polygon. - const std::size_t n = polygon.size(); - for (std::size_t i = 0; i < n; ++i) { - const auto& p1 = get(point_map, *(polygon.begin() + i)); + ++next; + if (next == last) + next = first; - const std::size_t im = (i + n - 1) % n; - const std::size_t ip = (i + 1) % n; - - const auto& p0 = get(point_map, *(polygon.begin() + im)); - const auto& p2 = get(point_map, *(polygon.begin() + ip)); - - if (collinear_2(p0, p1, p2)) { - return Polygon_type::WEAKLY_CONVEX; + goto switch_orient; } + break; } - // Otherwise, return STRICTLY_CONVEX polygon. - return Polygon_type::STRICTLY_CONVEX; } - // Otherwise, return CONCAVE polygon. - return Polygon_type::CONCAVE; + + const bool new_order = less_xy_2(get(point_map, *curr), get(point_map, *next)); + + if (order != new_order) + num_order_changes++; + + if (num_order_changes > 2) + return false; + + if (has_clockwise_triplets && has_counterclockwise_triplets) + return false; + + prev = curr; + curr = next; + ++next; + if (next == last) + next = first; + + order = new_order; + } while (prev != first); + + return true; +} + +// This function is taken from the Polygon_2_algorithms.h header. +// But it is updated to support property maps. +template +bool is_simple_2(const VertexRange& polygon, + const GeomTraits traits, + const PointMap point_map) +{ + const auto first = polygon.begin(); + const auto last = polygon.end(); + if (first == last) + return true; + + std::vector poly; + poly.reserve(polygon.size()); + for (const auto& vertex : polygon) + poly.push_back(get(point_map, vertex)); + + return CGAL::is_simple_2(poly.begin(), poly.end(), traits); +} + +template +Polygon_type polygon_type_2(const VertexRange& polygon, + const GeomTraits traits, + const PointMap point_map) +{ + auto collinear_2 = traits.collinear_2_object(); + CGAL_precondition(polygon.size() >= 3); + + // First, test the polygon on convexity. + if (is_convex_2(polygon, traits, point_map)) + { + // Test all the consequent triplets of polygon vertices on collinearity. + // In case we find at least one, return WEAKLY_CONVEX polygon. + const std::size_t n = polygon.size(); + for (std::size_t i = 0; i < n; ++i) + { + const auto& p1 = get(point_map, *(polygon.begin() + i)); + + const std::size_t im = (i + n - 1) % n; + const std::size_t ip = (i + 1) % n; + + const auto& p0 = get(point_map, *(polygon.begin() + im)); + const auto& p2 = get(point_map, *(polygon.begin() + ip)); + + if (collinear_2(p0, p1, p2)) + return Polygon_type::WEAKLY_CONVEX; + } + + // Otherwise, return STRICTLY_CONVEX polygon. + return Polygon_type::STRICTLY_CONVEX; } + // Otherwise, return CONCAVE polygon. + return Polygon_type::CONCAVE; +} + } // namespace internal } // namespace Weights } // namespace CGAL diff --git a/Weights/include/CGAL/Weights/internal/utils.h b/Weights/include/CGAL/Weights/internal/utils.h index 4e6ef42f96c..744af8be2d3 100644 --- a/Weights/include/CGAL/Weights/internal/utils.h +++ b/Weights/include/CGAL/Weights/internal/utils.h @@ -14,722 +14,493 @@ #ifndef CGAL_WEIGHTS_INTERNAL_UTILS_H #define CGAL_WEIGHTS_INTERNAL_UTILS_H -// STL includes. -#include -#include -#include -#include -#include -#include -#include -#include - -// Boost headers. -#include -#include - -// CGAL includes. -#include #include -#include +#include #include +#include #include -#include -#include +#include + +#include + +#include +#include +#include +#include +#include namespace CGAL { namespace Weights { namespace internal { - // Sqrt helpers. - template - class Default_sqrt { +// Sqrt helpers. +template +class Default_sqrt +{ +private: + using Traits = GeomTraits; + using FT = typename Traits::FT; - private: - using Traits = GeomTraits; - using FT = typename Traits::FT; - - public: - FT operator()(const FT value) const { - return static_cast( - CGAL::sqrt(CGAL::to_double(CGAL::abs(value)))); - } - }; - - BOOST_MPL_HAS_XXX_TRAIT_NAMED_DEF(Has_nested_type_Sqrt, Sqrt, false) - - // Case: do_not_use_default = false. - template::value> - class Get_sqrt { - - public: - using Traits = GeomTraits; - using Sqrt = Default_sqrt; - - static Sqrt sqrt_object(const Traits& ) { - return Sqrt(); - } - }; - - // Case: do_not_use_default = true. - template - class Get_sqrt { - - public: - using Traits = GeomTraits; - using Sqrt = typename Traits::Sqrt; - - static Sqrt sqrt_object(const Traits& traits) { - return traits.sqrt_object(); - } - }; - - // Normalize values. - template - void normalize(std::vector& values) { - - FT sum = FT(0); - for (const FT& value : values) { - sum += value; - } - - CGAL_assertion(sum != FT(0)); - if (sum == FT(0)) { - return; - } - - const FT inv_sum = FT(1) / sum; - for (FT& value : values) { - value *= inv_sum; - } +public: + FT operator()(const FT value) const + { + return static_cast(CGAL::sqrt(CGAL::to_double(CGAL::abs(value)))); } +}; - // Raises value to the power. - template - typename GeomTraits::FT power( - const GeomTraits&, - const typename GeomTraits::FT value, - const typename GeomTraits::FT p) { +BOOST_MPL_HAS_XXX_TRAIT_NAMED_DEF(Has_nested_type_Sqrt, Sqrt, false) - using FT = typename GeomTraits::FT; - const double base = CGAL::to_double(value); - const double exp = CGAL::to_double(p); - return static_cast(std::pow(base, exp)); +// Case: do_not_use_default = false. +template::value> +class Get_sqrt +{ +public: + using Traits = GeomTraits; + using Sqrt = Default_sqrt; + + static Sqrt sqrt_object(const Traits&) + { + return Sqrt(); } +}; - // Computes distance between two 2D points. - template - typename GeomTraits::FT distance_2( - const GeomTraits& traits, - const typename GeomTraits::Point_2& p, - const typename GeomTraits::Point_2& q) { +// Case: do_not_use_default = true. +template +class Get_sqrt +{ +public: + using Traits = GeomTraits; + using Sqrt = typename Traits::Sqrt; - using Get_sqrt = Get_sqrt; - const auto sqrt = Get_sqrt::sqrt_object(traits); - - const auto squared_distance_2 = - traits.compute_squared_distance_2_object(); - return sqrt(squared_distance_2(p, q)); - } - - // Computes length of a 2D vector. - template - typename GeomTraits::FT length_2( - const GeomTraits& traits, - const typename GeomTraits::Vector_2& v) { - - using Get_sqrt = Get_sqrt; - const auto sqrt = Get_sqrt::sqrt_object(traits); - - const auto squared_length_2 = - traits.compute_squared_length_2_object(); - return sqrt(squared_length_2(v)); - } - - // Normalizes a 2D vector. - template - void normalize_2( - const GeomTraits& traits, - typename GeomTraits::Vector_2& v) { - - using FT = typename GeomTraits::FT; - const FT length = length_2(traits, v); - CGAL_assertion(length != FT(0)); - if (length == FT(0)) { - return; - } - v /= length; - } - - // Computes cotanget between two 2D vectors. - template - typename GeomTraits::FT cotangent_2( - const GeomTraits& traits, - const typename GeomTraits::Point_2& p, - const typename GeomTraits::Point_2& q, - const typename GeomTraits::Point_2& r) { - - using FT = typename GeomTraits::FT; - const auto dot_product_2 = - traits.compute_scalar_product_2_object(); - const auto cross_product_2 = - traits.compute_determinant_2_object(); - const auto construct_vector_2 = - traits.construct_vector_2_object(); - - const auto v1 = construct_vector_2(q, r); - const auto v2 = construct_vector_2(q, p); - - const FT dot = dot_product_2(v1, v2); - const FT cross = cross_product_2(v1, v2); - - const FT length = CGAL::abs(cross); - // CGAL_assertion(length != FT(0)); not really necessary - if (length != FT(0)) { - return dot / length; - } else { - return FT(0); // undefined - } - } - - // Computes tanget between two 2D vectors. - template - typename GeomTraits::FT tangent_2( - const GeomTraits& traits, - const typename GeomTraits::Point_2& p, - const typename GeomTraits::Point_2& q, - const typename GeomTraits::Point_2& r) { - - using FT = typename GeomTraits::FT; - const auto dot_product_2 = - traits.compute_scalar_product_2_object(); - const auto cross_product_2 = - traits.compute_determinant_2_object(); - const auto construct_vector_2 = - traits.construct_vector_2_object(); - - const auto v1 = construct_vector_2(q, r); - const auto v2 = construct_vector_2(q, p); - - const FT dot = dot_product_2(v1, v2); - const FT cross = cross_product_2(v1, v2); - - const FT length = CGAL::abs(cross); - // CGAL_assertion(dot != FT(0)); not really necessary - if (dot != FT(0)) { - return length / dot; - } else { - return FT(0); // undefined - } - } - - // Computes distance between two 3D points. - template - typename GeomTraits::FT distance_3( - const GeomTraits& traits, - const typename GeomTraits::Point_3& p, - const typename GeomTraits::Point_3& q) { - - using Get_sqrt = Get_sqrt; - const auto sqrt = Get_sqrt::sqrt_object(traits); - - const auto squared_distance_3 = - traits.compute_squared_distance_3_object(); - return sqrt(squared_distance_3(p, q)); - } - - // Computes length of a 3D vector. - template - typename GeomTraits::FT length_3( - const GeomTraits& traits, - const typename GeomTraits::Vector_3& v) { - - using Get_sqrt = Get_sqrt; - const auto sqrt = Get_sqrt::sqrt_object(traits); - - const auto squared_length_3 = - traits.compute_squared_length_3_object(); - return sqrt(squared_length_3(v)); - } - - // Normalizes a 3D vector. - template - void normalize_3( - const GeomTraits& traits, - typename GeomTraits::Vector_3& v) { - - using FT = typename GeomTraits::FT; - const FT length = length_3(traits, v); - CGAL_assertion(length != FT(0)); - if (length == FT(0)) { - return; - } - v /= length; - } - - // Computes cotanget between two 3D vectors. - template - typename GeomTraits::FT cotangent_3( - const GeomTraits& traits, - const typename GeomTraits::Point_3& p, - const typename GeomTraits::Point_3& q, - const typename GeomTraits::Point_3& r) { - - using FT = typename GeomTraits::FT; - const auto dot_product_3 = - traits.compute_scalar_product_3_object(); - const auto cross_product_3 = - traits.construct_cross_product_vector_3_object(); - const auto construct_vector_3 = - traits.construct_vector_3_object(); - - const auto v1 = construct_vector_3(q, r); - const auto v2 = construct_vector_3(q, p); - - const FT dot = dot_product_3(v1, v2); - const auto cross = cross_product_3(v1, v2); - - const FT length = length_3(traits, cross); - // TODO: - // Not really necessary: since we handle case length = 0. Does this case happen? - // Yes, e.g. in Surface Parameterization tests. Does it affect the results? - // In current applications, not really. - // CGAL_assertion(length != FT(0)); - if (length != FT(0)) { - return dot / length; - } else { - return FT(0); // undefined - } - } - - // Computes tanget between two 3D vectors. - template - typename GeomTraits::FT tangent_3( - const GeomTraits& traits, - const typename GeomTraits::Point_3& p, - const typename GeomTraits::Point_3& q, - const typename GeomTraits::Point_3& r) { - - using FT = typename GeomTraits::FT; - const auto dot_product_3 = - traits.compute_scalar_product_3_object(); - const auto cross_product_3 = - traits.construct_cross_product_vector_3_object(); - const auto construct_vector_3 = - traits.construct_vector_3_object(); - - const auto v1 = construct_vector_3(q, r); - const auto v2 = construct_vector_3(q, p); - - const FT dot = dot_product_3(v1, v2); - const auto cross = cross_product_3(v1, v2); - - const FT length = length_3(traits, cross); - // CGAL_assertion(dot != FT(0)); not really necessary - if (dot != FT(0)) { - return length / dot; - } else { - return FT(0); // undefined - } - } - - // Computes 3D angle between two vectors. - template - double angle_3( - const GeomTraits& traits, - const typename GeomTraits::Vector_3& v1, - const typename GeomTraits::Vector_3& v2) { - - const auto dot_product_3 = - traits.compute_scalar_product_3_object(); - const double dot = - CGAL::to_double(dot_product_3(v1, v2)); - - double angle_rad = 0.0; - if (dot < -1.0) { - angle_rad = std::acos(-1.0); - } else if (dot > 1.0) { - angle_rad = std::acos(+1.0); - } else { - angle_rad = std::acos(dot); - } - return angle_rad; - } - - // Rotates a 3D point around axis. - template - typename GeomTraits::Point_3 rotate_point_3( - const GeomTraits&, - const double angle_rad, - const typename GeomTraits::Vector_3& axis, - const typename GeomTraits::Point_3& query) { - - using FT = typename GeomTraits::FT; - using Point_3 = typename GeomTraits::Point_3; - - const FT c = static_cast(std::cos(angle_rad)); - const FT s = static_cast(std::sin(angle_rad)); - const FT C = FT(1) - c; - - const auto x = axis.x(); - const auto y = axis.y(); - const auto z = axis.z(); - - return Point_3( - (x * x * C + c) * query.x() + - (x * y * C - z * s) * query.y() + - (x * z * C + y * s) * query.z(), - (y * x * C + z * s) * query.x() + - (y * y * C + c) * query.y() + - (y * z * C - x * s) * query.z(), - (z * x * C - y * s) * query.x() + - (z * y * C + x * s) * query.y() + - (z * z * C + c) * query.z()); - } - - // Computes two 3D orthogonal base vectors wrt a given normal. - template - void orthogonal_bases_3( - const GeomTraits& traits, - const typename GeomTraits::Vector_3& normal, - typename GeomTraits::Vector_3& b1, - typename GeomTraits::Vector_3& b2) { - - using Vector_3 = typename GeomTraits::Vector_3; - const auto cross_product_3 = - traits.construct_cross_product_vector_3_object(); - - const auto nx = normal.x(); - const auto ny = normal.y(); - const auto nz = normal.z(); - - if (CGAL::abs(nz) >= CGAL::abs(ny)) { - b1 = Vector_3(nz, 0, -nx); - } else { - b1 = Vector_3(ny, -nx, 0); - } - b2 = cross_product_3(normal, b1); - - normalize_3(traits, b1); - normalize_3(traits, b2); - } - - // Converts a 3D point into a 2D point wrt to a given plane. - template - typename GeomTraits::Point_2 to_2d( - const GeomTraits& traits, - const typename GeomTraits::Vector_3& b1, - const typename GeomTraits::Vector_3& b2, - const typename GeomTraits::Point_3& origin, - const typename GeomTraits::Point_3& query) { - - using Point_2 = typename GeomTraits::Point_2; - const auto dot_product_3 = - traits.compute_scalar_product_3_object(); - const auto construct_vector_3 = - traits.construct_vector_3_object(); - - const auto v = construct_vector_3(origin, query); - const auto x = dot_product_3(b1, v); - const auto y = dot_product_3(b2, v); - return Point_2(x, y); - } - - // Flattening. - - // \cgalFigureBegin{flattening, flattening.svg} - // The non-planar configuration (top) is flattened to the planar configuration (bottom). - // \cgalFigureEnd - - // When computing weights for a query point \f$q\f$ with respect to its neighbors - // \f$p_0\f$, \f$p_1\f$, and \f$p_2\f$, the local configuration is a quadrilateral - // [\f$p_0\f$, \f$p_1\f$, \f$p_2\f$, \f$q\f$] or two connected triangles [\f$q\f$, \f$p_0\f$, \f$p_1\f$] - // and [\f$q\f$, \f$p_1\f$, \f$p_2\f$]. When working in 3D, these triangles are not - // necessarily coplanar, in other words, they do not belong to the same common plane. - // When they are not coplanar, they can be made coplanar through the process called *flattening* (see the Figure above), - // however the latter introduces a distortion because the weights are computed with respect to the - // flattened configuration rather than to the original non-flat configuration. - - // \subsection Weights_Examples_ProjectionTraits Computing 2D Weights in 3D - - // If you have a 2D polygon in 3D plane that is not an XY plane, you can still compute - // the 2D weights, however you need to provide a special projection traits class. - // The common plane that is used in this example is projectable to the XY plane. We first - // compute `Mean_value_weights_2` for a 3D polygon in this plane. We then also show how to use - // the projection traits to compute the \ref PkgWeightsRefWachspressWeights "2D Wachspress weight" - // for 3D points which are not strictly coplanar. - - // \cgalExample{Weights/projection_traits.cpp} - - // Example of flattening: - - // 3D configuration. - // const Point_3 p0(0, 1, 1); - // const Point_3 p1(2, 0, 1); - // const Point_3 p2(7, 1, 1); - // const Point_3 q0(3, 1, 1); - - // Choose a type of the weight: - // e.g. 0 - Wachspress (WP) weight. - // const FT wp = FT(0); - - // Compute WP weights for q1 which is not on the plane [p0, p1, p2]. - - // Point_3 q1(3, 1, 2); - // std::cout << "3D wachspress (WP, q1): "; - // std::cout << CGAL::Weights::three_point_family_weight(p0, p1, p2, q1, wp) << std::endl; - - // Converge q1 towards q0 that is we flatten the configuration. - // We also compare the result with the authalic weight. - - // std::cout << "Converge q1 to q0: " << std::endl; - // for (FT x = FT(0); x <= FT(1); x += step) { - // std::cout << "3D wachspress/authalic: "; - // q1 = Point_3(3, 1, FT(2) - x); - // std::cout << CGAL::Weights::three_point_family_weight(p0, p1, p2, q1, wp) << "/"; - // std::cout << CGAL::Weights::authalic_weight(p0, p1, p2, q1) << std::endl; - // } - - // Flattens an arbitrary quad into a planar quad. - template - void flatten( - const GeomTraits& traits, - const typename GeomTraits::Point_3& t, // prev neighbor/vertex/point - const typename GeomTraits::Point_3& r, // curr neighbor/vertex/point - const typename GeomTraits::Point_3& p, // next neighbor/vertex/point - const typename GeomTraits::Point_3& q, // query point - typename GeomTraits::Point_2& tf, - typename GeomTraits::Point_2& rf, - typename GeomTraits::Point_2& pf, - typename GeomTraits::Point_2& qf) { - - // std::cout << std::endl; - using Point_3 = typename GeomTraits::Point_3; - using Vector_3 = typename GeomTraits::Vector_3; - - const auto cross_product_3 = - traits.construct_cross_product_vector_3_object(); - const auto construct_vector_3 = - traits.construct_vector_3_object(); - const auto centroid_3 = - traits.construct_centroid_3_object(); - - // Compute centroid. - const auto center = centroid_3(t, r, p, q); - // std::cout << "centroid: " << center << std::endl; - - // Translate. - const Point_3 t1 = Point_3( - t.x() - center.x(), t.y() - center.y(), t.z() - center.z()); - const Point_3 r1 = Point_3( - r.x() - center.x(), r.y() - center.y(), r.z() - center.z()); - const Point_3 p1 = Point_3( - p.x() - center.x(), p.y() - center.y(), p.z() - center.z()); - const Point_3 q1 = Point_3( - q.x() - center.x(), q.y() - center.y(), q.z() - center.z()); - - // std::cout << "translated t1: " << t1 << std::endl; - // std::cout << "translated r1: " << r1 << std::endl; - // std::cout << "translated p1: " << p1 << std::endl; - // std::cout << "translated q1: " << q1 << std::endl; - - // Middle axis. - auto ax = construct_vector_3(q1, r1); - normalize_3(traits, ax); - - // Prev and next vectors. - auto v1 = construct_vector_3(q1, t1); - auto v2 = construct_vector_3(q1, p1); - - normalize_3(traits, v1); - normalize_3(traits, v2); - - // Two triangle normals. - auto n1 = cross_product_3(v1, ax); - auto n2 = cross_product_3(ax, v2); - - normalize_3(traits, n1); - normalize_3(traits, n2); - - // std::cout << "normal n1: " << n1 << std::endl; - // std::cout << "normal n2: " << n2 << std::endl; - - // Angle between two normals. - const double angle_rad = angle_3(traits, n1, n2); - // std::cout << "angle deg n1 <-> n2: " << angle_rad * 180.0 / CGAL_PI << std::endl; - - // Rotate p1 around ax so that it lands onto the plane [q1, t1, r1]. - const auto& t2 = t1; - const auto& r2 = r1; - const auto p2 = rotate_point_3(traits, angle_rad, ax, p1); - const auto& q2 = q1; - // std::cout << "rotated p2: " << p2 << std::endl; - - // Compute orthogonal base vectors. - Vector_3 b1, b2; - const auto& normal = n1; - orthogonal_bases_3(traits, normal, b1, b2); - - // const auto angle12 = angle_3(traits, b1, b2); - // std::cout << "angle deg b1 <-> b2: " << angle12 * 180.0 / CGAL_PI << std::endl; - - // Flatten a quad. - const auto& origin = q2; - tf = to_2d(traits, b1, b2, origin, t2); - rf = to_2d(traits, b1, b2, origin, r2); - pf = to_2d(traits, b1, b2, origin, p2); - qf = to_2d(traits, b1, b2, origin, q2); - - // std::cout << "flattened qf: " << qf << std::endl; - // std::cout << "flattened tf: " << tf << std::endl; - // std::cout << "flattened rf: " << rf << std::endl; - // std::cout << "flattened pf: " << pf << std::endl; - - // std::cout << "A1: " << area_2(traits, rf, qf, pf) << std::endl; - // std::cout << "A2: " << area_2(traits, pf, qf, rf) << std::endl; - // std::cout << "C: " << area_2(traits, tf, rf, pf) << std::endl; - // std::cout << "B: " << area_2(traits, pf, qf, tf) << std::endl; - } - - // Computes area of a 2D triangle. - template - typename GeomTraits::FT area_2( - const GeomTraits& traits, - const typename GeomTraits::Point_2& p, - const typename GeomTraits::Point_2& q, - const typename GeomTraits::Point_2& r) { - - const auto area_2 = traits.compute_area_2_object(); - return area_2(p, q, r); - } - - // Computes positive area of a 2D triangle. - template - typename GeomTraits::FT positive_area_2( - const GeomTraits& traits, - const typename GeomTraits::Point_2& p, - const typename GeomTraits::Point_2& q, - const typename GeomTraits::Point_2& r) { - - return CGAL::abs(area_2(traits, p, q, r)); - } - - // Computes area of a 3D triangle. - template - typename GeomTraits::FT area_3( - const GeomTraits& traits, - const typename GeomTraits::Point_3& p, - const typename GeomTraits::Point_3& q, - const typename GeomTraits::Point_3& r) { - - using FT = typename GeomTraits::FT; - using Point_3 = typename GeomTraits::Point_3; - using Vector_3 = typename GeomTraits::Vector_3; - - const auto cross_product_3 = - traits.construct_cross_product_vector_3_object(); - const auto construct_vector_3 = - traits.construct_vector_3_object(); - const auto centroid_3 = - traits.construct_centroid_3_object(); - - // Compute centroid. - const auto center = centroid_3(p, q, r); - - // Translate. - const Point_3 a = Point_3( - p.x() - center.x(), p.y() - center.y(), p.z() - center.z()); - const Point_3 b = Point_3( - q.x() - center.x(), q.y() - center.y(), q.z() - center.z()); - const Point_3 c = Point_3( - r.x() - center.x(), r.y() - center.y(), r.z() - center.z()); - - // Prev and next vectors. - auto v1 = construct_vector_3(b, a); - auto v2 = construct_vector_3(b, c); - normalize_3(traits, v1); - normalize_3(traits, v2); - - // Compute normal. - auto normal = cross_product_3(v1, v2); - normalize_3(traits, normal); - - // Compute orthogonal base vectors. - Vector_3 b1, b2; - orthogonal_bases_3(traits, normal, b1, b2); - - // Compute area. - const auto& origin = b; - const auto pf = to_2d(traits, b1, b2, origin, a); - const auto qf = to_2d(traits, b1, b2, origin, b); - const auto rf = to_2d(traits, b1, b2, origin, c); - - const FT A = area_2(traits, pf, qf, rf); - return A; - } - - // Computes positive area of a 3D triangle. - template - typename GeomTraits::FT positive_area_3( - const GeomTraits& traits, - const typename GeomTraits::Point_3& p, - const typename GeomTraits::Point_3& q, - const typename GeomTraits::Point_3& r) { - - using FT = typename GeomTraits::FT; - const auto construct_vector_3 = - traits.construct_vector_3_object(); - - const auto v1 = construct_vector_3(q, r); - const auto v2 = construct_vector_3(q, p); - - const auto cross_product_3 = - traits.construct_cross_product_vector_3_object(); - const auto cross = cross_product_3(v1, v2); - const FT half = FT(1) / FT(2); - const FT A = half * length_3(traits, cross); - return A; - } - - // Computes a clamped cotangent between two 3D vectors. - // In the old version of weights in PMP, it has been called secure. - // See Weights/internal/pmp_weights_deprecated.h for more information. - template - typename GeomTraits::FT cotangent_3_clamped( - const GeomTraits& traits, - const typename GeomTraits::Point_3& p, - const typename GeomTraits::Point_3& q, - const typename GeomTraits::Point_3& r) { - - using FT = typename GeomTraits::FT; - using Get_sqrt = Get_sqrt; - const auto sqrt = Get_sqrt::sqrt_object(traits); - - const auto dot_product_3 = - traits.compute_scalar_product_3_object(); - const auto construct_vector_3 = - traits.construct_vector_3_object(); - - const auto v1 = construct_vector_3(q, r); - const auto v2 = construct_vector_3(q, p); - - const FT dot = dot_product_3(v1, v2); - const FT length_v1 = length_3(traits, v1); - const FT length_v2 = length_3(traits, v2); - - const FT lb = -FT(999) / FT(1000), ub = FT(999) / FT(1000); - FT cosine = dot / length_v1 / length_v2; - cosine = (cosine < lb) ? lb : cosine; - cosine = (cosine > ub) ? ub : cosine; - const FT sine = sqrt(FT(1) - cosine * cosine); - - CGAL_assertion(sine != FT(0)); - if (sine != FT(0)) { - return cosine / sine; - } - return FT(0); // undefined + static Sqrt sqrt_object(const Traits& traits) + { + return traits.sqrt_object(); } +}; + +template +void normalize(std::vector& values) +{ + FT sum = FT(0); + for (const FT& value : values) + sum += value; + + CGAL_assertion(!is_zero(sum)); + if (is_zero(sum)) + return; + + const FT inv_sum = FT(1) / sum; + for (FT& value : values) + value *= inv_sum; +} + +template +FT power(const FT value, + const FT p) +{ + const double base = CGAL::to_double(value); + const double exp = CGAL::to_double(p); + + return static_cast(std::pow(base, exp)); +} + +// 2D ============================================================================================== + +template +typename GeomTraits::FT distance_2(const typename GeomTraits::Point_2& p, + const typename GeomTraits::Point_2& q, + const GeomTraits& traits) +{ + using Get_sqrt = Get_sqrt; + auto sqrt = Get_sqrt::sqrt_object(traits); + + auto squared_distance_2 = traits.compute_squared_distance_2_object(); + return sqrt(squared_distance_2(p, q)); +} + +template +typename GeomTraits::FT length_2(const typename GeomTraits::Vector_2& v, + const GeomTraits& traits) +{ + using Get_sqrt = Get_sqrt; + auto sqrt = Get_sqrt::sqrt_object(traits); + + auto squared_length_2 = traits.compute_squared_length_2_object(); + return sqrt(squared_length_2(v)); +} + +template +void normalize_2(typename GeomTraits::Vector_2& v, + const GeomTraits& traits) +{ + using FT = typename GeomTraits::FT; + + const FT length = length_2(v, traits); + CGAL_assertion(!is_zero(length)); + if (is_zero(length)) + return; + + v /= length; +} + +// 3D ============================================================================================== + +template +typename GeomTraits::FT distance_3(const typename GeomTraits::Point_3& p, + const typename GeomTraits::Point_3& q, + const GeomTraits& traits) +{ + auto squared_distance_3 = traits.compute_squared_distance_3_object(); + + using Get_sqrt = Get_sqrt; + auto sqrt = Get_sqrt::sqrt_object(traits); + + return sqrt(squared_distance_3(p, q)); +} + +template +typename GeomTraits::FT length_3(const typename GeomTraits::Vector_3& v, + const GeomTraits& traits) +{ + using Get_sqrt = Get_sqrt; + auto sqrt = Get_sqrt::sqrt_object(traits); + + auto squared_length_3 = traits.compute_squared_length_3_object(); + return sqrt(squared_length_3(v)); +} + +template +void normalize_3(typename GeomTraits::Vector_3& v, + const GeomTraits& traits) +{ + using FT = typename GeomTraits::FT; + const FT length = length_3(v, traits); + CGAL_assertion(!is_zero(length)); + if (is_zero(length)) + return; + + v /= length; +} + +// the angle is in radians +template +double angle_3(const typename GeomTraits::Vector_3& v1, + const typename GeomTraits::Vector_3& v2, + const GeomTraits& traits) +{ + auto dot_product_3 = traits.compute_scalar_product_3_object(); + + const double product = CGAL::sqrt(to_double(dot_product_3(v1,v1) * dot_product_3(v2,v2))); + if(product == 0.) + return 0.; + + const double dot = CGAL::to_double(dot_product_3(v1, v2)); + const double cosine = dot / product; + + if (cosine < -1.0) + return std::acos(-1.0); + else if (cosine > 1.0) + return std::acos(+1.0); + else + return std::acos(cosine); +} + +// Rotates a 3D point around axis. +template +typename GeomTraits::Point_3 rotate_point_3(const double angle_rad, + const typename GeomTraits::Vector_3& axis, + const typename GeomTraits::Point_3& query, + const GeomTraits& traits) +{ + using FT = typename GeomTraits::FT; + using Point_3 = typename GeomTraits::Point_3; + + auto point_3 = traits.construct_point_3_object(); + + const FT c = static_cast(std::cos(angle_rad)); + const FT s = static_cast(std::sin(angle_rad)); + const FT C = FT(1) - c; + + const FT& x = axis.x(); + const FT& y = axis.y(); + const FT& z = axis.z(); + + return point_3( + (x * x * C + c) * query.x() + + (x * y * C - z * s) * query.y() + + (x * z * C + y * s) * query.z(), + (y * x * C + z * s) * query.x() + + (y * y * C + c) * query.y() + + (y * z * C - x * s) * query.z(), + (z * x * C - y * s) * query.x() + + (z * y * C + x * s) * query.y() + + (z * z * C + c) * query.z()); +} + +// Computes two 3D orthogonal base vectors wrt a given normal. +template +void orthogonal_bases_3(const typename GeomTraits::Vector_3& normal, + typename GeomTraits::Vector_3& b1, + typename GeomTraits::Vector_3& b2, + const GeomTraits& traits) +{ + using FT = typename GeomTraits::FT; + using Vector_3 = typename GeomTraits::Vector_3; + + auto cross_product_3 = traits.construct_cross_product_vector_3_object(); + + const FT& nx = normal.x(); + const FT& ny = normal.y(); + const FT& nz = normal.z(); + + if (CGAL::abs(nz) >= CGAL::abs(ny)) + b1 = Vector_3(nz, 0, -nx); + else + b1 = Vector_3(ny, -nx, 0); + + b2 = cross_product_3(normal, b1); + + normalize_3(b1, traits); + normalize_3(b2, traits); +} + +// Converts a 3D point into a 2D point wrt to a given plane. +template +typename GeomTraits::Point_2 to_2d(const typename GeomTraits::Vector_3& b1, + const typename GeomTraits::Vector_3& b2, + const typename GeomTraits::Point_3& origin, + const typename GeomTraits::Point_3& query, + const GeomTraits& traits) +{ + using FT = typename GeomTraits::FT; + using Point_2 = typename GeomTraits::Point_2; + using Vector_3 = typename GeomTraits::Vector_3; + + auto dot_product_3 = traits.compute_scalar_product_3_object(); + auto vector_3 = traits.construct_vector_3_object(); + auto point_2 = traits.construct_point_2_object(); + + const Vector_3 v = vector_3(origin, query); + const FT x = dot_product_3(b1, v); + const FT y = dot_product_3(b2, v); + + return point_2(x, y); +} + +// Flattening. + +// \cgalFigureBegin{flattening, flattening.svg} +// The non-planar configuration (top) is flattened to the planar configuration (bottom). +// \cgalFigureEnd + +// When computing weights for a query point \f$q\f$ with respect to its neighbors +// \f$p_0\f$, \f$p_1\f$, and \f$p_2\f$, the local configuration is a quadrilateral +// [\f$p_0\f$, \f$p_1\f$, \f$p_2\f$, \f$q\f$] or two connected triangles [\f$q\f$, \f$p_0\f$, \f$p_1\f$] +// and [\f$q\f$, \f$p_1\f$, \f$p_2\f$]. When working in 3D, these triangles are not +// necessarily coplanar, in other words, they do not belong to the same common plane. +// When they are not coplanar, they can be made coplanar through the process called *flattening* (see the Figure above), +// however the latter introduces a distortion because the weights are computed with respect to the +// flattened configuration rather than to the original non-flat configuration. + +// \subsection Weights_Examples_ProjectionTraits Computing 2D Weights in 3D + +// If you have a 2D polygon in 3D plane that is not an XY plane, you can still compute +// the 2D weights, however you need to provide a special projection traits class. +// The common plane that is used in this example is projectable to the XY plane. We first +// compute `Mean_value_weights_2` for a 3D polygon in this plane. We then also show how to use +// the projection traits to compute the \ref PkgWeightsRefWachspressWeights "2D Wachspress weight" +// for 3D points which are not strictly coplanar. + +// \cgalExample{Weights/projection_traits.cpp} + +// Example of flattening: + +// 3D configuration. +// const Point_3 p0(0, 1, 1); +// const Point_3 p1(2, 0, 1); +// const Point_3 p2(7, 1, 1); +// const Point_3 q0(3, 1, 1); + +// Choose a type of the weight: +// e.g. 0 - Wachspress (WP) weight. +// const FT wp = FT(0); + +// Compute WP weights for q1 which is not on the plane [p0, p1, p2]. + +// Point_3 q1(3, 1, 2); +// std::cout << "3D wachspress (WP, q1): "; +// std::cout << CGAL::Weights::three_point_family_weight(p0, p1, p2, q1, wp) << std::endl; + +// Converge q1 towards q0 that is we flatten the configuration. +// We also compare the result with the authalic weight. + +// std::cout << "Converge q1 to q0: " << std::endl; +// for (FT x = FT(0); x <= FT(1); x += step) { +// std::cout << "3D wachspress/authalic: "; +// q1 = Point_3(3, 1, FT(2) - x); +// std::cout << CGAL::Weights::three_point_family_weight(p0, p1, p2, q1, wp) << "/"; +// std::cout << CGAL::Weights::authalic_weight(p0, p1, p2, q1) << std::endl; +// } + +// Flattens an arbitrary quad into a planar quad. +template +void flatten(const typename GeomTraits::Point_3& t, // prev neighbor/vertex/point + const typename GeomTraits::Point_3& r, // curr neighbor/vertex/point + const typename GeomTraits::Point_3& p, // next neighbor/vertex/point + const typename GeomTraits::Point_3& q, // query point + typename GeomTraits::Point_2& tf, + typename GeomTraits::Point_2& rf, + typename GeomTraits::Point_2& pf, + typename GeomTraits::Point_2& qf, + const GeomTraits& traits) +{ + // std::cout << std::endl; + using Point_3 = typename GeomTraits::Point_3; + using Vector_3 = typename GeomTraits::Vector_3; + + auto point_3 = traits.construct_point_3_object(); + auto cross_product_3 = traits.construct_cross_product_vector_3_object(); + auto vector_3 = traits.construct_vector_3_object(); + auto centroid_3 = traits.construct_centroid_3_object(); + + // Compute centroid. + const Point_3 center = centroid_3(t, r, p, q); + // std::cout << "centroid: " << center << std::endl; + + // Translate. + const Point_3 t1 = point_3(t.x() - center.x(), t.y() - center.y(), t.z() - center.z()); + const Point_3 r1 = point_3(r.x() - center.x(), r.y() - center.y(), r.z() - center.z()); + const Point_3 p1 = point_3(p.x() - center.x(), p.y() - center.y(), p.z() - center.z()); + const Point_3 q1 = point_3(q.x() - center.x(), q.y() - center.y(), q.z() - center.z()); + + // std::cout << "translated t1: " << t1 << std::endl; + // std::cout << "translated r1: " << r1 << std::endl; + // std::cout << "translated p1: " << p1 << std::endl; + // std::cout << "translated q1: " << q1 << std::endl; + + // Middle axis. + Vector_3 ax = vector_3(q1, r1); + normalize_3(ax, traits); + + // Prev and next vectors. + Vector_3 v1 = vector_3(q1, t1); + Vector_3 v2 = vector_3(q1, p1); + + // Two triangle normals. + Vector_3 n1 = cross_product_3(v1, ax); + Vector_3 n2 = cross_product_3(ax, v2); + + // std::cout << "normal n1: " << n1 << std::endl; + // std::cout << "normal n2: " << n2 << std::endl; + + // Angle between two normals. + const double angle_rad = angle_3(n1, n2, traits); + // std::cout << "angle deg n1 <-> n2: " << angle_rad * 180.0 / CGAL_PI << std::endl; + + // Rotate p1 around ax so that it lands onto the plane [q1, t1, r1]. + const Point_3& t2 = t1; + const Point_3& r2 = r1; + const Point_3 p2 = rotate_point_3(angle_rad, ax, p1, traits); + const Point_3& q2 = q1; + // std::cout << "rotated p2: " << p2 << std::endl; + + // Compute orthogonal base vectors. + Vector_3 b1, b2; + const Vector_3& normal = n1; + orthogonal_bases_3(normal, b1, b2, traits); + + // const Angle angle12 = angle_3(b1, b2, traits); + // std::cout << "angle deg b1 <-> b2: " << angle12 * 180.0 / CGAL_PI << std::endl; + + // Flatten a quad. + const Point_3& origin = q2; + tf = to_2d(b1, b2, origin, t2, traits); + rf = to_2d(b1, b2, origin, r2, traits); + pf = to_2d(b1, b2, origin, p2, traits); + qf = to_2d(b1, b2, origin, q2, traits); + + // std::cout << "flattened qf: " << qf << std::endl; + // std::cout << "flattened tf: " << tf << std::endl; + // std::cout << "flattened rf: " << rf << std::endl; + // std::cout << "flattened pf: " << pf << std::endl; + + // std::cout << "A1: " << area_2(rf, qf, pf, traits) << std::endl; + // std::cout << "A2: " << area_2(pf, qf, rf, traits) << std::endl; + // std::cout << "C: " << area_2(tf, rf, pf, traits) << std::endl; + // std::cout << "B: " << area_2(pf, qf, tf, traits) << std::endl; +} + +template +typename GeomTraits::FT positive_area_2(const typename GeomTraits::Point_2& p, + const typename GeomTraits::Point_2& q, + const typename GeomTraits::Point_2& r, + const GeomTraits& traits) +{ + auto area_2 = traits.compute_area_2_object(); + return CGAL::abs(area_2(p, q, r)); +} + +template +typename GeomTraits::FT area_3(const typename GeomTraits::Point_3& p, + const typename GeomTraits::Point_3& q, + const typename GeomTraits::Point_3& r, + const GeomTraits& traits) +{ + using FT = typename GeomTraits::FT; + using Point_2 = typename GeomTraits::Point_2; + using Point_3 = typename GeomTraits::Point_3; + using Vector_3 = typename GeomTraits::Vector_3; + + auto area_2 = traits.compute_area_2_object(); + auto point_3 = traits.construct_point_3_object(); + auto cross_product_3 = traits.construct_cross_product_vector_3_object(); + auto vector_3 = traits.construct_vector_3_object(); + auto centroid_3 = traits.construct_centroid_3_object(); + + // Compute centroid. + const Point_3 center = centroid_3(p, q, r); + + // Translate. + const Point_3 a = point_3(p.x() - center.x(), p.y() - center.y(), p.z() - center.z()); + const Point_3 b = point_3(q.x() - center.x(), q.y() - center.y(), q.z() - center.z()); + const Point_3 c = point_3(r.x() - center.x(), r.y() - center.y(), r.z() - center.z()); + + // Prev and next vectors. + Vector_3 v1 = vector_3(b, a); + Vector_3 v2 = vector_3(b, c); + + // Compute normal. + Vector_3 normal = cross_product_3(v1, v2); + + // Compute orthogonal base vectors. + Vector_3 b1, b2; + orthogonal_bases_3(normal, b1, b2, traits); + + // Compute area. + const Point_3& origin = b; + const Point_2 pf = to_2d(b1, b2, origin, a, traits); + const Point_2 qf = to_2d(b1, b2, origin, b, traits); + const Point_2 rf = to_2d(b1, b2, origin, c, traits); + + return area_2(pf, qf, rf); +} + +// Computes positive area of a 3D triangle. +template +typename GeomTraits::FT positive_area_3(const typename GeomTraits::Point_3& p, + const typename GeomTraits::Point_3& q, + const typename GeomTraits::Point_3& r, + const GeomTraits& traits) +{ + using FT = typename GeomTraits::FT; + using Get_sqrt = Get_sqrt; + auto sqrt = Get_sqrt::sqrt_object(traits); + + auto squared_area_3 = traits.compute_squared_area_3_object(); + + return sqrt(squared_area_3(p, q, r)); +} } // namespace internal } // namespace Weights diff --git a/Weights/include/CGAL/Weights/inverse_distance_weights.h b/Weights/include/CGAL/Weights/inverse_distance_weights.h index 39dd22a189b..34e7a69bddd 100644 --- a/Weights/include/CGAL/Weights/inverse_distance_weights.h +++ b/Weights/include/CGAL/Weights/inverse_distance_weights.h @@ -14,219 +14,167 @@ #ifndef CGAL_INVERSE_DISTANCE_WEIGHTS_H #define CGAL_INVERSE_DISTANCE_WEIGHTS_H -// Internal includes. #include +#include +#include + namespace CGAL { namespace Weights { - /// \cond SKIP_IN_MANUAL - namespace inverse_distance_ns { +/// \cond SKIP_IN_MANUAL +namespace inverse_distance_ns { - template - FT weight(const FT d) { +template +FT weight(const FT d) +{ + FT w = FT(0); + CGAL_precondition(!is_zero(d)); + if (!is_zero(d)) + w = FT(1) / d; - FT w = FT(0); - CGAL_precondition(d != FT(0)); - if (d != FT(0)) { - w = FT(1) / d; - } - return w; - } - } - /// \endcond + return w; +} - #if defined(DOXYGEN_RUNNING) +} // namespace inverse_distance_ns - /*! - \ingroup PkgWeightsRefInverseDistanceWeights +/// \endcond - \brief computes the inverse distance weight in 2D using the points `p` and `q`, - given a traits class `traits` with geometric objects, predicates, and constructions. - */ - template - typename GeomTraits::FT inverse_distance_weight( - const typename GeomTraits::Point_2&, - const typename GeomTraits::Point_2& p, - const typename GeomTraits::Point_2&, - const typename GeomTraits::Point_2& q, - const GeomTraits& traits) { } +/*! + \ingroup PkgWeightsRefInverseDistanceWeights + \brief computes the inverse distance weight in 2D using the points `p` and `q`. + \tparam GeomTraits a model of `AnalyticWeightTraits_2` +*/ +template +typename GeomTraits::FT inverse_distance_weight(const typename GeomTraits::Point_2&, + const typename GeomTraits::Point_2& p, + const typename GeomTraits::Point_2&, + const typename GeomTraits::Point_2& q, + const GeomTraits& traits) +{ + using FT = typename GeomTraits::FT; - /*! - \ingroup PkgWeightsRefInverseDistanceWeights + const FT d = internal::distance_2(p, q, traits); + return inverse_distance_ns::weight(d); +} - \brief computes the inverse distance weight in 3D using the points `p` and `q`, - given a traits class `traits` with geometric objects, predicates, and constructions. - */ - template - typename GeomTraits::FT inverse_distance_weight( - const typename GeomTraits::Point_3&, - const typename GeomTraits::Point_3& p, - const typename GeomTraits::Point_3&, - const typename GeomTraits::Point_3& q, - const GeomTraits& traits) { } +/*! + \ingroup PkgWeightsRefInverseDistanceWeights + \brief computes the inverse distance weight in 2D using the points `p` and `q`. + \tparam Kernel a model of `Kernel` +*/ +template +#ifdef DOXYGEN_RUNNING +typename Kernel::FT inverse_distance_weight(const CGAL::Point_2&, + const CGAL::Point_2& p, + const CGAL::Point_2&, + const CGAL::Point_2& q) +#else +typename Kernel::FT inverse_distance_weight(const CGAL::Point_2& stub_l, + const CGAL::Point_2& p, + const CGAL::Point_2& stub_r, + const CGAL::Point_2& q) +#endif +{ + const Kernel traits; + return inverse_distance_weight(stub_l, p, stub_r, q, traits); +} - /*! - \ingroup PkgWeightsRefInverseDistanceWeights +/*! + \ingroup PkgWeightsRefInverseDistanceWeights + \brief computes the inverse distance weight in 2D using the points `p` and `q`. + \tparam GeomTraits a model of `AnalyticWeightTraits_2` +*/ +template +typename GeomTraits::FT inverse_distance_weight(const typename GeomTraits::Point_2& p, + const typename GeomTraits::Point_2& q, + const GeomTraits& traits) +{ + typename GeomTraits::Point_2 stub; + return inverse_distance_weight(stub, p, stub, q, traits); +} - \brief computes the inverse distance weight in 2D using the points `p` and `q`, - which are parameterized by a `Kernel` K. - */ - template - typename K::FT inverse_distance_weight( - const CGAL::Point_2&, - const CGAL::Point_2& p, - const CGAL::Point_2&, - const CGAL::Point_2& q) { } +/*! + \ingroup PkgWeightsRefInverseDistanceWeights + \brief computes the inverse distance weight in 2D using the points `p` and `q`. + \tparam Kernel a model of `Kernel` +*/ +template +typename Kernel::FT inverse_distance_weight(const CGAL::Point_2& p, + const CGAL::Point_2& q) +{ + CGAL::Point_2 stub; + return inverse_distance_weight(stub, p, stub, q); +} - /*! - \ingroup PkgWeightsRefInverseDistanceWeights +// 3D ============================================================================================== - \brief computes the inverse distance weight in 3D using the points `p` and `q`, - which are parameterized by a `Kernel` K. - */ - template - typename K::FT inverse_distance_weight( - const CGAL::Point_3&, - const CGAL::Point_3& p, - const CGAL::Point_3&, - const CGAL::Point_3& q) { } +/*! + \ingroup PkgWeightsRefInverseDistanceWeights + \brief computes the inverse distance weight in 3D using the points `p` and `q`. + \tparam GeomTraits a model of `AnalyticWeightTraits_3` +*/ +template +typename GeomTraits::FT inverse_distance_weight(const typename GeomTraits::Point_3&, + const typename GeomTraits::Point_3& p, + const typename GeomTraits::Point_3&, + const typename GeomTraits::Point_3& q, + const GeomTraits& traits) +{ + using FT = typename GeomTraits::FT; - /*! - \ingroup PkgWeightsRefInverseDistanceWeights + const FT d = internal::distance_3(p, q, traits); + return inverse_distance_ns::weight(d); +} - \brief computes the inverse distance weight in 2D using the points `p` and `q`, - given a traits class `traits` with geometric objects, predicates, and constructions. - */ - template - typename GeomTraits::FT inverse_distance_weight( - const typename GeomTraits::Point_2& p, - const typename GeomTraits::Point_2& q, - const GeomTraits& traits) { } +/*! + \ingroup PkgWeightsRefInverseDistanceWeights + \brief computes the inverse distance weight in 3D using the points `p` and `q`. + \tparam Kernel a model of `Kernel` +*/ +template +#ifdef DOXYGEN_RUNNING +typename Kernel::FT inverse_distance_weight(const CGAL::Point_3&, + const CGAL::Point_3& p, + const CGAL::Point_3&, + const CGAL::Point_3& q) +#else +typename Kernel::FT inverse_distance_weight(const CGAL::Point_3& stub_l, + const CGAL::Point_3& p, + const CGAL::Point_3& stub_r, + const CGAL::Point_3& q) +#endif +{ + const Kernel traits; + return inverse_distance_weight(stub_l, p, stub_r, q, traits); +} - /*! - \ingroup PkgWeightsRefInverseDistanceWeights +/*! + \ingroup PkgWeightsRefInverseDistanceWeights + \brief computes the inverse distance weight in 3D using the points `p` and `q`. + \tparam GeomTraits a model of `AnalyticWeightTraits_3` +*/ +template +typename GeomTraits::FT inverse_distance_weight(const typename GeomTraits::Point_3& p, + const typename GeomTraits::Point_3& q, + const GeomTraits& traits) +{ + typename GeomTraits::Point_3 stub; + return inverse_distance_weight(stub, p, stub, q, traits); +} - \brief computes the inverse distance weight in 3D using the points `p` and `q`, - given a traits class `traits` with geometric objects, predicates, and constructions. - */ - template - typename GeomTraits::FT inverse_distance_weight( - const typename GeomTraits::Point_3& p, - const typename GeomTraits::Point_3& q, - const GeomTraits& traits) { } - - /*! - \ingroup PkgWeightsRefInverseDistanceWeights - - \brief computes the inverse distance weight in 2D using the points `p` and `q`, - which are parameterized by a `Kernel` K. - */ - template - typename K::FT inverse_distance_weight( - const CGAL::Point_2& p, - const CGAL::Point_2& q) { } - - /*! - \ingroup PkgWeightsRefInverseDistanceWeights - - \brief computes the inverse distance weight in 3D using the points `p` and `q`, - which are parameterized by a `Kernel` K. - */ - template - typename K::FT inverse_distance_weight( - const CGAL::Point_3& p, - const CGAL::Point_3& q) { } - - #endif // DOXYGEN_RUNNING - - /// \cond SKIP_IN_MANUAL - template - typename GeomTraits::FT inverse_distance_weight( - const typename GeomTraits::Point_2&, - const typename GeomTraits::Point_2& r, - const typename GeomTraits::Point_2&, - const typename GeomTraits::Point_2& q, - const GeomTraits& traits) { - - using FT = typename GeomTraits::FT; - const FT d = internal::distance_2(traits, q, r); - return inverse_distance_ns::weight(d); - } - - template - typename GeomTraits::FT inverse_distance_weight( - const CGAL::Point_2& t, - const CGAL::Point_2& r, - const CGAL::Point_2& p, - const CGAL::Point_2& q) { - - const GeomTraits traits; - return inverse_distance_weight(t, r, p, q, traits); - } - - template - typename GeomTraits::FT inverse_distance_weight( - const typename GeomTraits::Point_2& p, - const typename GeomTraits::Point_2& q, - const GeomTraits& traits) { - - typename GeomTraits::Point_2 stub; - return inverse_distance_weight(stub, p, stub, q, traits); - } - - template - typename GeomTraits::FT inverse_distance_weight( - const CGAL::Point_2& p, - const CGAL::Point_2& q) { - - CGAL::Point_2 stub; - return inverse_distance_weight(stub, p, stub, q); - } - - template - typename GeomTraits::FT inverse_distance_weight( - const typename GeomTraits::Point_3&, - const typename GeomTraits::Point_3& r, - const typename GeomTraits::Point_3&, - const typename GeomTraits::Point_3& q, - const GeomTraits& traits) { - - using FT = typename GeomTraits::FT; - const FT d = internal::distance_3(traits, q, r); - return inverse_distance_ns::weight(d); - } - - template - typename GeomTraits::FT inverse_distance_weight( - const CGAL::Point_3& t, - const CGAL::Point_3& r, - const CGAL::Point_3& p, - const CGAL::Point_3& q) { - - const GeomTraits traits; - return inverse_distance_weight(t, r, p, q, traits); - } - - template - typename GeomTraits::FT inverse_distance_weight( - const typename GeomTraits::Point_3& p, - const typename GeomTraits::Point_3& q, - const GeomTraits& traits) { - - typename GeomTraits::Point_3 stub; - return inverse_distance_weight(stub, p, stub, q, traits); - } - - template - typename GeomTraits::FT inverse_distance_weight( - const CGAL::Point_3& p, - const CGAL::Point_3& q) { - - CGAL::Point_3 stub; - return inverse_distance_weight(stub, p, stub, q); - } - /// \endcond +/*! + \ingroup PkgWeightsRefInverseDistanceWeights + \brief computes the inverse distance weight in 3D using the points `p` and `q`. + \tparam Kernel a model of `Kernel` +*/ +template +typename Kernel::FT inverse_distance_weight(const CGAL::Point_3& p, + const CGAL::Point_3& q) +{ + CGAL::Point_3 stub; + return inverse_distance_weight(stub, p, stub, q); +} } // namespace Weights } // namespace CGAL diff --git a/Weights/include/CGAL/Weights/mean_value_weights.h b/Weights/include/CGAL/Weights/mean_value_weights.h index 814ba883608..a7bd53e9d6c 100644 --- a/Weights/include/CGAL/Weights/mean_value_weights.h +++ b/Weights/include/CGAL/Weights/mean_value_weights.h @@ -14,498 +14,457 @@ #ifndef CGAL_MEAN_VALUE_WEIGHTS_H #define CGAL_MEAN_VALUE_WEIGHTS_H -// Internal includes. #include #include +#include +#include +#include +#include + +#include + namespace CGAL { namespace Weights { - /// \cond SKIP_IN_MANUAL - namespace mean_value_ns { +/// \cond SKIP_IN_MANUAL - template - FT sign_of_weight(const FT A1, const FT A2, const FT B) { +namespace mean_value_ns { - if (A1 > FT(0) && A2 > FT(0) && B <= FT(0)) { - return +FT(1); - } - if (A1 < FT(0) && A2 < FT(0) && B >= FT(0)) { - return -FT(1); - } - if (B > FT(0)) { - return +FT(1); - } - if (B < FT(0)) { - return -FT(1); - } - return FT(0); - } +template +FT sign_of_weight(const FT A0, const FT A2, const FT B) +{ + if (A0 > FT(0) && A2 > FT(0) && B <= FT(0)) + return +FT(1); - template - typename GeomTraits::FT weight( - const GeomTraits& traits, - const typename GeomTraits::FT r1, - const typename GeomTraits::FT r2, - const typename GeomTraits::FT r3, - const typename GeomTraits::FT D1, - const typename GeomTraits::FT D2, - const typename GeomTraits::FT D, - const typename GeomTraits::FT sign) { + if (A0 < FT(0) && A2 < FT(0) && B >= FT(0)) + return -FT(1); - using FT = typename GeomTraits::FT; - using Get_sqrt = internal::Get_sqrt; - const auto sqrt = Get_sqrt::sqrt_object(traits); + if (B > FT(0)) + return +FT(1); - const FT P1 = r1 * r2 + D1; - const FT P2 = r2 * r3 + D2; + if (B < FT(0)) + return -FT(1); - FT w = FT(0); - CGAL_precondition(P1 != FT(0) && P2 != FT(0)); - const FT prod = P1 * P2; - if (prod != FT(0)) { - const FT inv = FT(1) / prod; - w = FT(2) * (r1 * r3 - D) * inv; - CGAL_assertion(w >= FT(0)); - w = sqrt(w); - } - w *= FT(2); w *= sign; - return w; - } + return FT(0); +} + +template +typename GeomTraits::FT weight(const typename GeomTraits::FT d0, + const typename GeomTraits::FT d2, + const typename GeomTraits::FT d, + const typename GeomTraits::FT D0, + const typename GeomTraits::FT D2, + const typename GeomTraits::FT D, + const typename GeomTraits::FT sign, + const GeomTraits& traits) +{ + using FT = typename GeomTraits::FT; + + using Get_sqrt = internal::Get_sqrt; + auto sqrt = Get_sqrt::sqrt_object(traits); + + const FT P1 = d * d0 + D0; + const FT P2 = d * d2 + D2; + + FT w = FT(0); + CGAL_precondition(!is_zero(P1) && !is_zero(P2)); + const FT prod = P1 * P2; + if (!is_zero(prod)) + { + w = FT(2) * (d0 * d2 - D) / prod; + CGAL_assertion(w >= FT(0)); + w = sqrt(w); } - /// \endcond - #if defined(DOXYGEN_RUNNING) + w *= sign * FT(2); + return w; +} - /*! - \ingroup PkgWeightsRefMeanValueWeights +} // namespace mean_value_ns - \brief computes the mean value weight in 2D at `q` using the points `p0`, `p1`, - and `p2`, given a traits class `traits` with geometric objects, predicates, and constructions. - */ - template - typename GeomTraits::FT mean_value_weight( - const typename GeomTraits::Point_2& p0, - const typename GeomTraits::Point_2& p1, - const typename GeomTraits::Point_2& p2, - const typename GeomTraits::Point_2& q, - const GeomTraits& traits) { } +/// \endcond - /*! - \ingroup PkgWeightsRefMeanValueWeights +// 2D ============================================================================================== - \brief computes the mean value weight in 2D at `q` using the points `p0`, `p1`, - and `p2` which are parameterized by a `Kernel` K. - */ - template - typename K::FT mean_value_weight( - const CGAL::Point_2& p0, - const CGAL::Point_2& p1, - const CGAL::Point_2& p2, - const CGAL::Point_2& q) { } +/*! + \ingroup PkgWeightsRefMeanValueWeights + \brief computes the mean value weight in 2D at `q` using the points `p0`, `p1`, and `p2`. + \tparam GeomTraits a model of `AnalyticWeightTraits_2` +*/ +template +typename GeomTraits::FT mean_value_weight(const typename GeomTraits::Point_2& p0, + const typename GeomTraits::Point_2& p1, + const typename GeomTraits::Point_2& p2, + const typename GeomTraits::Point_2& q, + const GeomTraits& traits) +{ + using FT = typename GeomTraits::FT; + using Vector_2 = typename GeomTraits::Vector_2; - #endif // DOXYGEN_RUNNING + auto vector_2 = traits.construct_vector_2_object(); + auto dot_product_2 = traits.compute_scalar_product_2_object(); + auto area_2 = traits.compute_area_2_object(); + + const Vector_2 v1 = vector_2(q, p0); + const Vector_2 v = vector_2(q, p1); + const Vector_2 v2 = vector_2(q, p2); + + const FT d0 = internal::length_2(v1, traits); + const FT d = internal::length_2(v, traits); + const FT d2 = internal::length_2(v2, traits); + + const FT D0 = dot_product_2(v1, v); + const FT D2 = dot_product_2(v, v2); + const FT D = dot_product_2(v1, v2); + + const FT A0 = area_2(p1, q, p0); + const FT A2 = area_2(p2, q, p1); + const FT B = area_2(p2, q, p0); + + const FT sign = mean_value_ns::sign_of_weight(A0, A2, B); + return mean_value_ns::weight(d0, d2, d, D0, D2, D, sign, traits); +} + +/*! + \ingroup PkgWeightsRefMeanValueWeights + \brief computes the mean value weight in 2D at `q` using the points `p0`, `p1`, and `p2`. + \tparam Kernel a model of `Kernel` +*/ +template +typename Kernel::FT mean_value_weight(const CGAL::Point_2& p0, + const CGAL::Point_2& p1, + const CGAL::Point_2& p2, + const CGAL::Point_2& q) +{ + const Kernel traits; + return mean_value_weight(p0, p1, p2, q, traits); +} + +// 3D ============================================================================================== + +/// \cond SKIP_IN_MANUAL + +template +typename GeomTraits::FT mean_value_weight(const typename GeomTraits::Point_3& p0, + const typename GeomTraits::Point_3& p1, + const typename GeomTraits::Point_3& p2, + const typename GeomTraits::Point_3& q, + const GeomTraits& traits) +{ + using Point_2 = typename GeomTraits::Point_2; + + Point_2 p0f, p1f, p2f, qf; + internal::flatten(p0, p1, p2, q, + p0f, p1f, p2f, qf, + traits); + return CGAL::Weights::mean_value_weight(p0f, p1f, p2f, qf, traits); +} + +template +typename Kernel::FT mean_value_weight(const CGAL::Point_3& p0, + const CGAL::Point_3& p1, + const CGAL::Point_3& p2, + const CGAL::Point_3& q) +{ + const Kernel traits; + return mean_value_weight(p0, p1, p2, q, traits); +} + +/// \endcond + +/*! + \ingroup PkgWeightsRefBarycentricMeanValueWeights + + \brief 2D mean value weights for polygons. + + This class implements 2D mean value weights (\cite cgal:bc:fhk-gcbcocp-06, \cite cgal:f-mvc-03, + \cite cgal:bc:hf-mvcapp-06) which can be computed at any point inside and outside a simple polygon. + + Mean value weights are well-defined inside and outside a simple polygon and are + non-negative in the kernel of a star-shaped polygon. These weights are computed + analytically using the formulation from `tangent_weight()`. + + \tparam VertexRange a model of `ConstRange` whose iterator type is `RandomAccessIterator` + \tparam GeomTraits a model of `AnalyticWeightTraits_2` + \tparam PointMap a model of `ReadablePropertyMap` whose key type is `VertexRange::value_type` and + value type is `Point_2`. The default is `CGAL::Identity_property_map`. + + \cgalModels `BarycentricWeights_2` +*/ +template > +class Mean_value_weights_2 +{ +public: + /// \name Types + /// @{ /// \cond SKIP_IN_MANUAL - template - typename GeomTraits::FT mean_value_weight( - const typename GeomTraits::Point_2& t, - const typename GeomTraits::Point_2& r, - const typename GeomTraits::Point_2& p, - const typename GeomTraits::Point_2& q, - const GeomTraits& traits) { - using FT = typename GeomTraits::FT; - const auto dot_product_2 = - traits.compute_scalar_product_2_object(); - const auto construct_vector_2 = - traits.construct_vector_2_object(); + using Vertex_range = VertexRange; + using Geom_traits = GeomTraits; + using Point_map = PointMap; - const auto v1 = construct_vector_2(q, t); - const auto v2 = construct_vector_2(q, r); - const auto v3 = construct_vector_2(q, p); - - const FT l1 = internal::length_2(traits, v1); - const FT l2 = internal::length_2(traits, v2); - const FT l3 = internal::length_2(traits, v3); - - const FT D1 = dot_product_2(v1, v2); - const FT D2 = dot_product_2(v2, v3); - const FT D = dot_product_2(v1, v3); - - const FT A1 = internal::area_2(traits, r, q, t); - const FT A2 = internal::area_2(traits, p, q, r); - const FT B = internal::area_2(traits, p, q, t); - - const FT sign = mean_value_ns::sign_of_weight(A1, A2, B); - return mean_value_ns::weight( - traits, l1, l2, l3, D1, D2, D, sign); - } - - template - typename GeomTraits::FT mean_value_weight( - const CGAL::Point_2& t, - const CGAL::Point_2& r, - const CGAL::Point_2& p, - const CGAL::Point_2& q) { - - const GeomTraits traits; - return mean_value_weight(t, r, p, q, traits); - } - - namespace internal { - - template - typename GeomTraits::FT mean_value_weight( - const typename GeomTraits::Point_3& t, - const typename GeomTraits::Point_3& r, - const typename GeomTraits::Point_3& p, - const typename GeomTraits::Point_3& q, - const GeomTraits& traits) { - - using Point_2 = typename GeomTraits::Point_2; - Point_2 tf, rf, pf, qf; - internal::flatten( - traits, - t, r, p, q, - tf, rf, pf, qf); - return CGAL::Weights:: - mean_value_weight(tf, rf, pf, qf, traits); - } - - template - typename GeomTraits::FT mean_value_weight( - const CGAL::Point_3& t, - const CGAL::Point_3& r, - const CGAL::Point_3& p, - const CGAL::Point_3& q) { - - const GeomTraits traits; - return mean_value_weight(t, r, p, q, traits); - } - - } // namespace internal + using Vector_2 = typename GeomTraits::Vector_2; + using Area_2 = typename GeomTraits::Compute_area_2; + using Construct_vector_2 = typename GeomTraits::Construct_vector_2; + using Squared_length_2 = typename GeomTraits::Compute_squared_length_2; + using Scalar_product_2 = typename GeomTraits::Compute_scalar_product_2; + using Get_sqrt = internal::Get_sqrt; + using Sqrt = typename Get_sqrt::Sqrt; /// \endcond - /*! - \ingroup PkgWeightsRefBarycentricMeanValueWeights + /// Number type. + typedef typename GeomTraits::FT FT; - \brief 2D mean value weights for polygons. + /// Point type. + typedef typename GeomTraits::Point_2 Point_2; - This class implements 2D mean value weights ( \cite cgal:bc:hf-mvcapp-06, - \cite cgal:bc:fhk-gcbcocp-06, \cite cgal:f-mvc-03 ) which can be computed - at any point inside and outside a simple polygon. + /// @} - Mean value weights are well-defined inside and outside a simple polygon and are - non-negative in the kernel of a star-shaped polygon. These weights are computed - analytically using the formulation from the `tangent_weight()`. - - \tparam VertexRange - a model of `ConstRange` whose iterator type is `RandomAccessIterator` - - \tparam GeomTraits - a model of `AnalyticWeightTraits_2` - - \tparam PointMap - a model of `ReadablePropertyMap` whose key type is `VertexRange::value_type` and - value type is `Point_2`. The default is `CGAL::Identity_property_map`. - - \cgalModels `BarycentricWeights_2` - */ - template< - typename VertexRange, - typename GeomTraits, - typename PointMap = CGAL::Identity_property_map > - class Mean_value_weights_2 { - - public: - - /// \name Types - /// @{ - - /// \cond SKIP_IN_MANUAL - using Vertex_range = VertexRange; - using Geom_traits = GeomTraits; - using Point_map = PointMap; - - using Vector_2 = typename GeomTraits::Vector_2; - using Area_2 = typename GeomTraits::Compute_area_2; - using Construct_vector_2 = typename GeomTraits::Construct_vector_2; - using Squared_length_2 = typename GeomTraits::Compute_squared_length_2; - using Scalar_product_2 = typename GeomTraits::Compute_scalar_product_2; - using Get_sqrt = internal::Get_sqrt; - using Sqrt = typename Get_sqrt::Sqrt; - /// \endcond - - /// Number type. - typedef typename GeomTraits::FT FT; - - /// Point type. - typedef typename GeomTraits::Point_2 Point_2; - - /// @} - - /// \name Initialization - /// @{ - - /*! - \brief initializes all internal data structures. - - This class implements the behavior of mean value weights - for 2D query points inside simple polygons. - - \param polygon - an instance of `VertexRange` with the vertices of a simple polygon - - \param traits - a traits class with geometric objects, predicates, and constructions; - the default initialization is provided - - \param point_map - an instance of `PointMap` that maps a vertex from `polygon` to `Point_2`; - the default initialization is provided - - \pre polygon.size() >= 3 - \pre polygon is simple - */ - Mean_value_weights_2( - const VertexRange& polygon, - const GeomTraits traits = GeomTraits(), - const PointMap point_map = PointMap()) : - m_polygon(polygon), - m_traits(traits), - m_point_map(point_map), - m_area_2(m_traits.compute_area_2_object()), - m_construct_vector_2(m_traits.construct_vector_2_object()), - m_squared_length_2(m_traits.compute_squared_length_2_object()), - m_scalar_product_2(m_traits.compute_scalar_product_2_object()), - m_sqrt(Get_sqrt::sqrt_object(m_traits)) { - - CGAL_precondition( - polygon.size() >= 3); - CGAL_precondition( - internal::is_simple_2(polygon, traits, point_map)); - resize(); - } - - /// @} - - /// \name Access - /// @{ - - /*! - \brief computes 2D mean value weights. - - This function fills a destination range with 2D mean value weights computed at - the `query` point with respect to the vertices of the input polygon. - - The number of computed weights is equal to the number of polygon vertices. - - \tparam OutIterator - a model of `OutputIterator` whose value type is `FT` - - \param query - a query point - - \param w_begin - the beginning of the destination range with the computed weights - - \return an output iterator to the element in the destination range, - one past the last weight stored - */ - template - OutIterator operator()(const Point_2& query, OutIterator w_begin) { - const bool normalize = false; - return operator()(query, w_begin, normalize); - } - - /// @} - - /// \cond SKIP_IN_MANUAL - template - OutIterator operator()(const Point_2& query, OutIterator weights, const bool normalize) { - return optimal_weights(query, weights, normalize); - } - /// \endcond - - private: - - // Fields. - const VertexRange& m_polygon; - const GeomTraits m_traits; - const PointMap m_point_map; - - const Area_2 m_area_2; - const Construct_vector_2 m_construct_vector_2; - const Squared_length_2 m_squared_length_2; - const Scalar_product_2 m_scalar_product_2; - const Sqrt m_sqrt; - - std::vector s; - std::vector r; - std::vector A; - std::vector D; - std::vector t; - std::vector w; - - // Functions. - void resize() { - s.resize(m_polygon.size()); - r.resize(m_polygon.size()); - A.resize(m_polygon.size()); - D.resize(m_polygon.size()); - t.resize(m_polygon.size()); - w.resize(m_polygon.size()); - } - - template - OutputIterator optimal_weights( - const Point_2& query, OutputIterator weights, const bool normalize) { - - // Get the number of vertices in the polygon. - const std::size_t n = m_polygon.size(); - - // Compute vectors s following the pseudo-code in the Figure 10 from [1]. - for (std::size_t i = 0; i < n; ++i) { - const auto& pi = get(m_point_map, *(m_polygon.begin() + i)); - s[i] = m_construct_vector_2(query, pi); - } - - // Compute lengths r, areas A, and dot products D following the pseudo-code - // in the Figure 10 from [1]. Split the loop to make this computation faster. - const auto& p1 = get(m_point_map, *(m_polygon.begin() + 0)); - const auto& p2 = get(m_point_map, *(m_polygon.begin() + 1)); - - r[0] = m_sqrt(m_squared_length_2(s[0])); - A[0] = m_area_2(p1, p2, query); - D[0] = m_scalar_product_2(s[0], s[1]); - - for (std::size_t i = 1; i < n - 1; ++i) { - const auto& pi1 = get(m_point_map, *(m_polygon.begin() + (i + 0))); - const auto& pi2 = get(m_point_map, *(m_polygon.begin() + (i + 1))); - - r[i] = m_sqrt(m_squared_length_2(s[i])); - A[i] = m_area_2(pi1, pi2, query); - D[i] = m_scalar_product_2(s[i], s[i + 1]); - } - - const auto& pn = get(m_point_map, *(m_polygon.begin() + (n - 1))); - r[n - 1] = m_sqrt(m_squared_length_2(s[n - 1])); - A[n - 1] = m_area_2(pn, p1, query); - D[n - 1] = m_scalar_product_2(s[n - 1], s[0]); - - // Compute intermediate values t using the formulas from slide 19 here - // - http://www.inf.usi.ch/hormann/nsfworkshop/presentations/Hormann.pdf - for (std::size_t i = 0; i < n - 1; ++i) { - CGAL_assertion((r[i] * r[i + 1] + D[i]) != FT(0)); - t[i] = FT(2) * A[i] / (r[i] * r[i + 1] + D[i]); - } - - CGAL_assertion((r[n - 1] * r[0] + D[n - 1]) != FT(0)); - t[n - 1] = FT(2) * A[n - 1] / (r[n - 1] * r[0] + D[n - 1]); - - // Compute mean value weights using the same pseudo-code as before. - CGAL_assertion(r[0] != FT(0)); - w[0] = FT(2) * (t[n - 1] + t[0]) / r[0]; - - for (std::size_t i = 1; i < n - 1; ++i) { - CGAL_assertion(r[i] != FT(0)); - w[i] = FT(2) * (t[i - 1] + t[i]) / r[i]; - } - - CGAL_assertion(r[n - 1] != FT(0)); - w[n - 1] = FT(2) * (t[n - 2] + t[n - 1]) / r[n - 1]; - - // Normalize if necessary. - if (normalize) { - internal::normalize(w); - } - - // Return weights. - for (std::size_t i = 0; i < n; ++i) { - *(weights++) = w[i]; - } - return weights; - } - }; + /// \name Initialization + /// @{ /*! - \ingroup PkgWeightsRefBarycentricMeanValueWeights + \brief initializes all internal data structures. - \brief computes 2D mean value weights for polygons. + This class implements the behavior of mean value weights + for 2D query points inside simple polygons. - This function computes 2D mean value weights at a given `query` point - with respect to the vertices of a simple `polygon`, that is one - weight per vertex. The weights are stored in a destination range - beginning at `w_begin`. - - Internally, the class `Mean_value_weights_2` is used. If one wants to process - multiple query points, it is better to use that class. When using the free function, - internal memory is allocated for each query point, while when using the class, - it is allocated only once which is much more efficient. However, for a few query - points, it is easier to use this function. It can also be used when the processing - time is not a concern. - - \tparam PointRange - a model of `ConstRange` whose iterator type is `RandomAccessIterator` - and value type is `GeomTraits::Point_2` - - \tparam OutIterator - a model of `OutputIterator` whose value type is `GeomTraits::FT` - - \tparam GeomTraits - a model of `AnalyticWeightTraits_2` - - \param polygon - an instance of `PointRange` with 2D points which form a simple polygon - - \param query - a query point - - \param w_begin - the beginning of the destination range with the computed weights - - \param traits - a traits class with geometric objects, predicates, and constructions; - this parameter can be omitted if the traits class can be deduced from the point type - - \return an output iterator to the element in the destination range, - one past the last weight stored + \param polygon an instance of `VertexRange` with the vertices of a simple polygon + \param traits a traits class with geometric objects, predicates, and constructions; + the default initialization is provided + \param point_map an instance of `PointMap` that maps a vertex from `polygon` to `Point_2`; + the default initialization is provided \pre polygon.size() >= 3 \pre polygon is simple */ - template< - typename PointRange, - typename OutIterator, - typename GeomTraits> - OutIterator mean_value_weights_2( - const PointRange& polygon, const typename GeomTraits::Point_2& query, - OutIterator w_begin, const GeomTraits& traits) { - - Mean_value_weights_2 - mean_value(polygon, traits); - return mean_value(query, w_begin); + Mean_value_weights_2(const VertexRange& polygon, + const GeomTraits traits = GeomTraits(), + const PointMap point_map = PointMap()) + : m_polygon(polygon), + m_traits(traits), + m_point_map(point_map), + m_area_2(m_traits.compute_area_2_object()), + m_construct_vector_2(m_traits.construct_vector_2_object()), + m_squared_length_2(m_traits.compute_squared_length_2_object()), + m_scalar_product_2(m_traits.compute_scalar_product_2_object()), + m_sqrt(Get_sqrt::sqrt_object(m_traits)) + { + CGAL_precondition(polygon.size() >= 3); + CGAL_precondition(internal::is_simple_2(polygon, traits, point_map)); + resize(); } + /// @} + + /// \name Access + /// @{ + + /*! + \brief computes 2D mean value weights. + + This function fills a destination range with 2D mean value weights computed at + the `query` point with respect to the vertices of the input polygon. + + The number of computed weights is equal to the number of polygon vertices. + + \tparam OutIterator a model of `OutputIterator` whose value type is `FT` + + \param query a query point + \param w_begin the beginning of the destination range with the computed weights + + \return an output iterator to the element in the destination range, one past the last weight stored + */ + template + OutIterator operator()(const Point_2& query, OutIterator w_begin) + { + const bool normalize = false; + return operator()(query, w_begin, normalize); + } + + /// @} + /// \cond SKIP_IN_MANUAL - template< - typename PointRange, - typename OutIterator> - OutIterator mean_value_weights_2( - const PointRange& polygon, - const typename PointRange::value_type& query, - OutIterator w_begin) { - using Point_2 = typename PointRange::value_type; - using GeomTraits = typename Kernel_traits::Kernel; - const GeomTraits traits; - return mean_value_weights_2( - polygon, query, w_begin, traits); + template + OutIterator operator()(const Point_2& query, + OutIterator weights, + const bool normalize) + { + return optimal_weights(query, weights, normalize); } + /// \endcond +private: + const VertexRange& m_polygon; + const GeomTraits m_traits; + const PointMap m_point_map; + + const Area_2 m_area_2; + const Construct_vector_2 m_construct_vector_2; + const Squared_length_2 m_squared_length_2; + const Scalar_product_2 m_scalar_product_2; + const Sqrt m_sqrt; + + std::vector s; + std::vector r; + std::vector A; + std::vector D; + std::vector t; + std::vector w; + + void resize() + { + s.resize(m_polygon.size()); + r.resize(m_polygon.size()); + A.resize(m_polygon.size()); + D.resize(m_polygon.size()); + t.resize(m_polygon.size()); + w.resize(m_polygon.size()); + } + + template + OutputIterator optimal_weights(const Point_2& query, + OutputIterator weights, + const bool normalize) + { + const std::size_t n = m_polygon.size(); + + // Compute vectors s following the pseudo-code in the Figure 10 from [1]. + for (std::size_t i = 0; i < n; ++i) + { + const auto& pi = get(m_point_map, *(m_polygon.begin() + i)); + s[i] = m_construct_vector_2(query, pi); + } + + // Compute lengths r, areas A, and dot products D following the pseudo-code + // in the Figure 10 from [1]. Split the loop to make this computation faster. + const auto& p1 = get(m_point_map, *(m_polygon.begin() + 0)); + const auto& p2 = get(m_point_map, *(m_polygon.begin() + 1)); + + r[0] = m_sqrt(m_squared_length_2(s[0])); + A[0] = m_area_2(p1, p2, query); + D[0] = m_scalar_product_2(s[0], s[1]); + + for (std::size_t i = 1; i < n - 1; ++i) + { + const auto& pi1 = get(m_point_map, *(m_polygon.begin() + (i + 0))); + const auto& pi2 = get(m_point_map, *(m_polygon.begin() + (i + 1))); + + r[i] = m_sqrt(m_squared_length_2(s[i])); + A[i] = m_area_2(pi1, pi2, query); + D[i] = m_scalar_product_2(s[i], s[i + 1]); + } + + const auto& pn = get(m_point_map, *(m_polygon.begin() + (n - 1))); + r[n - 1] = m_sqrt(m_squared_length_2(s[n - 1])); + A[n - 1] = m_area_2(pn, p1, query); + D[n - 1] = m_scalar_product_2(s[n - 1], s[0]); + + // Compute intermediate values t using the formulas from slide 19 here + // - http://www.inf.usi.ch/hormann/nsfworkshop/presentations/Hormann.pdf + for (std::size_t i = 0; i < n - 1; ++i) + { + CGAL_assertion((r[i] * r[i + 1] + D[i]) != FT(0)); + t[i] = FT(2) * A[i] / (r[i] * r[i + 1] + D[i]); + } + + CGAL_assertion((r[n - 1] * r[0] + D[n - 1]) != FT(0)); + t[n - 1] = FT(2) * A[n - 1] / (r[n - 1] * r[0] + D[n - 1]); + + // Compute mean value weights using the same pseudo-code as before. + CGAL_assertion(r[0] != FT(0)); + w[0] = FT(2) * (t[n - 1] + t[0]) / r[0]; + + for (std::size_t i = 1; i < n - 1; ++i) + { + CGAL_assertion(r[i] != FT(0)); + w[i] = FT(2) * (t[i - 1] + t[i]) / r[i]; + } + + CGAL_assertion(r[n - 1] != FT(0)); + w[n - 1] = FT(2) * (t[n - 2] + t[n - 1]) / r[n - 1]; + + // Normalize if necessary. + if (normalize) + internal::normalize(w); + + // Return weights. + for (std::size_t i = 0; i < n; ++i) + *(weights++) = w[i]; + + return weights; + } +}; + +/*! + \ingroup PkgWeightsRefBarycentricMeanValueWeights + + \brief computes 2D mean value weights for polygons. + + This function computes 2D mean value weights at a given `query` point + with respect to the vertices of a simple `polygon`, that is one + weight per vertex. The weights are stored in a destination range + beginning at `w_begin`. + + Internally, the class `Mean_value_weights_2` is used. If one wants to process + multiple query points, it is better to use that class. When using the free function, + internal memory is allocated for each query point, while when using the class, + it is allocated only once which is much more efficient. However, for a few query + points, it is easier to use this function. It can also be used when the processing + time is not a concern. + + \tparam PointRange a model of `ConstRange` whose iterator type is `RandomAccessIterator` + and value type is `GeomTraits::Point_2` + \tparam OutIterator a model of `OutputIterator` whose value type is `GeomTraits::FT` + \tparam GeomTraits a model of `AnalyticWeightTraits_2` + + \param polygon an instance of `PointRange` with 2D points which form a simple polygon + \param query a query point + \param w_begin the beginning of the destination range with the computed weights + \param traits a traits class with geometric objects, predicates, and constructions; + this parameter can be omitted if the traits class can be deduced from the point type + + \return an output iterator to the element in the destination range, one past the last weight stored + + \pre `polygon.size() >= 3` + \pre `polygon` is simple +*/ +template +OutIterator mean_value_weights_2(const PointRange& polygon, + const typename GeomTraits::Point_2& query, + OutIterator w_begin, + const GeomTraits& traits) +{ + Mean_value_weights_2 mean_value(polygon, traits); + return mean_value(query, w_begin); +} + +/// \cond SKIP_IN_MANUAL + +template +OutIterator mean_value_weights_2(const PointRange& polygon, + const typename PointRange::value_type& query, + OutIterator w_begin) +{ + using Point_2 = typename PointRange::value_type; + using GeomTraits = typename Kernel_traits::Kernel; + + const GeomTraits traits; + return mean_value_weights_2(polygon, query, w_begin, traits); +} + +/// \endcond + } // namespace Weights } // namespace CGAL diff --git a/Weights/include/CGAL/Weights/mixed_voronoi_region_weights.h b/Weights/include/CGAL/Weights/mixed_voronoi_region_weights.h index 579e8efda77..647e771a7c9 100644 --- a/Weights/include/CGAL/Weights/mixed_voronoi_region_weights.h +++ b/Weights/include/CGAL/Weights/mixed_voronoi_region_weights.h @@ -14,157 +14,115 @@ #ifndef CGAL_MIXED_VORONOI_REGION_WEIGHTS_H #define CGAL_MIXED_VORONOI_REGION_WEIGHTS_H -// Internal includes. #include +#include +#include + namespace CGAL { namespace Weights { - #if defined(DOXYGEN_RUNNING) +// 2D ============================================================================================== - /*! - \ingroup PkgWeightsRefMixedVoronoiRegionWeights +/*! + \ingroup PkgWeightsRefMixedVoronoiRegionWeights + \brief computes the area of the mixed Voronoi cell in 2D using the points `p`, `q`, and `r`. + \tparam GeomTraits a model of `AnalyticWeightTraits_2` +*/ +template +typename GeomTraits::FT mixed_voronoi_area(const typename GeomTraits::Point_2& p, + const typename GeomTraits::Point_2& q, + const typename GeomTraits::Point_2& r, + const GeomTraits& traits) +{ + using FT = typename GeomTraits::FT; + using Point_2 = typename GeomTraits::Point_2; - \brief computes the area of the mixed Voronoi cell in 2D using the points `p`, `q` - and `r`, given a traits class `traits` with geometric objects, predicates, and constructions. - */ - template - typename GeomTraits::FT mixed_voronoi_area( - const typename GeomTraits::Point_2& p, - const typename GeomTraits::Point_2& q, - const typename GeomTraits::Point_2& r, - const GeomTraits& traits) { } + auto angle_2 = traits.angle_2_object(); + auto midpoint_2 = traits.construct_midpoint_2_object(); + auto circumcenter_2 = traits.construct_circumcenter_2_object(); - /*! - \ingroup PkgWeightsRefMixedVoronoiRegionWeights + Point_2 center; + if (angle_2(p, q, r) != CGAL::OBTUSE && + angle_2(q, r, p) != CGAL::OBTUSE && + angle_2(r, p, q) != CGAL::OBTUSE) + center = circumcenter_2(p, q, r); + else + center = midpoint_2(r, p); - \brief computes the area of the mixed Voronoi cell in 3D using the points `p`, `q` - and `r`, given a traits class `traits` with geometric objects, predicates, and constructions. - */ - template - typename GeomTraits::FT mixed_voronoi_area( - const typename GeomTraits::Point_3& p, - const typename GeomTraits::Point_3& q, - const typename GeomTraits::Point_3& r, - const GeomTraits& traits) { } + const Point_2 m1 = midpoint_2(q, r); + const Point_2 m2 = midpoint_2(q, p); - /*! - \ingroup PkgWeightsRefMixedVoronoiRegionWeights + const FT A1 = internal::positive_area_2(q, m1, center, traits); + const FT A2 = internal::positive_area_2(q, center, m2, traits); - \brief computes the area of the mixed Voronoi cell in 2D using the points `p`, `q` - and `r` which are parameterized by a `Kernel` K. - */ - template - typename K::FT mixed_voronoi_area( - const CGAL::Point_2& p, - const CGAL::Point_2& q, - const CGAL::Point_2& r) { } + return A1 + A2; +} - /*! - \ingroup PkgWeightsRefMixedVoronoiRegionWeights +/*! + \ingroup PkgWeightsRefMixedVoronoiRegionWeights + \brief computes the area of the mixed Voronoi cell in 2D using the points `p`, `q`, and `r`. + \tparam Kernel a model of `Kernel` +*/ +template +typename GeomTraits::FT mixed_voronoi_area(const CGAL::Point_2& p, + const CGAL::Point_2& q, + const CGAL::Point_2& r) +{ + const GeomTraits traits; + return mixed_voronoi_area(p, q, r, traits); +} - \brief computes the area of the mixed Voronoi cell in 3D using the points `p`, `q` - and `r` which are parameterized by a `Kernel` K. - */ - template - typename K::FT mixed_voronoi_area( - const CGAL::Point_3& p, - const CGAL::Point_3& q, - const CGAL::Point_3& r) { } +// 3D ============================================================================================== - #endif // DOXYGEN_RUNNING +/*! + \ingroup PkgWeightsRefMixedVoronoiRegionWeights + \brief computes the area of the mixed Voronoi cell in 3D using the points `p`, `q`, and `r`. + \tparam GeomTraits a model of `AnalyticWeightTraits_3` +*/ +template +typename GeomTraits::FT mixed_voronoi_area(const typename GeomTraits::Point_3& p, + const typename GeomTraits::Point_3& q, + const typename GeomTraits::Point_3& r, + const GeomTraits& traits) +{ + using FT = typename GeomTraits::FT; + using Point_3 = typename GeomTraits::Point_3; - /// \cond SKIP_IN_MANUAL - template - typename GeomTraits::FT mixed_voronoi_area( - const typename GeomTraits::Point_2& p, - const typename GeomTraits::Point_2& q, - const typename GeomTraits::Point_2& r, - const GeomTraits& traits) { + auto angle_3 = traits.angle_3_object(); + auto midpoint_3 = traits.construct_midpoint_3_object(); + auto circumcenter_3 = traits.construct_circumcenter_3_object(); - using FT = typename GeomTraits::FT; - using Point_2 = typename GeomTraits::Point_2; + Point_3 center; + if (angle_3(p, q, r) != CGAL::OBTUSE && + angle_3(q, r, p) != CGAL::OBTUSE && + angle_3(r, p, q) != CGAL::OBTUSE) + center = circumcenter_3(p, q, r); + else + center = midpoint_3(r, p); - const auto angle_2 = - traits.angle_2_object(); - const auto a1 = angle_2(p, q, r); - const auto a2 = angle_2(q, r, p); - const auto a3 = angle_2(r, p, q); + const Point_3 m1 = midpoint_3(q, r); + const Point_3 m2 = midpoint_3(q, p); - Point_2 center; - const auto midpoint_2 = - traits.construct_midpoint_2_object(); - if (a1 != CGAL::OBTUSE && a2 != CGAL::OBTUSE && a3 != CGAL::OBTUSE) { - const auto circumcenter_2 = - traits.construct_circumcenter_2_object(); - center = circumcenter_2(p, q, r); - } else { - center = midpoint_2(r, p); - } + const FT A1 = internal::positive_area_3(q, m1, center, traits); + const FT A2 = internal::positive_area_3(q, center, m2, traits); - const auto m1 = midpoint_2(q, r); - const auto m2 = midpoint_2(q, p); + return A1 + A2; +} - const FT A1 = internal::positive_area_2(traits, q, m1, center); - const FT A2 = internal::positive_area_2(traits, q, center, m2); - return A1 + A2; - } - - template - typename GeomTraits::FT mixed_voronoi_area( - const CGAL::Point_2& p, - const CGAL::Point_2& q, - const CGAL::Point_2& r) { - - const GeomTraits traits; - return mixed_voronoi_area(p, q, r, traits); - } - - template - typename GeomTraits::FT mixed_voronoi_area( - const typename GeomTraits::Point_3& p, - const typename GeomTraits::Point_3& q, - const typename GeomTraits::Point_3& r, - const GeomTraits& traits) { - - using FT = typename GeomTraits::FT; - using Point_3 = typename GeomTraits::Point_3; - - const auto angle_3 = - traits.angle_3_object(); - const auto a1 = angle_3(p, q, r); - const auto a2 = angle_3(q, r, p); - const auto a3 = angle_3(r, p, q); - - Point_3 center; - const auto midpoint_3 = - traits.construct_midpoint_3_object(); - if (a1 != CGAL::OBTUSE && a2 != CGAL::OBTUSE && a3 != CGAL::OBTUSE) { - const auto circumcenter_3 = - traits.construct_circumcenter_3_object(); - center = circumcenter_3(p, q, r); - } else { - center = midpoint_3(r, p); - } - - const auto m1 = midpoint_3(q, r); - const auto m2 = midpoint_3(q, p); - - const FT A1 = internal::positive_area_3(traits, q, m1, center); - const FT A2 = internal::positive_area_3(traits, q, center, m2); - return A1 + A2; - } - - template - typename GeomTraits::FT mixed_voronoi_area( - const CGAL::Point_3& p, - const CGAL::Point_3& q, - const CGAL::Point_3& r) { - - const GeomTraits traits; - return mixed_voronoi_area(p, q, r, traits); - } - /// \endcond +/*! + \ingroup PkgWeightsRefMixedVoronoiRegionWeights + \brief computes the area of the mixed Voronoi cell in 3D using the points `p`, `q`, and `r`. + \tparam Kernel a model of `Kernel` +*/ +template +typename Kernel::FT mixed_voronoi_area(const CGAL::Point_3& p, + const CGAL::Point_3& q, + const CGAL::Point_3& r) +{ + const Kernel traits; + return mixed_voronoi_area(p, q, r, traits); +} } // namespace Weights } // namespace CGAL diff --git a/Weights/include/CGAL/Weights/shepard_weights.h b/Weights/include/CGAL/Weights/shepard_weights.h index 0a9fb5f8494..e510cbd6507 100644 --- a/Weights/include/CGAL/Weights/shepard_weights.h +++ b/Weights/include/CGAL/Weights/shepard_weights.h @@ -14,251 +14,178 @@ #ifndef CGAL_SHEPARD_WEIGHTS_H #define CGAL_SHEPARD_WEIGHTS_H -// Internal includes. #include +#include +#include + namespace CGAL { namespace Weights { - /// \cond SKIP_IN_MANUAL - namespace shepard_ns { +/// \cond SKIP_IN_MANUAL - template - typename GeomTraits::FT weight( - const GeomTraits& traits, - const typename GeomTraits::FT d, - const typename GeomTraits::FT p) { +namespace shepard_ns { - using FT = typename GeomTraits::FT; - FT w = FT(0); - CGAL_precondition(d != FT(0)); - if (d != FT(0)) { - FT denom = d; - if (p != FT(1)) { - denom = internal::power(traits, d, p); - } - w = FT(1) / denom; - } - return w; - } - } - /// \endcond +template +FT weight(const FT d, const FT p) +{ + FT w = FT(0); + CGAL_precondition(is_positive(d)); + if(is_positive(d)) + w = internal::power(d, -p); - #if defined(DOXYGEN_RUNNING) + return w; +} - /*! - \ingroup PkgWeightsRefShepardWeights +} // namespace shepard_ns - \brief computes the Shepard weight in 2D using the points `p` and `q` and the power parameter `a`, - given a traits class `traits` with geometric objects, predicates, and constructions. - */ - template - typename GeomTraits::FT shepard_weight( - const typename GeomTraits::Point_2&, - const typename GeomTraits::Point_2& p, - const typename GeomTraits::Point_2&, - const typename GeomTraits::Point_2& q, - const typename GeomTraits::FT a, - const GeomTraits& traits) { } +/// \endcond - /*! - \ingroup PkgWeightsRefShepardWeights +// 2D ============================================================================================== - \brief computes the Shepard weight in 3D using the points `p` and `q` and the power parameter `a`, - given a traits class `traits` with geometric objects, predicates, and constructions. - */ - template - typename GeomTraits::FT shepard_weight( - const typename GeomTraits::Point_3&, - const typename GeomTraits::Point_3& p, - const typename GeomTraits::Point_3&, - const typename GeomTraits::Point_3& q, - const typename GeomTraits::FT a, - const GeomTraits& traits) { } +/*! + \ingroup PkgWeightsRefShepardWeights + \brief computes the Shepard weight in 2D using the points `p` and `q` and the power parameter `a`. + \tparam GeomTraits a model of `AnalyticWeightTraits_2` +*/ +template +typename GeomTraits::FT shepard_weight(const typename GeomTraits::Point_2&, + const typename GeomTraits::Point_2& p, + const typename GeomTraits::Point_2&, + const typename GeomTraits::Point_2& q, + const typename GeomTraits::FT a, + const GeomTraits& traits) +{ + using FT = typename GeomTraits::FT; + const FT d = internal::distance_2(p, q, traits); + return shepard_ns::weight(d, a); +} - /*! - \ingroup PkgWeightsRefShepardWeights +/*! + \ingroup PkgWeightsRefShepardWeights + \brief computes the Shepard weight in 2D using the points `p` and `q`, and the power parameter `a` + \tparam Kernel a model of `Kernel` +*/ +template +#ifdef DOXYGEN_RUNNING +typename Kernel::FT shepard_weight(const CGAL::Point_2&, + const CGAL::Point_2& p^, + const CGAL::Point_2&, + const CGAL::Point_2& q, + const typename Kernel::FT a = {1}) +#else +typename Kernel::FT shepard_weight(const CGAL::Point_2& stub_l, + const CGAL::Point_2& p, + const CGAL::Point_2& stub_r, + const CGAL::Point_2& q, + const typename Kernel::FT a = {1}) +#endif +{ + const Kernel traits; + return shepard_weight(stub_l, p, stub_r, q, a, traits); +} - \brief computes the Shepard weight in 2D using the points `p` and `q`, - which are parameterized by a `Kernel` K, and the power parameter `a` which - can be omitted. - */ - template - typename K::FT shepard_weight( - const CGAL::Point_2&, - const CGAL::Point_2& p, - const CGAL::Point_2&, - const CGAL::Point_2& q, - const typename K::FT a = typename K::FT(1)) { } +/*! + \ingroup PkgWeightsRefShepardWeights + \brief computes the Shepard weight in 2D using the points `p` and `q` and the power parameter `a`. + \tparam GeomTraits a model of `AnalyticWeightTraits_2` +*/ +template +typename GeomTraits::FT shepard_weight(const typename GeomTraits::Point_2& p, + const typename GeomTraits::Point_2& q, + const typename GeomTraits::FT a, + const GeomTraits& traits) +{ + typename GeomTraits::Point_2 stub; + return shepard_weight(stub, p, stub, q, a, traits); +} - /*! - \ingroup PkgWeightsRefShepardWeights +/*! + \ingroup PkgWeightsRefShepardWeights + \brief computes the Shepard weight in 2D using the points `p` and `q`, and the power parameter `a`. + \tparam Kernel a model of `Kernel` +*/ +template +typename Kernel::FT shepard_weight(const CGAL::Point_2& p, + const CGAL::Point_2& q, + const typename Kernel::FT a = {1}) +{ + CGAL::Point_2 stub; + return shepard_weight(stub, p, stub, q, a); +} - \brief computes the Shepard weight in 3D using the points `p` and `q`, - which are parameterized by a `Kernel` K, and the power parameter `a` which - can be omitted. - */ - template - typename K::FT shepard_weight( - const CGAL::Point_3&, - const CGAL::Point_3& p, - const CGAL::Point_3&, - const CGAL::Point_3& q, - const typename K::FT a = typename K::FT(1)) { } +// 3D ============================================================================================== - /*! - \ingroup PkgWeightsRefShepardWeights +/*! + \ingroup PkgWeightsRefShepardWeights + \brief computes the Shepard weight in 3D using the points `p` and `q` and the power parameter `a`. + \tparam GeomTraits a model of `AnalyticWeightTraits_3` +*/ +template +typename GeomTraits::FT shepard_weight(const typename GeomTraits::Point_3&, + const typename GeomTraits::Point_3& p, + const typename GeomTraits::Point_3&, + const typename GeomTraits::Point_3& q, + const typename GeomTraits::FT a, + const GeomTraits& traits) +{ + using FT = typename GeomTraits::FT; + const FT d = internal::distance_3(p, q, traits); + return shepard_ns::weight(d, a); +} - \brief computes the Shepard weight in 2D using the points `p` and `q` and the power parameter `a`, - given a traits class `traits` with geometric objects, predicates, and constructions. - */ - template - typename GeomTraits::FT shepard_weight( - const typename GeomTraits::Point_2& p, - const typename GeomTraits::Point_2& q, - const typename GeomTraits::FT a, - const GeomTraits& traits) { } +/*! + \ingroup PkgWeightsRefShepardWeights + \brief computes the Shepard weight in 3D using the points `p` and `q`, and the power parameter `a`. + \tparam Kernel a model of `Kernel` +*/ +template +#ifdef DOXYGEN_RUNNING +typename Kernel::FT shepard_weight(const CGAL::Point_3& p, + const CGAL::Point_3&, + const CGAL::Point_3& q, + const CGAL::Point_3&, + const typename Kernel::FT a = {1}) +#else +typename Kernel::FT shepard_weight(const CGAL::Point_3& stub_l, + const CGAL::Point_3& p, + const CGAL::Point_3& stub_r, + const CGAL::Point_3& q, + const typename Kernel::FT a = {1}) +#endif +{ + const Kernel traits; + return shepard_weight(stub_l, p, stub_r, q, a, traits); +} - /*! - \ingroup PkgWeightsRefShepardWeights +/*! + \ingroup PkgWeightsRefShepardWeights + \brief computes the Shepard weight in 3D using the points `p` and `q` and the power parameter `a`. + \tparam GeomTraits a model of `AnalyticWeightTraits_3` +*/ +template +typename GeomTraits::FT shepard_weight(const typename GeomTraits::Point_3& p, + const typename GeomTraits::Point_3& q, + const typename GeomTraits::FT a, + const GeomTraits& traits) +{ + typename GeomTraits::Point_3 stub; + return shepard_weight(stub, p, stub, q, a, traits); +} - \brief computes the Shepard weight in 3D using the points `p` and `q` and the power parameter `a`, - given a traits class `traits` with geometric objects, predicates, and constructions. - */ - template - typename GeomTraits::FT shepard_weight( - const typename GeomTraits::Point_3& p, - const typename GeomTraits::Point_3& q, - const typename GeomTraits::FT a, - const GeomTraits& traits) { } - - /*! - \ingroup PkgWeightsRefShepardWeights - - \brief computes the Shepard weight in 2D using the points `p` and `q`, - which are parameterized by a `Kernel` K, and the power parameter `a` which - can be omitted. - */ - template - typename K::FT shepard_weight( - const CGAL::Point_2& p, - const CGAL::Point_2& q, - const typename K::FT a = typename K::FT(1)) { } - - /*! - \ingroup PkgWeightsRefShepardWeights - - \brief computes the Shepard weight in 3D using the points `p` and `q`, - which are parameterized by a `Kernel` K, and the power parameter `a` which - can be omitted. - */ - template - typename K::FT shepard_weight( - const CGAL::Point_3& p, - const CGAL::Point_3& q, - const typename K::FT a = typename K::FT(1)) { } - - #endif // DOXYGEN_RUNNING - - /// \cond SKIP_IN_MANUAL - template - typename GeomTraits::FT shepard_weight( - const typename GeomTraits::Point_2&, - const typename GeomTraits::Point_2& r, - const typename GeomTraits::Point_2&, - const typename GeomTraits::Point_2& q, - const typename GeomTraits::FT a, - const GeomTraits& traits) { - - using FT = typename GeomTraits::FT; - const FT d = internal::distance_2(traits, q, r); - return shepard_ns::weight(traits, d, a); - } - - template - typename GeomTraits::FT shepard_weight( - const CGAL::Point_2& t, - const CGAL::Point_2& r, - const CGAL::Point_2& p, - const CGAL::Point_2& q, - const typename GeomTraits::FT a = - typename GeomTraits::FT(1)) { - - const GeomTraits traits; - return shepard_weight(t, r, p, q, a, traits); - } - - template - typename GeomTraits::FT shepard_weight( - const typename GeomTraits::Point_2& p, - const typename GeomTraits::Point_2& q, - const typename GeomTraits::FT a, - const GeomTraits& traits) { - - typename GeomTraits::Point_2 stub; - return shepard_weight(stub, p, stub, q, a, traits); - } - - template - typename GeomTraits::FT shepard_weight( - const CGAL::Point_2& p, - const CGAL::Point_2& q, - const typename GeomTraits::FT a = - typename GeomTraits::FT(1)) { - - CGAL::Point_2 stub; - return shepard_weight(stub, p, stub, q, a); - } - - template - typename GeomTraits::FT shepard_weight( - const typename GeomTraits::Point_3&, - const typename GeomTraits::Point_3& r, - const typename GeomTraits::Point_3&, - const typename GeomTraits::Point_3& q, - const typename GeomTraits::FT a, - const GeomTraits& traits) { - - using FT = typename GeomTraits::FT; - const FT d = internal::distance_3(traits, q, r); - return shepard_ns::weight(traits, d, a); - } - - template - typename GeomTraits::FT shepard_weight( - const CGAL::Point_3& t, - const CGAL::Point_3& r, - const CGAL::Point_3& p, - const CGAL::Point_3& q, - const typename GeomTraits::FT a = - typename GeomTraits::FT(1)) { - - const GeomTraits traits; - return shepard_weight(t, r, p, q, a, traits); - } - - template - typename GeomTraits::FT shepard_weight( - const typename GeomTraits::Point_3& p, - const typename GeomTraits::Point_3& q, - const typename GeomTraits::FT a, - const GeomTraits& traits) { - - typename GeomTraits::Point_3 stub; - return shepard_weight(stub, p, stub, q, a, traits); - } - - template - typename GeomTraits::FT shepard_weight( - const CGAL::Point_3& p, - const CGAL::Point_3& q, - const typename GeomTraits::FT a = - typename GeomTraits::FT(1)) { - - CGAL::Point_3 stub; - return shepard_weight(stub, p, stub, q, a); - } - /// \endcond +/*! + \ingroup PkgWeightsRefShepardWeights + \brief computes the Shepard weight in 3D using the points `p` and `q`, and the power parameter `a`. + \tparam Kernel a model of `Kernel` +*/ +template +typename Kernel::FT shepard_weight(const CGAL::Point_3& p, + const CGAL::Point_3& q, + const typename Kernel::FT a = {1}) +{ + CGAL::Point_3 stub; + return shepard_weight(stub, p, stub, q, a); +} } // namespace Weights } // namespace CGAL diff --git a/Weights/include/CGAL/Weights/tangent_weights.h b/Weights/include/CGAL/Weights/tangent_weights.h index da4c87d0fdd..7788a961218 100644 --- a/Weights/include/CGAL/Weights/tangent_weights.h +++ b/Weights/include/CGAL/Weights/tangent_weights.h @@ -14,495 +14,507 @@ #ifndef CGAL_TANGENT_WEIGHTS_H #define CGAL_TANGENT_WEIGHTS_H -// Internal includes. -#include +#include + +#include +#include + +#include namespace CGAL { namespace Weights { - /// \cond SKIP_IN_MANUAL - namespace tangent_ns { +/// \cond SKIP_IN_MANUAL - template - FT half_angle_tangent(const FT r, const FT d, const FT A, const FT D) { +namespace tangent_ns { - FT t = FT(0); - const FT P = r * d + D; - CGAL_precondition(P != FT(0)); - if (P != FT(0)) { - const FT inv = FT(2) / P; - t = A * inv; - } - return t; - } +template +FT half_weight(const FT t, const FT r) +{ + FT w = FT(0); + CGAL_precondition(!is_zero(r)); + if (!is_zero(r)) + w = FT(2) * t / r; - template - FT half_weight(const FT t, const FT r) { + return w; +} - FT w = FT(0); - CGAL_precondition(r != FT(0)); - if (r != FT(0)) { - const FT inv = FT(2) / r; - w = t * inv; - } - return w; - } +template +FT weight(const FT t0, const FT t2, const FT r) +{ + FT w = FT(0); + CGAL_precondition(r != FT(0)); + if (r != FT(0)) + w = FT(2) * (t0 + t2) / r; - template - FT weight(const FT t1, const FT t2, const FT r) { + return w; +} - FT w = FT(0); - CGAL_precondition(r != FT(0)); - if (r != FT(0)) { - const FT inv = FT(2) / r; - w = (t1 + t2) * inv; - } - return w; - } +template +FT weight(const FT d0, const FT d2, const FT d, + const FT A0, const FT A2, + const FT D0, const FT D2) +{ + const FT P0 = d * d0 + D0; + const FT P2 = d * d2 + D2; - template - FT weight( - const FT d1, const FT r, const FT d2, - const FT A1, const FT A2, - const FT D1, const FT D2) { - - const FT P1 = d1 * r + D1; - const FT P2 = d2 * r + D2; - - FT w = FT(0); - CGAL_precondition(P1 != FT(0) && P2 != FT(0)); - if (P1 != FT(0) && P2 != FT(0)) { - const FT inv1 = FT(2) / P1; - const FT inv2 = FT(2) / P2; - const FT t1 = A1 * inv1; - const FT t2 = A2 * inv2; - w = weight(t1, t2, r); - } - return w; - } - - // This is positive case only. - // This version is based on the positive area. - // This version is more precise for all positive cases. - template - typename GeomTraits::FT tangent_weight_v1( - const typename GeomTraits::Point_3& t, - const typename GeomTraits::Point_3& r, - const typename GeomTraits::Point_3& p, - const typename GeomTraits::Point_3& q, - const GeomTraits& traits) { - - using FT = typename GeomTraits::FT; - const auto dot_product_3 = - traits.compute_scalar_product_3_object(); - const auto construct_vector_3 = - traits.construct_vector_3_object(); - - const auto v1 = construct_vector_3(q, t); - const auto v2 = construct_vector_3(q, r); - const auto v3 = construct_vector_3(q, p); - - const FT l1 = internal::length_3(traits, v1); - const FT l2 = internal::length_3(traits, v2); - const FT l3 = internal::length_3(traits, v3); - - const FT A1 = internal::positive_area_3(traits, r, q, t); - const FT A2 = internal::positive_area_3(traits, p, q, r); - - const FT D1 = dot_product_3(v1, v2); - const FT D2 = dot_product_3(v2, v3); - - return weight(l1, l2, l3, A1, A2, D1, D2); - } - - // This version handles both positive and negative cases. - // However, it is less precise. - template - typename GeomTraits::FT tangent_weight_v2( - const typename GeomTraits::Point_3& t, - const typename GeomTraits::Point_3& r, - const typename GeomTraits::Point_3& p, - const typename GeomTraits::Point_3& q, - const GeomTraits& traits) { - - using FT = typename GeomTraits::FT; - const auto construct_vector_3 = - traits.construct_vector_3_object(); - - auto v1 = construct_vector_3(q, t); - auto v2 = construct_vector_3(q, r); - auto v3 = construct_vector_3(q, p); - - const FT l2 = internal::length_3(traits, v2); - - internal::normalize_3(traits, v1); - internal::normalize_3(traits, v2); - internal::normalize_3(traits, v3); - - const double ha_rad_1 = internal::angle_3(traits, v1, v2) / 2.0; - const double ha_rad_2 = internal::angle_3(traits, v2, v3) / 2.0; - const FT t1 = static_cast(std::tan(ha_rad_1)); - const FT t2 = static_cast(std::tan(ha_rad_2)); - - return weight(t1, t2, l2); - } - } - /// \endcond - - /*! - \ingroup PkgWeightsRefTangentWeights - - \brief computes the tangent of the half angle. - - This function computes the tangent of the half angle using the precomputed - distance, area, and dot product values. The returned value is - \f$\frac{2\textbf{A}}{\textbf{d}\textbf{l} + \textbf{D}}\f$. - - \tparam FT - a model of `FieldNumberType` - - \param d - the distance value - - \param l - the distance value - - \param A - the area value - - \param D - the dot product value - - \pre (d * l + D) != 0 - - \sa `half_tangent_weight()` - */ - template - FT tangent_half_angle(const FT d, const FT l, const FT A, const FT D) { - return tangent_ns::half_angle_tangent(d, l, A, D); + FT w = FT(0); + CGAL_precondition(!is_zero(P0) && !is_zero(P2)); + if (!is_zero(P0) && !is_zero(P2)) + { + const FT t0 = FT(2) * A0 / P0; + const FT t2 = FT(2) * A2 / P2; + w = weight(t0, t2, d); } - /*! - \ingroup PkgWeightsRefTangentWeights + return w; +} - \brief computes the half value of the tangent weight. +// This is positive case only. +// This version is based on the positive area. +// This version is more precise for all positive cases. +template +typename GeomTraits::FT tangent_weight_v1(const typename GeomTraits::Point_3& p0, + const typename GeomTraits::Point_3& p1, + const typename GeomTraits::Point_3& p2, + const typename GeomTraits::Point_3& q, + const GeomTraits& traits) +{ + using FT = typename GeomTraits::FT; + using Vector_3 = typename GeomTraits::Vector_3; - This function constructs the half of the tangent weight using the precomputed - half angle tangent and distance values. The returned value is - \f$\frac{2\textbf{tan05}}{\textbf{d}}\f$. + auto dot_product_3 = traits.compute_scalar_product_3_object(); + auto vector_3 = traits.construct_vector_3_object(); - \tparam FT - a model of `FieldNumberType` + const Vector_3 v0 = vector_3(q, p0); + const Vector_3 v = vector_3(q, p1); + const Vector_3 v2 = vector_3(q, p2); - \param tan05 - the half angle tangent value + const FT d0 = internal::length_3(v0, traits); + const FT d = internal::length_3(v, traits); + const FT d2 = internal::length_3(v2, traits); - \param d - the distance value + const FT A0 = internal::positive_area_3(p1, q, p0, traits); + const FT A2 = internal::positive_area_3(p2, q, p1, traits); - \pre d != 0 + const FT D0 = dot_product_3(v0, v); + const FT D2 = dot_product_3(v, v2); - \sa `tangent_half_angle()` - \sa `tangent_weight()` - */ - template - FT half_tangent_weight(const FT tan05, const FT d) { - return tangent_ns::half_weight(tan05, d); - } + return weight(d0, d2, d, A0, A2, D0, D2); +} - /*! - \ingroup PkgWeightsRefTangentWeights +// This version handles both positive and negative cases. +// However, it is less precise. +template +typename GeomTraits::FT tangent_weight_v2(const typename GeomTraits::Point_3& p0, + const typename GeomTraits::Point_3& p1, + const typename GeomTraits::Point_3& p2, + const typename GeomTraits::Point_3& q, + const GeomTraits& traits) +{ + using FT = typename GeomTraits::FT; + using Vector_3 = typename GeomTraits::Vector_3; - \brief computes the half value of the tangent weight. + auto vector_3 = traits.construct_vector_3_object(); - This function constructs the half of the tangent weight using the precomputed - distance, area, and dot product values. The returned value is - \f$\frac{2\textbf{t}}{\textbf{d}}\f$ where - \f$\textbf{t} = \frac{2\textbf{A}}{\textbf{d}\textbf{l} + \textbf{D}}\f$. + Vector_3 v0 = vector_3(q, p0); + Vector_3 v = vector_3(q, p1); + Vector_3 v2 = vector_3(q, p2); - \tparam FT - a model of `FieldNumberType` + const FT l2 = internal::length_3(v, traits); - \param d - the distance value + const double ha_rad_1 = internal::angle_3(v0, v, traits) / 2.0; + const double ha_rad_2 = internal::angle_3(v, v2, traits) / 2.0; + const FT t0 = static_cast(std::tan(ha_rad_1)); + const FT t2 = static_cast(std::tan(ha_rad_2)); - \param l - the distance value + return weight(t0, t2, l2); +} - \param A - the area value +} // namespace tangent_ns - \param D - the dot product value +/// \endcond - \pre (d * l + D) != 0 && d != 0 +// 2D ============================================================================================== - \sa `tangent_weight()` - */ - template - FT half_tangent_weight(const FT d, const FT l, const FT A, const FT D) { - const FT tan05 = tangent_half_angle(d, l, A, D); - return half_tangent_weight(tan05, d); - } +/*! + \ingroup PkgWeightsRefTangentWeights - #if defined(DOXYGEN_RUNNING) + \brief computes the half value of the tangent weight. - /*! - \ingroup PkgWeightsRefTangentWeights + This function constructs the half of the tangent weight using the precomputed + half angle tangent and distance values. The returned value is + \f$\frac{2\textbf{tan05}}{\textbf{d}}\f$. - \brief computes the tangent weight in 2D at `q` using the points `p0`, `p1`, - and `p2`, given a traits class `traits` with geometric objects, predicates, and constructions. - */ - template - typename GeomTraits::FT tangent_weight( - const typename GeomTraits::Point_2& p0, - const typename GeomTraits::Point_2& p1, - const typename GeomTraits::Point_2& p2, - const typename GeomTraits::Point_2& q, - const GeomTraits& traits) { } + \tparam FT a model of `FieldNumberType` - /*! - \ingroup PkgWeightsRefTangentWeights + \param tan05 the half angle tangent value + \param d the distance value - \brief computes the tangent weight in 3D at `q` using the points `p0`, `p1`, - and `p2`, given a traits class `traits` with geometric objects, predicates, and constructions. - */ - template - typename GeomTraits::FT tangent_weight( - const typename GeomTraits::Point_3& p0, - const typename GeomTraits::Point_3& p1, - const typename GeomTraits::Point_3& p2, - const typename GeomTraits::Point_3& q, - const GeomTraits& traits) { } + \pre d != 0 - /*! - \ingroup PkgWeightsRefTangentWeights + \sa `tangent_half_angle()` + \sa `tangent_weight()` +*/ +template +FT half_tangent_weight(const FT tan05, const FT d) +{ + return tangent_ns::half_weight(tan05, d); +} - \brief computes the tangent weight in 2D at `q` using the points `p0`, `p1`, - and `p2` which are parameterized by a `Kernel` K. - */ - template - typename K::FT tangent_weight( - const CGAL::Point_2& p0, - const CGAL::Point_2& p1, - const CGAL::Point_2& p2, - const CGAL::Point_2& q) { } +/*! + \ingroup PkgWeightsRefTangentWeights - /*! - \ingroup PkgWeightsRefTangentWeights + \brief computes the tangent of the half angle. - \brief computes the tangent weight in 3D at `q` using the points `p0`, `p1`, - and `p2` which are parameterized by a `Kernel` K. - */ - template - typename K::FT tangent_weight( - const CGAL::Point_3& p0, - const CGAL::Point_3& p1, - const CGAL::Point_3& p2, - const CGAL::Point_3& q) { } + This function computes the tangent of the half angle using the precomputed + distance, area, and dot product values. The returned value is + \f$\frac{2\textbf{A}}{\textbf{d}\textbf{l} + \textbf{D}}\f$. - #endif // DOXYGEN_RUNNING + \tparam FT a model of `FieldNumberType` - /// \cond SKIP_IN_MANUAL - template - typename GeomTraits::FT tangent_weight( - const typename GeomTraits::Point_2& t, - const typename GeomTraits::Point_2& r, - const typename GeomTraits::Point_2& p, - const typename GeomTraits::Point_2& q, - const GeomTraits& traits) { + \param d the distance value + \param l the distance value + \param A the area value + \param D the dot product value - using FT = typename GeomTraits::FT; - const auto dot_product_2 = - traits.compute_scalar_product_2_object(); - const auto construct_vector_2 = - traits.construct_vector_2_object(); + \pre (d * l + D) != 0 - const auto v1 = construct_vector_2(q, t); - const auto v2 = construct_vector_2(q, r); - const auto v3 = construct_vector_2(q, p); + \sa `half_tangent_weight()` +*/ +template +FT tangent_half_angle(const FT d, const FT l, const FT A, const FT D) +{ + // tan(theta/2) = sin(theta) / ( 1 + cos(theta) ), also = (1 - cos(theta)) / sin(theta). + // = ( 2*A / |v1|*|v2| ) / ( 1 + v1.v2 / |v1|*|v2| ) + // = 2*A / ( |v1|*|v2| + v1.v2 ) - const FT l1 = internal::length_2(traits, v1); - const FT l2 = internal::length_2(traits, v2); - const FT l3 = internal::length_2(traits, v3); + FT t = FT(0); + const FT P = d * l + D; + CGAL_precondition(!is_zero(P)); + if (!is_zero(P)) + t = FT(2) * A / P; - const FT A1 = internal::area_2(traits, r, q, t); - const FT A2 = internal::area_2(traits, p, q, r); + return t; +} - const FT D1 = dot_product_2(v1, v2); - const FT D2 = dot_product_2(v2, v3); +/*! + \ingroup PkgWeightsRefTangentWeights - return tangent_ns::weight( - l1, l2, l3, A1, A2, D1, D2); - } + \brief computes the half value of the tangent weight. - template - typename GeomTraits::FT tangent_weight( - const CGAL::Point_2& t, - const CGAL::Point_2& r, - const CGAL::Point_2& p, - const CGAL::Point_2& q) { + This function constructs the half of the tangent weight using the precomputed + distance, area, and dot product values. The returned value is + \f$\frac{2\textbf{t}}{\textbf{d}}\f$ where + \f$\textbf{t} = \frac{2\textbf{A}}{\textbf{d}\textbf{l} + \textbf{D}}\f$. - const GeomTraits traits; - return tangent_weight(t, r, p, q, traits); - } + \tparam FT a model of `FieldNumberType` - template - typename GeomTraits::FT tangent_weight( - const typename GeomTraits::Point_3& t, - const typename GeomTraits::Point_3& r, - const typename GeomTraits::Point_3& p, - const typename GeomTraits::Point_3& q, - const GeomTraits& traits) { + \param d the distance value + \param l the distance value + \param A the area value + \param D the dot product value - // return tangent_ns::tangent_weight_v1(t, r, p, q, traits); - return tangent_ns::tangent_weight_v2(t, r, p, q, traits); - } + \pre (d * l + D) != 0 && d != 0 - template - typename GeomTraits::FT tangent_weight( - const CGAL::Point_3& t, - const CGAL::Point_3& r, - const CGAL::Point_3& p, - const CGAL::Point_3& q) { + \sa `tangent_weight()` +*/ +template +FT half_tangent_weight(const FT d, const FT l, const FT A, const FT D) +{ + const FT tan05 = tangent_half_angle(d, l, A, D); + return tangent_ns::half_weight(tan05, d); +} - const GeomTraits traits; - return tangent_weight(t, r, p, q, traits); - } +/// \cond SKIP_IN_MANUAL - // Undocumented tangent weight class. - // Its constructor takes a polygon mesh and a vertex to point map - // and its operator() is defined based on the halfedge_descriptor only. - // This version is currently used in: - // Surface_mesh_parameterizer -> Iterative_authalic_parameterizer_3.h - template< - typename PolygonMesh, - typename VertexPointMap = typename boost::property_map::type> - class Edge_tangent_weight { +template +typename GeomTraits::FT half_tangent_weight(const typename GeomTraits::Point_2& p0, + const typename GeomTraits::Point_2& q, + const typename GeomTraits::Point_2& p2, + const GeomTraits& traits) +{ + using FT = typename GeomTraits::FT; + using Vector_2 = typename GeomTraits::Vector_2; - using GeomTraits = typename CGAL::Kernel_traits< - typename boost::property_traits::value_type>::type; - using FT = typename GeomTraits::FT; + auto vector_2 = traits.construct_vector_2_object(); + auto dot_product_2 = traits.compute_scalar_product_2_object(); + auto area_2 = traits.compute_area_2_object(); - const PolygonMesh& m_pmesh; - const VertexPointMap m_pmap; - const GeomTraits m_traits; + const Vector_2 v0 = vector_2(q, p0); + const Vector_2 v2 = vector_2(q, p2); - public: - using vertex_descriptor = typename boost::graph_traits::vertex_descriptor; - using halfedge_descriptor = typename boost::graph_traits::halfedge_descriptor; + const FT l0 = internal::length_2(v0, traits); + const FT l2 = internal::length_2(v2, traits); + const FT A = area_2(p2, q, p0); + const FT D = dot_product_2(v0, v2); - Edge_tangent_weight(const PolygonMesh& pmesh, const VertexPointMap pmap) : - m_pmesh(pmesh), m_pmap(pmap), m_traits() { } + return half_tangent_weight(l0, l2, A, D); +} - FT operator()(const halfedge_descriptor he) const { +template +typename GeomTraits::FT half_tangent_weight(const typename GeomTraits::Point_3& p0, + const typename GeomTraits::Point_3& q, + const typename GeomTraits::Point_3& p2, + const GeomTraits& traits) +{ + using FT = typename GeomTraits::FT; + using Vector_3 = typename GeomTraits::Vector_3; - FT weight = FT(0); - if (is_border_edge(he, m_pmesh)) { - const auto h1 = next(he, m_pmesh); + auto vector_3 = traits.construct_vector_3_object(); + auto dot_product_3 = traits.compute_scalar_product_3_object(); - const auto v0 = target(he, m_pmesh); - const auto v1 = source(he, m_pmesh); - const auto v2 = target(h1, m_pmesh); + const Vector_3 v0 = vector_3(q, p0); + const Vector_3 v2 = vector_3(q, p2); - const auto& p0 = get(m_pmap, v0); - const auto& p1 = get(m_pmap, v1); - const auto& p2 = get(m_pmap, v2); + const FT l0 = internal::length_3(v0, traits); + const FT l2 = internal::length_3(v2, traits); + const FT A = internal::area_3(p2, q, p0, traits); + const FT D = dot_product_3(v0, v2); - weight = internal::tangent_3(m_traits, p0, p2, p1); + return half_tangent_weight(l0, l2, A, D); +} - } else { - const auto h1 = next(he, m_pmesh); - const auto h2 = prev(opposite(he, m_pmesh), m_pmesh); +/// \endcond - const auto v0 = target(he, m_pmesh); - const auto v1 = source(he, m_pmesh); - const auto v2 = target(h1, m_pmesh); - const auto v3 = source(h2, m_pmesh); +// 2D ============================================================================================== - const auto& p0 = get(m_pmap, v0); - const auto& p1 = get(m_pmap, v1); - const auto& p2 = get(m_pmap, v2); - const auto& p3 = get(m_pmap, v3); +/*! + \ingroup PkgWeightsRefTangentWeights + \brief computes the tangent weight in 2D at `q` using the points `p0`, `p1`, and `p2` + \tparam GeomTraits a model of `AnalyticWeightTraits_2` +*/ +template +typename GeomTraits::FT tangent_weight(const typename GeomTraits::Point_2& p0, + const typename GeomTraits::Point_2& p1, + const typename GeomTraits::Point_2& p2, + const typename GeomTraits::Point_2& q, + const GeomTraits& traits) +{ + using FT = typename GeomTraits::FT; + using Vector_2 = typename GeomTraits::Vector_2; - weight = tangent_weight(p2, p1, p3, p0) / FT(2); - } - return weight; + auto vector_2 = traits.construct_vector_2_object(); + auto dot_product_2 = traits.compute_scalar_product_2_object(); + auto area_2 = traits.compute_area_2_object(); + + const Vector_2 v0 = vector_2(q, p0); + const Vector_2 v = vector_2(q, p1); + const Vector_2 v2 = vector_2(q, p2); + + const FT l0 = internal::length_2(v0, traits); + const FT l = internal::length_2(v, traits); + const FT l2 = internal::length_2(v2, traits); + + const FT A0 = area_2(p1, q, p0); + const FT A2 = area_2(p2, q, p1); + + const FT D0 = dot_product_2(v0, v); + const FT D2 = dot_product_2(v, v2); + + return tangent_ns::weight(l0, l2, l, A0, A2, D0, D2); +} + +/*! + \ingroup PkgWeightsRefTangentWeights + \brief computes the tangent weight in 2D at `q` using the points `p0`, `p1`, and `p2` + \tparam Kernel a model of `Kernel` +*/ +template +typename Kernel::FT tangent_weight(const CGAL::Point_2& p0, + const CGAL::Point_2& p1, + const CGAL::Point_2& p2, + const CGAL::Point_2& q) +{ + const Kernel traits; + return tangent_weight(p0, p1, p2, q, traits); +} + +// 3D ============================================================================================== + +/*! + \ingroup PkgWeightsRefTangentWeights + \brief computes the tangent weight in 3D at `q` using the points `p0`, `p1`, and `p2` + \tparam GeomTraits a model of `AnalyticWeightTraits_3` +*/ +template +typename GeomTraits::FT tangent_weight(const typename GeomTraits::Point_3& p0, + const typename GeomTraits::Point_3& p1, + const typename GeomTraits::Point_3& p2, + const typename GeomTraits::Point_3& q, + const GeomTraits& traits) +{ +// return tangent_ns::tangent_weight_v1(p0, p1, p2, q, traits); + return tangent_ns::tangent_weight_v2(p0, p1, p2, q, traits); +} + +/*! + \ingroup PkgWeightsRefTangentWeights + \brief computes the tangent weight in 3D at `q` using the points `p0`, `p1`, and `p2` + \tparam Kernel a model of `Kernel` +*/ +template +typename Kernel::FT tangent_weight(const CGAL::Point_3& p0, + const CGAL::Point_3& p1, + const CGAL::Point_3& p2, + const CGAL::Point_3& q) +{ + const Kernel traits; + return tangent_weight(p0, p1, p2, q, traits); +} + +/// \cond SKIP_IN_MANUAL + +// Undocumented tangent weight class. +// +// Its constructor takes a polygon mesh and a vertex to point map +// and its operator() is defined based on the halfedge_descriptor only. +// This version is currently used in: +// Surface_mesh_parameterizer -> Iterative_authalic_parameterizer_3.h +template< + typename PolygonMesh, + typename VertexPointMap, + typename GeomTraits> +class Edge_tangent_weight +{ + using vertex_descriptor = typename boost::graph_traits::vertex_descriptor; + using halfedge_descriptor = typename boost::graph_traits::halfedge_descriptor; + + using Point_ref = typename boost::property_traits::reference; + using FT = typename GeomTraits::FT; + + const PolygonMesh& m_pmesh; + const VertexPointMap m_pmap; + const GeomTraits m_traits; + +public: + + Edge_tangent_weight(const PolygonMesh& pmesh, + const VertexPointMap pmap, + const GeomTraits& traits) + : m_pmesh(pmesh), m_pmap(pmap), m_traits(traits) + { } + + FT operator()(halfedge_descriptor he) const + { + if(is_border(he, m_pmesh)) + return FT(0); + + FT weight = FT(0); + if (is_border_edge(he, m_pmesh)) // ie, opp(he, pmesh) is a border halfedge + { + const halfedge_descriptor h1 = next(he, m_pmesh); + + const vertex_descriptor v0 = target(he, m_pmesh); + const vertex_descriptor v1 = source(he, m_pmesh); + const vertex_descriptor v2 = target(h1, m_pmesh); + + const Point_ref p0 = get(m_pmap, v0); + const Point_ref p1 = get(m_pmap, v1); + const Point_ref p2 = get(m_pmap, v2); + + weight = half_tangent_weight(p1, p0, p2, m_traits) / FT(2); } - }; + else + { + const halfedge_descriptor h1 = next(he, m_pmesh); + const halfedge_descriptor h2 = prev(opposite(he, m_pmesh), m_pmesh); - // Undocumented tangent weight class. - // Its constructor takes three points either in 2D or 3D. - // This version is currently used in: - // Surface_mesh_parameterizer -> MVC_post_processor_3.h - // Surface_mesh_parameterizer -> Orbifold_Tutte_parameterizer_3.h - template - class Tangent_weight { - FT m_d_r, m_d_p, m_w_base; + const vertex_descriptor v0 = target(he, m_pmesh); + const vertex_descriptor v1 = source(he, m_pmesh); + const vertex_descriptor v2 = target(h1, m_pmesh); + const vertex_descriptor v3 = source(h2, m_pmesh); - public: - template - Tangent_weight( - const CGAL::Point_2& p, - const CGAL::Point_2& q, - const CGAL::Point_2& r) { + const Point_ref p0 = get(m_pmap, v0); + const Point_ref p1 = get(m_pmap, v1); + const Point_ref p2 = get(m_pmap, v2); + const Point_ref p3 = get(m_pmap, v3); - const GeomTraits traits; - const auto scalar_product_2 = - traits.compute_scalar_product_2_object(); - const auto construct_vector_2 = - traits.construct_vector_2_object(); - - m_d_r = internal::distance_2(traits, q, r); - CGAL_assertion(m_d_r != FT(0)); // two points are identical! - m_d_p = internal::distance_2(traits, q, p); - CGAL_assertion(m_d_p != FT(0)); // two points are identical! - - const auto v1 = construct_vector_2(q, r); - const auto v2 = construct_vector_2(q, p); - - const auto A = internal::positive_area_2(traits, p, q, r); - CGAL_assertion(A != FT(0)); // three points are identical! - const auto S = scalar_product_2(v1, v2); - m_w_base = -tangent_half_angle(m_d_r, m_d_p, A, S); + weight = tangent_weight(p2, p1, p3, p0, m_traits) / FT(2); } + return weight; + } +}; - template - Tangent_weight( - const CGAL::Point_3& p, - const CGAL::Point_3& q, - const CGAL::Point_3& r) { +// Undocumented tangent weight class. +// Returns - std::tan(theta/2); uses positive areas. +// +// Its constructor takes three points either in 2D or 3D. +// This version is currently used in: +// Surface_mesh_parameterizer -> MVC_post_processor_3.h +// Surface_mesh_parameterizer -> Orbifold_Tutte_parameterizer_3.h +template +class Tangent_weight +{ + FT m_d_r, m_d_p, m_w_base; - const GeomTraits traits; - const auto scalar_product_3 = - traits.compute_scalar_product_3_object(); - const auto construct_vector_3 = - traits.construct_vector_3_object(); +public: + template + Tangent_weight(const CGAL::Point_2& p, + const CGAL::Point_2& q, + const CGAL::Point_2& r) + { + const Kernel traits; - m_d_r = internal::distance_3(traits, q, r); - CGAL_assertion(m_d_r != FT(0)); // two points are identical! - m_d_p = internal::distance_3(traits, q, p); - CGAL_assertion(m_d_p != FT(0)); // two points are identical! + using Vector_2 = typename Kernel::Vector_2; - const auto v1 = construct_vector_3(q, r); - const auto v2 = construct_vector_3(q, p); + auto vector_2 = traits.construct_vector_2_object(); + auto scalar_product_2 = traits.compute_scalar_product_2_object(); - const auto A = internal::positive_area_3(traits, p, q, r); - CGAL_assertion(A != FT(0)); // three points are identical! - const auto S = scalar_product_3(v1, v2); - m_w_base = -tangent_half_angle(m_d_r, m_d_p, A, S); - } + m_d_r = internal::distance_2(q, r, traits); + CGAL_assertion(is_positive(m_d_r)); // two points are identical! + m_d_p = internal::distance_2(q, p, traits); + CGAL_assertion(is_positive(m_d_p)); // two points are identical! - FT get_w_r() const { - return half_tangent_weight(m_w_base, m_d_r) / FT(2); - } + const Vector_2 v1 = vector_2(q, r); + const Vector_2 v2 = vector_2(q, p); - FT get_w_p() const { - return half_tangent_weight(m_w_base, m_d_p) / FT(2); - } - }; + const FT A = internal::positive_area_2(p, q, r, traits); + CGAL_assertion(!is_zero(A)); - /// \endcond + const FT S = scalar_product_2(v1, v2); + m_w_base = -tangent_half_angle(m_d_r, m_d_p, A, S); + } + + template + Tangent_weight(const CGAL::Point_3& p, + const CGAL::Point_3& q, + const CGAL::Point_3& r) + { + const Kernel traits; + + using Vector_3 = typename Kernel::Vector_3; + + auto vector_3 = traits.construct_vector_3_object(); + auto scalar_product_3 = traits.compute_scalar_product_3_object(); + + m_d_r = internal::distance_3(q, r, traits); + CGAL_assertion(is_positive(m_d_r)); // two points are identical! + m_d_p = internal::distance_3(q, p, traits); + CGAL_assertion(is_positive(m_d_p)); // two points are identical! + + const Vector_3 v1 = vector_3(q, r); + const Vector_3 v2 = vector_3(q, p); + + const FT A = internal::positive_area_3(p, q, r, traits); + CGAL_assertion(is_positive(A)); + + const FT S = scalar_product_3(v1, v2); + m_w_base = -tangent_half_angle(m_d_r, m_d_p, A, S); + } + + FT get_w_r() const + { + return half_tangent_weight(m_w_base, m_d_r) / FT(2); + } + + FT get_w_p() const + { + return half_tangent_weight(m_w_base, m_d_p) / FT(2); + } +}; + +/// \endcond } // namespace Weights } // namespace CGAL diff --git a/Weights/include/CGAL/Weights/three_point_family_weights.h b/Weights/include/CGAL/Weights/three_point_family_weights.h index eca32f1b281..51bdf0eeb51 100644 --- a/Weights/include/CGAL/Weights/three_point_family_weights.h +++ b/Weights/include/CGAL/Weights/three_point_family_weights.h @@ -14,155 +14,122 @@ #ifndef CGAL_THREE_POINT_FAMILY_WEIGHTS_H #define CGAL_THREE_POINT_FAMILY_WEIGHTS_H -// Internal includes. #include +#include +#include + namespace CGAL { namespace Weights { - /// \cond SKIP_IN_MANUAL - namespace three_point_family_ns { +/// \cond SKIP_IN_MANUAL +namespace three_point_family_ns { - template - typename GeomTraits::FT weight( - const GeomTraits& traits, - const typename GeomTraits::FT d1, - const typename GeomTraits::FT d2, - const typename GeomTraits::FT d3, - const typename GeomTraits::FT A1, - const typename GeomTraits::FT A2, - const typename GeomTraits::FT B, - const typename GeomTraits::FT p) { +template +FT weight(const FT d0, const FT d2, const FT d, + const FT A0, const FT A2, const FT B, + const FT p) +{ + FT w = FT(0); + CGAL_precondition(!is_zero(A0) && !is_zero(A2)); + const FT prod = A0 * A2; + if (!is_zero(prod)) + { + const FT r0 = internal::power(d0, p); + const FT r = internal::power(d , p); + const FT r2 = internal::power(d2, p); - using FT = typename GeomTraits::FT; - FT w = FT(0); - CGAL_precondition(A1 != FT(0) && A2 != FT(0)); - const FT prod = A1 * A2; - if (prod != FT(0)) { - const FT inv = FT(1) / prod; - FT r1 = d1; - FT r2 = d2; - FT r3 = d3; - if (p != FT(1)) { - r1 = internal::power(traits, d1, p); - r2 = internal::power(traits, d2, p); - r3 = internal::power(traits, d3, p); - } - w = (r3 * A1 - r2 * B + r1 * A2) * inv; - } - return w; - } + w = (r2 * A0 - r * B + r0 * A2) / prod; } - /// \endcond + return w; +} - #if defined(DOXYGEN_RUNNING) +} // namespace three_point_family_ns - /*! - \ingroup PkgWeightsRefThreePointFamilyWeights +/// \endcond - \brief computes the three-point family weight in 2D at `q` using the points `p0`, `p1`, - and `p2` and the power parameter `a`, given a traits class `traits` with geometric objects, - predicates, and constructions. - */ - template - typename GeomTraits::FT three_point_family_weight( - const typename GeomTraits::Point_2& p0, - const typename GeomTraits::Point_2& p1, - const typename GeomTraits::Point_2& p2, - const typename GeomTraits::Point_2& q, - const typename GeomTraits::FT a, - const GeomTraits& traits) { } +// 2D ============================================================================================== - /*! - \ingroup PkgWeightsRefThreePointFamilyWeights +/*! + \ingroup PkgWeightsRefThreePointFamilyWeights + \brief computes the three-point family weight in 2D at `q` using the points `p0`, `p1` and `p2`, + and the power parameter `a`. + \tparam GeomTraits a model of `AnalyticWeightTraits_2` +*/ +template +typename GeomTraits::FT three_point_family_weight(const typename GeomTraits::Point_2& p0, + const typename GeomTraits::Point_2& p1, + const typename GeomTraits::Point_2& p2, + const typename GeomTraits::Point_2& q, + const typename GeomTraits::FT a, + const GeomTraits& traits) +{ + using FT = typename GeomTraits::FT; - \brief computes the three-point family weight in 2D at `q` using the points `p0`, `p1`, - and `p2` which are parameterized by a `Kernel` K, and the power parameter `a` which - can be omitted. - */ - template - typename K::FT three_point_family_weight( - const CGAL::Point_2& p0, - const CGAL::Point_2& p1, - const CGAL::Point_2& p2, - const CGAL::Point_2& q, - const typename K::FT a = typename K::FT(1)) { } + auto area_2 = traits.compute_area_2_object(); - #endif // DOXYGEN_RUNNING + const FT d0 = internal::distance_2(q, p0, traits); + const FT d = internal::distance_2(q, p1, traits); + const FT d2 = internal::distance_2(q, p2, traits); - /// \cond SKIP_IN_MANUAL - template - typename GeomTraits::FT three_point_family_weight( - const typename GeomTraits::Point_2& t, - const typename GeomTraits::Point_2& r, - const typename GeomTraits::Point_2& p, - const typename GeomTraits::Point_2& q, - const typename GeomTraits::FT a, - const GeomTraits& traits) { + const FT A0 = area_2(p1, q, p0); + const FT A2 = area_2(p2, q, p1); + const FT B = area_2(p2, q, p0); - using FT = typename GeomTraits::FT; - const FT d1 = internal::distance_2(traits, q, t); - const FT d2 = internal::distance_2(traits, q, r); - const FT d3 = internal::distance_2(traits, q, p); + return three_point_family_ns::weight(d0, d2, d, A0, A2, B, a); +} - const FT A1 = internal::area_2(traits, r, q, t); - const FT A2 = internal::area_2(traits, p, q, r); - const FT B = internal::area_2(traits, p, q, t); +/*! + \ingroup PkgWeightsRefThreePointFamilyWeights + \brief computes the three-point family weight in 2D at `q` using the points `p0`, `p1` and `p2`, + and the power parameter `a`. + \tparam Kernel a model of `Kernel` +*/ +template +typename Kernel::FT three_point_family_weight(const CGAL::Point_2& p0, + const CGAL::Point_2& p1, + const CGAL::Point_2& p2, + const CGAL::Point_2& q, + const typename Kernel::FT a = {1}) +{ + const Kernel traits; + return three_point_family_weight(p0, p1, p2, q, a, traits); +} - return three_point_family_ns::weight( - traits, d1, d2, d3, A1, A2, B, a); - } +// 3D ============================================================================================== - template - typename GeomTraits::FT three_point_family_weight( - const CGAL::Point_2& t, - const CGAL::Point_2& r, - const CGAL::Point_2& p, - const CGAL::Point_2& q, - const typename GeomTraits::FT a = - typename GeomTraits::FT(1)) { +/// \cond SKIP_IN_MANUAL - const GeomTraits traits; - return three_point_family_weight(t, r, p, q, a, traits); - } +template +typename GeomTraits::FT three_point_family_weight(const typename GeomTraits::Point_3& p0, + const typename GeomTraits::Point_3& p1, + const typename GeomTraits::Point_3& p2, + const typename GeomTraits::Point_3& q, + const typename GeomTraits::FT a, + const GeomTraits& traits) +{ + using Point_2 = typename GeomTraits::Point_2; - namespace internal { + Point_2 p0f, p1f, p2f, qf; + internal::flatten(p0, p1, p2 , q, + p0f, p1f, p2f, qf, + traits); - template - typename GeomTraits::FT three_point_family_weight( - const typename GeomTraits::Point_3& t, - const typename GeomTraits::Point_3& r, - const typename GeomTraits::Point_3& p, - const typename GeomTraits::Point_3& q, - const typename GeomTraits::FT a, - const GeomTraits& traits) { + return CGAL::Weights::three_point_family_weight(p0f, p1f, p2f, qf, a, traits); +} - using Point_2 = typename GeomTraits::Point_2; - Point_2 tf, rf, pf, qf; - internal::flatten( - traits, - t, r, p, q, - tf, rf, pf, qf); - return CGAL::Weights:: - three_point_family_weight(tf, rf, pf, qf, a, traits); - } +template +typename Kernel::FT three_point_family_weight(const CGAL::Point_3& p0, + const CGAL::Point_3& p1, + const CGAL::Point_3& p2, + const CGAL::Point_3& q, + const typename Kernel::FT a = {1}) +{ + const Kernel traits; + return three_point_family_weight(p0, p1, p2, q, a, traits); +} - template - typename GeomTraits::FT three_point_family_weight( - const CGAL::Point_3& t, - const CGAL::Point_3& r, - const CGAL::Point_3& p, - const CGAL::Point_3& q, - const typename GeomTraits::FT a = - typename GeomTraits::FT(1)) { - - const GeomTraits traits; - return three_point_family_weight(t, r, p, q, a, traits); - } - - } // namespace internal - - /// \endcond +/// \endcond } // namespace Weights } // namespace CGAL diff --git a/Weights/include/CGAL/Weights/triangular_region_weights.h b/Weights/include/CGAL/Weights/triangular_region_weights.h index d0605d8e1bf..aa4b20a567a 100644 --- a/Weights/include/CGAL/Weights/triangular_region_weights.h +++ b/Weights/include/CGAL/Weights/triangular_region_weights.h @@ -14,107 +14,73 @@ #ifndef CGAL_TRIANGULAR_REGION_WEIGHTS_H #define CGAL_TRIANGULAR_REGION_WEIGHTS_H -// Internal includes. #include +#include +#include + namespace CGAL { namespace Weights { - #if defined(DOXYGEN_RUNNING) +// 2D ============================================================================================== - /*! - \ingroup PkgWeightsRefTriangularRegionWeights +/*! + \ingroup PkgWeightsRefTriangularRegionWeights + \brief computes the area of the triangular cell in 2D using the points `p`, `q`, and `r` + \tparam GeomTraits a model of `AnalyticWeightTraits_2` +*/ +template +typename GeomTraits::FT triangular_area(const typename GeomTraits::Point_2& p, + const typename GeomTraits::Point_2& q, + const typename GeomTraits::Point_2& r, + const GeomTraits& traits) +{ + return internal::positive_area_2(p, q, r, traits); +} - \brief computes the area of the triangular cell in 2D using the points `p`, `q` - and `r`, given a traits class `traits` with geometric objects, predicates, and constructions. - */ - template - typename GeomTraits::FT triangular_area( - const typename GeomTraits::Point_2& p, - const typename GeomTraits::Point_2& q, - const typename GeomTraits::Point_2& r, - const GeomTraits& traits) { } +/*! + \ingroup PkgWeightsRefTriangularRegionWeights + \brief computes the area of the triangular cell in 2D using the points `p`, `q`, and `r`. + \tparam Kernel a model of `Kernel` +*/ +template +typename Kernel::FT triangular_area(const CGAL::Point_2& p, + const CGAL::Point_2& q, + const CGAL::Point_2& r) +{ + const Kernel traits; + return triangular_area(p, q, r, traits); +} - /*! - \ingroup PkgWeightsRefTriangularRegionWeights +// 3D ============================================================================================== - \brief computes the area of the triangular cell in 3D using the points `p`, `q` - and `r`, given a traits class `traits` with geometric objects, predicates, and constructions. - */ - template - typename GeomTraits::FT triangular_area( - const typename GeomTraits::Point_3& p, - const typename GeomTraits::Point_3& q, - const typename GeomTraits::Point_3& r, - const GeomTraits& traits) { } +/*! + \ingroup PkgWeightsRefTriangularRegionWeights + \brief computes the area of the triangular cell in 3D using the points `p`, `q`, and `r`. + \tparam GeomTraits a model of `AnalyticWeightTraits_3` +*/ +template +typename GeomTraits::FT triangular_area(const typename GeomTraits::Point_3& p, + const typename GeomTraits::Point_3& q, + const typename GeomTraits::Point_3& r, + const GeomTraits& traits) +{ + return internal::positive_area_3(p, q, r, traits); +} - /*! - \ingroup PkgWeightsRefTriangularRegionWeights - - \brief computes the area of the triangular cell in 2D using the points `p`, `q` - and `r` which are parameterized by a `Kernel` K. - */ - template - typename K::FT triangular_area( - const CGAL::Point_2& p, - const CGAL::Point_2& q, - const CGAL::Point_2& r) { } - - /*! - \ingroup PkgWeightsRefTriangularRegionWeights - - \brief computes the area of the triangular cell in 3D using the points `p`, `q` - and `r` which are parameterized by a `Kernel` K. - */ - template - typename K::FT triangular_area( - const CGAL::Point_3& p, - const CGAL::Point_3& q, - const CGAL::Point_3& r) { } - - #endif // DOXYGEN_RUNNING - - /// \cond SKIP_IN_MANUAL - template - typename GeomTraits::FT triangular_area( - const typename GeomTraits::Point_2& p, - const typename GeomTraits::Point_2& q, - const typename GeomTraits::Point_2& r, - const GeomTraits& traits) { - - return internal::positive_area_2(traits, p, q, r); - } - - template - typename GeomTraits::FT triangular_area( - const CGAL::Point_2& p, - const CGAL::Point_2& q, - const CGAL::Point_2& r) { - - const GeomTraits traits; - return triangular_area(p, q, r, traits); - } - - template - typename GeomTraits::FT triangular_area( - const typename GeomTraits::Point_3& p, - const typename GeomTraits::Point_3& q, - const typename GeomTraits::Point_3& r, - const GeomTraits& traits) { - - return internal::positive_area_3(traits, p, q, r); - } - - template - typename GeomTraits::FT triangular_area( - const CGAL::Point_3& p, - const CGAL::Point_3& q, - const CGAL::Point_3& r) { - - const GeomTraits traits; - return triangular_area(p, q, r, traits); - } - /// \endcond +/*! + \ingroup PkgWeightsRefTriangularRegionWeights + \brief computes the area of the triangular cell in 3D using the points `p`, `q`, and `r`. + \tparam Kernel a model of `Kernel` +*/ +template +typename Kernel::FT triangular_area(const CGAL::Point_3& p, + const CGAL::Point_3& q, + const CGAL::Point_3& r) +{ + const Kernel traits; + return triangular_area(p, q, r, traits); +} } // namespace Weights } // namespace CGAL diff --git a/Weights/include/CGAL/Weights/uniform_region_weights.h b/Weights/include/CGAL/Weights/uniform_region_weights.h index 9d78a58b6b5..6ed0f0726b8 100644 --- a/Weights/include/CGAL/Weights/uniform_region_weights.h +++ b/Weights/include/CGAL/Weights/uniform_region_weights.h @@ -14,109 +14,73 @@ #ifndef CGAL_UNIFORM_REGION_WEIGHTS_H #define CGAL_UNIFORM_REGION_WEIGHTS_H -// Internal includes. -#include +#include +#include namespace CGAL { namespace Weights { - #if defined(DOXYGEN_RUNNING) +// 2D ============================================================================================== - /*! - \ingroup PkgWeightsRefUniformRegionWeights +/*! + \ingroup PkgWeightsRefUniformRegionWeights + \brief this function always returns `1`, given three 2D points. + \tparam GeomTraits a model of `AnalyticWeightTraits_2` +*/ +template +typename GeomTraits::FT uniform_area(const typename GeomTraits::Point_2&, + const typename GeomTraits::Point_2&, + const typename GeomTraits::Point_2&, + const GeomTraits&) +{ + using FT = typename GeomTraits::FT; + return FT(1); +} - \brief this function always returns 1, given three points in 2D and a traits class - with geometric objects, predicates, and constructions. - */ - template - typename GeomTraits::FT uniform_area( - const typename GeomTraits::Point_2&, - const typename GeomTraits::Point_2&, - const typename GeomTraits::Point_2&, - const GeomTraits&) { } +/*! + \ingroup PkgWeightsRefUniformRegionWeights + \brief this function always returns `1`, given three 2D points in 2D. + \tparam Kernel a model of `Kernel` +*/ +template +typename Kernel::FT uniform_area(const CGAL::Point_2& p, + const CGAL::Point_2& q, + const CGAL::Point_2& r) +{ + const Kernel traits; + return uniform_area(p, q, r, traits); +} - /*! - \ingroup PkgWeightsRefUniformRegionWeights +// 3D ============================================================================================== - \brief this function always returns 1, given three points in 3D and a traits class - with geometric objects, predicates, and constructions. - */ - template - typename GeomTraits::FT uniform_area( - const typename GeomTraits::Point_3&, - const typename GeomTraits::Point_3&, - const typename GeomTraits::Point_3&, - const GeomTraits&) { } +/*! + \ingroup PkgWeightsRefUniformRegionWeights + \brief this function always returns `1`, given three 3D points. + \tparam GeomTraits a model of `AnalyticWeightTraits_3` +*/ +template +typename GeomTraits::FT uniform_area(const typename GeomTraits::Point_3&, + const typename GeomTraits::Point_3&, + const typename GeomTraits::Point_3&, + const GeomTraits&) +{ + using FT = typename GeomTraits::FT; + return FT(1); +} - /*! - \ingroup PkgWeightsRefUniformRegionWeights - - \brief this function always returns 1, given three points in 2D which are - parameterized by a `Kernel` K. - */ - template - typename K::FT uniform_area( - const CGAL::Point_2&, - const CGAL::Point_2&, - const CGAL::Point_2&) { } - - /*! - \ingroup PkgWeightsRefUniformRegionWeights - - \brief this function always returns 1, given three points in 3D which are - parameterized by a `Kernel` K. - */ - template - typename K::FT uniform_area( - const CGAL::Point_3&, - const CGAL::Point_3&, - const CGAL::Point_3&) { } - - #endif // DOXYGEN_RUNNING - - /// \cond SKIP_IN_MANUAL - template - typename GeomTraits::FT uniform_area( - const typename GeomTraits::Point_2&, - const typename GeomTraits::Point_2&, - const typename GeomTraits::Point_2&, - const GeomTraits&) { - - using FT = typename GeomTraits::FT; - return FT(1); - } - - template - typename GeomTraits::FT uniform_area( - const CGAL::Point_2& p, - const CGAL::Point_2& q, - const CGAL::Point_2& r) { - - const GeomTraits traits; - return uniform_area(p, q, r, traits); - } - - template - typename GeomTraits::FT uniform_area( - const typename GeomTraits::Point_3&, - const typename GeomTraits::Point_3&, - const typename GeomTraits::Point_3&, - const GeomTraits&) { - - using FT = typename GeomTraits::FT; - return FT(1); - } - - template - typename GeomTraits::FT uniform_area( - const CGAL::Point_3& p, - const CGAL::Point_3& q, - const CGAL::Point_3& r) { - - const GeomTraits traits; - return uniform_area(p, q, r, traits); - } - /// \endcond +/*! + \ingroup PkgWeightsRefUniformRegionWeights + \brief this function always returns `1`, given three 3D points. + \tparam Kernel a model of `Kernel` +*/ +template +typename Kernel::FT uniform_area(const CGAL::Point_3& p, + const CGAL::Point_3& q, + const CGAL::Point_3& r) +{ + const Kernel traits; + return uniform_area(p, q, r, traits); +} } // namespace Weights } // namespace CGAL diff --git a/Weights/include/CGAL/Weights/uniform_weights.h b/Weights/include/CGAL/Weights/uniform_weights.h index 9ce8d49d360..69d1cf2a288 100644 --- a/Weights/include/CGAL/Weights/uniform_weights.h +++ b/Weights/include/CGAL/Weights/uniform_weights.h @@ -14,134 +14,98 @@ #ifndef CGAL_UNIFORM_WEIGHTS_H #define CGAL_UNIFORM_WEIGHTS_H -// Internal includes. -#include +#include +#include + +#include namespace CGAL { namespace Weights { - #if defined(DOXYGEN_RUNNING) +// 2D ============================================================================================== - /*! - \ingroup PkgWeightsRefUniformWeights +/*! + \ingroup PkgWeightsRefUniformWeights + \brief returns `1`. + \tparam GeomTraits a model of `AnalyticWeightTraits_2` +*/ +template +typename GeomTraits::FT uniform_weight(const typename GeomTraits::Point_2&, + const typename GeomTraits::Point_2&, + const typename GeomTraits::Point_2&, + const typename GeomTraits::Point_2&, + const GeomTraits&) +{ + return {1}; +} - \brief this function always returns 1, given four points in 2D and a traits class - with geometric objects, predicates, and constructions. - */ - template - typename GeomTraits::FT uniform_weight( - const typename GeomTraits::Point_2&, - const typename GeomTraits::Point_2&, - const typename GeomTraits::Point_2&, - const typename GeomTraits::Point_2&, - const GeomTraits&) { } +/*! + \ingroup PkgWeightsRefUniformWeights + \brief returns `1`. + \tparam Kernel a model of `Kernel` +*/ +template +typename GeomTraits::FT uniform_weight(const CGAL::Point_2& p0, + const CGAL::Point_2& p1, + const CGAL::Point_2& p2, + const CGAL::Point_2& q) +{ + const GeomTraits traits; + return uniform_weight(p0, p1, p2, q, traits); +} - /*! - \ingroup PkgWeightsRefUniformWeights +// 3D ============================================================================================== - \brief this function always returns 1, given four points in 3D and a traits class - with geometric objects, predicates, and constructions. - */ - template - typename GeomTraits::FT uniform_weight( - const typename GeomTraits::Point_3&, - const typename GeomTraits::Point_3&, - const typename GeomTraits::Point_3&, - const typename GeomTraits::Point_3&, - const GeomTraits&) { } +/*! + \ingroup PkgWeightsRefUniformWeights + \brief returns `1`. + \tparam GeomTraits a model of `AnalyticWeightTraits_2` +*/ +template +typename GeomTraits::FT uniform_weight(const typename GeomTraits::Point_3&, + const typename GeomTraits::Point_3&, + const typename GeomTraits::Point_3&, + const typename GeomTraits::Point_3&, + const GeomTraits&) +{ + return {1}; +} - /*! - \ingroup PkgWeightsRefUniformWeights +/*! + \ingroup PkgWeightsRefUniformWeights + \brief returns `1`. + \tparam Kernel a model of `Kernel` +*/ +template +typename GeomTraits::FT uniform_weight(const CGAL::Point_3& p0, + const CGAL::Point_3& p1, + const CGAL::Point_3& p2, + const CGAL::Point_3& q) +{ + const GeomTraits traits; + return uniform_weight(p0, p1, p2, q, traits); +} - \brief this function always returns 1, given four points in 2D which are - parameterized by a `Kernel` K. - */ - template - typename K::FT uniform_weight( - const CGAL::Point_2&, - const CGAL::Point_2&, - const CGAL::Point_2&, - const CGAL::Point_2&) { } +/// \cond SKIP_IN_MANUAL - /*! - \ingroup PkgWeightsRefUniformWeights +// Undocumented uniform weight class taking as input a polygon mesh. +// +// It is currently used in: +// Polygon_mesh_processing -> triangulate_hole_Polyhedron_3_test.cpp +// Polygon_mesh_processing -> triangulate_hole_Polyhedron_3_no_delaunay_test.cpp +// Polyhedron demo -> Fairing_plugin.cpp +// Polyhedron demo -> Hole_filling_plugin.cpp +template +class Uniform_weight +{ +public: + using vertex_descriptor = typename boost::graph_traits::vertex_descriptor; + using halfedge_descriptor = typename boost::graph_traits::halfedge_descriptor; + double w_i(vertex_descriptor) { return 1.; } + double w_ij(halfedge_descriptor) { return 1.; } +}; - \brief this function always returns 1, given four points in 3D which are - parameterized by a `Kernel` K. - */ - template - typename K::FT uniform_weight( - const CGAL::Point_3&, - const CGAL::Point_3&, - const CGAL::Point_3&, - const CGAL::Point_3&) { } - - #endif // DOXYGEN_RUNNING - - /// \cond SKIP_IN_MANUAL - template - typename GeomTraits::FT uniform_weight( - const typename GeomTraits::Point_2&, - const typename GeomTraits::Point_2&, - const typename GeomTraits::Point_2&, - const typename GeomTraits::Point_2&, - const GeomTraits&) { - - using FT = typename GeomTraits::FT; - return FT(1); - } - - template - typename GeomTraits::FT uniform_weight( - const CGAL::Point_2& q, - const CGAL::Point_2& t, - const CGAL::Point_2& r, - const CGAL::Point_2& p) { - - const GeomTraits traits; - return uniform_weight(q, t, r, p, traits); - } - - template - typename GeomTraits::FT uniform_weight( - const typename GeomTraits::Point_3&, - const typename GeomTraits::Point_3&, - const typename GeomTraits::Point_3&, - const typename GeomTraits::Point_3&, - const GeomTraits&) { - - using FT = typename GeomTraits::FT; - return FT(1); - } - - template - typename GeomTraits::FT uniform_weight( - const CGAL::Point_3& q, - const CGAL::Point_3& t, - const CGAL::Point_3& r, - const CGAL::Point_3& p) { - - const GeomTraits traits; - return uniform_weight(q, t, r, p, traits); - } - - // Undocumented uniform weight class taking as input a polygon mesh. - // It is currently used in: - // Polygon_mesh_processing -> triangulate_hole_Polyhedron_3_test.cpp - // Polygon_mesh_processing -> triangulate_hole_Polyhedron_3_no_delaunay_test.cpp - // Polyhedron demo -> Fairing_plugin.cpp - // Polyhedron demo -> Hole_filling_plugin.cpp - template - class Uniform_weight { - - public: - using vertex_descriptor = typename boost::graph_traits::vertex_descriptor; - using halfedge_descriptor = typename boost::graph_traits::halfedge_descriptor; - double w_i(vertex_descriptor) { return 1; } - double w_ij(halfedge_descriptor) { return 1; } - }; - - /// \endcond +/// \endcond } // namespace Weights } // namespace CGAL diff --git a/Weights/include/CGAL/Weights/utils.h b/Weights/include/CGAL/Weights/utils.h index 5636e00f296..67c10ce16c2 100644 --- a/Weights/include/CGAL/Weights/utils.h +++ b/Weights/include/CGAL/Weights/utils.h @@ -14,193 +14,242 @@ #ifndef CGAL_WEIGHTS_UTILS_H #define CGAL_WEIGHTS_UTILS_H -// Internal includes. #include +#include + namespace CGAL { namespace Weights { - /// \cond SKIP_IN_MANUAL - template - typename GeomTraits::FT tangent( - const typename GeomTraits::Point_2& p, - const typename GeomTraits::Point_2& q, - const typename GeomTraits::Point_2& r, - const GeomTraits& traits) { +/// \cond SKIP_IN_MANUAL - return internal::tangent_2(traits, p, q, r); +// Computes cotangent between two 2D vectors. +template +typename GeomTraits::FT cotangent_2(const typename GeomTraits::Point_2& p, + const typename GeomTraits::Point_2& q, + const typename GeomTraits::Point_2& r, + const GeomTraits& traits) +{ + using FT = typename GeomTraits::FT; + using Vector_2 = typename GeomTraits::Vector_2; + + auto dot_product_2 = traits.compute_scalar_product_2_object(); + auto determinant_2 = traits.compute_determinant_2_object(); + auto vector_2 = traits.construct_vector_2_object(); + + const Vector_2 v1 = vector_2(q, r); + const Vector_2 v2 = vector_2(q, p); + + const FT dot = dot_product_2(v1, v2); + const FT length = CGAL::abs(determinant_2(v1, v2)); + + if (!is_zero(length)) + return dot / length; + + return FT(0); // undefined +} + +template +typename GeomTraits::FT cotangent(const typename GeomTraits::Point_2& p, + const typename GeomTraits::Point_2& q, + const typename GeomTraits::Point_2& r, + const GeomTraits& traits) +{ + return cotangent_2(p, q, r, traits); +} + +template +typename Kernel::FT cotangent(const CGAL::Point_2& p, + const CGAL::Point_2& q, + const CGAL::Point_2& r) +{ + const Kernel traits; + return cotangent(p, q, r, traits); +} + +// ================================================================================================= + +// Computes cotangent between two 3D vectors. +template +typename GeomTraits::FT cotangent_3(const typename GeomTraits::Point_3& p, + const typename GeomTraits::Point_3& q, + const typename GeomTraits::Point_3& r, + const GeomTraits& traits) +{ + using FT = typename GeomTraits::FT; + using Vector_3 = typename GeomTraits::Vector_3; + + auto dot_product_3 = traits.compute_scalar_product_3_object(); + auto cross_product_3 = traits.construct_cross_product_vector_3_object(); + auto vector_3 = traits.construct_vector_3_object(); + + const Vector_3 v1 = vector_3(q, r); + const Vector_3 v2 = vector_3(q, p); + + const FT dot = dot_product_3(v1, v2); + const Vector_3 cross = cross_product_3(v1, v2); + + const FT length = internal::length_3(cross, traits); + if (!is_zero(length)) + return dot / length; + + return FT(0); // undefined +} + +template +typename GeomTraits::FT cotangent(const typename GeomTraits::Point_3& p, + const typename GeomTraits::Point_3& q, + const typename GeomTraits::Point_3& r, + const GeomTraits& traits) +{ + return cotangent_3(p, q, r, traits); +} + +template +typename Kernel::FT cotangent(const CGAL::Point_3& p, + const CGAL::Point_3& q, + const CGAL::Point_3& r) +{ + const Kernel traits; + return cotangent(p, q, r, traits); +} + +// ================================================================================================= + +// Computes tangent between two 2D vectors. +template +typename GeomTraits::FT tangent_2(const typename GeomTraits::Point_2& p, + const typename GeomTraits::Point_2& q, + const typename GeomTraits::Point_2& r, + const GeomTraits& traits) +{ + using FT = typename GeomTraits::FT; + using Vector_2 = typename GeomTraits::Vector_2; + + auto dot_product_2 = traits.compute_scalar_product_2_object(); + auto determinant_2 = traits.compute_determinant_2_object(); + auto vector_2 = traits.construct_vector_2_object(); + + const Vector_2 v1 = vector_2(q, r); + const Vector_2 v2 = vector_2(q, p); + + const FT dot = dot_product_2(v1, v2); + if (!is_zero(dot)) + { + const FT cross = determinant_2(v1, v2); + const FT length = CGAL::abs(cross); + return length / dot; } - template - typename GeomTraits::FT tangent( - const CGAL::Point_2& p, - const CGAL::Point_2& q, - const CGAL::Point_2& r) { + return FT(0); // undefined +} - const GeomTraits traits; - return tangent(p, q, r, traits); +template +typename GeomTraits::FT tangent(const typename GeomTraits::Point_2& p, + const typename GeomTraits::Point_2& q, + const typename GeomTraits::Point_2& r, + const GeomTraits& traits) +{ + return tangent_2(p, q, r, traits); +} + +template +typename Kernel::FT tangent(const CGAL::Point_2& p, + const CGAL::Point_2& q, + const CGAL::Point_2& r) +{ + const Kernel traits; + return tangent(p, q, r, traits); +} + +// ================================================================================================= + +// Computes tangent between two 3D vectors. +template +typename GeomTraits::FT tangent_3(const typename GeomTraits::Point_3& p, + const typename GeomTraits::Point_3& q, + const typename GeomTraits::Point_3& r, + const GeomTraits& traits) +{ + using FT = typename GeomTraits::FT; + using Vector_3 = typename GeomTraits::Vector_3; + + auto dot_product_3 = traits.compute_scalar_product_3_object(); + auto cross_product_3 = traits.construct_cross_product_vector_3_object(); + auto vector_3 = traits.construct_vector_3_object(); + + const Vector_3 v1 = vector_3(q, r); + const Vector_3 v2 = vector_3(q, p); + + const FT dot = dot_product_3(v1, v2); + if (!is_zero(dot)) + { + const Vector_3 cross = cross_product_3(v1, v2); + const FT length = internal::length_3(cross, traits); + return length / dot; } - template - typename GeomTraits::FT tangent( - const typename GeomTraits::Point_3& p, - const typename GeomTraits::Point_3& q, - const typename GeomTraits::Point_3& r, - const GeomTraits& traits) { + return FT(0); // undefined +} - return internal::tangent_3(traits, p, q, r); - } +template +typename GeomTraits::FT tangent(const typename GeomTraits::Point_3& p, + const typename GeomTraits::Point_3& q, + const typename GeomTraits::Point_3& r, + const GeomTraits& traits) +{ + return tangent_3(p, q, r, traits); +} - template - typename GeomTraits::FT tangent( - const CGAL::Point_3& p, - const CGAL::Point_3& q, - const CGAL::Point_3& r) { +template +typename Kernel::FT tangent(const CGAL::Point_3& p, + const CGAL::Point_3& q, + const CGAL::Point_3& r) +{ + const Kernel traits; + return tangent(p, q, r, traits); +} - const GeomTraits traits; - return tangent(p, q, r, traits); - } +// ================================================================================================= - template - typename GeomTraits::FT cotangent( - const typename GeomTraits::Point_2& p, - const typename GeomTraits::Point_2& q, - const typename GeomTraits::Point_2& r, - const GeomTraits& traits) { +// Computes a clamped cotangent between two 3D vectors. +// In the old version of weights in PMP, it was called "Cotangent_value_Meyer_secure". +// See Weights/internal/pmp_weights_deprecated.h for more information. +template +typename GeomTraits::FT cotangent_3_clamped(const typename GeomTraits::Point_3& p, + const typename GeomTraits::Point_3& q, + const typename GeomTraits::Point_3& r, + const GeomTraits& traits) +{ + using FT = typename GeomTraits::FT; + using Vector_3 = typename GeomTraits::Vector_3; - return internal::cotangent_2(traits, p, q, r); - } + using Get_sqrt = internal::Get_sqrt; + auto sqrt = Get_sqrt::sqrt_object(traits); - template - typename GeomTraits::FT cotangent( - const CGAL::Point_2& p, - const CGAL::Point_2& q, - const CGAL::Point_2& r) { + auto dot_product_3 = traits.compute_scalar_product_3_object(); + auto vector_3 = traits.construct_vector_3_object(); - const GeomTraits traits; - return cotangent(p, q, r, traits); - } + const Vector_3 v1 = vector_3(q, r); + const Vector_3 v2 = vector_3(q, p); - template - typename GeomTraits::FT cotangent( - const typename GeomTraits::Point_3& p, - const typename GeomTraits::Point_3& q, - const typename GeomTraits::Point_3& r, - const GeomTraits& traits) { + const FT dot = dot_product_3(v1, v2); + const FT length_v1 = internal::length_3(v1, traits); + const FT length_v2 = internal::length_3(v2, traits); - return internal::cotangent_3(traits, p, q, r); - } + const FT lb = -FT(999) / FT(1000), + ub = FT(999) / FT(1000); + const FT cosine = boost::algorithm::clamp(dot / (length_v1 * length_v2), lb, ub); + const FT sine = sqrt(FT(1) - square(cosine)); - template - typename GeomTraits::FT cotangent( - const CGAL::Point_3& p, - const CGAL::Point_3& q, - const CGAL::Point_3& r) { + CGAL_assertion(!is_zero(sine)); + if (!is_zero(sine)) + return cosine / sine; - const GeomTraits traits; - return cotangent(p, q, r, traits); - } - /// \endcond + return FT(0); // undefined +} - /// \cond SKIP_IN_MANUAL - // These are free functions to be used when building weights from parts rather - // than using the predefined weight functions. In principle, they can be removed. - // They are here to have unified interface within the Weights package and its - // construction weight system. - template - typename GeomTraits::FT squared_distance( - const CGAL::Point_2& p, - const CGAL::Point_2& q) { - - const GeomTraits traits; - const auto squared_distance_2 = - traits.compute_squared_distance_2_object(); - return squared_distance_2(p, q); - } - - template - typename GeomTraits::FT squared_distance( - const CGAL::Point_3& p, - const CGAL::Point_3& q) { - - const GeomTraits traits; - const auto squared_distance_3 = - traits.compute_squared_distance_3_object(); - return squared_distance_3(p, q); - } - - template - typename GeomTraits::FT distance( - const CGAL::Point_2& p, - const CGAL::Point_2& q) { - - const GeomTraits traits; - return internal::distance_2(traits, p, q); - } - - template - typename GeomTraits::FT distance( - const CGAL::Point_3& p, - const CGAL::Point_3& q) { - - const GeomTraits traits; - return internal::distance_3(traits, p, q); - } - - template - typename GeomTraits::FT area( - const CGAL::Point_2& p, - const CGAL::Point_2& q, - const CGAL::Point_2& r) { - - const GeomTraits traits; - return internal::area_2(traits, p, q, r); - } - - template - typename GeomTraits::FT area( - const CGAL::Point_3& p, - const CGAL::Point_3& q, - const CGAL::Point_3& r) { - - const GeomTraits traits; - return internal::positive_area_3(traits, p, q, r); - } - - template - typename GeomTraits::FT scalar_product( - const CGAL::Point_2& p, - const CGAL::Point_2& q, - const CGAL::Point_2& r) { - - const GeomTraits traits; - const auto scalar_product_2 = - traits.compute_scalar_product_2_object(); - const auto construct_vector_2 = - traits.construct_vector_2_object(); - - const auto v1 = construct_vector_2(q, r); - const auto v2 = construct_vector_2(q, p); - return scalar_product_2(v1, v2); - } - - template - typename GeomTraits::FT scalar_product( - const CGAL::Point_3& p, - const CGAL::Point_3& q, - const CGAL::Point_3& r) { - - const GeomTraits traits; - const auto scalar_product_3 = - traits.compute_scalar_product_3_object(); - const auto construct_vector_3 = - traits.construct_vector_3_object(); - - const auto v1 = construct_vector_3(q, r); - const auto v2 = construct_vector_3(q, p); - return scalar_product_3(v1, v2); - } - /// \endcond +/// \endcond } // namespace Weights } // namespace CGAL diff --git a/Weights/include/CGAL/Weights/voronoi_region_weights.h b/Weights/include/CGAL/Weights/voronoi_region_weights.h index 569c26a6870..86d06a07243 100644 --- a/Weights/include/CGAL/Weights/voronoi_region_weights.h +++ b/Weights/include/CGAL/Weights/voronoi_region_weights.h @@ -14,131 +14,99 @@ #ifndef CGAL_VORONOI_REGION_WEIGHTS_H #define CGAL_VORONOI_REGION_WEIGHTS_H -// Internal includes. #include +#include +#include + namespace CGAL { namespace Weights { - #if defined(DOXYGEN_RUNNING) +// 2D ============================================================================================== - /*! - \ingroup PkgWeightsRefVoronoiRegionWeights +/*! + \ingroup PkgWeightsRefVoronoiRegionWeights + \brief computes the area of the Voronoi cell in 2D using the points `p`, `q`, and `r`. + \tparam GeomTraits a model of `AnalyticWeightTraits_2` +*/ +template +typename GeomTraits::FT voronoi_area(const typename GeomTraits::Point_2& p, + const typename GeomTraits::Point_2& q, + const typename GeomTraits::Point_2& r, + const GeomTraits& traits) +{ + using FT = typename GeomTraits::FT; + using Point_2 = typename GeomTraits::Point_2; - \brief computes the area of the Voronoi cell in 2D using the points `p`, `q` - and `r`, given a traits class `traits` with geometric objects, predicates, and constructions. - */ - template - typename GeomTraits::FT voronoi_area( - const typename GeomTraits::Point_2& p, - const typename GeomTraits::Point_2& q, - const typename GeomTraits::Point_2& r, - const GeomTraits& traits) { } + auto circumcenter_2 = traits.construct_circumcenter_2_object(); + auto midpoint_2 = traits.construct_midpoint_2_object(); - /*! - \ingroup PkgWeightsRefVoronoiRegionWeights + const Point_2 center = circumcenter_2(p, q, r); + const Point_2 m1 = midpoint_2(q, r); + const Point_2 m2 = midpoint_2(q, p); - \brief computes the area of the Voronoi cell in 3D using the points `p`, `q` - and `r`, given a traits class `traits` with geometric objects, predicates, and constructions. - */ - template - typename GeomTraits::FT voronoi_area( - const typename GeomTraits::Point_3& p, - const typename GeomTraits::Point_3& q, - const typename GeomTraits::Point_3& r, - const GeomTraits& traits) { } + const FT A1 = internal::positive_area_2(q, m1, center,traits); + const FT A2 = internal::positive_area_2(q, center, m2, traits); - /*! - \ingroup PkgWeightsRefVoronoiRegionWeights + return A1 + A2; +} - \brief computes the area of the Voronoi cell in 2D using the points `p`, `q` - and `r` which are parameterized by a `Kernel` K. - */ - template - typename K::FT voronoi_area( - const CGAL::Point_2& p, - const CGAL::Point_2& q, - const CGAL::Point_2& r) { } +/*! + \ingroup PkgWeightsRefVoronoiRegionWeights + \brief computes the area of the Voronoi cell in 2D using the points `p`, `q`, and `r`. + \tparam Kernel a model of `Kernel` +*/ +template +typename Kernel::FT voronoi_area(const CGAL::Point_2& p, + const CGAL::Point_2& q, + const CGAL::Point_2& r) +{ + const Kernel traits; + return voronoi_area(p, q, r, traits); +} - /*! - \ingroup PkgWeightsRefVoronoiRegionWeights +// 3D ============================================================================================== - \brief computes the area of the Voronoi cell in 3D using the points `p`, `q` - and `r` which are parameterized by a `Kernel` K. - */ - template - typename K::FT voronoi_area( - const CGAL::Point_3& p, - const CGAL::Point_3& q, - const CGAL::Point_3& r) { } +/*! + \ingroup PkgWeightsRefVoronoiRegionWeights + \brief computes the area of the Voronoi cell in 3D using the points `p`, `q`, and `r` + \tparam GeomTraits a model of `AnalyticWeightTraits_3`. +*/ +template +typename GeomTraits::FT voronoi_area(const typename GeomTraits::Point_3& p, + const typename GeomTraits::Point_3& q, + const typename GeomTraits::Point_3& r, + const GeomTraits& traits) +{ + using FT = typename GeomTraits::FT; + using Point_3 = typename GeomTraits::Point_3; - #endif // DOXYGEN_RUNNING + auto circumcenter_3 = traits.construct_circumcenter_3_object(); + auto midpoint_3 = traits.construct_midpoint_3_object(); - /// \cond SKIP_IN_MANUAL - template - typename GeomTraits::FT voronoi_area( - const typename GeomTraits::Point_2& p, - const typename GeomTraits::Point_2& q, - const typename GeomTraits::Point_2& r, - const GeomTraits& traits) { + const Point_3 center = circumcenter_3(p, q, r); + const Point_3 m1 = midpoint_3(q, r); + const Point_3 m2 = midpoint_3(q, p); - using FT = typename GeomTraits::FT; - const auto circumcenter_2 = - traits.construct_circumcenter_2_object(); - const auto midpoint_2 = - traits.construct_midpoint_2_object(); + const FT A1 = internal::positive_area_3(q, m1, center, traits); + const FT A2 = internal::positive_area_3(q, center, m2, traits); - const auto center = circumcenter_2(p, q, r); - const auto m1 = midpoint_2(q, r); - const auto m2 = midpoint_2(q, p); + return A1 + A2; +} - const FT A1 = internal::positive_area_2(traits, q, m1, center); - const FT A2 = internal::positive_area_2(traits, q, center, m2); - return A1 + A2; - } - - template - typename GeomTraits::FT voronoi_area( - const CGAL::Point_2& p, - const CGAL::Point_2& q, - const CGAL::Point_2& r) { - - const GeomTraits traits; - return voronoi_area(p, q, r, traits); - } - - template - typename GeomTraits::FT voronoi_area( - const typename GeomTraits::Point_3& p, - const typename GeomTraits::Point_3& q, - const typename GeomTraits::Point_3& r, - const GeomTraits& traits) { - - using FT = typename GeomTraits::FT; - const auto circumcenter_3 = - traits.construct_circumcenter_3_object(); - const auto midpoint_3 = - traits.construct_midpoint_3_object(); - - const auto center = circumcenter_3(p, q, r); - const auto m1 = midpoint_3(q, r); - const auto m2 = midpoint_3(q, p); - - const FT A1 = internal::positive_area_3(traits, q, m1, center); - const FT A2 = internal::positive_area_3(traits, q, center, m2); - return A1 + A2; - } - - template - typename GeomTraits::FT voronoi_area( - const CGAL::Point_3& p, - const CGAL::Point_3& q, - const CGAL::Point_3& r) { - - const GeomTraits traits; - return voronoi_area(p, q, r, traits); - } - /// \endcond +/*! + \ingroup PkgWeightsRefVoronoiRegionWeights + \brief computes the area of the Voronoi cell in 3D using the points `p`, `q`, and `r`. + \tparam Kernel a model of `Kernel` +*/ +template +typename Kernel::FT voronoi_area(const CGAL::Point_3& p, + const CGAL::Point_3& q, + const CGAL::Point_3& r) +{ + const Kernel traits; + return voronoi_area(p, q, r, traits); +} } // namespace Weights } // namespace CGAL diff --git a/Weights/include/CGAL/Weights/wachspress_weights.h b/Weights/include/CGAL/Weights/wachspress_weights.h index 34299c24a52..9a1c9e7bd1b 100644 --- a/Weights/include/CGAL/Weights/wachspress_weights.h +++ b/Weights/include/CGAL/Weights/wachspress_weights.h @@ -14,409 +14,373 @@ #ifndef CGAL_WACHSPRESS_WEIGHTS_H #define CGAL_WACHSPRESS_WEIGHTS_H -// Internal includes. #include #include +#include +#include +#include + +#include + namespace CGAL { namespace Weights { - /// \cond SKIP_IN_MANUAL - namespace wachspress_ns { +/// \cond SKIP_IN_MANUAL - template - FT weight(const FT A1, const FT A2, const FT C) { +namespace wachspress_ns { - FT w = FT(0); - CGAL_precondition(A1 != FT(0) && A2 != FT(0)); - const FT prod = A1 * A2; - if (prod != FT(0)) { - const FT inv = FT(1) / prod; - w = C * inv; - } - return w; - } - } - /// \endcond +template +FT weight(const FT A0, const FT A2, const FT C) +{ + FT w = FT(0); + CGAL_precondition(!is_zero(A0) && !is_zero(A2)); + const FT prod = A0 * A2; + if (!is_zero(prod)) + w = C / prod; - #if defined(DOXYGEN_RUNNING) + return w; +} - /*! - \ingroup PkgWeightsRefWachspressWeights +} // namespace wachspress_ns - \brief computes the Wachspress weight in 2D at `q` using the points `p0`, `p1`, - and `p2`, given a traits class `traits` with geometric objects, predicates, and constructions. - */ - template - typename GeomTraits::FT wachspress_weight( - const typename GeomTraits::Point_2& p0, - const typename GeomTraits::Point_2& p1, - const typename GeomTraits::Point_2& p2, - const typename GeomTraits::Point_2& q, - const GeomTraits& traits) { } +/// \endcond - /*! - \ingroup PkgWeightsRefWachspressWeights +// 2D ============================================================================================== - \brief computes the Wachspress weight in 2D at `q` using the points `p0`, `p1`, - and `p2` which are parameterized by a `Kernel` K. - */ - template - typename K::FT wachspress_weight( - const CGAL::Point_2& p0, - const CGAL::Point_2& p1, - const CGAL::Point_2& p2, - const CGAL::Point_2& q) { } +/*! + \ingroup PkgWeightsRefWachspressWeights + \brief computes the Wachspress weight in 2D at `q` using the points `p0`, `p1`, and `p2`. + \tparam GeomTraits a model of `AnalyticWeightTraits_2` +*/ +template +typename GeomTraits::FT wachspress_weight(const typename GeomTraits::Point_2& p0, + const typename GeomTraits::Point_2& p1, + const typename GeomTraits::Point_2& p2, + const typename GeomTraits::Point_2& q, + const GeomTraits& traits) +{ + using FT = typename GeomTraits::FT; - #endif // DOXYGEN_RUNNING + auto area_2 = traits.compute_area_2_object(); + + const FT A0 = area_2(p1, q, p0); + const FT A2 = area_2(p2, q, p1); + const FT C = area_2(p0, p1, p2); + + return wachspress_ns::weight(A0, A2, C); +} + +/*! + \ingroup PkgWeightsRefWachspressWeights + \brief computes the Wachspress weight in 2D at `q` using the points `p0`, `p1`, and `p2`. + \tparam Kernel a model of `Kernel` +*/ +template +typename Kernel::FT wachspress_weight(const CGAL::Point_2& p0, + const CGAL::Point_2& p1, + const CGAL::Point_2& p2, + const CGAL::Point_2& q) +{ + const Kernel traits; + return wachspress_weight(p0, p1, p2, q, traits); +} + +// 3D ============================================================================================== + +/// \cond SKIP_IN_MANUAL + +template +typename GeomTraits::FT wachspress_weight(const typename GeomTraits::Point_3& p0, + const typename GeomTraits::Point_3& p1, + const typename GeomTraits::Point_3& p2, + const typename GeomTraits::Point_3& q, + const GeomTraits& traits) +{ + using Point_2 = typename GeomTraits::Point_2; + + Point_2 p0f, p1f, p2f, qf; + internal::flatten(p0, p1, p2, q, + p0f, p1f, p2f, qf, + traits); + + return CGAL::Weights::wachspress_weight(p0f, p1f, p2f, qf, traits); +} + +template +typename Kernel::FT wachspress_weight(const CGAL::Point_3& p0, + const CGAL::Point_3& p1, + const CGAL::Point_3& p2, + const CGAL::Point_3& q) +{ + const Kernel traits; + return wachspress_weight(p0, p1, p2, q, traits); +} + +/// \endcond + +/*! + \ingroup PkgWeightsRefBarycentricWachspressWeights + + \brief 2D Wachspress weights for polygons. + + This class implements 2D Wachspress weights ( \cite cgal:bc:fhk-gcbcocp-06, + \cite cgal:bc:mlbd-gbcip-02, \cite cgal:bc:w-rfeb-75 ) which can be computed + at any point inside a strictly convex polygon. + + Wachspress weights are well-defined and non-negative inside a strictly convex polygon. + The weights are computed analytically using the formulation from the `wachspress_weight()`. + + \tparam VertexRange a model of `ConstRange` whose iterator type is `RandomAccessIterator` + \tparam GeomTraits a model of `AnalyticWeightTraits_2` + \tparam PointMap a model of `ReadablePropertyMap` whose key type is `VertexRange::value_type` and + value type is `Point_2`. The default is `CGAL::Identity_property_map`. + + \cgalModels `BarycentricWeights_2` +*/ +template > +class Wachspress_weights_2 +{ +public: + + /// \name Types + /// @{ /// \cond SKIP_IN_MANUAL - template - typename GeomTraits::FT wachspress_weight( - const typename GeomTraits::Point_2& t, - const typename GeomTraits::Point_2& r, - const typename GeomTraits::Point_2& p, - const typename GeomTraits::Point_2& q, - const GeomTraits& traits) { - using FT = typename GeomTraits::FT; - const FT A1 = internal::area_2(traits, r, q, t); - const FT A2 = internal::area_2(traits, p, q, r); - const FT C = internal::area_2(traits, t, r, p); - return wachspress_ns::weight(A1, A2, C); - } + using Vertex_range = VertexRange; + using Geom_traits = GeomTraits; + using Point_map = PointMap; - template - typename GeomTraits::FT wachspress_weight( - const CGAL::Point_2& t, - const CGAL::Point_2& r, - const CGAL::Point_2& p, - const CGAL::Point_2& q) { - - const GeomTraits traits; - return wachspress_weight(t, r, p, q, traits); - } - - namespace internal { - - template - typename GeomTraits::FT wachspress_weight( - const typename GeomTraits::Point_3& t, - const typename GeomTraits::Point_3& r, - const typename GeomTraits::Point_3& p, - const typename GeomTraits::Point_3& q, - const GeomTraits& traits) { - - using Point_2 = typename GeomTraits::Point_2; - Point_2 tf, rf, pf, qf; - internal::flatten( - traits, - t, r, p, q, - tf, rf, pf, qf); - return CGAL::Weights:: - wachspress_weight(tf, rf, pf, qf, traits); - } - - template - typename GeomTraits::FT wachspress_weight( - const CGAL::Point_3& t, - const CGAL::Point_3& r, - const CGAL::Point_3& p, - const CGAL::Point_3& q) { - - const GeomTraits traits; - return wachspress_weight(t, r, p, q, traits); - } - - } // namespace internal + using Area_2 = typename GeomTraits::Compute_area_2; /// \endcond + /// Number type. + typedef typename GeomTraits::FT FT; + + /// Point type. + typedef typename GeomTraits::Point_2 Point_2; + + /// @} + + /// \name Initialization + /// @{ + /*! - \ingroup PkgWeightsRefBarycentricWachspressWeights + \brief initializes all internal data structures. - \brief 2D Wachspress weights for polygons. + This class implements the behavior of Wachspress weights + for 2D query points inside strictly convex polygons. - This class implements 2D Wachspress weights ( \cite cgal:bc:fhk-gcbcocp-06, - \cite cgal:bc:mlbd-gbcip-02, \cite cgal:bc:w-rfeb-75 ) which can be computed - at any point inside a strictly convex polygon. + \param polygon an instance of `VertexRange` with the vertices of a strictly convex polygon + \param traits a traits class with geometric objects, predicates, and constructions; + the default initialization is provided + \param point_map an instance of `PointMap` that maps a vertex from `polygon` to `Point_2`; + the default initialization is provided - Wachspress weights are well-defined and non-negative inside a strictly convex polygon. - The weights are computed analytically using the formulation from the `wachspress_weight()`. - - \tparam VertexRange - a model of `ConstRange` whose iterator type is `RandomAccessIterator` - - \tparam GeomTraits - a model of `AnalyticWeightTraits_2` - - \tparam PointMap - a model of `ReadablePropertyMap` whose key type is `VertexRange::value_type` and - value type is `Point_2`. The default is `CGAL::Identity_property_map`. - - \cgalModels `BarycentricWeights_2` + \pre `polygon.size() >= 3` + \pre `polygon` is simple + \pre `polygon` is strictly convex */ - template< - typename VertexRange, - typename GeomTraits, - typename PointMap = CGAL::Identity_property_map > - class Wachspress_weights_2 { + Wachspress_weights_2(const VertexRange& polygon, + const GeomTraits traits = GeomTraits(), + const PointMap point_map = PointMap()) + : m_polygon(polygon), + m_traits(traits), + m_point_map(point_map), + m_area_2(m_traits.compute_area_2_object()) + { + CGAL_precondition(polygon.size() >= 3); + CGAL_precondition(internal::is_simple_2(polygon, traits, point_map)); + CGAL_precondition(internal::polygon_type_2(polygon, traits, point_map) == + internal::Polygon_type::STRICTLY_CONVEX); + resize(); + } - public: + /// @} - /// \name Types - /// @{ - - /// \cond SKIP_IN_MANUAL - using Vertex_range = VertexRange; - using Geom_traits = GeomTraits; - using Point_map = PointMap; - - using Area_2 = typename GeomTraits::Compute_area_2; - /// \endcond - - /// Number type. - typedef typename GeomTraits::FT FT; - - /// Point type. - typedef typename GeomTraits::Point_2 Point_2; - - /// @} - - /// \name Initialization - /// @{ - - /*! - \brief initializes all internal data structures. - - This class implements the behavior of Wachspress weights - for 2D query points inside strictly convex polygons. - - \param polygon - an instance of `VertexRange` with the vertices of a strictly convex polygon - - \param traits - a traits class with geometric objects, predicates, and constructions; - the default initialization is provided - - \param point_map - an instance of `PointMap` that maps a vertex from `polygon` to `Point_2`; - the default initialization is provided - - \pre polygon.size() >= 3 - \pre polygon is simple - \pre polygon is strictly convex - */ - Wachspress_weights_2( - const VertexRange& polygon, - const GeomTraits traits = GeomTraits(), - const PointMap point_map = PointMap()) : - m_polygon(polygon), - m_traits(traits), - m_point_map(point_map), - m_area_2(m_traits.compute_area_2_object()) { - - CGAL_precondition( - polygon.size() >= 3); - CGAL_precondition( - internal::is_simple_2(polygon, traits, point_map)); - CGAL_precondition( - internal::polygon_type_2(polygon, traits, point_map) == - internal::Polygon_type::STRICTLY_CONVEX); - resize(); - } - - /// @} - - /// \name Access - /// @{ - - /*! - \brief computes 2D Wachspress weights. - - This function fills a destination range with 2D Wachspress weights computed - at the `query` point with respect to the vertices of the input polygon. - - The number of computed weights is equal to the number of polygon vertices. - - \tparam OutIterator - a model of `OutputIterator` whose value type is `FT` - - \param query - a query point - - \param w_begin - the beginning of the destination range with the computed weights - - \return an output iterator to the element in the destination range, - one past the last weight stored - */ - template - OutIterator operator()(const Point_2& query, OutIterator w_begin) { - const bool normalize = false; - return operator()(query, w_begin, normalize); - } - - /// @} - - /// \cond SKIP_IN_MANUAL - template - OutIterator operator()(const Point_2& query, OutIterator w_begin, const bool normalize) { - return optimal_weights(query, w_begin, normalize); - } - /// \endcond - - private: - - // Fields. - const VertexRange& m_polygon; - const GeomTraits m_traits; - const PointMap m_point_map; - - const Area_2 m_area_2; - - std::vector A; - std::vector C; - std::vector w; - - // Functions. - void resize() { - A.resize(m_polygon.size()); - C.resize(m_polygon.size()); - w.resize(m_polygon.size()); - } - - template - OutputIterator optimal_weights( - const Point_2& query, OutputIterator weights, const bool normalize) { - - // Get the number of vertices in the polygon. - const std::size_t n = m_polygon.size(); - - // Compute areas A and C following the area notation from [1]. - // Split the loop to make this computation faster. - const auto& p1 = get(m_point_map, *(m_polygon.begin() + 0)); - const auto& p2 = get(m_point_map, *(m_polygon.begin() + 1)); - const auto& pn = get(m_point_map, *(m_polygon.begin() + (n - 1))); - - A[0] = m_area_2(p1, p2, query); - C[0] = m_area_2(pn, p1, p2); - - for (std::size_t i = 1; i < n - 1; ++i) { - const auto& pi0 = get(m_point_map, *(m_polygon.begin() + (i - 1))); - const auto& pi1 = get(m_point_map, *(m_polygon.begin() + (i + 0))); - const auto& pi2 = get(m_point_map, *(m_polygon.begin() + (i + 1))); - - A[i] = m_area_2(pi1, pi2, query); - C[i] = m_area_2(pi0, pi1, pi2); - } - - const auto& pm = get(m_point_map, *(m_polygon.begin() + (n - 2))); - A[n - 1] = m_area_2(pn, p1, query); - C[n - 1] = m_area_2(pm, pn, p1); - - // Compute unnormalized weights following the formula (28) from [1]. - CGAL_assertion(A[n - 1] != FT(0) && A[0] != FT(0)); - w[0] = C[0] / (A[n - 1] * A[0]); - - for (std::size_t i = 1; i < n - 1; ++i) { - CGAL_assertion(A[i - 1] != FT(0) && A[i] != FT(0)); - w[i] = C[i] / (A[i - 1] * A[i]); - } - - CGAL_assertion(A[n - 2] != FT(0) && A[n - 1] != FT(0)); - w[n - 1] = C[n - 1] / (A[n - 2] * A[n - 1]); - - // Normalize if necessary. - if (normalize) { - internal::normalize(w); - } - - // Return weights. - for (std::size_t i = 0; i < n; ++i) { - *(weights++) = w[i]; - } - return weights; - } - }; + /// \name Access + /// @{ /*! - \ingroup PkgWeightsRefBarycentricWachspressWeights + \brief computes 2D Wachspress weights. - \brief computes 2D Wachspress weights for polygons. + This function fills a destination range with 2D Wachspress weights computed + at the `query` point with respect to the vertices of the input polygon. - This function computes 2D Wachspress weights at a given `query` point - with respect to the vertices of a strictly convex `polygon`, that is one - weight per vertex. The weights are stored in a destination range - beginning at `w_begin`. + The number of computed weights is equal to the number of polygon vertices. - Internally, the class `Wachspress_weights_2` is used. If one wants to process - multiple query points, it is better to use that class. When using the free function, - internal memory is allocated for each query point, while when using the class, - it is allocated only once which is much more efficient. However, for a few query - points, it is easier to use this function. It can also be used when the processing - time is not a concern. + \tparam OutIterator a model of `OutputIterator` whose value type is `FT` - \tparam PointRange - a model of `ConstRange` whose iterator type is `RandomAccessIterator` - and value type is `GeomTraits::Point_2` - - \tparam OutIterator - a model of `OutputIterator` whose value type is `GeomTraits::FT` - - \tparam GeomTraits - a model of `AnalyticWeightTraits_2` - - \param polygon - an instance of `PointRange` with 2D points which form a strictly convex polygon - - \param query - a query point - - \param w_begin - the beginning of the destination range with the computed weights - - \param traits - a traits class with geometric objects, predicates, and constructions; - this parameter can be omitted if the traits class can be deduced from the point type + \param query a query point + \param w_begin the beginning of the destination range with the computed weights \return an output iterator to the element in the destination range, one past the last weight stored - - \pre polygon.size() >= 3 - \pre polygon is simple - \pre polygon is strictly convex */ - template< - typename PointRange, - typename OutIterator, - typename GeomTraits> - OutIterator wachspress_weights_2( - const PointRange& polygon, const typename GeomTraits::Point_2& query, - OutIterator w_begin, const GeomTraits& traits) { - - Wachspress_weights_2 - wachspress(polygon, traits); - return wachspress(query, w_begin); + template + OutIterator operator()(const Point_2& query, + OutIterator w_begin) + { + const bool normalize = false; + return operator()(query, w_begin, normalize); } + /// @} + /// \cond SKIP_IN_MANUAL - template< - typename PointRange, - typename OutIterator> - OutIterator wachspress_weights_2( - const PointRange& polygon, - const typename PointRange::value_type& query, - OutIterator w_begin) { - using Point_2 = typename PointRange::value_type; - using GeomTraits = typename Kernel_traits::Kernel; - const GeomTraits traits; - return wachspress_weights_2( - polygon, query, w_begin, traits); + template + OutIterator operator()(const Point_2& query, + OutIterator w_begin, + const bool normalize) + { + return optimal_weights(query, w_begin, normalize); } + /// \endcond +private: + const VertexRange& m_polygon; + const GeomTraits m_traits; + const PointMap m_point_map; + + const Area_2 m_area_2; + + std::vector A; + std::vector C; + std::vector w; + + void resize() + { + A.resize(m_polygon.size()); + C.resize(m_polygon.size()); + w.resize(m_polygon.size()); + } + + template + OutputIterator optimal_weights(const Point_2& query, + OutputIterator weights, + const bool normalize) + { + + // Get the number of vertices in the polygon. + const std::size_t n = m_polygon.size(); + + // Compute areas A and C following the area notation from [1]. + // Split the loop to make this computation faster. + const auto& p1 = get(m_point_map, *(m_polygon.begin() + 0)); + const auto& p2 = get(m_point_map, *(m_polygon.begin() + 1)); + const auto& pn = get(m_point_map, *(m_polygon.begin() + (n - 1))); + + A[0] = m_area_2(p1, p2, query); + C[0] = m_area_2(pn, p1, p2); + + for (std::size_t i = 1; i < n - 1; ++i) + { + const auto& pi0 = get(m_point_map, *(m_polygon.begin() + (i - 1))); + const auto& pi1 = get(m_point_map, *(m_polygon.begin() + (i + 0))); + const auto& pi2 = get(m_point_map, *(m_polygon.begin() + (i + 1))); + + A[i] = m_area_2(pi1, pi2, query); + C[i] = m_area_2(pi0, pi1, pi2); + } + + const auto& pm = get(m_point_map, *(m_polygon.begin() + (n - 2))); + A[n - 1] = m_area_2(pn, p1, query); + C[n - 1] = m_area_2(pm, pn, p1); + + // Compute unnormalized weights following the formula (28) from [1]. + CGAL_assertion(A[n - 1] != FT(0) && A[0] != FT(0)); + w[0] = C[0] / (A[n - 1] * A[0]); + + for (std::size_t i = 1; i < n - 1; ++i) + { + CGAL_assertion(A[i - 1] != FT(0) && A[i] != FT(0)); + w[i] = C[i] / (A[i - 1] * A[i]); + } + + CGAL_assertion(A[n - 2] != FT(0) && A[n - 1] != FT(0)); + w[n - 1] = C[n - 1] / (A[n - 2] * A[n - 1]); + + // Normalize if necessary. + if (normalize) + internal::normalize(w); + + // Return weights. + for (std::size_t i = 0; i < n; ++i) + *(weights++) = w[i]; + + return weights; + } +}; + +/*! + \ingroup PkgWeightsRefBarycentricWachspressWeights + + \brief computes 2D Wachspress weights for polygons. + + This function computes 2D Wachspress weights at a given `query` point + with respect to the vertices of a strictly convex `polygon`, that is one + weight per vertex. The weights are stored in a destination range + beginning at `w_begin`. + + Internally, the class `Wachspress_weights_2` is used. If one wants to process + multiple query points, it is better to use that class. When using the free function, + internal memory is allocated for each query point, while when using the class, + it is allocated only once which is much more efficient. However, for a few query + points, it is easier to use this function. It can also be used when the processing + time is not a concern. + + \tparam PointRange a model of `ConstRange` whose iterator type is `RandomAccessIterator` + and value type is `GeomTraits::Point_2` + \tparam OutIterator a model of `OutputIterator` whose value type is `GeomTraits::FT` + \tparam GeomTraits a model of `AnalyticWeightTraits_2` + + \param polygon an instance of `PointRange` with 2D points which form a strictly convex polygon + \param query a query point + \param w_begin the beginning of the destination range with the computed weights + \param traits a traits class with geometric objects, predicates, and constructions; + this parameter can be omitted if the traits class can be deduced from the point type + + \return an output iterator to the element in the destination range, one past the last weight stored + + \pre `polygon.size() >= 3` + \pre `polygon` is simple + \pre `polygon` is strictly convex +*/ +template +OutIterator wachspress_weights_2(const PointRange& polygon, + const typename GeomTraits::Point_2& query, + OutIterator w_begin, + const GeomTraits& traits) +{ + Wachspress_weights_2 wachspress(polygon, traits); + return wachspress(query, w_begin); +} + +/// \cond SKIP_IN_MANUAL + +template +OutIterator wachspress_weights_2(const PointRange& polygon, + const typename PointRange::value_type& query, + OutIterator w_begin) +{ + using Point_2 = typename PointRange::value_type; + using GeomTraits = typename Kernel_traits::Kernel; + + const GeomTraits traits; + return wachspress_weights_2(polygon, query, w_begin, traits); +} + +/// \endcond + } // namespace Weights } // namespace CGAL diff --git a/Weights/test/Weights/include/utils.h b/Weights/test/Weights/include/utils.h index 89b9beb0911..90afd589149 100644 --- a/Weights/test/Weights/include/utils.h +++ b/Weights/test/Weights/include/utils.h @@ -1,113 +1,177 @@ #ifndef CGAL_WEIGHTS_TESTS_UTILS_H #define CGAL_WEIGHTS_TESTS_UTILS_H -// STL includes. +#include + +#include +#include + #include #include #include #include #include -// CGAL includes. -#include -#include -#include +namespace CGAL { +namespace Weights { +namespace internal { + +template +typename Kernel::FT squared_distance(const CGAL::Point_2& p, + const CGAL::Point_2& q) +{ + const Kernel traits; + auto squared_distance_2 = traits.compute_squared_distance_2_object(); + return squared_distance_2(p, q); +} + +template +typename Kernel::FT squared_distance(const CGAL::Point_3& p, + const CGAL::Point_3& q) +{ + const Kernel traits; + auto squared_distance_3 = traits.compute_squared_distance_3_object(); + return squared_distance_3(p, q); +} + +template +typename Kernel::FT distance(const CGAL::Point_2& p, + const CGAL::Point_2& q) +{ + const Kernel traits; + return CGAL::Weights::internal::distance_2(p, q, traits); +} + +template +typename Kernel::FT distance(const CGAL::Point_3& p, + const CGAL::Point_3& q) +{ + const Kernel traits; + return CGAL::Weights::internal::distance_3(p, q, traits); +} + +template +typename Kernel::FT area(const CGAL::Point_2& p, + const CGAL::Point_2& q, + const CGAL::Point_2& r) +{ + const Kernel traits; + return CGAL::Weights::internal::positive_area_2(p, q, r, traits); +} + +template +typename Kernel::FT area(const CGAL::Point_3& p, + const CGAL::Point_3& q, + const CGAL::Point_3& r) +{ + const Kernel traits; + return CGAL::Weights::internal::positive_area_3(p, q, r, traits); +} + +template +typename Kernel::FT scalar_product(const CGAL::Point_2& p, + const CGAL::Point_2& q, + const CGAL::Point_2& r) +{ + const Kernel traits; + auto scalar_product_2 = traits.compute_scalar_product_2_object(); + auto vector_2 = traits.construct_vector_2_object(); + + const auto v1 = vector_2(q, r); + const auto v2 = vector_2(q, p); + return scalar_product_2(v1, v2); +} + +template +typename Kernel::FT scalar_product(const CGAL::Point_3& p, + const CGAL::Point_3& q, + const CGAL::Point_3& r) +{ + const Kernel traits; + auto scalar_product_3 = traits.compute_scalar_product_3_object(); + auto vector_3 = traits.construct_vector_3_object(); + + const auto v1 = vector_3(q, r); + const auto v2 = vector_3(q, p); + + return scalar_product_3(v1, v2); +} + +} // namespace internal +} // namespace Weights +} // namespace CGAL namespace tests { template -FT get_tolerance() { - return FT(1) / FT(10000000000); -} +FT get_tolerance() { return FT(1e-10); } template std::vector< std::array > -get_all_triangles() { - +get_all_triangles() +{ using Point_2 = typename Kernel::Point_2; - const std::array triangle0 = { - Point_2(-1, 0), Point_2(0, -1), Point_2(1, 0) - }; - const std::array triangle1 = { - Point_2(-2, 0), Point_2(0, -1), Point_2(2, 0) - }; - const std::array triangle2 = { - Point_2(-2, 0), Point_2(-2, -2), Point_2(2, 0) - }; - const std::array triangle3 = { - Point_2(-2, 0), Point_2(2, -2), Point_2(2, 0) - }; + + const std::array triangle0 = { Point_2(-1, 0), Point_2(0, -1), Point_2(1, 0) }; + const std::array triangle1 = { Point_2(-2, 0), Point_2(0, -1), Point_2(2, 0) }; + const std::array triangle2 = { Point_2(-2, 0), Point_2(-2, -2), Point_2(2, 0) }; + const std::array triangle3 = { Point_2(-2, 0), Point_2(2, -2), Point_2(2, 0) }; + return { triangle0, triangle1, triangle2, triangle3 }; } template std::vector< std::array > -get_symmetric_triangles() { - +get_symmetric_triangles() +{ using Point_2 = typename Kernel::Point_2; - const std::array triangle0 = { - Point_2(-1, 0), Point_2(0, -1), Point_2(1, 0) - }; - const std::array triangle1 = { - Point_2(-2, 0), Point_2(0, -1), Point_2(2, 0) - }; - const std::array triangle2 = { - Point_2(-3, 0), Point_2(0, -1), Point_2(3, 0) - }; + + const std::array triangle0 = { Point_2(-1, 0), Point_2(0, -1), Point_2(1, 0) }; + const std::array triangle1 = { Point_2(-2, 0), Point_2(0, -1), Point_2(2, 0) }; + const std::array triangle2 = { Point_2(-3, 0), Point_2(0, -1), Point_2(3, 0) }; + return { triangle0, triangle1, triangle2 }; } template std::vector< std::array > -get_uniform_triangles() { - +get_uniform_triangles() +{ using Point_2 = typename Kernel::Point_2; - const std::array triangle0 = { - Point_2(-1, 0), Point_2(0, -1), Point_2(1, 0) - }; - const std::array triangle1 = { - Point_2(-2, 0), Point_2(0, -2), Point_2(2, 0) - }; - const std::array triangle2 = { - Point_2(1, 0), Point_2(-1, 0), Point_2(-1, -2) - }; - const std::array triangle3 = { - Point_2(1, -2), Point_2(1, 0), Point_2(-1, 0) - }; + + const std::array triangle0 = { Point_2(-1, 0), Point_2(0, -1), Point_2(1, 0) }; + const std::array triangle1 = { Point_2(-2, 0), Point_2(0, -2), Point_2(2, 0) }; + const std::array triangle2 = { Point_2(1, 0), Point_2(-1, 0), Point_2(-1, -2) }; + const std::array triangle3 = { Point_2(1, -2), Point_2(1, 0), Point_2(-1, 0) }; + return { triangle0, triangle1, triangle2, triangle3 }; } template std::vector< std::vector > -get_all_polygons() { - +get_all_polygons() +{ using Point_2 = typename Kernel::Point_2; - const std::vector polygon0 = { - Point_2(-2, -2), Point_2(2, -2), Point_2(0, 2) - }; - const std::vector polygon1 = { - Point_2(-1, -1), Point_2(1, -1), Point_2(1, 1), Point_2(-1, 1) - }; - const std::vector polygon2 = { - Point_2(-2, 0), Point_2(0, -2), Point_2(2, 0), Point_2(0, 2) - }; - const std::vector polygon3 = { - Point_2(-2, -2), Point_2(2, -2), Point_2(2, 0), Point_2(0, 2), Point_2(-2, 0) - }; + + const std::vector polygon0 = { Point_2(-2, -2), Point_2(2, -2), Point_2(0, 2) }; + const std::vector polygon1 = { Point_2(-1, -1), Point_2(1, -1), Point_2(1, 1), Point_2(-1, 1) }; + const std::vector polygon2 = { Point_2(-2, 0), Point_2(0, -2), Point_2(2, 0), Point_2(0, 2) }; + const std::vector polygon3 = { Point_2(-2, -2), Point_2(2, -2), Point_2(2, 0), + Point_2(0, 2), Point_2(-2, 0) }; + return { polygon0, polygon1, polygon2, polygon3 }; } -template< -typename Kernel, -typename Weight_wrapper> -bool test_query( - const Weight_wrapper& wrapper, - const typename Kernel::Point_2& query, - const std::array& neighbors) { - +template +void test_query(const Weight_wrapper& wrapper, + const typename Kernel::Point_2& query, + const std::array& neighbors) +{ using FT = typename Kernel::FT; using Point_2 = typename Kernel::Point_2; using Point_3 = typename Kernel::Point_3; + const FT tol = get_tolerance(); // 2D configuration. @@ -122,36 +186,28 @@ bool test_query( const Point_3 p3(p2.x(), p2.y(), 1); const Point_3 q3(q2.x(), q2.y(), 1); - const auto a2 = wrapper.weight_a(t2, r2, p2, q2); - const auto b2 = wrapper.weight_b(t2, r2, p2, q2); + const FT a2 = wrapper.weight_a(t2, r2, p2, q2); + const FT b2 = wrapper.weight_b(t2, r2, p2, q2); assert(a2 >= FT(0) && b2 >= FT(0)); - if (a2 < FT(0) || b2 < FT(0)) return false; assert(CGAL::abs(a2 - b2) < tol); - if (CGAL::abs(a2 - b2) >= tol) return false; - if (wrapper.supports_3d()) { - const auto a3 = wrapper.weight_a(t3, r3, p3, q3); - const auto b3 = wrapper.weight_b(t3, r3, p3, q3); + if (wrapper.supports_3d()) + { + const FT a3 = wrapper.weight_a(t3, r3, p3, q3); + const FT b3 = wrapper.weight_b(t3, r3, p3, q3); assert(a3 >= FT(0) && b3 >= FT(0)); - if (a3 < FT(0) || b3 < FT(0)) return false; assert(CGAL::abs(a3 - b3) < tol); - if (CGAL::abs(a3 - b3) >= tol) return false; assert(CGAL::abs(a2 - a3) < tol); assert(CGAL::abs(b2 - b3) < tol); - if (CGAL::abs(a2 - a3) >= tol) return false; - if (CGAL::abs(b2 - b3) >= tol) return false; } - return true; } -template< -typename Kernel, -typename Weight_wrapper> -bool test_symmetry_x( - const Weight_wrapper& wrapper, - const std::array& neighbors, - const typename Kernel::FT& x) { - +template +void test_symmetry_x(const Weight_wrapper& wrapper, + const std::array& neighbors, + const typename Kernel::FT& x) +{ using FT = typename Kernel::FT; using Point_2 = typename Kernel::Point_2; using Point_3 = typename Kernel::Point_3; @@ -167,41 +223,34 @@ bool test_symmetry_x( const Point_3 r3(r2.x(), r2.y(), 1); const Point_3 p3(p2.x(), p2.y(), 1); - const auto a2 = wrapper.weight_a(t2, r2, p2, Point_2(-x, 0)); - const auto b2 = wrapper.weight_a(t2, r2, p2, Point_2(+x, 0)); + const FT a2 = wrapper.weight_a(t2, r2, p2, Point_2(-x, 0)); + const FT b2 = wrapper.weight_a(t2, r2, p2, Point_2(+x, 0)); assert(a2 >= FT(0) && b2 >= FT(0)); - if (a2 < FT(0) || b2 < FT(0)) return false; assert(CGAL::abs(a2 - b2) < tol); - if (CGAL::abs(a2 - b2) >= tol) return false; - if (wrapper.supports_3d()) { - const auto a3 = wrapper.weight_a(t3, r3, p3, Point_3(-x, 0, 1)); - const auto b3 = wrapper.weight_a(t3, r3, p3, Point_3(+x, 0, 1)); + if (wrapper.supports_3d()) + { + const FT a3 = wrapper.weight_a(t3, r3, p3, Point_3(-x, 0, 1)); + const FT b3 = wrapper.weight_a(t3, r3, p3, Point_3(+x, 0, 1)); assert(a3 >= FT(0) && b3 >= FT(0)); - if (a3 < FT(0) || b3 < FT(0)) return false; assert(CGAL::abs(a3 - b3) < tol); - if (CGAL::abs(a3 - b3) >= tol) return false; assert(CGAL::abs(a2 - a3) < tol); assert(CGAL::abs(b2 - b3) < tol); - if (CGAL::abs(a2 - a3) >= tol) return false; - if (CGAL::abs(b2 - b3) >= tol) return false; } - return true; } -template< -typename Kernel, -typename Weight_wrapper_1, -typename Weight_wrapper_2> -bool test_compare( - const Weight_wrapper_1& wrapper1, - const Weight_wrapper_2& wrapper2, - const typename Kernel::Point_2& query, - const std::array& neighbors) { - +template +void test_compare(const Weight_wrapper_1& wrapper1, + const Weight_wrapper_2& wrapper2, + const typename Kernel::Point_2& query, + const std::array& neighbors) +{ using FT = typename Kernel::FT; using Point_2 = typename Kernel::Point_2; using Point_3 = typename Kernel::Point_3; + const FT tol = get_tolerance(); // 2D configuration. @@ -216,34 +265,29 @@ bool test_compare( const Point_3 p3(p2.x(), p2.y(), 1); const Point_3 q3(q2.x(), q2.y(), 1); - const auto a2 = wrapper1.weight_a(t2, r2, p2, q2); - const auto b2 = wrapper2.weight_a(t2, r2, p2, q2); + const FT a2 = wrapper1.weight_a(t2, r2, p2, q2); + const FT b2 = wrapper2.weight_a(t2, r2, p2, q2); assert(a2 >= FT(0) && b2 >= FT(0)); - if (a2 < FT(0) || b2 < FT(0)) return false; assert(CGAL::abs(a2 - b2) < tol); - if (CGAL::abs(a2 - b2) >= tol) return false; - if (wrapper1.supports_3d() && wrapper2.supports_3d()) { - const auto a3 = wrapper1.weight_a(t3, r3, p3, q3); - const auto b3 = wrapper2.weight_a(t3, r3, p3, q3); + if (wrapper1.supports_3d() && wrapper2.supports_3d()) + { + const FT a3 = wrapper1.weight_a(t3, r3, p3, q3); + const FT b3 = wrapper2.weight_a(t3, r3, p3, q3); assert(a3 >= FT(0) && b3 >= FT(0)); - if (a3 < FT(0) || b3 < FT(0)) return false; assert(CGAL::abs(a3 - b3) < tol); - if (CGAL::abs(a3 - b3) >= tol) return false; } - return true; } -template< -typename Kernel, -typename Weight_wrapper> -bool test_neighbors( - const Weight_wrapper& wrapper, - const std::array& neighbors) { - +template +void test_neighbors(const Weight_wrapper& wrapper, + const std::array& neighbors) +{ using FT = typename Kernel::FT; using Point_2 = typename Kernel::Point_2; using Point_3 = typename Kernel::Point_3; + const FT tol = get_tolerance(); // 2D configuration. @@ -256,22 +300,17 @@ bool test_neighbors( const Point_3 q3(q2.x(), q2.y(), 1); const Point_3 r3(r2.x(), r2.y(), 1); - const auto a2 = wrapper.weight(p2, q2, r2); - const auto a3 = wrapper.weight(p3, q3, r3); + const FT a2 = wrapper.weight(p2, q2, r2); + const FT a3 = wrapper.weight(p3, q3, r3); assert(a2 >= FT(0) && a3 >= FT(0)); - if (a2 < FT(0) || a3 < FT(0)) return false; assert(CGAL::abs(a2 - a3) < tol); - if (CGAL::abs(a2 - a3) >= tol) return false; - return true; } -template< -typename Kernel, -typename Weight_wrapper> -bool test_area( - const Weight_wrapper& wrapper, - const std::array& neighbors) { - +template +void test_area(const Weight_wrapper& wrapper, + const std::array& neighbors) +{ using FT = typename Kernel::FT; using Point_2 = typename Kernel::Point_2; using Point_3 = typename Kernel::Point_3; @@ -286,129 +325,105 @@ bool test_area( const Point_3 q3(q2.x(), q2.y(), 1); const Point_3 r3(r2.x(), r2.y(), 1); - const auto a2 = wrapper.weight(p2, q2, r2); - const auto a3 = wrapper.weight(p3, q3, r3); - assert(a2 <= CGAL::Weights::area(p2, q2, r2)); - assert(a3 <= CGAL::Weights::area(p3, q3, r3)); - if (a2 > CGAL::Weights::area(p2, q2, r2)) return false; - if (a3 > CGAL::Weights::area(p3, q3, r3)) return false; + const FT a2 = wrapper.weight(p2, q2, r2); + const FT a3 = wrapper.weight(p3, q3, r3); + assert(a2 <= CGAL::Weights::internal::area(p2, q2, r2)); + assert(a3 <= CGAL::Weights::internal::area(p3, q3, r3)); + assert(a2 >= FT(0)); assert(a3 >= FT(0)); - if (a2 < FT(0)) return false; - if (a3 < FT(0)) return false; - return true; } template -bool test_coordinates( - const Point& query, - const std::vector& polygon, - const std::vector& weights) { - +void test_coordinates(const Point& query, + const std::vector& polygon, + const std::vector& weights) +{ assert(weights.size() > 0); - if (weights.size() == 0) return false; // Compute the sum of weights. const FT tol = get_tolerance(); FT sum = FT(0); - for (const FT& weight : weights) { + for (const FT& weight : weights) sum += weight; - } assert(sum >= tol); - if (sum < tol) return false; // Compute coordinates. std::vector coordinates; coordinates.reserve(weights.size()); - for (const FT& weight : weights) { + for (const FT& weight : weights) coordinates.push_back(weight / sum); - } + assert(coordinates.size() == weights.size()); - if (coordinates.size() != weights.size()) return false; // Test partition of unity. sum = FT(0); - for (const FT& coordinate : coordinates) { + for (const FT& coordinate : coordinates) sum += coordinate; - } assert(CGAL::abs(FT(1) - sum) < tol); - if (CGAL::abs(FT(1) - sum) >= tol) return false; // Test linear precision. FT x = FT(0), y = FT(0); - for (std::size_t i = 0; i < polygon.size(); ++i) { + for (std::size_t i = 0; i < polygon.size(); ++i) + { x += coordinates[i] * polygon[i].x(); y += coordinates[i] * polygon[i].y(); } assert(CGAL::abs(query.x() - x) < tol); assert(CGAL::abs(query.y() - y) < tol); - if (CGAL::abs(query.x() - x) >= tol) return false; - if (CGAL::abs(query.y() - y) >= tol) return false; - return true; } -template< -typename Kernel, -typename Weight_wrapper> -bool test_on_polygon( - const Weight_wrapper& wrapper, - const typename Kernel::Point_2& query_2, - const std::vector& polygon_2) { - +template +void test_on_polygon(const Weight_wrapper& wrapper, + const typename Kernel::Point_2& query_2, + const std::vector& polygon_2) +{ // Get weights. using FT = typename Kernel::FT; assert(polygon_2.size() >= 3); - if (polygon_2.size() < 3) return false; // 2D version. std::vector weights_2; weights_2.reserve(polygon_2.size()); - wrapper.compute_on_polygon( - polygon_2, query_2, Kernel(), std::back_inserter(weights_2)); + wrapper.compute_on_polygon(polygon_2, query_2, Kernel(), std::back_inserter(weights_2)); assert(weights_2.size() == polygon_2.size()); - if (weights_2.size() != polygon_2.size()) return false; - if (!test_coordinates(query_2, polygon_2, weights_2)) return false; + test_coordinates(query_2, polygon_2, weights_2); // 3D version. using Point_3 = typename Kernel::Point_3; const Point_3 query_3(query_2.x(), query_2.y(), 1); std::vector polygon_3; polygon_3.reserve(polygon_2.size()); - for (const auto& vertex_2 : polygon_2) { - polygon_3.push_back(Point_3(vertex_2.x(), vertex_2.y(), 1)); - } + for (const auto& vertex_2 : polygon_2) + polygon_3.emplace_back(vertex_2.x(), vertex_2.y(), 1); assert(polygon_3.size() == polygon_2.size()); - if (polygon_3.size() != polygon_2.size()) return false; - const CGAL::Projection_traits_xy_3 ptraits; + const CGAL::Projection_traits_xy_3 ptraits; std::vector weights_3; weights_3.reserve(polygon_3.size()); - wrapper.compute_on_polygon( - polygon_3, query_3, ptraits, std::back_inserter(weights_3)); + wrapper.compute_on_polygon(polygon_3, query_3, ptraits, std::back_inserter(weights_3)); assert(weights_3.size() == polygon_3.size()); - if (weights_3.size() != polygon_3.size()) return false; - if (!test_coordinates(query_3, polygon_3, weights_3)) return false; - return true; + + test_coordinates(query_3, polygon_3, weights_3); } -template< -typename Kernel, -typename Weight_wrapper> -bool test_barycentric_properties( - const Weight_wrapper& wrapper, - const typename Kernel::Point_2& query, - const std::vector& polygon) { - +template +void test_barycentric_properties(const Weight_wrapper& wrapper, + const typename Kernel::Point_2& query, + const std::vector& polygon) +{ // Get weights. using FT = typename Kernel::FT; const std::size_t n = polygon.size(); assert(n >= 3); - if (n < 3) return false; // Check properties. std::vector weights; weights.reserve(n); - for (std::size_t i = 0; i < n; ++i) { + for (std::size_t i = 0; i < n; ++i) + { const std::size_t im = (i + n - 1) % n; const std::size_t ip = (i + 1) % n; const auto& t = polygon[im]; @@ -419,23 +434,19 @@ bool test_barycentric_properties( weights.push_back(weight); } assert(weights.size() == n); - if (weights.size() != n) return false; - if (!test_coordinates(query, polygon, weights)) return false; - return true; + + test_coordinates(query, polygon, weights); } -template< -typename Kernel, -typename Weight_wrapper_1, -typename Weight_wrapper_2> -bool test_analytic_weight( - const Weight_wrapper_1& weight, - const Weight_wrapper_2& alternative) { - +template +void test_analytic_weight(const Weight_wrapper_1& weight, + const Weight_wrapper_2& alternative) +{ using FT = typename Kernel::FT; using Point_2 = typename Kernel::Point_2; - // Data. const FT q = FT(1) / FT(4); const FT h = FT(1) / FT(2); const FT t = FT(3) / FT(4); @@ -449,66 +460,59 @@ bool test_analytic_weight( // Test query points. auto configs = get_all_triangles(); - for (const auto& config : configs) { - if (!test_query(weight, zero, config)) return false; - for (const auto& query : queries) { - if (!test_query(weight, query, config)) return false; - } + for (const auto& config : configs) + { + test_query(weight, zero, config); + for (const auto& query : queries) + test_query(weight, query, config); } // Test alternative formulations. - for (const auto& config : configs) { - if (!test_compare(weight, alternative, zero, config)) { - return false; - } - for (const auto& query : queries) { - if (!test_compare(weight, alternative, query, config)) { - return false; - } - } + for (const auto& config : configs) + { + test_compare(weight, alternative, zero, config); + for (const auto& query : queries) + test_compare(weight, alternative, query, config); } // Test symmetry along x axis. configs = get_symmetric_triangles(); - for (const auto& config : configs) { - if (!test_symmetry_x(weight, config, q)) return false; - if (!test_symmetry_x(weight, config, h)) return false; - if (!test_symmetry_x(weight, config, t)) return false; + for (const auto& config : configs) + { + test_symmetry_x(weight, config, q); + test_symmetry_x(weight, config, h); + test_symmetry_x(weight, config, t); } // Test barycentric properties. - if (weight.is_barycentric()) { + if (weight.is_barycentric()) + { const auto polygons = get_all_polygons(); - for (const auto& polygon : polygons) { - if (!test_barycentric_properties(weight, zero, polygon)) { - return false; - } - for (const auto& query : queries) { - if (!test_barycentric_properties(weight, query, polygon)) { - return false; - } - } + for (const auto& polygon : polygons) + { + test_barycentric_properties(weight, zero, polygon); + for (const auto& query : queries) + test_barycentric_properties(weight, query, polygon); } } - return true; + + return; } -template< -typename Kernel, -typename Weight_wrapper_1, -typename Weight_wrapper_2> -bool test_barycentric_weight( - const Weight_wrapper_1& weight, - const Weight_wrapper_2& alternative) { - +template +void test_barycentric_weight(const Weight_wrapper_1& weight, + const Weight_wrapper_2& alternative) +{ using FT = typename Kernel::FT; using Point_2 = typename Kernel::Point_2; - // Data. const FT q = FT(1) / FT(4); const FT h = FT(1) / FT(2); const Point_2 zero(0, 0); - const std::vector queries = { + const std::vector queries = + { Point_2(-h, 0), Point_2(+h, 0), Point_2(-q, 0), Point_2(+q, 0), Point_2( 0, -h), Point_2( 0, +h), Point_2( 0, -q), Point_2( 0, +q), Point_2(-h, -h), Point_2(+h, +h), Point_2(-q, -q), Point_2(+q, +q), @@ -516,40 +520,29 @@ bool test_barycentric_weight( }; // Test analytic formulations. - if (!test_analytic_weight(weight, alternative)) { - return false; - } + test_analytic_weight(weight, alternative); // Test on polygons. const auto polygons = get_all_polygons(); - for (const auto& polygon : polygons) { - if (!test_on_polygon(weight, zero, polygon)) return false; - for (const auto& query : queries) { - if (!test_on_polygon(weight, query, polygon)) { - return false; - } - } + for (const auto& polygon : polygons) + { + test_on_polygon(weight, zero, polygon); + for (const auto& query : queries) + test_on_polygon(weight, query, polygon); } - return true; } -template< -typename Kernel, -typename Weight_wrapper> -bool test_region_weight(const Weight_wrapper& weight) { - - // Test neighborhoods. +template +void test_region_weight(const Weight_wrapper& weight) +{ auto configs = get_all_triangles(); - for (const auto& config : configs) { - if (!test_neighbors(weight, config)) return false; - } + for (const auto& config : configs) + test_neighbors(weight, config); - // Test areas. configs = get_uniform_triangles(); - for (const auto& config : configs) { - if (!test_area(weight, config)) return false; - } - return true; + for (const auto& config : configs) + test_area(weight, config); } } // namespace tests diff --git a/Weights/test/Weights/include/wrappers.h b/Weights/test/Weights/include/wrappers.h index 9946236476a..2566a219a6c 100644 --- a/Weights/test/Weights/include/wrappers.h +++ b/Weights/test/Weights/include/wrappers.h @@ -1,261 +1,345 @@ #ifndef CGAL_WEIGHTS_TESTS_WRAPPERS_H #define CGAL_WEIGHTS_TESTS_WRAPPERS_H -// STL includes. +#include "utils.h" + +#include + #include #include -// CGAL includes. -#include - namespace wrappers { template -struct Authalic_wrapper { +struct Authalic_wrapper +{ using FT = typename Kernel::FT; + template - FT weight_a(const Point& t, const Point& r, const Point& p, const Point& q) const { - return CGAL::Weights::authalic_weight(t, r, p, q); + FT weight_a(const Point& p0, const Point& p1, const Point& p2, const Point& q) const + { + return CGAL::Weights::authalic_weight(p0, p1, p2, q); } + template - FT weight_b(const Point& t, const Point& r, const Point& p, const Point& q) const { - return - CGAL::Weights::half_authalic_weight( - CGAL::Weights::cotangent(t, r, q), - CGAL::Weights::squared_distance(q, r)) + - CGAL::Weights::half_authalic_weight( - CGAL::Weights::cotangent(q, r, p), - CGAL::Weights::squared_distance(q, r)); + FT weight_b(const Point& p0, const Point& p1, const Point& p2, const Point& q) const + { + return CGAL::Weights::half_authalic_weight(CGAL::Weights::cotangent(p0, p1, q), + CGAL::Weights::internal::squared_distance(q, p1)) + + CGAL::Weights::half_authalic_weight(CGAL::Weights::cotangent(q, p1, p2), + CGAL::Weights::internal::squared_distance(q, p1)); } + bool supports_3d() const { return true; } bool is_barycentric() const { return true; } }; template -struct Cotangent_wrapper { +struct Cotangent_wrapper +{ using FT = typename Kernel::FT; + template - FT weight_a(const Point& t, const Point& r, const Point& p, const Point& q) const { - return CGAL::Weights::cotangent_weight(t, r, p, q); + FT weight_a(const Point& p0, const Point& p1, const Point& p2, const Point& q) const + { + return CGAL::Weights::cotangent_weight(p0, p1, p2, q); } + template - FT weight_b(const Point& t, const Point& r, const Point& p, const Point& q) const { - return - CGAL::Weights::half_cotangent_weight( - CGAL::Weights::cotangent(q, t, r)) + - CGAL::Weights::half_cotangent_weight( - CGAL::Weights::cotangent(r, p, q)); + FT weight_b(const Point& p0, const Point& p1, const Point& p2, const Point& q) const + { + return CGAL::Weights::half_cotangent_weight(CGAL::Weights::cotangent(q, p0, p1)) + + CGAL::Weights::half_cotangent_weight(CGAL::Weights::cotangent(p1, p2, q)); } + bool supports_3d() const { return true; } bool is_barycentric() const { return true; } }; template -struct Tangent_wrapper { +struct Tangent_wrapper +{ using FT = typename Kernel::FT; + template - FT weight_a(const Point& t, const Point& r, const Point& p, const Point& q) const { + FT weight_a(const Point& t, const Point& r, const Point& p, const Point& q) const + { return CGAL::Weights::tangent_weight(t, r, p, q); } + template - FT weight_b(const Point& t, const Point& r, const Point& p, const Point& q) const { - return - CGAL::Weights::half_tangent_weight( - CGAL::Weights::distance(r, q), - CGAL::Weights::distance(t, q), - CGAL::Weights::area(r, q, t), - CGAL::Weights::scalar_product(r, q, t)) + - CGAL::Weights::half_tangent_weight( - CGAL::Weights::distance(r, q), - CGAL::Weights::distance(p, q), - CGAL::Weights::area(p, q, r), - CGAL::Weights::scalar_product(p, q, r)); + FT weight_b(const Point& t, const Point& r, const Point& p, const Point& q) const + { + return CGAL::Weights::half_tangent_weight(CGAL::Weights::internal::distance(r, q), + CGAL::Weights::internal::distance(t, q), + CGAL::Weights::internal::area(r, q, t), + CGAL::Weights::internal::scalar_product(r, q, t)) + + CGAL::Weights::half_tangent_weight(CGAL::Weights::internal::distance(r, q), + CGAL::Weights::internal::distance(p, q), + CGAL::Weights::internal::area(p, q, r), + CGAL::Weights::internal::scalar_product(p, q, r)); } + bool supports_3d() const { return true; } bool is_barycentric() const { return true; } }; template -struct Wachspress_wrapper { +struct Wachspress_wrapper +{ using FT = typename Kernel::FT; using Point_2 = typename Kernel::Point_2; using Point_3 = typename Kernel::Point_3; - FT weight_a(const Point_2& t, const Point_2& r, const Point_2& p, const Point_2& q) const { - return CGAL::Weights::wachspress_weight(t, r, p, q); + + FT weight_a(const Point_2& p0, const Point_2& p1, const Point_2& p2, const Point_2& q) const + { + return CGAL::Weights::wachspress_weight(p0, p1, p2, q); } - FT weight_a(const Point_3&, const Point_3&, const Point_3&, const Point_3&) const { + + FT weight_a(const Point_3&, const Point_3&, const Point_3&, const Point_3&) const + { return FT(-1); } + template - FT weight_b(const Point& t, const Point& r, const Point& p, const Point& q) const { - return weight_a(t, r, p, q); + FT weight_b(const Point& p0, const Point& p1, const Point& p2, const Point& q) const + { + return weight_a(p0, p1, p2, q); } + template - void compute_on_polygon( - const Polygon& polygon, const Point& query, const Traits& traits, OutputIterator out) const { + void compute_on_polygon(const Polygon& polygon, + const Point& query, + const Traits& traits, + OutputIterator out) const + { CGAL::Weights::wachspress_weights_2(polygon, query, out, traits); } + bool supports_3d() const { return false; } bool is_barycentric() const { return true; } }; template -struct Discrete_harmonic_wrapper { +struct Discrete_harmonic_wrapper +{ using FT = typename Kernel::FT; using Point_2 = typename Kernel::Point_2; using Point_3 = typename Kernel::Point_3; - FT weight_a(const Point_2& t, const Point_2& r, const Point_2& p, const Point_2& q) const { - return CGAL::Weights::discrete_harmonic_weight(t, r, p, q); + + FT weight_a(const Point_2& p0, const Point_2& p1, const Point_2& p2, const Point_2& q) const + { + return CGAL::Weights::discrete_harmonic_weight(p0, p1, p2, q); } - FT weight_a(const Point_3&, const Point_3&, const Point_3&, const Point_3&) const { + + FT weight_a(const Point_3&, const Point_3&, const Point_3&, const Point_3&) const + { return FT(-1); } + template - FT weight_b(const Point& t, const Point& r, const Point& p, const Point& q) const { - return weight_a(t, r, p, q); + FT weight_b(const Point& p0, const Point& p1, const Point& p2, const Point& q) const + { + return weight_a(p0, p1, p2, q); } + template - void compute_on_polygon( - const Polygon& polygon, const Point& query, const Traits& traits, OutputIterator out) const { + void compute_on_polygon(const Polygon& polygon, + const Point& query, + const Traits& traits, + OutputIterator out) const + { CGAL::Weights::discrete_harmonic_weights_2(polygon, query, out, traits); } + bool supports_3d() const { return false; } bool is_barycentric() const { return true; } }; template -struct Mean_value_wrapper { +struct Mean_value_wrapper +{ using FT = typename Kernel::FT; using Point_2 = typename Kernel::Point_2; using Point_3 = typename Kernel::Point_3; - FT weight_a(const Point_2& t, const Point_2& r, const Point_2& p, const Point_2& q) const { + + FT weight_a(const Point_2& t, const Point_2& r, const Point_2& p, const Point_2& q) const + { return CGAL::Weights::mean_value_weight(t, r, p, q); } - FT weight_a(const Point_3&, const Point_3&, const Point_3&, const Point_3&) const { + + FT weight_a(const Point_3&, const Point_3&, const Point_3&, const Point_3&) const + { return FT(-1); } + template - FT weight_b(const Point& t, const Point& r, const Point& p, const Point& q) const { + FT weight_b(const Point& t, const Point& r, const Point& p, const Point& q) const + { return weight_a(t, r, p, q); } + template - void compute_on_polygon( - const Polygon& polygon, const Point& query, const Traits& traits, OutputIterator out) const { + void compute_on_polygon(const Polygon& polygon, + const Point& query, + const Traits& traits, + OutputIterator out) const + { CGAL::Weights::mean_value_weights_2(polygon, query, out, traits); } + bool supports_3d() const { return false; } bool is_barycentric() const { return true; } }; template -struct Three_point_family_wrapper { +struct Three_point_family_wrapper +{ using FT = typename Kernel::FT; using Point_2 = typename Kernel::Point_2; using Point_3 = typename Kernel::Point_3; + const FT a; + Three_point_family_wrapper(const FT a) : a(a) { } - FT weight_a(const Point_2& t, const Point_2& r, const Point_2& p, const Point_2& q) const { + FT weight_a(const Point_2& t, const Point_2& r, const Point_2& p, const Point_2& q) const + { return CGAL::Weights::three_point_family_weight(t, r, p, q, a); } - FT weight_a(const Point_3&, const Point_3&, const Point_3&, const Point_3&) const { + + FT weight_a(const Point_3&, const Point_3&, const Point_3&, const Point_3&) const + { return FT(-1); } + template - FT weight_b(const Point& t, const Point& r, const Point& p, const Point& q) const { + FT weight_b(const Point& t, const Point& r, const Point& p, const Point& q) const + { return weight_a(t, r, p, q); } + bool supports_3d() const { return false; } bool is_barycentric() const { return true; } }; template -struct Uniform_region_wrapper { +struct Uniform_region_wrapper +{ using FT = typename Kernel::FT; template - FT weight(const Point& p, const Point& q, const Point& r) const { + FT weight(const Point& p, const Point& q, const Point& r) const + { return CGAL::Weights::uniform_area(p, q, r); } }; template -struct Triangular_region_wrapper { +struct Triangular_region_wrapper +{ using FT = typename Kernel::FT; template - FT weight(const Point& p, const Point& q, const Point& r) const { + FT weight(const Point& p, const Point& q, const Point& r) const + { return CGAL::Weights::triangular_area(p, q, r); } }; template -struct Barycentric_region_wrapper { +struct Barycentric_region_wrapper +{ using FT = typename Kernel::FT; template - FT weight(const Point& p, const Point& q, const Point& r) const { + FT weight(const Point& p, const Point& q, const Point& r) const + { return CGAL::Weights::barycentric_area(p, q, r); } }; template -struct Voronoi_region_wrapper { +struct Voronoi_region_wrapper +{ using FT = typename Kernel::FT; template - FT weight(const Point& p, const Point& q, const Point& r) const { + FT weight(const Point& p, const Point& q, const Point& r) const + { return CGAL::Weights::voronoi_area(p, q, r); } }; template -struct Mixed_voronoi_region_wrapper { +struct Mixed_voronoi_region_wrapper +{ using FT = typename Kernel::FT; template - FT weight(const Point& p, const Point& q, const Point& r) const { + FT weight(const Point& p, const Point& q, const Point& r) const + { return CGAL::Weights::mixed_voronoi_area(p, q, r); } }; template -struct Uniform_wrapper { +struct Uniform_wrapper +{ using FT = typename Kernel::FT; + template - FT weight_a(const Point& t, const Point& r, const Point& p, const Point& q) const { + FT weight_a(const Point& t, const Point& r, const Point& p, const Point& q) const + { return CGAL::Weights::uniform_weight(t, r, p, q); } + template - FT weight_b(const Point& t, const Point& r, const Point& p, const Point& q) const { + FT weight_b(const Point& t, const Point& r, const Point& p, const Point& q) const + { return weight_a(t, r, p, q); } + bool supports_3d() const { return true; } bool is_barycentric() const { return false; } }; template -struct Inverse_distance_wrapper { +struct Inverse_distance_wrapper +{ using FT = typename Kernel::FT; + template - FT weight_a(const Point& t, const Point& r, const Point& p, const Point& q) const { + FT weight_a(const Point& t, const Point& r, const Point& p, const Point& q) const + { return CGAL::Weights::inverse_distance_weight(t, r, p, q); } + template - FT weight_b(const Point& t, const Point& r, const Point& p, const Point& q) const { + FT weight_b(const Point& t, const Point& r, const Point& p, const Point& q) const + { return weight_a(t, r, p, q); } + bool supports_3d() const { return true; } bool is_barycentric() const { return false; } }; template -struct Shepard_wrapper { +struct Shepard_wrapper +{ using FT = typename Kernel::FT; + const FT a; + Shepard_wrapper(const FT a) : a(a) { } + template - FT weight_a(const Point& t, const Point& r, const Point& p, const Point& q) const { + FT weight_a(const Point& t, const Point& r, const Point& p, const Point& q) const + { return CGAL::Weights::shepard_weight(t, r, p, q, a); } + template - FT weight_b(const Point& t, const Point& r, const Point& p, const Point& q) const { + FT weight_b(const Point& t, const Point& r, const Point& p, const Point& q) const + { return weight_a(t, r, p, q); } + bool supports_3d() const { return true; } bool is_barycentric() const { return false; } }; diff --git a/Weights/test/Weights/test_authalic_weights.cpp b/Weights/test/Weights/test_authalic_weights.cpp index 1aa439a3523..68aa6553417 100644 --- a/Weights/test/Weights/test_authalic_weights.cpp +++ b/Weights/test/Weights/test_authalic_weights.cpp @@ -1,26 +1,29 @@ +#include "include/utils.h" +#include "include/wrappers.h" + #include #include #include -#include "include/utils.h" -#include "include/wrappers.h" - -// Typedefs. using SCKER = CGAL::Simple_cartesian; using EPICK = CGAL::Exact_predicates_inexact_constructions_kernel; using EPECK = CGAL::Exact_predicates_exact_constructions_kernel; template -bool test_kernel() { +void test_kernel() +{ const wrappers::Authalic_wrapper aut; const wrappers::Wachspress_wrapper whp; - return tests::test_analytic_weight(aut, whp); + const wrappers::Three_point_family_wrapper tpf(0); + tests::test_analytic_weight(aut, whp); + tests::test_analytic_weight(aut, tpf); } -int main() { - assert(test_kernel()); - assert(test_kernel()); - assert(test_kernel()); +int main(int, char**) +{ + test_kernel(); + test_kernel(); + test_kernel(); std::cout << "* test_authalic_weights: SUCCESS" << std::endl; return EXIT_SUCCESS; } diff --git a/Weights/test/Weights/test_barycentric_region_weights.cpp b/Weights/test/Weights/test_barycentric_region_weights.cpp index 49be26810bf..39dfebe8c39 100644 --- a/Weights/test/Weights/test_barycentric_region_weights.cpp +++ b/Weights/test/Weights/test_barycentric_region_weights.cpp @@ -1,25 +1,48 @@ +#include "include/utils.h" +#include "include/wrappers.h" + #include #include #include -#include "include/utils.h" -#include "include/wrappers.h" - -// Typedefs. using SCKER = CGAL::Simple_cartesian; using EPICK = CGAL::Exact_predicates_inexact_constructions_kernel; using EPECK = CGAL::Exact_predicates_exact_constructions_kernel; template -bool test_kernel() { +void test_kernel() +{ + using FT = typename Kernel::FT; + using Point_2 = typename Kernel::Point_2; + using Point_3 = typename Kernel::Point_3; + + const Point_2 p( 1, 0); + const Point_2 q( 0, 6); + const Point_2 r(-1, 0); + const FT w1 = CGAL::Weights::barycentric_area(p, q, r); + const FT w2 = CGAL::Weights::barycentric_area(r, p, q); + const FT w3 = CGAL::Weights::barycentric_area(q, r, p); + assert(w1 == FT(2)); // medians subdivide a triangle into 6 triangles of equal areas + assert(w1 == w2 && w2 == w3); + + const Point_3 s( 0, -1, 0); + const Point_3 t( 0, 0, 6); + const Point_3 u( 0, 1, 0); + const FT w4 = CGAL::Weights::barycentric_area(s, t, u); + const FT w5 = CGAL::Weights::barycentric_area(t, u, s); + const FT w6 = CGAL::Weights::barycentric_area(u, s, t); + assert(w4 == FT(2)); + assert(w4 == w5 && w5 == w6); + const wrappers::Barycentric_region_wrapper bar; - return tests::test_region_weight(bar); + tests::test_region_weight(bar); } -int main() { - assert(test_kernel()); - assert(test_kernel()); - assert(test_kernel()); +int main(int, char**) +{ + test_kernel(); + test_kernel(); + test_kernel(); std::cout << "* test_barycentric_region_weights: SUCCESS" << std::endl; return EXIT_SUCCESS; } diff --git a/Weights/test/Weights/test_cotangent_weights.cpp b/Weights/test/Weights/test_cotangent_weights.cpp index 962ed140c44..e1bcb98da72 100644 --- a/Weights/test/Weights/test_cotangent_weights.cpp +++ b/Weights/test/Weights/test_cotangent_weights.cpp @@ -1,26 +1,39 @@ +#include "include/utils.h" +#include "include/wrappers.h" + #include #include #include -#include "include/utils.h" -#include "include/wrappers.h" - -// Typedefs. using SCKER = CGAL::Simple_cartesian; using EPICK = CGAL::Exact_predicates_inexact_constructions_kernel; using EPECK = CGAL::Exact_predicates_exact_constructions_kernel; template -bool test_kernel() { +void test_kernel() +{ + using FT = typename Kernel::FT; + using Point_2 = typename Kernel::Point_2; + + const Point_2 p0(-2, 1); + const Point_2 p1( 0, 1); + const Point_2 p2( 0, 3); + const Point_2 q( -2, 3); + const FT w = CGAL::Weights::cotangent_weight(p0, p1, p2, q); + assert(w == FT(0)); + const wrappers::Cotangent_wrapper cot; const wrappers::Discrete_harmonic_wrapper dhw; - return tests::test_analytic_weight(cot, dhw); + const wrappers::Three_point_family_wrapper tpf(2); + tests::test_analytic_weight(cot, dhw); + tests::test_analytic_weight(cot, tpf); } -int main() { - assert(test_kernel()); - assert(test_kernel()); - assert(test_kernel()); +int main(int, char**) +{ + test_kernel(); + test_kernel(); + test_kernel(); std::cout << "* test_cotangent_weights: SUCCESS" << std::endl; return EXIT_SUCCESS; } diff --git a/Weights/test/Weights/test_discrete_harmonic_weights.cpp b/Weights/test/Weights/test_discrete_harmonic_weights.cpp index b49d7beac51..f358f412191 100644 --- a/Weights/test/Weights/test_discrete_harmonic_weights.cpp +++ b/Weights/test/Weights/test_discrete_harmonic_weights.cpp @@ -1,17 +1,17 @@ +#include "include/utils.h" +#include "include/wrappers.h" + #include #include #include -#include "include/utils.h" -#include "include/wrappers.h" - -// Typedefs. using SCKER = CGAL::Simple_cartesian; using EPICK = CGAL::Exact_predicates_inexact_constructions_kernel; using EPECK = CGAL::Exact_predicates_exact_constructions_kernel; template -void test_overloads() { +void test_overloads() +{ using FT = typename Kernel::FT; using Point_2 = typename Kernel::Point_2; using Point_3 = typename Kernel::Point_3; @@ -19,36 +19,42 @@ void test_overloads() { const Point_2 r1( 0, -1); const Point_2 p1( 1, 0); const Point_2 q1( 0, 0); + const Point_3 t2(-1, 0, 1); const Point_3 r2( 0, -1, 1); const Point_3 p2( 1, 0, 1); const Point_3 q2( 0, 0, 1); + const FT a2 = CGAL::Weights::discrete_harmonic_weight(t1, r1, p1, q1); - const FT a3 = CGAL::Weights::internal::discrete_harmonic_weight(t2, r2, p2, q2); - assert(a2 >= FT(0)); - assert(a3 >= FT(0)); + const FT a3 = CGAL::Weights::discrete_harmonic_weight(t2, r2, p2, q2); + assert(a2 == FT(4)); + assert(a3 == FT(4)); assert(a2 == a3); + struct Traits : public Kernel { }; assert(CGAL::Weights::discrete_harmonic_weight(t1, r1, p1, q1, Traits()) == a2); - assert(CGAL::Weights::internal::discrete_harmonic_weight(t2, r2, p2, q2, Traits()) == a3); + assert(CGAL::Weights::discrete_harmonic_weight(t2, r2, p2, q2, Traits()) == a3); + CGAL::Projection_traits_xy_3 ptraits; const FT a23 = CGAL::Weights::discrete_harmonic_weight(t2, r2, p2, q2, ptraits); - assert(a23 >= FT(0)); - assert(a23 == a2 && a23 == a3); + assert(a23 == FT(4)); + assert(a23 == a2); } template -bool test_kernel() { +void test_kernel() +{ test_overloads(); const wrappers::Discrete_harmonic_wrapper dhw; const wrappers::Cotangent_wrapper cot; - return tests::test_barycentric_weight(dhw, cot); + tests::test_barycentric_weight(dhw, cot); } -int main() { - assert(test_kernel()); - assert(test_kernel()); - assert(test_kernel()); +int main(int, char**) +{ + test_kernel(); + test_kernel(); + test_kernel(); std::cout << "* test_discrete_harmonic_weights: SUCCESS" << std::endl; return EXIT_SUCCESS; } diff --git a/Weights/test/Weights/test_inverse_distance_weights.cpp b/Weights/test/Weights/test_inverse_distance_weights.cpp index a19dec04749..5cccd29824b 100644 --- a/Weights/test/Weights/test_inverse_distance_weights.cpp +++ b/Weights/test/Weights/test_inverse_distance_weights.cpp @@ -1,47 +1,53 @@ +#include "include/utils.h" +#include "include/wrappers.h" + #include #include #include -#include "include/utils.h" -#include "include/wrappers.h" - -// Typedefs. using SCKER = CGAL::Simple_cartesian; using EPICK = CGAL::Exact_predicates_inexact_constructions_kernel; using EPECK = CGAL::Exact_predicates_exact_constructions_kernel; template -void test_overloads() { +void test_overloads() +{ using FT = typename Kernel::FT; using Point_2 = typename Kernel::Point_2; using Point_3 = typename Kernel::Point_3; const Point_2 p1(0, 0); - const Point_2 q1(1, 0); + const Point_2 q1(2, 0); const Point_3 p2(0, 0, 1); - const Point_3 q2(1, 0, 1); - const FT a2 = CGAL::Weights::inverse_distance_weight(p1, q1); - const FT a3 = CGAL::Weights::inverse_distance_weight(p2, q2); - assert(a2 == FT(1)); - assert(a3 == FT(1)); - assert(CGAL::Weights::inverse_distance_weight(p1, p1, q1, q1) == a2); - assert(CGAL::Weights::inverse_distance_weight(p2, p2, q2, q2) == a3); + const Point_3 q2(2, 0, 1); + + const FT w1 = CGAL::Weights::inverse_distance_weight(p1, q1); + const FT w2 = CGAL::Weights::inverse_distance_weight(p2, q2); + assert(w1 == FT(1) / FT(2)); + assert(w2 == FT(1) / FT(2)); + assert(CGAL::Weights::inverse_distance_weight(p1, p1, q1, q1) == w1); + assert(CGAL::Weights::inverse_distance_weight(p2, p2, q2, q2) == w2); + struct Traits : public Kernel { }; - assert(CGAL::Weights::inverse_distance_weight(p1, p1, q1, q1, Traits()) == a2); - assert(CGAL::Weights::inverse_distance_weight(p2, p2, q2, q2, Traits()) == a3); + assert(CGAL::Weights::inverse_distance_weight(p1, q1, Traits()) == w1); + assert(CGAL::Weights::inverse_distance_weight(p2, q2, Traits()) == w2); + assert(CGAL::Weights::inverse_distance_weight(p1, p1, q1, q1, Traits()) == w1); + assert(CGAL::Weights::inverse_distance_weight(p2, p2, q2, q2, Traits()) == w2); } template -bool test_kernel() { +void test_kernel() +{ test_overloads(); const wrappers::Inverse_distance_wrapper idw; const wrappers::Shepard_wrapper spw(1); - return tests::test_analytic_weight(idw, spw); + tests::test_analytic_weight(idw, spw); } -int main() { - assert(test_kernel()); - assert(test_kernel()); - assert(test_kernel()); +int main(int, char**) +{ + test_kernel(); + test_kernel(); + test_kernel(); std::cout << "* test_inverse_distance_weights: SUCCESS" << std::endl; return EXIT_SUCCESS; } diff --git a/Weights/test/Weights/test_mean_value_weights.cpp b/Weights/test/Weights/test_mean_value_weights.cpp index 883ff79d591..74ec6ffa4a5 100644 --- a/Weights/test/Weights/test_mean_value_weights.cpp +++ b/Weights/test/Weights/test_mean_value_weights.cpp @@ -1,17 +1,17 @@ +#include "include/utils.h" +#include "include/wrappers.h" + #include #include #include -#include "include/utils.h" -#include "include/wrappers.h" - -// Typedefs. using SCKER = CGAL::Simple_cartesian; using EPICK = CGAL::Exact_predicates_inexact_constructions_kernel; using EPECK = CGAL::Exact_predicates_exact_constructions_kernel; template -void test_overloads() { +void test_overloads() +{ using FT = typename Kernel::FT; using Point_2 = typename Kernel::Point_2; using Point_3 = typename Kernel::Point_3; @@ -23,14 +23,16 @@ void test_overloads() { const Point_3 r2( 0, -1, 1); const Point_3 p2( 1, 0, 1); const Point_3 q2( 0, 0, 1); + const FT a2 = CGAL::Weights::mean_value_weight(t1, r1, p1, q1); - const FT a3 = CGAL::Weights::internal::mean_value_weight(t2, r2, p2, q2); + const FT a3 = CGAL::Weights::mean_value_weight(t2, r2, p2, q2); assert(a2 >= FT(0)); assert(a3 >= FT(0)); assert(a2 == a3); + struct Traits : public Kernel { }; assert(CGAL::Weights::mean_value_weight(t1, r1, p1, q1, Traits()) == a2); - assert(CGAL::Weights::internal::mean_value_weight(t2, r2, p2, q2, Traits()) == a3); + assert(CGAL::Weights::mean_value_weight(t2, r2, p2, q2, Traits()) == a3); CGAL::Projection_traits_xy_3 ptraits; const FT a23 = CGAL::Weights::mean_value_weight(t2, r2, p2, q2, ptraits); assert(a23 >= FT(0)); @@ -38,17 +40,21 @@ void test_overloads() { } template -bool test_kernel() { +void test_kernel() +{ test_overloads(); const wrappers::Mean_value_wrapper mvw; const wrappers::Tangent_wrapper tan; - return tests::test_barycentric_weight(mvw, tan); + const wrappers::Three_point_family_wrapper tpf(1); + tests::test_barycentric_weight(mvw, tan); + tests::test_barycentric_weight(mvw, tpf); } -int main() { - assert(test_kernel()); - assert(test_kernel()); - assert(test_kernel()); +int main(int, char**) +{ + test_kernel(); + test_kernel(); + test_kernel(); std::cout << "* test_mean_value_weights: SUCCESS" << std::endl; return EXIT_SUCCESS; } diff --git a/Weights/test/Weights/test_mixed_voronoi_region_weights.cpp b/Weights/test/Weights/test_mixed_voronoi_region_weights.cpp index 3c78f1f18a2..d0c6571d95e 100644 --- a/Weights/test/Weights/test_mixed_voronoi_region_weights.cpp +++ b/Weights/test/Weights/test_mixed_voronoi_region_weights.cpp @@ -1,25 +1,26 @@ +#include "include/utils.h" +#include "include/wrappers.h" + #include #include #include -#include "include/utils.h" -#include "include/wrappers.h" - -// Typedefs. using SCKER = CGAL::Simple_cartesian; using EPICK = CGAL::Exact_predicates_inexact_constructions_kernel; using EPECK = CGAL::Exact_predicates_exact_constructions_kernel; template -bool test_kernel() { +void test_kernel() +{ const wrappers::Mixed_voronoi_region_wrapper mix; - return tests::test_region_weight(mix); + tests::test_region_weight(mix); } -int main() { - assert(test_kernel()); - assert(test_kernel()); - assert(test_kernel()); +int main(int, char**) +{ + test_kernel(); + test_kernel(); + test_kernel(); std::cout << "* test_mixed_voronoi_region_weights: SUCCESS" << std::endl; return EXIT_SUCCESS; } diff --git a/Weights/test/Weights/test_projected_weights.cpp b/Weights/test/Weights/test_projected_weights.cpp index 96d01644499..874bc73d22b 100644 --- a/Weights/test/Weights/test_projected_weights.cpp +++ b/Weights/test/Weights/test_projected_weights.cpp @@ -1,18 +1,19 @@ #include #include #include + #include #include #include #include -// Typedefs. using SCKER = CGAL::Simple_cartesian; using EPICK = CGAL::Exact_predicates_inexact_constructions_kernel; using EPECK = CGAL::Exact_predicates_exact_constructions_kernel; template -void test_kernel() { +void test_kernel() +{ using FT = typename Kernel::FT; using Point_2 = typename Kernel::Point_2; using Point_3 = typename Kernel::Point_3; @@ -110,7 +111,8 @@ void test_kernel() { assert(CGAL::Weights::three_point_family_weight(t3, r3, p3, q3, 1, yz_traits) == ref_value); } -int main() { +int main(int, char**) +{ test_kernel(); test_kernel(); test_kernel(); diff --git a/Weights/test/Weights/test_shepard_weights.cpp b/Weights/test/Weights/test_shepard_weights.cpp index e178b574144..9806892d386 100644 --- a/Weights/test/Weights/test_shepard_weights.cpp +++ b/Weights/test/Weights/test_shepard_weights.cpp @@ -1,49 +1,55 @@ +#include "include/utils.h" +#include "include/wrappers.h" + #include #include #include -#include "include/utils.h" -#include "include/wrappers.h" - -// Typedefs. using SCKER = CGAL::Simple_cartesian; using EPICK = CGAL::Exact_predicates_inexact_constructions_kernel; using EPECK = CGAL::Exact_predicates_exact_constructions_kernel; template -void test_overloads() { +void test_overloads() +{ using FT = typename Kernel::FT; using Point_2 = typename Kernel::Point_2; using Point_3 = typename Kernel::Point_3; + const Point_2 p1(0, 0); - const Point_2 q1(1, 0); + const Point_2 q1(2, 0); const Point_3 p2(0, 0, 1); - const Point_3 q2(1, 0, 1); - const FT a2 = CGAL::Weights::shepard_weight(p1, q1); - const FT a3 = CGAL::Weights::shepard_weight(p2, q2); - assert(a2 == FT(1)); - assert(a3 == FT(1)); - assert(CGAL::Weights::shepard_weight(p1, p1, q1, q1) == a2); - assert(CGAL::Weights::shepard_weight(p2, p2, q2, q2) == a3); + const Point_3 q2(2, 0, 1); + + const FT a2 = CGAL::Weights::shepard_weight(p1, q1, 3); + const FT a3 = CGAL::Weights::shepard_weight(p2, q2, 3); + assert(a2 == FT(1)/FT(8)); + assert(a3 == FT(1)/FT(8)); + + assert(CGAL::Weights::shepard_weight(p1, p1, q1, q1, 3) == a2); + assert(CGAL::Weights::shepard_weight(p2, p2, q2, q2, 3) == a3); + struct Traits : public Kernel { }; - assert(CGAL::Weights::shepard_weight(p1, p1, q1, q1, 1, Traits()) == a2); - assert(CGAL::Weights::shepard_weight(p2, p2, q2, q2, 1, Traits()) == a3); + assert(CGAL::Weights::shepard_weight(p1, p1, q1, q1, 3, Traits()) == a2); + assert(CGAL::Weights::shepard_weight(p2, p2, q2, q2, 3, Traits()) == a3); } template -bool test_kernel() { +void test_kernel() +{ test_overloads(); const wrappers::Shepard_wrapper spwa(1); const wrappers::Shepard_wrapper spwb(2); const wrappers::Inverse_distance_wrapper idw; - assert(tests::test_analytic_weight(spwa, idw)); - return tests::test_analytic_weight(spwb, spwb); + tests::test_analytic_weight(spwa, idw); + tests::test_analytic_weight(spwb, spwb); } -int main() { - assert(test_kernel()); - assert(test_kernel()); - assert(test_kernel()); +int main(int, char**) +{ + test_kernel(); + test_kernel(); + test_kernel(); std::cout << "* test_shepard_weights: SUCCESS" << std::endl; return EXIT_SUCCESS; } diff --git a/Weights/test/Weights/test_tangent_weights.cpp b/Weights/test/Weights/test_tangent_weights.cpp index 8fe08620ad7..aece71cb567 100644 --- a/Weights/test/Weights/test_tangent_weights.cpp +++ b/Weights/test/Weights/test_tangent_weights.cpp @@ -1,26 +1,29 @@ +#include "include/utils.h" +#include "include/wrappers.h" + #include #include #include -#include "include/utils.h" -#include "include/wrappers.h" - -// Typedefs. using SCKER = CGAL::Simple_cartesian; using EPICK = CGAL::Exact_predicates_inexact_constructions_kernel; using EPECK = CGAL::Exact_predicates_exact_constructions_kernel; template -bool test_kernel() { +void test_kernel() +{ const wrappers::Tangent_wrapper tan; const wrappers::Mean_value_wrapper mvw; - return tests::test_analytic_weight(tan, mvw); + const wrappers::Three_point_family_wrapper tpf(1); + tests::test_analytic_weight(tan, mvw); + tests::test_analytic_weight(tan, tpf); } -int main() { - assert(test_kernel()); - assert(test_kernel()); - assert(test_kernel()); +int main(int, char**) +{ + test_kernel(); + test_kernel(); + test_kernel(); std::cout << "* test_tangent_weights: SUCCESS" << std::endl; return EXIT_SUCCESS; } diff --git a/Weights/test/Weights/test_three_point_family_weights.cpp b/Weights/test/Weights/test_three_point_family_weights.cpp index e6ebfb0f64b..85f231b7eb0 100644 --- a/Weights/test/Weights/test_three_point_family_weights.cpp +++ b/Weights/test/Weights/test_three_point_family_weights.cpp @@ -1,17 +1,17 @@ +#include "include/utils.h" +#include "include/wrappers.h" + #include #include #include -#include "include/utils.h" -#include "include/wrappers.h" - -// Typedefs. using SCKER = CGAL::Simple_cartesian; using EPICK = CGAL::Exact_predicates_inexact_constructions_kernel; using EPECK = CGAL::Exact_predicates_exact_constructions_kernel; template -void test_overloads() { +void test_overloads() +{ using FT = typename Kernel::FT; using Point_2 = typename Kernel::Point_2; using Point_3 = typename Kernel::Point_3; @@ -23,14 +23,16 @@ void test_overloads() { const Point_3 r2( 0, -1, 1); const Point_3 p2( 1, 0, 1); const Point_3 q2( 0, 0, 1); + const FT a2 = CGAL::Weights::three_point_family_weight(t1, r1, p1, q1); - const FT a3 = CGAL::Weights::internal::three_point_family_weight(t2, r2, p2, q2); + const FT a3 = CGAL::Weights::three_point_family_weight(t2, r2, p2, q2); assert(a2 >= FT(0)); assert(a3 >= FT(0)); assert(a2 == a3); + struct Traits : public Kernel { }; assert(CGAL::Weights::three_point_family_weight(t1, r1, p1, q1, 1, Traits()) == a2); - assert(CGAL::Weights::internal::three_point_family_weight(t2, r2, p2, q2, 1, Traits()) == a3); + assert(CGAL::Weights::three_point_family_weight(t2, r2, p2, q2, 1, Traits()) == a3); CGAL::Projection_traits_xy_3 ptraits; const FT a23 = CGAL::Weights::three_point_family_weight(t2, r2, p2, q2, 0, ptraits); assert(a23 >= FT(0)); @@ -38,7 +40,8 @@ void test_overloads() { } template -bool test_kernel() { +void test_kernel() +{ test_overloads(); using FT = typename Kernel::FT; const FT h = FT(1) / FT(2); @@ -49,16 +52,18 @@ bool test_kernel() { const wrappers::Wachspress_wrapper whp; const wrappers::Mean_value_wrapper mvw; const wrappers::Discrete_harmonic_wrapper dhw; - assert(tests::test_analytic_weight(tpfa, whp)); - assert(tests::test_analytic_weight(tpfb, mvw)); - assert(tests::test_analytic_weight(tpfc, dhw)); - return tests::test_analytic_weight(tpfd, tpfd); + + tests::test_analytic_weight(tpfa, whp); + tests::test_analytic_weight(tpfb, mvw); + tests::test_analytic_weight(tpfc, dhw); + tests::test_analytic_weight(tpfd, tpfd); } -int main() { - assert(test_kernel()); - assert(test_kernel()); - assert(test_kernel()); +int main(int, char**) +{ + test_kernel(); + test_kernel(); + test_kernel(); std::cout << "* test_three_point_family_weights: SUCCESS" << std::endl; return EXIT_SUCCESS; } diff --git a/Weights/test/Weights/test_triangular_region_weights.cpp b/Weights/test/Weights/test_triangular_region_weights.cpp index c6bde65c492..bafdc2ed189 100644 --- a/Weights/test/Weights/test_triangular_region_weights.cpp +++ b/Weights/test/Weights/test_triangular_region_weights.cpp @@ -1,25 +1,26 @@ +#include "include/utils.h" +#include "include/wrappers.h" + #include #include #include -#include "include/utils.h" -#include "include/wrappers.h" - -// Typedefs. using SCKER = CGAL::Simple_cartesian; using EPICK = CGAL::Exact_predicates_inexact_constructions_kernel; using EPECK = CGAL::Exact_predicates_exact_constructions_kernel; template -bool test_kernel() { +void test_kernel() +{ const wrappers::Triangular_region_wrapper tri; - return tests::test_region_weight(tri); + tests::test_region_weight(tri); } -int main() { - assert(test_kernel()); - assert(test_kernel()); - assert(test_kernel()); +int main(int, char**) +{ + test_kernel(); + test_kernel(); + test_kernel(); std::cout << "* test_triangular_region_weights: SUCCESS" << std::endl; return EXIT_SUCCESS; } diff --git a/Weights/test/Weights/test_uniform_region_weights.cpp b/Weights/test/Weights/test_uniform_region_weights.cpp index 52124ede996..71d25a9a555 100644 --- a/Weights/test/Weights/test_uniform_region_weights.cpp +++ b/Weights/test/Weights/test_uniform_region_weights.cpp @@ -1,17 +1,17 @@ +#include "include/utils.h" +#include "include/wrappers.h" + #include #include #include -#include "include/utils.h" -#include "include/wrappers.h" - -// Typedefs. using SCKER = CGAL::Simple_cartesian; using EPICK = CGAL::Exact_predicates_inexact_constructions_kernel; using EPECK = CGAL::Exact_predicates_exact_constructions_kernel; template -void test_overloads() { +void test_overloads() +{ using FT = typename Kernel::FT; using Point_2 = typename Kernel::Point_2; using Point_3 = typename Kernel::Point_3; @@ -20,22 +20,25 @@ void test_overloads() { const Point_3 q(0, 0, 0); assert(CGAL::Weights::uniform_area(p, p, p) == a); assert(CGAL::Weights::uniform_area(q, q, q) == a); + struct Traits : public Kernel { }; assert(CGAL::Weights::uniform_area(p, p, p, Traits()) == a); assert(CGAL::Weights::uniform_area(q, q, q, Traits()) == a); } template -bool test_kernel() { +void test_kernel() +{ test_overloads(); const wrappers::Uniform_region_wrapper uni; - return tests::test_region_weight(uni); + tests::test_region_weight(uni); } -int main() { - assert(test_kernel()); - assert(test_kernel()); - assert(test_kernel()); +int main(int, char**) +{ + test_kernel(); + test_kernel(); + test_kernel(); std::cout << "* test_uniform_region_weights: SUCCESS" << std::endl; return EXIT_SUCCESS; } diff --git a/Weights/test/Weights/test_uniform_weights.cpp b/Weights/test/Weights/test_uniform_weights.cpp index 68ae5af005c..00501f1f13d 100644 --- a/Weights/test/Weights/test_uniform_weights.cpp +++ b/Weights/test/Weights/test_uniform_weights.cpp @@ -1,41 +1,46 @@ +#include "include/utils.h" +#include "include/wrappers.h" + #include #include #include -#include "include/utils.h" -#include "include/wrappers.h" - -// Typedefs. using SCKER = CGAL::Simple_cartesian; using EPICK = CGAL::Exact_predicates_inexact_constructions_kernel; using EPECK = CGAL::Exact_predicates_exact_constructions_kernel; template -void test_overloads() { +void test_overloads() +{ using FT = typename Kernel::FT; using Point_2 = typename Kernel::Point_2; using Point_3 = typename Kernel::Point_3; + const FT a = FT(1); const Point_2 p(0, 0); const Point_3 q(0, 0, 0); + assert(CGAL::Weights::uniform_weight(p, p, p, p) == a); assert(CGAL::Weights::uniform_weight(q, q, q, q) == a); + struct Traits : public Kernel { }; assert(CGAL::Weights::uniform_weight(p, p, p, p, Traits()) == a); assert(CGAL::Weights::uniform_weight(q, q, q, q, Traits()) == a); } template -bool test_kernel() { +void test_kernel() +{ test_overloads(); const wrappers::Uniform_wrapper uni; - return tests::test_analytic_weight(uni, uni); + tests::test_analytic_weight(uni, uni); } -int main() { - assert(test_kernel()); - assert(test_kernel()); - assert(test_kernel()); +int main(int, char**) +{ + test_kernel(); + test_kernel(); + test_kernel(); std::cout << "* test_uniform_weights: SUCCESS" << std::endl; return EXIT_SUCCESS; } diff --git a/Weights/test/Weights/test_voronoi_region_weights.cpp b/Weights/test/Weights/test_voronoi_region_weights.cpp index a0d6bcc43d4..49b0fe672af 100644 --- a/Weights/test/Weights/test_voronoi_region_weights.cpp +++ b/Weights/test/Weights/test_voronoi_region_weights.cpp @@ -1,25 +1,42 @@ +#include "include/utils.h" +#include "include/wrappers.h" + #include #include #include -#include "include/utils.h" -#include "include/wrappers.h" - -// Typedefs. using SCKER = CGAL::Simple_cartesian; using EPICK = CGAL::Exact_predicates_inexact_constructions_kernel; using EPECK = CGAL::Exact_predicates_exact_constructions_kernel; template -bool test_kernel() { +void test_kernel() +{ + using FT = typename Kernel::FT; + using Point_2 = typename Kernel::Point_2; + using Point_3 = typename Kernel::Point_3; + + const Point_2 p( 2, 0); + const Point_2 q( 0, 2); + const Point_2 r(-2, 0); + const FT w1 = CGAL::Weights::voronoi_area(p, q, r); + assert(w1 == FT(2)); + + const Point_3 s( 0, -2, 0); + const Point_3 t( 0, 0, 2); + const Point_3 u( 0, 2, 0); + const FT w4 = CGAL::Weights::voronoi_area(s, t, u); + assert(w4 == FT(2)); + const wrappers::Voronoi_region_wrapper vor; - return tests::test_region_weight(vor); + tests::test_region_weight(vor); } -int main() { - assert(test_kernel()); - assert(test_kernel()); - assert(test_kernel()); +int main(int, char**) +{ + test_kernel(); + test_kernel(); + test_kernel(); std::cout << "* test_voronoi_region_weights: SUCCESS" << std::endl; return EXIT_SUCCESS; } diff --git a/Weights/test/Weights/test_wachspress_weights.cpp b/Weights/test/Weights/test_wachspress_weights.cpp index 75b43f46437..f370c383745 100644 --- a/Weights/test/Weights/test_wachspress_weights.cpp +++ b/Weights/test/Weights/test_wachspress_weights.cpp @@ -1,17 +1,17 @@ +#include "include/utils.h" +#include "include/wrappers.h" + #include #include #include -#include "include/utils.h" -#include "include/wrappers.h" - -// Typedefs. using SCKER = CGAL::Simple_cartesian; using EPICK = CGAL::Exact_predicates_inexact_constructions_kernel; using EPECK = CGAL::Exact_predicates_exact_constructions_kernel; template -void test_overloads() { +void test_overloads() +{ using FT = typename Kernel::FT; using Point_2 = typename Kernel::Point_2; using Point_3 = typename Kernel::Point_3; @@ -23,32 +23,38 @@ void test_overloads() { const Point_3 r2( 0, -1, 1); const Point_3 p2( 1, 0, 1); const Point_3 q2( 0, 0, 1); + const FT a2 = CGAL::Weights::wachspress_weight(t1, r1, p1, q1); - const FT a3 = CGAL::Weights::internal::wachspress_weight(t2, r2, p2, q2); - assert(a2 >= FT(0)); - assert(a3 >= FT(0)); + const FT a3 = CGAL::Weights::wachspress_weight(t2, r2, p2, q2); + assert(a2 == FT(4)); + assert(a3 == FT(4)); assert(a2 == a3); + struct Traits : public Kernel { }; assert(CGAL::Weights::wachspress_weight(t1, r1, p1, q1, Traits()) == a2); - assert(CGAL::Weights::internal::wachspress_weight(t2, r2, p2, q2, Traits()) == a3); + assert(CGAL::Weights::wachspress_weight(t2, r2, p2, q2, Traits()) == a3); CGAL::Projection_traits_xy_3 ptraits; const FT a23 = CGAL::Weights::wachspress_weight(t2, r2, p2, q2, ptraits); - assert(a23 >= FT(0)); - assert(a23 == a2 && a23 == a3); + assert(a23 == FT(4)); + assert(a23 == a2); } template -bool test_kernel() { +void test_kernel() +{ test_overloads(); const wrappers::Wachspress_wrapper whp; const wrappers::Authalic_wrapper aut; - return tests::test_barycentric_weight(whp, aut); + const wrappers::Three_point_family_wrapper tpf(0); + tests::test_barycentric_weight(whp, aut); + tests::test_barycentric_weight(whp, tpf); } -int main() { - assert(test_kernel()); - assert(test_kernel()); - assert(test_kernel()); +int main(int, char**) +{ + test_kernel(); + test_kernel(); + test_kernel(); std::cout << "* test_wachspress_weights: SUCCESS" << std::endl; return EXIT_SUCCESS; }