Fixed a weird bug that caused wrong check on self-intersections and polychord's adjacency.
This commit is contained in:
parent
ee3177b1d9
commit
b179459e62
|
|
@ -68,14 +68,15 @@ public:
|
||||||
* @brief The PC_ResultCode enum codifies the result type of a polychord collapse operation.
|
* @brief The PC_ResultCode enum codifies the result type of a polychord collapse operation.
|
||||||
*/
|
*/
|
||||||
enum PC_ResultCode {
|
enum PC_ResultCode {
|
||||||
PC_SUCCESS = 0,
|
PC_SUCCESS = 0x00,
|
||||||
PC_NOTMANIF = 1,
|
PC_NOTMANIF = 0x01,
|
||||||
PC_NOTQUAD = 2,
|
PC_NOTQUAD = 0x02,
|
||||||
PC_NOLINKCOND = 4,
|
PC_NOLINKCOND = 0x04,
|
||||||
PC_SINGBOTH = 8,
|
PC_SINGBOTH = 0x08,
|
||||||
PC_SELFINTERSECT = 16,
|
PC_SELFINTERSECT = 0x10,
|
||||||
PC_VOID = 32,
|
PC_NOMOREMANIF = 0x20,
|
||||||
PC_OTHER = 64
|
PC_VOID = 0x30,
|
||||||
|
PC_OTHER = 0x40
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -112,9 +113,8 @@ public:
|
||||||
* @brief ResetMarks
|
* @brief ResetMarks
|
||||||
*/
|
*/
|
||||||
void ResetMarks() {
|
void ResetMarks() {
|
||||||
typename std::vector<PC_Chord>::iterator it = _Chords.begin();
|
for (size_t i = 0; i < _Chords.size(); ++i)
|
||||||
for (; it != _Chords.end(); it++)
|
_Chords.at(i).mark = std::numeric_limits<unsigned long>::max();
|
||||||
(*it).mark = std::numeric_limits<unsigned long>::max();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -124,13 +124,13 @@ public:
|
||||||
*/
|
*/
|
||||||
void Reset(const PolyMeshType &mesh) {
|
void Reset(const PolyMeshType &mesh) {
|
||||||
_Chords.resize(2*mesh.face.size());
|
_Chords.resize(2*mesh.face.size());
|
||||||
for (size_t j = 0; j < _Chords.size(); j++)
|
for (size_t j = 0; j < _Chords.size(); ++j)
|
||||||
_Chords[j].Reset();
|
_Chords[j].Reset();
|
||||||
_currentChord = NULL;
|
_currentChord = NULL;
|
||||||
|
|
||||||
PC_Chord *chord = NULL;
|
PC_Chord *chord = NULL;
|
||||||
long long j = 0;
|
long long j = 0;
|
||||||
for (size_t i = 0; i < _Chords.size(); i++) {
|
for (size_t i = 0; i < _Chords.size(); ++i) {
|
||||||
// set the prev
|
// set the prev
|
||||||
chord = NULL;
|
chord = NULL;
|
||||||
if ((long long)i-1 >= 0) {
|
if ((long long)i-1 >= 0) {
|
||||||
|
|
@ -138,7 +138,7 @@ public:
|
||||||
if (vcg::tri::HasPerFaceFlags(mesh)) {
|
if (vcg::tri::HasPerFaceFlags(mesh)) {
|
||||||
j = i-1;
|
j = i-1;
|
||||||
while (j >= 0 && mesh.face[j/2].IsD())
|
while (j >= 0 && mesh.face[j/2].IsD())
|
||||||
j--;
|
--j;
|
||||||
if (j >= 0)
|
if (j >= 0)
|
||||||
chord = &_Chords[j];
|
chord = &_Chords[j];
|
||||||
else
|
else
|
||||||
|
|
@ -154,7 +154,7 @@ public:
|
||||||
if (vcg::tri::HasPerFaceFlags(mesh)) {
|
if (vcg::tri::HasPerFaceFlags(mesh)) {
|
||||||
j = i+1;
|
j = i+1;
|
||||||
while (j < (long long)_Chords.size() && mesh.face[j/2].IsD())
|
while (j < (long long)_Chords.size() && mesh.face[j/2].IsD())
|
||||||
j++;
|
++j;
|
||||||
if (j < (long long)_Chords.size())
|
if (j < (long long)_Chords.size())
|
||||||
chord = &_Chords[j];
|
chord = &_Chords[j];
|
||||||
else
|
else
|
||||||
|
|
@ -213,8 +213,8 @@ public:
|
||||||
coord.prev->next = coord.next;
|
coord.prev->next = coord.next;
|
||||||
if (coord.next != NULL && &coord != _currentChord)
|
if (coord.next != NULL && &coord != _currentChord)
|
||||||
coord.next->prev = coord.prev;
|
coord.next->prev = coord.prev;
|
||||||
coord.mark = mark;
|
|
||||||
}
|
}
|
||||||
|
coord.mark = mark;
|
||||||
coord.q = resultCode;
|
coord.q = resultCode;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -372,7 +372,7 @@ public:
|
||||||
* @brief LC_ResetStars resets the stars on a polychord.
|
* @brief LC_ResetStars resets the stars on a polychord.
|
||||||
*/
|
*/
|
||||||
void LC_ResetStars() {
|
void LC_ResetStars() {
|
||||||
for (size_t v = 0; v < _lcVertices.size(); v++)
|
for (size_t v = 0; v < _lcVertices.size(); ++v)
|
||||||
_lcVertices[v].reset();
|
_lcVertices[v].reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -394,7 +394,7 @@ public:
|
||||||
|
|
||||||
// count how many edges
|
// count how many edges
|
||||||
do {
|
do {
|
||||||
nEdges++;
|
++nEdges;
|
||||||
// go on the next edge
|
// go on the next edge
|
||||||
runPos.FlipE();
|
runPos.FlipE();
|
||||||
runPos.FlipV();
|
runPos.FlipV();
|
||||||
|
|
@ -402,11 +402,11 @@ public:
|
||||||
runPos.FlipF();
|
runPos.FlipF();
|
||||||
} while (runPos != startPos && !runPos.IsBorder());
|
} while (runPos != startPos && !runPos.IsBorder());
|
||||||
if (runPos.IsBorder())
|
if (runPos.IsBorder())
|
||||||
nEdges++;
|
++nEdges;
|
||||||
|
|
||||||
// resize the vector of edges
|
// resize the vector of edges
|
||||||
lcEdges.resize(nEdges);
|
lcEdges.resize(nEdges);
|
||||||
for (size_t e = 0; e < nEdges; e++)
|
for (size_t e = 0; e < nEdges; ++e)
|
||||||
lcEdges[e].reset();
|
lcEdges[e].reset();
|
||||||
|
|
||||||
/// compute the star of all the vertices and edges seen from the polychord
|
/// compute the star of all the vertices and edges seen from the polychord
|
||||||
|
|
@ -524,7 +524,7 @@ public:
|
||||||
_lcVertices[v2].star.erase(v1); // remove v1 from v2-star
|
_lcVertices[v2].star.erase(v1); // remove v1 from v2-star
|
||||||
// foreach v | v2 \in star(v) [i.e. v \in star(v2)]
|
// foreach v | v2 \in star(v) [i.e. v \in star(v2)]
|
||||||
// star(v) = star(v) U {v1} \ {v2}
|
// star(v) = star(v) U {v1} \ {v2}
|
||||||
for (typename LCVertexStar::iterator vIt = _lcVertices[v2].star.begin(); vIt != _lcVertices[v2].star.end(); vIt++) {
|
for (typename LCVertexStar::iterator vIt = _lcVertices[v2].star.begin(); vIt != _lcVertices[v2].star.end(); ++vIt) {
|
||||||
v = *vIt;
|
v = *vIt;
|
||||||
if (v == v2) // skip v2 itself
|
if (v == v2) // skip v2 itself
|
||||||
continue;
|
continue;
|
||||||
|
|
@ -534,9 +534,9 @@ public:
|
||||||
/// update the star of the edges which include v1 and v2 in their star
|
/// update the star of the edges which include v1 and v2 in their star
|
||||||
// foreach e | v1 \in star(e) ^ v2 \in star(e)
|
// foreach e | v1 \in star(e) ^ v2 \in star(e)
|
||||||
// star(e) = star(e) \ {v1,v2} U {v1}
|
// star(e) = star(e) \ {v1,v2} U {v1}
|
||||||
for (typename LCEdgeStar::iterator eIt = _lcVertices[v1].edges.begin(); eIt != _lcVertices[v1].edges.end(); eIt++)
|
for (typename LCEdgeStar::iterator eIt = _lcVertices[v1].edges.begin(); eIt != _lcVertices[v1].edges.end(); ++eIt)
|
||||||
lcEdges[*eIt].star.erase(v2);
|
lcEdges[*eIt].star.erase(v2);
|
||||||
for (typename LCEdgeStar::iterator eIt = _lcVertices[v2].edges.begin(); eIt != _lcVertices[v2].edges.end(); eIt++) {
|
for (typename LCEdgeStar::iterator eIt = _lcVertices[v2].edges.begin(); eIt != _lcVertices[v2].edges.end(); ++eIt) {
|
||||||
lcEdges[*eIt].star.erase(v2);
|
lcEdges[*eIt].star.erase(v2);
|
||||||
lcEdges[*eIt].star.insert(v1);
|
lcEdges[*eIt].star.insert(v1);
|
||||||
}
|
}
|
||||||
|
|
@ -551,6 +551,58 @@ public:
|
||||||
|
|
||||||
// PolychordCollapse's methods begin here::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
|
// PolychordCollapse's methods begin here::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
|
||||||
|
|
||||||
|
// /**
|
||||||
|
// * @brief CheckConsistent checks for consistency. ONLY FOR DEBUG.
|
||||||
|
// * @param mesh
|
||||||
|
// * @return
|
||||||
|
// */
|
||||||
|
// static bool CheckConsistent(PolyMeshType &mesh) {
|
||||||
|
// vcg::tri::RequirePerFaceFlags(mesh);
|
||||||
|
// vcg::tri::RequirePerFaceColor(mesh);
|
||||||
|
// for (size_t f = 0; f < mesh.face.size(); ++f) {
|
||||||
|
// if (!mesh.face[f].IsD()) {
|
||||||
|
// for (int v = 0; v < mesh.face[f].VN(); ++v) {
|
||||||
|
// if (!vcg::face::IsBorder(mesh.face[f], v)) {
|
||||||
|
// if (mesh.face[f].FFp(v)->IsD()) {
|
||||||
|
// mesh.face[f].C() = vcg::Color4b(vcg::Color4b::Magenta);
|
||||||
|
// return false;
|
||||||
|
// }
|
||||||
|
// if (mesh.face[f].FFp(v)->FFp(mesh.face[f].FFi(v)) != &mesh.face[f]) {
|
||||||
|
// mesh.face[f].C() = vcg::Color4b(vcg::Color4b::Yellow);
|
||||||
|
// return false;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// return true;
|
||||||
|
// }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief MarkPolychords marks the chords of the polychord starting at startPos.
|
||||||
|
* @param mesh The input mesh.
|
||||||
|
* @param startPos The starting position.
|
||||||
|
* @param chords The vector of chords.
|
||||||
|
* @param mark The current mark, used to identify quads already visited.
|
||||||
|
*/
|
||||||
|
static void MarkPolychords(const PolyMeshType &mesh,
|
||||||
|
const vcg::face::Pos<FaceType> &startPos,
|
||||||
|
PC_Chords &chords,
|
||||||
|
const unsigned long mark) {
|
||||||
|
vcg::face::Pos<FaceType> runPos = startPos;
|
||||||
|
std::pair<size_t, unsigned char> face_edge(std::numeric_limits<size_t>::max(), 0);
|
||||||
|
do {
|
||||||
|
assert(runPos.F()->VN() == 4);
|
||||||
|
face_edge.first = vcg::tri::Index(mesh, runPos.F());
|
||||||
|
face_edge.second = runPos.E() % 2;
|
||||||
|
chords[face_edge].mark = mark;
|
||||||
|
runPos.FlipE();
|
||||||
|
runPos.FlipV();
|
||||||
|
runPos.FlipE();
|
||||||
|
runPos.FlipF();
|
||||||
|
} while (runPos != startPos && !runPos.IsBorder());
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief CollapsePolychord performs all checks and then collapses the polychord.
|
* @brief CollapsePolychord performs all checks and then collapses the polychord.
|
||||||
*
|
*
|
||||||
|
|
@ -595,6 +647,8 @@ public:
|
||||||
if (pos.IsNull())
|
if (pos.IsNull())
|
||||||
return PC_VOID;
|
return PC_VOID;
|
||||||
|
|
||||||
|
// vcg::tri::io::Exporter<PolyMeshType>::Save(mesh, "current_step.obj");
|
||||||
|
|
||||||
vcg::face::Pos<FaceType> tempPos, startPos;
|
vcg::face::Pos<FaceType> tempPos, startPos;
|
||||||
|
|
||||||
// check if the sequence of facets is a polychord and find the starting coord
|
// check if the sequence of facets is a polychord and find the starting coord
|
||||||
|
|
@ -623,24 +677,32 @@ public:
|
||||||
tempPos.FlipV();
|
tempPos.FlipV();
|
||||||
tempPos.FlipE();
|
tempPos.FlipE();
|
||||||
} while (tempPos != startPos);
|
} while (tempPos != startPos);
|
||||||
|
VisitPolychord(mesh, startPos, chords, mark, resultCode);
|
||||||
|
return resultCode;
|
||||||
}
|
}
|
||||||
VisitPolychord(mesh, startPos, chords, mark, resultCode);
|
VisitPolychord(mesh, startPos, chords, mark, resultCode);
|
||||||
return resultCode;
|
return resultCode;
|
||||||
}
|
}
|
||||||
// check if the link conditions are satisfied
|
// check if the link conditions are satisfied
|
||||||
bool lc = linkConditions.CheckLinkConditions(mesh, startPos);
|
|
||||||
// if not satisfied, visit the sequence for marking it and return
|
// if not satisfied, visit the sequence for marking it and return
|
||||||
if (!lc) {
|
if (!linkConditions.CheckLinkConditions(mesh, startPos)) {
|
||||||
VisitPolychord(mesh, startPos, chords, mark, PC_NOLINKCOND);
|
VisitPolychord(mesh, startPos, chords, mark, PC_NOLINKCOND);
|
||||||
return PC_NOLINKCOND;
|
return PC_NOLINKCOND;
|
||||||
}
|
}
|
||||||
|
// mark the polychord's chords
|
||||||
|
MarkPolychords(mesh, startPos, chords, mark);
|
||||||
// check if the polychord does not intersect itself
|
// check if the polychord does not intersect itself
|
||||||
bool si = IsPolychordSelfIntersecting(mesh, startPos, chords, mark);
|
|
||||||
// if it self-intersects, visit the polychord for marking it and return
|
// if it self-intersects, visit the polychord for marking it and return
|
||||||
if (si) {
|
if (IsPolychordSelfIntersecting(mesh, startPos, chords, mark)) {
|
||||||
VisitPolychord(mesh, startPos, chords, mark, PC_SELFINTERSECT);
|
VisitPolychord(mesh, startPos, chords, mark, PC_SELFINTERSECT);
|
||||||
return PC_SELFINTERSECT;
|
return PC_SELFINTERSECT;
|
||||||
}
|
}
|
||||||
|
// check if manifoldness remains
|
||||||
|
// if it will loose manifoldness, visit the sequence for marking it and return
|
||||||
|
if (!WillPolychordBeManifold(mesh, startPos, chords, mark)) {
|
||||||
|
VisitPolychord(mesh, startPos, chords, mark, PC_NOMOREMANIF);
|
||||||
|
return PC_NOMOREMANIF;
|
||||||
|
}
|
||||||
// at this point the polychord is collapsable, visit it for marking
|
// at this point the polychord is collapsable, visit it for marking
|
||||||
VisitPolychord(mesh, startPos, chords, mark, PC_SUCCESS);
|
VisitPolychord(mesh, startPos, chords, mark, PC_SUCCESS);
|
||||||
|
|
||||||
|
|
@ -669,12 +731,12 @@ public:
|
||||||
valenceB = runPos.NumberOfIncidentVertices();
|
valenceB = runPos.NumberOfIncidentVertices();
|
||||||
tmpPos.Set(runPos.F(), runPos.E(), runPos.V());
|
tmpPos.Set(runPos.F(), runPos.E(), runPos.V());
|
||||||
if (tmpPos.FindBorder())
|
if (tmpPos.FindBorder())
|
||||||
valenceB++;
|
++valenceB;
|
||||||
runPos.FlipV();
|
runPos.FlipV();
|
||||||
valenceA = runPos.NumberOfIncidentVertices();
|
valenceA = runPos.NumberOfIncidentVertices();
|
||||||
tmpPos.Set(runPos.F(), runPos.E(), runPos.V());
|
tmpPos.Set(runPos.F(), runPos.E(), runPos.V());
|
||||||
if (tmpPos.FindBorder())
|
if (tmpPos.FindBorder())
|
||||||
valenceA++;
|
++valenceA;
|
||||||
if (valenceA != 4)
|
if (valenceA != 4)
|
||||||
onSideA = true;
|
onSideA = true;
|
||||||
if (valenceB != 4)
|
if (valenceB != 4)
|
||||||
|
|
@ -816,6 +878,12 @@ public:
|
||||||
verticesToDeleteQueue.pop();
|
verticesToDeleteQueue.pop();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// if (!CheckConsistent(mesh)) {
|
||||||
|
// int mask = vcg::tri::io::Mask::IOM_FACECOLOR;
|
||||||
|
// vcg::tri::io::Exporter<PolyMeshType>::Save(mesh, "current_step_failed.obj", mask);
|
||||||
|
// assert(false);
|
||||||
|
// }
|
||||||
|
|
||||||
return PC_SUCCESS;
|
return PC_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -843,6 +911,8 @@ public:
|
||||||
while (!chords.End()) {
|
while (!chords.End()) {
|
||||||
// get the current coord
|
// get the current coord
|
||||||
chords.GetCurrent(face_edge);
|
chords.GetCurrent(face_edge);
|
||||||
|
resultCode = chords[face_edge].q;
|
||||||
|
assert(resultCode == PC_VOID);
|
||||||
// construct a pos on the face and edge of the current coord
|
// construct a pos on the face and edge of the current coord
|
||||||
pos.Set(&mesh.face[face_edge.first], face_edge.second, mesh.face[face_edge.first].V(face_edge.second));
|
pos.Set(&mesh.face[face_edge.first], face_edge.second, mesh.face[face_edge.first].V(face_edge.second));
|
||||||
// (try to) collapse the polychord
|
// (try to) collapse the polychord
|
||||||
|
|
@ -851,7 +921,7 @@ public:
|
||||||
chords.Next();
|
chords.Next();
|
||||||
|
|
||||||
// increment the mark
|
// increment the mark
|
||||||
mark++;
|
++mark;
|
||||||
if (mark == std::numeric_limits<unsigned long>::max()) {
|
if (mark == std::numeric_limits<unsigned long>::max()) {
|
||||||
chords.ResetMarks();
|
chords.ResetMarks();
|
||||||
mark = 0;
|
mark = 0;
|
||||||
|
|
@ -1013,7 +1083,7 @@ public:
|
||||||
// allocate and initialize 4 vertices and ffAdj for each new face
|
// allocate and initialize 4 vertices and ffAdj for each new face
|
||||||
for (FaceIterator fIt = firstAddedFaceIt; fIt != mesh.face.end(); ++fIt) {
|
for (FaceIterator fIt = firstAddedFaceIt; fIt != mesh.face.end(); ++fIt) {
|
||||||
fIt->Alloc(4);
|
fIt->Alloc(4);
|
||||||
for (size_t j = 0; j < 4; j++) {
|
for (size_t j = 0; j < 4; ++j) {
|
||||||
fIt->FFp(j) = &*fIt;
|
fIt->FFp(j) = &*fIt;
|
||||||
fIt->FFi(j) = j;
|
fIt->FFi(j) = j;
|
||||||
}
|
}
|
||||||
|
|
@ -1566,7 +1636,7 @@ public:
|
||||||
// if the vertex is on border increment its valence by 1 (virtually connect it to a dummy vertex)
|
// if the vertex is on border increment its valence by 1 (virtually connect it to a dummy vertex)
|
||||||
jmpPos.Set(startPos.F(), startPos.E(), startPos.V());
|
jmpPos.Set(startPos.F(), startPos.E(), startPos.V());
|
||||||
if (jmpPos.FindBorder())
|
if (jmpPos.FindBorder())
|
||||||
valence++;
|
++valence;
|
||||||
if (valence != 4)
|
if (valence != 4)
|
||||||
singSideB = true;
|
singSideB = true;
|
||||||
// a 2-valence internl vertex cause a polychord to touch itself, producing non-2manifoldness
|
// a 2-valence internl vertex cause a polychord to touch itself, producing non-2manifoldness
|
||||||
|
|
@ -1579,7 +1649,7 @@ public:
|
||||||
// if the vertex is on border increment its valence by 1 (virtually connect it to a dummy vertex)
|
// if the vertex is on border increment its valence by 1 (virtually connect it to a dummy vertex)
|
||||||
jmpPos.Set(startPos.F(), startPos.E(), startPos.V());
|
jmpPos.Set(startPos.F(), startPos.E(), startPos.V());
|
||||||
if (jmpPos.FindBorder())
|
if (jmpPos.FindBorder())
|
||||||
valence++;
|
++valence;
|
||||||
if (valence != 4)
|
if (valence != 4)
|
||||||
singSideA = true;
|
singSideA = true;
|
||||||
// a 2-valence internal vertex cause a polychord to touch itself, producing non-2manifoldness
|
// a 2-valence internal vertex cause a polychord to touch itself, producing non-2manifoldness
|
||||||
|
|
@ -1644,14 +1714,13 @@ public:
|
||||||
vcg::face::Pos<FaceType> tmpPos, runPos = startPos;
|
vcg::face::Pos<FaceType> tmpPos, runPos = startPos;
|
||||||
std::pair<size_t, unsigned char> face_edge(std::numeric_limits<size_t>::max(), 0);
|
std::pair<size_t, unsigned char> face_edge(std::numeric_limits<size_t>::max(), 0);
|
||||||
|
|
||||||
if (runPos.F()->VN() != 4) // non-quads are not visited
|
|
||||||
return;
|
|
||||||
|
|
||||||
// follow the sequence of quads
|
// follow the sequence of quads
|
||||||
do {
|
do {
|
||||||
// check manifoldness
|
// check manifoldness
|
||||||
tmpPos = runPos;
|
tmpPos = runPos;
|
||||||
do {
|
do {
|
||||||
|
if (runPos.F()->VN() != 4) // non-quads are not visited
|
||||||
|
return;
|
||||||
if (!tmpPos.IsManifold()) {
|
if (!tmpPos.IsManifold()) {
|
||||||
// update current coord
|
// update current coord
|
||||||
face_edge.first = vcg::tri::Index(mesh, tmpPos.F());
|
face_edge.first = vcg::tri::Index(mesh, tmpPos.F());
|
||||||
|
|
@ -1694,6 +1763,7 @@ public:
|
||||||
vcg::face::JumpingPos<FaceType> jmpPos;
|
vcg::face::JumpingPos<FaceType> jmpPos;
|
||||||
jmpPos.Set(pos.F(), pos.E(), pos.V());
|
jmpPos.Set(pos.F(), pos.E(), pos.V());
|
||||||
do {
|
do {
|
||||||
|
assert(!jmpPos.FFlip()->IsD());
|
||||||
if (!jmpPos.IsManifold())
|
if (!jmpPos.IsManifold())
|
||||||
return true;
|
return true;
|
||||||
jmpPos.NextFE();
|
jmpPos.NextFE();
|
||||||
|
|
@ -1737,6 +1807,10 @@ public:
|
||||||
face_edge.second = (tmpPos.E()+1)%2;
|
face_edge.second = (tmpPos.E()+1)%2;
|
||||||
if (chords[face_edge].mark == mark)
|
if (chords[face_edge].mark == mark)
|
||||||
return true;
|
return true;
|
||||||
|
// this should never hapen:
|
||||||
|
face_edge.second = tmpPos.E()%2;
|
||||||
|
if (chords[face_edge].mark == mark)
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
tmpPos = runPos;
|
tmpPos = runPos;
|
||||||
tmpPos.FlipV();
|
tmpPos.FlipV();
|
||||||
|
|
@ -1747,6 +1821,10 @@ public:
|
||||||
face_edge.second = (tmpPos.E()+1)%2;
|
face_edge.second = (tmpPos.E()+1)%2;
|
||||||
if (chords[face_edge].mark == mark)
|
if (chords[face_edge].mark == mark)
|
||||||
return true;
|
return true;
|
||||||
|
// this should never hapen:
|
||||||
|
face_edge.second = tmpPos.E()%2;
|
||||||
|
if (chords[face_edge].mark == mark)
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
runPos.FlipE();
|
runPos.FlipE();
|
||||||
runPos.FlipV();
|
runPos.FlipV();
|
||||||
|
|
@ -1756,6 +1834,164 @@ public:
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief WillPolychordBeManifold checks whether a polychord starting at startPos would cause non-manifoldness
|
||||||
|
* if it was collapsed.
|
||||||
|
* @note VisitPolychord() should be called before this method.
|
||||||
|
* @param mesh The input mesh.
|
||||||
|
* @param startPos The starting Pos.
|
||||||
|
* @param chords The vector of chords.
|
||||||
|
* @param mark The current mark, used to identify quads already visited.
|
||||||
|
* @return true if manifoldness remains, false otherwise.
|
||||||
|
*/
|
||||||
|
static bool WillPolychordBeManifold(const PolyMeshType &mesh,
|
||||||
|
const vcg::face::Pos<FaceType> &startPos,
|
||||||
|
PC_Chords &chords,
|
||||||
|
const unsigned long mark) {
|
||||||
|
assert(!startPos.IsNull());
|
||||||
|
vcg::face::Pos<FaceType> runPos = startPos;
|
||||||
|
vcg::face::JumpingPos<FaceType> tmpPos;
|
||||||
|
std::pair<size_t, unsigned char> face_edge1(std::numeric_limits<size_t>::max(), 0);
|
||||||
|
std::pair<size_t, unsigned char> face_edge2(std::numeric_limits<size_t>::max(), 0);
|
||||||
|
bool in = true;
|
||||||
|
unsigned int nTraversal = 0;
|
||||||
|
|
||||||
|
// second step: check
|
||||||
|
runPos = startPos;
|
||||||
|
do {
|
||||||
|
face_edge1.first = vcg::tri::Index(mesh, runPos.F());
|
||||||
|
face_edge1.second = runPos.E() % 2;
|
||||||
|
assert(chords[face_edge1].mark == mark);
|
||||||
|
// check one vertex
|
||||||
|
runPos.FlipV();
|
||||||
|
in = true;
|
||||||
|
nTraversal = 0;
|
||||||
|
tmpPos.Set(runPos.F(), runPos.E(), runPos.V());
|
||||||
|
do {
|
||||||
|
if (tmpPos.IsBorder() && in) {
|
||||||
|
in = false;
|
||||||
|
nTraversal++;
|
||||||
|
}
|
||||||
|
// go to next edge
|
||||||
|
tmpPos.NextFE();
|
||||||
|
// check if this face is already visited
|
||||||
|
face_edge1.first = vcg::tri::Index(mesh, tmpPos.F());
|
||||||
|
face_edge1.second = tmpPos.E() % 2;
|
||||||
|
face_edge2.first = vcg::tri::Index(mesh, tmpPos.F());
|
||||||
|
face_edge2.second = (tmpPos.E() + 1) % 2;
|
||||||
|
if (in && chords[face_edge1].mark != mark && chords[face_edge2].mark != mark) {
|
||||||
|
in = false;
|
||||||
|
++nTraversal;
|
||||||
|
} else if (!in && (chords[face_edge1].mark == mark || chords[face_edge2].mark == mark)) {
|
||||||
|
in = true;
|
||||||
|
++nTraversal;
|
||||||
|
}
|
||||||
|
} while (tmpPos != runPos);
|
||||||
|
assert(in);
|
||||||
|
assert(nTraversal % 2 == 0);
|
||||||
|
if (nTraversal > 2)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// check other vertex
|
||||||
|
runPos.FlipV();
|
||||||
|
in = true;
|
||||||
|
nTraversal = 0;
|
||||||
|
tmpPos.Set(runPos.F(), runPos.E(), runPos.V());
|
||||||
|
do {
|
||||||
|
if (tmpPos.IsBorder() && in) {
|
||||||
|
in = false;
|
||||||
|
++nTraversal;
|
||||||
|
}
|
||||||
|
// go to next edge
|
||||||
|
tmpPos.NextFE();
|
||||||
|
// check if this face is already visited
|
||||||
|
face_edge1.first = vcg::tri::Index(mesh, tmpPos.F());
|
||||||
|
face_edge1.second = tmpPos.E() % 2;
|
||||||
|
face_edge2.first = vcg::tri::Index(mesh, tmpPos.F());
|
||||||
|
face_edge2.second = (tmpPos.E() + 1) % 2;
|
||||||
|
if (in && chords[face_edge1].mark != mark && chords[face_edge2].mark != mark) {
|
||||||
|
in = false;
|
||||||
|
nTraversal++;
|
||||||
|
} else if (!in && (chords[face_edge1].mark == mark || chords[face_edge2].mark == mark)) {
|
||||||
|
in = true;
|
||||||
|
++nTraversal;
|
||||||
|
}
|
||||||
|
} while (tmpPos != runPos);
|
||||||
|
assert(in);
|
||||||
|
assert(nTraversal % 2 == 0);
|
||||||
|
if (nTraversal > 2)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
runPos.FlipE();
|
||||||
|
runPos.FlipV();
|
||||||
|
runPos.FlipE();
|
||||||
|
runPos.FlipF();
|
||||||
|
} while (runPos != startPos && !runPos.IsBorder());
|
||||||
|
if (runPos.IsBorder()) {
|
||||||
|
// check one vertex
|
||||||
|
runPos.FlipV();
|
||||||
|
in = true;
|
||||||
|
nTraversal = 0;
|
||||||
|
tmpPos.Set(runPos.F(), runPos.E(), runPos.V());
|
||||||
|
do {
|
||||||
|
if (tmpPos.IsBorder() && in) {
|
||||||
|
in = false;
|
||||||
|
++nTraversal;
|
||||||
|
}
|
||||||
|
// go to next edge
|
||||||
|
tmpPos.NextFE();
|
||||||
|
// check if this face is already visited
|
||||||
|
face_edge1.first = vcg::tri::Index(mesh, tmpPos.F());
|
||||||
|
face_edge1.second = tmpPos.E() % 2;
|
||||||
|
face_edge2.first = vcg::tri::Index(mesh, tmpPos.F());
|
||||||
|
face_edge2.second = (tmpPos.E() + 1) % 2;
|
||||||
|
if (in && chords[face_edge1].mark != mark && chords[face_edge2].mark != mark) {
|
||||||
|
in = false;
|
||||||
|
++nTraversal;
|
||||||
|
} else if (!in && (chords[face_edge1].mark == mark || chords[face_edge2].mark == mark)) {
|
||||||
|
in = true;
|
||||||
|
++nTraversal;
|
||||||
|
}
|
||||||
|
} while (tmpPos != runPos);
|
||||||
|
assert(in);
|
||||||
|
assert(nTraversal % 2 == 0);
|
||||||
|
if (nTraversal > 2)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// check other vertex
|
||||||
|
runPos.FlipV();
|
||||||
|
in = true;
|
||||||
|
nTraversal = 0;
|
||||||
|
tmpPos.Set(runPos.F(), runPos.E(), runPos.V());
|
||||||
|
do {
|
||||||
|
if (tmpPos.IsBorder() && in) {
|
||||||
|
in = false;
|
||||||
|
++nTraversal;
|
||||||
|
}
|
||||||
|
// go to next edge
|
||||||
|
tmpPos.NextFE();
|
||||||
|
// check if this face is already visited
|
||||||
|
face_edge1.first = vcg::tri::Index(mesh, tmpPos.F());
|
||||||
|
face_edge1.second = tmpPos.E() % 2;
|
||||||
|
face_edge2.first = vcg::tri::Index(mesh, tmpPos.F());
|
||||||
|
face_edge2.second = (tmpPos.E() + 1) % 2;
|
||||||
|
if (in && chords[face_edge1].mark != mark && chords[face_edge2].mark != mark) {
|
||||||
|
in = false;
|
||||||
|
++nTraversal;
|
||||||
|
} else if (!in && (chords[face_edge1].mark == mark || chords[face_edge2].mark == mark)) {
|
||||||
|
in = true;
|
||||||
|
++nTraversal;
|
||||||
|
}
|
||||||
|
} while (tmpPos != runPos);
|
||||||
|
assert(in);
|
||||||
|
assert(nTraversal % 2 == 0);
|
||||||
|
if (nTraversal > 2)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue