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:
Sven Oesau 2023-10-10 09:44:42 +02:00
commit 5a27f38675
50 changed files with 3457 additions and 2462 deletions

View File

@ -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")

View File

@ -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>;

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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]);
}
}

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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.

View File

@ -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);

View File

@ -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

View File

@ -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

View File

@ -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);
}

View File

@ -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;
}

View File

@ -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)

View File

@ -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}

View File

@ -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`

View File

@ -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;

View File

@ -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();
}

View File

@ -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;

View File

@ -293,4 +293,4 @@ provided kind help and advice all the way through.
*/
}
}

View File

@ -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);

View File

@ -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);

View File

@ -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;

View File

@ -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.

View File

@ -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);

View File

@ -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());

View File

@ -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;

View File

@ -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();

View File

@ -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;

View File

@ -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);

View File

@ -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;

View File

@ -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));
}

View File

@ -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;

View File

@ -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)

View File

@ -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);

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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,

View File

@ -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;

View File

@ -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];
}
}

View File

@ -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];
}

View File

@ -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

View File

@ -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)));
}
}
};

View File

@ -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);
}

View File

@ -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 );

View File

@ -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,