Generate intersection curves for surfaces of extrusion along a
parallel axis (which are always lines parallel to that axis). Remove short pwl segments when possible, to avoid short edges that get misclassified. [git-p4: depot-paths = "//depot/solvespace/": change = 1952]solver
parent
d6d198ee40
commit
40ed1b7ac1
|
@ -36,9 +36,9 @@ SCurve SCurve::MakeCopySplitAgainst(SShell *agnstA, SShell *agnstB,
|
|||
ret = *this;
|
||||
ZERO(&(ret.pts));
|
||||
|
||||
Vector *p = pts.First();
|
||||
SCurvePt *p = pts.First();
|
||||
if(!p) oops();
|
||||
Vector prev = *p;
|
||||
SCurvePt prev = *p;
|
||||
ret.pts.Add(p);
|
||||
p = pts.NextAfter(p);
|
||||
|
||||
|
@ -47,8 +47,10 @@ SCurve SCurve::MakeCopySplitAgainst(SShell *agnstA, SShell *agnstB,
|
|||
ZERO(&il);
|
||||
|
||||
// Find all the intersections with the two passed shells
|
||||
if(agnstA) agnstA->AllPointsIntersecting(prev, *p, &il, true,true,true);
|
||||
if(agnstB) agnstB->AllPointsIntersecting(prev, *p, &il, true,true,true);
|
||||
if(agnstA)
|
||||
agnstA->AllPointsIntersecting(prev.p, p->p, &il, true, true, true);
|
||||
if(agnstB)
|
||||
agnstB->AllPointsIntersecting(prev.p, p->p, &il, true, true, true);
|
||||
|
||||
if(il.n > 0) {
|
||||
// The intersections were generated by intersecting the pwl
|
||||
|
@ -65,8 +67,8 @@ SCurve SCurve::MakeCopySplitAgainst(SShell *agnstA, SShell *agnstB,
|
|||
// And now sort them in order along the line. Note that we must
|
||||
// do that after refining, in case the refining would make two
|
||||
// points switch places.
|
||||
LineStart = prev;
|
||||
LineDirection = p->Minus(prev);
|
||||
LineStart = prev.p;
|
||||
LineDirection = (p->p).Minus(prev.p);
|
||||
qsort(il.elem, il.n, sizeof(il.elem[0]), ByTAlongLine);
|
||||
|
||||
// And now uses the intersections to generate our split pwl edge(s)
|
||||
|
@ -76,7 +78,11 @@ SCurve SCurve::MakeCopySplitAgainst(SShell *agnstA, SShell *agnstB,
|
|||
// On-edge intersection will generate same split point for
|
||||
// both surfaces, so don't create zero-length edge.
|
||||
if(!prev.Equals(pi->p)) {
|
||||
ret.pts.Add(&(pi->p));
|
||||
SCurvePt scpt;
|
||||
scpt.tag = 0;
|
||||
scpt.p = pi->p;
|
||||
scpt.vertex = true;
|
||||
ret.pts.Add(&scpt);
|
||||
}
|
||||
prev = pi->p;
|
||||
}
|
||||
|
@ -329,8 +335,8 @@ SSurface SSurface::MakeCopyTrimAgainst(SShell *agnst, SShell *parent,
|
|||
|
||||
int i;
|
||||
for(i = 1; i < sc->pts.n; i++) {
|
||||
Vector a = sc->pts.elem[i-1],
|
||||
b = sc->pts.elem[i];
|
||||
Vector a = sc->pts.elem[i-1].p,
|
||||
b = sc->pts.elem[i].p;
|
||||
|
||||
Point2d auv, buv;
|
||||
ss->ClosestPointTo(a, &(auv.x), &(auv.y));
|
||||
|
@ -506,6 +512,22 @@ void SShell::MakeFromBoolean(SShell *a, SShell *b, int type) {
|
|||
// the surfaces in B (which is all of the intersection curves).
|
||||
a->MakeIntersectionCurvesAgainst(b, this);
|
||||
|
||||
SCurve *sc;
|
||||
for(sc = curve.First(); sc; sc = curve.NextAfter(sc)) {
|
||||
SSurface *srfA, *srfB;
|
||||
if(sc->source == SCurve::FROM_A) {
|
||||
srfA = a->surface.FindById(sc->surfA);
|
||||
srfB = a->surface.FindById(sc->surfB);
|
||||
} else if(sc->source == SCurve::FROM_B) {
|
||||
srfA = b->surface.FindById(sc->surfA);
|
||||
srfB = b->surface.FindById(sc->surfB);
|
||||
} else if(sc->source == SCurve::FROM_INTERSECTION) {
|
||||
srfA = a->surface.FindById(sc->surfA);
|
||||
srfB = b->surface.FindById(sc->surfB);
|
||||
}
|
||||
sc->RemoveShortSegments(srfA, srfB);
|
||||
}
|
||||
|
||||
if(b->surface.n == 0 || a->surface.n == 0) {
|
||||
// Then trim and copy the surfaces
|
||||
a->CopySurfacesTrimAgainst(b, this, type, true);
|
||||
|
@ -518,7 +540,6 @@ void SShell::MakeFromBoolean(SShell *a, SShell *b, int type) {
|
|||
// Now that we've copied the surfaces, we know their new hSurfaces, so
|
||||
// rewrite the curves to refer to the surfaces by their handles in the
|
||||
// result.
|
||||
SCurve *sc;
|
||||
for(sc = curve.First(); sc; sc = curve.NextAfter(sc)) {
|
||||
if(sc->source == SCurve::FROM_A) {
|
||||
sc->surfA = a->surface.FindById(sc->surfA)->newH;
|
||||
|
|
|
@ -388,9 +388,10 @@ SCurve SCurve::FromTransformationOf(SCurve *a, Vector t, Quaternion q) {
|
|||
ret.surfA = a->surfA;
|
||||
ret.surfB = a->surfB;
|
||||
|
||||
Vector *p;
|
||||
SCurvePt *p;
|
||||
for(p = a->pts.First(); p; p = a->pts.NextAfter(p)) {
|
||||
Vector pp = (q.Rotate(*p)).Plus(t);
|
||||
SCurvePt pp = *p;
|
||||
pp.p = (q.Rotate(p->p)).Plus(t);
|
||||
ret.pts.Add(&pp);
|
||||
}
|
||||
return ret;
|
||||
|
@ -400,6 +401,55 @@ void SCurve::Clear(void) {
|
|||
pts.Clear();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// When we split line segments wherever they intersect a surface, we introduce
|
||||
// extra pwl points. This may create very short edges that could be removed
|
||||
// without violating the chord tolerance. Those are ugly, and also break
|
||||
// stuff in the Booleans. So remove them.
|
||||
//-----------------------------------------------------------------------------
|
||||
void SCurve::RemoveShortSegments(SSurface *srfA, SSurface *srfB) {
|
||||
if(pts.n < 2) return;
|
||||
pts.ClearTags();
|
||||
|
||||
Vector prev = pts.elem[0].p;
|
||||
int i, a;
|
||||
for(i = 1; i < pts.n - 1; i++) {
|
||||
SCurvePt *sct = &(pts.elem[i]),
|
||||
*scn = &(pts.elem[i+1]);
|
||||
if(sct->vertex) {
|
||||
prev = sct->p;
|
||||
continue;
|
||||
}
|
||||
bool mustKeep = false;
|
||||
|
||||
// We must check against both surfaces; the piecewise linear edge
|
||||
// may have a different chord tolerance in the two surfaces. (For
|
||||
// example, a circle in the surface of a cylinder is just a straight
|
||||
// line, so it always has perfect chord tol, but that circle in
|
||||
// a plane is a circle so it doesn't).
|
||||
for(a = 0; a < 2; a++) {
|
||||
SSurface *srf = (a == 0) ? srfA : srfB;
|
||||
Vector puv, nuv;
|
||||
srf->ClosestPointTo(prev, &(puv.x), &(puv.y));
|
||||
srf->ClosestPointTo(scn->p, &(nuv.x), &(nuv.y));
|
||||
|
||||
if(srf->ChordToleranceForEdge(nuv, puv) > SS.ChordTolMm()) {
|
||||
mustKeep = true;
|
||||
}
|
||||
}
|
||||
|
||||
if(mustKeep) {
|
||||
prev = sct->p;
|
||||
} else {
|
||||
sct->tag = 1;
|
||||
// and prev is unchanged, since there's no longer any point
|
||||
// in between
|
||||
}
|
||||
}
|
||||
|
||||
pts.RemoveTagged();
|
||||
}
|
||||
|
||||
STrimBy STrimBy::EntireCurve(SShell *shell, hSCurve hsc, bool backwards) {
|
||||
STrimBy stb;
|
||||
ZERO(&stb);
|
||||
|
@ -407,12 +457,12 @@ STrimBy STrimBy::EntireCurve(SShell *shell, hSCurve hsc, bool backwards) {
|
|||
SCurve *sc = shell->curve.FindById(hsc);
|
||||
|
||||
if(backwards) {
|
||||
stb.finish = sc->pts.elem[0];
|
||||
stb.start = sc->pts.elem[sc->pts.n - 1];
|
||||
stb.finish = sc->pts.elem[0].p;
|
||||
stb.start = sc->pts.elem[sc->pts.n - 1].p;
|
||||
stb.backwards = true;
|
||||
} else {
|
||||
stb.start = sc->pts.elem[0];
|
||||
stb.finish = sc->pts.elem[sc->pts.n - 1];
|
||||
stb.start = sc->pts.elem[0].p;
|
||||
stb.finish = sc->pts.elem[sc->pts.n - 1].p;
|
||||
stb.backwards = false;
|
||||
}
|
||||
|
||||
|
|
|
@ -199,6 +199,20 @@ void SBezier::SplitAt(double t, SBezier *bef, SBezier *aft) {
|
|||
}
|
||||
}
|
||||
|
||||
void SBezier::MakePwlInto(List<SCurvePt> *l) {
|
||||
List<Vector> lv;
|
||||
ZERO(&lv);
|
||||
MakePwlInto(&lv);
|
||||
int i;
|
||||
for(i = 0; i < lv.n; i++) {
|
||||
SCurvePt scpt;
|
||||
scpt.tag = 0;
|
||||
scpt.p = lv.elem[i];
|
||||
scpt.vertex = (i == 0) || (i == (lv.n - 1));
|
||||
l->Add(&scpt);
|
||||
}
|
||||
lv.Clear();
|
||||
}
|
||||
void SBezier::MakePwlInto(List<Vector> *l) {
|
||||
l->Add(&(ctrl[0]));
|
||||
MakePwlWorker(l, 0.0, 1.0);
|
||||
|
|
|
@ -202,7 +202,7 @@ void SSurface::MakeTrimEdgesInto(SEdgeList *sel, bool asUv,
|
|||
increment = 1;
|
||||
}
|
||||
for(i = first; i != (last + increment); i += increment) {
|
||||
Vector *pt = &(sc->pts.elem[i]);
|
||||
Vector *pt = &(sc->pts.elem[i].p);
|
||||
if(asUv) {
|
||||
ClosestPointTo(*pt, &u, &v);
|
||||
ptuv = Vector::From(u, v, 0);
|
||||
|
|
|
@ -7,6 +7,7 @@ double Bernstein(int k, int deg, double t);
|
|||
double BernsteinDerivative(int k, int deg, double t);
|
||||
|
||||
class SSurface;
|
||||
class SCurvePt;
|
||||
|
||||
// Utility data structure, a two-dimensional BSP to accelerate polygon
|
||||
// operations.
|
||||
|
@ -67,6 +68,7 @@ public:
|
|||
Vector Start(void);
|
||||
Vector Finish(void);
|
||||
bool Equals(SBezier *b);
|
||||
void MakePwlInto(List<SCurvePt> *l);
|
||||
void MakePwlInto(List<Vector> *l);
|
||||
void MakePwlWorker(List<Vector> *l, double ta, double tb);
|
||||
|
||||
|
@ -123,6 +125,13 @@ public:
|
|||
};
|
||||
|
||||
// Stuff for the surface trim curves: piecewise linear
|
||||
class SCurvePt {
|
||||
public:
|
||||
int tag;
|
||||
Vector p;
|
||||
bool vertex;
|
||||
};
|
||||
|
||||
class SCurve {
|
||||
public:
|
||||
hSCurve h;
|
||||
|
@ -139,7 +148,7 @@ public:
|
|||
bool isExact;
|
||||
SBezier exact;
|
||||
|
||||
List<Vector> pts;
|
||||
List<SCurvePt> pts;
|
||||
|
||||
hSSurface surfA;
|
||||
hSSurface surfB;
|
||||
|
@ -147,6 +156,7 @@ public:
|
|||
static SCurve FromTransformationOf(SCurve *a, Vector t, Quaternion q);
|
||||
SCurve MakeCopySplitAgainst(SShell *agnstA, SShell *agnstB,
|
||||
SSurface *srfA, SSurface *srfB);
|
||||
void RemoveShortSegments(SSurface *srfA, SSurface *srfB);
|
||||
|
||||
void Clear(void);
|
||||
};
|
||||
|
|
|
@ -35,7 +35,7 @@ void SSurface::AddExactIntersectionCurve(SBezier *sb, SSurface *srfB,
|
|||
}
|
||||
}
|
||||
if(existing) {
|
||||
Vector *v;
|
||||
SCurvePt *v;
|
||||
for(v = existing->pts.First(); v; v = existing->pts.NextAfter(v)) {
|
||||
sc.pts.Add(v);
|
||||
}
|
||||
|
@ -51,11 +51,11 @@ void SSurface::AddExactIntersectionCurve(SBezier *sb, SSurface *srfB,
|
|||
|
||||
if(0 && sb->deg == 1) {
|
||||
dbp(" ");
|
||||
Vector *prev = NULL, *v;
|
||||
SCurvePt *prev = NULL, *v;
|
||||
dbp("split.pts.n =%d", split.pts.n);
|
||||
for(v = split.pts.First(); v; v = split.pts.NextAfter(v)) {
|
||||
if(prev) {
|
||||
SS.nakedEdges.AddEdge(*prev, *v);
|
||||
SS.nakedEdges.AddEdge(prev->p, v->p);
|
||||
}
|
||||
prev = v;
|
||||
}
|
||||
|
@ -79,6 +79,11 @@ void SSurface::IntersectAgainst(SSurface *b, SShell *agnstA, SShell *agnstB,
|
|||
return;
|
||||
}
|
||||
|
||||
Vector alongt, alongb;
|
||||
SBezier oft, ofb;
|
||||
bool isExtdt = this->IsExtrusion(&oft, &alongt),
|
||||
isExtdb = b->IsExtrusion(&ofb, &alongb);
|
||||
|
||||
if(degm == 1 && degn == 1 && b->degm == 1 && b->degn == 1) {
|
||||
// Line-line intersection; it's a plane or nothing.
|
||||
Vector na = NormalAt(0, 0).WithMagnitude(1),
|
||||
|
@ -139,8 +144,8 @@ void SSurface::IntersectAgainst(SSurface *b, SShell *agnstA, SShell *agnstB,
|
|||
p.Plus(dl.ScaledBy(tmax)));
|
||||
AddExactIntersectionCurve(&bezier, b, agnstA, agnstB, into);
|
||||
}
|
||||
} else if((degm == 1 && degn == 1 && b->IsExtrusion(NULL, NULL)) ||
|
||||
(b->degm == 1 && b->degn == 1 && this->IsExtrusion(NULL, NULL)))
|
||||
} else if((degm == 1 && degn == 1 && isExtdb) ||
|
||||
(b->degm == 1 && b->degn == 1 && isExtdt))
|
||||
{
|
||||
// The intersection between a plane and a surface of extrusion
|
||||
SSurface *splane, *sext;
|
||||
|
@ -202,6 +207,55 @@ void SSurface::IntersectAgainst(SSurface *b, SShell *agnstA, SShell *agnstB,
|
|||
|
||||
AddExactIntersectionCurve(&bezier, b, agnstA, agnstB, into);
|
||||
}
|
||||
} else if(isExtdt && isExtdb &&
|
||||
sqrt(fabs(alongt.Dot(alongb))) >
|
||||
sqrt(alongt.Magnitude() * alongb.Magnitude()) - LENGTH_EPS)
|
||||
{
|
||||
// Two surfaces of extrusion along the same axis. So they might
|
||||
// intersect along some number of lines parallel to the axis.
|
||||
Vector axis = alongt.WithMagnitude(1);
|
||||
|
||||
List<SInter> inters;
|
||||
ZERO(&inters);
|
||||
List<Vector> lv;
|
||||
ZERO(&lv);
|
||||
|
||||
Vector axisa = axis.ScaledBy((b->ctrl[0][0]).Dot(axis)),
|
||||
axisb = axis.ScaledBy((b->ctrl[0][1]).Dot(axis)),
|
||||
axisc = (axisa.Plus(axisb)).ScaledBy(0.5);
|
||||
|
||||
oft.MakePwlInto(&lv);
|
||||
|
||||
int i;
|
||||
for(i = 0; i < lv.n - 1; i++) {
|
||||
Vector pa = lv.elem[i], pb = lv.elem[i+1];
|
||||
pa = pa.Minus(axis.ScaledBy(pa.Dot(axis)));
|
||||
pb = pb.Minus(axis.ScaledBy(pb.Dot(axis)));
|
||||
pa = pa.Plus(axisc);
|
||||
pb = pb.Plus(axisc);
|
||||
|
||||
b->AllPointsIntersecting(pa, pb, &inters, true, false, false);
|
||||
}
|
||||
|
||||
SInter *si;
|
||||
for(si = inters.First(); si; si = inters.NextAfter(si)) {
|
||||
Vector p = (si->p).Minus(axis.ScaledBy((si->p).Dot(axis)));
|
||||
double ub, vb;
|
||||
b->ClosestPointTo(p, &ub, &vb, true);
|
||||
SSurface plane;
|
||||
plane = SSurface::FromPlane(p, axis.Normal(0), axis.Normal(1));
|
||||
|
||||
b->PointOnSurfaces(this, &plane, &ub, &vb);
|
||||
|
||||
p = b->PointAt(ub, vb);
|
||||
|
||||
SBezier bezier;
|
||||
bezier = SBezier::From(p.Plus(axisa), p.Plus(axisb));
|
||||
AddExactIntersectionCurve(&bezier, b, agnstA, agnstB, into);
|
||||
}
|
||||
|
||||
inters.Clear();
|
||||
lv.Clear();
|
||||
}
|
||||
|
||||
// need to implement general numerical surface intersection for tough
|
||||
|
@ -632,6 +686,7 @@ int SShell::ClassifyPoint(Vector p, Vector edge_n, Vector surf_n) {
|
|||
|
||||
if(d < dmin) {
|
||||
dmin = d;
|
||||
|
||||
if(d < LENGTH_EPS) {
|
||||
// Edge-on-face (unless edge-on-edge above supercedes)
|
||||
double dot = (si->surfNormal).Dot(edge_n);
|
||||
|
|
|
@ -1,8 +1,7 @@
|
|||
|
||||
marching algorithm for surface intersection
|
||||
boundary avoidance when casting ray for point-in-shell
|
||||
tangent intersections
|
||||
short pwl edge avoidance
|
||||
surfaces with coincident control points
|
||||
assembly
|
||||
|
||||
-----
|
||||
|
|
Loading…
Reference in New Issue