several repeating functions are moved to internal

This commit is contained in:
Dmitry Anisimov 2021-03-23 12:29:22 +01:00
parent 25cd87cce3
commit 1ff8c00af4
14 changed files with 155 additions and 227 deletions

View File

@ -212,4 +212,5 @@ CGAL_add_named_parameter(maximum_normal_deviation_t, maximum_normal_deviation, m
CGAL_add_named_parameter(distance_threshold_t, distance_threshold, distance_threshold) CGAL_add_named_parameter(distance_threshold_t, distance_threshold, distance_threshold)
CGAL_add_named_parameter(angle_deg_threshold_t, angle_deg_threshold, angle_deg_threshold) CGAL_add_named_parameter(angle_deg_threshold_t, angle_deg_threshold, angle_deg_threshold)
CGAL_add_named_parameter(cos_value_threshold_t, cos_value_threshold, cos_value_threshold) CGAL_add_named_parameter(cos_value_threshold_t, cos_value_threshold, cos_value_threshold)
CGAL_add_named_parameter(min_region_size_t, min_region_size, min_region_size) CGAL_add_named_parameter(min_region_size_t, min_region_size, min_region_size)
CGAL_add_named_parameter(sort_regions_t, sort_regions, sort_regions)

View File

@ -56,7 +56,7 @@ namespace Point_set {
a model of `ConstRange` whose iterator type is `RandomAccessIterator` a model of `ConstRange` whose iterator type is `RandomAccessIterator`
\tparam PointMap \tparam PointMap
a model of `ReadPropertyMap` whose key type is the value type of the input a model of `LValuePropertyMap` whose key type is the value type of the input
range and value type is `Kernel::Point_2` or `Kernel::Point_3` range and value type is `Kernel::Point_2` or `Kernel::Point_3`
\cgalModels `NeighborQuery` \cgalModels `NeighborQuery`

View File

@ -16,21 +16,10 @@
#include <CGAL/license/Shape_detection.h> #include <CGAL/license/Shape_detection.h>
// STL includes.
#include <vector>
// Boost includes. // Boost includes.
#include <CGAL/boost/graph/named_params_helper.h> #include <CGAL/boost/graph/named_params_helper.h>
#include <CGAL/boost/graph/Named_function_parameters.h> #include <CGAL/boost/graph/Named_function_parameters.h>
// CGAL includes.
#include <CGAL/assertions.h>
#include <CGAL/number_utils.h>
#include <CGAL/Cartesian_converter.h>
#include <CGAL/Eigen_diagonalize_traits.h>
#include <CGAL/linear_least_squares_fitting_2.h>
#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
// Internal includes. // Internal includes.
#include <CGAL/Shape_detection/Region_growing/internal/utils.h> #include <CGAL/Shape_detection/Region_growing/internal/utils.h>
@ -56,11 +45,11 @@ namespace Point_set {
a model of `ConstRange` whose iterator type is `RandomAccessIterator` a model of `ConstRange` whose iterator type is `RandomAccessIterator`
\tparam PointMap \tparam PointMap
a model of `ReadPropertyMap` whose key type is the value type of the input a model of `LValuePropertyMap` whose key type is the value type of the input
range and value type is `Kernel::Point_2`. range and value type is `Kernel::Point_2`.
\tparam NormalMap \tparam NormalMap
a model of `ReadPropertyMap` whose key type is the value type of the input a model of `LValuePropertyMap` whose key type is the value type of the input
range and value type is `Kernel::Vector_2`. range and value type is `Kernel::Vector_2`.
\cgalModels `RegionType` \cgalModels `RegionType`
@ -93,19 +82,10 @@ namespace Point_set {
using Vector_2 = typename Traits::Vector_2; using Vector_2 = typename Traits::Vector_2;
using Line_2 = typename Traits::Line_2; using Line_2 = typename Traits::Line_2;
using ITraits = Exact_predicates_inexact_constructions_kernel;
using IFT = typename ITraits::FT;
using IPoint_2 = typename ITraits::Point_2;
using ILine_2 = typename ITraits::Line_2;
using IConverter = Cartesian_converter<Traits, ITraits>;
using Squared_length_2 = typename Traits::Compute_squared_length_2; using Squared_length_2 = typename Traits::Compute_squared_length_2;
using Squared_distance_2 = typename Traits::Compute_squared_distance_2; using Squared_distance_2 = typename Traits::Compute_squared_distance_2;
using Scalar_product_2 = typename Traits::Compute_scalar_product_2; using Scalar_product_2 = typename Traits::Compute_scalar_product_2;
using Get_sqrt = internal::Get_sqrt<Traits>;
using Sqrt = typename Get_sqrt::Sqrt;
public: public:
/// \name Initialization /// \name Initialization
/// @{ /// @{
@ -155,9 +135,7 @@ namespace Point_set {
m_normal_map(normal_map), m_normal_map(normal_map),
m_squared_length_2(traits.compute_squared_length_2_object()), m_squared_length_2(traits.compute_squared_length_2_object()),
m_squared_distance_2(traits.compute_squared_distance_2_object()), m_squared_distance_2(traits.compute_squared_distance_2_object()),
m_scalar_product_2(traits.compute_scalar_product_2_object()), m_scalar_product_2(traits.compute_scalar_product_2_object()) {
m_sqrt(Get_sqrt::sqrt_object(traits)),
m_iconverter() {
CGAL_precondition(input_range.size() > 0); CGAL_precondition(input_range.size() > 0);
m_distance_threshold = parameters::choose_parameter( m_distance_threshold = parameters::choose_parameter(
@ -177,6 +155,9 @@ namespace Point_set {
m_cos_value_threshold = parameters::choose_parameter( m_cos_value_threshold = parameters::choose_parameter(
parameters::get_parameter(np, internal_np::cos_value_threshold), cos_value_threshold); parameters::get_parameter(np, internal_np::cos_value_threshold), cos_value_threshold);
CGAL_precondition(m_cos_value_threshold >= FT(0) && m_cos_value_threshold <= FT(1)); CGAL_precondition(m_cos_value_threshold >= FT(0) && m_cos_value_threshold <= FT(1));
m_sort_regions = parameters::choose_parameter(
parameters::get_parameter(np, internal_np::sort_regions), false);
} }
/// @} /// @}
@ -272,31 +253,10 @@ namespace Point_set {
} else { // update reference line and normal } else { // update reference line and normal
std::vector<IPoint_2> points;
points.reserve(region.size());
for (const std::size_t point_index : region) {
CGAL_precondition(point_index < m_input_range.size());
const auto& key = *(m_input_range.begin() + point_index);
const Point_2& point = get(m_point_map, key);
points.push_back(m_iconverter(point));
}
CGAL_postcondition(points.size() == region.size());
ILine_2 fitted_line;
IPoint_2 fitted_centroid;
// The best fit line will be a line fitted to all region points with // The best fit line will be a line fitted to all region points with
// its normal being perpendicular to the line. // its normal being perpendicular to the line.
CGAL::linear_least_squares_fitting_2( internal::create_line_from_points_2(
points.begin(), points.end(), m_input_range, m_point_map, region, m_line_of_best_fit);
fitted_line, fitted_centroid,
CGAL::Dimension_tag<0>(), ITraits(),
CGAL::Eigen_diagonalize_traits<IFT, 2>());
m_line_of_best_fit = Line_2(
static_cast<FT>(fitted_line.a()),
static_cast<FT>(fitted_line.b()),
static_cast<FT>(fitted_line.c()));
m_normal_of_best_fit = m_line_of_best_fit.perpendicular( m_normal_of_best_fit = m_line_of_best_fit.perpendicular(
m_line_of_best_fit.point(0)).to_vector(); m_line_of_best_fit.point(0)).to_vector();
} }
@ -310,6 +270,7 @@ namespace Point_set {
FT m_distance_threshold; FT m_distance_threshold;
FT m_cos_value_threshold; FT m_cos_value_threshold;
std::size_t m_min_region_size; std::size_t m_min_region_size;
bool m_sort_regions;
const Point_map m_point_map; const Point_map m_point_map;
const Normal_map m_normal_map; const Normal_map m_normal_map;
@ -317,9 +278,6 @@ namespace Point_set {
const Squared_length_2 m_squared_length_2; const Squared_length_2 m_squared_length_2;
const Squared_distance_2 m_squared_distance_2; const Squared_distance_2 m_squared_distance_2;
const Scalar_product_2 m_scalar_product_2; const Scalar_product_2 m_scalar_product_2;
const Sqrt m_sqrt;
const IConverter m_iconverter;
Line_2 m_line_of_best_fit; Line_2 m_line_of_best_fit;
Vector_2 m_normal_of_best_fit; Vector_2 m_normal_of_best_fit;

View File

@ -16,17 +16,6 @@
#include <CGAL/license/Shape_detection.h> #include <CGAL/license/Shape_detection.h>
// STL includes.
#include <vector>
#include <algorithm>
// CGAL includes.
#include <CGAL/assertions.h>
#include <CGAL/Cartesian_converter.h>
#include <CGAL/Eigen_diagonalize_traits.h>
#include <CGAL/linear_least_squares_fitting_2.h>
#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
// Internal includes. // Internal includes.
#include <CGAL/Shape_detection/Region_growing/internal/utils.h> #include <CGAL/Shape_detection/Region_growing/internal/utils.h>
#include <CGAL/Shape_detection/Region_growing/internal/property_map.h> #include <CGAL/Shape_detection/Region_growing/internal/property_map.h>
@ -53,7 +42,7 @@ namespace Point_set {
a model of `NeighborQuery` a model of `NeighborQuery`
\tparam PointMap \tparam PointMap
a model of `ReadPropertyMap` whose key type is the value type of the input a model of `LValuePropertyMap` whose key type is the value type of the input
range and value type is `Kernel::Point_2` range and value type is `Kernel::Point_2`
*/ */
template< template<
@ -77,7 +66,7 @@ namespace Point_set {
#ifdef DOXYGEN_RUNNING #ifdef DOXYGEN_RUNNING
/*! /*!
a model of `ReadPropertyMap` whose key and value type is `std::size_t`. a model of `ReadablePropertyMap` whose key and value type is `std::size_t`.
This map provides an access to the ordered indices of input points. This map provides an access to the ordered indices of input points.
*/ */
typedef unspecified_type Seed_map; typedef unspecified_type Seed_map;
@ -86,12 +75,9 @@ namespace Point_set {
/// @} /// @}
private: private:
using ITraits = Exact_predicates_inexact_constructions_kernel; using FT = typename Traits::FT;
using IFT = typename ITraits::FT; using Line_2 = typename Traits::Line_2;
using IPoint_2 = typename ITraits::Point_2; using Compare_scores = internal::Compare_scores<FT>;
using ILine_2 = typename ITraits::Line_2;
using IConverter = Cartesian_converter<Traits, ITraits>;
using Compare_scores = internal::Compare_scores<IFT>;
public: public:
/// \name Initialization /// \name Initialization
@ -119,8 +105,7 @@ namespace Point_set {
const PointMap point_map = PointMap()) : const PointMap point_map = PointMap()) :
m_input_range(input_range), m_input_range(input_range),
m_neighbor_query(neighbor_query), m_neighbor_query(neighbor_query),
m_point_map(point_map), m_point_map(point_map) {
m_iconverter() {
CGAL_precondition(input_range.size() > 0); CGAL_precondition(input_range.size() > 0);
m_order.resize(m_input_range.size()); m_order.resize(m_input_range.size());
@ -164,35 +149,18 @@ namespace Point_set {
Neighbor_query& m_neighbor_query; Neighbor_query& m_neighbor_query;
const Point_map m_point_map; const Point_map m_point_map;
std::vector<std::size_t> m_order; std::vector<std::size_t> m_order;
std::vector<IFT> m_scores; std::vector<FT> m_scores;
const IConverter m_iconverter;
void compute_scores() { void compute_scores() {
std::vector<IPoint_2> points; Line_2 line;
std::vector<std::size_t> neighbors; std::vector<std::size_t> neighbors;
for (std::size_t i = 0; i < m_input_range.size(); ++i) { for (std::size_t i = 0; i < m_input_range.size(); ++i) {
neighbors.clear(); neighbors.clear();
m_neighbor_query(i, neighbors); m_neighbor_query(i, neighbors);
neighbors.push_back(i); neighbors.push_back(i);
m_scores[i] = internal::create_line_from_points_2(
points.clear(); m_input_range, m_point_map, neighbors, line);
for (const std::size_t point_index : neighbors) {
CGAL_precondition(point_index < m_input_range.size());
const auto& key = *(m_input_range.begin() + point_index);
const auto& point = get(m_point_map, key);
points.push_back(m_iconverter(point));
}
CGAL_postcondition(points.size() == neighbors.size());
ILine_2 fitted_line;
IPoint_2 fitted_centroid;
m_scores[i] = CGAL::linear_least_squares_fitting_2(
points.begin(), points.end(),
fitted_line, fitted_centroid,
CGAL::Dimension_tag<0>(), ITraits(),
CGAL::Eigen_diagonalize_traits<IFT, 2>());
} }
} }
}; };

View File

@ -56,11 +56,11 @@ namespace Point_set {
a model of `ConstRange` whose iterator type is `RandomAccessIterator` a model of `ConstRange` whose iterator type is `RandomAccessIterator`
\tparam PointMap \tparam PointMap
a model of `ReadPropertyMap` whose key type is the value type of the input a model of `LValuePropertyMap` whose key type is the value type of the input
range and value type is `Kernel::Point_3` range and value type is `Kernel::Point_3`
\tparam NormalMap \tparam NormalMap
a model of `ReadPropertyMap` whose key type is the value type of the input a model of `LValuePropertyMap` whose key type is the value type of the input
range and value type is `Kernel::Vector_3` range and value type is `Kernel::Vector_3`
\cgalModels `RegionType` \cgalModels `RegionType`
@ -177,6 +177,9 @@ namespace Point_set {
m_cos_value_threshold = parameters::choose_parameter( m_cos_value_threshold = parameters::choose_parameter(
parameters::get_parameter(np, internal_np::cos_value_threshold), cos_value_threshold); parameters::get_parameter(np, internal_np::cos_value_threshold), cos_value_threshold);
CGAL_precondition(m_cos_value_threshold >= FT(0) && m_cos_value_threshold <= FT(1)); CGAL_precondition(m_cos_value_threshold >= FT(0) && m_cos_value_threshold <= FT(1));
m_sort_regions = parameters::choose_parameter(
parameters::get_parameter(np, internal_np::sort_regions), false);
} }
/// @} /// @}
@ -310,6 +313,7 @@ namespace Point_set {
FT m_distance_threshold; FT m_distance_threshold;
FT m_cos_value_threshold; FT m_cos_value_threshold;
std::size_t m_min_region_size; std::size_t m_min_region_size;
bool m_sort_regions;
const Point_map m_point_map; const Point_map m_point_map;
const Normal_map m_normal_map; const Normal_map m_normal_map;

View File

@ -53,7 +53,7 @@ namespace Point_set {
a model of `NeighborQuery` a model of `NeighborQuery`
\tparam PointMap \tparam PointMap
a model of `ReadPropertyMap` whose key type is the value type of the input a model of `LValuePropertyMap` whose key type is the value type of the input
range and value type is `Kernel::Point_3` range and value type is `Kernel::Point_3`
*/ */
template< template<
@ -77,7 +77,7 @@ namespace Point_set {
#ifdef DOXYGEN_RUNNING #ifdef DOXYGEN_RUNNING
/*! /*!
a model of `ReadPropertyMap` whose key and value type is `std::size_t`. a model of `ReadablePropertyMap` whose key and value type is `std::size_t`.
This map provides an access to the ordered indices of input points. This map provides an access to the ordered indices of input points.
*/ */
typedef unspecified_type Seed_map; typedef unspecified_type Seed_map;

View File

@ -57,7 +57,7 @@ namespace Point_set {
a model of `ConstRange` whose iterator type is `RandomAccessIterator` a model of `ConstRange` whose iterator type is `RandomAccessIterator`
\tparam PointMap \tparam PointMap
a model of `ReadPropertyMap` whose key type is the value type of the input a model of `LValuePropertyMap` whose key type is the value type of the input
range and value type is `Kernel::Point_2` or `Kernel::Point_3` range and value type is `Kernel::Point_2` or `Kernel::Point_3`
\cgalModels `NeighborQuery` \cgalModels `NeighborQuery`

View File

@ -69,7 +69,7 @@ namespace Polygon_mesh {
value type is the face type of a polygon mesh value type is the face type of a polygon mesh
\tparam VertexToPointMap \tparam VertexToPointMap
a model of `ReadPropertyMap` whose key type is the vertex type of a polygon mesh and a model of `LValuePropertyMap` whose key type is the vertex type of a polygon mesh and
value type is `Kernel::Point_3` value type is `Kernel::Point_3`
\cgalModels `RegionType` \cgalModels `RegionType`
@ -182,6 +182,9 @@ namespace Polygon_mesh {
m_cos_value_threshold = parameters::choose_parameter( m_cos_value_threshold = parameters::choose_parameter(
parameters::get_parameter(np, internal_np::cos_value_threshold), cos_value_threshold); parameters::get_parameter(np, internal_np::cos_value_threshold), cos_value_threshold);
CGAL_precondition(m_cos_value_threshold >= FT(0) && m_cos_value_threshold <= FT(1)); CGAL_precondition(m_cos_value_threshold >= FT(0) && m_cos_value_threshold <= FT(1));
m_sort_regions = parameters::choose_parameter(
parameters::get_parameter(np, internal_np::sort_regions), false);
} }
/// @} /// @}
@ -354,6 +357,7 @@ namespace Polygon_mesh {
FT m_distance_threshold; FT m_distance_threshold;
FT m_cos_value_threshold; FT m_cos_value_threshold;
std::size_t m_min_region_size; std::size_t m_min_region_size;
bool m_sort_regions;
const Vertex_to_point_map m_vertex_to_point_map; const Vertex_to_point_map m_vertex_to_point_map;

View File

@ -65,7 +65,7 @@ namespace Polygon_mesh {
value type is the face type of a polygon mesh value type is the face type of a polygon mesh
\tparam VertexToPointMap \tparam VertexToPointMap
a model of `ReadPropertyMap` whose key type is the vertex type of a polygon mesh and a model of `LValuePropertyMap` whose key type is the vertex type of a polygon mesh and
value type is `Kernel::Point_3` value type is `Kernel::Point_3`
*/ */
template< template<
@ -91,7 +91,7 @@ namespace Polygon_mesh {
#ifdef DOXYGEN_RUNNING #ifdef DOXYGEN_RUNNING
/*! /*!
a model of `ReadPropertyMap` whose key and value type is `std::size_t`. a model of `ReadablePropertyMap` whose key and value type is `std::size_t`.
This map provides an access to the ordered indices of polygon mesh faces. This map provides an access to the ordered indices of polygon mesh faces.
*/ */
typedef unspecified_type Seed_map; typedef unspecified_type Seed_map;

View File

@ -52,15 +52,12 @@ namespace internal {
reference operator[](const key_type item_index) const { reference operator[](const key_type item_index) const {
CGAL_precondition(item_index < m_item_range.size()); CGAL_precondition(item_index < m_item_range.size());
const auto& key = *(m_item_range.begin() + item_index); const auto& key = *(m_item_range.begin() + item_index);
return get(m_property_map, key); return get(m_property_map, key);
} }
friend inline reference get( friend inline reference get(
const Item_property_map& item_map, const Item_property_map& item_map, const key_type key) {
const key_type key) {
return item_map[key]; return item_map[key];
} }
@ -80,7 +77,7 @@ namespace internal {
using value_type = std::size_t; using value_type = std::size_t;
using key_type = Item; using key_type = Item;
using category = boost::lvalue_property_map_tag; using category = boost::readable_property_map_tag;
using Item_map = std::map<key_type, value_type>; using Item_map = std::map<key_type, value_type>;
@ -103,9 +100,7 @@ namespace internal {
} }
friend inline value_type get( friend inline value_type get(
const Item_to_index_property_map& item_to_index_map, const Item_to_index_property_map& item_to_index_map, const key_type& key) {
const key_type& key) {
return item_to_index_map[key]; return item_to_index_map[key];
} }
@ -119,7 +114,7 @@ namespace internal {
public: public:
using key_type = std::size_t; using key_type = std::size_t;
using value_type = std::size_t; using value_type = std::size_t;
using category = boost::lvalue_property_map_tag; using category = boost::readable_property_map_tag;
Seed_property_map( Seed_property_map(
const std::vector<std::size_t>& seeds) : const std::vector<std::size_t>& seeds) :
@ -131,9 +126,7 @@ namespace internal {
} }
friend value_type get( friend value_type get(
const Seed_property_map& seed_map, const Seed_property_map& seed_map, const key_type key) {
const key_type key) {
return seed_map[key]; return seed_map[key];
} }
@ -141,11 +134,7 @@ namespace internal {
const std::vector<std::size_t>& m_seeds; const std::vector<std::size_t>& m_seeds;
}; };
} // namespace internal class Point_to_region_index_map {
namespace RG {
class Point_to_shape_index_map {
public: public:
using key_type = std::size_t; using key_type = std::size_t;
@ -153,24 +142,24 @@ namespace RG {
using reference = value_type; using reference = value_type;
using category = boost::readable_property_map_tag; using category = boost::readable_property_map_tag;
Point_to_shape_index_map() { } Point_to_region_index_map() { }
template<typename PointRange> template<typename PointRange>
Point_to_shape_index_map( Point_to_region_index_map(
const PointRange& points, const PointRange& points,
const std::vector< std::vector<std::size_t> >& regions) : const std::vector< std::vector<std::size_t> >& regions) :
m_indices(new std::vector<int>(points.size(), -1)) { m_indices(new std::vector<int>(points.size(), -1)) {
for (std::size_t i = 0; i < regions.size(); ++i) for (std::size_t i = 0; i < regions.size(); ++i)
for (const std::size_t idx : regions[i]) for (const std::size_t index : regions[i])
(*m_indices)[idx] = static_cast<int>(i); (*m_indices)[index] = static_cast<int>(i);
} }
inline friend value_type get( inline friend value_type get(
const Point_to_shape_index_map& point_to_shape_index_map, const Point_to_region_index_map& point_to_region_index_map,
const key_type key) { const key_type key) {
const auto& indices = *(point_to_shape_index_map.m_indices); const auto& indices = *(point_to_region_index_map.m_indices);
return indices[key]; return indices[key];
} }
@ -178,7 +167,7 @@ namespace RG {
std::shared_ptr< std::vector<int> > m_indices; std::shared_ptr< std::vector<int> > m_indices;
}; };
} // namespace RG } // namespace internal
} // namespace Shape_detection } // namespace Shape_detection
} // namespace CGAL } // namespace CGAL

View File

@ -18,6 +18,7 @@
// STL includes. // STL includes.
#include <vector> #include <vector>
#include <algorithm>
// Boost headers. // Boost headers.
#include <boost/mpl/has_xxx.hpp> #include <boost/mpl/has_xxx.hpp>
@ -27,6 +28,7 @@
#include <CGAL/number_utils.h> #include <CGAL/number_utils.h>
#include <CGAL/Cartesian_converter.h> #include <CGAL/Cartesian_converter.h>
#include <CGAL/Eigen_diagonalize_traits.h> #include <CGAL/Eigen_diagonalize_traits.h>
#include <CGAL/linear_least_squares_fitting_2.h>
#include <CGAL/linear_least_squares_fitting_3.h> #include <CGAL/linear_least_squares_fitting_3.h>
#include <CGAL/Exact_predicates_inexact_constructions_kernel.h> #include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
@ -42,8 +44,7 @@ namespace internal {
using FT = typename Traits::FT; using FT = typename Traits::FT;
public: public:
FT operator()(const FT value) const { const FT operator()(const FT value) const {
CGAL_precondition(value >= FT(0)); CGAL_precondition(value >= FT(0));
return static_cast<FT>(CGAL::sqrt(CGAL::to_double(value))); return static_cast<FT>(CGAL::sqrt(CGAL::to_double(value)));
} }
@ -80,29 +81,74 @@ namespace internal {
template<typename FT> template<typename FT>
struct Compare_scores { struct Compare_scores {
const std::vector<FT>& m_scores;
const std::vector<FT>& m_scores;
Compare_scores(const std::vector<FT>& scores) : Compare_scores(const std::vector<FT>& scores) :
m_scores(scores) m_scores(scores)
{ } { }
bool operator()(const std::size_t i, const std::size_t j) const { bool operator()(const std::size_t i, const std::size_t j) const {
CGAL_precondition(i < m_scores.size()); CGAL_precondition(i < m_scores.size());
CGAL_precondition(j < m_scores.size()); CGAL_precondition(j < m_scores.size());
return m_scores[i] > m_scores[j]; return m_scores[i] > m_scores[j];
} }
}; };
template<
typename InputRange,
typename PointMap,
typename Line_2>
const typename Kernel_traits<Line_2>::Kernel::FT
create_line_from_points_2(
const InputRange& input_range, const PointMap point_map,
const std::vector<std::size_t>& region, Line_2& line) {
using Traits = typename Kernel_traits<Line_2>::Kernel;
using FT = typename Traits::FT;
using ITraits = CGAL::Exact_predicates_inexact_constructions_kernel;
using IConverter = Cartesian_converter<Traits, ITraits>;
using IFT = typename ITraits::FT;
using IPoint_2 = typename ITraits::Point_2;
using ILine_2 = typename ITraits::Line_2;
std::vector<IPoint_2> points;
CGAL_precondition(region.size() > 0);
points.reserve(region.size());
const IConverter iconverter = IConverter();
for (const std::size_t point_index : region) {
CGAL_precondition(point_index < input_range.size());
const auto& key = *(input_range.begin() + point_index);
const auto& point = get(point_map, key);
points.push_back(iconverter(point));
}
CGAL_postcondition(points.size() == region.size());
ILine_2 fitted_line;
IPoint_2 fitted_centroid;
const IFT score = CGAL::linear_least_squares_fitting_2(
points.begin(), points.end(),
fitted_line, fitted_centroid,
CGAL::Dimension_tag<0>(), ITraits(),
CGAL::Eigen_diagonalize_traits<IFT, 2>());
line = Line_2(
static_cast<FT>(fitted_line.a()),
static_cast<FT>(fitted_line.b()),
static_cast<FT>(fitted_line.c()));
return static_cast<FT>(score);
}
template< template<
typename InputRange, typename InputRange,
typename PointMap, typename PointMap,
typename Plane_3> typename Plane_3>
void create_planes_from_points( const typename Kernel_traits<Plane_3>::Kernel::FT
const InputRange& input_range, create_plane_from_points(
const PointMap point_map, const InputRange& input_range, const PointMap point_map,
std::vector< std::vector<std::size_t> >& regions, const std::vector<std::size_t>& region, Plane_3& plane) {
std::vector<Plane_3>& planes) {
using Traits = typename Kernel_traits<Plane_3>::Kernel; using Traits = typename Kernel_traits<Plane_3>::Kernel;
using FT = typename Traits::FT; using FT = typename Traits::FT;
@ -114,98 +160,56 @@ namespace internal {
using IPoint_3 = typename ITraits::Point_3; using IPoint_3 = typename ITraits::Point_3;
using IPlane_3 = typename ITraits::Plane_3; using IPlane_3 = typename ITraits::Plane_3;
std::vector<IPoint_3> points;
CGAL_precondition(region.size() > 0);
points.reserve(region.size());
const IConverter iconverter = IConverter();
for (const std::size_t point_index : region) {
CGAL_precondition(point_index < input_range.size());
const auto& key = *(input_range.begin() + point_index);
const auto& point = get(point_map, key);
points.push_back(iconverter(point));
}
CGAL_postcondition(points.size() == region.size());
IPlane_3 fitted_plane;
IPoint_3 fitted_centroid;
const IFT score = CGAL::linear_least_squares_fitting_3(
points.begin(), points.end(),
fitted_plane, fitted_centroid,
CGAL::Dimension_tag<0>(), ITraits(),
CGAL::Eigen_diagonalize_traits<IFT, 3>());
plane = Plane_3(
static_cast<FT>(fitted_plane.a()),
static_cast<FT>(fitted_plane.b()),
static_cast<FT>(fitted_plane.c()),
static_cast<FT>(fitted_plane.d()));
return static_cast<FT>(score);
}
template<
typename InputRange,
typename PointMap,
typename Plane_3>
void create_planes_from_points(
const InputRange& input_range, const PointMap point_map,
std::vector< std::vector<std::size_t> >& regions,
std::vector<Plane_3>& planes) {
planes.clear(); planes.clear();
planes.reserve(regions.size()); planes.reserve(regions.size());
std::vector<IPoint_3> points; Plane_3 plane;
const IConverter iconverter = IConverter();
for (const auto& region : regions) { for (const auto& region : regions) {
CGAL_assertion(region.size() > 0); create_plane_from_points(input_range, point_map, region, plane);
points.clear();
for (const std::size_t point_index : region) {
CGAL_precondition(point_index < input_range.size());
const auto& key = *(input_range.begin() + point_index);
const auto& point = get(point_map, key);
points.push_back(iconverter(point));
}
CGAL_postcondition(points.size() == region.size());
IPlane_3 fitted_plane;
IPoint_3 fitted_centroid;
CGAL::linear_least_squares_fitting_3(
points.begin(), points.end(),
fitted_plane, fitted_centroid,
CGAL::Dimension_tag<0>(), ITraits(),
CGAL::Eigen_diagonalize_traits<IFT, 3>());
const Plane_3 plane = Plane_3(
static_cast<FT>(fitted_plane.a()),
static_cast<FT>(fitted_plane.b()),
static_cast<FT>(fitted_plane.c()),
static_cast<FT>(fitted_plane.d()));
planes.push_back(plane); planes.push_back(plane);
} }
CGAL_postcondition(planes.size() == regions.size()); CGAL_postcondition(planes.size() == regions.size());
} }
} // namespace internal } // namespace internal
namespace RG {
template<typename GeomTraits>
class Plane {
public:
using Traits = GeomTraits;
using FT = typename Traits::FT;
using Point_2 = typename Traits::Point_2;
using Point_3 = typename Traits::Point_3;
using Plane_3 = typename Traits::Plane_3;
using Vector_3 = typename Traits::Vector_3;
template<
typename Input_range,
typename Point_map>
Plane(
const Input_range& input_range,
const Point_map point_map,
const std::vector<std::size_t>& region,
const Plane_3& plane) {
FT x = FT(0), y = FT(0), z = FT(0);
for (const std::size_t idx : region) {
const auto& p = get(point_map, *(input_range.begin() + idx));
x += p.x();
y += p.y();
z += p.z();
}
x /= static_cast<FT>(region.size());
y /= static_cast<FT>(region.size());
z /= static_cast<FT>(region.size());
m_centroid = Point_3(x, y, z);
m_base1 = plane.base1() / static_cast<FT>(CGAL::sqrt(
CGAL::to_double(plane.base1() * plane.base1())));
m_base2 = plane.base2() / static_cast<FT>(CGAL::sqrt(
CGAL::to_double(plane.base2() * plane.base2())));
}
Point_2 to_2d(const Point_3& query) const {
const Vector_3 v(m_centroid, query);
return Point_2(v * m_base1, v * m_base2);
}
Point_3 to_3d(const Point_2& query) const {
return m_centroid + query.x() * m_base1 + query.y() * m_base2;
}
private:
Point_3 m_centroid;
Vector_3 m_base1, m_base2;
};
} // namespace RG
} // namespace Shape_detection } // namespace Shape_detection
} // namespace CGAL } // namespace CGAL

View File

@ -83,8 +83,8 @@ bool test_region_growing_on_degenerated_mesh(int argc, char *argv[]) {
region_growing.detect(std::back_inserter(regions)); region_growing.detect(std::back_inserter(regions));
// Test data. // Test data.
assert(regions.size() >= 265 && regions.size() <= 269); assert(regions.size() >= 260 && regions.size() <= 264);
if (regions.size() < 265 || regions.size() > 269) if (regions.size() < 260 || regions.size() > 264)
return false; return false;
for (const auto& region : regions) for (const auto& region : regions)
@ -94,8 +94,8 @@ bool test_region_growing_on_degenerated_mesh(int argc, char *argv[]) {
std::vector<std::size_t> unassigned_faces; std::vector<std::size_t> unassigned_faces;
region_growing.unassigned_items(std::back_inserter(unassigned_faces)); region_growing.unassigned_items(std::back_inserter(unassigned_faces));
assert(unassigned_faces.size() >= 501 && unassigned_faces.size() <= 521); assert(unassigned_faces.size() >= 493 && unassigned_faces.size() <= 513);
if (unassigned_faces.size() < 501 || unassigned_faces.size() > 521) if (unassigned_faces.size() < 493 || unassigned_faces.size() > 513)
return false; return false;
return true; return true;

View File

@ -82,8 +82,8 @@ bool test_region_growing_on_polygon_mesh(int argc, char *argv[]) {
region_growing.detect(std::back_inserter(regions)); region_growing.detect(std::back_inserter(regions));
// Test data. // Test data.
assert(regions.size() >= 324 && regions.size() <= 328); assert(regions.size() >= 325 && regions.size() <= 334);
if (regions.size() < 324 || regions.size() > 328) if (regions.size() < 325 || regions.size() > 334)
return false; return false;
for (const auto& region : regions) for (const auto& region : regions)
@ -93,8 +93,8 @@ bool test_region_growing_on_polygon_mesh(int argc, char *argv[]) {
std::vector<std::size_t> unassigned_faces; std::vector<std::size_t> unassigned_faces;
region_growing.unassigned_items(std::back_inserter(unassigned_faces)); region_growing.unassigned_items(std::back_inserter(unassigned_faces));
assert(unassigned_faces.size() >= 904 && unassigned_faces.size() <= 924); assert(unassigned_faces.size() >= 908 && unassigned_faces.size() <= 928);
if (unassigned_faces.size() < 904 || unassigned_faces.size() > 924) if (unassigned_faces.size() < 908 || unassigned_faces.size() > 928)
return false; return false;
return true; return true;

View File

@ -7,4 +7,4 @@
- cleanup the code - cleanup the code
- finish new tests - finish new tests
- update the docs - update the docs
- remove sqrt - do not use Plane_3 from RG namespace in the polyhedron demo