diff --git a/Operations_on_polyhedra/include/CGAL/orient_polygon_soup.h b/Operations_on_polyhedra/include/CGAL/orient_polygon_soup.h index 363ae34ffc7..196e07fceaf 100644 --- a/Operations_on_polyhedra/include/CGAL/orient_polygon_soup.h +++ b/Operations_on_polyhedra/include/CGAL/orient_polygon_soup.h @@ -14,21 +14,22 @@ // // $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 + #include +#include #include #include #include -#include - namespace CGAL { namespace internal { @@ -36,193 +37,368 @@ namespace internal { template class Polygon_soup_orienter { - typedef typename std::iterator_traits::value_type Index; - typedef std::vector Points; - typedef std::map, std::set > Edges_map; - typedef cpp11::array Edge; - typedef std::vector Polygons; - typedef std::set Edges; - typedef typename Polygons::size_type size_type; +/// Index types + typedef typename std::iterator_traits< + typename Polygon_3::iterator >::value_type V_ID; + typedef typename std::vector::size_type P_ID; +// typedef int CC_ID; + typedef std::pair V_ID_pair; +/// Container types + typedef std::vector Points; + typedef std::vector Polygons; + typedef std::map > Edge_map; + typedef typename Edge_map::iterator Edge_map_iterator; + typedef std::set 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 > incident_polygons_per_vertex; -private: - Edge canonical_edge(Index i, Index j) +/// Utility functions + V_ID_pair canonical_edge(V_ID i, V_ID j) { - return i 2 ) - { - non_manifold_edges.insert(canonical_edge(i0,i1)); - } - } - } + cpp11::array + 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 + next_cw_vertex_around_source(V_ID src, V_ID tgt) + { + typedef std::pair 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 + next_ccw_vertex_around_target(V_ID src, V_ID tgt) + { + typedef std::pair 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()); } -public: - - Polygon_soup_orienter(const Points& points, Polygons& polygons) - : points(points), polygons(polygons) + void replace_vertex_index_in_polygon( + std::size_t polygon_id, + V_ID old_index, + V_ID new_index) { - fill_edges(); + BOOST_FOREACH(V_ID& i, polygons[polygon_id]) + if( i==old_index ) + i=new_index; } - bool orient() +/// 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 oriented; std::stack 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 Index& i1 = polygons[to_be_oriented_index][ih]; - const Index& i2 = polygons[to_be_oriented_index][ihp1]; - if(non_manifold_edges.count(canonical_edge(i1,i2)) > 0) { - continue; - } +// CGAL_assertion(polygon_cc_id[to_be_oriented_index]==-1); +// polygon_cc_id[to_be_oriented_index]=current_cc_index; + + 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) - typename 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) - typename 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 Index& i0 = polygons[index][j]; - const Index& 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 Index& i0 = polygons[index][j]; - const Index& 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 > > vertices_to_duplicate; + + V_ID nbv = static_cast( 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 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 >()); + vertices_to_duplicate.back().first=v_id; + } + + const cpp11::array& 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_and_Polygon_ids; + BOOST_FOREACH(const V_ID_and_Polygon_ids& vid_and_pids, vertices_to_duplicate) + { + V_ID new_index = static_cast(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. +/** + * 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 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. + * @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 true if a consistent orientation has been found + * @return return false if some points where duplicated, thus producing a self-intersecting polyhedron * - * \TODO code: there is no check for duplicate points, yet it can be implemented as separate filter function - */ + */ template -bool orient_polygon_soup(const std::vector& points, +bool orient_polygon_soup(std::vector& points, std::vector< Polygon_3 >& polygons) { + std::size_t inital_nb_pts = points.size(); internal::Polygon_soup_orienter orienter(points, polygons); - return orienter.orient(); + orienter.orient(); + orienter.duplicate_singular_vertices(); + + return inital_nb_pts==points.size(); } }// namespace CGAL diff --git a/Operations_on_polyhedra/test/Operations_on_polyhedra/data_polygon_soup/bad_cube.off b/Operations_on_polyhedra/test/Operations_on_polyhedra/data_polygon_soup/bad_cube.off new file mode 100644 index 00000000000..95d9b19531b --- /dev/null +++ b/Operations_on_polyhedra/test/Operations_on_polyhedra/data_polygon_soup/bad_cube.off @@ -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 diff --git a/Operations_on_polyhedra/test/Operations_on_polyhedra/data_polygon_soup/incompatible_orientation.off b/Operations_on_polyhedra/test/Operations_on_polyhedra/data_polygon_soup/incompatible_orientation.off new file mode 100644 index 00000000000..16733a214e1 --- /dev/null +++ b/Operations_on_polyhedra/test/Operations_on_polyhedra/data_polygon_soup/incompatible_orientation.off @@ -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 diff --git a/Operations_on_polyhedra/test/Operations_on_polyhedra/data_polygon_soup/isolated_singular_vertex_one_cc.off b/Operations_on_polyhedra/test/Operations_on_polyhedra/data_polygon_soup/isolated_singular_vertex_one_cc.off new file mode 100644 index 00000000000..ab29e5ba53e --- /dev/null +++ b/Operations_on_polyhedra/test/Operations_on_polyhedra/data_polygon_soup/isolated_singular_vertex_one_cc.off @@ -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 + + diff --git a/Operations_on_polyhedra/test/Operations_on_polyhedra/data_polygon_soup/isolated_vertices.off b/Operations_on_polyhedra/test/Operations_on_polyhedra/data_polygon_soup/isolated_vertices.off new file mode 100644 index 00000000000..f9b2ca98807 --- /dev/null +++ b/Operations_on_polyhedra/test/Operations_on_polyhedra/data_polygon_soup/isolated_vertices.off @@ -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 diff --git a/Operations_on_polyhedra/test/Operations_on_polyhedra/data_polygon_soup/nm_vertex_and_edge.off b/Operations_on_polyhedra/test/Operations_on_polyhedra/data_polygon_soup/nm_vertex_and_edge.off new file mode 100644 index 00000000000..8edd5c86886 --- /dev/null +++ b/Operations_on_polyhedra/test/Operations_on_polyhedra/data_polygon_soup/nm_vertex_and_edge.off @@ -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 diff --git a/Operations_on_polyhedra/test/Operations_on_polyhedra/data_polygon_soup/one_duplicated_edge.off b/Operations_on_polyhedra/test/Operations_on_polyhedra/data_polygon_soup/one_duplicated_edge.off new file mode 100644 index 00000000000..4e392ac96e6 --- /dev/null +++ b/Operations_on_polyhedra/test/Operations_on_polyhedra/data_polygon_soup/one_duplicated_edge.off @@ -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 diff --git a/Operations_on_polyhedra/test/Operations_on_polyhedra/data_polygon_soup/one_duplicated_edge_sharing_vertex.off b/Operations_on_polyhedra/test/Operations_on_polyhedra/data_polygon_soup/one_duplicated_edge_sharing_vertex.off new file mode 100644 index 00000000000..cc9930a335f --- /dev/null +++ b/Operations_on_polyhedra/test/Operations_on_polyhedra/data_polygon_soup/one_duplicated_edge_sharing_vertex.off @@ -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 \ No newline at end of file diff --git a/Operations_on_polyhedra/test/Operations_on_polyhedra/data_polygon_soup/partial_overlap.off b/Operations_on_polyhedra/test/Operations_on_polyhedra/data_polygon_soup/partial_overlap.off new file mode 100644 index 00000000000..6b21dc7c94e --- /dev/null +++ b/Operations_on_polyhedra/test/Operations_on_polyhedra/data_polygon_soup/partial_overlap.off @@ -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 diff --git a/Operations_on_polyhedra/test/Operations_on_polyhedra/test_orient_polygon_soup.cpp b/Operations_on_polyhedra/test/Operations_on_polyhedra/test_orient_polygon_soup.cpp new file mode 100644 index 00000000000..c5ce5e0f31b --- /dev/null +++ b/Operations_on_polyhedra/test/Operations_on_polyhedra/test_orient_polygon_soup.cpp @@ -0,0 +1,54 @@ +#include +#include + +#include +#include +#include + +#include +#include +#include + +typedef CGAL::Simple_cartesian K; +typedef CGAL::Polyhedron_3 Polyhedron; + +void test(std::string fname, std::size_t expected_duplicated_vertices) +{ + std::vector points; + std::vector< std::vector > 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); +} \ No newline at end of file diff --git a/Polyhedron/demo/Polyhedron/Polyhedron_demo_orient_soup_plugin.cpp b/Polyhedron/demo/Polyhedron/Polyhedron_demo_orient_soup_plugin.cpp index 82a9fb7ff5a..7ce9e84c45a 100644 --- a/Polyhedron/demo/Polyhedron/Polyhedron_demo_orient_soup_plugin.cpp +++ b/Polyhedron/demo/Polyhedron/Polyhedron_demo_orient_soup_plugin.cpp @@ -88,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{ diff --git a/Polyhedron/demo/Polyhedron/Scene_polygon_soup_item.cpp b/Polyhedron/demo/Polyhedron/Scene_polygon_soup_item.cpp index 63f8b5eae69..7ff448012c6 100644 --- a/Polyhedron/demo/Polyhedron/Scene_polygon_soup_item.cpp +++ b/Polyhedron/demo/Polyhedron/Scene_polygon_soup_item.cpp @@ -155,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); }