Commenting and cleaning up the ball pivoting/ advancing front framework
This commit is contained in:
parent
b6e2315d73
commit
e268e69ad3
|
@ -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<FrontEdge>::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 MESH> 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<FrontEdge>::iterator up = NewEdge(FrontEdge(v2, v1, v0, mesh.face.size()));
|
||||
std::list<FrontEdge>::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<FrontEdge>::iterator up = NewEdge(FrontEdge(v0, v2, v1, mesh.face.size()));
|
||||
std::list<FrontEdge>::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<FrontEdge>::iterator down = NewEdge(FrontEdge(v2, v1, v0, mesh.face.size()));
|
||||
std::list<FrontEdge>::iterator up = NewEdge(FrontEdge(v0, v2, v1, mesh.face.size()));
|
||||
std::list<FrontEdge>::iterator down = addNewEdge(FrontEdge(v2, v1, v0));
|
||||
std::list<FrontEdge>::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<FrontEdge>::iterator down = NewEdge(FrontEdge(v2, v1, v0, mesh.face.size()));
|
||||
std::list<FrontEdge>::iterator up = NewEdge(FrontEdge(v0, v2, v1, mesh.face.size()));
|
||||
std::list<FrontEdge>::iterator down = addNewEdge(FrontEdge(v2, v1, v0));
|
||||
std::list<FrontEdge>::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<MESH>::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<FrontEdge>::iterator NewEdge(FrontEdge e) {
|
||||
std::list<FrontEdge>::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<FrontEdge>::iterator e) {
|
||||
|
|
|
@ -25,8 +25,8 @@ template <class MESH> class BallPivoting: public AdvancingFront<MESH> {
|
|||
typedef GridStaticPtr<typename MESH::VertexType, typename MESH::ScalarType > 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 MESH> class BallPivoting: public AdvancingFront<MESH> {
|
|||
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<MESH>::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<MESH>::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 MESH> class BallPivoting: public AdvancingFront<MESH> {
|
|||
// 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<VertexType *> targets;
|
||||
std::vector<VertexType *> targets; // The vector of
|
||||
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);
|
||||
|
||||
|
@ -242,21 +242,22 @@ template <class MESH> class BallPivoting: public AdvancingFront<MESH> {
|
|||
|
||||
VertexType *candidate = NULL;
|
||||
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];
|
||||
int id = v - &*this->mesh.vert.begin();
|
||||
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 MESH> class BallPivoting: public AdvancingFront<MESH> {
|
|||
}
|
||||
|
||||
/* 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. */
|
||||
|
@ -299,35 +300,35 @@ template <class MESH> class BallPivoting: public AdvancingFront<MESH> {
|
|||
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<FrontEdge>::iterator k = this->front.begin(); k != this->front.end(); k++)
|
||||
{
|
||||
if((*k).v0 == id)
|
||||
{
|
||||
touch.first = AdvancingFront<MESH>::FRONT;
|
||||
touch.second = k;
|
||||
}
|
||||
}
|
||||
for(std::list<FrontEdge>::iterator k = this->deads.begin(); k != this->deads.end(); k++)
|
||||
{
|
||||
if((*k).v0 == id)
|
||||
{
|
||||
touch.first = AdvancingFront<MESH>::DEADS;
|
||||
touch.second = k;
|
||||
}
|
||||
}
|
||||
//test if id is in some border (to return touch
|
||||
for(std::list<FrontEdge>::iterator k = this->front.begin(); k != this->front.end(); k++)
|
||||
{
|
||||
if((*k).v0 == candidateIndex)
|
||||
{
|
||||
touch.first = AdvancingFront<MESH>::FRONT;
|
||||
touch.second = k;
|
||||
}
|
||||
}
|
||||
for(std::list<FrontEdge>::iterator k = this->deads.begin(); k != this->deads.end(); k++)
|
||||
{
|
||||
if((*k).v0 == candidateIndex)
|
||||
{
|
||||
touch.first = AdvancingFront<MESH>::DEADS;
|
||||
touch.second = k;
|
||||
}
|
||||
}
|
||||
|
||||
//mark vertices close to candidate
|
||||
Mark(candidate);
|
||||
return id;
|
||||
return candidateIndex;
|
||||
}
|
||||
|
||||
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
|
||||
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 MESH> class BallPivoting: public AdvancingFront<MESH> {
|
|||
}
|
||||
|
||||
/* 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;
|
||||
|
|
Loading…
Reference in New Issue