Test for self-intersecting mesh too when we test for naked edges.

[git-p4: depot-paths = "//depot/solvespace/": change = 1909]
This commit is contained in:
Jonathan Westhues 2009-01-27 23:09:01 -08:00
parent 715a554637
commit db8859ec31
3 changed files with 55 additions and 12 deletions

View File

@ -476,19 +476,19 @@ void SKdNode::MakeMeshInto(SMesh *m) {
} }
} }
void SKdNode::FindEdgeOn(Vector a, Vector b, int *n, int cnt) { void SKdNode::FindEdgeOn(Vector a, Vector b, int *n, int cnt, bool *inter) {
if(gt && lt) { if(gt && lt) {
double ac = a.Element(which), double ac = a.Element(which),
bc = b.Element(which); bc = b.Element(which);
if(ac < c + KDTREE_EPS || if(ac < c + KDTREE_EPS ||
bc < c + KDTREE_EPS) bc < c + KDTREE_EPS)
{ {
lt->FindEdgeOn(a, b, n, cnt); lt->FindEdgeOn(a, b, n, cnt, inter);
} }
if(ac > c - KDTREE_EPS || if(ac > c - KDTREE_EPS ||
bc > c - KDTREE_EPS) bc > c - KDTREE_EPS)
{ {
gt->FindEdgeOn(a, b, n, cnt); gt->FindEdgeOn(a, b, n, cnt, inter);
} }
} else { } else {
STriangleLl *ll; STriangleLl *ll;
@ -497,12 +497,37 @@ void SKdNode::FindEdgeOn(Vector a, Vector b, int *n, int cnt) {
if(tr->tag == cnt) continue; if(tr->tag == cnt) continue;
// Test if this triangle matches up with the given edge
if((a.Equals(tr->b) && b.Equals(tr->a)) || if((a.Equals(tr->b) && b.Equals(tr->a)) ||
(a.Equals(tr->c) && b.Equals(tr->b)) || (a.Equals(tr->c) && b.Equals(tr->b)) ||
(a.Equals(tr->a) && b.Equals(tr->c))) (a.Equals(tr->a) && b.Equals(tr->c)))
{ {
(*n)++; (*n)++;
} else if(((a.Equals(tr->a) && b.Equals(tr->b)) ||
(a.Equals(tr->b) && b.Equals(tr->c)) ||
(a.Equals(tr->c) && b.Equals(tr->a))))
{
// It's an edge of this triangle, okay.
} else {
// Check for self-intersection
Vector n = (tr->Normal()).WithMagnitude(1);
double d = (tr->a).Dot(n);
double pa = a.Dot(n) - d, pb = b.Dot(n) - d;
// It's an intersection if neither point lies in-plane,
// and the edge crosses the plane (should handle in-plane
// intersections separately but don't yet).
if((pa < -LENGTH_EPS || pa > LENGTH_EPS) &&
(pb < -LENGTH_EPS || pb > LENGTH_EPS) &&
(pa*pb < 0))
{
// The edge crosses the plane of the triangle; now see if
// it crosses inside the triangle.
if(tr->ContainsPointProjd(b.Minus(a), a)) {
*inter = true;
}
}
} }
// Ensure that we don't count this triangle twice if it appears // Ensure that we don't count this triangle twice if it appears
// in two buckets of the kd tree. // in two buckets of the kd tree.
tr->tag = cnt; tr->tag = cnt;
@ -510,7 +535,10 @@ void SKdNode::FindEdgeOn(Vector a, Vector b, int *n, int cnt) {
} }
} }
void SKdNode::MakeNakedEdgesInto(SEdgeList *sel) { void SKdNode::MakeNakedEdgesInto(SEdgeList *sel, bool *inter, bool *leaky) {
if(inter) *inter = false;
if(leaky) *leaky = false;
SMesh m; SMesh m;
ZERO(&m); ZERO(&m);
ClearTags(); ClearTags();
@ -526,10 +554,17 @@ void SKdNode::MakeNakedEdgesInto(SEdgeList *sel) {
Vector b = (j == 0) ? tr->b : ((j == 1) ? tr->c : tr->a); Vector b = (j == 0) ? tr->b : ((j == 1) ? tr->c : tr->a);
int n = 0, nOther = 0; int n = 0, nOther = 0;
FindEdgeOn(a, b, &n, cnt); bool thisIntersects = false;
FindEdgeOn(a, b, &n, cnt, &thisIntersects);
if(n != 1) { if(n != 1) {
sel->AddEdge(a, b); sel->AddEdge(a, b);
if(leaky) *leaky = true;
} }
if(thisIntersects) {
sel->AddEdge(a, b);
if(inter) *inter = true;
}
cnt++; cnt++;
} }
} }

View File

@ -219,8 +219,8 @@ public:
void MakeMeshInto(SMesh *m); void MakeMeshInto(SMesh *m);
void ClearTags(void); void ClearTags(void);
void FindEdgeOn(Vector a, Vector b, int *n, int cnt); void FindEdgeOn(Vector a, Vector b, int *n, int cnt, bool *inter);
void MakeNakedEdgesInto(SEdgeList *sel); void MakeNakedEdgesInto(SEdgeList *sel, bool *inter=NULL, bool *leaky=NULL);
}; };
#endif #endif

View File

@ -406,15 +406,23 @@ void SolveSpace::MenuAnalyze(int id) {
SMesh *m = &(SS.GetGroup(SS.GW.activeGroup)->runningMesh); SMesh *m = &(SS.GetGroup(SS.GW.activeGroup)->runningMesh);
SKdNode *root = SKdNode::From(m); SKdNode *root = SKdNode::From(m);
root->MakeNakedEdgesInto(&(SS.nakedEdges)); bool inters, leaks;
root->MakeNakedEdgesInto(&(SS.nakedEdges), &inters, &leaks);
InvalidateGraphics(); InvalidateGraphics();
char *intersMsg = inters ?
"The mesh is self-intersecting (NOT okay, invalid)." :
"The mesh is not self-intersecting (okay, valid).";
char *leaksMsg = leaks ?
"The mesh has naked edges (NOT okay, invalid)." :
"The mesh is watertight (okay, valid).";
if(SS.nakedEdges.l.n == 0) { if(SS.nakedEdges.l.n == 0) {
Error("Zero naked edges; the model is watertight. " Message("%s\r\n\r\n%s\r\n\r\nZero problematic edges, good.",
"An exported STL file will be valid."); intersMsg, leaksMsg);
} else { } else {
Error("Found %d naked edges, now highlighted.", Error("%s\r\n\r\n%s\r\n\r\n%d problematic edges, bad.",
SS.nakedEdges.l.n); intersMsg, leaksMsg, SS.nakedEdges.l.n);
} }
break; break;
} }