diff --git a/.gitignore b/.gitignore index c1553f03af9..44a3f3a6bd0 100644 --- a/.gitignore +++ b/.gitignore @@ -1206,5 +1206,3 @@ gmon.* /Stream_support/test/Stream_support/cgal_test_with_cmake /*.html /Snap_rounding_2/test/Snap_rounding_2/data/out -/Operations_on_polyhedra/examples/Operations_on_polyhedra/cgal_test_with_cmake -/Operations_on_polyhedra/test/Operations_on_polyhedra/cgal_test_with_cmake diff --git a/.travis.yml b/.travis.yml index d5461dd8ece..5959198a264 100644 --- a/.travis.yml +++ b/.travis.yml @@ -29,28 +29,27 @@ env: - PACKAGE='Mesher_level Minkowski_sum_2 Minkowski_sum_3 ' - PACKAGE='Modifier Modular_arithmetic Nef_2 ' - PACKAGE='Nef_3 Nef_S2 NewKernel_d ' - - PACKAGE='Number_types OpenNL Operations_on_polyhedra ' - - PACKAGE='Optimal_transportation_reconstruction_2 Optimisation_basic Partition_2 ' - - PACKAGE='Periodic_2_triangulation_2 Periodic_3_mesh_3 Periodic_3_triangulation_3 ' - - PACKAGE='Point_set_2 Point_set_3 Point_set_processing_3 ' - - PACKAGE='Point_set_shape_detection_3 Poisson_surface_reconstruction_3 Polygon ' - - PACKAGE='Polygon_mesh_processing Polyhedron Polyhedron_IO ' - - PACKAGE='Polyline_simplification_2 Polynomial Polytope_distance_d ' - - PACKAGE='Principal_component_analysis Principal_component_analysis_LGPL Profiling_tools ' - - PACKAGE='Property_map QP_solver Random_numbers ' - - PACKAGE='Ridges_3 Scale_space_reconstruction_3 Scripts ' - - PACKAGE='SearchStructures Segment_Delaunay_graph_2 Segment_Delaunay_graph_Linf_2 ' - - PACKAGE='Set_movable_separability_2 Skin_surface_3 Snap_rounding_2 ' - - PACKAGE='Solver_interface Spatial_searching Spatial_sorting ' - - PACKAGE='STL_Extension Straight_skeleton_2 Stream_lines_2 ' - - PACKAGE='Stream_support Subdivision_method_3 Surface_mesh ' - - PACKAGE='Surface_mesh_deformation Surface_mesher Surface_mesh_parameterization ' - - PACKAGE='Surface_mesh_segmentation Surface_mesh_shortest_path Surface_mesh_simplification ' - - PACKAGE='Surface_mesh_skeletonization Surface_sweep_2 TDS_2 ' - - PACKAGE='TDS_3 Testsuite Three ' - - PACKAGE='Triangulation Triangulation_2 Triangulation_3 ' - - PACKAGE='Union_find Visibility_2 Voronoi_diagram_2 ' - - PACKAGE='wininst ' + - PACKAGE='Number_types OpenNL Optimal_transportation_reconstruction_2 ' + - PACKAGE='Optimisation_basic Partition_2 Periodic_2_triangulation_2 ' + - PACKAGE='Periodic_3_mesh_3 Periodic_3_triangulation_3 Point_set_2 ' + - PACKAGE='Point_set_3 Point_set_processing_3 Point_set_shape_detection_3 ' + - PACKAGE='Poisson_surface_reconstruction_3 Polygon Polygon_mesh_processing ' + - PACKAGE='Polyhedron Polyhedron_IO Polyline_simplification_2 ' + - PACKAGE='Polynomial Polytope_distance_d Principal_component_analysis ' + - PACKAGE='Principal_component_analysis_LGPL Profiling_tools Property_map ' + - PACKAGE='QP_solver Random_numbers Ridges_3 ' + - PACKAGE='Scale_space_reconstruction_3 Scripts SearchStructures ' + - PACKAGE='Segment_Delaunay_graph_2 Segment_Delaunay_graph_Linf_2 Set_movable_separability_2 ' + - PACKAGE='Skin_surface_3 Snap_rounding_2 Solver_interface ' + - PACKAGE='Spatial_searching Spatial_sorting STL_Extension ' + - PACKAGE='Straight_skeleton_2 Stream_lines_2 Stream_support ' + - PACKAGE='Subdivision_method_3 Surface_mesh Surface_mesh_deformation ' + - PACKAGE='Surface_mesher Surface_mesh_parameterization Surface_mesh_segmentation ' + - PACKAGE='Surface_mesh_shortest_path Surface_mesh_simplification Surface_mesh_skeletonization ' + - PACKAGE='Surface_sweep_2 TDS_2 TDS_3 ' + - PACKAGE='Testsuite Three Triangulation ' + - PACKAGE='Triangulation_2 Triangulation_3 Union_find ' + - PACKAGE='Visibility_2 Voronoi_diagram_2 wininst ' compiler: clang-3.6 install: - echo "$PWD" @@ -63,7 +62,7 @@ before_script: - sudo chmod +x /usr/bin/doxygen - mkdir -p build - cd build -- cmake -DCMAKE_CXX_FLAGS="-std=c++11" -DCGAL_HEADER_ONLY=ON -DQt5_DIR="/opt/qt55/lib/cmake/Qt5" -DQt5Svg_DIR="/opt/qt55/lib/cmake/Qt5Svg" -DQt5OpenGL_DIR="/opt/qt55/lib/cmake/Qt5OpenGL" -DCMAKE_CXX_FLAGS_RELEASE=-DCGAL_NDEBUG .. +- cmake -DCMAKE_CXX_FLAGS="-std=c++11" -DCGAL_HEADER_ONLY=ON -DQt5_DIR="/opt/qt55/lib/cmake/Qt5" -DQt5Svg_DIR="/opt/qt55/lib/cmake/Qt5Svg" -DQt5OpenGL_DIR="/opt/qt55/lib/cmake/Qt5OpenGL" -DCMAKE_CXX_FLAGS_RELEASE=-DCGAL_NDEBUG -DWITH_examples=ON -DWITH_demos=ON -DWITH_tests=ON .. - make - sudo make install &>/dev/null - cd .. diff --git a/.travis/packages.txt b/.travis/packages.txt index 4c872da0115..53b128c1c85 100644 --- a/.travis/packages.txt +++ b/.travis/packages.txt @@ -69,7 +69,6 @@ Nef_S2 NewKernel_d Number_types OpenNL -Operations_on_polyhedra Optimal_transportation_reconstruction_2 Optimisation_basic Partition_2 diff --git a/.travis/template.txt b/.travis/template.txt index c023fe68f3e..1632aa16cbf 100644 --- a/.travis/template.txt +++ b/.travis/template.txt @@ -19,7 +19,7 @@ before_script: - sudo chmod +x /usr/bin/doxygen - mkdir -p build - cd build -- cmake -DCMAKE_CXX_FLAGS="-std=c++11" -DCGAL_HEADER_ONLY=ON -DQt5_DIR="/opt/qt55/lib/cmake/Qt5" -DQt5Svg_DIR="/opt/qt55/lib/cmake/Qt5Svg" -DQt5OpenGL_DIR="/opt/qt55/lib/cmake/Qt5OpenGL" -DCMAKE_CXX_FLAGS_RELEASE=-DCGAL_NDEBUG .. +- cmake -DCMAKE_CXX_FLAGS="-std=c++11" -DCGAL_HEADER_ONLY=ON -DQt5_DIR="/opt/qt55/lib/cmake/Qt5" -DQt5Svg_DIR="/opt/qt55/lib/cmake/Qt5Svg" -DQt5OpenGL_DIR="/opt/qt55/lib/cmake/Qt5OpenGL" -DCMAKE_CXX_FLAGS_RELEASE=-DCGAL_NDEBUG -DWITH_examples=ON -DWITH_demos=ON -DWITH_tests=ON .. - make - sudo make install &>/dev/null - cd .. diff --git a/Arrangement_on_surface_2/test/Arrangement_on_surface_2/cgal_test_base b/Arrangement_on_surface_2/test/Arrangement_on_surface_2/cgal_test_base deleted file mode 100755 index bfd9c7c30b6..00000000000 --- a/Arrangement_on_surface_2/test/Arrangement_on_surface_2/cgal_test_base +++ /dev/null @@ -1,1759 +0,0 @@ -#! /bin/bash - -# This is a script for the CGAL test suite. Such a script must obey -# the following rules: -# -# - the name of the script is cgal_test -# - for every target two one line messages are written to the file 'error.txt' -# the first one indicates if the compilation was successful -# the second one indicates if the execution was successful -# if one of the two was not successful, the line should start with 'ERROR:' -# - running the script should not require any user interaction -# - the script should clean up object files and executables - -# SET PARAMETERS FOR cgal_test - - -ERRORFILE=error.txt -DO_RUN=y -if [ -z "${MAKE_CMD}" ]; then - MAKE_CMD=make -fi - - -FULL_ERROR_DESCRIPTION_FILE=ProgramOutput.error.txt - -#---------------------------------------------------------------------# -# compile_and_run -#---------------------------------------------------------------------# - -# note that these values shloud match to the values in test_configuration.h file - -CARTESIAN_KERNEL=0 -SIMPLE_CARTESIAN_KERNEL=1 -UNIVARIATE_ALGEBRAIC_KERNEL=2 - -SEGMENT_GEOM_TRAITS=0 -NON_CACHING_SEGMENT_GEOM_TRAITS=1 -POLYLINE_GEOM_TRAITS=2 -NON_CACHING_POLYLINE_GEOM_TRAITS=3 -POLYCURVE_CONIC_GEOM_TRAITS=14 -POLYCURVE_CIRCULAR_ARC_GEOM_TRAITS=15 -POLYCURVE_BEZIER_GEOM_TRAITS=16 -LINEAR_GEOM_TRAITS=4 -CORE_CONIC_GEOM_TRAITS=5 -LINE_ARC_GEOM_TRAITS=6 -CIRCULAR_ARC_GEOM_TRAITS=7 -CIRCULAR_LINE_ARC_GEOM_TRAITS=8 -CIRCLE_SEGMENT_GEOM_TRAITS=9 -BEZIER_GEOM_TRAITS=10 -GEODESIC_ARC_ON_SPHERE_GEOM_TRAITS=11 -RATIONAL_ARC_GEOM_TRAITS=12 -ALGEBRAIC_GEOM_TRAITS=13 -POLYCURVE_CONIC_GEOM_TRAITS=14 -POLYCURVE_CIRCULAR_ARC_GEOM_TRAITS=15 -POLYCURVE_BEZIER_GEOM_TRAITS=16 -FLAT_TORUS_GEOM_TRAITS=17 - -PLANAR_BOUNDED_TOPOL_TRAITS=0 -PLANAR_UNBOUNDED_TOPOL_TRAITS=1 -SPHERICAL_TOPOL_TRAITS=2 - -DOUBLE_NT=0 -MP_FLOAT_NT=1 -GMPZ_NT=2 -LEDA_RAT_NT=3 -QUOTIENT_MP_FLOAT_NT=4 -QUOTIENT_CGAL_GMPZ_NT=5 -CGAL_GMPQ_NT=6 -LAZY_LEDA_RAT_NT=7 -LAZY_CGAL_GMPQ_NT=8 -LAZY_QUOTIENT_MP_FLOAT_NT=9 -LEDA_REAL_NT=10 -CORE_EXPR_NT=11 -LAZY_GMPZ_NT=12 -LEDA_INT_NT=13 -CGAL_GMPZ_NT=14 -CORE_INT_NT=15 -CORE_RAT_NT=16 - -if [ -n "${CGAL_DISABLE_GMP}" ]; then - echo GMP is disable. Try to use LEDA instead. - GMPZ_NT=$LEDA_INT_NT - QUOTIENT_CGAL_GMPZ_NT=$LEDA_RAT_NT - CGAL_GMPQ_NT=$LEDA_RAT_NT - LAZY_CGAL_GMPQ_NT=$LAZY_LEDA_RAT_NT - LAZY_GMPZ_NT=$LAZY_LEDA_RAT_NT - CGAL_GMPZ_NT=$LEDA_INT_NT -fi - -COMPARE=1 -VERTEX=2 -IS_VERTICAL=3 -COMPARE_Y_AT_X=4 -COMPARE_Y_AT_X_LEFT=5 -COMPARE_Y_AT_X_RIGHT=6 -MAKE_X_MONOTONE=7 -INTERSECT=8 -SPLIT=9 -ARE_MERGEABLE=10 -MERGE=11 -ASSERTIONS=12 -CONSTRUCTOR=13 -COMPARE_X_AT_LIMIT=14 -COMPARE_X_NEAR_LIMIT=15 -COMPARE_X_ON_BOUNDARY=16 -COMPARE_X_NEAR_BOUNDARY=17 -COMPARE_Y_NEAR_BOUNDARY=18 -PARAMETER_SPACE_X=19 -PARAMETER_SPACE_Y=20 -X_ON_IDENTIFICATION=21 -Y_ON_IDENTIFICATION=22 -IS_BOUNDED=23 -IS_IN_X_RANGE=24 -COMPARE_Y_POSITION=25 -IS_BETWEEN_CW=26 -COMPARE_CW_AROUND_POINT=27 -PUSH_BACK=28 -PUSH_FRONT=29 -NUMBER_OF_POINTS=32 -COMPARE_ENDPOINTS_XY=33 -CONSTRUCT_OPPOSITE=34 -TRIM=35 - -#---------------------------------------------------------------------# -# configure -#---------------------------------------------------------------------# - -configure() -{ - echo "Configuring... " - rm -rf CMakeCache.txt CMakeFiles/ - echo "cmake --no-warn-unused-cli "$CMAKE_GENERATOR" -DRUNNING_CGAL_AUTO_TEST=TRUE \ - -DCGAL_DIR=\"$CGAL_DIR\" \ - -DCGAL_CXX_FLAGS:STRING=\"$TESTSUITE_CXXFLAGS -I../../include\" \ - -DCGAL_EXE_LINKER_FLAGS=\"$TESTSUITE_LDFLAGS\" \ - -DCMAKE_BUILD_TYPE=NOTFOUND \ - ." - if eval 'cmake --no-warn-unused-cli "$CMAKE_GENERATOR" -DRUNNING_CGAL_AUTO_TEST=TRUE \ - -DCGAL_DIR="$CGAL_DIR" \ - -DCGAL_CXX_FLAGS:STRING="$TESTSUITE_CXXFLAGS -I../../include" \ - -DCGAL_EXE_LINKER_FLAGS="$TESTSUITE_LDFLAGS" \ - -DCMAKE_BUILD_TYPE=NOTFOUND \ - .' ; then - - echo " successful configuration" >> $ERRORFILE - else - echo " ERROR: configuration" >> $ERRORFILE - fi -} - -compile_test_with_flags() -{ - local name=$1; - local type=$2; - local flags=$3; - - echo "Compiling $name $type ... " - if [ "${TEST_WITH_CMAKE}" != "FALSE" ]; then - export TESTSUITE_CXXFLAGS="$flags" - configure - if eval '${MAKE_CMD} VERBOSE=1 -fMakefile \ - $name' ; then - echo " successful compilation of $name $type" >> $ERRORFILE; - SUCCESS="y" - else - echo " ERROR: compilation of $name $type" >> $ERRORFILE; - SUCCESS="" - fi - else - if eval 'make CGAL_MAKEFILE=$CGAL_MAKEFILE \ - TESTSUITE_CXXFLAGS="$TESTSUITE_CXXFLAGS" \ - TESTSUITE_LDFLAGS="$TESTSUITE_LDFLAGS" $name'; then - echo " successful compilation of $name $type" >> $ERRORFILE; - SUCCESS="y" - else - echo " ERROR: compilation of $name $type" >> $ERRORFILE; - SUCCESS="" - fi - fi -} - -run_test() -{ - # $1 - executable name - - basedata=`basename "$5"` - OUTPUTFILE="ProgramOutput.$1" - rm -f $OUTPUTFILE - COMMAND="./$1" - if [ -f $1.cmd ] ; then - COMMAND="$COMMAND `cat $1.cmd`" - fi - if [ -f $1.cin ] ; then - COMMAND="cat $1.cin | $COMMAND" - fi - OUTPUTFILE="$OUTPUTFILE.$PLATFORM" - echo "Executing $1 ($2) ... " - ulimit -t 3600 2> /dev/null - if eval $COMMAND > $OUTPUTFILE 2>&1 ; then - echo " successful execution of $1" >> $ERRORFILE - else - echo " ERROR: execution of $1" >> $ERRORFILE - cat $OUTPUTFILE >> $FULL_ERROR_DESCRIPTION_FILE - fi -} - -run_test_with_flags() -{ - # $1 - executable name - # $2 - test substring name - - basedata=`basename "$5"` - OUTPUTFILE="ProgramOutput.$1" - rm -f $OUTPUTFILE - COMMAND="./$1" - if [ -f $1.cmd ] ; then - COMMAND="$COMMAND `cat $1.cmd`" - elif [ -f $1.$2.cmd ] ; then - COMMAND="$COMMAND `cat $1.$2.cmd`" - OUTPUTFILE=$OUTPUTFILE.`echo $2 | tr '/' '.'` - fi - if [ -f $1.cin ] ; then - COMMAND="cat $1.cin | $COMMAND" - elif [ -f $1.$2.cin ] ; then - COMMAND="cat $1.$2.cin | $COMMAND" - OUTPUTFILE=$OUTPUTFILE.`echo $2 | tr '/' '.'` - fi - OUTPUTFILE="$OUTPUTFILE.$PLATFORM" - echo "Executing $1 ($2) ... " - ulimit -t 3600 2> /dev/null - if eval $COMMAND > $OUTPUTFILE 2>&1 ; then - echo " successful execution of $1 ($2)" >> $ERRORFILE - else - echo " ERROR: execution of $1 ($2)" >> $ERRORFILE - cat $OUTPUTFILE >> $FULL_ERROR_DESCRIPTION_FILE - fi -} - -run_test_alt() -{ - basedata=`basename "$5"` - OUTPUTFILE=ProgramOutput.$1.`echo $5 | tr '/' '.'`.$6 - #echo ****generating file $OUTPUTFILE - # dirdata=`dirname "$datafile"` - rm -f $OUTPUTFILE - COMMAND="./$1" - echo "Executing $1 $5 $6 ... " - if eval $COMMAND $2 $3 $4 $5 $6 > $OUTPUTFILE 2>&1 ; then - echo " successful execution of $5 $6" >> $ERRORFILE - else - echo " ERROR: execution of $5 $6" >> $ERRORFILE - cat $OUTPUTFILE >> $FULL_ERROR_DESCRIPTION_FILE - fi -} - -run_trapped_test() -{ - #local name=$1; - #local datafile=$2; - - if [ "${OSTYPE}" != "cygwin" ]; then - ulimit -t 1200 - run_test_alt $1 $2 $3 $4 $5 $6 - else - run_test_alt $1 $2 $3 $4 $5 $6 & - WPID=$! - trap "kill -9 $WPID" INT - (sleep 1200; kill -9 $WPID) > /dev/null 2>&1 & - SPID=$! - wait $WPID > /dev/null 2>&1 - # RES=$? - kill -9 $SPID > /dev/null 2>&1 - # return $RES - fi -} - -clean_tests() -{ - if [ "${TEST_WITH_CMAKE}" != "FALSE" ]; then - # - # The clean target generated by CMake under cygwin - # always fails for some reason - # - if ! ( uname | grep -q "CYGWIN" ) ; then - make -fMakefile clean - fi - fi - eval "make clean > /dev/null 2>&1" -} - -compile_and_run() -{ - local name=$1; - - echo "Compiling $name ... " - if [ "${TEST_WITH_CMAKE}" != "FALSE" ]; then - if eval '${MAKE_CMD} VERBOSE=1 -fMakefile $1' ; then - echo " successful compilation of $1" >> $ERRORFILE - SUCCESS="y" - else - echo " ERROR: compilation of $1" >> $ERRORFILE - SUCCESS="" - fi - else - SUCCESS="y" - #TESTSUITE_CXXFLAGS="$TESTSUITE_CXXFLAGS" - TESTSUITE_CXXFLAGS="" - TESTSUITE_LDFLAGS="$TESTSUITE_LDFLAGS" - if eval 'make CGAL_MAKEFILE=$CGAL_MAKEFILE \ - TESTSUITE_CXXFLAGS="$TESTSUITE_CXXFLAGS" \ - TESTSUITE_LDFLAGS="$TESTSUITE_LDFLAGS" $name' ; then - echo " successful compilation of $name" >> $ERRORFILE - else - echo " ERROR: compilation of $name" >> $ERRORFILE - SUCCESS="" - fi - fi - - if [ "${TEST_WITH_CMAKE}" != "FALSE" ]; then - if [ -n "$DO_RUN" ] ; then - if [ -n "${SUCCESS}" ] ; then - run_test $1 - else - echo " ERROR: not executed $1" >> $ERRORFILE - fi - fi - else - if [ -n "${SUCCESS}" ] ; then - OUTPUTFILE=ProgramOutput.$name.$PLATFORM - rm -f $OUTPUTFILE - COMMAND="./$name" - if [ -f $name.cmd ] ; then - COMMAND="$COMMAND `cat $name.cmd`" - fi - if [ -f $name.cin ] ; then - COMMAND="cat $name.cin | $COMMAND" - fi - echo "Executing $name ... " - echo " " - if eval $COMMAND > $OUTPUTFILE 2>&1 ; then - echo " successful execution of $name" >> $ERRORFILE - else - echo " ERROR: execution of $name" >> $ERRORFILE - cat $OUTPUTFILE >> $FULL_ERROR_DESCRIPTION_FILE - fi - else - echo " ERROR: not executed $name" >> $ERRORFILE - fi - fi - clean_tests -} - -compile_and_run_trapped_test() -{ - local name=$1; - - if [ "${OSTYPE}" != "cygwin" ]; then - ulimit -t 1200 - compile_and_run $1 - else - compile_and_run $1 & - WPID=$! - trap "kill -9 $WPID" INT - (sleep 1200; kill -9 $WPID) > /dev/null 2>&1 & - SPID=$! - wait $WPID > /dev/null 2>&1 - # RES=$? - kill -9 $SPID > /dev/null 2>&1 - # return $RES - fi -} - -execute_commands_old_structure() -{ - -# at first the tests where designed in such way that all the test input was -# in one file, the points, the xcurves, the curves and the execution block -# this function is used to execute the old tests, one may use it when needed -# but you should remember that separating the input into smaller files creates -# much more modular and comfortable test suite - -# the old structure is default, so this function executes all commands -# except the commands that are given as arguments - - - commands_indicator[COMPARE]=1 - commands_indicator[VERTEX]=1 - commands_indicator[IS_VERTICAL]=1 - commands_indicator[COMPARE_Y_AT_X]=1 - commands_indicator[COMPARE_Y_AT_X_LEFT]=1 - commands_indicator[COMPARE_Y_AT_X_RIGHT]=1 - commands_indicator[MAKE_X_MONOTONE]=1 - commands_indicator[INTERSECT]=1 - commands_indicator[SPLIT]=1 - commands_indicator[ARE_MERGEABLE]=1 - commands_indicator[MERGE]=1 - commands_indicator[ASSERTIONS]=1 - commands_indicator[CONSTRUCTOR]=1 - i=1 - if [ $# -gt 2 ] ; then - for arg in $* ; do - if [ $i -gt 2 ] ; then - commands_indicator[$arg]=0 - fi - let "i+=1" - done - fi - if [ ${commands_indicator[$COMPARE]} -ne 0 ] ; then - run_trapped_test test_traits \ - data/compare.pt data/empty.zero \ - data/empty.zero data/compare $2 - fi - if [ ${commands_indicator[$VERTEX]} -ne 0 ] ; then - run_trapped_test test_traits \ - data/$1/vertex.pt data/$1/vertex.xcv \ - data/empty.zero data/$1/vertex $2 - fi - if [ ${commands_indicator[$IS_VERTICAL]} -ne 0 ] ; then - run_trapped_test test_traits \ - data/empty.zero data/$1/is_vertical.xcv data/empty.zero \ - data/$1/is_vertical $2 - fi - if [ ${commands_indicator[$COMPARE_Y_AT_X]} -ne 0 ] ; then - run_trapped_test test_traits \ - data/$1/compare_y_at_x.pt data/$1/compare_y_at_x.xcv \ - data/empty.zero data/$1/compare_y_at_x $2 - fi - if [ ${commands_indicator[$COMPARE_Y_AT_X_LEFT]} -ne 0 ] ; then - run_trapped_test test_traits \ - data/$1/compare_y_at_x_left.pt data/$1/compare_y_at_x_left.xcv \ - data/empty.zero data/$1/compare_y_at_x_left $2 - fi - if [ ${commands_indicator[$COMPARE_Y_AT_X_RIGHT]} -ne 0 ] ; then - run_trapped_test test_traits \ - data/$1/compare_y_at_x_right.pt data/$1/compare_y_at_x_right.xcv \ - data/empty.zero data/$1/compare_y_at_x_right $2 - fi - if [ ${commands_indicator[$MAKE_X_MONOTONE]} -ne 0 ] ; then - run_trapped_test test_traits \ - data/empty.zero data/$1/make_x_monotone.xcv \ - data/$1/make_x_monotone.cv data/$1/make_x_monotone $2 - fi - if [ ${commands_indicator[$INTERSECT]} -ne 0 ] ; then - run_trapped_test test_traits \ - data/$1/intersect.pt data/$1/intersect.xcv \ - data/empty.zero data/$1/intersect $2 - fi - if [ ${commands_indicator[$SPLIT]} -ne 0 ] ; then - run_trapped_test test_traits \ - data/$1/split.pt data/$1/split.xcv \ - data/empty.zero data/$1/split $2 - fi - if [ ${commands_indicator[$ARE_MERGEABLE]} -ne 0 ] ; then - run_trapped_test test_traits \ - data/empty.zero data/$1/are_mergeable.xcv \ - data/empty.zero data/$1/are_mergeable $2 - fi - if [ ${commands_indicator[$MERGE]} -ne 0 ] ; then - run_trapped_test test_traits \ - data/empty.zero data/$1/merge.xcv \ - data/empty.zero data/$1/merge $2 - fi - if [ ${commands_indicator[$ASSERTIONS]} -ne 0 ] ; then - run_trapped_test test_traits \ - data/$1/assertions.pt data/$1/assertions.xcv \ - data/empty.zero data/$1/assertions $2 - fi - if [ ${commands_indicator[$CONSTRUCTOR]} -ne 0 ] ; then - run_trapped_test test_traits \ - data/empty.zero data/$1/constructor.xcv \ - data/$1/constructor.cv data/$1/constructor $2 - fi -} - -execute_commands_new_structure() -{ - -# the new design for the tests includes separation of the test input into 4 -# parts: points file, xcurves file, curves file and execution block file. -# one may reuse the input files for the various tests - -# the new structure is not default, so this function executes only -# commands that are given as arguments - - commands_indicator[COMPARE]=0 - commands_indicator[VERTEX]=0 - commands_indicator[IS_VERTICAL]=0 - commands_indicator[COMPARE_X_AT_LIMIT]=0 - commands_indicator[COMPARE_X_NEAR_LIMIT]=0 - commands_indicator[COMPARE_X_ON_BOUNDARY]=0 - commands_indicator[COMPARE_X_NEAR_BOUNDARY]=0 - commands_indicator[COMPARE_Y_NEAR_BOUNDARY]=0 - commands_indicator[PARAMETER_SPACE_X]=0 - commands_indicator[PARAMETER_SPACE_Y]=0 - commands_indicator[COMPARE_Y_AT_X]=0 - commands_indicator[COMPARE_Y_AT_X_LEFT]=0 - commands_indicator[COMPARE_Y_AT_X_RIGHT]=0 - commands_indicator[MAKE_X_MONOTONE]=0 - commands_indicator[INTERSECT]=0 - commands_indicator[SPLIT]=0 - commands_indicator[ARE_MERGEABLE]=0 - commands_indicator[MERGE]=0 - commands_indicator[ASSERTIONS]=0 - commands_indicator[CONSTRUCTOR]=0 - commands_indicator[EQUAL]=0 - commands_indicator[PUSH_BACK]=0 - commands_indicator[PUSH_FRONT]=0 - commands_indicator[NUMBER_OF_POINTS]=0 - commands_indicator[COMPARE_ENDPOINTS_XY]=0 - commands_indicator[CONSTRUCT_OPPOSITE]=0 - commands_indicator[TRIM]=0 - i=1 - if [ $# -gt 2 ] ; then - for arg in $* ; do - if [ $i -gt 2 ] ; then - commands_indicator[$arg]=1 - fi - let "i+=1" - done - fi - if [ ${commands_indicator[$COMPARE]} -ne 0 ] ; then - run_trapped_test test_traits data/$1/points \ - data/$1/xcurves data/$1/curves data/$1/compare $2 - fi - if [ ${commands_indicator[$VERTEX]} -ne 0 ] ; then - run_trapped_test test_traits data/$1/points \ - data/$1/xcurves data/$1/curves data/$1/vertex $2 - fi - if [ ${commands_indicator[$IS_VERTICAL]} -ne 0 ] ; then - run_trapped_test test_traits data/$1/points \ - data/$1/xcurves data/$1/curves data/$1/is_vertical $2 - fi - if [ ${commands_indicator[$COMPARE_X_AT_LIMIT]} -ne 0 ] ; then - run_trapped_test test_traits data/$1/points \ - data/$1/xcurves data/$1/curves data/$1/compare_x_at_limit $2 - fi - if [ ${commands_indicator[$COMPARE_X_NEAR_LIMIT]} -ne 0 ] ; then - run_trapped_test test_traits data/$1/points \ - data/$1/xcurves data/$1/curves data/$1/compare_x_near_limit $2 - fi - if [ ${commands_indicator[$COMPARE_X_ON_BOUNDARY]} -ne 0 ] ; then - run_trapped_test test_traits data/$1/points \ - data/$1/xcurves data/$1/curves data/$1/compare_x_on_boundary $2 - fi - if [ ${commands_indicator[$COMPARE_X_NEAR_BOUNDARY]} -ne 0 ] ; then - run_trapped_test test_traits data/$1/points \ - data/$1/xcurves data/$1/curves data/$1/compare_x_near_boundary $2 - fi - if [ ${commands_indicator[$COMPARE_Y_NEAR_BOUNDARY]} -ne 0 ] ; then - run_trapped_test test_traits data/$1/points \ - data/$1/xcurves data/$1/curves data/$1/compare_y_near_boundary $2 - fi - if [ ${commands_indicator[$PARAMETER_SPACE_X]} -ne 0 ] ; then - run_trapped_test test_traits data/$1/points \ - data/$1/xcurves data/$1/curves data/$1/parameter_space_x $2 - fi - if [ ${commands_indicator[$PARAMETER_SPACE_Y]} -ne 0 ] ; then - run_trapped_test test_traits data/$1/points \ - data/$1/xcurves data/$1/curves data/$1/parameter_space_y $2 - fi - if [ ${commands_indicator[$COMPARE_Y_AT_X]} -ne 0 ] ; then - run_trapped_test test_traits data/$1/points \ - data/$1/xcurves data/$1/curves data/$1/compare_y_at_x $2 - fi - if [ ${commands_indicator[$COMPARE_Y_AT_X_LEFT]} -ne 0 ] ; then - run_trapped_test test_traits data/$1/points \ - data/$1/xcurves data/$1/curves data/$1/compare_y_at_x_left $2 - fi - if [ ${commands_indicator[$COMPARE_Y_AT_X_RIGHT]} -ne 0 ] ; then - run_trapped_test test_traits data/$1/points \ - data/$1/xcurves data/$1/curves data/$1/compare_y_at_x_right $2 - fi - if [ ${commands_indicator[$MAKE_X_MONOTONE]} -ne 0 ] ; then - run_trapped_test test_traits data/$1/points \ - data/$1/xcurves data/$1/curves data/$1/make_x_monotone $2 - fi - if [ ${commands_indicator[$INTERSECT]} -ne 0 ] ; then - run_trapped_test test_traits data/$1/points \ - data/$1/xcurves data/$1/curves data/$1/intersect $2 - fi - if [ ${commands_indicator[$SPLIT]} -ne 0 ] ; then - run_trapped_test test_traits data/$1/points \ - data/$1/xcurves data/$1/curves data/$1/split $2 - fi - if [ ${commands_indicator[$ARE_MERGEABLE]} -ne 0 ] ; then - run_trapped_test test_traits data/$1/points \ - data/$1/xcurves data/$1/curves data/$1/are_mergeable $2 - fi - if [ ${commands_indicator[$MERGE]} -ne 0 ] ; then - run_trapped_test test_traits data/$1/points \ - data/$1/xcurves data/$1/curves data/$1/merge $2 - fi - if [ ${commands_indicator[$ASSERTIONS]} -ne 0 ] ; then - run_trapped_test test_traits data/$1/points \ - data/$1/xcurves data/$1/curves data/$1/assertions $2 - fi - if [ ${commands_indicator[$CONSTRUCTOR]} -ne 0 ] ; then - run_trapped_test test_traits data/$1/points \ - data/$1/xcurves data/$1/curves data/$1/constructor $2 - fi - if [ ${commands_indicator[$EQUAL]} -ne 0 ] ; then - run_trapped_test test_traits data/$1/points \ - data/$1/xcurves data/$1/curves data/$1/equal $2 - fi - if [ ${commands_indicator[$PUSH_BACK]} -ne 0 ] ; then - run_trapped_test test_traits data/$1/points \ - data/$1/xcurves data/$1/curves data/$1/push_back $2 - fi - if [ ${commands_indicator[$PUSH_FRONT]} -ne 0 ] ; then - run_trapped_test test_traits data/$1/points \ - data/$1/xcurves data/$1/curves data/$1/push_front $2 - fi - if [ ${commands_indicator[$NUMBER_OF_POINTS]} -ne 0 ] ; then - run_trapped_test test_traits data/$1/points \ - data/$1/xcurves data/$1/curves data/$1/number_of_points $2 - fi - if [ ${commands_indicator[$COMPARE_ENDPOINTS_XY]} -ne 0 ] ; then - run_trapped_test test_traits data/$1/points \ - data/$1/xcurves data/$1/curves data/$1/compare_endpoints_xy $2 - fi - if [ ${commands_indicator[$CONSTRUCT_OPPOSITE]} -ne 0 ] ; then - run_trapped_test test_traits data/$1/points \ - data/$1/xcurves data/$1/curves data/$1/construct_opposite $2 - fi - if [ ${commands_indicator[$TRIM]} -ne 0 ] ; then - run_trapped_test test_traits data/$1/points \ - data/$1/xcurves data/$1/curves data/$1/trim $2 - fi -} - -execute_commands_traits_adaptor() -{ - -# the new structure is not default, so this function executes only -# commands that are given as arguments - - commands_indicator[PARAMETER_SPACE_X]=0 - commands_indicator[PARAMETER_SPACE_Y]=0 - commands_indicator[COMPARE_X_AT_LIMIT]=0 - commands_indicator[COMPARE_X_NEAR_LIMIT]=0 - commands_indicator[COMPARE_X_ON_BOUNDARY]=0 - commands_indicator[COMPARE_X_NEAR_BOUNDARY]=0 - commands_indicator[COMPARE_Y_NEAR_BOUNDARY]=0 - commands_indicator[COMPARE_Y_AT_X_LEFT]=0 - commands_indicator[ARE_MERGEABLE]=0 - commands_indicator[MERGE]=0 - commands_indicator[X_ON_IDENTIFICATION]=0 - commands_indicator[Y_ON_IDENTIFICATION]=0 - commands_indicator[IS_BOUNDED]=0 - commands_indicator[IS_IN_X_RANGE]=0 - commands_indicator[COMPARE_Y_POSITION]=0 - commands_indicator[IS_BETWEEN_CW]=0 - commands_indicator[COMPARE_CW_AROUND_POINT]=0 - - i=1 - if [ $# -gt 2 ] ; then - for arg in $* ; do - if [ $i -gt 2 ] ; then - commands_indicator[$arg]=1 - fi - let "i+=1" - done - fi - - if [ ${commands_indicator[$PARAMETER_SPACE_X]} -ne 0 ] ; then - run_trapped_test test_traits_adaptor data/test_adaptor/$1/points \ - data/test_adaptor/$1/xcurves data/test_adaptor/$1/curves \ - data/test_adaptor/$1/parameter_space_x $2 - fi - if [ ${commands_indicator[$PARAMETER_SPACE_Y]} -ne 0 ] ; then - run_trapped_test test_traits_adaptor data/test_adaptor/$1/points \ - data/test_adaptor/$1/xcurves data/test_adaptor/$1/curves \ - data/test_adaptor/$1/parameter_space_y $2 - fi - if [ ${commands_indicator[$COMPARE_X_AT_LIMIT]} -ne 0 ] ; then - run_trapped_test test_traits_adaptor data/test_adaptor/$1/points \ - data/test_adaptor/$1/xcurves data/test_adaptor/$1/curves \ - data/test_adaptor/$1/compare_x_at_limit $2 - fi - if [ ${commands_indicator[$COMPARE_X_NEAR_LIMIT]} -ne 0 ] ; then - run_trapped_test test_traits_adaptor data/test_adaptor/$1/points \ - data/test_adaptor/$1/xcurves data/test_adaptor/$1/curves \ - data/test_adaptor/$1/compare_x_near_limit $2 - fi - - if [ ${commands_indicator[$COMPARE_X_ON_BOUNDARY]} -ne 0 ] ; then - run_trapped_test test_traits_adaptor data/test_adaptor/$1/points \ - data/test_adaptor/$1/xcurves data/test_adaptor/$1/curves \ - data/test_adaptor/$1/compare_x_on_boundary $2 - fi - if [ ${commands_indicator[$COMPARE_X_NEAR_BOUNDARY]} -ne 0 ] ; then - run_trapped_test test_traits_adaptor data/test_adaptor/$1/points \ - data/test_adaptor/$1/xcurves data/test_adaptor/$1/curves \ - data/test_adaptor/$1/compare_x_near_boundary $2 - fi - - if [ ${commands_indicator[$COMPARE_Y_NEAR_BOUNDARY]} -ne 0 ] ; then - run_trapped_test test_traits_adaptor data/test_adaptor/$1/points \ - data/test_adaptor/$1/xcurves data/test_adaptor/$1/curves \ - data/test_adaptor/$1/compare_y_near_boundary $2 - fi - if [ ${commands_indicator[$COMPARE_Y_AT_X_LEFT]} -ne 0 ] ; then - run_trapped_test test_traits_adaptor data/test_adaptor/$1/points \ - data/test_adaptor/$1/xcurves data/test_adaptor/$1/curves \ - data/test_adaptor/$1/compare_y_at_x_left $2 - fi - if [ ${commands_indicator[$ARE_MERGEABLE]} -ne 0 ] ; then - run_trapped_test test_traits_adaptor data/test_adaptor/$1/points \ - data/test_adaptor/$1/xcurves data/test_adaptor/$1/curves \ - data/test_adaptor/$1/are_mergeable $2 - fi - if [ ${commands_indicator[$MERGE]} -ne 0 ] ; then - run_trapped_test test_traits_adaptor data/test_adaptor/$1/points \ - data/test_adaptor/$1/xcurves data/test_adaptor/$1/curves \ - data/test_adaptor/$1/merge $2 - fi - if [ ${commands_indicator[X_ON_IDENTIFICATION]} -ne 0 ] ; then - run_trapped_test test_traits_adaptor data/test_adaptor/$1/points \ - data/test_adaptor/$1/xcurves data/test_adaptor/$1/curves \ - data/test_adaptor/$1/x_on_idintification $2 - fi - if [ ${commands_indicator[Y_ON_IDENTIFICATION]} -ne 0 ] ; then - run_trapped_test test_traits_adaptor data/test_adaptor/$1/points \ - data/test_adaptor/$1/xcurves data/test_adaptor/$1/curves \ - data/test_adaptor/$1/x_on_idintification $2 - fi - if [ ${commands_indicator[IS_BOUNDED]} -ne 0 ] ; then - run_trapped_test test_traits_adaptor data/test_adaptor/$1/points \ - data/test_adaptor/$1/xcurves data/test_adaptor/$1/curves \ - data/test_adaptor/$1/is_bounded $2 - fi - if [ ${commands_indicator[IS_IN_X_RANGE]} -ne 0 ] ; then - run_trapped_test test_traits_adaptor data/test_adaptor/$1/points \ - data/test_adaptor/$1/xcurves data/test_adaptor/$1/curves \ - data/test_adaptor/$1/is_in_x_range $2 - fi - if [ ${commands_indicator[COMPARE_Y_POSITION]} -ne 0 ] ; then - run_trapped_test test_traits_adaptor data/test_adaptor/$1/points \ - data/test_adaptor/$1/xcurves data/test_adaptor/$1/curves \ - data/test_adaptor/$1/compare_y_position $2 - fi - if [ ${commands_indicator[IS_BETWEEN_CW]} -ne 0 ] ; then - run_trapped_test test_traits_adaptor data/test_adaptor/$1/points \ - data/test_adaptor/$1/xcurves data/test_adaptor/$1/curves \ - data/test_adaptor/$1/is_between_cw $2 - fi - if [ ${commands_indicator[COMPARE_CW_AROUND_POINT]} -ne 0 ] ; then - run_trapped_test test_traits_adaptor data/test_adaptor/$1/points \ - data/test_adaptor/$1/xcurves data/test_adaptor/$1/curves \ - data/test_adaptor/$1/compare_cw_around_point $2 - fi -} - -#---------------------------------------------------------------------# -# traits adaptor (segments traits) -#---------------------------------------------------------------------# -test_segment_traits_adaptor() -{ - local nt=$QUOTIENT_MP_FLOAT_NT; - local kernel=$CARTESIAN_KERNEL; - local geom_traits=$SEGMENT_GEOM_TRAITS; - local flags="-DTEST_NT=$nt -DTEST_KERNEL=$kernel -DTEST_GEOM_TRAITS=$geom_traits"; - - compile_test_with_flags test_traits_adaptor segments "$flags" - if [ -n "${SUCCESS}" ] ; then - execute_commands_traits_adaptor segments segments_traits_adaptor \ - COMPARE_Y_POSITION COMPARE_CW_AROUND_POINT COMPARE_Y_AT_X_LEFT \ - ARE_MERGEABLE MERGE IS_IN_X_RANGE IS_BETWEEN_CW - else - echo " ERROR: not executed test_traits_adaptor segment_traits" >> $ERRORFILE - fi - clean_tests -} - -#---------------------------------------------------------------------# -# traits adaptor (linear traits) -#---------------------------------------------------------------------# -test_linear_traits_adaptor() -{ - local nt=$QUOTIENT_MP_FLOAT_NT; - local kernel=$CARTESIAN_KERNEL; - local geom_traits=$LINEAR_GEOM_TRAITS; - local flags="-DTEST_NT=$nt -DTEST_KERNEL=$kernel -DTEST_GEOM_TRAITS=$geom_traits"; - - compile_test_with_flags test_traits_adaptor linear "$flags" - if [ -n "${SUCCESS}" ] ; then - execute_commands_traits_adaptor linear linear_traits_adaptor \ - COMPARE_Y_AT_X_LEFT ARE_MERGEABLE MERGE IS_IN_X_RANGE \ - COMPARE_Y_POSITION IS_BETWEEN_CW COMPARE_CW_AROUND_POINT - else - echo " ERROR: not executed test_traits_adaptor linear_traits" >> $ERRORFILE - fi - clean_tests -} - -#---------------------------------------------------------------------# -# traits adaptor (spherical arcs traits) -#---------------------------------------------------------------------# -test_spherical_arcs_traits_adaptor() -{ - local nt=$CGAL_GMPQ_NT; - local kernel=$CARTESIAN_KERNEL; - local geom_traits=$GEODESIC_ARC_ON_SPHERE_GEOM_TRAITS; - local topol_traits=$SPHERICAL_TOPOL_TRAITS - local flags="-DTEST_NT=$nt -DTEST_KERNEL=$kernel -DTEST_GEOM_TRAITS=$geom_traits -DTEST_TOPOL_TRAITS=$topol_traits"; - - compile_test_with_flags test_traits_adaptor geodesic_arcs_on_sphere "$flags" - if [ -n "${SUCCESS}" ] ; then - execute_commands_traits_adaptor spherical_arcs spherical_arcs_traits_adaptor \ - COMPARE_Y_AT_X_LEFT ARE_MERGEABLE MERGE IS_IN_X_RANGE \ - COMPARE_Y_POSITION IS_BETWEEN_CW COMPARE_CW_AROUND_POINT - else - echo " ERROR: not executed test_traits_adaptor spherical_arcs_traits" >> $ERRORFILE - fi - clean_tests -} - -#---------------------------------------------------------------------# -# compile and run test with traits -#---------------------------------------------------------------------# -compile_and_run_with_flags() -{ - local name=$1; - local type=$2; - local flags=$3; - - compile_test_with_flags $name $type "$flags" - if [ -n "${SUCCESS}" ] ; then - if [ -n "$DO_RUN" ] ; then - run_test_with_flags $name $type - fi - else - echo " ERROR: not executed construction of segments" >> $ERRORFILE - fi - clean_tests -} - -#---------------------------------------------------------------------# -# construction with segments -#---------------------------------------------------------------------# -test_construction_segments() -{ - local nt=$CGAL_GMPQ_NT; - local kernel=$CARTESIAN_KERNEL; - local geom_traits=$SEGMENT_GEOM_TRAITS; - local flags="-DTEST_NT=$nt -DTEST_KERNEL=$kernel -DTEST_GEOM_TRAITS=$geom_traits"; - compile_and_run_with_flags test_construction segments "$flags" -} - -#---------------------------------------------------------------------# -# construction with linear curves -#---------------------------------------------------------------------# -test_construction_linear_curves() -{ - local nt=$CGAL_GMPQ_NT; - local kernel=$CARTESIAN_KERNEL; - local geom_traits=$LINEAR_GEOM_TRAITS; - local topol_traits=$PLANAR_UNBOUNDED_TOPOL_TRAITS; - local flags="-DTEST_NT=$nt -DTEST_KERNEL=$kernel -DTEST_GEOM_TRAITS=$geom_traits -DTEST_TOPOL_TRAITS=$topol_traits"; - compile_and_run_with_flags test_construction linear "$flags" -} - -#---------------------------------------------------------------------# -# construction with geodesic arcs on the sphere -#---------------------------------------------------------------------# -test_construction_spherical_arcs() -{ - local nt=$CGAL_GMPQ_NT; - local kernel=$CARTESIAN_KERNEL; - local geom_traits=$GEODESIC_ARC_ON_SPHERE_GEOM_TRAITS; - local topol_traits=$SPHERICAL_TOPOL_TRAITS; - local flags="-DTEST_NT=$nt -DTEST_KERNEL=$kernel -DTEST_GEOM_TRAITS=$geom_traits -DTEST_TOPOL_TRAITS=$topol_traits"; - compile_and_run_with_flags test_construction geodesic_arcs_on_sphere "$flags" -} - -#---------------------------------------------------------------------# -# construction with polylines -#---------------------------------------------------------------------# -test_construction_polylines() -{ - local nt=$CGAL_GMPQ_NT; - local kernel=$CARTESIAN_KERNEL; - local geom_traits=$POLYLINE_GEOM_TRAITS; - local flags="-DTEST_NT=$nt -DTEST_KERNEL=$kernel -DTEST_GEOM_TRAITS=$geom_traits"; - compile_and_run_with_flags test_construction polylines "$flags" -} - -#---------------------------------------------------------------------# -# overlay with segments -#---------------------------------------------------------------------# -test_overlay_segments() -{ - local nt=$CGAL_GMPQ_NT; - local kernel=$CARTESIAN_KERNEL; - local geom_traits=$SEGMENT_GEOM_TRAITS; - local flags="-DTEST_NT=$nt -DTEST_KERNEL=$kernel -DTEST_GEOM_TRAITS=$geom_traits"; - compile_and_run_with_flags test_overlay segments "$flags" -} - -#---------------------------------------------------------------------# -# overlay with geodesic arcs on the sphere -#---------------------------------------------------------------------# -test_overlay_spherical_arcs() -{ - local nt=$CGAL_GMPQ_NT; - local kernel=$CARTESIAN_KERNEL; - local geom_traits=$GEODESIC_ARC_ON_SPHERE_GEOM_TRAITS; - local topol_traits=$SPHERICAL_TOPOL_TRAITS; - local flags="-DTEST_NT=$nt -DTEST_KERNEL=$kernel -DTEST_GEOM_TRAITS=$geom_traits -DTEST_TOPOL_TRAITS=$topol_traits"; - compile_and_run_with_flags test_overlay geodesic_arcs_on_sphere "$flags" -} - -#---------------------------------------------------------------------# -# point location with segments -#---------------------------------------------------------------------# -test_point_location_segments() -{ - local nt=$CGAL_GMPQ_NT; - local kernel=$CARTESIAN_KERNEL; - local geom_traits=$SEGMENT_GEOM_TRAITS; - local flags="-DTEST_NT=$nt -DTEST_KERNEL=$kernel -DTEST_GEOM_TRAITS=$geom_traits"; - compile_and_run_with_flags test_point_location segments "$flags" -} - -# For backward compatibility -test_point_location_segments_version() -{ - local nt=$CGAL_GMPQ_NT; - local kernel=$CARTESIAN_KERNEL; - local geom_traits=$SEGMENT_GEOM_TRAITS; - local flags="-DTEST_NT=$nt -DTEST_KERNEL=$kernel -DTEST_GEOM_TRAITS=$geom_traits -DCGAL_ARR_POINT_LOCATION_VERSION=1"; - compile_and_run_with_flags test_point_location segments "$flags" -} - -# For backward compatibility -test_point_location_segments_conversion() -{ - local nt=$CGAL_GMPQ_NT; - local kernel=$CARTESIAN_KERNEL; - local geom_traits=$SEGMENT_GEOM_TRAITS; - local flags="-DTEST_NT=$nt -DTEST_KERNEL=$kernel -DTEST_GEOM_TRAITS=$geom_traits -DCGAL_ARR_POINT_LOCATION_CONVERSION"; - compile_and_run_with_flags test_point_location segments "$flags" -} - -#---------------------------------------------------------------------# -# point location dynamic with segments -#---------------------------------------------------------------------# -test_point_location_dynamic_segments() -{ - local nt=$CGAL_GMPQ_NT; - local kernel=$CARTESIAN_KERNEL; - local geom_traits=$SEGMENT_GEOM_TRAITS; - local flags="-DTEST_NT=$nt -DTEST_KERNEL=$kernel -DTEST_GEOM_TRAITS=$geom_traits"; - compile_and_run_with_flags test_point_location_dynamic segments "$flags" -} - -#---------------------------------------------------------------------# -# point location with circle segments -#---------------------------------------------------------------------# -test_point_location_circle_segments() -{ - local nt=$CGAL_GMPQ_NT; - local kernel=$CARTESIAN_KERNEL; - local geom_traits=$CIRCLE_SEGMENT_GEOM_TRAITS; - local flags="-DTEST_NT=$nt -DTEST_KERNEL=$kernel -DTEST_GEOM_TRAITS=$geom_traits"; - compile_and_run_with_flags test_point_location circle_segments "$flags" -} - -#---------------------------------------------------------------------# -# point location with linear objects -#---------------------------------------------------------------------# -test_point_location_linear() -{ - local nt=$CGAL_GMPQ_NT; - local kernel=$CARTESIAN_KERNEL; - local geom_traits=$LINEAR_GEOM_TRAITS; - local flags="-DTEST_NT=$nt -DTEST_KERNEL=$kernel -DTEST_GEOM_TRAITS=$geom_traits"; - compile_and_run_with_flags test_point_location linear "$flags" -} - -#---------------------------------------------------------------------# -# batchecd point location with segments -#---------------------------------------------------------------------# -test_batched_point_location_segments() -{ - local nt=$CGAL_GMPQ_NT; - local kernel=$CARTESIAN_KERNEL; - local geom_traits=$SEGMENT_GEOM_TRAITS; - local flags="-DTEST_NT=$nt -DTEST_KERNEL=$kernel -DTEST_GEOM_TRAITS=$geom_traits"; - compile_and_run_with_flags test_batched_point_location segments "$flags" -} - -#---------------------------------------------------------------------# -# batchecd point location with linear objects -#---------------------------------------------------------------------# -test_batched_point_location_linear() -{ - local nt=$CGAL_GMPQ_NT; - local kernel=$CARTESIAN_KERNEL; - local geom_traits=$LINEAR_GEOM_TRAITS; - local flags="-DTEST_NT=$nt -DTEST_KERNEL=$kernel -DTEST_GEOM_TRAITS=$geom_traits"; - compile_and_run_with_flags test_batched_point_location linear "$flags" -} - -#---------------------------------------------------------------------# -# batchecd point location with geodesic arcs on the sphere -#---------------------------------------------------------------------# -test_batched_point_location_spherical_arcs() -{ - local nt=$CGAL_GMPQ_NT; - local kernel=$CARTESIAN_KERNEL; - local geom_traits=$GEODESIC_ARC_ON_SPHERE_GEOM_TRAITS; - local topol_traits=$SPHERICAL_TOPOL_TRAITS; - local flags="-DTEST_NT=$nt -DTEST_KERNEL=$kernel -DTEST_GEOM_TRAITS=$geom_traits -DTEST_TOPOL_TRAITS=$topol_traits"; - compile_and_run_with_flags test_batched_point_location geodesic_arcs_on_sphere "$flags" -} - -#---------------------------------------------------------------------# -# vertical decomposition with segments -#---------------------------------------------------------------------# -test_vertical_decomposition_segments() -{ - local nt=$CGAL_GMPQ_NT; - local kernel=$CARTESIAN_KERNEL; - local geom_traits=$SEGMENT_GEOM_TRAITS; - local flags="-DTEST_NT=$nt -DTEST_KERNEL=$kernel -DTEST_GEOM_TRAITS=$geom_traits"; - compile_and_run_with_flags test_vertical_decomposition segments "$flags" -} - -#---------------------------------------------------------------------# -# vertical decomposition with linear objects -#---------------------------------------------------------------------# -test_vertical_decomposition_linear() -{ - local nt=$CGAL_GMPQ_NT; - local kernel=$CARTESIAN_KERNEL; - local geom_traits=$LINEAR_GEOM_TRAITS; - local flags="-DTEST_NT=$nt -DTEST_KERNEL=$kernel -DTEST_GEOM_TRAITS=$geom_traits"; - compile_and_run_with_flags test_vertical_decomposition linear "$flags" -} - -#---------------------------------------------------------------------# -# vertical decomposition with geodesic arcs on the sphere -#---------------------------------------------------------------------# -test_vertical_decomposition_spherical_arcs() -{ - local nt=$CGAL_GMPQ_NT; - local kernel=$CARTESIAN_KERNEL; - local geom_traits=$LINEAR_GEOM_TRAITS; - local topol_traits=$SPHERICAL_TOPOL_TRAITS; - local flags="-DTEST_NT=$nt -DTEST_KERNEL=$kernel -DTEST_GEOM_TRAITS=$geom_traits -DTEST_TOPOL_TRAITS=$topol_traits"; - compile_and_run_with_flags test_vertical_decomposition geodesic_arcs_on_sphere "$flags" -} - -#---------------------------------------------------------------------# -# segment traits -#---------------------------------------------------------------------# -test_segment_traits() -{ - local nt=$QUOTIENT_MP_FLOAT_NT; - local kernel=$CARTESIAN_KERNEL; - local geom_traits=$SEGMENT_GEOM_TRAITS; - local flags="-DTEST_NT=$nt -DTEST_KERNEL=$kernel -DTEST_GEOM_TRAITS=$geom_traits"; - - compile_test_with_flags test_traits segments "$flags" - if [ -n "${SUCCESS}" ] ; then - execute_commands_old_structure segments segment_traits \ - VERTEX IS_VERTICAL COMPARE_Y_AT_X COMPARE_Y_AT_X_LEFT CONSTRUCTOR \ - COMPARE_Y_AT_X_RIGHT ARE_MERGEABLE - - execute_commands_new_structure segments segment_traits \ - IS_VERTICAL COMPARE_Y_AT_X COMPARE_Y_AT_X_LEFT ARE_MERGEABLE - - run_trapped_test test_traits \ - data/segments/vertex.pt data/segments/xcurves \ - data/empty.zero data/segments/vertex segment_traits - else - echo " ERROR: not executed test_traits segment_traits" >> $ERRORFILE - fi - clean_tests -} - -#---------------------------------------------------------------------# -# non-caching segment traits -#---------------------------------------------------------------------# -test_non_caching_segment_traits() -{ - local nt=$CGAL_GMPQ_NT; - local kernel=$CARTESIAN_KERNEL; - local geom_traits=$NON_CACHING_SEGMENT_GEOM_TRAITS; - local flags="-DTEST_NT=$nt -DTEST_KERNEL=$kernel -DTEST_GEOM_TRAITS=$geom_traits"; - - compile_test_with_flags test_traits non_caching_segments "$flags" - if [ -n "${SUCCESS}" ] ; then - execute_commands_old_structure segments non_caching_segment_traits \ - VERTEX IS_VERTICAL COMPARE_Y_AT_X COMPARE_Y_AT_X_LEFT CONSTRUCTOR \ - COMPARE_Y_AT_X_RIGHT ARE_MERGEABLE ASSERTIONS - - execute_commands_new_structure segments segment_traits \ - IS_VERTICAL COMPARE_Y_AT_X COMPARE_Y_AT_X_LEFT - - run_trapped_test test_traits \ - data/segments/vertex.pt data/segments/xcurves \ - data/empty.zero data/segments/vertex non_caching_segment_traits - else - echo " ERROR: not executed test_traits non_caching_segment_traits" >> $ERRORFILE - fi - clean_tests -} - -#---------------------------------------------------------------------# -# polycurve conic traits -#---------------------------------------------------------------------# -test_polycurve_conic_traits() -{ - if [ -n "${CGAL_DISABLE_GMP}" ]; then - echo "CORE is not available, test_polycurve_conic_traits not ran" - return - fi - echo polycurve test starting - local nt=$CORE_EXPR_NT; - local kernel=$CARTESIAN_KERNEL; - local geom_traits=$POLYCURVE_CONIC_GEOM_TRAITS; - local flags="-DTEST_NT=$nt -DTEST_KERNEL=$kernel -DTEST_GEOM_TRAITS=$geom_traits"; - - compile_test_with_flags test_traits conic_polycurve "$flags" - if [ -n "${SUCCESS}" ] ; then - - # The input arguments for the execute_commands_new_structure, - # 1. Polycurve_conics is the directory name in "data" - # 2. polycurve_conic_traits is a string - # Execute_command_new_structure will only run the test on functors provided as the third, fourth and so on arguments. - # To see how the input data directory should be structured for each functor, check the execute_commands_new_structure function in this file. - execute_commands_new_structure polycurves_conics polycurve_conic_traits \ - COMPARE_Y_AT_X \ - INTERSECT \ - EQUAL \ - IS_VERTICAL \ - SPLIT \ - ARE_MERGEABLE \ - COMPARE_Y_AT_X_LEFT \ - COMPARE_Y_AT_X_RIGHT \ - MAKE_X_MONOTONE \ - PUSH_BACK \ - PUSH_FRONT \ - NUMBER_OF_POINTS \ - VERTEX \ - CONSTRUCT_OPPOSITE \ - MERGE \ - COMPARE_ENDPOINTS_XY \ - TRIM - - else - echo " ERROR: not executed test_traits polyline_traits" >> $ERRORFILE - fi - clean_tests -} - -#---------------------------------------------------------------------# -# polycurve arc traits -#---------------------------------------------------------------------# -test_polycurve_circular_arc_traits() -{ - local nt=$QUOTIENT_MP_FLOAT_NT; - local kernel=$CARTESIAN_KERNEL; - local geom_traits=$POLYCURVE_CIRCULAR_ARC_GEOM_TRAITS; - local flags="-DTEST_NT=$nt -DTEST_KERNEL=$kernel -DTEST_GEOM_TRAITS=$geom_traits"; - - compile_test_with_flags test_traits circular_arc_polycurve "$flags" - if [ -n "${SUCCESS}" ] ; then - execute_commands_new_structure Polycurves_circular_arcs polycurve_circular_arc_traits \ - COMPARE_Y_AT_X \ - EQUAL \ - IS_VERTICAL \ - SPLIT \ - ARE_MERGEABLE \ - COMPARE_Y_AT_X_LEFT \ - COMPARE_Y_AT_X_RIGHT \ - MAKE_X_MONOTONE \ - PUSH_BACK \ - PUSH_FRONT \ - NUMBER_OF_POINTS \ - VERTEX \ - CONSTRUCT_OPPOSITE \ - MERGE \ - COMPARE_ENDPOINTS_XY \ - INTERSECT - - else - echo " ERROR: not executed test_traits polyline_traits" >> $ERRORFILE - fi - clean_tests -} - -#---------------------------------------------------------------------# -# polycurve bezier traits -#---------------------------------------------------------------------# -test_polycurve_bezier_traits() -{ - if [ -n "${CGAL_DISABLE_GMP}" ]; then - echo "CORE is not available, test_polycurve_bezier_traits not ran" - return - fi - local nt=$CORE_EXPR_NT; - local kernel=$CARTESIAN_KERNEL; - local geom_traits=$POLYCURVE_BEZIER_GEOM_TRAITS; - local flags="-DTEST_NT=$nt -DTEST_KERNEL=$kernel -DTEST_GEOM_TRAITS=$geom_traits"; - - compile_test_with_flags test_traits bezier_polycurve "$flags" - if [ -n "${SUCCESS}" ] ; then - execute_commands_new_structure Polycurves_bezier test_polycurve_bezier_traits \ - MERGE \ - EQUAL \ - IS_VERTICAL \ - NUMBER_OF_POINTS \ - PUSH_BACK \ - PUSH_FRONT \ - VERTEX \ - ARE_MERGEABLE \ - COMPARE_ENDPOINTS_XY - # TODO (add data for these tests) - # COMPARE_Y_AT_X \ - # SPLIT \ - # COMPARE_Y_AT_X_LEFT \ - # COMPARE_Y_AT_X_RIGHT \ - # MAKE_X_MONOTONE \ - # CONSTRUCT_OPPOSITE \ - - # INTERSECT - - else - echo " ERROR: not executed test_traits polyline_traits" >> $ERRORFILE - fi - clean_tests -} - -#---------------------------------------------------------------------# -# polyline traits -#---------------------------------------------------------------------# -test_polyline_traits() -{ - local nt=$CGAL_GMPQ_NT; - local kernel=$CARTESIAN_KERNEL; - local geom_traits=$POLYLINE_GEOM_TRAITS; - local flags="-DTEST_NT=$nt -DTEST_KERNEL=$kernel -DTEST_GEOM_TRAITS=$geom_traits"; - - compile_test_with_flags test_traits test_polylines "$flags" - if [ -n "${SUCCESS}" ] ; then - execute_commands_old_structure polylines polyline_traits \ - CONSTRUCTOR COMPARE_Y_AT_X_LEFT \ - COMPARE_Y_AT_X_RIGHT ARE_MERGEABLE - else - echo " ERROR: not executed test_traits polyline_traits" >> $ERRORFILE - fi - clean_tests -} - -#---------------------------------------------------------------------# -# non-caching polyline traits -#---------------------------------------------------------------------# -test_non_caching_polyline_traits() -{ - local nt=$CGAL_GMPQ_NT; - local kernel=$CARTESIAN_KERNEL; - local geom_traits=$NON_CACHING_POLYLINE_GEOM_TRAITS; - local flags="-DTEST_NT=$nt -DTEST_KERNEL=$kernel -DTEST_GEOM_TRAITS=$geom_traits"; - - compile_test_with_flags test_traits non_caching_polylines "$flags" - if [ -n "${SUCCESS}" ] ; then - execute_commands_old_structure polylines non_caching_polyline_traits \ - CONSTRUCTOR COMPARE_Y_AT_X_LEFT \ - COMPARE_Y_AT_X_RIGHT ARE_MERGEABLE - else - echo " ERROR: not executed test_traits non_caching_polyline_traits" >> $ERRORFILE - fi - clean_tests -} - -#---------------------------------------------------------------------# -# linear traits -#---------------------------------------------------------------------# -test_linear_traits() -{ - local nt=$QUOTIENT_MP_FLOAT_NT; - local kernel=$CARTESIAN_KERNEL; - local geom_traits=$LINEAR_GEOM_TRAITS; - local flags="-DTEST_NT=$nt -DTEST_KERNEL=$kernel -DTEST_GEOM_TRAITS=$geom_traits"; - - compile_test_with_flags test_traits linear "$flags" - if [ -n "${SUCCESS}" ] ; then - execute_commands_old_structure linear/segments linear_traits.segments \ - VERTEX IS_VERTICAL COMPARE_Y_AT_X COMPARE_Y_AT_X_LEFT \ - COMPARE_Y_AT_X_RIGHT CONSTRUCTOR ARE_MERGEABLE - - execute_commands_new_structure linear/segments linear_traits.segments \ - IS_VERTICAL COMPARE_Y_AT_X COMPARE_Y_AT_X_LEFT - - run_trapped_test test_traits \ - data/linear/segments/vertex.pt data/linear/segments/xcurves \ - data/empty.zero data/linear/segments/vertex linear_traits.segments - - execute_commands_old_structure linear/rays linear_traits.rays \ - VERTEX IS_VERTICAL COMPARE_Y_AT_X COMPARE_Y_AT_X_LEFT \ - COMPARE_Y_AT_X_RIGHT CONSTRUCTOR ARE_MERGEABLE - - execute_commands_new_structure linear/rays linear_traits.rays \ - IS_VERTICAL COMPARE_Y_AT_X COMPARE_Y_AT_X_LEFT - - run_trapped_test test_traits \ - data/linear/rays/vertex.pt data/linear/rays/xcurves \ - data/empty.zero data/linear/rays/vertex linear_traits.rays - - execute_commands_new_structure linear/lines linear_traits.lines \ - IS_VERTICAL COMPARE_Y_AT_X COMPARE_Y_AT_X_LEFT INTERSECT \ - SPLIT MERGE \ - PARAMETER_SPACE_X PARAMETER_SPACE_Y \ - COMPARE_X_AT_LIMIT COMPARE_X_NEAR_LIMIT COMPARE_Y_NEAR_BOUNDARY - else - echo " ERROR: not executed test_traits linear_traits" >> $ERRORFILE - fi - clean_tests -} - -#---------------------------------------------------------------------# -# conic traits -#---------------------------------------------------------------------# -test_conic_traits() -{ - if [ -n "${CGAL_DISABLE_GMP}" ]; then - echo "CORE is not available, test_conic_traits not ran" - return - fi - local nt=$CORE_EXPR_NT; - local kernel=$CARTESIAN_KERNEL; - local geom_traits=$CORE_CONIC_GEOM_TRAITS; - local flags="-DTEST_NT=$nt -DTEST_KERNEL=$kernel -DTEST_GEOM_TRAITS=$geom_traits"; - - compile_test_with_flags test_traits conics "$flags" - if [ -n "${SUCCESS}" ] ; then - execute_commands_old_structure conics conic_traits \ - INTERSECT SPLIT MERGE COMPARE_Y_AT_X_LEFT \ - COMPARE_Y_AT_X_RIGHT ARE_MERGEABLE - - execute_commands_new_structure conics conic_traits \ - INTERSECT SPLIT MERGE - - run_trapped_test test_traits \ - data/conics/compare.pt data/empty.zero \ - data/empty.zero data/conics/compare conic_traits - else - echo " ERROR: not executed test_traits conic_traits" >> $ERRORFILE - fi - clean_tests -} - -#---------------------------------------------------------------------# -# "line arcs" (segments) only -#---------------------------------------------------------------------# -test_line_arc_traits() -{ - local nt=$QUOTIENT_MP_FLOAT_NT; - local kernel=$CARTESIAN_KERNEL; - local geom_traits=$LINE_ARC_GEOM_TRAITS; - local flags="-DTEST_NT=$nt -DTEST_KERNEL=$kernel -DTEST_GEOM_TRAITS=$geom_traits"; - - compile_test_with_flags test_traits line_arcs "$flags" - if [ -n "${SUCCESS}" ] ; then - execute_commands_old_structure circular_lines line_arc_traits \ - VERTEX IS_VERTICAL COMPARE_Y_AT_X COMPARE_Y_AT_X_LEFT \ - ASSERTIONS COMPARE_Y_AT_X_RIGHT MERGE ARE_MERGEABLE - - execute_commands_new_structure circular_lines line_arc_traits \ - IS_VERTICAL COMPARE_Y_AT_X - - run_trapped_test test_traits \ - data/circular_lines/compare.pt data/empty.zero \ - data/empty.zero data/circular_lines/compare line_arc_traits - - run_trapped_test test_traits \ - data/circular_lines/vertex.pt data/circular_lines/xcurves \ - data/empty.zero data/circular_lines/vertex line_arc_traits - else - echo " ERROR: not executed test_traits" >> $ERRORFILE - fi - clean_tests -} - -#---------------------------------------------------------------------# -# circular arcs only -#---------------------------------------------------------------------# -test_circular_arc_traits() -{ - local nt=$QUOTIENT_MP_FLOAT_NT; - local kernel=$CARTESIAN_KERNEL; - local geom_traits=$CIRCULAR_ARC_GEOM_TRAITS; - local flags="-DTEST_NT=$nt -DTEST_KERNEL=$kernel -DTEST_GEOM_TRAITS=$geom_traits"; - - compile_test_with_flags test_traits circular_arcs "$flags" - if [ -n "${SUCCESS}" ] ; then - execute_commands_old_structure circular_arcs circular_arc_traits \ - VERTEX IS_VERTICAL COMPARE_Y_AT_X COMPARE_Y_AT_X_LEFT \ - ASSERTIONS COMPARE_Y_AT_X_RIGHT MERGE ARE_MERGEABLE - - execute_commands_new_structure circular_arcs circular_arc_traits \ - VERTEX IS_VERTICAL COMPARE_Y_AT_X - else - echo " ERROR: not executed test_traits" >> $ERRORFILE - fi - clean_tests -} - -#---------------------------------------------------------------------# -# circular and line arcs -#---------------------------------------------------------------------# -test_circular_line_arc_traits() -{ - local nt=$QUOTIENT_MP_FLOAT_NT; - local kernel=$CARTESIAN_KERNEL; - local geom_traits=$CIRCULAR_LINE_ARC_GEOM_TRAITS; - local flags="-DTEST_NT=$nt -DTEST_KERNEL=$kernel -DTEST_GEOM_TRAITS=$geom_traits"; - - compile_test_with_flags test_traits circular_line_arcs "$flags" - if [ -n "${SUCCESS}" ] ; then - execute_commands_old_structure circular_line_arcs circular_line_arc_traits \ - VERTEX IS_VERTICAL CONSTRUCTOR COMPARE_Y_AT_X COMPARE_Y_AT_X_LEFT \ - ASSERTIONS COMPARE_Y_AT_X_RIGHT MERGE ARE_MERGEABLE - - execute_commands_new_structure circular_line_arcs circular_line_arc_traits \ - IS_VERTICAL COMPARE_Y_AT_X - - run_trapped_test test_traits \ - data/circular_line_arcs/vertex.pt data/circular_line_arcs/xcurves \ - data/empty.zero data/circular_line_arcs/vertex circular_line_arc_traits - else - echo " ERROR: not executed test_traits circular_line_arc_traits" >> $ERRORFILE - fi - clean_tests -} - -#---------------------------------------------------------------------# -# circle segment traits -#---------------------------------------------------------------------# -test_circle_segments_traits() -{ - local nt=$QUOTIENT_MP_FLOAT_NT; - local kernel=$CARTESIAN_KERNEL; - local geom_traits=$CIRCLE_SEGMENT_GEOM_TRAITS; - local flags="-DTEST_NT=$nt -DTEST_KERNEL=$kernel -DTEST_GEOM_TRAITS=$geom_traits"; - - compile_test_with_flags test_traits circle_segments "$flags" - if [ -n "${SUCCESS}" ] ; then - execute_commands_old_structure circle_segments circle_segments_traits \ - VERTEX IS_VERTICAL COMPARE_Y_AT_X COMPARE_Y_AT_X_LEFT \ - COMPARE_Y_AT_X_RIGHT CONSTRUCTOR ARE_MERGEABLE - - run_trapped_test test_traits \ - data/circle_segments/points data/circle_segments/xcurves.8 \ - data/empty.zero data/circle_segments/vertex circle_segments_traits - run_trapped_test test_traits \ - data/empty.zero data/circle_segments/xcurves.8 \ - data/empty.zero data/circle_segments/is_vertical circle_segments_traits - run_trapped_test test_traits \ - data/circle_segments/points data/circle_segments/xcurves.8 \ - data/empty.zero data/circle_segments/compare_y_at_x circle_segments_traits - run_trapped_test test_traits \ - data/circle_segments/points data/circle_segments/xcurves.16 \ - data/empty.zero data/circle_segments/compare_y_at_x_left circle_segments_traits - run_trapped_test test_traits \ - data/circle_segments/points data/circle_segments/xcurves.16 \ - data/empty.zero data/circle_segments/compare_y_at_x_right circle_segments_traits - run_trapped_test test_traits \ - data/empty.zero data/circle_segments/constructor.xcv \ - data/empty.zero data/circle_segments/constructor circle_segments_traits - else - echo " ERROR: not executed test_traits circle_segments_traits" >> $ERRORFILE - fi - clean_tests -} - -#---------------------------------------------------------------------# -# bezier traits -#---------------------------------------------------------------------# -test_bezier_traits() -{ - if [ -n "${CGAL_DISABLE_GMP}" ]; then - echo "CORE is not available, test_bezier_traits not ran" - return - fi - local nt=$CORE_EXPR_NT; - local kernel=$CARTESIAN_KERNEL; - local geom_traits=$BEZIER_GEOM_TRAITS; - local flags="-DTEST_NT=$nt -DTEST_KERNEL=$kernel -DTEST_GEOM_TRAITS=$geom_traits"; - - compile_test_with_flags test_traits Bezier "$flags" - if [ -n "${SUCCESS}" ] ; then - execute_commands_old_structure bezier bezier_traits \ - COMPARE_Y_AT_X_LEFT COMPARE_Y_AT_X_RIGHT SPLIT \ - CONSTRUCTOR ASSERTIONS ARE_MERGEABLE - else - echo " ERROR: not executed test_traits bezier_traits" >> $ERRORFILE - fi - clean_tests -} - -#---------------------------------------------------------------------# -# spherical arc traits -#---------------------------------------------------------------------# -test_spherical_arc_traits() -{ - local nt=$CGAL_GMPQ_NT; - local kernel=$CARTESIAN_KERNEL; - local geom_traits=$GEODESIC_ARC_ON_SPHERE_GEOM_TRAITS; - local topol_traits=$SPHERICAL_TOPOL_TRAITS - local flags="-DTEST_NT=$nt -DTEST_KERNEL=$kernel -DTEST_GEOM_TRAITS=$geom_traits -DTEST_TOPOL_TRAITS=$topol_traits"; - - compile_test_with_flags test_traits geodesic_arcs_on_sphere "$flags" - if [ -n "${SUCCESS}" ] ; then - execute_commands_old_structure spherical_arcs spherical_arc_traits \ - COMPARE_Y_AT_X_LEFT COMPARE_Y_AT_X_RIGHT INTERSECT \ - CONSTRUCTOR \ - COMPARE MAKE_X_MONOTONE SPLIT MERGE ASSERTIONS ARE_MERGEABLE - - execute_commands_new_structure spherical_arcs spherical_arc_traits \ - INTERSECT \ - COMPARE_X_ON_BOUNDARY COMPARE_X_NEAR_BOUNDARY \ - COMPARE_Y_NEAR_BOUNDARY - - run_trapped_test test_traits \ - data/spherical_arcs/compare.pt data/spherical_arcs/compare.xcv \ - data/empty.zero data/spherical_arcs/compare spherical_arc_traits - else - echo " ERROR: not executed test_traits spherical_arc_traits" >> $ERRORFILE - fi - clean_tests -} - -#---------------------------------------------------------------------# -# rational arc traits -#---------------------------------------------------------------------# -test_rational_arc_traits() -{ - if [ -n "${CGAL_DISABLE_GMP}" ]; then - echo "CORE is not available, test_rational_arc_traits not ran" - return - fi - local nt=$CORE_INT_NT; - local kernel=$UNIVARIATE_ALGEBRAIC_KERNEL; - local geom_traits=$RATIONAL_ARC_GEOM_TRAITS; - local flags="-DTEST_NT=$nt -DTEST_KERNEL=$kernel -DTEST_GEOM_TRAITS=$geom_traits"; - - compile_test_with_flags test_traits rational_arcs "$flags" - if [ -n "${SUCCESS}" ] ; then - run_trapped_test test_traits \ - data/compare.pt data/empty.zero \ - data/empty.zero data/compare rational_arc_traits - - execute_commands_new_structure rational_arcs rational_arc_traits \ - VERTEX IS_VERTICAL COMPARE_Y_AT_X COMPARE_Y_AT_X_LEFT SPLIT MERGE \ - COMPARE_X_AT_LIMIT COMPARE_X_NEAR_LIMIT COMPARE_Y_NEAR_BOUNDARY - else - echo " ERROR: not executed test_traits rational_arc_traits" >> $ERRORFILE - fi - clean_tests -} - -#---------------------------------------------------------------------# -# algebraic traits with GMP/MPFI -#---------------------------------------------------------------------# -test_algebraic_traits_gmp() -{ - #TODO: Adapt - - local nt=$CGAL_GMPZ_NT; - local kernel=$UNIVARIATE_ALGEBRAIC_KERNEL; - local geom_traits=$ALGEBRAIC_GEOM_TRAITS; - local flags="-DTEST_NT=$nt -DTEST_KERNEL=$kernel -DTEST_GEOM_TRAITS=$geom_traits"; - - compile_test_with_flags test_traits algebraic "$flags" - if [ -n "${SUCCESS}" ] ; then - execute_commands_new_structure algebraic algebraic_traits_gmp \ - COMPARE COMPARE_Y_AT_X COMPARE_Y_AT_X_RIGHT COMPARE_Y_AT_X_LEFT \ - MAKE_X_MONOTONE IS_VERTICAL VERTEX SPLIT MERGE INTERSECT \ - PARAMETER_SPACE_X PARAMETER_SPACE_Y - else - echo " ERROR: not executed test_traits algebraic_traits_gmp" >> $ERRORFILE - fi - clean_tests -} - -#---------------------------------------------------------------------# -# algebraic traits with LEDA -#---------------------------------------------------------------------# -test_algebraic_traits_leda() -{ - #TODO: Adapt - - local nt=$LEDA_INT_NT; - local kernel=$UNIVARIATE_ALGEBRAIC_KERNEL; - local geom_traits=$ALGEBRAIC_GEOM_TRAITS; - local flags="-DTEST_NT=$nt -DTEST_KERNEL=$kernel -DTEST_GEOM_TRAITS=$geom_traits"; - - compile_test_with_flags test_traits algebraic "$flags" - if [ -n "${SUCCESS}" ] ; then - execute_commands_new_structure algebraic algebraic_traits_leda \ - COMPARE COMPARE_Y_AT_X COMPARE_Y_AT_X_RIGHT COMPARE_Y_AT_X_LEFT \ - MAKE_X_MONOTONE IS_VERTICAL VERTEX SPLIT MERGE INTERSECT \ - PARAMETER_SPACE_X PARAMETER_SPACE_Y - else - echo " ERROR: not executed test_traits algebraic_traits_leda" >> $ERRORFILE - fi - clean_tests -} - - -#---------------------------------------------------------------------# -# algebraic traits with CORE -#---------------------------------------------------------------------# -test_algebraic_traits_core() -{ - #TODO: Adapt - if [ -n "${CGAL_DISABLE_GMP}" ]; then - echo "CORE is not available, test_algebraic_traits_core not ran" - return - fi - local nt=$CORE_INT_NT; - local kernel=$UNIVARIATE_ALGEBRAIC_KERNEL; - local geom_traits=$ALGEBRAIC_GEOM_TRAITS; - local flags="-DTEST_NT=$nt -DTEST_KERNEL=$kernel -DTEST_GEOM_TRAITS=$geom_traits"; - - compile_test_with_flags test_traits algebraic "$flags" - if [ -n "${SUCCESS}" ] ; then - execute_commands_new_structure algebraic algebraic_traits_core \ - COMPARE COMPARE_Y_AT_X COMPARE_Y_AT_X_RIGHT COMPARE_Y_AT_X_LEFT \ - MAKE_X_MONOTONE IS_VERTICAL VERTEX SPLIT MERGE INTERSECT \ - PARAMETER_SPACE_X PARAMETER_SPACE_Y - else - echo " ERROR: not executed test_traits algebraic_traits_core" >> $ERRORFILE - fi - clean_tests -} - -#---------------------------------------------------------------------# -# remove the previous error file -#---------------------------------------------------------------------# - -rm -f $ERRORFILE -rm -f $FULL_ERROR_DESCRIPTION_FILE -rm -f ProgramOutput.test_* -touch $ERRORFILE - -#---------------------------------------------------------------------# -# compile and run the tests -#---------------------------------------------------------------------# - - - -if [ $# -ne 0 ] ; then - case $1 in - -cmake) TEST_WITH_CMAKE="TRUE" ;; - *)TEST_WITH_CMAKE="FALSE" ;; - esac -else - TEST_WITH_CMAKE="FALSE" -fi - -echo "Run all tests." - -if [ "${TEST_WITH_CMAKE}" != "FALSE" ]; then - configure -fi - -if [ "${TEST_WITH_CMAKE}" != "FALSE" ]; then - compile_and_run construction_test_suite_generator -fi - -test_segment_traits -test_non_caching_segment_traits -test_polyline_traits -test_polycurve_conic_traits -test_polycurve_circular_arc_traits -test_polycurve_bezier_traits -test_non_caching_polyline_traits -test_linear_traits -test_conic_traits - -test_line_arc_traits # "line arcs" (segments) only -test_circular_arc_traits # circular arcs only -test_circular_line_arc_traits # for both - -test_circle_segments_traits -test_bezier_traits - -test_spherical_arc_traits - -test_rational_arc_traits - -test_algebraic_traits_core -test_algebraic_traits_gmp -test_algebraic_traits_leda - -compile_and_run test_data_traits - -compile_and_run test_insertion -compile_and_run test_unbounded_rational_insertion -compile_and_run test_unbounded_rational_direct_insertion -compile_and_run test_rational_function_traits_2 -compile_and_run test_iso_verts - -compile_and_run test_vert_ray_shoot_vert_segments - -test_construction_segments -test_construction_linear_curves -test_construction_spherical_arcs -test_construction_polylines - -test_overlay_segments -test_overlay_spherical_arcs - -test_point_location_segments -test_point_location_segments_version -test_point_location_segments_conversion -test_point_location_circle_segments -test_point_location_linear - -test_point_location_dynamic_segments - -test_batched_point_location_segments -test_batched_point_location_linear -test_batched_point_location_spherical_arcs - -test_vertical_decomposition_segments -test_vertical_decomposition_linear -# test_vertical_decomposition_spherical_arcs - -compile_and_run test_dual -compile_and_run test_do_intersect -compile_and_run test_zone - -compile_and_run test_observer -compile_and_run test_do_equal - -test_segment_traits_adaptor -test_linear_traits_adaptor -test_spherical_arcs_traits_adaptor - -compile_and_run test_removal -compile_and_run test_unbounded_removal -compile_and_run test_spherical_removal - -compile_and_run test_io - -compile_and_run test_sgm - -# if any error occured then append the full error description file to error file - -if [ -f $FULL_ERROR_DESCRIPTION_FILE ] ; then - echo "******************** appending all error outputs ********************" >> $ERRORFILE - cat $FULL_ERROR_DESCRIPTION_FILE >> $ERRORFILE -fi diff --git a/Arrangement_on_surface_2/test/Arrangement_on_surface_2/cgal_test_with_cmake b/Arrangement_on_surface_2/test/Arrangement_on_surface_2/cgal_test_with_cmake index 8c72a52e332..33cd53adeea 100755 --- a/Arrangement_on_surface_2/test/Arrangement_on_surface_2/cgal_test_with_cmake +++ b/Arrangement_on_surface_2/test/Arrangement_on_surface_2/cgal_test_with_cmake @@ -1,4 +1,1759 @@ #! /bin/bash -./cgal_test_base -cmake +# This is a script for the CGAL test suite. Such a script must obey +# the following rules: +# +# - the name of the script is cgal_test +# - for every target two one line messages are written to the file 'error.txt' +# the first one indicates if the compilation was successful +# the second one indicates if the execution was successful +# if one of the two was not successful, the line should start with 'ERROR:' +# - running the script should not require any user interaction +# - the script should clean up object files and executables +# SET PARAMETERS FOR cgal_test + +set -- -cmake +ERRORFILE=error.txt +DO_RUN=y +if [ -z "${MAKE_CMD}" ]; then + MAKE_CMD=make +fi + + +FULL_ERROR_DESCRIPTION_FILE=ProgramOutput.error.txt + +#---------------------------------------------------------------------# +# compile_and_run +#---------------------------------------------------------------------# + +# note that these values shloud match to the values in test_configuration.h file + +CARTESIAN_KERNEL=0 +SIMPLE_CARTESIAN_KERNEL=1 +UNIVARIATE_ALGEBRAIC_KERNEL=2 + +SEGMENT_GEOM_TRAITS=0 +NON_CACHING_SEGMENT_GEOM_TRAITS=1 +POLYLINE_GEOM_TRAITS=2 +NON_CACHING_POLYLINE_GEOM_TRAITS=3 +POLYCURVE_CONIC_GEOM_TRAITS=14 +POLYCURVE_CIRCULAR_ARC_GEOM_TRAITS=15 +POLYCURVE_BEZIER_GEOM_TRAITS=16 +LINEAR_GEOM_TRAITS=4 +CORE_CONIC_GEOM_TRAITS=5 +LINE_ARC_GEOM_TRAITS=6 +CIRCULAR_ARC_GEOM_TRAITS=7 +CIRCULAR_LINE_ARC_GEOM_TRAITS=8 +CIRCLE_SEGMENT_GEOM_TRAITS=9 +BEZIER_GEOM_TRAITS=10 +GEODESIC_ARC_ON_SPHERE_GEOM_TRAITS=11 +RATIONAL_ARC_GEOM_TRAITS=12 +ALGEBRAIC_GEOM_TRAITS=13 +POLYCURVE_CONIC_GEOM_TRAITS=14 +POLYCURVE_CIRCULAR_ARC_GEOM_TRAITS=15 +POLYCURVE_BEZIER_GEOM_TRAITS=16 +FLAT_TORUS_GEOM_TRAITS=17 + +PLANAR_BOUNDED_TOPOL_TRAITS=0 +PLANAR_UNBOUNDED_TOPOL_TRAITS=1 +SPHERICAL_TOPOL_TRAITS=2 + +DOUBLE_NT=0 +MP_FLOAT_NT=1 +GMPZ_NT=2 +LEDA_RAT_NT=3 +QUOTIENT_MP_FLOAT_NT=4 +QUOTIENT_CGAL_GMPZ_NT=5 +CGAL_GMPQ_NT=6 +LAZY_LEDA_RAT_NT=7 +LAZY_CGAL_GMPQ_NT=8 +LAZY_QUOTIENT_MP_FLOAT_NT=9 +LEDA_REAL_NT=10 +CORE_EXPR_NT=11 +LAZY_GMPZ_NT=12 +LEDA_INT_NT=13 +CGAL_GMPZ_NT=14 +CORE_INT_NT=15 +CORE_RAT_NT=16 + +if [ -n "${CGAL_DISABLE_GMP}" ]; then + echo GMP is disable. Try to use LEDA instead. + GMPZ_NT=$LEDA_INT_NT + QUOTIENT_CGAL_GMPZ_NT=$LEDA_RAT_NT + CGAL_GMPQ_NT=$LEDA_RAT_NT + LAZY_CGAL_GMPQ_NT=$LAZY_LEDA_RAT_NT + LAZY_GMPZ_NT=$LAZY_LEDA_RAT_NT + CGAL_GMPZ_NT=$LEDA_INT_NT +fi + +COMPARE=1 +VERTEX=2 +IS_VERTICAL=3 +COMPARE_Y_AT_X=4 +COMPARE_Y_AT_X_LEFT=5 +COMPARE_Y_AT_X_RIGHT=6 +MAKE_X_MONOTONE=7 +INTERSECT=8 +SPLIT=9 +ARE_MERGEABLE=10 +MERGE=11 +ASSERTIONS=12 +CONSTRUCTOR=13 +COMPARE_X_AT_LIMIT=14 +COMPARE_X_NEAR_LIMIT=15 +COMPARE_X_ON_BOUNDARY=16 +COMPARE_X_NEAR_BOUNDARY=17 +COMPARE_Y_NEAR_BOUNDARY=18 +PARAMETER_SPACE_X=19 +PARAMETER_SPACE_Y=20 +X_ON_IDENTIFICATION=21 +Y_ON_IDENTIFICATION=22 +IS_BOUNDED=23 +IS_IN_X_RANGE=24 +COMPARE_Y_POSITION=25 +IS_BETWEEN_CW=26 +COMPARE_CW_AROUND_POINT=27 +PUSH_BACK=28 +PUSH_FRONT=29 +NUMBER_OF_POINTS=32 +COMPARE_ENDPOINTS_XY=33 +CONSTRUCT_OPPOSITE=34 +TRIM=35 + +#---------------------------------------------------------------------# +# configure +#---------------------------------------------------------------------# + +configure() +{ + echo "Configuring... " + rm -rf CMakeCache.txt CMakeFiles/ + echo "cmake --no-warn-unused-cli ${INIT_FILE:+"-C${INIT_FILE}"} "$CMAKE_GENERATOR" -DRUNNING_CGAL_AUTO_TEST=TRUE \ + -DCGAL_DIR=\"$CGAL_DIR\" \ + -DCGAL_CXX_FLAGS:STRING=\"$TESTSUITE_CXXFLAGS -I../../include\" \ + -DCGAL_EXE_LINKER_FLAGS=\"$TESTSUITE_LDFLAGS\" \ + -DCMAKE_BUILD_TYPE=NOTFOUND \ + ." + if eval 'cmake --no-warn-unused-cli ${INIT_FILE:+"-C${INIT_FILE}"} "$CMAKE_GENERATOR" -DRUNNING_CGAL_AUTO_TEST=TRUE \ + -DCGAL_DIR="$CGAL_DIR" \ + -DCGAL_CXX_FLAGS:STRING="$TESTSUITE_CXXFLAGS -I../../include" \ + -DCGAL_EXE_LINKER_FLAGS="$TESTSUITE_LDFLAGS" \ + -DCMAKE_BUILD_TYPE=NOTFOUND \ + .' ; then + + echo " successful configuration" >> $ERRORFILE + else + echo " ERROR: configuration" >> $ERRORFILE + fi +} + +compile_test_with_flags() +{ + local name=$1; + local type=$2; + local flags=$3; + + echo "Compiling $name $type ... " + if [ "${TEST_WITH_CMAKE}" != "FALSE" ]; then + export TESTSUITE_CXXFLAGS="$flags" + configure + if eval '${MAKE_CMD} VERBOSE=1 -fMakefile \ + $name' ; then + echo " successful compilation of $name $type" >> $ERRORFILE; + SUCCESS="y" + else + echo " ERROR: compilation of $name $type" >> $ERRORFILE; + SUCCESS="" + fi + else + if eval 'make CGAL_MAKEFILE=$CGAL_MAKEFILE \ + TESTSUITE_CXXFLAGS="$TESTSUITE_CXXFLAGS" \ + TESTSUITE_LDFLAGS="$TESTSUITE_LDFLAGS" $name'; then + echo " successful compilation of $name $type" >> $ERRORFILE; + SUCCESS="y" + else + echo " ERROR: compilation of $name $type" >> $ERRORFILE; + SUCCESS="" + fi + fi +} + +run_test() +{ + # $1 - executable name + + basedata=`basename "$5"` + OUTPUTFILE="ProgramOutput.$1" + rm -f $OUTPUTFILE + COMMAND="./$1" + if [ -f $1.cmd ] ; then + COMMAND="$COMMAND `cat $1.cmd`" + fi + if [ -f $1.cin ] ; then + COMMAND="cat $1.cin | $COMMAND" + fi + OUTPUTFILE="$OUTPUTFILE.$PLATFORM" + echo "Executing $1 ($2) ... " + ulimit -t 3600 2> /dev/null + if eval $COMMAND > $OUTPUTFILE 2>&1 ; then + echo " successful execution of $1" >> $ERRORFILE + else + echo " ERROR: execution of $1" >> $ERRORFILE + cat $OUTPUTFILE >> $FULL_ERROR_DESCRIPTION_FILE + fi +} + +run_test_with_flags() +{ + # $1 - executable name + # $2 - test substring name + + basedata=`basename "$5"` + OUTPUTFILE="ProgramOutput.$1" + rm -f $OUTPUTFILE + COMMAND="./$1" + if [ -f $1.cmd ] ; then + COMMAND="$COMMAND `cat $1.cmd`" + elif [ -f $1.$2.cmd ] ; then + COMMAND="$COMMAND `cat $1.$2.cmd`" + OUTPUTFILE=$OUTPUTFILE.`echo $2 | tr '/' '.'` + fi + if [ -f $1.cin ] ; then + COMMAND="cat $1.cin | $COMMAND" + elif [ -f $1.$2.cin ] ; then + COMMAND="cat $1.$2.cin | $COMMAND" + OUTPUTFILE=$OUTPUTFILE.`echo $2 | tr '/' '.'` + fi + OUTPUTFILE="$OUTPUTFILE.$PLATFORM" + echo "Executing $1 ($2) ... " + ulimit -t 3600 2> /dev/null + if eval $COMMAND > $OUTPUTFILE 2>&1 ; then + echo " successful execution of $1 ($2)" >> $ERRORFILE + else + echo " ERROR: execution of $1 ($2)" >> $ERRORFILE + cat $OUTPUTFILE >> $FULL_ERROR_DESCRIPTION_FILE + fi +} + +run_test_alt() +{ + basedata=`basename "$5"` + OUTPUTFILE=ProgramOutput.$1.`echo $5 | tr '/' '.'`.$6 + #echo ****generating file $OUTPUTFILE + # dirdata=`dirname "$datafile"` + rm -f $OUTPUTFILE + COMMAND="./$1" + echo "Executing $1 $5 $6 ... " + if eval $COMMAND $2 $3 $4 $5 $6 > $OUTPUTFILE 2>&1 ; then + echo " successful execution of $5 $6" >> $ERRORFILE + else + echo " ERROR: execution of $5 $6" >> $ERRORFILE + cat $OUTPUTFILE >> $FULL_ERROR_DESCRIPTION_FILE + fi +} + +run_trapped_test() +{ + #local name=$1; + #local datafile=$2; + + if [ "${OSTYPE}" != "cygwin" ]; then + ulimit -t 1200 + run_test_alt $1 $2 $3 $4 $5 $6 + else + run_test_alt $1 $2 $3 $4 $5 $6 & + WPID=$! + trap "kill -9 $WPID" INT + (sleep 1200; kill -9 $WPID) > /dev/null 2>&1 & + SPID=$! + wait $WPID > /dev/null 2>&1 + # RES=$? + kill -9 $SPID > /dev/null 2>&1 + # return $RES + fi +} + +clean_tests() +{ + if [ "${TEST_WITH_CMAKE}" != "FALSE" ]; then + # + # The clean target generated by CMake under cygwin + # always fails for some reason + # + if ! ( uname | grep -q "CYGWIN" ) ; then + make -fMakefile clean + fi + fi + eval "make clean > /dev/null 2>&1" +} + +compile_and_run() +{ + local name=$1; + + echo "Compiling $name ... " + if [ "${TEST_WITH_CMAKE}" != "FALSE" ]; then + if eval '${MAKE_CMD} VERBOSE=1 -fMakefile $1' ; then + echo " successful compilation of $1" >> $ERRORFILE + SUCCESS="y" + else + echo " ERROR: compilation of $1" >> $ERRORFILE + SUCCESS="" + fi + else + SUCCESS="y" + #TESTSUITE_CXXFLAGS="$TESTSUITE_CXXFLAGS" + TESTSUITE_CXXFLAGS="" + TESTSUITE_LDFLAGS="$TESTSUITE_LDFLAGS" + if eval 'make CGAL_MAKEFILE=$CGAL_MAKEFILE \ + TESTSUITE_CXXFLAGS="$TESTSUITE_CXXFLAGS" \ + TESTSUITE_LDFLAGS="$TESTSUITE_LDFLAGS" $name' ; then + echo " successful compilation of $name" >> $ERRORFILE + else + echo " ERROR: compilation of $name" >> $ERRORFILE + SUCCESS="" + fi + fi + + if [ "${TEST_WITH_CMAKE}" != "FALSE" ]; then + if [ -n "$DO_RUN" ] ; then + if [ -n "${SUCCESS}" ] ; then + run_test $1 + else + echo " ERROR: not executed $1" >> $ERRORFILE + fi + fi + else + if [ -n "${SUCCESS}" ] ; then + OUTPUTFILE=ProgramOutput.$name.$PLATFORM + rm -f $OUTPUTFILE + COMMAND="./$name" + if [ -f $name.cmd ] ; then + COMMAND="$COMMAND `cat $name.cmd`" + fi + if [ -f $name.cin ] ; then + COMMAND="cat $name.cin | $COMMAND" + fi + echo "Executing $name ... " + echo " " + if eval $COMMAND > $OUTPUTFILE 2>&1 ; then + echo " successful execution of $name" >> $ERRORFILE + else + echo " ERROR: execution of $name" >> $ERRORFILE + cat $OUTPUTFILE >> $FULL_ERROR_DESCRIPTION_FILE + fi + else + echo " ERROR: not executed $name" >> $ERRORFILE + fi + fi + clean_tests +} + +compile_and_run_trapped_test() +{ + local name=$1; + + if [ "${OSTYPE}" != "cygwin" ]; then + ulimit -t 1200 + compile_and_run $1 + else + compile_and_run $1 & + WPID=$! + trap "kill -9 $WPID" INT + (sleep 1200; kill -9 $WPID) > /dev/null 2>&1 & + SPID=$! + wait $WPID > /dev/null 2>&1 + # RES=$? + kill -9 $SPID > /dev/null 2>&1 + # return $RES + fi +} + +execute_commands_old_structure() +{ + +# at first the tests where designed in such way that all the test input was +# in one file, the points, the xcurves, the curves and the execution block +# this function is used to execute the old tests, one may use it when needed +# but you should remember that separating the input into smaller files creates +# much more modular and comfortable test suite + +# the old structure is default, so this function executes all commands +# except the commands that are given as arguments + + + commands_indicator[COMPARE]=1 + commands_indicator[VERTEX]=1 + commands_indicator[IS_VERTICAL]=1 + commands_indicator[COMPARE_Y_AT_X]=1 + commands_indicator[COMPARE_Y_AT_X_LEFT]=1 + commands_indicator[COMPARE_Y_AT_X_RIGHT]=1 + commands_indicator[MAKE_X_MONOTONE]=1 + commands_indicator[INTERSECT]=1 + commands_indicator[SPLIT]=1 + commands_indicator[ARE_MERGEABLE]=1 + commands_indicator[MERGE]=1 + commands_indicator[ASSERTIONS]=1 + commands_indicator[CONSTRUCTOR]=1 + i=1 + if [ $# -gt 2 ] ; then + for arg in $* ; do + if [ $i -gt 2 ] ; then + commands_indicator[$arg]=0 + fi + let "i+=1" + done + fi + if [ ${commands_indicator[$COMPARE]} -ne 0 ] ; then + run_trapped_test test_traits \ + data/compare.pt data/empty.zero \ + data/empty.zero data/compare $2 + fi + if [ ${commands_indicator[$VERTEX]} -ne 0 ] ; then + run_trapped_test test_traits \ + data/$1/vertex.pt data/$1/vertex.xcv \ + data/empty.zero data/$1/vertex $2 + fi + if [ ${commands_indicator[$IS_VERTICAL]} -ne 0 ] ; then + run_trapped_test test_traits \ + data/empty.zero data/$1/is_vertical.xcv data/empty.zero \ + data/$1/is_vertical $2 + fi + if [ ${commands_indicator[$COMPARE_Y_AT_X]} -ne 0 ] ; then + run_trapped_test test_traits \ + data/$1/compare_y_at_x.pt data/$1/compare_y_at_x.xcv \ + data/empty.zero data/$1/compare_y_at_x $2 + fi + if [ ${commands_indicator[$COMPARE_Y_AT_X_LEFT]} -ne 0 ] ; then + run_trapped_test test_traits \ + data/$1/compare_y_at_x_left.pt data/$1/compare_y_at_x_left.xcv \ + data/empty.zero data/$1/compare_y_at_x_left $2 + fi + if [ ${commands_indicator[$COMPARE_Y_AT_X_RIGHT]} -ne 0 ] ; then + run_trapped_test test_traits \ + data/$1/compare_y_at_x_right.pt data/$1/compare_y_at_x_right.xcv \ + data/empty.zero data/$1/compare_y_at_x_right $2 + fi + if [ ${commands_indicator[$MAKE_X_MONOTONE]} -ne 0 ] ; then + run_trapped_test test_traits \ + data/empty.zero data/$1/make_x_monotone.xcv \ + data/$1/make_x_monotone.cv data/$1/make_x_monotone $2 + fi + if [ ${commands_indicator[$INTERSECT]} -ne 0 ] ; then + run_trapped_test test_traits \ + data/$1/intersect.pt data/$1/intersect.xcv \ + data/empty.zero data/$1/intersect $2 + fi + if [ ${commands_indicator[$SPLIT]} -ne 0 ] ; then + run_trapped_test test_traits \ + data/$1/split.pt data/$1/split.xcv \ + data/empty.zero data/$1/split $2 + fi + if [ ${commands_indicator[$ARE_MERGEABLE]} -ne 0 ] ; then + run_trapped_test test_traits \ + data/empty.zero data/$1/are_mergeable.xcv \ + data/empty.zero data/$1/are_mergeable $2 + fi + if [ ${commands_indicator[$MERGE]} -ne 0 ] ; then + run_trapped_test test_traits \ + data/empty.zero data/$1/merge.xcv \ + data/empty.zero data/$1/merge $2 + fi + if [ ${commands_indicator[$ASSERTIONS]} -ne 0 ] ; then + run_trapped_test test_traits \ + data/$1/assertions.pt data/$1/assertions.xcv \ + data/empty.zero data/$1/assertions $2 + fi + if [ ${commands_indicator[$CONSTRUCTOR]} -ne 0 ] ; then + run_trapped_test test_traits \ + data/empty.zero data/$1/constructor.xcv \ + data/$1/constructor.cv data/$1/constructor $2 + fi +} + +execute_commands_new_structure() +{ + +# the new design for the tests includes separation of the test input into 4 +# parts: points file, xcurves file, curves file and execution block file. +# one may reuse the input files for the various tests + +# the new structure is not default, so this function executes only +# commands that are given as arguments + + commands_indicator[COMPARE]=0 + commands_indicator[VERTEX]=0 + commands_indicator[IS_VERTICAL]=0 + commands_indicator[COMPARE_X_AT_LIMIT]=0 + commands_indicator[COMPARE_X_NEAR_LIMIT]=0 + commands_indicator[COMPARE_X_ON_BOUNDARY]=0 + commands_indicator[COMPARE_X_NEAR_BOUNDARY]=0 + commands_indicator[COMPARE_Y_NEAR_BOUNDARY]=0 + commands_indicator[PARAMETER_SPACE_X]=0 + commands_indicator[PARAMETER_SPACE_Y]=0 + commands_indicator[COMPARE_Y_AT_X]=0 + commands_indicator[COMPARE_Y_AT_X_LEFT]=0 + commands_indicator[COMPARE_Y_AT_X_RIGHT]=0 + commands_indicator[MAKE_X_MONOTONE]=0 + commands_indicator[INTERSECT]=0 + commands_indicator[SPLIT]=0 + commands_indicator[ARE_MERGEABLE]=0 + commands_indicator[MERGE]=0 + commands_indicator[ASSERTIONS]=0 + commands_indicator[CONSTRUCTOR]=0 + commands_indicator[EQUAL]=0 + commands_indicator[PUSH_BACK]=0 + commands_indicator[PUSH_FRONT]=0 + commands_indicator[NUMBER_OF_POINTS]=0 + commands_indicator[COMPARE_ENDPOINTS_XY]=0 + commands_indicator[CONSTRUCT_OPPOSITE]=0 + commands_indicator[TRIM]=0 + i=1 + if [ $# -gt 2 ] ; then + for arg in $* ; do + if [ $i -gt 2 ] ; then + commands_indicator[$arg]=1 + fi + let "i+=1" + done + fi + if [ ${commands_indicator[$COMPARE]} -ne 0 ] ; then + run_trapped_test test_traits data/$1/points \ + data/$1/xcurves data/$1/curves data/$1/compare $2 + fi + if [ ${commands_indicator[$VERTEX]} -ne 0 ] ; then + run_trapped_test test_traits data/$1/points \ + data/$1/xcurves data/$1/curves data/$1/vertex $2 + fi + if [ ${commands_indicator[$IS_VERTICAL]} -ne 0 ] ; then + run_trapped_test test_traits data/$1/points \ + data/$1/xcurves data/$1/curves data/$1/is_vertical $2 + fi + if [ ${commands_indicator[$COMPARE_X_AT_LIMIT]} -ne 0 ] ; then + run_trapped_test test_traits data/$1/points \ + data/$1/xcurves data/$1/curves data/$1/compare_x_at_limit $2 + fi + if [ ${commands_indicator[$COMPARE_X_NEAR_LIMIT]} -ne 0 ] ; then + run_trapped_test test_traits data/$1/points \ + data/$1/xcurves data/$1/curves data/$1/compare_x_near_limit $2 + fi + if [ ${commands_indicator[$COMPARE_X_ON_BOUNDARY]} -ne 0 ] ; then + run_trapped_test test_traits data/$1/points \ + data/$1/xcurves data/$1/curves data/$1/compare_x_on_boundary $2 + fi + if [ ${commands_indicator[$COMPARE_X_NEAR_BOUNDARY]} -ne 0 ] ; then + run_trapped_test test_traits data/$1/points \ + data/$1/xcurves data/$1/curves data/$1/compare_x_near_boundary $2 + fi + if [ ${commands_indicator[$COMPARE_Y_NEAR_BOUNDARY]} -ne 0 ] ; then + run_trapped_test test_traits data/$1/points \ + data/$1/xcurves data/$1/curves data/$1/compare_y_near_boundary $2 + fi + if [ ${commands_indicator[$PARAMETER_SPACE_X]} -ne 0 ] ; then + run_trapped_test test_traits data/$1/points \ + data/$1/xcurves data/$1/curves data/$1/parameter_space_x $2 + fi + if [ ${commands_indicator[$PARAMETER_SPACE_Y]} -ne 0 ] ; then + run_trapped_test test_traits data/$1/points \ + data/$1/xcurves data/$1/curves data/$1/parameter_space_y $2 + fi + if [ ${commands_indicator[$COMPARE_Y_AT_X]} -ne 0 ] ; then + run_trapped_test test_traits data/$1/points \ + data/$1/xcurves data/$1/curves data/$1/compare_y_at_x $2 + fi + if [ ${commands_indicator[$COMPARE_Y_AT_X_LEFT]} -ne 0 ] ; then + run_trapped_test test_traits data/$1/points \ + data/$1/xcurves data/$1/curves data/$1/compare_y_at_x_left $2 + fi + if [ ${commands_indicator[$COMPARE_Y_AT_X_RIGHT]} -ne 0 ] ; then + run_trapped_test test_traits data/$1/points \ + data/$1/xcurves data/$1/curves data/$1/compare_y_at_x_right $2 + fi + if [ ${commands_indicator[$MAKE_X_MONOTONE]} -ne 0 ] ; then + run_trapped_test test_traits data/$1/points \ + data/$1/xcurves data/$1/curves data/$1/make_x_monotone $2 + fi + if [ ${commands_indicator[$INTERSECT]} -ne 0 ] ; then + run_trapped_test test_traits data/$1/points \ + data/$1/xcurves data/$1/curves data/$1/intersect $2 + fi + if [ ${commands_indicator[$SPLIT]} -ne 0 ] ; then + run_trapped_test test_traits data/$1/points \ + data/$1/xcurves data/$1/curves data/$1/split $2 + fi + if [ ${commands_indicator[$ARE_MERGEABLE]} -ne 0 ] ; then + run_trapped_test test_traits data/$1/points \ + data/$1/xcurves data/$1/curves data/$1/are_mergeable $2 + fi + if [ ${commands_indicator[$MERGE]} -ne 0 ] ; then + run_trapped_test test_traits data/$1/points \ + data/$1/xcurves data/$1/curves data/$1/merge $2 + fi + if [ ${commands_indicator[$ASSERTIONS]} -ne 0 ] ; then + run_trapped_test test_traits data/$1/points \ + data/$1/xcurves data/$1/curves data/$1/assertions $2 + fi + if [ ${commands_indicator[$CONSTRUCTOR]} -ne 0 ] ; then + run_trapped_test test_traits data/$1/points \ + data/$1/xcurves data/$1/curves data/$1/constructor $2 + fi + if [ ${commands_indicator[$EQUAL]} -ne 0 ] ; then + run_trapped_test test_traits data/$1/points \ + data/$1/xcurves data/$1/curves data/$1/equal $2 + fi + if [ ${commands_indicator[$PUSH_BACK]} -ne 0 ] ; then + run_trapped_test test_traits data/$1/points \ + data/$1/xcurves data/$1/curves data/$1/push_back $2 + fi + if [ ${commands_indicator[$PUSH_FRONT]} -ne 0 ] ; then + run_trapped_test test_traits data/$1/points \ + data/$1/xcurves data/$1/curves data/$1/push_front $2 + fi + if [ ${commands_indicator[$NUMBER_OF_POINTS]} -ne 0 ] ; then + run_trapped_test test_traits data/$1/points \ + data/$1/xcurves data/$1/curves data/$1/number_of_points $2 + fi + if [ ${commands_indicator[$COMPARE_ENDPOINTS_XY]} -ne 0 ] ; then + run_trapped_test test_traits data/$1/points \ + data/$1/xcurves data/$1/curves data/$1/compare_endpoints_xy $2 + fi + if [ ${commands_indicator[$CONSTRUCT_OPPOSITE]} -ne 0 ] ; then + run_trapped_test test_traits data/$1/points \ + data/$1/xcurves data/$1/curves data/$1/construct_opposite $2 + fi + if [ ${commands_indicator[$TRIM]} -ne 0 ] ; then + run_trapped_test test_traits data/$1/points \ + data/$1/xcurves data/$1/curves data/$1/trim $2 + fi +} + +execute_commands_traits_adaptor() +{ + +# the new structure is not default, so this function executes only +# commands that are given as arguments + + commands_indicator[PARAMETER_SPACE_X]=0 + commands_indicator[PARAMETER_SPACE_Y]=0 + commands_indicator[COMPARE_X_AT_LIMIT]=0 + commands_indicator[COMPARE_X_NEAR_LIMIT]=0 + commands_indicator[COMPARE_X_ON_BOUNDARY]=0 + commands_indicator[COMPARE_X_NEAR_BOUNDARY]=0 + commands_indicator[COMPARE_Y_NEAR_BOUNDARY]=0 + commands_indicator[COMPARE_Y_AT_X_LEFT]=0 + commands_indicator[ARE_MERGEABLE]=0 + commands_indicator[MERGE]=0 + commands_indicator[X_ON_IDENTIFICATION]=0 + commands_indicator[Y_ON_IDENTIFICATION]=0 + commands_indicator[IS_BOUNDED]=0 + commands_indicator[IS_IN_X_RANGE]=0 + commands_indicator[COMPARE_Y_POSITION]=0 + commands_indicator[IS_BETWEEN_CW]=0 + commands_indicator[COMPARE_CW_AROUND_POINT]=0 + + i=1 + if [ $# -gt 2 ] ; then + for arg in $* ; do + if [ $i -gt 2 ] ; then + commands_indicator[$arg]=1 + fi + let "i+=1" + done + fi + + if [ ${commands_indicator[$PARAMETER_SPACE_X]} -ne 0 ] ; then + run_trapped_test test_traits_adaptor data/test_adaptor/$1/points \ + data/test_adaptor/$1/xcurves data/test_adaptor/$1/curves \ + data/test_adaptor/$1/parameter_space_x $2 + fi + if [ ${commands_indicator[$PARAMETER_SPACE_Y]} -ne 0 ] ; then + run_trapped_test test_traits_adaptor data/test_adaptor/$1/points \ + data/test_adaptor/$1/xcurves data/test_adaptor/$1/curves \ + data/test_adaptor/$1/parameter_space_y $2 + fi + if [ ${commands_indicator[$COMPARE_X_AT_LIMIT]} -ne 0 ] ; then + run_trapped_test test_traits_adaptor data/test_adaptor/$1/points \ + data/test_adaptor/$1/xcurves data/test_adaptor/$1/curves \ + data/test_adaptor/$1/compare_x_at_limit $2 + fi + if [ ${commands_indicator[$COMPARE_X_NEAR_LIMIT]} -ne 0 ] ; then + run_trapped_test test_traits_adaptor data/test_adaptor/$1/points \ + data/test_adaptor/$1/xcurves data/test_adaptor/$1/curves \ + data/test_adaptor/$1/compare_x_near_limit $2 + fi + + if [ ${commands_indicator[$COMPARE_X_ON_BOUNDARY]} -ne 0 ] ; then + run_trapped_test test_traits_adaptor data/test_adaptor/$1/points \ + data/test_adaptor/$1/xcurves data/test_adaptor/$1/curves \ + data/test_adaptor/$1/compare_x_on_boundary $2 + fi + if [ ${commands_indicator[$COMPARE_X_NEAR_BOUNDARY]} -ne 0 ] ; then + run_trapped_test test_traits_adaptor data/test_adaptor/$1/points \ + data/test_adaptor/$1/xcurves data/test_adaptor/$1/curves \ + data/test_adaptor/$1/compare_x_near_boundary $2 + fi + + if [ ${commands_indicator[$COMPARE_Y_NEAR_BOUNDARY]} -ne 0 ] ; then + run_trapped_test test_traits_adaptor data/test_adaptor/$1/points \ + data/test_adaptor/$1/xcurves data/test_adaptor/$1/curves \ + data/test_adaptor/$1/compare_y_near_boundary $2 + fi + if [ ${commands_indicator[$COMPARE_Y_AT_X_LEFT]} -ne 0 ] ; then + run_trapped_test test_traits_adaptor data/test_adaptor/$1/points \ + data/test_adaptor/$1/xcurves data/test_adaptor/$1/curves \ + data/test_adaptor/$1/compare_y_at_x_left $2 + fi + if [ ${commands_indicator[$ARE_MERGEABLE]} -ne 0 ] ; then + run_trapped_test test_traits_adaptor data/test_adaptor/$1/points \ + data/test_adaptor/$1/xcurves data/test_adaptor/$1/curves \ + data/test_adaptor/$1/are_mergeable $2 + fi + if [ ${commands_indicator[$MERGE]} -ne 0 ] ; then + run_trapped_test test_traits_adaptor data/test_adaptor/$1/points \ + data/test_adaptor/$1/xcurves data/test_adaptor/$1/curves \ + data/test_adaptor/$1/merge $2 + fi + if [ ${commands_indicator[X_ON_IDENTIFICATION]} -ne 0 ] ; then + run_trapped_test test_traits_adaptor data/test_adaptor/$1/points \ + data/test_adaptor/$1/xcurves data/test_adaptor/$1/curves \ + data/test_adaptor/$1/x_on_idintification $2 + fi + if [ ${commands_indicator[Y_ON_IDENTIFICATION]} -ne 0 ] ; then + run_trapped_test test_traits_adaptor data/test_adaptor/$1/points \ + data/test_adaptor/$1/xcurves data/test_adaptor/$1/curves \ + data/test_adaptor/$1/x_on_idintification $2 + fi + if [ ${commands_indicator[IS_BOUNDED]} -ne 0 ] ; then + run_trapped_test test_traits_adaptor data/test_adaptor/$1/points \ + data/test_adaptor/$1/xcurves data/test_adaptor/$1/curves \ + data/test_adaptor/$1/is_bounded $2 + fi + if [ ${commands_indicator[IS_IN_X_RANGE]} -ne 0 ] ; then + run_trapped_test test_traits_adaptor data/test_adaptor/$1/points \ + data/test_adaptor/$1/xcurves data/test_adaptor/$1/curves \ + data/test_adaptor/$1/is_in_x_range $2 + fi + if [ ${commands_indicator[COMPARE_Y_POSITION]} -ne 0 ] ; then + run_trapped_test test_traits_adaptor data/test_adaptor/$1/points \ + data/test_adaptor/$1/xcurves data/test_adaptor/$1/curves \ + data/test_adaptor/$1/compare_y_position $2 + fi + if [ ${commands_indicator[IS_BETWEEN_CW]} -ne 0 ] ; then + run_trapped_test test_traits_adaptor data/test_adaptor/$1/points \ + data/test_adaptor/$1/xcurves data/test_adaptor/$1/curves \ + data/test_adaptor/$1/is_between_cw $2 + fi + if [ ${commands_indicator[COMPARE_CW_AROUND_POINT]} -ne 0 ] ; then + run_trapped_test test_traits_adaptor data/test_adaptor/$1/points \ + data/test_adaptor/$1/xcurves data/test_adaptor/$1/curves \ + data/test_adaptor/$1/compare_cw_around_point $2 + fi +} + +#---------------------------------------------------------------------# +# traits adaptor (segments traits) +#---------------------------------------------------------------------# +test_segment_traits_adaptor() +{ + local nt=$QUOTIENT_MP_FLOAT_NT; + local kernel=$CARTESIAN_KERNEL; + local geom_traits=$SEGMENT_GEOM_TRAITS; + local flags="-DTEST_NT=$nt -DTEST_KERNEL=$kernel -DTEST_GEOM_TRAITS=$geom_traits"; + + compile_test_with_flags test_traits_adaptor segments "$flags" + if [ -n "${SUCCESS}" ] ; then + execute_commands_traits_adaptor segments segments_traits_adaptor \ + COMPARE_Y_POSITION COMPARE_CW_AROUND_POINT COMPARE_Y_AT_X_LEFT \ + ARE_MERGEABLE MERGE IS_IN_X_RANGE IS_BETWEEN_CW + else + echo " ERROR: not executed test_traits_adaptor segment_traits" >> $ERRORFILE + fi + clean_tests +} + +#---------------------------------------------------------------------# +# traits adaptor (linear traits) +#---------------------------------------------------------------------# +test_linear_traits_adaptor() +{ + local nt=$QUOTIENT_MP_FLOAT_NT; + local kernel=$CARTESIAN_KERNEL; + local geom_traits=$LINEAR_GEOM_TRAITS; + local flags="-DTEST_NT=$nt -DTEST_KERNEL=$kernel -DTEST_GEOM_TRAITS=$geom_traits"; + + compile_test_with_flags test_traits_adaptor linear "$flags" + if [ -n "${SUCCESS}" ] ; then + execute_commands_traits_adaptor linear linear_traits_adaptor \ + COMPARE_Y_AT_X_LEFT ARE_MERGEABLE MERGE IS_IN_X_RANGE \ + COMPARE_Y_POSITION IS_BETWEEN_CW COMPARE_CW_AROUND_POINT + else + echo " ERROR: not executed test_traits_adaptor linear_traits" >> $ERRORFILE + fi + clean_tests +} + +#---------------------------------------------------------------------# +# traits adaptor (spherical arcs traits) +#---------------------------------------------------------------------# +test_spherical_arcs_traits_adaptor() +{ + local nt=$CGAL_GMPQ_NT; + local kernel=$CARTESIAN_KERNEL; + local geom_traits=$GEODESIC_ARC_ON_SPHERE_GEOM_TRAITS; + local topol_traits=$SPHERICAL_TOPOL_TRAITS + local flags="-DTEST_NT=$nt -DTEST_KERNEL=$kernel -DTEST_GEOM_TRAITS=$geom_traits -DTEST_TOPOL_TRAITS=$topol_traits"; + + compile_test_with_flags test_traits_adaptor geodesic_arcs_on_sphere "$flags" + if [ -n "${SUCCESS}" ] ; then + execute_commands_traits_adaptor spherical_arcs spherical_arcs_traits_adaptor \ + COMPARE_Y_AT_X_LEFT ARE_MERGEABLE MERGE IS_IN_X_RANGE \ + COMPARE_Y_POSITION IS_BETWEEN_CW COMPARE_CW_AROUND_POINT + else + echo " ERROR: not executed test_traits_adaptor spherical_arcs_traits" >> $ERRORFILE + fi + clean_tests +} + +#---------------------------------------------------------------------# +# compile and run test with traits +#---------------------------------------------------------------------# +compile_and_run_with_flags() +{ + local name=$1; + local type=$2; + local flags=$3; + + compile_test_with_flags $name $type "$flags" + if [ -n "${SUCCESS}" ] ; then + if [ -n "$DO_RUN" ] ; then + run_test_with_flags $name $type + fi + else + echo " ERROR: not executed construction of segments" >> $ERRORFILE + fi + clean_tests +} + +#---------------------------------------------------------------------# +# construction with segments +#---------------------------------------------------------------------# +test_construction_segments() +{ + local nt=$CGAL_GMPQ_NT; + local kernel=$CARTESIAN_KERNEL; + local geom_traits=$SEGMENT_GEOM_TRAITS; + local flags="-DTEST_NT=$nt -DTEST_KERNEL=$kernel -DTEST_GEOM_TRAITS=$geom_traits"; + compile_and_run_with_flags test_construction segments "$flags" +} + +#---------------------------------------------------------------------# +# construction with linear curves +#---------------------------------------------------------------------# +test_construction_linear_curves() +{ + local nt=$CGAL_GMPQ_NT; + local kernel=$CARTESIAN_KERNEL; + local geom_traits=$LINEAR_GEOM_TRAITS; + local topol_traits=$PLANAR_UNBOUNDED_TOPOL_TRAITS; + local flags="-DTEST_NT=$nt -DTEST_KERNEL=$kernel -DTEST_GEOM_TRAITS=$geom_traits -DTEST_TOPOL_TRAITS=$topol_traits"; + compile_and_run_with_flags test_construction linear "$flags" +} + +#---------------------------------------------------------------------# +# construction with geodesic arcs on the sphere +#---------------------------------------------------------------------# +test_construction_spherical_arcs() +{ + local nt=$CGAL_GMPQ_NT; + local kernel=$CARTESIAN_KERNEL; + local geom_traits=$GEODESIC_ARC_ON_SPHERE_GEOM_TRAITS; + local topol_traits=$SPHERICAL_TOPOL_TRAITS; + local flags="-DTEST_NT=$nt -DTEST_KERNEL=$kernel -DTEST_GEOM_TRAITS=$geom_traits -DTEST_TOPOL_TRAITS=$topol_traits"; + compile_and_run_with_flags test_construction geodesic_arcs_on_sphere "$flags" +} + +#---------------------------------------------------------------------# +# construction with polylines +#---------------------------------------------------------------------# +test_construction_polylines() +{ + local nt=$CGAL_GMPQ_NT; + local kernel=$CARTESIAN_KERNEL; + local geom_traits=$POLYLINE_GEOM_TRAITS; + local flags="-DTEST_NT=$nt -DTEST_KERNEL=$kernel -DTEST_GEOM_TRAITS=$geom_traits"; + compile_and_run_with_flags test_construction polylines "$flags" +} + +#---------------------------------------------------------------------# +# overlay with segments +#---------------------------------------------------------------------# +test_overlay_segments() +{ + local nt=$CGAL_GMPQ_NT; + local kernel=$CARTESIAN_KERNEL; + local geom_traits=$SEGMENT_GEOM_TRAITS; + local flags="-DTEST_NT=$nt -DTEST_KERNEL=$kernel -DTEST_GEOM_TRAITS=$geom_traits"; + compile_and_run_with_flags test_overlay segments "$flags" +} + +#---------------------------------------------------------------------# +# overlay with geodesic arcs on the sphere +#---------------------------------------------------------------------# +test_overlay_spherical_arcs() +{ + local nt=$CGAL_GMPQ_NT; + local kernel=$CARTESIAN_KERNEL; + local geom_traits=$GEODESIC_ARC_ON_SPHERE_GEOM_TRAITS; + local topol_traits=$SPHERICAL_TOPOL_TRAITS; + local flags="-DTEST_NT=$nt -DTEST_KERNEL=$kernel -DTEST_GEOM_TRAITS=$geom_traits -DTEST_TOPOL_TRAITS=$topol_traits"; + compile_and_run_with_flags test_overlay geodesic_arcs_on_sphere "$flags" +} + +#---------------------------------------------------------------------# +# point location with segments +#---------------------------------------------------------------------# +test_point_location_segments() +{ + local nt=$CGAL_GMPQ_NT; + local kernel=$CARTESIAN_KERNEL; + local geom_traits=$SEGMENT_GEOM_TRAITS; + local flags="-DTEST_NT=$nt -DTEST_KERNEL=$kernel -DTEST_GEOM_TRAITS=$geom_traits"; + compile_and_run_with_flags test_point_location segments "$flags" +} + +# For backward compatibility +test_point_location_segments_version() +{ + local nt=$CGAL_GMPQ_NT; + local kernel=$CARTESIAN_KERNEL; + local geom_traits=$SEGMENT_GEOM_TRAITS; + local flags="-DTEST_NT=$nt -DTEST_KERNEL=$kernel -DTEST_GEOM_TRAITS=$geom_traits -DCGAL_ARR_POINT_LOCATION_VERSION=1"; + compile_and_run_with_flags test_point_location segments "$flags" +} + +# For backward compatibility +test_point_location_segments_conversion() +{ + local nt=$CGAL_GMPQ_NT; + local kernel=$CARTESIAN_KERNEL; + local geom_traits=$SEGMENT_GEOM_TRAITS; + local flags="-DTEST_NT=$nt -DTEST_KERNEL=$kernel -DTEST_GEOM_TRAITS=$geom_traits -DCGAL_ARR_POINT_LOCATION_CONVERSION"; + compile_and_run_with_flags test_point_location segments "$flags" +} + +#---------------------------------------------------------------------# +# point location dynamic with segments +#---------------------------------------------------------------------# +test_point_location_dynamic_segments() +{ + local nt=$CGAL_GMPQ_NT; + local kernel=$CARTESIAN_KERNEL; + local geom_traits=$SEGMENT_GEOM_TRAITS; + local flags="-DTEST_NT=$nt -DTEST_KERNEL=$kernel -DTEST_GEOM_TRAITS=$geom_traits"; + compile_and_run_with_flags test_point_location_dynamic segments "$flags" +} + +#---------------------------------------------------------------------# +# point location with circle segments +#---------------------------------------------------------------------# +test_point_location_circle_segments() +{ + local nt=$CGAL_GMPQ_NT; + local kernel=$CARTESIAN_KERNEL; + local geom_traits=$CIRCLE_SEGMENT_GEOM_TRAITS; + local flags="-DTEST_NT=$nt -DTEST_KERNEL=$kernel -DTEST_GEOM_TRAITS=$geom_traits"; + compile_and_run_with_flags test_point_location circle_segments "$flags" +} + +#---------------------------------------------------------------------# +# point location with linear objects +#---------------------------------------------------------------------# +test_point_location_linear() +{ + local nt=$CGAL_GMPQ_NT; + local kernel=$CARTESIAN_KERNEL; + local geom_traits=$LINEAR_GEOM_TRAITS; + local flags="-DTEST_NT=$nt -DTEST_KERNEL=$kernel -DTEST_GEOM_TRAITS=$geom_traits"; + compile_and_run_with_flags test_point_location linear "$flags" +} + +#---------------------------------------------------------------------# +# batchecd point location with segments +#---------------------------------------------------------------------# +test_batched_point_location_segments() +{ + local nt=$CGAL_GMPQ_NT; + local kernel=$CARTESIAN_KERNEL; + local geom_traits=$SEGMENT_GEOM_TRAITS; + local flags="-DTEST_NT=$nt -DTEST_KERNEL=$kernel -DTEST_GEOM_TRAITS=$geom_traits"; + compile_and_run_with_flags test_batched_point_location segments "$flags" +} + +#---------------------------------------------------------------------# +# batchecd point location with linear objects +#---------------------------------------------------------------------# +test_batched_point_location_linear() +{ + local nt=$CGAL_GMPQ_NT; + local kernel=$CARTESIAN_KERNEL; + local geom_traits=$LINEAR_GEOM_TRAITS; + local flags="-DTEST_NT=$nt -DTEST_KERNEL=$kernel -DTEST_GEOM_TRAITS=$geom_traits"; + compile_and_run_with_flags test_batched_point_location linear "$flags" +} + +#---------------------------------------------------------------------# +# batchecd point location with geodesic arcs on the sphere +#---------------------------------------------------------------------# +test_batched_point_location_spherical_arcs() +{ + local nt=$CGAL_GMPQ_NT; + local kernel=$CARTESIAN_KERNEL; + local geom_traits=$GEODESIC_ARC_ON_SPHERE_GEOM_TRAITS; + local topol_traits=$SPHERICAL_TOPOL_TRAITS; + local flags="-DTEST_NT=$nt -DTEST_KERNEL=$kernel -DTEST_GEOM_TRAITS=$geom_traits -DTEST_TOPOL_TRAITS=$topol_traits"; + compile_and_run_with_flags test_batched_point_location geodesic_arcs_on_sphere "$flags" +} + +#---------------------------------------------------------------------# +# vertical decomposition with segments +#---------------------------------------------------------------------# +test_vertical_decomposition_segments() +{ + local nt=$CGAL_GMPQ_NT; + local kernel=$CARTESIAN_KERNEL; + local geom_traits=$SEGMENT_GEOM_TRAITS; + local flags="-DTEST_NT=$nt -DTEST_KERNEL=$kernel -DTEST_GEOM_TRAITS=$geom_traits"; + compile_and_run_with_flags test_vertical_decomposition segments "$flags" +} + +#---------------------------------------------------------------------# +# vertical decomposition with linear objects +#---------------------------------------------------------------------# +test_vertical_decomposition_linear() +{ + local nt=$CGAL_GMPQ_NT; + local kernel=$CARTESIAN_KERNEL; + local geom_traits=$LINEAR_GEOM_TRAITS; + local flags="-DTEST_NT=$nt -DTEST_KERNEL=$kernel -DTEST_GEOM_TRAITS=$geom_traits"; + compile_and_run_with_flags test_vertical_decomposition linear "$flags" +} + +#---------------------------------------------------------------------# +# vertical decomposition with geodesic arcs on the sphere +#---------------------------------------------------------------------# +test_vertical_decomposition_spherical_arcs() +{ + local nt=$CGAL_GMPQ_NT; + local kernel=$CARTESIAN_KERNEL; + local geom_traits=$LINEAR_GEOM_TRAITS; + local topol_traits=$SPHERICAL_TOPOL_TRAITS; + local flags="-DTEST_NT=$nt -DTEST_KERNEL=$kernel -DTEST_GEOM_TRAITS=$geom_traits -DTEST_TOPOL_TRAITS=$topol_traits"; + compile_and_run_with_flags test_vertical_decomposition geodesic_arcs_on_sphere "$flags" +} + +#---------------------------------------------------------------------# +# segment traits +#---------------------------------------------------------------------# +test_segment_traits() +{ + local nt=$QUOTIENT_MP_FLOAT_NT; + local kernel=$CARTESIAN_KERNEL; + local geom_traits=$SEGMENT_GEOM_TRAITS; + local flags="-DTEST_NT=$nt -DTEST_KERNEL=$kernel -DTEST_GEOM_TRAITS=$geom_traits"; + + compile_test_with_flags test_traits segments "$flags" + if [ -n "${SUCCESS}" ] ; then + execute_commands_old_structure segments segment_traits \ + VERTEX IS_VERTICAL COMPARE_Y_AT_X COMPARE_Y_AT_X_LEFT CONSTRUCTOR \ + COMPARE_Y_AT_X_RIGHT ARE_MERGEABLE + + execute_commands_new_structure segments segment_traits \ + IS_VERTICAL COMPARE_Y_AT_X COMPARE_Y_AT_X_LEFT ARE_MERGEABLE + + run_trapped_test test_traits \ + data/segments/vertex.pt data/segments/xcurves \ + data/empty.zero data/segments/vertex segment_traits + else + echo " ERROR: not executed test_traits segment_traits" >> $ERRORFILE + fi + clean_tests +} + +#---------------------------------------------------------------------# +# non-caching segment traits +#---------------------------------------------------------------------# +test_non_caching_segment_traits() +{ + local nt=$CGAL_GMPQ_NT; + local kernel=$CARTESIAN_KERNEL; + local geom_traits=$NON_CACHING_SEGMENT_GEOM_TRAITS; + local flags="-DTEST_NT=$nt -DTEST_KERNEL=$kernel -DTEST_GEOM_TRAITS=$geom_traits"; + + compile_test_with_flags test_traits non_caching_segments "$flags" + if [ -n "${SUCCESS}" ] ; then + execute_commands_old_structure segments non_caching_segment_traits \ + VERTEX IS_VERTICAL COMPARE_Y_AT_X COMPARE_Y_AT_X_LEFT CONSTRUCTOR \ + COMPARE_Y_AT_X_RIGHT ARE_MERGEABLE ASSERTIONS + + execute_commands_new_structure segments segment_traits \ + IS_VERTICAL COMPARE_Y_AT_X COMPARE_Y_AT_X_LEFT + + run_trapped_test test_traits \ + data/segments/vertex.pt data/segments/xcurves \ + data/empty.zero data/segments/vertex non_caching_segment_traits + else + echo " ERROR: not executed test_traits non_caching_segment_traits" >> $ERRORFILE + fi + clean_tests +} + +#---------------------------------------------------------------------# +# polycurve conic traits +#---------------------------------------------------------------------# +test_polycurve_conic_traits() +{ + if [ -n "${CGAL_DISABLE_GMP}" ]; then + echo "CORE is not available, test_polycurve_conic_traits not ran" + return + fi + echo polycurve test starting + local nt=$CORE_EXPR_NT; + local kernel=$CARTESIAN_KERNEL; + local geom_traits=$POLYCURVE_CONIC_GEOM_TRAITS; + local flags="-DTEST_NT=$nt -DTEST_KERNEL=$kernel -DTEST_GEOM_TRAITS=$geom_traits"; + + compile_test_with_flags test_traits conic_polycurve "$flags" + if [ -n "${SUCCESS}" ] ; then + + # The input arguments for the execute_commands_new_structure, + # 1. Polycurve_conics is the directory name in "data" + # 2. polycurve_conic_traits is a string + # Execute_command_new_structure will only run the test on functors provided as the third, fourth and so on arguments. + # To see how the input data directory should be structured for each functor, check the execute_commands_new_structure function in this file. + execute_commands_new_structure polycurves_conics polycurve_conic_traits \ + COMPARE_Y_AT_X \ + INTERSECT \ + EQUAL \ + IS_VERTICAL \ + SPLIT \ + ARE_MERGEABLE \ + COMPARE_Y_AT_X_LEFT \ + COMPARE_Y_AT_X_RIGHT \ + MAKE_X_MONOTONE \ + PUSH_BACK \ + PUSH_FRONT \ + NUMBER_OF_POINTS \ + VERTEX \ + CONSTRUCT_OPPOSITE \ + MERGE \ + COMPARE_ENDPOINTS_XY \ + TRIM + + else + echo " ERROR: not executed test_traits polyline_traits" >> $ERRORFILE + fi + clean_tests +} + +#---------------------------------------------------------------------# +# polycurve arc traits +#---------------------------------------------------------------------# +test_polycurve_circular_arc_traits() +{ + local nt=$QUOTIENT_MP_FLOAT_NT; + local kernel=$CARTESIAN_KERNEL; + local geom_traits=$POLYCURVE_CIRCULAR_ARC_GEOM_TRAITS; + local flags="-DTEST_NT=$nt -DTEST_KERNEL=$kernel -DTEST_GEOM_TRAITS=$geom_traits"; + + compile_test_with_flags test_traits circular_arc_polycurve "$flags" + if [ -n "${SUCCESS}" ] ; then + execute_commands_new_structure Polycurves_circular_arcs polycurve_circular_arc_traits \ + COMPARE_Y_AT_X \ + EQUAL \ + IS_VERTICAL \ + SPLIT \ + ARE_MERGEABLE \ + COMPARE_Y_AT_X_LEFT \ + COMPARE_Y_AT_X_RIGHT \ + MAKE_X_MONOTONE \ + PUSH_BACK \ + PUSH_FRONT \ + NUMBER_OF_POINTS \ + VERTEX \ + CONSTRUCT_OPPOSITE \ + MERGE \ + COMPARE_ENDPOINTS_XY \ + INTERSECT + + else + echo " ERROR: not executed test_traits polyline_traits" >> $ERRORFILE + fi + clean_tests +} + +#---------------------------------------------------------------------# +# polycurve bezier traits +#---------------------------------------------------------------------# +test_polycurve_bezier_traits() +{ + if [ -n "${CGAL_DISABLE_GMP}" ]; then + echo "CORE is not available, test_polycurve_bezier_traits not ran" + return + fi + local nt=$CORE_EXPR_NT; + local kernel=$CARTESIAN_KERNEL; + local geom_traits=$POLYCURVE_BEZIER_GEOM_TRAITS; + local flags="-DTEST_NT=$nt -DTEST_KERNEL=$kernel -DTEST_GEOM_TRAITS=$geom_traits"; + + compile_test_with_flags test_traits bezier_polycurve "$flags" + if [ -n "${SUCCESS}" ] ; then + execute_commands_new_structure Polycurves_bezier test_polycurve_bezier_traits \ + MERGE \ + EQUAL \ + IS_VERTICAL \ + NUMBER_OF_POINTS \ + PUSH_BACK \ + PUSH_FRONT \ + VERTEX \ + ARE_MERGEABLE \ + COMPARE_ENDPOINTS_XY + # TODO (add data for these tests) + # COMPARE_Y_AT_X \ + # SPLIT \ + # COMPARE_Y_AT_X_LEFT \ + # COMPARE_Y_AT_X_RIGHT \ + # MAKE_X_MONOTONE \ + # CONSTRUCT_OPPOSITE \ + + # INTERSECT + + else + echo " ERROR: not executed test_traits polyline_traits" >> $ERRORFILE + fi + clean_tests +} + +#---------------------------------------------------------------------# +# polyline traits +#---------------------------------------------------------------------# +test_polyline_traits() +{ + local nt=$CGAL_GMPQ_NT; + local kernel=$CARTESIAN_KERNEL; + local geom_traits=$POLYLINE_GEOM_TRAITS; + local flags="-DTEST_NT=$nt -DTEST_KERNEL=$kernel -DTEST_GEOM_TRAITS=$geom_traits"; + + compile_test_with_flags test_traits test_polylines "$flags" + if [ -n "${SUCCESS}" ] ; then + execute_commands_old_structure polylines polyline_traits \ + CONSTRUCTOR COMPARE_Y_AT_X_LEFT \ + COMPARE_Y_AT_X_RIGHT ARE_MERGEABLE + else + echo " ERROR: not executed test_traits polyline_traits" >> $ERRORFILE + fi + clean_tests +} + +#---------------------------------------------------------------------# +# non-caching polyline traits +#---------------------------------------------------------------------# +test_non_caching_polyline_traits() +{ + local nt=$CGAL_GMPQ_NT; + local kernel=$CARTESIAN_KERNEL; + local geom_traits=$NON_CACHING_POLYLINE_GEOM_TRAITS; + local flags="-DTEST_NT=$nt -DTEST_KERNEL=$kernel -DTEST_GEOM_TRAITS=$geom_traits"; + + compile_test_with_flags test_traits non_caching_polylines "$flags" + if [ -n "${SUCCESS}" ] ; then + execute_commands_old_structure polylines non_caching_polyline_traits \ + CONSTRUCTOR COMPARE_Y_AT_X_LEFT \ + COMPARE_Y_AT_X_RIGHT ARE_MERGEABLE + else + echo " ERROR: not executed test_traits non_caching_polyline_traits" >> $ERRORFILE + fi + clean_tests +} + +#---------------------------------------------------------------------# +# linear traits +#---------------------------------------------------------------------# +test_linear_traits() +{ + local nt=$QUOTIENT_MP_FLOAT_NT; + local kernel=$CARTESIAN_KERNEL; + local geom_traits=$LINEAR_GEOM_TRAITS; + local flags="-DTEST_NT=$nt -DTEST_KERNEL=$kernel -DTEST_GEOM_TRAITS=$geom_traits"; + + compile_test_with_flags test_traits linear "$flags" + if [ -n "${SUCCESS}" ] ; then + execute_commands_old_structure linear/segments linear_traits.segments \ + VERTEX IS_VERTICAL COMPARE_Y_AT_X COMPARE_Y_AT_X_LEFT \ + COMPARE_Y_AT_X_RIGHT CONSTRUCTOR ARE_MERGEABLE + + execute_commands_new_structure linear/segments linear_traits.segments \ + IS_VERTICAL COMPARE_Y_AT_X COMPARE_Y_AT_X_LEFT + + run_trapped_test test_traits \ + data/linear/segments/vertex.pt data/linear/segments/xcurves \ + data/empty.zero data/linear/segments/vertex linear_traits.segments + + execute_commands_old_structure linear/rays linear_traits.rays \ + VERTEX IS_VERTICAL COMPARE_Y_AT_X COMPARE_Y_AT_X_LEFT \ + COMPARE_Y_AT_X_RIGHT CONSTRUCTOR ARE_MERGEABLE + + execute_commands_new_structure linear/rays linear_traits.rays \ + IS_VERTICAL COMPARE_Y_AT_X COMPARE_Y_AT_X_LEFT + + run_trapped_test test_traits \ + data/linear/rays/vertex.pt data/linear/rays/xcurves \ + data/empty.zero data/linear/rays/vertex linear_traits.rays + + execute_commands_new_structure linear/lines linear_traits.lines \ + IS_VERTICAL COMPARE_Y_AT_X COMPARE_Y_AT_X_LEFT INTERSECT \ + SPLIT MERGE \ + PARAMETER_SPACE_X PARAMETER_SPACE_Y \ + COMPARE_X_AT_LIMIT COMPARE_X_NEAR_LIMIT COMPARE_Y_NEAR_BOUNDARY + else + echo " ERROR: not executed test_traits linear_traits" >> $ERRORFILE + fi + clean_tests +} + +#---------------------------------------------------------------------# +# conic traits +#---------------------------------------------------------------------# +test_conic_traits() +{ + if [ -n "${CGAL_DISABLE_GMP}" ]; then + echo "CORE is not available, test_conic_traits not ran" + return + fi + local nt=$CORE_EXPR_NT; + local kernel=$CARTESIAN_KERNEL; + local geom_traits=$CORE_CONIC_GEOM_TRAITS; + local flags="-DTEST_NT=$nt -DTEST_KERNEL=$kernel -DTEST_GEOM_TRAITS=$geom_traits"; + + compile_test_with_flags test_traits conics "$flags" + if [ -n "${SUCCESS}" ] ; then + execute_commands_old_structure conics conic_traits \ + INTERSECT SPLIT MERGE COMPARE_Y_AT_X_LEFT \ + COMPARE_Y_AT_X_RIGHT ARE_MERGEABLE + + execute_commands_new_structure conics conic_traits \ + INTERSECT SPLIT MERGE + + run_trapped_test test_traits \ + data/conics/compare.pt data/empty.zero \ + data/empty.zero data/conics/compare conic_traits + else + echo " ERROR: not executed test_traits conic_traits" >> $ERRORFILE + fi + clean_tests +} + +#---------------------------------------------------------------------# +# "line arcs" (segments) only +#---------------------------------------------------------------------# +test_line_arc_traits() +{ + local nt=$QUOTIENT_MP_FLOAT_NT; + local kernel=$CARTESIAN_KERNEL; + local geom_traits=$LINE_ARC_GEOM_TRAITS; + local flags="-DTEST_NT=$nt -DTEST_KERNEL=$kernel -DTEST_GEOM_TRAITS=$geom_traits"; + + compile_test_with_flags test_traits line_arcs "$flags" + if [ -n "${SUCCESS}" ] ; then + execute_commands_old_structure circular_lines line_arc_traits \ + VERTEX IS_VERTICAL COMPARE_Y_AT_X COMPARE_Y_AT_X_LEFT \ + ASSERTIONS COMPARE_Y_AT_X_RIGHT MERGE ARE_MERGEABLE + + execute_commands_new_structure circular_lines line_arc_traits \ + IS_VERTICAL COMPARE_Y_AT_X + + run_trapped_test test_traits \ + data/circular_lines/compare.pt data/empty.zero \ + data/empty.zero data/circular_lines/compare line_arc_traits + + run_trapped_test test_traits \ + data/circular_lines/vertex.pt data/circular_lines/xcurves \ + data/empty.zero data/circular_lines/vertex line_arc_traits + else + echo " ERROR: not executed test_traits" >> $ERRORFILE + fi + clean_tests +} + +#---------------------------------------------------------------------# +# circular arcs only +#---------------------------------------------------------------------# +test_circular_arc_traits() +{ + local nt=$QUOTIENT_MP_FLOAT_NT; + local kernel=$CARTESIAN_KERNEL; + local geom_traits=$CIRCULAR_ARC_GEOM_TRAITS; + local flags="-DTEST_NT=$nt -DTEST_KERNEL=$kernel -DTEST_GEOM_TRAITS=$geom_traits"; + + compile_test_with_flags test_traits circular_arcs "$flags" + if [ -n "${SUCCESS}" ] ; then + execute_commands_old_structure circular_arcs circular_arc_traits \ + VERTEX IS_VERTICAL COMPARE_Y_AT_X COMPARE_Y_AT_X_LEFT \ + ASSERTIONS COMPARE_Y_AT_X_RIGHT MERGE ARE_MERGEABLE + + execute_commands_new_structure circular_arcs circular_arc_traits \ + VERTEX IS_VERTICAL COMPARE_Y_AT_X + else + echo " ERROR: not executed test_traits" >> $ERRORFILE + fi + clean_tests +} + +#---------------------------------------------------------------------# +# circular and line arcs +#---------------------------------------------------------------------# +test_circular_line_arc_traits() +{ + local nt=$QUOTIENT_MP_FLOAT_NT; + local kernel=$CARTESIAN_KERNEL; + local geom_traits=$CIRCULAR_LINE_ARC_GEOM_TRAITS; + local flags="-DTEST_NT=$nt -DTEST_KERNEL=$kernel -DTEST_GEOM_TRAITS=$geom_traits"; + + compile_test_with_flags test_traits circular_line_arcs "$flags" + if [ -n "${SUCCESS}" ] ; then + execute_commands_old_structure circular_line_arcs circular_line_arc_traits \ + VERTEX IS_VERTICAL CONSTRUCTOR COMPARE_Y_AT_X COMPARE_Y_AT_X_LEFT \ + ASSERTIONS COMPARE_Y_AT_X_RIGHT MERGE ARE_MERGEABLE + + execute_commands_new_structure circular_line_arcs circular_line_arc_traits \ + IS_VERTICAL COMPARE_Y_AT_X + + run_trapped_test test_traits \ + data/circular_line_arcs/vertex.pt data/circular_line_arcs/xcurves \ + data/empty.zero data/circular_line_arcs/vertex circular_line_arc_traits + else + echo " ERROR: not executed test_traits circular_line_arc_traits" >> $ERRORFILE + fi + clean_tests +} + +#---------------------------------------------------------------------# +# circle segment traits +#---------------------------------------------------------------------# +test_circle_segments_traits() +{ + local nt=$QUOTIENT_MP_FLOAT_NT; + local kernel=$CARTESIAN_KERNEL; + local geom_traits=$CIRCLE_SEGMENT_GEOM_TRAITS; + local flags="-DTEST_NT=$nt -DTEST_KERNEL=$kernel -DTEST_GEOM_TRAITS=$geom_traits"; + + compile_test_with_flags test_traits circle_segments "$flags" + if [ -n "${SUCCESS}" ] ; then + execute_commands_old_structure circle_segments circle_segments_traits \ + VERTEX IS_VERTICAL COMPARE_Y_AT_X COMPARE_Y_AT_X_LEFT \ + COMPARE_Y_AT_X_RIGHT CONSTRUCTOR ARE_MERGEABLE + + run_trapped_test test_traits \ + data/circle_segments/points data/circle_segments/xcurves.8 \ + data/empty.zero data/circle_segments/vertex circle_segments_traits + run_trapped_test test_traits \ + data/empty.zero data/circle_segments/xcurves.8 \ + data/empty.zero data/circle_segments/is_vertical circle_segments_traits + run_trapped_test test_traits \ + data/circle_segments/points data/circle_segments/xcurves.8 \ + data/empty.zero data/circle_segments/compare_y_at_x circle_segments_traits + run_trapped_test test_traits \ + data/circle_segments/points data/circle_segments/xcurves.16 \ + data/empty.zero data/circle_segments/compare_y_at_x_left circle_segments_traits + run_trapped_test test_traits \ + data/circle_segments/points data/circle_segments/xcurves.16 \ + data/empty.zero data/circle_segments/compare_y_at_x_right circle_segments_traits + run_trapped_test test_traits \ + data/empty.zero data/circle_segments/constructor.xcv \ + data/empty.zero data/circle_segments/constructor circle_segments_traits + else + echo " ERROR: not executed test_traits circle_segments_traits" >> $ERRORFILE + fi + clean_tests +} + +#---------------------------------------------------------------------# +# bezier traits +#---------------------------------------------------------------------# +test_bezier_traits() +{ + if [ -n "${CGAL_DISABLE_GMP}" ]; then + echo "CORE is not available, test_bezier_traits not ran" + return + fi + local nt=$CORE_EXPR_NT; + local kernel=$CARTESIAN_KERNEL; + local geom_traits=$BEZIER_GEOM_TRAITS; + local flags="-DTEST_NT=$nt -DTEST_KERNEL=$kernel -DTEST_GEOM_TRAITS=$geom_traits"; + + compile_test_with_flags test_traits Bezier "$flags" + if [ -n "${SUCCESS}" ] ; then + execute_commands_old_structure bezier bezier_traits \ + COMPARE_Y_AT_X_LEFT COMPARE_Y_AT_X_RIGHT SPLIT \ + CONSTRUCTOR ASSERTIONS ARE_MERGEABLE + else + echo " ERROR: not executed test_traits bezier_traits" >> $ERRORFILE + fi + clean_tests +} + +#---------------------------------------------------------------------# +# spherical arc traits +#---------------------------------------------------------------------# +test_spherical_arc_traits() +{ + local nt=$CGAL_GMPQ_NT; + local kernel=$CARTESIAN_KERNEL; + local geom_traits=$GEODESIC_ARC_ON_SPHERE_GEOM_TRAITS; + local topol_traits=$SPHERICAL_TOPOL_TRAITS + local flags="-DTEST_NT=$nt -DTEST_KERNEL=$kernel -DTEST_GEOM_TRAITS=$geom_traits -DTEST_TOPOL_TRAITS=$topol_traits"; + + compile_test_with_flags test_traits geodesic_arcs_on_sphere "$flags" + if [ -n "${SUCCESS}" ] ; then + execute_commands_old_structure spherical_arcs spherical_arc_traits \ + COMPARE_Y_AT_X_LEFT COMPARE_Y_AT_X_RIGHT INTERSECT \ + CONSTRUCTOR \ + COMPARE MAKE_X_MONOTONE SPLIT MERGE ASSERTIONS ARE_MERGEABLE + + execute_commands_new_structure spherical_arcs spherical_arc_traits \ + INTERSECT \ + COMPARE_X_ON_BOUNDARY COMPARE_X_NEAR_BOUNDARY \ + COMPARE_Y_NEAR_BOUNDARY + + run_trapped_test test_traits \ + data/spherical_arcs/compare.pt data/spherical_arcs/compare.xcv \ + data/empty.zero data/spherical_arcs/compare spherical_arc_traits + else + echo " ERROR: not executed test_traits spherical_arc_traits" >> $ERRORFILE + fi + clean_tests +} + +#---------------------------------------------------------------------# +# rational arc traits +#---------------------------------------------------------------------# +test_rational_arc_traits() +{ + if [ -n "${CGAL_DISABLE_GMP}" ]; then + echo "CORE is not available, test_rational_arc_traits not ran" + return + fi + local nt=$CORE_INT_NT; + local kernel=$UNIVARIATE_ALGEBRAIC_KERNEL; + local geom_traits=$RATIONAL_ARC_GEOM_TRAITS; + local flags="-DTEST_NT=$nt -DTEST_KERNEL=$kernel -DTEST_GEOM_TRAITS=$geom_traits"; + + compile_test_with_flags test_traits rational_arcs "$flags" + if [ -n "${SUCCESS}" ] ; then + run_trapped_test test_traits \ + data/compare.pt data/empty.zero \ + data/empty.zero data/compare rational_arc_traits + + execute_commands_new_structure rational_arcs rational_arc_traits \ + VERTEX IS_VERTICAL COMPARE_Y_AT_X COMPARE_Y_AT_X_LEFT SPLIT MERGE \ + COMPARE_X_AT_LIMIT COMPARE_X_NEAR_LIMIT COMPARE_Y_NEAR_BOUNDARY + else + echo " ERROR: not executed test_traits rational_arc_traits" >> $ERRORFILE + fi + clean_tests +} + +#---------------------------------------------------------------------# +# algebraic traits with GMP/MPFI +#---------------------------------------------------------------------# +test_algebraic_traits_gmp() +{ + #TODO: Adapt + + local nt=$CGAL_GMPZ_NT; + local kernel=$UNIVARIATE_ALGEBRAIC_KERNEL; + local geom_traits=$ALGEBRAIC_GEOM_TRAITS; + local flags="-DTEST_NT=$nt -DTEST_KERNEL=$kernel -DTEST_GEOM_TRAITS=$geom_traits"; + + compile_test_with_flags test_traits algebraic "$flags" + if [ -n "${SUCCESS}" ] ; then + execute_commands_new_structure algebraic algebraic_traits_gmp \ + COMPARE COMPARE_Y_AT_X COMPARE_Y_AT_X_RIGHT COMPARE_Y_AT_X_LEFT \ + MAKE_X_MONOTONE IS_VERTICAL VERTEX SPLIT MERGE INTERSECT \ + PARAMETER_SPACE_X PARAMETER_SPACE_Y + else + echo " ERROR: not executed test_traits algebraic_traits_gmp" >> $ERRORFILE + fi + clean_tests +} + +#---------------------------------------------------------------------# +# algebraic traits with LEDA +#---------------------------------------------------------------------# +test_algebraic_traits_leda() +{ + #TODO: Adapt + + local nt=$LEDA_INT_NT; + local kernel=$UNIVARIATE_ALGEBRAIC_KERNEL; + local geom_traits=$ALGEBRAIC_GEOM_TRAITS; + local flags="-DTEST_NT=$nt -DTEST_KERNEL=$kernel -DTEST_GEOM_TRAITS=$geom_traits"; + + compile_test_with_flags test_traits algebraic "$flags" + if [ -n "${SUCCESS}" ] ; then + execute_commands_new_structure algebraic algebraic_traits_leda \ + COMPARE COMPARE_Y_AT_X COMPARE_Y_AT_X_RIGHT COMPARE_Y_AT_X_LEFT \ + MAKE_X_MONOTONE IS_VERTICAL VERTEX SPLIT MERGE INTERSECT \ + PARAMETER_SPACE_X PARAMETER_SPACE_Y + else + echo " ERROR: not executed test_traits algebraic_traits_leda" >> $ERRORFILE + fi + clean_tests +} + + +#---------------------------------------------------------------------# +# algebraic traits with CORE +#---------------------------------------------------------------------# +test_algebraic_traits_core() +{ + #TODO: Adapt + if [ -n "${CGAL_DISABLE_GMP}" ]; then + echo "CORE is not available, test_algebraic_traits_core not ran" + return + fi + local nt=$CORE_INT_NT; + local kernel=$UNIVARIATE_ALGEBRAIC_KERNEL; + local geom_traits=$ALGEBRAIC_GEOM_TRAITS; + local flags="-DTEST_NT=$nt -DTEST_KERNEL=$kernel -DTEST_GEOM_TRAITS=$geom_traits"; + + compile_test_with_flags test_traits algebraic "$flags" + if [ -n "${SUCCESS}" ] ; then + execute_commands_new_structure algebraic algebraic_traits_core \ + COMPARE COMPARE_Y_AT_X COMPARE_Y_AT_X_RIGHT COMPARE_Y_AT_X_LEFT \ + MAKE_X_MONOTONE IS_VERTICAL VERTEX SPLIT MERGE INTERSECT \ + PARAMETER_SPACE_X PARAMETER_SPACE_Y + else + echo " ERROR: not executed test_traits algebraic_traits_core" >> $ERRORFILE + fi + clean_tests +} + +#---------------------------------------------------------------------# +# remove the previous error file +#---------------------------------------------------------------------# + +rm -f $ERRORFILE +rm -f $FULL_ERROR_DESCRIPTION_FILE +rm -f ProgramOutput.test_* +touch $ERRORFILE + +#---------------------------------------------------------------------# +# compile and run the tests +#---------------------------------------------------------------------# + + + +if [ $# -ne 0 ] ; then + case $1 in + -cmake) TEST_WITH_CMAKE="TRUE" ;; + *)TEST_WITH_CMAKE="FALSE" ;; + esac +else + TEST_WITH_CMAKE="FALSE" +fi + +echo "Run all tests." + +if [ "${TEST_WITH_CMAKE}" != "FALSE" ]; then + configure +fi + +if [ "${TEST_WITH_CMAKE}" != "FALSE" ]; then + compile_and_run construction_test_suite_generator +fi + +test_segment_traits +test_non_caching_segment_traits +test_polyline_traits +test_polycurve_conic_traits +test_polycurve_circular_arc_traits +test_polycurve_bezier_traits +test_non_caching_polyline_traits +test_linear_traits +test_conic_traits + +test_line_arc_traits # "line arcs" (segments) only +test_circular_arc_traits # circular arcs only +test_circular_line_arc_traits # for both + +test_circle_segments_traits +test_bezier_traits + +test_spherical_arc_traits + +test_rational_arc_traits + +test_algebraic_traits_core +test_algebraic_traits_gmp +test_algebraic_traits_leda + +compile_and_run test_data_traits + +compile_and_run test_insertion +compile_and_run test_unbounded_rational_insertion +compile_and_run test_unbounded_rational_direct_insertion +compile_and_run test_rational_function_traits_2 +compile_and_run test_iso_verts + +compile_and_run test_vert_ray_shoot_vert_segments + +test_construction_segments +test_construction_linear_curves +test_construction_spherical_arcs +test_construction_polylines + +test_overlay_segments +test_overlay_spherical_arcs + +test_point_location_segments +test_point_location_segments_version +test_point_location_segments_conversion +test_point_location_circle_segments +test_point_location_linear + +test_point_location_dynamic_segments + +test_batched_point_location_segments +test_batched_point_location_linear +test_batched_point_location_spherical_arcs + +test_vertical_decomposition_segments +test_vertical_decomposition_linear +# test_vertical_decomposition_spherical_arcs + +compile_and_run test_dual +compile_and_run test_do_intersect +compile_and_run test_zone + +compile_and_run test_observer +compile_and_run test_do_equal + +test_segment_traits_adaptor +test_linear_traits_adaptor +test_spherical_arcs_traits_adaptor + +compile_and_run test_removal +compile_and_run test_unbounded_removal +compile_and_run test_spherical_removal + +compile_and_run test_io + +compile_and_run test_sgm + +# if any error occured then append the full error description file to error file + +if [ -f $FULL_ERROR_DESCRIPTION_FILE ] ; then + echo "******************** appending all error outputs ********************" >> $ERRORFILE + cat $FULL_ERROR_DESCRIPTION_FILE >> $ERRORFILE +fi diff --git a/BGL/doc/BGL/Concepts/EdgeListGraph.h b/BGL/doc/BGL/Concepts/EdgeListGraph.h index 0816fb407ac..6a4d502d51e 100644 --- a/BGL/doc/BGL/Concepts/EdgeListGraph.h +++ b/BGL/doc/BGL/Concepts/EdgeListGraph.h @@ -38,16 +38,16 @@ num_edges(const EdgeListGraph& g); /*! \relates EdgeListGraph -returns the source vertex of `h`. +returns the source vertex of `e`. */ template boost::graph_traits::vertex_descriptor -source(boost::graph_traits::halfedge_descriptor h, const EdgeListGraph& g); +source(boost::graph_traits::edge_descriptor e, const EdgeListGraph& g); /*! \relates EdgeListGraph -returns the target vertex of `h`. +returns the target vertex of `e`. */ template boost::graph_traits::vertex_descriptor -target(boost::graph_traits::halfedge_descriptor h, const EdgeListGraph& g); +target(boost::graph_traits::edge_descriptor e, const EdgeListGraph& g); diff --git a/BGL/doc/BGL/PackageDescription.txt b/BGL/doc/BGL/PackageDescription.txt index 85411a04874..1aaf1804fbc 100644 --- a/BGL/doc/BGL/PackageDescription.txt +++ b/BGL/doc/BGL/PackageDescription.txt @@ -122,12 +122,12 @@ and adds the requirement for traversal of all edges in a graph. An upper bound of the number of edges of the graph - `source(g)` + `source(e, g)` `vertex_descriptor` The source vertex of `e` - `target(g)` + `target(e, g)` `vertex_descriptor` The target vertex of `e` diff --git a/BGL/include/CGAL/boost/graph/helpers.h b/BGL/include/CGAL/boost/graph/helpers.h index e1023d591df..44bebed6a9f 100644 --- a/BGL/include/CGAL/boost/graph/helpers.h +++ b/BGL/include/CGAL/boost/graph/helpers.h @@ -973,33 +973,6 @@ make_tetrahedron(const P& p0, const P& p1, const P& p2, const P& p3, Graph& g) return opposite(h2,g); } -/// \cond SKIP_IN_DOC -template -bool is_degenerate_triangle_face( - typename boost::graph_traits::halfedge_descriptor hd, - TriangleMesh& tmesh, - const VertexPointMap& vpmap, - const Traits& traits) -{ - CGAL_assertion(!is_border(hd, tmesh)); - - const typename Traits::Point_3& p1 = get(vpmap, target( hd, tmesh) ); - const typename Traits::Point_3& p2 = get(vpmap, target(next(hd, tmesh), tmesh) ); - const typename Traits::Point_3& p3 = get(vpmap, source( hd, tmesh) ); - return traits.collinear_3_object()(p1, p2, p3); -} - -template -bool is_degenerate_triangle_face( - typename boost::graph_traits::face_descriptor fd, - TriangleMesh& tmesh, - const VertexPointMap& vpmap, - const Traits& traits) -{ - return is_degenerate_triangle_face(halfedge(fd,tmesh), tmesh, vpmap, traits); -} -/// \endcond - /** * \ingroup PkgBGLHelperFct * \brief Creates a triangulated regular prism, outward oriented, diff --git a/BGL/include/CGAL/boost/graph/parameters_interface.h b/BGL/include/CGAL/boost/graph/parameters_interface.h index 1ec0f1504de..01c9796e813 100644 --- a/BGL/include/CGAL/boost/graph/parameters_interface.h +++ b/BGL/include/CGAL/boost/graph/parameters_interface.h @@ -78,6 +78,7 @@ CGAL_add_named_parameter(projection_functor_t, projection_functor, projection_fu CGAL_add_named_parameter(throw_on_self_intersection_t, throw_on_self_intersection, throw_on_self_intersection) CGAL_add_named_parameter(clip_volume_t, clip_volume, clip_volume) CGAL_add_named_parameter(use_compact_clipper_t, use_compact_clipper, use_compact_clipper) +CGAL_add_named_parameter(output_iterator_t, output_iterator, output_iterator) // List of named parameters that we use in the package 'Surface Mesh Simplification' CGAL_add_named_parameter(get_cost_policy_t, get_cost_policy, get_cost) diff --git a/BGL/test/BGL/test_cgal_bgl_named_params.cpp b/BGL/test/BGL/test_cgal_bgl_named_params.cpp index 019ad98dedf..22252abdd36 100644 --- a/BGL/test/BGL/test_cgal_bgl_named_params.cpp +++ b/BGL/test/BGL/test_cgal_bgl_named_params.cpp @@ -101,6 +101,7 @@ void test(const NamedParameters& np) assert(get_param(np, CGAL::internal_np::verbosity_level).v == 41); assert(get_param(np, CGAL::internal_np::projection_functor).v == 42); assert(get_param(np, CGAL::internal_np::apply_per_connected_component).v == 46); + assert(get_param(np, CGAL::internal_np::output_iterator).v == 47); // Test types @@ -177,6 +178,7 @@ void test(const NamedParameters& np) check_same_type<41>(get_param(np, CGAL::internal_np::verbosity_level)); check_same_type<42>(get_param(np, CGAL::internal_np::projection_functor)); check_same_type<46>(get_param(np, CGAL::internal_np::apply_per_connected_component)); + check_same_type<47>(get_param(np, CGAL::internal_np::output_iterator)); } int main() @@ -238,6 +240,7 @@ int main() .clip_volume(A<44>(44)) .use_compact_clipper(A<45>(45)) .apply_per_connected_component(A<46>(46)) + .output_iterator(A<47>(47)) ); return EXIT_SUCCESS; diff --git a/CGAL_ipelets/demo/CGAL_ipelets/cgal_test_with_cmake b/CGAL_ipelets/demo/CGAL_ipelets/cgal_test_with_cmake index 1893347ec5b..7113a52ffb8 100755 --- a/CGAL_ipelets/demo/CGAL_ipelets/cgal_test_with_cmake +++ b/CGAL_ipelets/demo/CGAL_ipelets/cgal_test_with_cmake @@ -26,7 +26,7 @@ configure() { echo "Configuring... " - if eval 'cmake --no-warn-unused-cli "$CMAKE_GENERATOR" -DRUNNING_CGAL_AUTO_TEST=TRUE \ + if eval 'cmake --no-warn-unused-cli ${INIT_FILE:+"-C$INIT_FILE"} "$CMAKE_GENERATOR" -DRUNNING_CGAL_AUTO_TEST=TRUE \ -DCGAL_DIR="$CGAL_DIR" \ .' ; then diff --git a/Circular_kernel_2/doc/Circular_kernel_2/Circular_kernel_2.txt b/Circular_kernel_2/doc/Circular_kernel_2/Circular_kernel_2.txt index 288a9337069..bc2674a7f71 100644 --- a/Circular_kernel_2/doc/Circular_kernel_2/Circular_kernel_2.txt +++ b/Circular_kernel_2/doc/Circular_kernel_2/Circular_kernel_2.txt @@ -73,7 +73,7 @@ The following example shows how to use a functor of the kernel. The first pieces of prototype code were comparisons of algebraic numbers of degree 2, written by Olivier Devillers -\cgalCite{cgal:dfmt-amafe-00},cgal:dfmt-amafe-02. +\cgalCite{cgal:dfmt-amafe-00},\cgalCite{cgal:dfmt-amafe-02}. Some work was then done in the direction of a "kernel" for \cgal.\cgalFootnote{Monique Teillaud, First Prototype of a \cgal Geometric Kernel with Circular Arcs, Technical Report ECG-TR-182203-01, 2002 diff --git a/Convex_hull_2/doc/Convex_hull_2/CGAL/ch_akl_toussaint.h b/Convex_hull_2/doc/Convex_hull_2/CGAL/ch_akl_toussaint.h index 50631e75cb1..0f1a616be0e 100644 --- a/Convex_hull_2/doc/Convex_hull_2/CGAL/ch_akl_toussaint.h +++ b/Convex_hull_2/doc/Convex_hull_2/CGAL/ch_akl_toussaint.h @@ -26,6 +26,7 @@ functions that return instances of these types:
  • `Traits::Less_xy_2`,
  • `Traits::Less_yx_2`,
  • `Traits::Left_turn_2`, +
  • `Traits::Orientation_2`,
  • `Traits::Equal_2`. diff --git a/Convex_hull_2/doc/Convex_hull_2/CGAL/convex_hull_2.h b/Convex_hull_2/doc/Convex_hull_2/CGAL/convex_hull_2.h index 1793bd3d593..7c8edc910bb 100644 --- a/Convex_hull_2/doc/Convex_hull_2/CGAL/convex_hull_2.h +++ b/Convex_hull_2/doc/Convex_hull_2/CGAL/convex_hull_2.h @@ -31,7 +31,8 @@ functions that return instances of these types:
  • `Traits::Equal_2`,
  • `Traits::Less_xy_2`,
  • `Traits::Less_yx_2`, -
  • `Traits::Left_turn_2`. +
  • `Traits::Left_turn_2`, +
  • `Traits::Orientation_2`. diff --git a/Convex_hull_3/include/CGAL/Convex_hull_traits_3.h b/Convex_hull_3/include/CGAL/Convex_hull_traits_3.h index 0a008157691..699155f983d 100644 --- a/Convex_hull_3/include/CGAL/Convex_hull_traits_3.h +++ b/Convex_hull_3/include/CGAL/Convex_hull_traits_3.h @@ -147,15 +147,8 @@ public: const Point_3& hp = h.p(); const Point_3& hq = h.q(); const Point_3& hr = h.r(); - //typename OldK::Less_signed_distance_to_plane_3 - // less_signed_distance_to_plane_3; - // return less_signed_distance_to_plane_3(hp, hq, hr, p, q); - return has_smaller_signed_dist_to_planeC3(hp.x(), hp.y(), hp.z(), - hq.x(), hq.y(), hq.z(), - hr.x(), hr.y(), hr.z(), - p.x(), p.y(), p.z(), - q.x(), q.y(), q.z()); - + typename K::Less_signed_distance_to_plane_3 less_signed_distance_to_plane_3; + return less_signed_distance_to_plane_3(hp, hq, hr, p, q); } }; @@ -164,35 +157,10 @@ struct GT3_for_CH3 { typedef typename GT::Point_3 Point_2; }; -template -struct Convex_hull_traits_base_3 { - typedef Point_triple_has_on_positive_side_3 Has_on_positive_side_3; - - typedef Point_triple_less_signed_distance_to_plane_3 - Less_signed_distance_to_plane_3; -}; - -template -struct Convex_hull_traits_base_3{ - typedef Filtered_predicate< - Point_triple_has_on_positive_side_3< typename R_::Exact_kernel_rt >, - Point_triple_has_on_positive_side_3< typename R_::Approximate_kernel >, - Point_triple_converter, - Point_triple_converter - > Has_on_positive_side_3; - - typedef Filtered_predicate< - Point_triple_less_signed_distance_to_plane_3< typename R_::Exact_kernel_rt >, - Point_triple_less_signed_distance_to_plane_3< typename R_::Approximate_kernel >, - Point_triple_converter, - Point_triple_converter - > Less_signed_distance_to_plane_3; -}; template -class Convex_hull_traits_3 : - public Convex_hull_traits_base_3 +class Convex_hull_traits_3 { public: typedef R_ R; @@ -228,11 +196,12 @@ class Convex_hull_traits_3 : typedef typename R::Coplanar_3 Coplanar_3; typedef typename R::Less_distance_to_point_3 Less_distance_to_point_3; - typedef typename Convex_hull_traits_base_3 - ::Has_on_positive_side_3 Has_on_positive_side_3; + typedef Point_triple_has_on_positive_side_3 Has_on_positive_side_3; - typedef typename Convex_hull_traits_base_3 - ::Less_signed_distance_to_plane_3 Less_signed_distance_to_plane_3; + typedef Point_triple_less_signed_distance_to_plane_3 + Less_signed_distance_to_plane_3; + + // required for degenerate case of all points coplanar typedef CGAL::Projection_traits_xy_3 Traits_xy_3; diff --git a/Convex_hull_3/include/CGAL/Extreme_points_traits_adapter_3.h b/Convex_hull_3/include/CGAL/Extreme_points_traits_adapter_3.h index 599f3f948c6..8991774adc3 100644 --- a/Convex_hull_3/include/CGAL/Extreme_points_traits_adapter_3.h +++ b/Convex_hull_3/include/CGAL/Extreme_points_traits_adapter_3.h @@ -138,7 +138,7 @@ public: public: Construct_plane_3(const PointPropertyMap& map, const typename Base_traits::Construct_plane_3& base): Base_traits::Construct_plane_3(base),vpm_(map), base(base){} - typename Base_traits::Plane_3 operator()(const Point_3& p, const Point_3& q, const Point_3& r)const + typename Base_traits::Plane_3 operator()(const Vertex& p, const Vertex& q, const Vertex& r)const { return base(get(vpm_,p),get(vpm_,q),get(vpm_,r)); } @@ -159,7 +159,7 @@ public: typedef bool result_type; result_type - operator()( const Plane_3& pl, const Point_3& p) const + operator()( const Plane_3& pl, const Vertex& p) const { return base(pl, get(vpm_, p)); } diff --git a/Convex_hull_3/include/CGAL/convex_hull_3.h b/Convex_hull_3/include/CGAL/convex_hull_3.h index 333334b3f42..531bfd3d943 100644 --- a/Convex_hull_3/include/CGAL/convex_hull_3.h +++ b/Convex_hull_3/include/CGAL/convex_hull_3.h @@ -182,13 +182,13 @@ struct Is_cartesian_kernel< Convex_hull_traits_3 { // Rational here is that Tag_true can only be passed by us since it is not documented // so we can assume that Kernel is a CGAL Kernel - typedef boost::is_same type; + typedef typename boost::is_same::type type; }; // Predicate internally used as a wrapper around has_on_positive_side // We provide a partial specialization restricted to the case of CGAL Cartesian Kernels with inexact constructions below //template ::type > -template > +template ::type > class Is_on_positive_side_of_plane_3{ typedef typename Traits::Point_3 Point_3; typename Traits::Plane_3 plane; diff --git a/Installation/CHANGES.md b/Installation/CHANGES.md index 49e5a58b899..fcd898c453f 100644 --- a/Installation/CHANGES.md +++ b/Installation/CHANGES.md @@ -1,6 +1,25 @@ Release History =============== +Release 4.14 +------------ + +Release date: March 2019 + +### Polygon Mesh Processing package +- Added the following new functions to detect and repair mesh degeneracies: + - `CGAL::Polygon_mesh_processing::degenerate_edges()` + - `CGAL::Polygon_mesh_processing::degenerate_faces()` + - `CGAL::Polygon_mesh_processing::is_non_manifold_vertex()` + - `CGAL::Polygon_mesh_processing::is_degenerate_triangle_face()` + - `CGAL::Polygon_mesh_processing::is_degenerate_edge()` + - `CGAL::Polygon_mesh_processing::is_needle_triangle_face()` + - `CGAL::Polygon_mesh_processing::is_cap_triangle_face()` + - `CGAL::Polygon_mesh_processing::duplicate_non_manifold_vertices()` + - `CGAL::Polygon_mesh_processing::extract_boundary_cycles()` + - `CGAL::Polygon_mesh_processing::merge_duplicated_vertices_in_boundary_cycle()` + - `CGAL::Polygon_mesh_processing::merge_duplicated_vertices_in_boundary_cycles()` + Release 4.13 ------------ diff --git a/Kernel_23/doc/Kernel_23/CGAL/Kernel_traits.h b/Kernel_23/doc/Kernel_23/CGAL/Kernel_traits.h index 3f650d01399..7cf0de10c85 100644 --- a/Kernel_23/doc/Kernel_23/CGAL/Kernel_traits.h +++ b/Kernel_23/doc/Kernel_23/CGAL/Kernel_traits.h @@ -7,7 +7,7 @@ namespace CGAL { The class `Kernel_traits` provides access to the kernel model to which the argument type `T` belongs. (Provided `T` belongs to some kernel model.) The default implementation assumes there is a -local type `T::Kernel` referring to the kernel model of `T`. +local type `T::R` referring to the kernel model of `T`. If this type does not exist, a specialization of `Kernel_traits` can be used to provide the desired information. diff --git a/Kernel_23/doc/Kernel_23/Concepts/GeomObjects.h b/Kernel_23/doc/Kernel_23/Concepts/GeomObjects.h index 6feb89c5318..01fff5476ca 100644 --- a/Kernel_23/doc/Kernel_23/Concepts/GeomObjects.h +++ b/Kernel_23/doc/Kernel_23/Concepts/GeomObjects.h @@ -722,6 +722,8 @@ public: \cgalHasModel `CGAL::Vector_2` \sa `Kernel::ComputeDeterminant_2` + \sa `Kernel::ComputeScalarProduct_2` + \sa `Kernel::ComputeSquaredLength_2` \sa `Kernel::ComputeX_2` \sa `Kernel::ComputeY_2` \sa `Kernel::ComputeHx_2` @@ -754,7 +756,10 @@ A type representing vectors in three dimensions. \cgalHasModel `CGAL::Vector_3` -\sa `Kernel::ComputeDeterminant_3` +\sa `Kernel::CompareDihedralAngle_3` +\sa `Kernel::ComputeDeterminant_3` +\sa `Kernel::ComputeScalarProduct_3` +\sa `Kernel::ComputeSquaredLength_3` \sa `Kernel::ComputeX_3` \sa `Kernel::ComputeY_3` \sa `Kernel::ComputeZ_3` diff --git a/Minkowski_sum_2/test/Minkowski_sum_2/cgal_test_with_cmake b/Minkowski_sum_2/test/Minkowski_sum_2/cgal_test_with_cmake index 5206be1c0cb..a69891eaba2 100755 --- a/Minkowski_sum_2/test/Minkowski_sum_2/cgal_test_with_cmake +++ b/Minkowski_sum_2/test/Minkowski_sum_2/cgal_test_with_cmake @@ -26,7 +26,7 @@ configure() { echo "Configuring... " - if eval 'cmake --no-warn-unused-cli "$CMAKE_GENERATOR" -DRUNNING_CGAL_AUTO_TEST=TRUE \ + if eval 'cmake --no-warn-unused-cli ${INIT_FILE:+"-C${INIT_FILE}"} "$CMAKE_GENERATOR" -DRUNNING_CGAL_AUTO_TEST=TRUE \ -DCGAL_DIR="$CGAL_DIR" \ .' ; then diff --git a/Number_types/include/CGAL/Mpzf.h b/Number_types/include/CGAL/Mpzf.h index 348cb8c81ba..bcf2c480c87 100644 --- a/Number_types/include/CGAL/Mpzf.h +++ b/Number_types/include/CGAL/Mpzf.h @@ -302,7 +302,13 @@ struct Mpzf { data()[-1] = mini; } void clear(){ - while(*--data()==0); // in case we skipped final zeroes + // while(*--data()==0); + // This line gave a misscompilation by Intel Compiler 2019 + // (19.0.0.117). I replaced it by the following two lines: + // -- Laurent Rineau, sept. 2018 + --data(); + while(*data()==0) { --data(); } // in case we skipped final zeroes + #ifdef CGAL_MPZF_USE_CACHE if (data() == cache) return; #endif diff --git a/Operations_on_polyhedra/include/CGAL/Triangle_accessor_with_ppmap_3.h b/Operations_on_polyhedra/include/CGAL/Triangle_accessor_with_ppmap_3.h deleted file mode 100644 index 0b4fd781f9e..00000000000 --- a/Operations_on_polyhedra/include/CGAL/Triangle_accessor_with_ppmap_3.h +++ /dev/null @@ -1,72 +0,0 @@ -// Copyright (c) 2011 GeometryFactory (France). -// All rights reserved. -// -// This file is part of CGAL (www.cgal.org). -// You can redistribute it and/or modify it under the terms of the GNU -// General Public License as published by the Free Software Foundation, -// either version 3 of the License, or (at your option) any later version. -// -// Licensees holding a valid commercial license may use this file in -// accordance with the commercial license agreement provided with the software. -// -// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE -// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. -// -// $URL$ -// $Id$ -// SPDX-License-Identifier: GPL-3.0+ -// -// -// Author(s) : Sebastien Loriot - - -#ifndef CGAL_TRIANGLE_ACCESSOR_WITH_PPMAP_3_H -#define CGAL_TRIANGLE_ACCESSOR_WITH_PPMAP_3_H - -#include - - -#include -#include - -namespace CGAL{ - -template < class Polyhedron, class PolyhedronPointPMap> -struct Triangle_accessor_with_ppmap_3 -{ - typedef PolyhedronPointPMap Ppmap; - typedef typename boost::property_traits< Ppmap >::value_type Point_3; - typedef typename CGAL::Kernel_traits::Kernel Kernel; - typedef typename Kernel::Triangle_3 Triangle_3; - typedef typename Polyhedron::Facet_const_iterator Triangle_iterator; - typedef typename Polyhedron::Facet_const_handle Triangle_handle; - - PolyhedronPointPMap ppmap; - - Triangle_accessor_with_ppmap_3(){} - - Triangle_accessor_with_ppmap_3(PolyhedronPointPMap ppmap):ppmap(ppmap) {} - - Triangle_iterator triangles_begin(const Polyhedron& p) const - { - return p.facets_begin(); - } - - Triangle_iterator triangles_end(const Polyhedron& p) const - { - return p.facets_end(); - } - - Triangle_3 triangle(const Triangle_handle& handle) const - { - typedef typename Kernel::Point_3 Point; - const Point& a = get(ppmap, handle->halfedge()->vertex()); - const Point& b = get(ppmap, handle->halfedge()->next()->vertex()); - const Point& c = get(ppmap, handle->halfedge()->next()->next()->vertex()); - return Triangle_3(a,b,c); - } -}; - -} // end of namespace CGAL - -#endif // CGAL_TRIANGLE_ACCESSOR_WITH_PPMAP_3_H diff --git a/Operations_on_polyhedra/include/CGAL/corefinement_operations.h b/Operations_on_polyhedra/include/CGAL/corefinement_operations.h deleted file mode 100644 index 80d1c7d7bbe..00000000000 --- a/Operations_on_polyhedra/include/CGAL/corefinement_operations.h +++ /dev/null @@ -1,484 +0,0 @@ -// Copyright (c) 2011 GeometryFactory (France). -// All rights reserved. -// -// This file is part of CGAL (www.cgal.org). -// You can redistribute it and/or modify it under the terms of the GNU -// General Public License as published by the Free Software Foundation, -// either version 3 of the License, or (at your option) any later version. -// -// Licensees holding a valid commercial license may use this file in -// accordance with the commercial license agreement provided with the software. -// -// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE -// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. -// -// $URL$ -// $Id$ -// SPDX-License-Identifier: GPL-3.0+ -// -// -// Author(s) : Sebastien Loriot - -#ifndef CGAL_COREFINEMENT_OPERATIONS_H -#define CGAL_COREFINEMENT_OPERATIONS_H - -#include - - -#include -#include -#include - -namespace CGAL{ -/** \cond */ -namespace internal{ - -template -class Import_volume_as_polyhedron : public CGAL::Modifier_base { - typedef typename HDS::Halfedge_handle Halfedge_handle; - typedef typename HDS::Vertex_handle Vertex_handle; - typedef typename HDS::Face_handle Face_handle; - typedef typename HDS::Vertex Vertex; - typedef typename HDS::Halfedge Halfedge; - typedef typename HDS::Face Face; - - //data members - Face_handle current_face; - std::vector< typename Vertex::Point > points; - std::size_t nb_edges; - std::vector > faces; - -public: - - //to import each piece individually - template - Import_volume_as_polyhedron(const Combinatorial_map_3& map,typename Combinatorial_map_3::Dart_const_handle dart):nb_edges(0) - { - typedef Combinatorial_map_3 CMap; - typedef std::map Vertex_map; - Vertex_map vertex_map; - unsigned int index=0; - //recover all the vertices in the current volumeiterator over all the point - //map the vertex to the index of the point in the vector - for (typename CMap::template One_dart_per_incident_cell_const_range<0,3>::const_iterator - it=map.template one_dart_per_incident_cell<0,3>(dart).begin(), - itend=map.template one_dart_per_incident_cell<0,3>(dart).end(); - it!=itend; ++it) - { - points.push_back(map.template attribute<0>(it)->point()); - vertex_map.insert(std::make_pair(&map.template attribute<0>(it)->point(),index++)); - } - - //count the number of edges - nb_edges+=map.template one_dart_per_incident_cell<1,3>(dart).size(); - - //recover one dart per face - for (typename CMap::template One_dart_per_incident_cell_const_range<2,3>::const_iterator - it=map.template one_dart_per_incident_cell<2,3>(dart).begin(), - itend=map.template one_dart_per_incident_cell<2,3>(dart).end(); - it!=itend; ++it) - { - //warning: the convention used into a polyhedron is that the normal - // of a triangle indicates the outside of the object; thus - // we need to reverse the orientation of the faces of the - // combinatorial map. - unsigned int i=vertex_map[&map.template attribute<0>(it)->point()]; - unsigned int j=vertex_map[&map.template attribute<0>(map.beta(it, 0))->point()]; - unsigned int k=vertex_map[&map.template attribute<0>(map.beta(it, 1))->point()]; - faces.push_back(CGAL::cpp11::make_tuple(i,j,k)); - } - } - - //for intersection and symetric difference - template - Import_volume_as_polyhedron(const Combinatorial_map_3& map, - Iterator dart_begin, - Iterator dart_end):nb_edges(0) - { - typedef Combinatorial_map_3 CMap; - typedef std::map Vertex_map; - Vertex_map vertex_map; - unsigned int index=0; - - for (Iterator it=dart_begin;it!=dart_end;++it) - { - typename Combinatorial_map_3::Dart_const_handle dart=*it; - //recover all the vertices in the current volumeiterator over all the point - //map the vertex to the index of the point in the vector - for (typename CMap::template One_dart_per_incident_cell_const_range<0,3>::const_iterator - it=map.template one_dart_per_incident_cell<0,3>(dart).begin(), - itend=map.template one_dart_per_incident_cell<0,3>(dart).end(); - it!=itend; ++it) - { - if ( vertex_map.insert(std::make_pair(&map.template attribute<0>(it)->point(),index)).second ) - { - points.push_back(map.template attribute<0>(it)->point()); - ++index; - } - } - - //count the number of edges - nb_edges+=map.template one_dart_per_incident_cell<1,3>(dart).size(); - - //recover one dart per face - for (typename CMap::template One_dart_per_incident_cell_const_range<2,3>::const_iterator - it=map.template one_dart_per_incident_cell<2,3>(dart).begin(), - itend=map.template one_dart_per_incident_cell<2,3>(dart).end(); - it!=itend; ++it) - { - //warning: the convention used into a polyhedron is that the normal - // of a triangle indicates the outside of the object; thus - // we need to reverse the orientation of the faces of the - // combinatorial map. - unsigned int i=vertex_map[&map.template attribute<0>(it)->point()]; - unsigned int j=vertex_map[&map.template attribute<0>(map.beta(it, 0))->point()]; - unsigned int k=vertex_map[&map.template attribute<0>(map.beta(it, 1))->point()]; - faces.push_back(CGAL::cpp11::make_tuple(i,j,k)); - } - } - } - - //for union : use the inverse of the complementary - template - Import_volume_as_polyhedron(const Combinatorial_map_3& map, - Iterator dart_begin, - Iterator dart_end,bool):nb_edges(0) - { - typedef Combinatorial_map_3 CMap; - typedef std::map Vertex_map; - Vertex_map vertex_map; - unsigned int index=0; - - for (Iterator it=dart_begin;it!=dart_end;++it) - { - typename Combinatorial_map_3::Dart_const_handle dart=*it; - //recover all the vertices in the current volumeiterator over all the point - //map the vertex to the index of the point in the vector - for (typename CMap::template One_dart_per_incident_cell_const_range<0,3>::const_iterator - it=map.template one_dart_per_incident_cell<0,3>(dart).begin(), - itend=map.template one_dart_per_incident_cell<0,3>(dart).end(); - it!=itend; ++it) - { - if (vertex_map.insert(std::make_pair(&map.template attribute<0>(it)->point(),index)).second ) - { - points.push_back(map.template attribute<0>(it)->point()); - ++index; - } - } - - //count the number of edges - nb_edges+=map.template one_dart_per_incident_cell<1,3>(dart).size(); - - //recover one dart per face - for (typename CMap::template One_dart_per_incident_cell_const_range<2,3>::const_iterator - it=map.template one_dart_per_incident_cell<2,3>(dart).begin(), - itend=map.template one_dart_per_incident_cell<2,3>(dart).end(); - it!=itend; ++it) - { - //warning: the convention used into a polyhedron is that the normal - // of a triangle indicates the outside of the object; thus - // we need to reverse the orientation of the faces of the - // combinatorial map. Since to get the complementary we - // also need to reverse the orientation, we finally do - // not change it. - unsigned int i=vertex_map[&map.template attribute<0>(it)->point()]; - unsigned int j=vertex_map[&map.template attribute<0>(map.beta(it, 1))->point()]; - unsigned int k=vertex_map[&map.template attribute<0>(map.beta(it, 0))->point()]; - faces.push_back(CGAL::cpp11::make_tuple(i,j,k)); - } - } - } - - - void operator()( HDS& hds) - { - CGAL::Polyhedron_incremental_builder_3 B(hds, true); - B.begin_surface( points.size(), faces.size(),2*nb_edges); - - //insert vertices - for (typename std::vector::iterator it=points.begin();it!=points.end();++it) - B.add_vertex(*it); - - //create faces - for (std::vector >::iterator it=faces.begin();it!=faces.end();++it) - { - B.begin_facet(); - B.add_vertex_to_facet(CGAL::cpp11::get<0>(*it)); - B.add_vertex_to_facet(CGAL::cpp11::get<1>(*it)); - B.add_vertex_to_facet(CGAL::cpp11::get<2>(*it)); - B.end_facet(); - } - B.end_surface(); - } -}; - -} -/** \endcond */ - -/*! \class Polyhedron_corefinement corefinement_operations.h CGAL/corefinement_operations.h - * Function object to compute the decomposition of the space induced by two polyhedra. - * @tparam Polyhedron must be an instantiation of CGAL::Polyhedron_3. - * @tparam Kernel must be a CGAL Kernel compatible with the underlying kernel of Polyhedron. - * @tparam Output_polyhedron is a polyhedron type used as output. `Kernel` must be compatible with the underlying kernel of `Output_polyhedron`. - */ -template -class Polyhedron_corefinement -{ - typedef internal::Import_volume_as_polyhedron Volume_import_modifier; - -public: - /** Enumeration of the different feature tags, listing all kind of space decomposition the functor can compute given two input polyhedra P and Q.*/ - enum Boolean_operation_tag - { - Join_tag=1, /*!< the union of P and Q. */ - Intersection_tag=2, /*!< the intersection of P and Q. */ - P_minus_Q_tag=4, /*!< P minus Q. */ - Q_minus_P_tag=8, /*!< Q minus P. */ - Parts_of_P_tag=32, /*!< decomposition of the volume bounded by P induced by Q. */ - Parts_of_Q_tag=64, /*!< decomposition of the volume bounded by Q induced by P. */ - Decomposition_tag=16 /*!< Both decompositions of P and Q. */ - }; - - /** - * This computes different polyhedra according to the value of features. - * Each input polyhedron is expected to bound a volume: the volume is bounded by the surface polyhedron with facet - * normals pointing outside the volume. Each facet is supposed to be counterclockwise oriented, that is its vertex - * sequence (induced by halfedges) is seen counterclockwise from the side of the facet pointed by its normal. If one or - * both polyhedra are not closed, the algorithm will end up correctly if each intersection polyline separates each surface - * in two components. In that case for each triangle of each surface path boundary, the interior of the volume is considered - * to be on the side opposite of that pointed by it normals (but the orientation must be consistent on each patch). - * the surface the volume bounded by an open surface is considered to be an infinite volume above - * or below the surface (the side not pointed by normal vectors). - * @tparam Polyline_output_iterator must be an output iterator of std::vector. - * @tparam Polyhedron_ptr_and_type_output_iterator an output iterator of std::pair. - * @param P is the first input triangulated polyhedron. Note that a reference is taken and P will be updated to contain the 1D intersection between the two surfaces P and Q. - * @param Q is the second input triangulated polyhedron. Note that a reference is taken and Q will be updated to contain the 1D intersection between the two surfaces P and Q. - * @param polyline_output is an output iterator that collects intersection polylines between P and Q. - * @param poly_output is an output iterator that collects output polyhedra. Note that each polyhedron is allocated within this function (thus must be explicitly deleted when no longer used). The integer is a feature tag corresponding to the volume represented by the polyhedron of the pair. - * @param features is an integer indicating what polyhedra the function must compute. If several kind of polyhedra are expected, feature tags must be combined by |. For example if features = Polyhedron_corefinement::Join_tag | Polyhedron_corefinement::Intersection_tag, then poly_output will collect two polyhedra, the union and the intersection of P and Q. - */ - template - void operator()( Polyhedron& P, Polyhedron& Q, - Polyline_output_iterator polyline_output, - Polyhedron_ptr_and_type_output_iterator poly_output, - int features) const - { - typedef CGAL::Corefinement::Combinatorial_map_output_builder Output_builder; - Output_builder output_builder; - typedef CGAL::Node_visitor_refine_polyhedra Split_visitor; - Split_visitor visitor(output_builder); - CGAL::Intersection_of_Polyhedra_3 polyline_intersections(visitor); - - polyline_intersections(P, Q, polyline_output); - - typedef typename Output_builder::Combinatorial_map_3 Combinatorial_map_3; - typedef typename Output_builder::Volume_info Volume_info; - typedef typename Combinatorial_map_3::Dart_const_handle Dart_const_handle; - - const Combinatorial_map_3& final_map=output_builder.combinatorial_map(); - - typename Combinatorial_map_3::template One_dart_per_cell_const_range<3> cell_range=final_map.template one_dart_per_cell<3>(); - - std::list intersection; - std::list union_; - std::list P_minus_Q; - std::list Q_minus_P; - - for (typename Combinatorial_map_3::template One_dart_per_cell_const_range<3>::const_iterator - it = cell_range.begin(), it_end= cell_range.end(); - it!= it_end; - ++it ) - { - - const Volume_info& info=final_map.template attribute<3>(it)->info(); - std::size_t inside_size=info.inside.size(); - std::size_t outside_size=info.outside.size(); - - if ( inside_size + outside_size != 2){ - std::cerr << "Error: One volume cannot be represented using a polyhedron. Aborted.\n"; - break; - } - - switch (outside_size) - { - case 2: - if (features & Join_tag) union_.push_back(it); - break; - case 0: - if (features & Intersection_tag) intersection.push_back(it); - break; - default: - if ( *info.inside.begin() == &P ) - { if (features & P_minus_Q_tag) P_minus_Q.push_back(it); } - else - { if (features & Q_minus_P_tag) Q_minus_P.push_back(it); } - } - - if ( features&Decomposition_tag ) - { - Volume_import_modifier modifier(final_map,it); - Output_polyhedron* new_poly=new Output_polyhedron(); - new_poly->delegate(modifier); - *poly_output++ = std::make_pair( new_poly,static_cast(Decomposition_tag) ); - } - - if ( features&Parts_of_P_tag && info.inside.find(&P)!=info.inside.end() ) - { - Volume_import_modifier modifier(final_map,it); - Output_polyhedron* new_poly=new Output_polyhedron(); - new_poly->delegate(modifier); - *poly_output++ = std::make_pair( new_poly,static_cast(Parts_of_P_tag) ); - } - - if ( features&Parts_of_Q_tag && info.inside.find(&Q)!=info.inside.end() ) - { - Volume_import_modifier modifier(final_map,it); - Output_polyhedron* new_poly=new Output_polyhedron(); - new_poly->delegate(modifier); - *poly_output++ = std::make_pair( new_poly,static_cast(Parts_of_Q_tag) ); - } - } - - if (!intersection.empty()) - { - Volume_import_modifier modifier(final_map,intersection.begin(),intersection.end()); - Output_polyhedron* new_poly=new Output_polyhedron(); - new_poly->delegate(modifier); - *poly_output++=std::make_pair( new_poly,static_cast(Intersection_tag) ); - } - - if (!P_minus_Q.empty()) - { - Volume_import_modifier modifier(final_map,P_minus_Q.begin(),P_minus_Q.end()); - Output_polyhedron* new_poly=new Output_polyhedron(); - new_poly->delegate(modifier); - *poly_output++=std::make_pair( new_poly,static_cast(P_minus_Q_tag) ); - } - - if (!Q_minus_P.empty()) - { - Volume_import_modifier modifier(final_map,Q_minus_P.begin(),Q_minus_P.end()); - Output_polyhedron* new_poly=new Output_polyhedron(); - new_poly->delegate(modifier); - *poly_output++=std::make_pair( new_poly,static_cast(Q_minus_P_tag) ); - } - - if (!union_.empty()) - { - Volume_import_modifier modifier(final_map,union_.begin(),union_.end(),true); - Output_polyhedron* new_poly=new Output_polyhedron(); - new_poly->delegate(modifier); - *poly_output++=std::make_pair( new_poly,static_cast(Join_tag) ); - } - } - /** - * This updates P according to the value of features. - * Each input polyhedron is expected to bound a volume: the volume is bounded by the surface polyhedron with facet - * normals pointing outside the volume. Each facet is supposed to be counterclockwise oriented, that is its vertex - * sequence (induced by halfedges) is seen counterclockwise from the side of the facet pointed by its normal. If one or - * both polyhedra are not closed, the algorithm will end up correctly if each intersection polyline separates each surface - * in two components. In that case for each triangle of each surface path boundary, the interior of the volume is considered - * to be on the side opposite of that pointed by it normals (but the orientation must be consistent on each patch). - * the surface the volume bounded by an open surface is considered to be an infinite volume above - * or below the surface (the side not pointed by normal vectors). - * @tparam Polyline_output_iterator must be an output iterator of std::vector. - * @param P is the first input triangulated polyhedron. Note that a reference is taken and P will be updated to contain the 1D intersection between the two surfaces P and Q. - * @param Q is the first input triangulated polyhedron. Note that a reference is taken and Q will be updated to contain the 1D intersection between the two surfaces P and Q. - * @param polyline_output is an output iterator that collects intersection polylines between P and Q. - * @param features is either Join_tag, Intersection_tag, P_minus_Q_tag or Q_minus_P_tag - */ - template - void operator()( Polyhedron& P, Polyhedron& Q, - Polyline_output_iterator polyline_output, - Boolean_operation_tag features) const - { - typedef CGAL::Node_visitor_refine_polyhedra Split_visitor; - Split_visitor visitor; - CGAL::Intersection_of_Polyhedra_3 polyline_intersections(visitor); - - polyline_intersections(P, Q, polyline_output); - - typedef typename Split_visitor::Combinatorial_map_3 Combinatorial_map_3; - typedef typename Split_visitor::Volume_info Volume_info; - typedef typename Combinatorial_map_3::Dart_const_handle Dart_const_handle; - - const typename Split_visitor::Combinatorial_map_3& final_map=visitor.combinatorial_map(); - - typename Combinatorial_map_3::template One_dart_per_cell_const_range<3> cell_range=final_map.template one_dart_per_cell<3>(); - - std::list darts; - - for (typename Combinatorial_map_3::template One_dart_per_cell_const_range<3>::const_iterator - it = cell_range.begin(), it_end= cell_range.end(); - it!= it_end; - ++it ) - { - - const Volume_info& info=it->template attribute<3>()->info(); - std::size_t inside_size=info.inside.size(); - std::size_t outside_size=info.outside.size(); - - if ( inside_size + outside_size != 2){ - std::cerr << "Error: One volume cannot be represented using a polyhedron. Aborted.\n"; - break; - } - - switch (outside_size) - { - case 2: - if ( features==Join_tag ) darts.push_back(it); - break; - case 0: - if ( features==Intersection_tag ) darts.push_back(it); - break; - default: - if ( *info.inside.begin() == &P ) - { if (features == P_minus_Q_tag) darts.push_back(it); } - else - { if (features == Q_minus_P_tag) darts.push_back(it); } - } - } - - P.clear(); - - if (!darts.empty()) - { - Volume_import_modifier modifier= - features==Join_tag? - Volume_import_modifier(final_map,darts.begin(),darts.end(),true) - : Volume_import_modifier(final_map,darts.begin(),darts.end()); - P.delegate(modifier); - } - } - - /** \cond */ - static std::string get_type_str(const std::string& Pname,const std::string& Qname,int i) - { - switch (i) - { - case Join_tag: - return Pname+std::string("_union_")+Qname; - case P_minus_Q_tag: - return Pname+std::string("_minus_")+Qname; - case Q_minus_P_tag: - return Qname+std::string("_minus_")+Pname; - case Intersection_tag: - return Pname+std::string("_inter_")+Qname; - case Decomposition_tag: - return std::string("Decomposition"); - } - return std::string("Unknow"); - } - /** \endcond */ -}; - - - - -} - -#endif // CGAL_COREFINEMENT_OPERATIONS_H diff --git a/Operations_on_polyhedra/include/CGAL/internal/corefinement/Combinatorial_map_for_corefinement.h b/Operations_on_polyhedra/include/CGAL/internal/corefinement/Combinatorial_map_for_corefinement.h deleted file mode 100644 index 396da390ead..00000000000 --- a/Operations_on_polyhedra/include/CGAL/internal/corefinement/Combinatorial_map_for_corefinement.h +++ /dev/null @@ -1,115 +0,0 @@ -// Copyright (c) 2012 GeometryFactory Sarl (France) -// All rights reserved. -// -// This file is part of CGAL (www.cgal.org). -// You can redistribute it and/or modify it under the terms of the GNU -// General Public License as published by the Free Software Foundation, -// either version 3 of the License, or (at your option) any later version. -// -// Licensees holding a valid commercial license may use this file in -// accordance with the commercial license agreement provided with the software. -// -// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE -// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. -// -// $URL$ -// $Id$ -// SPDX-License-Identifier: GPL-3.0+ -// -// -// Author(s) : Sebastien Loriot - -#ifndef CGAL_INTERNAL_COMBINATORIAL_MAP_FOR_COREFINEMENT_H -#define CGAL_INTERNAL_COMBINATORIAL_MAP_FOR_COREFINEMENT_H - -#include - - -#include -#include -#include -#include - -namespace CGAL{ - namespace internal_IOP{ - -template -struct Volume_info{ - std::set outside; - std::set inside; - bool is_empty; - Volume_info():is_empty(false){} -}; - -struct Volume_on_merge -{ - template - void operator() (Attribute& a1,const Attribute& a2) const - { - CGAL_assertion(!a1.info().is_empty && !a2.info().is_empty); - std::copy(a2.info().outside.begin(),a2.info().outside.end(),std::inserter(a1.info().outside,a1.info().outside.begin())); - std::copy(a2.info().inside.begin(),a2.info().inside.end(),std::inserter(a1.info().inside,a1.info().inside.begin())); - } -}; - -#ifndef NDEBUG -struct Point_on_merge -{ - template - void operator() (Attribute& a1,const Attribute& a2) const - { - CGAL_assertion(a1.point()==a2.point() ); - CGAL_USE(a1); CGAL_USE(a2); - } -}; -#endif - - -template < class Refs, class T, class Point_, - class Functor_on_merge_=CGAL::Null_functor, - class Functor_on_split_=CGAL::Null_functor > -class My_cell_attribute_with_point : - public CGAL::Cell_attribute_without_info -{ - Point_ mpoint; -public: - typedef Point_ Point; - typedef Functor_on_merge_ Functor_on_merge; - typedef Functor_on_split_ Functor_on_split; - - My_cell_attribute_with_point(){} - My_cell_attribute_with_point(const Point& apoint) : mpoint(apoint) {} - Point& point() { return mpoint; } - const Point& point() const { return mpoint; } - -}; - -template -struct Item_with_points_and_volume_info -{ - static const unsigned int dimension = 3; - static const unsigned int NB_MARKS = 32; - - template - struct Dart_wrapper - { - typedef Traits_ Traits; - typedef typename Traits::FT FT; - typedef typename Traits::Point_3 Point; - typedef typename Traits::Vector_3 Vector; - #ifndef NDEBUG - typedef My_cell_attribute_with_point Vertex_attribute; - #else - typedef My_cell_attribute_with_point Vertex_attribute; - #endif - typedef CGAL::Cell_attribute,CGAL::Tag_true,Volume_on_merge > Volume_attribute; - typedef CGAL::cpp11::tuple< Vertex_attribute, - void, - void, - Volume_attribute> Attributes; - }; -}; - -} } //namespace CGAL::internal_IOP - -#endif //CGAL_INTERNAL_COMBINATORIAL_MAP_FOR_COREFINEMENT_H diff --git a/Operations_on_polyhedra/include/CGAL/internal/corefinement/Combinatorial_map_output_builder.h b/Operations_on_polyhedra/include/CGAL/internal/corefinement/Combinatorial_map_output_builder.h deleted file mode 100644 index 944236e98c2..00000000000 --- a/Operations_on_polyhedra/include/CGAL/internal/corefinement/Combinatorial_map_output_builder.h +++ /dev/null @@ -1,1378 +0,0 @@ -// Copyright (c) 2011 GeometryFactory (France). -// All rights reserved. -// -// This file is part of CGAL (www.cgal.org). -// You can redistribute it and/or modify it under the terms of the GNU -// General Public License as published by the Free Software Foundation, -// either version 3 of the License, or (at your option) any later version. -// -// Licensees holding a valid commercial license may use this file in -// accordance with the commercial license agreement provided with the software. -// -// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE -// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. -// -// $URL$ -// $Id$ -// SPDX-License-Identifier: GPL-3.0+ -// -// -// Author(s) : Sebastien Loriot - -#ifndef CGAL_INTERNAL_COREFINEMENT_COMBINATORIAL_MAP_OUTPUT_BUILDER_H -#define CGAL_INTERNAL_COREFINEMENT_COMBINATORIAL_MAP_OUTPUT_BUILDER_H - -#include - - -#include -#include -#include -#include -#include -#include -#include - -/// \todo right now patches made of coplanar patches are handled by considering -/// each coplanar triangle while it should be sufficient to have one -/// procedure for all coplanar triangles of the patch together with -/// a sew-handling of the boundary of the patch. - -namespace CGAL { - -namespace internal_IOP { -//turn around the target vertex of dart to find a marked dart -template -boost::optional -next_marked_dart_around_target_vertex( - Combinatorial_map_3& final_map, - typename Combinatorial_map_3::Dart_handle dart, - std::size_t mark_index) -{ - CGAL_precondition(final_map.is_marked(dart,mark_index)); - typename Combinatorial_map_3::Dart_handle next=final_map.beta(dart,1); - while ( ! final_map.is_marked(next,mark_index) ) { - if (final_map.is_free(next,2) )//we reach a boundary - return boost::optional(); - next=final_map.beta(next,2,1); - } - if (next == dart) //no new dart have been found - return boost::optional(); - CGAL_precondition(&final_map.template attribute<0>(final_map.beta(dart,1))->point() == - &final_map.template attribute<0>(next)->point()); - return boost::optional (next); -} - -//turn around the target vertex of dart to find a marked dart -//with expected_target as target vertex -template -typename Combinatorial_map_3::Dart_handle -get_next_marked_dart_around_target_vertex( - Combinatorial_map_3& final_map, - typename Combinatorial_map_3::Dart_handle dart, - std::size_t mark_index) -{ - CGAL_precondition(final_map.is_marked(dart,mark_index)); - typename Combinatorial_map_3::Dart_handle next=final_map.beta(dart,1); - while ( !final_map.is_marked(next,mark_index) ) { - CGAL_assertion( !final_map.is_free(next,2) ); - next=final_map.beta(next,2,1); - CGAL_assertion(next != dart); - } - CGAL_precondition(&final_map.template attribute<0>(final_map.beta(dart,1))->point() == - &final_map.template attribute<0>(next)->point()); - return next; -} - -//turn around the source vertex of dart to find a marked dart -//with expected_source as source vertex -template -typename Combinatorial_map_3::Dart_handle -get_next_marked_dart_around_source_vertex( - Combinatorial_map_3& final_map, - typename Combinatorial_map_3::Dart_handle dart, - std::size_t mark_index) -{ - CGAL_precondition(final_map.is_marked(dart,mark_index)); - typename Combinatorial_map_3::Dart_handle next=final_map.beta(dart,0); - while ( ! final_map.is_marked(next,mark_index) ) { - CGAL_assertion( !final_map.is_free(next,2) ); - next=final_map.beta(next,2,0); - CGAL_assertion(next != dart); - } - CGAL_precondition(&final_map.template attribute<0>(dart)->point() == - &final_map.template attribute<0>(final_map.beta(next,1))->point()); - return next; -} - -//given two marked darts, this function links these two darts with beta<2> -//but in addition it follows the marked darts connected to the same vertex -//(there should be only one) to connect them all together -//( this function is a kind of zipper ;) ) -template -void sew_2_marked_darts( Combinatorial_map_3& final_map, - typename Combinatorial_map_3::Dart_handle dart_1, - typename Combinatorial_map_3::Dart_handle dart_2, - std::size_t mark_index, - const Nodes_vector& nodes, - const std::pair& indices, - const std::pair& polyline_info) -{ - CGAL_precondition( final_map.is_free(dart_1, 2) ); - CGAL_precondition( final_map.is_free(dart_2, 2) ); - CGAL_precondition( final_map.is_marked(dart_1,mark_index) ); - CGAL_precondition( final_map.is_marked(dart_2,mark_index) ); - CGAL_precondition( final_map.template attribute<0>(dart_1)->point() == - final_map.template attribute<0>(final_map.beta(dart_2,1))->point() ); - CGAL_precondition( final_map.template attribute<0>(final_map.beta(dart_1,1))->point() == - final_map.template attribute<0>(dart_2)->point() ); - - int src_index = ( ( indices.first < indices.second) == polyline_info.first ) - ? indices.second:indices.first; - - if ( final_map.template attribute<0>(dart_1)->point() != nodes[ src_index ] ) - std::swap(dart_1,dart_2); - - int nb_segs=polyline_info.second+1,k=1; - - do { - CGAL_precondition( final_map.template is_sewable<2>(dart_1,dart_2) ); - final_map.template sew<2>(dart_1,dart_2); - - if (k==nb_segs) break; - - dart_1 = get_next_marked_dart_around_target_vertex( - final_map, dart_1, mark_index); - dart_2 = get_next_marked_dart_around_source_vertex( - final_map, dart_2, mark_index); - } while(++k); -} - -//not_top and not_down are two darts from volumes that get merged with an -//existing other one because of a set of identical coplanar triangles. -//top and down is the dart of the volumes "replacing" that of not_top and -//not down respectively, The function is considering all triangles that -//are bounded by a cycle of marked edges. The volume not_top and not_down -//are part of are those that will disappear at the end of the main algorithm. -template -void sew_3_marked_darts( Combinatorial_map_3& final_map, - typename Combinatorial_map_3::Dart_handle not_top, - typename Combinatorial_map_3::Dart_handle not_down, - typename Combinatorial_map_3::Dart_handle top, - typename Combinatorial_map_3::Dart_handle down, - std::size_t mark_index, - std::set& - darts_to_remove -){ - typedef boost::optional - O_Dart_handle; - - if ( final_map.template attribute<3>(not_top)->info().is_empty ) { - CGAL_assertion(final_map.template attribute<3>(not_down)->info().is_empty); - return; - } - - CGAL_assertion(!final_map.template attribute<3>(not_down)->info().is_empty); - - //merge attribute of the two volumes: - internal_IOP::Volume_on_merge merge_attributes; - merge_attributes(*final_map.template attribute<3>(top), - *final_map.template attribute<3>(not_top)); - merge_attributes(*final_map.template attribute<3>(down), - *final_map.template attribute<3>(not_down)); - - //set volume attributes as empty to avoid double sew_3 - //of the same topological disk of triangles - final_map.template attribute<3>(not_top)->info().is_empty=true; - final_map.template attribute<3>(not_down)->info().is_empty=true; - - CGAL_precondition( final_map.is_marked(not_top,mark_index) - && final_map.is_marked(top,mark_index) ); - CGAL_precondition( final_map.is_marked(not_down,mark_index) - && final_map.is_marked(down,mark_index) ); - CGAL_precondition( final_map.template attribute<0>(not_top)->point() == - final_map.template attribute<0>(final_map.beta(not_down,1))->point() ); - CGAL_precondition( final_map.template attribute<0>(final_map.beta(not_top,1))->point() == - final_map.template attribute<0>(not_down)->point() ); - CGAL_precondition( final_map.template attribute<0>(not_top)->point() == - final_map.template attribute<0>(top)->point() ); - CGAL_precondition( final_map.template attribute<0>(not_down)->point() == - final_map.template attribute<0>(down)->point() ); - - CGAL_assertion( final_map.beta(top,3)==down ); - - //set to be removed the darts of the two no longer used volumes - typename Combinatorial_map_3::Dart_handle start=not_top; - do { - CGAL_assertion(!final_map.is_free(not_top, 3)); - darts_to_remove.insert(not_top); - darts_to_remove.insert(final_map.beta(not_top,1)); - darts_to_remove.insert(final_map.beta(not_top,1,1)); - darts_to_remove.insert(final_map.beta(not_top,3)); - darts_to_remove.insert(final_map.beta(not_top,3,1)); - darts_to_remove.insert(final_map.beta(not_top,3,1,1)); - O_Dart_handle current_1 = - next_marked_dart_around_target_vertex(final_map, not_top, mark_index); - CGAL_precondition(bool(current_1)); - not_top=*current_1; - } while(not_top!=start); -} - -} //end of internal_IOP namespace - -namespace Corefinement -{ - -//import into the combinatorial map facets in the given range. -//they are supposed to be in the same connected component. -//two volume are created (each facets gives two opposite orientation 2-cell in the map) -template -typename Map::Dart_handle import_from_polyhedron_subset( - Map& amap, - Face_iterator faces_begin, - Face_iterator faces_end, - const Non_special_edge_predicate& is_non_special_edge, - Halfedge_to_dart_map_& selected_hedge_to_dart, - std::size_t mark_index, - PolyhedronPointPMap ppmap - ) -{ - typedef typename Polyhedron::Halfedge_const_handle Halfedge_const_handle; - typedef std::map< Halfedge_const_handle, - typename Map::Dart_handle, - internal_IOP::Compare_address > - Halfedge_to_dart_map; - - Halfedge_to_dart_map hedge_to_dart; - typename Map::Dart_handle first_dart = NULL; - // First traversal to build the darts and link them. - for (Face_iterator it_face = faces_begin; it_face != faces_end; ++it_face) { - Halfedge_const_handle start=(*it_face)->halfedge(); - - CGAL_precondition(start->next()!=start); - - Halfedge_const_handle current=start; - typename Map::Dart_handle prev = NULL; - typename Map::Dart_handle first_dart_of_face = NULL; - do { - typename Map::Dart_handle d = amap.create_dart(); - amap.template link_beta<3>(d,amap.create_dart()); //for opposite volume - hedge_to_dart[current] = d; - - if (prev != NULL) { - amap.template link_beta<1>(prev, d); - amap.template link_beta<1>(amap.beta(d,3),amap.beta(prev,3));//for opposite volume - } else { - first_dart_of_face = d; - if (first_dart==NULL) first_dart=d; - } - - if ( is_non_special_edge (current) ) { - if ( !current->is_border_edge() ) { - CGAL_assertion(current != current->opposite()); - typename Halfedge_to_dart_map::iterator it = - hedge_to_dart.find(current->opposite()); - if (it != hedge_to_dart.end()) { - //link the opposites halfedges only when both - //corresponding darts have been created - amap.template link_beta<2>(d, it->second); - amap.template link_beta<2>(amap.beta(d,3), - amap.beta(it->second,3));//for opposite volume - } - } - } else { - typename Halfedge_to_dart_map_::iterator it_hedge_map= - selected_hedge_to_dart.find(current); - //all marked hedges are not the selected one for its polyline - if ( it_hedge_map!=selected_hedge_to_dart.end() ) it_hedge_map->second=d; - //darts d and d->beta(3) are special edges - amap.mark(d,mark_index); - amap.mark(amap.beta(d,3),mark_index); - } - prev = d; - current=current->next(); - } while (current != start); - amap.template link_beta<1>(prev, first_dart_of_face); - amap.template link_beta<1>(amap.beta(first_dart_of_face,3), - amap.beta(prev,3));//for opposite volume - } - - // Second traversal to update the geometry. - // We run one again through the facets of the HDS. - for (Face_iterator it_face = faces_begin; it_face != faces_end; ++it_face) { - Halfedge_const_handle start=(*it_face)->halfedge(); - Halfedge_const_handle current=start; - do { - typename Map::Dart_handle d = - hedge_to_dart[current]; // Get the dart associated to the Halfedge - if (amap.template attribute<0>(d) == NULL) { - amap.template set_attribute<0>(d, - amap.template create_attribute<0>( - get(ppmap, current->opposite()->vertex())) - ); - } - current=current->next(); - } while (current != start); - } - - return first_dart; -} - -template -class Combinatorial_map_output_builder -{ -//Default typedefs - typedef typename Default::Get< - PolyhedronPointPMap_, - Default_polyhedron_ppmap >::type PolyhedronPointPMap; - typedef typename Default::Get< - Kernel_, - typename Kernel_traits< - typename boost::property_traits::value_type >::Kernel - >::type Kernel; -//Polyhedron typedefs - typedef typename Polyhedron::Halfedge_handle Halfedge_handle; - typedef typename Polyhedron::Halfedge_const_handle Halfedge_const_handle; - typedef typename Polyhedron::Vertex_handle Vertex_handle; -//Other typedefs - typedef internal_IOP::Compare_unik_address Cmp_unik_ad; - typedef std::map< std::pair, - std::pair< std::map, - std::pair > > An_edge_per_polyline_map; - typedef std::map Node_to_polyhedron_vertex_map; - typedef std::map Poly_to_map_node; -public: -//Combinatorial map typedefs - typedef internal_IOP::Item_with_points_and_volume_info Items; - typedef CGAL::Combinatorial_map<3,Items> Combinatorial_map_3; - typedef typename Combinatorial_map_3::Dart_handle Dart_handle; - typedef internal_IOP::Volume_info Volume_info; -private: -//Data members - PolyhedronPointPMap ppmap; - boost::shared_ptr final_map_ptr; -private: - template - inline Dart_handle get_associated_dart(Halfedge_handle hedge, - Halfedge_to_dart_map& selected_hedge_to_dart) { - typename Halfedge_to_dart_map::iterator it_saved_dart= - selected_hedge_to_dart.find(hedge); - CGAL_assertion(it_saved_dart!=selected_hedge_to_dart.end()); - return it_saved_dart->second; - } - - //first_hedge defines four volumes, second_hedge only two - //first_poly is not needed as inside/outside volume is update during the merge - //of the sew. Only second_poly is needed - template - void sew_2_three_volumes_case( Halfedge_handle first_hedge, - Halfedge_handle second_hedge, - const std::pair& indices, - const Nodes_vector& nodes, - Border_halfedges_map& border_halfedges, - Halfedge_to_dart_map& selected_hedge_to_dart, - Polyhedron* /*first_poly*/, - Polyhedron* second_poly, - std::size_t mark_index, - std::set& darts_to_remove, - const std::pair& polyline_info) { - bool took_opposite=second_hedge->is_border(); - if (took_opposite) second_hedge=second_hedge->opposite(); - - Vertex_handle P1=first_hedge->opposite()->next()->vertex(); - Vertex_handle P2=first_hedge->next()->vertex(); - // when looking from the side of indices.second, the interior of the first polyhedron is described - // by turning counterclockwise from P1 to P2 - - Vertex_handle Q = second_hedge->next()->vertex(); - - //check if the third point of each triangular face is an original point (stay -1) - //or a intersection point (in that case we need the index of the corresponding node to - //have the exact value of the point) - int index_p1=node_index_of_incident_vertex(first_hedge->opposite()->next(), - border_halfedges); - int index_p2=node_index_of_incident_vertex(first_hedge->next(), - border_halfedges); - int index_q =node_index_of_incident_vertex(second_hedge->next(), - border_halfedges); - - //Recover the dart that will be the start point of the different sewing - // dof_X_outside = dart of face of, meaning the triangle containing the - // point X and part of the volume outside of the corresponding polyhedron - //-----first polyhedron - Dart_handle dof_P1_outside = get_associated_dart(first_hedge->opposite(), - selected_hedge_to_dart); - Dart_handle dof_P2_outside = get_associated_dart(first_hedge, - selected_hedge_to_dart); - //-----second polyhedron - Dart_handle dof_Q_outside = get_associated_dart(second_hedge, - selected_hedge_to_dart); - - if (index_p1!=-1 && index_p1==index_q) { - Dart_handle top=final_map().beta(dof_P1_outside,3), - not_top=took_opposite?final_map().beta(dof_Q_outside,3):dof_Q_outside; - Dart_handle down=dof_P1_outside, - not_down=took_opposite?dof_Q_outside:final_map().beta(dof_Q_outside,3); - - if ( final_map().template attribute<3>(top)->info().is_empty ) - std::swap(not_top,top); - if ( final_map().template attribute<3>(down)->info().is_empty ) - std::swap(not_down,down); - CGAL_assertion( !final_map().template attribute<3>(top)->info().is_empty ); - CGAL_assertion( !final_map().template attribute<3>(down)->info().is_empty ); - - //P1P2 or QP2 - sew_2_marked_darts( final_map(), top, final_map().beta(dof_P2_outside,3), - mark_index, nodes, indices, polyline_info); - //P2Q or P2P1 - sew_2_marked_darts( final_map(),dof_P2_outside, down, - mark_index, nodes, indices, polyline_info); - sew_3_marked_darts( final_map(),not_top, not_down, top, down, mark_index, - darts_to_remove); - - return; - } - - if (index_p2!=-1 && index_p2==index_q) { - Dart_handle top=final_map().beta(dof_P2_outside,3), - not_top=took_opposite?dof_Q_outside:final_map().beta(dof_Q_outside,3); - Dart_handle down=dof_P2_outside, - not_down=took_opposite?final_map().beta(dof_Q_outside,3):dof_Q_outside; - - if ( final_map().template attribute<3>(top)->info().is_empty ) - std::swap(not_top,top); - if ( final_map().template attribute<3>(down)->info().is_empty ) - std::swap(not_down,down); - CGAL_assertion( !final_map().template attribute<3>(top)->info().is_empty ); - CGAL_assertion( !final_map().template attribute<3>(down)->info().is_empty ); - - //P1Q or P1P2 - sew_2_marked_darts( final_map(), final_map().beta(dof_P1_outside,3), top, - mark_index, nodes, indices, polyline_info); - //QP1 or P2P1 - sew_2_marked_darts( final_map(), down, dof_P1_outside, - mark_index, nodes, indices, polyline_info); - sew_3_marked_darts( final_map(), not_top, not_down, top, down, mark_index, - darts_to_remove); - - return; - } - - bool Q_is_between_P1P2 = OOP::sorted_around_edge_filtered(indices.first, - indices.second, - index_p1,index_p2, - index_q,P1,P2,Q, - nodes,ppmap); - - if (Q_is_between_P1P2) { - // poly_first - poly_second = took_opposite?P1Q:QP2 - // poly_second - poly_first = {0} - // poly_first \cap poly_second = took_opposite?QP2:P1Q - // opposite( poly_first U poly_second ) = P2P1 - sew_2_marked_darts( final_map(), - final_map().beta(dof_P1_outside,3), - took_opposite?dof_Q_outside:final_map().beta(dof_Q_outside,3), - mark_index, nodes, indices, polyline_info); //P1Q - sew_2_marked_darts( final_map(), - took_opposite?final_map().beta(dof_Q_outside,3):dof_Q_outside, - final_map().beta(dof_P2_outside,3),mark_index, nodes, indices, - polyline_info); //QP2 - sew_2_marked_darts( final_map(), - dof_P2_outside, dof_P1_outside, mark_index, - nodes, indices, polyline_info); //P2P1 - final_map().template attribute<3>(dof_P1_outside)->info().outside - .insert(second_poly); //update P2P1 outside poly - } else { - // poly_first - poly_second = P1P2 - // poly_second - poly_first = took_opposite?QP1:P2Q - // poly_first \cap poly_second = {0} - // opposite( poly_first U poly_second ) = took_opposite?P2Q:QP1 - sew_2_marked_darts( final_map(), - dof_P2_outside, - took_opposite?dof_Q_outside:final_map().beta(dof_Q_outside,3), - mark_index, nodes, indices, polyline_info); //P2Q - sew_2_marked_darts( final_map(), - took_opposite?final_map().beta(dof_Q_outside,3):dof_Q_outside, - dof_P1_outside,mark_index, nodes, - indices, polyline_info); //QP1 - sew_2_marked_darts( final_map(), - final_map().beta(dof_P1_outside,3), final_map().beta(dof_P2_outside,3), - mark_index, nodes, indices, polyline_info); //P1P2 - final_map().template attribute<3>(final_map().beta(dof_P1_outside,3))->info().outside - .insert(second_poly); //update P1P2 outside poly - } - } - -//first_hedge defines two volumes, second_hedge only two - template - void sew_2_two_volumes_case( Halfedge_handle first_hedge, - Halfedge_handle second_hedge, - Border_halfedges_map& border_halfedges, - Halfedge_to_dart_map& selected_hedge_to_dart, - std::size_t mark_index, - std::set& darts_to_remove, - const Nodes_vector& nodes, - const std::pair& indices, - const std::pair& polyline_info) - { - bool first_took_opposite=first_hedge->is_border(); - if (first_took_opposite) first_hedge=first_hedge->opposite(); - bool second_took_opposite=second_hedge->is_border(); - if (second_took_opposite) second_hedge=second_hedge->opposite(); - - //-----first polyhedron - Dart_handle dof_P_outside = get_associated_dart(first_hedge, - selected_hedge_to_dart); - //-----second polyhedron - Dart_handle dof_Q_outside = get_associated_dart(second_hedge, - selected_hedge_to_dart); - - - - - int index_p =node_index_of_incident_vertex(first_hedge->next(), - border_halfedges); - int index_q =node_index_of_incident_vertex(second_hedge->next(), - border_halfedges); - - if (index_p!=-1 && index_q!=-1 && index_p==index_q) { - Dart_handle top=dof_P_outside, not_top=final_map().beta(dof_Q_outside,3); - Dart_handle down=final_map().beta(dof_P_outside,3), not_down=dof_Q_outside; - - if (first_took_opposite==second_took_opposite) { - top=final_map().beta(dof_P_outside,3); - not_top=final_map().beta(dof_Q_outside,3); - down=dof_P_outside; - not_down=dof_Q_outside; - } - - if ( final_map().template attribute<3>(top)->info().is_empty ) - std::swap(not_top,top); - if ( final_map().template attribute<3>(down)->info().is_empty ) - std::swap(not_down,down); - CGAL_assertion( !final_map().template attribute<3>(top)->info().is_empty ); - CGAL_assertion( !final_map().template attribute<3>(down)->info().is_empty ); - - sew_3_marked_darts( final_map(),not_top,not_down,top,down,mark_index, - darts_to_remove); - - return; - } - - - - //since the edge is shared, the inside of each polyhedron must be on opposite orientation halfedges - if (first_took_opposite==second_took_opposite) { - //sew out with in - sew_2_marked_darts( final_map(),final_map().beta(dof_P_outside,3), dof_Q_outside, - mark_index, nodes, indices, polyline_info); //PQ - sew_2_marked_darts( final_map(),final_map().beta(dof_Q_outside,3), dof_P_outside, - mark_index, nodes, indices, polyline_info); //QP - } else { - //sew in with in - sew_2_marked_darts( final_map(), dof_P_outside, dof_Q_outside, - mark_index, nodes, indices, polyline_info); //PQ - sew_2_marked_darts( final_map(),final_map().beta(dof_Q_outside,3), - final_map().beta(dof_P_outside,3), mark_index, nodes, indices, - polyline_info); //QP - } - } - -//4 volume case with 2 identical volume -//Q2 is supposed to be identical to P2 - template - void sew_2_four_volumes_case_1( Halfedge_handle first_hedge, - Halfedge_handle second_hedge, - const std::pair& indices, - const Nodes_vector& nodes, - int index_p1, int index_p2, int index_q1, - Halfedge_to_dart_map& selected_hedge_to_dart, - std::size_t mark_index, - std::set& darts_to_remove, - const std::pair& polyline_info, - bool swap_in_out_Q=false) { - Vertex_handle P1=first_hedge->opposite()->next()->vertex(); - Vertex_handle P2=first_hedge->next()->vertex(); - // when looking from the side of indices.second, - // the interior of the first polyhedron is described - // by turning counterclockwise from P1 to P2 - Vertex_handle Q1=second_hedge->opposite()->next()->vertex(); - // Vertex_handle Q2=second_hedge->next()->vertex(); - bool Q1_is_between_P1P2 = - OOP::sorted_around_edge_filtered( indices.first, indices.second, index_p1, - index_p2, index_q1, P1, P2, Q1, nodes, ppmap); - - - //Recover the dart that will be the start point of the different sewing - // dof_X_outside = dart of face of, meaning the triangle containing the - // point X and part of the volume outside of the corresponding polyhedron - //-----first polyhedron - Dart_handle dof_P1_outside = get_associated_dart(first_hedge->opposite(), - selected_hedge_to_dart); - Dart_handle dof_P2_outside = get_associated_dart(first_hedge, - selected_hedge_to_dart); - //-----second polyhedron - Dart_handle dof_Q1_outside = get_associated_dart(second_hedge->opposite(), - selected_hedge_to_dart); - Dart_handle dof_Q2_outside = get_associated_dart(second_hedge, - selected_hedge_to_dart); - - if( swap_in_out_Q ) { - dof_Q1_outside=final_map().beta(dof_Q1_outside,3); - dof_Q2_outside=final_map().beta(dof_Q2_outside,3); - } - - if (Q1_is_between_P1P2) { - Dart_handle top=final_map().beta(dof_Q2_outside,3), not_top=final_map().beta(dof_P2_outside,3); - Dart_handle down=dof_Q2_outside, not_down=dof_P2_outside; - if ( final_map().template attribute<3>(top)->info().is_empty ) - std::swap(not_top,top); - if ( final_map().template attribute<3>(down)->info().is_empty ) - std::swap(not_down,down); - CGAL_assertion( !final_map().template attribute<3>(top)->info().is_empty ); - CGAL_assertion( !final_map().template attribute<3>(down)->info().is_empty ); - - // poly_first - poly_second = P1Q1 - // poly_second - poly_first = {0} - // poly_first \cap poly_second = Q1P2 or Q1Q2 - // opposite( poly_first U poly_second ) = Q2P1 or P2P1 - sew_2_marked_darts( final_map(), final_map().beta(dof_P1_outside,3), dof_Q1_outside, - mark_index, nodes, indices, polyline_info); //P1Q1 - sew_2_marked_darts( final_map(),final_map().beta(dof_Q1_outside,3), - top, mark_index, nodes, indices, - polyline_info); //Q1P2 or Q1Q2 - sew_2_marked_darts( final_map(),down, - dof_P1_outside, mark_index, nodes, indices, - polyline_info); //Q2P1 or P2P1 - sew_3_marked_darts( final_map(),not_top,not_down,top,down,mark_index, - darts_to_remove); - - } else { - Dart_handle top=final_map().beta(dof_Q2_outside,3), not_top=final_map().beta(dof_P2_outside,3); - Dart_handle down=dof_Q2_outside, not_down=dof_P2_outside; - if ( final_map().template attribute<3>(top)->info().is_empty ) - std::swap(not_top,top); - if ( final_map().template attribute<3>(down)->info().is_empty ) - std::swap(not_down,down); - CGAL_assertion( !final_map().template attribute<3>(top)->info().is_empty ); - CGAL_assertion( !final_map().template attribute<3>(down)->info().is_empty ); - - // poly_first - poly_second = {0} - // poly_second - poly_first = Q1P1 - // poly_first \cap poly_second = P1P2 or P1Q2 - // opposite( poly_first U poly_second ) = Q2Q1 or P2Q1 - sew_2_marked_darts( final_map(),final_map().beta(dof_Q1_outside,3), dof_P1_outside, - mark_index, nodes, indices, polyline_info); //Q1P1 - sew_2_marked_darts( final_map(),final_map().beta(dof_P1_outside,3), - top, mark_index, nodes, indices, - polyline_info); //P1P2 or P1Q2 - sew_2_marked_darts( final_map(),down, - dof_Q1_outside, mark_index, nodes, indices, - polyline_info); //Q2Q1 or P2Q1 - sew_3_marked_darts( final_map(),not_top,not_down,top,down,mark_index, - darts_to_remove); - } - } - - template - bool coplanar_triangles_case_handled( - Halfedge_handle first_hedge, Halfedge_handle second_hedge, - const std::pair& indices, - const Nodes_vector& nodes, - int index_p1, int index_p2, - int index_q1,int index_q2, - Halfedge_to_dart_map& selected_hedge_to_dart, - std::size_t mark_index, - std::set& darts_to_remove, - const std::pair& polyline_info - ){ - if( index_p1!=-1 ) { - if (index_p1==index_q1) { - if(index_p2!=-1) { - CGAL_assertion(index_p2!=index_q1); - if(index_p2==index_q2) { - //-----first polyhedron - Dart_handle dof_P1_outside = get_associated_dart(first_hedge->opposite(), - selected_hedge_to_dart); - Dart_handle dof_P2_outside = get_associated_dart(first_hedge, - selected_hedge_to_dart); - //-----second polyhedron - Dart_handle dof_Q1_outside = get_associated_dart(second_hedge->opposite(), - selected_hedge_to_dart); - Dart_handle dof_Q2_outside = get_associated_dart(second_hedge, - selected_hedge_to_dart); - - Dart_handle top_1=final_map().beta(dof_P1_outside,3), - not_top_1=final_map().beta(dof_Q1_outside,3); - Dart_handle top_2=final_map().beta(dof_P2_outside,3), - not_top_2=final_map().beta(dof_Q2_outside,3); - Dart_handle down_1=dof_P1_outside, not_down_1=dof_Q1_outside; - Dart_handle down_2=dof_P2_outside, not_down_2=dof_Q2_outside; - if ( final_map().template attribute<3>(top_1)->info().is_empty ) - std::swap(top_1,not_top_1); - if ( final_map().template attribute<3>(top_2)->info().is_empty ) - std::swap(top_2,not_top_2); - if ( final_map().template attribute<3>(down_1)->info().is_empty ) - std::swap(down_1,not_down_1); - if ( final_map().template attribute<3>(down_2)->info().is_empty ) - std::swap(down_2,not_down_2); - CGAL_assertion( !final_map().template attribute<3>(top_1)->info().is_empty ); - CGAL_assertion( !final_map().template attribute<3>(top_2)->info().is_empty ); - CGAL_assertion( !final_map().template attribute<3>(down_1)->info().is_empty ); - CGAL_assertion( !final_map().template attribute<3>(down_2)->info().is_empty ); - - // poly_first - poly_second = {0} - // poly_second - poly_first = {0} - // poly_first \cap poly_second = P1P2 or Q1Q2 or P1Q1 or Q1P2 - // opposite( poly_first U poly_second ) = P2P1 or Q2Q1 or P2Q1 or Q2P1 - sew_2_marked_darts( final_map(),top_1, top_2,mark_index, nodes, - indices, polyline_info); //P1P2 or Q1Q2 or P1Q1 or Q1P2 - sew_2_marked_darts( final_map(),down_2, down_1, mark_index, nodes, - indices, polyline_info); //P2P1 or Q2Q1 or P2Q1 or Q2P1 - sew_3_marked_darts( final_map(),not_top_1, not_down_1, top_1, - down_1,mark_index, darts_to_remove); - sew_3_marked_darts( final_map(),not_top_2, not_down_2, top_2, - down_2,mark_index, darts_to_remove); - return true; - } - } - sew_2_four_volumes_case_1(first_hedge->opposite(),second_hedge->opposite(), - std::make_pair(indices.second,indices.first), - nodes,index_p2,index_p1,index_q2, - selected_hedge_to_dart,mark_index, - darts_to_remove,polyline_info); - return true; - } - if (index_p1==index_q2) { - if(index_p2!=-1) { - CGAL_assertion(index_p2!=index_q2); - if(index_p2==index_q1) { - //-----first polyhedron - Dart_handle dof_P1_outside = get_associated_dart(first_hedge->opposite(), - selected_hedge_to_dart); - Dart_handle dof_P2_outside = get_associated_dart(first_hedge, - selected_hedge_to_dart); - //-----second polyhedron - Dart_handle dof_Q1_outside = get_associated_dart(second_hedge->opposite(), - selected_hedge_to_dart); - Dart_handle dof_Q2_outside = get_associated_dart(second_hedge, - selected_hedge_to_dart); - - Dart_handle top_1=final_map().beta(dof_P1_outside,3), not_top_1=dof_Q2_outside; - Dart_handle top_2=final_map().beta(dof_P2_outside,3), not_top_2=dof_Q1_outside; - Dart_handle down_1=dof_P1_outside, not_down_1=final_map().beta(dof_Q2_outside,3); - Dart_handle down_2=dof_P2_outside, not_down_2=final_map().beta(dof_Q1_outside,3); - if ( final_map().template attribute<3>(top_1)->info().is_empty ) - std::swap(top_1,not_top_1); - if ( final_map().template attribute<3>(top_2)->info().is_empty ) - std::swap(top_2,not_top_2); - if ( final_map().template attribute<3>(down_1)->info().is_empty ) - std::swap(down_1,not_down_1); - if ( final_map().template attribute<3>(down_2)->info().is_empty ) - std::swap(down_2,not_down_2); - CGAL_assertion( !final_map().template attribute<3>(top_1)->info().is_empty ); - CGAL_assertion( !final_map().template attribute<3>(top_2)->info().is_empty ); - CGAL_assertion( !final_map().template attribute<3>(down_1)->info().is_empty ); - CGAL_assertion( !final_map().template attribute<3>(down_2)->info().is_empty ); - - // poly_first - poly_second = P1P2 or P1Q1 or Q2P2 or Q2Q1 - // poly_second - poly_first = Q1Q2 or Q1P1 or P2P1 or P2Q2 - // poly_first \cap poly_second = {0} - // opposite( poly_first U poly_second ) = all space - sew_2_marked_darts( final_map(),top_1, top_2, mark_index, nodes, - indices, polyline_info); //P1P2 or Q1Q2 or P1Q1 or Q1P2 - sew_2_marked_darts( final_map(),down_2, down_1, mark_index, nodes, - indices, polyline_info); //P2P1 or Q2Q1 or P2Q1 or Q2P1 - sew_3_marked_darts( final_map(),not_top_1, not_down_1, top_1,down_1,mark_index, - darts_to_remove); - sew_3_marked_darts( final_map(),not_top_2, not_down_2, top_2,down_2,mark_index, - darts_to_remove); - return true; - } - } - sew_2_four_volumes_case_1(first_hedge->opposite(), second_hedge, - std::make_pair(indices.second,indices.first), - nodes,index_p2, index_p1, index_q1, - selected_hedge_to_dart, mark_index, - darts_to_remove, polyline_info, true); - return true; - } - } - - if(index_p2!=-1) { - if (index_p2==index_q1) { - sew_2_four_volumes_case_1(first_hedge,second_hedge->opposite(), - indices,nodes, index_p1,index_p2,index_q2, - selected_hedge_to_dart,mark_index, - darts_to_remove, polyline_info,true); - return true; - } - if(index_p2==index_q2) { - sew_2_four_volumes_case_1(first_hedge, second_hedge, indices, nodes, - index_p1, index_p2, index_q1, - selected_hedge_to_dart, mark_index, - darts_to_remove, polyline_info); - return true; - } - } - - - return false; - } - -public: - - Combinatorial_map_3& final_map() { - return *final_map_ptr; - } - Combinatorial_map_3& combinatorial_map() { - return *final_map_ptr; - } - boost::shared_ptr combinatorial_map_shared_ptr() { - return final_map_ptr; - } - - Combinatorial_map_output_builder(boost::shared_ptr map_ptr) - : final_map_ptr(map_ptr) {} - - Combinatorial_map_output_builder( - PolyhedronPointPMap point_pmap = PolyhedronPointPMap() - ) : ppmap(point_pmap) - , final_map_ptr(new Combinatorial_map_3()) - {} - - void input_have_coplanar_facets(){} - - template - void operator()( - const std::map,Cmp_unik_ad >& border_halfedges, - const Nodes_vector& nodes, - const An_edge_per_polyline_map& an_edge_per_polyline, - const Bitset& /*is_node_of_degree_one*/, - const Poly_to_map_node& polyhedron_to_map_node_to_polyhedron_vertex) { - //4) create one output polyhedron per connected component of polyhedron, - // connected by an edge which is not an intersection edge - //5) import into a Combinatorial map -#ifdef CGAL_COREFINEMENT_DEBUG - std::cout << "Nb marked edges " << border_halfedges.size() << std::endl; -// for (typename Border_halfedges_map::iterator it=border_halfedges.begin();it!=border_halfedges.end();++it) -// std::cout << it->first->get(ppmap,opposite()->vertex()) << " " << get(ppmap,it->first->vertex()) << " is constrained " << std::endl; - std::cout << "Nb polylines " << an_edge_per_polyline.size() << std::endl; -#endif - - internal_IOP::Non_intersection_halfedge criterium(border_halfedges); - - std::size_t mark_index= - final_map().get_new_mark(); //mark used to tag dart that are on an intersection - - //define a map that will contain the correspondance between selected halfedges of the boundary and - //their corresponding Dart_handle in the cmap. - typedef std::map< Halfedge_const_handle, - Dart_handle, - internal_IOP::Compare_address > - Halfedge_to_dart_map; - Halfedge_to_dart_map selected_hedge_to_dart; - for (typename An_edge_per_polyline_map::const_iterator it= - an_edge_per_polyline.begin(); it!=an_edge_per_polyline.end(); ++it) { - CGAL_assertion(it->second.first.size()==2); - //orientation of faces around the edge (to be sure we can do it) - Halfedge_handle first_hedge=it->second.first.begin()->second; - Halfedge_handle second_hedge=boost::next(it->second.first.begin())->second; - - if (!first_hedge->is_border()) - selected_hedge_to_dart - .insert(std::make_pair(first_hedge,Dart_handle(NULL))); - if (!first_hedge->opposite()->is_border()) - selected_hedge_to_dart - .insert(std::make_pair(first_hedge->opposite(),Dart_handle(NULL))); - if (!second_hedge->is_border()) - selected_hedge_to_dart - .insert(std::make_pair(second_hedge,Dart_handle(NULL))); - if (!second_hedge->opposite()->is_border()) - selected_hedge_to_dart - .insert(std::make_pair(second_hedge->opposite(),Dart_handle(NULL))); - } - -#ifdef CGAL_COREFINEMENT_DEBUG - int polynb=0; -#endif - for (typename Poly_to_map_node::const_iterator - it=polyhedron_to_map_node_to_polyhedron_vertex.begin(); - it!=polyhedron_to_map_node_to_polyhedron_vertex.end(); - ++it - ) { - typedef typename Polyhedron::Facet_const_handle Facet_const_handle; - typedef ::CGAL::Union_find UF; - typedef typename UF::handle UF_handle; - typedef std::map< Facet_const_handle, - std::list, - internal::corefinement::Compare_handle_ptr > Result; - typedef std::map< Facet_const_handle, - UF_handle, - internal::corefinement::Compare_handle_ptr > - Facet_to_handle_map; - - UF uf; - Facet_to_handle_map map_f2h; - Result result; - Polyhedron* current_poly=it->first; - -#ifdef CGAL_COREFINEMENT_DEBUG - std::cout << "writing poly debug"<< std::endl; - std::stringstream ss; - ss << "output_debug-" << ++polynb << ".off"; - std::ofstream output_debug(ss.str().c_str()); - output_debug << *current_poly; -#endif - - internal::corefinement::extract_connected_components(*(static_cast (current_poly) ), - criterium,uf,map_f2h,result); - - //add each connected component in the map with 2 volumes per component. - for (typename Result::iterator it_res=result.begin(); it_res!=result.end(); - ++it_res) { - //create in the final Cmap a 2D component containing faces of a connected component - //(twice: one with same orientation and one with the opposite orientation to model the other volume) - Dart_handle d = - import_from_polyhedron_subset( - final_map(), it_res->second.begin(), it_res->second.end(), - criterium, selected_hedge_to_dart, mark_index,ppmap); - //set an attribute to one volume represented by this component - //to indicate a part outside of the polyhedron current_poly - typename Combinatorial_map_3::template Attribute_range<3>::type::iterator - attrib=final_map().template create_attribute<3>(); - attrib->info().outside.insert(current_poly); - final_map().template set_attribute<3>(d,attrib); - //set the attribute for the opposite volume: represent a part inside current_poly - attrib=final_map().template create_attribute<3>(); - attrib->info().inside.insert(current_poly); - final_map().template set_attribute<3>(final_map().beta(d, 3),attrib); - -#ifdef CGAL_COREFINEMENT_DEBUG - final_map().display_characteristics(std::cout); - std::cout << std::endl; -#endif - } - } -#ifndef NDEBUG - for(typename Halfedge_to_dart_map::iterator it=selected_hedge_to_dart.begin(); - it!=selected_hedge_to_dart.end(); ++it) - CGAL_assertion(it->second!=Dart_handle(NULL)); -#endif - - CGAL_assertion(final_map().is_valid()); - - std::set darts_to_remove; - - //6) Glue pieces together - // using one edge per intersection polyline, we merge the different volumes - for (typename An_edge_per_polyline_map::const_iterator it= - an_edge_per_polyline.begin(); it!=an_edge_per_polyline.end(); ++it) { - CGAL_assertion(it->second.first.size()==2); - //orientation of faces around the edge (to be sure we can do it) - std::pair indices = it->first; - const std::pair& polyline_info=it->second.second; - - //get the two halfedges incident to the edge [indices.first,indices.second] - Halfedge_handle first_hedge=it->second.first.begin()->second; - Halfedge_handle second_hedge=boost::next(it->second.first.begin())->second; - - CGAL_assertion(nodes[indices.second]==get(ppmap,first_hedge->vertex())); - CGAL_assertion(nodes[indices.first]==get(ppmap, - first_hedge->opposite()->vertex())); - CGAL_assertion(nodes[indices.second]==get(ppmap,second_hedge->vertex())); - CGAL_assertion(nodes[indices.first]==get(ppmap, - second_hedge->opposite()->vertex())); - - Polyhedron* first_poly = it->second.first.begin()->first; - Polyhedron* second_poly = boost::next(it->second.first.begin())->first; - - //different handling depending on the number of incident triangles to the edge. - //After sewing there are two,three or four volumes if there are two,three or four incident triangles respectively - if ( first_hedge->is_border() || first_hedge->opposite()->is_border() ) { - if (second_hedge->is_border() || second_hedge->opposite()->is_border()) - sew_2_two_volumes_case(first_hedge, second_hedge, border_halfedges, - selected_hedge_to_dart, mark_index, - darts_to_remove, nodes, indices, polyline_info); - else - sew_2_three_volumes_case(second_hedge, first_hedge,indices,nodes, - border_halfedges,selected_hedge_to_dart, - second_poly,first_poly,mark_index, - darts_to_remove,polyline_info); - } else - if (second_hedge->is_border() || second_hedge->opposite()->is_border()) - sew_2_three_volumes_case(first_hedge, second_hedge, indices, nodes, - border_halfedges, selected_hedge_to_dart, - first_poly,second_poly,mark_index, - darts_to_remove,polyline_info); - else { - //Sort the four triangle facets around their common edge - // we suppose that the exterior of the polyhedron is indicated by - // counterclockwise oriented facets. - Vertex_handle P1=first_hedge->opposite()->next()->vertex(); - Vertex_handle P2=first_hedge->next()->vertex(); - // when looking from the side of indices.second, the interior of the first polyhedron is described - // by turning counterclockwise from P1 to P2 - Vertex_handle Q1=second_hedge->opposite()->next()->vertex(); - Vertex_handle Q2=second_hedge->next()->vertex(); - // when looking from the side of indices.second, the interior of the second polyhedron is described - // by turning from Q1 to Q2 - - //check if the third point of each triangular face is an original point (stay -1) - //or a intersection point (in that case we need the index of the corresponding node to - //have the exact value of the point) - int index_p1 = node_index_of_incident_vertex( - first_hedge->opposite()->next(),border_halfedges); - int index_p2=node_index_of_incident_vertex( - first_hedge->next(), border_halfedges); - int index_q1=node_index_of_incident_vertex( - second_hedge->opposite()->next(), border_halfedges); - int index_q2=node_index_of_incident_vertex( - second_hedge->next(), border_halfedges); - -#ifdef CGAL_COREFINEMENT_DEBUG - std::cout << index_p1 << " " << index_p2 << " " << index_q1 << " " <opposite(), selected_hedge_to_dart); - Dart_handle dof_P2_outside = - get_associated_dart(first_hedge, selected_hedge_to_dart); - //-----second polyhedron - Dart_handle dof_Q1_outside = - get_associated_dart(second_hedge->opposite(),selected_hedge_to_dart); - Dart_handle dof_Q2_outside = - get_associated_dart(second_hedge, selected_hedge_to_dart); - - if ( Q1_is_between_P1P2 ) { - if( Q2_is_between_P1P2 ) { - bool P1_is_between_Q1Q2 = - OOP::sorted_around_edge_filtered(indices.first, indices.second, - index_q1, index_q2, index_p1, - Q1, Q2, P1, nodes, ppmap); - if (!P1_is_between_Q1Q2) { - // poly_first - poly_second = P1Q1 U Q2P2 - // poly_second - poly_first = {0} - // poly_first \cap poly_second = Q1Q2 - // opposite( poly_first U poly_second ) = P2P1 - sew_2_marked_darts( final_map(),final_map().beta(dof_P1_outside, 3), - dof_Q1_outside, mark_index, nodes, - indices, polyline_info); //P1Q1 - sew_2_marked_darts( final_map(),dof_Q2_outside, - final_map().beta(dof_P2_outside,3),mark_index, nodes, - indices, polyline_info); //Q2P2 - sew_2_marked_darts( final_map(),final_map().beta(dof_Q1_outside,3), - final_map().beta(dof_Q2_outside,3), mark_index, nodes, - indices, polyline_info); //Q1Q2 - sew_2_marked_darts( final_map(),dof_P2_outside, - dof_P1_outside, mark_index, - nodes, indices, polyline_info); //P2P1 - //update inside outside info (because darts from the same volume have been merged) - final_map().template attribute<3>(final_map().beta(dof_Q1_outside,3))->info().inside - .insert(first_poly); //update Q1Q2 inside poly - final_map().template attribute<3>(dof_P2_outside)->info().outside - .insert(second_poly);//update P2P1 outside poly - } else { - // poly_first - poly_second = Q2Q1 - // poly_second - poly_first = P2P1 - // poly_first \cap poly_second = P1Q2 U Q1P2 - // opposite( poly_first U poly_second ) = {O} - sew_2_marked_darts( final_map(),dof_Q2_outside, - dof_Q1_outside, mark_index, nodes, - indices, polyline_info); //Q2Q1 - sew_2_marked_darts( final_map(),dof_P2_outside, - dof_P1_outside, mark_index, nodes, indices, - polyline_info); //P2P1 - sew_2_marked_darts( final_map(),final_map().beta(dof_Q1_outside,3), - final_map().beta(dof_P2_outside,3), mark_index, nodes, - indices, polyline_info); //Q1P2 - sew_2_marked_darts( final_map(),final_map().beta(dof_P1_outside,3), - final_map().beta(dof_Q2_outside,3),mark_index, nodes, - indices, polyline_info); //P1Q2 - //update inside outside info (because darts from the same volume have been merged) - final_map().template attribute<3>(dof_Q2_outside)->info().inside.insert( - first_poly); //update Q2Q1 inside poly - final_map().template attribute<3>(dof_P2_outside)->info().inside.insert( - second_poly);//update P2P1 inside poly - } - } else { - // poly_first - poly_second = P1Q1 - // poly_second - poly_first = P2Q2 - // poly_first \cap poly_second = Q1P2 - // opposite( poly_first U poly_second ) = Q2P1 - sew_2_marked_darts( final_map(),final_map().beta(dof_P1_outside,3), - dof_Q1_outside, mark_index, nodes, - indices, polyline_info); //P1Q1 - sew_2_marked_darts( final_map(),dof_P2_outside, - final_map().beta(dof_Q2_outside,3), mark_index, nodes, - indices, polyline_info); //P2Q2 - sew_2_marked_darts( final_map(),final_map().beta(dof_Q1_outside,3), - final_map().beta(dof_P2_outside,3), mark_index, nodes, - indices, polyline_info); //Q1P2 - sew_2_marked_darts( final_map(),dof_Q2_outside, - dof_P1_outside, mark_index, nodes, - indices, polyline_info); //Q2P1 - } - } else { - if( Q2_is_between_P1P2 ) { - // poly_first - poly_second = Q2P2 - // poly_second - poly_first = Q1P1 - // poly_first \cap poly_second = P1Q2 - // opposite( poly_first U poly_second ) = P2Q1 - sew_2_marked_darts( final_map(),dof_Q2_outside, - final_map().beta(dof_P2_outside,3), mark_index, nodes, - indices, polyline_info); //Q2P2 - sew_2_marked_darts( final_map(),final_map().beta(dof_Q1_outside,3), - dof_P1_outside, mark_index, nodes, - indices, polyline_info); //Q1P1 - sew_2_marked_darts( final_map(),final_map().beta(dof_P1_outside,3), - final_map().beta(dof_Q2_outside,3),mark_index, nodes, - indices, polyline_info); //P1Q2 - sew_2_marked_darts( final_map(),dof_P2_outside, - dof_Q1_outside, mark_index, nodes, - indices, polyline_info); //P2Q1 - } else { - bool P1_is_between_Q1Q2 = - OOP::sorted_around_edge_filtered(indices.first, indices.second, - index_q1,index_q2,index_p1,Q1,Q2,P1, - nodes,ppmap); - if (!P1_is_between_Q1Q2) { - // poly_first - poly_second = P1P2 - // poly_second - poly_first = Q1Q2 - // poly_first \cap poly_second = {0} - // opposite( poly_first U poly_second ) = P2Q1 U Q2P1 - sew_2_marked_darts( final_map(),final_map().beta(dof_P1_outside,3), - final_map().beta(dof_P2_outside,3), mark_index, nodes, - indices, polyline_info); //P1P2 - sew_2_marked_darts( final_map(),final_map().beta(dof_Q1_outside,3), - final_map().beta(dof_Q2_outside,3), mark_index, nodes, - indices, polyline_info); //Q1Q2 - sew_2_marked_darts( final_map(),dof_P2_outside, - dof_Q1_outside, mark_index, nodes, - indices, polyline_info); //P2Q1 - sew_2_marked_darts( final_map(),dof_Q2_outside, - dof_P1_outside, mark_index, nodes, - indices, polyline_info); //Q2P1 - //update inside outside info (because darts from the same volume have been merged) - final_map().template attribute<3>(final_map().beta(dof_Q1_outside,3))->info().outside - .insert(first_poly); //update Q1Q2 outside poly - final_map().template attribute<3>(final_map().beta(dof_P1_outside,3))->info().outside - .insert(second_poly);//update P2P1 outside poly - } else { - // poly_first - poly_second = {0} - // poly_second - poly_first = Q1P1 U P2Q2 - // poly_first \cap poly_second = P1P2 - // opposite( poly_first U poly_second ) = Q2Q1 - sew_2_marked_darts( final_map(),final_map().beta(dof_Q1_outside,3), - dof_P1_outside, mark_index, nodes, - indices, polyline_info); //Q1P1 - sew_2_marked_darts( final_map(),dof_P2_outside, - final_map().beta(dof_Q2_outside,3), mark_index, nodes, - indices, polyline_info); //P2Q2 - sew_2_marked_darts( final_map(),final_map().beta(dof_P1_outside,3), - final_map().beta(dof_P2_outside,3), mark_index, nodes, - indices, polyline_info); //P1P2 - sew_2_marked_darts( final_map(),dof_Q2_outside, - dof_Q1_outside, mark_index, nodes, indices, - polyline_info); //Q2Q1 - //update inside outside info (because darts from the same volume have been merged) - final_map().template attribute<3>(final_map().beta(dof_P1_outside,3))->info().inside - .insert(second_poly); //update P1P2 inside poly - final_map().template attribute<3>(dof_Q2_outside)->info().outside - .insert(first_poly);//update Q2Q1 outside poly - } - } - } - } - } - -#ifdef CGAL_COREFINEMENT_DEBUG - std::cout << "number of darts to remove: " << darts_to_remove.size() - <::iterator itdart=darts_to_remove.begin(), - end=darts_to_remove.end(); itdart!=end; ++itdart) { - final_map().erase_dart(*itdart); - } - - //remove empty volumes - typedef typename Combinatorial_map_3::template Attribute_range<3>::type - Volume_attribute_range; - Volume_attribute_range& ratrib=final_map().template attributes<3>(); - typename Volume_attribute_range::iterator curr=ratrib.begin(),end=ratrib.end(); - do { - if (curr->info().is_empty) - final_map().template erase_attribute<3>(curr++); - else - ++curr; - } while(curr!=end); - - CGAL_assertion(final_map().is_valid()); - - //update the info of each volume knowing about only one polyhedron: - //this happens when one polyhedron has a connected component - //that do not intersect the other polyhedron - - typedef Side_of_triangle_mesh - Inside_poly_test; - - CGAL_precondition(polyhedron_to_map_node_to_polyhedron_vertex.size()==2); - Polyhedron* Poly_A = - polyhedron_to_map_node_to_polyhedron_vertex.begin()->first; - Polyhedron* Poly_B = - boost::next(polyhedron_to_map_node_to_polyhedron_vertex.begin())->first; - Inside_poly_test* inside_A_test_ptr=NULL; - Inside_poly_test* inside_B_test_ptr=NULL; - bool Poly_A_is_closed = Poly_A->is_closed(); - bool Poly_B_is_closed = Poly_B->is_closed(); - -#ifdef CGAL_COREFINEMENT_DEBUG - final_map().display_characteristics(std::cout); - std::cout << "\n"; -#endif - - typename Combinatorial_map_3::template One_dart_per_cell_range<3> cell_range= - final_map().template one_dart_per_cell<3>(); - for (typename Combinatorial_map_3::template One_dart_per_cell_range<3> - ::iterator it = cell_range.begin(), it_end=cell_range.end(); - it_end!= it; ++it ) - { - internal_IOP::Volume_info& info = - final_map().template attribute<3>(it)->info(); - std::size_t inside_size = info.inside.size(); - std::size_t outside_size = info.outside.size(); - - // if a volume is not classified wrt the two polyhedra, it means the component we look at does not - // is a disjoint (but maybe at a vertex TAG SL001) - if ( inside_size + outside_size == 1) { - bool is_inside = (inside_size==1); - Polyhedron* current_poly= is_inside ? (*info.inside.begin()) - : (*info.outside.begin()); - Polyhedron* test_poly; - Inside_poly_test* inside_test_ptr; - if ( current_poly==Poly_A) { - // if the polyhedron is not closed, we set Poly_A to be outside by default - if (!Poly_B_is_closed){ - info.outside.insert(Poly_B); - continue; - } - test_poly=Poly_B; - if (inside_B_test_ptr == NULL) - inside_B_test_ptr = new Inside_poly_test(*Poly_B, ppmap); - inside_test_ptr=inside_B_test_ptr; - } else { - // if the polyhedron is not closed, we set Poly_B to be outside by default - if (!Poly_A_is_closed){ - info.outside.insert(Poly_A); - continue; - } - test_poly=Poly_A; - if (inside_A_test_ptr == NULL) - inside_A_test_ptr = new Inside_poly_test(*Poly_A, ppmap); - inside_test_ptr=inside_A_test_ptr; - } - - // We need to find a point of the volume that is not on the boundary of the other volume. - // Then the position of this point give the position of the volume. If all the points are on - // the bounday, we take the mid-point of an edge (which must not be on the boundary otherwise - // it contradicts the fact that volumes are disjoint - // We first use the dart we have since one_dart_per_incident_cell has a non-negligeable cost. - typename Kernel::Point_3 query=final_map().template attribute<0>(it)->point(); - CGAL::Bounded_side res = (*inside_test_ptr)(query); - if (res==ON_BOUNDARY) { - typedef typename Combinatorial_map_3:: - template One_dart_per_incident_cell_range<0,3> Vertex_range; - - Vertex_range vertex_range = - final_map().template one_dart_per_incident_cell<0,3>(it); - typename Vertex_range::iterator vit = vertex_range.begin(); - - CGAL_assertion( typename Combinatorial_map_3::Dart_handle(vit) == - typename Combinatorial_map_3::Dart_handle(it) ); - ++vit; - for ( ; vit!=vertex_range.end(); ++vit) { - query=final_map().template attribute<0>(vit)->point(); - res = (*inside_test_ptr)(query); - if ( res != ON_BOUNDARY ) break; - } - - //take edge midpoint - if (res == ON_BOUNDARY) { - /// \todo see do a better test here. At least the construction cannot fail - /// but the mid-point can fall outside of the volume... -#ifdef CGAL_COREFINEMENT_DEBUG -#warning this is not exact!!! -#endif - typename Kernel::Point_3 p1 = final_map().template attribute<0>(it)->point(); - typename Kernel::Point_3 p2 = - final_map().template attribute<0>(final_map().beta(it,1))->point(); - query=midpoint(p1,p2); - res = (*inside_test_ptr)(query); - } - - CGAL_assertion( res!= ON_BOUNDARY ); - } - - if (res == ON_BOUNDED_SIDE ) - info.inside.insert(test_poly); - else - info.outside.insert(test_poly); - } - -#ifdef CGAL_COREFINEMENT_DEBUG - std::cout << "This volume has inside: "; - for (typename std::set::iterator itpoly=info.inside.begin(); - itpoly!=info.inside.end(); ++itpoly) - std::cout << " " << *itpoly; - std::cout << " and outside: "; - for (typename std::set::iterator itpoly=info.outside.begin(); - itpoly!=info.outside.end(); ++itpoly) - std::cout << " " << *itpoly; - std::cout << std::endl; -#endif - } - if (inside_A_test_ptr!=NULL) delete inside_A_test_ptr; - if (inside_B_test_ptr!=NULL) delete inside_B_test_ptr; - } - -}; - -} -} //end of namespace CGAL::Corefinement - -#endif //CGAL_INTERNAL_COREFINEMENT_COMBINATORIAL_MAP_OUTPUT_BUILDER_H diff --git a/Operations_on_polyhedra/include/CGAL/internal/corefinement/Polyhedra_output_builder.h b/Operations_on_polyhedra/include/CGAL/internal/corefinement/Polyhedra_output_builder.h deleted file mode 100644 index 33cf1a4df8c..00000000000 --- a/Operations_on_polyhedra/include/CGAL/internal/corefinement/Polyhedra_output_builder.h +++ /dev/null @@ -1,2516 +0,0 @@ -// Copyright (c) 2014 GeometryFactory (France). -// All rights reserved. -// -// This file is part of CGAL (www.cgal.org). -// You can redistribute it and/or modify it under the terms of the GNU -// General Public License as published by the Free Software Foundation, -// either version 3 of the License, or (at your option) any later version. -// -// Licensees holding a valid commercial license may use this file in -// accordance with the commercial license agreement provided with the software. -// -// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE -// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. -// -// $URL$ -// $Id$ -// SPDX-License-Identifier: GPL-3.0+ -// -// -// Author(s) : Sebastien Loriot - -#ifndef CGAL_INTERNAL_COREFINEMENT_POLYHEDRA_OUTPUT_BUILDER_H -#define CGAL_INTERNAL_COREFINEMENT_POLYHEDRA_OUTPUT_BUILDER_H - -#include - -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include - -#include -#include - -namespace CGAL{ - -namespace internal_IOP{ - -#ifdef DEFINE_UNUSED_CLASSES -template -struct Import_patch_helper; - -template -struct Import_patch_helper -{ - typedef typename Polyhedron::HalfedgeDS HDS; - typedef typename HDS::Vertex_handle Vertex_handle; - typedef typename HDS::Face_handle Face_handle; - - Vertex_handle first_vertex(Face_handle f){ - return f->halfedge()->vertex(); - } - Vertex_handle second_hedge(Face_handle f){ - return f->halfedge()->next()->vertex(); - } - Vertex_handle third_hedge(Face_handle f){ - return f->halfedge()->prev()->vertex(); - } -}; - -template -struct Import_patch_helper -{ - typedef typename Polyhedron::HalfedgeDS HDS; - typedef typename HDS::Vertex_handle Vertex_handle; - typedef typename HDS::Face_handle Face_handle; - - Vertex_handle first_vertex(Face_handle f){ - return f->halfedge()->vertex(); - } - Vertex_handle second_vertex(Face_handle f){ - return f->halfedge()->prev()->vertex(); - } - Vertex_handle third_vertex(Face_handle f){ - return f->halfedge()->next()->vertex(); - } -}; - -template -class Import_patch - : public CGAL::Modifier_base - , public Import_patch_helper -{ - typedef typename Polyhedron::HalfedgeDS HDS; - typedef typename HDS::Halfedge_handle Halfedge_handle; - typedef typename HDS::Vertex_handle Vertex_handle; - typedef typename HDS::Face_handle Face_handle; - typedef typename HDS::Vertex Vertex; - typedef typename HDS::Halfedge Halfedge; - typedef typename HDS::Face Face; - typedef typename HDS::Halfedge::Base HBase; - - const std::vector& facets; - const std::set& interior_vertices; - const std::vector& interior_halfedges; - const std::vector& patch_border_halfedges; - -public: - - Import_patch( - const std::vector& facets_, - const std::set& interior_vertices_, - const std::vector& interior_halfedges_, - const std::vector& patch_border_halfedges_ - ) : facets(facets_) - , interior_vertices(interior_vertices_) - ,interior_halfedges(interior_halfedges_) - ,patch_border_halfedges(patch_border_halfedges_) - {} - - void operator()(HDS& hds) - { - Polyhedron_incremental_builder_3 B( hds); - B.begin_surface( interior_vertices.size(), - facets.size(), - interior_halfedges.size() * 2); - - std::size_t index=0; - std::map vertex_indices; - - //insert interior vertices - BOOST_FOREACH( Vertex_handle vh, interior_vertices){ - B.add_vertex( vh->point() ); - vertex_indices.insert( std::make_pair(vh, index++) ); - } - - //insert border vertices : TODO WE SHOULD GET THEM FROM hds - BOOST_FOREACH(Halfedge_handle h, patch_border_halfedges) - { - if( vertex_indices.insert( std::make_pair(h->vertex(),index) ).second ){ - B.add_vertex( h->vertex()->point() ); - ++index; - } - if( vertex_indices.insert( std::make_pair(h->opposite()->vertex(),index) ).second ){ - B.add_vertex( h->opposite()->vertex()->point() ); - ++index; - } - } - - BOOST_FOREACH(Face_handle fh, facets) - { - B.begin_facet(); - B.add_vertex_to_facet( vertex_indices[ this->first_vertex(fh) ] ); - B.add_vertex_to_facet( vertex_indices[ this->second_vertex(fh) ] ); - B.add_vertex_to_facet( vertex_indices[ this->third_vertex(fh) ] ); - B.end_facet(); - } - - B.end_surface(); - } -}; -#endif //DEFINE_UNUSED_CLASSES - -template < class Polyhedron, class PolyhedronPointPMap, class HalfedgeOutputIterator > -struct Import_polyline - : public CGAL::Modifier_base -{ - typedef typename Polyhedron::HalfedgeDS HDS; - typedef typename HDS::Halfedge_handle Halfedge_handle; - typedef typename HDS::Halfedge_const_handle Halfedge_const_handle; - typedef typename HDS::Vertex_handle Vertex_handle; - typedef typename HDS::Face_handle Face_handle; - typedef typename HDS::Vertex Vertex; - typedef typename HDS::Halfedge Halfedge; - typedef typename HDS::Face Face; - typedef typename HDS::Halfedge::Base HBase; - typedef std::map< Halfedge_handle, - Halfedge_handle, - Compare_unik_address > Hedge_map; - typedef std::map< Vertex_handle, - Vertex_handle > Vertex_map; - typedef internal_IOP::Compare_unik_address Cmp_unik_ad; - - Vertex_map& vertex_map; - Hedge_map& P_to_O_hedge; - Hedge_map& Q_to_O_hedge; - int nb_segments; - Halfedge_handle P_first_halfedge; - Halfedge_handle Q_first_halfedge; - Halfedge_handle O_first_halfedge; - const std::map< Halfedge_const_handle, - std::pair,Cmp_unik_ad >& border_halfedges; - PolyhedronPointPMap ppmap; - HalfedgeOutputIterator output; - - Import_polyline( - Vertex_map& vertex_map_, - Hedge_map& P_to_O_hedge_, - Hedge_map& Q_to_O_hedge_, - int nb_segments_, - Halfedge_handle P_first_halfedge_, - Halfedge_handle Q_first_halfedge_, - const std::map< Halfedge_const_handle, - std::pair,Cmp_unik_ad >& border_halfedges_, - PolyhedronPointPMap ppmap_, - HalfedgeOutputIterator output_) - : vertex_map( vertex_map_ ) - , P_to_O_hedge( P_to_O_hedge_ ) - , Q_to_O_hedge( Q_to_O_hedge_ ) - , nb_segments( nb_segments_ ) - , P_first_halfedge( P_first_halfedge_ ) - , Q_first_halfedge( Q_first_halfedge_ ) - , border_halfedges( border_halfedges_ ) - , ppmap( ppmap_ ) - , output(output_) - {} - - void operator()(HDS& hds) - { - HalfedgeDS_decorator decorator(hds); - - typename HDS::Halfedge dummy_hedge; //dummy default constructed halfedge - O_first_halfedge=hds.edges_push_back(dummy_hedge, dummy_hedge); - *output++=O_first_halfedge; - - //make sure the first vertex does not already exist - Vertex_handle source; - std::pair< typename std::map< Vertex_handle, Vertex_handle >::iterator, bool > insert_res= - vertex_map.insert( std::make_pair( P_first_halfedge->opposite()->vertex(), source ) ); - - - if( insert_res.second ) - { - source = decorator.vertices_push_back( *(P_first_halfedge->opposite()->vertex()) ); - decorator.set_vertex_halfedge(source, O_first_halfedge->opposite()); - put(ppmap, source, get(ppmap, P_first_halfedge->opposite()->vertex() ) ); - insert_res.first->second = source; - } - else - source = insert_res.first->second; - - //make sure the target vertex does not already exist if it is a polyline endpoint - Vertex_handle target; - if ( nb_segments==1 ) - { - insert_res = - vertex_map.insert( std::make_pair( P_first_halfedge->vertex(), target ) ); - if (insert_res.second) - { - target=decorator.vertices_push_back( *(P_first_halfedge->vertex()) ); - decorator.set_vertex_halfedge(target, O_first_halfedge); - put(ppmap, target, get(ppmap, P_first_halfedge->vertex() ) ); - insert_res.first->second = target; - } - else - target = insert_res.first->second; - } - else{ - target=decorator.vertices_push_back( *(P_first_halfedge->vertex()) ); - decorator.set_vertex_halfedge(target, O_first_halfedge); - put(ppmap, target, get(ppmap, P_first_halfedge->vertex() ) ); - } - - - //update source and target vertex of the edge created - decorator.set_vertex(O_first_halfedge, target); - decorator.set_vertex(O_first_halfedge->opposite(), source); - - - Halfedge_handle O_previous=O_first_halfedge; - Halfedge_handle P_previous=P_first_halfedge; - Halfedge_handle Q_previous=Q_first_halfedge; - - //set the correspondance - P_to_O_hedge.insert( std::make_pair(P_previous, O_previous) ); - Q_to_O_hedge.insert( std::make_pair(Q_previous, O_previous) ); - - source=target; - for (int i=1; ivertex()) ); - decorator.set_vertex_halfedge(target, O_hedge); - put(ppmap, target, get(ppmap, P_hedge->vertex() ) ); - } - else{ - std::pair< typename std::map< Vertex_handle, Vertex_handle >::iterator, bool > insert_res= - vertex_map.insert( std::make_pair(P_hedge->vertex(), Vertex_handle()) ); - if (insert_res.second) - { - target=decorator.vertices_push_back( *(P_hedge->vertex()) ); - decorator.set_vertex_halfedge(target, O_hedge); - put(ppmap, target, get(ppmap, P_hedge->vertex() ) ); - insert_res.first->second = target; - } - else - target = insert_res.first->second; - } - - decorator.set_vertex(O_hedge, target); - decorator.set_vertex(O_hedge->opposite(), source); - - O_previous=O_hedge; - P_previous = P_hedge; - Q_previous = Q_hedge; - source = target; - - P_to_O_hedge.insert( std::make_pair(P_previous, O_previous) ); - Q_to_O_hedge.insert( std::make_pair(Q_previous, O_previous) ); - } - } -}; - -template -struct Surface_extension_helper; - -template -struct Surface_extension_helper -{ - typedef typename Polyhedron::HalfedgeDS HDS; - typedef typename HDS::Halfedge_handle Halfedge_handle; - typedef typename HDS::Face_handle Face_handle; - typedef std::map< Halfedge_handle, - Halfedge_handle, - Compare_unik_address > Hedge_map; - Hedge_map& Qhedge_to_Phedge; - - Surface_extension_helper(Hedge_map& qh_to_ph):Qhedge_to_Phedge(qh_to_ph){} - - Halfedge_handle get_hedge(Halfedge_handle qhedge) - { - CGAL_assertion( Qhedge_to_Phedge.find(qhedge)!=Qhedge_to_Phedge.end() ); - std::pair key_and_value = - *Qhedge_to_Phedge.find(qhedge); - return key_and_value.first != qhedge - ? key_and_value.second - : key_and_value.second->opposite(); - } - - Halfedge_handle first_hedge(Face_handle f){ - return get_hedge( f->halfedge() ); - } - Halfedge_handle second_hedge(Face_handle f){ - return get_hedge( f->halfedge()->prev() ); - } - Halfedge_handle third_hedge(Face_handle f){ - return get_hedge( f->halfedge()->next() ); - } -}; - -template -struct Surface_extension_helper -{ - typedef typename Polyhedron::HalfedgeDS HDS; - typedef typename HDS::Halfedge_handle Halfedge_handle; - typedef typename HDS::Face_handle Face_handle; - typedef std::map< Halfedge_handle, - Halfedge_handle, - Compare_unik_address > Hedge_map; - Hedge_map& Qhedge_to_Phedge; - - Surface_extension_helper(Hedge_map& qh_to_ph):Qhedge_to_Phedge(qh_to_ph){} - - Halfedge_handle get_hedge(Halfedge_handle qhedge) - { - CGAL_assertion( Qhedge_to_Phedge.count(qhedge)==1 ); - std::pair key_and_value = - *Qhedge_to_Phedge.find(qhedge); - return key_and_value.first == qhedge - ? key_and_value.second - : key_and_value.second->opposite(); - } - - Halfedge_handle first_hedge(Face_handle f){ - return get_hedge( f->halfedge() ); - } - Halfedge_handle second_hedge(Face_handle f){ - return get_hedge( f->halfedge()->next() ); - } - Halfedge_handle third_hedge(Face_handle f){ - return get_hedge( f->halfedge()->prev() ); - } -}; - - - -template -class Surface_extension_by_patch_appending - : public CGAL::Modifier_base - , public Surface_extension_helper -{ - typedef typename Polyhedron::HalfedgeDS HDS; - typedef typename HDS::Halfedge_handle Halfedge_handle; - typedef typename HDS::Vertex_handle Vertex_handle; - typedef typename HDS::Face_handle Face_handle; - typedef typename HDS::Vertex Vertex; - typedef typename HDS::Halfedge Halfedge; - typedef typename HDS::Face Face; - typedef typename HDS::Halfedge::Base HBase; - - const std::vector& facets; - const std::vector& interior_halfedges; - const std::vector& patch_border_halfedges; - const std::set& interior_vertices; - PolyhedronPointPMap ppmap; - - typedef Surface_extension_helper Base; - using Base::first_hedge; - using Base::second_hedge; - using Base::third_hedge; - using Base::get_hedge; - using Base::Qhedge_to_Phedge; - -public: - - Surface_extension_by_patch_appending( - const std::vector& facets_, - const std::vector& interior_halfedges_, - const std::vector& patch_border_halfedges_, - const std::set& interior_vertices_, - typename Base::Hedge_map& Qhedge_to_Phedge_, - PolyhedronPointPMap ppmap_ - ) : Base( Qhedge_to_Phedge_ ) - ,facets(facets_) - ,interior_halfedges(interior_halfedges_) - ,patch_border_halfedges(patch_border_halfedges_) - ,interior_vertices(interior_vertices_) - ,ppmap(ppmap_) - {} - - void operator()(HDS& hds) - { - HalfedgeDS_decorator decorator(hds); - std::vector interior_vertex_halfedges; - - //insert interior halfedges and create interior vertices - BOOST_FOREACH(Halfedge_handle h, interior_halfedges){ - Halfedge_handle new_h = hds.edges_push_back( *h ); - Qhedge_to_Phedge[ h ] = new_h; - // put new halfedges on the border of the mesh - decorator.set_face(new_h, Face_handle()); - decorator.set_face(new_h->opposite(), Face_handle()); - - //create a copy of interior vertices only once - if ( h->vertex()->halfedge()==h && interior_vertices.count(h->vertex()) ) - { - Vertex_handle v = decorator.vertices_push_back( *(h->vertex()) ); - decorator.set_vertex_halfedge(v, new_h); - decorator.set_vertex(new_h, v); - put(ppmap, v, get(ppmap, h->vertex() ) ); - interior_vertex_halfedges.push_back( new_h ); - } - if ( h->opposite()->vertex()->halfedge()==h->opposite() && - interior_vertices.count(h->opposite()->vertex()) ) - { - Vertex_handle v = decorator.vertices_push_back( *(h->opposite()->vertex()) ); - decorator.set_vertex_halfedge(v, new_h->opposite()); - decorator.set_vertex(new_h->opposite(), v); - put(ppmap, v, get(ppmap, h->opposite()->vertex() ) ); - interior_vertex_halfedges.push_back( new_h->opposite() ); - } - } - - //create facets and connect halfedges - BOOST_FOREACH(Face_handle f, facets) - { - Halfedge_handle hedges[]={ - first_hedge(f), second_hedge(f), third_hedge(f) - }; - - Face_handle new_f = decorator.faces_push_back( *f ); - decorator.set_face_halfedge(new_f, hedges[0]); - - for (int i=0;i<3;++i) - { - hedges[i]->HBase::set_next(hedges[(i+1)%3]); - decorator.set_prev(hedges[(i+1)%3], hedges[i]); - decorator.set_face(hedges[i], new_f); - } - } - - // handle interior edges that are on the border of the mesh: - // they do not have a prev/next pointer set since only the pointers - // of patch interior halfedges part a face have been. In the following - // (i) we set the next/prev pointer around interior vertices on the mesh - // boundary and (ii) we collect interior mesh border halfedges incident to - // a patch border vertex and set their next/prev pointer (possibly of - // another patch) - - // Containers used for step (ii) for collecting mesh border halfedges - // with source/target on an intersection polyline that needs it prev/next - // pointer to be set - std::vector border_halfedges_source_to_link; - std::vector border_halfedges_target_to_link; - BOOST_FOREACH(Halfedge_handle h, interior_halfedges) - if (h->is_border_edge()) - { - if (!h->is_border()) h=h->opposite(); - - Vertex_handle src = h->opposite()->vertex(); - Vertex_handle tgt = h->vertex(); - if (reverse_patch_orientation) std::swap(src, tgt); - - if ( !interior_vertices.count(src) ) - border_halfedges_source_to_link.push_back(get_hedge(h)); - if ( !interior_vertices.count(tgt) ){ - border_halfedges_target_to_link.push_back(get_hedge(h)); - continue; // since the next halfedge should not be in the same patch - } - CGAL_assertion( h->is_border() && - h->prev()->is_border() && h->next()->is_border() ); - // step (i) - Halfedge_handle qhedge=get_hedge(h); - Halfedge_handle qnext = reverse_patch_orientation ? - get_hedge(h->prev()) : get_hedge(h->next()); - CGAL_assertion( qhedge->is_border() && qnext->is_border() ); - qhedge->HBase::set_next(qnext); - decorator.set_prev(qnext, qhedge); - } - // now the step (ii) we look for the candidate halfedge by turning around - // the vertex in the direction of the interior of the patch - BOOST_FOREACH(Halfedge_handle h, border_halfedges_target_to_link) - { - Halfedge_handle candidate=h->opposite()->prev()->opposite(); - CGAL_assertion_code(Halfedge_handle start=candidate); - while (!candidate->is_border()){ - candidate=candidate->prev()->opposite(); - CGAL_assertion(candidate!=start); - } - h->HBase::set_next(candidate); - decorator.set_prev(candidate,h); - } - BOOST_FOREACH(Halfedge_handle h, border_halfedges_source_to_link) - { - Halfedge_handle candidate=h->opposite()->next()->opposite(); - while (!candidate->is_border()) - candidate=candidate->next()->opposite(); - candidate->HBase::set_next(h); - decorator.set_prev(h,candidate); - } - - // For all interior vertices, update the vertex pointer - // of all but the vertex halfedge - BOOST_FOREACH(Halfedge_handle h, interior_vertex_halfedges) - { - Vertex_handle v=h->vertex(); - Halfedge_handle next_around_vertex=h; - do{ - CGAL_assertion (next_around_vertex->next() != Halfedge_handle()); - next_around_vertex=next_around_vertex->next()->opposite(); - decorator.set_vertex(next_around_vertex, v); - }while(h != next_around_vertex); - } - - // For all patch boundary vertices, update the vertex pointer - // of all but the vertex halfedge - BOOST_FOREACH(Halfedge_handle qhedge, patch_border_halfedges) - { - //check for a halfedge pointing inside an already imported patch - Halfedge_handle h = get_hedge(qhedge); - CGAL_assertion( h->next()!=Halfedge_handle() ); - // update the pointers on the target - Halfedge_handle next_around_target=h; - Vertex_handle v=h->vertex(); - do{ - next_around_target = next_around_target->next()->opposite(); - decorator.set_vertex(next_around_target, v); - }while( next_around_target->next()!=Halfedge_handle() && - next_around_target!=h && !next_around_target->is_border()); - // update the pointers on the source - Halfedge_handle next_around_source=h->prev(); - CGAL_assertion(next_around_source!=Halfedge_handle()); - v = h->opposite()->vertex(); - do{ - decorator.set_vertex(next_around_source, v); - next_around_source = next_around_source->opposite()->prev(); - }while( next_around_source!=Halfedge_handle() && - next_around_source!=h->opposite() && - !next_around_source->is_border()); - } - } -}; - -template -struct Intersection_polylines{ - typedef typename Polyhedron::Halfedge_handle Halfedge_handle; - const std::vector& P; - const std::vector& Q; - const std::vector& lengths; - boost::dynamic_bitset<> to_skip; - boost::dynamic_bitset<> to_skip_in_P; - boost::dynamic_bitset<> to_skip_in_Q; - Intersection_polylines( - const std::vector& P_polylines, - const std::vector& Q_polylines, - const std::vector& lengths_ - ) : P( P_polylines ) - , Q( Q_polylines ) - , lengths( lengths_ ) - , to_skip(P.size(),false) - , to_skip_in_P(P.size(),false) - , to_skip_in_Q(P.size(),false) - {} -}; - -template -class Remove_patch_simplices : public CGAL::Modifier_base { - typedef typename Polyhedron::HalfedgeDS HDS; - typedef typename HDS::Halfedge_handle Halfedge_handle; - typedef typename HDS::Vertex_handle Vertex_handle; - typedef typename HDS::Face_handle Face_handle; - typedef typename HDS::Vertex Vertex; - typedef typename HDS::Halfedge Halfedge; - typedef typename HDS::Face Face; - typedef typename HDS::Halfedge::Base HBase; - - const std::vector& facets; - const std::set& interior_vertices; - const std::vector& interior_halfedges; - const std::vector& patch_border_halfedges; - -public: - - Remove_patch_simplices( - const std::vector& facets_, - const std::set& interior_vertices_, - const std::vector& interior_halfedges_, - const std::vector& patch_border_halfedges_ - ) : facets(facets_) - , interior_vertices(interior_vertices_) - ,interior_halfedges(interior_halfedges_) - ,patch_border_halfedges(patch_border_halfedges_) - {} - - void operator()(HDS& hds) - { - CGAL::HalfedgeDS_decorator decorator(hds); - - // put the halfedges on the boundary of the patch on the boundary of the polyhedron - Face_handle border; - BOOST_FOREACH(Halfedge_handle h, patch_border_halfedges) - decorator.set_face(h, border); - - // set next/prev relationship of border halfedges - BOOST_FOREACH(Halfedge_handle h, patch_border_halfedges) - { - Halfedge_handle next=h->next(); - while(!next->is_border()) - next=next->opposite()->next(); - h->HBase::set_next(next); - decorator.set_prev(next,h); - decorator.set_vertex_halfedge(h->vertex(),h); - } - - // In case a ccb of the patch is not a cycle (the source and target vertices - // are border vertices), the first halfedge of that ccb will not have its - // prev pointer set correctly. To fix that, we consider all interior edges - // and check for one that is on the border of the patch and that is incident - // to a border vertex and use it to get the missing prev pointer. - BOOST_FOREACH(Halfedge_handle h, interior_halfedges) - if(h->is_border_edge()) - { - if (h->is_border()) h=h->opposite(); - if ( !interior_vertices.count(h->vertex()) ) - { - // look for the halfedge belonging to patch_border_halfedge - // having the prev pointer not correctly set - Halfedge_handle next=h->next(); - while(!next->is_border()) - next=next->opposite()->next(); - CGAL_assertion( next->is_border() );//we marked it above! - // now update the prev pointer - Halfedge_handle prev=h->opposite()->prev(); - prev->HBase::set_next(h->next()); - decorator.set_prev(h->next(),prev); - decorator.set_vertex_halfedge(prev->vertex(),prev); - } - } - - //now remove the simplices - BOOST_FOREACH(Halfedge_handle h, interior_halfedges) - hds.edges_erase(h); - BOOST_FOREACH(Face_handle f, facets) - hds.faces_erase(f); - BOOST_FOREACH(Vertex_handle v, interior_vertices) - hds.vertices_erase(v); - } -}; - -template -class Remove_isolated_patch_simplices - : public CGAL::Modifier_base -{ - typedef typename Polyhedron::HalfedgeDS HDS; - typedef typename HDS::Halfedge_handle Halfedge_handle; - typedef typename HDS::Vertex_handle Vertex_handle; - typedef typename HDS::Face_handle Face_handle; - typedef typename HDS::Vertex Vertex; - typedef typename HDS::Halfedge Halfedge; - typedef typename HDS::Face Face; - typedef typename HDS::Halfedge::Base HBase; - - const std::vector& facets; - const std::set& interior_vertices; - const std::vector& interior_halfedges; - const std::vector& border_halfedges; - -public: - - Remove_isolated_patch_simplices( - const std::vector& facets_, - const std::set& interior_vertices_, - const std::vector& interior_halfedges_, - const std::vector& border_halfedges_ - ) : facets(facets_) - , interior_vertices(interior_vertices_) - , interior_halfedges(interior_halfedges_) - , border_halfedges(border_halfedges_) - {} - - void operator()(HDS& hds) - { - CGAL::HalfedgeDS_decorator decorator(hds); - //remove the simplices - BOOST_FOREACH(Halfedge_handle h, interior_halfedges) - hds.edges_erase(h); - // There is no shared halfedge between duplicated patches even - // if they were before the duplication. Thus the erase that follows is safe. - // However remember that vertices were not duplicated which is why their - // removal is not handled here (still in use or to be removed in - // remove_unused_polylines()) - BOOST_FOREACH(Halfedge_handle h, border_halfedges) - hds.edges_erase(h); - BOOST_FOREACH(Face_handle f, facets) - hds.faces_erase(f); - BOOST_FOREACH(Vertex_handle v, interior_vertices) - hds.vertices_erase(v); - } -}; - -template -class Disconnect_patches : public CGAL::Modifier_base { - typedef typename Polyhedron::HalfedgeDS HDS; - typedef typename HDS::Halfedge_handle Halfedge_handle; - typedef typename HDS::Vertex_handle Vertex_handle; - typedef typename HDS::Face_handle Face_handle; - typedef typename HDS::Vertex Vertex; - typedef typename HDS::Halfedge Halfedge; - typedef typename HDS::Face Face; - typedef typename HDS::Halfedge::Base HBase; - - const std::vector& facets; - const std::set& interior_vertices; - const std::vector& interior_halfedges; - const std::vector& patch_border_halfedges; - std::vector& new_patch_border; - -public: - - Disconnect_patches( - const std::vector& facets_, - const std::set& interior_vertices_, - const std::vector& interior_halfedges_, - const std::vector& patch_border_halfedges_, - std::vector& new_patch_border_ - ) : facets(facets_) - , interior_vertices(interior_vertices_) - , interior_halfedges(interior_halfedges_) - , patch_border_halfedges(patch_border_halfedges_) - , new_patch_border(new_patch_border_) - {} - - void operator()(HDS& hds) - { - CGAL::HalfedgeDS_decorator decorator(hds); - - new_patch_border.reserve( patch_border_halfedges.size() ); - - std::map old_to_new; - - // put the halfedges on the boundary of the patch on the boundary of the polyhedron - Face_handle border; - BOOST_FOREACH(Halfedge_handle h, patch_border_halfedges) - { - Halfedge_handle new_hedge = hds.edges_push_back(*h); - new_patch_border.push_back(new_hedge); - decorator.set_face(h, border); - decorator.set_face(new_hedge->opposite(), border); - old_to_new.insert( std::make_pair(h, new_hedge) ); - } - - // update next/prev pointer of new hedges in case it is one of the new hedges - BOOST_FOREACH(Halfedge_handle h, new_patch_border) - { - if ( h->next()->is_border() ){ - h->HBase::set_next( old_to_new[h->next()] ); - decorator.set_prev( h->next(), h); - } - } - - // set next/prev pointers on the border of the neighbor patch - BOOST_FOREACH(Halfedge_handle h, patch_border_halfedges) - { - Halfedge_handle next=h->next(); - // check if not already done - if ( !next->is_border() ){ - do{ - next=next->opposite()->next(); - } while(!next->is_border()); - h->HBase::set_next(next); - decorator.set_prev(next,h); - } - - // setting prev is only needed in case the polyhedron has a boundary - // and the intersection polyline intersects its boundary - if ( !h->prev()->is_border() ){ - Halfedge_handle prev=h->prev(); - do{ - prev=prev->opposite()->prev(); - } while( !prev->is_border() ); - prev->HBase::set_next(h); - decorator.set_prev(h, prev); - } - - CGAL_assertion( h->prev()->is_border() ); - - decorator.set_vertex_halfedge(h->vertex(),h); - decorator.set_vertex_halfedge(h->opposite()->vertex(),h->opposite()); // only needed if the polyhedra is open - } - - //update next/prev relationship inside the patch - //to have a correct connectivity, and update facet halfedge pointer - BOOST_FOREACH(Halfedge_handle h, new_patch_border) - { - if ( h->prev()->next() != h ) - h->prev()->HBase::set_next( h ); - if ( h->next()->prev() != h ) - decorator.set_prev(h->next(), h); - decorator.set_face_halfedge(h->facet(), h); - } - - // update next/prev pointers on the border of the patch - BOOST_FOREACH(Halfedge_handle h, new_patch_border) - { - h=h->opposite(); - //set next pointer if not already set - if ( h->next()->prev()!=h ) - { - // we visit facets inside the patch we consider - Halfedge_handle candidate = h->opposite()->prev()->opposite(); - while ( !candidate->is_border() ) - candidate = candidate->prev()->opposite(); - h->HBase::set_next(candidate); - decorator.set_prev(candidate,h); - } - CGAL_assertion( h->next()->prev()== h ); - - // set prev pointer if not already set - if ( h->prev()->next() != h ) - { - Halfedge_handle candidate = h->opposite()->next()->opposite(); - while ( !candidate->is_border() ) - candidate = candidate->next()->opposite(); - decorator.set_prev(h,candidate); - candidate->HBase::set_next(h); - } - - CGAL_assertion( h->next()->prev()== h ); - CGAL_assertion( h->prev()->is_border() ); - CGAL_assertion( h->next()->is_border() ); - } - } -}; - - -template -struct Patch_description{ - typedef typename Polyhedron::Facet_handle Facet_handle; - typedef typename Polyhedron::Vertex_handle Vertex_handle; - typedef typename Polyhedron::Halfedge_handle Halfedge_handle; - - std::vector facets; - std::set interior_vertices; - std::vector interior_halfedges; - std::vector patch_border_halfedges; - bool is_initialized; - - Patch_description(): is_initialized(false) {}; -}; - -template -void extract_patch_simplices( - std::size_t patch_id, - Polyhedron& P, - Facet_index_pmap facet_indices, - const std::vector& patch_ids, - std::vector& facets, - std::set& interior_vertices, - std::vector& interior_halfedges, - std::vector& patch_border_halfedges, - const Is_marked_edge_map& is_marked_edge -) -{ - typedef typename Polyhedron::Halfedge_handle Halfedge_handle; - typedef typename Polyhedron::Vertex_handle Vertex_handle; - - for (typename Polyhedron::Facet_iterator fit=P.facets_begin(), - fit_end=P.facets_end(); - fit!=fit_end; ++fit) - { - if ( patch_ids[ get(facet_indices, fit) ]==patch_id ) - { - facets.push_back( fit ); - Halfedge_handle hedges[]={fit->halfedge(), fit->halfedge()->next(), fit->halfedge()->prev()}; - for (int i=0;i<3;++i) - { - if ( !is_marked_edge.count(hedges[i]) ) - { - if ( hedges[i] < hedges[i]->opposite() - || hedges[i]->opposite()->is_border()) - interior_halfedges.push_back( hedges[i] ); - } - else - patch_border_halfedges.push_back(hedges[i]); - } - } - } - - std::set border_vertices; - for (std::size_t k=0, end=patch_border_halfedges.size(); k!=end; ++k) - { - border_vertices.insert( patch_border_halfedges[k]->vertex() ); - // if the model is not closed i.e. patch_border_halfedge is not cycle only - border_vertices.insert( patch_border_halfedges[k]->opposite()->vertex() ); - } - - for (std::size_t k=0, end=interior_halfedges.size(); k!=end; ++k) - { - if ( border_vertices.find( interior_halfedges[k]->vertex() ) - == border_vertices.end() ) - { - interior_vertices.insert( interior_halfedges[k]->vertex() ); - } - if ( border_vertices.find( interior_halfedges[k]->opposite()->vertex() ) - == border_vertices.end() ) - { - interior_vertices.insert( interior_halfedges[k]->opposite()->vertex() ); - } - } -} - -template -struct Patch_container{ -//typedefs - typedef typename Polyhedron::Halfedge_const_handle Halfedge_const_handle; - typedef internal_IOP::Compare_unik_address Cmp_unik_ad; -// data members - std::vector< Patch_description > patches; -// external data members - Polyhedron* poly_ptr; - const std::vector& patch_ids; - Facet_index_pmap facet_id_pmap; - const std::map< Halfedge_const_handle, - std::pair,Cmp_unik_ad >& border_halfedges; -// constructor - Patch_container( - Polyhedron* poly_ptr_, - const std::vector& patch_ids_, - Facet_index_pmap facet_id_pmap_, - const std::map< Halfedge_const_handle, - std::pair,Cmp_unik_ad >& border_halfedges_, - std::size_t nb_patches - ) : patches(nb_patches) - , poly_ptr(poly_ptr_) - , patch_ids(patch_ids_) - , facet_id_pmap(facet_id_pmap_) - , border_halfedges(border_halfedges_) - {} - - Patch_description& operator[](std::size_t i) { - if ( !patches[i].is_initialized ) - { - extract_patch_simplices( - i, *poly_ptr, - facet_id_pmap, patch_ids, - patches[i].facets, patches[i].interior_vertices, - patches[i].interior_halfedges, patches[i].patch_border_halfedges, - border_halfedges - ); - - patches[i].is_initialized=true; - } - return patches[i]; - } - - /// debug - std::ostream& dump_patch(std::size_t i, std::ostream& out) - { - Patch_description& patch=this->operator[](i); - out << "OFF\n" << patch.interior_vertices.size()+patch.patch_border_halfedges.size(); - out << " " << patch.facets.size() << " 0\n"; - std::map vertexid; - int id=0; - BOOST_FOREACH(typename Polyhedron::Vertex_handle vh, patch.interior_vertices) - { - vertexid[vh]=id++; - out << vh->point() << "\n"; - } - - BOOST_FOREACH(typename Polyhedron::Halfedge_handle hh, patch.patch_border_halfedges) - { - vertexid[hh->vertex()]=id++; - out << hh->vertex()->point() << "\n"; - } - - BOOST_FOREACH(typename Polyhedron::Facet_handle fh, patch.facets) - { - out << "3 " << vertexid[fh->halfedge()->vertex()] << - " " << vertexid[fh->halfedge()->next()->vertex()] << - " " << vertexid[fh->halfedge()->next()->next()->vertex()] << "\n"; - } - - return out; - } - - void dump_patches(const boost::dynamic_bitset<>& selection, std::string prefix) - { - for (std::size_t i=selection.find_first(); - i < selection.npos; i = selection.find_next(i)) - { - std::stringstream ss; - ss << prefix << "-" << i << ".off"; - std::ofstream output(ss.str().c_str()); - dump_patch(i, output); - } - } - -}; - -} //end of namespace internal_IOP - -template -struct Default_facet_id_pmap -{ - typedef boost::read_write_property_map_tag category; - typedef std::size_t value_type; - typedef std::size_t& reference; - typedef typename Polyhedron::Facet_const_handle key_type; - - friend std::size_t get(Default_facet_id_pmap, key_type f) { return f->id(); } - friend void put(Default_facet_id_pmap, key_type f, std::size_t i) { const_cast(*f).id()=i; } -}; - -namespace Corefinement -{ - -template -class Polyhedra_output_builder -{ -//Default typedefs - typedef typename Default::Get< - PolyhedronPointPMap_, - Default_polyhedron_ppmap >::type PolyhedronPointPMap; - typedef typename Default::Get< - Kernel_, - typename Kernel_traits< - typename boost::property_traits::value_type - >::Kernel >::type Kernel; - typedef typename Default::Get< - Facet_id_pmap_, - Default_facet_id_pmap >::type Facet_id_pmap; - typedef typename Default::Get >::type - EdgeMarkPropertyMap; - - -public: -//Boolean operation indices - enum Boolean_operation {P_UNION_Q = 0, P_INTER_Q, P_MINUS_Q, Q_MINUS_P, NONE }; -private: -//Data members - Polyhedron *P_ptr, *Q_ptr; - cpp11::array, 4 > desired_output; - Facet_id_pmap P_facet_id_pmap, Q_facet_id_pmap; - PolyhedronPointPMap ppmap; - EdgeMarkPropertyMap edge_mark_pmap; - bool input_with_coplanar_facets; - // bitset containing information about operations that cannot be - // performed because of non-manifoldness or that is ambiguous - // 0 = P+Q - // 1 = P inter Q - // 2 = P - Q - // 3 = Q - P - std::bitset<4> impossible_operation; - - //Orientation of polyhedra - bool is_P_inside_out; - bool is_Q_inside_out; - -//Polyhedron typedefs - typedef typename Polyhedron::Halfedge_const_handle Halfedge_const_handle; - typedef typename Polyhedron::Halfedge_handle Halfedge_handle; - typedef typename Polyhedron::Vertex_handle Vertex_handle; - typedef typename Polyhedron::Vertex_const_handle Vertex_const_handle; - typedef typename Polyhedron::Facet_handle Facet_handle; -//Other typedefs - typedef internal_IOP::Compare_unik_address Cmp_unik_ad; - typedef std::map< std::pair, - std::pair< std::map, - std::pair > > An_edge_per_polyline_map; - typedef std::map Node_to_polyhedron_vertex_map; - typedef std::map Poly_to_map_node; - typedef internal_IOP::Intersection_polylines Intersection_polylines; - typedef internal_IOP::Patch_description Patch_description; - typedef internal_IOP::Patch_container Patch_container; - typedef std::map< Halfedge_handle, Halfedge_handle, Cmp_unik_ad> Edge_map; -#ifdef CGAL_COREFINEMENT_POLYHEDRA_DEBUG - #warning move these to predicates.h -#endif - template - bool are_triangles_coplanar_same_side( - const typename Kernel::Point_3& O_prime,const typename Kernel::Point_3& O, - const typename Kernel::Point_3& P,const typename Kernel::Point_3& Q) - { - if ( CGAL::orientation(O_prime, O, P ,Q) != CGAL::COPLANAR ) return false; - CGAL::Orientation cpl_orient = CGAL::coplanar_orientation(O_prime, O, P, Q); - CGAL_assertion( cpl_orient != CGAL::COLLINEAR ); - return cpl_orient == CGAL::POSITIVE; - } - - - template - bool are_triangles_coplanar_same_side_filtered( int O_prime_index, - int O_index, - int P_index, - int Q_index, - Vertex_handle P, - Vertex_handle Q, - const Nodes_vector& nodes) - { - typename Nodes_vector::Protector p; - try{ - CGAL_USE(p); - return are_triangles_coplanar_same_side( - nodes.interval_node(O_prime_index), - nodes.interval_node(O_index), - P_index == -1 ? nodes.to_interval(get(ppmap,P)): nodes.interval_node(P_index), - Q_index == -1 ? nodes.to_interval(get(ppmap,Q)) : nodes.interval_node(Q_index ) - ); - } - catch(Uncertain_conversion_exception&){ - return are_triangles_coplanar_same_side( - nodes.exact_node(O_prime_index), - nodes.exact_node(O_index), - P_index == -1 ? nodes.to_exact(get(ppmap,P)): nodes.exact_node(P_index), - Q_index == -1 ? nodes.to_exact(get(ppmap,Q)) : nodes.exact_node(Q_index ) - ); - } - } - - void remove_patches_from_polyhedra( - Polyhedron* P_ptr, - const boost::dynamic_bitset<>& patches_to_remove, - Patch_container& patches_of_P - ) - { - for (std::size_t i=patches_to_remove.find_first(); - i < patches_to_remove.npos; i = patches_to_remove.find_next(i)) - { - Patch_description& patch=patches_of_P[i]; - internal_IOP::Remove_patch_simplices - modifier( patch.facets, - patch.interior_vertices, - patch.interior_halfedges, - patch.patch_border_halfedges); - P_ptr->delegate(modifier); - } - } - - // function used to remove polylines imported or kept that are incident only - // to patches not kept for the operation P_ptr is used for storing - // the result. We look for edges with halfedges both on the border of - // the mesh. The vertices incident only to such edges should be removed. - // Here to detect vertices that should be kept, we abuse the fact that - // the halfedge to be removed and incident to a vertex that should not be - // removed will still have its next pointer set to a halfedge part of - // the result. - void remove_unused_polylines( - Polyhedron* P_ptr, - const boost::dynamic_bitset<>& patches_to_remove, - Patch_container& patches_of_P) - { - std::set vertices_to_remove; - std::set edges_to_remove; - for (std::size_t i = patches_to_remove.find_first(); - i < patches_to_remove.npos; - i = patches_to_remove.find_next(i)) - { - Patch_description& patch=patches_of_P[i]; - BOOST_FOREACH(Halfedge_handle h, patch.patch_border_halfedges) - { - if (h->is_border() && h->opposite()->is_border()){ - vertices_to_remove.insert(h->vertex()); - vertices_to_remove.insert(h->opposite()->vertex()); - edges_to_remove.insert( hopposite()?h:h->opposite()); - } - } - } - - BOOST_FOREACH(Vertex_handle vh, vertices_to_remove) - { - bool to_remove=true; - BOOST_FOREACH(Halfedge_handle h, halfedges_around_target(vh,*P_ptr)) - if (!h->is_border() || !h->opposite()->is_border()) - { - to_remove=false; - // in case the vertex halfedge was one that is going to remove, - // update it - set_halfedge(vh, h, *P_ptr); - break; - } - if (to_remove) - remove_vertex(vh,*P_ptr); - } - BOOST_FOREACH(Halfedge_handle hh, edges_to_remove) - remove_edge(edge(hh,*P_ptr),*P_ptr); - } - - void disconnect_patches_from_polyhedra( - Polyhedron* P_ptr, - const boost::dynamic_bitset<>& patches_to_remove, - Patch_container& patches_of_P, - const Edge_map& Phedge_to_Qhedge, //map former patch border halfedge to the equivalent in the other polyhedron - Edge_map& new_Phedge_to_Qhedge //map new patch border halfedge to the equivalent in the other polyhedron - ) - { - for (std::size_t i=patches_to_remove.find_first(); - i < patches_to_remove.npos; i = patches_to_remove.find_next(i)) - { - Patch_description& patch=patches_of_P[i]; - std::vector new_patch_border; - internal_IOP::Disconnect_patches - modifier( patch.facets, - patch.interior_vertices, - patch.interior_halfedges, - patch.patch_border_halfedges, - new_patch_border ); - P_ptr->delegate(modifier); - - - CGAL_assertion( new_patch_border.size() == - patch.patch_border_halfedges.size() ); - - std::size_t nb_hedges=new_patch_border.size(); - for (std::size_t k=0; k < nb_hedges; ++k){ - - CGAL_assertion( patch.patch_border_halfedges[k]->vertex() == new_patch_border[k]->vertex() ); - CGAL_assertion( patch.patch_border_halfedges[k]->opposite()->vertex() == new_patch_border[k]->opposite()->vertex() ); - CGAL_assertion( new_patch_border[k]->is_border_edge() ); - CGAL_assertion( !new_patch_border[k]->is_border() ); - CGAL_assertion( new_patch_border[k]->opposite()->next()->is_border() ); - CGAL_assertion( new_patch_border[k]->opposite()->prev()->is_border() ); - - typename Edge_map::const_iterator it_res = - Phedge_to_Qhedge.find(patch.patch_border_halfedges[k]); - CGAL_assertion( it_res != Phedge_to_Qhedge.end() ); - CGAL_assertion( it_res->first->vertex()->point() == it_res->second->vertex()->point() ); - CGAL_assertion( it_res->first->opposite()->vertex()->point() == it_res->second->opposite()->vertex()->point() ); - new_Phedge_to_Qhedge[ - patch.patch_border_halfedges[k]==it_res->first - ? new_patch_border[k] - : new_patch_border[k]->opposite() ] = it_res->second; - } - - patch.patch_border_halfedges.swap(new_patch_border); - } - } - - template - void append_Q_patches_to_P( - Polyhedron* P_ptr, - const boost::dynamic_bitset<>& patches_to_append, - Patch_container& patches, - std::map< Halfedge_handle, - Halfedge_handle, - internal_IOP::Compare_unik_address - >& Qhedge_to_Phedge - ){ - #ifdef CGAL_COREFINEMENT_POLYHEDRA_DEBUG - #warning the size of Qhedge_to_Phedge will increase when adding new patches by the size of internal edges. Maybe the use of a copy would be better? - #endif - for (std::size_t i=patches_to_append.find_first(); - i < patches_to_append.npos; i = patches_to_append.find_next(i)) - { - Patch_description& patch = patches[i]; - - internal_IOP::Surface_extension_by_patch_appending - modifier(patch.facets, patch.interior_halfedges, patch.patch_border_halfedges, patch.interior_vertices, Qhedge_to_Phedge, ppmap); - P_ptr->delegate(modifier); - } - - //CGAL_assertion( Qhedge_to_Phedge.size()==patch_border_halfedges.size() ); // this is not true in case of coplanar patches - //CGAL_assertion( P_ptr->is_valid() ); - } - - template < class HalfedgeOutputIterator > - void - import_polyline( - Polyhedron& O, - Halfedge_handle P_first_polyline_hedge, - Halfedge_handle Q_first_polyline_hedge, - int nb_segments, - std::map< Halfedge_handle, - Halfedge_handle, - internal_IOP::Compare_unik_address - > & P_to_O_hedge, - std::map< Halfedge_handle, - Halfedge_handle, - internal_IOP::Compare_unik_address - > & Q_to_O_hedge, - std::map& vertex_map, - const std::map< Halfedge_const_handle, - std::pair,Cmp_unik_ad >& border_halfedges, - HalfedgeOutputIterator output) - { - internal_IOP::Import_polyline - modifier( vertex_map, P_to_O_hedge, Q_to_O_hedge, nb_segments, - P_first_polyline_hedge, Q_first_polyline_hedge, - border_halfedges, ppmap, output); - - O.delegate( modifier ); - } - - void compute_border_edge_map( - const Intersection_polylines& polylines, - Patch_container& patches_of_P, - Patch_container& patches_of_Q, - Edge_map& Qhedge_to_Phedge - ){ - std::size_t nb_polylines = polylines.lengths.size(); - for( std::size_t i=0; i& patches_of_P_to_keep, - const boost::dynamic_bitset<>& patches_of_Q_to_import, - Patch_container& patches_of_P, - Patch_container& patches_of_Q, - bool reverse_patch_orientation_P, - bool reverse_patch_orientation_Q, - Edge_map& Qhedge_to_Phedge - ){ - //clean up patches not kept - remove_patches_from_polyhedra(P_ptr, ~patches_of_P_to_keep, patches_of_P); - - if (reverse_patch_orientation_P){ - Polygon_mesh_processing::reverse_face_orientations_of_mesh_with_polylines(*P_ptr); - // here we need to update the mapping to use the correct border - // halfedges while appending the patches from Q - BOOST_FOREACH(typename Edge_map::value_type& v, Qhedge_to_Phedge) - v.second=v.second->opposite(); - } - - //we import patches from Q - if ( reverse_patch_orientation_Q ) - append_Q_patches_to_P(P_ptr, patches_of_Q_to_import, patches_of_Q, Qhedge_to_Phedge); - else - append_Q_patches_to_P(P_ptr, patches_of_Q_to_import, patches_of_Q, Qhedge_to_Phedge); - } - - void compute_inplace_operation( - Polyhedron* P_ptr, - const boost::dynamic_bitset<>& patches_of_P_to_keep, - const boost::dynamic_bitset<>& patches_of_Q_to_import, - Patch_container& patches_of_P, - Patch_container& patches_of_Q, - bool reverse_patch_orientation_P, - bool reverse_patch_orientation_Q, - const Intersection_polylines& polylines - ){ - Edge_map Qhedge_to_Phedge; - //maps patch border halfedge from Q to halfedge from P - compute_border_edge_map(polylines, patches_of_P, - patches_of_Q, Qhedge_to_Phedge); - - compute_inplace_operation( P_ptr, - patches_of_P_to_keep, patches_of_Q_to_import, - patches_of_P, patches_of_Q, - reverse_patch_orientation_P, reverse_patch_orientation_Q, - Qhedge_to_Phedge ); - } - - -#ifdef CGAL_COREFINEMENT_POLYHEDRA_DEBUG - #warning factorize with the code of compute_difference_inplace -#endif - void compute_inplace_operation_delay_removal_and_insideout( - Polyhedron* P_ptr, - const boost::dynamic_bitset<>& patches_of_P_to_keep, - const boost::dynamic_bitset<>& patches_of_Q_to_import, - Patch_container& patches_of_P, - Patch_container& patches_of_Q, - bool reverse_patch_orientation_Q, - const Intersection_polylines& polylines, - Edge_map& disconnected_patches_hedge_to_Qhedge - ){ - Edge_map Qhedge_to_Phedge, Phedge_to_Qhedge; - //maps patch border halfedge from Q to halfedge from P - std::size_t nb_polylines = polylines.lengths.size(); - for( std::size_t i=0; iis_border() -#endif - // disconnect patches inside Q - // For the patches scheduled to be removed, their patch descriptions - // in patches_of_P will be updated so that patch_border_halfedges are - // the newly created halfedges within disconnect_patches_from_polyhedra. - // Note that disconnected_patches_hedge_to_Qhedge also refers to those halfedges - //init the map with the previously filled one (needed when reusing patches in two operations) - disconnected_patches_hedge_to_Qhedge=Phedge_to_Qhedge; - disconnect_patches_from_polyhedra(P_ptr, ~patches_of_P_to_keep, patches_of_P, - Phedge_to_Qhedge, disconnected_patches_hedge_to_Qhedge); - - //we import patches from Q - if (reverse_patch_orientation_Q) - append_Q_patches_to_P(P_ptr, patches_of_Q_to_import, patches_of_Q, Qhedge_to_Phedge); - else - append_Q_patches_to_P(P_ptr, patches_of_Q_to_import, patches_of_Q, Qhedge_to_Phedge); - } - - void remove_disconnected_patches( - Polyhedron& P, - Patch_container& patches, - const boost::dynamic_bitset<>& patches_to_remove) - { - for (std::size_t i=patches_to_remove.find_first(); - i < patches_to_remove.npos; - i = patches_to_remove.find_next(i)) - { - Patch_description& patch=patches[i]; - internal_IOP::Remove_isolated_patch_simplices - modifier( patch.facets, patch.interior_vertices, - patch.interior_halfedges, patch.patch_border_halfedges - ); - P.delegate( modifier ); - } - } - - template < class HalfedgeOutputIterator > - void fill_new_polyhedron( - Polyhedron& O, // output - const boost::dynamic_bitset<>& patches_of_P_to_import, - const boost::dynamic_bitset<>& patches_of_Q_to_import, - Patch_container& patches_of_P, - Patch_container& patches_of_Q, - bool reverse_orientation_of_patches_from_P, - bool reverse_orientation_of_patches_from_Q, - const Intersection_polylines& polylines, - const std::map< Halfedge_const_handle, - std::pair,Cmp_unik_ad >& border_halfedges, - HalfedgeOutputIterator shared_halfedge_output // new shared halfedges - ) - { - //add a polyline inside O for each intersection polyline - std::size_t nb_polylines = polylines.lengths.size(); - std::map P_to_O_vertex; - std::map< Halfedge_handle, - Halfedge_handle, - internal_IOP::Compare_unik_address - > P_to_O_hedge, Q_to_O_hedge; - for (std::size_t i=0; i < nb_polylines; ++i) - if (!polylines.to_skip.test(i)) - import_polyline(O, polylines.P[i], polylines.Q[i], - polylines.lengths[i], - P_to_O_hedge, Q_to_O_hedge, - P_to_O_vertex, border_halfedges, shared_halfedge_output); - - //import patches of P - if (reverse_orientation_of_patches_from_P) - append_Q_patches_to_P(&O, patches_of_P_to_import, patches_of_P, P_to_O_hedge); - else - append_Q_patches_to_P(&O, patches_of_P_to_import, patches_of_P, P_to_O_hedge); - - //import patches from Q - if (reverse_orientation_of_patches_from_Q) - append_Q_patches_to_P(&O, patches_of_Q_to_import, patches_of_Q, Q_to_O_hedge); - else - append_Q_patches_to_P(&O, patches_of_Q_to_import, patches_of_Q, Q_to_O_hedge); - } - - // detect if a polyline is incident to two patches that won't be imported - // for the current operation (polylines skipt are always incident to a - // coplanar patch) - template - static - void fill_polylines_to_skip( - Intersection_polylines& polylines, - const std::vector& P_patch_ids, - const std::vector& Q_patch_ids, - const boost::dynamic_bitset<>& patches_of_P_used, - const boost::dynamic_bitset<>& patches_of_Q_used, - const FacetIdPmap& P_face_id_pmap, - const FacetIdPmap& Q_face_id_pmap) - { - for (std::size_t i=0;iis_border()){ - std::size_t patch_id = P_patch_ids[ get( P_face_id_pmap, h_P->facet() ) ]; - if (patches_of_P_used.test(patch_id)) - skip_polyline_in_P=false; - } - if (skip_polyline_in_P && !h_P->opposite()->is_border()){ - std::size_t patch_id = P_patch_ids[ get( P_face_id_pmap, h_P->opposite()->facet() ) ]; - if (patches_of_P_used.test(patch_id)) - skip_polyline_in_P=false; - } - bool skip_polyline_in_Q=true; - if (!h_Q->is_border()){ - std::size_t patch_id = Q_patch_ids[ get( Q_face_id_pmap, h_Q->facet() ) ]; - if (patches_of_Q_used.test(patch_id)) - skip_polyline_in_Q=false; - } - if (skip_polyline_in_Q && !h_Q->opposite()->is_border()){ - std::size_t patch_id = Q_patch_ids[ get( Q_face_id_pmap, h_Q->opposite()->facet() ) ]; - if (patches_of_Q_used.test(patch_id)) - skip_polyline_in_Q=false; - } - - if (skip_polyline_in_P) polylines.to_skip_in_P.set(i); - if (skip_polyline_in_Q) polylines.to_skip_in_Q.set(i); - if (skip_polyline_in_P && skip_polyline_in_Q) - polylines.to_skip.set(i); - } - } - - bool is_dangling_edge(int src_id, int tgt_id, - Halfedge_const_handle hedge, - const boost::dynamic_bitset<>& is_node_of_degree_one) const - { - if ( is_node_of_degree_one.test(src_id) ) - { - bool res=true; - Halfedge_const_handle h = hedge->opposite(), start=h; - do{ - if (h->is_border()) - { - res = false; - break; - } - h=h->next()->opposite(); - } while(h!=start); - if (res) return true; - } - if ( is_node_of_degree_one.test(tgt_id) ) - { - Halfedge_const_handle h = hedge, start=h; - do{ - if (h->is_border()) - return false; - h=h->next()->opposite(); - } while(h!=start); - return true; - } - return false; - } - -public: - - Polyhedra_output_builder( - Polyhedron& P, - Polyhedron& Q, - cpp11::array, 4 > desired_output_, - Facet_id_pmap P_facet_id_pmap_, - Facet_id_pmap Q_facet_id_pmap_, - PolyhedronPointPMap point_pmap = PolyhedronPointPMap(), - EdgeMarkPropertyMap edge_pmap = EdgeMarkPropertyMap() - ) : P_ptr(&P) - , Q_ptr(&Q) - , desired_output( desired_output_ ) - , P_facet_id_pmap(P_facet_id_pmap_) - , Q_facet_id_pmap(Q_facet_id_pmap_) - , ppmap(point_pmap) - , edge_mark_pmap(edge_pmap) - , input_with_coplanar_facets(false) - , is_P_inside_out( !Polygon_mesh_processing::is_outward_oriented(*P_ptr) ) - , is_Q_inside_out( !Polygon_mesh_processing::is_outward_oriented(*Q_ptr) ) - {} - - Polyhedra_output_builder( - Polyhedron& P, - Polyhedron& Q, - cpp11::array, 4 > desired_output_, - PolyhedronPointPMap point_pmap = PolyhedronPointPMap(), - EdgeMarkPropertyMap edge_pmap = EdgeMarkPropertyMap() - ) : P_ptr(&P) - , Q_ptr(&Q) - , desired_output( desired_output_ ) - , ppmap(point_pmap) - , edge_mark_pmap(edge_pmap) - , input_with_coplanar_facets(false) - , is_P_inside_out( !Polygon_mesh_processing::is_outward_oriented(*P_ptr) ) - , is_Q_inside_out( !Polygon_mesh_processing::is_outward_oriented(*Q_ptr) ) - {} - - bool union_valid() const { return !impossible_operation[P_UNION_Q]; } - bool intersection_valid() const { return !impossible_operation[P_INTER_Q]; } - bool P_minus_Q_valid() const { return !impossible_operation[P_MINUS_Q]; } - bool Q_minus_P_valid() const { return !impossible_operation[Q_MINUS_P]; } - - void P_is_inside_out() { is_P_inside_out = true; } - void Q_is_inside_out() { is_Q_inside_out = true; } - - void input_have_coplanar_facets() - { - input_with_coplanar_facets=true; - } - - template - void operator()( - std::map,Cmp_unik_ad >& border_halfedges, - const Nodes_vector& nodes, - An_edge_per_polyline_map& an_edge_per_polyline, - const boost::dynamic_bitset<>& is_node_of_degree_one, - const Poly_to_map_node& /* polyhedron_to_map_node_to_polyhedron_vertex */) - { - // first create and fill a map from vertex to node_id - boost::unordered_map vertex_to_node_id; - for(typename std::map,Cmp_unik_ad >::iterator it=border_halfedges.begin(), - it_end=border_halfedges.end(); - it!=it_end;++it) - { - vertex_to_node_id[it->first->vertex()]=it->second.second; - vertex_to_node_id[it->first->opposite()->vertex()]=it->second.first; - } - - std::size_t num_facets_P = internal::corefinement::init_facet_indices(*P_ptr, P_facet_id_pmap); - std::size_t num_facets_Q = internal::corefinement::init_facet_indices(*Q_ptr, Q_facet_id_pmap); - boost::dynamic_bitset<> coplanar_facets_P(num_facets_P, 0); - boost::dynamic_bitset<> coplanar_facets_Q(num_facets_Q, 0); - - // In the following loop we filter intersection edge that are strictly inside a patch - // of coplanar facets so that we keep only the edges on the border of the patch. - // This is not optimal and in an ideal world being able to find the outside edges - // directly would avoid to compute the intersection of edge/facets inside the patch - // This loop is done only if the input have some coplanar facets - typename An_edge_per_polyline_map::iterator epp_it=input_with_coplanar_facets - ?an_edge_per_polyline.begin() - :an_edge_per_polyline.end(), - epp_it_end=an_edge_per_polyline.end(); - std::set border_edges_to_remove; - for (;epp_it!=epp_it_end;) - { - Halfedge_handle first_hedge = epp_it->second.first[P_ptr]; - Halfedge_handle first_hedge_opp = first_hedge->opposite(); - Halfedge_handle second_hedge = epp_it->second.first[Q_ptr]; - Halfedge_handle second_hedge_opp = second_hedge->opposite(); - - //vertices from P - // Vertex_handle P1=first_hedge_opp->next()->vertex(); - // Vertex_handle P2=first_hedge->next()->vertex(); - //vertices from Q - // Vertex_handle Q1=second_hedge_opp->next()->vertex(); - // Vertex_handle Q2=second_hedge->next()->vertex(); - - int index_p1=get_node_id(first_hedge_opp->next()->vertex(),vertex_to_node_id); - int index_p2=get_node_id(first_hedge->next()->vertex(),vertex_to_node_id); - int index_q1=get_node_id(second_hedge_opp->next()->vertex(),vertex_to_node_id); - int index_q2=get_node_id(second_hedge->next()->vertex(),vertex_to_node_id); - - // set boolean for the position of P1 wrt to Q1 and Q2 - bool P1_eq_Q1=false, P1_eq_Q2=false; - if (!first_hedge_opp->is_border() && index_p1!=-1) - { - if (!second_hedge_opp->is_border()) - P1_eq_Q1 = index_p1 == index_q1; - if (!second_hedge->is_border()) - P1_eq_Q2 = index_p1 == index_q2; - } - - // set boolean for the position of P2 wrt to Q1 and Q2 - bool P2_eq_Q1=false, P2_eq_Q2=false; - if (!first_hedge->is_border() && index_p2!=-1) - { - if (!second_hedge_opp->is_border()) - P2_eq_Q1 = index_p2 == index_q1; - if (!P1_eq_Q2 && !second_hedge->is_border()) - P2_eq_Q2 = index_p2 == index_q2; - } - - //mark coplanar facets if any - if (P1_eq_Q1){ - coplanar_facets_P.set(get(P_facet_id_pmap, first_hedge_opp->facet())); - coplanar_facets_Q.set(get(Q_facet_id_pmap, second_hedge_opp->facet())); - } - if (P1_eq_Q2){ - coplanar_facets_P.set(get(P_facet_id_pmap, first_hedge_opp->facet())); - coplanar_facets_Q.set(get(Q_facet_id_pmap, second_hedge->facet())); - } - if (P2_eq_Q1){ - coplanar_facets_P.set(get(P_facet_id_pmap, first_hedge->facet())); - coplanar_facets_Q.set(get(Q_facet_id_pmap, second_hedge_opp->facet())); - } - if (P2_eq_Q2){ - coplanar_facets_P.set(get(P_facet_id_pmap, first_hedge->facet())); - coplanar_facets_Q.set(get(Q_facet_id_pmap, second_hedge->facet())); - } - - // remove the edge if it is in the middle of a coplanar patch - if ( (P1_eq_Q1 || P1_eq_Q2) && (P2_eq_Q1 || P2_eq_Q2) ) - { - typename An_edge_per_polyline_map::iterator it_to_rm=epp_it; - ++epp_it; - an_edge_per_polyline.erase(it_to_rm); - border_edges_to_remove.insert(first_hedge); - border_edges_to_remove.insert(second_hedge); - #ifdef CGAL_COREFINEMENT_DEBUG - #warning we need to have the EdgeMarkPropertyMap to unmark intersection hedge - #endif - } - else - ++epp_it; - } - - BOOST_FOREACH(Halfedge_const_handle h, border_edges_to_remove) - border_halfedges.erase(h); - - // (1) Assign a patch id to each facet indicating in which connected - // component limited by intersection edges of the surface they are. - internal_IOP::Non_intersection_halfedge is_not_marked(border_halfedges); - - CGAL_assertion (P_ptr!=Q_ptr); - - std::vector P_patch_ids, Q_patch_ids; - std::vector P_patch_sizes, Q_patch_sizes; -#ifdef CGAL_COREFINEMENT_POLYHEDRA_DEBUG - #warning: the extraction of patches could be done by using a seed provided. That is we first make the \ - classification of patches using a representative facet (incident to a marked edge) and once \ - we really need a patch we extract it using this seed. Note that this requires a post-processing \ - if the input polyhedra have several connected component free from intersection \ - this would require to guarantee that there is no connected component not involved in the \ - intersection -#endif //CGAL_COREFINEMENT_POLYHEDRA_DEBUG - - /// \todo I need a property map indicating if an edge is an intersection edge - std::size_t P_nb_patches = internal::corefinement:: - mark_connected_components_v2(*P_ptr, - is_not_marked, - P_facet_id_pmap, - P_patch_ids, - P_patch_sizes); - std::size_t Q_nb_patches = internal::corefinement:: - mark_connected_components_v2(*Q_ptr, - is_not_marked, - Q_facet_id_pmap, - Q_patch_ids, - Q_patch_sizes); - - CGAL_assertion ( P_nb_patches==P_patch_sizes.size() ); - CGAL_assertion ( Q_nb_patches==Q_patch_sizes.size() ); - - // (2-a) Use the orientation around an edge to classify a patch - boost::dynamic_bitset<> is_patch_inside_Q(P_nb_patches, false); - boost::dynamic_bitset<> is_patch_inside_P(Q_nb_patches, false); - boost::dynamic_bitset<> patch_status_not_set_P(P_nb_patches,true); - boost::dynamic_bitset<> patch_status_not_set_Q(Q_nb_patches,true); - boost::dynamic_bitset<> coplanar_patches_of_P(P_nb_patches,false); - boost::dynamic_bitset<> coplanar_patches_of_Q(Q_nb_patches,false); - boost::dynamic_bitset<> coplanar_patches_of_P_for_union_and_intersection(P_nb_patches,false); - boost::dynamic_bitset<> coplanar_patches_of_Q_for_union_and_intersection(Q_nb_patches,false); - - for (typename An_edge_per_polyline_map::const_iterator it=an_edge_per_polyline.begin();it!=an_edge_per_polyline.end();++it) - { - CGAL_assertion(it->second.first.size()==2); - //orientation of faces around the edge (to be sure we can do it) - std::pair indices = it->first; - //const std::pair& polyline_info=it->second.second; - - //get the two halfedges incident to the edge [indices.first,indices.second] - Halfedge_handle first_hedge = it->second.first.find(P_ptr)->second; - Halfedge_handle second_hedge = it->second.first.find(Q_ptr)->second; - - CGAL_assertion(nodes[indices.second]==get(ppmap,first_hedge->vertex())); - CGAL_assertion(nodes[indices.first]==get(ppmap,first_hedge->opposite()->vertex())); - CGAL_assertion(nodes[indices.second]==get(ppmap,second_hedge->vertex())); - CGAL_assertion(nodes[indices.first]==get(ppmap,second_hedge->opposite()->vertex())); - - //different handling depending on the number of incident triangles to the edge. - //After sewing there are two,three or four volumes if there are two,three or four incident triangles respectively - if ( first_hedge->is_border_edge() ){ - if (second_hedge->is_border_edge() ) - { - if ( first_hedge->is_border() != second_hedge->is_border() ) - { - //No restriction at this level - std::size_t patch_id_P = - P_patch_ids[ get( P_facet_id_pmap, first_hedge->is_border() - ? first_hedge->opposite()->facet() - : first_hedge->facet() ) ]; - std::size_t patch_id_Q = - Q_patch_ids[ get( Q_facet_id_pmap, second_hedge->is_border() - ? second_hedge->opposite()->facet() - : second_hedge->facet() ) ]; - patch_status_not_set_P.reset(patch_id_P); - patch_status_not_set_Q.reset(patch_id_Q); - } - else - { - //Nothing allowed - impossible_operation.set(); - return; - } - } - else - { - //Ambiguous, we can do nothing - impossible_operation.set(); - return; - } - } - else - if ( second_hedge->is_border_edge() ) - { - //Ambiguous, we do nothing - impossible_operation.set(); - return; - } - else - { - //Sort the four triangle facets around their common edge - // we suppose that the exterior of the polyhedron is indicated by - // counterclockwise oriented facets. - Vertex_handle P1=first_hedge->opposite()->next()->vertex(); - Vertex_handle P2=first_hedge->next()->vertex(); - // when looking from the side of indices.second, the interior of the first polyhedron is described - // by turning counterclockwise from P1 to P2 - Vertex_handle Q1=second_hedge->opposite()->next()->vertex(); - Vertex_handle Q2=second_hedge->next()->vertex(); - // when looking from the side of indices.second, the interior of the second polyhedron is described - // by turning from Q1 to Q2 - - //check if the third point of each triangular face is an original point (stay -1) - //or a intersection point (in that case we need the index of the corresponding node to - //have the exact value of the point) - int index_p1=get_node_id(first_hedge->opposite()->next()->vertex(),vertex_to_node_id); - int index_p2=get_node_id(first_hedge->next()->vertex(),vertex_to_node_id); - int index_q1=get_node_id(second_hedge->opposite()->next()->vertex(),vertex_to_node_id); - int index_q2=get_node_id(second_hedge->next()->vertex(),vertex_to_node_id); - - std::size_t patch_id_p1=P_patch_ids[ get(P_facet_id_pmap, first_hedge->opposite()->facet()) ]; - std::size_t patch_id_p2=P_patch_ids[ get(P_facet_id_pmap, first_hedge->facet()) ]; - std::size_t patch_id_q1=Q_patch_ids[ get(Q_facet_id_pmap, second_hedge->opposite()->facet()) ]; - std::size_t patch_id_q2=Q_patch_ids[ get(Q_facet_id_pmap, second_hedge->facet()) ]; - - //indicates that patch status will be updated - patch_status_not_set_P.reset(patch_id_p1); - patch_status_not_set_P.reset(patch_id_p2); - patch_status_not_set_Q.reset(patch_id_q1); - patch_status_not_set_Q.reset(patch_id_q2); - -#ifdef CGAL_COREFINEMENT_POLYHEDRA_DEBUG - #warning: Factorize the orientation predicates. -#endif //CGAL_COREFINEMENT_POLYHEDRA_DEBUG - // handle case of coplanar facets - // We choose that a coplanar patch is classified like the other incident patch since they bound the same volume. - if ( are_triangles_coplanar_same_side_filtered(indices.first,indices.second,index_p1,index_q1,P1,Q1,nodes) ) //P1==Q1 - { - coplanar_patches_of_P.set(patch_id_p1); - coplanar_patches_of_Q.set(patch_id_q1); - coplanar_patches_of_P_for_union_and_intersection.set(patch_id_p1); - coplanar_patches_of_Q_for_union_and_intersection.set(patch_id_q1); - - CGAL_assertion( !are_triangles_coplanar_same_side_filtered(indices.first,indices.second,index_p2,index_q2,P2,Q2,nodes) ); - - bool Q2_is_between_P1P2 = OOP::sorted_around_edge_filtered(indices.first,indices.second,index_p1,index_p2,index_q2,P1,P2,Q2,nodes,ppmap); - if ( Q2_is_between_P1P2 ) is_patch_inside_P.set(patch_id_q2); //case 1 - else is_patch_inside_Q.set(patch_id_p2); //case 2 - continue; - } - else{ - if ( are_triangles_coplanar_same_side_filtered(indices.first,indices.second,index_p1,index_q2,P1,Q2,nodes) ) //P1==Q2 - { - CGAL_assertion( index_p1!=index_p2 || index_p1==-1 ); - coplanar_patches_of_P.set(patch_id_p1); - coplanar_patches_of_Q.set(patch_id_q2); - bool Q1_is_between_P1P2 = OOP::sorted_around_edge_filtered(indices.first,indices.second,index_p1,index_p2,index_q1,P1,P2,Q1,nodes,ppmap); - if ( Q1_is_between_P1P2 ) - { // case 3 - is_patch_inside_P.set(patch_id_q1); - is_patch_inside_Q.set(patch_id_p2); - } //else case 4 - continue; - } - else - { - if ( are_triangles_coplanar_same_side_filtered(indices.first,indices.second,index_p2,index_q1,P2,Q1,nodes) ) //P2==Q1 - { - coplanar_patches_of_P.set(patch_id_p2); - coplanar_patches_of_Q.set(patch_id_q1); - bool Q2_is_between_P1P2 = OOP::sorted_around_edge_filtered(indices.first,indices.second,index_p1,index_p2,index_q2,P1,P2,Q2,nodes,ppmap); - if ( Q2_is_between_P1P2 ) - { //case 5 - is_patch_inside_P.set(patch_id_q2); - is_patch_inside_Q.set(patch_id_p1); - } // else case 6 - continue; - } - else{ - if ( are_triangles_coplanar_same_side_filtered(indices.first,indices.second,index_p2,index_q2,P2,Q2,nodes) ) //P2==Q2 - { - coplanar_patches_of_P.set(patch_id_p2); - coplanar_patches_of_Q.set(patch_id_q2); - coplanar_patches_of_P_for_union_and_intersection.set(patch_id_p2); - coplanar_patches_of_Q_for_union_and_intersection.set(patch_id_q2); - bool Q1_is_between_P1P2 = OOP::sorted_around_edge_filtered(indices.first,indices.second,index_p1,index_p2,index_q1,P1,P2,Q1,nodes,ppmap); - if ( Q1_is_between_P1P2 ) is_patch_inside_P.set(patch_id_q1); //case 7 - else is_patch_inside_Q.set(patch_id_p1); //case 8 - continue; - } - } - } - } -#ifdef CGAL_COREFINEMENT_POLYHEDRA_DEBUG - #warning At some point we should have a check if a patch status is already set, what we do is consistant otherwise --> ambiguous -#endif //CGAL_COREFINEMENT_POLYHEDRA_DEBUG - - CGAL_assertion( - ( index_p1 == -1 ? nodes.to_exact(get(ppmap,P1)): nodes.exact_node(index_p1) ) != - ( index_q1 == -1 ? nodes.to_exact(get(ppmap,Q1)): nodes.exact_node(index_q1) ) - && - ( index_p2 == -1 ? nodes.to_exact(get(ppmap,P2)): nodes.exact_node(index_p2) ) != - ( index_q1 == -1 ? nodes.to_exact(get(ppmap,Q1)): nodes.exact_node(index_q1) ) - && - ( index_p1 == -1 ? nodes.to_exact(get(ppmap,P1)): nodes.exact_node(index_p1) ) != - ( index_q2 == -1 ? nodes.to_exact(get(ppmap,Q2)): nodes.exact_node(index_q2) ) - && - ( index_p2 == -1 ? nodes.to_exact(get(ppmap,P2)): nodes.exact_node(index_p2) ) != - ( index_q2 == -1 ? nodes.to_exact(get(ppmap,Q2)): nodes.exact_node(index_q2) ) - ); - - bool Q1_is_between_P1P2 = OOP::sorted_around_edge_filtered(indices.first,indices.second,index_p1,index_p2,index_q1,P1,P2,Q1,nodes,ppmap); - bool Q2_is_between_P1P2 = OOP::sorted_around_edge_filtered(indices.first,indices.second,index_p1,index_p2,index_q2,P1,P2,Q2,nodes,ppmap); - - if ( Q1_is_between_P1P2 ){ - is_patch_inside_P.set(patch_id_q1); - if( Q2_is_between_P1P2 ) - { - is_patch_inside_P.set(patch_id_q2); - bool P1_is_between_Q1Q2 = OOP::sorted_around_edge_filtered(indices.first,indices.second,index_q1,index_q2,index_p1,Q1,Q2,P1,nodes,ppmap); - if (!P1_is_between_Q1Q2){ - // case (a4) - // poly_first - poly_second = P1Q1 U Q2P2 - // poly_second - poly_first = {0} - // poly_first \cap poly_second = Q1Q2 - // opposite( poly_first U poly_second ) = P2P1 - impossible_operation.set(P_MINUS_Q); // P-Q is non-manifold - } - else{ - // case (b4) - // poly_first - poly_second = Q2Q1 - // poly_second - poly_first = P2P1 - // poly_first \cap poly_second = P1Q2 U Q1P2 - // opposite( poly_first U poly_second ) = {O} - is_patch_inside_Q.set(patch_id_p1); - is_patch_inside_Q.set(patch_id_p2); - impossible_operation.set(P_INTER_Q); // P \cap Q is non-manifold - } - } - else - { - //case (c4) - // poly_first - poly_second = P1Q1 - // poly_second - poly_first = P2Q2 - // poly_first \cap poly_second = Q1P2 - // opposite( poly_first U poly_second ) = Q2P1 - if ( is_dangling_edge(indices.first, indices.second, first_hedge, is_node_of_degree_one) || - is_dangling_edge(indices.first, indices.second, second_hedge, is_node_of_degree_one) ) - { - impossible_operation.set(); - return; - } - is_patch_inside_Q.set(patch_id_p2); - } - } - else - { - if( Q2_is_between_P1P2 ) - { - //case (d4) - // poly_first - poly_second = Q2P2 - // poly_second - poly_first = Q1P1 - // poly_first \cap poly_second = P1Q2 - // opposite( poly_first U poly_second ) = P2Q1 - if ( is_dangling_edge(indices.first, indices.second, first_hedge, is_node_of_degree_one) || - is_dangling_edge(indices.first, indices.second, second_hedge, is_node_of_degree_one) ) - { - impossible_operation.set(); - return; - } - is_patch_inside_P.set(patch_id_q2); - is_patch_inside_Q.set(patch_id_p1); - } - else - { - bool P1_is_between_Q1Q2 = OOP::sorted_around_edge_filtered(indices.first,indices.second,index_q1,index_q2,index_p1,Q1,Q2,P1,nodes,ppmap); - if (!P1_is_between_Q1Q2){ - //case (e4) - // poly_first - poly_second = P1P2 - // poly_second - poly_first = Q1Q2 - // poly_first \cap poly_second = {0} - // opposite( poly_first U poly_second ) = P2Q1 U Q2P1 - impossible_operation.set(P_UNION_Q); // P U Q is non-manifold - } - else{ - //case (f4) - is_patch_inside_Q.set(patch_id_p1); - is_patch_inside_Q.set(patch_id_p2); - // poly_first - poly_second = {0} - // poly_second - poly_first = Q1P1 U P2Q2 - // poly_first \cap poly_second = P1P2 - // opposite( poly_first U poly_second ) = Q2Q1 - impossible_operation.set(Q_MINUS_P); // Q - P is non-manifold - } - } - } - } - } - - -/////////////////////////////////////////////// -//////////////////////END////////////////////// -/////////////////////////////////////////////// - - // (2-b) Classify isolated surface patches wrt the other support polyhedron -#ifdef CGAL_COREFINEMENT_POLYHEDRA_DEBUG - #warning this does not work with open polyhedra - #warning this should not be done if we have surfaces with boundaries!!! ask the user a flag? -#endif //CGAL_COREFINEMENT_POLYHEDRA_DEBUG - typedef Side_of_triangle_mesh Inside_poly_test; - -#ifdef CGAL_COREFINEMENT_POLYHEDRA_DEBUG - #warning stop using next_marked_halfedge_around_target_vertex and create lists of halfedges instead? -#endif - - if ( patch_status_not_set_P.any() ) - { - CGAL::Bounded_side in_Q = is_Q_inside_out ? ON_UNBOUNDED_SIDE : ON_BOUNDED_SIDE; - - Inside_poly_test inside_Q(*Q_ptr, ppmap); - for (typename Polyhedron::Face_iterator fit=P_ptr->facets_begin(), - fit_end=P_ptr->facets_end(); - fit!=fit_end; ++fit) - { - std::size_t patch_id=P_patch_ids[ get(P_facet_id_pmap, fit) ]; - if ( patch_status_not_set_P.test( patch_id ) ) - { - patch_status_not_set_P.reset( patch_id ); - CGAL::Bounded_side position = inside_Q( get(ppmap,fit->halfedge()->vertex()) ); - if ( position == in_Q ) - is_patch_inside_Q.set(patch_id); - else - if ( position == ON_BOUNDARY ) - { - if (coplanar_facets_P.test(get(P_facet_id_pmap, fit))) - { - coplanar_patches_of_P.set(patch_id); - coplanar_patches_of_P_for_union_and_intersection.set(patch_id); - } - else - { - Vertex_handle vn = fit->halfedge()->opposite()->vertex(); - Bounded_side other_position = inside_Q( get(ppmap, vn) ); - if (other_position==ON_BOUNDARY) - { - // \todo improve this part which is not robust with a kernel with inexact constructions. - other_position = inside_Q(midpoint(get(ppmap, vn), - get(ppmap, fit->halfedge()->vertex()) )); - } - if ( other_position == in_Q ) - is_patch_inside_Q.set(patch_id); - } - } - - if ( patch_status_not_set_P.none() ) break; - } - } - } - - if ( patch_status_not_set_Q.any() ) - { - CGAL::Bounded_side in_P = is_P_inside_out ? ON_UNBOUNDED_SIDE : ON_BOUNDED_SIDE; - - Inside_poly_test inside_P(*P_ptr, ppmap); - for (typename Polyhedron::Face_iterator fit=Q_ptr->facets_begin(), - fit_end=Q_ptr->facets_end(); - fit!=fit_end; ++fit) - { - std::size_t patch_id=Q_patch_ids[ get(Q_facet_id_pmap, fit) ]; - if ( patch_status_not_set_Q.test( patch_id ) ) - { - patch_status_not_set_Q.reset( patch_id ); - Bounded_side position = inside_P( get(ppmap,fit->halfedge()->vertex()) ); - if ( position == in_P ) - is_patch_inside_P.set(patch_id); - else - if ( position == ON_BOUNDARY ) - { - if (coplanar_facets_Q.test(get(Q_facet_id_pmap, fit))) - { - coplanar_patches_of_Q.set(patch_id); - coplanar_patches_of_Q_for_union_and_intersection.set(patch_id); - } - else - { - Vertex_handle vn = fit->halfedge()->opposite()->vertex(); - Bounded_side other_position = inside_P( get(ppmap, vn) ); - if (other_position==ON_BOUNDARY) - { - // \todo improve this part which is not robust with a kernel with inexact constructions. - other_position = inside_P(midpoint(get(ppmap, vn), - get(ppmap, fit->halfedge()->vertex()) )); - } - if ( other_position == in_P ) - is_patch_inside_P.set(patch_id); - } - } - if ( patch_status_not_set_Q.none() ) break; - } - } - } - - /// \todo There might be some patches for which the status is unknown, we need to use - /// for example the centroid of the facet to decide, but this would require an exact - /// inside-polyhedron object or to work with points at endpoints of the intervals. - /// See SL_TMP_ASSERT - //to maintain a polyhedron halfedge on each polyline + pair - //with first = "is the key (pair) was reversed?" and second is the number of edges +1 in the polyline - //typedef std::map< std::pair, std::pair< std::map,std::pair > > An_edge_per_polyline_map; - -#ifdef CGAL_COREFINEMENT_POLYHEDRA_DEBUG - #warning add a mechanism to handle the patches independantly (for example calculating the volume without building the polyhedron) \ - This can be done by using a functor to which we give the bitset, the polyhedra and one facet per patch? -#endif // CGAL_COREFINEMENT_POLYHEDRA_DEBUG - - #ifdef CGAL_COREFINEMENT_DEBUG - std::cout << "is_patch_inside_Q " << is_patch_inside_Q << "\n"; - std::cout << "is_patch_inside_P " << is_patch_inside_P << "\n"; - std::cout << "coplanar_patches_of_P " << coplanar_patches_of_P << "\n"; - std::cout << "coplanar_patches_of_Q " << coplanar_patches_of_Q << "\n"; - std::cout << "coplanar_patches_of_P_for_union_and_intersection " << coplanar_patches_of_P_for_union_and_intersection << "\n"; - std::cout << "coplanar_patches_of_Q_for_union_and_intersection " << coplanar_patches_of_Q_for_union_and_intersection << "\n"; - std::cout << "Size of patches of P: "; - std::copy(P_patch_sizes.rbegin(), P_patch_sizes.rend(), std::ostream_iterator(std::cout," ") ); - std::cout << "\n"; - std::cout << "Size of patches of Q: "; - std::copy(Q_patch_sizes.rbegin(), Q_patch_sizes.rend(), std::ostream_iterator(std::cout," ") ); - std::cout << "\n"; - #endif - - //backup an halfedge per polyline - std::vector P_polylines, Q_polylines; - std::vector polyline_lengths; - - for (typename An_edge_per_polyline_map::const_iterator - it=an_edge_per_polyline.begin(), - it_end=an_edge_per_polyline.end(); - it!=it_end;++it) - { - const std::pair& polyline_info=it->second.second; - - Halfedge_handle qhedge = it->second.first.find( Q_ptr )->second; - Halfedge_handle phedge = it->second.first.find( P_ptr )->second; - - if( polyline_info.first ){ - phedge=phedge->opposite(); - qhedge=qhedge->opposite(); - } - - P_polylines.push_back(phedge); - Q_polylines.push_back(qhedge); - polyline_lengths.push_back(polyline_info.second+1); - } - - //store the patch description in a container to avoid recomputing it several times - Patch_container patches_of_P( P_ptr, P_patch_ids, P_facet_id_pmap, border_halfedges, P_nb_patches), - patches_of_Q( Q_ptr, Q_patch_ids, Q_facet_id_pmap, border_halfedges, Q_nb_patches); - - // for each boolean operation, define two bitsets of patches contributing - // to the result - std::vector< boost::dynamic_bitset<> > patches_of_P_used(4); - std::vector< boost::dynamic_bitset<> > patches_of_Q_used(4); - - /// handle the bitset for the union - if ( !impossible_operation.test(P_UNION_Q) && desired_output[P_UNION_Q] ) - { - //define patches to import from P - patches_of_P_used[P_UNION_Q] = ~is_patch_inside_Q - coplanar_patches_of_P; - //define patches to import from Q - patches_of_Q_used[P_UNION_Q] = ~is_patch_inside_P - coplanar_patches_of_Q; - //handle coplanar patches - if (coplanar_patches_of_P.any()) - { - if (desired_output[P_UNION_Q]==Q_ptr) - patches_of_Q_used[P_UNION_Q] |= coplanar_patches_of_Q_for_union_and_intersection; - else - patches_of_P_used[P_UNION_Q] |= coplanar_patches_of_P_for_union_and_intersection; - } - } - - /// handle the bitset for the intersection - if ( !impossible_operation.test(P_INTER_Q) && desired_output[P_INTER_Q] ) - { - //define patches to import from P - patches_of_P_used[P_INTER_Q] = is_patch_inside_Q; - //define patches to import from Q - patches_of_Q_used[P_INTER_Q] = is_patch_inside_P; - //handle coplanar patches - if (coplanar_patches_of_P.any()) - { - if (desired_output[P_INTER_Q]==Q_ptr) - patches_of_Q_used[P_INTER_Q] |= coplanar_patches_of_Q_for_union_and_intersection; - else - patches_of_P_used[P_INTER_Q] |= coplanar_patches_of_P_for_union_and_intersection; - } - } - - /// handle the bitset for P-Q - if ( !impossible_operation.test(P_MINUS_Q) && desired_output[P_MINUS_Q] ) - { - //define patches to import from P - patches_of_P_used[P_MINUS_Q] = (~is_patch_inside_Q - coplanar_patches_of_P); - //define patches to import from Q - patches_of_Q_used[P_MINUS_Q] = is_patch_inside_P; - //handle coplanar patches - if (coplanar_patches_of_P.any()) - { - if (desired_output[P_MINUS_Q]==Q_ptr) - patches_of_Q_used[P_MINUS_Q] |= ~coplanar_patches_of_Q_for_union_and_intersection & coplanar_patches_of_Q; - else - patches_of_P_used[P_MINUS_Q] |= ~coplanar_patches_of_P_for_union_and_intersection & coplanar_patches_of_P; - } - } - - /// handle the bitset for Q-P - if ( !impossible_operation.test(Q_MINUS_P) && desired_output[Q_MINUS_P] ) - { - //define patches to import from P - patches_of_P_used[Q_MINUS_P] = is_patch_inside_Q; - //define patches to import from Q - patches_of_Q_used[Q_MINUS_P] = ~is_patch_inside_P - coplanar_patches_of_Q; - //handle coplanar patches - if (coplanar_patches_of_P.any()) - { - if (desired_output[Q_MINUS_P]==Q_ptr) - patches_of_Q_used[Q_MINUS_P] |= ~coplanar_patches_of_Q_for_union_and_intersection & coplanar_patches_of_Q; - else - patches_of_P_used[Q_MINUS_P] |= ~coplanar_patches_of_P_for_union_and_intersection & coplanar_patches_of_P; - } - } - - #ifdef CGAL_COREFINEMENT_DEBUG - std::cout << "patches_of_P_used[P_UNION_Q] " << patches_of_P_used[P_UNION_Q] << "\n"; - std::cout << "patches_of_Q_used[P_UNION_Q] " << patches_of_Q_used[P_UNION_Q] << "\n"; - std::cout << "patches_of_P_used[P_INTER_Q] " << patches_of_P_used[P_INTER_Q] << "\n"; - std::cout << "patches_of_Q_used[P_INTER_Q] " << patches_of_Q_used[P_INTER_Q] << "\n"; - std::cout << "patches_of_P_used[P_MINUS_Q] " << patches_of_P_used[P_MINUS_Q] << "\n"; - std::cout << "patches_of_Q_used[P_MINUS_Q] " << patches_of_Q_used[P_MINUS_Q] << "\n"; - std::cout << "patches_of_P_used[Q_MINUS_P] " << patches_of_P_used[Q_MINUS_P] << "\n"; - std::cout << "patches_of_Q_used[Q_MINUS_P] " << patches_of_Q_used[Q_MINUS_P] << "\n"; - #endif // CGAL_COREFINEMENT_DEBUG - // Schedule the order in which the different boolean operations should be - // done. First operations are those filling polyhedra different - // from P and Q, then the one modifying P and finally the one - // modifying Q. - std::vector out_of_place_operations; - Boolean_operation inplace_operation_P=NONE, inplace_operation_Q=NONE; - for (int i=0;i<4;++i) - { - Boolean_operation operation=enum_cast(i); - - if (!desired_output[operation] || impossible_operation.test(operation)) - continue; - - if (desired_output[operation]==P_ptr) - inplace_operation_P=operation; - else - if (desired_output[operation]==Q_ptr) - inplace_operation_Q=operation; - else - out_of_place_operations.push_back(operation); - } - - /// first handle operations in a polyhedron that is neither P nor Q - BOOST_FOREACH(Boolean_operation operation, out_of_place_operations) - { - Polyhedron* ouput_ptr = *desired_output[operation]; - CGAL_assertion(P_ptr!=ouput_ptr && Q_ptr!=ouput_ptr); - - Intersection_polylines polylines(P_polylines, Q_polylines, polyline_lengths); - // skip the import of polylines only incident to patch(es) - // not used by the current operation - fill_polylines_to_skip( - polylines, P_patch_ids, Q_patch_ids, - patches_of_P_used[operation], patches_of_Q_used[operation], - P_facet_id_pmap, Q_facet_id_pmap - ); - - std::vector shared_halfedges; - fill_new_polyhedron( - *ouput_ptr, - patches_of_P_used[operation], patches_of_Q_used[operation], - patches_of_P, patches_of_Q, - operation == Q_MINUS_P, operation == P_MINUS_Q, - polylines, - border_halfedges, - std::back_inserter(shared_halfedges) - ); - BOOST_FOREACH(Halfedge_handle h, shared_halfedges){ - put(edge_mark_pmap, std::make_pair(h,ouput_ptr),true); - put(edge_mark_pmap, std::make_pair(h->opposite(),ouput_ptr),true); - } - } - - Edge_map disconnected_patches_hedge_to_Qhedge; - - /// handle the operations updating P and/or Q - if ( inplace_operation_P!=NONE ) - { - CGAL_assertion( *desired_output[inplace_operation_P] == P_ptr ); - - if ( inplace_operation_Q!=NONE) - { - // operation in P with removal (and optinally inside-out) delayed - // First backup the border edges of patches to be used - Patch_container tmp_patches_of_P(P_ptr, - patches_of_P.patch_ids, - patches_of_P.facet_id_pmap, - patches_of_P.border_halfedges, - patches_of_P.patches.size()); - boost::dynamic_bitset<> patches_of_P_removed = ~patches_of_P_used[inplace_operation_P]; - for (std::size_t i = patches_of_P_removed.find_first(); - i < patches_of_P_removed.npos; - i = patches_of_P_removed.find_next(i)) - { - // we are only interested by patch border halfedges so - // squeeze the auto-filling mechanism - tmp_patches_of_P.patches[i].is_initialized=true; - tmp_patches_of_P.patches[i].patch_border_halfedges= - patches_of_P[i].patch_border_halfedges; - } - - Intersection_polylines polylines_in_P( - P_polylines, Q_polylines, polyline_lengths); - Intersection_polylines polylines_in_Q=polylines_in_P; - fill_polylines_to_skip( - polylines_in_P, P_patch_ids, Q_patch_ids, - patches_of_P_used[inplace_operation_P], - patches_of_Q_used[inplace_operation_P], - P_facet_id_pmap, Q_facet_id_pmap); - fill_polylines_to_skip( - polylines_in_Q, P_patch_ids, Q_patch_ids, - patches_of_P_used[inplace_operation_Q], - patches_of_Q_used[inplace_operation_Q], - P_facet_id_pmap, Q_facet_id_pmap); - // force the initialization of the patches of P used - // for the operation in Q before P is modified - for (std::size_t i=patches_of_P_used[inplace_operation_Q].find_first(); - i < patches_of_P_used[inplace_operation_Q].npos; - i = patches_of_P_used[inplace_operation_Q].find_next(i)) - { - patches_of_P[i]; - } - // Operation in P: disconnect patches not use and append the one from Q - compute_inplace_operation_delay_removal_and_insideout( - P_ptr, - patches_of_P_used[inplace_operation_P], patches_of_Q_used[inplace_operation_P], - patches_of_P, patches_of_Q, - inplace_operation_P == P_MINUS_Q || inplace_operation_P == Q_MINUS_P, - polylines_in_P, disconnected_patches_hedge_to_Qhedge); - // Operation in Q: discard patches and append the one from Q - CGAL_assertion( *desired_output[inplace_operation_Q] == Q_ptr ); - compute_inplace_operation( Q_ptr, - patches_of_Q_used[inplace_operation_Q], - patches_of_P_used[inplace_operation_Q], - patches_of_Q, patches_of_P, - inplace_operation_Q==P_MINUS_Q, - inplace_operation_Q==Q_MINUS_P, - disconnected_patches_hedge_to_Qhedge); - // remove polylines only on the border of patches not kept in Q - if (polylines_in_Q.to_skip.any()) - remove_unused_polylines(Q_ptr, - ~patches_of_Q_used[inplace_operation_Q], - patches_of_Q); - // now remove patches temporarily kept in P - remove_disconnected_patches(*P_ptr, patches_of_P, patches_of_P_removed); - // remove polylines only on the border of patches not kept in P - if (polylines_in_P.to_skip.any()) - remove_unused_polylines(P_ptr, - ~patches_of_P_used[inplace_operation_P], - tmp_patches_of_P); - // finally reverse orientation of P if needed - if (inplace_operation_P == Q_MINUS_P) - CGAL::Polygon_mesh_processing::reverse_face_orientations(*P_ptr); - } - else{ - /// handle the operation updating only P - CGAL_assertion( *desired_output[inplace_operation_P] == P_ptr ); - Intersection_polylines polylines( - P_polylines, Q_polylines, polyline_lengths); - fill_polylines_to_skip( - polylines, P_patch_ids, Q_patch_ids, - patches_of_P_used[inplace_operation_P], - patches_of_Q_used[inplace_operation_P], - P_facet_id_pmap, Q_facet_id_pmap - ); - - compute_inplace_operation( - P_ptr, - patches_of_P_used[inplace_operation_P], - patches_of_Q_used[inplace_operation_P], - patches_of_P, patches_of_Q, - inplace_operation_P == Q_MINUS_P, - inplace_operation_P == P_MINUS_Q, - polylines - ); - // remove polylines only on the border of patches not kept - if (polylines.to_skip.any()) - remove_unused_polylines(P_ptr, - ~patches_of_P_used[inplace_operation_P], - patches_of_P); - } - } - else - if ( inplace_operation_Q!=NONE ) - { - /// handle the operation updating only Q - CGAL_assertion( *desired_output[inplace_operation_Q] == Q_ptr ); - Intersection_polylines polylines( - Q_polylines, P_polylines, polyline_lengths); - fill_polylines_to_skip( - polylines, Q_patch_ids, P_patch_ids, - patches_of_Q_used[inplace_operation_Q], - patches_of_P_used[inplace_operation_Q], - Q_facet_id_pmap, P_facet_id_pmap - ); - - compute_inplace_operation( Q_ptr, - patches_of_Q_used[inplace_operation_Q], - patches_of_P_used[inplace_operation_Q], - patches_of_Q, patches_of_P, - inplace_operation_Q==P_MINUS_Q, - inplace_operation_Q==Q_MINUS_P, - polylines); - - // remove polylines only on the border of patches not kept - if (polylines.to_skip.any()) - remove_unused_polylines(Q_ptr, - ~patches_of_Q_used[inplace_operation_Q], - patches_of_Q); - } - } -}; - -} } // end of namespace CGAL::Corefinement - -#include - -#endif // CGAL_INTERNAL_COREFINEMENT_POLYHEDRA_OUTPUT_BUILDER_H diff --git a/Operations_on_polyhedra/include/CGAL/internal/corefinement/Polyhedron_constness_types.h b/Operations_on_polyhedra/include/CGAL/internal/corefinement/Polyhedron_constness_types.h deleted file mode 100644 index 9c76535af3a..00000000000 --- a/Operations_on_polyhedra/include/CGAL/internal/corefinement/Polyhedron_constness_types.h +++ /dev/null @@ -1,83 +0,0 @@ -// Copyright (c) 2011 GeometryFactory (France). -// All rights reserved. -// -// This file is part of CGAL (www.cgal.org). -// You can redistribute it and/or modify it under the terms of the GNU -// General Public License as published by the Free Software Foundation, -// either version 3 of the License, or (at your option) any later version. -// -// Licensees holding a valid commercial license may use this file in -// accordance with the commercial license agreement provided with the software. -// -// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE -// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. -// -// $URL$ -// $Id$ -// SPDX-License-Identifier: GPL-3.0+ -// -// -// Author(s) : Sebastien Loriot - -#ifndef CGAL_INTERNAL_POLYHEDRON_CONSTNESS_TYPES_H -#define CGAL_INTERNAL_POLYHEDRON_CONSTNESS_TYPES_H - -#include - - -namespace CGAL { -namespace internal_IOP{ - -template -struct Polyhedron_types; - -template -struct Polyhedron_types{ - typedef Polyhedron& Polyhedron_ref; - typedef typename Polyhedron::Halfedge_handle Halfedge_handle; - typedef typename Polyhedron::Halfedge_iterator Halfedge_iterator; - typedef typename Polyhedron::Facet_iterator Facet_iterator; - typedef typename Polyhedron::Facet_handle Facet_handle; - typedef typename Polyhedron::Vertex_handle Vertex_handle; - typedef typename Polyhedron::Vertex Vertex; - typedef typename Polyhedron::Halfedge Halfedge; - typedef typename Polyhedron::Facet Facet; -}; - -template -struct Polyhedron_types{ - typedef const Polyhedron& Polyhedron_ref; - typedef typename Polyhedron::Halfedge_const_handle Halfedge_handle; - typedef typename Polyhedron::Halfedge_const_iterator Halfedge_iterator; - typedef typename Polyhedron::Facet_const_iterator Facet_iterator; - typedef typename Polyhedron::Facet_const_handle Facet_handle; - typedef typename Polyhedron::Vertex_const_handle Vertex_handle; - typedef const typename Polyhedron::Vertex Vertex; - typedef const typename Polyhedron::Halfedge Halfedge; - typedef const typename Polyhedron::Facet Facet; -}; - -#include -#include -#include - -template -struct Polyhedron_types_with_mpl -{ - typedef typename boost::remove_const::type Polyhedron; - typedef typename boost::mpl::if_< boost::is_const, - typename Polyhedron::Face_const_handle, - typename Polyhedron::Face_handle>::type Face_handle; - typedef typename boost::mpl::if_< boost::is_const, - typename Polyhedron::Face_const_iterator, - typename Polyhedron::Face_iterator>::type Face_iterator; - typedef typename boost::mpl::if_< boost::is_const, - typename Polyhedron::Halfedge_const_handle, - typename Polyhedron::Halfedge_handle>::type Halfedge_handle; - typedef Face_handle Facet_handle; - typedef Face_iterator Facet_iterator; -}; - -} } //namespace CGAL::internal_IOP - -#endif //CGAL_INTERNAL_POLYHEDRON_CONSTNESS_TYPES_H diff --git a/Operations_on_polyhedra/include/CGAL/internal/corefinement/connected_components.h b/Operations_on_polyhedra/include/CGAL/internal/corefinement/connected_components.h deleted file mode 100644 index 324e6e027e8..00000000000 --- a/Operations_on_polyhedra/include/CGAL/internal/corefinement/connected_components.h +++ /dev/null @@ -1,344 +0,0 @@ -// Copyright (c) 2011, 2015 GeometryFactory (France). -// All rights reserved. -// -// This file is part of CGAL (www.cgal.org). -// You can redistribute it and/or modify it under the terms of the GNU -// General Public License as published by the Free Software Foundation, -// either version 3 of the License, or (at your option) any later version. -// -// Licensees holding a valid commercial license may use this file in -// accordance with the commercial license agreement provided with the software. -// -// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE -// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. -// -// $URL$ -// $Id$ -// SPDX-License-Identifier: GPL-3.0+ -// -// -// Author(s) : Sebastien Loriot and Andreas Fabri - -#ifndef CGAL_INTERNAL_POLYHEDRON_SUBSET_EXTRACTION_H -#define CGAL_INTERNAL_POLYHEDRON_SUBSET_EXTRACTION_H - -#include - - -#include -#include - -#include - -#include -#include - -#include -#include -#include -#include -#include - -namespace CGAL { - namespace internal{ - namespace corefinement{ - -template -struct Compare_handle_ptr{ - typedef typename Polyhedron::Facet_const_handle Facet_const_handle; - typedef typename Polyhedron::Vertex_const_handle Vertex_const_handle; - - bool operator()(Facet_const_handle f1,Facet_const_handle f2) const { - return &(*f1) < &(*f2); - } - - bool operator()(Vertex_const_handle v1,Vertex_const_handle v2) const { - return &(*v1) < &(*v2); - } -}; - -struct Dummy_true{ - template - bool operator()(T) const {return true;} -}; - -template -class Build_polyhedron_subset : public ::CGAL::Modifier_base { - typedef typename Polyhedron::Facet_const_handle Facet_const_handle; - typedef typename Polyhedron::Vertex_const_handle Vertex_const_handle; - typedef typename Polyhedron::Halfedge_const_handle Halfedge_const_handle; - - typedef typename HDS::Vertex::Point Point; - std::list points; - std::list< std::vector > facets; - - template - typename Polyhedron::Halfedge_const_handle get_facet_halfedge(Facet_iterator facet_it) const - { - return (*facet_it)->halfedge(); - } - - typename Polyhedron::Halfedge_const_handle get_facet_halfedge(typename Polyhedron::Facet_const_handle facet) const - { - return facet->halfedge(); - } - -public: - template - Build_polyhedron_subset(const Polyhedron&,Facets_const_iterator begin,Facets_const_iterator end) - { - typedef std::map > Vertices; - Vertices vertices; - unsigned int index=0; - //get vertices and get face description relatively to the restricted set of vertices - for (Facets_const_iterator it=begin;it!=end;++it) - { - Halfedge_const_handle start=get_facet_halfedge(it); - Halfedge_const_handle curr=start; - facets.push_back(std::vector()); - std::vector& indices = facets.back(); - do{ - bool is_new_vertex; - typename Vertices::iterator it_vertex; - ::CGAL::cpp11::tie(it_vertex,is_new_vertex)=vertices.insert(std::make_pair(curr->vertex(),index)); - if (is_new_vertex) { - ++index; - points.push_back(curr->vertex()); - } - indices.push_back(it_vertex->second); - curr=curr->next(); - }while(curr!=start); - } - } - - void operator()( HDS& hds) { - ::CGAL::Polyhedron_incremental_builder_3 B( hds, true); - B.begin_surface( points.size(), facets.size() ); - for (typename std::list::iterator it=points.begin();it!=points.end();++it) - B.add_vertex((*it)->point()); - for (typename std::list< std::vector >::iterator - it=facets.begin();it!=facets.end();++it) - { - B.begin_facet(); - for (std::vector::iterator it_i=it->begin();it_i!=it->end();++it_i) - B.add_vertex_to_facet(*it_i); - B.end_facet(); - } - B.end_surface(); - } -}; - - - -template -void extract_connected_components( - Polyhedron& P, - const Adjacency_criterium& adjacent, - CGAL::Union_find::Facet_handle>& uf, - Face_to_UF_handle_map& map_f2h, - Result& result - ) -{ - typedef typename internal_IOP::Polyhedron_types_with_mpl::Facet_handle Facet_handle; - typedef typename internal_IOP::Polyhedron_types_with_mpl::Facet_iterator Facet_iterator; - typedef typename internal_IOP::Polyhedron_types_with_mpl::Halfedge_handle Halfedge_handle; - typedef ::CGAL::Union_find UF; - typedef typename UF::handle UF_handle; - typedef typename UF::iterator UF_iterator; - -//init union-find: each facet is in its own set - for (Facet_iterator it=P.facets_begin();it!=P.facets_end();++it){ - map_f2h.insert(std::make_pair(it,uf.make_set(it))); - } -//merge 2 facets if they share a common edge - for (Facet_iterator it=P.facets_begin();it!=P.facets_end();++it){ - Facet_handle facet=it; - - UF_handle current=map_f2h.find(it)->second; - std::vector neighbors; - Halfedge_handle hedge=facet->halfedge(); - do - { - neighbors.push_back( hedge->opposite() ); - hedge=hedge->next(); - } - while(hedge!=facet->halfedge()); - - std::size_t nb_edges=neighbors.size(); - for (std::size_t i=0;iis_border() ) continue; - UF_handle neigh=map_f2h.find(neighbors[i]->facet())->second; - if ( adjacent(neighbors[i]) && !uf.same_set(current,neigh) ){ - uf.unify_sets(current,neigh); - } - } - } - -//recover merged sets - for (UF_iterator it=uf.begin();it!=uf.end();++it){ - UF_handle master=uf.find(it); - result[*master].push_back(*it); - } -} - -template -void extract_connected_components(const Polyhedron& P,const Adjacency_criterium& adjacent,Output_iterator out) -{ - typedef typename Polyhedron::Facet_const_handle Facet_const_handle; - typedef ::CGAL::Union_find UF; - typedef typename UF::handle UF_handle; - typedef std::map,Compare_handle_ptr > Result; - typedef std::map > Facet_to_handle_map; - - UF uf; - Facet_to_handle_map map_f2h; - Result result; - - extract_connected_components(P,adjacent,uf,map_f2h,result); - - for (typename Result::iterator it=result.begin();it!=result.end();++it) - { - typedef std::list Facets; - const Facets& facets=it->second; - Polyhedron new_poly; - Build_polyhedron_subset modifier(new_poly,facets.begin(),facets.end()); - new_poly.delegate(modifier); - *out++=new_poly; - } -} - -template -void mark_connected_components(Polyhedron& P, const Adjacency_criterium& adjacent, Face_marker& face_marker) -{ - typedef typename Polyhedron::Facet_handle Facet_handle; - typedef ::CGAL::Union_find UF; - typedef typename UF::handle UF_handle; - typedef std::map,Compare_handle_ptr > Result; - typedef std::map > Facet_to_handle_map; - - UF uf; - Facet_to_handle_map map_f2h; - Result result; - - extract_connected_components(P,adjacent,uf,map_f2h,result); - - for (typename Result::iterator it=result.begin();it!=result.end();++it) - { - face_marker.start_new_connected_component(); - typedef std::list Facets; - const Facets& facets=it->second; - face_marker.mark(facets.begin(),facets.end()); - } -} - -template -OutputIterator -mark_connected_components(Polyhedron& P, const Adjacency_criterium& adjacent, Face_marker& face_marker, OutputIterator out) -{ - typedef typename Polyhedron::Facet_handle Facet_handle; - typedef ::CGAL::Union_find UF; - typedef typename UF::handle UF_handle; - typedef std::map,Compare_handle_ptr > Result; - typedef std::map > Facet_to_handle_map; - - UF uf; - Facet_to_handle_map map_f2h; - Result result; - - extract_connected_components(P,adjacent,uf,map_f2h,result); - - for (typename Result::iterator it=result.begin();it!=result.end();++it) - { - face_marker.start_new_connected_component(); - typedef std::list Facets; - const Facets& facets=it->second; - face_marker.mark(facets.begin(),facets.end()); - *out++=*facets.begin(); - } - return out; -} - -template -void extract_connected_components(const Polyhedron& P,Output_iterator out) -{ - extract_connected_components(P,Dummy_true(),out); -} - -template -std::size_t -init_facet_indices( - const Polyhedron& P, - Polyhedron_facet_index_map facet_index_map) -{ - //init facet indices - std::size_t index=0; - for (typename Polyhedron::Facet_const_iterator fit=P.facets_begin(), - fit_end=P.facets_end(); - fit!=fit_end; ++fit) - { - put(facet_index_map, fit, index++); - } - return index; -} - -// alternative method by propagation -template -std::size_t -mark_connected_components_v2( - const Polyhedron& P, - const Adjacency_criterium& adjacent, - Polyhedron_facet_index_map facet_index_map, - std::vector& patch_ids, - std::vector& patch_sizes) -{ - typedef typename Polyhedron::Halfedge_const_handle Halfedge_handle; - - std::size_t max_id=(std::numeric_limits::max)(); - patch_ids.clear(); - patch_ids.resize(P.size_of_facets(), max_id); - - //traversal of the facets to discover connected components - std::size_t patch_id=0; - for (typename Polyhedron::Facet_const_iterator fit=P.facets_begin(), - fit_end=P.facets_end(); - fit!=fit_end; ++fit) - { - std::size_t index=get(facet_index_map, fit); - if ( patch_ids[index]==max_id ) - { - patch_sizes.push_back(0); - patch_ids[index]=patch_id;// set patch id - ++(patch_sizes.back()); - std::vector queue; - if ( adjacent(fit->halfedge()) ) - queue.push_back( fit->halfedge()->opposite() ); - if ( adjacent(fit->halfedge()->next()) ) - queue.push_back( fit->halfedge()->next()->opposite() ); - if ( adjacent(fit->halfedge()->next()->next()) ) - queue.push_back( fit->halfedge()->next()->next()->opposite() ); - while (!queue.empty()) - { - Halfedge_handle h=queue.back(); - queue.pop_back(); - index=get(facet_index_map, h->facet()); - if ( patch_ids[index]!=max_id ) continue; - patch_ids[index]=patch_id; - ++(patch_sizes.back()); - if ( adjacent(h->next()) ) - queue.push_back( h->next()->opposite() ); - if ( adjacent(h->next()->next()) ) - queue.push_back( h->next()->next()->opposite() ); - } - ++patch_id; - } - } - - return patch_id; -} - -} } // end of namespace internal::corefinement - - -} // namespace CGAL - -#endif //CGAL_INTERNAL_POLYHEDRON_SUBSET_EXTRACTION_H diff --git a/Operations_on_polyhedra/include/CGAL/internal/corefinement/intersection_coplanar_triangles_3.h b/Operations_on_polyhedra/include/CGAL/internal/corefinement/intersection_coplanar_triangles_3.h deleted file mode 100644 index eb4136ef265..00000000000 --- a/Operations_on_polyhedra/include/CGAL/internal/corefinement/intersection_coplanar_triangles_3.h +++ /dev/null @@ -1,334 +0,0 @@ -// Copyright (c) 2011 GeometryFactory (France). -// All rights reserved. -// -// This file is part of CGAL (www.cgal.org). -// You can redistribute it and/or modify it under the terms of the GNU -// General Public License as published by the Free Software Foundation, -// either version 3 of the License, or (at your option) any later version. -// -// Licensees holding a valid commercial license may use this file in -// accordance with the commercial license agreement provided with the software. -// -// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE -// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. -// -// $URL$ -// $Id$ -// SPDX-License-Identifier: GPL-3.0+ -// -// -// Author(s) : Sebastien Loriot - -#ifndef CGAL_INTERNAL_INTERSECTION_COPLANAR_TRIANGLES_3_H -#define CGAL_INTERNAL_INTERSECTION_COPLANAR_TRIANGLES_3_H - -#include - - -#include //for Intersection_type -#include -#include -#include - -//TODO rename this file when doing proper integration -namespace CGAL{ -namespace internal_IOP{ - - -//intersection point of two coplanar triangles that keeps track of -//the location of that point onto the triangles. -template -struct Intersection_point_with_info -{ - typedef CGAL::Exact_predicates_exact_constructions_kernel Exact_kernel; - typedef IK Input_kernel; - typedef CGAL::Cartesian_converter Converter; - - Intersection_type type_1,type_2; //intersection type for 1st and 2nd facets - Halfedge_handle info_1,info_2; //halfedge providing primitive indicated by type_1 and type_2 - typename Exact_kernel::Point_3 point; //the geometric embedding of the intersection - PolyhedronPointPMap ppmap; // extract the point from a vertex. Only needed to be stored in the class for is_valid - - //constructor from a vertex of first triangle initialized inside the second triangle - Intersection_point_with_info(Halfedge_handle info1,Halfedge_handle info2, PolyhedronPointPMap ppmap): - type_1(VERTEX),type_2(FACET),info_1(info1),info_2(info2),ppmap(ppmap) - { - Converter converter; - point=converter(get(ppmap,info_1->vertex())); - } - - //constructor for intersection of edges. prev and curr are two points on an edge of the first facet (preserving the - //orientation of the facet). This edge is intersected by info2 from the second facet. - // - //The rational is the following: we first check whether curr and prev are on the same edge. I so we create - //an intersection point between two edges. Otherwise, the point is a vertex of the second facet included into - //the first facet. - // - //(V,F) : point initialy constructed - //(V,E) : (V,F) updated by get_orientation_and_update_info_2 (i.e lies on one edge) - //(V,V) : (V,E) updated by get_orientation_and_update_info_2 (i.e lies on two edges) - //(E,E) : created in the following function when prev and curr lie on the same edge - //(E,V) : (E,E) updated by get_orientation_and_update_info_2 (always done as lies on two edges) - //(E,F) : impossible - //(F,V) : detected when curr and prev and not on the same edge - //(F,E) : impossible - //(F,F) : impossible - // - Intersection_point_with_info(Intersection_point_with_info prev,Intersection_point_with_info curr, - Halfedge_handle info1,Halfedge_handle info2, PolyhedronPointPMap ppmap): - type_2(EDGE),info_2(info2),ppmap(ppmap) - { - #ifdef CGAL_DEBUG_COPLANAR_TRIANGLE_INTERSECTION - std::cout << "prev: "; prev.print_debug(); - std::cout << "curr: "; curr.print_debug(); std::cout << std::endl; - #endif //CGAL_DEBUG_COPLANAR_TRIANGLE_INTERSECTION - Converter converter; - if (prev.type_1==VERTEX && prev.info_1->next() == curr.info_1){ - CGAL_assertion(curr.type_1!=FACET); - type_1=EDGE; - info_1=curr.info_1; - } - else{ - if(curr.type_1==VERTEX && prev.info_1 == curr.info_1){ - CGAL_assertion(prev.type_1!=FACET); - type_1=EDGE; - info_1=curr.info_1; - } - else{ - if (curr.type_1==EDGE && prev.type_1==EDGE && curr.info_1==prev.info_1){ - type_1=EDGE; - info_1=curr.info_1; - } - else{ - //curr and prev are not on the same edge of the first facet. - //The intersection point to be computed is a VERTEX of the second facet - type_1=FACET; - info_1=info1; - type_2=VERTEX; - - //this is used to select the correct endpoint of the edge of the second facet - typename Exact_kernel::Collinear_3 is_collinear = Exact_kernel().collinear_3_object(); - if ( !is_collinear(prev.point,curr.point,converter(get(ppmap,info_2->vertex()) ) ) ){ - info_2=info_2->next()->next(); - CGAL_assertion( is_collinear(prev.point,curr.point,converter(get(ppmap,info_2->vertex())) ) ); - } - point = converter( get(ppmap, info_2->vertex()) ); - return; - } - } - } - - //handle degenerate case when two edges overlap - //at least one of the two vertex has already been found as a vertex of a facet. Here we set it for the second point - if(prev.type_2!=FACET && curr.type_2!=FACET && (prev.type_1==VERTEX || prev.type_2==VERTEX) && (curr.type_1==VERTEX || curr.type_2==VERTEX)){ - typename Exact_kernel::Collinear_3 is_collinear = Exact_kernel().collinear_3_object(); - if ( is_collinear(prev.point,curr.point,converter(get(ppmap, info_2->opposite()->vertex())) ) ){ - info_2=info_2->next()->next(); - type_2=VERTEX; - point = converter( get(ppmap, info_2->vertex()) ); - return; - } - if ( is_collinear(prev.point,curr.point,converter(get(ppmap, info_2->vertex())) ) ){ - type_2=VERTEX; - point = converter( get(ppmap, info_2->vertex()) ); - return; - } - } - - //handle regular intersection of two edges - typename Exact_kernel::Construct_line_3 line_3=Exact_kernel().construct_line_3_object(); - typename Exact_kernel::Line_3 l1= - line_3(converter(get(ppmap, info_2->vertex())),converter(get(ppmap, info_2->opposite()->vertex()))); - typename Exact_kernel::Line_3 l2=line_3(prev.point,curr.point); - CGAL::Object res=Exact_kernel().intersect_3_object()(l1,l2); - const typename Exact_kernel::Point_3* ptptr=CGAL::object_cast(&res); - CGAL_assertion(ptptr!=NULL); - point=*ptptr; - } - - void print_debug() const{ - std::cout << " ("; - if (type_1==VERTEX) std::cout << "V"; - if (type_1==EDGE) std::cout << "E"; - if (type_1==FACET) std::cout << "F"; - if (type_1==EMPTY) std::cout << "?"; - std::cout << "-" << &(*info_1); - std::cout << ";"; - if (type_2==VERTEX) std::cout << "V"; - if (type_2==EDGE) std::cout << "E"; - if (type_2==FACET) std::cout << "F"; - if (type_2==EMPTY) std::cout << "?"; - std::cout << ")" << "[" << CGAL::to_double(point.x()) << "," << CGAL::to_double(point.y()) << "," << CGAL::to_double(point.z()) << "]"; - } - - int debug_unique_type_int() const{ - int res=0; - switch (type_1){ - case VERTEX: res+=1; break; - case EDGE: res+=3; break; - case FACET: res+=7; break; - default: break; - } - switch (type_2){ - case VERTEX: res+=1; break; - case EDGE: res+=3; break; - case FACET: res+=7; break; - default: break; - } - return res; - } - - bool is_valid(Intersection_type type,Halfedge_handle info){ - bool valid=true; - Converter converter; - switch (type){ - case VERTEX: valid&= converter(get(ppmap, info->vertex()))==point; break; - case EDGE:{ - typename Exact_kernel::Segment_3 seg= - Exact_kernel().construct_segment_3_object()( converter(get(ppmap,info->vertex())), - converter(get(ppmap,info->opposite()->vertex())) ); - valid&= Exact_kernel().has_on_3_object()(seg,point); - } - break; - case FACET:{ - typename Exact_kernel::Coplanar_orientation_3 orient=Exact_kernel().coplanar_orientation_3_object(); - typename Exact_kernel::Point_3 p=converter(get(ppmap,info->vertex())); - typename Exact_kernel::Point_3 q=converter(get(ppmap,info->next()->vertex())); - typename Exact_kernel::Point_3 r=converter(get(ppmap,info->opposite()->vertex())); - valid &= orient(p,q,r,point)==POSITIVE; - valid &= orient(q,r,p,point)==POSITIVE; - valid &= orient(r,p,q,point)==POSITIVE; - } - break; - default: valid=false; - } - return valid; - } - - bool is_valid(){ - return is_valid(type_1,info_1) && is_valid(type_2,info_2); - } - -}; - -template -CGAL::Orientation get_orientation_and_update_info_2(Halfedge_handle h,Inter_pt& p, PolyhedronPointPMap ppmap) -{ - typename Inter_pt::Exact_kernel::Coplanar_orientation_3 orient= - typename Inter_pt::Exact_kernel().coplanar_orientation_3_object(); - typename Inter_pt::Converter converter; - - CGAL::Orientation res = orient(converter(get(ppmap,h->opposite()->vertex())), - converter(get(ppmap,h->vertex())), - converter(get(ppmap,h->next()->vertex())), - p.point); - - if ( (p.type_1==VERTEX || p.type_1==EDGE) && res==COLLINEAR){ - if (p.type_2==FACET){ //detect a case (VERTEX,EDGE) - p.type_2=EDGE; - p.info_2=h; - } - else{ - //detect a case (VERTEX,VERTEX) or (EDGE,VERTEX) - CGAL_assertion(p.type_2==EDGE); - p.type_2=VERTEX; - if (p.info_2->next()!=h){ - CGAL_assertion(h->next()==p.info_2); - p.info_2=h; - } - } - } - - return res; -} - -template -void intersection_coplanar_facets_cutoff(Facet_handle f,std::list& inter_pts,Facet_handle other,PolyhedronPointPMap ppmap) -{ - #ifdef CGAL_DEBUG_COPLANAR_TRIANGLE_INTERSECTION - std::cout << "cutoff: " << f->opposite()->vertex()->point() << " " << f->vertex()->point() << std::endl; - #endif //CGAL_DEBUG_COPLANAR_TRIANGLE_INTERSECTION - if ( inter_pts.empty() ) return; - typedef typename std::list::iterator Iterator; - - std::map orientations; - for (Iterator it=inter_pts.begin();it!=inter_pts.end();++it){ - #ifdef CGAL_DEBUG_COPLANAR_TRIANGLE_INTERSECTION - it->print_debug(); - #endif //CGAL_DEBUG_COPLANAR_TRIANGLE_INTERSECTION - orientations[ &(*it) ]=get_orientation_and_update_info_2(f,*it,ppmap); - } - #ifdef CGAL_DEBUG_COPLANAR_TRIANGLE_INTERSECTION - std::cout << std::endl; - #endif //CGAL_DEBUG_COPLANAR_TRIANGLE_INTERSECTION - - int pt_added=0; - - Inter_pt* prev = &(*boost::prior(inter_pts.end())); - bool inter_pts_size_g_2 = inter_pts.size() > 2; - Iterator stop = inter_pts_size_g_2 ? inter_pts.end() : boost::prior(inter_pts.end()); - for (Iterator it=inter_pts.begin();it!=stop;++it) - { - Inter_pt* curr=&(*it); - if (!inter_pts_size_g_2) std::swap(prev,curr); - Orientation or_prev=orientations[prev],or_curr=orientations[curr]; - if ( (or_prev==POSITIVE && or_curr==NEGATIVE) || (or_prev==NEGATIVE && or_curr==POSITIVE) ) - { - Iterator it_curr = inter_pts_size_g_2 ? it:boost::next(it); - prev=&(* inter_pts.insert( it_curr,Inter_pt(*prev,*curr,other,f,ppmap) ) ); - orientations[prev]=COLLINEAR; - ++pt_added; - } - prev=&(*it); - } - - CGAL_kernel_assertion(pt_added<3); - Iterator it=inter_pts.begin(); - std::size_t nb_interpt=inter_pts.size(); - //this boolean allows to reverse order of intersection points in case there were 3 remaining intersection points - //and the point in the middle was removed. In that case the order must be reversed to preserve the orientations - //of the last edge: - // A---X---B --> AB to be consistent with the other cases this should be BA! - // X---B---A --> BA - // B---A---X --> BA - // - bool should_revert_list=false; - - while(it!=inter_pts.end()) - { - if (orientations[&(*it)]==NEGATIVE){ - inter_pts.erase(it++); - if (--nb_interpt == 2 && it!=inter_pts.end() && boost::next(it)==inter_pts.end()) should_revert_list=true; - } - else - ++it; - } - if (should_revert_list && nb_interpt==2) inter_pts.reverse(); -} - -template -void -intersection_coplanar_facets( - Halfedge_handle f1, - Halfedge_handle f2, - PolyhedronPointPMap ppmap, - std::list >& output ) -{ - typedef Intersection_point_with_info Inter_pt; - output.push_back( Inter_pt(f1,f2,ppmap) ); - output.push_back( Inter_pt(f1->next(),f2,ppmap) ); - output.push_back( Inter_pt(f1->next()->next(),f2,ppmap) ); - - //intersect f2 with the three half planes which intersection defines f1 - intersection_coplanar_facets_cutoff(f2,output,f1,ppmap); - intersection_coplanar_facets_cutoff(f2->next(),output,f1,ppmap); - intersection_coplanar_facets_cutoff(f2->next()->next(),output,f1,ppmap); -} - - - -} } //namespace CGAL::internal_IOP - - -#endif //CGAL_INTERNAL_INTERSECTION_COPLANAR_TRIANGLES_3_H - diff --git a/Operations_on_polyhedra/include/CGAL/internal/corefinement/intersection_triangle_segment_3.h b/Operations_on_polyhedra/include/CGAL/internal/corefinement/intersection_triangle_segment_3.h deleted file mode 100644 index 1a892a9fab0..00000000000 --- a/Operations_on_polyhedra/include/CGAL/internal/corefinement/intersection_triangle_segment_3.h +++ /dev/null @@ -1,172 +0,0 @@ -// Copyright (c) 2011 GeometryFactory (France). -// All rights reserved. -// -// This file is part of CGAL (www.cgal.org). -// You can redistribute it and/or modify it under the terms of the GNU -// General Public License as published by the Free Software Foundation, -// either version 3 of the License, or (at your option) any later version. -// -// Licensees holding a valid commercial license may use this file in -// accordance with the commercial license agreement provided with the software. -// -// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE -// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. -// -// $URL$ -// $Id$ -// SPDX-License-Identifier: GPL-3.0+ -// -// -// Author(s) : Sebastien Loriot - -#ifndef CGAL_INTERNAL_INTERSECTION_TRIANGLE_SEGMENT_3_H -#define CGAL_INTERNAL_INTERSECTION_TRIANGLE_SEGMENT_3_H - -#include - - -//TODO rename this file when doing proper integration -#include -#include -namespace CGAL{ -namespace internal_IOP{ - -enum Intersection_type {FACET,EDGE,VERTEX,EMPTY,COPLNR}; - - -//define shortcut for intersection result types -template -struct Intersection_types{ - typedef typename Polyhedron_types::Halfedge_handle Intersection_info; - typedef cpp11::tuple Intersection_result; -}; - - -template -typename Intersection_types::Intersection_result -find_intersection(const typename Kernel::Point_3& p, const typename Kernel::Point_3& q, - const typename Kernel::Point_3& a, const typename Kernel::Point_3& b, const typename Kernel::Point_3& c, - typename Polyhedron_types::Halfedge_handle /*hh*/, - typename Polyhedron_types::Facet_handle fh, - bool is_vertex_coplanar=false,bool is_vertex_opposite_coplanar=false) -{ - typedef typename Intersection_types::Intersection_info Intersection_info; - typedef typename Intersection_types::Intersection_result Intersection_result; - - Orientation ab=orientation(p,q,a,b); - Orientation bc=orientation(p,q,b,c); - Orientation ca=orientation(p,q,c,a); - - if ( ab==POSITIVE || bc==POSITIVE || ca==POSITIVE ) - return Intersection_result(EMPTY,Intersection_info(),false,false); - - int nb_coplanar=(ab==COPLANAR?1:0) + (bc==COPLANAR?1:0) + (ca==COPLANAR?1:0); - - if ( nb_coplanar==0 ) - return cpp11::make_tuple(FACET,Intersection_info(fh->halfedge()),is_vertex_coplanar,is_vertex_opposite_coplanar); - - if (nb_coplanar==1){ - if (ab==COPLANAR) - return cpp11::make_tuple(EDGE,Intersection_info(fh->halfedge()->next()),is_vertex_coplanar,is_vertex_opposite_coplanar); - if (bc==COPLANAR) - return cpp11::make_tuple(EDGE,Intersection_info(fh->halfedge()->next()->next()),is_vertex_coplanar,is_vertex_opposite_coplanar); - CGAL_assertion(ca==COPLANAR); - return cpp11::make_tuple(EDGE,Intersection_info(fh->halfedge()),is_vertex_coplanar,is_vertex_opposite_coplanar); - } - - CGAL_assertion(nb_coplanar==2); - - if (ab!=COPLANAR) - return cpp11::make_tuple(VERTEX,Intersection_info(fh->halfedge()->next()->next()),is_vertex_coplanar,is_vertex_opposite_coplanar); - if (bc!=COPLANAR) - return cpp11::make_tuple(VERTEX,Intersection_info(fh->halfedge()),is_vertex_coplanar,is_vertex_opposite_coplanar); - CGAL_assertion(ca!=COPLANAR); - return cpp11::make_tuple(VERTEX,Intersection_info(fh->halfedge()->next()),is_vertex_coplanar,is_vertex_opposite_coplanar); -} - - -template -typename Intersection_types::Intersection_result -do_intersect(typename Polyhedron_types::Halfedge_handle hh, - typename Polyhedron_types::Facet_handle fh, - PolyhedronPointPmap ppmap) -{ - typedef typename Intersection_types::Intersection_info Intersection_info; - typedef typename Intersection_types::Intersection_result Intersection_result; - - const typename Kernel::Point_3 & a = get(ppmap, fh->halfedge()->vertex() ); - const typename Kernel::Point_3 & b = get(ppmap, fh->halfedge()->next()->vertex() ); - const typename Kernel::Point_3 & c = get(ppmap, fh->halfedge()->next()->next()->vertex() ); - const typename Kernel::Point_3 & p = get(ppmap, hh->vertex() ); - const typename Kernel::Point_3 & q = get(ppmap, hh->opposite()->vertex() ); - - - const Orientation abcp = orientation(a,b,c,p); - const Orientation abcq = orientation(a,b,c,q); - - - switch ( abcp ) { - case POSITIVE: - switch ( abcq ) { - case POSITIVE: - // the segment lies in the positive open halfspaces defined by the - // triangle's supporting plane - return Intersection_result(EMPTY,Intersection_info(),false,false); - case NEGATIVE: - // p sees the triangle in counterclockwise order - return find_intersection(p,q,a,b,c,hh,fh); - case COPLANAR: - // q belongs to the triangle's supporting plane - // p sees the triangle in counterclockwise order - return find_intersection(p,q,a,b,c,hh,fh,false,true); - - default: // should not happen. - CGAL_assertion(false); - return Intersection_result(EMPTY,Intersection_info(),false,false); - } - case NEGATIVE: - switch ( abcq ) { - case POSITIVE: - // q sees the triangle in counterclockwise order - return find_intersection(q,p,a,b,c,hh,fh); - case NEGATIVE: - // the segment lies in the negative open halfspaces defined by the - // triangle's supporting plane - return Intersection_result(EMPTY,Intersection_info(),false,false); - case COPLANAR: - // q belongs to the triangle's supporting plane - // p sees the triangle in clockwise order - return find_intersection(q,p,a,b,c,hh,fh,false,true); - default: // should not happen. - CGAL_assertion(false); - return Intersection_result(EMPTY,Intersection_info(),false,false); - } - case COPLANAR: // p belongs to the triangle's supporting plane - switch ( abcq ) { - case POSITIVE: - // q sees the triangle in counterclockwise order - return find_intersection(q,p,a,b,c,hh,fh,true,false); - case NEGATIVE: - // q sees the triangle in clockwise order - return find_intersection(p,q,a,b,c,hh,fh,true,false); - case COPLANAR: - // the segment is coplanar with the triangle's supporting plane - // we test whether the segment intersects the triangle in the common - // supporting plane - if ( ::CGAL::internal::do_intersect_coplanar(a,b,c,p,q,Kernel()) ) - return Intersection_result(COPLNR,Intersection_info(),true,true); - return Intersection_result(EMPTY,Intersection_info(),true,true); - - default: // should not happen. - CGAL_assertion(false); - return Intersection_result(EMPTY,Intersection_info(),false,false); - } - default: // should not happen. - CGAL_assertion(false); - return Intersection_result(EMPTY,Intersection_info(),false,false); - } -} - -}} //namespace CGAL::internal_IOP - -#endif //CGAL_INTERNAL_INTERSECTION_TRIANGLE_SEGMENT_3_H diff --git a/Operations_on_polyhedra/include/CGAL/internal/corefinement/intersection_triangle_segment_3_coplanar.h b/Operations_on_polyhedra/include/CGAL/internal/corefinement/intersection_triangle_segment_3_coplanar.h deleted file mode 100644 index a41fc3c5324..00000000000 --- a/Operations_on_polyhedra/include/CGAL/internal/corefinement/intersection_triangle_segment_3_coplanar.h +++ /dev/null @@ -1,400 +0,0 @@ -// Copyright (c) 2011 GeometryFactory (France). -// All rights reserved. -// -// This file is part of CGAL (www.cgal.org). -// You can redistribute it and/or modify it under the terms of the GNU -// General Public License as published by the Free Software Foundation, -// either version 3 of the License, or (at your option) any later version. -// -// Licensees holding a valid commercial license may use this file in -// accordance with the commercial license agreement provided with the software. -// -// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE -// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. -// -// $URL$ -// $Id$ -// SPDX-License-Identifier: GPL-3.0+ -// -// -// Author(s) : Sebastien Loriot - -#ifndef CGAL_INTERNAL_INTERSECTION_TRIANGLE_SEGMENT_3_COPLANAR_H -#define CGAL_INTERNAL_INTERSECTION_TRIANGLE_SEGMENT_3_COPLANAR_H - -#include - - - -namespace CGAL{ - namespace internal_IOP{ - -//enum Intersection_type {FACET,EDGE,VERTEX,EMPTY,COPLNR}; - -template -struct Intersection_point_coplanar{ - typedef typename Polyhedron_types::Halfedge_handle Halfedge_handle; - - Intersection_type type; - Halfedge_handle info; - Halfedge_handle segment_vertex; - - Intersection_point_coplanar(){}; - - Intersection_point_coplanar(Intersection_type type_, - Halfedge_handle info_, - Halfedge_handle segment_vertex_ - ) :type(type_),info(info_),segment_vertex(segment_vertex_){} -}; - -//test q vs segment bc -template -void point_vs_segment(Inter_pt_coplanar& pt, - Halfedge_handle bc, Halfedge_handle ab, - const Orientation& pqc, const Orientation& pqb) -{ - if (pqb==COLLINEAR){ - pt.type=VERTEX; - pt.info=ab; - } - else{ - if (pqc==COLLINEAR){ - pt.type=VERTEX; - pt.info=bc; - } - else{ - pt.type=EDGE; - pt.info=bc; - } - } -} - - -/* -// c -// / \ -// ___/___\____ with q-------p -// / \ -// a_______b -//supporting line of segment pq intersects ac and bc -*/ - -template -std::pair -decision_tree(const Point_3* a,const Point_3* b,const Point_3* c, - const Point_3* p,const Point_3* q, - const Orientation& pqa,const Orientation& pqb,const Orientation& pqc, - Halfedge_handle pq, - Halfedge_handle ca,Halfedge_handle ab,Halfedge_handle bc) -{ - CGAL_precondition(pqa!=NEGATIVE); - CGAL_precondition(pqb!=NEGATIVE); - CGAL_precondition(pqc!=POSITIVE); - - Inter_pt_coplanar pt1(EMPTY,NULL,NULL),pt2(EMPTY,NULL,NULL); - - //the segment supporting line intersects ac and bc - const Orientation bcq = coplanar_orientation(*b,*c,*q); - switch(bcq){ - case NEGATIVE: //segment does not intersect the triangle - return std::make_pair(pt1,pt2); - case COLLINEAR: //q \in [bc] - point_vs_segment(pt1,bc,ab,pqc,pqb); - pt1.segment_vertex=pq; - return std::make_pair(pt1,pt2); - default: - break; - } - - //===> q is to the left of bc - - const Orientation cap = coplanar_orientation(*c,*a,*p); - switch(cap){ - case NEGATIVE: //segment does not intersect the triangle - return false; - case COLLINEAR: //p \in [ca] - point_vs_segment(pt1,ca,bc,pqa,pqc); - pt1.segment_vertex=pq->opposite(); - return std::make_pair(pt1,pt2); - default: - break; - } - //===> p is to the right of ac - - - const Orientation cqa = coplanar_orientation(*c,*q,*a); - const Orientation cbp = coplanar_orientation(*c,*b,*p); - - if (pqc==COLLINEAR && cqa==POSITIVE && cbp==POSITIVE){ - //special case when c is inside the segment pq - pt1.type=VERTEX; - pt1.info=bc; - return std::make_pair(pt1,pt2); - } - - //where is located q? - switch (cqa){ - case POSITIVE: //q is outside the triangle - point_vs_segment(pt1,ca,bc,pqa,pqc); - break; - case NEGATIVE: //q is inside the triangle - pt1.type=FACET; - pt1.info=pq; - break; - case COLLINEAR: //q \in [ca] - point_vs_segment(pt1,ca,bc,pqa,pqc); - pt1.segment_vertex=pq; - break; - } - - //where is located p? - switch (cbp){ - case POSITIVE: //p is outside the triangle - point_vs_segment(pt2,bc,ab,pqc,pqb); - break; - case NEGATIVE: //p is inside the triangle - pt2.type=FACET; - pt2.info=pq->opposite(); - break; - case COLLINEAR: //p \in [bc] - point_vs_segment(pt2,bc,ab,pqc,pqb); - pt2.segment_vertex=pq->opposite(); - break; - } - return std::make_pair(pt1,pt2); -} - - -/* -// c -// / \ -// / \ -// / \ -// ____a_______b______ with q-------p -//supporting lines of segments pq and ab are the same. -*/ - -template -std::pair -collinear_decision_tree(const Point_3* a,const Point_3* b,const Point_3* c, - const Point_3* p,const Point_3* q, - const Orientation& pqa,const Orientation& pqb,const Orientation& pqc, - Halfedge_handle pq, - Halfedge_handle ca,Halfedge_handle ab,Halfedge_handle bc) -{ - CGAL_precondition(pqa==COLLINEAR); - CGAL_precondition(pqb==COLLINEAR); - CGAL_precondition(pqc==NEGATIVE); - - Inter_pt_coplanar pt1(EMPTY,NULL,NULL),pt2(EMPTY,NULL,NULL); - - //the segment supporting line intersects ac and bc - const Orientation bcq = coplanar_orientation(*b,*c,*q); - switch(bcq){ - case NEGATIVE: //segment does not intersect the triangle - return std::make_pair(pt1,pt2); - case COLLINEAR: // q = b - pt1.type=VERTEX; - pt1.info=ab; - pt1.segment_vertex=pq; - return std::make_pair(pt1,pt2); - default: - break; - } - - //===> q is to the left of b - - const Orientation cap = coplanar_orientation(*c,*a,*p); - switch(cap){ - case NEGATIVE: //segment does not intersect the triangle - return false; - case COLLINEAR: //p = a - pt1.type=VERTEX; - pt1.info=ca; - pt1.segment_vertex=pq->opposite(); - return std::make_pair(pt1,pt2); - default: - break; - } - - //===> p is to the right of a - - - const Orientation cqa = coplanar_orientation(*c,*q,*a); - const Orientation cbp = coplanar_orientation(*c,*b,*p); - - //where is located q? - switch (cqa){ - case POSITIVE: //q is to the left of a - pt1.type=VERTEX; - pt1.info=ca; - break; - case NEGATIVE: //q is to the right of a - pt1.type=EDGE; - pt1.info=ab; - pt1.segment_vertex=pq; - break; - case COLLINEAR: //q = a - pt1.type=VERTEX; - pt1.info=ca; - pt1.segment_vertex=pq; - break; - } - - //where is located p? - switch (cbp){ - case POSITIVE: //p is to the right of b - { - pt2.type=VERTEX; - pt2.info=ab; - } - break; - case NEGATIVE: //p is to the left of b - { - pt2.type=EDGE; - pt2.info=ab; - pt2.segment_vertex=pq->opposite(); - } - break; - case COLLINEAR: //p = b - pt2.type=VERTEX; - pt2.info=ab; - pt2.segment_vertex=pq->opposite(); - break; - } - - return std::make_pair(pt1,pt2); -} - -//std::pair,Intersection_point_coplanar > -template -std::pair,Intersection_point_coplanar > -do_intersect_coplanar(typename Polyhedron_types::Halfedge_handle pq, - typename Polyhedron_types::Face_handle fh) -{ - typedef Intersection_point_coplanar Inter_pt_coplanar; - typedef std::pair Return_type; - - - typedef typename Polyhedron_types::Halfedge_handle Halfedge_handle; - - const typename Kernel::Point_3 & A = fh->halfedge()->vertex()->point(); - const typename Kernel::Point_3 & B = fh->halfedge()->next()->vertex()->point(); - const typename Kernel::Point_3 & C = fh->halfedge()->next()->next()->vertex()->point(); - const typename Kernel::Point_3 & P = pq->vertex()->point(); - const typename Kernel::Point_3 & Q = pq->opposite()->vertex()->point(); - - const typename Kernel::Point_3 * a = &A; - const typename Kernel::Point_3 * b = &B; - const typename Kernel::Point_3 * c = &C; - - const typename Kernel::Point_3* p = &P; - const typename Kernel::Point_3* q = &Q; - - Halfedge_handle ca=fh->halfedge(); - Halfedge_handle ab=fh->halfedge()->next(); - Halfedge_handle bc=fh->halfedge()->next()->next(); - - - // Determine the orientation of the triangle in the common plane - - if (coplanar_orientation(A,B,C) != POSITIVE){ - // The triangle is not counterclockwise oriented swap two vertices. - b = &C; - c = &B; - std::swap(bc,ab); - } - - // Test whether the segment's supporting line intersects the - // triangle in the common plane - - Orientation pqa = coplanar_orientation(*p,*q,*a); - - //ensure pqa >= 0 - if (pqa == NEGATIVE){ - std::swap(p,q); - pqa=POSITIVE; - pq=pq->opposite(); - } - - const Orientation pqb = coplanar_orientation(*p,*q,*b); - const Orientation pqc = coplanar_orientation(*p,*q,*c); - - - - //Handle first case pq collinear with a triangle edge - if (pqa == COLLINEAR){ - if (pqb == COLLINEAR){ - //ab and pq are on the same line - if (pqc == NEGATIVE) - return collinear_decision_tree - (a,b,c,p,q,pqa,pqb,pqc,pq,ca,ab,bc); - else - return collinear_decision_tree - (a,b,c,q,p,pqa,pqb,NEGATIVE,pq->opposite(),ca,ab,bc); - } - if (pqc == COLLINEAR){ - //ac and pq are on the same line - if (pqb == NEGATIVE) - return collinear_decision_tree - (c,a,b,p,q,pqc,pqa,pqb,pq,bc,ca,ab); - else - return collinear_decision_tree - (c,a,b,q,p,pqc,pqa,NEGATIVE,pq->opposite(),bc,ca,ab); - } - } - else - if(pqb ==COLLINEAR && pqc == COLLINEAR){ - //bc and pq are on the same line - return collinear_decision_tree - (b,c,a,q,p,pqb,pqc,NEGATIVE,pq->opposite(),ab,bc,ca); - } - - - CGAL_assertion(pqa!=NEGATIVE); - - switch ( pqa ) { - case POSITIVE: - switch ( pqb ) { - case POSITIVE: - if (pqc == POSITIVE) - return std::make_pair(Inter_pt_coplanar(EMPTY,NULL,NULL),Inter_pt_coplanar(EMPTY,NULL,NULL)); - return decision_tree(a,b,c,p,q,pqa,pqb,pqc,pq,ca,ab,bc); - - case COLLINEAR: - case NEGATIVE: - if (pqc == POSITIVE) // b is isolated on the negative side - return decision_tree(c,a,b,p,q,pqc,pqa,pqb,pq,bc,ca,ab); - return decision_tree - (b,c,a,q,p,POSITIVE,opposite(pqc),NEGATIVE,pq->opposite(),ab,bc,ca); - default:// should not happen. - CGAL_assertion(false); - return std::make_pair(Inter_pt_coplanar(EMPTY,NULL,NULL),Inter_pt_coplanar(EMPTY,NULL,NULL)); - } - case COLLINEAR: - switch ( pqb ) { - case POSITIVE: - if (pqc == POSITIVE) // a is isolated on the negative side - return decision_tree(b,c,a,p,q,pqb,pqc,pqa,pq,ab,bc,ca); - return decision_tree(a,b,c,p,q,pqa,pqb,pqc,pq,ca,ab,bc); - - case NEGATIVE: - if (pqc == NEGATIVE) // a is isolated on the positive side - return decision_tree - (b,c,a,q,p,POSITIVE,POSITIVE,pqa,pq->opposite(),ab,bc,ca); - return decision_tree(c,a,b,p,q,pqc,pqa,pqb,pq,bc,ca,ab); - - default:// should not happen. - CGAL_assertion(false); - return std::make_pair(Inter_pt_coplanar(EMPTY,NULL,NULL),Inter_pt_coplanar(EMPTY,NULL,NULL)); - } - default:// should not happen. - CGAL_assertion(false); - return std::make_pair(Inter_pt_coplanar(EMPTY,NULL,NULL),Inter_pt_coplanar(EMPTY,NULL,NULL)); - - } -} - -}}//namespace CGAL::internal_IOP - -#endif //CGAL_INTERNAL_INTERSECTION_TRIANGLE_SEGMENT_3_COPLANAR_H diff --git a/Operations_on_polyhedra/include/CGAL/internal/corefinement/predicates.h b/Operations_on_polyhedra/include/CGAL/internal/corefinement/predicates.h deleted file mode 100644 index edb8a3f534a..00000000000 --- a/Operations_on_polyhedra/include/CGAL/internal/corefinement/predicates.h +++ /dev/null @@ -1,131 +0,0 @@ -// Copyright (c) 2011 GeometryFactory (France). -// All rights reserved. -// -// This file is part of CGAL (www.cgal.org). -// You can redistribute it and/or modify it under the terms of the GNU -// General Public License as published by the Free Software Foundation, -// either version 3 of the License, or (at your option) any later version. -// -// Licensees holding a valid commercial license may use this file in -// accordance with the commercial license agreement provided with the software. -// -// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE -// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. -// -// $URL$ -// $Id$ -// SPDX-License-Identifier: GPL-3.0+ -// -// -// Author(s) : Sebastien Loriot - -#ifndef CGAL_INTERNAL_COREFINEMENT_PREDICATES_H -#define CGAL_INTERNAL_COREFINEMENT_PREDICATES_H - -#include - - -namespace CGAL{ - -namespace Corefinement{ - -namespace OOP{ -//Considering the plane with normal vector [O_prime,O] and containing O. -//We define the counterclockwise order around O when looking from -//the side of the plane into which the vector [O_prime,O] is pointing. -//We consider the portion of the plane defined by rotating a ray starting at O -//from the planar projection of P1 to the planar projection of P2 in -//counterclockwise order. -//The predicates indicates whether the planar projection of point Q lies in this -//portion of the plane. -//Preconditions: -// O_prime,O,P1 are not collinear -// O_prime,O,P2 are not collinear -// O_prime,O,Q are not collinear -// O_prime,O,P1,Q are not coplanar or coplanar_orientation(O,O_prime,P1,Q)==NEGATIVE -// O_prime,O,P2,Q are not coplanar or coplanar_orientation(O,O_prime,P2,Q)==NEGATIVE -template -bool sorted_around_edge( - const typename Kernel::Point_3& O_prime,const typename Kernel::Point_3& O, - const typename Kernel::Point_3& P1,const typename Kernel::Point_3& P2, - const typename Kernel::Point_3& Q) -{ - //guarantee to have non-flat triangles - CGAL_precondition( !collinear(O_prime,O,P1) ); - CGAL_precondition( !collinear(O_prime,O,P2) ); - CGAL_precondition( !collinear(O_prime,O,Q) ); - - //no two triangles are coplanar and on the same side of their common edge - CGAL_precondition( !coplanar(O_prime,O,P1,Q) - || coplanar_orientation(O,O_prime,P1,Q)==NEGATIVE ); - CGAL_precondition( !coplanar(O_prime,O,P2,Q) - || coplanar_orientation(O,O_prime,P2,Q)==NEGATIVE ); - - Sign s0 = CGAL::sign( determinant(O-O_prime,P1-O,P2-O) ); - - if ( s0==ZERO ) { - //O, O_prime, P1 and P2 are coplanar - Orientation o=orientation(O_prime,O,P1,Q); - CGAL_precondition(o!=COPLANAR); - return o==POSITIVE; - } - - //O, O_prime, P1 and P2 are not coplanar - Sign s1 = CGAL::sign( determinant(O-O_prime,P1-O,Q -O) ); - Sign s2 = CGAL::sign( determinant(O-O_prime,Q -O,P2-O) ); - - if (s0 == POSITIVE) // the angle P1,O,P2 is smaller that Pi. - return ( s1 == POSITIVE ) - && ( s2 ==POSITIVE ); //true if the angles P1,O,Q and Q,O,P2 are smaller than Pi - else - return ( s1 != NEGATIVE ) - || ( s2 != - NEGATIVE ); //true if the angle P1,O,Q or the angle Q,O,P2 is smaller than or equal to Pi -} - -template -bool sorted_around_edge_filtered( int O_prime_index, - int O_index, - int P1_index, - int P2_index, - int Q_index, - Vertex_handle P1, - Vertex_handle P2, - Vertex_handle Q, - const Nodes_vector& nodes, - PolyhedronPointPMap ppmap) -{ - typename Nodes_vector::Protector p; - try { - CGAL_USE(p); - return sorted_around_edge( - nodes.interval_node(O_prime_index), - nodes.interval_node(O_index), - P1_index == -1 ? nodes.to_interval(get(ppmap,P1)) - : nodes.interval_node(P1_index), - P2_index == -1 ? nodes.to_interval(get(ppmap,P2)) - : nodes.interval_node(P2_index), - Q_index == -1 ? nodes.to_interval(get(ppmap,Q)) - : nodes.interval_node(Q_index ) - ); - } catch(Uncertain_conversion_exception&) { - return sorted_around_edge( - nodes.exact_node(O_prime_index), - nodes.exact_node(O_index), - P1_index == -1 ? nodes.to_exact(get(ppmap,P1)) - : nodes.exact_node(P1_index), - P2_index == -1 ? nodes.to_exact(get(ppmap,P2)) - : nodes.exact_node(P2_index), - Q_index == -1 ? nodes.to_exact(get(ppmap,Q)) - : nodes.exact_node(Q_index ) - ); - } -} - -} - -} - -} // end of namespace CGAL::Corefinement::OOP - -#endif //CGAL_INTERNAL_COREFINEMENT_PREDICATES_H diff --git a/Operations_on_polyhedra/include/CGAL/internal/corefinement/utils.h b/Operations_on_polyhedra/include/CGAL/internal/corefinement/utils.h deleted file mode 100644 index f8574d1888a..00000000000 --- a/Operations_on_polyhedra/include/CGAL/internal/corefinement/utils.h +++ /dev/null @@ -1,133 +0,0 @@ -// Copyright (c) 2011 GeometryFactory (France). -// All rights reserved. -// -// This file is part of CGAL (www.cgal.org). -// You can redistribute it and/or modify it under the terms of the GNU -// General Public License as published by the Free Software Foundation, -// either version 3 of the License, or (at your option) any later version. -// -// Licensees holding a valid commercial license may use this file in -// accordance with the commercial license agreement provided with the software. -// -// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE -// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. -// -// $URL$ -// $Id$ -// SPDX-License-Identifier: GPL-3.0+ -// -// -// Author(s) : Sebastien Loriot - -#ifndef CGAL_INTERNAL_COREFINEMENT_UTILS_H -#define CGAL_INTERNAL_COREFINEMENT_UTILS_H - -#include - - -namespace CGAL{ - -namespace internal_IOP { - -template -struct Compare_unik_address{ - typedef typename Polyhedron::Halfedge_handle Halfedge_handle; - typedef typename Polyhedron::Halfedge_const_handle Halfedge_const_handle; - typedef typename Polyhedron::Halfedge Halfedge; - - bool operator()(Halfedge_handle h1,Halfedge_handle h2) const { - Halfedge* ph1=&(*h1) < &(*h1->opposite()) ? &(*h1) : &(*h1->opposite()); - Halfedge* ph2=&(*h2) < &(*h2->opposite()) ? &(*h2) : &(*h2->opposite()); - return ph1 < ph2; - } - - bool operator()(Halfedge_const_handle h1,Halfedge_const_handle h2) const { - const Halfedge* ph1=&(*h1) < &(*h1->opposite()) ? &(*h1) : &(*h1->opposite()); - const Halfedge* ph2=&(*h2) < &(*h2->opposite()) ? &(*h2) : &(*h2->opposite()); - return ph1 < ph2; - } -}; - -template -struct Compare_address{ - typedef typename Polyhedron::Halfedge_handle Halfedge_handle; - typedef typename Polyhedron::Halfedge_const_handle Halfedge_const_handle; - typedef typename Polyhedron::Halfedge Halfedge; - - bool operator()(Halfedge_handle h1,Halfedge_handle h2) const { - return &(*h1) < &(*h2); - } - - bool operator()(Halfedge_const_handle h1,Halfedge_const_handle h2) const { - return &(*h1) < &(*h2); - } -}; - -template -class Non_intersection_halfedge{ - typedef std::map< typename Polyhedron::Halfedge_const_handle, - std::pair, - Compare_unik_address - > Intersection_hedges_set; - Intersection_hedges_set intersection_hedges_; -public: - Non_intersection_halfedge(const Intersection_hedges_set& the_set) : intersection_hedges_(the_set){} - - - bool operator()(typename Polyhedron::Halfedge_const_handle h) const - { - if (h->is_border_edge()) return false; - return intersection_hedges_.find(h)==intersection_hedges_.end(); - } -}; - -} //end of namespace internal_IOP - -namespace Corefinement{ - -template -struct Dummy_edge_mark_property_map{ - typedef bool value_type; - typedef value_type reference; - typedef std::pair key_type; - typedef boost::read_write_property_map_tag category; - - Dummy_edge_mark_property_map(){} - - friend reference get(Dummy_edge_mark_property_map,key_type) {return false;} - friend void put(Dummy_edge_mark_property_map,key_type,value_type) {} -}; - - -template -int node_index_of_incident_vertex(Halfedge_const_handle h, - const Border_halfedges_map& border_halfedges) -{ - //WARNING this may be expensive - Halfedge_const_handle start=h; - Halfedge_const_handle curr=start; - do { - typename Border_halfedges_map::const_iterator it_border = - border_halfedges.find(curr ); - if (it_border!=border_halfedges.end()) - return it_border->first==curr?it_border->second.second - :it_border->second.first; - curr=curr->next()->opposite(); - } while(curr!=start); - - return -1; -} - -template -int get_node_id(Vertex_handle vh, - const Vertex_to_node_id& vertex_to_node_id) -{ - typename Vertex_to_node_id::const_iterator it=vertex_to_node_id.find(vh); - if (it==vertex_to_node_id.end()) - return -1; - return it->second; -} - -} } //end of namespace CGAL::Corefinement - -#endif // CGAL_INTERNAL_COREFINEMENT_UTILS_H diff --git a/Operations_on_polyhedra/include/CGAL/intersection_of_Polyhedra_3.h b/Operations_on_polyhedra/include/CGAL/intersection_of_Polyhedra_3.h deleted file mode 100644 index 9d7bb7ec679..00000000000 --- a/Operations_on_polyhedra/include/CGAL/intersection_of_Polyhedra_3.h +++ /dev/null @@ -1,2187 +0,0 @@ -// Copyright (c) 2010-2012 GeometryFactory (France). -// All rights reserved. -// -// This file is part of CGAL (www.cgal.org). -// You can redistribute it and/or modify it under the terms of the GNU -// General Public License as published by the Free Software Foundation, -// either version 3 of the License, or (at your option) any later version. -// -// Licensees holding a valid commercial license may use this file in -// accordance with the commercial license agreement provided with the software. -// -// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE -// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. -// -// $URL$ -// $Id$ -// SPDX-License-Identifier: GPL-3.0+ -// -// -// Author(s) : Sebastien Loriot - -#ifndef CGAL_INTERSECTION_OF_POLYHEDRA_3_H -#define CGAL_INTERSECTION_OF_POLYHEDRA_3_H - -#include - -#include - -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -#include -#include - -#include -#include - -#include - -#ifdef CGAL_COREFINEMENT_DEBUG -#warning look at CGAL/Mesh_3/Robust_intersection_traits.h and the statically filtered decision tree -#endif - -namespace CGAL{ - -//This functor computes the pairwise intersection of polyhedral surfaces. -//Intersection are given as a set of polylines -//The algorithm works as follow: -//From each polyhedral surface we can get it as a set of segments or as a set of triangles. -//We first use Box_intersection_d to filter intersection between all polyhedral -//surface segments and polyhedral triangles. -//From this filtered set, for each pair (segment,triangle), we look at the -//intersection type. If not empty, we can have three different cases -// 1)the segment intersect the interior of the triangle: -// We compute the intersection point and for each triangle incident -// to the segment, we write the fact that the point belong to the intersection -// of these two triangles. -// 2)the segment intersect the triangle on an edge -// We do the same thing as described above but -// for all triangle incident to the edge intersected -// 3)the segment intersect the triangle at a vertex -// for each edge incident to the vertex, we do -// the same operations as in 2) -// -//In case the segment intersect the triangle at one of the segment endpoint, -//we repeat the same procedure for each segment incident to this -//endpoint. -// -//Note that given a pair (segment,triangle)=(S,T), if S belongs -//to the plane of T, we have nothing to do in the following cases: -// -- no triangle T' contains S such that T and T' are coplanar -// -- at least one triangle contains S -// Indeed, the intersection points of S and T will be found using segments -// of T or segments adjacent to S. -// -// -- Sebastien Loriot, 2010/04/07 - -template -struct Default_polyhedron_ppmap{ - typedef typename Polyhedron::Point_3 value_type; - typedef const value_type& reference; - typedef typename Polyhedron::Vertex_handle key_type; - typedef boost::read_write_property_map_tag category; - - friend reference get(Default_polyhedron_ppmap, key_type vh) {return vh->point();} - friend reference get(Default_polyhedron_ppmap, typename Polyhedron::Vertex_const_handle vh) {return vh->point();} - friend void put(Default_polyhedron_ppmap,key_type vh, const value_type& v) {vh->point()=v;} -}; - - -namespace internal_IOP { - //an enum do decide which kind of intersection points are needed - struct No_predicates_on_constructions{}; - struct Predicates_on_constructions{}; -} // namespace internal_IOP - -template -struct Empty_node_visitor{ - typedef typename Polyhedron::Halfedge_const_handle Halfedge_handle; - void new_node_added(int,internal_IOP::Intersection_type,Halfedge_handle,Halfedge_handle,bool,bool){} - template - void annotate_graph(Iterator,Iterator){} - void update_terminal_nodes(std::vector&){} - void set_number_of_intersection_points_from_coplanar_facets(int){} - void input_have_coplanar_facets(){} - void add_filtered_intersection(Halfedge_handle,Halfedge_handle,const Polyhedron&,const Polyhedron&){} - void start_new_polyline(int,int){} - void add_node_to_polyline(int){} - void new_input_polyhedron(const Polyhedron&){} - template - void finalize(T&){} - typedef internal_IOP::No_predicates_on_constructions Node_storage_type; - typedef Tag_true Is_polyhedron_const; - static const bool do_need_vertex_graph = false; -}; - -namespace internal_IOP{ - -template -struct Compare_handles{ - typedef typename Polyhedron_types::Halfedge_handle Halfedge_handle; - typedef typename Polyhedron_types::Halfedge Halfedge; - typedef typename Polyhedron_types::Vertex Vertex; - typedef typename Polyhedron_types::Facet Facet; - typedef typename Polyhedron_types::Facet_handle Facet_handle; - typedef std::pair Vertex_handle_pair; - - static inline Vertex_handle_pair - make_sorted_pair_of_vertices(Halfedge_handle h) { - const Vertex* v1=&(* h->vertex() ); - const Vertex* v2=&(* h->opposite()->vertex() ); - if ( v1 < v2 ) - return Vertex_handle_pair(v1,v2); - return Vertex_handle_pair(v2,v1); - } - - bool operator()(Halfedge_handle h1,Halfedge_handle h2) const { - Vertex_handle_pair p1=make_sorted_pair_of_vertices(h1); - Vertex_handle_pair p2=make_sorted_pair_of_vertices(h2); - return p1 < p2; - } - - bool operator()(Facet_handle f1,Facet_handle f2) const { - return &(*f1) < &(*f2); - } - - bool operator()(const std::pair& p1, const std::pair& p2) const{ - Halfedge* h1= (std::min) ( &(*(p1.first)), &(*(p1.first->opposite())) ); - Halfedge* h2= (std::min) ( &(*(p2.first)), &(*(p2.first->opposite())) ); - return h1 -struct Compare_handle_pairs{ - typedef typename Polyhedron_types::Facet Facet; - typedef typename Polyhedron_types::Facet_handle Facet_handle; - typedef std::pair Facet_pair; - typedef std::pair Facet_pair_and_int; - - bool operator()(const Facet_pair& p1, const Facet_pair& p2) const{ - Facet* f1=&(*p1.first); - Facet* f2=&(*p2.first); - if (f1==f2){ - f1=&(*p1.second); - f2=&(*p2.second); - } - return f1f2) return false; - return p1.second -struct Order_along_a_halfedge{ - typedef typename Polyhedron_types::Halfedge_handle Halfedge_handle; - const Nodes_vector& nodes; - Halfedge_handle hedge; - PolyhedronPointPMap ppmap; - - Order_along_a_halfedge(Halfedge_handle hedge_,const Nodes_vector& nodes_, PolyhedronPointPMap ppmap):nodes(nodes_),hedge(hedge_), ppmap(ppmap){} - bool operator()(int i,int j) const { - //returns true, iff q lies strictly between p and r. - typename Nodes_vector::Protector p; - try{ - CGAL::internal::use(p); - - return CGAL::collinear_are_strictly_ordered_along_line(nodes.to_interval(get(ppmap, hedge->vertex())), - nodes.interval_node(j), - nodes.interval_node(i)); - } - catch(CGAL::Uncertain_conversion_exception&){ - return CGAL::collinear_are_strictly_ordered_along_line(nodes.to_exact(get(ppmap, hedge->vertex())), - nodes.exact_node(j), - nodes.exact_node(i)); - } - } -}; - - -template -class Split_halfedge : public CGAL::Modifier_base { - typedef typename HDS::Halfedge_handle Halfedge_handle; - typedef typename HDS::Vertex_handle Vertex_handle; - typedef typename HDS::Vertex Vertex; - Halfedge_handle hedge; - - typename HDS::Halfedge::Base* - unlock_halfedge(Halfedge_handle h){ - return static_cast(&(*h)); - } - -public: - - Split_halfedge(Halfedge_handle h) : hedge(h){} - - // new_hedge hedge - // -----------> -----------> - // v - // <----------- <----------- - // new_opposite opposite - // - void operator()( HDS& hds) { - - Vertex_handle v=hds.vertices_push_back(Vertex()); - - Halfedge_handle opposite=hedge->opposite(); - - Halfedge_handle new_hedge=hds.edges_push_back(*hedge); - Halfedge_handle new_opposite=new_hedge->opposite(); - - //update next relations - unlock_halfedge(new_hedge)->set_next(hedge); - unlock_halfedge(new_hedge->prev())->set_next(new_hedge); - unlock_halfedge(hedge)->set_prev(new_hedge); - - unlock_halfedge(opposite)->set_next(new_opposite); - unlock_halfedge(new_opposite)->set_prev(opposite); - unlock_halfedge(new_opposite->next())->set_prev(new_opposite); - - unlock_halfedge(opposite)->set_vertex(v); - unlock_halfedge(new_hedge)->set_vertex(v); - - v->set_halfedge(new_hedge); - new_opposite->vertex()->set_halfedge(new_opposite); - } -}; - - - -} //namespace internal_IOP - - - -//WARNING THIS IS DONE ONLY FOR POLYHEDRON -// Warning this will split only existing edges, newly created edge intersected -// by the intersection polyline won't be split -template, - class Kernel=typename Kernel_traits< typename boost::property_traits::value_type>::Kernel > -class Node_visitor_for_polyline_split{ -//typedefs - typedef typename Polyhedron::Halfedge_handle Halfedge_handle; - typedef typename Polyhedron::Halfedge Halfedge; - typedef typename Polyhedron::Vertex_handle Vertex_handle; - //Info stores information about a particular intersection on an - //edge or a vertex of a polyhedron. The two first elements in - //the template describe the intersected simplex of the considered - //polyhedron; the two last elements describe the element of the - //second polyhedron (can be either a vertex, an edge of a facet) - //involved in the intersection - typedef CGAL::cpp11::tuple Info; - typedef std::map Hedge_to_polyhedron_map; - typedef std::vector Infos; - typedef std::map Node_to_infos_map; -//data members - Node_to_infos_map node_infos; - Hedge_to_polyhedron_map hedge_to_polyhedron; - Halfedge_predicate is_on_polyline; - Set_vertex_corner set_as_corner; - PolyhedronPointPMap ppmap; -//functions - void handle_principal_edge(int node_id, - internal_IOP::Intersection_type type, - Halfedge_handle principal_edge, - Halfedge_handle additional_edge, - bool is_vertex_coplanar, - bool is_vertex_opposite_coplanar) - { - bool coplanar_v=false; - if (is_vertex_coplanar) coplanar_v=true; - else if (is_vertex_opposite_coplanar){ - principal_edge=principal_edge->opposite(); - coplanar_v=true; - } - - if (coplanar_v) - handle_on_vertex(node_id,principal_edge,type,additional_edge); - else{ - if ( is_on_polyline(principal_edge) ){ - typename Node_to_infos_map::iterator it_res= - node_infos.insert(std::make_pair(node_id,Infos())).first; - it_res->second.push_back( Info(internal_IOP::EDGE,principal_edge,type,additional_edge) ); - } - } - } - - void handle_on_vertex(int node_id,Halfedge_handle edge,internal_IOP::Intersection_type type,Halfedge_handle additional_edge){ - Halfedge_handle current=edge; - do{ - if (is_on_polyline(current)){ - typename Node_to_infos_map::iterator it_res= - node_infos.insert(std::make_pair(node_id,Infos())).first; - it_res->second.push_back( Info(internal_IOP::VERTEX,current,type,additional_edge) ); - break; - } - current=current->next()->opposite(); - } - while(current!=edge); - } - - Halfedge* make_unique_key(Halfedge_handle h){ - if (&(*h) < &(*h->opposite())) - return &(*h); - else - return &(*h->opposite()); - } - - // new_hedge hedge - // -----------> -----------> - // v - // <----------- <----------- - // new_opposite opposite - // - void split_edge_and_retriangulate(Halfedge_handle hedge,const typename Kernel::Point_3& point,Polyhedron& P){ - internal_IOP::Split_halfedge delegated(hedge); - P.delegate( delegated ); - - Vertex_handle vh=boost::prior(P.vertices_end()); - put(ppmap, vh, point); - CGAL_assertion(get(ppmap,vh)==point); - - CGAL_assertion(P.is_valid()); - //triangulate the two adjacent facets - if (!hedge->is_border()) - P.split_facet(hedge->prev(),hedge->next()); - if (!hedge->opposite()->is_border()) - P.split_facet(hedge->opposite(),hedge->opposite()->next()->next()); - CGAL_assertion(P.is_valid()); - } - - //sort node ids so that we can split the hedge - //consecutively - template - void sort_vertices_along_hedge(std::vector& node_ids,Halfedge_handle hedge,const Nodes_vector& nodes) - { - std::sort(node_ids.begin(), - node_ids.end(), - internal_IOP::Order_along_a_halfedge(hedge,nodes,ppmap) - ); - } - -public: - static const bool do_need_vertex_graph = false; - typedef internal_IOP::Predicates_on_constructions Node_storage_type; - typedef Tag_false Is_polyhedron_const; - - Node_visitor_for_polyline_split(){} - Node_visitor_for_polyline_split(const Halfedge_predicate& getting, - const Set_vertex_corner& setting, - PolyhedronPointPMap ppmap) - :is_on_polyline(getting),set_as_corner(setting),ppmap(ppmap){} - - void new_node_added(int node_id, - internal_IOP::Intersection_type type, - Halfedge_handle principal_edge, - Halfedge_handle additional_edge, - bool is_vertex_coplanar, - bool is_vertex_opposite_coplanar) - { - switch(type) - { - case internal_IOP::FACET: //Facet intersected by an edge - handle_principal_edge(node_id,type,principal_edge,additional_edge,is_vertex_coplanar,is_vertex_opposite_coplanar); - break; - case internal_IOP::EDGE: //Edge intersected by an edge - handle_principal_edge(node_id,type,principal_edge,additional_edge,is_vertex_coplanar,is_vertex_opposite_coplanar); - if ( is_on_polyline(additional_edge) ){ - typename Node_to_infos_map::iterator it_res= - node_infos.insert(std::make_pair(node_id,Infos())).first; - it_res->second.push_back( Info(type,additional_edge, - ( is_vertex_coplanar||is_vertex_opposite_coplanar ) ? internal_IOP::VERTEX:internal_IOP::EDGE, - is_vertex_opposite_coplanar?principal_edge->opposite():principal_edge) ); - } - break; - case internal_IOP::VERTEX://Vertex intersected by an edge - handle_principal_edge(node_id,type,principal_edge,additional_edge,is_vertex_coplanar,is_vertex_opposite_coplanar); - handle_on_vertex( node_id,additional_edge, - ( is_vertex_coplanar||is_vertex_opposite_coplanar ) ? internal_IOP::VERTEX:internal_IOP::EDGE, - is_vertex_opposite_coplanar?principal_edge->opposite():principal_edge); - break; - default: - break; - } - } - - template - void annotate_graph(Iterator begin,Iterator end){ - for(Iterator it=begin;it!=end;++it){ - typename Node_to_infos_map::iterator it_res=node_infos.find(static_cast(std::distance(begin, it))); - if (it_res!=node_infos.end()) - it->make_terminal(); - } - } - - void update_terminal_nodes(std::vector& terminal_bools){ - for (typename Node_to_infos_map::iterator it=node_infos.begin();it!=node_infos.end();++it){ - terminal_bools[it->first]=true; - } - } - - void new_input_polyhedron(const Polyhedron&){} - void start_new_polyline(int,int){} - void add_node_to_polyline(int){} - void set_number_of_intersection_points_from_coplanar_facets(int){} - - void add_filtered_intersection(Halfedge_handle eh,Halfedge_handle fh,Polyhedron& Pe,Polyhedron& Pf){ - hedge_to_polyhedron.insert(std::make_pair(make_unique_key(eh),&Pe)); - hedge_to_polyhedron.insert(std::make_pair(make_unique_key(fh),&Pf)); - hedge_to_polyhedron.insert(std::make_pair(make_unique_key(fh->next()),&Pf)); - hedge_to_polyhedron.insert(std::make_pair(make_unique_key(fh->next()->next()),&Pf)); - } - - //split_halfedges - template - void finalize(const Nodes_vector& nodes){ - typedef std::map, - std::vector,internal_IOP::Compare_handles > Halfedges_to_split; - - Halfedges_to_split halfedges_to_split; - - for (typename Node_to_infos_map::iterator it=node_infos.begin();it!=node_infos.end();++it){ - int node_id=it->first; - const Infos& infos=it->second; - std::map > hedges_to_split; - - //collect information about halfedge to split - typename Infos::const_iterator it_info=infos.begin(); - for (;it_info!=infos.end();++it_info) - { - typename Hedge_to_polyhedron_map::iterator it_poly= - hedge_to_polyhedron.find(make_unique_key(CGAL::cpp11::get<1>(*it_info))); - CGAL_assertion(it_poly!=hedge_to_polyhedron.end()); - //associate information to an intersection point: - //we give which simplex of the other polyhedron intersect the simplex considered - set_as_corner.add_info_to_node(node_id,it_poly->second,*it_info); - switch(CGAL::cpp11::get<0>(*it_info)) - { - case internal_IOP::EDGE: - { - halfedges_to_split.insert( - std::make_pair( std::make_pair(CGAL::cpp11::get<1>(*it_info),&(*(it_poly->second))),std::vector() ) - ).first->second.push_back(node_id); - break; - } - case internal_IOP::VERTEX: - set_as_corner(CGAL::cpp11::get<1>(*it_info)->vertex(),node_id,it_poly->second); - break; - default: - CGAL_assertion(false); - //should never be here - } - } - } - - - //do the split - for(typename Halfedges_to_split::iterator it=halfedges_to_split.begin();it!=halfedges_to_split.end();++it){ - Halfedge_handle hedge=it->first.first; - Polyhedron* P=it->first.second; - std::vector& node_ids=it->second; - - sort_vertices_along_hedge(node_ids,hedge,nodes); - for (std::vector::iterator it_id=node_ids.begin();it_id!=node_ids.end();++it_id){ - split_edge_and_retriangulate(hedge,nodes[*it_id],*P); - set_as_corner(hedge->opposite()->vertex(),*it_id,(Polyhedron*)(0)); - } - } - } - void input_have_coplanar_facets() {} -}; - - -namespace internal_IOP{ - - template - typename Exact_kernel::Point_3 - compute_triangle_segment_intersection_point( - typename Polyhedron::Vertex_const_handle vh1,typename Polyhedron::Vertex_const_handle vh2, - typename Polyhedron::Vertex_const_handle vf1,typename Polyhedron::Vertex_const_handle vf2,typename Polyhedron::Vertex_const_handle vf3, - const Exact_kernel& ek, - PolyhedronPointPMap ppmap) - { - CGAL::Cartesian_converter to_exact; - typename Exact_kernel::Triangle_3 t(to_exact( get(ppmap, vf1) ), - to_exact( get(ppmap, vf2) ), - to_exact( get(ppmap, vf3) ) - ); - - typename Exact_kernel::Segment_3 s (to_exact( get(ppmap, vh1) ), - to_exact( get(ppmap, vh2) ) - ); - - typename Exact_kernel::Intersect_3 exact_intersect=ek.intersect_3_object(); - CGAL::Object inter=exact_intersect(t,s); - CGAL_assertion(CGAL::do_intersect(t,s)); - const typename Exact_kernel::Point_3* e_pt=CGAL::object_cast(&inter); - CGAL_assertion(e_pt!=NULL); - return *e_pt; - } - - template - typename Exact_kernel::Point_3 - compute_triangle_segment_intersection_point( - typename Polyhedron::Halfedge_const_handle edge, - typename Polyhedron::Facet_const_handle facet, - const Exact_kernel& ek, - PolyhedronPointPMap pmap) - { - return compute_triangle_segment_intersection_point( - edge->vertex(),edge->opposite()->vertex(), - facet->halfedge()->vertex(),facet->halfedge()->next()->vertex(),facet->halfedge()->opposite()->vertex(), - ek, - pmap); - - } - - - //A class containing a vector of the intersection points. - //The third template parameter indicates whether an - //exact representation is required - template ::value> - class Triangle_segment_intersection_points; - - - //Store only the double version of the intersection points. - template - class Triangle_segment_intersection_points - { - //typedefs - typedef std::vector Nodes_vector; - typedef typename Polyhedron::Halfedge_const_handle Halfedge_handle; - typedef typename Polyhedron::Facet_const_handle Facet_handle; - typedef CGAL::Exact_predicates_exact_constructions_kernel Exact_kernel; - typedef CGAL::Cartesian_converter Exact_to_double; - //members - Nodes_vector nodes; - Exact_kernel ek; - Exact_to_double exact_to_double; - PolyhedronPointPMap ppmap; - public: - - Triangle_segment_intersection_points(PolyhedronPointPMap ppmap): - ppmap(ppmap){} - - typedef CGAL::Interval_nt::Protector Protector; - - const typename Kernel::Point_3& - operator[](int i) const { - return nodes[i]; - } - - const typename Kernel::Point_3& exact_node(int i) const {return nodes[i];} - const typename Kernel::Point_3& interval_node(int i) const {return nodes[i];} - const typename Kernel::Point_3& to_exact(const typename Kernel::Point_3& p) const {return p;} - const typename Kernel::Point_3& to_interval(const typename Kernel::Point_3& p) const {return p;} - - size_t size() const {return nodes.size();} - - void add_new_node(const typename Exact_kernel::Point_3& p) - { - nodes.push_back( exact_to_double(p) ); - } - - //add a new node in the final graph. - //it is the intersection of the triangle with the segment - void add_new_node(Halfedge_handle edge,Facet_handle facet) - { - add_new_node( - compute_triangle_segment_intersection_point(edge,facet,ek, ppmap) - ); - } - - void add_new_node(const typename Kernel::Point_3& p) - { - nodes.push_back(p); - } - }; // end specialization - // Triangle_segment_intersection_points - - - //second specializations: store an exact copy of the points so that we can answer exactly predicates - //FYI, it used to have two specializations (one in the case the polyhedron - //can be edited and on if it cannot) building exact representation on demand. - //In the former case, we were using facet and halfedge while in the latter - //triple of vertex_handle and pair of vertex_handle - template - class Triangle_segment_intersection_points - { - //typedefs - public: - typedef CGAL::Simple_cartesian > Ikernel; - typedef CGAL::Exact_predicates_exact_constructions_kernel Exact_kernel; - private: - typedef CGAL::Cartesian_converter Interval_to_double; - typedef CGAL::Cartesian_converter Double_to_interval; - typedef CGAL::Cartesian_converter Exact_to_interval; - typedef CGAL::Cartesian_converter Double_to_exact; - - typedef typename Polyhedron::Vertex_const_handle Vertex_handle; - typedef typename Polyhedron::Halfedge_const_handle Halfedge_handle; - typedef typename Polyhedron::Facet_const_handle Facet_handle; - - typedef std::vector Interval_nodes; - typedef std::vector Exact_nodes; - - - //members - Interval_nodes inodes; - Exact_nodes enodes; - - Interval_to_double interval_to_double; - Exact_to_interval exact_to_interval; - Double_to_interval double_to_interval; - Double_to_exact double_to_exact; - Exact_kernel ek; - PolyhedronPointPMap ppmap; - - public: - - Triangle_segment_intersection_points(PolyhedronPointPMap ppmap): - ppmap(ppmap){} - - typedef CGAL::Interval_nt::Protector Protector; - - typename Kernel::Point_3 - operator[](int i) const { - return interval_to_double(inodes[i]); - } - - const typename Ikernel::Point_3& - interval_node(int i) const { - return inodes[i]; - } - - typename Ikernel::Point_3 - to_interval(const typename Kernel::Point_3& p) const { - return double_to_interval(p); - } - - const Exact_kernel::Point_3 - exact_node(int i) const { - return enodes[i]; - } - - typename Exact_kernel::Point_3 - to_exact(const typename Kernel::Point_3& p) const { - return double_to_exact(p); - } - - - size_t size() const {return enodes.size();} - - void add_new_node(const Exact_kernel::Point_3& p){ - const Ikernel::Point_3& p_approx=p.approx(); - if ( !has_smaller_relative_precision(p_approx.x(),Lazy_exact_nt::get_relative_precision_of_to_double()) || - !has_smaller_relative_precision(p_approx.y(),Lazy_exact_nt::get_relative_precision_of_to_double()) || - !has_smaller_relative_precision(p_approx.z(),Lazy_exact_nt::get_relative_precision_of_to_double()) ) p.exact(); - enodes.push_back(p); - inodes.push_back( exact_to_interval(p) ); - } - - void add_new_node(Halfedge_handle edge,Facet_handle facet) - { - add_new_node( compute_triangle_segment_intersection_point(edge,facet,ek,ppmap) ); - } - - //the point is an input - void add_new_node(const typename Kernel::Point_3& p){ - enodes.push_back(to_exact(p)); - inodes.push_back( double_to_interval(p) ); - } - }; // end specialization - // Triangle_segment_intersection_points - - //Third specialization: The kernel already has exact constructions. - template - class Triangle_segment_intersection_points - { - //typedefs - typedef std::vector Nodes_vector; - typedef typename Polyhedron::Halfedge_const_handle Halfedge_handle; - typedef typename Polyhedron::Facet_const_handle Facet_handle; - //members - Nodes_vector nodes; - Kernel k; - PolyhedronPointPMap ppmap; - public: - typedef Kernel Ikernel; - typedef Kernel Exact_kernel; - typedef void* Protector; - - Triangle_segment_intersection_points(PolyhedronPointPMap ppmap): - ppmap(ppmap){} - - const typename Kernel::Point_3& - operator[](int i) const { - return nodes[i]; - } - - size_t size() const {return nodes.size();} - const typename Kernel::Point_3& exact_node(int i) const {return nodes[i];} - const typename Kernel::Point_3& interval_node(int i) const {return nodes[i];} - - //add a new node in the final graph. - //it is the intersection of the triangle with the segment - void add_new_node(Halfedge_handle edge,Facet_handle facet) - { - nodes.push_back ( - compute_triangle_segment_intersection_point(edge,facet,k,ppmap) - ); - } - - void add_new_node(const typename Kernel::Point_3& p) - { - nodes.push_back(p); - } - - const typename Kernel::Point_3& to_interval(const typename Kernel::Point_3& p) const { return p; } - const typename Kernel::Point_3& to_exact(const typename Kernel::Point_3& p) const { return p; } - - }; // end specialization - // Triangle_segment_intersection_points - -} - -#ifdef CGAL_COREFINEMENT_DO_REPORT_SELF_INTERSECTIONS -struct Intersection_of_Polyhedra_3_self_intersection_exception - : public std::logic_error - { - Intersection_of_Polyhedra_3_self_intersection_exception() - : std::logic_error("Self-intersection found in the facets involved in the intersection") - {} - }; -#endif - -//TODO an important requirement is that the Polyhedron should be based on a list-based -//HDS. We use a lot of maps that use the address of Facet,Halfedge and a reallocation would -//be dramatic. - -template< class Polyhedron, - class Kernel_=Default, - class Node_visitor_=Default, - class Node_storage_type_=Default, - class Use_const_polyhedron_=Default, - class PolyhedronPointPMap_=Default - > -class Intersection_of_Polyhedra_3{ -//Default template parameters - typedef typename Default::Get >::type Node_visitor; - typedef typename Default::Get::type Node_storage_type; - typedef typename Default::Get > ::type PolyhedronPointPMap; - typedef typename Default::Get::type Use_const_polyhedron; - typedef typename Default::Get::value_type >::Kernel >::type Kernel; - -//typedefs - typedef typename Kernel::Triangle_3 Triangle; - typedef typename Kernel::Segment_3 Segment; - typedef internal_IOP:: - Polyhedron_types Polyhedron_types; - - typedef typename Polyhedron_types::Polyhedron_ref Polyhedron_ref; - typedef typename Polyhedron_types::Halfedge_handle Halfedge_handle; - typedef typename Polyhedron_types::Halfedge_iterator Halfedge_iterator; - typedef typename Polyhedron_types::Facet_iterator Facet_iterator; - typedef typename Polyhedron_types::Facet_handle Facet_handle; - typedef typename Polyhedron_types::Vertex_handle Vertex_handle; - typedef typename Polyhedron_types::Vertex Vertex; - typedef typename Polyhedron_types::Facet Facet; - typedef CGAL::Box_intersection_d::Box_with_handle_d< - double, 3, Halfedge_handle> Box; - typedef std::pair Facet_pair; - typedef std::pair Facet_pair_and_int; - - typedef internal_IOP:: - Compare_handles Compare_handles; - - typedef internal_IOP:: - Compare_handle_pairs Compare_handle_pairs; - - - typedef std::map,Compare_handle_pairs> Facets_to_nodes_map;//Indeed the boundary of the intersection of two coplanar triangles may contain several segments. - typedef std::set Coplanar_facets_set;//any insertion should be done with make_sorted_pair_of_facets - typedef typename Kernel::Point_3 Node; - typedef internal_IOP::Triangle_segment_intersection_points - Nodes_vector; - - typedef typename internal_IOP:: - Intersection_types - ::Intersection_result Intersection_result; - - typedef std::set Facet_set; - - typedef std::map - Edge_to_intersected_facets; - #ifdef USE_DETECTION_MULTIPLE_DEFINED_EDGES - typedef std::set Coplanar_duplicated_intersection_set; - #endif -//member data - PolyhedronPointPMap ppmap; -//helper functions - static inline Facet_pair - make_sorted_pair_of_facets(Facet_handle fh1,Facet_handle fh2) { - const Facet* f1=&(*fh1); - const Facet* f2=&(*fh2); - if (f1 < f2) - return Facet_pair(fh1,fh2); - return Facet_pair(fh2,fh1); - } - - static inline Facet_pair_and_int - make_sorted_pair_of_facets_with_int(Facet_handle fh1,Facet_handle fh2,int i) { - return std::make_pair(make_sorted_pair_of_facets(fh1,fh2),i); - } - - static inline std::pair make_sorted_void_pair(void* v1,void* v2){ - if (v1opposite()) ) return h; - return h->opposite(); - } - -//member variables - Edge_to_intersected_facets edge_to_sfacet; //Associate a segment to a filtered set of facets that may be intersected - Facets_to_nodes_map f_to_node; //Associate a pair of triangle to their intersection points - Coplanar_facets_set coplanar_facets;//Contains all pairs of triangular facets intersecting that are coplanar - Nodes_vector nodes; //Contains intersection points of polyhedra - Node_visitor* visitor; - bool is_default_visitor; //indicates whether the visitor need to be deleted - #ifdef USE_DETECTION_MULTIPLE_DEFINED_EDGES - //this does not occur only when one extremity of an edge is inside a face. - // The problem occur every time an edge or a part of an edge with two incident triangles - // is on the intersection polyline, I choose to direcly filter the output by removing duplicated edges - Coplanar_duplicated_intersection_set coplanar_duplicated_intersection;//Set containing edges that are duplicated because of edges (partially) included in a triangle - #endif - -//functions that should come from a traits class - bool has_at_least_two_incident_faces(Halfedge_handle edge) - { - return !edge->is_border_edge(); - } - - template - void get_incident_facets(Halfedge_handle edge,Output_iterator out){ - if (!edge->is_border()) *out++=edge->facet(); - if (!edge->opposite()->is_border()) *out++=edge->opposite()->facet(); - } - - template - void get_incident_edges_to_vertex(Halfedge_handle edge,Output_iterator out){ - Halfedge_handle current=edge; - do{ - *out++=current; - current=current->next()->opposite(); - } - while(current!=edge); - } - -//internal functions - - class Map_edge_facet_bbox_intersection { - Edge_to_intersected_facets& edge_to_sfacet; - Polyhedron_ref polyhedron_triangle; - Polyhedron_ref polyhedron_edge; - Node_visitor& visitor; - public: - Map_edge_facet_bbox_intersection(Edge_to_intersected_facets& map_, - Polyhedron_ref P, - Polyhedron_ref Q, - Node_visitor& visitor_) - :edge_to_sfacet(map_),polyhedron_triangle(P),polyhedron_edge(Q),visitor(visitor_){} - - void operator()( const Box* fb, const Box* eb) const { - Halfedge_handle fh = fb->handle(); - Halfedge_handle eh = eb->handle(); - - // The following call to map::insert() attempts an insertion of a pair - // into 'edge_to_sfacet'. If 'eh' is already inserted in the map, - // then the result 'res' is the current entry in the map for 'eh'. - typename Edge_to_intersected_facets::iterator res= - edge_to_sfacet.insert(std::make_pair(eh,Facet_set())).first; - - res->second.insert(fh->facet()); - // That could have been shortened to: - // - // edge_to_sfacet[eh].insert(fh->facet()) - // - // -- Laurent Rineau, 2012/11/01 - - visitor.add_filtered_intersection(eh,fh,polyhedron_edge,polyhedron_triangle); - } - }; - - class Map_edge_facet_bbox_intersection_extract_coplanar { - Edge_to_intersected_facets& edge_to_sfacet; - Coplanar_facets_set& coplanar_facets; - Polyhedron_ref polyhedron_triangle; - Polyhedron_ref polyhedron_edge; - Node_visitor& visitor; - PolyhedronPointPMap ppmap; - public: - Map_edge_facet_bbox_intersection_extract_coplanar( - Edge_to_intersected_facets& map_, - Coplanar_facets_set& coplanar_facets_, - Polyhedron_ref P, - Polyhedron_ref Q, - Node_visitor& visitor_, - PolyhedronPointPMap ppmap) - :edge_to_sfacet(map_),coplanar_facets(coplanar_facets_),polyhedron_triangle(P),polyhedron_edge(Q),visitor(visitor_),ppmap(ppmap) - {} - - void operator()( const Box* fb, const Box* eb) const { - Halfedge_handle fh = fb->handle(); //handle for the face - Halfedge_handle eh = eb->handle(); //handle for the edge - if(eh->is_border()) eh = eh->opposite(); - CGAL_assertion(!eh->is_border()); - - //check if the segment intersects the plane of the facet or if it is included in the plane - const typename Kernel::Point_3 & a = get(ppmap, fh->vertex()); - const typename Kernel::Point_3 & b = get(ppmap, fh->next()->vertex()); - const typename Kernel::Point_3 & c = get(ppmap, fh->next()->next()->vertex()); - const Orientation abcp = orientation(a,b,c, get(ppmap, eh->vertex())); - const Orientation abcq = orientation(a,b,c, get(ppmap, eh->opposite()->vertex())); - if (abcp==abcq){ - if (abcp!=COPLANAR){ -// std::cout << "rejected " << &(*fh->facet()) << "{" << &(*eh->facet()) << " " <<&(*eh->opposite()->facet()) << " "<< get(ppmap, eh->vertex()) << " " << get(eh->opposite()->vertex()) << "}" <is_border() && */ orientation(a,b,c,get(ppmap, eh->next()->vertex()))==COPLANAR){ - coplanar_facets.insert(make_sorted_pair_of_facets(eh->facet(),fh->facet())); - } - if (!eh->opposite()->is_border() && orientation(a,b,c,get(ppmap, eh->opposite()->next()->vertex()))==COPLANAR){ - coplanar_facets.insert(make_sorted_pair_of_facets(eh->opposite()->facet(),fh->facet())); - } - visitor.add_filtered_intersection(eh,fh,polyhedron_edge,polyhedron_triangle); - //in case only the edge is coplanar, the intersection points will be detected using an incident facet - //(see remark at the beginning of the file) - return; - } - - typename Edge_to_intersected_facets::iterator res= - edge_to_sfacet.insert(std::make_pair(eh,Facet_set())).first; - res->second.insert(fh->facet()); - visitor.add_filtered_intersection(eh,fh,polyhedron_edge,polyhedron_triangle); - } - }; - - class Map_edge_facet_bbox_intersection_extract_coplanar_filter_self_intersections { - Polyhedron_ref polyhedron_triangle; - Polyhedron_ref polyhedron_edge; - - std::set& m_reported_facets; - std::vector >& m_intersecting_bboxes; - PolyhedronPointPMap ppmap; - public: - Map_edge_facet_bbox_intersection_extract_coplanar_filter_self_intersections( - Polyhedron_ref P, - Polyhedron_ref Q, - std::set& reported_facets, - std::vector >& intersecting_bboxes, - PolyhedronPointPMap ppmap - ) - : polyhedron_triangle(P) - , polyhedron_edge(Q) - , m_reported_facets(reported_facets) - , m_intersecting_bboxes(intersecting_bboxes) - , ppmap(ppmap) - {} - - void operator()( const Box* fb, const Box* eb) { - m_reported_facets.insert( fb->handle()->facet() ); - m_intersecting_bboxes.push_back( std::make_pair(fb, eb) ); - } - - bool self_intersections_found() - { - try{ - typedef typename CGAL::Box_intersection_d::Box_with_info_d Box; - - // make one box per facet - std::vector boxes; - boxes.reserve(m_reported_facets.size()); - - BOOST_FOREACH(Facet_handle fh, m_reported_facets) - { - boxes.push_back( Box( fh->halfedge()->vertex()->point().bbox() + - fh->halfedge()->next()->vertex()->point().bbox() + - fh->halfedge()->opposite()->vertex()->point().bbox(), fh ) - ); - } - - // generate box pointers - std::vector box_ptr; - box_ptr.reserve(boxes.size()); - typename std::vector::iterator b; - for(b = boxes.begin(); - b != boxes.end(); - b++) - box_ptr.push_back(&*b); - - // compute self-intersections filtered out by boxes - typedef boost::function_output_iterator OutputIterator; - OutputIterator out; - internal::Intersect_facets - intersect_facets(polyhedron_triangle, out, ppmap, Kernel()); - std::ptrdiff_t cutoff = 2000; - CGAL::box_self_intersection_d(box_ptr.begin(), box_ptr.end(),intersect_facets,cutoff); - return false; - } - catch( internal::Throw_at_output::Throw_at_output_exception& ) - { - return true; - } - } - }; - - // This function tests the intersection of the faces of P with the edges of Q - void filter_intersections( Polyhedron_ref P, Polyhedron_ref Q) { - std::vector facet_boxes, edge_boxes; - facet_boxes.reserve( P.size_of_facets()); - for ( Facet_iterator i = P.facets_begin(); i != P.facets_end(); ++i){ - facet_boxes.push_back( - Box( get(ppmap, i->halfedge()->vertex()).bbox() - + get(ppmap, i->halfedge()->next()->vertex()).bbox() - + get(ppmap, i->halfedge()->next()->next()->vertex()).bbox(), - i->halfedge())); - } - std::vector facet_box_ptr; - facet_box_ptr.reserve( P.size_of_facets()); - for ( typename std::vector::iterator j = facet_boxes.begin(); j != facet_boxes.end(); ++j){ - facet_box_ptr.push_back( &*j); - } - - for ( Halfedge_iterator i = Q.halfedges_begin(); i != Q.halfedges_end(); ++i){ - if(&*i < &*(i->opposite())){ - edge_boxes.push_back( - Box( get(ppmap, i->vertex()).bbox() - + get(ppmap, i->opposite()->vertex()).bbox(), - i)); - } - } - - std::vector edge_box_ptr; - edge_box_ptr.reserve( Q.size_of_halfedges()/2); - for ( typename std::vector::iterator j = edge_boxes.begin(); j != edge_boxes.end(); ++j){ - edge_box_ptr.push_back( &*j); - } - - #ifdef CGAL_COREFINEMENT_DO_REPORT_SELF_INTERSECTIONS - // this version first collect faces involved in the intersection and first - // check if they are involved in a self-intersection. - std::set reported_facets; - std::vector > intersecting_bboxes; - Map_edge_facet_bbox_intersection_extract_coplanar_filter_self_intersections - inter_functor4selfi(P, Q, reported_facets, intersecting_bboxes, ppmap); - CGAL::box_intersection_d( facet_box_ptr.begin(), facet_box_ptr.end(), - edge_box_ptr.begin(), edge_box_ptr.end(), - inter_functor4selfi, std::ptrdiff_t(2000) ); - - if (inter_functor4selfi.self_intersections_found()) throw Intersection_of_Polyhedra_3_self_intersection_exception(); - - #ifdef DO_NOT_HANDLE_COPLANAR_FACETS - Map_edge_facet_bbox_intersection inter_functor(edge_to_sfacet,P,Q,*visitor); - #else // not DO_NOT_HANDLE_COPLANAR_FACETS - Map_edge_facet_bbox_intersection_extract_coplanar inter_functor(edge_to_sfacet,coplanar_facets,P,Q,*visitor,ppmap); - #endif // not DO_NOT_HANDLE_COPLANAR_FACETS - - typedef std::pair Type_pair; - BOOST_FOREACH(const Type_pair& p, intersecting_bboxes) - inter_functor(p.first, p.second); - #else - CGAL::box_intersection_d( facet_box_ptr.begin(), facet_box_ptr.end(), - edge_box_ptr.begin(), edge_box_ptr.end(), - #ifdef DO_NOT_HANDLE_COPLANAR_FACETS - // Note that 'edge_to_sfacet' is passed by - // non-const reference, here, to be filled. - Map_edge_facet_bbox_intersection(edge_to_sfacet,P,Q,*visitor), - #else // not DO_NOT_HANDLE_COPLANAR_FACETS - Map_edge_facet_bbox_intersection_extract_coplanar(edge_to_sfacet,coplanar_facets,P,Q,*visitor,ppmap), - #endif // not DO_NOT_HANDLE_COPLANAR_FACETS - std::ptrdiff_t(2000) - ); - #endif - } - - - void add_intersection_point_to_facet_and_all_edge_incident_facets(Facet_handle facet, - Halfedge_handle edge, - int node_id) - { - std::vector incident_facets; - get_incident_facets(edge,std::back_inserter(incident_facets)); - for (typename std::vector::iterator it=incident_facets.begin(); - it!=incident_facets.end();++it) - { - CGAL_assertion(cgal_do_intersect_debug(facet,*it)); - - Facet_pair facet_pair = make_sorted_pair_of_facets(facet,*it); - if ( !coplanar_facets.empty() && coplanar_facets.find(facet_pair)!=coplanar_facets.end() ) continue; - typename Facets_to_nodes_map::iterator it_list= - f_to_node.insert( std::make_pair( Facet_pair_and_int(facet_pair,0),std::set()) ).first; - it_list->second.insert(node_id); - } - } - - void cip_handle_case_edge(int node_id, - Facet_set* fset, - Halfedge_handle edge, - Halfedge_handle edge_intersected) - { - //associate the intersection point to all facets incident to the intersected edge using edge - std::vector incident_facets; - get_incident_facets(edge_intersected,std::back_inserter(incident_facets)); - for (typename std::vector::iterator it=incident_facets.begin(); - it!=incident_facets.end();++it) - { - add_intersection_point_to_facet_and_all_edge_incident_facets(*it,edge,node_id); - if (fset!=NULL) fset->erase(*it); - } - incident_facets.clear(); - - //associate the intersection point to all facets incident to edge using the intersected edge - //at least one pair of facets is already handle above - - typename Edge_to_intersected_facets::iterator it_fset=edge_to_sfacet.find(edge_intersected); - if (it_fset==edge_to_sfacet.end()) return; - Facet_set& fset_bis=it_fset->second; - get_incident_facets(edge,std::back_inserter(incident_facets)); - for (typename std::vector::iterator it=incident_facets.begin(); - it!=incident_facets.end();++it) - { -// add_intersection_point_to_facet_and_all_edge_incident_facets(*it,edge_intersected,node_id); //this call is not needed, already done in the first loop - fset_bis.erase(*it); - } - } - - void cip_handle_case_vertex(int node_id, - Facet_set* fset, - Halfedge_handle edge, - Halfedge_handle vertex_intersected) - { - std::vector incident_halfedges; - get_incident_edges_to_vertex(vertex_intersected,std::back_inserter(incident_halfedges)); - for (typename std::vector::iterator - it=incident_halfedges.begin();it!=incident_halfedges.end();++it) - { - cip_handle_case_edge(node_id,fset,edge,*it); - } - } - - //add a new node in the final graph. - //it is the intersection of the triangle with the segment - void add_new_node(Halfedge_handle edge, - Facet_handle facet, - const Intersection_result& inter_res, - Nodes_vector& nodes) - { - bool is_vertex_coplanar = CGAL::cpp11::get<2>(inter_res); - if (is_vertex_coplanar) - nodes.add_new_node(get(ppmap, edge->vertex())); - else{ - bool is_opposite_vertex_coplanar = CGAL::cpp11::get<3>(inter_res); - if (is_opposite_vertex_coplanar) - nodes.add_new_node(get(ppmap, edge->opposite()->vertex())); - else - nodes.add_new_node(edge,facet); - } - } - - //either the exact or input point can be used to create a node - //with this function - template - void add_new_node(const Point& pt) - { - nodes.add_new_node(pt); - } - - - #ifdef USE_DETECTION_MULTIPLE_DEFINED_EDGES - void check_coplanar_edge(Halfedge_handle hedge,Facet_handle facet) - { - const typename Kernel::Point_3& p0=get(ppmap, facet->halfedge()->vertex()); - const typename Kernel::Point_3& p1=get(ppmap, facet->halfedge()->next()->vertex()); - const typename Kernel::Point_3& p2=get(ppmap, facet->halfedge()->opposite()->vertex()); - CGAL_precondition( orientation( p0,p1,p2,get(ppmap, hedge->vertex()) ) == COPLANAR ); - - if ( has_at_least_two_incident_faces(hedge) && orientation( p0,p1,p2,get(ppmap, hedge->opposite()->vertex()) ) == COPLANAR ) - { - //In case two facets are incident along such this edge, the intersection - //will be reported twice. We keep track of this so that at the end, we can remove one intersecting edge out of the two - //choose the smaller of the two faces (only one need to de deleted) - Facet_handle smaller=make_sorted_pair_of_facets(hedge->face(),hedge->opposite()->face()).first; - coplanar_duplicated_intersection.insert(make_sorted_pair_of_facets(smaller,facet)); - } - } - - bool are_incident_facets_coplanar(Halfedge_handle hedge){ - const typename Kernel::Point_3& p0=get(ppmap, hedge->vertex()); - const typename Kernel::Point_3& p1=get(ppmap, hedge->next()->vertex()); - const typename Kernel::Point_3& p2=get(ppmap, hedge->opposite()->vertex()); - const typename Kernel::Point_3& p3=get(ppmap, hedge->opposite()->next()->vertex()); - return orientation( p0,p1,p2,p3 ) == COPLANAR; - } - - void check_coplanar_edge(Halfedge_handle hedge,Halfedge_handle additional_edge,internal_IOP::Intersection_type type) - { - switch(type){ - case internal_IOP::FACET: - check_coplanar_edge(hedge,additional_edge->face()); - break; - - case internal_IOP::EDGE: - if ( !additional_edge->is_border() ){ - check_coplanar_edge(hedge,additional_edge->face()); - } - if (!additional_edge->opposite()->is_border()) - check_coplanar_edge(hedge,additional_edge->opposite()->face()); - break; - case internal_IOP::VERTEX: - { - //consider all incident faces - Halfedge_handle current=additional_edge; - do{ - if( !current->is_border() ) - check_coplanar_edge(hedge,current->face()); - current=current->next()->opposite(); - } - while(current!=additional_edge); - } - break; - - default: - CGAL_assertion(type==internal_IOP::COPLNR); - break; - } - } - - void check_coplanar_edge_old(Halfedge_handle hedge,Halfedge_handle additional_edge,internal_IOP::Intersection_type type) - { - switch(type){ - case internal_IOP::FACET: - check_coplanar_edge(hedge,additional_edge->face()); - break; - - case internal_IOP::EDGE: - { - if ( !additional_edge->is_border() ){ - if (!additional_edge->opposite()->is_border()){ - if ( are_incident_facets_coplanar(additional_edge) ) - { - Facet_handle facet=additional_edge->face(); - const typename Kernel::Point_3& p0=get(ppmap, facet->halfedge()->vertex()); - const typename Kernel::Point_3& p1=get(ppmap, facet->halfedge()->next()->vertex()); - const typename Kernel::Point_3& p2=get(ppmap, facet->halfedge()->opposite()->vertex()); - CGAL_precondition( orientation( p0,p1,p2, get(ppmap, hedge->vertex()) ) == COPLANAR ); - - if ( has_at_least_two_incident_faces(hedge) && orientation( p0,p1,p2, get(ppmap, hedge->opposite()->vertex()) ) == COPLANAR ) - { - //In case two facets are incident along a common edge of two coplanar triangles. - //We need to remove three out of the four reported pair - Facet_handle smaller=make_sorted_pair_of_facets(hedge->face(),hedge->opposite()->face()).first; - coplanar_duplicated_intersection.insert(make_sorted_pair_of_facets(hedge->face(),facet)); - coplanar_duplicated_intersection.insert(make_sorted_pair_of_facets(hedge->opposite()->face(),facet)); - coplanar_duplicated_intersection.insert(make_sorted_pair_of_facets(hedge->opposite()->face(),additional_edge->opposite()->face())); - } - } - else - { - check_coplanar_edge(hedge,additional_edge->face()); - check_coplanar_edge(hedge,additional_edge->opposite()->face()); - } - } - else - check_coplanar_edge(hedge,additional_edge->face()); - } - else{ - CGAL_assertion(!additional_edge->opposite()->is_border()); - check_coplanar_edge(hedge,additional_edge->opposite()->face()); - } - } - break; - case internal_IOP::VERTEX: - - break; - - default: - CGAL_assertion(type==internal_IOP::COPLNR); - break; - } - } - - template - void check_coplanar_edges(Hedge_iterator begin,Hedge_iterator end,Halfedge_handle additional_edge,internal_IOP::Intersection_type type) - { - for (Hedge_iterator it=begin;it!=end;++it) - check_coplanar_edge(*it,additional_edge,type); - } - #endif // USE_DETECTION_MULTIPLE_DEFINED_EDGES - - void print_type_debug(internal_IOP::Intersection_type type,bool cpl,bool opp_cpl) - { - switch(type){ - case internal_IOP::COPLNR: - std::cout << "COPLNR " << cpl << " " << opp_cpl << std::endl; - break; - case internal_IOP::EMPTY: - std::cout << "EMPTY " << cpl << " " << opp_cpl << std::endl; - break; - - case internal_IOP::FACET: - std::cout << "FACET " << cpl << " " << opp_cpl << std::endl; - break; - - case internal_IOP::EDGE: - std::cout << "EDGE " << cpl << " " << opp_cpl << std::endl; - break; - case internal_IOP::VERTEX: - std::cout << "VERTEX " << cpl << " " << opp_cpl << std::endl; - break; - } - } - - - void handle_coplanar_case_VERTEX_FACET(Halfedge_handle vertex,Halfedge_handle facet,int node_id, bool is_new_node){ - if (is_new_node) - visitor->new_node_added(node_id,internal_IOP::FACET,vertex,facet,true,false); - std::vector all_edges; - get_incident_edges_to_vertex(vertex,std::back_inserter(all_edges)); - typename std::vector::iterator it_edge=all_edges.begin(); - for (;it_edge!=all_edges.end();++it_edge){ - add_intersection_point_to_facet_and_all_edge_incident_facets(facet->facet(),*it_edge,node_id); - typename Edge_to_intersected_facets::iterator it_ets=edge_to_sfacet.find(*it_edge); - if (it_ets!=edge_to_sfacet.end()) it_ets->second.erase(facet->facet()); - } - } - - void handle_coplanar_case_VERTEX_EDGE(Halfedge_handle vertex,Halfedge_handle edge,int node_id, bool is_new_node){ - if(is_new_node) - visitor->new_node_added(node_id,internal_IOP::VERTEX,edge,vertex,false,false); - std::vector all_edges; - get_incident_edges_to_vertex(vertex,std::back_inserter(all_edges)); - typename std::vector::iterator it_edge=all_edges.begin(); - for (;it_edge!=all_edges.end();++it_edge){ - typename Edge_to_intersected_facets::iterator it_ets=edge_to_sfacet.find(*it_edge); - Facet_set* fset = (it_ets!=edge_to_sfacet.end())?&(it_ets->second):NULL; - cip_handle_case_edge(node_id,fset,*it_edge,edge); - } - } - - void handle_coplanar_case_VERTEX_VERTEX(Halfedge_handle vertex1,Halfedge_handle vertex2,int node_id, bool is_new_node){ - if (is_new_node) - visitor->new_node_added(node_id,internal_IOP::VERTEX,vertex2,vertex1,true,false); - std::vector all_edges; - get_incident_edges_to_vertex(vertex1,std::back_inserter(all_edges)); - typename std::vector::iterator it_edge=all_edges.begin(); - for (;it_edge!=all_edges.end();++it_edge){ - typename Edge_to_intersected_facets::iterator it_ets=edge_to_sfacet.find(*it_edge); - Facet_set* fset = (it_ets!=edge_to_sfacet.end())?&(it_ets->second):NULL; - cip_handle_case_vertex(node_id,fset,*it_edge,vertex2); - } - } - - - template - std::pair get_or_create_node(Cpl_inter_pt& ipt,int& current_node,Coplanar_node_map& coplanar_node_map){ - void *v1, *v2; - switch(ipt.type_1){ - case internal_IOP::VERTEX: v1=(void*)( &(*(ipt.info_1->vertex())) ); break; - case internal_IOP::EDGE : v1=(void*)( &(*smaller_handle(ipt.info_1)) ); break; - case internal_IOP::FACET : v1=(void*)( &(*(ipt.info_1->facet())) ); break; - default: CGAL_error_msg("Should not get there!"); - } - - switch(ipt.type_2){ - case internal_IOP::VERTEX: v2=(void*)( &(*(ipt.info_2->vertex())) ); break; - case internal_IOP::EDGE : v2=(void*)( &(*smaller_handle(ipt.info_2)) ); break; - case internal_IOP::FACET : v2=(void*)( &(*(ipt.info_2->facet())) ); break; - default: CGAL_error_msg("Should not get there!"); - } - - std::pair key=make_sorted_void_pair(v1,v2); - - std::pair res=coplanar_node_map.insert(std::make_pair(key,current_node+1)); - if (res.second){ //insert a new node - - if (ipt.type_1==internal_IOP::VERTEX) - add_new_node(get(ppmap, ipt.info_1->vertex())); - else{ - if(ipt.type_2==internal_IOP::VERTEX) - add_new_node(get(ppmap, ipt.info_2->vertex())); - else - add_new_node(ipt.point); - } - return std::pair(++current_node, true); - } - return std::pair(res.first->second, false); - } - - void compute_intersection_of_coplanar_facets(int& current_node){ - typedef std::map,int> Coplanar_node_map; - Coplanar_node_map coplanar_node_map; - - for (typename Coplanar_facets_set::iterator it=coplanar_facets.begin();it!=coplanar_facets.end();++it){ - Facet_handle f1=it->first; - Facet_handle f2=it->second; - typedef internal_IOP::Intersection_point_with_info Cpl_inter_pt; - std::list inter_pts; - internal_IOP::intersection_coplanar_facets(f1->halfedge(),f2->halfedge(),ppmap,inter_pts); -// std::cout << "found " << inter_pts.size() << " inter pts: "; - std::size_t nb_pts=inter_pts.size(); - if (inter_pts.empty()) continue; - std::vector cpln_nodes; cpln_nodes.reserve(nb_pts); - for (typename std::list::iterator iti=inter_pts.begin();iti!=inter_pts.end();++iti){ - #ifdef CGAL_COREFINEMENT_DEBUG - //iti->print_debug(); - #endif - CGAL_assertion(iti->is_valid()); - int node_id; - bool is_new_node; - cpp11::tie(node_id, is_new_node)=get_or_create_node(*iti,current_node,coplanar_node_map); - cpln_nodes.push_back(node_id); - - switch(iti->type_1){ - case internal_IOP::VERTEX: - { - switch(iti->type_2){ - case internal_IOP::VERTEX: handle_coplanar_case_VERTEX_VERTEX(iti->info_1,iti->info_2,node_id, is_new_node); break; - case internal_IOP::EDGE : handle_coplanar_case_VERTEX_EDGE(iti->info_1,iti->info_2,node_id, is_new_node); break; - case internal_IOP::FACET : handle_coplanar_case_VERTEX_FACET(iti->info_1,iti->info_2,node_id, is_new_node); break; - default: CGAL_error_msg("Should not get there!"); - } - } - break; - case internal_IOP::EDGE:{ - switch(iti->type_2){ - case internal_IOP::VERTEX:handle_coplanar_case_VERTEX_EDGE(iti->info_2,iti->info_1,node_id, is_new_node);break; - case internal_IOP::EDGE: - { - if (is_new_node) - visitor->new_node_added(node_id,internal_IOP::EDGE,iti->info_1,iti->info_2,false,false); - typename Edge_to_intersected_facets::iterator it_ets=edge_to_sfacet.find(iti->info_1); - Facet_set* fset = (it_ets!=edge_to_sfacet.end())?&(it_ets->second):NULL; - cip_handle_case_edge(node_id,fset,iti->info_1,iti->info_2); - } - break; - default: CGAL_error_msg("Should not get there!"); - } - } - break; - - case internal_IOP::FACET: - { - CGAL_assertion(iti->type_2==internal_IOP::VERTEX); - handle_coplanar_case_VERTEX_FACET(iti->info_2,iti->info_1,node_id, is_new_node); - } - break; - - default: CGAL_error_msg("Should not get there!"); - } - } - switch (nb_pts){ - case 0: break; - case 1: - { - typename Facets_to_nodes_map::iterator it_list= - f_to_node.insert( std::make_pair( Facet_pair_and_int(*it,1),std::set()) ).first; - it_list->second.insert(cpln_nodes[0]); - } - break; - default: - { - int i=0; - std::size_t stop=nb_pts + (nb_pts<3?-1:0); - for (std::size_t k=0;k()) ).first; - it_list->second.insert( cpln_nodes[k] ); - it_list->second.insert( cpln_nodes[(k+1)%nb_pts] ); - } - } - } -// std::cout << std::endl; - } - } - - void compute_intersection_points(int& current_node){ - for(typename Edge_to_intersected_facets::iterator it=edge_to_sfacet.begin();it!=edge_to_sfacet.end();++it){ - Halfedge_handle edge=it->first; - Facet_set& fset=it->second; - while (!fset.empty()){ - Facet_handle facet=*fset.begin(); - - Intersection_result res=internal_IOP::do_intersect(edge,facet,ppmap); - internal_IOP::Intersection_type type=CGAL::cpp11::get<0>(res); - - //handle degenerate case: one extremity of edge below to facet - std::vector all_edges; - if ( CGAL::cpp11::get<2>(res) ) - get_incident_edges_to_vertex(edge,std::back_inserter(all_edges)); - else{ - if ( CGAL::cpp11::get<3>(res) ) - get_incident_edges_to_vertex(edge->opposite(),std::back_inserter(all_edges)); - else - all_edges.push_back(edge); - } - - CGAL_precondition(*all_edges.begin()==edge || *all_edges.begin()==edge->opposite()); -// print_type_debug(type,CGAL::cpp11::get<2>(res),CGAL::cpp11::get<3>(res)); - - #ifdef USE_DETECTION_MULTIPLE_DEFINED_EDGES - check_coplanar_edges(boost::next(all_edges.begin()),all_edges.end(),CGAL::cpp11::get<1>(res),type); - #endif - - typename std::vector::iterator it_edge=all_edges.begin(); - switch(type){ - case internal_IOP::COPLNR: - #ifndef DO_NOT_HANDLE_COPLANAR_FACETS - assert(!"COPLNR : this point should never be reached!"); - #else - //nothing need to be done, cf. comments at the beginning of the file - #endif - break; - case internal_IOP::EMPTY: - fset.erase(fset.begin()); - CGAL_assertion(!cgal_do_intersect_debug(edge,facet)); - break; - - // Case when the edge pierces the facet in its interior. - case internal_IOP::FACET: - { - CGAL_assertion(cgal_do_intersect_debug(edge,facet)); - CGAL_assertion(facet==CGAL::cpp11::get<1>(res)->face()); - - int node_id=++current_node; - add_new_node(edge,facet,res,nodes); - visitor->new_node_added(node_id,internal_IOP::FACET,edge,facet->halfedge(),CGAL::cpp11::get<2>(res),CGAL::cpp11::get<3>(res)); - for (;it_edge!=all_edges.end();++it_edge){ - add_intersection_point_to_facet_and_all_edge_incident_facets(facet,*it_edge,node_id); - //erase facet from the list to test intersection with it_edge - if ( it_edge==all_edges.begin() ) - fset.erase(fset.begin()); - else - { - typename Edge_to_intersected_facets::iterator it_ets=edge_to_sfacet.find(*it_edge); - if(it_ets!=edge_to_sfacet.end()) it_ets->second.erase(facet); - } - } - } // end case FACET - break; - - // Case when the edge intersect one edge of the facet. - case internal_IOP::EDGE: - { - CGAL_assertion(cgal_do_intersect_debug(edge,facet)); - int node_id=++current_node; - add_new_node(edge,facet,res,nodes); - Halfedge_handle edge_intersected=CGAL::cpp11::get<1>(res); - visitor->new_node_added(node_id,internal_IOP::EDGE,edge,edge_intersected,CGAL::cpp11::get<2>(res),CGAL::cpp11::get<3>(res)); - for (;it_edge!=all_edges.end();++it_edge){ - if ( it_edge!=all_edges.begin() ){ - typename Edge_to_intersected_facets::iterator it_ets=edge_to_sfacet.find(*it_edge); - Facet_set* fset_bis = (it_ets!=edge_to_sfacet.end())?&(it_ets->second):NULL; - cip_handle_case_edge(node_id,fset_bis,*it_edge,edge_intersected); - } - else - cip_handle_case_edge(node_id,&fset,*it_edge,edge_intersected); - } - } // end case EDGE - break; - - case internal_IOP::VERTEX: - { - CGAL_assertion(cgal_do_intersect_debug(edge,facet)); - int node_id=++current_node; - Halfedge_handle vertex_intersected=CGAL::cpp11::get<1>(res); - add_new_node(get(ppmap, vertex_intersected->vertex())); //we use the original vertex to create the node - //before it was internal_IOP::FACET but do not remember why, probably a bug... - visitor->new_node_added(node_id,internal_IOP::VERTEX,edge,vertex_intersected,CGAL::cpp11::get<2>(res),CGAL::cpp11::get<3>(res)); - for (;it_edge!=all_edges.end();++it_edge){ - if ( it_edge!=all_edges.begin() ){ - typename Edge_to_intersected_facets::iterator it_ets=edge_to_sfacet.find(*it_edge); - Facet_set* fset_bis = (it_ets!=edge_to_sfacet.end())?&(it_ets->second):NULL; - cip_handle_case_vertex(node_id,fset_bis,*it_edge,vertex_intersected); - } - else - cip_handle_case_vertex(node_id,&fset,*it_edge,vertex_intersected); - } - } // end case VERTEX - break; - - } // end switch on the type of the intersection - } // end loop on all facets that intersect the edge - } // end loop on all entries (edges) in 'edge_to_sfacet' - CGAL_assertion(nodes.size()==unsigned(current_node+1)); - } - - #ifdef USE_DETECTION_MULTIPLE_DEFINED_EDGES - void remove_duplicated_intersecting_edges() - { - for (typename Coplanar_duplicated_intersection_set::iterator - it=coplanar_duplicated_intersection.begin(); - it!=coplanar_duplicated_intersection.end(); - ++it) - { - typename Facets_to_nodes_map::iterator res=f_to_node.find(*it); - //CGAL_assertion(res!=f_to_node.end()); - //we cannot use a precondition here: in some cases the coplanarity test is not sufficient. - //if on surface1 we have to coplanar triangle incident along edge e. Then in surface2, take a triangle - //with one edge inside one triangle of surface1 such that one vertex in on e. Then the collinearity test - //return true for both faces but only one implies a duplicated edge - if(res!=f_to_node.end()) - f_to_node.erase(res); - } - } - #else // not USE_DETECTION_MULTIPLE_DEFINED_EDGES - void remove_duplicated_intersecting_edges() - { - std::set< std::pair > already_seen; - std::list to_erase; - for (typename Facets_to_nodes_map::iterator - it=f_to_node.begin(); - it!=f_to_node.end(); - ++it - ) - { - if (it->second.size()==1) continue; - CGAL_precondition(it->second.size()==2); - //it->second is a set so int are already sorted - bool is_new=already_seen.insert( std::make_pair( - *(it->second.begin()), - *boost::next(it->second.begin()) ) - ).second; - - if (!is_new) - to_erase.push_back(it); - } - - for ( typename std::list::iterator - it=to_erase.begin();it!=to_erase.end();++it - ) - f_to_node.erase(*it); - } - #endif // not USE_DETECTION_MULTIPLE_DEFINED_EDGES - - - struct Graph_node{ - std::set neighbors; - unsigned degree; - - Graph_node():degree(0){} - - void insert(int i){ - ++degree; - CGAL_assertion(neighbors.find(i)==neighbors.end()); - neighbors.insert(i); - } - - void erase(int i){ - CGAL_assertion(neighbors.find(i)!=neighbors.end()); - neighbors.erase(i); - } - void make_terminal() {if (degree==2) degree=45;} - bool is_terminal()const {return degree!=2;} - bool empty() const {return neighbors.empty();} - int top() const {return *neighbors.begin();} - void pop() { - CGAL_assertion(!neighbors.empty()); - neighbors.erase(neighbors.begin()); - } - }; - - - template - void construct_polylines(Nodes_vector& nodes,Output_iterator out){ - std::size_t nb_nodes=nodes.size(); - std::vector graph(nb_nodes); - //counts the number of time each node has been seen - bool isolated_point_seen=false; - for (typename Facets_to_nodes_map::iterator it=f_to_node.begin();it!=f_to_node.end();++it){ - const std::set& segment=it->second; - CGAL_assertion(segment.size()==2 || segment.size()==1); - if (segment.size()==2){ - int i=*segment.begin(); - int j=*boost::next(segment.begin()); - graph[i].insert(j); - graph[j].insert(i); - } - else{ - CGAL_assertion(segment.size()==1); - isolated_point_seen=true; - } - } - - //visitor call - visitor->annotate_graph(graph.begin(),graph.end()); - - //collect terminal and interior nodes - boost::dynamic_bitset<> terminal_nodes(nb_nodes), interior_nodes(nb_nodes); - for (std::size_t i=0;i(1,nodes[static_cast(i)]); - visitor->start_new_polyline(static_cast(i),static_cast(i)); - terminal_nodes.reset(i); - } - } - - //handle polylines - while(terminal_nodes.any()) - { - int i = static_cast(terminal_nodes.find_first()); - Graph_node& node_i = graph[i]; - std::vector polyline; - - int j=node_i.top(); - visitor->start_new_polyline(i,j); - CGAL_assertion(i!=j); - node_i.pop(); - if (node_i.empty()) - terminal_nodes.reset(i); - polyline.push_back(nodes[i]); - while(true){ - Graph_node& node_j=graph[j]; - CGAL_assertion(!node_j.empty()); - node_j.erase(i); - i=j; - polyline.push_back(nodes[i]); - if (node_j.is_terminal()) - { - if (node_j.empty()) - terminal_nodes.reset(j); - break; - } - else{ - j=node_j.top(); - visitor->add_node_to_polyline(j); - node_j.pop(); - CGAL_assertion(node_j.empty()); - interior_nodes.reset(i); - } - } - *out++=polyline; - } - - //handle cycles - while(interior_nodes.any()) - { - int i=static_cast(interior_nodes.find_first()); - Graph_node& node_i=graph[i]; - std::vector polyline; - - int j=node_i.top(); - visitor->start_new_polyline(i,j); - interior_nodes.reset(i); - polyline.push_back(nodes[i]); - int first=i; - do{ - Graph_node& node_j=graph[j]; - interior_nodes.reset(j); - node_j.erase(i); - i=j; - polyline.push_back(nodes[i]); - j=node_j.top(); - visitor->add_node_to_polyline(j); - }while(j!=first); - polyline.push_back(nodes[j]);// we duplicate first point for cycles - *out++=polyline; - } - } - - int get_other_int(const std::set& s,int i) const { - if (*s.begin()!=i) return *s.begin(); - return *boost::next(s.begin()); - } - - template - bool is_grabbed(const Dispatch_out_it&) const{ - return CGAL::Is_in_tuple::value; - } - - - template - struct Is_dispatch_based_ouput_iterator{ - typedef boost::false_type type; - }; - - template class Dispatch_based_output_it,class V,class O> - struct Is_dispatch_based_ouput_iterator >{ - typedef typename boost::is_base_of< Dispatch_output_iterator, - Dispatch_based_output_it >::type type; - }; - - template - inline void construct_polylines_with_info(Nodes_vector& nodes,Output_iterator out){ - return construct_polylines_with_info(nodes,out,typename Is_dispatch_based_ouput_iterator::type()); - } - - template - void construct_polylines_with_info(Nodes_vector& nodes,Output_iterator out,boost::false_type){ - construct_polylines_with_info(nodes, - dispatch_or_drop_output >(out),boost::true_type()); - } - - template class Dispatch_based_output_it,class V,class O> - void construct_polylines_with_info(Nodes_vector& nodes, - Dispatch_based_output_it out,boost::true_type) - { - typedef typename Facets_to_nodes_map::value_type Edge; - typedef std::list Polyline_info; - - - std::size_t nb_nodes=nodes.size(); - std::vector node_mult(nb_nodes,0); - std::vector terminal_bools(nb_nodes,false); - std::vector< std::set > connections(nb_nodes); - // --counts the number of time each node has been seen - // --associate to each node its incident edges. An edge = a pair of Facet_handle+2 indices of intersection points - for (typename Facets_to_nodes_map::iterator it=f_to_node.begin();it!=f_to_node.end();++it){ - const std::set& segment=it->second; - CGAL_assertion(segment.size()==2 || segment.size()==1); - if (segment.size()==2){ - int i=*segment.begin(); - int j=*boost::next(segment.begin()); - connections[i].insert(&(*it)); - connections[j].insert(&(*it)); - ++(node_mult[i]); - ++(node_mult[j]); - } - } - - //detect terminal nodes and isolated nodes - for (unsigned k=0;k(1,nodes[k]); - if ( is_grabbed >(out)) - *out++=std::vector(); - } - } - - //visitor call - visitor->update_terminal_nodes(terminal_bools); - - //We start from a node N and recursively walk one edge to find other - // node. If this is a cycle we stop when we are back at the node N; - //otherwise we stop at a terminal node and restart a walk from N - //following another edge (if N is not terminal) until finding a terminal - //node. With this we can associate to each edge the pair of facet_handle - //intersecting that define this edge. - unsigned current_node=0; - while (current_node!=nb_nodes){ - if (connections[current_node].empty()){ - ++current_node; - continue; - } - - Edge* edge=*connections[current_node].begin(); - connections[current_node].erase(connections[current_node].begin()); - - Polyline_info polyline_info; - std::list polyline_embedding; - - if ( is_grabbed >(out)) - polyline_info.push_back(edge->first.first); - polyline_embedding.push_back(nodes[current_node]); - - unsigned i=current_node; - unsigned start_node=current_node; - bool reverse=false; - while (true){ - i=get_other_int(edge->second,i); - connections[i].erase(edge); - - if (reverse) polyline_embedding.push_front(nodes[i]); - else polyline_embedding.push_back(nodes[i]); - - if (i==start_node) break; - if (terminal_bools[i]){ - if (reverse || terminal_bools[current_node]) break; - reverse=true; - i=current_node; - if ( connections[i].empty() ) break; - } - - edge=*connections[i].begin(); - connections[i].erase(connections[i].begin()); - - if ( is_grabbed >(out)){ - if (reverse) polyline_info.push_front(edge->first.first); - else polyline_info.push_back(edge->first.first); - } - - } - - *out++=std::vector(polyline_embedding.begin(),polyline_embedding.end()); - if ( is_grabbed >(out)){ - CGAL_assertion(polyline_embedding.size()==polyline_info.size()+1); - *out++=std::vector(polyline_info.begin(),polyline_info.end()); - } - } - } - -//debug functions - - bool cgal_do_intersect_debug(Halfedge_handle eh,Facet_handle fh){ - Triangle t( get(ppmap, fh->halfedge()->vertex()), - get(ppmap, fh->halfedge()->next()->vertex()), - get(ppmap, fh->halfedge()->next()->next()->vertex())); - - Segment s( get(ppmap, eh->vertex()), - get(ppmap, eh->opposite()->vertex())); - - return CGAL::do_intersect( s, t); - } - - bool cgal_do_intersect_debug(Facet_handle fh1,Facet_handle fh2){ - Triangle t1( get(ppmap, fh1->halfedge()->vertex()), - get(ppmap, fh1->halfedge()->next()->vertex()), - get(ppmap, fh1->halfedge()->next()->next()->vertex())); - Triangle t2( get(ppmap, fh2->halfedge()->vertex()), - get(ppmap, fh2->halfedge()->next()->vertex()), - get(ppmap, fh2->halfedge()->next()->next()->vertex())); - - - return CGAL::do_intersect( t1, t2); - } - - void print_f_to_node_debug(){ - std::cout << "print_f_to_node_debug " << &f_to_node << std::endl; - for (typename Facets_to_nodes_map::iterator it=f_to_node.begin();it!=f_to_node.end();++it){ - std::cout << &(*(it->first.first.first)) << " " << &(*(it->first.first.second)) << " " << it->first.second << " -> {"; - std::copy(it->second.begin(),it->second.end(),std::ostream_iterator(std::cout,",")); - std::cout << "}" <& graph){ - for (typename std::map::const_iterator it=graph.begin();it!=graph.end();++it){ - std::cout << it->first << " -> {"; - std::copy(it->second.neighbors.begin(),it->second.neighbors.end(),std::ostream_iterator(std::cout,",")); - std::cout << "}" <second; - std::cout << &fset << " fset size " << fset.size() << std::endl; - } - } - - - template - OutputIterator main_run(OutputIterator out,bool build_polylines=true){ - // std::cout << edge_to_sfacet.size() << std::endl; - int current_node=-1; - - //print_edge_to_sfacet_debug(); - #ifndef DO_NOT_HANDLE_COPLANAR_FACETS - //first handle coplanar triangles - compute_intersection_of_coplanar_facets(current_node); - visitor->set_number_of_intersection_points_from_coplanar_facets(current_node+1); - if (!coplanar_facets.empty()) - visitor->input_have_coplanar_facets(); - #endif // not DO_NOT_HANDLE_COPLANAR_FACETS - //print_edge_to_sfacet_debug(); - //compute intersection points of segments and triangles. - //build node of the graph - //build connectivity info - compute_intersection_points(current_node); // 'current_node' is passed by - // non-const reference - - if (!build_polylines){ - visitor->finalize(nodes); - return out; - } - //remove duplicated intersecting edges: - // In case two facets are incident along such an edge coplanar in a facet of another polyhedron (and one extremity inside the facet), the intersection - // will be reported twice. We kept track (check_coplanar_edge(s)) of this so that, we can remove one intersecting edge out of the two - //print_f_to_node_debug(); - remove_duplicated_intersecting_edges(); - - //std::cout << "f_to_node "<< f_to_node.size() << std::endl; - //print_f_to_node_debug(); - //collect connectivity infos and create polylines - if ( Node_visitor::do_need_vertex_graph ) - construct_polylines(nodes,out); //using the graph approach (at some point we know all connections between intersection points) - else - construct_polylines_with_info(nodes,out); //direct construction by propagation - - visitor->finalize(nodes); - - return out; - } - -public: - Intersection_of_Polyhedra_3(PolyhedronPointPMap ppmap=PolyhedronPointPMap()) - :ppmap(ppmap),nodes(ppmap), - visitor(new Node_visitor()), - is_default_visitor(true){} - Intersection_of_Polyhedra_3(Node_visitor& v, - PolyhedronPointPMap ppmap=PolyhedronPointPMap()) - :ppmap(ppmap),nodes(ppmap),visitor(&v),is_default_visitor(false){} - ~Intersection_of_Polyhedra_3(){if (is_default_visitor) delete visitor;} - //pairwise intersection between all elements in the range - template - OutputIterator - operator()(InputIterator begin, InputIterator end, OutputIterator out) { - for(InputIterator it1=begin;it1!=end;++it1){ - CGAL_precondition( it1->is_pure_triangle() ); - Polyhedron_ref P=*it1; - visitor->new_input_polyhedron(P); - for(InputIterator it2=boost::next(it1);it2!=end;++it2){ - CGAL_precondition( it2->is_pure_triangle() ); - Polyhedron_ref Q=*it2; - filter_intersections(P, Q); - filter_intersections(Q, P); - } - } - - return main_run(out); - } - - //pairwise intersection between all elements in the range - //(pointers version) - template - OutputIterator - operator()(InputIterator begin, InputIterator end, OutputIterator out, int) { - for(InputIterator it1=begin;it1!=end;++it1){ - CGAL_precondition( (*it1)->is_pure_triangle() ); - Polyhedron_ref P=**it1; - visitor->new_input_polyhedron(P); - for(InputIterator it2=boost::next(it1);it2!=end;++it2){ - CGAL_precondition( (*it2)->is_pure_triangle() ); - Polyhedron_ref Q=**it2; - filter_intersections(P, Q); - filter_intersections(Q, P); - } - } - - return main_run(out); - } - - //intersection between P and each element in the range - template - OutputIterator - operator()( Polyhedron_ref P, InputIterator begin, InputIterator end, OutputIterator out) { - CGAL_precondition( P.is_pure_triangle() ); - visitor->new_input_polyhedron(P); - for(InputIterator it=begin;it!=end;++it){ - CGAL_precondition( it->is_pure_triangle() ); - Polyhedron_ref Q=*it; - visitor->new_input_polyhedron(Q); - filter_intersections(P, Q); - filter_intersections(Q, P); - } - return main_run(out); - } - - //intersection between P and each element in the range - //(pointers version) - template - OutputIterator - operator()(Polyhedron_ref P, InputIterator begin, InputIterator end, OutputIterator out, int) { - CGAL_precondition( P.is_pure_triangle() ); - visitor->new_input_polyhedron(P); - for(InputIterator it=begin;it!=end;++it){ - CGAL_precondition( (*it)->is_pure_triangle() ); - Polyhedron_ref Q=**it; - visitor->new_input_polyhedron(Q); - filter_intersections(P, Q); - filter_intersections(Q, P); - } - return main_run(out); - } - - //intersection between P and Q - template - OutputIterator - operator()(Polyhedron_ref P, Polyhedron_ref Q, OutputIterator out) { - visitor->new_input_polyhedron(P); - visitor->new_input_polyhedron(Q); - filter_intersections(P, Q); - filter_intersections(Q, P); - return main_run(out); - } - - //intersection between P and Q, only visitor called not polyline is constructed - void operator()(Polyhedron_ref P, Polyhedron_ref Q) { - visitor->new_input_polyhedron(P); - visitor->new_input_polyhedron(Q); - filter_intersections(P, Q); - filter_intersections(Q, P); - main_run(Emptyset_iterator(),false); - } -}; - -template -OutputIterator -intersection_Polyhedron_3_Polyhedron_3(const Polyhedron& P, const Polyhedron& Q, OutputIterator out) -{ - return Intersection_of_Polyhedra_3()(P,Q,out); -} - -}// namespace CGAL - -#include - -#endif //CGAL_INTERSECTION_OF_POLYHEDRA_3_H - -/* - // Local variables for Emacs: - // - set special indentation of case labels, compared to usual C/C++ - // indentation styles. - Local Variables: - c-file-offsets:((case-label . +)) - End: -*/ diff --git a/Operations_on_polyhedra/include/CGAL/intersection_of_Polyhedra_3_refinement_visitor.h b/Operations_on_polyhedra/include/CGAL/intersection_of_Polyhedra_3_refinement_visitor.h deleted file mode 100644 index 71533b11402..00000000000 --- a/Operations_on_polyhedra/include/CGAL/intersection_of_Polyhedra_3_refinement_visitor.h +++ /dev/null @@ -1,1163 +0,0 @@ -// Copyright (c) 2011 GeometryFactory (France). -// All rights reserved. -// -// This file is part of CGAL (www.cgal.org). -// You can redistribute it and/or modify it under the terms of the GNU -// General Public License as published by the Free Software Foundation, -// either version 3 of the License, or (at your option) any later version. -// -// Licensees holding a valid commercial license may use this file in -// accordance with the commercial license agreement provided with the software. -// -// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE -// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. -// -// $URL$ -// $Id$ -// SPDX-License-Identifier: GPL-3.0+ -// -// -// Author(s) : Sebastien Loriot - -#ifndef CGAL_INTERSECTION_OF_POLYHEDRA_3_REFINEMENT_VISITOR_H -#define CGAL_INTERSECTION_OF_POLYHEDRA_3_REFINEMENT_VISITOR_H - -#include - -#include - -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include -#include -#include - -// TODOCUMENT -// --We suppose that the two input polyhedra are triangulated orientable surfaces. -// --Any polyhedron defines two bounding volumes: one inside and one outside. -// The convention used is the following: the normal of a triangle always indicates -// the outside of the object. -// --The input polyhedra should not touch at only one point locally. If so, the current -// implementation just ignore it (TAG SL001) -// --Polyhedron type should be list-based or should guarantee no reallocation. We use maps -// on pointer of halfedges,facets and vertices -// --Polyhedral_mesh_domain requires the domain tp be closed: do not provided as input -// an open polyhedral surface and a polyhedron with a connected component free from intersection -//OPTIMIZATIONS -// --cdt: try using intervals? in that case, only points inside the face should be considered -// and points on edge should be handled by hand (simply start using the point opposite to the edge) -// --sorted_around_edge_filtered: can be done using the original supporting planes -// --in intersection_of_Polyhedra_3: upon call to Triangle_segment_intersection_point::add_new_node, interval and exact nodes are -// inserted into a vector. Since we do not know the final size of vector this lead to reallocation of data. -// --in Triangle_segment_intersection_point, try using EPEC instead of Interval_nt+SC -// --use a sorted pair of indices in edge_to_hedge+simplify the code TAG_SLXX1 -// --in sew_2_marked_darts arrange how darts are passed to avoid comparing to a Point_3 -//TODO: -// --validity of the embedding: points inserted in polyhedron are approximation of the real -// intersection points. It may happen that because of the approximation, the embedding gets -// wrong. To avoid this, for each new triangle created, we should make an orientation test -// with the approximated point to check if this is correct. If not, points must be moved -// within their double interval so that all triangles incident to each of these points are correctly -// oriented. This is probably an expensive test that can be activated only with a template parameter -// of something similar. -// -- We should have an option to report intersection at a point and refinement of polyhedra -// so that the point is included into the other polyhedra. Please be careful if the point -// already exists bool report_isolated_point or a template parameter (polyline with a unique point) -namespace CGAL -{ - - namespace internal_IOP - { - - template - class Triangulate_a_face : public CGAL::Modifier_base { - typedef typename HDS::Halfedge_handle Halfedge_handle; - typedef typename HDS::Vertex_handle Vertex_handle; - typedef typename HDS::Face_handle Face_handle; - typedef typename HDS::Vertex Vertex; - typedef typename HDS::Halfedge Halfedge; - typedef typename HDS::Face Face; - typedef typename boost::property_traits::value_type Point; - - //data members - Face_handle current_face; - std::map nodes_; - std::map& node_to_polyhedron_vertex_; - std::map,Halfedge_handle>& edge_to_hedge_; - std::vector > edges_to_create_; - std::vector > faces_to_create_; - NestedFacetConstruct facet_construct; - NewNodeVertexVisitor& node_vertex_visitor; - PolyhedronPointPMap ppmap; - - typename HDS::Halfedge::Base* - unlock_halfedge(Halfedge_handle h){ - return static_cast(&(*h)); - } - - typename HDS::Face::Base* - unlock_face(Face_handle f){ - return static_cast(&(*f)); - } - - public: - - template - Triangulate_a_face( Face_handle face, - const Nodes_vector& nodes, - const std::vector& node_ids, - std::map& node_to_polyhedron_vertex, - std::map,Halfedge_handle>& edge_to_hedge, - const Triangulation& triangulation, - const NestedFacetConstruct& fc, - NewNodeVertexVisitor& nv, - PolyhedronPointPMap ppmap) - :current_face(face), node_to_polyhedron_vertex_(node_to_polyhedron_vertex), edge_to_hedge_(edge_to_hedge), facet_construct(fc), node_vertex_visitor(nv), ppmap(ppmap) - { - //grab vertices to be inserted to copy them from the vector - for (std::vector::const_iterator it=node_ids.begin();it!=node_ids.end();++it) - { - nodes_.insert(std::make_pair(*it,nodes[*it])); - } - //grab edges that are not on the convex hull (these have already been created) - for (typename Triangulation::Finite_edges_iterator - it=triangulation.finite_edges_begin(); - it!=triangulation.finite_edges_end(); - ++it) - { - typename Triangulation::Vertex_handle v0=it->first->vertex((it->second+1)%3); - typename Triangulation::Vertex_handle v1=it->first->vertex((it->second+2)%3); - //warning in degenerate cases you can insert outsite expected convex hull edges: need exact here. - //an alternative is to test if one the incident faces are infinite (cf assertion below) - if ( edge_to_hedge_.find(std::make_pair(v0->info(),v1->info()))==edge_to_hedge_.end() && - edge_to_hedge_.find(std::make_pair(v1->info(),v0->info()))==edge_to_hedge_.end() ) - { - edges_to_create_.push_back( std::make_pair(v0->info(),v1->info()) ); - } - else - CGAL_assertion( triangulation.is_infinite(it->first->vertex(it->second)) || triangulation.is_infinite( triangulation.mirror_vertex(it->first,it->second)) ); - } - //grab triangles. - for (typename Triangulation::Finite_faces_iterator - it=triangulation.finite_faces_begin(); - it!=triangulation.finite_faces_end(); - ++it) - { - typename Triangulation::Vertex_handle v0=it->vertex(0); - typename Triangulation::Vertex_handle v1=it->vertex(1); - typename Triangulation::Vertex_handle v2=it->vertex(2); - //warning in degenerate case we can have non wanted triangles: need exact here - faces_to_create_.push_back( CGAL::cpp11::make_tuple( v0->info(),v1->info(),v2->info() ) ); - } - } - - - - void operator()( HDS& hds) { -// std::cerr << "node_to_polyhedron_vertex_"<< std::endl; -// for (typename std::map::iterator it=node_to_polyhedron_vertex_.begin();it!=node_to_polyhedron_vertex_.end();++it) -// std::cerr << it->first << " " << &(*(it->second)) << std::endl; - - //insert the intersection point interior to the face inside the polyhedron and - //save their Polyhedron::vertex_handle - for (typename std::map::iterator it=nodes_.begin();it!=nodes_.end();++it) - { - Vertex_handle v=hds.vertices_push_back(Vertex()); - node_vertex_visitor.new_vertex_added(it->first, v); - put(ppmap, v, it->second); - CGAL_assertion( node_to_polyhedron_vertex_.find( it->first ) == node_to_polyhedron_vertex_.end()); - node_to_polyhedron_vertex_.insert( std::make_pair(it->first,v) ); -// std::cerr << "vertices " << it->first << " " << &(*v) << std::endl; - } - - //insert the new halfedge and set their incident vertex - for (typename std::vector >::iterator - it=edges_to_create_.begin();it!=edges_to_create_.end();++it) - { - Halfedge_handle he=hds.edges_push_back(Halfedge(),Halfedge()); - - //associate edge to halfedge going from i to j with j as incident vertex - CGAL_assertion(node_to_polyhedron_vertex_.find(it->second)!= node_to_polyhedron_vertex_.end()); - Vertex_handle v=node_to_polyhedron_vertex_.find(it->second)->second; - unlock_halfedge(he)->set_vertex( v ); - v->set_halfedge(he); -// std::cerr << " --in edge " << &(*v) << std::endl; - edge_to_hedge_.insert( std::make_pair(*it,he) ); - v=node_to_polyhedron_vertex_.find(it->first)->second; -// std::cerr << " --in edge " << &(*v) << std::endl; - unlock_halfedge( he->opposite() )->set_vertex( v ); - v->set_halfedge(he->opposite()); - edge_to_hedge_.insert( std::make_pair(std::make_pair(it->second,it->first),he->opposite()) ); -// std::cerr << "edges " << it->first << " " << it->second << std::endl; - } - - std::vector >::iterator it=faces_to_create_.begin(); - Face_handle face_triangulated = current_face; - //create the new faces and update adjacencies - while (true) - { - int i=cpp11::get<0>(*it),j=cpp11::get<1>(*it),k=cpp11::get<2>(*it); -// std::cerr << "faces " << i << " " << j << " " << k<< std::endl; - Halfedge_handle current = edge_to_hedge_.find(std::make_pair(i,j))->second; - Halfedge_handle next = edge_to_hedge_.find(std::make_pair(j,k))->second; - Halfedge_handle previous = edge_to_hedge_.find(std::make_pair(k,i))->second; - - - CGAL_assertion (edge_to_hedge_.find(std::make_pair(i,j))!=edge_to_hedge_.end()); - CGAL_assertion (edge_to_hedge_.find(std::make_pair(j,k))!=edge_to_hedge_.end()); - CGAL_assertion (edge_to_hedge_.find(std::make_pair(k,i))!=edge_to_hedge_.end()); - - CGAL_assertion(current->vertex()==node_to_polyhedron_vertex_.find(j)->second); - CGAL_assertion(next->vertex()==node_to_polyhedron_vertex_.find(k)->second); - CGAL_assertion(previous->vertex()==node_to_polyhedron_vertex_.find(i)->second); - - unlock_halfedge(current)->set_next(next); - unlock_halfedge(next)->set_next(previous); - unlock_halfedge(previous)->set_next(current); - - unlock_halfedge(current)->set_prev(previous); - unlock_halfedge(next)->set_prev(current); - unlock_halfedge(previous)->set_prev(next); - - //update face halfedge - unlock_face(current_face)->set_halfedge(current); - - //update face of halfedges - unlock_halfedge(current) ->set_face(current_face); - unlock_halfedge(next) ->set_face(current_face); - unlock_halfedge(previous) ->set_face(current_face); - - if ( ++it!=faces_to_create_.end() ) - current_face=hds.faces_push_back( facet_construct(*face_triangulated) ); - else - break; - } - } - }; - - template - Halfedge_handle - next_marked_halfedge_around_target_vertex(Halfedge_handle h, const Marked_set& is_marked) - { - CGAL_assertion( is_marked.find(h)!=is_marked.end() ); - Halfedge_handle next=h->next(); - while( is_marked.find(next)==is_marked.end() ) - { - next=next->opposite()->next(); - } - CGAL_assertion(next!=h); - return next; - } - - template - Halfedge_handle - next_marked_halfedge_around_source_vertex(Halfedge_handle h, const Marked_set& is_marked) - { - CGAL_assertion( is_marked.find(h)!=is_marked.end() ); - Halfedge_handle prev=h->prev(); - while(is_marked.find(prev)==is_marked.end()) - { - prev=prev->opposite()->prev(); - } - CGAL_assertion(prev!=h); - return prev; - } - - } //namespace internal_IOP - -template -struct Default_facet_construct{ - typename Polyhedron::Facet operator()( const typename Polyhedron::Facet& f) - { return f; } -}; - -template -struct Default_node_vertex_visitor{ - void new_node_added( int /* node_id */, - internal_IOP::Intersection_type /* type */, - typename Polyhedron::Halfedge_handle /* principal_edge */, - typename Polyhedron::Halfedge_handle /* additional_edge */, - bool /* is_vertex_coplanar */, - bool /* is_vertex_opposite_coplanar */ ) - {} - - void new_vertex_added(int /* node_id */, typename Polyhedron::Vertex_handle /* vh */){} -}; - -struct Default_output_builder{ - template - void operator()(const T1&, const T2&, const T3&, const T4&, const T5&){} - void input_have_coplanar_facets(){} -}; - -template< class Polyhedron, - class OutputBuilder_=Default, - class Kernel_=Default, - class EdgeMarkPropertyMap_=Default, - class NestedFacetConstruct_=Default, - class NewNodeVertexVisitor_=Default, - class PolyhedronPointPMap_=Default - > -class Node_visitor_refine_polyhedra{ -//Default typedefs - typedef typename Default::Get::type OutputBuilder; - typedef typename Default::Get >::type EdgeMarkPropertyMap; - typedef typename Default::Get >::type NestedFacetConstruct; - typedef typename Default::Get >::type NewNodeVertexVisitor; - typedef typename Default::Get >::type PolyhedronPointPMap; - typedef typename Default::Get::value_type >::Kernel >::type Kernel; -//typedefs - typedef typename Polyhedron::Halfedge_handle Halfedge_handle; - typedef typename Polyhedron::Halfedge_const_handle Halfedge_const_handle; - typedef typename Polyhedron::Face_handle Face_handle; - typedef typename Polyhedron::Halfedge Halfedge; - typedef typename Polyhedron::Vertex_handle Vertex_handle; - typedef internal_IOP::Compare_handles Cmp_handle; //This ensures uniqueness of edges when comparing halfedges - typedef internal_IOP::Compare_unik_address Cmp_unik_ad; //This ensures uniqueness of edges when comparing halfedges - - //constrained triangulation used for triangulation interior of faces - #ifdef DO_NO_USE_EXACT_CDT - typedef CGAL::Triangulation_vertex_base_with_info_2 Vbi; - typedef CGAL::Constrained_triangulation_face_base_2 Fb; - typedef CGAL::Triangulation_data_structure_2 TDS_2; - typedef CGAL::Constrained_Delaunay_triangulation_2 CDT; //DO WE NEED DELAUNAY???? - #else - /// \todo change this, use it only if not already exact - typedef CGAL::Exact_predicates_exact_constructions_kernel Exact_kernel; - typedef CGAL::Triangulation_vertex_base_with_info_2 Vbi; - typedef CGAL::Constrained_triangulation_face_base_2 Fb; - typedef CGAL::Triangulation_data_structure_2 TDS_2; - typedef CGAL::Constrained_Delaunay_triangulation_2 CDT; //DO WE NEED DELAUNAY???? - #endif - - typedef std::map Hedge_to_polyhedron_map; - - typedef std::vector Node_ids; - typedef std::map< Face_handle,Node_ids,Cmp_handle > In_face_map; - typedef std::map< Halfedge_handle,Node_ids,Cmp_unik_ad > In_halfedge_map; - //to keep the correspondance between node_id and vertex_handle in each polyhedron - typedef std::map Node_to_polyhedron_vertex_map; - typedef std::map Poly_to_map_node; - //to maintain an polyhedron halfedge on each polyline + pair - //with first = "is the key (pair) was reversed?" and second is the number of edges +1 in the polyline - typedef std::map< std::pair, std::pair< std::map,std::pair > > An_edge_per_polyline_map; - //to handle coplanar halfedge of polyhedra that are full in the intersection - typedef std::map< int,Halfedge_handle > Node_to_target_of_hedge_map; - typedef std::map< Polyhedron*,Node_to_target_of_hedge_map> Poly_to_vertices_on_intersection_map; - -//data members - Hedge_to_polyhedron_map hedge_to_polyhedron; - In_face_map in_face; - In_halfedge_map in_hedge; - std::map< int,std::set > graph_of_constraints; - boost::dynamic_bitset<> is_node_of_degree_one; - std::map< int,std::set > coplanar_constraints; - An_edge_per_polyline_map an_edge_per_polyline; - typename An_edge_per_polyline_map::iterator last_polyline; - Poly_to_vertices_on_intersection_map poly_to_vertices_on_inter; - Poly_to_map_node polyhedron_to_map_node_to_polyhedron_vertex; - std::set non_manifold_nodes; //contain nodes that are original vertices of input polyhedron and that neighborhood is not a topological disk - std::map nodes_that_are_original_vertices;//to keep the correspondance between original polyhedron vertices that are also nodes - - OutputBuilder output_builder; - - // new_hedge hedge - // -----------> -----------> - // v - // <----------- <----------- - // new_opposite opposite - // - template - Vertex_handle split_edge( Halfedge_handle hedge, - int node_id, - const Nodes_vector& nodes, - Polyhedron& P) - { - internal_IOP::Split_halfedge delegated(hedge); - P.delegate( delegated ); - CGAL_assertion(P.is_valid()); - - Vertex_handle vh=boost::prior(P.vertices_end()); - node_vertex_visitor.new_vertex_added(node_id, vh); - put(ppmap, vh, nodes[node_id]); - CGAL_assertion(get(ppmap,vh)==nodes[node_id]); - - //update marker tags. If the edge was marked, then the resulting edges in the split must be marked - if ( get(m_edge_mark_pmap,std::make_pair(hedge,&P)) ) - { - CGAL_assertion( get(m_edge_mark_pmap,std::make_pair(hedge->opposite(),&P)) ); - put(m_edge_mark_pmap,std::make_pair(hedge->prev(),&P),true); - put(m_edge_mark_pmap,std::make_pair(hedge->prev()->opposite(),&P),true); - } - - return vh; - } - - //sort node ids so that we can split the hedge - //consecutively - template - void sort_vertices_along_hedge(std::vector& node_ids,Halfedge_handle hedge,const Nodes_vector& nodes) - { - std::sort(node_ids.begin(), - node_ids.end(), - internal_IOP::Order_along_a_halfedge(hedge,nodes, ppmap) - ); - } - - //insert intersection as constrained edges in a CDT triangulation - template - void insert_constrained_edges_coplanar_case(int node_id, - CDT& triangulation, - std::map& id_to_CDT_vh) - { - if (node_id < number_coplanar_vertices){ - //XSL_TAG_CPL_VERT - //Insert constrained edges from coplanar facets that have been retriangulated. This ensure that triangulations are compatible - std::map< int,std::set >::iterator it_neighbors=coplanar_constraints.find(node_id); - if (it_neighbors!=coplanar_constraints.end()) - { - typename CDT::Vertex_handle vh=id_to_CDT_vh.find(node_id)->second; - for (std::set::iterator it_n=it_neighbors->second.begin();it_n!=it_neighbors->second.end();++it_n){ - typename std::map::iterator it_vh=id_to_CDT_vh.find(*it_n); - // this condition ensures to consider only graph edges that are in the same triangle (not in a neighbor one when involving node on a triangle edge) - // here we can't make the difference between a point on the interior or the boundary, so points_on_triangle is not used. - if ( it_vh!=id_to_CDT_vh.end() ){ - triangulation.insert_constraint(vh,id_to_CDT_vh.find(*it_n)->second); - } - } - } - } - } - //insert intersection as constrained edges in a CDT triangulation - template - void insert_constrained_edges(Node_ids& node_ids, //index of vertices we are interested in - CDT& triangulation, - std::map& id_to_CDT_vh, - Constrained_edges_map& constrained_edges, //list of pair of int to indicate edges that are constrained - bool points_on_triangle=false) - { - for (Node_ids::iterator it_node_id=node_ids.begin();it_node_id!=node_ids.end();++it_node_id){ - std::map< int,std::set >::iterator it_neighbors=graph_of_constraints.find(*it_node_id); - if (it_neighbors!=graph_of_constraints.end()) - { - typename CDT::Vertex_handle vh=id_to_CDT_vh.find(*it_node_id)->second; - for (std::set::iterator it_n=it_neighbors->second.begin();it_n!=it_neighbors->second.end();++it_n){ - typename std::map::iterator it_vh=id_to_CDT_vh.find(*it_n); - // this condition ensures to consider only graph edges that are in the same triangle (not in a neighbor one when involving node on a triangle edge) - if ( !points_on_triangle || it_vh!=id_to_CDT_vh.end() ){ - CGAL_assertion(it_vh!=id_to_CDT_vh.end()); - triangulation.insert_constraint(vh,id_to_CDT_vh.find(*it_n)->second); - constrained_edges.push_back(std::make_pair(*it_node_id,*it_n)); - } - } - } - #ifdef CGAL_COREFINEMENT_DEBUG - else - { - std::cout << "X0: Found an isolated point" << std::endl; - } - #endif - - insert_constrained_edges_coplanar_case(*it_node_id,triangulation,id_to_CDT_vh); - } - } - - std::pair make_sorted_pair(int i,int j) const {return i indices,typename Polyhedron::Halfedge_handle hedge) - { - std::pair sorted_pair=make_sorted_pair(indices.first,indices.second); - typename An_edge_per_polyline_map::iterator it=an_edge_per_polyline.find(sorted_pair); - if (it!=an_edge_per_polyline.end()){ - it->second.first.insert(std::make_pair( P,sorted_pair.first==indices.first?hedge:hedge->opposite() )); - } - } - - //keep track of the fact that a polyhedron original vertex is a node - void all_incident_faces_got_a_node_as_vertex(Halfedge_handle incident_to_vertex_edge,int node_id) - { - nodes_that_are_original_vertices.insert(std::make_pair(incident_to_vertex_edge->vertex(),node_id)); - } - - //if an original polyhedron vertex is also a node, do no use a fake id - void set_triangle_boundary_indices( - Vertex_handle* triangle_boundary, - int* triangle_boundary_indices) - { - triangle_boundary_indices[0]=-1; - triangle_boundary_indices[1]=-2; - triangle_boundary_indices[2]=-3; - - for (int k=0;k<3;++k){ - typename std::map::iterator it=nodes_that_are_original_vertices.find(triangle_boundary[k]); - if (it!=nodes_that_are_original_vertices.end()) - triangle_boundary_indices[k]=it->second; - } - } - - int number_coplanar_vertices; //number of intersection points between coplanar facets, see fixes XSL_TAG_CPL_VERT - EdgeMarkPropertyMap m_edge_mark_pmap; //property map to mark halfedge of the original polyhedra that are on the intersection - NestedFacetConstruct facet_construct; // functor called to create new triangular faces inside a given face - NewNodeVertexVisitor node_vertex_visitor; // functor called when a new node is created and when a new vertex is added - PolyhedronPointPMap ppmap; -public: - Node_visitor_refine_polyhedra ( - OutputBuilder output_builder_=OutputBuilder(), - PolyhedronPointPMap ppmap = PolyhedronPointPMap(), - EdgeMarkPropertyMap pmap=EdgeMarkPropertyMap(), - const NestedFacetConstruct& fc = NestedFacetConstruct(), - const NewNodeVertexVisitor& nv = NewNodeVertexVisitor() ) - : output_builder(output_builder_) - , m_edge_mark_pmap(pmap) - , facet_construct(fc) - , node_vertex_visitor(nv) - , ppmap(ppmap) - {} - - typedef internal_IOP::Predicates_on_constructions Node_storage_type; - typedef Tag_false Is_polyhedron_const; - static const bool do_need_vertex_graph = true; //because we need to know which edges are constrained - - void set_number_of_intersection_points_from_coplanar_facets(int n){ - number_coplanar_vertices=n; - } - - void input_have_coplanar_facets() - { - output_builder.input_have_coplanar_facets(); - } - - void check_node_on_non_manifold_vertex(int node_id,Halfedge_handle hedge){ - //we turn around the hedge and check no halfedge is a border halfedge - Halfedge_handle curr=hedge; - do{ - if ( curr->is_border_edge() ){ - non_manifold_nodes.insert(node_id); - return; - } - curr=curr->next()->opposite(); - } - while(curr!=hedge); - } - - void check_node_on_non_manifold_edge(int node_id,Halfedge_handle hedge){ - if ( hedge->is_border_edge() ) non_manifold_nodes.insert(node_id); - } - - void new_node_added(int node_id, - internal_IOP::Intersection_type type, - Halfedge_handle principal_edge, - Halfedge_handle additional_edge, - bool is_vertex_coplanar, - bool is_vertex_opposite_coplanar) - { - //forward to the visitor - node_vertex_visitor.new_node_added(node_id, type, principal_edge, additional_edge, is_vertex_coplanar, is_vertex_opposite_coplanar); - switch(type) - { - case internal_IOP::FACET: //Facet intersected by an edge - { - typename In_face_map::iterator it_fmap=in_face.insert(std::make_pair(additional_edge->face(), Node_ids())).first; - it_fmap->second.push_back(node_id); - } - break; - case internal_IOP::EDGE: //Edge intersected by an edge - { - typename In_halfedge_map::iterator it_hedge_map=in_hedge.insert(std::make_pair(additional_edge,Node_ids())).first; - it_hedge_map->second.push_back(node_id); - check_node_on_non_manifold_edge(node_id,additional_edge); - } - break; - case internal_IOP::VERTEX: - { - //grab original vertex that is on commom intersection - typename Hedge_to_polyhedron_map::iterator it=hedge_to_polyhedron.find(additional_edge->facet()->halfedge()); - CGAL_assertion(it!=hedge_to_polyhedron.end()); - poly_to_vertices_on_inter[it->second].insert(std::make_pair(node_id,additional_edge)); - polyhedron_to_map_node_to_polyhedron_vertex[it->second].insert(std::make_pair(node_id,additional_edge->vertex())); - all_incident_faces_got_a_node_as_vertex(additional_edge,node_id); - check_node_on_non_manifold_vertex(node_id,additional_edge); - } - break; - default: - return; - } - - CGAL_assertion(!is_vertex_coplanar || !is_vertex_opposite_coplanar); //coplanar edge are not forwarded - - - if ( is_vertex_coplanar ) - { - //grab original vertex that is on commom intersection - typename Hedge_to_polyhedron_map::iterator it=hedge_to_polyhedron.find(principal_edge->facet()->halfedge()); - poly_to_vertices_on_inter[it->second].insert(std::make_pair(node_id,principal_edge)); - polyhedron_to_map_node_to_polyhedron_vertex[it->second].insert(std::make_pair(node_id,principal_edge->vertex())); - all_incident_faces_got_a_node_as_vertex(principal_edge,node_id); - check_node_on_non_manifold_vertex(node_id,principal_edge); - } - else{ - if ( is_vertex_opposite_coplanar ){ - //grab original vertex that is on commom intersection - typename Hedge_to_polyhedron_map::iterator it=hedge_to_polyhedron.find(principal_edge->facet()->halfedge()); - poly_to_vertices_on_inter[it->second].insert(std::make_pair(node_id,principal_edge->opposite())); - polyhedron_to_map_node_to_polyhedron_vertex[it->second].insert(std::make_pair(node_id,principal_edge->opposite()->vertex())); - all_incident_faces_got_a_node_as_vertex(principal_edge->opposite(),node_id); - check_node_on_non_manifold_vertex(node_id,principal_edge->opposite()); - } - else{ - //handle intersection on principal edge - typename In_halfedge_map::iterator it_hedge_map=in_hedge.insert(std::make_pair(principal_edge,Node_ids())).first; - it_hedge_map->second.push_back(node_id); - check_node_on_non_manifold_edge(node_id,principal_edge); - } - } - } - - template - void annotate_graph(Iterator begin,Iterator end) - { -// std::cout << "Annotation graph..." << std::endl; - int node_id = 0; - is_node_of_degree_one.resize(std::distance(begin, end)); - for (Iterator it=begin;it!=end;++it, ++node_id) - { - if (non_manifold_nodes.count(node_id)) it->make_terminal(); - const std::set& neighbors = it->neighbors; - graph_of_constraints.insert(std::make_pair(node_id,neighbors)); - if (neighbors.size()==1) - is_node_of_degree_one.set(node_id); - } - } - - void update_terminal_nodes(std::vector&) - { - CGAL_assertion(!"Must not call this function"); - } - - void add_filtered_intersection(Halfedge_handle eh,Halfedge_handle fh,Polyhedron& Pe,Polyhedron& Pf){ - //use the representant halfedge of the facet as key - //--set polyhedron for the two facets incident to the edge - CGAL_assertion(!eh->is_border()); - hedge_to_polyhedron.insert(std::make_pair(eh->facet()->halfedge(),&Pe)); - if ( !eh->opposite()->is_border() ) - hedge_to_polyhedron.insert(std::make_pair(eh->opposite()->facet()->halfedge(),&Pe)); - //--set polyhedron for the facet intersected by the edge - hedge_to_polyhedron.insert(std::make_pair(fh->facet()->halfedge(),&Pf)); - } - - - struct Polyhedron_face_boundary{ - std::vector node_ids_array[3]; // the node_ids on each halfedges - std::map hedges_ids; - Halfedge_handle halfedges[3]; //the three halfedges of the original face - Vertex_handle vertices[3]; //the three vertices of the original face - //node_ids_array[0] corresponds to the original edge vertices[0],vertices[1] = halfedges[0] - //node_ids_array[1] corresponds to the original edge vertices[1],vertices[2] = halfedges[1] - //node_ids_array[2] corresponds to the original edge vertices[2],vertices[0] = halfedges[2] - Polyhedron_face_boundary(Halfedge_handle first) - { - CGAL_assertion(first->next()->next()->next()==first); //the face is a triangle - hedges_ids.insert(std::make_pair(first,0)); - hedges_ids.insert(std::make_pair(first->next(),1)); - hedges_ids.insert(std::make_pair(first->next()->next(),2)); - halfedges[0]=first; - halfedges[1]=first->next(); - halfedges[2]=first->next()->next(); - - vertices[0]=halfedges[0]->opposite()->vertex(); - vertices[1]=halfedges[1]->opposite()->vertex(); - vertices[2]=halfedges[2]->opposite()->vertex(); - } - - //used when object was created with hedge but opposite was used to split the original face - void update_original_halfedge(Halfedge_handle original,Halfedge_handle new_hedge) - { - typename std::map::iterator it_id=hedges_ids.find(original); - CGAL_assertion(it_id!=hedges_ids.end()); - int index=it_id->second; - CGAL_assertion(halfedges[index]==original); - hedges_ids.erase(it_id); - hedges_ids.insert(std::make_pair(new_hedge,index)); - halfedges[index]=new_hedge; - } - - template - void copy_node_ids(Halfedge_handle hedge,Iterator begin,Iterator end) - { - typename std::map::iterator it_id=hedges_ids.find(hedge); - CGAL_assertion(it_id!=hedges_ids.end()); - std::copy(begin,end,std::back_inserter(node_ids_array[it_id->second])); - } - }; - - - void start_new_polyline(int i, int j) - { - if ( i==j ) //case of a single point - { - //TAG SL001 - //nothing is done - return; - } - std::pair res= - an_edge_per_polyline.insert( - std::make_pair( make_sorted_pair(i,j), - std::make_pair( std::map(),std::make_pair(false,0)) ) - ); - CGAL_assertion(res.second); - last_polyline=res.first; - if ( i !=last_polyline->first.first ) - last_polyline->second.second.first=true; - } - - void add_node_to_polyline(int){ - ++(last_polyline->second.second.second); - } - - void new_input_polyhedron(Polyhedron& P) - { - typedef std::pair Res; - CGAL_USE_TYPE(Res); - CGAL_assertion_code(Res res = ) - polyhedron_to_map_node_to_polyhedron_vertex.insert(std::make_pair( &P,Node_to_polyhedron_vertex_map() )); - CGAL_assertion(res.second == true); - } - - //1) split_halfedges and retriangulate faces with no intersection point interior to the facet - //2) retriangulate using a constrained Delaunay triangulation each triangle in each Polyhedron that contains at least - // one intersection point inside the facet - //3) mark polyhedron edges that are on the intersection - //4) create one output polyhedron per connected component of polyhedron, connected by an edge which is not an intersection edge - //5) import each piece into a common combinatorial map - //6) glue all the pieces together - template - void finalize(const Nodes_vector& nodes){ - //mark halfedge that are on the intersection - //SL: I needed to use a map because to get the orientation around the edge, - // I need to know in the case the third vertex is a node its index (for exact construction) - typedef std::map,Cmp_unik_ad > Border_halfedges_map; - Border_halfedges_map border_halfedges; - - //store for each triangle facet which boundary is intersected by the other surface, - //original vertices (and halfedges in the refined mesh pointing on these vertices) - typedef std::map Faces_boundary; - Faces_boundary faces_boundary; - - //0) For each polyhedron, collect original vertices that belongs to the intersection. - // From the graph of constraints, extract intersection edges that are incident to such vertices. In case - // there exists another original vertex adjacent to the first one found, this halfedge must be - // marked on the boundary (and possibly update an_edge_per_polyline). - // This is done first to avoid halfedges stored to be modified in the steps following. - for (typename Poly_to_vertices_on_intersection_map::iterator - it=poly_to_vertices_on_inter.begin(); - it!=poly_to_vertices_on_inter.end(); - ++it) - { - Polyhedron* poly=it->first; - std::set > already_done; - Node_to_target_of_hedge_map& nodes_to_hedge=it->second; - for(typename Node_to_target_of_hedge_map::iterator - it_node_2_hedge=nodes_to_hedge.begin(); - it_node_2_hedge!=nodes_to_hedge.end(); - ++it_node_2_hedge) - { - int node_id_of_first=it_node_2_hedge->first; - std::map< int,std::set >::iterator it_neighbors=graph_of_constraints.find(node_id_of_first); - if ( it_neighbors!=graph_of_constraints.end() ) - { - std::set& neighbors=it_neighbors->second; - for (std::set::iterator it_id=neighbors.begin();it_id!=neighbors.end();++it_id){ - if ( already_done.find(std::make_pair(*it_id,node_id_of_first))!=already_done.end() ) continue;//already done for the opposite - typename Node_to_target_of_hedge_map::iterator it_node_2_hedge_two=nodes_to_hedge.find(*it_id); - if ( it_node_2_hedge_two!=nodes_to_hedge.end() ) //a full edge is on intersection - { - //get the corresponding halfedge with vertex corresponding to node_id_of_first - Halfedge_handle hedge=it_node_2_hedge->second; - CGAL_assertion_code(Halfedge_handle start=hedge;) - while ( hedge->opposite()->vertex()!=it_node_2_hedge_two->second->vertex() ){ - hedge=hedge->next()->opposite(); - CGAL_assertion(hedge!=start); - } - std::pair edge_pair(*it_id,node_id_of_first); - if ( border_halfedges.insert( std::make_pair(hedge,edge_pair) ).second) - { - put(m_edge_mark_pmap,std::make_pair(hedge,poly),true); - put(m_edge_mark_pmap,std::make_pair(hedge->opposite(),poly),true); - } - update_edge_per_polyline(poly,edge_pair,hedge); - //save the fact that we already handle this edge - already_done.insert(std::make_pair(node_id_of_first,*it_id)); - } - } - } - #ifdef CGAL_COREFINEMENT_DEBUG - else - { - std::cout << "X1: Found an isolated point" << std::endl; - } - #endif - } - } - - //1) First split halfedges cut by the intersection polyline(s) - for (typename In_halfedge_map::iterator it=in_hedge.begin();it!=in_hedge.end();++it) - { - Halfedge_handle hedge=it->first; //the halfedge to be split (and its opposite too) - Node_ids& node_ids = it->second; //indices of the intersection points to be inserted - CGAL_assertion( std::set(node_ids.begin(), node_ids.end()).size()==node_ids.size() ); - typename Hedge_to_polyhedron_map::iterator it_poly=hedge_to_polyhedron.find( hedge->facet()->halfedge() ); - CGAL_assertion(it_poly!=hedge_to_polyhedron.end()); - Polyhedron* P=it_poly->second; //the polyhedron in which vertices should be added - - sort_vertices_along_hedge(node_ids,hedge,nodes); - - //save original face and nodes for face of hedge (1) - if ( !hedge->is_border() ){ - typename Faces_boundary::iterator it_face=faces_boundary.find(hedge->face()); - if (it_face==faces_boundary.end()) - it_face=faces_boundary.insert(std::make_pair(hedge->face(),Polyhedron_face_boundary(hedge))).first; - it_face->second.copy_node_ids(hedge,node_ids.begin(),node_ids.end()); - } - - //save original face and nodes for face of hedge->opposite (2) - typename Faces_boundary::iterator opposite_original_info=faces_boundary.end(); - if ( !hedge->opposite()->is_border() ){ - opposite_original_info=faces_boundary.find(hedge->opposite()->face()); - if (opposite_original_info==faces_boundary.end()) - opposite_original_info=faces_boundary.insert(std::make_pair(hedge->opposite()->face(),Polyhedron_face_boundary(hedge->opposite()))).first; - opposite_original_info->second.copy_node_ids(hedge->opposite(),node_ids.rbegin(),node_ids.rend()); - } - - typename Poly_to_map_node::iterator it_map=polyhedron_to_map_node_to_polyhedron_vertex.find(P); - CGAL_assertion(it_map!=polyhedron_to_map_node_to_polyhedron_vertex.end()); - //a map to identify the vertex in the polyhedron corresponding to an intersection point - Node_to_polyhedron_vertex_map& node_to_polyhedron_vertex=it_map->second; - - CGAL_assertion_code(Vertex_handle original_vertex=hedge->opposite()->vertex();) - - //We need an edge incident to the source vertex of hedge. This is the first opposite edge created. - bool first=true; Halfedge_handle hedge_incident_to_src; - //do split the edges - for (std::vector::const_iterator it_id=node_ids.begin();it_id!=node_ids.end();++it_id){ - Vertex_handle v=split_edge(hedge, *it_id, nodes, *P); - node_to_polyhedron_vertex.insert(std::make_pair(*it_id,v)); - if (first){ - first=false; - hedge_incident_to_src=hedge->opposite()->next(); - } - } - - CGAL_assertion(hedge_incident_to_src->vertex()==original_vertex); - CGAL_assertion(hedge_incident_to_src->face()==hedge->opposite()->face()); - - //save original face and nodes for face of hedge->opposite (2) - if ( !hedge->opposite()->is_border() ){ - CGAL_assertion(opposite_original_info!=faces_boundary.end()); - opposite_original_info->second.update_original_halfedge(hedge->opposite(),hedge_incident_to_src); - } - - //insert the two incident faces in in_face map so that they will be triangulated. - if (!hedge->is_border()) in_face.insert(std::make_pair(hedge->face(),Node_ids())); - if (!hedge->opposite()->is_border()) in_face.insert(std::make_pair(hedge->opposite()->face(),Node_ids())); - } - - //2)triangulation of the triangle faces containing intersection point in their interior - // and also those with intersection points only on the boundary. - for (typename In_face_map::iterator it=in_face.begin();it!=in_face.end();++it) - { - Face_handle f = it->first; //the face to be retriangulated - Node_ids& node_ids = it->second; //the index of the intersection point that are interior to the face - CGAL_assertion(std::set(node_ids.begin(), node_ids.end()).size()==node_ids.size()); - typename Faces_boundary::iterator it_fb=faces_boundary.find(f); - - - typename Hedge_to_polyhedron_map::iterator it_polyhedron = hedge_to_polyhedron.find (f->halfedge()); //we can do this because the halfedge is still the same (at least its address)+no Face::set_halfedge called - CGAL_assertion(it_polyhedron != hedge_to_polyhedron.end()); - Polyhedron* P=it_polyhedron->second; - typename Poly_to_map_node::iterator it_map=polyhedron_to_map_node_to_polyhedron_vertex.find(P); - CGAL_assertion(it_map!=polyhedron_to_map_node_to_polyhedron_vertex.end()); - //a map to identify the vertex in the polyhedron corresponding to an intersection point - Node_to_polyhedron_vertex_map& node_to_polyhedron_vertex=it_map->second; - - std::map id_to_CDT_vh; - - //associate an edge of the triangulation to a halfedge in a given polyhedron - std::map,Halfedge_handle> edge_to_hedge; - - Vertex_handle triangle_boundary[3]; - int triangle_boundary_indices[3]; //the node_id of the triangle original vertex or a fake id - if (it_fb!=faces_boundary.end()){ //the boundary of the triangle face was refined - triangle_boundary[0]=it_fb->second.vertices[0]; - triangle_boundary[1]=it_fb->second.vertices[1]; - triangle_boundary[2]=it_fb->second.vertices[2]; - set_triangle_boundary_indices(triangle_boundary,triangle_boundary_indices); - } - else{ - triangle_boundary[0]=f->halfedge()->vertex(); //-1 - triangle_boundary[1]=f->halfedge()->next()->vertex(); //-2 - triangle_boundary[2]=f->halfedge()->next()->next()->vertex(); //-3 - CGAL_assertion(f->halfedge()->next()->next()->next()==f->halfedge());//check this is a triangle - set_triangle_boundary_indices(triangle_boundary,triangle_boundary_indices); - edge_to_hedge.insert (std::make_pair( std::make_pair( triangle_boundary_indices[2],triangle_boundary_indices[0] ) , f->halfedge() ) ); - edge_to_hedge.insert (std::make_pair( std::make_pair( triangle_boundary_indices[0],triangle_boundary_indices[1] ) , f->halfedge()->next() ) ); - edge_to_hedge.insert (std::make_pair( std::make_pair( triangle_boundary_indices[1],triangle_boundary_indices[2] ) , f->halfedge()->next()->next() ) ); - } - - - #ifdef DO_NO_USE_EXACT_CDT - typename Kernel::Plane_3 plane( get(ppmap,triangle_boundary[0]),get(ppmap,triangle_boundary[1]),get(ppmap,triangle_boundary[2])); - #else - CGAL::Cartesian_converter convert; - typename Exact_kernel::Plane_3 plane(convert(get(ppmap,triangle_boundary[0])),convert(get(ppmap,triangle_boundary[1])),convert(get(ppmap,triangle_boundary[2]))); - #endif - CDT triangulation; - //insert point inside face - for (std::vector::iterator it_node_id=node_ids.begin();it_node_id!=node_ids.end();++it_node_id){ - #ifdef DO_NO_USE_EXACT_CDT - typename CDT::Vertex_handle vh=triangulation.insert(plane.to_2d(nodes[*it_node_id])); - #else - typename CDT::Vertex_handle vh=triangulation.insert(plane.to_2d(nodes.exact_node(*it_node_id))); - #endif - vh->info()=*it_node_id; - id_to_CDT_vh.insert(std::make_pair(*it_node_id,vh)); - } - - - typename CDT::Vertex_handle triangle_vertices[3]; - #ifdef DO_NO_USE_EXACT_CDT - triangle_vertices[0]=triangulation.insert(plane.to_2d(get(ppmap,triangle_boundary[0]))); - triangle_vertices[1]=triangulation.insert(plane.to_2d(get(ppmap,triangle_boundary[1]))); - triangle_vertices[2]=triangulation.insert(plane.to_2d(get(ppmap,triangle_boundary[2]))); - #else - //we can do this because these are input points. - triangle_vertices[0]=triangulation.insert(plane.to_2d(convert(get(ppmap,triangle_boundary[0])))); - triangle_vertices[1]=triangulation.insert(plane.to_2d(convert(get(ppmap,triangle_boundary[1])))); - triangle_vertices[2]=triangulation.insert(plane.to_2d(convert(get(ppmap,triangle_boundary[2])))); - #endif - - triangle_vertices[0]->info()=triangle_boundary_indices[0]; - triangle_vertices[1]->info()=triangle_boundary_indices[1]; - triangle_vertices[2]->info()=triangle_boundary_indices[2]; - //insert face_extremities: we use operator[] because indice -1,-2,-3 are used in each loop and are specific to the current face - node_to_polyhedron_vertex[-1]=triangle_boundary[0]; - node_to_polyhedron_vertex[-2]=triangle_boundary[1]; - node_to_polyhedron_vertex[-3]=triangle_boundary[2]; - - //if one of the triangle original vertex is also a node - for (int ik=0;ik<3;++ik){ - if ( triangle_boundary_indices[ik]>=0 ) - id_to_CDT_vh.insert(std::make_pair(triangle_boundary_indices[ik],triangle_vertices[ik])); - } - //insert points on edges - #ifdef DO_NO_USE_EXACT_CDT - //and constrains these edges - #endif - if (it_fb!=faces_boundary.end()) //is there at least one intersection point on the boundary of the face? - { - //in the following loop, for each original edge of the triangle, we insert the constrained edges - // and we recover the halfedge_handle corresponding to these constrained (they are already in the polyhedron) - for (int i=0;i<3;++i){ -// std::cerr << "Boundary edges" << std::endl; -// std::cerr << " " << -1-i <second.node_ids_array[i]; - typename CDT::Vertex_handle previous=triangle_vertices[i]; - int previous_index=triangle_boundary_indices[i]; //index of original Polyhedron vertex - Halfedge_handle hedge = it_fb->second.halfedges[ (i+2) % 3]->next(); - CGAL_assertion( hedge->opposite()->vertex()==it_fb->second.vertices[i] ); - if (!bounding_ids.empty()){ //is there al least one intersection point on this edge? - for (Node_ids::iterator it_id=bounding_ids.begin();it_id!=bounding_ids.end();++it_id){ -// std::cerr << " "<< *it_id << std::endl; - #ifdef DO_NO_USE_EXACT_CDT - typename CDT::Vertex_handle vh=triangulation.insert(plane.to_2d(nodes[*it_id])); - #else - typename CDT::Vertex_handle vh=triangulation.insert(plane.to_2d(nodes.exact_node(*it_id))); - #endif - vh->info()=*it_id; - id_to_CDT_vh.insert(std::make_pair(*it_id,vh)); - #ifdef DO_NO_USE_EXACT_CDT - triangulation.insert_constraint(previous,vh); - #endif - edge_to_hedge.insert (std::make_pair( std::make_pair(previous_index,*it_id),hedge) ); - previous=vh; - hedge=hedge->next(); - previous_index=*it_id; - } - } - else{ - CGAL_assertion( it_fb->second.halfedges[i]->vertex() == it_fb->second.vertices[ (i+1) % 3 ] ); - CGAL_assertion( it_fb->second.halfedges[i]->opposite()->vertex() == it_fb->second.vertices[ i ] ); - } - CGAL_assertion(hedge==it_fb->second.halfedges[i]); - edge_to_hedge.insert (std::make_pair( std::make_pair(previous_index,triangle_boundary_indices[(i+1) % 3]) , it_fb->second.halfedges[i] ) ); -// std::cerr << " " << -1 - ( (i+1) % 3 ) < > constrained_edges; - - //insert constraints that are interior to the triangle (in the case no edges are collinear in the meshes) - insert_constrained_edges(node_ids,triangulation,id_to_CDT_vh,constrained_edges); - - //insert constraints between points that are on the boundary (not a contrained on the triangle boundary) - if (it_fb!=faces_boundary.end()) //is there at least one intersection point on the boundary of the face? - { - for (int i=0;i<3;++i){ - Node_ids& bounding_ids=it_fb->second.node_ids_array[i]; - insert_constrained_edges(bounding_ids,triangulation,id_to_CDT_vh,constrained_edges,true); - } - } - - //insert coplanar edges for endpoints of triangles - for (int i=0;i<3;++i){ - int nindex=triangle_vertices[i]->info(); - if ( nindex >=0 ) - insert_constrained_edges_coplanar_case(nindex,triangulation,id_to_CDT_vh); - } - - //XSL_TAG_CPL_VERT - //collect edges incident to a point that is the intersection of two coplanar faces. - //This ensure that triangulations are compatible. - if (it_fb!=faces_boundary.end()) //is there at least one intersection point on the boundary of the face? - { - for (typename CDT::Finite_vertices_iterator vit=triangulation.finite_vertices_begin(), - vit_end=triangulation.finite_vertices_end();vit_end!=vit;++vit) - { - //skip original vertices (that are not nodes) and non-coplanar facet issued vertices - //(this is working because intersection points between coplanar facets are the first inserted) - if ( vit->info() < 0 || vit->info() >= number_coplanar_vertices) continue; - std::map< int,std::set >::iterator res=coplanar_constraints.insert(std::make_pair(vit->info(),std::set())).first; - //turn around the vertex and get incident edge - typename CDT::Edge_circulator start=triangulation.incident_edges(vit); - typename CDT::Edge_circulator curr=start; - do{ - if (triangulation.is_infinite(*curr) ) continue; - typename CDT::Edge mirror_edge=triangulation.mirror_edge(*curr); - if ( triangulation.is_infinite( curr->first->vertex(curr->second) ) || - triangulation.is_infinite( mirror_edge.first->vertex(mirror_edge.second) ) ) - continue; //skip edges that are on the boundary of the triangle (these are already constrained) - //insert edges in the set of constraints - int nindex = - curr->first->vertex( (curr->second+1)%3 )==static_cast(vit)? - (curr->second+2)%3:(curr->second+1)%3; - typename CDT::Vertex_handle vn=curr->first->vertex(nindex); - if ( vit->info() > vn->info() ) continue; //take only one out of the two edges + skip negative vn->info() - CGAL_assertion(vn->info()>=0); - res->second.insert( vn->info() ); - }while(start!=++curr); - } - -// this is a working alternative that should be slower -// for (typename CDT::Finite_edges_iterator eit=triangulation.finite_edges_begin(), -// eit_end=triangulation.finite_edges_end();eit_end!=eit;++eit) -// { -// typename CDT::Edge mirror_edge=triangulation.mirror_edge(*eit); -// if ( triangulation.is_infinite( eit->first->vertex(eit->second) ) || -// triangulation.is_infinite( mirror_edge.first->vertex(mirror_edge.second) ) ) -// continue; //skip edges that are on the boundary of the triangle (these are already constrained) -// typename CDT::Vertex_handle v1=eit->first->vertex( (eit->second+1)%3 ), -// v2=eit->first->vertex( (eit->second+2)%3 ); -// if (v1->info()<0 || v2->info()<0) continue; -// if ( v1->info() > v2->info() ) std::swap(v1,v2); -// coplanar_constraints.insert(std::make_pair(v1->info(),std::set())).first->second.insert(v2->info()); -// } - } - - - //create a modifier to insert nodes and copy the triangulation of the face - //inside the polyhedron - internal_IOP::Triangulate_a_face modifier( - f, nodes, node_ids, node_to_polyhedron_vertex, edge_to_hedge, triangulation, facet_construct, node_vertex_visitor, ppmap); - - CGAL_assertion(P->is_valid()); - P->delegate(modifier); - CGAL_assertion(P->is_valid()); - - //3) mark halfedges that are common to two polyhedral surfaces - //recover halfedges inserted that are on the intersection - for (std::list >::iterator it_cst=constrained_edges.begin();it_cst!=constrained_edges.end();++it_cst) - { - typename std::map,Halfedge_handle>::iterator it_poly_hedge=edge_to_hedge.find(*it_cst); - //we cannot have an assertion here in the case an edge or part of an edge is a constraints. - //Indeed, the graph_of_constraints report an edge 0,1 and 1,0 for example while only one of the two - //is defined as one of them defines an adjacent face - //CGAL_assertion(it_poly_hedge!=edge_to_hedge.end()); - if( it_poly_hedge!=edge_to_hedge.end() ){ - if ( border_halfedges.insert( std::make_pair(Halfedge_const_handle(it_poly_hedge->second),*it_cst) ).second) - { - put(m_edge_mark_pmap,std::make_pair(it_poly_hedge->second,P),true); - put(m_edge_mark_pmap,std::make_pair(it_poly_hedge->second->opposite(),P),true); //setting the opposite is only needed for border edges (done in adjacent triangle otherwise) - } - update_edge_per_polyline(P,it_poly_hedge->first,it_poly_hedge->second); - } - else{ - //WARNING: in few case this is needed if the marked edge is on the border - //to optimize it might be better to only use sorted pair. TAG_SLXX1 - std::pair opposite_pair(it_cst->second,it_cst->first); - it_poly_hedge=edge_to_hedge.find(opposite_pair); - CGAL_assertion( it_poly_hedge!=edge_to_hedge.end() ); - - if ( border_halfedges.insert( std::make_pair(Halfedge_const_handle(it_poly_hedge->second),opposite_pair) ).second ) - { - put(m_edge_mark_pmap,std::make_pair(it_poly_hedge->second,P),true); - put(m_edge_mark_pmap,std::make_pair(it_poly_hedge->second->opposite(),P),true); //setting the opposite is only needed for border edges (done in adjacent triangle otherwise) - } - update_edge_per_polyline(P,it_poly_hedge->first,it_poly_hedge->second); - } - } - } - output_builder(border_halfedges, nodes, an_edge_per_polyline, is_node_of_degree_one, polyhedron_to_map_node_to_polyhedron_vertex); - } - - template - PolylineOfHalfedgeOutputIterator - explicitly_compute_polylines( - Polyhedron* P, - const Marked_set& is_marked, - PolylineOfHalfedgeOutputIterator out) - { - typedef std::pair< const std::pair, - std::pair< std::map, - std::pair > > Complicated_pair; - BOOST_FOREACH( - Complicated_pair& p, - an_edge_per_polyline) - { - const std::pair& reversed_and_nbpts = p.second.second; - Halfedge_handle hedge = p.second.first[P]; - std::vector polyline; - int nbsegments=reversed_and_nbpts.second-1; - polyline.reserve( nbsegments ); - polyline.push_back( reversed_and_nbpts.first?hedge->opposite():hedge ); - for (int i=1; i - -#endif //CGAL_INTERSECTION_OF_POLYHEDRA_3_REFINEMENT_VISITOR_H diff --git a/Operations_on_polyhedra/package_info/Operations_on_polyhedra/copyright b/Operations_on_polyhedra/package_info/Operations_on_polyhedra/copyright deleted file mode 100644 index d6bcad90777..00000000000 --- a/Operations_on_polyhedra/package_info/Operations_on_polyhedra/copyright +++ /dev/null @@ -1,2 +0,0 @@ -GeometryFactory -INRIA Sophia-Antipolis diff --git a/Operations_on_polyhedra/package_info/Operations_on_polyhedra/dependencies b/Operations_on_polyhedra/package_info/Operations_on_polyhedra/dependencies deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/Operations_on_polyhedra/package_info/Operations_on_polyhedra/description.txt b/Operations_on_polyhedra/package_info/Operations_on_polyhedra/description.txt deleted file mode 100644 index fb0b8c5d6c6..00000000000 --- a/Operations_on_polyhedra/package_info/Operations_on_polyhedra/description.txt +++ /dev/null @@ -1,3 +0,0 @@ -Package gathering non-documented functionalities used in a polyhedron demo plugin -and some other packages. At some point, we might decide to document them properly. - diff --git a/Operations_on_polyhedra/package_info/Operations_on_polyhedra/license.txt b/Operations_on_polyhedra/package_info/Operations_on_polyhedra/license.txt deleted file mode 100644 index 8bb8efcb72b..00000000000 --- a/Operations_on_polyhedra/package_info/Operations_on_polyhedra/license.txt +++ /dev/null @@ -1 +0,0 @@ -GPL (v3 or later) diff --git a/Operations_on_polyhedra/package_info/Operations_on_polyhedra/maintainer b/Operations_on_polyhedra/package_info/Operations_on_polyhedra/maintainer deleted file mode 100644 index 5b055eb65c1..00000000000 --- a/Operations_on_polyhedra/package_info/Operations_on_polyhedra/maintainer +++ /dev/null @@ -1 +0,0 @@ -Sébastien Loriot diff --git a/Optimal_transportation_reconstruction_2/demo/Optimal_transportation_reconstruction_2/random.h b/Optimal_transportation_reconstruction_2/demo/Optimal_transportation_reconstruction_2/random.h deleted file mode 100644 index b8886e54b7c..00000000000 --- a/Optimal_transportation_reconstruction_2/demo/Optimal_transportation_reconstruction_2/random.h +++ /dev/null @@ -1,26 +0,0 @@ -#ifndef _RANDOM_ -#define _RANDOM_ 1 - -inline -double random_double(const double min, const double max) -{ - double range = max - min; - return min + (double(rand()) / double(RAND_MAX)) * range; -} - -inline -int random_int(const int min, const int max) -{ - int range = max - min; - return min + int((double(rand())/double(RAND_MAX)) * range); -} - -template -Vector random_vec(const double scale) -{ - double dx = random_double(-scale, scale); - double dy = random_double(-scale, scale); - return Vector(dx, dy); -} - -#endif diff --git a/Optimal_transportation_reconstruction_2/demo/Optimal_transportation_reconstruction_2/scene.h b/Optimal_transportation_reconstruction_2/demo/Optimal_transportation_reconstruction_2/scene.h index 4a9d9c8f73b..5c2444aefc9 100644 --- a/Optimal_transportation_reconstruction_2/demo/Optimal_transportation_reconstruction_2/scene.h +++ b/Optimal_transportation_reconstruction_2/demo/Optimal_transportation_reconstruction_2/scene.h @@ -18,7 +18,7 @@ #define cimg_display 0 // To avoid X11 or Windows-GDI dependency #include #endif -#include "random.h" +#include #include // std::pair #include #include @@ -104,7 +104,17 @@ private: double m_bbox_x; double m_bbox_y; double m_bbox_size; - + + //Random + CGAL::Random random; + + template + Vector random_vec(const double scale) + { + double dx = random.get_double(-scale, scale); + double dy = random.get_double(-scale, scale); + return Vector(dx, dy); + } public: Scene() { @@ -523,7 +533,7 @@ public: std::vector::iterator it; for (it = m_samples.begin(); it != m_samples.end(); it++) { - const double rd = random_double(0.0, 1.0); + const double rd = random.get_double(0.0, 1.0); if (rd >= percentage) selected.push_back(*it); } @@ -542,7 +552,7 @@ public: Sample_& s = *it; samples.push_back(&s); - FT rv = random_double(0.0, 1.0); + FT rv = random.get_double(0.0, 1.0); if (rv <= percentage) vertices.push_back(&s); } diff --git a/Point_set_shape_detection_3/include/CGAL/regularize_planes.h b/Point_set_shape_detection_3/include/CGAL/regularize_planes.h index 14cb4907b22..6f2067a456d 100644 --- a/Point_set_shape_detection_3/include/CGAL/regularize_planes.h +++ b/Point_set_shape_detection_3/include/CGAL/regularize_planes.h @@ -781,6 +781,13 @@ void regularize_planes (const PointRange& points, /// \cond SKIP_IN_MANUAL +// Workaround for bug reported here: +// https://developercommunity.visualstudio.com/content/problem/340310/unaccepted-typename-that-other-compilers-require.html +#if _MSC_VER == 1915 +#define CGAL_TYPENAME_FOR_MSC +#else +#define CGAL_TYPENAME_FOR_MSC typename +#endif // This variant deduces the kernel from the point property map. template ::value_type>::Kernel::Vector_3 symmetry_direction - = typename Kernel_traits + = CGAL_TYPENAME_FOR_MSC Kernel_traits ::value_type>::Kernel::Vector_3 - (typename Kernel_traits + ( + CGAL_TYPENAME_FOR_MSC Kernel_traits ::value_type>::Kernel::FT(0.), - typename Kernel_traits + CGAL_TYPENAME_FOR_MSC Kernel_traits ::value_type>::Kernel::FT(0.), - typename Kernel_traits + CGAL_TYPENAME_FOR_MSC Kernel_traits ::value_type>::Kernel::FT(1.))) { @@ -824,6 +832,10 @@ void regularize_planes (const PointRange& points, tolerance_angle, tolerance_coplanarity, symmetry_direction); } +#ifdef CGAL_TYPENAME_FOR_MSC +#undef CGAL_TYPENAME_FOR_MSC +#endif + /// \endcond diff --git a/Poisson_surface_reconstruction_3/examples/Poisson_surface_reconstruction_3/cgal_test_with_cmake b/Poisson_surface_reconstruction_3/examples/Poisson_surface_reconstruction_3/cgal_test_with_cmake index a40dfb9baac..f95394fe687 100755 --- a/Poisson_surface_reconstruction_3/examples/Poisson_surface_reconstruction_3/cgal_test_with_cmake +++ b/Poisson_surface_reconstruction_3/examples/Poisson_surface_reconstruction_3/cgal_test_with_cmake @@ -49,7 +49,7 @@ configure() { echo "Configuring... " - if eval 'cmake --no-warn-unused-cli "$CMAKE_GENERATOR" -DRUNNING_CGAL_AUTO_TEST=TRUE \ + if eval 'cmake --no-warn-unused-cli ${INIT_FILE:+"-C${INIT_FILE}"} "$CMAKE_GENERATOR" -DRUNNING_CGAL_AUTO_TEST=TRUE \ -DCGAL_DIR="$CGAL_DIR" \ .' ; then diff --git a/Poisson_surface_reconstruction_3/test/Poisson_surface_reconstruction_3/cgal_test_with_cmake b/Poisson_surface_reconstruction_3/test/Poisson_surface_reconstruction_3/cgal_test_with_cmake index 80ba7fc5820..61ad14fd1d6 100755 --- a/Poisson_surface_reconstruction_3/test/Poisson_surface_reconstruction_3/cgal_test_with_cmake +++ b/Poisson_surface_reconstruction_3/test/Poisson_surface_reconstruction_3/cgal_test_with_cmake @@ -49,7 +49,7 @@ configure() { echo "Configuring... " - if eval 'cmake --no-warn-unused-cli "$CMAKE_GENERATOR" -DRUNNING_CGAL_AUTO_TEST=TRUE \ + if eval 'cmake --no-warn-unused-cli ${INIT_FILE:+"-C${INIT_FILE}"} "$CMAKE_GENERATOR" -DRUNNING_CGAL_AUTO_TEST=TRUE \ -DCGAL_DIR="$CGAL_DIR" \ .' ; then diff --git a/Polygon_mesh_processing/doc/Polygon_mesh_processing/NamedParameters.txt b/Polygon_mesh_processing/doc/Polygon_mesh_processing/NamedParameters.txt index 839bd7b52ff..a2c5456db34 100644 --- a/Polygon_mesh_processing/doc/Polygon_mesh_processing/NamedParameters.txt +++ b/Polygon_mesh_processing/doc/Polygon_mesh_processing/NamedParameters.txt @@ -337,7 +337,7 @@ of a mesh independently.\n Parameter used to pass a visitor class to a function. Its type and behavior depend on the visited function. \n \b Type : `A class` \n -\b Default Specific to the function visited +\b Default : Specific to the function visited \cgalNPEnd \cgalNPBegin{throw_on_self_intersection} \anchor PMP_throw_on_self_intersection @@ -364,6 +364,12 @@ should be considered as part of the clipping volume or not. \b Default value is `true` \cgalNPEnd +\cgalNPBegin{output_iterator} \anchor PMP_output_iterator +Parameter to pass an output iterator. +\n +\b Type : a model of `OutputIterator` \n +\b Default : `Emptyset_iterator` +\cgalNPEnd \cgalNPTableEnd diff --git a/Polygon_mesh_processing/doc/Polygon_mesh_processing/PackageDescription.txt b/Polygon_mesh_processing/doc/Polygon_mesh_processing/PackageDescription.txt index 3baa705dad3..e2a59d63cf9 100644 --- a/Polygon_mesh_processing/doc/Polygon_mesh_processing/PackageDescription.txt +++ b/Polygon_mesh_processing/doc/Polygon_mesh_processing/PackageDescription.txt @@ -113,19 +113,29 @@ and provides a list of the parameters that are used in this package. - `CGAL::Polygon_mesh_processing::self_intersections()` - \link PMP_predicates_grp `CGAL::Polygon_mesh_processing::do_intersect()` \endlink - `CGAL::Polygon_mesh_processing::intersecting_meshes()` +- `CGAL::Polygon_mesh_processing::is_degenerate_edge()` +- `CGAL::Polygon_mesh_processing::degenerate_edges()` +- `CGAL::Polygon_mesh_processing::is_degenerate_triangle_face()` +- `CGAL::Polygon_mesh_processing::degenerate_faces()` +- `CGAL::Polygon_mesh_processing::is_needle_triangle_face()` +- `CGAL::Polygon_mesh_processing::is_cap_triangle_face()` ## Orientation Functions ## -- `CGAL::Polygon_mesh_processing::is_outward_oriented()` -- `CGAL::Polygon_mesh_processing::reverse_face_orientations()` - `CGAL::Polygon_mesh_processing::orient_polygon_soup()` - `CGAL::Polygon_mesh_processing::orient()` - `CGAL::Polygon_mesh_processing::orient_to_bound_a_volume()` +- `CGAL::Polygon_mesh_processing::is_outward_oriented()` +- `CGAL::Polygon_mesh_processing::reverse_face_orientations()` ## Combinatorial Repairing Functions ## - \link PMP_repairing_grp `CGAL::Polygon_mesh_processing::stitch_borders()` \endlink - `CGAL::Polygon_mesh_processing::is_polygon_soup_a_polygon_mesh()` - `CGAL::Polygon_mesh_processing::polygon_soup_to_polygon_mesh()` - `CGAL::Polygon_mesh_processing::remove_isolated_vertices()` +- `CGAL::Polygon_mesh_processing::is_non_manifold_vertex()` +- `CGAL::Polygon_mesh_processing::duplicate_non_manifold_vertices()` +- `CGAL::Polygon_mesh_processing::merge_duplicated_vertices_in_boundary_cycle()` +- `CGAL::Polygon_mesh_processing::merge_duplicated_vertices_in_boundary_cycles()` ## Normal Computation Functions ## - `CGAL::Polygon_mesh_processing::compute_face_normal()` @@ -179,6 +189,7 @@ and provides a list of the parameters that are used in this package. - `CGAL::Polygon_mesh_processing::edge_bbox()` - `CGAL::Polygon_mesh_processing::face_bbox()` - `CGAL::Polygon_mesh_processing::border_halfedges()` +- `CGAL::Polygon_mesh_processing::extract_boundary_cycles()` - `CGAL::Polygon_mesh_processing::transform()` */ diff --git a/Polygon_mesh_processing/doc/Polygon_mesh_processing/Polygon_mesh_processing.txt b/Polygon_mesh_processing/doc/Polygon_mesh_processing/Polygon_mesh_processing.txt index 985deadf51f..e09b5620d85 100644 --- a/Polygon_mesh_processing/doc/Polygon_mesh_processing/Polygon_mesh_processing.txt +++ b/Polygon_mesh_processing/doc/Polygon_mesh_processing/Polygon_mesh_processing.txt @@ -43,14 +43,14 @@ meshes, refinement, optimization by fairing, and isotropic remeshing of triangul - \ref Coref_section : methods to corefine triangle meshes and to compute boolean operations out of corefined closed triangle meshes. - \ref PMPHoleFilling : available hole filling algorithms, which can possibly be combined with refinement and fairing. -- \ref PMPPredicates : predicates that can be evaluated on the processed polygon +- \ref PMPPredicates : predicates that can be evaluated on the processed polygon. mesh, which includes point location and self intersection tests. -- \ref PMPOrientation : checking or fixing the \ref PMPOrientation of a polygon soup. -- \ref PMPRepairing : reparation of polygon meshes and polygon soups. +- \ref PMPOrientation : checking or fixing the orientation of a polygon soup. +- \ref PMPRepairing : repair of polygon meshes and polygon soups. - \ref PMPNormalComp : normal computation at vertices and on faces of a polygon mesh. - \ref PMPSlicer : functor able to compute the intersections of a polygon mesh with arbitrary planes (slicer). - \ref PMPConnectedComponents : methods to deal with connected - components of a polygon mesh (extraction, marks, removal, ...) + components of a polygon mesh (extraction, marks, removal, ...). **************************************** \section PMPMeshing Meshing @@ -309,7 +309,7 @@ This package provides an algorithm for filling one closed hole that is either in or defined by a sequence of points that describe a polyline. The main steps of the algorithm are described in \cgalCite{liepa2003filling} and can be summarized as follows. -First, the largest patch triangulating the boundary of the hole is generated without introducing any new vertex. +First, the largest patch triangulating the boundary of the hole is generated without introducing any new vertex. The patch is selected so as to minimize a quality function evaluated for all possible triangular patches. The quality function first minimizes the worst dihedral angle between patch triangles, then the total surface area of the patch as a tiebreaker. @@ -335,10 +335,10 @@ From left to right: (a) the hole, \subsection HoleFillingAPI API This package provides four functions for hole filling: - - `triangulate_hole_polyline()` : given a sequence of points defining the hole, triangulates the hole. - - `triangulate_hole()` : given a border halfedge on the boundary of the hole on a mesh, triangulates the hole. - - `triangulate_and_refine_hole()` : in addition to `triangulate_hole()` the generated patch is refined. - - `triangulate_refine_and_fair_hole()` : in addition to `triangulate_and_refine_hole()` the generated patch is also faired. + - `triangulate_hole_polyline()` : given a sequence of points defining the hole, triangulates the hole. + - `triangulate_hole()` : given a border halfedge on the boundary of the hole on a mesh, triangulates the hole. + - `triangulate_and_refine_hole()` : in addition to `triangulate_hole()` the generated patch is refined. + - `triangulate_refine_and_fair_hole()` : in addition to `triangulate_and_refine_hole()` the generated patch is also faired. \subsection HFExamples Examples @@ -372,51 +372,65 @@ iteratively filled, refined and faired to get a faired mesh with no hole. The hole filling algorithm has a complexity which depends on the number of vertices. While \cgalCite{liepa2003filling} has a running time of \f$ O(n^3)\f$ , \cgalCite{zou2013algorithm} in most cases has -running time of \f$ O(n \log n)\f$. We were running -`triangulate_refine_and_fair_hole()` for the below meshes (and two -more meshes with smaller holes). The machine used is a PC running -Windows 10 with an Intel Core i7 CPU clocked at 2.70 GHz. -The program has been compiled with Visual C++ 2013 compiler with the O2 -option which maximizes speed. +running time of \f$ O(n \log n)\f$. We benchmarked the function +`triangulate_refine_and_fair_hole()` for the two meshes below (as well as two +more meshes with smaller holes). The machine used was a PC running +Windows 10 with an Intel Core i7 CPU clocked at 2.70 GHz. +The program was compiled with the Visual C++ 2013 compiler with the O2 +option, which maximizes speed. \cgalFigureBegin{Elephants, elephants-with-holes.png} The elephant on the left/right has a hole with 963/7657 vertices. \cgalFigureEnd -This takes time +The following running times were observed: +
    | # vertices | without Delaunay (sec.) | with Delaunay (sec.)| -| ----: | ----: | ----: | +| ----: | ----: | ----: | 565 | 8.5 | 0.03 | 774 | 21 | 0.035 | 967 | 43 | 0.06 | 7657 | na | 0.4 | - +
    *************************************** \section PMPPredicates Predicates This packages provides several predicates to be evaluated with respect to a triangle mesh. -\subsection PMPSelIntersections Self Intersections +\subsection PMPDoIntersect Intersections Detection +Intersection tests between triangle meshes and/or polylines can be done using +\link PMP_predicates_grp `CGAL::Polygon_mesh_processing::do_intersect()` \endlink. +Additionally, the function `CGAL::Polygon_mesh_processing::intersecting_meshes()` +records all pairs of intersecting meshes in a range. -Self intersections can be detected from a triangle mesh, by calling the predicate +\subsubsection PMPSelIntersections Self Intersections + +Self intersections within a triangle mesh can be detected by calling the function `CGAL::Polygon_mesh_processing::does_self_intersect()`. Additionally, the function `CGAL::Polygon_mesh_processing::self_intersections()` reports all pairs of intersecting triangles. -\cgalFigureBegin{SelfIntersections, selfintersections.jpg} -Detecting self-intersections on a triangle mesh. -The intersecting triangles are displayed in dark grey on the right image. -\cgalFigureEnd - \subsubsection SIExample Self Intersections Example + +The following example illustrates the detection of self intersection in the `pig.off` mesh. +The detected self-intersection is illustrated on Figure \cgalFigureRef{SelfIntersections}. + \cgalExample{Polygon_mesh_processing/self_intersections_example.cpp} +\cgalFigureAnchor{SelfIntersections} +
    + +
    +\cgalFigureCaptionBegin{SelfIntersections} +Detecting self-intersections on a triangle mesh. +The intersecting triangles are displayed in dark grey and red on the right image. +\cgalFigureCaptionEnd \subsection PMPInsideTest Side of Triangle Mesh -The class `CGAL::Side_of_triangle_mesh` provides a functor that tests whether a query point is +The class `CGAL::Side_of_triangle_mesh` provides a functor that tests whether a query point is inside, outside, or on the boundary of the domain bounded by a given closed triangle mesh. A point is said to be on the bounded side of the domain bounded by the input triangle mesh @@ -435,39 +449,88 @@ input triangle mesh. \subsubsection InsideExample Inside Test Example \cgalExample{Polygon_mesh_processing/point_inside_example.cpp} -\subsection PMPDoIntersect Intersections Detection -Intersection tests between triangle meshes and/or polylines can be done using -\link PMP_predicates_grp `CGAL::Polygon_mesh_processing::do_intersect()` \endlink. -Additionally, the function `CGAL::Polygon_mesh_processing::intersecting_meshes()` -records all pairs of intersecting meshes in a range. +\subsection PMPShapePredicates Shape Predicates + +Badly shaped or, even worse, completely degenerate elements of a polygon mesh are problematic +in many algorithms which one might want to use on the mesh. +This package offers a toolkit of functions to detect such undesirable elements. +- `CGAL::Polygon_mesh_processing::is_degenerate_edge()`, to detect if an edge is degenerate + (that is, if its two vertices share the same geometric location). +- `CGAL::Polygon_mesh_processing::is_degenerate_triangle_face()`, to detect if a face is + degenerate (that is, if its three vertices are collinear). +- `CGAL::Polygon_mesh_processing::degenerate_edges()`, to collect degenerate edges within a range of edges. +- `CGAL::Polygon_mesh_processing::degenerate_faces()`, to collect degenerate faces within a range of faces. +- `CGAL::Polygon_mesh_processing::is_cap_triangle_face()` +- `CGAL::Polygon_mesh_processing::is_needle_triangle_face()` **************************************** \section PMPOrientation Orientation +This package offers multiple functions to compute consistent face orientations for set of faces +(Section \ref PolygonSoups) and polygon meshes (Section \ref OrientingPolygonMeshes). +Section \ref PolygonSoupExample offers an example of combination of these functions. + +\subsection PolygonSoups Polygon Soups + +When the faces of a polygon mesh are given but the connectivity is unknown, +this set of faces is called a \e polygon \e soup. + +Before running any of the algorithms on a polygon soup, +one should ensure that the polygons are consistently oriented. +To do so, this package provides the function +`CGAL::Polygon_mesh_processing::orient_polygon_soup()`, +described in \cgalCite{gueziec2001cutting}. + +To deal with polygon soups that cannot be converted to a +combinatorially manifold surface, some points must be duplicated. +Because a polygon soup does not have any connectivity (each point +has as many occurences as the number of polygons it belongs to), +duplicating one point (or a pair of points) +amounts to duplicating the polygon to which it belongs. +The duplicated points are either an endpoint of an edge incident to more +than two polygons, an endpoint of an edge between +two polygons with incompatible orientations (during the re-orientation process), +or more generally a point \a p at which the intersection +of an infinitesimally small ball centered at \a p +with the polygons incident to it is not a topological disk. + +Once the polygon soup is consistently oriented, +with possibly duplicated (or more) points, +the connectivity can be recovered and made consistent +to build a valid polygon mesh. +The function `CGAL::Polygon_mesh_processing::polygon_soup_to_polygon_mesh()` +performs this mesh construction step. + +\subsection OrientingPolygonMeshes Polygon Meshes + This package provides functions dealing with the orientation of faces in a closed polygon mesh. -The function `CGAL::Polygon_mesh_processing::is_outward_oriented()` checks whether +- The function `CGAL::Polygon_mesh_processing::orient()` makes each connected component +of a closed polygon mesh outward- or inward-oriented. +- The function `CGAL::Polygon_mesh_processing::orient_to_bound_a_volume()` orients +the connected components of a closed polygon mesh so that it bounds a volume +(see \ref coref_def_subsec for the precise definition). +- The function `CGAL::Polygon_mesh_processing::is_outward_oriented()` checks whether an oriented polygon mesh is oriented such that the normals to all faces are oriented towards the outside of the domain bounded by the input polygon mesh. - -The function -`CGAL::Polygon_mesh_processing::reverse_face_orientations()` reverses the orientation +- The function `CGAL::Polygon_mesh_processing::reverse_face_orientations()` reverses the orientation of halfedges around faces. As a consequence, the normal computed for each face (see Section \ref PMPNormalComp) is also reversed. -The \ref PolygonSoupExample puts these functions at work on a polygon soup. +\subsection PolygonSoupExample Orientation Example -The function `CGAL::Polygon_mesh_processing::orient()` makes each connected component -of a closed polygon mesh outward or inward oriented. - -The function `CGAL::Polygon_mesh_processing::orient_to_bound_a_volume()` orients -the connected components of a closed polygon mesh so that it bounds a volume -(see \ref coref_def_subsec for the precise definition). +This example shows how to generate a mesh from a polygon soup. +The first step is to get a soup of consistently oriented faces, before +rebuilding the connectivity. +In this example, some orientation tests are performed on the output +polygon mesh to illustrate +Section \ref PMPOrientation. +\cgalExample{Polygon_mesh_processing/orient_polygon_soup_example.cpp} **************************************** -\section PMPRepairing Combinatorial Repairing +\section PMPRepairing Combinatorial Repairing ******************* \subsection Stitching @@ -490,16 +553,14 @@ with duplicated border edges. \cgalExample{Polygon_mesh_processing/stitch_borders_example.cpp} -******************* \if READY_TO_PUBLISH + \subsection DegenerateFaces Removing Degenerate Faces Some degenerate faces may be part of a given triangle mesh. A face is considered \e degenerate if two of its vertices -share the same location, -or in general if its three vertices are collinear. -The function -`CGAL::Polygon_mesh_processing::remove_degenerate_faces()` +share the same location, or more generally if its three vertices are collinear. +The function `CGAL::Polygon_mesh_processing::remove_degenerate_faces()` removes those faces and fixes the connectivity of the newly cleaned up mesh. It is also possible to remove isolated vertices from any polygon mesh, using the function `CGAL::Polygon_mesh_processing::remove_isolated_vertices()`. @@ -512,52 +573,33 @@ is output. \cgalExample{Polygon_mesh_processing/remove_degeneracies_example.cpp} \endif -******************* -\subsection PolygonSoups Polygon Soups -When the faces of a polygon mesh are given but the connectivity is unknown, -we must deal with of a \e polygon \e soup. +\subsection PMPManifoldness Polygon Mesh Manifoldness -Before running any of the algorithms on the so-called -polygon soup, one should ensure that the polygons are consistently oriented. -To do so, this package provides the function -`CGAL::Polygon_mesh_processing::orient_polygon_soup()`, -described in \cgalCite{gueziec2001cutting}. +Non-manifold vertices can be detected using the function `CGAL::Polygon_mesh_processing::is_non_manifold_vertex()`. +The function `CGAL::Polygon_mesh_processing::duplicate_non_manifold_vertices()` can be used +to attempt to create a combinatorially manifold surface mesh by splitting any non-manifold vertex +into as many vertices as there are manifold sheets at this geometric position. +Note however that the mesh will still not be manifold from a geometric +point of view, as the positions of the new vertices introduced at a non-manifold vertex are identical +to the input non-manifold vertex. -To deal with polygon soups that cannot be converted to a -combinatorial manifold surface, some points are duplicated. -Because a polygon soup does not have any connectivity (each point -has as many occurrences as the number of polygons it belongs to), -duplicating one point (or a pair of points) -amounts to duplicate the polygon to which it belongs. +\subsubsection FixNMVerticeExample Manifoldness Repair Example -The duplicated points are either an endpoint of an edge incident to more -than two polygons, an endpoint of an edge between -two polygons with incompatible orientations (during the re-orientation process), -or more generally a point \a p at which the intersection -of an infinitesimally small ball centered at \a p -with the polygons incident to it is not a topological disk. +In the following example, a non-manifold configuration is artifically created and +fixed with the help of the functions described above. -Once the polygon soup is consistently oriented, -with possibly duplicated (or more) points, -the connectivity can be recovered and made consistent -to build a valid polygon mesh. -The function `CGAL::Polygon_mesh_processing::polygon_soup_to_polygon_mesh()` -performs this mesh construction step. - - -\subsubsection PolygonSoupExample Polygon Soup Example - -This example shows how to generate a mesh from a polygon soup. -The first step is to get a soup of consistently oriented faces, before -rebuilding the connectivity. -In this example, some orientation tests are performed on the output -polygon mesh to illustrate -Section \ref PMPOrientation. - -\cgalExample{Polygon_mesh_processing/polygon_soup_example.cpp} +\cgalExample{Polygon_mesh_processing/manifoldness_repair_example.cpp} +\subsection PMPDuplicateVertexBoundaryCycle Duplicated Vertices in Boundary Cycles +Similarly to the problematic configuration described in the previous section, another issue that can be present +in a polygon mesh is the occurrence of a "pinched" hole, that is the configuration where, when +starting from a border halfedge and walking the halfedges of this border, a geometric position appears +more than once (although, with different vertices) before reaching the initial border halfedge again. The functions +`CGAL::Polygon_mesh_processing::merge_duplicated_vertices_in_boundary_cycle()` and +`CGAL::Polygon_mesh_processing::merge_duplicated_vertices_in_boundary_cycle()`, which merge +vertices at identical positions, can be used to repair this configuration. **************************************** \section PMPNormalComp Computing Normals @@ -569,7 +611,7 @@ These computations are performed with : - `CGAL::Polygon_mesh_processing::compute_face_normal()` - `CGAL::Polygon_mesh_processing::compute_vertex_normal()` -We further provide functions to compute all the normals to faces, +Furthermore, we provide functions to compute all the normals to faces, or to vertices, or to both : - `CGAL::Polygon_mesh_processing::compute_face_normals()` - `CGAL::Polygon_mesh_processing::compute_vertex_normals()` @@ -577,14 +619,12 @@ or to vertices, or to both : Property maps are used to record the computed normals. - \subsection NormalsExample Normals Computation Examples -Property maps are an API introduced in the boost library, that allows to +Property maps are an API introduced in the boost library that allows to associate values to keys. In the following examples we associate a normal vector to each vertex and to each face. - \subsubsection NormalsExampleSM Normals Computation for a Surface Mesh The following example illustrates how to @@ -728,7 +768,7 @@ that respectively detect the sharp edges, compute the patch indices, and give ea \subsection DetectFeaturesExample Feature Detection Example In the following example, we count how many edges of `pmesh` are incident to two faces -which normals form an angle smaller than 90 degrees, +whose normals form an angle smaller than 90 degrees, and the number of surface patches that are separated by these edges. \cgalExample{Polygon_mesh_processing/detect_features_example.cpp} diff --git a/Polygon_mesh_processing/doc/Polygon_mesh_processing/examples.txt b/Polygon_mesh_processing/doc/Polygon_mesh_processing/examples.txt index 2811a37ecef..cb09da7d83f 100644 --- a/Polygon_mesh_processing/doc/Polygon_mesh_processing/examples.txt +++ b/Polygon_mesh_processing/doc/Polygon_mesh_processing/examples.txt @@ -8,7 +8,7 @@ \example Polygon_mesh_processing/triangulate_faces_example.cpp \example Polygon_mesh_processing/connected_components_example.cpp \example Polygon_mesh_processing/face_filtered_graph_example.cpp -\example Polygon_mesh_processing/polygon_soup_example.cpp +\example Polygon_mesh_processing/orient_polygon_soup_example.cpp \example Polygon_mesh_processing/triangulate_polyline_example.cpp \example Polygon_mesh_processing/refine_fair_example.cpp \example Polygon_mesh_processing/mesh_slicer_example.cpp @@ -21,4 +21,5 @@ \example Polygon_mesh_processing/corefinement_mesh_union_and_intersection.cpp \example Polygon_mesh_processing/corefinement_consecutive_bool_op.cpp \example Polygon_mesh_processing/detect_features_example.cpp +\example Polygon_mesh_processing/manifoldness_repair_example.cpp */ diff --git a/Polygon_mesh_processing/doc/Polygon_mesh_processing/fig/selfintersections.jpg b/Polygon_mesh_processing/doc/Polygon_mesh_processing/fig/selfintersections.jpg index 7504ff7b865..ffc0bc0cfc2 100644 Binary files a/Polygon_mesh_processing/doc/Polygon_mesh_processing/fig/selfintersections.jpg and b/Polygon_mesh_processing/doc/Polygon_mesh_processing/fig/selfintersections.jpg differ diff --git a/Polygon_mesh_processing/examples/Polygon_mesh_processing/CMakeLists.txt b/Polygon_mesh_processing/examples/Polygon_mesh_processing/CMakeLists.txt index ed6a9a6e8f9..2a3bc719826 100644 --- a/Polygon_mesh_processing/examples/Polygon_mesh_processing/CMakeLists.txt +++ b/Polygon_mesh_processing/examples/Polygon_mesh_processing/CMakeLists.txt @@ -86,7 +86,7 @@ create_single_source_cgal_program( "point_inside_example.cpp") create_single_source_cgal_program( "triangulate_faces_example.cpp") create_single_source_cgal_program( "connected_components_example.cpp") create_single_source_cgal_program( "face_filtered_graph_example.cpp") -create_single_source_cgal_program( "polygon_soup_example.cpp") +create_single_source_cgal_program( "orient_polygon_soup_example.cpp") create_single_source_cgal_program( "triangulate_polyline_example.cpp") create_single_source_cgal_program( "mesh_slicer_example.cpp") #create_single_source_cgal_program( "remove_degeneracies_example.cpp") @@ -104,6 +104,7 @@ create_single_source_cgal_program( "random_perturbation_SM_example.cpp" ) create_single_source_cgal_program( "corefinement_LCC.cpp") create_single_source_cgal_program( "hole_filling_example_LCC.cpp" ) create_single_source_cgal_program( "detect_features_example.cpp" ) +create_single_source_cgal_program( "manifoldness_repair_example.cpp" ) if(OpenMesh_FOUND) create_single_source_cgal_program( "compute_normals_example_OM.cpp" ) diff --git a/Polygon_mesh_processing/examples/Polygon_mesh_processing/manifoldness_repair_example.cpp b/Polygon_mesh_processing/examples/Polygon_mesh_processing/manifoldness_repair_example.cpp new file mode 100644 index 00000000000..64c3a91cab6 --- /dev/null +++ b/Polygon_mesh_processing/examples/Polygon_mesh_processing/manifoldness_repair_example.cpp @@ -0,0 +1,82 @@ +#include + +#include +#include +#include +#include + +#include + +#include +#include +#include +#include + +namespace PMP = CGAL::Polygon_mesh_processing; +namespace NP = CGAL::parameters; + +typedef CGAL::Exact_predicates_inexact_constructions_kernel K; +typedef CGAL::Surface_mesh Mesh; + +typedef boost::graph_traits::vertex_descriptor vertex_descriptor; +typedef boost::graph_traits::halfedge_descriptor halfedge_descriptor; + +void merge_vertices(vertex_descriptor v_keep, vertex_descriptor v_rm, Mesh& mesh) +{ + std::cout << "merging vertices " << v_keep << " and " << v_rm << std::endl; + + BOOST_FOREACH(halfedge_descriptor h, CGAL::halfedges_around_target(v_rm, mesh)){ + set_target(h, v_keep, mesh); // to ensure that no halfedge points at the deleted vertex + } + + remove_vertex(v_rm, mesh); +} + +int main(int argc, char* argv[]) +{ + const char* filename = (argc > 1) ? argv[1] : "data/blobby.off"; + std::ifstream input(filename); + + Mesh mesh; + if(!input || !(input >> mesh) || num_vertices(mesh) == 0) + { + std::cerr << filename << " is not a valid off file.\n"; + return EXIT_FAILURE; + } + + // Artificially create non-manifoldness for the sake of the example by merging some vertices + vertex_descriptor v0 = *(vertices(mesh).begin()); + vertex_descriptor v1 = *(--(vertices(mesh).end())); + merge_vertices(v0, v1, mesh); + + // Count non manifold vertices + int counter = 0; + BOOST_FOREACH(vertex_descriptor v, vertices(mesh)) + { + if(PMP::is_non_manifold_vertex(v, mesh)) + { + std::cout << "vertex " << v << " is non-manifold" << std::endl; + ++counter; + } + } + + std::cout << counter << " non-manifold occurrence(s)" << std::endl; + + // Fix manifoldness by splitting non-manifold vertices + std::vector > duplicated_vertices; + std::size_t new_vertices_nb = PMP::duplicate_non_manifold_vertices(mesh, + NP::output_iterator( + std::back_inserter(duplicated_vertices))); + + std::cout << new_vertices_nb << " vertices have been added to fix mesh manifoldness" << std::endl; + + for(std::size_t i=0; i + #include -#include +#include + #include #include #include +#include + #include #include #include -typedef CGAL::Exact_predicates_inexact_constructions_kernel K; -typedef CGAL::Polyhedron_3 Polyhedron; +typedef CGAL::Exact_predicates_inexact_constructions_kernel K; +typedef CGAL::Polyhedron_3 Polyhedron; int main(int argc, char* argv[]) { const char* filename = (argc > 1) ? argv[1] : "data/tet-shuffled.off"; std::ifstream input(filename); - if (!input) + std::vector points; + std::vector > polygons; + + if(!input || !CGAL::read_OFF(input, points, polygons) || points.empty()) { std::cerr << "Cannot open file " << std::endl; - return 1; - } - - std::vector points; - std::vector< std::vector > polygons; - if (!CGAL::read_OFF(input, points, polygons)) - { - std::cerr << "Error parsing the OFF file " << std::endl; - return 1; + return EXIT_FAILURE; } CGAL::Polygon_mesh_processing::orient_polygon_soup(points, polygons); @@ -36,8 +35,13 @@ int main(int argc, char* argv[]) Polyhedron mesh; CGAL::Polygon_mesh_processing::polygon_soup_to_polygon_mesh(points, polygons, mesh); - if (CGAL::is_closed(mesh) && (!CGAL::Polygon_mesh_processing::is_outward_oriented(mesh))) - CGAL::Polygon_mesh_processing::reverse_face_orientations(mesh); + // Number the faces because 'orient_to_bound_a_volume' needs a face <--> index map + int index = 0; + for(Polyhedron::Face_iterator fb=mesh.facets_begin(), fe=mesh.facets_end(); fb!=fe; ++fb) + fb->id() = index++; + + if(CGAL::is_closed(mesh)) + CGAL::Polygon_mesh_processing::orient_to_bound_a_volume(mesh); std::ofstream out("tet-oriented1.off"); out << mesh; @@ -48,5 +52,5 @@ int main(int argc, char* argv[]) out2 << mesh; out2.close(); - return 0; + return EXIT_SUCCESS; } diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/border.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/border.h index 6c30cb6d077..dbe1f4945a7 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/border.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/border.h @@ -24,16 +24,16 @@ #include +#include +#include +#include +#include #include #include #include #include -#include -#include -#include - #include namespace CGAL{ @@ -257,6 +257,38 @@ namespace Polygon_mesh_processing { return border_counter; } + + /// @ingroup PkgPolygonMeshProcessing + /// extracts boundary cycles as a list of halfedges, with one halfedge per border. + /// + /// @tparam PolygonMesh a model of `HalfedgeListGraph` + /// @tparam OutputIterator a model of `OutputIterator` holding objects of type + /// `boost::graph_traits::%halfedge_descriptor` + /// + /// @param pm a polygon mesh + /// @param out an output iterator where the border halfedges will be put + /// + /// @todo It could make sense to also return the length of each cycle. + /// @todo It should probably go into BGL package (like the rest of this file). + template + OutputIterator extract_boundary_cycles(PolygonMesh& pm, + OutputIterator out) + { + typedef typename boost::graph_traits::halfedge_descriptor halfedge_descriptor; + + boost::unordered_set hedge_handled; + BOOST_FOREACH(halfedge_descriptor h, halfedges(pm)) + { + if(is_border(h, pm) && hedge_handled.insert(h).second) + { + *out++ = h; + BOOST_FOREACH(halfedge_descriptor h2, halfedges_around_face(h, pm)) + hedge_handled.insert(h2); + } + } + return out; + } + } // end of namespace Polygon_mesh_processing } // end of namespace CGAL diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Isotropic_remeshing/remesh_impl.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Isotropic_remeshing/remesh_impl.h index 08d90b8f234..7dd14e43a7d 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Isotropic_remeshing/remesh_impl.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Isotropic_remeshing/remesh_impl.h @@ -30,6 +30,7 @@ #include #include #include +#include #include #include @@ -90,21 +91,6 @@ namespace internal { }; // A property map - template - struct No_constraint_pmap - { - public: - typedef Descriptor key_type; - typedef bool value_type; - typedef value_type& reference; - typedef boost::read_write_property_map_tag category; - - friend bool get(const No_constraint_pmap& , const key_type& ) { - return false; - } - friend void put(No_constraint_pmap& , const key_type& , const bool ) {} - }; - template struct Border_constraint_pmap { @@ -325,6 +311,7 @@ namespace internal { public: Incremental_remesher(PolygonMesh& pmesh , VertexPointMap& vpmap + , const GeomTraits& gt , const bool protect_constraints , EdgeIsConstrainedMap ecmap , VertexIsConstrainedMap vcmap @@ -333,6 +320,7 @@ namespace internal { , const bool build_tree = true)//built by the remesher : mesh_(pmesh) , vpmap_(vpmap) + , gt_(gt) , build_tree_(build_tree) , has_border_(false) , input_triangles_() @@ -364,9 +352,10 @@ namespace internal { BOOST_FOREACH(face_descriptor f, face_range) { - if (is_degenerate_triangle_face(halfedge(f,mesh_),mesh_,vpmap_,GeomTraits())){ + if(is_degenerate_triangle_face(f, mesh_, parameters::vertex_point_map(vpmap_) + .geom_traits(gt_))) continue; - } + Patch_id pid = get_patch_id(f); input_triangles_.push_back(triangle(f)); input_patch_ids_.push_back(pid); @@ -828,7 +817,8 @@ namespace internal { debug_status_map(); debug_self_intersections(); CGAL_assertion(0 == PMP::remove_degenerate_faces(mesh_, - PMP::parameters::vertex_point_map(vpmap_).geom_traits(GeomTraits()))); + parameters::vertex_point_map(vpmap_) + .geom_traits(gt_))); #endif } @@ -933,7 +923,7 @@ namespace internal { debug_status_map(); CGAL_assertion(0 == PMP::remove_degenerate_faces(mesh_ , PMP::parameters::vertex_point_map(vpmap_) - .geom_traits(GeomTraits()))); + .geom_traits(gt_))); debug_self_intersections(); #endif @@ -975,9 +965,9 @@ namespace internal { else if (is_on_patch(v)) { - Vector_3 vn = PMP::compute_vertex_normal(v, mesh_ - , PMP::parameters::vertex_point_map(vpmap_) - .geom_traits(GeomTraits())); + Vector_3 vn = PMP::compute_vertex_normal(v, mesh_, + parameters::vertex_point_map(vpmap_) + .geom_traits(gt_)); put(propmap_normals, v, vn); Vector_3 move = CGAL::NULL_VECTOR; @@ -1469,20 +1459,8 @@ private: if (f == boost::graph_traits::null_face()) return CGAL::NULL_VECTOR; - halfedge_descriptor hd = halfedge(f, mesh_); - typename boost::property_traits::reference - p = get(vpmap_, target(hd, mesh_)); - hd = next(hd,mesh_); - typename boost::property_traits::reference - q = get(vpmap_, target(hd, mesh_)); - hd = next(hd,mesh_); - typename boost::property_traits::reference - r =get(vpmap_, target(hd, mesh_)); - - if (GeomTraits().collinear_3_object()(p,q,r)) - return CGAL::NULL_VECTOR; - else - return PMP::compute_face_normal(f, mesh_, parameters::vertex_point_map(vpmap_)); + return PMP::compute_face_normal(f, mesh_, parameters::vertex_point_map(vpmap_) + .geom_traits(gt_)); } template @@ -1524,7 +1502,7 @@ private: // update status using constrained edge map if (!boost::is_same >::value) + Constant_property_map >::value) { BOOST_FOREACH(edge_descriptor e, edges(mesh_)) { @@ -1598,27 +1576,31 @@ private: const bool collapse_constraints) { CGAL_assertion_code(std::size_t nb_done = 0); + boost::unordered_set degenerate_faces; BOOST_FOREACH(halfedge_descriptor h, halfedges_around_target(halfedge(v, mesh_), mesh_)) { - if (is_border(h, mesh_)) - continue; - if (is_degenerate_triangle_face(h, mesh_, vpmap_, GeomTraits())) + if(!is_border(h, mesh_) && + is_degenerate_triangle_face(face(h, mesh_), mesh_, + parameters::vertex_point_map(vpmap_) + .geom_traits(gt_))) degenerate_faces.insert(h); } + while(!degenerate_faces.empty()) { halfedge_descriptor h = *(degenerate_faces.begin()); degenerate_faces.erase(degenerate_faces.begin()); - if (!is_degenerate_triangle_face(h, mesh_, vpmap_, GeomTraits())) + if (!is_degenerate_triangle_face(face(h, mesh_), mesh_, + parameters::vertex_point_map(vpmap_) + .geom_traits(gt_))) //this can happen when flipping h has consequences further in the mesh continue; //check that opposite is not also degenerate - if (degenerate_faces.find(opposite(h, mesh_)) != degenerate_faces.end()) - degenerate_faces.erase(opposite(h, mesh_)); + degenerate_faces.erase(opposite(h, mesh_)); if(is_border(h, mesh_)) continue; @@ -1664,11 +1646,15 @@ private: short_edges.insert(typename Bimap::value_type(hf, sqlen)); } - if (!is_border(hf, mesh_) - && is_degenerate_triangle_face(hf, mesh_, vpmap_, GeomTraits())) + if(!is_border(hf, mesh_) && + is_degenerate_triangle_face(face(hf, mesh_), mesh_, + parameters::vertex_point_map(vpmap_) + .geom_traits(gt_))) degenerate_faces.insert(hf); - if (!is_border(hfo, mesh_) - && is_degenerate_triangle_face(hfo, mesh_, vpmap_, GeomTraits())) + if(!is_border(hfo, mesh_) && + is_degenerate_triangle_face(face(hfo, mesh_), mesh_, + parameters::vertex_point_map(vpmap_) + .geom_traits(gt_))) degenerate_faces.insert(hfo); break; @@ -1685,9 +1671,10 @@ private: BOOST_FOREACH(halfedge_descriptor h, halfedges_around_target(he, mesh_)) { - if (is_border(h, mesh_)) - continue; - if (is_degenerate_triangle_face(h, mesh_, vpmap_, GeomTraits())) + if(!is_border(h, mesh_) && + is_degenerate_triangle_face(face(h, mesh_), mesh_, + parameters::vertex_point_map(vpmap_) + .geom_traits(gt_))) return true; } return false; @@ -1828,10 +1815,10 @@ private: { std::cout << "Test self intersections..."; std::vector > facets; - PMP::self_intersections( - mesh_, - std::back_inserter(facets), - PMP::parameters::vertex_point_map(vpmap_)); + PMP::self_intersections(mesh_, + std::back_inserter(facets), + PMP::parameters::vertex_point_map(vpmap_) + .geom_traits(gt_)); //CGAL_assertion(facets.empty()); std::cout << "done ("<< facets.size() <<" facets)." << std::endl; } @@ -1840,11 +1827,11 @@ private: { std::cout << "Test self intersections..."; std::vector > facets; - PMP::self_intersections( - faces_around_target(halfedge(v, mesh_), mesh_), - mesh_, - std::back_inserter(facets), - PMP::parameters::vertex_point_map(vpmap_)); + PMP::self_intersections(faces_around_target(halfedge(v, mesh_), mesh_), + mesh_, + std::back_inserter(facets), + PMP::parameters::vertex_point_map(vpmap_) + .geom_traits(gt_)); //CGAL_assertion(facets.empty()); std::cout << "done ("<< facets.size() <<" facets)." << std::endl; } @@ -1926,6 +1913,7 @@ private: private: PolygonMesh& mesh_; VertexPointMap& vpmap_; + const GeomTraits& gt_; bool build_tree_; bool has_border_; std::vector trees; diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/merge_border_vertices.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/merge_border_vertices.h new file mode 100644 index 00000000000..d4600321959 --- /dev/null +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/merge_border_vertices.h @@ -0,0 +1,293 @@ +// Copyright (c) 2018 GeometryFactory (France). +// All rights reserved. +// +// This file is part of CGAL (www.cgal.org). +// You can redistribute it and/or modify it under the terms of the GNU +// General Public License as published by the Free Software Foundation, +// either version 3 of the License, or (at your option) any later version. +// +// Licensees holding a valid commercial license may use this file in +// accordance with the commercial license agreement provided with the software. +// +// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +// +// $URL$ +// $Id$ +// SPDX-License-Identifier: GPL-3.0+ +// +// +// Author(s) : Sebastien Loriot + +#ifndef CGAL_POLYGON_MESH_PROCESSING_MERGE_BORDER_VERTICES_H +#define CGAL_POLYGON_MESH_PROCESSING_MERGE_BORDER_VERTICES_H + +#include + +#include +#include +#include +#include +#include +#include + +#include +#include + +namespace CGAL { + +namespace Polygon_mesh_processing { + +namespace internal { + +template +struct Less_on_point_of_target +{ + typedef typename boost::graph_traits::halfedge_descriptor + halfedge_descriptor; + typedef typename boost::property_traits::reference Point; + + Less_on_point_of_target(const PM& pm, + const VertexPointMap& vpm) + : pm(pm), + vpm(vpm) + {} + + bool operator()(const std::pair& h1, + const std::pair& h2) const + { + if ( get(vpm, target(h1.first, pm)) < get(vpm, target(h2.first, pm)) ) + return true; + if ( get(vpm, target(h1.first, pm)) > get(vpm, target(h2.first, pm)) ) + return false; + return h1.second < h2.second; + } + + const PM& pm; + const VertexPointMap& vpm; +}; + + +// warning: cycle_hedges will be altered (sorted) +template +void detect_identical_mergeable_vertices( + std::vector< std::pair >& cycle_hedges, + std::vector< std::vector >& hedges_with_identical_point_target, + const PolygonMesh& pm, + Vpm vpm) +{ + // sort vertices using their point to ease the detection + // of vertices with identical points + Less_on_point_of_target less(pm, vpm); + std::sort( cycle_hedges.begin(), cycle_hedges.end(), less); + + std::size_t nbv=cycle_hedges.size(); + std::size_t i=1; + + std::set< std::pair > intervals; + + while(i!=nbv) + { + if ( get(vpm, target(cycle_hedges[i].first, pm)) == + get(vpm, target(cycle_hedges[i-1].first, pm)) ) + { + hedges_with_identical_point_target.push_back( std::vector() ); + hedges_with_identical_point_target.back().push_back(cycle_hedges[i-1].first); + hedges_with_identical_point_target.back().push_back(cycle_hedges[i].first); + intervals.insert( std::make_pair(cycle_hedges[i-1].second, cycle_hedges[i].second) ); + std::size_t previous = cycle_hedges[i].second; + while(++i!=nbv) + { + if ( get(vpm, target(cycle_hedges[i].first, pm)) == + get(vpm, target(cycle_hedges[i-1].first, pm)) ) + { + hedges_with_identical_point_target.back().push_back(cycle_hedges[i].first); + intervals.insert( std::make_pair(previous, cycle_hedges[i].second) ); + previous = cycle_hedges[i].second; + } + else + { + ++i; + break; + } + } + } + else + ++i; + } + + // check that intervals are disjoint or strictly nested + // if there is only one issue we drop the whole cycle. + /// \todo shall we try to be more conservative? + if (hedges_with_identical_point_target.empty()) return; + std::set< std::pair >::iterator it1 = intervals.begin(), + end2 = intervals.end(), + end1 = cpp11::prev(end2), + it2; + for (; it1!=end1; ++it1) + for(it2=cpp11::next(it1); it2!= end2; ++it2 ) + { + CGAL_assertion(it1->firstfirst); + CGAL_assertion(it1->first < it1->second && it2->first < it2->second); + if (it1->second > it2->first && it2->second > it1->second) + { + std::cerr << "Merging is skipt to avoid bad cycle connections\n"; + hedges_with_identical_point_target.clear(); + return; + } + } +} + +// \ingroup PMP_repairing_grp +// merges target vertices of a list of halfedges. +// Halfedges must be sorted in the list. +// +// @tparam PolygonMesh a model of `FaceListGraph` and `MutableFaceGraph`. +// @tparam HalfedgeRange a range of halfedge descriptors of `PolygonMesh`, model of `Range`. +// +// @param sorted_hedges a sorted list of halfedges. +// @param pm the polygon mesh which contains the list of halfedges. +// +template +void merge_vertices_in_range(const HalfedgeRange& sorted_hedges, + PolygonMesh& pm) +{ + typedef typename boost::graph_traits::halfedge_descriptor halfedge_descriptor; + typedef typename boost::graph_traits::vertex_descriptor vertex_descriptor; + + halfedge_descriptor in_h_kept = *boost::begin(sorted_hedges); + halfedge_descriptor out_h_kept = next(in_h_kept, pm); + vertex_descriptor v_kept = target(in_h_kept, pm); + + std::vector vertices_to_rm; + + BOOST_FOREACH(halfedge_descriptor in_h_rm, sorted_hedges) + { + vertex_descriptor vd = target(in_h_rm, pm); + if (vd==v_kept) continue; // skip identical vertices (in particular this skips the first halfedge) + if (edge(vd, v_kept, pm).second) continue; // skip null edges + bool shall_continue=false; + BOOST_FOREACH(halfedge_descriptor h, halfedges_around_target(v_kept, pm)) + { + if (edge(vd, source(h, pm), pm).second) + { + shall_continue=true; + break; + } + } + if (shall_continue) continue; // skip vertices already incident to the same vertex + // update the vertex of the halfedges incident to the vertex to remove + internal::update_target_vertex(in_h_rm, v_kept, pm); + // update next/prev pointers around the 2 vertices to be merged + halfedge_descriptor out_h_rm = next(in_h_rm, pm); + set_next(in_h_kept, out_h_rm, pm); + set_next(in_h_rm, out_h_kept, pm); + vertices_to_rm.push_back(vd); + out_h_kept=out_h_rm; + } + + BOOST_FOREACH(vertex_descriptor vd, vertices_to_rm) + remove_vertex(vd, pm); +} + +} // end of internal + +/// \ingroup PMP_repairing_grp +/// merges identical vertices around a cycle of boundary edges. +/// +/// @tparam PolygonMesh a model of `FaceListGraph` and `MutableFaceGraph`. +/// @tparam NamedParameter a sequence of \ref pmp_namedparameters "Named Parameters". +/// +/// @param h a halfedge that belongs to a boundary cycle. +/// @param pm the polygon mesh which contains the boundary cycle. +/// @param np optional parameter of \ref pmp_namedparameters "Named Parameters" listed below. +/// +/// \cgalNamedParamsBegin +/// \cgalParamBegin{vertex_point_map} +/// the property map with the points associated to the vertices of `pm`. +/// If this parameter is omitted, an internal property map for +/// `CGAL::vertex_point_t` should be available in `PolygonMesh` +/// \cgalParamEnd +/// \cgalNamedParamsEnd +template +void merge_duplicated_vertices_in_boundary_cycle( + typename boost::graph_traits::halfedge_descriptor h, + PolygonMesh& pm, + const NamedParameter& np) +{ + typedef typename boost::graph_traits::halfedge_descriptor halfedge_descriptor; + typedef typename GetVertexPointMap::const_type Vpm; + + Vpm vpm = choose_param(get_param(np, internal_np::vertex_point), + get_const_property_map(vertex_point, pm)); + + // collect all the halfedges of the cycle + std::vector< std::pair > cycle_hedges; + halfedge_descriptor start=h; + std::size_t index=0; + do{ + cycle_hedges.push_back( std::make_pair(h, index) ); + h=next(h, pm); + ++index; + }while(start!=h); + + std::vector< std::vector > hedges_with_identical_point_target; + internal::detect_identical_mergeable_vertices(cycle_hedges, hedges_with_identical_point_target, pm, vpm); + + BOOST_FOREACH(const std::vector& hedges, + hedges_with_identical_point_target) + { + start=hedges.front(); + // hedges are sorted along the cycle + internal::merge_vertices_in_range(hedges, pm); + } +} + +/// \ingroup PMP_repairing_grp +/// extracts boundary cycles and merges the duplicated vertices of each cycle. +/// +/// @tparam PolygonMesh a model of `FaceListGraph` and `MutableFaceGraph`. +/// @tparam NamedParameter a sequence of \ref pmp_namedparameters "Named Parameters". +/// +/// @param pm the polygon mesh which contains the cycles. +/// @param np optional parameter of \ref pmp_namedparameters "Named Parameters" listed below. +/// +/// \cgalNamedParamsBegin +/// \cgalParamBegin{vertex_point_map} +/// the property map with the points associated to the vertices of `pm`. +/// If this parameter is omitted, an internal property map for +/// `CGAL::vertex_point_t` should be available in `PolygonMesh` +/// \cgalParamEnd +/// \cgalNamedParamsEnd +/// +/// \sa `merge_duplicated_vertices_in_boundary_cycle()` +template +void merge_duplicated_vertices_in_boundary_cycles( PolygonMesh& pm, + const NamedParameter& np) +{ + typedef typename boost::graph_traits::halfedge_descriptor halfedge_descriptor; + + std::vector cycles; + extract_boundary_cycles(pm, std::back_inserter(cycles)); + + BOOST_FOREACH(halfedge_descriptor h, cycles) + merge_duplicated_vertices_in_boundary_cycle(h, pm, np); +} + +template +void merge_duplicated_vertices_in_boundary_cycles(PolygonMesh& pm) +{ + merge_duplicated_vertices_in_boundary_cycles(pm, parameters::all_default()); +} + +template +void merge_duplicated_vertices_in_boundary_cycle( + typename boost::graph_traits::halfedge_descriptor h, + PolygonMesh& pm) +{ + merge_duplicated_vertices_in_boundary_cycle(h, pm, parameters::all_default()); +} + +} } // end of CGAL::Polygon_mesh_processing + +#endif //CGAL_POLYGON_MESH_PROCESSING_MERGE_BORDER_VERTICES_H diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/random_perturbation.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/random_perturbation.h index ea7362e1a95..8a210843b1e 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/random_perturbation.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/random_perturbation.h @@ -174,10 +174,10 @@ void random_perturbation(VertexRange vertices typedef typename boost::lookup_named_param_def < internal_np::vertex_is_constrained_t, NamedParameters, - internal::No_constraint_pmap//default + Constant_property_map // default > ::type VCMap; VCMap vcmap = choose_param(get_param(np, internal_np::vertex_is_constrained), - internal::No_constraint_pmap()); + Constant_property_map(false)); unsigned int seed = choose_param(get_param(np, internal_np::random_seed), -1); bool do_project = choose_param(get_param(np, internal_np::do_project), true); diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/remesh.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/remesh.h index d87cd651b6a..b50060998f0 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/remesh.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/remesh.h @@ -163,6 +163,7 @@ void isotropic_remeshing(const FaceRange& faces boost::is_default_param(get_param(np, internal_np::projection_functor)); typedef typename GetGeomTraits::type GT; + GT gt = choose_param(get_param(np, internal_np::geom_traits), GT()); typedef typename GetVertexPointMap::type VPMap; VPMap vpmap = choose_param(get_param(np, internal_np::vertex_point), @@ -175,18 +176,18 @@ void isotropic_remeshing(const FaceRange& faces typedef typename boost::lookup_named_param_def < internal_np::edge_is_constrained_t, NamedParameters, - internal::No_constraint_pmap//default + Constant_property_map // default (no constraint pmap) > ::type ECMap; - ECMap ecmap = choose_param(get_param(np, internal_np::edge_is_constrained) - , internal::No_constraint_pmap()); + ECMap ecmap = choose_param(get_param(np, internal_np::edge_is_constrained), + Constant_property_map(false)); typedef typename boost::lookup_named_param_def < internal_np::vertex_is_constrained_t, NamedParameters, - internal::No_constraint_pmap//default + Constant_property_map // default (no constraint pmap) > ::type VCMap; VCMap vcmap = choose_param(get_param(np, internal_np::vertex_is_constrained), - internal::No_constraint_pmap()); + Constant_property_map(false)); bool protect = choose_param(get_param(np, internal_np::protect_constraints), false); typedef typename boost::lookup_named_param_def < @@ -227,7 +228,7 @@ void isotropic_remeshing(const FaceRange& faces #endif typename internal::Incremental_remesher - remesher(pmesh, vpmap, protect, ecmap, vcmap, fpmap, fimap, need_aabb_tree); + remesher(pmesh, vpmap, gt, protect, ecmap, vcmap, fpmap, fimap, need_aabb_tree); remesher.init_remeshing(faces); #ifdef CGAL_PMP_REMESHING_VERBOSE @@ -340,6 +341,8 @@ void split_long_edges(const EdgeRange& edges using boost::get_param; typedef typename GetGeomTraits::type GT; + GT gt = choose_param(get_param(np, internal_np::geom_traits), GT()); + typedef typename GetVertexPointMap::type VPMap; VPMap vpmap = choose_param(get_param(np, internal_np::vertex_point), get_property_map(vertex_point, pmesh)); @@ -351,22 +354,21 @@ void split_long_edges(const EdgeRange& edges typedef typename boost::lookup_named_param_def < internal_np::edge_is_constrained_t, NamedParameters, - internal::No_constraint_pmap//default + Constant_property_map // default (no constraint pmap) > ::type ECMap; ECMap ecmap = choose_param(get_param(np, internal_np::edge_is_constrained), - internal::No_constraint_pmap()); + Constant_property_map(false)); typename internal::Incremental_remesher, + Constant_property_map, // no constraint pmap internal::Connected_components_pmap, FIMap > - remesher(pmesh, vpmap, false/*protect constraints*/ - , ecmap - , internal::No_constraint_pmap() - , internal::Connected_components_pmap(faces(pmesh), pmesh, ecmap, fimap, false) - , fimap - , false/*need aabb_tree*/); + remesher(pmesh, vpmap, gt, false/*protect constraints*/, ecmap, + Constant_property_map(false), + internal::Connected_components_pmap(faces(pmesh), pmesh, ecmap, fimap, false), + fimap, + false/*need aabb_tree*/); remesher.split_long_edges(edges, max_length); } diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/repair.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/repair.h index 6fcb1e929dd..917eac4b22e 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/repair.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/repair.h @@ -24,12 +24,9 @@ #include - -#include -#include -#include #include #include +#include #include #include @@ -40,21 +37,33 @@ #include #include +#include #include #include +#include + #ifdef CGAL_PMP_REMOVE_DEGENERATE_FACES_DEBUG #include #include -#include -#include #endif +#include +#include +#include + +#include +#include +#include +#include +#include +#include + namespace CGAL{ namespace Polygon_mesh_processing { - namespace debug{ + template std::ostream& dump_edge_neighborhood( typename boost::graph_traits::edge_descriptor ed, @@ -142,8 +151,11 @@ namespace debug{ << vids[ target(next(next(halfedge(f, tm), tm), tm), tm) ] << "\n"; } } + } //end of namespace debug +namespace internal { + template struct Less_vertex_point{ typedef typename boost::graph_traits::vertex_descriptor vertex_descriptor; @@ -157,33 +169,158 @@ struct Less_vertex_point{ } }; -///\cond SKIP_IN_MANUAL +} // end namespace internal -template -OutputIterator -degenerate_faces(const TriangleMesh& tm, - const VertexPointMap& vpmap, - const Traits& traits, - OutputIterator out) +/// \ingroup PMP_repairing_grp +/// collects the degenerate edges within a given range of edges. +/// +/// @tparam EdgeRange a model of `Range` with value type `boost::graph_traits::%edge_descriptor` +/// @tparam TriangleMesh a model of `HalfedgeGraph` +/// @tparam NamedParameters a sequence of \ref pmp_namedparameters "Named Parameters" +/// +/// @param edges a subset of edges of `tm` +/// @param tm a triangle mesh +/// @param out an output iterator in which the degenerate edges are written +/// @param np optional \ref pmp_namedparameters "Named Parameters" described below +/// +/// \cgalNamedParamsBegin +/// \cgalParamBegin{vertex_point_map} the property map with the points associated to the vertices of `tm`. +/// The type of this map is model of `ReadWritePropertyMap`. +/// If this parameter is omitted, an internal property map for +/// `CGAL::vertex_point_t` should be available in `TriangleMesh` +/// \cgalParamEnd +/// \cgalParamBegin{geom_traits} a geometric traits class instance. +/// The traits class must provide the nested type `Point_3`, +/// and the nested functor `Equal_3` to check whether two points are identical. +/// \cgalParamEnd +/// \cgalNamedParamsEnd +template +OutputIterator degenerate_edges(const EdgeRange& edges, + const TriangleMesh& tm, + OutputIterator out, + const NamedParameters& np) { - typedef typename boost::graph_traits::face_descriptor face_descriptor; - BOOST_FOREACH(face_descriptor fd, faces(tm)) + typedef typename boost::graph_traits::edge_descriptor edge_descriptor; + + BOOST_FOREACH(edge_descriptor ed, edges) { - if ( is_degenerate_triangle_face(fd, tm, vpmap, traits) ) - *out++=fd; + if(is_degenerate_edge(ed, tm, np)) + *out++ = ed; } return out; } +template +OutputIterator degenerate_edges(const EdgeRange& edges, + const TriangleMesh& tm, + OutputIterator out, + typename boost::enable_if< + typename boost::has_range_iterator + >::type* = 0) +{ + return degenerate_edges(edges, tm, out, CGAL::parameters::all_default()); +} + +/// \ingroup PMP_repairing_grp +/// calls the function `degenerate_edges()` with the range: `edges(tm)`. +/// +/// See above for the comprehensive description of the parameters. +/// +template +OutputIterator degenerate_edges(const TriangleMesh& tm, + OutputIterator out, + const NamedParameters& np +#ifndef DOXYGEN_RUNNING + , typename boost::disable_if< + boost::has_range_iterator + >::type* = 0 +#endif + ) +{ + return degenerate_edges(edges(tm), tm, out, np); +} + template OutputIterator -degenerate_faces(const TriangleMesh& tm, OutputIterator out) +degenerate_edges(const TriangleMesh& tm, OutputIterator out) { - typedef typename boost::property_map::type Vpm; - typedef typename boost::property_traits::value_type Point; - typedef typename Kernel_traits::Kernel Kernel; + return degenerate_edges(edges(tm), tm, out, CGAL::parameters::all_default()); +} - return degenerate_faces(tm, get(vertex_point, tm), Kernel(), out); +/// \ingroup PMP_repairing_grp +/// collects the degenerate faces within a given range of faces. +/// +/// @tparam FaceRange a model of `Range` with value type `boost::graph_traits::%face_descriptor` +/// @tparam TriangleMesh a model of `FaceGraph` +/// @tparam NamedParameters a sequence of \ref pmp_namedparameters "Named Parameters" +/// +/// @param faces a subset of faces of `tm` +/// @param tm a triangle mesh +/// @param out an output iterator in which the degenerate faces are put +/// @param np optional \ref pmp_namedparameters "Named Parameters" described below +/// +/// \cgalNamedParamsBegin +/// \cgalParamBegin{vertex_point_map} the property map with the points associated to the vertices of `tm`. +/// The type of this map is model of `ReadWritePropertyMap`. +/// If this parameter is omitted, an internal property map for +/// `CGAL::vertex_point_t` should be available in `TriangleMesh` +/// \cgalParamEnd +/// \cgalParamBegin{geom_traits} a geometric traits class instance. +/// The traits class must provide the nested functor `Collinear_3` +/// to check whether three points are collinear. +/// \cgalParamEnd +/// \cgalNamedParamsEnd +/// +template +OutputIterator degenerate_faces(const FaceRange& faces, + const TriangleMesh& tm, + OutputIterator out, + const NamedParameters& np) +{ + typedef typename boost::graph_traits::face_descriptor face_descriptor; + + BOOST_FOREACH(face_descriptor fd, faces) + { + if(is_degenerate_triangle_face(fd, tm, np)) + *out++ = fd; + } + return out; +} + +template +OutputIterator degenerate_faces(const FaceRange& faces, + const TriangleMesh& tm, + OutputIterator out, + typename boost::enable_if< + boost::has_range_iterator + >::type* = 0) +{ + return degenerate_faces(faces, tm, out, CGAL::parameters::all_default()); +} + +/// \ingroup PMP_repairing_grp +/// calls the function `degenerate_faces()` with the range: `faces(tm)`. +/// +/// See above for the comprehensive description of the parameters. +/// +template +OutputIterator degenerate_faces(const TriangleMesh& tm, + OutputIterator out, + const NamedParameters& np +#ifndef DOXYGEN_RUNNING + , typename boost::disable_if< + boost::has_range_iterator + >::type* = 0 +#endif + ) +{ + return degenerate_faces(faces(tm), tm, out, np); +} + +template +OutputIterator degenerate_faces(const TriangleMesh& tm, OutputIterator out) +{ + return degenerate_faces(faces(tm), tm, out, CGAL::parameters::all_default()); } // this function remove a border edge even if it does not satisfy the link condition. @@ -365,10 +502,9 @@ remove_a_border_edge(typename boost::graph_traits::edge_descriptor } template -std::size_t remove_null_edges( - const EdgeRange& edge_range, - TriangleMesh& tmesh, - const NamedParameters& np) +bool remove_degenerate_edges(const EdgeRange& edge_range, + TriangleMesh& tmesh, + const NamedParameters& np) { CGAL_assertion(CGAL::is_triangle_mesh(tmesh)); @@ -385,27 +521,25 @@ std::size_t remove_null_edges( typedef typename GetVertexPointMap::type VertexPointMap; VertexPointMap vpmap = choose_param(get_param(np, internal_np::vertex_point), get_property_map(vertex_point, tmesh)); + typedef typename GetGeomTraits::type Traits; - Traits traits = choose_param(get_param(np, internal_np::geom_traits), Traits()); std::size_t nb_deg_faces = 0; + bool all_removed=true; // collect edges of length 0 - std::set null_edges_to_remove; - BOOST_FOREACH(edge_descriptor ed, edge_range) - { - if ( traits.equal_3_object()(get(vpmap, target(ed, tmesh)), get(vpmap, source(ed, tmesh))) ) - null_edges_to_remove.insert(ed); - } + std::set degenerate_edges_to_remove; + degenerate_edges(edge_range, tmesh, std::inserter(degenerate_edges_to_remove, + degenerate_edges_to_remove.end())); - #ifdef CGAL_PMP_REMOVE_DEGENERATE_FACES_DEBUG - std::cout << "Found " << null_edges_to_remove.size() << " null edges.\n"; - #endif +#ifdef CGAL_PMP_REMOVE_DEGENERATE_FACES_DEBUG + std::cout << "Found " << degenerate_edges_to_remove.size() << " null edges.\n"; +#endif - while (!null_edges_to_remove.empty()) + while (!degenerate_edges_to_remove.empty()) { - edge_descriptor ed = *null_edges_to_remove.begin(); - null_edges_to_remove.erase(null_edges_to_remove.begin()); + edge_descriptor ed = *degenerate_edges_to_remove.begin(); + degenerate_edges_to_remove.erase(degenerate_edges_to_remove.begin()); halfedge_descriptor h = halfedge(ed, tmesh); @@ -415,12 +549,12 @@ std::size_t remove_null_edges( if ( face(h, tmesh)!=GT::null_face() ) { ++nb_deg_faces; - null_edges_to_remove.erase(edge(prev(h, tmesh), tmesh)); + degenerate_edges_to_remove.erase(edge(prev(h, tmesh), tmesh)); } if (face(opposite(h, tmesh), tmesh)!=GT::null_face()) { ++nb_deg_faces; - null_edges_to_remove.erase(edge(prev(opposite(h, tmesh), tmesh), tmesh)); + degenerate_edges_to_remove.erase(edge(prev(opposite(h, tmesh), tmesh), tmesh)); } //now remove the edge CGAL::Euler::collapse_edge(ed, tmesh); @@ -435,10 +569,40 @@ std::size_t remove_null_edges( if (is_triangle(hd, tmesh)) { Euler::fill_hole(hd, tmesh); - null_edges_to_remove.insert(ed); + degenerate_edges_to_remove.insert(ed); continue; } } + else + { + halfedge_descriptor hd = halfedge(ed,tmesh); + // if both vertices are boundary vertices we can't do anything + bool impossible = false; + BOOST_FOREACH(halfedge_descriptor h, halfedges_around_target(hd, tmesh)) + { + if (is_border(h, tmesh)) + { + impossible = true; + break; + } + } + if (impossible) + { + BOOST_FOREACH(halfedge_descriptor h, halfedges_around_source(hd, tmesh)) + { + if (is_border(h, tmesh)) + { + impossible = true; + break; + } + } + if (impossible) + { + all_removed=false; + continue; + } + } + } // When the edge does not satisfy the link condition, it means that it cannot be // collapsed as is. In the following we assume that there is no topological issue @@ -621,7 +785,7 @@ std::size_t remove_null_edges( // remove edges BOOST_FOREACH(edge_descriptor ed, edges_to_remove) { - null_edges_to_remove.erase(ed); + degenerate_edges_to_remove.erase(ed); remove_edge(ed, tmesh); } @@ -641,61 +805,60 @@ std::size_t remove_null_edges( put(vpmap, target(new_hd, tmesh), pt); BOOST_FOREACH(halfedge_descriptor hd, halfedges_around_target(new_hd, tmesh)) - if ( traits.equal_3_object()(get(vpmap, target(hd, tmesh)), get(vpmap, source(hd, tmesh))) ) - null_edges_to_remove.insert(edge(hd, tmesh)); + if(is_degenerate_edge(edge(hd, tmesh), tmesh, np)) + degenerate_edges_to_remove.insert(edge(hd, tmesh)); CGAL_assertion( is_valid_polygon_mesh(tmesh) ); } } - return nb_deg_faces; + return all_removed; } template -std::size_t remove_null_edges( - const EdgeRange& edge_range, - TriangleMesh& tmesh) +bool remove_degenerate_edges(const EdgeRange& edge_range, + TriangleMesh& tmesh) { - return remove_null_edges(edge_range, tmesh, - parameters::all_default()); + return remove_degenerate_edges(edge_range, tmesh, parameters::all_default()); } -/// \ingroup PMP_repairing_grp -/// removes the degenerate faces from a triangulated surface mesh. -/// A face is considered degenerate if two of its vertices share the same location, -/// or more generally if all its vertices are collinear. -/// -/// @pre `CGAL::is_triangle_mesh(tmesh)` -/// -/// @tparam TriangleMesh a model of `FaceListGraph` and `MutableFaceGraph` -/// @tparam NamedParameters a sequence of \ref pmp_namedparameters "Named Parameters" -/// -/// @param tmesh the triangulated surface mesh to be repaired -/// @param np optional \ref pmp_namedparameters "Named Parameters" described below -/// -/// \cgalNamedParamsBegin -/// \cgalParamBegin{vertex_point_map} the property map with the points associated to the vertices of `pmesh`. The type of this map is model of `ReadWritePropertyMap`. -/// If this parameter is omitted, an internal property map for -/// `CGAL::vertex_point_t` must be available in `TriangleMesh` -/// \cgalParamEnd -/// \cgalParamBegin{geom_traits} a geometric traits class instance. -/// The traits class must provide the nested type `Point_3`, -/// and the nested functors : -/// - `Compare_distance_3` to compute the distance between 2 points -/// - `Collinear_are_ordered_along_line_3` to check whether 3 collinear points are ordered -/// - `Collinear_3` to check whether 3 points are collinear -/// - `Less_xyz_3` to compare lexicographically two points -/// - `Equal_3` to check whether 2 points are identical -/// - for each functor Foo, a function `Foo foo_object()` -/// \cgalParamEnd -/// \cgalNamedParamsEnd -/// -/// \todo the function might not be able to remove all degenerate faces. -/// We should probably do something with the return type. -/// \return number of removed degenerate faces +// \ingroup PMP_repairing_grp +// removes the degenerate faces from a triangulated surface mesh. +// A face is considered degenerate if two of its vertices share the same location, +// or more generally if all its vertices are collinear. +// +// @pre `CGAL::is_triangle_mesh(tmesh)` +// +// @tparam TriangleMesh a model of `FaceListGraph` and `MutableFaceGraph` +// @tparam NamedParameters a sequence of \ref pmp_namedparameters "Named Parameters" +// +// @param tmesh the triangulated surface mesh to be repaired +// @param np optional \ref pmp_namedparameters "Named Parameters" described below +// +// \cgalNamedParamsBegin +// \cgalParamBegin{vertex_point_map} the property map with the points associated to the vertices of `pmesh`. +// The type of this map is model of `ReadWritePropertyMap`. +// If this parameter is omitted, an internal property map for +// `CGAL::vertex_point_t` must be available in `TriangleMesh` +// \cgalParamEnd +// \cgalParamBegin{geom_traits} a geometric traits class instance. +// The traits class must provide the nested type `Point_3`, +// and the nested functors : +// - `Compare_distance_3` to compute the distance between 2 points +// - `Collinear_3` to check whether 3 points are collinear +// - `Less_xyz_3` to compare lexicographically two points +// - `Equal_3` to check whether 2 points are identical +// For each functor `Foo`, a function `Foo foo_object()` +// \cgalParamEnd +// \cgalNamedParamsEnd +// +// \todo the function might not be able to remove all degenerate faces. +// We should probably do something with the return type. +// +/// \return `true` if all degenerate faces were successfully removed, and `false` otherwise. template -std::size_t remove_degenerate_faces(TriangleMesh& tmesh, - const NamedParameters& np) +bool remove_degenerate_faces( TriangleMesh& tmesh, + const NamedParameters& np) { CGAL_assertion(CGAL::is_triangle_mesh(tmesh)); @@ -717,8 +880,9 @@ std::size_t remove_degenerate_faces(TriangleMesh& tmesh, typedef typename boost::property_traits::value_type Point_3; typedef typename boost::property_traits::reference Point_ref; + // First remove edges of length 0 - std::size_t nb_deg_faces = remove_null_edges(edges(tmesh), tmesh, np); + bool all_removed = remove_degenerate_edges(edges(tmesh), tmesh, np); #ifdef CGAL_PMP_REMOVE_DEGENERATE_FACES_DEBUG { @@ -731,10 +895,21 @@ std::size_t remove_degenerate_faces(TriangleMesh& tmesh, // Then, remove triangles made of 3 collinear points std::set degenerate_face_set; - BOOST_FOREACH(face_descriptor fd, faces(tmesh)) - if ( is_degenerate_triangle_face(fd, tmesh, vpmap, traits) ) - degenerate_face_set.insert(fd); - nb_deg_faces+=degenerate_face_set.size(); + degenerate_faces(tmesh, std::inserter(degenerate_face_set, degenerate_face_set.begin()), np); +// Ignore faces with null edges + if (!all_removed) + { + BOOST_FOREACH(edge_descriptor ed, edges(tmesh)) + { + if ( traits.equal_3_object()(get(vpmap, target(ed, tmesh)), get(vpmap, source(ed, tmesh))) ) + { + halfedge_descriptor h = halfedge(ed, tmesh); + if (!is_border(h, tmesh)) degenerate_face_set.erase(face(h, tmesh)); + h=opposite(h, tmesh); + if (!is_border(h, tmesh)) degenerate_face_set.erase(face(h, tmesh)); + } + } + } // first remove degree 3 vertices that are part of a cap // (only the vertex in the middle of the opposite edge) @@ -747,7 +922,7 @@ std::size_t remove_degenerate_faces(TriangleMesh& tmesh, BOOST_FOREACH(halfedge_descriptor hd, halfedges_around_face(halfedge(fd, tmesh), tmesh)) { vertex_descriptor vd = target(hd, tmesh); - if (degree(vd, tmesh) == 3) + if (degree(vd, tmesh) == 3 && is_border(vd, tmesh)==GT::null_halfedge()) { vertices_to_remove.insert(vd); break; @@ -763,7 +938,7 @@ std::size_t remove_degenerate_faces(TriangleMesh& tmesh, degenerate_face_set.erase( face(hd2, tmesh) ); // remove the central vertex and check if the new face is degenerated hd=CGAL::Euler::remove_center_vertex(hd, tmesh); - if (is_degenerate_triangle_face(face(hd, tmesh), tmesh, vpmap, traits)) + if (is_degenerate_triangle_face(face(hd, tmesh), tmesh, np)) { degenerate_face_set.insert( face(hd, tmesh) ); } @@ -855,15 +1030,17 @@ std::size_t remove_degenerate_faces(TriangleMesh& tmesh, { Euler::flip_edge(edge_to_flip, tmesh); } + else + { + all_removed=false; #ifdef CGAL_PMP_REMOVE_DEGENERATE_FACES_DEBUG - else{ std::cout << " WARNING: flip is not possible\n"; // \todo Let p and q be the vertices opposite to `edge_to_flip`, and let // r be the vertex of `edge_to_flip` that is the furthest away from // the edge `pq`. In that case I think we should remove all the triangles // so that the triangle pqr is in the mesh. - } #endif + } } } else @@ -964,7 +1141,7 @@ std::size_t remove_degenerate_faces(TriangleMesh& tmesh, // preliminary step to check if the operation is possible // sort the boundary points along the common supporting line // we first need a reference point - typedef Less_vertex_point Less_vertex; + typedef internal::Less_vertex_point Less_vertex; std::pair< typename std::set::iterator, typename std::set::iterator > ref_vertices = @@ -1278,10 +1455,9 @@ std::size_t remove_degenerate_faces(TriangleMesh& tmesh, } } - return nb_deg_faces; + return all_removed; } - template std::size_t remove_degenerate_faces(TriangleMesh& tmesh) { @@ -1289,52 +1465,207 @@ std::size_t remove_degenerate_faces(TriangleMesh& tmesh) CGAL::Polygon_mesh_processing::parameters::all_default()); } -template -std::size_t duplicate_non_manifold_vertices(TriangleMesh& tm, Vpm vpm) +namespace internal { + +template +struct Vertex_collector { + typedef typename boost::graph_traits::vertex_descriptor vertex_descriptor; + + void collect_vertices(vertex_descriptor v1, vertex_descriptor v2) + { + std::vector& verts = collections[v1]; + if(verts.empty()) + verts.push_back(v1); + verts.push_back(v2); + } + + void dump(OutputIterator out) + { + typedef std::pair > Pair_type; + BOOST_FOREACH(const Pair_type& p, collections) { + *out++ = p.second; + } + } + + std::map > collections; +}; + +template +struct Vertex_collector +{ + typedef typename boost::graph_traits::vertex_descriptor vertex_descriptor; + void collect_vertices(vertex_descriptor, vertex_descriptor) + {} + + void dump(Emptyset_iterator) + {} +}; + +} // end namespace internal + +/// \ingroup PMP_repairing_grp +/// checks whether a vertex of a polygon mesh is non-manifold. +/// +/// @tparam PolygonMesh a model of `HalfedgeListGraph` +/// +/// @param v a vertex of `pm` +/// @param pm a triangle mesh containing `v` +/// +/// \sa `duplicate_non_manifold_vertices()` +/// +/// \return `true` if the vertex is non-manifold, `false` otherwise. +template +bool is_non_manifold_vertex(typename boost::graph_traits::vertex_descriptor v, + const PolygonMesh& pm) +{ + typedef typename boost::graph_traits::halfedge_descriptor halfedge_descriptor; + boost::unordered_set halfedges_handled; + + std::size_t incident_null_faces_counter = 0; + BOOST_FOREACH(halfedge_descriptor h, halfedges_around_target(v, pm)) + { + halfedges_handled.insert(h); + if(CGAL::is_border(h, pm)) + ++incident_null_faces_counter; + } + + if(incident_null_faces_counter > 1) + { + // The vertex is the sole connection between two connected components --> non-manifold + return true; + } + + BOOST_FOREACH(halfedge_descriptor h, halfedges(pm)) + { + if(v == target(h, pm)) + { + // More than one umbrella incident to 'v' --> non-manifold + if(halfedges_handled.count(h) == 0) + return true; + } + } + + return false; +} + +/// \ingroup PMP_repairing_grp +/// duplicates all the non-manifold vertices of the input mesh. +/// +/// @tparam TriangleMesh a model of `HalfedgeListGraph` and `MutableHalfedgeGraph` +/// @tparam NamedParameters a sequence of \ref pmp_namedparameters "Named Parameters" +/// +/// @param tm the triangulated surface mesh to be repaired +/// @param np optional \ref pmp_namedparameters "Named Parameters" described below +/// +/// \cgalNamedParamsBegin +/// \cgalParamBegin{vertex_point_map} the property map with the points associated to the vertices of `pmesh`. +/// The type of this map is model of `ReadWritePropertyMap`. +/// If this parameter is omitted, an internal property map for +/// `CGAL::vertex_point_t` should be available in `TriangleMesh` +/// \cgalParamEnd +/// \cgalParamBegin{vertex_is_constrained_map} a writable property map with `vertex_descriptor` +/// as key and `bool` as `value_type`. `put(pmap, v, true)` will be called for each duplicated +/// vertices, as well as the original non-manifold vertex in the input mesh. +/// \cgalParamEnd +/// \cgalParamBegin{output_iterator} a model of `OutputIterator` with value type +/// `std::vector`. The first vertex of each vector is a non-manifold vertex +/// of the input mesh, followed by the new vertices that were created to fix this precise +/// non-manifold configuration. +/// \cgalParamEnd +/// \cgalNamedParamsEnd +/// +/// \return the number of vertices created. +template +std::size_t duplicate_non_manifold_vertices(TriangleMesh& tm, + const NamedParameters& np) +{ + CGAL_assertion(CGAL::is_triangle_mesh(tm)); + + using boost::get_param; + using boost::choose_param; + typedef boost::graph_traits GT; typedef typename GT::vertex_descriptor vertex_descriptor; typedef typename GT::halfedge_descriptor halfedge_descriptor; + typedef typename GetVertexPointMap::type VertexPointMap; + VertexPointMap vpm = choose_param(get_param(np, internal_np::vertex_point), + get_property_map(vertex_point, tm)); + + typedef typename boost::lookup_named_param_def < + internal_np::vertex_is_constrained_t, + NamedParameters, + Constant_property_map // default (no constraint pmap) + > ::type VerticesMap; + VerticesMap cmap + = choose_param(get_param(np, internal_np::vertex_is_constrained), + Constant_property_map(false)); + + typedef typename boost::lookup_named_param_def < + internal_np::output_iterator_t, + NamedParameters, + Emptyset_iterator + > ::type Output_iterator; + Output_iterator out + = choose_param(get_param(np, internal_np::output_iterator), + Emptyset_iterator()); + + internal::Vertex_collector dmap; boost::unordered_set vertices_handled; boost::unordered_set halfedges_handled; - std::size_t nb_new_vertices=0; + std::size_t nb_new_vertices = 0; std::vector non_manifold_cones; BOOST_FOREACH(halfedge_descriptor h, halfedges(tm)) { - if (halfedges_handled.insert(h).second) + // If 'h' is not visited yet, we walk around the target of 'h' and mark these + // halfedges as visited. Thus, if we are here and the target is already marked as visited, + // it means that the vertex is non manifold. + if(halfedges_handled.insert(h).second) { vertex_descriptor vd = target(h, tm); - if ( !vertices_handled.insert(vd).second ) + if(!vertices_handled.insert(vd).second) { + put(cmap, vd, true); // store the originals non_manifold_cones.push_back(h); } else + { set_halfedge(vd, h, tm); - halfedge_descriptor start=opposite(next(h, tm), tm); - h=start; - do{ + } + + halfedge_descriptor start = opposite(next(h, tm), tm); + h = start; + do + { halfedges_handled.insert(h); - h=opposite(next(h, tm), tm); - }while(h!=start); + h = opposite(next(h, tm), tm); + } + while(h != start); } } - if (!non_manifold_cones.empty()) { + if(!non_manifold_cones.empty()) + { BOOST_FOREACH(halfedge_descriptor h, non_manifold_cones) { halfedge_descriptor start = h; vertex_descriptor new_vd = add_vertex(tm); ++nb_new_vertices; + put(cmap, new_vd, true); // store the duplicates + dmap.collect_vertices(target(h, tm), new_vd); put(vpm, new_vd, get(vpm, target(h, tm))); set_halfedge(new_vd, h, tm); - do{ + do + { set_target(h, new_vd, tm); - h=opposite(next(h, tm), tm); - } while(h!=start); + h = opposite(next(h, tm), tm); + } + while(h != start); } + dmap.dump(out); } return nb_new_vertices; @@ -1343,12 +1674,9 @@ std::size_t duplicate_non_manifold_vertices(TriangleMesh& tm, Vpm vpm) template std::size_t duplicate_non_manifold_vertices(TriangleMesh& tm) { - return duplicate_non_manifold_vertices(tm, get(vertex_point, tm)); + return duplicate_non_manifold_vertices(tm, parameters::all_default()); } -/// \endcond - - /// \ingroup PMP_repairing_grp /// removes the isolated vertices from any polygon mesh. /// A vertex is considered isolated if it is not incident to any simplex diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/shape_predicates.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/shape_predicates.h new file mode 100644 index 00000000000..c1f0b7c040b --- /dev/null +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/shape_predicates.h @@ -0,0 +1,358 @@ +// Copyright (c) 2015, 2018 GeometryFactory (France). +// All rights reserved. +// +// This file is part of CGAL (www.cgal.org). +// You can redistribute it and/or modify it under the terms of the GNU +// General Public License as published by the Free Software Foundation, +// either version 3 of the License, or (at your option) any later version. +// +// Licensees holding a valid commercial license may use this file in +// accordance with the commercial license agreement provided with the software. +// +// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +// +// $URL$ +// $Id$ +// SPDX-License-Identifier: GPL-3.0+ +// +// +// Author(s) : Konstantinos Katrioplas, +// Mael Rouxel-Labbé + +#ifndef CGAL_POLYGON_MESH_PROCESSING_SHAPE_PREDICATES_H +#define CGAL_POLYGON_MESH_PROCESSING_SHAPE_PREDICATES_H + +#include + +#include +#include + +#include +#include +#include + +#include +#include + +#include +#include +#include +#include + +namespace CGAL { + +namespace Polygon_mesh_processing { + +/// \ingroup PMP_repairing_grp +/// checks whether an edge is degenerate. +/// An edge is considered degenerate if the geometric positions of its two extremities are identical. +/// +/// @tparam PolygonMesh a model of `HalfedgeGraph` +/// @tparam NamedParameters a sequence of \ref pmp_namedparameters "Named Parameters" +/// +/// @param e an edge of `pm` +/// @param pm polygon mesh containing `e` +/// @param np optional \ref pmp_namedparameters "Named Parameters" described below +/// +/// \cgalNamedParamsBegin +/// \cgalParamBegin{vertex_point_map} the property map with the points associated to the vertices of `pm`. +/// The type of this map is model of `ReadWritePropertyMap`. +/// If this parameter is omitted, an internal property map for +/// `CGAL::vertex_point_t` should be available in `PolygonMesh` +/// \cgalParamEnd +/// \cgalParamBegin{geom_traits} a geometric traits class instance. +/// The traits class must provide the nested type `Point_3`, +/// and the nested functor `Equal_3` to check whether two points are identical. +/// \cgalParamEnd +/// \cgalNamedParamsEnd +/// +/// \sa `degenerate_edges()` +/// +/// \return `true` if the edge `e` is degenerate, `false` otherwise. +template +bool is_degenerate_edge(typename boost::graph_traits::edge_descriptor e, + const PolygonMesh& pm, + const NamedParameters& np) +{ + using boost::get_param; + using boost::choose_param; + + typedef typename GetVertexPointMap::const_type VertexPointMap; + VertexPointMap vpmap = choose_param(get_param(np, internal_np::vertex_point), + get_const_property_map(vertex_point, pm)); + + typedef typename GetGeomTraits::type Traits; + Traits traits = choose_param(get_param(np, internal_np::geom_traits), Traits()); + + return traits.equal_3_object()(get(vpmap, source(e, pm)), get(vpmap, target(e, pm))); +} + +template +bool is_degenerate_edge(typename boost::graph_traits::edge_descriptor e, + const PolygonMesh& pm) +{ + return is_degenerate_edge(e, pm, parameters::all_default()); +} + +/// \ingroup PMP_repairing_grp +/// checks whether a triangle face is degenerate. +/// A triangle face is considered degenerate if the geometric positions of its vertices are collinear. +/// +/// @tparam TriangleMesh a model of `FaceGraph` +/// @tparam NamedParameters a sequence of \ref pmp_namedparameters "Named Parameters" +/// +/// @param f a triangle face of `tm` +/// @param tm a triangle mesh containing `f` +/// @param np optional \ref pmp_namedparameters "Named Parameters" described below +/// +/// \cgalNamedParamsBegin +/// \cgalParamBegin{vertex_point_map} the property map with the points associated to the vertices of `tm`. +/// The type of this map is model of `ReadWritePropertyMap`. +/// If this parameter is omitted, an internal property map for +/// `CGAL::vertex_point_t` should be available in `TriangleMesh` +/// \cgalParamEnd +/// \cgalParamBegin{geom_traits} a geometric traits class instance. +/// The traits class must provide the nested functor `Collinear_3` +/// to check whether three points are collinear. +/// \cgalParamEnd +/// \cgalNamedParamsEnd +/// +/// \sa `degenerate_faces()` +/// +/// \return `true` if the face `f` is degenerate, `false` otherwise. +template +bool is_degenerate_triangle_face(typename boost::graph_traits::face_descriptor f, + const TriangleMesh& tm, + const NamedParameters& np) +{ + CGAL_precondition(CGAL::is_triangle(halfedge(f, tm), tm)); + + using boost::get_param; + using boost::choose_param; + + typedef typename GetVertexPointMap::const_type VertexPointMap; + VertexPointMap vpmap = choose_param(get_param(np, internal_np::vertex_point), + get_const_property_map(vertex_point, tm)); + + typedef typename GetGeomTraits::type Traits; + Traits traits = choose_param(get_param(np, internal_np::geom_traits), Traits()); + + typename boost::graph_traits::halfedge_descriptor h = halfedge(f, tm); + + return traits.collinear_3_object()(get(vpmap, source(h, tm)), + get(vpmap, target(h, tm)), + get(vpmap, target(next(h, tm), tm))); +} + +template +bool is_degenerate_triangle_face(typename boost::graph_traits::face_descriptor f, + const TriangleMesh& tm) +{ + return CGAL::Polygon_mesh_processing::is_degenerate_triangle_face(f, tm, parameters::all_default()); +} + +/// \ingroup PMP_repairing_grp +/// checks whether a triangle face is needle. +/// A triangle is said to be a needle if its longest edge is much longer than its shortest edge. +/// +/// @tparam TriangleMesh a model of `FaceGraph` +/// @tparam NamedParameters a sequence of \ref pmp_namedparameters "Named Parameters" +/// +/// @param f a triangle face of `tm` +/// @param tm triangle mesh containing `f` +/// @param threshold a bound on the ratio of the longest edge length and the shortest edge length +/// @param np optional \ref pmp_namedparameters "Named Parameters" described below +/// +/// \cgalNamedParamsBegin +/// \cgalParamBegin{vertex_point_map} the property map with the points associated to the vertices of `tm`. +/// The type of this map is model of `ReadWritePropertyMap`. +/// If this parameter is omitted, an internal property map for +/// `CGAL::vertex_point_t` should be available in `TriangleMesh` +/// \cgalParamEnd +/// \cgalParamBegin{geom_traits} a geometric traits class instance. +/// The traits class must provide the nested type `FT` and +/// the nested functor `Compute_squared_distance_3`. +/// \cgalParamEnd +/// \cgalNamedParamsEnd +/// +/// \return the shortest halfedge if the triangle face is a needle, and a null halfedge otherwise. +/// If the face contains degenerate edges, a halfedge corresponding to one of these edges is returned. +template +typename boost::graph_traits::halfedge_descriptor +is_needle_triangle_face(typename boost::graph_traits::face_descriptor f, + const TriangleMesh& tm, + const double threshold, + const NamedParameters& np) +{ + CGAL_precondition(threshold >= 1.); + + using boost::get_param; + using boost::choose_param; + + typedef typename boost::graph_traits::halfedge_descriptor halfedge_descriptor; + + typedef typename GetVertexPointMap::const_type VertexPointMap; + VertexPointMap vpmap = choose_param(get_param(np, internal_np::vertex_point), + get_const_property_map(vertex_point, tm)); + + typedef typename GetGeomTraits::type Traits; + Traits traits = choose_param(get_param(np, internal_np::geom_traits), Traits()); + + typedef typename Traits::FT FT; + + CGAL::Halfedge_around_face_iterator hit, hend; + boost::tie(hit, hend) = CGAL::halfedges_around_face(halfedge(f, tm), tm); + CGAL_precondition(std::distance(hit, hend) == 3); + + const halfedge_descriptor h0 = *hit++; + FT sq_length = traits.compute_squared_distance_3_object()(get(vpmap, source(h0, tm)), + get(vpmap, target(h0, tm))); + + FT min_sq_length = sq_length, max_sq_length = sq_length; + halfedge_descriptor min_h = h0; + + for(; hit!=hend; ++hit) + { + const halfedge_descriptor h = *hit; + sq_length = traits.compute_squared_distance_3_object()(get(vpmap, source(h, tm)), + get(vpmap, target(h, tm))); + + if(max_sq_length < sq_length) + max_sq_length = sq_length; + + if(min_sq_length > sq_length) + { + min_h = h; + min_sq_length = sq_length; + } + } + + if(min_sq_length == 0) + return min_h; + + const FT sq_threshold = threshold * threshold; + if(max_sq_length / min_sq_length >= sq_threshold) + { + CGAL_assertion(min_h != boost::graph_traits::null_halfedge()); + return min_h; + } + else + return boost::graph_traits::null_halfedge(); +} + +template +typename boost::graph_traits::halfedge_descriptor +is_needle_triangle_face(typename boost::graph_traits::face_descriptor f, + const TriangleMesh& tm, + const double threshold) +{ + return is_needle_triangle_face(f, tm, threshold, parameters::all_default()); +} + +/// \ingroup PMP_repairing_grp +/// checks whether a triangle face is a cap. +/// A triangle is said to be a cap if one of the its angles is close to `180` degrees. +/// +/// @tparam TriangleMesh a model of `FaceGraph` +/// @tparam NamedParameters a sequence of \ref pmp_namedparameters "Named Parameters" +/// +/// @param f a triangle face of `tm` +/// @param tm triangle mesh containing `f` +/// @param threshold the cosine of a minimum angle such that if `f` has an angle greater than this bound, +/// it is a cap. The threshold is in range `[-1 0]` and corresponds to an angle +/// between `90` and `180` degrees. +/// @param np optional \ref pmp_namedparameters "Named Parameters" described below +/// +/// \cgalNamedParamsBegin +/// \cgalParamBegin{vertex_point_map} the property map with the points associated to the vertices of `tm`. +/// The type of this map is model of `ReadWritePropertyMap`. +/// If this parameter is omitted, an internal property map for +/// `CGAL::vertex_point_t` should be available in `TriangleMesh` +/// \cgalParamEnd +/// \cgalParamBegin{geom_traits} a geometric traits class instance. +/// The traits class must provide the nested type `Point_3` and +/// the nested functors `Compute_squared_distance_3`, `Construct_vector_3`, +/// and `Compute_scalar_product_3`. +/// \cgalParamEnd +/// \cgalNamedParamsEnd +/// +/// \return the halfedge opposite of the largest angle if the face is a cap, and a null halfedge otherwise. +template +typename boost::graph_traits::halfedge_descriptor +is_cap_triangle_face(typename boost::graph_traits::face_descriptor f, + const TriangleMesh& tm, + const double threshold, + const NamedParameters& np) +{ + CGAL_precondition(CGAL::is_triangle_mesh(tm)); + CGAL_precondition(threshold >= -1.); + CGAL_precondition(threshold <= 0.); + + using boost::get_param; + using boost::choose_param; + + typedef typename boost::graph_traits::vertex_descriptor vertex_descriptor; + typedef typename boost::graph_traits::halfedge_descriptor halfedge_descriptor; + + typedef typename GetVertexPointMap::const_type VertexPointMap; + VertexPointMap vpmap = choose_param(get_param(np, internal_np::vertex_point), + get_const_property_map(vertex_point, tm)); + + typedef typename GetGeomTraits::type Traits; + Traits traits = choose_param(get_param(np, internal_np::geom_traits), Traits()); + + typedef typename Traits::FT FT; + typedef typename Traits::Vector_3 Vector_3; + + const FT sq_threshold = threshold * threshold; + const halfedge_descriptor h0 = halfedge(f, tm); + + cpp11::array sq_lengths; + int pos = 0; + BOOST_FOREACH(halfedge_descriptor h, halfedges_around_face(h0, tm)) + { + const FT sq_d = traits.compute_squared_distance_3_object()(get(vpmap, source(h, tm)), + get(vpmap, target(h, tm))); + + // If even one edge is degenerate, it cannot be a cap + if(sq_d == 0) + return boost::graph_traits::null_halfedge(); + + sq_lengths[pos++] = sq_d; + } + + pos = 0; + BOOST_FOREACH(halfedge_descriptor h, halfedges_around_face(h0, tm)) + { + const vertex_descriptor v0 = source(h, tm); + const vertex_descriptor v1 = target(h, tm); + const vertex_descriptor v2 = target(next(h, tm), tm); + const Vector_3 a = traits.construct_vector_3_object()(get(vpmap, v1), get(vpmap, v2)); + const Vector_3 b = traits.construct_vector_3_object()(get(vpmap, v1), get(vpmap, v0)); + const FT dot_ab = traits.compute_scalar_product_3_object()(a, b); + const bool neg_sp = (dot_ab <= 0); + const FT sq_a = sq_lengths[(pos+1)%3]; + const FT sq_b = sq_lengths[pos]; + const FT sq_cos = dot_ab * dot_ab / (sq_a * sq_b); + + if(neg_sp && sq_cos >= sq_threshold) + return prev(h, tm); + + ++pos; + } + return boost::graph_traits::null_halfedge(); +} + +template +typename boost::graph_traits::halfedge_descriptor +is_cap_triangle_face(typename boost::graph_traits::face_descriptor f, + const TriangleMesh& tm, + const double threshold) +{ + return is_cap_triangle_face(f, tm, threshold, parameters::all_default()); +} + +} } // end namespaces CGAL and PMP + +#endif // CGAL_POLYGON_MESH_PROCESSING_SHAPE_PREDICATES_H diff --git a/Polygon_mesh_processing/include/CGAL/polygon_mesh_processing.h b/Polygon_mesh_processing/include/CGAL/polygon_mesh_processing.h index 7d587ad4b84..164b29b25b7 100644 --- a/Polygon_mesh_processing/include/CGAL/polygon_mesh_processing.h +++ b/Polygon_mesh_processing/include/CGAL/polygon_mesh_processing.h @@ -49,6 +49,8 @@ #include #include #include +#include +#include // the named parameter header being not documented the doc is put here for now #ifdef DOXYGEN_RUNNING diff --git a/Polygon_mesh_processing/test/Polygon_mesh_processing/CMakeLists.txt b/Polygon_mesh_processing/test/Polygon_mesh_processing/CMakeLists.txt index 6ffde721a7d..124a9379880 100644 --- a/Polygon_mesh_processing/test/Polygon_mesh_processing/CMakeLists.txt +++ b/Polygon_mesh_processing/test/Polygon_mesh_processing/CMakeLists.txt @@ -101,6 +101,8 @@ endif() create_single_source_cgal_program("test_orient_cc.cpp") create_single_source_cgal_program("test_pmp_transform.cpp") create_single_source_cgal_program("extrude_test.cpp") + create_single_source_cgal_program("test_merging_border_vertices.cpp") + create_single_source_cgal_program("test_shape_predicates.cpp") if( TBB_FOUND ) CGAL_target_use_TBB(test_pmp_distance) diff --git a/Polygon_mesh_processing/test/Polygon_mesh_processing/data/merge_points.off b/Polygon_mesh_processing/test/Polygon_mesh_processing/data/merge_points.off new file mode 100644 index 00000000000..7a83712189f --- /dev/null +++ b/Polygon_mesh_processing/test/Polygon_mesh_processing/data/merge_points.off @@ -0,0 +1,95 @@ +OFF +47 45 0 + +-0.026804100000000001 -0.30492799999999998 0.142542 +-0.018234400000000001 -0.28125499999999998 0.15192700000000001 +-0.074329900000000004 -0.27701599999999998 0.17852999999999999 +-0.075232300000000002 -0.238787 0.19677600000000001 +-0.092496499999999995 -0.26196000000000003 0.18681900000000001 +-0.107975 -0.220055 0.202264 +-0.098042799999999999 -0.24015500000000001 0.197738 +-0.076830499999999996 -0.20389099999999999 0.20217599999999999 +-0.10664999999999999 -0.18507100000000001 0.204627 +-0.048507700000000001 -0.30671799999999999 0.14971999999999999 +-0.10985300000000001 -0.27012399999999998 0.16877500000000001 +0.020159400000000001 -0.26358599999999999 0.11985899999999999 +-0.0820192 -0.303394 0.145977 +-0.11151800000000001 -0.28692499999999999 0.148566 +0.033791700000000001 -0.209923 0.115845 +0.019949499999999998 -0.19298699999999999 0.125832 +0.00080011299999999997 -0.19967099999999999 0.13874900000000001 +0.0102764 -0.16375000000000001 0.13344700000000001 +0.015325999999999999 -0.12934699999999999 0.14213100000000001 +0.043303899999999999 -0.239647 0.099889199999999997 +-0.010328800000000001 -0.10643 0.14183100000000001 +-0.032521000000000001 -0.10838299999999999 0.13683899999999999 +-0.085985000000000006 -0.101282 0.15809300000000001 +-0.108849 -0.11043600000000001 0.16941700000000001 +-0.052558500000000001 -0.097836599999999996 0.13975499999999999 +-0.10316599999999999 -0.15746599999999999 0.19631499999999999 +-0.112763 -0.133107 0.183753 +-0.063495300000000005 -0.15489 0.17952499999999999 +-0.064211199999999996 -0.12604799999999999 0.16286 +-0.086169300000000004 -0.13996600000000001 0.183699 +-0.063495300000000005 -0.15489 0.17952499999999999 +-0.023309900000000001 -0.17152600000000001 0.15354100000000001 +-0.0254547 -0.133829 0.14063300000000001 +-0.079254099999999994 -0.17391000000000001 0.197354 +-0.0458796 -0.210094 0.18626999999999999 +-0.063495300000000005 -0.15489 0.17952499999999999 +-0.0097084900000000002 -0.22793099999999999 0.15407299999999999 +-0.0458796 -0.210094 0.18626999999999999 +-0.0458796 -0.210094 0.18626999999999999 +-0.075232300000000002 -0.238787 0.19677600000000001 +-0.049308200000000003 -0.25528899999999999 0.18343899999999999 +-0.0218198 -0.25775500000000001 0.16445000000000001 +-0.049308200000000003 -0.25528899999999999 0.18343899999999999 +-0.041782300000000001 -0.28198800000000002 0.16825000000000001 +0.00026201499999999999 -0.25824399999999997 0.14286599999999999 +0.015174200000000001 -0.229959 0.128466 +-0.0097084900000000002 -0.22793099999999999 0.15407299999999999 +3 43 0 1 +3 2 3 4 +3 5 6 3 +3 7 5 3 +3 5 7 8 +3 0 43 9 +3 10 2 4 +3 1 44 41 +3 11 45 44 +3 12 9 2 +3 13 12 2 +3 14 15 45 +3 16 45 15 +3 43 1 41 +3 17 16 15 +3 16 31 36 +3 31 16 17 +3 17 18 32 +3 11 19 45 +3 43 2 9 +3 18 20 32 +3 20 21 32 +3 13 2 10 +3 29 28 22 +3 45 19 14 +3 23 29 22 +3 24 22 28 +3 21 24 28 +3 32 21 28 +3 33 29 25 +3 8 33 25 +3 8 7 33 +3 26 29 23 +3 34 33 7 +3 25 29 26 +3 4 3 6 +3 31 17 32 +3 29 27 28 +3 32 30 31 +3 34 35 33 +3 31 37 36 +3 40 38 39 +3 41 42 43 +3 45 46 44 +3 44 46 41 diff --git a/Polygon_mesh_processing/test/Polygon_mesh_processing/data/non_manifold_vertex_duplicated.off b/Polygon_mesh_processing/test/Polygon_mesh_processing/data/non_manifold_vertex_duplicated.off new file mode 100644 index 00000000000..5733b99f480 --- /dev/null +++ b/Polygon_mesh_processing/test/Polygon_mesh_processing/data/non_manifold_vertex_duplicated.off @@ -0,0 +1,20 @@ +OFF +8 8 0 +0 1 0 +1 0 0 +0 0 0 +0 0 1 +2 1 0 +2 0 0 +2 0 -1 +1 0 0 +3 0 1 2 +3 2 3 0 +3 1 3 2 +3 0 3 1 +3 7 5 4 +3 7 6 5 +3 4 6 7 +3 5 6 4 + + diff --git a/Polygon_mesh_processing/test/Polygon_mesh_processing/data_degeneracies/caps_and_needles.off b/Polygon_mesh_processing/test/Polygon_mesh_processing/data_degeneracies/caps_and_needles.off new file mode 100644 index 00000000000..4e206746788 --- /dev/null +++ b/Polygon_mesh_processing/test/Polygon_mesh_processing/data_degeneracies/caps_and_needles.off @@ -0,0 +1,17 @@ +OFF +9 3 0 +0 0 0 +1 0 0 +1 1 0 +0 0 1 +1 0 1 +10 10 1 +0 0 2 +1 0 2 +-0.99619469809 0.08715574274 2 +3 0 1 2 +3 3 4 5 +3 6 7 8 + + + diff --git a/Polygon_mesh_processing/test/Polygon_mesh_processing/data_degeneracies/degtri_edge.off b/Polygon_mesh_processing/test/Polygon_mesh_processing/data_degeneracies/degtri_edge.off new file mode 100644 index 00000000000..afd48de232f --- /dev/null +++ b/Polygon_mesh_processing/test/Polygon_mesh_processing/data_degeneracies/degtri_edge.off @@ -0,0 +1,6 @@ +OFF +3 1 0 +0 0 0 +1 0 0 +0 0 0 +3 0 1 2 diff --git a/Polygon_mesh_processing/test/Polygon_mesh_processing/remove_degeneracies_test.cpp b/Polygon_mesh_processing/test/Polygon_mesh_processing/remove_degeneracies_test.cpp index 386e27723a1..b37cc61eb92 100644 --- a/Polygon_mesh_processing/test/Polygon_mesh_processing/remove_degeneracies_test.cpp +++ b/Polygon_mesh_processing/test/Polygon_mesh_processing/remove_degeneracies_test.cpp @@ -11,11 +11,34 @@ //the last test (on trihole.off) does not terminate // -typedef CGAL::Exact_predicates_inexact_constructions_kernel K; +namespace PMP = CGAL::Polygon_mesh_processing; -typedef CGAL::Surface_mesh Surface_mesh; +typedef CGAL::Exact_predicates_inexact_constructions_kernel K; -void fix(const char* fname) +typedef CGAL::Surface_mesh Surface_mesh; + +typedef boost::graph_traits::edge_descriptor edge_descriptor; +typedef boost::graph_traits::face_descriptor face_descriptor; + +void detect_degeneracies(const Surface_mesh& mesh) +{ + std::vector dfaces; + + PMP::degenerate_faces(mesh, std::back_inserter(dfaces)); + PMP::degenerate_faces(faces(mesh), mesh, std::back_inserter(dfaces)); + PMP::degenerate_faces(mesh, std::back_inserter(dfaces), CGAL::parameters::all_default()); + PMP::degenerate_faces(faces(mesh), mesh, std::back_inserter(dfaces), CGAL::parameters::all_default()); + assert(!dfaces.empty()); + + std::set dedges; + PMP::degenerate_edges(mesh, std::inserter(dedges, dedges.end())); + PMP::degenerate_edges(edges(mesh), mesh, std::inserter(dedges, dedges.begin())); + PMP::degenerate_edges(mesh, std::inserter(dedges, dedges.end()), CGAL::parameters::all_default()); + PMP::degenerate_edges(edges(mesh), mesh, std::inserter(dedges, dedges.begin()), CGAL::parameters::all_default()); + assert(dedges.empty()); +} + +void fix_degeneracies(const char* fname) { std::ifstream input(fname); @@ -24,20 +47,22 @@ void fix(const char* fname) std::cerr << fname << " is not a valid off file.\n"; exit(1); } - CGAL::Polygon_mesh_processing::remove_degenerate_faces(mesh); + detect_degeneracies(mesh); + + CGAL::Polygon_mesh_processing::remove_degenerate_faces(mesh); assert( CGAL::is_valid_polygon_mesh(mesh) ); } int main() { - fix("data_degeneracies/degtri_2dt_1edge_split_twice.off"); - fix("data_degeneracies/degtri_four-2.off"); - fix("data_degeneracies/degtri_four.off"); - fix("data_degeneracies/degtri_on_border.off"); - fix("data_degeneracies/degtri_three.off"); - fix("data_degeneracies/degtri_single.off"); - fix("data_degeneracies/trihole.off"); + fix_degeneracies("data_degeneracies/degtri_2dt_1edge_split_twice.off"); + fix_degeneracies("data_degeneracies/degtri_four-2.off"); + fix_degeneracies("data_degeneracies/degtri_four.off"); + fix_degeneracies("data_degeneracies/degtri_on_border.off"); + fix_degeneracies("data_degeneracies/degtri_three.off"); + fix_degeneracies("data_degeneracies/degtri_single.off"); + fix_degeneracies("data_degeneracies/trihole.off"); return 0; } diff --git a/Polygon_mesh_processing/test/Polygon_mesh_processing/run_test_corefinement_bool_op_full.sh b/Polygon_mesh_processing/test/Polygon_mesh_processing/run_test_corefinement_bool_op_full.sh index 3d54c2f0f47..2cea97cfb6b 100644 --- a/Polygon_mesh_processing/test/Polygon_mesh_processing/run_test_corefinement_bool_op_full.sh +++ b/Polygon_mesh_processing/test/Polygon_mesh_processing/run_test_corefinement_bool_op_full.sh @@ -4,27 +4,19 @@ GREEN="\\033[1;32m" NORMAL="\\033[0;39m" RED="\\033[1;31m" -METHOD="SM" - -if [ ! -e $1 ""]; then - METHOD=$1 -fi - -echo "Testing with $METHOD" - k=`wc -l test_corefinement_bool_op_full.cmd | awk '{print $1}'` for i in `seq 1 $k`; do files=`head -n $i test_corefinement_bool_op_full.cmd | tail -n 1` f1=`echo $files | awk '{print $1}'` f2=`echo $files | awk '{print $2}'` - ru=`echo $files | awk '{print $5}'` - ri=`echo $files | awk '{print $6}'` - rm=`echo $files | awk '{print $7}'` - rmr=`echo $files | awk '{print $8}'` + ru=`echo $files | awk '{print $4}'` + ri=`echo $files | awk '{print $5}'` + rm=`echo $files | awk '{print $6}'` + rmr=`echo $files | awk '{print $7}'` echo -n "==== " $f1 $f2 " " - if (./test_corefinement_bool_op $f1 $f2 $METHOD ALL $ru $ri $rm $rmr|| false ) > /dev/null 2>&1; then + if (./test_corefinement_bool_op $f1 $f2 ALL $ru $ri $rm $rmr|| false ) > /dev/null 2>&1; then echo -e " ==> $GREEN SUCCEED" echo -e -n "$NORMAL" else diff --git a/Polygon_mesh_processing/test/Polygon_mesh_processing/test_corefinement_bool_op.cmd b/Polygon_mesh_processing/test/Polygon_mesh_processing/test_corefinement_bool_op.cmd index 15f6bd5c23d..3740f7caf89 100644 --- a/Polygon_mesh_processing/test/Polygon_mesh_processing/test_corefinement_bool_op.cmd +++ b/Polygon_mesh_processing/test/Polygon_mesh_processing/test_corefinement_bool_op.cmd @@ -1 +1 @@ -data-coref/elephant.off data-coref/sphere.off SM ALL 1 1 1 1 +data-coref/elephant.off data-coref/sphere.off ALL 1 1 1 1 diff --git a/Polygon_mesh_processing/test/Polygon_mesh_processing/test_corefinement_bool_op.cpp b/Polygon_mesh_processing/test/Polygon_mesh_processing/test_corefinement_bool_op.cpp index 97e23b20cf2..ec1664aef97 100644 --- a/Polygon_mesh_processing/test/Polygon_mesh_processing/test_corefinement_bool_op.cpp +++ b/Polygon_mesh_processing/test/Polygon_mesh_processing/test_corefinement_bool_op.cpp @@ -1,23 +1,15 @@ // #define CGAL_COREFINEMENT_POLYHEDRA_DEBUG // #define CGAL_COREFINEMENT_DEBUG -// #define CGAL_TODO_WARNINGS #include #include #include -#include - #include #include #include #include -// includes for Operations on polyhedra -#include -#include -#include - #include #include @@ -28,16 +20,6 @@ typedef CGAL::Surface_mesh Surface_mesh; namespace PMP = CGAL::Polygon_mesh_processing; namespace CFR = PMP::Corefinement; -//includes typedefs for Operations on polyhedra -typedef CGAL::Polyhedron_3 Polyhedron; -typedef std::map Facet_id_map; -typedef boost::associative_property_map Facet_id_pmap; -typedef CGAL::Corefinement - ::Polyhedra_output_builder< Polyhedron, - Facet_id_pmap> Output_builder; -typedef CGAL::Node_visitor_refine_polyhedra Split_visitor; - struct Result_checking { bool check; @@ -49,111 +31,6 @@ struct Result_checking Result_checking() : check(false) {} }; -void run_boolean_operations( - Polyhedron& P, - Polyhedron& Q, - Polyhedron& union_, - Polyhedron& inter, - Polyhedron& P_minus_Q, - Polyhedron& Q_minus_P, - std::string scenario, - std::size_t id, - const Result_checking& rc) -{ - std::cout << "Scenario #" << id << " - " << scenario << "\n"; - - CGAL::Emptyset_iterator output_it; - Facet_id_map P_facet_id_map, Q_facet_id_map; - - CGAL::cpp11::array, 4 > output; - - output[Output_builder::P_UNION_Q]=boost::make_optional( &union_ ); - output[Output_builder::P_INTER_Q]=boost::make_optional( &inter ); - output[Output_builder::P_MINUS_Q]=boost::make_optional( &P_minus_Q ); - output[Output_builder::Q_MINUS_P]=boost::make_optional( &Q_minus_P ); - - Output_builder output_builder(P, Q, - output, - Facet_id_pmap(P_facet_id_map), - Facet_id_pmap(Q_facet_id_map) ); - Split_visitor visitor(output_builder); - - CGAL::Intersection_of_Polyhedra_3 polyline_intersections(visitor); - std::cout << " Vertices before " << P.size_of_vertices() - << " " << Q.size_of_vertices() << std::endl; - polyline_intersections(P, Q, output_it); - std::cout << " Vertices after " << P.size_of_vertices() - << " " << Q.size_of_vertices() << std::endl; - - - if ( output_builder.union_valid() ){ - std::cout << " Union is a valid operation\n"; - assert(union_.is_valid()); - #ifdef CGAL_COREFINEMENT_DEBUG - std::stringstream fname; - fname << scenario << "_P_union_Q.off"; - std::ofstream output(fname.str().c_str()); - output << std::setprecision(17) << union_; - #endif - } - else - std::cout << " Union is invalid\n"; - - if ( output_builder.intersection_valid() ){ - std::cout << " Intersection is a valid operation\n"; - assert(inter.is_valid()); - #ifdef CGAL_COREFINEMENT_DEBUG - std::stringstream fname; - fname << scenario << "_P_inter_Q.off"; - std::ofstream output(fname.str().c_str()); - output << std::setprecision(17) << inter; - #endif - } - else - std::cout << " Intersection is invalid\n"; - - if ( output_builder.P_minus_Q_valid() ){ - std::cout << " P-Q is a valid operation\n"; - assert(P_minus_Q.is_valid()); - #ifdef CGAL_COREFINEMENT_DEBUG - std::stringstream fname; - fname << scenario << "_P_minus_Q.off"; - std::ofstream output(fname.str().c_str()); - output << std::setprecision(17) << P_minus_Q; - #endif - } - else - std::cout << " P-Q is invalid\n"; - - if ( output_builder.Q_minus_P_valid() ){ - std::cout << " Q-P is a valid operation\n"; - assert(Q_minus_P.is_valid()); - #ifdef CGAL_COREFINEMENT_DEBUG - std::stringstream fname; - fname << scenario << "_Q_minus_P.off"; - std::ofstream output(fname.str().c_str()); - output << std::setprecision(17) << Q_minus_P; - #endif - } - else - std::cout << " Q-P is invalid\n"; - - if (rc.check) - { - if(output_builder.union_valid()!=rc.union_res || - output_builder.intersection_valid()!=rc.inter_res || - output_builder.P_minus_Q_valid()!=rc.P_minus_Q_res || - output_builder.Q_minus_P_valid()!=rc.Q_minus_P_res) - { - std::cerr << " ERROR: at least one operation is not as expected!\n"; - exit(EXIT_FAILURE); - } - else - std::cout << " All operations are as expected.\n"; - } -} - - void run_boolean_operations( Surface_mesh& tm1, Surface_mesh& tm2, @@ -344,34 +221,26 @@ void run(char* P_fname, char* Q_fname, int k, int main(int argc,char** argv) { if (argc<3){ - std::cerr << "Usage "<< argv[0] << " file1.off file2.off [SM/POLY] [scenario_id/ALL] [0/1 0/1 0/1 0/1 (expected valid operations U I P-Q Q-P)]\n"; + std::cerr << "Usage "<< argv[0] << " file1.off file2.off [scenario_id/ALL] [0/1 0/1 0/1 0/1 (expected valid operations U I P-Q Q-P)]\n"; return 1; } Result_checking rc; - if (argc==9) + if (argc==8) { rc.check=true; - rc.union_res = atoi(argv[5])!=0; - rc.inter_res = atoi(argv[6])!=0; - rc.P_minus_Q_res = atoi(argv[7])!=0; - rc.Q_minus_P_res = atoi(argv[8])!=0; + rc.union_res = atoi(argv[4])!=0; + rc.inter_res = atoi(argv[5])!=0; + rc.P_minus_Q_res = atoi(argv[6])!=0; + rc.Q_minus_P_res = atoi(argv[7])!=0; } int scenario = -1; - if (argc>=5 && std::string(argv[4])!=std::string("ALL")) + if (argc>=5 && std::string(argv[3])!=std::string("ALL")) scenario = atoi(argv[4]); - if ( argc==3 || std::string(argv[3])==std::string("SM") ) - run(argv[1], argv[2], scenario, rc); - else - if ( std::string(argv[3])==std::string("POLY") ) - run(argv[1], argv[2], scenario, rc); - else - { - std::cout <<"Invalid value, only SM or POLY can be given\n"; - return 1; - } + run(argv[1], argv[2], scenario, rc); + return 0; } diff --git a/Polygon_mesh_processing/test/Polygon_mesh_processing/test_corefinement_bool_op_full.cmd b/Polygon_mesh_processing/test/Polygon_mesh_processing/test_corefinement_bool_op_full.cmd index 8b49a99ecf9..1c03b1ed689 100644 --- a/Polygon_mesh_processing/test/Polygon_mesh_processing/test_corefinement_bool_op_full.cmd +++ b/Polygon_mesh_processing/test/Polygon_mesh_processing/test_corefinement_bool_op_full.cmd @@ -1,49 +1,49 @@ -data-coref/sphere.off data-coref/sphere-2.off SM ALL 1 1 1 1 -data-coref/cube.off data-coref/coplanar_with_cube.off SM ALL 1 1 1 1 -data-coref/cube.off data-coref/coplanar_with_cube1.off SM ALL 1 1 1 1 -data-coref/cube.off data-coref/coplanar_with_cube2.off SM ALL 1 1 1 1 -data-coref/cube.off data-coref/with_cube.off SM ALL 1 1 1 0 -data-coref/open_large_cube.off data-coref/open_small_cube.off SM ALL 1 1 1 1 -data-coref/open_large_cube.off data-coref/open_small_cube_inout.off SM ALL 0 0 0 0 -data-coref/elephant.off data-coref/elephant_plane/plane_1.off SM ALL 1 1 1 1 -data-coref/elephant.off data-coref/elephant_plane/plane_2.off SM ALL 1 1 1 1 -data-coref/elephant.off data-coref/elephant_plane/plane_3.off SM ALL 1 1 1 1 -data-coref/open_tet_1.off data-coref/open_tet_2.off SM ALL 1 1 1 1 -data-coref/small_cube_coplanar_inside.off data-coref/small_cube_coplanar_outside.off SM ALL 1 1 1 1 -data-coref/large_cube_coplanar.off data-coref/small_cube_coplanar_inside.off SM ALL 1 1 1 1 -data-coref/large_cube_coplanar.off data-coref/small_cube_coplanar_outside.off SM ALL 1 1 1 1 -data-coref/P7.off data-coref/Q7.off SM ALL 1 1 1 1 -data-coref/square1.off data-coref/square2.off SM ALL 1 1 1 1 -data-coref/square_pair.off data-coref/square2.off SM ALL 1 1 1 1 -data-coref/elephant.off data-coref/sphere.off SM ALL 1 1 1 1 -data-coref/elephant_split_1.off data-coref/elephant_split_2.off SM ALL 1 1 1 1 -data-coref/cube.off data-coref/cube_on_cube_edge.off SM ALL 0 1 1 1 -data-coref/cube.off data-coref/cube_on_cube_corner.off SM ALL 1 1 1 1 -data-coref/cow.off data-coref/cross.off SM ALL 1 1 1 1 -data-coref/sphere.off data-coref/sphere_trans_cut.off SM ALL 0 0 0 0 -data-coref/open_t11.off data-coref/open_t12.off SM ALL 1 1 1 1 -data-coref/cube.off data-coref/coplanar_with_cube3.off SM ALL 1 1 1 1 -data-coref/cube.off data-coref/coplanar_with_cube4.off SM ALL 1 1 1 1 -data-coref/square1.off data-coref/square_pair.off SM ALL 1 1 1 1 -data-coref/cube_meshed.off data-coref/cube.off SM ALL 1 1 1 1 -data-coref/cube.off data-coref/cube_interior_tgt.off SM ALL 1 1 1 1 -data-coref/cube.off data-coref/edge_tangent_to_cube.off SM ALL 1 1 0 1 -data-coref/cube_dig.off data-coref/wedge.off SM ALL 1 1 1 1 -data-coref/star_tgt1-0.off data-coref/star_tgt2-0.off SM ALL 1 1 1 0 -data-coref/star_tgt1-0.off data-coref/star_tgt2-1.off SM ALL 1 1 1 0 -data-coref/star_tgt1-0.off data-coref/star_tgt2-2.off SM ALL 0 1 1 1 -data-coref/star_tgt1-0.off data-coref/star_tgt2-3.off SM ALL 1 1 1 0 -data-coref/star_tgt1-0.off data-coref/star_tgt2-4.off SM ALL 0 1 1 1 -data-coref/star_tgt1-0.off data-coref/star_tgt2-5.off SM ALL 1 1 1 0 -data-coref/star_tgt1-1.off data-coref/star_tgt2-0.off SM ALL 1 1 1 0 -data-coref/star_tgt1-1.off data-coref/star_tgt2-1.off SM ALL 1 1 1 0 -data-coref/star_tgt1-1.off data-coref/star_tgt2-2.off SM ALL 0 1 1 1 -data-coref/star_tgt1-1.off data-coref/star_tgt2-3.off SM ALL 1 1 1 0 -data-coref/star_tgt1-1.off data-coref/star_tgt2-4.off SM ALL 0 1 1 1 -data-coref/star_tgt1-1.off data-coref/star_tgt2-5.off SM ALL 1 1 1 0 -data-coref/star_tgt1-2.off data-coref/star_tgt2-0.off SM ALL 1 1 1 0 -data-coref/star_tgt1-2.off data-coref/star_tgt2-1.off SM ALL 1 1 1 0 -data-coref/star_tgt1-2.off data-coref/star_tgt2-2.off SM ALL 0 1 1 1 -data-coref/star_tgt1-2.off data-coref/star_tgt2-3.off SM ALL 1 1 1 1 -data-coref/star_tgt1-2.off data-coref/star_tgt2-4.off SM ALL 0 1 1 1 -data-coref/star_tgt1-2.off data-coref/star_tgt2-5.off SM ALL 1 1 1 1 +data-coref/sphere.off data-coref/sphere-2.off ALL 1 1 1 1 +data-coref/cube.off data-coref/coplanar_with_cube.off ALL 1 1 1 1 +data-coref/cube.off data-coref/coplanar_with_cube1.off ALL 1 1 1 1 +data-coref/cube.off data-coref/coplanar_with_cube2.off ALL 1 1 1 1 +data-coref/cube.off data-coref/with_cube.off ALL 1 1 1 0 +data-coref/open_large_cube.off data-coref/open_small_cube.off ALL 1 1 1 1 +data-coref/open_large_cube.off data-coref/open_small_cube_inout.off ALL 0 0 0 0 +data-coref/elephant.off data-coref/elephant_plane/plane_1.off ALL 1 1 1 1 +data-coref/elephant.off data-coref/elephant_plane/plane_2.off ALL 1 1 1 1 +data-coref/elephant.off data-coref/elephant_plane/plane_3.off ALL 1 1 1 1 +data-coref/open_tet_1.off data-coref/open_tet_2.off ALL 1 1 1 1 +data-coref/small_cube_coplanar_inside.off data-coref/small_cube_coplanar_outside.off ALL 1 1 1 1 +data-coref/large_cube_coplanar.off data-coref/small_cube_coplanar_inside.off ALL 1 1 1 1 +data-coref/large_cube_coplanar.off data-coref/small_cube_coplanar_outside.off ALL 1 1 1 1 +data-coref/P7.off data-coref/Q7.off ALL 1 1 1 1 +data-coref/square1.off data-coref/square2.off ALL 1 1 1 1 +data-coref/square_pair.off data-coref/square2.off ALL 1 1 1 1 +data-coref/elephant.off data-coref/sphere.off ALL 1 1 1 1 +data-coref/elephant_split_1.off data-coref/elephant_split_2.off ALL 1 1 1 1 +data-coref/cube.off data-coref/cube_on_cube_edge.off ALL 0 1 1 1 +data-coref/cube.off data-coref/cube_on_cube_corner.off ALL 1 1 1 1 +data-coref/cow.off data-coref/cross.off ALL 1 1 1 1 +data-coref/sphere.off data-coref/sphere_trans_cut.off ALL 0 0 0 0 +data-coref/open_t11.off data-coref/open_t12.off ALL 1 1 1 1 +data-coref/cube.off data-coref/coplanar_with_cube3.off ALL 1 1 1 1 +data-coref/cube.off data-coref/coplanar_with_cube4.off ALL 1 1 1 1 +data-coref/square1.off data-coref/square_pair.off ALL 1 1 1 1 +data-coref/cube_meshed.off data-coref/cube.off ALL 1 1 1 1 +data-coref/cube.off data-coref/cube_interior_tgt.off ALL 1 1 1 1 +data-coref/cube.off data-coref/edge_tangent_to_cube.off ALL 1 1 0 1 +data-coref/cube_dig.off data-coref/wedge.off ALL 1 1 1 1 +data-coref/star_tgt1-0.off data-coref/star_tgt2-0.off ALL 1 1 1 0 +data-coref/star_tgt1-0.off data-coref/star_tgt2-1.off ALL 1 1 1 0 +data-coref/star_tgt1-0.off data-coref/star_tgt2-2.off ALL 0 1 1 1 +data-coref/star_tgt1-0.off data-coref/star_tgt2-3.off ALL 1 1 1 0 +data-coref/star_tgt1-0.off data-coref/star_tgt2-4.off ALL 0 1 1 1 +data-coref/star_tgt1-0.off data-coref/star_tgt2-5.off ALL 1 1 1 0 +data-coref/star_tgt1-1.off data-coref/star_tgt2-0.off ALL 1 1 1 0 +data-coref/star_tgt1-1.off data-coref/star_tgt2-1.off ALL 1 1 1 0 +data-coref/star_tgt1-1.off data-coref/star_tgt2-2.off ALL 0 1 1 1 +data-coref/star_tgt1-1.off data-coref/star_tgt2-3.off ALL 1 1 1 0 +data-coref/star_tgt1-1.off data-coref/star_tgt2-4.off ALL 0 1 1 1 +data-coref/star_tgt1-1.off data-coref/star_tgt2-5.off ALL 1 1 1 0 +data-coref/star_tgt1-2.off data-coref/star_tgt2-0.off ALL 1 1 1 0 +data-coref/star_tgt1-2.off data-coref/star_tgt2-1.off ALL 1 1 1 0 +data-coref/star_tgt1-2.off data-coref/star_tgt2-2.off ALL 0 1 1 1 +data-coref/star_tgt1-2.off data-coref/star_tgt2-3.off ALL 1 1 1 1 +data-coref/star_tgt1-2.off data-coref/star_tgt2-4.off ALL 0 1 1 1 +data-coref/star_tgt1-2.off data-coref/star_tgt2-5.off ALL 1 1 1 1 diff --git a/Polygon_mesh_processing/test/Polygon_mesh_processing/test_merging_border_vertices.cpp b/Polygon_mesh_processing/test/Polygon_mesh_processing/test_merging_border_vertices.cpp new file mode 100644 index 00000000000..ed21427f4d1 --- /dev/null +++ b/Polygon_mesh_processing/test/Polygon_mesh_processing/test_merging_border_vertices.cpp @@ -0,0 +1,54 @@ +#include +#include + +#include +#include + +#include + + +typedef CGAL::Exact_predicates_inexact_constructions_kernel K; +typedef CGAL::Surface_mesh Surface_mesh; + + +void test_merge_duplicated_vertices_in_boundary_cycles(const char* fname, + std::size_t expected_nb_vertices) +{ + std::ifstream input(fname); + + Surface_mesh mesh; + if (!input || !(input >> mesh) || mesh.is_empty()) { + std::cerr << fname << " is not a valid off file.\n"; + exit(1); + } + + std::cout << "Testing merging in cycles " << fname << "\n"; + std::cout << " input mesh has " << vertices(mesh).size() << " vertices.\n"; + CGAL::Polygon_mesh_processing::merge_duplicated_vertices_in_boundary_cycles(mesh); + std::cout << " output mesh has " << vertices(mesh).size() << " vertices.\n"; + + assert(expected_nb_vertices==0 || + expected_nb_vertices == vertices(mesh).size()); + if (expected_nb_vertices==0) + { + std::cout << "writting output to out1.off\n"; + std::ofstream output("out1.off"); + output << std::setprecision(17); + output << mesh; + } +} + +int main(int argc, char** argv) +{ + if (argc==1) + { + test_merge_duplicated_vertices_in_boundary_cycles("data/merge_points.off", 43); + } + else + { + for (int i=1; i< argc; ++i) + test_merge_duplicated_vertices_in_boundary_cycles(argv[i], 0); + } + + return EXIT_SUCCESS; +} diff --git a/Polygon_mesh_processing/test/Polygon_mesh_processing/test_shape_predicates.cpp b/Polygon_mesh_processing/test/Polygon_mesh_processing/test_shape_predicates.cpp new file mode 100644 index 00000000000..378c438102b --- /dev/null +++ b/Polygon_mesh_processing/test/Polygon_mesh_processing/test_shape_predicates.cpp @@ -0,0 +1,251 @@ +#include + +#include + +#include +#include + +#include + +#include +#include + +typedef CGAL::Exact_predicates_inexact_constructions_kernel K; +typedef K::FT FT; +typedef K::Point_3 Point_3; +typedef CGAL::Surface_mesh Surface_mesh; + +void check_edge_degeneracy(const char* fname) +{ + std::cout << "test edge degeneracy..."; + + typedef boost::graph_traits::edge_descriptor edge_descriptor; + + std::ifstream input(fname); + Surface_mesh mesh; + if (!input || !(input >> mesh) || mesh.is_empty()) { + std::cerr << fname << " is not a valid off file.\n"; + std::exit(1); + } + std::vector all_edges(edges(mesh).begin(), edges(mesh).end()); + + assert(!CGAL::Polygon_mesh_processing::is_degenerate_edge(all_edges[0], mesh)); + assert(!CGAL::Polygon_mesh_processing::is_degenerate_edge(all_edges[1], mesh)); + assert(CGAL::Polygon_mesh_processing::is_degenerate_edge(all_edges[2], mesh)); + std::cout << "done" << std::endl; +} + +void check_triangle_face_degeneracy(const char* fname) +{ + std::cout << "test face degeneracy..."; + + typedef boost::graph_traits::face_descriptor face_descriptor; + + std::ifstream input(fname); + Surface_mesh mesh; + if (!input || !(input >> mesh) || mesh.is_empty()) { + std::cerr << fname << " is not a valid off file.\n"; + std::exit(1); + } + + std::vector all_faces(faces(mesh).begin(), faces(mesh).end()); + assert(CGAL::Polygon_mesh_processing::is_degenerate_triangle_face(all_faces[0], mesh)); + assert(!CGAL::Polygon_mesh_processing::is_degenerate_triangle_face(all_faces[1], mesh)); + assert(!CGAL::Polygon_mesh_processing::is_degenerate_triangle_face(all_faces[2], mesh)); + assert(!CGAL::Polygon_mesh_processing::is_degenerate_triangle_face(all_faces[3], mesh)); + + std::cout << "done" << std::endl; +} + +// tests merge_and_duplication +template +void merge_identical_points(typename boost::graph_traits::vertex_descriptor v_keep, + typename boost::graph_traits::vertex_descriptor v_rm, + PolygonMesh& mesh) +{ + typedef typename boost::graph_traits::halfedge_descriptor halfedge_descriptor; + + halfedge_descriptor h = halfedge(v_rm, mesh); + halfedge_descriptor start = h; + + do + { + set_target(h, v_keep, mesh); + h = opposite(next(h, mesh), mesh); + } + while( h != start ); + + remove_vertex(v_rm, mesh); +} + +void test_vertex_non_manifoldness(const char* fname) +{ + std::cout << "test vertex non manifoldness..."; + + typedef boost::graph_traits::vertex_descriptor vertex_descriptor; + typedef boost::graph_traits::vertices_size_type size_type; + + std::ifstream input(fname); + Surface_mesh mesh; + if (!input || !(input >> mesh) || mesh.is_empty()) { + std::cerr << fname << " is not a valid off file.\n"; + std::exit(1); + } + + size_type ini_nv = num_vertices(mesh); + + // create non-manifold vertex + Surface_mesh::Vertex_index vertex_to_merge_onto(1); + Surface_mesh::Vertex_index vertex_to_merge(7); + merge_identical_points(vertex_to_merge_onto, vertex_to_merge, mesh); + mesh.collect_garbage(); + + assert(num_vertices(mesh) == ini_nv - 1); + + BOOST_FOREACH(vertex_descriptor v, vertices(mesh)) + { + if(v == vertex_to_merge_onto) + assert(CGAL::Polygon_mesh_processing::is_non_manifold_vertex(v, mesh)); + else + assert(!CGAL::Polygon_mesh_processing::is_non_manifold_vertex(v, mesh)); + } + + std::cout << "done" << std::endl; +} + +void test_vertices_merge_and_duplication(const char* fname) +{ + std::cout << "test non manifold vertex duplication..."; + + typedef boost::graph_traits::vertex_descriptor vertex_descriptor; + + std::ifstream input(fname); + Surface_mesh mesh; + if (!input || !(input >> mesh) || mesh.is_empty()) { + std::cerr << fname << " is not a valid off file.\n"; + std::exit(1); + } + const std::size_t initial_vertices = num_vertices(mesh); + + // create non-manifold vertex + Surface_mesh::Vertex_index vertex_to_merge_onto(1); + Surface_mesh::Vertex_index vertex_to_merge(7); + Surface_mesh::Vertex_index vertex_to_merge_2(14); + Surface_mesh::Vertex_index vertex_to_merge_3(21); + + Surface_mesh::Vertex_index vertex_to_merge_onto_2(2); + Surface_mesh::Vertex_index vertex_to_merge_4(8); + + merge_identical_points(vertex_to_merge_onto, vertex_to_merge, mesh); + merge_identical_points(vertex_to_merge_onto, vertex_to_merge_2, mesh); + merge_identical_points(vertex_to_merge_onto, vertex_to_merge_3, mesh); + merge_identical_points(vertex_to_merge_onto_2, vertex_to_merge_4, mesh); + mesh.collect_garbage(); + + const std::size_t vertices_after_merge = num_vertices(mesh); + assert(vertices_after_merge == initial_vertices - 4); + + std::vector > duplicated_vertices; + std::size_t new_vertices_nb = + CGAL::Polygon_mesh_processing::duplicate_non_manifold_vertices(mesh, + CGAL::parameters::output_iterator(std::back_inserter(duplicated_vertices))); + + const std::size_t final_vertices_size = vertices(mesh).size(); + assert(final_vertices_size == initial_vertices); + assert(new_vertices_nb == 4); + assert(duplicated_vertices.size() == 2); // two non-manifold vertex + assert(duplicated_vertices.front().size() == 4); + assert(duplicated_vertices.back().size() == 2); + + std::cout << "done" << std::endl; +} + +void test_needles_and_caps(const char* fname) +{ + std::cout << "test needles&caps..."; + + namespace PMP = CGAL::Polygon_mesh_processing; + + typedef boost::graph_traits::halfedge_descriptor halfedge_descriptor; + typedef boost::graph_traits::face_iterator face_iterator; + typedef boost::graph_traits::face_descriptor face_descriptor; + + std::ifstream input(fname); + Surface_mesh mesh; + if (!input || !(input >> mesh) || mesh.is_empty()) { + std::cerr << fname << " is not a valid off file.\n"; + std::exit(1); + } + + const FT eps = std::numeric_limits::epsilon(); + + face_iterator fit, fend; + boost::tie(fit, fend) = faces(mesh); + + // (0 0 0) -- (1 0 0) -- (1 1 0) (90° cap angle) + face_descriptor f = *fit; + halfedge_descriptor res = PMP::is_needle_triangle_face(f, mesh, 2/*needle_threshold*/); + assert(res == boost::graph_traits::null_halfedge()); // not a needle + res = PMP::is_needle_triangle_face(f, mesh, CGAL::sqrt(FT(2) - eps)/*needle_threshold*/); + assert(res != boost::graph_traits::null_halfedge()); // is a needle + + res = PMP::is_cap_triangle_face(f, mesh, 0./*cos(pi/2)*/); + assert(mesh.point(target(res, mesh)) == CGAL::ORIGIN); + res = PMP::is_cap_triangle_face(f, mesh, std::cos(91 * CGAL_PI / 180)); + assert(res == boost::graph_traits::null_halfedge()); + res = PMP::is_cap_triangle_face(f, mesh, std::cos(2 * CGAL_PI / 3)); + assert(res == boost::graph_traits::null_halfedge()); + ++ fit; + + // (0 0 1) -- (1 0 1) -- (10 10 1) + f = *fit; + res = PMP::is_needle_triangle_face(f, mesh, 20); + assert(res == boost::graph_traits::null_halfedge()); + res = PMP::is_needle_triangle_face(f, mesh, 10 * CGAL::sqrt(FT(2) - eps)); + assert(mesh.point(target(res, mesh)) == Point_3(1,0,1)); + res = PMP::is_needle_triangle_face(f, mesh, 1); + assert(mesh.point(target(res, mesh)) == Point_3(1,0,1)); + + res = PMP::is_cap_triangle_face(f, mesh, 0./*cos(pi/2)*/); + assert(mesh.point(target(res, mesh)) == Point_3(0,0,1)); + res = PMP::is_cap_triangle_face(f, mesh, std::cos(2 * CGAL_PI / 3)); + assert(mesh.point(target(res, mesh)) == Point_3(0,0,1)); + res = PMP::is_cap_triangle_face(f, mesh, std::cos(0.75 * CGAL_PI)); + assert(res == boost::graph_traits::null_halfedge()); + ++ fit; + + // (0 0 2) -- (1 0 2) -- (-0.99619469809 0.08715574274 2) (175° cap angle) + f = *fit; + res = PMP::is_needle_triangle_face(f, mesh, 2); + assert(res == boost::graph_traits::null_halfedge()); + res = PMP::is_needle_triangle_face(f, mesh, 1.9); + assert(mesh.point(target(res, mesh)) == Point_3(0,0,2) || + mesh.point(target(res, mesh)) == Point_3(1,0,2)); + res = PMP::is_needle_triangle_face(f, mesh, 1); + assert(mesh.point(target(res, mesh)) == Point_3(0,0,2) || + mesh.point(target(res, mesh)) == Point_3(1,0,2)); + + res = PMP::is_cap_triangle_face(f, mesh, 0./*cos(pi/2)*/); + assert(res != boost::graph_traits::null_halfedge() && + mesh.point(target(res, mesh)) != Point_3(0,0,2) && + mesh.point(target(res, mesh)) != Point_3(1,0,2)); + res = PMP::is_cap_triangle_face(f, mesh, std::cos(2 * CGAL_PI / 3)); + assert(res != boost::graph_traits::null_halfedge()); + res = PMP::is_cap_triangle_face(f, mesh, std::cos(175 * CGAL_PI / 180)); + assert(res != boost::graph_traits::null_halfedge()); + res = PMP::is_cap_triangle_face(f, mesh, std::cos(176 * CGAL_PI / 180)); + assert(res == boost::graph_traits::null_halfedge()); + + std::cout << "done" << std::endl; +} + +int main() +{ + check_edge_degeneracy("data_degeneracies/degtri_edge.off"); + check_triangle_face_degeneracy("data_degeneracies/degtri_four.off"); + test_vertex_non_manifoldness("data/blobby.off"); + test_vertices_merge_and_duplication("data/blobby.off"); + test_needles_and_caps("data_degeneracies/caps_and_needles.off"); + + return EXIT_SUCCESS; +} diff --git a/Polyhedron/demo/Polyhedron/MainWindow.cpp b/Polyhedron/demo/Polyhedron/MainWindow.cpp index 9075e0574a7..f9e35196b9a 100644 --- a/Polyhedron/demo/Polyhedron/MainWindow.cpp +++ b/Polyhedron/demo/Polyhedron/MainWindow.cpp @@ -1468,7 +1468,7 @@ void MainWindow::readSettings() CGAL::Three::Three::s_defaultSMRM = CGAL::Three::Three::modeFromName( settings.value("default_sm_rm", "flat+edges").toString()); CGAL::Three::Three::s_defaultPSRM = CGAL::Three::Three::modeFromName( - settings.value("default_ps_rm", "points").toString()); + settings.value("default_ps_rm", "shaded points").toString()); // read plugin blacklist QStringList blacklist=settings.value("plugin_blacklist",QStringList()).toStringList(); Q_FOREACH(QString name,blacklist){ plugin_blacklist.insert(name); } diff --git a/Polyhedron/demo/Polyhedron/Plugins/Classification/Cluster_classification.cpp b/Polyhedron/demo/Polyhedron/Plugins/Classification/Cluster_classification.cpp index 5aca25e2ed1..d8e20fd778f 100644 --- a/Polyhedron/demo/Polyhedron/Plugins/Classification/Cluster_classification.cpp +++ b/Polyhedron/demo/Polyhedron/Plugins/Classification/Cluster_classification.cpp @@ -541,8 +541,13 @@ void Cluster_classification::compute_features (std::size_t nb_scales) std::cerr << "Computing pointwise features with " << nb_scales << " scale(s)" << std::endl; m_features.clear(); + Point_set::Vector_map normal_map; bool normals = m_points->point_set()->has_normal_map(); + if (normals) + normal_map = m_points->point_set()->normal_map(); + bool colors = (m_color != Point_set::Property_map()); + Point_set::Property_map echo_map; bool echo; boost::tie (echo_map, echo) = m_points->point_set()->template property_map("echo"); @@ -562,7 +567,7 @@ void Cluster_classification::compute_features (std::size_t nb_scales) generator.generate_point_based_features(pointwise_features); if (normals) - generator.generate_normal_based_features (pointwise_features, m_points->point_set()->normal_map()); + generator.generate_normal_based_features (pointwise_features, normal_map); if (colors) generator.generate_color_based_features (pointwise_features, m_color); if (echo) diff --git a/Polyhedron/demo/Polyhedron/Plugins/Classification/Point_set_item_classification.cpp b/Polyhedron/demo/Polyhedron/Plugins/Classification/Point_set_item_classification.cpp index 69e5451bbbd..1096fe5d067 100644 --- a/Polyhedron/demo/Polyhedron/Plugins/Classification/Point_set_item_classification.cpp +++ b/Polyhedron/demo/Polyhedron/Plugins/Classification/Point_set_item_classification.cpp @@ -442,8 +442,13 @@ void Point_set_item_classification::compute_features (std::size_t nb_scales) std::cerr << "Computing features with " << nb_scales << " scale(s)" << std::endl; m_features.clear(); + Point_set::Vector_map normal_map; bool normals = m_points->point_set()->has_normal_map(); + if (normals) + normal_map = m_points->point_set()->normal_map(); + bool colors = (m_color != Point_set::Property_map()); + Point_set::Property_map echo_map; bool echo; boost::tie (echo_map, echo) = m_points->point_set()->template property_map("echo"); @@ -461,7 +466,7 @@ void Point_set_item_classification::compute_features (std::size_t nb_scales) m_generator->generate_point_based_features(m_features); if (normals) - m_generator->generate_normal_based_features (m_features, m_points->point_set()->normal_map()); + m_generator->generate_normal_based_features (m_features, normal_map); if (colors) m_generator->generate_color_based_features (m_features, m_color); if (echo) diff --git a/Polyhedron/demo/Polyhedron/Plugins/PCA/Affine_transform_plugin.cpp b/Polyhedron/demo/Polyhedron/Plugins/PCA/Affine_transform_plugin.cpp index 785d65733a1..e6f28c124f4 100644 --- a/Polyhedron/demo/Polyhedron/Plugins/PCA/Affine_transform_plugin.cpp +++ b/Polyhedron/demo/Polyhedron/Plugins/PCA/Affine_transform_plugin.cpp @@ -6,6 +6,7 @@ #include #include #include +#include #include "Scene_surface_mesh_item.h" #include "Scene_facegraph_transform_item.h" @@ -17,6 +18,7 @@ #include #include #include +#include #include #include #include @@ -25,7 +27,7 @@ using namespace CGAL::Three; typedef Viewer_interface Vi; typedef Point_container Pc; - +#include "ui_MeshOnGrid_dialog.h" typedef Scene_surface_mesh_item Facegraph_item; @@ -165,15 +167,20 @@ public: Polyhedron_demo_affine_transform_plugin():started(false){} QList actions() const { - return QList() << actionTransformPolyhedron; + return QList() << actionTransformPolyhedron + << actionMeshOnGrid; } - - bool applicable(QAction*) const { - return qobject_cast(scene->item(scene->mainSelectionIndex())) - || qobject_cast(scene->item(scene->mainSelectionIndex())) - || qobject_cast(scene->item(scene->mainSelectionIndex())) - || qobject_cast(scene->item(scene->mainSelectionIndex())) - ; + + bool applicable(QAction* a) const { + if(a == actionMeshOnGrid) + { + return qobject_cast(scene->item(scene->mainSelectionIndex())); + } + else + return qobject_cast(scene->item(scene->mainSelectionIndex())) + || qobject_cast(scene->item(scene->mainSelectionIndex())) + || qobject_cast(scene->item(scene->mainSelectionIndex())) + || qobject_cast(scene->item(scene->mainSelectionIndex())); } void init(QMainWindow* _mw, CGAL::Three::Scene_interface* scene_interface, Messages_interface*) { @@ -186,6 +193,12 @@ public: mw = _mw; this->scene = scene_interface; + actionMeshOnGrid = new QAction( + tr("Create a Grid of Surface Meshes") + , mw); + if(actionMeshOnGrid) { + connect(actionMeshOnGrid, SIGNAL(triggered()),this, SLOT(grid())); + } actionTransformPolyhedron = new QAction( tr("Affine Transformation") @@ -235,10 +248,10 @@ public: } private: - QDockWidget* dock_widget; Ui::TransformationWidget ui; QAction* actionTransformPolyhedron; + QAction* actionMeshOnGrid; Scene_facegraph_transform_item* transform_item; Scene_transform_point_set_item* transform_points_item; CGAL::Three::Scene_interface::Item_id tr_item_index; @@ -282,6 +295,7 @@ private: template void normalize(Item*); public Q_SLOTS: + void grid(); void go(); void transformed_killed(); @@ -364,6 +378,75 @@ public Q_SLOTS: }; // end class Polyhedron_demo_affine_transform_plugin +class GridDialog : + public QDialog, + public Ui::GridDialog +{ + Q_OBJECT +public: + GridDialog(QWidget* =0) + { + setupUi(this); + } +}; + +void Polyhedron_demo_affine_transform_plugin::grid() +{ + Facegraph_item* item = + qobject_cast(scene->item(scene->mainSelectionIndex())); + if(!item) + return; + + + FaceGraph m = *item->face_graph(); + + Scene_item::Bbox b = item->bbox(); + + + double x_t(CGAL::sqrt(CGAL::squared_distance(Kernel::Point_3(b.min(0), b.min(1), b.min(2)), + Kernel::Point_3(b.max(0), b.min(1), b.min(2))))), + y_t(CGAL::sqrt(CGAL::squared_distance(Kernel::Point_3(b.min(0), b.min(1), b.min(2)), + Kernel::Point_3(b.min(0), b.max(1), b.min(2))))), + z_t(CGAL::sqrt(CGAL::squared_distance(Kernel::Point_3(b.min(0), b.min(1), b.min(2)), + Kernel::Point_3(b.min(0), b.min(1), b.max(2))))); + + GridDialog dialog(mw); + dialog.x_space_doubleSpinBox->setValue(x_t); + dialog.y_space_doubleSpinBox->setValue(y_t); + dialog.z_space_doubleSpinBox->setValue(z_t); + if(!dialog.exec()) + return; + QApplication::setOverrideCursor(Qt::WaitCursor); + int i_max=dialog.x_spinBox->value(), + j_max=dialog.y_spinBox->value(), + k_max=dialog.z_spinBox->value(); + x_t = dialog.x_space_doubleSpinBox->value(); + y_t = dialog.y_space_doubleSpinBox->value(); + z_t = dialog.z_space_doubleSpinBox->value(); + + for(int i = 0; i < i_max; ++i) + { + for(int j = 0; j< j_max; ++j) + { + for(int k = 0; k< k_max; ++k) + { + FaceGraph e; + CGAL::copy_face_graph(m,e); + + Kernel::Aff_transformation_3 trans(CGAL::TRANSLATION, Kernel::Vector_3(i*x_t,j*y_t,k*z_t)); + CGAL::Polygon_mesh_processing::transform(trans, e); + Facegraph_item* t_item = new Facegraph_item(e); + t_item->setName(tr("%1 %2%3%4") + .arg(item->name()) + .arg(i) + .arg(j) + .arg(k)); + scene->addItem(t_item); + } + } + } + QApplication::restoreOverrideCursor(); +} void Polyhedron_demo_affine_transform_plugin::go(){ if (!started){ Scene_item* item = scene->item(scene->mainSelectionIndex()); diff --git a/Polyhedron/demo/Polyhedron/Plugins/PCA/CMakeLists.txt b/Polyhedron/demo/Polyhedron/Plugins/PCA/CMakeLists.txt index 75df6a2df8f..02660fb8bfd 100644 --- a/Polyhedron/demo/Polyhedron/Plugins/PCA/CMakeLists.txt +++ b/Polyhedron/demo/Polyhedron/Plugins/PCA/CMakeLists.txt @@ -2,7 +2,7 @@ include( polyhedron_demo_macros ) polyhedron_demo_plugin(pca_plugin Pca_plugin) target_link_libraries(pca_plugin PUBLIC scene_surface_mesh_item scene_points_with_normal_item scene_basic_objects) -qt5_wrap_ui( transformUI_FILES Transformation_widget.ui ) +qt5_wrap_ui( transformUI_FILES Transformation_widget.ui MeshOnGrid_dialog.ui) polyhedron_demo_plugin(affine_transform_plugin Affine_transform_plugin ${transformUI_FILES}) target_link_libraries(affine_transform_plugin PUBLIC scene_surface_mesh_item scene_transform_item scene_points_with_normal_item) diff --git a/Polyhedron/demo/Polyhedron/Plugins/PCA/MeshOnGrid_dialog.ui b/Polyhedron/demo/Polyhedron/Plugins/PCA/MeshOnGrid_dialog.ui new file mode 100644 index 00000000000..f4ae9f081f0 --- /dev/null +++ b/Polyhedron/demo/Polyhedron/Plugins/PCA/MeshOnGrid_dialog.ui @@ -0,0 +1,203 @@ + + + GridDialog + + + + 0 + 0 + 330 + 394 + + + + + 0 + 0 + + + + Dialog + + + + + + Along X + + + + + + 99999999999999999475366575191804932315794610450682175621941694731908308538307845136842752.000000000000000 + + + + + + + Spacing: + + + + + + + Number of items : + + + + + + + 999 + + + 2 + + + + + + + + + + Along Y + + + + + + 99999999999999999475366575191804932315794610450682175621941694731908308538307845136842752.000000000000000 + + + + + + + Spacing: + + + + + + + 999 + + + 2 + + + + + + + Number of items : + + + + + + + + + + Along Z + + + + + + 99999999999999999475366575191804932315794610450682175621941694731908308538307845136842752.000000000000000 + + + + + + + Number of items : + + + + + + + Spacing: + + + + + + + 999 + + + 2 + + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + Qt::Horizontal + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + + + + + + buttonBox + accepted() + GridDialog + accept() + + + 248 + 254 + + + 157 + 274 + + + + + buttonBox + rejected() + GridDialog + reject() + + + 316 + 260 + + + 286 + 274 + + + + + diff --git a/Polyhedron/demo/Polyhedron/Plugins/PMP/Degenerated_faces_plugin.cpp b/Polyhedron/demo/Polyhedron/Plugins/PMP/Degenerated_faces_plugin.cpp index df2a9d1cb48..0f8881c50de 100644 --- a/Polyhedron/demo/Polyhedron/Plugins/PMP/Degenerated_faces_plugin.cpp +++ b/Polyhedron/demo/Polyhedron/Plugins/PMP/Degenerated_faces_plugin.cpp @@ -14,6 +14,8 @@ #include #include #include +#include + typedef Scene_surface_mesh_item Scene_facegraph_item; typedef Scene_facegraph_item::Face_graph Face_graph; using namespace CGAL::Three; @@ -71,14 +73,12 @@ template bool isDegen(Mesh* mesh, std::vector::face_descriptor> &out_faces) { typedef typename boost::graph_traits::face_descriptor FaceDescriptor; - typedef typename boost::property_map::type Vpm; - typedef typename boost::property_traits::value_type Point; - typedef typename CGAL::Kernel_traits::Kernel Kernel; + //filter non-triangle_faces BOOST_FOREACH(FaceDescriptor f, faces(*mesh)) { if(is_triangle(halfedge(f, *mesh), *mesh) - && is_degenerate_triangle_face(f, *mesh, get(boost::vertex_point, *mesh), Kernel()) ) + && CGAL::Polygon_mesh_processing::is_degenerate_triangle_face(f, *mesh) ) out_faces.push_back(f); } return !out_faces.empty(); diff --git a/Polyhedron/demo/Polyhedron/Plugins/PMP/Repair_polyhedron_plugin.cpp b/Polyhedron/demo/Polyhedron/Plugins/PMP/Repair_polyhedron_plugin.cpp index 56eae5f6f53..548cc110464 100644 --- a/Polyhedron/demo/Polyhedron/Plugins/PMP/Repair_polyhedron_plugin.cpp +++ b/Polyhedron/demo/Polyhedron/Plugins/PMP/Repair_polyhedron_plugin.cpp @@ -56,7 +56,7 @@ public: actionStitchCloseBorderHalfedges->setProperty("subMenuName", "Polygon Mesh Processing/Repair/Experimental"); actionRemoveSelfIntersections->setProperty("subMenuName", "Polygon Mesh Processing/Repair/Experimental"); actionRemoveIsolatedVertices->setProperty("subMenuName", "Polygon Mesh Processing/Repair"); - actionDuplicateNMVertices->setProperty("subMenuName", "Polygon Mesh Processing/Repair/Experimental"); + actionDuplicateNMVertices->setProperty("subMenuName", "Polygon Mesh Processing/Repair"); actionAutorefine->setProperty("subMenuName", "Polygon Mesh Processing/Repair/Experimental"); actionAutorefineAndRMSelfIntersections->setProperty("subMenuName", "Polygon Mesh Processing/Repair/Experimental"); diff --git a/Polyhedron/demo/Polyhedron/Plugins/PMP/Selection_plugin.cpp b/Polyhedron/demo/Polyhedron/Plugins/PMP/Selection_plugin.cpp index 891013267bb..19f9e452ea0 100644 --- a/Polyhedron/demo/Polyhedron/Plugins/PMP/Selection_plugin.cpp +++ b/Polyhedron/demo/Polyhedron/Plugins/PMP/Selection_plugin.cpp @@ -23,6 +23,7 @@ #include #include #include +#include #include typedef Scene_surface_mesh_item Scene_face_graph_item; @@ -724,14 +725,10 @@ public Q_SLOTS: //Edition mode case 1: { - VPmap vpmap = get(CGAL::vertex_point, *selection_item->polyhedron()); bool is_valid = true; BOOST_FOREACH(boost::graph_traits::face_descriptor fd, faces(*selection_item->polyhedron())) { - if (CGAL::is_degenerate_triangle_face(fd, - *selection_item->polyhedron(), - vpmap, - CGAL::Kernel_traits< boost::property_traits::value_type >::Kernel())) + if (CGAL::Polygon_mesh_processing::is_degenerate_triangle_face(fd, *selection_item->polyhedron())) { is_valid = false; break; diff --git a/Polyhedron/demo/Polyhedron/Plugins/Point_set/Point_set_normal_estimation_plugin.cpp b/Polyhedron/demo/Polyhedron/Plugins/Point_set/Point_set_normal_estimation_plugin.cpp index 398f08f707d..ab53c6c887b 100644 --- a/Polyhedron/demo/Polyhedron/Plugins/Point_set/Point_set_normal_estimation_plugin.cpp +++ b/Polyhedron/demo/Polyhedron/Plugins/Point_set/Point_set_normal_estimation_plugin.cpp @@ -275,8 +275,8 @@ void Polyhedron_demo_point_set_normal_estimation_plugin::on_actionNormalEstimati << (memory>>20) << " Mb allocated" << std::endl; } - - item->setRenderingMode(PointsPlusNormals); + item->resetMenu(); + item->setRenderingMode(ShadedPoints); //*************************************** // normal orientation diff --git a/Polyhedron/demo/Polyhedron/Plugins/Point_set/Point_set_selection_plugin.cpp b/Polyhedron/demo/Polyhedron/Plugins/Point_set/Point_set_selection_plugin.cpp index 25c60ea8802..480efabd553 100644 --- a/Polyhedron/demo/Polyhedron/Plugins/Point_set/Point_set_selection_plugin.cpp +++ b/Polyhedron/demo/Polyhedron/Plugins/Point_set/Point_set_selection_plugin.cpp @@ -680,6 +680,7 @@ protected: // mouse events if(shift_pressing && event->type() == QEvent::MouseButtonPress) { + background = static_cast(*CGAL::QGLViewer::QGLViewerPool().begin())->grabFramebuffer(); QMouseEvent *mouseEvent = static_cast(event); Viewer_interface* viewer = qobject_cast( Three::mainWindow()->childAt(QCursor::pos())); diff --git a/Polyhedron/demo/Polyhedron/Plugins/Point_set/Point_set_shape_detection_plugin.cpp b/Polyhedron/demo/Polyhedron/Plugins/Point_set/Point_set_shape_detection_plugin.cpp index 32a40d64702..6ee00f2e52f 100644 --- a/Polyhedron/demo/Polyhedron/Plugins/Point_set/Point_set_shape_detection_plugin.cpp +++ b/Polyhedron/demo/Polyhedron/Plugins/Point_set/Point_set_shape_detection_plugin.cpp @@ -357,6 +357,7 @@ private: ++ nb_colored_pts; colored_item->point_set()->set_color(*it, r, g, b); } + colored_item->invalidateOpenGLBuffers(); } // Providing a useful name consisting of the order of detection, name of type and number of inliers @@ -399,27 +400,28 @@ private: ss << "(" << ref << ")_"; if (dialog.generate_alpha ()) - { - // If plane, build alpha shape - Scene_surface_mesh_item* sm_item = NULL; - sm_item = new Scene_surface_mesh_item; + { + // If plane, build alpha shape + Scene_surface_mesh_item* sm_item = NULL; + sm_item = new Scene_surface_mesh_item; + + + build_alpha_shape (*(point_item->point_set()), pshape, + sm_item, dialog.cluster_epsilon()); + + if(sm_item){ + sm_item->setColor(point_item->color ()); + sm_item->setName(QString("%1%2_alpha_shape").arg(QString::fromStdString(ss.str())) + .arg (QString::number (shape->indices_of_assigned_points().size()))); + sm_item->setRenderingMode (Flat); - - build_alpha_shape (*(point_item->point_set()), pshape, - sm_item, dialog.cluster_epsilon()); - if(sm_item){ - sm_item->setColor(point_item->color ()); - sm_item->setName(QString("%1%2_alpha_shape").arg(QString::fromStdString(ss.str())) - .arg (QString::number (shape->indices_of_assigned_points().size()))); - sm_item->setRenderingMode (Flat); - - scene->addItem(sm_item); - if(scene->item_id(groups[0]) == -1) - scene->addItem(groups[0]); - scene->changeGroup(sm_item, groups[0]); - } + scene->addItem(sm_item); + if(scene->item_id(groups[0]) == -1) + scene->addItem(groups[0]); + scene->changeGroup(sm_item, groups[0]); } - } + } + } else if (dynamic_cast *>(shape.get())) ss << item->name().toStdString() << "_cone_"; else if (dynamic_cast *>(shape.get())) @@ -435,6 +437,7 @@ private: point_item->setRenderingMode(item->renderingMode()); if (dialog.generate_subset()){ + point_item->invalidateOpenGLBuffers(); scene->addItem(point_item); if (dynamic_cast *>(shape.get())) { @@ -452,6 +455,7 @@ private: if(scene->item_id(groups[0]) == -1) scene->addItem(groups[0]); + point_item->invalidateOpenGLBuffers(); scene->changeGroup(point_item, groups[0]); } else if (dynamic_cast *>(shape.get())) @@ -506,6 +510,7 @@ private: pts_full->setName(tr("%1 (structured)").arg(item->name())); pts_full->setRenderingMode(PointsPlusNormals); pts_full->setColor(Qt::blue); + pts_full->invalidateOpenGLBuffers(); scene->addItem (pts_full); } std::cerr << "done" << std::endl; diff --git a/Polyhedron/demo/Polyhedron/Plugins/Point_set/Surface_reconstruction_plugin.cpp b/Polyhedron/demo/Polyhedron/Plugins/Point_set/Surface_reconstruction_plugin.cpp index f1ee63304a7..1cdd134fd57 100644 --- a/Polyhedron/demo/Polyhedron/Plugins/Point_set/Surface_reconstruction_plugin.cpp +++ b/Polyhedron/demo/Polyhedron/Plugins/Point_set/Surface_reconstruction_plugin.cpp @@ -865,7 +865,6 @@ private: local_timer.start(); Priority_with_structure_coherence priority (structuring, 10. * op.cluster_epsilon); - Scene_surface_mesh_item* reco_item = new Scene_surface_mesh_item(SMesh()); SMesh& P = * const_cast(reco_item->polyhedron()); Construct construct(P,structured->point_set()->points().begin(),structured->point_set()->points().end()); @@ -881,7 +880,6 @@ private: reco_item->setColor(Qt::magenta); reco_item->setRenderingMode(FlatPlusEdges); scene->addItem(reco_item); - if (dialog.generate_structured ()) { structured->setName(tr("%1 (structured)").arg(point_set_item->name())); @@ -1050,7 +1048,6 @@ void Polyhedron_demo_surface_reconstruction_plugin::automatic_reconstruction { std::cerr << "Advancing front reconstruction... "; time.restart(); - Scene_surface_mesh_item* reco_item = new Scene_surface_mesh_item(SMesh()); SurfaceReconstruction::advancing_front (*points, reco_item, 10. * (std::max)(noise_size, aniso_size)); @@ -1059,8 +1056,8 @@ void Polyhedron_demo_surface_reconstruction_plugin::automatic_reconstruction reco_item->setRenderingMode(FlatPlusEdges); scene->addItem(reco_item); std::cerr << "ok (" << time.elapsed() << " ms)" << std::endl; + } - } else { @@ -1068,7 +1065,6 @@ void Polyhedron_demo_surface_reconstruction_plugin::automatic_reconstruction { std::cerr << "Advancing front reconstruction... "; time.restart(); - Scene_surface_mesh_item* reco_item = new Scene_surface_mesh_item(SMesh()); SurfaceReconstruction::advancing_front (*points, reco_item, 10. * (std::max)(noise_size, aniso_size)); @@ -1077,7 +1073,6 @@ void Polyhedron_demo_surface_reconstruction_plugin::automatic_reconstruction reco_item->setRenderingMode(FlatPlusEdges); scene->addItem(reco_item); - std::cerr << "ok (" << time.elapsed() << " ms)" << std::endl; } else @@ -1097,13 +1092,12 @@ void Polyhedron_demo_surface_reconstruction_plugin::automatic_reconstruction std::cerr << "Poisson reconstruction... "; time.restart(); - SMesh* smRemesh = NULL; - - smRemesh = poisson_reconstruct_sm(*points, - 20, - 100 * (std::max)(noise_size, aniso_size), - (std::max)(noise_size, aniso_size), - QString ("Eigen - built-in CG"), false, false); + SMesh* smRemesh = + poisson_reconstruct_sm(*points, + 20, + 100 * (std::max)(noise_size, aniso_size), + (std::max)(noise_size, aniso_size), + QString ("Eigen - built-in CG"), false, false); if(smRemesh) { // Add polyhedron to scene @@ -1160,6 +1154,7 @@ void Polyhedron_demo_surface_reconstruction_plugin::advancing_front_reconstructi reco_item->setColor(Qt::lightGray); reco_item->setRenderingMode(FlatPlusEdges); scene->addItem(reco_item); + QApplication::restoreOverrideCursor(); } } diff --git a/Polyhedron/demo/Polyhedron/Plugins/Surface_mesh_deformation/Edit_polyhedron_plugin.cpp b/Polyhedron/demo/Polyhedron/Plugins/Surface_mesh_deformation/Edit_polyhedron_plugin.cpp index 9e40568de7e..be392346bc7 100644 --- a/Polyhedron/demo/Polyhedron/Plugins/Surface_mesh_deformation/Edit_polyhedron_plugin.cpp +++ b/Polyhedron/demo/Polyhedron/Plugins/Surface_mesh_deformation/Edit_polyhedron_plugin.cpp @@ -5,6 +5,7 @@ #include "Scene_edit_polyhedron_item.h" #include "Scene_polyhedron_selection_item.h" #include +#include #include #include #include @@ -392,10 +393,7 @@ void Polyhedron_demo_edit_polyhedron_plugin::dock_widget_visibility_changed(bool bool is_valid = true; BOOST_FOREACH(boost::graph_traits::face_descriptor fd, faces(*poly_item->face_graph())) { - if (CGAL::is_degenerate_triangle_face(fd, - *poly_item->face_graph(), - get(boost::vertex_point, - *poly_item->face_graph()), EPICK())) + if (CGAL::Polygon_mesh_processing::is_degenerate_triangle_face(fd, *poly_item->face_graph())) { is_valid = false; break; diff --git a/Polyhedron/demo/Polyhedron/Scene_group_item.cpp b/Polyhedron/demo/Polyhedron/Scene_group_item.cpp index c35335b93f4..4879cc5d191 100644 --- a/Polyhedron/demo/Polyhedron/Scene_group_item.cpp +++ b/Polyhedron/demo/Polyhedron/Scene_group_item.cpp @@ -30,7 +30,21 @@ bool Scene_group_item::isEmpty() const { Scene_group_item::Bbox Scene_group_item::bbox() const { - return Bbox(0, 0, 0, 0, 0,0); + Scene_item* first_non_empty = nullptr; + Q_FOREACH(Scene_interface::Item_id id, children) + if(!getChild(id)->isEmpty()) + { + first_non_empty = getChild(id); + } + + if(first_non_empty) + { + Bbox b =first_non_empty->bbox(); + Q_FOREACH(Scene_interface::Item_id id, children) + b+=getChild(id)->bbox(); + return b; + } + return Bbox(0,0,0,0,0,0); } diff --git a/Polyhedron/demo/Polyhedron/Scene_item.cpp b/Polyhedron/demo/Polyhedron/Scene_item.cpp index ce7b0a53370..7093872e5e3 100644 --- a/Polyhedron/demo/Polyhedron/Scene_item.cpp +++ b/Polyhedron/demo/Polyhedron/Scene_item.cpp @@ -112,6 +112,11 @@ QMenu* CGAL::Three::Scene_item::contextMenu() return defaultContextMenu; } +void CGAL::Three::Scene_item::resetMenu() +{ + delete defaultContextMenu; + defaultContextMenu = nullptr; +} CGAL::Three::Scene_group_item* CGAL::Three::Scene_item::parentGroup() const { return parent_group; } diff --git a/Polyhedron/demo/Polyhedron/Scene_points_with_normal_item.cpp b/Polyhedron/demo/Polyhedron/Scene_points_with_normal_item.cpp index 37fc7aace4c..9a3f7c866db 100644 --- a/Polyhedron/demo/Polyhedron/Scene_points_with_normal_item.cpp +++ b/Polyhedron/demo/Polyhedron/Scene_points_with_normal_item.cpp @@ -251,7 +251,6 @@ Scene_points_with_normal_item::Scene_points_with_normal_item(const SMesh& input_ invalidateOpenGLBuffers(); } - Scene_points_with_normal_item::~Scene_points_with_normal_item() { delete d; @@ -558,7 +557,7 @@ bool Scene_points_with_normal_item::read_las_point_set(std::istream& stream) !isEmpty(); std::cerr << d->m_points->info(); - + if (!d->m_points->has_normal_map()) { setRenderingMode(Points); diff --git a/Polyhedron/demo/Polyhedron/Scene_polyhedron_selection_item.cpp b/Polyhedron/demo/Polyhedron/Scene_polyhedron_selection_item.cpp index 208c7db84ef..3b888ab5fd7 100644 --- a/Polyhedron/demo/Polyhedron/Scene_polyhedron_selection_item.cpp +++ b/Polyhedron/demo/Polyhedron/Scene_polyhedron_selection_item.cpp @@ -2,6 +2,7 @@ #include "Scene_polyhedron_selection_item.h" #include #include +#include #include #include #include @@ -1868,8 +1869,9 @@ bool Scene_polyhedron_selection_item_priv::canAddFace(fg_halfedge_descriptor hc, found = true; fg_halfedge_descriptor res = CGAL::Euler::add_face_to_border(t,hc, *item->polyhedron()); + fg_face_descriptor resf = face(res, *item->polyhedron()); - if(CGAL::is_degenerate_triangle_face(res, *item->polyhedron(), get(CGAL::vertex_point, *item->polyhedron()), EPICK())) + if(CGAL::Polygon_mesh_processing::is_degenerate_triangle_face(resf, *item->polyhedron())) { CGAL::Euler::remove_face(res, *item->polyhedron()); tempInstructions("Edge not selected : resulting facet is degenerated.", diff --git a/Polyhedron/demo/Polyhedron/Scene_polyhedron_selection_item.h b/Polyhedron/demo/Polyhedron/Scene_polyhedron_selection_item.h index 7faa8973911..1c67a7e6f8f 100644 --- a/Polyhedron/demo/Polyhedron/Scene_polyhedron_selection_item.h +++ b/Polyhedron/demo/Polyhedron/Scene_polyhedron_selection_item.h @@ -218,7 +218,7 @@ public: bool printVertexIds() const; bool printEdgeIds() const; bool printFaceIds() const; - void printAllIds(CGAL::Three::Viewer_interface*); + void printAllIds(); bool testDisplayId(double, double, double, CGAL::Three::Viewer_interface*)const; bool shouldDisplayIds(CGAL::Three::Scene_item *current_item) const; QString defaultSaveName() const diff --git a/Polyhedron/demo/Polyhedron/Scene_surface_mesh_item.cpp b/Polyhedron/demo/Polyhedron/Scene_surface_mesh_item.cpp index 706592494f3..0709a156d7a 100644 --- a/Polyhedron/demo/Polyhedron/Scene_surface_mesh_item.cpp +++ b/Polyhedron/demo/Polyhedron/Scene_surface_mesh_item.cpp @@ -28,6 +28,7 @@ #include #include #include +#include #include #include #include "triangulate_primitive.h" @@ -838,9 +839,6 @@ void Scene_surface_mesh_item_priv::triangulate_convex_facet(face_descriptor fd, Scene_item_rendering_helper::Gl_data_names name, bool index) const { - const CGAL::qglviewer::Vec v_offset = static_cast(CGAL::QGLViewer::QGLViewerPool().first())->offset(); - EPICK::Vector_3 offset = EPICK::Vector_3(v_offset.x, v_offset.y, v_offset.z); - Point p0,p1,p2; SMesh::Halfedge_around_face_circulator he(halfedge(fd, *smesh_), *smesh_); SMesh::Halfedge_around_face_circulator he_end = he; @@ -851,9 +849,9 @@ void Scene_surface_mesh_item_priv::triangulate_convex_facet(face_descriptor fd, vertex_descriptor v0(target(*he_end, *smesh_)), v1(target(*he, *smesh_)), v2(target(next(*he, *smesh_), *smesh_)); - p0 = smesh_->point(v0) + offset; - p1 = smesh_->point(v1) + offset; - p2 = smesh_->point(v2) + offset; + p0 = smesh_->point(v0); + p1 = smesh_->point(v1); + p2 = smesh_->point(v2); if(!index) { CGAL::Color* color; @@ -1076,7 +1074,7 @@ void* Scene_surface_mesh_item_priv::get_aabb_tree() BOOST_FOREACH( face_descriptor f, faces(*sm)) { //if face is degenerate, skip it - if (CGAL::is_degenerate_triangle_face(f, *sm, get(CGAL::vertex_point, *sm), EPICK())) + if (CGAL::Polygon_mesh_processing::is_degenerate_triangle_face(f, *sm)) continue; //if face not triangle, triangulate corresponding primitive before adding it to the tree if(!CGAL::is_triangle(halfedge(f, *sm), *sm)) @@ -1562,7 +1560,7 @@ QString Scene_surface_mesh_item::computeStats(int type) if(is_triangle_mesh(*d->smesh_)) { if (d->number_of_degenerated_faces == (unsigned int)(-1)) - d->number_of_degenerated_faces = nb_degenerate_faces(d->smesh_, get(CGAL::vertex_point, *(d->smesh_))); + d->number_of_degenerated_faces = nb_degenerate_faces(d->smesh_); return QString::number(d->number_of_degenerated_faces); } else diff --git a/Polyhedron/demo/Polyhedron/cgal_test_with_cmake b/Polyhedron/demo/Polyhedron/cgal_test_with_cmake index 740946b6ccc..0b7ad915e26 100755 --- a/Polyhedron/demo/Polyhedron/cgal_test_with_cmake +++ b/Polyhedron/demo/Polyhedron/cgal_test_with_cmake @@ -26,7 +26,7 @@ configure() { echo "Configuring... " - if eval 'cmake --no-warn-unused-cli "$CMAKE_GENERATOR" -DRUNNING_CGAL_AUTO_TEST=TRUE \ + if eval 'cmake --no-warn-unused-cli ${INIT_FILE:+"-C${INIT_FILE}"} "$CMAKE_GENERATOR" -DRUNNING_CGAL_AUTO_TEST=TRUE \ -DCGAL_DIR="$CGAL_DIR" \ .' ; then diff --git a/Polyhedron/demo/Polyhedron/include/CGAL/statistics_helpers.h b/Polyhedron/demo/Polyhedron/include/CGAL/statistics_helpers.h index e87c838848f..d0449e819b5 100644 --- a/Polyhedron/demo/Polyhedron/include/CGAL/statistics_helpers.h +++ b/Polyhedron/demo/Polyhedron/include/CGAL/statistics_helpers.h @@ -1,7 +1,8 @@ #ifndef POLYHEDRON_DEMO_STATISTICS_HELPERS_H #define POLYHEDRON_DEMO_STATISTICS_HELPERS_H -#include +#include +#include #include #include @@ -9,10 +10,13 @@ #include #include #include -#include -#include #include +#include +#include +#include +#include +#include template void angles(Mesh* poly, double& mini, double& maxi, double& ave) @@ -81,19 +85,15 @@ void edges_length(Mesh* poly, mid = extract_result< tag::median >(acc); } -template -unsigned int nb_degenerate_faces(Mesh* poly, VPmap vpmap) +template +unsigned int nb_degenerate_faces(Mesh* poly) { typedef typename boost::graph_traits::face_descriptor face_descriptor; - typedef typename CGAL::Kernel_traits< typename boost::property_traits::value_type >::Kernel Traits; - unsigned int nb = 0; - BOOST_FOREACH(face_descriptor f, faces(*poly)) - { - if (CGAL::is_degenerate_triangle_face(f, *poly, vpmap, Traits())) - ++nb; - } - return nb; + std::vector degenerate_faces; + CGAL::Polygon_mesh_processing::degenerate_faces(*poly, std::back_inserter(degenerate_faces)); + + return static_cast(degenerate_faces.size()); } template diff --git a/Property_map/include/CGAL/property_map.h b/Property_map/include/CGAL/property_map.h index d8610c0f4dd..c38061b11a2 100644 --- a/Property_map/include/CGAL/property_map.h +++ b/Property_map/include/CGAL/property_map.h @@ -463,10 +463,11 @@ make_property_map(const std::vector& v) template struct Constant_property_map { - const ValueType default_value; + ValueType default_value; typedef KeyType key_type; typedef ValueType value_type; + typedef value_type& reference; typedef boost::read_write_property_map_tag category; Constant_property_map(const value_type& default_value = value_type()) : default_value (default_value) { } diff --git a/Scripts/developer_scripts/Bundle_polyhedron_demo_with_appimage.sh b/Scripts/developer_scripts/Bundle_polyhedron_demo_with_appimage.sh new file mode 100644 index 00000000000..e2911620838 --- /dev/null +++ b/Scripts/developer_scripts/Bundle_polyhedron_demo_with_appimage.sh @@ -0,0 +1,8 @@ +#!/bin/bash +if [ "$1" == '--help' ]; then + echo "Usage: $0 " + echo "Builds and packages the Polyhedron demo form the CGAL dir." + exit 0 +fi +docker run --rm -v "$2":/results:Z -v "$1":/cgal:ro docker.io/cgal/bundle-3d-demo "/scripts/build.sh -j$3 && /scripts/deploy.sh" + diff --git a/Scripts/developer_scripts/autotest_cgal b/Scripts/developer_scripts/autotest_cgal index 27ae791e4ce..848566200f7 100755 --- a/Scripts/developer_scripts/autotest_cgal +++ b/Scripts/developer_scripts/autotest_cgal @@ -1,4 +1,4 @@ -#!/bin/sh +#!/bin/bash # ---------------------------------------------------- # ---------------------------------------------------- # autotest_cgal: a script to automagically install and @@ -525,7 +525,7 @@ export MAKE_CMD; export CGAL_BINARY_DIR; export CGAL_REFERENCE_CACHE_DIR; cd '${CGAL_BINARY_DIR}'; -cmake '${CMAKE_GENERATOR}' -DRUNNING_CGAL_AUTO_TEST=TRUE \\ +cmake \${INIT_FILE:+"-C\${INIT_FILE}"} '${CMAKE_GENERATOR}' -DRUNNING_CGAL_AUTO_TEST=TRUE \\ -DCGAL_REFERENCE_CACHE_DIR="\$CGAL_REFERENCE_CACHE_DIR" \\ VERBOSE=1 \\ ../../..; diff --git a/Scripts/developer_scripts/cgal_create_release_with_cmake.cmake b/Scripts/developer_scripts/cgal_create_release_with_cmake.cmake index db6119a6bf5..b9c40f0ebc6 100644 --- a/Scripts/developer_scripts/cgal_create_release_with_cmake.cmake +++ b/Scripts/developer_scripts/cgal_create_release_with_cmake.cmake @@ -1,4 +1,5 @@ #option : +# GIT_REPO the path to the Git repository, default is the current working directory # DESTINATION the path where the release is created, default is /tmp # PUBLIC=[ON/OFF] indicates if a public release should be built, default is OFF # VERBOSE=[ON/OFF] makes the script more verbose, default is OFF @@ -7,11 +8,15 @@ # CGAL_VERSION_NR=release string used to update version.h. Must be something like 1041200033 , or 104120090 # TESTSUITE=indicate if the release is meant to be used by the testsuite, default if OFF -if (NOT EXISTS ${CMAKE_BINARY_DIR}/Installation/include/CGAL/version.h) +if (NOT GIT_REPO) + set(GIT_REPO ${CMAKE_BINARY_DIR}) +endif() + +if (NOT EXISTS ${GIT_REPO}/Installation/include/CGAL/version.h) message(FATAL_ERROR "Cannot find Installation/include/CGAL/version.h. Make sure you are at the root of a CGAL branch") endif() -file(READ "${CMAKE_BINARY_DIR}/Installation/include/CGAL/version.h" version_file_content) +file(READ "${GIT_REPO}/Installation/include/CGAL/version.h" version_file_content) string(REGEX MATCH "define CGAL_VERSION (.*)\n#define CGAL_VERSION_NR" CGAL_VERSION_FOUND "${version_file_content}") if (CGAL_VERSION_FOUND) @@ -41,10 +46,10 @@ else() endif() file(MAKE_DIRECTORY "${release_dir}") -file(GLOB files RELATIVE ${CMAKE_BINARY_DIR} ${CMAKE_BINARY_DIR}/*) +file(GLOB files RELATIVE ${GIT_REPO} ${GIT_REPO}/*) foreach(pkg ${files}) - set(pkg_dir ${CMAKE_BINARY_DIR}/${pkg}) # use absolute path + set(pkg_dir ${GIT_REPO}/${pkg}) # use absolute path if(IS_DIRECTORY ${pkg_dir} AND (NOT "${pkg}" STREQUAL "Maintenance") AND (EXISTS ${pkg_dir}/package_info OR "${pkg}" STREQUAL "Documentation" @@ -73,9 +78,9 @@ foreach(pkg ${files}) if ("${fext}" STREQUAL ".h" OR "${fext}" STREQUAL ".hpp") file(READ "${pkg_dir}/${f}" file_content) string(REPLACE "$URL$" "$URL: ${GITHUB_PREFIX}/${pkg}/${f} $" file_content "${file_content}") - if(EXISTS ${CMAKE_BINARY_DIR}/.git) + if(EXISTS ${GIT_REPO}/.git) execute_process( - COMMAND git --git-dir=${CMAKE_BINARY_DIR}/.git --work-tree=${CMAKE_BINARY_DIR} log -n1 "--format=format:%h %aI %an" -- "${pkg}/${f}" + COMMAND git --git-dir=${GIT_REPO}/.git --work-tree=${GIT_REPO} log -n1 "--format=format:%h %aI %an" -- "${pkg}/${f}" RESULT_VARIABLE RESULT_VAR OUTPUT_VARIABLE OUT_VAR ) @@ -91,7 +96,7 @@ foreach(pkg ${files}) endforeach() if (EXISTS "${release_dir}/doc/${pkg}") #generate filelist.txt used by doxygen ran on a release - file(GLOB_RECURSE includes LIST_DIRECTORIES false RELATIVE "${CMAKE_BINARY_DIR}/${pkg}/include" "${CMAKE_BINARY_DIR}/${pkg}/include/CGAL/*.h") + file(GLOB_RECURSE includes LIST_DIRECTORIES false RELATIVE "${GIT_REPO}/${pkg}/include" "${GIT_REPO}/${pkg}/include/CGAL/*.h") foreach(f ${includes}) file(APPEND "${release_dir}/doc/${pkg}/filelist.txt" "${f}\n") endforeach() @@ -109,9 +114,9 @@ file(WRITE ${release_dir}/VERSION "${CGAL_VERSION}") #edit include/CGAL/version.h file(READ "${release_dir}/include/CGAL/version.h" file_content) # update CGAL_GIT_HASH -if(EXISTS ${CMAKE_BINARY_DIR}/.git) +if(EXISTS ${GIT_REPO}/.git) execute_process( - COMMAND git rev-parse HEAD + COMMAND git --git-dir=${GIT_REPO}/.git rev-parse HEAD RESULT_VARIABLE RESULT_VAR OUTPUT_VARIABLE OUT_VAR ) @@ -131,12 +136,29 @@ file(WRITE ${release_dir}/include/CGAL/version.h "${file_content}") # make an extra copy of examples and demos for the testsuite and generate # create_cgal_test_with_cmake for tests, demos, and examples if (TESTSUITE) + SET(FMT_ARG "format:SCM branch:%n%H %d%n%nShort log from master:%n") + execute_process( + COMMAND git --git-dir=${GIT_REPO}/.git --work-tree=${GIT_REPO} log -n1 --format=${FMT_ARG} + WORKING_DIRECTORY "${release_dir}" + OUTPUT_VARIABLE OUT_VAR + ) +#write result in .scm-branch + file(WRITE ${release_dir}/.scm-branch "${OUT_VAR}") + SET(FMT_ARG "%h %s%n parents: %p%n") + execute_process( + COMMAND git --git-dir=${GIT_REPO}/.git --work-tree=${GIT_REPO} log --first-parent --format=${FMT_ARG} cgal/master.. + WORKING_DIRECTORY "${release_dir}" + OUTPUT_VARIABLE OUT_VAR + ) +#append result in .scm-branch + file(APPEND ${release_dir}/.scm-branch "${OUT_VAR}") + file(GLOB tests RELATIVE "${release_dir}/test" "${release_dir}/test/*") foreach(d ${tests}) if(IS_DIRECTORY "${release_dir}/test/${d}") if(NOT EXISTS "${release_dir}/test/${d}/cgal_test_with_cmake") execute_process( - COMMAND ${CMAKE_BINARY_DIR}/Scripts/developer_scripts/create_cgal_test_with_cmake + COMMAND ${GIT_REPO}/Scripts/developer_scripts/create_cgal_test_with_cmake WORKING_DIRECTORY "${release_dir}/test/${d}" RESULT_VARIABLE RESULT_VAR OUTPUT_VARIABLE OUT_VAR @@ -162,7 +184,7 @@ if (TESTSUITE) file(RENAME "${release_dir}/tmp/${d}" "${release_dir}/test/${d}_Demo") if(NOT EXISTS "${release_dir}/test/${d}_Demo/cgal_test_with_cmake") execute_process( - COMMAND ${CMAKE_BINARY_DIR}/Scripts/developer_scripts/create_cgal_test_with_cmake --no-run + COMMAND ${GIT_REPO}/Scripts/developer_scripts/create_cgal_test_with_cmake --no-run WORKING_DIRECTORY "${release_dir}/test/${d}_Demo" RESULT_VARIABLE RESULT_VAR OUTPUT_VARIABLE OUT_VAR @@ -183,7 +205,7 @@ if (TESTSUITE) file(RENAME "${release_dir}/tmp/${d}" "${release_dir}/test/${d}_Examples") if(NOT EXISTS "${release_dir}/test/${d}_Examples/cgal_test_with_cmake") execute_process( - COMMAND ${CMAKE_BINARY_DIR}/Scripts/developer_scripts/create_cgal_test_with_cmake + COMMAND ${GIT_REPO}/Scripts/developer_scripts/create_cgal_test_with_cmake WORKING_DIRECTORY "${release_dir}/test/${d}_Examples" RESULT_VARIABLE RESULT_VAR OUTPUT_VARIABLE OUT_VAR @@ -195,7 +217,7 @@ if (TESTSUITE) endif() endforeach() file(REMOVE_RECURSE "${release_dir}/tmp") -endif() +endif() #TESTSUITE # removal of extra directories and files file(REMOVE_RECURSE ${release_dir}/benchmark) diff --git a/Scripts/developer_scripts/create_cgal_test b/Scripts/developer_scripts/create_cgal_test index b65d4b9c3fc..48296e17658 100755 --- a/Scripts/developer_scripts/create_cgal_test +++ b/Scripts/developer_scripts/create_cgal_test @@ -74,20 +74,20 @@ cat << EOF EOF header "configure" -cat << EOF +cat << 'EOF' configure() { echo "Configuring... " - if eval 'cmake "\$CMAKE_GENERATOR" -DRUNNING_CGAL_AUTO_TEST=TRUE \\ - -DCGAL_DIR="\$CGAL_DIR" \\ - --no-warn-unused-cli \\ + if eval 'cmake ${INIT_FILE:+"-C${INIT_FILE}"} "$CMAKE_GENERATOR" -DRUNNING_CGAL_AUTO_TEST=TRUE \ + -DCGAL_DIR="$CGAL_DIR" \ + --no-warn-unused-cli \ .' ; then - echo " successful configuration" >> \$ERRORFILE + echo " successful configuration" >> $ERRORFILE else - echo " ERROR: configuration" >> \$ERRORFILE + echo " ERROR: configuration" >> $ERRORFILE fi } diff --git a/Scripts/developer_scripts/create_new_release b/Scripts/developer_scripts/create_new_release index 055ac8c41fa..9f4ddc266df 100755 --- a/Scripts/developer_scripts/create_new_release +++ b/Scripts/developer_scripts/create_new_release @@ -5,7 +5,6 @@ # Radu Ursu, Sylvain Pion, 2004-2006. # TODO : -# - Use svn revision instead of separate internal release number ? # - Cleanup the public/internal separation: # - have CGAL_VERSION_NR be not affected by the internal version # - have CGAL_REVISION be the revision (replacing the internal number) @@ -13,45 +12,44 @@ # [new] : create_internal_release should not know about internal/public mode. # - Merge [some parts] into ./create_internal_release ? -DO_RPM="" # Also build RPMs (no RPMs by default) DO_PUBLIC="" # Also build the public versions -DO_IT="" # Real mode (svn tag, copy to HTTP server), versus local testing -DO_NOT_TAG="" # If set, do not call svn tag -DO_TAG="" # If set, svn tag is called anyway +DO_IT="" # Real mode (copy to HTTP server), versus local testing +DO_NOT_TAG="" # If set, do not call tag +DO_TAG="" # If set, tag is called anyway NO_TESTUITE="" # If set, the LATEST file is not updated NO_SCM="" # If set, git pull is not called. -SOURCES_DIR="$PWD/trunk" # SVN working copy directory, default is "$PWD/trunk" +SOURCES_DIR="$PWD" # Directory containing the sources, default is "$PWD" VERBOSE="" # Verbose mode (displays log to standard err) BETA="" #If set, will change the release number and version number accordingly. -SCM=svn +DESTINATION="/tmp" +IS_MASTER="y" SOURCES_DIR_HAS_BEEN_SET= -CANDIDATES_DIR_HAS_BEEN_SET= printerr() { echo "$@" >&2; } usage() { - printerr "Usage : $0 [--help] [--rpm] [--public] [--do-it] [--beta ] []" + printerr "Usage : $0 [--help] [--public] [--do-it] [--beta ] " printerr printerr ' --help : prints this usage help' - printerr ' --rpm : also build the corresponding SRPMs' printerr ' --public : also build the corresponding public versions' printerr ' --do-it : the real thing (NOT for local tests! Only for the release' printerr ' master! Does write operations (updating the version_number,' - printerr ' svn tag, copying on the web server...)' + printerr ' tag, copying on the web server...)' printerr ' --do-not-tag : when used with --do-it, the tag is not created.' printerr ' --tag : when used without --do-it, the tag is created, but files' printerr ' are not published' - printerr ' --no-scm-update : do not "svn update" or "git pull"' + printerr ' --no-scm-update : do not "git pull"' printerr ' --no-testsuite : when used with --do-it, the tag is made, files are published,' printerr ' but the LATEST file is not updated.' printerr ' --verbose : print log to standard output, instead of the log file' printerr ' --beta : followed by a number. When used with --public, will modify the release number and the release version name to include beta' + printerr ' --dest : followed by the path to where the release should be created. Default is /tmp.' + printerr ' --is_master : replace the Ic in the name by I.' printerr ' : the directory containing the packages [default is trunk]' - printerr ' : the directory containing the candidate packages [no default]' } @@ -62,12 +60,8 @@ while [ $1 ]; do usage; exit; ;; - --rpm) - DO_RPM="y" - shift; continue - ;; --public) - DO_PUBLIC="y" + DO_PUBLIC="ON" shift; continue ;; --do-it) @@ -91,7 +85,7 @@ while [ $1 ]; do shift; continue ;; --verbose) - VERBOSE="y" + VERBOSE="ON" shift; continue ;; --beta) @@ -104,6 +98,15 @@ while [ $1 ]; do shift; continue ;; + --dest) + shift + DESTINATION=$1 + shift;continue + ;; + --is_master) + IS_MASTER="y" + shift;continue + ;; -*) printerr "Unrecognized option : $1" exit @@ -113,9 +116,9 @@ while [ $1 ]; do SOURCES_DIR="$1" SOURCES_DIR_HAS_BEEN_SET=y shift; continue - elif [ -z "$CANDIDATES_DIR_HAS_BEEN_SET" ]; then - CANDIDATES_DIR="$1" - CANDIDATES_DIR_HAS_BEEN_SET=y + elif [ -n "$IS_MASTER" ]; then + # Compatibility with the old syntax with candidates + IS_MASTER="" shift; continue else printerr "Unrecognized option : $1" @@ -132,8 +135,6 @@ VERSION_FILE="version_number" HTML_DIR="/u/agrion/geometrica/CGAL/Members/Releases" URL="http://cgal.inria.fr/CGAL/Members/Releases" -# SVN repository -SVNCGAL="svn+ssh://scm.gforge.inria.fr/svn/cgal" PATH=$PATH:/usr/local/bin:/usr/bin/gnu @@ -168,22 +169,15 @@ set -e cd ${TMPDIR} || return # Update the working copy -if [ -d "${SOURCES_DIR}/.git" ]; then +if [ -e "${SOURCES_DIR}/.git" ]; then pushd "${SOURCES_DIR}" [ -z "$NO_SCM" ] && git pull CGAL_GIT_HASH=`git rev-parse HEAD` - CGAL_SVN_REVISION=99999 popd - SCM=git else - [ -z "$NO_SCM" ] && svn update ${SOURCES_DIR} - CGAL_SVN_REVISION=`svn info ${SOURCES_DIR} | grep Revision | cut -d' ' -f2` - CGAL_GIT_HASH=n/a + echo "Not a git repository" + exit 1 fi -if [ "$SCM" = "svn" -a -n "${CANDIDATES_DIR_HAS_BEEN_SET}" ]; then - [ -z "$NO_SCM" ] && svn update ${CANDIDATES_DIR} -fi - # Set the major/minor/bugfix release numbers NUMBERS_DIR=${SOURCES_DIR}/Maintenance/release_building MAJOR_NUMBER=`cat ${NUMBERS_DIR}/MAJOR_NUMBER` # 2 digits max @@ -202,13 +196,13 @@ if [ -r $VERSION_FILE ]; then INTERNAL_NUMBER=$(( `cat $VERSION_FILE` + 1 )) [ -n "$DO_TAG" ] && printf "%d\n" "${INTERNAL_NUMBER}" > $VERSION_FILE else - INTERNAL_NUMBER=$((`svn ls $SVNCGAL/tags/internal-releases | awk "/${MAJOR_NUMBER}\\.${MINOR_NUMBER}${BUGFIX_STRING}/ "'{FS="-|/"; print $4}' | sort -n | tail -1` + 1 )) + echo "Need a \"version_number\" file." fi if [ -z "$INTERNAL_NUMBER" ]; then INTERNAL_NUMBER=1 fi -if [ -n "${CANDIDATES_DIR_HAS_BEEN_SET}" ]; then +if [ -z "${IS_MASTER}" ]; then INTERNAL_STRING="-Ic-${INTERNAL_NUMBER}" else INTERNAL_STRING="-I-${INTERNAL_NUMBER}" @@ -217,10 +211,11 @@ fi internal_nr=`printf "%4s" "${INTERNAL_NUMBER}" | sed "y/ /0/"` if [ -r "${NUMBERS_DIR}/release_name" ]; then - release_name=`cat "${NUMBERS_DIR}/release_name"`${INTERNAL_STRING} + release_version=`cat "${NUMBERS_DIR}/release_name"`${INTERNAL_STRING} else - release_name="CGAL-${MAJOR_NUMBER}.${MINOR_NUMBER}${BUGFIX_STRING}${INTERNAL_STRING}" + release_version="${MAJOR_NUMBER}.${MINOR_NUMBER}${BUGFIX_STRING}${INTERNAL_STRING}" fi +release_name="CGAL-${release_version}" echo "${release_name}" major_nr=`printf "%2s" "${MAJOR_NUMBER}" | sed "y/ /0/"` minor_nr=`printf "%2s" "${MINOR_NUMBER}" | sed "y/ /0/"` @@ -235,8 +230,15 @@ fi function cleanup() { # Remove local directory and tarball - rm -rf ./"${release_name}" - rm ${release_name}.tar.gz + if [ -d ${release_name} ]; then + rm -rf ./"${release_name}" + fi + if [ -d "${DESTINATION}/${release_name}" ]; then + rm -rf "${DESTINATION}/${release_name}" + fi + if [ -f ${release_name}.tar.gz ]; then + rm ${release_name}.tar.gz + fi if [ -n "$DO_PUBLIC" ]; then [ -d "${public_release_name}" ] && rm -rf ./"${public_release_name}" rm -rf doc @@ -249,14 +251,8 @@ function cleanup() { trap cleanup EXIT # Create the release -if [ -n "$CANDIDATES_DIR_HAS_BEEN_SET" ]; then - ${SOURCES_DIR}/Scripts/developer_scripts/create_internal_release -a ${SOURCES_DIR} -c ${CANDIDATES_DIR} -r ${release_name} -n ${release_number} -else - ${SOURCES_DIR}/Scripts/developer_scripts/create_internal_release -a ${SOURCES_DIR} -r ${release_name} -n ${release_number} -fi -# Add the SVN revision to version.h -cd "${release_name}" -sed -i -e "s/define CGAL_SVN_REVISION .*/define CGAL_SVN_REVISION $CGAL_SVN_REVISION/" include/CGAL/version.h +cmake -DGIT_REPO=${SOURCES_DIR} -DPUBLIC=NO -DTESTSUITE=ON -DDESTINATION="${DESTINATION}" -DCGAL_VERSION="${release_version}" -DCGAL_VERSION_NR="${release_number}" -DVERBOSE="${VERBOSE}" -P ${SOURCES_DIR}/Scripts/developer_scripts/cgal_create_release_with_cmake.cmake +pushd "${DESTINATION}/${release_name}" sed -i -e "s/define CGAL_GIT_HASH .*/define CGAL_GIT_HASH $CGAL_GIT_HASH/" include/CGAL/version.h cd .. # Make the release tarball @@ -269,6 +265,7 @@ ln -s "${release_name}.tar.gz" "$HTML_DIR/CGAL-last.tar.gz" if [ -z "${NO_TESTSUITE}" ]; then echo "${release_name}.tar.gz" > "${HTML_DIR}/LATEST" fi +popd # Tag if [ -n "$DO_TAG" ]; then @@ -284,20 +281,8 @@ if [ -n "$DO_TAG" ]; then if [ -n "$NO_TESTSUITE" ]; then TAG_MSG_EXTRA=" (no testsuite)" fi - [ "$SCM" = "svn" ] && svn cp -m "Internal release tag for $release_name$TAG_MSG_EXTRA (automated commit)" ${SOURCES_DIR} $SVNCGAL/tags/internal-releases/$release_name fi -# Build the SRPM -if [ "$DO_RPM" ]; then - echo "Making the SRPM file" - rm -rf rpm - cp -r ${SOURCES_DIR}/Maintenance/rpm . - cp ${release_name}.tar.gz rpm/SOURCES/ - make -C rpm CGAL.src CGAL_INTERNAL_RELEASE=${INTERNAL_NUMBER} - echo "`basename rpm/SRPMS/*.src.rpm`" > "${HTML_DIR}/LATEST_SRPM" - mv rpm/SRPMS/*.src.rpm "${HTML_DIR}" - rm -rf rpm -fi # Build public release version if [ -n "$DO_PUBLIC" ]; then @@ -309,19 +294,17 @@ if [ -n "$DO_PUBLIC" ]; then fi public_release_version="${MAJOR_NUMBER}.${MINOR_NUMBER}${BUGFIX_STRING}" if [ -n "$BETA" ]; then - public_release_name="CGAL-${public_release_version}-beta${BETA}" - elif [ -r "${NUMBERS_DIR}/public_release_name" ]; then + public_release_version="${public_release_version}-beta${BETA}" + fi + if [ -r "${NUMBERS_DIR}/public_release_name" ]; then public_release_name=`cat "${NUMBERS_DIR}/public_release_name"` + public_release_version=${public_release_name#CGAL-} else public_release_name="CGAL-${public_release_version}" fi - mv -T ${release_name} $public_release_name - cd ${public_release_name} - rm -rf bench* Bench* test package_info developer_scripts doc winutils include/CGAL/Test include/CGAL/Testsuite/ - rm -f examples/*/cgal_test* demo/*/cgal_test* - find . -name .scm-urls -exec rm '{}' '+' - rm -f .scm-branch + cmake -DGIT_REPO=${SOURCES_DIR} -DPUBLIC="ON" -DDESTINATION="${DESTINATION}" -DCGAL_VERSION="${public_release_version}" -DCGAL_VERSION_NR="${release_number}" -DVERBOSE="${VERBOSE}" -P ${SOURCES_DIR}/Scripts/developer_scripts/cgal_create_release_with_cmake.cmake + pushd "${DESTINATION}/${public_release_name}" # Modify the version numbers in sed -i -e "s/define CGAL_VERSION .*/define CGAL_VERSION $public_release_version/" -e "s/define CGAL_VERSION_NR .*/define CGAL_VERSION_NR $public_release_number/" include/CGAL/version.h @@ -343,28 +326,21 @@ if [ -n "$DO_PUBLIC" ]; then cp "${public_release_name}.zip" "${HTML_DIR}/${release_name}-public/" rm -f "$HTML_DIR/CGAL-last-public" ln -s "${release_name}-public" "$HTML_DIR/CGAL-last-public" -fi - -# Build the SRPM of the public version -if [ -n "$DO_RPM" -a -n "$DO_PUBLIC" ]; then - echo "Making the SRPM public file" - rm -rf rpm - cp -r ${SOURCES_DIR}/Maintenance/rpm . - cp ${public_release_name}.tar.gz rpm/SOURCES/ - make -C rpm CGAL.src - # echo "`basename rpm/SRPMS/*.src.rpm`" > "${HTML_DIR}/LATEST_SRPM" - mv rpm/SRPMS/*.src.rpm "${HTML_DIR}/${release_name}-public/" - rm -rf rpm + popd fi if [ -n "$DO_PUBLIC" ]; then - # Build the Windows installer - docker pull cgal/cgal-nsis-dockerfile - docker create -v `realpath ${public_release_name}`:/mnt/cgal_release:ro,z \ - -v ${SOURCES_DIR}:/mnt/cgal_sources:ro,z \ - cgal/cgal-nsis-dockerfile - container_id=`docker ps -q -l` - docker start -a ${container_id} - docker cp ${container_id}:/nsis_release/${public_release_name}-Setup.exe "${HTML_DIR}/${release_name}-public/" - docker rm ${container_id} + if docker version > /dev/null; then + # Build the Windows installer + docker pull cgal/cgal-nsis-dockerfile + docker create -v `realpath ${DESTINATION}/${public_release_name}`:/mnt/cgal_release:ro,z \ + -v ${SOURCES_DIR}:/mnt/cgal_sources:ro,z \ + cgal/cgal-nsis-dockerfile + container_id=`docker ps -q -l` + docker start -a ${container_id} + docker cp ${container_id}:/nsis_release/${public_release_name}-Setup.exe "${HTML_DIR}/${release_name}-public/" + docker rm ${container_id} + else + echo "Cannot use Docker, the Windows installer will not be created" >&2 + fi fi diff --git a/Set_movable_separability_2/test/Set_movable_separability_2/cgal_test_with_cmake b/Set_movable_separability_2/test/Set_movable_separability_2/cgal_test_with_cmake index 6ecbcff56f4..fc1dcde3929 100755 --- a/Set_movable_separability_2/test/Set_movable_separability_2/cgal_test_with_cmake +++ b/Set_movable_separability_2/test/Set_movable_separability_2/cgal_test_with_cmake @@ -26,7 +26,7 @@ configure() { echo "Configuring... " - if eval 'cmake "$CMAKE_GENERATOR" -DRUNNING_CGAL_AUTO_TEST=TRUE \ + if eval 'cmake ${INIT_FILE:+"-C${INIT_FILE}"} "$CMAKE_GENERATOR" -DRUNNING_CGAL_AUTO_TEST=TRUE \ -DCGAL_DIR="$CGAL_DIR" \ .' ; then diff --git a/Surface_mesh_skeletonization/test/Surface_mesh_skeletonization/MCF_Skeleton_test.cpp b/Surface_mesh_skeletonization/test/Surface_mesh_skeletonization/MCF_Skeleton_test.cpp index 63deba74b69..4d710853a78 100644 --- a/Surface_mesh_skeletonization/test/Surface_mesh_skeletonization/MCF_Skeleton_test.cpp +++ b/Surface_mesh_skeletonization/test/Surface_mesh_skeletonization/MCF_Skeleton_test.cpp @@ -2,7 +2,7 @@ #include #include #include -#include +#include #include @@ -34,12 +34,16 @@ bool is_mesh_valid(Polyhedron& pMesh) return false; } + std::size_t i = 0; + BOOST_FOREACH(Polyhedron::Face_handle fh, faces(pMesh)) + fh->id()=i++; + // the algorithm is only applicable on a mesh // that has only one connected component - std::size_t num_component; - CGAL::Counting_output_iterator output_it(&num_component); - CGAL::internal::corefinement::extract_connected_components(pMesh, output_it); - ++output_it; + std::size_t num_component = + CGAL::Polygon_mesh_processing::connected_components( + pMesh, get(CGAL::dynamic_face_property_t(), pMesh)); + if (num_component != 1) { std::cerr << "The mesh is not a single closed mesh. It has " diff --git a/Surface_mesh_skeletonization/test/Surface_mesh_skeletonization/skeleton_connectivity_test.cpp b/Surface_mesh_skeletonization/test/Surface_mesh_skeletonization/skeleton_connectivity_test.cpp index 4409100ab7e..49da555bf98 100644 --- a/Surface_mesh_skeletonization/test/Surface_mesh_skeletonization/skeleton_connectivity_test.cpp +++ b/Surface_mesh_skeletonization/test/Surface_mesh_skeletonization/skeleton_connectivity_test.cpp @@ -2,7 +2,7 @@ #include #include #include -#include +#include #include @@ -35,13 +35,15 @@ bool is_mesh_valid(Polyhedron& pMesh) std::cerr << "The mesh is not a pure triangle mesh."; return false; } + std::size_t i=0; + BOOST_FOREACH(Polyhedron::Face_handle fh, faces(pMesh)) + fh->id()=i++; // the algorithm is only applicable on a mesh // that has only one connected component - std::size_t num_component; - CGAL::Counting_output_iterator output_it(&num_component); - CGAL::internal::corefinement::extract_connected_components(pMesh, output_it); - ++output_it; + std::size_t num_component = + CGAL::Polygon_mesh_processing::connected_components( + pMesh, get(CGAL::dynamic_face_property_t(), pMesh)); if (num_component != 1) { std::cerr << "The mesh is not a single closed mesh. It has " diff --git a/Surface_sweep_2/test/Surface_sweep_2/cgal_test_base b/Surface_sweep_2/test/Surface_sweep_2/cgal_test_base index 7152f915d58..59f380da802 100755 --- a/Surface_sweep_2/test/Surface_sweep_2/cgal_test_base +++ b/Surface_sweep_2/test/Surface_sweep_2/cgal_test_base @@ -32,7 +32,7 @@ configure() rm CMakeCache.txt - if eval 'cmake --no-warn-unused-cli "$CMAKE_GENERATOR" -DRUNNING_CGAL_AUTO_TEST=TRUE \ + if eval 'cmake --no-warn-unused-cli ${INIT_FILE:+"-C${INIT_FILE}"} "$CMAKE_GENERATOR" -DRUNNING_CGAL_AUTO_TEST=TRUE \ -DCGAL_DIR="$CGAL_DIR" \ -DCGAL_CXX_FLAGS:STRING="$TESTSUITE_CXXFLAGS" \ -DCGAL_EXE_LINKER_FLAGS="$TESTSUITE_LDFLAGS" \ diff --git a/TDS_3/include/CGAL/Triangulation_ds_cell_base_3.h b/TDS_3/include/CGAL/Triangulation_ds_cell_base_3.h index b8046fa77af..38726c9fa30 100644 --- a/TDS_3/include/CGAL/Triangulation_ds_cell_base_3.h +++ b/TDS_3/include/CGAL/Triangulation_ds_cell_base_3.h @@ -164,7 +164,7 @@ public: void set_neighbor(int i, Cell_handle n) { CGAL_triangulation_precondition( i >= 0 && i <= 3); - CGAL_triangulation_precondition( this != &*n ); + CGAL_triangulation_precondition( this != n.operator->() ); N[i] = n; } diff --git a/Three/include/CGAL/Three/Scene_item.h b/Three/include/CGAL/Three/Scene_item.h index 7a7b30e2224..65cefc51816 100644 --- a/Three/include/CGAL/Three/Scene_item.h +++ b/Three/include/CGAL/Three/Scene_item.h @@ -248,6 +248,9 @@ public: //! int getId()const; + //! invalidates the context menu. Call it when supportsRenderingMode() changes, + //! for example. + void resetMenu(); //!Handles key press events. virtual bool keyPressEvent(QKeyEvent*){return false;} diff --git a/Triangulation_2/doc/Triangulation_2/Triangulation_2.txt b/Triangulation_2/doc/Triangulation_2/Triangulation_2.txt index 65688e950b0..e9bcdeccf88 100644 --- a/Triangulation_2/doc/Triangulation_2/Triangulation_2.txt +++ b/Triangulation_2/doc/Triangulation_2/Triangulation_2.txt @@ -379,12 +379,12 @@ Flip. \subsection Triangulation_2Implementation Implementation -Locate is implemented by a line walk. The walk -begins at a vertex of the face which +Locate is implemented by a stochastic walk \cgalCite{cgal:dpt-wt-02}. +The walk begins at a vertex of the face which is given as an optional argument or at an arbitrary vertex of the triangulation if no optional argument is given. It takes -time \f$ O(n)\f$ in the worst case, but only \f$ O(\sqrt{n})\f$ +time \f$ O(n)\f$ in the worst case for Delaunay Triangulations, but only \f$ O(\sqrt{n})\f$ on average if the vertices are distributed uniformly at random. The class `Triangulation_hierarchy_2`, described in section \ref Section_2D_Triangulations_Hierarchy,