mirror of https://github.com/CGAL/cgal
Merge remote-tracking branch 'orth/orthtree-generalization' into Kinetic_shape_reconstruction-new_package-soesau
# Conflicts: # Orthtree/include/CGAL/Orthtree.h
This commit is contained in:
commit
5a27f38675
|
|
@ -12,3 +12,4 @@ create_single_source_cgal_program("triangle_soup_wrap.cpp")
|
|||
create_single_source_cgal_program("point_set_wrap.cpp")
|
||||
create_single_source_cgal_program("wrap_from_cavity.cpp")
|
||||
create_single_source_cgal_program("mixed_inputs_wrap.cpp")
|
||||
create_single_source_cgal_program("volumetric_wrap.cpp")
|
||||
|
|
|
|||
|
|
@ -16,9 +16,9 @@ using K = CGAL::Exact_predicates_inexact_constructions_kernel;
|
|||
using Point_3 = K::Point_3;
|
||||
using Segment_3 = K::Segment_3;
|
||||
|
||||
using Face = std::array<std::size_t, 3>;
|
||||
using Segments = std::vector<Segment_3>;
|
||||
using Points = std::vector<Point_3>;
|
||||
using Face = std::array<std::size_t, 3>;
|
||||
using Faces = std::vector<Face>;
|
||||
|
||||
using Mesh = CGAL::Surface_mesh<Point_3>;
|
||||
|
|
|
|||
|
|
@ -0,0 +1,173 @@
|
|||
#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
|
||||
#include <CGAL/Surface_mesh.h>
|
||||
|
||||
#include <CGAL/alpha_wrap_3.h>
|
||||
|
||||
#include <CGAL/tetrahedral_remeshing.h>
|
||||
#include <CGAL/Tetrahedral_remeshing/Remeshing_cell_base_3.h>
|
||||
#include <CGAL/Tetrahedral_remeshing/Remeshing_vertex_base_3.h>
|
||||
#include <CGAL/Simplicial_mesh_cell_base_3.h>
|
||||
#include <CGAL/Simplicial_mesh_vertex_base_3.h>
|
||||
|
||||
#include <CGAL/Polygon_mesh_processing/bbox.h>
|
||||
#include <CGAL/Polygon_mesh_processing/IO/polygon_mesh_io.h>
|
||||
#include <CGAL/property_map.h>
|
||||
#include <CGAL/Real_timer.h>
|
||||
|
||||
#include <CGAL/Delaunay_triangulation_3.h>
|
||||
#include <CGAL/draw_triangulation_3.h>
|
||||
|
||||
#include <CGAL/IO/Triangulation_off_ostream_3.h>
|
||||
#include <CGAL/IO/File_medit.h>
|
||||
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
|
||||
namespace PMP = CGAL::Polygon_mesh_processing;
|
||||
namespace AW3i = CGAL::Alpha_wraps_3::internal;
|
||||
|
||||
using K = CGAL::Exact_predicates_inexact_constructions_kernel;
|
||||
using Point_3 = K::Point_3;
|
||||
|
||||
using Points = std::vector<Point_3>;
|
||||
using Face = std::array<std::size_t, 3>;
|
||||
using Faces = std::vector<Face>;
|
||||
|
||||
using Mesh = CGAL::Surface_mesh<Point_3>;
|
||||
|
||||
// If we provide a triangulation, AW3 uses its Gt, so we have to make the Gt stack explicit
|
||||
using Gtb = AW3i::Alpha_wrap_AABB_geom_traits<K>; // provides Ball_3
|
||||
using Gt = CGAL::Robust_circumcenter_filtered_traits_3<Gtb>; // better inexact constructions (not mandatory)
|
||||
|
||||
// Since we are going to use tetrahedral remeshing on the underlying triangulation,
|
||||
// we need special vertex and cell base types that meets the requirements of the
|
||||
// tetrahedral remeshing concepts
|
||||
using Vbbb = AW3i::Alpha_wrap_triangulation_vertex_base_3<K>;
|
||||
using Vbb = CGAL::Simplicial_mesh_vertex_base_3<K, int, int, int, int, Vbbb>;
|
||||
using Vb = CGAL::Tetrahedral_remeshing::Remeshing_vertex_base_3<K, Vbb>;
|
||||
|
||||
using Cbbb = AW3i::Alpha_wrap_triangulation_cell_base_3<K>;
|
||||
using Cbb = CGAL::Simplicial_mesh_cell_base_3<K, int, int, Cbbb>;
|
||||
using Cb = CGAL::Tetrahedral_remeshing::Remeshing_cell_base_3<K, Cbb>;
|
||||
|
||||
using Tds = CGAL::Triangulation_data_structure_3<Vb, Cb>;
|
||||
|
||||
using Delaunay_triangulation = CGAL::Delaunay_triangulation_3<Gt, Tds, CGAL::Fast_location>;
|
||||
|
||||
// because the Fast_location does all kinds of rebinding shenanigans + T3_hierarchy is in the stack...
|
||||
using Triangulation = CGAL::Triangulation_3<typename Delaunay_triangulation::Geom_traits,
|
||||
typename Delaunay_triangulation::Triangulation_data_structure>;
|
||||
|
||||
using Facet = Triangulation::Facet;
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
// Read the input
|
||||
const std::string filename = (argc > 1) ? argv[1] : CGAL::data_file_path("meshes/bull.off");
|
||||
std::cout << "Reading " << filename << "..." << std::endl;
|
||||
|
||||
Points points;
|
||||
Faces faces;
|
||||
if(!CGAL::IO::read_polygon_soup(filename, points, faces) || faces.empty())
|
||||
{
|
||||
std::cerr << "Invalid input." << std::endl;
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
std::cout << "Input: " << points.size() << " vertices, " << faces.size() << " faces" << std::endl;
|
||||
|
||||
// Compute the alpha and offset values
|
||||
const double relative_alpha = (argc > 2) ? std::stod(argv[2]) : 20.;
|
||||
const double relative_offset = (argc > 3) ? std::stod(argv[3]) : 600.;
|
||||
|
||||
CGAL::Bbox_3 bbox;
|
||||
for(const Point_3& p : points)
|
||||
bbox += p.bbox();
|
||||
|
||||
const double diag_length = std::sqrt(CGAL::square(bbox.xmax() - bbox.xmin()) +
|
||||
CGAL::square(bbox.ymax() - bbox.ymin()) +
|
||||
CGAL::square(bbox.zmax() - bbox.zmin()));
|
||||
|
||||
const double alpha = diag_length / relative_alpha;
|
||||
const double offset = diag_length / relative_offset;
|
||||
std::cout << "alpha: " << alpha << ", offset: " << offset << std::endl;
|
||||
|
||||
// Construct the wrap
|
||||
CGAL::Real_timer t;
|
||||
t.start();
|
||||
|
||||
using Oracle = CGAL::Alpha_wraps_3::internal::Triangle_soup_oracle<K>;
|
||||
|
||||
Oracle oracle(K{});
|
||||
oracle.add_triangle_soup(points, faces, CGAL::parameters::default_values());
|
||||
|
||||
CGAL::Alpha_wraps_3::internal::Alpha_wrap_3<Oracle, Delaunay_triangulation> aw3(oracle);
|
||||
Mesh wrap;
|
||||
aw3(alpha, offset, wrap);
|
||||
|
||||
t.stop();
|
||||
std::cout << "Result: " << num_vertices(wrap) << " vertices, " << num_faces(wrap) << " faces" << std::endl;
|
||||
std::cout << "Took " << t.time() << " s." << std::endl;
|
||||
|
||||
// Get the interior tetrahedrization
|
||||
auto dt = aw3.triangulation();
|
||||
|
||||
// Save the result
|
||||
std::string input_name = std::string(filename);
|
||||
input_name = input_name.substr(input_name.find_last_of("/") + 1, input_name.length() - 1);
|
||||
input_name = input_name.substr(0, input_name.find_last_of("."));
|
||||
std::string output_name = input_name
|
||||
+ "_" + std::to_string(static_cast<int>(relative_alpha))
|
||||
+ "_" + std::to_string(static_cast<int>(relative_offset)) + ".off";
|
||||
std::cout << "Writing to " << output_name << std::endl;
|
||||
CGAL::IO::write_polygon_mesh(output_name, wrap, CGAL::parameters::stream_precision(17));
|
||||
|
||||
// Remesh the interior of the wrap
|
||||
const Delaunay_triangulation& aw3_dt = aw3.triangulation();
|
||||
const Triangulation& aw3_tr = static_cast<const Triangulation&>(aw3_dt);
|
||||
Triangulation tr = aw3_tr; // intentional copy
|
||||
|
||||
std::cout << "BEFORE: " << tr.number_of_vertices() << " vertices, " << tr.number_of_cells() << " cells" << std::endl;
|
||||
|
||||
// Set up the c3t3 information
|
||||
for(auto v : tr.finite_vertex_handles())
|
||||
v->set_dimension(3);
|
||||
|
||||
for(auto c : tr.finite_cell_handles())
|
||||
{
|
||||
if(c->is_outside())
|
||||
c->set_subdomain_index(0);
|
||||
else
|
||||
c->set_subdomain_index(1);
|
||||
|
||||
// if the neighboring cell has a different outside info, put the vertices
|
||||
// of the common face on the surface boundary
|
||||
for(int i=0; i<4; ++i)
|
||||
{
|
||||
if(c->neighbor(i)->is_outside() != c->is_outside())
|
||||
{
|
||||
c->set_surface_patch_index(i, 1);
|
||||
for(int j=1; j<4; ++j)
|
||||
c->vertex((i+j)%4)->set_dimension(2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::ofstream out_before("before_remeshing.mesh");
|
||||
CGAL::IO::write_MEDIT(out_before, tr);
|
||||
|
||||
// edge length of equilateral triangle with circumradius alpha
|
||||
// const double l = 2 * alpha * 0.8660254037844386; // sqrt(3)/2
|
||||
|
||||
// edge length of regular tetrahedron with circumradius alpha
|
||||
const double l = 1.6329931618554521 * alpha; // sqrt(8/3)
|
||||
|
||||
CGAL::tetrahedral_isotropic_remeshing(tr, l, CGAL::parameters::remesh_boundaries(false));
|
||||
|
||||
std::cout << "AFTER: " << tr.number_of_vertices() << " vertices, " << tr.number_of_cells() << " cells" << std::endl;
|
||||
|
||||
std::ofstream out_after("after_remeshing.mesh");
|
||||
CGAL::IO::write_MEDIT(out_after, tr);
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright (c) 2019-2022 Google LLC (USA).
|
||||
// Copyright (c) 2019-2023 Google LLC (USA).
|
||||
// All rights reserved.
|
||||
//
|
||||
// This file is part of CGAL (www.cgal.org).
|
||||
|
|
@ -29,16 +29,25 @@
|
|||
|
||||
#include <CGAL/license/Alpha_wrap_3.h>
|
||||
|
||||
#include <CGAL/Alpha_wrap_3/internal/Alpha_wrap_triangulation_cell_base_3.h>
|
||||
#include <CGAL/Alpha_wrap_3/internal/Alpha_wrap_triangulation_vertex_base_3.h>
|
||||
#include <CGAL/Alpha_wrap_3/internal/Alpha_wrap_AABB_geom_traits.h>
|
||||
#include <CGAL/Alpha_wrap_3/internal/gate_priority_queue.h>
|
||||
#include <CGAL/Alpha_wrap_3/internal/geometry_utils.h>
|
||||
#include <CGAL/Alpha_wrap_3/internal/oracles.h>
|
||||
|
||||
#include <CGAL/Delaunay_triangulation_3.h>
|
||||
#include <CGAL/Triangulation_data_structure_3.h>
|
||||
#include <CGAL/Delaunay_triangulation_cell_base_3.h>
|
||||
#include <CGAL/Delaunay_triangulation_cell_base_with_circumcenter_3.h>
|
||||
#include <CGAL/Robust_weighted_circumcenter_filtered_traits_3.h>
|
||||
|
||||
#include <CGAL/Cartesian_converter.h>
|
||||
#include <CGAL/Simple_cartesian.h>
|
||||
|
||||
#include <CGAL/boost/graph/Euler_operations.h>
|
||||
#include <CGAL/boost/graph/named_params_helper.h>
|
||||
#include <CGAL/Default.h>
|
||||
#include <CGAL/Named_function_parameters.h>
|
||||
#include <CGAL/Modifiable_priority_queue.h>
|
||||
#include <CGAL/Polygon_mesh_processing/bbox.h>
|
||||
|
|
@ -50,16 +59,9 @@
|
|||
#include <CGAL/Polygon_mesh_processing/stitch_borders.h> // only if non-manifoldness is not treated
|
||||
#include <CGAL/property_map.h>
|
||||
#include <CGAL/Real_timer.h>
|
||||
#include <CGAL/Delaunay_triangulation_3.h>
|
||||
#include <CGAL/Triangulation_data_structure_3.h>
|
||||
#include <CGAL/Delaunay_triangulation_cell_base_3.h>
|
||||
#include <CGAL/Triangulation_cell_base_with_info_3.h>
|
||||
#include <CGAL/Delaunay_triangulation_cell_base_with_circumcenter_3.h>
|
||||
#include <CGAL/Triangulation_vertex_base_with_info_3.h>
|
||||
#include <CGAL/Robust_weighted_circumcenter_filtered_traits_3.h>
|
||||
|
||||
#include <array>
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
#include <fstream>
|
||||
#include <functional>
|
||||
#include <iostream>
|
||||
|
|
@ -74,30 +76,11 @@ namespace CGAL {
|
|||
namespace Alpha_wraps_3 {
|
||||
namespace internal {
|
||||
|
||||
template <typename Cb>
|
||||
class Cell_base_with_timestamp
|
||||
: public Cb
|
||||
{
|
||||
std::size_t time_stamp_;
|
||||
namespace {
|
||||
|
||||
public:
|
||||
template <typename... Args>
|
||||
Cell_base_with_timestamp(const Args&... args) : Cb(args...), time_stamp_(-1) { }
|
||||
namespace AW3i = ::CGAL::Alpha_wraps_3::internal;
|
||||
|
||||
Cell_base_with_timestamp(const Cell_base_with_timestamp& other) : Cb(other), time_stamp_(other.time_stamp_) { }
|
||||
|
||||
typedef CGAL::Tag_true Has_timestamp;
|
||||
|
||||
std::size_t time_stamp() const { return time_stamp_; }
|
||||
void set_time_stamp(const std::size_t& ts) { time_stamp_ = ts; }
|
||||
|
||||
template <class TDS>
|
||||
struct Rebind_TDS
|
||||
{
|
||||
typedef typename Cb::template Rebind_TDS<TDS>::Other Cb2;
|
||||
typedef Cell_base_with_timestamp<Cb2> Other;
|
||||
};
|
||||
};
|
||||
} // unnamed namespace
|
||||
|
||||
struct Wrapping_default_visitor
|
||||
{
|
||||
|
|
@ -125,11 +108,34 @@ struct Wrapping_default_visitor
|
|||
void on_alpha_wrapping_end(const AlphaWrapper&) { };
|
||||
};
|
||||
|
||||
template <typename Oracle>
|
||||
template <typename Oracle_,
|
||||
typename Triangulation_ = CGAL::Default>
|
||||
class Alpha_wrap_3
|
||||
{
|
||||
using Oracle = Oracle_;
|
||||
|
||||
// Triangulation
|
||||
using Base_GT = typename Oracle::Geom_traits;
|
||||
using Geom_traits = Robust_circumcenter_filtered_traits_3<Base_GT>;
|
||||
using Default_Gt = CGAL::Robust_circumcenter_filtered_traits_3<Base_GT>;
|
||||
|
||||
using Default_Vb = Alpha_wrap_triangulation_vertex_base_3<Default_Gt>;
|
||||
using Default_Cb = Alpha_wrap_triangulation_cell_base_3<Default_Gt>;
|
||||
using Default_Cbt = Cell_base_with_timestamp<Default_Cb>; // determinism
|
||||
using Default_Tds = CGAL::Triangulation_data_structure_3<Default_Vb, Default_Cbt>;
|
||||
using Default_Triangulation = CGAL::Delaunay_triangulation_3<Default_Gt, Default_Tds, Fast_location>;
|
||||
|
||||
using Triangulation = typename Default::Get<Triangulation_, Default_Triangulation>::type;
|
||||
|
||||
using Cell_handle = typename Triangulation::Cell_handle;
|
||||
using Facet = typename Triangulation::Facet;
|
||||
using Vertex_handle = typename Triangulation::Vertex_handle;
|
||||
using Locate_type = typename Triangulation::Locate_type;
|
||||
|
||||
using Gate = internal::Gate<Triangulation>;
|
||||
using Alpha_PQ = Modifiable_priority_queue<Gate, Less_gate, Gate_ID_PM<Triangulation>, CGAL_BOOST_PAIRING_HEAP>;
|
||||
|
||||
// Use the geom traits from the triangulation, and trust the (advanced) user that provided it
|
||||
using Geom_traits = typename Triangulation::Geom_traits;
|
||||
|
||||
using FT = typename Geom_traits::FT;
|
||||
using Point_3 = typename Geom_traits::Point_3;
|
||||
|
|
@ -143,34 +149,6 @@ class Alpha_wrap_3
|
|||
using SC_Iso_cuboid_3 = SC::Iso_cuboid_3;
|
||||
using SC2GT = Cartesian_converter<SC, Geom_traits>;
|
||||
|
||||
struct Cell_info
|
||||
{
|
||||
bool is_outside = false;
|
||||
};
|
||||
|
||||
enum Vertex_info
|
||||
{
|
||||
DEFAULT = 0,
|
||||
BBOX_VERTEX,
|
||||
SEED_VERTEX
|
||||
};
|
||||
|
||||
using Vb = Triangulation_vertex_base_3<Geom_traits>;
|
||||
using Vbi = Triangulation_vertex_base_with_info_3<Vertex_info, Geom_traits, Vb>;
|
||||
using Cbb = Delaunay_triangulation_cell_base_3<Geom_traits>;
|
||||
using Cb = Delaunay_triangulation_cell_base_with_circumcenter_3<Geom_traits, Cbb>;
|
||||
using Cbi = Triangulation_cell_base_with_info_3<Cell_info, Geom_traits, Cb>;
|
||||
using Cbt = Cell_base_with_timestamp<Cbi>;
|
||||
using Tds = Triangulation_data_structure_3<Vbi, Cbt>;
|
||||
using Dt = Delaunay_triangulation_3<Geom_traits, Tds, Fast_location>;
|
||||
|
||||
using Cell_handle = typename Dt::Cell_handle;
|
||||
using Facet = typename Dt::Facet;
|
||||
using Vertex_handle = typename Dt::Vertex_handle;
|
||||
using Locate_type = typename Dt::Locate_type;
|
||||
|
||||
using Gate = internal::Gate<Dt>;
|
||||
using Alpha_PQ = Modifiable_priority_queue<Gate, Less_gate, Gate_ID_PM<Dt>, CGAL_BOOST_PAIRING_HEAP>;
|
||||
|
||||
protected:
|
||||
const Oracle m_oracle;
|
||||
|
|
@ -179,7 +157,7 @@ protected:
|
|||
FT m_alpha, m_sq_alpha;
|
||||
FT m_offset, m_sq_offset;
|
||||
|
||||
Dt m_dt;
|
||||
Triangulation m_tr;
|
||||
Alpha_PQ m_queue;
|
||||
|
||||
public:
|
||||
|
|
@ -187,7 +165,7 @@ public:
|
|||
Alpha_wrap_3(const Oracle& oracle)
|
||||
:
|
||||
m_oracle(oracle),
|
||||
m_dt(Geom_traits(oracle.geom_traits())),
|
||||
m_tr(Geom_traits(oracle.geom_traits())),
|
||||
// used to set up the initial MPQ, use some arbitrary not-too-small value
|
||||
m_queue(4096)
|
||||
{
|
||||
|
|
@ -197,9 +175,9 @@ public:
|
|||
}
|
||||
|
||||
public:
|
||||
const Geom_traits& geom_traits() const { return m_dt.geom_traits(); }
|
||||
Dt& triangulation() { return m_dt; }
|
||||
const Dt& triangulation() const { return m_dt; }
|
||||
const Geom_traits& geom_traits() const { return m_tr.geom_traits(); }
|
||||
Triangulation& triangulation() { return m_tr; }
|
||||
const Triangulation& triangulation() const { return m_tr; }
|
||||
const Alpha_PQ& queue() const { return m_queue; }
|
||||
|
||||
double default_alpha() const
|
||||
|
|
@ -216,13 +194,13 @@ private:
|
|||
const Point_3& circumcenter(const Cell_handle c) const
|
||||
{
|
||||
// We only cross an infinite facet once, so this isn't going to be recomputed many times
|
||||
if(m_dt.is_infinite(c))
|
||||
if(m_tr.is_infinite(c))
|
||||
{
|
||||
const int inf_index = c->index(m_dt.infinite_vertex());
|
||||
const int inf_index = c->index(m_tr.infinite_vertex());
|
||||
c->set_circumcenter(
|
||||
geom_traits().construct_circumcenter_3_object()(m_dt.point(c, (inf_index+1)&3),
|
||||
m_dt.point(c, (inf_index+2)&3),
|
||||
m_dt.point(c, (inf_index+3)&3)));
|
||||
geom_traits().construct_circumcenter_3_object()(m_tr.point(c, (inf_index+1)&3),
|
||||
m_tr.point(c, (inf_index+2)&3),
|
||||
m_tr.point(c, (inf_index+3)&3)));
|
||||
}
|
||||
|
||||
return c->circumcenter(geom_traits());
|
||||
|
|
@ -418,11 +396,11 @@ private:
|
|||
for(int i=0; i<8; ++i)
|
||||
{
|
||||
const Point_3 bp = SC2GT()(m_bbox.vertex(i));
|
||||
Vertex_handle bv = m_dt.insert(bp);
|
||||
Vertex_handle bv = m_tr.insert(bp);
|
||||
#ifdef CGAL_AW3_DEBUG_INITIALIZATION
|
||||
std::cout << "\t" << bp << std::endl;
|
||||
#endif
|
||||
bv->info() = BBOX_VERTEX;
|
||||
bv->type() = AW3i::Vertex_type:: BBOX_VERTEX;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -433,7 +411,7 @@ private:
|
|||
// that the refinement point is separated from the existing point set.
|
||||
bool cavity_cell_outside_tag(const Cell_handle ch)
|
||||
{
|
||||
CGAL_precondition(!m_dt.is_infinite(ch));
|
||||
CGAL_precondition(!m_tr.is_infinite(ch));
|
||||
|
||||
const Tetrahedron_with_outside_info<Geom_traits> tet(ch, geom_traits());
|
||||
if(m_oracle.do_intersect(tet))
|
||||
|
|
@ -536,8 +514,8 @@ private:
|
|||
// This problem only appears when the seed and icosahedron vertices are close to the offset surface,
|
||||
// which usually happens for large alpha values.
|
||||
|
||||
Vertex_handle seed_v = m_dt.insert(seed_p);
|
||||
seed_v->info() = SEED_VERTEX;
|
||||
Vertex_handle seed_v = m_tr.insert(seed_p);
|
||||
seed_v->type() = AW3i::Vertex_type:: SEED_VERTEX;
|
||||
seed_vs.push_back(seed_v);
|
||||
|
||||
// Icosahedron vertices (see also BGL::make_icosahedron())
|
||||
|
|
@ -573,8 +551,8 @@ private:
|
|||
if(bbox.has_on_unbounded_side(seed_neighbor_p))
|
||||
continue;
|
||||
|
||||
Vertex_handle ico_v = m_dt.insert(seed_neighbor_p, seed_v /*hint*/);
|
||||
ico_v->info() = SEED_VERTEX;
|
||||
Vertex_handle ico_v = m_tr.insert(seed_neighbor_p, seed_v /*hint*/);
|
||||
ico_v->type() = AW3i::Vertex_type:: SEED_VERTEX;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -587,26 +565,26 @@ private:
|
|||
}
|
||||
|
||||
#ifdef CGAL_AW3_DEBUG_INITIALIZATION
|
||||
std::cout << m_dt.number_of_vertices() - 8 /*bbox*/ << " vertice(s) due to seeds" << std::endl;
|
||||
std::cout << m_tr.number_of_vertices() - 8 /*bbox*/ << " vertice(s) due to seeds" << std::endl;
|
||||
#endif
|
||||
|
||||
for(Vertex_handle seed_v : seed_vs)
|
||||
{
|
||||
std::vector<Cell_handle> inc_cells;
|
||||
inc_cells.reserve(64);
|
||||
m_dt.incident_cells(seed_v, std::back_inserter(inc_cells));
|
||||
m_tr.incident_cells(seed_v, std::back_inserter(inc_cells));
|
||||
for(Cell_handle ch : inc_cells)
|
||||
ch->info().is_outside = cavity_cell_outside_tag(ch);
|
||||
ch->is_outside() = cavity_cell_outside_tag(ch);
|
||||
}
|
||||
|
||||
// Might as well go through the full triangulation since only seeds should have been inserted
|
||||
for(Cell_handle ch : m_dt.all_cell_handles())
|
||||
for(Cell_handle ch : m_tr.all_cell_handles())
|
||||
{
|
||||
if(!ch->info().is_outside)
|
||||
if(!ch->is_outside())
|
||||
continue;
|
||||
|
||||
// When the algorithm starts from a manually dug hole, infinite cells are tagged "inside"
|
||||
CGAL_assertion(!m_dt.is_infinite(ch));
|
||||
CGAL_assertion(!m_tr.is_infinite(ch));
|
||||
|
||||
for(int i=0; i<4; ++i)
|
||||
push_facet(std::make_pair(ch, i));
|
||||
|
|
@ -627,17 +605,17 @@ private:
|
|||
// init queue with all convex hull facets
|
||||
bool initialize_from_infinity()
|
||||
{
|
||||
for(Cell_handle ch : m_dt.all_cell_handles())
|
||||
for(Cell_handle ch : m_tr.all_cell_handles())
|
||||
{
|
||||
if(m_dt.is_infinite(ch))
|
||||
if(m_tr.is_infinite(ch))
|
||||
{
|
||||
ch->info().is_outside = true;
|
||||
const int inf_index = ch->index(m_dt.infinite_vertex());
|
||||
ch->is_outside() = true;
|
||||
const int inf_index = ch->index(m_tr.infinite_vertex());
|
||||
push_facet(std::make_pair(ch, inf_index));
|
||||
}
|
||||
else
|
||||
{
|
||||
ch->info().is_outside = false;
|
||||
ch->is_outside() = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -659,13 +637,13 @@ public:
|
|||
|
||||
clear(output_mesh);
|
||||
|
||||
CGAL_assertion_code(for(auto cit=m_dt.finite_cells_begin(), cend=m_dt.finite_cells_end(); cit!=cend; ++cit))
|
||||
CGAL_assertion_code(for(auto cit=m_tr.finite_cells_begin(), cend=m_tr.finite_cells_end(); cit!=cend; ++cit))
|
||||
CGAL_assertion(cit->tds_data().is_clear());
|
||||
|
||||
for(auto cit=m_dt.finite_cells_begin(), cend=m_dt.finite_cells_end(); cit!=cend; ++cit)
|
||||
for(auto cit=m_tr.finite_cells_begin(), cend=m_tr.finite_cells_end(); cit!=cend; ++cit)
|
||||
{
|
||||
Cell_handle seed = cit;
|
||||
if(seed->info().is_outside || seed->tds_data().processed())
|
||||
if(seed->is_outside() || seed->tds_data().processed())
|
||||
continue;
|
||||
|
||||
std::queue<Cell_handle> to_visit;
|
||||
|
|
@ -678,7 +656,7 @@ public:
|
|||
while(!to_visit.empty())
|
||||
{
|
||||
const Cell_handle cell = to_visit.front();
|
||||
CGAL_assertion(!cell->info().is_outside && !m_dt.is_infinite(cell));
|
||||
CGAL_assertion(!cell->is_outside() && !m_tr.is_infinite(cell));
|
||||
|
||||
to_visit.pop();
|
||||
|
||||
|
|
@ -690,17 +668,17 @@ public:
|
|||
for(int fid=0; fid<4; ++fid)
|
||||
{
|
||||
const Cell_handle neighbor = cell->neighbor(fid);
|
||||
if(neighbor->info().is_outside)
|
||||
if(neighbor->is_outside())
|
||||
{
|
||||
// There shouldn't be any artificial vertex on the inside/outside boundary
|
||||
// (past initialization)
|
||||
// CGAL_assertion(cell->vertex((fid + 1)&3)->info() == DEFAULT);
|
||||
// CGAL_assertion(cell->vertex((fid + 2)&3)->info() == DEFAULT);
|
||||
// CGAL_assertion(cell->vertex((fid + 3)&3)->info() == DEFAULT);
|
||||
// CGAL_assertion(cell->vertex((fid + 1)&3)->type() == AW3i::Vertex_type:: DEFAULT);
|
||||
// CGAL_assertion(cell->vertex((fid + 2)&3)->type() == AW3i::Vertex_type:: DEFAULT);
|
||||
// CGAL_assertion(cell->vertex((fid + 3)&3)->type() == AW3i::Vertex_type:: DEFAULT);
|
||||
|
||||
points.push_back(m_dt.point(cell, Dt::vertex_triple_index(fid, 0)));
|
||||
points.push_back(m_dt.point(cell, Dt::vertex_triple_index(fid, 1)));
|
||||
points.push_back(m_dt.point(cell, Dt::vertex_triple_index(fid, 2)));
|
||||
points.push_back(m_tr.point(cell, Triangulation::vertex_triple_index(fid, 0)));
|
||||
points.push_back(m_tr.point(cell, Triangulation::vertex_triple_index(fid, 1)));
|
||||
points.push_back(m_tr.point(cell, Triangulation::vertex_triple_index(fid, 2)));
|
||||
faces.push_back({idx, idx + 1, idx + 2});
|
||||
idx += 3;
|
||||
}
|
||||
|
|
@ -722,7 +700,7 @@ public:
|
|||
CGAL_assertion(is_closed(output_mesh));
|
||||
}
|
||||
|
||||
for(auto cit=m_dt.finite_cells_begin(), cend=m_dt.finite_cells_end(); cit!=cend; ++cit)
|
||||
for(auto cit=m_tr.finite_cells_begin(), cend=m_tr.finite_cells_end(); cit!=cend; ++cit)
|
||||
cit->tds_data().clear();
|
||||
|
||||
CGAL_postcondition(!is_empty(output_mesh));
|
||||
|
|
@ -742,7 +720,7 @@ public:
|
|||
std::cout << "> Extract wrap... ()" << std::endl;
|
||||
#endif
|
||||
|
||||
CGAL_assertion_code(for(Vertex_handle v : m_dt.finite_vertex_handles()))
|
||||
CGAL_assertion_code(for(Vertex_handle v : m_tr.finite_vertex_handles()))
|
||||
CGAL_assertion(!is_non_manifold(v));
|
||||
|
||||
clear(output_mesh);
|
||||
|
|
@ -754,26 +732,26 @@ public:
|
|||
std::unordered_map<Vertex_handle, std::size_t> vertex_to_id;
|
||||
std::size_t nv = 0;
|
||||
|
||||
for(auto fit=m_dt.finite_facets_begin(), fend=m_dt.finite_facets_end(); fit!=fend; ++fit)
|
||||
for(auto fit=m_tr.finite_facets_begin(), fend=m_tr.finite_facets_end(); fit!=fend; ++fit)
|
||||
{
|
||||
Facet f = *fit;
|
||||
if(!f.first->info().is_outside)
|
||||
f = m_dt.mirror_facet(f);
|
||||
if(!f.first->is_outside())
|
||||
f = m_tr.mirror_facet(f);
|
||||
|
||||
const Cell_handle c = f.first;
|
||||
const int s = f.second;
|
||||
const Cell_handle nh = c->neighbor(s);
|
||||
if(c->info().is_outside == nh->info().is_outside)
|
||||
if(c->is_outside() == nh->is_outside())
|
||||
continue;
|
||||
|
||||
std::array<std::size_t, 3> ids;
|
||||
for(int pos=0; pos<3; ++pos)
|
||||
{
|
||||
Vertex_handle vh = c->vertex(Dt::vertex_triple_index(s, pos));
|
||||
Vertex_handle vh = c->vertex(Triangulation::vertex_triple_index(s, pos));
|
||||
auto insertion_res = vertex_to_id.emplace(vh, nv);
|
||||
if(insertion_res.second) // successful insertion, never-seen-before vertex
|
||||
{
|
||||
points.push_back(m_dt.point(vh));
|
||||
points.push_back(m_tr.point(vh));
|
||||
++nv;
|
||||
}
|
||||
|
||||
|
|
@ -817,14 +795,14 @@ public:
|
|||
private:
|
||||
bool is_traversable(const Facet& f) const
|
||||
{
|
||||
return less_squared_radius_of_min_empty_sphere(m_sq_alpha, f, m_dt);
|
||||
return less_squared_radius_of_min_empty_sphere(m_sq_alpha, f, m_tr);
|
||||
}
|
||||
|
||||
bool compute_steiner_point(const Cell_handle ch,
|
||||
const Cell_handle neighbor,
|
||||
Point_3& steiner_point) const
|
||||
{
|
||||
CGAL_precondition(!m_dt.is_infinite(neighbor));
|
||||
CGAL_precondition(!m_tr.is_infinite(neighbor));
|
||||
|
||||
typename Geom_traits::Construct_ball_3 ball = geom_traits().construct_ball_3_object();
|
||||
typename Geom_traits::Construct_vector_3 vector = geom_traits().construct_vector_3_object();
|
||||
|
|
@ -920,7 +898,7 @@ private:
|
|||
// e.g. from DT3
|
||||
Facet_queue_status facet_status(const Facet& f) const
|
||||
{
|
||||
CGAL_precondition(!m_dt.is_infinite(f));
|
||||
CGAL_precondition(!m_tr.is_infinite(f));
|
||||
|
||||
#ifdef CGAL_AW3_DEBUG_FACET_STATUS
|
||||
std::cout << "facet status: "
|
||||
|
|
@ -933,10 +911,10 @@ private:
|
|||
const Cell_handle ch = f.first;
|
||||
const int id = f.second;
|
||||
const Cell_handle nh = ch->neighbor(id);
|
||||
if(m_dt.is_infinite(nh))
|
||||
if(m_tr.is_infinite(nh))
|
||||
return TRAVERSABLE;
|
||||
|
||||
if(nh->info().is_outside)
|
||||
if(nh->is_outside())
|
||||
{
|
||||
#ifdef CGAL_AW3_DEBUG_FACET_STATUS
|
||||
std::cout << "Neighbor already outside" << std::endl;
|
||||
|
|
@ -947,8 +925,9 @@ private:
|
|||
// push if facet is connected to artificial vertices
|
||||
for(int i=0; i<3; ++i)
|
||||
{
|
||||
const Vertex_handle vh = ch->vertex(Dt::vertex_triple_index(id, i));
|
||||
if(vh->info() == BBOX_VERTEX || vh->info() == SEED_VERTEX)
|
||||
const Vertex_handle vh = ch->vertex(Triangulation::vertex_triple_index(id, i));
|
||||
if(vh->type() == AW3i::Vertex_type:: BBOX_VERTEX ||
|
||||
vh->type() == AW3i::Vertex_type:: SEED_VERTEX)
|
||||
{
|
||||
#ifdef CGAL_AW3_DEBUG_FACET_STATUS
|
||||
std::cout << "artificial facet due to artificial vertex #" << i << std::endl;
|
||||
|
|
@ -974,7 +953,7 @@ private:
|
|||
|
||||
bool push_facet(const Facet& f)
|
||||
{
|
||||
CGAL_precondition(f.first->info().is_outside);
|
||||
CGAL_precondition(f.first->is_outside());
|
||||
|
||||
// skip if f is already in queue
|
||||
if(m_queue.contains_with_bounds_check(Gate(f)))
|
||||
|
|
@ -986,9 +965,9 @@ private:
|
|||
|
||||
const Cell_handle ch = f.first;
|
||||
const int id = f.second;
|
||||
const Point_3& p0 = m_dt.point(ch, (id+1)&3);
|
||||
const Point_3& p1 = m_dt.point(ch, (id+2)&3);
|
||||
const Point_3& p2 = m_dt.point(ch, (id+3)&3);
|
||||
const Point_3& p0 = m_tr.point(ch, (id+1)&3);
|
||||
const Point_3& p1 = m_tr.point(ch, (id+2)&3);
|
||||
const Point_3& p2 = m_tr.point(ch, (id+3)&3);
|
||||
|
||||
// @todo should prob be the real value we compare to alpha instead of squared_radius
|
||||
const FT sqr = geom_traits().compute_squared_radius_3_object()(p0, p1, p2);
|
||||
|
|
@ -1022,7 +1001,7 @@ private:
|
|||
m_offset = FT(offset);
|
||||
m_sq_offset = square(m_offset);
|
||||
|
||||
m_dt.clear();
|
||||
m_tr.clear();
|
||||
m_queue.clear();
|
||||
|
||||
insert_bbox_corners();
|
||||
|
|
@ -1052,7 +1031,7 @@ private:
|
|||
// const& to something that will be popped, but safe as `ch` && `id` are extracted before the pop
|
||||
const Gate& gate = m_queue.top();
|
||||
const Facet& f = gate.facet();
|
||||
CGAL_precondition(!m_dt.is_infinite(f));
|
||||
CGAL_precondition(!m_tr.is_infinite(f));
|
||||
|
||||
const Cell_handle ch = f.first;
|
||||
const int id = f.second;
|
||||
|
|
@ -1060,11 +1039,11 @@ private:
|
|||
|
||||
#ifdef CGAL_AW3_DEBUG_QUEUE
|
||||
static int fid = 0;
|
||||
std::cout << m_dt.number_of_vertices() << " DT vertices" << std::endl;
|
||||
std::cout << m_tr.number_of_vertices() << " DT vertices" << std::endl;
|
||||
std::cout << m_queue.size() << " facets in the queue" << std::endl;
|
||||
std::cout << "Face " << fid++ << "\n"
|
||||
<< "c = " << &*ch << " (" << m_dt.is_infinite(ch) << "), n = " << &*neighbor << " (" << m_dt.is_infinite(neighbor) << ")" << "\n"
|
||||
<< m_dt.point(ch, (id+1)&3) << "\n" << m_dt.point(ch, (id+2)&3) << "\n" << m_dt.point(ch, (id+3)&3) << std::endl;
|
||||
<< "c = " << &*ch << " (" << m_tr.is_infinite(ch) << "), n = " << &*neighbor << " (" << m_tr.is_infinite(neighbor) << ")" << "\n"
|
||||
<< m_tr.point(ch, (id+1)&3) << "\n" << m_tr.point(ch, (id+2)&3) << "\n" << m_tr.point(ch, (id+3)&3) << std::endl;
|
||||
std::cout << "Priority: " << gate.priority() << std::endl;
|
||||
#endif
|
||||
|
||||
|
|
@ -1080,13 +1059,13 @@ private:
|
|||
std::string face_name = "results/steps/face_" + std::to_string(static_cast<int>(i++)) + ".xyz";
|
||||
std::ofstream face_out(face_name);
|
||||
face_out.precision(17);
|
||||
face_out << "3\n" << m_dt.point(ch, (id+1)&3) << "\n" << m_dt.point(ch, (id+2)&3) << "\n" << m_dt.point(ch, (id+3)&3) << std::endl;
|
||||
face_out << "3\n" << m_tr.point(ch, (id+1)&3) << "\n" << m_tr.point(ch, (id+2)&3) << "\n" << m_tr.point(ch, (id+3)&3) << std::endl;
|
||||
face_out.close();
|
||||
#endif
|
||||
|
||||
if(m_dt.is_infinite(neighbor))
|
||||
if(m_tr.is_infinite(neighbor))
|
||||
{
|
||||
neighbor->info().is_outside = true;
|
||||
neighbor->is_outside() = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
|
|
@ -1100,14 +1079,16 @@ private:
|
|||
// locate cells that are going to be destroyed and remove their facet from the queue
|
||||
int li, lj = 0;
|
||||
Locate_type lt;
|
||||
const Cell_handle conflict_cell = m_dt.locate(steiner_point, lt, li, lj, neighbor);
|
||||
CGAL_assertion(lt != Dt::VERTEX);
|
||||
const Cell_handle conflict_cell = m_tr.locate(steiner_point, lt, li, lj, neighbor);
|
||||
CGAL_assertion(lt != Triangulation::VERTEX);
|
||||
|
||||
// Using small vectors like in Triangulation_3 does not bring any runtime improvement
|
||||
std::vector<Facet> boundary_facets;
|
||||
std::vector<Cell_handle> conflict_zone;
|
||||
boundary_facets.reserve(32);
|
||||
conflict_zone.reserve(32);
|
||||
m_dt.find_conflicts(steiner_point, conflict_cell,
|
||||
|
||||
m_tr.find_conflicts(steiner_point, conflict_cell,
|
||||
std::back_inserter(boundary_facets),
|
||||
std::back_inserter(conflict_zone));
|
||||
|
||||
|
|
@ -1125,7 +1106,7 @@ private:
|
|||
|
||||
for(const Facet& f : boundary_facets)
|
||||
{
|
||||
const Facet mf = m_dt.mirror_facet(f); // boundary facets have incident cells in the CZ
|
||||
const Facet mf = m_tr.mirror_facet(f); // boundary facets have incident cells in the CZ
|
||||
if(m_queue.contains_with_bounds_check(Gate(mf)))
|
||||
m_queue.erase(Gate(mf));
|
||||
}
|
||||
|
|
@ -1133,18 +1114,20 @@ private:
|
|||
visitor.before_Steiner_point_insertion(*this, steiner_point);
|
||||
|
||||
// Actual insertion of the Steiner point
|
||||
Vertex_handle vh = m_dt.insert(steiner_point, lt, conflict_cell, li, lj);
|
||||
vh->info() = DEFAULT;
|
||||
// We could use TDS functions to avoid recomputing the conflict zone, but in practice
|
||||
// it does not bring any runtime improvements
|
||||
Vertex_handle vh = m_tr.insert(steiner_point, lt, conflict_cell, li, lj);
|
||||
vh->type() = AW3i::Vertex_type:: DEFAULT;
|
||||
|
||||
visitor.after_Steiner_point_insertion(*this, vh);
|
||||
|
||||
std::vector<Cell_handle> new_cells;
|
||||
new_cells.reserve(32);
|
||||
m_dt.incident_cells(vh, std::back_inserter(new_cells));
|
||||
m_tr.incident_cells(vh, std::back_inserter(new_cells));
|
||||
for(const Cell_handle& ch : new_cells)
|
||||
{
|
||||
// std::cout << "new cell has time stamp " << ch->time_stamp() << std::endl;
|
||||
ch->info().is_outside = m_dt.is_infinite(ch);
|
||||
ch->is_outside() = m_tr.is_infinite(ch);
|
||||
}
|
||||
|
||||
// Push all new boundary facets to the queue.
|
||||
|
|
@ -1156,25 +1139,25 @@ private:
|
|||
{
|
||||
for(int i=0; i<4; ++i)
|
||||
{
|
||||
if(m_dt.is_infinite(ch, i))
|
||||
if(m_tr.is_infinite(ch, i))
|
||||
continue;
|
||||
|
||||
const Cell_handle nh = ch->neighbor(i);
|
||||
if(nh->info().is_outside == ch->info().is_outside) // not on the boundary
|
||||
if(nh->is_outside() == ch->is_outside()) // not on the boundary
|
||||
continue;
|
||||
|
||||
const Facet boundary_f = std::make_pair(ch, i);
|
||||
if(ch->info().is_outside)
|
||||
if(ch->is_outside())
|
||||
push_facet(boundary_f);
|
||||
else
|
||||
push_facet(m_dt.mirror_facet(boundary_f));
|
||||
push_facet(m_tr.mirror_facet(boundary_f));
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// tag neighbor as OUTSIDE
|
||||
neighbor->info().is_outside = true;
|
||||
neighbor->is_outside() = true;
|
||||
|
||||
// for each finite facet of neighbor, push it to the queue
|
||||
for(int i=0; i<4; ++i)
|
||||
|
|
@ -1188,10 +1171,10 @@ private:
|
|||
visitor.on_flood_fill_end(*this);
|
||||
|
||||
// Check that no useful facet has been ignored
|
||||
CGAL_postcondition_code(for(auto fit=m_dt.finite_facets_begin(), fend=m_dt.finite_facets_end(); fit!=fend; ++fit) {)
|
||||
CGAL_postcondition_code( if(fit->first->info().is_outside == fit->first->neighbor(fit->second)->info().is_outside) continue;)
|
||||
CGAL_postcondition_code(for(auto fit=m_tr.finite_facets_begin(), fend=m_tr.finite_facets_end(); fit!=fend; ++fit) {)
|
||||
CGAL_postcondition_code( if(fit->first->is_outside() == fit->first->neighbor(fit->second)->is_outside()) continue;)
|
||||
CGAL_postcondition_code( Facet f = *fit;)
|
||||
CGAL_postcondition_code( if(!fit->first->info().is_outside) f = m_dt.mirror_facet(f);)
|
||||
CGAL_postcondition_code( if(!fit->first->is_outside()) f = m_tr.mirror_facet(f);)
|
||||
CGAL_postcondition( facet_status(f) == IRRELEVANT);
|
||||
CGAL_postcondition_code(})
|
||||
}
|
||||
|
|
@ -1199,13 +1182,13 @@ private:
|
|||
private:
|
||||
bool is_non_manifold(Vertex_handle v) const
|
||||
{
|
||||
CGAL_precondition(!m_dt.is_infinite(v));
|
||||
CGAL_precondition(!m_tr.is_infinite(v));
|
||||
|
||||
bool is_non_manifold = false;
|
||||
|
||||
std::vector<Cell_handle> inc_cells;
|
||||
inc_cells.reserve(64);
|
||||
m_dt.incident_cells(v, std::back_inserter(inc_cells));
|
||||
m_tr.incident_cells(v, std::back_inserter(inc_cells));
|
||||
|
||||
// Flood one inside and outside CC.
|
||||
// Process both an inside and an outside CC to also detect edge pinching.
|
||||
|
|
@ -1218,7 +1201,7 @@ private:
|
|||
for(Cell_handle ic : inc_cells)
|
||||
{
|
||||
ic->tds_data().clear();
|
||||
if(ic->info().is_outside)
|
||||
if(ic->is_outside())
|
||||
outside_start = ic;
|
||||
else if(inside_start == Cell_handle())
|
||||
inside_start = ic;
|
||||
|
|
@ -1253,7 +1236,7 @@ private:
|
|||
CGAL_assertion(neigh_c->has_vertex(v));
|
||||
|
||||
if(neigh_c->tds_data().processed() ||
|
||||
neigh_c->info().is_outside != curr_c->info().is_outside) // do not cross the boundary
|
||||
neigh_c->is_outside() != curr_c->is_outside()) // do not cross the boundary
|
||||
continue;
|
||||
|
||||
cells_to_visit.push(neigh_c);
|
||||
|
|
@ -1278,7 +1261,7 @@ private:
|
|||
|
||||
bool is_non_manifold(Cell_handle c) const
|
||||
{
|
||||
CGAL_precondition(!m_dt.is_infinite(c));
|
||||
CGAL_precondition(!m_tr.is_infinite(c));
|
||||
|
||||
for(int i=0; i<4; ++i)
|
||||
{
|
||||
|
|
@ -1294,7 +1277,7 @@ private:
|
|||
{
|
||||
// Not the best complexity, but it's not important: this function is purely for information
|
||||
// Better complexity --> see PMP::non_manifold_vertices + throw
|
||||
for(const Vertex_handle v : m_dt.finite_vertex_handles())
|
||||
for(const Vertex_handle v : m_tr.finite_vertex_handles())
|
||||
if(is_non_manifold(v))
|
||||
return true;
|
||||
|
||||
|
|
@ -1307,18 +1290,18 @@ private:
|
|||
bool remove_bbox_vertices()
|
||||
{
|
||||
bool do_remove = true;
|
||||
auto vit = m_dt.finite_vertices_begin();
|
||||
auto vit = m_tr.finite_vertices_begin();
|
||||
for(std::size_t i=0; i<8; ++i)
|
||||
{
|
||||
Vertex_handle v = vit++;
|
||||
|
||||
std::vector<Cell_handle> inc_cells;
|
||||
inc_cells.reserve(64);
|
||||
m_dt.finite_incident_cells(v, std::back_inserter(inc_cells));
|
||||
m_tr.finite_incident_cells(v, std::back_inserter(inc_cells));
|
||||
|
||||
for(Cell_handle c : inc_cells)
|
||||
{
|
||||
if(!c->info().is_outside)
|
||||
if(!c->is_outside())
|
||||
{
|
||||
do_remove = false;
|
||||
break;
|
||||
|
|
@ -1333,11 +1316,11 @@ private:
|
|||
if(!do_remove)
|
||||
return false;
|
||||
|
||||
vit = m_dt.finite_vertices_begin();
|
||||
vit = m_tr.finite_vertices_begin();
|
||||
for(std::size_t i=0; i<8; ++i)
|
||||
{
|
||||
Vertex_handle v = vit++;
|
||||
m_dt.remove(v);
|
||||
m_tr.remove(v);
|
||||
}
|
||||
|
||||
return true;
|
||||
|
|
@ -1355,7 +1338,7 @@ public:
|
|||
// remove_bbox_vertices();
|
||||
|
||||
std::stack<Vertex_handle> non_manifold_vertices; // @todo sort somehow?
|
||||
for(Vertex_handle v : m_dt.finite_vertex_handles())
|
||||
for(Vertex_handle v : m_tr.finite_vertex_handles())
|
||||
{
|
||||
if(is_non_manifold(v))
|
||||
non_manifold_vertices.push(v);
|
||||
|
|
@ -1365,15 +1348,20 @@ public:
|
|||
auto has_artificial_vertex = [](Cell_handle c) -> bool
|
||||
{
|
||||
for(int i=0; i<4; ++i)
|
||||
if(c->vertex(i)->info() == BBOX_VERTEX || c->vertex(i)->info() == SEED_VERTEX)
|
||||
{
|
||||
if(c->vertex(i)->type() == AW3i::Vertex_type:: BBOX_VERTEX ||
|
||||
c->vertex(i)->type() == AW3i::Vertex_type:: SEED_VERTEX)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
};
|
||||
|
||||
auto is_on_boundary = [](Cell_handle c, int i) -> bool
|
||||
{
|
||||
return (c->info().is_outside != c->neighbor(i)->info().is_outside);
|
||||
return (c->is_outside() != c->neighbor(i)->is_outside());
|
||||
};
|
||||
|
||||
auto count_boundary_facets = [&](Cell_handle c, Vertex_handle v) -> int
|
||||
|
|
@ -1395,17 +1383,17 @@ public:
|
|||
// auto sq_circumradius = [&](Cell_handle c) -> FT
|
||||
// {
|
||||
// const Point_3& cc = circumcenter(c);
|
||||
// return geom_traits().compute_squared_distance_3_object()(m_dt.point(c, 0), cc);
|
||||
// return geom_traits().compute_squared_distance_3_object()(m_tr.point(c, 0), cc);
|
||||
// };
|
||||
|
||||
auto sq_longest_edge = [&](Cell_handle c) -> FT
|
||||
{
|
||||
return (std::max)({ squared_distance(m_dt.point(c, 0), m_dt.point(c, 1)),
|
||||
squared_distance(m_dt.point(c, 0), m_dt.point(c, 2)),
|
||||
squared_distance(m_dt.point(c, 0), m_dt.point(c, 3)),
|
||||
squared_distance(m_dt.point(c, 1), m_dt.point(c, 2)),
|
||||
squared_distance(m_dt.point(c, 3), m_dt.point(c, 3)),
|
||||
squared_distance(m_dt.point(c, 2), m_dt.point(c, 3)) });
|
||||
return (std::max)({ squared_distance(m_tr.point(c, 0), m_tr.point(c, 1)),
|
||||
squared_distance(m_tr.point(c, 0), m_tr.point(c, 2)),
|
||||
squared_distance(m_tr.point(c, 0), m_tr.point(c, 3)),
|
||||
squared_distance(m_tr.point(c, 1), m_tr.point(c, 2)),
|
||||
squared_distance(m_tr.point(c, 3), m_tr.point(c, 3)),
|
||||
squared_distance(m_tr.point(c, 2), m_tr.point(c, 3)) });
|
||||
};
|
||||
|
||||
#ifdef CGAL_AW3_DEBUG_MANIFOLDNESS
|
||||
|
|
@ -1450,7 +1438,7 @@ public:
|
|||
|
||||
std::vector<Cell_handle> inc_cells;
|
||||
inc_cells.reserve(64);
|
||||
m_dt.finite_incident_cells(v, std::back_inserter(inc_cells));
|
||||
m_tr.finite_incident_cells(v, std::back_inserter(inc_cells));
|
||||
|
||||
#define CGAL_AW3_USE_BRUTE_FORCE_MUTABLE_PRIORITY_QUEUE
|
||||
#ifndef CGAL_AW3_USE_BRUTE_FORCE_MUTABLE_PRIORITY_QUEUE
|
||||
|
|
@ -1464,10 +1452,10 @@ public:
|
|||
std::sort(cit, cend, comparer);
|
||||
#endif
|
||||
Cell_handle ic = *cit;
|
||||
CGAL_assertion(!m_dt.is_infinite(ic));
|
||||
CGAL_assertion(!m_tr.is_infinite(ic));
|
||||
|
||||
// This is where new material is added
|
||||
ic->info().is_outside = false;
|
||||
ic->is_outside() = false;
|
||||
|
||||
#ifdef CGAL_AW3_DEBUG_DUMP_EVERY_STEP
|
||||
static int i = 0;
|
||||
|
|
@ -1484,14 +1472,14 @@ public:
|
|||
|
||||
std::vector<Vertex_handle> adj_vertices;
|
||||
adj_vertices.reserve(64);
|
||||
m_dt.finite_adjacent_vertices(v, std::back_inserter(adj_vertices));
|
||||
m_tr.finite_adjacent_vertices(v, std::back_inserter(adj_vertices));
|
||||
|
||||
for(Vertex_handle nv : adj_vertices)
|
||||
if(is_non_manifold(nv))
|
||||
non_manifold_vertices.push(nv);
|
||||
}
|
||||
|
||||
CGAL_assertion_code(for(Vertex_handle v : m_dt.finite_vertex_handles()))
|
||||
CGAL_assertion_code(for(Vertex_handle v : m_tr.finite_vertex_handles()))
|
||||
CGAL_assertion(!is_non_manifold(v));
|
||||
}
|
||||
|
||||
|
|
@ -1508,12 +1496,12 @@ private:
|
|||
const Facet& current_f = current_gate.facet();
|
||||
const Cell_handle ch = current_f.first;
|
||||
const int id = current_f.second;
|
||||
const Point_3& p0 = m_dt.point(ch, (id+1)&3);
|
||||
const Point_3& p1 = m_dt.point(ch, (id+2)&3);
|
||||
const Point_3& p2 = m_dt.point(ch, (id+3)&3);
|
||||
const Point_3& p0 = m_tr.point(ch, (id+1)&3);
|
||||
const Point_3& p1 = m_tr.point(ch, (id+2)&3);
|
||||
const Point_3& p2 = m_tr.point(ch, (id+3)&3);
|
||||
const FT sqr = geom_traits().compute_squared_radius_3_object()(p0, p1, p2);
|
||||
|
||||
std::cout << "At Facet with VID " << get(Gate_ID_PM<Dt>(), current_gate) << std::endl;
|
||||
std::cout << "At Facet with VID " << get(Gate_ID_PM<Triangulation>(), current_gate) << std::endl;
|
||||
|
||||
if(current_gate.priority() != sqr)
|
||||
std::cerr << "Error: facet in queue has wrong priority" << std::endl;
|
||||
|
|
@ -1546,13 +1534,13 @@ private:
|
|||
std::size_t nv = 0;
|
||||
std::size_t nf = 0;
|
||||
|
||||
for(auto fit=m_dt.finite_facets_begin(), fend=m_dt.finite_facets_end(); fit!=fend; ++fit)
|
||||
for(auto fit=m_tr.finite_facets_begin(), fend=m_tr.finite_facets_end(); fit!=fend; ++fit)
|
||||
{
|
||||
Cell_handle c = fit->first;
|
||||
int s = fit->second;
|
||||
|
||||
Cell_handle nc = c->neighbor(s);
|
||||
if(only_boundary_faces && (c->info().is_outside == nc->info().is_outside))
|
||||
if(only_boundary_faces && (c->is_outside() == nc->is_outside()))
|
||||
continue;
|
||||
|
||||
std::array<std::size_t, 3> ids;
|
||||
|
|
@ -1562,7 +1550,7 @@ private:
|
|||
auto insertion_res = vertex_to_id.emplace(v, nv);
|
||||
if(insertion_res.second)
|
||||
{
|
||||
vertices_ss << m_dt.point(v) << "\n";
|
||||
vertices_ss << m_tr.point(v) << "\n";
|
||||
++nv;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -36,24 +36,24 @@ struct Tetrahedron_with_outside_info
|
|||
using Triangle_3 = typename Kernel::Triangle_3;
|
||||
|
||||
template <typename CellHandle>
|
||||
Tetrahedron_with_outside_info(const CellHandle ch, const K& k)
|
||||
Tetrahedron_with_outside_info(const CellHandle c, const K& k)
|
||||
{
|
||||
typename K::Construct_bbox_3 bbox = k.construct_bbox_3_object();
|
||||
typename K::Construct_tetrahedron_3 tetrahedron = k.construct_tetrahedron_3_object();
|
||||
typename K::Construct_triangle_3 triangle = k.construct_triangle_3_object();
|
||||
|
||||
m_tet = tetrahedron(ch->vertex(0)->point(), ch->vertex(1)->point(),
|
||||
ch->vertex(2)->point(), ch->vertex(3)->point());
|
||||
m_tet = tetrahedron(c->vertex(0)->point(), c->vertex(1)->point(),
|
||||
c->vertex(2)->point(), c->vertex(3)->point());
|
||||
m_bbox = bbox(m_tet);
|
||||
|
||||
for(int i=0; i<4; ++i)
|
||||
{
|
||||
if(ch->neighbor(i)->info().is_outside)
|
||||
if(c->neighbor(i)->is_outside())
|
||||
m_b.set(i, true);
|
||||
|
||||
m_triangles[i] = triangle(ch->vertex((i+1)& 3)->point(),
|
||||
ch->vertex((i+2)& 3)->point(),
|
||||
ch->vertex((i+3)& 3)->point());
|
||||
m_triangles[i] = triangle(c->vertex((i+1)& 3)->point(),
|
||||
c->vertex((i+2)& 3)->point(),
|
||||
c->vertex((i+3)& 3)->point());
|
||||
m_tbox[i] = bbox(m_triangles[i]);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,97 @@
|
|||
// Copyright (c) 2019-2023 Google LLC (USA).
|
||||
// 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) : Mael Rouxel-Labbé
|
||||
|
||||
#ifndef CGAL_ALPHA_WRAP_TRIANGULATION_CELL_BASE_3_H
|
||||
#define CGAL_ALPHA_WRAP_TRIANGULATION_CELL_BASE_3_H
|
||||
|
||||
#include <CGAL/license/Alpha_wrap_3.h>
|
||||
|
||||
#include <CGAL/Delaunay_triangulation_cell_base_with_circumcenter_3.h>
|
||||
|
||||
namespace CGAL {
|
||||
namespace Alpha_wraps_3 {
|
||||
namespace internal {
|
||||
|
||||
template < typename GT,
|
||||
typename Cb = CGAL::Delaunay_triangulation_cell_base_with_circumcenter_3<GT> >
|
||||
class Alpha_wrap_triangulation_cell_base_3
|
||||
: public Cb
|
||||
{
|
||||
private:
|
||||
bool outside = false;
|
||||
|
||||
public:
|
||||
typedef typename Cb::Vertex_handle Vertex_handle;
|
||||
typedef typename Cb::Cell_handle Cell_handle;
|
||||
|
||||
template < typename TDS2 >
|
||||
struct Rebind_TDS
|
||||
{
|
||||
using Cb2 = typename Cb::template Rebind_TDS<TDS2>::Other;
|
||||
using Other = Alpha_wrap_triangulation_cell_base_3<GT, Cb2>;
|
||||
};
|
||||
|
||||
Alpha_wrap_triangulation_cell_base_3()
|
||||
: Cb()
|
||||
{}
|
||||
|
||||
Alpha_wrap_triangulation_cell_base_3(Vertex_handle v0, Vertex_handle v1,
|
||||
Vertex_handle v2, Vertex_handle v3)
|
||||
: Cb(v0, v1, v2, v3)
|
||||
{}
|
||||
|
||||
Alpha_wrap_triangulation_cell_base_3(Vertex_handle v0, Vertex_handle v1,
|
||||
Vertex_handle v2, Vertex_handle v3,
|
||||
Cell_handle n0, Cell_handle n1,
|
||||
Cell_handle n2, Cell_handle n3)
|
||||
: Cb(v0, v1, v2, v3, n0, n1, n2, n3)
|
||||
{}
|
||||
|
||||
bool is_outside() const { return outside; }
|
||||
bool& is_outside() { return outside; }
|
||||
};
|
||||
|
||||
template <typename Cb>
|
||||
class Cell_base_with_timestamp
|
||||
: public Cb
|
||||
{
|
||||
std::size_t time_stamp_;
|
||||
|
||||
public:
|
||||
using Has_timestamp = CGAL::Tag_true;
|
||||
|
||||
template <class TDS>
|
||||
struct Rebind_TDS
|
||||
{
|
||||
using Cb2 = typename Cb::template Rebind_TDS<TDS>::Other;
|
||||
using Other = Cell_base_with_timestamp<Cb2>;
|
||||
};
|
||||
|
||||
public:
|
||||
template <typename... Args>
|
||||
Cell_base_with_timestamp(const Args&... args)
|
||||
: Cb(args...), time_stamp_(-1)
|
||||
{ }
|
||||
|
||||
Cell_base_with_timestamp(const Cell_base_with_timestamp& other)
|
||||
: Cb(other), time_stamp_(other.time_stamp_)
|
||||
{ }
|
||||
|
||||
public:
|
||||
std::size_t time_stamp() const { return time_stamp_; }
|
||||
void set_time_stamp(const std::size_t& ts) { time_stamp_ = ts; }
|
||||
};
|
||||
|
||||
} // namespace internal
|
||||
} // namespace Alpha_wraps_3
|
||||
} // namespace CGAL
|
||||
|
||||
#endif // CGAL_ALPHA_WRAP_TRIANGULATION_CELL_BASE_3_H
|
||||
|
|
@ -0,0 +1,71 @@
|
|||
// Copyright (c) 2019-2023 Google LLC (USA).
|
||||
// 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) : Mael Rouxel-Labbé
|
||||
|
||||
#ifndef CGAL_ALPHA_WRAP_TRIANGULATION_VERTEX_BASE_3_H
|
||||
#define CGAL_ALPHA_WRAP_TRIANGULATION_VERTEX_BASE_3_H
|
||||
|
||||
#include <CGAL/license/Alpha_wrap_3.h>
|
||||
|
||||
#include <CGAL/Triangulation_vertex_base_3.h>
|
||||
|
||||
namespace CGAL {
|
||||
namespace Alpha_wraps_3 {
|
||||
namespace internal {
|
||||
|
||||
enum class Vertex_type
|
||||
{
|
||||
DEFAULT = 0,
|
||||
BBOX_VERTEX,
|
||||
SEED_VERTEX
|
||||
};
|
||||
|
||||
template <typename GT,
|
||||
typename Vb = Triangulation_vertex_base_3<GT> >
|
||||
class Alpha_wrap_triangulation_vertex_base_3
|
||||
: public Vb
|
||||
{
|
||||
private:
|
||||
Vertex_type vertex_type = Vertex_type::DEFAULT;
|
||||
|
||||
public:
|
||||
using Cell_handle = typename Vb::Cell_handle;
|
||||
using Point = typename Vb::Point;
|
||||
|
||||
template <typename TDS2>
|
||||
struct Rebind_TDS
|
||||
{
|
||||
using Vb2 = typename Vb::template Rebind_TDS<TDS2>::Other;
|
||||
using Other = Alpha_wrap_triangulation_vertex_base_3<GT, Vb2>;
|
||||
};
|
||||
|
||||
public:
|
||||
Alpha_wrap_triangulation_vertex_base_3()
|
||||
: Vb() {}
|
||||
|
||||
Alpha_wrap_triangulation_vertex_base_3(const Point& p)
|
||||
: Vb(p) {}
|
||||
|
||||
Alpha_wrap_triangulation_vertex_base_3(const Point& p, Cell_handle c)
|
||||
: Vb(p, c) {}
|
||||
|
||||
Alpha_wrap_triangulation_vertex_base_3(Cell_handle c)
|
||||
: Vb(c) {}
|
||||
|
||||
public:
|
||||
const Vertex_type& type() const { return vertex_type; }
|
||||
Vertex_type& type() { return vertex_type; }
|
||||
};
|
||||
|
||||
} // namespace internal
|
||||
} // namespace Alpha_wraps_3
|
||||
} // namespace CGAL
|
||||
|
||||
#endif // CGAL_ALPHA_WRAP_TRIANGULATION_VERTEX_BASE_3_H
|
||||
File diff suppressed because it is too large
Load Diff
|
|
@ -28,8 +28,7 @@ namespace CGAL {
|
|||
//
|
||||
template <typename Arrangement, typename ZoneVisitor>
|
||||
void Arrangement_zone_2<Arrangement, ZoneVisitor>::
|
||||
init_with_hint(const X_monotone_curve_2& cv, Pl_result_type obj)
|
||||
{
|
||||
init_with_hint(const X_monotone_curve_2& cv, Pl_result_type obj) {
|
||||
#if defined(ARR_ZONE_VERBOSE)
|
||||
std::cout << "init_with_hint()" << std::endl;
|
||||
#endif
|
||||
|
|
@ -80,8 +79,7 @@ init_with_hint(const X_monotone_curve_2& cv, Pl_result_type obj)
|
|||
// notifications for the visitor.
|
||||
//
|
||||
template <typename Arrangement, typename ZoneVisitor>
|
||||
void Arrangement_zone_2<Arrangement, ZoneVisitor>::compute_zone()
|
||||
{
|
||||
void Arrangement_zone_2<Arrangement, ZoneVisitor>::compute_zone() {
|
||||
#if defined(ARR_ZONE_VERBOSE)
|
||||
std::cout << "compute_zone()" << std::endl;
|
||||
#endif
|
||||
|
|
@ -137,7 +135,7 @@ void Arrangement_zone_2<Arrangement, ZoneVisitor>::compute_zone()
|
|||
if (m_found_overlap) {
|
||||
// In this case m_cv overlaps the curve associated with m_intersect_he.
|
||||
// Compute the overlapping subcurve.
|
||||
bool dummy;
|
||||
Arr_parameter_space dummy;
|
||||
auto obj = _compute_next_intersection(m_intersect_he, false, dummy);
|
||||
m_overlap_cv = std::get<X_monotone_curve_2>(*obj);
|
||||
|
||||
|
|
@ -153,7 +151,7 @@ void Arrangement_zone_2<Arrangement, ZoneVisitor>::compute_zone()
|
|||
// overlaps the curve associated with this edge.
|
||||
m_intersect_he = m_arr.non_const_handle(*hh);
|
||||
|
||||
bool dummy;
|
||||
Arr_parameter_space dummy;
|
||||
auto obj = _compute_next_intersection(m_intersect_he, false, dummy);
|
||||
m_overlap_cv = std::get<X_monotone_curve_2>(*obj);
|
||||
|
||||
|
|
@ -211,7 +209,7 @@ void Arrangement_zone_2<Arrangement, ZoneVisitor>::compute_zone()
|
|||
if (m_found_overlap) {
|
||||
// In this case m_cv overlaps the curve associated with m_intersect_he.
|
||||
// Compute the overlapping subcurve to the right of curr_v.
|
||||
bool dummy;
|
||||
Arr_parameter_space dummy;
|
||||
auto obj = _compute_next_intersection(m_intersect_he, false, dummy);
|
||||
m_overlap_cv = std::get<X_monotone_curve_2>(*obj);
|
||||
|
||||
|
|
@ -253,8 +251,7 @@ template <typename Arrangement, typename ZoneVisitor>
|
|||
bool Arrangement_zone_2<Arrangement, ZoneVisitor>::
|
||||
do_overlap_impl(const X_monotone_curve_2& cv1,
|
||||
const X_monotone_curve_2& cv2,
|
||||
const Point_2& p, Arr_not_all_sides_oblivious_tag) const
|
||||
{
|
||||
const Point_2& p, Arr_not_all_sides_oblivious_tag) const {
|
||||
typename Traits_adaptor_2::Compare_y_at_x_right_2 cmp_right =
|
||||
m_geom_traits->compare_y_at_x_right_2_object();
|
||||
|
||||
|
|
@ -307,8 +304,7 @@ do_overlap_impl(const X_monotone_curve_2& cv1,
|
|||
//
|
||||
template <typename Arrangement, typename ZoneVisitor>
|
||||
bool Arrangement_zone_2<Arrangement, ZoneVisitor>::
|
||||
_find_prev_around_vertex(Vertex_handle v, Halfedge_handle& he)
|
||||
{
|
||||
_find_prev_around_vertex(Vertex_handle v, Halfedge_handle& he) {
|
||||
#if defined(ARR_ZONE_VERBOSE)
|
||||
std::cout << "_find_prev_around_vertex(" << v->point() << ")" << std::endl;
|
||||
#endif
|
||||
|
|
@ -393,8 +389,7 @@ typename Arrangement_zone_2<Arrangement, ZoneVisitor>::Halfedge_handle
|
|||
Arrangement_zone_2<Arrangement, ZoneVisitor>::
|
||||
_direct_intersecting_edge_to_right(const X_monotone_curve_2& cv_ins,
|
||||
const Point_2& cv_left_pt,
|
||||
Halfedge_handle query_he)
|
||||
{
|
||||
Halfedge_handle query_he) {
|
||||
#if defined(ARR_ZONE_VERBOSE)
|
||||
std::cout << "_direct_intersecting_edge_to_right() " << cv_left_pt
|
||||
<< std::endl;
|
||||
|
|
@ -446,8 +441,7 @@ template <typename Arrangement, typename ZoneVisitor>
|
|||
typename Arrangement_zone_2<Arrangement, ZoneVisitor>::Halfedge_handle
|
||||
Arrangement_zone_2<Arrangement, ZoneVisitor>::
|
||||
_direct_intersecting_edge_to_left(const X_monotone_curve_2& cv_ins,
|
||||
Halfedge_handle query_he)
|
||||
{
|
||||
Halfedge_handle query_he) {
|
||||
#if defined(ARR_ZONE_VERBOSE)
|
||||
std::cout << "_direct_intersecting_edge_to_left()" << std::endl;
|
||||
#endif
|
||||
|
|
@ -505,6 +499,74 @@ _direct_intersecting_edge_to_left(const X_monotone_curve_2& cv_ins,
|
|||
}
|
||||
}
|
||||
|
||||
//! Implementation for no boundary conditions.
|
||||
template <typename Arrangement, typename ZoneVisitor>
|
||||
bool Arrangement_zone_2<Arrangement, ZoneVisitor>::
|
||||
is_intersection_valid_impl(const Point_2& ip,
|
||||
Arr_parameter_space& /* intersection_location */,
|
||||
Arr_all_sides_oblivious_tag) const
|
||||
{ return (m_geom_traits->compare_xy_2_object()(ip, m_left_pt) == LARGER); }
|
||||
|
||||
//! Implementation for left and right identified boundaries.
|
||||
template <typename Arrangement, typename ZoneVisitor>
|
||||
bool Arrangement_zone_2<Arrangement, ZoneVisitor>::
|
||||
is_intersection_valid_impl(const Point_2& ip,
|
||||
Arr_parameter_space& intersection_location,
|
||||
Arr_has_identified_side_tag) const {
|
||||
auto equal = m_geom_traits->equal_2_object();
|
||||
auto is_on_y_ident = m_geom_traits->is_on_y_identification_2_object();
|
||||
// Case 1: the curve lies on the y-identification
|
||||
if (is_on_y_ident(m_cv)) {
|
||||
if (equal(ip, m_left_pt)) return false;
|
||||
// We set the location to be on the left as a convention
|
||||
intersection_location = ARR_LEFT_BOUNDARY;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Case 2: The left-end lies on the left boundary
|
||||
// (It cannot lie on the right boundary)
|
||||
// If the intersection point is not equal to the left-end, it must lie to
|
||||
// its right; thus valid.
|
||||
if (m_left_on_boundary) return ! equal(ip, m_left_pt);
|
||||
|
||||
// Case 3: The right-end lies on the right boundary
|
||||
if (m_right_on_boundary && equal(ip, m_right_pt)) {
|
||||
intersection_location = ARR_RIGHT_BOUNDARY;
|
||||
return true;
|
||||
}
|
||||
|
||||
// We have a simple intersection point;
|
||||
// make sure it lies to the right of m_left_pt.
|
||||
return (m_geom_traits->compare_xy_2_object()(ip, m_left_pt) == LARGER);
|
||||
}
|
||||
|
||||
/*! Implementation for all the rest.
|
||||
* It would be better to split into the various cases, which is the cartesian
|
||||
* product of (contructed, closed, open) X (contructed, closed, open)
|
||||
*/
|
||||
template <typename Arrangement, typename ZoneVisitor>
|
||||
bool Arrangement_zone_2<Arrangement, ZoneVisitor>::
|
||||
is_intersection_valid_impl(const Point_2& ip,
|
||||
Arr_parameter_space& intersection_location,
|
||||
Arr_boundary_cond_tag) const {
|
||||
auto equal = m_geom_traits->equal_2_object();
|
||||
if (m_left_on_boundary) {
|
||||
// The left-end lies on the left boundary. If the intersection point is not
|
||||
// equal to the left-end, the intersection is valid, because it must lie to
|
||||
// its right.
|
||||
if (m_has_left_pt) return ! equal(ip, m_left_pt);
|
||||
else return true;
|
||||
}
|
||||
if (m_has_right_pt && m_right_on_boundary && equal(ip, m_right_pt)) {
|
||||
intersection_location = ARR_RIGHT_BOUNDARY;
|
||||
return true;
|
||||
}
|
||||
|
||||
// We have a simple intersection point;
|
||||
// make sure it lies to the right of m_left_pt.
|
||||
return (m_geom_traits->compare_xy_2_object()(ip, m_left_pt) == LARGER);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Get the next intersection of cv with the given halfedge.
|
||||
//
|
||||
|
|
@ -513,14 +575,12 @@ typename Arrangement_zone_2<Arrangement, ZoneVisitor>::Optional_intersection
|
|||
Arrangement_zone_2<Arrangement, ZoneVisitor>::
|
||||
_compute_next_intersection(Halfedge_handle he,
|
||||
bool skip_first_point,
|
||||
bool& intersection_on_right_boundary)
|
||||
{
|
||||
Arr_parameter_space& intersection_location) {
|
||||
#if defined(ARR_ZONE_VERBOSE)
|
||||
std::cout << "_compute_next_intersection(" << he->curve() << ", "
|
||||
<< skip_first_point << ")" << std::endl;
|
||||
#endif
|
||||
|
||||
auto equal = m_geom_traits->equal_2_object();
|
||||
auto compare_xy = m_geom_traits->compare_xy_2_object();
|
||||
auto ctr_min = m_geom_traits->construct_min_vertex_2_object();
|
||||
auto is_closed = m_geom_traits->is_closed_2_object();
|
||||
|
|
@ -529,12 +589,12 @@ _compute_next_intersection(Halfedge_handle he,
|
|||
const X_monotone_curve_2* p_curve = &(he->curve());
|
||||
|
||||
// Try to locate the intersections with this curve in the intersections map.
|
||||
Intersect_map_iterator iter = m_inter_map.find(p_curve);
|
||||
auto iter = m_inter_map.find(p_curve);
|
||||
const Intersection_point* ip;
|
||||
const X_monotone_curve_2* icv;
|
||||
bool valid_intersection;
|
||||
|
||||
intersection_on_right_boundary = false;
|
||||
intersection_location = ARR_INTERIOR;
|
||||
if (iter != m_inter_map.end()) {
|
||||
// The intersections with the curve have already been computed.
|
||||
// Retrieve the intersections list from the map.
|
||||
|
|
@ -548,25 +608,9 @@ _compute_next_intersection(Halfedge_handle he,
|
|||
// Compare that current object with m_left_pt (if exists).
|
||||
ip = std::get_if<Intersection_point>(&(inter_list.front()));
|
||||
if (ip != nullptr) {
|
||||
// We have an intersection point
|
||||
if (m_left_on_boundary) {
|
||||
// The left-end lies on the left boundary. If the intersection point
|
||||
// is not equal to the left-end, the intersection is valid, because
|
||||
// it must lie to its right.
|
||||
if (m_has_left_pt) valid_intersection = ! equal(ip->first, m_left_pt);
|
||||
else valid_intersection = true;
|
||||
}
|
||||
else if (m_has_right_pt && m_right_on_boundary &&
|
||||
equal(ip->first, m_right_pt))
|
||||
{
|
||||
valid_intersection = true;
|
||||
intersection_on_right_boundary = true;
|
||||
}
|
||||
else {
|
||||
// We have a simple intersection point - make sure it lies to the
|
||||
// right of m_left_pt.
|
||||
valid_intersection = (compare_xy(ip->first, m_left_pt) == LARGER);
|
||||
}
|
||||
// We have an intersection point -
|
||||
valid_intersection =
|
||||
is_intersection_valid(ip->first, intersection_location);
|
||||
}
|
||||
else {
|
||||
// We have an overlapping subcurve.
|
||||
|
|
@ -576,7 +620,8 @@ _compute_next_intersection(Halfedge_handle he,
|
|||
if (is_closed(*icv, ARR_MIN_END)) {
|
||||
// The curve has a valid left point - make sure it lies to the
|
||||
// right of m_left_pt.
|
||||
valid_intersection = (compare_xy(ctr_min(*icv), m_left_pt) != SMALLER);
|
||||
valid_intersection =
|
||||
(compare_xy(ctr_min(*icv), m_left_pt) != SMALLER);
|
||||
}
|
||||
// In this case the overlap is not valid.
|
||||
else valid_intersection = false;
|
||||
|
|
@ -613,23 +658,8 @@ _compute_next_intersection(Halfedge_handle he,
|
|||
if (ip != nullptr) {
|
||||
// We have an intersection point -
|
||||
// Check whether we need to skip the first intersection
|
||||
if (is_first && skip_first_point) valid_intersection = false;
|
||||
else if (m_left_on_boundary) {
|
||||
// The left-end lies on the left boundary. If the intersection point
|
||||
// is not equal to the left-end, the intersection is valid, because
|
||||
// it must lie to its right.
|
||||
if (m_has_left_pt) valid_intersection = ! equal(ip->first, m_left_pt);
|
||||
else valid_intersection = true;
|
||||
}
|
||||
else if (m_right_on_boundary && m_has_right_pt &&
|
||||
equal(ip->first, m_right_pt))
|
||||
{
|
||||
valid_intersection = true;
|
||||
intersection_on_right_boundary = true;
|
||||
}
|
||||
else {
|
||||
valid_intersection = (compare_xy(ip->first, m_left_pt) == LARGER);
|
||||
}
|
||||
valid_intersection = (is_first && skip_first_point) ? false :
|
||||
is_intersection_valid(ip->first, intersection_location);
|
||||
}
|
||||
else if (m_left_on_boundary) {
|
||||
// The left end is on the boundary, so all overlapping curves are valid,
|
||||
|
|
@ -671,13 +701,12 @@ _compute_next_intersection(Halfedge_handle he,
|
|||
//
|
||||
template <typename Arrangement, typename ZoneVisitor>
|
||||
void Arrangement_zone_2<Arrangement, ZoneVisitor>::
|
||||
_remove_next_intersection(Halfedge_handle he)
|
||||
{
|
||||
_remove_next_intersection(Halfedge_handle he) {
|
||||
// Get a pointer to the curve associated with the halfedge.
|
||||
const X_monotone_curve_2* p_curve = &(he->curve());
|
||||
|
||||
// Locate the intersections with this curve in the intersections map.
|
||||
Intersect_map_iterator iter = m_inter_map.find(p_curve);
|
||||
auto iter = m_inter_map.find(p_curve);
|
||||
|
||||
CGAL_assertion(iter != m_inter_map.end());
|
||||
CGAL_assertion(! iter->second.empty());
|
||||
|
|
@ -692,8 +721,7 @@ _remove_next_intersection(Halfedge_handle he)
|
|||
template <typename Arrangement, typename ZoneVisitor>
|
||||
bool Arrangement_zone_2<Arrangement, ZoneVisitor>::
|
||||
_is_to_left_impl(const Point_2& p, Halfedge_handle he,
|
||||
Arr_not_all_sides_oblivious_tag) const
|
||||
{
|
||||
Arr_not_all_sides_oblivious_tag) const {
|
||||
#if defined(ARR_ZONE_VERBOSE)
|
||||
std::cout << "_is_to_left_impl(" << p << "," << he->curve() << ")"
|
||||
<< std::endl;
|
||||
|
|
@ -708,12 +736,12 @@ _is_to_left_impl(const Point_2& p, Halfedge_handle he,
|
|||
if (ps_x_min == ARR_LEFT_BOUNDARY) return false;
|
||||
|
||||
auto ps_in_y = m_geom_traits->parameter_space_in_y_2_object();
|
||||
auto ps_y = ps_in_y(he->curve(), ARR_MIN_END);
|
||||
if (ps_y != ARR_INTERIOR) {
|
||||
auto ps_y_min = ps_in_y(he->curve(), ARR_MIN_END);
|
||||
if (ps_y_min != ARR_INTERIOR) {
|
||||
// Check if p is to the left of the minimal curve-end:
|
||||
auto cmp_x = m_geom_traits->compare_x_point_curve_end_2_object();
|
||||
const auto res = cmp_x(p, he->curve(), ARR_MIN_END);
|
||||
return ((res == SMALLER) || (res == EQUAL && ps_y == ARR_TOP_BOUNDARY));
|
||||
return ((res == SMALLER) || (res == EQUAL && ps_y_min == ARR_TOP_BOUNDARY));
|
||||
}
|
||||
|
||||
// In case the minimal curve-end does not have boundary conditions, simply
|
||||
|
|
@ -724,13 +752,13 @@ _is_to_left_impl(const Point_2& p, Halfedge_handle he,
|
|||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Determine whether a given point lies completely to the right of a given curve.
|
||||
// Determine whether a given point lies completely to the right of a given
|
||||
// curve.
|
||||
//
|
||||
template <typename Arrangement, typename ZoneVisitor>
|
||||
bool Arrangement_zone_2<Arrangement, ZoneVisitor>::
|
||||
_is_to_right_impl(const Point_2& p, Halfedge_handle he,
|
||||
Arr_not_all_sides_oblivious_tag) const
|
||||
{
|
||||
Arr_not_all_sides_oblivious_tag) const {
|
||||
#if defined(ARR_ZONE_VERBOSE)
|
||||
std::cout << "_is_to_right_impl(" << p << "," << he->curve() << ")"
|
||||
<< std::endl;
|
||||
|
|
@ -747,12 +775,12 @@ _is_to_right_impl(const Point_2& p, Halfedge_handle he,
|
|||
if (ps_x_max == ARR_LEFT_BOUNDARY) return true;
|
||||
|
||||
auto ps_in_y = m_geom_traits->parameter_space_in_y_2_object();
|
||||
auto ps_y = ps_in_y(he->curve(), ARR_MAX_END);
|
||||
if (ps_y != ARR_INTERIOR) {
|
||||
auto ps_y_max = ps_in_y(he->curve(), ARR_MAX_END);
|
||||
if (ps_y_max != ARR_INTERIOR) {
|
||||
// Check if p is to the right of the maximal curve-end:
|
||||
auto cmp_x = m_geom_traits->compare_x_point_curve_end_2_object();
|
||||
auto res = cmp_x(p, he->curve(), ARR_MAX_END);
|
||||
return ((res == LARGER) || (res == EQUAL && ps_y == ARR_BOTTOM_BOUNDARY));
|
||||
return ((res == LARGER) || (res == EQUAL && ps_y_max == ARR_BOTTOM_BOUNDARY));
|
||||
}
|
||||
|
||||
// In case the maximal curve-end does not have boundary conditions, simply
|
||||
|
|
@ -768,8 +796,7 @@ _is_to_right_impl(const Point_2& p, Halfedge_handle he,
|
|||
template <typename Arrangement, typename ZoneVisitor>
|
||||
void Arrangement_zone_2<Arrangement, ZoneVisitor>::
|
||||
_leftmost_intersection(Ccb_halfedge_circulator he_curr, bool on_boundary,
|
||||
bool& leftmost_on_right_boundary)
|
||||
{
|
||||
Arr_parameter_space& leftmost_location) {
|
||||
#if defined(ARR_ZONE_VERBOSE)
|
||||
std::cout << "_leftmost_intersection(" << he_curr->curve() << ", "
|
||||
<< on_boundary << ")" << std::endl;
|
||||
|
|
@ -793,7 +820,7 @@ _leftmost_intersection(Ccb_halfedge_circulator he_curr, bool on_boundary,
|
|||
// entirely to the right of m_intersect_p, its intersection with m_cv (if any)
|
||||
// cannot lie to the left of this point. We therefore do not need to compute
|
||||
// this intersection.
|
||||
if (m_found_intersect && ! leftmost_on_right_boundary &&
|
||||
if (m_found_intersect && (leftmost_location == ARR_INTERIOR) &&
|
||||
_is_to_left(m_intersect_p, he_curr))
|
||||
return;
|
||||
|
||||
|
|
@ -821,13 +848,14 @@ _leftmost_intersection(Ccb_halfedge_circulator he_curr, bool on_boundary,
|
|||
// do not intersect.
|
||||
if (! left_equals_curr_endpoint &&
|
||||
((! m_left_on_boundary && _is_to_right(m_left_pt, he_curr)) ||
|
||||
! is_in_x_range(m_cv, he_curr->curve())))
|
||||
! is_in_x_range(m_cv, he_curr->curve()))) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Compute the next intersection of m_cv and the current halfedge.
|
||||
bool intersection_on_right_boundary;
|
||||
Arr_parameter_space intersection_location;
|
||||
auto iobj = _compute_next_intersection(he_curr, left_equals_curr_endpoint,
|
||||
intersection_on_right_boundary);
|
||||
intersection_location);
|
||||
|
||||
if (iobj) {
|
||||
// We have found an intersection (either a simple point or an
|
||||
|
|
@ -839,8 +867,8 @@ _leftmost_intersection(Ccb_halfedge_circulator he_curr, bool on_boundary,
|
|||
// Found a simple intersection point. Check if it is the leftmost
|
||||
// intersection point so far.
|
||||
if (! m_found_intersect ||
|
||||
(! intersection_on_right_boundary &&
|
||||
(leftmost_on_right_boundary ||
|
||||
((intersection_location != ARR_RIGHT_BOUNDARY) &&
|
||||
((leftmost_location == ARR_RIGHT_BOUNDARY) ||
|
||||
compare_xy(ip, m_intersect_p) == SMALLER)))
|
||||
{
|
||||
// Store the leftmost intersection point and the halfedge handle.
|
||||
|
|
@ -848,7 +876,7 @@ _leftmost_intersection(Ccb_halfedge_circulator he_curr, bool on_boundary,
|
|||
m_ip_multiplicity = int_p->second;
|
||||
m_intersect_he = he_curr;
|
||||
m_found_overlap = false;
|
||||
leftmost_on_right_boundary = intersection_on_right_boundary;
|
||||
leftmost_location = intersection_location;
|
||||
}
|
||||
}
|
||||
else {
|
||||
|
|
@ -880,8 +908,7 @@ _leftmost_intersection(Ccb_halfedge_circulator he_curr, bool on_boundary,
|
|||
//
|
||||
template <typename Arrangement, typename ZoneVisitor>
|
||||
void Arrangement_zone_2<Arrangement, ZoneVisitor>::
|
||||
_leftmost_intersection_with_face_boundary(Face_handle face, bool on_boundary)
|
||||
{
|
||||
_leftmost_intersection_with_face_boundary(Face_handle face, bool on_boundary) {
|
||||
#if defined(ARR_ZONE_VERBOSE)
|
||||
std::cout << "_leftmost_intersection_with_face_boundary(" << on_boundary
|
||||
<< ")" << std::endl;
|
||||
|
|
@ -895,25 +922,23 @@ _leftmost_intersection_with_face_boundary(Face_handle face, bool on_boundary)
|
|||
auto compare_xy = m_geom_traits->compare_xy_2_object();
|
||||
auto is_in_x_range = m_geom_traits->is_in_x_range_2_object();
|
||||
|
||||
bool leftmost_on_right_boundary = false;
|
||||
Arr_parameter_space leftmost_location = ARR_INTERIOR;
|
||||
|
||||
// Traverse the face outer-boundaries; iterate through all outer CCBs.
|
||||
for (auto occb_it = face->outer_ccbs_begin();
|
||||
occb_it != face->outer_ccbs_end(); ++occb_it)
|
||||
{
|
||||
occb_it != face->outer_ccbs_end(); ++occb_it) {
|
||||
Ccb_halfedge_circulator he_first = *occb_it;
|
||||
Ccb_halfedge_circulator he_curr = he_first;
|
||||
do _leftmost_intersection(he_curr, on_boundary, leftmost_on_right_boundary);
|
||||
do _leftmost_intersection(he_curr, on_boundary, leftmost_location);
|
||||
while (++he_curr != he_first);
|
||||
}
|
||||
|
||||
// Traverse the face inner-boundaries; iterate through all inner CCBs (holes).
|
||||
for (auto iccb_it = face->inner_ccbs_begin();
|
||||
iccb_it != face->inner_ccbs_end(); ++iccb_it)
|
||||
{
|
||||
iccb_it != face->inner_ccbs_end(); ++iccb_it) {
|
||||
Ccb_halfedge_circulator he_first = *iccb_it;
|
||||
Ccb_halfedge_circulator he_curr = he_first;
|
||||
do _leftmost_intersection(he_curr, on_boundary, leftmost_on_right_boundary);
|
||||
do _leftmost_intersection(he_curr, on_boundary, leftmost_location);
|
||||
while (++he_curr != he_first);
|
||||
}
|
||||
|
||||
|
|
@ -921,17 +946,17 @@ _leftmost_intersection_with_face_boundary(Face_handle face, bool on_boundary)
|
|||
|
||||
// Traverse the isolated vertices inside the face (if there exist any), and
|
||||
// check whether an isolated vertex lies on the curve.
|
||||
typedef typename Arrangement_2::Isolated_vertex_iterator
|
||||
Isolated_vertex_iterator;
|
||||
for (Isolated_vertex_iterator iv_it = face->isolated_vertices_begin();
|
||||
iv_it != face->isolated_vertices_end(); ++iv_it)
|
||||
{
|
||||
// MSVC17 requires an explicit (non-const) type for the iterator.
|
||||
typename Arrangement_2::Isolated_vertex_iterator iv_it;
|
||||
for (iv_it = face->isolated_vertices_begin();
|
||||
iv_it != face->isolated_vertices_end(); ++iv_it) {
|
||||
// If the isolated vertex is not in the x-range of our curve, disregard it.
|
||||
if (! is_in_x_range(m_cv, iv_it->point())) continue;
|
||||
|
||||
// If we already have an intersection point, compare it to the current
|
||||
// isolated vertex, in order to filter unnecessary computations.
|
||||
if (m_found_intersect && compare_xy(iv_it->point(), m_intersect_p) == LARGER)
|
||||
if (m_found_intersect &&
|
||||
(compare_xy(iv_it->point(), m_intersect_p) == LARGER))
|
||||
continue;
|
||||
|
||||
// In case the isolated vertex lies on the curve, update the intersection
|
||||
|
|
@ -960,8 +985,7 @@ _leftmost_intersection_with_face_boundary(Face_handle face, bool on_boundary)
|
|||
//
|
||||
template <typename Arrangement, typename ZoneVisitor>
|
||||
bool Arrangement_zone_2<Arrangement, ZoneVisitor>::
|
||||
_zone_in_face(Face_handle face, bool on_boundary)
|
||||
{
|
||||
_zone_in_face(Face_handle face, bool on_boundary) {
|
||||
#if defined(ARR_ZONE_VERBOSE)
|
||||
std::cout << "_zone_in_face(" << on_boundary << ")" << std::endl;
|
||||
#endif
|
||||
|
|
@ -1095,7 +1119,7 @@ _zone_in_face(Face_handle face, bool on_boundary)
|
|||
// Associate the intersection list of the original curve with the
|
||||
// right subcurve, while we can associate an empty list with the
|
||||
// left subcurve, as we are now done with it.
|
||||
Intersect_map_iterator iter = m_inter_map.find(p_orig_curve);
|
||||
auto iter = m_inter_map.find(p_orig_curve);
|
||||
Intersect_list empty_inter_list;
|
||||
|
||||
m_inter_map[p_right_subcurve] = iter->second;
|
||||
|
|
@ -1190,8 +1214,7 @@ _zone_in_face(Face_handle face, bool on_boundary)
|
|||
// curve currently associated with m_intersect_he.
|
||||
//
|
||||
template <typename Arrangement, typename ZoneVisitor>
|
||||
bool Arrangement_zone_2<Arrangement, ZoneVisitor>::_zone_in_overlap()
|
||||
{
|
||||
bool Arrangement_zone_2<Arrangement, ZoneVisitor>::_zone_in_overlap() {
|
||||
#if defined(ARR_ZONE_VERBOSE)
|
||||
std::cout << "_zone_in_overlap()" << std::endl;
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -55,65 +55,68 @@ namespace CGAL {
|
|||
template <typename Arrangement_, typename ZoneVisitor_>
|
||||
class Arrangement_zone_2 {
|
||||
public:
|
||||
typedef Arrangement_ Arrangement_2;
|
||||
typedef typename Arrangement_2::Geometry_traits_2 Geometry_traits_2;
|
||||
typedef typename Arrangement_2::Topology_traits Topology_traits;
|
||||
using Arrangement_2 = Arrangement_;
|
||||
using Geometry_traits_2 = typename Arrangement_2::Geometry_traits_2;
|
||||
using Topology_traits = typename Arrangement_2::Topology_traits;
|
||||
|
||||
protected:
|
||||
typedef Arr_traits_adaptor_2<Geometry_traits_2> Traits_adaptor_2;
|
||||
using Traits_adaptor_2 = Arr_traits_adaptor_2<Geometry_traits_2>;
|
||||
|
||||
typedef typename Traits_adaptor_2::Left_side_category Left_side_category;
|
||||
typedef typename Traits_adaptor_2::Bottom_side_category Bottom_side_category;
|
||||
typedef typename Traits_adaptor_2::Top_side_category Top_side_category;
|
||||
typedef typename Traits_adaptor_2::Right_side_category Right_side_category;
|
||||
using Left_side_category = typename Traits_adaptor_2::Left_side_category;
|
||||
using Bottom_side_category = typename Traits_adaptor_2::Bottom_side_category;
|
||||
using Top_side_category = typename Traits_adaptor_2::Top_side_category;
|
||||
using Right_side_category = typename Traits_adaptor_2::Right_side_category;
|
||||
|
||||
static_assert(Arr_sane_identified_tagging<Left_side_category,
|
||||
Bottom_side_category,
|
||||
Bottom_side_category,
|
||||
Top_side_category,
|
||||
Right_side_category>::value);
|
||||
// Categories for dispatching
|
||||
using Are_all_sides_oblivious_category =
|
||||
typename Arr_all_sides_oblivious_category<Left_side_category,
|
||||
Bottom_side_category,
|
||||
Top_side_category,
|
||||
Right_side_category>::result;
|
||||
|
||||
using Left_or_right_sides_category =
|
||||
typename Arr_two_sides_category<Left_side_category,
|
||||
Right_side_category>::result;
|
||||
|
||||
public:
|
||||
typedef ZoneVisitor_ Visitor;
|
||||
using Visitor = ZoneVisitor_;
|
||||
|
||||
typedef typename Arrangement_2::Vertex_handle Vertex_handle;
|
||||
typedef typename Arrangement_2::Halfedge_handle Halfedge_handle;
|
||||
typedef typename Arrangement_2::Face_handle Face_handle;
|
||||
using Vertex_handle = typename Arrangement_2::Vertex_handle;
|
||||
using Halfedge_handle = typename Arrangement_2::Halfedge_handle;
|
||||
using Face_handle = typename Arrangement_2::Face_handle;
|
||||
|
||||
typedef std::pair<Halfedge_handle, bool> Visitor_result;
|
||||
using Visitor_result = std::pair<Halfedge_handle, bool>;
|
||||
|
||||
typedef typename Geometry_traits_2::Point_2 Point_2;
|
||||
typedef typename Geometry_traits_2::X_monotone_curve_2 X_monotone_curve_2;
|
||||
typedef typename Geometry_traits_2::Multiplicity Multiplicity;
|
||||
using Point_2 = typename Geometry_traits_2::Point_2;
|
||||
using X_monotone_curve_2 = typename Geometry_traits_2::X_monotone_curve_2;
|
||||
using Multiplicity = typename Geometry_traits_2::Multiplicity;
|
||||
|
||||
protected:
|
||||
typedef typename Arr_all_sides_oblivious_category<Left_side_category,
|
||||
Bottom_side_category,
|
||||
Top_side_category,
|
||||
Right_side_category>::result
|
||||
Are_all_sides_oblivious_category;
|
||||
// General types
|
||||
using Vertex_const_handle = typename Arrangement_2::Vertex_const_handle;
|
||||
using Halfedge_const_handle = typename Arrangement_2::Halfedge_const_handle;
|
||||
using Face_const_handle = typename Arrangement_2::Face_const_handle;
|
||||
|
||||
typedef typename Arrangement_2::Vertex_const_handle Vertex_const_handle;
|
||||
typedef typename Arrangement_2::Halfedge_const_handle Halfedge_const_handle;
|
||||
typedef typename Arrangement_2::Face_const_handle Face_const_handle;
|
||||
|
||||
typedef typename Arrangement_2::Ccb_halfedge_circulator
|
||||
Ccb_halfedge_circulator;
|
||||
using Ccb_halfedge_circulator =
|
||||
typename Arrangement_2::Ccb_halfedge_circulator;
|
||||
|
||||
// Types used for caching intersection points:
|
||||
typedef std::pair<Point_2, Multiplicity> Intersection_point;
|
||||
typedef std::variant<Intersection_point, X_monotone_curve_2>
|
||||
Intersection_result;
|
||||
typedef std::optional<Intersection_result> Optional_intersection;
|
||||
typedef std::list<Intersection_result> Intersect_list;
|
||||
typedef std::map<const X_monotone_curve_2*, Intersect_list>
|
||||
Intersect_map;
|
||||
typedef typename Intersect_map::iterator Intersect_map_iterator;
|
||||
using Intersection_point = std::pair<Point_2, Multiplicity>;
|
||||
using Intersection_result =
|
||||
std::variant<Intersection_point, X_monotone_curve_2>;
|
||||
using Optional_intersection = std::optional<Intersection_result>;
|
||||
using Intersect_list = std::list<Intersection_result>;
|
||||
using Intersect_map = std::map<const X_monotone_curve_2*, Intersect_list>;
|
||||
|
||||
typedef std::set<const X_monotone_curve_2*> Curves_set;
|
||||
typedef typename Curves_set::iterator Curves_set_iterator;
|
||||
using Curves_set = std::set<const X_monotone_curve_2*>;
|
||||
using Curves_set_iterator = typename Curves_set::iterator;
|
||||
|
||||
typedef Arr_point_location_result<Arrangement_2> Pl_result;
|
||||
typedef typename Pl_result::Type Pl_result_type;
|
||||
using Pl_result = Arr_point_location_result<Arrangement_2>;
|
||||
using Pl_result_type = typename Pl_result::Type;
|
||||
|
||||
// Data members:
|
||||
Arrangement_2& m_arr; // The associated arrangement.
|
||||
|
|
@ -193,8 +196,7 @@ public:
|
|||
* \param pl A point-location object associated with the arrangement.
|
||||
*/
|
||||
template <typename PointLocation>
|
||||
void init(const X_monotone_curve_2& cv, const PointLocation& pl)
|
||||
{
|
||||
void init(const X_monotone_curve_2& cv, const PointLocation& pl) {
|
||||
// Set the curve and check whether its left end has boundary conditions.
|
||||
m_cv = cv;
|
||||
|
||||
|
|
@ -267,8 +269,7 @@ private:
|
|||
*/
|
||||
bool do_overlap_impl(const X_monotone_curve_2& cv1,
|
||||
const X_monotone_curve_2& cv2,
|
||||
const Point_2& p, Arr_all_sides_oblivious_tag) const
|
||||
{
|
||||
const Point_2& p, Arr_all_sides_oblivious_tag) const {
|
||||
return m_geom_traits->compare_y_at_x_right_2_object()(cv1, cv2, p) == EQUAL;
|
||||
}
|
||||
|
||||
|
|
@ -336,7 +337,7 @@ private:
|
|||
Optional_intersection
|
||||
_compute_next_intersection(Halfedge_handle he,
|
||||
bool skip_first_point,
|
||||
bool& intersect_on_right_boundary);
|
||||
Arr_parameter_space& intersection_location);
|
||||
|
||||
/*! Remove the next intersection of m_cv with the given halfedge from the map.
|
||||
* \param he A handle to the halfedge.
|
||||
|
|
@ -381,8 +382,7 @@ private:
|
|||
{ return (_is_to_right_impl(p, he, Are_all_sides_oblivious_category())); }
|
||||
|
||||
bool _is_to_right_impl(const Point_2& p, Halfedge_handle he,
|
||||
Arr_all_sides_oblivious_tag) const
|
||||
{
|
||||
Arr_all_sides_oblivious_tag) const {
|
||||
return (((he->direction() == ARR_LEFT_TO_RIGHT) &&
|
||||
m_geom_traits->compare_xy_2_object()(p, he->target()->point()) ==
|
||||
LARGER) ||
|
||||
|
|
@ -394,12 +394,33 @@ private:
|
|||
bool _is_to_right_impl(const Point_2& p, Halfedge_handle he,
|
||||
Arr_not_all_sides_oblivious_tag) const;
|
||||
|
||||
/*! Check whether an intersection point is valid. A valid intersection point
|
||||
* must be to the left of the left end of the curve involved.
|
||||
*/
|
||||
bool is_intersection_valid(const Point_2& ip,
|
||||
Arr_parameter_space& intersection_location) const {
|
||||
return is_intersection_valid_impl(ip, intersection_location,
|
||||
Left_or_right_sides_category());
|
||||
}
|
||||
|
||||
bool is_intersection_valid_impl(const Point_2& ip,
|
||||
Arr_parameter_space& intersection_location,
|
||||
Arr_all_sides_oblivious_tag) const;
|
||||
|
||||
bool is_intersection_valid_impl(const Point_2& ip,
|
||||
Arr_parameter_space& intersection_location,
|
||||
Arr_has_identified_side_tag) const;
|
||||
|
||||
bool is_intersection_valid_impl(const Point_2& ip,
|
||||
Arr_parameter_space& intersection_location,
|
||||
Arr_boundary_cond_tag) const;
|
||||
|
||||
/*! Compute the (lexicographically) leftmost intersection of the query
|
||||
* curve with a given halfedge on the boundary of a face in the arrangement.
|
||||
*/
|
||||
void
|
||||
_leftmost_intersection(Ccb_halfedge_circulator he_curr, bool on_boundary,
|
||||
bool& leftmost_on_right_boundary);
|
||||
Arr_parameter_space& leftmost_location);
|
||||
|
||||
/*! Compute the (lexicographically) leftmost intersection of the query
|
||||
* curve with the boundary of a given face in the arrangement.
|
||||
|
|
|
|||
|
|
@ -29,7 +29,9 @@
|
|||
|
||||
#include <type_traits>
|
||||
#include <CGAL/Qt/init_ogl_context.h>
|
||||
#include <CGAL/Arrangement_on_surface_2.h>
|
||||
#include <CGAL/Arrangement_2.h>
|
||||
#include <CGAL/Arr_geodesic_arc_on_sphere_traits_2.h>
|
||||
|
||||
namespace CGAL {
|
||||
|
||||
|
|
@ -46,32 +48,32 @@ struct Default_color_generator {
|
|||
};
|
||||
|
||||
// Viewer class for`< Polygon_2
|
||||
template <typename Arrangement_2_,
|
||||
template <typename ArrangementOnSurface_2,
|
||||
typename ColorGenerator = Default_color_generator>
|
||||
class Arr_2_basic_viewer_qt : public Basic_viewer_qt {
|
||||
using Arr = Arrangement_2_;
|
||||
class Aos_2_basic_viewer_qt : public Basic_viewer_qt {
|
||||
using Aos = ArrangementOnSurface_2;
|
||||
using Color_generator = ColorGenerator;
|
||||
using Base = Basic_viewer_qt;
|
||||
using Gt = typename Arr::Geometry_traits_2;
|
||||
using Point = typename Arr::Point_2;
|
||||
using X_monotone_curve = typename Arr::X_monotone_curve_2;
|
||||
using Vertex_const_handle = typename Arr::Vertex_const_handle;
|
||||
using Halfedge_const_handle = typename Arr::Halfedge_const_handle;
|
||||
using Face_const_handle = typename Arr::Face_const_handle;
|
||||
using Gt = typename Aos::Geometry_traits_2;
|
||||
using Point = typename Aos::Point_2;
|
||||
using X_monotone_curve = typename Aos::X_monotone_curve_2;
|
||||
using Vertex_const_handle = typename Aos::Vertex_const_handle;
|
||||
using Halfedge_const_handle = typename Aos::Halfedge_const_handle;
|
||||
using Face_const_handle = typename Aos::Face_const_handle;
|
||||
using Ccb_halfedge_const_circulator =
|
||||
typename Arr::Ccb_halfedge_const_circulator;
|
||||
typename Aos::Ccb_halfedge_const_circulator;
|
||||
|
||||
public:
|
||||
/// Construct the viewer.
|
||||
/// @param arr the arrangement to view
|
||||
/// @param title the title of the window
|
||||
Arr_2_basic_viewer_qt(QWidget* parent, const Arr& arr,
|
||||
Aos_2_basic_viewer_qt(QWidget* parent, const Aos& aos,
|
||||
Color_generator color_generator,
|
||||
const char* title = "2D Arrangement Basic Viewer",
|
||||
bool draw_vertices = false) :
|
||||
// First draw: vertices; edges, faces; multi-color; no inverse normal
|
||||
Base(parent, title, draw_vertices, true, true, false, false),
|
||||
m_arr(arr),
|
||||
m_aos(aos),
|
||||
m_color_generator(color_generator)
|
||||
{
|
||||
// mimic the computation of Camera::pixelGLRatio()
|
||||
|
|
@ -154,32 +156,47 @@ public:
|
|||
*/
|
||||
CGAL::Bbox_2 bounding_box() {
|
||||
CGAL::Bbox_2 bbox;
|
||||
const auto* traits = this->m_arr.geometry_traits();
|
||||
const auto* traits = this->m_aos.geometry_traits();
|
||||
// At this point we assume that the arrangement is not open, and thus the
|
||||
// bounding box is defined by the vertices.
|
||||
for (auto it = m_arr.vertices_begin(); it != m_arr.vertices_end(); ++it)
|
||||
for (auto it = m_aos.vertices_begin(); it != m_aos.vertices_end(); ++it)
|
||||
bounding_box_impl1(bbox, it->point(), *traits, 0);
|
||||
return bbox;
|
||||
}
|
||||
|
||||
/*! Add all faces.
|
||||
*/
|
||||
template <typename Traits>
|
||||
void add_faces(const Traits&) {
|
||||
for (auto it = m_aos.unbounded_faces_begin();
|
||||
it != m_aos.unbounded_faces_end(); ++it)
|
||||
add_face(it);
|
||||
}
|
||||
|
||||
/*! Add all faces.
|
||||
*/
|
||||
template <typename Kernel_, int AtanX, int AtanY>
|
||||
void
|
||||
add_faces(Arr_geodesic_arc_on_sphere_traits_2<Kernel_, AtanX, AtanY> const&)
|
||||
{ add_face(m_aos.faces_begin()); }
|
||||
|
||||
/*! Add all elements to be drawn.
|
||||
*/
|
||||
void add_elements() {
|
||||
// std::cout << "add_elements()\n";
|
||||
// std::cout << "ratio: " << this->pixel_ratio() << std::endl;
|
||||
clear();
|
||||
m_visited.clear();
|
||||
|
||||
if (m_arr.is_empty()) return;
|
||||
for (auto it = m_arr.unbounded_faces_begin();
|
||||
it != m_arr.unbounded_faces_end(); ++it)
|
||||
add_face(it);
|
||||
if (m_aos.is_empty()) return;
|
||||
add_faces(*(this->m_aos.geometry_traits()));
|
||||
|
||||
// Add edges that do not separe faces.
|
||||
for (auto it = m_arr.edges_begin(); it != m_arr.edges_end(); ++it)
|
||||
// Add edges that do not separate faces.
|
||||
for (auto it = m_aos.edges_begin(); it != m_aos.edges_end(); ++it)
|
||||
if (it->face() == it->twin()->face()) draw_curve(it->curve());
|
||||
|
||||
// Add all points
|
||||
for (auto it = m_arr.vertices_begin(); it != m_arr.vertices_end(); ++it)
|
||||
for (auto it = m_aos.vertices_begin(); it != m_aos.vertices_end(); ++it)
|
||||
draw_point(it->point());
|
||||
|
||||
m_visited.clear();
|
||||
|
|
@ -190,11 +207,20 @@ public:
|
|||
double pixel_ratio() const { return m_pixel_ratio; }
|
||||
|
||||
protected:
|
||||
template <typename Kernel, int AtanX, int AtanY>
|
||||
Halfedge_const_handle
|
||||
find_smallest(Ccb_halfedge_const_circulator circ,
|
||||
Arr_geodesic_arc_on_sphere_traits_2<Kernel, AtanX, AtanY> const&)
|
||||
{ return circ; }
|
||||
|
||||
/*! Find the halfedge incident to the lexicographically smallest vertex
|
||||
* along the CCB, such that there is no other halfedge underneath.
|
||||
*/
|
||||
Halfedge_const_handle find_smallest(Ccb_halfedge_const_circulator circ) {
|
||||
const auto* traits = this->m_arr.geometry_traits();
|
||||
template <typename Traits>
|
||||
Halfedge_const_handle find_smallest(Ccb_halfedge_const_circulator circ,
|
||||
const Traits&) {
|
||||
// std::cout << "find_smallest()\n";
|
||||
const auto* traits = this->m_aos.geometry_traits();
|
||||
auto cmp_xy = traits->compare_xy_2_object();
|
||||
auto cmp_y = traits->compare_y_at_x_right_2_object();
|
||||
|
||||
|
|
@ -241,6 +267,7 @@ protected:
|
|||
template <typename Approximate>
|
||||
void draw_approximate_region(Halfedge_const_handle curr,
|
||||
const Approximate& approx) {
|
||||
// std::cout << "draw_approximate_region()\n";
|
||||
std::vector<typename Gt::Approximate_point_2> polyline;
|
||||
double error(this->pixel_ratio());
|
||||
bool l2r = curr->direction() == ARR_LEFT_TO_RIGHT;
|
||||
|
|
@ -258,7 +285,7 @@ protected:
|
|||
*/
|
||||
template <typename XMonotoneCurve>
|
||||
void draw_exact_curve(const XMonotoneCurve& curve) {
|
||||
const auto* traits = this->m_arr.geometry_traits();
|
||||
const auto* traits = this->m_aos.geometry_traits();
|
||||
auto ctr_min = traits->construct_min_vertex_2_object();
|
||||
auto ctr_max = traits->construct_max_vertex_2_object();
|
||||
this->add_segment(ctr_min(curve), ctr_max(curve));
|
||||
|
|
@ -267,7 +294,7 @@ protected:
|
|||
/*! Draw an exact region.
|
||||
*/
|
||||
void draw_exact_region(Halfedge_const_handle curr) {
|
||||
this->add_point_in_face(curr->source()->point());
|
||||
// this->add_point_in_face(curr->source()->point());
|
||||
draw_exact_curve(curr->curve());
|
||||
}
|
||||
|
||||
|
|
@ -300,9 +327,46 @@ protected:
|
|||
{ draw_approximate_region(curr, traits.approximate_2_object()); }
|
||||
#endif
|
||||
|
||||
template <typename Kernel_, int AtanX, int AtanY>
|
||||
void draw_region_impl1
|
||||
(Halfedge_const_handle curr,
|
||||
Arr_geodesic_arc_on_sphere_traits_2<Kernel_, AtanX, AtanY> const& traits,
|
||||
int) {
|
||||
// std::cout << "draw_region_impl1()\n";
|
||||
auto approx = traits.approximate_2_object();
|
||||
using Kernel = Kernel_;
|
||||
using Traits = Arr_geodesic_arc_on_sphere_traits_2<Kernel, AtanX, AtanY>;
|
||||
using Ak = typename Traits::Approximate_kernel;
|
||||
using Ap = typename Traits::Approximate_point_2;
|
||||
using Approx_point_3 = typename Ak::Point_3;
|
||||
|
||||
std::vector<Ap> polyline;
|
||||
double error(0.01);
|
||||
bool l2r = curr->direction() == ARR_LEFT_TO_RIGHT;
|
||||
approx(curr->curve(), error, std::back_inserter(polyline), l2r);
|
||||
if (polyline.empty()) return;
|
||||
auto it = polyline.begin();
|
||||
auto x = it->dx();
|
||||
auto y = it->dy();
|
||||
auto z = it->dz();
|
||||
auto l = std::sqrt(x*x + y*y + z*z);
|
||||
Approx_point_3 prev(x/l, y/l, z/l);
|
||||
for (++it; it != polyline.end(); ++it) {
|
||||
auto x = it->dx();
|
||||
auto y = it->dy();
|
||||
auto z = it->dz();
|
||||
auto l = std::sqrt(x*x + y*y + z*z);
|
||||
Approx_point_3 next(x/l, y/l, z/l);
|
||||
this->add_segment(prev, next);
|
||||
prev = next;
|
||||
// this->add_point_in_face(*prev);
|
||||
}
|
||||
}
|
||||
|
||||
/*! Draw a region.
|
||||
*/
|
||||
void draw_region(Ccb_halfedge_const_circulator circ) {
|
||||
// std::cout << "draw_region()\n";
|
||||
/* Check whether the traits has a member function called
|
||||
* approximate_2_object() and if so check whether the return type, namely
|
||||
* `Approximate_2` has an appropriate operator.
|
||||
|
|
@ -321,8 +385,8 @@ protected:
|
|||
auto color = m_color_generator(circ->face());
|
||||
this->face_begin(color);
|
||||
|
||||
const auto* traits = this->m_arr.geometry_traits();
|
||||
auto ext = find_smallest(circ);
|
||||
const auto* traits = this->m_aos.geometry_traits();
|
||||
auto ext = find_smallest(circ, *traits);
|
||||
auto curr = ext;
|
||||
|
||||
do {
|
||||
|
|
@ -382,6 +446,37 @@ protected:
|
|||
{ draw_approximate_curve(xcv, traits.approximate_2_object()); }
|
||||
#endif
|
||||
|
||||
template <typename Kernel_, int AtanX, int AtanY>
|
||||
void draw_curve_impl1
|
||||
(const X_monotone_curve& xcv,
|
||||
Arr_geodesic_arc_on_sphere_traits_2<Kernel_, AtanX, AtanY> const& traits,
|
||||
int) {
|
||||
auto approx = traits.approximate_2_object();
|
||||
using Kernel = Kernel_;
|
||||
using Traits = Arr_geodesic_arc_on_sphere_traits_2<Kernel, AtanX, AtanY>;
|
||||
using Ak = typename Traits::Approximate_kernel;
|
||||
using Ap = typename Traits::Approximate_point_2;
|
||||
using Approx_point_3 = typename Ak::Point_3;
|
||||
std::vector<Ap> apoints;
|
||||
double error(0.01);
|
||||
approx(xcv, error, std::back_inserter(apoints));
|
||||
auto it = apoints.begin();
|
||||
auto x = it->dx();
|
||||
auto y = it->dy();
|
||||
auto z = it->dz();
|
||||
auto l = std::sqrt(x*x + y*y + z*z);
|
||||
Approx_point_3 prev(x/l, y/l, z/l);
|
||||
for (++it; it != apoints.end(); ++it) {
|
||||
auto x = it->dx();
|
||||
auto y = it->dy();
|
||||
auto z = it->dz();
|
||||
auto l = std::sqrt(x*x + y*y + z*z);
|
||||
Approx_point_3 next(x/l, y/l, z/l);
|
||||
this->add_segment(prev, next);
|
||||
prev = next;
|
||||
}
|
||||
}
|
||||
|
||||
/*! Draw a curve.
|
||||
*/
|
||||
template <typename XMonotoneCurve>
|
||||
|
|
@ -404,14 +499,14 @@ protected:
|
|||
#if 0
|
||||
if constexpr (std::experimental::is_detected_v<approximate_2_object_t, Gt>)
|
||||
{
|
||||
const auto* traits = this->m_arr.geometry_traits();
|
||||
const auto* traits = this->m_aos.geometry_traits();
|
||||
auto approx = traits->approximate_2_object();
|
||||
draw_approximate_curve(curve, approx);
|
||||
return;
|
||||
}
|
||||
draw_exact_curve(curve);
|
||||
#else
|
||||
const auto* traits = this->m_arr.geometry_traits();
|
||||
const auto* traits = this->m_aos.geometry_traits();
|
||||
draw_curve_impl1(curve, *traits, 0);
|
||||
#endif
|
||||
}
|
||||
|
|
@ -442,16 +537,35 @@ protected:
|
|||
{ add_point(traits.approximate_2_object()(p)); }
|
||||
#endif
|
||||
|
||||
template <typename Kernel_, int AtanX, int AtanY>
|
||||
void draw_point_impl1
|
||||
(const Point& p,
|
||||
Arr_geodesic_arc_on_sphere_traits_2<Kernel_, AtanX, AtanY> const& traits,
|
||||
int) {
|
||||
auto approx = traits.approximate_2_object();
|
||||
using Traits = Arr_geodesic_arc_on_sphere_traits_2<Kernel_, AtanX, AtanY>;
|
||||
using Ak = typename Traits::Approximate_kernel;
|
||||
using Approx_point_3 = typename Ak::Point_3;
|
||||
auto ap = approx(p);
|
||||
auto x = ap.dx();
|
||||
auto y = ap.dy();
|
||||
auto z = ap.dz();
|
||||
auto l = std::sqrt(x*x + y*y + z*z);
|
||||
Approx_point_3 p3(x/l, y/l, z/l);
|
||||
add_point(p3);
|
||||
}
|
||||
|
||||
/*! Draw a point.
|
||||
*/
|
||||
void draw_point(const Point& p) {
|
||||
const auto* traits = m_arr.geometry_traits();
|
||||
const auto* traits = m_aos.geometry_traits();
|
||||
draw_point_impl1(p, *traits, 0);
|
||||
}
|
||||
|
||||
/*! Add a Connected Component of the Boundary.
|
||||
*/
|
||||
void add_ccb(Ccb_halfedge_const_circulator circ) {
|
||||
// std::cout << "add_ccb()\n";
|
||||
auto curr = circ;
|
||||
do {
|
||||
auto new_face = curr->twin()->face();
|
||||
|
|
@ -464,8 +578,9 @@ protected:
|
|||
/*! Add a face.
|
||||
*/
|
||||
void add_face(Face_const_handle face) {
|
||||
using Inner_ccb_const_iterator = typename Arr::Inner_ccb_const_iterator;
|
||||
using Outer_ccb_const_iterator = typename Arr::Outer_ccb_const_iterator;
|
||||
// std::cout << "add_face()\n";
|
||||
using Inner_ccb_const_iterator = typename Aos::Inner_ccb_const_iterator;
|
||||
using Outer_ccb_const_iterator = typename Aos::Outer_ccb_const_iterator;
|
||||
|
||||
for (Inner_ccb_const_iterator it = face->inner_ccbs_begin();
|
||||
it != face->inner_ccbs_end(); ++it)
|
||||
|
|
@ -505,7 +620,7 @@ protected:
|
|||
double m_pixel_ratio = 1;
|
||||
|
||||
//! The arrangement to draw.
|
||||
const Arr& m_arr;
|
||||
const Aos& m_aos;
|
||||
|
||||
//! The color generator.
|
||||
Color_generator m_color_generator;
|
||||
|
|
@ -514,32 +629,63 @@ protected:
|
|||
};
|
||||
|
||||
//! Basic viewer of a 2D arrangement.
|
||||
template <typename Arrangement_2_,
|
||||
template <typename ArrangementOnSurface_2,
|
||||
typename ColorGenerator = Default_color_generator>
|
||||
class Arr_2_viewer_qt : public Arr_2_basic_viewer_qt<Arrangement_2_,
|
||||
class Aos_2_viewer_qt : public Aos_2_basic_viewer_qt<ArrangementOnSurface_2,
|
||||
ColorGenerator> {
|
||||
public:
|
||||
using Arr = Arrangement_2_;
|
||||
using Aos = ArrangementOnSurface_2;
|
||||
using Color_generator = ColorGenerator;
|
||||
using Base = Arr_2_basic_viewer_qt<Arr, Color_generator>;
|
||||
using Point = typename Arr::Point_2;
|
||||
using X_monotone_curve = typename Arr::X_monotone_curve_2;
|
||||
using Halfedge_const_handle = typename Arr::Halfedge_const_handle;
|
||||
using Face_const_handle = typename Arr::Face_const_handle;
|
||||
using Base = Aos_2_basic_viewer_qt<Aos, Color_generator>;
|
||||
using Point = typename Aos::Point_2;
|
||||
using X_monotone_curve = typename Aos::X_monotone_curve_2;
|
||||
using Halfedge_const_handle = typename Aos::Halfedge_const_handle;
|
||||
using Face_const_handle = typename Aos::Face_const_handle;
|
||||
using Ccb_halfedge_const_circulator =
|
||||
typename Arr::Ccb_halfedge_const_circulator;
|
||||
typename Aos::Ccb_halfedge_const_circulator;
|
||||
|
||||
/// Construct the viewer.
|
||||
/// @param arr the arrangement to view
|
||||
/// @param title the title of the window
|
||||
Arr_2_viewer_qt(QWidget* parent, const Arr& arr,
|
||||
Aos_2_viewer_qt(QWidget* parent, const Aos& aos,
|
||||
Color_generator color_generator,
|
||||
const char* title = "2D Arrangement Basic Viewer",
|
||||
const char* title = "2D Arrangement on Surface Basic Viewer",
|
||||
bool draw_vertices = false) :
|
||||
Base(parent, arr, color_generator, title, draw_vertices)
|
||||
Base(parent, aos, color_generator, title, draw_vertices)
|
||||
{}
|
||||
};
|
||||
|
||||
/*! Draw an arrangement on surface.
|
||||
*/
|
||||
template <typename GeometryTraits_2, typename TopologyTraits>
|
||||
void draw(const Arrangement_on_surface_2<GeometryTraits_2, TopologyTraits>& aos,
|
||||
const char* title = "2D Arrangement on Surface Basic Viewer",
|
||||
bool draw_vertices = false) {
|
||||
#if defined(CGAL_TEST_SUITE)
|
||||
bool cgal_test_suite=true;
|
||||
#else
|
||||
bool cgal_test_suite = qEnvironmentVariableIsSet("CGAL_TEST_SUITE");
|
||||
#endif
|
||||
|
||||
if (cgal_test_suite) return;
|
||||
using Gt = GeometryTraits_2;
|
||||
using Tt = TopologyTraits;
|
||||
using Aos = CGAL::Arrangement_on_surface_2<Gt, Tt>;
|
||||
using Viewer = Aos_2_viewer_qt<Aos, Default_color_generator>;
|
||||
|
||||
CGAL::Qt::init_ogl_context(4,3);
|
||||
|
||||
int argc = 1;
|
||||
const char* argv[2] = {"t2_viewer", nullptr};
|
||||
QApplication app(argc, const_cast<char**>(argv));
|
||||
Default_color_generator color_generator;
|
||||
Viewer mainwindow(app.activeWindow(), aos, color_generator, title,
|
||||
draw_vertices);
|
||||
mainwindow.add_elements();
|
||||
mainwindow.show();
|
||||
app.exec();
|
||||
}
|
||||
|
||||
/*! Draw an arrangement.
|
||||
*/
|
||||
template <typename GeometryTraits_2, typename Dcel>
|
||||
|
|
@ -555,7 +701,7 @@ void draw(const Arrangement_2<GeometryTraits_2, Dcel>& arr,
|
|||
if (cgal_test_suite) return;
|
||||
using Gt = GeometryTraits_2;
|
||||
using Arr = CGAL::Arrangement_2<Gt, Dcel>;
|
||||
using Viewer = Arr_2_viewer_qt<Arr, Default_color_generator>;
|
||||
using Viewer = Aos_2_viewer_qt<Arr, Default_color_generator>;
|
||||
|
||||
CGAL::Qt::init_ogl_context(4,3);
|
||||
|
||||
|
|
@ -589,7 +735,7 @@ void draw(const Arrangement_2<GeometryTraits_2, Dcel>& arr,
|
|||
using Color_generator = ColorGenerator;
|
||||
using Gt = GeometryTraits_2;
|
||||
using Arr = CGAL::Arrangement_2<Gt, Dcel>;
|
||||
using Viewer = Arr_2_viewer_qt<Arr, Color_generator>;
|
||||
using Viewer = Aos_2_viewer_qt<Arr, Color_generator>;
|
||||
|
||||
CGAL::Qt::init_ogl_context(4,3);
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,17 @@
|
|||
5
|
||||
0 -1 0 0 0 -1 0
|
||||
0 0 -1 0 0 0 -1
|
||||
0 0 0 -1 0 1 0
|
||||
0 0 1 0 -1 0 0
|
||||
0 0 0 -1 -1 0 0
|
||||
0
|
||||
4 5 3
|
||||
0 0 -1
|
||||
-1 0 0
|
||||
0 -1 0
|
||||
0 1 0
|
||||
0 0 0 -1 -1 0 0 1
|
||||
0 -1 0 0 0 -1 0 1
|
||||
0 0 -1 0 0 0 -1 1
|
||||
0 0 0 -1 0 1 0 1
|
||||
0 0 1 0 -1 0 0 1
|
||||
|
|
@ -37,3 +37,4 @@ data/test_construction/geodesic_arcs_on_sphere/test36.txt
|
|||
data/test_construction/geodesic_arcs_on_sphere/test37.txt
|
||||
data/test_construction/geodesic_arcs_on_sphere/test38.txt
|
||||
data/test_construction/geodesic_arcs_on_sphere/test39.txt
|
||||
data/test_construction/geodesic_arcs_on_sphere/test40.txt
|
||||
|
|
|
|||
|
|
@ -59,7 +59,7 @@ private:
|
|||
using Image_bool = Image<bool>;
|
||||
|
||||
const PointRange* m_points;
|
||||
PointMap m_point_map;
|
||||
std::optional<PointMap> m_point_map;
|
||||
Iso_cuboid_3 m_bbox;
|
||||
float m_resolution;
|
||||
|
||||
|
|
@ -342,7 +342,7 @@ public:
|
|||
{
|
||||
if (m_lower_scale == nullptr)
|
||||
{
|
||||
const Point_3& p = get(m_point_map, *(m_points->begin()+index));
|
||||
const Point_3& p = get(m_point_map.value(), *(m_points->begin()+index));
|
||||
return (std::size_t)((p.x() - m_bbox.xmin()) / m_resolution);
|
||||
}
|
||||
|
||||
|
|
@ -356,7 +356,7 @@ public:
|
|||
{
|
||||
if (m_lower_scale == nullptr)
|
||||
{
|
||||
const Point_3& p = get(m_point_map, *(m_points->begin()+index));
|
||||
const Point_3& p = get(m_point_map.value(), *(m_points->begin()+index));
|
||||
return (std::size_t)((p.y() - m_bbox.ymin()) / m_resolution);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -69,7 +69,7 @@ class Point_set_neighborhood
|
|||
using key_type = std::uint32_t;
|
||||
using category = boost::readable_property_map_tag;
|
||||
|
||||
My_point_property_map () { }
|
||||
//My_point_property_map () { }
|
||||
My_point_property_map (const PointRange *input, PointMap point_map)
|
||||
: input (input), point_map (point_map) { }
|
||||
|
||||
|
|
@ -88,7 +88,7 @@ class Point_set_neighborhood
|
|||
using Knn = Orthogonal_k_neighbor_search<Search_traits, Distance, Splitter, Tree>;
|
||||
|
||||
std::shared_ptr<Tree> m_tree;
|
||||
Distance m_distance;
|
||||
std::optional<Distance> m_distance;
|
||||
|
||||
public:
|
||||
|
||||
|
|
@ -300,7 +300,7 @@ private:
|
|||
void k_neighbors (const Point& query, const unsigned int k, OutputIterator output) const
|
||||
{
|
||||
CGAL_assertion (m_tree != nullptr);
|
||||
Knn search (*m_tree, query, k, 0, true, m_distance);
|
||||
Knn search (*m_tree, query, k, 0, true, m_distance.value());
|
||||
for (typename Knn::iterator it = search.begin(); it != search.end(); ++ it)
|
||||
*(output ++) = it->first;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -59,8 +59,6 @@ private:
|
|||
|
||||
public:
|
||||
|
||||
Face_descriptor_to_center_of_mass_map ()
|
||||
: m_mesh (nullptr) { }
|
||||
Face_descriptor_to_center_of_mass_map (const FaceGraph* mesh)
|
||||
: m_mesh (mesh), m_vpm (get (vertex_point, *m_mesh)) { }
|
||||
Face_descriptor_to_center_of_mass_map (const FaceGraph* mesh, VertexPointMap vpm)
|
||||
|
|
|
|||
|
|
@ -73,7 +73,7 @@ seems that the points are collinear, or perform a right turn.
|
|||
|
||||
If you must ensure that your numbers get interpreted at their full precision
|
||||
you can use a \cgal kernel that performs exact predicates and
|
||||
extract constructions.
|
||||
exact constructions.
|
||||
|
||||
\cgalExample{Kernel_23/exact.cpp}
|
||||
|
||||
|
|
|
|||
|
|
@ -35,6 +35,10 @@ Release date: October 2023
|
|||
- Removed the class templates `Gray_image_mesh_domain_3`, `Implicit_mesh_domain_3`, and `Labeled_image_mesh_domain_3`
|
||||
which are deprecated since CGAL-4.13.
|
||||
|
||||
### [2D Arrangements](https://doc.cgal.org/6.0/Manual/packages.html#PkgArrangementOnSurface2)
|
||||
- Fixed a bug in the zone construction code applied to arrangements of geodesic arcs on a sphere,
|
||||
when inserting an arc that lies on the identification curve.
|
||||
|
||||
### [Tetrahedral Remeshing](https://doc.cgal.org/6.0/Manual/packages.html#PkgTetrahedralRemeshing)
|
||||
- **Breaking change**: The template parameters of
|
||||
`CGAL::Tetrahedral_remeshing::Remeshing_cell_base_3`
|
||||
|
|
|
|||
|
|
@ -708,10 +708,11 @@ private:
|
|||
const Polygon_2& polygon = pair.first;
|
||||
const Indices& input_indices = pair.second;
|
||||
m_data.add_input_polygon(support_plane_idx, input_indices, polygon);
|
||||
if (m_parameters.debug)
|
||||
dump_polygons(m_data, polygons, m_data.prefix() + "inserted-polygons");
|
||||
}
|
||||
|
||||
//if (m_parameters.debug)
|
||||
dump_polygons(m_data, polygons, m_data.prefix() + "inserted-polygons.ply");
|
||||
|
||||
CGAL_assertion(m_data.number_of_support_planes() >= 6);
|
||||
if (m_parameters.verbose) {
|
||||
std::cout << "* provided input polygons: " << m_data.input_polygons().size() << std::endl;
|
||||
|
|
|
|||
|
|
@ -1084,7 +1084,8 @@ public:
|
|||
\param it
|
||||
output iterator.
|
||||
|
||||
\warning Removed\n Replaced by `for (auto d : CMap::darts_of_cell<2, 3>(d)) *it++ = to_inexact(CMap::attribute<0>(d).point);`
|
||||
\warning Removed\n Replaced by `for (auto vd : CMap::darts_of_cell<2, 2>(fd)) *it++ = to_inexact(CMap::attribute<0>(vd).point);`
|
||||
alternatively a loop with beta(1) to be sure the vertices are in correct order
|
||||
|
||||
\pre successful partition
|
||||
*/
|
||||
|
|
@ -1106,7 +1107,7 @@ public:
|
|||
\param it
|
||||
output iterator.
|
||||
|
||||
\warning Replaced by `CMap::darts_of_cell<2, 3>(d)`
|
||||
\warning Replaced by `CMap::darts_of_cell<2, 2>(d)`
|
||||
|
||||
\pre successful partition
|
||||
*/
|
||||
|
|
@ -1182,7 +1183,7 @@ public:
|
|||
\param it
|
||||
output iterator.
|
||||
|
||||
\warning Replaced by `CMap::one_dart_per_incident_cell<2, 3, 3>(d)`
|
||||
\warning Replaced by `CMap::one_dart_per_incident_cell<2, 3, 3>(vol_d)`
|
||||
|
||||
\pre successful partition
|
||||
*/
|
||||
|
|
@ -1237,7 +1238,8 @@ public:
|
|||
@return
|
||||
pair of adjacent volumes.
|
||||
|
||||
\warning Replaced by `beta<3>(d)` as d is part of one 3-cell already
|
||||
\warning Replaced by `beta<3>(vol_d)` as d is part of one 3-cell already
|
||||
bbox sides should be stored in the Face_property
|
||||
|
||||
\pre successful partition
|
||||
*/
|
||||
|
|
@ -1353,6 +1355,11 @@ public:
|
|||
//auto vertex_range = m_data.pvertices_of_pface(vol.pfaces[i]);
|
||||
ib.begin_facet();
|
||||
|
||||
bool outward;
|
||||
|
||||
PVertex vtx = *m_data.pvertices_of_pface(volume.pfaces[i]).begin();
|
||||
volume.pface_oriented_outwards[i] = ((m_data.point_3(vtx) - volume.centroid) * m_data.support_plane(volume.pfaces[i]).plane().orthogonal_vector() < 0);
|
||||
|
||||
if (!vol.pface_oriented_outwards[j])
|
||||
std::reverse(vtx_of_face.begin(), vtx_of_face.end());
|
||||
|
||||
|
|
@ -1360,15 +1367,16 @@ public:
|
|||
ib.add_vertex_to_facet(static_cast<std::size_t>(mapped_vertices[v]));
|
||||
|
||||
auto face_dart = ib.end_facet(); // returns a dart to the face
|
||||
LCC_Properties::Face_property face_prop;
|
||||
face_prop.Input_polygon_index = 5;
|
||||
face_prop.Part_of_initial_polygon = true;
|
||||
m_lcc.info<2>(face_dart) = face_prop;
|
||||
m_lcc.set_attribute<2>(face_dart, m_lcc.create_attribute<2>());
|
||||
m_lcc.info<2>(face_dart).Input_polygon_index = 5;
|
||||
m_lcc.info<2>(face_dart).Part_of_initial_polygon = true;
|
||||
|
||||
vtx_of_face.clear();
|
||||
}
|
||||
|
||||
auto vol_dart = ib.end_surface(); // returns a dart to the volume
|
||||
m_lcc.set_attribute<3>(vol_dart, m_lcc.create_attribute<3>());
|
||||
m_lcc.info<3>(vol_dart).barycenter;
|
||||
int num_faces = m_lcc.one_dart_per_cell<2>().size();
|
||||
faces_of_volume.clear();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1216,6 +1216,17 @@ private:
|
|||
.maximum_angle(angle_tolerance)
|
||||
.maximum_offset(maximum_offset));*/
|
||||
|
||||
// Merge coplanar regions
|
||||
for (std::size_t i = 0; i < m_regions.size() - 1; i++) {
|
||||
for (std::size_t j = i + 1; j < m_regions.size(); j++) {
|
||||
if (m_regions[i].first == m_regions[j].first || m_regions[i].first.opposite() == m_regions[j].first) {
|
||||
std::move(m_regions[j].second.begin(), m_regions[j].second.begin(), std::back_inserter(m_regions[i].second));
|
||||
m_regions.remove(m_regions.begin() + j);
|
||||
j--
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<Plane_3> pl;
|
||||
|
||||
std::size_t idx = 0;
|
||||
|
|
|
|||
|
|
@ -293,4 +293,4 @@ provided kind help and advice all the way through.
|
|||
|
||||
*/
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -23,7 +23,7 @@ int main() {
|
|||
points.emplace_back(-1, 1, 1);
|
||||
|
||||
// Create an octree from the points
|
||||
Octree octree({points});
|
||||
Octree octree(points);
|
||||
|
||||
// Build the octree
|
||||
octree.refine(10, 1);
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@ int main() {
|
|||
points.emplace_back(-1.0001, 1, 1);
|
||||
|
||||
// Create an octree from the points
|
||||
Octree octree({points});
|
||||
Octree octree(points);
|
||||
|
||||
// Build the octree with a small bucket size, so we get a deep node
|
||||
octree.refine(10, 2);
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ int main()
|
|||
points_2d.emplace_back(r.get_double(-1., 1.),
|
||||
r.get_double(-1., 1.));
|
||||
|
||||
Quadtree quadtree({points_2d});
|
||||
Quadtree quadtree(points_2d);
|
||||
quadtree.refine(10, 5);
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
|
|
|
|||
|
|
@ -129,6 +129,7 @@ namespace Orthtrees {
|
|||
|
||||
\tparam Tree must be an orthtree with traits which are a model of CollectionPartitioningOrthtreeTraits
|
||||
\tparam OutputIterator must be a model of `OutputIterator` that accepts points
|
||||
|
||||
\param orthtree the tree to search within
|
||||
\param query_sphere the region to search within
|
||||
\param k the number of points to find
|
||||
|
|
@ -172,6 +173,7 @@ OutputIterator nearest_k_neighbors_in_radius(
|
|||
|
||||
\tparam Tree must be an orthtree with traits which are a model of CollectionPartitioningOrthtreeTraits
|
||||
\tparam OutputIterator a model of `OutputIterator` that accept `Point_d` objects.
|
||||
|
||||
\param orthtree the tree to search within
|
||||
\param query query point.
|
||||
\param k number of neighbors.
|
||||
|
|
@ -193,6 +195,7 @@ OutputIterator nearest_neighbors(const Tree& orthtree, const typename Tree::Poin
|
|||
|
||||
\tparam Tree must be an orthtree with traits which are a model of CollectionPartitioningOrthtreeTraits
|
||||
\tparam OutputIterator a model of `OutputIterator` that accept `Point_d` objects.
|
||||
|
||||
\param orthtree the tree to search within
|
||||
\param query query sphere.
|
||||
\param output output iterator.
|
||||
|
|
|
|||
|
|
@ -747,7 +747,7 @@ namespace CGAL {
|
|||
if (v == Polygon_mesh::null_vertex()) // failed splitting edge
|
||||
return Polygon_mesh::null_halfedge();
|
||||
|
||||
typename Polygon_mesh::template Property_map<Vertex_descriptor, Point>& coords = mesh.points();
|
||||
auto &coords = mesh.points();
|
||||
coords[v] = *ep.pos;
|
||||
|
||||
Edge_descriptor e1 = mesh.edge(h);
|
||||
|
|
|
|||
|
|
@ -142,7 +142,7 @@ namespace CGAL {
|
|||
std::size_t idx = 0;
|
||||
for (typename PointRange::const_iterator it = points.begin(); it != points.end(); ++it) {
|
||||
Base_class::m_points[idx] = get(point_map, *it);
|
||||
Base_class::m_normals[idx] = get(normal_map, *it);
|
||||
Base_class::m_normals.value()[idx] = get(normal_map, *it);
|
||||
int plane_index = get(plane_index_map, *it);
|
||||
if (plane_index != -1) {
|
||||
auto it_and_bool = plane_index_remap.emplace(plane_index, planar_segments_.size());
|
||||
|
|
|
|||
|
|
@ -153,13 +153,13 @@ public:
|
|||
for(auto fit=wrapper.triangulation().finite_facets_begin(), fend=wrapper.triangulation().finite_facets_end(); fit!=fend; ++fit)
|
||||
{
|
||||
Facet f = *fit;
|
||||
if(!f.first->info().is_outside)
|
||||
if(!f.first->is_outside())
|
||||
f = wrapper.triangulation().mirror_facet(f);
|
||||
|
||||
const Cell_handle c = f.first;
|
||||
const int s = f.second;
|
||||
const Cell_handle nh = c->neighbor(s);
|
||||
if(c->info().is_outside == nh->info().is_outside)
|
||||
if(c->is_outside() == nh->is_outside())
|
||||
continue;
|
||||
|
||||
std::array<std::size_t, 3> ids;
|
||||
|
|
|
|||
|
|
@ -30,9 +30,8 @@ Cluster_classification::Cluster_classification(Scene_points_with_normal_item* po
|
|||
|
||||
backup_existing_colors_and_add_new();
|
||||
|
||||
bool cluster_found = false;
|
||||
boost::tie (m_cluster_id, cluster_found) = m_points->point_set()->property_map<int>("shape");
|
||||
if (!cluster_found)
|
||||
auto m_cluster_id = m_points->point_set()->property_map<int>("shape");
|
||||
if (!m_cluster_id)
|
||||
{
|
||||
std::cerr << "Error! Cluster not found!" << std::endl;
|
||||
abort();
|
||||
|
|
@ -40,7 +39,7 @@ Cluster_classification::Cluster_classification(Scene_points_with_normal_item* po
|
|||
|
||||
CGAL::Classification::create_clusters_from_indices (*(m_points->point_set()),
|
||||
m_points->point_set()->point_map(),
|
||||
m_cluster_id,
|
||||
m_cluster_id.value(),
|
||||
m_clusters);
|
||||
|
||||
std::cerr << m_clusters.size() << " cluster(s) found" << std::endl;
|
||||
|
|
@ -57,20 +56,20 @@ Cluster_classification::Cluster_classification(Scene_points_with_normal_item* po
|
|||
|
||||
if (!classif_found)
|
||||
{
|
||||
Point_set::Property_map<unsigned char> las_classif;
|
||||
boost::tie (las_classif, las_found) = m_points->point_set()->property_map<unsigned char>("classification");
|
||||
if (las_found)
|
||||
auto las_classif = m_points->point_set()->property_map<unsigned char>("classification");
|
||||
las_found = las_classif.has_value();
|
||||
if (las_classif)
|
||||
{
|
||||
m_input_is_las = true;
|
||||
for (Point_set::const_iterator it = m_points->point_set()->begin();
|
||||
it != m_points->point_set()->first_selected(); ++ it)
|
||||
{
|
||||
unsigned char uc = las_classif[*it];
|
||||
m_classif[*it] = int(uc);
|
||||
unsigned char uc = las_classif.value()[*it];
|
||||
m_classif.value()[*it] = int(uc);
|
||||
if (!training_found)
|
||||
m_training[*it] = int(uc);
|
||||
m_training.value()[*it] = int(uc);
|
||||
}
|
||||
m_points->point_set()->remove_property_map (las_classif);
|
||||
m_points->point_set()->remove_property_map (las_classif.value());
|
||||
classif_found = true;
|
||||
training_found = true;
|
||||
}
|
||||
|
|
@ -85,7 +84,7 @@ Cluster_classification::Cluster_classification(Scene_points_with_normal_item* po
|
|||
{
|
||||
if (training_found)
|
||||
{
|
||||
int l = m_training[*it];
|
||||
int l = m_training.value()[*it];
|
||||
if (l >= 0)
|
||||
{
|
||||
if (std::size_t(l) >= used_indices.size())
|
||||
|
|
@ -95,7 +94,7 @@ Cluster_classification::Cluster_classification(Scene_points_with_normal_item* po
|
|||
}
|
||||
if (classif_found)
|
||||
{
|
||||
int l = m_classif[*it];
|
||||
int l = m_classif.value()[*it];
|
||||
if (l >= 0)
|
||||
{
|
||||
if (std::size_t(l) >= used_indices.size())
|
||||
|
|
@ -125,31 +124,31 @@ Cluster_classification::Cluster_classification(Scene_points_with_normal_item* po
|
|||
for (Point_set::const_iterator it = m_points->point_set()->begin();
|
||||
it != m_points->point_set()->first_selected(); ++ it)
|
||||
{
|
||||
int c = m_cluster_id[*it];
|
||||
int c = m_cluster_id.value()[*it];
|
||||
|
||||
if (training_found)
|
||||
{
|
||||
if (std::size_t(current_idx) != used_indices.size()) // Empty indices -> reorder indices in point set
|
||||
{
|
||||
if (las_found && (m_training[*it] == 0 || m_training[*it] == 1)) // Unclassified class in LAS
|
||||
m_training[*it] = -1;
|
||||
else if (m_training[*it] != -1)
|
||||
m_training[*it] = used_indices[std::size_t(m_training[*it])];
|
||||
if (las_found && (m_training.value()[*it] == 0 || m_training.value()[*it] == 1)) // Unclassified class in LAS
|
||||
m_training.value()[*it] = -1;
|
||||
else if (m_training.value()[*it] != -1)
|
||||
m_training.value()[*it] = used_indices[std::size_t(m_training.value()[*it])];
|
||||
}
|
||||
if (c != -1 && m_training[*it] != -1)
|
||||
m_clusters[c].training() = m_training[*it];
|
||||
if (c != -1 && m_training.value()[*it] != -1)
|
||||
m_clusters[c].training() = m_training.value()[*it];
|
||||
}
|
||||
if (classif_found)
|
||||
{
|
||||
if (std::size_t(current_idx) != used_indices.size()) // Empty indices -> reorder indices in point set
|
||||
{
|
||||
if (las_found && (m_classif[*it] == 0 || m_classif[*it] == 1)) // Unclassified class in LAS
|
||||
m_classif[*it] = -1;
|
||||
else if (m_classif[*it] != -1)
|
||||
m_classif[*it] = used_indices[std::size_t(m_classif[*it])];
|
||||
if (las_found && (m_classif.value()[*it] == 0 || m_classif.value()[*it] == 1)) // Unclassified class in LAS
|
||||
m_classif.value()[*it] = -1;
|
||||
else if (m_classif.value()[*it] != -1)
|
||||
m_classif.value()[*it] = used_indices[std::size_t(m_classif.value()[*it])];
|
||||
}
|
||||
if (c != -1 && m_classif[*it] != -1)
|
||||
m_clusters[c].label() = m_classif[*it];
|
||||
if (c != -1 && m_classif.value()[*it] != -1)
|
||||
m_clusters[c].label() = m_classif.value()[*it];
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -240,11 +239,11 @@ Cluster_classification::Cluster_classification(Scene_points_with_normal_item* po
|
|||
Delaunay dt (boost::make_transform_iterator
|
||||
(m_points->point_set()->begin(),
|
||||
Point_set_with_cluster_info (m_points->point_set(),
|
||||
m_cluster_id)),
|
||||
m_cluster_id.value())),
|
||||
boost::make_transform_iterator
|
||||
(m_points->point_set()->end(),
|
||||
Point_set_with_cluster_info (m_points->point_set(),
|
||||
m_cluster_id)));
|
||||
m_cluster_id.value())));
|
||||
|
||||
std::set<std::pair<int, int> > adjacencies;
|
||||
|
||||
|
|
@ -294,16 +293,16 @@ Cluster_classification::~Cluster_classification()
|
|||
for (Point_set::const_iterator it = m_points->point_set()->begin();
|
||||
it != m_points->point_set()->first_selected(); ++ it)
|
||||
{
|
||||
int c = m_cluster_id[*it];
|
||||
int c = m_cluster_id.value()[*it];
|
||||
if (c != -1)
|
||||
{
|
||||
m_training[*it] = m_clusters[c].training();
|
||||
m_classif[*it] = m_clusters[c].label();
|
||||
m_training.value()[*it] = m_clusters[c].training();
|
||||
m_classif.value()[*it] = m_clusters[c].label();
|
||||
}
|
||||
else
|
||||
{
|
||||
m_training[*it] = -1;
|
||||
m_classif[*it] = -1;
|
||||
m_training.value()[*it] = -1;
|
||||
m_classif.value()[*it] = -1;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -359,22 +358,22 @@ Cluster_classification::~Cluster_classification()
|
|||
for (Point_set::const_iterator it = m_points->point_set()->begin();
|
||||
it != m_points->point_set()->end(); ++ it)
|
||||
{
|
||||
int c = m_classif[*it];
|
||||
int c = m_classif.value()[*it];
|
||||
unsigned char lc = 1; // unclassified in LAS standard
|
||||
if (c != -1)
|
||||
lc = label_indices[std::size_t(c)];
|
||||
|
||||
las_classif[*it] = lc;
|
||||
|
||||
int t = m_training[*it];
|
||||
int t = m_training.value()[*it];
|
||||
unsigned char lt = 1; // unclassified in LAS standard
|
||||
if (t != -1)
|
||||
lt = label_indices[std::size_t(t)];
|
||||
|
||||
m_training[*it] = int(lt);
|
||||
m_training.value()[*it] = int(lt);
|
||||
}
|
||||
|
||||
m_points->point_set()->remove_property_map (m_classif);
|
||||
m_points->point_set()->remove_property_map (m_classif.value());
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -391,7 +390,7 @@ void Cluster_classification::backup_existing_colors_and_add_new()
|
|||
m_color = m_points->point_set()->add_property_map<CGAL::IO::Color>("real_color").first;
|
||||
for (Point_set::const_iterator it = m_points->point_set()->begin();
|
||||
it != m_points->point_set()->first_selected(); ++ it)
|
||||
m_color[*it] = CGAL::IO::Color ((unsigned char)(255 * m_points->point_set()->red(*it)),
|
||||
m_color.value()[*it] = CGAL::IO::Color ((unsigned char)(255 * m_points->point_set()->red(*it)),
|
||||
(unsigned char)(255 * m_points->point_set()->green(*it)),
|
||||
(unsigned char)(255 * m_points->point_set()->blue(*it)));
|
||||
|
||||
|
|
@ -403,15 +402,15 @@ void Cluster_classification::backup_existing_colors_and_add_new()
|
|||
|
||||
void Cluster_classification::reset_colors()
|
||||
{
|
||||
if (m_color == Point_set::Property_map<CGAL::IO::Color>())
|
||||
if (!m_color)
|
||||
m_points->point_set()->remove_colors();
|
||||
else
|
||||
{
|
||||
for (Point_set::const_iterator it = m_points->point_set()->begin();
|
||||
it != m_points->point_set()->first_selected(); ++ it)
|
||||
m_points->point_set()->set_color(*it, m_color[*it]);
|
||||
m_points->point_set()->set_color(*it, m_color.value()[*it]);
|
||||
|
||||
m_points->point_set()->remove_property_map(m_color);
|
||||
m_points->point_set()->remove_property_map(m_color.value());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -438,7 +437,7 @@ void Cluster_classification::change_color (int index, float* vmin, float* vmax)
|
|||
|
||||
for (Point_set::const_iterator it = m_points->point_set()->begin();
|
||||
it != m_points->point_set()->first_selected(); ++ it)
|
||||
m_points->point_set()->set_color(*it, m_color[*it]);
|
||||
m_points->point_set()->set_color(*it, m_color.value()[*it]);
|
||||
}
|
||||
else if (index_color == 1) // classif
|
||||
{
|
||||
|
|
@ -446,7 +445,7 @@ void Cluster_classification::change_color (int index, float* vmin, float* vmax)
|
|||
it != m_points->point_set()->first_selected(); ++ it)
|
||||
{
|
||||
QColor color (0, 0, 0);
|
||||
int cid = m_cluster_id[*it];
|
||||
int cid = m_cluster_id.value()[*it];
|
||||
if (cid != -1)
|
||||
{
|
||||
std::size_t c = m_clusters[cid].label();
|
||||
|
|
@ -464,7 +463,7 @@ void Cluster_classification::change_color (int index, float* vmin, float* vmax)
|
|||
it != m_points->point_set()->first_selected(); ++ it)
|
||||
{
|
||||
QColor color (0, 0, 0);
|
||||
int cid = m_cluster_id[*it];
|
||||
int cid = m_cluster_id.value()[*it];
|
||||
float div = 1;
|
||||
|
||||
if (cid != -1)
|
||||
|
|
@ -486,7 +485,7 @@ void Cluster_classification::change_color (int index, float* vmin, float* vmax)
|
|||
for (Point_set::const_iterator it = m_points->point_set()->begin();
|
||||
it != m_points->point_set()->first_selected(); ++ it)
|
||||
{
|
||||
int cid = m_cluster_id[*it];
|
||||
int cid = m_cluster_id.value()[*it];
|
||||
|
||||
if (cid != -1)
|
||||
{
|
||||
|
|
@ -516,7 +515,7 @@ void Cluster_classification::change_color (int index, float* vmin, float* vmax)
|
|||
for (Point_set::const_iterator it = m_points->point_set()->begin();
|
||||
it != m_points->point_set()->first_selected(); ++ it)
|
||||
{
|
||||
int cid = m_cluster_id[*it];
|
||||
int cid = m_cluster_id.value()[*it];
|
||||
if (cid != -1)
|
||||
{
|
||||
float v = (std::max) (0.f, (std::min)(1.f, m_label_probabilities[corrected_index][cid]));
|
||||
|
|
@ -553,7 +552,7 @@ void Cluster_classification::change_color (int index, float* vmin, float* vmax)
|
|||
for (Point_set::const_iterator it = m_points->point_set()->begin();
|
||||
it != m_points->point_set()->first_selected(); ++ it)
|
||||
{
|
||||
int cid = m_cluster_id[*it];
|
||||
int cid = m_cluster_id.value()[*it];
|
||||
if (cid != -1)
|
||||
{
|
||||
if (feature->value(cid) > max)
|
||||
|
|
@ -567,7 +566,7 @@ void Cluster_classification::change_color (int index, float* vmin, float* vmax)
|
|||
for (Point_set::const_iterator it = m_points->point_set()->begin();
|
||||
it != m_points->point_set()->first_selected(); ++ it)
|
||||
{
|
||||
int cid = m_cluster_id[*it];
|
||||
int cid = m_cluster_id.value()[*it];
|
||||
if (cid != -1)
|
||||
{
|
||||
float v = (feature->value(cid) - min) / (max - min);
|
||||
|
|
@ -598,15 +597,14 @@ int Cluster_classification::real_index_color() const
|
|||
{
|
||||
int out = m_index_color;
|
||||
|
||||
if (out == 0 && m_color == Point_set::Property_map<CGAL::IO::Color>())
|
||||
if (out == 0 && !m_color)
|
||||
out = -1;
|
||||
return out;
|
||||
}
|
||||
|
||||
void Cluster_classification::reset_indices ()
|
||||
{
|
||||
Point_set::Property_map<Point_set::Index> indices
|
||||
= m_points->point_set()->property_map<Point_set::Index>("index").first;
|
||||
auto indices = m_points->point_set()->property_map<Point_set::Index>("index").value();
|
||||
|
||||
m_points->point_set()->unselect_all();
|
||||
Point_set::Index idx;
|
||||
|
|
@ -629,18 +627,16 @@ void Cluster_classification::compute_features (std::size_t nb_scales, float voxe
|
|||
|
||||
m_features.clear();
|
||||
|
||||
Point_set::Vector_map normal_map;
|
||||
std::optional<Point_set::Vector_map> normal_map;
|
||||
bool normals = m_points->point_set()->has_normal_map();
|
||||
if (normals)
|
||||
normal_map = m_points->point_set()->normal_map();
|
||||
|
||||
bool colors = (m_color != Point_set::Property_map<CGAL::IO::Color>());
|
||||
bool colors = m_color.has_value();
|
||||
|
||||
Point_set::Property_map<std::uint8_t> echo_map;
|
||||
bool echo;
|
||||
boost::tie (echo_map, echo) = m_points->point_set()->template property_map<std::uint8_t>("echo");
|
||||
if (!echo)
|
||||
boost::tie (echo_map, echo) = m_points->point_set()->template property_map<std::uint8_t>("number_of_returns");
|
||||
auto echo_map = m_points->point_set()->template property_map<std::uint8_t>("echo");
|
||||
if (!echo_map)
|
||||
echo_map = m_points->point_set()->template property_map<std::uint8_t>("number_of_returns").value();
|
||||
|
||||
Feature_set pointwise_features;
|
||||
|
||||
|
|
@ -655,11 +651,11 @@ void Cluster_classification::compute_features (std::size_t nb_scales, float voxe
|
|||
|
||||
generator.generate_point_based_features(pointwise_features);
|
||||
if (normals)
|
||||
generator.generate_normal_based_features (pointwise_features, normal_map);
|
||||
generator.generate_normal_based_features (pointwise_features, normal_map.value());
|
||||
if (colors)
|
||||
generator.generate_color_based_features (pointwise_features, m_color);
|
||||
if (echo)
|
||||
generator.generate_echo_based_features (pointwise_features, echo_map);
|
||||
generator.generate_color_based_features (pointwise_features, m_color.value());
|
||||
if (echo_map)
|
||||
generator.generate_echo_based_features (pointwise_features, echo_map.value());
|
||||
|
||||
#ifdef CGAL_LINKED_WITH_TBB
|
||||
pointwise_features.end_parallel_additions();
|
||||
|
|
|
|||
|
|
@ -125,13 +125,12 @@ class Cluster_classification : public Item_classification_base
|
|||
{
|
||||
typedef typename Point_set::template Property_map<Type> Pmap;
|
||||
bool okay = false;
|
||||
Pmap pmap;
|
||||
boost::tie (pmap, okay) = m_points->point_set()->template property_map<Type>(name.c_str());
|
||||
if (okay)
|
||||
auto pmap = m_points->point_set()->template property_map<Type>(name.c_str());
|
||||
if (pmap)
|
||||
feature_set.template add<CGAL::Classification::Feature::Simple_feature <Point_set, Pmap> >
|
||||
(*(m_points->point_set()), pmap, name.c_str());
|
||||
(*(m_points->point_set()), pmap.value(), name.c_str());
|
||||
|
||||
return okay;
|
||||
return pmap.has_value();
|
||||
}
|
||||
|
||||
void add_selection_to_training_set (std::size_t label)
|
||||
|
|
@ -139,7 +138,7 @@ class Cluster_classification : public Item_classification_base
|
|||
for (Point_set::const_iterator it = m_points->point_set()->first_selected();
|
||||
it != m_points->point_set()->end(); ++ it)
|
||||
{
|
||||
int cid = m_cluster_id[*it];
|
||||
int cid = m_cluster_id.value()[*it];
|
||||
if (cid != -1)
|
||||
{
|
||||
m_clusters[cid].training() = int(label);
|
||||
|
|
@ -165,7 +164,7 @@ class Cluster_classification : public Item_classification_base
|
|||
for (Point_set::const_iterator it = m_points->point_set()->first_selected();
|
||||
it != m_points->point_set()->end(); ++ it)
|
||||
{
|
||||
int cid = m_cluster_id[*it];
|
||||
int cid = m_cluster_id.value()[*it];
|
||||
if (cid != -1)
|
||||
{
|
||||
m_clusters[cid].training() = -1;
|
||||
|
|
@ -187,7 +186,7 @@ class Cluster_classification : public Item_classification_base
|
|||
for (Point_set::const_iterator it = m_points->point_set()->first_selected();
|
||||
it != m_points->point_set()->end(); ++ it)
|
||||
{
|
||||
int cid = m_cluster_id[*it];
|
||||
int cid = m_cluster_id.value()[*it];
|
||||
if (cid != -1)
|
||||
m_clusters[cid].training() = m_clusters[cid].label();
|
||||
}
|
||||
|
|
@ -212,7 +211,7 @@ class Cluster_classification : public Item_classification_base
|
|||
for (Point_set::const_iterator it = m_points->point_set()->begin();
|
||||
it != m_points->point_set()->end(); ++ it)
|
||||
{
|
||||
int cid = m_cluster_id[*it];
|
||||
int cid = m_cluster_id.value()[*it];
|
||||
if (cid != -1)
|
||||
{
|
||||
int c = m_clusters[cid].label();
|
||||
|
|
@ -238,7 +237,7 @@ class Cluster_classification : public Item_classification_base
|
|||
for (Point_set::const_iterator it = m_points->point_set()->begin();
|
||||
it != m_points->point_set()->end(); ++ it)
|
||||
{
|
||||
int cid = m_cluster_id[*it];
|
||||
int cid = m_cluster_id.value()[*it];
|
||||
if (cid != -1)
|
||||
{
|
||||
int c = m_clusters[cid].label();
|
||||
|
|
@ -376,13 +375,10 @@ class Cluster_classification : public Item_classification_base
|
|||
|
||||
std::vector<Cluster> m_clusters;
|
||||
|
||||
Point_set::Property_map<unsigned char> m_red;
|
||||
Point_set::Property_map<unsigned char> m_green;
|
||||
Point_set::Property_map<unsigned char> m_blue;
|
||||
Point_set::Property_map<CGAL::IO::Color> m_color;
|
||||
Point_set::Property_map<int> m_cluster_id;
|
||||
Point_set::Property_map<int> m_training;
|
||||
Point_set::Property_map<int> m_classif;
|
||||
std::optional<Point_set::Property_map<CGAL::IO::Color>> m_color;
|
||||
std::optional<Point_set::Property_map<int>> m_cluster_id;
|
||||
std::optional<Point_set::Property_map<int>> m_training;
|
||||
std::optional<Point_set::Property_map<int>> m_classif;
|
||||
|
||||
std::vector<std::vector<float> > m_label_probabilities;
|
||||
|
||||
|
|
|
|||
|
|
@ -16,23 +16,20 @@
|
|||
#include <algorithm>
|
||||
|
||||
Point_set_item_classification::Point_set_item_classification(Scene_points_with_normal_item* points)
|
||||
: m_points (points)
|
||||
, m_generator (nullptr)
|
||||
, m_input_is_las (false)
|
||||
{
|
||||
: m_points(points), m_generator(nullptr), m_input_is_las(false),
|
||||
m_training(),
|
||||
m_classif(){
|
||||
m_index_color = 1;
|
||||
|
||||
reset_indices();
|
||||
|
||||
Point_set::Property_map<int> cluster_id;
|
||||
bool cluster_found = false;
|
||||
boost::tie (cluster_id, cluster_found) = m_points->point_set()->property_map<int>("shape");
|
||||
if (cluster_found)
|
||||
auto cluster_id = m_points->point_set()->property_map<int>("shape");
|
||||
if (cluster_id)
|
||||
{
|
||||
for (Point_set::const_iterator it = m_points->point_set()->begin();
|
||||
it != m_points->point_set()->first_selected(); ++ it)
|
||||
{
|
||||
int c = cluster_id[*it];
|
||||
int c = cluster_id.value()[*it];
|
||||
if (c == -1)
|
||||
continue;
|
||||
if (std::size_t(c) >= m_clusters.size())
|
||||
|
|
@ -54,20 +51,20 @@ Point_set_item_classification::Point_set_item_classification(Scene_points_with_n
|
|||
|
||||
if (!classif_found)
|
||||
{
|
||||
Point_set::Property_map<unsigned char> las_classif;
|
||||
boost::tie (las_classif, las_found) = m_points->point_set()->property_map<unsigned char>("classification");
|
||||
if (las_found)
|
||||
auto las_classif = m_points->point_set()->property_map<unsigned char>("classification");
|
||||
las_found = las_classif.has_value();
|
||||
if (las_classif)
|
||||
{
|
||||
m_input_is_las = true;
|
||||
for (Point_set::const_iterator it = m_points->point_set()->begin();
|
||||
it != m_points->point_set()->first_selected(); ++ it)
|
||||
{
|
||||
unsigned char uc = las_classif[*it];
|
||||
m_classif[*it] = int(uc);
|
||||
unsigned char uc = las_classif.value()[*it];
|
||||
m_classif.value()[*it] = int(uc);
|
||||
if (!training_found)
|
||||
m_training[*it] = int(uc);
|
||||
m_training.value()[*it] = int(uc);
|
||||
}
|
||||
m_points->point_set()->remove_property_map (las_classif);
|
||||
m_points->point_set()->remove_property_map (las_classif.value());
|
||||
classif_found = true;
|
||||
training_found = true;
|
||||
}
|
||||
|
|
@ -82,7 +79,7 @@ Point_set_item_classification::Point_set_item_classification(Scene_points_with_n
|
|||
{
|
||||
if (training_found)
|
||||
{
|
||||
int l = m_training[*it];
|
||||
int l = m_training.value()[*it];
|
||||
if (l >= 0)
|
||||
{
|
||||
if (std::size_t(l) >= used_indices.size())
|
||||
|
|
@ -92,7 +89,7 @@ Point_set_item_classification::Point_set_item_classification(Scene_points_with_n
|
|||
}
|
||||
if (classif_found)
|
||||
{
|
||||
int l = m_classif[*it];
|
||||
int l = m_classif.value()[*it];
|
||||
if (l >= 0)
|
||||
{
|
||||
if (std::size_t(l) >= used_indices.size())
|
||||
|
|
@ -125,17 +122,17 @@ Point_set_item_classification::Point_set_item_classification(Scene_points_with_n
|
|||
{
|
||||
if (training_found)
|
||||
{
|
||||
if (las_found && (m_training[*it] == 0 || m_training[*it] == 1)) // Unclassified class in LAS
|
||||
m_training[*it] = -1;
|
||||
else if (m_training[*it] != -1)
|
||||
m_training[*it] = used_indices[std::size_t(m_training[*it])];
|
||||
if (las_found && (m_training.value()[*it] == 0 || m_training.value()[*it] == 1)) // Unclassified class in LAS
|
||||
m_training.value()[*it] = -1;
|
||||
else if (m_training.value()[*it] != -1)
|
||||
m_training.value()[*it] = used_indices[std::size_t(m_training.value()[*it])];
|
||||
}
|
||||
if (classif_found)
|
||||
{
|
||||
if (las_found && (m_classif[*it] == 0 || m_classif[*it] == 1)) // Unclassified class in LAS
|
||||
m_classif[*it] = -1;
|
||||
else if (m_classif[*it] != -1)
|
||||
m_classif[*it] = used_indices[std::size_t(m_classif[*it])];
|
||||
if (las_found && (m_classif.value()[*it] == 0 || m_classif.value()[*it] == 1)) // Unclassified class in LAS
|
||||
m_classif.value()[*it] = -1;
|
||||
else if (m_classif.value()[*it] != -1)
|
||||
m_classif.value()[*it] = used_indices[std::size_t(m_classif.value()[*it])];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -295,22 +292,22 @@ Point_set_item_classification::~Point_set_item_classification()
|
|||
for (Point_set::const_iterator it = m_points->point_set()->begin();
|
||||
it != m_points->point_set()->end(); ++ it)
|
||||
{
|
||||
int c = m_classif[*it];
|
||||
int c = m_classif.value()[*it];
|
||||
unsigned char lc = 1; // unclassified in LAS standard
|
||||
if (c != -1)
|
||||
lc = label_indices[std::size_t(c)];
|
||||
|
||||
las_classif[*it] = lc;
|
||||
|
||||
int t = m_training[*it];
|
||||
int t = m_training.value()[*it];
|
||||
unsigned char lt = 1; // unclassified in LAS standard
|
||||
if (t != -1)
|
||||
lt = label_indices[std::size_t(t)];
|
||||
|
||||
m_training[*it] = int(lt);
|
||||
m_training.value()[*it] = int(lt);
|
||||
}
|
||||
|
||||
m_points->point_set()->remove_property_map (m_classif);
|
||||
m_points->point_set()->remove_property_map (m_classif.value());
|
||||
}
|
||||
|
||||
reset_colors();
|
||||
|
|
@ -327,7 +324,7 @@ void Point_set_item_classification::backup_existing_colors_and_add_new()
|
|||
m_color = m_points->point_set()->add_property_map<CGAL::IO::Color>("real_color").first;
|
||||
for (Point_set::const_iterator it = m_points->point_set()->begin();
|
||||
it != m_points->point_set()->first_selected(); ++ it)
|
||||
m_color[*it] = CGAL::IO::Color((unsigned char)(255 * m_points->point_set()->red(*it)),
|
||||
m_color.value()[*it] = CGAL::IO::Color((unsigned char)(255 * m_points->point_set()->red(*it)),
|
||||
(unsigned char)(255 * m_points->point_set()->green(*it)),
|
||||
(unsigned char)(255 * m_points->point_set()->blue(*it)));
|
||||
|
||||
|
|
@ -339,15 +336,15 @@ void Point_set_item_classification::backup_existing_colors_and_add_new()
|
|||
|
||||
void Point_set_item_classification::reset_colors()
|
||||
{
|
||||
if (m_color == Point_set::Property_map<CGAL::IO::Color>())
|
||||
if (!m_color)
|
||||
m_points->point_set()->remove_colors();
|
||||
else
|
||||
{
|
||||
for (Point_set::const_iterator it = m_points->point_set()->begin();
|
||||
it != m_points->point_set()->first_selected(); ++ it)
|
||||
m_points->point_set()->set_color(*it, m_color[*it]);
|
||||
m_points->point_set()->set_color(*it, m_color.value()[*it]);
|
||||
|
||||
m_points->point_set()->remove_property_map(m_color);
|
||||
m_points->point_set()->remove_property_map(m_color.value());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -374,7 +371,7 @@ void Point_set_item_classification::change_color (int index, float* vmin, float*
|
|||
|
||||
for (Point_set::const_iterator it = m_points->point_set()->begin();
|
||||
it != m_points->point_set()->first_selected(); ++ it)
|
||||
m_points->point_set()->set_color(*it, m_color[*it]);
|
||||
m_points->point_set()->set_color(*it, m_color.value()[*it]);
|
||||
}
|
||||
else if (index_color == 1) // classif
|
||||
{
|
||||
|
|
@ -382,7 +379,7 @@ void Point_set_item_classification::change_color (int index, float* vmin, float*
|
|||
it != m_points->point_set()->first_selected(); ++ it)
|
||||
{
|
||||
QColor color (0, 0, 0);
|
||||
std::size_t c = m_classif[*it];
|
||||
std::size_t c = m_classif.value()[*it];
|
||||
|
||||
if (c != std::size_t(-1))
|
||||
color = label_qcolor (m_labels[c]);
|
||||
|
|
@ -396,8 +393,8 @@ void Point_set_item_classification::change_color (int index, float* vmin, float*
|
|||
it != m_points->point_set()->first_selected(); ++ it)
|
||||
{
|
||||
QColor color (0, 0, 0);
|
||||
int c = m_training[*it];
|
||||
int c2 = m_classif[*it];
|
||||
int c = m_training.value()[*it];
|
||||
int c2 = m_classif.value()[*it];
|
||||
|
||||
if (c != -1)
|
||||
color = label_qcolor (m_labels[std::size_t(c)]);
|
||||
|
|
@ -490,15 +487,14 @@ int Point_set_item_classification::real_index_color() const
|
|||
{
|
||||
int out = m_index_color;
|
||||
|
||||
if (out == 0 && m_color == Point_set::Property_map<CGAL::IO::Color>())
|
||||
if (out == 0 && !m_color)
|
||||
out = -1;
|
||||
return out;
|
||||
}
|
||||
|
||||
void Point_set_item_classification::reset_indices ()
|
||||
{
|
||||
Point_set::Property_map<Point_set::Index> indices
|
||||
= m_points->point_set()->property_map<Point_set::Index>("index").first;
|
||||
auto indices = m_points->point_set()->property_map<Point_set::Index>("index").value();
|
||||
|
||||
m_points->point_set()->unselect_all();
|
||||
Point_set::Index idx;
|
||||
|
|
@ -524,18 +520,16 @@ void Point_set_item_classification::compute_features (std::size_t nb_scales, flo
|
|||
|
||||
m_features.clear();
|
||||
|
||||
Point_set::Vector_map normal_map;
|
||||
std::optional<Point_set::Vector_map> normal_map;
|
||||
bool normals = m_points->point_set()->has_normal_map();
|
||||
if (normals)
|
||||
normal_map = m_points->point_set()->normal_map();
|
||||
|
||||
bool colors = (m_color != Point_set::Property_map<CGAL::IO::Color>());
|
||||
bool colors = m_color.has_value();
|
||||
|
||||
Point_set::Property_map<std::uint8_t> echo_map;
|
||||
bool echo;
|
||||
boost::tie (echo_map, echo) = m_points->point_set()->template property_map<std::uint8_t>("echo");
|
||||
if (!echo)
|
||||
boost::tie (echo_map, echo) = m_points->point_set()->template property_map<std::uint8_t>("number_of_returns");
|
||||
auto echo_map = m_points->point_set()->template property_map<std::uint8_t>("echo");
|
||||
if (!echo_map)
|
||||
echo_map = m_points->point_set()->template add_property_map<std::uint8_t>("number_of_returns").first;
|
||||
|
||||
m_generator = new Generator (*(m_points->point_set()), m_points->point_set()->point_map(), nb_scales, voxel_size);
|
||||
|
||||
|
|
@ -548,11 +542,11 @@ void Point_set_item_classification::compute_features (std::size_t nb_scales, flo
|
|||
|
||||
m_generator->generate_point_based_features(m_features);
|
||||
if (normals)
|
||||
m_generator->generate_normal_based_features (m_features, normal_map);
|
||||
m_generator->generate_normal_based_features (m_features, normal_map.value());
|
||||
if (colors)
|
||||
m_generator->generate_color_based_features (m_features, m_color);
|
||||
if (echo)
|
||||
m_generator->generate_echo_based_features (m_features, echo_map);
|
||||
m_generator->generate_color_based_features (m_features, m_color.value());
|
||||
if (echo_map)
|
||||
m_generator->generate_echo_based_features (m_features, echo_map.value());
|
||||
|
||||
#ifdef CGAL_LINKED_WITH_TBB
|
||||
m_features.end_parallel_additions();
|
||||
|
|
@ -709,7 +703,7 @@ void Point_set_item_classification::train(int classifier, const QMultipleInputDi
|
|||
for (Point_set::const_iterator it = m_points->point_set()->begin();
|
||||
it != m_points->point_set()->first_selected(); ++ it)
|
||||
{
|
||||
training[*it] = m_training[*it];
|
||||
training[*it] = m_training.value()[*it];
|
||||
if (training[*it] != -1)
|
||||
{
|
||||
nb_label[std::size_t(training[*it])] ++;
|
||||
|
|
@ -758,7 +752,7 @@ void Point_set_item_classification::train(int classifier, const QMultipleInputDi
|
|||
|
||||
for (Point_set::const_iterator it = m_points->point_set()->begin();
|
||||
it != m_points->point_set()->first_selected(); ++ it)
|
||||
m_classif[*it] = indices[*it];
|
||||
m_classif.value()[*it] = indices[*it];
|
||||
|
||||
if (m_index_color == 1 || m_index_color == 2)
|
||||
change_color (m_index_color);
|
||||
|
|
|
|||
|
|
@ -47,13 +47,9 @@ class Point_set_item_classification : public Item_classification_base
|
|||
Point_set::Property_map<int> cluster_id;
|
||||
std::vector<Cluster>* clusters;
|
||||
|
||||
Cluster_neighborhood (Point_set* point_set,
|
||||
std::vector<Cluster>& clusters)
|
||||
: point_set (point_set)
|
||||
, clusters (&clusters)
|
||||
{
|
||||
cluster_id = point_set->property_map<int>("shape").first;
|
||||
}
|
||||
Cluster_neighborhood(Point_set* point_set,
|
||||
std::vector<Cluster>& clusters)
|
||||
: point_set(point_set), clusters(&clusters), cluster_id(point_set->add_property_map<int>("shape").first) {}
|
||||
|
||||
template <typename OutputIterator>
|
||||
OutputIterator operator() (const Point_set::Index& idx,
|
||||
|
|
@ -147,18 +143,16 @@ class Point_set_item_classification : public Item_classification_base
|
|||
bool try_adding_simple_feature (const std::string& name)
|
||||
{
|
||||
typedef typename Point_set::template Property_map<Type> Pmap;
|
||||
bool okay = false;
|
||||
Pmap pmap;
|
||||
boost::tie (pmap, okay) = m_points->point_set()->template property_map<Type>(name.c_str());
|
||||
if (okay)
|
||||
auto pmap = m_points->point_set()->template property_map<Type>(name.c_str());
|
||||
if (pmap)
|
||||
{
|
||||
std::cerr << "Adding property<" << CGAL::demangle(typeid(Type).name()) << ">("
|
||||
<< name << ") as feature" << std::endl;
|
||||
m_features.template add<CGAL::Classification::Feature::Simple_feature <Point_set, Pmap> >
|
||||
(*(m_points->point_set()), pmap, name.c_str());
|
||||
(*(m_points->point_set()), pmap.value(), name.c_str());
|
||||
}
|
||||
|
||||
return okay;
|
||||
return pmap.has_value();
|
||||
}
|
||||
|
||||
void add_selection_to_training_set (std::size_t label)
|
||||
|
|
@ -166,8 +160,8 @@ class Point_set_item_classification : public Item_classification_base
|
|||
for (Point_set::const_iterator it = m_points->point_set()->first_selected();
|
||||
it != m_points->point_set()->end(); ++ it)
|
||||
{
|
||||
m_training[*it] = int(label);
|
||||
m_classif[*it] = int(label);
|
||||
m_training.value()[*it] = int(label);
|
||||
m_classif.value()[*it] = int(label);
|
||||
}
|
||||
|
||||
m_points->resetSelection();
|
||||
|
|
@ -178,8 +172,8 @@ class Point_set_item_classification : public Item_classification_base
|
|||
{
|
||||
for (Point_set::const_iterator it = m_points->point_set()->begin();
|
||||
it != m_points->point_set()->end(); ++ it)
|
||||
if (m_training[*it] == int(label))
|
||||
m_training[*it] = -1;
|
||||
if (m_training.value()[*it] == int(label))
|
||||
m_training.value()[*it] = -1;
|
||||
if (m_index_color == 1 || m_index_color == 2)
|
||||
change_color (m_index_color);
|
||||
}
|
||||
|
|
@ -188,8 +182,8 @@ class Point_set_item_classification : public Item_classification_base
|
|||
for (Point_set::const_iterator it = m_points->point_set()->first_selected();
|
||||
it != m_points->point_set()->end(); ++ it)
|
||||
{
|
||||
m_training[*it] = -1;
|
||||
m_classif[*it] = -1;
|
||||
m_training.value()[*it] = -1;
|
||||
m_classif.value()[*it] = -1;
|
||||
}
|
||||
if (m_index_color == 1 || m_index_color == 2)
|
||||
change_color (m_index_color);
|
||||
|
|
@ -198,7 +192,7 @@ class Point_set_item_classification : public Item_classification_base
|
|||
{
|
||||
for (Point_set::const_iterator it = m_points->point_set()->begin();
|
||||
it != m_points->point_set()->end(); ++ it)
|
||||
m_training[*it] = -1;
|
||||
m_training.value()[*it] = -1;
|
||||
if (m_index_color == 1 || m_index_color == 2)
|
||||
change_color (m_index_color);
|
||||
}
|
||||
|
|
@ -206,7 +200,7 @@ class Point_set_item_classification : public Item_classification_base
|
|||
{
|
||||
for (Point_set::const_iterator it = m_points->point_set()->first_selected();
|
||||
it != m_points->point_set()->end(); ++ it)
|
||||
m_training[*it] = m_classif[*it];
|
||||
m_training.value()[*it] = m_classif.value()[*it];
|
||||
|
||||
m_points->resetSelection();
|
||||
if (m_index_color == 1 || m_index_color == 2)
|
||||
|
|
@ -229,7 +223,7 @@ class Point_set_item_classification : public Item_classification_base
|
|||
for (Point_set::const_iterator it = m_points->point_set()->begin();
|
||||
it != m_points->point_set()->end(); ++ it)
|
||||
{
|
||||
int c = m_classif[*it];
|
||||
int c = m_classif.value()[*it];
|
||||
if (c == label)
|
||||
points_item->point_set()->insert (m_points->point_set()->point(*it));
|
||||
}
|
||||
|
|
@ -251,7 +245,7 @@ class Point_set_item_classification : public Item_classification_base
|
|||
for (Point_set::const_iterator it = m_points->point_set()->begin();
|
||||
it != m_points->point_set()->end(); ++ it)
|
||||
{
|
||||
int c = m_classif[*it];
|
||||
int c = m_classif.value()[*it];
|
||||
if (c != -1)
|
||||
points_item[c]->point_set()->insert (m_points->point_set()->point(*it));
|
||||
}
|
||||
|
|
@ -271,15 +265,15 @@ class Point_set_item_classification : public Item_classification_base
|
|||
for (Point_set::const_iterator it = m_points->point_set()->begin();
|
||||
it != m_points->point_set()->end(); ++ it)
|
||||
{
|
||||
if (m_training[*it] == int(position))
|
||||
m_training[*it] = -1;
|
||||
else if (m_training[*it] > int(position))
|
||||
m_training[*it] --;
|
||||
if (m_training.value()[*it] == int(position))
|
||||
m_training.value()[*it] = -1;
|
||||
else if (m_training.value()[*it] > int(position))
|
||||
m_training.value()[*it] --;
|
||||
|
||||
if (m_classif[*it] == int(position))
|
||||
m_classif[*it] = -1;
|
||||
else if (m_classif[*it] > int(position))
|
||||
m_classif[*it] --;
|
||||
if (m_classif.value()[*it] == int(position))
|
||||
m_classif.value()[*it] = -1;
|
||||
else if (m_classif.value()[*it] > int(position))
|
||||
m_classif.value()[*it] --;
|
||||
}
|
||||
update_comments_of_point_set_item();
|
||||
}
|
||||
|
|
@ -364,8 +358,8 @@ class Point_set_item_classification : public Item_classification_base
|
|||
for (Point_set::const_iterator it = m_points->point_set()->begin();
|
||||
it != m_points->point_set()->first_selected(); ++ it)
|
||||
{
|
||||
m_classif[*it] = indices[*it];
|
||||
ground_truth[*it] = m_training[*it];
|
||||
m_classif.value()[*it] = indices[*it];
|
||||
ground_truth[*it] = m_training.value()[*it];
|
||||
}
|
||||
|
||||
if (m_index_color == 1 || m_index_color == 2)
|
||||
|
|
@ -396,14 +390,11 @@ class Point_set_item_classification : public Item_classification_base
|
|||
|
||||
std::vector<Cluster> m_clusters;
|
||||
|
||||
Point_set::Property_map<unsigned char> m_red;
|
||||
Point_set::Property_map<unsigned char> m_green;
|
||||
Point_set::Property_map<unsigned char> m_blue;
|
||||
Point_set::Property_map<CGAL::IO::Color> m_color;
|
||||
std::optional<Point_set::Property_map<CGAL::IO::Color>> m_color;
|
||||
std::vector<std::vector<float> > m_label_probabilities;
|
||||
|
||||
Point_set::Property_map<int> m_training;
|
||||
Point_set::Property_map<int> m_classif;
|
||||
std::optional<Point_set::Property_map<int>> m_training;
|
||||
std::optional<Point_set::Property_map<int>> m_classif;
|
||||
|
||||
Generator* m_generator;
|
||||
|
||||
|
|
|
|||
|
|
@ -15,13 +15,13 @@
|
|||
Surface_mesh_item_classification::Surface_mesh_item_classification(Scene_surface_mesh_item* mesh)
|
||||
: m_mesh (mesh),
|
||||
m_selection (nullptr),
|
||||
m_generator (nullptr)
|
||||
m_generator (nullptr),
|
||||
m_training(m_mesh->polyhedron()->add_property_map<face_descriptor, std::size_t>("f:training", std::size_t(-1)).first),
|
||||
m_classif(m_mesh->polyhedron()->add_property_map<face_descriptor, std::size_t>("f:label", std::size_t(-1)).first)
|
||||
{
|
||||
m_index_color = 1;
|
||||
|
||||
backup_existing_colors_and_add_new();
|
||||
m_training = m_mesh->polyhedron()->add_property_map<face_descriptor, std::size_t>("f:training", std::size_t(-1)).first;
|
||||
m_classif = m_mesh->polyhedron()->add_property_map<face_descriptor, std::size_t>("f:label", std::size_t(-1)).first;
|
||||
|
||||
m_labels.add("ground");
|
||||
m_labels.add("vegetation");
|
||||
|
|
@ -64,8 +64,8 @@ void Surface_mesh_item_classification::backup_existing_colors_and_add_new()
|
|||
= m_mesh->polyhedron()->add_property_map<face_descriptor, CGAL::IO::Color>("f:real_color").first;
|
||||
for(face_descriptor fd : faces(*(m_mesh->polyhedron())))
|
||||
{
|
||||
m_real_color[fd] = m_color[fd];
|
||||
m_color[fd] = CGAL::IO::Color(128, 128, 128);
|
||||
m_real_color.value()[fd] = m_color.value()[fd];
|
||||
m_color.value()[fd] = CGAL::IO::Color(128, 128, 128);
|
||||
}
|
||||
}
|
||||
else
|
||||
|
|
@ -77,7 +77,7 @@ void Surface_mesh_item_classification::change_color (int index, float* vmin, flo
|
|||
{
|
||||
m_index_color = index;
|
||||
int index_color = index;
|
||||
if (index == 0 && m_real_color == Mesh::Property_map<face_descriptor, CGAL::IO::Color>())
|
||||
if (index == 0 && !m_real_color)
|
||||
index_color = -1;
|
||||
|
||||
static Color_ramp ramp;
|
||||
|
|
@ -86,12 +86,12 @@ void Surface_mesh_item_classification::change_color (int index, float* vmin, flo
|
|||
if (index_color == -1) // item color
|
||||
{
|
||||
for(face_descriptor fd : faces(*(m_mesh->polyhedron())))
|
||||
m_color[fd] = CGAL::IO::Color(128,128,128);
|
||||
m_color.value()[fd] = CGAL::IO::Color(128,128,128);
|
||||
}
|
||||
else if (index_color == 0) // real colors
|
||||
{
|
||||
for(face_descriptor fd : faces(*(m_mesh->polyhedron())))
|
||||
m_color[fd] = m_real_color[fd];
|
||||
m_color.value()[fd] = m_real_color.value()[fd];
|
||||
}
|
||||
else if (index_color == 1) // classif
|
||||
{
|
||||
|
|
@ -103,7 +103,7 @@ void Surface_mesh_item_classification::change_color (int index, float* vmin, flo
|
|||
if (c != std::size_t(-1))
|
||||
color = label_qcolor (m_labels[c]);
|
||||
|
||||
m_color[fd] = CGAL::IO::Color(color.red(), color.green(), color.blue());
|
||||
m_color.value()[fd] = CGAL::IO::Color(color.red(), color.green(), color.blue());
|
||||
}
|
||||
}
|
||||
else if (index_color == 2) // training
|
||||
|
|
@ -120,7 +120,7 @@ void Surface_mesh_item_classification::change_color (int index, float* vmin, flo
|
|||
float div = 1;
|
||||
if (c != c2)
|
||||
div = 2;
|
||||
m_color[fd] = CGAL::IO::Color(color.red() / div,
|
||||
m_color.value()[fd] = CGAL::IO::Color(color.red() / div,
|
||||
color.green() / div,
|
||||
color.blue() / div);
|
||||
}
|
||||
|
|
@ -135,7 +135,7 @@ void Surface_mesh_item_classification::change_color (int index, float* vmin, flo
|
|||
{
|
||||
for(face_descriptor fd : faces(*(m_mesh->polyhedron())))
|
||||
{
|
||||
m_color[fd] = CGAL::IO::Color((unsigned char)(128),
|
||||
m_color.value()[fd] = CGAL::IO::Color((unsigned char)(128),
|
||||
(unsigned char)(128),
|
||||
(unsigned char)(128));
|
||||
}
|
||||
|
|
@ -145,7 +145,7 @@ void Surface_mesh_item_classification::change_color (int index, float* vmin, flo
|
|||
for(face_descriptor fd : faces(*(m_mesh->polyhedron())))
|
||||
{
|
||||
float v = (std::max) (0.f, (std::min)(1.f, m_label_probabilities[corrected_index][fd]));
|
||||
m_color[fd] = CGAL::IO::Color((unsigned char)(ramp.r(v) * 255),
|
||||
m_color.value()[fd] = CGAL::IO::Color((unsigned char)(ramp.r(v) * 255),
|
||||
(unsigned char)(ramp.g(v) * 255),
|
||||
(unsigned char)(ramp.b(v) * 255));
|
||||
}
|
||||
|
|
@ -189,7 +189,7 @@ void Surface_mesh_item_classification::change_color (int index, float* vmin, flo
|
|||
if (v < 0.f) v = 0.f;
|
||||
if (v > 1.f) v = 1.f;
|
||||
|
||||
m_color[fd] = CGAL::IO::Color((unsigned char)(ramp.r(v) * 255),
|
||||
m_color.value()[fd] = CGAL::IO::Color((unsigned char)(ramp.r(v) * 255),
|
||||
(unsigned char)(ramp.g(v) * 255),
|
||||
(unsigned char)(ramp.b(v) * 255));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -200,8 +200,9 @@ protected:
|
|||
Scene_polyhedron_selection_item* m_selection;
|
||||
Mesh::Property_map<face_descriptor, std::size_t> m_training;
|
||||
Mesh::Property_map<face_descriptor, std::size_t> m_classif;
|
||||
Mesh::Property_map<face_descriptor, CGAL::IO::Color> m_color;
|
||||
Mesh::Property_map<face_descriptor, CGAL::IO::Color> m_real_color;
|
||||
|
||||
std::optional<Mesh::Property_map<face_descriptor, CGAL::IO::Color>> m_color;
|
||||
std::optional<Mesh::Property_map<face_descriptor, CGAL::IO::Color>> m_real_color;
|
||||
|
||||
std::vector<std::vector<float> > m_label_probabilities;
|
||||
|
||||
|
|
|
|||
|
|
@ -730,11 +730,9 @@ private:
|
|||
return;
|
||||
|
||||
// Here we only target the property maps added by this plugin, so 'double' is fine
|
||||
SMesh::Property_map<face_descriptor, double> property;
|
||||
bool found;
|
||||
std::tie(property, found) = sm->property_map<face_descriptor, double>(property_name);
|
||||
if(found)
|
||||
sm->remove_property_map(property);
|
||||
auto property = sm->get_property_map<face_descriptor, double>(property_name);
|
||||
if(property)
|
||||
sm->remove_property_map(property.value());
|
||||
}
|
||||
|
||||
void removePluginProperties(Scene_item* item)
|
||||
|
|
|
|||
|
|
@ -1035,7 +1035,7 @@ treat_result(Scene_item& source_item,
|
|||
float((bbox.ymin() + bbox.ymax())/2.f),
|
||||
float((bbox.zmin() + bbox.zmax())/2.f));
|
||||
|
||||
result_item->setColor(default_mesh_color);
|
||||
result_item->setColor(source_item.color());
|
||||
result_item->setRenderingMode(source_item.renderingMode());
|
||||
result_item->set_data_item(&source_item);
|
||||
|
||||
|
|
|
|||
|
|
@ -19,9 +19,8 @@ struct Construct{
|
|||
|
||||
template <typename PointRange>
|
||||
Construct(SMesh& mesh, const PointRange& points)
|
||||
: mesh(mesh)
|
||||
: mesh(mesh), vpmap(get(boost::vertex_point, mesh))
|
||||
{
|
||||
vpmap = get(boost::vertex_point, mesh);
|
||||
for (const auto& p : points)
|
||||
{
|
||||
typename boost::graph_traits<SMesh>::vertex_descriptor v;
|
||||
|
|
@ -192,8 +191,7 @@ SMesh* advancing_front (const Point_set& points,
|
|||
|
||||
if (structuring) // todo
|
||||
{
|
||||
Point_set::Property_map<int> shape_map
|
||||
= points.property_map<int>("shape").first;
|
||||
auto shape_map = points.property_map<int>("shape").value();
|
||||
|
||||
typedef CGAL::Point_set_with_structure<Kernel> Structuring;
|
||||
std::vector<Plane_3> planes;
|
||||
|
|
|
|||
|
|
@ -26,11 +26,9 @@ SMesh* polygonal_reconstruct (const Point_set& points,
|
|||
CGAL_USE (model_complexity);
|
||||
CGAL_USE (solver_name);
|
||||
|
||||
Point_set::Property_map<int> shape_map
|
||||
= points.property_map<int>("shape").first;
|
||||
auto shape_map = points.property_map<int>("shape").value();
|
||||
|
||||
Polygonal_surface_reconstruction poly
|
||||
(points, points.point_map(), points.normal_map(), shape_map);
|
||||
Polygonal_surface_reconstruction poly(points, points.point_map(), points.normal_map(), shape_map);
|
||||
|
||||
SMesh* mesh = new SMesh;
|
||||
|
||||
|
|
|
|||
|
|
@ -269,10 +269,9 @@ public :
|
|||
pen.setWidth(0);
|
||||
painter->setPen(pen);
|
||||
painter->setBrush(brush);
|
||||
SMesh::Property_map<halfedge_descriptor,float> u,v;
|
||||
|
||||
u = graph->add_property_map<halfedge_descriptor,float>("h:u", 0.0f).first;
|
||||
v = graph->add_property_map<halfedge_descriptor,float>("h:v", 0.0f).first;
|
||||
auto u = graph->add_property_map<halfedge_descriptor,float>("h:u", 0.0f).first;
|
||||
auto v = graph->add_property_map<halfedge_descriptor,float>("h:v", 0.0f).first;
|
||||
|
||||
for( Component::iterator
|
||||
fi = components->at(m_current_component).begin();
|
||||
|
|
@ -926,11 +925,8 @@ void Polyhedron_demo_parameterization_plugin::parameterize(const Parameterizatio
|
|||
QApplication::restoreOverrideCursor();
|
||||
QPointF pmin(FLT_MAX, FLT_MAX), pmax(-FLT_MAX, -FLT_MAX);
|
||||
|
||||
SMesh::Property_map<halfedge_descriptor, float> umap;
|
||||
SMesh::Property_map<halfedge_descriptor, float> vmap;
|
||||
|
||||
umap = tMesh.add_property_map<halfedge_descriptor, float>("h:u", 0.0f).first;
|
||||
vmap = tMesh.add_property_map<halfedge_descriptor, float>("h:v", 0.0f).first;
|
||||
auto umap = tMesh.add_property_map<halfedge_descriptor, float>("h:u", 0.0f).first;
|
||||
auto vmap = tMesh.add_property_map<halfedge_descriptor, float>("h:v", 0.0f).first;
|
||||
|
||||
tMesh.property_stats(std::cerr);
|
||||
Base_face_graph::Halfedge_iterator it;
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ template <typename Word_type>
|
|||
class Image_accessor
|
||||
{
|
||||
public:
|
||||
Image_accessor(const Image& im, int dx=1, int dy=1, int dz=1);
|
||||
Image_accessor(const Image& im, int dx=1, int dy=1, int dz=1, const QColor& default_color = QColor());
|
||||
|
||||
bool is_vertex_active(std::size_t i, std::size_t j, std::size_t k) const;
|
||||
const QColor& vertex_color(std::size_t i, std::size_t j, std::size_t k) const;
|
||||
|
|
@ -64,12 +64,12 @@ private:
|
|||
};
|
||||
|
||||
template <typename Word_type>
|
||||
Image_accessor<Word_type>::Image_accessor(const Image& im, int dx, int dy, int dz)
|
||||
Image_accessor<Word_type>::Image_accessor(const Image& im, int dx, int dy, int dz, const QColor& default_color)
|
||||
: im_(&im)
|
||||
, dx_(dx)
|
||||
, dy_(dy)
|
||||
, dz_(dz)
|
||||
, default_color_()
|
||||
, default_color_(default_color)
|
||||
, colors_()
|
||||
{
|
||||
const std::size_t xdim = im_->xdim();
|
||||
|
|
@ -88,14 +88,15 @@ Image_accessor<Word_type>::Image_accessor(const Image& im, int dx, int dy, int d
|
|||
}
|
||||
}
|
||||
|
||||
double i=0;
|
||||
const double starting_hue = 45./360.; // magenta
|
||||
const double nb_Colors = colors_.size()+1;
|
||||
double i=1;
|
||||
const double starting_hue = default_color.hueF();
|
||||
for ( auto it = colors_.begin(),
|
||||
end = colors_.end() ; it != end ; ++it, i += 1.)
|
||||
{
|
||||
double hue = starting_hue + 1./double(colors_.size()) * i;
|
||||
double hue = starting_hue + 1./nb_Colors * i;
|
||||
if ( hue > 1. ) { hue -= 1.; }
|
||||
it->second = QColor::fromHsvF(hue, .75, .75);
|
||||
it->second = QColor::fromHsvF(hue, default_color.saturationF(), default_color.valueF());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -762,6 +763,11 @@ void Scene_image_item::drawEdges(Viewer_interface *viewer) const
|
|||
|
||||
bool Scene_image_item::isGray() { return d->is_hidden;}
|
||||
|
||||
void Scene_image_item::setColor(QColor c) {
|
||||
color_ = c;
|
||||
invalidateOpenGLBuffers();
|
||||
}
|
||||
|
||||
void Scene_image_item::invalidateOpenGLBuffers()
|
||||
{
|
||||
setBuffersFilled(false);
|
||||
|
|
@ -788,9 +794,9 @@ void Scene_image_item::initializeBuffers(Viewer_interface *v) const
|
|||
|
||||
template <typename Word_type>
|
||||
internal::Vertex_buffer_helper*
|
||||
init_helper(const Image &im, int dx, int dy, int dz, bool is_ogl_4_3)
|
||||
init_helper(const Image &im, int dx, int dy, int dz, bool is_ogl_4_3, const QColor& default_color = QColor())
|
||||
{
|
||||
internal::Image_accessor<Word_type> image_data_accessor(im, dx, dy, dz);
|
||||
internal::Image_accessor<Word_type> image_data_accessor(im, dx, dy, dz, default_color);
|
||||
return new internal::Vertex_buffer_helper_impl<Word_type>(std::move(image_data_accessor),
|
||||
is_ogl_4_3);
|
||||
}
|
||||
|
|
@ -809,7 +815,8 @@ void Scene_image_item::computeElements() const
|
|||
CGAL_IMAGE_IO_CASE(m_image->image(),
|
||||
d->helper = init_helper<Word>(*m_image,
|
||||
d->m_voxel_scale, d->m_voxel_scale, d->m_voxel_scale,
|
||||
d->is_ogl_4_3));
|
||||
d->is_ogl_4_3,
|
||||
color_));
|
||||
d->helper->fill_buffer_data();
|
||||
getTriangleContainer(0)->allocate(
|
||||
Tc::Smooth_vertices,
|
||||
|
|
|
|||
|
|
@ -50,6 +50,8 @@ public:
|
|||
float sigma_weights() const;
|
||||
float default_sigma_weights() const;
|
||||
|
||||
void setColor(QColor c);
|
||||
|
||||
void invalidateOpenGLBuffers();
|
||||
void initializeBuffers(Viewer_interface *) const;
|
||||
void computeElements() const;
|
||||
|
|
|
|||
|
|
@ -442,6 +442,7 @@ struct Scene_triangulation_3_item_priv {
|
|||
typedef std::set<int> Indices;
|
||||
Indices surface_patch_indices_;
|
||||
Indices subdomain_indices_;
|
||||
std::unordered_map<int, int> visible_surface_patch_to_subdomain;
|
||||
std::unordered_map<int, int> id_to_compact;
|
||||
QSlider* tet_Slider;
|
||||
bool is_filterable;
|
||||
|
|
@ -643,6 +644,7 @@ Scene_triangulation_3_item::triangulation_changed()
|
|||
// Fill indices map and get max subdomain value
|
||||
d->surface_patch_indices_.clear();
|
||||
d->subdomain_indices_.clear();
|
||||
d->visible_surface_patch_to_subdomain.clear();
|
||||
d->visible_subdomain.clear();
|
||||
d->id_to_compact.clear();
|
||||
|
||||
|
|
@ -664,7 +666,18 @@ Scene_triangulation_3_item::triangulation_changed()
|
|||
end = triangulation().finite_facets_end(); fit != end; ++fit)
|
||||
{
|
||||
max = (std::max)(max, fit->first->surface_patch_index(fit->second));
|
||||
d->surface_patch_indices_.insert(fit->first->surface_patch_index(fit->second));
|
||||
int index = fit->first->surface_patch_index(fit->second);
|
||||
d->surface_patch_indices_.insert(index);
|
||||
int dom0 = fit->first->subdomain_index();
|
||||
int dom1 = fit->first->neighbor(fit->second)->subdomain_index();
|
||||
if (dom0 == 0) // if cell is not in complex
|
||||
{
|
||||
d->visible_surface_patch_to_subdomain[index] = dom1;
|
||||
}
|
||||
else if (dom1 == 0) // if opposite cell is not in complex
|
||||
{
|
||||
d->visible_surface_patch_to_subdomain[index] = dom0;
|
||||
}
|
||||
}
|
||||
|
||||
d->colors.resize(max + 1);
|
||||
|
|
@ -882,12 +895,19 @@ Scene_triangulation_3_item_priv::compute_color_map(const QColor& c)
|
|||
}
|
||||
const size_type nb_patch_indices = surface_patch_indices_.size();
|
||||
i = 0;
|
||||
double patch_hsv_value = fmod(c.valueF() + .5, 1.);
|
||||
for (Indices::iterator it = surface_patch_indices_.begin(),
|
||||
end = surface_patch_indices_.end(); it != end; ++it, i += 1.)
|
||||
{
|
||||
double hue = c.hueF() + 1. / double(nb_patch_indices) * i;
|
||||
if (hue > 1) { hue -= 1.; }
|
||||
colors[*it] = QColor::fromHsvF(hue, c.saturationF(), c.valueF());
|
||||
colors[*it] = QColor::fromHsvF(hue, c.saturationF(), patch_hsv_value);
|
||||
}
|
||||
|
||||
for (std::unordered_map<int, int>::iterator it = visible_surface_patch_to_subdomain.begin(),
|
||||
end = visible_surface_patch_to_subdomain.end(); it != end; ++it)
|
||||
{
|
||||
colors[it->first] = colors_subdomains[it->second];
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -295,17 +295,17 @@ public:
|
|||
|
||||
void set_color (const Index& index, const QColor& color)
|
||||
{
|
||||
m_red[index] = color.red();
|
||||
m_green[index] = color.green();
|
||||
m_blue[index] = color.blue();
|
||||
m_red.value()[index] = color.red();
|
||||
m_green.value()[index] = color.green();
|
||||
m_blue.value()[index] = color.blue();
|
||||
}
|
||||
|
||||
template <typename ColorRange>
|
||||
void set_color (const Index& index, const ColorRange& color)
|
||||
{
|
||||
m_red[index] = color[0];
|
||||
m_green[index] = color[1];
|
||||
m_blue[index] = color[2];
|
||||
m_red.value()[index] = color[0];
|
||||
m_green.value()[index] = color[1];
|
||||
m_blue.value()[index] = color[2];
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -66,13 +66,15 @@ struct Get_iso_box_d<T,true>
|
|||
|
||||
template <class Point_with_info,class PointPropertyMap,class Base_traits>
|
||||
class Search_traits_adapter : public Base_traits{
|
||||
PointPropertyMap ppmap;
|
||||
std::optional<PointPropertyMap> ppmap;
|
||||
|
||||
public:
|
||||
typedef Base_traits Base;
|
||||
typedef typename internal::Get_iso_box_d<Base>::type Iso_box_d;
|
||||
|
||||
Search_traits_adapter(const PointPropertyMap& ppmap_=PointPropertyMap(),
|
||||
Search_traits_adapter() {}
|
||||
|
||||
Search_traits_adapter(const PointPropertyMap& ppmap_,
|
||||
const Base_traits& base=Base_traits()
|
||||
):Base_traits(base),ppmap(ppmap_){}
|
||||
|
||||
|
|
@ -246,28 +248,30 @@ public:
|
|||
}
|
||||
Iso_box_d operator() (const Point_with_info& p, const Point_with_info& q) const
|
||||
{
|
||||
return Base_functor::operator() (get(ppmap,p),get(ppmap,q));
|
||||
return Base_functor::operator() (get(ppmap.value(),p),get(ppmap.value(),q));
|
||||
}
|
||||
};
|
||||
|
||||
const PointPropertyMap& point_property_map() const {return ppmap;}
|
||||
const PointPropertyMap& point_property_map() const {return ppmap.value();}
|
||||
|
||||
Construct_cartesian_const_iterator_d construct_cartesian_const_iterator_d_object() const {
|
||||
return Construct_cartesian_const_iterator_d(
|
||||
Base::construct_cartesian_const_iterator_d_object(),
|
||||
ppmap);
|
||||
ppmap.value());
|
||||
}
|
||||
};
|
||||
|
||||
template <class Point_with_info,class PointPropertyMap,class Base_distance>
|
||||
class Distance_adapter : public Base_distance {
|
||||
PointPropertyMap ppmap;
|
||||
std::optional<PointPropertyMap> ppmap;
|
||||
|
||||
public:
|
||||
|
||||
Distance_adapter( const PointPropertyMap& ppmap_=PointPropertyMap(),
|
||||
const Base_distance& distance=Base_distance()
|
||||
):Base_distance(distance),ppmap(ppmap_){}
|
||||
Distance_adapter() {}
|
||||
|
||||
Distance_adapter(const PointPropertyMap& ppmap_,
|
||||
const Base_distance& distance = Base_distance())
|
||||
: Base_distance(distance), ppmap(ppmap_) {}
|
||||
|
||||
using Base_distance::transformed_distance;
|
||||
|
||||
|
|
@ -275,11 +279,11 @@ public:
|
|||
typedef Point_with_info Point_d;
|
||||
typedef typename Base_distance::Query_item Query_item;
|
||||
|
||||
const PointPropertyMap& point_property_map() const {return ppmap;}
|
||||
const PointPropertyMap& point_property_map() const {return ppmap.value();}
|
||||
|
||||
FT transformed_distance(const Query_item& p1, const Point_with_info& p2) const
|
||||
{
|
||||
return Base_distance::transformed_distance(p1,get(ppmap,p2));
|
||||
return Base_distance::transformed_distance(p1,get(ppmap.value(),p2));
|
||||
}
|
||||
|
||||
template <class FT,class Dimension>
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load Diff
|
|
@ -64,20 +64,20 @@ struct test_emptiness : public Surface_fixture
|
|||
assert(m.is_isolated(iv));
|
||||
|
||||
Sm::Vertex_around_target_range vr = m.vertices_around_target(m.halfedge(iv));
|
||||
assert(is_empty_range(std::begin(vr), std::end(vr)));
|
||||
assert(is_empty_range(boost::begin(vr), boost::end(vr)));
|
||||
|
||||
Sm::Face_around_target_range fr = m.faces_around_target(m.halfedge(iv));
|
||||
assert(is_empty_range(std::begin(fr), std::end(fr)));
|
||||
assert(is_empty_range(boost::begin(fr), boost::end(fr)));
|
||||
|
||||
Sm::Halfedge_around_target_range hr = m.halfedges_around_target(m.halfedge(iv));
|
||||
assert(is_empty_range(std::begin(hr), std::end(hr)));
|
||||
assert(is_empty_range(boost::begin(hr), boost::end(hr)));
|
||||
// not true for everything else
|
||||
m.remove_vertex(iv);
|
||||
assert(m.is_removed(iv));
|
||||
Sm::Vertex_iterator vb, ve;
|
||||
for(boost::tie(vb, ve) = m.vertices(); vb != ve; ++vb) {
|
||||
Sm::Vertex_around_target_range vr = m.vertices_around_target(m.halfedge(*vb));
|
||||
assert(!is_empty_range(std::begin(vr), std::end(vr)));
|
||||
assert(!is_empty_range(boost::begin(vr), boost::end(vr)));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -19,24 +19,35 @@ typedef boost::graph_traits<Sm>::face_descriptor face_descriptor;
|
|||
void
|
||||
freelist(const Sm& sm, int vc, int fc, int ec)
|
||||
{
|
||||
// vc should be the number of in-active vertex indices
|
||||
std::cout << "vertex freelist" << std::endl;
|
||||
auto unused_vertices = sm.vertex_freelist();
|
||||
for (auto vd: unused_vertices)
|
||||
vertex_descriptor vd = sm.vertex_freelist();
|
||||
while(vd != sm.null_vertex()){
|
||||
--vc;
|
||||
std::cout << vd << std::endl;
|
||||
assert(vc == unused_vertices.size());
|
||||
halfedge_descriptor hd = halfedge(vd,sm);
|
||||
vd = vertex_descriptor((Sm::size_type)hd);
|
||||
}
|
||||
assert(vc == 0);
|
||||
|
||||
std::cout << "face freelist" << std::endl;
|
||||
auto unused_faces = sm.face_freelist();
|
||||
for (auto fd: unused_faces)
|
||||
face_descriptor fd = sm.face_freelist();
|
||||
while(fd != sm.null_face()){
|
||||
--fc;
|
||||
std::cout << fd << std::endl;
|
||||
assert(fc == unused_faces.size());
|
||||
halfedge_descriptor hd = halfedge(fd,sm);
|
||||
fd = face_descriptor((Sm::size_type)hd);
|
||||
}
|
||||
assert(fc == 0);
|
||||
|
||||
std::cout << "edge freelist" << std::endl;
|
||||
auto unused_edges = sm.edge_freelist();
|
||||
for (auto ed: unused_edges)
|
||||
edge_descriptor ed = sm.edge_freelist();
|
||||
while(ed != sm.null_edge()){
|
||||
--ec;
|
||||
std::cout << ed << std::endl;
|
||||
assert(ec == unused_edges.size());
|
||||
halfedge_descriptor hd = next(halfedge(ed,sm),sm);
|
||||
ed = edge(hd,sm);
|
||||
}
|
||||
assert(ec == 0);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -19,13 +19,13 @@ int main()
|
|||
Sm m;
|
||||
Sm::vertex_index u;
|
||||
|
||||
assert(m.number_of_vertices() == 0);
|
||||
assert(m.num_vertices() == 0);
|
||||
assert(m.number_of_removed_vertices() == 0);
|
||||
for(int i=0; i < 10; i++){
|
||||
u = m.add_vertex(Point_3(0,0,0));
|
||||
m.remove_vertex(u);
|
||||
}
|
||||
assert(m.number_of_vertices() == 0);
|
||||
assert(m.num_vertices() == 1);
|
||||
assert(m.number_of_removed_vertices() == 1);
|
||||
|
||||
|
||||
|
|
@ -34,23 +34,26 @@ int main()
|
|||
assert(! m.does_recycle_garbage());
|
||||
|
||||
m.add_vertex(Point_3(0,0,0));
|
||||
assert(m.number_of_vertices() == 1);
|
||||
assert(m.num_vertices() == 2);
|
||||
assert(m.number_of_removed_vertices() == 1);
|
||||
|
||||
m.set_recycle_garbage(true);
|
||||
m.add_vertex(Point_3(0,0,0));
|
||||
assert(m.number_of_vertices() == 2);
|
||||
assert(m.num_vertices() == 2);
|
||||
assert(m.number_of_removed_vertices() == 0);
|
||||
|
||||
|
||||
std::cout << m.number_of_vertices() << " " << m.number_of_removed_vertices() << std::endl;
|
||||
std::cout << m.num_vertices() << " " << m.number_of_removed_vertices() << std::endl;
|
||||
|
||||
// make sure all is OK when clearing the mesh
|
||||
|
||||
auto vconn = m.add_property_map<Vertex_index, Vertex_connectivity>("v:connectivity").first;
|
||||
auto hconn = m.add_property_map<Halfedge_index, Halfedge_connectivity>("h:connectivity").first;
|
||||
auto fconn = m.add_property_map<Face_index, Face_connectivity>("f:connectivity").first;
|
||||
auto vpoint = m.add_property_map<Vertex_index, Point_3>("v:point").first;
|
||||
auto vconn = m.property_map<Vertex_index, Vertex_connectivity>("v:connectivity").first;
|
||||
auto hconn = m.property_map<Halfedge_index, Halfedge_connectivity>("h:connectivity").first;
|
||||
auto fconn = m.property_map<Face_index, Face_connectivity>("f:connectivity").first;
|
||||
auto vpoint = m.property_map<Vertex_index, Point_3>("v:point").first;
|
||||
auto vremoved = m.property_map<Vertex_index, bool>("v:removed").first;
|
||||
auto eremoved = m.property_map<Edge_index, bool>("e:removed").first;
|
||||
auto fremoved = m.property_map<Face_index, bool>("f:removed").first;
|
||||
|
||||
// first call to squat the first available position
|
||||
m.add_property_map<Vertex_index, int>("vprop_dummy");
|
||||
|
|
@ -71,10 +74,13 @@ int main()
|
|||
auto l_fprop = m.add_property_map<Face_index, int>("fprop").first;
|
||||
auto l_eprop = m.add_property_map<Edge_index, int>("eprop").first;
|
||||
|
||||
auto l_vconn = m.add_property_map<Vertex_index, Vertex_connectivity>("v:connectivity").first;
|
||||
auto l_hconn = m.add_property_map<Halfedge_index, Halfedge_connectivity>("h:connectivity").first;
|
||||
auto l_fconn = m.add_property_map<Face_index, Face_connectivity>("f:connectivity").first;
|
||||
auto l_vpoint = m.add_property_map<Vertex_index, Point_3>("v:point").first;
|
||||
auto l_vconn = m.property_map<Vertex_index, Vertex_connectivity>("v:connectivity").first;
|
||||
auto l_hconn = m.property_map<Halfedge_index, Halfedge_connectivity>("h:connectivity").first;
|
||||
auto l_fconn = m.property_map<Face_index, Face_connectivity>("f:connectivity").first;
|
||||
auto l_vpoint = m.property_map<Vertex_index, Point_3>("v:point").first;
|
||||
auto l_vremoved = m.property_map<Vertex_index, bool>("v:removed").first;
|
||||
auto l_eremoved = m.property_map<Edge_index, bool>("e:removed").first;
|
||||
auto l_fremoved = m.property_map<Face_index, bool>("f:removed").first;
|
||||
|
||||
assert( vconn == l_vconn );
|
||||
assert( hconn == l_hconn );
|
||||
|
|
@ -89,10 +95,13 @@ int main()
|
|||
{
|
||||
m.clear();
|
||||
|
||||
auto l_vconn = m.add_property_map<Vertex_index, Vertex_connectivity>("v:connectivity").first;
|
||||
auto l_hconn = m.add_property_map<Halfedge_index, Halfedge_connectivity>("h:connectivity").first;
|
||||
auto l_fconn = m.add_property_map<Face_index, Face_connectivity>("f:connectivity").first;
|
||||
auto l_vpoint = m.add_property_map<Vertex_index, Point_3>("v:point").first;
|
||||
auto l_vconn = m.property_map<Vertex_index, Vertex_connectivity>("v:connectivity").first;
|
||||
auto l_hconn = m.property_map<Halfedge_index, Halfedge_connectivity>("h:connectivity").first;
|
||||
auto l_fconn = m.property_map<Face_index, Face_connectivity>("f:connectivity").first;
|
||||
auto l_vpoint = m.property_map<Vertex_index, Point_3>("v:point").first;
|
||||
auto l_vremoved = m.property_map<Vertex_index, bool>("v:removed").first;
|
||||
auto l_eremoved = m.property_map<Edge_index, bool>("e:removed").first;
|
||||
auto l_fremoved = m.property_map<Face_index, bool>("f:removed").first;
|
||||
|
||||
assert( vconn == l_vconn );
|
||||
assert( hconn == l_hconn );
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ namespace CGAL {
|
|||
\section secTetRemeshing Multi-Material Isotropic Tetrahedral Remeshing
|
||||
|
||||
This package implements an algorithm for quality tetrahedral remeshing,
|
||||
introduced by N.Faraj et al in \cgalCite{faraj2016mvr}.
|
||||
introduced by Faraj et al in \cgalCite{faraj2016mvr}.
|
||||
This practical iterative remeshing algorithm is designed to remesh
|
||||
multi-material tetrahedral meshes, by iteratively performing a sequence of
|
||||
elementary operations such as edge splits, edge collapses, edge flips,
|
||||
|
|
|
|||
Loading…
Reference in New Issue