DIRECTORY Cubic2, Matrix3d, Real, RealFns, Spline3d, Vector2, Vector3d, TubeDefs, TubeStructure; TubeStructureImpl: CEDAR PROGRAM IMPORTS Cubic2, Matrix3d, Real, RealFns, Spline3d, Vector2, Vector3d EXPORTS TubeStructure ~ BEGIN OPEN TubeDefs; nCircles: NAT ~ 40; circles: ARRAY [1..nCircles] OF PairSequence _ ALL[NIL]; PropagateCircleRes: PUBLIC PROC [tube: Tube, circleRes: NAT] ~ { 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] ~ { Inner: PROC [t: Tube, length, scale0: REAL] ~ { scale1: REAL _ scale0; IF t = NIL THEN RETURN; IF taper # 0.0 THEN { length _ length+Spline3d.Length[t.c]; scale1 _ scale*(1.0-taper*length); }; MakeFrames[t, scale0, scale1, epsilon, view]; FOR n: NAT IN [0..t.nBranches) DO Inner[t.branches[n], length, scale1]; ENDLOOP; Inner[t.next, length, scale1]; }; Inner[tube, 0.0, scale]; }; MakeFrames: PUBLIC PROC [ tube: Tube, scale0, scale1, epsilon: REAL _ 1.0, view: Matrix _ NIL] ~ { bez: Spline3d.Bezier _ Spline3d.BezierFromCoeffs[tube.c]; maxLen: REAL _ IF view = NIL THEN 0.01*Spline3d.ConvexHullLength[bez] ELSE 0.0; vv: Triple _ Vector3d.Sub[bez.b1, bez.b0]; tw0: REAL _ tube.twist0; tw1: REAL _ tube.twist1; sc0: REAL _ tube.r0*scale0; sc1: REAL _ tube.r1*scale1; ScreenCircleRes: PROC [tube: Tube, view: Matrix] RETURNS [res: NAT] ~ { 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, epsilon]]]; }; res _ MAX[CircleRes[tube.p0, scale0*tube.r0], CircleRes[tube.p1, scale1*tube.r1]]; IF res MOD 2 = 1 THEN res _ res+1; }; LengthenFrameSeq: PROC [f: FrameSeq] RETURNS [FrameSeq] ~ { temp: FrameSeq _ NEW[FrameSeqRep[MAX[5, Real.RoundI[1.3*f.maxLength]]]]; FOR i: NAT IN[0..f.maxLength) DO temp[i] _ f[i]; ENDLOOP; RETURN[temp]; }; SmallEnough: 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]], epsilon]]; }; Walker: PROC [bez: Spline3d.Bezier, t0, t1: REAL] ~ { IF SmallEnough[bez] THEN MakeFrame[bez.b0, 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: NAT _ tube.axialRes; tt: REAL _ 1.0-t; tube.axialRes _ i+1; IF tube.axialRes >= tube.frames.maxLength THEN tube.frames _ LengthenFrameSeq[tube.frames]; 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[FrameSeqRep]; tube.axialRes _ 0; tube.refVec _ IF tube.prev # NIL THEN tube.prev.refVec ELSE Spline3d.RefVec[tube.c, 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]; }; TubeResInfo: PUBLIC PROC [tube: Tube] RETURNS [nPoints, nPolys, minCres, maxCres: INTEGER] ~ { Inner: PROC [t: Tube] ~ { IF t = NIL THEN RETURN; IF t.circleRes > maxCres THEN maxCres _ t.circleRes; IF t.circleRes < minCres THEN minCres _ t.circleRes; nPoints _ nPoints+t.circleRes*(IF t.next # NIL THEN t.axialRes ELSE t.axialRes-1); nPolys _ nPolys+2*t.circleRes*(t.axialRes-1); Inner[t.next]; FOR n: NAT IN [0..t.nBranches) DO Inner[t.branches[n]] ENDLOOP; }; minCres _ 10000; maxCres _ nPolys _ nPoints _ 0; Inner[tube]; }; GetCircle: PUBLIC PROC [res: NAT] 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: NAT] RETURNS [PairSequence] ~ { rad: REAL _ 0.0; drad: REAL _ 2.0*3.1415926535/REAL[res]; circle: PairSequence _ NEW[PairSequenceRec[res]]; FOR i: NAT IN[0..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: NAT _ 0] ~ { FOR t: Tube _ tube, t.next WHILE t # NIL DO n _ n+1; ENDLOOP; }; END. .. ¨TubeStructureImpl.mesa Copyright c 1985 by Xerox Corporation. All rights reserved. Bloomenthal, May 23, 1986 12:57:02 pm PDT Keep scale non-zero (avoid subsequent surface normal computation problems): Return number of splines in limb: MakeMatrices: PUBLIC PROC [s: SplineData, scale: REAL] ~ { sc0: REAL _ s.rad0*scale; sc1: REAL _ s.rad1*scale; tw0: REAL _ s.twist0; tw1: REAL _ s.twist1; vv: Triple _ s.v0; mats: MatrixSeq _ s.mats; s.refVec _ IF s.prev # NIL THEN s.prev.refVec ELSE Spline3d.RefVec[s.c, 0.0]; mats[0] _Misc3d.RefMatrix[s.p0, s.refVec, Vector3d.Cross[vv, s.refVec], vv, sc0, tw0, mats[0]]; FOR i: NAT IN[1..s.axialRes) DO n, b: Triple; t: REAL _ i/REAL[s.axialRes-1.0]; p: Triple _ Spline3d.Position[s.c, t]; v: Triple _ Spline3d.Tangent[s.c, t]; [n, b] _ Misc3d.Basis[v, vv, s.refVec]; mats[i] _ Misc3d.RefMatrix[p, n, b, v, (1.0-t)*sc0+t*sc1, (1.0-t)*tw0+t*tw1, mats[i]]; vv _ v; s.refVec _ n; ENDLOOP; }; Κ0˜šœ™Jšœ Οmœ1™