From 367f3805ad290fd1d0404475793c901b282e3bc0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Loriot?= Date: Tue, 19 Jul 2022 17:33:04 +0200 Subject: [PATCH] remove region growing on polylines not being able to share vertices does not really make sense for a polyline. Segment_set should be used instead --- .../Shape_detection/Concepts/NeighborQuery.h | 1 - .../doc/Shape_detection/Concepts/RegionType.h | 1 - .../Shape_detection/PackageDescription.txt | 11 - .../doc/Shape_detection/Shape_detection.txt | 30 +- .../doc/Shape_detection/examples.txt | 1 - .../region_growing_on_polyline.png | Bin 10688 -> 0 bytes .../examples/Shape_detection/CMakeLists.txt | 4 +- .../region_growing_lines_on_polyline.cpp | 121 ------ .../CGAL/Shape_detection/Region_growing.h | 1 - .../Shape_detection/Region_growing/Polyline.h | 31 -- .../Polyline/Least_squares_line_fit_region.h | 369 ------------------ .../Polyline/Least_squares_line_fit_sorting.h | 205 ---------- .../Polyline/One_ring_neighbor_query.h | 130 ------ .../Region_growing/free_functions.h | 77 ---- .../internal/region_growing_traits.h | 18 - .../test/Shape_detection/CMakeLists.txt | 4 - .../test_region_growing_on_polyline.cpp | 158 -------- ...egion_growing_on_polyline_with_sorting.cpp | 175 --------- .../test_region_growing_strict.cpp | 71 ---- 19 files changed, 2 insertions(+), 1406 deletions(-) delete mode 100644 Shape_detection/doc/Shape_detection/fig/Region_growing/region_growing_on_polyline.png delete mode 100644 Shape_detection/examples/Shape_detection/region_growing_lines_on_polyline.cpp delete mode 100644 Shape_detection/include/CGAL/Shape_detection/Region_growing/Polyline.h delete mode 100644 Shape_detection/include/CGAL/Shape_detection/Region_growing/Polyline/Least_squares_line_fit_region.h delete mode 100644 Shape_detection/include/CGAL/Shape_detection/Region_growing/Polyline/Least_squares_line_fit_sorting.h delete mode 100644 Shape_detection/include/CGAL/Shape_detection/Region_growing/Polyline/One_ring_neighbor_query.h delete mode 100644 Shape_detection/test/Shape_detection/test_region_growing_on_polyline.cpp delete mode 100644 Shape_detection/test/Shape_detection/test_region_growing_on_polyline_with_sorting.cpp diff --git a/Shape_detection/doc/Shape_detection/Concepts/NeighborQuery.h b/Shape_detection/doc/Shape_detection/Concepts/NeighborQuery.h index bbd1ff2c654..5495e5d0c9a 100644 --- a/Shape_detection/doc/Shape_detection/Concepts/NeighborQuery.h +++ b/Shape_detection/doc/Shape_detection/Concepts/NeighborQuery.h @@ -10,7 +10,6 @@ to access neighbors of an item. - `CGAL::Shape_detection::Point_set::Sphere_neighbor_query` - `CGAL::Shape_detection::Polygon_mesh::Polyline_graph` - `CGAL::Shape_detection::Polygon_mesh::One_ring_neighbor_query` -- `CGAL::Shape_detection::Polyline::One_ring_neighbor_query` */ class NeighborQuery { diff --git a/Shape_detection/doc/Shape_detection/Concepts/RegionType.h b/Shape_detection/doc/Shape_detection/Concepts/RegionType.h index 2f7e065ad00..8a43af29e13 100644 --- a/Shape_detection/doc/Shape_detection/Concepts/RegionType.h +++ b/Shape_detection/doc/Shape_detection/Concepts/RegionType.h @@ -15,7 +15,6 @@ A region is represented by a set items, which are included in this region. - `CGAL::Shape_detection::Point_set::Least_squares_cylinder_fit_region` - `CGAL::Shape_detection::Segment_set::Least_squares_line_fit_region` - `CGAL::Shape_detection::Polygon_mesh::Least_squares_plane_fit_region` -- `CGAL::Shape_detection::Polyline::Least_squares_line_fit_region` */ class RegionType { diff --git a/Shape_detection/doc/Shape_detection/PackageDescription.txt b/Shape_detection/doc/Shape_detection/PackageDescription.txt index 81db90f7a8e..c1ee0095c6a 100644 --- a/Shape_detection/doc/Shape_detection/PackageDescription.txt +++ b/Shape_detection/doc/Shape_detection/PackageDescription.txt @@ -29,12 +29,6 @@ for shape detection in a segment set. Models that can be used with the `CGAL::Shape_detection::Region_growing` for shape detection on a polygon mesh. -\defgroup PkgShapeDetectionRGOnPolyline Polyline -\ingroup PkgShapeDetectionRG - -Models that can be used with the `CGAL::Shape_detection::Region_growing` -for shape detection on a polyline. - \addtogroup PkgShapeDetectionRG \defgroup PkgShapeDetectionRANSAC Efficient RANSAC @@ -142,9 +136,4 @@ and the Region Growing approach for detecting shapes in a set of arbitrary items - `CGAL::Shape_detection::Polygon_mesh::Least_squares_plane_fit_region` - `CGAL::Shape_detection::Polygon_mesh::Least_squares_plane_fit_sorting` -### Polyline ### -- `CGAL::Shape_detection::Polyline::One_ring_neighbor_query` -- `CGAL::Shape_detection::Polyline::Least_squares_line_fit_region` -- `CGAL::Shape_detection::Polyline::Least_squares_line_fit_sorting` - */ diff --git a/Shape_detection/doc/Shape_detection/Shape_detection.txt b/Shape_detection/doc/Shape_detection/Shape_detection.txt index 1bd31631cdb..0da8321b010 100644 --- a/Shape_detection/doc/Shape_detection/Shape_detection.txt +++ b/Shape_detection/doc/Shape_detection/Shape_detection.txt @@ -239,7 +239,6 @@ Together with the generic algorithm's implementation `CGAL::Shape_detection::Reg - Line and circle detection in a \ref Shape_detection_RegionGrowingPoints "2D point set"; - Line detection in a \ref Shape_detection_RegionGrowingSegments "2D/3D segment set"; -- Line detection on a \ref Shape_detection_RegionGrowingPolyline "2D/3D polyline"; - Plane, sphere, and cylinder detection in a \ref Shape_detection_RegionGrowingPoints "3D point set"; - Plane detection on a \ref Shape_detection_RegionGrowingMesh "polygon mesh". @@ -616,33 +615,6 @@ More details are explained in Section \ref Shape_detection_RegionGrowingFramework_conditions "Framework Regions". The right choice of these parameters is important for producing the good results. - -\subsection Shape_detection_RegionGrowingPolyline Polyline - -\cgalFigureBegin{Region_growing_on_polyline, Region_growing/region_growing_on_polyline.png} -A 3D polyline depicted with one color per detected line. -\cgalFigureEnd - -If one wants to detect lines along a 2D or 3D polyline, one can use the -- `CGAL::Shape_detection::Polyline::Least_squares_line_fit_region` class that fits a 2D or 3D line -to the chunks of polyline vertices, respectively, and controls the quality of this fit. - -As before, one can improve the quality of the region growing by using the class -- `CGAL::Shape_detection::Polyline::Least_squares_line_fit_sorting` - the input vertices are sorted with respect -to the quality of the least squares line fit applied to the neighbors of each vertex. - - -\subsubsection Shape_detection_RegionGrowingPolyline_parameters Parameters - -The line fitting class above depends on three parameters: - -- `maximum_distance` - the maximum distance from the polyline vertex to a line; -- `maximum_angle` - the maximum angle in degrees between the polyline edge direction and the direction of a line; -- `minimum_region_size` - the minimum number of vertices a region must have. - -As already mentioned, the right choice of these parameters is important for producing the good results. - - \section Shape_detection_Comparison Comparison The Efficient RANSAC algorithm is very quick, however, since it is not deterministic, some small shapes might be missed in the detection process. @@ -699,7 +671,7 @@ with the help of Clément Jamin and under the supervision of Pierre Alliez. The region growing algorithm on a 3D point set was first implemented by Simon Giraudot based on the prototype version developed by Florent Lafarge and then generalized to arbitrary items including versions for a 2D point set, a 3D point set, and a polygon mesh by Thien Hoang during the -Google Summer of Code 2018 under the supervision of Dmitry Anisimov. The versions for segments and polylines were added later by Dmitry Anisimov. +Google Summer of Code 2018 under the supervision of Dmitry Anisimov. The version for segments was added later by Dmitry Anisimov. \section Shape_detection_Acknowledgments Acknowledgments diff --git a/Shape_detection/doc/Shape_detection/examples.txt b/Shape_detection/doc/Shape_detection/examples.txt index 6bb1d677442..3396294943b 100644 --- a/Shape_detection/doc/Shape_detection/examples.txt +++ b/Shape_detection/doc/Shape_detection/examples.txt @@ -13,5 +13,4 @@ \example Shape_detection/region_growing_cylinders_on_point_set_3.cpp \example Shape_detection/region_growing_planes_on_polygon_mesh.cpp \example Shape_detection/region_growing_lines_on_segment_set.cpp -\example Shape_detection/region_growing_lines_on_polyline.cpp */ diff --git a/Shape_detection/doc/Shape_detection/fig/Region_growing/region_growing_on_polyline.png b/Shape_detection/doc/Shape_detection/fig/Region_growing/region_growing_on_polyline.png deleted file mode 100644 index 3800c62e83116bbacf3c0f33b45a1880f72ad3ad..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 10688 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 -#include -#include - -// Typedefs. -using Kernel = CGAL::Simple_cartesian; -using FT = typename Kernel::FT; -using Point_2 = typename Kernel::Point_2; -using Point_3 = typename Kernel::Point_3; -using Plane_3 = typename Kernel::Plane_3; - -using Polyline_2 = std::vector; -using Polyline_3 = std::vector; -using Point_map_2 = CGAL::Identity_property_map; -using Point_map_3 = CGAL::Identity_property_map; - -using Neighbor_query_2 = CGAL::Shape_detection::Polyline::One_ring_neighbor_query; -using Region_type_2 = CGAL::Shape_detection::Polyline::Least_squares_line_fit_region; -using Region_growing_2 = CGAL::Shape_detection::Region_growing; - -using Neighbor_query_3 = CGAL::Shape_detection::Polyline::One_ring_neighbor_query; -using Region_type_3 = CGAL::Shape_detection::Polyline::Least_squares_line_fit_region; -using Region_growing_3 = CGAL::Shape_detection::Region_growing; - -int main(int argc, char *argv[]) { - - // Load polyline data either from a local folder or a user-provided file. - const bool is_default_input = argc > 1 ? false : true; - std::ifstream in(is_default_input ? CGAL::data_file_path("polylines_3/wavy_circle.polylines.txt") : argv[1]); - CGAL::IO::set_ascii_mode(in); - if (!in) { - std::cerr << "ERROR: cannot read the input file!" << std::endl; - return EXIT_FAILURE; - } - - Polyline_3 polyline_3; - std::size_t n = std::size_t(-1); - in >> n; - polyline_3.reserve(n); - while (n--) { - Point_3 point; in >> point; - polyline_3.push_back(point); - if (!in.good()) { - std::cout << "ERROR: cannot load a polyline!" << std::endl; - return EXIT_FAILURE; - } - } - in.close(); - std::cout << "* number of input vertices: " << polyline_3.size() << std::endl; - assert(is_default_input && polyline_3.size() == 249); - - // Default parameter values for the data file wavy_circle.polylines.txt. - const FT max_distance = FT(45) / FT(10); - const FT max_angle = FT(45); - - // Setting up the 3D polyline algorithm. - Neighbor_query_3 neighbor_query_3(polyline_3); - Region_type_3 region_type_3( - polyline_3, - CGAL::parameters:: - maximum_distance(max_distance). - maximum_angle(max_angle)); - Region_growing_3 region_growing_3( - polyline_3, neighbor_query_3, region_type_3); - - // Run the algorithm on a 3D polyline. - std::vector regions; - region_growing_3.detect(std::back_inserter(regions)); - std::cout << "* number of found 3D regions: " << regions.size() << std::endl; - assert(is_default_input && regions.size() == 17); - - // Save 3D regions to a file. - std::string fullpath = (argc > 2 ? argv[2] : "regions_polyline_3.ply"); - utils::save_point_regions_3, Point_map_3>( - regions, fullpath); - - // Create the 2D polyline. - Plane_3 plane; Point_3 centroid; - CGAL::linear_least_squares_fitting_3( - polyline_3.begin(), polyline_3.end(), plane, centroid, - CGAL::Dimension_tag<0>(), Kernel(), - CGAL::Eigen_diagonalize_traits()); - - Polyline_2 polyline_2; - polyline_2.reserve(polyline_3.size()); - for (const auto& point : polyline_3) { - const auto p3 = plane.projection(point); - const auto p2 = plane.to_2d(p3); - polyline_2.push_back(p2); - } - assert(is_default_input && polyline_2.size() == polyline_3.size()); - - // Setting up the 2D polyline algorithm. - Neighbor_query_2 neighbor_query_2(polyline_2); - Region_type_2 region_type_2( - polyline_2, - CGAL::parameters:: - maximum_distance(max_distance). - maximum_angle(max_angle)); - Region_growing_2 region_growing_2( - polyline_2, neighbor_query_2, region_type_2); - - // Run the algorithm on a 2D polyline. - std::vector regions2; - region_growing_2.detect(std::back_inserter(regions2)); - std::cout << "* number of found 2D regions: " << regions2.size() << std::endl; - assert(is_default_input && regions2.size() == 5); - - // Save 2D regions to a file. - polyline_3.clear(); - for (const auto& p2 : polyline_2) { - polyline_3.push_back(plane.to_3d(p2)); - } - - fullpath = (argc > 2 ? argv[2] : "regions_polyline_2.ply"); - utils::save_point_regions_2, Point_map_2>( - regions2, fullpath); - - return EXIT_SUCCESS; -} diff --git a/Shape_detection/include/CGAL/Shape_detection/Region_growing.h b/Shape_detection/include/CGAL/Shape_detection/Region_growing.h index 10e9778b09a..fbf75985850 100644 --- a/Shape_detection/include/CGAL/Shape_detection/Region_growing.h +++ b/Shape_detection/include/CGAL/Shape_detection/Region_growing.h @@ -28,6 +28,5 @@ #include #include #include -#include #endif // CGAL_SHAPE_DETECTION_REGION_GROWING_HEADERS_H diff --git a/Shape_detection/include/CGAL/Shape_detection/Region_growing/Polyline.h b/Shape_detection/include/CGAL/Shape_detection/Region_growing/Polyline.h deleted file mode 100644 index 47a90aaa818..00000000000 --- a/Shape_detection/include/CGAL/Shape_detection/Region_growing/Polyline.h +++ /dev/null @@ -1,31 +0,0 @@ -// Copyright (c) 2020 GeometryFactory SARL (France). -// All rights reserved. -// -// This file is part of CGAL (www.cgal.org). -// -// $URL$ -// $Id$ -// SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-Commercial -// -// -// Author(s) : Dmitry Anisimov -// - -#ifndef CGAL_SHAPE_DETECTION_REGION_GROWING_POLYLINE_H -#define CGAL_SHAPE_DETECTION_REGION_GROWING_POLYLINE_H - -/// \cond SKIP_IN_MANUAL -#include -/// \endcond - -/** -* \ingroup PkgShapeDetectionRef -* \file CGAL/Shape_detection/Region_growing/Polyline.h -* A convenience header that includes all classes related to the region growing algorithm on a polyline. -*/ - -#include -#include -#include - -#endif // CGAL_SHAPE_DETECTION_REGION_GROWING_POLYLINE_H diff --git a/Shape_detection/include/CGAL/Shape_detection/Region_growing/Polyline/Least_squares_line_fit_region.h b/Shape_detection/include/CGAL/Shape_detection/Region_growing/Polyline/Least_squares_line_fit_region.h deleted file mode 100644 index 60900b0ff9c..00000000000 --- a/Shape_detection/include/CGAL/Shape_detection/Region_growing/Polyline/Least_squares_line_fit_region.h +++ /dev/null @@ -1,369 +0,0 @@ -// Copyright (c) 2020 GeometryFactory SARL (France). -// All rights reserved. -// -// This file is part of CGAL (www.cgal.org). -// -// $URL$ -// $Id$ -// SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-Commercial -// -// -// Author(s) : Dmitry Anisimov -// - -#ifndef CGAL_SHAPE_DETECTION_REGION_GROWING_POLYLINE_LEAST_SQUARES_LINE_FIT_REGION_H -#define CGAL_SHAPE_DETECTION_REGION_GROWING_POLYLINE_LEAST_SQUARES_LINE_FIT_REGION_H - -#include - -// Boost includes. -#include - -// Internal includes. -#include -#include - -namespace CGAL { -namespace Shape_detection { -namespace Polyline { - - /*! - \ingroup PkgShapeDetectionRGOnPolyline - - \brief Region type based on the quality of the least squares line - fit applied to the vertices of a polyline. - - This class fits a line, using \ref PkgPrincipalComponentAnalysisDRef "PCA", - to chunks of polyline vertices and controls the quality of this fit. - If all quality conditions are satisfied, the chunk is accepted as a valid region, - otherwise rejected. - - \tparam GeomTraits - a model of `Kernel` - - \tparam InputRange - a model of `ConstRange` whose iterator type is `RandomAccessIterator` - - \tparam PointMap - a model of `ReadablePropertyMap` whose key type is the value type of the input - range and value type is `Kernel::Point_2` or `Kernel::Point_3` - - \cgalModels `RegionType` - */ - template< - typename GeomTraits, - typename InputRange, - typename PointMap> - class Least_squares_line_fit_region { - - private: - using Polyline_traits = typename std::conditional< - std::is_same::value, - internal::Region_growing_traits_2, - internal::Region_growing_traits_3 >::type; - - public: - /// \name Types - /// @{ - - /// \cond SKIP_IN_MANUAL - using Traits = GeomTraits; - using Input_range = InputRange; - using Point_map = PointMap; - using Point_type = typename Point_map::value_type; - /// \endcond - - /// Item type. - using Item = typename InputRange::const_iterator; - using Region = std::vector; - - /// Number type. - typedef typename GeomTraits::FT FT; - - /// Primitive type depends on the dimension of the input data. -#ifdef DOXYGEN_RUNNING - using Primitive = typename GeomTraits::Line_2 or typename GeomTraits::Line_3 -#else - using Primitive = typename Polyline_traits::Line; -#endif - - /// Region map - using Region_unordered_map = boost::unordered_map >; - using Region_index_map = boost::associative_property_map; - /// @} - - private: - using Point = typename Polyline_traits::Point; - using Vector = typename Polyline_traits::Vector; - using Line = typename Polyline_traits::Line; - - using Squared_length = typename Polyline_traits::Compute_squared_length; - using Squared_distance = typename Polyline_traits::Compute_squared_distance; - using Scalar_product = typename Polyline_traits::Compute_scalar_product; - - public: - /// \name Initialization - /// @{ - - /*! - \brief initializes all internal data structures. - - \tparam NamedParameters - a sequence of \ref bgl_namedparameters "Named Parameters" - - \param input_range - an instance of `InputRange` with polyline vertices - - \param np - a sequence of \ref bgl_namedparameters "Named Parameters" - among the ones listed below - - \cgalNamedParamsBegin - \cgalParamNBegin{maximum_distance} - \cgalParamDescription{the maximum distance from a vertex to a line} - \cgalParamType{`GeomTraits::FT`} - \cgalParamDefault{1} - \cgalParamNEnd - \cgalParamNBegin{maximum_angle} - \cgalParamDescription{the maximum angle in degrees between - the direction of a polyline edge and the direction of a line} - \cgalParamType{`GeomTraits::FT`} - \cgalParamDefault{25 degrees} - \cgalParamNEnd - \cgalParamNBegin{cosine_value} - \cgalParamDescription{the cos value computed as `cos(maximum_angle * PI / 180)`, - this parameter can be used instead of the `maximum_angle`} - \cgalParamType{`GeomTraits::FT`} - \cgalParamDefault{`cos(25 * PI / 180)`} - \cgalParamNEnd - \cgalParamNBegin{minimum_region_size} - \cgalParamDescription{the minimum number of vertices a region must have} - \cgalParamType{`std::size_t`} - \cgalParamDefault{2} - \cgalParamNEnd - \cgalParamNBegin{point_map} - \cgalParamDescription{an instance of `PointMap` that maps an item from `input_range` - to `Kernel::Point_2` or `Kernel::Point_3`} - \cgalParamDefault{`PointMap()`} - \cgalParamNEnd - \cgalParamNBegin{geom_traits} - \cgalParamDescription{an instance of `GeomTraits`} - \cgalParamDefault{`GeomTraits()`} - \cgalParamNEnd - \cgalNamedParamsEnd - - \pre `input_range.size() > 0` - \pre `maximum_distance >= 0` - \pre `maximum_angle >= 0 && maximum_angle <= 90` - \pre `cosine_value >= 0 && cosine_value <= 1` - \pre `minimum_region_size > 0` - */ - template - Least_squares_line_fit_region( - const InputRange& input_range, - const NamedParameters& np = parameters::default_values()) : - m_point_map(parameters::choose_parameter(parameters::get_parameter( - np, internal_np::point_map), PointMap())), - m_traits(parameters::choose_parameter(parameters::get_parameter( - np, internal_np::geom_traits), GeomTraits())), - m_polyline_traits(m_traits), - m_squared_length(m_polyline_traits.compute_squared_length_object()), - m_squared_distance(m_polyline_traits.compute_squared_distance_object()), - m_scalar_product(m_polyline_traits.compute_scalar_product_object()) { - - CGAL_precondition(input_range.size() > 0); - const FT max_distance = parameters::choose_parameter( - parameters::get_parameter(np, internal_np::maximum_distance), FT(1)); - CGAL_precondition(max_distance >= FT(0)); - m_distance_threshold = max_distance; - - const FT max_angle = parameters::choose_parameter( - parameters::get_parameter(np, internal_np::maximum_angle), FT(25)); - CGAL_precondition(max_angle >= FT(0) && max_angle <= FT(90)); - - m_min_region_size = parameters::choose_parameter( - parameters::get_parameter(np, internal_np::minimum_region_size), 2); - CGAL_precondition(m_min_region_size > 0); - - const FT default_cos_value = static_cast(std::cos(CGAL::to_double( - (max_angle * static_cast(CGAL_PI)) / FT(180)))); - const FT cos_value = parameters::choose_parameter( - parameters::get_parameter(np, internal_np::cosine_value), default_cos_value); - CGAL_precondition(cos_value >= FT(0) && cos_value <= FT(1)); - m_cos_value_threshold = cos_value; - } - - /// @} - - /// \name Access - /// @{ - - /*! - \brief implements `RegionType::region_index_map()`. - - This function creates an empty property map that maps iterators on the input range `Item` to std::size_t - */ - Region_index_map region_index_map() { - return Region_index_map(m_region_map); - } - - /*! - \brief implements `RegionType::primitive()`. - - This function provides the last primitive that has been fitted with the region. - - \return Primitive parameters that fits the region - - \pre `successful fitted primitive via successful call of update(region) with a sufficient large region` - */ - Primitive primitive() const { - return m_line_of_best_fit; - } - - /*! - \brief implements `RegionType::is_part_of_region()`. - - This function controls if a vertex with the item `query` is within - the `maximum_distance` from the corresponding line and if the angle between the - direction of the inward edge and the line's direction is within the `maximum_angle`. - If both conditions are satisfied, it returns `true`, otherwise `false`. - - \param previous - `Item` of the previous vertex - - \param query - `Item` of the query vertex - - \return Boolean `true` or `false` - - \pre `region.size() > 0` - \pre `previous` is a valid const_iterator of the input_range. - \pre `query` is a valid const_iterator of the input_range. - */ - bool is_part_of_region( - const Item previous, const Item query, - const Region&) { - - const Point& input_point = get(m_point_map, *previous); - const Point& query_point = get(m_point_map, *query); - - // Update new reference line and direction. - if (m_direction_of_best_fit == CGAL::NULL_VECTOR) { - if (input_point == query_point) return true; - CGAL_precondition(input_point != query_point); - m_line_of_best_fit = Line(input_point, query_point); - m_direction_of_best_fit = m_line_of_best_fit.to_vector(); - return true; - } - CGAL_precondition(m_direction_of_best_fit != CGAL::NULL_VECTOR); - - // Add equal points to the previously defined region. - if (input_point == query_point) return true; - CGAL_precondition(input_point != query_point); - const Vector query_direction(input_point, query_point); - - // Check real conditions. - const FT squared_distance_to_fitted_line = - m_squared_distance(query_point, m_line_of_best_fit); - const FT squared_distance_threshold = - m_distance_threshold * m_distance_threshold; - - const FT cos_value = - m_scalar_product(query_direction, m_direction_of_best_fit); - const FT squared_cos_value = cos_value * cos_value; - - FT squared_cos_value_threshold = - m_cos_value_threshold * m_cos_value_threshold; - squared_cos_value_threshold *= m_squared_length(query_direction); - squared_cos_value_threshold *= m_squared_length(m_direction_of_best_fit); - - return ( - ( squared_distance_to_fitted_line <= squared_distance_threshold ) && - ( squared_cos_value >= squared_cos_value_threshold )); - } - - /*! - \brief implements `RegionType::is_valid_region()`. - - This function controls if the `region` contains at least `minimum_region_size` vertices. - - \param region - Vertices of the region represented as `Items`. - - \return Boolean `true` or `false` - */ - inline bool is_valid_region(const Region& region) const { - if (m_direction_of_best_fit == CGAL::NULL_VECTOR) - return false; // all points are equal - return (region.size() >= m_min_region_size); - } - - /*! - \brief implements `RegionType::update()`. - - This function fits the least squares line to all vertices from the `region`. - - \param region - Vertices of the region represented as `Items`. - - \return Boolean `true` if the line fitting succeeded and `false` otherwise - - \pre `region.size() > 0` - */ - bool update(const Region& region) { - - CGAL_precondition(region.size() > 0); - if (region.size() == 1) { // create new reference line and direction - m_direction_of_best_fit = CGAL::NULL_VECTOR; - } else { // update reference line and direction - if (m_direction_of_best_fit == CGAL::NULL_VECTOR) - return false; // all points are equal - CGAL_precondition(region.size() >= 2); - std::tie(m_line_of_best_fit, m_direction_of_best_fit) = - get_line_and_direction(region); - } - return true; - } - - /// @} - - /// \cond SKIP_IN_MANUAL - std::pair get_line_and_direction( - const Region& region) const { - - // The best fit line will be a line fitted to all region points with - // its direction being the line's direction. - CGAL_precondition(region.size() > 0); - const Line line_of_best_fit = - m_polyline_traits.create_line( - region, m_point_map).first; - const Vector direction_of_best_fit = - line_of_best_fit.to_vector(); - - return std::make_pair(line_of_best_fit, direction_of_best_fit); - } - /// \endcond - - private: - const Point_map m_point_map; - const Traits m_traits; - const Polyline_traits m_polyline_traits; - Region_unordered_map m_region_map; - - FT m_distance_threshold; - FT m_cos_value_threshold; - std::size_t m_min_region_size; - - const Squared_length m_squared_length; - const Squared_distance m_squared_distance; - const Scalar_product m_scalar_product; - - Line m_line_of_best_fit; - Vector m_direction_of_best_fit; - }; - -} // namespace Polyline -} // namespace Shape_detection -} // namespace CGAL - -#endif // CGAL_SHAPE_DETECTION_REGION_GROWING_POLYLINE_LEAST_SQUARES_LINE_FIT_REGION_H diff --git a/Shape_detection/include/CGAL/Shape_detection/Region_growing/Polyline/Least_squares_line_fit_sorting.h b/Shape_detection/include/CGAL/Shape_detection/Region_growing/Polyline/Least_squares_line_fit_sorting.h deleted file mode 100644 index 7710b137922..00000000000 --- a/Shape_detection/include/CGAL/Shape_detection/Region_growing/Polyline/Least_squares_line_fit_sorting.h +++ /dev/null @@ -1,205 +0,0 @@ -// Copyright (c) 2020 GeometryFactory SARL (France). -// All rights reserved. -// -// This file is part of CGAL (www.cgal.org). -// -// $URL$ -// $Id$ -// SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-Commercial -// -// -// Author(s) : Dmitry Anisimov -// - -#ifndef CGAL_SHAPE_DETECTION_REGION_GROWING_POLYLINE_LEAST_SQUARES_LINE_FIT_SORTING_H -#define CGAL_SHAPE_DETECTION_REGION_GROWING_POLYLINE_LEAST_SQUARES_LINE_FIT_SORTING_H - -#include - -// Internal includes. -#include - -namespace CGAL { -namespace Shape_detection { -namespace Polyline { - - /*! - \ingroup PkgShapeDetectionRGOnPolyline - - \brief Sorting of polyline vertices with respect to the local line fit quality. - - `Items` of input vertices are sorted with respect to the quality of the - least squares line fit applied to the incident vertices of each vertex. - - \tparam GeomTraits - a model of `Kernel` - - \tparam InputRange - a model of `ConstRange` whose iterator type is `RandomAccessIterator` - - \tparam NeighborQuery - a model of `NeighborQuery` - - \tparam PointMap - a model of `ReadablePropertyMap` whose key type is the value type of the input - range and value type is `Kernel::Point_2` or `Kernel::Point_3` - */ - template< - typename GeomTraits, - typename InputRange, - typename NeighborQuery, - typename PointMap> - class Least_squares_line_fit_sorting { - - public: - /// \name Types - /// @{ - - /// \cond SKIP_IN_MANUAL - using Input_range = InputRange; - using Neighbor_query = NeighborQuery; - using Point_map = PointMap; - using Point_type = typename Point_map::value_type; - /// \endcond - - /// Item type. - using Item = typename InputRange::const_iterator; - - /// Seed range. - using Seed_range = std::vector; - - /// @} - - private: - using FT = typename GeomTraits::FT; - using Polyline_traits = typename std::conditional< - std::is_same::value, - internal::Region_growing_traits_2, - internal::Region_growing_traits_3 >::type; - using Compare_scores = internal::Compare_scores; - using Dereference_pmap = internal::Dereference_property_map_adaptor; - - public: - /// \name Initialization - /// @{ - - /*! - \brief initializes all internal data structures. - - \tparam NamedParameters - a sequence of \ref bgl_namedparameters "Named Parameters" - - \param input_range - an instance of `InputRange` with polyline vertices - - \param neighbor_query - an instance of `NeighborQuery` that is used internally to - access vertex's neighbors - - \param np - a sequence of \ref bgl_namedparameters "Named Parameters" - among the ones listed below - - \cgalNamedParamsBegin - \cgalParamNBegin{point_map} - \cgalParamDescription{an instance of `PointMap` that maps a vertex from `input_range` - to `Kernel::Point_2` or `Kernel::Point_3`} - \cgalParamDefault{`PointMap()`} - \cgalParamNEnd - \cgalParamNBegin{geom_traits} - \cgalParamDescription{an instance of `GeomTraits`} - \cgalParamDefault{`GeomTraits()`} - \cgalParamNEnd - \cgalNamedParamsEnd - - \pre `input_range.size() > 0` - */ - template - Least_squares_line_fit_sorting( - const InputRange& input_range, - NeighborQuery& neighbor_query, - const NamedParameters& np = parameters::default_values()) : - m_neighbor_query(neighbor_query), - m_point_map(parameters::choose_parameter(parameters::get_parameter( - np, internal_np::point_map), PointMap())), - m_deref_pmap(m_point_map), - m_traits(parameters::choose_parameter(parameters::get_parameter( - np, internal_np::geom_traits), GeomTraits())), - m_polyline_traits(m_traits) { - - CGAL_precondition(input_range.size() > 0); - - m_ordered.resize(input_range.size()); - - std::size_t index = 0; - for (auto it = input_range.begin(); it != input_range.end(); it++) - m_ordered[index++] = it; - - m_scores.resize(input_range.size()); - } - - /// @} - - /// \name Sorting - /// @{ - - /*! - \brief sorts `Items` of input vertices. - */ - void sort() { - compute_scores(); - CGAL_precondition(m_scores.size() > 0); - Compare_scores cmp(m_scores); - - std::vector order(m_ordered.size()); - std::iota(order.begin(), order.end(), 0); - std::sort(order.begin(), order.end(), cmp); - - std::vector tmp(m_ordered.size()); - for (std::size_t i = 0; i < m_ordered.size(); i++) - tmp[i] = m_ordered[order[i]]; - - m_ordered.swap(tmp); - } - /// @} - - /// \name Access - /// @{ - - /*! - \brief returns an instance of `Seed_range` to access the ordered `Items` - of input points. - */ - const Seed_range& ordered() { - return m_ordered; - } - /// @} - - private: - Neighbor_query& m_neighbor_query; - const Point_map m_point_map; - Dereference_pmap m_deref_pmap; - const GeomTraits m_traits; - const Polyline_traits m_polyline_traits; - Seed_range m_ordered; - std::vector m_scores; - - void compute_scores() { - - std::vector neighbors; - std::size_t idx = 0; - for (const Item& item : m_ordered) { - neighbors.clear(); - m_neighbor_query(item, neighbors); - neighbors.push_back(item); - m_scores[idx++] = m_polyline_traits.create_line( - neighbors, m_point_map).second; - } - } - }; - -} // namespace Polyline -} // namespace Shape_detection -} // namespace CGAL - -#endif // #define CGAL_SHAPE_DETECTION_REGION_GROWING_POLYLINE_LEAST_SQUARES_LINE_FIT_SORTING_H diff --git a/Shape_detection/include/CGAL/Shape_detection/Region_growing/Polyline/One_ring_neighbor_query.h b/Shape_detection/include/CGAL/Shape_detection/Region_growing/Polyline/One_ring_neighbor_query.h deleted file mode 100644 index 9ed3fb3e8fb..00000000000 --- a/Shape_detection/include/CGAL/Shape_detection/Region_growing/Polyline/One_ring_neighbor_query.h +++ /dev/null @@ -1,130 +0,0 @@ -// Copyright (c) 2020 GeometryFactory SARL (France). -// All rights reserved. -// -// This file is part of CGAL (www.cgal.org). -// -// $URL$ -// $Id$ -// SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-Commercial -// -// -// Author(s) : Dmitry Anisimov -// - -#ifndef CGAL_SHAPE_DETECTION_REGION_GROWING_POLYLINE_ONE_RING_NEIGHBOR_QUERY_H -#define CGAL_SHAPE_DETECTION_REGION_GROWING_POLYLINE_ONE_RING_NEIGHBOR_QUERY_H - -#include - -// STL includes. -#include - -// CGAL includes. -#include - -namespace CGAL { -namespace Shape_detection { -namespace Polyline { - - /*! - \ingroup PkgShapeDetectionRGOnPolyline - - \brief Direct neighbors connectivity in a polyline. - - This class returns `Items` of the previous and next vertex - in a polyline given as `InputRange.` - - \tparam GeomTraits - a model of `Kernel` - - \tparam InputRange - a model of `ConstRange` whose iterator type is `RandomAccessIterator` - - \cgalModels `NeighborQuery` - */ - template< - typename GeomTraits, - typename InputRange> - class One_ring_neighbor_query { - - public: - /// \cond SKIP_IN_MANUAL - using Traits = GeomTraits; - using Input_range = InputRange; - /// \endcond - - /// Item type. - using Item = typename InputRange::const_iterator; - using Region = std::vector; - - /// \name Initialization - /// @{ - - /*! - \brief initializes all internal data structures. - - \param input_range - an instance of `InputRange` with polyline vertices - - \pre `input_range.size() > 0` - */ - One_ring_neighbor_query( - const InputRange& input_range) : - m_begin(input_range.begin()) , - m_end(input_range.end()) - { - - CGAL_precondition(input_range.size() > 0); - } - - /// @} - - /// \name Access - /// @{ - - /*! - \brief implements `NeighborQuery::operator()()`. - - This operator retrieves the previous and next vertex in a polyline - with respect to the vertex `query`. - The `Items` are returned in `neighbors`. - - \param query - `Item` of the query point - - \param neighbors - `Items` of vertices, which are direct neighbors of the query point - - \pre `query_index < input_range.size()` - */ - void operator()( - const Item query, - std::vector& neighbors) const { - - neighbors.clear(); - - Item before; - if (query == m_begin) - before = std::prev(m_end); - else - before = query - 1; - - Item after = query + 1; - if (after == m_end) - after = m_begin; - - neighbors.push_back(before); - neighbors.push_back(after); - } - - /// @} - - private: - Item m_begin, m_end; - }; - -} // namespace Polyline -} // namespace Shape_detection -} // namespace CGAL - -#endif // CGAL_SHAPE_DETECTION_REGION_GROWING_POLYLINE_ONE_RING_NEIGHBOR_QUERY_H diff --git a/Shape_detection/include/CGAL/Shape_detection/Region_growing/free_functions.h b/Shape_detection/include/CGAL/Shape_detection/Region_growing/free_functions.h index d38ae687fb7..e030ca4e210 100644 --- a/Shape_detection/include/CGAL/Shape_detection/Region_growing/free_functions.h +++ b/Shape_detection/include/CGAL/Shape_detection/Region_growing/free_functions.h @@ -19,7 +19,6 @@ #include #include #include -#include #include namespace CGAL { @@ -276,82 +275,6 @@ OutputIterator region_growing_planes_polygon_mesh( return regions; } -/*! - \ingroup PkgShapeDetectionRG - helper function to facilitate region growing for line detection on point sets. - - @tparam InputRange - a model of `ConstRange` representing a polyline. - @tparam OutputIterator a model of `OutputIterator` accepting a `std::pair >` or `std::pair >`. - @tparam NamedParameters a sequence of \ref bgl_namedparameters "Named Parameters" - - @param polyline input point range for region growing. - @param regions output iterator to store the detected regions and fitted lines. - @param np an optional sequence of \ref bgl_namedparameters "Named Parameters" among the ones listed below - - \cgalNamedParamsBegin - \cgalParamNBegin{maximum_distance} - \cgalParamDescription{the maximum distance from a vertex to a line} - \cgalParamType{`GeomTraits::FT`} - \cgalParamDefault{1} - \cgalParamNEnd - \cgalParamNBegin{maximum_angle} - \cgalParamDescription{the maximum angle in degrees between - the direction of a polyline edge and the direction of a line} - \cgalParamType{`GeomTraits::FT`} - \cgalParamDefault{25 degrees} - \cgalParamNEnd - \cgalParamNBegin{cosine_value} - \cgalParamDescription{the cos value computed as `cos(maximum_angle * PI / 180)`, - this parameter can be used instead of the `maximum_angle`} - \cgalParamType{`GeomTraits::FT`} - \cgalParamDefault{`cos(25 * PI / 180)`} - \cgalParamNEnd - \cgalParamNBegin{minimum_region_size} - \cgalParamDescription{the minimum number of vertices a region must have} - \cgalParamType{`std::size_t`} - \cgalParamDefault{2} - \cgalParamNEnd - \cgalParamNBegin{point_map} - \cgalParamDescription{an instance of `PointMap` that maps an item from `input_range` - to `Kernel::Point_2` or `Kernel::Point_3`} - \cgalParamDefault{`PointMap()`} - \cgalParamNEnd - \cgalParamNBegin{geom_traits} - \cgalParamDescription{an instance of `GeomTraits`} - \cgalParamDefault{`GeomTraits()`} - \cgalParamNEnd - \cgalNamedParamsEnd - - */ -template< -typename InputRange, -typename OutputIterator, -typename CGAL_NP_TEMPLATE_PARAMETERS> -OutputIterator region_growing_polylines( - const InputRange& polyline, OutputIterator regions, const CGAL_NP_CLASS& np = parameters::default_values()) { - - using Point_type = typename InputRange::value_type; - using Kernel = typename Kernel_traits::Kernel; - using Point_map = CGAL::Identity_property_map; - - using Neighbor_query = Polyline::One_ring_neighbor_query; - using Region_type = Polyline::Least_squares_line_fit_region; - using Sorting = Polyline::Least_squares_line_fit_sorting; - using Region_growing = Region_growing; - - Neighbor_query neighbor_query(polyline); - Region_type region_type(polyline, np); - Sorting sorting(polyline, neighbor_query, np); - sorting.sort(); - - Region_growing region_growing( - polyline, neighbor_query, region_type, sorting.ordered()); - region_growing.detect(regions); - - return regions; -} - } // namespace Shape_detection } // namespace CGAL diff --git a/Shape_detection/include/CGAL/Shape_detection/Region_growing/internal/region_growing_traits.h b/Shape_detection/include/CGAL/Shape_detection/Region_growing/internal/region_growing_traits.h index b0e574e0071..a934e6fa8a9 100644 --- a/Shape_detection/include/CGAL/Shape_detection/Region_growing/internal/region_growing_traits.h +++ b/Shape_detection/include/CGAL/Shape_detection/Region_growing/internal/region_growing_traits.h @@ -23,24 +23,6 @@ namespace CGAL { namespace Shape_detection { namespace internal { - template - struct Polyline_graph_traits_2 { - using Segment = typename GeomTraits::Segment_2; - using Construct_segment = typename GeomTraits::Construct_segment_2; - decltype(auto) construct_segment_object() const { - return GeomTraits().construct_segment_2_object(); - } - }; - - template - struct Polyline_graph_traits_3 { - using Segment = typename GeomTraits::Segment_3; - using Construct_segment = typename GeomTraits::Construct_segment_3; - decltype(auto) construct_segment_object() const { - return GeomTraits().construct_segment_3_object(); - } - }; - template struct Region_growing_traits_2 { using Point = typename GeomTraits::Point_2; diff --git a/Shape_detection/test/Shape_detection/CMakeLists.txt b/Shape_detection/test/Shape_detection/CMakeLists.txt index 504a65ecace..cbf67b762ce 100644 --- a/Shape_detection/test/Shape_detection/CMakeLists.txt +++ b/Shape_detection/test/Shape_detection/CMakeLists.txt @@ -18,11 +18,9 @@ if(EIGEN3_FOUND) create_single_source_cgal_program("test_region_growing_on_point_set_2.cpp") create_single_source_cgal_program("test_region_growing_on_point_set_3.cpp") create_single_source_cgal_program("test_region_growing_on_polygon_mesh.cpp") - create_single_source_cgal_program("test_region_growing_on_polyline.cpp") create_single_source_cgal_program("test_region_growing_on_point_set_2_with_sorting.cpp") create_single_source_cgal_program("test_region_growing_on_point_set_3_with_sorting.cpp") create_single_source_cgal_program("test_region_growing_on_polygon_mesh_with_sorting.cpp") - create_single_source_cgal_program("test_region_growing_on_polyline_with_sorting.cpp") create_single_source_cgal_program("test_region_growing_on_degenerated_mesh.cpp") foreach( target @@ -32,11 +30,9 @@ if(EIGEN3_FOUND) test_region_growing_on_point_set_2 test_region_growing_on_point_set_3 test_region_growing_on_polygon_mesh - test_region_growing_on_polyline test_region_growing_on_point_set_2_with_sorting test_region_growing_on_point_set_3_with_sorting test_region_growing_on_polygon_mesh_with_sorting - test_region_growing_on_polyline_with_sorting test_region_growing_on_degenerated_mesh) target_link_libraries(${target} PUBLIC CGAL::Eigen3_support) endforeach() diff --git a/Shape_detection/test/Shape_detection/test_region_growing_on_polyline.cpp b/Shape_detection/test/Shape_detection/test_region_growing_on_polyline.cpp deleted file mode 100644 index cc2e4bf75cb..00000000000 --- a/Shape_detection/test/Shape_detection/test_region_growing_on_polyline.cpp +++ /dev/null @@ -1,158 +0,0 @@ -// STL includes. -#include -#include -#include -#include -#include -#include -#include - -// CGAL includes. -#include -#include - -#include -#include -#include - -#include -#include - -namespace SD = CGAL::Shape_detection; - -template -bool test_region_growing_on_polyline(int argc, char *argv[]) { - - using FT = typename Kernel::FT; - using Point_2 = typename Kernel::Point_2; - using Point_3 = typename Kernel::Point_3; - - using Polyline_2 = std::vector; - using Polyline_3 = std::vector; - using Point_map_2 = CGAL::Identity_property_map; - using Point_map_3 = CGAL::Identity_property_map; - - using Neighbor_query_2 = SD::Polyline::One_ring_neighbor_query; - using Region_type_2 = SD::Polyline::Least_squares_line_fit_region; - using Region_growing_2 = SD::Region_growing; - - using Neighbor_query_3 = SD::Polyline::One_ring_neighbor_query; - using Region_type_3 = SD::Polyline::Least_squares_line_fit_region; - using Region_growing_3 = SD::Region_growing; - - // Default parameter values. - const FT distance_threshold = FT(45) / FT(10); - const FT angle_threshold = FT(45); - - // Load data. - std::ifstream in(argc > 1 ? argv[1] : CGAL::data_file_path("polylines_3/wavy_circle.polylines.txt")); - CGAL::IO::set_ascii_mode(in); - assert(in); - - // Create 3D polyline. - Polyline_3 polyline_3; - std::size_t n = std::size_t(-1); - in >> n; - polyline_3.reserve(n); - while (n--) { - Point_3 point; in >> point; - polyline_3.push_back(point); - assert(in.good()); - } - in.close(); - assert(polyline_3.size() == 249); - - // Create 3D parameter classes. - Neighbor_query_3 neighbor_query_3(polyline_3); - Region_type_3 region_type_3( - polyline_3, - CGAL::parameters:: - maximum_distance(distance_threshold). - maximum_angle(angle_threshold)); - - // Run 3D region growing. - Region_growing_3 region_growing_3( - polyline_3, neighbor_query_3, region_type_3); - - std::vector regions_3; - region_growing_3.detect(std::back_inserter(regions_3)); - assert(regions_3.size() == 17); - for (const auto& region : regions_3) - assert(region_type_3.is_valid_region(region.second)); - - std::vector unassigned_points; - region_growing_3.unassigned_items(polyline_3, std::back_inserter(unassigned_points)); - assert(unassigned_points.size() == 0); - - // Create 2D polyline. - std::vector indices(polyline_3.size()); - std::iota(indices.begin(), indices.end(), 0); - const auto plane = SD::internal::create_plane( - polyline_3, Point_map_3(), indices, Kernel()).first; - - Polyline_2 polyline_2; - polyline_2.reserve(polyline_3.size()); - for (const auto& point : polyline_3) { - const auto p3 = plane.projection(point); - const auto p2 = plane.to_2d(p3); - polyline_2.push_back(p2); - } - assert(polyline_2.size() == polyline_3.size()); - - // Create 2D parameter classes. - Neighbor_query_2 neighbor_query_2(polyline_2); - Region_type_2 region_type_2( - polyline_2, - CGAL::parameters:: - maximum_distance(distance_threshold). - maximum_angle(angle_threshold)); - - // Run 2D region growing. - Region_growing_2 region_growing_2( - polyline_2, neighbor_query_2, region_type_2); - - std::vector regions_2; - region_growing_2.detect(std::back_inserter(regions_2)); - assert(regions_2.size() == 5); - for (const auto& region : regions_2) - assert(region_type_2.is_valid_region(region.second)); - std::vector unassigned_points2; - region_growing_2.unassigned_items(polyline_2, std::back_inserter(unassigned_points2)); - assert(unassigned_points2.size() == 0); - - return true; -} - -int main(int argc, char *argv[]) { - - using SC = CGAL::Simple_cartesian; - using EPICK = CGAL::Exact_predicates_inexact_constructions_kernel; - using EPECK = CGAL::Exact_predicates_exact_constructions_kernel; - - // ------> - - bool sc_test_success = true; - if (!test_region_growing_on_polyline(argc, argv)) - sc_test_success = false; - std::cout << "rg_poly, sc_test_success: " << sc_test_success << std::endl; - assert(sc_test_success); - - // ------> - - bool epick_test_success = true; - if (!test_region_growing_on_polyline(argc, argv)) - epick_test_success = false; - std::cout << "rg_poly, epick_test_success: " << epick_test_success << std::endl; - assert(epick_test_success); - - // ------> - - bool epeck_test_success = true; - if (!test_region_growing_on_polyline(argc, argv)) - epeck_test_success = false; - std::cout << "rg_poly, epeck_test_success: " << epeck_test_success << std::endl; - assert(epeck_test_success); - - const bool success = sc_test_success && epick_test_success && epeck_test_success; - return (success) ? EXIT_SUCCESS : EXIT_FAILURE; -} diff --git a/Shape_detection/test/Shape_detection/test_region_growing_on_polyline_with_sorting.cpp b/Shape_detection/test/Shape_detection/test_region_growing_on_polyline_with_sorting.cpp deleted file mode 100644 index 9396fc757aa..00000000000 --- a/Shape_detection/test/Shape_detection/test_region_growing_on_polyline_with_sorting.cpp +++ /dev/null @@ -1,175 +0,0 @@ -// STL includes. -#include -#include -#include -#include -#include -#include -#include -#include - -// CGAL includes. -#include -#include -#include - -#include -#include -#include - -namespace SD = CGAL::Shape_detection; -using Kernel = CGAL::Simple_cartesian; - -using FT = typename Kernel::FT; -using Point_2 = typename Kernel::Point_2; -using Point_3 = typename Kernel::Point_3; - -using Polyline_2 = std::vector; -using Polyline_3 = std::vector; -using Point_map_2 = CGAL::Identity_property_map; -using Point_map_3 = CGAL::Identity_property_map; - -using Neighbor_query_2 = SD::Polyline::One_ring_neighbor_query; -using Region_type_2 = SD::Polyline::Least_squares_line_fit_region; -using Sorting_2 = SD::Polyline::Least_squares_line_fit_sorting; -using Region_growing_2 = SD::Region_growing; - -using Neighbor_query_3 = SD::Polyline::One_ring_neighbor_query; -using Region_type_3 = SD::Polyline::Least_squares_line_fit_region; -using Sorting_3 = SD::Polyline::Least_squares_line_fit_sorting; -using Region_growing_3 = SD::Region_growing; - -int main(int argc, char *argv[]) { - - // Default parameter values. - const FT distance_threshold = FT(45) / FT(10); - const FT angle_threshold = FT(45); - - // Load data. - std::ifstream in(argc > 1 ? argv[1] : CGAL::data_file_path("polylines_3/wavy_circle.polylines.txt")); - CGAL::IO::set_ascii_mode(in); - assert(in); - - // Create 3D polyline. - Polyline_3 polyline_3; - std::size_t n = std::size_t(-1); - in >> n; - polyline_3.reserve(n); - while (n--) { - Point_3 point; in >> point; - polyline_3.push_back(point); - assert(in.good()); - } - in.close(); - assert(polyline_3.size() == 249); - - // Create 3D parameter classes. - Neighbor_query_3 neighbor_query_3(polyline_3); - Region_type_3 region_type_3( - polyline_3, - CGAL::parameters:: - maximum_distance(distance_threshold). - maximum_angle(angle_threshold)); - - // Sort indices. - Sorting_3 sorting_3(polyline_3, neighbor_query_3); - sorting_3.sort(); - - // Run 3D region growing. - Region_growing_3 region_growing_3( - polyline_3, neighbor_query_3, region_type_3, sorting_3.ordered()); - - std::vector regions3; - region_growing_3.detect(std::back_inserter(regions3)); - assert(regions3.size() == 16); - - std::vector unassigned_points; - region_growing_3.unassigned_items(polyline_3, std::back_inserter(unassigned_points)); - assert(unassigned_points.size() == 1); - - // Test free functions and stability. - for (std::size_t k = 0; k < 3; ++k) { - regions3.clear(); - SD::region_growing_polylines( - polyline_3, std::back_inserter(regions3), - CGAL::parameters:: - maximum_distance(distance_threshold). - maximum_angle(angle_threshold)); - assert(regions3.size() == 16); - } - - // Create 2D polyline. - std::vector indices(polyline_3.size()); - std::iota(indices.begin(), indices.end(), 0); - const auto plane = SD::internal::create_plane( - polyline_3, Point_map_3(), indices, Kernel()).first; - - Polyline_2 polyline_2; - polyline_2.reserve(polyline_3.size()); - for (const auto& point : polyline_3) { - const auto p3 = plane.projection(point); - const auto p2 = plane.to_2d(p3); - polyline_2.push_back(p2); - } - assert(polyline_2.size() == polyline_3.size()); - - // Create 2D parameter classes. - Neighbor_query_2 neighbor_query_2(polyline_2); - Region_type_2 region_type_2( - polyline_2, - CGAL::parameters:: - maximum_distance(distance_threshold). - maximum_angle(angle_threshold)); - - // Sort indices. - Sorting_2 sorting_2(polyline_2, neighbor_query_2); - sorting_2.sort(); - - // Run 2D region growing. - Region_growing_2 region_growing_2( - polyline_2, neighbor_query_2, region_type_2, sorting_2.ordered()); - - std::vector regions2; - region_growing_2.detect(std::back_inserter(regions2)); - assert(regions2.size() == 5); - for (const auto& region : regions2) - assert(region_type_2.is_valid_region(region.second)); - - Region_growing_2::Region_map map = region_growing_2.region_map(); - - for (std::size_t i = 0; i < regions2.size(); i++) - for (auto& item : regions2[i].second) { - if (i != get(map, CGAL::Shape_detection::internal::conditional_deref()(item))) { - std::cout << "Region map incorrect" << std::endl; - assert(false); - } - } - - std::vector unassigned; - region_growing_2.unassigned_items(polyline_2, std::back_inserter(unassigned)); - - for (auto& item : unassigned) { - if (std::size_t(-1) != get(map, CGAL::Shape_detection::internal::conditional_deref()(item))) { - std::cout << "Region map for unassigned incorrect" << std::endl; - assert(false); - } - } - - std::vector unassigned2; - region_growing_2.unassigned_items(polyline_2, std::back_inserter(unassigned2)); - assert(unassigned2.size() == 0); - - // Test free functions and stability. - for (std::size_t k = 0; k < 3; ++k) { - regions2.clear(); - SD::region_growing_polylines( - polyline_2, std::back_inserter(regions2), - CGAL::parameters:: - maximum_distance(distance_threshold). - maximum_angle(angle_threshold)); - assert(regions2.size() == 5); - } - - std::cout << "rg_sortpoly, sc_test_success: " << true << std::endl; - return EXIT_SUCCESS; -} diff --git a/Shape_detection/test/Shape_detection/test_region_growing_strict.cpp b/Shape_detection/test/Shape_detection/test_region_growing_strict.cpp index aed1357dc9c..fc11fe5ff7c 100644 --- a/Shape_detection/test/Shape_detection/test_region_growing_strict.cpp +++ b/Shape_detection/test/Shape_detection/test_region_growing_strict.cpp @@ -23,7 +23,6 @@ #include #include #include -#include #include #include @@ -60,73 +59,6 @@ bool test_lines_points_with_normals() { return true; } -template -bool test_lines_polylines_2() { - - using Point_2 = typename Kernel::Point_2; - using Item = typename std::vector::const_iterator; - const std::vector polyline_2 = { - Point_2(0.10, 0.00), Point_2(0.50, 0.00), Point_2(0.90, 0.00), - Point_2(0.13, 0.00), Point_2(0.17, 0.00), Point_2(0.21, 0.00), - Point_2(0.21, 2.10), Point_2(0.21, 2.50), Point_2(0.21, 2.90), - Point_2(0.21, 2.13), Point_2(0.21, 2.17), Point_2(0.21, 2.21) - }; - - assert(polyline_2.size() == 12); - std::vector< std::pair< typename Kernel::Line_2, std::vector > > regions; - CGAL::Shape_detection::region_growing_polylines( - polyline_2, std::back_inserter(regions)); - assert(regions.size() == 2); - assert(regions[0].second.size() == 6); - assert(regions[1].second.size() == 6); - - return true; -} - -template -bool test_lines_polylines_3() { - - using Point_3 = typename Kernel::Point_3; - using Item = typename std::vector::const_iterator; - const std::vector polyline_3 = { - Point_3(0.10, 0.0, 1.0), Point_3(0.50, 0.0, 1.0), Point_3(0.90, 0.0, 1.0), - Point_3(0.13, 0.0, 1.0), Point_3(0.17, 0.0, 1.0), Point_3(0.21, 0.0, 1.0) - }; - - assert(polyline_3.size() == 6); - std::vector< std::pair< typename Kernel::Line_3, std::vector > > regions; - CGAL::Shape_detection::region_growing_polylines( - polyline_3, std::back_inserter(regions)); - assert(regions.size() == 1); - assert(regions[0].second.size() == 6); - return true; -} - -template -bool test_polylines_equal_points() { - - using Point_2 = typename Kernel::Point_2; - using Item = typename std::vector::const_iterator; - const std::vector polyline_2 = { - Point_2(0, 0), Point_2(1, 0), Point_2(2, 0), Point_2(3, 0), - Point_2(7, 1), Point_2(8, 1), Point_2(9, 1), Point_2(10, 1), - Point_2(14, 2), Point_2(15, 2), Point_2(16, 2), Point_2(17, 2), - Point_2(19, 3), Point_2(20, 3), Point_2(21, 3), Point_2(22, 3) - }; - - assert(polyline_2.size() == 16); - std::vector< std::pair< typename Kernel::Line_2, std::vector > > regions; - CGAL::Shape_detection::region_growing_polylines( - polyline_2, std::back_inserter(regions), CGAL::parameters::maximum_distance(0.01)); - assert(regions.size() == 4); - - assert(regions[0].second.size() == 4); - assert(regions[1].second.size() == 4); - assert(regions[2].second.size() == 4); - assert(regions[3].second.size() == 4); - return true; -} - template bool test_lines_segment_set_2() { @@ -323,9 +255,6 @@ bool test_lines_segment_set_3() { template bool test_region_growing_lines() { assert(test_lines_points_with_normals()); - assert(test_lines_polylines_2()); - assert(test_lines_polylines_3()); - assert(test_polylines_equal_points()); assert(test_lines_segment_set_2()); assert(test_lines_segment_set_2_sorting()); assert(test_lines_segment_set_3());