
a grid of quads, with adaptive spacing. The quads that lie entirely within the trim polygon are triangulated and knocked out from the polygon, and then the polygon is triangulated. That works okay, though rather slow. But there are issues with surfaces of revolution that touch the axis, since they end up with a singularity. That will require some thought. [git-p4: depot-paths = "//depot/solvespace/": change = 1951]
640 lines
20 KiB
C++
640 lines
20 KiB
C++
//-----------------------------------------------------------------------------
|
|
// Anything involving surfaces and sets of surfaces (i.e., shells); except
|
|
// for the real math, which is in ratpoly.cpp.
|
|
//-----------------------------------------------------------------------------
|
|
#include "../solvespace.h"
|
|
|
|
SSurface SSurface::FromExtrusionOf(SBezier *sb, Vector t0, Vector t1) {
|
|
SSurface ret;
|
|
ZERO(&ret);
|
|
|
|
ret.degm = sb->deg;
|
|
ret.degn = 1;
|
|
|
|
int i;
|
|
for(i = 0; i <= ret.degm; i++) {
|
|
ret.ctrl[i][0] = (sb->ctrl[i]).Plus(t0);
|
|
ret.weight[i][0] = sb->weight[i];
|
|
|
|
ret.ctrl[i][1] = (sb->ctrl[i]).Plus(t1);
|
|
ret.weight[i][1] = sb->weight[i];
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
bool SSurface::IsExtrusion(SBezier *of, Vector *alongp) {
|
|
int i;
|
|
|
|
if(degn != 1) return false;
|
|
|
|
Vector along = (ctrl[0][1]).Minus(ctrl[0][0]);
|
|
for(i = 0; i <= degm; i++) {
|
|
if((fabs(weight[i][1] - weight[i][0]) < LENGTH_EPS) &&
|
|
((ctrl[i][1]).Minus(ctrl[i][0])).Equals(along))
|
|
{
|
|
continue;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
// yes, we are a surface of extrusion; copy the original curve and return
|
|
if(of) {
|
|
for(i = 0; i <= degm; i++) {
|
|
of->weight[i] = weight[i][0];
|
|
of->ctrl[i] = ctrl[i][0];
|
|
}
|
|
of->deg = degm;
|
|
*alongp = along;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool SSurface::IsCylinder(Vector *axis, Vector *center, double *r,
|
|
Vector *start, Vector *finish)
|
|
{
|
|
SBezier sb;
|
|
if(!IsExtrusion(&sb, axis)) return false;
|
|
if(!sb.IsCircle(*axis, center, r)) return false;
|
|
|
|
*start = sb.ctrl[0];
|
|
*finish = sb.ctrl[2];
|
|
return true;
|
|
}
|
|
|
|
SSurface SSurface::FromRevolutionOf(SBezier *sb, Vector pt, Vector axis,
|
|
double thetas, double thetaf)
|
|
{
|
|
SSurface ret;
|
|
ZERO(&ret);
|
|
ret.degm = sb->deg;
|
|
ret.degn = 2;
|
|
|
|
double dtheta = fabs(WRAP_SYMMETRIC(thetaf - thetas, 2*PI));
|
|
|
|
// We now wish to revolve the curve about the z axis
|
|
int i;
|
|
for(i = 0; i <= ret.degm; i++) {
|
|
Vector p = sb->ctrl[i];
|
|
|
|
Vector ps = p.RotatedAbout(pt, axis, thetas),
|
|
pf = p.RotatedAbout(pt, axis, thetaf);
|
|
|
|
Vector c = ps.ClosestPointOnLine(pt, axis);
|
|
|
|
Vector rs = ps.Minus(c),
|
|
rf = pf.Minus(c);
|
|
|
|
Vector ts = axis.Cross(rs),
|
|
tf = axis.Cross(rf);
|
|
|
|
Vector ct = Vector::AtIntersectionOfLines(ps, ps.Plus(ts),
|
|
pf, pf.Plus(tf),
|
|
NULL, NULL, NULL);
|
|
|
|
ret.ctrl[i][0] = ps;
|
|
ret.ctrl[i][1] = ct;
|
|
ret.ctrl[i][2] = pf;
|
|
|
|
ret.weight[i][0] = sb->weight[i];
|
|
ret.weight[i][1] = sb->weight[i]*cos(dtheta/2);
|
|
ret.weight[i][2] = sb->weight[i];
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
SSurface SSurface::FromPlane(Vector pt, Vector u, Vector v) {
|
|
SSurface ret;
|
|
ZERO(&ret);
|
|
|
|
ret.degm = 1;
|
|
ret.degn = 1;
|
|
|
|
ret.weight[0][0] = ret.weight[0][1] = 1;
|
|
ret.weight[1][0] = ret.weight[1][1] = 1;
|
|
|
|
ret.ctrl[0][0] = pt;
|
|
ret.ctrl[0][1] = pt.Plus(u);
|
|
ret.ctrl[1][0] = pt.Plus(v);
|
|
ret.ctrl[1][1] = pt.Plus(v).Plus(u);
|
|
|
|
return ret;
|
|
}
|
|
|
|
SSurface SSurface::FromTransformationOf(SSurface *a, Vector t, Quaternion q,
|
|
bool includingTrims)
|
|
{
|
|
SSurface ret;
|
|
ZERO(&ret);
|
|
|
|
ret.h = a->h;
|
|
ret.color = a->color;
|
|
ret.face = a->face;
|
|
|
|
ret.degm = a->degm;
|
|
ret.degn = a->degn;
|
|
int i, j;
|
|
for(i = 0; i <= 3; i++) {
|
|
for(j = 0; j <= 3; j++) {
|
|
ret.ctrl[i][j] = (q.Rotate(a->ctrl[i][j])).Plus(t);
|
|
ret.weight[i][j] = a->weight[i][j];
|
|
}
|
|
}
|
|
|
|
if(includingTrims) {
|
|
STrimBy *stb;
|
|
for(stb = a->trim.First(); stb; stb = a->trim.NextAfter(stb)) {
|
|
STrimBy n = *stb;
|
|
n.start = (q.Rotate(n.start)) .Plus(t);
|
|
n.finish = (q.Rotate(n.finish)).Plus(t);
|
|
ret.trim.Add(&n);
|
|
}
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
void SSurface::GetAxisAlignedBounding(Vector *ptMax, Vector *ptMin) {
|
|
*ptMax = Vector::From(VERY_NEGATIVE, VERY_NEGATIVE, VERY_NEGATIVE);
|
|
*ptMin = Vector::From(VERY_POSITIVE, VERY_POSITIVE, VERY_POSITIVE);
|
|
|
|
int i, j;
|
|
for(i = 0; i <= degm; i++) {
|
|
for(j = 0; j <= degn; j++) {
|
|
(ctrl[i][j]).MakeMaxMin(ptMax, ptMin);
|
|
}
|
|
}
|
|
}
|
|
|
|
bool SSurface::LineEntirelyOutsideBbox(Vector a, Vector b, bool segment) {
|
|
Vector amax, amin;
|
|
GetAxisAlignedBounding(&amax, &amin);
|
|
if(!Vector::BoundingBoxIntersectsLine(amax, amin, a, b, segment)) {
|
|
// The line segment could fail to intersect the bbox, but lie entirely
|
|
// within it and intersect the surface.
|
|
if(a.OutsideAndNotOn(amax, amin) && b.OutsideAndNotOn(amax, amin)) {
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Generate the piecewise linear approximation of the trim stb, which applies
|
|
// to the curve sc.
|
|
//-----------------------------------------------------------------------------
|
|
void SSurface::MakeTrimEdgesInto(SEdgeList *sel, bool asUv,
|
|
SCurve *sc, STrimBy *stb)
|
|
{
|
|
Vector prev, prevuv, ptuv;
|
|
bool inCurve = false, empty = true;
|
|
double u = 0, v = 0;
|
|
|
|
int i, first, last, increment;
|
|
if(stb->backwards) {
|
|
first = sc->pts.n - 1;
|
|
last = 0;
|
|
increment = -1;
|
|
} else {
|
|
first = 0;
|
|
last = sc->pts.n - 1;
|
|
increment = 1;
|
|
}
|
|
for(i = first; i != (last + increment); i += increment) {
|
|
Vector *pt = &(sc->pts.elem[i]);
|
|
if(asUv) {
|
|
ClosestPointTo(*pt, &u, &v);
|
|
ptuv = Vector::From(u, v, 0);
|
|
if(inCurve) {
|
|
sel->AddEdge(prevuv, ptuv, sc->h.v, stb->backwards);
|
|
empty = false;
|
|
}
|
|
prevuv = ptuv;
|
|
} else {
|
|
if(inCurve) {
|
|
sel->AddEdge(prev, *pt, sc->h.v, stb->backwards);
|
|
empty = false;
|
|
}
|
|
prev = *pt;
|
|
}
|
|
|
|
if(pt->Equals(stb->start)) inCurve = true;
|
|
if(pt->Equals(stb->finish)) inCurve = false;
|
|
}
|
|
if(inCurve) dbp("trim was unterminated");
|
|
if(empty) dbp("trim was empty");
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Generate all of our trim curves, in piecewise linear form. We can do
|
|
// so in either uv or xyz coordinates. And if requested, then we can use
|
|
// the split curves from useCurvesFrom instead of the curves in our own
|
|
// shell.
|
|
//-----------------------------------------------------------------------------
|
|
void SSurface::MakeEdgesInto(SShell *shell, SEdgeList *sel, bool asUv,
|
|
SShell *useCurvesFrom)
|
|
{
|
|
STrimBy *stb;
|
|
for(stb = trim.First(); stb; stb = trim.NextAfter(stb)) {
|
|
SCurve *sc = shell->curve.FindById(stb->curve);
|
|
|
|
// We have the option to use the curves from another shell; this
|
|
// is relevant when generating the coincident edges while doing the
|
|
// Booleans, since the curves from the output shell will be split
|
|
// against any intersecting surfaces (and the originals aren't).
|
|
if(useCurvesFrom) {
|
|
sc = useCurvesFrom->curve.FindById(sc->newH);
|
|
}
|
|
|
|
MakeTrimEdgesInto(sel, asUv, sc, stb);
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Report our trim curves. If a trim curve is exact and sbl is not null, then
|
|
// add its exact form to sbl. Otherwise, add its piecewise linearization to
|
|
// sel.
|
|
//-----------------------------------------------------------------------------
|
|
void SSurface::MakeSectionEdgesInto(SShell *shell,
|
|
SEdgeList *sel, SBezierList *sbl)
|
|
{
|
|
STrimBy *stb;
|
|
for(stb = trim.First(); stb; stb = trim.NextAfter(stb)) {
|
|
SCurve *sc = shell->curve.FindById(stb->curve);
|
|
SBezier *sb = &(sc->exact);
|
|
|
|
if(sbl && sc->isExact && sb->deg != 1) {
|
|
double ts, tf;
|
|
if(stb->backwards) {
|
|
sb->ClosestPointTo(stb->start, &tf);
|
|
sb->ClosestPointTo(stb->finish, &ts);
|
|
} else {
|
|
sb->ClosestPointTo(stb->start, &ts);
|
|
sb->ClosestPointTo(stb->finish, &tf);
|
|
}
|
|
SBezier junk_bef, keep_aft;
|
|
sb->SplitAt(ts, &junk_bef, &keep_aft);
|
|
// In the kept piece, the range that used to go from ts to 1
|
|
// now goes from 0 to 1; so rescale tf appropriately.
|
|
tf = (tf - ts)/(1 - ts);
|
|
|
|
SBezier keep_bef, junk_aft;
|
|
keep_aft.SplitAt(tf, &keep_bef, &junk_aft);
|
|
|
|
sbl->l.Add(&keep_bef);
|
|
} else {
|
|
MakeTrimEdgesInto(sel, false, sc, stb);
|
|
}
|
|
}
|
|
}
|
|
|
|
void SSurface::TriangulateInto(SShell *shell, SMesh *sm) {
|
|
SEdgeList el;
|
|
ZERO(&el);
|
|
|
|
MakeEdgesInto(shell, &el, true);
|
|
|
|
SPolygon poly;
|
|
ZERO(&poly);
|
|
if(el.AssemblePolygon(&poly, NULL, true)) {
|
|
int i, start = sm->l.n;
|
|
if(degm == 1 && degn == 1) {
|
|
// A plane; triangulate any old way
|
|
poly.UvTriangulateInto(sm, NULL);
|
|
} else if(degm == 1 || degn == 1) {
|
|
// A surface with curvature along one direction only; so
|
|
// choose the triangulation with chords that lie as much
|
|
// as possible within the surface. And since the trim curves
|
|
// have been pwl'd to within the desired chord tol, that will
|
|
// produce a surface good to within roughly that tol.
|
|
poly.UvTriangulateInto(sm, this);
|
|
} else {
|
|
// A surface with compound curvature. So we must overlay a
|
|
// two-dimensional grid, and triangulate around that.
|
|
poly.UvGridTriangulateInto(sm, this);
|
|
}
|
|
|
|
STriMeta meta = { face, color };
|
|
for(i = start; i < sm->l.n; i++) {
|
|
STriangle *st = &(sm->l.elem[i]);
|
|
st->meta = meta;
|
|
st->an = NormalAt(st->a.x, st->a.y);
|
|
st->bn = NormalAt(st->b.x, st->b.y);
|
|
st->cn = NormalAt(st->c.x, st->c.y);
|
|
st->a = PointAt(st->a.x, st->a.y);
|
|
st->b = PointAt(st->b.x, st->b.y);
|
|
st->c = PointAt(st->c.x, st->c.y);
|
|
// Works out that my chosen contour direction is inconsistent with
|
|
// the triangle direction, sigh.
|
|
st->FlipNormal();
|
|
}
|
|
} else {
|
|
dbp("failed to assemble polygon to trim nurbs surface in uv space");
|
|
}
|
|
|
|
el.Clear();
|
|
poly.Clear();
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Reverse the parametrisation of one of our dimensions, which flips the
|
|
// normal. We therefore must reverse all our trim curves too. The uv
|
|
// coordinates change, but trim curves are stored as xyz so nothing happens
|
|
//-----------------------------------------------------------------------------
|
|
void SSurface::Reverse(void) {
|
|
int i, j;
|
|
for(i = 0; i < (degm+1)/2; i++) {
|
|
for(j = 0; j <= degn; j++) {
|
|
SWAP(Vector, ctrl[i][j], ctrl[degm-i][j]);
|
|
SWAP(double, weight[i][j], weight[degm-i][j]);
|
|
}
|
|
}
|
|
|
|
STrimBy *stb;
|
|
for(stb = trim.First(); stb; stb = trim.NextAfter(stb)) {
|
|
stb->backwards = !stb->backwards;
|
|
SWAP(Vector, stb->start, stb->finish);
|
|
}
|
|
}
|
|
|
|
void SSurface::Clear(void) {
|
|
trim.Clear();
|
|
}
|
|
|
|
void SShell::MakeFromExtrusionOf(SBezierLoopSet *sbls, Vector t0, Vector t1,
|
|
int color)
|
|
{
|
|
ZERO(this);
|
|
|
|
// Make the extrusion direction consistent with respect to the normal
|
|
// of the sketch we're extruding.
|
|
if((t0.Minus(t1)).Dot(sbls->normal) < 0) {
|
|
SWAP(Vector, t0, t1);
|
|
}
|
|
|
|
// Define a coordinate system to contain the original sketch, and get
|
|
// a bounding box in that csys
|
|
Vector n = sbls->normal.ScaledBy(-1);
|
|
Vector u = n.Normal(0), v = n.Normal(1);
|
|
Vector orig = sbls->point;
|
|
double umax = 1e-10, umin = 1e10;
|
|
sbls->GetBoundingProjd(u, orig, &umin, &umax);
|
|
double vmax = 1e-10, vmin = 1e10;
|
|
sbls->GetBoundingProjd(v, orig, &vmin, &vmax);
|
|
// and now fix things up so that all u and v lie between 0 and 1
|
|
orig = orig.Plus(u.ScaledBy(umin));
|
|
orig = orig.Plus(v.ScaledBy(vmin));
|
|
u = u.ScaledBy(umax - umin);
|
|
v = v.ScaledBy(vmax - vmin);
|
|
|
|
// So we can now generate the top and bottom surfaces of the extrusion,
|
|
// planes within a translated (and maybe mirrored) version of that csys.
|
|
SSurface s0, s1;
|
|
s0 = SSurface::FromPlane(orig.Plus(t0), u, v);
|
|
s0.color = color;
|
|
s1 = SSurface::FromPlane(orig.Plus(t1).Plus(u), u.ScaledBy(-1), v);
|
|
s1.color = color;
|
|
hSSurface hs0 = surface.AddAndAssignId(&s0),
|
|
hs1 = surface.AddAndAssignId(&s1);
|
|
|
|
// Now go through the input curves. For each one, generate its surface
|
|
// of extrusion, its two translated trim curves, and one trim line. We
|
|
// go through by loops so that we can assign the lines correctly.
|
|
SBezierLoop *sbl;
|
|
for(sbl = sbls->l.First(); sbl; sbl = sbls->l.NextAfter(sbl)) {
|
|
SBezier *sb;
|
|
|
|
typedef struct {
|
|
hSCurve hc;
|
|
hSSurface hs;
|
|
} TrimLine;
|
|
List<TrimLine> trimLines;
|
|
ZERO(&trimLines);
|
|
|
|
for(sb = sbl->l.First(); sb; sb = sbl->l.NextAfter(sb)) {
|
|
// Generate the surface of extrusion of this curve, and add
|
|
// it to the list
|
|
SSurface ss = SSurface::FromExtrusionOf(sb, t0, t1);
|
|
ss.color = color;
|
|
hSSurface hsext = surface.AddAndAssignId(&ss);
|
|
|
|
// Translate the curve by t0 and t1 to produce two trim curves
|
|
SCurve sc;
|
|
ZERO(&sc);
|
|
sc.isExact = true;
|
|
sc.exact = sb->TransformedBy(t0, Quaternion::IDENTITY);
|
|
(sc.exact).MakePwlInto(&(sc.pts));
|
|
sc.surfA = hs0;
|
|
sc.surfB = hsext;
|
|
hSCurve hc0 = curve.AddAndAssignId(&sc);
|
|
|
|
ZERO(&sc);
|
|
sc.isExact = true;
|
|
sc.exact = sb->TransformedBy(t1, Quaternion::IDENTITY);
|
|
(sc.exact).MakePwlInto(&(sc.pts));
|
|
sc.surfA = hs1;
|
|
sc.surfB = hsext;
|
|
hSCurve hc1 = curve.AddAndAssignId(&sc);
|
|
|
|
STrimBy stb0, stb1;
|
|
// 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(hs1))->trim.Add(&stb1);
|
|
|
|
// The translated curves also trim the surface of extrusion.
|
|
stb0 = STrimBy::EntireCurve(this, hc0, true);
|
|
stb1 = STrimBy::EntireCurve(this, hc1, false);
|
|
(surface.FindById(hsext))->trim.Add(&stb0);
|
|
(surface.FindById(hsext))->trim.Add(&stb1);
|
|
|
|
// And form the trim line
|
|
Vector pt = sb->Finish();
|
|
ZERO(&sc);
|
|
sc.isExact = true;
|
|
sc.exact = SBezier::From(pt.Plus(t0), pt.Plus(t1));
|
|
(sc.exact).MakePwlInto(&(sc.pts));
|
|
hSCurve hl = curve.AddAndAssignId(&sc);
|
|
// save this for later
|
|
TrimLine tl;
|
|
tl.hc = hl;
|
|
tl.hs = hsext;
|
|
trimLines.Add(&tl);
|
|
}
|
|
|
|
int i;
|
|
for(i = 0; i < trimLines.n; i++) {
|
|
TrimLine *tl = &(trimLines.elem[i]);
|
|
SSurface *ss = surface.FindById(tl->hs);
|
|
|
|
TrimLine *tlp = &(trimLines.elem[WRAP(i-1, trimLines.n)]);
|
|
|
|
STrimBy stb;
|
|
stb = STrimBy::EntireCurve(this, tl->hc, true);
|
|
ss->trim.Add(&stb);
|
|
stb = STrimBy::EntireCurve(this, tlp->hc, false);
|
|
ss->trim.Add(&stb);
|
|
|
|
(curve.FindById(tl->hc))->surfA = ss->h;
|
|
(curve.FindById(tlp->hc))->surfB = ss->h;
|
|
}
|
|
trimLines.Clear();
|
|
}
|
|
}
|
|
|
|
|
|
void SShell::MakeFromRevolutionOf(SBezierLoopSet *sbls, Vector pt, Vector axis,
|
|
int color)
|
|
{
|
|
ZERO(this);
|
|
|
|
// Normalize the axis direction so that the direction of revolution
|
|
// ends up parallel to the normal of the sketch, on the side of the
|
|
// axis where the sketch is.
|
|
Vector pto = sbls->point,
|
|
ptc = pto.ClosestPointOnLine(pt, axis),
|
|
up = (pto.Minus(ptc)).WithMagnitude(1),
|
|
vp = (sbls->normal).Cross(up);
|
|
|
|
if(vp.Dot(axis) < 0) {
|
|
axis = axis.ScaledBy(-1);
|
|
}
|
|
|
|
SBezierLoop *sbl;
|
|
for(sbl = sbls->l.First(); sbl; sbl = sbls->l.NextAfter(sbl)) {
|
|
int i, j;
|
|
SBezier *sb, *prev;
|
|
|
|
typedef struct {
|
|
hSSurface d[4];
|
|
} Revolved;
|
|
List<Revolved> hsl;
|
|
ZERO(&hsl);
|
|
|
|
for(sb = sbl->l.First(); sb; sb = sbl->l.NextAfter(sb)) {
|
|
Revolved revs;
|
|
for(j = 0; j < 4; j++) {
|
|
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);
|
|
}
|
|
|
|
for(i = 0; i < sbl->l.n; i++) {
|
|
Revolved revs = hsl.elem[i],
|
|
revsp = hsl.elem[WRAP(i-1, sbl->l.n)];
|
|
|
|
sb = &(sbl->l.elem[i]);
|
|
prev = &(sbl->l.elem[WRAP(i-1, sbl->l.n)]);
|
|
|
|
for(j = 0; j < 4; j++) {
|
|
Quaternion qs = Quaternion::From(axis, (PI/2)*j);
|
|
// we want Q*(x - p) + p = Q*x + (p - Q*p)
|
|
Vector ts = pt.Minus(qs.Rotate(pt));
|
|
|
|
SCurve sc;
|
|
ZERO(&sc);
|
|
sc.isExact = true;
|
|
sc.exact = sb->TransformedBy(ts, qs);
|
|
(sc.exact).MakePwlInto(&(sc.pts));
|
|
sc.surfA = revs.d[j];
|
|
sc.surfB = revs.d[WRAP(j-1, 4)];
|
|
|
|
hSCurve hcb = curve.AddAndAssignId(&sc);
|
|
|
|
STrimBy stb;
|
|
stb = STrimBy::EntireCurve(this, hcb, true);
|
|
(surface.FindById(sc.surfA))->trim.Add(&stb);
|
|
stb = STrimBy::EntireCurve(this, hcb, false);
|
|
(surface.FindById(sc.surfB))->trim.Add(&stb);
|
|
|
|
SSurface *ss = surface.FindById(sc.surfA);
|
|
|
|
ZERO(&sc);
|
|
sc.isExact = true;
|
|
sc.exact = SBezier::From(ss->ctrl[0][0],
|
|
ss->ctrl[0][1],
|
|
ss->ctrl[0][2]);
|
|
sc.exact.weight[1] = ss->weight[0][1];
|
|
(sc.exact).MakePwlInto(&(sc.pts));
|
|
sc.surfA = revs.d[j];
|
|
sc.surfB = revsp.d[j];
|
|
|
|
hSCurve hcc = curve.AddAndAssignId(&sc);
|
|
|
|
stb = STrimBy::EntireCurve(this, hcc, false);
|
|
(surface.FindById(sc.surfA))->trim.Add(&stb);
|
|
stb = STrimBy::EntireCurve(this, hcc, true);
|
|
(surface.FindById(sc.surfB))->trim.Add(&stb);
|
|
}
|
|
}
|
|
|
|
hsl.Clear();
|
|
}
|
|
}
|
|
|
|
void SShell::MakeFromCopyOf(SShell *a) {
|
|
MakeFromTransformationOf(a, Vector::From(0, 0, 0), Quaternion::IDENTITY);
|
|
}
|
|
|
|
void SShell::MakeFromTransformationOf(SShell *a, Vector t, Quaternion q) {
|
|
SSurface *s;
|
|
for(s = a->surface.First(); s; s = a->surface.NextAfter(s)) {
|
|
SSurface n;
|
|
n = SSurface::FromTransformationOf(s, t, q, true);
|
|
surface.Add(&n); // keeping the old ID
|
|
}
|
|
|
|
SCurve *c;
|
|
for(c = a->curve.First(); c; c = a->curve.NextAfter(c)) {
|
|
SCurve n;
|
|
n = SCurve::FromTransformationOf(c, t, q);
|
|
curve.Add(&n); // keeping the old ID
|
|
}
|
|
}
|
|
|
|
void SShell::MakeEdgesInto(SEdgeList *sel) {
|
|
SSurface *s;
|
|
for(s = surface.First(); s; s = surface.NextAfter(s)) {
|
|
s->MakeEdgesInto(this, sel, false);
|
|
}
|
|
}
|
|
|
|
void SShell::MakeSectionEdgesInto(Vector n, double d,
|
|
SEdgeList *sel, SBezierList *sbl)
|
|
{
|
|
SSurface *s;
|
|
for(s = surface.First(); s; s = surface.NextAfter(s)) {
|
|
if(s->CoincidentWithPlane(n, d)) {
|
|
s->MakeSectionEdgesInto(this, sel, sbl);
|
|
}
|
|
}
|
|
}
|
|
|
|
void SShell::TriangulateInto(SMesh *sm) {
|
|
SSurface *s;
|
|
for(s = surface.First(); s; s = surface.NextAfter(s)) {
|
|
s->TriangulateInto(this, sm);
|
|
}
|
|
}
|
|
|
|
void SShell::Clear(void) {
|
|
SSurface *s;
|
|
for(s = surface.First(); s; s = surface.NextAfter(s)) {
|
|
s->Clear();
|
|
}
|
|
surface.Clear();
|
|
|
|
SCurve *c;
|
|
for(c = curve.First(); c; c = curve.NextAfter(c)) {
|
|
c->Clear();
|
|
}
|
|
curve.Clear();
|
|
}
|
|
|