Merge remote-tracking branch 'upstream/master' into feature/issue_7395

This commit is contained in:
albert-github 2023-07-17 10:17:34 +02:00
commit de3ba0f47c
62 changed files with 14814 additions and 14197 deletions

View File

@ -39,6 +39,7 @@ if(GMP_FOUND)
create_single_source_cgal_program("Arithmetic_kernel.cpp")
create_single_source_cgal_program("LEDA_arithmetic_kernel.cpp")
create_single_source_cgal_program("CORE_arithmetic_kernel.cpp")
create_single_source_cgal_program("GMPXX_arithmetic_kernel.cpp")
create_single_source_cgal_program("Get_arithmetic_kernel.cpp")
else()

View File

@ -9,7 +9,7 @@ find_package(CGAL REQUIRED)
# create a target per cppfile
file(
GLOB_RECURSE cppfiles
GLOB cppfiles
RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}
*.cpp)
foreach(cppfile ${cppfiles})

View File

@ -1,125 +0,0 @@
#define BOOST_TEST_MODULE graph_traits test
#include <boost/test/unit_test.hpp>
#include <boost/test/floating_point_comparison.hpp>
BOOST_AUTO_TEST_CASE( edges_test )
{
edge_iterator eb, ee;
vertex_iterator vb, ve;
Surface_fixture f;
boost::tie(eb, ee) = edges(f.m);
boost::tie(vb, ve) = vertices(f.m);
BOOST_CHECK(std::distance(eb, ee) == 7);
BOOST_CHECK(std::distance(vb, ve) == 5);
Cube_fixture cf;
boost::tie(eb, ee) = edges(cf.m);
boost::tie(vb, ve) = vertices(cf.m);
BOOST_CHECK(std::distance(eb, ee) == 18);
BOOST_CHECK(std::distance(vb, ve) == 8);
}
BOOST_AUTO_TEST_CASE( out_edges_test )
{
Surface_fixture f;
BOOST_CHECK(out_degree(f.u, f.m) == 2);
BOOST_CHECK(out_degree(f.v, f.m) == 4);
std::pair<out_edge_iterator, out_edge_iterator> out = out_edges(f.v, f.m);
BOOST_CHECK(std::distance(out.first, out.second) == 4);
out_edge_iterator it = out.first;
while(it != out.second) {
// the source should always be u
BOOST_CHECK(source(*it, f.m) == f.v);
// the target never
BOOST_CHECK(target(*it, f.m) != f.v);
++it;
}
}
BOOST_AUTO_TEST_CASE( in_edges_test )
{
Surface_fixture f;
BOOST_CHECK(in_degree(f.u, f.m) == 2);
BOOST_CHECK(in_degree(f.x, f.m) == 3);
BOOST_CHECK(in_degree(f.v, f.m) == 4);
std::pair<in_edge_iterator, in_edge_iterator> in = in_edges(f.v, f.m);
BOOST_CHECK(std::distance(in.first, in.second) == 4);
in_edge_iterator it = in.first;
while(it != in.second) {
// the source should never be u
BOOST_CHECK(source(*it, f.m) != f.v);
// the target must always be u
BOOST_CHECK(target(*it, f.m) == f.v);
++it;
}
}
BOOST_AUTO_TEST_CASE( in_out_equality )
{
// in and out degrees must be equal for each vertex
Cube_fixture f;
for(Sm::Vertex_iterator it = f.m.vertices_begin();
it != f.m.vertices_end(); ++it) {
BOOST_CHECK(in_degree(*it, f.m) == out_degree(*it, f.m));
}
}
BOOST_AUTO_TEST_CASE( face_test )
{
Surface_fixture f;
std::pair<enclosure_iterator, enclosure_iterator>
enc = enclosure(f.f1, f.m);
BOOST_CHECK(enc.first != enc.second);
BOOST_CHECK(std::distance(enc.first, enc.second) == 3);
enclosure_iterator begin = enc.first;
while(begin != enc.second)
{
BOOST_CHECK(face(*begin, f.m) == f.f1);
++begin;
}
}
BOOST_AUTO_TEST_CASE( weight_map_test )
{
Surface_fixture f;
Cube_fixture c;
CGAL::SM_edge_weight_pmap<K> wm1 = boost::get(boost::edge_weight, c.m);
edge_iterator eb, ee;
boost::test_tools::check_is_close_t check_close;
for(boost::tie(eb, ee) = edges(c.m); eb != ee; ++eb) {
BOOST_CHECK(
check_close(wm1[*eb], 2.0, boost::test_tools::percent_tolerance_t<double>(0.00001))
|| check_close(wm1[*eb], 2.82843, boost::test_tools::percent_tolerance_t<double>(0.001)));
}
}
BOOST_AUTO_TEST_CASE( vertices_test )
{
Surface_fixture f;
// boost::property_map<Sm,boost::vertex_index_t>::type vi_map = get(f.m, boost::vertex_index);
// vertex_iterator b,e;
// for(boost::tie(b,e) = vertices(f.m);
// b!= e;
// ++b){
// std::cout << boost::get(vi_map, *(b)) << std::endl;
// }
// boost::property_map<Sm,boost::edge_weight_t>::type ew_map = get(f.m, boost::edge_weight);
// edge_iterator be, ee;
// for(boost::tie(be,ee) = edges(f.m);
// be!= ee;
// ++be){
// std::cout << boost::get(ew_map, *(be)) << std::endl;
// }
}

View File

@ -21,18 +21,18 @@ int main()
SM sm_in, sm_out;
Point_3 p0(0,0,0), p1(1,0,0), p2(0,1,0);
CGAL::make_triangle(p0, p1, p2, sm_out);
bool ok = CGAL::write_off("tmp.off", sm_out);
bool ok = CGAL::write_off("tmp_deprecated.off", sm_out);
assert(ok);
ok = CGAL::read_off("tmp.off", sm_in);
ok = CGAL::read_off("tmp_deprecated.off", sm_in);
assert(ok);
assert(num_vertices(sm_in) == 3 && num_faces(sm_in) == 1);
sm_in.clear();
std::ofstream os("tmp.off");
std::ofstream os("tmp_deprecated.off");
ok = CGAL::write_off(os, sm_out);
assert(ok);
os.close();
std::ifstream is("tmp.off");
std::ifstream is("tmp_deprecated.off");
ok = CGAL::read_off(is, sm_in);
assert(ok);
assert(num_vertices(sm_in) == 3 && num_faces(sm_in) == 1);
@ -40,18 +40,18 @@ int main()
sm_in.clear();
#ifdef CGAL_USE_VTK
//vtk
os.open("tmp.vtp");
os.open("tmp_deprecated.vtp");
ok = CGAL::write_vtp(os, sm_out);
assert(ok);
os.close();
ok = CGAL::IO::read_VTP("tmp.vtp", sm_in);
ok = CGAL::IO::read_VTP("tmp_deprecated.vtp", sm_in);
assert(ok);
assert(num_vertices(sm_in) == 3 && num_faces(sm_in) == 1);
sm_in.clear();
#endif
//wrl
os.open("tmp.wrl");
os.open("tmp_deprecated.wrl");
ok = CGAL::write_wrl(os, sm_out);
assert(ok);
os.close();

View File

@ -16,6 +16,7 @@
#include <map>
#include <memory>
#include <CGAL/assertions.h>
#define CGAL_CLASSIFICATION_IMAGE_SIZE_LIMIT 100000000
@ -38,12 +39,15 @@ class Image
std::shared_ptr<Map> m_sparse;
Type m_default;
// Forbid using copy constructor
Image (const Image&)
{
}
public:
// Forbid using copy constructor
// Make it public for a strange VC++ std17 boost-1_82 error
// https://github.com/boostorg/core/issues/148
Image(const Image&)
{
CGAL_assertion(false);
}
Image () : m_width(0), m_height(0), m_depth(0)
{

View File

@ -241,6 +241,18 @@ else()
"#EXTRACT_ALL_NO_DETAILED_IF_EMPTY = NO")
endif()
option(CGAL_NO_ADDITIONAL_DETAILS
"Use CGAL special doxygen setting NO_ADDITIONAL_DETAILS." ON)
if(CGAL_NO_ADDITIONAL_DETAILS)
set(CGAL_OPT_NO_ADDITIONAL_DETAILS
"NO_ADDITIONAL_DETAILS = YES")
else()
# The default is NO, so we could leave it out, but it is better to have a commented out placeholder
# this will work for versions with and without the setting.
set(CGAL_OPT_NO_ADDITIONAL_DETAILS
"#NO_ADDITIONAL_DETAILS = NO")
endif()
#we use two directories for the generation/reading of tag files to prevent issues
#if the targets are built in parallel
set(CGAL_DOC_TAG_GEN_DIR "${CMAKE_BINARY_DIR}/doc_gen_tags")

View File

@ -276,7 +276,7 @@ EXTRACT_ALL = YES
# the EXTRACT_ALL tag is set to NO.
# The default value is: NO.
EXTRACT_ALL_NO_DETAILED_IF_EMPTY = YES
${CGAL_OPT_EXTRACT_ALL_NO_DETAILED_IF_EMPTY}
# If the EXTRACT_STATIC tag is set to YES, all static members of a file will be
# included in the documentation.

View File

@ -805,5 +805,5 @@ GENERATE_LEGEND = NO
# NO_ADDITIONAL_DETAILS tag is set to YES. This tag has no effect if
# the EXTRACT_ALL tag is set to NO.
# The default value is: NO.
NO_ADDITIONAL_DETAILS = YES
${CGAL_OPT_NO_ADDITIONAL_DETAILS}

View File

@ -14,6 +14,7 @@ create_single_source_cgal_program(Linear_cell_complex_2_test.cpp ${hfiles})
create_single_source_cgal_program(Linear_cell_complex_3_test.cpp ${hfiles})
create_single_source_cgal_program(Linear_cell_complex_4_test.cpp ${hfiles})
create_single_source_cgal_program(Linear_cell_complex_copy_test.cpp ${hfiles})
create_single_source_cgal_program(LCC_3_incremental_builder_test.cpp ${hfiles})
# Same targets, defining USE_COMPACT_CONTAINER_WITH_INDEX to test index version
add_executable(Linear_cell_complex_2_test_index Linear_cell_complex_2_test.cpp ${hfiles})

View File

@ -42,12 +42,12 @@ printf "Copy documentation to doc_html/ and doc_html_online/...\n"
[ -d "/srv/CGAL/www/${PUBLIC_RELEASE_NAME#CGAL-}/Manual" ] || mkdir -p "/srv/CGAL/www/${PUBLIC_RELEASE_NAME#CGAL-}/Manual"
cp "$PUBLIC_RELEASE_DIR"/*(.) "${RELEASE_CANDIDATES_DIR}/$PUBLIC_RELEASE_NAME"
files=("$MANUAL_TESTS_DIR/$INTERNAL_RELEASE"/output2/*)
files=("$MANUAL_TESTS_DIR/$INTERNAL_RELEASE"/output1/*)
if ((${#files[@]} == 0)); then
printf "ERROR: documentation files are missing\n"
error_code=1
else
rsync -a --exclude xml "$MANUAL_TESTS_DIR/$INTERNAL_RELEASE"/output2/* "$DEST_DIR/doc_html/"
rsync -a --exclude xml "$MANUAL_TESTS_DIR/$INTERNAL_RELEASE"/output1/* "$DEST_DIR/doc_html/"
pushd "$DEST_DIR/doc_html/Manual/search"
for i in g n c s i; do sed -i "s/..\/BGL$i/..\/BGL\/$i/g" *; done
popd

View File

@ -49,6 +49,9 @@ target_link_libraries(mesh_hybrid_mesh_domain PUBLIC CGAL::Eigen3_support)
create_single_source_cgal_program("mesh_implicit_sphere.cpp")
target_link_libraries(mesh_implicit_sphere PUBLIC CGAL::Eigen3_support)
create_single_source_cgal_program("mesh_implicit_ellipsoid.cpp")
target_link_libraries(mesh_implicit_ellipsoid PUBLIC CGAL::Eigen3_support)
create_single_source_cgal_program("mesh_implicit_sphere_variable_size.cpp")
target_link_libraries(mesh_implicit_sphere_variable_size PUBLIC CGAL::Eigen3_support)

View File

@ -1,303 +0,0 @@
///////////////// Code for functions of famous surfaces /////////////////
// Sphere (r=1)
double sphere_function (double x, double y, double z) {
double x2=x*x, y2=y*y, z2=z*z;
return x2+y2+z2-1;
}
// Ellipsoid (r=1)
double ellipsoid_function (double x, double y, double z) {
double x2=x*x, y2=y*y, z2=z*z;
return x2+2*y2+4*z2-1;
}
// Torus (r=2)
double torus_function (double x, double y, double z) {
double x2=x*x, y2=y*y, z2=z*z;
double x4=x2*x2, y4=y2*y2, z4=z2*z2;
return x4 + y4 + z4 + 2 *x2* y2 + 2*
x2*z2 + 2*y2* z2 - 5 *x2 + 4* y2 - 5*z2+4;
}
// "Chair" (r=6)
double chair_function (double x, double y, double z) {
double x2=x*x, y2=y*y, z2=z*z;
double x4=x2*x2, y4=y2*y2, z4=z2*z2;
return x4-1.2*x2*y2+3.6*x2*z2-7.50*x2+y4+3.6*y2*z2-7.50*y2+.2*z4-7.50*z2+64.0625-16.0*z*y2+16.0*x2*z;
}
// "Tanglecube" (r=4)
double tanglecube_function (double x, double y, double z) {
double x2=x*x, y2=y*y, z2=z*z;
double x4=x2*x2, y4=y2*y2, z4=z2*z2;
return x4 - 5*x2 + y4 - 5*y2 + z4 - 5*z2 + 11.8;
}
double cube_function (double x, double y, double z){
if( x < 1 && -x < 1 &&
y < 1 && -y < 1 &&
z < 1 && -z < 1 )
return -1.;
return 1.;
}
// Barth's octic surface (degree 8)
double octic_function (double x, double y, double z) { // r=2
double x2=x*x, y2=y*y, z2=z*z;
double x4=x2*x2, y4=y2*y2, z4=z2*z2;
double x6=x4*x2, y6=y4*y2, z6=z4*z2;
double x8=x4*x4, y8=y4*y4, z8=z4*z4;
return 43.30495169 *x2* y2 + 43.30495169 *x2* z2 + 43.30495169 *y2 * z2 + 44.36067980 *x6* y2 + 44.36067980* x6 * z2 + 66.54101970* x4* y4 + 66.54101970* x4 * z4 + 44.36067980 *x2 * y6 - 11.70820393* x2 - 11.70820393* y2 - 11.70820393* z2 + 37.65247585 *x4 + 37.65247585 *y4 + 37.65247585* z4 + 11.09016995* x8 + 11.09016995 *y8 + 11.09016995* z8 + 133.0820394 *x2* y4* z2 + 133.0820394 *x2 * y2 * z4 + 44.36067980* x2 * z6 + 44.36067980 *y6 * z2 + 66.54101970 *y4 * z4 + 44.36067980 *y2 * z6 + 133.0820394* x4* y2 * z2 - 91.95742756 *x4 * y2 - 91.95742756 *x4 *z2 - 91.95742756* x2 * y4 - 91.95742756 *x2 *z4 - 91.95742756* y4 * z2 - 183.9148551* x2 *y2 *z2 - 30.65247585 *x6 - 30.65247585* y6 - 91.95742756 *y2 * z4 - 30.65247585* z6 + 1.618033988;
}
// "Heart"
double heart_function (double x, double y, double z) { // radius = 2
return (2*x*x+y*y+z*z-1)*(2*x*x+y*y+z*z-1)*(2*x*x+y*y+z*z-1) - (0.1*x*x+y*y)*z*z*z;
}
// Klein's bottle
double klein_function (double x, double y, double z) { // radius = 4
return (x*x+y*y+z*z+2*y-1)*((x*x+y*y+z*z-2*y-1)*(x*x+y*y+z*z-2*y-1)-8*z*z)+16*x*z*(x*x+y*y+z*z-2*y-1);
}
// Ring
double ring_function (double x, double y, double z) { // radius = ?
double e=0.1;
double f1 = x*x+y*y+z*z-1;
double f2 = x;
f1 = f1*f1-e*e;
f2 = f2*f2-e*e;
if (f1 < 0 && f2 < 0)
return -1.;
else if (f1 > 0 || f2 > 0)
return 1.;
else
return 0.;
}
// False knot
double false_knot_function (double x, double y, double z) { // radius = 1
double d=1.2, e=0.1;
double f1 = x*(x*x-z*z)-2*x*z*z-y*y+d*d-x*x-z*z-y*y;
double m2 = z*(x*x-z*z)+2*x*x*z;
double f2 = 4*y*y*(d*d-x*x-z*z-y*y) - m2*m2;
f1 = f1*f1-e*e;
f2 = f2*f2-e*e;
if (f1 < 0 && f2 < 0)
return -1.;
else if (f1 > 0 || f2 > 0)
return 1.;
else
return 0.;
}
// Knot 1
void puiss(double& x, double& y, int n) {
double xx = 1, yy = 0;
while(n>0) {
if (n&1) {
double xxx = xx, yyy = yy;
xx = xxx*x - yyy*y;
yy = xxx*y + yyy*x;
}
double xxx = x, yyy = y;
x=xxx*xxx-yyy*yyy;
y=2*xxx*yyy;
n/=2;
}
x = xx;
y = yy;
}
double knot1_function (double a, double b, double c) { // radius = 4
double e=0.1;
double x, y, z, t, den;
den=1+a*a+b*b+c*c;
x=2*a/den;
y=2*b/den;
z=2*c/den;
t=(1-a*a-b*b-c*c)/den;
double x3=x, y3=y, z2=z, t2=t;
puiss(x3,y3,3);
puiss(z2,t2,2);
double f1 = z2-x3;
double f2 = t2-y3;
f1 = f1*f1;
f2 = f2*f2;
e=e*e/(den-1);
if (f1+f2-e < 0)
return -1.;
else if (f1+f2-e > 0)
return 1.;
else
return 0.;
}
/*
double knot1_function (double x, double y, double z) { // radius = 4
double e=0.1;
double c1, c2, c3, c4, den;
den=1+x*x+y*y+z*z;
c1=2*x/den;
c2=2*y/den;
c3=2*z/den;
c4=(1-x*x-y*y-z*z)/den;
double f1 = c1*(c1*c1-c2*c2)-2*c1*c2*c2-c3*c3+c4*c4;
double f2 = c2*(c1*c1-c2*c2)+2*c1*c1*c2-2*c3*c4;
f1 = f1*f1;
f2 = f2*f2;
e=e*e/(den-1);
if (f1+f2-e < 0)
return -1.;
else if (f1+f2-e > 0)
return 1.;
else
return 0.;
}
*/
double knot1_surf1_function (double x, double y, double z) { // radius = 4
double c1, c2, c3, c4, den;
den=1+x*x+y*y+z*z;
c1=2*x/den;
c2=2*y/den;
c3=2*z/den;
c4=(1-x*x-y*y-z*z)/den;
return c1*(c1*c1-c2*c2)-2*c1*c2*c2-c3*c3+c4*c4;
}
double knot1_surf2_function (double x, double y, double z) { // radius = 4
double c1, c2, c3, c4, den;
den=1+x*x+y*y+z*z;
c1=2*x/den;
c2=2*y/den;
c3=2*z/den;
c4=(1-x*x-y*y-z*z)/den;
return c2*(c1*c1-c2*c2)+2*c1*c1*c2-2*c3*c4;
}
// Knot 2
double knot2_function (double a, double b, double c) { // radius = 4
double e=0.025;
double x, y, z, t, den;
den=1+a*a+b*b+c*c;
x=2*a/den;
y=2*b/den;
z=2*c/den;
t=(1-a*a-b*b-c*c)/den;
double x7=x, y7=y, x13=x, y13=y;
puiss(x7,y7,7);
puiss(x13,y13,13);
double z3=z, t3=t;
puiss(z3,t3,3);
double f1t = (z3-x7)*(z3-x7+100*x13) - (t3-y7)*(t3-y7+100*y13);
double f2t = (z3-x7)*(t3-y7+100*y13) + (t3-y7)*(z3-x7+100*x13);
double f1 = f1t*(z3-x7-100*x13) - f2t*(t3-y7-100*y13);
double f2 = f1t*(t3-y7-100*y13) + f2t*(z3-x7-100*x13);
f1 = f1*f1;
f2 = f2*f2;
e=e*e/(den-1);
if (f1+f2-e < 0)
return -1.;
else if (f1+f2-e > 0)
return 1.;
else
return 0.;
}
// Knot 3
double knot3_function (double a, double b, double c) { // radius = 4
double e=0.025;
double x, y, z, t, den;
den=1+a*a+b*b+c*c;
x=2*a/den;
y=2*b/den;
z=2*c/den;
t=(1-a*a-b*b-c*c)/den;
double x19=x, y19=y, z17=z, t17=t;
puiss(x19,y19,19);
puiss(z17,t17,17);
double f1 = z17-x19;
double f2 = t17-y19;
f1 = f1*f1;
f2 = f2*f2;
e=e*e/(den-1);
if (f1+f2-e < 0)
return -1.;
else if (f1+f2-e > 0)
return 1.;
else
return 0.;
}

View File

@ -1,36 +0,0 @@
///////////////// Definitions of several famous surfaces /////////////////
double sphere_function (double, double, double); // (c=(0,0,0), r=1)
double ellipsoid_function (double, double, double); // (c=(0,0,0), r=1)
double torus_function (double, double, double); // (c=(0,0,0), r=2)
double chair_function (double, double, double); // (c=(0,0,0), r=6)
double tanglecube_function (double, double, double); // (c=(0,0,0), r=4)
double octic_function (double, double, double); // (c=(0,0,0), r=2)
double heart_function (double, double, double); // (c=(0,0,0), r=2)
double klein_function (double, double, double); // (c=(0,0,0), r=4)
double ring_function (double, double, double); // (c=(0,0,0), r=?)
double false_knot_function (double, double, double); // (c=(0,0,0), r=1)
double knot1_function (double, double, double); // (c=(0,0,0), r=4)
double knot2_function (double, double, double); // (c=(0,0,0), r=4)
double knot3_function (double, double, double); // (c=(0,0,0), r=4)
double cube_function (double, double, double); // (c=(0,0,0), r=2)
template <int Sq_radius>
double sphere_function (double x, double y, double z) // (c=(0,0,0), r=Sq_radius)
{
double x2=x*x, y2=y*y, z2=z*z;
return (x2+y2+z2)/Sq_radius - 1;
}
template <typename FT, typename P>
class FT_to_point_function_wrapper : public CGAL::cpp98::unary_function<P, FT>
{
typedef FT (*Implicit_function)(FT, FT, FT);
Implicit_function function;
public:
typedef P Point;
FT_to_point_function_wrapper(Implicit_function f) : function(f) {}
FT operator()(Point p) const { return function(p.x(), p.y(), p.z()); }
};

View File

@ -63,6 +63,8 @@ create_single_source_cgal_program("_test_valid_finite_float.cpp")
create_single_source_cgal_program("to_interval_test.cpp")
create_single_source_cgal_program("unsigned.cpp")
create_single_source_cgal_program("utilities.cpp")
create_single_source_cgal_program("Exact_rational.cpp")
create_single_source_cgal_program("Mpzf_new.cpp")
find_package( GMP )
if( GMP_FOUND AND NOT CGAL_DISABLE_GMP )

View File

@ -198,7 +198,7 @@ public:
/// \name
/// A point-offset pair (`p`,`off`) is said to be in conflict with a
/// cell `c` iff `dt`.`side_of_circle(c, p, off)` returns
/// face `f` iff `dt`.`side_of_circle(f, p, off)` returns
/// `ON_BOUNDED_SIDE`. The set of faces that are in conflict with
/// (`p`,`off`) is star-shaped.
/// @{
@ -309,7 +309,7 @@ public:
Checks the combinatorial validity of the triangulation and the
validity of its geometric embedding (see
Section \ref P2Triangulation2secintro). Also checks that all the
circumscribing circles of cells are empty.
circumscribing circles of faces are empty.
When `verbose` is set to true, messages describing the first
invalidity encountered are printed.
@ -321,9 +321,9 @@ public:
/*!
\cgalAdvancedFunction
\cgalAdvancedBegin
Checks the combinatorial and geometric validity of the cell (see
Checks the combinatorial and geometric validity of the face (see
Section \ref P2Triangulation2secintro). Also checks that the
circumscribing circle of cells is empty.
circumscribing circle of faces is empty.
When `verbose` is set to true, messages are printed to give
a precise indication of the kind of invalidity encountered.

View File

@ -65,10 +65,10 @@ concepts `Periodic_2TriangulationFaceBase_2` and
A triangulation is stored as a collection of vertices and faces that
are linked together through incidence and adjacency relations. Each
face gives access to its three incident vertices and to its three
adjacent cells. Each vertex gives access to one of its incident
adjacent faces. Each vertex gives access to one of its incident
faces.
The three vertices of a cell are indexed with 0, 1, and 2 in positive
The three vertices of a face are indexed with 0, 1, and 2 in positive
orientation, the positive orientation being defined by the orientation
of the underlying space \f$ \mathbb T_c^3\f$. The neighbors of a face are
also indexed with 0, 1, 2 in such a way that the neighbor indexed

View File

@ -134,7 +134,7 @@ A periodic triangulation is said to be `locally valid` iff
data structure, is `locally valid`
(see Chapter \ref Chapter_2D_Triangulation_Data_Structure)
<B>(c)</B> Any cell has its vertices ordered according to positive
<B>(c)</B> Any face has its vertices ordered according to positive
orientation. See \cgalFigureRef{P2Triangulation2figorient}.
\section P2T2_Delaunay Delaunay Triangulation
@ -264,7 +264,7 @@ to support periodicity: the vertex and face must be models of
`Periodic_2TriangulationVertexBase_2` and `Periodic_2TriangulationFaceBase_2`.
A model of such concept is `CGAL::Triangulation_data_structure_2`. It is
parameterized by a vertex base class and a face base class, which gives the
possibility to customize the vertices and cells used by the triangulation data
possibility to customize the vertices and faces used by the triangulation data
structure, and hence by the geometric triangulation using it.
Basic models of the vertex and face concepts are provided: `CGAL::Periodic_2_triangulation_vertex_base_2`
and `CGAL::Periodic_2_triangulation_face_base_2`.
@ -272,7 +272,7 @@ and `CGAL::Periodic_2_triangulation_face_base_2`.
A default value for the triangulation data structure parameter is provided in
all the triangulation classes, so it does not need to be specified by
the user unless he wants to use a different triangulation data
structure or a different vertex or cell base class.
structure or a different vertex or face base class.
\subsection P2T2FlexDesign Flexibility of the Design

View File

@ -27,24 +27,21 @@ int main()
// Gets the conflict region of 100 random points
// in the Delaunay tetrahedralization
for (int i = 0; i != 100; ++i)
{
Point p = (*rnd++);
{
Point p = (*rnd++);
// Locate the point
Delaunay::Locate_type lt;
int li;
Face_handle f = T.locate(p, lt, li);
if (lt == Delaunay::VERTEX)
continue; // Point already exists
// Locate the point
Delaunay::Locate_type lt;
int li;
Face_handle f = T.locate(p, lt, li);
if (lt == Delaunay::VERTEX)
continue; // Point already exists
// Get the cells that conflict with p in a vector V,
// and a facet on the boundary of this hole in f.
std::vector<Face_handle> V;
// Get the faces that conflict with p in a vector V.
std::vector<Face_handle> V;
T.get_conflicts(p,
std::back_inserter(V), // Conflict cells in V
f);
}
T.get_conflicts(p, std::back_inserter(V), f);
}
std::cout << "Final triangulation has " << T.number_of_vertices()
<< " vertices." << std::endl;

View File

@ -119,12 +119,21 @@ public:
/// Unique_vertex_iterator iterates over exactly one representative.
typedef Periodic_2_triangulation_unique_vertex_iterator_2<Self>
Unique_vertex_iterator;
/// Iterator over the canonical edges, i.e. for each set of periodic copies the
/// Unique_edge_iterator iterates over exactly one representative.
typedef Periodic_2_triangulation_unique_edge_iterator_2<Self>
Unique_edge_iterator;
/// Iterator over the canonical faces, i.e. for each set of periodic copies the
/// Unique_face_iterator iterates over exactly one representative.
typedef Periodic_2_triangulation_unique_face_iterator_2<Self>
Unique_face_iterator;
/// \name For compatibility with the Triangulation_2 class
// \{
typedef Face_iterator Finite_faces_iterator;
typedef Edge_iterator Finite_edges_iterator;
typedef Vertex_iterator Finite_vertices_iterator;
typedef Vertex_iterator All_vertices_iterator;
typedef Face_iterator All_faces_iterator;
// \}
@ -381,10 +390,11 @@ public:
/// Checks whether the triangulation is a valid simplicial complex in the one cover.
bool is_triangulation_in_1_sheet() const;
/// Convert a 9 sheeted cover (used for sparse triangulations) to a single sheeted cover.
/// Converts a 9 sheeted cover (used for sparse triangulations) to a single sheeted cover.
/// \pre !is_1_cover();
void convert_to_1_sheeted_covering();
/// Convert a single sheeted cover (used for dense triangulations) to a 9 sheeted cover.
/// Converts a single sheeted cover (used for dense triangulations) to a 9 sheeted cover.
/// \pre is_1_cover();
void convert_to_9_sheeted_covering();
// \}
@ -676,6 +686,32 @@ public:
Periodic_2_triangulation_2_internal::Domain_tester<Self>(this));
}
Unique_edge_iterator unique_edges_begin() const
{
return CGAL::filter_iterator(edges_end(),
Periodic_2_triangulation_2_internal::Domain_tester<Self>(this),
edges_begin());
}
/// past-the-end iterator over the canonical edges
Unique_edge_iterator unique_edges_end() const
{
return CGAL::filter_iterator(edges_end(),
Periodic_2_triangulation_2_internal::Domain_tester<Self>(this));
}
Unique_face_iterator unique_faces_begin() const
{
return CGAL::filter_iterator(faces_end(),
Periodic_2_triangulation_2_internal::Domain_tester<Self>(this),
faces_begin());
}
/// past-the-end iterator over the non-virtual vertices
Unique_face_iterator unique_faces_end() const
{
return CGAL::filter_iterator(faces_end(),
Periodic_2_triangulation_2_internal::Domain_tester<Self>(this));
}
// \}
/// \name Geometric iterators
//\{
@ -972,6 +1008,32 @@ public:
return Offset();
}
// Gets the canonicalized offsets of a face.
void get_offsets(Face_handle fh,
Offset& off0, Offset& off1, Offset& off2) const
{
Offset face_off0 = int_to_off(fh->offset(0));
Offset face_off1 = int_to_off(fh->offset(1));
Offset face_off2 = int_to_off(fh->offset(2));
Offset diff_off((face_off0.x() == 1 && face_off1.x() == 1 && face_off2.x() == 1) ? -1 : 0,
(face_off0.y() == 1 && face_off1.y() == 1 && face_off2.y() == 1) ? -1 : 0);
off0 = combine_offsets(get_offset(fh, 0), diff_off);
off1 = combine_offsets(get_offset(fh, 1), diff_off);
off2 = combine_offsets(get_offset(fh, 2), diff_off);
}
// Gets the canonicalized offsets of an edge.
void get_offsets(const Edge& e,
Offset& off0, Offset& off1) const
{
Offset edge_off0 = int_to_off(e.first->offset(cw(e.second)));
Offset edge_off1 = int_to_off(e.first->offset(ccw(e.second)));
Offset diff_off((edge_off0.x() == 1 && edge_off1.x() == 1) ? -1 : 0,
(edge_off0.y() == 1 && edge_off1.y() == 1) ? -1 : 0);
off0 = combine_offsets(get_offset(e.first, cw(e.second)), diff_off);
off1 = combine_offsets(get_offset(e.first, ccw(e.second)), diff_off);
}
/// Converts an offset to a bit pattern where bit1==offx and bit0==offy.
int off_to_int(const Offset & off) const
{
@ -986,13 +1048,12 @@ public:
return Offset((i >> 1) & 1, i & 1);
}
// \}
// Protected functions of Periodic_2_triangulation_2
/// Const accessor to the virtual vertices reverse map,
/// used to optimize point location for periodic copies.
const Virtual_vertex_reverse_map &virtual_vertices_reverse() const
/// Tests whether a vertex is a periodic copy of a vertex in the 3-cover.
bool is_virtual(Vertex_handle v) const
{
return _virtual_vertices_reverse;
if (is_1_cover())
return false;
return (_virtual_vertices.find(v) != _virtual_vertices.end());
}
/// [Undoc] Returns the non-virtual copy of the vertex.
@ -1007,15 +1068,6 @@ public:
return vh;
}
/// Tests whether a vertex is a periodic copy of a vertex in the 3-cover.
bool is_virtual(Vertex_handle v)
{
if (is_1_cover())
return false;
return (_virtual_vertices.find(v) != _virtual_vertices.end());
}
const std::vector<Vertex_handle>& periodic_copies(const Vertex_handle v) const
{
CGAL_precondition(number_of_sheets() != make_array(1, 1) );
@ -1024,6 +1076,77 @@ public:
return _virtual_vertices_reverse.find(v)->second;
}
// Protected functions of Periodic_2_triangulation_2
/// Const accessor to the virtual vertices reverse map,
/// used to optimize point location for periodic copies.
const Virtual_vertex_reverse_map& virtual_vertices_reverse() const
{
return _virtual_vertices_reverse;
}
// check whether pos points onto a unique edge or not.
// If we are computing in 1-sheeted covering this should
// always be true.
bool is_canonical(Face_handle fh) const
{
if(is_1_cover())
return true;
Offset off0, off1, off2;
get_offsets(fh, off0, off1, off2);
// If there is one offset with entries larger than 1 then we are
// talking about a vertex that is too far away from the original
// domain to belong to a canonical triangle.
if (off0.x() > 1) return false;
if (off0.y() > 1) return false;
if (off1.x() > 1) return false;
if (off1.y() > 1) return false;
if (off2.x() > 1) return false;
if (off2.y() > 1) return false;
// If there is one direction of space for which all offsets are
// non-zero then the edge is not canonical because we can
// take the copy closer towards the origin in that direction.
int offx = off0.x() & off1.x() & off2.x();
int offy = off0.y() & off1.y() & off2.y();
return (offx == 0 && offy == 0);
}
bool is_canonical(const Edge& e) const
{
if(is_1_cover())
return true;
// fetch all offsets
Offset off0, off1;
get_offsets(e, off0, off1);
// If there is one offset with entries larger than 1 then we are
// talking about a vertex that is too far away from the original
// domain to belong to a canonical edge.
if (off0.x() > 1) return false;
if (off0.y() > 1) return false;
if (off1.x() > 1) return false;
if (off1.y() > 1) return false;
// If there is one direction of space for which all offsets are
// non-zero then the edge is not canonical because we can
// take the copy closer towards the origin in that direction.
int offx = off0.x() & off1.x();
int offy = off0.y() & off1.y();
return (offx == 0 && offy == 0);
}
// checks whether pos points onto a vertex inside the original domain
bool is_canonical(Vertex_handle vh) const
{
return !is_virtual(vh);
}
public:
template<class Stream>
Stream& draw_triangulation(Stream& os) const
{

View File

@ -14,13 +14,11 @@
#include <CGAL/license/Periodic_2_triangulation_2.h>
#include <CGAL/assertions.h>
#include <CGAL/iterator.h>
#include <CGAL/array.h>
namespace CGAL
{
namespace CGAL {
template < class T >
class Periodic_2_triangulation_triangle_iterator_2
@ -66,7 +64,7 @@ public:
{
if (_it == T::UNIQUE || _it == T::UNIQUE_COVER_DOMAIN)
{
while (pos != _t->faces_end() && !is_canonical() )
while (pos != _t->faces_end() && !_t->is_canonical(pos) )
++pos;
}
}
@ -88,7 +86,7 @@ public:
{
++pos;
}
while (pos != _t->faces_end() && !is_canonical());
while (pos != _t->faces_end() && !_t->is_canonical(pos));
break;
case T::STORED_COVER_DOMAIN:
case T::UNIQUE_COVER_DOMAIN:
@ -112,7 +110,7 @@ public:
{
--pos;
}
while (pos != _t->faces_begin() && !is_canonical());
while (pos != _t->faces_begin() && !_t->is_canonical(pos));
break;
case T::STORED_COVER_DOMAIN:
case T::UNIQUE_COVER_DOMAIN:
@ -172,37 +170,6 @@ private:
mutable Periodic_triangle periodic_triangle; // current triangle.
private:
// check whether pos points onto a unique edge or not.
// If we are computing in 1-sheeted covering this should
// always be true.
bool is_canonical()
{
// fetch all offsets
Offset off0, off1, off2;
get_edge_offsets(off0, off1, off2);
if (_t->number_of_sheets() != make_array(1, 1))
{
// If there is one offset with entries larger than 1 then we are
// talking about a vertex that is too far away from the original
// domain to belong to a canonical triangle.
if (off0.x() > 1) return false;
if (off0.y() > 1) return false;
if (off1.x() > 1) return false;
if (off1.y() > 1) return false;
if (off2.x() > 1) return false;
if (off2.y() > 1) return false;
}
// If there is one direction of space for which all offsets are
// non-zero then the edge is not canonical because we can
// take the copy closer towards the origin in that direction.
int offx = off0.x() & off1.x() & off2.x();
int offy = off0.y() & off1.y() & off2.y();
return (offx == 0 && offy == 0);
}
// Artificial incrementation function that takes periodic
// copies into account.
void increment_domain()
@ -217,7 +184,7 @@ private:
++pos;
}
while (_it == T::UNIQUE_COVER_DOMAIN
&& pos != _t->faces_end() && !is_canonical());
&& pos != _t->faces_end() && !_t->is_canonical(pos));
}
else
{
@ -241,7 +208,7 @@ private:
{
--pos;
}
while (_it == T::UNIQUE_COVER_DOMAIN && !is_canonical());
while (_it == T::UNIQUE_COVER_DOMAIN && !_t->is_canonical(pos));
_off = get_drawing_offsets();
}
else
@ -256,25 +223,6 @@ private:
}
}
// Get the canonicalized offsets of an edge.
// This works in any cover that is encoded in _t->combine_offsets
void get_edge_offsets(Offset &off0, Offset &off1,
Offset &off2) const
{
Offset face_off0 = _t->int_to_off(pos->offset(0));
Offset face_off1 = _t->int_to_off(pos->offset(1));
Offset face_off2 = _t->int_to_off(pos->offset(2));
Offset diff_off((face_off0.x() == 1
&& face_off1.x() == 1
&& face_off2.x() == 1) ? -1 : 0,
(face_off0.y() == 1
&& face_off1.y() == 1
&& face_off2.y() == 1) ? -1 : 0);
off0 = _t->combine_offsets(_t->get_offset(pos, 0), diff_off);
off1 = _t->combine_offsets(_t->get_offset(pos, 1), diff_off);
off2 = _t->combine_offsets(_t->get_offset(pos, 2), diff_off);
}
// return an integer that encodes the translations which have to be
// applied to the edge *pos
int get_drawing_offsets()
@ -284,10 +232,10 @@ private:
// intersect the boundary of the periodic domain. In UNIQUE mode
// this means that the offset with respect to drawing should
// differ in some entries. Otherwise we consider the offsets
// internally stored inside the cell telling us that this cell
// internally stored inside the face telling us that this face
// wraps around the domain.
if (_it == T::UNIQUE_COVER_DOMAIN)
get_edge_offsets(off0, off1, off2);
_t->get_offsets(pos, off0, off1, off2);
else
{
CGAL_assertion(_it == T::STORED_COVER_DOMAIN);
@ -319,7 +267,7 @@ private:
{
CGAL_assertion(pos != typename T::Face_handle());
Offset off0, off1, off2;
get_edge_offsets(off0, off1, off2);
_t->get_offsets(pos, off0, off1, off2);
Offset transl_off = Offset((((_off >> 1) & 1) == 1 ? -1 : 0),
(((_off ) & 1) == 1 ? -1 : 0));
if (_it == T::STORED_COVER_DOMAIN)
@ -385,7 +333,7 @@ public:
{
if (_it == T::UNIQUE || _it == T::UNIQUE_COVER_DOMAIN)
{
while (pos != _t->edges_end() && !is_canonical() )
while (pos != _t->edges_end() && !_t->is_canonical(*pos) )
++pos;
}
}
@ -407,7 +355,7 @@ public:
{
++pos;
}
while (pos != _t->edges_end() && !is_canonical());
while (pos != _t->edges_end() && !_t->is_canonical(*pos));
break;
case T::STORED_COVER_DOMAIN:
case T::UNIQUE_COVER_DOMAIN:
@ -431,7 +379,7 @@ public:
{
--pos;
}
while (pos != _t->edges_begin() && !is_canonical());
while (pos != _t->edges_begin() && !_t->is_canonical(*pos));
break;
case T::STORED_COVER_DOMAIN:
case T::UNIQUE_COVER_DOMAIN:
@ -490,35 +438,6 @@ private:
mutable Periodic_segment periodic_segment; // current segment.
private:
// check whether pos points onto a unique edge or not.
// If we are computing in 1-sheeted covering this should
// always be true.
bool is_canonical()
{
// fetch all offsets
Offset off0, off1;
get_edge_offsets(off0, off1);
if (_t->number_of_sheets() != make_array(1, 1))
{
// If there is one offset with entries larger than 1 then we are
// talking about a vertex that is too far away from the original
// domain to belong to a canonical triangle.
if (off0.x() > 1) return false;
if (off0.y() > 1) return false;
if (off1.x() > 1) return false;
if (off1.y() > 1) return false;
}
// If there is one direction of space for which all offsets are
// non-zero then the edge is not canonical because we can
// take the copy closer towards the origin in that direction.
int offx = off0.x() & off1.x();
int offy = off0.y() & off1.y();
return (offx == 0 && offy == 0);
}
// Artificial incrementation function that takes periodic
// copies into account.
void increment_domain()
@ -533,7 +452,7 @@ private:
++pos;
}
while (_it == T::UNIQUE_COVER_DOMAIN
&& pos != _t->edges_end() && !is_canonical());
&& pos != _t->edges_end() && !_t->is_canonical(*pos));
}
else
{
@ -557,7 +476,7 @@ private:
{
--pos;
}
while (_it == T::UNIQUE_COVER_DOMAIN && !is_canonical());
while (_it == T::UNIQUE_COVER_DOMAIN && !_t->is_canonical(*pos));
_off = get_drawing_offsets();
}
else
@ -572,20 +491,6 @@ private:
}
}
// Get the canonicalized offsets of an edge.
// This works in any cover that is encoded in _t->combine_offsets
void get_edge_offsets(Offset &off0, Offset &off1) const
{
Offset cell_off0 = _t->int_to_off(pos->first->offset(_t->cw(pos->second)));
Offset cell_off1 = _t->int_to_off(pos->first->offset(_t->ccw(pos->second)));
Offset diff_off((cell_off0.x() == 1 && cell_off1.x() == 1) ? -1 : 0,
(cell_off0.y() == 1 && cell_off1.y() == 1) ? -1 : 0);
off0 = _t->combine_offsets(_t->get_offset(pos->first, _t->cw(pos->second)),
diff_off);
off1 = _t->combine_offsets(_t->get_offset(pos->first, _t->ccw(pos->second)),
diff_off);
}
// return an integer that encodes the translations which have to be
// applied to the edge *pos
int get_drawing_offsets()
@ -595,10 +500,10 @@ private:
// intersect the boundary of the periodic domain. In UNIQUE mode
// this means that the offset with respect to drawing should
// differ in some entries. Otherwise we consider the offsets
// internally stored inside the cell telling us that this cell
// internally stored inside the face telling us that this face
// wraps around the domain.
if (_it == T::UNIQUE_COVER_DOMAIN)
get_edge_offsets(off0, off1);
_t->get_offsets(*pos, off0, off1);
else
{
CGAL_assertion(_it == T::STORED_COVER_DOMAIN);
@ -618,7 +523,7 @@ private:
{
CGAL_assertion(pos->first != typename T::Face_handle());
Offset off0, off1;
get_edge_offsets(off0, off1);
_t->get_offsets(*pos, off0, off1);
Offset transl_off = Offset((((_off >> 1) & 1) == 1 ? -1 : 0),
(( _off & 1) == 1 ? -1 : 0));
if (_it == T::STORED_COVER_DOMAIN)
@ -681,7 +586,7 @@ public:
{
if (_it == T::UNIQUE || _it == T::UNIQUE_COVER_DOMAIN)
{
while (pos != _t->vertices_end() && !is_canonical() )
while (pos != _t->vertices_end() && !_t->is_canonical(pos) )
++pos;
}
}
@ -705,7 +610,7 @@ public:
{
++pos;
}
while (pos != _t->vertices_end() && !is_canonical());
while (pos != _t->vertices_end() && !_t->is_canonical(pos));
break;
default:
CGAL_assertion(false);
@ -727,7 +632,7 @@ public:
{
--pos;
}
while (pos != _t->vertices_begin() && !is_canonical());
while (pos != _t->vertices_begin() && !_t->is_canonical(pos));
break;
default:
CGAL_assertion(false);
@ -785,14 +690,6 @@ private:
mutable Periodic_point periodic_point; // current point.
private:
// check whether pos points onto a vertex inside the original
// domain. If we are computing in 1-sheeted covering this should
// always be true.
bool is_canonical()
{
return (_t->get_offset(pos).is_null());
}
Periodic_point construct_periodic_point() const
{
CGAL_assertion(pos != typename T::Vertex_handle());
@ -801,23 +698,91 @@ private:
}
};
namespace Periodic_2_triangulation_2_internal
{
namespace Periodic_2_triangulation_2_internal {
// returns `true` if the simplex is not canonical, and has to be filtered out
template <class T>
class Domain_tester
{
const T *t;
typedef typename T::Offset Offset;
public:
Domain_tester() {}
Domain_tester(const T *tr) : t(tr) {}
const T *t;
bool operator()(const typename T::Vertex_iterator & v) const
public:
Domain_tester() {}
Domain_tester(const T *tr) : t(tr) {}
bool operator()(const typename T::Vertex_iterator v) const
{
return !(t->get_offset(v).is_null());
}
bool operator()(const typename T::Edge_iterator e) const
{
Offset eo_0 = t->int_to_off(e->first->offset(t->cw(e->second)));
Offset eo_1 = t->int_to_off(e->first->offset(t->ccw(e->second)));
Offset diff_off((eo_0.x() == 1 && eo_1.x() == 1) ? -1 : 0,
(eo_0.y() == 1 && eo_1.y() == 1) ? -1 : 0);
Offset off0 = t->combine_offsets(t->get_offset(e->first, t->cw(e->second)), diff_off);
Offset off1 = t->combine_offsets(t->get_offset(e->first, t->ccw(e->second)), diff_off);
if (t->number_of_sheets() != make_array(1, 1))
{
return (t->get_offset(v) != typename T::Offset(0, 0));
// If there is one offset with entries larger than 1 then we are
// talking about a vertex that is too far away from the original
// domain to belong to a canonical edge.
if (off0.x() > 1) return true;
if (off0.y() > 1) return true;
if (off1.x() > 1) return true;
if (off1.y() > 1) return true;
}
// If there is one direction of space for which all offsets are
// non-zero then the edge is not canonical because we can
// take the copy closer towards the origin in that direction.
int offx = off0.x() & off1.x();
int offy = off0.y() & off1.y();
return (offx != 0 || offy != 0);
}
bool operator()(const typename T::Face_iterator f) const
{
Offset fo_0 = t->int_to_off(f->offset(0));
Offset fo_1 = t->int_to_off(f->offset(1));
Offset fo_2 = t->int_to_off(f->offset(2));
Offset diff_off((fo_0.x() == 1 && fo_1.x() == 1 && fo_2.x() == 1) ? -1 : 0,
(fo_0.y() == 1 && fo_1.y() == 1 && fo_2.y() == 1) ? -1 : 0);
Offset off0 = t->combine_offsets(t->get_offset(f, 0), diff_off);
Offset off1 = t->combine_offsets(t->get_offset(f, 1), diff_off);
Offset off2 = t->combine_offsets(t->get_offset(f, 2), diff_off);
if (t->number_of_sheets() != make_array(1, 1))
{
// If there is one offset with entries larger than 1 then we are
// talking about a vertex that is too far away from the original
// domain to belong to a canonical triangle.
if (off0.x() > 1) return true;
if (off0.y() > 1) return true;
if (off1.x() > 1) return true;
if (off1.y() > 1) return true;
if (off2.x() > 1) return true;
if (off2.y() > 1) return true;
}
// If there is one direction of space for which all offsets are
// non-zero then the edge is not canonical because we can
// take the copy closer towards the origin in that direction.
int offx = off0.x() & off1.x() & off2.x();
int offy = off0.y() & off1.y() & off2.y();
return (offx != 0 || offy != 0);
}
};
}
} // Periodic_2_triangulation_2_internal
// Iterates over the vertices in a periodic triangulation that are
// located inside the original cube.
@ -830,7 +795,6 @@ template <class T>
class Periodic_2_triangulation_unique_vertex_iterator_2
: public Filter_iterator<typename T::Vertex_iterator, Periodic_2_triangulation_2_internal::Domain_tester<T> >
{
typedef typename T::Vertex_handle Vertex_handle;
typedef typename T::Vertex_iterator Vertex_iterator;
@ -838,8 +802,8 @@ class Periodic_2_triangulation_unique_vertex_iterator_2
typedef Filter_iterator<Vertex_iterator, Tester > Base;
typedef Periodic_2_triangulation_unique_vertex_iterator_2 Self;
public:
public:
Periodic_2_triangulation_unique_vertex_iterator_2() : Base() {}
Periodic_2_triangulation_unique_vertex_iterator_2(const Base &b) : Base(b) {}
@ -872,6 +836,108 @@ public:
}
};
} //namespace CGAL
// Iterates over the canonical edges in a periodic triangulation.
// Derives from Filter_iterator in order to add a conversion to handle
//
// Comments:
// When computing in 1-sheeted covering, there will be no difference
// between a normal Edge_iterator and this iterator
template <class T>
class Periodic_2_triangulation_unique_edge_iterator_2
: public Filter_iterator<typename T::Edge_iterator, Periodic_2_triangulation_2_internal::Domain_tester<T> >
{
typedef typename T::Edge Edge;
typedef typename T::Edge_iterator Edge_iterator;
typedef typename Periodic_2_triangulation_2_internal::Domain_tester<T> Tester;
typedef Filter_iterator<Edge_iterator, Tester > Base;
typedef Periodic_2_triangulation_unique_edge_iterator_2 Self;
public:
Periodic_2_triangulation_unique_edge_iterator_2() : Base() {}
Periodic_2_triangulation_unique_edge_iterator_2(const Base &b) : Base(b) {}
Self & operator++()
{
Base::operator++();
return *this;
}
Self & operator--()
{
Base::operator--();
return *this;
}
Self operator++(int)
{
Self tmp(*this);
++(*this);
return tmp;
}
Self operator--(int)
{
Self tmp(*this);
--(*this);
return tmp;
}
operator Edge() const
{
return Base::base();
}
};
// Iterates over the canonical faces in a periodic triangulation.
// Derives from Filter_iterator in order to add a conversion to handle
//
// Comments:
// When computing in 1-sheeted covering, there will be no difference
// between a normal Face_iterator and this iterator
template <class T>
class Periodic_2_triangulation_unique_face_iterator_2
: public Filter_iterator<typename T::Face_iterator, Periodic_2_triangulation_2_internal::Domain_tester<T> >
{
typedef typename T::Face_handle Face_handle;
typedef typename T::Face_iterator Face_iterator;
typedef typename Periodic_2_triangulation_2_internal::Domain_tester<T> Tester;
typedef Filter_iterator<Face_iterator, Tester > Base;
typedef Periodic_2_triangulation_unique_face_iterator_2 Self;
public:
Periodic_2_triangulation_unique_face_iterator_2() : Base() {}
Periodic_2_triangulation_unique_face_iterator_2(const Base &b) : Base(b) {}
Self & operator++()
{
Base::operator++();
return *this;
}
Self & operator--()
{
Base::operator--();
return *this;
}
Self operator++(int)
{
Self tmp(*this);
++(*this);
return tmp;
}
Self operator--(int)
{
Self tmp(*this);
--(*this);
return tmp;
}
operator Face_handle() const
{
return Base::base();
}
};
} // namespace CGAL
#endif // CGAL_PERIODIC_2_TRIANGULATION_ITERATORS_2_H

View File

@ -208,6 +208,8 @@ void test_iterators()
Vertex_handle vh2 = t.insert(Point(0.7, 0.7));
CGAL_USE(vh2);
std::cout << "Cover = " << t.number_of_sheets()[0] << " " << t.number_of_sheets()[1] << std::endl;
// vertices
size_t size = 0;
for (typename T::Vertex_iterator vit = t_const.vertices_begin();
@ -217,19 +219,19 @@ void test_iterators()
}
assert(size == t_const.number_of_stored_vertices());
size = 0;
for (typename T::Vertex_iterator vit = t_const.all_vertices_begin();
vit != t_const.all_vertices_end(); ++vit)
{
++size;
}
assert(size == t_const.number_of_stored_vertices());
size = 0;
for (typename T::Unique_vertex_iterator uvit = t_const.unique_vertices_begin();
uvit != t_const.unique_vertices_end(); ++uvit)
{
++size;
}
assert(size == t_const.number_of_vertices());
size = 0;
for (typename T::Vertex_iterator vit = t_const.all_vertices_begin();
vit != t_const.all_vertices_end(); ++vit)
{
++size;
}
assert(size == t_const.number_of_stored_vertices());
// edges
size = 0;
@ -246,6 +248,13 @@ void test_iterators()
++size;
}
assert(size == t_const.number_of_stored_edges());
size = 0;
for (typename T::Unique_edge_iterator uvit = t_const.unique_edges_begin();
uvit != t_const.unique_edges_end(); ++uvit)
{
++size;
}
assert(size == t_const.number_of_edges());
// faces
size = 0;
@ -262,6 +271,13 @@ void test_iterators()
++size;
}
assert(size == t_const.number_of_stored_faces());
size = 0;
for (typename T::Unique_face_iterator uvit = t_const.unique_faces_begin();
uvit != t_const.unique_faces_end(); ++uvit)
{
++size;
}
assert(size == t_const.number_of_faces());
/// Geometric iterators
for (typename T::Periodic_point_iterator ppit = t_const.periodic_points_begin();

View File

@ -169,6 +169,13 @@ public:
typedef Facet_iterator All_facets_iterator;
typedef Edge_iterator All_edges_iterator;
typedef Vertex_iterator All_vertices_iterator;
typedef Periodic_3_triangulation_unique_cell_iterator_3<Self>
Unique_cell_iterator;
typedef Periodic_3_triangulation_unique_facet_iterator_3<Self>
Unique_facet_iterator;
typedef Periodic_3_triangulation_unique_edge_iterator_3<Self>
Unique_edge_iterator;
typedef Periodic_3_triangulation_unique_vertex_iterator_3<Self>
Unique_vertex_iterator;
@ -397,26 +404,14 @@ public:
}
const Covering_sheets& number_of_sheets() const { return _cover; }
const std::pair<Vertex_handle, Offset> original_vertex(const Vertex_handle v) const
{
return (virtual_vertices.find(v) == virtual_vertices.end()) ?
std::make_pair(v,Offset()) : virtual_vertices.find(v)->second;
}
const std::vector<Vertex_handle>& periodic_copies(const Vertex_handle v) const
{
CGAL_precondition(number_of_sheets() != CGAL::make_array(1,1,1));
CGAL_precondition(virtual_vertices.find(v) == virtual_vertices.end());
CGAL_assertion(
virtual_vertices_reverse.find(v) != virtual_vertices_reverse.end());
return virtual_vertices_reverse.find(v)->second;
}
bool is_triangulation_in_1_sheet() const;
void convert_to_1_sheeted_covering();
virtual void update_cover_data_after_converting_to_27_sheeted_covering() { }
void convert_to_27_sheeted_covering();
public:
size_type number_of_cells() const {
if(is_1_cover()) return _tds.number_of_cells();
else return _tds.number_of_cells()/27;
@ -460,14 +455,6 @@ public:
_cover = cover;
}
public:
bool is_virtual(Vertex_handle v)
{
if(is_1_cover())
return false;
return (virtual_vertices.find(v) != virtual_vertices.end());
}
public:
// Offset converters
int off_to_int(const Offset& off) const
@ -549,6 +536,232 @@ public:
c->set_offsets(o0i,o1i,o2i,o3i);
}
public:
// undocumented access functions
Offset get_offset(Cell_handle ch, int i) const
{
if(is_1_cover())
return int_to_off(ch->offset(i));
Virtual_vertex_map_it it = virtual_vertices.find(ch->vertex(i));
if(it != virtual_vertices.end())
return combine_offsets(it->second.second, int_to_off(ch->offset(i)));
else
return combine_offsets(Offset(), int_to_off(ch->offset(i)));
}
Offset get_offset(Vertex_handle vh) const
{
if(is_1_cover())
return Offset();
Virtual_vertex_map_it it = virtual_vertices.find(vh);
if(it != virtual_vertices.end())
return it->second.second;
else
return Offset();
}
// Get the canonicalized offsets of a cell.
void get_offsets(Cell_handle ch,
Offset& off0, Offset& off1, Offset& off2, Offset& off3) const
{
Offset cell_off0 = int_to_off(ch->offset(0));
Offset cell_off1 = int_to_off(ch->offset(1));
Offset cell_off2 = int_to_off(ch->offset(2));
Offset cell_off3 = int_to_off(ch->offset(3));
Offset diff_off((cell_off0.x() == 1 && cell_off1.x() == 1 &&
cell_off2.x() == 1 && cell_off3.x() == 1) ? -1 : 0,
(cell_off0.y() == 1 && cell_off1.y() == 1 &&
cell_off2.y() == 1 && cell_off3.y() == 1) ? -1 : 0,
(cell_off0.z() == 1 && cell_off1.z() == 1 &&
cell_off2.z() == 1 && cell_off3.z() == 1) ? -1 : 0);
off0 = combine_offsets(get_offset(ch,0), diff_off);
off1 = combine_offsets(get_offset(ch,1), diff_off);
off2 = combine_offsets(get_offset(ch,2), diff_off);
off3 = combine_offsets(get_offset(ch,3), diff_off);
}
// Gets the canonicalized offsets of a face.
void get_offsets(const Facet& f,
Offset& off0, Offset& off1, Offset& off2) const
{
Offset cell_off0 = int_to_off(f.first->offset((f.second+1)&3));
Offset cell_off1 = int_to_off(f.first->offset((f.second+2)&3));
Offset cell_off2 = int_to_off(f.first->offset((f.second+3)&3));
Offset diff_off((cell_off0.x() == 1 && cell_off1.x() == 1 && cell_off2.x() == 1) ? -1 : 0,
(cell_off0.y() == 1 && cell_off1.y() == 1 && cell_off2.y() == 1) ? -1 : 0,
(cell_off0.z() == 1 && cell_off1.z() == 1 && cell_off2.z() == 1) ? -1 : 0);
off0 = combine_offsets(get_offset(f.first, (f.second+1)&3), diff_off);
off1 = combine_offsets(get_offset(f.first, (f.second+2)&3), diff_off);
off2 = combine_offsets(get_offset(f.first, (f.second+3)&3), diff_off);
}
// Gets the canonicalized offsets of an edge.
void get_offsets(const Edge& e,
Offset& off0, Offset& off1) const
{
Offset cell_off0 = int_to_off(e.first->offset(e.second));
Offset cell_off1 = int_to_off(e.first->offset(e.third));
Offset diff_off((cell_off0.x()==1 && cell_off1.x()==1) ? -1 : 0,
(cell_off0.y()==1 && cell_off1.y()==1) ? -1 : 0,
(cell_off0.z()==1 && cell_off1.z()==1) ? -1 : 0);
off0 = combine_offsets(get_offset(e.first, e.second), diff_off);
off1 = combine_offsets(get_offset(e.first, e.third), diff_off);
}
public:
Offset combine_offsets(const Offset& o_c, const Offset& o_t) const
{
Offset o_ct(_cover[0]*o_t.x(), _cover[1]*o_t.y(), _cover[2]*o_t.z());
return o_c + o_ct;
}
public:
Offset neighbor_offset(Cell_handle ch, int i, Cell_handle nb) const;
Offset neighbor_offset(Cell_handle ch, int i) const
{
return neighbor_offset(ch, i, ch->neighbor(i));
}
public:
/// Tests whether a vertex is a periodic copy of a vertex in the 3-cover.
bool is_virtual(Vertex_handle vh) const
{
if(is_1_cover())
return false;
return (virtual_vertices.find(vh) != virtual_vertices.end());
}
/// Returns the non-virtual (i.e. canonical) copy of the vertex.
Vertex_handle get_original_vertex(Vertex_handle vh) const
{
if(is_1_cover())
return vh;
Virtual_vertex_map_it it = virtual_vertices.find(vh);
if(it != virtual_vertices.end())
return it->second.first;
else
return vh;
}
const std::pair<Vertex_handle, Offset> original_vertex(const Vertex_handle v) const
{
return (virtual_vertices.find(v) == virtual_vertices.end()) ?
std::make_pair(v,Offset()) : virtual_vertices.find(v)->second;
}
const std::vector<Vertex_handle>& periodic_copies(const Vertex_handle v) const
{
CGAL_precondition(number_of_sheets() != CGAL::make_array(1,1,1));
CGAL_precondition(virtual_vertices.find(v) == virtual_vertices.end());
CGAL_assertion(
virtual_vertices_reverse.find(v) != virtual_vertices_reverse.end());
return virtual_vertices_reverse.find(v)->second;
}
public:
bool is_canonical(Cell_handle ch) const
{
if(is_1_cover())
return true;
Offset off0, off1, off2, off3;
get_offsets(ch, off0, off1, off2, off3);
// If there is one offset with entries larger than 1 then we are
// talking about a vertex that is too far away from the original
// domain to belong to a canonical triangle.
if (off0.x() > 1) return false;
if (off0.y() > 1) return false;
if (off0.z() > 1) return false;
if (off1.x() > 1) return false;
if (off1.y() > 1) return false;
if (off1.z() > 1) return false;
if (off2.x() > 1) return false;
if (off2.y() > 1) return false;
if (off2.z() > 1) return false;
if (off3.x() > 1) return false;
if (off3.y() > 1) return false;
if (off3.z() > 1) return false;
// If there is one direction of space for which all offsets are
// non-zero then the edge is not canonical because we can
// take the copy closer towards the origin in that direction.
int offx = off0.x() & off1.x() & off2.x() & off3.x();
int offy = off0.y() & off1.y() & off2.y() & off3.y();
int offz = off0.z() & off1.z() & off2.z() & off3.z();
return (offx == 0 && offy == 0 && offz == 0);
}
bool is_canonical(const Edge& e) const
{
if(is_1_cover())
return true;
Offset off0, off1;
get_offsets(e, off0, off1);
// If there is one offset with entries larger than 1 then we are
// talking about a vertex that is too far away from the original
// domain to belong to a canonical edge.
if (off0.x() > 1) return false;
if (off0.y() > 1) return false;
if (off0.z() > 1) return false;
if (off1.x() > 1) return false;
if (off1.y() > 1) return false;
if (off1.z() > 1) return false;
// If there is one direction of space for which all offsets are
// non-zero then the edge is not canonical because we can
// take the copy closer towards the origin in that direction.
int offx = off0.x() & off1.x();
int offy = off0.y() & off1.y();
int offz = off0.z() & off1.z();
return (offx == 0 && offy == 0 && offz == 0);
}
bool is_canonical(const Facet& f) const
{
if(is_1_cover())
return true;
Offset off0, off1, off2;
get_offsets(f, off0, off1, off2);
// If there is one offset with entries larger than 1 then we are
// talking about a vertex that is too far away from the original
// domain to belong to a canonical triangle.
if(off0.x() > 1) return false;
if(off0.y() > 1) return false;
if(off0.z() > 1) return false;
if(off1.x() > 1) return false;
if(off1.y() > 1) return false;
if(off1.z() > 1) return false;
if(off2.x() > 1) return false;
if(off2.y() > 1) return false;
if(off2.z() > 1) return false;
// If there is one direction of space for which all offsets are
// non-zero then the facet is not canonical because we can
// take the copy closer towards the origin in that direction.
int offx = off0.x() & off1.x() & off2.x();
int offy = off0.y() & off1.y() & off2.y();
int offz = off0.z() & off1.z() & off2.z();
return (offx == 0 && offy == 0 && offz == 0);
}
/// Tests whether a vertex belongs to the original (canonical) domain.
bool is_canonical(Vertex_handle vh) const
{
return !is_virtual(vh);
}
public:
/** @name Wrapping the traits */
// Note that calling functors with "construct_point(p), offset" and not
@ -988,6 +1201,14 @@ public:
// end of geometric functions
public:
// These functions give the pair (vertex, offset) that corresponds to the
// i-th vertex of cell ch or vertex vh, respectively.
void get_vertex(Cell_handle ch, int i, Vertex_handle& vh, Offset& off) const;
void get_vertex(Vertex_handle vh_i, Vertex_handle& vh, Offset& off) const;
// Auxiliary functions
Cell_handle get_cell(const Vertex_handle* vh) const;
/** @name Queries */
bool is_vertex(const Point& p, Vertex_handle& v) const;
@ -1305,6 +1526,14 @@ public:
std::vector<Vertex_handle> insert_generic_dummy_points();
protected:
template<class Conflict_tester>
Offset get_location_offset(const Conflict_tester& tester,
Cell_handle c) const;
template<class Conflict_tester>
Offset get_location_offset(const Conflict_tester& tester,
Cell_handle c, bool& found) const;
// this is needed for compatibility reasons
template <class Conflict_test, class OutputIteratorBoundaryFacets,
class OutputIteratorCells, class OutputIteratorInternalFacets>
@ -1474,6 +1703,8 @@ public:
return _tds.facets_end();
}
// Finite iterators (= all iterators, for periodic triangulations)
Cell_iterator finite_cells_begin() const {
return _tds.cells_begin();
}
@ -1502,6 +1733,8 @@ public:
return _tds.facets_end();
}
// All iterators (= finite, for periodic triangulations)
All_cells_iterator all_cells_begin() const {
return _tds.cells_begin();
}
@ -1530,6 +1763,16 @@ public:
return _tds.facets_end();
}
// Unique iterators
Unique_cell_iterator unique_cells_begin() const {
return CGAL::filter_iterator(cells_end(), Domain_tester<Self>(this),
cells_begin());
}
Unique_cell_iterator unique_cells_end() const {
return CGAL::filter_iterator(cells_end(), Domain_tester<Self>(this));
}
Unique_vertex_iterator unique_vertices_begin() const {
return CGAL::filter_iterator(vertices_end(), Domain_tester<Self>(this),
vertices_begin());
@ -1538,6 +1781,22 @@ public:
return CGAL::filter_iterator(vertices_end(), Domain_tester<Self>(this));
}
Unique_edge_iterator unique_edges_begin() const {
return CGAL::filter_iterator(edges_end(), Domain_tester<Self>(this),
edges_begin());
}
Unique_edge_iterator unique_edges_end() const {
return CGAL::filter_iterator(edges_end(), Domain_tester<Self>(this));
}
Unique_facet_iterator unique_facets_begin() const {
return CGAL::filter_iterator(facets_end(), Domain_tester<Self>(this),
facets_begin());
}
Unique_facet_iterator unique_facets_end() const {
return CGAL::filter_iterator(facets_end(), Domain_tester<Self>(this));
}
// Geometric iterators
Periodic_tetrahedron_iterator periodic_tetrahedra_begin(
Iterator_type it = STORED) const {
@ -1576,6 +1835,7 @@ public:
}
// Circulators
Cell_circulator incident_cells(const Edge& e) const {
return _tds.incident_cells(e);
}
@ -1695,75 +1955,6 @@ public:
}
};
public:
// undocumented access functions
Offset get_offset(Cell_handle ch, int i) const
{
if(is_1_cover())
return int_to_off(ch->offset(i));
Virtual_vertex_map_it it = virtual_vertices.find(ch->vertex(i));
if(it != virtual_vertices.end())
return combine_offsets(it->second.second, int_to_off(ch->offset(i)));
else
return combine_offsets(Offset(), int_to_off(ch->offset(i)));
}
Offset get_offset(Vertex_handle vh) const
{
if(is_1_cover())
return Offset();
Virtual_vertex_map_it it = virtual_vertices.find(vh);
if(it != virtual_vertices.end())
return it->second.second;
else
return Offset();
}
Vertex_handle get_original_vertex(Vertex_handle vh) const
{
if(is_1_cover())
return vh;
Virtual_vertex_map_it it = virtual_vertices.find(vh);
if(it != virtual_vertices.end())
return it->second.first;
else
return vh;
}
Offset combine_offsets(const Offset& o_c, const Offset& o_t) const
{
Offset o_ct(_cover[0]*o_t.x(), _cover[1]*o_t.y(), _cover[2]*o_t.z());
return o_c + o_ct;
}
// These functions give the pair (vertex, offset) that corresponds to the
// i-th vertex of cell ch or vertex vh, respectively.
void get_vertex(Cell_handle ch, int i, Vertex_handle& vh, Offset& off) const;
void get_vertex(Vertex_handle vh_i, Vertex_handle& vh, Offset& off) const;
protected:
// Auxiliary functions
Cell_handle get_cell(const Vertex_handle* vh) const;
template<class Conflict_tester>
Offset get_location_offset(const Conflict_tester& tester,
Cell_handle c) const;
template<class Conflict_tester>
Offset get_location_offset(const Conflict_tester& tester,
Cell_handle c, bool& found) const;
Offset neighbor_offset(Cell_handle ch, int i, Cell_handle nb) const;
public:
Offset neighbor_offset(Cell_handle ch, int i) const
{
return neighbor_offset(ch, i, ch->neighbor(i));
}
protected:
/** @name Friends */
friend std::istream& operator>> <>
@ -1788,51 +1979,6 @@ protected:
return construct_periodic_point(p);
}
public:
bool is_canonical(const Facet& f) const
{
if(number_of_sheets() == CGAL::make_array(1,1,1))
return true;
Offset cell_off0 = int_to_off(f.first->offset((f.second+1)&3));
Offset cell_off1 = int_to_off(f.first->offset((f.second+2)&3));
Offset cell_off2 = int_to_off(f.first->offset((f.second+3)&3));
Offset diff_off((cell_off0.x() == 1
&& cell_off1.x() == 1
&& cell_off2.x() == 1) ? -1 : 0,
(cell_off0.y() == 1
&& cell_off1.y() == 1
&& cell_off2.y() == 1) ? -1 : 0,
(cell_off0.z() == 1
&& cell_off1.z() == 1
&& cell_off2.z() == 1) ? -1 : 0);
Offset off0 = combine_offsets(get_offset(f.first, (f.second+1)&3), diff_off);
Offset off1 = combine_offsets(get_offset(f.first, (f.second+2)&3), diff_off);
Offset off2 = combine_offsets(get_offset(f.first, (f.second+3)&3), diff_off);
// If there is one offset with entries larger than 1 then we are
// talking about a vertex that is too far away from the original
// domain to belong to a canonical triangle.
if(off0.x() > 1) return false;
if(off0.y() > 1) return false;
if(off0.z() > 1) return false;
if(off1.x() > 1) return false;
if(off1.y() > 1) return false;
if(off1.z() > 1) return false;
if(off2.x() > 1) return false;
if(off2.y() > 1) return false;
if(off2.z() > 1) return false;
// If there is one direction of space for which all offsets are
// non-zero then the edge is not canonical because we can
// take the copy closer towards the origin in that direction.
int offx = off0.x() & off1.x() & off2.x();
int offy = off0.y() & off1.y() & off2.y();
int offz = off0.z() & off1.z() & off2.z();
return (offx == 0 && offy == 0 && offz == 0);
}
protected:
template <class ConstructCircumcenter>
bool canonical_dual_segment(Cell_handle c, int i, Periodic_segment_3& ps,
@ -3310,7 +3456,7 @@ periodic_remove(Vertex_handle v,
nr_vec.push_back(boost::make_tuple(o_ch,o_i,new_ch));
nr_vec.push_back(boost::make_tuple(new_ch,i_i,o_ch));
// for the other faces check, if they can also be glued
// for the other facets check, if they can also be glued
for(unsigned int i = 0; i < 4; i++) {
if(i != i_i) {
Facet f = std::pair<Cell_handle,int>(new_ch,i);
@ -3322,7 +3468,7 @@ periodic_remove(Vertex_handle v,
std::swap(vt.second,vt.third);
outer_map[vt]= f;
} else {
// glue the faces
// glue the facets
typename Vertex_triple_Facet_map::value_type o_vt_f_pair2 = *oit2;
Cell_handle o_ch2 = o_vt_f_pair2.second.first;
int o_i2 = o_vt_f_pair2.second.second;

View File

@ -63,7 +63,7 @@ public:
Iterator_type it = T::STORED)
: _t(t), pos(_t->cells_begin()), _it(it), _off(0) {
if (_it == T::UNIQUE || _it == T::UNIQUE_COVER_DOMAIN) {
while (pos != _t->cells_end() && !is_canonical() )
while (pos != _t->cells_end() && !_t->is_canonical(pos) )
++pos;
}
}
@ -79,7 +79,7 @@ public:
++pos;
break;
case T::UNIQUE:
do { ++pos; } while (pos != _t->cells_end() && !is_canonical());
do { ++pos; } while (pos != _t->cells_end() && !_t->is_canonical(pos));
break;
case T::STORED_COVER_DOMAIN:
case T::UNIQUE_COVER_DOMAIN:
@ -97,7 +97,7 @@ public:
--pos;
break;
case T::UNIQUE:
do { --pos; } while (pos != _t->cells_begin() && !is_canonical());
do { --pos; } while (pos != _t->cells_begin() && !_t->is_canonical(pos));
break;
case T::STORED_COVER_DOMAIN:
case T::UNIQUE_COVER_DOMAIN:
@ -156,42 +156,6 @@ private:
mutable Periodic_tetrahedron periodic_tetrahedron; // current tetrahedron.
private:
// check whether pos points onto a unique edge or not.
// If we are computing in 1-sheeted covering this should
// always be true.
bool is_canonical() {
// fetch all offsets
Offset off0, off1, off2, off3;
get_edge_offsets(off0, off1, off2, off3);
if (_t->number_of_sheets() != make_array(1,1,1)) {
// If there is one offset with entries larger than 1 then we are
// talking about a vertex that is too far away from the original
// domain to belong to a canonical triangle.
if (off0.x() > 1) return false;
if (off0.y() > 1) return false;
if (off0.z() > 1) return false;
if (off1.x() > 1) return false;
if (off1.y() > 1) return false;
if (off1.z() > 1) return false;
if (off2.x() > 1) return false;
if (off2.y() > 1) return false;
if (off2.z() > 1) return false;
if (off3.x() > 1) return false;
if (off3.y() > 1) return false;
if (off3.z() > 1) return false;
}
// If there is one direction of space for which all offsets are
// non-zero then the edge is not canonical because we can
// take the copy closer towards the origin in that direction.
int offx = off0.x() & off1.x() & off2.x() & off3.x();
int offy = off0.y() & off1.y() & off2.y() & off3.y();
int offz = off0.z() & off1.z() & off2.z() & off3.z();
return (offx == 0 && offy == 0 && offz == 0);
}
// Artificial incrementation function that takes periodic
// copies into account.
void increment_domain() {
@ -200,7 +164,7 @@ private:
if (_off == off) {
_off = 0;
do { ++pos; } while (_it == T::UNIQUE_COVER_DOMAIN
&& pos != _t->cells_end() && !is_canonical());
&& pos != _t->cells_end() && !_t->is_canonical(pos));
} else {
do {
++_off;
@ -214,7 +178,7 @@ private:
void decrement_domain() {
if (_off == 0) {
if (pos == _t->cells_begin()) return;
do { --pos; } while (_it == T::UNIQUE_COVER_DOMAIN && !is_canonical());
do { --pos; } while (_it == T::UNIQUE_COVER_DOMAIN && !_t->is_canonical(pos));
_off = get_drawing_offsets();
} else {
int off = get_drawing_offsets();
@ -225,32 +189,6 @@ private:
}
}
// Get the canonicalized offsets of an edge.
// This works in any cover that is encoded in _t->combine_offsets
void get_edge_offsets(Offset &off0, Offset &off1,
Offset &off2, Offset &off3) const {
Offset cell_off0 = _t->int_to_off(pos->offset(0));
Offset cell_off1 = _t->int_to_off(pos->offset(1));
Offset cell_off2 = _t->int_to_off(pos->offset(2));
Offset cell_off3 = _t->int_to_off(pos->offset(3));
Offset diff_off((cell_off0.x() == 1
&& cell_off1.x() == 1
&& cell_off2.x() == 1
&& cell_off3.x() == 1)?-1:0,
(cell_off0.y() == 1
&& cell_off1.y() == 1
&& cell_off2.y() == 1
&& cell_off3.y() == 1)?-1:0,
(cell_off0.z() == 1
&& cell_off1.z() == 1
&& cell_off2.z() == 1
&& cell_off3.z() == 1)?-1:0);
off0 = _t->combine_offsets(_t->get_offset(pos,0), diff_off);
off1 = _t->combine_offsets(_t->get_offset(pos,1), diff_off);
off2 = _t->combine_offsets(_t->get_offset(pos,2), diff_off);
off3 = _t->combine_offsets(_t->get_offset(pos,3), diff_off);
}
// return an integer that encodes the translations which have to be
// applied to the edge *pos
int get_drawing_offsets() {
@ -262,7 +200,7 @@ private:
// internally stored inside the cell telling us that this cell
// wraps around the domain.
if (_it == T::UNIQUE_COVER_DOMAIN)
get_edge_offsets(off0,off1,off2,off3);
_t->get_offsets(pos, off0, off1, off2, off3);
else {
CGAL_assertion(_it == T::STORED_COVER_DOMAIN);
off0 = _t->int_to_off(pos->offset(0));
@ -303,7 +241,7 @@ private:
Periodic_tetrahedron construct_periodic_tetrahedron() const {
CGAL_assertion(pos != typename T::Cell_handle());
Offset off0, off1, off2, off3;
get_edge_offsets(off0, off1, off2, off3);
_t->get_offsets(pos, off0, off1, off2, off3);
Offset transl_off = Offset((((_off>>2)&1)==1 ? -1:0),
(((_off>>1)&1)==1 ? -1:0),
(( _off &1)==1 ? -1:0));
@ -369,7 +307,7 @@ public:
Iterator_type it = T::STORED)
: _t(t), pos(_t->facets_begin()), _it(it), _off(0) {
if (_it == T::UNIQUE || _it == T::UNIQUE_COVER_DOMAIN) {
while (pos != _t->facets_end() && !is_canonical() )
while (pos != _t->facets_end() && !_t->is_canonical(*pos) )
++pos;
}
}
@ -385,7 +323,7 @@ public:
++pos;
break;
case T::UNIQUE:
do { ++pos; } while (pos != _t->facets_end() && !is_canonical());
do { ++pos; } while (pos != _t->facets_end() && !_t->is_canonical(*pos));
break;
case T::STORED_COVER_DOMAIN:
case T::UNIQUE_COVER_DOMAIN:
@ -403,7 +341,7 @@ public:
--pos;
break;
case T::UNIQUE:
do { --pos; } while (pos != _t->facets_begin() && !is_canonical());
do { --pos; } while (pos != _t->facets_begin() && !_t->is_canonical(*pos));
break;
case T::STORED_COVER_DOMAIN:
case T::UNIQUE_COVER_DOMAIN:
@ -462,39 +400,6 @@ private:
mutable Periodic_triangle periodic_triangle; // current segment.
private:
// check whether pos points onto a unique edge or not.
// If we are computing in 1-sheeted covering this should
// always be true.
bool is_canonical() {
// fetch all offsets
Offset off0, off1, off2;
get_edge_offsets(off0, off1, off2);
if (_t->number_of_sheets() != make_array(1,1,1)) {
// If there is one offset with entries larger than 1 then we are
// talking about a vertex that is too far away from the original
// domain to belong to a canonical triangle.
if (off0.x() > 1) return false;
if (off0.y() > 1) return false;
if (off0.z() > 1) return false;
if (off1.x() > 1) return false;
if (off1.y() > 1) return false;
if (off1.z() > 1) return false;
if (off2.x() > 1) return false;
if (off2.y() > 1) return false;
if (off2.z() > 1) return false;
}
// If there is one direction of space for which all offsets are
// non-zero then the edge is not canonical because we can
// take the copy closer towards the origin in that direction.
int offx = off0.x() & off1.x() & off2.x();
int offy = off0.y() & off1.y() & off2.y();
int offz = off0.z() & off1.z() & off2.z();
return (offx == 0 && offy == 0 && offz == 0);
}
// Artificial incrementation function that takes periodic
// copies into account.
void increment_domain() {
@ -503,7 +408,7 @@ private:
if (_off == off) {
_off = 0;
do { ++pos; } while (_it == T::UNIQUE_COVER_DOMAIN
&& pos != _t->facets_end() && !is_canonical());
&& pos != _t->facets_end() && !_t->is_canonical(*pos));
} else {
do {
++_off;
@ -517,7 +422,7 @@ private:
void decrement_domain() {
if (_off == 0) {
if (pos == _t->facets_begin()) return;
do { --pos; } while (_it == T::UNIQUE_COVER_DOMAIN && !is_canonical());
do { --pos; } while (_it == T::UNIQUE_COVER_DOMAIN && !_t->is_canonical(*pos));
_off = get_drawing_offsets();
} else {
int off = get_drawing_offsets();
@ -528,32 +433,6 @@ private:
}
}
// Get the canonicalized offsets of an edge.
// This works in any cover that is encoded in _t->combine_offsets
void get_edge_offsets(Offset &off0, Offset &off1, Offset &off2) const {
Offset cell_off0 = _t->int_to_off(pos->first->offset((pos->second+1)&3));
Offset cell_off1 = _t->int_to_off(pos->first->offset((pos->second+2)&3));
Offset cell_off2 = _t->int_to_off(pos->first->offset((pos->second+3)&3));
Offset diff_off((cell_off0.x() == 1
&& cell_off1.x() == 1
&& cell_off2.x() == 1)?-1:0,
(cell_off0.y() == 1
&& cell_off1.y() == 1
&& cell_off2.y() == 1)?-1:0,
(cell_off0.z() == 1
&& cell_off1.z() == 1
&& cell_off2.z() == 1)?-1:0);
off0 = _t->combine_offsets(_t->get_offset(pos->first,
(pos->second+1)&3),
diff_off);
off1 = _t->combine_offsets(_t->get_offset(pos->first,
(pos->second+2)&3),
diff_off);
off2 = _t->combine_offsets(_t->get_offset(pos->first,
(pos->second+3)&3),
diff_off);
}
// return an integer that encodes the translations which have to be
// applied to the edge *pos
int get_drawing_offsets() {
@ -565,7 +444,7 @@ private:
// internally stored inside the cell telling us that this cell
// wraps around the domain.
if (_it == T::UNIQUE_COVER_DOMAIN)
get_edge_offsets(off0,off1,off2);
_t->get_offsets(*pos, off0, off1, off2);
else {
CGAL_assertion(_it == T::STORED_COVER_DOMAIN);
off0 = _t->int_to_off(pos->first->offset((pos->second+1)&3));
@ -596,7 +475,7 @@ private:
Periodic_triangle construct_periodic_triangle() const {
CGAL_assertion(pos->first != typename T::Cell_handle());
Offset off0, off1, off2;
get_edge_offsets(off0, off1, off2);
_t->get_offsets(*pos, off0, off1, off2);
Offset transl_off = Offset((((_off>>2)&1)==1 ? -1:0),
(((_off>>1)&1)==1 ? -1:0),
(( _off &1)==1 ? -1:0));
@ -659,7 +538,7 @@ public:
Iterator_type it = T::STORED)
: _t(t), pos(_t->edges_begin()), _it(it), _off(0) {
if (_it == T::UNIQUE || _it == T::UNIQUE_COVER_DOMAIN) {
while (pos != _t->edges_end() && !is_canonical() )
while (pos != _t->edges_end() && !_t->is_canonical(*pos) )
++pos;
}
}
@ -675,7 +554,7 @@ public:
++pos;
break;
case T::UNIQUE:
do { ++pos; } while (pos != _t->edges_end() && !is_canonical());
do { ++pos; } while (pos != _t->edges_end() && !_t->is_canonical(*pos));
break;
case T::STORED_COVER_DOMAIN:
case T::UNIQUE_COVER_DOMAIN:
@ -693,7 +572,7 @@ public:
--pos;
break;
case T::UNIQUE:
do { --pos; } while (pos != _t->edges_begin() && !is_canonical());
do { --pos; } while (pos != _t->edges_begin() && !_t->is_canonical(*pos));
break;
case T::STORED_COVER_DOMAIN:
case T::UNIQUE_COVER_DOMAIN:
@ -751,36 +630,6 @@ private:
mutable Periodic_segment periodic_segment; // current segment.
private:
// check whether pos points onto a unique edge or not.
// If we are computing in 1-sheeted covering this should
// always be true.
bool is_canonical() {
// fetch all offsets
Offset off0, off1;
get_edge_offsets(off0, off1);
if (_t->number_of_sheets() != make_array(1,1,1)) {
// If there is one offset with entries larger than 1 then we are
// talking about a vertex that is too far away from the original
// domain to belong to a canonical triangle.
if (off0.x() > 1) return false;
if (off0.y() > 1) return false;
if (off0.z() > 1) return false;
if (off1.x() > 1) return false;
if (off1.y() > 1) return false;
if (off1.z() > 1) return false;
}
// If there is one direction of space for which all offsets are
// non-zero then the edge is not canonical because we can
// take the copy closer towards the origin in that direction.
int offx = off0.x() & off1.x();
int offy = off0.y() & off1.y();
int offz = off0.z() & off1.z();
return (offx == 0 && offy == 0 && offz == 0);
}
// Artificial incrementation function that takes periodic
// copies into account.
void increment_domain() {
@ -789,7 +638,7 @@ private:
if (_off == off) {
_off = 0;
do { ++pos; } while (_it == T::UNIQUE_COVER_DOMAIN
&& pos != _t->edges_end() && !is_canonical());
&& pos != _t->edges_end() && !_t->is_canonical(*pos));
} else {
do {
++_off;
@ -803,7 +652,7 @@ private:
void decrement_domain() {
if (_off == 0) {
if (pos == _t->edges_begin()) return;
do { --pos; } while (_it == T::UNIQUE_COVER_DOMAIN && !is_canonical());
do { --pos; } while (_it == T::UNIQUE_COVER_DOMAIN && !_t->is_canonical(*pos));
_off = get_drawing_offsets();
} else {
int off = get_drawing_offsets();
@ -814,20 +663,6 @@ private:
}
}
// Get the canonicalized offsets of an edge.
// This works in any cover that is encoded in _t->combine_offsets
void get_edge_offsets(Offset &off0, Offset &off1) const {
Offset cell_off0 = _t->int_to_off(pos->first->offset(pos->second));
Offset cell_off1 = _t->int_to_off(pos->first->offset(pos->third));
Offset diff_off((cell_off0.x()==1 && cell_off1.x()==1)?-1:0,
(cell_off0.y()==1 && cell_off1.y()==1)?-1:0,
(cell_off0.z()==1 && cell_off1.z()==1)?-1:0);
off0 = _t->combine_offsets(_t->get_offset(pos->first,pos->second),
diff_off);
off1 = _t->combine_offsets(_t->get_offset(pos->first,pos->third),
diff_off);
}
// return an integer that encodes the translations which have to be
// applied to the edge *pos
int get_drawing_offsets() {
@ -839,7 +674,7 @@ private:
// internally stored inside the cell telling us that this cell
// wraps around the domain.
if (_it == T::UNIQUE_COVER_DOMAIN)
get_edge_offsets(off0,off1);
_t->get_offsets(*pos, off0, off1);
else {
CGAL_assertion(_it == T::STORED_COVER_DOMAIN);
off0 = _t->int_to_off(pos->first->offset(pos->second));
@ -859,7 +694,7 @@ private:
Periodic_segment construct_periodic_segment() const {
CGAL_assertion(pos->first != typename T::Cell_handle());
Offset off0, off1;
get_edge_offsets(off0, off1);
_t->get_offsets(*pos, off0, off1);
Offset transl_off = Offset((((_off>>2)&1)==1 ? -1:0),
(((_off>>1)&1)==1 ? -1:0),
(( _off &1)==1 ? -1:0));
@ -918,7 +753,7 @@ public:
Iterator_type it = T::STORED)
: _t(t), pos(_t->vertices_begin()), _it(it) {
if (_it == T::UNIQUE || _it == T::UNIQUE_COVER_DOMAIN) {
while (pos != _t->vertices_end() && !is_canonical() )
while (pos != _t->vertices_end() && !_t->is_canonical(pos) )
++pos;
}
}
@ -936,7 +771,7 @@ public:
break;
case T::UNIQUE:
case T::UNIQUE_COVER_DOMAIN:
do { ++pos; } while (pos != _t->vertices_end() && !is_canonical());
do { ++pos; } while (pos != _t->vertices_end() && !_t->is_canonical(pos));
break;
default:
CGAL_assertion(false);
@ -952,7 +787,7 @@ public:
break;
case T::UNIQUE:
case T::UNIQUE_COVER_DOMAIN:
do { --pos; } while (pos != _t->vertices_begin() && !is_canonical());
do { --pos; } while (pos != _t->vertices_begin() && !_t->is_canonical(pos));
break;
default:
CGAL_assertion(false);
@ -1009,13 +844,6 @@ private:
mutable Periodic_point periodic_point; // current point.
private:
// check whether pos points onto a vertex inside the original
// domain. If we are computing in 1-sheeted covering this should
// always be true.
bool is_canonical() {
return (_t->get_offset(pos) == Offset(0,0,0));
}
Periodic_point construct_periodic_point() const {
CGAL_assertion(pos != typename T::Vertex_handle());
Offset off = _t->get_offset(pos);
@ -1031,9 +859,54 @@ public:
Domain_tester() {}
Domain_tester(const T *tr) : t(tr) {}
bool operator()(const typename T::Vertex_iterator & v) const {
return (t->get_offset(v) != typename T::Offset(0,0,0));
bool operator()(const typename T::Cell_iterator c) const
{
return !t->is_canonical(c);
}
bool operator()(const typename T::Facet_iterator f) const
{
return !t->is_canonical(*f);
}
bool operator()(const typename T::Edge_iterator e) const
{
return !t->is_canonical(*e);
}
bool operator()(const typename T::Vertex_iterator v) const
{
return !t->is_canonical(v);
}
};
// Iterates over the canonical cells in a periodic triangulation.
// Derives from Filter_iterator in order to add a conversion to handle
//
// Comments:
// When computing in 1-sheeted covering, there will be no difference
// between a normal Cell_iterator and this iterator
template <class T>
class Periodic_3_triangulation_unique_cell_iterator_3
: public Filter_iterator<typename T::Cell_iterator, Domain_tester<T> >
{
typedef typename T::Cell_handle Cell_handle;
typedef typename T::Cell_iterator Cell_iterator;
typedef Filter_iterator<Cell_iterator, Domain_tester<T> > Base;
typedef Periodic_3_triangulation_unique_cell_iterator_3 Self;
public:
Periodic_3_triangulation_unique_cell_iterator_3() : Base() {}
Periodic_3_triangulation_unique_cell_iterator_3(const Base &b) : Base(b) {}
Self & operator++() { Base::operator++(); return *this; }
Self & operator--() { Base::operator--(); return *this; }
Self operator++(int) { Self tmp(*this); ++(*this); return tmp; }
Self operator--(int) { Self tmp(*this); --(*this); return tmp; }
operator Cell_handle() const { return Base::base(); }
};
// Iterates over the vertices in a periodic triangulation that are
@ -1045,15 +918,15 @@ public:
// between a normal Vertex_iterator and this iterator
template <class T>
class Periodic_3_triangulation_unique_vertex_iterator_3
: public Filter_iterator<typename T::Vertex_iterator, Domain_tester<T> > {
: public Filter_iterator<typename T::Vertex_iterator, Domain_tester<T> >
{
typedef typename T::Vertex_handle Vertex_handle;
typedef typename T::Vertex_iterator Vertex_iterator;
typedef Filter_iterator<Vertex_iterator, Domain_tester<T> > Base;
typedef Periodic_3_triangulation_unique_vertex_iterator_3 Self;
public:
public:
Periodic_3_triangulation_unique_vertex_iterator_3() : Base() {}
Periodic_3_triangulation_unique_vertex_iterator_3(const Base &b) : Base(b) {}
@ -1065,6 +938,62 @@ public:
operator Vertex_handle() const { return Base::base(); }
};
} //namespace CGAL
// Iterates over the canonical edges in a periodic triangulation.
// Derives from Filter_iterator in order to add a conversion to handle
//
// Comments:
// When computing in 1-sheeted covering, there will be no difference
// between a normal Edge_iterator and this iterator
template <class T>
class Periodic_3_triangulation_unique_edge_iterator_3
: public Filter_iterator<typename T::Edge_iterator, Domain_tester<T> >
{
typedef typename T::Edge Edge;
typedef typename T::Edge_iterator Edge_iterator;
typedef Filter_iterator<Edge_iterator, Domain_tester<T> > Base;
typedef Periodic_3_triangulation_unique_edge_iterator_3 Self;
public:
Periodic_3_triangulation_unique_edge_iterator_3() : Base() {}
Periodic_3_triangulation_unique_edge_iterator_3(const Base &b) : Base(b) {}
Self & operator++() { Base::operator++(); return *this; }
Self & operator--() { Base::operator--(); return *this; }
Self operator++(int) { Self tmp(*this); ++(*this); return tmp; }
Self operator--(int) { Self tmp(*this); --(*this); return tmp; }
operator Edge() const { return Base::base(); }
};
// Iterates over the canonical facets in a periodic triangulation.
// Derives from Filter_iterator in order to add a conversion to handle
//
// Comments:
// When computing in 1-sheeted covering, there will be no difference
// between a normal Facet_iterator and this iterator
template <class T>
class Periodic_3_triangulation_unique_facet_iterator_3
: public Filter_iterator<typename T::Facet_iterator, Domain_tester<T> >
{
typedef typename T::Facet Facet;
typedef typename T::Facet_iterator Facet_iterator;
typedef Filter_iterator<Facet_iterator, Domain_tester<T> > Base;
typedef Periodic_3_triangulation_unique_facet_iterator_3 Self;
public:
Periodic_3_triangulation_unique_facet_iterator_3() : Base() {}
Periodic_3_triangulation_unique_facet_iterator_3(const Base &b) : Base(b) {}
Self & operator++() { Base::operator++(); return *this; }
Self & operator--() { Base::operator--(); return *this; }
Self operator++(int) { Self tmp(*this); ++(*this); return tmp; }
Self operator--(int) { Self tmp(*this); --(*this); return tmp; }
operator Facet() const { return Base::base(); }
};
} // namespace CGAL
#endif // CGAL_PERIODIC_3_TRIANGULATION_ITERATORS_3_H

View File

@ -86,32 +86,158 @@ _test_unique_vertex_iterator( const Triangulation &T )
size_type n = 0;
for (Unique_vertex_iterator ovit = T.unique_vertices_begin();
ovit != T.unique_vertices_end(); ++ovit)
{
Vertex_handle vh = ovit; // Test the conversion.
n++;
const Vertex & v = *ovit; // Test operator*;
Cell_handle c = ovit->cell(); // Test operator->;
(void) vh;
(void) v;
(void) c;
}
ovit != T.unique_vertices_end(); ++ovit)
{
Vertex_handle vh = ovit; // Test the conversion.
++n;
const Vertex & v = *ovit; // Test operator*;
Cell_handle c = ovit->cell(); // Test operator->;
(void) vh;
(void) v;
(void) c;
}
assert( n == T.number_of_vertices() );
// Test Backward-ness of the iterators.
n=0;
n = 0;
for (Unique_vertex_iterator ovit = T.unique_vertices_end();
ovit != T.unique_vertices_begin(); --ovit)
{
Vertex_handle vh = ovit; // Test the conversion.
(void) vh;
n++;
}
ovit != T.unique_vertices_begin(); --ovit)
{
Vertex_handle vh = ovit; // Test the conversion.
(void) vh;
++n;
}
assert( n == T.number_of_vertices() );
return n;
}
template < class Triangulation >
typename Triangulation::size_type
_test_unique_edge_iterator( const Triangulation &T )
{
typedef typename Triangulation::size_type size_type;
typedef typename Triangulation::Edge Edge;
typedef typename Triangulation::Cell_handle Cell_handle;
typedef typename Triangulation::Unique_edge_iterator
Unique_edge_iterator;
size_type n = 0;
for (Unique_edge_iterator oeit = T.unique_edges_begin();
oeit != T.unique_edges_end(); ++oeit)
{
++n;
const Edge& e = *oeit; // Test operator*;
Cell_handle c = oeit->first; // Test operator->;
assert(c != Cell_handle());
(void) e;
(void) c;
}
assert( n == T.number_of_edges() );
// Test Backward-ness of the iterators.
n = 0;
for (Unique_edge_iterator oeit = T.unique_edges_end();
oeit != T.unique_edges_begin(); --oeit)
{
++n;
}
assert( n == T.number_of_edges() );
return n;
}
template < class Triangulation >
typename Triangulation::size_type
_test_unique_facet_iterator( const Triangulation &T )
{
typedef typename Triangulation::size_type size_type;
typedef typename Triangulation::Facet Facet;
typedef typename Triangulation::Cell_handle Cell_handle;
typedef typename Triangulation::Unique_facet_iterator
Unique_facet_iterator;
size_type n = 0;
for (Unique_facet_iterator ofit = T.unique_facets_begin();
ofit != T.unique_facets_end(); ++ofit)
{
++n;
const Facet& f = *ofit; // Test operator*;
Cell_handle c = ofit->first; // Test operator->;
assert(c != Cell_handle());
(void) f;
(void) c;
}
assert( n == T.number_of_facets() );
// Test Backward-ness of the iterators.
n = 0;
for (Unique_facet_iterator ofit = T.unique_facets_end();
ofit != T.unique_facets_begin(); --ofit)
{
++n;
}
assert( n == T.number_of_facets() );
return n;
}
template < class Triangulation >
typename Triangulation::size_type
_test_unique_cell_iterator( const Triangulation &T )
{
typedef typename Triangulation::size_type size_type;
typedef typename Triangulation::Cell Cell;
typedef typename Triangulation::Vertex_handle Vertex_handle;
typedef typename Triangulation::Cell_handle Cell_handle;
typedef typename Triangulation::Unique_cell_iterator
Unique_cell_iterator;
size_type n = 0;
for (Unique_cell_iterator ocit = T.unique_cells_begin();
ocit != T.unique_cells_end(); ++ocit)
{
Cell_handle ch = ocit; // Test the conversion.
n++;
const Cell& c = *ocit; // Test operator*;
Vertex_handle vh = ocit->vertex(0); // Test operator->;
(void) ch;
(void) c;
(void) vh;
}
assert( n == T.number_of_cells() );
// Test Backward-ness of the iterators.
n=0;
for (Unique_cell_iterator ocit = T.unique_cells_end();
ocit != T.unique_cells_begin(); --ocit)
{
Cell_handle ch = ocit; // Test the conversion.
(void) ch;
++n;
}
assert( n == T.number_of_cells() );
return n;
}
template < class Triangulation >
typename Triangulation::size_type
_test_triangulation_unique_iterator( const Triangulation &T )
{
typedef typename Triangulation::size_type size_type;
const size_type nc = _test_unique_cell_iterator(T);
const size_type nf = _test_unique_facet_iterator(T);
const size_type ne = _test_unique_edge_iterator(T);
const size_type nv = _test_unique_vertex_iterator(T);
assert((nv-ne+nf-nc) == 0);
return nv-ne+nf-nc;
}
template < class Triangulation >
typename Triangulation::size_type
_test_triangulation_iterator( const Triangulation &T )

View File

@ -479,10 +479,10 @@ _test_cls_periodic_3_triangulation_3(const PeriodicTriangulation &,
_test_vertex_iterator(PT3_deg);
_test_vertex_iterator(PT1_deg);
_test_unique_vertex_iterator(PT3);
_test_unique_vertex_iterator(PT1);
_test_unique_vertex_iterator(PT3_deg);
_test_unique_vertex_iterator(PT1_deg);
_test_triangulation_unique_iterator(PT3);
_test_triangulation_unique_iterator(PT1);
_test_triangulation_unique_iterator(PT3_deg);
_test_triangulation_unique_iterator(PT1_deg);
_test_triangulation_iterator(PT3);
_test_triangulation_iterator(PT1);

View File

@ -68,6 +68,9 @@ if(TARGET CGAL::Eigen3_support)
create_single_source_cgal_program("jet_pointer_as_property_map.cpp")
target_link_libraries(jet_pointer_as_property_map PUBLIC CGAL::Eigen3_support)
create_single_source_cgal_program("psp_jet_includes.cpp")
target_link_libraries(psp_jet_includes PUBLIC CGAL::Eigen3_support)
else()
message(STATUS "NOTICE: Some tests require Eigen 3.1 (or greater), and will not be compiled.")
endif()

View File

@ -2455,9 +2455,8 @@ bounded_error_squared_Hausdorff_distance_naive_impl(const TriangleMesh1& tm1,
/**
* \ingroup PMP_distance_grp
*
* returns an estimate on the Hausdorff distance between `tm1` and `tm2` that
* is at most `error_bound` away from the actual Hausdorff distance between
* the two given meshes.
* returns an estimate on the Hausdorff distance from `tm1` to `tm2` that
* is at most `error_bound` away from the actual Hausdorff distance from `tm1` to `tm2`.
*
* @tparam Concurrency_tag enables sequential versus parallel algorithm.
* Possible values are `Sequential_tag` and `Parallel_tag`.

View File

@ -3,13 +3,17 @@
#include <QColor>
inline QColor generate_color(double h, double s_min = 0.35)
#include <stdlib.h>
#include <iostream>
inline QColor generate_color(double h,
double s_min = 0.35)
{
std::size_t s_max=255;
if(h >0.8 && h < 0.95) //span of ugly pink, desaturates make it less garish IMO
std::size_t s_max = 255;
if(h > 0.8 && h < 0.95) // span of ugly pink, desaturates make it less garish IMO
s_max = 160;
std::size_t s = std::rand() % (s_max-static_cast<std::size_t>(s_min*255)) + static_cast<int>(s_min*255);
return QColor::fromHsvF(h,s/255.0,1.0);
return QColor::fromHsvF(h, s/255.0, 1.0);
}
@ -22,19 +26,23 @@ compute_color_map(QColor base_color,
qreal hue = base_color.hueF();
const qreal step = (static_cast<qreal>(1)) / nb_of_colors;
qreal h = hue==-1 ? 0
:hue;
for(unsigned i = 0; i < nb_of_colors; ++i) {
if (h!=-1) h += step;
if ( h > 1 ) { h -= 1; }
qreal h = (hue == -1) ? 0 : hue;
for(std::size_t i=0; i<nb_of_colors; ++i)
{
if(h != -1)
h += step;
if(h > 1)
h -= 1;
*out++ = generate_color(h);
}
return out;
}
inline QColor generate_random_color() {
inline QColor generate_random_color()
{
std::size_t h = static_cast<std::size_t>(std::rand() % 360);
return generate_color(h/359.0);
return generate_color(h / 359.0);
}
#endif
#endif // _COLOR_MAP_H

View File

@ -1440,7 +1440,7 @@ QList<int> MainWindow::getSelectedSceneItemIndices() const
void MainWindow::selectionChanged()
{
scene->setSelectedItemIndex(getSelectedSceneItemIndex());
scene->setSelectedItemsList(getSelectedSceneItemIndices());
scene->setSelectedItemIndices(getSelectedSceneItemIndices());
CGAL::Three::Scene_item* item = scene->item(getSelectedSceneItemIndex());
Q_FOREACH(CGAL::QGLViewer* vi, CGAL::QGLViewer::QGLViewerPool())
{
@ -2193,7 +2193,7 @@ void MainWindow::on_actionEraseAll_triggered()
QList<int> all_ids;
for(int i = 0; i < scene->numberOfEntries(); ++i)
all_ids.push_back(i);
scene->setSelectedItemsList(all_ids);
scene->setSelectedItemIndices(all_ids);
on_actionErase_triggered();
}

View File

@ -1,11 +1,16 @@
include(polyhedron_demo_macros)
qt5_wrap_ui(display_propertyUI_FILES Display_property.ui)
polyhedron_demo_plugin(display_property_plugin Display_property_plugin ${display_propertyUI_FILES} KEYWORDS Viewer)
target_link_libraries(display_property_plugin PUBLIC scene_surface_mesh_item
scene_points_with_normal_item
scene_color_ramp)
if(TARGET CGAL::Eigen3_support)
qt5_wrap_ui( display_propertyUI_FILES Display_property.ui )
polyhedron_demo_plugin(display_property_plugin Display_property_plugin ${display_propertyUI_FILES} KEYWORDS Viewer)
target_link_libraries(display_property_plugin
PUBLIC
scene_surface_mesh_item
scene_points_with_normal_item
scene_color_ramp
CGAL::Eigen3_support)
qt5_wrap_ui(heat_methodUI_FILES Heat_method.ui)
polyhedron_demo_plugin(heat_method_plugin Heat_method_plugin ${heat_methodUI_FILES} KEYWORDS Viewer)
target_link_libraries(heat_method_plugin PUBLIC scene_surface_mesh_item
scene_selection_item
scene_color_ramp
CGAL::Eigen3_support)
endif()

View File

@ -2,26 +2,202 @@
<ui version="4.0">
<class>DisplayPropertyWidget</class>
<widget class="QDockWidget" name="DisplayPropertyWidget">
<property name="enabled">
<bool>false</bool>
</property>
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>292</width>
<height>508</height>
<width>514</width>
<height>695</height>
</rect>
</property>
<property name="minimumSize">
<size>
<width>514</width>
<height>695</height>
</size>
</property>
<property name="windowTitle">
<string>Property Displaying</string>
<string>Property Display</string>
</property>
<widget class="QWidget" name="dockWidgetContents">
<layout class="QVBoxLayout" name="verticalLayout" stretch="0,0,0">
<item>
<layout class="QHBoxLayout" name="horizontalLayout_3" stretch="0,0">
<item>
<widget class="QScrollArea" name="scrollArea">
<property name="horizontalScrollBarPolicy">
<enum>Qt::ScrollBarAlwaysOff</enum>
<layout class="QGridLayout" name="gridLayout_3">
<item row="9" column="0" colspan="2">
<widget class="QPushButton" name="colorizeButton">
<property name="font">
<font>
<family>Cantarell</family>
<bold>true</bold>
</font>
</property>
<property name="text">
<string>Color Item</string>
</property>
</widget>
</item>
<item row="0" column="0" colspan="2">
<widget class="QGroupBox" name="propertyGroup">
<property name="title">
<string>Property</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_2">
<property name="leftMargin">
<number>6</number>
</property>
<property name="topMargin">
<number>6</number>
</property>
<property name="rightMargin">
<number>6</number>
</property>
<property name="bottomMargin">
<number>6</number>
</property>
<item>
<widget class="QComboBox" name="propertyBox">
<property name="sizeAdjustPolicy">
<enum>QComboBox::AdjustToContents</enum>
</property>
<item>
<property name="text">
<string>Smallest Angle Per Face</string>
</property>
</item>
<item>
<property name="text">
<string>Scaled Jacobian</string>
</property>
</item>
<item>
<property name="text">
<string>Heat Intensity</string>
</property>
</item>
<item>
<property name="text">
<string>Heat Intensity (Intrinsic Delaunay)</string>
</property>
</item>
</widget>
</item>
</layout>
</widget>
</item>
<item row="1" column="0">
<layout class="QGridLayout" name="ColoringGroup" columnstretch="50,50">
<item row="0" 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="1" column="0">
<widget class="QGroupBox" name="coloringChoiceGroup">
<property name="title">
<string>Color Visualization</string>
</property>
<layout class="QGridLayout" name="gridLayout_2" columnstretch="50,50">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item row="8" column="0">
<widget class="QRadioButton" name="randomColorsRadioButton">
<property name="text">
<string>Random colors</string>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QPushButton" name="minColorButton">
<property name="styleSheet">
<string notr="true"/>
</property>
<property name="text">
<string/>
</property>
</widget>
</item>
<item row="9" column="0">
<widget class="QLabel" name="initColorLabel">
<property name="text">
<string>First color</string>
</property>
</widget>
</item>
<item row="5" column="0">
<widget class="QLabel" name="maxColorLabel">
<property name="text">
<string>Max color</string>
</property>
</widget>
</item>
<item row="2" column="0" colspan="2">
<widget class="QRadioButton" name="colorRampRadioButton">
<property name="text">
<string>Color Ramp</string>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
<item row="9" column="1">
<widget class="QPushButton" name="initColorButton">
<property name="text">
<string/>
</property>
</widget>
</item>
<item row="5" column="1">
<widget class="QPushButton" name="maxColorButton">
<property name="text">
<string/>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QLabel" name="minColorLabel">
<property name="text">
<string>Min color</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item row="2" 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="0" column="1" rowspan="3">
<widget class="QScrollArea" name="scrollArea">
<property name="widgetResizable">
<bool>true</bool>
</property>
@ -30,12 +206,12 @@
<rect>
<x>0</x>
<y>0</y>
<width>127</width>
<height>430</height>
<width>236</width>
<height>397</height>
</rect>
</property>
<layout class="QVBoxLayout" name="verticalLayout_7">
<item>
<layout class="QGridLayout" name="gridLayout_5">
<item row="0" column="0" alignment="Qt::AlignHCenter">
<widget class="QLabel" name="legendLabel">
<property name="text">
<string>RAMP DISPLAYING</string>
@ -46,206 +222,70 @@
</widget>
</widget>
</item>
<item>
<layout class="QGridLayout" name="gridLayout">
<item row="4" column="0">
<widget class="QLabel" name="label_3">
<property name="text">
<string/>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QLabel" name="label_2">
<property name="text">
<string/>
</property>
</widget>
</item>
<item row="4" column="1">
<widget class="QPushButton" name="colorizeButton">
<property name="text">
<string>Colorize</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QTabWidget" name="colorChoiceWidget">
<property name="currentIndex">
<number>0</number>
</property>
<widget class="QWidget" name="ramp_tab">
<attribute name="title">
<string>Ramp</string>
</attribute>
<layout class="QVBoxLayout" name="verticalLayout_5">
<item>
<widget class="QGroupBox" name="groupBox_2">
<property name="title">
<string>Ramp Colors</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_3">
<item>
<widget class="QPushButton" name="minColorButton">
<property name="text">
<string>Color Min...</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="maxColorButton">
<property name="text">
<string>Color Max...</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
</layout>
</widget>
<widget class="QWidget" name="map_tab">
<attribute name="title">
<string>Map</string>
</attribute>
<layout class="QVBoxLayout" name="verticalLayout_6">
<item>
<widget class="QPushButton" name="initColorButton">
<property name="text">
<string>Initial Color...</string>
</property>
</widget>
</item>
</layout>
</widget>
</widget>
</item>
<item row="6" column="1">
<widget class="QPushButton" name="sourcePointsButton">
<property name="text">
<string>Select Source Points</string>
</property>
<property name="checkable">
<bool>true</bool>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QGroupBox" name="groupBox_3">
<property name="title">
<string>Zoom </string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_4">
<item>
<widget class="QPushButton" name="zoomToMinButton">
<property name="text">
<string>Zoom to min</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="zoomToMaxButton">
<property name="text">
<string>Zoom to max</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item row="1" column="1">
<widget class="QGroupBox" name="groupBox">
<property name="title">
<string>Ramp Extrema</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>
<widget class="DoubleEdit" name="minBox">
<property name="text">
<string>0.00</string>
</property>
</widget>
</item>
<item>
<widget class="DoubleEdit" name="maxBox">
<property name="text">
<string>2.00</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item row="7" column="1">
<widget class="QPushButton" name="deleteButton">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string>Delete Group</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout" stretch="0,0">
<item>
<spacer name="horizontalSpacer_2">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QComboBox" name="propertyBox">
<property name="sizeAdjustPolicy">
<enum>QComboBox::AdjustToContents</enum>
</property>
<item>
<property name="text">
<string>Smallest Angle Per Face</string>
</property>
</item>
<item>
<property name="text">
<string>Scaled Jacobian</string>
</property>
</item>
<item>
<property name="text">
<string>Heat Intensity</string>
</property>
</item>
<item>
<property name="text">
<string>Heat Intensity (Intrinsic Delaunay)</string>
</property>
</item>
</widget>
</item>
</layout>
</item>
<item>
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
<item row="11" column="0">
<widget class="QGroupBox" name="extremeValuesGroup">
<property name="enabled">
<bool>false</bool>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
<property name="title">
<string>Extreme Values</string>
</property>
</spacer>
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="0">
<widget class="QLabel" name="extremeValuesMinLabel">
<property name="text">
<string>Min Value</string>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="extremeValuesMaxLabel">
<property name="text">
<string>Max Value</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="DoubleEdit" name="maxBox">
<property name="text">
<string>2.00</string>
</property>
<property name="readOnly">
<bool>true</bool>
</property>
</widget>
</item>
<item row="2" column="2">
<widget class="QPushButton" name="zoomToMaxButton">
<property name="text">
<string>Zoom to max value</string>
</property>
</widget>
</item>
<item row="0" column="2">
<widget class="QPushButton" name="zoomToMinButton">
<property name="text">
<string>Zoom to min value</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="DoubleEdit" name="minBox">
<property name="text">
<string>0.00</string>
</property>
<property name="frame">
<bool>true</bool>
</property>
<property name="readOnly">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</widget>
</item>
</layout>
</widget>

View File

@ -0,0 +1,294 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>HeatMethodWidget</class>
<widget class="QDockWidget" name="HeatMethodWidget">
<property name="enabled">
<bool>true</bool>
</property>
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>365</width>
<height>708</height>
</rect>
</property>
<property name="minimumSize">
<size>
<width>365</width>
<height>708</height>
</size>
</property>
<property name="windowTitle">
<string>Heat Method</string>
</property>
<widget class="QWidget" name="dockWidgetContents">
<layout class="QGridLayout" name="gridLayout_3">
<item row="3" column="0">
<layout class="QGridLayout" name="coloringGroup" columnstretch="50,50">
<item row="2" column="0">
<spacer name="verticalSpacer_4">
<property name="enabled">
<bool>true</bool>
</property>
<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="0" column="1" rowspan="3">
<widget class="QScrollArea" name="scrollArea">
<property name="enabled">
<bool>true</bool>
</property>
<property name="widgetResizable">
<bool>true</bool>
</property>
<widget class="QWidget" name="scrollAreaWidgetContents">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>161</width>
<height>371</height>
</rect>
</property>
<layout class="QGridLayout" name="gridLayout_5">
<item row="0" column="0" alignment="Qt::AlignHCenter">
<widget class="QLabel" name="legendLabel">
<property name="enabled">
<bool>true</bool>
</property>
<property name="text">
<string>RAMP DISPLAYING</string>
</property>
</widget>
</item>
</layout>
</widget>
</widget>
</item>
<item row="1" column="0">
<widget class="QGroupBox" name="coloringChoiceGroup">
<property name="enabled">
<bool>true</bool>
</property>
<property name="title">
<string>Color Ramp</string>
</property>
<layout class="QGridLayout" name="gridLayout_2" columnstretch="50,50">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item row="2" column="0">
<widget class="QLabel" name="minColorLabel">
<property name="enabled">
<bool>true</bool>
</property>
<property name="text">
<string>Min color</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QPushButton" name="minColorButton">
<property name="enabled">
<bool>true</bool>
</property>
<property name="styleSheet">
<string notr="true"/>
</property>
<property name="text">
<string/>
</property>
</widget>
</item>
<item row="4" column="0">
<widget class="QLabel" name="maxColorLabel">
<property name="enabled">
<bool>true</bool>
</property>
<property name="text">
<string>Max color</string>
</property>
</widget>
</item>
<item row="4" column="1">
<widget class="QPushButton" name="maxColorButton">
<property name="enabled">
<bool>true</bool>
</property>
<property name="text">
<string/>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item row="0" column="0">
<spacer name="verticalSpacer">
<property name="enabled">
<bool>true</bool>
</property>
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
<item row="0" column="0" colspan="2">
<widget class="QGroupBox" name="methodGroup">
<property name="enabled">
<bool>true</bool>
</property>
<property name="title">
<string>Method</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_2">
<property name="leftMargin">
<number>6</number>
</property>
<property name="topMargin">
<number>6</number>
</property>
<property name="rightMargin">
<number>6</number>
</property>
<property name="bottomMargin">
<number>6</number>
</property>
<item>
<widget class="QComboBox" name="methodBox">
<property name="enabled">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item row="13" column="0">
<widget class="QGroupBox" name="extremeValueGroup">
<property name="enabled">
<bool>true</bool>
</property>
<property name="title">
<string>Extreme Value</string>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="1" column="2">
<widget class="QPushButton" name="zoomToMaxButton">
<property name="enabled">
<bool>true</bool>
</property>
<property name="text">
<string>Zoom to max value</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="extremeValueMaxLabel">
<property name="enabled">
<bool>true</bool>
</property>
<property name="text">
<string>Max Value</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="DoubleEdit" name="maxBox">
<property name="enabled">
<bool>true</bool>
</property>
<property name="text">
<string>0</string>
</property>
<property name="readOnly">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item row="11" column="0" colspan="2">
<widget class="QPushButton" name="estimateDistancesButton">
<property name="enabled">
<bool>true</bool>
</property>
<property name="font">
<font>
<family>Cantarell</family>
<bold>true</bold>
</font>
</property>
<property name="text">
<string>Estimate Geodesic Distances</string>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QGroupBox" name="sourcesGroup">
<property name="enabled">
<bool>true</bool>
</property>
<property name="title">
<string>Source Vertices</string>
</property>
<layout class="QGridLayout" name="gridLayout_4">
<item row="0" column="0">
<widget class="QPushButton" name="createSourceVerticesButton">
<property name="enabled">
<bool>true</bool>
</property>
<property name="toolTip">
<string extracomment="Use 'Shift + Left Click'"/>
</property>
<property name="toolTipDuration">
<number>1</number>
</property>
<property name="text">
<string>Create Source Vertices Selection Item</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
</layout>
</widget>
</widget>
<customwidgets>
<customwidget>
<class>DoubleEdit</class>
<extends>QLineEdit</extends>
<header>CGAL_double_edit.h</header>
</customwidget>
</customwidgets>
<resources/>
<connections/>
</ui>

View File

@ -0,0 +1,821 @@
#include "ui_Heat_method.h"
#include "Color_ramp.h"
#include "id_printing.h"
#include "Messages_interface.h"
#include "triangulate_primitive.h"
#include "Scene.h"
#include "Scene_polyhedron_selection_item.h"
#include "Scene_surface_mesh_item.h"
#include <CGAL/Three/Polyhedron_demo_plugin_interface.h>
#include <CGAL/Three/Polyhedron_demo_plugin_helper.h>
#include <CGAL/Three/Three.h>
#include <CGAL/Three/Triangle_container.h>
#include <CGAL/Buffer_for_vao.h>
#include <CGAL/boost/bimap.hpp>
#include <CGAL/boost/graph/helpers.h>
#include <CGAL/Dynamic_property_map.h>
#include <CGAL/Heat_method_3/Surface_mesh_geodesic_distances_3.h>
#include <QAbstractItemView>
#include <QAction>
#include <QApplication>
#include <QColor>
#include <QColorDialog>
#include <QInputDialog>
#include <QMainWindow>
#include <QMessageBox>
#include <QObject>
#include <QPalette>
#include <QStyleFactory>
// @fixme multiple selection items are broken, so don't create a selection item if there is already one
using namespace CGAL::Three;
Viewer_interface* (&getActiveViewer)() = Three::activeViewer;
class Scene_heat_item
: public Scene_item_rendering_helper
{
Q_OBJECT
private:
Scene_surface_mesh_item* parent;
SMesh* sm;
mutable std::vector<float> verts;
mutable std::vector<float> normals;
mutable std::vector<unsigned int> idx;
mutable std::vector<float> colors;
mutable std::vector<float> heat_values;
mutable std::size_t nb_idx;
public:
Scene_heat_item(Scene_surface_mesh_item* item)
: parent(item), sm(item->face_graph())
{
CGAL_precondition(is_triangle_mesh(*sm));
setTriangleContainer(0, new Triangle_container(Viewer_interface::PROGRAM_HEAT_INTENSITY, true));
setRenderingMode(Gouraud);
}
~Scene_heat_item(){}
Scene_item* clone() const Q_DECL_OVERRIDE { return nullptr; }
QString toolTip() const Q_DECL_OVERRIDE{ return QString(); }
Scene_surface_mesh_item* getParent() { return parent; }
bool isEmpty() const Q_DECL_OVERRIDE { return false; }
SMesh* face_graph() { return sm; }
void initializeBuffers(Viewer_interface *viewer) const Q_DECL_OVERRIDE
{
getTriangleContainer(0)->initializeBuffers(viewer);
getTriangleContainer(0)->setIdxSize(nb_idx);
verts.resize(0);
verts.shrink_to_fit();
normals.resize(0);
normals.shrink_to_fit();
colors.resize(0);
colors.shrink_to_fit();
idx.clear();
idx.shrink_to_fit();
}
void draw(Viewer_interface *viewer) const Q_DECL_OVERRIDE
{
if(!visible())
return;
if(!isInit(viewer))
initGL(viewer);
if(getBuffersFilled() && !getBuffersInit(viewer))
{
initializeBuffers(viewer);
setBuffersInit(viewer, true);
}
if(!getBuffersFilled())
{
computeElements();
initializeBuffers(viewer);
}
getTriangleContainer(0)->setAlpha(1.0f);
getTriangleContainer(0)->draw(viewer, false);
}
void compute_bbox() const Q_DECL_OVERRIDE
{
setBbox(parent->bbox());
}
virtual bool supportsRenderingMode(RenderingMode m) const Q_DECL_OVERRIDE
{
return (m == Gouraud);
}
virtual void invalidateOpenGLBuffers() Q_DECL_OVERRIDE
{
setBuffersFilled(false);
compute_bbox();
getTriangleContainer(0)->reset_vbos(NOT_INSTANCED);
}
void computeElements() const Q_DECL_OVERRIDE
{
typedef CGAL::Buffer_for_vao<float, unsigned int> CPF;
QApplication::setOverrideCursor(Qt::WaitCursor);
auto vpm = CGAL::get(CGAL::vertex_point, *sm);
auto vnormals = sm->property_map<vertex_descriptor, EPICK::Vector_3>("v:normal").first;
auto [vcolors, vcolors_found] = sm->property_map<vertex_descriptor, CGAL::IO::Color>("v:color");
CGAL_assertion(vcolors_found);
auto [vdist, vdist_found] = sm->property_map<vertex_descriptor, double>("v:HM_Plugin_heat_intensity");
CGAL_assertion(vdist_found);
verts.clear();
normals.clear();
idx.clear();
colors.clear();
idx.reserve(3 * num_faces(*sm));
for(face_descriptor fd : faces(*sm))
{
for(halfedge_descriptor hd : halfedges_around_face(halfedge(fd, *sm),*sm))
idx.push_back(source(hd, *sm));
}
const CGAL::qglviewer::Vec& o = static_cast<Viewer_interface*>(CGAL::QGLViewer::QGLViewerPool().first())->offset();
EPICK::Vector_3 offset(o.x, o.y, o.z);
for(vertex_descriptor vd : vertices(*sm))
{
const CGAL::IO::Color& c = vcolors[vd];
colors.push_back(float(c.red()) / 255);
colors.push_back(float(c.green()) / 255);
colors.push_back(float(c.blue()) / 255);
const EPICK::Point_3& p = get(vpm, vd) + offset;
CPF::add_point_in_buffer(p, verts);
const EPICK::Vector_3& n = vnormals[vd];
CPF::add_normal_in_buffer(n, normals);
heat_values.push_back(vdist[vd]);
}
nb_idx = idx.size();
getTriangleContainer(0)->allocate(Triangle_container::Vertex_indices, idx.data(),
static_cast<int>(idx.size()*sizeof(unsigned int)));
getTriangleContainer(0)->allocate(Triangle_container::Smooth_vertices, verts.data(),
static_cast<int>(num_vertices(*sm)*3*sizeof(float)));
getTriangleContainer(0)->allocate(Triangle_container::Smooth_normals, normals.data(),
static_cast<int>(num_vertices(*sm)*3*sizeof(float)));
getTriangleContainer(0)->allocate(Triangle_container::VColors, colors.data(),
static_cast<int>(colors.size()*sizeof(float)));
getTriangleContainer(0)->allocate(Triangle_container::Distances, heat_values.data(),
static_cast<int>(heat_values.size()*sizeof(float)));
compute_bbox();
setBuffersFilled(true);
QApplication::restoreOverrideCursor();
}
}; // class Scene_heat_item
class DockWidget
: public QDockWidget,
public Ui::HeatMethodWidget
{
public:
DockWidget(const QString& name, QWidget *parent)
: QDockWidget(name, parent)
{
setupUi(this);
}
};
class Heat_method_plugin
: public QObject,
public Polyhedron_demo_plugin_helper
{
Q_OBJECT
Q_INTERFACES(CGAL::Three::Polyhedron_demo_plugin_interface)
Q_PLUGIN_METADATA(IID "com.geometryfactory.PolyhedronDemo.PluginInterface/1.0")
using Vertex_distance_map = SMesh::Property_map<vertex_descriptor, double>;
using Heat_method = CGAL::Heat_method_3::Surface_mesh_geodesic_distances_3<SMesh>;
using Heat_method_idt = CGAL::Heat_method_3::Surface_mesh_geodesic_distances_3<SMesh, CGAL::Heat_method_3::Intrinsic_Delaunay>;
private:
QAction* actionHeatMethod;
DockWidget* dock_widget;
// coloring choice and legend
double rm = 1.;
double gm = 0.;
double bm = 0.;
double rM = 0.;
double gM = 1.;
double bM = 0.;
Color_ramp color_ramp;
QPixmap legend;
// tracking which scene items have which sources, and which heat method builders
boost::bimap<boost::bimaps::set_of<Scene_surface_mesh_item*>,
boost::bimaps::set_of<Scene_polyhedron_selection_item*> > item_source_vertices;
// the point of storing this is that in the Heat Method(s), a number of computations are only
// dependent on the mesh, and not the sources, and such can be performed just once.
std::unordered_map<Scene_surface_mesh_item*, Heat_method*> heat_methods;
std::unordered_map<Scene_surface_mesh_item*, Heat_method_idt*> idt_heat_methods;
public:
bool applicable(QAction*) const Q_DECL_OVERRIDE
{
// Single item => it must be a mesh and the selection item will be created through the plugin's button
if(scene->selectionIndices().size() == 1)
{
Scene_item* item = scene->item(scene->mainSelectionIndex());
return qobject_cast<Scene_surface_mesh_item*>(item);
}
// Two items => it must be a surface mesh and a selection item (in any order)
else if(scene->selectionIndices().size() == 2)
{
Scene_item* item1 = scene->item(scene->selectionIndices().front());
Scene_item* item2 = scene->item(scene->selectionIndices().back());
return ((qobject_cast<Scene_surface_mesh_item*>(item1) &&
qobject_cast<Scene_polyhedron_selection_item*>(item2)) ||
(qobject_cast<Scene_polyhedron_selection_item*>(item1) &&
qobject_cast<Scene_surface_mesh_item*>(item2)));
}
return false;
}
QList<QAction*> actions() const Q_DECL_OVERRIDE
{
return QList<QAction*>() << actionHeatMethod;
}
void init(QMainWindow* mw,
Scene_interface* sc,
Messages_interface*) Q_DECL_OVERRIDE
{
this->scene = sc;
this->mw = mw;
actionHeatMethod = new QAction(QString("Heat Method"), mw);
actionHeatMethod->setProperty("submenuName", "Color");
connect(actionHeatMethod, SIGNAL(triggered()),
this, SLOT(openDialog()));
Scene* scene_item = static_cast<Scene*>(scene);
connect(scene_item, SIGNAL(itemIndicesSelected(QList<int>)),
this, SLOT(onItemIndicesSelected(QList<int>)));
// Dock Widget
dock_widget = new DockWidget("Heat Method", mw);
addDockWidget(dock_widget);
dock_widget->setVisible(false);
connect(dock_widget->methodBox, SIGNAL(currentIndexChanged(int)),
this, SLOT(onNewMethodSelected(int)));
dock_widget->methodBox->addItems({"Heat Method",
"Heat Method (Intrinsic Delaunay)"});
connect(dock_widget->createSourceVerticesButton, SIGNAL(clicked()),
this, SLOT(createSourceVerticesSelectionItem()));
QPalette palette(Qt::red);
dock_widget->minColorButton->setPalette(palette);
dock_widget->minColorButton->setStyle(QStyleFactory::create("Fusion"));
dock_widget->minColorButton->update();
palette = QPalette(Qt::green);
dock_widget->maxColorButton->setPalette(palette);
dock_widget->maxColorButton->setStyle(QStyleFactory::create("Fusion"));
dock_widget->maxColorButton->update();
// lambda to generate the three connect(), for each color button (min, max, map)
auto connect_color_buttons = [this](QPushButton* colorButton,
double& r, double& g, double& b)
{
connect(colorButton, &QPushButton::pressed,
this, [this, colorButton, &r, &g, &b]()
{
QColor color = QColorDialog::getColor();
if(!color.isValid())
return;
r = color.redF();
g = color.greenF();
b = color.blueF();
QPalette palette(color);
colorButton->setPalette(palette);
colorButton->update();
displayRampLegend();
});
};
connect_color_buttons(dock_widget->minColorButton, rm, gm, bm);
connect_color_buttons(dock_widget->maxColorButton, rM, gM, bM);
// Main action connection
connect(dock_widget->estimateDistancesButton, SIGNAL(clicked(bool)),
this, SLOT(estimateDistances()));
// Post coloring connection
connect(dock_widget->zoomToMaxButton, &QPushButton::pressed,
this, &Heat_method_plugin::on_zoomToMaxButton_pressed);
}
private Q_SLOTS:
void openDialog()
{
if(!dock_widget->isVisible())
dock_widget->show();
dock_widget->raise();
}
void closure() Q_DECL_OVERRIDE
{
dock_widget->hide();
}
private:
void disableExtremeValue()
{
dock_widget->extremeValueGroup->setEnabled(false);
dock_widget->zoomToMaxButton->setEnabled(false);
}
void enableExtremeValue()
{
dock_widget->extremeValueGroup->setEnabled(true);
dock_widget->zoomToMaxButton->setEnabled(true);
}
void resetExtremeValue()
{
dock_widget->maxBox->setRange(0, 99999999);
dock_widget->maxBox->setValue(0);
}
void displayRampLegend()
{
color_ramp = Color_ramp(rm, rM, gm, gM, bm, bM);
const int height = 256;
const int width = 140;
const int cell_width = width / 3;
const int top_margin = 5;
const int left_margin = 5;
const int drawing_height = height - 2*top_margin;
const int text_height = 20;
legend = QPixmap(width, height + text_height);
legend.fill(QColor(200, 200, 200));
QPainter painter(&legend);
painter.setPen(Qt::black);
painter.setBrush(QColor(200, 200, 200));
const double min_value = 0;
const double max_value = dock_widget->maxBox->value();
// Build legend data
std::vector<double> graduations(100);
for(int i=0; i<100; ++i)
graduations[i] = i / 100.0;
int i = 0;
for(std::vector<double>::iterator it = graduations.begin(), end = graduations.end(); it != end; ++it, i+=2)
{
QColor color(255 * color_ramp.r(*it),
255 * color_ramp.g(*it),
255 * color_ramp.b(*it));
painter.fillRect(left_margin, drawing_height - top_margin - i, cell_width, 2, color);
}
// draw right vertical line
painter.setPen(Qt::blue);
painter.drawLine(QPoint(left_margin + cell_width + 10,
drawing_height - top_margin + 2),
QPoint(left_margin + cell_width + 10,
drawing_height - top_margin - static_cast<int>(graduations.size())*2 + 2));
// draw min value and max value
painter.setPen(Qt::blue);
QRect min_text_rect(left_margin + cell_width + 10,
drawing_height - top_margin, 100, text_height);
painter.drawText(min_text_rect, Qt::AlignCenter, QObject::tr("%1").arg(min_value, 0, 'f', 3));
QRect max_text_rect(left_margin + cell_width + 10,
drawing_height - top_margin - 200, 100, text_height);
painter.drawText(max_text_rect, Qt::AlignCenter, QObject::tr("%1").arg(max_value, 0, 'f', 3));
dock_widget->legendLabel->setPixmap(legend);
}
private Q_SLOTS:
// Called when new geometric objects are selected in the scene
void onItemIndicesSelected(QList<int> selected_items)
{
resetExtremeValue();
dock_widget->setEnabled(false);
Scene_surface_mesh_item* sm_item = nullptr;
Scene_polyhedron_selection_item* source_vertices = nullptr;
if(selected_items.size() == 1)
{
Scene_item* item = scene->item(scene->mainSelectionIndex());
source_vertices = qobject_cast<Scene_polyhedron_selection_item*>(item);
if(source_vertices)
{
// While selecting a selection item, enable coloring if the selection item is linked to a sm_item
if(item_source_vertices.right.count(source_vertices) == 0)
return;
dock_widget->setEnabled(true);
dock_widget->createSourceVerticesButton->setEnabled(false);
dock_widget->estimateDistancesButton->setEnabled(true);
disableExtremeValue();
return;
}
else if(qobject_cast<Scene_heat_item*>(item))
{
dock_widget->setEnabled(true);
dock_widget->createSourceVerticesButton->setEnabled(false);
dock_widget->estimateDistancesButton->setEnabled(false);
disableExtremeValue();
return;
}
sm_item = qobject_cast<Scene_surface_mesh_item*>(item);
}
else if(selected_items.size() == 2)
{
Scene_item* item1 = scene->item(selected_items.front());
Scene_item* item2 = scene->item(selected_items.back());
sm_item = qobject_cast<Scene_surface_mesh_item*>(item1);
source_vertices = qobject_cast<Scene_polyhedron_selection_item*>(item2);
if(!sm_item)
{
sm_item = qobject_cast<Scene_surface_mesh_item*>(item2);
source_vertices = qobject_cast<Scene_polyhedron_selection_item*>(item1);
}
}
if(!sm_item)
return;
dock_widget->setEnabled(true);
const bool has_sources = (source_vertices || item_source_vertices.left.count(sm_item) != 0);
dock_widget->estimateDistancesButton->setEnabled(has_sources);
dock_widget->createSourceVerticesButton->setEnabled(!has_sources);
disableExtremeValue();
}
// This function is only called if the index actually changed (doesn't trigger
// if you click again the item)
void onNewMethodSelected(int method_index)
{
resetExtremeValue(); // reset extreme value before the legend to get the proper values
displayRampLegend();
if(method_index >= 0 && method_index < dock_widget->methodBox->count()) // valid method
{
dock_widget->setEnabled(true);
disableExtremeValue(); // only available after displaying geodesic distances
}
else // no or broken method?
{
dock_widget->setEnabled(false);
dock_widget->methodBox->setEnabled(true);
}
}
private:
bool displayHeatIntensity(Scene_surface_mesh_item* sm_item,
Scene_polyhedron_selection_item* source_vertices,
const bool use_iDT = false)
{
SMesh& mesh = *sm_item->face_graph();
SMesh::Property_map<vertex_descriptor, double> heat_intensity =
mesh.add_property_map<vertex_descriptor, double>("v:HM_Plugin_heat_intensity", 0).first;
auto initialize_hm_map = [this, sm_item, &mesh] (auto*& hm_ptr, auto& hm_map) -> void
{
using Method = std::decay_t<decltype(*hm_ptr)>;
auto it = hm_map.find(sm_item);
if(it != hm_map.end()) // method already exists
{
hm_ptr = it->second;
for(vertex_descriptor v : vertices(mesh))
hm_ptr->remove_source(v);
}
else
{
hm_ptr = new Method(mesh);
hm_map[sm_item] = hm_ptr;
}
connect(sm_item, &Scene_surface_mesh_item::aboutToBeDestroyed,
this, [this, sm_item, &hm_map]()
{
item_source_vertices.left.erase(sm_item);
auto it = hm_map.find(sm_item);
if(it == hm_map.end())
return;
delete it->second;
hm_map.erase(it);
});
};
Heat_method* hm = nullptr;
Heat_method_idt* hm_idt = nullptr;
if(use_iDT)
initialize_hm_map(hm_idt, idt_heat_methods);
else
initialize_hm_map(hm, heat_methods);
for(auto v : source_vertices->selected_vertices)
{
if(use_iDT)
hm_idt->add_source(v);
else
hm->add_source(v);
}
if(use_iDT)
hm_idt->estimate_geodesic_distances(heat_intensity);
else
hm->estimate_geodesic_distances(heat_intensity);
// Post treatment
double max = 0;
for(vertex_descriptor v : vertices(mesh))
{
double hi = heat_intensity[v];
if(hi > max)
max = hi;
}
displayRampLegend();
auto [vcolors, vcolors_added] = mesh.add_property_map<vertex_descriptor, CGAL::IO::Color >("v:color", CGAL::IO::Color());
for(vertex_descriptor v : vertices(mesh))
{
double h = heat_intensity[v] / max;
CGAL::IO::Color color(255 * color_ramp.r(h),
255 * color_ramp.g(h),
255 * color_ramp.b(h));
vcolors[v] = color;
}
// Create the colored item
Scene_heat_item* heat_item = new Scene_heat_item(sm_item);
heat_item->setName(tr("%1 (distance isolines)").arg(sm_item->name()));
heat_item->setVisible(false);
sm_item->invalidateOpenGLBuffers();
sm_item->setRenderingMode(GouraudPlusEdges);
sm_item->redraw();
scene->addItem(heat_item);
scene->setSelectedItem(scene->item_id(sm_item));
// any change of sm_item destroys everything
connect(sm_item, &Scene_surface_mesh_item::itemChanged,
this, [this, sm_item, heat_item]()
{
sm_item->resetColors();
removePluginProperties(sm_item);
scene->erase(scene->item_id(heat_item));
onItemIndicesSelected(scene->selectionIndices());
});
connect(sm_item, &Scene_surface_mesh_item::aboutToBeDestroyed,
this, [this, heat_item]()
{
scene->erase(scene->item_id(heat_item));
onItemIndicesSelected(scene->selectionIndices());
});
// here because if it's put above, the setSelectedItem() might reset the value
dock_widget->maxBox->setValue(max);
return true;
}
private Q_SLOTS:
void estimateDistances()
{
// Get the mesh and source vertices items
Scene_surface_mesh_item* sm_item = nullptr;
Scene_polyhedron_selection_item* source_vertices = nullptr;
if(scene->selectionIndices().size() == 1)
{
Scene_item* item = scene->item(scene->mainSelectionIndex());
sm_item = qobject_cast<Scene_surface_mesh_item*>(item);
if(sm_item)
{
// a surface mesh item is selected, an existing associated selection item must exist
source_vertices = item_source_vertices.left.at(sm_item);
}
else
{
// a selection item is selected, an existing associated mesh item must exist
source_vertices = qobject_cast<Scene_polyhedron_selection_item*>(item);
if(source_vertices)
sm_item = item_source_vertices.right.at(source_vertices);
}
}
else if(scene->selectionIndices().size() == 2)
{
// two items, for (possibly unlinked) sm_item and its associated selection
Scene_item* item1 = scene->item(scene->selectionIndices().front());
Scene_item* item2 = scene->item(scene->selectionIndices().back());
sm_item = qobject_cast<Scene_surface_mesh_item*>(item1);
source_vertices = qobject_cast<Scene_polyhedron_selection_item*>(item2);
if(!sm_item)
{
sm_item = qobject_cast<Scene_surface_mesh_item*>(item2);
source_vertices = qobject_cast<Scene_polyhedron_selection_item*>(item1);
}
link_mesh_and_selection(sm_item, source_vertices);
}
else
{
QMessageBox::critical(mw, "Error","Unsupported selection of items.");
return;
}
CGAL_assertion(sm_item && source_vertices);
if(!is_triangle_mesh(*sm_item->face_graph()))
{
QApplication::restoreOverrideCursor();
QMessageBox::critical(mw, "Error","The mesh must be triangulated.");
return;
}
if(source_vertices->selected_vertices.empty())
{
QApplication::restoreOverrideCursor();
QMessageBox::critical(mw, "Error","At least one source vertex is required.");
return;
}
QApplication::setOverrideCursor(Qt::WaitCursor);
enableExtremeValue();
const std::string& method_name = dock_widget->methodBox->currentText().toStdString();
if(method_name == "Heat Method")
displayHeatIntensity(sm_item, source_vertices);
else if(method_name == "Heat Method (Intrinsic Delaunay)")
displayHeatIntensity(sm_item, source_vertices, true /*use IDT*/);
// @todo emit a new SIGNAL on successful coloring, something like "colorChanged()"
// itemChanged is too strong and would conflict with the connection below
sm_item->invalidateOpenGLBuffers();
sm_item->redraw();
QApplication::restoreOverrideCursor();
}
private:
void removePluginProperty(Scene_item* item,
const std::string& property_name)
{
Scene_surface_mesh_item* sm_item = qobject_cast<Scene_surface_mesh_item*>(item);
if(!sm_item)
return;
SMesh* sm = sm_item->face_graph();
if(sm == nullptr)
return;
// Here we only target the property maps added by this plugin, so 'double' is fine
SMesh::Property_map<face_descriptor, double> property;
bool found;
std::tie(property, found) = sm->property_map<face_descriptor, double>(property_name);
if(found)
sm->remove_property_map(property);
}
void removePluginProperties(Scene_item* item)
{
removePluginProperty(item, "v:HM_Plugin_heat_intensity");
}
private Q_SLOTS:
// deletion of the selection item removes the pair from the map
void link_mesh_and_selection(Scene_surface_mesh_item* sm_item,
Scene_polyhedron_selection_item* source_vertices)
{
item_source_vertices.left.insert(std::make_pair(sm_item, source_vertices));
connect(source_vertices, &Scene_polyhedron_selection_item::aboutToBeDestroyed,
this, [this, sm_item]()
{
item_source_vertices.left.erase(sm_item);
onItemIndicesSelected(scene->selectionIndices());
});
}
void createSourceVerticesSelectionItem()
{
Scene_item* item = scene->item(scene->mainSelectionIndex());
Scene_surface_mesh_item* sm_item = qobject_cast<Scene_surface_mesh_item*>(item);
if(!sm_item)
{
QMessageBox::warning(mw, "Warning", "Select a surface mesh to add source vertices");
dock_widget->createSourceVerticesButton->setChecked(false);
return;
}
CGAL_assertion(item_source_vertices.left.count(sm_item) == 0);
Scene_polyhedron_selection_item* source_vertices = new Scene_polyhedron_selection_item(sm_item, mw);
source_vertices->setName(tr("%1 (source vertices)").arg(sm_item->name()));
scene->addItem(source_vertices);
link_mesh_and_selection(sm_item, source_vertices);
dock_widget->createSourceVerticesButton->setEnabled(false);
dock_widget->estimateDistancesButton->setEnabled(true);
}
private Q_SLOTS:
void on_zoomToMaxButton_pressed()
{
Scene_surface_mesh_item* sm_item = nullptr;
if(scene->selectionIndices().size() == 1)
{
Scene_item* item = scene->item(scene->mainSelectionIndex());
sm_item = qobject_cast<Scene_surface_mesh_item*>(item);
}
else if(scene->selectionIndices().size() == 2)
{
Scene_item* item1 = scene->item(scene->selectionIndices().front());
Scene_item* item2 = scene->item(scene->selectionIndices().back());
sm_item = qobject_cast<Scene_surface_mesh_item*>(item1);
if(!sm_item)
sm_item = qobject_cast<Scene_surface_mesh_item*>(item2);
}
const SMesh& mesh = *(sm_item->face_graph());
auto [heat_intensity, found] = mesh.property_map<vertex_descriptor, double>("v:HM_Plugin_heat_intensity");
CGAL_assertion(found);
double max = 0;
vertex_descriptor max_v = boost::graph_traits<SMesh>::null_vertex();
for(vertex_descriptor v : vertices(mesh))
{
if(heat_intensity[v] > max)
{
max = heat_intensity[v];
max_v = v;
}
}
CGAL_assertion(max_v != boost::graph_traits<SMesh>::null_vertex());
face_descriptor unused_fd;
Point_3 unused_p;
::zoomToId(mesh,
QString("v%1").arg(max_v),
getActiveViewer(),
unused_fd, unused_p);
}
};
#include "Heat_method_plugin.moc"

View File

@ -217,7 +217,7 @@ void Polyhedron_demo_join_and_split_polyhedra_plugin::on_actionColorConnectedCom
item->computeItemColorVectorAutomatically(true);
item->invalidateOpenGLBuffers();
item->setProperty("NbPatchIds", nb_patch_ids);
scene->itemChanged(item);
scene->itemChanged(item); // @todo emits
}
else
{

View File

@ -7,21 +7,20 @@
#include <CGAL/boost/graph/properties.h>
#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
typedef CGAL::Exact_predicates_inexact_constructions_kernel EPICK;
typedef EPICK::Point_3 Point_3;
typedef CGAL::Surface_mesh<Point_3> SMesh;
typedef boost::graph_traits<SMesh>::face_descriptor face_descriptor;
typedef boost::graph_traits<SMesh>::vertex_descriptor vertex_descriptor;
typedef boost::graph_traits<SMesh>::halfedge_descriptor halfedge_descriptor;
namespace boost {
template <typename P>
struct property_map<CGAL::Surface_mesh<P>, CGAL::vertex_selection_t>
{
typedef typename boost::graph_traits<CGAL::Surface_mesh<P> >::vertex_descriptor vertex_descriptor;
typedef typename CGAL::Surface_mesh<P>::template Property_map<vertex_descriptor, int> type;
@ -32,7 +31,6 @@ struct property_map<CGAL::Surface_mesh<P>, CGAL::vertex_selection_t>
template <typename P>
struct property_map<CGAL::Surface_mesh<P>, CGAL::face_selection_t>
{
typedef typename boost::graph_traits<CGAL::Surface_mesh<P> >::face_descriptor face_descriptor;
typedef typename CGAL::Surface_mesh<P>::template Property_map<face_descriptor, int> type;
@ -41,11 +39,11 @@ struct property_map<CGAL::Surface_mesh<P>, CGAL::face_selection_t>
} // namespace boost
namespace CGAL {
template <typename P, typename Property_tag>
struct Get_pmap_of_surface_mesh_ {
struct Get_pmap_of_surface_mesh_
{
typedef typename boost::property_map<Surface_mesh<P>, Property_tag >::type type;
};

View File

@ -172,20 +172,22 @@ Scene::replaceItem(Scene::Item_id index, CGAL::Three::Scene_item* item, bool emi
Scene::Item_id
Scene::erase(Scene::Item_id index)
{
if(index <0 || index >= numberOfEntries())
if(index < 0 || index >= numberOfEntries())
return -1;
CGAL::Three::Scene_item* item = m_entries[index];
if(qobject_cast<Scene_group_item*>(item))
{
setSelectedItemsList(QList<Scene_interface::Item_id>()<<item_id(item));
setSelectedItemIndices(QList<Scene_interface::Item_id>() << item_id(item));
return erase(selectionIndices());
}
m_groups.removeAll(index);
if(item->parentGroup()
&& item->parentGroup()->isChildLocked(item))
if(item->parentGroup() && item->parentGroup()->isChildLocked(item))
return -1;
//clears the Scene_view
// clears the Scene_view
clear();
index_map.clear();
if(item->parentGroup())
@ -286,12 +288,12 @@ Scene::erase(QList<int> indices)
void Scene::remove_item_from_groups(Scene_item* item)
{
CGAL::Three::Scene_group_item* group = item->parentGroup();
if(group)
{
group->removeChild(item);
children.push_back(item_id(item));
}
CGAL::Three::Scene_group_item* group = item->parentGroup();
if(group)
{
group->removeChild(item);
children.push_back(item_id(item));
}
}
Scene::~Scene()
{
@ -315,19 +317,19 @@ Scene::~Scene()
CGAL::Three::Scene_item*
Scene::item(Item_id index) const
{
return m_entries.value(index); // QList::value checks bounds
return m_entries.value(index); // QList::value checks bounds
}
Scene::Item_id
Scene::item_id(CGAL::Three::Scene_item* scene_item) const
{
return m_entries.indexOf(scene_item);
return m_entries.indexOf(scene_item);
}
int
Scene::numberOfEntries() const
{
return m_entries.size();
return m_entries.size();
}
// Duplicate a scene item.
@ -335,20 +337,23 @@ Scene::numberOfEntries() const
Scene::Item_id
Scene::duplicate(Item_id index)
{
if(index < 0 || index >= m_entries.size())
return -1;
if(index < 0 || index >= m_entries.size())
return -1;
const CGAL::Three::Scene_item* item = m_entries[index];
CGAL::Three::Scene_item* new_item = item->clone();
if(new_item) {
new_item->setName(tr("%1 (copy)").arg(item->name()));
new_item->setColor(item->color());
new_item->setVisible(item->visible());
addItem(new_item);
return m_entries.size() - 1;
}
else
return -1;
const CGAL::Three::Scene_item* item = m_entries[index];
CGAL::Three::Scene_item* new_item = item->clone();
if(new_item)
{
new_item->setName(tr("%1 (copy)").arg(item->name()));
new_item->setColor(item->color());
new_item->setVisible(item->visible());
addItem(new_item);
return m_entries.size() - 1;
}
else
{
return -1;
}
}
void Scene::initializeGL(CGAL::Three::Viewer_interface* viewer)
@ -486,33 +491,33 @@ void Scene::initializeGL(CGAL::Three::Viewer_interface* viewer)
void Scene::s_itemAboutToBeDestroyed(CGAL::Three::Scene_item *rmv_itm)
{
Q_FOREACH(CGAL::Three::Scene_item* item, m_entries)
{
if(item == rmv_itm)
item->itemAboutToBeDestroyed(item);
}
Q_FOREACH(CGAL::Three::Scene_item* item, m_entries)
{
if(item == rmv_itm)
item->itemAboutToBeDestroyed(item);
}
}
bool
Scene::keyPressEvent(QKeyEvent* e){
bool res=false;
for (QList<int>::iterator it=selected_items_list.begin(),endit=selected_items_list.end();
it!=endit;++it)
{
CGAL::Three::Scene_item* item=m_entries[*it];
res |= item->keyPressEvent(e);
}
return res;
Scene::keyPressEvent(QKeyEvent* e)
{
bool res = false;
Q_FOREACH(int i, selected_items_list)
{
CGAL::Three::Scene_item* item = m_entries[i];
res |= item->keyPressEvent(e);
}
return res;
}
void
Scene::draw(CGAL::Three::Viewer_interface* viewer)
{
draw_aux(false, viewer);
draw_aux(false, viewer);
}
void
Scene::drawWithNames(CGAL::Three::Viewer_interface* viewer)
{
draw_aux(true, viewer);
draw_aux(true, viewer);
}
bool item_should_be_skipped_in_draw(Scene_item* item) {
@ -615,12 +620,10 @@ void Scene::renderWireScene(const QList<Scene_interface::Item_id> &items,
viewer->setGlPointSize(2.f);
if(index == selected_item || selected_items_list.contains(index))
{
item.selection_changed(true);
}
else
{
item.selection_changed(false);
}
item.drawEdges(viewer);
@ -1122,12 +1125,14 @@ bool Scene::dropMimeData(const QMimeData * /*data*/,
if(group)
{
Q_FOREACH(int id, selected_items_list)
{
if(group->getChildren().contains(id))
{
one_contained = true;
break;
}
}
}
//if the drop item is not a group_item or if it already contains the item, then the drop action must be ignored
if(!group ||one_contained)

View File

@ -195,8 +195,10 @@ public Q_SLOTS:
++i;
}
}
//! Sets the target list of indices as the selected indices.
QList<int> setSelectedItemsList(QList<int> l )
const QList<int>& setSelectedItemIndices(QList<int> l,
const bool do_emit = true)
{
Q_FOREACH(int i,l)
{
@ -206,13 +208,38 @@ public Q_SLOTS:
{
QList<int> list;
Q_FOREACH(Item_id id, group->getChildrenForSelection())
list<<id;
l << setSelectedItemsList(list);
list << id;
l << setSelectedItemIndices(list, false /*do not emit*/);
}
}
selected_items_list = l;
return l;
if(do_emit)
Q_EMIT itemIndicesSelected(selected_items_list);
return selected_items_list;
}
//! Sets the target list of indices as the selected indices.
const QList<int>& setSelectedItemList(QList<int> l,
const bool do_emit = true)
{
Q_FOREACH(int i,l)
{
CGAL::Three::Scene_group_item* group =
qobject_cast<CGAL::Three::Scene_group_item*>(item(i));
if(group)
{
QList<int> list;
Q_FOREACH(Item_id id, group->getChildrenForSelection())
list << id;
l << setSelectedItemList(list, false /*do not emit*/);
}
}
selected_items_list = l;
if(do_emit)
Q_EMIT selectionChanged(selected_items_list);
return selected_items_list;
}
// Accessors (setters)
@ -249,6 +276,8 @@ Q_SIGNALS:
void selectionChanged(QList<int> is);
//! Used when you don't want to update the selectedItem in the Geometric Objects view.
void itemIndexSelected(int i);
//! Used when you don't want to update the selectedItem in the Geometric Objects view.
void itemIndicesSelected(QList<int> is);
//! Emit this to reset the collapsed state of all groups after the Geometric Objects view has been redrawn.
void restoreCollapsedState();
//! Is emitted when draw() is finished.

View File

@ -1175,11 +1175,11 @@ void* Scene_surface_mesh_item_priv::get_aabb_tree()
void
Scene_surface_mesh_item::select(double orig_x,
double orig_y,
double orig_z,
double dir_x,
double dir_y,
double dir_z)
double orig_y,
double orig_z,
double dir_x,
double dir_y,
double dir_z)
{
SMesh *sm = d->smesh_;
std::size_t vertex_to_emit = 0;
@ -2005,7 +2005,7 @@ void Scene_surface_mesh_item::resetColors()
d->has_feature_edges = false;
}
invalidate(COLORS);
itemChanged();
itemChanged(); // @fixme really shouldn't call something that strong
}
QMenu* Scene_surface_mesh_item::contextMenu()
@ -2387,7 +2387,6 @@ void Scene_surface_mesh_item::computeElements() const
{
d->compute_elements(ALL);
setBuffersFilled(true);
const_cast<Scene_surface_mesh_item*>(this)->itemChanged();
}
void

View File

@ -1,79 +1,96 @@
#ifndef ID_PRINTING_H
#define ID_PRINTING_H
#ifndef CGAL_POLYHEDRON_DEMO_ID_PRINTING_H
#define CGAL_POLYHEDRON_DEMO_ID_PRINTING_H
#include <CGAL/boost/graph/selection.h>
#include <CGAL/Kernel_traits.h>
#include <CGAL/Kernel/global_functions.h>
#include <CGAL/Polygon_mesh_processing/compute_normal.h>
#include <CGAL/Three/Viewer_interface.h>
#include <CGAL/Three/TextRenderer.h>
#include <CGAL/Three/Three.h>
#include <CGAL/Kernel_traits.h>
#include <CGAL/Polygon_mesh_processing/compute_normal.h>
#include <vector>
#define POINT_SIZE 11
template<class Mesh>
struct VKRingPMAP{
typedef typename boost::graph_traits<Mesh>::vertex_descriptor key_type;
typedef bool value_type;
typedef value_type reference;
typedef boost::read_write_property_map_tag category;
typedef typename boost::property_map<Mesh, boost::vertex_index_t>::type IDmap;
struct VKRingPMAP
{
using key_type = typename boost::graph_traits<Mesh>::vertex_descriptor;
using value_type = bool;
using reference = value_type;
using category = boost::read_write_property_map_tag;
using IDmap = typename boost::property_map<Mesh, boost::vertex_index_t>::type;
std::vector<bool>* vec;
Mesh* poly;
IDmap idmap;
VKRingPMAP(std::vector<bool>* vec, Mesh* poly)
:vec(vec), poly(poly)
: vec(vec), poly(poly)
{
idmap = get(boost::vertex_index, *poly);
}
friend value_type get(const VKRingPMAP<Mesh>& map, const key_type& v){
friend value_type get(const VKRingPMAP<Mesh>& map, const key_type& v)
{
return (*map.vec)[get(map.idmap, v)];
}
friend void put(VKRingPMAP<Mesh>& map, const key_type& v, const value_type i){
friend void put(VKRingPMAP<Mesh>& map, const key_type& v, const value_type i)
{
(*map.vec)[get(map.idmap, v)] = i;
}
};
template<class Mesh>
struct EdgeKRingPMAP{
typedef typename boost::graph_traits<Mesh>::edge_descriptor key_type;
typedef bool value_type;
typedef value_type reference;
typedef boost::read_write_property_map_tag category;
typedef typename boost::property_map<Mesh, boost::halfedge_index_t>::type IDmap;
struct EdgeKRingPMAP
{
using key_type = typename boost::graph_traits<Mesh>::edge_descriptor;
using value_type = bool;
using reference = value_type;
using category = boost::read_write_property_map_tag;
using IDmap = typename boost::property_map<Mesh, boost::halfedge_index_t>::type;
std::vector<bool>* vec;
Mesh* poly;
IDmap idmap;
EdgeKRingPMAP(std::vector<bool>* vec, Mesh* poly)
:vec(vec), poly(poly)
: vec(vec), poly(poly)
{
idmap = get(boost::halfedge_index, *poly);
}
friend value_type get(const EdgeKRingPMAP<Mesh>& map, const key_type& e){
friend value_type get(const EdgeKRingPMAP<Mesh>& map, const key_type& e)
{
return (*map.vec)[get(map.idmap, halfedge(e, *map.poly))/2];
}
friend void put(EdgeKRingPMAP<Mesh>& map, const key_type& e, const value_type i){
friend void put(EdgeKRingPMAP<Mesh>& map, const key_type& e, const value_type i)
{
(*map.vec)[get(map.idmap, halfedge(e, *map.poly))/2] = i;
}
};
template<class Mesh>
struct FKRingPMAP{
typedef typename boost::graph_traits<Mesh>::face_descriptor key_type;
typedef bool value_type;
typedef value_type reference;
typedef boost::read_write_property_map_tag category;
typedef typename boost::property_map<Mesh, boost::face_index_t>::type IDmap;
struct FKRingPMAP
{
using key_type = typename boost::graph_traits<Mesh>::face_descriptor;
using value_type = bool;
using reference = value_type;
using category = boost::read_write_property_map_tag;
using IDmap = typename boost::property_map<Mesh, boost::face_index_t>::type;
std::vector<bool>* vec;
Mesh* poly;
IDmap idmap;
FKRingPMAP(std::vector<bool>* vec, Mesh* poly)
:vec(vec), poly(poly)
: vec(vec), poly(poly)
{
idmap = get(boost::face_index, *poly);
}
@ -81,7 +98,9 @@ struct FKRingPMAP{
friend value_type get(const FKRingPMAP<Mesh>& map, const key_type& f){
return (*map.vec)[get(map.idmap, f)];
}
friend void put(FKRingPMAP<Mesh>& map, const key_type& f, const value_type i){
friend void put(FKRingPMAP<Mesh>& map, const key_type& f, const value_type i)
{
(*map.vec)[get(map.idmap, f)] = i;
}
};
@ -91,26 +110,28 @@ void deleteIds(CGAL::Three::Viewer_interface* viewer,
TextListItem* fitems,
std::vector<TextItem*>* targeted_ids)
{
TextRenderer *renderer = viewer->textRenderer();
TextRenderer* renderer = viewer->textRenderer();
for(TextItem* it : vitems->textList())
delete it;
delete it;
for(TextItem* it : eitems->textList())
delete it;
delete it;
for(TextItem* it : fitems->textList())
delete it;
delete it;
vitems->clear();
renderer->removeTextList(vitems);
eitems->clear();
renderer->removeTextList(eitems);
fitems->clear();
renderer->removeTextList(fitems);
targeted_ids->clear();
viewer->update();
}
template<typename Handle, typename Point, typename Tree>
bool find_primitive_id(const QPoint& point,
Tree* aabb_tree,
@ -118,12 +139,13 @@ bool find_primitive_id(const QPoint& point,
Handle& selected_fh,
Point& pt_under)
{
typedef typename CGAL::Kernel_traits<Point>::Kernel Traits;
using Traits = typename CGAL::Kernel_traits<Point>::Kernel;
bool found = false;
CGAL::qglviewer::Vec point_under = viewer->camera()->pointUnderPixel(point,found);
const CGAL::qglviewer::Vec offset = static_cast<CGAL::Three::Viewer_interface*>(CGAL::QGLViewer::QGLViewerPool().first())->offset();
//find clicked facet
// find clicked facet
CGAL::qglviewer::Vec dir;
Point ray_origin;
if(viewer->camera()->type() == CGAL::qglviewer::Camera::PERSPECTIVE)
@ -151,38 +173,39 @@ bool find_primitive_id(const QPoint& point,
if(intersections.empty())
return false;
typename Intersections::iterator closest = intersections.begin();
const Point* closest_point =
boost::get<Point>(&closest->first);
for(typename Intersections::iterator
it = std::next(intersections.begin()),
end = intersections.end();
it != end; ++it)
const Point* closest_point = boost::get<Point>(&closest->first);
for(typename Intersections::iterator it = std::next(intersections.begin()),
end = intersections.end(); it != end; ++it)
{
if(! closest_point) {
if(! closest_point)
{
closest = it;
}
else {
const Point* it_point =
boost::get<Point>(&it->first);
if(it_point &&
(ray_dir * (*it_point - *closest_point)) < 0)
else
{
const Point* it_point = boost::get<Point>(&it->first);
if(it_point && (ray_dir * (*it_point - *closest_point)) < 0)
{
closest = it;
closest_point = it_point;
}
}
}
if(!closest_point)
return false;
pt_under = Point(point_under.x, point_under.y, point_under.z);
selected_fh = closest->second;
return true;
}
template<typename Mesh, typename Point >
template<typename Mesh, typename Point>
void compute_displayed_ids(Mesh& mesh,
CGAL::Three::Viewer_interface *viewer,
CGAL::Three::Viewer_interface* viewer,
const typename boost::graph_traits<Mesh>::face_descriptor& selected_fh,
const Point& pt_under,
const CGAL::qglviewer::Vec& offset,
@ -191,21 +214,21 @@ void compute_displayed_ids(Mesh& mesh,
TextListItem* fitems,
std::vector<TextItem*>* targeted_ids)
{
typedef typename boost::graph_traits<Mesh>::face_descriptor face_descriptor;
typedef typename boost::graph_traits<Mesh>::vertex_descriptor vertex_descriptor;
typedef typename boost::graph_traits<Mesh>::edge_descriptor edge_descriptor;
typedef typename boost::graph_traits<Mesh>::halfedge_descriptor halfedge_descriptor;
using vertex_descriptor = typename boost::graph_traits<Mesh>::vertex_descriptor;
using halfedge_descriptor = typename boost::graph_traits<Mesh>::halfedge_descriptor;
using edge_descriptor = typename boost::graph_traits<Mesh>::edge_descriptor;
using face_descriptor = typename boost::graph_traits<Mesh>::face_descriptor;
typedef typename boost::property_map<Mesh, boost::vertex_point_t>::type Ppmap;
using Ppmap = typename boost::property_map<Mesh, boost::vertex_point_t>::type;
Ppmap ppmap = get(boost::vertex_point, mesh);
typedef typename boost::property_map<Mesh, boost::vertex_index_t>::type VIDmap;
using VIDmap = typename boost::property_map<Mesh, boost::vertex_index_t>::type;
VIDmap vidmap = get(boost::vertex_index, mesh);
typedef typename boost::property_map<Mesh, boost::halfedge_index_t>::type HIDmap;
using HIDmap = typename boost::property_map<Mesh, boost::halfedge_index_t>::type;
HIDmap hidmap = get(boost::halfedge_index, mesh);
typedef typename boost::property_map<Mesh, boost::face_index_t>::type FIDmap;
using FIDmap = typename boost::property_map<Mesh, boost::face_index_t>::type;
FIDmap fidmap = get(boost::face_index, mesh);
QFont font;
@ -214,70 +237,77 @@ void compute_displayed_ids(Mesh& mesh,
std::vector<vertex_descriptor> displayed_vertices;
std::vector<edge_descriptor> displayed_edges;
std::vector<face_descriptor> displayed_faces;
//Test spots around facet to find the closest to point
// Test spots around facet to find the closest to point
double min_dist = (std::numeric_limits<double>::max)();
// test the vertices of the closest face
for(vertex_descriptor vh : vertices_around_face(halfedge(selected_fh, mesh), mesh))
{
Point test=Point(get(ppmap, vh).x()+offset.x,
get(ppmap, vh).y()+offset.y,
get(ppmap, vh).z()+offset.z);
Point test=Point(get(ppmap, vh).x() + offset.x,
get(ppmap, vh).y() + offset.y,
get(ppmap, vh).z() + offset.z);
double dist = CGAL::squared_distance(test, pt_under);
if( dist < min_dist){
if(dist < min_dist)
{
min_dist = dist;
displayed_vertices.clear();
displayed_vertices.push_back(vh);
}
}
QVector3D point(
float(get(ppmap, displayed_vertices[0]).x() + offset.x),
float(get(ppmap, displayed_vertices[0]).y() + offset.y),
float(get(ppmap, displayed_vertices[0]).z() + offset.z));
//test if we want to erase or not
QVector3D point(float(get(ppmap, displayed_vertices[0]).x() + offset.x),
float(get(ppmap, displayed_vertices[0]).y() + offset.y),
float(get(ppmap, displayed_vertices[0]).z() + offset.z));
// test if we want to erase or not
for(TextItem* text_item : *targeted_ids)
{
if(text_item->position() == point)
{
//hide and stop
// hide and stop
deleteIds(viewer, vitems, eitems, fitems, targeted_ids);
return;
}
}
deleteIds(viewer, vitems, eitems, fitems, targeted_ids);
// test the midpoint of edges of the closest face
for(halfedge_descriptor e : halfedges_around_face(halfedge(selected_fh, mesh), mesh))
{
Point test=CGAL::midpoint(get(ppmap, source(e, mesh)),get(ppmap, target(e, mesh)));
Point test = CGAL::midpoint(get(ppmap, source(e, mesh)),get(ppmap, target(e, mesh)));
test = Point(test.x()+offset.x,
test.y()+offset.y,
test.z()+offset.z);
double dist = CGAL::squared_distance(test, pt_under);
if(dist < min_dist){
if(dist < min_dist)
{
min_dist = dist;
displayed_vertices.clear();
displayed_edges.clear();
displayed_edges.push_back(edge(e, mesh));
}
}
// test the centroid of the closest face
double x(0), y(0), z(0);
int total(0);
for(vertex_descriptor vh : vertices_around_face(halfedge(selected_fh, mesh), mesh))
{
x+=get(ppmap, vh).x();
y+=get(ppmap, vh).y();
z+=get(ppmap, vh).z();
x += get(ppmap, vh).x();
y += get(ppmap, vh).y();
z += get(ppmap, vh).z();
++total;
}
Point test(x/total+offset.x,
y/total+offset.y,
z/total+offset.z);
Point test(x / total+offset.x,
y / total+offset.y,
z / total+offset.z);
double dist = CGAL::squared_distance(test, pt_under);
if(dist < min_dist){
if(dist < min_dist)
{
min_dist = dist;
displayed_vertices.clear();
displayed_edges.clear();
@ -293,23 +323,21 @@ void compute_displayed_ids(Mesh& mesh,
if(f != boost::graph_traits<Mesh>::null_face())
displayed_faces.push_back(f);
}
for(halfedge_descriptor h : CGAL::halfedges_around_target(halfedge(displayed_vertices[0], mesh), mesh))
{
displayed_edges.push_back(edge(h, mesh));
}
}
else if(!displayed_edges.empty())
{
displayed_vertices.push_back(target(halfedge(displayed_edges[0], mesh), mesh));
displayed_vertices.push_back(target(opposite(halfedge(displayed_edges[0], mesh), mesh),mesh));
face_descriptor f1(face(halfedge(displayed_edges[0], mesh),mesh)),
f2(face(opposite(halfedge(displayed_edges[0], mesh), mesh),mesh));
f2(face(opposite(halfedge(displayed_edges[0], mesh), mesh),mesh));
if(f1 != boost::graph_traits<Mesh>::null_face())
displayed_faces.push_back(f1);
if(f2 != boost::graph_traits<Mesh>::null_face())
displayed_faces.push_back(f2);
}
else if(!displayed_faces.empty())
{
for(halfedge_descriptor h : CGAL::halfedges_around_face(halfedge(displayed_faces[0], mesh), mesh))
@ -318,7 +346,8 @@ void compute_displayed_ids(Mesh& mesh,
displayed_vertices.push_back(target(h, mesh));
}
}
//fill TextItems
// fill TextItems
std::vector<bool> vertex_selection(false);
vertex_selection.resize(num_vertices(mesh));
VKRingPMAP<Mesh> vpmap(&vertex_selection, &mesh);
@ -345,9 +374,7 @@ void compute_displayed_ids(Mesh& mesh,
face_selection.resize(num_faces(mesh));
FKRingPMAP<Mesh> fpmap(&face_selection, &mesh);
for(face_descriptor f_h : displayed_faces)
{
put(fpmap, f_h, true);
}
put(fpmap, f_h, true);
CGAL::expand_face_selection(displayed_faces,
mesh,
1,
@ -356,9 +383,9 @@ void compute_displayed_ids(Mesh& mesh,
for(vertex_descriptor vh : displayed_vertices)
{
Point pos=Point(get(ppmap, vh).x()+offset.x,
get(ppmap, vh).y()+offset.y,
get(ppmap, vh).z()+offset.z);
Point pos = Point(get(ppmap, vh).x() + offset.x,
get(ppmap, vh).y() + offset.y,
get(ppmap, vh).z() + offset.z);
TextItem* text_item = new TextItem(float(pos.x()),
float(pos.y()),
float(pos.z()),
@ -366,13 +393,14 @@ void compute_displayed_ids(Mesh& mesh,
vitems->append(text_item);
targeted_ids->push_back(text_item);
}
for(edge_descriptor e : displayed_edges)
{
halfedge_descriptor h(halfedge(e, mesh));
Point pos=CGAL::midpoint(get(ppmap, source(h, mesh)),get(ppmap, target(h, mesh)));
pos = Point(pos.x()+offset.x,
pos.y()+offset.y,
pos.z()+offset.z);
halfedge_descriptor h(halfedge(e, mesh));
Point pos = CGAL::midpoint(get(ppmap, source(h, mesh)),get(ppmap, target(h, mesh)));
pos = Point(pos.x() + offset.x,
pos.y() + offset.y,
pos.z() + offset.z);
TextItem* text_item = new TextItem(float(pos.x()),
float(pos.y()),
@ -387,15 +415,15 @@ void compute_displayed_ids(Mesh& mesh,
int total(0);
for(vertex_descriptor vh :vertices_around_face(halfedge(f, mesh), mesh))
{
x+=get(ppmap, vh).x();
y+=get(ppmap, vh).y();
z+=get(ppmap, vh).z();
x += get(ppmap, vh).x();
y += get(ppmap, vh).y();
z += get(ppmap, vh).z();
++total;
}
Point pos(x/total+offset.x,
y/total+offset.y,
z/total+offset.z);
Point pos(x/total + offset.x,
y/total + offset.y,
z/total + offset.z);
TextItem* text_item = new TextItem(float(pos.x()),
float(pos.y()),
float(pos.z()),
@ -408,18 +436,20 @@ template<class Mesh>
bool printVertexIds(const Mesh& mesh,
TextListItem* vitems)
{
typedef typename boost::property_map<Mesh, boost::vertex_point_t>::const_type Ppmap;
typedef typename boost::property_traits<Ppmap>::value_type Point;
typedef typename boost::property_map<Mesh, boost::vertex_index_t>::type IDmap;
using Ppmap = typename boost::property_map<Mesh, boost::vertex_point_t>::const_type;
using Point = typename boost::property_traits<Ppmap>::value_type;
using IDmap = typename boost::property_map<Mesh, boost::vertex_index_t>::type;
Ppmap ppmap = get(boost::vertex_point, mesh);
IDmap idmap = get(boost::vertex_index, mesh);
const CGAL::qglviewer::Vec offset = CGAL::Three::Three::mainViewer()->offset();
QFont font;
font.setBold(true);
font.setPointSize(POINT_SIZE);
//fills textItems
// fills textItems
for(typename boost::graph_traits<Mesh>::vertex_descriptor vh : vertices(mesh))
{
const Point& p = get(ppmap, vh);
@ -429,7 +459,8 @@ bool printVertexIds(const Mesh& mesh,
QString("%1").arg(get(idmap, vh)), true, font, Qt::red));
}
//add the QList to the render's pool
// add the QList to the render's pool
bool res = true;
Q_FOREACH(CGAL::QGLViewer* v, CGAL::QGLViewer::QGLViewerPool())
{
@ -437,10 +468,9 @@ bool printVertexIds(const Mesh& mesh,
renderer->addTextList(vitems);
v->update();
if(vitems->size() > static_cast<std::size_t>(renderer->getMax_textItems()))
{
res = false;
}
}
return res;
}
@ -448,13 +478,15 @@ template<class Mesh>
bool printEdgeIds(const Mesh& mesh,
TextListItem* eitems)
{
typedef typename boost::property_map<Mesh, boost::vertex_point_t>::const_type Ppmap;
typedef typename boost::property_traits<Ppmap>::value_type Point;
typedef typename boost::property_map<Mesh, boost::halfedge_index_t>::type IDmap;
using Ppmap = typename boost::property_map<Mesh, boost::vertex_point_t>::const_type;
using Point = typename boost::property_traits<Ppmap>::value_type;
using IDmap = typename boost::property_map<Mesh, boost::halfedge_index_t>::type;
Ppmap ppmap = get(boost::vertex_point, mesh);
IDmap idmap = get(boost::halfedge_index, mesh);
const CGAL::qglviewer::Vec offset = CGAL::Three::Three::mainViewer()->offset();
QFont font;
font.setBold(true);
font.setPointSize(POINT_SIZE);
@ -468,7 +500,8 @@ bool printEdgeIds(const Mesh& mesh,
float((p1.z() + p2.z()) / 2 + offset.z),
QString("%1").arg(get(idmap, halfedge(e, mesh)) / 2), true, font, Qt::green));
}
//add the QList to the render's pool
// add the QList to the render's pool
bool res = true;
Q_FOREACH(CGAL::QGLViewer* v, CGAL::QGLViewer::QGLViewerPool())
{
@ -476,10 +509,9 @@ bool printEdgeIds(const Mesh& mesh,
renderer->addTextList(eitems);
v->update();
if(eitems->size() > static_cast<std::size_t>(renderer->getMax_textItems()))
{
res = false;
}
}
return res;
}
@ -487,15 +519,18 @@ template<class Mesh>
bool printFaceIds(const Mesh& mesh,
TextListItem* fitems)
{
typedef typename boost::property_map<Mesh, boost::vertex_point_t>::const_type Ppmap;
typedef typename boost::property_map<Mesh, boost::face_index_t>::type IDmap;
using Ppmap = typename boost::property_map<Mesh, boost::vertex_point_t>::const_type;
using IDmap = typename boost::property_map<Mesh, boost::face_index_t>::type;
Ppmap ppmap = get(boost::vertex_point, mesh);
IDmap idmap = get(boost::face_index, mesh);
const CGAL::qglviewer::Vec offset = CGAL::Three::Three::mainViewer()->offset();
QFont font;
font.setBold(true);
font.setPointSize(POINT_SIZE);
for(typename boost::graph_traits<Mesh>::face_descriptor fh : faces(mesh))
{
double x(0), y(0), z(0);
@ -513,7 +548,8 @@ bool printFaceIds(const Mesh& mesh,
float(z / total + offset.z),
QString("%1").arg(get(idmap, fh)), true, font, Qt::blue));
}
//add the QList to the render's pool
// add the QList to the render's pool
bool res = true;
Q_FOREACH(CGAL::QGLViewer* v, CGAL::QGLViewer::QGLViewerPool())
{
@ -521,9 +557,7 @@ bool printFaceIds(const Mesh& mesh,
renderer->addTextList(fitems);
v->update();
if(fitems->size() > static_cast<std::size_t>(renderer->getMax_textItems()))
{
res = false;
}
}
return res;
}
@ -535,14 +569,15 @@ int zoomToId(const Mesh& mesh,
typename boost::graph_traits<Mesh>::face_descriptor& selected_fh,
Point& p)
{
typedef typename boost::graph_traits<Mesh>::face_descriptor face_descriptor;
typedef typename boost::graph_traits<Mesh>::vertex_descriptor vertex_descriptor;
typedef typename boost::property_map<Mesh, boost::vertex_point_t>::const_type Ppmap;
typedef typename boost::property_map<Mesh, boost::vertex_index_t>::type VIDmap;
typedef typename boost::property_map<Mesh, boost::halfedge_index_t>::type EIDmap;
typedef typename boost::property_map<Mesh, boost::face_index_t>::type FIDmap;
typedef typename CGAL::Kernel_traits<Point>::Kernel Traits;
using vertex_descriptor = typename boost::graph_traits<Mesh>::vertex_descriptor;
using face_descriptor = typename boost::graph_traits<Mesh>::face_descriptor;
using Ppmap = typename boost::property_map<Mesh, boost::vertex_point_t>::const_type;
using VIDmap = typename boost::property_map<Mesh, boost::vertex_index_t>::type;
using EIDmap = typename boost::property_map<Mesh, boost::halfedge_index_t>::type;
using FIDmap = typename boost::property_map<Mesh, boost::face_index_t>::type;
using Traits = typename CGAL::Kernel_traits<Point>::Kernel;
Ppmap ppmap = get(boost::vertex_point, mesh);
VIDmap vidmap = get(boost::vertex_index, mesh);
@ -555,10 +590,11 @@ int zoomToId(const Mesh& mesh,
if((first != QString("v") &&
first != QString("e") &&
first != QString("f")) ||
!is_int)
!is_int)
{
return 1; //("Input must be of the form [v/e/f][int]"
}
const CGAL::qglviewer::Vec offset = viewer->offset();
typename Traits::Vector_3 normal;
if(first == QString("v"))
@ -567,26 +603,25 @@ int zoomToId(const Mesh& mesh,
for(vertex_descriptor vh : vertices(mesh))
{
std::size_t cur_id = get(vidmap, vh);
if( cur_id == id)
if(cur_id == id)
{
p = Point(get(ppmap, vh).x() + offset.x,
get(ppmap, vh).y() + offset.y,
get(ppmap, vh).z() + offset.z);
typename boost::graph_traits<Mesh>::halfedge_descriptor hf = halfedge(vh, mesh);
if(CGAL::is_border(hf, mesh))
{
hf = opposite(hf, mesh);
}
selected_fh = face(hf, mesh);
normal = CGAL::Polygon_mesh_processing::compute_vertex_normal(vh, mesh);
found = true;
break;
}
}
if(!found)
{
return 2;//"No vertex with id %1").arg(id)
}
return 2; // "No vertex with id %1").arg(id)
}
else if(first == QString("e"))
{
@ -604,10 +639,10 @@ int zoomToId(const Mesh& mesh,
typename Traits::Vector_3 normal1(0,0,0);
if(!is_border(hf, mesh))
{
normal1= CGAL::Polygon_mesh_processing::compute_face_normal(face(hf,mesh),
mesh);
normal1 = CGAL::Polygon_mesh_processing::compute_face_normal(face(hf,mesh), mesh);
selected_fh = face(hf, mesh);
}
typename Traits::Vector_3 normal2(0,0,0);
if(!is_border(opposite(hf, mesh), mesh))
{
@ -615,15 +650,15 @@ int zoomToId(const Mesh& mesh,
mesh);
selected_fh = face(hf, mesh);
}
normal = 0.5*normal1+0.5*normal2;
normal = 0.5*normal1 + 0.5*normal2;
found = true;
break;
}
}
if(!found)
{
return 3;//"No edge with id %1").arg(id)
}
return 3; // "No edge with id %1").arg(id)
}
else if(first == QString("f"))
{
@ -634,30 +669,30 @@ int zoomToId(const Mesh& mesh,
{
if(get(fidmap, fh) != id)
continue;
for(vertex_descriptor vh : vertices_around_face(halfedge(fh, mesh), mesh))
{
x+=get(ppmap, vh).x();
y+=get(ppmap, vh).y();
z+=get(ppmap, vh).z();
x += get(ppmap, vh).x();
y += get(ppmap, vh).y();
z += get(ppmap, vh).z();
++total;
}
p = Point(x/total + offset.x,
y/total + offset.y,
z/total + offset.z);
normal = CGAL::Polygon_mesh_processing::compute_face_normal(
fh,
mesh);
y/total + offset.y,
z/total + offset.z);
normal = CGAL::Polygon_mesh_processing::compute_face_normal(fh, mesh);
selected_fh = fh;
found = true;
break;
}
if(!found)
{
return 4; //"No face with id %1").arg(id)
}
return 4; // "No face with id %1").arg(id)
}
CGAL::qglviewer::Quaternion new_orientation(CGAL::qglviewer::Vec(0,0,-1),
CGAL::qglviewer::Vec(-normal.x(), -normal.y(), -normal.z()));
CGAL::qglviewer::Vec(-normal.x(), -normal.y(), -normal.z()));
Point new_pos = p +
0.25*CGAL::qglviewer::Vec(
viewer->camera()->position().x - viewer->camera()->pivotPoint().x,
@ -665,19 +700,69 @@ int zoomToId(const Mesh& mesh,
viewer->camera()->position().z - viewer->camera()->pivotPoint().z)
.norm() * normal ;
viewer->camera()->setPivotPoint(CGAL::qglviewer::Vec(p.x(),
p.y(),
p.z()));
viewer->camera()->setPivotPoint(CGAL::qglviewer::Vec(p.x(), p.y(), p.z()));
viewer->moveCameraToCoordinates(QString("%1 %2 %3 %4 %5 %6 %7").arg(new_pos.x())
.arg(new_pos.y())
.arg(new_pos.z())
.arg(new_orientation[0])
.arg(new_orientation[1])
.arg(new_orientation[2])
.arg(new_orientation[3]));
.arg(new_pos.y())
.arg(new_pos.z())
.arg(new_orientation[0])
.arg(new_orientation[1])
.arg(new_orientation[2])
.arg(new_orientation[3]));
viewer->update();
return 0; //all clear;
}
#endif // ID_PRINTING_H
return 0; // all clear;
}
template<class PointSet>
int zoomToPoint(const PointSet& ps,
const typename PointSet::Index& index,
CGAL::Three::Viewer_interface* viewer,
typename PointSet::Point_3& p)
{
const CGAL::qglviewer::Vec offset = viewer->offset();
using Point_3 = typename PointSet::Point_3;
using Vector_3 = typename PointSet::Vector_3;
const Point_3& op = ps.point(index);
p = Point_3(op.x() + offset.x,
op.y() + offset.y,
op.z() + offset.z);
Vector_3 normal;
if(ps.has_normal_map())
normal = ps.normal(index);
else
normal = { viewer->camera()->position().x - viewer->camera()->pivotPoint().x,
viewer->camera()->position().y - viewer->camera()->pivotPoint().y,
viewer->camera()->position().z - viewer->camera()->pivotPoint().z };
Point_3 new_pos = p +
0.25 * CGAL::qglviewer::Vec(
viewer->camera()->position().x - viewer->camera()->pivotPoint().x,
viewer->camera()->position().y - viewer->camera()->pivotPoint().y,
viewer->camera()->position().z - viewer->camera()->pivotPoint().z)
.norm() * normal ;
viewer->camera()->setPivotPoint(CGAL::qglviewer::Vec(p.x(), p.y(), p.z()));
CGAL::qglviewer::Quaternion new_orientation(CGAL::qglviewer::Vec(0,0,-1),
CGAL::qglviewer::Vec(-normal.x(), -normal.y(), -normal.z()));
viewer->moveCameraToCoordinates(QString("%1 %2 %3 %4 %5 %6 %7").arg(new_pos.x())
.arg(new_pos.y())
.arg(new_pos.z())
.arg(new_orientation[0])
.arg(new_orientation[1])
.arg(new_orientation[2])
.arg(new_orientation[3]));
viewer->update();
return 0;
}
#endif // CGAL_POLYHEDRON_DEMO_ID_PRINTING_H

View File

@ -1,234 +1,246 @@
#ifndef TRIANGULATE_PRIMITIVE
#define TRIANGULATE_PRIMITIVE
#ifndef CGAL_DEMO_TRIANGULATE_PRIMITIVE_H
#define CGAL_DEMO_TRIANGULATE_PRIMITIVE_H
#include <CGAL/Three/Scene_item.h>
#include <CGAL/Triangulation_vertex_base_with_info_2.h>
#include <CGAL/Triangulation_face_base_with_info_2.h>
#include <CGAL/Constrained_Delaunay_triangulation_2.h>
#include <CGAL/Projection_traits_3.h>
#include <CGAL/Three/Scene_item.h>
#include <queue>
#include <QColor>
//Make sure all the facets are triangles
#include <CGAL/boost/graph/properties.h>
#include <boost/graph/graph_traits.hpp>
#include <iostream>
#include <queue>
#include <vector>
// Ensure that all the facets are triangles
// @todo just use PMP::triangulate_face()...?
// or at least mark_faces_in_domain()
template<class Mesh, typename Kernel, typename Index_type>
class FacetTriangulator
{
typedef Kernel Traits;
public:
using Traits = Kernel;
using Point = typename Kernel::Point_3;
using Vector = typename Kernel::Vector_3;
typedef typename boost::graph_traits<Mesh>::halfedge_descriptor halfedge_descriptor;
using P_traits = CGAL::Projection_traits_3<Traits>;
typedef typename Kernel::Vector_3 Vector;
using halfedge_descriptor = typename boost::graph_traits<Mesh>::halfedge_descriptor;
using face_descriptor = typename boost::graph_traits<Mesh>::face_descriptor;
struct Face_info
{
typename boost::graph_traits<Mesh>::halfedge_descriptor e[3];
bool is_external;
};
typedef CGAL::Projection_traits_3<Traits> P_traits;
using Vb = CGAL::Triangulation_vertex_base_with_info_2<halfedge_descriptor, P_traits>;
using Fbb = CGAL::Triangulation_face_base_with_info_2<Face_info, P_traits>;
using Fb = CGAL::Constrained_triangulation_face_base_2<P_traits, Fbb>;
using TDS = CGAL::Triangulation_data_structure_2<Vb, Fb>;
using Itag = CGAL::Exact_predicates_tag;
using CDT = CGAL::Constrained_Delaunay_triangulation_2<P_traits, TDS, Itag>;
typedef CGAL::Triangulation_vertex_base_with_info_2<halfedge_descriptor,
P_traits> Vb;
using Vertex_handle = typename CDT::Vertex_handle;
using Face_handle = typename CDT::Face_handle;
struct Face_info {
typename boost::graph_traits<Mesh>::halfedge_descriptor e[3];
bool is_external;
};
typedef CGAL::Triangulation_face_base_with_info_2<Face_info,
P_traits> Fb1;
typedef CGAL::Constrained_triangulation_face_base_2<P_traits, Fb1> Fb;
typedef CGAL::Triangulation_data_structure_2<Vb,Fb> TDS;
typedef CGAL::Exact_predicates_tag Itag;
struct PointAndId
{
Point point;
Index_type id;
PointAndId() = default;
PointAndId(const Point& point, const Index_type id) : point(point), id(id) { }
};
public:
struct PointAndId {
typename Kernel::Point_3 point;
Index_type id;
};
CDT* cdt;
CGAL::Unique_hash_map<Vertex_handle, Index_type> v2v;
typedef CGAL::Constrained_Delaunay_triangulation_2<P_traits,
TDS,
Itag> CDT;
CDT *cdt;
CGAL::Unique_hash_map<typename CDT::Vertex_handle, Index_type> v2v;
//Constructor
FacetTriangulator(typename boost::graph_traits<Mesh>::face_descriptor fd,
public:
// Constructor
FacetTriangulator(face_descriptor fd,
const Vector& normal,
Mesh *poly,
Mesh* poly,
Vector offset = Vector(0,0,0))
{
std::vector<PointAndId> idPoints;
for(halfedge_descriptor he_circ : halfedges_around_face( halfedge(fd, *poly), *poly))
{
PointAndId idPoint;
idPoint.point = get(boost::vertex_point,*poly,source(he_circ, *poly))+offset;
idPoint.id = source(he_circ, *poly);
idPoints.push_back(idPoint);
for(halfedge_descriptor he_circ : halfedges_around_face(halfedge(fd, *poly), *poly))
idPoints.emplace_back(get(CGAL::vertex_point, *poly, source(he_circ, *poly)) + offset,
source(he_circ, *poly));
}
if(!triangulate(idPoints, normal))
std::cerr<<"Facet not displayed"<<std::endl;
std::cerr << "Facet not displayed" << std::endl;
}
FacetTriangulator(typename boost::graph_traits<Mesh>::face_descriptor fd,
const std::vector<typename Kernel::Point_3>& more_points,
FacetTriangulator(face_descriptor fd,
const std::vector<Point>& more_points,
const Vector& normal,
Mesh *poly,
Mesh* poly,
Vector offset = Vector(0,0,0))
{
std::vector<PointAndId> idPoints;
for(halfedge_descriptor he_circ : halfedges_around_face( halfedge(fd, *poly), *poly))
{
PointAndId idPoint;
idPoint.point = get(boost::vertex_point,*poly,source(he_circ, *poly))+offset;
idPoint.id = source(he_circ, *poly);
idPoints.push_back(idPoint);
std::vector<PointAndId> idPoints;
for(halfedge_descriptor he_circ : halfedges_around_face(halfedge(fd, *poly), *poly))
idPoints.emplace_back(get(CGAL::vertex_point, *poly, source(he_circ, *poly)) + offset,
source(he_circ, *poly));
}
if(!triangulate_with_points(idPoints,more_points, normal))
std::cerr<<"Facet not displayed"<<std::endl;
if(!triangulate_with_points(idPoints, more_points, normal))
std::cerr << "Facet not displayed" << std::endl;
}
FacetTriangulator(std::vector<PointAndId > &idPoints,
const Vector& normal)
{
if(!triangulate(idPoints, normal))
std::cerr<<"Facet not displayed"<<std::endl;
}
FacetTriangulator(std::vector<PointAndId > &idPoints,
const std::vector<typename Kernel::Point_3>& more_points,
FacetTriangulator(std::vector<PointAndId>& idPoints,
const Vector& normal)
{
if(!triangulate_with_points(idPoints, more_points, normal))
std::cerr<<"Facet not displayed"<<std::endl;
if(!triangulate(idPoints, normal))
std::cerr << "Facet not displayed" << std::endl;
}
FacetTriangulator(std::vector<PointAndId>& idPoints,
const std::vector<Point>& more_points,
const Vector& normal)
{
if(!triangulate_with_points(idPoints, more_points, normal))
std::cerr << "Facet not displayed" << std::endl;
}
~FacetTriangulator()
{
if (cdt )
delete cdt;
if(cdt)
delete cdt;
}
private:
bool triangulate( std::vector<PointAndId > &idPoints,
const Vector& normal )
bool triangulate(std::vector<PointAndId>& idPoints,
const Vector& normal)
{
P_traits cdt_traits(normal);
cdt = new CDT(cdt_traits);
typename CDT::Vertex_handle previous, first, last_inserted;
Vertex_handle previous, first, last_inserted;
// Iterate the points of the facet and decide if they must be inserted in the CDT
typename Kernel::FT x(0), y(0), z(0);
for(PointAndId idPoint : idPoints)
for(const PointAndId& idPoint : idPoints)
{
x += idPoint.point.x();
y += idPoint.point.y();
z += idPoint.point.z();
typename CDT::Vertex_handle vh;
//Always insert the first point, then only insert
// if the distance with the previous is reasonable.
if(first == typename CDT::Vertex_handle() || idPoint.point != previous->point())
{
vh = cdt->insert(idPoint.point);
v2v[vh] = idPoint.id;
if(first == typename CDT::Vertex_handle()) {
first = vh;
}
if(previous != nullptr && previous != vh) {
cdt->insert_constraint(previous, vh);
last_inserted = previous;
}
previous = vh;
}
}
if(last_inserted == typename CDT::Vertex_handle())
return false;
if(previous != first)
cdt->insert_constraint(previous, first);
// sets mark is_external
for(typename CDT::All_faces_iterator
fit2 = cdt->all_faces_begin(),
end = cdt->all_faces_end();
fit2 != end; ++fit2)
{
fit2->info().is_external = false;
}
//check if the facet is external or internal
std::queue<typename CDT::Face_handle> face_queue;
face_queue.push(cdt->infinite_vertex()->face());
while(! face_queue.empty() ) {
typename CDT::Face_handle fh = face_queue.front();
face_queue.pop();
if(fh->info().is_external) continue;
fh->info().is_external = true;
for(int i = 0; i <3; ++i) {
if(!cdt->is_constrained(std::make_pair(fh, i)))
{
face_queue.push(fh->neighbor(i));
}
}
}
return true;
}
y += idPoint.point.y();
z += idPoint.point.z();
bool triangulate_with_points( std::vector<PointAndId > &idPoints,
const std::vector<typename Kernel::Point_3>& more_points,
const Vector& normal)
{
P_traits cdt_traits(normal);
cdt = new CDT(cdt_traits);
typename CDT::Vertex_handle previous, first, last_inserted;
// Iterate the points of the facet and decide if they must be inserted in the CDT
for(PointAndId idPoint : idPoints)
{
typename CDT::Vertex_handle vh;
//Always insert the first point, then only insert
// if the distance with the previous is reasonable.
if(first == typename CDT::Vertex_handle() || idPoint.point != previous->point())
Vertex_handle vh;
// Always insert the first point, then only insert if the distance with the previous is reasonable.
if(first == Vertex_handle() || idPoint.point != previous->point())
{
vh = cdt->insert(idPoint.point);
v2v[vh] = idPoint.id;
if(first == typename CDT::Vertex_handle()) {
if(first == Vertex_handle())
first = vh;
}
if(previous != nullptr && previous != vh) {
if(previous != nullptr && previous != vh)
{
cdt->insert_constraint(previous, vh);
last_inserted = previous;
}
previous = vh;
previous = vh;
}
}
if(last_inserted == typename CDT::Vertex_handle())
return false;
cdt->insert_constraint(previous, first);
for(typename Kernel::Point_3 point : more_points)
{
cdt->insert(point);
}
// sets mark is_external
for(typename CDT::All_faces_iterator
fit2 = cdt->all_faces_begin(),
end = cdt->all_faces_end();
fit2 != end; ++fit2)
{
fit2->info().is_external = false;
}
//check if the facet is external or internal
std::queue<typename CDT::Face_handle> face_queue;
face_queue.push(cdt->infinite_vertex()->face());
while(! face_queue.empty() ) {
typename CDT::Face_handle fh = face_queue.front();
face_queue.pop();
if(fh->info().is_external) continue;
fh->info().is_external = true;
for(int i = 0; i <3; ++i) {
if(!cdt->is_constrained(std::make_pair(fh, i)))
{
face_queue.push(fh->neighbor(i));
}
}
}
return true;
}
if(last_inserted == Vertex_handle())
return false;
if(previous != first)
cdt->insert_constraint(previous, first);
// sets mark is_external
for(Face_handle f2 : cdt->all_face_handles())
f2->info().is_external = false;
// check if the facet is external or internal
std::queue<typename CDT::Face_handle> face_queue;
face_queue.push(cdt->infinite_vertex()->face());
while(! face_queue.empty())
{
typename CDT::Face_handle fh = face_queue.front();
face_queue.pop();
if(fh->info().is_external)
continue;
fh->info().is_external = true;
for(int i = 0; i <3; ++i)
{
if(!cdt->is_constrained(std::make_pair(fh, i)))
face_queue.push(fh->neighbor(i));
}
}
return true;
}
bool triangulate_with_points(std::vector<PointAndId >& idPoints,
const std::vector<Point>& more_points,
const Vector& normal)
{
P_traits cdt_traits(normal);
cdt = new CDT(cdt_traits);
// Iterate the points of the facet and decide if they must be inserted in the CDT
Vertex_handle previous, first, last_inserted;
for(const PointAndId& idPoint : idPoints)
{
Vertex_handle vh;
// Always insert the first point, then only insert if the distance with the previous is reasonable.
if(first == Vertex_handle() || idPoint.point != previous->point())
{
vh = cdt->insert(idPoint.point);
v2v[vh] = idPoint.id;
if(first == Vertex_handle())
first = vh;
if(previous != nullptr && previous != vh)
{
cdt->insert_constraint(previous, vh);
last_inserted = previous;
}
previous = vh;
}
}
if(last_inserted == Vertex_handle())
return false;
cdt->insert_constraint(previous, first);
for(const Point& point : more_points)
cdt->insert(point);
// sets mark is_external
for(Face_handle f2 : cdt->all_face_handles())
f2->info().is_external = false;
// check if the facet is external or internal
std::queue<typename CDT::Face_handle> face_queue;
face_queue.push(cdt->infinite_vertex()->face());
while(!face_queue.empty())
{
typename CDT::Face_handle fh = face_queue.front();
face_queue.pop();
if(fh->info().is_external)
continue;
fh->info().is_external = true;
for(int i = 0; i <3; ++i)
{
if(!cdt->is_constrained(std::make_pair(fh, i)))
face_queue.push(fh->neighbor(i));
}
}
return true;
}
};
#endif // TRIANGULATE_PRIMITIVE
#endif // CGAL_DEMO_TRIANGULATE_PRIMITIVE_H

View File

@ -50,6 +50,9 @@ create_single_source_cgal_program("test_Uncertain.cpp")
create_single_source_cgal_program("test_vector.cpp")
create_single_source_cgal_program("test_join_iterators.cpp")
create_single_source_cgal_program("test_for_each.cpp")
create_single_source_cgal_program("test_skiplist.cpp")
create_single_source_cgal_program("test_leak.cpp")
create_single_source_cgal_program("test_nth_element.cpp")
if(TARGET CGAL::TBB_support)
message(STATUS "Found TBB")
target_link_libraries(test_for_each PUBLIC CGAL::TBB_support)

View File

@ -12,18 +12,18 @@ int test() {
CGAL::nth_element(nbs, nbs+pivot, nbs+sizeof(nbs) / sizeof(int), cmp);
std::cerr << "After nth_element, nbs["<< pivot << "] = " << nbs[pivot] << std::endl;
assert(nbs[pivot]==expected_value);
for(int i = 0; i < sizeof(nbs) / sizeof(int); ++i) {
for(std::size_t i = 0; i < sizeof(nbs) / sizeof(int); ++i) {
std::cerr << " " << nbs[i];
}
std::cerr << std::endl;
for(pivot=0; pivot < 10; ++pivot)
CGAL::nth_element(nbs, nbs+pivot, nbs+sizeof(nbs) / sizeof(int), cmp);
std::cerr << "After sort:\n";
for(int i = 0; i < sizeof(nbs) / sizeof(int); ++i) {
for(std::size_t i = 0; i < sizeof(nbs) / sizeof(int); ++i) {
std::cerr << " " << nbs[i];
}
std::cerr << std::endl;
for(int i = 1; i < sizeof(nbs) / sizeof(int); ++i) {
for(std::size_t i = 1; i < sizeof(nbs) / sizeof(int); ++i) {
assert(nbs[i]>=nbs[i-1]);
}
return 0;

View File

@ -50,8 +50,8 @@ BOOST_FIXTURE_TEST_CASE( test_insert, Fixture )
// clear and try again
l.clear();
BOOST_CHECK_EQUAL(l.all_size(), 0);
BOOST_CHECK_EQUAL(l.skip_size(), 0);
BOOST_CHECK_EQUAL(l.all_size(), std::size_t(0));
BOOST_CHECK_EQUAL(l.skip_size(), std::size_t(0));
l.insert(l.all_begin(), all.begin(), all.end());
skips += 8, 9;
BOOST_CHECK_EQUAL_COLLECTIONS(l.all_begin(), l.all_end(),
@ -60,7 +60,6 @@ BOOST_FIXTURE_TEST_CASE( test_insert, Fixture )
skips.begin(), skips.end());
// the same goes for inserting at an arbitrary position
skip::all_iterator pos = std::next(l.all_begin(), 3);
l.insert(std::next(l.all_begin(), 3)
, 20);
all.insert(std::next(all.begin(), 3)
@ -124,7 +123,7 @@ BOOST_FIXTURE_TEST_CASE( skip_all_case, Fixture )
l.skip(l.all_begin(), l.all_end());
skips.clear();
BOOST_CHECK_EQUAL(l.all_size(), all.size());
BOOST_CHECK_EQUAL(l.skip_size(), 0);
BOOST_CHECK_EQUAL(l.skip_size(), std::size_t(0));
BOOST_CHECK_EQUAL_COLLECTIONS(l.skip_begin(), l.skip_end(),
skips.begin(), skips.end());
}

View File

@ -414,6 +414,13 @@ run_test_on_host()
fi
for PLATFORM in ${PLATFORMS}; do
if [ "${CGAL_RELEASE_ID}" \> "CGAL-6.0" ]; then
if [ "${PLATFORM}" = "MSVC2015-Release-64bits" ]; then
continue
fi
fi
run_test_on_platform "${PLATFORM}"
collect_demos_binaries "${PLATFORM}"
publish_results "${PLATFORM}"

View File

@ -92,6 +92,33 @@ for i in `ls -d ^build*/examples/*/ ^build*/test/*/ ^build*/demo/^(icons|resourc
fi
done
#check all tests/examples are tested
echo '.. Checking if all .cpp files in examples/test are compiled...'
CML_ERRORS=""
for CML in `grep -L "GLOB cppfiles" */test/*/CMakeLists.txt */examples/*/CMakeLists.txt`; do
DIR=`dirname $CML`
if [ "Arrangement_on_surface_2/test/Arrangement_on_surface_2" = $DIR ]; then
continue
fi
if [ "Installation/test/Installation" = $DIR ]; then
continue
fi
for i in `ls ${DIR}/*.cpp`; do
f=`basename $i .cpp`
if ! grep -q $f ${CML}; then
CML_ERRORS=`echo "${CML_ERRORS}\n$i is not tested!"`
fi
done
done
if [ -n "${CML_ERRORS}" ]; then
echo -n "Some tests/examples are not tested:"
echo ${CML_ERRORS}
exit 1
fi
# check project in cmake scripts is correct
echo '.. Checking if all CMakeLists.txt project names are correct...'

View File

@ -22,7 +22,8 @@ if(TARGET CGAL::OSQP_support)
test_3_segments
test_4_segments
test_100_segments_angles
test_100_segments_offsets)
test_100_segments_offsets
test_cgal_solver)
foreach(osqp_target ${osqp_targets})
create_single_source_cgal_program("${osqp_target}.cpp")

View File

@ -21,7 +21,7 @@ void test_cgal_solver() {
using NQ = SR::Segments::Delaunay_neighbor_query_2<Traits, Segments>;
using AR = SR::Segments::Angle_regularization_2<Traits, Segments>;
using QP = CGAL::CGAL_quadratic_program_traits<FT>;
using QP = CGAL::OSQP_quadratic_program_traits<FT>;
using QP_AR = SR::QP_regularization<Traits, Segments, NQ, AR, QP>;

View File

@ -19,6 +19,7 @@ create_single_source_cgal_program("skin_surface_subdiv.cpp")
create_single_source_cgal_program("skin_surface_subdiv_with_normals.cpp")
create_single_source_cgal_program("union_of_balls_simple.cpp")
create_single_source_cgal_program("union_of_balls_subdiv.cpp")
create_single_source_cgal_program("skin_surface_retrieve_defining_weighted_points.cpp")
find_package(ESBTL QUIET)
if(ESBTL_FOUND)

View File

@ -27,6 +27,8 @@ create_single_source_cgal_program("searching_polyhedron_vertices_with_fuzzy_sphe
create_single_source_cgal_program("user_defined_point_and_distance.cpp")
create_single_source_cgal_program("using_fair_splitting_rule.cpp")
create_single_source_cgal_program("weighted_Minkowski_distance.cpp")
create_single_source_cgal_program("searching_sphere_orthogonally.cpp")
create_single_source_cgal_program("splitter_worst_cases.cpp")
find_package(Eigen3 3.1.91 QUIET) #(requires 3.1.91 or greater)
include(CGAL_Eigen3_support)

View File

@ -58,7 +58,6 @@ namespace Three{
* */
class Scene_interface {
public:
//!A bounding box is a box with each face corresponding to an extremum of its contents.
typedef CGAL::Bbox_3 Bbox;

View File

@ -81,7 +81,7 @@ public:
PROGRAM_OLD_FLAT, /** Used to render flat shading without pre computing normals without geometry shader*/
PROGRAM_SOLID_WIREFRAME, //! Used to render edges with width superior to 1.
PROGRAM_NO_INTERPOLATION, //! Used to render faces without interpolating their color.
PROGRAM_HEAT_INTENSITY, //! Used to render special item in Display_property_plugin
PROGRAM_HEAT_INTENSITY, //! Used to render special item in Heat_method_plugin
NB_OF_PROGRAMS //! Holds the number of different programs in this enum.
};
typedef CGAL::Bbox_3 Bbox;

View File

@ -70,7 +70,7 @@ public:
PROGRAM_OLD_FLAT, /** Used to render flat shading without pre computing normals without geometry shader*/
PROGRAM_SOLID_WIREFRAME, //! Used to render edges with width superior to 1.
PROGRAM_NO_INTERPOLATION, //! Used to render faces without interpolating their color.
PROGRAM_HEAT_INTENSITY, //! Used to render special item in Display_property_plugin
PROGRAM_HEAT_INTENSITY, //! Used to render special item in Heat_method_plugin
PROGRAM_TETRA_FILTERING, //! Used in Scene_tetrahedra_item with Tetrahedra_filtering_plugin
NB_OF_PROGRAMS //! Holds the number of different programs in this enum.
};

View File

@ -347,8 +347,8 @@ ask the triangulation to construct the set of edges
(\f$ 1\f$ dimensional faces) incident to the vertex at infinity. It is easy to see that
these edges are in bijection with the vertices on the convex hull of the
points. This gives us a handy way to count the convex hull vertices
(include files <tt>triangulation1.cpp</tt> and
<tt>triangulation2.cpp</tt> are given and commented below).
(include files <tt>triangulation1.h</tt> and
<tt>triangulation2.h</tt> are given and commented below).
\cgalExample{triangulation.cpp}
@ -368,14 +368,14 @@ there are (at least) two possibilities:
The first is to iterate over the full cells of the triangulation and check if they
are infinite or not:
\cgalExample{triangulation1.cpp}
\cgalExample{triangulation1.h}
A second possibility is to ask the triangulation to gather all the full cells
incident to the infinite vertex: they form precisely the set of infinite
full cells:
\cgalExample{triangulation2.cpp}
\cgalExample{triangulation2.h}
One important difference between the two examples above is that the first uses
<I>little</I> memory but traverses <I>all</I> the full cells, while the second

View File

@ -3,8 +3,8 @@
\example delaunay_triangulation.cpp
\example regular_triangulation.cpp
\example triangulation.cpp
\example triangulation1.cpp
\example triangulation2.cpp
\example triangulation1.h
\example triangulation2.h
\example triangulation_data_structure_dynamic.cpp
\example triangulation_data_structure_static.cpp
*/

View File

@ -36,8 +36,8 @@ int main()
std::cout << "There are " << edges.size()
<< " vertices on the convex hull." << std::endl;
#include "triangulation1.cpp" // See below
#include "triangulation2.cpp"
#include "triangulation1.h" // See below
#include "triangulation2.h"
return 0;
}

View File

@ -37,6 +37,9 @@ create_single_source_cgal_program("test_static_filters.cpp")
create_single_source_cgal_program("test_triangulation_3.cpp")
create_single_source_cgal_program("test_io_triangulation_3.cpp")
create_single_source_cgal_program("test_triangulation_serialization_3.cpp")
create_single_source_cgal_program("test_dt_deterministic_3.cpp")
create_single_source_cgal_program("test_Triangulation_with_transform_iterator.cpp")
create_single_source_cgal_program("test_Triangulation_with_zip_iterator.cpp")
if(TARGET CGAL::TBB_support)
message(STATUS "Found TBB")

View File

@ -27,9 +27,9 @@ int main()
std::stringstream buffer;
buffer << dt3;
//~ std::ofstream out ("test_dt_deterministic_3.in");
//~ out << dt3;
//std::ofstream out ("test_dt_deterministic_3.in");
//out << dt3;
//out.close();
//reading the result from a file
std::ifstream file ("test_dt_deterministic_3.in");

File diff suppressed because it is too large Load Diff