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]solver
parent
64c7a4e61b
commit
71391e6a55
|
@ -567,14 +567,21 @@ void Constraint::Generate(IdList<Equation,hEquation> *l) {
|
||||||
ExprVector ea = a->PointGetExprs();
|
ExprVector ea = a->PointGetExprs();
|
||||||
ExprVector eb = b->PointGetExprs();
|
ExprVector eb = b->PointGetExprs();
|
||||||
ExprVector eab = ea.Minus(eb);
|
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 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) {
|
if(p->group.v == group.v) {
|
||||||
AddEq(l, VectorsParallel(0, eab, eap), 0);
|
AddEq(l, VectorsParallel(0, eab, elp), 0);
|
||||||
AddEq(l, VectorsParallel(1, eab, eap), 1);
|
AddEq(l, VectorsParallel(1, eab, elp), 1);
|
||||||
} else {
|
} else {
|
||||||
AddEq(l, VectorsParallel(0, eap, eab), 0);
|
AddEq(l, VectorsParallel(0, elp, eab), 0);
|
||||||
AddEq(l, VectorsParallel(1, eap, eab), 1);
|
AddEq(l, VectorsParallel(1, elp, eab), 1);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
AddEq(l, PointLineDistance(workplane, ptA, entityA), 0);
|
AddEq(l, PointLineDistance(workplane, ptA, entityA), 0);
|
||||||
|
|
2
file.cpp
2
file.cpp
|
@ -234,7 +234,7 @@ bool SolveSpace::SaveToFile(char *filename) {
|
||||||
double mag = tr->Normal().Magnitude();
|
double mag = tr->Normal().Magnitude();
|
||||||
dbp("triangle: mag=%.5f", mag); */
|
dbp("triangle: mag=%.5f", mag); */
|
||||||
fprintf(fh, "Triangle %08x %08x "
|
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,
|
tr->meta.face, tr->meta.color,
|
||||||
CO(tr->a), CO(tr->b), CO(tr->c));
|
CO(tr->a), CO(tr->b), CO(tr->c));
|
||||||
}
|
}
|
||||||
|
|
31
mesh.cpp
31
mesh.cpp
|
@ -225,7 +225,7 @@ void SMesh::MakeFromDifference(SMesh *a, SMesh *b) {
|
||||||
SBsp3 *bspb = SBsp3::FromMesh(b);
|
SBsp3 *bspb = SBsp3::FromMesh(b);
|
||||||
|
|
||||||
flipNormal = true;
|
flipNormal = true;
|
||||||
keepCoplanar = false;
|
keepCoplanar = true;
|
||||||
AddAgainstBsp(b, bspa);
|
AddAgainstBsp(b, bspa);
|
||||||
|
|
||||||
flipNormal = false;
|
flipNormal = false;
|
||||||
|
@ -235,6 +235,31 @@ void SMesh::MakeFromDifference(SMesh *a, SMesh *b) {
|
||||||
dbp("tris = %d", l.n);
|
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) {
|
DWORD SMesh::FirstIntersectionWith(Point2d mp) {
|
||||||
Vector gu = SS.GW.projRight, gv = SS.GW.projUp;
|
Vector gu = SS.GW.projRight, gv = SS.GW.projUp;
|
||||||
Vector gn = (gu.Cross(gv)).WithMagnitude(1);
|
Vector gn = (gu.Cross(gv)).WithMagnitude(1);
|
||||||
|
@ -325,7 +350,9 @@ void SBsp3::InsertInPlane(bool pos2, STriangle *tr, SMesh *m) {
|
||||||
ll = ll->more;
|
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);
|
m->AddTriangle(tr->meta, tr->c, tr->b, tr->a);
|
||||||
} else if(!(m->flipNormal) && ((pos2 && !onFace) ||
|
} else if(!(m->flipNormal) && ((pos2 && !onFace) ||
|
||||||
(onFace && sameNormal && m->keepCoplanar)))
|
(onFace && sameNormal && m->keepCoplanar)))
|
||||||
|
|
|
@ -191,6 +191,7 @@ public:
|
||||||
void AddAgainstBsp(SMesh *srcm, SBsp3 *bsp3);
|
void AddAgainstBsp(SMesh *srcm, SBsp3 *bsp3);
|
||||||
void MakeFromUnion(SMesh *a, SMesh *b);
|
void MakeFromUnion(SMesh *a, SMesh *b);
|
||||||
void MakeFromDifference(SMesh *a, SMesh *b);
|
void MakeFromDifference(SMesh *a, SMesh *b);
|
||||||
|
bool MakeFromInterferenceCheck(SMesh *srca, SMesh *srcb, SMesh *errorAt);
|
||||||
|
|
||||||
DWORD FirstIntersectionWith(Point2d mp);
|
DWORD FirstIntersectionWith(Point2d mp);
|
||||||
};
|
};
|
||||||
|
|
28
sketch.cpp
28
sketch.cpp
|
@ -737,13 +737,22 @@ void Group::GenerateMesh(void) {
|
||||||
// So our group's mesh appears in outm. Combine this with the previous
|
// So our group's mesh appears in outm. Combine this with the previous
|
||||||
// group's mesh, using the requested operation.
|
// group's mesh, using the requested operation.
|
||||||
mesh.Clear();
|
mesh.Clear();
|
||||||
|
bool prevMeshError = meshError.yes;
|
||||||
|
meshError.yes = false;
|
||||||
|
meshError.interferesAt.Clear();
|
||||||
SMesh *a = PreviousGroupMesh();
|
SMesh *a = PreviousGroupMesh();
|
||||||
if(meshCombine == COMBINE_AS_UNION) {
|
if(meshCombine == COMBINE_AS_UNION) {
|
||||||
mesh.MakeFromUnion(a, &outm);
|
mesh.MakeFromUnion(a, &outm);
|
||||||
} else if(meshCombine == COMBINE_AS_DIFFERENCE) {
|
} else if(meshCombine == COMBINE_AS_DIFFERENCE) {
|
||||||
mesh.MakeFromDifference(a, &outm);
|
mesh.MakeFromDifference(a, &outm);
|
||||||
} else {
|
} 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();
|
outm.Clear();
|
||||||
}
|
}
|
||||||
|
@ -789,6 +798,23 @@ void Group::Draw(void) {
|
||||||
if(SS.GW.showShaded) glxFillMesh(specColor, &mesh, mh, ms1, ms2);
|
if(SS.GW.showShaded) glxFillMesh(specColor, &mesh, mh, ms1, ms2);
|
||||||
glDisable(GL_LIGHTING);
|
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.showMesh) glxDebugMesh(&mesh);
|
||||||
|
|
||||||
if(!SS.GW.showShaded) return;
|
if(!SS.GW.showShaded) return;
|
||||||
|
|
4
sketch.h
4
sketch.h
|
@ -124,6 +124,10 @@ public:
|
||||||
bool yes;
|
bool yes;
|
||||||
} polyError;
|
} polyError;
|
||||||
SMesh mesh;
|
SMesh mesh;
|
||||||
|
struct {
|
||||||
|
SMesh interferesAt;
|
||||||
|
bool yes;
|
||||||
|
} meshError;
|
||||||
|
|
||||||
static const int COMBINE_AS_UNION = 0;
|
static const int COMBINE_AS_UNION = 0;
|
||||||
static const int COMBINE_AS_DIFFERENCE = 1;
|
static const int COMBINE_AS_DIFFERENCE = 1;
|
||||||
|
|
|
@ -656,6 +656,9 @@ void TextWindow::ShowGroupInfo(void) {
|
||||||
Group::COMBINE_AS_ASSEMBLE,
|
Group::COMBINE_AS_ASSEMBLE,
|
||||||
(asy || !asa ? "" : "assemble"), (asy && asa ? "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) {
|
if(g->type == Group::EXTRUDE) {
|
||||||
#define TWOX(v) v v
|
#define TWOX(v) v v
|
||||||
|
|
Loading…
Reference in New Issue