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 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) {
|
||||||
|
|
|
@ -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 ¢er) {
|
bool FindSphere(const Point3x &p0, const Point3x &p1, const Point3x &p2, Point3x ¢er) {
|
||||||
//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;
|
||||||
|
|
Loading…
Reference in New Issue