From 8f72b462eb5ffc548dd088ef23012d8f641c4246 Mon Sep 17 00:00:00 2001 From: giorgiomarcias Date: Sun, 4 May 2014 18:53:31 +0000 Subject: [PATCH] Corrected a silly bug causing the polychord collapse process a strange behaviour (also some crash) when compiled with c++11. Changed also recursive types (forward declarations) avoiding pointers (by using vectors - rather than lists - and indices). --- .../algorithms/polygon_polychord_collapse.h | 274 ++++++++---------- 1 file changed, 126 insertions(+), 148 deletions(-) diff --git a/vcg/complex/algorithms/polygon_polychord_collapse.h b/vcg/complex/algorithms/polygon_polychord_collapse.h index 6bf10bab..97b7571e 100644 --- a/vcg/complex/algorithms/polygon_polychord_collapse.h +++ b/vcg/complex/algorithms/polygon_polychord_collapse.h @@ -23,7 +23,11 @@ #ifndef POLYGON_POLYCHORD_COLLAPSE_H #define POLYGON_POLYCHORD_COLLAPSE_H +#include #include +#include +#include +#include #include #include @@ -248,11 +252,54 @@ public: */ class LinkConditions { private: - struct LCEdge; - struct LCVertex; + typedef long int LCVertexIndex; + typedef std::set LCVertexStar; // define the star of a vertex + typedef long int LCEdgeIndex; + typedef std::set LCEdgeStar; // define the set of edges whose star involves a vertex - typedef std::set LCVertexStar; // define the star of a vertex - typedef std::set LCEdgeStar; // define the set of edges whose star involves a vertex + /** + * @brief The LCVertex struct represents a vertex for the Link Conditions. + */ + struct LCVertex { + LCVertexStar star; // vertex star + LCEdgeStar edges; // list of edges whose star involves this vertex + LCVertex(){} // default constructor + LCVertex(const LCVertex &lcVertex) { // copy constructor + star = lcVertex.star; + edges = lcVertex.edges; + } + LCVertex & operator=(const LCVertex &lcVertex) { // assignment operator + star = lcVertex.star; + edges = lcVertex.edges; + return *this; + } + void reset() { star.clear(); edges.clear(); } // reset + }; + + /** + * @brief The LCEdge struct represents an edge for the Link Conditions. + */ + struct LCEdge { + LCVertexIndex v1, v2; // endpoints + LCVertexStar star; // edge star + LCEdge() {v1 = v2 = -1;} // default contructor + LCEdge(const LCEdge &lcEdge) { // copy constructor + v1 = lcEdge.v1; + v2 = lcEdge.v2; + star = lcEdge.star; + } + LCEdge & operator=(const LCEdge &lcEdge) { // assignment operator + v1 = lcEdge.v1; + v2 = lcEdge.v2; + star = lcEdge.star; + return *this; + } + void reset() { // reset + v1 = -1; + v2 = -1; + star.clear(); + } + }; public: /** @@ -267,6 +314,7 @@ public: */ inline void Resize(const size_t size) { _lcVertices.resize(size); + LC_ResetStars(); } /** @@ -281,12 +329,11 @@ public: bool CheckLinkConditions (const PolyMeshType &mesh, const vcg::face::Pos &startPos) { assert(!startPos.IsNull()); assert(mesh.vert.size() == _lcVertices.size()); - std::list lcEdges; - LCEdge *e = NULL; + std::vector lcEdges; LCVertexStar intersection; // reset the stars - LC_ResetStars(mesh, startPos); + LC_ResetStars(); // compute the stars LC_computeStars(mesh, startPos, lcEdges); @@ -296,96 +343,31 @@ public: // then collapse e // else // return false (i.e. link conditions not satisfied) - for (typename std::list::iterator eIt = lcEdges.begin(); eIt != lcEdges.end(); eIt++) { - e = &*eIt; + for (size_t e = 0; e < lcEdges.size(); e++) { // compute the intersetion - SetIntersection(e->v1->star, e->v2->star, intersection); + intersection.clear(); + std::set_intersection(_lcVertices[lcEdges[e].v1].star.begin(), _lcVertices[lcEdges[e].v1].star.end(), + _lcVertices[lcEdges[e].v2].star.begin(), _lcVertices[lcEdges[e].v2].star.end(), + std::inserter(intersection, intersection.end())); + // if intersection( star(v1) , star(v2) ) != star(e) then return false - if (intersection != e->star) + if (intersection != lcEdges[e].star) return false; + // else simulate the collapse - LC_SimulateEdgeCollapse(*e); + LC_SimulateEdgeCollapse(lcEdges, e); } // at this point all collapses are possible, thus return true return true; } private: - /** - * @brief SetIntersection computes the set intersection between two sets. - * @param set1 - * @param set2 - * @param result The set resulting from the intersection. - */ - static void SetIntersection (const LCVertexStar &set1, const LCVertexStar &set2, LCVertexStar &result) { - typename LCVertexStar::const_iterator set1It = set1.begin(); - typename LCVertexStar::const_iterator set2It = set2.begin(); - result.clear(); - while (set1It != set1.end() && set2It != set2.end()) { - if (*set1It < *set2It) ++set1It; - else if (*set2It < *set1It) ++set2It; - else { - result.insert(*set1It); - ++set1It; - ++set2It; - } - } - } - /** * @brief LC_ResetStars resets the stars on a polychord. - * @param mesh The mesh for getting the vertex index. - * @param startPos */ - void LC_ResetStars (const PolyMeshType &mesh, const vcg::face::Pos &startPos) { - assert(!startPos.IsNull()); - assert(mesh.vert.size() == _lcVertices.size()); - vcg::face::Pos runPos = startPos; - vcg::face::JumpingPos vStarPos; - // reset the stars - do { - // reset the star of this edge endpoints - _lcVertices[vcg::tri::Index(mesh, runPos.V())].edges.clear(); - _lcVertices[vcg::tri::Index(mesh, runPos.V())].star.clear(); - _lcVertices[vcg::tri::Index(mesh, runPos.VFlip())].edges.clear(); - _lcVertices[vcg::tri::Index(mesh, runPos.VFlip())].star.clear(); - // reset the stars of the vertices in the star of the second vertex - runPos.FlipV(); - vStarPos.Set(runPos.F(), runPos.E(), runPos.V()); - do { - vStarPos.FlipV(); - vStarPos.FlipE(); - while (vStarPos.V() != runPos.V()) { - _lcVertices[vcg::tri::Index(mesh, vStarPos.V())].edges.clear(); - _lcVertices[vcg::tri::Index(mesh, vStarPos.V())].star.clear(); - vStarPos.FlipV(); - vStarPos.FlipE(); - } - vStarPos.NextFE(); - } while (vStarPos != runPos); - // reset the stars of the vertices in the star of the first vertex - runPos.FlipV(); - vStarPos.Set(runPos.F(), runPos.E(), runPos.V()); - do { - vStarPos.FlipV(); - vStarPos.FlipE(); - while (vStarPos.V() != runPos.V()) { - _lcVertices[vcg::tri::Index(mesh, vStarPos.V())].edges.clear(); - _lcVertices[vcg::tri::Index(mesh, vStarPos.V())].star.clear(); - vStarPos.FlipV(); - vStarPos.FlipE(); - } - vStarPos.NextFE(); - } while (vStarPos != runPos); - // when arrive to a border, return - if (runPos != startPos && runPos.IsBorder()) - break; - // go on the next edge - runPos.FlipE(); - runPos.FlipV(); - runPos.FlipE(); - runPos.FlipF(); - } while (runPos != startPos); + void LC_ResetStars() { + for (size_t v = 0; v < _lcVertices.size(); v++) + _lcVertices[v].reset(); } /** @@ -393,42 +375,57 @@ public: * either to itself (if it's a loop) or to the border edge. * @param mesh The mesh for getting the vertex index. * @param startPos Starting position. - * @param lcEdges List of edge stars. + * @param lcEdges Vector of edge stars. */ - void LC_computeStars (const PolyMeshType &mesh, const vcg::face::Pos &startPos, std::list &lcEdges) - { + void LC_computeStars (const PolyMeshType &mesh, const vcg::face::Pos &startPos, std::vector &lcEdges) { assert(!startPos.IsNull()); assert(mesh.vert.size() == _lcVertices.size()); - LCEdge *lcedgeP = NULL; vcg::face::Pos runPos = startPos; vcg::face::JumpingPos vStarPos; vcg::face::Pos eStarPos; + LCEdgeIndex edgeInd = -1; + size_t nEdges = 0; + + // count how many edges + do { + nEdges++; + // go on the next edge + runPos.FlipE(); + runPos.FlipV(); + runPos.FlipE(); + runPos.FlipF(); + } while (runPos != startPos && !runPos.IsBorder()); + if (runPos.IsBorder()) + nEdges++; + + // resize the vector of edges + lcEdges.resize(nEdges); + for (size_t e = 0; e < nEdges; e++) + lcEdges[e].reset(); - lcEdges.clear(); /// compute the star of all the vertices and edges seen from the polychord runPos = startPos; do { - // create a lcedge - lcEdges.push_back(LCEdge()); - lcedgeP = &lcEdges.back(); + // access the next lcedge + edgeInd++; // set lcvertices references - lcedgeP->v1 = &_lcVertices[vcg::tri::Index(mesh, runPos.V())]; - lcedgeP->v2 = &_lcVertices[vcg::tri::Index(mesh, runPos.VFlip())]; + lcEdges[edgeInd].v1 = vcg::tri::Index(mesh, runPos.V()); + lcEdges[edgeInd].v2 = vcg::tri::Index(mesh, runPos.VFlip()); // add this edge to its vertices edge-stars - lcedgeP->v1->edges.insert(lcedgeP); - lcedgeP->v2->edges.insert(lcedgeP); + _lcVertices[lcEdges[edgeInd].v1].edges.insert(edgeInd); + _lcVertices[lcEdges[edgeInd].v2].edges.insert(edgeInd); // compute the star of this edge - lcedgeP->star.insert(lcedgeP->v1); // its endpoints, clearly - lcedgeP->star.insert(lcedgeP->v2); // its endpoints, clearly + lcEdges[edgeInd].star.insert(lcEdges[edgeInd].v1); // its endpoints, clearly + lcEdges[edgeInd].star.insert(lcEdges[edgeInd].v2); // its endpoints, clearly // navigate over the other vertices of this facet eStarPos = runPos; eStarPos.FlipE(); eStarPos.FlipV(); while (eStarPos.V() != runPos.VFlip()) { // add current vertex to the star of this edge - lcedgeP->star.insert(&_lcVertices[vcg::tri::Index(mesh, eStarPos.V())]); + lcEdges[edgeInd].star.insert(vcg::tri::Index(mesh, eStarPos.V())); // add this edge to the edge-star of the current vertex - _lcVertices[vcg::tri::Index(mesh, eStarPos.V())].edges.insert(lcedgeP); + _lcVertices[vcg::tri::Index(mesh, eStarPos.V())].edges.insert(edgeInd); // go on eStarPos.FlipE(); eStarPos.FlipV(); @@ -441,9 +438,9 @@ public: eStarPos.FlipV(); while (eStarPos.V() != runPos.VFlip()) { // add current vertex to the star of this edge - lcedgeP->star.insert(&_lcVertices[vcg::tri::Index(mesh, eStarPos.V())]); + lcEdges[edgeInd].star.insert(vcg::tri::Index(mesh, eStarPos.V())); // add this edge to the edge-star of the current vertex - _lcVertices[vcg::tri::Index(mesh, eStarPos.V())].edges.insert(lcedgeP); + _lcVertices[vcg::tri::Index(mesh, eStarPos.V())].edges.insert(edgeInd); // go on eStarPos.FlipE(); eStarPos.FlipV(); @@ -454,15 +451,15 @@ public: runPos.FlipV(); vStarPos.Set(runPos.F(), runPos.E(), runPos.V()); // v2 is in its star - _lcVertices[vcg::tri::Index(mesh, vStarPos.V())].star.insert(&_lcVertices[vcg::tri::Index(mesh, vStarPos.V())]); + _lcVertices[vcg::tri::Index(mesh, vStarPos.V())].star.insert(vcg::tri::Index(mesh, vStarPos.V())); do { vStarPos.FlipV(); vStarPos.FlipE(); while (vStarPos.V() != runPos.V()) { // add the current vertex to the v2 star - _lcVertices[vcg::tri::Index(mesh, runPos.V())].star.insert(&_lcVertices[vcg::tri::Index(mesh, vStarPos.V())]); + _lcVertices[vcg::tri::Index(mesh, runPos.V())].star.insert(vcg::tri::Index(mesh, vStarPos.V())); // add v2 to the star of the current vertex - _lcVertices[vcg::tri::Index(mesh, vStarPos.V())].star.insert(&_lcVertices[vcg::tri::Index(mesh, runPos.V())]); + _lcVertices[vcg::tri::Index(mesh, vStarPos.V())].star.insert(vcg::tri::Index(mesh, runPos.V())); vStarPos.FlipV(); vStarPos.FlipE(); } @@ -473,15 +470,15 @@ public: runPos.FlipV(); vStarPos.Set(runPos.F(), runPos.E(), runPos.V()); // v1 is in its star - _lcVertices[vcg::tri::Index(mesh, vStarPos.V())].star.insert(&_lcVertices[vcg::tri::Index(mesh, vStarPos.V())]); + _lcVertices[vcg::tri::Index(mesh, vStarPos.V())].star.insert(vcg::tri::Index(mesh, vStarPos.V())); do { vStarPos.FlipV(); vStarPos.FlipE(); while (vStarPos.V() != runPos.V()) { // add the current vertex to the v2 star - _lcVertices[vcg::tri::Index(mesh, runPos.V())].star.insert(&_lcVertices[vcg::tri::Index(mesh, vStarPos.V())]); + _lcVertices[vcg::tri::Index(mesh, runPos.V())].star.insert(vcg::tri::Index(mesh, vStarPos.V())); // add v2 to the star of the current vertex - _lcVertices[vcg::tri::Index(mesh, vStarPos.V())].star.insert(&_lcVertices[vcg::tri::Index(mesh, runPos.V())]); + _lcVertices[vcg::tri::Index(mesh, vStarPos.V())].star.insert(vcg::tri::Index(mesh, runPos.V())); vStarPos.FlipV(); vStarPos.FlipE(); } @@ -505,59 +502,40 @@ public: /** * @brief LC_SimulateEdgeCollapse simulates an edge collapse by updating the stars involved. - * @param edge The edge to collapse. + * @param lcEdges The vector of edges. + * @param edgeInd The in dex of the edge to collapse. */ - void LC_SimulateEdgeCollapse (LCEdge &edge) { + void LC_SimulateEdgeCollapse (std::vector &lcEdges, const LCEdgeIndex edgeInd) { // let v1 and v2 be the two end points - LCVertex *v1 = edge.v1; - LCVertex *v2 = edge.v2; - assert(v1 && v2); - LCVertex *v = NULL; - LCEdge *e = NULL; + LCVertexIndex v1 = lcEdges[edgeInd].v1; + LCVertexIndex v2 = lcEdges[edgeInd].v2; + LCVertexIndex v = -1; /// v2 merges into v1: // star(v1) = star(v1) U star(v2) - v1->star.insert(v2->star.begin(), v2->star.end()); - v1->star.erase(v2); // remove v2 from v1-star - v2->star.erase(v1); // remove v1 from v2-star + _lcVertices[v1].star.insert(_lcVertices[v2].star.begin(), _lcVertices[v2].star.end()); + _lcVertices[v1].star.erase(v2); // remove v2 from v1-star + _lcVertices[v2].star.erase(v1); // remove v1 from v2-star // foreach v | v2 \in star(v) [i.e. v \in star(v2)] // star(v) = star(v) U {v1} \ {v2} - for (typename LCVertexStar::iterator vIt = v2->star.begin(); vIt != v2->star.end(); vIt++) { + for (typename LCVertexStar::iterator vIt = _lcVertices[v2].star.begin(); vIt != _lcVertices[v2].star.end(); vIt++) { v = *vIt; - v->star.insert(v1); - v->star.erase(v2); + if (v == v2) // skip v2 itself + continue; + _lcVertices[v].star.insert(v1); + _lcVertices[v].star.erase(v2); } /// update the star of the edges which include v1 and v2 in their star // foreach e | v1 \in star(e) ^ v2 \in star(e) // star(e) = star(e) \ {v1,v2} U {v1} - for (typename LCEdgeStar::iterator eIt = v1->edges.begin(); eIt != v1->edges.end(); eIt++) { - e = *eIt; - e->star.erase(v2); - } - for (typename LCEdgeStar::iterator eIt = v2->edges.begin(); eIt != v2->edges.end(); eIt++) { - e = *eIt; - e->star.erase(v2); - e->star.insert(v1); + for (typename LCEdgeStar::iterator eIt = _lcVertices[v1].edges.begin(); eIt != _lcVertices[v1].edges.end(); eIt++) + lcEdges[*eIt].star.erase(v2); + for (typename LCEdgeStar::iterator eIt = _lcVertices[v2].edges.begin(); eIt != _lcVertices[v2].edges.end(); eIt++) { + lcEdges[*eIt].star.erase(v2); + lcEdges[*eIt].star.insert(v1); } } - /** - * @brief The LCVertex struct represents a vertex for the Link Conditions. - */ - struct LCVertex { - LCVertexStar star; // vertex star - LCEdgeStar edges; // list of edges whose star involves this vertex - }; - - /** - * @brief The LCEdge struct represents an edge for the Link Conditions. - */ - struct LCEdge { - LCVertex *v1, *v2; // endpoints - LCVertexStar star; // edge star - LCEdge() {v1 = v2 = NULL;} // default contructor - }; - /** * @brief _lcVertices is a vector of vertex stars for the link conditions. */ @@ -606,7 +584,7 @@ public: vcg::tri::RequirePerVertexFlags(mesh); vcg::tri::RequirePerFaceFlags(mesh); - if (mesh.face.size() == 0) + if (mesh.IsEmpty()) return PC_VOID; if (pos.IsNull()) @@ -844,7 +822,7 @@ public: static void CollapseAllPolychords (PolyMeshType &mesh, const bool checkSing = true) { vcg::tri::RequireFFAdjacency(mesh); - if (mesh.FN() == 0) + if (mesh.IsEmpty()) return; vcg::face::Pos pos;