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 Vector LineStart, LineDirection;
|
||||||
static int ByTAlongLine(const void *av, const void *bv)
|
static int ByTAlongLine(const void *av, const void *bv)
|
||||||
{
|
{
|
||||||
Vector *a = (Vector *)av,
|
SInter *a = (SInter *)av,
|
||||||
*b = (Vector *)bv;
|
*b = (SInter *)bv;
|
||||||
|
|
||||||
double ta = (a->Minus(LineStart)).DivPivoting(LineDirection),
|
double ta = (a->p.Minus(LineStart)).DivPivoting(LineDirection),
|
||||||
tb = (b->Minus(LineStart)).DivPivoting(LineDirection);
|
tb = (b->p.Minus(LineStart)).DivPivoting(LineDirection);
|
||||||
|
|
||||||
return (ta > tb) ? 1 : -1;
|
return (ta > tb) ? 1 : -1;
|
||||||
}
|
}
|
||||||
|
@ -34,7 +34,7 @@ SCurve SCurve::MakeCopySplitAgainst(SShell *agnstA, SShell *agnstB) {
|
||||||
p = pts.NextAfter(p);
|
p = pts.NextAfter(p);
|
||||||
|
|
||||||
for(; p; p = pts.NextAfter(p)) {
|
for(; p; p = pts.NextAfter(p)) {
|
||||||
List<Vector> il;
|
List<SInter> il;
|
||||||
ZERO(&il);
|
ZERO(&il);
|
||||||
|
|
||||||
// Find all the intersections with the two passed shells
|
// Find all the intersections with the two passed shells
|
||||||
|
@ -48,12 +48,13 @@ SCurve SCurve::MakeCopySplitAgainst(SShell *agnstA, SShell *agnstB) {
|
||||||
LineDirection = p->Minus(prev);
|
LineDirection = p->Minus(prev);
|
||||||
qsort(il.elem, il.n, sizeof(il.elem[0]), ByTAlongLine);
|
qsort(il.elem, il.n, sizeof(il.elem[0]), ByTAlongLine);
|
||||||
|
|
||||||
Vector *pi;
|
SInter *pi;
|
||||||
for(pi = il.First(); pi; pi = il.NextAfter(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);
|
ret.pts.Add(p);
|
||||||
prev = *p;
|
prev = *p;
|
||||||
}
|
}
|
||||||
|
@ -197,31 +198,23 @@ SSurface SSurface::MakeCopyTrimAgainst(SShell *agnst, SShell *parent,
|
||||||
SEdgeList final;
|
SEdgeList final;
|
||||||
ZERO(&final);
|
ZERO(&final);
|
||||||
|
|
||||||
if(I == 2) dbp("INTERBSP: %d", inter.l.n);
|
|
||||||
SBspUv *interbsp = SBspUv::From(&inter);
|
SBspUv *interbsp = SBspUv::From(&inter);
|
||||||
if(I == 2) dbp("INTEROVER");
|
|
||||||
|
|
||||||
|
|
||||||
SEdge *se;
|
SEdge *se;
|
||||||
N = 0;
|
|
||||||
for(se = orig.l.First(); se; se = orig.l.NextAfter(se)) {
|
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",
|
if(c == SShell::OUTSIDE) {
|
||||||
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");
|
|
||||||
final.AddEdge(se->a, se->b, se->auxA, se->auxB);
|
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)) {
|
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 mid = (se->a).Plus(se->b).ScaledBy(0.5);
|
||||||
Vector arrow = (se->b).Minus(se->a);
|
Vector arrow = (se->b).Minus(se->a);
|
||||||
SWAP(double, arrow.x, arrow.y);
|
SWAP(double, arrow.x, arrow.y);
|
||||||
|
@ -229,13 +222,14 @@ SSurface SSurface::MakeCopyTrimAgainst(SShell *agnst, SShell *parent,
|
||||||
arrow = arrow.WithMagnitude(0.03);
|
arrow = arrow.WithMagnitude(0.03);
|
||||||
arrow = arrow.Plus(mid);
|
arrow = arrow.Plus(mid);
|
||||||
|
|
||||||
SS.nakedEdges.AddEdge(PointAt(se->a.x, se->a.y),
|
if(c == SBspUv::INSIDE) {
|
||||||
PointAt(se->b.x, se->b.y));
|
SS.nakedEdges.AddEdge(PointAt(se->a.x, se->a.y),
|
||||||
SS.nakedEdges.AddEdge(PointAt(mid.x, mid.y),
|
PointAt(se->b.x, se->b.y));
|
||||||
PointAt(arrow.x, arrow.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) {
|
if(c == SBspUv::INSIDE) {
|
||||||
final.AddEdge(se->b, se->a, se->auxA, !se->auxB);
|
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);
|
a->CopySurfacesTrimAgainst(b, this, type, true);
|
||||||
b->CopySurfacesTrimAgainst(a, this, type, false);
|
b->CopySurfacesTrimAgainst(a, this, type, false);
|
||||||
} else {
|
} else {
|
||||||
I = -1;
|
I = 0;
|
||||||
a->CopySurfacesTrimAgainst(b, this, type, true);
|
a->CopySurfacesTrimAgainst(b, this, type, true);
|
||||||
b->CopySurfacesTrimAgainst(a, this, type, false);
|
b->CopySurfacesTrimAgainst(a, this, type, false);
|
||||||
}
|
}
|
||||||
|
@ -369,10 +363,6 @@ SBspUv *SBspUv::From(SEdgeList *el) {
|
||||||
}
|
}
|
||||||
|
|
||||||
SBspUv *SBspUv::InsertEdge(Point2d ea, Point2d eb) {
|
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) {
|
if(!this) {
|
||||||
SBspUv *ret = Alloc();
|
SBspUv *ret = Alloc();
|
||||||
ret->a = ea;
|
ret->a = ea;
|
||||||
|
@ -434,12 +424,7 @@ int SBspUv::ClassifyPoint(Point2d p, Point2d eb) {
|
||||||
|
|
||||||
double dp = p.Dot(n) - d;
|
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(fabs(dp) < LENGTH_EPS) {
|
||||||
if(I == 2 && N == 5) dbp(" on line");
|
|
||||||
SBspUv *f = this;
|
SBspUv *f = this;
|
||||||
while(f) {
|
while(f) {
|
||||||
Point2d ba = (f->b).Minus(f->a);
|
Point2d ba = (f->b).Minus(f->a);
|
||||||
|
@ -457,12 +442,15 @@ int SBspUv::ClassifyPoint(Point2d p, Point2d eb) {
|
||||||
f = f->more;
|
f = f->more;
|
||||||
}
|
}
|
||||||
// Pick arbitrarily which side to send it down, doesn't matter
|
// 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) {
|
} else if(dp > 0) {
|
||||||
if(I == 2 && N == 5) dbp(" pos");
|
|
||||||
return pos ? pos->ClassifyPoint(p, eb) : INSIDE;
|
return pos ? pos->ClassifyPoint(p, eb) : INSIDE;
|
||||||
} else {
|
} else {
|
||||||
if(I == 2 && N == 5) dbp(" neg");
|
|
||||||
return neg ? neg->ClassifyPoint(p, eb) : OUTSIDE;
|
return neg ? neg->ClassifyPoint(p, eb) : OUTSIDE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -145,6 +145,14 @@ public:
|
||||||
static STrimBy STrimBy::EntireCurve(SShell *shell, hSCurve hsc, bool bkwds);
|
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.
|
// A rational polynomial surface in Bezier form.
|
||||||
class SSurface {
|
class SSurface {
|
||||||
public:
|
public:
|
||||||
|
@ -172,7 +180,7 @@ public:
|
||||||
void TrimFromEdgeList(SEdgeList *el);
|
void TrimFromEdgeList(SEdgeList *el);
|
||||||
void IntersectAgainst(SSurface *b, SShell *agnstA, SShell *agnstB,
|
void IntersectAgainst(SSurface *b, SShell *agnstA, SShell *agnstB,
|
||||||
SShell *into);
|
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);
|
void ClosestPointTo(Vector p, double *u, double *v);
|
||||||
Vector PointAt(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 CopySurfacesTrimAgainst(SShell *against, SShell *into, int t, bool a);
|
||||||
void MakeIntersectionCurvesAgainst(SShell *against, SShell *into);
|
void MakeIntersectionCurvesAgainst(SShell *against, SShell *into);
|
||||||
void MakeClassifyingBsps(void);
|
void MakeClassifyingBsps(void);
|
||||||
void AllPointsIntersecting(Vector a, Vector b, List<Vector> *il);
|
void AllPointsIntersecting(Vector a, Vector b, List<SInter> *il);
|
||||||
void CleanupAfterBoolean(void);
|
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 MakeFromCopyOf(SShell *a);
|
||||||
void MakeFromTransformationOf(SShell *a, Vector trans, Quaternion q);
|
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
|
// 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) {
|
if(degm == 1 && degn == 1) {
|
||||||
// line-plane intersection
|
// line-plane intersection
|
||||||
Vector p = ctrl[0][0];
|
Vector p = ctrl[0][0];
|
||||||
|
@ -74,16 +74,51 @@ void SSurface::AllPointsIntersecting(Vector a, Vector b, List<Vector> *l) {
|
||||||
Point2d puv, dummy = { 0, 0 };
|
Point2d puv, dummy = { 0, 0 };
|
||||||
ClosestPointTo(pi, &(puv.x), &(puv.y));
|
ClosestPointTo(pi, &(puv.x), &(puv.y));
|
||||||
if(bsp->ClassifyPoint(puv, dummy) != SBspUv::OUTSIDE) {
|
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;
|
SSurface *ss;
|
||||||
for(ss = surface.First(); ss; ss = surface.NextAfter(ss)) {
|
for(ss = surface.First(); ss; ss = surface.NextAfter(ss)) {
|
||||||
ss->AllPointsIntersecting(a, b, il);
|
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 Point2d::DistanceToLine(Point2d p0, Point2d dp, bool segment) {
|
||||||
double m = dp.x*dp.x + dp.y*dp.y;
|
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
|
// 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;
|
double t = (dp.x*(x - p0.x) + dp.y*(y - p0.y))/m;
|
||||||
|
|
Loading…
Reference in New Issue