<> <> <> DIRECTORY Cubic2, Matrix3d, Real, RealFns, Spline3d, Vector2, Vector3d, TubeDefs, TubeMisc, TubeStructure; TubeStructureImpl: CEDAR PROGRAM IMPORTS Cubic2, Matrix3d, Real, RealFns, Spline3d, TubeMisc, Vector2, Vector3d EXPORTS TubeStructure ~ BEGIN OPEN TubeDefs; nCircles: INTEGER ~ 40; circles: ARRAY [1..nCircles] OF PairSequence _ ALL[NIL]; MakeNormals: PROC [contour: Contour] ~ { MakeNormal: PROC [pairs: PairSequence, n: INTEGER] RETURNS [Pair] ~ { IF pairs.length < 2 THEN RETURN[[0, 0]] ELSE { first: INTEGER _ 0; last: INTEGER _ pairs.length-1; p0: Pair _ SELECT n FROM first => IF contour.closed THEN pairs[last] ELSE pairs[first], ENDCASE => pairs[n-1]; p1: Pair _ SELECT n FROM last => IF contour.closed THEN pairs[first] ELSE pairs[last], ENDCASE => pairs[n+1]; v: Pair _ [p1.x-p0.x, p1.y-p0.y]; RETURN[[-v.y, v.x]]; }; }; FOR n: NAT IN [0..contour.pairs.length) DO contour.normals[n] _ MakeNormal[contour.pairs, n]; ENDLOOP; }; ReScaleTube: PUBLIC PROC [tube: Tube, scale: REAL] ~ { ApplyReScale: TubeProc ~ { FOR n: NAT IN [0..tube.nFrames) DO f: Frame _ tube.frames[n]; f.m _ Matrix3d.MakeFromTriad[ [f.m[0][0], f.m[0][1], f.m[0][2]], [f.m[1][0], f.m[1][1], f.m[1][2]], [f.m[2][0], f.m[2][1], f.m[2][2]], [f.m[3][0], f.m[3][1], f.m[3][2]], f.m]; f.m _ Matrix3d.LocalScale[f.m, scale*(f.t*tube.r0+(1.0-f.t)*tube.r1), f.m]; ENDLOOP; }; TubeMisc.ApplyProc[tube, ApplyReScale]; }; MakeTube: PUBLIC PROC [ tube: Tube, scale, epsilon: REAL _ 1.0, taper: REAL _ 0.0, view: Matrix _ NIL] ~ { ApplyMake: TubeProc ~ { tube.coeffs _ Spline3d.CoeffsFromHermite[[tube.p0, tube.p1, tube.v0, tube.v1]]; }; TubeMisc.ApplyProc[tube, ApplyMake]; PropagateFrames[tube, scale, epsilon, taper, view]; }; PropagateCircleRes: PUBLIC PROC [tube: Tube, circleRes: INTEGER] ~ { IF tube = NIL THEN RETURN; tube.circleRes _ circleRes; FOR n: NAT IN [0..tube.nBranches) DO PropagateCircleRes[tube.branches[n], circleRes]; ENDLOOP; PropagateCircleRes[tube.next, circleRes]; }; PropagateFrames: PUBLIC PROC [ tube: Tube, scale, epsilon: REAL _ 1.0, taper: REAL _ 0.0, view: Matrix _ NIL] ~ { InnerPropagate: PROC [tube: Tube, length, scale0: REAL] ~ { scale1: REAL _ scale0; IF tube = NIL THEN RETURN; IF taper # 0.0 THEN { length _ length+Spline3d.Length[tube.coeffs]; scale1 _ scale*(1.0-taper*length); }; MakeFrames[tube, scale0, scale1, epsilon, view]; InnerPropagate[tube.next, length, scale1]; FOR n: NAT IN [0..tube.nBranches) DO InnerPropagate[tube.branches[n], length, scale1]; ENDLOOP; }; InnerPropagate[tube, 0.0, scale]; }; MakeFrames: PUBLIC PROC [ tube: Tube, scale0, scale1, epsilon: REAL _ 1.0, view: Matrix _ NIL] ~ { bez: Spline3d.Bezier _ Spline3d.BezierFromCoeffs[tube.coeffs]; maxLen: REAL _ IF view = NIL THEN 0.01*Spline3d.ConvexHullLength[bez] ELSE 0.0; vv: Triple _ IF Vector3d.Equal[bez.b1, bez.b0, 0.0001] THEN Vector3d.Sub[bez.b2, bez.b1] ELSE Vector3d.Sub[bez.b1, bez.b0]; tw0: REAL _ tube.tw0; tw1: REAL _ tube.tw1; sc0: REAL _ tube.r0*scale0; sc1: REAL _ tube.r1*scale1; ScreenCircleRes: PROC [tube: Tube, view: Matrix] RETURNS [res: INTEGER] ~ { CircleRes: PROC [p: Triple, r: REAL] RETURNS [NAT] ~ { q: Vector2.VEC _ Matrix3d.TransformD[p, view]; q1: Vector2.VEC _ Matrix3d.TransformD[[p.x+r, p.y, p.z], view]; q2: Vector2.VEC _ Matrix3d.TransformD[[p.x, p.y+r, p.z], view]; l: REAL _ MAX[Vector2.Length[Vector2.Sub[q, q1]], Vector2.Length[Vector2.Sub[q, q2]]]; RETURN[3+Real.RoundI[0.4*l/MAX[0.01, 100.0*epsilon]]]; }; res _ MAX[CircleRes[tube.p0, scale0*tube.r0], CircleRes[tube.p1, scale1*tube.r1]]; IF res MOD 2 = 1 THEN res _ res+1; }; LengthenFrameSequence: PROC [f: FrameSequence] RETURNS [FrameSequence] ~ { temp: FrameSequence _ NEW[FrameSequenceRec[MAX[5, Real.RoundI[1.3*f.maxLength]]]]; FOR i: NAT IN[0..f.maxLength) DO temp[i] _ f[i]; ENDLOOP; RETURN[temp]; }; TwistSmallEnough: PROC [t0, t1: REAL] RETURNS[BOOL] ~ { RETURN[ABS[(t1-t0)*(tube.tw1-tube.tw0)] < 20.0]; }; BezSmallEnough: PROC [bez: Spline3d.Bezier] RETURNS[BOOL] ~ { RETURN[IF view = NIL THEN Spline3d.ConvexHullLength[bez] < maxLen OR Spline3d.FlatBezier[bez, epsilon] ELSE Cubic2.Flat[ [Matrix3d.TransformD[bez.b0, view], Matrix3d.TransformD[bez.b1, view], Matrix3d.TransformD[bez.b2, view], Matrix3d.TransformD[bez.b3, view]], 100.0*epsilon]]; }; Walker: PROC [bez: Spline3d.Bezier, t0, t1: REAL] ~ { IF BezSmallEnough[bez] AND TwistSmallEnough[t0, t1] THEN MakeFrame[ bez.b0, IF Vector3d.Equal[bez.b1, bez.b0, 0.0001] -- check for degenerate end tangent THEN Vector3d.Sub[bez.b2, bez.b1] ELSE Vector3d.Sub[bez.b1, bez.b0], t0] ELSE { left, rite: Spline3d.Bezier; t: REAL _ 0.5*(t0+t1); [left, rite] _ Spline3d.SplitBezier[bez]; Walker[left, t0, t]; Walker[rite, t, t1]; }; }; MakeFrame: PROC [p, v: Triple, t: REAL] ~ { n, b: Triple; i: INTEGER _ tube.nFrames; tt: REAL _ 1.0-t; IF tube.nFrames >= tube.frames.maxLength THEN tube.frames _ LengthenFrameSequence[tube.frames]; tube.nFrames _ i+1; tube.frames[i].t _ t; [n, b] _ Basis[v, vv, tube.refVec]; <> tube.frames[i].m _ RefMatrix[p, n, b, v, MAX[0.000001, tt*sc0+t*sc1], tt*tw0+t*tw1, tube.frames[i].m]; vv _ v; tube.refVec _ n; }; IF tube.frames = NIL THEN tube.frames _ NEW[FrameSequenceRec]; tube.nFrames _ 0; tube.refVec _ IF tube.prev # NIL THEN tube.prev.refVec ELSE Spline3d.RefVec[tube.coeffs, 0.0]; Walker[bez, 0.0, 1.0]; MakeFrame[ bez.b3, IF Vector3d.Equal[bez.b3, bez.b2, 0.0001] -- check for degenerate end tangent THEN Vector3d.Sub[bez.b2, bez.b1] ELSE Vector3d.Sub[bez.b3, bez.b2], 1.0]; IF view # NIL THEN tube.circleRes _ ScreenCircleRes[tube, view]; }; ResInfo: PUBLIC PROC [tube: Tube] RETURNS [nPoints, nPolys, minCres, maxCres: INTEGER] ~ { ApplyResInfo: TubeProc ~ { IF tube.circleRes > maxCres THEN maxCres _ tube.circleRes; IF tube.circleRes < minCres THEN minCres _ tube.circleRes; nPoints _ nPoints+ tube.circleRes*(IF tube.next # NIL THEN tube.nFrames ELSE tube.nFrames-1); nPolys _ nPolys+2*tube.circleRes*(tube.nFrames-1); }; minCres _ 10000; maxCres _ nPolys _ nPoints _ 0; TubeMisc.ApplyProc[tube, ApplyResInfo]; }; <> <> <> <<>> <> <> <> <> <<};>> <<>> <> <<};>> GetCircle: PUBLIC PROC [res: INTEGER] RETURNS [PairSequence] ~ { IF res <= 0 THEN RETURN[NIL]; IF res > nCircles THEN RETURN[NewCircle[res]]; IF circles[res] = NIL THEN circles[res] _ NewCircle[res]; RETURN[circles[res]]; }; NewCircle: PROC [res: INTEGER] RETURNS [PairSequence] ~ { rad: REAL _ 0.0; drad: REAL _ 2.0*3.1415926535/REAL[res]; circle: PairSequence _ NEW[PairSequenceRec[res]]; FOR i: NAT IN[0..circle.length _ res) DO circle[i] _ [RealFns.Cos[rad], RealFns.Sin[rad]]; rad _ rad+drad; ENDLOOP; RETURN[circle]; }; Basis: PUBLIC PROC [v, vv, rv: Triple] RETURNS [n, b: Triple] ~ { dot: REAL; vv _ Vector3d.Normalize[vv]; v _ Vector3d.Normalize[v]; rv _ Vector3d.Normalize[rv]; dot _ Vector3d.Dot[v, vv]; IF ABS[dot] > 0.9999 THEN { -- tangents v, vv colinear n _ IF dot > 0.0 THEN rv ELSE [-rv.x, -rv.y, -rv.z]; n _ Vector3d.V90[v, n]; -- ensure orthogonality } ELSE { a: REAL _ RealFns.ArcTanDeg[RealFns.SqRt[1.0-dot*dot], dot]; -- == Acos[] axis: Triple _ Vector3d.Cross[v, vv]; n _ Vector3d.Normalize[Vector3d.RotateAbout[rv, axis, a]]; -- incremental kludge }; b _ Vector3d.Normalize[Vector3d.Cross[v, n]]; }; RefMatrix: PUBLIC PROC [p, x, y, z: Triple, s, t: REAL, out: Matrix_NIL] RETURNS [Matrix] ~ { IF ABS[t] > 0.001 THEN { out _ Matrix3d.MakePureRotate[z, t, , out]; x _ Matrix3d.TransformVec[x, out]; y _ Matrix3d.TransformVec[y, out]; }; RETURN[Matrix3d.LocalScale[Matrix3d.MakeFromTriad[x, y, z, p], s, out]]; }; NSegments: PUBLIC PROC [tube: Tube] RETURNS [n: INTEGER _ 0] ~ { <> FOR t: Tube _ tube, t.next WHILE t # NIL DO n _ n+1; ENDLOOP; }; END. .. <> <> <> <> <> <> <> <> <> <> <> <> <> <> <<[n, b] _ Misc3d.Basis[v, vv, s.refVec];>> <> <> <> <> <<};>> <<>>