From 71391e6a55743e499315852b4bc3449563c3881c Mon Sep 17 00:00:00 2001 From: Jonathan Westhues Date: Tue, 3 Jun 2008 22:39:32 -0800 Subject: [PATCH] Add an interference check for assembled parts. That's easy once the BSP stuff works. The failures are reported with red stripes and no depth buffering, and in a message in the text window. Also improve convergence of point-on-line constraints, and don't write triangles to export files with limited precision, because that was making the coplanar tests fail. [git-p4: depot-paths = "//depot/solvespace/": change = 1774] --- constraint.cpp | 15 +++++++++++---- file.cpp | 2 +- mesh.cpp | 31 +++++++++++++++++++++++++++++-- polygon.h | 1 + sketch.cpp | 28 +++++++++++++++++++++++++++- sketch.h | 4 ++++ textwin.cpp | 3 +++ 7 files changed, 76 insertions(+), 8 deletions(-) diff --git a/constraint.cpp b/constraint.cpp index 45d42299..f09fe45b 100644 --- a/constraint.cpp +++ b/constraint.cpp @@ -567,14 +567,21 @@ void Constraint::Generate(IdList *l) { ExprVector ea = a->PointGetExprs(); ExprVector eb = b->PointGetExprs(); ExprVector eab = ea.Minus(eb); + + // Construct a vector from the point to either endpoint of + // the line segment, and choose the longer of these. ExprVector eap = ea.Minus(ep); + ExprVector ebp = eb.Minus(ep); + ExprVector elp = + (ebp.Magnitude()->Eval() > eap.Magnitude()->Eval()) ? + ebp : eap; if(p->group.v == group.v) { - AddEq(l, VectorsParallel(0, eab, eap), 0); - AddEq(l, VectorsParallel(1, eab, eap), 1); + AddEq(l, VectorsParallel(0, eab, elp), 0); + AddEq(l, VectorsParallel(1, eab, elp), 1); } else { - AddEq(l, VectorsParallel(0, eap, eab), 0); - AddEq(l, VectorsParallel(1, eap, eab), 1); + AddEq(l, VectorsParallel(0, elp, eab), 0); + AddEq(l, VectorsParallel(1, elp, eab), 1); } } else { AddEq(l, PointLineDistance(workplane, ptA, entityA), 0); diff --git a/file.cpp b/file.cpp index 86b7c898..23810134 100644 --- a/file.cpp +++ b/file.cpp @@ -234,7 +234,7 @@ bool SolveSpace::SaveToFile(char *filename) { double mag = tr->Normal().Magnitude(); dbp("triangle: mag=%.5f", mag); */ fprintf(fh, "Triangle %08x %08x " - "%.3f %.3f %.3f %.3f %.3f %.3f %.3f %.3f %.3f\n", + "%.20f %.20f %.20f %.20f %.20f %.20f %.20f %.20f %.20f\n", tr->meta.face, tr->meta.color, CO(tr->a), CO(tr->b), CO(tr->c)); } diff --git a/mesh.cpp b/mesh.cpp index 6e0b560f..18e82797 100644 --- a/mesh.cpp +++ b/mesh.cpp @@ -225,7 +225,7 @@ void SMesh::MakeFromDifference(SMesh *a, SMesh *b) { SBsp3 *bspb = SBsp3::FromMesh(b); flipNormal = true; - keepCoplanar = false; + keepCoplanar = true; AddAgainstBsp(b, bspa); flipNormal = false; @@ -235,6 +235,31 @@ void SMesh::MakeFromDifference(SMesh *a, SMesh *b) { dbp("tris = %d", l.n); } +bool SMesh::MakeFromInterferenceCheck(SMesh *srca, SMesh *srcb, SMesh *error) { + SBsp3 *bspa = SBsp3::FromMesh(srca); + SBsp3 *bspb = SBsp3::FromMesh(srcb); + + error->Clear(); + error->flipNormal = true; + error->keepCoplanar = false; + + error->AddAgainstBsp(srcb, bspa); + error->AddAgainstBsp(srca, bspb); + // Now we have a list of all the triangles (or fragments thereof) from + // A that lie inside B, or vice versa. That's the interference, and + // we report it so that it can be flagged. + + // But as far as the actual model, we just copy everything over. + int i; + for(i = 0; i < srca->l.n; i++) { + AddTriangle(&(srca->l.elem[i])); + } + for(i = 0; i < srcb->l.n; i++) { + AddTriangle(&(srcb->l.elem[i])); + } + return (error->l.n == 0); +} + DWORD SMesh::FirstIntersectionWith(Point2d mp) { Vector gu = SS.GW.projRight, gv = SS.GW.projUp; Vector gn = (gu.Cross(gv)).WithMagnitude(1); @@ -325,7 +350,9 @@ void SBsp3::InsertInPlane(bool pos2, STriangle *tr, SMesh *m) { ll = ll->more; } - if(m->flipNormal && ((!pos2 && !onFace) || (onFace && !sameNormal))) { + if(m->flipNormal && ((!pos2 && !onFace) || + (onFace && !sameNormal && m->keepCoplanar))) + { m->AddTriangle(tr->meta, tr->c, tr->b, tr->a); } else if(!(m->flipNormal) && ((pos2 && !onFace) || (onFace && sameNormal && m->keepCoplanar))) diff --git a/polygon.h b/polygon.h index 743c3cd9..87b3f743 100644 --- a/polygon.h +++ b/polygon.h @@ -191,6 +191,7 @@ public: void AddAgainstBsp(SMesh *srcm, SBsp3 *bsp3); void MakeFromUnion(SMesh *a, SMesh *b); void MakeFromDifference(SMesh *a, SMesh *b); + bool MakeFromInterferenceCheck(SMesh *srca, SMesh *srcb, SMesh *errorAt); DWORD FirstIntersectionWith(Point2d mp); }; diff --git a/sketch.cpp b/sketch.cpp index c5904279..ee221628 100644 --- a/sketch.cpp +++ b/sketch.cpp @@ -737,13 +737,22 @@ void Group::GenerateMesh(void) { // So our group's mesh appears in outm. Combine this with the previous // group's mesh, using the requested operation. mesh.Clear(); + bool prevMeshError = meshError.yes; + meshError.yes = false; + meshError.interferesAt.Clear(); SMesh *a = PreviousGroupMesh(); if(meshCombine == COMBINE_AS_UNION) { mesh.MakeFromUnion(a, &outm); } else if(meshCombine == COMBINE_AS_DIFFERENCE) { mesh.MakeFromDifference(a, &outm); } else { - + if(!mesh.MakeFromInterferenceCheck(a, &outm, &(meshError.interferesAt))) + meshError.yes = true; + // And the list of failed triangles appears in meshError.interferesAt + } + if(prevMeshError != meshError.yes) { + // The error is reported in the text window for the group. + SS.later.showTW = true; } outm.Clear(); } @@ -789,6 +798,23 @@ void Group::Draw(void) { if(SS.GW.showShaded) glxFillMesh(specColor, &mesh, mh, ms1, ms2); glDisable(GL_LIGHTING); + if(meshError.yes) { + // Draw the error triangles in bright red stripes, with no Z buffering + GLubyte mask[32*32/8]; + memset(mask, 0xf0, sizeof(mask)); + glPolygonStipple(mask); + + int specColor = 0; + glDisable(GL_DEPTH_TEST); + glColor3d(0, 0, 0); + glxFillMesh(0, &meshError.interferesAt, 0, 0, 0); + glEnable(GL_POLYGON_STIPPLE); + glColor3d(1, 0, 0); + glxFillMesh(0, &meshError.interferesAt, 0, 0, 0); + glEnable(GL_DEPTH_TEST); + glDisable(GL_POLYGON_STIPPLE); + } + if(SS.GW.showMesh) glxDebugMesh(&mesh); if(!SS.GW.showShaded) return; diff --git a/sketch.h b/sketch.h index 4527c319..d14e2f53 100644 --- a/sketch.h +++ b/sketch.h @@ -124,6 +124,10 @@ public: bool yes; } polyError; SMesh mesh; + struct { + SMesh interferesAt; + bool yes; + } meshError; static const int COMBINE_AS_UNION = 0; static const int COMBINE_AS_DIFFERENCE = 1; diff --git a/textwin.cpp b/textwin.cpp index b93fff52..78d906b6 100644 --- a/textwin.cpp +++ b/textwin.cpp @@ -656,6 +656,9 @@ void TextWindow::ShowGroupInfo(void) { Group::COMBINE_AS_ASSEMBLE, (asy || !asa ? "" : "assemble"), (asy && asa ? "assemble" : "")); } + if(g->type == Group::IMPORTED && g->meshError.yes) { + Printf(false, "%Fx the parts interfere!"); + } if(g->type == Group::EXTRUDE) { #define TWOX(v) v v