mirror of https://github.com/CGAL/cgal
Mirror AW2 improvements into AW3
This commit is contained in:
parent
57e5d7db09
commit
48d09df6e6
|
|
@ -1,5 +1,4 @@
|
|||
// Copyright (c) 2019-2022 Google LLC (USA).
|
||||
// Copyright (c) 2025 GeometryFactory (France).
|
||||
// All rights reserved.
|
||||
//
|
||||
// This file is part of CGAL (www.cgal.org).
|
||||
|
|
@ -110,6 +109,10 @@ public:
|
|||
void add_points(const PointRange& points,
|
||||
const CGAL_NP_CLASS& /*np*/ = CGAL::parameters::default_values())
|
||||
{
|
||||
#ifdef CGAL_AW2_DEBUG
|
||||
std::cout << "Insert into AABB tree (points)..." << std::endl;
|
||||
#endif
|
||||
|
||||
if(points.empty())
|
||||
{
|
||||
#ifdef CGAL_AW2_DEBUG
|
||||
|
|
@ -121,10 +124,6 @@ public:
|
|||
const std::size_t old_size = m_points_ptr->size();
|
||||
m_points_ptr->insert(std::cend(*m_points_ptr), std::cbegin(points), std::cend(points));
|
||||
|
||||
#ifdef CGAL_AW2_DEBUG
|
||||
std::cout << "Insert into AABB tree (points)..." << std::endl;
|
||||
#endif
|
||||
|
||||
this->tree().rebuild(std::cbegin(*m_points_ptr), std::cend(*m_points_ptr));
|
||||
|
||||
// Manually constructing it here purely for profiling reasons: if we keep the lazy approach,
|
||||
|
|
|
|||
|
|
@ -100,8 +100,8 @@ int main(int argc, char** argv)
|
|||
Oracle oracle(ss_oracle);
|
||||
|
||||
oracle.add_triangle_soup(points, faces, CGAL::parameters::default_values());
|
||||
oracle.add_segment_soup(segments, CGAL::parameters::default_values());
|
||||
oracle.add_point_set(ps_points, CGAL::parameters::default_values());
|
||||
oracle.add_segments(segments, CGAL::parameters::default_values());
|
||||
oracle.add_points(ps_points, CGAL::parameters::default_values());
|
||||
|
||||
CGAL::Alpha_wraps_3::internal::Alpha_wrapper_3<Oracle> aw3(oracle);
|
||||
|
||||
|
|
|
|||
|
|
@ -207,13 +207,27 @@ public:
|
|||
static_assert(std::is_floating_point<FT>::value);
|
||||
}
|
||||
|
||||
void clear()
|
||||
{
|
||||
m_oracle.clear();
|
||||
m_bbox = {};
|
||||
m_alpha = m_sq_alpha = FT(-1);
|
||||
m_offset = m_sq_offset = FT(-1);
|
||||
m_seeds.clear();
|
||||
m_tr.clear();
|
||||
m_queue.clear();
|
||||
}
|
||||
|
||||
public:
|
||||
const Geom_traits& geom_traits() const { return m_tr.geom_traits(); }
|
||||
Oracle& oracle() { return m_oracle; }
|
||||
const Oracle& oracle() const { return m_oracle; }
|
||||
Triangulation& triangulation() { return m_tr; }
|
||||
const Triangulation& triangulation() const { return m_tr; }
|
||||
Alpha_PQ& queue() { return m_queue; }
|
||||
const Alpha_PQ& queue() const { return m_queue; }
|
||||
const FT& alpha() const { return m_alpha; }
|
||||
const FT& offset() const { return m_offset; }
|
||||
|
||||
double default_alpha() const
|
||||
{
|
||||
|
|
@ -365,6 +379,11 @@ public:
|
|||
#endif
|
||||
}
|
||||
|
||||
#ifdef CGAL_AW3_DEBUG_DUMP_INTERMEDIATE_WRAPS
|
||||
IO::write_polygon_mesh("final_wrap.off", output_mesh, CGAL::parameters::stream_precision(17));
|
||||
dump_triangulation_faces("final_tr.off", false /*only_boundary_faces*/);
|
||||
#endif
|
||||
|
||||
extract_surface(output_mesh, ovpm, !do_enforce_manifoldness);
|
||||
|
||||
#ifdef CGAL_AW3_TIMER
|
||||
|
|
@ -375,11 +394,6 @@ public:
|
|||
#ifdef CGAL_AW3_DEBUG
|
||||
std::cout << "Alpha wrap vertices: " << vertices(output_mesh).size() << std::endl;
|
||||
std::cout << "Alpha wrap faces: " << faces(output_mesh).size() << std::endl;
|
||||
|
||||
#ifdef CGAL_AW3_DEBUG_DUMP_INTERMEDIATE_WRAPS
|
||||
IO::write_polygon_mesh("final_wrap.off", output_mesh, CGAL::parameters::stream_precision(17));
|
||||
dump_triangulation_faces("final_tr.off", false /*only_boundary_faces*/);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
visitor.on_alpha_wrapping_end(*this);
|
||||
|
|
@ -501,7 +515,7 @@ private:
|
|||
// which yields
|
||||
// r = a * sin(2pi / 5) =~ 0.95105651629515353 * a
|
||||
// Faces of an icosahedron are equilateral triangles with size a and circumradius a / sqrt(3)
|
||||
// Since we want faces of the icosahedron to be traversable, we want a such that
|
||||
// Since we want faces of the icosahedron to be traversable, we want `a` such that
|
||||
// a / sqrt(3) > alpha
|
||||
// Hence r such that
|
||||
// r / (sqrt(3) * sin(2pi/5)) > alpha
|
||||
|
|
@ -509,7 +523,7 @@ private:
|
|||
//
|
||||
// Furthermore, the triangles between edges of the icosahedron and the center of the icosahedron
|
||||
// are not equilateral triangles since a is slightly bigger than r. They are
|
||||
// slightly flattened isocele triangles with base 'a' and the circumradius is smaller.
|
||||
// slightly flattened isocele triangles with base `a` and the circumradius is smaller.
|
||||
// The circumradius is
|
||||
// r_iso = r² / (2 * h) = r² / (2 * sqrt(r² - (a / 2)²))
|
||||
// Since r = a * sin(2pi / 5)
|
||||
|
|
@ -896,6 +910,16 @@ private:
|
|||
return less_squared_radius_of_min_empty_sphere(m_sq_alpha, f, m_tr);
|
||||
}
|
||||
|
||||
Steiner_status compute_steiner_point(const Gate& gate,
|
||||
Point_2& steiner_point) const
|
||||
{
|
||||
const Face_handle fh = gate.face();
|
||||
const Cell_handle ch = f.first;
|
||||
const int s = f.second;
|
||||
const Cell_handle nh = ch->neighbor(s);
|
||||
return compute_steiner_point(ch, nh, steiner_point);
|
||||
}
|
||||
|
||||
bool compute_steiner_point(const Cell_handle ch,
|
||||
const Cell_handle neighbor,
|
||||
Point_3& steiner_point) const
|
||||
|
|
@ -950,7 +974,7 @@ private:
|
|||
#ifdef CGAL_AW3_DEBUG_STEINER_COMPUTATION
|
||||
std::cout << "Steiner found through first_intersection(): " << steiner_point << std::endl;
|
||||
#endif
|
||||
return true;
|
||||
return Steiner_status::RULE_1;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -959,6 +983,10 @@ private:
|
|||
{
|
||||
// steiner point is the closest point on input from cell centroid with offset
|
||||
const Point_3 closest_pt = m_oracle.closest_point(neighbor_cc);
|
||||
#ifdef CGAL_AW3_DEBUG_STEINER_COMPUTATION
|
||||
std::cout << "Steiner found through neighboring triangle intersecting the input" << std::endl;
|
||||
std::cout << "Closest point: " << closest_pt << std::endl;
|
||||
#endif
|
||||
CGAL_assertion(closest_pt != neighbor_cc);
|
||||
|
||||
Vector_3 unit = vector(closest_pt, neighbor_cc);
|
||||
|
|
@ -968,19 +996,18 @@ private:
|
|||
steiner_point = translate(closest_pt, unit);
|
||||
|
||||
#ifdef CGAL_AW3_DEBUG_STEINER_COMPUTATION
|
||||
std::cout << "Steiner found through neighboring tet intersecting the input: " << steiner_point << std::endl;
|
||||
std::cout << "Closest point: " << closest_pt << std::endl;
|
||||
std::cout << "Direction: " << vector(closest_pt, neighbor_cc) << std::endl;
|
||||
std::cout << "Direction: " << unit << std::endl;
|
||||
std::cout << "Steiner: " << steiner_point << std::endl;
|
||||
#endif
|
||||
|
||||
return true;
|
||||
return Steiner_status::RULE_2;
|
||||
}
|
||||
|
||||
#ifdef CGAL_AW3_DEBUG_STEINER_COMPUTATION
|
||||
std::cout << "No Steiner point" << std::endl;
|
||||
#endif
|
||||
|
||||
return false;
|
||||
return Steiner_status::NO_STEINER_POINT;
|
||||
}
|
||||
|
||||
private:
|
||||
|
|
@ -1043,7 +1070,12 @@ public:
|
|||
CGAL_precondition(ch->label() == Cell_label::INSIDE || ch->label() == Cell_label::OUTSIDE);
|
||||
|
||||
if(m_tr.is_infinite(nh))
|
||||
{
|
||||
#ifdef CGAL_AW3_DEBUG_FACET_STATUS
|
||||
std::cout << "Infinite neighboring cell" << std::endl;
|
||||
#endif
|
||||
return Facet_status::HAS_INFINITE_NEIGHBOR;
|
||||
}
|
||||
|
||||
if(nh->is_outside())
|
||||
{
|
||||
|
|
@ -1104,9 +1136,23 @@ private:
|
|||
const FT sqr = smallest_squared_radius_3(f, m_tr);
|
||||
const bool is_permissive = (status == Facet_status::HAS_INFINITE_NEIGHBOR ||
|
||||
status == Facet_status::SCAFFOLDING);
|
||||
m_queue.resize_and_push(Gate(f, sqr, is_permissive));
|
||||
Gate new_gate(f, sqr, is_permissive);
|
||||
#else
|
||||
m_queue.push(Gate(f, m_tr));
|
||||
Gate new_gate(f, m_tr);
|
||||
#endif
|
||||
|
||||
#ifdef CGAL_AW2_COMPUTE_AND_STORE_STEINER_INFO_AT_GATE_CREATION
|
||||
Point_3 steiner_point;
|
||||
Steiner_status steiner_status = compute_steiner_point(new_gate, steiner_point);
|
||||
new_gate.m_steiner_status = steiner_status;
|
||||
if(steiner_status == Steiner_status::RULE_1 || steiner_status == Steiner_status::RULE_2)
|
||||
new_gate.m_steiner_point = steiner_point;
|
||||
#endif
|
||||
|
||||
#ifdef CGAL_AW3_USE_SORTED_PRIORITY_QUEUE
|
||||
m_queue.resize_and_push(new_gate);
|
||||
#else
|
||||
m_queue.push(new_gate);
|
||||
#endif
|
||||
|
||||
#ifdef CGAL_AW3_DEBUG_QUEUE
|
||||
|
|
@ -1241,26 +1287,25 @@ private:
|
|||
#endif
|
||||
|
||||
const Facet& f = gate.facet();
|
||||
CGAL_precondition(!m_tr.is_infinite(f));
|
||||
|
||||
const Cell_handle ch = f.first;
|
||||
const int s = f.second;
|
||||
CGAL_precondition(ch->is_outside());
|
||||
|
||||
const Cell_handle nh = ch->neighbor(s);
|
||||
CGAL_precondition(nh->label() == Cell_label::INSIDE || nh->label() == Cell_label::OUTSIDE);
|
||||
|
||||
#ifdef CGAL_AW3_DEBUG_QUEUE
|
||||
static int fid = 0;
|
||||
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_tr.is_infinite(ch) << "), n = " << &*nh << " (" << m_tr.is_infinite(nh) << ")" << "\n"
|
||||
<< m_tr.point(ch, Triangulation::vertex_triple_index(s, 0)) << "\n"
|
||||
<< m_tr.point(ch, Triangulation::vertex_triple_index(s, 1)) << "\n"
|
||||
<< m_tr.point(ch, Triangulation::vertex_triple_index(s, 2)) << std::endl;
|
||||
std::cout << "Face " << fid++ << " ["
|
||||
<< m_tr.point(ch, Triangulation::vertex_triple_index(s, 0)) << " "
|
||||
<< m_tr.point(ch, Triangulation::vertex_triple_index(s, 1)) << " "
|
||||
<< m_tr.point(ch, Triangulation::vertex_triple_index(s, 2)) << "]" << std::endl;
|
||||
std::cout << "c = " << &*ch << " (inf: " << m_tr.is_infinite(ch) << ", label: " << ch->label() << "), n = "
|
||||
<< &*nh << " (inf: " << m_tr.is_infinite(nh) << ", label: " << nh->label() << ")" << "\n"
|
||||
|
||||
# ifdef CGAL_AW3_USE_SORTED_PRIORITY_QUEUE
|
||||
std::cout << "Priority: " << gate.priority() << " (sq alpha: " << m_sq_alpha << ")" << std::endl;
|
||||
std::cout << "Permissiveness: " << gate.is_permissive_facet() << std::endl;
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifdef CGAL_AW3_DEBUG_DUMP_EVERY_STEP
|
||||
|
|
@ -1277,6 +1322,10 @@ private:
|
|||
face_out.close();
|
||||
#endif
|
||||
|
||||
CGAL_precondition(!m_tr.is_infinite(f));
|
||||
CGAL_precondition(ch->is_outside());
|
||||
CGAL_precondition(nh->label() == Cell_label::INSIDE || nh->label() == Cell_label::OUTSIDE);
|
||||
|
||||
visitor.before_facet_treatment(*this, gate);
|
||||
|
||||
m_queue.pop();
|
||||
|
|
@ -1291,7 +1340,8 @@ private:
|
|||
}
|
||||
|
||||
Point_3 steiner_point;
|
||||
if(compute_steiner_point(ch, nh, steiner_point))
|
||||
Steiner_status ss = compute_steiner_point(ch, nh, steiner_point);
|
||||
if(ss != Steiner_status::NO_STEINER_POINT)
|
||||
{
|
||||
// std::cout << CGAL::abs(CGAL::approximate_sqrt(m_oracle.squared_distance(steiner_point)) - m_offset)
|
||||
// << " vs " << 1e-2 * m_offset << std::endl;
|
||||
|
|
|
|||
|
|
@ -23,13 +23,33 @@ namespace internal {
|
|||
enum class Cell_label
|
||||
{
|
||||
// Cells that have been carved
|
||||
OUTSIDE,
|
||||
OUTSIDE = 0,
|
||||
// Cells that have not yet been carved
|
||||
INSIDE,
|
||||
// OUTSIDE cells that have been labeled "inside" again as to make the result manifold
|
||||
MANIFOLD
|
||||
};
|
||||
|
||||
inline std::string label_string(const Cell_label& label) {
|
||||
switch(label) {
|
||||
case Cell_label::OUTSIDE:
|
||||
return "OUTSIDE";
|
||||
case Cell_label::INSIDE:
|
||||
return "INSIDE";
|
||||
case Cell_label::MANIFOLD:
|
||||
return "MANIFOLD";
|
||||
default:
|
||||
CGAL_assertion_msg(false, "Unknown label");
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
inline std::ostream& operator <<(std::ostream& os, const Cell_label& label)
|
||||
{
|
||||
os << static_cast<std::underlying_type<Cell_label>::type>(label);
|
||||
return os;
|
||||
}
|
||||
|
||||
template < typename GT,
|
||||
typename Cb = CGAL::Delaunay_triangulation_cell_base_with_circumcenter_3<GT> >
|
||||
class Alpha_wrap_triangulation_cell_base_3
|
||||
|
|
|
|||
|
|
@ -145,7 +145,11 @@ public:
|
|||
bool empty() const { return m_tree_ptr->empty(); }
|
||||
bool do_call() const { return (!empty() || base().do_call()); }
|
||||
|
||||
void clear() { m_tree_ptr->clear() && base().clear(); }
|
||||
void clear()
|
||||
{
|
||||
m_tree_ptr->clear();
|
||||
base().clear();
|
||||
}
|
||||
|
||||
public:
|
||||
typename AABB_tree::Bounding_box bbox() const
|
||||
|
|
|
|||
|
|
@ -97,12 +97,22 @@ public:
|
|||
{ }
|
||||
|
||||
public:
|
||||
void clear()
|
||||
{
|
||||
m_points_ptr->clear();
|
||||
Oracle_base::clear();
|
||||
}
|
||||
|
||||
// adds a range of points to the oracle
|
||||
template <typename PointRange,
|
||||
typename CGAL_NP_TEMPLATE_PARAMETERS>
|
||||
void add_point_set(const PointRange& points,
|
||||
const CGAL_NP_CLASS& /*np*/ = CGAL::parameters::default_values())
|
||||
void add_points(const PointRange& points,
|
||||
const CGAL_NP_CLASS& /*np*/ = CGAL::parameters::default_values())
|
||||
{
|
||||
#ifdef CGAL_AW3_DEBUG
|
||||
std::cout << "Insert into AABB tree (points)..." << std::endl;
|
||||
#endif
|
||||
|
||||
if(points.empty())
|
||||
{
|
||||
#ifdef CGAL_AW3_DEBUG
|
||||
|
|
@ -114,20 +124,18 @@ public:
|
|||
const std::size_t old_size = m_points_ptr->size();
|
||||
m_points_ptr->insert(std::cend(*m_points_ptr), std::cbegin(points), std::cend(points));
|
||||
|
||||
#ifdef CGAL_AW3_DEBUG
|
||||
std::cout << "Insert into AABB tree (points)..." << std::endl;
|
||||
#endif
|
||||
|
||||
this->tree().insert(std::next(std::cbegin(*m_points_ptr), old_size), std::cend(*m_points_ptr));
|
||||
this->tree().rebuild(std::cbegin(*m_points_ptr), std::cend(*m_points_ptr));
|
||||
|
||||
// Manually constructing it here purely for profiling reasons: if we keep the lazy approach,
|
||||
// it will be done at the first treatment of a facet that needs a Steiner point.
|
||||
// So if one wanted to bench the flood fill runtime, it would be skewed by the time it takes
|
||||
// to accelerate the tree.
|
||||
this->tree().accelerate_distance_queries();
|
||||
|
||||
CGAL_postcondition(this->tree().size() == m_points_ptr->size());
|
||||
}
|
||||
|
||||
#ifdef CGAL_AW2_DEBUG
|
||||
std::cout << "PS Tree: " << this->tree().size() << " primitives" << std::endl;
|
||||
#endif
|
||||
};
|
||||
|
||||
} // namespace internal
|
||||
|
|
|
|||
|
|
@ -99,11 +99,21 @@ public:
|
|||
{ }
|
||||
|
||||
public:
|
||||
void clear()
|
||||
{
|
||||
m_segments_ptr->clear();
|
||||
Oracle_base::clear();
|
||||
}
|
||||
|
||||
template <typename SegmentRange,
|
||||
typename CGAL_NP_TEMPLATE_PARAMETERS>
|
||||
void add_segment_soup(const SegmentRange& segments,
|
||||
const CGAL_NP_CLASS& /*np*/ = CGAL::parameters::default_values())
|
||||
void add_segments(const SegmentRange& segments,
|
||||
const CGAL_NP_CLASS& /*np*/ = CGAL::parameters::default_values())
|
||||
{
|
||||
#ifdef CGAL_AW3_DEBUG
|
||||
std::cout << "Insert into AABB Tree (" << segments.size() << " segments)..." << std::endl;
|
||||
#endif
|
||||
|
||||
if(segments.empty())
|
||||
{
|
||||
#ifdef CGAL_AW3_DEBUG
|
||||
|
|
@ -129,10 +139,7 @@ public:
|
|||
m_segments_ptr->push_back(s);
|
||||
}
|
||||
|
||||
#ifdef CGAL_AW3_DEBUG
|
||||
std::cout << "Insert into AABB tree (segments)..." << std::endl;
|
||||
#endif
|
||||
this->tree().insert(std::next(std::cbegin(*m_segments_ptr), old_size), std::cend(*m_segments_ptr));
|
||||
this->tree().rebuild(std::cbegin(*m_segments_ptr), std::cend(*m_segments_ptr));
|
||||
|
||||
// Manually constructing it here purely for profiling reasons: if we keep the lazy approach,
|
||||
// it will be done at the first treatment of a facet that needs a Steiner point.
|
||||
|
|
@ -140,7 +147,9 @@ public:
|
|||
// to accelerate the tree.
|
||||
this->tree().accelerate_distance_queries();
|
||||
|
||||
CGAL_postcondition(this->tree().size() == m_segments_ptr->size());
|
||||
#ifdef CGAL_AW3_DEBUG
|
||||
std::cout << "SS Tree: " << this->tree().size() << " primitives" << std::endl;
|
||||
#endif
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -130,6 +130,10 @@ public:
|
|||
using VPM = typename GetVertexPointMap<TriangleMesh>::const_type;
|
||||
using Point_ref = typename boost::property_traits<VPM>::reference;
|
||||
|
||||
#ifdef CGAL_AW3_DEBUG
|
||||
std::cout << "Insert into AABB tree (" << faces(tmesh).size() << " faces)..." << std::endl;
|
||||
#endif
|
||||
|
||||
CGAL_precondition(CGAL::is_triangle_mesh(tmesh));
|
||||
|
||||
if(is_empty(tmesh))
|
||||
|
|
@ -140,10 +144,6 @@ public:
|
|||
return;
|
||||
}
|
||||
|
||||
#ifdef CGAL_AW3_DEBUG
|
||||
std::cout << "Insert into AABB tree (faces)..." << std::endl;
|
||||
#endif
|
||||
|
||||
VPM vpm = choose_parameter(get_parameter(np, internal_np::vertex_point),
|
||||
get_const_property_map(vertex_point, tmesh));
|
||||
static_assert(std::is_same<typename boost::property_traits<VPM>::value_type, Point_3>::value);
|
||||
|
|
@ -176,7 +176,7 @@ public:
|
|||
this->tree().accelerate_distance_queries();
|
||||
|
||||
#ifdef CGAL_AW3_DEBUG
|
||||
std::cout << "Tree: " << this->tree().size() << " primitives (" << num_faces(tmesh) << " faces in input)" << std::endl;
|
||||
std::cout << "Tree: " << this->tree().size() << " primitives" << std::endl;
|
||||
#endif
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -130,6 +130,10 @@ public:
|
|||
|
||||
using Face = typename boost::range_value<FaceRange>::type;
|
||||
|
||||
#ifdef CGAL_AW3_DEBUG
|
||||
std::cout << "Insert into AABB Tree (" << faces.size() << " faces)..." << std::endl;
|
||||
#endif
|
||||
|
||||
if(points.empty() || faces.empty())
|
||||
{
|
||||
#ifdef CGAL_AW3_DEBUG
|
||||
|
|
@ -138,10 +142,6 @@ public:
|
|||
return;
|
||||
}
|
||||
|
||||
#ifdef CGAL_AW3_DEBUG
|
||||
std::cout << "Insert into AABB Tree (triangles)..." << std::endl;
|
||||
#endif
|
||||
|
||||
PPM pm = choose_parameter<PPM>(get_parameter(np, internal_np::point_map));
|
||||
static_assert(std::is_same<typename boost::property_traits<PPM>::value_type, Point_3>::value);
|
||||
|
||||
|
|
@ -181,15 +181,19 @@ public:
|
|||
this->tree().accelerate_distance_queries();
|
||||
|
||||
#ifdef CGAL_AW3_DEBUG
|
||||
std::cout << "Tree: " << this->tree().size() << " primitives (" << faces.size() << " faces in input)" << std::endl;
|
||||
std::cout << "TS Tree: " << this->tree().size() << " primitives" << std::endl;
|
||||
#endif
|
||||
}
|
||||
|
||||
template <typename TriangleRange,
|
||||
typename CGAL_NP_TEMPLATE_PARAMETERS>
|
||||
void add_triangle_soup(const TriangleRange& triangles,
|
||||
const CGAL_NP_CLASS& /*np*/ = CGAL::parameters::default_values())
|
||||
void add_triangles(const TriangleRange& triangles,
|
||||
const CGAL_NP_CLASS& /*np*/ = CGAL::parameters::default_values())
|
||||
{
|
||||
#ifdef CGAL_AW3_DEBUG
|
||||
std::cout << "Insert into AABB Tree (" << triangles.size() << " triangles)..." << std::endl;
|
||||
#endif
|
||||
|
||||
if(triangles.empty())
|
||||
{
|
||||
#ifdef CGAL_AW3_DEBUG
|
||||
|
|
@ -198,10 +202,6 @@ public:
|
|||
return;
|
||||
}
|
||||
|
||||
#ifdef CGAL_AW3_DEBUG
|
||||
std::cout << "Insert into AABB Tree (triangles)..." << std::endl;
|
||||
#endif
|
||||
|
||||
typename Geom_traits::Is_degenerate_3 is_degenerate = this->geom_traits().is_degenerate_3_object();
|
||||
|
||||
Splitter_base::reserve(triangles.size());
|
||||
|
|
@ -218,6 +218,9 @@ public:
|
|||
|
||||
Splitter_base::split_and_insert_datum(tr, this->tree(), this->geom_traits());
|
||||
}
|
||||
#ifdef CGAL_AW3_DEBUG
|
||||
std::cout << "TS Tree: " << this->tree().size() << " primitives" << std::endl;
|
||||
#endif
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -22,16 +22,46 @@
|
|||
|
||||
#include <cassert>
|
||||
#include <iostream>
|
||||
#include <optional>
|
||||
|
||||
namespace CGAL {
|
||||
namespace Alpha_wraps_3 {
|
||||
namespace internal {
|
||||
|
||||
enum class Steiner_status
|
||||
{
|
||||
UNKONWN = 0,
|
||||
NO_STEINER_POINT,
|
||||
RULE_1,
|
||||
RULE_2
|
||||
};
|
||||
|
||||
#ifdef CGAL_AW2_COMPUTE_AND_STORE_STEINER_INFO_AT_GATE_CREATION
|
||||
template <typename Tr>
|
||||
struct Gate_steiner_info
|
||||
{
|
||||
using Point_3 = typename Tr::Geom_traits::Point_3;
|
||||
|
||||
Steiner_status m_steiner_status = Steiner_status::UNKNOWN;
|
||||
std::optional<Point_3> m_steiner_point = std::nullopt;
|
||||
|
||||
bool has_steiner_point() const { return m_steiner_point.has_value(); }
|
||||
bool has_steiner_from_projection() const { return (m_steiner_status == Steiner_status::RULE_2); }
|
||||
const Point_3& steiner_point() const {
|
||||
CGAL_precondition(has_steiner_point());
|
||||
return *m_steiner_point;
|
||||
}
|
||||
};
|
||||
#endif
|
||||
|
||||
#ifdef CGAL_AW3_USE_SORTED_PRIORITY_QUEUE
|
||||
|
||||
// Represents an alpha-traversable facet in the mutable priority queue
|
||||
template <typename Tr>
|
||||
class Gate
|
||||
#ifdef CGAL_AW2_COMPUTE_AND_STORE_STEINER_INFO_AT_GATE_CREATION
|
||||
: public Gate_steiner_info<Tr>
|
||||
#endif
|
||||
{
|
||||
using Facet = typename Tr::Facet;
|
||||
using FT = typename Tr::Geom_traits::FT;
|
||||
|
|
@ -97,6 +127,9 @@ struct Less_gate
|
|||
// Represents an alpha-traversable facet in the mutable priority queue
|
||||
template <typename Tr>
|
||||
class Gate
|
||||
#ifdef CGAL_AW2_COMPUTE_AND_STORE_STEINER_INFO_AT_GATE_CREATION
|
||||
: public Gate_steiner_info<Tr>
|
||||
#endif
|
||||
{
|
||||
using Facet = typename Tr::Facet;
|
||||
using FT = typename Tr::Geom_traits::FT;
|
||||
|
|
|
|||
|
|
@ -65,20 +65,30 @@ bool has_degenerated_faces(const TriangleMesh& mesh,
|
|||
// Edge length is bounded by twice the circumradius
|
||||
template <typename TriangleMesh,
|
||||
typename NamedParameters = parameters::Default_named_parameters>
|
||||
bool check_edge_length(const TriangleMesh& output_mesh,
|
||||
const double alpha,
|
||||
const NamedParameters& np = CGAL::parameters::default_values())
|
||||
bool has_bounded_edge_length(const TriangleMesh& wrap,
|
||||
const double alpha,
|
||||
const NamedParameters& np = CGAL::parameters::default_values())
|
||||
{
|
||||
const auto sq_alpha_bound = 4 * square(alpha);
|
||||
for(auto e : edges(output_mesh))
|
||||
using Geom_traits = typename GetGeomTraits<TriangleMesh, NamedParameters>::type;
|
||||
using FT = typename Geom_traits::FT;
|
||||
using VPM = typename CGAL::GetVertexPointMap<PolygonMesh, NamedParameters>::type;
|
||||
|
||||
Geom_traits gt = choose_parameter<Geom_traits>(get_parameter(in_np, internal_np::geom_traits));
|
||||
VPM vpm = choose_parameter(get_parameter(np, internal_np::vertex_point),
|
||||
get_const_property_map(vertex_point, tmesh));
|
||||
|
||||
const FT sq_alpha_bound = 4 * square(alpha);
|
||||
for(auto e : edges(wrap))
|
||||
{
|
||||
const auto sqd = Polygon_mesh_processing::squared_edge_length(e, output_mesh, np);
|
||||
if(sqd > sq_alpha_bound) // alpha is the circumradius
|
||||
if(gt.compare_squared_distance(get(vpm, source(e, wrap)),
|
||||
get(vpm, target(e, wrap)),
|
||||
sq_alpha_bound) == LARGER)
|
||||
{
|
||||
#ifdef CGAL_AW3_DEBUG
|
||||
const FT sqd = Polygon_mesh_processing::squared_edge_length(e, wrap, np);
|
||||
std::cerr << "Error: " << sqd << " greater than " << sq_alpha_bound << std::endl;
|
||||
std::cerr << get(CGAL::vertex_point, output_mesh, source(e, output_mesh)) << std::endl;
|
||||
std::cerr << get(CGAL::vertex_point, output_mesh, target(e, output_mesh)) << std::endl;
|
||||
std::cerr << "source pt: " << get(vpm, source(e, wrap)) << std::endl;
|
||||
std::cerr << "target pt: " << get(vpm, target(e, wrap)) << std::endl;
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
|
@ -346,13 +356,12 @@ bool is_outer_wrap_of_point_set(const TriangleMesh& wrap,
|
|||
|
||||
CGAL::Side_of_triangle_mesh<TriangleMesh, K, OVPM> side_of_wrap(wrap, out_vpm);
|
||||
|
||||
// @speed a single vertex per CC would be sufficient
|
||||
for(const auto& p : points)
|
||||
{
|
||||
if(side_of_wrap(get(in_pm, p)) != CGAL::ON_BOUNDED_SIDE)
|
||||
{
|
||||
#ifdef CGAL_AW3_DEBUG
|
||||
std::cerr << "Part(s) of the input mesh are outside the wrap: " << get(in_pm, p) << std::endl;
|
||||
std::cerr << "An input point is outside the wrap: " << get(in_pm, p) << std::endl;
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -355,7 +355,7 @@ void alpha_wrap_3(const PointRange& points,
|
|||
Geom_traits gt = choose_parameter<Geom_traits>(get_parameter(in_np, internal_np::geom_traits));
|
||||
|
||||
Oracle oracle(gt);
|
||||
oracle.add_point_set(points, in_np);
|
||||
oracle.add_points(points, in_np);
|
||||
AW3 alpha_wrap_builder(oracle);
|
||||
alpha_wrap_builder(alpha, offset, alpha_wrap, in_np, out_np);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -105,7 +105,7 @@ void alpha_wrap_triangle_mesh(Mesh& input_mesh,
|
|||
}
|
||||
|
||||
if(!enforce_manifoldness)
|
||||
assert(AW3::internal::check_edge_length(wrap, alpha));
|
||||
assert(AW3::internal::has_bounded_edge_length(wrap, alpha));
|
||||
}
|
||||
|
||||
void alpha_wrap_triangle_mesh(Mesh& input_mesh,
|
||||
|
|
|
|||
|
|
@ -57,7 +57,7 @@ void alpha_wrap_triangle_manifoldness(Mesh& input_mesh,
|
|||
assert(AW3::internal::has_expected_Hausdorff_distance(nm_wrap, input_mesh, alpha, offset));
|
||||
}
|
||||
|
||||
assert(AW3::internal::check_edge_length(nm_wrap, alpha));
|
||||
assert(AW3::internal::has_bounded_edge_length(nm_wrap, alpha));
|
||||
|
||||
FT base_vol = 0;
|
||||
if(!is_closed(nm_wrap))
|
||||
|
|
|
|||
|
|
@ -52,7 +52,7 @@ void alpha_wrap_triangle_soup(Points& pr,
|
|||
|
||||
// AW3
|
||||
Oracle oracle;
|
||||
oracle.add_triangle_soup(pr, fr);
|
||||
oracle.add_triangles(pr, fr);
|
||||
AW3::internal::Alpha_wrapper_3<Oracle> aw3(oracle);
|
||||
|
||||
Mesh wrap;
|
||||
|
|
@ -65,7 +65,7 @@ void alpha_wrap_triangle_soup(Points& pr,
|
|||
assert(AW3::internal::is_valid_wrap(wrap, false /*manifoldness*/));
|
||||
assert(AW3::internal::is_outer_wrap_of_triangle_soup(wrap, pr, fr));
|
||||
assert(AW3::internal::has_expected_Hausdorff_distance(wrap, input_mesh, alpha, offset));
|
||||
assert(AW3::internal::check_edge_length(wrap, alpha));
|
||||
assert(AW3::internal::has_bounded_edge_length(wrap, alpha));
|
||||
|
||||
alpha *= 2;
|
||||
offset *= 2;
|
||||
|
|
@ -83,7 +83,7 @@ void alpha_wrap_triangle_soup(Points& pr,
|
|||
assert(AW3::internal::is_valid_wrap(wrap_2, false /*manifoldness*/));
|
||||
assert(AW3::internal::is_outer_wrap_of_triangle_soup(wrap_2, pr, fr));
|
||||
assert(AW3::internal::has_expected_Hausdorff_distance(wrap_2, input_mesh, alpha, offset));
|
||||
assert(AW3::internal::check_edge_length(wrap_2, alpha));
|
||||
assert(AW3::internal::has_bounded_edge_length(wrap_2, alpha));
|
||||
}
|
||||
|
||||
void alpha_wrap_triangle_soup(const std::string& filename)
|
||||
|
|
|
|||
|
|
@ -63,7 +63,7 @@ void alpha_wrap_triangle_mesh(Mesh& input_mesh,
|
|||
}
|
||||
|
||||
if(!enforce_manifoldness)
|
||||
assert(AW3::internal::check_edge_length(wrap, alpha));
|
||||
assert(AW3::internal::has_bounded_edge_length(wrap, alpha));
|
||||
}
|
||||
|
||||
void alpha_wrap_triangle_mesh(const std::string& filename,
|
||||
|
|
|
|||
|
|
@ -732,11 +732,11 @@ public Q_SLOTS:
|
|||
Oracle oracle(ss_oracle);
|
||||
|
||||
if(wrap_triangles)
|
||||
oracle.add_triangle_soup(triangles);
|
||||
oracle.add_triangles(triangles);
|
||||
if(wrap_segments)
|
||||
oracle.add_segment_soup(segments);
|
||||
oracle.add_segments(segments);
|
||||
if(wrap_points)
|
||||
oracle.add_point_set(points);
|
||||
oracle.add_points(points);
|
||||
|
||||
if(!oracle.do_call())
|
||||
{
|
||||
|
|
|
|||
Loading…
Reference in New Issue