mirror of https://github.com/CGAL/cgal
merging LCC creation, point on face projection for reconstruction and fixed t-functions
This commit is contained in:
parent
b26e22bca8
commit
2b254121fe
|
|
@ -25,19 +25,8 @@ namespace KSR {
|
|||
// Path to the input data file.
|
||||
std::string data; // required!
|
||||
|
||||
// Label indices defined in the ply header:
|
||||
// ground (gi),
|
||||
// building boundary (bi),
|
||||
// building interior (ii),
|
||||
// vegetation (vi).
|
||||
std::string gi, bi, ii, vi;
|
||||
|
||||
// Main parameters.
|
||||
FT scale; // meters
|
||||
FT noise; // meters
|
||||
|
||||
// Boolean tags.
|
||||
const bool with_normals; // do we use normals
|
||||
bool with_normals; // do we use normals
|
||||
bool verbose;// verbose basic info
|
||||
bool debug; // verbose more info
|
||||
|
||||
|
|
@ -52,43 +41,35 @@ namespace KSR {
|
|||
// Partitioning.
|
||||
// See KSR/parameters.h
|
||||
unsigned int k_intersections;
|
||||
const unsigned int n_subdivisions;
|
||||
const FT enlarge_bbox_ratio;
|
||||
const bool reorient;
|
||||
FT enlarge_bbox_ratio;
|
||||
bool reorient;
|
||||
|
||||
std::size_t max_octree_depth;
|
||||
std::size_t max_octree_node_size;
|
||||
|
||||
// Reconstruction.
|
||||
FT graphcut_beta; // magic parameter between 0 and 1
|
||||
|
||||
// Constructor.
|
||||
All_parameters() :
|
||||
data(""),
|
||||
gi("0"), bi("1"), ii("2"), vi("3"), // semantic labels mapping
|
||||
// main parameters
|
||||
scale(FT(4)),
|
||||
noise(FT(2)),
|
||||
// boolean tags
|
||||
with_normals(true),
|
||||
verbose(false),
|
||||
debug(false),
|
||||
// shape detection / shape regularization
|
||||
k_neighbors(12),
|
||||
distance_threshold(noise / FT(2)),
|
||||
angle_threshold(FT(25)),
|
||||
min_region_size(100),
|
||||
regularize(false),
|
||||
// partition
|
||||
k_intersections(1),
|
||||
n_subdivisions(0),
|
||||
enlarge_bbox_ratio(FT(11) / FT(10)),
|
||||
reorient(false),
|
||||
// reconstruction
|
||||
graphcut_beta(FT(1) / FT(2))
|
||||
data(""),
|
||||
// boolean tags
|
||||
with_normals(true),
|
||||
verbose(false),
|
||||
debug(false),
|
||||
// shape detection / shape regularization
|
||||
k_neighbors(12),
|
||||
min_region_size(100),
|
||||
max_octree_node_size(40),
|
||||
max_octree_depth(3),
|
||||
// partition
|
||||
k_intersections(1),
|
||||
enlarge_bbox_ratio(FT(11) / FT(10)),
|
||||
reorient(false),
|
||||
// reconstruction
|
||||
graphcut_beta(FT(1) / FT(2))
|
||||
{ }
|
||||
|
||||
// Update all parameters, which depend on scale and noise.
|
||||
void update_dependent() {
|
||||
distance_threshold = noise / FT(2);
|
||||
}
|
||||
};
|
||||
|
||||
} // KSR
|
||||
|
|
|
|||
|
|
@ -55,25 +55,15 @@ void parse_terminal(Terminal_parser& parser, Parameters& parameters) {
|
|||
// Required parameters.
|
||||
parser.add_str_parameter("-data", parameters.data);
|
||||
|
||||
// Label indices.
|
||||
parser.add_str_parameter("-gi", parameters.gi);
|
||||
parser.add_str_parameter("-bi", parameters.bi);
|
||||
parser.add_str_parameter("-ii", parameters.ii);
|
||||
parser.add_str_parameter("-vi", parameters.vi);
|
||||
|
||||
// Main parameters.
|
||||
parser.add_val_parameter("-scale", parameters.scale);
|
||||
parser.add_val_parameter("-noise", parameters.noise);
|
||||
|
||||
// Update.
|
||||
parameters.update_dependent();
|
||||
|
||||
// Shape detection.
|
||||
parser.add_val_parameter("-kn" , parameters.k_neighbors);
|
||||
parser.add_val_parameter("-dist" , parameters.distance_threshold);
|
||||
parser.add_val_parameter("-angle", parameters.angle_threshold);
|
||||
parser.add_val_parameter("-minp" , parameters.min_region_size);
|
||||
|
||||
parser.add_val_parameter("-odepth", parameters.max_octree_depth);
|
||||
parser.add_val_parameter("-osize", parameters.max_octree_node_size);
|
||||
|
||||
// Shape regularization.
|
||||
parser.add_bool_parameter("-regularize", parameters.regularize);
|
||||
|
||||
|
|
@ -147,25 +137,24 @@ int main(const int argc, const char** argv) {
|
|||
.distance_tolerance(parameters.distance_threshold * 0.025)
|
||||
.debug(parameters.debug)
|
||||
.verbose(parameters.verbose)
|
||||
.max_octree_depth(parameters.max_octree_depth)
|
||||
.max_octree_node_size(parameters.max_octree_node_size)
|
||||
.regularize_parallelism(true)
|
||||
.regularize_coplanarity(true)
|
||||
.regularize_orthogonality(false)
|
||||
.regularize_axis_symmetry(false)
|
||||
.angle_tolerance(10)
|
||||
.maximum_offset(0.01);
|
||||
.maximum_offset(0.02);
|
||||
|
||||
// Algorithm.
|
||||
KSR ksr(point_set, param);
|
||||
|
||||
/*
|
||||
auto rm = point_set. template property_map<int>("region");
|
||||
|
||||
const Region_map region_map = point_set. template property_map<int>("region").value();
|
||||
const bool is_segmented = point_set. template property_map<int>("region").second;*/
|
||||
const Region_map region_map = point_set. template property_map<int>("region").first;
|
||||
const bool is_segmented = point_set. template property_map<int>("region").second;
|
||||
|
||||
Timer timer;
|
||||
timer.start();
|
||||
std::size_t num_shapes = ksr.detect_planar_shapes(param);
|
||||
std::size_t num_shapes = ksr.detect_planar_shapes(false, param);
|
||||
|
||||
std::cout << num_shapes << " detected planar shapes" << std::endl;
|
||||
|
||||
|
|
@ -195,6 +184,7 @@ int main(const int argc, const char** argv) {
|
|||
|
||||
FT after_energyterms = timer.time();
|
||||
|
||||
|
||||
ksr.reconstruct(parameters.graphcut_beta);
|
||||
FT after_reconstruction = timer.time();
|
||||
|
||||
|
|
@ -205,7 +195,8 @@ int main(const int argc, const char** argv) {
|
|||
std::vector<std::vector<std::size_t> > polylist;
|
||||
ksr.reconstructed_model_polylist(std::back_inserter(vtx), std::back_inserter(polylist));
|
||||
|
||||
CGAL::KSR_3::dump_indexed_polygons(vtx, polylist, "polylist");
|
||||
if (polylist.size() > 0)
|
||||
CGAL::KSR_3::dump_indexed_polygons(vtx, polylist, "polylist");
|
||||
|
||||
ksr.reconstruct(0.3);
|
||||
|
||||
|
|
@ -213,31 +204,141 @@ int main(const int argc, const char** argv) {
|
|||
polylist.clear();
|
||||
ksr.reconstructed_model_polylist(std::back_inserter(vtx), std::back_inserter(polylist));
|
||||
|
||||
CGAL::KSR_3::dump_indexed_polygons(vtx, polylist, "polylist_b0.3");
|
||||
if (polylist.size() > 0)
|
||||
CGAL::KSR_3::dump_indexed_polygons(vtx, polylist, "polylist_b0.3");
|
||||
ksr.reconstruct(0.5);
|
||||
|
||||
vtx.clear();
|
||||
polylist.clear();
|
||||
ksr.reconstructed_model_polylist(std::back_inserter(vtx), std::back_inserter(polylist));
|
||||
|
||||
CGAL::KSR_3::dump_indexed_polygons(vtx, polylist, "polylist_b0.5");
|
||||
if (polylist.size() > 0)
|
||||
CGAL::KSR_3::dump_indexed_polygons(vtx, polylist, "polylist_b0.5");
|
||||
ksr.reconstruct(0.6);
|
||||
|
||||
vtx.clear();
|
||||
polylist.clear();
|
||||
ksr.reconstructed_model_polylist(std::back_inserter(vtx), std::back_inserter(polylist));
|
||||
|
||||
if (polylist.size() > 0)
|
||||
CGAL::KSR_3::dump_indexed_polygons(vtx, polylist, "polylist_b0.6");
|
||||
ksr.reconstruct(0.7);
|
||||
|
||||
vtx.clear();
|
||||
polylist.clear();
|
||||
ksr.reconstructed_model_polylist(std::back_inserter(vtx), std::back_inserter(polylist));
|
||||
|
||||
CGAL::KSR_3::dump_indexed_polygons(vtx, polylist, "polylist_b0.7");
|
||||
if (polylist.size() > 0)
|
||||
CGAL::KSR_3::dump_indexed_polygons(vtx, polylist, "polylist_b0.7");
|
||||
ksr.reconstruct(0.8);
|
||||
|
||||
vtx.clear();
|
||||
polylist.clear();
|
||||
ksr.reconstructed_model_polylist(std::back_inserter(vtx), std::back_inserter(polylist));
|
||||
|
||||
if (polylist.size() > 0)
|
||||
CGAL::KSR_3::dump_indexed_polygons(vtx, polylist, "polylist_b0.8");
|
||||
ksr.reconstruct(0.95);
|
||||
|
||||
vtx.clear();
|
||||
polylist.clear();
|
||||
ksr.reconstructed_model_polylist(std::back_inserter(vtx), std::back_inserter(polylist));
|
||||
|
||||
CGAL::KSR_3::dump_indexed_polygons(vtx, polylist, "polylist_b0.95");
|
||||
if (polylist.size() > 0)
|
||||
CGAL::KSR_3::dump_indexed_polygons(vtx, polylist, "polylist_b0.95");
|
||||
|
||||
ksr.reconstruct(0.97);
|
||||
|
||||
vtx.clear();
|
||||
polylist.clear();
|
||||
ksr.reconstructed_model_polylist(std::back_inserter(vtx), std::back_inserter(polylist));
|
||||
|
||||
if (polylist.size() > 0)
|
||||
CGAL::KSR_3::dump_indexed_polygons(vtx, polylist, "polylist_b0.97");
|
||||
ksr.reconstruct(0.99);
|
||||
|
||||
vtx.clear();
|
||||
polylist.clear();
|
||||
ksr.reconstructed_model_polylist(std::back_inserter(vtx), std::back_inserter(polylist));
|
||||
|
||||
if (polylist.size() > 0)
|
||||
CGAL::KSR_3::dump_indexed_polygons(vtx, polylist, "polylist_b0.99");
|
||||
ksr.reconstruct(1.0);
|
||||
|
||||
vtx.clear();
|
||||
polylist.clear();
|
||||
ksr.reconstructed_model_polylist(std::back_inserter(vtx), std::back_inserter(polylist));
|
||||
|
||||
if (polylist.size() > 0)
|
||||
CGAL::KSR_3::dump_indexed_polygons(vtx, polylist, "polylist_b1.0");
|
||||
|
||||
// Output.
|
||||
//ksr.partition().get_linear_cell_complex();
|
||||
ksr.partition().get_linear_cell_complex();
|
||||
/*
|
||||
|
||||
// Vertices.
|
||||
std::vector<Point_3> all_vertices;
|
||||
ksp.output_partition_vertices(
|
||||
std::back_inserter(all_vertices), -1);
|
||||
|
||||
// Edges.
|
||||
std::vector<Segment_3> all_edges;
|
||||
ksp.output_partition_edges(
|
||||
std::back_inserter(all_edges), -1);
|
||||
|
||||
// Faces.
|
||||
std::vector< std::vector<std::size_t> > all_faces;
|
||||
ksp.output_partition_faces(
|
||||
std::back_inserter(all_faces), -1, 6);
|
||||
|
||||
// Model.
|
||||
std::vector<Point_3> output_vertices;
|
||||
std::vector< std::vector<std::size_t> > output_faces;
|
||||
ksp.output_reconstructed_model(
|
||||
std::back_inserter(output_vertices),
|
||||
std::back_inserter(output_faces));
|
||||
const std::size_t num_vertices = output_vertices.size();
|
||||
const std::size_t num_faces = output_faces.size();
|
||||
|
||||
std::cout << std::endl;
|
||||
std::cout << "--- OUTPUT STATS: " << std::endl;
|
||||
std::cout << "* number of vertices: " << num_vertices << std::endl;
|
||||
std::cout << "* number of faces: " << num_faces << std::endl;
|
||||
|
||||
// Export.
|
||||
std::cout << std::endl;
|
||||
std::cout << "--- EXPORT: " << std::endl;
|
||||
|
||||
// Edges.
|
||||
std::string output_filename = "partition-edges.polylines.txt";
|
||||
std::ofstream output_file_edges(output_filename);
|
||||
output_file_edges.precision(20);
|
||||
for (const auto& output_edge : all_edges)
|
||||
output_file_edges << "2 " << output_edge << std::endl;
|
||||
output_file_edges.close();
|
||||
std::cout << "* partition edges exported successfully" << std::endl;
|
||||
|
||||
// Faces.
|
||||
output_filename = "partition-faces.ply";
|
||||
std::ofstream output_file_faces(output_filename);
|
||||
output_file_faces.precision(20);
|
||||
if (!CGAL::IO::write_PLY(output_file_faces, all_vertices, all_faces)) {
|
||||
std::cerr << "ERROR: can't write to the file " << output_filename << "!" << std::endl;
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
output_file_faces.close();
|
||||
std::cout << "* partition faces exported successfully" << std::endl;
|
||||
|
||||
// Model.
|
||||
output_filename = "reconstructed-model.ply";
|
||||
std::ofstream output_file_model(output_filename);
|
||||
output_file_model.precision(20);
|
||||
if (!CGAL::IO::write_PLY(output_file_model, output_vertices, output_faces)) {
|
||||
std::cerr << "ERROR: can't write to the file " << output_filename << "!" << std::endl;
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
output_file_model.close();
|
||||
std::cout << "* the reconstructed model exported successfully" << std::endl;*/
|
||||
|
||||
std::cout << "Shape detection: " << after_shape_detection << " seconds!" << std::endl;
|
||||
std::cout << "Kinetic partition: " << (after_partition - after_shape_detection) << " seconds!" << std::endl;
|
||||
|
|
|
|||
|
|
@ -38,10 +38,12 @@
|
|||
namespace CGAL {
|
||||
namespace KSR_3 {
|
||||
|
||||
const CGAL::Color get_idx_color(std::size_t idx) {
|
||||
const std::tuple<unsigned char, unsigned char, unsigned char>
|
||||
get_idx_color(std::size_t idx) {
|
||||
|
||||
CGAL::Random rand(static_cast<unsigned int>(idx));
|
||||
return CGAL::Color(static_cast<unsigned char>(rand.get_int(32, 192)),
|
||||
return std::make_tuple(
|
||||
static_cast<unsigned char>(rand.get_int(32, 192)),
|
||||
static_cast<unsigned char>(rand.get_int(32, 192)),
|
||||
static_cast<unsigned char>(rand.get_int(32, 192)));
|
||||
}
|
||||
|
|
@ -106,11 +108,12 @@ void dump_2d_surface_mesh(
|
|||
using Mesh = CGAL::Surface_mesh<Point_3>;
|
||||
using Face_index = typename Mesh::Face_index;
|
||||
using Vertex_index = typename Mesh::Vertex_index;
|
||||
|
||||
using Color_map = typename Mesh::template Property_map<Face_index, CGAL::Color>;
|
||||
using Uchar_map = typename Mesh::template Property_map<Face_index, unsigned char>;
|
||||
|
||||
Mesh mesh;
|
||||
Color_map color = mesh.template add_property_map<Face_index, CGAL::Color>("f:color", CGAL::IO::white()).first;
|
||||
Uchar_map red = mesh.template add_property_map<Face_index, unsigned char>("red", 0).first;
|
||||
Uchar_map green = mesh.template add_property_map<Face_index, unsigned char>("green", 0).first;
|
||||
Uchar_map blue = mesh.template add_property_map<Face_index, unsigned char>("blue", 0).first;
|
||||
|
||||
std::vector<Vertex_index> vertices;
|
||||
std::vector<Vertex_index> map_vertices;
|
||||
|
|
@ -137,8 +140,8 @@ void dump_2d_surface_mesh(
|
|||
std::cout << "could not dump mesh " << tag << std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
color[face] = get_idx_color((support_plane_idx + 1) * (pface.second + 1));
|
||||
std::tie(red[face], green[face], blue[face]) =
|
||||
get_idx_color((support_plane_idx + 1) * (pface.second + 1));
|
||||
}
|
||||
|
||||
const std::string filename = (tag != std::string() ? tag + "-" : "") + "polygons.ply";
|
||||
|
|
@ -155,13 +158,17 @@ void dump_polygons(const DS& data, const std::string tag = std::string()) {
|
|||
using Mesh = CGAL::Surface_mesh<Point_3>;
|
||||
using Face_index = typename Mesh::Face_index;
|
||||
using Vertex_index = typename Mesh::Vertex_index;
|
||||
using Color_map = typename Mesh::template Property_map<Face_index, CGAL::Color>;
|
||||
using Uchar_map = typename Mesh::template Property_map<Face_index, unsigned char>;
|
||||
|
||||
Mesh mesh;
|
||||
Color_map color = mesh.template add_property_map<Face_index, CGAL::Color>("f:color", CGAL::IO::white()).first;
|
||||
Uchar_map red = mesh.template add_property_map<Face_index, unsigned char>("red", 0).first;
|
||||
Uchar_map green = mesh.template add_property_map<Face_index, unsigned char>("green", 0).first;
|
||||
Uchar_map blue = mesh.template add_property_map<Face_index, unsigned char>("blue", 0).first;
|
||||
|
||||
Mesh bbox_mesh;
|
||||
Color_map bbox_color = bbox_mesh.template add_property_map<Face_index, CGAL::Color>("f:color", CGAL::IO::white()).first;
|
||||
Uchar_map bbox_red = bbox_mesh.template add_property_map<Face_index, unsigned char>("red", 0).first;
|
||||
Uchar_map bbox_green = bbox_mesh.template add_property_map<Face_index, unsigned char>("green", 0).first;
|
||||
Uchar_map bbox_blue = bbox_mesh.template add_property_map<Face_index, unsigned char>("blue", 0).first;
|
||||
|
||||
std::vector<Vertex_index> vertices;
|
||||
std::vector<Vertex_index> map_vertices;
|
||||
|
|
@ -186,7 +193,8 @@ void dump_polygons(const DS& data, const std::string tag = std::string()) {
|
|||
CGAL_assertion(vertices.size() >= 3);
|
||||
const auto face = bbox_mesh.add_face(vertices);
|
||||
CGAL_assertion(face != Mesh::null_face());
|
||||
bbox_color[face] = get_idx_color((i + 1) * (pface.second + 1));
|
||||
std::tie(bbox_red[face], bbox_green[face], bbox_blue[face]) =
|
||||
get_idx_color((i + 1) * (pface.second + 1));
|
||||
}
|
||||
|
||||
} else {
|
||||
|
|
@ -208,8 +216,8 @@ void dump_polygons(const DS& data, const std::string tag = std::string()) {
|
|||
CGAL_assertion(vertices.size() >= 3);
|
||||
const auto face = mesh.add_face(vertices);
|
||||
CGAL_assertion(face != Mesh::null_face());
|
||||
|
||||
color[face] = get_idx_color(i * (pface.second + 1));
|
||||
std::tie(red[face], green[face], blue[face]) =
|
||||
get_idx_color(i * (pface.second + 1));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -299,6 +307,12 @@ void dump(const DS& data, const std::string tag = std::string()) {
|
|||
dump_intersection_edges(data, tag);
|
||||
}
|
||||
|
||||
template<typename LCC>
|
||||
void dump_lcc(const LCC& lcc, const std::string tag = std::string()) {
|
||||
std::map<CGAL::Epeck::Point_3, std::size_t> pt2idx;
|
||||
std::vector<CGAL::Epeck::Point_3> pts;
|
||||
}
|
||||
|
||||
template<typename GeomTraits>
|
||||
class Saver {
|
||||
|
||||
|
|
@ -871,6 +885,40 @@ void dump_volumes(const DS& data, const std::string tag = std::string()) {
|
|||
}
|
||||
}
|
||||
|
||||
template<typename KSP>
|
||||
void dump_volumes_ksp(const KSP& ksp, const std::string tag = std::string()) {
|
||||
using Point_3 = typename KSP::Point_3;
|
||||
using Index = typename KSP::Index;
|
||||
std::vector< std::vector<Point_3> > polygons;
|
||||
std::vector<Color> colors;
|
||||
|
||||
std::vector<Index> faces_of_volume;
|
||||
std::vector<Point_3> pts_of_face;
|
||||
|
||||
Saver<typename KSP::Kernel> saver;
|
||||
for (std::size_t i = 0; i < ksp.number_of_volumes(); ++i) {
|
||||
faces_of_volume.clear();
|
||||
polygons.clear();
|
||||
colors.clear();
|
||||
|
||||
const auto color = saver.get_idx_color(i);
|
||||
ksp.faces(i, std::back_inserter(faces_of_volume));
|
||||
|
||||
colors.clear();
|
||||
polygons.clear();
|
||||
for (const Index& f : faces_of_volume) {
|
||||
pts_of_face.clear();
|
||||
ksp.vertices(f, std::back_inserter(pts_of_face));
|
||||
|
||||
polygons.push_back(pts_of_face);
|
||||
colors.push_back(color);
|
||||
}
|
||||
|
||||
const std::string file_name = tag + std::to_string(i);
|
||||
saver.export_polygon_soup_3(polygons, colors, file_name);
|
||||
}
|
||||
}
|
||||
|
||||
void dump_polygon(const std::vector<CGAL::Epick::Point_3>& pts, const std::string& filename) {
|
||||
Saver<CGAL::Epick> saver;
|
||||
std::vector<std::vector<CGAL::Epick::Point_3> > pts2;
|
||||
|
|
|
|||
|
|
@ -127,10 +127,10 @@ inline bool intersection(
|
|||
|
||||
const auto inter = intersection(t1, t2);
|
||||
if (!inter) return false;
|
||||
if (const ResultType* typed_inter = boost::get<ResultType>(&*inter)) {
|
||||
result = *typed_inter;
|
||||
|
||||
if (CGAL::assign(result, inter))
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -255,7 +255,6 @@ public:
|
|||
const Type1& t1, const Type2& t2, ResultType& result) {
|
||||
|
||||
const auto inter = CGAL::intersection(t1, t2);
|
||||
|
||||
if (!inter) return false;
|
||||
if (CGAL::assign(result, inter))
|
||||
return true;
|
||||
|
|
@ -267,34 +266,6 @@ public:
|
|||
** INITIALIZATION **
|
||||
********************************/
|
||||
|
||||
/*
|
||||
template<typename InputRange, typename PolygonRange,
|
||||
typename NamedParameters = parameters::Default_named_parameters >
|
||||
void add_input_shape(InputRange input_range, PolygonRange polygon_range, const NamedParameters& np = CGAL::parameters::default_values()) {
|
||||
for (auto poly : polygon_range) {
|
||||
std::vector<Point_3> pts;
|
||||
pts.reserve(poly.size());
|
||||
for (auto it : poly)
|
||||
pts.push_back(*(input_range.begin() + it));
|
||||
|
||||
Plane_3 pl;
|
||||
CGAL::linear_least_squares_fitting_3(pts.begin(), pts.end(), pl, CGAL::Dimension_tag<0>());
|
||||
|
||||
std::vector<Point_2> pts2d(pts.size());
|
||||
for (std::size_t i = 0; i < pts.size(); i++)
|
||||
pts2d[i] = pl.to_2d(pts[i]);
|
||||
|
||||
std::vector<Point_2> ch;
|
||||
CGAL::convex_hull_2(pts2d.begin(), pts2d.end(), std::back_inserter(ch));
|
||||
|
||||
m_input_polygons.push_back(std::vector<Point_3>(ch.size()));
|
||||
|
||||
for (std::size_t i = 0; i < ch.size(); i++)
|
||||
m_input_polygons.back()[i] = pl.to_3d(ch[i]);
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
void clear() {
|
||||
m_support_planes.clear();
|
||||
m_intersection_graph.clear();
|
||||
|
|
@ -420,6 +391,11 @@ public:
|
|||
|
||||
typename Intersection_graph::Kinetic_interval& kinetic_interval = m_intersection_graph.kinetic_interval(edge, sp_idx);
|
||||
|
||||
if (kinetic_interval.size() != 0) {
|
||||
int a;
|
||||
a = 3;
|
||||
}
|
||||
|
||||
Point_2 s = sp.to_2d(from_exact(point_3(m_intersection_graph.source(edge))));
|
||||
Point_2 t = sp.to_2d(from_exact(point_3(m_intersection_graph.target(edge))));
|
||||
Vector_2 segment = t - s;
|
||||
|
|
@ -574,11 +550,10 @@ public:
|
|||
}
|
||||
|
||||
if (kinetic_interval.size() > 4) {
|
||||
for (std::size_t i = 1; i < kinetic_interval.size(); i++)
|
||||
if (kinetic_interval[i].first > kinetic_interval[i - 1].first) {
|
||||
int a;
|
||||
a = 2;
|
||||
}
|
||||
if (kinetic_interval[2].first > kinetic_interval[1].first) {
|
||||
int a;
|
||||
a = 2;
|
||||
}
|
||||
}
|
||||
|
||||
CGAL_assertion(0 <= event.intersection_bary && event.intersection_bary <= 1);
|
||||
|
|
@ -1723,41 +1698,6 @@ public:
|
|||
return m_intersection_graph.segment_3(edge);
|
||||
}
|
||||
|
||||
/*******************************
|
||||
** PREDICATES **
|
||||
********************************/
|
||||
|
||||
std::pair<bool, bool> is_occupied(
|
||||
const PVertex& pvertex, const IVertex& ivertex, const IEdge& query_iedge) const {
|
||||
|
||||
const auto pair = is_occupied(pvertex, query_iedge);
|
||||
const bool has_polygon = pair.first;
|
||||
const bool is_bbox_reached = pair.second;
|
||||
|
||||
if (is_bbox_reached) return std::make_pair(true, true);
|
||||
CGAL_assertion(!is_bbox_reached);
|
||||
if (!has_polygon) {
|
||||
// std::cout << "NO POLYGON DETECTED" << std::endl;
|
||||
return std::make_pair(false, false);
|
||||
}
|
||||
CGAL_assertion(has_polygon);
|
||||
|
||||
CGAL_assertion(ivertex != null_ivertex());
|
||||
std::set<PEdge> pedges;
|
||||
get_occupied_pedges(pvertex, query_iedge, pedges);
|
||||
for (const auto& pedge : pedges) {
|
||||
CGAL_assertion(pedge != null_pedge());
|
||||
// std::cout << "PEDGE: " << segment_3(pedge) << std::endl;
|
||||
|
||||
const auto source = this->source(pedge);
|
||||
const auto target = this->target(pedge);
|
||||
if (this->ivertex(source) == ivertex || this->ivertex(target) == ivertex) {
|
||||
return std::make_pair(true, false);
|
||||
}
|
||||
}
|
||||
return std::make_pair(false, false);
|
||||
}
|
||||
|
||||
/*******************************
|
||||
** CHECKING PROPERTIES **
|
||||
********************************/
|
||||
|
|
@ -1859,7 +1799,6 @@ public:
|
|||
bool success = true;
|
||||
|
||||
std::vector<PFace> nfaces;
|
||||
std::size_t idx = 0;
|
||||
for (const auto edge : m_intersection_graph.edges()) {
|
||||
incident_faces(edge, nfaces);
|
||||
if (nfaces.size() == 1) {
|
||||
|
|
@ -1870,7 +1809,6 @@ public:
|
|||
"ERROR: EDGE MUST HAVE 0 OR AT LEAST 2 NEIGHBORS!");
|
||||
success = false;
|
||||
}
|
||||
idx++;
|
||||
}
|
||||
return success;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -114,11 +114,6 @@ private:
|
|||
********************************/
|
||||
|
||||
void initialize_queue() {
|
||||
|
||||
if (m_parameters.debug) {
|
||||
std::cout << "initializing queue" << std::endl;
|
||||
}
|
||||
|
||||
m_data.fill_event_queue(m_face_queue);
|
||||
}
|
||||
|
||||
|
|
@ -148,12 +143,7 @@ private:
|
|||
********************************/
|
||||
|
||||
void apply(const Face_event& event, std::size_t iteration) {
|
||||
if (m_parameters.verbose)
|
||||
std::cout << "support plane: " << event.support_plane << " edge: " << event.crossed_edge << " t: " << event.time << std::endl;
|
||||
if (m_data.igraph().face(event.face).part_of_partition) {
|
||||
|
||||
if (m_parameters.verbose)
|
||||
std::cout << " face already crossed, skipping event" << std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -106,7 +106,6 @@ public:
|
|||
if (m_parameters.debug) {
|
||||
for (std::size_t sp = 0; sp < m_data.number_of_support_planes(); sp++) {
|
||||
dump_2d_surface_mesh(m_data, sp, m_data.prefix() + "after-partition-sp" + std::to_string(sp));
|
||||
std::cout << sp << " has " << m_data.support_plane(sp).data().mesh.number_of_faces() << " faces" << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -120,24 +119,12 @@ public:
|
|||
|
||||
create_volumes();
|
||||
|
||||
if (m_parameters.debug) {
|
||||
/*
|
||||
boost::filesystem::path dir("volumes");
|
||||
|
||||
if (!boost::filesystem::exists(dir) && !boost::filesystem::create_directory(dir)) {
|
||||
std::cout << "Could not create volumes folder to export volumes from partition!" << std::endl;
|
||||
}*/
|
||||
|
||||
if (boost::filesystem::is_directory("volumes/")) {
|
||||
for (boost::filesystem::directory_iterator end_dir_it, it("volumes/"); it != end_dir_it; ++it) {
|
||||
boost::filesystem::remove_all(it->path());
|
||||
}
|
||||
|
||||
if (m_parameters.debug) {
|
||||
for (const auto& v : m_data.volumes())
|
||||
dump_volume(m_data, v.pfaces, "volumes/" + m_data.prefix() + std::to_string(v.index), true, v.index);
|
||||
}
|
||||
}
|
||||
CGAL_assertion(m_data.check_faces());
|
||||
}*/
|
||||
(m_data.check_faces());
|
||||
}
|
||||
|
||||
private:
|
||||
|
|
@ -260,6 +247,8 @@ private:
|
|||
volume.pface_oriented_outwards[i] = ((m_data.point_3(vtx) - volume.centroid) * m_data.support_plane(volume.pfaces[i]).plane().orthogonal_vector() < 0);
|
||||
}
|
||||
}
|
||||
|
||||
remove_collinear_vertices();
|
||||
}
|
||||
|
||||
void segment_adjacent_volumes(const PFace& pface,
|
||||
|
|
@ -567,18 +556,26 @@ private:
|
|||
// Purpose: merge facets between the same volumes. Every pair of volumes can have at most one contact polygon (which also has to be convex)
|
||||
// Precondition: all volumes are convex, the contact area between each pair of volumes is empty or convex
|
||||
|
||||
std::vector<E_constraint_map> edge_constraint_maps;
|
||||
std::vector<E_constraint_map> edge_constraint_maps(m_data.number_of_support_planes());
|
||||
|
||||
for (std::size_t sp = 0; sp < m_data.number_of_support_planes(); sp++) {
|
||||
//dump_2d_surface_mesh(m_data, sp, "face_merge/" + m_data.prefix() + std::to_string(sp) + "-before");
|
||||
typename Support_plane::Mesh& mesh = m_data.support_plane(sp).mesh();
|
||||
|
||||
edge_constraint_maps.push_back(mesh.template add_property_map<typename Support_plane::Edge_index, bool>("e:keep", true).first);
|
||||
edge_constraint_maps[sp] = mesh.template add_property_map<typename Support_plane::Edge_index, bool>("e:keep", true).first;
|
||||
F_component_map fcm = mesh.template add_property_map<typename Support_plane::Face_index, typename boost::graph_traits<typename Support_plane::Mesh>::faces_size_type>("f:component", 0).first;
|
||||
|
||||
std::size_t num = 0;
|
||||
|
||||
for (auto e : mesh.edges()) {
|
||||
IEdge iedge = m_data.iedge(PEdge(sp, e));
|
||||
edge_constraint_maps[sp][e] = is_occupied(iedge, sp);
|
||||
|
||||
if (is_occupied(iedge, sp)) {
|
||||
edge_constraint_maps[sp][e] = true;
|
||||
num++;
|
||||
}
|
||||
else
|
||||
edge_constraint_maps[sp][e] = false;
|
||||
}
|
||||
|
||||
CGAL::Polygon_mesh_processing::connected_components(mesh, fcm, CGAL::parameters::edge_is_constrained_map(edge_constraint_maps[sp]));
|
||||
|
|
@ -586,9 +583,6 @@ private:
|
|||
merge_connected_components(sp, mesh, fcm, edge_constraint_maps[sp]);
|
||||
|
||||
mesh.collect_garbage();
|
||||
|
||||
// Use a face property map? easier to copy to 3d mesh
|
||||
//dump_2d_surface_mesh(m_data, sp, "face_merge/" + m_data.prefix() + std::to_string(sp) + "-after");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -620,7 +614,6 @@ private:
|
|||
std::vector<Point_3> pts;
|
||||
pts.push_back(s);
|
||||
pts.push_back(t);
|
||||
|
||||
if (visited_halfedges[h])
|
||||
continue;
|
||||
|
||||
|
|
@ -661,8 +654,6 @@ private:
|
|||
else
|
||||
n = mesh.next(mesh.opposite(n));
|
||||
|
||||
Halfedge p = mesh.prev(n);
|
||||
|
||||
//Point_3 tn2 = m_data.support_plane(sp).to_3d(mesh.point(mesh.target(h)));
|
||||
visited_halfedges[n] = true;
|
||||
|
||||
|
|
@ -673,12 +664,11 @@ private:
|
|||
if (f_other == mesh.null_face())
|
||||
break;
|
||||
c_other = fcm[f_other];
|
||||
if (c0 == c_other && ecm[Edge_index(n>>1)])
|
||||
if (c0 == c_other && ecm[Edge_index(n >> 1)])
|
||||
std::cout << "edge and face constraint map inconsistent1" << std::endl;
|
||||
|
||||
if (c0 != c_other && !ecm[Edge_index(n >> 1)])
|
||||
std::cout << "edge and face constraint map inconsistent2" << std::endl;
|
||||
|
||||
} while (c0 == c_other && n != h);
|
||||
|
||||
if (n == h) {
|
||||
|
|
@ -692,37 +682,6 @@ private:
|
|||
remove_vertices[mesh.target(n)] = false;
|
||||
h = n;
|
||||
} while (h != first);
|
||||
|
||||
// Loop complete
|
||||
/*
|
||||
const std::string vfilename = "face_merge/" + std::to_string(sp) + "-" + std::to_string(c0) + ".polylines.txt";
|
||||
std::ofstream vout(vfilename);
|
||||
vout.precision(20);
|
||||
vout << std::to_string(loop.size());
|
||||
for (Halfedge n : loop) {
|
||||
vout << " " << m_data.support_plane(sp).to_3d(mesh.point(mesh.target(n)));
|
||||
}
|
||||
vout << std::endl;
|
||||
vout.close();*/
|
||||
}
|
||||
|
||||
bool empty = true;
|
||||
for (std::size_t i = 0; i < remove_vertices.size(); i++)
|
||||
if (remove_vertices[i]) {
|
||||
empty = false;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!empty) {
|
||||
const std::string vfilename2 = "face_merge/" + std::to_string(sp_idx) + "-remove.xyz";
|
||||
std::ofstream vout2(vfilename2);
|
||||
vout2.precision(20);
|
||||
std::size_t i = 0;
|
||||
for (auto v : mesh.vertices()) {
|
||||
if (remove_vertices[i++])
|
||||
vout2 << sp.to_3d(mesh.point(v)) << std::endl;
|
||||
}
|
||||
vout2.close();
|
||||
}
|
||||
|
||||
// Remove all vertices in remove_vertices and all edges marked in constrained list
|
||||
|
|
@ -744,7 +703,7 @@ private:
|
|||
}
|
||||
|
||||
if (!mesh.is_valid(true)) {
|
||||
std::cout << "mesh is not valid after merging faces of sp " << sp_idx << " in " << m_data.prefix() << std::endl;
|
||||
std::cout << "mesh is not valid after merging faces of sp " << sp_idx << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -754,6 +713,8 @@ private:
|
|||
if (sp == j)
|
||||
continue;
|
||||
|
||||
m_data.support_plane(j).mesh().is_valid(true);
|
||||
|
||||
for (auto e2 : m_data.support_plane(j).mesh().edges()) {
|
||||
if (iedge == m_data.iedge(PEdge(j, e2))) {
|
||||
return true;
|
||||
|
|
@ -825,6 +786,40 @@ private:
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
void remove_collinear_vertices() {
|
||||
auto& vertices = m_data.face_to_vertices();
|
||||
std::vector<bool> coll(m_data.exact_vertices().size(), true);
|
||||
std::unordered_map<std::size_t, std::vector<std::size_t> > vtx2face;
|
||||
|
||||
for (std::size_t f = 0; f < vertices.size(); f++) {
|
||||
for (std::size_t i = 0; i < vertices[f].size(); i++) {
|
||||
if (!coll[vertices[f][i]])
|
||||
continue;
|
||||
const typename Intersection_kernel::Point_3& a = m_data.exact_vertices()[vertices[f][(i - 1 + vertices[f].size()) % vertices[f].size()]];
|
||||
const typename Intersection_kernel::Point_3& b = m_data.exact_vertices()[vertices[f][i]];
|
||||
const typename Intersection_kernel::Point_3& c = m_data.exact_vertices()[vertices[f][(i + 1) % vertices[f].size()]];
|
||||
if (!CGAL::collinear(a, b, c))
|
||||
coll[vertices[f][i]] = false;
|
||||
else
|
||||
vtx2face[vertices[f][i]].push_back(f);
|
||||
}
|
||||
}
|
||||
|
||||
for (std::size_t i = 0; i < coll.size(); i++) {
|
||||
if (!coll[i])
|
||||
continue;
|
||||
const auto& f = vtx2face[i];
|
||||
for (std::size_t j = 0; j < f.size(); j++) {
|
||||
for (std::size_t v = 0; v < vertices[f[j]].size(); v++) {
|
||||
if (vertices[f[j]][v] == i) {
|
||||
vertices[f[j]].erase(vertices[f[j]].begin() + v);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
#endif //DOXYGEN_RUNNING
|
||||
|
|
|
|||
|
|
@ -67,32 +67,6 @@ namespace KSR_3 {
|
|||
}
|
||||
compute_graphcut(edges, edge_weights, cost_matrix, labels);
|
||||
}
|
||||
/*
|
||||
|
||||
void compute(std::vector<Volume_cell>& volumes, std::size_t inliers) {
|
||||
|
||||
if (volumes.size() == 0) return;
|
||||
|
||||
std::vector<Wrapper> wrappers;
|
||||
create_pface_wrappers(wrappers);
|
||||
|
||||
compute_weights(wrappers, inliers);
|
||||
compute_weights(volumes);
|
||||
|
||||
std::vector< std::pair<std::size_t, std::size_t> > edges;
|
||||
std::vector<double> edge_costs;
|
||||
set_graph_edges(wrappers, edges, edge_costs);
|
||||
|
||||
std::vector< std::vector<double> > cost_matrix;
|
||||
set_cost_matrix(volumes, cost_matrix);
|
||||
|
||||
std::vector<std::size_t> labels;
|
||||
set_initial_labels(volumes, labels);
|
||||
|
||||
compute_graphcut(edges, edge_costs, cost_matrix, labels);
|
||||
apply_new_labels(labels, volumes);
|
||||
}
|
||||
*/
|
||||
|
||||
private:
|
||||
const FT m_lambda;
|
||||
|
|
@ -165,7 +139,7 @@ namespace KSR_3 {
|
|||
std::cout << "sum inside: " << sum_inside << std::endl;
|
||||
std::cout << "sum outside: " << sum_outside << std::endl;
|
||||
|
||||
CGAL::alpha_expansion_graphcut(edges, edge_costs_lambda, cost_matrix, labels);
|
||||
CGAL::alpha_expansion_graphcut(edges, edge_costs_lambda, cost_matrix_lambda, labels);
|
||||
/*
|
||||
CGAL::min_cut(
|
||||
edges, edge_costs, cost_matrix, labels, CGAL::parameters::implementation_tag(CGAL::Alpha_expansion_MaxFlow_tag()));*/
|
||||
|
|
|
|||
|
|
@ -144,10 +144,11 @@ public:
|
|||
|
||||
m_data.initialization_done();
|
||||
|
||||
|
||||
if (m_parameters.debug) {
|
||||
for (std::size_t sp = 0; sp < m_data.number_of_support_planes(); sp++) {
|
||||
dump_2d_surface_mesh(m_data, sp, m_data.prefix() + "before-partition-sp" + std::to_string(sp));
|
||||
std::cout << sp << " has " << m_data.support_plane(sp).data().mesh.number_of_faces() << " faces" << std::endl;
|
||||
//std::cout << sp << " has " << m_data.support_plane(sp).data().mesh.number_of_faces() << " faces" << std::endl;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
@ -396,7 +397,6 @@ private:
|
|||
if (sp.is_bbox())
|
||||
continue;
|
||||
|
||||
// Until here the mesh of each support plane contains the input polygon.
|
||||
sp.mesh().clear_without_removing_property_maps();
|
||||
|
||||
std::map<std::size_t, std::vector<IEdge> > line2edges;
|
||||
|
|
@ -661,6 +661,7 @@ private:
|
|||
for (std::size_t i = 0; i < 6; i++)
|
||||
for (std::size_t j = 0; j < m_input_planes.size(); j++)
|
||||
if (m_data.support_plane(i).exact_plane() == m_input_planes[j] || m_data.support_plane(i).exact_plane() == m_input_planes[j].opposite()) {
|
||||
m_data.support_plane(i).set_input_polygon(j);
|
||||
m_data.input_polygon_map()[j] = i;
|
||||
remove[j] = true;
|
||||
}
|
||||
|
|
@ -702,16 +703,15 @@ private:
|
|||
std::map< std::size_t, std::pair<Polygon_2, Indices> > polygons;
|
||||
preprocess_polygons(polygons);
|
||||
|
||||
for (const auto& item : polygons) {
|
||||
for (const auto &item : polygons) {
|
||||
const std::size_t support_plane_idx = item.first;
|
||||
const auto& pair = item.second;
|
||||
const Polygon_2& polygon = pair.first;
|
||||
const Indices& input_indices = pair.second;
|
||||
m_data.add_input_polygon(support_plane_idx, input_indices, polygon);
|
||||
m_data.support_plane(support_plane_idx).set_input_polygon(static_cast<int>(item.first) - 6);
|
||||
}
|
||||
|
||||
//if (m_parameters.debug)
|
||||
dump_polygons(m_data, polygons, m_data.prefix() + "inserted-polygons.ply");
|
||||
//dump_polygons(m_data, polygons, m_data.prefix() + "inserted-polygons");
|
||||
|
||||
CGAL_assertion(m_data.number_of_support_planes() >= 6);
|
||||
if (m_parameters.verbose) {
|
||||
|
|
|
|||
|
|
@ -125,6 +125,8 @@ public:
|
|||
FT distance_tolerance;
|
||||
FT angle_tolerance;
|
||||
|
||||
std::size_t actual_input_polygon;
|
||||
|
||||
int k;
|
||||
};
|
||||
|
||||
|
|
@ -151,7 +153,6 @@ public:
|
|||
const std::size_t n = points.size();
|
||||
CGAL_assertion(n == polygon.size());
|
||||
|
||||
|
||||
/*
|
||||
Vector_3 normal = CGAL::NULL_VECTOR;
|
||||
for (std::size_t i = 0; i < n; ++i) {
|
||||
|
|
@ -174,6 +175,7 @@ public:
|
|||
m_data->is_bbox = is_bbox;
|
||||
m_data->distance_tolerance = 0;
|
||||
m_data->angle_tolerance = 0;
|
||||
m_data->actual_input_polygon = -1;
|
||||
|
||||
std::vector<Triangle_2> tris(points.size() - 2);
|
||||
for (std::size_t i = 2; i < points.size(); i++) {
|
||||
|
|
@ -220,6 +222,7 @@ public:
|
|||
m_data->is_bbox = is_bbox;
|
||||
m_data->distance_tolerance = 0;
|
||||
m_data->angle_tolerance = 0;
|
||||
m_data->actual_input_polygon = -1;
|
||||
|
||||
std::vector<Triangle_2> tris(points.size() - 2);
|
||||
for (std::size_t i = 2; i < points.size(); i++) {
|
||||
|
|
@ -254,6 +257,7 @@ public:
|
|||
m_data->is_bbox = is_bbox;
|
||||
m_data->distance_tolerance = 0;
|
||||
m_data->angle_tolerance = 0;
|
||||
m_data->actual_input_polygon = -1;
|
||||
|
||||
std::vector<Triangle_2> tris(points.size() - 2);
|
||||
for (std::size_t i = 2; i < points.size(); i++) {
|
||||
|
|
@ -266,6 +270,7 @@ public:
|
|||
}
|
||||
|
||||
void add_property_maps() {
|
||||
|
||||
m_data->v_ivertex_map = m_data->mesh.template add_property_map<Vertex_index, IVertex>("v:ivertex", Intersection_graph::null_ivertex()).first;
|
||||
m_data->v_iedge_map = m_data->mesh.template add_property_map<Vertex_index, IEdge>("v:iedge", Intersection_graph::null_iedge()).first;
|
||||
m_data->e_iedge_map = m_data->mesh.template add_property_map<Edge_index, IEdge>("e:iedge", Intersection_graph::null_iedge()).first;
|
||||
|
|
@ -482,6 +487,10 @@ public:
|
|||
m_data->crossed_lines.insert(line);
|
||||
}
|
||||
|
||||
void set_input_polygon(std::size_t input_polygon_idx) {
|
||||
m_data->actual_input_polygon = input_polygon_idx;
|
||||
}
|
||||
|
||||
template<typename Pair>
|
||||
bool is_valid_polygon(const std::vector<Pair>& polygon) const {
|
||||
for (std::size_t i = 0; i < polygon.size(); ++i) {
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load Diff
|
|
@ -360,7 +360,7 @@ public:
|
|||
typedef typename boost::graph_traits<MutableFaceGraph>::halfedge_descriptor halfedge_descriptor;
|
||||
typedef typename boost::graph_traits<MutableFaceGraph>::face_descriptor face_descriptor;
|
||||
|
||||
CGAL_static_assertion((CGAL::graph_has_property<MutableFaceGraph, boost::vertex_point_t>::value));
|
||||
static_assert((CGAL::graph_has_property<MutableFaceGraph, boost::vertex_point_t>::value));
|
||||
typedef typename property_map_selector<MutableFaceGraph, CGAL::vertex_point_t>::type VPMap;
|
||||
VPMap vpm = get_property_map(boost::vertex_point, mesh);
|
||||
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@
|
|||
#include <CGAL/Triangulation_vertex_base_with_info_2.h>
|
||||
#include <CGAL/KSR/debug.h>
|
||||
#include <CGAL/Shape_regularization/regularize_planes.h>
|
||||
#include <CGAL/bounding_box.h>
|
||||
|
||||
#include <boost/filesystem.hpp>
|
||||
#include <boost/range/adaptor/transformed.hpp>
|
||||
|
|
@ -36,6 +37,8 @@
|
|||
#include <CGAL/AABB_traits.h>
|
||||
#include <CGAL/boost/graph/helpers.h>
|
||||
|
||||
//#define WITH_LCC
|
||||
|
||||
namespace CGAL
|
||||
{
|
||||
#ifndef DOXYGEN_RUNNING
|
||||
|
|
@ -88,7 +91,7 @@ public:
|
|||
*/
|
||||
template<typename NamedParameters = parameters::Default_named_parameters>
|
||||
Kinetic_shape_reconstruction_3(PointSet& ps,
|
||||
const NamedParameters& np = CGAL::parameters::default_values()) : m_points(ps), m_kinetic_partition(np), m_point_map(ps.point_map()), m_normal_map(ps.normal_map()) {}
|
||||
const NamedParameters& np = CGAL::parameters::default_values()) : m_points(ps), m_ground_polygon_index(-1), m_kinetic_partition(np), m_lcc(m_kinetic_partition.get_linear_cell_complex()) {}
|
||||
|
||||
/*!
|
||||
\brief Detects shapes in the provided point cloud
|
||||
|
|
@ -133,7 +136,7 @@ public:
|
|||
*/
|
||||
template<
|
||||
typename CGAL_NP_TEMPLATE_PARAMETERS>
|
||||
std::size_t detect_planar_shapes(
|
||||
std::size_t detect_planar_shapes(bool estimate_ground = false,
|
||||
const CGAL_NP_CLASS& np = parameters::default_values()) {
|
||||
|
||||
if (m_verbose)
|
||||
|
|
@ -146,7 +149,7 @@ public:
|
|||
m_point_map = Point_set_processing_3_np_helper<Point_set, CGAL_NP_CLASS, Point_map>::get_point_map(m_points, np);
|
||||
m_normal_map = Point_set_processing_3_np_helper<Point_set, CGAL_NP_CLASS, Normal_map>::get_normal_map(m_points, np);
|
||||
|
||||
create_planar_shapes(np);
|
||||
create_planar_shapes(estimate_ground, np);
|
||||
|
||||
CGAL_assertion(m_planes.size() == m_polygons.size());
|
||||
CGAL_assertion(m_polygons.size() == m_region_map.size());
|
||||
|
|
@ -256,10 +259,17 @@ public:
|
|||
bool setup_energyterms() {
|
||||
CGAL::Timer timer;
|
||||
timer.start();
|
||||
if (m_kinetic_partition.number_of_volumes() == 0) {
|
||||
if (m_verbose) std::cout << "Kinetic partition is not constructed or does not have volumes" << std::endl;
|
||||
#ifdef WITH_LCC
|
||||
if (m_lcc.one_dart_per_cell<3>().size() == 0) {
|
||||
std::cout << "Kinetic partition is not constructed or does not have volumes" << std::endl;
|
||||
return false;
|
||||
}
|
||||
#else
|
||||
if (m_kinetic_partition.number_of_volumes() == 0) {
|
||||
std::cout << "Kinetic partition is not constructed or does not have volumes" << std::endl;
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
m_faces.clear();
|
||||
m_face2index.clear();
|
||||
|
|
@ -268,12 +278,34 @@ public:
|
|||
m_face_inliers.clear();
|
||||
m_face_neighbors.clear();
|
||||
|
||||
#ifdef WITH_LCC
|
||||
auto face_range = m_lcc.one_dart_per_cell<2>();
|
||||
m_faces_lcc.reserve(face_range.size());
|
||||
for (auto& d : face_range) {
|
||||
KSP::LCC::Dart_const_descriptor dh;
|
||||
dh = m_lcc.dart_descriptor(d);
|
||||
|
||||
auto a = m_lcc.attribute<3>(dh);
|
||||
|
||||
if (m_lcc.is_attribute_used<3>(a))
|
||||
m_faces_lcc.push_back(dh);
|
||||
else
|
||||
std::cout << "face dart skipped" << std::endl;
|
||||
};
|
||||
|
||||
#else
|
||||
#endif
|
||||
m_kinetic_partition.unique_faces(std::back_inserter(m_faces));
|
||||
std::cout << "Found " << m_faces.size() << " faces between volumes" << std::endl;
|
||||
std::cout << "Found " << m_faces.size() << " / " << m_faces_lcc.size() << " faces between volumes" << std::endl;
|
||||
timer.reset();
|
||||
|
||||
#ifdef WITH_LCC
|
||||
for (std::size_t i = 0; i < m_faces_lcc.size(); i++)
|
||||
m_face2index_lcc[m_faces_lcc[i]] = i;
|
||||
#else
|
||||
for (std::size_t i = 0; i < m_faces.size(); i++)
|
||||
m_face2index[m_faces[i]] = i;
|
||||
#endif
|
||||
|
||||
// Create value arrays for graph cut
|
||||
m_face_inliers.resize(m_faces.size());
|
||||
|
|
@ -286,6 +318,13 @@ public:
|
|||
|
||||
std::cout << "* computing visibility ... ";
|
||||
|
||||
#ifdef WITH_LCC
|
||||
for (std::size_t i = 0; i < m_faces_lcc.size(); i++) {
|
||||
const typename KSP::LCC::Dart_const_descriptor &d = m_faces_lcc[i];
|
||||
// Filter whether faces have properties or not. -> after fixing the creation, all faces should have properties.
|
||||
m_lcc.is_attribute_used<3>(m_lcc.attribute<3>(d));
|
||||
}
|
||||
#else
|
||||
for (std::size_t i = 0; i < m_faces.size(); i++) {
|
||||
// Shift by 6 for accommodate outside volumes
|
||||
// Map negative numbers -1..-6 to 0..5
|
||||
|
|
@ -296,6 +335,8 @@ public:
|
|||
else
|
||||
m_face_neighbors[i] = std::make_pair(p.first + 6, p.second + 6);
|
||||
}
|
||||
#endif
|
||||
check_ground();
|
||||
|
||||
timer.reset();
|
||||
collect_points_for_faces3();
|
||||
|
|
@ -577,12 +618,19 @@ private:
|
|||
std::map<std::size_t, Indices> m_region_map;
|
||||
double m_detection_distance_tolerance;
|
||||
|
||||
std::size_t m_ground_polygon_index;
|
||||
Plane_3 m_ground_plane;
|
||||
|
||||
std::vector<Plane_3> m_planes;
|
||||
std::vector<Point_3> m_polygon_pts;
|
||||
std::vector<std::vector<std::size_t> > m_polygon_indices;
|
||||
std::vector<Polygon_3> m_polygons;
|
||||
KSP m_kinetic_partition;
|
||||
|
||||
const typename KSP::LCC &m_lcc;
|
||||
std::vector<typename KSP::LCC::Dart_const_descriptor> m_faces_lcc;
|
||||
std::map<typename KSP::LCC::Dart_const_descriptor, std::size_t> m_face2index_lcc;
|
||||
|
||||
// Face indices are now of type Indices and are not in a range 0 to n
|
||||
std::vector<typename KSP::Index> m_faces;
|
||||
std::map<typename KSP::Index, std::size_t> m_face2index;
|
||||
|
|
@ -591,6 +639,7 @@ private:
|
|||
std::vector<std::pair<std::size_t, std::size_t> > m_face_neighbors;
|
||||
|
||||
std::vector<std::pair<std::size_t, std::size_t> > m_volume_votes; // pair<inside, outside> votes
|
||||
std::vector<bool> m_volume_below_ground;
|
||||
std::vector<std::vector<double> > m_cost_matrix;
|
||||
std::vector<FT> m_volumes; // normalized volume of each kinetic volume
|
||||
std::vector<std::size_t> m_labels;
|
||||
|
|
@ -632,7 +681,8 @@ private:
|
|||
return shape_idx;
|
||||
}
|
||||
|
||||
void store_convex_hull_shape(const std::vector<std::size_t>& region, const Plane_3& plane, std::vector<std::vector<Point_3> >& polys) {
|
||||
void store_convex_hull_shape(const std::vector<std::size_t>& region, const Plane_3& plane, std::vector<std::vector<Point_3> > &polys) {
|
||||
|
||||
std::vector<Point_2> points;
|
||||
points.reserve(region.size());
|
||||
for (const std::size_t idx : region) {
|
||||
|
|
@ -927,24 +977,37 @@ private:
|
|||
}
|
||||
*/
|
||||
|
||||
void check_ground() {
|
||||
std::size_t num_volumes = m_kinetic_partition.number_of_volumes();
|
||||
// Set all volumes to not be below the ground, this leads to the standard 6 outside node connection.
|
||||
m_volume_below_ground.resize(num_volumes, false);
|
||||
|
||||
if (m_ground_polygon_index != -1)
|
||||
for (std::size_t i = 0; i < num_volumes; i++) {
|
||||
// Evaluate if volume centroid is below or above ground plane
|
||||
const Point_3& centroid = m_kinetic_partition.volume_centroid(i);
|
||||
m_volume_below_ground[i] = (centroid - m_regions[m_ground_polygon_index].first.projection(centroid)).z() < 0;
|
||||
}
|
||||
}
|
||||
|
||||
void collect_points_for_faces3() {
|
||||
FT total_area = 0;
|
||||
m_total_inliers = 0;
|
||||
From_exact from_exact;
|
||||
auto& reg2input = m_kinetic_partition.regularized_input_mapping();
|
||||
std::cout << reg2input.size() << std::endl;
|
||||
auto& inputmap = m_kinetic_partition.input_mapping();
|
||||
std::cout << inputmap.size() << std::endl;
|
||||
std::size_t next = 0, step = 1;
|
||||
for (std::size_t i = 0; i < reg2input.size(); i++) {
|
||||
for (std::size_t i = 0; i < inputmap.size(); i++) {
|
||||
|
||||
std::vector<std::pair<KSP::Index, std::vector<std::size_t> > > mapping;
|
||||
std::size_t fusioned_input_regions = 0;
|
||||
for (const auto& p : reg2input[i])
|
||||
for (const auto& p : inputmap[i])
|
||||
fusioned_input_regions += m_regions[p].second.size();
|
||||
|
||||
std::vector<Point_3> pts;
|
||||
std::vector<std::size_t> pts_idx;
|
||||
pts.reserve(fusioned_input_regions);
|
||||
for (const auto& p : reg2input[i]) {
|
||||
for (const auto& p : inputmap[i]) {
|
||||
for (std::size_t j = 0; j < m_regions[p].second.size(); j++) {
|
||||
pts.emplace_back(get(m_point_map, m_regions[p].second[j]));
|
||||
pts_idx.push_back(m_regions[p].second[j]);
|
||||
|
|
@ -964,13 +1027,13 @@ private:
|
|||
}
|
||||
|
||||
std::vector<KSP::Index> faces;
|
||||
m_kinetic_partition.faces_of_polygon(i, std::back_inserter(faces));
|
||||
m_kinetic_partition.faces_of_input_polygon(i, std::back_inserter(faces));
|
||||
|
||||
std::vector<std::vector<std::size_t> > faces2d(faces.size());
|
||||
std::vector<std::vector<std::size_t> > indices; // Adjacent faces for each vertex
|
||||
std::map<KSP::Index, std::size_t> idx2pts; // Mapping of vertices to pts vector
|
||||
|
||||
Plane_3 pl = from_exact(m_kinetic_partition.plane(i));
|
||||
Plane_3 pl = from_exact(m_kinetic_partition.input_plane(i));
|
||||
|
||||
for (std::size_t j = 0; j < faces.size(); j++) {
|
||||
std::size_t idx = m_face2index[faces[j]];
|
||||
|
|
@ -1032,13 +1095,23 @@ private:
|
|||
|
||||
for (std::size_t i = 0; i < m_faces.size(); i++) {
|
||||
// Check boundary faces and if the outside node has a defined value, if not, set area to 0.
|
||||
|
||||
if (m_face_neighbors[i].second < 6 && m_cost_matrix[0][m_face_neighbors[i].second] == m_cost_matrix[1][m_face_neighbors[i].second]) {
|
||||
m_face_area[i] = 0;
|
||||
}
|
||||
else
|
||||
m_face_area[i] = m_face_area[i] * 2.0 * m_total_inliers / total_area;
|
||||
}
|
||||
|
||||
std::size_t redirected = 0;
|
||||
for (std::size_t i = 0; i < m_face_neighbors.size(); i++) {
|
||||
// Check if the face is on a bbox face besides the top face.
|
||||
// If so and the connected volume is below the ground, redirect the face to the bottom face node.
|
||||
if (m_face_neighbors[i].second < 5 && m_volume_below_ground[m_face_neighbors[i].first - 6]) {
|
||||
redirected++;
|
||||
m_face_neighbors[i].second = 0;
|
||||
}
|
||||
}
|
||||
std::cout << redirected << " faces redirected to below ground" << std::endl;
|
||||
}
|
||||
|
||||
void count_volume_votes() {
|
||||
|
|
@ -1051,7 +1124,6 @@ private:
|
|||
std::size_t count_points = 0;
|
||||
|
||||
m_volumes.resize(num_volumes, 0);
|
||||
std::size_t next = 0, step = num_volumes / 100;
|
||||
for (std::size_t i = 0; i < num_volumes; i++) {
|
||||
|
||||
std::vector<Index> faces;
|
||||
|
|
@ -1140,7 +1212,7 @@ private:
|
|||
}
|
||||
|
||||
template<typename NamedParameters>
|
||||
void create_planar_shapes(const NamedParameters& np) {
|
||||
void create_planar_shapes(bool estimate_ground, const NamedParameters& np) {
|
||||
|
||||
if (m_points.size() < 3) {
|
||||
if (m_verbose) std::cout << "* no points found, skipping" << std::endl;
|
||||
|
|
@ -1193,7 +1265,7 @@ private:
|
|||
//KSR_3::dump_polygon(polys_debug[i], std::to_string(i) + "-detected-region.ply");
|
||||
}
|
||||
|
||||
KSR_3::dump_polygons(polys_debug, "detected-" + std::to_string(m_regions.size()) + "-polygons.ply");
|
||||
//KSR_3::dump_polygons(polys_debug, "detected-" + std::to_string(m_regions.size()) + "-polygons.ply");
|
||||
|
||||
// Convert indices.
|
||||
m_planar_regions.clear();
|
||||
|
|
@ -1223,7 +1295,6 @@ private:
|
|||
|
||||
// Regularize detected planes.
|
||||
|
||||
/*
|
||||
CGAL::Shape_regularization::Planes::regularize_planes(range, m_points,
|
||||
CGAL::parameters::plane_index_map(region_growing.region_map())
|
||||
.point_map(m_point_map)
|
||||
|
|
@ -1232,8 +1303,7 @@ private:
|
|||
.regularize_parallelism(regularize_parallelism)
|
||||
.regularize_coplanarity(regularize_coplanarity)
|
||||
.maximum_angle(angle_tolerance)
|
||||
.maximum_offset(maximum_offset));*/
|
||||
|
||||
.maximum_offset(maximum_offset));
|
||||
|
||||
polys_debug.clear();
|
||||
|
||||
|
|
@ -1247,7 +1317,7 @@ private:
|
|||
//KSR_3::dump_polygon(polys_debug[i], std::to_string(i) + "-detected-region.ply");
|
||||
}
|
||||
|
||||
KSR_3::dump_polygons(polys_debug, "regularized-" + std::to_string(m_regions.size()) + "-polygons.ply");
|
||||
//KSR_3::dump_polygons(polys_debug, "regularized-" + std::to_string(m_regions.size()) + "-polygons.ply");
|
||||
|
||||
// Merge coplanar regions
|
||||
for (std::size_t i = 0; i < m_regions.size() - 1; i++) {
|
||||
|
|
@ -1260,6 +1330,67 @@ private:
|
|||
}
|
||||
}
|
||||
|
||||
if (estimate_ground) {
|
||||
// How to estimate ground plane? Find low z peak
|
||||
std::vector<std::size_t> candidates;
|
||||
FT low_z_peak = (std::numeric_limits<FT>::max)();
|
||||
FT bbox_min[] = { (std::numeric_limits<FT>::max)(), (std::numeric_limits<FT>::max)(), (std::numeric_limits<FT>::max)() };
|
||||
FT bbox_max[] = { -(std::numeric_limits<FT>::max)(), -(std::numeric_limits<FT>::max)(), -(std::numeric_limits<FT>::max)() };
|
||||
for (const auto& p : m_points) {
|
||||
const auto& point = get(m_point_map, p);
|
||||
for (std::size_t i = 0; i < 3; i++) {
|
||||
bbox_min[i] = (std::min)(point[i], bbox_min[i]);
|
||||
bbox_max[i] = (std::max)(point[i], bbox_max[i]);
|
||||
}
|
||||
}
|
||||
|
||||
FT bbox_center[] = { 0.5 * (bbox_min[0] + bbox_max[0]), 0.5 * (bbox_min[1] + bbox_max[1]), 0.5 * (bbox_min[2] + bbox_max[2]) };
|
||||
|
||||
for (std::size_t i = 0; i < m_regions.size(); i++) {
|
||||
Vector_3 d = m_regions[i].first.orthogonal_vector();
|
||||
if (abs(d.z()) > 0.98) {
|
||||
candidates.push_back(i);
|
||||
FT z = m_regions[i].first.projection(Point_3(bbox_center[0], bbox_center[1], bbox_center[2])).z();
|
||||
low_z_peak = (std::min<FT>)(z, low_z_peak);
|
||||
}
|
||||
}
|
||||
|
||||
m_ground_polygon_index = -1;
|
||||
std::vector<std::size_t> other_ground;
|
||||
for (std::size_t i = 0; i < candidates.size(); i++) {
|
||||
Vector_3 d = m_regions[candidates[i]].first.orthogonal_vector();
|
||||
FT z = m_regions[candidates[i]].first.projection(Point_3(bbox_center[0], bbox_center[1], bbox_center[2])).z();
|
||||
if (z - low_z_peak < max_distance_to_plane) {
|
||||
if (m_ground_polygon_index == -1)
|
||||
m_ground_polygon_index = candidates[i];
|
||||
else
|
||||
other_ground.push_back(candidates[i]);
|
||||
}
|
||||
}
|
||||
|
||||
for (std::size_t i = 0; i < other_ground.size(); i++)
|
||||
std::move(m_regions[other_ground[i]].second.begin(), m_regions[other_ground[i]].second.end(), std::back_inserter(m_regions[m_ground_polygon_index].second));
|
||||
|
||||
std::cout << "ground polygon " << m_ground_polygon_index << ", merging other polygons";
|
||||
while (other_ground.size() != 0) {
|
||||
m_regions.erase(m_regions.begin() + other_ground.back());
|
||||
std::cout << " " << other_ground.back();
|
||||
other_ground.pop_back();
|
||||
}
|
||||
std::cout << std::endl;
|
||||
|
||||
std::vector<Point_3> ground_plane;
|
||||
ground_plane.reserve(m_regions[m_ground_polygon_index].second.size());
|
||||
for (std::size_t i = 0; i < m_regions[m_ground_polygon_index].second.size(); i++) {
|
||||
ground_plane.push_back(get(m_point_map, m_regions[m_ground_polygon_index].second[i]));
|
||||
}
|
||||
|
||||
CGAL::linear_least_squares_fitting_3(ground_plane.begin(), ground_plane.end(), m_regions[m_ground_polygon_index].first, CGAL::Dimension_tag<0>());
|
||||
|
||||
if (m_regions[m_ground_polygon_index].first.orthogonal_vector().z() < 0)
|
||||
m_regions[m_ground_polygon_index].first = m_regions[m_ground_polygon_index].first.opposite();
|
||||
}
|
||||
|
||||
polys_debug.clear();
|
||||
|
||||
for (std::size_t i = 0; i < m_regions.size(); i++) {
|
||||
|
|
@ -1272,7 +1403,7 @@ private:
|
|||
//KSR_3::dump_polygon(polys_debug[i], std::to_string(i) + "-detected-region.ply");
|
||||
}
|
||||
|
||||
KSR_3::dump_polygons(polys_debug, "merged-" + std::to_string(m_regions.size()) + "-polygons.ply");
|
||||
//KSR_3::dump_polygons(polys_debug, "merged-" + std::to_string(m_regions.size()) + "-polygons.ply");
|
||||
|
||||
std::vector<Plane_3> pl;
|
||||
|
||||
|
|
@ -1342,18 +1473,32 @@ private:
|
|||
// 4 xmin
|
||||
// 5 zmax
|
||||
const std::size_t force = m_total_inliers * 3;
|
||||
// 0 - cost for labelled as outside
|
||||
cost_matrix[0][0] = 0;
|
||||
cost_matrix[0][1] = 0;
|
||||
cost_matrix[0][2] = 0;
|
||||
cost_matrix[0][3] = 0;
|
||||
cost_matrix[0][4] = 0;
|
||||
cost_matrix[0][5] = 0;
|
||||
// 1 - cost for labelled as inside
|
||||
cost_matrix[1][0] = 0;
|
||||
cost_matrix[1][1] = 0;
|
||||
cost_matrix[1][2] = 0;
|
||||
cost_matrix[1][3] = 0;
|
||||
cost_matrix[1][4] = 0;
|
||||
cost_matrix[1][5] = 0;
|
||||
|
||||
if (m_ground_polygon_index != -1) {
|
||||
std::cout << "using estimated ground plane for reconstruction" << std::endl;
|
||||
cost_matrix[0][1] = 0;
|
||||
cost_matrix[0][2] = 0;
|
||||
cost_matrix[0][3] = 0;
|
||||
cost_matrix[0][4] = 0;
|
||||
cost_matrix[1][1] = force;
|
||||
cost_matrix[1][2] = force;
|
||||
cost_matrix[1][3] = force;
|
||||
cost_matrix[1][4] = force;
|
||||
}
|
||||
}
|
||||
|
||||
void dump_volume(std::size_t i, const std::string& filename, const CGAL::Color &color) const {
|
||||
|
|
|
|||
|
|
@ -467,7 +467,7 @@ public:
|
|||
Bbox_dimensions size = m_side_per_depth[depth(n)];
|
||||
for (int i = 0; i < Dimension::value; i++) {
|
||||
min_corner[i] = m_bbox_min[i] + (global_coordinates(n)[i] * size[i]);
|
||||
max_corner[i] = min_corner[i] + size[i];
|
||||
max_corner[i] = m_bbox_min[i] + ((global_coordinates(n)[i] + 1) * size[i]);
|
||||
}
|
||||
return {std::apply(m_traits.construct_point_d_object(), min_corner),
|
||||
std::apply(m_traits.construct_point_d_object(), max_corner)};
|
||||
|
|
|
|||
|
|
@ -266,6 +266,8 @@ CGAL_add_named_parameter(distance_tolerance_t, distance_tolerance, distance_tole
|
|||
CGAL_add_named_parameter(angle_tolerance_t, angle_tolerance, angle_tolerance)
|
||||
CGAL_add_named_parameter(debug_t, debug, debug)
|
||||
CGAL_add_named_parameter(graphcut_beta_t, graphcut_beta, graphcut_beta)
|
||||
CGAL_add_named_parameter(max_octree_depth_t, max_octree_depth, max_octree_depth)
|
||||
CGAL_add_named_parameter(max_octree_node_size_t, max_octree_node_size, max_octree_node_size)
|
||||
|
||||
// List of named parameters used in Shape_detection package
|
||||
CGAL_add_named_parameter(maximum_angle_t, maximum_angle, maximum_angle)
|
||||
|
|
|
|||
Loading…
Reference in New Issue