Merge 'cgal/master'

This commit is contained in:
Sébastien Loriot 2020-09-22 15:47:26 +02:00
commit 7938060fd0
1164 changed files with 135010 additions and 24766 deletions

10
.gitattributes vendored
View File

@ -5,7 +5,7 @@
# to native line endings on checkout.
*.cpp text
*.c text
*.h text
*.h text linguist-language=C++
*.hpp text
*.tex text
*.txt text
@ -18,7 +18,6 @@
*.js text
*.hmtl text
*.bib text
*.sh text
*.css text
*.ui text
*.qrc text
@ -29,13 +28,18 @@
*.xyz text
*.qhcp text
*.qhp text
*.pwn text
*.pwn text linguist-detectable=false
*.poly text
*.rb text
*.perl text
*.pdb text
# Nef_3 data files
*.EH linguist-detectable=false
*.SH linguist-detectable=false
# Declare files that will always have LF line endings on checkout.
*.sh text eol=lf
Documentation/Doxyfile text eol=lf
Documentation/pkglist_filter text eol=lf
Installation/update_CHANGES text eol=lf

View File

@ -1,5 +1,5 @@
language: cpp
dist: xenial
dist: bionic
sudo: required
git:
depth: 3
@ -30,34 +30,35 @@ env:
- PACKAGE='Minkowski_sum_2 Minkowski_sum_3 Modifier '
- PACKAGE='Modular_arithmetic Nef_2 Nef_3 '
- PACKAGE='Nef_S2 NewKernel_d Number_types '
- PACKAGE='OpenNL Optimal_transportation_reconstruction_2 Optimisation_basic '
- PACKAGE='Partition_2 Periodic_2_triangulation_2 Periodic_3_mesh_3 '
- PACKAGE='Periodic_3_triangulation_3 Periodic_4_hyperbolic_triangulation_2 Point_set_2 '
- PACKAGE='Point_set_3 Point_set_processing_3 Poisson_surface_reconstruction_3 '
- PACKAGE='Polygon Polygon_mesh_processing Polygonal_surface_reconstruction '
- 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='STL_Extension Scale_space_reconstruction_3 Scripts '
- PACKAGE='SearchStructures Segment_Delaunay_graph_2 Segment_Delaunay_graph_Linf_2 '
- PACKAGE='Set_movable_separability_2 Shape_detection Skin_surface_3 '
- PACKAGE='Snap_rounding_2 Solver_interface Spatial_searching '
- PACKAGE='Spatial_sorting Straight_skeleton_2 Stream_lines_2 '
- PACKAGE='Stream_support Subdivision_method_3 Surface_mesh '
- PACKAGE='Surface_mesh_approximation Surface_mesh_deformation Surface_mesh_parameterization '
- PACKAGE='Surface_mesh_segmentation Surface_mesh_shortest_path Surface_mesh_simplification '
- PACKAGE='Surface_mesh_skeletonization Surface_mesh_topology Surface_mesher '
- 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 '
- PACKAGE='OpenNL Optimal_bounding_box Optimal_transportation_reconstruction_2 '
- PACKAGE='Optimisation_basic Partition_2 Periodic_2_triangulation_2 '
- PACKAGE='Periodic_3_mesh_3 Periodic_3_triangulation_3 Periodic_4_hyperbolic_triangulation_2 '
- PACKAGE='Point_set_2 Point_set_3 Point_set_processing_3 '
- PACKAGE='Poisson_surface_reconstruction_3 Polygon Polygon_mesh_processing '
- PACKAGE='Polygonal_surface_reconstruction 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 STL_Extension Scale_space_reconstruction_3 '
- PACKAGE='Scripts SearchStructures Segment_Delaunay_graph_2 '
- PACKAGE='Segment_Delaunay_graph_Linf_2 Set_movable_separability_2 Shape_detection '
- PACKAGE='Skin_surface_3 Snap_rounding_2 Solver_interface '
- PACKAGE='Spatial_searching Spatial_sorting Straight_skeleton_2 '
- PACKAGE='Stream_lines_2 Stream_support Subdivision_method_3 '
- PACKAGE='Surface_mesh Surface_mesh_approximation Surface_mesh_deformation '
- PACKAGE='Surface_mesh_parameterization Surface_mesh_segmentation Surface_mesh_shortest_path '
- PACKAGE='Surface_mesh_simplification Surface_mesh_skeletonization Surface_mesh_topology '
- PACKAGE='Surface_mesher Surface_sweep_2 TDS_2 '
- PACKAGE='TDS_3 Testsuite Tetrahedral_remeshing '
- PACKAGE='Three Triangulation Triangulation_2 '
- PACKAGE='Triangulation_3 Union_find Visibility_2 '
- PACKAGE='Voronoi_diagram_2 wininst '
compiler: clang
install:
- echo "$PWD"
- if [ -n "$TRAVIS_PULL_REQUEST_BRANCH" ] && [ "$PACKAGE" != CHECK ]; then DO_IGNORE=FALSE; for ARG in $(echo "$PACKAGE");do if [ "$ARG" = "Maintenance" ]; then continue; fi; . $PWD/.travis/test_package.sh "$PWD" "$ARG"; echo "DO_IGNORE is $DO_IGNORE"; if [ "$DO_IGNORE" = "FALSE" ]; then break; fi; done; if [ "$DO_IGNORE" = "TRUE" ]; then travis_terminate 0; fi;fi
- /usr/bin/time -f 'Spend time of %C -- %E (real)' bash .travis/install.sh
- export CXX=clang++ CC=clang;
- export CXX=clang++-10 CC=clang-10;
before_script:
- wget -O doxygen_exe https://cgal.geometryfactory.com/~mgimeno/doxygen_exe
- sudo mv doxygen_exe /usr/bin/doxygen

View File

@ -28,7 +28,7 @@ function build_demo {
EXTRA_CXX_FLAGS="-Werror=inconsistent-missing-override"
;;
esac
mytime cmake -DCGAL_DIR="/usr/local/lib/cmake/CGAL" -DCGAL_DONT_OVERRIDE_CMAKE_FLAGS:BOOL=ON -DCMAKE_CXX_FLAGS="${CXX_FLAGS} ${EXTRA_CXX_FLAGS}" ..
mytime cmake -DCGAL_DIR="/usr/local/lib/cmake/CGAL" -DCGAL_DONT_OVERRIDE_CMAKE_FLAGS:BOOL=ON -DCMAKE_CXX_FLAGS="${CXX_FLAGS} ${EXTRA_CXX_FLAGS}" ..
mytime make -j2 VERBOSE=1
}
old_IFS=$IFS
@ -57,46 +57,46 @@ cd $ROOT
cd ..
IFS=$old_IFS
mytime zsh $ROOT/Scripts/developer_scripts/test_merge_of_branch HEAD
#test dependencies
#test dependencies
cd $ROOT
mytime bash Scripts/developer_scripts/cgal_check_dependencies.sh --check_headers /usr/bin/doxygen
cd .travis
#parse current matrix and check that no package has been forgotten
#parse current matrix and check that no package has been forgotten
IFS=$'\n'
COPY=0
MATRIX=()
for LINE in $(cat "$PWD/packages.txt")
do
MATRIX+="$LINE "
done
PACKAGES=()
cd ..
for f in *
do
if [ -d "$f/package_info/$f" ]
then
PACKAGES+="$f "
fi
done
DIFFERENCE=$(echo ${MATRIX[@]} ${PACKAGES[@]} | tr ' ' '\n' | sort | uniq -u)
IFS=$' '
if [ "${DIFFERENCE[0]}" != "" ]
then
echo "The matrix and the actual package list differ : ."
echo ${DIFFERENCE[*]}
IFS=$'\n'
COPY=0
MATRIX=()
for LINE in $(cat "$PWD/packages.txt")
do
MATRIX+="$LINE "
done
PACKAGES=()
cd ..
for f in *
do
if [ -d "$f/package_info/$f" ]
then
PACKAGES+="$f "
fi
done
DIFFERENCE=$(echo ${MATRIX[@]} ${PACKAGES[@]} | tr ' ' '\n' | sort | uniq -u)
IFS=$' '
if [ "${DIFFERENCE[0]}" != "" ]
then
echo "The matrix and the actual package list differ : ."
echo ${DIFFERENCE[*]}
echo "You should run generate_travis.sh."
exit 1
fi
echo "Matrix is up to date."
exit 1
fi
echo "Matrix is up to date."
#check if non standard cgal installation works
cd $ROOT
mkdir build_test
cd build_test
mytime cmake -DCMAKE_INSTALL_PREFIX=install/ ..
mytime cmake -DCMAKE_INSTALL_PREFIX=install/ -DCGAL_BUILD_THREE_DOC=TRUE ..
mytime make install
# test install with minimal downstream example
mkdir installtest
@ -110,7 +110,7 @@ cd $ROOT
echo 'target_link_libraries(${PROJECT_NAME} CGAL::CGAL)' >> CMakeLists.txt
echo '#include "CGAL/remove_outliers.h"' >> main.cpp
cd build
mytime cmake -DCMAKE_INSTALL_PREFIX=../../install ..
mytime cmake -DCMAKE_INSTALL_PREFIX=../../install -DCGAL_BUILD_THREE_DOC=TRUE ..
cd ..
exit 0
fi
@ -126,7 +126,7 @@ cd $ROOT
fi
IFS=$' '
EXAMPLES="$ARG/examples/$ARG"
TEST="$ARG/test/$ARG"
TEST="$ARG/test/$ARG"
DEMOS=$ROOT/$ARG/demo/*
if [ -d "$ROOT/$EXAMPLES" ]
@ -168,17 +168,17 @@ cd $ROOT
for DEMO in $DEMOS; do
DEMO=${DEMO#"$ROOT"}
echo $DEMO
#If there is no demo subdir, try in GraphicsView
#If there is no demo subdir, try in GraphicsView
if [ ! -d "$ROOT/$DEMO" ] || [ ! -f "$ROOT/$DEMO/CMakeLists.txt" ]; then
DEMO="GraphicsView/demo/$ARG"
fi
if [ "$ARG" != Polyhedron ] && [ -d "$ROOT/$DEMO" ]
then
if [ "$ARG" != Polyhedron ] && [ -d "$ROOT/$DEMO" ]
then
cd $ROOT/$DEMO
build_demo
elif [ "$ARG" != Polyhedron_demo ]; then
echo "No demo found for $ARG"
fi
fi
done
if [ "$ARG" = Polyhedron_demo ]; then
DEMO=Polyhedron/demo/Polyhedron

View File

@ -2,14 +2,15 @@
[ -n "$CGAL_DEBUG_TRAVIS" ] && set -x
DONE=0
sudo add-apt-repository ppa:mikhailnov/pulseeffects -y
sudo apt-get update
while [ $DONE = 0 ]
do
DONE=1 && sudo -E apt-get -yq --no-install-suggests --no-install-recommends --force-yes install clang zsh \
flex bison cmake graphviz libgmp-dev libmpfr-dev libmpfi-dev zlib1g-dev libeigen3-dev libboost-dev \
libboost-system-dev libboost-program-options-dev libboost-thread-dev libboost-iostreams-dev \
DONE=1 && sudo -E apt-get -yq --no-install-suggests --no-install-recommends --force-yes install clang-10 zsh \
flex bison cmake graphviz libgmp-dev libmpfr-dev libmpfi-dev zlib1g-dev libeigen3-dev \
qtbase5-dev libqt5sql5-sqlite libqt5opengl5-dev qtscript5-dev libqt5svg5-dev qttools5-dev qttools5-dev-tools qml-module-qtgraphicaleffects libopencv-dev mesa-common-dev libmetis-dev libglu1-mesa-dev \
|| DONE=0 && sudo apt-get update
libboost1.72-dev || DONE=0 && sudo apt-get update
done
exit 0

View File

@ -71,6 +71,7 @@ Nef_S2
NewKernel_d
Number_types
OpenNL
Optimal_bounding_box
Optimal_transportation_reconstruction_2
Optimisation_basic
Partition_2
@ -128,6 +129,7 @@ Surface_sweep_2
TDS_2
TDS_3
Testsuite
Tetrahedral_remeshing
Three
Triangulation
Triangulation_2

View File

@ -1,5 +1,5 @@
language: cpp
dist: xenial
dist: bionic
sudo: required
git:
depth: 3
@ -12,7 +12,7 @@ install:
- echo "$PWD"
- if [ -n "$TRAVIS_PULL_REQUEST_BRANCH" ] && [ "$PACKAGE" != CHECK ]; then DO_IGNORE=FALSE; for ARG in $(echo "$PACKAGE");do if [ "$ARG" = "Maintenance" ]; then continue; fi; . $PWD/.travis/test_package.sh "$PWD" "$ARG"; echo "DO_IGNORE is $DO_IGNORE"; if [ "$DO_IGNORE" = "FALSE" ]; then break; fi; done; if [ "$DO_IGNORE" = "TRUE" ]; then travis_terminate 0; fi;fi
- /usr/bin/time -f 'Spend time of %C -- %E (real)' bash .travis/install.sh
- export CXX=clang++ CC=clang;
- export CXX=clang++-10 CC=clang-10;
before_script:
- wget -O doxygen_exe https://cgal.geometryfactory.com/~mgimeno/doxygen_exe
- sudo mv doxygen_exe /usr/bin/doxygen

12
.travis/windows.h Normal file
View File

@ -0,0 +1,12 @@
#define MAX(a,b) (((a) > (b)) ? (a) : (b))
#define max(a,b) (((a) > (b)) ? (a) : (b))
#define MIN(a,b) (((a) < (b)) ? (a) : (b))
#define min(a,b) (((a) < (b)) ? (a) : (b))
#define FAR #error named reserved in windows.h
#define far #error named reserved in windows.h
#define Polyline #error named reserved in windows.h
#define Polygon #error named reserved in windows.h

View File

@ -1,24 +1,20 @@
# Created by the script cgal_create_CMakeLists
# This is the CMake script for compiling a set of CGAL applications.
# Created by the script cgal_create_cmake_script
# This is the CMake script for compiling a CGAL application.
cmake_minimum_required(VERSION 3.1...3.15)
project( AABB_traits_benchmark)
cmake_minimum_required(VERSION 3.1...3.14)
project( AABB_traits_benchmark )
# CGAL and its components
find_package( CGAL REQUIRED )
include( ${CGAL_USE_FILE} )
find_package(CGAL REQUIRED QUIET OPTIONAL_COMPONENTS Core )
# Boost and its components
find_package( Boost REQUIRED )
# include for local directory
create_single_source_cgal_program( "test.cpp" )
create_single_source_cgal_program( "tree_construction.cpp" )
# google benchmark
find_package(benchmark REQUIRED)
find_package(benchmark)
# include for local package
include_directories( BEFORE ../../include )
if (benchmark_FOUND)
create_single_source_cgal_program("tree_creation.cpp")
target_link_libraries(tree_creation benchmark::benchmark)
endif()
# add_executable (test_ test.cpp) // TODO: fix this benchmark
add_executable(tree_creation tree_creation.cpp)
target_link_libraries(tree_creation benchmark::benchmark)

View File

@ -0,0 +1,124 @@
#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
#include <CGAL/Exact_predicates_exact_constructions_kernel.h>
#include <CGAL/AABB_tree.h>
#include <CGAL/AABB_traits.h>
#include <CGAL/Surface_mesh.h>
#include <CGAL/AABB_face_graph_triangle_primitive.h>
#include <CGAL/Polygon_mesh_processing/bbox.h>
#include <CGAL/Timer.h>
#include <iostream>
#include <fstream>
int longest_axis(const CGAL::Bbox_3& bbox)
{
const double dx = bbox.xmax() - bbox.xmin();
const double dy = bbox.ymax() - bbox.ymin();
const double dz = bbox.zmax() - bbox.zmin();
return (dx>=dy) ? ((dx>=dz) ? 0 : 2) : ((dy>=dz) ? 1 : 2);
}
template <class RPM>
struct Split_primitives
{
Split_primitives(RPM rpm)
: rpm(rpm)
{}
template<typename PrimitiveIterator>
void operator()(PrimitiveIterator first,
PrimitiveIterator beyond,
const CGAL::Bbox_3& bbox) const
{
PrimitiveIterator middle = first + (beyond - first)/2;
typedef typename std::iterator_traits<PrimitiveIterator>::value_type Primitive;
const int crd=longest_axis(bbox);
const RPM& l_rpm=rpm;
std::nth_element(first, middle, beyond,
[l_rpm, crd](const Primitive& p1, const Primitive& p2){ return get(l_rpm, p1.id())[crd] < get(l_rpm, p2.id())[crd];});
}
RPM rpm;
};
template <class BBM>
struct Compute_bbox {
Compute_bbox(const BBM& bbm)
: bbm(bbm)
{}
template<typename ConstPrimitiveIterator>
CGAL::Bbox_3 operator()(ConstPrimitiveIterator first,
ConstPrimitiveIterator beyond) const
{
CGAL::Bbox_3 bbox = get(bbm, first->id());
for(++first; first != beyond; ++first)
{
bbox += get(bbm, first->id());
}
return bbox;
}
BBM bbm;
};
template <class K>
void run(std::string input)
{
typedef typename K::Point_3 Point_3;
typedef CGAL::Surface_mesh<Point_3> Mesh;
typedef CGAL::AABB_face_graph_triangle_primitive<Mesh> Primitive;
typedef CGAL::AABB_traits<K, Primitive> Traits;
typedef CGAL::AABB_tree<Traits> Tree;
Mesh tm;
std::ifstream(input) >> tm;
{
Tree tree(faces(tm).begin(), faces(tm).end(), tm);
CGAL::Timer time;
time.start();
tree.build();
time.stop();
std::cout << " build() time: " << time.time() << "\n";
}
{
Tree tree(faces(tm).begin(), faces(tm).end(), tm);
CGAL::Timer time;
time.start();
typedef CGAL::Pointer_property_map<CGAL::Bbox_3>::type BBM;
typedef CGAL::Pointer_property_map<CGAL::Epick::Point_3>::type RPM; // EPIC on purpose here
std::vector<CGAL::Bbox_3> v_bb;
std::vector<CGAL::Epick::Point_3> v_rp;
std::size_t nbf = num_faces(tm);
v_bb.resize(nbf);
v_rp.resize(nbf);
BBM bbm = CGAL::make_property_map(v_bb);
RPM rpm = CGAL::make_property_map(v_rp);
CGAL::Cartesian_converter<K, CGAL::Epick> to_input;
for(typename Mesh::Face_index f : tm.faces())
{
v_bb[f]=CGAL::Polygon_mesh_processing::face_bbox(f, tm);
v_rp[f]=to_input(tm.point(target(halfedge(f, tm), tm)));
}
Compute_bbox<BBM> compute_bbox(bbm);
Split_primitives<RPM> split_primitives(rpm);
tree.custom_build(compute_bbox, split_primitives);
time.stop();
std::cout << " custom_build() time: " << time.time() << "\n";
}
}
int main(int, char** argv)
{
std::cout << "Build with Epick\n";
run<CGAL::Epick>(argv[1]);
std::cout << "Build with Epeck\n";
run<CGAL::Epeck>(argv[1]);
return EXIT_SUCCESS;
}

View File

@ -45,8 +45,7 @@ Scene::Scene()
m_blue_ramp.build_blue();
m_max_distance_function = (FT)0.0;
texture = new Texture(m_grid_size,m_grid_size);
startTimer(0);
ready_to_cut = false;
ready_to_cut = true;
are_buffers_initialized = false;
gl_init = false;
@ -519,6 +518,7 @@ void Scene::changed()
compute_elements(_UNSIGNED);
else
compute_elements(_SIGNED);
ready_to_cut=false;
are_buffers_initialized = false;
}
@ -855,8 +855,8 @@ void Scene::update_grid_size()
}
void Scene::generate_points_in(const unsigned int nb_points,
const double min,
const double max)
const double vmin,
const double vmax)
{
if(m_pPolyhedron == NULL)
{
@ -875,7 +875,7 @@ void Scene::generate_points_in(const unsigned int nb_points,
CGAL::Timer timer;
timer.start();
std::cout << "Generate " << nb_points << " points in interval ["
<< min << ";" << max << "]";
<< vmin << ";" << vmax << "]";
unsigned int nb_trials = 0;
Vector vec = random_vector();
@ -892,8 +892,8 @@ void Scene::generate_points_in(const unsigned int nb_points,
if(nb_intersections % 2 != 0)
signed_distance *= -1.0;
if(signed_distance >= min &&
signed_distance <= max)
if(signed_distance >= vmin &&
signed_distance <= vmax)
{
m_points.push_back(p);
if(m_points.size()%(nb_points/10) == 0)
@ -1226,12 +1226,16 @@ void Scene::cut_segment_plane()
m_cut_plane = CUT_SEGMENTS;
changed();
}
void Scene::updateCutPlane()
{
ready_to_cut = true;
QTimer::singleShot(0,this,SLOT(cutting_plane()));
}
void Scene::cutting_plane(bool override)
{
if(ready_to_cut || override)
{
ready_to_cut = false;
switch( m_cut_plane )
{
case UNSIGNED_FACETS:
@ -1304,13 +1308,13 @@ void Scene::refine_loop()
void Scene::activate_cutting_plane()
{
connect(m_frame, SIGNAL(modified()), this, SLOT(cutting_plane()));
connect(m_frame, SIGNAL(modified()), this, SLOT(updateCutPlane()));
m_view_plane = true;
}
void Scene::deactivate_cutting_plane()
{
disconnect(m_frame, SIGNAL(modified()), this, SLOT(cutting_plane()));
disconnect(m_frame, SIGNAL(modified()), this, SLOT(updateCutPlane()));
m_view_plane = false;
}
void Scene::initGL()
@ -1326,10 +1330,3 @@ void Scene::initGL()
compile_shaders();
gl_init = true;
}
void Scene::timerEvent(QTimerEvent *)
{
if(manipulatedFrame()->isSpinning())
set_fast_distance(true);
ready_to_cut = true;
}

View File

@ -173,6 +173,8 @@ private:
void attrib_buffers(CGAL::QGLViewer*);
void compile_shaders();
void compute_texture(int, int, Color_ramp, Color_ramp);
private slots:
void updateCutPlane();
public:
// file menu
@ -192,7 +194,7 @@ public:
void generate_boundary_points(const unsigned int nb_points);
void generate_boundary_segments(const unsigned int nb_slices);
void generate_points_in(const unsigned int nb_points,
const double min, const double max);
const double vmin, const double vmax);
// algorithms/refine
void refine_loop();
@ -251,8 +253,6 @@ public:
void activate_cutting_plane();
void deactivate_cutting_plane();
//timer sends a top when all the events are finished
void timerEvent(QTimerEvent *);
public slots:

View File

@ -132,62 +132,62 @@ typedef unspecified_type Equal_3;
/// @{
/*!
Returns the intersection detection functor.
returns the intersection detection functor.
*/
Do_intersect_3 do_intersect_3_object();
/*!
Returns the intersection constructor.
returns the intersection constructor.
*/
Intersect_3 intersect_3_object();
/*!
Returns the sphere constructor.
returns the sphere constructor.
*/
Construct_sphere_3 construct_sphere_3_object();
/*!
Returns the closest point constructor.
returns the closest point constructor.
*/
Construct_projected_point_3 construct_projected_point_3_object();
/*!
Returns the compare distance constructor.
returns the compare distance constructor.
*/
Compare_distance_3 compare_distance_3_object();
/*!
Returns the closest point constructor.
returns the closest point constructor.
*/
Has_on_bounded_side_3 has_on_bounded_side_3_object();
/*!
Returns the squared radius functor.
returns the squared radius functor.
*/
Compute_squared_radius_3 compute_squared_radius_3_object();
/*!
Returns the squared distance functor.
returns the squared distance functor.
*/
Compute_squared_distance_3 compute_squared_distance_3_object();
/*!
Returns the `Less_x_3` functor.
returns the `Less_x_3` functor.
*/
Less_x_3 less_x_3_object();
/*!
Returns the `Less_y_3` functor.
returns the `Less_y_3` functor.
*/
Less_y_3 less_y_3_object();
/*!
Returns the `Less_z_3` functor.
returns the `Less_z_3` functor.
*/
Less_z_3 less_z_3_object();
/*!
Returns the equal functor.
returns the equal functor.
*/
Equal_3 equal_3_object();

View File

@ -56,17 +56,17 @@ typedef unspecified_type Id;
/// @{
/*!
Returns the datum (geometric object) represented by the primitive.
returns the datum (geometric object) represented by the primitive.
*/
Datum_reference datum();
/*!
Returns the corresponding identifier. This identifier is only used as a reference for the objects in the output of the `AABB_tree` methods.
returns the corresponding identifier. This identifier is only used as a reference for the objects in the output of the `AABB_tree` methods.
*/
Id id();
/*!
Returns a 3D point located on the geometric object represented by the primitive. This function is used to sort the primitives during the AABB tree construction as well as to construct the search KD-tree internal to the AABB tree used to accelerate distance queries.
returns a 3D point located on the geometric object represented by the primitive. This function is used to sort the primitives during the AABB tree construction as well as to construct the search KD-tree internal to the AABB tree used to accelerate distance queries.
*/
Point_reference reference_point();

View File

@ -66,22 +66,22 @@ typedef unspecified_type Shared_data;
/// \name Operations
/// @{
/*!
Returns the datum (geometric object) represented by the primitive.
returns the datum (geometric object) represented by the primitive.
*/
Datum_reference datum(const Shared_data& data);
/*!
Returns the corresponding identifier. This identifier is only used as a reference for the objects in the output of the `AABB_tree` methods.
returns the corresponding identifier. This identifier is only used as a reference for the objects in the output of the `AABB_tree` methods.
*/
Id id();
/*!
Returns a 3D point located on the geometric object represented by the primitive. This function is used to sort the primitives during the AABB tree construction as well as to construct the search KD-tree internal to the AABB tree used to accelerate distance queries.
returns a 3D point located on the geometric object represented by the primitive. This function is used to sort the primitives during the AABB tree construction as well as to construct the search KD-tree internal to the AABB tree used to accelerate distance queries.
*/
Point_reference reference_point(const Shared_data& data);
/*!
A static function responsible for the creation of the shared data of a primitive.
constructs the shared data of a primitive.
The parameter pack is such that there exists a constructor `template <class T1, class ... T> AABBPrimitiveWithSharedData (T1,T...)`.
*/
template <class ... T>

View File

@ -44,7 +44,7 @@ public:
typedef unspecified_type Intersection_distance;
/*!
Returns the intersection distance functor.
returns the intersection distance functor.
*/
Intersection_distance intersection_distance_object() const ;
};

View File

@ -164,42 +164,42 @@ typedef unspecified_type Equal_3;
/// @{
/*!
Returns the primitive splitting functor.
returns the primitive splitting functor.
*/
Split_primitives split_primitives_object();
/*!
Returns the bounding box constructor.
returns the bounding box constructor.
*/
Compute_bbox compute_bbox_object();
/*!
Returns the intersection detection functor.
returns the intersection detection functor.
*/
Do_intersect do_intersect_object();
/*!
Returns the intersection constructor.
returns the intersection constructor.
*/
Intersection intersection_object();
/*!
Returns the distance comparison functor.
returns the distance comparison functor.
*/
Compare_distance compare_distance_object();
/*!
Returns the closest point constructor.
returns the closest point constructor.
*/
Closest_point closest_point_object();
/*!
Returns the squared distance functor.
returns the squared distance functor.
*/
Squared_distance squared_distance_object();
/*!
Returns the equal functor.
returns the equal functor.
*/
Equal_3 equal_3_object();
@ -220,7 +220,7 @@ void set_shared_data(T ... t);
{}
/*!
Returns the shared data of the primitive constructed after a call to `set_shared_data`.
returns the shared data of the primitive constructed after a call to `set_shared_data`.
If no call to `set_shared_data` has been done, `Primitive::Shared_data()` is returned.
*/
const Primitive::Shared_data& shared_data() const;

View File

@ -189,7 +189,7 @@ example illustrates this for two polyhedral surfaces.
\subsection aabb_tree_examples_7 Trees of Custom Primitives
The AABB tree example folder contains three examples of trees
constructed with customize primitives. In \ref AABB_tree/AABB_custom_example.cpp "AABB_custom_example.cpp"
constructed with custom primitives. In \ref AABB_tree/AABB_custom_example.cpp "AABB_custom_example.cpp"
the primitive contains triangles which are defined by three pointers
to custom points. In \ref AABB_tree/AABB_custom_triangle_soup_example.cpp "AABB_custom_triangle_soup_example.cpp" all input
triangles are stored into a single array so as to form a triangle
@ -336,7 +336,7 @@ inside the bounding box.
The experiments described above are neither exhaustive nor conclusive
as we have chosen one specific case where the input primitives are the
facets of a triangle surface polyhedron. Nevertheless we now provide
some general observations and advices about how to put the AABB tree
some general observations and advises about how to put the AABB tree
to use with satisfactory performances. While the tree construction
times and memory occupancy do not fluctuate much in our experiments
depending on the input surface triangle mesh, the performance
@ -423,10 +423,11 @@ primitives at the leafs of the tree. The ball radius is then shrunk to
the distance between `p` and `q` for all remaining recursive
traversals of the tree. Efficiency is achieved through setting the
initial ball radius to a small value still guaranteed to intersect the
input primitives. This is achieved by constructing through the
function `AABB_tree::accelerate_distance_queries()` an internal secondary data
input primitives. This is achieved by constructing an internal secondary data
structure which provides a good hint to the algorithm at the beginning
of the traversal.
of the traversal (done by default).
Calling `do_not_accelerate_distance_queries()` will disable
the construction and the usage of this internal secondary data structure.
\section aabb_tree_history Design and Implementation History
@ -434,10 +435,10 @@ Camille Wormser and Pierre Alliez started working on a data structure
for efficient collision detection in 2007. The generic design for
implementing both intersection and distance queries, and for generic
queries and primitives was developed by Camille Wormser. In 2009,
Pierre Alliez, St&eacute;phane Tayeb and Camille Wormser made the
Pierre Alliez, Stéphane Tayeb and Camille Wormser made the
implementation CGAL-compliant, with the help of Laurent Rineau for
optimizing the tree construction. The authors wish to thank Andreas
Fabri, Jane Tournois, Mariette Yvinec and Sylvain Lef&egrave;bvre for
Fabri, Jane Tournois, Mariette Yvinec and Sylvain Lefèbvre for
helpful comments and discussions.
*/

View File

@ -112,7 +112,7 @@ public:
/*!
Id type:
- `boost::graph_traits<FaceGraph>::%face_descriptor` if `OneFaceGraphPerTree` is `CGAL::Tag_true`
- `std::pair<boost::graph_traits<FaceGraph>::%face_descriptor, FaceGraph>` if `OneFaceGraphPerTree` is `CGAL::Tag_false`
- `std::pair<boost::graph_traits<FaceGraph>::%face_descriptor, const FaceGraph*>` if `OneFaceGraphPerTree` is `CGAL::Tag_false`
*/
unspecified_type Id;
@ -130,7 +130,7 @@ public:
// constructors
/*!
\tparam Iterator an input iterator with `Id` as value type.
Constructs a primitive.
constructs a primitive.
If `VertexPointPMap` is the default of the class, an additional constructor
is available with `vppm` set to `get(vertex_point, graph)`.
*/
@ -142,7 +142,7 @@ public:
{}
/*!
Constructs a primitive.
constructs a primitive.
If `VertexPointPMap` is the default of the class, an additional constructor
is available with `vppm` set to `get(vertex_point, graph)`.
*/

View File

@ -125,8 +125,8 @@ public:
typedef Kernel_traits<Point>::Kernel::Segment_3 Datum;
/*!
Id type:
- `boost::graph_traits<HalfedgeGraph>::%edge_descriptor if `OneHalfedgeGraphPerTree` is `Tag_true`
- `std::pair<boost::graph_traits<HalfedgeGraph>::edge_descriptor, HalfedgeGraph>` if `OneHalfedgeGraphPerTree` is `Tag_false`
- `boost::graph_traits<HalfedgeGraph>::%edge_descriptor` if `OneHalfedgeGraphPerTree` is `Tag_true`
- `std::pair<boost::graph_traits<HalfedgeGraph>::%edge_descriptor, const HalfedgeGraph*>` if `OneHalfedgeGraphPerTree` is `Tag_false`
*/
unspecified_type Id;
/// @}
@ -141,7 +141,7 @@ public:
typedef typename boost::graph_traits<HalfedgeGraph>::edge_descriptor edge_descriptor;
/*!
Constructs a primitive.
constructs a primitive.
\tparam Iterator is an input iterator with `Id` as value type.
This \ref AABB_tree/AABB_halfedge_graph_edge_example.cpp "example" gives a way to call this constructor
using the insert-by-range method of the class `AABB_tree<Traits>`.
@ -156,7 +156,7 @@ public:
{}
/*!
Constructs a primitive.
constructs a primitive.
If `VertexPointPMap` is the default of the class, an additional constructor
is available with `vppm` set to `boost::get(vertex_point, graph)`.
*/
@ -202,4 +202,3 @@ public:
#include <CGAL/enable_warnings.h>
#endif // CGAL_AABB_HALFEDGE_GRAPH_SEGMENT_PRIMITIVE_H

View File

@ -112,14 +112,14 @@ struct AABB_primitive
/// @}
/*!
Constructs a primitive and initializes the property maps.
constructs a primitive and initializes the property maps.
*/
AABB_primitive(Id id,
ObjectPropertyMap o_pmap=ObjectPropertyMap(),
PointPropertyMap p_pmap=PointPropertyMap());
/*!
Constructs a primitive from an iterator with `Id` as value type
constructs a primitive from an iterator with `Id` as value type
and initializes the property maps.
*/
template <class Iterator>

View File

@ -88,7 +88,7 @@ class AABB_segment_primitive
Tag_false,
CacheDatum > Base;
public:
///Constructor from an iterator
///constructor from an iterator
AABB_segment_primitive(Iterator it) : Base(it){}
};

View File

@ -171,9 +171,11 @@ class AABB_tree;
/// \sa `AABBPrimitiveWithSharedData`
template<typename GeomTraits, typename AABBPrimitive, typename BboxMap = Default>
class AABB_traits:
public internal::AABB_tree::AABB_traits_base<AABBPrimitive>,
class AABB_traits
#ifndef DOXYGEN_RUNNING
: public internal::AABB_tree::AABB_traits_base<AABBPrimitive>,
public internal::AABB_tree::AABB_traits_base_2<GeomTraits>
#endif
{
typedef typename CGAL::Object Object;
public:

View File

@ -41,7 +41,7 @@ namespace CGAL {
/// @{
/**
* Class AABB_tree is a static data structure for efficient
* Static data structure for efficient
* intersection and distance computations in 3D. It builds a
* hierarchy of axis-aligned bounding boxes (an AABB tree) from a set
* of 3D geometric objects, and can receive intersection and distance
@ -63,6 +63,7 @@ namespace CGAL {
// type of the primitives container
typedef std::vector<typename AABBTraits::Primitive> Primitives;
typedef internal::Primitive_helper<AABBTraits> Helper;
typedef AABB_tree<AABBTraits> Self;
public:
@ -111,7 +112,7 @@ namespace CGAL {
/// \name Creation
///@{
/// Constructs an empty tree, and initializes the internally stored traits
/// constructs an empty tree, and initializes the internally stored traits
/// class using `traits`.
AABB_tree(const AABBTraits& traits = AABBTraits());
@ -128,39 +129,45 @@ namespace CGAL {
* @param first iterator over first primitive to insert
* @param beyond past-the-end iterator
*
* It is equivalent to constructing an empty tree and calling `insert(first,last,t...)`.
* constructs an empty tree followed by a call to `insert(first,last,t...)`.
* The tree stays empty if the memory allocation is not successful.
*/
template<typename InputIterator,typename ... T>
AABB_tree(InputIterator first, InputIterator beyond,T&& ...);
/// After one or more calls to `insert()` the internal data
/// structure of the tree must be reconstructed. This procedure
/// has a complexity of \f$O(n log(n))\f$, where \f$n\f$ is the number of
/// primitives of the tree. This procedure is called implicitly
/// at the first call to a query member function. You can call
/// `build()` explicitly to ensure that the next call to
/// query functions will not trigger the reconstruction of the
/// data structure.
/// A call to `AABBTraits::set_shared_data(t...)`
/// is made using the internally stored traits.
/// triggers the (re)construction of the internal tree structure.
/// The internal tree structure is automatically invalidated by the insertion of any primitives
/// after one or more calls to `insert()`.
/// This procedure is called implicitly at the first call to a query member function.
/// An explicit call to `build()` must be made to ensure that the next call to
/// a query function will not trigger the construction of the data structure.
/// A call to `AABBTraits::set_shared_data(t...)` is made using the internally stored traits.
/// This procedure has a complexity of \f$O(n log(n))\f$, where \f$n\f$ is the number of
/// primitives of the tree.
template<typename ... T>
void build(T&& ...);
#ifndef DOXYGEN_RUNNING
void build();
/// triggers the (re)construction of the tree similarly to a call to `build()`
/// but the traits functors `Compute_bbox` and `Split_primitives` are ignored
/// and `compute_bbox` and `split_primitives` are used instead.
template <class ComputeBbox, class SplitPrimitives>
void custom_build(const ComputeBbox& compute_bbox,
const SplitPrimitives& split_primitives);
#endif
///@}
/// \name Operations
///@{
/// Equivalent to calling `clear()` and then `insert(first,last,t...)`.
/// is equivalent to calling `clear()`, `insert(first,last,t...)`, and `build()`
template<typename ConstPrimitiveIterator,typename ... T>
void rebuild(ConstPrimitiveIterator first, ConstPrimitiveIterator beyond,T&& ...);
/// Add a sequence of primitives to the set of primitives of the AABB tree.
/// `%InputIterator` is any iterator and the parameter pack `T` are any types
/// adds a sequence of primitives to the set of primitives of the AABB tree.
/// `%InputIterator` is any iterator and the parameter pack `T` contains any types
/// such that `Primitive` has a constructor with the following signature:
/// `Primitive(%InputIterator, T...)`. If `Primitive` is a model of the concept
/// `AABBPrimitiveWithSharedData`, a call to `AABBTraits::set_shared_data(t...)`
@ -168,30 +175,31 @@ namespace CGAL {
template<typename InputIterator,typename ... T>
void insert(InputIterator first, InputIterator beyond,T&& ...);
/// Adds a primitive to the set of primitives of the tree.
/// adds a primitive to the set of primitives of the tree.
inline void insert(const Primitive& p);
/// Clears and destroys the tree.
/// clears and destroys the tree.
~AABB_tree()
{
clear();
}
/// Returns a const reference to the internally stored traits class.
/// returns a const reference to the internally stored traits class.
const AABBTraits& traits() const{
return m_traits;
}
/// Clears the tree.
/// clears the tree and the search tree if it was constructed,
/// and switches on the usage of the search tree to find the hint for the distance queries
void clear()
{
// clear AABB tree
clear_nodes();
m_primitives.clear();
clear_search_tree();
m_default_search_tree_constructed = true;
m_use_default_search_tree = true;
}
/// Returns the axis-aligned bounding box of the whole tree.
/// returns the axis-aligned bounding box of the whole tree.
/// \pre `!empty()`
const Bounding_box bbox() const {
CGAL_precondition(!empty());
@ -202,10 +210,10 @@ namespace CGAL {
m_primitives.end());
}
/// Returns the number of primitives in the tree.
/// returns the number of primitives in the tree.
size_type size() const { return m_primitives.size(); }
/// Returns \c true, iff the tree contains no primitive.
/// returns \c true, iff the tree contains no primitive.
bool empty() const { return m_primitives.empty(); }
///@}
@ -221,47 +229,46 @@ namespace CGAL {
set_primitive_data_impl(CGAL::Boolean_tag<internal::Has_nested_type_Shared_data<Primitive>::value>(),std::forward<T>(t)...);
}
bool build_kd_tree() const;
bool build_kd_tree();
template<typename ConstPointIterator>
bool build_kd_tree(ConstPointIterator first, ConstPointIterator beyond) const;
bool build_kd_tree(ConstPointIterator first, ConstPointIterator beyond);
public:
/// \name Intersection Tests
///@{
/// Returns `true`, iff the query intersects at least one of
/// the input primitives. \tparam Query must be a type for
/// which `do_intersect` predicates are
/// defined in the traits class `AABBTraits`.
/// returns `true`, iff the query intersects at least one of
/// the input primitives.
/// \tparam Query must be a type for which `Do_intersect` operators are
/// defined in the traits class `AABBTraits`.
template<typename Query>
bool do_intersect(const Query& query) const;
/// Returns the number of primitives intersected by the
/// query. \tparam Query must be a type for which
/// `do_intersect` predicates are defined
/// in the traits class `AABBTraits`.
/// returns the number of primitives intersected by the
/// query.
/// \tparam Query must be a type for which `Do_intersect` operators are
/// defined in the traits class `AABBTraits`.
template<typename Query>
size_type number_of_intersected_primitives(const Query& query) const;
/// Outputs to the iterator the list of all intersected primitives
/// ids. This function does not compute the intersection points
/// puts in `out` the ids of all intersected primitives.
/// This function does not compute the intersection points
/// and is hence faster than the function `all_intersections()`
/// function below. \tparam Query must be a type for which
/// `do_intersect` predicates are defined
/// in the traits class `AABBTraits`.
/// function below.
/// \tparam Query must be a type for which `Do_intersect` operators are
/// defined in the traits class `AABBTraits`.
template<typename Query, typename OutputIterator>
OutputIterator all_intersected_primitives(const Query& query, OutputIterator out) const;
/// Returns the intersected primitive id that is encountered first
/// returns the id of the intersected primitive that is encountered first
/// in the tree traversal, iff
/// the query intersects at least one of the input primitives. No
/// particular order is guaranteed over the tree traversal, such
/// that, e.g, the primitive returned is not necessarily the
/// closest from the source point of a ray query. \tparam Query
/// must be a type for which
/// `do_intersect` predicates are defined
/// in the traits class `AABBTraits`.
/// closest from the source point of a ray query.
/// \tparam Query must be a type for which `Do_intersect` operators are
/// defined in the traits class `AABBTraits`.
template <typename Query>
boost::optional<Primitive_id> any_intersected_primitive(const Query& query) const;
///@}
@ -269,30 +276,29 @@ public:
/// \name Intersections
///@{
/// Outputs the list of all intersections, as objects of
/// puts in `out` all intersections, as objects of
/// `Intersection_and_primitive_id<Query>::%Type`,
/// between the query and the input data to
/// the iterator. `do_intersect()`
/// predicates and intersections must be defined for `Query`
/// in the `AABBTraits` class.
/// the iterator.
/// \tparam Query must be a type for which `Do_intersect` and `Intersection` operators are
/// defined in the traits class `AABBTraits`.
template<typename Query, typename OutputIterator>
OutputIterator all_intersections(const Query& query, OutputIterator out) const;
/// Returns the intersection that is encountered first
/// returns if any the intersection that is encountered first
/// in the tree traversal. No particular
/// order is guaranteed over the tree traversal, e.g, the
/// primitive returned is not necessarily the closest from the
/// source point of a ray query. Type `Query` must be a type
/// for which `do_intersect` predicates
/// and intersections are defined in the traits class AABBTraits.
/// primitive returned is not necessarily the closest from the query.
/// \tparam Query must be a type for which `Do_intersect` and `Intersection` operators are
/// defined in the traits class `AABBTraits`.
template <typename Query>
boost::optional< typename Intersection_and_primitive_id<Query>::Type >
any_intersection(const Query& query) const;
/// Returns the intersection and primitive id closest to the source point of the ray
/// returns the intersection and primitive id closest to the source point of the ray
/// query.
/// \tparam Ray must be the same as `AABBTraits::Ray_3` and
/// `do_intersect` predicates and intersections for it must be
@ -323,7 +329,7 @@ public:
}
/// \endcond
/// Returns the primitive id closest to the source point of the ray
/// returns the primitive id closest to the source point of the ray
/// query.
/// \tparam Ray must be the same as `AABBTraits::Ray_3` and
/// `do_intersect` predicates and intersections for it must be
@ -352,31 +358,22 @@ public:
/// \name Distance Queries
///@{
/// Returns the minimum squared distance between the query point
/// and all input primitives. Method
/// `accelerate_distance_queries()` should be called before the
/// first distance query, so that an internal secondary search
/// structure is build, for improving performance.
/// returns the minimum squared distance between the query point
/// and all input primitives.
/// \pre `!empty()`
FT squared_distance(const Point& query) const;
/// Returns the point in the union of all input primitives which
/// returns the point in the union of all input primitives which
/// is closest to the query. In case there are several closest
/// points, one arbitrarily chosen closest point is
/// returned. Method `accelerate_distance_queries()` should be
/// called before the first distance query, so that an internal
/// secondary search structure is build, for improving
/// performance.
/// returned.
/// \pre `!empty()`
Point closest_point(const Point& query) const;
/// Returns a `Point_and_primitive_id` which realizes the
/// returns a `Point_and_primitive_id` which realizes the
/// smallest distance between the query point and all input
/// primitives. Method `accelerate_distance_queries()` should be
/// called before the first distance query, so that an internal
/// secondary search structure is build, for improving
/// performance.
/// primitives.
/// \pre `!empty()`
Point_and_primitive_id closest_point_and_primitive(const Point& query) const;
@ -416,19 +413,18 @@ public:
/// one may want to provide a much better hint than a vertex of
/// the triangle soup could be. It could be, for example, the
/// barycenter of one of the triangles. But, except with the use
/// of an exact constructions kernel, one cannot easily construct
/// of a kernel with exact constructions, one cannot easily construct
/// points other than the vertices, that lie exactly on a triangle
/// soup. Hence, providing a good hint sometimes means not being
/// able to provide it exactly on the primitives. In rare
/// occasions, this hint can be returned as the closest point.
/// In order to accelerate distance queries significantly, the
/// AABB tree builds an internal KD-tree containing a set of
/// potential hints, when the method
/// `accelerate_distance_queries()` is called. This KD-tree
/// provides very good hints that allow the algorithms to run much
/// faster than with a default hint (such as the
/// `reference_point` of the first primitive). The set of
/// potential hints is a sampling of the union of the primitives,
/// potential hints. This KD-tree provides very good hints
/// that allow the algorithms to run much faster than
/// when `do_not_accelerate_distance_queries()` that makes the
/// hint to always be the `reference_point` of the first primitive.
/// The set of potential hints is a sampling of the union of the primitives,
/// which is obtained, by default, by calling the method
/// `reference_point` of each of the primitives. However, such
/// a sampling with one point per primitive may not be the most
@ -436,45 +432,46 @@ public:
/// inserting more than one sample on them. Conversely, a sparser
/// sampling with less than one point per input primitive is
/// relevant in some cases.
/// The internal KD-tree is always used if no call to `do_not_accelerate_distance_queries()`
/// was made since object creation or the last call to `clear()`. It will be built by
/// the first distance query or by a call to `accelerate_distance_queries()`.
///@{
/// Constructs internal search tree from
/// constructs the internal search tree from
/// a point set taken on the internal primitives
/// returns `true` iff successful memory allocation
bool accelerate_distance_queries() const;
///Turns off the lazy construction of the internal search tree.
void do_not_accelerate_distance_queries() const;
bool accelerate_distance_queries();
/// turns off the usage of the internal search tree and clears it if it was already constructed.
void do_not_accelerate_distance_queries();
/// Constructs an internal KD-tree containing the specified point
/// constructs an internal KD-tree containing the specified point
/// set, to be used as the set of potential hints for accelerating
/// the distance queries.
/// the distance queries. Note that the search tree built in
/// this function will not be invalidated by the insertion of a new
/// primitive, and an explicit call to `accelerate_distance_queries()`
/// is needed to update the search tree.
/// \tparam ConstPointIterator is an iterator with
/// value type `Point_and_primitive_id`.
template<typename ConstPointIterator>
bool accelerate_distance_queries(ConstPointIterator first, ConstPointIterator beyond) const
bool accelerate_distance_queries(ConstPointIterator first, ConstPointIterator beyond)
{
#ifdef CGAL_HAS_THREADS
//this ensures that this is done once at a time
CGAL_SCOPED_LOCK(kd_tree_mutex);
#endif
clear_search_tree();
m_default_search_tree_constructed = false; // not a default kd-tree
m_use_default_search_tree = false;
return build_kd_tree(first,beyond);
}
/// Returns the minimum squared distance between the query point
/// returns the minimum squared distance between the query point
/// and all input primitives. The internal KD-tree is not used.
/// \pre `!empty()`
FT squared_distance(const Point& query, const Point& hint) const;
/// Returns the point in the union of all input primitives which
/// returns the point in the union of all input primitives which
/// is closest to the query. In case there are several closest
/// points, one arbitrarily chosen closest point is returned. The
/// internal KD-tree is not used.
/// \pre `!empty()`
Point closest_point(const Point& query, const Point& hint) const;
/// Returns a `Point_and_primitive_id` which realizes the
/// returns a `Point_and_primitive_id` which realizes the
/// smallest distance between the query point and all input
/// primitives. The internal KD-tree is not used.
/// \pre `!empty()`
@ -493,14 +490,22 @@ public:
}
// clears internal KD tree
void clear_search_tree() const
void clear_search_tree()
{
#ifdef CGAL_HAS_THREADS
if ( m_atomic_search_tree_constructed.load(std::memory_order_relaxed) )
#else
if ( m_search_tree_constructed )
#endif
{
CGAL_assertion( m_p_search_tree!=nullptr );
m_p_search_tree.reset();
#ifdef CGAL_HAS_THREADS
m_atomic_search_tree_constructed.store(false, std::memory_order_relaxed);
#else
m_search_tree_constructed = false;
}
#endif
}
}
public:
@ -532,11 +537,13 @@ public:
*
* [first,last[ is the range of primitives to be added to the tree.
*/
template<typename ConstPrimitiveIterator>
template<typename ConstPrimitiveIterator, typename ComputeBbox, typename SplitPrimitives>
void expand(Node& node,
ConstPrimitiveIterator first,
ConstPrimitiveIterator beyond,
const std::size_t range,
const ComputeBbox& compute_bbox,
const SplitPrimitives& split_primitives,
const AABBTraits&);
public:
@ -545,31 +552,43 @@ public:
{
CGAL_assertion(!empty());
return Point_and_primitive_id(
internal::Primitive_helper<AABB_traits>::get_reference_point(m_primitives[0],m_traits), m_primitives[0].id()
Helper::get_reference_point(m_primitives[0],m_traits), m_primitives[0].id()
);
}
public:
Point_and_primitive_id best_hint(const Point& query) const
{
#ifdef CGAL_HAS_THREADS
bool m_search_tree_constructed = m_atomic_search_tree_constructed.load(std::memory_order_acquire);
#endif
// lazily build the search tree in case the default should be used
if (m_use_default_search_tree && !m_search_tree_constructed)
{
#ifdef CGAL_HAS_THREADS
CGAL_SCOPED_LOCK(build_mutex);
m_search_tree_constructed = m_atomic_search_tree_constructed.load(std::memory_order_relaxed);
if (!m_search_tree_constructed)
#endif
m_search_tree_constructed = const_cast<AABB_tree*>(this)->build_kd_tree();
}
if(m_search_tree_constructed)
{
return m_p_search_tree->closest_point(query);
}
else
return this->any_reference_point_and_id();
}
//! Returns the datum (geometric object) represented `p`.
#ifndef DOXYGEN_RUNNING
typename internal::Primitive_helper<AABBTraits>::Datum_type
typename Helper::Datum_type
#else
typename AABBTraits::Primitive::Datum_reference
#endif
datum(Primitive& p)const
{
return internal::Primitive_helper<AABBTraits>::
get_datum(p, this->traits());
return Helper::get_datum(p, this->traits());
}
private:
@ -580,19 +599,23 @@ public:
// tree nodes. first node is the root node
std::vector<Node> m_p_nodes;
#ifdef CGAL_HAS_THREADS
mutable CGAL_MUTEX internal_tree_mutex;//mutex used to protect const calls inducing build()
mutable CGAL_MUTEX kd_tree_mutex;//mutex used to protect calls to accelerate_distance_queries
mutable CGAL_MUTEX build_mutex; // mutex used to protect const calls inducing build() and build_kd_tree()
#endif
const Node* root_node() const {
CGAL_assertion(size() > 1);
#ifdef CGAL_HAS_THREADS
bool m_need_build = m_atomic_need_build.load(std::memory_order_acquire);
#endif
if(m_need_build){
#ifdef CGAL_HAS_THREADS
#ifdef CGAL_HAS_THREADS
//this ensures that build() will be called once
CGAL_SCOPED_LOCK(internal_tree_mutex);
CGAL_SCOPED_LOCK(build_mutex);
m_need_build = m_atomic_need_build.load(std::memory_order_relaxed);
if(m_need_build)
#endif
const_cast< AABB_tree<AABBTraits>* >(this)->build();
#endif
const_cast< AABB_tree<AABBTraits>* >(this)->build();
}
return std::addressof(m_p_nodes[0]);
}
@ -610,9 +633,15 @@ public:
// search KD-tree
mutable std::unique_ptr<const Search_tree> m_p_search_tree;
mutable bool m_search_tree_constructed;
mutable bool m_default_search_tree_constructed; // indicates whether the internal kd-tree should be built
bool m_need_build;
bool m_use_default_search_tree = true; // indicates whether the internal kd-tree should be built
#ifdef CGAL_HAS_THREADS
std::atomic<bool> m_atomic_need_build;
std::atomic<bool> m_atomic_search_tree_constructed;
#else
bool m_need_build = false;
mutable bool m_search_tree_constructed = false;
#endif
}; // end class AABB_tree
@ -621,12 +650,10 @@ public:
template<typename Tr>
AABB_tree<Tr>::AABB_tree(const Tr& traits)
: m_traits(traits)
, m_primitives()
, m_p_nodes()
, m_p_search_tree(nullptr)
, m_search_tree_constructed(false)
, m_default_search_tree_constructed(true)
, m_need_build(false)
#ifdef CGAL_HAS_THREADS
, m_atomic_need_build(false)
, m_atomic_search_tree_constructed(false)
#endif
{}
template <typename Tr>
@ -636,9 +663,14 @@ public:
m_primitives = std::move(tree.m_primitives);
m_p_nodes = std::move(tree.m_p_nodes);
m_p_search_tree = std::move(tree.m_p_search_tree);
m_search_tree_constructed = std::exchange(tree.m_search_tree_constructed, false);
m_default_search_tree_constructed = std::exchange(tree.m_default_search_tree_constructed, true);
m_use_default_search_tree = std::exchange(tree.m_use_default_search_tree, true);
#ifdef CGAL_HAS_THREADS
m_atomic_need_build = tree.m_atomic_need_build.load(std::memory_order_relaxed);
m_atomic_search_tree_constructed = tree.m_atomic_search_tree_constructed.load(std::memory_order_relaxed);
#else
m_need_build = std::exchange(tree.m_need_build, false);
m_search_tree_constructed = std::exchange(tree.m_search_tree_constructed, false);
#endif
return *this;
}
@ -653,13 +685,10 @@ public:
AABB_tree<Tr>::AABB_tree(ConstPrimitiveIterator first,
ConstPrimitiveIterator beyond,
T&& ... t)
: m_traits()
, m_primitives()
, m_p_nodes()
, m_p_search_tree(nullptr)
, m_search_tree_constructed(false)
, m_default_search_tree_constructed(true)
, m_need_build(false)
#ifdef CGAL_HAS_THREADS
: m_atomic_need_build(false)
, m_atomic_search_tree_constructed(false)
#endif
{
// Insert each primitive into tree
insert(first, beyond,std::forward<T>(t)...);
@ -671,13 +700,19 @@ public:
ConstPrimitiveIterator beyond,
T&& ... t)
{
if (m_use_default_search_tree && first!=beyond)
clear_search_tree();
set_shared_data(std::forward<T>(t)...);
while(first != beyond)
{
m_primitives.push_back(Primitive(first,std::forward<T>(t)...));
++first;
}
#ifdef CGAL_HAS_THREADS
m_atomic_need_build.store(true, std::memory_order_relaxed);
#else
m_need_build = true;
#endif
}
// Clears tree and insert a set of primitives
@ -696,34 +731,42 @@ public:
build();
}
template<typename Tr>
template<typename ... T>
void AABB_tree<Tr>::build(T&& ... t)
{
set_shared_data(std::forward<T>(t)...);
build();
}
template<typename Tr>
template<typename ... T>
void AABB_tree<Tr>::build(T&& ... t)
{
set_shared_data(std::forward<T>(t)...);
build();
}
template<typename Tr>
void AABB_tree<Tr>::insert(const Primitive& p)
{
if (m_use_default_search_tree)
clear_search_tree();
m_primitives.push_back(p);
#ifdef CGAL_HAS_THREADS
m_atomic_need_build.store(true, std::memory_order_relaxed);
#else
m_need_build = true;
#endif
}
template<typename Tr>
template<typename ConstPrimitiveIterator>
template<typename ConstPrimitiveIterator, typename ComputeBbox, typename SplitPrimitives>
void
AABB_tree<Tr>::expand(Node& node,
ConstPrimitiveIterator first,
ConstPrimitiveIterator beyond,
const std::size_t range,
const ComputeBbox& compute_bbox,
const SplitPrimitives& split_primitives,
const Tr& traits)
{
node.set_bbox(traits.compute_bbox_object()(first, beyond));
node.set_bbox(compute_bbox(first, beyond));
// sort primitives along longest axis aabb
traits.split_primitives_object()(first, beyond, node.bbox());
split_primitives(first, beyond, node.bbox());
switch(range)
{
@ -732,13 +775,13 @@ public:
break;
case 3:
node.set_children(*first, new_node());
expand(node.right_child(), first+1, beyond, 2, traits);
expand(node.right_child(), first+1, beyond, 2, compute_bbox, split_primitives, traits);
break;
default:
const std::size_t new_range = range/2;
node.set_children(new_node(), new_node());
expand(node.left_child(), first, first + new_range, new_range, traits);
expand(node.right_child(), first + new_range, beyond, range - new_range, traits);
expand(node.left_child(), first, first + new_range, new_range, compute_bbox, split_primitives, traits);
expand(node.right_child(), first + new_range, beyond, range - new_range, compute_bbox, split_primitives, traits);
}
}
@ -746,6 +789,17 @@ public:
// Build the data structure, after calls to insert(..)
template<typename Tr>
void AABB_tree<Tr>::build()
{
custom_build(m_traits.compute_bbox_object(),
m_traits.split_primitives_object());
}
#ifndef DOXYGEN_RUNNING
// Build the data structure, after calls to insert(..)
template<typename Tr>
template <class ComputeBbox, class SplitPrimitives>
void AABB_tree<Tr>::custom_build(
const ComputeBbox& compute_bbox,
const SplitPrimitives& split_primitives)
{
clear_nodes();
@ -755,38 +809,33 @@ public:
m_p_nodes.reserve(m_primitives.size()-1);
// constructs the tree
expand(new_node(), m_primitives.begin(), m_primitives.end(),
m_primitives.size(), m_traits);
}
// In case the users has switched on the accelerated distance query
// data structure with the default arguments, then it has to be
// /built/rebuilt.
if(m_default_search_tree_constructed && !empty()){
build_kd_tree();
expand(new_node(),
m_primitives.begin(), m_primitives.end(),
m_primitives.size(),
compute_bbox,
split_primitives,
m_traits);
}
#ifdef CGAL_HAS_THREADS
m_atomic_need_build.store(false, std::memory_order_release); // in case build() is triggered by a call to root_node()
#else
m_need_build = false;
#endif
}
#endif
// constructs the search KD tree from given points
// to accelerate the distance queries
template<typename Tr>
bool AABB_tree<Tr>::build_kd_tree() const
bool AABB_tree<Tr>::build_kd_tree()
{
// iterate over primitives to get reference points on them
std::vector<Point_and_primitive_id> points;
points.reserve(m_primitives.size());
typename Primitives::const_iterator it;
for(it = m_primitives.begin(); it != m_primitives.end(); ++it)
points.push_back( Point_and_primitive_id(
internal::Primitive_helper<AABB_traits>::get_reference_point(
*it,m_traits), it->id() ) );
for(const Primitive& p : m_primitives)
points.push_back( Point_and_primitive_id( Helper::get_reference_point(p, m_traits), p.id() ) );
// clears current KD tree
clear_search_tree();
bool res = build_kd_tree(points.begin(), points.end());
m_default_search_tree_constructed = true;
return res;
return build_kd_tree(points.begin(), points.end());
}
// constructs the search KD tree from given points
@ -794,49 +843,32 @@ public:
template<typename Tr>
template<typename ConstPointIterator>
bool AABB_tree<Tr>::build_kd_tree(ConstPointIterator first,
ConstPointIterator beyond) const
ConstPointIterator beyond)
{
clear_search_tree();
m_p_search_tree = std::make_unique<const Search_tree>(first, beyond);
m_default_search_tree_constructed = true;
m_search_tree_constructed = true;
return true;
#ifdef CGAL_HAS_THREADS
m_atomic_search_tree_constructed.store(true, std::memory_order_release); // in case build_kd_tree() is triggered by a call to best_hint()
#else
m_search_tree_constructed = true;
#endif
return true;
}
template<typename Tr>
void AABB_tree<Tr>::do_not_accelerate_distance_queries()const
void AABB_tree<Tr>::do_not_accelerate_distance_queries()
{
clear_search_tree();
m_default_search_tree_constructed = false;
m_use_default_search_tree = false;
}
// constructs the search KD tree from internal primitives
template<typename Tr>
bool AABB_tree<Tr>::accelerate_distance_queries() const
bool AABB_tree<Tr>::accelerate_distance_queries()
{
m_use_default_search_tree = true;
if(m_primitives.empty()) return true;
if (m_default_search_tree_constructed)
{
if (!m_need_build) return m_search_tree_constructed;
return true; // default return type, no tree built
}
if(!m_need_build) // the tree was already built, build the kd-tree
{
#ifdef CGAL_HAS_THREADS
//this ensures that this function will be done once
CGAL_SCOPED_LOCK(kd_tree_mutex);
#endif
if (!m_need_build)
{
// clears current KD tree
clear_search_tree();
bool res = build_kd_tree();
m_default_search_tree_constructed = true;
return res;
};
}
m_default_search_tree_constructed = true;
return m_search_tree_constructed;
return build_kd_tree();
}
template<typename Tr>

View File

@ -88,7 +88,7 @@ class AABB_triangle_primitive
Tag_false,
CacheDatum > Base;
public:
///Constructor from an iterator
///constructor from an iterator
AABB_triangle_primitive(Iterator it) : Base(it){}
};

View File

@ -111,6 +111,7 @@ private:
}; // end class AABB_node
template<typename Tr>
template<class Traversal_traits, class Query>
void

View File

@ -47,6 +47,9 @@ not provide any guarantee on the topology of the surface.
We describe next the algorithm and provide examples.
\note A \ref tuto_reconstruction "detailed tutorial on surface reconstruction"
is provided with a guide to choose the most appropriate method along
with pre- and post-processing.
\section AFSR_Definitions Definitions and the Algorithm

View File

@ -1,6 +1,7 @@
#include <iostream>
#include <fstream>
#include <algorithm>
#include <array>
#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
#include <CGAL/Shape_detection/Efficient_RANSAC.h>
@ -36,7 +37,7 @@ typedef CGAL::Triangulation_data_structure_3<LVb,LCb> Tds;
typedef CGAL::Delaunay_triangulation_3<Kernel,Tds> Triangulation_3;
typedef Triangulation_3::Vertex_handle Vertex_handle;
typedef CGAL::cpp11::array<std::size_t,3> Facet;
typedef std::array<std::size_t,3> Facet;
// Functor to init the advancing front algorithm with indexed points

View File

@ -1,10 +1,10 @@
#include <iostream>
#include <fstream>
#include <algorithm>
#include <array>
#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
#include <CGAL/Advancing_front_surface_reconstruction.h>
#include <CGAL/Surface_mesh.h>
#include <CGAL/array.h>
#include <CGAL/disable_warnings.h>
typedef std::array<std::size_t,3> Facet;

View File

@ -430,7 +430,11 @@ public:
Curve_analysis_2 operator()
(const Polynomial_2& f) const {
return _m_kernel->curve_cache_2()(f);
if (_m_kernel->is_square_free_2_object()(f)) {
return _m_kernel->curve_cache_2()(f);
} else {
return _m_kernel->curve_cache_2()(_m_kernel->make_square_free_2_object()(f));
}
}
protected:

View File

@ -39,7 +39,7 @@ public:
typedef typename Algebraic_kernel_d_1::Algebraic_real_1 Algebraic_real_1;
Bitstream_coefficient_kernel_at_alpha_rep() {}
Bitstream_coefficient_kernel_at_alpha_rep() : _m_kernel(nullptr) {}
Bitstream_coefficient_kernel_at_alpha_rep(Algebraic_kernel_d_1* kernel,
Algebraic_real_1 alpha)

View File

@ -41,11 +41,11 @@ int main()
int n;
is >> n;
std::cout << "Reading " << n << " points " << std::endl;
Bare_point bp;
for( ; n>0 ; n--) {
is >> bp;
Weighted_point p(bp, 0.0001 * random.get_double(0., 0.015625)); // arbitrary weights
pts.push_back(p);
for( ; n>0 ; n--)
{
Bare_point bp;
if(is >> bp)
pts.emplace_back(bp, 0.0001 * random.get_double(0., 0.015625)); // arbitrary weights
}
// Define the periodic cube

View File

@ -22,8 +22,8 @@ ArrangementDemoGraphicsView::ArrangementDemoGraphicsView( QWidget* parent ) :
gridColor( ::Qt::black ),
backgroundColor( ::Qt::white )
{
QMatrix m( 1.0, 0.0, 0.0, -1.0, 0.0, 0.0 );
this->setMatrix( m );
QTransform m( 1.0, 0.0, 0.0, -1.0, 0.0, 0.0 );
this->setTransform( m );
this->setBackgroundBrush( QBrush( backgroundColor ) );
}
@ -109,10 +109,10 @@ QRectF ArrangementDemoGraphicsView::getViewportRect( ) const
QPointF p1 = this->mapToScene( 0, 0 );
QPointF p2 = this->mapToScene( this->width( ), this->height( ) );
double xmin = std::min( p1.x( ), p2.x( ) );
double xmax = std::max( p1.x( ), p2.x( ) );
double ymin = std::min( p1.y( ), p2.y( ) );
double ymax = std::max( p1.y( ), p2.y( ) );
double xmin = (std::min)( p1.x( ), p2.x( ) );
double xmax = (std::max)( p1.x( ), p2.x( ) );
double ymin = (std::min)( p1.y( ), p2.y( ) );
double ymax = (std::max)( p1.y( ), p2.y( ) );
QRectF res = QRectF( QPointF( xmin, ymin ), QPointF( xmax, ymax ) );

View File

@ -43,7 +43,7 @@ class ArrangementDemoPropertiesDialog : public QDialog
};
ArrangementDemoPropertiesDialog( ArrangementDemoWindow* parent_ = 0,
Qt::WindowFlags f = 0 );
Qt::WindowFlags f = Qt::WindowType(0));
QVariant property( int index );
protected:

View File

@ -14,7 +14,7 @@
#include "ui_NewTabDialog.h"
#include <QButtonGroup>
NewTabDialog::NewTabDialog( QWidget* parent, Qt::WindowFlags f ) :
NewTabDialog::NewTabDialog( QWidget* parent, Qt::WindowFlags f) :
QDialog( parent, f ),
ui( new Ui::NewTabDialog ),
buttonGroup( new QButtonGroup )

View File

@ -23,7 +23,7 @@ namespace Ui
class NewTabDialog : public QDialog
{
public:
NewTabDialog( QWidget* parent = 0, Qt::WindowFlags f = 0 );
NewTabDialog( QWidget* parent = 0, Qt::WindowFlags f = Qt::WindowType(0) );
int checkedId( ) const;
protected:

View File

@ -29,7 +29,7 @@ class OverlayDialog : public QDialog
ARRANGEMENT = 32
} OverlayDialogRole;
OverlayDialog( ArrangementDemoWindow* parent, Qt::WindowFlags f = 0 );
OverlayDialog( ArrangementDemoWindow* parent, Qt::WindowFlags f = Qt::WindowType(0) );
std::vector< CGAL::Object > selectedArrangements( ) const;

View File

@ -127,7 +127,11 @@ protected:
void highlightPointLocation( QGraphicsSceneMouseEvent *event );
Face_const_handle getFace( const CGAL::Object& o );
CGAL::Object rayShootUp( const Kernel_point_2& point );
CGAL::Object rayShootUp( const Kernel_point_2& point, CGAL::Tag_true );
CGAL::Object rayShootUp( const Kernel_point_2& point, CGAL::Tag_false );
CGAL::Object rayShootDown( const Kernel_point_2& point );
CGAL::Object rayShootDown( const Kernel_point_2& point, CGAL::Tag_true );
CGAL::Object rayShootDown( const Kernel_point_2& point, CGAL::Tag_false );
using Superclass::scene;
using Superclass::shootingUp;
@ -304,6 +308,14 @@ VerticalRayShootCallback< Arr_ >::getFace( const CGAL::Object& obj )
template < typename Arr_ >
CGAL::Object
VerticalRayShootCallback< Arr_ >::rayShootUp( const Kernel_point_2& pt )
{
typename Supports_landmarks< Arrangement >::Tag supportsLandmarks;
return this->rayShootUp( pt, supportsLandmarks );
}
template < typename Arr_ >
CGAL::Object VerticalRayShootCallback< Arr_ >::rayShootUp( const Kernel_point_2& pt,
CGAL::Tag_true )
{
CGAL::Object pointLocationResult;
Walk_pl_strategy* walkStrategy;
@ -334,9 +346,48 @@ VerticalRayShootCallback< Arr_ >::rayShootUp( const Kernel_point_2& pt )
return pointLocationResult;
}
template < typename Arr_ >
CGAL::Object VerticalRayShootCallback< Arr_ >::rayShootUp( const Kernel_point_2& pt,
CGAL::Tag_false )
{
CGAL::Object pointLocationResult;
Walk_pl_strategy* walkStrategy;
TrapezoidPointLocationStrategy* trapezoidStrategy;
SimplePointLocationStrategy* simpleStrategy;
Point_2 point = this->toArrPoint( pt );
if ( CGAL::assign( walkStrategy, this->pointLocationStrategy ) )
{
pointLocationResult = walkStrategy->ray_shoot_up( point );
}
else if ( CGAL::assign( trapezoidStrategy, this->pointLocationStrategy ) )
{
pointLocationResult = trapezoidStrategy->ray_shoot_up( point );
}
else if ( CGAL::assign( simpleStrategy, this->pointLocationStrategy ) )
{
pointLocationResult = simpleStrategy->ray_shoot_up( point );
}
else
{
std::cout<<"Didn't find the right strategy\n";
}
return pointLocationResult;
}
template < typename Arr_ >
CGAL::Object
VerticalRayShootCallback< Arr_ >::rayShootDown( const Kernel_point_2& pt )
{
typename Supports_landmarks< Arrangement >::Tag supportsLandmarks;
return this->rayShootDown( pt, supportsLandmarks );
}
template < typename Arr_ >
CGAL::Object
VerticalRayShootCallback< Arr_ >::rayShootDown( const Kernel_point_2& pt, CGAL::Tag_true )
{
CGAL::Object pointLocationResult;
Walk_pl_strategy* walkStrategy;
@ -367,4 +418,30 @@ VerticalRayShootCallback< Arr_ >::rayShootDown( const Kernel_point_2& pt )
return pointLocationResult;
}
template < typename Arr_ >
CGAL::Object
VerticalRayShootCallback< Arr_ >::rayShootDown( const Kernel_point_2& pt, CGAL::Tag_false )
{
CGAL::Object pointLocationResult;
Walk_pl_strategy* walkStrategy;
TrapezoidPointLocationStrategy* trapezoidStrategy;
SimplePointLocationStrategy* simpleStrategy;
Point_2 point = this->toArrPoint( pt );
if ( CGAL::assign( walkStrategy, this->pointLocationStrategy ) )
{
pointLocationResult = walkStrategy->ray_shoot_down( point );
}
else if ( CGAL::assign( trapezoidStrategy, this->pointLocationStrategy ) )
{
pointLocationResult = trapezoidStrategy->ray_shoot_down( point );
}
else if ( CGAL::assign( simpleStrategy, this->pointLocationStrategy ) )
{
pointLocationResult = simpleStrategy->ray_shoot_down( point );
}
return pointLocationResult;
}
#endif // VERTICAL_RAY_SHOOT_CALLBACK_H

View File

@ -285,8 +285,8 @@ virtual void before_split_face (Face_handle f,
Halfedge_handle e);
/*!
issued immediately after the existing face `f1` has been split,
such that a portion of it now forms a new face `f2`. The flag
issued immediately after the existing face `f1` has been split
into the two faces `f1` and `f2`. The flag
`is_hole` designates whether `f2` forms a hole inside `f1`.
*/
virtual void after_split_face (Face_handle f1,

View File

@ -16,21 +16,19 @@ public:
/// A model of this concept must provide:
/// @{
/*!
computes the intersections of `xc1` and `xc2` and
inserts them <I>in an ascending lexicographic \f$ xy\f$-order</I> into the
output iterator `oi`. The value-type of `Output_iterator` is
`CGAL::Object`, where each `Object` wraps either a
`pair<ArrTraits::Point_2,ArrTraits::Multiplicity>` object, which
represents an intersection point with its multiplicity (in case the
multiplicity is undefined or unknown, it should be set to \f$ 0\f$) or an
`ArrTraits::X_monotone_curve_2` object, representing an
overlapping subcurve of `xc1` and `xc2`. The operator
returns a past-the-end iterator for the output sequence.
*/
Output_iterator operator()(ArrTraits::X_monotone_curve_2 xc1,
ArrTraits::X_monotone_curve_2 xc2,
Output_iterator& oi);
/*! computes the intersections of `xc1` and `xc2` and inserts them <I>in an
* ascending lexicographic \f$ xy\f$-order</I> into a range begining at
* `oi`. The type `OutputIterator` dereferences a `boost::variant` of either the
* type `pair<ArrTraits::Point_2,ArrTraits::Multiplicity>` or the type
* `ArrTraits::X_monotone_curve_2`. An object of the former type represents an
* intersection point with its multiplicity (in case the multiplicity is
* undefined or unknown, it should be set to \f$ 0\f$). An object of the latter
* type representing an overlapping subcurve of `xc1` and `xc2`. The operator
* returns a past-the-end iterator of the destination range.
*/
OutputIterator operator()(ArrTraits::X_monotone_curve_2 xc1,
ArrTraits::X_monotone_curve_2 xc2,
Output_iterator& oi);
/// @}

View File

@ -7,9 +7,10 @@
// $Id$
// SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-Commercial
//
// Author(s) : Ron Wein <wein@post.tau.ac.il>
// Baruch Zukerman <baruchzu@post.tau.ac.il>
// Waqar Khan <wkhan@mpi-inf.mpg.de>
// Author(s): Ron Wein <wein@post.tau.ac.il>
// Baruch Zukerman <baruchzu@post.tau.ac.il>
// Waqar Khan <wkhan@mpi-inf.mpg.de>
// Efi Fogel <efifogel@gmail.com>
#ifndef CGAL_ARR_CIRCLE_SEGMENT_TRAITS_2_H
#define CGAL_ARR_CIRCLE_SEGMENT_TRAITS_2_H
@ -546,21 +547,15 @@ public:
return Split_2();
}
class Intersect_2
{
class Intersect_2 {
private:
Intersection_map& _inter_map; // The map of intersection points.
Intersection_map& _inter_map; // The map of intersection points.
public:
/*! Constructor. */
Intersect_2 (Intersection_map& map) :
_inter_map (map)
{}
Intersect_2(Intersection_map& map) : _inter_map(map) {}
/*!
* Find the intersections of the two given curves and insert them to the
/*! Find the intersections of the two given curves and insert them to the
* given output iterator. As two segments may itersect only once, only a
* single will be contained in the iterator.
* \param cv1 The first curve.
@ -568,20 +563,15 @@ public:
* \param oi The output iterator.
* \return The past-the-end iterator.
*/
template<class OutputIterator>
OutputIterator operator() (const X_monotone_curve_2& cv1,
const X_monotone_curve_2& cv2,
OutputIterator oi) const
{
return (cv1.intersect (cv2, oi, &_inter_map));
}
template <typename OutputIterator>
OutputIterator operator()(const X_monotone_curve_2& cv1,
const X_monotone_curve_2& cv2,
OutputIterator oi) const
{ return (cv1.intersect(cv2, oi, &_inter_map)); }
};
/*! Get an Intersect_2 functor object. */
Intersect_2 intersect_2_object () const
{
return (Intersect_2 (inter_map));
}
Intersect_2 intersect_2_object() const { return (Intersect_2(inter_map)); }
class Are_mergeable_2
{
@ -706,14 +696,11 @@ public:
friend class Arr_circle_segment_traits_2<Kernel, Filter>;
public:
/*!\brief
* Returns a trimmed version of an arc
*
/*! Obtain a trimmed version of an arc
* \param xcv The arc
* \param src the new first endpoint
* \param tgt the new second endpoint
* \return The trimmed arc
*
* \pre src != tgt
* \pre both points must be interior and must lie on \c cv
*/

View File

@ -22,7 +22,6 @@
#include <CGAL/disable_warnings.h>
/*! \file
* This file was developed at Inria, France, and copied over to the
* Arrangement_2 package, which it is now part of. It contains a traits
@ -30,12 +29,13 @@
* It is based on the circular kernel.
*/
#include <CGAL/basic.h>
#include <boost/variant.hpp>
#include <CGAL/Arr_tags.h>
#include <vector>
#include <boost/variant.hpp>
#include <CGAL/basic.h>
#include <CGAL/Arr_tags.h>
namespace CGAL {
namespace VariantFunctors{
@ -47,9 +47,9 @@ namespace CGAL {
object_to_object_variant(const std::vector<CGAL::Object>& res1,
OutputIterator res2)
{
for(std::vector<CGAL::Object>::const_iterator it = res1.begin();
it != res1.end(); ++it ){
if(const Arc1 *arc = CGAL::object_cast< Arc1 >(&*it)){
for (std::vector<CGAL::Object>::const_iterator it = res1.begin();
it != res1.end(); ++it ) {
if (const Arc1 *arc = CGAL::object_cast< Arc1 >(&*it)){
boost::variant< Arc1, Arc2 > v = *arc;
*res2++ = make_object(v);
}
@ -64,29 +64,27 @@ namespace CGAL {
return res2;
}
template <class CircularKernel, class Arc1, class Arc2>
class In_x_range_2
template <class CK, class Arc,
class IntersectionPoint, class XMonotoneCurve,
class InternaType, class OutputIterator>
OutputIterator
object_to_object_variant1(const std::vector<InternaType>& res,
OutputIterator oi)
{
public:
typedef typename CircularKernel::Circular_arc_point_2
Circular_arc_point_2;
typedef bool result_type;
typedef IntersectionPoint Intersection_point;
typedef XMonotoneCurve X_monotone_curve_2;
typedef boost::variant<Intersection_point, X_monotone_curve_2>
Intersection_result;
result_type
operator()(const boost::variant< Arc1, Arc2 > &a,
const Circular_arc_point_2 &p) const
{
if ( const Arc1* arc1 = boost::get<Arc1>( &a ) ){
return CircularKernel().in_x_range_2_object()(*arc1, p);
}
else {
const Arc2* arc2 = boost::get<Arc2>( &a );
return CircularKernel().in_x_range_2_object()(*arc2, p);
for (auto it = res.begin(); it != res.end(); ++it) {
if (const Arc* arc = boost::get<Arc>(&*it)) {
X_monotone_curve_2 cv = *arc;
*oi++ = Intersection_result(cv);
}
else *oi++ = Intersection_result(*it);
}
};
return oi;
}
template <class CircularKernel, class Arc1, class Arc2>
class Compare_y_to_right_2
@ -277,7 +275,7 @@ namespace CGAL {
CircularKernel()
.make_x_monotone_2_object()(*arc1,std::back_inserter(container));
return object_to_object_variant<CircularKernel, Arc1, Arc2>
(container, res);
(container, res);
}
else {
const Arc2* arc2 = boost::get<Arc2>( &A );
@ -285,65 +283,42 @@ namespace CGAL {
CircularKernel()
.make_x_monotone_2_object()(*arc2,std::back_inserter(container));
return object_to_object_variant<CircularKernel, Arc1, Arc2>
(container, res);
(container, res);
}
}
};
template <class CircularKernel, class Arc1, class Arc2>
class Intersect_2
{
public:
typedef typename CircularKernel::Circular_arc_point_2
Circular_arc_point_2;
typedef typename CircularKernel::Circular_arc_point_2
Circular_arc_point_2;
template < class OutputIterator >
OutputIterator
operator()(const boost::variant< Arc1, Arc2 > &c1,
const boost::variant< Arc1, Arc2 > &c2,
OutputIterator res) const
OutputIterator oi) const
{
if ( const Arc1* arc1 = boost::get<Arc1>( &c1 ) ){
if ( const Arc1* arc2 = boost::get<Arc1>( &c2 ) ){
std::vector<CGAL::Object> container;
CircularKernel()
.intersect_2_object()(*arc1,*arc2,std::back_inserter(container));
return object_to_object_variant<CircularKernel, Arc1, Arc2>
(container, res);
}
else if ( const Arc2* arc2 = boost::get<Arc2>( &c2 ) ){
std::vector<CGAL::Object> container;
CircularKernel()
.intersect_2_object()(*arc1,*arc2,std::back_inserter(container));
return object_to_object_variant<CircularKernel, Arc1, Arc2>
(container, res);
}
}
else {
const Arc2* arc1e = boost::get<Arc2>( &c1 );
if ( const Arc1* arc2 = boost::get<Arc1>( &c2 ) ){
std::vector<CGAL::Object> container;
CircularKernel()
.intersect_2_object()(*arc1e,*arc2,std::back_inserter(container));
return object_to_object_variant<CircularKernel, Arc1, Arc2>
(container, res);
return CircularKernel().intersect_2_object()(*arc1, *arc2, oi);
}
const Arc2* arc2 = boost::get<Arc2>( &c2 );
std::vector<CGAL::Object> container;
CircularKernel()
.intersect_2_object()(*arc1e,*arc2,std::back_inserter(container));
return object_to_object_variant<CircularKernel, Arc1, Arc2>
(container, res);
return CircularKernel().intersect_2_object()(*arc1, *arc2, oi);
}
CGAL_error();
return res;//for no warning
const Arc2* arc1e = boost::get<Arc2>( &c1 );
if ( const Arc1* arc2 = boost::get<Arc1>( &c2 ) ){
return CircularKernel().intersect_2_object()(*arc1e, *arc2, oi);
}
const Arc2* arc2 = boost::get<Arc2>( &c2 );
return CircularKernel().intersect_2_object()(*arc1e, *arc2, oi);
}
};
template <class CircularKernel, class Arc1, class Arc2>
class Split_2
{
@ -533,7 +508,7 @@ namespace CGAL {
typedef unsigned int Multiplicity;
typedef CGAL::Tag_false Has_left_category;
typedef CGAL::Tag_false Has_merge_category;
typedef CGAL::Tag_false Has_merge_category;
typedef CGAL::Tag_false Has_do_intersect_category;
typedef Arr_oblivious_side_tag Left_side_category;

View File

@ -8,8 +8,8 @@
// SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-Commercial
//
//
// Author(s) : Ron Wein <wein@post.tau.ac.il>
// Waqar Khan <wkhan@mpi-inf.mpg.de>
// Author(s): Ron Wein <wein@post.tau.ac.il>
// Waqar Khan <wkhan@mpi-inf.mpg.de>
#ifndef CGAL_ARR_CONIC_TRAITS_2_H
#define CGAL_ARR_CONIC_TRAITS_2_H
@ -22,6 +22,8 @@
* The conic traits-class for the arrangement package.
*/
#include <fstream>
#include <CGAL/atomic.h>
#include <CGAL/tags.h>
#include <CGAL/Arr_tags.h>
@ -29,8 +31,6 @@
#include <CGAL/Arr_geometry_traits/Conic_x_monotone_arc_2.h>
#include <CGAL/Arr_geometry_traits/Conic_point_2.h>
#include <fstream>
namespace CGAL {
/*!
@ -88,8 +88,7 @@ private:
// Type definition for the intersection points mapping.
typedef typename X_monotone_curve_2::Conic_id Conic_id;
typedef typename X_monotone_curve_2::Intersection_point_2
Intersection_point_2;
typedef typename X_monotone_curve_2::Intersection_point Intersection_point;
typedef typename X_monotone_curve_2::Intersection_map Intersection_map;
mutable Intersection_map inter_map; // Mapping conic pairs to their
@ -604,21 +603,15 @@ public:
return Split_2();
}
class Intersect_2
{
class Intersect_2 {
private:
Intersection_map& _inter_map; // The map of intersection points.
Intersection_map& _inter_map; // The map of intersection points.
public:
/*! Constructor. */
Intersect_2 (Intersection_map& map) :
_inter_map (map)
{}
Intersect_2(Intersection_map& map) : _inter_map(map) {}
/*!
* Find the intersections of the two given curves and insert them to the
/*! Find the intersections of the two given curves and insert them to the
* given output iterator. As two segments may itersect only once, only a
* single will be contained in the iterator.
* \param cv1 The first curve.
@ -626,20 +619,15 @@ public:
* \param oi The output iterator.
* \return The past-the-end iterator.
*/
template<class OutputIterator>
OutputIterator operator() (const X_monotone_curve_2& cv1,
const X_monotone_curve_2& cv2,
OutputIterator oi) const
{
return (cv1.intersect (cv2, _inter_map, oi));
}
template <typename OutputIterator>
OutputIterator operator()(const X_monotone_curve_2& cv1,
const X_monotone_curve_2& cv2,
OutputIterator oi) const
{ return (cv1.intersect(cv2, _inter_map, oi)); }
};
/*! Get an Intersect_2 functor object. */
Intersect_2 intersect_2_object () const
{
return (Intersect_2 (inter_map));
}
Intersect_2 intersect_2_object () const { return (Intersect_2(inter_map)); }
class Are_mergeable_2
{

View File

@ -7,8 +7,8 @@
// $Id$
// SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-Commercial
//
// Author(s) : Ron Wein <wein@post.tau.ac.il>
// Efi Fogel <efifogel@gmail.com>
// Author(s): Ron Wein <wein@post.tau.ac.il>
// Efi Fogel <efifogel@gmail.com>
#ifndef CGAL_ARR_CURVE_DATA_TRAITS_2_H
#define CGAL_ARR_CURVE_DATA_TRAITS_2_H
@ -22,6 +22,8 @@
*/
#include <list>
#include <boost/variant.hpp>
#include <boost/utility/enable_if.hpp>
#include <boost/mpl/has_xxx.hpp>
@ -193,35 +195,40 @@ public:
* \param oi The output iterator.
* \return The past-the-end iterator.
*/
template<typename OutputIterator>
template <typename OutputIterator>
OutputIterator operator()(const X_monotone_curve_2& cv1,
const X_monotone_curve_2& cv2,
OutputIterator oi) const
{
typedef std::pair<Point_2, Multiplicity> Intersection_point;
typedef boost::variant<Intersection_point, X_monotone_curve_2>
Intersection_result;
typedef boost::variant<Intersection_point, Base_x_monotone_curve_2>
Intersection_base_result;
// Use the base functor to obtain all intersection objects.
std::list<CGAL::Object> base_objects;
std::list<Intersection_base_result> base_objects;
m_base.intersect_2_object()(cv1, cv2, std::back_inserter(base_objects));
// Stop if the list is empty:
if (base_objects.empty()) return oi;
// Go over all intersection objects and prepare the output.
const Base_x_monotone_curve_2* base_cv;
for (typename std::list<CGAL::Object>::const_iterator it =
base_objects.begin(); it != base_objects.end(); ++it)
{
if ((base_cv = object_cast<Base_x_monotone_curve_2>(&(*it))) != nullptr) {
for (const auto& item : base_objects) {
const Base_x_monotone_curve_2* base_cv =
boost::get<Base_x_monotone_curve_2>(&item);
if (base_cv != nullptr) {
// The current intersection object is an overlapping x-monotone
// curve: Merge the data fields of both intersecting curves and
// associate the result with the overlapping curve.
X_monotone_curve_2 cv(*base_cv, Merge() (cv1.data(), cv2.data()));
*oi++ = make_object(cv);
}
else {
// The current intersection object is an intersection point:
// Copy it as is.
*oi++ = *it;
X_monotone_curve_2 cv(*base_cv, Merge()(cv1.data(), cv2.data()));
*oi++ = Intersection_result(cv);
continue;
}
// The current intersection object is an intersection point:
// Copy it as is.
const Intersection_point* ip = boost::get<Intersection_point>(&item);
*oi++ = Intersection_result(*ip);
}
return oi;

View File

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

View File

@ -7,7 +7,7 @@
// $Id$
// SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-Commercial
//
// Author(s) : Efi Fogel <efif@post.tau.ac.il>
// Author(s) : Efi Fogel <efif@post.tau.ac.il>
#ifndef CGAL_ARR_GEODESIC_ARC_ON_SPHERE_TRAITS_2_H
#define CGAL_ARR_GEODESIC_ARC_ON_SPHERE_TRAITS_2_H
@ -25,6 +25,8 @@
#include <fstream>
#include <boost/variant.hpp>
#include <CGAL/config.h>
#include <CGAL/tags.h>
#include <CGAL/tss.h>
@ -1646,7 +1648,10 @@ public:
Project project,
OutputIterator oi) const
{
typedef std::pair<Point_2, Multiplicity> Point_2_pair;
typedef std::pair<Point_2, Multiplicity> Intersection_point;
typedef boost::variant<Intersection_point, X_monotone_curve_2>
Intersection_result;
const Kernel* kernel = m_traits;
typename Kernel::Equal_2 equal = kernel->equal_2_object();
@ -1658,7 +1663,7 @@ public:
if (equal(l1, l2)) {
const Point_2& trg = (in_between(r1, l2, r2)) ? r1_3 : r2_3;
X_monotone_curve_2 xc(l1_3, trg, normal, vertical, true);
*oi++ = make_object(xc);
*oi++ = Intersection_result(xc);
return oi;
}
@ -1668,29 +1673,29 @@ public:
if (l1_eq_start || (!l2_eq_start && in_between(l1, start, l2))) {
// The following applies only to full circles:
if (l1_eq_start && equal(r2, start))
*oi++ = make_object(Point_2_pair(r2_3, 1));
*oi++ = Intersection_result(Intersection_point(r2_3, 1));
if (in_between(r1, l1, l2)) return oi; // no intersection
if (equal(r1, l2)) {
*oi++ = make_object(Point_2_pair(r1_3, 1));
*oi++ = Intersection_result(Intersection_point(r1_3, 1));
return oi;
}
const Point_2& trg = (in_between(r1, l2, r2)) ? r1_3 : r2_3;
X_monotone_curve_2 xc(l2_3, trg, normal, vertical, true);
*oi++ = make_object(xc);
*oi++ = Intersection_result(xc);
return oi;
}
CGAL_assertion(l2_eq_start || in_between(l2, start, l1));
// The following applies only to full circles:
if (l2_eq_start && equal(r1, start))
*oi++ = make_object(Point_2_pair(r1_3, 1));
*oi++ = Intersection_result(Intersection_point(r1_3, 1));
if (in_between(r2, l2, l1)) return oi; // no intersection
if (equal(r2, l1)) {
*oi++ = make_object(Point_2_pair(r2_3, 1));
*oi++ = Intersection_result(Intersection_point(r2_3, 1));
return oi;
}
const Point_2& trg = (in_between(r1, l2, r2)) ? r1_3 : r2_3;
X_monotone_curve_2 xc(l1_3, trg, normal, vertical, true);
*oi++ = make_object(xc);
*oi++ = Intersection_result(xc);
return oi;
}
@ -1784,9 +1789,12 @@ public:
typedef Arr_geodesic_arc_on_sphere_traits_2<Kernel> Traits;
typedef typename Kernel::Counterclockwise_in_between_2
Counterclockwise_in_between_2;
typedef typename Kernel::Equal_3 Equal_3;
typedef typename Kernel::Equal_3 Equal_3;
typedef std::pair<Point_2, Multiplicity> Intersection_point;
typedef boost::variant<Intersection_point, X_monotone_curve_2>
Intersection_result;
typedef std::pair<Point_2, Multiplicity> Point_2_pair;
const Kernel* kernel = m_traits;
Equal_3 equal_3 = kernel->equal_3_object();
@ -1810,9 +1818,9 @@ public:
(res && (xc1.is_directed_right() != xc2.is_directed_right())))
{
if (xc1.left().is_min_boundary() && xc2.left().is_min_boundary())
*oi++ = make_object(Point_2_pair(xc1.left(), 1));
*oi++ = Intersection_result(Intersection_point(xc1.left(), 1));
if (xc1.right().is_max_boundary() && xc2.right().is_max_boundary())
*oi++ = make_object(Point_2_pair(xc1.right(), 1));
*oi++ = Intersection_result(Intersection_point(xc1.right(), 1));
return oi;
}
@ -1820,11 +1828,11 @@ public:
* the other arc is completely overlapping.
*/
if (xc1.left().is_min_boundary() && xc1.right().is_max_boundary()) {
*oi++ = make_object(xc2);
*oi++ = Intersection_result(xc2);
return oi;
}
if (xc2.left().is_min_boundary() && xc2.right().is_max_boundary()) {
*oi++ = make_object(xc1);
*oi++ = Intersection_result(xc1);
return oi;
}
/*! Find an endpoint that does not coincide with a pole, and project
@ -1877,14 +1885,14 @@ public:
// Determine which one of the two directions:
Point_2 ed(v.direction());
if (is_in_between(ed, xc1) && is_in_between(ed, xc2)) {
*oi++ = make_object(Point_2_pair(ed, 1));
*oi++ = Intersection_result(Intersection_point(ed, 1));
return oi;
}
Vector_3 vo(kernel->construct_opposite_vector_3_object()(v));
Point_2 edo(vo.direction());
if (is_in_between(edo, xc1) && is_in_between(edo, xc2)) {
*oi++ = make_object(Point_2_pair(edo, 1));
*oi++ = Intersection_result(Intersection_point(edo, 1));
return oi;
}
return oi;
@ -1927,8 +1935,13 @@ public:
const Kernel* kernel = m_traits;
typename Kernel::Equal_3 equal = kernel->equal_3_object();
// Down cast to pass to kernel member functions
const Direction_3& xc1_left = xc1.left();
const Direction_3& xc2_left = xc2.left();
const Direction_3& xc1_right = xc1.right();
const Direction_3& xc2_right = xc2.right();
if (xc1.is_degenerate() && xc2.is_degenerate())
return equal(xc1.left(), xc2.left());
return equal(xc1_left, xc2_left);
if ((xc1.is_full() || xc1.is_meridian()) && xc2.is_degenerate())
return xc1.has_on(xc2.left());
if ((xc2.is_full() || xc2.is_meridian()) && xc1.is_degenerate())
@ -1941,8 +1954,8 @@ public:
if (!equal(normal1, normal2) && !equal(opposite_normal1, normal2))
return false;
bool eq1 = equal(xc1.right(), xc2.left());
bool eq2 = equal(xc1.left(), xc2.right());
bool eq1 = equal(xc1_right, xc2_left);
bool eq2 = equal(xc1_left, xc2_right);
#if defined(CGAL_FULL_X_MONOTONE_GEODESIC_ARC_ON_SPHERE_IS_SUPPORTED)
if (eq1 && eq2) return true;
@ -2001,14 +2014,20 @@ public:
const Kernel* kernel = m_traits;
typename Kernel::Equal_3 equal = kernel->equal_3_object();
// Down cast to pass to kernel member functions
const Direction_3& xc1_right = xc1.right();
const Direction_3& xc2_left = xc2.left();
xc.set_is_degenerate(false);
xc.set_is_empty(false);
xc.set_is_vertical(xc1.is_vertical());
bool eq1 = equal(xc1.right(), xc2.left());
bool eq1 = equal(xc1_right, xc2_left);
#if defined(CGAL_FULL_X_MONOTONE_GEODESIC_ARC_ON_SPHERE_IS_SUPPORTED)
bool eq2 = equal(xc1.left(), xc2.right());
const Direction_3& xc1_left = xc1.left();
const Direction_3& xc2_right = xc2.right();
bool eq2 = equal(xc1_left, xc2_right);
if (eq1 && eq2) {
const Point_2& p =
xc1.source().is_mid_boundary() ? xc1.source() : xc1.target();
@ -2017,8 +2036,10 @@ public:
xc.set_normal(xc1.normal());
xc.set_is_full(true);
}
#else
CGAL_assertion_code(const Direction_3& xc1_left = xc1.left();
const Direction_3& xc2_right = xc2.right());
#endif
if (xc1.is_directed_right() || xc2.is_directed_right()) {
xc.set_normal(xc1.is_directed_right() ? xc1.normal() : xc2.normal());
xc.set_is_directed_right(true);
@ -2026,20 +2047,23 @@ public:
if (eq1) {
xc.set_source(xc1.left());
xc.set_target(xc2.right());
} else {
CGAL_assertion(equal(xc1.left(), xc2.right()));
}
else {
CGAL_assertion(equal(xc1_left, xc2_right));
xc.set_source(xc2.left());
xc.set_target(xc1.right());
}
} else {
}
else {
xc.set_normal(xc1.normal());
xc.set_is_directed_right(false);
if (eq1) {
xc.set_source(xc2.right());
xc.set_target(xc1.left());
} else {
CGAL_assertion(equal(xc1.left(), xc2.right()));
}
else {
CGAL_assertion(equal(xc1_left, xc2_right));
xc.set_source(xc1.right());
xc.set_target(xc2.left());
}

View File

@ -52,11 +52,11 @@ public:
/// \name Type definitions for the intersection-point mapping.
//@{
/*! \struct Intersection_point_2
/*! \struct Intersection_point
* Representation of an intersection point (in both parameter and physical
* spaces).
*/
struct Intersection_point_2
struct Intersection_point
{
Algebraic s; // The parameter for the first curve.
Algebraic t; // The parameter for the second curve.
@ -64,7 +64,7 @@ public:
Algebraic y; // The y-coordinate.
/*! Constructor. */
Intersection_point_2 (const Algebraic& _s, const Algebraic& _t,
Intersection_point (const Algebraic& _s, const Algebraic& _t,
const Algebraic& _x, const Algebraic& _y) :
s(_s), t(_t),
x(_x), y(_y)
@ -73,7 +73,7 @@ public:
typedef std::pair<Curve_id, Curve_id> Curve_pair;
typedef std::pair<Algebraic, Algebraic> Parameter_pair;
typedef std::list<Intersection_point_2> Intersection_list;
typedef std::list<Intersection_point> Intersection_list;
typedef
typename Intersection_list::const_iterator Intersection_iter;
@ -251,7 +251,7 @@ private:
const Polynomial& polyY_1, const Integer& normY_1,
const Polynomial& polyX_2, const Integer& normX_2,
const Polynomial& polyY_2, const Integer& normY_2,
Parameter_list& s_vals) const;
Parameter_list& s_vals, bool find_out_of_range=false) const;
/*!
* Compute all s-parameter values of the self intersection of (X(s), Y(s))
@ -378,7 +378,7 @@ _Bezier_cache<NtTraits>::get_intersections
CGAL::compare (nt_traits.evaluate_at (polyY_1, *t_it),
y) == EQUAL)
{
info.first.push_back (Intersection_point_2 (*s_it, *t_it,
info.first.push_back (Intersection_point (*s_it, *t_it,
x / denX, y / denY));
}
}
@ -407,7 +407,7 @@ _Bezier_cache<NtTraits>::get_intersections
do_ovlp = _intersection_params (polyX_2, normX_2, polyY_2, normY_2,
polyX_1, normX_1, polyY_1, normY_1,
t_vals);
t_vals, true);
CGAL_assertion (! do_ovlp);
@ -457,21 +457,14 @@ _Bezier_cache<NtTraits>::get_intersections
const Algebraic one (1);
unsigned int k;
//pointers are used to set the list pts1_ptr as the one with the less values
Point_list* pts1_ptr=&pts1;
Point_list* pts2_ptr=&pts2;
bool swapt=pts1.size() > pts2.size();
if (swapt)
std::swap(pts1_ptr,pts2_ptr);
for (pit1 = pts1_ptr->begin(); pit1 != pts1_ptr->end(); ++pit1)
for (pit1 = pts1.begin(); pit1 != pts1.end(); ++pit1)
{
// Construct a vector of distances from the current point to all other
// points in the pts2 list.
const int n_pts2 = static_cast<int>(pts2_ptr->size());
const int n_pts2 = static_cast<int>(pts2.size());
std::vector<Distance_iter> dist_vec (n_pts2);
for (k = 0, pit2 = pts2_ptr->begin(); pit2 != pts2_ptr->end(); k++, ++pit2)
for (k = 0, pit2 = pts2.begin(); pit2 != pts2.end(); k++, ++pit2)
{
// Compute the approximate distance between the teo current points.
dx = pit1->app_x - pit2->app_x;
@ -508,7 +501,7 @@ _Bezier_cache<NtTraits>::get_intersections
pit1->y = pit2->y;
// Remove this point from pts2, as we found a match for it.
pts2_ptr->erase (pit2);
pts2.erase (pit2);
found = true;
}
}
@ -528,17 +521,15 @@ _Bezier_cache<NtTraits>::get_intersections
pit1->y = pit2->y;
// Remove this point from pts2, as we found a match for it.
pts2_ptr->erase (pit2);
pts2.erase (pit2);
}
// Check that s- and t-values both lie in the legal range of [0,1].
CGAL_assertion(CGAL::sign (s) != NEGATIVE && CGAL::compare (s, one) != LARGER &&
CGAL::sign (t) != NEGATIVE && CGAL::compare (t, one) != LARGER);
if (!swapt)
info.first.push_back (Intersection_point_2 (s, t,pit1->x, pit1->y));
else
info.first.push_back (Intersection_point_2 (t, s,pit1->x, pit1->y));
if(CGAL::sign (s) != NEGATIVE && CGAL::compare (s, one) != LARGER &&
CGAL::sign (t) != NEGATIVE && CGAL::compare (t, one) != LARGER)
{
info.first.push_back(Intersection_point(s, t,pit1->x, pit1->y));
}
}
info.second = false;
@ -582,7 +573,7 @@ bool _Bezier_cache<NtTraits>::_intersection_params
const Polynomial& polyY_1, const Integer& normY_1,
const Polynomial& polyX_2, const Integer& normX_2,
const Polynomial& polyY_2, const Integer& normY_2,
Parameter_list& s_vals) const
Parameter_list& s_vals, bool find_out_of_range) const
{
// Clear the output parameter list.
if (! s_vals.empty())
@ -633,8 +624,12 @@ bool _Bezier_cache<NtTraits>::_intersection_params
}
// Compute the roots of the resultant polynomial and mark that the curves do
// not overlap. The roots we are interested in must be in the interval [0,1].
nt_traits.compute_polynomial_roots (res,0,1,std::back_inserter (s_vals));
// not overlap. The roots we are interested in are usually in the interval [0,1].
if (find_out_of_range)
nt_traits.compute_polynomial_roots (res,std::back_inserter (s_vals));
else
nt_traits.compute_polynomial_roots (res,0,1,std::back_inserter (s_vals));
return (false);
}
@ -658,7 +653,7 @@ void _Bezier_cache<NtTraits>::_self_intersection_params
// II: Y(t) - Y(s) / (t - s) = 0
//
Integer *coeffs;
int i, k;
int i;
// Consruct the bivariate polynomial that corresponds to Equation I.
// Note that we represent a bivariate polynomial as a vector of univariate
@ -672,12 +667,11 @@ void _Bezier_cache<NtTraits>::_self_intersection_params
coeffs = new Integer [degX];
for (i = 0; i < degX; i++)
{
for (k = i + 1; k < degX; k++)
coeffs[k - i - 1] = nt_traits.get_coefficient (polyX, k);
coeffs[i] = nt_traits.get_coefficient(polyX, i + 1);
coeffsX_st[i] = nt_traits.construct_polynomial (coeffs, degX - i - 1);
}
for (i = 0; i < degX; i++)
coeffsX_st[degX - i - 1] =
nt_traits.construct_polynomial(coeffs + i, degX - i - 1);
delete[] coeffs;
@ -690,12 +684,11 @@ void _Bezier_cache<NtTraits>::_self_intersection_params
coeffs = new Integer [degY];
for (i = 0; i < degY; i++)
{
for (k = i + 1; k < degY; k++)
coeffs[k - i - 1] = nt_traits.get_coefficient (polyY, k);
coeffs[i] = nt_traits.get_coefficient(polyY, i + 1);
coeffsY_st[i] = nt_traits.construct_polynomial (coeffs, degY - i - 1);
}
for (i = 0; i < degY; i++)
coeffsY_st[degY - i - 1] =
nt_traits.construct_polynomial(coeffs + i, degY - i - 1);
delete[] coeffs;

View File

@ -1641,17 +1641,43 @@ void _Bezier_point_2_rep<RatKer, AlgKer, NtTrt, BndTrt>::_make_exact
const Algebraic t_min = nt_traits.convert (orig2.point_bound().t_min);
const Algebraic t_max = nt_traits.convert (orig2.point_bound().t_max);
bool self_intersecting = (org_it1->curve().id() == org_it2->curve().id());
for (intr_it = intr_list.begin(); intr_it != intr_list.end(); ++intr_it)
{
if (CGAL::compare (intr_it->s, s_min) != SMALLER &&
CGAL::compare (intr_it->s, s_max) != LARGER &&
CGAL::compare (intr_it->t, t_min) != SMALLER &&
CGAL::compare (intr_it->t, t_max) != LARGER)
auto in_bounding_interval =
[](const auto& s_, const auto& s_min_, const auto& s_max_) -> bool {
return CGAL::compare(s_, s_min_) != SMALLER &&
CGAL::compare(s_, s_max_) != LARGER;
};
bool st_in_st_range = in_bounding_interval(intr_it->s, s_min, s_max) &&
in_bounding_interval(intr_it->t, t_min, t_max);
bool ts_in_st_range = false;
if (st_in_st_range)
{
// Update the originators.
orig1.set_parameter (intr_it->s);
orig2.set_parameter (intr_it->t);
orig1.set_parameter(intr_it->s);
orig2.set_parameter(intr_it->t);
}
else if (self_intersecting)
{
// check whether s is in t range, and t is in s range
// s and t can be interchanged in case of self intersections
ts_in_st_range = in_bounding_interval(intr_it->t, s_min, s_max) &&
in_bounding_interval(intr_it->s, t_min, t_max);
if (ts_in_st_range)
{
// Update the originators.
orig1.set_parameter(intr_it->t);
orig2.set_parameter(intr_it->s);
}
}
if (st_in_st_range || ts_in_st_range)
{
// Set the exact point coordinates.
p_alg_x = new Algebraic (intr_it->x);
p_alg_y = new Algebraic (intr_it->y);

View File

@ -1830,7 +1830,7 @@ public:
typedef typename Base::Rat_vector Rat_vector;
typedef typename Base::Polynomial Polynomial;
typedef std::pair<Point_2,Multiplicity> Intersection_point_2;
typedef std::pair<Point_2,Multiplicity> Intersection_point;
/// \name Constrcution methods.
@ -1967,138 +1967,118 @@ public:
CGAL_precondition (this->is_valid() && this->is_continuous());
CGAL_precondition (arc.is_valid() && arc.is_continuous());
if (this->_has_same_base (arc))
{
Alg_kernel ker;
if (this->_has_same_base (arc)) {
Alg_kernel ker;
// Get the left and right endpoints of (*this) and their information
// bits.
const Point_2& left1 = (this->is_directed_right() ?
this->_ps : this->_pt);
const Point_2& right1 = (this->is_directed_right() ?
this->_pt : this->_ps);
int info_left1, info_right1;
const Point_2& left1 =
(this->is_directed_right() ? this->_ps : this->_pt);
const Point_2& right1 =
(this->is_directed_right() ? this->_pt : this->_ps);
int info_left1, info_right1;
if (this->is_directed_right())
{
if (this->is_directed_right()) {
info_left1 = (this->_info & this->SRC_INFO_BITS);
info_right1 = ((this->_info & this->TRG_INFO_BITS) >> 4);
}
else
{
else {
info_right1 = (this->_info & this->SRC_INFO_BITS);
info_left1 = ((this->_info & this->TRG_INFO_BITS) >> 4);
}
// Get the left and right endpoints of the other arc and their
// information bits.
const Point_2& left2 = (arc.is_directed_right() ? arc._ps : arc._pt);
const Point_2& right2 = (arc.is_directed_right() ? arc._pt : arc._ps);
int info_left2, info_right2;
const Point_2& left2 = (arc.is_directed_right() ? arc._ps : arc._pt);
const Point_2& right2 = (arc.is_directed_right() ? arc._pt : arc._ps);
int info_left2, info_right2;
if (arc.is_directed_right())
{
if (arc.is_directed_right()) {
info_left2 = (arc._info & this->SRC_INFO_BITS);
info_right2 = ((arc._info & this->TRG_INFO_BITS) >> 4);
}
else
{
else {
info_right2 = (arc._info & this->SRC_INFO_BITS);
info_left2 = ((arc._info & this->TRG_INFO_BITS) >> 4);
}
// Locate the left curve-end with larger x-coordinate.
bool at_minus_infinity = false;
Arr_parameter_space inf_l1 = this->left_infinite_in_x();
Arr_parameter_space inf_l2 = arc.left_infinite_in_x();
Point_2 p_left;
int info_left;
bool at_minus_infinity = false;
Arr_parameter_space inf_l1 = this->left_infinite_in_x();
Arr_parameter_space inf_l2 = arc.left_infinite_in_x();
Point_2 p_left;
int info_left;
if (inf_l1 == ARR_INTERIOR && inf_l2 == ARR_INTERIOR)
{
if (inf_l1 == ARR_INTERIOR && inf_l2 == ARR_INTERIOR) {
// Let p_left be the rightmost of the two left endpoints.
if (ker.compare_x_2_object() (left1, left2) == LARGER)
{
if (ker.compare_x_2_object() (left1, left2) == LARGER) {
p_left = left1;
info_left = info_left1;
}
else
{
else {
p_left = left2;
info_left = info_left2;
}
}
else if (inf_l1 == ARR_INTERIOR)
{
else if (inf_l1 == ARR_INTERIOR) {
// Let p_left be the left endpoint of (*this).
p_left = left1;
info_left = info_left1;
}
else if (inf_l2 == ARR_INTERIOR)
{
else if (inf_l2 == ARR_INTERIOR) {
// Let p_left be the left endpoint of the other arc.
p_left = left2;
info_left = info_left2;
}
else
{
else {
// Both arcs are defined at x = -oo.
at_minus_infinity = true;
info_left = info_left1;
}
// Locate the right curve-end with smaller x-coordinate.
bool at_plus_infinity = false;
Arr_parameter_space inf_r1 = this->right_infinite_in_x();
Arr_parameter_space inf_r2 = arc.right_infinite_in_x();
Point_2 p_right;
int info_right;
bool at_plus_infinity = false;
Arr_parameter_space inf_r1 = this->right_infinite_in_x();
Arr_parameter_space inf_r2 = arc.right_infinite_in_x();
Point_2 p_right;
int info_right;
if (inf_r1 == ARR_INTERIOR && inf_r2 == ARR_INTERIOR)
{
if (inf_r1 == ARR_INTERIOR && inf_r2 == ARR_INTERIOR) {
// Let p_right be the rightmost of the two right endpoints.
if (ker.compare_x_2_object() (right1, right2) == SMALLER)
{
if (ker.compare_x_2_object() (right1, right2) == SMALLER) {
p_right = right1;
info_right = info_right1;
}
else
{
else {
p_right = right2;
info_right = info_right2;
}
}
else if (inf_r1 == ARR_INTERIOR)
{
else if (inf_r1 == ARR_INTERIOR) {
// Let p_right be the right endpoint of (*this).
p_right = right1;
info_right = info_right1;
}
else if (inf_r2 == ARR_INTERIOR)
{
else if (inf_r2 == ARR_INTERIOR) {
// Let p_right be the right endpoint of the other arc.
p_right = right2;
info_right = info_right2;
}
else
{
else {
// Both arcs are defined at x = +oo.
at_plus_infinity = true;
info_right = info_right2;
}
// Check the case of two bounded (in x) ends.
if (! at_minus_infinity && ! at_plus_infinity)
{
if (! at_minus_infinity && ! at_plus_infinity) {
Comparison_result res = ker.compare_x_2_object() (p_left, p_right);
if (res == LARGER)
{
if (res == LARGER) {
// The x-range of the overlap is empty, so there is no overlap.
return (oi);
return oi;
}
else if (res == EQUAL)
{
if (res == EQUAL) {
// We have a single overlapping point. Just make sure this point
// is not at y = -/+ oo.
if (info_left &&
@ -2106,20 +2086,19 @@ public:
info_right &&
(this->SRC_AT_Y_MINUS_INFTY | this->SRC_AT_Y_PLUS_INFTY) == 0)
{
Intersection_point_2 ip (p_left, 0);
Intersection_point ip (p_left, 0);
*oi = make_object (ip);
++oi;
*oi++ = make_object (ip);
}
return (oi);
return oi;
}
}
// Create the overlapping portion of the rational arc by properly setting
// the source (left) and target (right) endpoints and their information
// bits.
Self overlap_arc (*this);
Self overlap_arc(*this);
overlap_arc._ps = p_left;
overlap_arc._pt = p_right;
@ -2128,10 +2107,9 @@ public:
this->IS_DIRECTED_RIGHT | this->IS_CONTINUOUS |
this->IS_VALID);
*oi = make_object (overlap_arc);
++oi;
*oi++ = make_object(overlap_arc);
return (oi);
return oi;
}
// We wish to find the intersection points between:
@ -2140,39 +2118,34 @@ public:
//
// It is clear that the x-coordinates of the intersection points are
// the roots of the polynomial: ip(x) = p1(x)*q2(x) - p2(x)*q1(x).
Nt_traits nt_traits;
Polynomial ipoly = this->_numer * arc._denom -
arc._numer * this->_denom;
std::list<Algebraic> xs;
Nt_traits nt_traits;
Polynomial ipoly = this->_numer * arc._denom - arc._numer* this->_denom;
std::list<Algebraic> xs;
typename std::list<Algebraic>::const_iterator x_iter;
nt_traits.compute_polynomial_roots (ipoly,
std::back_inserter(xs));
nt_traits.compute_polynomial_roots(ipoly, std::back_inserter(xs));
// Go over the x-values we obtained. For each value produce an
// intersection point if it is contained in the x-range of both curves.
unsigned int mult;
unsigned int mult;
for (x_iter = xs.begin(); x_iter != xs.end(); ++x_iter)
{
for (x_iter = xs.begin(); x_iter != xs.end(); ++x_iter) {
if (this->_is_in_true_x_range (*x_iter) &&
arc._is_in_true_x_range (*x_iter))
{
// Compute the intersection point and obtain its multiplicity.
Point_2 p (*x_iter, nt_traits.evaluate_at (this->_numer, *x_iter) /
nt_traits.evaluate_at (this->_denom, *x_iter));
Point_2 p(*x_iter, nt_traits.evaluate_at (this->_numer, *x_iter) /
nt_traits.evaluate_at (this->_denom, *x_iter));
this->compare_slopes (arc, p, mult);
this->compare_slopes(arc, p, mult);
// Output the intersection point:
Intersection_point_2 ip (p, mult);
*oi = make_object (ip);
++oi;
Intersection_point ip(p, mult);
*oi++ = make_object(ip);
}
}
return (oi);
return oi;
}
/*!

File diff suppressed because it is too large Load Diff

View File

@ -7,9 +7,9 @@
// $Id$
// SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-Commercial
//
// Author(s) : Efi Fogel <efif@post.tau.ac.il>
// Ron Wein <wein@post.tau.ac.il>
// (base on old version by: Iddo Hanniel)
// Author(s): Efi Fogel <efif@post.tau.ac.il>
// Ron Wein <wein@post.tau.ac.il>
// (base on old version by: Iddo Hanniel)
#ifndef CGAL_ARR_NON_CACHING_SEGMENT_TRAITS_H
#define CGAL_ARR_NON_CACHING_SEGMENT_TRAITS_H
@ -27,6 +27,8 @@
* functors required by the concept it models.
*/
#include <boost/variant.hpp>
#include <CGAL/Exact_predicates_exact_constructions_kernel.h>
#include <CGAL/tags.h>
#include <CGAL/Arr_tags.h>
@ -39,7 +41,7 @@ namespace CGAL {
* A model of the ArrangementTraits_2 concept that handles general
* line segments.
*/
template <class Kernel_T = Exact_predicates_exact_constructions_kernel>
template <typename Kernel_T = Exact_predicates_exact_constructions_kernel>
class Arr_non_caching_segment_traits_2 :
public Arr_non_caching_segment_basic_traits_2<Kernel_T>
{
@ -114,12 +116,10 @@ public:
/*! \class
* A functor for splitting curves into x-monotone pieces.
*/
class Make_x_monotone_2
{
class Make_x_monotone_2 {
public:
/*!
* Cut the given segment into x-monotone subcurves and insert them into
/*! Cut the given segment into x-monotone subcurves and insert them into
* the given output iterator. As segments are always x_monotone, only one
* x-monotone curve is inserted into the output iterator.
* \param cv The segment.
@ -127,54 +127,47 @@ public:
* object is a wrapper of an X_monotone_curve_2 object.
* \return The past-the-end iterator.
*/
template<class OutputIterator>
OutputIterator operator()(const Curve_2 & cv, OutputIterator oi) const
template <typename OutputIterator>
OutputIterator operator()(const Curve_2& cv, OutputIterator oi) const
{
*oi = make_object (cv);
++oi;
return (oi);
*oi++ = make_object(cv);
return oi;
}
};
/*! Get a Make_x_monotone_2 functor object. */
/*! Obtain a Make_x_monotone_2 functor object. */
Make_x_monotone_2 make_x_monotone_2_object() const
{
return Make_x_monotone_2();
}
{ return Make_x_monotone_2(); }
/*! \class
* A functor for splitting a segment into two segements.
*/
class Split_2
{
class Split_2 {
typedef Arr_non_caching_segment_traits_2<Kernel_T> Self;
public:
/*!
* Split a given x-monotone curve at a given point into two sub-curves.
public:
/*! Split a given x-monotone curve at a given point into two sub-curves.
* \param cv The curve to split
* \param p The split point.
* \param c1 Output: The left resulting subcurve (p is its right endpoint).
* \param c2 Output: The right resulting subcurve (p is its left endpoint).
* \pre p lies on cv but is not one of its end-points.
*/
void operator()(const X_monotone_curve_2 & cv, const Point_2 & p,
X_monotone_curve_2 & c1, X_monotone_curve_2 & c2) const
void operator()(const X_monotone_curve_2& cv, const Point_2& p,
X_monotone_curve_2& c1, X_monotone_curve_2& c2) const
{
Base base;
// Make sure that p lies on the interior of the curve.
CGAL_precondition_code (
Compare_xy_2 compare_xy = base.compare_xy_2_object();
);
CGAL_precondition_code(auto compare_xy = base.compare_xy_2_object());
Construct_min_vertex_2 min_vertex = base.construct_min_vertex_2_object();
Construct_max_vertex_2 max_vertex = base.construct_max_vertex_2_object();
const Point_2 & left = min_vertex(cv);
const Point_2 & right = max_vertex(cv);
const Point_2& left = min_vertex(cv);
const Point_2& right = max_vertex(cv);
CGAL_precondition
(Segment_assertions::_assert_is_point_on(p, cv, Has_exact_division())&&
(Segment_assertions::_assert_is_point_on(p, cv, Has_exact_division()) &&
compare_xy(left, p) == SMALLER &&
compare_xy(right, p) == LARGER);
@ -182,31 +175,36 @@ public:
base.construct_segment_2_object();
Self self;
if(self.compare_endpoints_xy_2_object()(cv) == SMALLER)
{
if (self.compare_endpoints_xy_2_object()(cv) == SMALLER) {
c1 = construct_segment(left, p);
c2 = construct_segment(p, right);
}
else
{
else {
c1 = construct_segment(p, left);
c2 = construct_segment(right, p);
}
}
};
/*! Get a Split_2 functor object. */
Split_2 split_2_object() const
{
return Split_2();
}
/*! Obtain a Split_2 functor object. */
Split_2 split_2_object() const { return Split_2(); }
/*! \class
* A functor for computing intersections.
*/
class Intersect_2
{
typedef Arr_non_caching_segment_traits_2<Kernel_T> Self;
class Intersect_2 {
protected:
typedef Arr_non_caching_segment_traits_2<Kernel> Traits;
/*! The traits (in case it has state) */
const Traits& m_traits;
/*! Constructor
* \param traits the traits (in case it has state)
*/
Intersect_2(const Traits& traits) : m_traits(traits) {}
friend class Arr_non_caching_segment_traits_2<Kernel>;
public:
/*! Find the intersections of the two given segments and insert them into
@ -217,67 +215,56 @@ public:
* \param oi The output iterator.
* \return The past-the-end iterator.
*/
template<class OutputIterator>
OutputIterator operator()(const X_monotone_curve_2 & cv1,
const X_monotone_curve_2 & cv2,
template <typename OutputIterator>
OutputIterator operator()(const X_monotone_curve_2& cv1,
const X_monotone_curve_2& cv2,
OutputIterator oi) const
{
Base base;
Object res = base.intersect_2_object()(cv1, cv2);
typedef std::pair<Point_2, Multiplicity> Intersection_point;
typedef boost::variant<Intersection_point, X_monotone_curve_2>
Intersection_result;
const Kernel& kernel = m_traits;
auto res = kernel.intersect_2_object()(cv1, cv2);
// There is no intersection:
if (res.is_empty())
return (oi);
if (! res) return oi;
// Chack if the intersection is a point:
const Point_2 *ip;
if ((ip = object_cast<Point_2> (&res)) != nullptr)
{
const Point_2* p_p = boost::get<Point_2>(&*res);
if (p_p != nullptr) {
// Create a pair representing the point with its multiplicity,
// which is always 1 for line segments for all practical purposes.
// If the two segments intersect at their endpoints, then the
// multiplicity is undefined, but we deliberately ignore it for
// efficieny reasons.
std::pair<Point_2,Multiplicity> ip_mult(*ip, 1);
*oi = make_object (ip_mult);
++oi;
*oi++ = Intersection_result(Intersection_point(*p_p, 1));
return oi;
}
else
{
// The intersection is a segment.
const X_monotone_curve_2 *ov = object_cast<X_monotone_curve_2>(&res);
CGAL_assertion (ov != nullptr);
// The intersection is a segment.
const X_monotone_curve_2* cv_p = boost::get<X_monotone_curve_2>(&*res);
CGAL_assertion(cv_p != nullptr);
Self self;
Comparison_result cmp1 = self.compare_endpoints_xy_2_object()(cv1);
Comparison_result cmp2 = self.compare_endpoints_xy_2_object()(cv2);
Comparison_result cmp1 = m_traits.compare_endpoints_xy_2_object()(cv1);
Comparison_result cmp2 = m_traits.compare_endpoints_xy_2_object()(cv2);
if(cmp1 == cmp2)
{
// cv1 and cv2 have the same directions, maintain this direction
// in the overlap segment
if(self.compare_endpoints_xy_2_object()(*ov) != cmp1)
{
Kernel k;
res = make_object(k.construct_opposite_segment_2_object()(*ov));
}
if (cmp1 == cmp2) {
// cv1 and cv2 have the same directions, maintain this direction
// in the overlap segment
if (m_traits.compare_endpoints_xy_2_object()(*cv_p) != cmp1) {
auto ctr_opposite = kernel.construct_opposite_segment_2_object();
*oi++ = Intersection_result(ctr_opposite(*cv_p));
return oi;
}
*oi = res;
++oi;
}
return (oi);
*oi++ = Intersection_result(*cv_p);
return oi;
}
};
/*! Get an Intersect_2 functor object. */
Intersect_2 intersect_2_object() const
{
return Intersect_2();
}
/*! Obtain an Intersect_2 functor object. */
Intersect_2 intersect_2_object() const { return Intersect_2(*this); }
/*! \class
* A functor for testing whether two segments are mergeable.
@ -297,24 +284,22 @@ public:
friend class Arr_non_caching_segment_traits_2<Kernel>;
public:
/*!
* Check whether it is possible to merge two given x-monotone curves.
/*! Check whether it is possible to merge two given x-monotone curves.
* \param cv1 The first curve.
* \param cv2 The second curve.
* \return (true) if the two curves are mergeable, that is, if they are
* supported by the same line; (false) otherwise.
* \pre cv1 and cv2 share a common endpoint.
*/
bool operator()(const X_monotone_curve_2 & cv1,
const X_monotone_curve_2 & cv2) const
bool operator()(const X_monotone_curve_2& cv1,
const X_monotone_curve_2& cv2) const
{
const Base* base = m_traits;
Equal_2 equal = base->equal_2_object();
Construct_min_vertex_2 min_vertex = base->construct_min_vertex_2_object();
Construct_max_vertex_2 max_vertex = base->construct_max_vertex_2_object();
if (!equal(max_vertex(cv1), min_vertex(cv2)) &&
!equal(max_vertex(cv2), min_vertex(cv1)))
if (! equal(max_vertex(cv1), min_vertex(cv2)) &&
! equal(max_vertex(cv2), min_vertex(cv1)))
return false;
// Check if the two curves have the same supporting line.
@ -344,16 +329,15 @@ public:
friend class Arr_non_caching_segment_traits_2<Kernel>;
public:
/*!
* Merge two given segments into a single segment.
/*! Merge two given segments into a single segment.
* \param cv1 The first curve.
* \param cv2 The second curve.
* \param c Output: The merged curve.
* \pre The two curves are mergeable.
*/
void operator()(const X_monotone_curve_2 & cv1,
const X_monotone_curve_2 & cv2,
X_monotone_curve_2 & c) const
void operator()(const X_monotone_curve_2& cv1,
const X_monotone_curve_2& cv2,
X_monotone_curve_2& c) const
{
CGAL_precondition(m_traits->are_mergeable_2_object()(cv2, cv1));
@ -390,12 +374,9 @@ public:
/*! Obtain a Construct_opposite_2 functor object */
Construct_opposite_2 construct_opposite_2_object() const
{
return Construct_opposite_2();
}
{ return Construct_opposite_2(); }
class Compare_endpoints_xy_2
{
class Compare_endpoints_xy_2 {
public:
/*!
* Compare the two endpoints of a given curve lexigoraphically.
@ -417,9 +398,7 @@ public:
/*! Obtain a Compare_endpoints_xy_2 functor object */
Compare_endpoints_xy_2 compare_endpoints_xy_2_object() const
{
return Compare_endpoints_xy_2();
}
{ return Compare_endpoints_xy_2(); }
//@}
};

View File

@ -2521,11 +2521,8 @@ protected:
template <typename Comparer>
class Compare_points {
private:
typedef Arr_polycurve_basic_traits_2<Subcurve_traits_2>
Polycurve_basic_traits_2;
/*! The polycurve traits (in case it has state). */
const Polycurve_basic_traits_2 m_poly_traits;
const Subcurve_traits_2& m_subcurve_traits;
const Point_2& m_point;
@ -2533,9 +2530,9 @@ protected:
public:
// Constructor
Compare_points(const Polycurve_basic_traits_2& traits, Comparer compare,
Compare_points(const Subcurve_traits_2& traits, Comparer compare,
const Point_2& p) :
m_poly_traits(traits),
m_subcurve_traits(traits),
m_point(p),
m_compare(compare)
{}
@ -2544,10 +2541,9 @@ protected:
Comparison_result operator()(const X_monotone_subcurve_2& xs,
Arr_curve_end ce)
{
const Subcurve_traits_2* geom_traits = m_poly_traits.subcurve_traits_2();
const Point_2& p = (ce == ARR_MAX_END) ?
geom_traits->construct_max_vertex_2_object()(xs) :
geom_traits->construct_min_vertex_2_object()(xs);
m_subcurve_traits.construct_max_vertex_2_object()(xs) :
m_subcurve_traits.construct_min_vertex_2_object()(xs);
return m_compare(p, m_point);
}
};
@ -2696,12 +2692,12 @@ protected:
Comparison_result res = compare_x(min_vertex(xcv[0]), q);
if (res != EQUAL) return INVALID_INDEX;
Compare_points<Compare_xy_2> compare(geom_traits,
Compare_points<Compare_xy_2> compare(*geom_traits,
compare_xy_2_object(), q);
return locate_gen(xcv, compare);
}
Compare_points<Compare_x_2> compare(geom_traits, compare_x_2_object(), q);
Compare_points<Compare_x_2> compare(*geom_traits, compare_x_2_object(), q);
return locate_gen(xcv, compare);
}

View File

@ -25,6 +25,8 @@
*/
#include <iterator>
#include <boost/variant.hpp>
#include <boost/type_traits/is_same.hpp>
#include <boost/utility/enable_if.hpp>
@ -193,13 +195,12 @@ public:
// If the polycurve is empty, return.
if (cv.number_of_subcurves() == 0) return oi;
Construct_x_monotone_curve_2 ctr_x_curve =
m_poly_traits.construct_x_monotone_curve_2_object();
auto ctr_x_curve = m_poly_traits.construct_x_monotone_curve_2_object();
typename Subcurve_traits_2::Make_x_monotone_2 make_seg_x_monotone =
auto make_seg_x_monotone =
m_poly_traits.subcurve_traits_2()->make_x_monotone_2_object();
typename Subcurve_traits_2::Compare_endpoints_xy_2 cmp_seg_endpts =
auto cmp_seg_endpts =
m_poly_traits.subcurve_traits_2()->compare_endpoints_xy_2_object();
#ifdef CGAL_ALWAYS_LEFT_TO_RIGHT
@ -238,12 +239,11 @@ public:
(
// To be used in order to verify continuity and well-orientedness
// of the input curve cv.
typename Subcurve_traits_2::Construct_min_vertex_2 min_seg_v =
auto min_seg_v =
m_poly_traits.subcurve_traits_2()->construct_min_vertex_2_object();
typename Subcurve_traits_2::Construct_max_vertex_2 max_seg_v =
auto max_seg_v =
m_poly_traits.subcurve_traits_2()->construct_max_vertex_2_object();
typename Subcurve_traits_2::Equal_2 equal =
m_poly_traits.subcurve_traits_2()->equal_2_object();
auto equal = m_poly_traits.subcurve_traits_2()->equal_2_object();
Point_2 last_target = (cmp_seg_endpts(x_seg) == SMALLER) ?
max_seg_v(x_seg) : min_seg_v(x_seg);
Point_2 next_src;
@ -329,19 +329,18 @@ public:
// If the polycurve is empty, return.
if (cv.number_of_subcurves() == 0) return oi;
Construct_x_monotone_curve_2 ctr_x_curve =
m_poly_traits.construct_x_monotone_curve_2_object();
auto ctr_x_curve = m_poly_traits.construct_x_monotone_curve_2_object();
typename Subcurve_traits_2::Make_x_monotone_2 make_seg_x_monotone =
auto make_seg_x_monotone =
m_poly_traits.subcurve_traits_2()->make_x_monotone_2_object();
typename Subcurve_traits_2::Compare_endpoints_xy_2 cmp_seg_endpts =
auto cmp_seg_endpts =
m_poly_traits.subcurve_traits_2()->compare_endpoints_xy_2_object();
typename Subcurve_traits_2::Parameter_space_in_x_2 ps_x =
m_poly_traits.subcurve_traits_2()->parameter_space_in_x_2_object();
typename Subcurve_traits_2::Parameter_space_in_y_2 ps_y =
m_poly_traits.subcurve_traits_2()->parameter_space_in_y_2_object();
auto ps_x =
m_poly_traits.subcurve_traits_2()->parameter_space_in_x_2_object();
auto ps_y =
m_poly_traits.subcurve_traits_2()->parameter_space_in_y_2_object();
#ifdef CGAL_ALWAYS_LEFT_TO_RIGHT
typename Subcurve_traits_2::Construct_opposite_2 ctr_seg_opposite =
@ -379,12 +378,11 @@ public:
(
// To be used in order to verify continuity and well-orientedness
// of the input curve cv.
typename Subcurve_traits_2::Construct_min_vertex_2 min_seg_v =
auto min_seg_v =
m_poly_traits.subcurve_traits_2()->construct_min_vertex_2_object();
typename Subcurve_traits_2::Construct_max_vertex_2 max_seg_v =
auto max_seg_v =
m_poly_traits.subcurve_traits_2()->construct_max_vertex_2_object();
typename Subcurve_traits_2::Equal_2 equal =
m_poly_traits.subcurve_traits_2()->equal_2_object();
auto equal = m_poly_traits.subcurve_traits_2()->equal_2_object();
Point_2 last_target = (cmp_seg_endpts(x_seg) == SMALLER) ?
max_seg_v(x_seg) : min_seg_v(x_seg);
Point_2 next_src;
@ -498,9 +496,7 @@ public:
public:
/*! Constructor. */
Push_back_2(const Polycurve_traits_2& traits) :
Base::Push_back_2(traits)
{}
Push_back_2(const Polycurve_traits_2& traits) : Base::Push_back_2(traits) {}
// Normally, the moment the compiler finds a name, it stops looking. In
// other words, the compiler first finds the operator() in the current
@ -584,20 +580,16 @@ public:
X_monotone_curve_2& xcv1, X_monotone_curve_2& xcv2) const
{
const Subcurve_traits_2* geom_traits = m_poly_traits.subcurve_traits_2();
typename Subcurve_traits_2::Construct_min_vertex_2 min_vertex =
geom_traits->construct_min_vertex_2_object();
typename Subcurve_traits_2::Construct_max_vertex_2 max_vertex =
geom_traits->construct_max_vertex_2_object();
typename Subcurve_traits_2::Equal_2 equal =
geom_traits->equal_2_object();
typename Subcurve_traits_2::Compare_endpoints_xy_2 cmp_seg_endpts =
geom_traits->compare_endpoints_xy_2_object();
auto min_vertex = geom_traits->construct_min_vertex_2_object();
auto max_vertex = geom_traits->construct_max_vertex_2_object();
auto equal = geom_traits->equal_2_object();
auto cmp_seg_endpts = geom_traits->compare_endpoints_xy_2_object();
// Make sure the split point is not one of the curve endpoints.
CGAL_precondition((!equal(m_poly_traits.
construct_min_vertex_2_object()(xcv), p)));
CGAL_precondition((!equal(m_poly_traits.
construct_max_vertex_2_object()(xcv), p)));
CGAL_precondition((! equal(m_poly_traits.
construct_min_vertex_2_object()(xcv), p)));
CGAL_precondition((! equal(m_poly_traits.
construct_max_vertex_2_object()(xcv), p)));
CGAL_precondition_msg(xcv.number_of_subcurves() > 0,
"Cannot split a polycurve of length zero.");
@ -709,22 +701,20 @@ public:
const X_monotone_curve_2& cv2,
OutputIterator oi) const
{
const Subcurve_traits_2* geom_traits = m_poly_traits.subcurve_traits_2();
Compare_y_at_x_2 cmp_y_at_x = m_poly_traits.compare_y_at_x_2_object();
typename Subcurve_traits_2::Equal_2 equal =
geom_traits->equal_2_object();
typename Subcurve_traits_2::Construct_min_vertex_2 min_vertex =
geom_traits->construct_min_vertex_2_object();
typename Subcurve_traits_2::Construct_max_vertex_2 max_vertex =
geom_traits->construct_max_vertex_2_object();
typename Subcurve_traits_2::Intersect_2 intersect =
geom_traits->intersect_2_object();
typename Subcurve_traits_2::Compare_endpoints_xy_2 cmp_seg_endpts =
geom_traits->compare_endpoints_xy_2_object();
typename Subcurve_traits_2::Construct_opposite_2 construct_opposite =
geom_traits->construct_opposite_2_object();
typedef std::pair<Point_2, Multiplicity> Intersection_point;
typedef boost::variant<Intersection_point, X_monotone_subcurve_2>
Intersection_base_result;
typedef boost::variant<Intersection_point, X_monotone_curve_2>
Intersection_result;
typedef std::pair<Point_2,Multiplicity> Point_2_pair;
const Subcurve_traits_2* geom_traits = m_poly_traits.subcurve_traits_2();
auto cmp_y_at_x = m_poly_traits.compare_y_at_x_2_object();
auto equal = geom_traits->equal_2_object();
auto min_vertex = geom_traits->construct_min_vertex_2_object();
auto max_vertex = geom_traits->construct_max_vertex_2_object();
auto intersect = geom_traits->intersect_2_object();
auto cmp_seg_endpts = geom_traits->compare_endpoints_xy_2_object();
auto construct_opposite = geom_traits->construct_opposite_2_object();
Comparison_result dir1 = cmp_seg_endpts(cv1[0]);
Comparison_result dir2 = cmp_seg_endpts(cv2[0]);
@ -737,7 +727,7 @@ public:
X_monotone_curve_2 ocv; // Used to represent overlaps.
Compare_xy_2 compare_xy = m_poly_traits.compare_xy_2_object();
auto compare_xy = m_poly_traits.compare_xy_2_object();
Comparison_result left_res =
compare_xy(cv1[i1], ARR_MIN_END, cv2[i2], ARR_MIN_END);
@ -754,12 +744,13 @@ public:
((dir1 == LARGER) && (i1 == 0))){
// cv1's right endpoint equals cv2's left endpoint
// Thus we can return this single(!) intersection point
std::pair<Point_2, Multiplicity> p(max_vertex(cv1[i1]), 0);
*oi++ = make_object(p);
Intersection_point p(max_vertex(cv1[i1]), 0);
*oi++ = Intersection_result(p);
return oi;
}
dir1 == SMALLER ?
++i1 : (i1 != 0) ? --i1 : (std::size_t) Polycurve_traits_2::INVALID_INDEX;
++i1 :
(i1 != 0) ? --i1 : (std::size_t) Polycurve_traits_2::INVALID_INDEX;
left_res = EQUAL;
}
}
@ -776,13 +767,14 @@ public:
((dir2 == LARGER) && (i2 == 0))){
// cv2's right endpoint equals cv1's left endpoint
// Thus we can return this single(!) intersection point
std::pair<Point_2, Multiplicity> p(max_vertex(cv2[i2]), 0);
*oi++ = make_object(p);
Intersection_point p(max_vertex(cv2[i2]), 0);
*oi++ = Intersection_result(p);
return oi;
}
dir2 == SMALLER ?
++i2 : (i2 != 0) ? --i2 : (std::size_t) Polycurve_traits_2::INVALID_INDEX;
++i2 :
(i2 != 0) ? --i2 : (std::size_t) Polycurve_traits_2::INVALID_INDEX;
left_res = EQUAL;
}
}
@ -823,48 +815,64 @@ public:
right_overlap = false;
if (!right_coincides && !left_coincides) {
//! EF: the following code is abit suspicious. It may erroneously
// assume that the subcurves cannot overlap more than once.
if (! right_coincides && ! left_coincides) {
// Non of the endpoints of the current subcurve of one polycurve
// coincides with the curent subcurve of the other polycurve:
// Output the intersection if exists.
oi = intersect(cv1[i1], cv2[i2], oi);
std::vector<Intersection_base_result> xections;
intersect(cv1[i1], cv2[i2], std::back_inserter(xections));
for (const auto& xection : xections) {
const X_monotone_subcurve_2* subcv_p =
boost::get<X_monotone_subcurve_2>(&xection);
if (subcv_p != nullptr) {
ocv.push_back(*subcv_p);
*oi++ = Intersection_result(ocv);
ocv.clear();
continue;
}
const Intersection_point* p_p =
boost::get<Intersection_point>(&xection);
if (p_p != nullptr) *oi++ = Intersection_result(*p_p);
}
}
else if (right_coincides && left_coincides) {
// An overlap exists between the current subcurves of the
// polycurves: Output the overlapping subcurve.
right_overlap = true;
std::vector<CGAL::Object> int_seg;
intersect(cv1[i1], cv2[i2], std::back_inserter(int_seg));
std::vector<Intersection_base_result> sub_xections;
intersect(cv1[i1], cv2[i2], std::back_inserter(sub_xections));
for (size_t i = 0; i < int_seg.size(); ++i) {
for (const auto& item : sub_xections) {
const X_monotone_subcurve_2* x_seg =
CGAL::object_cast<X_monotone_subcurve_2> (&(int_seg[i]));
boost::get<X_monotone_subcurve_2>(&item);
if (x_seg != nullptr) {
X_monotone_subcurve_2 seg = *x_seg;
// If for some reason the subcurve intersection
// results in left oriented curve.
if ( cmp_seg_endpts(seg) == LARGER)
seg = construct_opposite(seg);
if (cmp_seg_endpts(seg) == LARGER) seg = construct_opposite(seg);
ocv.push_back(seg);
}
const Point_2_pair* p_ptr =
CGAL::object_cast<Point_2_pair>(&(int_seg[i]));
const Intersection_point* p_ptr =
boost::get<Intersection_point>(&item);
if (p_ptr != nullptr) {
// Any point that is not equal to the max_vertex of the
// subcurve should be inserted into oi.
// The max_vertex of the current subcurve (if intersecting)
// will be taken care of as the min_vertex of in the next
// iteration.
if (!equal(p_ptr->first, max_vertex(cv1[i1])))
*oi++ = make_object(*p_ptr);
if (! equal(p_ptr->first, max_vertex(cv1[i1])))
*oi++ = Intersection_result(*p_ptr);
}
}
}
else if (left_coincides && !right_coincides) {
else if (left_coincides && ! right_coincides) {
// std::cout << "Left is coinciding but right is not." << std::endl;
// The left point of the current subcurve of one polycurve
// coincides with the current subcurve of the other polycurve.
@ -872,7 +880,7 @@ public:
// An overlap occurred at the previous iteration:
// Output the overlapping polycurve.
CGAL_assertion(ocv.number_of_subcurves() > 0);
*oi++ = make_object(ocv);
*oi++ = Intersection_result(ocv);
ocv.clear();
}
else {
@ -884,12 +892,12 @@ public:
// polycurves is not defined at this point, so we give
// it multiplicity 0.
if (left_res == SMALLER) {
std::pair<Point_2, Multiplicity> p(min_vertex(cv2[i2]), 0);
*oi++ = make_object(p);
Intersection_point p(min_vertex(cv2[i2]), 0);
*oi++ = Intersection_result(p);
}
else {
std::pair<Point_2, Multiplicity> p(min_vertex(cv1[i1]), 0);
*oi++ = make_object(p);
Intersection_point p(min_vertex(cv1[i1]), 0);
*oi++ = Intersection_result(p);
}
}
}
@ -919,7 +927,7 @@ public:
// Output the remaining overlapping polycurve, if necessary.
if (ocv.number_of_subcurves() > 0) {
*oi++ = make_object(ocv);
*oi++ = Intersection_result(ocv);
}
else if (right_coincides) {
typedef std::pair<Point_2,Multiplicity> return_point;
@ -930,7 +938,7 @@ public:
(i1 != Polycurve_traits_2::INVALID_INDEX) ?
return_point(max_vertex(cv1[i1+1]), 0) :
return_point(max_vertex(cv1[0]), 0);
*oi++ = make_object(ip);
*oi++ = Intersection_result(ip);
}
else if (right_res == LARGER) {
ip = (dir2 == SMALLER) ?
@ -938,7 +946,7 @@ public:
(i2 != Polycurve_traits_2::INVALID_INDEX) ?
return_point(max_vertex(cv2[i2+1]), 0) :
return_point(max_vertex(cv2[0]), 0);
*oi++ = make_object(ip);
*oi++ = Intersection_result(ip);
}
else if (((i1 > 0) && (dir1 == SMALLER)) ||
((i1 < n1) && (dir1 != SMALLER)) ||
@ -950,7 +958,7 @@ public:
(i1 != Polycurve_traits_2::INVALID_INDEX) ?
return_point(max_vertex(cv1[i1+1]), 0) :
return_point(max_vertex(cv1[0]), 0);
*oi++ = make_object(ip);
*oi++ = Intersection_result(ip);
}
else {
CGAL_assertion_msg((dir2 == SMALLER && i2 > 0) ||
@ -965,7 +973,7 @@ public:
(i2 != Polycurve_traits_2::INVALID_INDEX) ?
return_point(max_vertex(cv2[i2+1]), 0) :
return_point(max_vertex(cv2[0]), 0);
*oi++ = make_object(ip);
*oi++ = Intersection_result(ip);
}
}

View File

@ -1848,8 +1848,8 @@ public:
typedef typename Base::Cache Cache;
typedef std::pair<Algebraic_point_2, Multiplicity> Intersection_point_2;
//typedef std::pair<Algebraic_point_2, unsigned int> Intersection_point_2;
typedef std::pair<Algebraic_point_2, Multiplicity> Intersection_point;
//typedef std::pair<Algebraic_point_2, unsigned int> Intersection_point;
/// \name Constrcution methods.
@ -2029,8 +2029,7 @@ public:
/// \name Constructions of points and curves.
//@{
/*!
* Compute the intersections with the given arc.
/*! Compute the intersections with the given arc.
* \param arc The given intersecting arc.
* \param oi The output iterator.
* \return The past-the-end iterator.
@ -2039,33 +2038,31 @@ public:
OutputIterator intersect(const Self& arc, OutputIterator oi,
const Cache& cache) const
{
typedef boost::variant<Intersection_point, Self> Intersection_result;
CGAL_precondition(this->is_valid() && this->is_continuous());
CGAL_precondition(arc.is_valid() && arc.is_continuous());
if (this->equals(arc))
{
Self overlap_arc(*this);
*oi++ = make_object(overlap_arc);
return (oi);
if (this->equals(arc)) {
Self overlap_arc(*this);
*oi++ = Intersection_result(overlap_arc);
return oi;
}
if (this->_has_same_base(arc))
{
if (this->_has_same_base(arc)) {
// Get the left and right endpoints of (*this) and their information
// bits.
const Algebraic_point_2& left1 = (this->is_directed_right() ?
this->_ps : this->_pt);
const Algebraic_point_2& right1 = (this->is_directed_right() ?
this->_pt : this->_ps);
int info_left1, info_right1;
const Algebraic_point_2& left1 =
(this->is_directed_right() ? this->_ps : this->_pt);
const Algebraic_point_2& right1 =
(this->is_directed_right() ? this->_pt : this->_ps);
int info_left1, info_right1;
if (this->is_directed_right())
{
if (this->is_directed_right()) {
info_left1 = (this->_info & this->SRC_INFO_BITS);
info_right1 = ((this->_info & this->TRG_INFO_BITS) >> 4);
}
else
{
else {
info_right1 = (this->_info & this->SRC_INFO_BITS);
info_left1 = ((this->_info & this->TRG_INFO_BITS) >> 4);
}
@ -2076,110 +2073,93 @@ public:
(arc.is_directed_right() ? arc._ps : arc._pt);
const Algebraic_point_2& right2 =
(arc.is_directed_right() ? arc._pt : arc._ps);
int info_left2, info_right2;
int info_left2, info_right2;
if (arc.is_directed_right())
{
if (arc.is_directed_right()) {
info_left2 = (arc._info & this->SRC_INFO_BITS);
info_right2 = ((arc._info & this->TRG_INFO_BITS) >> 4);
}
else
{
else {
info_right2 = (arc._info & this->SRC_INFO_BITS);
info_left2 = ((arc._info & this->TRG_INFO_BITS) >> 4);
}
// Locate the left curve-end with larger x-coordinate.
bool at_minus_infinity = false;
Arr_parameter_space inf_l1 = this->left_parameter_space_in_x();
Arr_parameter_space inf_l2 = arc.left_parameter_space_in_x();
Algebraic_point_2 p_left;
int info_left;
bool at_minus_infinity = false;
Arr_parameter_space inf_l1 = this->left_parameter_space_in_x();
Arr_parameter_space inf_l2 = arc.left_parameter_space_in_x();
Algebraic_point_2 p_left;
int info_left;
if (inf_l1 == ARR_INTERIOR && inf_l2 == ARR_INTERIOR)
{
if (inf_l1 == ARR_INTERIOR && inf_l2 == ARR_INTERIOR) {
// Let p_left be the rightmost of the two left endpoints.
if (left1.x() > left2.x())
{
if (left1.x() > left2.x()) {
p_left = left1;
info_left = info_left1;
}
else
{
else {
p_left = left2;
info_left = info_left2;
}
}
else if (inf_l1 == ARR_INTERIOR)
{
else if (inf_l1 == ARR_INTERIOR) {
// Let p_left be the left endpoint of (*this).
p_left = left1;
info_left = info_left1;
}
else if (inf_l2 == ARR_INTERIOR)
{
else if (inf_l2 == ARR_INTERIOR) {
// Let p_left be the left endpoint of the other arc.
p_left = left2;
info_left = info_left2;
}
else
{
else {
// Both arcs are defined at x = -oo.
at_minus_infinity = true;
info_left = info_left1;
}
// Locate the right curve-end with smaller x-coordinate.
bool at_plus_infinity = false;
Arr_parameter_space inf_r1 = this->right_parameter_space_in_x();
Arr_parameter_space inf_r2 = arc.right_parameter_space_in_x();
Algebraic_point_2 p_right;
int info_right;
bool at_plus_infinity = false;
Arr_parameter_space inf_r1 = this->right_parameter_space_in_x();
Arr_parameter_space inf_r2 = arc.right_parameter_space_in_x();
Algebraic_point_2 p_right;
int info_right;
if (inf_r1 == ARR_INTERIOR && inf_r2 == ARR_INTERIOR)
{
if (inf_r1 == ARR_INTERIOR && inf_r2 == ARR_INTERIOR) {
// Let p_right be the rightmost of the two right endpoints.
if (right1.x() < right2.x())
{
if (right1.x() < right2.x()) {
p_right = right1;
info_right = info_right1;
}
else
{
else {
p_right = right2;
info_right = info_right2;
}
}
else if (inf_r1 == ARR_INTERIOR)
{
else if (inf_r1 == ARR_INTERIOR) {
// Let p_right be the right endpoint of (*this).
p_right = right1;
info_right = info_right1;
}
else if (inf_r2 == ARR_INTERIOR)
{
else if (inf_r2 == ARR_INTERIOR) {
// Let p_right be the right endpoint of the other arc.
p_right = right2;
info_right = info_right2;
}
else
{
else {
// Both arcs are defined at x = +oo.
at_plus_infinity = true;
info_right = info_right2;
}
// Check the case of two bounded (in x) ends.
if (! at_minus_infinity && ! at_plus_infinity)
{
if (! at_minus_infinity && ! at_plus_infinity) {
Comparison_result res = CGAL::compare(p_left.x(), p_right.x());
if (res == LARGER)
{
// The x-range of the overlap is empty, so there is no overlap.
return (oi);
}
else if (res == EQUAL)
{
// The x-range of the overlap is empty, so there is no overlap.
if (res == LARGER) return oi;
if (res == EQUAL) {
// We have a single overlapping point. Just make sure this point
// is not at y = -/+ oo.
if (info_left &&
@ -2187,19 +2167,18 @@ public:
info_right &&
(this->SRC_AT_Y_MINUS_INFTY | this->SRC_AT_Y_PLUS_INFTY) == 0)
{
Intersection_point_2 ip(p_left, 0);
*oi++ = make_object(ip);
Intersection_point ip(p_left, 0);
*oi++ = Intersection_result(ip);
}
return (oi);
return oi;
}
}
// Create the overlapping portion of the rational arc by properly setting
// the source (left) and target (right) endpoints and their information
// bits.
Self overlap_arc(*this);
Self overlap_arc(*this);
overlap_arc._ps = p_left;
overlap_arc._pt = p_right;
@ -2208,8 +2187,8 @@ public:
this->IS_DIRECTED_RIGHT | this->IS_CONTINUOUS |
this->IS_VALID);
*oi++ = make_object(overlap_arc);
return (oi);
*oi++ = Intersection_result(overlap_arc);
return oi;
}
// We wish to find the intersection points between:
@ -2237,15 +2216,14 @@ public:
if (this->_is_in_true_x_range(*x_iter) && arc._is_in_true_x_range(*x_iter))
{
// Compute the intersection point and obtain its multiplicity.
Algebraic_point_2 p(this->_f, *x_iter);
Algebraic_point_2 p(this->_f, *x_iter);
// Output the intersection point:
Intersection_point_2 ip(p, *m_iter);
*oi++ = make_object(ip);
Intersection_point ip(p, *m_iter);
*oi++ = Intersection_result(ip);
}
}
return (oi);
return oi;
}
/*!
@ -2255,7 +2233,8 @@ public:
* \param c2 Output: The first resulting arc, lying to the right of p.
* \pre p lies in the interior of the arc (not one of its endpoints).
*/
void split(const Algebraic_point_2& p, Self& c1, Self& c2, const Cache& CGAL_assertion_code(cache)) const
void split(const Algebraic_point_2& p, Self& c1, Self& c2,
const Cache& CGAL_assertion_code(cache)) const
{
CGAL_precondition(this->is_valid() && this->is_continuous());
@ -2598,4 +2577,3 @@ public:
} //namespace CGAL {
#endif //CGAL_RATIONAL_ARC_D_1_H

File diff suppressed because it is too large Load Diff

View File

@ -7,7 +7,7 @@
// $Id$
// SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-Commercial
//
// Author(s) : Efi Fogel <efif@post.tau.ac.il>
// Author(s): Efi Fogel <efif@post.tau.ac.il>
#ifndef CGAL_ARR_TRACING_TRAITS_H
#define CGAL_ARR_TRACING_TRAITS_H
@ -26,6 +26,8 @@
#include <iostream>
#include <list>
#include <boost/variant.hpp>
#include <CGAL/basic.h>
#include <CGAL/Arr_enums.h>
#include <CGAL/Arr_tags.h>
@ -592,7 +594,7 @@ public:
public:
/*! Construct */
Intersect_2(const Base * base, bool enabled = true) :
Intersect_2(const Base* base, bool enabled = true) :
m_object(base->intersect_2_object()), m_enabled(enabled) {}
/*! Operate
@ -604,37 +606,41 @@ public:
* multiplicity
* \return the output iterator
*/
template<typename OutputIterator>
template <typename OutputIterator>
OutputIterator operator()(const X_monotone_curve_2 & xcv1,
const X_monotone_curve_2 & xcv2,
OutputIterator oi) const
{
if (!m_enabled) return m_object(xcv1, xcv2, oi);
typedef std::pair<Point_2, Multiplicity> Intersection_point;
typedef boost::variant<Intersection_point, X_monotone_curve_2>
Intersection_result;
if (! m_enabled) return m_object(xcv1, xcv2, oi);
std::cout << "intersect" << std::endl
<< " xcv1: " << xcv1 << std::endl
<< " xcv2: " << xcv2 << std::endl;
std::list<CGAL::Object> container;
std::list<Intersection_result> container;
m_object(xcv1, xcv2, std::back_inserter(container));
if (container.empty()) return oi;
std::list<CGAL::Object>::iterator it;
unsigned int i = 0;
for (it = container.begin(); it != container.end(); ++it) {
X_monotone_curve_2 xcv;
if (assign (xcv, *it)) {
std::cout << " result[" << i++ << "]: xcv: " << xcv << std::endl;
for (const auto& item : container) {
const X_monotone_curve_2* xcv = boost::get<X_monotone_curve_2>(&item);
if (xcv != nullptr) {
std::cout << " result[" << i++ << "]: xcv: " << *xcv << std::endl;
continue;
}
std::pair<Point_2,Multiplicity> point_pair;
if (assign (point_pair, *it)) {
std::cout << " result[" << i++ << "]: p: " << point_pair.first
<< ", multiplicity: " << point_pair.second << std::endl;
const Intersection_point* ip = boost::get<Intersection_point>(&item);
if (ip != nullptr) {
std::cout << " result[" << i++ << "]: p: " << ip->first
<< ", multiplicity: " << ip->second << std::endl;
continue;
}
}
for (it = container.begin(); it != container.end(); ++it) *oi++ = *it;
for (auto it = container.begin(); it != container.end(); ++it) *oi++ = *it;
container.clear();
return oi;
}

View File

@ -132,8 +132,8 @@ void Arrangement_zone_2<Arrangement, ZoneVisitor>::compute_zone()
// In this case m_cv overlaps the curve associated with m_intersect_he.
// Compute the overlapping subcurve.
bool dummy;
m_obj = _compute_next_intersection(m_intersect_he, false, dummy);
m_overlap_cv = object_cast<X_monotone_curve_2>(m_obj);
auto obj = _compute_next_intersection(m_intersect_he, false, dummy);
m_overlap_cv = boost::get<X_monotone_curve_2>(*obj);
// Remove the overlap from the map.
_remove_next_intersection(m_intersect_he);
@ -148,8 +148,8 @@ void Arrangement_zone_2<Arrangement, ZoneVisitor>::compute_zone()
m_intersect_he = m_arr.non_const_handle(*hh);
bool dummy;
m_obj = _compute_next_intersection(m_intersect_he, false, dummy);
m_overlap_cv = object_cast<X_monotone_curve_2>(m_obj);
auto obj = _compute_next_intersection(m_intersect_he, false, dummy);
m_overlap_cv = boost::get<X_monotone_curve_2>(*obj);
// Remove the overlap from the map.
_remove_next_intersection(m_intersect_he);
@ -207,8 +207,8 @@ void Arrangement_zone_2<Arrangement, ZoneVisitor>::compute_zone()
// In this case m_cv overlaps the curve associated with m_intersect_he.
// Compute the overlapping subcurve to the right of curr_v.
bool dummy;
m_obj = _compute_next_intersection(m_intersect_he, false, dummy);
m_overlap_cv = object_cast<X_monotone_curve_2>(m_obj);
auto obj = _compute_next_intersection(m_intersect_he, false, dummy);
m_overlap_cv = boost::get<X_monotone_curve_2>(*obj);
// Remove the overlap from the map.
_remove_next_intersection(m_intersect_he);
@ -800,7 +800,7 @@ _direct_intersecting_edge_to_left(const X_monotone_curve_2& cv_ins,
// Get the next intersection of cv with the given halfedge.
//
template <typename Arrangement, typename ZoneVisitor>
CGAL::Object
typename Arrangement_zone_2<Arrangement, ZoneVisitor>::Optional_intersection
Arrangement_zone_2<Arrangement, ZoneVisitor>::
_compute_next_intersection(Halfedge_handle he,
bool skip_first_point,
@ -811,7 +811,7 @@ _compute_next_intersection(Halfedge_handle he,
// Try to locate the intersections with this curve in the intersections map.
Intersect_map_iterator iter = m_inter_map.find(p_curve);
const Intersect_point_2* ip;
const Intersection_point* ip;
const X_monotone_curve_2* icv;
bool valid_intersection;
@ -821,13 +821,13 @@ _compute_next_intersection(Halfedge_handle he,
// Retrieve the intersections list from the map.
Intersect_list& inter_list = iter->second;
if (inter_list.empty()) return CGAL::Object();
if (inter_list.empty()) return Optional_intersection();
// Locate the first intersection that lies to the right of m_left_pt
// (if the left point exists).
while (! inter_list.empty()) {
// Compare that current object with m_left_pt (if exists).
ip = object_cast<Intersect_point_2>(&(inter_list.front()));
ip = boost::get<Intersection_point>(&(inter_list.front()));
if (m_left_on_boundary) {
// The left end lie on the left boundary, so all intersections are
@ -851,7 +851,7 @@ _compute_next_intersection(Halfedge_handle he,
}
else {
// We have an overlapping subcurve.
icv = object_cast<X_monotone_curve_2>(&(inter_list.front()));
icv = boost::get<X_monotone_curve_2>(&(inter_list.front()));
CGAL_assertion(icv != nullptr);
if (m_geom_traits->is_closed_2_object()(*icv, ARR_MIN_END)) {
@ -869,14 +869,14 @@ _compute_next_intersection(Halfedge_handle he,
}
// Found an intersection to m_left_pt's right.
if (valid_intersection) return (inter_list.front());
if (valid_intersection) return Optional_intersection(inter_list.front());
// Discard the current intersection, which lies to m_left_pt's left.
inter_list.pop_front();
}
// If we reached here, the list of intersections is empty:
return CGAL::Object();
return Optional_intersection();
}
// The intersections with the curve have not been computed yet, so we
@ -894,7 +894,7 @@ _compute_next_intersection(Halfedge_handle he,
// Discard all intersection lying to the left of m_left_pt (if exists).
while (! inter_list.empty()) {
// Compare that current object with m_left_pt (if exists).
ip = object_cast<Intersect_point_2>(&(inter_list.front()));
ip = boost::get<Intersection_point>(&(inter_list.front()));
if (ip != nullptr) {
// We have a simple intersection point - if we don't have to skip it,
@ -920,7 +920,7 @@ _compute_next_intersection(Halfedge_handle he,
}
else {
// We have an overlapping subcurve.
icv = object_cast<X_monotone_curve_2>(&(inter_list.front()));
icv = boost::get<X_monotone_curve_2>(&(inter_list.front()));
CGAL_assertion(icv != nullptr);
if (m_geom_traits->is_closed_2_object()(*icv, ARR_MIN_END)) {
@ -947,8 +947,8 @@ _compute_next_intersection(Halfedge_handle he,
m_inter_map[p_curve] = inter_list;
// Return the first intersection object computed (may be empty).
if (inter_list.empty()) return CGAL::Object();
else return (inter_list.front());
if (inter_list.empty()) return Optional_intersection();
else return Optional_intersection(inter_list.front());
}
//-----------------------------------------------------------------------------
@ -1105,14 +1105,14 @@ _leftmost_intersection(Ccb_halfedge_circulator he_curr, bool on_boundary,
// Compute the next intersection of m_cv and the current halfedge.
bool intersection_on_right_boundary;
CGAL::Object iobj =
Optional_intersection iobj =
_compute_next_intersection(he_curr, left_equals_curr_endpoint,
intersection_on_right_boundary);
if (! iobj.is_empty()) {
if (iobj) {
// We have found an intersection (either a simple point or an
// overlapping x-monotone curve).
const Intersect_point_2* int_p = object_cast<Intersect_point_2>(&iobj);
const Intersection_point* int_p = boost::get<Intersection_point>(&*iobj);
if (int_p != nullptr) {
Point_2 ip = int_p->first;
@ -1134,7 +1134,7 @@ _leftmost_intersection(Ccb_halfedge_circulator he_curr, bool on_boundary,
else {
// We have located an overlapping curve. Assign ip as its left
// endpoint.
const X_monotone_curve_2* icv = object_cast<X_monotone_curve_2>(&iobj);
const X_monotone_curve_2* icv = boost::get<X_monotone_curve_2>(&*iobj);
CGAL_assertion(icv != nullptr);
Point_2 ip = min_vertex(*icv);

View File

@ -46,6 +46,8 @@
#include <CGAL/Iterator_project.h>
#include <CGAL/Iterator_transform.h>
#include <boost/pool/pool_alloc.hpp>
namespace CGAL {
/*! \class Arrangement_on_surface_2
@ -64,7 +66,7 @@ class Arrangement_on_surface_2 {
public:
typedef GeomTraits_ Geometry_traits_2;
typedef TopTraits_ Topology_traits;
typedef CGAL_ALLOCATOR(int) Allocator;
typedef boost::fast_pool_allocator<int> Allocator;
// first define adaptor ...
typedef Arr_traits_basic_adaptor_2<Geometry_traits_2> Traits_adaptor_2;
@ -308,6 +310,10 @@ public:
Base(iter, iend, pred)
{}
Edge_iterator(const Base& base) :
Base(base)
{}
// Casting to a halfedge iterator.
operator Halfedge_iterator() const
{
@ -342,6 +348,10 @@ public:
Base(iter, iend, pred)
{}
Edge_const_iterator(const Base& base) :
Base(base)
{}
// Casting to a halfedge iterator.
operator Halfedge_const_iterator() const
{
@ -432,6 +442,10 @@ public:
Base(iter, iend, is_unbounded)
{}
Unbounded_face_const_iterator(const Base& base) :
Base(base)
{}
// Casting to a face iterator.
operator Face_const_iterator() const
{

View File

@ -93,22 +93,25 @@ protected:
Right_side_category>::result
Are_all_sides_oblivious_category;
typedef typename Arrangement_2::Vertex_const_handle Vertex_const_handle;
typedef typename Arrangement_2::Halfedge_const_handle Halfedge_const_handle;
typedef typename Arrangement_2::Face_const_handle Face_const_handle;
typedef typename Arrangement_2::Vertex_const_handle Vertex_const_handle;
typedef typename Arrangement_2::Halfedge_const_handle Halfedge_const_handle;
typedef typename Arrangement_2::Face_const_handle Face_const_handle;
typedef typename Arrangement_2::Ccb_halfedge_circulator
Ccb_halfedge_circulator;
// Types used for caching intersection points:
typedef std::pair<Point_2, Multiplicity> Intersect_point_2;
typedef std::list<CGAL::Object> Intersect_list;
typedef std::pair<Point_2, Multiplicity> Intersection_point;
typedef boost::variant<Intersection_point, X_monotone_curve_2>
Intersection_result;
typedef boost::optional<Intersection_result> Optional_intersection;
typedef std::list<Intersection_result> Intersect_list;
typedef std::map<const X_monotone_curve_2*, Intersect_list>
Intersect_map;
typedef typename Intersect_map::iterator Intersect_map_iterator;
Intersect_map;
typedef typename Intersect_map::iterator Intersect_map_iterator;
typedef std::set<const X_monotone_curve_2*> Curves_set;
typedef typename Curves_set::iterator Curves_set_iterator;
typedef std::set<const X_monotone_curve_2*> Curves_set;
typedef typename Curves_set::iterator Curves_set_iterator;
// Data members:
Arrangement_2& m_arr; // The associated arrangement.
@ -378,14 +381,15 @@ private:
* point coincides with the right
* curve-end, which lies on the
* surface boundary.
* \return An object representing the next intersection: Intersect_point_2
* \return An object representing the next intersection: Intersection_point
* in case of a simple intersection point, X_monotone_curve_2 in
* case of an overlap, and an empty object if there is no
* intersection.
*/
CGAL::Object _compute_next_intersection(Halfedge_handle he,
bool skip_first_point,
bool& intersect_on_right_boundary);
Optional_intersection
_compute_next_intersection(Halfedge_handle he,
bool skip_first_point,
bool& intersect_on_right_boundary);
/*! Remove the next intersection of m_cv with the given halfedge from the map.
* \param he A handle to the halfedge.

View File

@ -3024,8 +3024,8 @@ public:
y_dapprox = y_interval_for_curve_end(*this, CGAL::ARR_MIN_END, prec);
// adapt y-interval
ymin = CGAL::min(ymin, y_dapprox.first);
ymax = CGAL::max(ymax, y_dapprox.second);
ymin = (CGAL::min)(ymin, y_dapprox.first);
ymax = (CGAL::max)(ymax, y_dapprox.second);
// right end
@ -3105,9 +3105,9 @@ public:
(curr_xy, prec);
// adapt y-interval
ymin = CGAL::min(ymin,
ymin = (CGAL::min)(ymin,
CGAL::to_double(xy_approx.first));
ymax = CGAL::max(ymax,
ymax = (CGAL::max)(ymax,
CGAL::to_double(xy_approx.second));
}
}

View File

@ -1459,29 +1459,24 @@ public:
OutputIterator operator()(const Arc_2& cv1, const Arc_2& cv2,
OutputIterator oi) const {
typedef unsigned int Multiplicity;
typedef std::pair<Point_2, Multiplicity> Intersection_point;
typedef boost::variant<Intersection_point, Arc_2> Intersection_result;
CERR("\nintersect; cv1: " << cv1
<< ";\n cv2:" << cv2 << "");
// if arcs overlap, just store their common part, otherwise compute
// point-wise intersections
std::vector< Arc_2 > common_arcs;
if (cv1._trim_if_overlapped(cv2, std::back_inserter(common_arcs))) {
typename std::vector< Arc_2 >::const_iterator it;
for(it = common_arcs.begin(); it < common_arcs.end(); it++) {
*oi++ = CGAL::make_object(*it);
}
std::vector<Arc_2> arcs;
if (cv1._trim_if_overlapped(cv2, std::back_inserter(arcs))) {
for (const auto& item : arcs) *oi++ = Intersection_result(item);
return oi;
}
// process non-ov erlapping case
typedef std::pair< Point_2, unsigned int > Point_and_mult;
typedef std::vector< Point_and_mult > Point_vector;
Point_vector vec;
typename Point_vector::const_iterator it;
std::vector<Intersection_point> vec;
Arc_2::_intersection_points(cv1, cv2, std::back_inserter(vec));
for (it = vec.begin(); it != vec.end(); it++) {
*oi++ = CGAL::make_object(*it);
}
for (const auto& item : vec) *oi++ = Intersection_result(item);
return oi;
}

View File

@ -572,7 +572,7 @@ void draw(const Arc_2& arc,
ref_bound = engine.pixel_h_r/CGAL_REFINE_X;
#ifdef CGAL_CKVA_RENDER_WITH_REFINEMENT
ref_bound = std::min(ref_bound, Rational(CGAL_REFINE_DOUBLE_APPROX));
ref_bound = (std::min)(ref_bound, Rational(CGAL_REFINE_DOUBLE_APPROX));
#endif
Gfx_OUT("computing y-coordinates\n");
@ -912,7 +912,7 @@ bool draw(const Point_2& pt, Coord_2& coord) {
const Coordinate_1& x0 = pt.x();
Rational ref_bound = engine.pixel_w_r / 2;
#ifdef CGAL_CKVA_RENDER_WITH_REFINEMENT
ref_bound = std::min(ref_bound, Rational(CGAL_REFINE_DOUBLE_APPROX));
ref_bound = (std::min)(ref_bound, Rational(CGAL_REFINE_DOUBLE_APPROX));
#endif
typename Curve_kernel_2::Algebraic_kernel_d_1::Approximate_relative_1
@ -932,7 +932,7 @@ bool draw(const Point_2& pt, Coord_2& coord) {
ref_bound = engine.pixel_h_r / CGAL_REFINE_X;
#ifdef CGAL_CKVA_RENDER_WITH_REFINEMENT
ref_bound = std::min(ref_bound, Rational(CGAL_REFINE_DOUBLE_APPROX));
ref_bound = (std::min)(ref_bound, Rational(CGAL_REFINE_DOUBLE_APPROX));
#endif
Coordinate_2 xy(x0, pt.curve(), pt.arcno());

View File

@ -80,17 +80,13 @@ public:
protected:
//! The base operators.
Base_intersect_2 m_base_intersect;
Halfedge_handle invalid_he;
/*! Constructor.
* The constructor is declared private to allow only the functor
* obtaining function, which is a member of the nesting class,
* constructing it.
*/
Intersect_2(const Base_intersect_2& base) :
m_base_intersect (base),
invalid_he()
{}
Intersect_2(const Base_intersect_2& base) : m_base_intersect (base) {}
//! Allow its functor obtaining function calling the private constructor.
friend class Arr_insertion_traits_2<Gt2, Arrangement_2>;
@ -101,6 +97,14 @@ public:
const X_monotone_curve_2& cv2,
OutputIterator oi)
{
typedef std::pair<Point_2, Multiplicity> Intersection_point;
typedef boost::variant<Intersection_point, X_monotone_curve_2>
Intersection_result;
typedef boost::variant<Intersection_point, Base_x_monotone_curve_2>
Intersection_base_result;
Halfedge_handle invalid_he;
if ((cv1.halfedge_handle() != invalid_he) &&
(cv2.halfedge_handle() != invalid_he) &&
(cv1.halfedge_handle() != cv2.halfedge_handle()))
@ -110,40 +114,32 @@ public:
return oi;
}
OutputIterator oi_end = m_base_intersect(cv1.base(), cv2.base(), oi);
const Base_x_monotone_curve_2* base_overlap_cv;
const std::pair<Base_point_2, unsigned int>* intersect_p;
std::vector<Intersection_base_result> xections;
m_base_intersect(cv1.base(), cv2.base(), std::back_inserter(xections));
// convert objects that are associated with Base_x_monotone_curve_2 to
// X_monotone_curve_2
for(; oi != oi_end; ++oi) {
base_overlap_cv = object_cast<Base_x_monotone_curve_2>(&(*oi));
if (base_overlap_cv != nullptr) {
// Add halfedge handles to the resulting curve.
Halfedge_handle he;
if (cv1.halfedge_handle() != invalid_he) he = cv1.halfedge_handle();
else if (cv2.halfedge_handle() != invalid_he)
he = cv2.halfedge_handle();
X_monotone_curve_2 overlap_cv (*base_overlap_cv, he);
overlap_cv.set_overlapping();
*oi = make_object (overlap_cv);
for (const auto& xection : xections) {
const Intersection_point*
p_p = boost::get<Intersection_point>(&xection);
if (p_p != nullptr) {
*oi++ = Intersection_result(xection);
continue;
}
else {
intersect_p =
object_cast<std::pair<Base_point_2, unsigned int> >(&(*oi));
const Base_x_monotone_curve_2* base_cv_p =
boost::get<Base_x_monotone_curve_2>(&xection);
CGAL_assertion(base_cv_p);
CGAL_assertion (intersect_p != nullptr);
*oi = make_object(std::make_pair(Point_2(intersect_p->first),
intersect_p->second));
}
// Add halfedge handles to the resulting curve.
Halfedge_handle he;
if (cv1.halfedge_handle() != invalid_he) he = cv1.halfedge_handle();
else if (cv2.halfedge_handle() != invalid_he)
he = cv2.halfedge_handle();
X_monotone_curve_2 cv(*base_cv_p, he);
cv.set_overlapping();
*oi++ = Intersection_result(cv);
}
// Return a past-the-end iterator.
return oi_end;
xections.clear();
return oi;
}
};

View File

@ -345,24 +345,31 @@ public:
class Intersect_2 {
protected:
//! The base traits.
const Arr_overlay_traits_2* m_traits;
const Arr_overlay_traits_2& m_traits;
/*! Constructor.
* The constructor is declared protected to allow only the functor
* obtaining function, which is a member of the nesting class,
* constructing it.
*/
Intersect_2(const Arr_overlay_traits_2* traits) : m_traits(traits) {}
Intersect_2(const Arr_overlay_traits_2& traits) : m_traits(traits) {}
//! Allow its functor obtaining function calling the protected constructor.
friend class Arr_overlay_traits_2<Gt2, Ar2, Ab2>;
public:
template<class OutputIterator>
template <typename OutputIterator>
OutputIterator operator()(const X_monotone_curve_2& xcv1,
const X_monotone_curve_2& xcv2,
OutputIterator oi)
{
typedef std::pair<Point_2, Multiplicity> Intersection_point;
typedef boost::variant<Intersection_point, X_monotone_curve_2>
Intersection_result;
typedef std::pair<Base_point_2, Multiplicity> Intersection_base_point;
typedef boost::variant<Intersection_base_point, Base_x_monotone_curve_2>
Intersection_base_result;
// In case the curves originate from the same arrangement, they are
// obviously interior-disjoint.
if (xcv1.color() == xcv2.color()) return oi;
@ -396,19 +403,16 @@ public:
// Note that we do not bother with curves whose left ends are open,
// since such curved did not intersect before.
const std::pair<Base_point_2, unsigned int>* base_ipt;
const Base_x_monotone_curve_2* overlap_xcv;
bool send_xcv1_first = true;
OutputIterator oi_end;
Parameter_space_in_x_2 ps_x_op = m_traits->parameter_space_in_x_2_object();
Parameter_space_in_y_2 ps_y_op = m_traits->parameter_space_in_y_2_object();
const Arr_parameter_space bx1 = ps_x_op(xcv1, ARR_MIN_END);
const Arr_parameter_space by1 = ps_y_op(xcv1, ARR_MIN_END);
const Arr_parameter_space bx2 = ps_x_op(xcv2, ARR_MIN_END);
const Arr_parameter_space by2 = ps_y_op(xcv2, ARR_MIN_END);
auto ps_x_op = m_traits.parameter_space_in_x_2_object();
auto ps_y_op = m_traits.parameter_space_in_y_2_object();
Arr_parameter_space bx1 = ps_x_op(xcv1, ARR_MIN_END);
Arr_parameter_space by1 = ps_y_op(xcv1, ARR_MIN_END);
Arr_parameter_space bx2 = ps_x_op(xcv2, ARR_MIN_END);
Arr_parameter_space by2 = ps_y_op(xcv2, ARR_MIN_END);
const Gt2* m_base_tr = m_traits->base_traits();
const Gt2* m_base_tr = m_traits.base_traits();
if ((bx1 == ARR_INTERIOR) && (by1 == ARR_INTERIOR) &&
(bx2 == ARR_INTERIOR) && (by2 == ARR_INTERIOR))
@ -419,15 +423,17 @@ public:
m_base_tr->construct_min_vertex_2_object()(xcv2.base())) == LARGER);
}
oi_end = (send_xcv1_first) ?
m_base_tr->intersect_2_object()(xcv1.base(), xcv2.base(), oi) :
m_base_tr->intersect_2_object()(xcv2.base(), xcv1.base(), oi);
auto intersector = m_base_tr->intersect_2_object();
std::vector<Intersection_base_result> xections;
(send_xcv1_first) ?
intersector(xcv1.base(), xcv2.base(), std::back_inserter(xections)) :
intersector(xcv2.base(), xcv1.base(), std::back_inserter(xections));
// Convert objects that are associated with Base_x_monotone_curve_2 to
// the exteneded X_monotone_curve_2.
while (oi != oi_end) {
base_ipt = object_cast<std::pair<Base_point_2, unsigned int> >(&(*oi));
for (const auto& xection : xections) {
const Intersection_base_point* base_ipt =
boost::get<Intersection_base_point>(&xection);
if (base_ipt != nullptr) {
// We have a red-blue intersection point, so we attach the
// intersecting red and blue halfedges to it.
@ -451,42 +457,44 @@ public:
// Create the extended point and add the multiplicity.
Point_2 ex_point(base_ipt->first, red_cell, blue_cell);
*oi++ = CGAL::make_object(std::make_pair(ex_point, base_ipt->second));
*oi++ =
Intersection_result(std::make_pair(ex_point, base_ipt->second));
continue;
}
const Base_x_monotone_curve_2* overlap_xcv =
boost::get<Base_x_monotone_curve_2>(&xection);
CGAL_assertion(overlap_xcv != nullptr);
// We have a red-blue overlap, so we mark the curve accordingly.
Halfedge_handle_red red_he;
Halfedge_handle_blue blue_he;
if (xcv1.color() == RED) {
red_he = xcv1.red_halfedge_handle();
// Overlap can occur only between curves from a different color.
CGAL_assertion(xcv2.color() == BLUE);
blue_he = xcv2.blue_halfedge_handle();
}
else {
overlap_xcv = object_cast<Base_x_monotone_curve_2>(&(*oi));
CGAL_assertion(overlap_xcv != nullptr);
CGAL_assertion((xcv1.color() == BLUE) && (xcv2.color() == RED));
// We have a red-blue overlap, so we mark the curve accordingly.
Halfedge_handle_red red_he;
Halfedge_handle_blue blue_he;
if (xcv1.color() == RED) {
red_he = xcv1.red_halfedge_handle();
// Overlap can occur only between curves from a different color.
CGAL_assertion(xcv2.color() == BLUE);
blue_he = xcv2.blue_halfedge_handle();
}
else {
CGAL_assertion((xcv1.color() == BLUE) && (xcv2.color() == RED));
red_he = xcv2.red_halfedge_handle();
blue_he = xcv1.blue_halfedge_handle();
}
*oi++ = CGAL::make_object(X_monotone_curve_2(*overlap_xcv,
red_he, blue_he));
red_he = xcv2.red_halfedge_handle();
blue_he = xcv1.blue_halfedge_handle();
}
X_monotone_curve_2 cv(*overlap_xcv, red_he, blue_he);
*oi++ = Intersection_result(cv);
}
// Return the past-the-end iterator.
return oi_end;
return oi;
}
};
/*! Obtain an Intersect_2 functor object. */
Intersect_2 intersect_2_object() const { return Intersect_2(this); }
Intersect_2 intersect_2_object() const { return Intersect_2(*this); }
/*! A functor that splits an arc at a point. */
class Split_2 {

View File

@ -17,6 +17,7 @@
#include <CGAL/Arr_tags.h>
#include <CGAL/Arrangement_2/Arr_traits_adaptor_2_dispatching.h>
#include <CGAL/use.h>
#include "Traits_base_test.h"
/*! Traits test */
@ -989,18 +990,22 @@ intersect_wrapper(std::istringstream& str_stream)
typedef typename Traits::X_monotone_curve_2 X_monotone_curve_2;
typedef typename Traits::Multiplicity Multiplicity;
typedef std::pair<Point_2, Multiplicity> Intersection_point;
typedef boost::variant<Intersection_point, X_monotone_curve_2>
Intersection_result;
unsigned int id1, id2;
str_stream >> id1 >> id2;
std::vector<CGAL::Object> object_vec;
std::vector<Intersection_result> xections;
this->m_geom_traits.intersect_2_object()(this->m_xcurves[id1],
this->m_xcurves[id2],
std::back_inserter(object_vec));
std::back_inserter(xections));
std::cout << "Test: intersect( " << this->m_xcurves[id1] << ","
<< this->m_xcurves[id2] << " ) ? ";
size_t num;
str_stream >> num;
if (!this->compare(num, object_vec.size(), "size")) return false;
if (! this->compare(num, xections.size(), "size")) return false;
for (size_t i = 0; i < num; ++i) {
unsigned int type; // 0 - point, 1 - x-monotone curve
@ -1011,30 +1016,25 @@ intersect_wrapper(std::istringstream& str_stream)
if (type == 0) str_stream >> multiplicity;
unsigned int exp_type = 1;
const X_monotone_curve_2 * xcv_ptr =
CGAL::object_cast<X_monotone_curve_2> (&(object_vec[i]));
const X_monotone_curve_2* cv_p =
boost::get<X_monotone_curve_2>(&(xections[i]));
if (xcv_ptr != NULL) {
if (!this->compare(type, exp_type, "type")) return false;
if (!this->compare_curves(this->m_xcurves[id], *xcv_ptr)) return false;
if (cv_p != nullptr) {
if (! this->compare(type, exp_type, "type")) return false;
if (! this->compare_curves(this->m_xcurves[id], *cv_p)) return false;
continue;
}
exp_type = 0;
typedef std::pair<Point_2,Multiplicity> Point_2_pair;
const Point_2_pair * pt_pair_ptr =
CGAL::object_cast<Point_2_pair> (&(object_vec[i]));
assert(pt_pair_ptr != NULL);
if (!this->compare(type, exp_type, "type")) return false;
if (!this->compare_points(this->m_points[id], (*pt_pair_ptr).first))
return false;
if (!this->compare(multiplicity, (*pt_pair_ptr).second, "multiplicity"))
return false;
} //forloop
object_vec.clear();
const Intersection_point* p_p =
boost::get<Intersection_point>(&(xections[i]));
assert(p_p != nullptr);
if (! this->compare(type, exp_type, "type")) return false;
if (! this->compare_points(this->m_points[id], p_p->first)) return false;
if (! this->compare(multiplicity, p_p->second, "multiplicity")) return false;
}
xections.clear();
return true;
}

View File

@ -634,6 +634,12 @@ Seam meshes are for example used in Chapter \ref PkgSurfaceMeshParameterization
to parameterize a topological sphere by first virtually cutting it into a topological
disk.
\subsection BGLInheriting Inheriting from a Model of a Face Graph Concept
In order for a type `FG` to be a model of one of the face graph concepts, a specialization of
`boost::graph_traits<FG>` must exist. When you derive a class from `FG` this graph traits class specialization does not match.
For such cases, a header file consuming some user defined macros is provided to make the derived class a valid model
of the same concept. See `CGAL/boost/graph/graph_traits_inheritance_macros.h` for more details.
\section BGLPartitioning Graph Partitioning
For algorithms that operate locally, partitioning is often an easy way to parallelize
@ -653,6 +659,99 @@ can be done directly using `Face_filtered_graph`.
Using \ref BGLNamedParameters some of the many options of METIS can be customized,
as shown in \ref BGL_polyhedron_3/polyhedron_partition.cpp "this example".
\section BGLGraphcut Graph Cut
An optimal partition from a set of labels can be computed through a
graph cut approach called alpha expansion
\cgalCite{Boykov2001FastApproximate}. \cgal provides
`CGAL::alpha_expansion_graphcut()` which, for a graph \f$(V,E)\f$,
computes the partition `f` that minimizes the following cost function:
\f[
\mathrm{C}(f) = \sum_{\{v0,v1\} \in E} C_E(v0,v1) + \sum_{v \in V} C_V(f_v)
\f]
where \f$C_E(v0,v1)\f$ is the edge cost of assigning a different label
to \f$v0\f$ and \f$v1\f$, and \f$C_V(f_v)\f$ is the vertex cost of
assigning the label \f$f\f$ to the vertex \f$v\f$.
Three different implementations are provided and can be selected by
using one of the following tags:
- `CGAL::Alpha_expansion_boost_adjacency_list_tag` (default)
- `CGAL::Alpha_expansion_boost_compressed_sparse_raw_tag`
- `CGAL::Alpha_expansion_MaxFlow_tag`, released under GPL
license and provided by the \ref PkgSurfaceMeshSegmentationRef
package
All these implementations produce the exact same result but behave
differently in terms of timing and memory (see
\cgalFigureRef{alpha_exp}). The _MaxFlow_ implementation is the
fastest, but it grows rapidly in memory when increasing the complexity
of the input graph and labeling; the _compressed sparse raw_ (CSR) is very
efficient from a memory point of view but becomes very slow as the
complexity of the input graph and labeling increases; the _adjacency
list_ version provides a good compromise and is therefore the default
implementation.
\cgalFigureBegin{alpha_exp, alpha_expansion.png}
Comparison of time and memory consumed by the different alpha
expansion implementations.
\cgalFigureEnd
\subsection BGLGraphcutExample Example
The following example shows how to apply the alpha expansion algorithm
to a `boost::adjacency_list` describing a 2D array with 3 labels "X",
" " and "O":
\cgalExample{BGL_graphcut/alpha_expansion_example.cpp}
The output of this program shows how the initial 2D array is
regularized spatially:
```
Input:
XOX
XX X O
OX OO
X OOX
OXOO
Alpha expansion...
Output:
XXX
XX O
XX OO
X OOO
OOOO
```
\subsection BGLGraphcutRegularizeSelection Application to Regularization of the Borders of a Face Selection
Manually selecting faces on a triangle mesh may create irregular
borders (sawtooth) because of the shape of the triangles. Such borders
can be regularized using the alpha expansion algorithm.
\cgal provides a function `CGAL::regularize_face_selection_borders()`
to apply this algorithm to the borders of a face selection on a
`FaceGraph`. \cgalFigureRef{regularization_fig} shows how this
function affects a selection depending on the parameters.
\cgalFigureBegin{regularization_fig, regularize_selection.png}
Regularization of the borders of a face selection using alpha
expansion. Different outputs are shown for different weight
parameters, with and without preventing unselection.
\cgalFigureEnd
The following example shows how to apply this alpha expansion
regularization to the borders of a face selection of a
`CGAL::Surface_mesh` object:
\cgalExample{BGL_graphcut/face_selection_borders_regularization_example.cpp}
*/
} /* namespace CGAL */

View File

@ -15,29 +15,21 @@ INPUT += ${CGAL_PACKAGE_INCLUDE_DIR}/CGAL/boost/graph/Euler_operations.h \
${CGAL_PACKAGE_INCLUDE_DIR}/CGAL/boost/graph/io.h \
${CGAL_PACKAGE_INCLUDE_DIR}/CGAL/boost/graph/partition.h \
${CGAL_PACKAGE_INCLUDE_DIR}/CGAL/boost/graph/METIS/partition_graph.h \
${CGAL_PACKAGE_INCLUDE_DIR}/CGAL/boost/graph/METIS/partition_dual_graph.h
${CGAL_PACKAGE_INCLUDE_DIR}/CGAL/boost/graph/METIS/partition_dual_graph.h \
${CGAL_PACKAGE_INCLUDE_DIR}/CGAL/boost/graph/alpha_expansion_graphcut.h \
${CGAL_PACKAGE_INCLUDE_DIR}/CGAL/boost/graph/graph_traits_inheritance_macros.h
EXAMPLE_PATH = ${CGAL_Surface_mesh_skeletonization_EXAMPLE_DIR} \
${CGAL_Surface_mesh_segmentation_EXAMPLE_DIR} \
${CGAL_Polygon_mesh_processing_EXAMPLE_DIR} \
${CGAL_Surface_mesh_EXAMPLE_DIR} \
${CGAL_Property_map_EXAMPLE_DIR} \
${CGAL_Polyhedron_EXAMPLE_DIR} \
${CGAL_BGL_EXAMPLE_DIR}
ALIASES += "bgllink{1}=<a href=\"http://www.boost.org/libs/graph/doc/\1.html\"><code>\1</code></a>"
# macros to be used inside the code
ALIASES += "cgalNamedParamsBegin=<dl class=\"params\"><dt>Named Parameters</dt><dd> <table class=\"params\">"
ALIASES += "cgalNamedParamsEnd=</table> </dd> </dl>"
ALIASES += "cgalParamBegin{1}=<tr><td class=\"paramname\">\ref BGL_\1 \"\1\"</td><td>"
ALIASES += "cgalParamEnd=</td></tr>"
#macros for NamedParameters.txt
ALIASES += "cgalNPTableBegin=<dl class=\"params\"><dt></dt><dd> <table class=\"params\">"
ALIASES += "cgalNPTableEnd=</table> </dd> </dl>"
ALIASES += "cgalNPBegin{1}=<tr><td class=\"paramname\">\1 </td><td>"
ALIASES += "cgalNPEnd=</td></tr>"
EXTRACT_ALL=NO
HIDE_UNDOC_MEMBERS = YES
HIDE_UNDOC_CLASSES = YES

View File

@ -1,8 +1,8 @@
/*!
\defgroup bgl_namedparameters BGL Named Parameters
\defgroup bgl_namedparameters Named Parameters
\ingroup PkgBGLRef
The algorithms of the \sc{Bgl} often have many parameters with default
The algorithms of the Boost Graph Library (\sc{Bgl}) often have many parameters with default
values that are appropriate for most cases. In general, when no
special treatment is applied, the values of such parameters are passed
as a sequence. Deviating from the default for a certain parameter
@ -20,181 +20,26 @@ dijkstra_shortest_paths(g, s, predecessor_map(&p[0]).distance_map(&d[0]));
In the \sc{Bgl} manual, this is called
<a href="https://www.boost.org/libs/graph/doc/bgl_named_params.html">named parameters</a>.
The named parameters in the example use the tags `predecessor_map` and `distance_map`
and they are concatenated with the dot operator.<BR>
The named parameters in the snippet use the tags `predecessor_map` and `distance_map`
and they are concatenated using the dot operator.<BR>
In the following, we assume that `PolygonMesh` is a model of the concept `FaceGraph`.
Note that for some functions, the type might be more specific:
A similar mechanism was introduced in \cgal, with the small difference that the named parameters
tag live in the `CGAL::parameters::` namespace and `CGAL::parameters::all_default()` can be used to indicate
that default values of optional named parameters must be used.
As in the \sc{BGL}, named parameters in \cgal are also concatenated using
the dot operator, and a typical usage is thus:
Here is the list of the named parameters available in this package:
\code {.cpp}
Graph g1, g2;
Vertex_point_map_2 vpm_2; // an hypothetical custom property map assigning a Point to the vertices of g2
\cgalNPTableBegin
\cgalNPBegin{vertex_point_map} \anchor BGL_vertex_point_map
is the property map with the points associated to the vertices of the polygon mesh.\n
<b>Type:</b> a class model of `ReadablePropertyMap` with
`boost::graph_traits<PolygonMesh>::%vertex_descriptor` as key type and
a \cgal point type as value type. \n
<b>Default:</b> \code boost::get(CGAL::vertex_point, pmesh) \endcode
\cgalNPEnd
\cgalNPBegin{vertex_index_map} \anchor BGL_vertex_index_map
is the property map associating a unique index to each vertex of a polygon mesh `g`,
between `0` and `num_vertices(g)-1`.
If this parameter is not passed, internal machinery will create and initialize a vertex index
property map, either using the internal property map if it exists or using an external map. The latter
might result in - slightly - worsened performance in case of non-constant complexity for index access.\n
<b>Type:</b> a class model of `ReadablePropertyMap` with
`boost::graph_traits<PolygonMesh>::%vertex_descriptor` as key type and the value type
\code typename boost::property_traits<typename boost::property_map<PolygonMesh, CGAL::vertex_index_t>::type>::value_type \endcode
<b>Default:</b> an initialized vertex index property map
\cgalNPEnd
\cgalNPBegin{halfedge_index_map} \anchor BGL_halfedge_index_map
is the property map associating a unique index to each halfedge of a polygon mesh,
between `0` and `num_halfedges(g)-1`.
If this parameter is not passed, internal machinery will create and initialize a halfedge index
property map, either using the internal property map if it exists or using an external map. The latter
might result in - slightly - worsened performance in case of non-constant complexity for index access.\n
<b>Type:</b> a class model of `ReadablePropertyMap` with
`boost::graph_traits<PolygonMesh>::%halfedge_descriptor` as key type and the value type:
\code typename boost::property_traits<typename boost::property_map<PolygonMesh, CGAL::halfedge_index_t>::type>::value_type \endcode
<b>Default:</b> an initialized halfedge index property map
\cgalNPEnd
\cgalNPBegin{edge_index_map} \anchor BGL_edge_index_map
is the property map associating a unique index to each edge of a polygon mesh,
between `0` and `num_edges(g)-1`.
If this parameter is not passed, internal machinery will create and initialize a edge index
property map, either using the internal property map if it exists or using an external map. The latter
might result in - slightly - worsened performance in case of non-constant complexity for index access.\n
<b>Type:</b> a class model of `ReadablePropertyMap` with
`boost::graph_traits<PolygonMesh>::%edge_descriptor` as key type and the value type:
\code typename boost::property_traits<typename boost::property_map<PolygonMesh, CGAL::edge_index_t>::type>::value_type \endcode
<b>Default:</b> an initialized edge index property map
\cgalNPEnd
\cgalNPBegin{face_index_map} \anchor BGL_face_index_map
is the property map associating a unique index to each face of a polygon mesh,
between `0` and `num_faces(g)-1`.
If this parameter is not passed, internal machinery will create and initialize a face index
property map, either using the internal property map if it exists or using an external map. The latter
might result in - slightly - worsened performance in case of non-constant complexity for index access.\n
<b>Type:</b> a class model of `ReadablePropertyMap` with
`boost::graph_traits<PolygonMesh>::%face_descriptor` as key type and the value type:
\code typename boost::property_traits<typename boost::property_map<PolygonMesh, CGAL::face_index_t>::type>::value_type \endcode
<b>Default:</b> an initialized face index property map
\cgalNPEnd
\cgalNPBegin{edge_is_constrained_map} \anchor BGL_edge_is_constrained_map
is the property map containing information about edges of the input polygon mesh
being marked or not.\n
<b>Type:</b> a class model of `ReadWritePropertyMap` with
`boost::graph_traits<PolygonMesh>::%edge_descriptor` as key type and
`bool` as value type. It should be default constructible.\n
<b>Default:</b> a default property map where no edge is constrained
\cgalNPEnd
\cgalNPBegin{use_binary_mode} \anchor BGL_use_binary_mode
is a Boolean indicating whether the binary mode or the ASCII mode should be used
when writing data into a stream.\n
<b>Type:</b> `bool`\n
<b>Default:</b> Function specific.
\cgalNPEnd
\cgalNPBegin{METIS_options} \anchor BGL_METIS_options
is a parameter used in `partition_graph()` and `partition_dual_graph()`
to pass options to the METIS graph partitioner. The many options of METIS
are not described here. Instead, users should refer to METIS'
<a href="http://glaros.dtc.umn.edu/gkhome/fetch/sw/metis/manual.pdf">documentation</a>.\n
<b>Type:</b> an array of size `METIS_NOPTIONS` with value type `idx_t`
(an integer type defined by METIS). \n
<b>Default:</b> an array of size `METIS_NOPTIONS` with value type `idx_t`,
initialized using the function `METIS_SetDefaultOptions()`.
\cgalNPEnd
\cgalNPBegin{vertex_partition_id_map} \anchor BGL_vertex_partition_id_map
is the property map storing for each vertex of the mesh the id of the subpart
of the partition that has been assigned to this vertex.\n
<b>Type:</b> a class model of `ReadWritePropertyMap` with
`boost::graph_traits<PolygonMesh>::%vertex_descriptor` as key type and
`int` as value type. \n
<b>Default:</b> None: this property map is used to store the partition IDs of the vertices
as result of a partition algorithm; if it is not provided, this information is
simply inaccessible.
\cgalNPEnd
\cgalNPBegin{face_partition_id_map} \anchor BGL_face_partition_id_map
is the property map storing for each face of the mesh the id of the subpart
of the partition that has been assigned to this face.\n
<b>Type:</b> a class model of `ReadWritePropertyMap` with
`boost::graph_traits<PolygonMesh>::%face_descriptor` as key type and
`int` as value type. \n
<b>Default:</b> None: this property map is used to store the partition IDs of the faces
as result of a partition algorithm; if it is not provided, this information is
simply inaccessible.
\cgalNPEnd
\cgalNPBegin{vertex_to_vertex_output_iterator} \anchor BGL_vertex_to_vertex_output_iterator
is a model of `OutputIterator` accepting `std::pair<vertex_descriptor, vertex_descriptor>`
A typical use case is mapping the vertices from a source mesh to its copy's after a `copy_face_graph()`
operation.\n
<b>Type:</b>a class model of `OutputIterator` accepting
`std::pair<`boost::graph_traits<PolygonMesh>::%vertex_descriptor, `boost::graph_traits<PolygonMesh>::%vertex_descriptor>`.\n
<b>Default:</b> Emptyset_iterator
\cgalNPEnd
\cgalNPBegin{halfedge_to_halfedge_output_iterator} \anchor BGL_halfedge_to_halfedge_output_iterator
is a model of `OutputIterator` accepting `std::pair<halfedge_descriptor, halfedge_descriptor>`
A typical use case is mapping the halfedges from a source mesh to its copy's after a `copy_face_graph()`
operation.\n
<b>Type:</b>a class model of `OutputIterator` accepting
`std::pair<`boost::graph_traits<PolygonMesh>::%halfedge_descriptor, `boost::graph_traits<PolygonMesh>::%halfedge_descriptor>`.\n
<b>Default:</b> Emptyset_iterator
\cgalNPEnd
\cgalNPBegin{face_to_face_output_iterator} \anchor BGL_face_to_face_output_iterator
is a model of `OutputIterator` accepting `std::pair<face_descriptor, face_descriptor>`
A typical use case is mapping the faces from a source mesh to its copy's after a `copy_face_graph()`
operation.\n
<b>Type:</b>a class model of `OutputIterator` accepting
`std::pair<`boost::graph_traits<PolygonMesh>::%face_descriptor, `boost::graph_traits<PolygonMesh>::%face_descriptor>`.\n
<b>Default:</b> Emptyset_iterator
\cgalNPEnd
\cgalNPBegin{vertex_to_vertex_map} \anchor BGL_vertex_to_vertex_map
is a property map storing for each vertex of a source mesh the corresponding vertex of another mesh.\n
A typical use case is mapping the vertices from a source mesh to its copy's after a `copy_face_graph()`
operation.\n
<b>Type:</b>a class model of `ReadWritePropertyMap` with
`boost::graph_traits<PolygonMesh1>::%vertex_descriptor` as key type and
`boost::graph_traits<PolygonMesh2>::%vertex_descriptor` as value type.\n
<b>Default:</b> None.
\cgalNPEnd
\cgalNPBegin{halfedge_to_halfedge_map} \anchor BGL_halfedge_to_halfedge_map
is a property map storing for each halfedge of a source mesh the corresponding halfedge of another mesh.\n
A typical use case is mapping the vertices from a source mesh to its copy's after a `copy_face_graph()`
operation.\n
<b>Type:</b>a class model of `ReadWritePropertyMap` with
`boost::graph_traits<PolygonMesh1>::%halfedge_descriptor` as key type and
`boost::graph_traits<PolygonMesh2>::%halfedge_descriptor` as value type.\n
<b>Default:</b> None.
\cgalNPEnd
\cgalNPBegin{face_to_face_map} \anchor BGL_face_to_face_map
is a property map storing for each face of a source mesh the corresponding face of another mesh.\n
A typical use case is mapping the vertices from a source mesh to its copy's after a `copy_face_graph()`
operation.\n
<b>Type:</b>a class model of `ReadWritePropertyMap` with
`boost::graph_traits<PolygonMesh1>::%face_descriptor` as key type and
`boost::graph_traits<PolygonMesh2>::%face_descriptor` as value type.\n
<b>Default:</b> None.
\cgalNPEnd
\cgalNPTableEnd
// without any named parameter (default values are used)
CGAL::copy_face_graph(g1, g2);
// specifying named parameters for the second graph
CGAL::copy_face_graph(g1, g2,
CGAL::parameters::all_default(),
CGAL::parameters::vertex_point_map(vpm_2));
\endcode
*/
˛

View File

@ -533,7 +533,8 @@ both in term of time and memory.
\addtogroup PkgBGLPartition
Methods to split a mesh into subdomains, using the library
<a href="http://glaros.dtc.umn.edu/gkhome/metis/metis/overview">METIS</a>.
<a href="http://glaros.dtc.umn.edu/gkhome/metis/metis/overview">METIS</a> or a graphcut
implementation.
*/
/*!
@ -701,6 +702,7 @@ user might encounter.
- `CGAL::reduce_vertex_selection()`
- `CGAL::select_incident_faces()`
- `CGAL::expand_face_selection_for_removal()`
- `CGAL::regularize_face_selection_borders()`
\cgalCRPSection{Conversion Functions}
- `CGAL::split_graph_into_polylines()`
@ -711,15 +713,17 @@ user might encounter.
- `CGAL::Graph_with_descriptor_with_graph`
- `CGAL::Graph_with_descriptor_with_graph_property_map`
- `CGAL::Seam_mesh`
- `CGAL/boost/graph/graph_traits_inheritance_macros.h`
\cgalCRPSection{Partitioning Methods}
- `CGAL::METIS::partition_graph()`
- `CGAL::METIS::partition_dual_graph()`
- `CGAL::alpha_expansion_graphcut()`
\cgalCRPSection{I/O Functions}
- \link PkgBGLIOFct CGAL::read_off() \endlink
- \link PkgBGLIOFct CGAL::write_off() \endlink
- \link PkgBGLIOFct CGAL::write_wrl() \endlink
- \link PkgBGLIOFct `CGAL::read_off()` \endlink
- \link PkgBGLIOFct `CGAL::write_off()` \endlink
- \link PkgBGLIOFct `CGAL::write_wrl()` \endlink
- `CGAL::write_vtp()`
*/

View File

@ -3,6 +3,8 @@
\example BGL_arrangement_2/arr_rational_nt.h
\example BGL_arrangement_2/arrangement_dual.cpp
\example BGL_arrangement_2/primal.cpp
\example BGL_graphcut/alpha_expansion_example.cpp
\example BGL_graphcut/face_selection_borders_regularization_example.cpp
\example BGL_polyhedron_3/copy_polyhedron.cpp
\example BGL_polyhedron_3/cube.off
\example BGL_polyhedron_3/distance.cpp
@ -29,4 +31,6 @@
\example Surface_mesh_segmentation/extract_segmentation_into_mesh_example.cpp
\example Polygon_mesh_processing/face_filtered_graph_example.cpp
\example Property_map/dynamic_properties.cpp
\example Surface_mesh/sm_derivation.cpp
\example Polyhedron/poly_derivation.cpp
*/

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

View File

@ -0,0 +1,43 @@
# Created by the script cgal_create_CMakeLists
# This is the CMake script for compiling a set of CGAL applications.
cmake_minimum_required(VERSION 3.1...3.15)
project( BGL_graphcut_Examples )
# CGAL and its components
find_package( CGAL QUIET COMPONENTS )
if ( NOT CGAL_FOUND )
message(STATUS "This project requires the CGAL library, and will not be compiled.")
return()
endif()
# Boost and its components
find_package( Boost REQUIRED )
if ( NOT Boost_FOUND )
message(STATUS "This project requires the Boost library, and will not be compiled.")
return()
endif()
# include for local directory
# include for local package
# Creating entries for all C++ files with "main" routine
# ##########################################################
create_single_source_cgal_program( "alpha_expansion_example.cpp" )
create_single_source_cgal_program( "face_selection_borders_regularization_example.cpp" )

View File

@ -0,0 +1,96 @@
#include <CGAL/boost/graph/alpha_expansion_graphcut.h>
#include <boost/graph/adjacency_list.hpp>
struct Vertex_property
{
int label;
std::vector<double> cost;
};
struct Edge_property
{
double weight;
};
using Graph = boost::adjacency_list <boost::setS,
boost::vecS,
boost::undirectedS,
Vertex_property,
Edge_property>;
using GT = boost::graph_traits<Graph>;
using vertex_descriptor = GT::vertex_descriptor;
using edge_descriptor = GT::edge_descriptor;
int main()
{
std::array<char, 3> labels = { 'X', ' ', 'O' };
std::array<std::array<int, 6>, 5> input
= { { { 0, 2, 0, 1, 1, 1 },
{ 0, 0, 1, 0, 1, 2 },
{ 2, 0, 1, 1, 2, 2 },
{ 0, 1, 1, 2, 2, 0 },
{ 1, 1, 2, 0, 2, 2 } } };
std::array<std::array<vertex_descriptor, 6>, 5> vertices;
// Init vertices from values
Graph g;
for (std::size_t i = 0; i < input.size(); ++ i)
for (std::size_t j = 0; j < input[i].size(); ++ j)
{
vertices[i][j] = boost::add_vertex(g);
g[vertices[i][j]].label = input[i][j];
// Cost of assigning this vertex to any label is positive except
// for current label which is 0 (favor init solution)
g[vertices[i][j]].cost.resize(3, 1);
g[vertices[i][j]].cost[std::size_t(input[i][j])] = 0;
}
// Display input values
std::cerr << "Input:" << std::endl;
for (std::size_t i = 0; i < vertices.size(); ++ i)
{
for (std::size_t j = 0; j < vertices[i].size(); ++ j)
std::cerr << labels[std::size_t(g[vertices[i][j]].label)];
std::cerr << std::endl;
}
// Init adjacency
double weight = 0.5;
for (std::size_t i = 0; i < vertices.size(); ++ i)
for (std::size_t j = 0; j < vertices[i].size(); ++ j)
{
// Neighbor vertices are connected
if (i < vertices.size() - 1)
{
edge_descriptor ed = boost::add_edge (vertices[i][j], vertices[i+1][j], g).first;
g[ed].weight = weight;
}
if (j < vertices[i].size() - 1)
{
edge_descriptor ed = boost::add_edge (vertices[i][j], vertices[i][j+1], g).first;
g[ed].weight = weight;
}
}
std::cerr << std::endl << "Alpha expansion..." << std::endl << std::endl;
CGAL::alpha_expansion_graphcut (g,
get (&Edge_property::weight, g),
get (&Vertex_property::cost, g),
get (&Vertex_property::label, g),
CGAL::parameters::vertex_index_map (get (boost::vertex_index, g)));
// Display output graph
std::cerr << "Output:" << std::endl;
for (std::size_t i = 0; i < vertices.size(); ++ i)
{
for (std::size_t j = 0; j < vertices[i].size(); ++ j)
std::cerr << labels[std::size_t(g[vertices[i][j]].label)];
std::cerr << std::endl;
}
return 0;
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,52 @@
#include <CGAL/Simple_cartesian.h>
#include <CGAL/Surface_mesh.h>
#include <CGAL/boost/graph/selection.h>
#include <fstream>
#include <iostream>
using Kernel = CGAL::Simple_cartesian<double>;
using Mesh = CGAL::Surface_mesh<Kernel::Point_3>;
using Face_index = Mesh::Face_index;
int main(int argc, char** argv)
{
std::ifstream in((argc>1) ? argv[1] : "data/blobby.off");
if(!in)
{
std::cerr << "Error: could not read input file" << std::endl;
return EXIT_FAILURE;
}
Mesh mesh;
CGAL::read_off (in, mesh);
boost::unordered_map<Face_index, bool> is_selected_map;
// randomly select 1/3 of faces
std::size_t nb_selected_before = 0;
CGAL::Random rand;
for (Face_index fi : faces(mesh))
{
bool selected = (rand.get_double() < 1. / 3.);
is_selected_map[fi] = selected;
if (selected)
nb_selected_before ++;
}
std::cerr << nb_selected_before << " selected before regularization" << std::endl;
CGAL::regularize_face_selection_borders (mesh,
boost::make_assoc_property_map(is_selected_map),
0.5); // using weight = 0.5
std::size_t nb_selected_after = 0;
for (const auto& sel : is_selected_map)
if (sel.second)
++ nb_selected_after;
std::cerr << nb_selected_after << " selected after regularization" << std::endl;
return EXIT_SUCCESS;
}

View File

@ -35,17 +35,17 @@ int main(int argc, char* argv[])
std::ifstream in((argc>1)?argv[1]:"cube.off");
in >> S;
assert( CGAL::is_valid_polygon_mesh(S) );
// Note that the vertex_point property of the Source and Target1
// come from different kernels.
typedef CGAL::Surface_mesh<Point> Target1;
Target1 T1;
{
CGAL::copy_face_graph(S, T1);
std::ofstream out("sm.off");
out.precision(17);
out << T1;
}
CGAL::copy_face_graph(S, T1);
assert( CGAL::is_valid_polygon_mesh(T1) );
assert( vertices(S).size()==vertices(T1).size() );
assert( halfedges(S).size()==halfedges(T1).size() );
assert( faces(S).size()==faces(T1).size() );
#if defined(CGAL_USE_OPENMESH)
typedef OpenMesh::PolyMesh_ArrayKernelT</* MyTraits*/> Target2;
@ -63,7 +63,13 @@ int main(int argc, char* argv[])
CGAL::copy_face_graph(S, T2, CGAL::parameters::vertex_to_vertex_output_iterator(std::inserter(v2v, v2v.end()))
.halfedge_to_halfedge_output_iterator(std::inserter(h2h, h2h.end()))
.face_to_face_output_iterator(std::inserter(f2f, f2f.end())));
OpenMesh::IO::write_mesh(T2, "om.off");
assert( CGAL::is_valid_polygon_mesh(T2) );
assert( v2v.size()==vertices(T2).size() );
assert( h2h.size()==halfedges(T2).size() );
assert( f2f.size()==faces(T2).size() );
assert( vertices(S).size()==vertices(T2).size() );
assert( halfedges(S).size()==halfedges(T2).size() );
assert( faces(S).size()==faces(T2).size() );
}
#endif
S.clear();
@ -80,13 +86,14 @@ int main(int argc, char* argv[])
boost::unordered_map<source_vertex_descriptor, tm_vertex_descriptor> v2v;
boost::unordered_map<source_halfedge_descriptor, tm_halfedge_descriptor> h2h;
boost::unordered_map<source_face_descriptor, tm_face_descriptor> f2f;
CGAL::copy_face_graph(T1, S, std::inserter(v2v, v2v.end()), std::inserter(h2h, h2h.end()));
std::ofstream out("reverse.off");
out.precision(17);
out << S;
CGAL::copy_face_graph(T1, S, CGAL::parameters::vertex_to_vertex_map(boost::make_assoc_property_map(v2v))
.halfedge_to_halfedge_output_iterator(std::inserter(h2h, h2h.end()))
.face_to_face_map(boost::make_assoc_property_map(f2f)));
assert( CGAL::is_valid_polygon_mesh(S) );
assert( vertices(S).size()==vertices(T1).size() );
assert( halfedges(S).size()==halfedges(T1).size() );
assert( faces(S).size()==faces(T1).size() );
}
return 0;
}

View File

@ -2,8 +2,8 @@
#include <CGAL/Regular_triangulation_2.h>
#include <CGAL/boost/graph/graph_traits_Regular_triangulation_2.h>
#include <CGAL/internal/boost/function_property_map.hpp>
#include <boost/property_map/function_property_map.hpp>
#include <boost/graph/kruskal_min_spanning_tree.hpp>
#include <fstream>
@ -75,7 +75,7 @@ int main(int argc,char* argv[])
std::list<edge_descriptor> mst;
boost::kruskal_minimum_spanning_tree(tr, std::back_inserter(mst),
vertex_index_map(vertex_index_pmap)
.weight_map(CGAL::internal::boost_::make_function_property_map<
.weight_map(boost::make_function_property_map<
edge_descriptor, FT, Edge_weight_functor>(Edge_weight_functor(tr))));
std::cout << "The edges of the Euclidean mimimum spanning tree:" << std::endl;

View File

@ -56,18 +56,18 @@ public:
/*! The underlying primal type. */
typedef Primal_ Primal;
/*! Construct a Dual from a given primal. */
/*! constructs a Dual from a given primal. */
Dual(const Primal& primal)
: primal_(primal) {}
/*! Returns the underlying primal. */
/*! returns the underlying primal. */
const Primal& primal() const
{ return primal_; }
};
/*!
Construct a `Dual` from a given `primal`.
constructs a `Dual` from a given `primal`.
\relates CGAL::Dual
*/
template<typename Primal>
@ -158,19 +158,15 @@ struct Dual_face_index_pmap{
}
};
template<typename P, typename Property,
bool is_edge = boost::is_same<boost::edge_property_tag,
typename boost::property_kind<Property>::type>::value>
struct Dual_property_maps : boost::property_map<P, Property> {};
template< typename P, typename Property>
struct Dual_property_maps<P, Property, false> {};
} //end of namespace internal
template <typename P, typename Property>
struct property_map<CGAL::Dual<P>, Property>
: internal::Dual_property_maps<P, Property> {};
template <typename P>
struct property_map<CGAL::Dual<P>, halfedge_index_t>
: boost::property_map<P, halfedge_index_t> {};
template <typename P>
struct property_map<CGAL::Dual<P>, edge_index_t>
: boost::property_map<P, edge_index_t> {};
template <typename P>
struct property_map<CGAL::Dual<P>, boost::vertex_index_t>
@ -190,53 +186,49 @@ struct property_map<CGAL::Dual<P>, boost::face_index_t>
namespace CGAL {
template <typename P, typename Property>
typename boost::property_map<P, Property>::type
get(Property p, Dual<P>& dual)
{
return get(p, dual.primal());
#define CGAL_GET_OVERLOADS(Property) \
\
template <typename P> \
typename boost::property_map<P, Property>::type \
get(Property p, Dual<P>& dual) \
{ \
return get(p, dual.primal()); \
} \
\
template <typename P> \
typename boost::property_map<P, Property>::const_type \
get(Property p, const Dual<P>& dual) \
{ \
return get(p, dual.primal()); \
} \
\
template <typename P, typename Key > \
typename boost::property_map_value<P, Property>::type \
get(Property p, const Dual<P>& dual, const Key& k) \
{ \
return get(p, dual.primal(), k); \
}
template <typename P, typename Property>
typename boost::property_map<P, Property>::const_type
get(Property p, const Dual<P>& dual)
{
return get(p, dual.primal());
}
CGAL_GET_OVERLOADS(boost::edge_index_t)
CGAL_GET_OVERLOADS(boost::halfedge_index_t)
CGAL_GET_OVERLOADS(boost::vertex_point_t)
template <typename P, typename Property, typename Key >
typename boost::property_map_value<P, Property>::type
get(Property p, const Dual<P>& dual, const Key& k)
{
return get(p, dual.primal(), k);
}
template<typename G, typename P, typename>
struct Property_map_value_dummy {
typedef typename boost::property_map_value<G, P>::type type;
};
#undef CGAL_GET_OVERLOADS
template <typename P, typename Key>
typename Property_map_value_dummy<Dual<P>, boost::vertex_index_t, Key>::type
typename boost::property_map_value<Dual<P>, boost::vertex_index_t>::type
get(boost::vertex_index_t, const Dual<P>& dual, const Key& k)
{
return get(typename boost::internal::Dual_vertex_index_pmap<P>(dual.primal()), k);
}
template <typename P, typename Key>
typename Property_map_value_dummy<Dual<P>, boost::face_index_t, Key>::type
typename boost::property_map_value<Dual<P>, boost::face_index_t>::type
get(boost::face_index_t, const Dual<P>& dual, const Key& k)
{
return get(typename boost::internal::Dual_face_index_pmap<P>(dual.primal()), k);
}
template <typename P, typename Property, typename Key, typename Value>
void
put(Property p, const Dual<P>& dual, const Key& k, const Value& val)
{
put(p, dual.primal(), k, val);
}
template <typename P>
typename boost::internal::Dual_vertex_index_pmap<P>
get(boost::vertex_index_t, const Dual<P>& dual)

View File

@ -21,6 +21,9 @@
#include <CGAL/boost/graph/helpers.h>
#include <CGAL/boost/graph/internal/helpers.h>
#include <CGAL/boost/graph/iterator.h>
#include <CGAL/boost/graph/named_params_helper.h>
#include <boost/container/small_vector.hpp>
namespace CGAL {
@ -753,6 +756,231 @@ add_face(const VertexRange& vr, Graph& g)
return f;
}
// TODO: add a visitor for new edge/vertex/face created
// TODO: doc (VertexRange is random access for now, making a copy to a vector as an noticeable impact on the runtime)
// TODO: handle and return false in case of non valid input?
// An interesting property of this function is that in case the mesh contains non-manifold boundary vertices,
// the connected components of faces incident to such a vertex will not be linked together around the
// vertex (boundary edges are connected by turning around the vertex in the interior of the mesh).
// This produce a deterministic behavior for non-manifold vertices.
template <class PolygonMesh, class RangeofVertexRange>
void add_faces(const RangeofVertexRange& faces_to_add, PolygonMesh& pm)
{
typedef typename boost::graph_traits<PolygonMesh> GT;
typedef typename GT::halfedge_descriptor halfedge_descriptor;
typedef typename GT::edge_descriptor edge_descriptor;
typedef typename GT::vertex_descriptor vertex_descriptor;
typedef typename GT::face_descriptor face_descriptor;
typedef typename RangeofVertexRange::const_iterator VTR_const_it;
typedef typename std::iterator_traits<VTR_const_it>::value_type Vertex_range;
typedef boost::container::small_vector<halfedge_descriptor,8> Halfedges;
typedef typename CGAL::GetInitializedVertexIndexMap<PolygonMesh>::type Vid_map;
Vid_map vid = CGAL::get_initialized_vertex_index_map(pm);
// TODO: add also this lambda as an Euler function?
auto add_new_edge = [&pm](vertex_descriptor v1, vertex_descriptor v2)
{
halfedge_descriptor v1v2 = halfedge(add_edge(pm), pm), v2v1=opposite(v1v2, pm);
if (halfedge(v1,pm)==GT::null_halfedge()) set_halfedge(v1, v2v1, pm);
if (halfedge(v2,pm)==GT::null_halfedge()) set_halfedge(v2, v1v2, pm);
set_target(v1v2, v2, pm);
set_target(v2v1, v1, pm);
set_next(v1v2,v2v1, pm);
set_next(v2v1,v1v2, pm);
return v1v2;
};
// used to collect existing border halfedges that will no longer be on the border.
// Some update is needed in case of non-manifold vertex at the source/target of those
// edges are present.
std::vector<halfedge_descriptor> former_border_hedges;
std::vector<Halfedges> outgoing_hedges(num_vertices(pm));
for (const Vertex_range& vr : faces_to_add)
{
std::size_t nbh=vr.size();
for (std::size_t i=0; i<nbh; ++i)
{
vertex_descriptor v1=vr[i], v2=vr[(i+1)%nbh];
std::pair<edge_descriptor, bool> edge_and_bool = edge(v1, v2, pm);
if (v2<v1){
// needed in case an existing border edge won't be found
// because the outgoing edge from the smallest vertex is on the patch boundary
if (edge_and_bool.second && is_border(halfedge(edge_and_bool.first, pm), pm))
{
outgoing_hedges[get(vid,v2)].push_back(opposite(halfedge(edge_and_bool.first, pm), pm));
former_border_hedges.push_back(halfedge(edge_and_bool.first, pm));
}
continue;
}
if (edge_and_bool.second)
{
halfedge_descriptor h = halfedge(edge_and_bool.first, pm);
outgoing_hedges[get(vid,v1)].push_back(h);
if (is_border(h, pm))
former_border_hedges.push_back(h);
}
else
outgoing_hedges[get(vid,v1)].push_back(add_new_edge(v1,v2));
CGAL_assertion( source(outgoing_hedges[get(vid,v1)].back(), pm)==v1 );
CGAL_assertion( target(outgoing_hedges[get(vid,v1)].back(), pm)==v2 );
}
}
// disconnect hand-fans (umbrellas being not affected) at non-manifold vertices
// in case the location on the boundary of the mesh where they are attached is closed.
// Note that we link the boundary of the hand fans together, making them
// independant boundary cycles (even if the non-manifold vertex is not duplicated)
if ( !former_border_hedges.empty() )
{
std::sort(former_border_hedges.begin(), former_border_hedges.end()); // TODO: is it better to use a dynamic pmap?
for (halfedge_descriptor h : former_border_hedges)
{
// update link around target vertex
halfedge_descriptor nh = next(h, pm);
if ( !std::binary_search(former_border_hedges.begin(), former_border_hedges.end(), nh) )
{
do
{
// look for a new prev for h
halfedge_descriptor candidate = opposite(next(opposite(nh, pm), pm), pm);
while (!is_border(candidate, pm))
candidate = opposite(next(candidate, pm), pm);
halfedge_descriptor for_next_iteration = next(candidate, pm);
set_next(candidate, nh, pm);
nh = for_next_iteration;
if (candidate==h) break; // stop condition for a vertex that will stay on the boundary after the operation
if ( std::binary_search(former_border_hedges.begin(), former_border_hedges.end(), nh) )
{
// linking halfedges that will no longer be on the boundary
set_next(h, nh, pm);
break;
}
}
while(true);
}
// update link around source vertex
halfedge_descriptor ph = prev(h, pm);
if ( !std::binary_search(former_border_hedges.begin(), former_border_hedges.end(), ph) )
{
do
{
// look for a new next for h
halfedge_descriptor candidate = opposite(prev(opposite(ph, pm), pm), pm);
while (!is_border(candidate, pm))
candidate = opposite(prev(candidate, pm), pm);
halfedge_descriptor for_next_iteration = prev(candidate, pm);
set_next(ph, candidate, pm);
ph = for_next_iteration;
if (candidate==h) break;; // stop condition for a vertex that will stay on the boundary after the operation
if( std::binary_search(former_border_hedges.begin(), former_border_hedges.end(), ph) )
{
// linking halfedges that will no longer be on the boundary
set_next(ph, h, pm);
break;
}
}
while(true);
}
}
}
for (Halfedges& hedges: outgoing_hedges)
{
if (!hedges.empty())
std::sort(hedges.begin(), hedges.end(), [&pm](halfedge_descriptor h1, halfedge_descriptor h2)
{
return target(h1, pm) < target(h2,pm);
});
}
std::vector<halfedge_descriptor> new_border_halfedges;
auto get_hedge = [&pm, &add_new_edge, &new_border_halfedges, &outgoing_hedges,&vid](vertex_descriptor v1, vertex_descriptor v2)
{
bool return_opposite = v2 < v1;
if (return_opposite) std::swap(v1,v2);
const Halfedges& v1_outgoing_hedges = outgoing_hedges[get(vid,v1)];
typename Halfedges::const_iterator it_find =
std::lower_bound(v1_outgoing_hedges.begin(),
v1_outgoing_hedges.end(),
v2, [&pm](halfedge_descriptor h, vertex_descriptor v){return target(h,pm) < v;});
if (it_find!=v1_outgoing_hedges.end() && target(*it_find, pm)==v2)
{
return return_opposite ? opposite(*it_find, pm) : *it_find;
}
// fall onto a border edge
halfedge_descriptor v1v2=add_new_edge(v1,v2);
if (return_opposite)
{
new_border_halfedges.push_back(v1v2);
return opposite(v1v2, pm);
}
new_border_halfedges.push_back(opposite(v1v2, pm));
return v1v2;
};
// link interior halfedges
for (const Vertex_range& vr : faces_to_add)
{
std::size_t nbh=vr.size();
face_descriptor f = add_face(pm);
halfedge_descriptor first = get_hedge(vr[nbh-1],vr[0]), prev=first;
set_halfedge(f, first, pm);
set_face(first, f, pm);
for(std::size_t i=0; i<nbh-1; ++i)
{
halfedge_descriptor curr = get_hedge(vr[i], vr[i+1]);
set_face(curr, f, pm);
set_next(prev, curr, pm);
prev=curr;
}
set_next(prev, first, pm);
}
// link border halfedges by turning around the vertex in the interior of the mesh
for (const Halfedges& hedges : outgoing_hedges)
{
for (halfedge_descriptor h : hedges)
{
halfedge_descriptor hopp = opposite(h, pm);
if (is_border(h, pm) && next(h, pm)==hopp)
new_border_halfedges.push_back(h);
if (is_border(hopp, pm) && next(hopp, pm)==h)
new_border_halfedges.push_back(hopp);
}
}
for (halfedge_descriptor h : new_border_halfedges)
{
CGAL_assertion(is_border(h, pm));
halfedge_descriptor hopp = opposite(h, pm);
// look around the target
if (next(h, pm)==hopp)
{
halfedge_descriptor candidate = hopp;
while(!is_border(candidate, pm))
{
candidate = opposite(prev(candidate, pm), pm);
}
set_next(h, candidate, pm);
}
//look around the source
if (prev(h, pm)==hopp)
{
halfedge_descriptor candidate = hopp;
while(!is_border(candidate, pm))
{
candidate = opposite(next(candidate, pm), pm);
}
set_next(candidate, h, pm);
}
}
}
/**
* removes the incident face of `h` and changes all halfedges incident to the face into border halfedges. See `remove_face(g,h)` for a more generalized variant.

View File

@ -113,22 +113,44 @@ struct Face_filtered_graph
* \tparam FacePatchIndexRange a model of `ConstRange` with `boost::property_traits<FacePatchIndexMap>::%value_type` as value type.
* \tparam NamedParameters a sequence of named parameters
*
* \param graph the underlying graph.
* \param face_patch_index_map the property_map that assigns a patch index to each face, with
`face_descriptor` as key type and `boost::graph_traits<Graph>::%faces_size_type` as value type.
* \param selected_face_patch_indices a range of the face patch indices to select.
* \param np optional sequence of named parameters among the ones listed below
* \param graph the underlying graph
* \param face_patch_index_map the property_map that assigns a patch index to each face
* \param selected_face_patch_indices a range of the face patch indices to select
* \param np an optional sequence of \ref bgl_namedparameters "Named Parameters" among the ones listed below
*
* \cgalNamedParamsBegin
* \cgalParamBegin{face_index_map}
* a property map containing for each face of `graph` a unique index between `0` and `num_faces(graph)-1`
* \cgalParamEnd
* \cgalParamBegin{vertex_index_map}
* a property map containing for each vertex of `graph` a unique index between `0` and `num_vertices(graph)-1`
* \cgalParamEnd
* \cgalParamBegin{halfedge_index_map}
* a property map containing for each halfedge of `graph` a unique index between `0` and `num_halfedges(graph)-1`
* \cgalParamEnd
* \cgalParamNBegin{vertex_index_map}
* \cgalParamDescription{a property map associating to each vertex of `graph` a unique index between `0` and `num_vertices(graph) - 1`}
* \cgalParamType{a class model of `ReadablePropertyMap` with `boost::graph_traits<Graph>::%vertex_descriptor`
* as key type and `std::size_t` as value type}
* \cgalParamDefault{an automatically indexed internal map}
* \cgalParamExtra{If this parameter is not passed, internal machinery will create and initialize
* a face index property map, either using the internal property map if it exists
* or using an external map. The latter might result in - slightly - worsened performance
* in case of non-constant complexity for index access.}
* \cgalParamNEnd
*
* \cgalParamNBegin{halfedge_index_map}
* \cgalParamDescription{a property map associating to each halfedge of `graph` a unique index between `0` and `num_halfedges(graph) - 1`}
* \cgalParamType{a class model of `ReadablePropertyMap` with `boost::graph_traits<Graph>::%halfedge_descriptor`
* as key type and `std::size_t` as value type}
* \cgalParamDefault{an automatically indexed internal map}
* \cgalParamExtra{If this parameter is not passed, internal machinery will create and initialize
* a face index property map, either using the internal property map if it exists
* or using an external map. The latter might result in - slightly - worsened performance
* in case of non-constant complexity for index access.}
* \cgalParamNEnd
*
* \cgalParamNBegin{face_index_map}
* \cgalParamDescription{a property map associating to each face of `graph` a unique index between `0` and `num_faces(graph) - 1`}
* \cgalParamType{a class model of `ReadablePropertyMap` with `boost::graph_traits<Graph>::%face_descriptor`
* as key type and `std::size_t` as value type}
* \cgalParamDefault{an automatically indexed internal map}
* \cgalParamExtra{If this parameter is not passed, internal machinery will create and initialize
* a face index property map, either using the internal property map if it exists
* or using an external map. The latter might result in - slightly - worsened performance
* in case of non-constant complexity for index access.}
* \cgalParamNEnd
* \cgalNamedParamsEnd
*/
template <typename FacePatchIndexMap, class FacePatchIndexRange, class CGAL_BGL_NP_TEMPLATE_PARAMETERS>
@ -172,23 +194,45 @@ struct Face_filtered_graph
`face_descriptor` as key type and
`graph_traits<Graph>::%faces_size_type` as value type.
* \tparam NamedParameters a sequence of named parameters
*
* \param graph the underlying graph.
* \param face_patch_index_map the property_map that assigns a patch index to each face, with
`face_descriptor` as key type and
`graph_traits<Graph>::%faces_size_type` as value type.
* \param selected_face_patch_index the index of the face patch selected.
* \param np optional sequence of named parameters among the ones listed below
* \param face_patch_index_map the property_map that assigns a patch index to each face
* \param selected_face_patch_index the index of the face patch selected
* \param np an optional sequence of \ref bgl_namedparameters "Named Parameters" among the ones listed below
*
* \cgalNamedParamsBegin
* \cgalParamBegin{face_index_map}
* a property map containing for each face of `graph` a unique index between `0` and `num_faces(graph)-1`
* \cgalParamEnd
* \cgalParamBegin{vertex_index_map}
* a property map containing for each vertex of `graph` a unique index between `0` and `num_vertices(graph)-1`
* \cgalParamEnd
* \cgalParamBegin{halfedge_index_map}
* a property map containing for each halfedge of `graph` a unique index between `0` and `num_halfedges(graph)-1`
* \cgalParamEnd
* \cgalParamNBegin{vertex_index_map}
* \cgalParamDescription{a property map associating to each vertex of `graph` a unique index between `0` and `num_vertices(graph) - 1`}
* \cgalParamType{a class model of `ReadablePropertyMap` with `boost::graph_traits<Graph>::%vertex_descriptor`
* as key type and `std::size_t` as value type}
* \cgalParamDefault{an automatically indexed internal map}
* \cgalParamExtra{If this parameter is not passed, internal machinery will create and initialize
* a face index property map, either using the internal property map if it exists
* or using an external map. The latter might result in - slightly - worsened performance
* in case of non-constant complexity for index access.}
* \cgalParamNEnd
*
* \cgalParamNBegin{halfedge_index_map}
* \cgalParamDescription{a property map associating to each halfedge of `graph` a unique index between `0` and `num_halfedges(graph) - 1`}
* \cgalParamType{a class model of `ReadablePropertyMap` with `boost::graph_traits<Graph>::%halfedge_descriptor`
* as key type and `std::size_t` as value type}
* \cgalParamDefault{an automatically indexed internal map}
* \cgalParamExtra{If this parameter is not passed, internal machinery will create and initialize
* a face index property map, either using the internal property map if it exists
* or using an external map. The latter might result in - slightly - worsened performance
* in case of non-constant complexity for index access.}
* \cgalParamNEnd
*
* \cgalParamNBegin{face_index_map}
* \cgalParamDescription{a property map associating to each face of `graph` a unique index between `0` and `num_faces(graph) - 1`}
* \cgalParamType{a class model of `ReadablePropertyMap` with `boost::graph_traits<Graph>::%face_descriptor`
* as key type and `std::size_t` as value type}
* \cgalParamDefault{an automatically indexed internal map}
* \cgalParamExtra{If this parameter is not passed, internal machinery will create and initialize
* a face index property map, either using the internal property map if it exists
* or using an external map. The latter might result in - slightly - worsened performance
* in case of non-constant complexity for index access.}
* \cgalParamNEnd
* \cgalNamedParamsEnd
*/
template <typename FacePatchIndexMap, class CGAL_BGL_NP_TEMPLATE_PARAMETERS>
@ -221,20 +265,44 @@ struct Face_filtered_graph
*
* \tparam FaceRange a model of `ConstRange` with `face_descriptor` as value type.
* \tparam NamedParameters a sequence of named parameters
* \param graph the graph containing the wanted patch.
* \param selected_faces the set of selected faces.
* \param np optional sequence of named parameters among the ones listed below
*
* \param graph the graph containing the wanted patch
* \param selected_faces the set of selected faces
* \param np an optional sequence of \ref bgl_namedparameters "Named Parameters" among the ones listed below
*
* \cgalNamedParamsBegin
* \cgalParamBegin{face_index_map}
* a property map containing an index for each face initialized from 0 to `num_vertices(graph)`
* \cgalParamEnd
* \cgalParamBegin{vertex_index_map}
* a property map containing an index for each vertex initialized 0 to `num_vertices(graph)`
* \cgalParamEnd
* \cgalParamBegin{halfedge_index_map}
* a property map containing an index for each halfedge initialized 0 to `num_halfedges(graph)`
* \cgalParamEnd
* \cgalParamNBegin{vertex_index_map}
* \cgalParamDescription{a property map associating to each vertex of `graph` a unique index between `0` and `num_vertices(graph) - 1`}
* \cgalParamType{a class model of `ReadablePropertyMap` with `boost::graph_traits<Graph>::%vertex_descriptor`
* as key type and `std::size_t` as value type}
* \cgalParamDefault{an automatically indexed internal map}
* \cgalParamExtra{If this parameter is not passed, internal machinery will create and initialize
* a face index property map, either using the internal property map if it exists
* or using an external map. The latter might result in - slightly - worsened performance
* in case of non-constant complexity for index access.}
* \cgalParamNEnd
*
* \cgalParamNBegin{halfedge_index_map}
* \cgalParamDescription{a property map associating to each halfedge of `graph` a unique index between `0` and `num_halfedges(graph) - 1`}
* \cgalParamType{a class model of `ReadablePropertyMap` with `boost::graph_traits<Graph>::%halfedge_descriptor`
* as key type and `std::size_t` as value type}
* \cgalParamDefault{an automatically indexed internal map}
* \cgalParamExtra{If this parameter is not passed, internal machinery will create and initialize
* a face index property map, either using the internal property map if it exists
* or using an external map. The latter might result in - slightly - worsened performance
* in case of non-constant complexity for index access.}
* \cgalParamNEnd
*
* \cgalParamNBegin{face_index_map}
* \cgalParamDescription{a property map associating to each face of `graph` a unique index between `0` and `num_faces(graph) - 1`}
* \cgalParamType{a class model of `ReadablePropertyMap` with `boost::graph_traits<Graph>::%face_descriptor`
* as key type and `std::size_t` as value type}
* \cgalParamDefault{an automatically indexed internal map}
* \cgalParamExtra{If this parameter is not passed, internal machinery will create and initialize
* a face index property map, either using the internal property map if it exists
* or using an external map. The latter might result in - slightly - worsened performance
* in case of non-constant complexity for index access.}
* \cgalParamNEnd
* \cgalNamedParamsEnd
*/
template <typename FaceRange, class CGAL_BGL_NP_TEMPLATE_PARAMETERS>
@ -1048,6 +1116,36 @@ get(PropertyTag ptag, Face_filtered_graph<Graph, FIMap, VIMap, HIMap>& w)
return get(ptag, w.graph());
}
#define CGAL_FFG_DYNAMIC_PMAP_SPEC(TAG) \
template <class Graph, \
typename FIMap, \
typename VIMap, \
typename HIMap, \
class T> \
typename boost::property_map<Graph, TAG<T> >::const_type \
get(TAG<T> ptag, const Face_filtered_graph<Graph, FIMap, VIMap, HIMap>& w) \
{ \
return get(ptag, w.graph()); \
} \
\
template <class Graph, \
typename FIMap, \
typename VIMap, \
typename HIMap, \
class T> \
typename boost::property_map<Graph, TAG<T> >::type \
get(TAG<T> ptag, Face_filtered_graph<Graph, FIMap, VIMap, HIMap>& w) \
{ \
return get(ptag, w.graph()); \
}
CGAL_FFG_DYNAMIC_PMAP_SPEC(dynamic_vertex_property_t)
CGAL_FFG_DYNAMIC_PMAP_SPEC(dynamic_halfedge_property_t)
CGAL_FFG_DYNAMIC_PMAP_SPEC(dynamic_edge_property_t)
CGAL_FFG_DYNAMIC_PMAP_SPEC(dynamic_face_property_t)
#undef CGAL_FFG_DYNAMIC_PMAP_SPEC
//specializations for indices
template <class Graph,
typename FIMap,

View File

@ -129,35 +129,56 @@ void partition_dual_graph(const TriangleMesh& tm, int nparts,
/// \ingroup PkgBGLPartition
///
/// Computes a partition of the input triangular mesh into `nparts` parts,
/// computes a partition of the input triangular mesh into `nparts` parts,
/// based on the mesh's dual graph. The resulting partition is stored in the vertex and/or face
/// property maps that are passed as parameters using \ref bgl_namedparameters "Named Parameters".
///
/// \param tm a triangle mesh
/// \param nparts the number of parts in the final partition
/// \param np optional \ref bgl_namedparameters "Named Parameters" described below
/// \param np an optional sequence of \ref bgl_namedparameters "Named Parameters" among the ones listed below
///
/// \tparam TriangleMesh is a model of the `FaceListGraph` concept.
/// \tparam TriangleMesh is a model of the `FaceListGraph` concept
/// \tparam NamedParameters a sequence of \ref bgl_namedparameters "Named Parameters"
///
/// \cgalNamedParamsBegin
/// \cgalParamBegin{vertex_index_map}
/// is a property map containing for each vertex of `tm` a unique index between `0` and `num_vertices(tm)-1`.
/// \cgalParamEnd
/// \cgalParamBegin{METIS_options}
/// is a parameter used in to pass options to the METIS mesh
/// partitioner. The many options of METIS are not described here. Instead, users
/// should refer to the <a href="http://glaros.dtc.umn.edu/gkhome/fetch/sw/metis/manual.pdf">documentation</a>
/// of METIS directly.
/// \cgalParamEnd
/// \cgalParamBegin{vertex_partition_id_map}
/// is a property map that contains (after the function has been run)
/// the ID of the subpart for each vertex of `tm`.
/// \cgalParamEnd
/// \cgalParamBegin{face_partition_id_map}
/// is a property map that contains (after the function has been run)
/// the ID of the subpart for each face of `tm`.
/// \cgalParamEnd
/// \cgalParamNBegin{vertex_index_map}
/// \cgalParamDescription{a property map associating to each vertex of `tm` a unique index between `0` and `num_vertices(tm) - 1`}
/// \cgalParamType{a class model of `ReadablePropertyMap` with `boost::graph_traits<TriangleMesh>::%vertex_descriptor`
/// as key type and `std::size_t` as value type}
/// \cgalParamDefault{an automatically indexed internal map}
/// \cgalParamExtra{If this parameter is not passed, internal machinery will create and initialize
/// a face index property map, either using the internal property map if it exists
/// or using an external map. The latter might result in - slightly - worsened performance
/// in case of non-constant complexity for index access.}
/// \cgalParamNEnd
///
/// \cgalParamNBegin{METIS_options}
/// \cgalParamDescription{a parameter used in to pass options to the METIS mesh partitioner}
/// \cgalParamType{an array of size `METIS_NOPTIONS` with value type `idx_t` (an integer type defined by METIS)}
/// \cgalParamDefault{an array of size `METIS_NOPTIONS` with value type `idx_t`,
/// initialized using the function `METIS_SetDefaultOptions()`}
/// \cgalParamExtra{The many options of METIS are not described here. Instead, users should refer
/// to the <a href="http://glaros.dtc.umn.edu/gkhome/fetch/sw/metis/manual.pdf">documentation</a>
/// of METIS directly.}
/// \cgalParamNEnd
///
/// \cgalParamNBegin{vertex_partition_id_map}
/// \cgalParamDescription{a property map that contains (after the function has been run)
/// the ID of the subpart for each vertex of `tm`}
/// \cgalParamType{a class model of `ReadWritePropertyMap` with
/// `boost::graph_traits<TriangleMesh>::%vertex_descriptor` as key type and
/// `int` as value type}
/// \cgalParamDefault{unused}
/// \cgalParamNEnd
///
/// \cgalParamNBegin{face_partition_id_map}
/// \cgalParamDescription{a property map that contains (after the function has been run)
/// the ID of the subpart for each face of `tm`}
/// \cgalParamType{a class model of `ReadWritePropertyMap` with
/// `boost::graph_traits<TriangleMesh>::%face_descriptor` as key type and
/// `int` as value type}
/// \cgalParamDefault{unused}
/// \cgalParamNEnd
/// \cgalNamedParamsEnd
///
/// \pre `tm` is a pure triangular surface mesh: there are no edges

View File

@ -161,35 +161,56 @@ void partition_graph(const TriangleMesh& tm, int nparts,
/// \ingroup PkgBGLPartition
///
/// Computes a partition of the input triangular mesh into `nparts` parts, based on the
/// computes a partition of the input triangular mesh into `nparts` parts, based on the
/// mesh's nodal graph. The resulting partition is stored in the vertex and/or face
/// property maps that are passed as parameters using \ref bgl_namedparameters "Named Parameters".
///
/// \param tm a triangle mesh
/// \param nparts the number of parts in the final partition
/// \param np optional \ref bgl_namedparameters "Named Parameters" described below
/// \param np an optional sequence of \ref bgl_namedparameters "Named Parameters" among the ones listed below
///
/// \tparam TriangleMesh is a model of the `FaceListGraph` concept.
/// \tparam NamedParameters a sequence of \ref bgl_namedparameters "Named Parameters"
///
/// \cgalNamedParamsBegin
/// \cgalParamBegin{vertex_index_map}
/// is a property map containing for each vertex of `tm` a unique index between `0` and `num_vertices(tm)-1`.
/// \cgalParamEnd
/// \cgalParamBegin{METIS_options}
/// is a parameter used in to pass options to the METIS mesh
/// partitioner. The many options of METIS are not described here. Instead, users
/// should refer to the <a href="http://glaros.dtc.umn.edu/gkhome/fetch/sw/metis/manual.pdf">documentation</a>
/// of METIS directly.
/// \cgalParamEnd
/// \cgalParamBegin{vertex_partition_id_map}
/// is a property map that contains (after the function has been run)
/// the ID of the subpart for each vertex of `tm`.
/// \cgalParamEnd
/// \cgalParamBegin{face_partition_id_map}
/// is a property map that contains (after the function has been run)
/// the ID of the subpart for each face of `tm`.
/// \cgalParamEnd
/// \cgalParamNBegin{vertex_index_map}
/// \cgalParamDescription{a property map associating to each vertex of `tm` a unique index between `0` and `num_vertices(tm) - 1`}
/// \cgalParamType{a class model of `ReadablePropertyMap` with `boost::graph_traits<TriangleMesh>::%vertex_descriptor`
/// as key type and `std::size_t` as value type}
/// \cgalParamDefault{an automatically indexed internal map}
/// \cgalParamExtra{If this parameter is not passed, internal machinery will create and initialize
/// a face index property map, either using the internal property map if it exists
/// or using an external map. The latter might result in - slightly - worsened performance
/// in case of non-constant complexity for index access.}
/// \cgalParamNEnd
///
/// \cgalParamNBegin{METIS_options}
/// \cgalParamDescription{a parameter used in to pass options to the METIS mesh partitioner}
/// \cgalParamType{an array of size `METIS_NOPTIONS` with value type `idx_t` (an integer type defined by METIS)}
/// \cgalParamDefault{an array of size `METIS_NOPTIONS` with value type `idx_t`,
/// initialized using the function `METIS_SetDefaultOptions()`}
/// \cgalParamExtra{The many options of METIS are not described here. Instead, users should refer
/// to the <a href="http://glaros.dtc.umn.edu/gkhome/fetch/sw/metis/manual.pdf">documentation</a>
/// of METIS directly.}
/// \cgalParamNEnd
///
/// \cgalParamNBegin{vertex_partition_id_map}
/// \cgalParamDescription{a property map that contains (after the function has been run)
/// the ID of the subpart for each vertex of `tm`}
/// \cgalParamType{a class model of `ReadWritePropertyMap` with
/// `boost::graph_traits<TriangleMesh>::%vertex_descriptor` as key type and
/// `int` as value type}
/// \cgalParamDefault{unused}
/// \cgalParamNEnd
///
/// \cgalParamNBegin{face_partition_id_map}
/// \cgalParamDescription{a property map that contains (after the function has been run)
/// the ID of the subpart for each face of `tm`}
/// \cgalParamType{a class model of `ReadWritePropertyMap` with
/// `boost::graph_traits<TriangleMesh>::%face_descriptor` as key type and
/// `int` as value type}
/// \cgalParamDefault{unused}
/// \cgalParamNEnd
/// \cgalNamedParamsEnd
///
/// \pre `tm` is a pure triangular surface mesh: there are no edges

View File

@ -194,19 +194,6 @@ get_parameter(const Named_function_parameters<T, Tag, Base>& np, Query_tag tag)
return internal_np::get_parameter_impl(static_cast<const internal_np::Named_params_impl<T, Tag, Base>&>(np), tag);
}
// single parameter so that we can avoid a default construction
template <typename D>
D choose_parameter(const internal_np::Param_not_found&)
{
return D();
}
template <typename D, typename T>
const T& choose_parameter(const T& t)
{
return t;
}
// Two parameters, non-trivial default value
template <typename D>
D choose_parameter(const internal_np::Param_not_found&, const D& d)
@ -220,6 +207,19 @@ const T& choose_parameter(const T& t, const D&)
return t;
}
// single parameter so that we can avoid a default construction
template <typename D>
D choose_parameter(const internal_np::Param_not_found&)
{
return D();
}
template <typename D, typename T>
const T& choose_parameter(const T& t)
{
return t;
}
bool inline is_default_parameter(const internal_np::Param_not_found&)
{
return true;

View File

@ -168,7 +168,7 @@ private:
mutable vertices_size_type number_of_vertices;
public:
/// Returns the underlying mesh.
/// returns the underlying mesh.
const TM& mesh() const
{
return tm;
@ -543,31 +543,31 @@ public:
/// \name Seam query functions
/// @{
/// Returns `true` if the vertex is on the seam.
/// returns `true` if the vertex is on the seam.
bool has_on_seam(TM_vertex_descriptor vd) const
{
return get(svm, vd);
}
/// Returns `true` if the edge is on the seam.
/// returns `true` if the edge is on the seam.
bool has_on_seam(TM_edge_descriptor ed) const
{
return get(sem, ed);
}
/// Returns `true` if the halfedge is on the seam.
/// returns `true` if the halfedge is on the seam.
bool has_on_seam(TM_halfedge_descriptor tmhd) const
{
return get(sem, CGAL::edge(tmhd, tm));
}
/// Returns `true` if the halfedge is on the seam.
/// returns `true` if the halfedge is on the seam.
bool has_on_seam(const halfedge_descriptor& hd) const
{
return has_on_seam(CGAL::edge(hd, tm));
}
/// Return the number of seam edges in the seam mesh.
/// returns the number of seam edges in the seam mesh.
edges_size_type number_of_seam_edges() const
{
return number_of_seams;
@ -601,7 +601,7 @@ public:
}
/// @endcond
/// Returns the iterator range of the vertices of the mesh.
/// returns the iterator range of the vertices of the mesh.
Iterator_range<vertex_iterator> vertices() const
{
Iterator_range<TM_halfedge_iterator> ir = CGAL::halfedges(tm);
@ -627,7 +627,7 @@ public:
}
/// @endcond
/// Returns the iterator range of the halfedges of the mesh.
/// returns the iterator range of the halfedges of the mesh.
Iterator_range<halfedge_iterator> halfedges() const
{
Iterator_range<TM_halfedge_iterator> ir = CGAL::halfedges(tm);
@ -652,7 +652,7 @@ public:
}
/// @endcond
/// Returns the iterator range of the edges of the mesh.
/// returns the iterator range of the edges of the mesh.
Iterator_range<edge_iterator> edges() const
{
Iterator_range<TM_halfedge_iterator> ir = CGAL::halfedges(tm);
@ -675,7 +675,7 @@ public:
}
/// @endcond
/// Returns the iterator range of the faces of the mesh.
/// returns the iterator range of the faces of the mesh.
Iterator_range<face_iterator> faces() const
{
return CGAL::faces(tm);
@ -686,7 +686,7 @@ public:
/// \name Memory Management
/// @{
/// Returns the number of vertices in the seam mesh.
/// returns the number of vertices in the seam mesh.
vertices_size_type num_vertices() const
{
if(number_of_vertices == static_cast<vertices_size_type>(-1)) {
@ -696,19 +696,19 @@ public:
return number_of_vertices;
}
/// Returns the number of halfedges in the seam mesh.
/// returns the number of halfedges in the seam mesh.
halfedges_size_type num_halfedges() const
{
return CGAL::num_halfedges(tm) + 2 * number_of_seams;
}
/// Returns the number of edges in the seam mesh.
/// returns the number of edges in the seam mesh.
halfedges_size_type num_edges() const
{
return CGAL::num_edges(tm) + number_of_seams;
}
/// Returns the number of faces in the seam mesh.
/// returns the number of faces in the seam mesh.
faces_size_type num_faces() const
{
return CGAL::num_faces(tm);
@ -719,7 +719,7 @@ public:
/// \name Degree Functions
/// @{
/// Returns the number of incident halfedges of vertex `v`.
/// returns the number of incident halfedges of vertex `v`.
degree_size_type degree(vertex_descriptor v) const
{
degree_size_type count(0);
@ -743,13 +743,13 @@ public:
#ifndef DOXYGEN_RUNNING
///@{
/// Returns the edge that contains halfedge `h` as one of its two halfedges.
/// returns the edge that contains halfedge `h` as one of its two halfedges.
edge_descriptor edge(halfedge_descriptor h) const
{
return edge_descriptor(h,this);
}
/// Returns the halfedge corresponding to the edge `e`.
/// returns the halfedge corresponding to the edge `e`.
halfedge_descriptor halfedge(edge_descriptor e) const
{
return e.hd;
@ -758,7 +758,7 @@ public:
///@{
/// Returns an incoming halfedge of vertex `v`.
/// returns an incoming halfedge of vertex `v`.
/// If `v` is a seam vertex, this will be the halfedge whose target is `v` and
/// whose opposite is a virtual border halfedge.
/// Otherwise, the rules of the underlying mesh are followed.
@ -769,7 +769,7 @@ public:
return halfedge_descriptor(h, false /*not on seam*/);
}
/// Finds a halfedge between two vertices. Returns a default constructed
/// finds a halfedge between two vertices. Returns a default constructed
/// `halfedge_descriptor`, if `source` and `target` are not connected.
std::pair<halfedge_descriptor, bool> halfedge(vertex_descriptor u,
vertex_descriptor v) const
@ -800,7 +800,7 @@ public:
return std::make_pair(halfedge_descriptor(), false/*invalid*/);
}
/// Finds an edge between two vertices. Returns a default constructed
/// finds an edge between two vertices. Returns a default constructed
/// `edge`, if `source` and `target` are not connected.
std::pair<edge_descriptor, bool> edge(vertex_descriptor u, vertex_descriptor v) const
{
@ -815,7 +815,7 @@ public:
return halfedge_descriptor(hd, false/*not on seam*/);
}
/// Returns the face incident to halfedge `h`.
/// returns the face incident to halfedge `h`.
face_descriptor face(halfedge_descriptor h) const
{
if(h.seam)
@ -825,7 +825,7 @@ public:
}
public:
/// Returns the next halfedge within the incident face.
/// returns the next halfedge within the incident face.
halfedge_descriptor next(const halfedge_descriptor& hd) const
{
if((!hd.seam) && (!is_border(hd.tmhd, tm)))
@ -840,7 +840,7 @@ public:
!is_border(CGAL::opposite(*hatc, tm), tm));
}
/// Returns the previous halfedge within the incident face.
/// returns the previous halfedge within the incident face.
halfedge_descriptor prev(const halfedge_descriptor& hd) const
{
if((!hd.seam) && (!is_border(hd.tmhd, tm)))
@ -855,7 +855,7 @@ public:
!is_border(CGAL::opposite(*hatc, tm), tm));
}
/// Returns the opposite halfedge of `hd`.
/// returns the opposite halfedge of `hd`.
halfedge_descriptor opposite(const halfedge_descriptor& hd) const
{
if(!hd.seam)
@ -864,7 +864,7 @@ public:
return halfedge_descriptor(CGAL::opposite(hd.tmhd, tm), false /*not on seam*/);
}
/// Returns the vertex the halfedge `h` emanates from.
/// returns the vertex the halfedge `h` emanates from.
vertex_descriptor target(halfedge_descriptor hd) const
{
TM_halfedge_descriptor tmhd(hd);
@ -884,7 +884,7 @@ public:
return vertex_descriptor(halfedge_descriptor(tmhd));
}
/// Returns the vertex the halfedge `h` emanates from.
/// returns the vertex the halfedge `h` emanates from.
vertex_descriptor source(const halfedge_descriptor& hd) const
{
return target(opposite(hd));
@ -922,7 +922,7 @@ public:
/// \name Seam selection
/// @{
/// Mark the edge of the underlying mesh that has extremities the vertices
/// marks the edge of the underlying mesh that has extremities the vertices
/// `tm_vd_s` and `tm_vd_s` as a seam edge.
///
/// \return whether the edge was successfully marked or not.
@ -963,7 +963,7 @@ public:
return true;
}
/// Create new seams.
/// creates new seams.
///
/// The edges to be marked as seams are described by the range [first, last) of
/// vertices of the underlying mesh. Each edge to be marked is described
@ -998,7 +998,7 @@ public:
return tmhd;
}
/// Create new seams.
/// creates new seams.
///
/// A seam edge is described by a pair of integers. The integer index
/// of a vertex of the underlying mesh is given by its position
@ -1024,7 +1024,7 @@ public:
return add_seams(seam_vertices.begin(), seam_vertices.end());
}
/// Create new seams.
/// creates new seams.
///
/// A seam edge is described by a pair of integers. The integer
/// index of a vertex of the underlying mesh is defined as its position when
@ -1041,7 +1041,7 @@ public:
return add_seams(in, tm_vds);
}
/// Create new seams.
/// creates new seams.
///
/// A seam edge is described by a pair of integers. The integer index
/// of a vertex of the underlying mesh is given by its position
@ -1085,7 +1085,7 @@ public:
return add_seams(in, tm_vds);
}
/// Create new seams.
/// creates new seams.
///
/// A seam edge is described by a pair of integers. The integer
/// index of a vertex of the underlying mesh is defined as its position when
@ -1104,7 +1104,7 @@ public:
/// @}
/// Constructs a seam mesh for a triangle mesh and an edge and vertex property map
/// constructs a seam mesh for a triangle mesh and an edge and vertex property map
///
/// \param tm the underlying mesh
/// \param sem the edge property map with value `true` for seam edges

View File

@ -0,0 +1,754 @@
#ifndef CGAL_BOOST_GRAPH_ALPHA_EXPANSION_GRAPHCUT_H
// Copyright (c) 2014 GeometryFactory (France). All rights reserved.
//
// This file is part of CGAL (www.cgal.org)
//
// $URL$
// $Id$
// SPDX-License-Identifier: LGPL-3.0-or-later OR LicenseRef-Commercial
//
//
// Author(s) : Ilker O. Yaz, Simon Giraudot
#define CGAL_BOOST_GRAPH_ALPHA_EXPANSION_GRAPHCUT_H
#include <CGAL/Iterator_range.h>
#include <CGAL/assertions.h>
#include <CGAL/property_map.h>
#ifdef CGAL_SEGMENTATION_BENCH_GRAPHCUT
#include <CGAL/Timer.h>
#endif
#include <CGAL/IO/trace.h>
#include <CGAL/boost/graph/Named_function_parameters.h>
#include <CGAL/boost/graph/named_params_helper.h>
#include <boost/version.hpp>
#include <boost/graph/adjacency_list.hpp>
#include <boost/graph/compressed_sparse_row_graph.hpp>
#if BOOST_VERSION >= 104400 // at this version kolmogorov_max_flow become depricated.
# include <boost/graph/boykov_kolmogorov_max_flow.hpp>
#else
# include <boost/graph/kolmogorov_max_flow.hpp>
#endif
#include <vector>
namespace CGAL
{
/// \cond SKIP_IN_MANUAL
namespace internal
{
struct Alpha_expansion_old_API_wrapper_graph
{
typedef std::size_t vertex_descriptor;
typedef std::size_t edge_descriptor;
typedef boost::directed_tag directed_category;
typedef boost::disallow_parallel_edge_tag edge_parallel_category;
typedef boost::edge_list_graph_tag traversal_category;
typedef boost::counting_iterator<std::size_t> counting_iterator;
typedef CGAL::Iterator_range<counting_iterator> counting_range;
typedef CGAL::Identity_property_map<std::size_t> Vertex_index_map;
typedef CGAL::Pointer_property_map<std::size_t>::type Vertex_label_map;
struct Vertex_label_cost_map
{
typedef std::size_t key_type;
typedef std::vector<double> value_type;
typedef value_type reference;
typedef boost::readable_property_map_tag category;
const std::vector<std::vector<double> >* cost_matrix;
Vertex_label_cost_map (const std::vector<std::vector<double> >* cost_matrix)
: cost_matrix (cost_matrix)
{ }
friend reference get (const Vertex_label_cost_map& pmap, key_type idx)
{
std::vector<double> out;
out.reserve (pmap.cost_matrix->size());
for (std::size_t i = 0; i < pmap.cost_matrix->size(); ++ i)
out.push_back ((*pmap.cost_matrix)[i][idx]);
return out;
}
};
typedef CGAL::Pointer_property_map<double>::const_type Edge_cost_map;
const std::vector<std::pair<std::size_t, std::size_t> >& edges;
const std::vector<double>& edge_costs;
const std::vector<std::vector<double> >& cost_matrix;
std::vector<std::size_t>& labels;
Alpha_expansion_old_API_wrapper_graph (const std::vector<std::pair<std::size_t, std::size_t> >& edges,
const std::vector<double>& edge_costs,
const std::vector<std::vector<double> >& cost_matrix,
std::vector<std::size_t>& labels)
: edges (edges), edge_costs (edge_costs), cost_matrix (cost_matrix), labels (labels)
{ }
friend counting_range vertices (const Alpha_expansion_old_API_wrapper_graph& graph)
{
return CGAL::make_range (boost::counting_iterator<std::size_t>(0),
boost::counting_iterator<std::size_t>(graph.labels.size()));
}
friend std::size_t num_vertices (const Alpha_expansion_old_API_wrapper_graph& graph) { return graph.labels.size(); }
friend counting_range edges (const Alpha_expansion_old_API_wrapper_graph& graph)
{
return CGAL::make_range (boost::counting_iterator<std::size_t>(0),
boost::counting_iterator<std::size_t>(graph.edges.size()));
}
friend vertex_descriptor source (edge_descriptor ed, const Alpha_expansion_old_API_wrapper_graph& graph)
{ return graph.edges[ed].first; }
friend vertex_descriptor target (edge_descriptor ed, const Alpha_expansion_old_API_wrapper_graph& graph)
{ return graph.edges[ed].second; }
Vertex_index_map vertex_index_map() const { return Vertex_index_map(); }
Vertex_label_map vertex_label_map() { return CGAL::make_property_map(labels); }
Vertex_label_cost_map vertex_label_cost_map() const
{ return Vertex_label_cost_map(&cost_matrix); }
Edge_cost_map edge_cost_map() const { return CGAL::make_property_map(edge_costs); }
};
////////////////////////////////////////////////////////////////////////////////////////
// Comments about performance:
//
// 1) With BGL:
// * Using adjacency_list:
// ** Without pre-allocating vertex-list
// | OutEdgeList | VertexList | Performance |
// | listS | listS | 25.2 |
// | vecS | listS | 22.7 |
// | listS | vecS | 30.7 |
// | vecS | vecS | 26.1 |
//
// ** With pre-allocating vertex-list with max-node size
// (Note: exact number of vertices are not certain at the beginning)
// | OutEdgeList | VertexList | Performance |
// | listS | vecS | 25.2 |
// | vecS | vecS | 23.4 |
//
// * Didn't try adjacency_matrix since our graph is sparse
// ( Also one can check BGL book, performance section )
//
// Decision:
// * Alpha_expansion_graph_cut_boost: use adjacency_list<vecS, listS> without
// pre-allocating vertex-list.
//
// 2) With Boykov-Kolmogorov MAXFLOW software:
// (http://pub.ist.ac.at/~vnk/software/maxflow-v2.21.src.tar.gz)
// | Performance |
// | 3.1 |
// * Alpha_expansion_graph_cut_boykov_kolmogorov provides an implementation.
// MAXFLOW does not provide any option for pre-allocation (It is possible with v_3.02 though).
//
// Typical Benchmark result provided by Ilker
// | construction of vertices | construction of edges | graph cut | Total
// -----------------------------------------------------------------------------------------------------------
// boost with an adjacency list | 1.53 | 1.51 | 3.00 | 6.04
// boost with CSR | 0.11 (gather in a vector) | 0.15 (gather in a vector) | 2.67 | 2.93
// MaxFlow | 0.042 | 0.076 | 1.043 | 1.161
//
// The main issue for now with CSR is the construction of the opposite edge map that is too costly,
// since it is done by exploring all edges to find opposite
////////////////////////////////////////////////////////////////////////////////////////
} // namespace internal
/**
* @brief Implements alpha-expansion graph cut algorithm.
*
* For representing graph, it uses adjacency_list with OutEdgeList = vecS, VertexList = listS.
* Also no pre-allocation is made for vertex-list.
*/
class Alpha_expansion_boost_adjacency_list_impl
{
private:
typedef boost::adjacency_list_traits<boost::vecS, boost::listS, boost::directedS>
Adjacency_list_traits;
typedef boost::adjacency_list<boost::vecS, boost::listS, boost::directedS,
// 4 vertex properties
boost::property<boost::vertex_index_t, std::size_t,
boost::property<boost::vertex_color_t, boost::default_color_type,
boost::property<boost::vertex_distance_t, double,
boost::property<boost::vertex_predecessor_t, Adjacency_list_traits::edge_descriptor >
> > >,
// 3 edge properties
boost::property<boost::edge_capacity_t, double,
boost::property<boost::edge_residual_capacity_t, double,
boost::property<boost::edge_reverse_t, Adjacency_list_traits::edge_descriptor> >
> > Graph;
typedef boost::graph_traits<Graph> Traits;
typedef boost::color_traits<boost::default_color_type> ColorTraits;
public:
typedef Traits::vertex_descriptor Vertex_descriptor;
typedef Traits::vertex_iterator Vertex_iterator;
typedef Traits::edge_descriptor Edge_descriptor;
typedef Traits::edge_iterator Edge_iterator;
private:
Graph graph;
Vertex_descriptor cluster_source;
Vertex_descriptor cluster_sink;
public:
void clear_graph()
{
graph.clear();
cluster_source = boost::add_vertex(graph);
cluster_sink = boost::add_vertex(graph);
}
Vertex_descriptor add_vertex()
{
return boost::add_vertex(graph);
}
void add_tweight (Vertex_descriptor& v, double w1, double w2)
{
add_edge (cluster_source, v, w1, 0);
add_edge (v, cluster_sink, w2, 0);
}
void init_vertices()
{
// initialize vertex indices, it is necessary since we are using VertexList = listS
Vertex_iterator v_begin, v_end;
Traits::vertices_size_type index = 0;
for(boost::tie(v_begin, v_end) = vertices(graph); v_begin != v_end; ++v_begin) {
boost::put(boost::vertex_index, graph, *v_begin, index++);
}
}
double max_flow()
{
#if BOOST_VERSION >= 104400
return boost::boykov_kolmogorov_max_flow(graph, cluster_source,
cluster_sink);
#else
return boost::kolmogorov_max_flow(graph, cluster_source, cluster_sink);
#endif
}
template <typename VertexLabelMap, typename InputVertexDescriptor>
void update(VertexLabelMap vertex_label_map,
const std::vector<Vertex_descriptor>& inserted_vertices,
InputVertexDescriptor vd,
std::size_t vertex_i,
std::size_t alpha)
{
boost::default_color_type color = boost::get(boost::vertex_color, graph,
inserted_vertices[vertex_i]);
if(std::size_t(get (vertex_label_map, vd)) != alpha
&& color == ColorTraits::white()) //new comers (expansion occurs)
put (vertex_label_map, vd,
static_cast<typename boost::property_traits<VertexLabelMap>::value_type>(alpha));
}
void add_edge (Vertex_descriptor& v1, Vertex_descriptor& v2, double w1, double w2)
{
Edge_descriptor v1_v2, v2_v1;
bool v1_v2_added, v2_v1_added;
boost::tie(v1_v2, v1_v2_added) = boost::add_edge(v1, v2, graph);
boost::tie(v2_v1, v2_v1_added) = boost::add_edge(v2, v1, graph);
CGAL_assertion(v1_v2_added && v2_v1_added);
//put edge capacities
boost::put(boost::edge_reverse, graph, v1_v2, v2_v1);
boost::put(boost::edge_reverse, graph, v2_v1, v1_v2);
//map reverse edges
boost::put(boost::edge_capacity, graph, v1_v2, w1);
boost::put(boost::edge_capacity, graph, v2_v1, w2);
}
};
// another implementation using compressed_sparse_row_graph
// for now there is a performance problem while setting reverse edges
// if that can be solved, it is faster than Alpha_expansion_graph_cut_boost
class Alpha_expansion_boost_compressed_sparse_row_impl
{
private:
// CSR only accepts bundled props
struct VertexP {
boost::default_color_type vertex_color;
double vertex_distance_t;
// ? do not now there is another way to take it, I think since edge_descriptor does not rely on properties
// this should be fine...
boost::compressed_sparse_row_graph<boost::directedS>::edge_descriptor
vertex_predecessor;
};
struct EdgeP {
double edge_capacity;
double edge_residual_capacity;
boost::compressed_sparse_row_graph<boost::directedS>::edge_descriptor
edge_reverse;
};
typedef boost::compressed_sparse_row_graph<boost::directedS,
VertexP, EdgeP> Graph;
typedef boost::graph_traits<Graph> Traits;
typedef boost::color_traits<boost::default_color_type> ColorTraits;
public:
typedef Traits::vertex_descriptor Vertex_descriptor;
typedef Traits::vertex_iterator Vertex_iterator;
typedef Traits::edge_descriptor Edge_descriptor;
typedef Traits::edge_iterator Edge_iterator;
private:
Graph graph;
std::size_t nb_vertices;
std::vector<std::pair<std::size_t, std::size_t> > edge_map;
std::vector<EdgeP> edge_map_weights;
public:
void clear_graph()
{
nb_vertices = 2;
edge_map.clear();
edge_map_weights.clear();
// edge_map.reserve(labels.size() *
// 8); // there is no way to know exact edge count, it is a heuristic value
// edge_map_weights.reserve(labels.size() * 8);
}
Vertex_descriptor add_vertex()
{
return (nb_vertices ++);
}
void add_tweight (Vertex_descriptor& v, double w1, double w2)
{
add_edge (0, v, w1, 0);
add_edge (v, 1, w2, 0);
}
void init_vertices()
{
#if BOOST_VERSION >= 104000
graph = Graph(boost::edges_are_unsorted, edge_map.begin(), edge_map.end(),
edge_map_weights.begin(), nb_vertices);
#else
graph= Graph(edge_map.begin(), edge_map.end(),
edge_map_weights.begin(), nb_vertices);
#endif
// PERFORMANCE PROBLEM
// need to set reverse edge map, I guess there is no way to do that before creating the graph
// since we do not have edge_descs
// however from our edge_map, we know that each (2i, 2i + 1) is reverse pairs, how to facilitate that ?
// will look it back
Graph::edge_iterator ei, ee;
for(boost::tie(ei, ee) = boost::edges(graph); ei != ee; ++ei) {
Graph::vertex_descriptor v1 = boost::source(*ei, graph);
Graph::vertex_descriptor v2 = boost::target(*ei, graph);
std::pair<Graph::edge_descriptor, bool> opp_edge = boost::edge(v2, v1, graph);
CGAL_assertion(opp_edge.second);
graph[opp_edge.first].edge_reverse =
*ei; // and edge_reverse of *ei will be (or already have been) set by the opp_edge
}
}
double max_flow()
{
#if BOOST_VERSION >= 104400
// since properties are bundled, defaults does not work need to specify them
return boost::boykov_kolmogorov_max_flow
(graph,
boost::get(&EdgeP::edge_capacity, graph),
boost::get(&EdgeP::edge_residual_capacity, graph),
boost::get(&EdgeP::edge_reverse, graph),
boost::get(&VertexP::vertex_predecessor, graph),
boost::get(&VertexP::vertex_color, graph),
boost::get(&VertexP::vertex_distance_t, graph),
boost::get(boost::vertex_index,
graph), // this is not bundled, get it from graph (CRS provides one)
0, 1);
#else
return boost::kolmogorov_max_flow
(graph,
boost::get(&EdgeP::edge_capacity, graph),
boost::get(&EdgeP::edge_residual_capacity, graph),
boost::get(&EdgeP::edge_reverse, graph),
boost::get(&VertexP::vertex_predecessor, graph),
boost::get(&VertexP::vertex_color, graph),
boost::get(&VertexP::vertex_distance_t, graph),
boost::get(boost::vertex_index,
graph), // this is not bundled, get it from graph
0, 1);
#endif
}
template <typename VertexLabelMap, typename InputVertexDescriptor>
void update(VertexLabelMap vertex_label_map,
const std::vector<Vertex_descriptor>&,
InputVertexDescriptor vd,
std::size_t vertex_i,
std::size_t alpha)
{
boost::default_color_type color = graph[vertex_i + 2].vertex_color;
if(get(vertex_label_map, vd)!= alpha
&& color == ColorTraits::white()) //new comers (expansion occurs)
put(vertex_label_map, vd, alpha);
}
void add_edge(Vertex_descriptor v1, Vertex_descriptor v2, double w1, double w2)
{
edge_map.push_back(std::make_pair(v1, v2));
EdgeP p1;
p1.edge_capacity = w1;
edge_map_weights.push_back(p1);
edge_map.push_back(std::make_pair(v2, v1));
EdgeP p2;
p2.edge_capacity = w2;
edge_map_weights.push_back(p2);
}
};
// tags
struct Alpha_expansion_boost_adjacency_list_tag { };
struct Alpha_expansion_boost_compressed_sparse_row_tag { };
struct Alpha_expansion_MaxFlow_tag { };
// forward declaration
class Alpha_expansion_MaxFlow_impl;
/// \endcond
// NOTE: latest performances check (2019-07-22)
//
// Using a random graph with 50000 vertices, 100000 edges and 30 labels:
//
// METHOD TIMING MEMORY
// Boost Adjacency list 49s 122MiB
// Boost CSR 187s 77MiB
// MaxFlow 12s 717MiB
/**
\ingroup PkgBGLPartition
regularizes a partition of a graph into `n` labels using the alpha
expansion algorithm \cgalCite{Boykov2001FastApproximate}.
For a graph \f$(V,E)\f$, this function computes a partition `f`
that minimizes the following cost function:
\f[
\mathrm{C}(f) = \sum_{\{v0,v1\} \in E} C_E(v0,v1) + \sum_{v \in V} C_V(f_v)
\f]
where \f$C_E(v0,v1)\f$ is the edge cost of assigning a different
label to \f$v0\f$ and \f$v1\f$, and \f$C_V(f_v)\f$ is the vertex
cost of assigning the label \f$f\f$ to the vertex \f$v\f$.
\tparam InputGraph a model of `VertexAndEdgeListGraph`
\tparam EdgeCostMap a model of `ReadablePropertyMap` with
`boost::graph_traits<InputGraph>::%edge_descriptor` as key and `double`
as value
\tparam VertexLabelCostMap a model of `ReadablePropertyMap`
with `boost::graph_traits<InputGraph>::%vertex_descriptor` as key and
`std::vector<double>` as value
\tparam VertexLabelMap a model of `ReadWritePropertyMap` with
`boost::graph_traits<InputGraph>::%vertex_descriptor` as key and
`std::size_t` as value
\tparam NamedParameters a sequence of named parameters
\param input_graph the input graph.
\param edge_cost_map a property map providing the weight of each
edge.
\param vertex_label_map a property map providing the label of each
vertex. This map will be updated by the algorithm with the
regularized version of the partition.
\param vertex_label_cost_map a property map providing, for each
vertex, an `std::vector` containing the cost of this vertex to
belong to each label. Each `std::vector` should have the same size
`n` (which is the number of labels), each label being indexed from
`0` to `n-1`. For example, `get(vertex_label_cost_map,
vd)[label_idx]` returns the cost of vertex `vd` to belong to the
label `label_idx`.
\param np an optional sequence of \ref bgl_namedparameters "Named Parameters" among the ones listed below
\cgalNamedParamsBegin
\cgalParamNBegin{vertex_index_map}
\cgalParamDescription{a property map associating to each vertex of `input_graph` a unique index between `0` and `num_vertices(input_graph) - 1`}
\cgalParamType{a class model of `ReadablePropertyMap` with `boost::graph_traits<InputGraph>::%vertex_descriptor`
as key type and `std::size_t` as value type}
\cgalParamDefault{an automatically indexed internal map}
\cgalParamExtra{If this parameter is not passed, internal machinery will create and initialize
a face index property map, either using the internal property map if it exists
or using an external map. The latter might result in - slightly - worsened performance
in case of non-constant complexity for index access.}
\cgalParamNEnd
\cgalParamNBegin{implementation_tag}
\cgalParamDescription{a tag used to select which implementation of the alpha expansion should be used.
Available implementation tags are:
- `CGAL::Alpha_expansion_boost_adjacency_list`
- `CGAL::Alpha_expansion_boost_compressed_sparse_row_tag`
- `CGAL::Alpha_expansion_MaxFlow_tag`}
\cgalParamDefault{`CGAL::Alpha_expansion_boost_adjacency_list`}
\cgalParamNEnd
\cgalNamedParamsEnd
\note The `MaxFlow` implementation is provided by the \ref PkgSurfaceMeshSegmentationRef
under GPL license. The header `<CGAL/boost/graph/Alpha_expansion_MaxFlow_tag.h>`
must be included if users want to use this implementation.
*/
template <typename InputGraph,
typename EdgeCostMap,
typename VertexLabelCostMap,
typename VertexLabelMap,
typename NamedParameters>
double alpha_expansion_graphcut (const InputGraph& input_graph,
EdgeCostMap edge_cost_map,
VertexLabelCostMap vertex_label_cost_map,
VertexLabelMap vertex_label_map,
const NamedParameters& np)
{
using parameters::choose_parameter;
using parameters::get_parameter;
typedef boost::graph_traits<InputGraph> GT;
typedef typename GT::edge_descriptor input_edge_descriptor;
typedef typename GT::vertex_descriptor input_vertex_descriptor;
typedef typename GetInitializedVertexIndexMap<InputGraph, NamedParameters>::type VertexIndexMap;
VertexIndexMap vertex_index_map = CGAL::get_initialized_vertex_index_map(input_graph, np);
typedef typename GetImplementationTag<NamedParameters>::type Impl_tag;
// select implementation
typedef typename std::conditional
<std::is_same<Impl_tag, Alpha_expansion_boost_adjacency_list_tag>::value,
Alpha_expansion_boost_adjacency_list_impl,
typename std::conditional
<std::is_same<Impl_tag, Alpha_expansion_boost_compressed_sparse_row_tag>::value,
Alpha_expansion_boost_compressed_sparse_row_impl,
Alpha_expansion_MaxFlow_impl>::type>::type
Alpha_expansion;
typedef typename Alpha_expansion::Vertex_descriptor Vertex_descriptor;
Alpha_expansion alpha_expansion;
// TODO: check this hardcoded parameter
const double tolerance = 1e-10;
double min_cut = (std::numeric_limits<double>::max)();
#ifdef CGAL_SEGMENTATION_BENCH_GRAPHCUT
double vertex_creation_time, edge_creation_time, cut_time;
vertex_creation_time = edge_creation_time = cut_time = 0.0;
#endif
std::vector<Vertex_descriptor> inserted_vertices;
inserted_vertices.resize(num_vertices (input_graph));
std::size_t number_of_labels = get(vertex_label_cost_map, *(vertices(input_graph).first)).size();
bool success;
do {
success = false;
for (std::size_t alpha = 0; alpha < number_of_labels; ++ alpha)
{
alpha_expansion.clear_graph();
#ifdef CGAL_SEGMENTATION_BENCH_GRAPHCUT
Timer timer;
timer.start();
#endif
// For E-Data
// add every input vertex as a vertex to the graph, put edges to source & sink vertices
for (input_vertex_descriptor vd : CGAL::make_range(vertices(input_graph)))
{
std::size_t vertex_i = get(vertex_index_map, vd);
Vertex_descriptor new_vertex = alpha_expansion.add_vertex();
inserted_vertices[vertex_i] = new_vertex;
double source_weight = get(vertex_label_cost_map, vd)[alpha];
// since it is expansion move, current alpha labeled vertices will be assigned to alpha again,
// making sink_weight 'infinity' guarantee this.
double sink_weight = (std::size_t(get(vertex_label_map, vd)) == alpha ?
(std::numeric_limits<double>::max)()
: get(vertex_label_cost_map, vd)[get(vertex_label_map, vd)]);
alpha_expansion.add_tweight(new_vertex, source_weight, sink_weight);
}
#ifdef CGAL_SEGMENTATION_BENCH_GRAPHCUT
vertex_creation_time += timer.time();
timer.reset();
#endif
// For E-Smooth
// add edge between every vertex,
for (input_edge_descriptor ed : CGAL::make_range(edges(input_graph)))
{
input_vertex_descriptor vd1 = source(ed, input_graph);
input_vertex_descriptor vd2 = target(ed, input_graph);
std::size_t idx1 = get (vertex_index_map, vd1);
std::size_t idx2 = get (vertex_index_map, vd2);
double weight = get (edge_cost_map, ed);
Vertex_descriptor v1 = inserted_vertices[idx1],
v2 = inserted_vertices[idx2];
std::size_t label_1 = get (vertex_label_map, vd1);
std::size_t label_2 = get (vertex_label_map, vd2);
if(label_1 == label_2) {
if(label_1 != alpha) {
alpha_expansion.add_edge(v1, v2, weight, weight);
}
} else {
Vertex_descriptor inbetween = alpha_expansion.add_vertex();
double w1 = (label_1 == alpha) ? 0 : weight;
double w2 = (label_2 == alpha) ? 0 : weight;
alpha_expansion.add_edge(inbetween, v1, w1, w1);
alpha_expansion.add_edge(inbetween, v2, w2, w2);
alpha_expansion.add_tweight(inbetween, 0., weight);
}
}
#ifdef CGAL_SEGMENTATION_BENCH_GRAPHCUT
edge_creation_time += timer.time();
#endif
alpha_expansion.init_vertices();
#ifdef CGAL_SEGMENTATION_BENCH_GRAPHCUT
timer.reset();
#endif
double flow = alpha_expansion.max_flow();
#ifdef CGAL_SEGMENTATION_BENCH_GRAPHCUT
cut_time += timer.time();
#endif
if(min_cut - flow <= flow * tolerance) {
continue;
}
min_cut = flow;
success = true;
//update labeling
for (input_vertex_descriptor vd : CGAL::make_range(vertices (input_graph)))
{
std::size_t vertex_i = get (vertex_index_map, vd);
alpha_expansion.update(vertex_label_map, inserted_vertices, vd, vertex_i, alpha);
}
}
} while(success);
#ifdef CGAL_SEGMENTATION_BENCH_GRAPHCUT
CGAL_TRACE_STREAM << "vertex creation time: " << vertex_creation_time <<
std::endl;
CGAL_TRACE_STREAM << "edge creation time: " << edge_creation_time << std::endl;
CGAL_TRACE_STREAM << "max flow algorithm time: " << cut_time << std::endl;
#endif
return min_cut;
}
/// \cond SKIP_IN_MANUAL
// variant with default NP
template <typename InputGraph,
typename EdgeCostMap,
typename VertexLabelCostMap,
typename VertexLabelMap>
double alpha_expansion_graphcut (const InputGraph& input_graph,
EdgeCostMap edge_cost_map,
VertexLabelCostMap vertex_label_cost_map,
VertexLabelMap vertex_label_map)
{
return alpha_expansion_graphcut (input_graph, edge_cost_map,
vertex_label_cost_map, vertex_label_map,
CGAL::parameters::all_default());
}
// Old API
inline double alpha_expansion_graphcut (const std::vector<std::pair<std::size_t, std::size_t> >& edges,
const std::vector<double>& edge_costs,
const std::vector<std::vector<double> >& cost_matrix,
std::vector<std::size_t>& labels)
{
internal::Alpha_expansion_old_API_wrapper_graph graph (edges, edge_costs, cost_matrix, labels);
return alpha_expansion_graphcut(graph,
graph.edge_cost_map(),
graph.vertex_label_cost_map(),
graph.vertex_label_map(),
CGAL::parameters::vertex_index_map (graph.vertex_index_map()));
}
template <typename AlphaExpansionImplementationTag>
double alpha_expansion_graphcut (const std::vector<std::pair<std::size_t, std::size_t> >& edges,
const std::vector<double>& edge_costs,
const std::vector<std::vector<double> >& cost_matrix,
std::vector<std::size_t>& labels,
const AlphaExpansionImplementationTag&)
{
internal::Alpha_expansion_old_API_wrapper_graph graph (edges, edge_costs, cost_matrix, labels);
return alpha_expansion_graphcut(graph,
graph.edge_cost_map(),
graph.vertex_label_cost_map(),
graph.vertex_label_map(),
CGAL::parameters::vertex_index_map (graph.vertex_index_map()).
implementation_tag (AlphaExpansionImplementationTag()));
}
/// \endcond
}//namespace CGAL
namespace boost
{
template <>
struct property_map<CGAL::internal::Alpha_expansion_old_API_wrapper_graph, boost::vertex_index_t>
{
typedef CGAL::internal::Alpha_expansion_old_API_wrapper_graph::Vertex_index_map type;
typedef CGAL::internal::Alpha_expansion_old_API_wrapper_graph::Vertex_index_map const_type;
};
}
#endif //CGAL_BOOST_GRAPH_ALPHA_EXPANSION_GRAPHCUT_H

View File

@ -32,17 +32,14 @@ namespace CGAL {
namespace internal {
template <typename SourceMesh, typename TargetMesh,
typename Hmap,
typename V2V, typename H2H, typename F2F,
typename Src_vpm, typename Tgt_vpm>
void copy_face_graph_impl(const SourceMesh& sm, TargetMesh& tm,
Hmap hmap,
V2V v2v, H2H h2h, F2F f2f,
Src_vpm sm_vpm, Tgt_vpm tm_vpm )
{
typedef typename boost::graph_traits<SourceMesh>::vertex_descriptor sm_vertex_descriptor;
typedef typename boost::graph_traits<TargetMesh>::vertex_descriptor tm_vertex_descriptor;
typedef typename boost::graph_traits<TargetMesh>::vertex_iterator tm_vertex_iterator;
typedef typename boost::graph_traits<SourceMesh>::face_descriptor sm_face_descriptor;
typedef typename boost::graph_traits<TargetMesh>::face_descriptor tm_face_descriptor;
@ -57,19 +54,26 @@ void copy_face_graph_impl(const SourceMesh& sm, TargetMesh& tm,
typename Kernel_traits<typename boost::property_traits<Tgt_vpm>::value_type>::type >
conv;
typedef CGAL::dynamic_halfedge_property_t<tm_halfedge_descriptor> Dyn_h_tag;
typename boost::property_map<SourceMesh, Dyn_h_tag >::const_type hs_to_ht = get(Dyn_h_tag(), sm);
std::vector<tm_halfedge_descriptor> tm_border_halfedges;
std::vector<sm_halfedge_descriptor> sm_border_halfedges;
tm_face_descriptor tm_null_face = boost::graph_traits<TargetMesh>::null_face();
const tm_face_descriptor tm_null_face = boost::graph_traits<TargetMesh>::null_face();
const tm_vertex_descriptor tm_null_vertex = boost::graph_traits<TargetMesh>::null_vertex();
reserve(tm, static_cast<typename boost::graph_traits<TargetMesh>::vertices_size_type>(vertices(sm).size()),
static_cast<typename boost::graph_traits<TargetMesh>::edges_size_type>(edges(sm).size()),
static_cast<typename boost::graph_traits<TargetMesh>::faces_size_type>(faces(sm).size()) );
reserve(tm, static_cast<typename boost::graph_traits<TargetMesh>::vertices_size_type>(vertices(tm).size()+vertices(sm).size()),
static_cast<typename boost::graph_traits<TargetMesh>::edges_size_type>(edges(tm).size()+edges(sm).size()),
static_cast<typename boost::graph_traits<TargetMesh>::faces_size_type>(faces(tm).size()+faces(sm).size()) );
//insert halfedges and create each vertex when encountering its halfedge
std::vector<tm_edge_descriptor> new_edges;
new_edges.reserve(edges(sm).size());
for(sm_edge_descriptor sm_e : edges(sm))
{
tm_edge_descriptor tm_e = add_edge(tm);
new_edges.push_back(tm_e);
sm_halfedge_descriptor sm_h = halfedge(sm_e, sm), sm_h_opp = opposite(sm_h, sm);
tm_halfedge_descriptor tm_h = halfedge(tm_e, tm), tm_h_opp = opposite(tm_h, tm);
@ -77,8 +81,8 @@ void copy_face_graph_impl(const SourceMesh& sm, TargetMesh& tm,
set_next( tm_h, tm_h, tm );
set_next( tm_h_opp, tm_h_opp, tm );
put(hmap, sm_h, tm_h);
put(hmap, sm_h_opp, tm_h_opp);
put(hs_to_ht, sm_h, tm_h);
put(hs_to_ht, sm_h_opp, tm_h_opp);
*h2h++=std::make_pair(sm_h, tm_h);
*h2h++=std::make_pair(sm_h_opp, tm_h_opp);
@ -106,6 +110,8 @@ void copy_face_graph_impl(const SourceMesh& sm, TargetMesh& tm,
set_target(tm_h, tm_h_tgt, tm);
put(tm_vpm, tm_h_tgt, conv(get(sm_vpm, sm_h_tgt)));
}
else
set_target(tm_h, tm_null_vertex, tm);
if ( halfedge(sm_h_src,sm)==sm_h_opp )
{
tm_vertex_descriptor tm_h_src = add_vertex(tm);
@ -114,6 +120,8 @@ void copy_face_graph_impl(const SourceMesh& sm, TargetMesh& tm,
set_target(tm_h_opp, tm_h_src, tm);
put(tm_vpm, tm_h_src, conv(get(sm_vpm, sm_h_src)));
}
else
set_target(tm_h_opp, tm_null_vertex, tm);
}
//create faces and connect halfedges
for(sm_face_descriptor sm_f : faces(sm))
@ -122,13 +130,13 @@ void copy_face_graph_impl(const SourceMesh& sm, TargetMesh& tm,
*f2f++=std::make_pair(sm_f, tm_f);
sm_halfedge_descriptor sm_h_i=halfedge(sm_f, sm);
tm_halfedge_descriptor tm_h_prev = get(hmap, prev(sm_h_i, sm));
tm_halfedge_descriptor tm_h_prev = get(hs_to_ht, prev(sm_h_i, sm));
set_halfedge(tm_f, tm_h_prev, tm);
CGAL_precondition(*halfedges_around_face(sm_h_i, sm).first == sm_h_i);
for(sm_halfedge_descriptor sm_h : halfedges_around_face(sm_h_i, sm))
{
tm_halfedge_descriptor tm_h = get(hmap, sm_h);
tm_halfedge_descriptor tm_h = get(hs_to_ht, sm_h);
set_next(tm_h_prev, tm_h, tm);
set_face(tm_h, tm_f, tm);
tm_h_prev=tm_h;
@ -150,16 +158,14 @@ void copy_face_graph_impl(const SourceMesh& sm, TargetMesh& tm,
halfedges_around_face(next(sm_border_halfedges[i], sm), sm))
{
CGAL_assertion(next(tm_h_prev, tm) == tm_h_prev);
tm_h = get(hmap, sm_h);
tm_h = get(hs_to_ht, sm_h);
set_next(tm_h_prev, tm_h, tm);
tm_h_prev=tm_h;
}
}
// update halfedge vertex of all but the vertex halfedge
for(tm_vertex_iterator vit = vertices(tm).first;
vit != vertices(tm).second; ++vit)
for(tm_vertex_descriptor v : vertices(tm))
{
tm_vertex_descriptor v = *vit;
tm_halfedge_descriptor h = halfedge(v, tm);
tm_halfedge_descriptor next_around_vertex=h;
do{
@ -167,47 +173,42 @@ void copy_face_graph_impl(const SourceMesh& sm, TargetMesh& tm,
set_target(next_around_vertex, v, tm);
}while(h != next_around_vertex);
}
// detect if there are some non-manifold umbrellas and fix missing halfedge target pointers
typedef typename std::vector<tm_edge_descriptor>::iterator edge_iterator;
for (edge_iterator it=new_edges.begin(); it!=new_edges.end(); ++it)
{
if (target(*it, tm) == tm_null_vertex || source(*it, tm) == tm_null_vertex)
{
// create and fill a map from target halfedge to source halfedge
typedef CGAL::dynamic_halfedge_property_t<sm_halfedge_descriptor> Dyn_th_tag;
typename boost::property_map<TargetMesh, Dyn_th_tag >::type ht_to_hs = get(Dyn_th_tag(), tm);
for (sm_halfedge_descriptor hs : halfedges(sm))
put(ht_to_hs, get(hs_to_ht, hs), hs);
for(; it!=new_edges.end(); ++it)
{
tm_halfedge_descriptor nh_t = halfedge(*it, tm);
for (int i=0; i<2; ++i)
{
if (target(nh_t, tm) == tm_null_vertex)
{
// we recover tm_v using the halfedge associated to the target vertex of
// the halfedge in sm corresponding to nh_t. This is working because we
// set the vertex halfedge pointer to the "same" halfedges.
tm_vertex_descriptor tm_v =
target( get(hs_to_ht, halfedge(target(get(ht_to_hs, nh_t), sm), sm)), tm);
for(tm_halfedge_descriptor ht : halfedges_around_target(nh_t, tm))
set_target(ht, tm_v, tm);
}
nh_t = opposite(nh_t, tm);
}
}
break;
}
}
}
template <typename SourceMesh, typename TargetMesh,
typename V2V, typename H2H, typename F2F,
typename Src_vpm, typename Tgt_vpm>
void copy_face_graph(const SourceMesh& sm, TargetMesh& tm,
Tag_false,
V2V v2v, H2H h2h, F2F f2f,
Src_vpm sm_vpm, Tgt_vpm tm_vpm )
{
typedef typename boost::graph_traits<SourceMesh>::halfedge_descriptor sm_halfedge_descriptor;
typedef typename boost::graph_traits<TargetMesh>::halfedge_descriptor tm_halfedge_descriptor;
boost::unordered_map<sm_halfedge_descriptor,
tm_halfedge_descriptor> hash_map(num_halfedges(sm));
copy_face_graph_impl(sm, tm,
boost::make_assoc_property_map(hash_map),
v2v, h2h, f2f,
sm_vpm, tm_vpm);
}
template <typename SourceMesh, typename TargetMesh,
typename V2V, typename H2H, typename F2F,
typename Src_vpm, typename Tgt_vpm>
void copy_face_graph(const SourceMesh& sm, TargetMesh& tm,
Tag_true,
V2V v2v, H2H h2h, F2F f2f,
Src_vpm sm_vpm, Tgt_vpm tm_vpm )
{
typedef typename boost::graph_traits<TargetMesh>::halfedge_descriptor tm_halfedge_descriptor;
std::vector<tm_halfedge_descriptor> hedges(num_halfedges(sm));
copy_face_graph_impl(sm, tm,
bind_property_maps(get_initialized_halfedge_index_map(sm),
make_property_map(hedges)),
v2v, h2h, f2f,
sm_vpm, tm_vpm);
}
} // end of namespace internal
namespace impl
{
@ -253,58 +254,97 @@ inline Emptyset_iterator make_functor(const internal_np::Param_not_found&)
and `boost::graph_traits<SourceMesh>::%face_descriptor` must be
models of `Hashable`.
\tparam TargetMesh a model of `FaceListGraph`
\tparam NamedParameters1 a sequence of \ref pmp_namedparameters "Named Parameters"
\tparam NamedParameters2 a sequence of \ref pmp_namedparameters "Named Parameters"
\tparam NamedParameters1 a sequence of \ref bgl_namedparameters "Named Parameters"
\tparam NamedParameters2 a sequence of \ref bgl_namedparameters "Named Parameters"
The types `sm_vertex_descriptor` and `sm_face_descriptor` must be models of the concept `Hashable`.
\param sm the source mesh
\param tm the target mesh
\param np1 optional sequence of \ref pmp_namedparameters "Named Parameters" among the ones listed below
\param np1 an optional sequence of \ref bgl_namedparameters "Named Parameters" among the ones listed below
\cgalNamedParamsBegin
\cgalParamBegin{vertex_point_map}
the property map with the points associated to the vertices of `sm` .
If this parameter is omitted, an internal property map for
`CGAL::vertex_point_t` should be available in `SourceMesh`
\cgalParamEnd
\cgalParamBegin{vertex_to_vertex_output_iterator} an `OutputIterator` containing the
pairs source-vertex, target-vertex. If this parameter is given, then
`vertex_to_vertex_map` cannot be used.
\cgalParamEnd
\cgalParamBegin{halfedge_to_halfedge_output_iterator} an `OutputIterator` containing the
pairs source-halfedge, target-halfedge. If this parameter is given, then
`halfedge_to_halfedge_map` cannot be used.
\cgalParamEnd
\cgalParamBegin{face_to_face_output_iterator} an `OutputIterator` containing the
pairs source-face, target-face. If this parameter is given, then
`face_to_face_map` cannot be used.
\cgalParamEnd
\cgalParamBegin{vertex_to_vertex_map} a `ReadWritePropertyMap` containing the
pairs source-vertex, target-vertex.
\cgalParamEnd
\cgalParamBegin{halfedge_to_halfedge_map} a `ReadWritePropertyMap` containing the
pairs source-halfedge, target-halfedge.
\cgalParamEnd
\cgalParamBegin{face_to_face_map} a `ReadWritePropertyMap` containing the
pairs source-face, target-face.
\cgalParamEnd
\cgalParamNBegin{vertex_point_map}
\cgalParamDescription{a property map associating points to the vertices of `sm`}
\cgalParamType{a class model of `ReadWritePropertyMap` with `boost::graph_traits<SourceMesh>::%vertex_descriptor`
as key type and `%Point_3` as value type}
\cgalParamDefault{`boost::get(CGAL::vertex_point, sm)`}
\cgalParamExtra{If this parameter is omitted, an internal property map for `CGAL::vertex_point_t`
must be available in `SourceMesh`.}
\cgalParamNEnd
\cgalParamNBegin{vertex_to_vertex_output_iterator}
\cgalParamDescription{an `OutputIterator` containing the pairs source-vertex, target-vertex.}
\cgalParamType{a class model of `OutputIterator` accepting
`std::pair<`boost::graph_traits<SourceMesh>::%vertex_descriptor, `boost::graph_traits<TargetMesh>::%vertex_descriptor>`}
\cgalParamDefault{`Emptyset_iterator`}
\cgalParamExtra{If this parameter is given, then `vertex_to_vertex_map` cannot be used.}
\cgalParamNEnd
\cgalParamNBegin{halfedge_to_halfedge_output_iterator}
\cgalParamDescription{an `OutputIterator` containing the pairs source-halfedge, target-halfedge.}
\cgalParamType{a class model of `OutputIterator` accepting
`std::pair<`boost::graph_traits<SourceMesh>::%halfedge_descriptor, `boost::graph_traits<TargetMesh>::%halfedge_descriptor>`}
\cgalParamDefault{`Emptyset_iterator`}
\cgalParamExtra{If this parameter is given, then `halfedge_to_halfedge_map` cannot be used.}
\cgalParamNEnd
\cgalParamNBegin{face_to_face_output_iterator}
\cgalParamDescription{an `OutputIterator` containing the pairs source-face, target-face.}
\cgalParamType{a class model of `OutputIterator` accepting
`std::pair<`boost::graph_traits<SourceMesh>::%face_descriptor, `boost::graph_traits<TargetMesh>::%face_descriptor>`}
\cgalParamDefault{`Emptyset_iterator`}
\cgalParamExtra{If this parameter is given, then `face_to_face_map` cannot be used.}
\cgalParamNEnd
\cgalParamNBegin{vertex_to_vertex_map}
\cgalParamDescription{a property map storing for each vertex of a source mesh the corresponding vertex of another mesh}
\cgalParamType{a class model of `ReadWritePropertyMap` with
`boost::graph_traits<SourceMesh>::%vertex_descriptor` as key type and
`boost::graph_traits<TargetMesh>::%vertex_descriptor` as value type.}
\cgalParamDefault{unused}
\cgalParamExtra{A typical use case is mapping the vertices from a source mesh
to its copy's after a `copy_face_graph()` operation.}
\cgalParamNEnd
\cgalParamNBegin{halfedge_to_halfedge_map}
\cgalParamDescription{a property map storing for each halfedge of a source mesh the corresponding halfedge of another mesh}
\cgalParamType{a class model of `ReadWritePropertyMap` with
`boost::graph_traits<SourceMesh>::%halfedge_descriptor` as key type and
`boost::graph_traits<TargetMesh>::%halfedge_descriptor` as value type}
\cgalParamDefault{unused}
\cgalParamExtra{A typical use case is mapping the halfedges from a source mesh to its copy's
after a `copy_face_graph()`operation.}
\cgalParamNEnd
\cgalParamNBegin{face_to_face_map}
\cgalParamDescription{a property map storing for each face of a source mesh the corresponding face of another mesh}
\cgalParamType{a class model of `ReadWritePropertyMap` with
`boost::graph_traits<SourceMesh>::%face_descriptor` as key type and
`boost::graph_traits<TargetMesh>::%face_descriptor` as value type}
\cgalParamDefault{unused}
\cgalParamExtra{A typical use case is mapping the faces from a source mesh to its copy's
after a `copy_face_graph()` operation}
\cgalParamNEnd
\cgalNamedParamsEnd
\param np2 optional sequence of \ref pmp_namedparameters "Named Parameters" among the ones listed below
\param np2 an optional sequence of \ref bgl_namedparameters "Named Parameters" among the ones listed below
\cgalNamedParamsBegin
\cgalParamBegin{vertex_point_map}
the property map with the points associated to the vertices of `tm`.
If this parameter is omitted, an internal property map for
`CGAL::vertex_point_t` should be available in `TargetMesh`
\cgalParamEnd
\cgalParamNBegin{vertex_point_map}
\cgalParamDescription{a property map associating points to the vertices of `tm`}
\cgalParamType{a class model of `ReadWritePropertyMap` with `boost::graph_traits<TargetMesh>::%vertex_descriptor`
as key type and `%Point_3` as value type}
\cgalParamDefault{`boost::get(CGAL::vertex_point, tm)`}
\cgalParamExtra{If this parameter is omitted, an internal property map for `CGAL::vertex_point_t`
must be available in `TargetMesh`.}
\cgalParamNEnd
\cgalNamedParamsEnd
The points from `sm` to `tm` are converted using
`CGAL::Cartesian_converter<SourceKernel, TargetKernel>`.
`SourceKernel` and `TargetKernel` are deduced using `CGAL::Kernel_traits`
from the value types of the vertex_point_maps.
from the value types of the vertex point maps.
Other properties are not copied.
*/
@ -329,8 +369,7 @@ void copy_face_graph(const SourceMesh& sm, TargetMesh& tm,
using parameters::choose_parameter;
using parameters::get_parameter;
internal::copy_face_graph(sm, tm,
CGAL::graph_has_property<SourceMesh,boost::halfedge_index_t>(),
internal::copy_face_graph_impl(sm, tm,
choose_parameter(get_parameter(np1, internal_np::vertex_to_vertex_output_iterator),
impl::make_functor(get_parameter(np1, internal_np::vertex_to_vertex_map))),
choose_parameter(get_parameter(np1, internal_np::halfedge_to_halfedge_output_iterator),
@ -357,7 +396,7 @@ void copy_face_graph(const SourceMesh& sm, TargetMesh& tm,
copy_face_graph(sm, tm, np, parameters::all_default());
}
#if !defined(DOXYGEN_RUNNING)
#if !defined(DOXYGEN_RUNNING) && !defined(CGAL_NO_DEPRECATED_CODE)
template <typename SourceMesh, typename TargetMesh,
typename V2V, typename H2H, typename F2F,
typename Src_vpm, typename Tgt_vpm>
@ -365,10 +404,9 @@ void copy_face_graph(const SourceMesh& sm, TargetMesh& tm,
V2V v2v, H2H h2h, F2F f2f,
Src_vpm sm_vpm, Tgt_vpm tm_vpm )
{
internal::copy_face_graph(sm, tm,
CGAL::graph_has_property<SourceMesh,boost::halfedge_index_t>(),
v2v, h2h, f2f,
sm_vpm, tm_vpm);
internal::copy_face_graph_impl(sm, tm,
v2v, h2h, f2f,
sm_vpm, tm_vpm);
}

View File

@ -0,0 +1,171 @@
// Copyright (c) 2020 GeometryFactory (France). All rights reserved.
//
// This file is part of CGAL (www.cgal.org)
//
// $URL$
// $Id$
// SPDX-License-Identifier: LGPL-3.0-or-later OR LicenseRef-Commercial
//
//
// Author(s) : Sébastien Loriot
// This file is intentionally not protected against re-inclusion.
// It's aimed at being included from within a user code to
// make any structure inheriting from a face graph model a face graph
// model itself
// It is the responsibility of the including file to correctly set the
// macros CGAL_GRAPH_TRAITS_INHERITANCE_CLASS_NAME, CGAL_GRAPH_TRAITS_INHERITANCE_BASE_CLASS_NAME
// and optionally CGAL_GRAPH_TRAITS_INHERITANCE_TEMPLATE_PARAMS.
// They are #undefed at the end of this file.
/**
* \ingroup PkgBGLRef
* \file CGAL/boost/graph/graph_traits_inheritance_macros.h
* Convenience header file defining the necessary specializations and overloads to make a
* class, inheriting from a model of a face graph concept, a model of that face graph concept itself.
* Prior to the inclusion of this header, specific macros must be defined and those macros will be
* undefined automatically when processing to the inclusion of this header.
* It is possible to include the header several times if the operation must be done for several classes.
* The macros that must be defined are the following:
* - `CGAL_GRAPH_TRAITS_INHERITANCE_CLASS_NAME`: the inheriting class. If it is a template class, it must be instantiated parameters named as in `CGAL_GRAPH_TRAITS_INHERITANCE_TEMPLATE_PARAMS` or parameters available in the scope including the header;
* - `CGAL_GRAPH_TRAITS_INHERITANCE_BASE_CLASS_NAME`: the base class. it must be instantiated parameters named as in `CGAL_GRAPH_TRAITS_INHERITANCE_TEMPLATE_PARAMS` or parameters available in the scope including the header;
* - `CGAL_GRAPH_TRAITS_INHERITANCE_TEMPLATE_PARAMS`: (optional) if the inheriting class, a list of template parameters separated by commas (`,`) including `class/typename/integral type`.
*
* Some examples are provided in \ref Surface_mesh/sm_derivation.cpp and \ref Polyhedron/poly_derivation.cpp.
*
*/
#include <CGAL/config.h>
#if !defined(CGAL_GRAPH_TRAITS_INHERITANCE_CLASS_NAME) || !defined(CGAL_GRAPH_TRAITS_INHERITANCE_BASE_CLASS_NAME)
CGAL_pragma_warning("\nBoth macros CGAL_GRAPH_TRAITS_INHERITANCE_CLASS_NAME and CGAL_GRAPH_TRAITS_INHERITANCE_BASE_CLASS_NAME "
"must be defined if you want to use this file\n")
#else
#ifdef CGAL_GRAPH_TRAITS_INHERITANCE_TEMPLATE_PARAMS
namespace boost {
template <CGAL_GRAPH_TRAITS_INHERITANCE_TEMPLATE_PARAMS>
struct graph_traits<CGAL_GRAPH_TRAITS_INHERITANCE_CLASS_NAME> :
public graph_traits<CGAL_GRAPH_TRAITS_INHERITANCE_BASE_CLASS_NAME>
{};
template <CGAL_GRAPH_TRAITS_INHERITANCE_TEMPLATE_PARAMS, typename CGAL_XX_YATP>
struct property_map<CGAL_GRAPH_TRAITS_INHERITANCE_CLASS_NAME, CGAL_XX_YATP> :
public property_map<CGAL_GRAPH_TRAITS_INHERITANCE_BASE_CLASS_NAME, CGAL_XX_YATP>
{};
} // boost namespace
#define CGAL_PM_DT_SPEC(DTAG) \
namespace boost {\
template <CGAL_GRAPH_TRAITS_INHERITANCE_TEMPLATE_PARAMS, typename CGAL_XX_YATP> \
struct property_map<CGAL_GRAPH_TRAITS_INHERITANCE_CLASS_NAME, DTAG<CGAL_XX_YATP> > \
: property_map<CGAL_GRAPH_TRAITS_INHERITANCE_BASE_CLASS_NAME, DTAG<CGAL_XX_YATP> > \
{};\
} /* boost namespace */\
\
namespace CGAL { \
template <CGAL_GRAPH_TRAITS_INHERITANCE_TEMPLATE_PARAMS, typename CGAL_XX_YATP>\
typename boost::property_map<CGAL_GRAPH_TRAITS_INHERITANCE_CLASS_NAME, DTAG<CGAL_XX_YATP> >::type \
get(DTAG<CGAL_XX_YATP> t, CGAL_GRAPH_TRAITS_INHERITANCE_CLASS_NAME& g) \
{ \
return get(t, static_cast<CGAL_GRAPH_TRAITS_INHERITANCE_BASE_CLASS_NAME&>(g)); \
} \
\
template <CGAL_GRAPH_TRAITS_INHERITANCE_TEMPLATE_PARAMS, typename CGAL_XX_YATP>\
typename boost::property_map<CGAL_GRAPH_TRAITS_INHERITANCE_CLASS_NAME, DTAG<CGAL_XX_YATP> >::const_type \
get(DTAG<CGAL_XX_YATP> t, const CGAL_GRAPH_TRAITS_INHERITANCE_CLASS_NAME& g) \
{ \
return get(t, static_cast<const CGAL_GRAPH_TRAITS_INHERITANCE_BASE_CLASS_NAME&>(g)); \
}\
} //CGAL namespace
CGAL_PM_DT_SPEC(CGAL::dynamic_vertex_property_t)
CGAL_PM_DT_SPEC(CGAL::dynamic_halfedge_property_t)
CGAL_PM_DT_SPEC(CGAL::dynamic_face_property_t)
CGAL_PM_DT_SPEC(CGAL::dynamic_edge_property_t)
#undef CGAL_PM_DT_SPEC
namespace CGAL {
template <CGAL_GRAPH_TRAITS_INHERITANCE_TEMPLATE_PARAMS, typename CGAL_XX_YATP>
struct graph_has_property<CGAL_GRAPH_TRAITS_INHERITANCE_CLASS_NAME, CGAL_XX_YATP> :
public CGAL::graph_has_property<CGAL_GRAPH_TRAITS_INHERITANCE_BASE_CLASS_NAME, CGAL_XX_YATP>
{};
} // CGAL namespace
#undef CGAL_GRAPH_TRAITS_INHERITANCE_TEMPLATE_PARAMS
#else
namespace boost {
template <>
struct graph_traits<CGAL_GRAPH_TRAITS_INHERITANCE_CLASS_NAME> :
public graph_traits<CGAL_GRAPH_TRAITS_INHERITANCE_BASE_CLASS_NAME>
{};
template <typename CGAL_XX_YATP>
struct property_map<CGAL_GRAPH_TRAITS_INHERITANCE_CLASS_NAME, CGAL_XX_YATP> :
public property_map<CGAL_GRAPH_TRAITS_INHERITANCE_BASE_CLASS_NAME, CGAL_XX_YATP>
{};
} // boost namespace
#define CGAL_PM_DT_SPEC(DTAG) \
namespace boost {\
template <typename CGAL_XX_YATP> \
struct property_map<CGAL_GRAPH_TRAITS_INHERITANCE_CLASS_NAME, DTAG<CGAL_XX_YATP> > \
: property_map<CGAL_GRAPH_TRAITS_INHERITANCE_BASE_CLASS_NAME, DTAG<CGAL_XX_YATP> > \
{};\
} /* boost namespace */\
\
namespace CGAL { \
template <typename CGAL_XX_YATP>\
typename boost::property_map<CGAL_GRAPH_TRAITS_INHERITANCE_CLASS_NAME, DTAG<CGAL_XX_YATP> >::type \
get(DTAG<CGAL_XX_YATP> t, CGAL_GRAPH_TRAITS_INHERITANCE_CLASS_NAME& g) \
{ \
return get(t, static_cast<CGAL_GRAPH_TRAITS_INHERITANCE_BASE_CLASS_NAME&>(g)); \
} \
\
template <typename CGAL_XX_YATP>\
typename boost::property_map<CGAL_GRAPH_TRAITS_INHERITANCE_CLASS_NAME, DTAG<CGAL_XX_YATP> >::const_type \
get(DTAG<CGAL_XX_YATP> t, const CGAL_GRAPH_TRAITS_INHERITANCE_CLASS_NAME& g) \
{ \
return get(t, static_cast<const CGAL_GRAPH_TRAITS_INHERITANCE_BASE_CLASS_NAME&>(g)); \
}\
} //CGAL namespace
CGAL_PM_DT_SPEC(CGAL::dynamic_vertex_property_t)
CGAL_PM_DT_SPEC(CGAL::dynamic_halfedge_property_t)
CGAL_PM_DT_SPEC(CGAL::dynamic_face_property_t)
CGAL_PM_DT_SPEC(CGAL::dynamic_edge_property_t)
#undef CGAL_PM_DT_SPEC
namespace CGAL {
template <typename CGAL_XX_YATP>
struct graph_has_property<CGAL_GRAPH_TRAITS_INHERITANCE_CLASS_NAME, CGAL_XX_YATP> :
public CGAL::graph_has_property<CGAL_GRAPH_TRAITS_INHERITANCE_BASE_CLASS_NAME, CGAL_XX_YATP>
{};
} // CGAL namespace
#endif
#undef CGAL_GRAPH_TRAITS_INHERITANCE_CLASS_NAME
#undef CGAL_GRAPH_TRAITS_INHERITANCE_BASE_CLASS_NAME
#endif

View File

@ -35,9 +35,11 @@ bool is_index_map_valid(IndexMap idmap,
Id_type max_id = static_cast<Id_type>(num_simplices);
std::vector<bool> indices(max_id);
for(const auto& d : range)
// According to concepts, the descriptor ranges such as 'vertices(g)' return a 'std::pair<it, it>'
for(auto it = range.first; it != range.second; ++it)
{
const Id_type id = get(idmap, d);
const Id_type id = get(idmap, *it);
if(id >= 0 && id < max_id && !indices[id])
{
indices[id] = true;

View File

@ -27,16 +27,27 @@
#include <CGAL/IO/write_vtk.h>
namespace CGAL {
/*!
\ingroup PkgBGLIOFct
writes the graph `g` in the wrl format (VRML 2.0).
\cgalNamedParamsBegin
* \cgalParamBegin{vertex_point_map} the property map with the points associated to the vertices of `g`.
* If this parameter is omitted, an internal property map for
* `CGAL::vertex_point_t` should be available in `FaceGraph`\cgalParamEnd
* \cgalNamedParamsEnd
*/
/*!
\ingroup PkgBGLIOFct
writes the graph `g` in the wrl format (VRML 2.0).
\param os the output stream
\param g the graph to be written
\param np an optional sequence of \ref bgl_namedparameters "Named Parameters" among the ones listed below
\cgalNamedParamsBegin
\cgalParamNBegin{vertex_point_map}
\cgalParamDescription{a property map associating points to the vertices of `g`}
\cgalParamType{a class model of `ReadablePropertyMap` with `boost::graph_traits<FaceGraph>::%vertex_descriptor`
as key type and `%Point_3` as value type}
\cgalParamDefault{`boost::get(CGAL::vertex_point, g)`}
\cgalParamExtra{If this parameter is omitted, an internal property map for `CGAL::vertex_point_t`
must be available in `FaceGraph`.}
\cgalParamNEnd
\cgalNamedParamsEnd
*/
template <typename FaceGraph, typename NamedParameters>
bool write_wrl(std::ostream& os,
const FaceGraph& g,
@ -114,18 +125,27 @@ bool write_wrl(std::ostream& os,
}
/*!
\ingroup PkgBGLIOFct
writes the graph `g` in the OFF format.
\ingroup PkgBGLIOFct
\cgalNamedParamsBegin
* \cgalParamBegin{vertex_point_map} the property map with the points associated to the vertices of `g`.
* If this parameter is omitted, an internal property map for
* `CGAL::vertex_point_t` should be available in `FaceGraph`\cgalParamEnd
* \cgalNamedParamsEnd
writes the graph `g` in the OFF format.
\sa Overloads of this function for specific models of the concept `FaceGraph`.
\param os the output stream
\param g the graph to be written
\param np an optional sequence of \ref bgl_namedparameters "Named Parameters" among the ones listed below
*/
\cgalNamedParamsBegin
\cgalParamNBegin{vertex_point_map}
\cgalParamDescription{a property map associating points to the vertices of `g`}
\cgalParamType{a class model of `ReadablePropertyMap` with `boost::graph_traits<FaceGraph>::%vertex_descriptor`
as key type and `%Point_3` as value type}
\cgalParamDefault{`boost::get(CGAL::vertex_point, g)`}
\cgalParamExtra{If this parameter is omitted, an internal property map for `CGAL::vertex_point_t`
must be available in `FaceGraph`.}
\cgalParamNEnd
\cgalNamedParamsEnd
\sa Overloads of this function for specific models of the concept `FaceGraph`.
*/
template <typename FaceGraph, typename NamedParameters>
bool write_off(std::ostream& os,
const FaceGraph& g,
@ -236,19 +256,30 @@ inline std::string next_non_comment(std::istream& is)
/*!
\ingroup PkgBGLIOFct
reads the graph `g` from data in the OFF format. Ignores comment lines which start with a hash, and lines with whitespace.
\ingroup PkgBGLIOFct
\cgalNamedParamsBegin
* \cgalParamBegin{vertex_point_map} the property map with the points associated to the vertices of `g`.
* If this parameter is omitted, an internal property map for
* `CGAL::vertex_point_t` should be available in `FaceGraph`\cgalParamEnd
* \cgalNamedParamsEnd
\sa Overloads of this function for specific models of the concept `FaceGraph`.
\pre The data must represent a 2-manifold
\attention The graph `g` is not cleared, and the data from the stream are added.
reads the graph `g` from data in the OFF format. Ignores comment lines which start with a hash, and lines with whitespace.
*/
\param is the input stream
\param g the graph to be read
\param np an optional sequence of \ref bgl_namedparameters "Named Parameters" among the ones listed below
\cgalNamedParamsBegin
\cgalParamNBegin{vertex_point_map}
\cgalParamDescription{a property map associating points to the vertices of `g`}
\cgalParamType{a class model of `WritablePropertyMap` with `boost::graph_traits<FaceGraph>::%vertex_descriptor`
as key type and `%Point_3` as value type}
\cgalParamDefault{`boost::get(CGAL::vertex_point, g)`}
\cgalParamExtra{If this parameter is omitted, an internal property map for `CGAL::vertex_point_t`
must be available in `FaceGraph`.}
\cgalParamNEnd
\cgalNamedParamsEnd
\sa Overloads of this function for specific models of the concept `FaceGraph`.
\pre The data must represent a 2-manifold
\attention The graph `g` is not cleared, and the data from the stream are added.
*/
template <typename FaceGraph, typename NamedParameters>
bool read_off(std::istream& is,
FaceGraph& g,
@ -614,24 +645,34 @@ write_polys_points(std::ostream& os,
* \brief writes a triangulated surface mesh in the `PolyData` XML format.
*
* \tparam TriangleMesh a model of `FaceListGraph` with only triangle faces.
* \tparam NamedParameters a sequence of \ref pmp_namedparameters "Named Parameters"
* \tparam NamedParameters a sequence of \ref bgl_namedparameters "Named Parameters"
*
* \param os the stream used for writing.
* \param mesh the triangle mesh to be written.
* \param np optional sequence of \ref pmp_namedparameters "Named Parameters" among the
* ones listed below
* \param np an optional sequence of \ref bgl_namedparameters "Named Parameters" among the ones listed below
*
* \cgalNamedParamsBegin
* \cgalParamBegin{use_binary_mode} a Boolean indicating if the
* data should be written in binary (`true`, the default) or in ASCII (`false`).
* \cgalParamEnd
* \cgalParamBegin{vertex_point_map} the property map with the points associated to
* the vertices of `mesh`. If this parameter is omitted, an internal property map for
* `CGAL::vertex_point_t` must be available in `TriangleMesh`.
* \cgalParamEnd
* \cgalParamBegin{vertex_index_map} the property map with the indices associated to
* the vertices of `mesh`.
* \cgalParamEnd
* \cgalParamNBegin{use_binary_mode}
* \cgalParamDescription{Boolean indicating if the data should be written in binary (`true`) or in ASCII (`false`)}
* \cgalParamType{Boolean}
* \cgalParamDefault{`true`}
* \cgalParamNEnd
*
* \cgalParamNBegin{vertex_point_map}
* \cgalParamDescription{a property map associating points to the vertices of `mesh`}
* \cgalParamType{a class model of `ReadablePropertyMap` with `boost::graph_traits<TriangleMesh>::%vertex_descriptor`
* as key type and `%Point_3` as value type}
* \cgalParamDefault{`boost::get(CGAL::vertex_point, mesh)`}
* \cgalParamExtra{If this parameter is omitted, an internal property map for `CGAL::vertex_point_t`
* must be available in `TriangleMesh`.}
* \cgalParamNEnd
*
* \cgalParamNBegin{vertex_index_map}
* \cgalParamDescription{a property map associating to each vertex of `mesh` a unique index between `0` and `num_vertices(mesh) - 1`}
* \cgalParamType{a class model of `ReadablePropertyMap` with `boost::graph_traits<TriangleMesh>::%vertex_descriptor`
* as key type and `std::size_t` as value type}
* \cgalParamDefault{an automatically indexed internal map}
* \cgalParamNEnd
* \cgalNamedParamsEnd
*/
template<class TriangleMesh,

View File

@ -25,6 +25,8 @@
#include <CGAL/Dynamic_property_map.h>
#include <CGAL/Kernel_traits.h>
#include <CGAL/Origin.h>
#include <CGAL/iterator.h>
#include <CGAL/property_map.h>
#include <boost/mpl/if.hpp>
@ -40,6 +42,7 @@ namespace CGAL {
class Default_diagonalize_traits;
class Eigen_svd;
class Lapack_svd;
struct Alpha_expansion_boost_adjacency_list_tag;
//
@ -222,7 +225,7 @@ typename BGL::internal::GetInitializedIndexMap<CGAL::internal_np::DTYPE##_index_
CGAL::dynamic_##DTYPE##_property_t<STYPE>, \
Graph, NamedParameters>::const_type \
get_initialized_##DTYPE##_index_map(const Graph& g, \
const NamedParameters& np) \
const NamedParameters& np) \
{ \
typedef BGL::internal::GetInitializedIndexMap<CGAL::internal_np::DTYPE##_index_t, \
boost::DTYPE##_index_t, \
@ -250,7 +253,7 @@ typename BGL::internal::GetInitializedIndexMap<CGAL::internal_np::DTYPE##_index_
CGAL::dynamic_##DTYPE##_property_t<STYPE>, \
Graph, NamedParameters>::type \
get_initialized_##DTYPE##_index_map(Graph& g, \
const NamedParameters& np) \
const NamedParameters& np) \
{ \
typedef BGL::internal::GetInitializedIndexMap<CGAL::internal_np::DTYPE##_index_t, \
boost::DTYPE##_index_t, \
@ -499,6 +502,18 @@ CGAL_DEF_GET_INITIALIZED_INDEX_MAP(face, typename boost::graph_traits<Graph>::fa
> ::type type;
};
template<typename PointRange, typename NamedParameters>
class GetAdjacencies
{
public:
typedef Emptyset_iterator Empty;
typedef typename internal_np::Lookup_named_param_def <
internal_np::adjacencies_t,
NamedParameters,
Empty//default
> ::type type;
};
} // namespace Point_set_processing_3
template<typename NamedParameters, typename DefaultSolver>
@ -550,6 +565,16 @@ CGAL_DEF_GET_INITIALIZED_INDEX_MAP(face, typename boost::graph_traits<Graph>::fa
> ::type type;
};
template<typename NamedParameters>
class GetImplementationTag
{
public:
typedef typename internal_np::Lookup_named_param_def <
internal_np::implementation_tag_t,
NamedParameters,
Alpha_expansion_boost_adjacency_list_tag
>::type type;
};
} //namespace CGAL

View File

@ -36,6 +36,8 @@ CGAL_add_named_parameter(face_to_face_output_iterator_t, face_to_face_output_ite
CGAL_add_named_parameter(vertex_to_vertex_map_t, vertex_to_vertex_map, vertex_to_vertex_map)
CGAL_add_named_parameter(halfedge_to_halfedge_map_t, halfedge_to_halfedge_map, halfedge_to_halfedge_map)
CGAL_add_named_parameter(face_to_face_map_t, face_to_face_map, face_to_face_map)
CGAL_add_named_parameter(implementation_tag_t, implementation_tag, implementation_tag)
CGAL_add_named_parameter(prevent_unselection_t, prevent_unselection, prevent_unselection)
// List of named parameters that we use in the package 'Mesh_3'
CGAL_add_named_parameter(vertex_feature_degree_t, vertex_feature_degree, vertex_feature_degree_map)
@ -84,9 +86,22 @@ CGAL_add_named_parameter(use_angle_smoothing_t, use_angle_smoothing, use_angle_s
CGAL_add_named_parameter(use_area_smoothing_t, use_area_smoothing, use_area_smoothing)
CGAL_add_named_parameter(use_Delaunay_flips_t, use_Delaunay_flips, use_Delaunay_flips)
CGAL_add_named_parameter(do_project_t, do_project, do_project)
CGAL_add_named_parameter(do_orientation_tests_t, do_orientation_tests, do_orientation_tests)
CGAL_add_named_parameter(do_self_intersection_tests_t, do_self_intersection_tests, do_self_intersection_tests)
CGAL_add_named_parameter(error_codes_t, error_codes, error_codes)
CGAL_add_named_parameter(volume_inclusions_t, volume_inclusions, volume_inclusions)
CGAL_add_named_parameter(face_cc_map_t, face_connected_component_map, face_connected_component_map)
CGAL_add_named_parameter(ccid_to_vid_vector_t, connected_component_id_to_volume_id, connected_component_id_to_volume_id)
CGAL_add_named_parameter(is_cc_outward_oriented_bs_t, is_cc_outward_oriented, is_cc_outward_oriented);
CGAL_add_named_parameter(intersecting_volume_pairs_t, intersecting_volume_pairs_output_iterator, intersecting_volume_pairs_output_iterator);
CGAL_add_named_parameter(i_used_as_a_predicate_t, i_used_as_a_predicate, i_used_as_a_predicate);
CGAL_add_named_parameter(nesting_levels_t, nesting_levels, nesting_levels);
CGAL_add_named_parameter(i_used_for_volume_orientation_t, i_used_for_volume_orientation, i_used_for_volume_orientation);
CGAL_add_named_parameter(area_threshold_t, area_threshold, area_threshold)
CGAL_add_named_parameter(halfedges_keeper_t, halfedges_keeper, halfedges_keeper)
CGAL_add_named_parameter(volume_threshold_t, volume_threshold, volume_threshold)
CGAL_add_named_parameter(dry_run_t, dry_run, dry_run)
CGAL_add_named_parameter(do_not_modify_t, do_not_modify, do_not_modify)
// 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)
@ -124,6 +139,7 @@ CGAL_add_named_parameter(plane_index_t, plane_index_map, plane_index_map)
CGAL_add_named_parameter(select_percentage_t, select_percentage, select_percentage)
CGAL_add_named_parameter(require_uniform_sampling_t, require_uniform_sampling, require_uniform_sampling)
CGAL_add_named_parameter(point_is_constrained_t, point_is_constrained, point_is_constrained_map)
CGAL_add_named_parameter(maximum_number_of_faces_t, maximum_number_of_faces, maximum_number_of_faces)
CGAL_add_named_parameter(transformation_t, transformation, transformation)
CGAL_add_named_parameter(point_set_filters_t, point_set_filters, point_set_filters)
CGAL_add_named_parameter(matcher_t, matcher, matcher)
@ -133,6 +149,7 @@ CGAL_add_named_parameter(transformation_checkers_t, transformation_checkers, tra
CGAL_add_named_parameter(inspector_t, inspector, inspector)
CGAL_add_named_parameter(logger_t, logger, logger)
CGAL_add_named_parameter(pointmatcher_config_t, pointmatcher_config, pointmatcher_config)
CGAL_add_named_parameter(adjacencies_t, adjacencies, adjacencies)
// List of named parameters used in Surface_mesh_approximation package
CGAL_add_named_parameter(verbose_level_t, verbose_level, verbose_level)
@ -141,6 +158,9 @@ CGAL_add_named_parameter(max_number_of_proxies_t, max_number_of_proxies, max_num
CGAL_add_named_parameter(min_error_drop_t, min_error_drop, min_error_drop)
CGAL_add_named_parameter(number_of_relaxations_t, number_of_relaxations, number_of_relaxations)
// List of named parameters used in Optimal_bounding_box package
CGAL_add_named_parameter(use_convex_hull_t, use_convex_hull, use_convex_hull)
// meshing parameters
CGAL_add_named_parameter(subdivision_ratio_t, subdivision_ratio, subdivision_ratio)
CGAL_add_named_parameter(relative_to_chord_t, relative_to_chord, relative_to_chord)
@ -148,6 +168,13 @@ CGAL_add_named_parameter(with_dihedral_angle_t, with_dihedral_angle, with_dihedr
CGAL_add_named_parameter(optimize_anchor_location_t, optimize_anchor_location, optimize_anchor_location)
CGAL_add_named_parameter(pca_plane_t, pca_plane, pca_plane)
// tetrahedral remeshing parameters
CGAL_add_named_parameter(remesh_boundaries_t, remesh_boundaries, remesh_boundaries)
CGAL_add_named_parameter(cell_selector_t, cell_selector, cell_selector)
CGAL_add_named_parameter(facet_is_constrained_t, facet_is_constrained, facet_is_constrained_map)
CGAL_add_named_parameter(remeshing_visitor_t, remeshing_visitor, remeshing_visitor)
CGAL_add_named_parameter(smooth_constrained_edges_t, smooth_constrained_edges, smooth_constrained_edges)
// output parameters
CGAL_add_named_parameter(face_proxy_map_t, face_proxy_map, face_proxy_map)
CGAL_add_named_parameter(proxies_t, proxies, proxies)
@ -159,4 +186,3 @@ CGAL_add_named_parameter(accuracy_t, accuracy, accuracy)
CGAL_add_named_parameter(maximum_running_time_t, maximum_running_time, maximum_running_time)
CGAL_add_named_parameter(overlap_t, overlap, overlap)
CGAL_add_named_parameter(maximum_normal_deviation_t, maximum_normal_deviation, maximum_normal_deviation)

View File

@ -423,7 +423,11 @@ template<typename K>
void
put(boost::vertex_point_t p, OPEN_MESH_CLASS& g,
typename boost::graph_traits< OPEN_MESH_CLASS >::vertex_descriptor vd,
#if defined(CGAL_USE_OM_POINTS)
const typename K::Point& point)
#else
const CGAL::Exact_predicates_inexact_constructions_kernel::Point_3& point)
#endif
{
put(get(p,g), vd, point);
}

View File

@ -16,6 +16,12 @@
#include <CGAL/boost/graph/iterator.h>
#include <boost/unordered_set.hpp>
#include <CGAL/boost/graph/Dual.h>
#include <boost/graph/filtered_graph.hpp>
#include <boost/iterator/filter_iterator.hpp>
#include <CGAL/boost/graph/alpha_expansion_graphcut.h>
#include <CGAL/squared_distance_3.h>
namespace CGAL {
@ -56,12 +62,231 @@ extract_selection_boundary(
}
return out;
}
template <typename GeomTraits,
typename FaceGraph,
typename IsSelectedMap,
typename FaceIndexMap,
typename VertexPointMap>
struct Regularization_graph
{
typedef boost::graph_traits<FaceGraph> GT;
typedef typename GT::face_descriptor fg_face_descriptor;
typedef typename GT::face_iterator fg_face_iterator;
typedef typename GT::halfedge_descriptor fg_halfedge_descriptor;
typedef typename GT::edge_descriptor fg_edge_descriptor;
typedef typename GT::edge_iterator fg_edge_iterator;
typedef typename GT::vertex_descriptor fg_vertex_descriptor;
typedef fg_face_descriptor vertex_descriptor;
typedef fg_face_iterator vertex_iterator;
typedef fg_edge_descriptor edge_descriptor;
typedef boost::undirected_tag directed_category;
typedef boost::disallow_parallel_edge_tag edge_parallel_category;
typedef boost::edge_list_graph_tag traversal_category;
struct Filter_border_edges
{
FaceGraph* fg;
Filter_border_edges (FaceGraph& fg) : fg (&fg) { }
bool operator() (const fg_edge_descriptor ed) const
{
return !is_border (ed, *fg);
}
};
typedef boost::filter_iterator<Filter_border_edges, fg_edge_iterator> edge_iterator;
struct Vertex_label_map
{
typedef vertex_descriptor key_type;
typedef std::size_t value_type;
typedef std::size_t& reference;
typedef boost::lvalue_property_map_tag category;
Regularization_graph* rg;
Vertex_label_map (Regularization_graph* rg)
: rg (rg) { }
friend reference get (const Vertex_label_map& map, key_type k)
{
return (map.rg->labels)[get(map.rg->face_index_map,k)];
}
friend void put (const Vertex_label_map& map, key_type k, const value_type& v)
{
(map.rg->labels)[get(map.rg->face_index_map,k)] = v;
}
};
struct Vertex_label_probability_map
{
typedef vertex_descriptor key_type;
typedef std::vector<double> value_type;
typedef value_type reference;
typedef boost::readable_property_map_tag category;
const Regularization_graph* rg;
Vertex_label_probability_map (const Regularization_graph* rg)
: rg (rg)
{ }
friend reference get (const Vertex_label_probability_map& pmap, key_type fd)
{
double value = (1. - pmap.rg->weight) * pmap.rg->area (fd) / pmap.rg->total_area;
std::vector<double> out(2);
if (get(pmap.rg->is_selected_map, fd))
{
if (pmap.rg->prevent_unselection)
out[0] = (std::numeric_limits<double>::max)();
else
out[0] = value;
out[1] = 0.;
}
else
{
out[0] = 0.;
out[1] = value;
}
return out;
}
};
struct Edge_cost_map
{
typedef edge_descriptor key_type;
typedef double value_type;
typedef value_type reference;
typedef boost::readable_property_map_tag category;
const Regularization_graph* rg;
Edge_cost_map (const Regularization_graph* rg)
: rg (rg) { }
friend reference get (const Edge_cost_map& pmap, key_type ed)
{
fg_vertex_descriptor esource = source(ed, pmap.rg->fg);
fg_vertex_descriptor etarget = target(ed, pmap.rg->fg);
// Cost
double edge_length = std::sqrt(CGAL::squared_distance (get (pmap.rg->vertex_point_map, esource),
get (pmap.rg->vertex_point_map, etarget)));
return pmap.rg->weight * edge_length / pmap.rg->total_length;
}
};
FaceGraph& fg;
IsSelectedMap is_selected_map;
FaceIndexMap face_index_map;
VertexPointMap vertex_point_map;
double total_length;
double total_area;
double weight;
bool prevent_unselection;
std::vector<std::size_t> labels;
Regularization_graph (FaceGraph& fg,
IsSelectedMap is_selected_map,
FaceIndexMap face_index_map,
VertexPointMap vertex_point_map,
double weight,
bool prevent_unselection)
: fg (fg),
is_selected_map (is_selected_map),
face_index_map (face_index_map),
vertex_point_map (vertex_point_map),
total_length(0),
total_area(0),
weight (weight),
prevent_unselection (prevent_unselection)
{
labels.reserve(num_faces(fg));
std::size_t nb_selected = 0;
for (fg_face_descriptor fd : faces(fg))
{
if (get(is_selected_map,fd))
{
labels.push_back(1);
++ nb_selected;
}
else
labels.push_back(0);
}
// Compute normalization factors
for (fg_edge_descriptor ed : edges(fg))
total_length += length (ed);
for (fg_face_descriptor fd : faces(fg))
total_area += area (fd);
}
double length (fg_edge_descriptor ed) const
{
fg_vertex_descriptor esource = source(ed, fg);
fg_vertex_descriptor etarget = target(ed, fg);
return approximate_sqrt (typename GeomTraits::Compute_squared_distance_3()
(get (vertex_point_map, esource),
get (vertex_point_map, etarget)));
}
double area (fg_face_descriptor fd) const
{
fg_halfedge_descriptor hd = halfedge (fd, fg);
fg_halfedge_descriptor nhd = next (hd, fg);
return approximate_sqrt (typename GeomTraits::Compute_squared_area_3()
(get (vertex_point_map, source (hd, fg)),
get (vertex_point_map, target (hd, fg)),
get (vertex_point_map, target (nhd, fg))));
}
friend CGAL::Iterator_range<vertex_iterator>
vertices (const Regularization_graph& graph)
{
return faces (graph.fg);
}
friend std::size_t num_vertices (const Regularization_graph& graph) { return num_faces(graph.fg); }
friend CGAL::Iterator_range<edge_iterator>
edges (const Regularization_graph& graph)
{
return CGAL::make_range (boost::make_filter_iterator
(Filter_border_edges(graph.fg),
begin(edges(graph.fg)), end(edges(graph.fg))),
boost::make_filter_iterator
(Filter_border_edges(graph.fg),
end(edges(graph.fg)), end(edges(graph.fg))));
}
friend vertex_descriptor source (edge_descriptor ed, const Regularization_graph& graph)
{
return face (halfedge (ed, graph.fg), graph.fg);
}
friend vertex_descriptor target (edge_descriptor ed, const Regularization_graph& graph)
{
return face (opposite(halfedge (ed, graph.fg), graph.fg), graph.fg);
}
Vertex_label_map vertex_label_map() { return Vertex_label_map(this); }
Vertex_label_probability_map vertex_label_probability_map() const
{ return Vertex_label_probability_map(this); }
Edge_cost_map edge_cost_map() const
{ return Edge_cost_map(this); }
};
} //end of namespace internal
/*!
\ingroup PkgBGLSelectionFct
Augments a selection with faces of `fg` that are adjacent
augments a selection with faces of `fg` that are adjacent
to a face in `selection`. This process is applied `k` times considering
all faces added in the previous steps.
Two faces are said to be adjacent if they share a vertex or an edge.
@ -131,7 +356,7 @@ expand_face_selection(
/*!
\ingroup PkgBGLSelectionFct
Diminishes a selection of faces from faces adjacent to a non-selected face.
diminishes a selection of faces from faces adjacent to a non-selected face.
This process is applied `k` times considering all faces removed in the previous steps.
Two faces are said to be adjacent if they share a vertex or an edge.
Each face removed from the selection is added exactly once in `out`.
@ -203,6 +428,283 @@ reduce_face_selection(
return out;
}
/*!
\ingroup PkgBGLSelectionFct
regularizes a selection in order to minimize the length of the
border of the selection.
The alpha expansion algorithm is used (see
`CGAL::alpha_expansion_graphcut()`) using the length of the edge
between two faces as the edge cost and the initial
selected/unselected property of a face as the face cost.
If `prevent_unselection` is set to `true`, the cost of unselecting a
face is set to infinity, which forces the regularization to only
select new faces and ensures that the regularization keeps all
selected faces.
\tparam TriangleMesh a model of `FaceGraph`
\tparam IsSelectedMap a model of `ReadWritePropertyMap` with
`boost::graph_traits<TriangleMesh>::%face_descriptor` as key type and
`bool` as value type
\tparam NamedParameters a sequence of named parameters
\param mesh the mesh containing the selected faces.
\param is_selected indicates if a face is part of the selection. It
is updated by the function to accommodate faces added or removed
from the selection.
\param weight sets the tradeoff between data fidelity and
regularity, ranging from 0 (no regularization at all, selection is
left unaltered) to 1 (maximum regularization, usually selects or
unselects everything so that the length of the border of the
selection is 0)
\param np an optional sequence of \ref bgl_namedparameters "Named Parameters" among the ones listed below
\cgalNamedParamsBegin
\cgalParamNBegin{vertex_point_map}
\cgalParamDescription{a property map associating points to the vertices of `tm`}
\cgalParamType{a class model of `ReadWritePropertyMap` with `boost::graph_traits<TriangleMesh>::%vertex_descriptor`
as key type and `%Point_3` as value type}
\cgalParamDefault{`boost::get(CGAL::vertex_point, tm)`}
\cgalParamExtra{If this parameter is omitted, an internal property map for `CGAL::vertex_point_t`
must be available in `TriangleMesh`.}
\cgalParamNEnd
\cgalParamNBegin{face_index_map}
\cgalParamDescription{a property map associating to each face of `tm` a unique index between `0` and `num_faces(tm) - 1`}
\cgalParamType{a class model of `ReadablePropertyMap` with `boost::graph_traits<TriangleMesh>::%face_descriptor`
as key type and `std::size_t` as value type}
\cgalParamDefault{an automatically indexed internal map}
\cgalParamNEnd
\cgalParamNBegin{prevent_unselection}
\cgalParamDescription{Boolean used to indicate if selection can be only extended or if it can also be shrinked.}
\cgalParamType{`bool`}
\cgalParamDefault{`false`}
\cgalParamExtra{The geometric traits class must be compatible with the vertex point type.}
\cgalParamNEnd
\cgalParamNBegin{geom_traits}
\cgalParamDescription{an instance of a geometric traits class}
\cgalParamType{a class model of `Kernel`}
\cgalParamDefault{a \cgal Kernel deduced from the point type, using `CGAL::Kernel_traits`}
\cgalParamExtra{The geometric traits class must be compatible with the vertex point type.}
\cgalParamNEnd
\cgalNamedParamsEnd
*/
template <typename TriangleMesh, typename IsSelectedMap, typename NamedParameters>
void
regularize_face_selection_borders(
TriangleMesh& mesh,
IsSelectedMap is_selected,
double weight,
const NamedParameters& np)
{
using parameters::choose_parameter;
using parameters::get_parameter;
CGAL_precondition (0.0 <= weight && weight < 1.0);
typedef boost::graph_traits<TriangleMesh> GT;
typedef typename GT::face_descriptor mesh_face_descriptor;
typedef typename GetInitializedFaceIndexMap<TriangleMesh, NamedParameters>::type FaceIndexMap;
FaceIndexMap face_index_map = CGAL::get_initialized_face_index_map(mesh, np);
typedef typename GetVertexPointMap<TriangleMesh, NamedParameters>::const_type VertexPointMap;
VertexPointMap vertex_point_map
= choose_parameter(get_parameter(np, internal_np::vertex_point),
get_const_property_map(vertex_point, mesh));
typedef typename GetGeomTraits<TriangleMesh, NamedParameters>::type Kernel;
bool prevent_unselection = choose_parameter(get_parameter(np, internal_np::prevent_unselection),
false);
internal::Regularization_graph<Kernel, TriangleMesh, IsSelectedMap, FaceIndexMap,
VertexPointMap>
graph (mesh, is_selected,
face_index_map,
vertex_point_map,
weight,
prevent_unselection);
alpha_expansion_graphcut (graph,
graph.edge_cost_map(),
graph.vertex_label_probability_map(),
graph.vertex_label_map(),
CGAL::parameters::vertex_index_map
(face_index_map));
for (mesh_face_descriptor fd : faces(mesh))
put(is_selected, fd, graph.labels[get(face_index_map,fd)]);
}
/// \cond SKIP_IN_MANUAL
// variant with default np
template <typename TriangleMesh, typename IsSelectedMap>
void
regularize_face_selection_borders(
TriangleMesh& fg,
IsSelectedMap is_selected,
double weight)
{
regularize_face_selection_borders (fg, is_selected, weight,
CGAL::parameters::all_default());
}
/// \endcond
/// \cond SKIP_IN_MANUAL
// TODO: improve and document if useful
//
// Variant of regularization without graphcut but with brut-force
// local expansions. Can be interesting in some cases but too
// experimental/messy so far to be officially integrated.
template <class FaceGraph, class IsSelectedMap, class VertexPointMap>
void
regularize_face_selection_borders(
FaceGraph& fg,
IsSelectedMap is_selected,
VertexPointMap vertex_point_map)
{
typedef boost::graph_traits<FaceGraph> GT;
typedef typename GT::face_descriptor fg_face_descriptor;
typedef typename GT::halfedge_descriptor fg_halfedge_descriptor;
typedef typename GT::edge_descriptor fg_edge_descriptor;
typedef typename GT::vertex_descriptor fg_vertex_descriptor;
// TODO: this is a quick and dirty version, the complexity is
// crazy and it should be easy to do better (with priority queues,
// for example)
auto border_length =
[&]() -> double
{
double out = 0.;
for(fg_edge_descriptor ed : edges(fg))
{
fg_face_descriptor f0 = face (halfedge (ed, fg), fg);
fg_face_descriptor f1 = face (opposite(halfedge (ed, fg), fg), fg);
if (get(is_selected,f0) == get(is_selected,f1))
continue;
fg_vertex_descriptor esource = source(ed, fg);
fg_vertex_descriptor etarget = target(ed, fg);
out += std::sqrt(CGAL::squared_distance (get (vertex_point_map, esource),
get (vertex_point_map, etarget)));
}
return out;
};
// First: try edges
while (true)
{
fg_edge_descriptor chosen;
double length_before = border_length();
double shortest_length = length_before;
for (fg_edge_descriptor ed : edges(fg))
{
fg_face_descriptor selected = face (halfedge (ed, fg), fg);
fg_face_descriptor unselected = face (opposite(halfedge (ed, fg), fg), fg);
if (get(is_selected,selected) == get(is_selected,unselected))
continue;
if (get(is_selected, unselected))
std::swap (selected, unselected);
put(is_selected, unselected, true);
double length_after = border_length();
if (length_after < shortest_length)
{
chosen = ed;
shortest_length = length_after;
}
// Cancel
put(is_selected, unselected, false);
}
if (shortest_length == length_before)
break;
fg_face_descriptor selected = face (halfedge (chosen, fg), fg);
fg_face_descriptor unselected = face (opposite(halfedge (chosen, fg), fg), fg);
if (get(is_selected,selected) == get(is_selected,unselected))
continue;
if (get(is_selected, unselected))
std::swap (selected, unselected);
put(is_selected, unselected, true);
}
// Second: try 1-ring of vertices
while (true)
{
fg_vertex_descriptor chosen;
double length_before = border_length();
double shortest_length = length_before;
for (fg_vertex_descriptor vd : vertices(fg))
{
fg_halfedge_descriptor hd = halfedge(vd, fg);
bool adjacent_to_selected = false, adjacent_to_nonselected = false;
for (fg_face_descriptor fd : faces_around_target (hd, fg))
{
if (get(is_selected, fd))
adjacent_to_selected = true;
else
adjacent_to_nonselected = true;
if (adjacent_to_selected && adjacent_to_nonselected)
break;
}
if (!(adjacent_to_selected && adjacent_to_nonselected))
continue;
std::vector<fg_face_descriptor> newly_selected;
for (fg_face_descriptor fd : faces_around_target (hd, fg))
{
if (!get(is_selected, fd))
{
newly_selected.push_back (fd);
put(is_selected, fd, true);
}
}
double length_after = border_length();
if (length_after < shortest_length)
{
chosen = vd;
shortest_length = length_after;
}
// Cancel
for (fg_face_descriptor fd : newly_selected)
put(is_selected, fd, false);
}
if (shortest_length == length_before)
break;
fg_halfedge_descriptor hd = halfedge (chosen, fg);
for (fg_face_descriptor fd : faces_around_target (hd, fg))
put(is_selected, fd, true);
}
}
/// \endcond
/*!
\ingroup PkgBGLSelectionFct
@ -247,7 +749,7 @@ select_incident_faces(
/*!
\ingroup PkgBGLSelectionFct
Augments a selection with edges of `fg` that are adjacent
augments a selection with edges of `fg` that are adjacent
to an edge in `selection`. This process is applied `k` times considering
all edges added in the previous steps.
Two edges are said to be adjacent if they are incident to the same face or vertex.
@ -314,7 +816,7 @@ expand_edge_selection(
/*!
\ingroup PkgBGLSelectionFct
Diminishes a selection of edges from edges adjacent to a non-selected edge.
diminishes a selection of edges from edges adjacent to a non-selected edge.
This process is applied `k` times considering all edges removed in the previous steps.
Two edges are said to be adjacent if they are incident to the same face or vertex.
Each edge removed from the selection is added exactly once in `out`.
@ -400,7 +902,7 @@ reduce_edge_selection(
/*!
\ingroup PkgBGLSelectionFct
Augments a selection with vertices of `fg` that are adjacent
augments a selection with vertices of `fg` that are adjacent
to a vertex in `selection`. This process is applied `k` times considering
all vertices added in the previous steps.
Two vertices are said to be adjacent if they are part of the same face.
@ -455,7 +957,7 @@ expand_vertex_selection(
/*!
\ingroup PkgBGLSelectionFct
Diminishes a selection of vertices from vertices adjacent to a non-selected vertex.
diminishes a selection of vertices from vertices adjacent to a non-selected vertex.
This process is applied `k` times considering all vertices removed in the previous steps.
Two vertices are said to be adjacent if they are part of the same face.
Each vertex removed from the selection is added exactly once in `out`.
@ -652,4 +1154,3 @@ bool is_selection_a_topological_disk(const FaceRange& face_selection,
} //end of namespace CGAL
#endif //CGAL_BOOST_GRAPH_SELECTION_H

View File

@ -131,7 +131,7 @@ public:
}
}; // end class Less_on_G_copy_vertex_descriptors
// Splits a graph at vertices with degree higher than two and at vertices where `is_terminal` returns `true`
// splits a graph at vertices with degree higher than two and at vertices where `is_terminal` returns `true`
// The vertices are duplicated, and new incident edges created.
// `OrigGraph` must be undirected
template <typename Graph,
@ -192,6 +192,7 @@ void duplicate_terminal_vertices(Graph& graph,
} // namespace internal
#ifndef DOXYGEN_RUNNING
template <typename Graph,
typename Visitor,
typename IsTerminal,
@ -201,6 +202,7 @@ split_graph_into_polylines(const Graph& graph,
Visitor& polyline_visitor,
IsTerminal is_terminal,
LessForVertexDescriptors less);
#endif
/*!
\ingroup PkgBGLRef

View File

@ -71,6 +71,8 @@ create_single_source_cgal_program( "graph_concept_Linear_cell_complex.cpp" )
create_single_source_cgal_program( "graph_concept_Arrangement_2.cpp" )
create_single_source_cgal_program( "graph_concept_Derived.cpp" )
create_single_source_cgal_program( "test_clear.cpp" )
create_single_source_cgal_program( "test_helpers.cpp" )
@ -87,6 +89,8 @@ create_single_source_cgal_program( "graph_concept_Face_filtered_graph.cpp" )
create_single_source_cgal_program( "test_Manifold_face_removal.cpp")
create_single_source_cgal_program( "test_Regularize_face_selection_borders.cpp")
create_single_source_cgal_program( "test_Face_filtered_graph.cpp" )
create_single_source_cgal_program( "test_Euler_operations.cpp" )
@ -99,6 +103,10 @@ create_single_source_cgal_program( "test_Properties.cpp" )
create_single_source_cgal_program( "test_wrl.cpp" )
create_single_source_cgal_program( "bench_read_from_stream_vs_add_face_and_add_faces.cpp" )
create_single_source_cgal_program( "graph_traits_inheritance.cpp" )
if(OpenMesh_FOUND)
target_link_libraries( test_clear PRIVATE ${OPENMESH_LIBRARIES})
target_link_libraries( test_Euler_operations PRIVATE ${OPENMESH_LIBRARIES})

View File

@ -0,0 +1,94 @@
#include <CGAL/Simple_cartesian.h>
#include <CGAL/Surface_mesh.h>
#include <iostream>
#include <fstream>
#include <CGAL/IO/OFF_reader.h>
#include <CGAL/boost/graph/Euler_operations.h>
#include <CGAL/Real_timer.h>
typedef CGAL::Simple_cartesian<double> Kernel;
typedef CGAL::Surface_mesh<Kernel::Point_3> Mesh;
void convert_to_vertex_triples(
const std::vector<std::array<std::size_t, 3> >& faces_ids,
std::vector<std::array<Mesh::Vertex_index, 3> >& triangles)
{
triangles.reserve(faces_ids.size());
for (const std::array<std::size_t, 3>& a : faces_ids)
triangles.push_back(
CGAL::make_array( Mesh::Vertex_index(static_cast<Mesh::size_type>(a[0])),
Mesh::Vertex_index(static_cast<Mesh::size_type>(a[1])),
Mesh::Vertex_index(static_cast<Mesh::size_type>(a[2])) ) );
}
int main(int argc, char** argv)
{
{
std::cout << "Reading from stream\n";
Mesh m;
CGAL::Real_timer timer;
timer.start();
std::ifstream in((argc>1) ? argv[1] : "data/genus3.off");
in >> m;
timer.stop();
std::cout << " is_valid? " << CGAL::is_valid_polygon_mesh(m) << "\n";
std::cout << "Total time: " << timer.time() << std::endl << std::endl;
}
////////////////////////////////
{
std::cout << "Reading from soup + iterative add_face\n";
Mesh m;
CGAL::Real_timer timer;
timer.start();
std::ifstream in((argc>1) ? argv[1] : "data/blobby.off");
std::vector<Kernel::Point_3> points;
std::vector<std::array<std::size_t, 3> > faces_ids;
std::vector<std::array<Mesh::Vertex_index, 3> > triangles;
CGAL::read_OFF(in, points, faces_ids);
convert_to_vertex_triples(faces_ids, triangles);
std::cout << " Read soup: " << timer.time() << std::endl;
m.reserve(static_cast<Mesh::size_type>(points.size()),
static_cast<Mesh::size_type>(3*triangles.size()/2),
static_cast<Mesh::size_type>(triangles.size()));
for (const Kernel::Point_3& pt : points)
m.add_vertex(pt);
CGAL::Real_timer subtimer;
subtimer.start();
for (const std::array<Mesh::Vertex_index, 3>& t : triangles)
CGAL::Euler::add_face(t, m);
subtimer.stop();
timer.stop();
std::cout << " is_valid? " << CGAL::is_valid_polygon_mesh(m) << "\n";
std::cout << " time for iterative add_face: " << subtimer.time() << std::endl;
std::cout << "Total time: " << timer.time() << std::endl << std::endl;
}
////////////////////////////////
{
std::cout << "Reading from soup + add_faces\n";
Mesh m;
CGAL::Real_timer timer;
timer.start();
std::ifstream in((argc>1) ? argv[1] : "data/blobby.off");
std::vector<Kernel::Point_3> points;
std::vector<std::array<std::size_t, 3> > faces_ids;
std::vector<std::array<Mesh::Vertex_index, 3> > triangles;
CGAL::read_OFF(in, points, faces_ids);
convert_to_vertex_triples(faces_ids, triangles);
std::cout << " Read soup: " << timer.time() << std::endl;
m.reserve(static_cast<Mesh::size_type>(points.size()),
static_cast<Mesh::size_type>(3*triangles.size()/2),
static_cast<Mesh::size_type>(triangles.size()));
for (const Kernel::Point_3& pt : points)
m.add_vertex(pt);
CGAL::Real_timer subtimer;
subtimer.start();
CGAL::Euler::add_faces(triangles, m);
subtimer.stop();
timer.stop();
std::cout << " is_valid? " << CGAL::is_valid_polygon_mesh(m) << "\n";
std::cout << " time for add_faces: " << subtimer.time() << std::endl;
std::cout << "Total time: " << timer.time() << std::endl;
}
return 0;
}

View File

@ -0,0 +1,112 @@
#include <CGAL/Simple_cartesian.h>
#include <CGAL/Polyhedron_3.h>
#include <CGAL/Polyhedron_items_with_id_3.h>
#include <CGAL/Surface_mesh.h>
#include <CGAL/boost/graph/graph_traits_Linear_cell_complex_for_combinatorial_map.h>
#include <boost/graph/graph_concepts.hpp>
#include <CGAL/boost/graph/graph_concepts.h>
typedef CGAL::Simple_cartesian<double> Kernel;
typedef Kernel::Point_3 Point_3;
template <typename Traits>
struct My_mesh_1 : public CGAL::Polyhedron_3<Traits, CGAL::Polyhedron_items_with_id_3> {};
struct My_mesh_2 : public CGAL::Polyhedron_3<Kernel, CGAL::Polyhedron_items_with_id_3> {};
template <typename PT>
struct My_mesh_3 : public CGAL::Surface_mesh<PT> {};
struct My_mesh_5 : public CGAL::Surface_mesh<Kernel::Point_3> {};
// dim could be hard-coded but for the purpose of the example it is left
template <int dim, typename K>
struct My_mesh_4 :
CGAL::Linear_cell_complex_for_bgl_combinatorial_map_helper
<2, dim, CGAL::Linear_cell_complex_traits<dim, K> >::type
{};
/// make My_mesh_1 a valid face graph model
#define CGAL_GRAPH_TRAITS_INHERITANCE_TEMPLATE_PARAMS typename Traits
#define CGAL_GRAPH_TRAITS_INHERITANCE_CLASS_NAME My_mesh_1<Traits>
#define CGAL_GRAPH_TRAITS_INHERITANCE_BASE_CLASS_NAME CGAL::Polyhedron_3<Traits, CGAL::Polyhedron_items_with_id_3>
#include <CGAL/boost/graph/graph_traits_inheritance_macros.h>
/// make My_mesh_2 a valid face graph model
// no template parameter, CGAL_GRAPH_TRAITS_INHERITANCE_TEMPLATE_PARAMS is then not defined
#define CGAL_GRAPH_TRAITS_INHERITANCE_CLASS_NAME My_mesh_2
#define CGAL_GRAPH_TRAITS_INHERITANCE_BASE_CLASS_NAME CGAL::Polyhedron_3<Kernel, CGAL::Polyhedron_items_with_id_3>
#include <CGAL/boost/graph/graph_traits_inheritance_macros.h>
/// make My_mesh_3 a valid face graph model
#define CGAL_GRAPH_TRAITS_INHERITANCE_TEMPLATE_PARAMS typename PT
#define CGAL_GRAPH_TRAITS_INHERITANCE_CLASS_NAME My_mesh_3<PT>
#define CGAL_GRAPH_TRAITS_INHERITANCE_BASE_CLASS_NAME CGAL::Surface_mesh<PT>
#include <CGAL/boost/graph/graph_traits_inheritance_macros.h>
/// make My_mesh_4 a valid face graph model
#define CGAL_GRAPH_TRAITS_INHERITANCE_TEMPLATE_PARAMS int dim, typename K
#define CGAL_GRAPH_TRAITS_INHERITANCE_CLASS_NAME My_mesh_4<dim, K>
#define CGAL_GRAPH_TRAITS_INHERITANCE_BASE_CLASS_NAME typename CGAL::Linear_cell_complex_for_bgl_combinatorial_map_helper\
<2, dim, CGAL::Linear_cell_complex_traits<dim, K> >::type
#include <CGAL/boost/graph/graph_traits_inheritance_macros.h>
/// make My_mesh_5 a valid face graph model
// no template parameter, CGAL_GRAPH_TRAITS_INHERITANCE_TEMPLATE_PARAMS is then not defined
#define CGAL_GRAPH_TRAITS_INHERITANCE_CLASS_NAME My_mesh_5
#define CGAL_GRAPH_TRAITS_INHERITANCE_BASE_CLASS_NAME CGAL::Surface_mesh<Kernel::Point_3>
#include <CGAL/boost/graph/graph_traits_inheritance_macros.h>
template <class Graph>
void concept_check()
{
typedef boost::graph_traits< Graph > Traits;
typedef typename Traits::edge_descriptor edge_descriptor;
typedef typename Traits::halfedge_descriptor halfedge_descriptor;
typedef typename Traits::vertex_descriptor vertex_descriptor;
typedef typename Traits::face_descriptor face_descriptor;
boost::function_requires< boost::GraphConcept<Graph> >();
boost::function_requires< boost::VertexListGraphConcept<Graph> >();
boost::function_requires< boost::EdgeListGraphConcept<Graph> >();
boost::function_requires< boost::IncidenceGraphConcept<Graph> >();
boost::function_requires< boost::AdjacencyMatrixConcept<Graph> >();
boost::function_requires< boost::BidirectionalGraphConcept<Graph> >();
boost::function_requires< CGAL::HalfedgeGraphConcept<Graph> >();
boost::function_requires< CGAL::HalfedgeListGraphConcept<Graph> >();
boost::function_requires< CGAL::FaceGraphConcept<Graph> >();
boost::function_requires< CGAL::FaceListGraphConcept<Graph> >();
boost::function_requires< CGAL::MutableHalfedgeGraphConcept<Graph> >();
boost::function_requires< CGAL::MutableFaceGraphConcept<Graph> >();
boost::function_requires< boost::concepts::ReadablePropertyGraph<
Graph, halfedge_descriptor, CGAL::halfedge_index_t> >();
boost::function_requires< boost::concepts::ReadablePropertyGraph<
Graph, edge_descriptor, boost::edge_index_t> >();
boost::function_requires< boost::concepts::ReadablePropertyGraph<
Graph, edge_descriptor, boost::edge_weight_t> >();
boost::function_requires< boost::concepts::PropertyGraph<
Graph, vertex_descriptor, CGAL::vertex_point_t> >();
boost::function_requires< boost::concepts::ReadablePropertyGraph<
Graph, vertex_descriptor, boost::vertex_index_t> >();
boost::function_requires< boost::concepts::ReadablePropertyGraph<
Graph, face_descriptor, CGAL::face_index_t> >();
// null
boost::graph_traits<Graph>::null_vertex();
boost::graph_traits<Graph>::null_halfedge();
boost::graph_traits<Graph>::null_face();
}
int main()
{
concept_check<My_mesh_1<Kernel>>();
concept_check<My_mesh_2>();
concept_check<My_mesh_3<Point_3> >();
concept_check<My_mesh_4<3,Kernel>>();
concept_check<My_mesh_5>();
return 0;
}

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