Fix stupidity in Point2d::DistanceToLine, and classify line
segments in Boolean against the shell, not the intersection polygon. (We just cast a ray, and use the surface-line intersection function that already existed.) That's slow, but can be accelerated later. [git-p4: depot-paths = "//depot/solvespace/": change = 1911]solver
parent
9ffe95ea65
commit
d0ab8270d9
|
@ -13,11 +13,11 @@ void SShell::MakeFromDifferenceOf(SShell *a, SShell *b) {
|
|||
static Vector LineStart, LineDirection;
|
||||
static int ByTAlongLine(const void *av, const void *bv)
|
||||
{
|
||||
Vector *a = (Vector *)av,
|
||||
*b = (Vector *)bv;
|
||||
SInter *a = (SInter *)av,
|
||||
*b = (SInter *)bv;
|
||||
|
||||
double ta = (a->Minus(LineStart)).DivPivoting(LineDirection),
|
||||
tb = (b->Minus(LineStart)).DivPivoting(LineDirection);
|
||||
double ta = (a->p.Minus(LineStart)).DivPivoting(LineDirection),
|
||||
tb = (b->p.Minus(LineStart)).DivPivoting(LineDirection);
|
||||
|
||||
return (ta > tb) ? 1 : -1;
|
||||
}
|
||||
|
@ -34,7 +34,7 @@ SCurve SCurve::MakeCopySplitAgainst(SShell *agnstA, SShell *agnstB) {
|
|||
p = pts.NextAfter(p);
|
||||
|
||||
for(; p; p = pts.NextAfter(p)) {
|
||||
List<Vector> il;
|
||||
List<SInter> il;
|
||||
ZERO(&il);
|
||||
|
||||
// Find all the intersections with the two passed shells
|
||||
|
@ -48,12 +48,13 @@ SCurve SCurve::MakeCopySplitAgainst(SShell *agnstA, SShell *agnstB) {
|
|||
LineDirection = p->Minus(prev);
|
||||
qsort(il.elem, il.n, sizeof(il.elem[0]), ByTAlongLine);
|
||||
|
||||
Vector *pi;
|
||||
SInter *pi;
|
||||
for(pi = il.First(); pi; pi = il.NextAfter(pi)) {
|
||||
ret.pts.Add(pi);
|
||||
ret.pts.Add(&(pi->p));
|
||||
}
|
||||
}
|
||||
|
||||
il.Clear();
|
||||
ret.pts.Add(p);
|
||||
prev = *p;
|
||||
}
|
||||
|
@ -197,31 +198,23 @@ SSurface SSurface::MakeCopyTrimAgainst(SShell *agnst, SShell *parent,
|
|||
SEdgeList final;
|
||||
ZERO(&final);
|
||||
|
||||
if(I == 2) dbp("INTERBSP: %d", inter.l.n);
|
||||
SBspUv *interbsp = SBspUv::From(&inter);
|
||||
if(I == 2) dbp("INTEROVER");
|
||||
|
||||
|
||||
SEdge *se;
|
||||
N = 0;
|
||||
for(se = orig.l.First(); se; se = orig.l.NextAfter(se)) {
|
||||
int c = interbsp->ClassifyEdge(se->a.ProjectXy(), se->b.ProjectXy());
|
||||
Vector ea = PointAt(se->a.x, se->a.y),
|
||||
eb = PointAt(se->b.x, se->b.y);
|
||||
int c = agnst->ClassifyPoint(ea.Plus(eb).ScaledBy(0.5));
|
||||
|
||||
if(I == 2) dbp("edge from %.3f %.3f %.3f to %.3f %.3f %.3f",
|
||||
CO(PointAt(se->a.x, se->a.y)), CO(PointAt(se->b.x, se->b.y)));
|
||||
|
||||
if(c == SBspUv::OUTSIDE) {
|
||||
if(I == 2) dbp(" keep");
|
||||
if(c == SShell::OUTSIDE) {
|
||||
final.AddEdge(se->a, se->b, se->auxA, se->auxB);
|
||||
} else {
|
||||
if(I == 2) dbp(" don't keep, %d", c);
|
||||
}
|
||||
N++;
|
||||
}
|
||||
|
||||
for(se = inter.l.First(); se; se = inter.l.NextAfter(se)) {
|
||||
int c = bsp->ClassifyEdge(se->a.ProjectXy(), se->b.ProjectXy());
|
||||
|
||||
if(I == 2) {
|
||||
if(I == 4) {
|
||||
Vector mid = (se->a).Plus(se->b).ScaledBy(0.5);
|
||||
Vector arrow = (se->b).Minus(se->a);
|
||||
SWAP(double, arrow.x, arrow.y);
|
||||
|
@ -229,13 +222,14 @@ SSurface SSurface::MakeCopyTrimAgainst(SShell *agnst, SShell *parent,
|
|||
arrow = arrow.WithMagnitude(0.03);
|
||||
arrow = arrow.Plus(mid);
|
||||
|
||||
if(c == SBspUv::INSIDE) {
|
||||
SS.nakedEdges.AddEdge(PointAt(se->a.x, se->a.y),
|
||||
PointAt(se->b.x, se->b.y));
|
||||
SS.nakedEdges.AddEdge(PointAt(mid.x, mid.y),
|
||||
PointAt(arrow.x, arrow.y));
|
||||
}
|
||||
}
|
||||
|
||||
int c = bsp->ClassifyEdge(se->a.ProjectXy(), se->b.ProjectXy());
|
||||
if(c == SBspUv::INSIDE) {
|
||||
final.AddEdge(se->b, se->a, se->auxA, !se->auxB);
|
||||
}
|
||||
|
@ -303,7 +297,7 @@ void SShell::MakeFromBoolean(SShell *a, SShell *b, int type) {
|
|||
a->CopySurfacesTrimAgainst(b, this, type, true);
|
||||
b->CopySurfacesTrimAgainst(a, this, type, false);
|
||||
} else {
|
||||
I = -1;
|
||||
I = 0;
|
||||
a->CopySurfacesTrimAgainst(b, this, type, true);
|
||||
b->CopySurfacesTrimAgainst(a, this, type, false);
|
||||
}
|
||||
|
@ -369,10 +363,6 @@ SBspUv *SBspUv::From(SEdgeList *el) {
|
|||
}
|
||||
|
||||
SBspUv *SBspUv::InsertEdge(Point2d ea, Point2d eb) {
|
||||
if(I == 2) {
|
||||
dbp("insert edge %.3f %.3f to %.3f %.3f", ea.x, ea.y, eb.x, eb.y);
|
||||
}
|
||||
|
||||
if(!this) {
|
||||
SBspUv *ret = Alloc();
|
||||
ret->a = ea;
|
||||
|
@ -434,12 +424,7 @@ int SBspUv::ClassifyPoint(Point2d p, Point2d eb) {
|
|||
|
||||
double dp = p.Dot(n) - d;
|
||||
|
||||
if(I == 2 && N == 5) {
|
||||
dbp("point %.3f %.3f has d=%.3f", p.x, p.y, dp);
|
||||
}
|
||||
|
||||
if(fabs(dp) < LENGTH_EPS) {
|
||||
if(I == 2 && N == 5) dbp(" on line");
|
||||
SBspUv *f = this;
|
||||
while(f) {
|
||||
Point2d ba = (f->b).Minus(f->a);
|
||||
|
@ -457,12 +442,15 @@ int SBspUv::ClassifyPoint(Point2d p, Point2d eb) {
|
|||
f = f->more;
|
||||
}
|
||||
// Pick arbitrarily which side to send it down, doesn't matter
|
||||
return neg ? neg->ClassifyPoint(p, eb) : OUTSIDE;
|
||||
int c1 = neg ? neg->ClassifyPoint(p, eb) : OUTSIDE;
|
||||
int c2 = pos ? pos->ClassifyPoint(p, eb) : INSIDE;
|
||||
if(c1 != c2) {
|
||||
dbp("MISMATCH: %d %d %08x %08x", c1, c2, neg, pos);
|
||||
}
|
||||
return c1;
|
||||
} else if(dp > 0) {
|
||||
if(I == 2 && N == 5) dbp(" pos");
|
||||
return pos ? pos->ClassifyPoint(p, eb) : INSIDE;
|
||||
} else {
|
||||
if(I == 2 && N == 5) dbp(" neg");
|
||||
return neg ? neg->ClassifyPoint(p, eb) : OUTSIDE;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -145,6 +145,14 @@ public:
|
|||
static STrimBy STrimBy::EntireCurve(SShell *shell, hSCurve hsc, bool bkwds);
|
||||
};
|
||||
|
||||
// An intersection point between a line and a surface
|
||||
class SInter {
|
||||
public:
|
||||
Vector p;
|
||||
double dot; // between line and surface's normal
|
||||
hSSurface surface;
|
||||
};
|
||||
|
||||
// A rational polynomial surface in Bezier form.
|
||||
class SSurface {
|
||||
public:
|
||||
|
@ -172,7 +180,7 @@ public:
|
|||
void TrimFromEdgeList(SEdgeList *el);
|
||||
void IntersectAgainst(SSurface *b, SShell *agnstA, SShell *agnstB,
|
||||
SShell *into);
|
||||
void AllPointsIntersecting(Vector a, Vector b, List<Vector> *l);
|
||||
void AllPointsIntersecting(Vector a, Vector b, List<SInter> *l);
|
||||
|
||||
void ClosestPointTo(Vector p, double *u, double *v);
|
||||
Vector PointAt(double u, double v);
|
||||
|
@ -205,9 +213,15 @@ public:
|
|||
void CopySurfacesTrimAgainst(SShell *against, SShell *into, int t, bool a);
|
||||
void MakeIntersectionCurvesAgainst(SShell *against, SShell *into);
|
||||
void MakeClassifyingBsps(void);
|
||||
void AllPointsIntersecting(Vector a, Vector b, List<Vector> *il);
|
||||
void AllPointsIntersecting(Vector a, Vector b, List<SInter> *il);
|
||||
void CleanupAfterBoolean(void);
|
||||
|
||||
static const int INSIDE = 100;
|
||||
static const int OUTSIDE = 200;
|
||||
static const int ON_SURFACE = 300;
|
||||
int ClassifyPoint(Vector p);
|
||||
|
||||
|
||||
void MakeFromCopyOf(SShell *a);
|
||||
void MakeFromTransformationOf(SShell *a, Vector trans, Quaternion q);
|
||||
|
||||
|
|
|
@ -56,7 +56,7 @@ void SSurface::IntersectAgainst(SSurface *b, SShell *agnstA, SShell *agnstB,
|
|||
// cases, just giving up for now
|
||||
}
|
||||
|
||||
void SSurface::AllPointsIntersecting(Vector a, Vector b, List<Vector> *l) {
|
||||
void SSurface::AllPointsIntersecting(Vector a, Vector b, List<SInter> *l) {
|
||||
if(degm == 1 && degn == 1) {
|
||||
// line-plane intersection
|
||||
Vector p = ctrl[0][0];
|
||||
|
@ -74,16 +74,51 @@ void SSurface::AllPointsIntersecting(Vector a, Vector b, List<Vector> *l) {
|
|||
Point2d puv, dummy = { 0, 0 };
|
||||
ClosestPointTo(pi, &(puv.x), &(puv.y));
|
||||
if(bsp->ClassifyPoint(puv, dummy) != SBspUv::OUTSIDE) {
|
||||
l->Add(&pi);
|
||||
SInter si;
|
||||
si.p = pi;
|
||||
si.dot = NormalAt(puv.x, puv.y).Dot(b.Minus(a));
|
||||
si.surface = h;
|
||||
l->Add(&si);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SShell::AllPointsIntersecting(Vector a, Vector b, List<Vector> *il) {
|
||||
void SShell::AllPointsIntersecting(Vector a, Vector b, List<SInter> *il) {
|
||||
SSurface *ss;
|
||||
for(ss = surface.First(); ss; ss = surface.NextAfter(ss)) {
|
||||
ss->AllPointsIntersecting(a, b, il);
|
||||
}
|
||||
}
|
||||
|
||||
int SShell::ClassifyPoint(Vector p) {
|
||||
List<SInter> l;
|
||||
ZERO(&l);
|
||||
|
||||
Vector d = Vector::From(1e5, 0, 0); // direction is arbitrary
|
||||
// but it does need to be a one-sided ray
|
||||
AllPointsIntersecting(p, p.Plus(d), &l);
|
||||
|
||||
double dmin = VERY_POSITIVE;
|
||||
int ret = OUTSIDE; // no intersections means it's outside
|
||||
|
||||
SInter *si;
|
||||
for(si = l.First(); si; si = l.NextAfter(si)) {
|
||||
double d = ((si->p).Minus(p)).Magnitude();
|
||||
|
||||
if(d < dmin) {
|
||||
dmin = d;
|
||||
if(d < LENGTH_EPS) {
|
||||
ret = ON_SURFACE;
|
||||
} else if(si->dot > 0) {
|
||||
ret = INSIDE;
|
||||
} else {
|
||||
ret = OUTSIDE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
l.Clear();
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
2
util.cpp
2
util.cpp
|
@ -667,7 +667,7 @@ double Point2d::Dot(Point2d p) {
|
|||
|
||||
double Point2d::DistanceToLine(Point2d p0, Point2d dp, bool segment) {
|
||||
double m = dp.x*dp.x + dp.y*dp.y;
|
||||
if(m < 0.05) return 1e12;
|
||||
if(m < LENGTH_EPS*LENGTH_EPS) return VERY_POSITIVE;
|
||||
|
||||
// Let our line be p = p0 + t*dp, for a scalar t from 0 to 1
|
||||
double t = (dp.x*(x - p0.x) + dp.y*(y - p0.y))/m;
|
||||
|
|
Loading…
Reference in New Issue