From e268e69ad34b24f1ff0cd342019248fe87e97176 Mon Sep 17 00:00:00 2001 From: cignoni Date: Wed, 14 Nov 2012 06:17:15 +0000 Subject: [PATCH] Commenting and cleaning up the ball pivoting/ advancing front framework --- .../algorithms/create/advancing_front.h | 80 ++++++++++------- vcg/complex/algorithms/create/ball_pivoting.h | 85 ++++++++++--------- 2 files changed, 90 insertions(+), 75 deletions(-) diff --git a/vcg/complex/algorithms/create/advancing_front.h b/vcg/complex/algorithms/create/advancing_front.h index 80b6bf32..bceef6eb 100644 --- a/vcg/complex/algorithms/create/advancing_front.h +++ b/vcg/complex/algorithms/create/advancing_front.h @@ -11,11 +11,15 @@ namespace vcg { namespace tri { +/* An active edge on the advancing front. + * belong to a triangle (v0,v1,v2) + * v0, v1 the active edge + * v2 internal vertex +*/ class FrontEdge { public: int v0, v1, v2; //v0, v1 represent the FrontEdge, v2 the other vertex //in the face this FrontEdge belongs to - int face; //index of the face bool active; //keep tracks of wether it is in front or in deads //the loops in the front are mantained as a double linked list @@ -23,14 +27,14 @@ class FrontEdge { std::list::iterator previous; FrontEdge() {} - FrontEdge(int _v0, int _v1, int _v2, int _face): - v0(_v0), v1(_v1), v2(_v2), face(_face), active(true) { + FrontEdge(int _v0, int _v1, int _v2): + v0(_v0), v1(_v1), v2(_v2), active(true) { assert(v0 != v1 && v1 != v2 && v0 != v2); } - const bool operator==(const FrontEdge& f) const + bool operator==(const FrontEdge& f) const { - return ((v0 == f.v0) && (v1 == f.v1) && (v2 == f.v2) && (face == f.face)); + return ((v0 == f.v0) && (v1 == f.v1) && (v2 == f.v2) ); } }; @@ -39,6 +43,7 @@ template class AdvancingFront { typedef typename MESH::VertexType VertexType; typedef typename MESH::FaceType FaceType; + typedef typename MESH::FaceIterator FaceIterator; typedef typename MESH::ScalarType ScalarType; typedef typename MESH::VertexType::CoordType Point3x; @@ -121,16 +126,17 @@ protected: } //create the FrontEdge loops from seed faces - void CreateLoops() { - VertexType *start = &*mesh.vert.begin(); - for(int i = 0; i < (int)mesh.face.size(); i++) { + void CreateLoops() + { + for(size_t i = 0; i < mesh.face.size(); i++) + { FaceType &f = mesh.face[i]; if(f.IsD()) continue; for(int k = 0; k < 3; k++) { if(f.IsB(k)) { - NewEdge(FrontEdge(f.V0(k) - start, f.V1(k) - start, f.V2(k) - start, i)); - nb[f.V0(k)-start]++; + addNewEdge(FrontEdge(tri::Index(mesh,f.V0(k)),tri::Index(mesh,f.V1(k)),tri::Index(mesh,f.V2(k))) ); + nb[tri::Index(mesh,f.V0(k))]++; } } } @@ -176,7 +182,7 @@ protected: mesh.vert[v0].SetB(); nb[v[i]]++; - e = front.insert(front.begin(), FrontEdge(v0, v1, v2, mesh.face.size())); + e = front.insert(front.begin(), FrontEdge(v0, v1, v2)); if(i != 0) { (*last).next = e; (*e).previous = last; @@ -218,7 +224,7 @@ public: assert(v2 != v0 && v2 != v1); if ((touch.first == FRONT) && (touch.second != front.end()) || - (touch.first == DEADS) && (touch.second != deads.end())) + (touch.first == DEADS) && (touch.second != deads.end())) { //check for orientation and manifoldness @@ -240,7 +246,7 @@ public: Detach(v0); - std::list::iterator up = NewEdge(FrontEdge(v2, v1, v0, mesh.face.size())); + std::list::iterator up = addNewEdge(FrontEdge(v2, v1, v0)); MoveFront(up); (*up).previous = previous.previous; (*up).next = current.next; @@ -266,7 +272,7 @@ public: v1 */ Detach(v1); - std::list::iterator up = NewEdge(FrontEdge(v0, v2, v1, mesh.face.size())); + std::list::iterator up = addNewEdge(FrontEdge(v0, v2, v1)); MoveFront(up); (*up).previous = current.previous; (*up).next = (*current.next).next; @@ -303,8 +309,8 @@ public: nb[v2]++; - std::list::iterator down = NewEdge(FrontEdge(v2, v1, v0, mesh.face.size())); - std::list::iterator up = NewEdge(FrontEdge(v0, v2, v1, mesh.face.size())); + std::list::iterator down = addNewEdge(FrontEdge(v2, v1, v0)); + std::list::iterator up = addNewEdge(FrontEdge(v0, v2, v1)); (*right).next = down; (*down).previous = right; @@ -322,8 +328,8 @@ public: } - else if ((touch.first == FRONT) && (touch.second == front.end()) || - (touch.first == DEADS) && (touch.second == deads.end())) + else if ((touch.first == FRONT) && (touch.second == front.end()) || + (touch.first == DEADS) && (touch.second == deads.end())) { // assert(CheckEdge(v0, v2)); // assert(CheckEdge(v2, v1)); @@ -340,8 +346,8 @@ public: nb[v2]++; mesh.vert[v2].SetB(); - std::list::iterator down = NewEdge(FrontEdge(v2, v1, v0, mesh.face.size())); - std::list::iterator up = NewEdge(FrontEdge(v0, v2, v1, mesh.face.size())); + std::list::iterator down = addNewEdge(FrontEdge(v2, v1, v0)); + std::list::iterator up = addNewEdge(FrontEdge(v0, v2, v1)); (*down).previous = up; (*up).next = down; @@ -359,13 +365,22 @@ public: protected: void AddFace(int v0, int v1, int v2) { assert(v0 < (int)mesh.vert.size() && v1 < (int)mesh.vert.size() && v2 < (int)mesh.vert.size()); - FaceType face; - face.V(0) = &mesh.vert[v0]; - face.V(1) = &mesh.vert[v1]; - face.V(2) = &mesh.vert[v2]; - ComputeNormalizedNormal(face); - mesh.face.push_back(face); - mesh.fn++; + FaceIterator fi = vcg::tri::Allocator::AddFaces(mesh,1); + fi->ClearFlags(); + fi->V(0) = &mesh.vert[v0]; + fi->V(1) = &mesh.vert[v1]; + fi->V(2) = &mesh.vert[v2]; + ComputeNormalizedNormal(*fi); + if(tri::HasVFAdjacency(mesh)) + { + for(int j=0;j<3;++j) + { + (*fi).VFp(j) = (*fi).V(j)->VFp(); + (*fi).VFi(j) = (*fi).V(j)->VFi(); + (*fi).V(j)->VFp() = &(*fi); + (*fi).V(j)->VFi() = j; + } + } } void AddVertex(VertexType &vertex) { @@ -384,13 +399,13 @@ protected: nb.push_back(0); } + // Given a possible new edge v0-v1 + // it checks that: + // 1) the orientation is consistent (all the faces with vertex v0 and v1 have the edge in the opposite way) + // 2) the edge appears at least once bool CheckEdge(int v0, int v1) { int tot = 0; - //HACK to speed up things until i can use a seach structure -/* int i = mesh.face.size() - 4*(front.size()); - if(front.size() < 100) i = mesh.face.size() - 100; - if(i < 0) i = 0;*/ VertexType *vv0 = &(mesh.vert[v0]); VertexType *vv1 = &(mesh.vert[v1]); @@ -410,7 +425,7 @@ protected: //front management: //Add a new FrontEdge to the back of the queue - std::list::iterator NewEdge(FrontEdge e) { + std::list::iterator addNewEdge(FrontEdge e) { return front.insert(front.end(), e); } @@ -427,7 +442,6 @@ protected: tmp.previous->next = newe; tmp.next->previous = newe; } - } void Erase(std::list::iterator e) { diff --git a/vcg/complex/algorithms/create/ball_pivoting.h b/vcg/complex/algorithms/create/ball_pivoting.h index 5a0e981c..7fed97be 100644 --- a/vcg/complex/algorithms/create/ball_pivoting.h +++ b/vcg/complex/algorithms/create/ball_pivoting.h @@ -25,8 +25,8 @@ template class BallPivoting: public AdvancingFront { typedef GridStaticPtr StaticGrid; float radius; //radius of the ball - float min_edge; //min lenght of an edge - float max_edge; //min lenght of an edge + float min_edge; //min length of an edge + float max_edge; //min length of an edge float max_angle; //max angle between 2 faces (cos(angle) actually) public: @@ -190,16 +190,16 @@ template class BallPivoting: public AdvancingFront { Mark(vv1); Mark(vv2); - v0 = vv0 - &*this->mesh.vert.begin(); - v1 = vv1 - &*this->mesh.vert.begin(); - v2 = vv2 - &*this->mesh.vert.begin(); + v0 = tri::Index(this->mesh,vv0); + v1 = tri::Index(this->mesh,vv1); + v2 = tri::Index(this->mesh,vv2); return true; } return false; } - //select a new vertex, mark as Visited and mark as usedBit all neighbours (less than min_edge) - int Place(FrontEdge &edge,typename AdvancingFront::ResultIterator &touch) { + // Given an edge select a new vertex, mark as Visited and mark as usedBit all neighbours (less than min_edge) + int Place(FrontEdge &edge, typename AdvancingFront::ResultIterator &touch) { Point3x v0 = this->mesh.vert[edge.v0].P(); Point3x v1 = this->mesh.vert[edge.v1].P(); Point3x v2 = this->mesh.vert[edge.v2].P(); @@ -230,9 +230,9 @@ template class BallPivoting: public AdvancingFront { // r is the radius of the thorus of all possible spheres passing throug v0 and v1 ScalarType r = sqrt(radius*radius - axis_len/4); - std::vector targets; + std::vector targets; // The vector of std::vector dists; - std::vector points; + std::vector points; // never used. tri::GetInSphereVertex(this->mesh, grid, middle, r + radius, targets, dists, points); @@ -242,21 +242,22 @@ template class BallPivoting: public AdvancingFront { VertexType *candidate = NULL; ScalarType min_angle = M_PI; - - for(int i = 0; i < static_cast(targets.size()); i++) { + // + // Loop over all the nearest vertexes and choose the best one according the ball pivoting strategy. + // + for(size_t i = 0; i < targets.size(); i++) { VertexType *v = targets[i]; - int id = v - &*this->mesh.vert.begin(); - if(v->IsD()) continue; - + if(v->IsD()) continue; + int vInd = tri::Index(this->mesh,v); // this should always be true IsB => IsV , IsV => IsU if(v->IsB()) assert(v->IsV()); if(v->IsV()) assert(v->IsUserBit(usedBit)); if(v->IsUserBit(usedBit) && !(v->IsB())) continue; - if(id == edge.v0 || id == edge.v1 || id == edge.v2) continue; + if(vInd == edge.v0 || vInd == edge.v1 || vInd == edge.v2) continue; - Point3x p = this->mesh.vert[id].P(); + Point3x p = this->mesh.vert[vInd].P(); /* Find the sphere through v0, p, v1 (store center on end_pivot */ if(!FindSphere(v0, p, v1, center)) { @@ -264,7 +265,7 @@ template class BallPivoting: public AdvancingFront { } /* Angle between old center and new center */ - ScalarType alpha = Angle(start_pivot, center - middle, axis); + ScalarType alpha = OrientedAngleRad(start_pivot, center - middle, axis); /* adding a small bias to already chosen vertices. doesn't solve numerical problems, but helps. */ @@ -280,7 +281,7 @@ template class BallPivoting: public AdvancingFront { Point3x proj = p - axis * (axis * p - axis * middle); ScalarType beta = angle(start_pivot, proj - middle, axis); - if(alpha > beta) alpha -= 2*M_PI; + if(alpha > beta) alpha -= 2*M_PI; } */ if(candidate == NULL || alpha < min_angle) { candidate = v; @@ -299,35 +300,35 @@ template class BallPivoting: public AdvancingFront { assert((candidate->P() - v1).Norm() > min_edge); } - int id = candidate - &*this->mesh.vert.begin(); - assert(id != edge.v0 && id != edge.v1); + int candidateIndex = tri::Index(this->mesh,candidate); + assert(candidateIndex != edge.v0 && candidateIndex != edge.v1); Point3x newnormal = ((candidate->P() - v0)^(v1 - v0)).Normalize(); - if(normal.dot(newnormal) < max_angle || this->nb[id] >= 2) { + if(normal.dot(newnormal) < max_angle || this->nb[candidateIndex] >= 2) { return -1; } - //test if id is in some border (to return touch - for(std::list::iterator k = this->front.begin(); k != this->front.end(); k++) - { - if((*k).v0 == id) - { - touch.first = AdvancingFront::FRONT; - touch.second = k; - } - } - for(std::list::iterator k = this->deads.begin(); k != this->deads.end(); k++) - { - if((*k).v0 == id) - { - touch.first = AdvancingFront::DEADS; - touch.second = k; - } - } - + //test if id is in some border (to return touch + for(std::list::iterator k = this->front.begin(); k != this->front.end(); k++) + { + if((*k).v0 == candidateIndex) + { + touch.first = AdvancingFront::FRONT; + touch.second = k; + } + } + for(std::list::iterator k = this->deads.begin(); k != this->deads.end(); k++) + { + if((*k).v0 == candidateIndex) + { + touch.first = AdvancingFront::DEADS; + touch.second = k; + } + } + //mark vertices close to candidate Mark(candidate); - return id; + return candidateIndex; } private: @@ -341,7 +342,7 @@ template class BallPivoting: public AdvancingFront { /* returns the sphere touching p0, p1, p2 of radius r such that the normal of the face points toward the center of the sphere */ - bool FindSphere(Point3x &p0, Point3x &p1, Point3x &p2, Point3x ¢er) { + bool FindSphere(const Point3x &p0, const Point3x &p1, const Point3x &p2, Point3x ¢er) { //we want p0 to be always the smallest one. Point3x p[3]; @@ -392,7 +393,7 @@ template class BallPivoting: public AdvancingFront { } /* compute angle from p to q, using axis for orientation */ - ScalarType Angle(Point3x p, Point3x q, Point3x &axis) { + ScalarType OrientedAngleRad(Point3x p, Point3x q, Point3x &axis) { p.Normalize(); q.Normalize(); Point3x vec = p^q;