added internal region growing traits and polyline graph based on segments

This commit is contained in:
Dmitry Anisimov 2021-03-26 14:48:53 +01:00
parent 35648ab3d6
commit 8cc513e935
20 changed files with 678 additions and 193 deletions

View File

@ -20,7 +20,7 @@ if(TARGET CGAL::Eigen3_support)
create_single_source_cgal_program("region_growing_on_point_set_2.cpp")
create_single_source_cgal_program("region_growing_on_point_set_3.cpp")
create_single_source_cgal_program("region_growing_on_polygon_mesh.cpp")
# create_single_source_cgal_program("region_growing_on_polyline_graph.cpp")
create_single_source_cgal_program("region_growing_on_polyline_graph.cpp")
create_single_source_cgal_program("region_growing_on_polyline.cpp")
create_single_source_cgal_program("region_growing_with_custom_classes.cpp")
create_single_source_cgal_program("shape_detection_basic_deprecated.cpp")
@ -34,7 +34,7 @@ if(TARGET CGAL::Eigen3_support)
region_growing_on_point_set_2
region_growing_on_point_set_3
region_growing_on_polygon_mesh
# region_growing_on_polyline_graph
region_growing_on_polyline_graph
region_growing_on_polyline
region_growing_with_custom_classes
shape_detection_basic_deprecated)

View File

@ -132,6 +132,104 @@ void save_point_regions_3(
out.close();
}
template<typename Kernel, typename Input_range, typename Segment_map>
void save_segment_regions_2(
const Input_range& input_range,
const std::vector< std::vector<std::size_t> >& regions,
const std::string fullpath,
const Segment_map segment_map = Segment_map()) {
using Point_3 = typename Kernel::Point_3;
using Color = std::array<unsigned char, 3>;
using Point_with_color = std::pair<Point_3, Color>;
using PLY_Point_map = CGAL::First_of_pair_property_map<Point_with_color>;
using PLY_Color_map = CGAL::Second_of_pair_property_map<Point_with_color>;
std::vector<Point_with_color> pwc;
srand(static_cast<unsigned int>(time(NULL)));
// Iterate through all regions.
for (const auto& region : regions) {
// Generate a random color.
const Color color =
CGAL::make_array(
static_cast<unsigned char>(rand() % 256),
static_cast<unsigned char>(rand() % 256),
static_cast<unsigned char>(rand() % 256));
// Iterate through all region items.
for (const auto index : region) {
const auto& key = *(input_range.begin() + index);
const auto& segment = get(segment_map, key);
const auto& s = segment.source();
const auto& t = segment.target();
pwc.push_back(std::make_pair(Point_3(s.x(), s.y(), 0), color));
pwc.push_back(std::make_pair(Point_3(t.x(), t.y(), 0), color));
}
}
std::ofstream out(fullpath);
CGAL::set_ascii_mode(out);
CGAL::write_PLY_with_properties(
out, pwc,
CGAL::make_ply_point_writer(PLY_Point_map()),
std::make_tuple(
PLY_Color_map(),
CGAL::PLY_property<unsigned char>("red"),
CGAL::PLY_property<unsigned char>("green"),
CGAL::PLY_property<unsigned char>("blue")));
out.close();
}
template<typename Kernel, typename Input_range, typename Segment_map>
void save_segment_regions_3(
const Input_range& input_range,
const std::vector< std::vector<std::size_t> >& regions,
const std::string fullpath,
const Segment_map segment_map = Segment_map()) {
using Point_3 = typename Kernel::Point_3;
using Color = std::array<unsigned char, 3>;
using Point_with_color = std::pair<Point_3, Color>;
using PLY_Point_map = CGAL::First_of_pair_property_map<Point_with_color>;
using PLY_Color_map = CGAL::Second_of_pair_property_map<Point_with_color>;
std::vector<Point_with_color> pwc;
srand(static_cast<unsigned int>(time(NULL)));
// Iterate through all regions.
for (const auto& region : regions) {
// Generate a random color.
const Color color =
CGAL::make_array(
static_cast<unsigned char>(rand() % 256),
static_cast<unsigned char>(rand() % 256),
static_cast<unsigned char>(rand() % 256));
// Iterate through all region items.
for (const auto index : region) {
const auto& key = *(input_range.begin() + index);
const auto& segment = get(segment_map, key);
pwc.push_back(std::make_pair(segment.source(), color));
pwc.push_back(std::make_pair(segment.target(), color));
}
}
std::ofstream out(fullpath);
CGAL::set_ascii_mode(out);
CGAL::write_PLY_with_properties(
out, pwc,
CGAL::make_ply_point_writer(PLY_Point_map()),
std::make_tuple(
PLY_Color_map(),
CGAL::PLY_property<unsigned char>("red"),
CGAL::PLY_property<unsigned char>("green"),
CGAL::PLY_property<unsigned char>("blue")));
out.close();
}
// Define an insert iterator.
template<
typename Input_range,

View File

@ -0,0 +1,96 @@
#include <CGAL/IO/PLY.h>
#include <CGAL/IO/OFF.h>
#include <CGAL/Surface_mesh.h>
#include <CGAL/Shape_detection/Region_growing/Region_growing.h>
#include <CGAL/Shape_detection/Region_growing/Region_growing_on_segment_set.h>
#include <CGAL/Shape_detection/Region_growing/Region_growing_on_polygon_mesh.h>
#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
#include "include/utils.h"
// Typedefs.
using Kernel = CGAL::Exact_predicates_inexact_constructions_kernel;
using Point_3 = typename Kernel::Point_3;
using Surface_mesh = CGAL::Surface_mesh<Point_3>;
using Face_range = typename Surface_mesh::Face_range;
using Edge_range = typename Surface_mesh::Edge_range;
using One_ring_query = CGAL::Shape_detection::Polygon_mesh::One_ring_neighbor_query<Surface_mesh>;
using Plane_region = CGAL::Shape_detection::Polygon_mesh::Least_squares_plane_fit_region<Kernel, Surface_mesh>;
using RG_planes = CGAL::Shape_detection::Region_growing<Face_range, One_ring_query, Plane_region>;
using Vertex_to_point_map = typename Plane_region::Vertex_to_point_map;
using Polyline_graph = CGAL::Shape_detection::Polygon_mesh::Polyline_graph<Kernel, Surface_mesh>;
using Segment_range = typename Polyline_graph::Segment_range;
using Segment_map = typename Polyline_graph::Segment_map;
// using Line_region = CGAL::Shape_detection::Segment_set::Least_squares_line_fit_region<Kernel, Segment_range, Segment_map>;
// using Line_sorting = CGAL::Shape_detection::Segment_set::Least_squares_line_fit_sorting<Kernel, Segment_range, Polyline_graph, Segment_map>;
// using RG_lines = CGAL::Shape_detection::Region_growing<Segment_range, Polyline_graph, Line_region, typename Line_sorting::Seed_map>;
int main(int argc, char *argv[]) {
// Load data either from a local folder or a user-provided file.
const std::string input_filename = (argc > 1 ? argv[1] : "data/am.off");
std::ifstream in_off(input_filename);
std::ifstream in_ply(input_filename);
CGAL::set_ascii_mode(in_off);
CGAL::set_ascii_mode(in_ply);
Surface_mesh surface_mesh;
if (CGAL::read_OFF(in_off, surface_mesh)) { in_off.close();
} else if (CGAL::read_PLY(in_ply, surface_mesh)) { in_ply.close();
} else {
std::cerr << "ERROR: cannot read the input file!" << std::endl;
return EXIT_FAILURE;
}
const Face_range face_range = faces(surface_mesh);
const Edge_range edge_range = edges(surface_mesh);
std::cout << "- number of input faces: " << face_range.size() << std::endl;
std::cout << "- number of input edges: " << edge_range.size() << std::endl;
assert(face_range.size() == 7320);
assert(edge_range.size() == 10980);
const Vertex_to_point_map vertex_to_point_map(
get(CGAL::vertex_point, surface_mesh));
// Find planar regions.
One_ring_query one_ring_query(surface_mesh);
Plane_region plane_region(surface_mesh,
CGAL::parameters::all_default(), vertex_to_point_map);
RG_planes rg_planes(face_range, one_ring_query, plane_region);
std::vector< std::vector<std::size_t> > regions;
rg_planes.detect(std::back_inserter(regions));
std::cout << "- number of found planar regions: " << regions.size() << std::endl;
assert(regions.size() == 9);
std::string fullpath = (argc > 2 ? argv[2] : "regions_sm.ply");
utils::save_polygon_mesh_regions(surface_mesh, regions, fullpath);
// Find linear regions.
Polyline_graph pgraph(surface_mesh, regions, vertex_to_point_map);
const auto& segment_range = pgraph.segment_range();
std::cout << "* number of extracted segments: " << segment_range.size() << std::endl;
// Line_region line_region(
// segment_range, CGAL::parameters::all_default(), pgraph.segment_map());
// Line_sorting line_sorting(
// segment_range, pgraph, pgraph.segment_map());
// line_sorting.sort();
// RG_lines rg_lines(
// segment_range, pgraph, line_region, line_sorting.seed_map());
// std::vector< std::vector<std::size_t> > subregions;
// rg_lines.detect(std::back_inserter(subregions));
// std::cout << "- number of found linear regions: " << subregions.size() << std::endl;
// assert(subregions.size() == 21);
// fullpath = (argc > 2 ? argv[2] : "subregions_sm.ply");
// utils::save_segment_regions_3<Kernel, Segment_range, Segment_map>(
// segment_range, subregions, fullpath, pgraph.segment_map());
return EXIT_SUCCESS;
}

View File

@ -16,19 +16,9 @@
#include <CGAL/license/Shape_detection.h>
// STL includes.
#include <typeinfo>
#include <type_traits>
// Boost includes.
#include <CGAL/boost/graph/named_params_helper.h>
#include <CGAL/boost/iterator/counting_iterator.hpp>
#include <CGAL/boost/graph/Named_function_parameters.h>
// CGAL includes.
#include <CGAL/Kd_tree.h>
#include <CGAL/Splitters.h>
#include <CGAL/assertions.h>
#include <CGAL/Search_traits_2.h>
#include <CGAL/Search_traits_3.h>
#include <CGAL/Search_traits_adapter.h>

View File

@ -16,10 +16,6 @@
#include <CGAL/license/Shape_detection.h>
// Boost includes.
#include <CGAL/boost/graph/named_params_helper.h>
#include <CGAL/boost/graph/Named_function_parameters.h>
// Internal includes.
#include <CGAL/Shape_detection/Region_growing/internal/utils.h>

View File

@ -17,7 +17,6 @@
#include <CGAL/license/Shape_detection.h>
// Internal includes.
#include <CGAL/Shape_detection/Region_growing/internal/utils.h>
#include <CGAL/Shape_detection/Region_growing/internal/property_map.h>
namespace CGAL {

View File

@ -16,10 +16,6 @@
#include <CGAL/license/Shape_detection.h>
// Boost includes.
#include <CGAL/boost/graph/named_params_helper.h>
#include <CGAL/boost/graph/Named_function_parameters.h>
// Internal includes.
#include <CGAL/Shape_detection/Region_growing/internal/utils.h>

View File

@ -17,7 +17,6 @@
#include <CGAL/license/Shape_detection.h>
// Internal includes.
#include <CGAL/Shape_detection/Region_growing/internal/utils.h>
#include <CGAL/Shape_detection/Region_growing/internal/property_map.h>
namespace CGAL {

View File

@ -16,19 +16,9 @@
#include <CGAL/license/Shape_detection.h>
// STL includes.
#include <typeinfo>
#include <type_traits>
// Boost includes.
#include <CGAL/boost/graph/named_params_helper.h>
#include <CGAL/boost/iterator/counting_iterator.hpp>
#include <CGAL/boost/graph/Named_function_parameters.h>
// CGAL includes.
#include <CGAL/Kd_tree.h>
#include <CGAL/Splitters.h>
#include <CGAL/assertions.h>
#include <CGAL/Fuzzy_sphere.h>
#include <CGAL/Search_traits_2.h>
#include <CGAL/Search_traits_3.h>

View File

@ -16,10 +16,6 @@
#include <CGAL/license/Shape_detection.h>
// Boost includes.
#include <CGAL/boost/graph/named_params_helper.h>
#include <CGAL/boost/graph/Named_function_parameters.h>
// Internal includes.
#include <CGAL/Shape_detection/Region_growing/internal/utils.h>

View File

@ -17,7 +17,6 @@
#include <CGAL/license/Shape_detection.h>
// Internal includes.
#include <CGAL/Shape_detection/Region_growing/internal/utils.h>
#include <CGAL/Shape_detection/Region_growing/internal/property_map.h>
namespace CGAL {

View File

@ -16,15 +16,6 @@
#include <CGAL/license/Shape_detection.h>
// Boost includes.
#include <boost/graph/properties.hpp>
#include <boost/graph/graph_traits.hpp>
// Face graph includes.
#include <CGAL/boost/graph/iterator.h>
#include <CGAL/boost/graph/graph_traits_Surface_mesh.h>
#include <CGAL/boost/graph/graph_traits_Polyhedron_3.h>
// Internal includes.
#include <CGAL/Shape_detection/Region_growing/internal/property_map.h>

View File

@ -0,0 +1,209 @@
// 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_POLYGON_MESH_POLYLINE_GRAPH_H
#define CGAL_SHAPE_DETECTION_REGION_GROWING_POLYGON_MESH_POLYLINE_GRAPH_H
#include <CGAL/license/Shape_detection.h>
// Internal includes.
#include <CGAL/Shape_detection/Region_growing/internal/property_map.h>
namespace CGAL {
namespace Shape_detection {
namespace Polygon_mesh {
template<
typename GeomTraits,
typename PolygonMesh,
typename FaceRange = typename PolygonMesh::Face_range,
typename EdgeRange = typename PolygonMesh::Edge_range,
typename VertexToPointMap = typename boost::property_map<PolygonMesh, CGAL::vertex_point_t>::type>
class Polyline_graph {
private:
struct PEdge {
std::size_t index = std::size_t(-1);
std::set<std::size_t> neighbors;
std::vector<std::size_t> regions;
};
public:
using Traits = GeomTraits;
using Face_graph = PolygonMesh;
using Face_range = FaceRange;
using Edge_range = EdgeRange;
using Vertex_to_point_map = VertexToPointMap;
using Segment_range = std::vector<PEdge>;
using Segment_map = internal::Polyline_graph_segment_map<PEdge, Face_graph, Edge_range, Vertex_to_point_map>;
private:
using Face_to_region_map = internal::Item_to_region_index_map;
using Face_to_index_map = internal::Item_to_index_property_map<Face_range>;
using Edge_to_index_map = internal::Item_to_index_property_map<Edge_range>;
public:
Polyline_graph(
const PolygonMesh& pmesh,
const std::vector< std::vector<std::size_t> >& regions,
const VertexToPointMap vertex_to_point_map) :
m_face_graph(pmesh),
m_regions(regions),
m_face_range(faces(m_face_graph)),
m_edge_range(edges(m_face_graph)),
m_vertex_to_point_map(vertex_to_point_map),
m_face_to_region_map(m_face_range, regions),
m_face_to_index_map(m_face_range),
m_edge_to_index_map(m_edge_range),
m_segment_map(m_face_graph, m_edge_range, m_vertex_to_point_map) {
CGAL_precondition(m_face_range.size() > 0);
CGAL_precondition(m_edge_range.size() > 0);
CGAL_precondition(regions.size() > 0);
build_graph();
}
void build_graph() {
clear();
int r1 = -1, r2 = -1;
std::vector<std::size_t> pedge_map(
m_edge_range.size(), std::size_t(-1));
for (const auto& edge : m_edge_range) {
std::tie(r1, r2) = get_regions(edge);
if (r1 == r2) continue;
add_graph_edge(edge, r1, r2, pedge_map);
}
for (std::size_t i = 0; i < m_pedges.size(); ++i) {
auto& pedge = m_pedges[i];
CGAL_precondition(pedge.regions.size() == 2);
CGAL_precondition(pedge.regions[0] != pedge.regions[1]);
CGAL_precondition(pedge.index != std::size_t(-1));
CGAL_precondition(pedge.index < m_edge_range.size());
const auto& edge = *(m_edge_range.begin() + pedge.index);
const auto s = source(edge, m_face_graph);
const auto t = target(edge, m_face_graph);
add_vertex_neighbors(s, i, pedge_map, pedge.neighbors);
add_vertex_neighbors(t, i, pedge_map, pedge.neighbors);
}
}
void operator()(
const std::size_t query_index,
std::vector<std::size_t>& neighbors) const {
neighbors.clear();
CGAL_precondition(query_index < m_pedges.size());
const auto& pedge = m_pedges[query_index];
for (const std::size_t neighbor : pedge.neighbors)
neighbors.push_back(neighbor);
}
const Segment_range& segment_range() const {
return m_pedges;
}
const Segment_map& segment_map() const {
return m_segment_map;
}
void clear() {
m_pedges.clear();
}
void release_memory() {
m_pedges.shrink_to_fit();
}
private:
const Face_graph& m_face_graph;
const std::vector< std::vector<std::size_t> >& m_regions;
const Face_range m_face_range;
const Edge_range m_edge_range;
const Vertex_to_point_map m_vertex_to_point_map;
const Face_to_region_map m_face_to_region_map;
const Face_to_index_map m_face_to_index_map;
const Edge_to_index_map m_edge_to_index_map;
const Segment_map m_segment_map;
Segment_range m_pedges;
template<typename EdgeType>
std::pair<int, int> get_regions(const EdgeType& edge) const {
const auto hedge1 = halfedge(edge, m_face_graph);
const auto hedge2 = opposite(hedge1, m_face_graph);
const auto face1 = face(hedge1, m_face_graph);
const auto face2 = face(hedge2, m_face_graph);
const std::size_t fi1 = get(m_face_to_index_map, face1);
const std::size_t fi2 = get(m_face_to_index_map, face2);
CGAL_precondition(fi1 != fi2);
int r1 = -1, r2 = -1;
if (fi1 != std::size_t(-1))
r1 = get(m_face_to_region_map, fi1);
if (fi2 != std::size_t(-1))
r2 = get(m_face_to_region_map, fi2);
return std::make_pair(r1, r2);
}
template<typename EdgeType>
void add_graph_edge(
const EdgeType& edge, const int region1, const int region2,
std::vector<std::size_t>& pedge_map) {
PEdge pedge;
CGAL_precondition(region1 != region2);
const std::size_t edge_index = get(m_edge_to_index_map, edge);
CGAL_precondition(edge_index != std::size_t(-1));
pedge.index = edge_index;
pedge.regions.push_back(region1);
pedge.regions.push_back(region2);
CGAL_precondition(pedge.index < pedge_map.size());
pedge_map[pedge.index] = m_pedges.size();
m_pedges.push_back(pedge);
}
template<typename VertexType>
void add_vertex_neighbors(
const VertexType& vertex, const std::size_t curr_pe,
const std::vector<std::size_t>& pedge_map,
std::set<std::size_t>& neighbors) const {
const auto query_hedge = halfedge(vertex, m_face_graph);
const auto hedges = halfedges_around_target(query_hedge, m_face_graph);
CGAL_precondition(hedges.size() > 0);
for (const auto& hedge : hedges) {
const auto e = edge(hedge, m_face_graph);
const std::size_t ei = get(m_edge_to_index_map, e);
CGAL_precondition(ei < pedge_map.size());
const std::size_t pe = pedge_map[ei];
if (pe == std::size_t(-1)) continue;
if (pe == curr_pe) continue;
CGAL_precondition(pe < m_pedges.size());
neighbors.insert(pe);
}
}
};
} // namespace Polygon_mesh
} // namespace Shape_detection
} // namespace CGAL
#endif // CGAL_SHAPE_DETECTION_REGION_GROWING_POLYGON_MESH_POLYLINE_GRAPH_H

View File

@ -16,12 +16,8 @@
#include <CGAL/license/Shape_detection.h>
// Boost includes.
#include <CGAL/boost/graph/named_params_helper.h>
#include <CGAL/boost/graph/Named_function_parameters.h>
// Internal includes.
#include <CGAL/Shape_detection/Region_growing/internal/utils.h>
#include <CGAL/Shape_detection/Region_growing/internal/region_growing_traits.h>
namespace CGAL {
namespace Shape_detection {

View File

@ -17,7 +17,6 @@
#include <CGAL/license/Shape_detection.h>
// Internal includes.
#include <CGAL/Shape_detection/Region_growing/internal/utils.h>
#include <CGAL/Shape_detection/Region_growing/internal/property_map.h>
namespace CGAL {

View File

@ -21,7 +21,6 @@
#include <CGAL/boost/graph/Named_function_parameters.h>
// Internal includes.
#include <CGAL/Shape_detection/Region_growing/internal/utils.h>
#include <CGAL/Shape_detection/Region_growing/internal/property_map.h>
namespace CGAL {
@ -29,7 +28,6 @@ namespace Shape_detection {
namespace internal {
template<
typename GeomTraits,
typename PolygonMesh,
typename FaceRange = typename PolygonMesh::Face_range,
typename VertexRange = typename PolygonMesh::Vertex_range,
@ -44,14 +42,13 @@ namespace internal {
};
public:
using Traits = GeomTraits;
using Face_graph = PolygonMesh;
using Face_range = FaceRange;
using Vertex_range = VertexRange;
using Vertex_to_point_map = VertexToPointMap;
using PVertex_range = std::vector<PVertex>;
using Point_map = internal::Polyline_graph_point_map<PVertex, Vertex_range, Vertex_to_point_map>;
using Point_range = std::vector<PVertex>;
using Point_map = internal::Polyline_graph_point_map<PVertex, Vertex_range, Vertex_to_point_map>;
private:
using Face_to_region_map = internal::Item_to_region_index_map;
@ -75,33 +72,20 @@ namespace internal {
CGAL_precondition(m_face_range.size() > 0);
CGAL_precondition(m_vertex_range.size() > 0);
CGAL_precondition(regions.size() > 0);
build_graph();
}
void build_graph() {
clear();
std::vector<std::size_t> vertex_map(
int r1 = -1, r2 = -1;
std::vector<std::size_t> pvertex_map(
m_vertex_range.size(), std::size_t(-1));
for (const auto& edge : edges(m_face_graph)) {
const auto hedge1 = halfedge(edge, m_face_graph);
const auto hedge2 = opposite(hedge1, m_face_graph);
const auto face1 = face(hedge1, m_face_graph);
const auto face2 = face(hedge2, m_face_graph);
const std::size_t fi1 = get(m_face_to_index_map, face1);
const std::size_t fi2 = get(m_face_to_index_map, face2);
CGAL_precondition(fi1 != fi2);
int r1 = -1, r2 = -1;
if (fi1 != std::size_t(-1))
r1 = get(m_face_to_region_map, fi1);
if (fi2 != std::size_t(-1))
r2 = get(m_face_to_region_map, fi2);
std::tie(r1, r2) = get_regions(edge);
if (r1 == r2) continue;
CGAL_precondition(r1 != r2);
add_graph_edge(edge, r1, r2, vertex_map);
add_graph_edge(edge, r1, r2, pvertex_map);
}
}
@ -110,14 +94,14 @@ namespace internal {
std::vector<std::size_t>& neighbors) const {
neighbors.clear();
CGAL_precondition(query_index < m_vertices.size());
const auto& vertex = m_vertices[query_index];
for (const std::size_t neighbor : vertex.neighbors)
CGAL_precondition(query_index < m_pvertices.size());
const auto& pvertex = m_pvertices[query_index];
for (const std::size_t neighbor : pvertex.neighbors)
neighbors.push_back(neighbor);
}
const PVertex_range& pvertex_range() const {
return m_vertices;
const Point_range& point_range() const {
return m_pvertices;
}
const Point_map& point_map() const {
@ -125,7 +109,11 @@ namespace internal {
}
void clear() {
m_vertices.clear();
m_pvertices.clear();
}
void release_memory() {
m_pvertices.shrink_to_fit();
}
private:
@ -138,12 +126,33 @@ namespace internal {
const Face_to_index_map m_face_to_index_map;
const Vertex_to_index_map m_vertex_to_index_map;
const Point_map m_point_map;
PVertex_range m_vertices;
Point_range m_pvertices;
template<typename EdgeType>
std::pair<int, int> get_regions(const EdgeType& edge) const {
const auto hedge1 = halfedge(edge, m_face_graph);
const auto hedge2 = opposite(hedge1, m_face_graph);
const auto face1 = face(hedge1, m_face_graph);
const auto face2 = face(hedge2, m_face_graph);
const std::size_t fi1 = get(m_face_to_index_map, face1);
const std::size_t fi2 = get(m_face_to_index_map, face2);
CGAL_precondition(fi1 != fi2);
int r1 = -1, r2 = -1;
if (fi1 != std::size_t(-1))
r1 = get(m_face_to_region_map, fi1);
if (fi2 != std::size_t(-1))
r2 = get(m_face_to_region_map, fi2);
return std::make_pair(r1, r2);
}
template<typename EdgeType>
void add_graph_edge(
const EdgeType& edge, const int region1, const int region2,
std::vector<std::size_t>& vertex_map) {
std::vector<std::size_t>& pvertex_map) {
const auto s = source(edge, m_face_graph);
const auto t = target(edge, m_face_graph);
@ -155,36 +164,39 @@ namespace internal {
CGAL_precondition(vsource != vtarget);
CGAL_precondition(region1 != region2);
CGAL_precondition(
vertex_map.size() == m_vertex_range.size());
pvertex_map.size() == m_vertex_range.size());
CGAL_precondition(vsource < vertex_map.size());
if (vertex_map[vsource] == std::size_t(-1)) { // add new vertex
vertex_map[vsource] = m_vertices.size();
m_vertices.push_back(PVertex());
m_vertices.back().index = vsource;
CGAL_precondition(vsource < pvertex_map.size());
if (pvertex_map[vsource] == std::size_t(-1)) { // add new pvertex
pvertex_map[vsource] = m_pvertices.size();
m_pvertices.push_back(PVertex());
m_pvertices.back().index = vsource;
}
CGAL_precondition(vtarget < vertex_map.size());
if (vertex_map[vtarget] == std::size_t(-1)) { // add new vertex
vertex_map[vtarget] = m_vertices.size();
m_vertices.push_back(PVertex());
m_vertices.back().index = vtarget;
CGAL_precondition(vtarget < pvertex_map.size());
if (pvertex_map[vtarget] == std::size_t(-1)) { // add new pvertex
pvertex_map[vtarget] = m_pvertices.size();
m_pvertices.push_back(PVertex());
m_pvertices.back().index = vtarget;
}
// Update vertex info.
const std::size_t v1 = vertex_map[vsource];
const std::size_t v2 = vertex_map[vtarget];
CGAL_precondition(v1 != std::size_t(-1) && v1 < m_vertices.size());
CGAL_precondition(v2 != std::size_t(-1) && v2 < m_vertices.size());
// Update pvertex info.
const std::size_t pv1 = pvertex_map[vsource];
const std::size_t pv2 = pvertex_map[vtarget];
auto& vertex1 = m_vertices[v1];
auto& vertex2 = m_vertices[v2];
vertex1.neighbors.insert(v2);
vertex2.neighbors.insert(v1);
vertex1.regions.insert(region1);
vertex1.regions.insert(region2);
vertex2.regions.insert(region1);
vertex2.regions.insert(region2);
CGAL_precondition(pv1 != std::size_t(-1) && pv1 < m_pvertices.size());
CGAL_precondition(pv2 != std::size_t(-1) && pv2 < m_pvertices.size());
auto& pvertex1 = m_pvertices[pv1];
auto& pvertex2 = m_pvertices[pv2];
pvertex1.neighbors.insert(pv2);
pvertex1.regions.insert(region1);
pvertex1.regions.insert(region2);
pvertex2.neighbors.insert(pv1);
pvertex2.regions.insert(region1);
pvertex2.regions.insert(region2);
}
};

View File

@ -25,6 +25,9 @@
#include <CGAL/assertions.h>
#include <CGAL/property_map.h>
// Internal includes.
#include <CGAL/Shape_detection/Region_growing/internal/region_growing_traits.h>
namespace CGAL {
namespace Shape_detection {
namespace internal {
@ -210,6 +213,60 @@ namespace internal {
const Vertex_to_point_map& m_vertex_to_point_map;
};
template<
typename KeyType,
typename FaceGraph,
typename EdgeRange,
typename VertexToPointMap>
class Polyline_graph_segment_map {
public:
using Key_type = KeyType;
using Face_graph = FaceGraph;
using Edge_range = EdgeRange;
using Vertex_to_point_map = VertexToPointMap;
using Point_type = typename Vertex_to_point_map::value_type;
using Traits = typename Kernel_traits<Point_type>::Kernel;
using RG_traits = typename std::conditional<
std::is_same<typename Traits::Point_2, Point_type>::value,
internal::Polyline_graph_traits_2<Traits>,
internal::Polyline_graph_traits_3<Traits> >::type;
using value_type = typename RG_traits::Segment;
using reference = value_type;
using key_type = Key_type;
using category = boost::readable_property_map_tag;
Polyline_graph_segment_map(
const Face_graph& face_graph,
const Edge_range& edge_range,
const Vertex_to_point_map& vertex_to_point_map) :
m_face_graph(face_graph),
m_edge_range(edge_range),
m_vertex_to_point_map(vertex_to_point_map)
{ }
reference operator[](const key_type& edge) const {
CGAL_precondition(edge.index < m_edge_range.size());
const auto& key = *(m_edge_range.begin() + edge.index);
const auto& s = get(m_vertex_to_point_map, source(key, m_face_graph));
const auto& t = get(m_vertex_to_point_map, target(key, m_face_graph));
const auto construct_segment = RG_traits().construct_segment();
return construct_segment(s, t);
}
friend inline reference get(
const Polyline_graph_segment_map& pgraph_map, const key_type& key) {
return pgraph_map[key];
}
private:
const Face_graph& m_face_graph;
const Edge_range& m_edge_range;
const Vertex_to_point_map& m_vertex_to_point_map;
};
} // namespace internal
} // namespace Shape_detection
} // namespace CGAL

View File

@ -0,0 +1,125 @@
// 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_INTERNAL_TRAITS_H
#define CGAL_SHAPE_DETECTION_REGION_GROWING_INTERNAL_TRAITS_H
#include <CGAL/license/Shape_detection.h>
// STL includes.
#include <vector>
#include <algorithm>
#include <type_traits>
// CGAL includes.
#include <CGAL/assertions.h>
#include <CGAL/number_utils.h>
// Internal includes.
#include <CGAL/Shape_detection/Region_growing/internal/utils.h>
namespace CGAL {
namespace Shape_detection {
namespace internal {
template<typename GeomTraits>
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().compute_segment_2_object();
}
};
template<typename GeomTraits>
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().compute_segment_3_object();
}
};
template<typename GeomTraits>
struct Polyline_traits_2 {
using Point = typename GeomTraits::Point_2;
using Vector = typename GeomTraits::Vector_2;
using Line = typename GeomTraits::Line_2;
using Compute_squared_length = typename GeomTraits::Compute_squared_length_2;
using Compute_squared_distance = typename GeomTraits::Compute_squared_distance_2;
using Compute_scalar_product = typename GeomTraits::Compute_scalar_product_2;
const GeomTraits m_traits;
Polyline_traits_2(const GeomTraits& traits) :
m_traits(traits)
{ }
decltype(auto) compute_squared_length_object() const {
return m_traits.compute_squared_length_2_object();
}
decltype(auto) compute_squared_distance_object() const {
return m_traits.compute_squared_distance_2_object();
}
decltype(auto) compute_scalar_product_object() const {
return m_traits.compute_scalar_product_2_object();
}
template<typename InputRange, typename PointMap>
decltype(auto) create_line_from_points(
const InputRange& input_range, const PointMap point_map,
const std::vector<std::size_t>& region) const {
return internal::create_line_from_points_2<GeomTraits>(
input_range, point_map, region);
}
};
template<typename GeomTraits>
struct Polyline_traits_3 {
using Point = typename GeomTraits::Point_3;
using Vector = typename GeomTraits::Vector_3;
using Line = typename GeomTraits::Line_3;
using Compute_squared_length = typename GeomTraits::Compute_squared_length_3;
using Compute_squared_distance = typename GeomTraits::Compute_squared_distance_3;
using Compute_scalar_product = typename GeomTraits::Compute_scalar_product_3;
const GeomTraits m_traits;
Polyline_traits_3(const GeomTraits& traits) :
m_traits(traits)
{ }
decltype(auto) compute_squared_length_object() const {
return m_traits.compute_squared_length_3_object();
}
decltype(auto) compute_squared_distance_object() const {
return m_traits.compute_squared_distance_3_object();
}
decltype(auto) compute_scalar_product_object() const {
return m_traits.compute_scalar_product_3_object();
}
template<typename InputRange, typename PointMap>
decltype(auto) create_line_from_points(
const InputRange& input_range, const PointMap point_map,
const std::vector<std::size_t>& region) const {
return internal::create_line_from_points_3<GeomTraits>(
input_range, point_map, region);
}
};
} // namespace internal
} // namespace Shape_detection
} // namespace CGAL
#endif // CGAL_SHAPE_DETECTION_REGION_GROWING_INTERNAL_TRAITS_H

View File

@ -22,12 +22,17 @@
#include <vector>
#include <algorithm>
#include <type_traits>
#include <typeinfo>
// Boost headers.
#include <boost/mpl/has_xxx.hpp>
#include <boost/graph/properties.hpp>
#include <boost/graph/graph_traits.hpp>
// Named parameters.
#include <CGAL/boost/graph/named_params_helper.h>
#include <CGAL/boost/graph/Named_function_parameters.h>
// Face graph includes.
#include <CGAL/Iterator_range.h>
#include <CGAL/HalfedgeDS_vector.h>
@ -42,6 +47,7 @@
#include <CGAL/Eigen_diagonalize_traits.h>
#include <CGAL/linear_least_squares_fitting_2.h>
#include <CGAL/linear_least_squares_fitting_3.h>
#include <CGAL/boost/iterator/counting_iterator.hpp>
#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
namespace CGAL {
@ -315,74 +321,6 @@ namespace internal {
return std::make_pair(plane, static_cast<FT>(score));
}
template<typename GeomTraits>
struct Polyline_traits_2 {
using Point = typename GeomTraits::Point_2;
using Vector = typename GeomTraits::Vector_2;
using Line = typename GeomTraits::Line_2;
using Compute_squared_length = typename GeomTraits::Compute_squared_length_2;
using Compute_squared_distance = typename GeomTraits::Compute_squared_distance_2;
using Compute_scalar_product = typename GeomTraits::Compute_scalar_product_2;
const GeomTraits m_traits;
Polyline_traits_2(const GeomTraits& traits) :
m_traits(traits)
{ }
decltype(auto) compute_squared_length_object() const {
return m_traits.compute_squared_length_2_object();
}
decltype(auto) compute_squared_distance_object() const {
return m_traits.compute_squared_distance_2_object();
}
decltype(auto) compute_scalar_product_object() const {
return m_traits.compute_scalar_product_2_object();
}
template<typename InputRange, typename PointMap>
decltype(auto) create_line_from_points(
const InputRange& input_range, const PointMap point_map,
const std::vector<std::size_t>& region) const {
return internal::create_line_from_points_2<GeomTraits>(
input_range, point_map, region);
}
};
template<typename GeomTraits>
struct Polyline_traits_3 {
using Point = typename GeomTraits::Point_3;
using Vector = typename GeomTraits::Vector_3;
using Line = typename GeomTraits::Line_3;
using Compute_squared_length = typename GeomTraits::Compute_squared_length_3;
using Compute_squared_distance = typename GeomTraits::Compute_squared_distance_3;
using Compute_scalar_product = typename GeomTraits::Compute_scalar_product_3;
const GeomTraits m_traits;
Polyline_traits_3(const GeomTraits& traits) :
m_traits(traits)
{ }
decltype(auto) compute_squared_length_object() const {
return m_traits.compute_squared_length_3_object();
}
decltype(auto) compute_squared_distance_object() const {
return m_traits.compute_squared_distance_3_object();
}
decltype(auto) compute_scalar_product_object() const {
return m_traits.compute_scalar_product_3_object();
}
template<typename InputRange, typename PointMap>
decltype(auto) create_line_from_points(
const InputRange& input_range, const PointMap point_map,
const std::vector<std::size_t>& region) const {
return internal::create_line_from_points_3<GeomTraits>(
input_range, point_map, region);
}
};
} // namespace internal
} // namespace Shape_detection
} // namespace CGAL

View File

@ -20,22 +20,20 @@
#include <CGAL/Shape_detection/Region_growing/internal/Polyline_graph.h>
#include "../../examples/Shape_detection/include/utils.h"
namespace SD = CGAL::Shape_detection;
using Kernel = CGAL::Exact_predicates_inexact_constructions_kernel;
using FT = typename Kernel::FT;
namespace SD = CGAL::Shape_detection;
using Kernel = CGAL::Exact_predicates_inexact_constructions_kernel;
using Point_3 = typename Kernel::Point_3;
using Surface_mesh = CGAL::Surface_mesh<Point_3>;
using Polyline_graph = CGAL::Shape_detection::internal::Polyline_graph_points<Kernel, Surface_mesh>;
using Polyline_graph = CGAL::Shape_detection::internal::Polyline_graph_points<Surface_mesh>;
using Vertex_to_point_map = typename Polyline_graph::Vertex_to_point_map;
using PVertex_range = typename Polyline_graph::PVertex_range;
using Point_range = typename Polyline_graph::Point_range;
using Point_map = typename Polyline_graph::Point_map;
using Region_type = CGAL::Shape_detection::Polyline::Least_squares_line_fit_region<Kernel, PVertex_range, Point_map>;
using Sorting = CGAL::Shape_detection::Polyline::Least_squares_line_fit_sorting<Kernel, PVertex_range, Polyline_graph, Point_map>;
using Region_growing = CGAL::Shape_detection::Region_growing<PVertex_range, Polyline_graph, Region_type, typename Sorting::Seed_map>;
using Region_type = CGAL::Shape_detection::Polyline::Least_squares_line_fit_region<Kernel, Point_range, Point_map>;
using Sorting = CGAL::Shape_detection::Polyline::Least_squares_line_fit_sorting<Kernel, Point_range, Polyline_graph, Point_map>;
using Region_growing = CGAL::Shape_detection::Region_growing<Point_range, Polyline_graph, Region_type, typename Sorting::Seed_map>;
int main(int argc, char *argv[]) {
@ -58,31 +56,32 @@ int main(int argc, char *argv[]) {
// std::cout << "- num regions: " << regions.size() << std::endl;
assert(regions.size() == 9);
std::string fullpath = (argc > 2 ? argv[2] : "regions_sm.ply");
utils::save_polygon_mesh_regions(surface_mesh, regions, fullpath);
// std::string fullpath = (argc > 2 ? argv[2] : "regions_sm.ply");
// utils::save_polygon_mesh_regions(surface_mesh, regions, fullpath);
const Vertex_to_point_map vertex_to_point_map(
get(CGAL::vertex_point, surface_mesh));
Polyline_graph pgraph(surface_mesh, regions, vertex_to_point_map);
const auto& pvertices = pgraph.pvertex_range();
const auto& point_range = pgraph.point_range();
// std::cout << "- num extracted points: " << point_range.size() << std::endl;
Region_type region_type(
pvertices, CGAL::parameters::all_default(), pgraph.point_map());
Sorting sorting(pvertices, pgraph, pgraph.point_map());
point_range, CGAL::parameters::all_default(), pgraph.point_map());
Sorting sorting(point_range, pgraph, pgraph.point_map());
sorting.sort();
Region_growing region_growing(
pvertices, pgraph, region_type, sorting.seed_map());
point_range, pgraph, region_type, sorting.seed_map());
std::vector< std::vector<std::size_t> > subregions;
region_growing.detect(std::back_inserter(subregions));
// std::cout << "- num subregions: " << subregions.size() << std::endl;
assert(subregions.size() == 21);
fullpath = (argc > 2 ? argv[2] : "subregions_sm.ply");
utils::save_point_regions_3<Kernel, PVertex_range, Point_map>(
pvertices, subregions, fullpath, pgraph.point_map());
// fullpath = (argc > 2 ? argv[2] : "subregions_sm.ply");
// utils::save_point_regions_3<Kernel, Point_range, Point_map>(
// point_range, subregions, fullpath, pgraph.point_map());
std::cout << "rg_pgraph, epick_test_success: " << true << std::endl;
return EXIT_SUCCESS;