mirror of https://github.com/CGAL/cgal
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:
commit
c4064b3b0f
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
||||
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -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
|
||||
|
|
@ -0,0 +1 @@
|
|||
GeometryFactory (France)
|
||||
|
|
@ -0,0 +1 @@
|
|||
GPL (v3 or later)
|
||||
|
|
@ -0,0 +1 @@
|
|||
Andreas Fabri <Andreas.Fabri@geometryfactory.com>
|
||||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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))
|
||||
);
|
||||
|
|
|
|||
|
|
@ -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{
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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)`.
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
Loading…
Reference in New Issue