Added a number of 'template' and 'typename' keyword to comply clang...
This commit is contained in:
parent
3f1b4519b5
commit
9a48f16579
|
|
@ -41,292 +41,294 @@ class ConvexHull
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
typedef typename InputMesh::ScalarType ScalarType;
|
typedef typename InputMesh::ScalarType ScalarType;
|
||||||
typedef typename InputMesh::VertexPointer InputVertexPointer;
|
typedef typename InputMesh::VertexPointer InputVertexPointer;
|
||||||
typedef typename InputMesh::VertexIterator InputVertexIterator;
|
typedef typename InputMesh::VertexIterator InputVertexIterator;
|
||||||
typedef typename CHMesh::VertexIterator CHVertexIterator;
|
typedef typename CHMesh::VertexIterator CHVertexIterator;
|
||||||
typedef typename CHMesh::VertexPointer CHVertexPointer;
|
typedef typename CHMesh::VertexPointer CHVertexPointer;
|
||||||
typedef typename CHMesh::FaceIterator CHFaceIterator;
|
typedef typename CHMesh::FaceIterator CHFaceIterator;
|
||||||
typedef typename CHMesh::FacePointer CHFacePointer;
|
typedef typename CHMesh::FacePointer CHFacePointer;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
typedef std::pair<InputVertexPointer, ScalarType> Pair;
|
typedef std::pair<InputVertexPointer, ScalarType> Pair;
|
||||||
|
|
||||||
|
|
||||||
// Initialize the convex hull with the biggest tetraedron created using the vertices of the input mesh
|
|
||||||
static void InitConvexHull(InputMesh& mesh, CHMesh& convexHull)
|
|
||||||
{
|
|
||||||
CMesh::PerVertexAttributeHandle<ScalarType> indexInputVertex = vcg::tri::Allocator<InputMesh>::GetPerVertexAttribute<ScalarType>(mesh, std::string("indexInput"));
|
|
||||||
InputVertexPointer v[3];
|
|
||||||
//Find the 6 points with min/max coordinate values
|
|
||||||
InputVertexIterator vi = mesh.vert.begin();
|
|
||||||
std::vector<InputVertexPointer> minMax(6, &(*vi));
|
|
||||||
for (; vi != mesh.vert.end(); vi++)
|
|
||||||
{
|
|
||||||
if ((*vi).P().X() < (*minMax[0]).P().X())
|
|
||||||
minMax[0] = &(*vi);
|
|
||||||
if ((*vi).P().Y() < (*minMax[1]).P().Y())
|
|
||||||
minMax[1] = &(*vi);
|
|
||||||
if ((*vi).P().Z() < (*minMax[2]).P().Z())
|
|
||||||
minMax[2] = &(*vi);
|
|
||||||
if ((*vi).P().X() > (*minMax[3]).P().X())
|
|
||||||
minMax[3] = &(*vi);
|
|
||||||
if ((*vi).P().Y() > (*minMax[4]).P().Y())
|
|
||||||
minMax[4] = &(*vi);
|
|
||||||
if ((*vi).P().Z() > (*minMax[5]).P().Z())
|
|
||||||
minMax[5] = &(*vi);
|
|
||||||
}
|
|
||||||
//Find the farthest two points
|
|
||||||
ScalarType maxDist = 0;
|
|
||||||
for (int i = 0; i < 6; i++)
|
|
||||||
{
|
|
||||||
for (int j = i + 1; j < 6; j++)
|
|
||||||
{
|
|
||||||
float dist = (minMax[i]->P() - minMax[j]->P()).SquaredNorm();
|
|
||||||
if (dist > maxDist)
|
|
||||||
{
|
|
||||||
maxDist = dist;
|
|
||||||
v[0] = minMax[i];
|
|
||||||
v[1] = minMax[j];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
//Find the third point to create the base of the tetrahedron
|
|
||||||
vcg::Line3<ScalarType> line(v[0]->P(), (v[0]->P() - v[1]->P()));
|
|
||||||
maxDist = 0;
|
|
||||||
for (vi = mesh.vert.begin(); vi != mesh.vert.end(); vi++)
|
|
||||||
{
|
|
||||||
ScalarType dist = vcg::Distance(line, (*vi).P());
|
|
||||||
if (dist > maxDist)
|
|
||||||
{
|
|
||||||
maxDist = dist;
|
|
||||||
v[2] = &(*vi);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
//Create face in the convex hull
|
|
||||||
CHVertexIterator chVi = vcg::tri::Allocator<CHMesh>::AddVertices(convexHull, 3);
|
|
||||||
for (int i = 0; i < 3; i++)
|
|
||||||
{
|
|
||||||
(*chVi).P().Import(v[i]->P());
|
|
||||||
indexInputVertex[chVi] = vcg::tri::Index(mesh, v[i]);
|
|
||||||
chVi++;
|
|
||||||
}
|
|
||||||
CHFaceIterator fi = vcg::tri::Allocator<CHMesh>::AddFace(convexHull, 0, 1, 2);
|
|
||||||
(*fi).N() = vcg::NormalizedTriangleNormal(*fi);
|
|
||||||
|
|
||||||
//Find the fourth point to create the tetrahedron
|
// Initialize the convex hull with the biggest tetraedron created using the vertices of the input mesh
|
||||||
InputVertexPointer v4;
|
static void InitConvexHull(InputMesh& mesh, CHMesh& convexHull)
|
||||||
float distance = 0;
|
{
|
||||||
float absDist = -1;
|
typename CHMesh:: template PerVertexAttributeHandle<int> indexInputVertex = Allocator<InputMesh>::template GetPerVertexAttribute<int>(mesh, std::string("indexInput"));
|
||||||
for (vi = mesh.vert.begin(); vi != mesh.vert.end(); vi++)
|
InputVertexPointer v[3];
|
||||||
{
|
//Find the 6 points with min/max coordinate values
|
||||||
float tempDist = ((*vi).P() - (*fi).P(0)).dot((*fi).N());
|
InputVertexIterator vi = mesh.vert.begin();
|
||||||
if (abs(tempDist) > absDist)
|
std::vector<InputVertexPointer> minMax(6, &(*vi));
|
||||||
{
|
for (; vi != mesh.vert.end(); vi++)
|
||||||
distance = tempDist;
|
{
|
||||||
v4 = &(*vi);
|
if ((*vi).P().X() < (*minMax[0]).P().X())
|
||||||
absDist = abs(distance);
|
minMax[0] = &(*vi);
|
||||||
}
|
if ((*vi).P().Y() < (*minMax[1]).P().Y())
|
||||||
}
|
minMax[1] = &(*vi);
|
||||||
|
if ((*vi).P().Z() < (*minMax[2]).P().Z())
|
||||||
|
minMax[2] = &(*vi);
|
||||||
|
if ((*vi).P().X() > (*minMax[3]).P().X())
|
||||||
|
minMax[3] = &(*vi);
|
||||||
|
if ((*vi).P().Y() > (*minMax[4]).P().Y())
|
||||||
|
minMax[4] = &(*vi);
|
||||||
|
if ((*vi).P().Z() > (*minMax[5]).P().Z())
|
||||||
|
minMax[5] = &(*vi);
|
||||||
|
}
|
||||||
|
//Find the farthest two points
|
||||||
|
ScalarType maxDist = 0;
|
||||||
|
for (int i = 0; i < 6; i++)
|
||||||
|
{
|
||||||
|
for (int j = i + 1; j < 6; j++)
|
||||||
|
{
|
||||||
|
float dist = (minMax[i]->P() - minMax[j]->P()).SquaredNorm();
|
||||||
|
if (dist > maxDist)
|
||||||
|
{
|
||||||
|
maxDist = dist;
|
||||||
|
v[0] = minMax[i];
|
||||||
|
v[1] = minMax[j];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//Find the third point to create the base of the tetrahedron
|
||||||
|
vcg::Line3<ScalarType> line(v[0]->P(), (v[0]->P() - v[1]->P()));
|
||||||
|
maxDist = 0;
|
||||||
|
for (vi = mesh.vert.begin(); vi != mesh.vert.end(); vi++)
|
||||||
|
{
|
||||||
|
ScalarType dist = vcg::Distance(line, (*vi).P());
|
||||||
|
if (dist > maxDist)
|
||||||
|
{
|
||||||
|
maxDist = dist;
|
||||||
|
v[2] = &(*vi);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//Create face in the convex hull
|
||||||
|
CHVertexIterator chVi = vcg::tri::Allocator<CHMesh>::AddVertices(convexHull, 3);
|
||||||
|
for (int i = 0; i < 3; i++)
|
||||||
|
{
|
||||||
|
(*chVi).P().Import(v[i]->P());
|
||||||
|
indexInputVertex[chVi] = vcg::tri::Index(mesh, v[i]);
|
||||||
|
chVi++;
|
||||||
|
}
|
||||||
|
CHFaceIterator fi = vcg::tri::Allocator<CHMesh>::AddFace(convexHull, 0, 1, 2);
|
||||||
|
(*fi).N() = vcg::NormalizedTriangleNormal(*fi);
|
||||||
|
|
||||||
//Flip the previous face if the fourth point is above the face
|
//Find the fourth point to create the tetrahedron
|
||||||
if (distance > 0)
|
InputVertexPointer v4;
|
||||||
{
|
float distance = 0;
|
||||||
(*fi).N() = -(*fi).N();
|
float absDist = -1;
|
||||||
CHVertexPointer tempV = (*fi).V(1);
|
for (vi = mesh.vert.begin(); vi != mesh.vert.end(); vi++)
|
||||||
(*fi).V(1) = (*fi).V(2);
|
{
|
||||||
(*fi).V(2) = tempV;
|
float tempDist = ((*vi).P() - (*fi).P(0)).dot((*fi).N());
|
||||||
}
|
if (abs(tempDist) > absDist)
|
||||||
|
{
|
||||||
//Create the other 3 faces of the tetrahedron
|
distance = tempDist;
|
||||||
chVi = vcg::tri::Allocator<CHMesh>::AddVertices(convexHull, 1);
|
v4 = &(*vi);
|
||||||
(*chVi).P().Import(v4->P());
|
absDist = abs(distance);
|
||||||
indexInputVertex[chVi] = vcg::tri::Index(mesh, v4);
|
}
|
||||||
fi = vcg::tri::Allocator<CHMesh>::AddFace(convexHull, &convexHull.vert[3], convexHull.face[0].V0(1), convexHull.face[0].V0(0));
|
}
|
||||||
(*fi).N() = vcg::NormalizedTriangleNormal(*fi);
|
|
||||||
fi = vcg::tri::Allocator<CHMesh>::AddFace(convexHull, &convexHull.vert[3], convexHull.face[0].V1(1), convexHull.face[0].V1(0));
|
//Flip the previous face if the fourth point is above the face
|
||||||
(*fi).N() = vcg::NormalizedTriangleNormal(*fi);
|
if (distance > 0)
|
||||||
fi = vcg::tri::Allocator<CHMesh>::AddFace(convexHull, &convexHull.vert[3], convexHull.face[0].V2(1), convexHull.face[0].V2(0));
|
{
|
||||||
(*fi).N() = vcg::NormalizedTriangleNormal(*fi);
|
(*fi).N() = -(*fi).N();
|
||||||
vcg::tri::UpdateTopology<CHMesh>::FaceFace(convexHull);
|
CHVertexPointer tempV = (*fi).V(1);
|
||||||
};
|
(*fi).V(1) = (*fi).V(2);
|
||||||
|
(*fi).V(2) = tempV;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Create the other 3 faces of the tetrahedron
|
||||||
|
chVi = vcg::tri::Allocator<CHMesh>::AddVertices(convexHull, 1);
|
||||||
|
(*chVi).P().Import(v4->P());
|
||||||
|
indexInputVertex[chVi] = vcg::tri::Index(mesh, v4);
|
||||||
|
fi = vcg::tri::Allocator<CHMesh>::AddFace(convexHull, &convexHull.vert[3], convexHull.face[0].V0(1), convexHull.face[0].V0(0));
|
||||||
|
(*fi).N() = vcg::NormalizedTriangleNormal(*fi);
|
||||||
|
fi = vcg::tri::Allocator<CHMesh>::AddFace(convexHull, &convexHull.vert[3], convexHull.face[0].V1(1), convexHull.face[0].V1(0));
|
||||||
|
(*fi).N() = vcg::NormalizedTriangleNormal(*fi);
|
||||||
|
fi = vcg::tri::Allocator<CHMesh>::AddFace(convexHull, &convexHull.vert[3], convexHull.face[0].V2(1), convexHull.face[0].V2(0));
|
||||||
|
(*fi).N() = vcg::NormalizedTriangleNormal(*fi);
|
||||||
|
vcg::tri::UpdateTopology<CHMesh>::FaceFace(convexHull);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Return the convex hull of the input mesh using the Quickhull algorithm.
|
Return the convex hull of the input mesh using the Quickhull algorithm.
|
||||||
For each vertex of the convex hull the algorithm stores the vertex index
|
For each vertex of the convex hull the algorithm stores the vertex index
|
||||||
of the original mesh in attribute "indexInput".
|
of the original mesh in attribute "indexInput".
|
||||||
|
|
||||||
|
"The quickhull algorithm for convex hulls" by C. Bradford Barber et al.
|
||||||
|
ACM Transactions on Mathematical Software, Volume 22 Issue 4, Dec. 1996
|
||||||
|
*/
|
||||||
|
static bool ComputeConvexHull(InputMesh& mesh, CHMesh& convexHull)
|
||||||
|
{
|
||||||
|
vcg::tri::RequireFFAdjacency(convexHull);
|
||||||
|
vcg::tri::RequirePerFaceNormal(convexHull);
|
||||||
|
vcg::tri::Allocator<InputMesh>::CompactVertexVector(mesh);
|
||||||
|
typename CHMesh:: template PerVertexAttributeHandle<int> indexInputVertex = Allocator<InputMesh>::template GetPerVertexAttribute<int>(mesh, std::string("indexInput"));
|
||||||
|
if (mesh.vert.size() < 4)
|
||||||
|
return false;
|
||||||
|
InitConvexHull(mesh, convexHull);
|
||||||
|
|
||||||
|
//Build list of visible vertices for each convex hull face and find the furthest vertex for each face
|
||||||
|
std::vector<std::vector<InputVertexPointer>> listVertexPerFace(convexHull.face.size());
|
||||||
|
std::vector<Pair> furthestVexterPerFace(convexHull.face.size(), std::make_pair((InputVertexPointer)NULL, 0.0f));
|
||||||
|
for (int i = 0; i < mesh.vert.size(); i++)
|
||||||
|
{
|
||||||
|
ScalarType maxDist = 0;
|
||||||
|
for (int j = 0; j < convexHull.face.size(); j++)
|
||||||
|
{
|
||||||
|
ScalarType dist = (mesh.vert[i].P() - convexHull.face[j].P(0)).dot(convexHull.face[j].N());
|
||||||
|
if (dist > 0)
|
||||||
|
{
|
||||||
|
listVertexPerFace[j].push_back(&mesh.vert[i]);
|
||||||
|
if (dist > furthestVexterPerFace[j].second)
|
||||||
|
{
|
||||||
|
furthestVexterPerFace[j].second = dist;
|
||||||
|
furthestVexterPerFace[j].first = &mesh.vert[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < listVertexPerFace.size(); i++)
|
||||||
|
{
|
||||||
|
if (listVertexPerFace[i].size() > 0)
|
||||||
|
{
|
||||||
|
//Find faces to remove and face on the border where to connect the new fan faces
|
||||||
|
InputVertexPointer vertex = furthestVexterPerFace[i].first;
|
||||||
|
std::queue<int> queue;
|
||||||
|
std::vector<int> visFace;
|
||||||
|
std::vector<int> borderFace;
|
||||||
|
visFace.push_back(i);
|
||||||
|
queue.push(i);
|
||||||
|
while (queue.size() > 0)
|
||||||
|
{
|
||||||
|
CHFacePointer fp = &convexHull.face[queue.front()];
|
||||||
|
queue.pop();
|
||||||
|
fp->SetV();
|
||||||
|
for (int ii = 0; ii < 3; ii++)
|
||||||
|
{
|
||||||
|
CHFacePointer nextF = fp->FFp(ii);
|
||||||
|
if (!nextF->IsV())
|
||||||
|
{
|
||||||
|
int indexF = vcg::tri::Index(convexHull, nextF);
|
||||||
|
ScalarType dist = (vertex->P() - nextF->P(0)).dot(nextF->N());
|
||||||
|
if (dist < 0)
|
||||||
|
{
|
||||||
|
borderFace.push_back(indexF);
|
||||||
|
fp->SetB(ii);
|
||||||
|
nextF->SetB(fp->FFi(ii));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
visFace.push_back(indexF);
|
||||||
|
queue.push(indexF);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (borderFace.size() > 0)
|
||||||
|
{
|
||||||
|
CHVertexIterator vi = vcg::tri::Allocator<CHMesh>::AddVertices(convexHull, 1);
|
||||||
|
(*vi).P().Import((*vertex).P());
|
||||||
|
indexInputVertex[vi] = vcg::tri::Index(mesh, vertex);
|
||||||
|
}
|
||||||
|
|
||||||
|
//Add a new face for each border
|
||||||
|
std::unordered_map< CHVertexPointer, std::pair<int, char> > fanMap;
|
||||||
|
for (int jj = 0; jj < borderFace.size(); jj++)
|
||||||
|
{
|
||||||
|
int indexFace = borderFace[jj];
|
||||||
|
CHFacePointer f = &convexHull.face[indexFace];
|
||||||
|
for (int j = 0; j < 3; j++)
|
||||||
|
{
|
||||||
|
if (f->IsB(j))
|
||||||
|
{
|
||||||
|
f->ClearB(j);
|
||||||
|
//Add new face
|
||||||
|
CHFaceIterator fi = vcg::tri::Allocator<CHMesh>::AddFace(convexHull, &convexHull.vert.back(), f->V1(j), f->V0(j));
|
||||||
|
(*fi).N() = vcg::NormalizedTriangleNormal(*fi);
|
||||||
|
f = &convexHull.face[indexFace];
|
||||||
|
int newFace = vcg::tri::Index(convexHull, *fi);
|
||||||
|
//Update convex hull FF topology
|
||||||
|
CHVertexPointer vp[] = { f->V1(j), f->V0(j) };
|
||||||
|
for (int ii = 0; ii < 2; ii++)
|
||||||
|
{
|
||||||
|
int indexE = ii * 2;
|
||||||
|
typename std::unordered_map< CHVertexPointer, std::pair<int, char> >::iterator vIter = fanMap.find(vp[ii]);
|
||||||
|
if (vIter != fanMap.end())
|
||||||
|
{
|
||||||
|
CHFacePointer f2 = &convexHull.face[(*vIter).second.first];
|
||||||
|
char edgeIndex = (*vIter).second.second;
|
||||||
|
f2->FFp(edgeIndex) = &convexHull.face.back();
|
||||||
|
f2->FFi(edgeIndex) = indexE;
|
||||||
|
fi->FFp(indexE) = f2;
|
||||||
|
fi->FFi(indexE) = edgeIndex;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
fanMap[vp[ii]] = std::make_pair(newFace, indexE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//Build the visibility list for the new face
|
||||||
|
std::vector<InputVertexPointer> tempVect;
|
||||||
|
int indices[2] = { indexFace, int(vcg::tri::Index(convexHull, f->FFp(j)) )};
|
||||||
|
std::vector<InputVertexPointer> vertexToTest(listVertexPerFace[indices[0]].size() + listVertexPerFace[indices[1]].size());
|
||||||
|
typename std::vector<InputVertexPointer>::iterator tempIt = std::set_union(listVertexPerFace[indices[0]].begin(), listVertexPerFace[indices[0]].end(), listVertexPerFace[indices[1]].begin(), listVertexPerFace[indices[1]].end(), vertexToTest.begin());
|
||||||
|
vertexToTest.resize(tempIt - vertexToTest.begin());
|
||||||
|
ScalarType maxDist = 0;
|
||||||
|
Pair newInfo = std::make_pair((InputVertexPointer)NULL , 0.0f);
|
||||||
|
for (int ii = 0; ii < vertexToTest.size(); ii++)
|
||||||
|
{
|
||||||
|
float dist = ((*vertexToTest[ii]).P() - (*fi).P(0)).dot((*fi).N());
|
||||||
|
if (dist > 0)
|
||||||
|
{
|
||||||
|
tempVect.push_back(vertexToTest[ii]);
|
||||||
|
if (dist > newInfo.second)
|
||||||
|
{
|
||||||
|
newInfo.second = dist;
|
||||||
|
newInfo.first = vertexToTest[ii];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
listVertexPerFace.push_back(tempVect);
|
||||||
|
furthestVexterPerFace.push_back(newInfo);
|
||||||
|
//Update topology of the new face
|
||||||
|
CHFacePointer ffp = f->FFp(j);
|
||||||
|
int ffi = f->FFi(j);
|
||||||
|
ffp->FFp(ffi) = ffp;
|
||||||
|
ffp->FFi(ffi) = ffi;
|
||||||
|
f->FFp(j) = &convexHull.face.back();
|
||||||
|
f->FFi(j) = 1;
|
||||||
|
fi->FFp(1) = f;
|
||||||
|
fi->FFi(1) = j;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//Delete the faces inside the updated convex hull
|
||||||
|
for (int j = 0; j < visFace.size(); j++)
|
||||||
|
{
|
||||||
|
if (!convexHull.face[visFace[j]].IsD())
|
||||||
|
{
|
||||||
|
std::vector<InputVertexPointer> emptyVec;
|
||||||
|
vcg::tri::Allocator<CHMesh>::DeleteFace(convexHull, convexHull.face[visFace[j]]);
|
||||||
|
listVertexPerFace[visFace[j]].swap(emptyVec);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
tri::UpdateTopology<CHMesh>::ClearFaceFace(convexHull);
|
||||||
|
vcg::tri::Allocator<CHMesh>::CompactFaceVector(convexHull);
|
||||||
|
vcg::tri::Clean<CHMesh>::RemoveUnreferencedVertex(convexHull);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
"The quickhull algorithm for convex hulls" by C. Bradford Barber et al.
|
|
||||||
ACM Transactions on Mathematical Software, Volume 22 Issue 4, Dec. 1996
|
|
||||||
*/
|
|
||||||
static bool ComputeConvexHull(InputMesh& mesh, CHMesh& convexHull)
|
|
||||||
{
|
|
||||||
vcg::tri::RequireFFAdjacency(convexHull);
|
|
||||||
vcg::tri::RequirePerFaceNormal(convexHull);
|
|
||||||
vcg::tri::Allocator<InputMesh>::CompactVertexVector(mesh);
|
|
||||||
CMesh::PerVertexAttributeHandle<ScalarType> indexInputVertex = vcg::tri::Allocator<InputMesh>::GetPerVertexAttribute<ScalarType>(mesh, std::string("indexInput"));
|
|
||||||
if (mesh.vert.size() < 4)
|
|
||||||
return false;
|
|
||||||
InitConvexHull(mesh, convexHull);
|
|
||||||
|
|
||||||
//Build list of visible vertices for each convex hull face and find the furthest vertex for each face
|
|
||||||
std::vector<std::vector<InputVertexPointer>> listVertexPerFace(convexHull.face.size());
|
|
||||||
std::vector<Pair> furthestVexterPerFace(convexHull.face.size(), std::make_pair((InputVertexPointer)NULL, 0.0f));
|
|
||||||
for (int i = 0; i < mesh.vert.size(); i++)
|
|
||||||
{
|
|
||||||
ScalarType maxDist = 0;
|
|
||||||
for (int j = 0; j < convexHull.face.size(); j++)
|
|
||||||
{
|
|
||||||
ScalarType dist = (mesh.vert[i].P() - convexHull.face[j].P(0)).dot(convexHull.face[j].N());
|
|
||||||
if (dist > 0)
|
|
||||||
{
|
|
||||||
listVertexPerFace[j].push_back(&mesh.vert[i]);
|
|
||||||
if (dist > furthestVexterPerFace[j].second)
|
|
||||||
{
|
|
||||||
furthestVexterPerFace[j].second = dist;
|
|
||||||
furthestVexterPerFace[j].first = &mesh.vert[i];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int i = 0; i < listVertexPerFace.size(); i++)
|
|
||||||
{
|
|
||||||
if (listVertexPerFace[i].size() > 0)
|
|
||||||
{
|
|
||||||
//Find faces to remove and face on the border where to connect the new fan faces
|
|
||||||
InputVertexPointer vertex = furthestVexterPerFace[i].first;
|
|
||||||
std::queue<int> queue;
|
|
||||||
std::vector<int> visFace;
|
|
||||||
std::vector<int> borderFace;
|
|
||||||
visFace.push_back(i);
|
|
||||||
queue.push(i);
|
|
||||||
while (queue.size() > 0)
|
|
||||||
{
|
|
||||||
CHFacePointer fp = &convexHull.face[queue.front()];
|
|
||||||
queue.pop();
|
|
||||||
fp->SetV();
|
|
||||||
for (int ii = 0; ii < 3; ii++)
|
|
||||||
{
|
|
||||||
CHFacePointer nextF = fp->FFp(ii);
|
|
||||||
if (!nextF->IsV())
|
|
||||||
{
|
|
||||||
int indexF = vcg::tri::Index(convexHull, nextF);
|
|
||||||
ScalarType dist = (vertex->P() - nextF->P(0)).dot(nextF->N());
|
|
||||||
if (dist < 0)
|
|
||||||
{
|
|
||||||
borderFace.push_back(indexF);
|
|
||||||
fp->SetB(ii);
|
|
||||||
nextF->SetB(fp->FFi(ii));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
visFace.push_back(indexF);
|
|
||||||
queue.push(indexF);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (borderFace.size() > 0)
|
|
||||||
{
|
|
||||||
CHVertexIterator vi = vcg::tri::Allocator<CHMesh>::AddVertices(convexHull, 1);
|
|
||||||
(*vi).P().Import((*vertex).P());
|
|
||||||
indexInputVertex[vi] = vcg::tri::Index(mesh, vertex);
|
|
||||||
}
|
|
||||||
|
|
||||||
//Add a new face for each border
|
|
||||||
std::unordered_map< CHVertexPointer, std::pair<int, char> > fanMap;
|
|
||||||
for (int jj = 0; jj < borderFace.size(); jj++)
|
|
||||||
{
|
|
||||||
int indexFace = borderFace[jj];
|
|
||||||
CHFacePointer f = &convexHull.face[indexFace];
|
|
||||||
for (int j = 0; j < 3; j++)
|
|
||||||
{
|
|
||||||
if (f->IsB(j))
|
|
||||||
{
|
|
||||||
f->ClearB(j);
|
|
||||||
//Add new face
|
|
||||||
CHFaceIterator fi = vcg::tri::Allocator<CHMesh>::AddFace(convexHull, &convexHull.vert.back(), f->V1(j), f->V0(j));
|
|
||||||
(*fi).N() = vcg::NormalizedTriangleNormal(*fi);
|
|
||||||
f = &convexHull.face[indexFace];
|
|
||||||
int newFace = vcg::tri::Index(convexHull, *fi);
|
|
||||||
//Update convex hull FF topology
|
|
||||||
CHVertexPointer vp[] = { f->V1(j), f->V0(j) };
|
|
||||||
for (int ii = 0; ii < 2; ii++)
|
|
||||||
{
|
|
||||||
int indexE = ii * 2;
|
|
||||||
std::unordered_map< CHVertexPointer, std::pair<int, char> >::iterator vIter = fanMap.find(vp[ii]);
|
|
||||||
if (vIter != fanMap.end())
|
|
||||||
{
|
|
||||||
CHFacePointer f2 = &convexHull.face[(*vIter).second.first];
|
|
||||||
char edgeIndex = (*vIter).second.second;
|
|
||||||
f2->FFp(edgeIndex) = &convexHull.face.back();
|
|
||||||
f2->FFi(edgeIndex) = indexE;
|
|
||||||
fi->FFp(indexE) = f2;
|
|
||||||
fi->FFi(indexE) = edgeIndex;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
fanMap[vp[ii]] = std::make_pair(newFace, indexE);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
//Build the visibility list for the new face
|
|
||||||
std::vector<InputVertexPointer> tempVect;
|
|
||||||
int indices[] = { indexFace, vcg::tri::Index(convexHull, f->FFp(j)) };
|
|
||||||
std::vector<InputVertexPointer> vertexToTest(listVertexPerFace[indices[0]].size() + listVertexPerFace[indices[1]].size());
|
|
||||||
std::vector<InputVertexPointer>::iterator tempIt = std::set_union(listVertexPerFace[indices[0]].begin(), listVertexPerFace[indices[0]].end(), listVertexPerFace[indices[1]].begin(), listVertexPerFace[indices[1]].end(), vertexToTest.begin());
|
|
||||||
vertexToTest.resize(tempIt - vertexToTest.begin());
|
|
||||||
ScalarType maxDist = 0;
|
|
||||||
Pair newInfo = std::make_pair((InputVertexPointer)NULL , 0.0f);
|
|
||||||
for (int ii = 0; ii < vertexToTest.size(); ii++)
|
|
||||||
{
|
|
||||||
float dist = ((*vertexToTest[ii]).P() - (*fi).P(0)).dot((*fi).N());
|
|
||||||
if (dist > 0)
|
|
||||||
{
|
|
||||||
tempVect.push_back(vertexToTest[ii]);
|
|
||||||
if (dist > newInfo.second)
|
|
||||||
{
|
|
||||||
newInfo.second = dist;
|
|
||||||
newInfo.first = vertexToTest[ii];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
listVertexPerFace.push_back(tempVect);
|
|
||||||
furthestVexterPerFace.push_back(newInfo);
|
|
||||||
//Update topology of the new face
|
|
||||||
CHFacePointer ffp = f->FFp(j);
|
|
||||||
int ffi = f->FFi(j);
|
|
||||||
ffp->FFp(ffi) = ffp;
|
|
||||||
ffp->FFi(ffi) = ffi;
|
|
||||||
f->FFp(j) = &convexHull.face.back();
|
|
||||||
f->FFi(j) = 1;
|
|
||||||
fi->FFp(1) = f;
|
|
||||||
fi->FFi(1) = j;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
//Delete the faces inside the updated convex hull
|
|
||||||
for (int j = 0; j < visFace.size(); j++)
|
|
||||||
{
|
|
||||||
if (!convexHull.face[visFace[j]].IsD())
|
|
||||||
{
|
|
||||||
vcg::tri::Allocator<CHMesh>::DeleteFace(convexHull, convexHull.face[visFace[j]]);
|
|
||||||
listVertexPerFace[visFace[j]].swap(std::vector<InputVertexPointer>());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
vcg::tri::Allocator<CHMesh>::CompactFaceVector(convexHull);
|
|
||||||
vcg::tri::Clean<CHMesh>::RemoveUnreferencedVertex(convexHull);
|
|
||||||
return true;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // end namespace tri
|
} // end namespace tri
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue