Merge branch 'Weights-v2.0-GF-5.5.x' into Weights-v2.0-GF-master
|
|
@ -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)) {
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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)));
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -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
|
||||
<TriangleMesh, SparseLinearSolver, WeightCalculator, VertexPointMap>
|
||||
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
|
||||
<TriangleMesh, SparseLinearSolver, WeightCalculator, VertexPointMap>
|
||||
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<GT>(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<TriangleMesh, VPMap> 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<TriangleMesh, VPMap, GT> Default_weight_calculator;
|
||||
|
||||
return internal::fair(tmesh, vertices,
|
||||
choose_parameter<Default_solver>(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 <CGAL/enable_warnings.h>
|
||||
|
||||
|
|
|
|||
|
|
@ -383,9 +383,9 @@ class Weight_incomplete
|
|||
private:
|
||||
template<class Point_3, class LookupTable>
|
||||
Weight_incomplete(const std::vector<Point_3>& P,
|
||||
const std::vector<Point_3>& Q,
|
||||
int i, int j, int k,
|
||||
const LookupTable& lambda)
|
||||
const std::vector<Point_3>& 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<class Point_3, class LookupTable>
|
||||
Weight operator()(const std::vector<Point_3>& P,
|
||||
const std::vector<Point_3>& Q,
|
||||
int i, int j, int k,
|
||||
const LookupTable& lambda) const
|
||||
const std::vector<Point_3>& Q,
|
||||
int i, int j, int k,
|
||||
const LookupTable& lambda) const
|
||||
{
|
||||
if( !is_valid(P,i,j,k) )
|
||||
{ return Weight::NOT_VALID(); }
|
||||
|
|
|
|||
|
|
@ -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<typename FaceRange>
|
||||
|
|
@ -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<std::size_t, double>::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<double> diagonal_; // index of vector -> index of vimap_
|
||||
std::vector<bool> constrained_flags_;
|
||||
|
||||
const GeomTraits& traits_;
|
||||
const CGAL::Weights::Edge_cotangent_weight<TriangleMesh, VertexPointMap> weight_calculator_;
|
||||
GeomTraits traits_;
|
||||
const CGAL::Weights::Cotangent_weight<TriangleMesh, VertexPointMap, GeomTraits> weight_calculator_;
|
||||
};
|
||||
|
||||
} // internal
|
||||
|
|
|
|||
|
|
@ -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<Face_graph, decltype(vpm), EPICK>(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<Face_graph, decltype(pmap)>(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!"); }
|
||||
|
|
|
|||
|
|
@ -55,49 +55,72 @@ enum Deformation_algorithm_tag
|
|||
/// @cond CGAL_DOCUMENT_INTERNAL
|
||||
namespace internal {
|
||||
|
||||
template<class TriangleMesh, Deformation_algorithm_tag deformation_algorithm_tag>
|
||||
// property map that create a Simple_cartesian<double>::Point_3
|
||||
// on the fly in order the deformation class to be used
|
||||
// with points with minimal requirements
|
||||
template <class Vertex_point_map>
|
||||
struct SC_on_the_fly_pmap
|
||||
: public Vertex_point_map
|
||||
{
|
||||
typedef boost::readable_property_map_tag category;
|
||||
typedef CGAL::Simple_cartesian<double>::Point_3 value_type;
|
||||
typedef value_type reference;
|
||||
typedef typename boost::property_traits<Vertex_point_map>::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<Vertex_point_map>::reference base=
|
||||
get(static_cast<const Vertex_point_map&>(map), k);
|
||||
return value_type(base[0], base[1], base[2]);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename TriangleMesh, typename VertexPointMap,
|
||||
Deformation_algorithm_tag deformation_algorithm_tag>
|
||||
struct Types_selectors;
|
||||
|
||||
template<class TriangleMesh>
|
||||
struct Types_selectors<TriangleMesh, CGAL::SPOKES_AND_RIMS> {
|
||||
template<typename TriangleMesh, typename VertexPointMap>
|
||||
struct Types_selectors<TriangleMesh, VertexPointMap, CGAL::SPOKES_AND_RIMS>
|
||||
{
|
||||
typedef SC_on_the_fly_pmap<VertexPointMap> Wrapped_VertexPointMap;
|
||||
typedef CGAL::Weights::Single_cotangent_weight<TriangleMesh, Wrapped_VertexPointMap> Weight_calculator;
|
||||
|
||||
// Get weight from the weight interface.
|
||||
typedef CGAL::Weights::Single_cotangent_weight<TriangleMesh> Weight_calculator;
|
||||
|
||||
struct ARAP_visitor{
|
||||
template <class VertexPointMap>
|
||||
struct ARAP_visitor
|
||||
{
|
||||
void init(TriangleMesh, VertexPointMap){}
|
||||
|
||||
void rotation_matrix_pre(
|
||||
typename boost::graph_traits<TriangleMesh>::vertex_descriptor,
|
||||
TriangleMesh&){}
|
||||
void rotation_matrix_pre(typename boost::graph_traits<TriangleMesh>::vertex_descriptor,
|
||||
TriangleMesh&){}
|
||||
|
||||
template <class Square_matrix_3>
|
||||
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<class TriangleMesh>
|
||||
struct Types_selectors<TriangleMesh, CGAL::ORIGINAL_ARAP> {
|
||||
template<class TriangleMesh, typename VertexPointMap>
|
||||
struct Types_selectors<TriangleMesh, VertexPointMap, CGAL::ORIGINAL_ARAP>
|
||||
{
|
||||
typedef SC_on_the_fly_pmap<VertexPointMap> Wrapped_VertexPointMap;
|
||||
typedef CGAL::Weights::Cotangent_weight<TriangleMesh, Wrapped_VertexPointMap> Weight_calculator;
|
||||
|
||||
// Get weight from the weight interface.
|
||||
typedef CGAL::Weights::Cotangent_weight<TriangleMesh> Weight_calculator;
|
||||
|
||||
typedef typename Types_selectors<TriangleMesh, CGAL::SPOKES_AND_RIMS>
|
||||
::ARAP_visitor ARAP_visitor;
|
||||
typedef typename Types_selectors<TriangleMesh, VertexPointMap, CGAL::SPOKES_AND_RIMS>::ARAP_visitor ARAP_visitor;
|
||||
};
|
||||
|
||||
template<class TriangleMesh>
|
||||
struct Types_selectors<TriangleMesh, CGAL::SRE_ARAP> {
|
||||
template<class TriangleMesh, typename VertexPointMap>
|
||||
struct Types_selectors<TriangleMesh, VertexPointMap, CGAL::SRE_ARAP>
|
||||
{
|
||||
typedef SC_on_the_fly_pmap<VertexPointMap> Wrapped_VertexPointMap;
|
||||
typedef CGAL::Weights::Cotangent_weight<TriangleMesh, Wrapped_VertexPointMap> Weight_calculator;
|
||||
|
||||
// Get weight from the weight interface.
|
||||
typedef CGAL::Weights::Cotangent_weight<TriangleMesh> 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<TriangleMesh, CGAL::SRE_ARAP> {
|
|||
public:
|
||||
ARAP_visitor(): m_alpha(0.02) {}
|
||||
|
||||
template<class VertexPointMap>
|
||||
void init(TriangleMesh triangle_mesh, const VertexPointMap& vpmap)
|
||||
{
|
||||
// calculate area
|
||||
|
|
@ -144,31 +166,6 @@ struct Types_selectors<TriangleMesh, CGAL::SRE_ARAP> {
|
|||
};
|
||||
};
|
||||
|
||||
// property map that create a Simple_cartesian<double>::Point_3
|
||||
// on the fly in order the deformation class to be used
|
||||
// with points with minimal requirements
|
||||
template <class Vertex_point_map>
|
||||
struct SC_on_the_fly_pmap
|
||||
: public Vertex_point_map
|
||||
{
|
||||
typedef boost::readable_property_map_tag category;
|
||||
typedef CGAL::Simple_cartesian<double>::Point_3 value_type;
|
||||
typedef value_type reference;
|
||||
typedef typename boost::property_traits<Vertex_point_map>::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<Vertex_point_map>::reference base=
|
||||
get(static_cast<const Vertex_point_map&>(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<TM, TAG>::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<Triangle_mesh, Vertex_point_map, TAG>::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<Triangle_mesh>::vertex_descriptor vertex_descriptor;
|
||||
/// The type for halfedge descriptor
|
||||
|
|
@ -304,8 +301,6 @@ public:
|
|||
private:
|
||||
typedef Surface_mesh_deformation<TM, VIM, HIM, TAG, WC, ST, CR> Self;
|
||||
// Repeat Triangle_mesh types
|
||||
typedef typename boost::graph_traits<Triangle_mesh>::vertex_iterator vertex_iterator;
|
||||
typedef typename boost::graph_traits<Triangle_mesh>::halfedge_iterator halfedge_iterator;
|
||||
typedef typename boost::graph_traits<Triangle_mesh>::in_edge_iterator in_edge_iterator;
|
||||
typedef typename boost::graph_traits<Triangle_mesh>::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<TM, TAG>::ARAP_visitor arap_visitor;
|
||||
typename internal::Types_selectors<Triangle_mesh, Vertex_point_map, TAG>::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<std::size_t>(num_vertices(triangle_mesh), (std::numeric_limits<std::size_t>::max)() )),
|
||||
is_roi_map(std::vector<bool>(num_vertices(triangle_mesh), false)),
|
||||
is_ctrl_map(std::vector<bool>(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<std::size_t>(num_vertices(triangle_mesh), (std::numeric_limits<std::size_t>::max)() )),
|
||||
is_roi_map(std::vector<bool>(num_vertices(triangle_mesh), false)),
|
||||
is_ctrl_map(std::vector<bool>(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<std::size_t>(num_vertices(triangle_mesh), (std::numeric_limits<std::size_t>::max)() )),
|
||||
is_roi_map(std::vector<bool>(num_vertices(triangle_mesh), false)),
|
||||
is_ctrl_map(std::vector<bool>(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>(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<Vertex_point_map> 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<Vertex_point_map> 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;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -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<Kernel>(uv1.x()-uv0.x(), uv1.y()-uv0.y()),
|
||||
Vector_2<Kernel>(uv2.x()-uv0.x(), uv2.y()-uv0.y()));
|
||||
NT det3 = CGAL::determinant(Vector_2<Kernel>(uv1.x()-uv0.x(), uv1.y()-uv0.y()),
|
||||
Vector_2<Kernel>(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<Triangle_mesh, decltype(vpm)> compute_mvc(tmesh, vpm);
|
||||
const CGAL::Weights::Edge_tangent_weight<Triangle_mesh, decltype(vpm), Kernel> 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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -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<SeamMesh> cotangent_weight;
|
||||
const NT w_ij = NT(2) * cotangent_weight(hd, mesh, pmap);
|
||||
if (i > j)
|
||||
continue;
|
||||
|
||||
const CGAL::Weights::Cotangent_weight<SeamMesh, PPM> 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 */);
|
||||
|
|
|
|||
|
|
@ -235,7 +235,7 @@ public:
|
|||
typedef typename boost::graph_traits<mTriangleMesh>::edge_iterator edge_iterator;
|
||||
|
||||
// Get weight from the weight interface.
|
||||
typedef CGAL::Weights::Cotangent_weight<mTriangleMesh> Weight_calculator;
|
||||
typedef CGAL::Weights::Cotangent_weight<mTriangleMesh, mVertexPointMap, Traits> Weight_calculator;
|
||||
|
||||
typedef internal::Curve_skeleton<mTriangleMesh,
|
||||
VertexIndexMap,
|
||||
|
|
@ -383,17 +383,19 @@ public:
|
|||
Mean_curvature_flow_skeletonization(const TriangleMesh& tmesh,
|
||||
VertexPointMap vertex_point_map,
|
||||
const Traits& traits = Traits())
|
||||
: m_traits(traits), m_weight_calculator(true /* use_clamped_version */)
|
||||
:
|
||||
m_tmesh(),
|
||||
m_tmesh_point_pmap(get(CGAL::vertex_point, m_tmesh)),
|
||||
m_traits(traits),
|
||||
m_weight_calculator(m_tmesh, m_tmesh_point_pmap, m_traits, true /* use_clamped_version */)
|
||||
{
|
||||
init(tmesh, vertex_point_map);
|
||||
}
|
||||
|
||||
Mean_curvature_flow_skeletonization(const TriangleMesh& tmesh,
|
||||
const Traits& traits = Traits())
|
||||
: m_traits(traits), m_weight_calculator(true /* use_clamped_version */)
|
||||
{
|
||||
init(tmesh, get(vertex_point, tmesh));
|
||||
}
|
||||
: Mean_curvature_flow_skeletonization(tmesh, get(vertex_point, tmesh), traits)
|
||||
{ }
|
||||
#endif
|
||||
/// @} Constructor
|
||||
|
||||
|
|
@ -871,8 +873,8 @@ private:
|
|||
typedef std::pair<Input_vertex_descriptor, vertex_descriptor> Vertex_pair;
|
||||
std::vector<Vertex_pair> 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.
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -1,235 +1,439 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Generator: Adobe Illustrator 24.0.3, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||
width="501.3px" height="161.7px" viewBox="0 0 501.3 161.7" style="enable-background:new 0 0 501.3 161.7;" xml:space="preserve"
|
||||
>
|
||||
<style type="text/css">
|
||||
|
||||
<svg
|
||||
version="1.1"
|
||||
id="Layer_1"
|
||||
x="0px"
|
||||
y="0px"
|
||||
width="501.3px"
|
||||
height="161.7px"
|
||||
viewBox="0 0 501.3 161.7"
|
||||
style="enable-background:new 0 0 501.3 161.7;"
|
||||
xml:space="preserve"
|
||||
sodipodi:docname="discrete_harmonic.svg"
|
||||
inkscape:version="1.2.1 (9c6d41e410, 2022-07-14)"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"><defs
|
||||
id="defs227" /><sodipodi:namedview
|
||||
id="namedview225"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
inkscape:showpageshadow="2"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pagecheckerboard="0"
|
||||
inkscape:deskcolor="#d1d1d1"
|
||||
showgrid="false"
|
||||
inkscape:zoom="5.4059447"
|
||||
inkscape:cx="63.171198"
|
||||
inkscape:cy="80.1895"
|
||||
inkscape:window-width="1881"
|
||||
inkscape:window-height="1192"
|
||||
inkscape:window-x="26"
|
||||
inkscape:window-y="23"
|
||||
inkscape:window-maximized="0"
|
||||
inkscape:current-layer="Layer_1" />
|
||||
<style
|
||||
type="text/css"
|
||||
id="style2">
|
||||
.st0{fill:none;stroke:#000000;stroke-miterlimit:10;}
|
||||
.st1{display:none;}
|
||||
.st2{display:inline;}
|
||||
</style>
|
||||
<circle cx="4.4" cy="87.7" r="2.5"/>
|
||||
<circle cx="96.9" cy="140.6" r="2.5"/>
|
||||
<circle cx="210" cy="83.4" r="2.5"/>
|
||||
<circle cx="90.9" cy="21.1" r="2.5"/>
|
||||
<polyline class="st0" points="90.9,21.1 4.4,87.7 96.9,140.6 90.9,21.1 "/>
|
||||
<polyline class="st0" points="96.9,140.6 210,83.3 90.9,21.1 "/>
|
||||
<g class="st1">
|
||||
<g class="st2">
|
||||
<path class="st0" d="M68.3,119.4c5.9-8.7,15.6-14.6,26.8-15.2"/>
|
||||
<g>
|
||||
<polygon points="71.6,119.1 68.8,118.7 67.1,116.4 66.2,123 "/>
|
||||
<circle
|
||||
cx="4.4"
|
||||
cy="87.7"
|
||||
r="2.5"
|
||||
id="circle4" />
|
||||
<circle
|
||||
cx="96.9"
|
||||
cy="140.6"
|
||||
r="2.5"
|
||||
id="circle6" />
|
||||
<circle
|
||||
cx="210"
|
||||
cy="83.4"
|
||||
r="2.5"
|
||||
id="circle8" />
|
||||
<circle
|
||||
cx="90.9"
|
||||
cy="21.1"
|
||||
r="2.5"
|
||||
id="circle10" />
|
||||
<polyline
|
||||
class="st0"
|
||||
points="90.9,21.1 4.4,87.7 96.9,140.6 90.9,21.1 "
|
||||
id="polyline12" />
|
||||
<polyline
|
||||
class="st0"
|
||||
points="96.9,140.6 210,83.3 90.9,21.1 "
|
||||
id="polyline14" />
|
||||
<g
|
||||
class="st1"
|
||||
id="g24">
|
||||
<g
|
||||
class="st2"
|
||||
id="g22">
|
||||
<path
|
||||
class="st0"
|
||||
d="M68.3,119.4c5.9-8.7,15.6-14.6,26.8-15.2"
|
||||
id="path16" />
|
||||
<g
|
||||
id="g20">
|
||||
<polygon
|
||||
points="71.6,119.1 68.8,118.7 67.1,116.4 66.2,123 "
|
||||
id="polygon18" />
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
<g class="st1">
|
||||
<g class="st2">
|
||||
<path class="st0" d="M99.2,108c10,2.3,18.8,9.2,23.3,19.2"/>
|
||||
<g>
|
||||
<polygon points="100.7,110.9 100.1,108.2 101.6,105.8 95.1,107.3 "/>
|
||||
<g
|
||||
class="st1"
|
||||
id="g34">
|
||||
<g
|
||||
class="st2"
|
||||
id="g32">
|
||||
<path
|
||||
class="st0"
|
||||
d="M99.2,108c10,2.3,18.8,9.2,23.3,19.2"
|
||||
id="path26" />
|
||||
<g
|
||||
id="g30">
|
||||
<polygon
|
||||
points="100.7,110.9 100.1,108.2 101.6,105.8 95.1,107.3 "
|
||||
id="polygon28" />
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
<g class="st1">
|
||||
<g class="st2">
|
||||
<path class="st0" d="M173.1,96.8c-3.6-9.9-2.6-21.3,3.5-30.6"/>
|
||||
<g>
|
||||
<polygon points="174.8,94 172.8,96 170,96 174.8,100.6 "/>
|
||||
<g
|
||||
class="st1"
|
||||
id="g44">
|
||||
<g
|
||||
class="st2"
|
||||
id="g42">
|
||||
<path
|
||||
class="st0"
|
||||
d="M173.1,96.8c-3.6-9.9-2.6-21.3,3.5-30.6"
|
||||
id="path36" />
|
||||
<g
|
||||
id="g40">
|
||||
<polygon
|
||||
points="174.8,94 172.8,96 170,96 174.8,100.6 "
|
||||
id="polygon38" />
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
<g class="st1">
|
||||
<g class="st2">
|
||||
<path class="st0" d="M30.4,73.1c5.6,8.9,7.1,20.2,3.1,30.7"/>
|
||||
<g>
|
||||
<polygon points="29.3,76.2 30.8,73.8 33.6,73.2 27.9,69.7 "/>
|
||||
<g
|
||||
class="st1"
|
||||
id="g54">
|
||||
<g
|
||||
class="st2"
|
||||
id="g52">
|
||||
<path
|
||||
class="st0"
|
||||
d="M30.4,73.1c5.6,8.9,7.1,20.2,3.1,30.7"
|
||||
id="path46" />
|
||||
<g
|
||||
id="g50">
|
||||
<polygon
|
||||
points="29.3,76.2 30.8,73.8 33.6,73.2 27.9,69.7 "
|
||||
id="polygon48" />
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
<g class="st1">
|
||||
<g class="st2">
|
||||
<path class="st0" d="M117,39.5c-4.5,9.5-13.3,16.8-24.2,19.1"/>
|
||||
<g>
|
||||
<polygon points="113.8,40.3 116.6,40.2 118.6,42.2 118.6,35.6 "/>
|
||||
<g
|
||||
class="st1"
|
||||
id="g64">
|
||||
<g
|
||||
class="st2"
|
||||
id="g62">
|
||||
<path
|
||||
class="st0"
|
||||
d="M117,39.5c-4.5,9.5-13.3,16.8-24.2,19.1"
|
||||
id="path56" />
|
||||
<g
|
||||
id="g60">
|
||||
<polygon
|
||||
points="113.8,40.3 116.6,40.2 118.6,42.2 118.6,35.6 "
|
||||
id="polygon58" />
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
<g class="st1">
|
||||
<g class="st2">
|
||||
<path class="st0" d="M88.2,55c-10,0.9-20.2-2.8-27.3-10.7"/>
|
||||
<g>
|
||||
<polygon points="85.9,52.6 87.3,55 86.6,57.8 92.3,54.3 "/>
|
||||
<g
|
||||
class="st1"
|
||||
id="g74">
|
||||
<g
|
||||
class="st2"
|
||||
id="g72">
|
||||
<path
|
||||
class="st0"
|
||||
d="M88.2,55c-10,0.9-20.2-2.8-27.3-10.7"
|
||||
id="path66" />
|
||||
<g
|
||||
id="g70">
|
||||
<polygon
|
||||
points="85.9,52.6 87.3,55 86.6,57.8 92.3,54.3 "
|
||||
id="polygon68" />
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
<g>
|
||||
<g class="st1">
|
||||
<path class="st2" d="M84.9,121.7v1.5c-0.4-2-1.1-3.9-1.8-5.7c-0.5-1.5-0.8-2-1.4-2c-0.2,0-0.4,0-0.6,0.1l-0.2-0.5
|
||||
c0.4-0.4,0.8-0.7,1.4-0.7c0.7,0,1.3,0.3,2,2.4c0.4,1.1,0.9,2.8,1.4,5.4l0.1,0.1l0.1,3.9l-1.4,0.3l-0.2-0.2L84.9,121.7z
|
||||
M85.4,122.3c1.2-2.1,1.7-3.5,2.5-5.5l-0.2,1.4c-0.2-1.7-0.3-2.3-0.3-2.7c0-0.8,0.4-1.2,0.9-1.2c0.3,0,0.5,0.1,0.6,0.2
|
||||
c0.1,0.2,0.1,0.4,0.1,0.8c0,1.9-1.8,5.3-3.3,7.8L85.4,122.3z"/>
|
||||
<g
|
||||
id="g80">
|
||||
<g
|
||||
class="st1"
|
||||
id="g78">
|
||||
<path
|
||||
class="st2"
|
||||
d="M84.9,121.7v1.5c-0.4-2-1.1-3.9-1.8-5.7c-0.5-1.5-0.8-2-1.4-2c-0.2,0-0.4,0-0.6,0.1l-0.2-0.5 c0.4-0.4,0.8-0.7,1.4-0.7c0.7,0,1.3,0.3,2,2.4c0.4,1.1,0.9,2.8,1.4,5.4l0.1,0.1l0.1,3.9l-1.4,0.3l-0.2-0.2L84.9,121.7z M85.4,122.3c1.2-2.1,1.7-3.5,2.5-5.5l-0.2,1.4c-0.2-1.7-0.3-2.3-0.3-2.7c0-0.8,0.4-1.2,0.9-1.2c0.3,0,0.5,0.1,0.6,0.2 c0.1,0.2,0.1,0.4,0.1,0.8c0,1.9-1.8,5.3-3.3,7.8L85.4,122.3z"
|
||||
id="path76" />
|
||||
</g>
|
||||
</g>
|
||||
<g>
|
||||
<g class="st1">
|
||||
<path class="st2" d="M101,128v-8.8c0-2.6,1.6-4.3,3.8-4.3c1.8,0,3.2,1.1,3.2,3c0,1.4-1,3.3-3.6,3.5l-0.1-0.2c3-0.1,4.7,1,4.7,3.4
|
||||
c0,2.5-1.9,3.8-3.7,3.8c-1.3,0-2.6-0.6-3.3-2.2l0.2-0.2c0.8,0.7,1.7,1.2,2.8,1.2c1.7,0,2.6-1.1,2.6-2.7c0-1.5-0.8-2.9-3.5-2.8
|
||||
l-0.2-1c1.7-0.3,2.7-1.3,2.7-2.9c0-1.4-0.7-2.3-1.9-2.3c-1.3,0-2.2,1.2-2.2,3.2v7.7l-0.1,0.3l0.3,4.5l-1.4,0.3l-0.2-0.2L101,128z"
|
||||
/>
|
||||
<g
|
||||
id="g86">
|
||||
<g
|
||||
class="st1"
|
||||
id="g84">
|
||||
<path
|
||||
class="st2"
|
||||
d="M101,128v-8.8c0-2.6,1.6-4.3,3.8-4.3c1.8,0,3.2,1.1,3.2,3c0,1.4-1,3.3-3.6,3.5l-0.1-0.2c3-0.1,4.7,1,4.7,3.4 c0,2.5-1.9,3.8-3.7,3.8c-1.3,0-2.6-0.6-3.3-2.2l0.2-0.2c0.8,0.7,1.7,1.2,2.8,1.2c1.7,0,2.6-1.1,2.6-2.7c0-1.5-0.8-2.9-3.5-2.8 l-0.2-1c1.7-0.3,2.7-1.3,2.7-2.9c0-1.4-0.7-2.3-1.9-2.3c-1.3,0-2.2,1.2-2.2,3.2v7.7l-0.1,0.3l0.3,4.5l-1.4,0.3l-0.2-0.2L101,128z"
|
||||
id="path82" />
|
||||
</g>
|
||||
</g>
|
||||
<g>
|
||||
<g class="st1">
|
||||
<path class="st2" d="M21.8,90v-8.8c0-2.6,1.6-4.3,3.8-4.3c1.8,0,3.2,1.1,3.2,3c0,1.4-1,3.3-3.6,3.5l-0.1-0.2c3-0.1,4.7,1,4.7,3.4
|
||||
c0,2.5-1.9,3.8-3.7,3.8c-1.3,0-2.6-0.6-3.3-2.2L23,88c0.8,0.7,1.7,1.2,2.8,1.2c1.7,0,2.6-1.1,2.6-2.7c0-1.5-0.8-2.9-3.5-2.8
|
||||
l-0.2-1c1.7-0.3,2.7-1.3,2.7-2.9c0-1.4-0.7-2.3-1.9-2.3c-1.3,0-2.2,1.2-2.2,3.2v7.7l-0.1,0.3l0.3,4.5l-1.4,0.3l-0.2-0.2L21.8,90z"
|
||||
/>
|
||||
<g
|
||||
id="g92">
|
||||
<g
|
||||
class="st1"
|
||||
id="g90">
|
||||
<path
|
||||
class="st2"
|
||||
d="M21.8,90v-8.8c0-2.6,1.6-4.3,3.8-4.3c1.8,0,3.2,1.1,3.2,3c0,1.4-1,3.3-3.6,3.5l-0.1-0.2c3-0.1,4.7,1,4.7,3.4 c0,2.5-1.9,3.8-3.7,3.8c-1.3,0-2.6-0.6-3.3-2.2L23,88c0.8,0.7,1.7,1.2,2.8,1.2c1.7,0,2.6-1.1,2.6-2.7c0-1.5-0.8-2.9-3.5-2.8 l-0.2-1c1.7-0.3,2.7-1.3,2.7-2.9c0-1.4-0.7-2.3-1.9-2.3c-1.3,0-2.2,1.2-2.2,3.2v7.7l-0.1,0.3l0.3,4.5l-1.4,0.3l-0.2-0.2L21.8,90z"
|
||||
id="path88" />
|
||||
</g>
|
||||
</g>
|
||||
<g>
|
||||
<g class="st1">
|
||||
<path class="st2" d="M182.6,84.9v1.5c-0.4-2-1.1-3.9-1.8-5.7c-0.5-1.5-0.8-2-1.4-2c-0.2,0-0.4,0-0.6,0.1l-0.2-0.5
|
||||
c0.4-0.4,0.8-0.7,1.4-0.7c0.7,0,1.3,0.3,2,2.4c0.4,1.1,0.9,2.8,1.4,5.4l0.1,0.1l0.1,3.9l-1.4,0.3l-0.2-0.2L182.6,84.9z
|
||||
M183.1,85.5c1.2-2.1,1.7-3.5,2.5-5.5l-0.2,1.4c-0.2-1.7-0.3-2.3-0.3-2.7c0-0.8,0.4-1.2,0.9-1.2c0.3,0,0.5,0.1,0.6,0.2
|
||||
c0.1,0.2,0.1,0.4,0.1,0.8c0,1.9-1.8,5.3-3.3,7.8L183.1,85.5z"/>
|
||||
<g
|
||||
id="g98">
|
||||
<g
|
||||
class="st1"
|
||||
id="g96">
|
||||
<path
|
||||
class="st2"
|
||||
d="M182.6,84.9v1.5c-0.4-2-1.1-3.9-1.8-5.7c-0.5-1.5-0.8-2-1.4-2c-0.2,0-0.4,0-0.6,0.1l-0.2-0.5 c0.4-0.4,0.8-0.7,1.4-0.7c0.7,0,1.3,0.3,2,2.4c0.4,1.1,0.9,2.8,1.4,5.4l0.1,0.1l0.1,3.9l-1.4,0.3l-0.2-0.2L182.6,84.9z M183.1,85.5c1.2-2.1,1.7-3.5,2.5-5.5l-0.2,1.4c-0.2-1.7-0.3-2.3-0.3-2.7c0-0.8,0.4-1.2,0.9-1.2c0.3,0,0.5,0.1,0.6,0.2 c0.1,0.2,0.1,0.4,0.1,0.8c0,1.9-1.8,5.3-3.3,7.8L183.1,85.5z"
|
||||
id="path94" />
|
||||
</g>
|
||||
</g>
|
||||
<circle cx="284.1" cy="88.3" r="2.5"/>
|
||||
<circle cx="376.6" cy="141.2" r="2.5"/>
|
||||
<circle cx="489.6" cy="84" r="2.5"/>
|
||||
<circle cx="370.5" cy="21.6" r="2.5"/>
|
||||
<line class="st0" x1="370.5" y1="21.6" x2="284.1" y2="88.3"/>
|
||||
<line class="st0" x1="489.6" y1="83.9" x2="370.5" y2="21.6"/>
|
||||
<polygon class="st0" points="376.6,141.2 284.1,88.3 489.6,83.9 "/>
|
||||
<g>
|
||||
<g>
|
||||
<path d="M367.8,54.4v-0.7h2.5v1h-0.2L367.8,54.4z M370.3,64.8v1h-2.5V65l2.3-0.3h0.2V64.8z M369.5,59.3c0-1.9,0-3.7-0.1-5.6h1.7
|
||||
c-0.1,1.8-0.1,3.7-0.1,5.6v0.6c0,2.1,0,4,0.1,5.9h-1.7c0.1-1.8,0.1-3.7,0.1-5.6V59.3z M370.3,59.1h1.8c2.2,0,3.2-0.7,3.2-2.4
|
||||
s-1-2.2-2.8-2.2h-2.2v-0.8h2.7c2.5,0,3.9,1.2,3.9,3c0,1.4-1,2.6-3.4,2.9v-0.2c2.8,0.2,4,1.5,4,3c0,1.6-1.4,3.3-4.8,3.3h-2.4v-0.8
|
||||
h2c2.3,0,3.5-0.9,3.5-2.5c0-1.7-1.1-2.5-3.6-2.5h-1.9L370.3,59.1L370.3,59.1z"/>
|
||||
<circle
|
||||
cx="284.1"
|
||||
cy="88.3"
|
||||
r="2.5"
|
||||
id="circle100" />
|
||||
<circle
|
||||
cx="376.6"
|
||||
cy="141.2"
|
||||
r="2.5"
|
||||
id="circle102" />
|
||||
<circle
|
||||
cx="489.6"
|
||||
cy="84"
|
||||
r="2.5"
|
||||
id="circle104" />
|
||||
<circle
|
||||
cx="370.5"
|
||||
cy="21.6"
|
||||
r="2.5"
|
||||
id="circle106" />
|
||||
<line
|
||||
class="st0"
|
||||
x1="370.5"
|
||||
y1="21.6"
|
||||
x2="284.1"
|
||||
y2="88.3"
|
||||
id="line108" />
|
||||
<line
|
||||
class="st0"
|
||||
x1="489.6"
|
||||
y1="83.9"
|
||||
x2="370.5"
|
||||
y2="21.6"
|
||||
id="line110" />
|
||||
<polygon
|
||||
class="st0"
|
||||
points="376.6,141.2 284.1,88.3 489.6,83.9 "
|
||||
id="polygon112" />
|
||||
<g
|
||||
id="g118">
|
||||
<g
|
||||
id="g116">
|
||||
<path
|
||||
d="M367.8,54.4v-0.7h2.5v1h-0.2L367.8,54.4z M370.3,64.8v1h-2.5V65l2.3-0.3h0.2V64.8z M369.5,59.3c0-1.9,0-3.7-0.1-5.6h1.7 c-0.1,1.8-0.1,3.7-0.1,5.6v0.6c0,2.1,0,4,0.1,5.9h-1.7c0.1-1.8,0.1-3.7,0.1-5.6V59.3z M370.3,59.1h1.8c2.2,0,3.2-0.7,3.2-2.4 s-1-2.2-2.8-2.2h-2.2v-0.8h2.7c2.5,0,3.9,1.2,3.9,3c0,1.4-1,2.6-3.4,2.9v-0.2c2.8,0.2,4,1.5,4,3c0,1.6-1.4,3.3-4.8,3.3h-2.4v-0.8 h2c2.3,0,3.5-0.9,3.5-2.5c0-1.7-1.1-2.5-3.6-2.5h-1.9L370.3,59.1L370.3,59.1z"
|
||||
id="path114" />
|
||||
</g>
|
||||
</g>
|
||||
<g>
|
||||
<g class="st1">
|
||||
<path class="st2" d="M380.7,113.1v1l-1.1,0.3l0.5-2.7h1.1l-0.1,2.6c-1.1,0.6-2.4,0.9-3.6,0.9c-3.6,0-6.1-2.6-6.1-6.3
|
||||
c0-3.6,2.6-6.3,6.1-6.3c1,0,2.3,0.2,3.5,0.9l0.1,2.6H380l-0.5-2.7l1.1,0.3v1.1c-1-1-2-1.3-2.9-1.3c-2.4,0-4.4,1.9-4.4,5.4
|
||||
s1.8,5.4,4.3,5.4C378.5,114.2,379.7,113.9,380.7,113.1z"/>
|
||||
<g
|
||||
id="g124">
|
||||
<g
|
||||
class="st1"
|
||||
id="g122">
|
||||
<path
|
||||
class="st2"
|
||||
d="M380.7,113.1v1l-1.1,0.3l0.5-2.7h1.1l-0.1,2.6c-1.1,0.6-2.4,0.9-3.6,0.9c-3.6,0-6.1-2.6-6.1-6.3 c0-3.6,2.6-6.3,6.1-6.3c1,0,2.3,0.2,3.5,0.9l0.1,2.6H380l-0.5-2.7l1.1,0.3v1.1c-1-1-2-1.3-2.9-1.3c-2.4,0-4.4,1.9-4.4,5.4 s1.8,5.4,4.3,5.4C378.5,114.2,379.7,113.9,380.7,113.1z"
|
||||
id="path120" />
|
||||
</g>
|
||||
</g>
|
||||
<g>
|
||||
<g>
|
||||
<path d="M88.4,8c0.9,0,1.5-0.4,2.4-1.5L91,7c-0.8,1.4-1.7,2-2.9,2c-2.2,0-3.7-1.8-3.7-4.4C84.4,1.9,86,0,88.2,0c1,0,2,0.4,2.9,1.8
|
||||
l-0.2,0.5c-1-1-1.8-1.3-2.4-1.3C87.1,1,86,2.1,86,4.6C85.9,6.9,86.9,8,88.4,8z M91.5,12.1l2,0.4v0.6h-4.6v-0.6l2.2-0.4H91.5z
|
||||
M92,13.1h-1.5c0-1.3,0.1-2.6,0.1-3.8V7.5l-0.1-0.3V1.3L91.7,0L92,0.2l-0.1,2.4v6.7C92,10.5,92,11.8,92,13.1z"/>
|
||||
<g
|
||||
id="g130">
|
||||
<g
|
||||
id="g128">
|
||||
<path
|
||||
d="M88.4,8c0.9,0,1.5-0.4,2.4-1.5L91,7c-0.8,1.4-1.7,2-2.9,2c-2.2,0-3.7-1.8-3.7-4.4C84.4,1.9,86,0,88.2,0c1,0,2,0.4,2.9,1.8 l-0.2,0.5c-1-1-1.8-1.3-2.4-1.3C87.1,1,86,2.1,86,4.6C85.9,6.9,86.9,8,88.4,8z M91.5,12.1l2,0.4v0.6h-4.6v-0.6l2.2-0.4H91.5z M92,13.1h-1.5c0-1.3,0.1-2.6,0.1-3.8V7.5l-0.1-0.3V1.3L91.7,0L92,0.2l-0.1,2.4v6.7C92,10.5,92,11.8,92,13.1z"
|
||||
id="path126" />
|
||||
</g>
|
||||
</g>
|
||||
<g>
|
||||
<g>
|
||||
<path d="M367.7,8c0.9,0,1.5-0.4,2.4-1.5l0.2,0.5c-0.8,1.4-1.7,2-2.9,2c-2.2,0-3.7-1.8-3.7-4.4c0-2.7,1.6-4.6,3.8-4.6
|
||||
c1,0,2,0.4,2.9,1.8l-0.2,0.5c-1-1-1.8-1.3-2.4-1.3c-1.4,0-2.5,1.1-2.5,3.6C365.2,6.9,366.3,8,367.7,8z M370.8,12.1l2,0.4v0.6h-4.6
|
||||
v-0.6l2.2-0.4H370.8z M371.4,13.1h-1.5c0-1.3,0.1-2.6,0.1-3.8V7.5l-0.1-0.3V1.3l1.2-1.3l0.3,0.2l-0.1,2.4v6.7
|
||||
C371.3,10.5,371.3,11.8,371.4,13.1z"/>
|
||||
<g
|
||||
id="g136">
|
||||
<g
|
||||
id="g134">
|
||||
<path
|
||||
d="M367.7,8c0.9,0,1.5-0.4,2.4-1.5l0.2,0.5c-0.8,1.4-1.7,2-2.9,2c-2.2,0-3.7-1.8-3.7-4.4c0-2.7,1.6-4.6,3.8-4.6 c1,0,2,0.4,2.9,1.8l-0.2,0.5c-1-1-1.8-1.3-2.4-1.3c-1.4,0-2.5,1.1-2.5,3.6C365.2,6.9,366.3,8,367.7,8z M370.8,12.1l2,0.4v0.6h-4.6 v-0.6l2.2-0.4H370.8z M371.4,13.1h-1.5c0-1.3,0.1-2.6,0.1-3.8V7.5l-0.1-0.3V1.3l1.2-1.3l0.3,0.2l-0.1,2.4v6.7 C371.3,10.5,371.3,11.8,371.4,13.1z"
|
||||
id="path132" />
|
||||
</g>
|
||||
</g>
|
||||
<g>
|
||||
<g>
|
||||
<path d="M34.2,50c0.9,0,1.5-0.4,2.4-1.5l0.2,0.5c-0.7,1.2-1.5,2-2.9,2c-2.2,0-3.7-1.8-3.7-4.4c0-2.7,1.6-4.6,3.8-4.6
|
||||
c1,0,1.9,0.4,2.8,1.8l-0.2,0.5c-1-1-1.8-1.3-2.4-1.3c-1.4,0-2.5,1.1-2.5,3.5C31.7,49,32.7,50,34.2,50z M39.2,50.2v0.6L36.4,51
|
||||
l-0.2-1.8v-5.3l0.1-0.2v-4.5L34.8,39v-0.6l2.8-0.8l0.3,0.1l-0.1,2.6v10.6L37.5,50L39.2,50.2z"/>
|
||||
<path d="M45.1,50.3v0.5h-4.5v-0.5l1.7-0.3h1.1L45.1,50.3z M43.4,43.5l0.2,0.1v7.1h-1.2v-6.1l-1.5,0.2v-0.6L43.4,43.5z"/>
|
||||
<g
|
||||
id="g144">
|
||||
<g
|
||||
id="g142">
|
||||
<path
|
||||
d="M34.2,50c0.9,0,1.5-0.4,2.4-1.5l0.2,0.5c-0.7,1.2-1.5,2-2.9,2c-2.2,0-3.7-1.8-3.7-4.4c0-2.7,1.6-4.6,3.8-4.6 c1,0,1.9,0.4,2.8,1.8l-0.2,0.5c-1-1-1.8-1.3-2.4-1.3c-1.4,0-2.5,1.1-2.5,3.5C31.7,49,32.7,50,34.2,50z M39.2,50.2v0.6L36.4,51 l-0.2-1.8v-5.3l0.1-0.2v-4.5L34.8,39v-0.6l2.8-0.8l0.3,0.1l-0.1,2.6v10.6L37.5,50L39.2,50.2z"
|
||||
id="path138" />
|
||||
|
||||
</g>
|
||||
</g>
|
||||
<g>
|
||||
<g>
|
||||
<path d="M104.3,81.7c0.9,0,1.5-0.4,2.4-1.5l0.2,0.5c-0.7,1.2-1.5,2-2.9,2c-2.2,0-3.7-1.8-3.7-4.4c0-2.7,1.6-4.6,3.8-4.6
|
||||
c1,0,1.9,0.4,2.8,1.8l-0.2,0.5c-1-1-1.8-1.3-2.4-1.3c-1.4,0-2.5,1.1-2.5,3.5C101.8,80.6,102.8,81.7,104.3,81.7z M109.3,81.8v0.6
|
||||
l-2.8,0.2l-0.2-1.8v-5.3l0.1-0.2v-4.6l-1.5-0.2v-0.6l2.8-0.8l0.3,0.1l-0.1,2.6v10.6l-0.3-0.9L109.3,81.8z"/>
|
||||
<g
|
||||
id="g150"
|
||||
transform="translate(-1.9943323,0.1596911)">
|
||||
<g
|
||||
id="g148">
|
||||
<path
|
||||
d="m 104.3,81.7 c 0.9,0 1.5,-0.4 2.4,-1.5 l 0.2,0.5 c -0.7,1.2 -1.5,2 -2.9,2 -2.2,0 -3.7,-1.8 -3.7,-4.4 0,-2.7 1.6,-4.6 3.8,-4.6 1,0 1.9,0.4 2.8,1.8 l -0.2,0.5 c -1,-1 -1.8,-1.3 -2.4,-1.3 -1.4,0 -2.5,1.1 -2.5,3.5 0,2.4 1,3.5 2.5,3.5 z m 5,0.1 v 0.6 l -2.8,0.2 -0.2,-1.8 v -5.3 l 0.1,-0.2 v -4.6 l -1.5,-0.2 v -0.6 l 2.8,-0.8 0.3,0.1 -0.1,2.6 v 10.6 l -0.3,-0.9 z"
|
||||
id="path146" />
|
||||
</g>
|
||||
</g>
|
||||
<g>
|
||||
<g>
|
||||
<path d="M160.1,49c0.9,0,1.5-0.4,2.4-1.5l0.2,0.5c-0.7,1.2-1.5,2-2.9,2c-2.2,0-3.7-1.8-3.7-4.4c0-2.7,1.6-4.6,3.8-4.6
|
||||
c1,0,1.9,0.4,2.8,1.8l-0.2,0.5c-1-1-1.8-1.3-2.4-1.3c-1.4,0-2.5,1.1-2.5,3.5C157.5,48,158.6,49,160.1,49z M165.1,49.2v0.6
|
||||
l-2.8,0.2l-0.2-1.8v-5.3l0.1-0.2v-4.5l-1.5-0.2v-0.6l2.8-0.8l0.3,0.1l-0.1,2.6v10.6l-0.3-0.9L165.1,49.2z"/>
|
||||
<path d="M166.3,48.9l1.7-1.6c1.1-1,1.6-1.9,1.6-2.8c0-0.9-0.5-1.4-1.4-1.4c-0.3,0-0.7,0.1-1.1,0.2l0.7-0.5l-0.3,1
|
||||
c-0.2,0.7-0.4,0.9-0.7,0.9s-0.5-0.2-0.6-0.4c0.1-1.2,1.2-1.8,2.5-1.8c1.6,0,2.2,0.9,2.2,1.9s-0.7,1.8-2.3,3.3l-1.7,1.6l0.3-0.7h4
|
||||
v1.2h-4.8L166.3,48.9L166.3,48.9z"/>
|
||||
<g
|
||||
id="g158">
|
||||
<g
|
||||
id="g156">
|
||||
<path
|
||||
d="M160.1,49c0.9,0,1.5-0.4,2.4-1.5l0.2,0.5c-0.7,1.2-1.5,2-2.9,2c-2.2,0-3.7-1.8-3.7-4.4c0-2.7,1.6-4.6,3.8-4.6 c1,0,1.9,0.4,2.8,1.8l-0.2,0.5c-1-1-1.8-1.3-2.4-1.3c-1.4,0-2.5,1.1-2.5,3.5C157.5,48,158.6,49,160.1,49z M165.1,49.2v0.6 l-2.8,0.2l-0.2-1.8v-5.3l0.1-0.2v-4.5l-1.5-0.2v-0.6l2.8-0.8l0.3,0.1l-0.1,2.6v10.6l-0.3-0.9L165.1,49.2z"
|
||||
id="path152" />
|
||||
<path
|
||||
d="M166.3,48.9l1.7-1.6c1.1-1,1.6-1.9,1.6-2.8c0-0.9-0.5-1.4-1.4-1.4c-0.3,0-0.7,0.1-1.1,0.2l0.7-0.5l-0.3,1 c-0.2,0.7-0.4,0.9-0.7,0.9s-0.5-0.2-0.6-0.4c0.1-1.2,1.2-1.8,2.5-1.8c1.6,0,2.2,0.9,2.2,1.9s-0.7,1.8-2.3,3.3l-1.7,1.6l0.3-0.7h4 v1.2h-4.8L166.3,48.9L166.3,48.9z"
|
||||
id="path154" />
|
||||
</g>
|
||||
</g>
|
||||
<g>
|
||||
<g>
|
||||
<path d="M55.3,87.6l1.8-0.3h0.4l2,0.3v0.7h-4.1L55.3,87.6L55.3,87.6z M60.7,76.2h1.1l4.1,12.1h-1.7l-3.6-10.8H61l-3.7,10.8h-0.8
|
||||
L60.7,76.2z M58.6,83.6h4.9l0.3,0.8h-5.4L58.6,83.6z M62.2,87.6l2.3-0.3h0.4l2.2,0.3v0.7h-4.9C62.2,88.3,62.2,87.6,62.2,87.6z"/>
|
||||
<path d="M72.8,87.8v0.5h-4.5v-0.5l1.7-0.3h1.1L72.8,87.8z M71.1,81.1l0.2,0.1v7.1h-1.2v-6.1l-1.4,0.1v-0.6L71.1,81.1z"/>
|
||||
<g
|
||||
id="g166">
|
||||
<g
|
||||
id="g164">
|
||||
<path
|
||||
d="M55.3,87.6l1.8-0.3h0.4l2,0.3v0.7h-4.1L55.3,87.6L55.3,87.6z M60.7,76.2h1.1l4.1,12.1h-1.7l-3.6-10.8H61l-3.7,10.8h-0.8 L60.7,76.2z M58.6,83.6h4.9l0.3,0.8h-5.4L58.6,83.6z M62.2,87.6l2.3-0.3h0.4l2.2,0.3v0.7h-4.9C62.2,88.3,62.2,87.6,62.2,87.6z"
|
||||
id="path160" />
|
||||
|
||||
</g>
|
||||
</g>
|
||||
<g>
|
||||
<g>
|
||||
<path d="M126.5,85.8l1.8-0.3h0.4l2,0.3v0.7h-4.1L126.5,85.8L126.5,85.8z M131.8,74.4h1.1l4.1,12.2h-1.7l-3.6-10.8h0.4l-3.7,10.8
|
||||
h-0.8L131.8,74.4z M129.7,81.8h4.9l0.3,0.8h-5.4L129.7,81.8z M133.3,85.8l2.3-0.3h0.4l2.2,0.3v0.7h-4.9V85.8z"/>
|
||||
<path d="M139.3,85.7l1.7-1.6c1.1-1,1.6-1.9,1.6-2.8s-0.5-1.4-1.4-1.4c-0.3,0-0.7,0.1-1.1,0.2l0.7-0.5l-0.3,1
|
||||
c-0.2,0.7-0.4,0.9-0.7,0.9s-0.5-0.2-0.6-0.4c0.1-1.2,1.2-1.8,2.5-1.8c1.6,0,2.2,0.9,2.2,1.9s-0.7,1.8-2.3,3.3l-1.7,1.6l0.3-0.7h4
|
||||
v1.2h-4.8L139.3,85.7L139.3,85.7z"/>
|
||||
<g
|
||||
id="g174">
|
||||
<g
|
||||
id="g172">
|
||||
<path
|
||||
d="M126.5,85.8l1.8-0.3h0.4l2,0.3v0.7h-4.1L126.5,85.8L126.5,85.8z M131.8,74.4h1.1l4.1,12.2h-1.7l-3.6-10.8h0.4l-3.7,10.8 h-0.8L131.8,74.4z M129.7,81.8h4.9l0.3,0.8h-5.4L129.7,81.8z M133.3,85.8l2.3-0.3h0.4l2.2,0.3v0.7h-4.9V85.8z"
|
||||
id="path168" />
|
||||
<path
|
||||
d="M139.3,85.7l1.7-1.6c1.1-1,1.6-1.9,1.6-2.8s-0.5-1.4-1.4-1.4c-0.3,0-0.7,0.1-1.1,0.2l0.7-0.5l-0.3,1 c-0.2,0.7-0.4,0.9-0.7,0.9s-0.5-0.2-0.6-0.4c0.1-1.2,1.2-1.8,2.5-1.8c1.6,0,2.2,0.9,2.2,1.9s-0.7,1.8-2.3,3.3l-1.7,1.6l0.3-0.7h4 v1.2h-4.8L139.3,85.7L139.3,85.7z"
|
||||
id="path170" />
|
||||
</g>
|
||||
</g>
|
||||
<g>
|
||||
<g>
|
||||
<path d="M4.6,111.1v0.6H0v-0.6l2-0.4h0.4L4.6,111.1z M1.5,102.8c0-1,0-1.5-0.1-2.3L0,100.3v-0.6l2.4-1.1l0.3,0.2l0.1,1.5h0.1v5.6
|
||||
L2.8,106v1.8c0,1.3,0,2.6,0.1,3.8H1.5c0-1.3,0.1-2.5,0.1-3.8L1.5,102.8L1.5,102.8z M5.2,99.6c-0.7,0-1.6,0.3-2.9,1.6l-0.2-0.3
|
||||
c1-1.6,2.2-2.3,3.4-2.3c1.9,0,3.4,1.7,3.4,4.5s-1.6,4.5-3.7,4.5c-1.1,0-2.2-0.5-3.2-2.4l0.2-0.3c0.9,1.2,1.8,1.7,2.7,1.7
|
||||
c1.4,0,2.5-1.1,2.5-3.4C7.5,100.9,6.5,99.6,5.2,99.6z"/>
|
||||
<path d="M15.7,107.7c0,2.6-1.2,3.7-2.5,3.7c-1.3,0-2.5-1.1-2.5-3.7s1.2-3.7,2.5-3.7C14.5,103.9,15.7,105,15.7,107.7z M13.2,110.8
|
||||
c0.6,0,1.2-0.6,1.2-3.1c0-2.6-0.6-3.1-1.2-3.1c-0.6,0-1.2,0.5-1.2,3.1C12,110.2,12.6,110.8,13.2,110.8z"/>
|
||||
<g
|
||||
id="g182">
|
||||
<g
|
||||
id="g180">
|
||||
<path
|
||||
d="M4.6,111.1v0.6H0v-0.6l2-0.4h0.4L4.6,111.1z M1.5,102.8c0-1,0-1.5-0.1-2.3L0,100.3v-0.6l2.4-1.1l0.3,0.2l0.1,1.5h0.1v5.6 L2.8,106v1.8c0,1.3,0,2.6,0.1,3.8H1.5c0-1.3,0.1-2.5,0.1-3.8L1.5,102.8L1.5,102.8z M5.2,99.6c-0.7,0-1.6,0.3-2.9,1.6l-0.2-0.3 c1-1.6,2.2-2.3,3.4-2.3c1.9,0,3.4,1.7,3.4,4.5s-1.6,4.5-3.7,4.5c-1.1,0-2.2-0.5-3.2-2.4l0.2-0.3c0.9,1.2,1.8,1.7,2.7,1.7 c1.4,0,2.5-1.1,2.5-3.4C7.5,100.9,6.5,99.6,5.2,99.6z"
|
||||
id="path176" />
|
||||
<path
|
||||
d="M15.7,107.7c0,2.6-1.2,3.7-2.5,3.7c-1.3,0-2.5-1.1-2.5-3.7s1.2-3.7,2.5-3.7C14.5,103.9,15.7,105,15.7,107.7z M13.2,110.8 c0.6,0,1.2-0.6,1.2-3.1c0-2.6-0.6-3.1-1.2-3.1c-0.6,0-1.2,0.5-1.2,3.1C12,110.2,12.6,110.8,13.2,110.8z"
|
||||
id="path178" />
|
||||
</g>
|
||||
</g>
|
||||
<g>
|
||||
<g>
|
||||
<path d="M284.8,111.1v0.6h-4.6v-0.6l2-0.4h0.4L284.8,111.1z M281.7,102.8c0-1,0-1.5-0.1-2.3l-1.4-0.2v-0.6l2.4-1.1l0.3,0.2
|
||||
l0.1,1.5h0.1v5.6L283,106v1.8c0,1.3,0,2.6,0.1,3.8h-1.5c0-1.3,0.1-2.5,0.1-3.8V102.8z M285.4,99.6c-0.7,0-1.6,0.3-2.9,1.6
|
||||
l-0.2-0.3c1-1.6,2.2-2.3,3.4-2.3c1.9,0,3.4,1.7,3.4,4.5s-1.6,4.5-3.7,4.5c-1.1,0-2.2-0.5-3.2-2.4l0.2-0.3c0.9,1.2,1.8,1.7,2.7,1.7
|
||||
c1.4,0,2.5-1.1,2.5-3.4C287.7,100.9,286.7,99.6,285.4,99.6z"/>
|
||||
<path d="M295.9,107.7c0,2.6-1.2,3.7-2.5,3.7s-2.5-1.1-2.5-3.7s1.2-3.7,2.5-3.7C294.7,103.9,295.9,105,295.9,107.7z M293.4,110.8
|
||||
c0.6,0,1.2-0.6,1.2-3.1c0-2.6-0.6-3.1-1.2-3.1s-1.2,0.5-1.2,3.1C292.2,110.2,292.8,110.8,293.4,110.8z"/>
|
||||
<g
|
||||
id="g190">
|
||||
<g
|
||||
id="g188">
|
||||
<path
|
||||
d="M284.8,111.1v0.6h-4.6v-0.6l2-0.4h0.4L284.8,111.1z M281.7,102.8c0-1,0-1.5-0.1-2.3l-1.4-0.2v-0.6l2.4-1.1l0.3,0.2 l0.1,1.5h0.1v5.6L283,106v1.8c0,1.3,0,2.6,0.1,3.8h-1.5c0-1.3,0.1-2.5,0.1-3.8V102.8z M285.4,99.6c-0.7,0-1.6,0.3-2.9,1.6 l-0.2-0.3c1-1.6,2.2-2.3,3.4-2.3c1.9,0,3.4,1.7,3.4,4.5s-1.6,4.5-3.7,4.5c-1.1,0-2.2-0.5-3.2-2.4l0.2-0.3c0.9,1.2,1.8,1.7,2.7,1.7 c1.4,0,2.5-1.1,2.5-3.4C287.7,100.9,286.7,99.6,285.4,99.6z"
|
||||
id="path184" />
|
||||
<path
|
||||
d="M295.9,107.7c0,2.6-1.2,3.7-2.5,3.7s-2.5-1.1-2.5-3.7s1.2-3.7,2.5-3.7C294.7,103.9,295.9,105,295.9,107.7z M293.4,110.8 c0.6,0,1.2-0.6,1.2-3.1c0-2.6-0.6-3.1-1.2-3.1s-1.2,0.5-1.2,3.1C292.2,110.2,292.8,110.8,293.4,110.8z"
|
||||
id="path186" />
|
||||
</g>
|
||||
</g>
|
||||
<g>
|
||||
<g>
|
||||
<path d="M97.6,161.1v0.6H93v-0.6l2-0.4h0.4L97.6,161.1z M94.5,152.8c0-1,0-1.5-0.1-2.3l-1.4-0.2v-0.6l2.4-1.1l0.3,0.2l0.1,1.5h0.1
|
||||
v5.6l-0.1,0.1v1.8c0,1.3,0,2.6,0.1,3.8h-1.5c0-1.3,0.1-2.5,0.1-3.8V152.8z M98.2,149.6c-0.7,0-1.6,0.3-2.9,1.6l-0.2-0.3
|
||||
c1-1.6,2.2-2.3,3.4-2.3c1.9,0,3.4,1.7,3.4,4.5s-1.6,4.5-3.7,4.5c-1.1,0-2.2-0.5-3.2-2.4l0.2-0.3c0.9,1.2,1.8,1.7,2.7,1.7
|
||||
c1.4,0,2.5-1.1,2.5-3.4C100.5,150.9,99.5,149.6,98.2,149.6z"/>
|
||||
<path d="M108.5,160.7v0.5H104v-0.5l1.7-0.3h1.1L108.5,160.7z M106.8,154l0.2,0.1v7.1h-1.2v-6.1l-1.4,0.1v-0.6L106.8,154z"/>
|
||||
<g
|
||||
id="g198">
|
||||
<g
|
||||
id="g196">
|
||||
<path
|
||||
d="M97.6,161.1v0.6H93v-0.6l2-0.4h0.4L97.6,161.1z M94.5,152.8c0-1,0-1.5-0.1-2.3l-1.4-0.2v-0.6l2.4-1.1l0.3,0.2l0.1,1.5h0.1 v5.6l-0.1,0.1v1.8c0,1.3,0,2.6,0.1,3.8h-1.5c0-1.3,0.1-2.5,0.1-3.8V152.8z M98.2,149.6c-0.7,0-1.6,0.3-2.9,1.6l-0.2-0.3 c1-1.6,2.2-2.3,3.4-2.3c1.9,0,3.4,1.7,3.4,4.5s-1.6,4.5-3.7,4.5c-1.1,0-2.2-0.5-3.2-2.4l0.2-0.3c0.9,1.2,1.8,1.7,2.7,1.7 c1.4,0,2.5-1.1,2.5-3.4C100.5,150.9,99.5,149.6,98.2,149.6z"
|
||||
id="path192" />
|
||||
<path
|
||||
d="M108.5,160.7v0.5H104v-0.5l1.7-0.3h1.1L108.5,160.7z M106.8,154l0.2,0.1v7.1h-1.2v-6.1l-1.4,0.1v-0.6L106.8,154z"
|
||||
id="path194" />
|
||||
</g>
|
||||
</g>
|
||||
<g>
|
||||
<g>
|
||||
<path d="M377.6,161.1v0.6H373v-0.6l2-0.4h0.4L377.6,161.1z M374.5,152.8c0-1,0-1.5-0.1-2.3l-1.4-0.2v-0.6l2.4-1.1l0.3,0.2l0.1,1.5
|
||||
h0.1v5.6l-0.1,0.1v1.8c0,1.3,0,2.6,0.1,3.8h-1.5c0-1.3,0.1-2.5,0.1-3.8V152.8z M378.2,149.6c-0.7,0-1.6,0.3-2.9,1.6l-0.2-0.3
|
||||
c1-1.6,2.2-2.3,3.4-2.3c1.9,0,3.4,1.7,3.4,4.5s-1.6,4.5-3.7,4.5c-1.1,0-2.2-0.5-3.2-2.4l0.2-0.3c0.9,1.2,1.8,1.7,2.7,1.7
|
||||
c1.4,0,2.5-1.1,2.5-3.4C380.5,150.9,379.5,149.6,378.2,149.6z"/>
|
||||
<path d="M388.5,160.7v0.5H384v-0.5l1.7-0.3h1.1L388.5,160.7z M386.8,154l0.2,0.1v7.1h-1.2v-6.1l-1.4,0.1v-0.6L386.8,154z"/>
|
||||
<g
|
||||
id="g206">
|
||||
<g
|
||||
id="g204">
|
||||
<path
|
||||
d="M377.6,161.1v0.6H373v-0.6l2-0.4h0.4L377.6,161.1z M374.5,152.8c0-1,0-1.5-0.1-2.3l-1.4-0.2v-0.6l2.4-1.1l0.3,0.2l0.1,1.5 h0.1v5.6l-0.1,0.1v1.8c0,1.3,0,2.6,0.1,3.8h-1.5c0-1.3,0.1-2.5,0.1-3.8V152.8z M378.2,149.6c-0.7,0-1.6,0.3-2.9,1.6l-0.2-0.3 c1-1.6,2.2-2.3,3.4-2.3c1.9,0,3.4,1.7,3.4,4.5s-1.6,4.5-3.7,4.5c-1.1,0-2.2-0.5-3.2-2.4l0.2-0.3c0.9,1.2,1.8,1.7,2.7,1.7 c1.4,0,2.5-1.1,2.5-3.4C380.5,150.9,379.5,149.6,378.2,149.6z"
|
||||
id="path200" />
|
||||
<path
|
||||
d="M388.5,160.7v0.5H384v-0.5l1.7-0.3h1.1L388.5,160.7z M386.8,154l0.2,0.1v7.1h-1.2v-6.1l-1.4,0.1v-0.6L386.8,154z"
|
||||
id="path202" />
|
||||
</g>
|
||||
</g>
|
||||
<g>
|
||||
<g>
|
||||
<path d="M210.7,105.5v0.6h-4.6v-0.6l2-0.4h0.4L210.7,105.5z M207.6,97.1c0-1,0-1.5-0.1-2.3l-1.4-0.2V94l2.4-1.1l0.3,0.2l0.1,1.5
|
||||
h0.1v5.6l-0.1,0.1v1.8c0,1.3,0,2.6,0.1,3.8h-1.5c0-1.3,0.1-2.5,0.1-3.8L207.6,97.1L207.6,97.1z M211.3,94c-0.7,0-1.6,0.3-2.9,1.6
|
||||
l-0.2-0.3c1-1.6,2.2-2.3,3.4-2.3c1.9,0,3.4,1.7,3.4,4.5s-1.6,4.5-3.7,4.5c-1.1,0-2.2-0.5-3.2-2.4l0.2-0.3c0.9,1.2,1.8,1.7,2.7,1.7
|
||||
c1.4,0,2.5-1.1,2.5-3.4C213.6,95.3,212.6,94,211.3,94z"/>
|
||||
<path d="M216.9,104.7l1.7-1.6c1.1-1,1.6-1.9,1.6-2.8s-0.5-1.4-1.4-1.4c-0.3,0-0.7,0.1-1.1,0.2l0.7-0.5l-0.3,1
|
||||
c-0.2,0.7-0.4,0.9-0.7,0.9s-0.5-0.2-0.6-0.4c0.1-1.2,1.2-1.8,2.5-1.8c1.6,0,2.2,0.9,2.2,1.9s-0.7,1.8-2.3,3.3l-1.7,1.6l0.3-0.7h4
|
||||
v1.2H217L216.9,104.7L216.9,104.7z"/>
|
||||
<g
|
||||
id="g214">
|
||||
<g
|
||||
id="g212">
|
||||
<path
|
||||
d="M210.7,105.5v0.6h-4.6v-0.6l2-0.4h0.4L210.7,105.5z M207.6,97.1c0-1,0-1.5-0.1-2.3l-1.4-0.2V94l2.4-1.1l0.3,0.2l0.1,1.5 h0.1v5.6l-0.1,0.1v1.8c0,1.3,0,2.6,0.1,3.8h-1.5c0-1.3,0.1-2.5,0.1-3.8L207.6,97.1L207.6,97.1z M211.3,94c-0.7,0-1.6,0.3-2.9,1.6 l-0.2-0.3c1-1.6,2.2-2.3,3.4-2.3c1.9,0,3.4,1.7,3.4,4.5s-1.6,4.5-3.7,4.5c-1.1,0-2.2-0.5-3.2-2.4l0.2-0.3c0.9,1.2,1.8,1.7,2.7,1.7 c1.4,0,2.5-1.1,2.5-3.4C213.6,95.3,212.6,94,211.3,94z"
|
||||
id="path208" />
|
||||
<path
|
||||
d="M216.9,104.7l1.7-1.6c1.1-1,1.6-1.9,1.6-2.8s-0.5-1.4-1.4-1.4c-0.3,0-0.7,0.1-1.1,0.2l0.7-0.5l-0.3,1 c-0.2,0.7-0.4,0.9-0.7,0.9s-0.5-0.2-0.6-0.4c0.1-1.2,1.2-1.8,2.5-1.8c1.6,0,2.2,0.9,2.2,1.9s-0.7,1.8-2.3,3.3l-1.7,1.6l0.3-0.7h4 v1.2H217L216.9,104.7L216.9,104.7z"
|
||||
id="path210" />
|
||||
</g>
|
||||
</g>
|
||||
<g>
|
||||
<g>
|
||||
<path d="M490.2,105.5v0.6h-4.6v-0.6l2-0.4h0.4L490.2,105.5z M487.1,97.1c0-1,0-1.5-0.1-2.3l-1.4-0.2V94l2.4-1.1l0.3,0.2l0.1,1.5
|
||||
h0.1v5.6l-0.1,0.1v1.8c0,1.3,0,2.6,0.1,3.8H487c0-1.3,0.1-2.5,0.1-3.8V97.1z M490.8,94c-0.7,0-1.6,0.3-2.9,1.6l-0.2-0.3
|
||||
c1-1.6,2.2-2.3,3.4-2.3c1.9,0,3.4,1.7,3.4,4.5s-1.6,4.5-3.7,4.5c-1.1,0-2.2-0.5-3.2-2.4l0.2-0.3c0.9,1.2,1.8,1.7,2.7,1.7
|
||||
c1.4,0,2.5-1.1,2.5-3.4C493.1,95.3,492.1,94,490.8,94z"/>
|
||||
<path d="M496.4,104.7l1.7-1.6c1.1-1,1.6-1.9,1.6-2.8s-0.5-1.4-1.4-1.4c-0.3,0-0.7,0.1-1.1,0.2l0.7-0.5l-0.3,1
|
||||
c-0.2,0.7-0.4,0.9-0.7,0.9c-0.3,0-0.5-0.2-0.6-0.4c0.1-1.2,1.2-1.8,2.5-1.8c1.6,0,2.2,0.9,2.2,1.9s-0.7,1.8-2.3,3.3l-1.7,1.6
|
||||
l0.3-0.7h4v1.2h-4.9V104.7z"/>
|
||||
<g
|
||||
id="g222">
|
||||
<g
|
||||
id="g220">
|
||||
<path
|
||||
d="M490.2,105.5v0.6h-4.6v-0.6l2-0.4h0.4L490.2,105.5z M487.1,97.1c0-1,0-1.5-0.1-2.3l-1.4-0.2V94l2.4-1.1l0.3,0.2l0.1,1.5 h0.1v5.6l-0.1,0.1v1.8c0,1.3,0,2.6,0.1,3.8H487c0-1.3,0.1-2.5,0.1-3.8V97.1z M490.8,94c-0.7,0-1.6,0.3-2.9,1.6l-0.2-0.3 c1-1.6,2.2-2.3,3.4-2.3c1.9,0,3.4,1.7,3.4,4.5s-1.6,4.5-3.7,4.5c-1.1,0-2.2-0.5-3.2-2.4l0.2-0.3c0.9,1.2,1.8,1.7,2.7,1.7 c1.4,0,2.5-1.1,2.5-3.4C493.1,95.3,492.1,94,490.8,94z"
|
||||
id="path216" />
|
||||
<path
|
||||
d="M496.4,104.7l1.7-1.6c1.1-1,1.6-1.9,1.6-2.8s-0.5-1.4-1.4-1.4c-0.3,0-0.7,0.1-1.1,0.2l0.7-0.5l-0.3,1 c-0.2,0.7-0.4,0.9-0.7,0.9c-0.3,0-0.5-0.2-0.6-0.4c0.1-1.2,1.2-1.8,2.5-1.8c1.6,0,2.2,0.9,2.2,1.9s-0.7,1.8-2.3,3.3l-1.7,1.6 l0.3-0.7h4v1.2h-4.9V104.7z"
|
||||
id="path218" />
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
<path
|
||||
d="m 44.898817,47.364552 c 0,2.6 -1.2,3.7 -2.5,3.7 -1.3,0 -2.5,-1.1 -2.5,-3.7 0,-2.6 1.2,-3.7 2.5,-3.7 1.3,-0.1 2.5,1 2.5,3.7 z m -2.5,3.1 c 0.6,0 1.2,-0.6 1.2,-3.1 0,-2.6 -0.6,-3.1 -1.2,-3.1 -0.6,0 -1.2,0.5 -1.2,3.1 0,2.5 0.6,3.1 1.2,3.1 z"
|
||||
id="path178-6" /><path
|
||||
d="m 72.819403,84.595293 c 0,2.6 -1.2,3.7 -2.5,3.7 -1.3,0 -2.5,-1.1 -2.5,-3.7 0,-2.6 1.2,-3.7 2.5,-3.7 1.3,-0.1 2.5,1 2.5,3.7 z m -2.5,3.1 c 0.6,0 1.2,-0.6 1.2,-3.1 0,-2.6 -0.6,-3.1 -1.2,-3.1 -0.6,0 -1.2,0.5 -1.2,3.1 0,2.5 0.6,3.1 1.2,3.1 z"
|
||||
id="path178-6-5" /><text
|
||||
xml:space="preserve"
|
||||
style="font-style:normal;font-weight:normal;font-size:40px;line-height:1.25;font-family:sans-serif;fill:#000000;fill-opacity:1;stroke:none"
|
||||
x="142.27249"
|
||||
y="19.292274"
|
||||
id="text704"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan702"></tspan></text></svg>
|
||||
|
|
|
|||
|
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 15 KiB |
|
|
@ -1,79 +1,163 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Generator: Adobe Illustrator 24.0.3, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||
width="222.1px" height="160.6px" viewBox="0 0 222.1 160.6" style="enable-background:new 0 0 222.1 160.6;" xml:space="preserve"
|
||||
>
|
||||
<style type="text/css">
|
||||
|
||||
<svg
|
||||
version="1.1"
|
||||
id="Layer_1"
|
||||
x="0px"
|
||||
y="0px"
|
||||
width="222.1px"
|
||||
height="160.6px"
|
||||
viewBox="0 0 222.1 160.6"
|
||||
style="enable-background:new 0 0 222.1 160.6;"
|
||||
xml:space="preserve"
|
||||
sodipodi:docname="mean_value.svg"
|
||||
inkscape:version="1.2.1 (9c6d41e410, 2022-07-14)"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"><defs
|
||||
id="defs73" /><sodipodi:namedview
|
||||
id="namedview71"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
inkscape:showpageshadow="2"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pagecheckerboard="0"
|
||||
inkscape:deskcolor="#d1d1d1"
|
||||
showgrid="false"
|
||||
inkscape:zoom="6.1008553"
|
||||
inkscape:cx="92.282143"
|
||||
inkscape:cy="61.30288"
|
||||
inkscape:window-width="2560"
|
||||
inkscape:window-height="1371"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-y="0"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:current-layer="Layer_1" />
|
||||
<style
|
||||
type="text/css"
|
||||
id="style2">
|
||||
.st0{fill:none;stroke:#000000;stroke-miterlimit:10;}
|
||||
</style>
|
||||
<circle cx="3.7" cy="86.8" r="2.5"/>
|
||||
<circle cx="96.2" cy="139.7" r="2.5"/>
|
||||
<circle cx="209.3" cy="82.5" r="2.5"/>
|
||||
<circle cx="90.2" cy="20.2" r="2.5"/>
|
||||
<line class="st0" x1="90.2" y1="20.2" x2="3.7" y2="86.8"/>
|
||||
<line class="st0" x1="96.2" y1="139.7" x2="90.2" y2="20.2"/>
|
||||
<line class="st0" x1="209.3" y1="82.4" x2="90.2" y2="20.2"/>
|
||||
<g>
|
||||
<g>
|
||||
<path d="M86.6,8c0.9,0,1.5-0.4,2.4-1.5L89.2,7c-0.8,1.4-1.7,2-2.9,2c-2.2,0-3.7-1.8-3.7-4.4c0-2.7,1.6-4.6,3.8-4.6
|
||||
c1,0,2,0.4,2.9,1.8l-0.2,0.5c-1-1-1.8-1.3-2.4-1.3c-1.4,0-2.5,1.1-2.5,3.6C84.1,6.9,85.2,8,86.6,8z M89.7,12.1l2,0.4v0.6h-4.6
|
||||
v-0.6l2.2-0.4H89.7z M90.3,13.1h-1.5c0-1.3,0.1-2.6,0.1-3.8V7.5l-0.1-0.3V1.3L90,0l0.3,0.2l-0.1,2.4v6.7
|
||||
C90.2,10.5,90.2,11.8,90.3,13.1z"/>
|
||||
<circle
|
||||
cx="3.7"
|
||||
cy="86.8"
|
||||
r="2.5"
|
||||
id="circle4" />
|
||||
<circle
|
||||
cx="96.2"
|
||||
cy="139.7"
|
||||
r="2.5"
|
||||
id="circle6" />
|
||||
<circle
|
||||
cx="209.3"
|
||||
cy="82.5"
|
||||
r="2.5"
|
||||
id="circle8" />
|
||||
<circle
|
||||
cx="90.2"
|
||||
cy="20.2"
|
||||
r="2.5"
|
||||
id="circle10" />
|
||||
<line
|
||||
class="st0"
|
||||
x1="90.2"
|
||||
y1="20.2"
|
||||
x2="3.7"
|
||||
y2="86.8"
|
||||
id="line12" />
|
||||
<line
|
||||
class="st0"
|
||||
x1="96.2"
|
||||
y1="139.7"
|
||||
x2="90.2"
|
||||
y2="20.2"
|
||||
id="line14" />
|
||||
<line
|
||||
class="st0"
|
||||
x1="209.3"
|
||||
y1="82.4"
|
||||
x2="90.2"
|
||||
y2="20.2"
|
||||
id="line16" />
|
||||
<g
|
||||
id="g22">
|
||||
<g
|
||||
id="g20">
|
||||
<path
|
||||
d="M86.6,8c0.9,0,1.5-0.4,2.4-1.5L89.2,7c-0.8,1.4-1.7,2-2.9,2c-2.2,0-3.7-1.8-3.7-4.4c0-2.7,1.6-4.6,3.8-4.6 c1,0,2,0.4,2.9,1.8l-0.2,0.5c-1-1-1.8-1.3-2.4-1.3c-1.4,0-2.5,1.1-2.5,3.6C84.1,6.9,85.2,8,86.6,8z M89.7,12.1l2,0.4v0.6h-4.6 v-0.6l2.2-0.4H89.7z M90.3,13.1h-1.5c0-1.3,0.1-2.6,0.1-3.8V7.5l-0.1-0.3V1.3L90,0l0.3,0.2l-0.1,2.4v6.7 C90.2,10.5,90.2,11.8,90.3,13.1z"
|
||||
id="path18" />
|
||||
</g>
|
||||
</g>
|
||||
<g>
|
||||
<g>
|
||||
<path d="M33.9,48.3c0.9,0,1.5-0.4,2.4-1.5l0.2,0.5c-0.7,1.2-1.5,2-2.9,2c-2.2,0-3.7-1.8-3.7-4.4c0-2.7,1.6-4.6,3.8-4.6
|
||||
c1,0,1.9,0.4,2.8,1.8l-0.2,0.5c-1-1-1.8-1.3-2.4-1.3c-1.4,0-2.5,1.1-2.5,3.5C31.4,47.2,32.5,48.3,33.9,48.3z M38.9,48.4V49
|
||||
l-2.7,0.2L36,47.4v-5.3l0.1-0.2v-4.5l-1.5-0.2v-0.6l2.8-0.8l0.3,0.1l-0.1,2.6v10.6l-0.3-0.9L38.9,48.4z"/>
|
||||
<path d="M44.8,48.5V49h-4.5v-0.5l1.7-0.3h1.2L44.8,48.5z M43.1,41.8l0.2,0.1V49h-1.2v-6.1L40.7,43v-0.6L43.1,41.8z"/>
|
||||
<g
|
||||
id="g30">
|
||||
<g
|
||||
id="g28">
|
||||
<path
|
||||
d="M33.9,48.3c0.9,0,1.5-0.4,2.4-1.5l0.2,0.5c-0.7,1.2-1.5,2-2.9,2c-2.2,0-3.7-1.8-3.7-4.4c0-2.7,1.6-4.6,3.8-4.6 c1,0,1.9,0.4,2.8,1.8l-0.2,0.5c-1-1-1.8-1.3-2.4-1.3c-1.4,0-2.5,1.1-2.5,3.5C31.4,47.2,32.5,48.3,33.9,48.3z M38.9,48.4V49 l-2.7,0.2L36,47.4v-5.3l0.1-0.2v-4.5l-1.5-0.2v-0.6l2.8-0.8l0.3,0.1l-0.1,2.6v10.6l-0.3-0.9L38.9,48.4z"
|
||||
id="path24" />
|
||||
|
||||
</g>
|
||||
</g>
|
||||
<g>
|
||||
<g>
|
||||
<path d="M103.6,88.5c0.9,0,1.5-0.4,2.4-1.5l0.2,0.5c-0.7,1.2-1.5,2-2.9,2c-2.2,0-3.7-1.8-3.7-4.4c0-2.7,1.6-4.6,3.8-4.6
|
||||
c1,0,1.9,0.4,2.8,1.8l-0.2,0.5c-1-1-1.8-1.3-2.4-1.3c-1.4,0-2.5,1.1-2.5,3.5C101.1,87.4,102.1,88.5,103.6,88.5z M108.6,88.7v0.6
|
||||
l-2.8,0.2l-0.2-1.8v-5.3l0.1-0.2v-4.5l-1.5-0.2v-0.6l2.8-0.8l0.3,0.1l-0.1,2.6v10.6l-0.3-0.9L108.6,88.7z"/>
|
||||
<g
|
||||
id="g36">
|
||||
<g
|
||||
id="g34">
|
||||
<path
|
||||
d="M103.6,88.5c0.9,0,1.5-0.4,2.4-1.5l0.2,0.5c-0.7,1.2-1.5,2-2.9,2c-2.2,0-3.7-1.8-3.7-4.4c0-2.7,1.6-4.6,3.8-4.6 c1,0,1.9,0.4,2.8,1.8l-0.2,0.5c-1-1-1.8-1.3-2.4-1.3c-1.4,0-2.5,1.1-2.5,3.5C101.1,87.4,102.1,88.5,103.6,88.5z M108.6,88.7v0.6 l-2.8,0.2l-0.2-1.8v-5.3l0.1-0.2v-4.5l-1.5-0.2v-0.6l2.8-0.8l0.3,0.1l-0.1,2.6v10.6l-0.3-0.9L108.6,88.7z"
|
||||
id="path32" />
|
||||
</g>
|
||||
</g>
|
||||
<g>
|
||||
<g>
|
||||
<path d="M155.6,47.3c0.9,0,1.5-0.4,2.4-1.5l0.2,0.5c-0.7,1.2-1.5,2-2.9,2c-2.2,0-3.7-1.8-3.7-4.4c0-2.7,1.6-4.6,3.8-4.6
|
||||
c1,0,1.9,0.4,2.8,1.8l-0.2,0.5c-1-1-1.8-1.3-2.4-1.3c-1.3,0-2.5,1.1-2.5,3.5C153.1,46.2,154.2,47.3,155.6,47.3z M160.7,47.4V48
|
||||
l-2.8,0.2l-0.2-1.8v-5.3l0.1-0.2v-4.5l-1.5-0.2v-0.6l2.8-0.8l0.3,0.1l-0.1,2.6v10.6l-0.3-0.9L160.7,47.4z"/>
|
||||
<path d="M161.9,47.2l1.7-1.6c1.1-1,1.6-1.9,1.6-2.8c0-0.9-0.5-1.4-1.4-1.4c-0.3,0-0.7,0.1-1.1,0.2l0.7-0.5l-0.3,1
|
||||
c-0.2,0.7-0.4,0.9-0.7,0.9s-0.5-0.2-0.6-0.4c0.1-1.2,1.2-1.8,2.5-1.8c1.6,0,2.2,0.9,2.2,1.9s-0.7,1.8-2.3,3.3l-1.7,1.6l0.3-0.7h4
|
||||
v1.2H162L161.9,47.2L161.9,47.2z"/>
|
||||
<g
|
||||
id="g44">
|
||||
<g
|
||||
id="g42">
|
||||
<path
|
||||
d="M155.6,47.3c0.9,0,1.5-0.4,2.4-1.5l0.2,0.5c-0.7,1.2-1.5,2-2.9,2c-2.2,0-3.7-1.8-3.7-4.4c0-2.7,1.6-4.6,3.8-4.6 c1,0,1.9,0.4,2.8,1.8l-0.2,0.5c-1-1-1.8-1.3-2.4-1.3c-1.3,0-2.5,1.1-2.5,3.5C153.1,46.2,154.2,47.3,155.6,47.3z M160.7,47.4V48 l-2.8,0.2l-0.2-1.8v-5.3l0.1-0.2v-4.5l-1.5-0.2v-0.6l2.8-0.8l0.3,0.1l-0.1,2.6v10.6l-0.3-0.9L160.7,47.4z"
|
||||
id="path38" />
|
||||
<path
|
||||
d="M161.9,47.2l1.7-1.6c1.1-1,1.6-1.9,1.6-2.8c0-0.9-0.5-1.4-1.4-1.4c-0.3,0-0.7,0.1-1.1,0.2l0.7-0.5l-0.3,1 c-0.2,0.7-0.4,0.9-0.7,0.9s-0.5-0.2-0.6-0.4c0.1-1.2,1.2-1.8,2.5-1.8c1.6,0,2.2,0.9,2.2,1.9s-0.7,1.8-2.3,3.3l-1.7,1.6l0.3-0.7h4 v1.2H162L161.9,47.2L161.9,47.2z"
|
||||
id="path40" />
|
||||
</g>
|
||||
</g>
|
||||
<g>
|
||||
<g>
|
||||
<path d="M4.6,108v0.6H0V108l2-0.4h0.4L4.6,108z M1.5,99.7c0-1,0-1.5-0.1-2.3L0,97.2v-0.6l2.4-1.1l0.3,0.2l0.1,1.5h0.1v5.6l0,0.2
|
||||
v1.8c0,1.3,0,2.6,0.1,3.8H1.5c0-1.3,0.1-2.5,0.1-3.8L1.5,99.7L1.5,99.7z M5.2,96.5c-0.7,0-1.6,0.3-2.9,1.6l-0.2-0.3
|
||||
c1-1.6,2.2-2.3,3.4-2.3c1.9,0,3.4,1.7,3.4,4.5s-1.6,4.5-3.7,4.5c-1.1,0-2.2-0.5-3.2-2.4l0.2-0.3c0.9,1.2,1.8,1.7,2.7,1.7
|
||||
c1.4,0,2.5-1.1,2.5-3.4C7.5,97.8,6.5,96.5,5.2,96.5z"/>
|
||||
<path d="M15.7,104.6c0,2.6-1.2,3.7-2.5,3.7c-1.3,0-2.5-1.1-2.5-3.7s1.2-3.7,2.5-3.7C14.5,100.8,15.7,101.9,15.7,104.6z
|
||||
M13.2,107.7c0.6,0,1.2-0.6,1.2-3.1c0-2.6-0.6-3.1-1.2-3.1c-0.6,0-1.2,0.5-1.2,3.1C12,107.1,12.6,107.7,13.2,107.7z"/>
|
||||
<g
|
||||
id="g52">
|
||||
<g
|
||||
id="g50">
|
||||
<path
|
||||
d="M4.6,108v0.6H0V108l2-0.4h0.4L4.6,108z M1.5,99.7c0-1,0-1.5-0.1-2.3L0,97.2v-0.6l2.4-1.1l0.3,0.2l0.1,1.5h0.1v5.6l0,0.2 v1.8c0,1.3,0,2.6,0.1,3.8H1.5c0-1.3,0.1-2.5,0.1-3.8L1.5,99.7L1.5,99.7z M5.2,96.5c-0.7,0-1.6,0.3-2.9,1.6l-0.2-0.3 c1-1.6,2.2-2.3,3.4-2.3c1.9,0,3.4,1.7,3.4,4.5s-1.6,4.5-3.7,4.5c-1.1,0-2.2-0.5-3.2-2.4l0.2-0.3c0.9,1.2,1.8,1.7,2.7,1.7 c1.4,0,2.5-1.1,2.5-3.4C7.5,97.8,6.5,96.5,5.2,96.5z"
|
||||
id="path46" />
|
||||
<path
|
||||
d="M15.7,104.6c0,2.6-1.2,3.7-2.5,3.7c-1.3,0-2.5-1.1-2.5-3.7s1.2-3.7,2.5-3.7C14.5,100.8,15.7,101.9,15.7,104.6z M13.2,107.7c0.6,0,1.2-0.6,1.2-3.1c0-2.6-0.6-3.1-1.2-3.1c-0.6,0-1.2,0.5-1.2,3.1C12,107.1,12.6,107.7,13.2,107.7z"
|
||||
id="path48" />
|
||||
</g>
|
||||
</g>
|
||||
<g>
|
||||
<g>
|
||||
<path d="M97.9,160v0.6h-4.6V160l2-0.4h0.4L97.9,160z M94.8,151.7c0-1,0-1.5-0.1-2.3l-1.4-0.2v-0.6l2.4-1.1l0.3,0.2l0.1,1.5h0.1
|
||||
v5.6l-0.1,0.1v1.8c0,1.3,0,2.6,0.1,3.8h-1.5c0-1.3,0.1-2.5,0.1-3.8V151.7z M98.5,148.6c-0.7,0-1.6,0.3-2.9,1.6l-0.2-0.3
|
||||
c1-1.6,2.2-2.3,3.4-2.3c1.9,0,3.4,1.7,3.4,4.5s-1.6,4.5-3.7,4.5c-1.1,0-2.2-0.5-3.2-2.4l0.2-0.3c0.9,1.2,1.8,1.7,2.7,1.7
|
||||
c1.4,0,2.5-1.1,2.5-3.4C100.8,149.9,99.8,148.6,98.5,148.6z"/>
|
||||
<path d="M108.8,159.6v0.5h-4.5v-0.5l1.7-0.3h1.1L108.8,159.6z M107.1,152.9l0.2,0.1v7.1h-1.2V154l-1.4,0.1v-0.6L107.1,152.9z"/>
|
||||
<g
|
||||
id="g60">
|
||||
<g
|
||||
id="g58">
|
||||
<path
|
||||
d="M97.9,160v0.6h-4.6V160l2-0.4h0.4L97.9,160z M94.8,151.7c0-1,0-1.5-0.1-2.3l-1.4-0.2v-0.6l2.4-1.1l0.3,0.2l0.1,1.5h0.1 v5.6l-0.1,0.1v1.8c0,1.3,0,2.6,0.1,3.8h-1.5c0-1.3,0.1-2.5,0.1-3.8V151.7z M98.5,148.6c-0.7,0-1.6,0.3-2.9,1.6l-0.2-0.3 c1-1.6,2.2-2.3,3.4-2.3c1.9,0,3.4,1.7,3.4,4.5s-1.6,4.5-3.7,4.5c-1.1,0-2.2-0.5-3.2-2.4l0.2-0.3c0.9,1.2,1.8,1.7,2.7,1.7 c1.4,0,2.5-1.1,2.5-3.4C100.8,149.9,99.8,148.6,98.5,148.6z"
|
||||
id="path54" />
|
||||
<path
|
||||
d="M108.8,159.6v0.5h-4.5v-0.5l1.7-0.3h1.1L108.8,159.6z M107.1,152.9l0.2,0.1v7.1h-1.2V154l-1.4,0.1v-0.6L107.1,152.9z"
|
||||
id="path56" />
|
||||
</g>
|
||||
</g>
|
||||
<g>
|
||||
<g>
|
||||
<path d="M211,103.4v0.6h-4.6v-0.6l2-0.4h0.4L211,103.4z M207.9,95c0-1,0-1.5-0.1-2.3l-1.4-0.2V92l2.4-1.1l0.3,0.2l0.1,1.5h0.1v5.6
|
||||
l-0.1,0.1v1.8c0,1.3,0,2.6,0.1,3.8h-1.5c0-1.3,0.1-2.5,0.1-3.8L207.9,95L207.9,95z M211.6,91.9c-0.7,0-1.6,0.3-2.9,1.6l-0.2-0.3
|
||||
c1-1.6,2.2-2.3,3.4-2.3c1.9,0,3.4,1.7,3.4,4.5s-1.6,4.5-3.7,4.5c-1.1,0-2.2-0.5-3.2-2.4l0.2-0.3c0.9,1.2,1.8,1.7,2.7,1.7
|
||||
c1.4,0,2.5-1.1,2.5-3.4C213.9,93.2,212.9,91.9,211.6,91.9z"/>
|
||||
<path d="M217.2,102.6l1.7-1.6c1.1-1,1.6-1.9,1.6-2.8s-0.5-1.4-1.4-1.4c-0.3,0-0.7,0.1-1.1,0.2l0.7-0.5l-0.3,1
|
||||
c-0.2,0.7-0.4,0.9-0.7,0.9s-0.5-0.2-0.6-0.4c0.1-1.2,1.2-1.8,2.5-1.8c1.6,0,2.2,0.9,2.2,1.9s-0.7,1.8-2.3,3.3l-1.7,1.6l0.3-0.7h4
|
||||
v1.2h-4.8L217.2,102.6L217.2,102.6z"/>
|
||||
<g
|
||||
id="g68">
|
||||
<g
|
||||
id="g66">
|
||||
<path
|
||||
d="M211,103.4v0.6h-4.6v-0.6l2-0.4h0.4L211,103.4z M207.9,95c0-1,0-1.5-0.1-2.3l-1.4-0.2V92l2.4-1.1l0.3,0.2l0.1,1.5h0.1v5.6 l-0.1,0.1v1.8c0,1.3,0,2.6,0.1,3.8h-1.5c0-1.3,0.1-2.5,0.1-3.8L207.9,95L207.9,95z M211.6,91.9c-0.7,0-1.6,0.3-2.9,1.6l-0.2-0.3 c1-1.6,2.2-2.3,3.4-2.3c1.9,0,3.4,1.7,3.4,4.5s-1.6,4.5-3.7,4.5c-1.1,0-2.2-0.5-3.2-2.4l0.2-0.3c0.9,1.2,1.8,1.7,2.7,1.7 c1.4,0,2.5-1.1,2.5-3.4C213.9,93.2,212.9,91.9,211.6,91.9z"
|
||||
id="path62" />
|
||||
<path
|
||||
d="M217.2,102.6l1.7-1.6c1.1-1,1.6-1.9,1.6-2.8s-0.5-1.4-1.4-1.4c-0.3,0-0.7,0.1-1.1,0.2l0.7-0.5l-0.3,1 c-0.2,0.7-0.4,0.9-0.7,0.9s-0.5-0.2-0.6-0.4c0.1-1.2,1.2-1.8,2.5-1.8c1.6,0,2.2,0.9,2.2,1.9s-0.7,1.8-2.3,3.3l-1.7,1.6l0.3-0.7h4 v1.2h-4.8L217.2,102.6L217.2,102.6z"
|
||||
id="path64" />
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
<path
|
||||
d="m 45.019848,45.642636 c 0,2.6 -1.2,3.7 -2.5,3.7 -1.3,0 -2.5,-1.1 -2.5,-3.7 0,-2.6 1.2,-3.7 2.5,-3.7 1.3,-0.1 2.5,1 2.5,3.7 z m -2.5,3.1 c 0.6,0 1.2,-0.6 1.2,-3.1 0,-2.6 -0.6,-3.1 -1.2,-3.1 -0.6,0 -1.2,0.5 -1.2,3.1 0,2.5 0.6,3.1 1.2,3.1 z"
|
||||
id="path48-3" /></svg>
|
||||
|
|
|
|||
|
Before Width: | Height: | Size: 4.6 KiB After Width: | Height: | Size: 6.1 KiB |
|
|
@ -1,93 +1,174 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Generator: Adobe Illustrator 24.0.3, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||
width="222.1px" height="161.4px" viewBox="0 0 222.1 161.4" style="enable-background:new 0 0 222.1 161.4;" xml:space="preserve"
|
||||
>
|
||||
<style type="text/css">
|
||||
|
||||
<svg
|
||||
version="1.1"
|
||||
id="Layer_1"
|
||||
x="0px"
|
||||
y="0px"
|
||||
width="222.1px"
|
||||
height="161.4px"
|
||||
viewBox="0 0 222.1 161.4"
|
||||
style="enable-background:new 0 0 222.1 161.4;"
|
||||
xml:space="preserve"
|
||||
sodipodi:docname="tangent.svg"
|
||||
inkscape:version="1.2.1 (9c6d41e410, 2022-07-14)"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"><defs
|
||||
id="defs87" /><sodipodi:namedview
|
||||
id="namedview85"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
inkscape:showpageshadow="2"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pagecheckerboard="0"
|
||||
inkscape:deskcolor="#d1d1d1"
|
||||
showgrid="false"
|
||||
inkscape:zoom="4.3139562"
|
||||
inkscape:cx="207.00257"
|
||||
inkscape:cy="57.951447"
|
||||
inkscape:window-width="2560"
|
||||
inkscape:window-height="1371"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-y="0"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:current-layer="Layer_1" />
|
||||
<style
|
||||
type="text/css"
|
||||
id="style2">
|
||||
.st0{fill:none;stroke:#000000;stroke-miterlimit:10;}
|
||||
</style>
|
||||
<circle cx="3.7" cy="86.7" r="2.5"/>
|
||||
<circle cx="96.2" cy="139.6" r="2.5"/>
|
||||
<circle cx="209.3" cy="82.4" r="2.5"/>
|
||||
<circle cx="90.2" cy="20.1" r="2.5"/>
|
||||
<polyline class="st0" points="90.2,20.1 3.7,86.7 96.2,139.6 90.2,20.1 "/>
|
||||
<polyline class="st0" points="96.2,139.6 209.3,82.3 90.2,20.1 "/>
|
||||
<g>
|
||||
<g>
|
||||
<path d="M87,8c0.9,0,1.5-0.4,2.4-1.5L89.6,7c-0.8,1.4-1.7,2-2.9,2C84.5,9,83,7.2,83,4.6C83,1.9,84.6,0,86.8,0c1,0,2,0.4,2.9,1.8
|
||||
l-0.2,0.5c-1-1-1.8-1.3-2.4-1.3c-1.4,0-2.5,1.1-2.5,3.6C84.5,6.9,85.5,8,87,8z M90.1,12.1l2,0.4v0.6h-4.6v-0.6l2.2-0.4H90.1z
|
||||
M90.6,13.1h-1.5c0-1.3,0.1-2.6,0.1-3.8V7.5l-0.1-0.3V1.3L90.3,0l0.3,0.2l-0.1,2.4v6.7C90.6,10.5,90.6,11.8,90.6,13.1z"/>
|
||||
<circle
|
||||
cx="3.7"
|
||||
cy="86.7"
|
||||
r="2.5"
|
||||
id="circle4" />
|
||||
<circle
|
||||
cx="96.2"
|
||||
cy="139.6"
|
||||
r="2.5"
|
||||
id="circle6" />
|
||||
<circle
|
||||
cx="209.3"
|
||||
cy="82.4"
|
||||
r="2.5"
|
||||
id="circle8" />
|
||||
<circle
|
||||
cx="90.2"
|
||||
cy="20.1"
|
||||
r="2.5"
|
||||
id="circle10" />
|
||||
<polyline
|
||||
class="st0"
|
||||
points="90.2,20.1 3.7,86.7 96.2,139.6 90.2,20.1 "
|
||||
id="polyline12" />
|
||||
<polyline
|
||||
class="st0"
|
||||
points="96.2,139.6 209.3,82.3 90.2,20.1 "
|
||||
id="polyline14" />
|
||||
<g
|
||||
id="g20">
|
||||
<g
|
||||
id="g18">
|
||||
<path
|
||||
d="M87,8c0.9,0,1.5-0.4,2.4-1.5L89.6,7c-0.8,1.4-1.7,2-2.9,2C84.5,9,83,7.2,83,4.6C83,1.9,84.6,0,86.8,0c1,0,2,0.4,2.9,1.8 l-0.2,0.5c-1-1-1.8-1.3-2.4-1.3c-1.4,0-2.5,1.1-2.5,3.6C84.5,6.9,85.5,8,87,8z M90.1,12.1l2,0.4v0.6h-4.6v-0.6l2.2-0.4H90.1z M90.6,13.1h-1.5c0-1.3,0.1-2.6,0.1-3.8V7.5l-0.1-0.3V1.3L90.3,0l0.3,0.2l-0.1,2.4v6.7C90.6,10.5,90.6,11.8,90.6,13.1z"
|
||||
id="path16" />
|
||||
</g>
|
||||
</g>
|
||||
<g>
|
||||
<g>
|
||||
<path d="M34.3,48.4c0.9,0,1.5-0.4,2.4-1.5l0.2,0.5c-0.7,1.2-1.5,2-2.9,2c-2.2,0-3.7-1.8-3.7-4.4c0-2.7,1.6-4.6,3.8-4.6
|
||||
c1,0,1.9,0.4,2.8,1.8l-0.2,0.5c-1-1-1.8-1.3-2.4-1.3c-1.4,0-2.5,1.1-2.5,3.5C31.8,47.3,32.9,48.4,34.3,48.4z M39.3,48.5v0.6
|
||||
l-2.8,0.2l-0.2-1.8v-5.3l0.1-0.2v-4.5l-1.5-0.2v-0.6l2.8-0.8L38,36l-0.1,2.6v10.6l-0.3-0.9L39.3,48.5z"/>
|
||||
<path d="M45.2,48.6v0.5h-4.5v-0.5l1.7-0.3h1.1L45.2,48.6z M43.5,41.9l0.2,0.1v7.1h-1.2V43l-1.4,0.1v-0.6L43.5,41.9z"/>
|
||||
<g
|
||||
id="g28">
|
||||
<g
|
||||
id="g26">
|
||||
<path
|
||||
d="M34.3,48.4c0.9,0,1.5-0.4,2.4-1.5l0.2,0.5c-0.7,1.2-1.5,2-2.9,2c-2.2,0-3.7-1.8-3.7-4.4c0-2.7,1.6-4.6,3.8-4.6 c1,0,1.9,0.4,2.8,1.8l-0.2,0.5c-1-1-1.8-1.3-2.4-1.3c-1.4,0-2.5,1.1-2.5,3.5C31.8,47.3,32.9,48.4,34.3,48.4z M39.3,48.5v0.6 l-2.8,0.2l-0.2-1.8v-5.3l0.1-0.2v-4.5l-1.5-0.2v-0.6l2.8-0.8L38,36l-0.1,2.6v10.6l-0.3-0.9L39.3,48.5z"
|
||||
id="path22" />
|
||||
|
||||
</g>
|
||||
</g>
|
||||
<g>
|
||||
<g>
|
||||
<path d="M102.1,75.4c0.9,0,1.5-0.4,2.4-1.5l0.2,0.5c-0.7,1.2-1.5,2-2.9,2c-2.2,0-3.7-1.8-3.7-4.4c0-2.7,1.6-4.6,3.8-4.6
|
||||
c1,0,1.9,0.4,2.8,1.8l-0.2,0.5c-1-1-1.8-1.3-2.4-1.3c-1.4,0-2.5,1.1-2.5,3.5C99.6,74.3,100.6,75.4,102.1,75.4z M107.1,75.5v0.6
|
||||
l-2.8,0.2l-0.2-1.8v-5.3l0.1-0.2v-4.5l-1.5-0.2v-0.6l2.8-0.8l0.3,0.1l-0.1,2.6v10.6l-0.3-0.9L107.1,75.5z"/>
|
||||
<g
|
||||
id="g34">
|
||||
<g
|
||||
id="g32">
|
||||
<path
|
||||
d="M102.1,75.4c0.9,0,1.5-0.4,2.4-1.5l0.2,0.5c-0.7,1.2-1.5,2-2.9,2c-2.2,0-3.7-1.8-3.7-4.4c0-2.7,1.6-4.6,3.8-4.6 c1,0,1.9,0.4,2.8,1.8l-0.2,0.5c-1-1-1.8-1.3-2.4-1.3c-1.4,0-2.5,1.1-2.5,3.5C99.6,74.3,100.6,75.4,102.1,75.4z M107.1,75.5v0.6 l-2.8,0.2l-0.2-1.8v-5.3l0.1-0.2v-4.5l-1.5-0.2v-0.6l2.8-0.8l0.3,0.1l-0.1,2.6v10.6l-0.3-0.9L107.1,75.5z"
|
||||
id="path30" />
|
||||
</g>
|
||||
</g>
|
||||
<g>
|
||||
<g>
|
||||
<path d="M158,48.4c0.9,0,1.5-0.4,2.4-1.5l0.2,0.5c-0.7,1.2-1.5,2-2.9,2c-2.2,0-3.7-1.8-3.7-4.4c0-2.7,1.6-4.6,3.8-4.6
|
||||
c1,0,1.9,0.4,2.8,1.8l-0.2,0.5c-1-1-1.8-1.3-2.4-1.3c-1.4,0-2.5,1.1-2.5,3.5C155.4,47.3,156.5,48.4,158,48.4z M163,48.5v0.6
|
||||
l-2.8,0.2l-0.2-1.8v-5.3l0.1-0.2v-4.5l-1.5-0.2v-0.6l2.8-0.8l0.3,0.1l-0.1,2.6v10.6l-0.3-0.9L163,48.5z"/>
|
||||
<path d="M164.2,48.3l1.7-1.6c1.1-1,1.6-1.9,1.6-2.8c0-0.9-0.5-1.4-1.4-1.4c-0.3,0-0.7,0.1-1.1,0.2l0.7-0.5l-0.3,1
|
||||
c-0.2,0.7-0.4,0.9-0.7,0.9s-0.5-0.2-0.6-0.4c0.1-1.2,1.2-1.8,2.5-1.8c1.6,0,2.2,0.9,2.2,1.9s-0.7,1.8-2.3,3.3l-1.7,1.6l0.3-0.7h4
|
||||
v1.2h-4.9V48.3z"/>
|
||||
<g
|
||||
id="g42">
|
||||
<g
|
||||
id="g40">
|
||||
<path
|
||||
d="M158,48.4c0.9,0,1.5-0.4,2.4-1.5l0.2,0.5c-0.7,1.2-1.5,2-2.9,2c-2.2,0-3.7-1.8-3.7-4.4c0-2.7,1.6-4.6,3.8-4.6 c1,0,1.9,0.4,2.8,1.8l-0.2,0.5c-1-1-1.8-1.3-2.4-1.3c-1.4,0-2.5,1.1-2.5,3.5C155.4,47.3,156.5,48.4,158,48.4z M163,48.5v0.6 l-2.8,0.2l-0.2-1.8v-5.3l0.1-0.2v-4.5l-1.5-0.2v-0.6l2.8-0.8l0.3,0.1l-0.1,2.6v10.6l-0.3-0.9L163,48.5z"
|
||||
id="path36" />
|
||||
<path
|
||||
d="M164.2,48.3l1.7-1.6c1.1-1,1.6-1.9,1.6-2.8c0-0.9-0.5-1.4-1.4-1.4c-0.3,0-0.7,0.1-1.1,0.2l0.7-0.5l-0.3,1 c-0.2,0.7-0.4,0.9-0.7,0.9s-0.5-0.2-0.6-0.4c0.1-1.2,1.2-1.8,2.5-1.8c1.6,0,2.2,0.9,2.2,1.9s-0.7,1.8-2.3,3.3l-1.7,1.6l0.3-0.7h4 v1.2h-4.9V48.3z"
|
||||
id="path38" />
|
||||
</g>
|
||||
</g>
|
||||
<g>
|
||||
<g>
|
||||
<path d="M50,83.6l1.8-0.3h0.4l2,0.3v0.7h-4.1v-0.7H50z M55.4,72.2h1.1l4.1,12.2h-1.7l-3.6-10.8h0.4L52,84.4h-0.8L55.4,72.2z
|
||||
M53.3,79.6h4.9l0.3,0.8h-5.4L53.3,79.6z M56.8,83.6l2.3-0.3h0.4l2.2,0.3v0.7h-4.9V83.6z"/>
|
||||
<path d="M67.5,83.8v0.5H63v-0.5l1.7-0.3h1.1L67.5,83.8z M65.8,77.1l0.2,0.1v7.1h-1.2v-6.1l-1.4,0.1v-0.6L65.8,77.1z"/>
|
||||
<g
|
||||
id="g50">
|
||||
<g
|
||||
id="g48">
|
||||
<path
|
||||
d="M50,83.6l1.8-0.3h0.4l2,0.3v0.7h-4.1v-0.7H50z M55.4,72.2h1.1l4.1,12.2h-1.7l-3.6-10.8h0.4L52,84.4h-0.8L55.4,72.2z M53.3,79.6h4.9l0.3,0.8h-5.4L53.3,79.6z M56.8,83.6l2.3-0.3h0.4l2.2,0.3v0.7h-4.9V83.6z"
|
||||
id="path44" />
|
||||
|
||||
<path
|
||||
d="m 67.653352,80.654808 c 0,2.6 -1.2,3.7 -2.5,3.7 -1.3,0 -2.5,-1.1 -2.5,-3.7 0,-2.6 1.2,-3.7 2.5,-3.7 1.3,-0.1 2.5,1 2.5,3.7 z m -2.5,3.1 c 0.6,0 1.2,-0.6 1.2,-3.1 0,-2.6 -0.6,-3.1 -1.2,-3.1 -0.6,0 -1.2,0.5 -1.2,3.1 0,2.5 0.6,3.1 1.2,3.1 z"
|
||||
id="path62-6" /></g>
|
||||
</g>
|
||||
<g
|
||||
id="g58">
|
||||
<g
|
||||
id="g56">
|
||||
<path
|
||||
d="M123,83.4l1.8-0.3h0.4l2,0.3v0.7h-4.1v-0.7H123z M128.4,72h1.1l4.1,12.2h-1.7l-3.6-10.8h0.4L125,84.2h-0.8L128.4,72z M126.3,79.4h4.9l0.3,0.8h-5.4L126.3,79.4z M129.8,83.4l2.3-0.3h0.4l2.2,0.3v0.7h-4.9V83.4z"
|
||||
id="path52" />
|
||||
<path
|
||||
d="M135.9,83.3l1.7-1.6c1.1-1,1.6-1.9,1.6-2.8s-0.5-1.4-1.4-1.4c-0.3,0-0.7,0.1-1.1,0.2l0.7-0.5l-0.3,1 c-0.2,0.7-0.4,0.9-0.7,0.9s-0.5-0.2-0.6-0.4c0.1-1.2,1.2-1.8,2.5-1.8c1.6,0,2.2,0.9,2.2,1.9s-0.7,1.8-2.3,3.3l-1.7,1.6l0.3-0.7h4 v1.2H136L135.9,83.3L135.9,83.3z"
|
||||
id="path54" />
|
||||
</g>
|
||||
</g>
|
||||
<g>
|
||||
<g>
|
||||
<path d="M123,83.4l1.8-0.3h0.4l2,0.3v0.7h-4.1v-0.7H123z M128.4,72h1.1l4.1,12.2h-1.7l-3.6-10.8h0.4L125,84.2h-0.8L128.4,72z
|
||||
M126.3,79.4h4.9l0.3,0.8h-5.4L126.3,79.4z M129.8,83.4l2.3-0.3h0.4l2.2,0.3v0.7h-4.9V83.4z"/>
|
||||
<path d="M135.9,83.3l1.7-1.6c1.1-1,1.6-1.9,1.6-2.8s-0.5-1.4-1.4-1.4c-0.3,0-0.7,0.1-1.1,0.2l0.7-0.5l-0.3,1
|
||||
c-0.2,0.7-0.4,0.9-0.7,0.9s-0.5-0.2-0.6-0.4c0.1-1.2,1.2-1.8,2.5-1.8c1.6,0,2.2,0.9,2.2,1.9s-0.7,1.8-2.3,3.3l-1.7,1.6l0.3-0.7h4
|
||||
v1.2H136L135.9,83.3L135.9,83.3z"/>
|
||||
<g
|
||||
id="g66">
|
||||
<g
|
||||
id="g64">
|
||||
<path
|
||||
d="M4.6,108.2v0.6H0v-0.6l2-0.4h0.4L4.6,108.2z M1.5,99.9c0-1,0-1.5-0.1-2.3L0,97.4v-0.6l2.4-1.1l0.3,0.2l0.1,1.5h0.1v5.6 l-0.1,0.1v1.8c0,1.3,0,2.6,0.1,3.8H1.5c0-1.3,0.1-2.5,0.1-3.8L1.5,99.9L1.5,99.9z M5.2,96.7c-0.7,0-1.6,0.3-2.9,1.6L2.2,98 c1-1.6,2.2-2.3,3.4-2.3c1.9,0,3.4,1.7,3.4,4.5s-1.6,4.5-3.7,4.5c-1.1,0-2.2-0.5-3.2-2.4l0.2-0.3c0.9,1.2,1.8,1.7,2.7,1.7 c1.4,0,2.5-1.1,2.5-3.4C7.5,98,6.5,96.7,5.2,96.7z"
|
||||
id="path60" />
|
||||
<path
|
||||
d="M15.7,104.8c0,2.6-1.2,3.7-2.5,3.7c-1.3,0-2.5-1.1-2.5-3.7s1.2-3.7,2.5-3.7C14.5,101,15.7,102.1,15.7,104.8z M13.2,107.9 c0.6,0,1.2-0.6,1.2-3.1c0-2.6-0.6-3.1-1.2-3.1c-0.6,0-1.2,0.5-1.2,3.1C12,107.3,12.6,107.9,13.2,107.9z"
|
||||
id="path62" />
|
||||
</g>
|
||||
</g>
|
||||
<g>
|
||||
<g>
|
||||
<path d="M4.6,108.2v0.6H0v-0.6l2-0.4h0.4L4.6,108.2z M1.5,99.9c0-1,0-1.5-0.1-2.3L0,97.4v-0.6l2.4-1.1l0.3,0.2l0.1,1.5h0.1v5.6
|
||||
l-0.1,0.1v1.8c0,1.3,0,2.6,0.1,3.8H1.5c0-1.3,0.1-2.5,0.1-3.8L1.5,99.9L1.5,99.9z M5.2,96.7c-0.7,0-1.6,0.3-2.9,1.6L2.2,98
|
||||
c1-1.6,2.2-2.3,3.4-2.3c1.9,0,3.4,1.7,3.4,4.5s-1.6,4.5-3.7,4.5c-1.1,0-2.2-0.5-3.2-2.4l0.2-0.3c0.9,1.2,1.8,1.7,2.7,1.7
|
||||
c1.4,0,2.5-1.1,2.5-3.4C7.5,98,6.5,96.7,5.2,96.7z"/>
|
||||
<path d="M15.7,104.8c0,2.6-1.2,3.7-2.5,3.7c-1.3,0-2.5-1.1-2.5-3.7s1.2-3.7,2.5-3.7C14.5,101,15.7,102.1,15.7,104.8z M13.2,107.9
|
||||
c0.6,0,1.2-0.6,1.2-3.1c0-2.6-0.6-3.1-1.2-3.1c-0.6,0-1.2,0.5-1.2,3.1C12,107.3,12.6,107.9,13.2,107.9z"/>
|
||||
<g
|
||||
id="g74">
|
||||
<g
|
||||
id="g72">
|
||||
<path
|
||||
d="M96.9,160.8v0.6h-4.6v-0.6l2-0.4h0.4L96.9,160.8z M93.8,152.5c0-1,0-1.5-0.1-2.3l-1.4-0.2v-0.6l2.4-1.1l0.3,0.2l0.1,1.5 h0.1v5.6l-0.1,0.1v1.8c0,1.3,0,2.6,0.1,3.8h-1.5c0-1.3,0.1-2.5,0.1-3.8V152.5z M97.5,149.3c-0.7,0-1.6,0.3-2.9,1.6l-0.2-0.3 c1-1.6,2.2-2.3,3.4-2.3c1.9,0,3.4,1.7,3.4,4.5s-1.6,4.5-3.7,4.5c-1.1,0-2.2-0.5-3.2-2.4l0.2-0.3c0.9,1.2,1.8,1.7,2.7,1.7 c1.4,0,2.5-1.1,2.5-3.4C99.8,150.6,98.8,149.3,97.5,149.3z"
|
||||
id="path68" />
|
||||
<path
|
||||
d="M107.8,160.4v0.5h-4.5v-0.5l1.7-0.3h1.1L107.8,160.4z M106.1,153.6l0.2,0.1v7.1h-1.2v-6.1l-1.4,0.1v-0.6L106.1,153.6z"
|
||||
id="path70" />
|
||||
</g>
|
||||
</g>
|
||||
<g>
|
||||
<g>
|
||||
<path d="M96.9,160.8v0.6h-4.6v-0.6l2-0.4h0.4L96.9,160.8z M93.8,152.5c0-1,0-1.5-0.1-2.3l-1.4-0.2v-0.6l2.4-1.1l0.3,0.2l0.1,1.5
|
||||
h0.1v5.6l-0.1,0.1v1.8c0,1.3,0,2.6,0.1,3.8h-1.5c0-1.3,0.1-2.5,0.1-3.8V152.5z M97.5,149.3c-0.7,0-1.6,0.3-2.9,1.6l-0.2-0.3
|
||||
c1-1.6,2.2-2.3,3.4-2.3c1.9,0,3.4,1.7,3.4,4.5s-1.6,4.5-3.7,4.5c-1.1,0-2.2-0.5-3.2-2.4l0.2-0.3c0.9,1.2,1.8,1.7,2.7,1.7
|
||||
c1.4,0,2.5-1.1,2.5-3.4C99.8,150.6,98.8,149.3,97.5,149.3z"/>
|
||||
<path d="M107.8,160.4v0.5h-4.5v-0.5l1.7-0.3h1.1L107.8,160.4z M106.1,153.6l0.2,0.1v7.1h-1.2v-6.1l-1.4,0.1v-0.6L106.1,153.6z"/>
|
||||
<g
|
||||
id="g82">
|
||||
<g
|
||||
id="g80">
|
||||
<path
|
||||
d="M211,103.9v0.6h-4.6v-0.6l2-0.4h0.4L211,103.9z M207.9,95.6c0-1,0-1.5-0.1-2.3l-1.4-0.2v-0.6l2.4-1.1l0.3,0.2l0.1,1.5h0.1 v5.6l-0.1,0.1v1.8c0,1.3,0,2.6,0.1,3.8h-1.5c0-1.3,0.1-2.5,0.1-3.8L207.9,95.6L207.9,95.6z M211.6,92.4c-0.7,0-1.6,0.3-2.9,1.6 l-0.2-0.3c1-1.6,2.2-2.3,3.4-2.3c1.9,0,3.4,1.7,3.4,4.5s-1.6,4.5-3.7,4.5c-1.1,0-2.2-0.5-3.2-2.4l0.2-0.3c0.9,1.2,1.8,1.7,2.7,1.7 c1.4,0,2.5-1.1,2.5-3.4C213.9,93.7,212.9,92.4,211.6,92.4z"
|
||||
id="path76" />
|
||||
<path
|
||||
d="M217.2,103.1l1.7-1.6c1.1-1,1.6-1.9,1.6-2.8s-0.5-1.4-1.4-1.4c-0.3,0-0.7,0.1-1.1,0.2l0.7-0.5l-0.3,1 c-0.2,0.7-0.4,0.9-0.7,0.9s-0.5-0.2-0.6-0.4c0.1-1.2,1.2-1.8,2.5-1.8c1.6,0,2.2,0.9,2.2,1.9s-0.7,1.8-2.3,3.3l-1.7,1.6l0.3-0.7h4 v1.2h-4.8L217.2,103.1L217.2,103.1z"
|
||||
id="path78" />
|
||||
</g>
|
||||
</g>
|
||||
<g>
|
||||
<g>
|
||||
<path d="M211,103.9v0.6h-4.6v-0.6l2-0.4h0.4L211,103.9z M207.9,95.6c0-1,0-1.5-0.1-2.3l-1.4-0.2v-0.6l2.4-1.1l0.3,0.2l0.1,1.5h0.1
|
||||
v5.6l-0.1,0.1v1.8c0,1.3,0,2.6,0.1,3.8h-1.5c0-1.3,0.1-2.5,0.1-3.8L207.9,95.6L207.9,95.6z M211.6,92.4c-0.7,0-1.6,0.3-2.9,1.6
|
||||
l-0.2-0.3c1-1.6,2.2-2.3,3.4-2.3c1.9,0,3.4,1.7,3.4,4.5s-1.6,4.5-3.7,4.5c-1.1,0-2.2-0.5-3.2-2.4l0.2-0.3c0.9,1.2,1.8,1.7,2.7,1.7
|
||||
c1.4,0,2.5-1.1,2.5-3.4C213.9,93.7,212.9,92.4,211.6,92.4z"/>
|
||||
<path d="M217.2,103.1l1.7-1.6c1.1-1,1.6-1.9,1.6-2.8s-0.5-1.4-1.4-1.4c-0.3,0-0.7,0.1-1.1,0.2l0.7-0.5l-0.3,1
|
||||
c-0.2,0.7-0.4,0.9-0.7,0.9s-0.5-0.2-0.6-0.4c0.1-1.2,1.2-1.8,2.5-1.8c1.6,0,2.2,0.9,2.2,1.9s-0.7,1.8-2.3,3.3l-1.7,1.6l0.3-0.7h4
|
||||
v1.2h-4.8L217.2,103.1L217.2,103.1z"/>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
<path
|
||||
d="m 45.360441,45.707672 c 0,2.6 -1.2,3.7 -2.5,3.7 -1.3,0 -2.5,-1.1 -2.5,-3.7 0,-2.6 1.2,-3.7 2.5,-3.7 1.3,-0.1 2.5,1 2.5,3.7 z m -2.5,3.1 c 0.6,0 1.2,-0.6 1.2,-3.1 0,-2.6 -0.6,-3.1 -1.2,-3.1 -0.6,0 -1.2,0.5 -1.2,3.1 0,2.5 0.6,3.1 1.2,3.1 z"
|
||||
id="path62-5" /></svg>
|
||||
|
|
|
|||
|
Before Width: | Height: | Size: 5.4 KiB After Width: | Height: | Size: 7.1 KiB |
|
|
@ -1,235 +1,433 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Generator: Adobe Illustrator 24.0.3, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||
width="501.3px" height="161.7px" viewBox="0 0 501.3 161.7" style="enable-background:new 0 0 501.3 161.7;" xml:space="preserve"
|
||||
>
|
||||
<style type="text/css">
|
||||
|
||||
<svg
|
||||
version="1.1"
|
||||
id="Layer_1"
|
||||
x="0px"
|
||||
y="0px"
|
||||
width="501.3px"
|
||||
height="161.7px"
|
||||
viewBox="0 0 501.3 161.7"
|
||||
style="enable-background:new 0 0 501.3 161.7;"
|
||||
xml:space="preserve"
|
||||
sodipodi:docname="three_point_family.svg"
|
||||
inkscape:version="1.2.1 (9c6d41e410, 2022-07-14)"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"><defs
|
||||
id="defs227" /><sodipodi:namedview
|
||||
id="namedview225"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
inkscape:showpageshadow="2"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pagecheckerboard="0"
|
||||
inkscape:deskcolor="#d1d1d1"
|
||||
showgrid="false"
|
||||
inkscape:zoom="2.7029723"
|
||||
inkscape:cx="186.09143"
|
||||
inkscape:cy="-27.377269"
|
||||
inkscape:window-width="2560"
|
||||
inkscape:window-height="1371"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-y="0"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:current-layer="Layer_1" />
|
||||
<style
|
||||
type="text/css"
|
||||
id="style2">
|
||||
.st0{fill:none;stroke:#000000;stroke-miterlimit:10;}
|
||||
.st1{display:none;}
|
||||
.st2{display:inline;}
|
||||
</style>
|
||||
<circle cx="4.4" cy="87.7" r="2.5"/>
|
||||
<circle cx="96.9" cy="140.6" r="2.5"/>
|
||||
<circle cx="210" cy="83.4" r="2.5"/>
|
||||
<circle cx="90.9" cy="21.1" r="2.5"/>
|
||||
<polyline class="st0" points="90.9,21.1 4.4,87.7 96.9,140.6 90.9,21.1 "/>
|
||||
<polyline class="st0" points="96.9,140.6 210,83.3 90.9,21.1 "/>
|
||||
<g class="st1">
|
||||
<g class="st2">
|
||||
<path class="st0" d="M68.3,119.4c5.9-8.7,15.6-14.6,26.8-15.2"/>
|
||||
<g>
|
||||
<polygon points="71.6,119.1 68.8,118.7 67.1,116.4 66.2,123 "/>
|
||||
<circle
|
||||
cx="4.4"
|
||||
cy="87.7"
|
||||
r="2.5"
|
||||
id="circle4" />
|
||||
<circle
|
||||
cx="96.9"
|
||||
cy="140.6"
|
||||
r="2.5"
|
||||
id="circle6" />
|
||||
<circle
|
||||
cx="210"
|
||||
cy="83.4"
|
||||
r="2.5"
|
||||
id="circle8" />
|
||||
<circle
|
||||
cx="90.9"
|
||||
cy="21.1"
|
||||
r="2.5"
|
||||
id="circle10" />
|
||||
<polyline
|
||||
class="st0"
|
||||
points="90.9,21.1 4.4,87.7 96.9,140.6 90.9,21.1 "
|
||||
id="polyline12" />
|
||||
<polyline
|
||||
class="st0"
|
||||
points="96.9,140.6 210,83.3 90.9,21.1 "
|
||||
id="polyline14" />
|
||||
<g
|
||||
class="st1"
|
||||
id="g24">
|
||||
<g
|
||||
class="st2"
|
||||
id="g22">
|
||||
<path
|
||||
class="st0"
|
||||
d="M68.3,119.4c5.9-8.7,15.6-14.6,26.8-15.2"
|
||||
id="path16" />
|
||||
<g
|
||||
id="g20">
|
||||
<polygon
|
||||
points="71.6,119.1 68.8,118.7 67.1,116.4 66.2,123 "
|
||||
id="polygon18" />
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
<g class="st1">
|
||||
<g class="st2">
|
||||
<path class="st0" d="M99.2,108c10,2.3,18.8,9.2,23.3,19.2"/>
|
||||
<g>
|
||||
<polygon points="100.7,110.9 100.1,108.2 101.6,105.8 95.1,107.3 "/>
|
||||
<g
|
||||
class="st1"
|
||||
id="g34">
|
||||
<g
|
||||
class="st2"
|
||||
id="g32">
|
||||
<path
|
||||
class="st0"
|
||||
d="M99.2,108c10,2.3,18.8,9.2,23.3,19.2"
|
||||
id="path26" />
|
||||
<g
|
||||
id="g30">
|
||||
<polygon
|
||||
points="100.7,110.9 100.1,108.2 101.6,105.8 95.1,107.3 "
|
||||
id="polygon28" />
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
<g class="st1">
|
||||
<g class="st2">
|
||||
<path class="st0" d="M173.1,96.8c-3.6-9.9-2.6-21.3,3.5-30.6"/>
|
||||
<g>
|
||||
<polygon points="174.8,94 172.8,96 170,96 174.8,100.6 "/>
|
||||
<g
|
||||
class="st1"
|
||||
id="g44">
|
||||
<g
|
||||
class="st2"
|
||||
id="g42">
|
||||
<path
|
||||
class="st0"
|
||||
d="M173.1,96.8c-3.6-9.9-2.6-21.3,3.5-30.6"
|
||||
id="path36" />
|
||||
<g
|
||||
id="g40">
|
||||
<polygon
|
||||
points="174.8,94 172.8,96 170,96 174.8,100.6 "
|
||||
id="polygon38" />
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
<g class="st1">
|
||||
<g class="st2">
|
||||
<path class="st0" d="M30.4,73.1c5.6,8.9,7.1,20.2,3.1,30.7"/>
|
||||
<g>
|
||||
<polygon points="29.3,76.2 30.8,73.8 33.6,73.2 27.9,69.7 "/>
|
||||
<g
|
||||
class="st1"
|
||||
id="g54">
|
||||
<g
|
||||
class="st2"
|
||||
id="g52">
|
||||
<path
|
||||
class="st0"
|
||||
d="M30.4,73.1c5.6,8.9,7.1,20.2,3.1,30.7"
|
||||
id="path46" />
|
||||
<g
|
||||
id="g50">
|
||||
<polygon
|
||||
points="29.3,76.2 30.8,73.8 33.6,73.2 27.9,69.7 "
|
||||
id="polygon48" />
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
<g class="st1">
|
||||
<g class="st2">
|
||||
<path class="st0" d="M117,39.5c-4.5,9.5-13.3,16.8-24.2,19.1"/>
|
||||
<g>
|
||||
<polygon points="113.8,40.3 116.6,40.2 118.6,42.2 118.6,35.6 "/>
|
||||
<g
|
||||
class="st1"
|
||||
id="g64">
|
||||
<g
|
||||
class="st2"
|
||||
id="g62">
|
||||
<path
|
||||
class="st0"
|
||||
d="M117,39.5c-4.5,9.5-13.3,16.8-24.2,19.1"
|
||||
id="path56" />
|
||||
<g
|
||||
id="g60">
|
||||
<polygon
|
||||
points="113.8,40.3 116.6,40.2 118.6,42.2 118.6,35.6 "
|
||||
id="polygon58" />
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
<g class="st1">
|
||||
<g class="st2">
|
||||
<path class="st0" d="M88.2,55c-10,0.9-20.2-2.8-27.3-10.7"/>
|
||||
<g>
|
||||
<polygon points="85.9,52.6 87.3,55 86.6,57.8 92.3,54.3 "/>
|
||||
<g
|
||||
class="st1"
|
||||
id="g74">
|
||||
<g
|
||||
class="st2"
|
||||
id="g72">
|
||||
<path
|
||||
class="st0"
|
||||
d="M88.2,55c-10,0.9-20.2-2.8-27.3-10.7"
|
||||
id="path66" />
|
||||
<g
|
||||
id="g70">
|
||||
<polygon
|
||||
points="85.9,52.6 87.3,55 86.6,57.8 92.3,54.3 "
|
||||
id="polygon68" />
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
<g>
|
||||
<g class="st1">
|
||||
<path class="st2" d="M84.9,121.7v1.5c-0.4-2-1.1-3.9-1.8-5.7c-0.5-1.5-0.8-2-1.4-2c-0.2,0-0.4,0-0.6,0.1l-0.2-0.5
|
||||
c0.4-0.4,0.8-0.7,1.4-0.7c0.7,0,1.3,0.3,2,2.4c0.4,1.1,0.9,2.8,1.4,5.4l0.1,0.1l0.1,3.9l-1.4,0.3l-0.2-0.2L84.9,121.7z
|
||||
M85.4,122.3c1.2-2.1,1.7-3.5,2.5-5.5l-0.2,1.4c-0.2-1.7-0.3-2.3-0.3-2.7c0-0.8,0.4-1.2,0.9-1.2c0.3,0,0.5,0.1,0.6,0.2
|
||||
c0.1,0.2,0.1,0.4,0.1,0.8c0,1.9-1.8,5.3-3.3,7.8L85.4,122.3z"/>
|
||||
<g
|
||||
id="g80">
|
||||
<g
|
||||
class="st1"
|
||||
id="g78">
|
||||
<path
|
||||
class="st2"
|
||||
d="M84.9,121.7v1.5c-0.4-2-1.1-3.9-1.8-5.7c-0.5-1.5-0.8-2-1.4-2c-0.2,0-0.4,0-0.6,0.1l-0.2-0.5 c0.4-0.4,0.8-0.7,1.4-0.7c0.7,0,1.3,0.3,2,2.4c0.4,1.1,0.9,2.8,1.4,5.4l0.1,0.1l0.1,3.9l-1.4,0.3l-0.2-0.2L84.9,121.7z M85.4,122.3c1.2-2.1,1.7-3.5,2.5-5.5l-0.2,1.4c-0.2-1.7-0.3-2.3-0.3-2.7c0-0.8,0.4-1.2,0.9-1.2c0.3,0,0.5,0.1,0.6,0.2 c0.1,0.2,0.1,0.4,0.1,0.8c0,1.9-1.8,5.3-3.3,7.8L85.4,122.3z"
|
||||
id="path76" />
|
||||
</g>
|
||||
</g>
|
||||
<g>
|
||||
<g class="st1">
|
||||
<path class="st2" d="M101,128v-8.8c0-2.6,1.6-4.3,3.8-4.3c1.8,0,3.2,1.1,3.2,3c0,1.4-1,3.3-3.6,3.5l-0.1-0.2c3-0.1,4.7,1,4.7,3.4
|
||||
c0,2.5-1.9,3.8-3.7,3.8c-1.3,0-2.6-0.6-3.3-2.2l0.2-0.2c0.8,0.7,1.7,1.2,2.8,1.2c1.7,0,2.6-1.1,2.6-2.7c0-1.5-0.8-2.9-3.5-2.8
|
||||
l-0.2-1c1.7-0.3,2.7-1.3,2.7-2.9c0-1.4-0.7-2.3-1.9-2.3c-1.3,0-2.2,1.2-2.2,3.2v7.7l-0.1,0.3l0.3,4.5l-1.4,0.3l-0.2-0.2L101,128z"
|
||||
/>
|
||||
<g
|
||||
id="g86">
|
||||
<g
|
||||
class="st1"
|
||||
id="g84">
|
||||
<path
|
||||
class="st2"
|
||||
d="M101,128v-8.8c0-2.6,1.6-4.3,3.8-4.3c1.8,0,3.2,1.1,3.2,3c0,1.4-1,3.3-3.6,3.5l-0.1-0.2c3-0.1,4.7,1,4.7,3.4 c0,2.5-1.9,3.8-3.7,3.8c-1.3,0-2.6-0.6-3.3-2.2l0.2-0.2c0.8,0.7,1.7,1.2,2.8,1.2c1.7,0,2.6-1.1,2.6-2.7c0-1.5-0.8-2.9-3.5-2.8 l-0.2-1c1.7-0.3,2.7-1.3,2.7-2.9c0-1.4-0.7-2.3-1.9-2.3c-1.3,0-2.2,1.2-2.2,3.2v7.7l-0.1,0.3l0.3,4.5l-1.4,0.3l-0.2-0.2L101,128z"
|
||||
id="path82" />
|
||||
</g>
|
||||
</g>
|
||||
<g>
|
||||
<g class="st1">
|
||||
<path class="st2" d="M21.8,90v-8.8c0-2.6,1.6-4.3,3.8-4.3c1.8,0,3.2,1.1,3.2,3c0,1.4-1,3.3-3.6,3.5l-0.1-0.2c3-0.1,4.7,1,4.7,3.4
|
||||
c0,2.5-1.9,3.8-3.7,3.8c-1.3,0-2.6-0.6-3.3-2.2L23,88c0.8,0.7,1.7,1.2,2.8,1.2c1.7,0,2.6-1.1,2.6-2.7c0-1.5-0.8-2.9-3.5-2.8
|
||||
l-0.2-1c1.7-0.3,2.7-1.3,2.7-2.9c0-1.4-0.7-2.3-1.9-2.3c-1.3,0-2.2,1.2-2.2,3.2v7.7l-0.1,0.3l0.3,4.5l-1.4,0.3l-0.2-0.2L21.8,90z"
|
||||
/>
|
||||
<g
|
||||
id="g92">
|
||||
<g
|
||||
class="st1"
|
||||
id="g90">
|
||||
<path
|
||||
class="st2"
|
||||
d="M21.8,90v-8.8c0-2.6,1.6-4.3,3.8-4.3c1.8,0,3.2,1.1,3.2,3c0,1.4-1,3.3-3.6,3.5l-0.1-0.2c3-0.1,4.7,1,4.7,3.4 c0,2.5-1.9,3.8-3.7,3.8c-1.3,0-2.6-0.6-3.3-2.2L23,88c0.8,0.7,1.7,1.2,2.8,1.2c1.7,0,2.6-1.1,2.6-2.7c0-1.5-0.8-2.9-3.5-2.8 l-0.2-1c1.7-0.3,2.7-1.3,2.7-2.9c0-1.4-0.7-2.3-1.9-2.3c-1.3,0-2.2,1.2-2.2,3.2v7.7l-0.1,0.3l0.3,4.5l-1.4,0.3l-0.2-0.2L21.8,90z"
|
||||
id="path88" />
|
||||
</g>
|
||||
</g>
|
||||
<g>
|
||||
<g class="st1">
|
||||
<path class="st2" d="M182.6,84.9v1.5c-0.4-2-1.1-3.9-1.8-5.7c-0.5-1.5-0.8-2-1.4-2c-0.2,0-0.4,0-0.6,0.1l-0.2-0.5
|
||||
c0.4-0.4,0.8-0.7,1.4-0.7c0.7,0,1.3,0.3,2,2.4c0.4,1.1,0.9,2.8,1.4,5.4l0.1,0.1l0.1,3.9l-1.4,0.3l-0.2-0.2L182.6,84.9z
|
||||
M183.1,85.5c1.2-2.1,1.7-3.5,2.5-5.5l-0.2,1.4c-0.2-1.7-0.3-2.3-0.3-2.7c0-0.8,0.4-1.2,0.9-1.2c0.3,0,0.5,0.1,0.6,0.2
|
||||
c0.1,0.2,0.1,0.4,0.1,0.8c0,1.9-1.8,5.3-3.3,7.8L183.1,85.5z"/>
|
||||
<g
|
||||
id="g98">
|
||||
<g
|
||||
class="st1"
|
||||
id="g96">
|
||||
<path
|
||||
class="st2"
|
||||
d="M182.6,84.9v1.5c-0.4-2-1.1-3.9-1.8-5.7c-0.5-1.5-0.8-2-1.4-2c-0.2,0-0.4,0-0.6,0.1l-0.2-0.5 c0.4-0.4,0.8-0.7,1.4-0.7c0.7,0,1.3,0.3,2,2.4c0.4,1.1,0.9,2.8,1.4,5.4l0.1,0.1l0.1,3.9l-1.4,0.3l-0.2-0.2L182.6,84.9z M183.1,85.5c1.2-2.1,1.7-3.5,2.5-5.5l-0.2,1.4c-0.2-1.7-0.3-2.3-0.3-2.7c0-0.8,0.4-1.2,0.9-1.2c0.3,0,0.5,0.1,0.6,0.2 c0.1,0.2,0.1,0.4,0.1,0.8c0,1.9-1.8,5.3-3.3,7.8L183.1,85.5z"
|
||||
id="path94" />
|
||||
</g>
|
||||
</g>
|
||||
<circle cx="284.1" cy="88.3" r="2.5"/>
|
||||
<circle cx="376.6" cy="141.2" r="2.5"/>
|
||||
<circle cx="489.6" cy="84" r="2.5"/>
|
||||
<circle cx="370.5" cy="21.6" r="2.5"/>
|
||||
<line class="st0" x1="370.5" y1="21.6" x2="284.1" y2="88.3"/>
|
||||
<line class="st0" x1="489.6" y1="83.9" x2="370.5" y2="21.6"/>
|
||||
<polygon class="st0" points="376.6,141.2 284.1,88.3 489.6,83.9 "/>
|
||||
<g>
|
||||
<g>
|
||||
<path d="M367.8,54.4v-0.7h2.5v1h-0.2L367.8,54.4z M370.3,64.8v1h-2.5V65l2.3-0.3h0.2V64.8z M369.5,59.3c0-1.9,0-3.7-0.1-5.6h1.7
|
||||
c-0.1,1.8-0.1,3.7-0.1,5.6v0.6c0,2.1,0,4,0.1,5.9h-1.7c0.1-1.8,0.1-3.7,0.1-5.6V59.3z M370.3,59.1h1.8c2.2,0,3.2-0.7,3.2-2.4
|
||||
s-1-2.2-2.8-2.2h-2.2v-0.8h2.7c2.5,0,3.9,1.2,3.9,3c0,1.4-1,2.6-3.4,2.9v-0.2c2.8,0.2,4,1.5,4,3c0,1.6-1.4,3.3-4.8,3.3h-2.4v-0.8
|
||||
h2c2.3,0,3.5-0.9,3.5-2.5c0-1.7-1.1-2.5-3.6-2.5h-1.9L370.3,59.1L370.3,59.1z"/>
|
||||
<circle
|
||||
cx="284.1"
|
||||
cy="88.3"
|
||||
r="2.5"
|
||||
id="circle100" />
|
||||
<circle
|
||||
cx="376.6"
|
||||
cy="141.2"
|
||||
r="2.5"
|
||||
id="circle102" />
|
||||
<circle
|
||||
cx="489.6"
|
||||
cy="84"
|
||||
r="2.5"
|
||||
id="circle104" />
|
||||
<circle
|
||||
cx="370.5"
|
||||
cy="21.6"
|
||||
r="2.5"
|
||||
id="circle106" />
|
||||
<line
|
||||
class="st0"
|
||||
x1="370.5"
|
||||
y1="21.6"
|
||||
x2="284.1"
|
||||
y2="88.3"
|
||||
id="line108" />
|
||||
<line
|
||||
class="st0"
|
||||
x1="489.6"
|
||||
y1="83.9"
|
||||
x2="370.5"
|
||||
y2="21.6"
|
||||
id="line110" />
|
||||
<polygon
|
||||
class="st0"
|
||||
points="376.6,141.2 284.1,88.3 489.6,83.9 "
|
||||
id="polygon112" />
|
||||
<g
|
||||
id="g118">
|
||||
<g
|
||||
id="g116">
|
||||
<path
|
||||
d="M367.8,54.4v-0.7h2.5v1h-0.2L367.8,54.4z M370.3,64.8v1h-2.5V65l2.3-0.3h0.2V64.8z M369.5,59.3c0-1.9,0-3.7-0.1-5.6h1.7 c-0.1,1.8-0.1,3.7-0.1,5.6v0.6c0,2.1,0,4,0.1,5.9h-1.7c0.1-1.8,0.1-3.7,0.1-5.6V59.3z M370.3,59.1h1.8c2.2,0,3.2-0.7,3.2-2.4 s-1-2.2-2.8-2.2h-2.2v-0.8h2.7c2.5,0,3.9,1.2,3.9,3c0,1.4-1,2.6-3.4,2.9v-0.2c2.8,0.2,4,1.5,4,3c0,1.6-1.4,3.3-4.8,3.3h-2.4v-0.8 h2c2.3,0,3.5-0.9,3.5-2.5c0-1.7-1.1-2.5-3.6-2.5h-1.9L370.3,59.1L370.3,59.1z"
|
||||
id="path114" />
|
||||
</g>
|
||||
</g>
|
||||
<g>
|
||||
<g class="st1">
|
||||
<path class="st2" d="M380.7,113.1v1l-1.1,0.3l0.5-2.7h1.1l-0.1,2.6c-1.1,0.6-2.4,0.9-3.6,0.9c-3.6,0-6.1-2.6-6.1-6.3
|
||||
c0-3.6,2.6-6.3,6.1-6.3c1,0,2.3,0.2,3.5,0.9l0.1,2.6H380l-0.5-2.7l1.1,0.3v1.1c-1-1-2-1.3-2.9-1.3c-2.4,0-4.4,1.9-4.4,5.4
|
||||
s1.8,5.4,4.3,5.4C378.5,114.2,379.7,113.9,380.7,113.1z"/>
|
||||
<g
|
||||
id="g124">
|
||||
<g
|
||||
class="st1"
|
||||
id="g122">
|
||||
<path
|
||||
class="st2"
|
||||
d="M380.7,113.1v1l-1.1,0.3l0.5-2.7h1.1l-0.1,2.6c-1.1,0.6-2.4,0.9-3.6,0.9c-3.6,0-6.1-2.6-6.1-6.3 c0-3.6,2.6-6.3,6.1-6.3c1,0,2.3,0.2,3.5,0.9l0.1,2.6H380l-0.5-2.7l1.1,0.3v1.1c-1-1-2-1.3-2.9-1.3c-2.4,0-4.4,1.9-4.4,5.4 s1.8,5.4,4.3,5.4C378.5,114.2,379.7,113.9,380.7,113.1z"
|
||||
id="path120" />
|
||||
</g>
|
||||
</g>
|
||||
<g>
|
||||
<g>
|
||||
<path d="M88.4,8c0.9,0,1.5-0.4,2.4-1.5L91,7c-0.8,1.4-1.7,2-2.9,2c-2.2,0-3.7-1.8-3.7-4.4C84.4,1.9,86,0,88.2,0c1,0,2,0.4,2.9,1.8
|
||||
l-0.2,0.5c-1-1-1.8-1.3-2.4-1.3C87.1,1,86,2.1,86,4.6C85.9,6.9,86.9,8,88.4,8z M91.5,12.1l2,0.4v0.6h-4.6v-0.6l2.2-0.4H91.5z
|
||||
M92,13.1h-1.5c0-1.3,0.1-2.6,0.1-3.8V7.5l-0.1-0.3V1.3L91.7,0L92,0.2l-0.1,2.4v6.7C92,10.5,92,11.8,92,13.1z"/>
|
||||
<g
|
||||
id="g130">
|
||||
<g
|
||||
id="g128">
|
||||
<path
|
||||
d="M88.4,8c0.9,0,1.5-0.4,2.4-1.5L91,7c-0.8,1.4-1.7,2-2.9,2c-2.2,0-3.7-1.8-3.7-4.4C84.4,1.9,86,0,88.2,0c1,0,2,0.4,2.9,1.8 l-0.2,0.5c-1-1-1.8-1.3-2.4-1.3C87.1,1,86,2.1,86,4.6C85.9,6.9,86.9,8,88.4,8z M91.5,12.1l2,0.4v0.6h-4.6v-0.6l2.2-0.4H91.5z M92,13.1h-1.5c0-1.3,0.1-2.6,0.1-3.8V7.5l-0.1-0.3V1.3L91.7,0L92,0.2l-0.1,2.4v6.7C92,10.5,92,11.8,92,13.1z"
|
||||
id="path126" />
|
||||
</g>
|
||||
</g>
|
||||
<g>
|
||||
<g>
|
||||
<path d="M367.7,8c0.9,0,1.5-0.4,2.4-1.5l0.2,0.5c-0.8,1.4-1.7,2-2.9,2c-2.2,0-3.7-1.8-3.7-4.4c0-2.7,1.6-4.6,3.8-4.6
|
||||
c1,0,2,0.4,2.9,1.8l-0.2,0.5c-1-1-1.8-1.3-2.4-1.3c-1.4,0-2.5,1.1-2.5,3.6C365.2,6.9,366.3,8,367.7,8z M370.8,12.1l2,0.4v0.6h-4.6
|
||||
v-0.6l2.2-0.4H370.8z M371.4,13.1h-1.5c0-1.3,0.1-2.6,0.1-3.8V7.5l-0.1-0.3V1.3l1.2-1.3l0.3,0.2l-0.1,2.4v6.7
|
||||
C371.3,10.5,371.3,11.8,371.4,13.1z"/>
|
||||
<g
|
||||
id="g136">
|
||||
<g
|
||||
id="g134">
|
||||
<path
|
||||
d="M367.7,8c0.9,0,1.5-0.4,2.4-1.5l0.2,0.5c-0.8,1.4-1.7,2-2.9,2c-2.2,0-3.7-1.8-3.7-4.4c0-2.7,1.6-4.6,3.8-4.6 c1,0,2,0.4,2.9,1.8l-0.2,0.5c-1-1-1.8-1.3-2.4-1.3c-1.4,0-2.5,1.1-2.5,3.6C365.2,6.9,366.3,8,367.7,8z M370.8,12.1l2,0.4v0.6h-4.6 v-0.6l2.2-0.4H370.8z M371.4,13.1h-1.5c0-1.3,0.1-2.6,0.1-3.8V7.5l-0.1-0.3V1.3l1.2-1.3l0.3,0.2l-0.1,2.4v6.7 C371.3,10.5,371.3,11.8,371.4,13.1z"
|
||||
id="path132" />
|
||||
</g>
|
||||
</g>
|
||||
<g>
|
||||
<g>
|
||||
<path d="M34.2,50c0.9,0,1.5-0.4,2.4-1.5l0.2,0.5c-0.7,1.2-1.5,2-2.9,2c-2.2,0-3.7-1.8-3.7-4.4c0-2.7,1.6-4.6,3.8-4.6
|
||||
c1,0,1.9,0.4,2.8,1.8l-0.2,0.5c-1-1-1.8-1.3-2.4-1.3c-1.4,0-2.5,1.1-2.5,3.5C31.7,49,32.7,50,34.2,50z M39.2,50.2v0.6L36.4,51
|
||||
l-0.2-1.8v-5.3l0.1-0.2v-4.5L34.8,39v-0.6l2.8-0.8l0.3,0.1l-0.1,2.6v10.6L37.5,50L39.2,50.2z"/>
|
||||
<path d="M45.1,50.3v0.5h-4.5v-0.5l1.7-0.3h1.1L45.1,50.3z M43.4,43.5l0.2,0.1v7.1h-1.2v-6.1l-1.5,0.2v-0.6L43.4,43.5z"/>
|
||||
<g
|
||||
id="g144">
|
||||
<g
|
||||
id="g142">
|
||||
<path
|
||||
d="M34.2,50c0.9,0,1.5-0.4,2.4-1.5l0.2,0.5c-0.7,1.2-1.5,2-2.9,2c-2.2,0-3.7-1.8-3.7-4.4c0-2.7,1.6-4.6,3.8-4.6 c1,0,1.9,0.4,2.8,1.8l-0.2,0.5c-1-1-1.8-1.3-2.4-1.3c-1.4,0-2.5,1.1-2.5,3.5C31.7,49,32.7,50,34.2,50z M39.2,50.2v0.6L36.4,51 l-0.2-1.8v-5.3l0.1-0.2v-4.5L34.8,39v-0.6l2.8-0.8l0.3,0.1l-0.1,2.6v10.6L37.5,50L39.2,50.2z"
|
||||
id="path138" />
|
||||
|
||||
</g>
|
||||
</g>
|
||||
<g>
|
||||
<g>
|
||||
<path d="M104.3,81.7c0.9,0,1.5-0.4,2.4-1.5l0.2,0.5c-0.7,1.2-1.5,2-2.9,2c-2.2,0-3.7-1.8-3.7-4.4c0-2.7,1.6-4.6,3.8-4.6
|
||||
c1,0,1.9,0.4,2.8,1.8l-0.2,0.5c-1-1-1.8-1.3-2.4-1.3c-1.4,0-2.5,1.1-2.5,3.5C101.8,80.6,102.8,81.7,104.3,81.7z M109.3,81.8v0.6
|
||||
l-2.8,0.2l-0.2-1.8v-5.3l0.1-0.2v-4.6l-1.5-0.2v-0.6l2.8-0.8l0.3,0.1l-0.1,2.6v10.6l-0.3-0.9L109.3,81.8z"/>
|
||||
<g
|
||||
id="g150">
|
||||
<g
|
||||
id="g148">
|
||||
<path
|
||||
d="M104.3,81.7c0.9,0,1.5-0.4,2.4-1.5l0.2,0.5c-0.7,1.2-1.5,2-2.9,2c-2.2,0-3.7-1.8-3.7-4.4c0-2.7,1.6-4.6,3.8-4.6 c1,0,1.9,0.4,2.8,1.8l-0.2,0.5c-1-1-1.8-1.3-2.4-1.3c-1.4,0-2.5,1.1-2.5,3.5C101.8,80.6,102.8,81.7,104.3,81.7z M109.3,81.8v0.6 l-2.8,0.2l-0.2-1.8v-5.3l0.1-0.2v-4.6l-1.5-0.2v-0.6l2.8-0.8l0.3,0.1l-0.1,2.6v10.6l-0.3-0.9L109.3,81.8z"
|
||||
id="path146" />
|
||||
</g>
|
||||
</g>
|
||||
<g>
|
||||
<g>
|
||||
<path d="M160.1,49c0.9,0,1.5-0.4,2.4-1.5l0.2,0.5c-0.7,1.2-1.5,2-2.9,2c-2.2,0-3.7-1.8-3.7-4.4c0-2.7,1.6-4.6,3.8-4.6
|
||||
c1,0,1.9,0.4,2.8,1.8l-0.2,0.5c-1-1-1.8-1.3-2.4-1.3c-1.4,0-2.5,1.1-2.5,3.5C157.5,48,158.6,49,160.1,49z M165.1,49.2v0.6
|
||||
l-2.8,0.2l-0.2-1.8v-5.3l0.1-0.2v-4.5l-1.5-0.2v-0.6l2.8-0.8l0.3,0.1l-0.1,2.6v10.6l-0.3-0.9L165.1,49.2z"/>
|
||||
<path d="M166.3,48.9l1.7-1.6c1.1-1,1.6-1.9,1.6-2.8c0-0.9-0.5-1.4-1.4-1.4c-0.3,0-0.7,0.1-1.1,0.2l0.7-0.5l-0.3,1
|
||||
c-0.2,0.7-0.4,0.9-0.7,0.9s-0.5-0.2-0.6-0.4c0.1-1.2,1.2-1.8,2.5-1.8c1.6,0,2.2,0.9,2.2,1.9s-0.7,1.8-2.3,3.3l-1.7,1.6l0.3-0.7h4
|
||||
v1.2h-4.8L166.3,48.9L166.3,48.9z"/>
|
||||
<g
|
||||
id="g158">
|
||||
<g
|
||||
id="g156">
|
||||
<path
|
||||
d="M160.1,49c0.9,0,1.5-0.4,2.4-1.5l0.2,0.5c-0.7,1.2-1.5,2-2.9,2c-2.2,0-3.7-1.8-3.7-4.4c0-2.7,1.6-4.6,3.8-4.6 c1,0,1.9,0.4,2.8,1.8l-0.2,0.5c-1-1-1.8-1.3-2.4-1.3c-1.4,0-2.5,1.1-2.5,3.5C157.5,48,158.6,49,160.1,49z M165.1,49.2v0.6 l-2.8,0.2l-0.2-1.8v-5.3l0.1-0.2v-4.5l-1.5-0.2v-0.6l2.8-0.8l0.3,0.1l-0.1,2.6v10.6l-0.3-0.9L165.1,49.2z"
|
||||
id="path152" />
|
||||
<path
|
||||
d="M166.3,48.9l1.7-1.6c1.1-1,1.6-1.9,1.6-2.8c0-0.9-0.5-1.4-1.4-1.4c-0.3,0-0.7,0.1-1.1,0.2l0.7-0.5l-0.3,1 c-0.2,0.7-0.4,0.9-0.7,0.9s-0.5-0.2-0.6-0.4c0.1-1.2,1.2-1.8,2.5-1.8c1.6,0,2.2,0.9,2.2,1.9s-0.7,1.8-2.3,3.3l-1.7,1.6l0.3-0.7h4 v1.2h-4.8L166.3,48.9L166.3,48.9z"
|
||||
id="path154" />
|
||||
</g>
|
||||
</g>
|
||||
<g>
|
||||
<g>
|
||||
<path d="M55.3,87.6l1.8-0.3h0.4l2,0.3v0.7h-4.1L55.3,87.6L55.3,87.6z M60.7,76.2h1.1l4.1,12.1h-1.7l-3.6-10.8H61l-3.7,10.8h-0.8
|
||||
L60.7,76.2z M58.6,83.6h4.9l0.3,0.8h-5.4L58.6,83.6z M62.2,87.6l2.3-0.3h0.4l2.2,0.3v0.7h-4.9C62.2,88.3,62.2,87.6,62.2,87.6z"/>
|
||||
<path d="M72.8,87.8v0.5h-4.5v-0.5l1.7-0.3h1.1L72.8,87.8z M71.1,81.1l0.2,0.1v7.1h-1.2v-6.1l-1.4,0.1v-0.6L71.1,81.1z"/>
|
||||
<g
|
||||
id="g166"
|
||||
transform="translate(-1.5665625,1.0361857)">
|
||||
<g
|
||||
id="g164">
|
||||
<path
|
||||
d="m 55.3,87.6 1.8,-0.3 h 0.4 l 2,0.3 v 0.7 h -4.1 l -0.1,-0.7 z m 5.4,-11.4 h 1.1 l 4.1,12.1 H 64.2 L 60.6,77.5 H 61 l -3.7,10.8 h -0.8 z m -2.1,7.4 h 4.9 l 0.3,0.8 h -5.4 z m 3.6,4 2.3,-0.3 h 0.4 l 2.2,0.3 v 0.7 h -4.9 c 0,0 0,-0.7 0,-0.7 z"
|
||||
id="path160" />
|
||||
|
||||
</g>
|
||||
</g>
|
||||
<g>
|
||||
<g>
|
||||
<path d="M126.5,85.8l1.8-0.3h0.4l2,0.3v0.7h-4.1L126.5,85.8L126.5,85.8z M131.8,74.4h1.1l4.1,12.2h-1.7l-3.6-10.8h0.4l-3.7,10.8
|
||||
h-0.8L131.8,74.4z M129.7,81.8h4.9l0.3,0.8h-5.4L129.7,81.8z M133.3,85.8l2.3-0.3h0.4l2.2,0.3v0.7h-4.9V85.8z"/>
|
||||
<path d="M139.3,85.7l1.7-1.6c1.1-1,1.6-1.9,1.6-2.8s-0.5-1.4-1.4-1.4c-0.3,0-0.7,0.1-1.1,0.2l0.7-0.5l-0.3,1
|
||||
c-0.2,0.7-0.4,0.9-0.7,0.9s-0.5-0.2-0.6-0.4c0.1-1.2,1.2-1.8,2.5-1.8c1.6,0,2.2,0.9,2.2,1.9s-0.7,1.8-2.3,3.3l-1.7,1.6l0.3-0.7h4
|
||||
v1.2h-4.8L139.3,85.7L139.3,85.7z"/>
|
||||
<g
|
||||
id="g174"
|
||||
transform="translate(4.0074518,2.1561911)">
|
||||
<g
|
||||
id="g172">
|
||||
<path
|
||||
d="m 126.5,85.8 1.8,-0.3 h 0.4 l 2,0.3 v 0.7 h -4.1 l -0.1,-0.7 z m 5.3,-11.4 h 1.1 l 4.1,12.2 h -1.7 l -3.6,-10.8 h 0.4 l -3.7,10.8 h -0.8 z m -2.1,7.4 h 4.9 l 0.3,0.8 h -5.4 z m 3.6,4 2.3,-0.3 h 0.4 l 2.2,0.3 v 0.7 h -4.9 z"
|
||||
id="path168" />
|
||||
<path
|
||||
d="m 139.3,85.7 1.7,-1.6 c 1.1,-1 1.6,-1.9 1.6,-2.8 0,-0.9 -0.5,-1.4 -1.4,-1.4 -0.3,0 -0.7,0.1 -1.1,0.2 l 0.7,-0.5 -0.3,1 c -0.2,0.7 -0.4,0.9 -0.7,0.9 -0.3,0 -0.5,-0.2 -0.6,-0.4 0.1,-1.2 1.2,-1.8 2.5,-1.8 1.6,0 2.2,0.9 2.2,1.9 0,1 -0.7,1.8 -2.3,3.3 l -1.7,1.6 0.3,-0.7 h 4 v 1.2 h -4.8 l -0.1,-0.9 z"
|
||||
id="path170" />
|
||||
</g>
|
||||
</g>
|
||||
<g>
|
||||
<g>
|
||||
<path d="M4.6,111.1v0.6H0v-0.6l2-0.4h0.4L4.6,111.1z M1.5,102.8c0-1,0-1.5-0.1-2.3L0,100.3v-0.6l2.4-1.1l0.3,0.2l0.1,1.5h0.1v5.6
|
||||
L2.8,106v1.8c0,1.3,0,2.6,0.1,3.8H1.5c0-1.3,0.1-2.5,0.1-3.8L1.5,102.8L1.5,102.8z M5.2,99.6c-0.7,0-1.6,0.3-2.9,1.6l-0.2-0.3
|
||||
c1-1.6,2.2-2.3,3.4-2.3c1.9,0,3.4,1.7,3.4,4.5s-1.6,4.5-3.7,4.5c-1.1,0-2.2-0.5-3.2-2.4l0.2-0.3c0.9,1.2,1.8,1.7,2.7,1.7
|
||||
c1.4,0,2.5-1.1,2.5-3.4C7.5,100.9,6.5,99.6,5.2,99.6z"/>
|
||||
<path d="M15.7,107.7c0,2.6-1.2,3.7-2.5,3.7c-1.3,0-2.5-1.1-2.5-3.7s1.2-3.7,2.5-3.7C14.5,103.9,15.7,105,15.7,107.7z M13.2,110.8
|
||||
c0.6,0,1.2-0.6,1.2-3.1c0-2.6-0.6-3.1-1.2-3.1c-0.6,0-1.2,0.5-1.2,3.1C12,110.2,12.6,110.8,13.2,110.8z"/>
|
||||
<g
|
||||
id="g182">
|
||||
<g
|
||||
id="g180">
|
||||
<path
|
||||
d="M4.6,111.1v0.6H0v-0.6l2-0.4h0.4L4.6,111.1z M1.5,102.8c0-1,0-1.5-0.1-2.3L0,100.3v-0.6l2.4-1.1l0.3,0.2l0.1,1.5h0.1v5.6 L2.8,106v1.8c0,1.3,0,2.6,0.1,3.8H1.5c0-1.3,0.1-2.5,0.1-3.8L1.5,102.8L1.5,102.8z M5.2,99.6c-0.7,0-1.6,0.3-2.9,1.6l-0.2-0.3 c1-1.6,2.2-2.3,3.4-2.3c1.9,0,3.4,1.7,3.4,4.5s-1.6,4.5-3.7,4.5c-1.1,0-2.2-0.5-3.2-2.4l0.2-0.3c0.9,1.2,1.8,1.7,2.7,1.7 c1.4,0,2.5-1.1,2.5-3.4C7.5,100.9,6.5,99.6,5.2,99.6z"
|
||||
id="path176" />
|
||||
<path
|
||||
d="M15.7,107.7c0,2.6-1.2,3.7-2.5,3.7c-1.3,0-2.5-1.1-2.5-3.7s1.2-3.7,2.5-3.7C14.5,103.9,15.7,105,15.7,107.7z M13.2,110.8 c0.6,0,1.2-0.6,1.2-3.1c0-2.6-0.6-3.1-1.2-3.1c-0.6,0-1.2,0.5-1.2,3.1C12,110.2,12.6,110.8,13.2,110.8z"
|
||||
id="path178" />
|
||||
</g>
|
||||
</g>
|
||||
<g>
|
||||
<g>
|
||||
<path d="M284.8,111.1v0.6h-4.6v-0.6l2-0.4h0.4L284.8,111.1z M281.7,102.8c0-1,0-1.5-0.1-2.3l-1.4-0.2v-0.6l2.4-1.1l0.3,0.2
|
||||
l0.1,1.5h0.1v5.6L283,106v1.8c0,1.3,0,2.6,0.1,3.8h-1.5c0-1.3,0.1-2.5,0.1-3.8V102.8z M285.4,99.6c-0.7,0-1.6,0.3-2.9,1.6
|
||||
l-0.2-0.3c1-1.6,2.2-2.3,3.4-2.3c1.9,0,3.4,1.7,3.4,4.5s-1.6,4.5-3.7,4.5c-1.1,0-2.2-0.5-3.2-2.4l0.2-0.3c0.9,1.2,1.8,1.7,2.7,1.7
|
||||
c1.4,0,2.5-1.1,2.5-3.4C287.7,100.9,286.7,99.6,285.4,99.6z"/>
|
||||
<path d="M295.9,107.7c0,2.6-1.2,3.7-2.5,3.7s-2.5-1.1-2.5-3.7s1.2-3.7,2.5-3.7C294.7,103.9,295.9,105,295.9,107.7z M293.4,110.8
|
||||
c0.6,0,1.2-0.6,1.2-3.1c0-2.6-0.6-3.1-1.2-3.1s-1.2,0.5-1.2,3.1C292.2,110.2,292.8,110.8,293.4,110.8z"/>
|
||||
<g
|
||||
id="g190">
|
||||
<g
|
||||
id="g188">
|
||||
<path
|
||||
d="M284.8,111.1v0.6h-4.6v-0.6l2-0.4h0.4L284.8,111.1z M281.7,102.8c0-1,0-1.5-0.1-2.3l-1.4-0.2v-0.6l2.4-1.1l0.3,0.2 l0.1,1.5h0.1v5.6L283,106v1.8c0,1.3,0,2.6,0.1,3.8h-1.5c0-1.3,0.1-2.5,0.1-3.8V102.8z M285.4,99.6c-0.7,0-1.6,0.3-2.9,1.6 l-0.2-0.3c1-1.6,2.2-2.3,3.4-2.3c1.9,0,3.4,1.7,3.4,4.5s-1.6,4.5-3.7,4.5c-1.1,0-2.2-0.5-3.2-2.4l0.2-0.3c0.9,1.2,1.8,1.7,2.7,1.7 c1.4,0,2.5-1.1,2.5-3.4C287.7,100.9,286.7,99.6,285.4,99.6z"
|
||||
id="path184" />
|
||||
<path
|
||||
d="M295.9,107.7c0,2.6-1.2,3.7-2.5,3.7s-2.5-1.1-2.5-3.7s1.2-3.7,2.5-3.7C294.7,103.9,295.9,105,295.9,107.7z M293.4,110.8 c0.6,0,1.2-0.6,1.2-3.1c0-2.6-0.6-3.1-1.2-3.1s-1.2,0.5-1.2,3.1C292.2,110.2,292.8,110.8,293.4,110.8z"
|
||||
id="path186" />
|
||||
</g>
|
||||
</g>
|
||||
<g>
|
||||
<g>
|
||||
<path d="M97.6,161.1v0.6H93v-0.6l2-0.4h0.4L97.6,161.1z M94.5,152.8c0-1,0-1.5-0.1-2.3l-1.4-0.2v-0.6l2.4-1.1l0.3,0.2l0.1,1.5h0.1
|
||||
v5.6l-0.1,0.1v1.8c0,1.3,0,2.6,0.1,3.8h-1.5c0-1.3,0.1-2.5,0.1-3.8V152.8z M98.2,149.6c-0.7,0-1.6,0.3-2.9,1.6l-0.2-0.3
|
||||
c1-1.6,2.2-2.3,3.4-2.3c1.9,0,3.4,1.7,3.4,4.5s-1.6,4.5-3.7,4.5c-1.1,0-2.2-0.5-3.2-2.4l0.2-0.3c0.9,1.2,1.8,1.7,2.7,1.7
|
||||
c1.4,0,2.5-1.1,2.5-3.4C100.5,150.9,99.5,149.6,98.2,149.6z"/>
|
||||
<path d="M108.5,160.7v0.5H104v-0.5l1.7-0.3h1.1L108.5,160.7z M106.8,154l0.2,0.1v7.1h-1.2v-6.1l-1.4,0.1v-0.6L106.8,154z"/>
|
||||
<g
|
||||
id="g198">
|
||||
<g
|
||||
id="g196">
|
||||
<path
|
||||
d="M97.6,161.1v0.6H93v-0.6l2-0.4h0.4L97.6,161.1z M94.5,152.8c0-1,0-1.5-0.1-2.3l-1.4-0.2v-0.6l2.4-1.1l0.3,0.2l0.1,1.5h0.1 v5.6l-0.1,0.1v1.8c0,1.3,0,2.6,0.1,3.8h-1.5c0-1.3,0.1-2.5,0.1-3.8V152.8z M98.2,149.6c-0.7,0-1.6,0.3-2.9,1.6l-0.2-0.3 c1-1.6,2.2-2.3,3.4-2.3c1.9,0,3.4,1.7,3.4,4.5s-1.6,4.5-3.7,4.5c-1.1,0-2.2-0.5-3.2-2.4l0.2-0.3c0.9,1.2,1.8,1.7,2.7,1.7 c1.4,0,2.5-1.1,2.5-3.4C100.5,150.9,99.5,149.6,98.2,149.6z"
|
||||
id="path192" />
|
||||
<path
|
||||
d="M108.5,160.7v0.5H104v-0.5l1.7-0.3h1.1L108.5,160.7z M106.8,154l0.2,0.1v7.1h-1.2v-6.1l-1.4,0.1v-0.6L106.8,154z"
|
||||
id="path194" />
|
||||
</g>
|
||||
</g>
|
||||
<g>
|
||||
<g>
|
||||
<path d="M377.6,161.1v0.6H373v-0.6l2-0.4h0.4L377.6,161.1z M374.5,152.8c0-1,0-1.5-0.1-2.3l-1.4-0.2v-0.6l2.4-1.1l0.3,0.2l0.1,1.5
|
||||
h0.1v5.6l-0.1,0.1v1.8c0,1.3,0,2.6,0.1,3.8h-1.5c0-1.3,0.1-2.5,0.1-3.8V152.8z M378.2,149.6c-0.7,0-1.6,0.3-2.9,1.6l-0.2-0.3
|
||||
c1-1.6,2.2-2.3,3.4-2.3c1.9,0,3.4,1.7,3.4,4.5s-1.6,4.5-3.7,4.5c-1.1,0-2.2-0.5-3.2-2.4l0.2-0.3c0.9,1.2,1.8,1.7,2.7,1.7
|
||||
c1.4,0,2.5-1.1,2.5-3.4C380.5,150.9,379.5,149.6,378.2,149.6z"/>
|
||||
<path d="M388.5,160.7v0.5H384v-0.5l1.7-0.3h1.1L388.5,160.7z M386.8,154l0.2,0.1v7.1h-1.2v-6.1l-1.4,0.1v-0.6L386.8,154z"/>
|
||||
<g
|
||||
id="g206">
|
||||
<g
|
||||
id="g204">
|
||||
<path
|
||||
d="M377.6,161.1v0.6H373v-0.6l2-0.4h0.4L377.6,161.1z M374.5,152.8c0-1,0-1.5-0.1-2.3l-1.4-0.2v-0.6l2.4-1.1l0.3,0.2l0.1,1.5 h0.1v5.6l-0.1,0.1v1.8c0,1.3,0,2.6,0.1,3.8h-1.5c0-1.3,0.1-2.5,0.1-3.8V152.8z M378.2,149.6c-0.7,0-1.6,0.3-2.9,1.6l-0.2-0.3 c1-1.6,2.2-2.3,3.4-2.3c1.9,0,3.4,1.7,3.4,4.5s-1.6,4.5-3.7,4.5c-1.1,0-2.2-0.5-3.2-2.4l0.2-0.3c0.9,1.2,1.8,1.7,2.7,1.7 c1.4,0,2.5-1.1,2.5-3.4C380.5,150.9,379.5,149.6,378.2,149.6z"
|
||||
id="path200" />
|
||||
<path
|
||||
d="M388.5,160.7v0.5H384v-0.5l1.7-0.3h1.1L388.5,160.7z M386.8,154l0.2,0.1v7.1h-1.2v-6.1l-1.4,0.1v-0.6L386.8,154z"
|
||||
id="path202" />
|
||||
</g>
|
||||
</g>
|
||||
<g>
|
||||
<g>
|
||||
<path d="M210.7,105.5v0.6h-4.6v-0.6l2-0.4h0.4L210.7,105.5z M207.6,97.1c0-1,0-1.5-0.1-2.3l-1.4-0.2V94l2.4-1.1l0.3,0.2l0.1,1.5
|
||||
h0.1v5.6l-0.1,0.1v1.8c0,1.3,0,2.6,0.1,3.8h-1.5c0-1.3,0.1-2.5,0.1-3.8L207.6,97.1L207.6,97.1z M211.3,94c-0.7,0-1.6,0.3-2.9,1.6
|
||||
l-0.2-0.3c1-1.6,2.2-2.3,3.4-2.3c1.9,0,3.4,1.7,3.4,4.5s-1.6,4.5-3.7,4.5c-1.1,0-2.2-0.5-3.2-2.4l0.2-0.3c0.9,1.2,1.8,1.7,2.7,1.7
|
||||
c1.4,0,2.5-1.1,2.5-3.4C213.6,95.3,212.6,94,211.3,94z"/>
|
||||
<path d="M216.9,104.7l1.7-1.6c1.1-1,1.6-1.9,1.6-2.8s-0.5-1.4-1.4-1.4c-0.3,0-0.7,0.1-1.1,0.2l0.7-0.5l-0.3,1
|
||||
c-0.2,0.7-0.4,0.9-0.7,0.9s-0.5-0.2-0.6-0.4c0.1-1.2,1.2-1.8,2.5-1.8c1.6,0,2.2,0.9,2.2,1.9s-0.7,1.8-2.3,3.3l-1.7,1.6l0.3-0.7h4
|
||||
v1.2H217L216.9,104.7L216.9,104.7z"/>
|
||||
<g
|
||||
id="g214">
|
||||
<g
|
||||
id="g212">
|
||||
<path
|
||||
d="M210.7,105.5v0.6h-4.6v-0.6l2-0.4h0.4L210.7,105.5z M207.6,97.1c0-1,0-1.5-0.1-2.3l-1.4-0.2V94l2.4-1.1l0.3,0.2l0.1,1.5 h0.1v5.6l-0.1,0.1v1.8c0,1.3,0,2.6,0.1,3.8h-1.5c0-1.3,0.1-2.5,0.1-3.8L207.6,97.1L207.6,97.1z M211.3,94c-0.7,0-1.6,0.3-2.9,1.6 l-0.2-0.3c1-1.6,2.2-2.3,3.4-2.3c1.9,0,3.4,1.7,3.4,4.5s-1.6,4.5-3.7,4.5c-1.1,0-2.2-0.5-3.2-2.4l0.2-0.3c0.9,1.2,1.8,1.7,2.7,1.7 c1.4,0,2.5-1.1,2.5-3.4C213.6,95.3,212.6,94,211.3,94z"
|
||||
id="path208" />
|
||||
<path
|
||||
d="M216.9,104.7l1.7-1.6c1.1-1,1.6-1.9,1.6-2.8s-0.5-1.4-1.4-1.4c-0.3,0-0.7,0.1-1.1,0.2l0.7-0.5l-0.3,1 c-0.2,0.7-0.4,0.9-0.7,0.9s-0.5-0.2-0.6-0.4c0.1-1.2,1.2-1.8,2.5-1.8c1.6,0,2.2,0.9,2.2,1.9s-0.7,1.8-2.3,3.3l-1.7,1.6l0.3-0.7h4 v1.2H217L216.9,104.7L216.9,104.7z"
|
||||
id="path210" />
|
||||
</g>
|
||||
</g>
|
||||
<g>
|
||||
<g>
|
||||
<path d="M490.2,105.5v0.6h-4.6v-0.6l2-0.4h0.4L490.2,105.5z M487.1,97.1c0-1,0-1.5-0.1-2.3l-1.4-0.2V94l2.4-1.1l0.3,0.2l0.1,1.5
|
||||
h0.1v5.6l-0.1,0.1v1.8c0,1.3,0,2.6,0.1,3.8H487c0-1.3,0.1-2.5,0.1-3.8V97.1z M490.8,94c-0.7,0-1.6,0.3-2.9,1.6l-0.2-0.3
|
||||
c1-1.6,2.2-2.3,3.4-2.3c1.9,0,3.4,1.7,3.4,4.5s-1.6,4.5-3.7,4.5c-1.1,0-2.2-0.5-3.2-2.4l0.2-0.3c0.9,1.2,1.8,1.7,2.7,1.7
|
||||
c1.4,0,2.5-1.1,2.5-3.4C493.1,95.3,492.1,94,490.8,94z"/>
|
||||
<path d="M496.4,104.7l1.7-1.6c1.1-1,1.6-1.9,1.6-2.8s-0.5-1.4-1.4-1.4c-0.3,0-0.7,0.1-1.1,0.2l0.7-0.5l-0.3,1
|
||||
c-0.2,0.7-0.4,0.9-0.7,0.9c-0.3,0-0.5-0.2-0.6-0.4c0.1-1.2,1.2-1.8,2.5-1.8c1.6,0,2.2,0.9,2.2,1.9s-0.7,1.8-2.3,3.3l-1.7,1.6
|
||||
l0.3-0.7h4v1.2h-4.9V104.7z"/>
|
||||
<g
|
||||
id="g222">
|
||||
<g
|
||||
id="g220">
|
||||
<path
|
||||
d="M490.2,105.5v0.6h-4.6v-0.6l2-0.4h0.4L490.2,105.5z M487.1,97.1c0-1,0-1.5-0.1-2.3l-1.4-0.2V94l2.4-1.1l0.3,0.2l0.1,1.5 h0.1v5.6l-0.1,0.1v1.8c0,1.3,0,2.6,0.1,3.8H487c0-1.3,0.1-2.5,0.1-3.8V97.1z M490.8,94c-0.7,0-1.6,0.3-2.9,1.6l-0.2-0.3 c1-1.6,2.2-2.3,3.4-2.3c1.9,0,3.4,1.7,3.4,4.5s-1.6,4.5-3.7,4.5c-1.1,0-2.2-0.5-3.2-2.4l0.2-0.3c0.9,1.2,1.8,1.7,2.7,1.7 c1.4,0,2.5-1.1,2.5-3.4C493.1,95.3,492.1,94,490.8,94z"
|
||||
id="path216" />
|
||||
<path
|
||||
d="M496.4,104.7l1.7-1.6c1.1-1,1.6-1.9,1.6-2.8s-0.5-1.4-1.4-1.4c-0.3,0-0.7,0.1-1.1,0.2l0.7-0.5l-0.3,1 c-0.2,0.7-0.4,0.9-0.7,0.9c-0.3,0-0.5-0.2-0.6-0.4c0.1-1.2,1.2-1.8,2.5-1.8c1.6,0,2.2,0.9,2.2,1.9s-0.7,1.8-2.3,3.3l-1.7,1.6 l0.3-0.7h4v1.2h-4.9V104.7z"
|
||||
id="path218" />
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
<path
|
||||
d="m 45.711075,47.390632 c 0,2.6 -1.2,3.7 -2.5,3.7 -1.3,0 -2.5,-1.1 -2.5,-3.7 0,-2.6 1.2,-3.7 2.5,-3.7 1.3,-0.1 2.5,1 2.5,3.7 z m -2.5,3.1 c 0.6,0 1.2,-0.6 1.2,-3.1 0,-2.6 -0.6,-3.1 -1.2,-3.1 -0.6,0 -1.2,0.5 -1.2,3.1 0,2.5 0.6,3.1 1.2,3.1 z"
|
||||
id="path178-3" /><path
|
||||
d="m 71.585549,85.750185 c 0,2.6 -1.2,3.7 -2.5,3.7 -1.3,0 -2.5,-1.1 -2.5,-3.7 0,-2.6 1.2,-3.7 2.5,-3.7 1.3,-0.1 2.5,1 2.5,3.7 z m -2.5,3.1 c 0.6,0 1.2,-0.6 1.2,-3.1 0,-2.6 -0.6,-3.1 -1.2,-3.1 -0.6,0 -1.2,0.5 -1.2,3.1 0,2.5 0.6,3.1 1.2,3.1 z"
|
||||
id="path178-6" /></svg>
|
||||
|
|
|
|||
|
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 15 KiB |
|
|
@ -1,244 +1,439 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Generator: Adobe Illustrator 24.0.3, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||
width="501.2px" height="161px" viewBox="0 0 501.2 161" style="enable-background:new 0 0 501.2 161;" xml:space="preserve">
|
||||
<style type="text/css">
|
||||
|
||||
<svg
|
||||
version="1.1"
|
||||
id="Layer_1"
|
||||
x="0px"
|
||||
y="0px"
|
||||
width="501.2px"
|
||||
height="161px"
|
||||
viewBox="0 0 501.2 161"
|
||||
style="enable-background:new 0 0 501.2 161;"
|
||||
xml:space="preserve"
|
||||
sodipodi:docname="wachspress.svg"
|
||||
inkscape:version="1.2.1 (9c6d41e410, 2022-07-14)"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"><defs
|
||||
id="defs227" /><sodipodi:namedview
|
||||
id="namedview225"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
inkscape:showpageshadow="2"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pagecheckerboard="0"
|
||||
inkscape:deskcolor="#d1d1d1"
|
||||
showgrid="false"
|
||||
inkscape:zoom="5.407023"
|
||||
inkscape:cx="135.0096"
|
||||
inkscape:cy="111.15174"
|
||||
inkscape:window-width="2560"
|
||||
inkscape:window-height="1371"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-y="0"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:current-layer="Layer_1" />
|
||||
<style
|
||||
type="text/css"
|
||||
id="style2">
|
||||
.st0{fill:none;stroke:#000000;stroke-miterlimit:10;}
|
||||
.st1{display:none;}
|
||||
.st2{display:inline;}
|
||||
</style>
|
||||
<circle cx="3.7" cy="86.7" r="2.5"/>
|
||||
<circle cx="96.2" cy="139.6" r="2.5"/>
|
||||
<circle cx="209.3" cy="82.4" r="2.5"/>
|
||||
<circle cx="90.2" cy="20.1" r="2.5"/>
|
||||
<polyline class="st0" points="90.2,20.1 3.7,86.7 96.2,139.6 90.2,20.1 "/>
|
||||
<polyline class="st0" points="96.2,139.6 209.3,82.3 90.2,20.1 "/>
|
||||
<g class="st1">
|
||||
<g class="st2">
|
||||
<path class="st0" d="M67.6,118.4c5.9-8.7,15.6-14.6,26.8-15.2"/>
|
||||
<g>
|
||||
<polygon points="70.9,118.1 68.1,117.7 66.4,115.4 65.5,122 "/>
|
||||
<circle
|
||||
cx="3.7"
|
||||
cy="86.7"
|
||||
r="2.5"
|
||||
id="circle4" />
|
||||
<circle
|
||||
cx="96.2"
|
||||
cy="139.6"
|
||||
r="2.5"
|
||||
id="circle6" />
|
||||
<circle
|
||||
cx="209.3"
|
||||
cy="82.4"
|
||||
r="2.5"
|
||||
id="circle8" />
|
||||
<circle
|
||||
cx="90.2"
|
||||
cy="20.1"
|
||||
r="2.5"
|
||||
id="circle10" />
|
||||
<polyline
|
||||
class="st0"
|
||||
points="90.2,20.1 3.7,86.7 96.2,139.6 90.2,20.1 "
|
||||
id="polyline12" />
|
||||
<polyline
|
||||
class="st0"
|
||||
points="96.2,139.6 209.3,82.3 90.2,20.1 "
|
||||
id="polyline14" />
|
||||
<g
|
||||
class="st1"
|
||||
id="g24">
|
||||
<g
|
||||
class="st2"
|
||||
id="g22">
|
||||
<path
|
||||
class="st0"
|
||||
d="M67.6,118.4c5.9-8.7,15.6-14.6,26.8-15.2"
|
||||
id="path16" />
|
||||
<g
|
||||
id="g20">
|
||||
<polygon
|
||||
points="70.9,118.1 68.1,117.7 66.4,115.4 65.5,122 "
|
||||
id="polygon18" />
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
<g class="st1">
|
||||
<g class="st2">
|
||||
<path class="st0" d="M98.5,107c10,2.3,18.8,9.2,23.3,19.2"/>
|
||||
<g>
|
||||
<polygon points="100,109.9 99.4,107.2 100.9,104.8 94.4,106.3 "/>
|
||||
<g
|
||||
class="st1"
|
||||
id="g34">
|
||||
<g
|
||||
class="st2"
|
||||
id="g32">
|
||||
<path
|
||||
class="st0"
|
||||
d="M98.5,107c10,2.3,18.8,9.2,23.3,19.2"
|
||||
id="path26" />
|
||||
<g
|
||||
id="g30">
|
||||
<polygon
|
||||
points="100,109.9 99.4,107.2 100.9,104.8 94.4,106.3 "
|
||||
id="polygon28" />
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
<g class="st1">
|
||||
<g class="st2">
|
||||
<path class="st0" d="M172.4,95.8c-3.6-9.9-2.6-21.3,3.5-30.6"/>
|
||||
<g>
|
||||
<polygon points="174.1,93 172.1,95 169.3,95 174.1,99.6 "/>
|
||||
<g
|
||||
class="st1"
|
||||
id="g44">
|
||||
<g
|
||||
class="st2"
|
||||
id="g42">
|
||||
<path
|
||||
class="st0"
|
||||
d="M172.4,95.8c-3.6-9.9-2.6-21.3,3.5-30.6"
|
||||
id="path36" />
|
||||
<g
|
||||
id="g40">
|
||||
<polygon
|
||||
points="174.1,93 172.1,95 169.3,95 174.1,99.6 "
|
||||
id="polygon38" />
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
<g class="st1">
|
||||
<g class="st2">
|
||||
<path class="st0" d="M29.7,72.1c5.6,8.9,7.1,20.2,3.1,30.7"/>
|
||||
<g>
|
||||
<polygon points="28.6,75.2 30.1,72.8 32.9,72.2 27.2,68.7 "/>
|
||||
<g
|
||||
class="st1"
|
||||
id="g54">
|
||||
<g
|
||||
class="st2"
|
||||
id="g52">
|
||||
<path
|
||||
class="st0"
|
||||
d="M29.7,72.1c5.6,8.9,7.1,20.2,3.1,30.7"
|
||||
id="path46" />
|
||||
<g
|
||||
id="g50">
|
||||
<polygon
|
||||
points="28.6,75.2 30.1,72.8 32.9,72.2 27.2,68.7 "
|
||||
id="polygon48" />
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
<g class="st1">
|
||||
<g class="st2">
|
||||
<path class="st0" d="M116.3,38.5C111.8,48,103,55.3,92.1,57.6"/>
|
||||
<g>
|
||||
<polygon points="113.1,39.3 115.9,39.2 117.9,41.2 117.9,34.6 "/>
|
||||
<g
|
||||
class="st1"
|
||||
id="g64">
|
||||
<g
|
||||
class="st2"
|
||||
id="g62">
|
||||
<path
|
||||
class="st0"
|
||||
d="M116.3,38.5C111.8,48,103,55.3,92.1,57.6"
|
||||
id="path56" />
|
||||
<g
|
||||
id="g60">
|
||||
<polygon
|
||||
points="113.1,39.3 115.9,39.2 117.9,41.2 117.9,34.6 "
|
||||
id="polygon58" />
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
<g class="st1">
|
||||
<g class="st2">
|
||||
<path class="st0" d="M87.5,54c-10,0.9-20.2-2.8-27.3-10.7"/>
|
||||
<g>
|
||||
<polygon points="85.2,51.6 86.6,54 85.9,56.8 91.6,53.3 "/>
|
||||
<g
|
||||
class="st1"
|
||||
id="g74">
|
||||
<g
|
||||
class="st2"
|
||||
id="g72">
|
||||
<path
|
||||
class="st0"
|
||||
d="M87.5,54c-10,0.9-20.2-2.8-27.3-10.7"
|
||||
id="path66" />
|
||||
<g
|
||||
id="g70">
|
||||
<polygon
|
||||
points="85.2,51.6 86.6,54 85.9,56.8 91.6,53.3 "
|
||||
id="polygon68" />
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
<g>
|
||||
<g class="st1">
|
||||
<path class="st2" d="M84.2,120.7v1.5c-0.4-2-1.1-3.9-1.8-5.7c-0.5-1.5-0.8-2-1.4-2c-0.2,0-0.4,0-0.6,0.1l-0.2-0.5
|
||||
c0.4-0.4,0.8-0.7,1.4-0.7c0.7,0,1.3,0.3,2,2.4c0.4,1.1,0.9,2.8,1.4,5.4l0.1,0.1l0.1,3.9l-1.4,0.3l-0.2-0.2L84.2,120.7z
|
||||
M84.7,121.3c1.2-2.1,1.7-3.5,2.5-5.5l-0.2,1.4c-0.2-1.7-0.3-2.3-0.3-2.7c0-0.8,0.4-1.2,0.9-1.2c0.3,0,0.5,0.1,0.6,0.2
|
||||
c0.1,0.2,0.1,0.4,0.1,0.8c0,1.9-1.8,5.3-3.3,7.8L84.7,121.3z"/>
|
||||
<g
|
||||
id="g80">
|
||||
<g
|
||||
class="st1"
|
||||
id="g78">
|
||||
<path
|
||||
class="st2"
|
||||
d="M84.2,120.7v1.5c-0.4-2-1.1-3.9-1.8-5.7c-0.5-1.5-0.8-2-1.4-2c-0.2,0-0.4,0-0.6,0.1l-0.2-0.5 c0.4-0.4,0.8-0.7,1.4-0.7c0.7,0,1.3,0.3,2,2.4c0.4,1.1,0.9,2.8,1.4,5.4l0.1,0.1l0.1,3.9l-1.4,0.3l-0.2-0.2L84.2,120.7z M84.7,121.3c1.2-2.1,1.7-3.5,2.5-5.5l-0.2,1.4c-0.2-1.7-0.3-2.3-0.3-2.7c0-0.8,0.4-1.2,0.9-1.2c0.3,0,0.5,0.1,0.6,0.2 c0.1,0.2,0.1,0.4,0.1,0.8c0,1.9-1.8,5.3-3.3,7.8L84.7,121.3z"
|
||||
id="path76" />
|
||||
</g>
|
||||
</g>
|
||||
<g>
|
||||
<g class="st1">
|
||||
<path class="st2" d="M100.3,127v-8.8c0-2.6,1.6-4.3,3.8-4.3c1.8,0,3.2,1.1,3.2,3c0,1.4-1,3.3-3.6,3.5l-0.1-0.2
|
||||
c3-0.1,4.7,1,4.7,3.4c0,2.5-1.9,3.8-3.7,3.8c-1.3,0-2.6-0.6-3.3-2.2l0.2-0.2c0.8,0.7,1.7,1.2,2.8,1.2c1.7,0,2.6-1.1,2.6-2.7
|
||||
c0-1.5-0.8-2.9-3.5-2.8l-0.2-1c1.7-0.3,2.7-1.3,2.7-2.9c0-1.4-0.7-2.3-1.9-2.3c-1.3,0-2.2,1.2-2.2,3.2v7.7l-0.1,0.3l0.3,4.5
|
||||
l-1.4,0.3l-0.2-0.2L100.3,127z"/>
|
||||
<g
|
||||
id="g86">
|
||||
<g
|
||||
class="st1"
|
||||
id="g84">
|
||||
<path
|
||||
class="st2"
|
||||
d="M100.3,127v-8.8c0-2.6,1.6-4.3,3.8-4.3c1.8,0,3.2,1.1,3.2,3c0,1.4-1,3.3-3.6,3.5l-0.1-0.2 c3-0.1,4.7,1,4.7,3.4c0,2.5-1.9,3.8-3.7,3.8c-1.3,0-2.6-0.6-3.3-2.2l0.2-0.2c0.8,0.7,1.7,1.2,2.8,1.2c1.7,0,2.6-1.1,2.6-2.7 c0-1.5-0.8-2.9-3.5-2.8l-0.2-1c1.7-0.3,2.7-1.3,2.7-2.9c0-1.4-0.7-2.3-1.9-2.3c-1.3,0-2.2,1.2-2.2,3.2v7.7l-0.1,0.3l0.3,4.5 l-1.4,0.3l-0.2-0.2L100.3,127z"
|
||||
id="path82" />
|
||||
</g>
|
||||
</g>
|
||||
<g>
|
||||
<g class="st1">
|
||||
<path class="st2" d="M83.1,78.4v-0.8c0-1,0-1.5-0.1-2.3l-1.4-0.2v-0.6l2.4-1.1l0.3,0.2l0.2,2.3v2.6c0,1.1,0,3,0.1,3.8h-1.5
|
||||
C83.1,81.4,83.1,79.6,83.1,78.4z M81.8,81.6l2-0.4h0.4l2,0.4v0.6h-4.3L81.8,81.6L81.8,81.6z M83.9,76h1l-0.5,0.1
|
||||
c0.6-1.7,1.7-2.7,2.7-2.7c0.5,0,1.1,0.3,1.3,0.6c0,0.8-0.3,1.3-1,1.3c-0.4,0-0.8-0.2-1.1-0.4l-0.5-0.4l0.9-0.2
|
||||
c-1.1,0.6-1.8,1.5-2.2,2.9h-0.7L83.9,76L83.9,76z"/>
|
||||
<g
|
||||
id="g92">
|
||||
<g
|
||||
class="st1"
|
||||
id="g90">
|
||||
<path
|
||||
class="st2"
|
||||
d="M83.1,78.4v-0.8c0-1,0-1.5-0.1-2.3l-1.4-0.2v-0.6l2.4-1.1l0.3,0.2l0.2,2.3v2.6c0,1.1,0,3,0.1,3.8h-1.5 C83.1,81.4,83.1,79.6,83.1,78.4z M81.8,81.6l2-0.4h0.4l2,0.4v0.6h-4.3L81.8,81.6L81.8,81.6z M83.9,76h1l-0.5,0.1 c0.6-1.7,1.7-2.7,2.7-2.7c0.5,0,1.1,0.3,1.3,0.6c0,0.8-0.3,1.3-1,1.3c-0.4,0-0.8-0.2-1.1-0.4l-0.5-0.4l0.9-0.2 c-1.1,0.6-1.8,1.5-2.2,2.9h-0.7L83.9,76L83.9,76z"
|
||||
id="path88" />
|
||||
</g>
|
||||
</g>
|
||||
<g>
|
||||
<g class="st1">
|
||||
<path class="st2" d="M21.1,89v-8.8c0-2.6,1.6-4.3,3.8-4.3c1.8,0,3.2,1.1,3.2,3c0,1.4-1,3.3-3.6,3.5l-0.1-0.2c3-0.1,4.7,1,4.7,3.4
|
||||
c0,2.5-1.9,3.8-3.7,3.8c-1.3,0-2.6-0.6-3.3-2.2l0.2-0.2c0.8,0.7,1.7,1.2,2.8,1.2c1.7,0,2.6-1.1,2.6-2.7c0-1.5-0.8-2.9-3.5-2.8
|
||||
l-0.2-1c1.7-0.3,2.7-1.3,2.7-2.9c0-1.4-0.7-2.3-1.9-2.3c-1.3,0-2.2,1.2-2.2,3.2v7.7l-0.1,0.3l0.3,4.5l-1.4,0.3l-0.2-0.2L21.1,89z"
|
||||
/>
|
||||
<g
|
||||
id="g98">
|
||||
<g
|
||||
class="st1"
|
||||
id="g96">
|
||||
<path
|
||||
class="st2"
|
||||
d="M21.1,89v-8.8c0-2.6,1.6-4.3,3.8-4.3c1.8,0,3.2,1.1,3.2,3c0,1.4-1,3.3-3.6,3.5l-0.1-0.2c3-0.1,4.7,1,4.7,3.4 c0,2.5-1.9,3.8-3.7,3.8c-1.3,0-2.6-0.6-3.3-2.2l0.2-0.2c0.8,0.7,1.7,1.2,2.8,1.2c1.7,0,2.6-1.1,2.6-2.7c0-1.5-0.8-2.9-3.5-2.8 l-0.2-1c1.7-0.3,2.7-1.3,2.7-2.9c0-1.4-0.7-2.3-1.9-2.3c-1.3,0-2.2,1.2-2.2,3.2v7.7l-0.1,0.3l0.3,4.5l-1.4,0.3l-0.2-0.2L21.1,89z"
|
||||
id="path94" />
|
||||
</g>
|
||||
</g>
|
||||
<g>
|
||||
<g class="st1">
|
||||
<path class="st2" d="M181.9,83.9v1.5c-0.4-2-1.1-3.9-1.8-5.7c-0.5-1.5-0.8-2-1.4-2c-0.2,0-0.4,0-0.6,0.1l-0.2-0.5
|
||||
c0.4-0.4,0.8-0.7,1.4-0.7c0.7,0,1.3,0.3,2,2.4c0.4,1.1,0.9,2.8,1.4,5.4l0.1,0.1l0.1,3.9l-1.4,0.3l-0.2-0.2L181.9,83.9z
|
||||
M182.4,84.5c1.2-2.1,1.7-3.5,2.5-5.5l-0.2,1.4c-0.2-1.7-0.3-2.3-0.3-2.7c0-0.8,0.4-1.2,0.9-1.2c0.3,0,0.5,0.1,0.6,0.2
|
||||
c0.1,0.2,0.1,0.4,0.1,0.8c0,1.9-1.8,5.3-3.3,7.8L182.4,84.5z"/>
|
||||
<g
|
||||
id="g104">
|
||||
<g
|
||||
class="st1"
|
||||
id="g102">
|
||||
<path
|
||||
class="st2"
|
||||
d="M181.9,83.9v1.5c-0.4-2-1.1-3.9-1.8-5.7c-0.5-1.5-0.8-2-1.4-2c-0.2,0-0.4,0-0.6,0.1l-0.2-0.5 c0.4-0.4,0.8-0.7,1.4-0.7c0.7,0,1.3,0.3,2,2.4c0.4,1.1,0.9,2.8,1.4,5.4l0.1,0.1l0.1,3.9l-1.4,0.3l-0.2-0.2L181.9,83.9z M182.4,84.5c1.2-2.1,1.7-3.5,2.5-5.5l-0.2,1.4c-0.2-1.7-0.3-2.3-0.3-2.7c0-0.8,0.4-1.2,0.9-1.2c0.3,0,0.5,0.1,0.6,0.2 c0.1,0.2,0.1,0.4,0.1,0.8c0,1.9-1.8,5.3-3.3,7.8L182.4,84.5z"
|
||||
id="path100" />
|
||||
</g>
|
||||
</g>
|
||||
<g>
|
||||
<g class="st1">
|
||||
<path class="st2" d="M32.9,41.8V41c0-1,0-1.5-0.1-2.3l-1.4-0.2v-0.6l2.4-1.1l0.3,0.2l0.2,2.3v2.6c0,1.1,0,3,0.1,3.8h-1.5
|
||||
C32.8,44.7,32.9,42.9,32.9,41.8z M31.5,44.9l2-0.4h0.4l2,0.4v0.6h-4.3v-0.6H31.5z M33.6,39.3h1l-0.5,0.1c0.6-1.7,1.7-2.7,2.7-2.7
|
||||
c0.5,0,1.1,0.3,1.3,0.6c0,0.8-0.3,1.3-1,1.3c-0.4,0-0.8-0.2-1.1-0.4l-0.5-0.4l0.9-0.2c-1.1,0.6-1.8,1.5-2.2,2.9h-0.6
|
||||
C33.6,40.5,33.6,39.3,33.6,39.3z"/>
|
||||
<path class="st2" d="M39.7,45.5c0-0.5,0-1.8,0-2.5v-0.6c0-0.7,0-1,0-1.5l-1-0.1v-0.4l1.6-0.7l0.2,0.1l0.1,1.4V43c0,0.7,0,2,0,2.5
|
||||
C40.6,45.5,39.7,45.5,39.7,45.5z M41.5,45.1v0.4h-2.8v-0.4l1.3-0.2h0.2L41.5,45.1z M44.3,41.9V43c0,0.8,0,2,0,2.5h-1
|
||||
c0-0.5,0-1.8,0-2.5v-1c0-1.1-0.3-1.5-1-1.5c-0.6,0-1.1,0.2-1.7,0.8h-0.3v-0.5h0.6L40.4,41c0.6-0.8,1.5-1.3,2.3-1.3
|
||||
C43.8,39.7,44.3,40.3,44.3,41.9z M43.9,44.9l1.2,0.2v0.4h-2.8v-0.4l1.3-0.2H43.9z M47.9,41.8V43c0,0.8,0,2,0,2.5h-1
|
||||
c0-0.5,0-1.8,0-2.5v-1c0-1.1-0.3-1.5-1-1.5c-0.5,0-1,0.2-1.7,0.8h-0.3v-0.4h0.6L43.9,41c0.6-0.9,1.5-1.3,2.4-1.3
|
||||
C47.3,39.7,47.9,40.3,47.9,41.8z M47.5,44.9l1.2,0.2v0.4h-2.8v-0.4l1.3-0.2H47.5z"/>
|
||||
<g
|
||||
id="g112">
|
||||
<g
|
||||
class="st1"
|
||||
id="g110">
|
||||
<path
|
||||
class="st2"
|
||||
d="M32.9,41.8V41c0-1,0-1.5-0.1-2.3l-1.4-0.2v-0.6l2.4-1.1l0.3,0.2l0.2,2.3v2.6c0,1.1,0,3,0.1,3.8h-1.5 C32.8,44.7,32.9,42.9,32.9,41.8z M31.5,44.9l2-0.4h0.4l2,0.4v0.6h-4.3v-0.6H31.5z M33.6,39.3h1l-0.5,0.1c0.6-1.7,1.7-2.7,2.7-2.7 c0.5,0,1.1,0.3,1.3,0.6c0,0.8-0.3,1.3-1,1.3c-0.4,0-0.8-0.2-1.1-0.4l-0.5-0.4l0.9-0.2c-1.1,0.6-1.8,1.5-2.2,2.9h-0.6 C33.6,40.5,33.6,39.3,33.6,39.3z"
|
||||
id="path106" />
|
||||
<path
|
||||
class="st2"
|
||||
d="M39.7,45.5c0-0.5,0-1.8,0-2.5v-0.6c0-0.7,0-1,0-1.5l-1-0.1v-0.4l1.6-0.7l0.2,0.1l0.1,1.4V43c0,0.7,0,2,0,2.5 C40.6,45.5,39.7,45.5,39.7,45.5z M41.5,45.1v0.4h-2.8v-0.4l1.3-0.2h0.2L41.5,45.1z M44.3,41.9V43c0,0.8,0,2,0,2.5h-1 c0-0.5,0-1.8,0-2.5v-1c0-1.1-0.3-1.5-1-1.5c-0.6,0-1.1,0.2-1.7,0.8h-0.3v-0.5h0.6L40.4,41c0.6-0.8,1.5-1.3,2.3-1.3 C43.8,39.7,44.3,40.3,44.3,41.9z M43.9,44.9l1.2,0.2v0.4h-2.8v-0.4l1.3-0.2H43.9z M47.9,41.8V43c0,0.8,0,2,0,2.5h-1 c0-0.5,0-1.8,0-2.5v-1c0-1.1-0.3-1.5-1-1.5c-0.5,0-1,0.2-1.7,0.8h-0.3v-0.4h0.6L43.9,41c0.6-0.9,1.5-1.3,2.4-1.3 C47.3,39.7,47.9,40.3,47.9,41.8z M47.5,44.9l1.2,0.2v0.4h-2.8v-0.4l1.3-0.2H47.5z"
|
||||
id="path108" />
|
||||
</g>
|
||||
</g>
|
||||
<g>
|
||||
<g class="st1">
|
||||
<path class="st2" d="M151.9,41.8V41c0-1,0-1.5-0.1-2.3l-1.4-0.2v-0.6l2.4-1.1l0.3,0.2l0.2,2.2v2.6c0,1.1,0,3,0.1,3.8h-1.5
|
||||
C151.8,44.7,151.9,42.9,151.9,41.8z M150.5,44.9l2-0.4h0.4l2,0.4v0.6h-4.3L150.5,44.9L150.5,44.9z M152.6,39.3h1l-0.5,0.1
|
||||
c0.6-1.7,1.7-2.7,2.7-2.7c0.5,0,1.1,0.3,1.3,0.6c0,0.8-0.3,1.3-1,1.3c-0.4,0-0.8-0.2-1.1-0.4l-0.5-0.4l0.9-0.2
|
||||
c-1.1,0.6-1.8,1.5-2.2,2.9h-0.6L152.6,39.3L152.6,39.3z"/>
|
||||
<path class="st2" d="M160.8,48v0.4h-3.1V48l1.4-0.2h0.2L160.8,48z M158.7,42.5c0-0.7,0-1,0-1.5l-1-0.1v-0.4l1.6-0.7l0.2,0.1l0.1,1
|
||||
l0,0v3.7v0.1v1.2c0,0.8,0,1.7,0,2.5h-1c0-0.8,0-1.7,0-2.5L158.7,42.5L158.7,42.5z M161.2,40.4c-0.4,0-1,0.2-1.9,1.1l-0.1-0.2
|
||||
c0.7-1.1,1.5-1.5,2.3-1.5c1.3,0,2.3,1.1,2.3,3c0,1.8-1.1,3-2.5,3c-0.7,0-1.5-0.3-2.1-1.6l0.1-0.2c0.6,0.8,1.2,1.1,1.8,1.1
|
||||
c0.9,0,1.7-0.7,1.7-2.3S162.1,40.4,161.2,40.4z"/>
|
||||
<g
|
||||
id="g120">
|
||||
<g
|
||||
class="st1"
|
||||
id="g118">
|
||||
<path
|
||||
class="st2"
|
||||
d="M151.9,41.8V41c0-1,0-1.5-0.1-2.3l-1.4-0.2v-0.6l2.4-1.1l0.3,0.2l0.2,2.2v2.6c0,1.1,0,3,0.1,3.8h-1.5 C151.8,44.7,151.9,42.9,151.9,41.8z M150.5,44.9l2-0.4h0.4l2,0.4v0.6h-4.3L150.5,44.9L150.5,44.9z M152.6,39.3h1l-0.5,0.1 c0.6-1.7,1.7-2.7,2.7-2.7c0.5,0,1.1,0.3,1.3,0.6c0,0.8-0.3,1.3-1,1.3c-0.4,0-0.8-0.2-1.1-0.4l-0.5-0.4l0.9-0.2 c-1.1,0.6-1.8,1.5-2.2,2.9h-0.6L152.6,39.3L152.6,39.3z"
|
||||
id="path114" />
|
||||
<path
|
||||
class="st2"
|
||||
d="M160.8,48v0.4h-3.1V48l1.4-0.2h0.2L160.8,48z M158.7,42.5c0-0.7,0-1,0-1.5l-1-0.1v-0.4l1.6-0.7l0.2,0.1l0.1,1 l0,0v3.7v0.1v1.2c0,0.8,0,1.7,0,2.5h-1c0-0.8,0-1.7,0-2.5L158.7,42.5L158.7,42.5z M161.2,40.4c-0.4,0-1,0.2-1.9,1.1l-0.1-0.2 c0.7-1.1,1.5-1.5,2.3-1.5c1.3,0,2.3,1.1,2.3,3c0,1.8-1.1,3-2.5,3c-0.7,0-1.5-0.3-2.1-1.6l0.1-0.2c0.6,0.8,1.2,1.1,1.8,1.1 c0.9,0,1.7-0.7,1.7-2.3S162.1,40.4,161.2,40.4z"
|
||||
id="path116" />
|
||||
</g>
|
||||
</g>
|
||||
<circle cx="283.4" cy="87.3" r="2.5"/>
|
||||
<circle cx="375.9" cy="140.2" r="2.5"/>
|
||||
<circle cx="488.9" cy="83" r="2.5"/>
|
||||
<circle cx="369.8" cy="20.6" r="2.5"/>
|
||||
<line class="st0" x1="369.8" y1="20.6" x2="283.4" y2="87.3"/>
|
||||
<line class="st0" x1="488.9" y1="82.9" x2="369.8" y2="20.6"/>
|
||||
<polygon class="st0" points="375.9,140.2 283.4,87.3 488.9,82.9 "/>
|
||||
<g>
|
||||
<g class="st1">
|
||||
<path class="st2" d="M367.1,53.4v-0.7h2.5v1h-0.2L367.1,53.4z M369.6,63.8v1h-2.5V64l2.3-0.3L369.6,63.8L369.6,63.8z M368.8,58.3
|
||||
c0-1.9,0-3.7-0.1-5.6h1.7c-0.1,1.8-0.1,3.7-0.1,5.6v0.6c0,2.1,0,4,0.1,5.9h-1.7c0.1-1.8,0.1-3.7,0.1-5.6V58.3z M369.6,58.1h1.8
|
||||
c2.2,0,3.2-0.7,3.2-2.4s-1-2.2-2.8-2.2h-2.2v-0.8h2.7c2.5,0,3.9,1.2,3.9,3c0,1.4-1,2.6-3.4,2.9v-0.2c2.8,0.2,4,1.5,4,3
|
||||
c0,1.6-1.4,3.3-4.8,3.3h-2.4v-0.8h2c2.3,0,3.5-0.9,3.5-2.5c0-1.7-1.1-2.5-3.6-2.5h-1.9L369.6,58.1L369.6,58.1z"/>
|
||||
<circle
|
||||
cx="283.4"
|
||||
cy="87.3"
|
||||
r="2.5"
|
||||
id="circle122" />
|
||||
<circle
|
||||
cx="375.9"
|
||||
cy="140.2"
|
||||
r="2.5"
|
||||
id="circle124" />
|
||||
<circle
|
||||
cx="488.9"
|
||||
cy="83"
|
||||
r="2.5"
|
||||
id="circle126" />
|
||||
<circle
|
||||
cx="369.8"
|
||||
cy="20.6"
|
||||
r="2.5"
|
||||
id="circle128" />
|
||||
<line
|
||||
class="st0"
|
||||
x1="369.8"
|
||||
y1="20.6"
|
||||
x2="283.4"
|
||||
y2="87.3"
|
||||
id="line130" />
|
||||
<line
|
||||
class="st0"
|
||||
x1="488.9"
|
||||
y1="82.9"
|
||||
x2="369.8"
|
||||
y2="20.6"
|
||||
id="line132" />
|
||||
<polygon
|
||||
class="st0"
|
||||
points="375.9,140.2 283.4,87.3 488.9,82.9 "
|
||||
id="polygon134" />
|
||||
<g
|
||||
id="g140">
|
||||
<g
|
||||
class="st1"
|
||||
id="g138">
|
||||
<path
|
||||
class="st2"
|
||||
d="M367.1,53.4v-0.7h2.5v1h-0.2L367.1,53.4z M369.6,63.8v1h-2.5V64l2.3-0.3L369.6,63.8L369.6,63.8z M368.8,58.3 c0-1.9,0-3.7-0.1-5.6h1.7c-0.1,1.8-0.1,3.7-0.1,5.6v0.6c0,2.1,0,4,0.1,5.9h-1.7c0.1-1.8,0.1-3.7,0.1-5.6V58.3z M369.6,58.1h1.8 c2.2,0,3.2-0.7,3.2-2.4s-1-2.2-2.8-2.2h-2.2v-0.8h2.7c2.5,0,3.9,1.2,3.9,3c0,1.4-1,2.6-3.4,2.9v-0.2c2.8,0.2,4,1.5,4,3 c0,1.6-1.4,3.3-4.8,3.3h-2.4v-0.8h2c2.3,0,3.5-0.9,3.5-2.5c0-1.7-1.1-2.5-3.6-2.5h-1.9L369.6,58.1L369.6,58.1z"
|
||||
id="path136" />
|
||||
</g>
|
||||
</g>
|
||||
<g>
|
||||
<g>
|
||||
<path d="M380,112.1v1l-1.1,0.3l0.5-2.7h1.1l-0.1,2.6c-1.1,0.6-2.4,0.9-3.6,0.9c-3.6,0-6.1-2.6-6.1-6.3c0-3.6,2.6-6.3,6.1-6.3
|
||||
c1,0,2.3,0.2,3.5,0.9l0.1,2.6h-1.1l-0.5-2.7l1.1,0.3v1.1c-1-1-2-1.3-2.9-1.3c-2.4,0-4.4,1.9-4.4,5.4s1.8,5.4,4.3,5.4
|
||||
C377.8,113.2,379,112.9,380,112.1z"/>
|
||||
<g
|
||||
id="g146">
|
||||
<g
|
||||
id="g144">
|
||||
<path
|
||||
d="M380,112.1v1l-1.1,0.3l0.5-2.7h1.1l-0.1,2.6c-1.1,0.6-2.4,0.9-3.6,0.9c-3.6,0-6.1-2.6-6.1-6.3c0-3.6,2.6-6.3,6.1-6.3 c1,0,2.3,0.2,3.5,0.9l0.1,2.6h-1.1l-0.5-2.7l1.1,0.3v1.1c-1-1-2-1.3-2.9-1.3c-2.4,0-4.4,1.9-4.4,5.4s1.8,5.4,4.3,5.4 C377.8,113.2,379,112.9,380,112.1z"
|
||||
id="path142" />
|
||||
</g>
|
||||
</g>
|
||||
<g>
|
||||
<g>
|
||||
<path d="M86.5,8c0.9,0,1.5-0.4,2.4-1.5L89.1,7c-0.8,1.4-1.7,2-2.9,2c-2.2,0-3.7-1.8-3.7-4.4c0-2.7,1.6-4.6,3.8-4.6
|
||||
c1,0,2,0.4,2.9,1.8L89,2.3c-1-1-1.8-1.3-2.4-1.3c-1.4,0-2.5,1.1-2.5,3.6C84,6.9,85,8,86.5,8z M89.6,12.1l2,0.4v0.6H87v-0.6
|
||||
l2.2-0.4H89.6z M90.1,13.1h-1.5c0-1.3,0.1-2.6,0.1-3.8V7.5l-0.1-0.3V1.3L89.8,0l0.3,0.2L90,2.6v6.7C90.1,10.5,90.1,11.8,90.1,13.1
|
||||
z"/>
|
||||
<g
|
||||
id="g152">
|
||||
<g
|
||||
id="g150">
|
||||
<path
|
||||
d="M86.5,8c0.9,0,1.5-0.4,2.4-1.5L89.1,7c-0.8,1.4-1.7,2-2.9,2c-2.2,0-3.7-1.8-3.7-4.4c0-2.7,1.6-4.6,3.8-4.6 c1,0,2,0.4,2.9,1.8L89,2.3c-1-1-1.8-1.3-2.4-1.3c-1.4,0-2.5,1.1-2.5,3.6C84,6.9,85,8,86.5,8z M89.6,12.1l2,0.4v0.6H87v-0.6 l2.2-0.4H89.6z M90.1,13.1h-1.5c0-1.3,0.1-2.6,0.1-3.8V7.5l-0.1-0.3V1.3L89.8,0l0.3,0.2L90,2.6v6.7C90.1,10.5,90.1,11.8,90.1,13.1 z"
|
||||
id="path148" />
|
||||
</g>
|
||||
</g>
|
||||
<g>
|
||||
<g>
|
||||
<path d="M366.2,8c0.9,0,1.5-0.4,2.4-1.5l0.2,0.5c-0.8,1.4-1.7,2-2.9,2c-2.2,0-3.7-1.8-3.7-4.4c0-2.7,1.6-4.6,3.8-4.6
|
||||
c1,0,2,0.4,2.9,1.8l-0.2,0.5c-1-1-1.8-1.3-2.4-1.3c-1.3,0-2.5,1.1-2.5,3.6C363.7,6.9,364.7,8,366.2,8z M369.3,12.1l2,0.4v0.6h-4.6
|
||||
v-0.6l2.2-0.4H369.3z M369.8,13.1h-1.5c0-1.3,0.1-2.6,0.1-3.8V7.5l-0.1-0.3V1.3l1.2-1.3l0.3,0.2l-0.1,2.4v6.7
|
||||
C369.8,10.5,369.8,11.8,369.8,13.1z"/>
|
||||
<g
|
||||
id="g158">
|
||||
<g
|
||||
id="g156">
|
||||
<path
|
||||
d="M366.2,8c0.9,0,1.5-0.4,2.4-1.5l0.2,0.5c-0.8,1.4-1.7,2-2.9,2c-2.2,0-3.7-1.8-3.7-4.4c0-2.7,1.6-4.6,3.8-4.6 c1,0,2,0.4,2.9,1.8l-0.2,0.5c-1-1-1.8-1.3-2.4-1.3c-1.3,0-2.5,1.1-2.5,3.6C363.7,6.9,364.7,8,366.2,8z M369.3,12.1l2,0.4v0.6h-4.6 v-0.6l2.2-0.4H369.3z M369.8,13.1h-1.5c0-1.3,0.1-2.6,0.1-3.8V7.5l-0.1-0.3V1.3l1.2-1.3l0.3,0.2l-0.1,2.4v6.7 C369.8,10.5,369.8,11.8,369.8,13.1z"
|
||||
id="path154" />
|
||||
</g>
|
||||
</g>
|
||||
<g>
|
||||
<g>
|
||||
<path d="M55.3,84.2l1.8-0.3h0.4l2,0.3v0.7h-4.1L55.3,84.2L55.3,84.2z M60.7,72.8h1.1L65.9,85h-1.7l-3.6-10.8H61L57.3,85h-0.8
|
||||
L60.7,72.8z M58.6,80.2h4.9l0.3,0.8h-5.4L58.6,80.2z M62.1,84.2l2.3-0.3h0.4l2.2,0.3v0.7h-4.9C62.1,84.9,62.1,84.2,62.1,84.2z"/>
|
||||
<path d="M72.8,84.4v0.5h-4.5v-0.5l1.7-0.3h1.1L72.8,84.4z M71.1,77.7l0.2,0.1v7.1h-1.2v-6.1l-1.4,0.1v-0.6L71.1,77.7z"/>
|
||||
<g
|
||||
id="g166">
|
||||
<g
|
||||
id="g164">
|
||||
<path
|
||||
d="M55.3,84.2l1.8-0.3h0.4l2,0.3v0.7h-4.1L55.3,84.2L55.3,84.2z M60.7,72.8h1.1L65.9,85h-1.7l-3.6-10.8H61L57.3,85h-0.8 L60.7,72.8z M58.6,80.2h4.9l0.3,0.8h-5.4L58.6,80.2z M62.1,84.2l2.3-0.3h0.4l2.2,0.3v0.7h-4.9C62.1,84.9,62.1,84.2,62.1,84.2z"
|
||||
id="path160" />
|
||||
|
||||
</g>
|
||||
</g>
|
||||
<g>
|
||||
<g>
|
||||
<path d="M123.1,84.8l1.8-0.3h0.4l2,0.3v0.7h-4.1v-0.7H123.1z M128.5,73.4h1.1l4.1,12.2H132l-3.6-10.9h0.4l-3.7,10.8h-0.8
|
||||
L128.5,73.4z M126.3,80.8h4.9l0.3,0.8h-5.4L126.3,80.8z M129.9,84.8l2.3-0.3h0.4l2.2,0.3v0.7h-4.9V84.8z"/>
|
||||
<path d="M135.9,84.6l1.7-1.6c1.1-1,1.6-1.9,1.6-2.8s-0.5-1.4-1.4-1.4c-0.3,0-0.7,0.1-1.1,0.2l0.7-0.5l-0.3,1
|
||||
c-0.2,0.7-0.4,0.9-0.7,0.9s-0.5-0.2-0.6-0.4c0.1-1.2,1.2-1.8,2.5-1.8c1.6,0,2.2,0.9,2.2,1.9s-0.7,1.8-2.3,3.3l-1.7,1.6l0.3-0.7h4
|
||||
v1.2H136L135.9,84.6L135.9,84.6z"/>
|
||||
<g
|
||||
id="g174">
|
||||
<g
|
||||
id="g172">
|
||||
<path
|
||||
d="M123.1,84.8l1.8-0.3h0.4l2,0.3v0.7h-4.1v-0.7H123.1z M128.5,73.4h1.1l4.1,12.2H132l-3.6-10.9h0.4l-3.7,10.8h-0.8 L128.5,73.4z M126.3,80.8h4.9l0.3,0.8h-5.4L126.3,80.8z M129.9,84.8l2.3-0.3h0.4l2.2,0.3v0.7h-4.9V84.8z"
|
||||
id="path168" />
|
||||
<path
|
||||
d="M135.9,84.6l1.7-1.6c1.1-1,1.6-1.9,1.6-2.8s-0.5-1.4-1.4-1.4c-0.3,0-0.7,0.1-1.1,0.2l0.7-0.5l-0.3,1 c-0.2,0.7-0.4,0.9-0.7,0.9s-0.5-0.2-0.6-0.4c0.1-1.2,1.2-1.8,2.5-1.8c1.6,0,2.2,0.9,2.2,1.9s-0.7,1.8-2.3,3.3l-1.7,1.6l0.3-0.7h4 v1.2H136L135.9,84.6L135.9,84.6z"
|
||||
id="path170" />
|
||||
</g>
|
||||
</g>
|
||||
<g>
|
||||
<g>
|
||||
<path d="M4.6,108.9v0.6H0v-0.6l2-0.4h0.4L4.6,108.9z M1.5,100.6c0-1,0-1.5-0.1-2.3L0,98.1v-0.6l2.4-1.1l0.3,0.2l0.1,1.5h0.1v5.6
|
||||
l-0.1,0.1v1.8c0,1.3,0,2.6,0.1,3.8H1.5c0-1.3,0.1-2.5,0.1-3.8L1.5,100.6L1.5,100.6z M5.2,97.4c-0.7,0-1.6,0.3-2.9,1.6l-0.2-0.3
|
||||
c1-1.6,2.2-2.3,3.4-2.3c1.9,0,3.4,1.7,3.4,4.5s-1.6,4.5-3.7,4.5c-1.1,0-2.2-0.5-3.2-2.4l0.2-0.3c0.9,1.2,1.8,1.7,2.7,1.7
|
||||
c1.4,0,2.5-1.1,2.5-3.4C7.5,98.7,6.5,97.4,5.2,97.4z"/>
|
||||
<path d="M15.7,105.5c0,2.6-1.2,3.7-2.5,3.7c-1.3,0-2.5-1.1-2.5-3.7s1.2-3.7,2.5-3.7C14.5,101.7,15.7,102.8,15.7,105.5z
|
||||
M13.2,108.6c0.6,0,1.2-0.6,1.2-3.1c0-2.6-0.6-3.1-1.2-3.1c-0.6,0-1.2,0.5-1.2,3.1C12,108,12.6,108.6,13.2,108.6z"/>
|
||||
<g
|
||||
id="g182">
|
||||
<g
|
||||
id="g180">
|
||||
<path
|
||||
d="M4.6,108.9v0.6H0v-0.6l2-0.4h0.4L4.6,108.9z M1.5,100.6c0-1,0-1.5-0.1-2.3L0,98.1v-0.6l2.4-1.1l0.3,0.2l0.1,1.5h0.1v5.6 l-0.1,0.1v1.8c0,1.3,0,2.6,0.1,3.8H1.5c0-1.3,0.1-2.5,0.1-3.8L1.5,100.6L1.5,100.6z M5.2,97.4c-0.7,0-1.6,0.3-2.9,1.6l-0.2-0.3 c1-1.6,2.2-2.3,3.4-2.3c1.9,0,3.4,1.7,3.4,4.5s-1.6,4.5-3.7,4.5c-1.1,0-2.2-0.5-3.2-2.4l0.2-0.3c0.9,1.2,1.8,1.7,2.7,1.7 c1.4,0,2.5-1.1,2.5-3.4C7.5,98.7,6.5,97.4,5.2,97.4z"
|
||||
id="path176" />
|
||||
<path
|
||||
d="M15.7,105.5c0,2.6-1.2,3.7-2.5,3.7c-1.3,0-2.5-1.1-2.5-3.7s1.2-3.7,2.5-3.7C14.5,101.7,15.7,102.8,15.7,105.5z M13.2,108.6c0.6,0,1.2-0.6,1.2-3.1c0-2.6-0.6-3.1-1.2-3.1c-0.6,0-1.2,0.5-1.2,3.1C12,108,12.6,108.6,13.2,108.6z"
|
||||
id="path178" />
|
||||
</g>
|
||||
</g>
|
||||
<g>
|
||||
<g>
|
||||
<path d="M96.9,160.4v0.6h-4.6v-0.6l2-0.4h0.4L96.9,160.4z M93.8,152.1c0-1,0-1.5-0.1-2.3l-1.4-0.2V149l2.4-1.1l0.3,0.2l0.1,1.5
|
||||
h0.1v5.6l-0.1,0.1v1.8c0,1.3,0,2.6,0.1,3.8h-1.5c0-1.3,0.1-2.5,0.1-3.8V152.1z M97.5,148.9c-0.7,0-1.6,0.3-2.9,1.6l-0.2-0.3
|
||||
c1-1.6,2.2-2.3,3.4-2.3c1.9,0,3.4,1.7,3.4,4.5s-1.6,4.5-3.7,4.5c-1.1,0-2.2-0.5-3.2-2.4l0.2-0.3c0.9,1.2,1.8,1.7,2.7,1.7
|
||||
c1.4,0,2.5-1.1,2.5-3.4C99.8,150.2,98.8,148.9,97.5,148.9z"/>
|
||||
<path d="M107.8,160v0.5h-4.5V160l1.7-0.3h1.1L107.8,160z M106.1,153.3l0.2,0.1v7.1h-1.2v-6.1l-1.4,0.1v-0.6L106.1,153.3z"/>
|
||||
<g
|
||||
id="g190">
|
||||
<g
|
||||
id="g188">
|
||||
<path
|
||||
d="M96.9,160.4v0.6h-4.6v-0.6l2-0.4h0.4L96.9,160.4z M93.8,152.1c0-1,0-1.5-0.1-2.3l-1.4-0.2V149l2.4-1.1l0.3,0.2l0.1,1.5 h0.1v5.6l-0.1,0.1v1.8c0,1.3,0,2.6,0.1,3.8h-1.5c0-1.3,0.1-2.5,0.1-3.8V152.1z M97.5,148.9c-0.7,0-1.6,0.3-2.9,1.6l-0.2-0.3 c1-1.6,2.2-2.3,3.4-2.3c1.9,0,3.4,1.7,3.4,4.5s-1.6,4.5-3.7,4.5c-1.1,0-2.2-0.5-3.2-2.4l0.2-0.3c0.9,1.2,1.8,1.7,2.7,1.7 c1.4,0,2.5-1.1,2.5-3.4C99.8,150.2,98.8,148.9,97.5,148.9z"
|
||||
id="path184" />
|
||||
<path
|
||||
d="M107.8,160v0.5h-4.5V160l1.7-0.3h1.1L107.8,160z M106.1,153.3l0.2,0.1v7.1h-1.2v-6.1l-1.4,0.1v-0.6L106.1,153.3z"
|
||||
id="path186" />
|
||||
</g>
|
||||
</g>
|
||||
<g>
|
||||
<g>
|
||||
<path d="M211,104.3v0.6h-4.6v-0.6l2-0.4h0.4L211,104.3z M207.9,96c0-1,0-1.5-0.1-2.3l-1.4-0.2v-0.6l2.4-1.1l0.3,0.2l0.1,1.5h0.1
|
||||
v5.6l-0.1,0.1v1.8c0,1.3,0,2.6,0.1,3.8h-1.5c0-1.3,0.1-2.5,0.1-3.8L207.9,96L207.9,96z M211.6,92.8c-0.7,0-1.6,0.3-2.9,1.6
|
||||
l-0.2-0.3c1-1.6,2.2-2.3,3.4-2.3c1.9,0,3.4,1.7,3.4,4.5s-1.6,4.5-3.7,4.5c-1.1,0-2.2-0.5-3.2-2.4l0.2-0.3c0.9,1.2,1.8,1.7,2.7,1.7
|
||||
c1.4,0,2.5-1.1,2.5-3.4C213.9,94.1,212.9,92.8,211.6,92.8z"/>
|
||||
<path d="M217.2,103.5l1.7-1.6c1.1-1,1.6-1.9,1.6-2.8s-0.5-1.4-1.4-1.4c-0.3,0-0.7,0.1-1.1,0.2l0.7-0.5l-0.3,1
|
||||
c-0.2,0.7-0.4,0.9-0.7,0.9s-0.5-0.2-0.6-0.4c0.1-1.2,1.2-1.8,2.5-1.8c1.6,0,2.2,0.9,2.2,1.9s-0.7,1.8-2.3,3.3l-1.7,1.6l0.3-0.7h4
|
||||
v1.2h-4.8L217.2,103.5L217.2,103.5z"/>
|
||||
<g
|
||||
id="g198">
|
||||
<g
|
||||
id="g196">
|
||||
<path
|
||||
d="M211,104.3v0.6h-4.6v-0.6l2-0.4h0.4L211,104.3z M207.9,96c0-1,0-1.5-0.1-2.3l-1.4-0.2v-0.6l2.4-1.1l0.3,0.2l0.1,1.5h0.1 v5.6l-0.1,0.1v1.8c0,1.3,0,2.6,0.1,3.8h-1.5c0-1.3,0.1-2.5,0.1-3.8L207.9,96L207.9,96z M211.6,92.8c-0.7,0-1.6,0.3-2.9,1.6 l-0.2-0.3c1-1.6,2.2-2.3,3.4-2.3c1.9,0,3.4,1.7,3.4,4.5s-1.6,4.5-3.7,4.5c-1.1,0-2.2-0.5-3.2-2.4l0.2-0.3c0.9,1.2,1.8,1.7,2.7,1.7 c1.4,0,2.5-1.1,2.5-3.4C213.9,94.1,212.9,92.8,211.6,92.8z"
|
||||
id="path192" />
|
||||
<path
|
||||
d="M217.2,103.5l1.7-1.6c1.1-1,1.6-1.9,1.6-2.8s-0.5-1.4-1.4-1.4c-0.3,0-0.7,0.1-1.1,0.2l0.7-0.5l-0.3,1 c-0.2,0.7-0.4,0.9-0.7,0.9s-0.5-0.2-0.6-0.4c0.1-1.2,1.2-1.8,2.5-1.8c1.6,0,2.2,0.9,2.2,1.9s-0.7,1.8-2.3,3.3l-1.7,1.6l0.3-0.7h4 v1.2h-4.8L217.2,103.5L217.2,103.5z"
|
||||
id="path194" />
|
||||
</g>
|
||||
</g>
|
||||
<g>
|
||||
<g>
|
||||
<path d="M284.7,108.9v0.6h-4.6v-0.6l2-0.4h0.4L284.7,108.9z M281.6,100.6c0-1,0-1.5-0.1-2.3l-1.4-0.2v-0.6l2.4-1.1l0.3,0.2
|
||||
l0.1,1.5h0.1v5.6l-0.1,0.1v1.8c0,1.3,0,2.6,0.1,3.8h-1.5c0-1.3,0.1-2.5,0.1-3.8V100.6z M285.3,97.4c-0.7,0-1.6,0.3-2.9,1.6
|
||||
l-0.2-0.3c1-1.6,2.2-2.3,3.4-2.3c1.9,0,3.4,1.7,3.4,4.5s-1.6,4.5-3.7,4.5c-1.1,0-2.2-0.5-3.2-2.4l0.2-0.3c0.9,1.2,1.8,1.7,2.7,1.7
|
||||
c1.4,0,2.5-1.1,2.5-3.4C287.6,98.7,286.6,97.4,285.3,97.4z"/>
|
||||
<path d="M295.8,105.5c0,2.6-1.2,3.7-2.5,3.7s-2.5-1.1-2.5-3.7s1.2-3.7,2.5-3.7C294.5,101.7,295.8,102.8,295.8,105.5z M293.3,108.6
|
||||
c0.6,0,1.2-0.6,1.2-3.1c0-2.6-0.6-3.1-1.2-3.1s-1.2,0.5-1.2,3.1C292,108,292.6,108.6,293.3,108.6z"/>
|
||||
<g
|
||||
id="g206">
|
||||
<g
|
||||
id="g204">
|
||||
<path
|
||||
d="M284.7,108.9v0.6h-4.6v-0.6l2-0.4h0.4L284.7,108.9z M281.6,100.6c0-1,0-1.5-0.1-2.3l-1.4-0.2v-0.6l2.4-1.1l0.3,0.2 l0.1,1.5h0.1v5.6l-0.1,0.1v1.8c0,1.3,0,2.6,0.1,3.8h-1.5c0-1.3,0.1-2.5,0.1-3.8V100.6z M285.3,97.4c-0.7,0-1.6,0.3-2.9,1.6 l-0.2-0.3c1-1.6,2.2-2.3,3.4-2.3c1.9,0,3.4,1.7,3.4,4.5s-1.6,4.5-3.7,4.5c-1.1,0-2.2-0.5-3.2-2.4l0.2-0.3c0.9,1.2,1.8,1.7,2.7,1.7 c1.4,0,2.5-1.1,2.5-3.4C287.6,98.7,286.6,97.4,285.3,97.4z"
|
||||
id="path200" />
|
||||
<path
|
||||
d="M295.8,105.5c0,2.6-1.2,3.7-2.5,3.7s-2.5-1.1-2.5-3.7s1.2-3.7,2.5-3.7C294.5,101.7,295.8,102.8,295.8,105.5z M293.3,108.6 c0.6,0,1.2-0.6,1.2-3.1c0-2.6-0.6-3.1-1.2-3.1s-1.2,0.5-1.2,3.1C292,108,292.6,108.6,293.3,108.6z"
|
||||
id="path202" />
|
||||
</g>
|
||||
</g>
|
||||
<g>
|
||||
<g>
|
||||
<path d="M377.2,160.4v0.6h-4.6v-0.6l2-0.4h0.4L377.2,160.4z M374.1,152.1c0-1,0-1.5-0.1-2.3l-1.4-0.2V149l2.4-1.1l0.3,0.2l0.1,1.5
|
||||
h0.1v5.6l-0.1,0.1v1.8c0,1.3,0,2.6,0.1,3.8H374c0-1.3,0.1-2.5,0.1-3.8V152.1z M377.8,148.9c-0.7,0-1.6,0.3-2.9,1.6l-0.2-0.3
|
||||
c1-1.6,2.2-2.3,3.4-2.3c1.9,0,3.4,1.7,3.4,4.5s-1.6,4.5-3.7,4.5c-1.1,0-2.2-0.5-3.2-2.4l0.2-0.3c0.9,1.2,1.8,1.7,2.7,1.7
|
||||
c1.4,0,2.5-1.1,2.5-3.4C380.1,150.2,379.1,148.9,377.8,148.9z"/>
|
||||
<path d="M388.1,160v0.5h-4.5V160l1.7-0.3h1.1L388.1,160z M386.4,153.3l0.2,0.1v7.1h-1.2v-6.1l-1.4,0.1v-0.6L386.4,153.3z"/>
|
||||
<g
|
||||
id="g214">
|
||||
<g
|
||||
id="g212">
|
||||
<path
|
||||
d="M377.2,160.4v0.6h-4.6v-0.6l2-0.4h0.4L377.2,160.4z M374.1,152.1c0-1,0-1.5-0.1-2.3l-1.4-0.2V149l2.4-1.1l0.3,0.2l0.1,1.5 h0.1v5.6l-0.1,0.1v1.8c0,1.3,0,2.6,0.1,3.8H374c0-1.3,0.1-2.5,0.1-3.8V152.1z M377.8,148.9c-0.7,0-1.6,0.3-2.9,1.6l-0.2-0.3 c1-1.6,2.2-2.3,3.4-2.3c1.9,0,3.4,1.7,3.4,4.5s-1.6,4.5-3.7,4.5c-1.1,0-2.2-0.5-3.2-2.4l0.2-0.3c0.9,1.2,1.8,1.7,2.7,1.7 c1.4,0,2.5-1.1,2.5-3.4C380.1,150.2,379.1,148.9,377.8,148.9z"
|
||||
id="path208" />
|
||||
<path
|
||||
d="M388.1,160v0.5h-4.5V160l1.7-0.3h1.1L388.1,160z M386.4,153.3l0.2,0.1v7.1h-1.2v-6.1l-1.4,0.1v-0.6L386.4,153.3z"
|
||||
id="path210" />
|
||||
</g>
|
||||
</g>
|
||||
<g>
|
||||
<g>
|
||||
<path d="M490.1,104.3v0.6h-4.6v-0.6l2-0.4h0.4L490.1,104.3z M487,96c0-1,0-1.5-0.1-2.3l-1.4-0.2v-0.6l2.4-1.1l0.3,0.2l0.1,1.5h0.1
|
||||
v5.6l-0.1,0.1v1.8c0,1.3,0,2.6,0.1,3.8h-1.5c0-1.3,0.1-2.5,0.1-3.8V96z M490.7,92.8c-0.7,0-1.6,0.3-2.9,1.6l-0.2-0.3
|
||||
c1-1.6,2.2-2.3,3.4-2.3c1.9,0,3.4,1.7,3.4,4.5s-1.6,4.5-3.7,4.5c-1.1,0-2.2-0.5-3.2-2.4l0.2-0.3c0.9,1.2,1.8,1.7,2.7,1.7
|
||||
c1.4,0,2.5-1.1,2.5-3.4C493,94.1,492,92.8,490.7,92.8z"/>
|
||||
<path d="M496.3,103.5l1.7-1.6c1.1-1,1.6-1.9,1.6-2.8s-0.5-1.4-1.4-1.4c-0.3,0-0.7,0.1-1.1,0.2l0.7-0.5l-0.3,1
|
||||
c-0.2,0.7-0.4,0.9-0.7,0.9c-0.3,0-0.5-0.2-0.6-0.4c0.1-1.2,1.2-1.8,2.5-1.8c1.6,0,2.2,0.9,2.2,1.9s-0.7,1.8-2.3,3.3l-1.7,1.6
|
||||
l0.3-0.7h4v1.2h-4.8v-0.9H496.3z"/>
|
||||
<g
|
||||
id="g222">
|
||||
<g
|
||||
id="g220">
|
||||
<path
|
||||
d="M490.1,104.3v0.6h-4.6v-0.6l2-0.4h0.4L490.1,104.3z M487,96c0-1,0-1.5-0.1-2.3l-1.4-0.2v-0.6l2.4-1.1l0.3,0.2l0.1,1.5h0.1 v5.6l-0.1,0.1v1.8c0,1.3,0,2.6,0.1,3.8h-1.5c0-1.3,0.1-2.5,0.1-3.8V96z M490.7,92.8c-0.7,0-1.6,0.3-2.9,1.6l-0.2-0.3 c1-1.6,2.2-2.3,3.4-2.3c1.9,0,3.4,1.7,3.4,4.5s-1.6,4.5-3.7,4.5c-1.1,0-2.2-0.5-3.2-2.4l0.2-0.3c0.9,1.2,1.8,1.7,2.7,1.7 c1.4,0,2.5-1.1,2.5-3.4C493,94.1,492,92.8,490.7,92.8z"
|
||||
id="path216" />
|
||||
<path
|
||||
d="M496.3,103.5l1.7-1.6c1.1-1,1.6-1.9,1.6-2.8s-0.5-1.4-1.4-1.4c-0.3,0-0.7,0.1-1.1,0.2l0.7-0.5l-0.3,1 c-0.2,0.7-0.4,0.9-0.7,0.9c-0.3,0-0.5-0.2-0.6-0.4c0.1-1.2,1.2-1.8,2.5-1.8c1.6,0,2.2,0.9,2.2,1.9s-0.7,1.8-2.3,3.3l-1.7,1.6 l0.3-0.7h4v1.2h-4.8v-0.9H496.3z"
|
||||
id="path218" />
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
<path
|
||||
d="m 73.601453,81.294142 c 0,2.6 -1.2,3.7 -2.5,3.7 -1.3,0 -2.5,-1.1 -2.5,-3.7 0,-2.6 1.2,-3.7 2.5,-3.7 1.3,-0.1 2.5,1 2.5,3.7 z m -2.5,3.1 c 0.6,0 1.2,-0.6 1.2,-3.1 0,-2.6 -0.6,-3.1 -1.2,-3.1 -0.6,0 -1.2,0.5 -1.2,3.1 0,2.5 0.6,3.1 1.2,3.1 z"
|
||||
id="path178-6" /></svg>
|
||||
|
|
|
|||
|
Before Width: | Height: | Size: 13 KiB After Width: | Height: | Size: 16 KiB |
|
|
@ -1,5 +1,4 @@
|
|||
#include <CGAL/Simple_cartesian.h>
|
||||
#include <CGAL/Weights/authalic_weights.h>
|
||||
#include <CGAL/Weights/three_point_family_weights.h>
|
||||
|
||||
// Typedefs.
|
||||
|
|
|
|||
|
|
@ -20,18 +20,18 @@ using HD = boost::graph_traits<Mesh>::halfedge_descriptor;
|
|||
template<typename PointMap>
|
||||
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<typename PointMap>
|
|||
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<std::size_t, FT> 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);
|
||||
|
|
|
|||
|
|
@ -14,186 +14,147 @@
|
|||
#ifndef CGAL_AUTHALIC_WEIGHTS_H
|
||||
#define CGAL_AUTHALIC_WEIGHTS_H
|
||||
|
||||
// Internal includes.
|
||||
#include <CGAL/Weights/internal/utils.h>
|
||||
#include <CGAL/Weights/utils.h>
|
||||
|
||||
#include <CGAL/Point_2.h>
|
||||
#include <CGAL/Point_3.h>
|
||||
|
||||
namespace CGAL {
|
||||
namespace Weights {
|
||||
|
||||
/// \cond SKIP_IN_MANUAL
|
||||
namespace authalic_ns {
|
||||
/// \cond SKIP_IN_MANUAL
|
||||
|
||||
template<typename FT>
|
||||
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<typename FT>
|
||||
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<typename FT>
|
||||
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<typename FT>
|
||||
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<typename FT>
|
||||
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<typename FT>
|
||||
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>
|
||||
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>
|
||||
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>
|
||||
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>
|
||||
typename K::FT authalic_weight(
|
||||
const CGAL::Point_2<K>& p0,
|
||||
const CGAL::Point_2<K>& p1,
|
||||
const CGAL::Point_2<K>& p2,
|
||||
const CGAL::Point_2<K>& 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>
|
||||
typename Kernel::FT authalic_weight(const CGAL::Point_2<Kernel>& p0,
|
||||
const CGAL::Point_2<Kernel>& p1,
|
||||
const CGAL::Point_2<Kernel>& p2,
|
||||
const CGAL::Point_2<Kernel>& 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>
|
||||
typename K::FT authalic_weight(
|
||||
const CGAL::Point_3<K>& p0,
|
||||
const CGAL::Point_3<K>& p1,
|
||||
const CGAL::Point_3<K>& p2,
|
||||
const CGAL::Point_3<K>& 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>
|
||||
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>
|
||||
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>
|
||||
typename GeomTraits::FT authalic_weight(
|
||||
const CGAL::Point_2<GeomTraits>& t,
|
||||
const CGAL::Point_2<GeomTraits>& r,
|
||||
const CGAL::Point_2<GeomTraits>& p,
|
||||
const CGAL::Point_2<GeomTraits>& q) {
|
||||
|
||||
const GeomTraits traits;
|
||||
return authalic_weight(t, r, p, q, traits);
|
||||
}
|
||||
|
||||
template<typename GeomTraits>
|
||||
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>
|
||||
typename GeomTraits::FT authalic_weight(
|
||||
const CGAL::Point_3<GeomTraits>& t,
|
||||
const CGAL::Point_3<GeomTraits>& r,
|
||||
const CGAL::Point_3<GeomTraits>& p,
|
||||
const CGAL::Point_3<GeomTraits>& 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>
|
||||
typename Kernel::FT authalic_weight(const CGAL::Point_3<Kernel>& p0,
|
||||
const CGAL::Point_3<Kernel>& p1,
|
||||
const CGAL::Point_3<Kernel>& p2,
|
||||
const CGAL::Point_3<Kernel>& q)
|
||||
{
|
||||
const Kernel traits;
|
||||
return authalic_weight(p0, p1, p2, q, traits);
|
||||
}
|
||||
|
||||
} // namespace Weights
|
||||
} // namespace CGAL
|
||||
|
|
|
|||
|
|
@ -14,131 +14,97 @@
|
|||
#ifndef CGAL_BARYCENTRIC_REGION_WEIGHTS_H
|
||||
#define CGAL_BARYCENTRIC_REGION_WEIGHTS_H
|
||||
|
||||
// Internal includes.
|
||||
#include <CGAL/Weights/internal/utils.h>
|
||||
#include <CGAL/Weights/utils.h>
|
||||
|
||||
#include <CGAL/Point_2.h>
|
||||
#include <CGAL/Point_3.h>
|
||||
|
||||
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>
|
||||
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>
|
||||
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>
|
||||
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>
|
||||
typename Kernel::FT barycentric_area(const CGAL::Point_2<Kernel>& p,
|
||||
const CGAL::Point_2<Kernel>& q,
|
||||
const CGAL::Point_2<Kernel>& 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>
|
||||
typename K::FT barycentric_area(
|
||||
const CGAL::Point_2<K>& p,
|
||||
const CGAL::Point_2<K>& q,
|
||||
const CGAL::Point_2<K>& 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>
|
||||
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>
|
||||
typename K::FT barycentric_area(
|
||||
const CGAL::Point_3<K>& p,
|
||||
const CGAL::Point_3<K>& q,
|
||||
const CGAL::Point_3<K>& 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>
|
||||
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>
|
||||
typename GeomTraits::FT barycentric_area(
|
||||
const CGAL::Point_2<GeomTraits>& p,
|
||||
const CGAL::Point_2<GeomTraits>& q,
|
||||
const CGAL::Point_2<GeomTraits>& r) {
|
||||
|
||||
const GeomTraits traits;
|
||||
return barycentric_area(p, q, r, traits);
|
||||
}
|
||||
|
||||
template<typename GeomTraits>
|
||||
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>
|
||||
typename GeomTraits::FT barycentric_area(
|
||||
const CGAL::Point_3<GeomTraits>& p,
|
||||
const CGAL::Point_3<GeomTraits>& q,
|
||||
const CGAL::Point_3<GeomTraits>& 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>
|
||||
typename Kernel::FT barycentric_area(const CGAL::Point_3<Kernel>& p,
|
||||
const CGAL::Point_3<Kernel>& q,
|
||||
const CGAL::Point_3<Kernel>& r)
|
||||
{
|
||||
const Kernel traits;
|
||||
return barycentric_area(p, q, r, traits);
|
||||
}
|
||||
|
||||
} // namespace Weights
|
||||
} // namespace CGAL
|
||||
|
|
|
|||
|
|
@ -14,482 +14,356 @@
|
|||
#ifndef CGAL_COTANGENT_WEIGHTS_H
|
||||
#define CGAL_COTANGENT_WEIGHTS_H
|
||||
|
||||
// Internal includes.
|
||||
#include <CGAL/Weights/internal/utils.h>
|
||||
#include <CGAL/Weights/utils.h>
|
||||
|
||||
#include <CGAL/boost/graph/helpers.h>
|
||||
#include <CGAL/Kernel_traits.h>
|
||||
#include <CGAL/Point_2.h>
|
||||
#include <CGAL/Point_3.h>
|
||||
#include <CGAL/utility.h>
|
||||
|
||||
namespace CGAL {
|
||||
namespace Weights {
|
||||
|
||||
/// \cond SKIP_IN_MANUAL
|
||||
namespace cotangent_ns {
|
||||
/// \cond SKIP_IN_MANUAL
|
||||
|
||||
template<typename FT>
|
||||
FT half_weight(const FT cot) {
|
||||
return FT(2) * cot;
|
||||
}
|
||||
namespace cotangent_ns {
|
||||
|
||||
template<typename FT>
|
||||
FT weight(const FT cot_beta, const FT cot_gamma) {
|
||||
return FT(2) * (cot_beta + cot_gamma);
|
||||
}
|
||||
template<typename FT>
|
||||
FT half_weight(const FT cot)
|
||||
{
|
||||
return FT(2) * cot;
|
||||
}
|
||||
|
||||
template<typename FT>
|
||||
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<typename FT>
|
||||
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>
|
||||
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>
|
||||
typename Kernel::FT cotangent_weight(const CGAL::Point_2<Kernel>& p0,
|
||||
const CGAL::Point_2<Kernel>& p1,
|
||||
const CGAL::Point_2<Kernel>& p2,
|
||||
const CGAL::Point_2<Kernel>& 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>
|
||||
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>
|
||||
typename Kernel::FT cotangent_weight(const CGAL::Point_3<Kernel>& p0,
|
||||
const CGAL::Point_3<Kernel>& p1,
|
||||
const CGAL::Point_3<Kernel>& p2,
|
||||
const CGAL::Point_3<Kernel>& 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<typename PolygonMesh,
|
||||
typename VertexPointMap,
|
||||
typename GeomTraits = typename Kernel_traits<
|
||||
typename boost::property_traits<VertexPointMap>::value_type>::type>
|
||||
class Single_cotangent_weight
|
||||
{
|
||||
using vertex_descriptor = typename boost::graph_traits<PolygonMesh>::vertex_descriptor;
|
||||
using halfedge_descriptor = typename boost::graph_traits<PolygonMesh>::halfedge_descriptor;
|
||||
|
||||
using Point_ref = typename boost::property_traits<VertexPointMap>::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<typename PolygonMesh,
|
||||
typename VertexPointMap,
|
||||
typename GeomTraits = typename Kernel_traits<
|
||||
typename boost::property_traits<VertexPointMap>::value_type>::type>
|
||||
class Cotangent_weight
|
||||
{
|
||||
using vertex_descriptor = typename boost::graph_traits<PolygonMesh>::vertex_descriptor;
|
||||
using halfedge_descriptor = typename boost::graph_traits<PolygonMesh>::halfedge_descriptor;
|
||||
|
||||
\brief computes the half value of the cotangent weight.
|
||||
using Point_ref = typename boost::property_traits<VertexPointMap>::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<typename FT>
|
||||
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<typename PolygonMesh,
|
||||
typename VertexPointMap,
|
||||
typename GeomTraits>
|
||||
class Secure_cotangent_weight_with_voronoi_area
|
||||
{
|
||||
using vertex_descriptor = typename boost::graph_traits<PolygonMesh>::vertex_descriptor;
|
||||
using halfedge_descriptor = typename boost::graph_traits<PolygonMesh>::halfedge_descriptor;
|
||||
|
||||
using Point_ref = typename boost::property_traits<VertexPointMap>::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<PolygonMesh, VertexPointMap, GeomTraits> 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>
|
||||
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>
|
||||
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>
|
||||
typename K::FT cotangent_weight(
|
||||
const CGAL::Point_2<K>& p0,
|
||||
const CGAL::Point_2<K>& p1,
|
||||
const CGAL::Point_2<K>& p2,
|
||||
const CGAL::Point_2<K>& 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>
|
||||
typename K::FT cotangent_weight(
|
||||
const CGAL::Point_3<K>& p0,
|
||||
const CGAL::Point_3<K>& p1,
|
||||
const CGAL::Point_3<K>& p2,
|
||||
const CGAL::Point_3<K>& q) { }
|
||||
|
||||
#endif // DOXYGEN_RUNNING
|
||||
|
||||
/// \cond SKIP_IN_MANUAL
|
||||
template<typename GeomTraits>
|
||||
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>
|
||||
typename GeomTraits::FT cotangent_weight(
|
||||
const CGAL::Point_2<GeomTraits>& t,
|
||||
const CGAL::Point_2<GeomTraits>& r,
|
||||
const CGAL::Point_2<GeomTraits>& p,
|
||||
const CGAL::Point_2<GeomTraits>& 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>
|
||||
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>
|
||||
typename GeomTraits::FT cotangent_weight(
|
||||
const CGAL::Point_3<GeomTraits>& t,
|
||||
const CGAL::Point_3<GeomTraits>& r,
|
||||
const CGAL::Point_3<GeomTraits>& p,
|
||||
const CGAL::Point_3<GeomTraits>& 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<PolygonMesh, CGAL::vertex_point_t>::type>
|
||||
class Edge_cotangent_weight {
|
||||
|
||||
using GeomTraits = typename CGAL::Kernel_traits<
|
||||
typename boost::property_traits<VertexPointMap>::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<PolygonMesh>::vertex_descriptor;
|
||||
using halfedge_descriptor = typename boost::graph_traits<PolygonMesh>::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<typename PolygonMesh>
|
||||
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<PolygonMesh>::vertex_descriptor;
|
||||
using halfedge_descriptor = typename boost::graph_traits<PolygonMesh>::halfedge_descriptor;
|
||||
|
||||
template<class VertexPointMap>
|
||||
decltype(auto) operator()(const halfedge_descriptor he,
|
||||
const PolygonMesh& pmesh, const VertexPointMap pmap) const {
|
||||
|
||||
using GeomTraits = typename CGAL::Kernel_traits<
|
||||
typename boost::property_traits<VertexPointMap>::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<typename PolygonMesh>
|
||||
class Cotangent_weight {
|
||||
bool m_use_clamped_version;
|
||||
|
||||
public:
|
||||
using vertex_descriptor = typename boost::graph_traits<PolygonMesh>::vertex_descriptor;
|
||||
using halfedge_descriptor = typename boost::graph_traits<PolygonMesh>::halfedge_descriptor;
|
||||
|
||||
Cotangent_weight(const bool use_clamped_version = false) :
|
||||
m_use_clamped_version(use_clamped_version) { }
|
||||
|
||||
template<class VertexPointMap>
|
||||
decltype(auto) operator()(const halfedge_descriptor he,
|
||||
const PolygonMesh& pmesh, const VertexPointMap pmap) const {
|
||||
|
||||
using GeomTraits = typename CGAL::Kernel_traits<
|
||||
typename boost::property_traits<VertexPointMap>::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<PolygonMesh, CGAL::vertex_point_t>::type>
|
||||
class Secure_cotangent_weight_with_voronoi_area {
|
||||
|
||||
using GeomTraits = typename CGAL::Kernel_traits<
|
||||
typename boost::property_traits<VertexPointMap>::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<PolygonMesh>::vertex_descriptor;
|
||||
using halfedge_descriptor = typename boost::graph_traits<PolygonMesh>::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
|
||||
|
|
|
|||
|
|
@ -14,429 +14,379 @@
|
|||
#ifndef CGAL_DISCRETE_HARMONIC_WEIGHTS_H
|
||||
#define CGAL_DISCRETE_HARMONIC_WEIGHTS_H
|
||||
|
||||
// Internal includes.
|
||||
#include <CGAL/Weights/internal/utils.h>
|
||||
#include <CGAL/Weights/internal/polygon_utils_2.h>
|
||||
|
||||
#include <CGAL/Point_2.h>
|
||||
#include <CGAL/Point_3.h>
|
||||
#include <CGAL/property_map.h>
|
||||
|
||||
#include <vector>
|
||||
|
||||
namespace CGAL {
|
||||
namespace Weights {
|
||||
|
||||
/// \cond SKIP_IN_MANUAL
|
||||
namespace discrete_harmonic_ns {
|
||||
/// \cond SKIP_IN_MANUAL
|
||||
|
||||
template<typename FT>
|
||||
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<typename FT>
|
||||
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>
|
||||
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>
|
||||
typename K::FT discrete_harmonic_weight(
|
||||
const CGAL::Point_2<K>& p0,
|
||||
const CGAL::Point_2<K>& p1,
|
||||
const CGAL::Point_2<K>& p2,
|
||||
const CGAL::Point_2<K>& 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>
|
||||
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>
|
||||
typename Kernel::FT discrete_harmonic_weight(const CGAL::Point_2<Kernel>& p0,
|
||||
const CGAL::Point_2<Kernel>& p1,
|
||||
const CGAL::Point_2<Kernel>& p2,
|
||||
const CGAL::Point_2<Kernel>& q)
|
||||
{
|
||||
const Kernel traits;
|
||||
return discrete_harmonic_weight(p0, p1, p2, q, traits);
|
||||
}
|
||||
|
||||
// 3D ==============================================================================================
|
||||
|
||||
/// \cond SKIP_IN_MANUAL
|
||||
|
||||
template<typename GeomTraits>
|
||||
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>
|
||||
typename Kernel::FT discrete_harmonic_weight(const CGAL::Point_3<Kernel>& p0,
|
||||
const CGAL::Point_3<Kernel>& p1,
|
||||
const CGAL::Point_3<Kernel>& p2,
|
||||
const CGAL::Point_3<Kernel>& 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<typename VertexRange,
|
||||
typename GeomTraits,
|
||||
typename PointMap = CGAL::Identity_property_map<typename GeomTraits::Point_2> >
|
||||
class Discrete_harmonic_weights_2
|
||||
{
|
||||
public:
|
||||
/// \name Types
|
||||
/// @{
|
||||
|
||||
/// \cond SKIP_IN_MANUAL
|
||||
template<typename GeomTraits>
|
||||
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>
|
||||
typename GeomTraits::FT discrete_harmonic_weight(
|
||||
const CGAL::Point_2<GeomTraits>& t,
|
||||
const CGAL::Point_2<GeomTraits>& r,
|
||||
const CGAL::Point_2<GeomTraits>& p,
|
||||
const CGAL::Point_2<GeomTraits>& q) {
|
||||
|
||||
const GeomTraits traits;
|
||||
return discrete_harmonic_weight(t, r, p, q, traits);
|
||||
}
|
||||
|
||||
namespace internal {
|
||||
|
||||
template<typename GeomTraits>
|
||||
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>
|
||||
typename GeomTraits::FT discrete_harmonic_weight(
|
||||
const CGAL::Point_3<GeomTraits>& t,
|
||||
const CGAL::Point_3<GeomTraits>& r,
|
||||
const CGAL::Point_3<GeomTraits>& p,
|
||||
const CGAL::Point_3<GeomTraits>& 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<typename GeomTraits::Point_2> >
|
||||
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<typename OutIterator>
|
||||
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 OutIterator>
|
||||
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<FT> r;
|
||||
std::vector<FT> A;
|
||||
std::vector<FT> B;
|
||||
std::vector<FT> 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<typename OutputIterator>
|
||||
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<PointRange, GeomTraits>
|
||||
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<typename OutIterator>
|
||||
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<Point_2>::Kernel;
|
||||
const GeomTraits traits;
|
||||
return discrete_harmonic_weights_2(
|
||||
polygon, query, w_begin, traits);
|
||||
template<typename OutIterator>
|
||||
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<FT> r;
|
||||
std::vector<FT> A;
|
||||
std::vector<FT> B;
|
||||
std::vector<FT> w;
|
||||
|
||||
void resize()
|
||||
{
|
||||
r.resize(m_polygon.size());
|
||||
A.resize(m_polygon.size());
|
||||
B.resize(m_polygon.size());
|
||||
w.resize(m_polygon.size());
|
||||
}
|
||||
|
||||
template<typename OutputIterator>
|
||||
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<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<PointRange, GeomTraits> discrete_harmonic(polygon, traits);
|
||||
return discrete_harmonic(query, w_begin);
|
||||
}
|
||||
|
||||
/// \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<Point_2>::Kernel;
|
||||
|
||||
const GeomTraits traits;
|
||||
return discrete_harmonic_weights_2(polygon, query, w_begin, traits);
|
||||
}
|
||||
/// \endcond
|
||||
|
||||
} // namespace Weights
|
||||
} // namespace CGAL
|
||||
|
||||
|
|
|
|||
|
|
@ -14,7 +14,12 @@
|
|||
#ifndef CGAL_WEIGHTS_INTERNAL_POLYGON_UTILS_2_H
|
||||
#define CGAL_WEIGHTS_INTERNAL_POLYGON_UTILS_2_H
|
||||
|
||||
// STL includes.
|
||||
#include <CGAL/utils.h>
|
||||
#include <CGAL/assertions.h>
|
||||
#include <CGAL/number_utils.h>
|
||||
#include <CGAL/property_map.h>
|
||||
#include <CGAL/Polygon_2_algorithms.h>
|
||||
|
||||
#include <cmath>
|
||||
#include <string>
|
||||
#include <memory>
|
||||
|
|
@ -23,345 +28,329 @@
|
|||
#include <iterator>
|
||||
#include <iostream>
|
||||
|
||||
// CGAL includes.
|
||||
#include <CGAL/utils.h>
|
||||
#include <CGAL/assertions.h>
|
||||
#include <CGAL/number_utils.h>
|
||||
#include <CGAL/property_map.h>
|
||||
#include <CGAL/Polygon_2_algorithms.h>
|
||||
|
||||
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<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 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<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 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<typename VertexRange,
|
||||
typename GeomTraits,
|
||||
typename PointMap>
|
||||
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<typename GeomTraits::Point_2> 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<typename VertexRange,
|
||||
typename GeomTraits,
|
||||
typename PointMap>
|
||||
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<typename GeomTraits::Point_2> 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 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
|
||||
|
|
|
|||
|
|
@ -14,219 +14,167 @@
|
|||
#ifndef CGAL_INVERSE_DISTANCE_WEIGHTS_H
|
||||
#define CGAL_INVERSE_DISTANCE_WEIGHTS_H
|
||||
|
||||
// Internal includes.
|
||||
#include <CGAL/Weights/internal/utils.h>
|
||||
|
||||
#include <CGAL/Point_2.h>
|
||||
#include <CGAL/Point_3.h>
|
||||
|
||||
namespace CGAL {
|
||||
namespace Weights {
|
||||
|
||||
/// \cond SKIP_IN_MANUAL
|
||||
namespace inverse_distance_ns {
|
||||
/// \cond SKIP_IN_MANUAL
|
||||
namespace inverse_distance_ns {
|
||||
|
||||
template<typename FT>
|
||||
FT weight(const FT d) {
|
||||
template<typename FT>
|
||||
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>
|
||||
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>
|
||||
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>
|
||||
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<typename Kernel>
|
||||
#ifdef DOXYGEN_RUNNING
|
||||
typename Kernel::FT inverse_distance_weight(const CGAL::Point_2<Kernel>&,
|
||||
const CGAL::Point_2<Kernel>& p,
|
||||
const CGAL::Point_2<Kernel>&,
|
||||
const CGAL::Point_2<Kernel>& q)
|
||||
#else
|
||||
typename Kernel::FT inverse_distance_weight(const CGAL::Point_2<Kernel>& stub_l,
|
||||
const CGAL::Point_2<Kernel>& p,
|
||||
const CGAL::Point_2<Kernel>& stub_r,
|
||||
const CGAL::Point_2<Kernel>& 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>
|
||||
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>
|
||||
typename K::FT inverse_distance_weight(
|
||||
const CGAL::Point_2<K>&,
|
||||
const CGAL::Point_2<K>& p,
|
||||
const CGAL::Point_2<K>&,
|
||||
const CGAL::Point_2<K>& 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>
|
||||
typename Kernel::FT inverse_distance_weight(const CGAL::Point_2<Kernel>& p,
|
||||
const CGAL::Point_2<Kernel>& q)
|
||||
{
|
||||
CGAL::Point_2<Kernel> 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>
|
||||
typename K::FT inverse_distance_weight(
|
||||
const CGAL::Point_3<K>&,
|
||||
const CGAL::Point_3<K>& p,
|
||||
const CGAL::Point_3<K>&,
|
||||
const CGAL::Point_3<K>& 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>
|
||||
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>
|
||||
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<typename Kernel>
|
||||
#ifdef DOXYGEN_RUNNING
|
||||
typename Kernel::FT inverse_distance_weight(const CGAL::Point_3<Kernel>&,
|
||||
const CGAL::Point_3<Kernel>& p,
|
||||
const CGAL::Point_3<Kernel>&,
|
||||
const CGAL::Point_3<Kernel>& q)
|
||||
#else
|
||||
typename Kernel::FT inverse_distance_weight(const CGAL::Point_3<Kernel>& stub_l,
|
||||
const CGAL::Point_3<Kernel>& p,
|
||||
const CGAL::Point_3<Kernel>& stub_r,
|
||||
const CGAL::Point_3<Kernel>& 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>
|
||||
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>
|
||||
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>
|
||||
typename K::FT inverse_distance_weight(
|
||||
const CGAL::Point_2<K>& p,
|
||||
const CGAL::Point_2<K>& 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>
|
||||
typename K::FT inverse_distance_weight(
|
||||
const CGAL::Point_3<K>& p,
|
||||
const CGAL::Point_3<K>& q) { }
|
||||
|
||||
#endif // DOXYGEN_RUNNING
|
||||
|
||||
/// \cond SKIP_IN_MANUAL
|
||||
template<typename GeomTraits>
|
||||
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>
|
||||
typename GeomTraits::FT inverse_distance_weight(
|
||||
const CGAL::Point_2<GeomTraits>& t,
|
||||
const CGAL::Point_2<GeomTraits>& r,
|
||||
const CGAL::Point_2<GeomTraits>& p,
|
||||
const CGAL::Point_2<GeomTraits>& q) {
|
||||
|
||||
const GeomTraits traits;
|
||||
return inverse_distance_weight(t, r, p, q, traits);
|
||||
}
|
||||
|
||||
template<typename GeomTraits>
|
||||
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>
|
||||
typename GeomTraits::FT inverse_distance_weight(
|
||||
const CGAL::Point_2<GeomTraits>& p,
|
||||
const CGAL::Point_2<GeomTraits>& q) {
|
||||
|
||||
CGAL::Point_2<GeomTraits> stub;
|
||||
return inverse_distance_weight(stub, p, stub, q);
|
||||
}
|
||||
|
||||
template<typename GeomTraits>
|
||||
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>
|
||||
typename GeomTraits::FT inverse_distance_weight(
|
||||
const CGAL::Point_3<GeomTraits>& t,
|
||||
const CGAL::Point_3<GeomTraits>& r,
|
||||
const CGAL::Point_3<GeomTraits>& p,
|
||||
const CGAL::Point_3<GeomTraits>& q) {
|
||||
|
||||
const GeomTraits traits;
|
||||
return inverse_distance_weight(t, r, p, q, traits);
|
||||
}
|
||||
|
||||
template<typename GeomTraits>
|
||||
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>
|
||||
typename GeomTraits::FT inverse_distance_weight(
|
||||
const CGAL::Point_3<GeomTraits>& p,
|
||||
const CGAL::Point_3<GeomTraits>& q) {
|
||||
|
||||
CGAL::Point_3<GeomTraits> 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>
|
||||
typename Kernel::FT inverse_distance_weight(const CGAL::Point_3<Kernel>& p,
|
||||
const CGAL::Point_3<Kernel>& q)
|
||||
{
|
||||
CGAL::Point_3<Kernel> stub;
|
||||
return inverse_distance_weight(stub, p, stub, q);
|
||||
}
|
||||
|
||||
} // namespace Weights
|
||||
} // namespace CGAL
|
||||
|
|
|
|||
|
|
@ -14,498 +14,457 @@
|
|||
#ifndef CGAL_MEAN_VALUE_WEIGHTS_H
|
||||
#define CGAL_MEAN_VALUE_WEIGHTS_H
|
||||
|
||||
// Internal includes.
|
||||
#include <CGAL/Weights/internal/utils.h>
|
||||
#include <CGAL/Weights/internal/polygon_utils_2.h>
|
||||
|
||||
#include <CGAL/Kernel_traits.h>
|
||||
#include <CGAL/Point_2.h>
|
||||
#include <CGAL/Point_3.h>
|
||||
#include <CGAL/property_map.h>
|
||||
|
||||
#include <vector>
|
||||
|
||||
namespace CGAL {
|
||||
namespace Weights {
|
||||
|
||||
/// \cond SKIP_IN_MANUAL
|
||||
namespace mean_value_ns {
|
||||
/// \cond SKIP_IN_MANUAL
|
||||
|
||||
template<typename FT>
|
||||
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<typename FT>
|
||||
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>
|
||||
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<GeomTraits>;
|
||||
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>
|
||||
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<GeomTraits>;
|
||||
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>
|
||||
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>
|
||||
typename K::FT mean_value_weight(
|
||||
const CGAL::Point_2<K>& p0,
|
||||
const CGAL::Point_2<K>& p1,
|
||||
const CGAL::Point_2<K>& p2,
|
||||
const CGAL::Point_2<K>& 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>
|
||||
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>
|
||||
typename Kernel::FT mean_value_weight(const CGAL::Point_2<Kernel>& p0,
|
||||
const CGAL::Point_2<Kernel>& p1,
|
||||
const CGAL::Point_2<Kernel>& p2,
|
||||
const CGAL::Point_2<Kernel>& q)
|
||||
{
|
||||
const Kernel traits;
|
||||
return mean_value_weight(p0, p1, p2, q, traits);
|
||||
}
|
||||
|
||||
// 3D ==============================================================================================
|
||||
|
||||
/// \cond SKIP_IN_MANUAL
|
||||
|
||||
template<typename GeomTraits>
|
||||
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>
|
||||
typename Kernel::FT mean_value_weight(const CGAL::Point_3<Kernel>& p0,
|
||||
const CGAL::Point_3<Kernel>& p1,
|
||||
const CGAL::Point_3<Kernel>& p2,
|
||||
const CGAL::Point_3<Kernel>& 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<typename VertexRange,
|
||||
typename GeomTraits,
|
||||
typename PointMap = CGAL::Identity_property_map<typename GeomTraits::Point_2> >
|
||||
class Mean_value_weights_2
|
||||
{
|
||||
public:
|
||||
/// \name Types
|
||||
/// @{
|
||||
|
||||
/// \cond SKIP_IN_MANUAL
|
||||
template<typename GeomTraits>
|
||||
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>
|
||||
typename GeomTraits::FT mean_value_weight(
|
||||
const CGAL::Point_2<GeomTraits>& t,
|
||||
const CGAL::Point_2<GeomTraits>& r,
|
||||
const CGAL::Point_2<GeomTraits>& p,
|
||||
const CGAL::Point_2<GeomTraits>& q) {
|
||||
|
||||
const GeomTraits traits;
|
||||
return mean_value_weight(t, r, p, q, traits);
|
||||
}
|
||||
|
||||
namespace internal {
|
||||
|
||||
template<typename GeomTraits>
|
||||
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>
|
||||
typename GeomTraits::FT mean_value_weight(
|
||||
const CGAL::Point_3<GeomTraits>& t,
|
||||
const CGAL::Point_3<GeomTraits>& r,
|
||||
const CGAL::Point_3<GeomTraits>& p,
|
||||
const CGAL::Point_3<GeomTraits>& 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<GeomTraits>;
|
||||
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<typename GeomTraits::Point_2> >
|
||||
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<GeomTraits>;
|
||||
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<typename OutIterator>
|
||||
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 OutIterator>
|
||||
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<Vector_2> s;
|
||||
std::vector<FT> r;
|
||||
std::vector<FT> A;
|
||||
std::vector<FT> D;
|
||||
std::vector<FT> t;
|
||||
std::vector<FT> 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<typename OutputIterator>
|
||||
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<PointRange, GeomTraits>
|
||||
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<typename OutIterator>
|
||||
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<Point_2>::Kernel;
|
||||
const GeomTraits traits;
|
||||
return mean_value_weights_2(
|
||||
polygon, query, w_begin, traits);
|
||||
template<typename OutIterator>
|
||||
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<Vector_2> s;
|
||||
std::vector<FT> r;
|
||||
std::vector<FT> A;
|
||||
std::vector<FT> D;
|
||||
std::vector<FT> t;
|
||||
std::vector<FT> 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<typename OutputIterator>
|
||||
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<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<PointRange, GeomTraits> mean_value(polygon, traits);
|
||||
return mean_value(query, w_begin);
|
||||
}
|
||||
|
||||
/// \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<Point_2>::Kernel;
|
||||
|
||||
const GeomTraits traits;
|
||||
return mean_value_weights_2(polygon, query, w_begin, traits);
|
||||
}
|
||||
|
||||
/// \endcond
|
||||
|
||||
} // namespace Weights
|
||||
} // namespace CGAL
|
||||
|
||||
|
|
|
|||
|
|
@ -14,157 +14,115 @@
|
|||
#ifndef CGAL_MIXED_VORONOI_REGION_WEIGHTS_H
|
||||
#define CGAL_MIXED_VORONOI_REGION_WEIGHTS_H
|
||||
|
||||
// Internal includes.
|
||||
#include <CGAL/Weights/internal/utils.h>
|
||||
|
||||
#include <CGAL/Point_2.h>
|
||||
#include <CGAL/Point_3.h>
|
||||
|
||||
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>
|
||||
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>
|
||||
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>
|
||||
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>
|
||||
typename K::FT mixed_voronoi_area(
|
||||
const CGAL::Point_2<K>& p,
|
||||
const CGAL::Point_2<K>& q,
|
||||
const CGAL::Point_2<K>& 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>
|
||||
typename GeomTraits::FT mixed_voronoi_area(const CGAL::Point_2<GeomTraits>& p,
|
||||
const CGAL::Point_2<GeomTraits>& q,
|
||||
const CGAL::Point_2<GeomTraits>& 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>
|
||||
typename K::FT mixed_voronoi_area(
|
||||
const CGAL::Point_3<K>& p,
|
||||
const CGAL::Point_3<K>& q,
|
||||
const CGAL::Point_3<K>& 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>
|
||||
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>
|
||||
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>
|
||||
typename GeomTraits::FT mixed_voronoi_area(
|
||||
const CGAL::Point_2<GeomTraits>& p,
|
||||
const CGAL::Point_2<GeomTraits>& q,
|
||||
const CGAL::Point_2<GeomTraits>& r) {
|
||||
|
||||
const GeomTraits traits;
|
||||
return mixed_voronoi_area(p, q, r, traits);
|
||||
}
|
||||
|
||||
template<typename GeomTraits>
|
||||
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>
|
||||
typename GeomTraits::FT mixed_voronoi_area(
|
||||
const CGAL::Point_3<GeomTraits>& p,
|
||||
const CGAL::Point_3<GeomTraits>& q,
|
||||
const CGAL::Point_3<GeomTraits>& 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>
|
||||
typename Kernel::FT mixed_voronoi_area(const CGAL::Point_3<Kernel>& p,
|
||||
const CGAL::Point_3<Kernel>& q,
|
||||
const CGAL::Point_3<Kernel>& r)
|
||||
{
|
||||
const Kernel traits;
|
||||
return mixed_voronoi_area(p, q, r, traits);
|
||||
}
|
||||
|
||||
} // namespace Weights
|
||||
} // namespace CGAL
|
||||
|
|
|
|||
|
|
@ -14,251 +14,178 @@
|
|||
#ifndef CGAL_SHEPARD_WEIGHTS_H
|
||||
#define CGAL_SHEPARD_WEIGHTS_H
|
||||
|
||||
// Internal includes.
|
||||
#include <CGAL/Weights/internal/utils.h>
|
||||
|
||||
#include <CGAL/Point_2.h>
|
||||
#include <CGAL/Point_3.h>
|
||||
|
||||
namespace CGAL {
|
||||
namespace Weights {
|
||||
|
||||
/// \cond SKIP_IN_MANUAL
|
||||
namespace shepard_ns {
|
||||
/// \cond SKIP_IN_MANUAL
|
||||
|
||||
template<typename GeomTraits>
|
||||
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<typename FT>
|
||||
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>
|
||||
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>
|
||||
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>
|
||||
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<typename Kernel>
|
||||
#ifdef DOXYGEN_RUNNING
|
||||
typename Kernel::FT shepard_weight(const CGAL::Point_2<Kernel>&,
|
||||
const CGAL::Point_2<Kernel>& p^,
|
||||
const CGAL::Point_2<Kernel>&,
|
||||
const CGAL::Point_2<Kernel>& q,
|
||||
const typename Kernel::FT a = {1})
|
||||
#else
|
||||
typename Kernel::FT shepard_weight(const CGAL::Point_2<Kernel>& stub_l,
|
||||
const CGAL::Point_2<Kernel>& p,
|
||||
const CGAL::Point_2<Kernel>& stub_r,
|
||||
const CGAL::Point_2<Kernel>& 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>
|
||||
typename K::FT shepard_weight(
|
||||
const CGAL::Point_2<K>&,
|
||||
const CGAL::Point_2<K>& p,
|
||||
const CGAL::Point_2<K>&,
|
||||
const CGAL::Point_2<K>& 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>
|
||||
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>
|
||||
typename Kernel::FT shepard_weight(const CGAL::Point_2<Kernel>& p,
|
||||
const CGAL::Point_2<Kernel>& q,
|
||||
const typename Kernel::FT a = {1})
|
||||
{
|
||||
CGAL::Point_2<Kernel> 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>
|
||||
typename K::FT shepard_weight(
|
||||
const CGAL::Point_3<K>&,
|
||||
const CGAL::Point_3<K>& p,
|
||||
const CGAL::Point_3<K>&,
|
||||
const CGAL::Point_3<K>& 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>
|
||||
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>
|
||||
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<typename Kernel>
|
||||
#ifdef DOXYGEN_RUNNING
|
||||
typename Kernel::FT shepard_weight(const CGAL::Point_3<Kernel>& p,
|
||||
const CGAL::Point_3<Kernel>&,
|
||||
const CGAL::Point_3<Kernel>& q,
|
||||
const CGAL::Point_3<Kernel>&,
|
||||
const typename Kernel::FT a = {1})
|
||||
#else
|
||||
typename Kernel::FT shepard_weight(const CGAL::Point_3<Kernel>& stub_l,
|
||||
const CGAL::Point_3<Kernel>& p,
|
||||
const CGAL::Point_3<Kernel>& stub_r,
|
||||
const CGAL::Point_3<Kernel>& 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>
|
||||
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>
|
||||
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>
|
||||
typename K::FT shepard_weight(
|
||||
const CGAL::Point_2<K>& p,
|
||||
const CGAL::Point_2<K>& 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>
|
||||
typename K::FT shepard_weight(
|
||||
const CGAL::Point_3<K>& p,
|
||||
const CGAL::Point_3<K>& q,
|
||||
const typename K::FT a = typename K::FT(1)) { }
|
||||
|
||||
#endif // DOXYGEN_RUNNING
|
||||
|
||||
/// \cond SKIP_IN_MANUAL
|
||||
template<typename GeomTraits>
|
||||
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>
|
||||
typename GeomTraits::FT shepard_weight(
|
||||
const CGAL::Point_2<GeomTraits>& t,
|
||||
const CGAL::Point_2<GeomTraits>& r,
|
||||
const CGAL::Point_2<GeomTraits>& p,
|
||||
const CGAL::Point_2<GeomTraits>& 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>
|
||||
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>
|
||||
typename GeomTraits::FT shepard_weight(
|
||||
const CGAL::Point_2<GeomTraits>& p,
|
||||
const CGAL::Point_2<GeomTraits>& q,
|
||||
const typename GeomTraits::FT a =
|
||||
typename GeomTraits::FT(1)) {
|
||||
|
||||
CGAL::Point_2<GeomTraits> stub;
|
||||
return shepard_weight(stub, p, stub, q, a);
|
||||
}
|
||||
|
||||
template<typename GeomTraits>
|
||||
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>
|
||||
typename GeomTraits::FT shepard_weight(
|
||||
const CGAL::Point_3<GeomTraits>& t,
|
||||
const CGAL::Point_3<GeomTraits>& r,
|
||||
const CGAL::Point_3<GeomTraits>& p,
|
||||
const CGAL::Point_3<GeomTraits>& 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>
|
||||
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>
|
||||
typename GeomTraits::FT shepard_weight(
|
||||
const CGAL::Point_3<GeomTraits>& p,
|
||||
const CGAL::Point_3<GeomTraits>& q,
|
||||
const typename GeomTraits::FT a =
|
||||
typename GeomTraits::FT(1)) {
|
||||
|
||||
CGAL::Point_3<GeomTraits> 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>
|
||||
typename Kernel::FT shepard_weight(const CGAL::Point_3<Kernel>& p,
|
||||
const CGAL::Point_3<Kernel>& q,
|
||||
const typename Kernel::FT a = {1})
|
||||
{
|
||||
CGAL::Point_3<Kernel> stub;
|
||||
return shepard_weight(stub, p, stub, q, a);
|
||||
}
|
||||
|
||||
} // namespace Weights
|
||||
} // namespace CGAL
|
||||
|
|
|
|||
|
|
@ -14,495 +14,507 @@
|
|||
#ifndef CGAL_TANGENT_WEIGHTS_H
|
||||
#define CGAL_TANGENT_WEIGHTS_H
|
||||
|
||||
// Internal includes.
|
||||
#include <CGAL/Weights/internal/utils.h>
|
||||
#include <CGAL/Weights/utils.h>
|
||||
|
||||
#include <CGAL/Point_2.h>
|
||||
#include <CGAL/Point_3.h>
|
||||
|
||||
#include <cmath>
|
||||
|
||||
namespace CGAL {
|
||||
namespace Weights {
|
||||
|
||||
/// \cond SKIP_IN_MANUAL
|
||||
namespace tangent_ns {
|
||||
/// \cond SKIP_IN_MANUAL
|
||||
|
||||
template<typename FT>
|
||||
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<typename FT>
|
||||
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<typename FT>
|
||||
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<typename FT>
|
||||
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<typename FT>
|
||||
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<typename FT>
|
||||
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<typename FT>
|
||||
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>
|
||||
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>
|
||||
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<FT>(std::tan(ha_rad_1));
|
||||
const FT t2 = static_cast<FT>(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<typename FT>
|
||||
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>
|
||||
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<typename FT>
|
||||
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>
|
||||
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<FT>(std::tan(ha_rad_1));
|
||||
const FT t2 = static_cast<FT>(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<typename FT>
|
||||
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>
|
||||
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>
|
||||
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<typename FT>
|
||||
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>
|
||||
typename K::FT tangent_weight(
|
||||
const CGAL::Point_2<K>& p0,
|
||||
const CGAL::Point_2<K>& p1,
|
||||
const CGAL::Point_2<K>& p2,
|
||||
const CGAL::Point_2<K>& 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>
|
||||
typename K::FT tangent_weight(
|
||||
const CGAL::Point_3<K>& p0,
|
||||
const CGAL::Point_3<K>& p1,
|
||||
const CGAL::Point_3<K>& p2,
|
||||
const CGAL::Point_3<K>& 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>
|
||||
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<typename FT>
|
||||
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>
|
||||
typename GeomTraits::FT tangent_weight(
|
||||
const CGAL::Point_2<GeomTraits>& t,
|
||||
const CGAL::Point_2<GeomTraits>& r,
|
||||
const CGAL::Point_2<GeomTraits>& p,
|
||||
const CGAL::Point_2<GeomTraits>& 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>
|
||||
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>
|
||||
typename GeomTraits::FT tangent_weight(
|
||||
const CGAL::Point_3<GeomTraits>& t,
|
||||
const CGAL::Point_3<GeomTraits>& r,
|
||||
const CGAL::Point_3<GeomTraits>& p,
|
||||
const CGAL::Point_3<GeomTraits>& q) {
|
||||
\sa `tangent_weight()`
|
||||
*/
|
||||
template<typename FT>
|
||||
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<PolygonMesh, CGAL::vertex_point_t>::type>
|
||||
class Edge_tangent_weight {
|
||||
template<typename GeomTraits>
|
||||
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<VertexPointMap>::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<PolygonMesh>::vertex_descriptor;
|
||||
using halfedge_descriptor = typename boost::graph_traits<PolygonMesh>::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>
|
||||
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>
|
||||
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>
|
||||
typename Kernel::FT tangent_weight(const CGAL::Point_2<Kernel>& p0,
|
||||
const CGAL::Point_2<Kernel>& p1,
|
||||
const CGAL::Point_2<Kernel>& p2,
|
||||
const CGAL::Point_2<Kernel>& 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>
|
||||
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>
|
||||
typename Kernel::FT tangent_weight(const CGAL::Point_3<Kernel>& p0,
|
||||
const CGAL::Point_3<Kernel>& p1,
|
||||
const CGAL::Point_3<Kernel>& p2,
|
||||
const CGAL::Point_3<Kernel>& 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<PolygonMesh>::vertex_descriptor;
|
||||
using halfedge_descriptor = typename boost::graph_traits<PolygonMesh>::halfedge_descriptor;
|
||||
|
||||
using Point_ref = typename boost::property_traits<VertexPointMap>::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<typename FT>
|
||||
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<typename GeomTraits>
|
||||
Tangent_weight(
|
||||
const CGAL::Point_2<GeomTraits>& p,
|
||||
const CGAL::Point_2<GeomTraits>& q,
|
||||
const CGAL::Point_2<GeomTraits>& 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<typename GeomTraits>
|
||||
Tangent_weight(
|
||||
const CGAL::Point_3<GeomTraits>& p,
|
||||
const CGAL::Point_3<GeomTraits>& q,
|
||||
const CGAL::Point_3<GeomTraits>& 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<typename FT>
|
||||
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<typename Kernel>
|
||||
Tangent_weight(const CGAL::Point_2<Kernel>& p,
|
||||
const CGAL::Point_2<Kernel>& q,
|
||||
const CGAL::Point_2<Kernel>& 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<typename Kernel>
|
||||
Tangent_weight(const CGAL::Point_3<Kernel>& p,
|
||||
const CGAL::Point_3<Kernel>& q,
|
||||
const CGAL::Point_3<Kernel>& 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
|
||||
|
|
|
|||
|
|
@ -14,155 +14,122 @@
|
|||
#ifndef CGAL_THREE_POINT_FAMILY_WEIGHTS_H
|
||||
#define CGAL_THREE_POINT_FAMILY_WEIGHTS_H
|
||||
|
||||
// Internal includes.
|
||||
#include <CGAL/Weights/internal/utils.h>
|
||||
|
||||
#include <CGAL/Point_2.h>
|
||||
#include <CGAL/Point_3.h>
|
||||
|
||||
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>
|
||||
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<typename FT>
|
||||
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>
|
||||
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>
|
||||
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>
|
||||
typename K::FT three_point_family_weight(
|
||||
const CGAL::Point_2<K>& p0,
|
||||
const CGAL::Point_2<K>& p1,
|
||||
const CGAL::Point_2<K>& p2,
|
||||
const CGAL::Point_2<K>& 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>
|
||||
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>
|
||||
typename Kernel::FT three_point_family_weight(const CGAL::Point_2<Kernel>& p0,
|
||||
const CGAL::Point_2<Kernel>& p1,
|
||||
const CGAL::Point_2<Kernel>& p2,
|
||||
const CGAL::Point_2<Kernel>& 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>
|
||||
typename GeomTraits::FT three_point_family_weight(
|
||||
const CGAL::Point_2<GeomTraits>& t,
|
||||
const CGAL::Point_2<GeomTraits>& r,
|
||||
const CGAL::Point_2<GeomTraits>& p,
|
||||
const CGAL::Point_2<GeomTraits>& 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>
|
||||
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>
|
||||
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>
|
||||
typename Kernel::FT three_point_family_weight(const CGAL::Point_3<Kernel>& p0,
|
||||
const CGAL::Point_3<Kernel>& p1,
|
||||
const CGAL::Point_3<Kernel>& p2,
|
||||
const CGAL::Point_3<Kernel>& q,
|
||||
const typename Kernel::FT a = {1})
|
||||
{
|
||||
const Kernel traits;
|
||||
return three_point_family_weight(p0, p1, p2, q, a, traits);
|
||||
}
|
||||
|
||||
template<typename GeomTraits>
|
||||
typename GeomTraits::FT three_point_family_weight(
|
||||
const CGAL::Point_3<GeomTraits>& t,
|
||||
const CGAL::Point_3<GeomTraits>& r,
|
||||
const CGAL::Point_3<GeomTraits>& p,
|
||||
const CGAL::Point_3<GeomTraits>& 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
|
||||
|
|
|
|||
|
|
@ -14,107 +14,73 @@
|
|||
#ifndef CGAL_TRIANGULAR_REGION_WEIGHTS_H
|
||||
#define CGAL_TRIANGULAR_REGION_WEIGHTS_H
|
||||
|
||||
// Internal includes.
|
||||
#include <CGAL/Weights/internal/utils.h>
|
||||
|
||||
#include <CGAL/Point_2.h>
|
||||
#include <CGAL/Point_3.h>
|
||||
|
||||
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>
|
||||
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>
|
||||
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>
|
||||
typename Kernel::FT triangular_area(const CGAL::Point_2<Kernel>& p,
|
||||
const CGAL::Point_2<Kernel>& q,
|
||||
const CGAL::Point_2<Kernel>& 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>
|
||||
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>
|
||||
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>
|
||||
typename K::FT triangular_area(
|
||||
const CGAL::Point_2<K>& p,
|
||||
const CGAL::Point_2<K>& q,
|
||||
const CGAL::Point_2<K>& 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>
|
||||
typename K::FT triangular_area(
|
||||
const CGAL::Point_3<K>& p,
|
||||
const CGAL::Point_3<K>& q,
|
||||
const CGAL::Point_3<K>& r) { }
|
||||
|
||||
#endif // DOXYGEN_RUNNING
|
||||
|
||||
/// \cond SKIP_IN_MANUAL
|
||||
template<typename GeomTraits>
|
||||
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>
|
||||
typename GeomTraits::FT triangular_area(
|
||||
const CGAL::Point_2<GeomTraits>& p,
|
||||
const CGAL::Point_2<GeomTraits>& q,
|
||||
const CGAL::Point_2<GeomTraits>& r) {
|
||||
|
||||
const GeomTraits traits;
|
||||
return triangular_area(p, q, r, traits);
|
||||
}
|
||||
|
||||
template<typename GeomTraits>
|
||||
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>
|
||||
typename GeomTraits::FT triangular_area(
|
||||
const CGAL::Point_3<GeomTraits>& p,
|
||||
const CGAL::Point_3<GeomTraits>& q,
|
||||
const CGAL::Point_3<GeomTraits>& 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>
|
||||
typename Kernel::FT triangular_area(const CGAL::Point_3<Kernel>& p,
|
||||
const CGAL::Point_3<Kernel>& q,
|
||||
const CGAL::Point_3<Kernel>& r)
|
||||
{
|
||||
const Kernel traits;
|
||||
return triangular_area(p, q, r, traits);
|
||||
}
|
||||
|
||||
} // namespace Weights
|
||||
} // namespace CGAL
|
||||
|
|
|
|||
|
|
@ -14,109 +14,73 @@
|
|||
#ifndef CGAL_UNIFORM_REGION_WEIGHTS_H
|
||||
#define CGAL_UNIFORM_REGION_WEIGHTS_H
|
||||
|
||||
// Internal includes.
|
||||
#include <CGAL/Weights/internal/utils.h>
|
||||
#include <CGAL/Point_2.h>
|
||||
#include <CGAL/Point_3.h>
|
||||
|
||||
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>
|
||||
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>
|
||||
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>
|
||||
typename Kernel::FT uniform_area(const CGAL::Point_2<Kernel>& p,
|
||||
const CGAL::Point_2<Kernel>& q,
|
||||
const CGAL::Point_2<Kernel>& 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>
|
||||
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>
|
||||
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>
|
||||
typename K::FT uniform_area(
|
||||
const CGAL::Point_2<K>&,
|
||||
const CGAL::Point_2<K>&,
|
||||
const CGAL::Point_2<K>&) { }
|
||||
|
||||
/*!
|
||||
\ingroup PkgWeightsRefUniformRegionWeights
|
||||
|
||||
\brief this function always returns 1, given three points in 3D which are
|
||||
parameterized by a `Kernel` K.
|
||||
*/
|
||||
template<typename K>
|
||||
typename K::FT uniform_area(
|
||||
const CGAL::Point_3<K>&,
|
||||
const CGAL::Point_3<K>&,
|
||||
const CGAL::Point_3<K>&) { }
|
||||
|
||||
#endif // DOXYGEN_RUNNING
|
||||
|
||||
/// \cond SKIP_IN_MANUAL
|
||||
template<typename GeomTraits>
|
||||
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>
|
||||
typename GeomTraits::FT uniform_area(
|
||||
const CGAL::Point_2<GeomTraits>& p,
|
||||
const CGAL::Point_2<GeomTraits>& q,
|
||||
const CGAL::Point_2<GeomTraits>& r) {
|
||||
|
||||
const GeomTraits traits;
|
||||
return uniform_area(p, q, r, traits);
|
||||
}
|
||||
|
||||
template<typename GeomTraits>
|
||||
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>
|
||||
typename GeomTraits::FT uniform_area(
|
||||
const CGAL::Point_3<GeomTraits>& p,
|
||||
const CGAL::Point_3<GeomTraits>& q,
|
||||
const CGAL::Point_3<GeomTraits>& 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>
|
||||
typename Kernel::FT uniform_area(const CGAL::Point_3<Kernel>& p,
|
||||
const CGAL::Point_3<Kernel>& q,
|
||||
const CGAL::Point_3<Kernel>& r)
|
||||
{
|
||||
const Kernel traits;
|
||||
return uniform_area(p, q, r, traits);
|
||||
}
|
||||
|
||||
} // namespace Weights
|
||||
} // namespace CGAL
|
||||
|
|
|
|||
|
|
@ -14,134 +14,98 @@
|
|||
#ifndef CGAL_UNIFORM_WEIGHTS_H
|
||||
#define CGAL_UNIFORM_WEIGHTS_H
|
||||
|
||||
// Internal includes.
|
||||
#include <CGAL/Weights/internal/utils.h>
|
||||
#include <CGAL/Point_2.h>
|
||||
#include <CGAL/Point_3.h>
|
||||
|
||||
#include <boost/graph/graph_traits.hpp>
|
||||
|
||||
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>
|
||||
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>
|
||||
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>
|
||||
typename GeomTraits::FT uniform_weight(const CGAL::Point_2<GeomTraits>& p0,
|
||||
const CGAL::Point_2<GeomTraits>& p1,
|
||||
const CGAL::Point_2<GeomTraits>& p2,
|
||||
const CGAL::Point_2<GeomTraits>& 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>
|
||||
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>
|
||||
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>
|
||||
typename GeomTraits::FT uniform_weight(const CGAL::Point_3<GeomTraits>& p0,
|
||||
const CGAL::Point_3<GeomTraits>& p1,
|
||||
const CGAL::Point_3<GeomTraits>& p2,
|
||||
const CGAL::Point_3<GeomTraits>& 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>
|
||||
typename K::FT uniform_weight(
|
||||
const CGAL::Point_2<K>&,
|
||||
const CGAL::Point_2<K>&,
|
||||
const CGAL::Point_2<K>&,
|
||||
const CGAL::Point_2<K>&) { }
|
||||
/// \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 PolygonMesh>
|
||||
class Uniform_weight
|
||||
{
|
||||
public:
|
||||
using vertex_descriptor = typename boost::graph_traits<PolygonMesh>::vertex_descriptor;
|
||||
using halfedge_descriptor = typename boost::graph_traits<PolygonMesh>::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>
|
||||
typename K::FT uniform_weight(
|
||||
const CGAL::Point_3<K>&,
|
||||
const CGAL::Point_3<K>&,
|
||||
const CGAL::Point_3<K>&,
|
||||
const CGAL::Point_3<K>&) { }
|
||||
|
||||
#endif // DOXYGEN_RUNNING
|
||||
|
||||
/// \cond SKIP_IN_MANUAL
|
||||
template<typename GeomTraits>
|
||||
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>
|
||||
typename GeomTraits::FT uniform_weight(
|
||||
const CGAL::Point_2<GeomTraits>& q,
|
||||
const CGAL::Point_2<GeomTraits>& t,
|
||||
const CGAL::Point_2<GeomTraits>& r,
|
||||
const CGAL::Point_2<GeomTraits>& p) {
|
||||
|
||||
const GeomTraits traits;
|
||||
return uniform_weight(q, t, r, p, traits);
|
||||
}
|
||||
|
||||
template<typename GeomTraits>
|
||||
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>
|
||||
typename GeomTraits::FT uniform_weight(
|
||||
const CGAL::Point_3<GeomTraits>& q,
|
||||
const CGAL::Point_3<GeomTraits>& t,
|
||||
const CGAL::Point_3<GeomTraits>& r,
|
||||
const CGAL::Point_3<GeomTraits>& 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 PolygonMesh>
|
||||
class Uniform_weight {
|
||||
|
||||
public:
|
||||
using vertex_descriptor = typename boost::graph_traits<PolygonMesh>::vertex_descriptor;
|
||||
using halfedge_descriptor = typename boost::graph_traits<PolygonMesh>::halfedge_descriptor;
|
||||
double w_i(vertex_descriptor) { return 1; }
|
||||
double w_ij(halfedge_descriptor) { return 1; }
|
||||
};
|
||||
|
||||
/// \endcond
|
||||
/// \endcond
|
||||
|
||||
} // namespace Weights
|
||||
} // namespace CGAL
|
||||
|
|
|
|||
|
|
@ -14,193 +14,242 @@
|
|||
#ifndef CGAL_WEIGHTS_UTILS_H
|
||||
#define CGAL_WEIGHTS_UTILS_H
|
||||
|
||||
// Internal includes.
|
||||
#include <CGAL/Weights/internal/utils.h>
|
||||
|
||||
#include <boost/algorithm/clamp.hpp>
|
||||
|
||||
namespace CGAL {
|
||||
namespace Weights {
|
||||
|
||||
/// \cond SKIP_IN_MANUAL
|
||||
template<typename GeomTraits>
|
||||
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>
|
||||
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>
|
||||
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>
|
||||
typename Kernel::FT cotangent(const CGAL::Point_2<Kernel>& p,
|
||||
const CGAL::Point_2<Kernel>& q,
|
||||
const CGAL::Point_2<Kernel>& r)
|
||||
{
|
||||
const Kernel traits;
|
||||
return cotangent(p, q, r, traits);
|
||||
}
|
||||
|
||||
// =================================================================================================
|
||||
|
||||
// Computes cotangent between two 3D vectors.
|
||||
template<typename GeomTraits>
|
||||
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>
|
||||
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>
|
||||
typename Kernel::FT cotangent(const CGAL::Point_3<Kernel>& p,
|
||||
const CGAL::Point_3<Kernel>& q,
|
||||
const CGAL::Point_3<Kernel>& r)
|
||||
{
|
||||
const Kernel traits;
|
||||
return cotangent(p, q, r, traits);
|
||||
}
|
||||
|
||||
// =================================================================================================
|
||||
|
||||
// Computes tangent between two 2D vectors.
|
||||
template<typename GeomTraits>
|
||||
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>
|
||||
typename GeomTraits::FT tangent(
|
||||
const CGAL::Point_2<GeomTraits>& p,
|
||||
const CGAL::Point_2<GeomTraits>& q,
|
||||
const CGAL::Point_2<GeomTraits>& r) {
|
||||
return FT(0); // undefined
|
||||
}
|
||||
|
||||
const GeomTraits traits;
|
||||
return tangent(p, q, r, traits);
|
||||
template<typename GeomTraits>
|
||||
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>
|
||||
typename Kernel::FT tangent(const CGAL::Point_2<Kernel>& p,
|
||||
const CGAL::Point_2<Kernel>& q,
|
||||
const CGAL::Point_2<Kernel>& r)
|
||||
{
|
||||
const Kernel traits;
|
||||
return tangent(p, q, r, traits);
|
||||
}
|
||||
|
||||
// =================================================================================================
|
||||
|
||||
// Computes tangent between two 3D vectors.
|
||||
template<typename GeomTraits>
|
||||
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>
|
||||
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>
|
||||
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>
|
||||
typename GeomTraits::FT tangent(
|
||||
const CGAL::Point_3<GeomTraits>& p,
|
||||
const CGAL::Point_3<GeomTraits>& q,
|
||||
const CGAL::Point_3<GeomTraits>& r) {
|
||||
template<typename Kernel>
|
||||
typename Kernel::FT tangent(const CGAL::Point_3<Kernel>& p,
|
||||
const CGAL::Point_3<Kernel>& q,
|
||||
const CGAL::Point_3<Kernel>& r)
|
||||
{
|
||||
const Kernel traits;
|
||||
return tangent(p, q, r, traits);
|
||||
}
|
||||
|
||||
const GeomTraits traits;
|
||||
return tangent(p, q, r, traits);
|
||||
}
|
||||
// =================================================================================================
|
||||
|
||||
template<typename GeomTraits>
|
||||
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>
|
||||
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<GeomTraits>;
|
||||
auto sqrt = Get_sqrt::sqrt_object(traits);
|
||||
|
||||
template<typename GeomTraits>
|
||||
typename GeomTraits::FT cotangent(
|
||||
const CGAL::Point_2<GeomTraits>& p,
|
||||
const CGAL::Point_2<GeomTraits>& q,
|
||||
const CGAL::Point_2<GeomTraits>& 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>
|
||||
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<FT>(dot / (length_v1 * length_v2), lb, ub);
|
||||
const FT sine = sqrt(FT(1) - square(cosine));
|
||||
|
||||
template<typename GeomTraits>
|
||||
typename GeomTraits::FT cotangent(
|
||||
const CGAL::Point_3<GeomTraits>& p,
|
||||
const CGAL::Point_3<GeomTraits>& q,
|
||||
const CGAL::Point_3<GeomTraits>& 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>
|
||||
typename GeomTraits::FT squared_distance(
|
||||
const CGAL::Point_2<GeomTraits>& p,
|
||||
const CGAL::Point_2<GeomTraits>& q) {
|
||||
|
||||
const GeomTraits traits;
|
||||
const auto squared_distance_2 =
|
||||
traits.compute_squared_distance_2_object();
|
||||
return squared_distance_2(p, q);
|
||||
}
|
||||
|
||||
template<typename GeomTraits>
|
||||
typename GeomTraits::FT squared_distance(
|
||||
const CGAL::Point_3<GeomTraits>& p,
|
||||
const CGAL::Point_3<GeomTraits>& q) {
|
||||
|
||||
const GeomTraits traits;
|
||||
const auto squared_distance_3 =
|
||||
traits.compute_squared_distance_3_object();
|
||||
return squared_distance_3(p, q);
|
||||
}
|
||||
|
||||
template<typename GeomTraits>
|
||||
typename GeomTraits::FT distance(
|
||||
const CGAL::Point_2<GeomTraits>& p,
|
||||
const CGAL::Point_2<GeomTraits>& q) {
|
||||
|
||||
const GeomTraits traits;
|
||||
return internal::distance_2(traits, p, q);
|
||||
}
|
||||
|
||||
template<typename GeomTraits>
|
||||
typename GeomTraits::FT distance(
|
||||
const CGAL::Point_3<GeomTraits>& p,
|
||||
const CGAL::Point_3<GeomTraits>& q) {
|
||||
|
||||
const GeomTraits traits;
|
||||
return internal::distance_3(traits, p, q);
|
||||
}
|
||||
|
||||
template<typename GeomTraits>
|
||||
typename GeomTraits::FT area(
|
||||
const CGAL::Point_2<GeomTraits>& p,
|
||||
const CGAL::Point_2<GeomTraits>& q,
|
||||
const CGAL::Point_2<GeomTraits>& r) {
|
||||
|
||||
const GeomTraits traits;
|
||||
return internal::area_2(traits, p, q, r);
|
||||
}
|
||||
|
||||
template<typename GeomTraits>
|
||||
typename GeomTraits::FT area(
|
||||
const CGAL::Point_3<GeomTraits>& p,
|
||||
const CGAL::Point_3<GeomTraits>& q,
|
||||
const CGAL::Point_3<GeomTraits>& r) {
|
||||
|
||||
const GeomTraits traits;
|
||||
return internal::positive_area_3(traits, p, q, r);
|
||||
}
|
||||
|
||||
template<typename GeomTraits>
|
||||
typename GeomTraits::FT scalar_product(
|
||||
const CGAL::Point_2<GeomTraits>& p,
|
||||
const CGAL::Point_2<GeomTraits>& q,
|
||||
const CGAL::Point_2<GeomTraits>& 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>
|
||||
typename GeomTraits::FT scalar_product(
|
||||
const CGAL::Point_3<GeomTraits>& p,
|
||||
const CGAL::Point_3<GeomTraits>& q,
|
||||
const CGAL::Point_3<GeomTraits>& 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
|
||||
|
|
|
|||
|
|
@ -14,131 +14,99 @@
|
|||
#ifndef CGAL_VORONOI_REGION_WEIGHTS_H
|
||||
#define CGAL_VORONOI_REGION_WEIGHTS_H
|
||||
|
||||
// Internal includes.
|
||||
#include <CGAL/Weights/internal/utils.h>
|
||||
|
||||
#include <CGAL/Point_2.h>
|
||||
#include <CGAL/Point_3.h>
|
||||
|
||||
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>
|
||||
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>
|
||||
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>
|
||||
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>
|
||||
typename K::FT voronoi_area(
|
||||
const CGAL::Point_2<K>& p,
|
||||
const CGAL::Point_2<K>& q,
|
||||
const CGAL::Point_2<K>& 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>
|
||||
typename Kernel::FT voronoi_area(const CGAL::Point_2<Kernel>& p,
|
||||
const CGAL::Point_2<Kernel>& q,
|
||||
const CGAL::Point_2<Kernel>& 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>
|
||||
typename K::FT voronoi_area(
|
||||
const CGAL::Point_3<K>& p,
|
||||
const CGAL::Point_3<K>& q,
|
||||
const CGAL::Point_3<K>& 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>
|
||||
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>
|
||||
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>
|
||||
typename GeomTraits::FT voronoi_area(
|
||||
const CGAL::Point_2<GeomTraits>& p,
|
||||
const CGAL::Point_2<GeomTraits>& q,
|
||||
const CGAL::Point_2<GeomTraits>& r) {
|
||||
|
||||
const GeomTraits traits;
|
||||
return voronoi_area(p, q, r, traits);
|
||||
}
|
||||
|
||||
template<typename GeomTraits>
|
||||
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>
|
||||
typename GeomTraits::FT voronoi_area(
|
||||
const CGAL::Point_3<GeomTraits>& p,
|
||||
const CGAL::Point_3<GeomTraits>& q,
|
||||
const CGAL::Point_3<GeomTraits>& 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>
|
||||
typename Kernel::FT voronoi_area(const CGAL::Point_3<Kernel>& p,
|
||||
const CGAL::Point_3<Kernel>& q,
|
||||
const CGAL::Point_3<Kernel>& r)
|
||||
{
|
||||
const Kernel traits;
|
||||
return voronoi_area(p, q, r, traits);
|
||||
}
|
||||
|
||||
} // namespace Weights
|
||||
} // namespace CGAL
|
||||
|
|
|
|||
|
|
@ -14,409 +14,373 @@
|
|||
#ifndef CGAL_WACHSPRESS_WEIGHTS_H
|
||||
#define CGAL_WACHSPRESS_WEIGHTS_H
|
||||
|
||||
// Internal includes.
|
||||
#include <CGAL/Weights/internal/utils.h>
|
||||
#include <CGAL/Weights/internal/polygon_utils_2.h>
|
||||
|
||||
#include <CGAL/Point_2.h>
|
||||
#include <CGAL/Point_3.h>
|
||||
#include <CGAL/property_map.h>
|
||||
|
||||
#include <vector>
|
||||
|
||||
namespace CGAL {
|
||||
namespace Weights {
|
||||
|
||||
/// \cond SKIP_IN_MANUAL
|
||||
namespace wachspress_ns {
|
||||
/// \cond SKIP_IN_MANUAL
|
||||
|
||||
template<typename FT>
|
||||
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<typename FT>
|
||||
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>
|
||||
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>
|
||||
typename K::FT wachspress_weight(
|
||||
const CGAL::Point_2<K>& p0,
|
||||
const CGAL::Point_2<K>& p1,
|
||||
const CGAL::Point_2<K>& p2,
|
||||
const CGAL::Point_2<K>& 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>
|
||||
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>
|
||||
typename Kernel::FT wachspress_weight(const CGAL::Point_2<Kernel>& p0,
|
||||
const CGAL::Point_2<Kernel>& p1,
|
||||
const CGAL::Point_2<Kernel>& p2,
|
||||
const CGAL::Point_2<Kernel>& q)
|
||||
{
|
||||
const Kernel traits;
|
||||
return wachspress_weight(p0, p1, p2, q, traits);
|
||||
}
|
||||
|
||||
// 3D ==============================================================================================
|
||||
|
||||
/// \cond SKIP_IN_MANUAL
|
||||
|
||||
template<typename GeomTraits>
|
||||
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>
|
||||
typename Kernel::FT wachspress_weight(const CGAL::Point_3<Kernel>& p0,
|
||||
const CGAL::Point_3<Kernel>& p1,
|
||||
const CGAL::Point_3<Kernel>& p2,
|
||||
const CGAL::Point_3<Kernel>& 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<typename VertexRange,
|
||||
typename GeomTraits,
|
||||
typename PointMap = CGAL::Identity_property_map<typename GeomTraits::Point_2> >
|
||||
class Wachspress_weights_2
|
||||
{
|
||||
public:
|
||||
|
||||
/// \name Types
|
||||
/// @{
|
||||
|
||||
/// \cond SKIP_IN_MANUAL
|
||||
template<typename GeomTraits>
|
||||
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>
|
||||
typename GeomTraits::FT wachspress_weight(
|
||||
const CGAL::Point_2<GeomTraits>& t,
|
||||
const CGAL::Point_2<GeomTraits>& r,
|
||||
const CGAL::Point_2<GeomTraits>& p,
|
||||
const CGAL::Point_2<GeomTraits>& q) {
|
||||
|
||||
const GeomTraits traits;
|
||||
return wachspress_weight(t, r, p, q, traits);
|
||||
}
|
||||
|
||||
namespace internal {
|
||||
|
||||
template<typename GeomTraits>
|
||||
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>
|
||||
typename GeomTraits::FT wachspress_weight(
|
||||
const CGAL::Point_3<GeomTraits>& t,
|
||||
const CGAL::Point_3<GeomTraits>& r,
|
||||
const CGAL::Point_3<GeomTraits>& p,
|
||||
const CGAL::Point_3<GeomTraits>& 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<typename GeomTraits::Point_2> >
|
||||
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<typename OutIterator>
|
||||
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 OutIterator>
|
||||
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<FT> A;
|
||||
std::vector<FT> C;
|
||||
std::vector<FT> w;
|
||||
|
||||
// Functions.
|
||||
void resize() {
|
||||
A.resize(m_polygon.size());
|
||||
C.resize(m_polygon.size());
|
||||
w.resize(m_polygon.size());
|
||||
}
|
||||
|
||||
template<typename OutputIterator>
|
||||
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<PointRange, GeomTraits>
|
||||
wachspress(polygon, traits);
|
||||
return wachspress(query, w_begin);
|
||||
template<typename OutIterator>
|
||||
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<Point_2>::Kernel;
|
||||
const GeomTraits traits;
|
||||
return wachspress_weights_2(
|
||||
polygon, query, w_begin, traits);
|
||||
template<typename OutIterator>
|
||||
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<FT> A;
|
||||
std::vector<FT> C;
|
||||
std::vector<FT> w;
|
||||
|
||||
void resize()
|
||||
{
|
||||
A.resize(m_polygon.size());
|
||||
C.resize(m_polygon.size());
|
||||
w.resize(m_polygon.size());
|
||||
}
|
||||
|
||||
template<typename OutputIterator>
|
||||
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<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<PointRange, GeomTraits> wachspress(polygon, traits);
|
||||
return wachspress(query, w_begin);
|
||||
}
|
||||
|
||||
/// \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<Point_2>::Kernel;
|
||||
|
||||
const GeomTraits traits;
|
||||
return wachspress_weights_2(polygon, query, w_begin, traits);
|
||||
}
|
||||
|
||||
/// \endcond
|
||||
|
||||
} // namespace Weights
|
||||
} // namespace CGAL
|
||||
|
||||
|
|
|
|||
|
|
@ -1,113 +1,177 @@
|
|||
#ifndef CGAL_WEIGHTS_TESTS_UTILS_H
|
||||
#define CGAL_WEIGHTS_TESTS_UTILS_H
|
||||
|
||||
// STL includes.
|
||||
#include <CGAL/Weights/utils.h>
|
||||
|
||||
#include <CGAL/assertions.h>
|
||||
#include <CGAL/Projection_traits_xy_3.h>
|
||||
|
||||
#include <array>
|
||||
#include <vector>
|
||||
#include <cassert>
|
||||
#include <algorithm>
|
||||
#include <string>
|
||||
|
||||
// CGAL includes.
|
||||
#include <CGAL/assertions.h>
|
||||
#include <CGAL/Projection_traits_xy_3.h>
|
||||
#include <CGAL/Weights/utils.h>
|
||||
namespace CGAL {
|
||||
namespace Weights {
|
||||
namespace internal {
|
||||
|
||||
template<typename Kernel>
|
||||
typename Kernel::FT squared_distance(const CGAL::Point_2<Kernel>& p,
|
||||
const CGAL::Point_2<Kernel>& q)
|
||||
{
|
||||
const Kernel traits;
|
||||
auto squared_distance_2 = traits.compute_squared_distance_2_object();
|
||||
return squared_distance_2(p, q);
|
||||
}
|
||||
|
||||
template<typename Kernel>
|
||||
typename Kernel::FT squared_distance(const CGAL::Point_3<Kernel>& p,
|
||||
const CGAL::Point_3<Kernel>& q)
|
||||
{
|
||||
const Kernel traits;
|
||||
auto squared_distance_3 = traits.compute_squared_distance_3_object();
|
||||
return squared_distance_3(p, q);
|
||||
}
|
||||
|
||||
template<typename Kernel>
|
||||
typename Kernel::FT distance(const CGAL::Point_2<Kernel>& p,
|
||||
const CGAL::Point_2<Kernel>& q)
|
||||
{
|
||||
const Kernel traits;
|
||||
return CGAL::Weights::internal::distance_2(p, q, traits);
|
||||
}
|
||||
|
||||
template<typename Kernel>
|
||||
typename Kernel::FT distance(const CGAL::Point_3<Kernel>& p,
|
||||
const CGAL::Point_3<Kernel>& q)
|
||||
{
|
||||
const Kernel traits;
|
||||
return CGAL::Weights::internal::distance_3(p, q, traits);
|
||||
}
|
||||
|
||||
template<typename Kernel>
|
||||
typename Kernel::FT area(const CGAL::Point_2<Kernel>& p,
|
||||
const CGAL::Point_2<Kernel>& q,
|
||||
const CGAL::Point_2<Kernel>& r)
|
||||
{
|
||||
const Kernel traits;
|
||||
return CGAL::Weights::internal::positive_area_2(p, q, r, traits);
|
||||
}
|
||||
|
||||
template<typename Kernel>
|
||||
typename Kernel::FT area(const CGAL::Point_3<Kernel>& p,
|
||||
const CGAL::Point_3<Kernel>& q,
|
||||
const CGAL::Point_3<Kernel>& r)
|
||||
{
|
||||
const Kernel traits;
|
||||
return CGAL::Weights::internal::positive_area_3(p, q, r, traits);
|
||||
}
|
||||
|
||||
template<typename Kernel>
|
||||
typename Kernel::FT scalar_product(const CGAL::Point_2<Kernel>& p,
|
||||
const CGAL::Point_2<Kernel>& q,
|
||||
const CGAL::Point_2<Kernel>& 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>
|
||||
typename Kernel::FT scalar_product(const CGAL::Point_3<Kernel>& p,
|
||||
const CGAL::Point_3<Kernel>& q,
|
||||
const CGAL::Point_3<Kernel>& 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<typename FT>
|
||||
FT get_tolerance() {
|
||||
return FT(1) / FT(10000000000);
|
||||
}
|
||||
FT get_tolerance() { return FT(1e-10); }
|
||||
|
||||
template<typename Kernel>
|
||||
std::vector< std::array<typename Kernel::Point_2, 3> >
|
||||
get_all_triangles() {
|
||||
|
||||
get_all_triangles()
|
||||
{
|
||||
using Point_2 = typename Kernel::Point_2;
|
||||
const std::array<Point_2, 3> triangle0 = {
|
||||
Point_2(-1, 0), Point_2(0, -1), Point_2(1, 0)
|
||||
};
|
||||
const std::array<Point_2, 3> triangle1 = {
|
||||
Point_2(-2, 0), Point_2(0, -1), Point_2(2, 0)
|
||||
};
|
||||
const std::array<Point_2, 3> triangle2 = {
|
||||
Point_2(-2, 0), Point_2(-2, -2), Point_2(2, 0)
|
||||
};
|
||||
const std::array<Point_2, 3> triangle3 = {
|
||||
Point_2(-2, 0), Point_2(2, -2), Point_2(2, 0)
|
||||
};
|
||||
|
||||
const std::array<Point_2, 3> triangle0 = { Point_2(-1, 0), Point_2(0, -1), Point_2(1, 0) };
|
||||
const std::array<Point_2, 3> triangle1 = { Point_2(-2, 0), Point_2(0, -1), Point_2(2, 0) };
|
||||
const std::array<Point_2, 3> triangle2 = { Point_2(-2, 0), Point_2(-2, -2), Point_2(2, 0) };
|
||||
const std::array<Point_2, 3> triangle3 = { Point_2(-2, 0), Point_2(2, -2), Point_2(2, 0) };
|
||||
|
||||
return { triangle0, triangle1, triangle2, triangle3 };
|
||||
}
|
||||
|
||||
template<typename Kernel>
|
||||
std::vector< std::array<typename Kernel::Point_2, 3> >
|
||||
get_symmetric_triangles() {
|
||||
|
||||
get_symmetric_triangles()
|
||||
{
|
||||
using Point_2 = typename Kernel::Point_2;
|
||||
const std::array<Point_2, 3> triangle0 = {
|
||||
Point_2(-1, 0), Point_2(0, -1), Point_2(1, 0)
|
||||
};
|
||||
const std::array<Point_2, 3> triangle1 = {
|
||||
Point_2(-2, 0), Point_2(0, -1), Point_2(2, 0)
|
||||
};
|
||||
const std::array<Point_2, 3> triangle2 = {
|
||||
Point_2(-3, 0), Point_2(0, -1), Point_2(3, 0)
|
||||
};
|
||||
|
||||
const std::array<Point_2, 3> triangle0 = { Point_2(-1, 0), Point_2(0, -1), Point_2(1, 0) };
|
||||
const std::array<Point_2, 3> triangle1 = { Point_2(-2, 0), Point_2(0, -1), Point_2(2, 0) };
|
||||
const std::array<Point_2, 3> triangle2 = { Point_2(-3, 0), Point_2(0, -1), Point_2(3, 0) };
|
||||
|
||||
return { triangle0, triangle1, triangle2 };
|
||||
}
|
||||
|
||||
template<typename Kernel>
|
||||
std::vector< std::array<typename Kernel::Point_2, 3> >
|
||||
get_uniform_triangles() {
|
||||
|
||||
get_uniform_triangles()
|
||||
{
|
||||
using Point_2 = typename Kernel::Point_2;
|
||||
const std::array<Point_2, 3> triangle0 = {
|
||||
Point_2(-1, 0), Point_2(0, -1), Point_2(1, 0)
|
||||
};
|
||||
const std::array<Point_2, 3> triangle1 = {
|
||||
Point_2(-2, 0), Point_2(0, -2), Point_2(2, 0)
|
||||
};
|
||||
const std::array<Point_2, 3> triangle2 = {
|
||||
Point_2(1, 0), Point_2(-1, 0), Point_2(-1, -2)
|
||||
};
|
||||
const std::array<Point_2, 3> triangle3 = {
|
||||
Point_2(1, -2), Point_2(1, 0), Point_2(-1, 0)
|
||||
};
|
||||
|
||||
const std::array<Point_2, 3> triangle0 = { Point_2(-1, 0), Point_2(0, -1), Point_2(1, 0) };
|
||||
const std::array<Point_2, 3> triangle1 = { Point_2(-2, 0), Point_2(0, -2), Point_2(2, 0) };
|
||||
const std::array<Point_2, 3> triangle2 = { Point_2(1, 0), Point_2(-1, 0), Point_2(-1, -2) };
|
||||
const std::array<Point_2, 3> triangle3 = { Point_2(1, -2), Point_2(1, 0), Point_2(-1, 0) };
|
||||
|
||||
return { triangle0, triangle1, triangle2, triangle3 };
|
||||
}
|
||||
|
||||
template<typename Kernel>
|
||||
std::vector< std::vector<typename Kernel::Point_2> >
|
||||
get_all_polygons() {
|
||||
|
||||
get_all_polygons()
|
||||
{
|
||||
using Point_2 = typename Kernel::Point_2;
|
||||
const std::vector<Point_2> polygon0 = {
|
||||
Point_2(-2, -2), Point_2(2, -2), Point_2(0, 2)
|
||||
};
|
||||
const std::vector<Point_2> polygon1 = {
|
||||
Point_2(-1, -1), Point_2(1, -1), Point_2(1, 1), Point_2(-1, 1)
|
||||
};
|
||||
const std::vector<Point_2> polygon2 = {
|
||||
Point_2(-2, 0), Point_2(0, -2), Point_2(2, 0), Point_2(0, 2)
|
||||
};
|
||||
const std::vector<Point_2> polygon3 = {
|
||||
Point_2(-2, -2), Point_2(2, -2), Point_2(2, 0), Point_2(0, 2), Point_2(-2, 0)
|
||||
};
|
||||
|
||||
const std::vector<Point_2> polygon0 = { Point_2(-2, -2), Point_2(2, -2), Point_2(0, 2) };
|
||||
const std::vector<Point_2> polygon1 = { Point_2(-1, -1), Point_2(1, -1), Point_2(1, 1), Point_2(-1, 1) };
|
||||
const std::vector<Point_2> polygon2 = { Point_2(-2, 0), Point_2(0, -2), Point_2(2, 0), Point_2(0, 2) };
|
||||
const std::vector<Point_2> 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<typename Kernel::Point_2, 3>& neighbors) {
|
||||
|
||||
template<typename Kernel,
|
||||
typename Weight_wrapper>
|
||||
void test_query(const Weight_wrapper& wrapper,
|
||||
const typename Kernel::Point_2& query,
|
||||
const std::array<typename Kernel::Point_2, 3>& 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<FT>();
|
||||
|
||||
// 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<typename Kernel::Point_2, 3>& neighbors,
|
||||
const typename Kernel::FT& x) {
|
||||
|
||||
template<typename Kernel,
|
||||
typename Weight_wrapper>
|
||||
void test_symmetry_x(const Weight_wrapper& wrapper,
|
||||
const std::array<typename Kernel::Point_2, 3>& 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<typename Kernel::Point_2, 3>& neighbors) {
|
||||
|
||||
template<typename Kernel,
|
||||
typename Weight_wrapper_1,
|
||||
typename Weight_wrapper_2>
|
||||
void test_compare(const Weight_wrapper_1& wrapper1,
|
||||
const Weight_wrapper_2& wrapper2,
|
||||
const typename Kernel::Point_2& query,
|
||||
const std::array<typename Kernel::Point_2, 3>& 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<FT>();
|
||||
|
||||
// 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<typename Kernel::Point_2, 3>& neighbors) {
|
||||
|
||||
template<typename Kernel,
|
||||
typename Weight_wrapper>
|
||||
void test_neighbors(const Weight_wrapper& wrapper,
|
||||
const std::array<typename Kernel::Point_2, 3>& 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<FT>();
|
||||
|
||||
// 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<typename Kernel::Point_2, 3>& neighbors) {
|
||||
|
||||
template<typename Kernel,
|
||||
typename Weight_wrapper>
|
||||
void test_area(const Weight_wrapper& wrapper,
|
||||
const std::array<typename Kernel::Point_2, 3>& 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<typename FT, typename Point>
|
||||
bool test_coordinates(
|
||||
const Point& query,
|
||||
const std::vector<Point>& polygon,
|
||||
const std::vector<FT>& weights) {
|
||||
|
||||
void test_coordinates(const Point& query,
|
||||
const std::vector<Point>& polygon,
|
||||
const std::vector<FT>& weights)
|
||||
{
|
||||
assert(weights.size() > 0);
|
||||
if (weights.size() == 0) return false;
|
||||
|
||||
// Compute the sum of weights.
|
||||
const FT tol = get_tolerance<FT>();
|
||||
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<FT> 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<typename Kernel::Point_2>& polygon_2) {
|
||||
|
||||
template<typename Kernel,
|
||||
typename Weight_wrapper>
|
||||
void test_on_polygon(const Weight_wrapper& wrapper,
|
||||
const typename Kernel::Point_2& query_2,
|
||||
const std::vector<typename Kernel::Point_2>& 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<FT> 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<Point_3> 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<Kernel> ptraits;
|
||||
|
||||
const CGAL::Projection_traits_xy_3<Kernel> ptraits;
|
||||
std::vector<FT> 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<typename Kernel::Point_2>& polygon) {
|
||||
|
||||
template<typename Kernel,
|
||||
typename Weight_wrapper>
|
||||
void test_barycentric_properties(const Weight_wrapper& wrapper,
|
||||
const typename Kernel::Point_2& query,
|
||||
const std::vector<typename Kernel::Point_2>& 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<FT> 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<typename Kernel,
|
||||
typename Weight_wrapper_1,
|
||||
typename Weight_wrapper_2>
|
||||
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<Kernel>();
|
||||
for (const auto& config : configs) {
|
||||
if (!test_query<Kernel>(weight, zero, config)) return false;
|
||||
for (const auto& query : queries) {
|
||||
if (!test_query<Kernel>(weight, query, config)) return false;
|
||||
}
|
||||
for (const auto& config : configs)
|
||||
{
|
||||
test_query<Kernel>(weight, zero, config);
|
||||
for (const auto& query : queries)
|
||||
test_query<Kernel>(weight, query, config);
|
||||
}
|
||||
|
||||
// Test alternative formulations.
|
||||
for (const auto& config : configs) {
|
||||
if (!test_compare<Kernel>(weight, alternative, zero, config)) {
|
||||
return false;
|
||||
}
|
||||
for (const auto& query : queries) {
|
||||
if (!test_compare<Kernel>(weight, alternative, query, config)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
for (const auto& config : configs)
|
||||
{
|
||||
test_compare<Kernel>(weight, alternative, zero, config);
|
||||
for (const auto& query : queries)
|
||||
test_compare<Kernel>(weight, alternative, query, config);
|
||||
}
|
||||
|
||||
// Test symmetry along x axis.
|
||||
configs = get_symmetric_triangles<Kernel>();
|
||||
for (const auto& config : configs) {
|
||||
if (!test_symmetry_x<Kernel>(weight, config, q)) return false;
|
||||
if (!test_symmetry_x<Kernel>(weight, config, h)) return false;
|
||||
if (!test_symmetry_x<Kernel>(weight, config, t)) return false;
|
||||
for (const auto& config : configs)
|
||||
{
|
||||
test_symmetry_x<Kernel>(weight, config, q);
|
||||
test_symmetry_x<Kernel>(weight, config, h);
|
||||
test_symmetry_x<Kernel>(weight, config, t);
|
||||
}
|
||||
|
||||
// Test barycentric properties.
|
||||
if (weight.is_barycentric()) {
|
||||
if (weight.is_barycentric())
|
||||
{
|
||||
const auto polygons = get_all_polygons<Kernel>();
|
||||
for (const auto& polygon : polygons) {
|
||||
if (!test_barycentric_properties<Kernel>(weight, zero, polygon)) {
|
||||
return false;
|
||||
}
|
||||
for (const auto& query : queries) {
|
||||
if (!test_barycentric_properties<Kernel>(weight, query, polygon)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
for (const auto& polygon : polygons)
|
||||
{
|
||||
test_barycentric_properties<Kernel>(weight, zero, polygon);
|
||||
for (const auto& query : queries)
|
||||
test_barycentric_properties<Kernel>(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<typename Kernel,
|
||||
typename Weight_wrapper_1,
|
||||
typename Weight_wrapper_2>
|
||||
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<Point_2> queries = {
|
||||
const std::vector<Point_2> 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<Kernel>(weight, alternative)) {
|
||||
return false;
|
||||
}
|
||||
test_analytic_weight<Kernel>(weight, alternative);
|
||||
|
||||
// Test on polygons.
|
||||
const auto polygons = get_all_polygons<Kernel>();
|
||||
for (const auto& polygon : polygons) {
|
||||
if (!test_on_polygon<Kernel>(weight, zero, polygon)) return false;
|
||||
for (const auto& query : queries) {
|
||||
if (!test_on_polygon<Kernel>(weight, query, polygon)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
for (const auto& polygon : polygons)
|
||||
{
|
||||
test_on_polygon<Kernel>(weight, zero, polygon);
|
||||
for (const auto& query : queries)
|
||||
test_on_polygon<Kernel>(weight, query, polygon);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
template<
|
||||
typename Kernel,
|
||||
typename Weight_wrapper>
|
||||
bool test_region_weight(const Weight_wrapper& weight) {
|
||||
|
||||
// Test neighborhoods.
|
||||
template<typename Kernel,
|
||||
typename Weight_wrapper>
|
||||
void test_region_weight(const Weight_wrapper& weight)
|
||||
{
|
||||
auto configs = get_all_triangles<Kernel>();
|
||||
for (const auto& config : configs) {
|
||||
if (!test_neighbors<Kernel>(weight, config)) return false;
|
||||
}
|
||||
for (const auto& config : configs)
|
||||
test_neighbors<Kernel>(weight, config);
|
||||
|
||||
// Test areas.
|
||||
configs = get_uniform_triangles<Kernel>();
|
||||
for (const auto& config : configs) {
|
||||
if (!test_area<Kernel>(weight, config)) return false;
|
||||
}
|
||||
return true;
|
||||
for (const auto& config : configs)
|
||||
test_area<Kernel>(weight, config);
|
||||
}
|
||||
|
||||
} // namespace tests
|
||||
|
|
|
|||
|
|
@ -1,261 +1,345 @@
|
|||
#ifndef CGAL_WEIGHTS_TESTS_WRAPPERS_H
|
||||
#define CGAL_WEIGHTS_TESTS_WRAPPERS_H
|
||||
|
||||
// STL includes.
|
||||
#include "utils.h"
|
||||
|
||||
#include <CGAL/Weights.h>
|
||||
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
// CGAL includes.
|
||||
#include <CGAL/Weights.h>
|
||||
|
||||
namespace wrappers {
|
||||
|
||||
template<typename Kernel>
|
||||
struct Authalic_wrapper {
|
||||
struct Authalic_wrapper
|
||||
{
|
||||
using FT = typename Kernel::FT;
|
||||
|
||||
template<typename Point>
|
||||
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<typename Point>
|
||||
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<typename Kernel>
|
||||
struct Cotangent_wrapper {
|
||||
struct Cotangent_wrapper
|
||||
{
|
||||
using FT = typename Kernel::FT;
|
||||
|
||||
template<typename Point>
|
||||
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<typename Point>
|
||||
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<typename Kernel>
|
||||
struct Tangent_wrapper {
|
||||
struct Tangent_wrapper
|
||||
{
|
||||
using FT = typename Kernel::FT;
|
||||
|
||||
template<typename Point>
|
||||
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<typename Point>
|
||||
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<typename Kernel>
|
||||
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<typename Point>
|
||||
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<typename Polygon, typename Point, typename Traits, typename OutputIterator>
|
||||
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<typename Kernel>
|
||||
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<typename Point>
|
||||
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<typename Polygon, typename Point, typename Traits, typename OutputIterator>
|
||||
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<typename Kernel>
|
||||
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<typename Point>
|
||||
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<typename Polygon, typename Point, typename Traits, typename OutputIterator>
|
||||
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<typename Kernel>
|
||||
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<typename Point>
|
||||
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<typename Kernel>
|
||||
struct Uniform_region_wrapper {
|
||||
struct Uniform_region_wrapper
|
||||
{
|
||||
using FT = typename Kernel::FT;
|
||||
template<typename Point>
|
||||
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<typename Kernel>
|
||||
struct Triangular_region_wrapper {
|
||||
struct Triangular_region_wrapper
|
||||
{
|
||||
using FT = typename Kernel::FT;
|
||||
template<typename Point>
|
||||
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<typename Kernel>
|
||||
struct Barycentric_region_wrapper {
|
||||
struct Barycentric_region_wrapper
|
||||
{
|
||||
using FT = typename Kernel::FT;
|
||||
template<typename Point>
|
||||
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<typename Kernel>
|
||||
struct Voronoi_region_wrapper {
|
||||
struct Voronoi_region_wrapper
|
||||
{
|
||||
using FT = typename Kernel::FT;
|
||||
template<typename Point>
|
||||
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<typename Kernel>
|
||||
struct Mixed_voronoi_region_wrapper {
|
||||
struct Mixed_voronoi_region_wrapper
|
||||
{
|
||||
using FT = typename Kernel::FT;
|
||||
template<typename Point>
|
||||
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<typename Kernel>
|
||||
struct Uniform_wrapper {
|
||||
struct Uniform_wrapper
|
||||
{
|
||||
using FT = typename Kernel::FT;
|
||||
|
||||
template<typename Point>
|
||||
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<typename Point>
|
||||
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<typename Kernel>
|
||||
struct Inverse_distance_wrapper {
|
||||
struct Inverse_distance_wrapper
|
||||
{
|
||||
using FT = typename Kernel::FT;
|
||||
|
||||
template<typename Point>
|
||||
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<typename Point>
|
||||
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<typename Kernel>
|
||||
struct Shepard_wrapper {
|
||||
struct Shepard_wrapper
|
||||
{
|
||||
using FT = typename Kernel::FT;
|
||||
|
||||
const FT a;
|
||||
|
||||
Shepard_wrapper(const FT a) : a(a) { }
|
||||
|
||||
template<typename Point>
|
||||
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<typename Point>
|
||||
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; }
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,26 +1,29 @@
|
|||
#include "include/utils.h"
|
||||
#include "include/wrappers.h"
|
||||
|
||||
#include <CGAL/Simple_cartesian.h>
|
||||
#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
|
||||
#include <CGAL/Exact_predicates_exact_constructions_kernel.h>
|
||||
|
||||
#include "include/utils.h"
|
||||
#include "include/wrappers.h"
|
||||
|
||||
// Typedefs.
|
||||
using SCKER = CGAL::Simple_cartesian<double>;
|
||||
using EPICK = CGAL::Exact_predicates_inexact_constructions_kernel;
|
||||
using EPECK = CGAL::Exact_predicates_exact_constructions_kernel;
|
||||
|
||||
template<typename Kernel>
|
||||
bool test_kernel() {
|
||||
void test_kernel()
|
||||
{
|
||||
const wrappers::Authalic_wrapper<Kernel> aut;
|
||||
const wrappers::Wachspress_wrapper<Kernel> whp;
|
||||
return tests::test_analytic_weight<Kernel>(aut, whp);
|
||||
const wrappers::Three_point_family_wrapper<Kernel> tpf(0);
|
||||
tests::test_analytic_weight<Kernel>(aut, whp);
|
||||
tests::test_analytic_weight<Kernel>(aut, tpf);
|
||||
}
|
||||
|
||||
int main() {
|
||||
assert(test_kernel<SCKER>());
|
||||
assert(test_kernel<EPICK>());
|
||||
assert(test_kernel<EPECK>());
|
||||
int main(int, char**)
|
||||
{
|
||||
test_kernel<SCKER>();
|
||||
test_kernel<EPICK>();
|
||||
test_kernel<EPECK>();
|
||||
std::cout << "* test_authalic_weights: SUCCESS" << std::endl;
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,25 +1,48 @@
|
|||
#include "include/utils.h"
|
||||
#include "include/wrappers.h"
|
||||
|
||||
#include <CGAL/Simple_cartesian.h>
|
||||
#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
|
||||
#include <CGAL/Exact_predicates_exact_constructions_kernel.h>
|
||||
|
||||
#include "include/utils.h"
|
||||
#include "include/wrappers.h"
|
||||
|
||||
// Typedefs.
|
||||
using SCKER = CGAL::Simple_cartesian<double>;
|
||||
using EPICK = CGAL::Exact_predicates_inexact_constructions_kernel;
|
||||
using EPECK = CGAL::Exact_predicates_exact_constructions_kernel;
|
||||
|
||||
template<typename Kernel>
|
||||
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<Kernel> bar;
|
||||
return tests::test_region_weight<Kernel>(bar);
|
||||
tests::test_region_weight<Kernel>(bar);
|
||||
}
|
||||
|
||||
int main() {
|
||||
assert(test_kernel<SCKER>());
|
||||
assert(test_kernel<EPICK>());
|
||||
assert(test_kernel<EPECK>());
|
||||
int main(int, char**)
|
||||
{
|
||||
test_kernel<SCKER>();
|
||||
test_kernel<EPICK>();
|
||||
test_kernel<EPECK>();
|
||||
std::cout << "* test_barycentric_region_weights: SUCCESS" << std::endl;
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,26 +1,39 @@
|
|||
#include "include/utils.h"
|
||||
#include "include/wrappers.h"
|
||||
|
||||
#include <CGAL/Simple_cartesian.h>
|
||||
#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
|
||||
#include <CGAL/Exact_predicates_exact_constructions_kernel.h>
|
||||
|
||||
#include "include/utils.h"
|
||||
#include "include/wrappers.h"
|
||||
|
||||
// Typedefs.
|
||||
using SCKER = CGAL::Simple_cartesian<double>;
|
||||
using EPICK = CGAL::Exact_predicates_inexact_constructions_kernel;
|
||||
using EPECK = CGAL::Exact_predicates_exact_constructions_kernel;
|
||||
|
||||
template<typename Kernel>
|
||||
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<Kernel> cot;
|
||||
const wrappers::Discrete_harmonic_wrapper<Kernel> dhw;
|
||||
return tests::test_analytic_weight<Kernel>(cot, dhw);
|
||||
const wrappers::Three_point_family_wrapper<Kernel> tpf(2);
|
||||
tests::test_analytic_weight<Kernel>(cot, dhw);
|
||||
tests::test_analytic_weight<Kernel>(cot, tpf);
|
||||
}
|
||||
|
||||
int main() {
|
||||
assert(test_kernel<SCKER>());
|
||||
assert(test_kernel<EPICK>());
|
||||
assert(test_kernel<EPECK>());
|
||||
int main(int, char**)
|
||||
{
|
||||
test_kernel<SCKER>();
|
||||
test_kernel<EPICK>();
|
||||
test_kernel<EPECK>();
|
||||
std::cout << "* test_cotangent_weights: SUCCESS" << std::endl;
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,17 +1,17 @@
|
|||
#include "include/utils.h"
|
||||
#include "include/wrappers.h"
|
||||
|
||||
#include <CGAL/Simple_cartesian.h>
|
||||
#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
|
||||
#include <CGAL/Exact_predicates_exact_constructions_kernel.h>
|
||||
|
||||
#include "include/utils.h"
|
||||
#include "include/wrappers.h"
|
||||
|
||||
// Typedefs.
|
||||
using SCKER = CGAL::Simple_cartesian<double>;
|
||||
using EPICK = CGAL::Exact_predicates_inexact_constructions_kernel;
|
||||
using EPECK = CGAL::Exact_predicates_exact_constructions_kernel;
|
||||
|
||||
template<typename Kernel>
|
||||
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<Kernel> 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<typename Kernel>
|
||||
bool test_kernel() {
|
||||
void test_kernel()
|
||||
{
|
||||
test_overloads<Kernel>();
|
||||
const wrappers::Discrete_harmonic_wrapper<Kernel> dhw;
|
||||
const wrappers::Cotangent_wrapper<Kernel> cot;
|
||||
return tests::test_barycentric_weight<Kernel>(dhw, cot);
|
||||
tests::test_barycentric_weight<Kernel>(dhw, cot);
|
||||
}
|
||||
|
||||
int main() {
|
||||
assert(test_kernel<SCKER>());
|
||||
assert(test_kernel<EPICK>());
|
||||
assert(test_kernel<EPECK>());
|
||||
int main(int, char**)
|
||||
{
|
||||
test_kernel<SCKER>();
|
||||
test_kernel<EPICK>();
|
||||
test_kernel<EPECK>();
|
||||
std::cout << "* test_discrete_harmonic_weights: SUCCESS" << std::endl;
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,47 +1,53 @@
|
|||
#include "include/utils.h"
|
||||
#include "include/wrappers.h"
|
||||
|
||||
#include <CGAL/Simple_cartesian.h>
|
||||
#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
|
||||
#include <CGAL/Exact_predicates_exact_constructions_kernel.h>
|
||||
|
||||
#include "include/utils.h"
|
||||
#include "include/wrappers.h"
|
||||
|
||||
// Typedefs.
|
||||
using SCKER = CGAL::Simple_cartesian<double>;
|
||||
using EPICK = CGAL::Exact_predicates_inexact_constructions_kernel;
|
||||
using EPECK = CGAL::Exact_predicates_exact_constructions_kernel;
|
||||
|
||||
template<typename Kernel>
|
||||
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<typename Kernel>
|
||||
bool test_kernel() {
|
||||
void test_kernel()
|
||||
{
|
||||
test_overloads<Kernel>();
|
||||
const wrappers::Inverse_distance_wrapper<Kernel> idw;
|
||||
const wrappers::Shepard_wrapper<Kernel> spw(1);
|
||||
return tests::test_analytic_weight<Kernel>(idw, spw);
|
||||
tests::test_analytic_weight<Kernel>(idw, spw);
|
||||
}
|
||||
|
||||
int main() {
|
||||
assert(test_kernel<SCKER>());
|
||||
assert(test_kernel<EPICK>());
|
||||
assert(test_kernel<EPECK>());
|
||||
int main(int, char**)
|
||||
{
|
||||
test_kernel<SCKER>();
|
||||
test_kernel<EPICK>();
|
||||
test_kernel<EPECK>();
|
||||
std::cout << "* test_inverse_distance_weights: SUCCESS" << std::endl;
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,17 +1,17 @@
|
|||
#include "include/utils.h"
|
||||
#include "include/wrappers.h"
|
||||
|
||||
#include <CGAL/Simple_cartesian.h>
|
||||
#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
|
||||
#include <CGAL/Exact_predicates_exact_constructions_kernel.h>
|
||||
|
||||
#include "include/utils.h"
|
||||
#include "include/wrappers.h"
|
||||
|
||||
// Typedefs.
|
||||
using SCKER = CGAL::Simple_cartesian<double>;
|
||||
using EPICK = CGAL::Exact_predicates_inexact_constructions_kernel;
|
||||
using EPECK = CGAL::Exact_predicates_exact_constructions_kernel;
|
||||
|
||||
template<typename Kernel>
|
||||
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<Kernel> 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<typename Kernel>
|
||||
bool test_kernel() {
|
||||
void test_kernel()
|
||||
{
|
||||
test_overloads<Kernel>();
|
||||
const wrappers::Mean_value_wrapper<Kernel> mvw;
|
||||
const wrappers::Tangent_wrapper<Kernel> tan;
|
||||
return tests::test_barycentric_weight<Kernel>(mvw, tan);
|
||||
const wrappers::Three_point_family_wrapper<Kernel> tpf(1);
|
||||
tests::test_barycentric_weight<Kernel>(mvw, tan);
|
||||
tests::test_barycentric_weight<Kernel>(mvw, tpf);
|
||||
}
|
||||
|
||||
int main() {
|
||||
assert(test_kernel<SCKER>());
|
||||
assert(test_kernel<EPICK>());
|
||||
assert(test_kernel<EPECK>());
|
||||
int main(int, char**)
|
||||
{
|
||||
test_kernel<SCKER>();
|
||||
test_kernel<EPICK>();
|
||||
test_kernel<EPECK>();
|
||||
std::cout << "* test_mean_value_weights: SUCCESS" << std::endl;
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,25 +1,26 @@
|
|||
#include "include/utils.h"
|
||||
#include "include/wrappers.h"
|
||||
|
||||
#include <CGAL/Simple_cartesian.h>
|
||||
#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
|
||||
#include <CGAL/Exact_predicates_exact_constructions_kernel.h>
|
||||
|
||||
#include "include/utils.h"
|
||||
#include "include/wrappers.h"
|
||||
|
||||
// Typedefs.
|
||||
using SCKER = CGAL::Simple_cartesian<double>;
|
||||
using EPICK = CGAL::Exact_predicates_inexact_constructions_kernel;
|
||||
using EPECK = CGAL::Exact_predicates_exact_constructions_kernel;
|
||||
|
||||
template<typename Kernel>
|
||||
bool test_kernel() {
|
||||
void test_kernel()
|
||||
{
|
||||
const wrappers::Mixed_voronoi_region_wrapper<Kernel> mix;
|
||||
return tests::test_region_weight<Kernel>(mix);
|
||||
tests::test_region_weight<Kernel>(mix);
|
||||
}
|
||||
|
||||
int main() {
|
||||
assert(test_kernel<SCKER>());
|
||||
assert(test_kernel<EPICK>());
|
||||
assert(test_kernel<EPECK>());
|
||||
int main(int, char**)
|
||||
{
|
||||
test_kernel<SCKER>();
|
||||
test_kernel<EPICK>();
|
||||
test_kernel<EPECK>();
|
||||
std::cout << "* test_mixed_voronoi_region_weights: SUCCESS" << std::endl;
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,18 +1,19 @@
|
|||
#include <CGAL/Simple_cartesian.h>
|
||||
#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
|
||||
#include <CGAL/Exact_predicates_exact_constructions_kernel.h>
|
||||
|
||||
#include <CGAL/Projection_traits_xy_3.h>
|
||||
#include <CGAL/Projection_traits_xz_3.h>
|
||||
#include <CGAL/Projection_traits_yz_3.h>
|
||||
#include <CGAL/Weights.h>
|
||||
|
||||
// Typedefs.
|
||||
using SCKER = CGAL::Simple_cartesian<double>;
|
||||
using EPICK = CGAL::Exact_predicates_inexact_constructions_kernel;
|
||||
using EPECK = CGAL::Exact_predicates_exact_constructions_kernel;
|
||||
|
||||
template<typename Kernel>
|
||||
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<SCKER>();
|
||||
test_kernel<EPICK>();
|
||||
test_kernel<EPECK>();
|
||||
|
|
|
|||
|
|
@ -1,49 +1,55 @@
|
|||
#include "include/utils.h"
|
||||
#include "include/wrappers.h"
|
||||
|
||||
#include <CGAL/Simple_cartesian.h>
|
||||
#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
|
||||
#include <CGAL/Exact_predicates_exact_constructions_kernel.h>
|
||||
|
||||
#include "include/utils.h"
|
||||
#include "include/wrappers.h"
|
||||
|
||||
// Typedefs.
|
||||
using SCKER = CGAL::Simple_cartesian<double>;
|
||||
using EPICK = CGAL::Exact_predicates_inexact_constructions_kernel;
|
||||
using EPECK = CGAL::Exact_predicates_exact_constructions_kernel;
|
||||
|
||||
template<typename Kernel>
|
||||
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<typename Kernel>
|
||||
bool test_kernel() {
|
||||
void test_kernel()
|
||||
{
|
||||
test_overloads<Kernel>();
|
||||
const wrappers::Shepard_wrapper<Kernel> spwa(1);
|
||||
const wrappers::Shepard_wrapper<Kernel> spwb(2);
|
||||
const wrappers::Inverse_distance_wrapper<Kernel> idw;
|
||||
assert(tests::test_analytic_weight<Kernel>(spwa, idw));
|
||||
return tests::test_analytic_weight<Kernel>(spwb, spwb);
|
||||
tests::test_analytic_weight<Kernel>(spwa, idw);
|
||||
tests::test_analytic_weight<Kernel>(spwb, spwb);
|
||||
}
|
||||
|
||||
int main() {
|
||||
assert(test_kernel<SCKER>());
|
||||
assert(test_kernel<EPICK>());
|
||||
assert(test_kernel<EPECK>());
|
||||
int main(int, char**)
|
||||
{
|
||||
test_kernel<SCKER>();
|
||||
test_kernel<EPICK>();
|
||||
test_kernel<EPECK>();
|
||||
std::cout << "* test_shepard_weights: SUCCESS" << std::endl;
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,26 +1,29 @@
|
|||
#include "include/utils.h"
|
||||
#include "include/wrappers.h"
|
||||
|
||||
#include <CGAL/Simple_cartesian.h>
|
||||
#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
|
||||
#include <CGAL/Exact_predicates_exact_constructions_kernel.h>
|
||||
|
||||
#include "include/utils.h"
|
||||
#include "include/wrappers.h"
|
||||
|
||||
// Typedefs.
|
||||
using SCKER = CGAL::Simple_cartesian<double>;
|
||||
using EPICK = CGAL::Exact_predicates_inexact_constructions_kernel;
|
||||
using EPECK = CGAL::Exact_predicates_exact_constructions_kernel;
|
||||
|
||||
template<typename Kernel>
|
||||
bool test_kernel() {
|
||||
void test_kernel()
|
||||
{
|
||||
const wrappers::Tangent_wrapper<Kernel> tan;
|
||||
const wrappers::Mean_value_wrapper<Kernel> mvw;
|
||||
return tests::test_analytic_weight<Kernel>(tan, mvw);
|
||||
const wrappers::Three_point_family_wrapper<Kernel> tpf(1);
|
||||
tests::test_analytic_weight<Kernel>(tan, mvw);
|
||||
tests::test_analytic_weight<Kernel>(tan, tpf);
|
||||
}
|
||||
|
||||
int main() {
|
||||
assert(test_kernel<SCKER>());
|
||||
assert(test_kernel<EPICK>());
|
||||
assert(test_kernel<EPECK>());
|
||||
int main(int, char**)
|
||||
{
|
||||
test_kernel<SCKER>();
|
||||
test_kernel<EPICK>();
|
||||
test_kernel<EPECK>();
|
||||
std::cout << "* test_tangent_weights: SUCCESS" << std::endl;
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,17 +1,17 @@
|
|||
#include "include/utils.h"
|
||||
#include "include/wrappers.h"
|
||||
|
||||
#include <CGAL/Simple_cartesian.h>
|
||||
#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
|
||||
#include <CGAL/Exact_predicates_exact_constructions_kernel.h>
|
||||
|
||||
#include "include/utils.h"
|
||||
#include "include/wrappers.h"
|
||||
|
||||
// Typedefs.
|
||||
using SCKER = CGAL::Simple_cartesian<double>;
|
||||
using EPICK = CGAL::Exact_predicates_inexact_constructions_kernel;
|
||||
using EPECK = CGAL::Exact_predicates_exact_constructions_kernel;
|
||||
|
||||
template<typename Kernel>
|
||||
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<Kernel> 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<typename Kernel>
|
||||
bool test_kernel() {
|
||||
void test_kernel()
|
||||
{
|
||||
test_overloads<Kernel>();
|
||||
using FT = typename Kernel::FT;
|
||||
const FT h = FT(1) / FT(2);
|
||||
|
|
@ -49,16 +52,18 @@ bool test_kernel() {
|
|||
const wrappers::Wachspress_wrapper<Kernel> whp;
|
||||
const wrappers::Mean_value_wrapper<Kernel> mvw;
|
||||
const wrappers::Discrete_harmonic_wrapper<Kernel> dhw;
|
||||
assert(tests::test_analytic_weight<Kernel>(tpfa, whp));
|
||||
assert(tests::test_analytic_weight<Kernel>(tpfb, mvw));
|
||||
assert(tests::test_analytic_weight<Kernel>(tpfc, dhw));
|
||||
return tests::test_analytic_weight<Kernel>(tpfd, tpfd);
|
||||
|
||||
tests::test_analytic_weight<Kernel>(tpfa, whp);
|
||||
tests::test_analytic_weight<Kernel>(tpfb, mvw);
|
||||
tests::test_analytic_weight<Kernel>(tpfc, dhw);
|
||||
tests::test_analytic_weight<Kernel>(tpfd, tpfd);
|
||||
}
|
||||
|
||||
int main() {
|
||||
assert(test_kernel<SCKER>());
|
||||
assert(test_kernel<EPICK>());
|
||||
assert(test_kernel<EPECK>());
|
||||
int main(int, char**)
|
||||
{
|
||||
test_kernel<SCKER>();
|
||||
test_kernel<EPICK>();
|
||||
test_kernel<EPECK>();
|
||||
std::cout << "* test_three_point_family_weights: SUCCESS" << std::endl;
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,25 +1,26 @@
|
|||
#include "include/utils.h"
|
||||
#include "include/wrappers.h"
|
||||
|
||||
#include <CGAL/Simple_cartesian.h>
|
||||
#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
|
||||
#include <CGAL/Exact_predicates_exact_constructions_kernel.h>
|
||||
|
||||
#include "include/utils.h"
|
||||
#include "include/wrappers.h"
|
||||
|
||||
// Typedefs.
|
||||
using SCKER = CGAL::Simple_cartesian<double>;
|
||||
using EPICK = CGAL::Exact_predicates_inexact_constructions_kernel;
|
||||
using EPECK = CGAL::Exact_predicates_exact_constructions_kernel;
|
||||
|
||||
template<typename Kernel>
|
||||
bool test_kernel() {
|
||||
void test_kernel()
|
||||
{
|
||||
const wrappers::Triangular_region_wrapper<Kernel> tri;
|
||||
return tests::test_region_weight<Kernel>(tri);
|
||||
tests::test_region_weight<Kernel>(tri);
|
||||
}
|
||||
|
||||
int main() {
|
||||
assert(test_kernel<SCKER>());
|
||||
assert(test_kernel<EPICK>());
|
||||
assert(test_kernel<EPECK>());
|
||||
int main(int, char**)
|
||||
{
|
||||
test_kernel<SCKER>();
|
||||
test_kernel<EPICK>();
|
||||
test_kernel<EPECK>();
|
||||
std::cout << "* test_triangular_region_weights: SUCCESS" << std::endl;
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,17 +1,17 @@
|
|||
#include "include/utils.h"
|
||||
#include "include/wrappers.h"
|
||||
|
||||
#include <CGAL/Simple_cartesian.h>
|
||||
#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
|
||||
#include <CGAL/Exact_predicates_exact_constructions_kernel.h>
|
||||
|
||||
#include "include/utils.h"
|
||||
#include "include/wrappers.h"
|
||||
|
||||
// Typedefs.
|
||||
using SCKER = CGAL::Simple_cartesian<double>;
|
||||
using EPICK = CGAL::Exact_predicates_inexact_constructions_kernel;
|
||||
using EPECK = CGAL::Exact_predicates_exact_constructions_kernel;
|
||||
|
||||
template<typename Kernel>
|
||||
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<typename Kernel>
|
||||
bool test_kernel() {
|
||||
void test_kernel()
|
||||
{
|
||||
test_overloads<Kernel>();
|
||||
const wrappers::Uniform_region_wrapper<Kernel> uni;
|
||||
return tests::test_region_weight<Kernel>(uni);
|
||||
tests::test_region_weight<Kernel>(uni);
|
||||
}
|
||||
|
||||
int main() {
|
||||
assert(test_kernel<SCKER>());
|
||||
assert(test_kernel<EPICK>());
|
||||
assert(test_kernel<EPECK>());
|
||||
int main(int, char**)
|
||||
{
|
||||
test_kernel<SCKER>();
|
||||
test_kernel<EPICK>();
|
||||
test_kernel<EPECK>();
|
||||
std::cout << "* test_uniform_region_weights: SUCCESS" << std::endl;
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,41 +1,46 @@
|
|||
#include "include/utils.h"
|
||||
#include "include/wrappers.h"
|
||||
|
||||
#include <CGAL/Simple_cartesian.h>
|
||||
#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
|
||||
#include <CGAL/Exact_predicates_exact_constructions_kernel.h>
|
||||
|
||||
#include "include/utils.h"
|
||||
#include "include/wrappers.h"
|
||||
|
||||
// Typedefs.
|
||||
using SCKER = CGAL::Simple_cartesian<double>;
|
||||
using EPICK = CGAL::Exact_predicates_inexact_constructions_kernel;
|
||||
using EPECK = CGAL::Exact_predicates_exact_constructions_kernel;
|
||||
|
||||
template<typename Kernel>
|
||||
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<typename Kernel>
|
||||
bool test_kernel() {
|
||||
void test_kernel()
|
||||
{
|
||||
test_overloads<Kernel>();
|
||||
const wrappers::Uniform_wrapper<Kernel> uni;
|
||||
return tests::test_analytic_weight<Kernel>(uni, uni);
|
||||
tests::test_analytic_weight<Kernel>(uni, uni);
|
||||
}
|
||||
|
||||
int main() {
|
||||
assert(test_kernel<SCKER>());
|
||||
assert(test_kernel<EPICK>());
|
||||
assert(test_kernel<EPECK>());
|
||||
int main(int, char**)
|
||||
{
|
||||
test_kernel<SCKER>();
|
||||
test_kernel<EPICK>();
|
||||
test_kernel<EPECK>();
|
||||
std::cout << "* test_uniform_weights: SUCCESS" << std::endl;
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,25 +1,42 @@
|
|||
#include "include/utils.h"
|
||||
#include "include/wrappers.h"
|
||||
|
||||
#include <CGAL/Simple_cartesian.h>
|
||||
#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
|
||||
#include <CGAL/Exact_predicates_exact_constructions_kernel.h>
|
||||
|
||||
#include "include/utils.h"
|
||||
#include "include/wrappers.h"
|
||||
|
||||
// Typedefs.
|
||||
using SCKER = CGAL::Simple_cartesian<double>;
|
||||
using EPICK = CGAL::Exact_predicates_inexact_constructions_kernel;
|
||||
using EPECK = CGAL::Exact_predicates_exact_constructions_kernel;
|
||||
|
||||
template<typename Kernel>
|
||||
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<Kernel> vor;
|
||||
return tests::test_region_weight<Kernel>(vor);
|
||||
tests::test_region_weight<Kernel>(vor);
|
||||
}
|
||||
|
||||
int main() {
|
||||
assert(test_kernel<SCKER>());
|
||||
assert(test_kernel<EPICK>());
|
||||
assert(test_kernel<EPECK>());
|
||||
int main(int, char**)
|
||||
{
|
||||
test_kernel<SCKER>();
|
||||
test_kernel<EPICK>();
|
||||
test_kernel<EPECK>();
|
||||
std::cout << "* test_voronoi_region_weights: SUCCESS" << std::endl;
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,17 +1,17 @@
|
|||
#include "include/utils.h"
|
||||
#include "include/wrappers.h"
|
||||
|
||||
#include <CGAL/Simple_cartesian.h>
|
||||
#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
|
||||
#include <CGAL/Exact_predicates_exact_constructions_kernel.h>
|
||||
|
||||
#include "include/utils.h"
|
||||
#include "include/wrappers.h"
|
||||
|
||||
// Typedefs.
|
||||
using SCKER = CGAL::Simple_cartesian<double>;
|
||||
using EPICK = CGAL::Exact_predicates_inexact_constructions_kernel;
|
||||
using EPECK = CGAL::Exact_predicates_exact_constructions_kernel;
|
||||
|
||||
template<typename Kernel>
|
||||
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<Kernel> 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<typename Kernel>
|
||||
bool test_kernel() {
|
||||
void test_kernel()
|
||||
{
|
||||
test_overloads<Kernel>();
|
||||
const wrappers::Wachspress_wrapper<Kernel> whp;
|
||||
const wrappers::Authalic_wrapper<Kernel> aut;
|
||||
return tests::test_barycentric_weight<Kernel>(whp, aut);
|
||||
const wrappers::Three_point_family_wrapper<Kernel> tpf(0);
|
||||
tests::test_barycentric_weight<Kernel>(whp, aut);
|
||||
tests::test_barycentric_weight<Kernel>(whp, tpf);
|
||||
}
|
||||
|
||||
int main() {
|
||||
assert(test_kernel<SCKER>());
|
||||
assert(test_kernel<EPICK>());
|
||||
assert(test_kernel<EPECK>());
|
||||
int main(int, char**)
|
||||
{
|
||||
test_kernel<SCKER>();
|
||||
test_kernel<EPICK>();
|
||||
test_kernel<EPECK>();
|
||||
std::cout << "* test_wachspress_weights: SUCCESS" << std::endl;
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
|
|
|||