DIRECTORY Controls, Contours, TubeDefs, TubeGeometry, TubeMisc, Matrix3d, Real, Spline3d, Vector3d; TubeMiscImpl: CEDAR PROGRAM IMPORTS Controls, Contours, Matrix3d, Real, Spline3d, TubeGeometry, Vector3d EXPORTS TubeMisc ~ BEGIN OPEN TubeDefs; Points: PUBLIC PROC [ tube: Tube, pointProc: PointProc, view: Matrix _ NIL] RETURNS [nPoints: INT] ~ { pointId: INT _ 0; uRangeStart: REAL _ 2.0*PI*tube.r0; OneSpline: PROC [tube: Tube, iStart: NAT, uRange0, v: REAL] ~ { IF tube # NIL AND tube.frames # NIL THEN { uRange1: REAL _ uRange0*(0.5+0.5*(tube.r1/tube.r0)); -- a compromise duRange: REAL _ (uRange1-uRange0)/(tube.frames.length-1.0); circle: PairSequence _ Contours.CirclePairs[tube.circleRes]; tapered: BOOL _ tube.r1 # tube.r0; vFactor: REAL _ IF tapered THEN (tube.r0-tube.r1)/Vector3d.Distance[tube.p0, tube.p1] ELSE 1.0; pNow, pPrev: Triple _ tube.p0; odd: BOOL _ tube.circleRes MOD 2 = 1; FOR i: NAT IN[iStart..NFrames[tube]) DO uRange: REAL _ uRange0+i*duRange; u: REAL _ 0.0; du: REAL _ 0.5*uRange/tube.circleRes; m: Matrix _ tube.frames[i].matrix; mm: Matrix _ IF view # NIL THEN Matrix3d.Mul[m, view] ELSE m; pPrev _ pNow; pNow _ [m[3][0], m[3][1], m[3][2]]; IF i # 0 THEN v _ v+Vector3d.Distance[pNow, pPrev]; FOR j: NAT IN[0..tube.circleRes) DO p: Triple _ Matrix3d.TransformPair[circle[j], mm]; n: Triple _ Matrix3d.TransformVec[[circle[j].x, circle[j].y, 0.0], mm]; IF tapered THEN { vv: Triple _ Spline3d.Velocity[tube.coeffs, tube.frames[i].t]; len: REAL _ Vector3d.Length[n]; n _ Vector3d.Add[n, Vector3d.Mul[vv, len*vFactor/Vector3d.Length[vv]]]; }; n _ Vector3d.Normalize[n]; [] _ pointProc[pointId, p, n, u, v]; pointId _ pointId+1; u _ IF j < tube.circleRes/2 OR odd THEN u+du ELSE u-du; -- u radial symmetry ENDLOOP; ENDLOOP; IF tube.next # NIL AND tube.next.circleRes = tube.circleRes AND tube.next.r0 = tube.r1 THEN OneSpline[tube.next, 1, uRange1, v] -- skip first frame ELSE OneSpline[tube.next, 0, uRange1, v]; -- do first frame FOR n: NAT IN [0..NBranches[tube]) DO OneSpline[tube.branches[n], 0, uRangeStart, v]; -- use 1st frame of 1st branch tube ENDLOOP; }; }; OneSpline[tube, 0, uRangeStart, 0.0]; -- start with first frame of first tube RETURN[pointId]; }; Polys: PUBLIC PROC [tube: Tube, polyProc: PolyProc] RETURNS [nPolys: INT] ~ { polyId, pointId: INTEGER _ 0; OneSpline: PROC [tube: Tube] ~ { IF tube # NIL THEN { cRes: INTEGER _ tube.circleRes; FOR i: NAT IN [0..NFrames[tube]-1) DO n: NAT _ pointId; FOR ii: NAT IN[0..cRes) DO nn: NAT _ IF ii = cRes-1 THEN pointId ELSE n+1; r: NAT _ n+cRes; rr: NAT _ nn+cRes; [] _ polyProc[polyId, n, nn, r]; -- reversed r and n, per Crow, 10/7/86 polyId _ polyId+1; [] _ polyProc[polyId, r, nn, rr]; -- reversed r and rr, per Crow, 10/7/86 n _ n+1; polyId _ polyId+1; ENDLOOP; pointId _ pointId+cRes; ENDLOOP; IF tube.next = NIL OR tube.next.circleRes # tube.circleRes OR tube.next.r0 # tube.r1 THEN pointId _ pointId+cRes; -- end of branch or discontinuity from t to t.next OneSpline[tube.next]; FOR n: NAT IN [0..NBranches[tube]) DO OneSpline[tube.branches[n]]; ENDLOOP; }; }; OneSpline[tube]; RETURN[polyId]; }; Find: PUBLIC PROC [searchee, search: Tube] RETURNS [found: BOOL] ~ { tubeProc: TubeProc ~ {IF tube = searchee THEN found _ TRUE; RETURN[NOT found]}; found _ FALSE; ApplyToTube[search, tubeProc]; }; First: PUBLIC PROC [tube: Tube] RETURNS [Tube] ~ { t: Tube _ tube; IF t = NIL THEN RETURN[NIL]; WHILE t.prev # NIL DO t _ t.prev; ENDLOOP; RETURN[t]; }; Delete: PUBLIC PROC [tube: Tube] ~ { IF tube # NIL AND tube.prev # NIL THEN { IF tube.prev.next = tube THEN tube.prev.next _ NIL ELSE FOR n: NAT IN [0..NBranches[tube.prev]) DO IF tube.prev.branches[n] # tube THEN LOOP; tube.prev.branches[n] _ tube.prev.branches[NBranches[tube.prev]-1]; tube.prev.branches.length _ tube.prev.branches.length-1; EXIT; ENDLOOP; }; }; UnSelectAll: PUBLIC PROC [tube: Tube] ~ { tubeProc: TubeProc ~ {tube.selected _ FALSE}; ApplyToTube[tube, tubeProc]; }; NewBranch: PUBLIC PROC [tube: Tube] RETURNS [Tube] ~ { branch: Tube ~ NEW[TubeRep _ [p0: tube.p1, v0: tube.v1]]; IF tube.next # NIL THEN { vDif: Triple ~ Vector3d.Sub[tube.next.p1, tube.next.p0]; v: Triple ~ Vector3d.SameLength[vDif, tube.v1]; branch.p1 _ Vector3d.Add[branch.p0, Vector3d.Combine[v, 1.5, vDif, -0.5]]; } ELSE branch.p1 _ Vector3d.Add[branch.p0, Vector3d.Sub[branch.p0, tube.p0]]; branch.v1 _ Vector3d.SameLength[branch.v0, Vector3d.Sub[branch.p1, branch.p0]]; TubeGeometry.SetCoeffs[branch]; RETURN[branch]; }; AddBranch: PUBLIC PROC [tube, branch: Tube] ~ { IF tube.branches = NIL THEN tube.branches _ NEW[TubeSequenceRep[1]]; IF tube.branches.length = tube.branches.maxLength THEN { old: TubeSequence ~ tube.branches; tube.branches _ NEW[TubeSequenceRep[old.length+1]]; tube.branches.length _ old.length; FOR i: NAT IN [0..old.length) DO tube.branches[i] _ old[i]; ENDLOOP; }; tube.branches[tube.branches.length] _ branch; tube.branches.length _ tube.branches.length+1; branch.prev _ tube; }; NearestTube: PUBLIC PROC [tube: Tube, point: Triple, tolerance: REAL _ 0.01] RETURNS [nearest: Tube] ~ { minDist: REAL _ 1000.0; tubeProc: TubeProc ~ { tube.near3d _ Spline3d.NearestPoint[point, tube.coeffs, 0.0, 1.0, tolerance]; IF tube.near3d.distance < minDist THEN {minDist _ tube.near3d.distance; nearest _ tube}; }; ApplyToTube[tube, tubeProc]; }; Radius: PUBLIC PROC [tube: Tube, t: REAL, roundTip: BOOL _ FALSE] RETURNS [REAL] ~ { r: REAL ~ (1.0-t)*tube.r0+t*tube.r1; IF roundTip AND ((t < 0.5 AND tube.prev = NIL) OR (t > 0.5 AND tube.next = NIL)) THEN { p: Triple ~ IF t < 0.5 THEN tube.p0 ELSE tube.p1; d: REAL ~ r-Vector3d.Distance[Spline3d.Position[tube.coeffs, t], p]; IF d > 0.0 THEN RETURN[Real.SqRt[r*r-d*d]]; }; RETURN[r]; }; SetDescendantRadii: PUBLIC PROC [tube: Tube, mode: RadiusMode] ~ { tubeProc: TubeProc ~ { summer: TubeProc ~ {sum _ sum+(IF mode = square THEN tube.r0*tube.r0 ELSE tube.r0)}; sum: REAL _ 0.0; ApplyToBranches[tube, summer]; IF sum # 0.0 THEN { factor: REAL ~ IF mode = square THEN Real.SqRt[tube.r1*tube.r1/sum] ELSE tube.r1/sum; setter: TubeProc ~ { taper: REAL ~ IF tube.r0 # 0.0 THEN tube.r1/tube.r0 ELSE 1.0; tube.r0 _ factor*tube.r0; tube.r1 _ tube.r0*taper; }; ApplyToBranches[tube, setter]; }; }; ApplyToTube[tube, tubeProc]; }; TubeHull: PUBLIC PROC [tube: Tube] RETURNS [hull: Hull] ~ { TubeMinMax: PROC [tube: Tube] RETURNS [hull: Hull] ~ { tubeProc: TubeProc ~ { b: Bezier _ Spline3d.BezierFromCoeffs[tube.coeffs]; points: ARRAY [0..4) OF Triple _ [b.b0, b.b1, b.b2, b.b3]; hull.rMin _ MIN[hull.rMin, tube.r0, tube.r1]; hull.rMax _ MAX[hull.rMax, tube.r0, tube.r1]; FOR n: NAT IN [0..4) DO p: Triple _ points[n]; hull.pMin _ [MIN[p.x, hull.pMin.x], MIN[p.y, hull.pMin.y], MIN[p.z, hull.pMin.z]]; hull.pMax _ [MAX[p.x, hull.pMax.x], MAX[p.y, hull.pMax.y], MAX[p.z, hull.pMax.z]]; ENDLOOP; }; hull _ [origin, [10000.0, 10000.0, 10000.0], [-10000.0, -10000.0, -10000.0], 10000.0, 0.0]; ApplyToTube[tube, tubeProc]; }; hull _ TubeMinMax[tube]; hull.center _ Vector3d.Mul[Vector3d.Add[hull.pMin, hull.pMax], 0.5]; }; NTubes: PUBLIC PROC [tube: Tube] RETURNS [INTEGER] ~ { nTubes: INTEGER _ 0; tubeProc: TubeProc ~ {nTubes _ nTubes+1}; ApplyToTube[tube, tubeProc]; RETURN[nTubes]; }; NBranches: PUBLIC PROC [tube: Tube] RETURNS [n: INTEGER] ~ { n _ IF tube.branches # NIL THEN tube.branches.length ELSE 0; }; NSiblings: PUBLIC PROC [tube: Tube, tubeAlso: BOOL _ TRUE] RETURNS [n: INTEGER] ~ { tubeProc: TubeProc ~ {n _ n+1}; n _ 0; ApplyToSiblings[tube, tubeProc, tubeAlso]; }; NFrames: PUBLIC PROC [tube: Tube] RETURNS [INTEGER] ~ { RETURN[IF tube.frames # NIL THEN tube.frames.length ELSE 0]; }; NPoints: PUBLIC PROC [tube: Tube] RETURNS [INT] ~ { OneSpline: PROC [tube: Tube, iStart: NAT] ~ { IF tube # NIL AND tube.frames # NIL THEN { nPoints _ nPoints+(tube.frames.length-iStart)*tube.circleRes; IF tube.next # NIL AND tube.next.circleRes = tube.circleRes AND tube.next.r0 = tube.r1 THEN OneSpline[tube.next, 1] -- skip first frame ELSE OneSpline[tube.next, 0]; -- do first frame FOR n: NAT IN [0..NBranches[tube]) DO OneSpline[tube.branches[n], 0]; -- use 1st frame of 1st branch tube ENDLOOP; }; }; nPoints: INT _ 0; OneSpline[tube, 0]; -- start with first frame of first tube RETURN[nPoints]; }; NPolys: PUBLIC PROC [tube: Tube] RETURNS [INT] ~ { n: INT _ 0; FOR t: Tube _ tube, t.next WHILE t # NIL DO IF t.frames # NIL THEN n _ n+2*(t.frames.length-1)*t.circleRes; ENDLOOP; RETURN[MAX[0, n]]; }; NSplinesInBranch: PUBLIC PROC [tube: Tube] RETURNS [INT] ~ { n: INT _ 0; FOR t: Tube _ tube, t.next WHILE t # NIL DO n _ n+1; ENDLOOP; RETURN[n]; }; Info: PUBLIC PROC [tube: Tube] RETURNS [nPoints, nPolys, minCres, maxCres: INT] ~ { InnerResInfo: TubeProc ~ { IF tube.circleRes > maxCres THEN maxCres _ tube.circleRes; IF tube.circleRes < minCres THEN minCres _ tube.circleRes; }; minCres _ 10000; maxCres _ nPolys _ nPoints _ 0; ApplyToTube[tube, InnerResInfo]; nPoints _ NPoints[tube]; nPolys _ NPolys[tube]; }; Copy: PUBLIC PROC [tube: Tube] RETURNS [copy: Tube] ~ { InnerCopy: PROC [tube, prev: Tube] RETURNS [copy: Tube] ~ { IF tube = NIL THEN RETURN[NIL]; copy _ NEW[TubeRep _ [ p0: tube.p0, p1: tube.p1, v0: tube.v0, v1: tube.v1, tw0: tube.tw0, tw1: tube.tw1, r0: tube.r0, r1: tube.r1, selected: tube.selected, coeffs: Spline3d.CopyCoeffs[tube.coeffs], xCoeffs: Spline3d.CopyCoeffs[tube.xCoeffs], refVec: tube.refVec, circleRes: tube.circleRes, prev: prev, refAny: tube.refAny ]]; copy.frames _ TubeGeometry.CopyFrames[tube.frames]; copy.branches _ NEW[TubeSequenceRep[NBranches[tube]]]; copy.branches.length _ copy.branches.maxLength; FOR n: NAT IN [0..NBranches[tube]) DO copy.branches[n] _ InnerCopy[tube.branches[n], copy]; ENDLOOP; copy.next _ InnerCopy[tube.next, copy]; }; copy _ InnerCopy[tube, NIL]; }; ApplyToTube: PUBLIC PROC [tube: Tube, tubeProc: TubeProc] ~ { Inner: PROC [tube: Tube] ~ { IF tube = NIL OR NOT tubeProc[tube] THEN RETURN; Inner[tube.next]; FOR n: NAT IN [0..NBranches[tube]) DO Inner[tube.branches[n]]; ENDLOOP; }; Inner[tube]; }; ApplyToBranches: PUBLIC PROC [tube: Tube, tubeProc: TubeProc, nextAlso: BOOL _ TRUE] ~{ IF tube = NIL THEN RETURN; IF nextAlso AND tube.next # NIL AND NOT tubeProc[tube.next] THEN RETURN; FOR n: NAT IN [0..NBranches[tube]) DO IF tube.branches[n] # NIL AND NOT tubeProc[tube.branches[n]] THEN RETURN; ENDLOOP; }; ApplyToSiblings: PUBLIC PROC [tube: Tube, tubeProc: TubeProc, tubeAlso: BOOL _ TRUE] ~ { IF tube # NIL THEN { prev: Tube ~ tube.prev; IF prev = NIL THEN { IF tubeAlso THEN [] _ tubeProc[tube]; RETURN; }; IF (tubeAlso OR prev.next # tube) AND prev.next # NIL AND NOT tubeProc[prev.next] THEN RETURN; FOR n: NAT IN [0..NBranches[prev]) DO IF (tubeAlso OR prev.branches[n] # tube) AND prev.branches[n] # NIL AND NOT tubeProc[prev.branches[n]] THEN RETURN; ENDLOOP; }; }; ToggleDetail: PUBLIC PROC [ details: Details, toToggle: DetailType, trueName, falseName: ROPE, outerData: OuterData] ~ { state: BOOL; SELECT toToggle FROM autoSimplify => state _ details.autoSimplify _ NOT details.autoSimplify; label => state _ details.label _ NOT details.label; skeleton => state _ details.skeleton _ NOT details.skeleton; ends => state _ details.ends _ NOT details.ends; spline => state _ details.spline _ NOT details.spline; pick => state _ details.pick _ NOT details.pick; enabled => state _ details.enabled _ NOT details.enabled; frames => state _ details.frames _ NOT details.frames; lines => state _ details.lines _ NOT details.lines; curvature => state _ details.curvature _ NOT details.curvature; velocity => state _ details.velocity _ NOT details.velocity; acceleration => state _ details.acceleration _ NOT details.acceleration; contours => state _ details.contours _ NOT details.contours; normals => state _ details.normals _ NOT details.normals; ENDCASE; details.shape _ details.frames OR details.curvature OR details.velocity OR details.acceleration; details.skin _ details.contours OR details.lines OR details.normals; Controls.ButtonToggle[outerData, state, trueName, falseName]; }; DetailState: PUBLIC PROC [details: Details, type: DetailType] RETURNS [BOOL] ~ { RETURN [SELECT type FROM autoSimplify => details.autoSimplify, label => details.label, skeleton => details.skeleton, spline => details.spline, pick => details.pick, enabled => details.enabled, frames => details.frames, lines => details.lines, curvature => details.curvature, velocity => details.velocity, acceleration => details.acceleration, contours => details.contours, normals => details.normals, shape => details.shape, skin => details.skin, ENDCASE => FALSE]; }; ClearPendings: PUBLIC PROC [pendings: Pendings] ~ { pendings.epsilon _ pendings.scale _ pendings.r _ pendings.tw0 _ pendings.tw1 _ pendings.cres _ pendings.holdPosition _ pendings.holdTangent _ pendings.shape _ pendings.skin _ FALSE; }; END. ΦTubeMiscImpl.mesa Copyright c 1985 by Xerox Corporation. All rights reserved. Bloomenthal, February 24, 1987 6:14:44 pm PST Points and Polygons Procedures See TubeDisplay.DrawNormals connect ith frame to (i+1)th frame: Miscellany Branching Nearness Procedures Radius Procedures r: REAL ~ IF t < 0.5 THEN tube.r0 ELSE tube.r1; Attributes Procedures Information Procedures Copy Procedure Call Back Procedure for Tube Sections Details Procedures Pendings Procedures Κo˜šœ™Jšœ Οmœ1™˜>Jšœžœ˜JšœG˜GJ˜—˜J˜—J˜$J˜Jšœ˜Jš œžœžœžœžœ‘˜MJšžœ˜J˜—Jšžœ˜—J˜šžœ žœžœ&žœ˜VJšžœ&‘˜=Jšžœ'‘˜<—J˜šžœžœžœž˜%Jšœ/‘$˜SJšžœ˜—J˜—J˜J˜—Jšœ*‘'˜QJšžœ ˜J˜J˜—š  œžœžœ!žœ žœ˜MJšœžœ˜J˜š  œžœ˜ šžœžœžœ˜Lšœžœ˜J˜Jšœ#™#šžœžœžœž˜%Jšœžœ ˜šžœžœžœ ž˜Jš œžœžœ žœ žœ˜/Jšœžœ ˜Jšœžœ ˜Jšœ"‘&˜HJ˜Jšœ#‘'˜JJ˜J˜Jšžœ˜—J˜Jšžœ˜—J˜šžœ žœžœ&žœ˜TJšžœ‘2˜PJ˜—J˜šžœžœžœž˜%Jšœ˜Jšžœ˜—J˜—Jšœ˜—J˜Lšœ˜Lšžœ ˜J˜——™ š  œžœžœžœ žœ˜DJš  œžœžœ žœžœžœ ˜OJšœžœ˜Jšœ˜J˜J˜—š œžœžœžœ ˜2J˜Jš žœžœžœžœžœ˜Jšžœ žœžœ žœ˜*Jšžœ˜ J˜J˜—š œžœžœ˜$š žœžœžœ žœžœ˜(šžœ˜Jšžœž˜š žœžœžœžœž˜/Jšžœžœžœ˜*JšœC˜CJ˜8Jšžœ˜Jšžœ˜——J˜—J˜J˜—š  œžœžœ˜)Jšœ&žœ˜-J˜J˜——™ š  œžœžœžœ ˜6Jšœžœ'˜9šžœ ž˜šžœ˜Jšœ8˜8Jšœ/˜/J˜JJ˜—JšžœG˜K—JšœO˜OJ˜Lšžœ ˜J˜J˜—š  œžœžœ˜/Jšžœžœžœžœ˜Dšžœ0žœ˜8J˜"Jšœžœ ˜3J˜"Jš žœžœžœžœžœ˜DJ˜—J˜-J˜.J˜J˜——šœ™š  œžœžœ(žœ˜LJšžœ˜Jšœ žœ ˜š œ˜JšœM˜MJšžœ žœ3˜YJ˜—J˜Jšœ˜——šœ™š œžœžœžœ žœžœžœžœ˜TLšœžœ˜$šžœ žœ žœ žœžœ žœ žœžœ˜WLš œžœžœ žœ žœ ™/Lšœ žœ žœ žœ ˜1Lšœžœ=˜DLšžœ žœžœ˜+Lšœ˜—Lšžœ˜ L˜L˜—š œž œ#˜Bš œ˜Jš œžœžœžœ ˜TJšœžœ˜Jšœ˜šžœ žœ˜Jš œžœžœžœžœ ˜Uš œ˜Jš œžœžœžœžœ˜=Jšœ˜Jšœ˜J˜—Jšœ˜J˜—J˜—J˜J˜——šœ™š œžœžœžœ˜;š  œžœžœ˜6š œ˜J˜3Jšœžœžœ#˜:Jšœ žœ˜-Jšœ žœ˜-šžœžœžœž˜J˜Jšœ žœžœžœ˜RJšœ žœžœžœ˜RJšžœ˜—J˜—Jšœ[˜[J˜J˜—Jšœ˜JšœD˜DJ˜——šœ™š œž œžœžœ˜6Jšœžœ˜Jšœ)˜)J˜Jšžœ ˜J˜J˜—š   œžœžœžœžœ˜Jšœ#žœ˜4Jšœ'žœ˜:Jšœ#žœ˜4Jšœ'žœ˜;Jšœ&žœ˜9Jšœ%žœ˜7Jšœ+žœ˜AJšœ*žœ˜?Jšœ0žœ˜IJšœ)žœ˜>Jšœ(žœ˜