More coincident fixing; test for edge-on-edge, fix some gross
stupidity. [git-p4: depot-paths = "//depot/solvespace/": change = 1915]solver
parent
c6b429b9ce
commit
577cdf2255
|
@ -193,10 +193,10 @@ static int TagByClassifiedEdge(int bspclass, int reg)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
case SBspUv::EDGE_PARALLEL:
|
case SBspUv::EDGE_PARALLEL:
|
||||||
return INSIDE(reg, OUTDIR);
|
return INSIDE(reg, INDIR);
|
||||||
|
|
||||||
case SBspUv::EDGE_ANTIPARALLEL:
|
case SBspUv::EDGE_ANTIPARALLEL:
|
||||||
return INSIDE(reg, INDIR);
|
return INSIDE(reg, OUTDIR);
|
||||||
|
|
||||||
default: oops();
|
default: oops();
|
||||||
}
|
}
|
||||||
|
@ -214,6 +214,23 @@ void DBPEDGE(int tag) {
|
||||||
(tag & INSIDE(ORIG, OUTDIR)) ? "orig" : "");
|
(tag & INSIDE(ORIG, OUTDIR)) ? "orig" : "");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void DEBUGEDGELIST(SEdgeList *sel, SSurface *surf) {
|
||||||
|
SEdge *se;
|
||||||
|
for(se = sel->l.First(); se; se = sel->l.NextAfter(se)) {
|
||||||
|
Vector mid = (se->a).Plus(se->b).ScaledBy(0.5);
|
||||||
|
Vector arrow = (se->b).Minus(se->a);
|
||||||
|
SWAP(double, arrow.x, arrow.y);
|
||||||
|
arrow.x *= -1;
|
||||||
|
arrow = arrow.WithMagnitude(0.03);
|
||||||
|
arrow = arrow.Plus(mid);
|
||||||
|
|
||||||
|
SS.nakedEdges.AddEdge(surf->PointAt(se->a.x, se->a.y),
|
||||||
|
surf->PointAt(se->b.x, se->b.y));
|
||||||
|
SS.nakedEdges.AddEdge(surf->PointAt(mid.x, mid.y),
|
||||||
|
surf->PointAt(arrow.x, arrow.y));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
// Trim this surface against the specified shell, in the way that's appropriate
|
// Trim this surface against the specified shell, in the way that's appropriate
|
||||||
// for the specified Boolean operation type (and which operand we are). We
|
// for the specified Boolean operation type (and which operand we are). We
|
||||||
|
@ -243,11 +260,14 @@ SSurface SSurface::MakeCopyTrimAgainst(SShell *agnst, SShell *parent,
|
||||||
ret.Reverse();
|
ret.Reverse();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Build up our original trim polygon
|
// Build up our original trim polygon; remember the coordinates could
|
||||||
|
// be changed if we just flipped the surface normal.
|
||||||
SEdgeList orig;
|
SEdgeList orig;
|
||||||
ZERO(&orig);
|
ZERO(&orig);
|
||||||
ret.MakeEdgesInto(into, &orig, true);
|
ret.MakeEdgesInto(into, &orig, true);
|
||||||
ret.trim.Clear();
|
ret.trim.Clear();
|
||||||
|
// which means that we can't necessarily use the old BSP...
|
||||||
|
SBspUv *origBsp = SBspUv::From(&orig);
|
||||||
|
|
||||||
// Find any surfaces from the other shell that are coincident with ours,
|
// Find any surfaces from the other shell that are coincident with ours,
|
||||||
// and get the intersection polygons, grouping surfaces with the same
|
// and get the intersection polygons, grouping surfaces with the same
|
||||||
|
@ -295,7 +315,10 @@ SSurface SSurface::MakeCopyTrimAgainst(SShell *agnst, SShell *parent,
|
||||||
Vector tn = ret.NormalAt(ta.x, ta.y);
|
Vector tn = ret.NormalAt(ta.x, ta.y);
|
||||||
Vector sn = ss->NormalAt(auv.x, auv.y);
|
Vector sn = ss->NormalAt(auv.x, auv.y);
|
||||||
|
|
||||||
bool bkwds = false;
|
// We are subtracting the portion of our surface that
|
||||||
|
// lies in the shell, so the in-plane edge normal should
|
||||||
|
// point opposite to the surface normal.
|
||||||
|
bool bkwds = true;
|
||||||
if((tn.Cross(b.Minus(a))).Dot(sn) < 0) bkwds = !bkwds;
|
if((tn.Cross(b.Minus(a))).Dot(sn) < 0) bkwds = !bkwds;
|
||||||
if(type == SShell::AS_DIFFERENCE && !opA) bkwds = !bkwds;
|
if(type == SShell::AS_DIFFERENCE && !opA) bkwds = !bkwds;
|
||||||
if(bkwds) {
|
if(bkwds) {
|
||||||
|
@ -339,10 +362,16 @@ SSurface SSurface::MakeCopyTrimAgainst(SShell *agnst, SShell *parent,
|
||||||
tag |= INSIDE(SHELL, INDIR) | INSIDE(SHELL, OUTDIR);
|
tag |= INSIDE(SHELL, INDIR) | INSIDE(SHELL, OUTDIR);
|
||||||
} else if(c_shell == SShell::OUTSIDE) {
|
} else if(c_shell == SShell::OUTSIDE) {
|
||||||
tag |= 0;
|
tag |= 0;
|
||||||
} else if(c_shell == SShell::ON_PARALLEL) {
|
} else if(c_shell == SShell::SURF_PARALLEL) {
|
||||||
tag |= INSIDE(SHELL, INDIR);
|
tag |= INSIDE(SHELL, INDIR);
|
||||||
} else if(c_shell == SShell::ON_ANTIPARALLEL) {
|
} else if(c_shell == SShell::SURF_ANTIPARALLEL) {
|
||||||
tag |= INSIDE(SHELL, OUTDIR);
|
tag |= INSIDE(SHELL, OUTDIR);
|
||||||
|
} else if(c_shell == SShell::EDGE_PARALLEL) {
|
||||||
|
tag |= INSIDE(SHELL, INDIR);
|
||||||
|
} else if(c_shell == SShell::EDGE_ANTIPARALLEL) {
|
||||||
|
tag |= INSIDE(SHELL, OUTDIR);
|
||||||
|
} else if(c_shell == SShell::EDGE_TANGENT) {
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(KeepEdge(type, opA, tag)) {
|
if(KeepEdge(type, opA, tag)) {
|
||||||
|
@ -354,7 +383,7 @@ SSurface SSurface::MakeCopyTrimAgainst(SShell *agnst, SShell *parent,
|
||||||
Point2d auv = (se->a).ProjectXy(),
|
Point2d auv = (se->a).ProjectXy(),
|
||||||
buv = (se->b).ProjectXy();
|
buv = (se->b).ProjectXy();
|
||||||
|
|
||||||
int c_this = bsp->ClassifyEdge(auv, buv);
|
int c_this = origBsp->ClassifyEdge(auv, buv);
|
||||||
int c_same = sameBsp->ClassifyEdge(auv, buv);
|
int c_same = sameBsp->ClassifyEdge(auv, buv);
|
||||||
int c_opp = oppositeBsp->ClassifyEdge(auv, buv);
|
int c_opp = oppositeBsp->ClassifyEdge(auv, buv);
|
||||||
|
|
||||||
|
@ -370,15 +399,12 @@ SSurface SSurface::MakeCopyTrimAgainst(SShell *agnst, SShell *parent,
|
||||||
tag |= INSIDE(SHELL, OUTDIR);
|
tag |= INSIDE(SHELL, OUTDIR);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(I == 0) DBPEDGE(tag);
|
|
||||||
|
|
||||||
if(KeepEdge(type, opA, tag)) {
|
if(KeepEdge(type, opA, tag)) {
|
||||||
final.AddEdge(se->b, se->a, se->auxA, !se->auxB);
|
final.AddEdge(se->a, se->b, se->auxA, se->auxB);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// If our surface intersects an edge, then it will intersect two surfaces
|
// Cull extraneous edges; duplicates or anti-parallel pairs
|
||||||
// from the shell at that edge, so we'll get a duplicate. Cull those.
|
|
||||||
final.l.ClearTags();
|
final.l.ClearTags();
|
||||||
int i, j;
|
int i, j;
|
||||||
for(i = 0; i < final.l.n; i++) {
|
for(i = 0; i < final.l.n; i++) {
|
||||||
|
@ -386,26 +412,22 @@ SSurface SSurface::MakeCopyTrimAgainst(SShell *agnst, SShell *parent,
|
||||||
for(j = i+1; j < final.l.n; j++) {
|
for(j = i+1; j < final.l.n; j++) {
|
||||||
SEdge *set = &(final.l.elem[j]);
|
SEdge *set = &(final.l.elem[j]);
|
||||||
if((set->a).Equals(se->a) && (set->b).Equals(se->b)) {
|
if((set->a).Equals(se->a) && (set->b).Equals(se->b)) {
|
||||||
|
// Two parallel edges exist; so keep only the first one. This
|
||||||
|
// can happen if our surface intersects the shell at an edge,
|
||||||
|
// so that we get two copies of the intersection edge.
|
||||||
|
set->tag = 1;
|
||||||
|
}
|
||||||
|
if((set->a).Equals(se->b) && (set->b).Equals(se->a)) {
|
||||||
|
// Two anti-parallel edges exist; so keep neither.
|
||||||
|
se->tag = 1;
|
||||||
set->tag = 1;
|
set->tag = 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(I == 0) {
|
|
||||||
Vector mid = (se->a).Plus(se->b).ScaledBy(0.5);
|
|
||||||
Vector arrow = (se->b).Minus(se->a);
|
|
||||||
SWAP(double, arrow.x, arrow.y);
|
|
||||||
arrow.x *= -1;
|
|
||||||
arrow = arrow.WithMagnitude(0.03);
|
|
||||||
arrow = arrow.Plus(mid);
|
|
||||||
|
|
||||||
SS.nakedEdges.AddEdge(ret.PointAt(se->a.x, se->a.y),
|
|
||||||
ret.PointAt(se->b.x, se->b.y));
|
|
||||||
SS.nakedEdges.AddEdge(ret.PointAt(mid.x, mid.y),
|
|
||||||
ret.PointAt(arrow.x, arrow.y));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
final.l.RemoveTagged();
|
final.l.RemoveTagged();
|
||||||
|
|
||||||
|
// if(I == 1) DEBUGEDGELIST(&final, &ret);
|
||||||
|
|
||||||
// Use our reassembled edges to trim the new surface.
|
// Use our reassembled edges to trim the new surface.
|
||||||
ret.TrimFromEdgeList(&final);
|
ret.TrimFromEdgeList(&final);
|
||||||
|
|
||||||
|
@ -468,8 +490,8 @@ void SShell::MakeFromBoolean(SShell *a, SShell *b, int type) {
|
||||||
a->CopySurfacesTrimAgainst(b, this, type, true);
|
a->CopySurfacesTrimAgainst(b, this, type, true);
|
||||||
b->CopySurfacesTrimAgainst(a, this, type, false);
|
b->CopySurfacesTrimAgainst(a, this, type, false);
|
||||||
} else {
|
} else {
|
||||||
I = 0;
|
|
||||||
a->CopySurfacesTrimAgainst(b, this, type, true);
|
a->CopySurfacesTrimAgainst(b, this, type, true);
|
||||||
|
I = 0;
|
||||||
b->CopySurfacesTrimAgainst(a, this, type, false);
|
b->CopySurfacesTrimAgainst(a, this, type, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -224,8 +224,12 @@ public:
|
||||||
|
|
||||||
static const int INSIDE = 100;
|
static const int INSIDE = 100;
|
||||||
static const int OUTSIDE = 200;
|
static const int OUTSIDE = 200;
|
||||||
static const int ON_PARALLEL = 300;
|
static const int SURF_PARALLEL = 300;
|
||||||
static const int ON_ANTIPARALLEL = 400;
|
static const int SURF_ANTIPARALLEL = 400;
|
||||||
|
static const int EDGE_PARALLEL = 500;
|
||||||
|
static const int EDGE_ANTIPARALLEL = 600;
|
||||||
|
static const int EDGE_TANGENT = 700;
|
||||||
|
|
||||||
int ClassifyPoint(Vector p, Vector out);
|
int ClassifyPoint(Vector p, Vector out);
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -110,7 +110,9 @@ int SShell::ClassifyPoint(Vector p, Vector pout) {
|
||||||
|
|
||||||
srand(0);
|
srand(0);
|
||||||
|
|
||||||
int ret, cnt = 0;
|
int ret, cnt = 0, edge_inters;
|
||||||
|
double edge_dotp[2];
|
||||||
|
|
||||||
for(;;) {
|
for(;;) {
|
||||||
// Cast a ray in a random direction (two-sided so that we test if
|
// Cast a ray in a random direction (two-sided so that we test if
|
||||||
// the point lies on a surface, but use only one side for in/out
|
// the point lies on a surface, but use only one side for in/out
|
||||||
|
@ -122,6 +124,7 @@ int SShell::ClassifyPoint(Vector p, Vector pout) {
|
||||||
double dmin = VERY_POSITIVE;
|
double dmin = VERY_POSITIVE;
|
||||||
ret = OUTSIDE; // no intersections means it's outside
|
ret = OUTSIDE; // no intersections means it's outside
|
||||||
bool onEdge = false;
|
bool onEdge = false;
|
||||||
|
edge_inters = 0;
|
||||||
|
|
||||||
SInter *si;
|
SInter *si;
|
||||||
for(si = l.First(); si; si = l.NextAfter(si)) {
|
for(si = l.First(); si; si = l.NextAfter(si)) {
|
||||||
|
@ -133,18 +136,24 @@ int SShell::ClassifyPoint(Vector p, Vector pout) {
|
||||||
|
|
||||||
double d = ((si->p).Minus(p)).Magnitude();
|
double d = ((si->p).Minus(p)).Magnitude();
|
||||||
|
|
||||||
|
// Handle edge-on-edge
|
||||||
|
if(d < LENGTH_EPS && si->onEdge && edge_inters < 2) {
|
||||||
|
edge_dotp[edge_inters] = (si->surfNormal).Dot(pout);
|
||||||
|
edge_inters++;
|
||||||
|
}
|
||||||
|
|
||||||
if(d < dmin) {
|
if(d < dmin) {
|
||||||
dmin = d;
|
dmin = d;
|
||||||
if(d < LENGTH_EPS) {
|
if(d < LENGTH_EPS) {
|
||||||
// Lies on the surface
|
// Edge-on-face (unless edge-on-edge above supercedes)
|
||||||
if((si->surfNormal).Dot(pout) > 0) {
|
if((si->surfNormal).Dot(pout) > 0) {
|
||||||
ret = ON_PARALLEL;
|
ret = SURF_PARALLEL;
|
||||||
} else {
|
} else {
|
||||||
ret = ON_ANTIPARALLEL;
|
ret = SURF_ANTIPARALLEL;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Does not lie on this surface; inside or out, depending
|
// Edge does not lie on surface; either strictly inside
|
||||||
// on the normal
|
// or strictly outside
|
||||||
if((si->surfNormal).Dot(ray) > 0) {
|
if((si->surfNormal).Dot(ray) > 0) {
|
||||||
ret = INSIDE;
|
ret = INSIDE;
|
||||||
} else {
|
} else {
|
||||||
|
@ -157,15 +166,28 @@ int SShell::ClassifyPoint(Vector p, Vector pout) {
|
||||||
l.Clear();
|
l.Clear();
|
||||||
|
|
||||||
// If the point being tested lies exactly on an edge of the shell,
|
// If the point being tested lies exactly on an edge of the shell,
|
||||||
// then our ray always lies on edge, and that's okay.
|
// then our ray always lies on edge, and that's okay. Otherwise
|
||||||
if(ret == ON_PARALLEL || ret == ON_ANTIPARALLEL || !onEdge) break;
|
// try again in a different random direction.
|
||||||
if(cnt++ > 10) {
|
if((edge_inters == 2) || !onEdge) break;
|
||||||
|
if(cnt++ > 20) {
|
||||||
dbp("can't find a ray that doesn't hit on edge!");
|
dbp("can't find a ray that doesn't hit on edge!");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret;
|
if(edge_inters == 2) {
|
||||||
|
double tol = 1e-3;
|
||||||
|
|
||||||
|
if(edge_dotp[0] > -tol && edge_dotp[1] > -tol) {
|
||||||
|
return EDGE_PARALLEL;
|
||||||
|
} else if(edge_dotp[0] < tol && edge_dotp[1] < tol) {
|
||||||
|
return EDGE_ANTIPARALLEL;
|
||||||
|
} else {
|
||||||
|
return EDGE_TANGENT;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
|
|
Loading…
Reference in New Issue