Add Newton iterations to intersect a line with a surface at a
point, and to intersect three surfaces at a point. So now when we split an edge, we can refine the split point to lie exactly on the trim curve, so I can do certain Booleans on curved surfaces. But surface-line intersection is globally broken, since I don't correctly detect the number of intersections or provide a good first guess. I maybe should test by bounding boxes and subdivision. [git-p4: depot-paths = "//depot/solvespace/": change = 1920]
This commit is contained in:
parent
3da1e1d390
commit
2023667311
4
dsc.h
4
dsc.h
@ -52,6 +52,10 @@ public:
|
|||||||
static Vector AtIntersectionOfPlaneAndLine(Vector n, double d,
|
static Vector AtIntersectionOfPlaneAndLine(Vector n, double d,
|
||||||
Vector p0, Vector p1,
|
Vector p0, Vector p1,
|
||||||
bool *parallel);
|
bool *parallel);
|
||||||
|
static Vector AtIntersectionOfPlanes(Vector na, double da,
|
||||||
|
Vector nb, double db,
|
||||||
|
Vector nc, double dc,
|
||||||
|
bool *parallel);
|
||||||
|
|
||||||
double Element(int i);
|
double Element(int i);
|
||||||
bool Equals(Vector v, double tol=LENGTH_EPS);
|
bool Equals(Vector v, double tol=LENGTH_EPS);
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
#include "solvespace.h"
|
#include "solvespace.h"
|
||||||
|
|
||||||
static int I, N;
|
int I, N, FLAG;
|
||||||
|
|
||||||
void SShell::MakeFromUnionOf(SShell *a, SShell *b) {
|
void SShell::MakeFromUnionOf(SShell *a, SShell *b) {
|
||||||
MakeFromBoolean(a, b, AS_UNION);
|
MakeFromBoolean(a, b, AS_UNION);
|
||||||
@ -10,6 +10,14 @@ void SShell::MakeFromDifferenceOf(SShell *a, SShell *b) {
|
|||||||
MakeFromBoolean(a, b, AS_DIFFERENCE);
|
MakeFromBoolean(a, b, AS_DIFFERENCE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
// Take our original pwl curve. Wherever an edge intersects a surface within
|
||||||
|
// either agnstA or agnstB, split the piecewise linear element. Then refine
|
||||||
|
// the intersection so that it lies on all three relevant surfaces: the
|
||||||
|
// intersecting surface, srfA, and srfB. (So the pwl curve should lie at
|
||||||
|
// the intersection of srfA and srfB.) Return a new pwl curve with everything
|
||||||
|
// split.
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
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)
|
||||||
{
|
{
|
||||||
@ -21,10 +29,11 @@ static int ByTAlongLine(const void *av, const void *bv)
|
|||||||
|
|
||||||
return (ta > tb) ? 1 : -1;
|
return (ta > tb) ? 1 : -1;
|
||||||
}
|
}
|
||||||
SCurve SCurve::MakeCopySplitAgainst(SShell *agnstA, SShell *agnstB) {
|
SCurve SCurve::MakeCopySplitAgainst(SShell *agnstA, SShell *agnstB,
|
||||||
|
SSurface *srfA, SSurface *srfB)
|
||||||
|
{
|
||||||
SCurve ret;
|
SCurve ret;
|
||||||
ret = *this;
|
ret = *this;
|
||||||
ret.interCurve = false;
|
|
||||||
ZERO(&(ret.pts));
|
ZERO(&(ret.pts));
|
||||||
|
|
||||||
Vector *p = pts.First();
|
Vector *p = pts.First();
|
||||||
@ -51,6 +60,14 @@ SCurve SCurve::MakeCopySplitAgainst(SShell *agnstA, SShell *agnstB) {
|
|||||||
Vector prev = Vector::From(VERY_POSITIVE, 0, 0);
|
Vector prev = Vector::From(VERY_POSITIVE, 0, 0);
|
||||||
SInter *pi;
|
SInter *pi;
|
||||||
for(pi = il.First(); pi; pi = il.NextAfter(pi)) {
|
for(pi = il.First(); pi; pi = il.NextAfter(pi)) {
|
||||||
|
// The intersection was generated by intersecting the pwl
|
||||||
|
// edge against a surface; so it must be refined to lie
|
||||||
|
// exactly on the original curve.
|
||||||
|
double u, v;
|
||||||
|
(pi->srf)->ClosestPointTo(pi->p, &u, &v, false);
|
||||||
|
(pi->srf)->PointOnSurfaces(srfA, srfB, &u, &v);
|
||||||
|
pi->p = (pi->srf)->PointAt(u, v);
|
||||||
|
|
||||||
// On-edge intersection will generate same split point for
|
// On-edge intersection will generate same split point for
|
||||||
// both surfaces, so don't create zero-length edge.
|
// both surfaces, so don't create zero-length edge.
|
||||||
if(!prev.Equals(pi->p)) {
|
if(!prev.Equals(pi->p)) {
|
||||||
@ -67,10 +84,14 @@ SCurve SCurve::MakeCopySplitAgainst(SShell *agnstA, SShell *agnstB) {
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SShell::CopyCurvesSplitAgainst(SShell *aga, SShell *agb, SShell *into) {
|
void SShell::CopyCurvesSplitAgainst(bool opA, SShell *agnst, SShell *into) {
|
||||||
SCurve *sc;
|
SCurve *sc;
|
||||||
for(sc = curve.First(); sc; sc = curve.NextAfter(sc)) {
|
for(sc = curve.First(); sc; sc = curve.NextAfter(sc)) {
|
||||||
SCurve scn = sc->MakeCopySplitAgainst(aga, agb);
|
SCurve scn = sc->MakeCopySplitAgainst(agnst, NULL,
|
||||||
|
surface.FindById(sc->surfA),
|
||||||
|
surface.FindById(sc->surfB));
|
||||||
|
scn.source = opA ? SCurve::FROM_A : SCurve::FROM_B;
|
||||||
|
|
||||||
hSCurve hsc = into->curve.AddAndAssignId(&scn);
|
hSCurve hsc = into->curve.AddAndAssignId(&scn);
|
||||||
// And note the new ID so that we can rewrite the trims appropriately
|
// And note the new ID so that we can rewrite the trims appropriately
|
||||||
sc->newH = hsc;
|
sc->newH = hsc;
|
||||||
@ -289,7 +310,7 @@ SSurface SSurface::MakeCopyTrimAgainst(SShell *agnst, SShell *parent,
|
|||||||
for(ss = agnst->surface.First(); ss; ss = agnst->surface.NextAfter(ss)) {
|
for(ss = agnst->surface.First(); ss; ss = agnst->surface.NextAfter(ss)) {
|
||||||
SCurve *sc;
|
SCurve *sc;
|
||||||
for(sc = into->curve.First(); sc; sc = into->curve.NextAfter(sc)) {
|
for(sc = into->curve.First(); sc; sc = into->curve.NextAfter(sc)) {
|
||||||
if(!(sc->interCurve)) continue;
|
if(sc->source != SCurve::FROM_INTERSECTION) continue;
|
||||||
if(opA) {
|
if(opA) {
|
||||||
if(sc->surfB.v != h.v || sc->surfA.v != ss->h.v) continue;
|
if(sc->surfB.v != h.v || sc->surfA.v != ss->h.v) continue;
|
||||||
} else {
|
} else {
|
||||||
@ -351,7 +372,11 @@ SSurface SSurface::MakeCopyTrimAgainst(SShell *agnst, SShell *parent,
|
|||||||
eb = ret.PointAt(buv.x, buv.y);
|
eb = ret.PointAt(buv.x, buv.y);
|
||||||
Vector ptout = n.Cross((eb.Minus(ea)));
|
Vector ptout = n.Cross((eb.Minus(ea)));
|
||||||
|
|
||||||
|
if(I == 1 && fabs(((se->b).Minus(se->a).Magnitude()) - 0.166) < 0.01) {
|
||||||
|
FLAG = 1;
|
||||||
|
}
|
||||||
int c_shell = agnst->ClassifyPoint(pt, ptout);
|
int c_shell = agnst->ClassifyPoint(pt, ptout);
|
||||||
|
FLAG = 0;
|
||||||
|
|
||||||
int tag = 0;
|
int tag = 0;
|
||||||
tag |= INSIDE(ORIG, INDIR);
|
tag |= INSIDE(ORIG, INDIR);
|
||||||
@ -376,6 +401,11 @@ SSurface SSurface::MakeCopyTrimAgainst(SShell *agnst, SShell *parent,
|
|||||||
|
|
||||||
if(KeepEdge(type, opA, tag)) {
|
if(KeepEdge(type, opA, tag)) {
|
||||||
final.AddEdge(se->a, se->b, se->auxA, se->auxB);
|
final.AddEdge(se->a, se->b, se->auxA, se->auxB);
|
||||||
|
} else {
|
||||||
|
if(I == 1) {
|
||||||
|
dbp("orig vs. shell: %d (l=%g)",
|
||||||
|
c_shell, ((se->b).Minus(se->a)).Magnitude());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -426,7 +456,7 @@ SSurface SSurface::MakeCopyTrimAgainst(SShell *agnst, SShell *parent,
|
|||||||
}
|
}
|
||||||
final.l.RemoveTagged();
|
final.l.RemoveTagged();
|
||||||
|
|
||||||
// if(I == 0) DEBUGEDGELIST(&final, &ret);
|
// 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);
|
||||||
@ -477,8 +507,8 @@ void SShell::MakeFromBoolean(SShell *a, SShell *b, int type) {
|
|||||||
// Copy over all the original curves, splitting them so that a
|
// Copy over all the original curves, splitting them so that a
|
||||||
// piecwise linear segment never crosses a surface from the other
|
// piecwise linear segment never crosses a surface from the other
|
||||||
// shell.
|
// shell.
|
||||||
a->CopyCurvesSplitAgainst(b, NULL, this);
|
a->CopyCurvesSplitAgainst(true, b, this);
|
||||||
b->CopyCurvesSplitAgainst(a, NULL, this);
|
b->CopyCurvesSplitAgainst(false, a, this);
|
||||||
|
|
||||||
// Generate the intersection curves for each surface in A against all
|
// Generate the intersection curves for each surface in A against all
|
||||||
// the surfaces in B (which is all of the intersection curves).
|
// the surfaces in B (which is all of the intersection curves).
|
||||||
@ -490,8 +520,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 = -1;
|
|
||||||
b->CopySurfacesTrimAgainst(a, this, type, false);
|
b->CopySurfacesTrimAgainst(a, this, type, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
120
srf/ratpoly.cpp
120
srf/ratpoly.cpp
@ -1,6 +1,12 @@
|
|||||||
#include "../solvespace.h"
|
#include "../solvespace.h"
|
||||||
|
|
||||||
double Bernstein(int k, int deg, double t)
|
// Converge it to better than LENGTH_EPS; we want two points, each
|
||||||
|
// independently projected into uv and back, to end up equal with the
|
||||||
|
// LENGTH_EPS. Best case that requires LENGTH_EPS/2, but more is better
|
||||||
|
// and convergence should be fast by now.
|
||||||
|
#define RATPOLY_EPS (LENGTH_EPS/(1e1))
|
||||||
|
|
||||||
|
static double Bernstein(int k, int deg, double t)
|
||||||
{
|
{
|
||||||
if(k > deg || k < 0) return 0;
|
if(k > deg || k < 0) return 0;
|
||||||
|
|
||||||
@ -523,13 +529,13 @@ Vector SSurface::NormalAt(double u, double v) {
|
|||||||
return tu.Cross(tv);
|
return tu.Cross(tv);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SSurface::ClosestPointTo(Vector p, double *u, double *v) {
|
void SSurface::ClosestPointTo(Vector p, double *u, double *v, bool converge) {
|
||||||
int i, j;
|
int i, j;
|
||||||
|
|
||||||
if(degm == 1 && degn == 1) {
|
if(degm == 1 && degn == 1) {
|
||||||
*u = *v = 0; // a plane, perfect no matter what the initial guess
|
*u = *v = 0; // a plane, perfect no matter what the initial guess
|
||||||
} else {
|
} else {
|
||||||
double minDist = 1e10;
|
double minDist = VERY_POSITIVE;
|
||||||
double res = 7.0;
|
double res = 7.0;
|
||||||
for(i = 0; i < (int)res; i++) {
|
for(i = 0; i < (int)res; i++) {
|
||||||
for(j = 0; j <= (int)res; j++) {
|
for(j = 0; j <= (int)res; j++) {
|
||||||
@ -548,15 +554,13 @@ void SSurface::ClosestPointTo(Vector p, double *u, double *v) {
|
|||||||
|
|
||||||
// Initial guess is in u, v
|
// Initial guess is in u, v
|
||||||
Vector p0;
|
Vector p0;
|
||||||
for(i = 0; i < 50; i++) {
|
for(i = 0; i < (converge ? 15 : 3); i++) {
|
||||||
p0 = PointAt(*u, *v);
|
p0 = PointAt(*u, *v);
|
||||||
// Converge it to better than LENGTH_EPS; we want two points, each
|
if(converge) {
|
||||||
// independently projected into uv and back, to end up equal with
|
if(p0.Equals(p, RATPOLY_EPS)) {
|
||||||
// the LENGTH_EPS. Best case that requires LENGTH_EPS/2, but more
|
|
||||||
// is better and convergence should be fast by now.
|
|
||||||
if(p0.Equals(p, LENGTH_EPS/1e2)) {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Vector tu, tv;
|
Vector tu, tv;
|
||||||
TangentsAt(*u, *v, &tu, &tv);
|
TangentsAt(*u, *v, &tu, &tv);
|
||||||
@ -569,15 +573,96 @@ void SSurface::ClosestPointTo(Vector p, double *u, double *v) {
|
|||||||
*u += du / (tu.MagSquared());
|
*u += du / (tu.MagSquared());
|
||||||
*v += dv / (tv.MagSquared());
|
*v += dv / (tv.MagSquared());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(converge) {
|
||||||
dbp("didn't converge");
|
dbp("didn't converge");
|
||||||
dbp("have %.3f %.3f %.3f", CO(p0));
|
dbp("have %.3f %.3f %.3f", CO(p0));
|
||||||
dbp("want %.3f %.3f %.3f", CO(p));
|
dbp("want %.3f %.3f %.3f", CO(p));
|
||||||
dbp("distance = %g", (p.Minus(p0)).Magnitude());
|
dbp("distance = %g", (p.Minus(p0)).Magnitude());
|
||||||
|
}
|
||||||
|
|
||||||
if(isnan(*u) || isnan(*v)) {
|
if(isnan(*u) || isnan(*v)) {
|
||||||
*u = *v = 0;
|
*u = *v = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool SSurface::PointIntersectingLine(Vector p0, Vector p1, double *u, double *v)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
for(i = 0; i < 15; i++) {
|
||||||
|
Vector pi, p, tu, tv;
|
||||||
|
p = PointAt(*u, *v);
|
||||||
|
TangentsAt(*u, *v, &tu, &tv);
|
||||||
|
|
||||||
|
Vector n = (tu.Cross(tv)).WithMagnitude(1);
|
||||||
|
double d = p.Dot(n);
|
||||||
|
|
||||||
|
bool parallel;
|
||||||
|
pi = Vector::AtIntersectionOfPlaneAndLine(n, d, p0, p1, ¶llel);
|
||||||
|
if(parallel) break;
|
||||||
|
|
||||||
|
// Check for convergence
|
||||||
|
if(pi.Equals(p, RATPOLY_EPS)) return true;
|
||||||
|
|
||||||
|
// Adjust our guess and iterate
|
||||||
|
Vector dp = pi.Minus(p);
|
||||||
|
double du = dp.Dot(tu), dv = dp.Dot(tv);
|
||||||
|
*u += du / (tu.MagSquared());
|
||||||
|
*v += dv / (tv.MagSquared());
|
||||||
|
}
|
||||||
|
// dbp("didn't converge (surface intersecting line)");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SSurface::PointOnSurfaces(SSurface *s1, SSurface *s2,
|
||||||
|
double *up, double *vp)
|
||||||
|
{
|
||||||
|
double u[3] = { *up, 0, 0 }, v[3] = { *vp, 0, 0 };
|
||||||
|
SSurface *srf[3] = { this, s1, s2 };
|
||||||
|
|
||||||
|
// Get initial guesses for (u, v) in the other surfaces
|
||||||
|
Vector p = PointAt(*u, *v);
|
||||||
|
(srf[1])->ClosestPointTo(p, &(u[1]), &(v[1]), false);
|
||||||
|
(srf[2])->ClosestPointTo(p, &(u[2]), &(v[2]), false);
|
||||||
|
|
||||||
|
int i, j;
|
||||||
|
for(i = 0; i < 15; i++) {
|
||||||
|
// Approximate each surface by a plane
|
||||||
|
Vector p[3], tu[3], tv[3], n[3];
|
||||||
|
double d[3];
|
||||||
|
for(j = 0; j < 3; j++) {
|
||||||
|
p[j] = (srf[j])->PointAt(u[j], v[j]);
|
||||||
|
(srf[j])->TangentsAt(u[j], v[j], &(tu[j]), &(tv[j]));
|
||||||
|
n[j] = ((tu[j]).Cross(tv[j])).WithMagnitude(1);
|
||||||
|
d[j] = (n[j]).Dot(p[j]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// If a = b and b = c, then does a = c? No, it doesn't.
|
||||||
|
if((p[0]).Equals(p[1], RATPOLY_EPS) &&
|
||||||
|
(p[1]).Equals(p[2], RATPOLY_EPS) &&
|
||||||
|
(p[2]).Equals(p[0], RATPOLY_EPS))
|
||||||
|
{
|
||||||
|
*up = u[0];
|
||||||
|
*vp = v[0];
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool parallel;
|
||||||
|
Vector pi = Vector::AtIntersectionOfPlanes(n[0], d[0],
|
||||||
|
n[1], d[1],
|
||||||
|
n[2], d[2], ¶llel);
|
||||||
|
if(parallel) break;
|
||||||
|
|
||||||
|
for(j = 0; j < 3; j++) {
|
||||||
|
Vector dp = pi.Minus(p[j]);
|
||||||
|
double du = dp.Dot(tu[j]), dv = dp.Dot(tv[j]);
|
||||||
|
u[j] += du / (tu[j]).MagSquared();
|
||||||
|
v[j] += dv / (tv[j]).MagSquared();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
dbp("didn't converge (three surfaces intersecting)");
|
||||||
|
}
|
||||||
|
|
||||||
void SSurface::GetAxisAlignedBounding(Vector *ptMax, Vector *ptMin) {
|
void SSurface::GetAxisAlignedBounding(Vector *ptMax, Vector *ptMin) {
|
||||||
*ptMax = Vector::From(VERY_NEGATIVE, VERY_NEGATIVE, VERY_NEGATIVE);
|
*ptMax = Vector::From(VERY_NEGATIVE, VERY_NEGATIVE, VERY_NEGATIVE);
|
||||||
*ptMin = Vector::From(VERY_POSITIVE, VERY_POSITIVE, VERY_POSITIVE);
|
*ptMin = Vector::From(VERY_POSITIVE, VERY_POSITIVE, VERY_POSITIVE);
|
||||||
@ -756,29 +841,28 @@ void SShell::MakeFromExtrusionOf(SBezierLoopSet *sbls, Vector t0, Vector t1,
|
|||||||
SCurve sc;
|
SCurve sc;
|
||||||
ZERO(&sc);
|
ZERO(&sc);
|
||||||
sb->MakePwlInto(&(sc.pts), t0);
|
sb->MakePwlInto(&(sc.pts), t0);
|
||||||
|
sc.surfA = hs0;
|
||||||
|
sc.surfB = hsext;
|
||||||
hSCurve hc0 = curve.AddAndAssignId(&sc);
|
hSCurve hc0 = curve.AddAndAssignId(&sc);
|
||||||
STrimBy stb0 = STrimBy::EntireCurve(this, hc0, false);
|
|
||||||
|
|
||||||
ZERO(&sc);
|
ZERO(&sc);
|
||||||
sb->MakePwlInto(&(sc.pts), t1);
|
sb->MakePwlInto(&(sc.pts), t1);
|
||||||
|
sc.surfA = hs1;
|
||||||
|
sc.surfB = hsext;
|
||||||
hSCurve hc1 = curve.AddAndAssignId(&sc);
|
hSCurve hc1 = curve.AddAndAssignId(&sc);
|
||||||
STrimBy stb1 = STrimBy::EntireCurve(this, hc1, true);
|
|
||||||
|
|
||||||
|
STrimBy stb0, stb1;
|
||||||
// The translated curves trim the flat top and bottom surfaces.
|
// The translated curves trim the flat top and bottom surfaces.
|
||||||
|
stb0 = STrimBy::EntireCurve(this, hc0, false);
|
||||||
|
stb1 = STrimBy::EntireCurve(this, hc1, true);
|
||||||
(surface.FindById(hs0))->trim.Add(&stb0);
|
(surface.FindById(hs0))->trim.Add(&stb0);
|
||||||
(curve.FindById(hc0))->surfA = hs0;
|
|
||||||
|
|
||||||
(surface.FindById(hs1))->trim.Add(&stb1);
|
(surface.FindById(hs1))->trim.Add(&stb1);
|
||||||
(curve.FindById(hc1))->surfA = hs1;
|
|
||||||
|
|
||||||
// The translated curves also trim the surface of extrusion.
|
// The translated curves also trim the surface of extrusion.
|
||||||
stb0 = STrimBy::EntireCurve(this, hc0, true);
|
stb0 = STrimBy::EntireCurve(this, hc0, true);
|
||||||
(surface.FindById(hsext))->trim.Add(&stb0);
|
|
||||||
(curve.FindById(hc0))->surfB = hsext;
|
|
||||||
|
|
||||||
stb1 = STrimBy::EntireCurve(this, hc1, false);
|
stb1 = STrimBy::EntireCurve(this, hc1, false);
|
||||||
|
(surface.FindById(hsext))->trim.Add(&stb0);
|
||||||
(surface.FindById(hsext))->trim.Add(&stb1);
|
(surface.FindById(hsext))->trim.Add(&stb1);
|
||||||
(curve.FindById(hc1))->surfB = hsext;
|
|
||||||
|
|
||||||
// And form the trim line
|
// And form the trim line
|
||||||
Vector pt = sb->Finish();
|
Vector pt = sb->Finish();
|
||||||
|
@ -6,6 +6,8 @@
|
|||||||
double Bernstein(int k, int deg, double t);
|
double Bernstein(int k, int deg, double t);
|
||||||
double BernsteinDerivative(int k, int deg, double t);
|
double BernsteinDerivative(int k, int deg, double t);
|
||||||
|
|
||||||
|
class SSurface;
|
||||||
|
|
||||||
// Utility data structure, a two-dimensional BSP to accelerate polygon
|
// Utility data structure, a two-dimensional BSP to accelerate polygon
|
||||||
// operations.
|
// operations.
|
||||||
class SBspUv {
|
class SBspUv {
|
||||||
@ -111,8 +113,14 @@ class SCurve {
|
|||||||
public:
|
public:
|
||||||
hSCurve h;
|
hSCurve h;
|
||||||
|
|
||||||
hSCurve newH; // when merging with booleans
|
// In a Boolean, C = A op B. The curves in A and B get copied into C, and
|
||||||
bool interCurve; // it's a newly-calculated intersection
|
// therefore must get new hSCurves assigned. For the curves in A and B,
|
||||||
|
// we use newH to record their new handle in C.
|
||||||
|
hSCurve newH;
|
||||||
|
static const int FROM_A = 100;
|
||||||
|
static const int FROM_B = 200;
|
||||||
|
static const int FROM_INTERSECTION = 300;
|
||||||
|
int source;
|
||||||
|
|
||||||
bool isExact;
|
bool isExact;
|
||||||
SBezier exact;
|
SBezier exact;
|
||||||
@ -123,7 +131,8 @@ public:
|
|||||||
hSSurface surfB;
|
hSSurface surfB;
|
||||||
|
|
||||||
static SCurve FromTransformationOf(SCurve *a, Vector t, Quaternion q);
|
static SCurve FromTransformationOf(SCurve *a, Vector t, Quaternion q);
|
||||||
SCurve MakeCopySplitAgainst(SShell *agnstA, SShell *agnstB);
|
SCurve MakeCopySplitAgainst(SShell *agnstA, SShell *agnstB,
|
||||||
|
SSurface *srfA, SSurface *srfB);
|
||||||
|
|
||||||
void Clear(void);
|
void Clear(void);
|
||||||
};
|
};
|
||||||
@ -148,8 +157,10 @@ public:
|
|||||||
// An intersection point between a line and a surface
|
// An intersection point between a line and a surface
|
||||||
class SInter {
|
class SInter {
|
||||||
public:
|
public:
|
||||||
|
int tag;
|
||||||
Vector p;
|
Vector p;
|
||||||
hSSurface surface;
|
SSurface *srf;
|
||||||
|
hSSurface hsrf;
|
||||||
Vector surfNormal; // of the intersecting surface, at pinter
|
Vector surfNormal; // of the intersecting surface, at pinter
|
||||||
bool onEdge; // pinter is on edge of trim poly
|
bool onEdge; // pinter is on edge of trim poly
|
||||||
};
|
};
|
||||||
@ -181,12 +192,14 @@ 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 AddExactIntersectionCurve(SBezier *sb, hSSurface hsb,
|
void AddExactIntersectionCurve(SBezier *sb, SSurface *srfB,
|
||||||
SShell *agnstA, SShell *agnstB, SShell *into);
|
SShell *agnstA, SShell *agnstB, SShell *into);
|
||||||
void AllPointsIntersecting(Vector a, Vector b,
|
void AllPointsIntersecting(Vector a, Vector b,
|
||||||
List<SInter> *l, bool seg, bool trimmed);
|
List<SInter> *l, bool seg, bool trimmed);
|
||||||
|
|
||||||
void ClosestPointTo(Vector p, double *u, double *v);
|
void ClosestPointTo(Vector p, double *u, double *v, bool converge=true);
|
||||||
|
bool PointIntersectingLine(Vector p0, Vector p1, double *u, double *v);
|
||||||
|
void PointOnSurfaces(SSurface *s1, SSurface *s2, double *u, double *v);
|
||||||
Vector PointAt(double u, double v);
|
Vector PointAt(double u, double v);
|
||||||
void TangentsAt(double u, double v, Vector *tu, Vector *tv);
|
void TangentsAt(double u, double v, Vector *tu, Vector *tv);
|
||||||
Vector NormalAt(double u, double v);
|
Vector NormalAt(double u, double v);
|
||||||
@ -217,7 +230,7 @@ public:
|
|||||||
static const int AS_DIFFERENCE = 11;
|
static const int AS_DIFFERENCE = 11;
|
||||||
static const int AS_INTERSECT = 12;
|
static const int AS_INTERSECT = 12;
|
||||||
void MakeFromBoolean(SShell *a, SShell *b, int type);
|
void MakeFromBoolean(SShell *a, SShell *b, int type);
|
||||||
void CopyCurvesSplitAgainst(SShell *agnstA, SShell *agnstB, SShell *into);
|
void CopyCurvesSplitAgainst(bool opA, SShell *agnst, SShell *into);
|
||||||
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);
|
||||||
|
@ -1,25 +1,28 @@
|
|||||||
#include "solvespace.h"
|
#include "solvespace.h"
|
||||||
|
|
||||||
void SSurface::AddExactIntersectionCurve(SBezier *sb, hSSurface hsb,
|
extern int FLAG;
|
||||||
|
|
||||||
|
void SSurface::AddExactIntersectionCurve(SBezier *sb, SSurface *srfB,
|
||||||
SShell *agnstA, SShell *agnstB, SShell *into)
|
SShell *agnstA, SShell *agnstB, SShell *into)
|
||||||
{
|
{
|
||||||
SCurve sc;
|
SCurve sc;
|
||||||
ZERO(&sc);
|
ZERO(&sc);
|
||||||
sc.surfA = h;
|
sc.surfA = h;
|
||||||
sc.surfB = hsb;
|
sc.surfB = srfB->h;
|
||||||
sb->MakePwlInto(&(sc.pts));
|
sb->MakePwlInto(&(sc.pts));
|
||||||
|
|
||||||
|
/*
|
||||||
Vector *prev = NULL, *v;
|
Vector *prev = NULL, *v;
|
||||||
for(v = sc.pts.First(); v; v = sc.pts.NextAfter(v)) {
|
for(v = sc.pts.First(); v; v = sc.pts.NextAfter(v)) {
|
||||||
if(prev) SS.nakedEdges.AddEdge(*prev, *v);
|
if(prev) SS.nakedEdges.AddEdge(*prev, *v);
|
||||||
prev = v;
|
prev = v;
|
||||||
}
|
} */
|
||||||
|
|
||||||
// Now split the line where it intersects our existing surfaces
|
// Now split the line where it intersects our existing surfaces
|
||||||
SCurve split = sc.MakeCopySplitAgainst(agnstA, agnstB);
|
SCurve split = sc.MakeCopySplitAgainst(agnstA, agnstB, this, srfB);
|
||||||
sc.Clear();
|
sc.Clear();
|
||||||
|
|
||||||
split.interCurve = true;
|
split.source = SCurve::FROM_INTERSECTION;
|
||||||
into->curve.AddAndAssignId(&split);
|
into->curve.AddAndAssignId(&split);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -79,7 +82,7 @@ void SSurface::IntersectAgainst(SSurface *b, SShell *agnstA, SShell *agnstB,
|
|||||||
SBezier bezier;
|
SBezier bezier;
|
||||||
bezier = SBezier::From((si->p).Minus(al), (si->p).Plus(al));
|
bezier = SBezier::From((si->p).Minus(al), (si->p).Plus(al));
|
||||||
|
|
||||||
AddExactIntersectionCurve(&bezier, b->h, agnstA, agnstB, into);
|
AddExactIntersectionCurve(&bezier, b, agnstA, agnstB, into);
|
||||||
}
|
}
|
||||||
|
|
||||||
inters.Clear();
|
inters.Clear();
|
||||||
@ -96,7 +99,7 @@ void SSurface::IntersectAgainst(SSurface *b, SShell *agnstA, SShell *agnstB,
|
|||||||
Vector::AtIntersectionOfPlaneAndLine(n, d, p0, p1, NULL);
|
Vector::AtIntersectionOfPlaneAndLine(n, d, p0, p1, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
AddExactIntersectionCurve(&bezier, b->h, agnstA, agnstB, into);
|
AddExactIntersectionCurve(&bezier, b, agnstA, agnstB, into);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -152,8 +155,14 @@ void SSurface::AllPointsIntersecting(Vector a, Vector b,
|
|||||||
}
|
}
|
||||||
|
|
||||||
Inter inter;
|
Inter inter;
|
||||||
ClosestPointTo(pi, &inter.p.x, &inter.p.y);
|
ClosestPointTo(pi, &inter.p.x, &inter.p.y, false);
|
||||||
|
if(PointIntersectingLine(a, b, &inter.p.x, &inter.p.y)) {
|
||||||
inters.Add(&inter);
|
inters.Add(&inter);
|
||||||
|
} else {
|
||||||
|
// No convergence; but this might not be an error, since
|
||||||
|
// the line can intersect the convex hull more times than
|
||||||
|
// it intersects the surface itself.
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -189,7 +198,8 @@ void SSurface::AllPointsIntersecting(Vector a, Vector b,
|
|||||||
SInter si;
|
SInter si;
|
||||||
si.p = pxyz;
|
si.p = pxyz;
|
||||||
si.surfNormal = NormalAt(puv.x, puv.y);
|
si.surfNormal = NormalAt(puv.x, puv.y);
|
||||||
si.surface = h;
|
si.hsrf = h;
|
||||||
|
si.srf = this;
|
||||||
si.onEdge = (c != SBspUv::INSIDE);
|
si.onEdge = (c != SBspUv::INSIDE);
|
||||||
l->Add(&si);
|
l->Add(&si);
|
||||||
}
|
}
|
||||||
@ -236,6 +246,11 @@ int SShell::ClassifyPoint(Vector p, Vector pout) {
|
|||||||
bool onEdge = false;
|
bool onEdge = false;
|
||||||
edge_inters = 0;
|
edge_inters = 0;
|
||||||
|
|
||||||
|
if(FLAG) {
|
||||||
|
dbp("inters=%d cnt=%d", l.n, cnt);
|
||||||
|
SS.nakedEdges.AddEdge(p, p.Plus(ray.WithMagnitude(50)));
|
||||||
|
}
|
||||||
|
|
||||||
SInter *si;
|
SInter *si;
|
||||||
for(si = l.First(); si; si = l.NextAfter(si)) {
|
for(si = l.First(); si; si = l.NextAfter(si)) {
|
||||||
double t = ((si->p).Minus(p)).DivPivoting(ray);
|
double t = ((si->p).Minus(p)).DivPivoting(ray);
|
||||||
@ -244,6 +259,8 @@ int SShell::ClassifyPoint(Vector p, Vector pout) {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(FLAG) SS.nakedEdges.AddEdge(p, si->p);
|
||||||
|
|
||||||
double d = ((si->p).Minus(p)).Magnitude();
|
double d = ((si->p).Minus(p)).Magnitude();
|
||||||
|
|
||||||
// Handle edge-on-edge
|
// Handle edge-on-edge
|
||||||
|
42
util.cpp
42
util.cpp
@ -640,6 +640,48 @@ Vector Vector::AtIntersectionOfPlaneAndLine(Vector n, double d,
|
|||||||
return p0.Plus(dp.ScaledBy(t));
|
return p0.Plus(dp.ScaledBy(t));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static double det2(double a1, double b1,
|
||||||
|
double a2, double b2)
|
||||||
|
{
|
||||||
|
return (a1*b2) - (b1*a2);
|
||||||
|
}
|
||||||
|
static double det3(double a1, double b1, double c1,
|
||||||
|
double a2, double b2, double c2,
|
||||||
|
double a3, double b3, double c3)
|
||||||
|
{
|
||||||
|
return a1*det2(b2, c2, b3, c3) -
|
||||||
|
b1*det2(a2, c2, a3, c3) +
|
||||||
|
c1*det2(a2, b2, a3, b3);
|
||||||
|
}
|
||||||
|
Vector Vector::AtIntersectionOfPlanes(Vector na, double da,
|
||||||
|
Vector nb, double db,
|
||||||
|
Vector nc, double dc,
|
||||||
|
bool *parallel)
|
||||||
|
{
|
||||||
|
double det = det3(na.x, na.y, na.z,
|
||||||
|
nb.x, nb.y, nb.z,
|
||||||
|
nc.x, nc.y, nc.z);
|
||||||
|
if(fabs(det) < 1e-10) { // arbitrary tolerance, not so good
|
||||||
|
*parallel = true;
|
||||||
|
return Vector::From(0, 0, 0);
|
||||||
|
}
|
||||||
|
*parallel = false;
|
||||||
|
|
||||||
|
double detx = det3(da, na.y, na.z,
|
||||||
|
db, nb.y, nb.z,
|
||||||
|
dc, nc.y, nc.z);
|
||||||
|
|
||||||
|
double dety = det3(na.x, da, na.z,
|
||||||
|
nb.x, db, nb.z,
|
||||||
|
nc.x, dc, nc.z);
|
||||||
|
|
||||||
|
double detz = det3(na.x, na.y, da,
|
||||||
|
nb.x, nb.y, db,
|
||||||
|
nc.x, nc.y, dc );
|
||||||
|
|
||||||
|
return Vector::From(detx/det, dety/det, detz/det);
|
||||||
|
}
|
||||||
|
|
||||||
Point2d Point2d::Plus(Point2d b) {
|
Point2d Point2d::Plus(Point2d b) {
|
||||||
Point2d r;
|
Point2d r;
|
||||||
r.x = x + b.x;
|
r.x = x + b.x;
|
||||||
|
Loading…
Reference in New Issue
Block a user