<<>> <> <> <> DIRECTORY Commander, CommanderOps, Controls, Convert, G2dBasic, G3dBasic, G3dSpline, G3dTool, G3dTube, G3dVector, IO, Menus, Rope; G3dTubeCmdsImpl: CEDAR PROGRAM IMPORTS CommanderOps, Controls, Convert, G3dSpline, G3dTool, G3dTube, G3dVector, IO, Rope ~ BEGIN <> Control: TYPE ~ Controls.Control; Triple: TYPE ~ G3dBasic.Triple; Tool: TYPE ~ G3dTool.Tool; ROPE: TYPE ~ Rope.ROPE; Tube: TYPE ~ G3dTube.Tube; TubeProc: TYPE ~ G3dTube.TubeProc; <> Data: TYPE ~ REF DataRep; DataRep: TYPE ~ RECORD [ tool: Tool ¬ NIL, alpha: Control ¬ NIL, tube1, tube2: Tube ¬ NIL, interp: Tube ¬ NIL ]; TubeInterpCmd: Commander.CommandProc ~ { argv: CommanderOps.ArgumentVector ¬ CommanderOps.Parse[cmd]; IF argv.argc # 3 THEN RETURN[$Failure, interpUsage] ELSE { Prepare: PROC [tube: Tube] ~ { tube.epsilon ¬ 1.0; G3dTube.Make[tube]; }; d: Data ¬ NEW[DataRep]; d.tube1 ¬ G3dTube.TubeFromFile[argv[1]]; d.tube2 ¬ G3dTube.TubeFromFile[argv[2]]; IF d.tube1 = NIL OR d.tube2 = NIL THEN RETURN[$Failure, "Can't read tube(s)"] ELSE { Prepare[d.tube1]; Prepare[d.tube2]; d.interp ¬ G3dTube.CopyEntireTube[d.tube1]; G3dTube.SelectAll[d.interp]; d.tool ¬ G3dTool.MakeTool[ name: "TubeInterp", extraControls: LIST[Controls.NewControl["alpha",, d, 0, 1, 0, Alpha,,,,,,, 136]], extraButtons: LIST[Controls.ClickButton["Write Tube", WriteTube, d]], client: [draw: Draw, data: d] ]; }; }; }; Alpha: Controls.ControlProc ~ { d: Data ¬ NARROW[clientData]; IF control.mouse.button # right THEN RETURN; G3dTube.InterpTubes[d.tube1, d.tube2, d.interp, control.value]; G3dTool.Repaint[d.tool]; }; Draw: G3dTool.DrawProc ~ { G3dTube.DrawSkeleton[context, NARROW[clientData, Data].interp, view, vp]; }; WriteTube: Controls.ClickProc ~ { d: Data ¬ NARROW[clientData]; fileName: ROPE ¬ Controls.TypescriptReadFileName[d.tool.typescript]; IF fileName # NIL THEN G3dTube.TubeToFile[d.interp, fileName]; }; <> TubeOpsCmd: Commander.CommandProc ~ { tube: Tube; argv: CommanderOps.ArgumentVector ¬ CommanderOps.Parse[cmd]; IF argv.argc < 4 THEN RETURN[$Failure, opsUsage]; IF (tube ¬ G3dTube.TubeFromFile[argv[1]]) = NIL THEN RETURN[$Failure, "Can't read tube"] ELSE { n: NAT ¬ 3; WHILE n < argv.argc DO Eq: PROC [r: ROPE] RETURNS [b: BOOL] ~ {b ¬ Rope.Equal[argv[n], r, FALSE]}; GetReal: PROC [n: NAT] RETURNS[r: REAL] ~ {r ¬ Convert.RealFromRope[argv[n]]}; SELECT TRUE FROM Eq["-fixUp"] => { Op: TubeProc ~ {IF tube.prev # NIL THEN tube.p0 ¬ tube.prev.p1}; G3dTube.ApplyToTube[tube, Op]; }; Eq["-normalize"] => { Op: TubeProc ~ { tube.p0 ¬ G3dVector.Mul[G3dVector.Sub[tube.p0, hull.center], scale]; tube.p1 ¬ G3dVector.Mul[G3dVector.Sub[tube.p1, hull.center], scale]; tube.v0 ¬ G3dVector.Mul[tube.v0, scale]; tube.v1 ¬ G3dVector.Mul[tube.v1, scale]; tube.r0 ¬ scale*tube.r0; tube.r1 ¬ scale*tube.r1; }; hull: G3dBasic.Hull ¬ G3dTube.TubeHull[tube]; size: Triple ¬ G3dVector.Sub[hull.pMax, hull.pMin]; scale: REAL ¬ 1.0/MAX[size.x, size.y, size.z]; G3dTube.ApplyToTube[tube, Op]; }; Eq["-scale"] => { Op: TubeProc ~ { tube.p0 ¬ G3dVector.Mul[tube.p0, scale]; tube.p1 ¬ G3dVector.Mul[tube.p1, scale]; }; scale: REAL ¬ GetReal[n+1]; n ¬ n+1; G3dTube.ApplyToTube[tube, Op]; }; Eq["-offset"] => { Op: TubeProc ~ { tube.p0 ¬ G3dVector.Add[tube.p0, offset]; tube.p1 ¬ G3dVector.Add[tube.p1, offset]; }; offset: Triple ¬ [GetReal[n+1], GetReal[n+2], GetReal[n+3]]; n ¬ n+3; G3dTube.ApplyToTube[tube, Op]; }; Eq["-invertZ"] => { Op: TubeProc ~ { tube.p0.z ¬ 1.0-tube.p0.z; tube.p1.z ¬ 1.0-tube.p1.z; }; G3dTube.ApplyToTube[tube, Op]; }; Eq["-interpolate"] => { Interpolate: TubeProc ~ { AddPt: PROC [p: Triple] ~ {pts[pts.length] ¬ p; pts.length ¬ pts.length+1}; temp: Tube ¬ tube; last: Tube ¬ G3dTube.Last[tube]; splines: G3dSpline.SplineSequence; tan0: Triple ¬ IF tube.prev # NIL THEN tube.prev.v1 ELSE G3dVector.Mul[G3dVector.Sub[tube.p1, tube.p0], (1.0/3.0)]; tan1: Triple ¬ G3dVector.Mul[G3dVector.Sub[last.p1, last.p0], (1.0/3.0)]; pts.length ¬ 0; AddPt[tube.p0]; FOR t: Tube ¬ tube, t.next WHILE t # NIL DO AddPt[t.p1]; ENDLOOP; splines ¬ G3dSpline.Interpolate[pts, tan0, tan1]; FOR n: NAT IN [0..splines.length) DO temp.spline ¬ splines[n]; temp.v0 ¬ G3dSpline.Velocity[temp.spline, 0.0]; temp.v1 ¬ G3dSpline.Velocity[temp.spline, 1.0]; temp ¬ temp.next; ENDLOOP; FOR t: Tube ¬ tube, t.next WHILE t # NIL DO G3dTube.ApplyToBranches[t, Interpolate, FALSE]; ENDLOOP; }; pts: G3dBasic.TripleSequence ¬ NEW[G3dBasic.TripleSequenceRep[100]]; [] ¬ Interpolate[tube]; }; ENDCASE => IO.PutF1[cmd.err, "Bad option: %g\n", IO.rope[argv[n]]]; n ¬ n+1; ENDLOOP; G3dTube.TubeToFile[tube, argv[2]]; }; }; <> opsUsage: ROPE ¬ " 3dTubeOps <-option> Options include: fixUp make tube.p0 = tube.prev.p1 scale scale by factor offset offset by x, y, z invertZ change z values to 1-z normalize scale and translate to +/- 1 in x, y, z interpolate create spline coefficients, v0 and v1"; interpUsage: ROPE ¬ "TubeInterp "; G3dTool.Register["TubeOps", TubeOpsCmd, opsUsage]; G3dTool.Register["TubeInterp", TubeInterpCmd, interpUsage]; END. .. <> <> <> <> DIRECTORY Commander, CommanderOps, Controls, G3dBasic, G3dTool, G3dMatrix, G3dQuaternion, G3dTimeTrees, G3dTube, G3dVector, Rope; G3dTubeInterpCmdImpl: CEDAR PROGRAM IMPORTS Commander, CommanderOps, Controls, G3dTool, G3dMatrix, G3dQuaternion, G3dTimeTrees, G3dTube, G3dVector ~ BEGIN <> Control: TYPE ~ Controls.Control; Tool: TYPE ~ G3dTool.Tool; Matrix: TYPE ~ G3dMatrix.Matrix; Triple: TYPE ~ G3dBasic.Triple; Quaternion: TYPE ~ G3dQuaternion.Quaternion; ROPE: TYPE ~ Rope.ROPE; TimeTree: TYPE ~ G3dTimeTrees.TimeTree; Tube: TYPE ~ G3dTube.Tube; <> Data: TYPE ~ REF DataRep; DataRep: TYPE ~ RECORD [ tool: Tool ¬ NIL, alpha: Control ¬ NIL, tube1, tube2: Tube ¬ NIL, interp: Tube ¬ NIL, newProc: BOOL ¬ FALSE ]; NewTubeInterpCmd: Commander.CommandProc ~ { [result, msg] ¬ MakeTestTool[cmd, TRUE]; }; TubeInterpCmd: Commander.CommandProc ~ { [result, msg] ¬ MakeTestTool[cmd, FALSE]; }; MakeTestTool: PROC [cmd: Commander.Handle, newProc: BOOL] RETURNS [result: REF ¬ NIL, msg: ROPE ¬ NIL] ~ { argv: CommanderOps.ArgumentVector ¬ CommanderOps.Parse[cmd]; IF argv.argc # 3 THEN RETURN [$Failure, interpUsage] ELSE { Prepare: PROC [tube: Tube] ~ { tube.epsilon ¬ 1.0; G3dTube.Make[tube]; }; d: Data ¬ NEW[DataRep]; d.tube1 ¬ G3dTube.TubeFromFile[argv[1]]; d.tube2 ¬ G3dTube.TubeFromFile[argv[2]]; d.newProc ¬ newProc; IF d.tube1 = NIL OR d.tube2 = NIL THEN RETURN[$Failure, "Can't read tube(s)"] ELSE { Prepare[d.tube1]; Prepare[d.tube2]; d.interp ¬ G3dTube.CopyEntireTube[d.tube1]; G3dTube.SelectAll[d.interp]; d.tool ¬ G3dTool.MakeTool[ name: "3dTubeInterp", extraControls: LIST[Controls.NewControl["alpha",, d, 0, 1, 0, Alpha,,,,,,, 136]], extraButtons: LIST[Controls.ClickButton["Write Tube", WriteTube, d]], client: [draw: Draw, data: d] ]; }; }; }; Alpha: Controls.ControlProc ~ { d: Data ¬ NARROW[clientData]; IF control.mouse.button # right THEN RETURN; IF d.newProc THEN NewInterpTubes[d.tube1, d.tube2, d.interp, control.value] ELSE InterpTubes[d.tube1, d.tube2, d.interp, control.value]; G3dTool.Repaint[d.tool]; }; WriteTube: Controls.ClickProc ~ { d: Data ¬ NARROW[clientData]; fileName: ROPE ¬ Controls.TypescriptReadFileName[d.tool.typescript]; IF fileName # NIL THEN G3dTube.TubeToFile[d.interp, fileName]; }; InterpTubes: PROC [tube1, tube2, interp: Tube, alpha: REAL] ~ { <<-- This presumes tube1 and tube2 have identical topology!>> GetQuaternion: PROC [t: Tube] RETURNS [Quaternion] ~ { z: Triple ¬ G3dVector.Unit[G3dVector.Sub[t.p1, t.p0]]; x: Triple ¬ G3dVector.Unit[G3dVector.V90[z, t.refVec]]; y: Triple ¬ G3dVector.Unit[G3dVector.Cross[z, x]]; m ¬ G3dMatrix.MakeFromTriad[x, y, z,, FALSE, m]; RETURN[G3dQuaternion.FromMatrix[m]]; }; Set: PROC [t, t1, t2: Tube] ~ { q1: Quaternion ¬ GetQuaternion[t1]; q2: Quaternion ¬ GetQuaternion[t2]; q: Quaternion ¬ G3dQuaternion.Slerp[ IF G3dQuaternion.Dot[q1, q2] < 0.0 THEN G3dQuaternion.Neg[q1] ELSE q1, q2, alpha]; len1: REAL ¬ G3dVector.Distance[t1.p0, t1.p1]; len2: REAL ¬ G3dVector.Distance[t2.p0, t2.p1]; len: REAL ¬ len1+alpha*(len2-len1); temp: Matrix ¬ m ¬ G3dQuaternion.ToMatrix[q, m]; z: Triple ¬ G3dMatrix.TransformVec[[0.0, 0.0, 1.0], m]; IF t.prev # NIL THEN t.p0 ¬ t.prev.p1; t.p1 ¬ G3dVector.Add[t.p0, G3dVector.SetVectorLength[z, len]]; }; DoTube: PROC [t, t1, t2: Tube] ~ { Set[t, t1, t2]; IF t.next # NIL THEN DoTube[t.next, t1.next, t2.next]; IF t.branches # NIL THEN FOR n: NAT IN [0..t.branches.length) DO DoTube[t.branches[n], t1.branches[n], t2.branches[n]]; ENDLOOP; }; m: Matrix ¬ G3dMatrix.ObtainMatrix[]; DoTube[interp, tube1, tube2]; G3dMatrix.ReleaseMatrix[m]; }; <> TimeTreeFromTubes: PROC [tube1, tube2: Tube] RETURNS [timeTree: TimeTree] ~ { GetMatrix: PROC [t: Tube] RETURNS [Matrix] ~ { z: Triple ¬ G3dVector.Unit[G3dVector.Sub[t.p1, t.p0]]; x: Triple ¬ G3dVector.Unit[G3dVector.V90[z, t.refVec]]; y: Triple ¬ G3dVector.Unit[G3dVector.Cross[z, x]]; RETURN[G3dMatrix.MakeFromTriad[x, y, z]]; }; NodesFromTubes: PROC [tube1, tube2: Tube] ~ { SetNode: PROC [t: Tube, time: REAL] ~ { G3dTimeTrees.InsertKey[timeTree, time, NEW[REAL ¬ G3dVector.Distance[t.p0, t.p1]], "length"]; G3dTimeTrees.InsertTransform[timeTree, time, GetMatrix[t]]; }; SetNode[tube1, 0.0]; SetNode[tube2, 1.0]; G3dTimeTrees.PushTimeTree[timeTree]; IF tube1.next # NIL THEN NodesFromTubes[tube1.next, tube2.next]; G3dTimeTrees.PopTimeTree[timeTree]; IF tube1.next = NIL THEN timeTree.activeNode.children[0] ¬ NIL; -- signify no "next" node IF tube1.branches # NIL THEN FOR n: NAT IN [0..tube1.branches.length) DO G3dTimeTrees.PushTimeTree[timeTree]; NodesFromTubes[tube1.branches[n], tube2.branches[n]]; G3dTimeTrees.PopTimeTree[timeTree]; ENDLOOP; }; timeTree ¬ G3dTimeTrees.CreateTimeTree[]; G3dTimeTrees.RegisterKeyType[timeTree, "length", real]; IF tube1 # NIL AND tube2 # NIL THEN NodesFromTubes[tube1, tube2]; }; InterpFromTimeTree: PROC [interp: Tube, timeTree: TimeTree] ~ { <<-- tube.next is node.children[0], other children are branches>> BuildTube: PROC [interp: Tube, node: G3dTimeTrees.Node] ~ { len: REAL ¬ NARROW[G3dTimeTrees.GetStrobedKey[node, "length"], REF REAL]­; z: Triple ¬ G3dMatrix.TransformVec[[0.0, 0.0, 1.0], node.globalTransform]; IF interp.prev # NIL THEN interp.p0 ¬ interp.prev.p1; interp.p1 ¬ G3dVector.Add[interp.p0, G3dVector.SetVectorLength[z, len]]; IF node.children = NIL OR node.children.length = 0 THEN RETURN; IF node.children[0] # NIL THEN BuildTube[interp.next, node.children[0]]; FOR i: INT IN [1.. node.children.length) DO BuildTube[interp.branches[i-1], node.children[i]]; ENDLOOP; }; BuildTube[interp, timeTree.root]; }; NewInterpTubes: PROC [tube1, tube2, interp: Tube, alpha: REAL] ~ { <<-- This presumes tube1 and tube2 have identical topology!>> timeTree: TimeTree ¬ TimeTreeFromTubes[tube1, tube2]; G3dTimeTrees.StrobeTimeTree[timeTree, alpha]; InterpFromTimeTree[interp, timeTree]; }; <> interpUsage: ROPE ¬ "TubeInterp "; G3dTool.Register["TubeInterp", TubeInterpCmd, interpUsage]; G3dTool.Register["NewTubeInterp", NewTubeInterpCmd, interpUsage]; END.