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:
parent
715a554637
commit
db8859ec31
45
mesh.cpp
45
mesh.cpp
@ -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++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user