G3dTubeCmdsImpl.mesa
Copyright Ó 1985, 1992 by Xerox Corporation. All rights reserved.
Bloomenthal, October 20, 1992 5:17 pm PDT
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
Types
Control:    TYPE ~ Controls.Control;
Triple:    TYPE ~ G3dBasic.Triple;
Tool:     TYPE ~ G3dTool.Tool;
ROPE:     TYPE ~ Rope.ROPE;
Tube:     TYPE ~ G3dTube.Tube;
TubeProc:   TYPE ~ G3dTube.TubeProc;
Interpolate Between Two Topologically Identical Tubes
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];
};
Tube Operations
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]];
};
};
Start Code
opsUsage: ROPE ¬ "
3dTubeOps <input tube file> <output tube file> <-option>
Options include:
 fixUp    make tube.p0 = tube.prev.p1
 scale <factor> scale by factor
 offset <x, y, z> 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 <tube #1> <tube #2>";
G3dTool.Register["TubeOps", TubeOpsCmd, opsUsage];
G3dTool.Register["TubeInterp", TubeInterpCmd, interpUsage];
END.
..
G3dTubeInterpCmdImpl.mesa
Copyright Ó 1985, 1992 by Xerox Corporation. All rights reservet.
Bloomenthal, July 22, 1992 11:21 pm PDT
Glassner, July 3, 1990 1:29:57 pm PDT
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
Types
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;
Interpolate Between Two Topologically Identical Tubes
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];
};
Using G3dTimeTrees
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];
};
Start Code
interpUsage: ROPE ¬ "TubeInterp <tube #1> <tube #2>";
G3dTool.Register["TubeInterp", TubeInterpCmd, interpUsage];
G3dTool.Register["NewTubeInterp", NewTubeInterpCmd, interpUsage];
END.