Commenting and cleaning up the ball pivoting/ advancing front framework

This commit is contained in:
Paolo Cignoni 2012-11-14 06:17:15 +00:00
parent b6e2315d73
commit e268e69ad3
2 changed files with 90 additions and 75 deletions

View File

@ -11,11 +11,15 @@
namespace vcg { namespace vcg {
namespace tri { 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 { class FrontEdge {
public: public:
int v0, v1, v2; //v0, v1 represent the FrontEdge, v2 the other vertex int v0, v1, v2; //v0, v1 represent the FrontEdge, v2 the other vertex
//in the face this FrontEdge belongs to //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 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 //the loops in the front are mantained as a double linked list
@ -23,14 +27,14 @@ class FrontEdge {
std::list<FrontEdge>::iterator previous; std::list<FrontEdge>::iterator previous;
FrontEdge() {} FrontEdge() {}
FrontEdge(int _v0, int _v1, int _v2, int _face): FrontEdge(int _v0, int _v1, int _v2):
v0(_v0), v1(_v1), v2(_v2), face(_face), active(true) { v0(_v0), v1(_v1), v2(_v2), active(true) {
assert(v0 != v1 && v1 != v2 && v0 != v2); 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 MESH> class AdvancingFront {
typedef typename MESH::VertexType VertexType; typedef typename MESH::VertexType VertexType;
typedef typename MESH::FaceType FaceType; typedef typename MESH::FaceType FaceType;
typedef typename MESH::FaceIterator FaceIterator;
typedef typename MESH::ScalarType ScalarType; typedef typename MESH::ScalarType ScalarType;
typedef typename MESH::VertexType::CoordType Point3x; typedef typename MESH::VertexType::CoordType Point3x;
@ -121,16 +126,17 @@ protected:
} }
//create the FrontEdge loops from seed faces //create the FrontEdge loops from seed faces
void CreateLoops() { void CreateLoops()
VertexType *start = &*mesh.vert.begin(); {
for(int i = 0; i < (int)mesh.face.size(); i++) { for(size_t i = 0; i < mesh.face.size(); i++)
{
FaceType &f = mesh.face[i]; FaceType &f = mesh.face[i];
if(f.IsD()) continue; if(f.IsD()) continue;
for(int k = 0; k < 3; k++) { for(int k = 0; k < 3; k++) {
if(f.IsB(k)) { if(f.IsB(k)) {
NewEdge(FrontEdge(f.V0(k) - start, f.V1(k) - start, f.V2(k) - start, i)); addNewEdge(FrontEdge(tri::Index(mesh,f.V0(k)),tri::Index(mesh,f.V1(k)),tri::Index(mesh,f.V2(k))) );
nb[f.V0(k)-start]++; nb[tri::Index(mesh,f.V0(k))]++;
} }
} }
} }
@ -176,7 +182,7 @@ protected:
mesh.vert[v0].SetB(); mesh.vert[v0].SetB();
nb[v[i]]++; 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) { if(i != 0) {
(*last).next = e; (*last).next = e;
(*e).previous = last; (*e).previous = last;
@ -218,7 +224,7 @@ public:
assert(v2 != v0 && v2 != v1); assert(v2 != v0 && v2 != v1);
if ((touch.first == FRONT) && (touch.second != front.end()) || 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 //check for orientation and manifoldness
@ -240,7 +246,7 @@ public:
Detach(v0); Detach(v0);
std::list<FrontEdge>::iterator up = NewEdge(FrontEdge(v2, v1, v0, mesh.face.size())); std::list<FrontEdge>::iterator up = addNewEdge(FrontEdge(v2, v1, v0));
MoveFront(up); MoveFront(up);
(*up).previous = previous.previous; (*up).previous = previous.previous;
(*up).next = current.next; (*up).next = current.next;
@ -266,7 +272,7 @@ public:
v1 */ v1 */
Detach(v1); Detach(v1);
std::list<FrontEdge>::iterator up = NewEdge(FrontEdge(v0, v2, v1, mesh.face.size())); std::list<FrontEdge>::iterator up = addNewEdge(FrontEdge(v0, v2, v1));
MoveFront(up); MoveFront(up);
(*up).previous = current.previous; (*up).previous = current.previous;
(*up).next = (*current.next).next; (*up).next = (*current.next).next;
@ -303,8 +309,8 @@ public:
nb[v2]++; nb[v2]++;
std::list<FrontEdge>::iterator down = NewEdge(FrontEdge(v2, v1, v0, mesh.face.size())); std::list<FrontEdge>::iterator down = addNewEdge(FrontEdge(v2, v1, v0));
std::list<FrontEdge>::iterator up = NewEdge(FrontEdge(v0, v2, v1, mesh.face.size())); std::list<FrontEdge>::iterator up = addNewEdge(FrontEdge(v0, v2, v1));
(*right).next = down; (*right).next = down;
(*down).previous = right; (*down).previous = right;
@ -322,8 +328,8 @@ public:
} }
else if ((touch.first == FRONT) && (touch.second == front.end()) || else if ((touch.first == FRONT) && (touch.second == front.end()) ||
(touch.first == DEADS) && (touch.second == deads.end())) (touch.first == DEADS) && (touch.second == deads.end()))
{ {
// assert(CheckEdge(v0, v2)); // assert(CheckEdge(v0, v2));
// assert(CheckEdge(v2, v1)); // assert(CheckEdge(v2, v1));
@ -340,8 +346,8 @@ public:
nb[v2]++; nb[v2]++;
mesh.vert[v2].SetB(); mesh.vert[v2].SetB();
std::list<FrontEdge>::iterator down = NewEdge(FrontEdge(v2, v1, v0, mesh.face.size())); std::list<FrontEdge>::iterator down = addNewEdge(FrontEdge(v2, v1, v0));
std::list<FrontEdge>::iterator up = NewEdge(FrontEdge(v0, v2, v1, mesh.face.size())); std::list<FrontEdge>::iterator up = addNewEdge(FrontEdge(v0, v2, v1));
(*down).previous = up; (*down).previous = up;
(*up).next = down; (*up).next = down;
@ -359,13 +365,22 @@ public:
protected: protected:
void AddFace(int v0, int v1, int v2) { void AddFace(int v0, int v1, int v2) {
assert(v0 < (int)mesh.vert.size() && v1 < (int)mesh.vert.size() && v2 < (int)mesh.vert.size()); assert(v0 < (int)mesh.vert.size() && v1 < (int)mesh.vert.size() && v2 < (int)mesh.vert.size());
FaceType face; FaceIterator fi = vcg::tri::Allocator<MESH>::AddFaces(mesh,1);
face.V(0) = &mesh.vert[v0]; fi->ClearFlags();
face.V(1) = &mesh.vert[v1]; fi->V(0) = &mesh.vert[v0];
face.V(2) = &mesh.vert[v2]; fi->V(1) = &mesh.vert[v1];
ComputeNormalizedNormal(face); fi->V(2) = &mesh.vert[v2];
mesh.face.push_back(face); ComputeNormalizedNormal(*fi);
mesh.fn++; 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) { void AddVertex(VertexType &vertex) {
@ -384,13 +399,13 @@ protected:
nb.push_back(0); 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) { bool CheckEdge(int v0, int v1) {
int tot = 0; 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 *vv0 = &(mesh.vert[v0]);
VertexType *vv1 = &(mesh.vert[v1]); VertexType *vv1 = &(mesh.vert[v1]);
@ -410,7 +425,7 @@ protected:
//front management: //front management:
//Add a new FrontEdge to the back of the queue //Add a new FrontEdge to the back of the queue
std::list<FrontEdge>::iterator NewEdge(FrontEdge e) { std::list<FrontEdge>::iterator addNewEdge(FrontEdge e) {
return front.insert(front.end(), e); return front.insert(front.end(), e);
} }
@ -427,7 +442,6 @@ protected:
tmp.previous->next = newe; tmp.previous->next = newe;
tmp.next->previous = newe; tmp.next->previous = newe;
} }
} }
void Erase(std::list<FrontEdge>::iterator e) { void Erase(std::list<FrontEdge>::iterator e) {

View File

@ -25,8 +25,8 @@ template <class MESH> class BallPivoting: public AdvancingFront<MESH> {
typedef GridStaticPtr<typename MESH::VertexType, typename MESH::ScalarType > StaticGrid; typedef GridStaticPtr<typename MESH::VertexType, typename MESH::ScalarType > StaticGrid;
float radius; //radius of the ball float radius; //radius of the ball
float min_edge; //min lenght of an edge float min_edge; //min length of an edge
float max_edge; //min lenght of an edge float max_edge; //min length of an edge
float max_angle; //max angle between 2 faces (cos(angle) actually) float max_angle; //max angle between 2 faces (cos(angle) actually)
public: public:
@ -190,16 +190,16 @@ template <class MESH> class BallPivoting: public AdvancingFront<MESH> {
Mark(vv1); Mark(vv1);
Mark(vv2); Mark(vv2);
v0 = vv0 - &*this->mesh.vert.begin(); v0 = tri::Index(this->mesh,vv0);
v1 = vv1 - &*this->mesh.vert.begin(); v1 = tri::Index(this->mesh,vv1);
v2 = vv2 - &*this->mesh.vert.begin(); v2 = tri::Index(this->mesh,vv2);
return true; return true;
} }
return false; return false;
} }
//select a new vertex, mark as Visited and mark as usedBit all neighbours (less than min_edge) // 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<MESH>::ResultIterator &touch) { int Place(FrontEdge &edge, typename AdvancingFront<MESH>::ResultIterator &touch) {
Point3x v0 = this->mesh.vert[edge.v0].P(); Point3x v0 = this->mesh.vert[edge.v0].P();
Point3x v1 = this->mesh.vert[edge.v1].P(); Point3x v1 = this->mesh.vert[edge.v1].P();
Point3x v2 = this->mesh.vert[edge.v2].P(); Point3x v2 = this->mesh.vert[edge.v2].P();
@ -230,9 +230,9 @@ template <class MESH> class BallPivoting: public AdvancingFront<MESH> {
// r is the radius of the thorus of all possible spheres passing throug v0 and v1 // r is the radius of the thorus of all possible spheres passing throug v0 and v1
ScalarType r = sqrt(radius*radius - axis_len/4); ScalarType r = sqrt(radius*radius - axis_len/4);
std::vector<VertexType *> targets; std::vector<VertexType *> targets; // The vector of
std::vector<ScalarType> dists; std::vector<ScalarType> dists;
std::vector<Point3x> points; std::vector<Point3x> points; // never used.
tri::GetInSphereVertex(this->mesh, grid, middle, r + radius, targets, dists, points); tri::GetInSphereVertex(this->mesh, grid, middle, r + radius, targets, dists, points);
@ -242,21 +242,22 @@ template <class MESH> class BallPivoting: public AdvancingFront<MESH> {
VertexType *candidate = NULL; VertexType *candidate = NULL;
ScalarType min_angle = M_PI; ScalarType min_angle = M_PI;
//
for(int i = 0; i < static_cast<int>(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]; 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 // this should always be true IsB => IsV , IsV => IsU
if(v->IsB()) assert(v->IsV()); if(v->IsB()) assert(v->IsV());
if(v->IsV()) assert(v->IsUserBit(usedBit)); if(v->IsV()) assert(v->IsUserBit(usedBit));
if(v->IsUserBit(usedBit) && !(v->IsB())) continue; 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 */ /* Find the sphere through v0, p, v1 (store center on end_pivot */
if(!FindSphere(v0, p, v1, center)) { if(!FindSphere(v0, p, v1, center)) {
@ -264,7 +265,7 @@ template <class MESH> class BallPivoting: public AdvancingFront<MESH> {
} }
/* Angle between old center and new center */ /* 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. /* adding a small bias to already chosen vertices.
doesn't solve numerical problems, but helps. */ doesn't solve numerical problems, but helps. */
@ -299,35 +300,35 @@ template <class MESH> class BallPivoting: public AdvancingFront<MESH> {
assert((candidate->P() - v1).Norm() > min_edge); assert((candidate->P() - v1).Norm() > min_edge);
} }
int id = candidate - &*this->mesh.vert.begin(); int candidateIndex = tri::Index(this->mesh,candidate);
assert(id != edge.v0 && id != edge.v1); assert(candidateIndex != edge.v0 && candidateIndex != edge.v1);
Point3x newnormal = ((candidate->P() - v0)^(v1 - v0)).Normalize(); 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; return -1;
} }
//test if id is in some border (to return touch //test if id is in some border (to return touch
for(std::list<FrontEdge>::iterator k = this->front.begin(); k != this->front.end(); k++) for(std::list<FrontEdge>::iterator k = this->front.begin(); k != this->front.end(); k++)
{ {
if((*k).v0 == id) if((*k).v0 == candidateIndex)
{ {
touch.first = AdvancingFront<MESH>::FRONT; touch.first = AdvancingFront<MESH>::FRONT;
touch.second = k; touch.second = k;
} }
} }
for(std::list<FrontEdge>::iterator k = this->deads.begin(); k != this->deads.end(); k++) for(std::list<FrontEdge>::iterator k = this->deads.begin(); k != this->deads.end(); k++)
{ {
if((*k).v0 == id) if((*k).v0 == candidateIndex)
{ {
touch.first = AdvancingFront<MESH>::DEADS; touch.first = AdvancingFront<MESH>::DEADS;
touch.second = k; touch.second = k;
} }
} }
//mark vertices close to candidate //mark vertices close to candidate
Mark(candidate); Mark(candidate);
return id; return candidateIndex;
} }
private: private:
@ -341,7 +342,7 @@ template <class MESH> class BallPivoting: public AdvancingFront<MESH> {
/* returns the sphere touching p0, p1, p2 of radius r such that /* returns the sphere touching p0, p1, p2 of radius r such that
the normal of the face points toward the center of the sphere */ the normal of the face points toward the center of the sphere */
bool FindSphere(Point3x &p0, Point3x &p1, Point3x &p2, Point3x &center) { bool FindSphere(const Point3x &p0, const Point3x &p1, const Point3x &p2, Point3x &center) {
//we want p0 to be always the smallest one. //we want p0 to be always the smallest one.
Point3x p[3]; Point3x p[3];
@ -392,7 +393,7 @@ template <class MESH> class BallPivoting: public AdvancingFront<MESH> {
} }
/* compute angle from p to q, using axis for orientation */ /* 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(); p.Normalize();
q.Normalize(); q.Normalize();
Point3x vec = p^q; Point3x vec = p^q;