mirror of https://github.com/CGAL/cgal
fixed examples + some other small stuff
This commit is contained in:
parent
7a068f227a
commit
ae50a0beae
|
|
@ -8,7 +8,7 @@
|
|||
#include <iterator>
|
||||
|
||||
// CGAL includes.
|
||||
#include <CGAL/Timer.h>
|
||||
#include <CGAL/Real_timer.h>
|
||||
#include <CGAL/property_map.h>
|
||||
#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
|
||||
|
||||
|
|
@ -32,7 +32,7 @@ using Neighbor_query = SD::Point_set::Sphere_neighbor_query<Kernel, Input_range,
|
|||
using Region_type = SD::Point_set::Least_squares_line_fit_region<Kernel, Input_range, Point_map, Normal_map>;
|
||||
using Region_growing = SD::Region_growing<Input_range, Neighbor_query, Region_type>;
|
||||
|
||||
using Timer = CGAL::Timer;
|
||||
using Timer = CGAL::Real_timer;
|
||||
using Region = std::vector<std::size_t>;
|
||||
|
||||
void benchmark_region_growing_on_point_set_2(
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@
|
|||
#include <iterator>
|
||||
|
||||
// CGAL includes.
|
||||
#include <CGAL/Timer.h>
|
||||
#include <CGAL/Real_timer.h>
|
||||
#include <CGAL/property_map.h>
|
||||
#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
|
||||
|
||||
|
|
@ -34,7 +34,7 @@ using Neighbor_query = SD::Point_set::K_neighbor_query<Kernel, Input_range, Poin
|
|||
using Region_type = SD::Point_set::Least_squares_plane_fit_region<Kernel, Input_range, Point_map, Normal_map>;
|
||||
using Region_growing = SD::Region_growing<Input_range, Neighbor_query, Region_type>;
|
||||
|
||||
using Timer = CGAL::Timer;
|
||||
using Timer = CGAL::Real_timer;
|
||||
using Region = std::vector<std::size_t>;
|
||||
|
||||
void create_input_range(
|
||||
|
|
|
|||
|
|
@ -10,7 +10,10 @@ this region.
|
|||
|
||||
\cgalHasModel
|
||||
- `CGAL::Shape_detection::Point_set::Least_squares_line_fit_region`
|
||||
- `CGAL::Shape_detection::Point_set::Least_squares_circle_fit_region`
|
||||
- `CGAL::Shape_detection::Point_set::Least_squares_plane_fit_region`
|
||||
- `CGAL::Shape_detection::Point_set::Least_squares_sphere_fit_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`
|
||||
|
|
|
|||
|
|
@ -118,6 +118,7 @@ and the Region Growing approach for detecting shapes in a set of arbitrary items
|
|||
### Point Set ###
|
||||
- `CGAL::Shape_detection::Point_set::K_neighbor_query<GeomTraits, InputRange, PointMap>`
|
||||
- `CGAL::Shape_detection::Point_set::Sphere_neighbor_query<GeomTraits, InputRange, PointMap>`
|
||||
|
||||
- `CGAL::Shape_detection::Point_set::Least_squares_line_fit_region<GeomTraits, InputRange, PointMap, NormalMap>`
|
||||
- `CGAL::Shape_detection::Point_set::Least_squares_circle_fit_region<GeomTraits, InputRange, PointMap, NormalMap>`
|
||||
- `CGAL::Shape_detection::Point_set::Least_squares_plane_fit_region<GeomTraits, InputRange, PointMap, NormalMap>`
|
||||
|
|
|
|||
|
|
@ -105,6 +105,7 @@ A lower probability provides a higher reliability and determinism at the cost of
|
|||
|
||||
|
||||
\subsection Shape_detection_RANSACExamples Examples
|
||||
|
||||
The main class `Shape_detection::Efficient_RANSAC` takes a template parameter `Shape_detection::Efficient_RANSAC_traits` that defines the geometric types and input format.
|
||||
Property maps provide a means to interface with the user-specific data structures.
|
||||
The first parameter of the `Shape_detection::Efficient_RANSAC_traits` class is the common `Kernel`.
|
||||
|
|
@ -373,6 +374,7 @@ to the quality of the least squares sphere fit applied to the neighbors of each
|
|||
- `CGAL::Shape_detection::Point_set::Least_squares_cylinder_fit_sorting` - indices of 3D input points are sorted with respect
|
||||
to the quality of the least squares cylinder fit applied to the neighbors of each point.
|
||||
|
||||
|
||||
\subsubsection Shape_detection_RegionGrowingPoints_parameters Parameters
|
||||
|
||||
The classes in Section \ref Shape_detection_RegionGrowingPoints "Region Growing On Point Set" depend on a few parameters
|
||||
|
|
@ -469,6 +471,7 @@ The following example shows another similar example, this time detecting (infini
|
|||
|
||||
\cgalExample{Shape_detection/region_growing_cylinders_on_point_set_3.cpp}
|
||||
|
||||
|
||||
\subsubsection Shape_detection_RegionGrowingPoints_performance Performance
|
||||
|
||||
The main parameter that affects the region growing algorithm on a point set is the neighborhood size
|
||||
|
|
|
|||
Binary file not shown.
Binary file not shown.
|
|
@ -16,6 +16,7 @@
|
|||
#include <CGAL/memory.h>
|
||||
#include <CGAL/IO/PLY.h>
|
||||
#include <CGAL/IO/OFF.h>
|
||||
#include <CGAL/Real_timer.h>
|
||||
#include <CGAL/property_map.h>
|
||||
#include <CGAL/IO/write_ply_points.h>
|
||||
#include <CGAL/IO/Color.h>
|
||||
|
|
|
|||
|
|
@ -1,123 +1,120 @@
|
|||
#include <CGAL/Real_timer.h>
|
||||
#include <CGAL/Random.h>
|
||||
#include <CGAL/Simple_cartesian.h>
|
||||
|
||||
#include "include/utils.h"
|
||||
#include <CGAL/Point_set_3.h>
|
||||
#include <CGAL/Point_set_3/IO.h>
|
||||
|
||||
#include <CGAL/Simple_cartesian.h>
|
||||
#include <CGAL/Shape_detection/Region_growing/Region_growing.h>
|
||||
#include <CGAL/Shape_detection/Region_growing/Region_growing_on_point_set.h>
|
||||
|
||||
#include <boost/iterator/function_output_iterator.hpp>
|
||||
|
||||
#include <fstream>
|
||||
|
||||
using Kernel = CGAL::Simple_cartesian<double>;
|
||||
using Point_3 = Kernel::Point_3;
|
||||
using Vector_3 = Kernel::Vector_3;
|
||||
using Point_2 = Kernel::Point_2;
|
||||
// Typedefs.
|
||||
using Kernel = CGAL::Simple_cartesian<double>;
|
||||
using FT = Kernel::FT;
|
||||
using Point_2 = Kernel::Point_2;
|
||||
using Point_3 = Kernel::Point_3;
|
||||
using Vector_2 = Kernel::Vector_2;
|
||||
using Vector_3 = Kernel::Vector_3;
|
||||
|
||||
using Point_set_3 = CGAL::Point_set_3<Point_3, Vector_3>;
|
||||
using Point_set_2 = CGAL::Point_set_3<Point_2, Vector_2>;
|
||||
using Point_map = Point_set_2::Point_map;
|
||||
using Point_set_3 = CGAL::Point_set_3<Point_3, Vector_3>;
|
||||
|
||||
using Point_map = Point_set_2::Point_map;
|
||||
using Normal_map = Point_set_2::Vector_map;
|
||||
|
||||
namespace Shape_detection = CGAL::Shape_detection::Point_set;
|
||||
using Neighbor_query = CGAL::Shape_detection::Point_set::K_neighbor_query<Kernel, Point_set_2, Point_map>;
|
||||
using Region_type = CGAL::Shape_detection::Point_set::Least_squares_circle_fit_region<Kernel, Point_set_2, Point_map, Normal_map>;
|
||||
using Sorting = CGAL::Shape_detection::Point_set::Least_squares_circle_fit_sorting<Kernel, Point_set_2, Neighbor_query, Point_map>;
|
||||
using Region_growing = CGAL::Shape_detection::Region_growing<Point_set_2, Neighbor_query, Region_type, typename Sorting::Seed_map>;
|
||||
|
||||
using Neighbor_query = Shape_detection::K_neighbor_query
|
||||
<Kernel, Point_set_2, Point_map>;
|
||||
using Region_type = Shape_detection::Least_squares_circle_fit_region
|
||||
<Kernel, Point_set_2, Point_map, Normal_map>;
|
||||
using Sorting = Shape_detection::Least_squares_circle_fit_sorting
|
||||
<Kernel, Point_set_2, Neighbor_query, Point_map>;
|
||||
using Region_growing = CGAL::Shape_detection::Region_growing
|
||||
<Point_set_2, Neighbor_query, Region_type, typename Sorting::Seed_map>;
|
||||
int main(int argc, char** argv) {
|
||||
|
||||
int main (int argc, char** argv)
|
||||
{
|
||||
std::ifstream ifile (argc > 1 ? argv[1] : "data/circles.ply");
|
||||
Point_set_3 points3;
|
||||
ifile >> points3;
|
||||
// Load ply 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 ? "data/circles.ply" : argv[1]);
|
||||
|
||||
std::cerr << points3.size() << " points read" << std::endl;
|
||||
|
||||
// Input should have normals
|
||||
assert (points3.has_normal_map());
|
||||
|
||||
Point_set_2 points;
|
||||
points.add_normal_map();
|
||||
for (Point_set_3::Index idx : points3)
|
||||
{
|
||||
const Point_3& p = points3.point(idx);
|
||||
const Vector_3& n = points3.normal(idx);
|
||||
points.insert (Point_2 (p.x(), p.y()), Vector_2 (n.x(), n.y()));
|
||||
CGAL::IO::set_ascii_mode(in);
|
||||
if (!in) {
|
||||
std::cerr << "ERROR: cannot read the input file!" << std::endl;
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
// Default parameters for data/circles.ply
|
||||
const std::size_t k = 12;
|
||||
const double max_distance = 0.01;
|
||||
const double max_angle = 10.;
|
||||
Point_set_3 point_set_3;
|
||||
in >> point_set_3;
|
||||
in.close();
|
||||
std::cout << "* number of input points: " << point_set_3.size() << std::endl;
|
||||
assert(is_default_input && point_set_3.size() == 1101);
|
||||
assert(point_set_3.has_normal_map()); // input should have normals
|
||||
|
||||
// Create a 2D point set.
|
||||
Point_set_2 point_set_2;
|
||||
point_set_2.add_normal_map();
|
||||
for (const auto& idx : point_set_3) {
|
||||
const Point_3& point = point_set_3.point(idx);
|
||||
const Vector_3& normal = point_set_3.normal(idx);
|
||||
point_set_2.insert(
|
||||
Point_2(point.x(), point.y()),
|
||||
Vector_2(normal.x(), normal.y()));
|
||||
}
|
||||
|
||||
// Default parameter values for the data file circles.ply.
|
||||
const std::size_t k = 12;
|
||||
const FT max_distance = FT(1) / FT(100);
|
||||
const FT max_angle = FT(10);
|
||||
const std::size_t min_region_size = 20;
|
||||
|
||||
// Create instances of the classes Neighbor_query and Region_type.
|
||||
Neighbor_query neighbor_query(
|
||||
points, CGAL::parameters::
|
||||
k_neighbors(k).
|
||||
point_map(points.point_map()));
|
||||
point_set_2, CGAL::parameters::k_neighbors(k).point_map(point_set_2.point_map()));
|
||||
|
||||
Region_type region_type(
|
||||
points, CGAL::parameters::
|
||||
point_set_2,
|
||||
CGAL::parameters::
|
||||
maximum_distance(max_distance).
|
||||
maximum_angle(max_angle).
|
||||
minimum_region_size(min_region_size).
|
||||
point_map(points.point_map()).
|
||||
normal_map(points.normal_map()));
|
||||
point_map(point_set_2.point_map()).
|
||||
normal_map(point_set_2.normal_map()));
|
||||
|
||||
// Sort indices
|
||||
// Sort indices.
|
||||
Sorting sorting(
|
||||
points, neighbor_query, CGAL::parameters::
|
||||
point_map(points.point_map()));
|
||||
point_set_2, neighbor_query, CGAL::parameters::point_map(point_set_2.point_map()));
|
||||
sorting.sort();
|
||||
|
||||
// Create an instance of the region growing class.
|
||||
Region_growing region_growing(
|
||||
points, neighbor_query, region_type, sorting.seed_map());
|
||||
point_set_2, neighbor_query, region_type, sorting.seed_map());
|
||||
|
||||
// Add maps to get colored output
|
||||
// Add maps to get a colored output.
|
||||
Point_set_3::Property_map<unsigned char>
|
||||
red = points3.add_property_map<unsigned char>("red", 0).first,
|
||||
green = points3.add_property_map<unsigned char>("green", 0).first,
|
||||
blue = points3.add_property_map<unsigned char>("blue", 0).first;
|
||||
red = point_set_3.add_property_map<unsigned char>("red" , 0).first,
|
||||
green = point_set_3.add_property_map<unsigned char>("green", 0).first,
|
||||
blue = point_set_3.add_property_map<unsigned char>("blue" , 0).first;
|
||||
|
||||
// Run the algorithm.
|
||||
CGAL::Random random;
|
||||
std::size_t num_circles = 0;
|
||||
region_growing.detect(
|
||||
boost::make_function_output_iterator(
|
||||
[&](const std::vector<std::size_t>& region) {
|
||||
|
||||
std::size_t nb_circles = 0;
|
||||
CGAL::Real_timer timer;
|
||||
timer.start();
|
||||
region_growing.detect
|
||||
(boost::make_function_output_iterator
|
||||
([&](const std::vector<std::size_t>& region)
|
||||
{
|
||||
// Assign a random color to each region
|
||||
unsigned char r = static_cast<unsigned char>(random.get_int(64, 192));
|
||||
unsigned char g = static_cast<unsigned char>(random.get_int(64, 192));
|
||||
unsigned char b = static_cast<unsigned char>(random.get_int(64, 192));
|
||||
for (const std::size_t& idx : region)
|
||||
{
|
||||
red[idx] = r;
|
||||
// Assign a random color to each region.
|
||||
const unsigned char r = static_cast<unsigned char>(random.get_int(64, 192));
|
||||
const unsigned char g = static_cast<unsigned char>(random.get_int(64, 192));
|
||||
const unsigned char b = static_cast<unsigned char>(random.get_int(64, 192));
|
||||
for (const std::size_t idx : region) {
|
||||
red[idx] = r;
|
||||
green[idx] = g;
|
||||
blue[idx] = b;
|
||||
blue[idx] = b;
|
||||
}
|
||||
++ nb_circles;
|
||||
}));
|
||||
timer.stop();
|
||||
|
||||
std::cerr << nb_circles << " circles detected in "
|
||||
<< timer.time() << " seconds" << std::endl;
|
||||
|
||||
// Save in colored_circles.ply
|
||||
std::ofstream out ("colored_circles.ply");
|
||||
CGAL::IO::set_binary_mode (out);
|
||||
out << points3;
|
||||
++num_circles;
|
||||
}
|
||||
)
|
||||
);
|
||||
std::cout << "* number of found circles: " << num_circles << std::endl;
|
||||
assert(is_default_input && num_circles == 0);
|
||||
|
||||
// Save regions to a file.
|
||||
std::ofstream out("circles_point_set_2.ply");
|
||||
CGAL::IO::set_ascii_mode(out);
|
||||
out << point_set_3;
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,103 +1,99 @@
|
|||
#include <fstream>
|
||||
#include <CGAL/Real_timer.h>
|
||||
#include <CGAL/Random.h>
|
||||
#include <CGAL/Simple_cartesian.h>
|
||||
|
||||
#include "include/utils.h"
|
||||
#include <CGAL/Point_set_3.h>
|
||||
#include <CGAL/Point_set_3/IO.h>
|
||||
|
||||
#include <CGAL/Simple_cartesian.h>
|
||||
#include <CGAL/Shape_detection/Region_growing/Region_growing.h>
|
||||
#include <CGAL/Shape_detection/Region_growing/Region_growing_on_point_set.h>
|
||||
|
||||
#include <boost/iterator/function_output_iterator.hpp>
|
||||
|
||||
|
||||
using Kernel = CGAL::Simple_cartesian<double>;
|
||||
using Point_3 = Kernel::Point_3;
|
||||
// Typedefs.
|
||||
using Kernel = CGAL::Simple_cartesian<double>;
|
||||
using FT = Kernel::FT;
|
||||
using Point_3 = Kernel::Point_3;
|
||||
using Vector_3 = Kernel::Vector_3;
|
||||
|
||||
using Point_set = CGAL::Point_set_3<Point_3>;
|
||||
using Point_map = typename Point_set::Point_map;
|
||||
using Point_set = CGAL::Point_set_3<Point_3>;
|
||||
using Point_map = typename Point_set::Point_map;
|
||||
using Normal_map = typename Point_set::Vector_map;
|
||||
|
||||
namespace Shape_detection = CGAL::Shape_detection::Point_set;
|
||||
using Neighbor_query = CGAL::Shape_detection::Point_set::K_neighbor_query<Kernel, Point_set, Point_map>;
|
||||
using Region_type = CGAL::Shape_detection::Point_set::Least_squares_cylinder_fit_region<Kernel, Point_set, Point_map, Normal_map>;
|
||||
using Region_growing = CGAL::Shape_detection::Region_growing<Point_set, Neighbor_query, Region_type>;
|
||||
|
||||
using Neighbor_query = Shape_detection::K_neighbor_query
|
||||
<Kernel, Point_set, Point_map>;
|
||||
using Region_type = Shape_detection::Least_squares_cylinder_fit_region
|
||||
<Kernel, Point_set, Point_map, Normal_map>;
|
||||
using Region_growing = CGAL::Shape_detection::Region_growing
|
||||
<Point_set, Neighbor_query, Region_type>;
|
||||
int main(int argc, char** argv) {
|
||||
|
||||
int main (int argc, char** argv)
|
||||
{
|
||||
std::ifstream ifile (argc > 1 ? argv[1] : "data/cube.pwn");
|
||||
Point_set points;
|
||||
ifile >> points;
|
||||
// Load ply 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 ? "data/cube.pwn" : argv[1]);
|
||||
|
||||
std::cerr << points.size() << " points read" << std::endl;
|
||||
CGAL::IO::set_ascii_mode(in);
|
||||
if (!in) {
|
||||
std::cerr << "ERROR: cannot read the input file!" << std::endl;
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
// Input should have normals
|
||||
assert (points.has_normal_map());
|
||||
Point_set point_set;
|
||||
in >> point_set;
|
||||
in.close();
|
||||
std::cout << "* number of input points: " << point_set.size() << std::endl;
|
||||
assert(is_default_input && point_set.size() == 50000);
|
||||
assert(point_set.has_normal_map()); // input should have normals
|
||||
|
||||
// Default parameters for data/cube.pwn
|
||||
const std::size_t k = 24;
|
||||
const double max_distance = 0.05;
|
||||
const double max_angle = 5.;
|
||||
// Default parameter values for the data file cuble.pwn.
|
||||
const std::size_t k = 24;
|
||||
const FT max_distance = FT(1) / FT(20);
|
||||
const FT max_angle = FT(5);
|
||||
const std::size_t min_region_size = 200;
|
||||
|
||||
// Create instances of the classes Neighbor_query and Region_type.
|
||||
Neighbor_query neighbor_query(
|
||||
points, CGAL::parameters::
|
||||
k_neighbors(k).
|
||||
point_map(points.point_map()));
|
||||
point_set, CGAL::parameters::k_neighbors(k).point_map(point_set.point_map()));
|
||||
|
||||
Region_type region_type(
|
||||
points, CGAL::parameters::
|
||||
point_set,
|
||||
CGAL::parameters::
|
||||
maximum_distance(max_distance).
|
||||
maximum_angle(max_angle).
|
||||
minimum_region_size(min_region_size).
|
||||
point_map(points.point_map()).
|
||||
normal_map(points.normal_map()));
|
||||
point_map(point_set.point_map()).
|
||||
normal_map(point_set.normal_map()));
|
||||
|
||||
// Create an instance of the region growing class.
|
||||
Region_growing region_growing(
|
||||
points, neighbor_query, region_type);
|
||||
point_set, neighbor_query, region_type);
|
||||
|
||||
// Add maps to get colored output
|
||||
// Add maps to get a colored output.
|
||||
Point_set::Property_map<unsigned char>
|
||||
red = points.add_property_map<unsigned char>("red", 0).first,
|
||||
green = points.add_property_map<unsigned char>("green", 0).first,
|
||||
blue = points.add_property_map<unsigned char>("blue", 0).first;
|
||||
red = point_set.add_property_map<unsigned char>("red" , 0).first,
|
||||
green = point_set.add_property_map<unsigned char>("green", 0).first,
|
||||
blue = point_set.add_property_map<unsigned char>("blue" , 0).first;
|
||||
|
||||
// Run the algorithm.
|
||||
CGAL::Random random;
|
||||
std::size_t num_cylinders = 0;
|
||||
region_growing.detect(
|
||||
boost::make_function_output_iterator(
|
||||
[&](const std::vector<std::size_t>& region) {
|
||||
|
||||
std::size_t nb_cylinders = 0;
|
||||
CGAL::Real_timer timer;
|
||||
timer.start();
|
||||
region_growing.detect
|
||||
(boost::make_function_output_iterator
|
||||
([&](const std::vector<std::size_t>& region)
|
||||
{
|
||||
// Assign a random color to each region
|
||||
unsigned char r = static_cast<unsigned char>(random.get_int(64, 192));
|
||||
unsigned char g = static_cast<unsigned char>(random.get_int(64, 192));
|
||||
unsigned char b = static_cast<unsigned char>(random.get_int(64, 192));
|
||||
for (const std::size_t& idx : region)
|
||||
{
|
||||
red[idx] = r;
|
||||
// Assign a random color to each region.
|
||||
const unsigned char r = static_cast<unsigned char>(random.get_int(64, 192));
|
||||
const unsigned char g = static_cast<unsigned char>(random.get_int(64, 192));
|
||||
const unsigned char b = static_cast<unsigned char>(random.get_int(64, 192));
|
||||
for (const std::size_t idx : region) {
|
||||
red[idx] = r;
|
||||
green[idx] = g;
|
||||
blue[idx] = b;
|
||||
blue[idx] = b;
|
||||
}
|
||||
++ nb_cylinders;
|
||||
}));
|
||||
timer.stop();
|
||||
|
||||
std::cerr << nb_cylinders << " cylinders detected in "
|
||||
<< timer.time() << " seconds" << std::endl;
|
||||
|
||||
// Save in colored_cylinders.ply
|
||||
std::ofstream out ("colored_cylinders.ply");
|
||||
CGAL::IO::set_binary_mode (out);
|
||||
out << points;
|
||||
++num_cylinders;
|
||||
}
|
||||
)
|
||||
);
|
||||
std::cout << "* number of found cylinders: " << num_cylinders << std::endl;
|
||||
assert(is_default_input && num_cylinders == 0);
|
||||
|
||||
// Save regions to a file.
|
||||
std::ofstream out("cylinders_point_set_3.ply");
|
||||
CGAL::IO::set_ascii_mode(out);
|
||||
out << point_set;
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -40,7 +40,7 @@ int main(int argc, char *argv[]) {
|
|||
std::cout << "* number of input points: " << point_set_2.size() << std::endl;
|
||||
assert(is_default_input && point_set_2.size() == 3634);
|
||||
|
||||
// Default parameter values for the data file point_set_2.xyz.
|
||||
// Default parameter values for the data file buildings_outline.xyz.
|
||||
const FT sphere_radius = FT(5);
|
||||
const FT max_distance = FT(45) / FT(10);
|
||||
const FT max_angle = FT(45);
|
||||
|
|
@ -64,11 +64,11 @@ int main(int argc, char *argv[]) {
|
|||
// Run the algorithm.
|
||||
std::vector< std::vector<std::size_t> > regions;
|
||||
region_growing.detect(std::back_inserter(regions));
|
||||
std::cout << "* number of found regions: " << regions.size() << std::endl;
|
||||
std::cout << "* number of found lines: " << regions.size() << std::endl;
|
||||
assert(is_default_input && regions.size() == 65);
|
||||
|
||||
// Save regions to a file.
|
||||
const std::string fullpath = (argc > 2 ? argv[2] : "regions_point_set_2.ply");
|
||||
const std::string fullpath = (argc > 2 ? argv[2] : "lines_point_set_2.ply");
|
||||
utils::save_point_regions_2<Kernel, Point_set_2, Point_map>(
|
||||
point_set_2, regions, fullpath);
|
||||
return EXIT_SUCCESS;
|
||||
|
|
|
|||
|
|
@ -40,7 +40,7 @@ int main(int argc, char *argv[]) {
|
|||
std::cout << "* number of input points: " << input_range.size() << std::endl;
|
||||
assert(is_default_input && input_range.size() == 8075);
|
||||
|
||||
// Default parameter values for the data file point_set_3.xyz.
|
||||
// Default parameter values for the data file building.xyz.
|
||||
const std::size_t k = 12;
|
||||
const FT max_distance = FT(2);
|
||||
const FT max_angle = FT(20);
|
||||
|
|
@ -73,11 +73,11 @@ int main(int argc, char *argv[]) {
|
|||
output_range, number_of_regions);
|
||||
region_growing.detect(
|
||||
boost::make_function_output_iterator(inserter));
|
||||
std::cout << "* number of found regions: " << number_of_regions << std::endl;
|
||||
std::cout << "* number of found planes: " << number_of_regions << std::endl;
|
||||
assert(is_default_input && number_of_regions == 7);
|
||||
|
||||
// Save regions to a file.
|
||||
const std::string fullpath = (argc > 2 ? argv[2] : "regions_point_set_3.ply");
|
||||
const std::string fullpath = (argc > 2 ? argv[2] : "planes_point_set_3.ply");
|
||||
std::ofstream out(fullpath);
|
||||
out << output_range;
|
||||
out.close();
|
||||
|
|
|
|||
|
|
@ -48,7 +48,7 @@ int main(int argc, char *argv[]) {
|
|||
std::cout << "* number of input faces: " << face_range.size() << std::endl;
|
||||
assert(is_default_input && face_range.size() == 32245);
|
||||
|
||||
// Default parameter values for the data file polygon_mesh.off.
|
||||
// Default parameter values for the data file building.off.
|
||||
const FT max_distance = FT(1);
|
||||
const FT max_angle = FT(45);
|
||||
const std::size_t min_region_size = 5;
|
||||
|
|
@ -75,12 +75,12 @@ int main(int argc, char *argv[]) {
|
|||
// Run the algorithm.
|
||||
std::vector< std::vector<std::size_t> > regions;
|
||||
region_growing.detect(std::back_inserter(regions));
|
||||
std::cout << "* number of found regions: " << regions.size() << std::endl;
|
||||
std::cout << "* number of found planes: " << regions.size() << std::endl;
|
||||
assert(is_default_input && regions.size() == 326);
|
||||
|
||||
// Save regions to a file only if it is stored in CGAL::Surface_mesh.
|
||||
#if defined(USE_SURFACE_MESH)
|
||||
const std::string fullpath = (argc > 2 ? argv[2] : "regions_polygon_mesh.ply");
|
||||
const std::string fullpath = (argc > 2 ? argv[2] : "planes_polygon_mesh.ply");
|
||||
utils::save_polygon_mesh_regions(polygon_mesh, regions, fullpath);
|
||||
#endif
|
||||
return EXIT_SUCCESS;
|
||||
|
|
|
|||
|
|
@ -1,103 +1,99 @@
|
|||
#include <CGAL/Real_timer.h>
|
||||
#include <CGAL/Random.h>
|
||||
#include <CGAL/Simple_cartesian.h>
|
||||
|
||||
#include "include/utils.h"
|
||||
#include <CGAL/Point_set_3.h>
|
||||
#include <CGAL/Point_set_3/IO.h>
|
||||
|
||||
#include <CGAL/Simple_cartesian.h>
|
||||
#include <CGAL/Shape_detection/Region_growing/Region_growing.h>
|
||||
#include <CGAL/Shape_detection/Region_growing/Region_growing_on_point_set.h>
|
||||
|
||||
#include <boost/iterator/function_output_iterator.hpp>
|
||||
|
||||
#include <fstream>
|
||||
|
||||
using Kernel = CGAL::Simple_cartesian<double>;
|
||||
using Point_3 = Kernel::Point_3;
|
||||
// Typedefs.
|
||||
using Kernel = CGAL::Simple_cartesian<double>;
|
||||
using FT = Kernel::FT;
|
||||
using Point_3 = Kernel::Point_3;
|
||||
using Vector_3 = Kernel::Vector_3;
|
||||
|
||||
using Point_set = CGAL::Point_set_3<Point_3>;
|
||||
using Point_map = typename Point_set::Point_map;
|
||||
using Point_set = CGAL::Point_set_3<Point_3>;
|
||||
using Point_map = typename Point_set::Point_map;
|
||||
using Normal_map = typename Point_set::Vector_map;
|
||||
|
||||
namespace Shape_detection = CGAL::Shape_detection::Point_set;
|
||||
using Neighbor_query = CGAL::Shape_detection::Point_set::K_neighbor_query<Kernel, Point_set, Point_map>;
|
||||
using Region_type = CGAL::Shape_detection::Point_set::Least_squares_sphere_fit_region<Kernel, Point_set, Point_map, Normal_map>;
|
||||
using Region_growing = CGAL::Shape_detection::Region_growing<Point_set, Neighbor_query, Region_type>;
|
||||
|
||||
using Neighbor_query = Shape_detection::K_neighbor_query
|
||||
<Kernel, Point_set, Point_map>;
|
||||
using Region_type = Shape_detection::Least_squares_sphere_fit_region
|
||||
<Kernel, Point_set, Point_map, Normal_map>;
|
||||
using Region_growing = CGAL::Shape_detection::Region_growing
|
||||
<Point_set, Neighbor_query, Region_type>;
|
||||
int main(int argc, char** argv) {
|
||||
|
||||
int main (int argc, char** argv)
|
||||
{
|
||||
std::ifstream ifile (argc > 1 ? argv[1] : "data/spheres.ply");
|
||||
Point_set points;
|
||||
ifile >> points;
|
||||
// Load ply 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 ? "data/spheres.ply" : argv[1]);
|
||||
|
||||
std::cerr << points.size() << " points read" << std::endl;
|
||||
CGAL::IO::set_ascii_mode(in);
|
||||
if (!in) {
|
||||
std::cerr << "ERROR: cannot read the input file!" << std::endl;
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
// Input should have normals
|
||||
assert (points.has_normal_map());
|
||||
Point_set point_set;
|
||||
in >> point_set;
|
||||
in.close();
|
||||
std::cout << "* number of input points: " << point_set.size() << std::endl;
|
||||
assert(is_default_input && point_set.size() == 5969);
|
||||
assert(point_set.has_normal_map()); // input should have normals
|
||||
|
||||
// Default parameters for data/spheres.ply
|
||||
const std::size_t k = 12;
|
||||
const double max_distance = 0.01;
|
||||
const double max_angle = 10.;
|
||||
// Default parameter values for the data file spheres.ply.
|
||||
const std::size_t k = 12;
|
||||
const FT max_distance = FT(1) / FT(100);
|
||||
const FT max_angle = FT(10);
|
||||
const std::size_t min_region_size = 50;
|
||||
|
||||
// Create instances of the classes Neighbor_query and Region_type.
|
||||
Neighbor_query neighbor_query(
|
||||
points, CGAL::parameters::
|
||||
k_neighbors(k).
|
||||
point_map(points.point_map()));
|
||||
point_set, CGAL::parameters::k_neighbors(k).point_map(point_set.point_map()));
|
||||
|
||||
Region_type region_type(
|
||||
points, CGAL::parameters::
|
||||
point_set,
|
||||
CGAL::parameters::
|
||||
maximum_distance(max_distance).
|
||||
maximum_angle(max_angle).
|
||||
minimum_region_size(min_region_size).
|
||||
point_map(points.point_map()).
|
||||
normal_map(points.normal_map()));
|
||||
point_map(point_set.point_map()).
|
||||
normal_map(point_set.normal_map()));
|
||||
|
||||
// Create an instance of the region growing class.
|
||||
Region_growing region_growing(
|
||||
points, neighbor_query, region_type);
|
||||
point_set, neighbor_query, region_type);
|
||||
|
||||
// Add maps to get colored output
|
||||
// Add maps to get a colored output.
|
||||
Point_set::Property_map<unsigned char>
|
||||
red = points.add_property_map<unsigned char>("red", 0).first,
|
||||
green = points.add_property_map<unsigned char>("green", 0).first,
|
||||
blue = points.add_property_map<unsigned char>("blue", 0).first;
|
||||
red = point_set.add_property_map<unsigned char>("red" , 0).first,
|
||||
green = point_set.add_property_map<unsigned char>("green", 0).first,
|
||||
blue = point_set.add_property_map<unsigned char>("blue" , 0).first;
|
||||
|
||||
// Run the algorithm.
|
||||
CGAL::Random random;
|
||||
std::size_t num_spheres = 0;
|
||||
region_growing.detect(
|
||||
boost::make_function_output_iterator(
|
||||
[&](const std::vector<std::size_t>& region) {
|
||||
|
||||
std::size_t nb_spheres = 0;
|
||||
CGAL::Real_timer timer;
|
||||
timer.start();
|
||||
region_growing.detect
|
||||
(boost::make_function_output_iterator
|
||||
([&](const std::vector<std::size_t>& region)
|
||||
{
|
||||
// Assign a random color to each region
|
||||
unsigned char r = static_cast<unsigned char>(random.get_int(64, 192));
|
||||
unsigned char g = static_cast<unsigned char>(random.get_int(64, 192));
|
||||
unsigned char b = static_cast<unsigned char>(random.get_int(64, 192));
|
||||
for (const std::size_t& idx : region)
|
||||
{
|
||||
red[idx] = r;
|
||||
// Assign a random color to each region.
|
||||
const unsigned char r = static_cast<unsigned char>(random.get_int(64, 192));
|
||||
const unsigned char g = static_cast<unsigned char>(random.get_int(64, 192));
|
||||
const unsigned char b = static_cast<unsigned char>(random.get_int(64, 192));
|
||||
for (const std::size_t idx : region) {
|
||||
red[idx] = r;
|
||||
green[idx] = g;
|
||||
blue[idx] = b;
|
||||
blue[idx] = b;
|
||||
}
|
||||
++ nb_spheres;
|
||||
}));
|
||||
timer.stop();
|
||||
|
||||
std::cerr << nb_spheres << " spheres detected in "
|
||||
<< timer.time() << " seconds" << std::endl;
|
||||
|
||||
// Save in colored_spheres.ply
|
||||
std::ofstream out ("colored_spheres.ply");
|
||||
CGAL::IO::set_binary_mode (out);
|
||||
out << points;
|
||||
++num_spheres;
|
||||
}
|
||||
)
|
||||
);
|
||||
std::cout << "* number of found spheres: " << num_spheres << std::endl;
|
||||
assert(is_default_input && num_spheres == 0);
|
||||
|
||||
// Save regions to a file.
|
||||
std::ofstream out("spheres_point_set_3.ply");
|
||||
CGAL::IO::set_ascii_mode(out);
|
||||
out << point_set;
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -303,17 +303,20 @@ namespace Point_set {
|
|||
CGAL_precondition(query_index < m_input_range.size());
|
||||
|
||||
// First, we need to integrate at least 6 points so that the
|
||||
// computed circle means something
|
||||
if (indices.size() < 6)
|
||||
// computed circle means something.
|
||||
if (indices.size() < 6) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// TODO: Why do we get so many nan in this class?
|
||||
if (std::isnan(m_radius))
|
||||
if (std::isnan(m_radius)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// If radius is out of bound, nothing fits, early ending
|
||||
if (m_radius < m_min_radius || m_radius > m_max_radius)
|
||||
// If radius is out of bound, nothing fits, early ending.
|
||||
if (m_radius < m_min_radius || m_radius > m_max_radius) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const auto& key = *(m_input_range.begin() + query_index);
|
||||
const Point_2& query_point = get(m_point_map, key);
|
||||
|
|
@ -321,24 +324,25 @@ namespace Point_set {
|
|||
|
||||
const FT sq_dist = m_squared_distance_2(query_point, m_center);
|
||||
if (std::isnan(sq_dist)) return false;
|
||||
FT distance_to_center = m_sqrt (sq_dist);
|
||||
FT distance_to_circle = CGAL::abs (distance_to_center - m_radius);
|
||||
const FT distance_to_center = m_sqrt (sq_dist);
|
||||
const FT distance_to_circle = CGAL::abs (distance_to_center - m_radius);
|
||||
|
||||
if (distance_to_circle > m_distance_threshold)
|
||||
if (distance_to_circle > m_distance_threshold) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const FT sq_norm = normal * normal;
|
||||
if (std::isnan(sq_norm)) return false;
|
||||
normal = normal / m_sqrt (sq_norm);
|
||||
|
||||
Vector_2 ray (m_center, query_point);
|
||||
Vector_2 ray(m_center, query_point);
|
||||
const FT sq_ray = ray * ray;
|
||||
if (std::isnan(sq_ray)) return false;
|
||||
ray = ray / m_sqrt (sq_ray);
|
||||
|
||||
if (CGAL::abs (normal * ray) < m_cos_value_threshold)
|
||||
if (CGAL::abs(normal * ray) < m_cos_value_threshold) {
|
||||
return false;
|
||||
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -375,17 +379,14 @@ namespace Point_set {
|
|||
bool update(const std::vector<std::size_t>& region) {
|
||||
|
||||
CGAL_precondition(region.size() > 0);
|
||||
auto unary_function
|
||||
= [&](const std::size_t& idx) -> const Point_2&
|
||||
{
|
||||
return get (m_point_map, *(m_input_range.begin() + idx));
|
||||
};
|
||||
auto unary_function = [&](const std::size_t& idx) -> const Point_2& {
|
||||
return get(m_point_map, *(m_input_range.begin() + idx));
|
||||
};
|
||||
|
||||
internal::circle_fit
|
||||
(make_range(boost::make_transform_iterator
|
||||
(region.begin(), unary_function),
|
||||
boost::make_transform_iterator
|
||||
(region.end(), unary_function)),
|
||||
internal::create_circle_2(
|
||||
make_range(
|
||||
boost::make_transform_iterator(region.begin(), unary_function),
|
||||
boost::make_transform_iterator(region.end(), unary_function)),
|
||||
m_sqrt, m_squared_distance_2, m_center, m_radius);
|
||||
return true;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -231,15 +231,17 @@ namespace Point_set {
|
|||
Local_point_2 fitted_center;
|
||||
Local_FT fitted_radius;
|
||||
|
||||
if (internal::circle_fit (points, sqrt, squared_distance_2, fitted_center, fitted_radius))
|
||||
{
|
||||
// Score is min squared distance to sphere
|
||||
if (internal::create_circle_2(
|
||||
points, sqrt, squared_distance_2, fitted_center, fitted_radius)) {
|
||||
|
||||
// Score is min squared distance to sphere.
|
||||
m_scores[i] = Local_FT(0);
|
||||
for (const Local_point_2& p : points)
|
||||
m_scores[i] += abs (sqrt(squared_distance_2(p, fitted_center)) - fitted_radius);
|
||||
for (const Local_point_2& p : points) {
|
||||
m_scores[i] += abs(sqrt(squared_distance_2(p, fitted_center)) - fitted_radius);
|
||||
}
|
||||
} else {
|
||||
m_scores[i] = Local_FT(std::numeric_limits<double>::max());
|
||||
}
|
||||
else
|
||||
m_scores[i] = Local_FT(std::numeric_limits<double>::infinity());
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -305,17 +305,20 @@ namespace Point_set {
|
|||
CGAL_precondition(query_index < m_input_range.size());
|
||||
|
||||
// First, we need to integrate at least 6 points so that the
|
||||
// computed cylinder means something
|
||||
if (indices.size() < 6)
|
||||
// computed cylinder means something.
|
||||
if (indices.size() < 6) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// TODO: Why do we get so many nan in this class?
|
||||
if (std::isnan(m_radius))
|
||||
if (std::isnan(m_radius)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// If radius is out of bound, nothing fits, early ending
|
||||
if (m_radius < m_min_radius || m_radius > m_max_radius)
|
||||
// If radius is out of bound, nothing fits, early ending.
|
||||
if (m_radius < m_min_radius || m_radius > m_max_radius) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const auto& key = *(m_input_range.begin() + query_index);
|
||||
const Point_3& query_point = get(m_point_map, key);
|
||||
|
|
@ -326,25 +329,26 @@ namespace Point_set {
|
|||
if (m_axis.to_vector() == Vector_3(0, 0, 0)) return false;
|
||||
const FT sq_dist = m_squared_distance_3(query_point, m_axis);
|
||||
if (std::isnan(sq_dist)) return false;
|
||||
FT distance_to_center = m_sqrt (sq_dist);
|
||||
FT distance_to_cylinder = CGAL::abs (distance_to_center - m_radius);
|
||||
const FT distance_to_center = m_sqrt(sq_dist);
|
||||
const FT distance_to_cylinder = CGAL::abs(distance_to_center - m_radius);
|
||||
|
||||
if (distance_to_cylinder > m_distance_threshold)
|
||||
if (distance_to_cylinder > m_distance_threshold) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const FT sq_norm = normal * normal;
|
||||
if (std::isnan(sq_norm)) return false;
|
||||
normal = normal / m_sqrt (sq_norm);
|
||||
|
||||
Point_3 proj = m_axis.projection(query_point);
|
||||
Vector_3 ray (proj, query_point);
|
||||
const Point_3 proj = m_axis.projection(query_point);
|
||||
Vector_3 ray(proj, query_point);
|
||||
const FT sq_ray = ray * ray;
|
||||
if (std::isnan(sq_ray)) return false;
|
||||
ray = ray / m_sqrt (sq_ray);
|
||||
ray = ray / m_sqrt(sq_ray);
|
||||
|
||||
if (CGAL::abs (normal * ray) < m_cos_value_threshold)
|
||||
if (CGAL::abs(normal * ray) < m_cos_value_threshold) {
|
||||
return false;
|
||||
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -382,25 +386,21 @@ namespace Point_set {
|
|||
|
||||
CGAL_precondition(region.size() > 0);
|
||||
|
||||
// Shuffle to avoid always picking 2 close points
|
||||
std::vector<std::size_t>& aregion
|
||||
= const_cast<std::vector<std::size_t>&>(region);
|
||||
cpp98::random_shuffle (aregion.begin(), aregion.end());
|
||||
// Shuffle to avoid always picking 2 close points.
|
||||
std::vector<std::size_t>& aregion =
|
||||
const_cast<std::vector<std::size_t>&>(region);
|
||||
cpp98::random_shuffle(aregion.begin(), aregion.end());
|
||||
|
||||
using VT = typename std::iterator_traits<typename InputRange::const_iterator>::value_type;
|
||||
auto unary_function
|
||||
= [&](const std::size_t& idx) -> VT
|
||||
{
|
||||
return *(m_input_range.begin() + idx);
|
||||
};
|
||||
auto unary_function = [&](const std::size_t& idx) -> VT {
|
||||
return *(m_input_range.begin() + idx);
|
||||
};
|
||||
|
||||
internal::cylinder_fit
|
||||
(make_range (boost::make_transform_iterator
|
||||
(region.begin(), unary_function),
|
||||
boost::make_transform_iterator
|
||||
(region.end(), unary_function)),
|
||||
m_point_map, m_normal_map, m_sqrt, m_squared_distance_3,
|
||||
m_axis, m_radius);
|
||||
internal::create_cylinder_3(
|
||||
make_range(
|
||||
boost::make_transform_iterator(region.begin(), unary_function),
|
||||
boost::make_transform_iterator(region.end(), unary_function)),
|
||||
m_point_map, m_normal_map, m_sqrt, m_squared_distance_3, m_axis, m_radius);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -236,16 +236,14 @@ namespace Point_set {
|
|||
typename internal::Get_sqrt<Local_traits>::Sqrt sqrt;
|
||||
typename Local_traits::Compute_squared_distance_3 squared_distance_3;
|
||||
|
||||
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();
|
||||
m_neighbor_query(i, neighbors);
|
||||
neighbors.push_back(i);
|
||||
|
||||
points.clear();
|
||||
for (std::size_t j = 0; j < neighbors.size(); ++j)
|
||||
{
|
||||
for (std::size_t j = 0; j < neighbors.size(); ++j) {
|
||||
CGAL_precondition(neighbors[j] < m_input_range.size());
|
||||
|
||||
const auto& key = *(m_input_range.begin() + neighbors[j]);
|
||||
|
|
@ -257,16 +255,18 @@ namespace Point_set {
|
|||
Local_line_3 fitted_line;
|
||||
Local_FT fitted_radius;
|
||||
|
||||
if (internal::cylinder_fit (points, Local_point_map(), Local_normal_map(),
|
||||
sqrt, squared_distance_3, fitted_line, fitted_radius))
|
||||
{
|
||||
// Score is min squared distance to cylinder
|
||||
if (internal::create_cylinder_3(
|
||||
points, Local_point_map(), Local_normal_map(),
|
||||
sqrt, squared_distance_3, fitted_line, fitted_radius)) {
|
||||
|
||||
// Score is min squared distance to cylinder.
|
||||
m_scores[i] = Local_FT(0);
|
||||
for (const Local_pwn& pwn : points)
|
||||
m_scores[i] += abs (sqrt(squared_distance_3(pwn.first, fitted_line)) - fitted_radius);
|
||||
for (const Local_pwn& pwn : points) {
|
||||
m_scores[i] += abs(sqrt(squared_distance_3(pwn.first, fitted_line)) - fitted_radius);
|
||||
}
|
||||
} else {
|
||||
m_scores[i] = Local_FT(std::numeric_limits<double>::max());
|
||||
}
|
||||
else
|
||||
m_scores[i] = Local_FT(std::numeric_limits<double>::infinity());
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -308,17 +308,20 @@ namespace Point_set {
|
|||
CGAL_precondition(query_index < m_input_range.size());
|
||||
|
||||
// First, we need to integrate at least 6 points so that the
|
||||
// computed sphere means something
|
||||
if (indices.size() < 6)
|
||||
// computed sphere means something.
|
||||
if (indices.size() < 6) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// TODO: Why do we get so many nan in this class?
|
||||
if (std::isnan(m_radius))
|
||||
if (std::isnan(m_radius)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// If radius is out of bound, nothing fits, early ending
|
||||
if (m_radius < m_min_radius || m_radius > m_max_radius)
|
||||
// If radius is out of bound, nothing fits, early ending.
|
||||
if (m_radius < m_min_radius || m_radius > m_max_radius) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const auto& key = *(m_input_range.begin() + query_index);
|
||||
const Point_3& query_point = get(m_point_map, key);
|
||||
|
|
@ -326,24 +329,25 @@ namespace Point_set {
|
|||
|
||||
const FT sq_dist = m_squared_distance_3(query_point, m_center);
|
||||
if (std::isnan(sq_dist)) return false;
|
||||
FT distance_to_center = m_sqrt (sq_dist);
|
||||
FT distance_to_sphere = CGAL::abs (distance_to_center - m_radius);
|
||||
const FT distance_to_center = m_sqrt(sq_dist);
|
||||
const FT distance_to_sphere = CGAL::abs(distance_to_center - m_radius);
|
||||
|
||||
if (distance_to_sphere > m_distance_threshold)
|
||||
if (distance_to_sphere > m_distance_threshold) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const FT sq_norm = normal * normal;
|
||||
if (std::isnan(sq_norm)) return false;
|
||||
normal = normal / m_sqrt (sq_norm);
|
||||
|
||||
Vector_3 ray (m_center, query_point);
|
||||
Vector_3 ray(m_center, query_point);
|
||||
const FT sq_ray = ray * ray;
|
||||
if (std::isnan(sq_ray)) return false;
|
||||
ray = ray / m_sqrt (sq_ray);
|
||||
|
||||
if (CGAL::abs (normal * ray) < m_cos_value_threshold)
|
||||
if (CGAL::abs(normal * ray) < m_cos_value_threshold) {
|
||||
return false;
|
||||
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -380,17 +384,14 @@ namespace Point_set {
|
|||
bool update(const std::vector<std::size_t>& region) {
|
||||
|
||||
CGAL_precondition(region.size() > 0);
|
||||
auto unary_function
|
||||
= [&](const std::size_t& idx) -> const Point_3&
|
||||
{
|
||||
return get (m_point_map, *(m_input_range.begin() + idx));
|
||||
};
|
||||
auto unary_function = [&](const std::size_t& idx) -> const Point_3& {
|
||||
return get (m_point_map, *(m_input_range.begin() + idx));
|
||||
};
|
||||
|
||||
internal::sphere_fit
|
||||
(make_range (boost::make_transform_iterator
|
||||
(region.begin(), unary_function),
|
||||
boost::make_transform_iterator
|
||||
(region.end(), unary_function)),
|
||||
internal::create_sphere_3(
|
||||
make_range(
|
||||
boost::make_transform_iterator(region.begin(), unary_function),
|
||||
boost::make_transform_iterator(region.end(), unary_function)),
|
||||
m_sqrt, m_squared_distance_3, m_center, m_radius);
|
||||
return true;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -212,16 +212,14 @@ namespace Point_set {
|
|||
typename internal::Get_sqrt<Local_traits>::Sqrt sqrt;
|
||||
typename Local_traits::Compute_squared_distance_3 squared_distance_3;
|
||||
|
||||
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();
|
||||
m_neighbor_query(i, neighbors);
|
||||
neighbors.push_back(i);
|
||||
|
||||
points.clear();
|
||||
for (std::size_t j = 0; j < neighbors.size(); ++j)
|
||||
{
|
||||
for (std::size_t j = 0; j < neighbors.size(); ++j) {
|
||||
CGAL_precondition(neighbors[j] < m_input_range.size());
|
||||
|
||||
const auto& key = *(m_input_range.begin() + neighbors[j]);
|
||||
|
|
@ -232,15 +230,17 @@ namespace Point_set {
|
|||
Local_point_3 fitted_center;
|
||||
Local_FT fitted_radius;
|
||||
|
||||
if (internal::sphere_fit (points, sqrt, squared_distance_3, fitted_center, fitted_radius))
|
||||
{
|
||||
// Score is min squared distance to sphere
|
||||
if (internal::create_sphere_3(
|
||||
points, sqrt, squared_distance_3, fitted_center, fitted_radius)) {
|
||||
|
||||
// Score is min squared distance to sphere.
|
||||
m_scores[i] = Local_FT(0);
|
||||
for (const Local_point_3& p : points)
|
||||
m_scores[i] += abs (sqrt(squared_distance_3(p, fitted_center)) - fitted_radius);
|
||||
for (const Local_point_3& p : points) {
|
||||
m_scores[i] += abs(sqrt(squared_distance_3(p, fitted_center)) - fitted_radius);
|
||||
}
|
||||
} else {
|
||||
m_scores[i] = Local_FT(std::numeric_limits<double>::max());
|
||||
}
|
||||
else
|
||||
m_scores[i] = Local_FT(std::numeric_limits<double>::infinity());
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -346,240 +346,272 @@ namespace internal {
|
|||
return std::make_pair(plane, static_cast<FT>(score));
|
||||
}
|
||||
|
||||
template <typename PointRange,
|
||||
typename Sqrt, typename Squared_distance_2,
|
||||
typename Point_2, typename FT>
|
||||
bool circle_fit (const PointRange& points,
|
||||
const Sqrt& sqrt,
|
||||
const Squared_distance_2& squared_distance_2,
|
||||
Point_2& center, FT& radius)
|
||||
{
|
||||
using Diagonalize_traits = Eigen_diagonalize_traits<FT, 4>;
|
||||
using Covariance_matrix = typename Diagonalize_traits::Covariance_matrix;
|
||||
using Vector = typename Diagonalize_traits::Vector;
|
||||
using Matrix = typename Diagonalize_traits::Matrix;
|
||||
template<
|
||||
typename PointRange,
|
||||
typename Sqrt,
|
||||
typename Squared_distance_2,
|
||||
typename Point_2,
|
||||
typename FT>
|
||||
bool create_circle_2(
|
||||
const PointRange& points,
|
||||
const Sqrt& sqrt,
|
||||
const Squared_distance_2& squared_distance_2,
|
||||
Point_2& center, FT& radius) {
|
||||
|
||||
// Use bbox to compute diagonalization with smaller coordinates to
|
||||
// avoid loss of precision when inverting large coordinates
|
||||
Bbox_2 bbox = bbox_2 (points.begin(), points.end());
|
||||
using Diagonalize_traits = Eigen_diagonalize_traits<FT, 4>;
|
||||
using Covariance_matrix = typename Diagonalize_traits::Covariance_matrix;
|
||||
|
||||
// Circle least squares fitting,
|
||||
// Circle of center (a,b) and radius R
|
||||
// Ri = sqrt((xi - a)^2 + (yi - b)^2)
|
||||
// Minimize Sum(Ri^2 - R^2)^2
|
||||
// -> Minimize Sum(xi^2 + yi^2 − 2 a*xi − 2 b*yi + a^2 + b^2 − R^2)^2
|
||||
// let B=-2a ; C=-2b; D= a^2 + b^2 - R^2
|
||||
// let ri = x^2 + y^2
|
||||
// -> Minimize Sum(D + B*xi + C*yi + ri)^2
|
||||
// -> Minimize Sum(1 + B/D*xi + C/D*yi + ri/D)^2
|
||||
// -> system of linear equations
|
||||
// -> diagonalize matrix
|
||||
// NB x y r
|
||||
// xx xy xr
|
||||
// yy yr
|
||||
// rr
|
||||
//
|
||||
// -> center coordinates = -0.5 * eigenvector(1) / eigenvector(3) ; -0.5 * eigenvector(2) / eigenvector(3)
|
||||
Covariance_matrix A
|
||||
= { FT(0), FT(0), FT(0), FT(0), FT(0),
|
||||
FT(0), FT(0), FT(0), FT(0), FT(0) };
|
||||
using Vector = typename Diagonalize_traits::Vector;
|
||||
using Matrix = typename Diagonalize_traits::Matrix;
|
||||
|
||||
A[0] = static_cast<FT>(points.size());
|
||||
for (const Point_2& p : points)
|
||||
{
|
||||
FT x = p.x() - bbox.xmin();
|
||||
FT y = p.y() - bbox.ymin();
|
||||
FT r = x*x + y*y;
|
||||
A[1] += x;
|
||||
A[2] += y;
|
||||
A[3] += r;
|
||||
A[4] += x * x;
|
||||
A[5] += x * y;
|
||||
A[6] += x * r;
|
||||
A[7] += y * y;
|
||||
A[8] += y * r;
|
||||
A[9] += r * r;
|
||||
// Use bbox to compute diagonalization with smaller coordinates to
|
||||
// avoid loss of precision when inverting large coordinates.
|
||||
const Bbox_2 bbox = bbox_2(points.begin(), points.end());
|
||||
|
||||
// Circle least squares fitting:
|
||||
// Circle of center (a, b) and radius R:
|
||||
// Ri = sqrt((xi - a)^2 + (yi - b)^2)
|
||||
// Minimize sum(Ri^2 - R^2)^2
|
||||
// -> Minimize sum(xi^2 + yi^2 − 2 * a * xi − 2 * b * yi + a^2 + b^2 − R^2)^2
|
||||
// Let B = -2a; C = -2b; D = a^2 + b^2 - R^2; and ri = x^2 + y^2.
|
||||
// -> Minimize sum(D + B * xi + C * yi + ri)^2
|
||||
// -> Minimize sum(1 + B / D * xi + C / D * yi + ri / D)^2
|
||||
// -> system of linear equations
|
||||
// -> diagonalize matrix
|
||||
// NB x y r
|
||||
// xx xy xr
|
||||
// yy yr
|
||||
// rr
|
||||
// -> center coordinates = [
|
||||
// -0.5 * eigenvector(1) / eigenvector(3);
|
||||
// -0.5 * eigenvector(2) / eigenvector(3); ]
|
||||
Covariance_matrix A = {
|
||||
FT(0), FT(0), FT(0), FT(0), FT(0),
|
||||
FT(0), FT(0), FT(0), FT(0), FT(0)
|
||||
};
|
||||
|
||||
A[0] = static_cast<FT>(points.size());
|
||||
for (const Point_2& p : points) {
|
||||
|
||||
const FT x = p.x() - bbox.xmin();
|
||||
const FT y = p.y() - bbox.ymin();
|
||||
const FT r = x * x + y * y;
|
||||
|
||||
A[1] += x;
|
||||
A[2] += y;
|
||||
A[3] += r;
|
||||
A[4] += x * x;
|
||||
A[5] += x * y;
|
||||
A[6] += x * r;
|
||||
A[7] += y * y;
|
||||
A[8] += y * r;
|
||||
A[9] += r * r;
|
||||
}
|
||||
|
||||
Vector eigenvalues = {
|
||||
FT(0), FT(0), FT(0), FT(0)
|
||||
};
|
||||
Matrix eigenvectors = {
|
||||
FT(0), FT(0), FT(0), FT(0),
|
||||
FT(0), FT(0), FT(0), FT(0),
|
||||
FT(0), FT(0), FT(0), FT(0),
|
||||
FT(0), FT(0), FT(0), FT(0)
|
||||
};
|
||||
Diagonalize_traits::
|
||||
diagonalize_selfadjoint_covariance_matrix(A, eigenvalues, eigenvectors);
|
||||
|
||||
// Perfect line case, no circle can be fitted.
|
||||
if (eigenvectors[3] == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Other cases.
|
||||
const FT half = FT(1) / FT(2);
|
||||
center = Point_2(
|
||||
bbox.xmin() - half * (eigenvectors[1] / eigenvectors[3]),
|
||||
bbox.ymin() - half * (eigenvectors[2] / eigenvectors[3]));
|
||||
|
||||
radius = FT(0);
|
||||
for (const Point_2& p : points) {
|
||||
radius += sqrt(squared_distance_2(p, center));
|
||||
}
|
||||
radius /= static_cast<FT>(points.size());
|
||||
return true;
|
||||
}
|
||||
|
||||
Vector eigenvalues = { FT(0), FT(0), FT(0), FT(0) };
|
||||
Matrix eigenvectors = { FT(0), FT(0), FT(0), FT(0),
|
||||
FT(0), FT(0), FT(0), FT(0),
|
||||
FT(0), FT(0), FT(0), FT(0),
|
||||
FT(0), FT(0), FT(0), FT(0) };
|
||||
template<
|
||||
typename PointRange,
|
||||
typename Sqrt,
|
||||
typename Squared_distance_3,
|
||||
typename Point_3,
|
||||
typename FT>
|
||||
bool create_sphere_3(
|
||||
const PointRange& points,
|
||||
const Sqrt& sqrt,
|
||||
const Squared_distance_3& squared_distance_3,
|
||||
Point_3& center, FT& radius) {
|
||||
|
||||
Diagonalize_traits::diagonalize_selfadjoint_covariance_matrix
|
||||
(A, eigenvalues, eigenvectors);
|
||||
using Diagonalize_traits = Eigen_diagonalize_traits<FT, 5>;
|
||||
using Covariance_matrix = typename Diagonalize_traits::Covariance_matrix;
|
||||
|
||||
// Perfect line case, no circle can be fitted
|
||||
if (eigenvectors[3] == 0)
|
||||
return false;
|
||||
using Vector = typename Diagonalize_traits::Vector;
|
||||
using Matrix = typename Diagonalize_traits::Matrix;
|
||||
|
||||
center = Point_2 (bbox.xmin() - FT(0.5) * (eigenvectors[1] / eigenvectors[3]),
|
||||
bbox.ymin() - FT(0.5) * (eigenvectors[2] / eigenvectors[3]));
|
||||
// Use bbox to compute diagonalization with smaller coordinates to
|
||||
// avoid loss of precision when inverting large coordinates.
|
||||
const Bbox_3 bbox = bbox_3(points.begin(), points.end());
|
||||
|
||||
radius = FT(0);
|
||||
for (const Point_2& p : points)
|
||||
radius += sqrt (squared_distance_2 (p, center));
|
||||
radius /= points.size();
|
||||
// Sphere least squares fitting.
|
||||
// See create_circle_2() above for more details on computation.
|
||||
Covariance_matrix A = {
|
||||
FT(0), FT(0), FT(0), FT(0), FT(0),
|
||||
FT(0), FT(0), FT(0), FT(0), FT(0),
|
||||
FT(0), FT(0), FT(0), FT(0), FT(0)
|
||||
};
|
||||
|
||||
return true;
|
||||
}
|
||||
A[0] = static_cast<FT>(points.size());
|
||||
for (const Point_3& p : points) {
|
||||
|
||||
template <typename PointRange,
|
||||
typename Sqrt, typename Squared_distance_3,
|
||||
typename Point_3, typename FT>
|
||||
bool sphere_fit (const PointRange& points,
|
||||
const Sqrt& sqrt,
|
||||
const Squared_distance_3& squared_distance_3,
|
||||
Point_3& center, FT& radius)
|
||||
{
|
||||
using Diagonalize_traits = Eigen_diagonalize_traits<FT, 5>;
|
||||
using Covariance_matrix = typename Diagonalize_traits::Covariance_matrix;
|
||||
using Vector = typename Diagonalize_traits::Vector;
|
||||
using Matrix = typename Diagonalize_traits::Matrix;
|
||||
const FT x = p.x() - bbox.xmin();
|
||||
const FT y = p.y() - bbox.ymin();
|
||||
const FT z = p.z() - bbox.zmin();
|
||||
const FT r = x * x + y * y + z * z;
|
||||
|
||||
// Use bbox to compute diagonalization with smaller coordinates to
|
||||
// avoid loss of precision when inverting large coordinates
|
||||
Bbox_3 bbox = bbox_3 (points.begin(), points.end());
|
||||
A[1] += x;
|
||||
A[2] += y;
|
||||
A[3] += z;
|
||||
A[4] += r;
|
||||
A[5] += x * x;
|
||||
A[6] += x * y;
|
||||
A[7] += x * z;
|
||||
A[8] += x * r;
|
||||
A[9] += y * y;
|
||||
A[10] += y * z;
|
||||
A[11] += y * r;
|
||||
A[12] += z * z;
|
||||
A[13] += z * r;
|
||||
A[14] += r * r;
|
||||
}
|
||||
|
||||
// Sphere least squares fitting
|
||||
// (see Least_square_circle_fit_region for details about computation)
|
||||
Covariance_matrix A
|
||||
= { FT(0), FT(0), FT(0), FT(0), FT(0),
|
||||
FT(0), FT(0), FT(0), FT(0), FT(0),
|
||||
FT(0), FT(0), FT(0), FT(0), FT(0) };
|
||||
Vector eigenvalues = {
|
||||
FT(0), FT(0), FT(0), FT(0), FT(0)
|
||||
};
|
||||
Matrix eigenvectors = {
|
||||
FT(0), FT(0), FT(0), FT(0), FT(0),
|
||||
FT(0), FT(0), FT(0), FT(0), FT(0),
|
||||
FT(0), FT(0), FT(0), FT(0), FT(0),
|
||||
FT(0), FT(0), FT(0), FT(0), FT(0),
|
||||
FT(0), FT(0), FT(0), FT(0), FT(0)
|
||||
};
|
||||
Diagonalize_traits::
|
||||
diagonalize_selfadjoint_covariance_matrix(A, eigenvalues, eigenvectors);
|
||||
|
||||
A[0] = static_cast<FT>(points.size());
|
||||
for (const Point_3& p : points)
|
||||
{
|
||||
FT x = p.x() - bbox.xmin();
|
||||
FT y = p.y() - bbox.ymin();
|
||||
FT z = p.z() - bbox.zmin();
|
||||
FT r = x*x + y*y + z*z;
|
||||
A[1] += x;
|
||||
A[2] += y;
|
||||
A[3] += z;
|
||||
A[4] += r;
|
||||
A[5] += x * x;
|
||||
A[6] += x * y;
|
||||
A[7] += x * z;
|
||||
A[8] += x * r;
|
||||
A[9] += y * y;
|
||||
A[10] += y * z;
|
||||
A[11] += y * r;
|
||||
A[12] += z * z;
|
||||
A[13] += z * r;
|
||||
A[14] += r * r;
|
||||
// Perfect plane case, no sphere can be fitted.
|
||||
if (eigenvectors[4] == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Other cases.
|
||||
const FT half = FT(1) / FT(2);
|
||||
center = Point_3(
|
||||
bbox.xmin() - half * (eigenvectors[1] / eigenvectors[4]),
|
||||
bbox.ymin() - half * (eigenvectors[2] / eigenvectors[4]),
|
||||
bbox.zmin() - half * (eigenvectors[3] / eigenvectors[4]));
|
||||
|
||||
radius = FT(0);
|
||||
for (const Point_3& p : points) {
|
||||
radius += sqrt(squared_distance_3(p, center));
|
||||
}
|
||||
radius /= static_cast<FT>(points.size());
|
||||
return true;
|
||||
}
|
||||
|
||||
Vector eigenvalues = { FT(0), FT(0), FT(0), FT(0), FT(0) };
|
||||
Matrix eigenvectors = { FT(0), FT(0), FT(0), FT(0), FT(0),
|
||||
FT(0), FT(0), FT(0), FT(0), FT(0),
|
||||
FT(0), FT(0), FT(0), FT(0), FT(0),
|
||||
FT(0), FT(0), FT(0), FT(0), FT(0),
|
||||
FT(0), FT(0), FT(0), FT(0), FT(0) };
|
||||
template<
|
||||
typename PointRange,
|
||||
typename PointMap,
|
||||
typename NormalMap,
|
||||
typename Sqrt,
|
||||
typename Squared_distance_3,
|
||||
typename Line_3,
|
||||
typename FT>
|
||||
bool create_cylinder_3(
|
||||
const PointRange& points,
|
||||
PointMap point_map,
|
||||
NormalMap normal_map,
|
||||
const Sqrt& sqrt,
|
||||
const Squared_distance_3& squared_distance_3,
|
||||
Line_3& axis, FT& radius) {
|
||||
|
||||
Diagonalize_traits::diagonalize_selfadjoint_covariance_matrix
|
||||
(A, eigenvalues, eigenvectors);
|
||||
using Point_3 = typename boost::property_traits<PointMap>::value_type;
|
||||
using Vector_3 = typename boost::property_traits<NormalMap>::value_type;
|
||||
|
||||
// Perfect plane case, no sphere can be fitted
|
||||
if (eigenvectors[4] == 0)
|
||||
return false;
|
||||
const Point_3& ref = get(point_map, *(points.begin()));
|
||||
|
||||
center = Point_3 (bbox.xmin() - FT(0.5) * (eigenvectors[1] / eigenvectors[4]),
|
||||
bbox.ymin() - FT(0.5) * (eigenvectors[2] / eigenvectors[4]),
|
||||
bbox.zmin() - FT(0.5) * (eigenvectors[3] / eigenvectors[4]));
|
||||
radius = FT(0);
|
||||
std::size_t nb = 0;
|
||||
Vector_3 mean_axis = CGAL::NULL_VECTOR;
|
||||
Point_3 point_on_axis = ORIGIN;
|
||||
|
||||
radius = FT(0);
|
||||
for (const Point_3& p : points)
|
||||
radius += sqrt (squared_distance_3 (p, center));
|
||||
radius /= points.size();
|
||||
for (std::size_t i = 0; i < points.size() - 1; ++i) {
|
||||
|
||||
return true;
|
||||
}
|
||||
Vector_3 v0 = get(normal_map, *std::next(points.begin(), i));
|
||||
v0 = v0 / sqrt(v0 * v0);
|
||||
Vector_3 v1 = get(normal_map, *std::next(points.begin(), i + 1));
|
||||
v1 = v1 / sqrt(v1 * v1);
|
||||
Vector_3 axis = cross_product(v0, v1);
|
||||
if (sqrt(axis.squared_length()) < FT(1) / FT(100)) {
|
||||
continue;
|
||||
}
|
||||
axis = axis / sqrt(axis * axis);
|
||||
|
||||
template <typename PointRange, typename PointMap, typename NormalMap,
|
||||
typename Sqrt, typename Squared_distance_3,
|
||||
typename Line_3, typename FT>
|
||||
bool cylinder_fit (const PointRange& points,
|
||||
PointMap point_map, NormalMap normal_map,
|
||||
const Sqrt& sqrt,
|
||||
const Squared_distance_3& squared_distance_3,
|
||||
Line_3& axis, FT& radius)
|
||||
{
|
||||
using Point_3 = typename boost::property_traits<PointMap>::value_type;
|
||||
using Vector_3 = typename boost::property_traits<NormalMap>::value_type;
|
||||
const Point_3& p0 = get(point_map, *std::next(points.begin(), i));
|
||||
const Point_3& p1 = get(point_map, *std::next(points.begin(), i + 1));
|
||||
|
||||
const Point_3& ref = get(point_map, *(points.begin()));
|
||||
Vector_3 xdir = v0 - axis * (v0 * axis);
|
||||
xdir = xdir / sqrt(xdir * xdir);
|
||||
|
||||
Vector_3 mean_axis = CGAL::NULL_VECTOR;
|
||||
std::size_t nb = 0;
|
||||
radius = FT(0);
|
||||
Point_3 point_on_axis = ORIGIN;
|
||||
for (std::size_t i = 0; i < points.size() - 1; ++ i)
|
||||
{
|
||||
Vector_3 v0 = get(normal_map, *std::next(points.begin(), i));
|
||||
v0 = v0 / sqrt(v0*v0);
|
||||
Vector_3 v1 = get(normal_map, *std::next(points.begin(), i + 1));
|
||||
v1 = v1 / sqrt(v1*v1);
|
||||
Vector_3 axis = cross_product (v0, v1);
|
||||
if (sqrt(axis.squared_length()) < (FT)(0.01))
|
||||
continue;
|
||||
axis = axis / sqrt(axis * axis);
|
||||
Vector_3 ydir = cross_product(axis, xdir);
|
||||
ydir = ydir / sqrt (ydir * ydir);
|
||||
|
||||
const Point_3& p0 = get(point_map, *std::next(points.begin(), i));
|
||||
const Point_3& p1 = get(point_map, *std::next(points.begin(), i + 1));
|
||||
const FT v1x = v1 * ydir;
|
||||
const FT v1y = -v1 * xdir;
|
||||
|
||||
Vector_3 xdir = v0 - axis * (v0 * axis);
|
||||
xdir = xdir / sqrt (xdir * xdir);
|
||||
Vector_3 d(p0, p1);
|
||||
const FT ox = xdir * d;
|
||||
const FT oy = ydir * d;
|
||||
const FT ldist = v1x * ox + v1y * oy;
|
||||
|
||||
Vector_3 ydir = cross_product (axis, xdir);
|
||||
ydir = ydir / sqrt (ydir * ydir);
|
||||
FT r = ldist / v1x;
|
||||
Point_3 point = p0 + xdir * r;
|
||||
const Line_3 line(point, axis);
|
||||
point = line.projection(ref);
|
||||
point_on_axis = barycenter(point_on_axis, static_cast<FT>(nb), point, FT(1));
|
||||
r += abs(r);
|
||||
|
||||
FT v1x = v1 * ydir;
|
||||
FT v1y = -v1 * xdir;
|
||||
if (nb != 0 && axis * mean_axis < 0) {
|
||||
axis = -axis;
|
||||
}
|
||||
mean_axis = mean_axis + axis;
|
||||
++nb;
|
||||
}
|
||||
|
||||
Vector_3 d (p0, p1);
|
||||
if (nb == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
FT ox = xdir * d;
|
||||
FT oy = ydir * d;
|
||||
FT ldist = v1x * ox + v1y * oy;
|
||||
mean_axis = mean_axis / sqrt(mean_axis * mean_axis);
|
||||
axis = Line_3(point_on_axis, mean_axis);
|
||||
radius /= static_cast<FT>(nb);
|
||||
|
||||
FT radius = ldist / v1x;
|
||||
|
||||
Point_3 point = p0 + xdir * radius;
|
||||
Line_3 line (point, axis);
|
||||
point = line.projection(ref);
|
||||
|
||||
point_on_axis = barycenter (point_on_axis, static_cast<FT>(nb), point, FT(1));
|
||||
|
||||
radius += abs(radius);
|
||||
|
||||
if (nb != 0 && axis * mean_axis < 0)
|
||||
axis = -axis;
|
||||
|
||||
mean_axis = mean_axis + axis;
|
||||
++ nb;
|
||||
radius = FT(0);
|
||||
for (const auto& p : points) {
|
||||
const Point_3& p0 = get(point_map, p);
|
||||
radius += sqrt(squared_distance_3(p0, axis));
|
||||
}
|
||||
radius /= static_cast<FT>(points.size());
|
||||
return true;
|
||||
}
|
||||
|
||||
if (nb == 0)
|
||||
return false;
|
||||
|
||||
mean_axis = mean_axis / sqrt(mean_axis * mean_axis);
|
||||
axis = Line_3 (point_on_axis, mean_axis);
|
||||
radius /= nb;
|
||||
|
||||
radius = FT(0);
|
||||
for (const auto& p : points)
|
||||
{
|
||||
const Point_3& p0 = get(point_map, p);
|
||||
radius += sqrt(squared_distance_3(p0, axis));
|
||||
}
|
||||
radius /= points.size();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
} // namespace Shape_detection
|
||||
} // namespace CGAL
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ Additional shapes can be detected, given a custom shape class by the user.
|
|||
|
||||
In addition to the RANSAC algorithm, the generic Region Growing algorithm is implemented.
|
||||
This algorithm can detect shapes in a set of arbitrary items. In particular,
|
||||
CGAL provides five instances of the algorithm: detecting lines in a 2D point set,
|
||||
detecting planes in a 3D point set, detecting planes on a polygon mesh, detecting lines
|
||||
CGAL provides several instances of the algorithm: detecting lines and circles in a 2D point set,
|
||||
detecting planes, spheres, and cylinders in a 3D point set, detecting planes on a polygon mesh, detecting lines
|
||||
in a 2D/3D segment set, and detecting lines on a 2D/3D polyline.
|
||||
Other custom instances can be easily added by the user.
|
||||
|
|
|
|||
|
|
@ -107,8 +107,8 @@ bool test (int argc, char** argv, const std::size_t minr, const std::size_t maxr
|
|||
int main(int argc, char *argv[]) {
|
||||
|
||||
return ((
|
||||
test<Line_region, Line_sorting>(argc, argv, 62, 66) // &&
|
||||
// test<Circle_region, Circle_sorting>(argc, argv, 196, 200)
|
||||
test<Line_region, Line_sorting>(argc, argv, 62, 66) &&
|
||||
test<Circle_region, Circle_sorting>(argc, argv, 196, 200)
|
||||
) ? EXIT_SUCCESS : EXIT_FAILURE );
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -138,7 +138,6 @@ int main(int argc, char *argv[]) {
|
|||
if (!success)
|
||||
return EXIT_FAILURE;
|
||||
|
||||
/*
|
||||
success =
|
||||
test<Sphere_region, Sphere_sorting>
|
||||
(argc, argv,
|
||||
|
|
@ -154,7 +153,7 @@ int main(int argc, char *argv[]) {
|
|||
const std::size_t min_region_size = 50;
|
||||
// No constraint on radius
|
||||
const double min_radius = 0.;
|
||||
const double max_radius = std::numeric_limits<double>::infinity();
|
||||
const double max_radius = std::numeric_limits<double>::max();
|
||||
return Sphere_region
|
||||
(input_range, tolerance, max_angle, min_region_size,
|
||||
min_radius, max_radius,
|
||||
|
|
@ -182,7 +181,7 @@ int main(int argc, char *argv[]) {
|
|||
const std::size_t min_region_size = 200;
|
||||
// No constraint on radius
|
||||
const double min_radius = 0.;
|
||||
const double max_radius = std::numeric_limits<double>::infinity();
|
||||
const double max_radius = std::numeric_limits<double>::max();
|
||||
return Cylinder_region
|
||||
(input_range, tolerance, max_angle, min_region_size,
|
||||
min_radius, max_radius,
|
||||
|
|
@ -193,7 +192,7 @@ int main(int argc, char *argv[]) {
|
|||
return (r.size() > 2 && r.size() < 30);
|
||||
});
|
||||
if (!success)
|
||||
return EXIT_FAILURE; */
|
||||
return EXIT_FAILURE;
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue