Merge branch 'master' into Triangulation_2-mark_domains-GF

# Conflicts:
#	Installation/CHANGES.md
This commit is contained in:
Laurent Rineau 2022-06-17 11:00:12 +02:00
commit 1ba31d6e3f
119 changed files with 2532 additions and 1258 deletions

1
.gitignore vendored
View File

@ -2,6 +2,7 @@
/*/*/*/build
/*/*/*/VC*
/*/*/*/GCC
.vscode
AABB_tree/demo/AABB_tree/AABB_demo
AABB_tree/demo/AABB_tree/Makefile
AABB_tree/examples/AABB_tree/*.kdev*

View File

@ -53,9 +53,8 @@ public:
* The two property maps which are template parameters of the class enable to get the datum and the reference point of
* the primitive from the identifier. The last template parameter controls whether the primitive class holds a copy of the datum.
*
* \cgalModels `AABBPrimitive` if `ExternalPropertyMaps` is `CGAL::Tag_false`,
* and `AABBPrimitiveWithSharedData` if `ExternalPropertyMaps` is `CGAL::Tag_true`.
*
* \cgalModels `AABBPrimitive` if `ExternalPropertyMaps` is `CGAL::Tag_false`.
* \cgalModels `AABBPrimitiveWithSharedData` if `ExternalPropertyMaps` is `CGAL::Tag_true`.
*
* \tparam ObjectPropertyMap is a model of `ReadablePropertyMap` with `Id` as
* `key_type`. It must be a model of `CopyConstructible`, `DefaultConstructible`, and `CopyAssignable`.
@ -70,7 +69,6 @@ public:
* it is constructed on the fly to reduce the memory footprint.
* The default is `CGAL::Tag_false` (datum is not stored).
*
* \sa `AABBPrimitive`
* \sa `AABB_segment_primitive<Iterator,CacheDatum>`
* \sa `AABB_triangle_primitive<Iterator,CacheDatum>`
* \sa `AABB_halfedge_graph_segment_primitive<HalfedgeGraph,OneHalfedgeGraphPerTree,CacheDatum>`

View File

@ -562,11 +562,14 @@ public:
/**
* @brief Builds the tree by recursive expansion.
* @param node the root node of the subtree to generate
* @param first the first primitive to insert
* @param last the last primitive to insert
* @param beyond the last primitive to insert
* @param range the number of primitive of the range
* @param compute_bbox a functor
* @param split_primitives a functor
*
* [first,last[ is the range of primitives to be added to the tree.
* [first,beyond[ is the range of primitives to be added to the tree.
*/
template<typename ConstPrimitiveIterator, typename ComputeBbox, typename SplitPrimitives>
void expand(Node& node,
@ -574,8 +577,7 @@ public:
ConstPrimitiveIterator beyond,
const std::size_t range,
const ComputeBbox& compute_bbox,
const SplitPrimitives& split_primitives,
const AABBTraits&);
const SplitPrimitives& split_primitives);
public:
// returns a point which must be on one primitive
@ -791,8 +793,7 @@ public:
ConstPrimitiveIterator beyond,
const std::size_t range,
const ComputeBbox& compute_bbox,
const SplitPrimitives& split_primitives,
const Tr& traits)
const SplitPrimitives& split_primitives)
{
node.set_bbox(compute_bbox(first, beyond));
@ -806,13 +807,13 @@ public:
break;
case 3:
node.set_children(*first, new_node());
expand(node.right_child(), first+1, beyond, 2, compute_bbox, split_primitives, traits);
expand(node.right_child(), first+1, beyond, 2, compute_bbox, split_primitives);
break;
default:
const std::size_t new_range = range/2;
node.set_children(new_node(), new_node());
expand(node.left_child(), first, first + new_range, new_range, compute_bbox, split_primitives, traits);
expand(node.right_child(), first + new_range, beyond, range - new_range, compute_bbox, split_primitives, traits);
expand(node.left_child(), first, first + new_range, new_range, compute_bbox, split_primitives);
expand(node.right_child(), first + new_range, beyond, range - new_range, compute_bbox, split_primitives);
}
}
@ -844,8 +845,7 @@ public:
m_primitives.begin(), m_primitives.end(),
m_primitives.size(),
compute_bbox,
split_primitives,
m_traits);
split_primitives);
}
#ifdef CGAL_HAS_THREADS
m_atomic_need_build.store(false, std::memory_order_release); // in case build() is triggered by a call to root_node()

View File

@ -2,5 +2,4 @@
PROJECT_NAME = "CGAL ${CGAL_DOC_VERSION} - 3D Alpha Shapes"
EXAMPLE_PATH = ${CGAL_Alpha_shapes_2_EXAMPLE_DIR} \
${CGAL_Alpha_shapes_3_EXAMPLE_DIR}
EXAMPLE_PATH += ${CGAL_Alpha_shapes_2_EXAMPLE_DIR}

View File

@ -75,7 +75,7 @@ int main(int argc, char** argv)
std::cerr << "Invalid point set input: " << ps_filename << std::endl;
return EXIT_FAILURE;
}
std::cout << ps_points.size() << " points (Point Set)" << std::endl;
std::cout << ps_points.size() << " points (point set)" << std::endl;
const double relative_alpha = (argc > 4) ? std::stod(argv[4]) : 15.;
const double relative_offset = (argc > 5) ? std::stod(argv[5]) : 450.;
@ -93,9 +93,9 @@ int main(int argc, char** argv)
CGAL::Real_timer t;
t.start();
using TS_Oracle = CGAL::Alpha_wraps_3::internal::Triangle_soup_oracle<Points, Faces>;
using SS_Oracle = CGAL::Alpha_wraps_3::internal::Segment_soup_oracle<Segments, CGAL::Default /*GT*/, TS_Oracle>;
using Oracle = CGAL::Alpha_wraps_3::internal::Point_set_oracle<Points, CGAL::Default /*GT*/, SS_Oracle>;
using TS_Oracle = CGAL::Alpha_wraps_3::internal::Triangle_soup_oracle<K>;
using SS_Oracle = CGAL::Alpha_wraps_3::internal::Segment_soup_oracle<K, TS_Oracle>;
using Oracle = CGAL::Alpha_wraps_3::internal::Point_set_oracle<K, SS_Oracle>;
TS_Oracle ts_oracle(K{});
SS_Oracle ss_oracle(ts_oracle);
@ -124,6 +124,7 @@ int main(int argc, char** argv)
ps_name = ps_name.substr(0, ps_name.find_last_of("."));
std::string output_name = ts_name + "_" + ss_name + "_" + ps_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, output_mesh, CGAL::parameters::stream_precision(17));
return EXIT_SUCCESS;

View File

@ -31,6 +31,8 @@ int main(int argc, char** argv)
return EXIT_FAILURE;
}
std::cout << points.size() << " points" << std::endl;
// Compute the alpha and offset values
const double relative_alpha = (argc > 2) ? std::stod(argv[2]) : 10.;
const double relative_offset = (argc > 3) ? std::stod(argv[3]) : 300.;
@ -41,6 +43,7 @@ int main(int argc, char** argv)
CGAL::square(bbox.zmax() - bbox.zmin()));
const double alpha = diag_length / relative_alpha;
const double offset = diag_length / relative_offset;
std::cout << "absolute alpha = " << alpha << " absolute offset = " << offset << std::endl;
// Construct the wrap
CGAL::Real_timer t;
@ -59,6 +62,7 @@ int main(int argc, char** argv)
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));
return EXIT_SUCCESS;

View File

@ -64,6 +64,7 @@ int main(int argc, char** argv)
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));
return EXIT_SUCCESS;

View File

@ -47,7 +47,7 @@ int main(int argc, char** argv)
const double offset = diag_length / relative_offset;
// Construct the wrap
using Oracle = CGAL::Alpha_wraps_3::internal::Triangle_mesh_oracle<Mesh>;
using Oracle = CGAL::Alpha_wraps_3::internal::Triangle_mesh_oracle<K>;
Oracle oracle;
oracle.add_triangle_mesh(input);
@ -78,6 +78,7 @@ int main(int argc, char** argv)
input_name = input_name.substr(0, input_name.find_last_of("."));
std::string output_name = input_name + "_cavity_" + 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));
return EXIT_SUCCESS;

View File

@ -19,6 +19,11 @@
#ifdef CGAL_AW3_DEBUG_PP
#ifndef CGAL_AW3_DEBUG
#define CGAL_AW3_DEBUG
#define CGAL_AW3_DEBUG_INITIALIZATION
#define CGAL_AW3_DEBUG_STEINER_COMPUTATION
#define CGAL_AW3_DEBUG_QUEUE
#define CGAL_AW3_DEBUG_FACET_STATUS
#define CGAL_AW3_DEBUG_MANIFOLDNESS
#endif
#endif
@ -94,6 +99,32 @@ public:
};
};
struct Wrapping_default_visitor
{
Wrapping_default_visitor() { }
template <typename AlphaWrapper>
void on_alpha_wrapping_begin(const AlphaWrapper&) { }
template <typename AlphaWrapper>
void on_flood_fill_begin(const AlphaWrapper&) { }
template <typename AlphaWrapper, typename Gate>
void before_facet_treatment(const AlphaWrapper&, const Gate&) { }
template <typename Wrapper, typename Point>
void before_Steiner_point_insertion(const Wrapper&, const Point&) { }
template <typename Wrapper, typename VertexHandle>
void after_Steiner_point_insertion(const Wrapper&, VertexHandle) { }
template <typename AlphaWrapper>
void on_flood_fill_end(const AlphaWrapper&) { }
template <typename AlphaWrapper>
void on_alpha_wrapping_end(const AlphaWrapper&) { };
};
template <typename Oracle>
class Alpha_wrap_3
{
@ -167,6 +198,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 Alpha_PQ& queue() const { return m_queue; }
double default_alpha() const
{
@ -211,6 +245,15 @@ public:
OVPM ovpm = choose_parameter(get_parameter(np, internal_np::vertex_point),
get_property_map(vertex_point, output_mesh));
typedef typename internal_np::Lookup_named_param_def <
internal_np::visitor_t,
NamedParameters,
Wrapping_default_visitor // default
>::reference Visitor;
Wrapping_default_visitor default_visitor;
Visitor visitor = choose_parameter(get_parameter_reference(np, internal_np::visitor), default_visitor);
std::vector<Point_3> no_seeds;
using Seeds = typename internal_np::Lookup_named_param_def<
internal_np::seed_points_t, NamedParameters, std::vector<Point_3> >::reference;
@ -223,6 +266,8 @@ public:
t.start();
#endif
visitor.on_alpha_wrapping_begin(*this);
if(!initialize(alpha, offset, seeds))
return;
@ -232,7 +277,7 @@ public:
CGAL::parameters::vertex_point_map(ovpm).stream_precision(17));
#endif
alpha_flood_fill();
alpha_flood_fill(visitor);
#ifdef CGAL_AW3_TIMER
t.stop();
@ -306,10 +351,12 @@ public:
std::cout << "Alpha wrap faces: " << faces(output_mesh).size() << std::endl;
#ifdef CGAL_AW3_DEBUG_DUMP_EVERY_STEP
IO::write_polygon_mesh("final.off", alpha_wrap, CGAL::parameters::stream_precision(17));
IO::write_polygon_mesh("final.off", output_mesh, CGAL::parameters::stream_precision(17));
dump_triangulation_faces("final_dt3.off", false /*only_boundary_faces*/);
#endif
#endif
visitor.on_alpha_wrapping_end(*this);
}
// Convenience overloads
@ -602,11 +649,12 @@ private:
return true;
}
public:
// Manifoldness is tolerated while debugging and extracting at intermediate states
// Not the preferred way because it uses 3*nv storage
template <typename OutputMesh, typename OVPM>
void extract_possibly_non_manifold_surface(OutputMesh& output_mesh,
OVPM ovpm)
OVPM ovpm) const
{
namespace PMP = Polygon_mesh_processing;
@ -691,7 +739,7 @@ private:
template <typename OutputMesh, typename OVPM>
void extract_manifold_surface(OutputMesh& output_mesh,
OVPM ovpm)
OVPM ovpm) const
{
namespace PMP = Polygon_mesh_processing;
@ -743,7 +791,12 @@ private:
if(faces.empty())
return;
CGAL_assertion(PMP::is_polygon_soup_a_polygon_mesh(faces));
if(!PMP::is_polygon_soup_a_polygon_mesh(faces))
{
CGAL_warning_msg(false, "Could NOT extract mesh...");
return;
}
PMP::polygon_soup_to_polygon_mesh(points, faces, output_mesh,
CGAL::parameters::default_values(),
CGAL::parameters::vertex_point_map(ovpm));
@ -758,7 +811,7 @@ private:
template <typename OutputMesh, typename OVPM>
void extract_surface(OutputMesh& output_mesh,
OVPM ovpm,
const bool tolerate_non_manifoldness = false)
const bool tolerate_non_manifoldness = false) const
{
if(tolerate_non_manifoldness)
extract_possibly_non_manifold_surface(output_mesh, ovpm);
@ -788,9 +841,9 @@ private:
const bool is_neighbor_cc_in_offset = m_oracle.do_intersect(neighbor_cc_offset_ball);
#ifdef CGAL_AW3_DEBUG_STEINER_COMPUTATION
const Point_3& chc = circumcenter(ch);
std::cout << "Compute_steiner_point(" << &*ch << ", " << &*neighbor << ")" << std::endl;
std::cout << "Compute_steiner_point()" << std::endl;
const Point_3& chc = circumcenter(ch);
std::cout << "CH" << std::endl;
std::cout << "\t" << ch->vertex(0)->point() << std::endl;
std::cout << "\t" << ch->vertex(1)->point() << std::endl;
@ -985,12 +1038,15 @@ private:
return initialize_with_cavities(seeds);
}
void alpha_flood_fill()
template <typename Visitor>
void alpha_flood_fill(Visitor& visitor)
{
#ifdef CGAL_AW3_DEBUG
std::cout << "> Flood fill..." << std::endl;
#endif
visitor.on_flood_fill_begin(*this);
// Explore all finite cells that are reachable from one of the initial outside cells.
while(!m_queue.empty())
{
@ -1012,11 +1068,13 @@ private:
std::cout << m_dt.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"
<< "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;
std::cout << "Priority: " << gate.priority() << std::endl;
#endif
visitor.before_facet_treatment(*this, gate);
m_queue.pop();
#ifdef CGAL_AW3_DEBUG_DUMP_EVERY_STEP
@ -1077,10 +1135,14 @@ private:
m_queue.erase(Gate(mf));
}
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;
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));
@ -1128,6 +1190,8 @@ private:
}
} // while(!queue.empty())
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;)

View File

@ -267,7 +267,11 @@ public:
for(int i=0; i<4; ++i)
{
if(!q.m_b.test(i) && do_overlap(q.m_tbox[i], bb) && Base::operator()(q.m_triangles[i], bb))
// this overload of do_intersect() must not filter based on q.m_b because
// it is called from the AABB_tree's traversal with a node's bounding box,
// and the fact that a facet is incident to an outside cell is irrelevant
// for the hierarchy of bounding boxes of the primitives.
if(do_overlap(q.m_tbox[i], bb) && Base::operator()(q.m_triangles[i], bb))
return true;
}

View File

@ -142,41 +142,85 @@ public:
BaseOracle& base() { return static_cast<BaseOracle&>(*this); }
const BaseOracle& base() const { return static_cast<const BaseOracle&>(*this); }
bool empty() const { return m_tree_ptr->empty(); }
bool do_call() const { return (!empty() || base().do_call()); }
public:
typename AABB_tree::Bounding_box bbox() const
{
CGAL_precondition(!tree().empty());
CGAL_precondition(do_call());
return base().bbox() + tree().bbox();
typename AABB_tree::Bounding_box bb;
if(base().do_call())
bb += base().bbox();
if(!empty())
bb += tree().bbox();
return bb;
}
template <typename T>
bool do_intersect(const T& t) const
{
if(base().do_intersect(t))
CGAL_precondition(do_call());
if(base().do_call() && base().do_intersect(t))
return true;
return AABB_helper::do_intersect(t, tree());
if(!empty())
return AABB_helper::do_intersect(t, tree());
return false;
}
FT squared_distance(const Point_3& p) const
{
const FT base_sqd = base().squared_distance(p);
CGAL_precondition(do_call());
// @speed could do a smarter traversal, no need to search deeper than the current best
const FT this_sqd = AABB_helper::squared_distance(p, tree());
return (std::min)(base_sqd, this_sqd);
if(base().do_call())
{
if(!empty()) // both non empty
{
const FT base_sqd = base().squared_distance(p);
// @speed could do a smarter traversal, no need to search deeper than the current best
const FT this_sqd = AABB_helper::squared_distance(p, tree());
return (std::min)(base_sqd, this_sqd);
}
else // this level is empty
{
return base().squared_distance(p);
}
}
else // empty base
{
return AABB_helper::squared_distance(p, tree());
}
}
Point_3 closest_point(const Point_3& p) const
{
const Point_3 base_c = base().closest_point(p);
CGAL_precondition(do_call());
// @speed could do a smarter traversal, no need to search deeper than the current best
const Point_3 this_c = AABB_helper::closest_point(p, tree());
return (compare_distance_to_point(p, base_c, this_c) == CGAL::SMALLER) ? base_c : this_c;
if(base().do_call())
{
if(!empty()) // both non empty
{
const Point_3 base_c = base().closest_point(p);
// @speed could do a smarter traversal, no need to search deeper than the current best
const Point_3 this_c = AABB_helper::closest_point(p, tree());
return (compare_distance_to_point(p, base_c, this_c) == CGAL::SMALLER) ? base_c : this_c;
}
else // this level is empty
{
return base().closest_point(p);
}
}
else // empty base
{
return AABB_helper::closest_point(p, tree());
}
}
bool first_intersection(const Point_3& p, const Point_3& q,
@ -184,22 +228,38 @@ public:
const FT offset_size,
const FT intersection_precision) const
{
Point_3 base_o;
bool base_b = base().first_intersection(p, q, base_o, offset_size, intersection_precision);
CGAL_precondition(do_call());
if(base_b)
if(base().do_call())
{
// @speed could do a smarter traversal, no need to search deeper than the current best
Point_3 this_o;
bool this_b = AABB_helper::first_intersection(p, q, this_o, offset_size, intersection_precision, tree());
if(this_b)
o = (compare_distance_to_point(p, base_o, this_o) == SMALLER) ? base_o : this_o;
else
o = base_o;
if(!empty()) // both non empty
{
Point_3 base_o;
bool base_b = base().first_intersection(p, q, base_o, offset_size, intersection_precision);
return true;
if(base_b) // intersection found in base
{
// @speed could do a smarter traversal, no need to search deeper than the current best
Point_3 this_o;
bool this_b = AABB_helper::first_intersection(p, q, this_o, offset_size, intersection_precision, tree());
if(this_b)
o = (compare_distance_to_point(p, base_o, this_o) == SMALLER) ? base_o : this_o;
else
o = base_o;
return true;
}
else // no intersection found in non-empty base
{
return AABB_helper::first_intersection(p, q, o, offset_size, intersection_precision, tree());
}
}
else // this level is empty
{
return base().first_intersection(p, q, o, offset_size, intersection_precision);
}
}
else
else // empty base
{
return AABB_helper::first_intersection(p, q, o, offset_size, intersection_precision, tree());
}
@ -250,10 +310,13 @@ public:
AABB_tree& tree() { return *m_tree_ptr; }
const AABB_tree& tree() const { return *m_tree_ptr; }
bool empty() const { return m_tree_ptr->empty(); }
bool do_call() const { return !empty(); }
public:
typename AABB_tree::Bounding_box bbox() const
{
CGAL_precondition(!tree().empty());
CGAL_precondition(!empty());
return tree().bbox();
}
@ -261,27 +324,32 @@ public:
template <typename T>
bool do_intersect(const T& t) const
{
CGAL_precondition(!empty());
return AABB_helper::do_intersect(t, tree());
}
FT squared_distance(const Point_3& p) const
{
CGAL_precondition(!empty());
return AABB_helper::squared_distance(p, tree());
}
Point_3 closest_point(const Point_3& p) const
{
CGAL_precondition(!empty());
return AABB_helper::closest_point(p, tree());
}
bool first_intersection(const Point_3& p, const Point_3& q, Point_3& o,
const FT offset_size, const FT intersection_precision) const
{
CGAL_precondition(!empty());
return AABB_helper::first_intersection(p, q, o, offset_size, intersection_precision, tree());
}
bool first_intersection(const Point_3& p, const Point_3& q, Point_3& o, const FT offset_size) const
{
CGAL_precondition(!empty());
return AABB_helper::first_intersection(p, q, o, offset_size, 1e-2 * offset_size, tree());
}

View File

@ -24,45 +24,25 @@
#include <CGAL/Named_function_parameters.h>
#include <CGAL/property_map.h>
#include <boost/range/value_type.hpp>
#include <algorithm>
#include <iostream>
#include <iterator>
#include <functional>
#include <vector>
namespace CGAL {
namespace Alpha_wraps_3 {
namespace internal {
// No longer used, but might find some purpose again in the future
template <class InputIterator, class PM>
struct Point_from_iterator_map
{
using key_type = InputIterator;
using value_type = typename boost::property_traits<PM>::value_type;
using reference = typename boost::property_traits<PM>::reference;
using category = boost::readable_property_map_tag;
Point_from_iterator_map(const PM& pm = PM()) : pm(pm) { }
inline friend reference get(const Point_from_iterator_map& map, const key_type it)
{
return get(map.pm, *it);
}
PM pm;
};
// Just some typedefs for readability
template <typename PointRange, typename GT_>
template <typename GT_>
struct PS_oracle_traits
{
using Point = typename boost::range_value<PointRange>::type;
using Default_GT = typename Kernel_traits<Point>::Kernel;
using Base_GT = typename Default::Get<GT_, Default_GT>::type; // = Kernel, usually
using Geom_traits = Alpha_wrap_AABB_traits<Base_GT>; // Wrap the kernel to add Ball_3 + custom Do_intersect_3
using Geom_traits = Alpha_wrap_AABB_traits<GT_>; // Wrap the kernel to add Ball_3 + custom Do_intersect_3
using Points = std::vector<typename GT_::Point_3>;
using PR_iterator = typename Points::const_iterator;
using PR_iterator = typename PointRange::const_iterator;
using Primitive = AABB_primitive<PR_iterator,
Input_iterator_property_map<PR_iterator> /*DPM*/,
Input_iterator_property_map<PR_iterator> /*RPM*/,
@ -73,25 +53,28 @@ struct PS_oracle_traits
using AABB_tree = CGAL::AABB_tree<AABB_traits>;
};
template <typename PointRange,
typename GT_ = CGAL::Default,
template <typename GT_,
typename BaseOracle = int>
class Point_set_oracle
: public AABB_tree_oracle<typename PS_oracle_traits<PointRange, GT_>::Geom_traits,
typename PS_oracle_traits<PointRange, GT_>::AABB_tree,
: public AABB_tree_oracle<typename PS_oracle_traits<GT_>::Geom_traits,
typename PS_oracle_traits<GT_>::AABB_tree,
CGAL::Default, // Default_traversal_traits<AABB_traits>
BaseOracle>
{
using PSOT = PS_oracle_traits<PointRange, GT_>;
using Base_GT = typename PSOT::Base_GT;
using PSOT = PS_oracle_traits<GT_>;
using Base_GT = GT_;
public:
using Geom_traits = typename PSOT::Geom_traits;
private:
using Points = typename PSOT::Points;
using AABB_tree = typename PSOT::AABB_tree;
using Oracle_base = AABB_tree_oracle<Geom_traits, AABB_tree, CGAL::Default, BaseOracle>;
private:
Points m_points;
public:
// Constructors
Point_set_oracle()
@ -110,9 +93,10 @@ public:
public:
// adds a range of points to the oracle
template <typename NamedParameters = parameters::Default_named_parameters>
template <typename PointRange,
typename CGAL_NP_TEMPLATE_PARAMETERS>
void add_point_set(const PointRange& points,
const NamedParameters& /*np*/ = CGAL::parameters::default_values())
const CGAL_NP_CLASS& /*np*/ = CGAL::parameters::default_values())
{
if(points.empty())
{
@ -122,11 +106,16 @@ public:
return;
}
const std::size_t old_size = m_points.size();
m_points.insert(std::cend(m_points), std::cbegin(points), std::cend(points));
#ifdef CGAL_AW3_DEBUG
std::cout << "Insert into AABB tree (points)..." << std::endl;
#endif
this->tree().insert(points.begin(), points.end());
this->tree().insert(std::next(std::cbegin(m_points), old_size), std::cend(m_points));
CGAL_postcondition(this->tree().size() == m_points.size());
}
};

View File

@ -24,26 +24,25 @@
#include <CGAL/Named_function_parameters.h>
#include <CGAL/property_map.h>
#include <boost/range/value_type.hpp>
#include <algorithm>
#include <iostream>
#include <iterator>
#include <functional>
#include <vector>
namespace CGAL {
namespace Alpha_wraps_3 {
namespace internal {
// Just some typedefs for readability
template <typename SegmentRange, typename GT_>
template <typename GT_>
struct SS_oracle_traits
{
using Segment = typename boost::range_value<SegmentRange>::type;
using Default_GT = typename Kernel_traits<Segment>::Kernel;
using Base_GT = typename Default::Get<GT_, Default_GT>::type; // = Kernel, usually
using Geom_traits = Alpha_wrap_AABB_traits<Base_GT>; // Wrap the kernel to add Ball_3 + custom Do_intersect_3
using Geom_traits = Alpha_wrap_AABB_traits<GT_>; // Wrap the kernel to add Ball_3 + custom Do_intersect_3
using Segments = std::vector<typename GT_::Segment_3>;
using SR_iterator = typename Segments::const_iterator;
using SR_iterator = typename SegmentRange::const_iterator;
using Primitive = AABB_primitive<SR_iterator,
Input_iterator_property_map<SR_iterator>, // DPM
CGAL::internal::Source_of_segment_3_iterator_property_map<Geom_traits, SR_iterator>, // RPM
@ -54,25 +53,28 @@ struct SS_oracle_traits
using AABB_tree = CGAL::AABB_tree<AABB_traits>;
};
template <typename SegmentRange,
typename GT_ = CGAL::Default,
template <typename GT_,
typename BaseOracle = int>
class Segment_soup_oracle
: public AABB_tree_oracle<typename SS_oracle_traits<SegmentRange, GT_>::Geom_traits,
typename SS_oracle_traits<SegmentRange, GT_>::AABB_tree,
: public AABB_tree_oracle<typename SS_oracle_traits<GT_>::Geom_traits,
typename SS_oracle_traits<GT_>::AABB_tree,
CGAL::Default, // Default_traversal_traits<AABB_traits>
BaseOracle>
{
using SSOT = SS_oracle_traits<SegmentRange, GT_>;
using Base_GT = typename SSOT::Base_GT;
using SSOT = SS_oracle_traits<GT_>;
using Base_GT = GT_;
public:
using Geom_traits = typename SSOT::Geom_traits;
private:
using Segments = typename SSOT::Segments;
using AABB_tree = typename SSOT::AABB_tree;
using Oracle_base = AABB_tree_oracle<Geom_traits, AABB_tree, CGAL::Default, BaseOracle>;
private:
Segments m_segments;
public:
// Constructors
Segment_soup_oracle()
@ -90,9 +92,10 @@ public:
{ }
public:
template <typename NamedParameters = parameters::Default_named_parameters>
template <typename SegmentRange,
typename CGAL_NP_TEMPLATE_PARAMETERS>
void add_segment_soup(const SegmentRange& segments,
const NamedParameters& /*np*/ = CGAL::parameters::default_values())
const CGAL_NP_CLASS& /*np*/ = CGAL::parameters::default_values())
{
if(segments.empty())
{
@ -102,12 +105,15 @@ public:
return;
}
const std::size_t old_size = m_segments.size();
m_segments.insert(std::cend(m_segments), std::cbegin(segments), std::cend(segments));
#ifdef CGAL_AW3_DEBUG
std::cout << "Insert into AABB tree (segments)..." << std::endl;
#endif
this->tree().insert(segments.begin(), segments.end());
this->tree().insert(std::next(std::cbegin(m_segments), old_size), std::cend(m_segments));
CGAL_postcondition(this->tree().size() == segments.size());
CGAL_postcondition(this->tree().size() == m_segments.size());
}
};

View File

@ -34,41 +34,36 @@ namespace Alpha_wraps_3 {
namespace internal {
// Just some typedefs for readability in the main oracle class
template <typename TriangleMesh, typename GT_>
template <typename GT_>
struct TM_oracle_traits
{
using Default_GT = typename GetGeomTraits<TriangleMesh>::type;
using Geom_traits = Alpha_wrap_AABB_traits<GT_>; // Wrap the kernel to add Ball_3 + custom Do_intersect_3
using Base_GT = typename Default::Get<GT_, Default_GT>::type; // = Kernel, usually
using Geom_traits = Alpha_wrap_AABB_traits<Base_GT>; // Wrap the kernel to add Ball_3 + custom Do_intersect_3
using Point_3 = typename Geom_traits::Point_3;
using AABB_traits = typename AABB_tree_splitter_traits<Point_3, Geom_traits>::AABB_traits;
using AABB_tree = typename AABB_tree_splitter_traits<Point_3, Geom_traits>::AABB_tree;
};
// @speed could do a partial specialization 'subdivide = false' with simpler code for speed?
template <typename TriangleMesh,
typename GT_ = CGAL::Default,
template <typename GT_,
typename BaseOracle = int,
bool subdivide = true>
class Triangle_mesh_oracle
: // this is the base that handles calls to the AABB tree
public AABB_tree_oracle<typename TM_oracle_traits<TriangleMesh, GT_>::Geom_traits,
typename TM_oracle_traits<TriangleMesh, GT_>::AABB_tree,
public AABB_tree_oracle<typename TM_oracle_traits<GT_>::Geom_traits,
typename TM_oracle_traits<GT_>::AABB_tree,
typename std::conditional<
/*condition*/subdivide,
/*true*/Splitter_traversal_traits<typename TM_oracle_traits<TriangleMesh, GT_>::AABB_traits>,
/*false*/Default_traversal_traits<typename TM_oracle_traits<TriangleMesh, GT_>::AABB_traits> >::type,
/*true*/Splitter_traversal_traits<typename TM_oracle_traits<GT_>::AABB_traits>,
/*false*/Default_traversal_traits<typename TM_oracle_traits<GT_>::AABB_traits> >::type,
BaseOracle>,
// this is the base that handles splitting input faces and inserting them into the AABB tree
public AABB_tree_oracle_splitter<subdivide,
typename TM_oracle_traits<TriangleMesh, GT_>::Point_3,
typename TM_oracle_traits<TriangleMesh, GT_>::Geom_traits>
typename TM_oracle_traits<GT_>::Point_3,
typename TM_oracle_traits<GT_>::Geom_traits>
{
using face_descriptor = typename boost::graph_traits<TriangleMesh>::face_descriptor;
using TMOT = TM_oracle_traits<TriangleMesh, GT_>;
using Base_GT = typename TMOT::Base_GT;
using TMOT = TM_oracle_traits<GT_>;
using Base_GT = GT_;
public:
using Geom_traits = typename TMOT::Geom_traits;
@ -122,13 +117,16 @@ public:
{ }
public:
template <typename NamedParameters = parameters::Default_named_parameters>
template <typename TriangleMesh,
typename CGAL_NP_TEMPLATE_PARAMETERS>
void add_triangle_mesh(const TriangleMesh& tmesh,
const NamedParameters& np = CGAL::parameters::default_values())
const CGAL_NP_CLASS& np = CGAL::parameters::default_values())
{
using parameters::get_parameter;
using parameters::choose_parameter;
using face_descriptor = typename boost::graph_traits<TriangleMesh>::face_descriptor;
using VPM = typename GetVertexPointMap<TriangleMesh>::const_type;
using Point_ref = typename boost::property_traits<VPM>::reference;

View File

@ -35,42 +35,34 @@ namespace Alpha_wraps_3 {
namespace internal {
// Just some typedefs for readability
template <typename PointRange, typename FaceRange, typename GT_>
template <typename GT_>
struct TS_oracle_traits
{
using Default_NP = parameters::Default_named_parameters;
using Default_NP_helper = Point_set_processing_3_np_helper<PointRange, Default_NP>;
using Default_GT = typename Default_NP_helper::Geom_traits;
using Base_GT = typename Default::Get<GT_, Default_GT>::type; // = Kernel, usually
using Geom_traits = Alpha_wrap_AABB_traits<Base_GT>; // Wrap the kernel to add Ball_3 + custom Do_intersect_3
using Geom_traits = Alpha_wrap_AABB_traits<GT_>; // Wrap the kernel to add Ball_3 + custom Do_intersect_3
using Point_3 = typename Geom_traits::Point_3;
using AABB_traits = typename AABB_tree_splitter_traits<Point_3, Geom_traits>::AABB_traits;
using AABB_tree = typename AABB_tree_splitter_traits<Point_3, Geom_traits>::AABB_tree;
};
template <typename PointRange, typename FaceRange,
typename GT_ = CGAL::Default,
template <typename GT_,
typename BaseOracle = int,
bool subdivide = true>
class Triangle_soup_oracle
: // this is the base that handles calls to the AABB tree
public AABB_tree_oracle<typename TS_oracle_traits<PointRange, FaceRange, GT_>::Geom_traits,
typename TS_oracle_traits<PointRange, FaceRange, GT_>::AABB_tree,
public AABB_tree_oracle<typename TS_oracle_traits<GT_>::Geom_traits,
typename TS_oracle_traits<GT_>::AABB_tree,
typename std::conditional<
/*condition*/subdivide,
/*true*/Splitter_traversal_traits<typename TS_oracle_traits<PointRange, FaceRange, GT_>::AABB_traits>,
/*false*/Default_traversal_traits<typename TS_oracle_traits<PointRange, FaceRange, GT_>::AABB_traits> >::type,
/*true*/Splitter_traversal_traits<typename TS_oracle_traits<GT_>::AABB_traits>,
/*false*/Default_traversal_traits<typename TS_oracle_traits<GT_>::AABB_traits> >::type,
BaseOracle>,
// this is the base that handles splitting input faces and inserting them into the AABB tree
public AABB_tree_oracle_splitter<subdivide,
typename TS_oracle_traits<PointRange, FaceRange, GT_>::Point_3,
typename TS_oracle_traits<PointRange, FaceRange, GT_>::Geom_traits>
typename TS_oracle_traits<GT_>::Point_3,
typename TS_oracle_traits<GT_>::Geom_traits>
{
using Face = typename boost::range_value<FaceRange>::type;
using TSOT = TS_oracle_traits<PointRange, FaceRange, GT_>;
using Base_GT = typename TSOT::Base_GT;
using TSOT = TS_oracle_traits<GT_>;
using Base_GT = GT_;
public:
using Geom_traits = typename TSOT::Geom_traits;
@ -124,17 +116,20 @@ public:
{ }
public:
template <typename NamedParameters = parameters::Default_named_parameters>
template <typename PointRange, typename FaceRange,
typename CGAL_NP_TEMPLATE_PARAMETERS>
void add_triangle_soup(const PointRange& points,
const FaceRange& faces,
const NamedParameters& np = CGAL::parameters::default_values())
const CGAL_NP_CLASS& np = CGAL::parameters::default_values())
{
using parameters::choose_parameter;
using parameters::get_parameter;
using PPM = typename GetPointMap<PointRange, NamedParameters>::const_type;
using PPM = typename GetPointMap<PointRange, CGAL_NP_CLASS>::const_type;
using Point_ref = typename boost::property_traits<PPM>::reference;
using Face = typename boost::range_value<FaceRange>::type;
if(points.empty() || faces.empty())
{
#ifdef CGAL_AW3_DEBUG
@ -178,6 +173,22 @@ public:
std::cout << "Tree: " << this->tree().size() << " primitives (" << faces.size() << " faces in input)" << 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())
{
typename Geom_traits::Is_degenerate_3 is_degenerate = this->geom_traits().is_degenerate_3_object();
for(const Triangle_3& tr : triangles)
{
if(is_degenerate(tr))
continue;
Splitter_base::split_and_insert_datum(tr, this->tree(), this->geom_traits());
}
}
};
} // namespace internal

View File

@ -104,7 +104,7 @@ void alpha_wrap_3(const PointRange& points,
using NP_helper = Point_set_processing_3_np_helper<PointRange, InputNamedParameters>;
using Geom_traits = typename NP_helper::Geom_traits;
using Oracle = Alpha_wraps_3::internal::Triangle_soup_oracle<PointRange, FaceRange, Geom_traits>;
using Oracle = Alpha_wraps_3::internal::Triangle_soup_oracle<Geom_traits>;
using AW3 = Alpha_wraps_3::internal::Alpha_wrap_3<Oracle>;
Geom_traits gt = choose_parameter<Geom_traits>(get_parameter(in_np, internal_np::geom_traits));
@ -253,7 +253,7 @@ void alpha_wrap_3(const TriangleMesh& tmesh,
using parameters::choose_parameter;
using Geom_traits = typename GetGeomTraits<TriangleMesh, InputNamedParameters>::type;
using Oracle = Alpha_wraps_3::internal::Triangle_mesh_oracle<TriangleMesh, Geom_traits>;
using Oracle = Alpha_wraps_3::internal::Triangle_mesh_oracle<Geom_traits>;
using AW3 = Alpha_wraps_3::internal::Alpha_wrap_3<Oracle>;
Geom_traits gt = choose_parameter<Geom_traits>(get_parameter(in_np, internal_np::geom_traits));
@ -349,7 +349,7 @@ void alpha_wrap_3(const PointRange& points,
using NP_helper = Point_set_processing_3_np_helper<PointRange, InputNamedParameters>;
using Geom_traits = typename NP_helper::Geom_traits;
using Oracle = Alpha_wraps_3::internal::Point_set_oracle<PointRange, Geom_traits>;
using Oracle = Alpha_wraps_3::internal::Point_set_oracle<Geom_traits>;
using AW3 = Alpha_wraps_3::internal::Alpha_wrap_3<Oracle>;
Geom_traits gt = choose_parameter<Geom_traits>(get_parameter(in_np, internal_np::geom_traits));

View File

@ -55,7 +55,8 @@ void alpha_wrap_triangle_mesh(Mesh& input_mesh,
namespace AW3 = CGAL::Alpha_wraps_3;
namespace PMP = CGAL::Polygon_mesh_processing;
using Oracle = AW3::internal::Triangle_mesh_oracle<Mesh>;
using Geom_traits = typename CGAL::GetGeomTraits<Mesh>::type;
using Oracle = AW3::internal::Triangle_mesh_oracle<Geom_traits>;
std::cout << "Input: " << num_vertices(input_mesh) << " vertices, " << num_faces(input_mesh) << " faces" << std::endl;

View File

@ -36,7 +36,7 @@ void alpha_wrap_triangle_soup(Points& pr,
namespace AW3 = CGAL::Alpha_wraps_3;
namespace PMP = CGAL::Polygon_mesh_processing;
using Oracle = AW3::internal::Triangle_soup_oracle<Points, Faces, Kernel, int, false /*subdivide*/>;
using Oracle = AW3::internal::Triangle_soup_oracle<Kernel, int, false /*subdivide*/>;
std::cout << "Input: " << pr.size() << " points, " << fr.size() << " faces" << std::endl;

View File

@ -6241,7 +6241,7 @@ face, respectively, \f$v_b\f$, \f$e_b\f$, and \f$f_b\f$ denote input
<span style="color:blue;">blue</span> features, and \f$v\f$, \f$e\f$,
and \f$f\f$ denote output features.
<OL compact>
<OL>
<LI> A new vertex \f$v\f$ is induced by coinciding vertices
\f$v_r\f$ and \f$v_b\f$.</LI>

View File

@ -34,8 +34,6 @@
#include <CGAL/Arrangement_2/Arrangement_2_iterators.h>
#include <CGAL/assertions.h>
#include <boost/pool/pool_alloc.hpp>
namespace CGAL {
inline void* _clean_pointer(const void* p)
@ -964,7 +962,7 @@ public:
* The arrangement DCEL class.
*/
template <class V, class H, class F,
class Allocator = boost::fast_pool_allocator<int> >
class Allocator = CGAL_ALLOCATOR(int) >
class Arr_dcel_base {
public:
// Define the vertex, halfedge and face types.

View File

@ -48,8 +48,6 @@
#include <CGAL/Iterator_transform.h>
#include <CGAL/Arr_point_location_result.h>
#include <boost/pool/pool_alloc.hpp>
namespace CGAL {
/*! \class Arrangement_on_surface_2
@ -68,7 +66,7 @@ class Arrangement_on_surface_2 {
public:
typedef GeomTraits_ Geometry_traits_2;
typedef TopTraits_ Topology_traits;
typedef boost::fast_pool_allocator<int> Allocator;
typedef CGAL_ALLOCATOR(int) Allocator;
// first define adaptor ...
typedef Arr_traits_basic_adaptor_2<Geometry_traits_2> Traits_adaptor_2;

View File

@ -21,13 +21,12 @@ INPUT += ${CGAL_PACKAGE_INCLUDE_DIR}/CGAL/boost/graph/Euler_operations.h \
${CGAL_PACKAGE_INCLUDE_DIR}/CGAL/boost/graph/graph_traits_inheritance_macros.h
EXAMPLE_PATH = ${CGAL_Surface_mesh_skeletonization_EXAMPLE_DIR} \
${CGAL_Surface_mesh_segmentation_EXAMPLE_DIR} \
${CGAL_Polygon_mesh_processing_EXAMPLE_DIR} \
${CGAL_Surface_mesh_EXAMPLE_DIR} \
${CGAL_Property_map_EXAMPLE_DIR} \
${CGAL_Polyhedron_EXAMPLE_DIR} \
${CGAL_BGL_EXAMPLE_DIR}
EXAMPLE_PATH += ${CGAL_Surface_mesh_skeletonization_EXAMPLE_DIR} \
${CGAL_Surface_mesh_segmentation_EXAMPLE_DIR} \
${CGAL_Polygon_mesh_processing_EXAMPLE_DIR} \
${CGAL_Surface_mesh_EXAMPLE_DIR} \
${CGAL_Property_map_EXAMPLE_DIR} \
${CGAL_Polyhedron_EXAMPLE_DIR}
ALIASES += "bgllink{1}=<a href=\"http://www.boost.org/libs/graph/doc/\1.html\"><code>\1</code></a>"

View File

@ -237,7 +237,8 @@ inline bool do_intersect(const General_polygon_with_holes_2<Polygon_>& pgn1,
// With Traits
template <typename InputIterator, typename Traits>
inline bool do_intersect(InputIterator begin, InputIterator end, Traits& traits,
unsigned int k=5)
unsigned int k=5,
std::enable_if_t<CGAL::is_iterator<InputIterator>::value>* = 0)
{ return r_do_intersect(begin, end, traits, k); }
// Without Traits
@ -245,6 +246,7 @@ inline bool do_intersect(InputIterator begin, InputIterator end, Traits& traits,
template <typename InputIterator>
inline bool do_intersect(InputIterator begin, InputIterator end,
Tag_true = Tag_true(), unsigned int k=5,
std::enable_if_t<CGAL::is_iterator<InputIterator>::value>* = 0,
Enable_if_Polygon_2_iterator<InputIterator>* = 0)
{ return r_do_intersect(begin, end, k); }
@ -252,6 +254,7 @@ inline bool do_intersect(InputIterator begin, InputIterator end,
template <typename InputIterator>
inline bool do_intersect(InputIterator begin, InputIterator end,
Tag_false, unsigned int k=5,
std::enable_if_t<CGAL::is_iterator<InputIterator>::value>* = 0,
Enable_if_Polygon_2_iterator<InputIterator>* = 0)
{
typename Iterator_to_gps_traits<InputIterator>::Traits traits;
@ -262,6 +265,7 @@ inline bool do_intersect(InputIterator begin, InputIterator end,
template <typename InputIterator>
inline bool do_intersect(InputIterator begin, InputIterator end,
unsigned int k=5,
std::enable_if_t<CGAL::is_iterator<InputIterator>::value>* = 0,
Disable_if_Polygon_2_iterator<InputIterator>* = 0)
{
typename Iterator_to_gps_traits<InputIterator>::Traits traits;

View File

@ -288,8 +288,7 @@ inline OutputIterator
intersection(InputIterator begin, InputIterator end,
OutputIterator oi, unsigned int k=5,
// workaround to avoid ambiguous calls with kernel functions
typename boost::enable_if
<typename CGAL::is_iterator<InputIterator>>::type* = 0,
std::enable_if_t<CGAL::is_iterator<InputIterator>::value>* = 0,
Disable_if_Polygon_2_iterator<InputIterator>* = 0)
{
typename Iterator_to_gps_traits<InputIterator>::Traits traits;

View File

@ -257,29 +257,6 @@ The first list of items are meant as rules, <I>i.e.</I>, you should follow them.
...
#endif // CGAL_THIS_IS_AN_EXAMPLE_H
\endcode
- Support the
<A HREF="https://www.boost.org/doc/libs/release/libs/utility/utility.htm#result_of">result_of</A>
protocol whenever your functors have more than one return type
otherwise provide a `result_type` member typedef.
An example for this is a C++03 style `identity` functor:
\code{.cpp}
struct Identity {
template<typename T>
T& operator()(T& t) { return t; }
template<typename T>
const T& operator()(const T& t) { return t; }
template<typename>
struct result;
template<typename F, typename T>
struct result<F(T&)> {
typedef T& type;
};
template<typename F, typename T>
struct result<F(const T&)> {
typedef const T& type;
};
};
\endcode
The following items can be seen as recommendations
in contrast to the rules of previous paragraph.

View File

@ -63,14 +63,14 @@ class Some_further_class_local_to_Package;
According to the resolutions of the following issues in the forthcoming
\cpp-standard (
<a href="http://www.open-std.org/jtc1/sc22/wg21/docs/lwg-defects.html#225">225</a>,
<a href="http://www.open-std.org/jtc1/sc22/wg21/docs/lwg-defects.html#226">226</a>
<a href="http://www.open-std.org/jtc1/sc22/wg21/docs/lwg-defects.html#229">229</a>.
<a href="https://www.open-std.org/jtc1/sc22/wg21/docs/lwg-defects.html#225">225</a>,
<a href="https://www.open-std.org/jtc1/sc22/wg21/docs/lwg-defects.html#226">226</a> and
<a href="https://www.open-std.org/jtc1/sc22/wg21/docs/lwg-defects.html#229">229</a>
):
<TT>Unless otherwise specified, no global or non-member function in the standard library
<blockquote>Unless otherwise specified, no global or non-member function in the standard library
shall use a function from another namespace which is found through argument-dependent
name lookup
</TT>, the namespace `CGAL::NTS` does not need to be used anymore
name lookup</blockquote>
the namespace `CGAL::NTS` does not need to be used anymore
(currently `CGAL_NTS` macro boils down to `CGAL::`).
\section Developer_manualRequirementsandrecommendations_1 Requirements and recommendations

View File

@ -1,8 +1,3 @@
///This concept refines both
/// <a href="https://en.cppreference.com/w/cpp/named_req/CopyAssignable"><tt>CopyAssignable</tt></a>
///and <a href="https://en.cppreference.com/w/cpp/named_req/CopyConstructible"><tt>CopyConstructible</tt></a>.
class Assignable {};
/// \cgalConcept
/// Concept from the \cpp standard.
/// See https://en.cppreference.com/w/cpp/named_req/DefaultConstructible
@ -13,6 +8,14 @@ class DefaultConstructible {};
/// See https://en.cppreference.com/w/cpp/named_req/CopyConstructible
class CopyConstructible {};
/// \cgalConcept
/// Concept from the \cpp standard.
/// See https://en.cppreference.com/w/cpp/named_req/CopyAssignable
class CopyAssignable {};
///This concept refines both `CopyAssignable` and `CopyConstructible`.
class Assignable {};
/// \cgalConcept
/// Concept from the \cpp standard.
/// See https://en.cppreference.com/w/cpp/named_req/Callable

View File

@ -44,16 +44,6 @@ also avoid CMake to link with the native threads support library on your system.
After being based on the \CC standard released in 1998 (and later refined in 2003) for a long time,
\cgal is now based on a newer major version of the standard, <a href="https://isocpp.org/wiki/faq/cpp14">C++14</a>.
\section Preliminaries_functor Functor Return Types
\cgal functors support the
<a href="https://www.boost.org/doc/libs/release/libs/utility/utility.htm#result_of">result_of</a>
protocol. If a functor `F` has the same return type across all
overloads of `operator()`, the nested type
`F::result_type` is defined to be that type. Otherwise the
return type of calling the functor with an argument of type
`Arg` can be accessed through \link CGAL::cpp11::result_of::type `CGAL::cpp11::result_of<F(Arg)>::type` \endlink.
\section preliminaries_secchecks Checks
Much of the \cgal code contains assert statements for preconditions, and postconditions of functions

View File

@ -12,7 +12,7 @@ supporting <a href="https://isocpp.org/wiki/faq/cpp14">C++14</a> or later.
| Operating System | Compiler |
| :---------- | :--------------- |
| Linux | \gnu `g++` 10.2.1 or later\cgalFootnote{<A HREF="http://gcc.gnu.org/">\cgalFootnoteCode{http://gcc.gnu.org/}</A>} |
| | `Clang` \cgalFootnote{<A HREF="http://clang.llvm.org/">\cgalFootnoteCode{http://clang.llvm.org/}</A>} compiler version 13.0.0 |
| | `Clang` \cgalFootnote{<A HREF="http://clang.llvm.org/">\cgalFootnoteCode{http://clang.llvm.org/}</A>} compiler version 13.0.1 |
| \ms Windows | \gnu `g++` 10.2.1 or later\cgalFootnote{<A HREF="http://gcc.gnu.org/">\cgalFootnoteCode{http://gcc.gnu.org/}</A>} |
| | \ms Visual `C++` 14.0, 15.9, 16.10, 17.0 (\visualstudio 2015, 2017, 2019, and 2022)\cgalFootnote{<A HREF="https://visualstudio.microsoft.com/">\cgalFootnoteCode{https://visualstudio.microsoft.com/}</A>} |
| MacOS X | \gnu `g++` 10.2.1 or later\cgalFootnote{<A HREF="http://gcc.gnu.org/">\cgalFootnoteCode{http://gcc.gnu.org/}</A>} |
@ -117,7 +117,7 @@ The exhaustive list of \qt5 components used in demos is:
`qcollectiongenerator` (with `sqlite` driver plugin), and `Xml`.
\subsection thirdpartyEigen Eigen
<b>Version 3.1 or later</b>
<b>Version 3.3.4 or later</b>
\eigen is a `C++` template library for linear algebra. \eigen supports all
matrix sizes, various matrix decomposition methods and sparse linear solvers.

View File

@ -6,9 +6,10 @@
var current_version_local = 'master'
var all_versions = [
'master',
'5.5-beta1',
'latest',
'5.4',
'5.3.1',
'5.4.1',
'5.3.2',
'5.2.4',
'5.1.5',
'5.0.4',

View File

@ -6,9 +6,10 @@
var current_version_local = 'master'
var all_versions = [
'master',
'5.5-beta1',
'latest',
'5.4',
'5.3.1',
'5.4.1',
'5.3.2',
'5.2.4',
'5.1.5',
'5.0.4',

View File

@ -6,9 +6,10 @@
var current_version_local = 'master'
var all_versions = [
'master',
'5.5-beta1',
'latest',
'5.4',
'5.3.1',
'5.4.1',
'5.3.2',
'5.2.4',
'5.1.5',
'5.0.4',

View File

@ -6,9 +6,10 @@
var current_version_local = 'master'
var all_versions = [
'master',
'5.5-beta1',
'latest',
'5.4',
'5.3.1',
'5.4.1',
'5.3.2',
'5.2.4',
'5.1.5',
'5.0.4',

View File

@ -254,6 +254,11 @@ removes some unneeded files, and performs minor repair on some glitches.''')
resources_absdir=args.resources
os.chdir(args.output)
#workaround issue with operator<< in pyquery
all_pages=glob.glob('*/*.html')
for f in all_pages:
re_replace_in_file("operator<<\(\)", "operator&lt;&lt;()", f)
# number figure
automagically_number_figures()

View File

@ -18,6 +18,7 @@
#include <CGAL/Qt/quaternion.h>
#include <CGAL/export/Qt.h>
#include <QOpenGLFunctions_2_1>
#include <QOpenGLFunctions>
namespace CGAL{
class QGLViewer;
@ -199,6 +200,7 @@ public:
CGAL::QGLViewer's window dimensions when the Camera is attached to a CGAL::QGLViewer. See
also QOpenGLWidget::height() */
int screenHeight() const { return screenHeight_; }
qreal devicePixelRatio() const { return devicePixelRatio_; }
void getViewport(GLint viewport[4]) const;
qreal pixelGLRatio(const Vec &position) const;
@ -279,7 +281,7 @@ public Q_SLOTS:
setScreenWidthAndHeight(int(100.0 * aspect), 100);
}
void setScreenWidthAndHeight(int width, int height);
void setScreenWidthAndHeight(int width, int height, qreal devicePixelRatio = 1.0);
/*! Sets the zNearCoefficient() value. */
void setZNearCoefficient(qreal coef) {
zNearCoef_ = coef;
@ -444,6 +446,7 @@ private:
// C a m e r a p a r a m e t e r s
int screenWidth_, screenHeight_; // size of the window, in pixels
qreal devicePixelRatio_;
qreal fieldOfView_; // in radians
Vec sceneCenter_;
qreal sceneRadius_; // OpenGL units
@ -467,6 +470,36 @@ private:
KeyFrameInterpolator *interpolationKfi_;
};
inline void read_pixel(const QPoint &pixel, QOpenGLFunctions *p,
const Camera *camera, GLenum format, GLenum type,
GLvoid *pixel_data) {
const auto pixel_ratio = camera->devicePixelRatio();
p->glReadPixels(pixel.x() * pixel_ratio,
(camera->screenHeight() - pixel.y()) * pixel_ratio - 1, 1, 1,
format, type, pixel_data);
}
inline auto read_pixel_as_float_rgb(const QPoint &pixel, QOpenGLFunctions *p,
const Camera *camera) {
std::array<float, 3> res;
read_pixel(pixel, p, camera, GL_RGB, GL_FLOAT, res.data());
return res;
}
inline auto read_pixel_as_ubyte_rgba(const QPoint &pixel, QOpenGLFunctions *p,
const Camera *camera) {
std::array<GLubyte, 4> res;
read_pixel(pixel, p, camera, GL_RGBA, GL_UNSIGNED_BYTE, res.data());
return res;
}
inline float read_depth_under_pixel(const QPoint &pixel, QOpenGLFunctions *p,
const Camera *camera) {
float depth = 2.0f;
read_pixel(pixel, p, camera, GL_DEPTH_COMPONENT, GL_FLOAT, &depth);
return depth;
}
} // namespace qglviewer
} //CGAL
#endif // QGLVIEWER_CAMERA_H

View File

@ -160,10 +160,11 @@ frustrum coherence.
If your Camera is used without a CGAL::QGLViewer (offscreen rendering, shadow maps),
use setAspectRatio() instead to define the projection matrix. */
CGAL_INLINE_FUNCTION
void Camera::setScreenWidthAndHeight(int width, int height) {
void Camera::setScreenWidthAndHeight(int width, int height, qreal devicePixelRatio) {
// Prevent negative and zero dimensions that would cause divisions by zero.
screenWidth_ = width > 0 ? width : 1;
screenHeight_ = height > 0 ? height : 1;
devicePixelRatio_ = devicePixelRatio;
projectionMatrixIsUpToDate_ = false;
}
@ -884,8 +885,7 @@ Vec Camera::pointUnderPixel(const QPoint &pixel, bool &found) const {
// Qt uses upper corner for its origin while GL uses the lower corner.
if(auto p = dynamic_cast<QOpenGLFunctions*>(parent()))
{
p->glReadPixels(pixel.x(), screenHeight() - 1 - pixel.y(), 1, 1,
GL_DEPTH_COMPONENT, GL_FLOAT, &depth);
depth = read_depth_under_pixel(pixel, p, this);
}
found = depth < 1.0;
Vec point(pixel.x(), pixel.y(), depth);

View File

@ -563,6 +563,21 @@ public:
*/
void saveSnapshot();
/*!
* Takes a snapshot without any dialog
*/
void saveSnapshot(const QString& fileName,
const qreal finalWidth,
const qreal finalHeight,
const bool expand = false,
const double oversampling = 1.,
qglviewer::SnapShotBackground background_color = qglviewer::CURRENT_BACKGROUND);
void saveSnapshot(const QString& fileName)
{
return saveSnapshot(fileName, this->width(), this->height());
}
public:
Q_SIGNALS:
/*! Signal emitted by the default init() method.

View File

@ -807,7 +807,7 @@ void CGAL::QGLViewer::setCamera(qglviewer::Camera *const camera) {
camera->setSceneRadius(sceneRadius());
camera->setSceneCenter(sceneCenter());
camera->setScreenWidthAndHeight(width(), height());
camera->setScreenWidthAndHeight(width(), height(), devicePixelRatio());
// Disconnect current camera from this viewer.
disconnect(this->camera()->frame(), SIGNAL(manipulated()), this,
@ -1147,7 +1147,9 @@ void CGAL::QGLViewer::beginSelection(const QPoint &point)
{
makeCurrent();
glEnable(GL_SCISSOR_TEST);
glScissor(point.x(), camera()->screenHeight()-1-point.y(), 1, 1);
glScissor(point.x() * devicePixelRatio(),
(camera()->screenHeight() - point.y()) * devicePixelRatio() - 1, 1,
1);
}
/*! This method is called by select() after scene elements were drawn by
@ -2369,7 +2371,7 @@ CGAL_INLINE_FUNCTION
void CGAL::QGLViewer::resizeGL(int width, int height) {
QOpenGLWidget::resizeGL(width, height);
glViewport(0, 0, GLint(width), GLint(height));
camera()->setScreenWidthAndHeight(this->width(), this->height());
camera()->setScreenWidthAndHeight(this->width(), this->height(), this->devicePixelRatio());
}
//////////////////////////////////////////////////////////////////////////
@ -3187,10 +3189,11 @@ void CGAL::QGLViewer::drawVisualHints() {
mvpMatrix.ortho(-1,1,-1,1,-1,1);
size=30*devicePixelRatio();
rendering_program.setUniformValue("mvp_matrix", mvpMatrix);
glViewport(GLint((camera()->projectedCoordinatesOf(camera()->pivotPoint()).x-size/2)*devicePixelRatio()),
GLint((height() - camera()->projectedCoordinatesOf(camera()->pivotPoint()).y-size/2)*devicePixelRatio()), size, size);
glScissor (GLint((camera()->projectedCoordinatesOf(camera()->pivotPoint()).x-size/2)*devicePixelRatio()),
GLint((height() - camera()->projectedCoordinatesOf(camera()->pivotPoint()).y-size/2)*devicePixelRatio()), size, size);
const auto point_2d = camera()->projectedCoordinatesOf(camera()->pivotPoint());
glViewport(GLint(point_2d.x*devicePixelRatio()-size/2),
GLint((height() - point_2d.y)*devicePixelRatio()-size/2), size, size);
glScissor (GLint(point_2d.x*devicePixelRatio()-size/2),
GLint((height() - point_2d.y)*devicePixelRatio()-size/2), size, size);
rendering_program.setUniformValue("color", QColor(::Qt::black));
glDisable(GL_DEPTH_TEST);
glDrawArrays(GL_LINES, 0, static_cast<GLsizei>(4));
@ -3758,8 +3761,29 @@ void CGAL::QGLViewer::saveSnapshot()
}
}
CGAL_INLINE_FUNCTION
void CGAL::QGLViewer::saveSnapshot(const QString& fileName,
const qreal finalWidth, const qreal finalHeight,
const bool expand,
const double oversampling,
qglviewer::SnapShotBackground background_color)
{
if(fileName.isEmpty())
return;
QSize finalSize(finalWidth, finalHeight);
QImage* image = takeSnapshot(qglviewer::SnapShotBackground(background_color),
finalSize, oversampling, expand);
if(image)
{
image->save(fileName);
delete image;
}
}
} // namespace CGAL
CGAL_INLINE_FUNCTION
bool CGAL::QGLViewer::isSharing() const
{

View File

@ -24,7 +24,6 @@ void test_vertex_handles(
assert(hds_list.vertex_handles().size() == 1);
for (auto vh : hds_list.vertex_handles()) {
assert(vh == lit);
assert(vh->point() == lit->point());
assert(vh->halfedge() == lit->halfedge());
++lit;
}
@ -34,7 +33,6 @@ void test_vertex_handles(
assert(hds_vector.vertex_handles().size() == 1);
for (auto vh : hds_vector.vertex_handles()) {
assert(vh == vit);
assert(vh->point() == vit->point());
assert(vh->halfedge() == vit->halfedge());
++vit;
}
@ -49,7 +47,6 @@ void test_const_vertex_handles(
assert(hds_list.vertex_handles().size() == 1);
for (const auto& vh : hds_list.vertex_handles()) {
assert(vh == lit);
assert(vh->point() == lit->point());
assert(vh->halfedge() == lit->halfedge());
++lit;
}
@ -59,7 +56,6 @@ void test_const_vertex_handles(
assert(hds_vector.vertex_handles().size() == 1);
for (const auto& vh : hds_vector.vertex_handles()) {
assert(vh == vit);
assert(vh->point() == vit->point());
assert(vh->halfedge() == vit->halfedge());
++vit;
}
@ -74,7 +70,6 @@ void test_face_handles(
assert(hds_list.face_handles().size() == 2);
for (auto fh : hds_list.face_handles()) {
assert(fh == lit);
assert(fh->plane() == lit->plane());
assert(fh->halfedge() == lit->halfedge());
++lit;
}
@ -84,7 +79,6 @@ void test_face_handles(
assert(hds_vector.face_handles().size() == 2);
for (auto fh : hds_vector.face_handles()) {
assert(fh == vit);
assert(fh->plane() == vit->plane());
assert(fh->halfedge() == vit->halfedge());
++vit;
}
@ -99,7 +93,6 @@ void test_const_face_handles(
assert(hds_list.face_handles().size() == 2);
for (const auto& fh : hds_list.face_handles()) {
assert(fh == lit);
assert(fh->plane() == lit->plane());
assert(fh->halfedge() == lit->halfedge());
++lit;
}
@ -109,7 +102,6 @@ void test_const_face_handles(
assert(hds_vector.face_handles().size() == 2);
for (const auto& fh : hds_vector.face_handles()) {
assert(fh == vit);
assert(fh->plane() == vit->plane());
assert(fh->halfedge() == vit->halfedge());
++vit;
}

View File

@ -2,8 +2,6 @@
EXTRACT_PRIVATE = NO
EXAMPLE_PATH = ${CGAL_PACKAGE_DIR}/examples
PROJECT_NAME = "CGAL ${CGAL_DOC_VERSION} - 2D Hyperbolic Delaunay Triangulations"
HTML_EXTRA_STYLESHEET = ${CGAL_PACKAGE_DOC_DIR}/css/customstyle.css

View File

@ -7,7 +7,7 @@ Release History
Release date: June 2022
### 3D Alpha Wrapping (new package)
### [3D Alpha Wrapping (new package)](https://doc.cgal.org/5.5/Manual/packages.html#PkgAlphaWrap3)
- This component takes a 3D triangle mesh, soup, or point set as input, and generates a valid
(watertight, intersection-free, and combinatorially 2-manifold) surface triangle mesh
@ -19,29 +19,26 @@ Release date: June 2022
to the input, respectively. Once combined, these parameters provide a means to trade fidelity
to the input for complexity of the output.
### [Point Set Processing](https://doc.cgal.org/5.5/Manual/packages.html#PkgPointSetProcessing3)
- A new optional named parameter, `min_points_per_cell` has been added to [`grid_simplify_point_set()`](https://doc.cgal.org/5.5/Point_set_processing_3/group__PkgPointSetProcessing3Algorithms.html#ga7757ef9b3900e42fde26f5a0ac56e20f). By adding a minimal number of points in a cell such that a point is retained, one can also filter out low density areas and outliers: in the case of densely sampled point clouds, this yields better results than using grid simplification and then outlier removal, while being very vast. The default value is `1` to keep the previous behavior as default.
### [dD Spatial Searching](https://doc.cgal.org/5.5/Manual/packages.html#PkgSpatialSearchingD)
- Added the member function `write_graphviz()` to the class `Kd_tree` that writes the tree in a stream in the [Graphviz](https://graphviz.org/) format.
See also the [announcement page](https://www.cgal.org/2022/05/18/alpha_wrap/).
### [3D Convex Hulls](https://doc.cgal.org/5.5/Manual/packages.html#PkgConvexHull3)
- Added an overload of the function `CGAL::convex_hull_3()`, which writes the result in an indexed triangle set.
- Added an [overload of the function `CGAL::convex_hull_3()`](https://doc.cgal.org/5.5/Convex_hull_3/group__PkgConvexHull3Functions.html#ga52fca4745c2ef0351063fbe66b035fd1), which writes the result in an indexed triangle set.
### Surface Mesh Simplification
- Introduced four variations of the Garland-Heckbert simplification algorithm based on the probabilistic approach of Trettner and Kobbelt (Fast and Robust QEF Minimization using Probabilistic Quadrics): `GarlandHeckbert_plane_policies`, `GarlandHeckbert_probabilistic_plane_policies`, `GarlandHeckbert_triangle_policies`, and `GarlandHeckbert_probabilistic_triangle_policies`
- The class `GarlandHeckbert_policies` has been deprecated, `GarlandHeckbert_plane_policies` replaces it.
### [2D Polygons](https://doc.cgal.org/5.5/Manual/packages.html#PkgPolygon2)
### [CGAL and the Boost Graph Library (BGL)](https://doc.cgal.org/5.5/Manual/packages.html#PkgBGL)
- Add vertex, edge, and hole ranges.
- The concept [`GeneralPolygonWithHoles_2`](https://doc.cgal.org/5.5/Polygon/classGeneralPolygonWithHoles__2.html) now requires the nested type `Polygon_2` instead of `General_polygon_2`.
- Added the function [`invert_selection()`](https://doc.cgal.org/5.5/BGL/structCGAL_1_1Face__filtered__graph.html#aa428541ebbdd35f9a6e9a3ffd60178df) in the class [`Face_filtered_graph`](https://doc.cgal.org/5.5/BGL/structCGAL_1_1Face__filtered__graph.html), which toggles the selected status of a graph: selected faces are deselected, and unselected faces are selected.
### [2D Regularized Boolean Set-Operations](https://doc.cgal.org/5.5/Manual/packages.html#PkgBooleanSetOperations2)
- The concept [`GeneralPolygonSetTraits_2`](https://doc.cgal.org/5.5/Boolean_set_operations_2/classGeneralPolygonSetTraits__2.html) now requires the nested type `Construct_polygon_with_holes_2` instead of `Construct_general_polygon_with_holes_2`.
### Combinatorial Maps
### [Combinatorial Maps](https://doc.cgal.org/5.5/Manual/packages.html#PkgCombinatorialMaps)
- Removed old code deprecated in CGAL 4.9 and 4.10 (global fonctions, and information associated with darts).
- Removed old code deprecated in CGAL 4.9 and 4.10 (global functions, and information associated with darts).
### [2D Arrangements](https://doc.cgal.org/5.5/Manual/packages.html#PkgArrangementOnSurface2)
- Fixed the `intersect_2`, `compare_y_at_x_right`, and `compare_y_at_x_left` function objects of the traits class template [`Arr_geodesic_arc_on_sphere_traits_2`](https://doc.cgal.org/5.5/Arrangement_on_surface_2/classCGAL_1_1Arr__geodesic__arc__on__sphere__traits__2.html) that handles geodesic arcs on sphere and applied a small syntactical fix to the tracing traits.
### [Tetrahedral Mesh Generation](https://doc.cgal.org/5.5/Manual/packages.html#PkgMesh3)
@ -50,22 +47,27 @@ Release date: June 2022
as a post-processing step for the tetrahedral mesh generation.
### [Polygon Mesh Processing](https://doc.cgal.org/5.5/Manual/packages.html#PkgPolygonMeshProcessing)
- Added the function `CGAL::Polygon_mesh_processing::orient_triangle_soup_with_reference_triangle_soup()`, which enables re-orienting the faces of a triangle soup based on the orientation of the nearest face in a reference triangle soup.
- Added the function `CGAL::Polygon_mesh_processing::compatible_orientations()`, which enables to retrieve the (in)compatibility of orientations of faces from different connected components.
- Added the function `CGAL::Polygon_mesh_processing::tangential_relaxation()`, which applies an area-based tangential mesh smoothing to the vertices of a surface triangle mesh.
- Added the named parameter `visitor`to the function `triangulate_hole()`, which enables to track progress with callbacks.
- Added the function [`CGAL::Polygon_mesh_processing::orient_triangle_soup_with_reference_triangle_soup()`](https://doc.cgal.org/5.5/Polygon_mesh_processing/group__PMP__orientation__grp.html#ga855b1c55c201b91ab04eebd2811a87fd), which enables re-orienting the faces of a triangle soup based on the orientation of the nearest face in a reference triangle soup.
- Added the function [`CGAL::Polygon_mesh_processing::compatible_orientations()`](https://doc.cgal.org/5.5/Polygon_mesh_processing/group__PMP__orientation__grp.html#ga9ac9b9434084b64f3304df636c3178a3), which enables to retrieve the (in)compatibility of orientations of faces from different connected components.
- Added the function [`CGAL::Polygon_mesh_processing::tangential_relaxation()`](https://doc.cgal.org/5.5/Polygon_mesh_processing/group__PMP__meshing__grp.html#ga136c659162e5360354db5879db7431b4), which applies an area-based tangential mesh smoothing to the vertices of a surface triangle mesh.
- Added the named parameter `visitor` to the function [`triangulate_hole()`](https://doc.cgal.org/5.5/Polygon_mesh_processing/group__PMP__hole__filling__grp.html#gad2d3c43bce0ef90a16530478196d7f42), which enables to track progress with callbacks.
- Added more functions in the [visitor of the corefinement based methods](https://doc.cgal.org/5.5/Polygon_mesh_processing/classPMPCorefinementVisitor.html) to track progress.
### [2D Polygons](https://doc.cgal.org/5.5/Manual/packages.html#PkgPolygon2)
### [Surface Mesh Simplification](https://doc.cgal.org/5.5/Manual/packages.html#PkgSurfaceMeshSimplification)
- Introduced four variations of the Garland-Heckbert simplification algorithm based on the probabilistic approach of Trettner and Kobbelt (Fast and Robust QEF Minimization using Probabilistic Quadrics): [`GarlandHeckbert_plane_policies`](https://doc.cgal.org/5.5/Surface_mesh_simplification/classCGAL_1_1Surface__mesh__simplification_1_1GarlandHeckbert__plane__policies.html), [`GarlandHeckbert_probabilistic_plane_policies`](https://doc.cgal.org/5.5/Surface_mesh_simplification/classCGAL_1_1Surface__mesh__simplification_1_1GarlandHeckbert__probabilistic__plane__policies.html), [`GarlandHeckbert_triangle_policies`](https://doc.cgal.org/5.5/Surface_mesh_simplification/classCGAL_1_1Surface__mesh__simplification_1_1GarlandHeckbert__triangle__policies.html), and [`GarlandHeckbert_probabilistic_triangle_policies`](https://doc.cgal.org/5.5/Surface_mesh_simplification/classCGAL_1_1Surface__mesh__simplification_1_1GarlandHeckbert__probabilistic__triangle__policies.html).
- The class `GarlandHeckbert_policies` has been deprecated, `GarlandHeckbert_plane_policies` replaces it.
- Add vertex, edge, and hole ranges.
- The concept `GeneralPolygonWithHoles_2` now requires the nested type `Polygon_2` instead of `General_polygon_2`.
### [Point Set Processing](https://doc.cgal.org/5.5/Manual/packages.html#PkgPointSetProcessing3)
### [2D Regularized Boolean Set-Operations](https://doc.cgal.org/5.5/Manual/packages.html#PkgBooleanSetOperations2)
- The concept `GeneralPolygonSetTraits_2` now requires the nested type `Construct_polygon_with_holes_2` instead of `Construct_general_polygon_with_holes_2`.
- A new optional named parameter, `min_points_per_cell` has been added to [`grid_simplify_point_set()`](https://doc.cgal.org/5.5/Point_set_processing_3/group__PkgPointSetProcessing3Algorithms.html#ga7757ef9b3900e42fde26f5a0ac56e20f). By adding a minimal number of points in a cell such that a point is retained, one can also filter out low density areas and outliers: in the case of densely sampled point clouds, this yields better results than using grid simplification and then outlier removal, while being very vast. The default value is `1` to keep the previous behavior as default.
### [2D Arrangements](https://doc.cgal.org/5.5/Manual/packages.html#PkgArrangementOnSurface2)
- Fixed the intersect_2, compare_y_at_x_right, and compare_y_at_x_left function objects of the traits class template that handles geodesic arcs on sphere and applied a small syntactical fix to the tracing traits.
### [dD Spatial Searching](https://doc.cgal.org/5.5/Manual/packages.html#PkgSpatialSearchingD)
- Added the member function [`write_graphviz()`](https://doc.cgal.org/5.5/Spatial_searching/classCGAL_1_1Kd__tree.html#ac2851b5cafb8d5cce0dc5fb107c8f13f) to the class `Kd_tree` that writes the tree in a stream in the [Graphviz](https://graphviz.org/) format.
### [CGAL and the Boost Graph Library (BGL)](https://doc.cgal.org/5.5/Manual/packages.html#PkgBGL)
- Added the function [`invert_selection()`](https://doc.cgal.org/5.5/BGL/structCGAL_1_1Face__filtered__graph.html#aa428541ebbdd35f9a6e9a3ffd60178df) in the class [`Face_filtered_graph`](https://doc.cgal.org/5.5/BGL/structCGAL_1_1Face__filtered__graph.html), which toggles the selected status of a graph: selected faces are deselected, and unselected faces are selected.
[Release 5.4](https://github.com/CGAL/cgal/releases/tag/v5.4)

View File

@ -75,6 +75,13 @@ endif()
# keyword.
#
function(CGAL_setup_CGAL_dependencies target)
foreach(dir ${CGAL_INCLUDE_DIRS})
target_include_directories(${target} INTERFACE
$<BUILD_INTERFACE:${dir}>)
endforeach()
target_include_directories(${target} INTERFACE
$<INSTALL_INTERFACE:include>)
if(CGAL_DISABLE_GMP)
target_compile_definitions(${target} INTERFACE CGAL_DISABLE_GMP=1)
else()
@ -96,13 +103,6 @@ function(CGAL_setup_CGAL_dependencies target)
use_CGAL_Boost_support(${target} INTERFACE)
foreach(dir ${CGAL_INCLUDE_DIRS})
target_include_directories(${target} INTERFACE
$<BUILD_INTERFACE:${dir}>)
endforeach()
target_include_directories(${target} INTERFACE
$<INSTALL_INTERFACE:include>)
# Make CGAL depend on threads-support (for Epeck and Epeck_d)
if(CGAL_HAS_NO_THREADS)
target_compile_definitions(${target} INTERFACE CGAL_HAS_NO_THREADS)

View File

@ -17,12 +17,12 @@
#define CGAL_VERSION_H
#ifndef SWIG
#define CGAL_VERSION 5.5-dev
#define CGAL_VERSION 5.6-dev
#define CGAL_GIT_HASH abcdef
#endif
#define CGAL_VERSION_NR 1050500900
#define CGAL_VERSION_NR 1050600900
#define CGAL_SVN_REVISION 99999
#define CGAL_RELEASE_DATE 20220531
#define CGAL_RELEASE_DATE 20221131
#include <CGAL/version_macros.h>

View File

@ -89,7 +89,9 @@ if (NOT CGAL_DATA_DIR)
if (EXISTS "${CMAKE_SOURCE_DIR}/../../data")
set(CGAL_DATA_DIR "${CMAKE_SOURCE_DIR}/../../data")
else()
message(WARNING "CGAL_DATA_DIR cannot be deduced, set the variable CGAL_DATA_DIR to set the default value of CGAL::data_file_path()")
if(CGAL_TEST_SUITE)
message(WARNING "CGAL_DATA_DIR cannot be deduced, set the variable CGAL_DATA_DIR to set the default value of CGAL::data_file_path()")
endif()
endif()
endif()
endif()

View File

@ -1,5 +1,5 @@
set(CGAL_MAJOR_VERSION 5)
set(CGAL_MINOR_VERSION 5)
set(CGAL_MINOR_VERSION 6)
set(CGAL_BUGFIX_VERSION 0)
include(${CMAKE_CURRENT_LIST_DIR}/CGALConfigBuildVersion.cmake)
set(CGAL_VERSION_PUBLIC_RELEASE_VERSION "5.5-dev")

View File

@ -353,6 +353,42 @@ protected:
mutable typename K::Point_2 _intersection_point, _other_point;
};
inline
double s2s2_alpha(double x0, double y0,
double x1, double y1,
double x2, double y2,
double x3, double y3)
{
const double s1_dx = x0 - x1,
s1_dy = y0 - y1,
s2_dx = x3 - x2,
s2_dy = y3 - y2,
lx = x3 - x1,
ly = y3 - y1;
double val = std::fma(lx,s2_dy,-ly*s2_dx)/std::fma(s1_dx,s2_dy,-s1_dy*s2_dx);
if (val!=val) return 0.5;
if (val<0) return 0;
if (val>1) return 1;
return val;
}
template <class FT>
FT s2s2_alpha(const FT& x0, const FT& y0,
const FT& x1, const FT& y1,
const FT& x2, const FT& y2,
const FT& x3, const FT& y3)
{
FT s1_dx = x0 - x1,
s1_dy = y0 - y1,
s2_dx = x3 - x2,
s2_dy = y3 - y2,
lx = x3 - x1,
ly = y3 - y1;
return (lx*s2_dy-ly*s2_dx)/(s1_dx*s2_dy-s1_dy*s2_dx);
}
template <class K>
typename Segment_2_Segment_2_pair<K>::Intersection_results
Segment_2_Segment_2_pair<K>::intersection_type() const
@ -400,14 +436,8 @@ Segment_2_Segment_2_pair<K>::intersection_type() const
: CGAL::make_array( _seg2->point(s2s2_id[c][2]), _seg2->point(s2s2_id[c][3]),
_seg1->point(s2s2_id[c][0]), _seg1->point(s2s2_id[c][1]) );
typename K::FT s1_dx = pts[0].x() - pts[1].x(),
s1_dy = pts[0].y() - pts[1].y(),
s2_dx = pts[3].x() - pts[2].x(),
s2_dy = pts[3].y() - pts[2].y(),
lx = pts[3].x() - pts[1].x(),
ly = pts[3].y() - pts[1].y();
typename K::FT alpha = s2s2_alpha(pts[0].x(), pts[0].y(), pts[1].x(), pts[1].y(), pts[2].x(), pts[2].y(), pts[3].x(), pts[3].y());
typename K::FT alpha = (lx*s2_dy-ly*s2_dx)/(s1_dx*s2_dy-s1_dy*s2_dx);
_intersection_point = K().construct_barycenter_2_object()(pts[0], alpha, pts[1]);
return _result;

View File

@ -0,0 +1,15 @@
#include <CGAL/Exact_predicates_exact_constructions_kernel.h>
#include <CGAL/Boolean_set_operations_2.h>
#include <CGAL/Polygon_mesh_processing/corefinement.h>
#include <CGAL/Surface_mesh.h>
int main()
{
typedef CGAL::Exact_predicates_exact_constructions_kernel Kernel;
typedef Kernel::Point_3 Point;
typedef CGAL::Surface_mesh<Point> Surface_mesh;
Surface_mesh mesh;
CGAL::Polygon_mesh_processing::experimental::autorefine_and_remove_self_intersections(mesh);
return 0;
}

View File

@ -30,7 +30,7 @@ do_intersect(const typename K::Segment_3& s1,
{
CGAL_precondition(!s1.is_degenerate() && !s2.is_degenerate());
bool b = do_intersect(s1.supporting_line(), s2.supporting_line(), k);
bool b = internal::do_intersect(s1.supporting_line(), s2.supporting_line(), k);
if(b)
{
// supporting_line intersects: points are coplanar

View File

@ -3548,7 +3548,7 @@ namespace CommonKernelFunctors {
// 25 possibilities, so I keep the template.
template <class T1, class T2>
decltype(auto)
typename CGAL::Intersection_traits<K,T1,T2>::result_type
operator()(const T1& t1, const T2& t2) const
{ return Intersections::internal::intersection(t1, t2, K()); }
};
@ -3561,11 +3561,11 @@ namespace CommonKernelFunctors {
// n possibilities, so I keep the template.
template <class T1, class T2>
decltype(auto)
typename CGAL::Intersection_traits<K,T1,T2>::result_type
operator()(const T1& t1, const T2& t2) const
{ return Intersections::internal::intersection(t1, t2, K() ); }
decltype(auto)
boost::optional<boost::variant<typename K::Point_3, typename K::Line_3, typename K::Plane_3> >
operator()(const Plane_3& pl1, const Plane_3& pl2, const Plane_3& pl3)const
{ return Intersections::internal::intersection(pl1, pl2, pl3, K() ); }
};

View File

@ -19,16 +19,18 @@ LC_CTYPE=en_US.UTF-8
# The script also updates the manual tools.
# "master" alone
0 21 * * Sun cd $HOME/CGAL/create_internal_release && /usr/bin/time scl enable rh-git29 -- $HOME/bin/create_release $HOME/CGAL/branches/master.git --do-it || echo ERROR
0 21 * * Sun cd $HOME/CGAL/create_internal_release && /usr/bin/time scl enable rh-git29 -- $HOME/bin/create_release $HOME/CGAL/branches/master.git --do-it --beta 2 --public || echo ERROR
# "integration"
0 21 * * Mon,Tue,Wed,Thu cd $HOME/CGAL/create_internal_release && /usr/bin/time scl enable rh-git29 -- $HOME/bin/create_release $HOME/CGAL/branches/integration.git $HOME/CGAL/branches/empty-dir --do-it || echo ERROR
# from branch 5.5
0 21 * * Fri cd $HOME/CGAL/create_internal_release-5.5-branch && /usr/bin/time scl enable rh-git29 -- $HOME/bin/create_release $HOME/CGAL/branches/CGAL-5.5-branch.git --public --do-it || echo ERROR
# from branch 5.4
0 21 * * Fri cd $HOME/CGAL/create_internal_release-5.4-branch && /usr/bin/time scl enable rh-git29 -- $HOME/bin/create_release $HOME/CGAL/branches/CGAL-5.4-branch.git --public --do-it || echo ERROR
# from branch 5.3
0 21 * * Sat cd $HOME/CGAL/create_internal_release-5.3-branch && /usr/bin/time scl enable rh-git29 -- $HOME/bin/create_release $HOME/CGAL/branches/CGAL-5.3-branch.git --public --do-it || echo ERROR
0 21 * * Sat cd $HOME/CGAL/create_internal_release-5.4-branch && /usr/bin/time scl enable rh-git29 -- $HOME/bin/create_release $HOME/CGAL/branches/CGAL-5.4-branch.git --public --do-it || echo ERROR
## Older stuff
# from branch 5.3
0 21 * * Sat cd $HOME/CGAL/create_internal_release-5.3-branch && /usr/bin/time scl enable rh-git29 -- $HOME/bin/create_release $HOME/CGAL/branches/CGAL-5.3-branch.git --public --do-it || echo ERROR
# from branch 5.2
#0 21 * * Fri cd $HOME/CGAL/create_internal_release-5.2-branch && /usr/bin/time scl enable rh-git29 -- $HOME/bin/create_release $HOME/CGAL/branches/CGAL-5.2-branch.git --public --do-it || echo ERROR
# from branch 5.1

View File

@ -1,88 +1,62 @@
%The CGAL Open Source Project is pleased to announce the release 5.3 Beta 1 of CGAL, the Computational Geometry Algorithms Library.
The CGAL Open Source Project is pleased to announce the release 5.5 Beta 1 of CGAL, the Computational Geometry Algorithms Library.
CGAL version 5.3 Beta 1 is a public testing release. It should provide a solid ground to report bugs that need to be tackled before the release of the final version of CGAL 5.3 in July 2021.
CGAL version 5.5 Beta 1 is a public testing release. It should provide a solid ground to report bugs that need to be tackled before the release of the final version of CGAL 5.5 in July 2022.
Besides fixes and general enhancement to existing packages, the following has changed since CGAL 5.4:
### [3D Alpha Wrapping (new package)](https://doc.cgal.org/5.5/Manual/packages.html#PkgAlphaWrap3)
- This component takes a 3D triangle mesh, soup, or point set as input, and generates a valid (watertight, intersection-free, and combinatorially 2-manifold) surface triangle mesh that contains the input.
The algorithm proceeds by shrink-wrapping and refining a 3D Delaunay triangulation, starting from a loose bounding box of the input.
Two user-defined parameters, alpha and offset, offer control over the maximum size of cavities where the shrink-wrapping process can enter, and the tightness of the final surface mesh to the input, respectively. Once combined, these parameters provide a means to trade fidelity
to the input for complexity of the output.
See also the [announcement page](https://www.cgal.org/2022/05/18/alpha_wrap/).
### [3D Convex Hulls](https://doc.cgal.org/5.5/Manual/packages.html#PkgConvexHull3)
- Added an [overload of the function `CGAL::convex_hull_3()`](https://doc.cgal.org/5.5/Convex_hull_3/group__PkgConvexHull3Functions.html#ga52fca4745c2ef0351063fbe66b035fd1), which writes the result in an indexed triangle set.
### [2D Polygons](https://doc.cgal.org/5.5/Manual/packages.html#PkgPolygon2)
- Add vertex, edge, and hole ranges.
- The concept [`GeneralPolygonWithHoles_2`](https://doc.cgal.org/5.5/Polygon/classGeneralPolygonWithHoles__2.html) now requires the nested type `Polygon_2` instead of `General_polygon_2`.
### [2D Regularized Boolean Set-Operations](https://doc.cgal.org/5.5/Manual/packages.html#PkgBooleanSetOperations2)
- The concept [`GeneralPolygonSetTraits_2`](https://doc.cgal.org/5.5/Boolean_set_operations_2/classGeneralPolygonSetTraits__2.html) now requires the nested type `Construct_polygon_with_holes_2` instead of `Construct_general_polygon_with_holes_2`.
### [Combinatorial Maps](https://doc.cgal.org/5.5/Manual/packages.html#PkgCombinatorialMaps)
- Removed old code deprecated in CGAL 4.9 and 4.10 (global functions, and information associated with darts).
### [2D Arrangements](https://doc.cgal.org/5.5/Manual/packages.html#PkgArrangementOnSurface2)
- Fixed the `intersect_2`, `compare_y_at_x_right`, and `compare_y_at_x_left` function objects of the traits class template [`Arr_geodesic_arc_on_sphere_traits_2`](https://doc.cgal.org/5.5/Arrangement_on_surface_2/classCGAL_1_1Arr__geodesic__arc__on__sphere__traits__2.html) that handles geodesic arcs on sphere and applied a small syntactical fix to the tracing traits.
### [Tetrahedral Mesh Generation](https://doc.cgal.org/5.5/Manual/packages.html#PkgMesh3)
- Added the function [`remove_isolated_vertices()`](https://doc.cgal.org/5.5/Mesh_3/classCGAL_1_1Mesh__complex__3__in__triangulation__3.html#ace57c4e777da457c6e33b4f6e89949ce) as a post-processing step for the tetrahedral mesh generation.
### [Polygon Mesh Processing](https://doc.cgal.org/5.5/Manual/packages.html#PkgPolygonMeshProcessing)
- Added the function [`CGAL::Polygon_mesh_processing::orient_triangle_soup_with_reference_triangle_soup()`](https://doc.cgal.org/5.5/Polygon_mesh_processing/group__PMP__orientation__grp.html#ga855b1c55c201b91ab04eebd2811a87fd), which enables re-orienting the faces of a triangle soup based on the orientation of the nearest face in a reference triangle soup.
- Added the function [`CGAL::Polygon_mesh_processing::compatible_orientations()`](https://doc.cgal.org/5.5/Polygon_mesh_processing/group__PMP__orientation__grp.html#ga9ac9b9434084b64f3304df636c3178a3), which enables to retrieve the (in)compatibility of orientations of faces from different connected components.
- Added the function [`CGAL::Polygon_mesh_processing::tangential_relaxation()`](https://doc.cgal.org/5.5/Polygon_mesh_processing/group__PMP__meshing__grp.html#ga136c659162e5360354db5879db7431b4), which applies an area-based tangential mesh smoothing to the vertices of a surface triangle mesh.
- Added the named parameter `visitor` to the function [`triangulate_hole()`](https://doc.cgal.org/5.5/Polygon_mesh_processing/group__PMP__hole__filling__grp.html#gad2d3c43bce0ef90a16530478196d7f42), which enables to track progress with callbacks.
- Added more functions in the [visitor of the corefinement based methods](https://doc.cgal.org/5.5/Polygon_mesh_processing/classPMPCorefinementVisitor.html) to track progress.
### [Surface Mesh Simplification](https://doc.cgal.org/5.5/Manual/packages.html#PkgSurfaceMeshSimplification)
- Introduced four variations of the Garland-Heckbert simplification algorithm based on the probabilistic approach of Trettner and Kobbelt (Fast and Robust QEF Minimization using Probabilistic Quadrics): [`GarlandHeckbert_plane_policies`](https://doc.cgal.org/5.5/Surface_mesh_simplification/classCGAL_1_1Surface__mesh__simplification_1_1GarlandHeckbert__plane__policies.html), [`GarlandHeckbert_probabilistic_plane_policies`](https://doc.cgal.org/5.5/Surface_mesh_simplification/classCGAL_1_1Surface__mesh__simplification_1_1GarlandHeckbert__probabilistic__plane__policies.html), [`GarlandHeckbert_triangle_policies`](https://doc.cgal.org/5.5/Surface_mesh_simplification/classCGAL_1_1Surface__mesh__simplification_1_1GarlandHeckbert__triangle__policies.html), and [`GarlandHeckbert_probabilistic_triangle_policies`](https://doc.cgal.org/5.5/Surface_mesh_simplification/classCGAL_1_1Surface__mesh__simplification_1_1GarlandHeckbert__probabilistic__triangle__policies.html).
- The class `GarlandHeckbert_policies` has been deprecated, `GarlandHeckbert_plane_policies` replaces it.
### [Point Set Processing](https://doc.cgal.org/5.5/Manual/packages.html#PkgPointSetProcessing3)
- A new optional named parameter, `min_points_per_cell` has been added to [`grid_simplify_point_set()`](https://doc.cgal.org/5.5/Point_set_processing_3/group__PkgPointSetProcessing3Algorithms.html#ga7757ef9b3900e42fde26f5a0ac56e20f). By adding a minimal number of points in a cell such that a point is retained, one can also filter out low density areas and outliers: in the case of densely sampled point clouds, this yields better results than using grid simplification and then outlier removal, while being very vast. The default value is `1` to keep the previous behavior as default.
### [dD Spatial Searching](https://doc.cgal.org/5.5/Manual/packages.html#PkgSpatialSearchingD)
- Added the member function [`write_graphviz()`](https://doc.cgal.org/5.5/Spatial_searching/classCGAL_1_1Kd__tree.html#ac2851b5cafb8d5cce0dc5fb107c8f13f) to the class `Kd_tree` that writes the tree in a stream in the [Graphviz](https://graphviz.org/) format.
### [CGAL and the Boost Graph Library (BGL)](https://doc.cgal.org/5.5/Manual/packages.html#PkgBGL)
- Added the function [`invert_selection()`](https://doc.cgal.org/5.5/BGL/structCGAL_1_1Face__filtered__graph.html#aa428541ebbdd35f9a6e9a3ffd60178df) in the class [`Face_filtered_graph`](https://doc.cgal.org/5.5/BGL/structCGAL_1_1Face__filtered__graph.html), which toggles the selected status of a graph: selected faces are deselected, and unselected faces are selected.
Besides fixes and general enhancement to existing packages, the following has changed since CGAL 5.2:
### [Quadtrees, Octrees, and Orthtrees](https://doc.cgal.org/5.3/Manual/packages.html#PkgOrthtree) (new package)
- This package implements a tree data structure in which each node encloses a hypercubic section
of space and each non-leave node has hypercubic children whose edge lengths are half its edge length.
Such a data structure is known as a quadtree in 2D, an octree in 3D, and is generalized
as an "orthtree" in higher dimensions.
### [Triangulations on the Sphere](https://doc.cgal.org/5.3/Manual/packages.html#PkgTriangulationOnSphere2) (new package)
- This package enables the construction and manipulation of Delaunay triangulations on the 2-sphere.
Triangulations are built incrementally and can be modified by insertion or removal of vertices.
Point location querying and primitives to build the dual Voronoi diagram are provided.
### File Input / Output
- Point set, polygon soup, and polygon mesh file I/O functions have been harmonized and documented:
- Point set I/O functions can be found in the packages [Point_set_processing_3](https://doc.cgal.org/5.3/Manual/packages.html#PkgPolygonMeshProcessing), and [Point_set_3](https://doc.cgal.org/5.3/Manual/packages.html#PkgPointSet3).
- Polygon mesh I/O functions can be found in the package [BGL](https://doc.cgal.org/5.3/Manual/packages.html#PkgBGL).
- Polygon soup I/O can be found in the package [Stream_support](https://doc.cgal.org/5.3/Manual/packages.html#PkgStreamSupport).
A comprehensive list of the supported file formats is available in the Stream_support package
[here](https://doc.cgal.org/5.3/Stream_support/index.html#IOstreamSupportedFormats);
inversely, the following [page](https://doc.cgal.org/5.3/Stream_support/IOStreamSupportedFileFormats.html)
can be used to find out which CGAL data structures can be used given a specific file format.
### [Requirements](https://doc.cgal.org/5.3/Manual/thirdparty.html)
- The CMake minimal version is now `3.14`.
- The GNU compiler g++ versions 6 and 7 are no longer tested. Only version 8.3 or later are supported
### [2D and 3D Linear Geometry Kernel](https://doc.cgal.org/5.3/Manual/packages.html#PkgKernel23)
- Added `is_translation()`, `is_scaling()`, `is_reflection()`, and `is_rotation()` to the classes
[`Aff_transformation_2`](https://doc.cgal.org/5.3/Kernel_23/classCGAL_1_1Aff__transformation__2.html)
and [`Aff_transformation_3`](https://doc.cgal.org/5.3/Kernel_23/classCGAL_1_1Aff__transformation__3.html),
which enable determining if the transformations use a specialized representation internally.
### [2D Regularized Boolean Set-Operations](https://doc.cgal.org/5.3/Manual/packages.html#PkgBooleanSetOperations2)
- Added documentation for the free functions [`oriented_side(const Point_2& p, ....)`](https://doc.cgal.org/5.3/Boolean_set_operations_2/group__boolean__oriented__side.html)
that accept a point and a polygon.
- Documentation has been improved across the whole package.
### [Polygon Mesh Processing](https://doc.cgal.org/5.3/Manual/packages.html#PkgPolygonMeshProcessing)
- Added the class [`CGAL::Polyhedral_envelope`](https://doc.cgal.org/5.3/Polygon_mesh_processing/structCGAL_1_1Polyhedral__envelope.html),
providing a way to quickly check if a primitive (point, segment, or triangle)
is within a polyhedral envelope around a set of triangles. It is based on the work of
Bolun Wang, Teseo Schneider, Yixin Hu, Marco Attene, and Daniele Panozzo.
"Exact and efficient polyhedral envelope containment check." (ACM Trans. Graph., 39-4, July 2020).
- Added more functions in the [visitor of the corefinement based methods](https://doc.cgal.org/5.3/Polygon_mesh_processing/classPMPCorefinementVisitor.html)
to track all edge creations.
### [Surface Mesh Topology](https://doc.cgal.org/5.3/Manual/packages.html#PkgSurfaceMeshTopologySummary)
- Added the function [`CGAL::Surface_mesh_topology::Curves_on_surface_topology::is_homotopic_to_simple_cycle()`](https://doc.cgal.org/5.3/Surface_mesh_topology/classCGAL_1_1Surface__mesh__topology_1_1Curves__on__surface__topology.html#a8d7c4cba2cf2cff542f5cd93117233db),
which can be used to determine whehter a closed path on a surface mesh can be continously
transformed to a cycle without self intersection.
### [Surface Mesh Simplification](https://doc.cgal.org/5.3/Manual/packages.html#PkgSurfaceMeshSimplification)
- Added a filtering mechanism so that costly tests get only applied to the next candidate for the edge collapse.
- Added the class [`Polyhedral_envelope_filter`](https://doc.cgal.org/5.3/Surface_mesh_simplification/classCGAL_1_1Surface__mesh__simplification_1_1Polyhedral__envelope__filter.html),
which enables to perform mesh simplification inside a polyhedral envelope of the input mesh.
### [2D Polyline Simplification](https://doc.cgal.org/5.3/Manual/packages.html#PkgPolylineSimplification2)
- When polylines have common subsequences of vertices, these subsequences may now be simplifified simultaneously.
### [dD Triangulations](https://doc.cgal.org/5.3/Manual/packages.html#PkgTriangulations)
- Added the function [`insert_if_in_star()`](https://doc.cgal.org/5.3/Triangulation/classCGAL_1_1Regular__triangulation.html#aa8df2d138f341939e834bcdd7cb6c71a)
to the class [`CGAL::Regular_triangulation`](https://doc.cgal.org/5.3/Triangulation/classCGAL_1_1Regular__triangulation.html),
which enables users to insert a point `p` in a regular triangulation on the condition that `p`
appears post-insertion in the star of a user-specified, existing vertex.
### [2D and 3D Alpha Shapes](https://doc.cgal.org/5.3/Manual/packages.html#PkgAlphaShapes2)
- **Breaking change**: The following deprecated classes have been removed: `Alpha_shape_euclidean_traits_2`,
`Weighted_alpha_shape_euclidean_traits_2`, `Alpha_shape_euclidean_traits_3`, and
`Weighted_alpha_shape_euclidean_traits_3`. All CGAL kernel can be used directly as models
of the concepts of the 2D and 3D Alpha Shape packages.
### [Classification](https://doc.cgal.org/5.3/Manual/packages.html#PkgClassification)
- **Breaking change**: the support for TensorFlow has been dropped; the
classifier `CGAL::TensorFlow::Neural_network_classifier` has been removed.

View File

@ -1,97 +1,133 @@
Subject: CGAL 5.4 Beta 1 Released, Computational Geometry Algorithms Library
Subject: CGAL 5.3.2, 5.4.1, and 5.5 Beta 1 Released, Computational Geometry Algorithms Library
Content-Type: text/plain; charset="utf-8"
Body:
The CGAL Open Source Project is pleased to announce the release 5.4 Beta 1
of CGAL, the Computational Geometry Algorithms Library.
The CGAL Open Source Project is pleased to announce today three new
releases:
- CGAL-5.3.2 is the second and last bug-fix release for CGAL-5.3,
- CGAL-5.4.1 is the first bug-fix release for CGAL-5.4, and
- CGAL-5.5-beta1 is the first beta release for CGAL-5.5.
CGAL version 5.4 Beta 1 is a public testing release. It should provide a
CGAL version 5.5 Beta 1 is a public testing release. It should provide a
solid ground to report bugs that need to be tackled before the release
of the final version of CGAL 5.4 in January 2022.
of the final version of CGAL 5.5 in July 2022.
Besides fixes and general enhancement to existing packages, the
following has changed since CGAL 5.4:
3D Alpha Wrapping (new package)
- This component takes a 3D triangle mesh, soup, or point set as
input, and generates a valid (watertight, intersection-free, and
combinatorially 2-manifold) surface triangle mesh that contains the
input. The algorithm proceeds by shrink-wrapping and refining a 3D
Delaunay triangulation, starting from a loose bounding box of the
input. Two user-defined parameters, alpha and offset, offer control
over the maximum size of cavities where the shrink-wrapping process
can enter, and the tightness of the final surface mesh to the input,
respectively. Once combined, these parameters provide a means to
trade fidelity to the input for complexity of the output.
See also https://www.cgal.org/2022/05/18/alpha_wrap/.
3D Convex Hulls
- Added an overload of the function CGAL::convex_hull_3(), which
writes the result in an indexed triangle set.
2D Polygons
- Add vertex, edge, and hole ranges.
- The concept GeneralPolygonWithHoles_2 now requires the nested type
Polygon_2 instead of General_polygon_2.
2D Regularized Boolean Set-Operations
- The concept GeneralPolygonSetTraits_2 now requires the nested type
Construct_polygon_with_holes_2 instead of
Construct_general_polygon_with_holes_2.
Combinatorial Maps
- Removed old code deprecated in CGAL 4.9 and 4.10 (global functions,
and information associated with darts).
2D Arrangements
- Fixed the intersect_2, compare_y_at_x_right, and compare_y_at_x_left
function objects of the traits class template
Arr_geodesic_arc_on_sphere_traits_2 that handles geodesic arcs on
sphere and applied a small syntactical fix to the tracing traits.
Tetrahedral Mesh Generation
- Added the function remove_isolated_vertices() as a post-processing
step for the tetrahedral mesh generation.
Polygon Mesh Processing
- Added the function
CGAL::Polygon_mesh_processing::orient_triangle_soup_with_reference_triangle_soup(),
which enables re-orienting the faces of a triangle soup based on the
orientation of the nearest face in a reference triangle soup.
- Added the function
CGAL::Polygon_mesh_processing::compatible_orientations(), which
enables to retrieve the (in)compatibility of orientations of faces
from different connected components.
- Added the function
CGAL::Polygon_mesh_processing::tangential_relaxation(), which
applies an area-based tangential mesh smoothing to the vertices of a
surface triangle mesh.
- Added the named parameter visitor to the function
triangulate_hole(), which enables to track progress with callbacks.
- Added more functions in the visitor of the corefinement based
methods to track progress.
Surface Mesh Simplification
- Introduced four variations of the Garland-Heckbert simplification
algorithm based on the probabilistic approach of Trettner and
Kobbelt (Fast and Robust QEF Minimization using Probabilistic
Quadrics): GarlandHeckbert_plane_policies,
GarlandHeckbert_probabilistic_plane_policies,
GarlandHeckbert_triangle_policies, and
GarlandHeckbert_probabilistic_triangle_policies.
- The class GarlandHeckbert_policies has been deprecated,
GarlandHeckbert_plane_policies replaces it.
Point Set Processing
- A new optional named parameter, min_points_per_cell has been added
to grid_simplify_point_set(). By adding a minimal number of points
in a cell such that a point is retained, one can also filter out low
density areas and outliers: in the case of densely sampled point
clouds, this yields better results than using grid simplification
and then outlier removal, while being very vast. The default value
is 1 to keep the previous behavior as default.
dD Spatial Searching
- Added the member function write_graphviz() to the class Kd_tree that
writes the tree in a stream in the Graphviz format.
CGAL and the Boost Graph Library (BGL)
- Added the function invert_selection() in the class
Face_filtered_graph, which toggles the selected status of a graph:
selected faces are deselected, and unselected faces are selected.
Besides fixes and general enhancement to existing packages, the following
has changed since CGAL 5.3:
General changes
- Added the cmake target CGAL::CGAL_Basic_viewer to ease the
compilation of programs using the basic viewer-based function
CGAL::draw(). This target will define the macro and link with
CGAL_Qt5 target when linked with it.
- The kernel providing exact constructions and exact predicates
(CGAL::Exact_predicates_exact_constructions_kernel) is now
thread-safe.
more details.
Shape Regularization (new package)
- This package enables to regularize a set of segments and open or
closed contours in 2D and a set of planes in 3D such that all input
objects are rotated and aligned with respect to the user-specified
conditions. In addition, it provides a global regularization
framework that can be adjusted for the user needs and any type of
geometric objects.
https://www.cgal.org/2021/11/16/shape-regularization/
https://doc.cgal.org/5.4/Manual/packages.html#PkgShapeRegularization
Weights (new package)
- This package provides a simple and unified interface to different
types of weights. In particular, it groups all weights into three
category: analytic weights including all basic weights which can be
computed analytically for a query point with respect to its local
neighbors in 2D and 3D; barycentric weights, including all weights
which can be computed for a query point with respect to the vertices
of a planar polygon; and weighting regions, including all weights
which are used to balance other weights.
https://doc.cgal.org/5.4/Manual/packages.html#PkgWeights
2D Generalized Barycentric Coordinates (major changes)
- Breaking change: The headers Segment_coordinates_2.h and
Triangle_coordinates_2.h are renamed to segment_coordinates_2.h and
triangle_coordinates_2.h.
- The classes Segment_coordinates_2 and Triangle_coordinates_2 are
deprecated. The free functions compute_segment_coordinates_2() and
compute_triangle_coordinates_2() are deprecated as well. Instead,
the free functions segment_coordinates_2() and
triangle_coordinates_2() should be used.
- The enums Query_point_location and Type_of_algorithm are deprecated.
Instead, the enum Computation_policy_2 should be used.
- The classes Wachspress_2, Discrete_harmonic_2, Mean_value_2, and
Generalized_barycentric_coordinates_2 are deprecated. As
consequence, the concept BarycentricCoordinates_2 is deprecated as
well. Instead, the classes Wachspress_coordinates_2,
Discrete_harmonic_coordinates_2, and Mean_value_coordinates_2 should
be used.
- Added the class Harmonic_coordinates_2 to compute approximate
harmonic coordinates in 2D. These coordinates satisfy all properties
of barycentric coordinates inside any simple polygon.
- Added a new concept DiscretizedDomain_2 and a model of this concept
called Delaunay_domain_2, which is based on the Mesh 2 package. A
model of this concept is required to use Harmonic_coordinates_2.
- Added free functions to compute Wachspress, discrete harmonic, and
mean value coordinates.
- All free functions and classes are now using ranges and property
maps.
https://doc.cgal.org/5.4/Manual/packages.html#PkgBarycentricCoordinates2
See https://www.cgal.org/2021/12/17/cgal54-beta1/ for a
See https://www.cgal.org/2022/06/06/cgal55-beta1/ for a
complete list of changes.
The development of CGAL will then now on the future CGAL-5.6 (planned
for December 2022), with bug-fixes regularly backported to the branches
for CGAL-5.4.x and CGAL-5.5.x.
The CGAL project is a collaborative effort to develop a robust,
easy-to-use, and efficient C++ software library of geometric data
structures and algorithms, like

View File

@ -23,4 +23,4 @@ HTML_EXTRA_FILES = ${CGAL_PACKAGE_DOC_DIR}/fig/implicit_domain_3.jpg
${CGAL_PACKAGE_DOC_DIR}/fig/protection-complex.png \
${CGAL_PACKAGE_DOC_DIR}/fig/no-protection-complex.png
EXAMPLE_PATH += ${CGAL_PACKAGE_INCLUDE_DIR}
EXAMPLE_PATH += ${CGAL_PACKAGE_INCLUDE_DIR} # non-documented headers are advertised

View File

@ -227,6 +227,7 @@ CGAL::Image_3 generate_label_weights_with_known_word_type(const CGAL::Image_3& i
/// @endcond
/*!
* \ingroup PkgMesh3Functions
* Free function that generates a `CGAL::Image_3` of weights associated to each
* voxel of `image`, to make the output mesh surfaces smoother.
* The weights image is generated using the algorithm described by Stalling et al

View File

@ -180,37 +180,9 @@ class Binary_operation : public CGAL::SNC_decorator<Map> {
snc0(s0), snc1(s1), bop(_bop), result(r),
inverse_order(invert_order), A(Ain) {}
void operator()(Halfedge_handle e0, Object_handle o1, const Point_3& ip)
const {
#ifdef CGAL_NEF3_DUMP_STATISTICS
++number_of_intersections;
#endif
Halfedge_handle e;
Halffacet_handle f;
Point_3 p(normalized(ip));
#ifdef CGAL_USE_TRACE
CGAL_NEF_TRACEN("Intersection_call_back: intersection reported on " << p << " (normalized: " << normalized(p) << " )");
CGAL_NEF_TRACEN("edge 0 has source " << e0->source()->point() << " and direction " << e0->vector());
if( CGAL::assign( e, o1)) {
CGAL_NEF_TRACEN("edge 1 has source " << e->source()->point() << " and direction " << e->vector());
}
else if( CGAL::assign( f, o1)) {
CGAL_NEF_TRACEN("face 1 has plane equation " << f->plane());
}
else
CGAL_error_msg( "wrong handle");
#endif
#if defined (CGAL_NEF3_TIMER_OVERLAY) || (CGAL_NEF3_TIMER_INTERSECTION)
timer_overlay.start();
#endif
if( CGAL::assign( e, o1)) {
// std::cerr << "inverse order " << inverse_order << std::endl;
void operator()(Halfedge_handle e0, Halfedge_handle e, const Point_3& ip) const override
{
Point_3 p(normalized(ip));
#ifdef CGAL_NEF_EXPERIMENTAL_CODE
typename CGAL::Edge_edge_overlay<SNC_structure> eeo(result, e0, e);
Sphere_map* M0 = eeo.create_edge_edge_overlay(p, bop, inverse_order, A);
@ -228,7 +200,10 @@ class Binary_operation : public CGAL::SNC_decorator<Map> {
result.delete_vertex(v1);
#endif
}
else if( CGAL::assign( f, o1)) {
void operator()(Halfedge_handle e0, Halffacet_handle f, const Point_3& ip) const override
{
Point_3 p(normalized(ip));
#ifdef CGAL_NEF3_OVERLAY_BY_HAND_OFF
Binary_operation D(result);
Vertex_handle v0, v1;
@ -246,14 +221,7 @@ class Binary_operation : public CGAL::SNC_decorator<Map> {
O.simplify(A);
#endif // CGAL_NEF3_OVERLAY_BY_HAND_OFF
}
else
CGAL_error_msg( "wrong handle");
#if defined (CGAL_NEF3_TIMER_OVERLAY) || (CGAL_NEF3_TIMER_INTERSECTION)
timer_overlay.stop();
#endif
}
private:
const SNC_structure& snc0;
const SNC_structure& snc1;

View File

@ -108,15 +108,8 @@ typedef Smaller_than<
public:
typedef Node* Node_handle;
Node(const Vertex_list& V, const Halfedge_list& E, const Halffacet_list& F) :
left_node(nullptr), right_node(nullptr)
left_node(nullptr), right_node(nullptr), vertex_list(V), edge_list(E), facet_list(F)
{
object_list.reserve(V.size()+E.size()+F.size());
for(Vertex_const_iterator vi=V.begin(); vi!=V.end(); ++vi)
object_list.push_back(make_object(*vi));
for(Halfedge_const_iterator ei=E.begin(); ei!=E.end(); ++ei)
object_list.push_back(make_object(*ei));
for(Halffacet_const_iterator fi=F.begin(); fi!=F.end(); ++fi)
object_list.push_back(make_object(*fi));
}
Node(Node_handle l, Node_handle r, const Plane_3& pl) :
@ -133,20 +126,27 @@ public:
Node_handle left() const { return left_node; }
Node_handle right() const { return right_node; }
const Plane_3& plane() const { return splitting_plane; }
const Object_list& objects() const { return object_list; }
bool empty() { return vertex_list.empty() && edge_list.empty() && facet_list.empty(); }
Vertex_const_iterator vertices_begin() { return vertex_list.begin(); }
Vertex_const_iterator vertices_end() { return vertex_list.end(); }
Halfedge_const_iterator edges_begin() { return edge_list.begin(); }
Halfedge_const_iterator edges_end() { return edge_list.end(); }
Halffacet_const_iterator facets_begin() { return facet_list.begin(); }
Halffacet_const_iterator facets_end() { return facet_list.end(); }
void transform(const Aff_transformation_3& t) {
if(left_node != nullptr) {
CGAL_assertion(right_node != nullptr);
left_node->transform(t);
right_node->transform(t);
splitting_plane = splitting_plane.transform(t);
right_node->transform(t);
splitting_plane = splitting_plane.transform(t);
}
}
void add_facet(Halffacet_handle f, int depth) {
if(left_node == nullptr) {
object_list.push_back(make_object(f));
facet_list.push_back(f);
return;
}
@ -160,7 +160,7 @@ public:
void add_edge(Halfedge_handle e, int depth) {
if(left_node == nullptr) {
object_list.push_back(make_object(e));
edge_list.push_back(e);
return;
}
@ -174,7 +174,7 @@ public:
void add_vertex(Vertex_handle v, int depth) {
if(left_node == nullptr) {
object_list.push_back(make_object(v));
vertex_list.push_back(v);
return;
}
@ -187,33 +187,19 @@ public:
}
friend std::ostream& operator<<
(std::ostream& os, const Node_handle node) {
CGAL_assertion( node != nullptr);
if( node->is_leaf())
os << node->objects().size();
else {
os << " ( ";
if( !node->left()) os << '-';
else os << node->left();
os << " , ";
if( !node->right()) os << '-';
else os << node->right();
os << " ) ";
}
return os;
}
private:
Node_handle left_node;
Node_handle right_node;
Plane_3 splitting_plane;
Object_list object_list;
Vertex_list vertex_list;
Halfedge_list edge_list;
Halffacet_list facet_list;
};
typedef boost::container::deque<Node> Node_range;
typedef Node* Node_handle;
typedef std::vector<Node_handle> Node_list;
public:
@ -266,10 +252,6 @@ public:
++(*this); // place the interator in the first intersected cell
}
Iterator( const Self& i) : S(i.S), node(i.node) {}
const Object_list& operator*() const {
CGAL_assertion( node != nullptr);
return node->objects();
}
Self& operator++() {
if( S.empty())
@ -350,35 +332,6 @@ void divide_segment_by_plane( Segment_3 s, Plane_3 pl,
};
};
class Objects_along_ray : public Objects_around_segment
{
typedef Objects_around_segment Base;
protected:
Traits traits;
public:
Objects_along_ray( const K3_tree& k, const Ray_3& r) {
CGAL_NEF_TRACEN("Objects_along_ray: input ray: "<<r);
Vector_3 vec(r.to_vector());
// First of all, we need to find out wheather we are working over an extended kernel or on a standard kernel. As precondition we have that ray is oriented in the minus x axis direction. When having an extended kernel, the ray can be subtituted by a segment with the endpoint on the 'intersection' between the ray and the bounding infimaximal box. In the presence of a standard kernel, the intersection is computed with the bounding box with the vertices of the Nef polyhedron.
Point_3 p(r.source()), q;
Bounding_box_3 b = k.bounding_box;
typename Kernel::Non_zero_coordinate_index_3 non_zero_coordinate_index_3;
int c = non_zero_coordinate_index_3(vec);
Point_3 pt_on_minus_x_plane = vec[c] < 0 ?
Point_3(FT(b.min_coord(0)), FT(b.min_coord(1)),FT(b.min_coord(2))) :
Point_3(FT(b.max_coord(0)), FT(b.max_coord(1)),FT(b.max_coord(2)));
// We compute the intersection between a plane with normal vector in
// the minus x direction and located at the minimum point of the bounding box, and the input ray. When the ray does not intersect the bounding volume, there won't be any object hit, so it is safe to construct a segment that simply lay in the unbounded side of the bounding box. This approach is taken instead of somehow (efficiently) report that there was no hit object, in order to mantain a clear interface with the Iterator class.
Plane_3 pl_on_minus_x = K3_tree::construct_splitting_plane(pt_on_minus_x_plane, c, typename Traits::Kernel::Kernel_tag());
Object o = traits.intersect_object()( pl_on_minus_x, r);
if( !CGAL::assign( q, o) || pl_on_minus_x.has_on(p))
q = r.source() + vec;
else
q = normalized(q);
Base::initialize( k, Segment_3( p, q));
}
};
private:
#ifdef CGAL_NEF_EXPLOIT_REFERENCE_COUNTING
@ -441,53 +394,23 @@ public:
non_efective_splits=0;
root = build_kdtree(vertices, edges, facets, 0);
}
const Object_list& objects_around_point( const Point_3& p) const {
return locate( p, root);
Node_handle locate_node_containing( const Point_3& p) const {
return locate_node_containing( p, root);
}
Objects_along_ray objects_along_ray( const Ray_3& r) const {
return Objects_along_ray( *this, r);
Node_list nodes_along_ray( const Ray_3& r) const {
Segment_3 s = ray_to_segment(r);
return nodes_around_segment(s);
}
Object_list objects_around_segment( const Segment_3& s) const {
Object_list O;
Node_list nodes_around_segment( const Segment_3& s) const {
Node_list result;
Objects_around_segment objects( *this, s);
Unique_hash_map< Vertex_handle, bool> v_mark(false);
Unique_hash_map< Halfedge_handle, bool> e_mark(false);
Unique_hash_map< Halffacet_handle, bool> f_mark(false);
for( typename Objects_around_segment::Iterator oar = objects.begin();
oar != objects.end(); ++oar) {
for( typename Object_list::const_iterator o = (*oar).begin();
o != (*oar).end(); ++o) { // TODO: implement operator->(...)
Vertex_handle v;
Halfedge_handle e;
Halffacet_handle f;
if( CGAL::assign( v, *o)) {
if( !v_mark[v]) {
O.push_back(*o);
v_mark[v] = true;
}
}
else if( CGAL::assign( e, *o)) {
if( !e_mark [e]) {
O.push_back(*o);
e_mark[e] = true;
}
}
else if( CGAL::assign( f, *o)) {
if( !f_mark[f]) {
O.push_back(*o);
f_mark[f] = true;
}
}
else
CGAL_error_msg( "wrong handle");
}
for(typename Objects_around_segment::Iterator oas = objects.begin(); oas != objects.end(); ++oas) {
result.push_back(oas.get_node());
}
return O;
return result;
}
bool is_point_on_cell( const Point_3& p, const typename Objects_around_segment::Iterator& target) const {
return is_point_on_cell( p, target.get_node(), root);
bool is_point_in_node( const Point_3& p, const Node_handle target) const {
return is_point_in_node( p, target, root);
}
void add_facet(Halffacet_handle f) {
@ -510,12 +433,8 @@ public:
void pre_visit(const Node_handle) {}
void post_visit(const Node_handle n) {
typename Object_list::const_iterator o;
for( o = n->objects().begin();
o != n->objects().end(); ++o) {
Vertex_handle v;
if( CGAL::assign( v, *o))
b.extend(v->point());
for(Vertex_const_iterator vi = n->vertex_list.begin(); vi!=n->vertex_list.end(); ++vi) {
b.extend((*vi)->point());
}
}
@ -722,7 +641,7 @@ static Node_handle get_child_by_side( const Node_handle node, Oriented_side side
return node->right();
}
Node_handle locate_cell_containing( const Point_3& p, const Node_handle node) const {
Node_handle locate_node_containing( const Point_3& p, const Node_handle node) const {
CGAL_precondition( node != nullptr);
if( node->is_leaf())
return node;
@ -730,26 +649,57 @@ Node_handle locate_cell_containing( const Point_3& p, const Node_handle node) co
Oriented_side side = node->plane().oriented_side(p);
if(side == ON_ORIENTED_BOUNDARY)
side = ON_NEGATIVE_SIDE;
return locate_cell_containing(p, get_child_by_side(node, side));
return locate_node_containing(p, get_child_by_side(node, side));
}
const Object_list& locate( const Point_3& p, const Node_handle node) const {
CGAL_precondition( node != nullptr);
return locate_cell_containing( p, node)->objects();
}
bool is_point_on_cell( const Point_3& p, const Node_handle target, const Node_handle current) const {
bool is_point_in_node( const Point_3& p, const Node_handle target, const Node_handle current) const {
CGAL_precondition( target != nullptr && current != nullptr);
if( current->is_leaf())
return (current == target);
Oriented_side side = current->plane().oriented_side(p);
if( side == ON_NEGATIVE_SIDE)
return is_point_on_cell( p, target, current->left());
return is_point_in_node( p, target, current->left());
else if( side == ON_POSITIVE_SIDE)
return is_point_on_cell( p, target, current->right());
return is_point_in_node( p, target, current->right());
CGAL_assertion( side == ON_ORIENTED_BOUNDARY);
return (is_point_on_cell( p, target, current->left()) ||
is_point_on_cell( p, target, current->right()));
return (is_point_in_node( p, target, current->left()) ||
is_point_in_node( p, target, current->right()));
}
Segment_3 ray_to_segment(const Ray_3& r) const
{
CGAL_NEF_TRACEN("Objects_along_ray: input ray: "<<r);
Vector_3 vec(r.to_vector());
/* First of all, we need to find out wheather we are working over an extended
* kernel or on a standard kernel. As precondition we have that ray is oriented
* in the minus x axis direction. When having an extended kernel, the ray can
* be subtituted by a segment with the endpoint on the 'intersection' between
* the ray and the bounding infimaximal box. In the presence of a standard
* kernel, the intersection is computed with the bounding box with the vertices
* of the Nef polyhedron.*/
Point_3 p(r.source()), q;
Bounding_box_3 b = bounding_box;
typename Kernel::Non_zero_coordinate_index_3 non_zero_coordinate_index_3;
int c = non_zero_coordinate_index_3(vec);
Point_3 pt_on_minus_x_plane = vec[c] < 0 ?
Point_3(FT(b.min_coord(0)), FT(b.min_coord(1)),FT(b.min_coord(2))) :
Point_3(FT(b.max_coord(0)), FT(b.max_coord(1)),FT(b.max_coord(2)));
/* We compute the intersection between a plane with normal vector in the minus x
* direction and located at the minimum point of the bounding box, and the input
* ray. When the ray does not intersect the bounding volume, there won't be any
* object hit, so it is safe to construct a segment that simply lay in the
* unbounded side of the bounding box. This approach is taken instead of somehow
* (efficiently) report that there was no hit object, in order to mantain a clear
* interface with the Iterator class.*/
Plane_3 pl_on_minus_x = K3_tree::construct_splitting_plane(pt_on_minus_x_plane, c, typename Traits::Kernel::Kernel_tag());
Object o = traits.intersect_object()( pl_on_minus_x, r);
if( !CGAL::assign( q, o) || pl_on_minus_x.has_on(p))
q = r.source() + vec;
else
q = normalized(q);
return Segment_3( p, q);
}
};

View File

@ -898,8 +898,7 @@ public:
if ( f->volume() != Volume_handle() )
continue;
CGAL_NEF_TRACEN( "Outer shell #" << ShellSf[f] << " volume?");
Volume_handle c = determine_volume( MinimalSFace[ShellSf[f]],
MinimalSFace, ShellSf );
Volume_handle c = determine_volume( f, MinimalSFace, ShellSf );
c->mark() = f->mark();
link_as_outer_shell( f, c );
}

View File

@ -93,14 +93,15 @@ public:
const = 0;
virtual void intersect_with_edges_and_facets( Halfedge_handle edge,
const Intersection_call_back& call_back) const = 0;
const Intersection_call_back& call_back) const = 0;
class Intersection_call_back
{
public:
virtual void operator()( Halfedge_handle edge, Object_handle object,
virtual void operator()( Halfedge_handle edge0, Halfedge_handle edge1,
const Point_3& intersection_point) const = 0;
virtual void operator()( Halfedge_handle edge0, Halffacet_handle facet1,
const Point_3& intersection_point) const = 0;
virtual ~Intersection_call_back() {}
};
@ -182,8 +183,14 @@ public:
typedef typename SNC_candidate_provider::Object_list Object_list;
typedef typename Object_list::iterator Object_list_iterator;
typedef typename SNC_candidate_provider::Objects_along_ray Objects_along_ray;
typedef typename Objects_along_ray::Iterator Objects_along_ray_iterator;
typedef typename SNC_candidate_provider::Node_handle Node_handle;
typedef typename SNC_candidate_provider::Node_list Node_list;
typedef typename SNC_candidate_provider::Vertex_list Vertex_list;
typedef typename SNC_candidate_provider::Halfedge_list Halfedge_list;
typedef typename SNC_candidate_provider::Halffacet_list Halffacet_list;
typedef typename SNC_point_locator::Intersection_call_back Intersection_call_back;
using Base::get_visible_facet;
public:
@ -218,454 +225,346 @@ public:
delete candidate_provider;
}
// We next check if v is a vertex on the face to avoid a geometric test
static inline bool v_vertex_of_f(Vertex_handle v, Halffacet_handle f) {
Halffacet_cycle_iterator fci;
for(fci=f->facet_cycles_begin(); fci!=f->facet_cycles_end(); ++fci) {
if(fci.is_shalfedge()) {
SHalfedge_around_facet_circulator sfc(fci), send(sfc);
CGAL_For_all(sfc,send) {
if(sfc->source()->center_vertex() == v){
return true;
}
}
}
}
return false;
}
virtual Object_handle shoot(const Ray_3& ray, int mask=255) const {
Vertex_handle null_handle;
return this->shoot(ray, null_handle, mask);
}
enum SOLUTION { is_vertex_, is_edge_, is_facet_ , is_none_};
virtual Object_handle shoot(const Ray_3& ray, Vertex_handle ray_source_vertex, int mask=255) const {
CGAL_NEF_TIMER(rs_t.start());
CGAL_assertion( initialized);
_CGAL_NEF_TRACEN( "shooting: "<<ray);
Object_handle result;
Vertex_handle v;
Halfedge_handle e;
Halffacet_handle f;
SOLUTION solution = is_none_;
Vertex_handle v_res;
Halfedge_handle e_res;
Halffacet_handle f_res;
bool hit = false;
Point_3 eor = CGAL::ORIGIN; // 'end of ray', the latest ray's hit point
Objects_along_ray objects = candidate_provider->objects_along_ray(ray);
Objects_along_ray_iterator objects_iterator = objects.begin();
while( !hit && objects_iterator != objects.end()) {
Object_list candidates = *objects_iterator;
Object_list_iterator o;
CGAL_for_each( o, candidates) {
if( CGAL::assign( v, *o) && ((mask&1) != 0)) {
Node_list nodes = candidate_provider->nodes_along_ray(ray);
typename Node_list::iterator nodes_iterator = nodes.begin();
while( !hit && nodes_iterator != nodes.end()) {
Node_handle n(*nodes_iterator);
if((mask&1)!=0) {
for(typename Vertex_list::const_iterator vi=n->vertices_begin(); vi!=n->vertices_end(); ++vi) {
Vertex_handle v(*vi);
_CGAL_NEF_TRACEN("trying vertex on "<<v->point());
if( (ray.source() != v->point()) && ray.has_on(v->point())) {
_CGAL_NEF_TRACEN("the ray intersects the vertex");
_CGAL_NEF_TRACEN("prev. intersection? "<<hit);
CGAL_assertion_code
(if( hit)_CGAL_NEF_TRACEN("prev. intersection on "<<eor));
(if( hit)_CGAL_NEF_TRACEN("prev. intersection on "<<eor));
if( hit && !Segment_3( ray.source(), eor).has_on(v->point()))
continue;
eor = v->point();
result = make_object(v);
v_res = v;
solution = is_vertex_;
hit = true;
_CGAL_NEF_TRACEN("the vertex becomes the new hit object");
}
}
else if( CGAL::assign( e, *o) && ((mask&2) != 0)) {
}
if((mask&2)!=0) {
for(typename Halfedge_list::const_iterator ei=n->edges_begin(); ei!=n->edges_end(); ++ei) {
Halfedge_handle e(*ei);
Point_3 q;
_CGAL_NEF_TRACEN("trying edge on "<< Segment_3(e->source()->point(),e->twin()->source()->point()));
if ( (ray_source_vertex == Vertex_handle()) || ( (ray_source_vertex != e->source()) && (ray_source_vertex != e->twin()->source())) ) {
if( SNC_intersection::does_intersect_internally( ray, Segment_3(e->source()->point(),
e->twin()->source()->point()), q)) {
_CGAL_NEF_TRACEN("ray intersects edge on " << q);
_CGAL_NEF_TRACEN("prev. intersection? " << hit);
CGAL_assertion_code
(if (hit) _CGAL_NEF_TRACEN("prev. intersection on " << eor));
if (hit && !has_smaller_distance_to_point(ray.source(), q, eor))
continue;
_CGAL_NEF_TRACEN("is the intersection point on the current cell? " <<
candidate_provider->is_point_on_cell(q, objects_iterator));
if (!candidate_provider->is_point_on_cell(q, objects_iterator))
continue;
eor = q;
result = make_object(e);
hit = true;
_CGAL_NEF_TRACEN("the edge becomes the new hit object");
}
if( SNC_intersection::does_intersect_internally( ray, Segment_3(e->source()->point(),
e->twin()->source()->point()), q)) {
_CGAL_NEF_TRACEN("ray intersects edge on "<<q);
_CGAL_NEF_TRACEN("prev. intersection? "<<hit);
CGAL_assertion_code
(if( hit) _CGAL_NEF_TRACEN("prev. intersection on "<<eor));
if( hit && !has_smaller_distance_to_point( ray.source(), q, eor))
continue;
_CGAL_NEF_TRACEN("is the intersection point on the current cell? "<<
candidate_provider->is_point_in_node( q, n));
if( !candidate_provider->is_point_in_node( q, n))
continue;
eor = q;
e_res = e;
solution = is_edge_;
hit = true;
_CGAL_NEF_TRACEN("the edge becomes the new hit object");
}
}
}
else if( CGAL::assign( f, *o) && ((mask&4) != 0)) {
}
if((mask&4)!=0) {
for(typename Halffacet_list::const_iterator fi=n->facets_begin(); fi!=n->facets_end(); ++fi) {
Halffacet_handle f(*fi);
Point_3 q;
_CGAL_NEF_TRACEN("trying facet with on plane "<<f->plane()<<
" with point on "<<f->plane().point());
if( SNC_intersection::does_intersect_internally( ray, f, q) ) {
_CGAL_NEF_TRACEN("ray intersects facet on "<<q);
_CGAL_NEF_TRACEN("prev. intersection? "<<hit);
if( hit) { _CGAL_NEF_TRACEN("prev. intersection on "<<eor); }
if( hit && !has_smaller_distance_to_point( ray.source(), q, eor))
continue;
_CGAL_NEF_TRACEN("is the intersection point on the current cell? "<<
candidate_provider->is_point_on_cell( q, objects_iterator));
if( !candidate_provider->is_point_on_cell( q, objects_iterator))
continue;
eor = q;
result = make_object(f);
hit = true;
_CGAL_NEF_TRACEN("the facet becomes the new hit object");
" with point on "<<f->plane().point());
if( (ray_source_vertex == Vertex_handle()) || !v_vertex_of_f(ray_source_vertex,f) ) {
if( SNC_intersection::does_intersect_internally( ray, f, q) ) {
_CGAL_NEF_TRACEN("ray intersects facet on "<<q);
_CGAL_NEF_TRACEN("prev. intersection? "<<hit);
if( hit) { _CGAL_NEF_TRACEN("prev. intersection on "<<eor); }
if( hit && !has_smaller_distance_to_point( ray.source(), q, eor))
continue;
_CGAL_NEF_TRACEN("is the intersection point on the current cell? "<<
candidate_provider->is_point_in_node( q, n));
if( !candidate_provider->is_point_in_node( q, n))
continue;
eor = q;
f_res = f;
solution = is_facet_;
hit = true;
_CGAL_NEF_TRACEN("the facet becomes the new hit object");
}
}
}
else if((mask&15) == 15)
CGAL_error_msg( "wrong handle");
}
if(!hit)
++objects_iterator;
++nodes_iterator;
}
CGAL_NEF_TIMER(rs_t.stop());
return result;
switch (solution) {
case is_vertex_: return make_object(v_res);
case is_edge_: return make_object(e_res);
case is_facet_: return make_object(f_res);
case is_none_ : break;
}
return Object_handle();
}
virtual Object_handle locate( const Point_3& p) const {
if(Infi_box::extended_kernel()) {
CGAL_NEF_TIMER(pl_t.start());
CGAL_assertion( initialized);
_CGAL_NEF_TRACEN( "locate "<<p);
Object_handle result;
Vertex_handle v;
Halfedge_handle e;
Halffacet_handle f;
Object_list candidates = candidate_provider->objects_around_point(p);
Object_list_iterator o = candidates.begin();
bool found = false;
while( !found && o != candidates.end()) {
if( CGAL::assign( v, *o)) {
CGAL_NEF_TIMER(pl_t.start());
CGAL_assertion( initialized);
_CGAL_NEF_TRACEN( "locate "<<p);
Node_handle n = candidate_provider->locate_node_containing(p);
for(typename Vertex_list::const_iterator vi=n->vertices_begin(); vi!=n->vertices_end(); ++vi) {
Vertex_handle v(*vi);
if ( p == v->point()) {
_CGAL_NEF_TRACEN("found on vertex "<<v->point());
result = make_object(v);
found = true;
return make_object(v);
}
}
else if( CGAL::assign( e, *o)) {
if ( SNC_intersection::does_contain_internally(e->source()->point(), e->twin()->source()->point(), p) ) {
for(typename Halfedge_list::const_iterator ei=n->edges_begin(); ei!=n->edges_end(); ++ei) {
Halfedge_handle e(*ei);
if (SNC_intersection::does_contain_internally(e->source()->point(),e->twin()->source()->point(), p) ) {
_CGAL_NEF_TRACEN("found on edge "<<Segment_3(e->source()->point(),e->twin()->source()->point()));
result = make_object(e);
found = true;
return make_object(e);
}
}
else if( CGAL::assign( f, *o)) {
for(typename Halffacet_list::const_iterator fi=n->facets_begin(); fi!=n->facets_end(); ++fi) {
Halffacet_handle f(*fi);
if (SNC_intersection::does_contain_internally( f, p) ) {
_CGAL_NEF_TRACEN("found on facet...");
result = make_object(f);
found = true;
return make_object(f);
}
}
o++;
}
if( !found) {
_CGAL_NEF_TRACEN("point not found in 2-skeleton");
_CGAL_NEF_TRACEN("shooting ray to determine the volume");
Ray_3 r( p, Vector_3( -1, 0, 0));
result = make_object(determine_volume(r));
} CGAL_NEF_TIMER(pl_t.start());
CGAL_NEF_TIMER(pl_t.stop());
return result;
return make_object(determine_volume(r));
} else { // standard kernel
} else { // standard kernel
CGAL_assertion( initialized);
_CGAL_NEF_TRACEN( "locate "<<p);
SOLUTION solution = is_none_;
Node_handle n = candidate_provider->locate_node_containing(p);
typename Vertex_list::const_iterator vi = n->vertices_begin();
CGAL_assertion( initialized);
_CGAL_NEF_TRACEN( "locate "<<p);
Object_handle result;
Vertex_handle v, closest;
Halfedge_handle e;
Halffacet_handle f;
Object_list candidates = candidate_provider->objects_around_point(p);
Object_list_iterator o = candidates.begin();
if(n->empty())
return make_object(Base(*this).volumes_begin());
if(candidates.empty())
return make_object(Base(*this).volumes_begin());
CGAL::assign(v,*o);
CGAL_assertion(CGAL::assign(v,*o));
if(p==v->point())
return make_object(v);
closest = v;
++o;
while(o!=candidates.end() && CGAL::assign(v,*o)) {
if ( p == v->point()) {
_CGAL_NEF_TRACEN("found on vertex "<<v->point());
Vertex_handle v(*vi),closest;
if(p==v->point())
return make_object(v);
}
if(CGAL::has_smaller_distance_to_point(p, v->point(), closest->point())){
closest = v;
}
++o;
}
v = closest;
result = make_object(v);
Segment_3 s(p,v->point());
// bool first = true;
Point_3 ip;
/*
// TODO: das geht effizienter
Object_list_iterator of(o);
while(of != candidates.end() && assign(e, *of)) ++of;
typename SNC_structure::SHalfedge_iterator sei;
for(sei=v->shalfedges_begin(); sei!=v->shalfedges_end(); ++sei){
if(sei->is_twin()) continue;
Halffacet_handle fout = sei->facet();
if(fout->is_twin()) fout = fout->twin();
Object_list_iterator ofc(of);
for(;ofc!=candidates.end();++ofc) {
if(CGAL::assign(f,*ofc)) {
if(f == fout->twin())
std::cerr << "shit" << std::endl;
if(f == fout) {
Object_list_iterator oe(ofc);
--ofc;
candidates.erase(oe);
}
closest = v;
++vi;
while(vi!=n->vertices_end()) {
v = *vi;
if ( p == v->point()) {
_CGAL_NEF_TRACEN("found on vertex "<<v->point());
return make_object(v);
}
if(CGAL::has_smaller_distance_to_point(p, v->point(), closest->point())){
closest = v;
}
++vi;
}
}
*/
for(;o!=candidates.end();++o) {
if( CGAL::assign( e, *o)) {
// if(first &&
// (e->source() == v || e->twin()->source() == v)) continue;
Segment_3 ss(e->source()->point(),e->twin()->source()->point());
v = closest;
Vertex_handle v_res;
Halfedge_handle e_res;
Halffacet_handle f_res;
v_res = v;
solution = is_vertex_;
Segment_3 s(p,v->point());
Point_3 ip;
Halfedge_handle e;
for(typename Halfedge_list::const_iterator ei=n->edges_begin(); ei!=n->edges_end(); ++ei) {
e = *ei;
CGAL_NEF_TRACEN("test edge " << e->source()->point() << "->" << e->twin()->source()->point());
if (SNC_intersection::does_contain_internally(e->source()->point(), e->twin()->source()->point(), p)) {
_CGAL_NEF_TRACEN("found on edge "<< ss);
_CGAL_NEF_TRACEN("found on edge "<< ss);
return make_object(e);
}
if((e->source() != v) && (e->twin()->source() != v) && SNC_intersection::does_intersect_internally(s, ss, ip)) {
// first = false;
if((e->source() != v) && (e->twin()->source() != v) &&
SNC_intersection::does_intersect_internally(s, Segment_3(e->source()->point(),e->twin()->source()->point()), ip)) {
s = Segment_3(p, normalized(ip));
result = make_object(e);
e_res = e;
solution = is_edge_;
}
}
} else
if( CGAL::assign( f, *o)) {
Halffacet_handle f;
for(typename Halffacet_list::const_iterator fi=n->facets_begin(); fi!=n->facets_end(); ++fi) {
f = *fi;
CGAL_NEF_TRACEN("test facet " << f->plane());
if (SNC_intersection::does_contain_internally(f,p) ) {
_CGAL_NEF_TRACEN("found on facet...");
return make_object(f);
}
// We next check if v is a vertex on the face to avoid a geometric test
bool v_vertex_of_f = false;
Halffacet_cycle_iterator fci;
for(fci=f->facet_cycles_begin(); (! v_vertex_of_f) && (fci!=f->facet_cycles_end()); ++fci) {
if(fci.is_shalfedge()) {
SHalfedge_around_facet_circulator sfc(fci), send(sfc);
CGAL_For_all(sfc,send) {
if(sfc->source()->center_vertex() == v){
v_vertex_of_f = true;
break;
}
}
}
}
if( (! v_vertex_of_f) && SNC_intersection::does_intersect_internally(s,f,ip) ) {
if( !v_vertex_of_f(v,f) && SNC_intersection::does_intersect_internally(s,f,ip) ) {
s = Segment_3(p, normalized(ip));
result = make_object(f);
f_res = f;
solution = is_facet_;
}
}
else CGAL_error_msg( "wrong handle type");
}
//CGAL_warning("altered code in SNC_point_locator");
/*
Halffacet_iterator fc;
CGAL_forall_facets(fc, *this->sncp()) {
CGAL_assertion(!SNC_intersection::does_intersect_internally(s,f,ip));
if( solution == is_vertex_) {
_CGAL_NEF_TRACEN("vertex hit, obtaining volume..." << v_res->point());
//CGAL_warning("altered code in SNC_point_locator");
SM_point_locator L(&*v_res);
Object_handle so = L.locate(s.source()-s.target(), true);
SFace_handle sf;
if(CGAL::assign(sf,so))
return make_object(sf->volume());
CGAL_error_msg( "wrong handle type");
return Object_handle();
} else if( solution == is_facet_) {
_CGAL_NEF_TRACEN("facet hit, obtaining volume...");
if(f_res->plane().oriented_side(p) == ON_NEGATIVE_SIDE)
f_res = f_res->twin();
return make_object(f_res->incident_volume());
} else if( solution == is_edge_) {
SM_decorator SD(&*e_res->source());
if( SD.is_isolated(e_res))
return make_object(e_res->incident_sface()->volume());
return make_object(get_visible_facet(e_res,Ray_3(s.source(),s.to_vector()))->incident_volume());
}
Halfedge_iterator ec;
CGAL_forall_edges(ec, *this->sncp()) {
Segment_3 ss(ec->source()->point(), ec->twin()->source()->point());
CGAL_assertion(!SNC_intersection::does_intersect_internally(s,ss,ip));
}
Vertex_iterator vc;
CGAL_forall_vertices(vc, *this->sncp()) {
std::cerr << "test vertex " << vc->point() << std::endl;
CGAL_assertion(vc->point() == s.target() || !s.has_on(vc->point()));
}
*/
if( CGAL::assign( v, result)) {
_CGAL_NEF_TRACEN("vertex hit, obtaining volume..." << v->point());
//CGAL_warning("altered code in SNC_point_locator");
SM_point_locator L(&*v);
Object_handle so = L.locate(s.source()-s.target(), true);
SFace_handle sf;
if(CGAL::assign(sf,so))
return make_object(sf->volume());
CGAL_error_msg( "wrong handle type");
return Object_handle();
/*
SHalfedge_handle se;
CGAL_assertion(CGAL::assign(se,so));
CGAL_NEF_TRACEN("intersect segment " << s << " with edges");
for(;ox!=candidates.end();++ox) {
if(!CGAL::assign(e,*ox)) continue;
CGAL_NEF_TRACEN("test edge " << e->source()->point() << "->" << e->twin()->source()->point());
if(SNC_intersection::does_intersect_internally(s,Segment_3(e->source()->point(),e->twin()->source()->point()),ip)) {
s = Segment_3(p, normalized(ip));
result = make_object(e);
}
}
CGAL_assertion(CGAL::assign(e,result));
CGAL::assign(e,result);
f = get_visible_facet(e, Ray_3(p, s.target()));
if( f != Halffacet_handle())
return f->incident_volume();
SM_decorator SD(&*v); // now, the vertex has no incident facets
CGAL_assertion( SD.number_of_sfaces() == 1);
return SD.sfaces_begin()->volume();
*/
} else if( CGAL::assign( f, result)) {
_CGAL_NEF_TRACEN("facet hit, obtaining volume...");
if(f->plane().oriented_side(p) == ON_NEGATIVE_SIDE)
f = f->twin();
return make_object(f->incident_volume());
} else if( CGAL::assign(e, result)) {
SM_decorator SD(&*e->source());
if( SD.is_isolated(e))
return make_object(e->incident_sface()->volume());
return make_object(get_visible_facet(e,Ray_3(s.source(),s.to_vector()))->incident_volume());
}
CGAL_error_msg( "wrong handle type");
return Object_handle();
}
}
virtual void intersect_with_edges_and_facets( Halfedge_handle e0,
const typename SNC_point_locator::Intersection_call_back& call_back) const {
CGAL_NEF_TIMER(it_t.start());
CGAL_assertion( initialized);
const Intersection_call_back& call_back) const {
_CGAL_NEF_TRACEN( "intersecting edge: "<<&*e0<<' '<<Segment_3(e0->source()->point(),
e0->twin()->source()->point()));
Segment_3 s(Segment_3(e0->source()->point(),e0->twin()->source()->point()));
Vertex_handle v;
Halfedge_handle e;
Halffacet_handle f;
Object_list_iterator o;
Object_list objects = candidate_provider->objects_around_segment(s);
CGAL_for_each( o, objects) {
if( CGAL::assign( v, *o)) {
/* do nothing */
}
else if( CGAL::assign( e, *o)) {
#ifdef CGAL_NEF3_DUMP_STATISTICS
++number_of_intersection_candidates;
#endif
Point_3 q;
if( SNC_intersection::does_intersect_internally( s, Segment_3(e->source()->point(),
e->twin()->source()->point()), q)) {
q = normalized(q);
call_back( e0, make_object(Halfedge_handle(e)), q);
_CGAL_NEF_TRACEN("edge intersects edge "<<' '<<&*e<< Segment_3(e->source()->point(),
e->twin()->source()->point())<<" on "<<q);
}
}
else if( CGAL::assign( f, *o)) {
#ifdef CGAL_NEF3_DUMP_STATISTICS
++number_of_intersection_candidates;
#endif
Point_3 q;
if( SNC_intersection::does_intersect_internally( s, f, q) ) {
q = normalized(q);
call_back( e0, make_object(Halffacet_handle(f)), q);
_CGAL_NEF_TRACEN("edge intersects facet on plane "<<f->plane()<<" on "<<q);
}
}
else
CGAL_error_msg( "wrong handle");
}
CGAL_NEF_TIMER(it_t.stop());
e0->twin()->source()->point()));
Segment_3 s(e0->source()->point(),e0->twin()->source()->point());
Node_list nodes = candidate_provider->nodes_around_segment(s);
intersect_with_edges(e0,call_back,s,nodes);
intersect_with_facets(e0,call_back,s,nodes);
}
virtual void intersect_with_edges( Halfedge_handle e0,
const typename SNC_point_locator::Intersection_call_back& call_back) const {
const Intersection_call_back& call_back) const {
CGAL_NEF_TIMER(it_t.start());
CGAL_assertion( initialized);
_CGAL_NEF_TRACEN( "intersecting edge: "<<&*e0<<' '<<Segment_3(e0->source()->point(),
e0->twin()->source()->point()));
Segment_3 s(Segment_3(e0->source()->point(),e0->twin()->source()->point()));
Vertex_handle v;
Halfedge_handle e;
Halffacet_handle f;
Object_list_iterator o;
Object_list objects = candidate_provider->objects_around_segment(s);
CGAL_for_each( o, objects) {
if( CGAL::assign( v, *o)) {
/* do nothing */
}
else if( CGAL::assign( e, *o)) {
#ifdef CGAL_NEF3_DUMP_STATISTICS
++number_of_intersection_candidates;
#endif
Point_3 q;
if( SNC_intersection::does_intersect_internally( s, Segment_3(e->source()->point(),
e->twin()->source()->point()), q)) {
q = normalized(q);
call_back( e0, make_object(Halfedge_handle(e)), q);
_CGAL_NEF_TRACEN("edge intersects edge "<<' '<<&*e<< Segment_3(e->source()->point(),
e->twin()->source()->point())<<" on "<<q);
}
}
else if( CGAL::assign( f, *o)) {
/* do nothing */
}
else
CGAL_error_msg( "wrong handle");
}
CGAL_NEF_TIMER(it_t.stop());
e0->twin()->source()->point()));
Segment_3 s(e0->source()->point(),e0->twin()->source()->point());
Node_list nodes = candidate_provider->nodes_around_segment(s);
intersect_with_edges(e0,call_back,s,nodes);
}
virtual void intersect_with_facets( Halfedge_handle e0,
const typename SNC_point_locator::Intersection_call_back& call_back) const {
CGAL_NEF_TIMER(it_t.start());
const Intersection_call_back& call_back) const {
CGAL_assertion( initialized);
_CGAL_NEF_TRACEN( "intersecting edge: "<< Segment_3(e0->source()->point(),
e0->twin()->source()->point()));
Segment_3 s(Segment_3(e0->source()->point(),e0->twin()->source()->point()));
Vertex_handle v;
Halfedge_handle e;
Halffacet_handle f;
Object_list_iterator o;
Object_list objects = candidate_provider->objects_around_segment(s);
CGAL_for_each( o, objects) {
if( CGAL::assign( v, *o)) {
/* do nothing */
}
else if( CGAL::assign( e, *o)) {
/* do nothing */
}
else if( CGAL::assign( f, *o)) {
#ifdef CGAL_NEF3_DUMP_STATISTICS
++number_of_intersection_candidates;
#endif
Point_3 q;
if( SNC_intersection::does_intersect_internally( s, f, q) ) {
q = normalized(q);
call_back( e0, make_object(Halffacet_handle(f)), q);
_CGAL_NEF_TRACEN("edge intersects facet on plane "<<f->plane()<<" on "<<q);
}
}
else
CGAL_error_msg( "wrong handle");
}
CGAL_NEF_TIMER(it_t.stop());
e0->twin()->source()->point()));
Segment_3 s(e0->source()->point(),e0->twin()->source()->point());
Node_list nodes = candidate_provider->nodes_around_segment(s);
intersect_with_facets(e0,call_back,s,nodes);
}
private:
void intersect_with_edges( Halfedge_handle e0,
const Intersection_call_back& call_back, Segment_3& s, Node_list& nodes) const {
Unique_hash_map<Halfedge_handle,bool> visited(false);
for(typename Node_list::iterator ni = nodes.begin(); ni!=nodes.end(); ++ni) {
Node_handle n(*ni);
for(typename Halfedge_list::const_iterator e = n->edges_begin(); e!=n->edges_end(); ++e) {
if(!visited[*e]) {
#ifdef CGAL_NEF3_DUMP_STATISTICS
++number_of_intersection_candidates;
#endif
Point_3 q;
if(SNC_intersection::does_intersect_internally( s, Segment_3((*e)->source()->point(),
(*e)->twin()->source()->point()), q)) {
q = normalized(q);
call_back( e0, *e, q);
_CGAL_NEF_TRACEN("edge intersects edge "<<' '<<&*e<< Segment_3((*e)->source()->point(),
(*e)->twin()->source()->point())<<" on "<<q);
}
visited[*e] = true;
}
}
}
}
void intersect_with_facets( Halfedge_handle e0,
const Intersection_call_back& call_back,Segment_3& s, Node_list& nodes) const {
Unique_hash_map<Halffacet_handle,bool> visited(false);
for(typename Node_list::iterator ni = nodes.begin(); ni!=nodes.end(); ++ni) {
Node_handle n(*ni);
for(typename Halffacet_list::const_iterator f = n->facets_begin(); f!=n->facets_end(); ++f) {
if(!visited[*f]) {
#ifdef CGAL_NEF3_DUMP_STATISTICS
++number_of_intersection_candidates;
#endif
Point_3 q;
if(SNC_intersection::does_intersect_internally( s, *f, q) ) {
q = normalized(q);
call_back( e0, *f, q);
_CGAL_NEF_TRACEN("edge intersects facet on plane "<<f->plane()<<" on "<<q);
}
visited[*f] = true;
}
}
}
}
Volume_handle determine_volume( const Ray_3& ray) const {
Halffacet_handle f_below;
Object_handle o = shoot(ray);

View File

@ -71,7 +71,7 @@ struct binop_intersection_test_segment_tree {
return;
Point_3 ip;
if( SNC_intersection::does_intersect_internally( Const_decorator::segment(e0), f1, ip )) {
cb(e0,make_object(f1),ip);
cb(e0,f1,ip);
}
}
};
@ -97,7 +97,7 @@ struct binop_intersection_test_segment_tree {
Point_3 ip;
if( SNC_intersection::does_intersect_internally( Const_decorator::segment( e1 ),
f0, ip ) )
cb(e1,make_object(f0),ip);
cb(e1,f0,ip);
}
};
@ -119,7 +119,7 @@ struct binop_intersection_test_segment_tree {
Point_3 ip;
if( SNC_intersection::does_intersect_internally( Const_decorator::segment( e0 ),
Const_decorator::segment( e1 ), ip ))
cb(e0,make_object(e1),ip);
cb(e0,e1,ip);
}
};

View File

@ -5,5 +5,3 @@ PROJECT_NAME = "CGAL ${CGAL_DOC_VERSION} - Quadtrees, Octrees, and Orthtrees"
EXTRACT_ALL = false
HIDE_UNDOC_MEMBERS = true
HIDE_UNDOC_CLASSES = true
EXAMPLE_PATH = ${CGAL_PACKAGE_DIR}/examples

View File

@ -855,19 +855,19 @@ private: // functions :
}
/*!
\brief finds the `k` points within a specific radius that are nearest to `query`.
\brief finds the `k` points within a specific radius that are
nearest to the center of `query_sphere`.
This function guarantees that there are no closer points than the ones returned,
but it does not guarantee that it will return at least `k` points.
For a query where the search radius encloses `k` or fewer points, all enclosed points will be returned.
If the search radius passed is too small, no points may be returned.
If the search radius is too small, no points may be returned.
This function is useful when the user already knows how sparse the points are,
or if they do not care about points that are too far away.
Setting a small radius may have performance benefits.
\tparam OutputIterator must be a model of `OutputIterator` that accepts points
\param search_point the location to find points near
\param search_radius_squared the size of the region to search within
\param query_sphere the region to search within
\param k the number of points to find
\param output the output iterator to add the found points to (in order of increasing distance)
*/

View File

@ -1,7 +1,6 @@
@INCLUDE = ${CGAL_DOC_PACKAGE_DEFAULTS}
PROJECT_NAME = "CGAL ${CGAL_DOC_VERSION} - 3D Periodic Mesh Generation"
EXAMPLE_PATH += ${CGAL_PACKAGE_INCLUDE_DIR}
EXTRACT_ALL = false
HIDE_UNDOC_CLASSES = true
WARN_IF_UNDOCUMENTED = false

View File

@ -3256,6 +3256,7 @@ periodic_remove(Vertex_handle v, PointRemover& remover, CoverManager& cover_mana
typename Vertex_triple_Facet_map::iterator oit = outer_map.begin();
typename Vertex_triple_Facet_map::value_type o_vt_f_pair = *oit;
outer_map.erase(oit);
Cell_handle o_ch = o_vt_f_pair.second.first;
unsigned int o_i = o_vt_f_pair.second.second;
@ -3314,7 +3315,6 @@ periodic_remove(Vertex_handle v, PointRemover& remover, CoverManager& cover_mana
}
}
}
outer_map.erase(oit);
}
// finally set the neighboring relations

View File

@ -1,7 +1,5 @@
@INCLUDE = ${CGAL_DOC_PACKAGE_DEFAULTS}
EXAMPLE_PATH = ${CGAL_PACKAGE_DIR}/examples
EXTRACT_ALL = YES
EXTRACT_LOCAL_CLASSES = YES
INHERIT_DOCS = YES

View File

@ -26,7 +26,6 @@ namespace CGAL {
///
/// This variant exports the surface as a triangle soup.
///
/// @commentheading Template Parameters:
/// @tparam OutputIteratorValueType value_type of OutputIterator.
/// It is default to value_type_traits<OutputIterator>::type, and can be omitted when the default is fine.
/// @tparam SurfaceMeshComplex_2InTriangulation_3 model of the SurfaceMeshComplex_2InTriangulation_3 concept.

View File

@ -763,8 +763,7 @@ private:
/// Poisson reconstruction.
/// Returns false on error.
///
/// @commentheading Template parameters:
/// @param SparseLinearAlgebraTraits_d Symmetric definite positive sparse linear solver.
/// @tparam SparseLinearAlgebraTraits_d Symmetric definite positive sparse linear solver.
template <class SparseLinearAlgebraTraits_d>
bool solve_poisson(
SparseLinearAlgebraTraits_d solver, ///< sparse linear solver
@ -1203,8 +1202,7 @@ private:
/// Assemble vi's row of the linear system A*X=B
///
/// @commentheading Template parameters:
/// @param SparseLinearAlgebraTraits_d Symmetric definite positive sparse linear solver.
/// @tparam SparseLinearAlgebraTraits_d Symmetric definite positive sparse linear solver.
template <class SparseLinearAlgebraTraits_d>
void assemble_poisson_row(typename SparseLinearAlgebraTraits_d::Matrix& A,
Vertex_handle vi,

View File

@ -348,12 +348,12 @@ public:
/// Insert the [first, beyond) range of points in the triangulation using a spatial sort.
/// Default type is INPUT.
///
/// @commentheading Template Parameters:
/// @param InputIterator iterator over input points.
/// @param PointPMap is a model of `ReadablePropertyMap` with a value_type = Point_3.
/// *Template Parameters:*
/// @tparam InputIterator iterator over input points.
/// @tparam PointPMap is a model of `ReadablePropertyMap` with a value_type = Point_3.
/// It can be omitted if InputIterator value_type is convertible to Point_3.
/// @param NormalPMap is a model of `ReadablePropertyMap` with a value_type = Vector_3.
///
/// @tparam NormalPMap is a model of `ReadablePropertyMap` with a value_type = Vector_3.
/// @tparam Visitor the visitor type
/// @return the number of inserted points.
// This variant requires all parameters.

View File

@ -180,17 +180,17 @@ public:
/// bad means badly shaped or too big).
/// @return the number of vertices inserted.
///
/// @commentheading Preconditions:
/// \pre
/// - Tr must use a geometric traits with robust circumcenter computation.
/// - convergence is guaranteed if radius_edge_ratio_bound >= 1.0.
///
/// @commentheading Template Parameters:
/// @param Tr 3D Delaunay triangulation.
/// @param Surface Sphere_3 or Iso_cuboid_3.
/// @param Sizing_field A sizing field functor type
/// @param Second_sizing_field A sizing field functor type
/// *Template Parameters*
/// @tparam Tr 3D Delaunay triangulation.
/// @tparam Surface Sphere_3 or Iso_cuboid_3.
/// @tparam Sizing_field A sizing field functor type
/// @tparam Second_sizing_field A sizing field functor type
///
/// @commentheading Sizing fields
/// *Sizing fields*
/// - The first sizing field is the real sizing field that is targeted by
/// the refinement process. It may be costly to use.
/// - The second sizing field is supposed to be a sizing field that is less

View File

@ -1,8 +1,7 @@
@INCLUDE = ${CGAL_DOC_PACKAGE_DEFAULTS}
PROJECT_NAME = "CGAL ${CGAL_DOC_VERSION} - 2D Polygons"
EXAMPLE_PATH = ${CGAL_PACKAGE_DIR}/examples \
${CGAL_Stream_support_EXAMPLE_DIR}
EXAMPLE_PATH += ${CGAL_Stream_support_EXAMPLE_DIR}
EXTRACT_ALL = false
HIDE_UNDOC_MEMBERS = true

View File

@ -63,6 +63,10 @@ public:
m_pgn(pgn_boundary)
{}
explicit General_polygon_with_holes_2(Polygon_2&& pgn_boundary) :
m_pgn(std::move(pgn_boundary))
{}
template <typename HolesInputIterator>
General_polygon_with_holes_2(const Polygon_2& pgn_boundary,
HolesInputIterator h_begin,
@ -71,6 +75,14 @@ public:
m_holes(h_begin, h_end)
{}
template <typename HolesInputIterator>
General_polygon_with_holes_2(Polygon_2&& pgn_boundary,
HolesInputIterator h_begin,
HolesInputIterator h_end) :
m_pgn(std::move(pgn_boundary)),
m_holes(h_begin, h_end)
{}
Holes_container& holes() { return m_holes; }
const Holes_container& holes() const { return m_holes; }
@ -91,6 +103,8 @@ public:
void add_hole(const Polygon_2& pgn_hole) { m_holes.push_back(pgn_hole); }
void add_hole(Polygon_2&& pgn_hole) { m_holes.emplace_back(std::move(pgn_hole)); }
void erase_hole(Hole_iterator hit) { m_holes.erase(hit); }
bool has_holes() const { return (!m_holes.empty()); }
@ -113,10 +127,10 @@ protected:
// operator<<
//-----------------------------------------------------------------------//
/*!
This operator exports a General_polygon_with_holes_2 to the output stream `out`.
This operator exports a `General_polygon_with_holes_2` to the output stream `os`.
An \ascii and a binary format exist. The format can be selected with
the \cgal modifiers for streams, `set_ascii_mode(0` and `set_binary_mode()`
the \cgal modifiers for streams, `set_ascii_mode()` and `set_binary_mode()`,
respectively. The modifier `set_pretty_mode()` can be used to allow for (a
few) structuring comments in the output. Otherwise, the output would
be free of comments. The default for writing is \ascii without comments.
@ -164,9 +178,9 @@ operator<<(std::ostream& os, const General_polygon_with_holes_2<Polygon_>& p) {
//-----------------------------------------------------------------------//
/*!
This operator imports a General_polygon_with_holes_2 from the input stream `in`.
This operator imports a `General_polygon_with_holes_2` from the input stream `is`.
Both ASCII and binary formats are supported, and the format is automatically detected.
Both \ascii and binary formats are supported, and the format is automatically detected.
The format consists of the number of curves of the outer boundary
followed by the curves themselves, followed
@ -187,7 +201,7 @@ operator>>(std::istream& is, General_polygon_with_holes_2<Polygon_>& p) {
Polygon_ pgn_hole;
for (unsigned int i=0; i<n_holes; ++i) {
is >> pgn_hole;
p.add_hole(pgn_hole);
p.add_hole(std::move(pgn_hole));
}
}

View File

@ -42,11 +42,11 @@
namespace CGAL {
/// \ingroup PkgPolygon2Ref
/// The class Polygon_2 implements polygons. The Polygon_2 is
/// The class `Polygon_2` implements polygons. The `Polygon_2` is
/// parameterized by a traits class and a container class. The latter
/// can be any class that fulfills the requirements for an STL
/// container, and has a function `resize()` that takes an std::size_t as argument
/// . It defaults to the std::vector class.
/// container, and has a function `resize()` that takes an `std::size_t` as argument.
/// It defaults to the `std::vector` class.
///
/// \cgalHeading{Implementation}
///
@ -154,14 +154,16 @@ class Polygon_2 {
/// @{
/// Creates an empty polygon.
Polygon_2() : traits() {}
Polygon_2() = default;
/// Creates an empty polygon.
Polygon_2(const Traits & p_traits) : traits(p_traits) {}
/// Copy constructor.
Polygon_2(const Polygon_2<Traits_P,Container_P>& polygon)
: d_container(polygon.d_container), traits(polygon.traits) {}
Polygon_2(const Polygon_2<Traits_P,Container_P>& polygon) = default;
/// Move constructor
Polygon_2(Polygon_2<Traits_P,Container_P>&& polygon) = default;
/// Creates a polygon with vertices from the sequence
/// defined by the range \c [first,last).
@ -173,7 +175,8 @@ class Polygon_2 {
{}
#ifndef DOXYGEN_RUNNING
Polygon_2& operator=(const Polygon_2&)=default;
Polygon_2& operator=(const Polygon_2&) = default;
Polygon_2& operator=(Polygon_2&& p) = default;
#endif
/// @}
@ -570,7 +573,7 @@ operator!=(const Polygon_2<Traits_P,Container1_P> &p1,
const Polygon_2<Traits_P,Container2_P> &p2);
/// Returns the image of the polygon \c p under the transformation \c t.
/// \memberof Polygon_2
/// \relates Polygon_2
template <class Transformation, class Traits_P, class Container_P>
Polygon_2<Traits_P,Container_P>
transform(const Transformation& t, const Polygon_2<Traits_P,Container_P>& p);
@ -584,13 +587,13 @@ transform(const Transformation& t, const Polygon_2<Traits_P,Container_P>& p);
/// Reads a polygon from stream `is` and assigns it to `p`.
/// \pre The extract operator must be defined for `Point_2`.
/// \memberof Polygon_2
/// \relates Polygon_2
template <class Traits_P, class Container_P>
std::istream &operator>>(std::istream &is, Polygon_2<Traits_P,Container_P>& p);
/// Inserts the polygon `p` into the stream `os`.
/// \pre The insert operator must be defined for `Point_2`.
/// \memberof Polygon_2
/// \relates Polygon_2
template <class Traits_P, class Container_P>
std::ostream &operator<<(std::ostream &os, const Polygon_2<Traits_P,Container_P>& p);

View File

@ -63,6 +63,11 @@ public:
Base (pgn_boundary)
{}
/*! Move constructor */
explicit Polygon_with_holes_2 (Polygon_2&& pgn_boundary) :
Base (std::move(pgn_boundary))
{}
/*! Constructor from a polygon (outer boundary) and hole polygons. */
template <class HolesInputIterator>
Polygon_with_holes_2 (const Polygon_2& pgn_boundary,
@ -71,6 +76,17 @@ public:
Base (pgn_boundary, h_begin, h_end)
{}
/*! Move constructor.
* \note In order to move the hole polygons a
* `std::move_iterator` may be used.
*/
template <class HolesInputIterator>
Polygon_with_holes_2 (Polygon_2&& pgn_boundary,
HolesInputIterator h_begin,
HolesInputIterator h_end) :
Base (std::move(pgn_boundary), h_begin, h_end)
{}
/*! Obtain the bounding box of the polygon with holes */
Bbox_2 bbox() const { return this->outer_boundary().bbox(); }
};
@ -80,10 +96,10 @@ public:
//-----------------------------------------------------------------------//
/*!
This operator exports a polygon with holes to the output stream `out`.
This operator exports a polygon with holes to the output stream `os`.
An \ascii and a binary format exist. The format can be selected with
the \cgal modifiers for streams, `set_ascii_mode()` and `set_binary_mode()`
the \cgal modifiers for streams, `set_ascii_mode()` and `set_binary_mode()`,
respectively. The modifier `set_pretty_mode()` can be used to allow for (a
few) structuring comments in the output. Otherwise, the output would
be free of comments. The default for writing is \ascii without comments.
@ -143,9 +159,9 @@ std::ostream& operator<<(std::ostream &os,
//-----------------------------------------------------------------------//
/*!
This operator imports a polygon with holes from the input stream `in`.
This operator imports a polygon with holes from the input stream `is`.
Both ASCII and binary formats are supported, and the format is automatically detected.
Both \ascii and binary formats are supported, and the format is automatically detected.
The format consists of the number of points of the outer boundary followed
by the points themselves in counterclockwise order, followed by the number of holes,
@ -170,7 +186,7 @@ std::istream &operator>>(std::istream &is,
{
Polygon_2 hole;
is >> hole;
p.add_hole(hole);
p.add_hole(std::move(hole));
}
}

View File

@ -51,6 +51,18 @@ void test_default_methods( vector<Point>& pvec0,
x=p0;
assert(x == p0);
// move assignement and constructor
x.clear();
assert(x.is_empty());
x = std::move(p0);
assert(p0.is_empty());
assert(x == p0_copy);
CGAL::Polygon_2<K, list<Point> > xm(std::move(x));
assert(x.is_empty());
assert(xm == p0_copy);
}
{
@ -336,4 +348,3 @@ int main()
return 0;
}

View File

@ -0,0 +1,45 @@
#include <CGAL/Simple_cartesian.h>
#include <CGAL/Polygon_2.h>
#include <CGAL/Polygon_with_holes_2.h>
#include <vector>
#include <iostream>
#include <cassert>
#include <iterator>
typedef CGAL::Simple_cartesian<double> K;
typedef K::Point_2 Point;
typedef CGAL::Polygon_2<K> Polygon_2;
typedef CGAL::Polygon_with_holes_2<K> Polygon_with_holes_2;
int main()
{
std::array<Point,4> outer = { Point(0, 0), Point(10, 0), Point(10, 10), Point(0, 10) };
std::array<Point, 4> hole1 = { Point(1, 1), Point(1, 2), Point(2, 2), Point(2, 1) };
std::array<Point, 4> hole2 = { Point(3, 3), Point(3, 4), Point(4, 4), Point(4, 3) };
std::vector<Polygon_2> holes;
holes.reserve(2);
holes.emplace_back(hole1.begin(), hole1.end());
holes.emplace_back(hole2.begin(), hole2.end());
Polygon_2 pouter(outer.begin(), outer.end());
Polygon_with_holes_2 pwh(std::move(pouter), std::move_iterator<std::vector<Polygon_2>::iterator>(holes.begin()), std::move_iterator<std::vector<Polygon_2>::iterator>(holes.end()));
assert(pouter.is_empty());
assert(holes[0].is_empty());
assert(holes[1].is_empty());
Polygon_with_holes_2 pwh_copy(pwh);
assert(pwh_copy == pwh);
Polygon_with_holes_2 pwh_move_cstructed(std::move(pwh));
assert(pwh.holes().empty());
assert(pwh.outer_boundary().is_empty());
Polygon_with_holes_2 pwh_move_assigned;
pwh_move_assigned = std::move(pwh_copy);
return 0;
}

View File

@ -441,18 +441,24 @@ namespace internal {
//insert new edges to keep triangular faces, and update long_edges
if (!is_border(hnew, mesh_))
{
Patch_id patch_id = get_patch_id(face(hnew, mesh_));
halfedge_descriptor hnew2 =
CGAL::Euler::split_face(hnew, next(next(hnew, mesh_), mesh_), mesh_);
put(ecmap_, edge(hnew2, mesh_), false);
set_patch_id(face(hnew2, mesh_), patch_id);
set_patch_id(face(opposite(hnew2, mesh_), mesh_), patch_id);
}
//do it again on the other side if we're not on boundary
halfedge_descriptor hnew_opp = opposite(hnew, mesh_);
if (!is_border(hnew_opp, mesh_))
{
Patch_id patch_id = get_patch_id(face(hnew_opp, mesh_));
halfedge_descriptor hnew2 =
CGAL::Euler::split_face(prev(hnew_opp, mesh_), next(hnew_opp, mesh_), mesh_);
put(ecmap_, edge(hnew2, mesh_), false);
set_patch_id(face(hnew2, mesh_), patch_id);
set_patch_id(face(opposite(hnew2, mesh_), mesh_), patch_id);
}
}
#ifdef CGAL_PMP_REMESHING_VERBOSE
@ -853,11 +859,12 @@ namespace internal {
mesh_, vpmap_, vcmap_, ecmap_, gt_,
cap_threshold, // bound on the angle: above 160 deg => cap
4, // bound on shortest/longest edge above 4 => needle
0);// collapse length threshold : not needed here
0,// collapse length threshold : not needed here
0); // flip triangle height threshold
std::array<halfedge_descriptor, 2> r2 = internal::is_badly_shaped(
face(opposite(he, mesh_), mesh_),
mesh_, vpmap_, vcmap_, ecmap_, gt_, cap_threshold, 4, 0);
mesh_, vpmap_, vcmap_, ecmap_, gt_, cap_threshold, 4, 0, 0);
const bool badly_shaped = (r1[0] != boost::graph_traits<PolygonMesh>::null_halfedge()//needle
|| r1[1] != boost::graph_traits<PolygonMesh>::null_halfedge()//cap

View File

@ -151,13 +151,19 @@ void simplify_range(HalfedgeRange& halfedge_range,
new_tolerance += CGAL::approximate_sqrt(CGAL::squared_distance(new_p, pt));
}
if (!CGAL::Euler::does_satisfy_link_condition(edge(h, tm), tm))
continue;
const halfedge_descriptor opoh = opposite(prev(opposite(h, tm), tm), tm);
if (is_border(opoh, tm))
edges_to_test.erase( opoh );
vertex_descriptor v = Euler::collapse_edge(edge(h, tm), tm);
put(vpm, v, new_p);
put(tolerance_map, v, new_tolerance);
if(get(range_halfedges, prev_h))
edges_to_test.insert(prev_h);
if(get(range_halfedges, next_h))
if(next_h!=opoh && get(range_halfedges, next_h))
edges_to_test.insert(next_h);
++collapsed_n;

View File

@ -364,8 +364,9 @@ void reverse_face_orientations(const FaceRange& face_range, PolygonMesh& pmesh)
/**
* \ingroup PMP_orientation_grp
*
* makes each connected component of a closed triangulated surface mesh inward or outward oriented.
* makes each closed connected component of a triangulated surface mesh
* inward or outward oriented. If a connected component is not closed,
* the orientation may or may not be changed or not is not guaranteed.
*
* @tparam TriangleMesh a model of `FaceListGraph` and `MutableFaceGraph`
* @tparam NamedParameters a sequence of \ref bgl_namedparameters
@ -418,7 +419,6 @@ void orient(TriangleMesh& tm,
CGAL_precondition(is_triangle_mesh(tm));
CGAL_precondition(is_valid_polygon_mesh(tm));
CGAL_precondition(is_closed(tm));
using parameters::choose_parameter;
using parameters::get_parameter;
@ -464,8 +464,17 @@ void orient(TriangleMesh& tm,
//orient ccs outward
for(std::size_t id=0; id<nb_cc; ++id)
{
if(internal::is_outward_oriented(xtrm_vertices[id], tm, np)
!= orient_outward)
// skip it if the vertex is on the boundary
bool v_is_border = false;
for(halfedge_descriptor h : halfedges_around_target(xtrm_vertices[id], tm))
if (is_border(h, tm))
{
v_is_border = true;
break;
}
if(!v_is_border && (internal::is_outward_oriented(xtrm_vertices[id], tm, np)
!= orient_outward))
{
reverse_face_orientations(ccs[id], tm);
}

View File

@ -377,6 +377,17 @@ void isotropic_remeshing(const FaceRange& faces
* \cgalParamDefault{an automatically indexed internal map}
* \cgalParamNEnd
*
* \cgalParamNBegin{face_patch_map}
* \cgalParamDescription{a property map with the patch id's associated to the faces of `faces`}
* \cgalParamType{a class model of `ReadWritePropertyMap` with `boost::graph_traits<PolygonMesh>::%face_descriptor`
* as key type and the desired property, model of `CopyConstructible` and `LessThanComparable` as value type.}
* \cgalParamDefault{a default property map where each face is associated with the ID of
* the connected component it belongs to. Connected components are
* computed with respect to the constrained edges listed in the property map
* `edge_is_constrained_map`}
* \cgalParamExtra{The map is updated during the remeshing process while new faces are created.}
* \cgalParamNEnd
*
* \cgalParamNBegin{edge_is_constrained_map}
* \cgalParamDescription{a property map containing the constrained-or-not status of each edge of `pmesh`}
* \cgalParamType{a class model of `ReadWritePropertyMap` with `boost::graph_traits<PolygonMesh>::%edge_descriptor`
@ -421,14 +432,22 @@ void split_long_edges(const EdgeRange& edges
ECMap ecmap = choose_parameter(get_parameter(np, internal_np::edge_is_constrained),
Static_boolean_property_map<edge_descriptor, false>());
typedef typename internal_np::Lookup_named_param_def <
internal_np::face_patch_t,
NamedParameters,
internal::Connected_components_pmap<PM, FIMap>//default
> ::type FPMap;
FPMap fpmap = choose_parameter(
get_parameter(np, internal_np::face_patch),
internal::Connected_components_pmap<PM, FIMap>(faces(pmesh), pmesh, ecmap, fimap, false));
typename internal::Incremental_remesher<PM, VPMap, GT, ECMap,
Static_boolean_property_map<vertex_descriptor, false>, // no constraint pmap
internal::Connected_components_pmap<PM, FIMap>,
FIMap
FPMap,FIMap
>
remesher(pmesh, vpmap, gt, false/*protect constraints*/, ecmap,
Static_boolean_property_map<vertex_descriptor, false>(),
internal::Connected_components_pmap<PM, FIMap>(faces(pmesh), pmesh, ecmap, fimap, false),
fpmap,
fimap,
false/*need aabb_tree*/);

View File

@ -61,7 +61,8 @@ is_badly_shaped(const typename boost::graph_traits<TriangleMesh>::face_descripto
const Traits& gt,
const double cap_threshold, // angle over 160° ==> cap
const double needle_threshold, // longest edge / shortest edge over this ratio ==> needle
const double collapse_length_threshold) // max length of edges allowed to be collapsed
const double collapse_length_threshold, // max length of edges allowed to be collapsed
const double flip_triangle_height_threshold_squared) // max height of triangles allowed to be flipped
{
namespace PMP = CGAL::Polygon_mesh_processing;
@ -83,8 +84,14 @@ is_badly_shaped(const typename boost::graph_traits<TriangleMesh>::face_descripto
}
res = PMP::is_cap_triangle_face(f, tmesh, cap_threshold, parameters::vertex_point_map(vpm).geom_traits(gt));
if(res != null_h && !get(ecm, edge(res, tmesh)))
if( res != null_h && !get(ecm, edge(res, tmesh) ) &&
(flip_triangle_height_threshold_squared == 0 ||
typename Traits::Compare_squared_distance_3()( get(vpm, target(next(res,tmesh), tmesh)),
typename Traits::Line_3(get(vpm, source(res,tmesh)), get(vpm, target(res,tmesh))),
flip_triangle_height_threshold_squared) != LARGER ))
{
return make_array(null_h, res);
}
return make_array(null_h, null_h);
}
@ -100,13 +107,15 @@ void collect_badly_shaped_triangles(const typename boost::graph_traits<TriangleM
const double cap_threshold, // angle over this threshold (as a cosine) ==> cap
const double needle_threshold, // longest edge / shortest edge over this ratio ==> needle
const double collapse_length_threshold, // max length of edges allowed to be collapsed
const double flip_triangle_height_threshold_squared, // max height squared of triangles that can be flipped
HalfedgeContainer& edges_to_collapse,
HalfedgeContainer& edges_to_flip)
{
typedef typename boost::graph_traits<TriangleMesh>::halfedge_descriptor halfedge_descriptor;
std::array<halfedge_descriptor, 2> res = is_badly_shaped(f, tmesh, vpm, vcm, ecm, gt, cap_threshold,
needle_threshold, collapse_length_threshold);
needle_threshold,
collapse_length_threshold, flip_triangle_height_threshold_squared);
if(res[0] != boost::graph_traits<TriangleMesh>::null_halfedge())
{
@ -580,6 +589,9 @@ bool remove_almost_degenerate_faces(const FaceRange& face_range,
typedef typename boost::property_map<TriangleMesh, Vertex_property_tag>::type DVCM;
DVCM vcm = get(Vertex_property_tag(), tmesh);
const double flip_triangle_height_threshold_squared =
CGAL::square(choose_parameter(get_parameter(np, internal_np::flip_triangle_height_threshold), 0));
CGAL_precondition(is_valid_polygon_mesh(tmesh));
CGAL_precondition(is_triangle_mesh(tmesh));
@ -611,7 +623,8 @@ bool remove_almost_degenerate_faces(const FaceRange& face_range,
for(face_descriptor f : face_range)
{
internal::collect_badly_shaped_triangles(f, tmesh, vpm, vcm, ecm, gt,
cap_threshold, needle_threshold, collapse_length_threshold,
cap_threshold, needle_threshold,
collapse_length_threshold, flip_triangle_height_threshold_squared,
edges_to_collapse, edges_to_flip);
}
@ -671,7 +684,7 @@ bool remove_almost_degenerate_faces(const FaceRange& face_range,
// Verify that the element is still badly shaped
const std::array<halfedge_descriptor, 2> nc =
internal::is_badly_shaped(face(h, tmesh), tmesh, vpm, vcm, ecm, gt,
cap_threshold, needle_threshold, collapse_length_threshold);
cap_threshold, needle_threshold, collapse_length_threshold, flip_triangle_height_threshold_squared);
if(nc[0] != h)
{
@ -757,7 +770,8 @@ bool remove_almost_degenerate_faces(const FaceRange& face_range,
if(!is_border(hv, tmesh))
{
internal::collect_badly_shaped_triangles(face(hv, tmesh), tmesh, vpm, vcm, ecm, gt,
cap_threshold, needle_threshold, collapse_length_threshold,
cap_threshold, needle_threshold,
collapse_length_threshold, flip_triangle_height_threshold_squared,
edges_to_collapse, edges_to_flip);
}
}
@ -806,7 +820,7 @@ bool remove_almost_degenerate_faces(const FaceRange& face_range,
std::array<halfedge_descriptor,2> nc = internal::is_badly_shaped(face(h, tmesh), tmesh, vpm, vcm, ecm, gt,
cap_threshold, needle_threshold,
collapse_length_threshold);
collapse_length_threshold, flip_triangle_height_threshold_squared);
// Check the triangle is still a cap
if(nc[1] != h)
{
@ -868,7 +882,8 @@ bool remove_almost_degenerate_faces(const FaceRange& face_range,
CGAL_assertion(!is_border(h, tmesh));
std::array<halfedge_descriptor, 2> nc =
internal::is_badly_shaped(face(h, tmesh), tmesh, vpm, vcm, ecm, gt,
cap_threshold, needle_threshold, collapse_length_threshold);
cap_threshold, needle_threshold,
collapse_length_threshold, flip_triangle_height_threshold_squared);
if(nc[1] != boost::graph_traits<TriangleMesh>::null_halfedge() && nc[1] != h)
next_edges_to_flip.insert(nc[1]);

View File

@ -30,6 +30,7 @@
#include <map>
#include <set>
#include <vector>
#include <deque>
#include <utility>
#include <unordered_map>
#include <unordered_set>

View File

@ -503,7 +503,7 @@ struct Is_cap_angle_over_threshold<K, true>
/// \ingroup PMP_predicates_grp
///
/// checks whether a triangle face is a cap.
/// A triangle is said to be a <i>cap</i> if one of the its angles is close to `180` degrees.
/// A triangle is said to be a <i>cap</i> if one of its angles is close to `180` degrees.
///
/// @tparam TriangleMesh a model of `FaceGraph`
/// @tparam NamedParameters a sequence of \ref bgl_namedparameters "Named Parameters"

View File

@ -5,6 +5,7 @@
#include <fstream>
#include <CGAL/Polygon_mesh_processing/repair_degeneracies.h>
#include <CGAL/Polyhedral_envelope.h>
#include <CGAL/Polygon_mesh_processing/measure.h>
#include <iostream>
#include <vector>
@ -116,7 +117,49 @@ void test_with_envelope(std::string filename, double eps)
std::cout << " Output mesh has self-intersections\n";
}
bool same_meshes(const Mesh& m1, const Mesh& m2)
{
std::size_t c=0, m1_only=0, m2_only=0;
PMP::match_faces(m1, m2, CGAL::Counting_output_iterator(&c)
, CGAL::Counting_output_iterator(&m1_only)
, CGAL::Counting_output_iterator(&m2_only));
return m1_only==0 && m2_only==0;
}
void test_parameters_on_pig(std::string filename)
{
std::ifstream input(filename);
Mesh mesh, bk;
if (!input || !(input >> mesh) || !CGAL::is_triangle_mesh(mesh)) {
std::cerr << "Not a valid input file." << std::endl;
exit(EXIT_FAILURE);
}
bk=mesh;
PMP::experimental::remove_almost_degenerate_faces(mesh,
std::cos(160. / 180 * CGAL_PI),
4,
9999 /*no_constraints*/);
assert(vertices(mesh).size()!=vertices(bk).size());
mesh=bk;
PMP::experimental::remove_almost_degenerate_faces(mesh,
std::cos(160. / 180 * CGAL_PI),
4,
0.000000000000001); // no-collapse but flips
assert(vertices(mesh).size()==vertices(bk).size());
assert(!same_meshes(mesh,bk));
mesh=bk;
PMP::experimental::remove_almost_degenerate_faces(mesh,
std::cos(160. / 180 * CGAL_PI),
4,
0.000000000000001,
CGAL::parameters::flip_triangle_height_threshold(0.000000000000001)); // no-collapse and no flip
assert(vertices(mesh).size()==vertices(bk).size());
assert(same_meshes(mesh,bk));
}
int main(int argc, char** argv)
{
@ -129,5 +172,9 @@ int main(int argc, char** argv)
if (argc==3)
test_with_envelope(filename, atof(argv[2]));
// only run that test with pig.off
if (argc==1)
test_parameters_on_pig(filename);
return 0;
}

View File

@ -5,17 +5,22 @@
#include "Scene_surface_mesh_item.h"
#include "Scene_polygon_soup_item.h"
#include "Scene_polyhedron_selection_item.h"
#include "Scene_polylines_item.h"
#include "Scene_points_with_normal_item.h"
#include <CGAL/alpha_wrap_3.h>
#include <CGAL/Polygon_mesh_processing/polygon_mesh_to_polygon_soup.h>
#include <QElapsedTimer>
#include <QAction>
#include <QMainWindow>
#include <QApplication>
#include <QString>
#include <QDialog>
#include <QElapsedTimer>
#include <QMainWindow>
#include <QMessageBox>
#include <QTextStream>
#include <QString>
#include <QTranslator>
#include <QtPlugin>
#include <vector>
@ -26,6 +31,183 @@
#include "ui_alpha_wrap_3_dialog.h"
struct Iterative_AW3_visualization_visitor
{
private:
bool m_do_snapshot;
Scene_polygon_soup_item* m_iterative_wrap_item = nullptr;
int sid = 0;
public:
template <typename Scene>
Iterative_AW3_visualization_visitor(Scene* scene,
const bool visualize_iterations,
const bool do_snapshot)
: m_do_snapshot(do_snapshot)
{
if(!visualize_iterations)
return;
m_iterative_wrap_item = new Scene_polygon_soup_item();
m_iterative_wrap_item->setName(QString("Iterative wrap"));
scene->addItem(m_iterative_wrap_item);
}
public:
template <typename AlphaWrapper>
void on_alpha_wrapping_begin(const AlphaWrapper&) { }
template <typename AlphaWrapper>
void on_flood_fill_begin(const AlphaWrapper&) { }
template <typename AlphaWrapper, typename Facet>
void before_facet_treatment(const AlphaWrapper&,
const Facet&) { }
template <typename AlphaWrapper, typename Point>
void before_Steiner_point_insertion(const AlphaWrapper& wrapper,
const Point& /* p */)
{
if(m_iterative_wrap_item == nullptr)
return;
// If the next top of the queue has vertices on the bbox, don't draw (as to avoid producing
// spikes in the visualization)
// const auto& gate = wrapper.queue().top();
// if(wrapper.triangulation().number_of_vertices() > 500 && gate.is_artificial_facet())
// return;
// Skip some...
if(wrapper.triangulation().number_of_vertices() % 50 != 0)
return;
// Extract the wrap as a triangle soup
using Dt = typename std::decay<decltype(wrapper.triangulation())>::type;
using Vertex_handle = typename Dt::Vertex_handle;
using Facet = typename Dt::Facet;
using Cell_handle = typename Dt::Cell_handle;
std::vector<Kernel::Point_3> points;
std::vector<std::vector<std::size_t> > faces;
std::unordered_map<Vertex_handle, std::size_t> vertex_to_id;
std::size_t nv = 0;
// This is used to compute colors depending on what is old and what is new.
// It is not currently used (a uniform gray color is used), but leaving it as it might be useful.
std::size_t min_time_stamp = -1, max_time_stamp = 0;
for(auto cit=wrapper.triangulation().finite_cells_begin(), cend=wrapper.triangulation().finite_cells_end(); cit!=cend; ++cit)
{
if(cit->time_stamp() > max_time_stamp)
max_time_stamp = cit->time_stamp();
if(cit->time_stamp() < min_time_stamp)
min_time_stamp = cit->time_stamp();
}
std::vector<CGAL::IO::Color> vcolors;
std::vector<CGAL::IO::Color> fcolors;
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)
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)
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));
auto insertion_res = vertex_to_id.emplace(vh, nv);
if(insertion_res.second) // successful insertion, never-seen-before vertex
{
points.push_back(wrapper.triangulation().point(vh));
vcolors.push_back(CGAL::IO::Color(0, 0, 0));
++nv;
}
ids[pos] = insertion_res.first->second;
}
faces.emplace_back(std::vector<std::size_t>{ids[0], ids[1], ids[2]});
double color_val = double(c->time_stamp() - min_time_stamp) / double(max_time_stamp - min_time_stamp);
color_val = int(256. * color_val);
// fcolors.push_back(CGAL::IO::Color(color_val, 10, 150)); // young is red, old is blue
// fcolors.push_back(CGAL::IO::Color(256 - color_val, 256 - color_val, 256 - color_val)); // young is light, old is dark
fcolors.push_back(CGAL::IO::Color(100, 100, 100)); // uniform darkish gray
}
// Update the wrap item's visualization
m_iterative_wrap_item->load(points, faces, fcolors, vcolors);
m_iterative_wrap_item->setName(QString("Iterative wrap #%1").arg(sid));
m_iterative_wrap_item->setAlpha(255 / 2);
m_iterative_wrap_item->invalidateOpenGLBuffers();
m_iterative_wrap_item->redraw();
m_iterative_wrap_item->itemChanged();
// Refresh the view
QApplication::processEvents();
if(m_do_snapshot)
{
std::stringstream oss;
oss << "Wrap_iteration-" << sid << ".png" << std::ends;
QString filename = QString::fromStdString(oss.str().c_str());
CGAL::Three::Viewer_interface* viewer = CGAL::Three::Three::activeViewer();
viewer->saveSnapshot(filename, 1920, 1080, true /*expand*/, 2.0 /*oversampling*/);
}
++sid;
}
template <typename AlphaWrapper, typename VertexHandle>
void after_Steiner_point_insertion(const AlphaWrapper&,
const VertexHandle) { }
template <typename AlphaWrapper>
void on_flood_fill_end(const AlphaWrapper&) { }
template <typename AlphaWrapper>
void on_alpha_wrapping_end(const AlphaWrapper&)
{
if(m_iterative_wrap_item == nullptr)
return;
m_iterative_wrap_item->setName(QString("Iterative wrap #%1").arg(sid));
m_iterative_wrap_item->setAlpha(255);
m_iterative_wrap_item->invalidateOpenGLBuffers();
m_iterative_wrap_item->redraw();
m_iterative_wrap_item->itemChanged();
QApplication::processEvents();
if(m_do_snapshot)
{
std::stringstream oss;
oss << "Wrap_iteration-" << sid << ".png" << std::ends;
QString filename = QString::fromStdString(oss.str().c_str());
CGAL::Three::Viewer_interface* viewer = CGAL::Three::Three::activeViewer();
viewer->saveSnapshot(filename);
}
m_iterative_wrap_item->setVisible(false);
// Refresh the view
QApplication::processEvents();
}
};
class Polyhedron_demo_alpha_wrap_3_plugin
: public QObject,
public CGAL::Three::Polyhedron_demo_plugin_helper
@ -34,6 +216,9 @@ class Polyhedron_demo_alpha_wrap_3_plugin
Q_INTERFACES(CGAL::Three::Polyhedron_demo_plugin_interface)
Q_PLUGIN_METADATA(IID "com.geometryfactory.PolyhedronDemo.PluginInterface/1.0")
private:
Ui::alpha_wrap_3_dialog ui;
public:
void init(QMainWindow* mainWindow,
CGAL::Three::Scene_interface* scene_interface,
@ -49,12 +234,17 @@ public:
bool applicable(QAction*) const
{
// Ok if there's at least one mesh
Q_FOREACH(int index, scene->selectionIndices())
{
if(qobject_cast<Scene_polygon_soup_item*>(scene->item(index)))
return true;
if(qobject_cast<Scene_surface_mesh_item*>(scene->item(index)))
return true;
if(qobject_cast<Scene_polygon_soup_item*>(scene->item(index)))
if(qobject_cast<Scene_polyhedron_selection_item*>(scene->item(index)))
return true;
if(qobject_cast<Scene_polylines_item*>(scene->item(index)))
return true;
if(qobject_cast<Scene_points_with_normal_item*>(scene->item(index)))
return true;
}
@ -67,10 +257,21 @@ public:
}
private:
void print_message(QString message) const
{
CGAL::Three::Three::information(message);
}
Ui::alpha_wrap_3_dialog create_dialog(QDialog* dialog)
{
Ui::alpha_wrap_3_dialog ui;
ui.setupUi(dialog);
connect(ui.wrapEdges, SIGNAL(clicked(bool)), this, SLOT(toggle_wrap_faces()));
connect(ui.wrapFaces, SIGNAL(clicked(bool)), this, SLOT(toggle_wrap_edges()));
connect(ui.visualizeIterations, SIGNAL(clicked(bool)),
this, SLOT(update_iteration_snapshot_checkbox()));
connect(ui.buttonBox, SIGNAL(accepted()), dialog, SLOT(accept()));
connect(ui.buttonBox, SIGNAL(rejected()), dialog, SLOT(reject()));
@ -78,14 +279,35 @@ private:
}
public Q_SLOTS:
void toggle_wrap_faces()
{
if(!ui.wrapEdges->isChecked()) // if edges are disabled, so are faces
ui.wrapFaces->setChecked(false);
}
void toggle_wrap_edges()
{
if(ui.wrapFaces->isChecked()) // if faces are enabled, so are edges
ui.wrapEdges->setChecked(true);
}
void update_iteration_snapshot_checkbox()
{
ui.snapshotIterations->setCheckable(ui.visualizeIterations->isChecked());
}
void on_actionAlpha_wrap_3_triggered()
{
using Points = typename Scene_polygon_soup_item::Points;
using Polygons = typename Scene_polygon_soup_item::Polygons;
using Oracle = CGAL::Alpha_wraps_3::internal::Triangle_soup_oracle<Points, Polygons>;
using Triangles = std::vector<Kernel::Triangle_3>;
using Segments = std::vector<Kernel::Segment_3>;
using Points = std::vector<Kernel::Point_3>;
using TS_Oracle = CGAL::Alpha_wraps_3::internal::Triangle_soup_oracle<Kernel>;
using SS_Oracle = CGAL::Alpha_wraps_3::internal::Segment_soup_oracle<Kernel, TS_Oracle>;
using Oracle = CGAL::Alpha_wraps_3::internal::Point_set_oracle<Kernel, SS_Oracle>;
QDialog dialog(mw);
Ui::alpha_wrap_3_dialog ui = create_dialog(&dialog);
ui = create_dialog(&dialog);
dialog.setWindowFlags(Qt::Dialog|Qt::CustomizeWindowHint|Qt::WindowCloseButtonHint);
int i = dialog.exec();
@ -97,49 +319,187 @@ public Q_SLOTS:
const bool enforce_manifoldness = ui.runManifoldness->isChecked();
double alpha = ui.alphaValue->value();
double offset = ui.offsetValue->value();
const bool visualize_iterations = ui.visualizeIterations->isChecked();
const bool do_snapshot_iterations = ui.snapshotIterations->isChecked();
if(alpha <= 0. || offset <= 0.)
return;
QApplication::setOverrideCursor(Qt::WaitCursor);
Oracle oracle;
TS_Oracle ts_oracle;
SS_Oracle ss_oracle(ts_oracle);
Oracle oracle(ss_oracle);
Triangles triangles;
Segments segments;
Points points;
Q_FOREACH(int index, scene->selectionIndices())
{
// ---
Scene_surface_mesh_item* sm_item = qobject_cast<Scene_surface_mesh_item*>(scene->item(index));
if(sm_item != nullptr)
{
if(!is_triangle_mesh(*(sm_item->polyhedron())))
continue;
SMesh* pMesh = sm_item->polyhedron();
auto vpm = get(CGAL::vertex_point, *pMesh);
Points points;
Polygons polygons;
CGAL::Polygon_mesh_processing::polygon_mesh_to_polygon_soup(*(sm_item->polyhedron()),
points, polygons);
oracle.add_triangle_soup(points, polygons);
}
else
{
Scene_polygon_soup_item* soup_item = qobject_cast<Scene_polygon_soup_item*>(scene->item(index));
if(soup_item != nullptr)
triangles.reserve(triangles.size() + num_faces(*pMesh));
for(boost::graph_traits<SMesh>::face_descriptor f : faces(*pMesh))
{
bool is_triangle_soup = true;
for(auto p : soup_item->polygons())
boost::graph_traits<SMesh>::halfedge_descriptor h = halfedge(f, *pMesh);
if(!is_triangle(h, *pMesh))
{
if(p.size() != 3)
{
is_triangle_soup = false;
break;
}
print_message("Warning: non-triangular face in input");
continue;
}
if(is_triangle_soup)
oracle.add_triangle_soup(soup_item->points(), soup_item->polygons());
triangles.emplace_back(get(vpm, target(h, *pMesh)),
get(vpm, target(next(h, *pMesh), *pMesh)),
get(vpm, source(h, *pMesh)));
}
sm_item->setRenderingMode(Flat);
continue;
}
// ---
Scene_polygon_soup_item* soup_item = qobject_cast<Scene_polygon_soup_item*>(scene->item(index));
if(soup_item != nullptr)
{
triangles.reserve(triangles.size() + soup_item->polygons().size());
for(const auto& p : soup_item->polygons())
{
if(p.size() != 3)
{
print_message("Warning: non-triangular face in input");
continue;
}
triangles.emplace_back(soup_item->points()[p[0]],
soup_item->points()[p[1]],
soup_item->points()[p[2]]);
}
soup_item->setRenderingMode(Flat);
continue;
}
// ---
Scene_polyhedron_selection_item* selection_item =
qobject_cast<Scene_polyhedron_selection_item*>(scene->item(index));
if(selection_item != nullptr)
{
SMesh* pMesh = selection_item->polyhedron();
auto vpm = get(CGAL::vertex_point, *pMesh);
triangles.reserve(triangles.size() + selection_item->selected_facets.size());
for(const auto& f : selection_item->selected_facets)
{
boost::graph_traits<SMesh>::halfedge_descriptor h = halfedge(f, *pMesh);
if(!is_triangle(h, *pMesh))
{
print_message("Warning: non-triangular face in input");
continue;
}
triangles.emplace_back(get(vpm, target(h, *pMesh)),
get(vpm, target(next(h, *pMesh), *pMesh)),
get(vpm, source(h, *pMesh)));
}
segments.reserve(segments.size() + selection_item->selected_edges.size());
for(const auto& e : selection_item->selected_edges)
{
segments.emplace_back(get(vpm, target(halfedge(e, *pMesh), *pMesh)),
get(vpm, target(opposite(halfedge(e, *pMesh), *pMesh), *pMesh)));
}
points.reserve(points.size() + selection_item->selected_vertices.size());
for(const auto& v : selection_item->selected_vertices)
{
points.push_back(get(vpm, v));
}
continue;
}
// ---
Scene_polylines_item* lines_item = qobject_cast<Scene_polylines_item*>(scene->item(index));
if(lines_item != nullptr)
{
for(auto& polyline : lines_item->polylines)
{
for(auto it=std::begin(polyline), end=std::end(polyline); it!=end; ++it)
{
auto nit = std::next(it);
if(nit != end)
segments.emplace_back(*it, *nit);
}
}
continue;
}
// ---
Scene_points_with_normal_item* pts_item = qobject_cast<Scene_points_with_normal_item*>(scene->item(index));
if(pts_item != nullptr)
{
points.insert(std::cend(points),
std::cbegin(pts_item->point_set()->points()),
std::cend(pts_item->point_set()->points()));
continue;
}
}
const bool wrap_triangles = ui.wrapFaces->isChecked();
const bool wrap_segments = ui.wrapEdges->isChecked();
if(!wrap_triangles)
{
segments.reserve(segments.size() + 3 * triangles.size());
for(const auto& tr : triangles)
{
segments.emplace_back(tr[0], tr[1]);
segments.emplace_back(tr[1], tr[2]);
segments.emplace_back(tr[2], tr[0]);
}
}
if(!wrap_segments)
{
points.reserve(points.size() + 2 * segments.size());
for(const auto& s : segments)
{
points.push_back(s[0]);
points.push_back(s[1]);
}
}
std::cout << triangles.size() << " triangles" << std::endl;
std::cout << segments.size() << " edges" << std::endl;
std::cout << points.size() << " points" << std::endl;
std::cout << "do wrap edges/faces: " << wrap_segments << " " << wrap_triangles << std::endl;
if(wrap_triangles)
oracle.add_triangle_soup(triangles);
if(wrap_segments)
oracle.add_segment_soup(segments);
oracle.add_point_set(points);
if(!oracle.do_call())
{
print_message("Warning: empty input - nothing to wrap");
QApplication::restoreOverrideCursor();
return;
}
// Oracles set up, time to wrap
CGAL::Bbox_3 bbox = oracle.bbox();
const double diag_length = std::sqrt(CGAL::square(bbox.xmax() - bbox.xmin()) +
CGAL::square(bbox.ymax() - bbox.ymin()) +
@ -152,13 +512,18 @@ public Q_SLOTS:
CGAL::Alpha_wraps_3::internal::Alpha_wrap_3<Oracle> aw3(oracle);
Iterative_AW3_visualization_visitor visitor(scene,
visualize_iterations,
do_snapshot_iterations);
SMesh wrap;
aw3(alpha, offset, wrap,
CGAL::parameters::do_enforce_manifoldness(enforce_manifoldness));
CGAL::parameters::do_enforce_manifoldness(enforce_manifoldness)
.visitor(visitor));
Scene_surface_mesh_item* wrap_item = new Scene_surface_mesh_item(wrap);
wrap_item->setName(tr("Wrap alpha %2 offset %3").arg(alpha).arg(offset));
wrap_item->setColor(Qt::cyan);
wrap_item->setName(tr("Wrap with alpha %2 offset %3").arg(alpha).arg(offset));
wrap_item->setColor(Qt::gray);
scene->addItem(wrap_item);
QApplication::restoreOverrideCursor();

View File

@ -5,4 +5,4 @@ qt5_wrap_ui(alpha_wrap_3UI_FILES alpha_wrap_3_dialog.ui)
polyhedron_demo_plugin(alpha_wrap_3_plugin Alpha_wrap_3_plugin ${alpha_wrap_3UI_FILES})
#if the plugin uses external libraries like scene_items
target_link_libraries(alpha_wrap_3_plugin PUBLIC scene_surface_mesh_item scene_polygon_soup_item)
target_link_libraries(alpha_wrap_3_plugin PUBLIC scene_surface_mesh_item scene_polygon_soup_item scene_points_with_normal_item scene_selection_item scene_polylines_item)

View File

@ -9,58 +9,22 @@
<rect>
<x>0</x>
<y>0</y>
<width>532</width>
<height>280</height>
<width>646</width>
<height>673</height>
</rect>
</property>
<property name="windowTitle">
<string>2D Mesh Criteria</string>
<string>3D Alpha Wrapping</string>
</property>
<layout class="QGridLayout" name="gridLayout_2">
<item row="0" column="0">
<item row="1" column="0">
<widget class="QGroupBox" name="groupBox">
<property name="title">
<string>3D Alpha Wrapping</string>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="8" column="1">
<widget class="QCheckBox" name="runManifoldness">
<property name="text">
<string/>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
<item row="8" column="0">
<widget class="QLabel" name="runManifoldness_Label">
<property name="enabled">
<bool>true</bool>
</property>
<property name="text">
<string>Enforce 2-manifoldness</string>
</property>
<property name="alignment">
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="7" column="0">
<spacer name="verticalSpacer_2">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
<item row="5" column="1">
<widget class="QCheckBox" name="relativeOffset">
<item row="11" column="1">
<widget class="QCheckBox" name="wrapEdges">
<property name="text">
<string/>
</property>
@ -88,15 +52,21 @@
</property>
</widget>
</item>
<item row="5" column="0">
<widget class="QLabel" name="relativeOffset_Label">
<item row="15" column="0">
<widget class="QLabel" name="runManifoldness_Label">
<property name="enabled">
<bool>true</bool>
</property>
<property name="text">
<string>Use relative-to-bbox offset</string>
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Enforce 2-manifold output&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="alignment">
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="2" column="0">
<spacer name="verticalSpacer">
<item row="18" column="0">
<spacer name="verticalSpacer_7">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
@ -108,23 +78,69 @@
</property>
</spacer>
</item>
<item row="1" column="0">
<widget class="QLabel" name="relativeAlpha_Label">
<item row="0" column="0">
<widget class="QLabel" name="alphaValue_Label">
<property name="text">
<string>Use relative-to-bbox alpha</string>
<string>Alpha value:</string>
</property>
<property name="alignment">
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QCheckBox" name="relativeAlpha">
<property name="text">
<string/>
<item row="9" column="0">
<spacer name="verticalSpacer_3">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="checked">
<bool>true</bool>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
<item row="12" column="0">
<spacer name="verticalSpacer_6">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
<item row="19" column="0">
<widget class="QLabel" name="visualizeIterations_Label">
<property name="text">
<string>Visualize iterations</string>
</property>
</widget>
</item>
<item row="6" column="0">
<widget class="QLabel" name="relativeOffset_Label">
<property name="text">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Use relative-to-bbox offset&lt;br/&gt;&lt;span style=&quot; font-size:9pt;&quot;&gt;As ratio of the length of the bbox's diagonal&lt;br/&gt;(i.e., value &lt;/span&gt;&lt;span style=&quot; font-size:9pt; font-style:italic;&quot;&gt;x &lt;/span&gt;&lt;span style=&quot; font-size:9pt;&quot;&gt;means &lt;/span&gt;&lt;span style=&quot; font-size:9pt; font-style:italic;&quot;&gt;offset := bbox_diag_l / x)&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
</widget>
</item>
<item row="16" column="0">
<spacer name="verticalSpacer_4">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
<item row="4" column="1">
<widget class="QDoubleSpinBox" name="offsetValue">
<property name="decimals">
@ -144,25 +160,39 @@
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QLabel" name="alphaValue_Label">
<property name="text">
<string>Alpha value:</string>
</property>
<property name="alignment">
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
<item row="17" column="0" colspan="2">
<widget class="Line" name="line_4">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
<item row="4" column="0">
<widget class="QLabel" name="offsetValue_Label">
<item row="10" column="0">
<widget class="QLabel" name="wrapFaces_Label">
<property name="text">
<string>Offset value:</string>
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Wrap faces&lt;br/&gt;&lt;span style=&quot; font-size:9pt;&quot;&gt;If deactivated, only edges of the faces are taken into account&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
</widget>
</item>
<item row="6" column="0">
<spacer name="verticalSpacer_3">
<item row="11" column="0">
<widget class="QLabel" name="wrapEdges_Label">
<property name="text">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Wrap edges&lt;br/&gt;&lt;span style=&quot; font-size:9pt;&quot;&gt;If deactivated, only extremities of the edges are taken into account&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QCheckBox" name="relativeAlpha">
<property name="text">
<string/>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
<item row="7" column="0">
<spacer name="verticalSpacer_5">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
@ -174,10 +204,125 @@
</property>
</spacer>
</item>
<item row="1" column="0">
<widget class="QLabel" name="relativeAlpha_Label">
<property name="text">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Use relative-to-bbox alpha&lt;br/&gt;&lt;span style=&quot; font-size:9pt;&quot;&gt;As ratio of the length of the bbox's diagonal&lt;br/&gt;(i.e., value &lt;/span&gt;&lt;span style=&quot; font-size:9pt; font-style:italic;&quot;&gt;x &lt;/span&gt;&lt;span style=&quot; font-size:9pt;&quot;&gt;means alpha&lt;/span&gt;&lt;span style=&quot; font-size:9pt; font-style:italic;&quot;&gt; := bbox_diag_l / x)&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
</widget>
</item>
<item row="21" column="0">
<widget class="Line" name="line_3">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
</widget>
</item>
<item row="19" column="1">
<widget class="QCheckBox" name="visualizeIterations">
<property name="text">
<string/>
</property>
</widget>
</item>
<item row="10" column="1">
<widget class="QCheckBox" name="wrapFaces">
<property name="text">
<string/>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
<item row="2" column="0">
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
<item row="6" column="1">
<widget class="QCheckBox" name="relativeOffset">
<property name="text">
<string/>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
<item row="13" column="0" colspan="2">
<widget class="Line" name="line_2">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
<item row="4" column="0">
<widget class="QLabel" name="offsetValue_Label">
<property name="text">
<string>Offset value:</string>
</property>
</widget>
</item>
<item row="8" column="0" colspan="2">
<widget class="Line" name="line">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
<item row="15" column="1">
<widget class="QCheckBox" name="runManifoldness">
<property name="text">
<string/>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
<item row="14" column="0">
<spacer name="verticalSpacer_2">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
<item row="20" column="0">
<widget class="QLabel" name="snapshotIterations_Label">
<property name="text">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Snapshot iterations&lt;br/&gt;&lt;span style=&quot; font-size:9pt;&quot;&gt;For each iteration, save a snapshot of the viewer &lt;br/&gt;to a file named &lt;/span&gt;&lt;span style=&quot; font-size:9pt; font-style:italic;&quot;&gt;Wrap-iteration_i.png&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
</widget>
</item>
<item row="20" column="1">
<widget class="QCheckBox" name="snapshotIterations">
<property name="text">
<string/>
</property>
<property name="checkable">
<bool>false</bool>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item row="1" column="0">
<item row="2" column="0">
<widget class="QDialogButtonBox" name="buttonBox">
<property name="orientation">
<enum>Qt::Horizontal</enum>

View File

@ -62,7 +62,7 @@ public:
}
QString name() const override{ return "polylines_io_plugin"; }
QString nameFilters() const override{ return "Polylines files (*.polylines.txt *.cgal)"; }
QString nameFilters() const override{ return "Polylines files (*.polylines.txt);; CGAL Polylines files (*.cgal)"; }
bool canLoad(QFileInfo fileinfo) const override;
QList<Scene_item*> load(QFileInfo fileinfo, bool& ok, bool add_to_scene=true) override;

View File

@ -116,11 +116,7 @@ private:
boost::optional<DoubleConverter> fc;
Viewer_interface* viewer;
void getPixel(const QPoint& e) {
float data[3];
int vp[4];
viewer->glGetIntegerv(GL_VIEWPORT, vp);
viewer->glReadPixels(e.x(), vp[3] - e.y(), 1, 1, GL_RGB, GL_FLOAT, data);
const auto data = read_pixel_as_float_rgb(e, viewer, viewer->camera());
if(fc) {
Q_EMIT x(QString::number((*fc)(data[0]), 'f', 6 ));
} else if(ic) {

View File

@ -1049,11 +1049,7 @@ void Scene_edit_box_item_priv::picking(int& type, int& id, Viewer_interface *vie
viewer->setBackgroundColor(::Qt::white);
draw_picking(viewer);
int rowLength = deviceWidth * 4; // data asked in RGBA,so 4 bytes.
const static int dataLength = rowLength * deviceHeight;
GLubyte* buffer = new GLubyte[dataLength];
// Qt uses upper corner for its origin while GL uses the lower corner.
viewer->glReadPixels(picked_pixel.x(), deviceHeight-1-picked_pixel.y(), 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, buffer);
const auto buffer = read_pixel_as_ubyte_rgba(picked_pixel, viewer, viewer->camera());
//decode ID and pick (don't forget the case nothing is picked
if(!(buffer[0]==buffer[1] && buffer[1]==buffer[2]))
{
@ -1080,7 +1076,6 @@ void Scene_edit_box_item_priv::picking(int& type, int& id, Viewer_interface *vie
}
}
}
delete[] buffer;
viewer->setBackgroundColor(bgColor);
fbo->release();
delete fbo;

View File

@ -123,7 +123,7 @@ target_link_libraries(
PUBLIC scene_surface_mesh_item scene_polylines_item
scene_points_with_normal_item)
qt5_wrap_ui( repairUI_FILES RemoveNeedlesDialog.ui)
qt5_wrap_ui( repairUI_FILES RemoveNeedlesDialog.ui SelfSnapDialog.ui)
polyhedron_demo_plugin(repair_polyhedron_plugin Repair_polyhedron_plugin ${repairUI_FILES} KEYWORDS PMP)
target_link_libraries(repair_polyhedron_plugin PUBLIC scene_points_with_normal_item scene_surface_mesh_item)

View File

@ -9,6 +9,7 @@
#include <CGAL/Three/Polyhedron_demo_plugin_interface.h>
#include <CGAL/Polygon_mesh_processing/stitch_borders.h>
#include <CGAL/Polygon_mesh_processing/orientation.h>
#include <CGAL/boost/graph/split_graph_into_polylines.h>
#include <CGAL/boost/graph/helpers.h>
@ -26,8 +27,9 @@ class Polyhedron_demo_polyhedron_stitching_plugin :
QAction* actionDetectBorders;
QAction* actionStitchBorders;
QAction* actionStitchByCC;
QAction* actionMergeReversibleCCs;
public:
QList<QAction*> actions() const { return QList<QAction*>() << actionDetectBorders << actionStitchBorders << actionStitchByCC; }
QList<QAction*> actions() const { return QList<QAction*>() << actionDetectBorders << actionStitchBorders << actionStitchByCC << actionMergeReversibleCCs; }
void init(QMainWindow* mainWindow, CGAL::Three::Scene_interface* scene_interface, Messages_interface* /* m */)
{
scene = scene_interface;
@ -42,6 +44,10 @@ public:
actionStitchByCC->setObjectName("actionStitchByCC");
actionStitchByCC->setProperty("subMenuName", "Polygon Mesh Processing/Repair");
actionMergeReversibleCCs = new QAction(tr("Merge Reversible Connected Components"), mainWindow);
actionMergeReversibleCCs->setObjectName("actionMergeReversibleCCs");
actionMergeReversibleCCs->setProperty("subMenuName", "Polygon Mesh Processing/Repair");
autoConnectActions();
}
@ -63,10 +69,14 @@ public:
template <typename Item>
void on_actionStitchByCC_triggered(Scene_interface::Item_id index);
template <typename Item>
void on_actionMergeReversibleCCs_triggered(Scene_interface::Item_id index);
public Q_SLOTS:
void on_actionDetectBorders_triggered();
void on_actionStitchBorders_triggered();
void on_actionStitchByCC_triggered();
void on_actionMergeReversibleCCs_triggered();
}; // end Polyhedron_demo_polyhedron_stitching_plugin
@ -151,6 +161,19 @@ void Polyhedron_demo_polyhedron_stitching_plugin::on_actionStitchByCC_triggered(
scene->itemChanged(item);
}
template <typename Item>
void Polyhedron_demo_polyhedron_stitching_plugin::on_actionMergeReversibleCCs_triggered(Scene_interface::Item_id index)
{
Item* item =
qobject_cast<Item*>(scene->item(index));
if(!item)
return;
CGAL::Polygon_mesh_processing::merge_reversible_connected_components(*item->polyhedron());
CGAL::Polygon_mesh_processing::orient(*item->polyhedron());
item->invalidateOpenGLBuffers();
scene->itemChanged(item);
}
void Polyhedron_demo_polyhedron_stitching_plugin::on_actionStitchByCC_triggered()
{
@ -158,4 +181,11 @@ void Polyhedron_demo_polyhedron_stitching_plugin::on_actionStitchByCC_triggered(
on_actionStitchByCC_triggered<Scene_surface_mesh_item>(index);
}
}
void Polyhedron_demo_polyhedron_stitching_plugin::on_actionMergeReversibleCCs_triggered()
{
Q_FOREACH(int index, scene->selectionIndices()){
on_actionMergeReversibleCCs_triggered<Scene_surface_mesh_item>(index);
}
}
#include "Polyhedron_stitching_plugin.moc"

View File

@ -18,8 +18,10 @@
#include <CGAL/Polygon_mesh_processing/corefinement.h>
#include <CGAL/Polygon_mesh_processing/repair_degeneracies.h>
#include <CGAL/Polygon_mesh_processing/merge_border_vertices.h>
#include <CGAL/Polygon_mesh_processing/internal/Snapping/snap.h>
#include "ui_RemoveNeedlesDialog.h"
#include "ui_SelfSnapDialog.h"
#include <cmath>
#include <limits>
#include <vector>
@ -53,6 +55,7 @@ public:
actionAutorefine = new QAction(tr("Autorefine Mesh"), mw);
actionAutorefineAndRMSelfIntersections = new QAction(tr("Autorefine and Remove Self-Intersections"), mw);
actionRemoveNeedlesAndCaps = new QAction(tr("Remove Needles And Caps"));
actionSnapBorders = new QAction(tr("Snap Boundaries"));
actionRemoveIsolatedVertices->setObjectName("actionRemoveIsolatedVertices");
actionRemoveDegenerateFaces->setObjectName("actionRemoveDegenerateFaces");
@ -64,6 +67,7 @@ public:
actionAutorefine->setObjectName("actionAutorefine");
actionAutorefineAndRMSelfIntersections->setObjectName("actionAutorefineAndRMSelfIntersections");
actionRemoveNeedlesAndCaps->setObjectName("actionRemoveNeedlesAndCaps");
actionSnapBorders->setObjectName("actionSnapBorders");
actionRemoveDegenerateFaces->setProperty("subMenuName", "Polygon Mesh Processing/Repair/Experimental");
actionStitchCloseBorderHalfedges->setProperty("subMenuName", "Polygon Mesh Processing/Repair/Experimental");
@ -74,7 +78,7 @@ public:
actionMergeDuplicatedVerticesOnBoundaryCycles->setProperty("subMenuName", "Polygon Mesh Processing/Repair");
actionAutorefine->setProperty("subMenuName", "Polygon Mesh Processing/Repair/Experimental");
actionAutorefineAndRMSelfIntersections->setProperty("subMenuName", "Polygon Mesh Processing/Repair/Experimental");
actionRemoveNeedlesAndCaps->setProperty("subMenuName", "Polygon Mesh Processing/Repair/Experimental");
actionSnapBorders->setProperty("subMenuName", "Polygon Mesh Processing/Repair/Experimental");
autoConnectActions();
}
@ -90,7 +94,8 @@ public:
<< actionMergeDuplicatedVerticesOnBoundaryCycles
<< actionAutorefine
<< actionAutorefineAndRMSelfIntersections
<< actionRemoveNeedlesAndCaps;
<< actionRemoveNeedlesAndCaps
<< actionSnapBorders;
}
bool applicable(QAction*) const
@ -128,6 +133,7 @@ public Q_SLOTS:
void on_actionAutorefine_triggered();
void on_actionAutorefineAndRMSelfIntersections_triggered();
void on_actionRemoveNeedlesAndCaps_triggered();
void on_actionSnapBorders_triggered();
private:
QAction* actionRemoveIsolatedVertices;
@ -140,6 +146,7 @@ private:
QAction* actionAutorefine;
QAction* actionAutorefineAndRMSelfIntersections;
QAction* actionRemoveNeedlesAndCaps;
QAction* actionSnapBorders;
Messages_interface* messages;
}; // end Polyhedron_demo_repair_polyhedron_plugin
@ -196,6 +203,148 @@ void Polyhedron_demo_repair_polyhedron_plugin::on_actionRemoveNeedlesAndCaps_tri
sm_item->itemChanged();
}
void Polyhedron_demo_repair_polyhedron_plugin::on_actionSnapBorders_triggered()
{
const Scene_interface::Item_id index = scene->mainSelectionIndex();
Scene_surface_mesh_item* sm_item = qobject_cast<Scene_surface_mesh_item*>(scene->item(index));
if(!sm_item)
{
return;
}
QDialog dialog;
Ui::SelfSnapDialog ui;
ui.setupUi(&dialog);
connect(ui.use_local_tolerance, SIGNAL(toggled(bool)),
ui.tolerances, SLOT(setDisabled(bool)));
if(dialog.exec() != QDialog::Accepted)
return;
QCursor tmp_cursor(Qt::WaitCursor);
CGAL::Three::Three::CursorScopeGuard guard(tmp_cursor);
typedef Scene_surface_mesh_item::Face_graph Face_graph;
Face_graph& tm = *sm_item->face_graph();
typedef boost::graph_traits<Face_graph>::halfedge_descriptor halfedge_descriptor;
typedef boost::graph_traits<Face_graph>::vertex_descriptor vertex_descriptor;
CGAL::Polygon_mesh_processing::stitch_borders(tm);
#if 1
/// detection of non-manifold parts
std::map< std::pair<Kernel::Point_3, Kernel::Point_3>, std::vector<halfedge_descriptor> > edges;
for(halfedge_descriptor h : halfedges(tm))
{
if (is_border(h,tm))
edges[CGAL::make_sorted_pair(tm.point(target(h,tm)), tm.point(source(h,tm)))].push_back(h);
}
std::vector<int> fccs(num_faces(tm),-1);
int nbcc = CGAL::Polygon_mesh_processing::connected_components(tm, CGAL::make_property_map(fccs));
//this has to be done per cycle so as to keep 2 patches
// remove the smallest CCs
std::vector<int> cc_sizes(nbcc, 0);
for(int i : fccs)
cc_sizes[i]+=1;
std::set<int> ccs_to_rm;
for (auto p : edges)
if (p.second.size() >= 2)
for(halfedge_descriptor h : p.second)
{
int ccid = fccs[face(opposite(h, tm),tm)];
if ( cc_sizes[ccid]<=4 )
ccs_to_rm.insert(ccid);
}
std::cout << "removing " << ccs_to_rm.size() << " ccs\n";
CGAL::Polygon_mesh_processing::remove_connected_components(tm, ccs_to_rm, CGAL::make_property_map(fccs));
std::cout << "input is valid after cc removal:"<< CGAL::is_valid_polygon_mesh(tm) << "\n";
///
#endif
if (ui.use_local_tolerance->isChecked())
{
CGAL::Polygon_mesh_processing::experimental::snap_borders(tm, CGAL::parameters::do_simplify_border(ui.do_simplify_border->isChecked()));
CGAL::Polygon_mesh_processing::stitch_borders(tm);
CGAL::Polygon_mesh_processing::duplicate_non_manifold_vertices(tm);
}
else
{
std::vector<double> tolerances/* = 0.005, 0.0125, 0.025, 0.05, 0.07 */;
bool ok;
Q_FOREACH(QString tol_text, ui.tolerances->text().split(","))
{
double d = tol_text.toDouble(&ok);
if (ok)
tolerances.push_back(d);
else
QMessageBox(QMessageBox::Warning,
QString("Invalid value"),
QString("\""+tol_text+"\" is not a valid double, ignored."),
QMessageBox::Ok,
this->mw).exec();
}
for (double tol : tolerances )
{
std::cout << "using tol = " << tol << "\n";
CGAL::Constant_property_map<vertex_descriptor, double> tolerance_map(tol);
CGAL::Polygon_mesh_processing::experimental::snap_borders(tm, tolerance_map, CGAL::parameters::do_simplify_border(ui.do_simplify_border->isChecked()));
CGAL::Polygon_mesh_processing::stitch_borders(tm);
CGAL::Polygon_mesh_processing::duplicate_non_manifold_vertices(tm);
// post processing
std::vector<halfedge_descriptor> remaining_cycles;
CGAL::Polygon_mesh_processing::extract_boundary_cycles(tm, std::back_inserter(remaining_cycles));
int tested=0, done=0;
for (halfedge_descriptor hc : remaining_cycles)
{
if (next(next(hc,tm),tm)==prev(hc,tm))
{
++tested;
//get smallest halfedge
halfedge_descriptor hm = hc;
double min_l = CGAL::Polygon_mesh_processing::edge_length(hc, tm);
double el = CGAL::Polygon_mesh_processing::edge_length(next(hc, tm), tm);
if (el<min_l)
{
min_l=el;
hm=next(hc, tm);
}
el = CGAL::Polygon_mesh_processing::edge_length(prev(hc, tm), tm);
if (el<min_l)
{
min_l=el;
hm=prev(hc, tm);
}
if (el>tol)
continue;
if (!CGAL::Euler::does_satisfy_link_condition(edge(hm, tm), tm))
{
// simply fill the face
std::array<vertex_descriptor,3> vr = { source(hm, tm), target(hm, tm), target(next(hm, tm), tm) };
CGAL::Euler::add_face(vr, tm);
continue;
}
std::array<vertex_descriptor,3> vr = { source(hm, tm), target(hm, tm), target(next(hm, tm), tm) };
CGAL::Euler::add_face(vr, tm);
CGAL::Euler::collapse_edge(edge(hm, tm), tm);
++done;
}
}
}
}
CGAL::Polygon_mesh_processing::duplicate_non_manifold_vertices(tm);
sm_item->invalidateOpenGLBuffers();
sm_item->itemChanged();
}
template <typename Item>
void Polyhedron_demo_repair_polyhedron_plugin::on_actionRemoveDegenerateFaces_triggered(Scene_interface::Item_id index)
{
@ -231,7 +380,7 @@ void Polyhedron_demo_repair_polyhedron_plugin::on_actionRemoveSelfIntersections_
{
bool solved =
CGAL::Polygon_mesh_processing::experimental::remove_self_intersections(
*poly_item->polyhedron());
*poly_item->polyhedron(), CGAL::parameters::preserve_genus(false));
if (!solved)
CGAL::Three::Three::information(tr("Some self-intersection could not be fixed"));
poly_item->invalidateOpenGLBuffers();

View File

@ -0,0 +1,91 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>SelfSnapDialog</class>
<widget class="QDialog" name="SelfSnapDialog">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>413</width>
<height>179</height>
</rect>
</property>
<property name="windowTitle">
<string>Dialog</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QCheckBox" name="use_local_tolerance">
<property name="text">
<string>Use Local Tolerance</string>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="label">
<property name="text">
<string>Fixed Snapping (comma separate values for several runs):</string>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="tolerances"/>
</item>
<item>
<widget class="QCheckBox" name="do_simplify_border">
<property name="text">
<string>Collapse Edges Before Snap</string>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QDialogButtonBox" name="buttonBox">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="standardButtons">
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
</property>
</widget>
</item>
</layout>
</widget>
<resources/>
<connections>
<connection>
<sender>buttonBox</sender>
<signal>accepted()</signal>
<receiver>SelfSnapDialog</receiver>
<slot>accept()</slot>
<hints>
<hint type="sourcelabel">
<x>248</x>
<y>254</y>
</hint>
<hint type="destinationlabel">
<x>157</x>
<y>274</y>
</hint>
</hints>
</connection>
<connection>
<sender>buttonBox</sender>
<signal>rejected()</signal>
<receiver>SelfSnapDialog</receiver>
<slot>reject()</slot>
<hints>
<hint type="sourcelabel">
<x>316</x>
<y>260</y>
</hint>
<hint type="destinationlabel">
<x>286</x>
<y>274</y>
</hint>
</hints>
</connection>
</connections>
</ui>

View File

@ -564,9 +564,8 @@ void Scene::renderScene(const QList<Scene_interface::Item_id> &items,
if(with_names) {
// read depth buffer at pick location;
float depth = 1.0;
viewer->glReadPixels(picked_pixel.x(),viewer->camera()->screenHeight()-1-picked_pixel.y(),1,1,GL_DEPTH_COMPONENT, GL_FLOAT, &depth);
if (depth != 1.0)
float depth = read_depth_under_pixel(picked_pixel, viewer, viewer->camera());
if (depth < 2.0)
{
//add object to list of picked objects;
picked_item_IDs[depth] = index;
@ -635,7 +634,7 @@ void Scene::renderWireScene(const QList<Scene_interface::Item_id> &items,
// read depth buffer at pick location;
float depth = 1.0;
viewer->glReadPixels(picked_pixel.x(),viewer->camera()->screenHeight()-1-picked_pixel.y(),1,1,GL_DEPTH_COMPONENT, GL_FLOAT, &depth);
depth = read_depth_under_pixel(picked_pixel, viewer, viewer->camera());
if (depth != 1.0)
{
//add object to list of picked objects;
@ -677,7 +676,7 @@ void Scene::renderPointScene(const QList<Scene_interface::Item_id> &items,
if(item.renderingMode() == Points && with_names) {
// read depth buffer at pick location;
float depth = 1.0;
viewer->glReadPixels(picked_pixel.x(),viewer->camera()->screenHeight()-1-picked_pixel.y(),1,1,GL_DEPTH_COMPONENT, GL_FLOAT, &depth);
depth = read_depth_under_pixel(picked_pixel, viewer, viewer->camera());
if (depth != 1.0)
{
//add object to list of picked objects;

View File

@ -211,7 +211,7 @@ void Scene_group_item::renderChildren(Viewer_interface *viewer,
if(with_names) {
// read depth buffer at pick location;
float depth = 1.0;
viewer->glReadPixels(picked_pixel.x(),viewer->camera()->screenHeight()-1-picked_pixel.y(),1,1,GL_DEPTH_COMPONENT, GL_FLOAT, &depth);
depth = read_depth_under_pixel(picked_pixel, viewer, viewer->camera());
if (depth != 1.0)
{
//add object to list of picked objects;

View File

@ -187,8 +187,6 @@ void Scene_spheres_item::draw(Viewer_interface *viewer) const
setBuffersFilled(true);
setBuffersInit(viewer, true);
}
int deviceWidth = viewer->camera()->screenWidth();
int deviceHeight = viewer->camera()->screenHeight();
if(d->has_plane)
{
QVector4D cp = cgal_plane_to_vector4d(d->plane);
@ -207,12 +205,8 @@ void Scene_spheres_item::draw(Viewer_interface *viewer) const
}
if(d->pickable && (d->spheres.size() > 1 && viewer->inDrawWithNames()))
{
int rowLength = deviceWidth * 4; // data asked in RGBA,so 4 bytes.
const static int dataLength = rowLength * deviceHeight;
GLubyte* buffer = new GLubyte[dataLength];
// Qt uses upper corner for its origin while GL uses the lower corner.
QPoint picking_target = viewer->mapFromGlobal(QCursor::pos());
viewer->glReadPixels(picking_target.x(), deviceHeight-1-picking_target.y(), 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, buffer);
const auto buffer = read_pixel_as_ubyte_rgba(picking_target, viewer, viewer->camera());
int ID = (buffer[0] + buffer[1] * 256 +buffer[2] * 256*256) ;
if(buffer[0]*buffer[1]*buffer[2] < 255*255*255)
{

View File

@ -1448,10 +1448,10 @@ public:
/// Erases the small connected components and the isolated vertices.
///
/// @commentheading Preconditions:
/// supports vertices, halfedges, and removal operation.
///
/// @commentheading Template Parameters:
/// \pre supports vertices, halfedges, and removal operation.
///
/// *Parameters*
/// @param nb_components_to_keep the number of large connected components to keep.
///
/// @return the number of connected components erased (ignoring isolated vertices).

View File

@ -397,7 +397,7 @@ void MainWindow::loadWKT(QString fileName)
m_pct.insert_constraint(poly.begin(), poly.end());
}
}
for(Polygon_with_holes_2 poly : polygons){
for(const Polygon_with_holes_2& poly : polygons){
m_pct.insert_constraint(poly.outer_boundary().vertices_begin(), poly.outer_boundary().vertices_end());
for(Polygon_with_holes_2::Hole_const_iterator it = poly.holes_begin(); it != poly.holes_end(); ++it){
const Polygon_2& hole = *it;

View File

@ -1,7 +1,5 @@
#include <iostream>
#include <fstream>
#include <boost/config.hpp>
#include <boost/version.hpp>
#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
#include <CGAL/Polygon_2.h>
@ -74,5 +72,3 @@ int main(int argc, char* argv[])
print(ct, cid);
return 0;
}

View File

@ -1,6 +1,3 @@
#include <boost/config.hpp>
#include <boost/version.hpp>
#include <iostream>
#include <fstream>
#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
@ -56,4 +53,3 @@ int main(int argc, char* argv[])
}
return 0;
}

View File

@ -1,5 +1,3 @@
#include <boost/config.hpp>
#include <boost/version.hpp>
#include <iostream>
#include <fstream>
#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>

Some files were not shown because too many files have changed in this diff Show More