Merge branch 'local/Polygon_mesh_processing-extract_cc' into Polyhedra_corefinement-enhancements-sloriot

Conflicts:
	Operations_on_polyhedra/include/CGAL/intersection_of_Polyhedra_3_refinement_visitor.h
	Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/Connected_components.h
This commit is contained in:
Sébastien Loriot 2015-02-03 09:22:23 +01:00
commit c4064b3b0f
32 changed files with 1129 additions and 543 deletions

View File

@ -22,11 +22,11 @@ LC_CTYPE=en_US.UTF-8
0 21 * * Sun cd $HOME/CGAL/create_internal_release && $HOME/bin/create_release $HOME/CGAL/branches/master.git --public --do-it
#0 21 * * Mon,Tue,Wed,Thu,Fri,Sun cd $HOME/CGAL/create_internal_release && $HOME/bin/create_release $HOME/CGAL/branches/master.git --public --do-it
# "integration"
0 21 * * Mon,Wed,Thu,Fri cd $HOME/CGAL/create_internal_release && $HOME/bin/create_release $HOME/CGAL/branches/integration.git $HOME/CGAL/branches/empty-dir --do-it
0 21 * * Mon,Tue,Wed,Thu,Fri cd $HOME/CGAL/create_internal_release && $HOME/bin/create_release $HOME/CGAL/branches/integration.git $HOME/CGAL/branches/empty-dir --do-it
# "integration-4.5"
0 21 * * Tue cd $HOME/CGAL/create_internal_release-4.5-branch && $HOME/bin/create_release $HOME/CGAL/branches/integration-4.5.git $HOME/CGAL/branches/empty-dir --do-it --public
0 21 * * Sat cd $HOME/CGAL/create_internal_release-4.5-branch && $HOME/bin/create_release $HOME/CGAL/branches/integration-4.5.git $HOME/CGAL/branches/empty-dir --do-it --public
# from branch 4.5
0 21 * * Sat cd $HOME/CGAL/create_internal_release-4.5-branch && $HOME/bin/create_release $HOME/CGAL/branches/CGAL-4.5-branch.git --public --do-it
#0 21 * * Sat cd $HOME/CGAL/create_internal_release-4.5-branch && $HOME/bin/create_release $HOME/CGAL/branches/CGAL-4.5-branch.git --public --do-it
# from branch 4.4
#0 21 * * Sun cd $HOME/CGAL/create_internal_release-4.4-branch && $HOME/bin/create_release $HOME/CGAL/branches/CGAL-4.4-branch.git --public --do-it

View File

@ -690,7 +690,7 @@ protected:
}
const int NUM_WORK_ITEMS_PER_BATCH;
const size_t NUM_WORK_ITEMS_PER_BATCH;
int m_num_cells_per_axis;
int m_num_cells;

View File

@ -25,7 +25,7 @@
#include <CGAL/Exact_predicates_exact_constructions_kernel.h>
#include <CGAL/Constrained_Delaunay_triangulation_2.h>
#include <CGAL/Triangulation_vertex_base_with_info_2.h>
#include <CGAL/internal/corefinement/Polyhedron_subset_extraction.h>
#include <CGAL/Polygon_mesh_processing/Connected_components.h>
#include <CGAL/internal/corefinement/utils.h>
#include <CGAL/property_map.h>

View File

@ -14,269 +14,392 @@
//
// $URL$
// $Id$
//
//
// Author(s) : Laurent Rineau and Ilker O. Yaz
//
// Author(s) : Laurent Rineau and Sebastien Loriot
#ifndef CGAL_ORIENT_POLYGON_SOUP
#define CGAL_ORIENT_POLYGON_SOUP
#include <CGAL/IO/generic_print_polyhedron.h>
#include <CGAL/Polyhedron_incremental_builder_3.h>
#include <CGAL/Modifier_base.h>
#include <boost/foreach.hpp>
#include <set>
#include <map>
#include <stack>
#include <algorithm>
#include <iostream>
#include <boost/array.hpp>
namespace CGAL {
namespace internal {
template<class Point_3>
template<class Point_3, class Polygon_3>
class Polygon_soup_orienter
{
typedef std::vector<std::size_t> Polygon_3;
typedef std::vector<Point_3> Points;
typedef std::map<std::pair<std::size_t, std::size_t>, std::set<std::size_t> > Edges_map;
typedef boost::array<std::size_t, 2> Edge;
typedef std::vector<Polygon_3> Polygons;
typedef std::set<Edge> Edges;
typedef Polygons::size_type size_type;
/// Index types
typedef typename std::iterator_traits<
typename Polygon_3::iterator >::value_type V_ID;
typedef typename std::vector<Polygon_3>::size_type P_ID;
// typedef int CC_ID;
typedef std::pair<V_ID, V_ID> V_ID_pair;
/// Container types
typedef std::vector<Point_3> Points;
typedef std::vector<Polygon_3> Polygons;
typedef std::map<V_ID_pair, std::set<P_ID> > Edge_map;
typedef typename Edge_map::iterator Edge_map_iterator;
typedef std::set<V_ID_pair> Marked_edges;
const Points& points;
Polygons& polygons;
/// Data members
Points& points; //< the set of input points
Polygons& polygons; //< the set of input polygons
Edge_map edges; //< the set of edges of the input polygons
Marked_edges marked_edges; //< the set of singular edges or edges incident
//< to non-compatible orientation polygons
Edges_map edges;
Edges non_manifold_edges;
/// for each polygon referenced by its position in `polygons`, indicates
/// the connected component it belongs too after orientation.
// std::vector< CC_ID > polygon_cc_id;
/// for each vertex, indicates the list of polygon containing it
std::vector< std::vector<P_ID> > incident_polygons_per_vertex;
public:
Polygon_soup_orienter(const Points& points, Polygons& polygons)
: points(points), polygons(polygons)
/// Utility functions
V_ID_pair canonical_edge(V_ID i, V_ID j)
{
fill_edges();
return i<j ? V_ID_pair(i,j):V_ID_pair(j,i);
}
private:
void fill_edges() {
// Fill edges
edges.clear();
for(size_type i = 0; i < polygons.size(); ++i)
{
const size_type size = polygons[i].size();
for(size_type j = 0; j < size; ++j) {
const std::size_t& i0 = polygons[i][j];
const std::size_t& i1 = polygons[i][ j+1 < size ? j+1: 0];
edges[std::make_pair(i0, i1)].insert(i);
}
}
bool is_edge_marked(V_ID i, V_ID j)
{
return marked_edges.count(canonical_edge(i,j));
}
// Fill non-manifold edges
non_manifold_edges.clear();
for(size_type i = 0; i < polygons.size(); ++i)
{
const size_type size = polygons[i].size();
for(size_type j = 0; j < size; ++j) {
const std::size_t& i0 = polygons[i][j];
const std::size_t& i1 = polygons[i][ j+1 < size ? j+1: 0];
if( (i0 < i1) &&
(edges[std::make_pair(i0, i1)].size() +
edges[std::make_pair(i1, i0)].size() > 2) )
{
Edge edge;
edge[0] = i0;
edge[1] = i1;
if(i0 > i1) std::swap(edge[0], edge[1]);
non_manifold_edges.insert(edge);
}
}
}
void set_edge_marked(V_ID i, V_ID j)
{
marked_edges.insert(canonical_edge(i,j));
}
cpp11::array<V_ID,3>
get_neighbor_vertices(V_ID v_id, P_ID polygon_index)
{
std::size_t nbv = polygons[polygon_index].size(), pvid=0;
for (; pvid!=nbv; ++pvid)
if (v_id==polygons[polygon_index][pvid]) break;
CGAL_assertion( pvid!=nbv );
V_ID prev = polygons[polygon_index][ (pvid+nbv-1)%nbv ];
V_ID next = polygons[polygon_index][ (pvid+1)%nbv ];
return make_array(prev,v_id,next);
}
std::pair<V_ID,P_ID>
next_cw_vertex_around_source(V_ID src, V_ID tgt)
{
typedef std::pair<V_ID,P_ID> VID_and_PID;
if ( is_edge_marked(src,tgt) ) return VID_and_PID(src,300612);
Edge_map_iterator em_it=edges.find(V_ID_pair(tgt, src));
if ( em_it==edges.end() ) return VID_and_PID(src,300612);// the vertex is on the border
CGAL_assertion(em_it->second.size()==1);
P_ID p_id = *(em_it->second.begin());
return VID_and_PID(get_neighbor_vertices(src, p_id)[2], p_id);
}
std::pair<V_ID,P_ID>
next_ccw_vertex_around_target(V_ID src, V_ID tgt)
{
typedef std::pair<V_ID,P_ID> VID_and_PID;
if ( is_edge_marked(src,tgt) ) return VID_and_PID(tgt,300612);
Edge_map_iterator em_it=edges.find(V_ID_pair(tgt, src));
if ( em_it==edges.end() ) return VID_and_PID(tgt,300612);// the vertex is on the border
CGAL_assertion(em_it->second.size()==1);
P_ID p_id = *(em_it->second.begin());
return VID_and_PID(get_neighbor_vertices(tgt, p_id)[0], p_id);
}
void inverse_orientation(const std::size_t index) {
std::reverse(polygons[index].begin(), polygons[index].end());
}
void replace_vertex_index_in_polygon(
std::size_t polygon_id,
V_ID old_index,
V_ID new_index)
{
BOOST_FOREACH(V_ID& i, polygons[polygon_id])
if( i==old_index )
i=new_index;
}
/// Functions filling containers
void fill_edge_map() {
// Fill edges
edges.clear();
for(P_ID i = 0; i < polygons.size(); ++i)
{
const P_ID size = polygons[i].size();
for(P_ID j = 0; j < size; ++j) {
V_ID i0 = polygons[i][j];
V_ID i1 = polygons[i][ (j+1)%size];
edges[V_ID_pair(i0, i1)].insert(i);
}
}
// Fill non-manifold edges
marked_edges.clear();
for(P_ID i = 0; i < polygons.size(); ++i)
{
const P_ID size = polygons[i].size();
for(P_ID j = 0; j < size; ++j) {
V_ID i0 = polygons[i][j];
V_ID i1 = polygons[i][ (j+1)%size ];
std::size_t nb_edges = 0;
Edge_map_iterator em_it = edges.find( V_ID_pair(i0, i1) );
if ( em_it!=edges.end() ) nb_edges += em_it->second.size();
em_it = edges.find( V_ID_pair(i1, i0) );
if ( em_it!=edges.end() ) nb_edges += em_it->second.size();
if( nb_edges > 2 ) set_edge_marked(i0,i1);
}
}
}
void fill_incident_polygons_per_vertex()
{
incident_polygons_per_vertex.resize(points.size());
P_ID nb_polygons=polygons.size();
for(P_ID ip=0; ip<nb_polygons; ++ip)
{
BOOST_FOREACH(V_ID iv, polygons[ip])
incident_polygons_per_vertex[iv].push_back(ip);
}
}
public:
bool orient()
Polygon_soup_orienter(Points& points, Polygons& polygons)
: points(points), polygons(polygons)
{
fill_edge_map();
}
/// We try to orient polygon consistently by walking in the dual graph, from
/// a not yet re-oriented polygon.
/// We have an edge between two polygons if they share an edge, and this edge
/// is shared by exactly two polygons. While walking along an edge, we reorient
/// the polygon we walked in if its orientation is not compatible with the one
/// we come from.
/// If the polygon was already marked as oriented, then we cut the dual edge
/// in the graph and the primal edge is marked.
/// At the same time, we assign an id to each polygon in the same connected
/// componenet of the dual graph.
void orient()
{
std::vector<bool> oriented;
std::stack<std::size_t> stack;
using std::make_pair;
// polygon_cc_id.resize(polygons.size(), -1);
// no polygon is oriented
// We first consider all polygons as non-oriented
oriented.resize(polygons.size());
size_type polygon_index = 0;
bool success = true;
P_ID polygon_index = 0;
while (polygon_index != polygons.size())
// CC_ID current_cc_index=-1;
while (polygon_index != polygons.size())
{
// We look for the first polygon not already oriented
while ( polygon_index != polygons.size() && oriented[polygon_index] ) {
++polygon_index;
}
if(polygon_index == polygons.size()) break;
// ++ current_cc_index; // visit a new connected component
// we visit the connected component by crossing edges manifold edges
oriented[polygon_index] = true;
stack.push(polygon_index);
while(! stack.empty() )
{
const size_type to_be_oriented_index = stack.top();
const P_ID to_be_oriented_index = stack.top();
stack.pop();
const size_type size = polygons[to_be_oriented_index].size();
for(size_type ih = 0 ; ih < size ; ++ih) {
size_type ihp1 = ih+1;
if(ihp1>=size) ihp1 = 0;
const std::size_t& i1 = polygons[to_be_oriented_index][ih];
const std::size_t& i2 = polygons[to_be_oriented_index][ihp1];
Edge edge;
edge[0] = i1;
edge[1] = i2;
if(i1 > i2) std::swap(edge[0], edge[1]);
// CGAL_assertion(polygon_cc_id[to_be_oriented_index]==-1);
// polygon_cc_id[to_be_oriented_index]=current_cc_index;
if(non_manifold_edges.count(edge) > 0) {
continue;
}
const P_ID size = polygons[to_be_oriented_index].size();
for(P_ID ih = 0 ; ih < size ; ++ih) {
P_ID ihp1 = (ih+1)%size;
const V_ID i1 = polygons[to_be_oriented_index][ih];
const V_ID i2 = polygons[to_be_oriented_index][ihp1];
if( is_edge_marked(i1,i2) ) continue;
// edge (i1,i2)
Edges_map::iterator it_same_orient = edges.find(make_pair(i1, i2));
Edge_map_iterator it_same_orient = edges.find(V_ID_pair(i1, i2));
// edges (i2,i1)
Edges_map::iterator it_other_orient = edges.find(make_pair(i2, i1));
Edge_map_iterator it_other_orient = edges.find(V_ID_pair(i2, i1));
CGAL_assertion(it_same_orient != edges.end());
if(it_same_orient->second.size() > 1) {
if((it_other_orient != edges.end() && it_other_orient->second.size() > 0) ||
it_same_orient->second.size() > 2) {
// three polygons at the edge
success = false; // non-orientable
}
{
// one neighbor polyhedron, opposite orientation
size_type index = *(it_same_orient->second.begin());
if(index == to_be_oriented_index)
index = *(++it_same_orient->second.begin());
if(oriented[index]) {
// "neighbor polygon #%1 is already oriented, but in opposite orientation").arg(index);
success = false; // non-orientable
continue; // next edge
}
CGAL_assertion(it_other_orient == edges.end() ||
it_other_orient->second.size()==1);
// reverse the orientation
const size_type size = polygons[index].size();
for(size_type j = 0; j < size; ++j) {
const std::size_t& i0 = polygons[index][j];
const std::size_t& i1 = polygons[index][ j+1 < size ? j+1: 0];
CGAL_assertion_code(const bool r = )
edges[std::make_pair(i0, i1)].erase(index)
CGAL_assertion_code(!= 0);
CGAL_assertion(r);
}
inverse_orientation(index);
for(size_type j = 0; j < size; ++j) {
const std::size_t& i0 = polygons[index][j];
const std::size_t& i1 = polygons[index][ j+1 < size ? j+1: 0];
edges[std::make_pair(i0, i1)].insert(index);
}
// "inverse the orientation of polygon #%1\n").arg(index);
if (it_same_orient->second.size() > 1)
{
CGAL_assertion(it_other_orient == edges.end());
// one neighbor but with the same orientation
P_ID index = *(it_same_orient->second.begin());
if(index == to_be_oriented_index)
index = *(++it_same_orient->second.begin());
if(oriented[index])
{
// polygon already oriented but its orientation is not compatible ---> mark the edge and continue
set_edge_marked(i1,i2);
continue; // next edge
}
// reverse the orientation
const P_ID size = polygons[index].size();
for(P_ID j = 0; j < size; ++j) {
V_ID i0 = polygons[index][j];
V_ID i1 = polygons[index][(j+1)%size];
Edge_map_iterator em_it = edges.find(V_ID_pair(i0, i1));
CGAL_assertion_code(const bool r = )
em_it->second.erase(index)
CGAL_assertion_code(!= 0);
CGAL_assertion(r);
if ( em_it->second.empty() ) edges.erase(em_it);
}
inverse_orientation(index);
for(P_ID j = 0; j < size; ++j) {
V_ID i0 = polygons[index][j];
V_ID i1 = polygons[index][(j+1)%size];
edges[V_ID_pair(i0, i1)].insert(index);
}
// "inverse the orientation of polygon #index
oriented[index] = true;
stack.push(index);
}
else{
if( it_other_orient != edges.end() ){
CGAL_assertion(it_same_orient->second.size() == 1);
CGAL_assertion(it_other_orient->second.size() == 1);
// one polygon, same orientation
const P_ID index = *(it_other_orient->second.begin());
if(oriented[index]) continue; //nothing todo already processed and correctly oriented
oriented[index] = true;
// "keep the orientation of polygon #index
stack.push(index);
}
}
else if(it_other_orient != edges.end() && it_other_orient->second.size() == 1) {
// one polygon, same orientation
const size_type index = *(it_other_orient->second.begin());
if(oriented[index])
continue;
oriented[index] = true;
// "keep the orientation of polygon #%1\n").arg(index);
stack.push(index);
}
else {
if(it_same_orient->second.size() != 1 ||
(it_other_orient != edges.end() && it_other_orient->second.size() > 0))
{
success = false; // non-orientable
}
}
} // end for on all edges of one
} // end for on all edges of one
} // end while loop on the polygons of the connected component
} // end while loop on all non-oriented polygons remaining
} // end while loop on all non-oriented polygons remaining
}
return success;
/// A vertex is said to be singular if its link is neither a cycle nor a chain,
/// but several cycles and chains.
/// For each such vertex v, we consider each set of polygons incident to v
/// and sharing a non-marked edge incident to v. A copy of v is assigned to
/// each but one set of incident polygons.
void duplicate_singular_vertices()
{
fill_incident_polygons_per_vertex();
std::vector< std::pair<V_ID, std::vector<P_ID> > > vertices_to_duplicate;
V_ID nbv = static_cast<V_ID>( points.size() );
for (V_ID v_id = 0; v_id < nbv; ++v_id)
{
const std::vector< P_ID >& incident_polygons = incident_polygons_per_vertex[v_id];
if ( incident_polygons.empty() ) continue; //isolated vertex
std::set<P_ID> visited_polygons;
bool first_pass = true;
BOOST_FOREACH(P_ID p_id, incident_polygons)
{
if ( !visited_polygons.insert(p_id).second ) continue; // already visited
if (!first_pass)
{
vertices_to_duplicate.push_back(std::pair<V_ID, std::vector<P_ID> >());
vertices_to_duplicate.back().first=v_id;
}
const cpp11::array<V_ID,3>& neighbors = get_neighbor_vertices(v_id,p_id);
V_ID next = neighbors[2];
if( !first_pass)
vertices_to_duplicate.back().second.push_back(p_id);
do{
P_ID other_p_id;
cpp11::tie(next, other_p_id) = next_cw_vertex_around_source(v_id, next);
if (next==v_id) break;
visited_polygons.insert(other_p_id);
if( !first_pass)
vertices_to_duplicate.back().second.push_back(other_p_id);
}
while(next!=neighbors[0]);
if (next==v_id){
/// turn the otherway round
next = neighbors[0];
do{
P_ID other_p_id;
cpp11::tie(next, other_p_id) = next_ccw_vertex_around_target(next, v_id);
if (next==v_id) break;
visited_polygons.insert(other_p_id);
if( !first_pass)
vertices_to_duplicate.back().second.push_back(other_p_id);
}
while(true);
}
first_pass=false;
}
}
/// now duplicate the vertices
typedef std::pair<V_ID, std::vector<P_ID> > V_ID_and_Polygon_ids;
BOOST_FOREACH(const V_ID_and_Polygon_ids& vid_and_pids, vertices_to_duplicate)
{
V_ID new_index = static_cast<V_ID>(points.size());
points.push_back( points[vid_and_pids.first] );
BOOST_FOREACH(P_ID polygon_id, vid_and_pids.second)
replace_vertex_index_in_polygon(polygon_id, vid_and_pids.first, new_index);
}
}
};
} // namespace internal
/**
* Tries to consistently orient a soup of polygons in 3D space.
* If a consistent orientation has been found, `true` is returned.
* In any case `polygons` is updated.
* @tparam Point_3 the point type
*
* @param points points of the soup of polygons.
* @param[in, out] polygons each element in the vector describes a polygon using the index of the points in the vector.
*
* @return true if a consistent orientation has been found
*
* \TODO code: there is no check for duplicate points, yet it can be implemented as separate filter function
* \TODO code: support fixed size arrays for polygons, or creating a concept which provides .size and .operator[]
*/
template <class Point_3>
bool orient_polygon_soup(const std::vector<Point_3>& points,
std::vector< std::vector<std::size_t> >& polygons)
{
internal::Polygon_soup_orienter<Point_3> orienter(points, polygons);
return orienter.orient();
}
/**
* Modifier to build a polyhedron from a soup of polygons.
*/
template <class HDS, class Point_3>
class Polygon_soup_to_polyhedron_3: public CGAL::Modifier_base<HDS>
* Tries to consistently orient a soup of polygons in 3D space.
* If it is not possible to produce a combinatorial manifold surface, some points will be
* duplicated. These points are either an endpoint of edges incident to more than
* two polygons, or an endpoint of an edge between two polygons with incompatible orientations
* (during the re-orientation process), or a point shared by at least two polygons that do not
* share an edge this point is incident to.
* @tparam Point_3 the point type
* @tparam Polygon_3 the Polygon type, being a container of indices
*
* @param[in,out] points points of the soup of polygons. Some points might be pushed back to resolve
* non-manifold or non-orientability issues.
* @param[in, out] polygons each element in the vector describes a polygon using the index of the points in `points`.
*
* @return return false if some points where duplicated, thus producing a self-intersecting polyhedron
*
*/
template <class Point_3, class Polygon_3>
bool orient_polygon_soup(std::vector<Point_3>& points,
std::vector< Polygon_3 >& polygons)
{
typedef std::vector<std::size_t> Polygon_3;
std::size_t inital_nb_pts = points.size();
internal::Polygon_soup_orienter<Point_3, Polygon_3> orienter(points, polygons);
orienter.orient();
orienter.duplicate_singular_vertices();
const std::vector<Point_3>& points;
const std::vector<std::vector<std::size_t> >& polygons;
public:
/**
* The constructor for modifier object.
* @param points points of the soup of polygons.
* @param polygons each element in the vector describes a polygon using the index of the points in the vector.
*/
Polygon_soup_to_polyhedron_3(const std::vector<Point_3>& points,
const std::vector<std::vector<std::size_t> >& polygons)
: points(points), polygons(polygons)
{ }
void operator()(HDS& out_hds)
{
Polyhedron_incremental_builder_3<HDS> builder(out_hds);
builder.begin_surface(points.size(), polygons.size());
for(std::size_t i = 0, end = points.size(); i < end; ++i)
{ builder.add_vertex(points[i]); }
for(std::size_t i = 0, end = polygons.size(); i < end; ++i)
{
const Polygon_3& polygon = polygons[i];
const std::size_t size = polygon.size();
builder.begin_facet();
for(std::size_t j = 0; j < size; ++j) {
builder.add_vertex_to_facet(polygon[j]);
}
builder.end_facet();
}
builder.end_surface();
}
};
return inital_nb_pts==points.size();
}
}// namespace CGAL

View File

@ -25,17 +25,22 @@
#include <algorithm>
#include <CGAL/internal/Operations_on_polyhedra/compute_normal.h>
namespace CGAL {
namespace internal {
namespace CGAL{
template<unsigned int axis>
struct Axis_compare {
template<class Vertex>
bool operator()(const Vertex& v0, const Vertex& v1) const
{ return v0.point()[axis] < v1.point()[axis]; }
};
namespace internal{
template <class Less_xyz>
struct Compare_vertex_points_xyz_3{
Less_xyz less;
} // namespace internal
typedef bool result_type;
template <class Vertex>
bool operator()(const Vertex& v1, const Vertex& v2) const
{
return less(v1.point(), v2.point());
}
};
} // end of namespace internal
/**
* Tests whether a closed polyhedron has a positive orientation.
@ -60,18 +65,23 @@ struct Axis_compare {
* @endcode
*/
template<class Polyhedron>
bool is_oriented(const Polyhedron& polyhedron) {
CGAL_precondition(polyhedron.is_closed());
const unsigned int axis = 0;
bool is_oriented(const Polyhedron& polyhedron)
{
typedef typename Polyhedron::Traits K;
internal::Compare_vertex_points_xyz_3< typename K::Less_xyz_3 > less_xyz;
typename Polyhedron::Vertex_const_iterator v_min
= std::min_element(polyhedron.vertices_begin(), polyhedron.vertices_end(), internal::Axis_compare<axis>());
= std::min_element(polyhedron.vertices_begin(), polyhedron.vertices_end(), less_xyz);
typedef typename Polyhedron::Traits K;
const typename K::Vector_3& normal_v_min = compute_vertex_normal<typename Polyhedron::Vertex, K>(*v_min);
CGAL_warning(normal_v_min[axis] != 0);
return normal_v_min[axis] < 0;
return normal_v_min[0] < 0 || (
normal_v_min[0] == 0 && (
normal_v_min[1] < 0 ||
( normal_v_min[1]==0 && normal_v_min[2] < 0 )
)
);
}
} // namespace CGAL
#endif // CGAL_ORIENT_POLYHEDRON_3

View File

@ -0,0 +1,92 @@
// Copyright (c) 2009-2013 GeometryFactory (France).
// All rights reserved.
//
// This file is part of CGAL (www.cgal.org).
// You can redistribute it and/or modify it under the terms of the GNU
// General Public License as published by the Free Software Foundation,
// either version 3 of the License, or (at your option) any later version.
//
// Licensees holding a valid commercial license may use this file in
// accordance with the commercial license agreement provided with the software.
//
// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
//
// $URL$
// $Id$
//
//
// Author(s) : Laurent Rineau and Sebastien Loriot
#ifndef CGAL_POLYGON_SOUP_TO_POLYHEDRON_3_H
#define CGAL_POLYGON_SOUP_TO_POLYHEDRON_3_H
#include <CGAL/IO/generic_print_polyhedron.h>
#include <CGAL/Polyhedron_incremental_builder_3.h>
#include <CGAL/Modifier_base.h>
namespace CGAL{
namespace internal{
/**
* Modifier to build a polyhedron from a soup of polygons.
*/
template <class HDS, class Point, class Polygon>
class Polygon_soup_to_polyhedron_3: public CGAL::Modifier_base<HDS>
{
const std::vector<Point>& points;
const std::vector<Polygon>& polygons;
typedef typename HDS::Vertex::Point Point_3;
public:
/**
* The constructor for modifier object.
* @param points points of the soup of polygons.
* @param polygons each element in the vector describes a polygon using the index of the points in the vector.
*/
Polygon_soup_to_polyhedron_3(
const std::vector<Point>& points,
const std::vector<Polygon>& polygons)
: points(points), polygons(polygons)
{ }
void operator()(HDS& out_hds)
{
Polyhedron_incremental_builder_3<HDS> builder(out_hds);
builder.begin_surface(points.size(), polygons.size());
for(std::size_t i = 0, end = points.size(); i < end; ++i)
builder.add_vertex( Point_3(points[i][0], points[i][1], points[i][2]) );
for(std::size_t i = 0, end = polygons.size(); i < end; ++i)
{
const Polygon& polygon = polygons[i];
const std::size_t size = polygon.size();
builder.begin_facet();
for(std::size_t j = 0; j < size; ++j)
builder.add_vertex_to_facet(polygon[j]);
builder.end_facet();
}
builder.end_surface();
}
};
} //namespace internal
/**
* Append a soup of polygons in a Polyhedron
*/
template <class Polyhedron, class Point, class Polygon>
void polygon_soup_to_polyhedron_3(Polyhedron& P,
const std::vector<Point>& points,
const std::vector<Polygon>& polygons)
{
internal::Polygon_soup_to_polyhedron_3< typename Polyhedron::HalfedgeDS,
Point, Polygon > modifier(points, polygons);
P.delegate(modifier);
}
} //end of namespace CGAL
#endif //CGAL_POLYGON_SOUP_TO_POLYHEDRON_3_H

View File

@ -0,0 +1,23 @@
OFF
8 13 0
-1 -1 -1
-1 1 -1
1 1 -1
1 -1 -1
-1 -1 1
-1 1 1
1 1 1
1 -1 1
3 0 1 3
3 3 1 2
3 0 4 1
3 1 4 5
3 3 2 7
3 7 2 6
3 4 0 3
3 7 4 3
3 6 4 7
3 6 5 4
3 1 5 6
3 2 1 6
3 0 1 2

View File

@ -0,0 +1,27 @@
OFF
14 9 0
0 0 0
1 0 0
1 1 0
0 1 0
2 1 0
0 2 0
1 2 0
2 2 0
0 0 0.5
0.8 0 0.5
1 1 1
2 1 1
2 2 1
1 2 1
4 0 1 2 3
4 2 4 7 6
4 3 2 6 5
4 2 4 11 10
4 6 7 12 13
4 10 11 12 13
4 0 1 9 8
3 13 10 8
3 8 9 13

View File

@ -0,0 +1,30 @@
OFF
9 12 0
0 0 0
1 0 0
0 1 0
1 1 0
0.5 0.5 0
0 0 1
1 0 1
1 1 1
0 1 1
3 1 3 4
3 0 1 4
3 4 3 2
3 0 4 2
3 5 6 4
3 6 7 4
3 4 7 8
3 5 4 8
4 0 1 6 5
4 0 2 8 5
4 3 2 8 7
4 1 3 7 6

View File

@ -0,0 +1,9 @@
OFF
5 2 0
0 0 0
0 1 0
1 0 0
0 0 1
0 1 1
3 0 1 2
3 0 3 4

View File

@ -0,0 +1,24 @@
OFF
9 13 0
0 1 0
1 0 0
1 2 0
0.5 1 1
0 1 2
1 0 2
1 2 2
1.5 1 0
1.5 1 0.5
3 0 1 2
3 0 1 3
3 1 2 3
3 0 2 3
3 3 5 4
3 3 5 6
3 3 6 4
3 4 6 5
3 1 2 5
3 1 2 7
3 1 2 8
3 2 5 8
3 1 8 5

View File

@ -0,0 +1,12 @@
OFF
6 4 0
0 0 0
0 1 0
1 0.5 0
0 0.5 1
0 0.5 -1
-1 0.5 0
3 0 1 2
3 0 1 3
3 0 1 4
3 0 1 5

View File

@ -0,0 +1,18 @@
OFF
10 6 0
0 0 0
0 1 0
1 0.5 0
0 0.5 1
0 0.5 -1
-1 0.5 0
-1 -1 0
1 -1 0
-1 -1 1
1 -1 1
3 0 1 2
3 0 1 3
3 0 1 4
3 0 1 5
3 0 6 7
3 0 8 9

View File

@ -0,0 +1,30 @@
OFF
16 8 0
0 0 0
1 0 0
2 0 0
0 1 0
1 1 0
2 1 0
0 2 0
1 2 0
2 2 0
1 1 -1
2 1 -1
3 1 -1
3 1 0
1 1 1
2 1 1
3 1 1
4 0 1 4 3
4 1 2 5 4
4 4 5 8 7
4 3 4 7 6
4 9 10 5 4
4 10 11 12 5
4 5 12 15 14
4 4 5 14 13

View File

@ -0,0 +1,54 @@
#include <CGAL/Polyhedron_3.h>
#include <CGAL/Simple_cartesian.h>
#include <CGAL/orient_polygon_soup.h>
#include <CGAL/polygon_soup_to_polyhedron_3.h>
#include <CGAL/IO/OFF_reader.h>
#include <string>
#include <fstream>
#include <iostream>
typedef CGAL::Simple_cartesian<double> K;
typedef CGAL::Polyhedron_3<K> Polyhedron;
void test(std::string fname, std::size_t expected_duplicated_vertices)
{
std::vector<K::Point_3> points;
std::vector< std::vector<std::size_t> > polygons;
std::ifstream input(fname.c_str());
if (!input)
{
std::cerr << "Cannot open file " << fname << "\n";
exit(EXIT_FAILURE);
}
if (!CGAL::read_OFF(input, points, polygons))
{
std::cerr << "Error parsing the OFF file " << fname << "\n";
exit(EXIT_FAILURE);
}
std::size_t initial_nb_points = points.size();
CGAL::orient_polygon_soup(points, polygons);
assert(expected_duplicated_vertices == points.size()-initial_nb_points);
Polyhedron P;
CGAL::polygon_soup_to_polyhedron_3(P, points, polygons);
assert(P.is_valid());
std::cout << fname << " OK\n";
}
int main()
{
test("data_polygon_soup/bad_cube.off", 4);
test("data_polygon_soup/isolated_singular_vertex_one_cc.off", 1);
test("data_polygon_soup/isolated_vertices.off", 1);
test("data_polygon_soup/nm_vertex_and_edge.off", 6);
test("data_polygon_soup/one_duplicated_edge.off", 6);
test("data_polygon_soup/one_duplicated_edge_sharing_vertex.off", 8);
test("data_polygon_soup/partial_overlap.off", 4);
test("data_polygon_soup/incompatible_orientation.off", 2);
}

View File

@ -29,6 +29,7 @@
namespace CGAL {
namespace internal{
namespace corefinement{
template <class Polyhedron>
struct Compare_handle_ptr{
@ -132,8 +133,6 @@ void extract_connected_components(
typedef ::CGAL::Union_find<Facet_handle> UF;
typedef typename UF::handle UF_handle;
typedef typename UF::iterator UF_iterator;
CGAL_precondition(P.is_pure_triangle());
//init union-find: each facet is in its own set
for (Facet_iterator it=P.facets_begin();it!=P.facets_end();++it){
@ -144,13 +143,18 @@ void extract_connected_components(
Facet_handle facet=it;
UF_handle current=map_f2h.find(it)->second;
Halfedge_handle neighbors[3];
neighbors[0]=facet->halfedge()->opposite();
neighbors[1]=facet->halfedge()->next()->opposite();
neighbors[2]=facet->halfedge()->next()->next()->opposite();
for (int i=0;i!=3;++i){
if ( neighbors[i]->is_border_edge() ) continue;
std::vector<Halfedge_handle> neighbors;
Halfedge_handle hedge=facet->halfedge();
do
{
neighbors.push_back( hedge->opposite() );
hedge=hedge->next();
}
while(hedge!=facet->halfedge());
std::size_t nb_edges=neighbors.size();
for (std::size_t i=0;i<nb_edges;++i){
if ( neighbors[i]->is_border() ) continue;
UF_handle neigh=map_f2h.find(neighbors[i]->facet())->second;
if ( adjacent(neighbors[i]) && !uf.same_set(current,neigh) ){
uf.unify_sets(current,neigh);
@ -320,6 +324,6 @@ mark_connected_components_v2(
return patch_id;
}
} } //namespace CGAL::internal
} } } //namespace CGAL::internal::corefinement
#endif //CGAL_INTERNAL_POLYHEDRON_SUBSET_EXTRACTION_H

View File

@ -0,0 +1 @@
GeometryFactory (France)

View File

@ -0,0 +1 @@
GPL (v3 or later)

View File

@ -0,0 +1 @@
Andreas Fabri <Andreas.Fabri@geometryfactory.com>

View File

@ -325,7 +325,7 @@ if(CGAL_Qt4_FOUND AND QT4_FOUND AND OPENGL_FOUND AND QGLVIEWER_FOUND)
target_link_libraries(gocad_plugin scene_polyhedron_item)
polyhedron_demo_plugin(stl_plugin Polyhedron_demo_stl_plugin)
target_link_libraries(stl_plugin scene_polyhedron_item)
target_link_libraries(stl_plugin scene_polyhedron_item scene_polygon_soup_item)
polyhedron_demo_plugin(xyz_plugin Polyhedron_demo_xyz_plugin)
target_link_libraries(xyz_plugin scene_points_with_normal_item)

View File

@ -11,7 +11,7 @@
#include "Polyhedron_demo_plugin_interface.h"
#include <CGAL/Polyhedron_copy_3.h>
#include <CGAL/internal/corefinement/Polyhedron_subset_extraction.h>
#include <CGAL/Polygon_mesh_processing/Connected_components.h>
#include <boost/foreach.hpp>
#include <boost/function_output_iterator.hpp>
@ -104,7 +104,7 @@ void Polyhedron_demo_join_and_split_polyhedra_plugin::on_actionSplitPolyhedra_tr
if(item)
{
std::list<Polyhedron*> new_polyhedra;
CGAL::internal::extract_connected_components(
CGAL::internal::corefinement::extract_connected_components(
*item->polyhedron(),
boost::make_function_output_iterator(Polyhedron_appender(new_polyhedra))
);

View File

@ -25,8 +25,7 @@ public:
bool applicable() const {
Q_FOREACH(Scene_interface::Item_id index, scene->selectionIndices()) {
if(qobject_cast<Scene_polygon_soup_item*>(scene->item(index))||
qobject_cast<Scene_polyhedron_item*>(scene->item(index)))
if(qobject_cast<Scene_polygon_soup_item*>(scene->item(index)))
return true;
}
return false;
@ -89,28 +88,27 @@ void Polyhedron_demo_orient_soup_plugin::orient()
// qDebug() << tr("I have the item %1\n").arg(item->name());
QApplication::setOverrideCursor(Qt::WaitCursor);
if(!item->orient()) {
messages->warning(tr("The polygon soup \"%1\" is not orientable.")
.arg(item->name()));
// QMessageBox::information(mw, tr("Not orientable"),
// tr("The polygon soup \"%1\" is not orientable.")
// .arg(item->name()));
scene->itemChanged(item);
} else {
Scene_polyhedron_item* poly_item = new Scene_polyhedron_item();
if(item->exportAsPolyhedron(poly_item->polyhedron())) {
poly_item->setName(item->name());
poly_item->setColor(item->color());
poly_item->setRenderingMode(item->renderingMode());
poly_item->setVisible(item->visible());
poly_item->changed();
poly_item->setProperty("source filename", item->property("source filename"));
scene->replaceItem(index, poly_item);
delete item;
} else {
scene->itemChanged(item);
}
QMessageBox::information(mw, tr("Not orientable without self-intersections"),
tr("The polygon soup \"%1\" is not directly orientable."
" Some vertices have been duplicated and some self-intersections"
" have been created.")
.arg(item->name()));
}
Scene_polyhedron_item* poly_item = new Scene_polyhedron_item();
if(item->exportAsPolyhedron(poly_item->polyhedron())) {
poly_item->setName(item->name());
poly_item->setColor(item->color());
poly_item->setRenderingMode(item->renderingMode());
poly_item->setVisible(item->visible());
poly_item->changed();
poly_item->setProperty("source filename", item->property("source filename"));
scene->replaceItem(index, poly_item);
delete item;
} else {
scene->itemChanged(item);
}
QApplication::restoreOverrideCursor();
}
else{

View File

@ -3,128 +3,14 @@
#include "Kernel_type.h"
#include "Polyhedron_type.h"
#include <CGAL/Modifier_base.h>
#include <CGAL/Polyhedron_incremental_builder_3.h>
#include "Polyhedron_demo_io_plugin_interface.h"
#include <fstream>
#include <boost/tuple/tuple.hpp>
#include <CGAL/IO/Polyhedron_builder_from_STL.h>
#include <CGAL/polygon_soup_to_polyhedron_3.h>
#include <QColor>
typedef Kernel::Point_3 Point_3;
typedef std::vector<Point_3> Points_3;
typedef boost::tuple<int,int,int> Facet;
typedef std::vector<Facet> Surface;
template <class HDS>
class Build_from_stl : public CGAL::Modifier_base<HDS> {
std::istream& is;
int counter;
Points_3 meshPoints;
Surface mesh;
public:
std::string name, color;
Build_from_stl(std::istream& is_)
: is(is_), counter(0)
{}
void operator()( HDS& hds) {
if(!read(is, meshPoints, mesh)) return;
CGAL::Polyhedron_incremental_builder_3<Polyhedron::HalfedgeDS> B(hds);
B.begin_surface( meshPoints.size(), mesh.size());
typedef typename Points_3::size_type size_type;
for(size_type i=0; i < meshPoints.size(); i++){
B.add_vertex( meshPoints[i]);
}
for(size_type i=0; i < mesh.size(); i++){
B.begin_facet();
B.add_vertex_to_facet( mesh[i].template get<0>());
B.add_vertex_to_facet( mesh[i].template get<1>());
B.add_vertex_to_facet( mesh[i].template get<2>());
B.end_facet();
}
if(B.error())
{
std::cerr << "An error occured while creating a Polyhedron" << std::endl;
B.rollback();
}
B.end_surface();
}
bool
read(std::istream& input, Points_3& points, Surface& surface, int /*offset*/ = 0)
{
std::string s, solid("solid"), facet("facet"), outer("outer"), loop("loop"), vertex("vertex"), endloop("endloop"), endsolid("endsolid");
std::map<Point_3, int> vertex_index;
int index = 0;
int ijk[3];
Point_3 p;
input >> s;
if(s == solid){
std::getline(input, s);
} else {
std::cerr << "We expect keyword 'solid'" << std::endl;
return false;
}
while(input >> s){
if(s == endsolid){
//std::cerr << "found endsolid" << std::endl;
} else if(s == facet){
//std::cerr << "found facet" << std::endl;
std::getline(input, s); // ignore the normal
input >> s;
if(s != outer){
std::cerr << "Expect 'outer' and got " << s << std::endl;
return false;
}
input >> s;
if(s != loop){
std::cerr << "Expect 'loop' and got " << s << std::endl;
return false;
}
int count = 0;
do {
input >> s;
if(s == vertex){
// std::cerr << "found vertex" << std::endl;
if(count < 3){
input >> p;
if(vertex_index.find(p) == vertex_index.end()){
ijk[count] = index;
vertex_index[p] = index++;
points.push_back(p);
} else {
ijk[count] = vertex_index[p];
}
++count;
} else {
std::cerr << "We can only read triangulated surfaces" << std::endl;
return false;
}
}
}while(s != endloop);
surface.push_back(boost::make_tuple(ijk[0], ijk[1], ijk[2]));
}
}
return true;
}
};
class Polyhedron_demo_stl_plugin :
public QObject,
public Polyhedron_demo_io_plugin_interface
@ -160,40 +46,34 @@ Polyhedron_demo_stl_plugin::load(QFileInfo fileinfo) {
std::cerr << "Error! Cannot open file " << (const char*)fileinfo.filePath().toUtf8() << std::endl;
return NULL;
}
std::vector<CGAL::cpp11::array<double, 3> > points;
std::vector<CGAL::cpp11::array<int, 3> > triangles;
if (!CGAL::read_STL(in, points, triangles))
{
std::cerr << "Error: invalid STL file" << std::endl;
return NULL;
}
try{
// Try building a polyhedron
Polyhedron P;
CGAL::polygon_soup_to_polyhedron_3(P, points, triangles);
// Try to read STL file in a polyhedron
Polyhedron P;
//Scene_polyhedron_item* item = new Scene_polyhedron_item(P);
//item->setName(fileinfo.baseName());
Build_from_stl<Polyhedron::HalfedgeDS> builder(in);
// item->polyhedron()->
P.delegate(builder);
if(! P.is_valid()){
std::cerr << "Error: Invalid polyhedron" << std::endl;
return 0;
}
if(P.empty()){
return 0;
}
Scene_polyhedron_item* item = new Scene_polyhedron_item(P);
if(builder.name.size() == 0){
item->setName(fileinfo.baseName());
} else {
item->setName(builder.name.c_str());
if(! P.is_valid() || P.empty()){
std::cerr << "Error: Invalid polyhedron" << std::endl;
}
else{
Scene_polyhedron_item* item = new Scene_polyhedron_item(P);
item->setName(fileinfo.baseName());
return item;
}
}
QColor color(builder.color.c_str());
if(color.isValid())
{
item->setColor(color);
item->changed();
}
catch(...){}
Scene_polygon_soup_item* item = new Scene_polygon_soup_item();
item->setName(fileinfo.baseName());
item->load(points, triangles);
return item;
}

View File

@ -1,7 +1,6 @@
#include "Scene_polygon_soup_item.h"
#include "Scene_polyhedron_item.h"
#include <CGAL/IO/Polyhedron_iostream.h>
#include "Polyhedron_type.h"
#include <CGAL/Polyhedron_incremental_builder_3.h>
#include <QObject>
@ -10,97 +9,19 @@
#include <set>
#include <stack>
#include <algorithm>
#include <boost/array.hpp>
#include <boost/foreach.hpp>
#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
#include <CGAL/IO/File_scanner_OFF.h>
#include <CGAL/IO/OFF_reader.h>
#include <CGAL/IO/File_writer_OFF.h>
#include <CGAL/version.h>
#include <CGAL/orient_polygon_soup.h>
#include <CGAL/polygon_soup_to_polyhedron_3.h>
#include <CGAL/orient_polyhedron_3.h>
typedef Kernel::Point_3 Point_3;
struct Polygon_soup
{
typedef std::vector<Point_3> Points;
typedef std::vector<std::size_t> Polygon_3;
typedef std::map<std::pair<std::size_t, std::size_t>, std::set<std::size_t> > Edges_map;
typedef boost::array<std::size_t, 2> Edge;
typedef std::vector<Polygon_3> Polygons;
typedef std::set<Edge> Edges;
typedef Polygons::size_type size_type;
Points points;
Polygons polygons;
Edges_map edges;
Edges non_manifold_edges;
bool display_non_manifold_edges;
Polygon_soup():
display_non_manifold_edges(false){}
Polygon_soup* clone() const {
Polygon_soup* result = new Polygon_soup();
result->points = points;
result->polygons = polygons;
result->edges = edges;
result->non_manifold_edges = non_manifold_edges;
result->display_non_manifold_edges = display_non_manifold_edges;
return result;
}
void clear() {
points.clear();
polygons.clear();
edges.clear();
non_manifold_edges.clear();
}
void fill_edges() {
// Fill edges
edges.clear();
for(size_type i = 0; i < polygons.size(); ++i)
{
const size_type size = polygons[i].size();
for(size_type j = 0; j < size; ++j) {
const std::size_t& i0 = polygons[i][j];
const std::size_t& i1 = polygons[i][ j+1 < size ? j+1: 0];
edges[std::make_pair(i0, i1)].insert(i);
// qDebug() << tr("edges[std::make_pair(%1, %2)].insert(%3). Size=%4")
// .arg(i0).arg(i1).arg(i).arg(edges[std::make_pair(i0, i1)].size());
}
}
// Fill non-manifold edges
non_manifold_edges.clear();
for(size_type i = 0; i < polygons.size(); ++i)
{
const size_type size = polygons[i].size();
for(size_type j = 0; j < size; ++j) {
const std::size_t& i0 = polygons[i][j];
const std::size_t& i1 = polygons[i][ j+1 < size ? j+1: 0];
if( (i0 < i1) &&
(edges[std::make_pair(i0, i1)].size() +
edges[std::make_pair(i1, i0)].size() > 2) )
{
Edge edge;
edge[0] = i0;
edge[1] = i1;
if(i0 > i1) std::swap(edge[0], edge[1]);
non_manifold_edges.insert(edge);
}
}
}
}
void inverse_orientation(const std::size_t index) {
std::reverse(polygons[index].begin(), polygons[index].end());
}
};
struct Polyhedron_to_polygon_soup_writer {
typedef Kernel::Point_3 Point_3;
Polygon_soup* soup;
Polygon_soup::Polygon_3 polygon;
@ -164,45 +85,9 @@ Scene_polygon_soup_item::clone() const {
bool
Scene_polygon_soup_item::load(std::istream& in)
{
#if CGAL_VERSION_NR >= 1030700091
typedef std::size_t indices_t;
#else
typedef boost::int32_t indices_t;
#endif
if(!soup)
soup = new Polygon_soup;
CGAL::File_scanner_OFF scanner(in);
soup->clear();
soup->points.resize(scanner.size_of_vertices());
soup->polygons.resize(scanner.size_of_facets());
for (indices_t i = 0; i < scanner.size_of_vertices(); ++i) {
double x, y, z, w;
scanner.scan_vertex( x, y, z, w);
soup->points[i] = Point_3(x, y, z, w);
scanner.skip_to_next_vertex( i);
}
if(!in)
return false;
for (indices_t i = 0; i < scanner.size_of_facets(); ++i) {
indices_t no;
scanner.scan_facet( no, i);
soup->polygons[i].resize(no);
for(indices_t j = 0; j < no; ++j) {
indices_t id;
scanner.scan_facet_vertex_index(id, i);
if(id < scanner.size_of_vertices())
{
soup->polygons[i][j] = id;
}
else
return false;
}
}
soup->fill_edges();
oriented = false;
return (bool) in;
if (!soup) soup=new Polygon_soup();
else soup->clear();
return CGAL::read_OFF(in, soup->points, soup->polygons);
}
void Scene_polygon_soup_item::init_polygon_soup(std::size_t nb_pts, std::size_t nb_polygons){
@ -270,11 +155,10 @@ void Scene_polygon_soup_item::inside_out()
bool
Scene_polygon_soup_item::orient()
{
if(isEmpty() || this->oriented)
if(isEmpty() || oriented)
return true; // nothing to do
oriented = CGAL::orient_polygon_soup(soup->points, soup->polygons);
return oriented;
oriented=true;
return CGAL::orient_polygon_soup(soup->points, soup->polygons);
}
@ -314,9 +198,7 @@ bool
Scene_polygon_soup_item::exportAsPolyhedron(Polyhedron* out_polyhedron)
{
orient();
CGAL::Polygon_soup_to_polyhedron_3<Polyhedron::HalfedgeDS, Point_3> builder(
soup->points, soup->polygons);
out_polyhedron->delegate(builder);
CGAL::polygon_soup_to_polyhedron_3(*out_polyhedron, soup->points, soup->polygons);
if(out_polyhedron->size_of_vertices() > 0) {
// Also check whether the consistent orientation is fine

View File

@ -3,16 +3,100 @@
#include "Scene_polygon_soup_item_config.h"
#include "Scene_item_with_display_list.h"
#include "Polyhedron_type.h"
#include <boost/foreach.hpp>
#include <boost/array.hpp>
#include <iostream>
#include "Polyhedron_type_fwd.h"
struct Polygon_soup;
struct Polygon_soup
{
typedef Kernel::Point_3 Point_3;
typedef std::vector<Point_3> Points;
typedef std::vector<std::size_t> Polygon_3;
typedef std::map<std::pair<std::size_t, std::size_t>, std::set<std::size_t> > Edges_map;
typedef boost::array<std::size_t, 2> Edge;
typedef std::vector<Polygon_3> Polygons;
typedef std::set<Edge> Edges;
typedef Polygons::size_type size_type;
Points points;
Polygons polygons;
Edges_map edges;
Edges non_manifold_edges;
bool display_non_manifold_edges;
Polygon_soup():
display_non_manifold_edges(false){}
Polygon_soup* clone() const {
Polygon_soup* result = new Polygon_soup();
result->points = points;
result->polygons = polygons;
result->edges = edges;
result->non_manifold_edges = non_manifold_edges;
result->display_non_manifold_edges = display_non_manifold_edges;
return result;
}
void clear() {
points.clear();
polygons.clear();
edges.clear();
non_manifold_edges.clear();
}
void fill_edges() {
// Fill edges
edges.clear();
for(size_type i = 0; i < polygons.size(); ++i)
{
const size_type size = polygons[i].size();
for(size_type j = 0; j < size; ++j) {
const std::size_t& i0 = polygons[i][j];
const std::size_t& i1 = polygons[i][ j+1 < size ? j+1: 0];
edges[std::make_pair(i0, i1)].insert(i);
// qDebug() << tr("edges[std::make_pair(%1, %2)].insert(%3). Size=%4")
// .arg(i0).arg(i1).arg(i).arg(edges[std::make_pair(i0, i1)].size());
}
}
// Fill non-manifold edges
non_manifold_edges.clear();
for(size_type i = 0; i < polygons.size(); ++i)
{
const size_type size = polygons[i].size();
for(size_type j = 0; j < size; ++j) {
const std::size_t& i0 = polygons[i][j];
const std::size_t& i1 = polygons[i][ j+1 < size ? j+1: 0];
if( (i0 < i1) &&
(edges[std::make_pair(i0, i1)].size() +
edges[std::make_pair(i1, i0)].size() > 2) )
{
Edge edge;
edge[0] = i0;
edge[1] = i1;
if(i0 > i1) std::swap(edge[0], edge[1]);
non_manifold_edges.insert(edge);
}
}
}
}
void inverse_orientation(const std::size_t index) {
std::reverse(polygons[index].begin(), polygons[index].end());
}
};
class Scene_polyhedron_item;
class SCENE_POLYGON_SOUP_ITEM_EXPORT Scene_polygon_soup_item
: public Scene_item_with_display_list
{
typedef Kernel::Point_3 Point_3;
Q_OBJECT
public:
Scene_polygon_soup_item();
@ -21,6 +105,30 @@ public:
Scene_polygon_soup_item* clone() const;
bool load(std::istream& in);
void load(Scene_polyhedron_item*);
template <class Point, class Polygon>
inline void load(const std::vector<Point>& points, const std::vector<Polygon>& polygons)
{
if(!soup)
soup = new Polygon_soup;
soup->clear();
/// add points
soup->points.reserve(points.size());
BOOST_FOREACH(const Point& p, points)
soup->points.push_back( Point_3(p[0], p[1], p[2]) );
/// add polygons
std::size_t nb_polygons=polygons.size();
soup->polygons.resize(nb_polygons);
for(std::size_t i=0; i<nb_polygons; ++i)
soup->polygons[i].assign(polygons[i].begin(), polygons[i].end());
/// fill non-manifold edges container
soup->fill_edges();
oriented = false;
}
bool save(std::ostream& out) const;
QString toolTip() const;

View File

@ -8,7 +8,7 @@
#include "Scene_polyhedron_item_decorator.h"
#include "Polyhedron_type.h"
#include <CGAL/gl_render.h>
#include <CGAL/orient_polygon_soup.h>
#include <CGAL/polygon_soup_to_polyhedron_3.h>
#include <fstream>
#include <boost/foreach.hpp>
@ -639,8 +639,7 @@ public:
polygons[counter].push_back(hb->vertex()->id() -1);
} while(++hb != hend);
}
CGAL::Polygon_soup_to_polyhedron_3<Polyhedron::HalfedgeDS, Polyhedron::Point_3> builder(points, polygons);
out->delegate(builder);
CGAL::polygon_soup_to_polyhedron_3(*out, points, polygons);
return out->size_of_vertices() > 0;
}

View File

@ -0,0 +1,71 @@
// Copyright (c) 2015 GeometryFactory
//
// This file is part of CGAL (www.cgal.org); you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public License as
// published by the Free Software Foundation; either version 3 of the License,
// or (at your option) any later version.
//
// Licensees holding a valid commercial license may use this file in
// accordance with the commercial license agreement provided with the software.
//
// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
//
// $URL$
// $Id$
//
// Author(s) : Laurent Rineau and Sebastien Loriot
#ifndef CGAL_IO_OFF_READER_H
#define CGAL_IO_OFF_READER_H
#include <CGAL/IO/File_scanner_OFF.h>
#include <vector>
#include <iostream>
namespace CGAL{
template <class Point_3, class Polygon_3>
bool
read_OFF( std::istream& in,
std::vector< Point_3 >& points,
std::vector< Polygon_3 >& polygons,
bool /* verbose */ = false)
{
CGAL::File_scanner_OFF scanner(in);
points.resize(scanner.size_of_vertices());
polygons.resize(scanner.size_of_facets());
for (std::size_t i = 0; i < scanner.size_of_vertices(); ++i) {
double x, y, z, w;
scanner.scan_vertex( x, y, z, w);
CGAL_assertion(w!=0);
points[i] = Point_3(x/w, y/w, z/w);
scanner.skip_to_next_vertex( i);
}
if(!in)
return false;
for (std::size_t i = 0; i < scanner.size_of_facets(); ++i) {
std::size_t no;
scanner.scan_facet( no, i);
polygons[i].resize(no);
for(std::size_t j = 0; j < no; ++j) {
std::size_t id;
scanner.scan_facet_vertex_index(id, i);
if(id < scanner.size_of_vertices())
{
polygons[i][j] = id;
}
else
return false;
}
}
return (bool) in;
}
} // namespace CGAL
#endif // CGAL_IO_OFF_READER_H

View File

@ -0,0 +1,79 @@
// Copyright (c) 2015 GeometryFactory
//
// This file is part of CGAL (www.cgal.org); you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public License as
// published by the Free Software Foundation; either version 3 of the License,
// or (at your option) any later version.
//
// Licensees holding a valid commercial license may use this file in
// accordance with the commercial license agreement provided with the software.
//
// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
//
// $URL$
// $Id$
//
// Author(s) : Andreas Fabri
#ifndef CGAL_IO_POLYHEDRON_STL_BUILDER_H
#define CGAL_IO_POLYHEDRON_STL_BUILDER_H
#include <CGAL/Modifier_base.h>
#include <CGAL/Polyhedron_incremental_builder_3.h>
#include <CGAL/IO/STL_reader.h>
#include <iostream>
namespace CGAL{
template <class HDS>
class Polyhedron_builder_from_STL : public CGAL::Modifier_base<HDS> {
typedef typename HDS::Vertex::Point Point_3;
typedef std::vector<cpp11::array<double, 3> > Points_3;
typedef cpp11::array<int,3> Facet;
typedef std::vector<Facet> Surface;
std::istream& is;
Points_3 meshPoints;
Surface mesh;
public:
Polyhedron_builder_from_STL(std::istream& is_)
: is(is_)
{}
void operator()( HDS& hds) {
if(!read_STL(is, meshPoints, mesh)) return;
CGAL::Polyhedron_incremental_builder_3<HDS> B(hds);
B.begin_surface( meshPoints.size(), mesh.size());
typedef typename Points_3::size_type size_type;
for(size_type i=0; i < meshPoints.size(); i++){
B.add_vertex(
Point_3(meshPoints[i][0], meshPoints[i][1], meshPoints[i][2])
);
}
for(size_type i=0; i < mesh.size(); i++){
B.begin_facet();
B.add_vertex_to_facet( mesh[i][0]);
B.add_vertex_to_facet( mesh[i][1]);
B.add_vertex_to_facet( mesh[i][2]);
B.end_facet();
}
if(B.error())
{
std::cerr << "An error occured while creating a Polyhedron" << std::endl;
B.rollback();
}
B.end_surface();
}
};
} //end of CGAL namespace
#endif // CGAL_IO_POLYHEDRON_STL_BUILDER_H

View File

@ -0,0 +1,110 @@
// Copyright (c) 2015 GeometryFactory
//
// This file is part of CGAL (www.cgal.org); you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public License as
// published by the Free Software Foundation; either version 3 of the License,
// or (at your option) any later version.
//
// Licensees holding a valid commercial license may use this file in
// accordance with the commercial license agreement provided with the software.
//
// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
//
// $URL$
// $Id$
//
// Author(s) : Andreas Fabri
#ifndef CGAL_IO_STL_READER_H
#define CGAL_IO_STL_READER_H
#include <CGAL/array.h>
#include <vector>
#include <map>
#include <iostream>
namespace CGAL{
bool
read_STL( std::istream& input,
std::vector< cpp11::array<double,3> >& points,
std::vector< cpp11::array<int,3> >& facets,
bool verbose = false)
{
std::string s,
solid("solid"),
facet("facet"),
outer("outer"),
loop("loop"),
vertex("vertex"),
endloop("endloop"),
endsolid("endsolid");
std::map<cpp11::array<double,3>, int> vertex_index;
int index = 0;
cpp11::array<int,3> ijk;
cpp11::array<double,3> p;
input >> s;
if(s == solid){
std::getline(input, s);
} else {
if (verbose)
std::cerr << "We expect keyword 'solid'" << std::endl;
return false;
}
while(input >> s){
if(s == endsolid){
//std::cerr << "found endsolid" << std::endl;
} else if(s == facet){
//std::cerr << "found facet" << std::endl;
std::getline(input, s); // ignore the normal
input >> s;
if(s != outer){
if (verbose)
std::cerr << "Expect 'outer' and got " << s << std::endl;
return false;
}
input >> s;
if(s != loop){
if (verbose)
std::cerr << "Expect 'loop' and got " << s << std::endl;
return false;
}
int count = 0;
do {
input >> s;
if(s == vertex){
// std::cerr << "found vertex" << std::endl;
if(count < 3){
input >> p[0] >> p[1] >> p[2];
std::map<cpp11::array<double,3>, int>::iterator iti=
vertex_index.insert(std::make_pair(p,-1)).first;
if(iti->second==-1){
ijk[count] = index;
iti->second = index++;
points.push_back(p);
} else {
ijk[count] = iti->second;
}
++count;
} else {
if (verbose)
std::cerr << "We can only read triangulated surfaces" << std::endl;
return false;
}
}
}while(s != endloop);
facets.push_back(ijk);
}
}
return true;
}
} // namespace CGAL
#endif // CGAL_IO_STL_READER_H

View File

@ -544,7 +544,7 @@ Cell_handle & c) const;
/// @}
/*! \name
There is a method `has_vertex` in the cell class. The analogous methods for facets are defined here.
There is a method `has_vertex()` in the cell class. The analogous methods for facets are defined here.
*/
/// @{
/*!
@ -784,7 +784,7 @@ Locate_type & lt, int & li) const;
Two kinds of flips exist for a three-dimensional triangulation. They
are reciprocal. To be flipped, an edge must be incident to three
tetrahedra. During the flip, these three tetrahedra disappear and two
tetrahedra appear. Figure \ref Triangulation3figflips (left) shows the
tetrahedra appear. \cgalFigureRef{Triangulation3figflips} (left) shows the
edge that is flipped as bold dashed, and one of its three incident
facets is shaded. On the right, the facet shared by the two new
tetrahedra is shaded. Flips are possible only under the following
@ -792,9 +792,9 @@ conditions: - the edge or facet to be flipped is not on the boundary
of the convex hull of the triangulation - the five points involved are
in convex position.
\anchor Triangulation3figflips
\image html flips.png "Flips"
\image latex flips.png "Flips"
\cgalFigureBegin{Triangulation3figflips, flips.png}
Flips
\cgalFigureEnd
The following methods guarantee the validity of the resulting 3D
triangulation. Flips for a 2d triangulation are not implemented yet.
@ -1027,7 +1027,7 @@ The following iterators allow the user to visit cells, facets, edges and vertice
/// @{
/*!
Starts at an arbitrary finite vertex. Then `++` and `-` will
Starts at an arbitrary finite vertex. Then `++` and `--` will
iterate over finite vertices. Returns `finite_vertices_end()` when
`t.number_of_vertices() == 0`.
*/
@ -1039,7 +1039,7 @@ Past-the-end iterator
Finite_vertices_iterator finite_vertices_end() const;
/*!
Starts at an arbitrary finite edge. Then `++` and `-` will
Starts at an arbitrary finite edge. Then `++` and `--` will
iterate over finite edges. Returns `finite_edges_end()` when
`t.dimension() < 1`.
*/
@ -1051,7 +1051,7 @@ Past-the-end iterator
Finite_edges_iterator finite_edges_end() const;
/*!
Starts at an arbitrary finite facet. Then `++` and `-` will
Starts at an arbitrary finite facet. Then `++` and `--` will
iterate over finite facets. Returns `finite_facets_end()` when
`t.dimension() < 2`.
*/
@ -1063,7 +1063,7 @@ Past-the-end iterator
Finite_facets_iterator finite_facets_end() const;
/*!
Starts at an arbitrary finite cell. Then `++` and `-` will
Starts at an arbitrary finite cell. Then `++` and `--` will
iterate over finite cells. Returns `finite_cells_end()` when
`t.dimension() < 3`.
*/
@ -1224,7 +1224,7 @@ Try to lock and copy the `Cell_handle`s of all cells incident to `v` into
`cells`.
Returns `true` in case of success. Otherwise, `cells` is emptied and the function
returns false. In any case, the locked cells are not unlocked by
`try_lock_and_get_incident_cells`, leaving this choice to the user.
`try_lock_and_get_incident_cells()`, leaving this choice to the user.
\pre `t.dimension() == 3`, `v != Vertex_handle()`, `t.is_vertex(v)`.
*/

View File

@ -340,7 +340,7 @@ public:
}
#endif // CGAL_CONCURRENT_TRIANGULATION_3_ADD_TEMPORARY_POINTS_ON_FAR_SPHERE
int i = 0;
size_t i = 0;
// Insert "num_points_seq" points sequentially
// (or more if dim < 3 after that)
size_t num_points_seq = (std::min)(num_points, (size_t)100);

View File

@ -274,7 +274,7 @@ namespace CGAL {
}
#endif // CGAL_CONCURRENT_TRIANGULATION_3_ADD_TEMPORARY_POINTS_ON_FAR_SPHERE
int i = 0;
size_t i = 0;
// Insert "num_points_seq" points sequentially
// (or more if dim < 3 after that)
size_t num_points_seq = (std::min)(num_points, (size_t)500);