2009-03-29 06:05:28 +00:00
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
// 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;
|
|
|
|
}
|
|
|
|
|
2009-04-15 02:55:18 +00:00
|
|
|
bool SSurface::IsCylinder(Vector *axis, Vector *center, double *r,
|
|
|
|
Vector *start, Vector *finish)
|
2009-03-29 06:05:28 +00:00
|
|
|
{
|
|
|
|
SBezier sb;
|
|
|
|
if(!IsExtrusion(&sb, axis)) return false;
|
2009-04-15 02:55:18 +00:00
|
|
|
if(!sb.IsCircle(*axis, center, r)) return false;
|
2009-03-29 06:05:28 +00:00
|
|
|
|
2009-04-15 02:55:18 +00:00
|
|
|
*start = sb.ctrl[0];
|
2009-03-29 06:05:28 +00:00
|
|
|
*finish = sb.ctrl[2];
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2009-04-29 02:42:44 +00:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2009-03-29 06:05:28 +00:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2009-04-14 04:19:23 +00:00
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
// 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) {
|
2009-05-18 07:26:51 +00:00
|
|
|
Vector *pt = &(sc->pts.elem[i].p);
|
2009-04-14 04:19:23 +00:00
|
|
|
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.
|
|
|
|
//-----------------------------------------------------------------------------
|
2009-03-29 06:05:28 +00:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2009-04-14 04:19:23 +00:00
|
|
|
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);
|
2009-03-29 06:05:28 +00:00
|
|
|
} else {
|
2009-04-14 04:19:23 +00:00
|
|
|
sb->ClosestPointTo(stb->start, &ts);
|
|
|
|
sb->ClosestPointTo(stb->finish, &tf);
|
2009-03-29 06:05:28 +00:00
|
|
|
}
|
2009-04-14 04:19:23 +00:00
|
|
|
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);
|
2009-03-29 06:05:28 +00:00
|
|
|
|
2009-04-14 04:19:23 +00:00
|
|
|
SBezier keep_bef, junk_aft;
|
|
|
|
keep_aft.SplitAt(tf, &keep_bef, &junk_aft);
|
|
|
|
|
|
|
|
sbl->l.Add(&keep_bef);
|
|
|
|
} else {
|
|
|
|
MakeTrimEdgesInto(sel, false, sc, stb);
|
2009-03-29 06:05:28 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
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;
|
2009-05-08 08:33:04 +00:00
|
|
|
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);
|
|
|
|
}
|
2009-03-29 06:05:28 +00:00
|
|
|
|
|
|
|
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();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-04-29 02:42:44 +00:00
|
|
|
|
|
|
|
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();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-03-29 06:05:28 +00:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-04-14 04:19:23 +00:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-03-29 06:05:28 +00:00
|
|
|
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();
|
|
|
|
}
|
|
|
|
|