mirror of https://github.com/CGAL/cgal
Merge pull request #4715 from afabri/BGL-test_face-GF
BGL: Add a function to check if add_face() can be called successfully
This commit is contained in:
commit
4e0fc267af
|
|
@ -13,6 +13,8 @@
|
||||||
#define CGAL_EULER_OPERATIONS_H
|
#define CGAL_EULER_OPERATIONS_H
|
||||||
|
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
|
#include <algorithm>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
#include <boost/graph/graph_traits.hpp>
|
#include <boost/graph/graph_traits.hpp>
|
||||||
#include <CGAL/boost/graph/properties.h>
|
#include <CGAL/boost/graph/properties.h>
|
||||||
|
|
@ -558,6 +560,127 @@ add_edge(typename boost::graph_traits<Graph>::vertex_descriptor s,
|
||||||
return e;
|
return e;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* checks whether a new face defined by a range of vertices (identified by their descriptors,
|
||||||
|
* `boost::graph_traits<Graph>::%vertex_descriptor`) can be added.
|
||||||
|
*/
|
||||||
|
template <typename VertexRange,typename PMesh>
|
||||||
|
bool can_add_face(const VertexRange& vrange, const PMesh& sm)
|
||||||
|
{
|
||||||
|
typedef typename boost::graph_traits<PMesh>::vertex_descriptor vertex_descriptor;
|
||||||
|
typedef typename boost::graph_traits<PMesh>::halfedge_descriptor halfedge_descriptor;
|
||||||
|
|
||||||
|
std::vector<typename boost::graph_traits<PMesh>::vertex_descriptor> face(vrange.begin(), vrange.end());
|
||||||
|
|
||||||
|
std::size_t N = face.size();
|
||||||
|
std::vector<vertex_descriptor> f2(face);
|
||||||
|
std::sort(f2.begin(), f2.end());
|
||||||
|
|
||||||
|
typename std::vector<vertex_descriptor>::iterator it = std::unique(f2.begin(),f2.end());
|
||||||
|
|
||||||
|
if((N > 0) && (it != f2.end())){
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(N < 3){
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
face.push_back(face.front());
|
||||||
|
|
||||||
|
for(std::size_t i=0; i < N; ++i){
|
||||||
|
halfedge_descriptor hd;
|
||||||
|
bool found;
|
||||||
|
boost::tie(hd,found) = halfedge(face[i],face[i+1],sm);
|
||||||
|
if(found && (! is_border(hd,sm))){
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for(std::size_t i=0; i < N; ++i){
|
||||||
|
if(halfedge(face[i],sm) == boost::graph_traits<PMesh>::null_halfedge()){
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(! is_border(face[i],sm)){
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//Test if all halfedges of the new face
|
||||||
|
//are possibly consecutive border halfedges in the HDS.
|
||||||
|
//Possibly because it may be not directly encoded in the HDS
|
||||||
|
//(using next() function ). This situation can occur when one or
|
||||||
|
//more facets share only a vertex: For example, the new facet we try to add
|
||||||
|
//would make the vertex indices[i] a manifold but this should be forbidden
|
||||||
|
//if a facet only incident to that vertex has already been inserted.
|
||||||
|
//We check this for each vertex of the sequence.
|
||||||
|
for(std::size_t i = 0; i < N; ++i) {
|
||||||
|
std::size_t prev_index= (i-1+N)%N;
|
||||||
|
std::size_t next_index= (i+1)%N;
|
||||||
|
vertex_descriptor previous_vertex = face[ prev_index ];
|
||||||
|
vertex_descriptor next_vertex = face[ next_index ];
|
||||||
|
|
||||||
|
halfedge_descriptor halfedge_around_vertex = halfedge(face[i],sm);
|
||||||
|
|
||||||
|
if ( halfedge_around_vertex == boost::graph_traits<PMesh>::null_halfedge() ||
|
||||||
|
halfedge(previous_vertex,sm) == boost::graph_traits<PMesh>::null_halfedge()||
|
||||||
|
halfedge(next_vertex,sm) == boost::graph_traits<PMesh>::null_halfedge()
|
||||||
|
) continue;
|
||||||
|
|
||||||
|
halfedge_descriptor start=halfedge_around_vertex;
|
||||||
|
//halfedges pointing to/running out from vertex indices[i]
|
||||||
|
//and that need to be possibly consecutive
|
||||||
|
halfedge_descriptor prev_hd= boost::graph_traits<PMesh>::null_halfedge(),next_hd= boost::graph_traits<PMesh>::null_halfedge();
|
||||||
|
|
||||||
|
halfedge_around_vertex = opposite(next(halfedge_around_vertex,sm),sm);
|
||||||
|
//look for a halfedge incident to vertex indices[i]
|
||||||
|
//and which opposite is incident to previous_vertex
|
||||||
|
do{
|
||||||
|
if(target(opposite(halfedge_around_vertex,sm),sm)==previous_vertex){
|
||||||
|
prev_hd=halfedge_around_vertex;
|
||||||
|
CGAL_precondition(is_border(prev_hd,sm));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
halfedge_around_vertex = opposite(next(halfedge_around_vertex,sm),sm);
|
||||||
|
}
|
||||||
|
while (halfedge_around_vertex!=start);
|
||||||
|
|
||||||
|
if (prev_hd != boost::graph_traits<PMesh>::null_halfedge()){
|
||||||
|
halfedge_around_vertex = opposite(next(halfedge_around_vertex,sm),sm);
|
||||||
|
//prev_hd and next are already consecutive in the HDS
|
||||||
|
if (target(opposite(halfedge_around_vertex,sm),sm)==next_vertex) continue;
|
||||||
|
|
||||||
|
//look for a border halfedge which opposite is
|
||||||
|
//incident to next_vertex: set next halfedge
|
||||||
|
do
|
||||||
|
{
|
||||||
|
if (target(opposite(halfedge_around_vertex,sm),sm)==next_vertex){
|
||||||
|
next_hd = opposite(halfedge_around_vertex,sm);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
halfedge_around_vertex = opposite(next(halfedge_around_vertex,sm),sm);
|
||||||
|
}
|
||||||
|
while(halfedge_around_vertex != prev_hd);
|
||||||
|
if (next_hd==boost::graph_traits<PMesh>::null_halfedge()) continue;
|
||||||
|
|
||||||
|
//check if no constraint prevents
|
||||||
|
//prev_hd and next_hd to be adjacent:
|
||||||
|
do{
|
||||||
|
halfedge_around_vertex = opposite(next(halfedge_around_vertex, sm),sm);
|
||||||
|
if ( is_border(opposite(halfedge_around_vertex,sm),sm) ) break;
|
||||||
|
}
|
||||||
|
while (halfedge_around_vertex != prev_hd);
|
||||||
|
if (halfedge_around_vertex == prev_hd) return false;
|
||||||
|
start = halfedge_around_vertex;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* adds a new face defined by a range of vertices (identified by their descriptors,
|
* adds a new face defined by a range of vertices (identified by their descriptors,
|
||||||
* `boost::graph_traits<Graph>::%vertex_descriptor`).
|
* `boost::graph_traits<Graph>::%vertex_descriptor`).
|
||||||
|
|
|
||||||
|
|
@ -95,6 +95,8 @@ create_single_source_cgal_program( "test_Face_filtered_graph.cpp" )
|
||||||
|
|
||||||
create_single_source_cgal_program( "test_Euler_operations.cpp" )
|
create_single_source_cgal_program( "test_Euler_operations.cpp" )
|
||||||
|
|
||||||
|
create_single_source_cgal_program( "test_test_face.cpp" )
|
||||||
|
|
||||||
create_single_source_cgal_program( "test_Collapse_edge.cpp" )
|
create_single_source_cgal_program( "test_Collapse_edge.cpp" )
|
||||||
|
|
||||||
create_single_source_cgal_program( "test_graph_traits.cpp" )
|
create_single_source_cgal_program( "test_graph_traits.cpp" )
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,60 @@
|
||||||
|
#include <CGAL/Surface_mesh.h>
|
||||||
|
#include <CGAL/Simple_cartesian.h>
|
||||||
|
#include <CGAL/boost/graph/Euler_operations.h>
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
typedef CGAL::Simple_cartesian<double> K;
|
||||||
|
typedef K::Point_3 Point_3;
|
||||||
|
typedef CGAL::Surface_mesh<Point_3> SM;
|
||||||
|
|
||||||
|
typedef boost::graph_traits<SM>::vertex_descriptor vertex_descriptor;
|
||||||
|
typedef boost::graph_traits<SM>::vertex_iterator vertex_iterator;
|
||||||
|
typedef std::vector<vertex_descriptor> V;
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
{
|
||||||
|
SM sm;
|
||||||
|
|
||||||
|
vertex_descriptor vp = CGAL::add_vertex(sm);
|
||||||
|
vertex_descriptor vq = CGAL::add_vertex(sm);
|
||||||
|
vertex_descriptor vr = CGAL::add_vertex(sm);
|
||||||
|
vertex_descriptor vs = CGAL::add_vertex(sm);
|
||||||
|
std::array<vertex_descriptor,0> face0;
|
||||||
|
assert( ! CGAL::Euler::can_add_face(face0,sm) );
|
||||||
|
std::array<vertex_descriptor,1> face1;
|
||||||
|
assert( ! CGAL::Euler::can_add_face(face1,sm) );
|
||||||
|
std::array<vertex_descriptor,2> face2;
|
||||||
|
assert( ! CGAL::Euler::can_add_face(face2,sm) );
|
||||||
|
|
||||||
|
std::array<vertex_descriptor,3> face = { vp, vq, vr };
|
||||||
|
CGAL::Euler::add_face(face, sm);
|
||||||
|
|
||||||
|
assert( ! CGAL::Euler::can_add_face(face,sm) );
|
||||||
|
std::swap(face[0],face[1]);
|
||||||
|
assert( CGAL::Euler::can_add_face(face,sm) );
|
||||||
|
|
||||||
|
face[2] = vs;
|
||||||
|
assert( CGAL::Euler::can_add_face(face,sm) );
|
||||||
|
std::swap(face[0],face[1]);
|
||||||
|
assert( ! CGAL::Euler::can_add_face(face,sm) );
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
SM sm;
|
||||||
|
Point_3 p(0,0,0), q(1,0,0), r(0,1,0), s(0,0,1);
|
||||||
|
CGAL::make_tetrahedron(p, q, r, s, sm);
|
||||||
|
std::array<vertex_descriptor,3> face;
|
||||||
|
vertex_iterator it = vertices(sm).first;
|
||||||
|
face[0] = *it;
|
||||||
|
++it;
|
||||||
|
face[1] = *it;
|
||||||
|
face[2] = CGAL::add_vertex(sm);
|
||||||
|
assert( ! CGAL::Euler::can_add_face(face,sm) );
|
||||||
|
std::swap(face[0],face[1]);
|
||||||
|
assert( ! CGAL::Euler::can_add_face(face,sm) );
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
@ -9,6 +9,7 @@ Release date: December 2020
|
||||||
|
|
||||||
- Added the convenience header `CGAL/boost/graph/graph_traits_inheritance_macros.h` that allows to easily
|
- Added the convenience header `CGAL/boost/graph/graph_traits_inheritance_macros.h` that allows to easily
|
||||||
make any class inheriting from a model of a face graph concept, a model of the same concept.
|
make any class inheriting from a model of a face graph concept, a model of the same concept.
|
||||||
|
- Added the function `can_add_face()`, which tests whether a new face defined by a range of vertices can be added.
|
||||||
|
|
||||||
### [3D Convex Hulls](https://doc.cgal.org/5.2/Manual/packages.html#PkgConvexHull3)
|
### [3D Convex Hulls](https://doc.cgal.org/5.2/Manual/packages.html#PkgConvexHull3)
|
||||||
- Added the function `CGAL::halfspace_intersection_interior_point_3()` that can be used to retrieve
|
- Added the function `CGAL::halfspace_intersection_interior_point_3()` that can be used to retrieve
|
||||||
|
|
@ -27,7 +28,7 @@ Release date: December 2020
|
||||||
to the make-x-monotone functions are fixed to use the new return type.
|
to the make-x-monotone functions are fixed to use the new return type.
|
||||||
- Changed `decompose()` interface to use `boost::variant` instead of legacy
|
- Changed `decompose()` interface to use `boost::variant` instead of legacy
|
||||||
[`CGAL::Object`](https://doc.cgal.org/5.1/STL_Extension/classCGAL_1_1Object.html)
|
[`CGAL::Object`](https://doc.cgal.org/5.1/STL_Extension/classCGAL_1_1Object.html)
|
||||||
As exaplained above, the code is backward compatible. However, it is recommended
|
As explained above, the code is backward compatible. However, it is recommended
|
||||||
that all calls to `decompose()` are fixed to use the new interface.
|
that all calls to `decompose()` are fixed to use the new interface.
|
||||||
|
|
||||||
### [Polygon Mesh Processing](https://doc.cgal.org/5.2/Manual/packages.html#PkgPolygonMeshProcessing)
|
### [Polygon Mesh Processing](https://doc.cgal.org/5.2/Manual/packages.html#PkgPolygonMeshProcessing)
|
||||||
|
|
|
||||||
|
|
@ -9,11 +9,9 @@
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-Commercial
|
// SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-Commercial
|
||||||
//
|
//
|
||||||
|
|
||||||
|
|
||||||
#ifndef CGAL_SURFACE_MESH_H
|
#ifndef CGAL_SURFACE_MESH_H
|
||||||
#define CGAL_SURFACE_MESH_H
|
#define CGAL_SURFACE_MESH_H
|
||||||
|
|
||||||
|
|
||||||
#include <CGAL/license/Surface_mesh.h>
|
#include <CGAL/license/Surface_mesh.h>
|
||||||
|
|
||||||
#include <CGAL/disable_warnings.h>
|
#include <CGAL/disable_warnings.h>
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue