Make surfaces of revolution with control points on the axis
triangulate correctly; don't screw up generating them, and make sure that the ratpoly stuff doesn't blow up near the singularity. [git-p4: depot-paths = "//depot/solvespace/": change = 1953]
This commit is contained in:
parent
40ed1b7ac1
commit
1d88f96e13
@ -301,17 +301,26 @@ Vector SSurface::NormalAt(double u, double v) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void SSurface::ClosestPointTo(Vector p, double *u, double *v, bool converge) {
|
void SSurface::ClosestPointTo(Vector p, double *u, double *v, bool converge) {
|
||||||
int i, j;
|
// A few special cases first; when control points are coincident the
|
||||||
|
// derivative goes to zero at the conrol points, and would result in
|
||||||
|
// nonconvergence. We avoid that here, and also guarantee a consistent
|
||||||
|
// (u, v) (of the infinitely many possible in one parameter).
|
||||||
|
if(p.Equals(ctrl[0] [0] )) { *u = 0; *v = 0; return; }
|
||||||
|
if(p.Equals(ctrl[degm][0] )) { *u = 1; *v = 0; return; }
|
||||||
|
if(p.Equals(ctrl[degm][degn])) { *u = 1; *v = 1; return; }
|
||||||
|
if(p.Equals(ctrl[0] [degn])) { *u = 0; *v = 1; return; }
|
||||||
|
|
||||||
|
// Search for a reasonable initial guess
|
||||||
|
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 = VERY_POSITIVE;
|
double minDist = VERY_POSITIVE;
|
||||||
double res = (max(degm, degn) == 2) ? 7.0 : 20.0;
|
int res = (max(degm, degn) == 2) ? 7 : 20;
|
||||||
for(i = 0; i < (int)res; i++) {
|
for(i = 0; i < res; i++) {
|
||||||
for(j = 0; j <= (int)res; j++) {
|
for(j = 0; j < res; j++) {
|
||||||
double tryu = (i/res), tryv = (j/res);
|
double tryu = (i + 0.5)/res, tryv = (j + 0.5)/res;
|
||||||
|
|
||||||
Vector tryp = PointAt(tryu, tryv);
|
Vector tryp = PointAt(tryu, tryv);
|
||||||
double d = (tryp.Minus(p)).Magnitude();
|
double d = (tryp.Minus(p)).Magnitude();
|
||||||
if(d < minDist) {
|
if(d < minDist) {
|
||||||
@ -323,7 +332,7 @@ void SSurface::ClosestPointTo(Vector p, double *u, double *v, bool converge) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Initial guess is in u, v
|
// Initial guess is in u, v; refine by Newton iteration.
|
||||||
Vector p0;
|
Vector p0;
|
||||||
for(i = 0; i < (converge ? 15 : 3); i++) {
|
for(i = 0; i < (converge ? 15 : 3); i++) {
|
||||||
p0 = PointAt(*u, *v);
|
p0 = PointAt(*u, *v);
|
||||||
|
133
srf/surface.cpp
133
srf/surface.cpp
@ -80,17 +80,25 @@ SSurface SSurface::FromRevolutionOf(SBezier *sb, Vector pt, Vector axis,
|
|||||||
Vector ps = p.RotatedAbout(pt, axis, thetas),
|
Vector ps = p.RotatedAbout(pt, axis, thetas),
|
||||||
pf = p.RotatedAbout(pt, axis, thetaf);
|
pf = p.RotatedAbout(pt, axis, thetaf);
|
||||||
|
|
||||||
Vector c = ps.ClosestPointOnLine(pt, axis);
|
Vector ct;
|
||||||
|
if(ps.Equals(pf)) {
|
||||||
|
// Degenerate case: a control point lies on the axis of revolution,
|
||||||
|
// so we get three coincident control points.
|
||||||
|
ct = ps;
|
||||||
|
} else {
|
||||||
|
// Normal case, the control point sweeps out a circle.
|
||||||
|
Vector c = ps.ClosestPointOnLine(pt, axis);
|
||||||
|
|
||||||
Vector rs = ps.Minus(c),
|
Vector rs = ps.Minus(c),
|
||||||
rf = pf.Minus(c);
|
rf = pf.Minus(c);
|
||||||
|
|
||||||
Vector ts = axis.Cross(rs),
|
Vector ts = axis.Cross(rs),
|
||||||
tf = axis.Cross(rf);
|
tf = axis.Cross(rf);
|
||||||
|
|
||||||
Vector ct = Vector::AtIntersectionOfLines(ps, ps.Plus(ts),
|
ct = Vector::AtIntersectionOfLines(ps, ps.Plus(ts),
|
||||||
pf, pf.Plus(tf),
|
pf, pf.Plus(tf),
|
||||||
NULL, NULL, NULL);
|
NULL, NULL, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
ret.ctrl[i][0] = ps;
|
ret.ctrl[i][0] = ps;
|
||||||
ret.ctrl[i][1] = ct;
|
ret.ctrl[i][1] = ct;
|
||||||
@ -489,20 +497,36 @@ void SShell::MakeFromRevolutionOf(SBezierLoopSet *sbls, Vector pt, Vector axis,
|
|||||||
int color)
|
int color)
|
||||||
{
|
{
|
||||||
ZERO(this);
|
ZERO(this);
|
||||||
|
SBezierLoop *sbl;
|
||||||
|
|
||||||
// Normalize the axis direction so that the direction of revolution
|
// Normalize the axis direction so that the direction of revolution
|
||||||
// ends up parallel to the normal of the sketch, on the side of the
|
// ends up parallel to the normal of the sketch, on the side of the
|
||||||
// axis where the sketch is.
|
// axis where the sketch is.
|
||||||
Vector pto = sbls->point,
|
Vector pto;
|
||||||
ptc = pto.ClosestPointOnLine(pt, axis),
|
double md = VERY_NEGATIVE;
|
||||||
|
for(sbl = sbls->l.First(); sbl; sbl = sbls->l.NextAfter(sbl)) {
|
||||||
|
SBezier *sb;
|
||||||
|
for(sb = sbl->l.First(); sb; sb = sbl->l.NextAfter(sb)) {
|
||||||
|
// Choose the point farthest from the axis; we'll get garbage
|
||||||
|
// if we choose a point that lies on the axis, for example.
|
||||||
|
// (And our surface will be self-intersecting if the sketch
|
||||||
|
// spans the axis, so don't worry about that.)
|
||||||
|
Vector p = sb->Start();
|
||||||
|
double d = p.DistanceToLine(pt, axis);
|
||||||
|
if(d > md) {
|
||||||
|
md = d;
|
||||||
|
pto = p;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Vector ptc = pto.ClosestPointOnLine(pt, axis),
|
||||||
up = (pto.Minus(ptc)).WithMagnitude(1),
|
up = (pto.Minus(ptc)).WithMagnitude(1),
|
||||||
vp = (sbls->normal).Cross(up);
|
vp = (sbls->normal).Cross(up);
|
||||||
|
|
||||||
if(vp.Dot(axis) < 0) {
|
if(vp.Dot(axis) < 0) {
|
||||||
axis = axis.ScaledBy(-1);
|
axis = axis.ScaledBy(-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
SBezierLoop *sbl;
|
// Now we actually build and trim the surfaces.
|
||||||
for(sbl = sbls->l.First(); sbl; sbl = sbls->l.NextAfter(sbl)) {
|
for(sbl = sbls->l.First(); sbl; sbl = sbls->l.NextAfter(sbl)) {
|
||||||
int i, j;
|
int i, j;
|
||||||
SBezier *sb, *prev;
|
SBezier *sb, *prev;
|
||||||
@ -516,11 +540,20 @@ void SShell::MakeFromRevolutionOf(SBezierLoopSet *sbls, Vector pt, Vector axis,
|
|||||||
for(sb = sbl->l.First(); sb; sb = sbl->l.NextAfter(sb)) {
|
for(sb = sbl->l.First(); sb; sb = sbl->l.NextAfter(sb)) {
|
||||||
Revolved revs;
|
Revolved revs;
|
||||||
for(j = 0; j < 4; j++) {
|
for(j = 0; j < 4; j++) {
|
||||||
SSurface ss = SSurface::FromRevolutionOf(sb, pt, axis,
|
if(sb->deg == 1 &&
|
||||||
(PI/2)*j,
|
(sb->ctrl[0]).DistanceToLine(pt, axis) < LENGTH_EPS &&
|
||||||
(PI/2)*(j+1));
|
(sb->ctrl[1]).DistanceToLine(pt, axis) < LENGTH_EPS)
|
||||||
ss.color = color;
|
{
|
||||||
revs.d[j] = surface.AddAndAssignId(&ss);
|
// This is a line on the axis of revolution; it does
|
||||||
|
// not contribute a surface.
|
||||||
|
revs.d[j].v = 0;
|
||||||
|
} else {
|
||||||
|
SSurface ss = SSurface::FromRevolutionOf(sb, pt, axis,
|
||||||
|
(PI/2)*j,
|
||||||
|
(PI/2)*(j+1));
|
||||||
|
ss.color = color;
|
||||||
|
revs.d[j] = surface.AddAndAssignId(&ss);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
hsl.Add(&revs);
|
hsl.Add(&revs);
|
||||||
}
|
}
|
||||||
@ -533,44 +566,54 @@ void SShell::MakeFromRevolutionOf(SBezierLoopSet *sbls, Vector pt, Vector axis,
|
|||||||
prev = &(sbl->l.elem[WRAP(i-1, sbl->l.n)]);
|
prev = &(sbl->l.elem[WRAP(i-1, sbl->l.n)]);
|
||||||
|
|
||||||
for(j = 0; j < 4; j++) {
|
for(j = 0; j < 4; j++) {
|
||||||
|
SCurve sc;
|
||||||
Quaternion qs = Quaternion::From(axis, (PI/2)*j);
|
Quaternion qs = Quaternion::From(axis, (PI/2)*j);
|
||||||
// we want Q*(x - p) + p = Q*x + (p - Q*p)
|
// we want Q*(x - p) + p = Q*x + (p - Q*p)
|
||||||
Vector ts = pt.Minus(qs.Rotate(pt));
|
Vector ts = pt.Minus(qs.Rotate(pt));
|
||||||
|
|
||||||
SCurve sc;
|
// If this input curve generate a surface, then trim that
|
||||||
ZERO(&sc);
|
// surface with the rotated version of the input curve.
|
||||||
sc.isExact = true;
|
if(revs.d[j].v) {
|
||||||
sc.exact = sb->TransformedBy(ts, qs);
|
ZERO(&sc);
|
||||||
(sc.exact).MakePwlInto(&(sc.pts));
|
sc.isExact = true;
|
||||||
sc.surfA = revs.d[j];
|
sc.exact = sb->TransformedBy(ts, qs);
|
||||||
sc.surfB = revs.d[WRAP(j-1, 4)];
|
(sc.exact).MakePwlInto(&(sc.pts));
|
||||||
|
sc.surfA = revs.d[j];
|
||||||
|
sc.surfB = revs.d[WRAP(j-1, 4)];
|
||||||
|
|
||||||
hSCurve hcb = curve.AddAndAssignId(&sc);
|
hSCurve hcb = curve.AddAndAssignId(&sc);
|
||||||
|
|
||||||
STrimBy stb;
|
STrimBy stb;
|
||||||
stb = STrimBy::EntireCurve(this, hcb, true);
|
stb = STrimBy::EntireCurve(this, hcb, true);
|
||||||
(surface.FindById(sc.surfA))->trim.Add(&stb);
|
(surface.FindById(sc.surfA))->trim.Add(&stb);
|
||||||
stb = STrimBy::EntireCurve(this, hcb, false);
|
stb = STrimBy::EntireCurve(this, hcb, false);
|
||||||
(surface.FindById(sc.surfB))->trim.Add(&stb);
|
(surface.FindById(sc.surfB))->trim.Add(&stb);
|
||||||
|
}
|
||||||
|
|
||||||
SSurface *ss = surface.FindById(sc.surfA);
|
// And if this input curve and the one after it both generated
|
||||||
|
// surfaces, then trim both of those by the appropriate
|
||||||
|
// circle.
|
||||||
|
if(revs.d[j].v && revsp.d[j].v) {
|
||||||
|
SSurface *ss = surface.FindById(revs.d[j]);
|
||||||
|
|
||||||
ZERO(&sc);
|
ZERO(&sc);
|
||||||
sc.isExact = true;
|
sc.isExact = true;
|
||||||
sc.exact = SBezier::From(ss->ctrl[0][0],
|
sc.exact = SBezier::From(ss->ctrl[0][0],
|
||||||
ss->ctrl[0][1],
|
ss->ctrl[0][1],
|
||||||
ss->ctrl[0][2]);
|
ss->ctrl[0][2]);
|
||||||
sc.exact.weight[1] = ss->weight[0][1];
|
sc.exact.weight[1] = ss->weight[0][1];
|
||||||
(sc.exact).MakePwlInto(&(sc.pts));
|
(sc.exact).MakePwlInto(&(sc.pts));
|
||||||
sc.surfA = revs.d[j];
|
sc.surfA = revs.d[j];
|
||||||
sc.surfB = revsp.d[j];
|
sc.surfB = revsp.d[j];
|
||||||
|
|
||||||
hSCurve hcc = curve.AddAndAssignId(&sc);
|
hSCurve hcc = curve.AddAndAssignId(&sc);
|
||||||
|
|
||||||
stb = STrimBy::EntireCurve(this, hcc, false);
|
STrimBy stb;
|
||||||
(surface.FindById(sc.surfA))->trim.Add(&stb);
|
stb = STrimBy::EntireCurve(this, hcc, false);
|
||||||
stb = STrimBy::EntireCurve(this, hcc, true);
|
(surface.FindById(sc.surfA))->trim.Add(&stb);
|
||||||
(surface.FindById(sc.surfB))->trim.Add(&stb);
|
stb = STrimBy::EntireCurve(this, hcc, true);
|
||||||
|
(surface.FindById(sc.surfB))->trim.Add(&stb);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
|
|
||||||
marching algorithm for surface intersection
|
marching algorithm for surface intersection
|
||||||
tangent intersections
|
tangent intersections
|
||||||
surfaces with coincident control points
|
put back the meshes
|
||||||
assembly
|
assembly
|
||||||
|
|
||||||
-----
|
-----
|
||||||
|
Loading…
Reference in New Issue
Block a user