TubeCommandsImpl:
CEDAR
PROGRAM
IMPORTS Commander, Controls, Controls3d, Draw2d, Draw3d, FileNames, Icons, IO, Real, Spline3d, TubeDisplay, TubeIO, TubePick, TubeStructure, Vector3d, ViewerOps
~ BEGIN
OPEN TubeDefs;
ActionType: TYPE ~ {none, select, camera, spline, shape, button};
ProgramData: TYPE ~ REF ProgramDataRec;
ProgramDataRec:
TYPE ~
RECORD [
out: IO.STREAM ← NIL,
wDir: Rope.ROPE ← NIL,
outer, graphics: Controls.Viewer ← NIL,
mouse, mousePrev: Mouse ← [0, 0, none, left],
entries: LIST OF Controls.Entry ← NIL,
cam: Controls3d.Camera, -- camera
hold: Controls3d.Hold, -- handle on a point and its tangent
twist0: ControlData ← NIL, -- twist 0
twist1: ControlData ← NIL, -- twist 1
r0: ControlData ← NIL, -- radius 0
r1: ControlData ← NIL, -- radius 1
scal: ControlData ← NIL, -- scale
eps: ControlData ← NIL, -- spline flatness value
cres: ControlData ← NIL, -- circ. resolution
lim: ControlData ← NIL, -- vector limit
graphicsData: GraphicsData ← NIL,
view: Matrix ← NIL,
xmats: MatrixSeq ← NIL,
tube: Tube ← NIL, -- all the tube splines
pick: Pick ← NIL,
action: ActionType ← none,
details: Details ← NIL,
circle: PairSequence ← NIL,
noDraw: BOOL ← FALSE
];
TubeCommand: Commander.CommandProc ~ {
d: ProgramData ← NEW[ProgramDataRec ← [out: cmd.err]];
Spline3d.DebugStream[cmd.out];
InitProgramData[d];
MakeDetails[d];
InitViewer[d];
};
InitProgramData:
PROC [d: ProgramData] ~ {
d.wDir ← FileNames.CurrentWorkingDirectory[];
d.pick ← NEW[PickRec];
d.view ← NEW[MatrixRep];
d.tube ← NEW[TubeRec ← [p0: [-0.5,0.,0.], p1: [0.5,0.,0.], v0: [1.,1.,0.], v1: [1.,1.,0.]]];
d.cam ← Controls3d.InitCamera[dz: 0.5, zoom: 3., fov: 0., proc: Controller, data: d];
d.hold ← Controls3d.InitHold[Controller, d];
d.twist0 ← Controls.NewControl["tw0", vert, , -1000., 1000., 0.0, , , , Controller, d];
d.twist1 ← Controls.NewControl["tw1", vert, , -1000., 1000., 0.0, , , , Controller, d];
d.r0 ← Controls.NewControl["r0", vert, , 0.0, 0.5, 0.0, , , , Controller, d];
d.r1 ← Controls.NewControl["r1", vert, , 0.0, 0.5, 0.0, , , , Controller, d];
d.scal ← Controls.NewControl["scal", vert, , 0.0, 4.0, 1.0, , , , Controller, d];
d.eps ← Controls.NewControl["eps", vert, , 0.001, 0.1, 0.03, , , , Controller, d];
d.cres ← Controls.NewControl["cres", vert, , 3.0, 15.0, 6.0, , TRUE, , Controller, d];
d.lim ← Controls.NewControl["lim", vert, , 0.0, 1000.0, 500.0, , TRUE, , Controller, d];
(d.pick.tube ← d.tube).c ← Spline3d.CoeffsFromHermite[[d.tube.p0, d.tube.v0, d.tube.p1, d.tube.v1]];
d.details ← NEW[DetailsRec];
TubePick.PointPick[d.pick];
};
InitViewer:
PROC [d: ProgramData] ~ {
Controls.ControlRow[d.twist0, 2];
Controls.ControlRow[d.cam.pan, 3];
d.outer ← Controls.OuterViewer[
name: "Tube",
column: left,
entries:
LIST[
[name: "Help", proc: Help, row: 0],
[name: "Auto-On", proc: TogAuto, row: 0],
[name: "Label-On", proc: TogLabel, row: 0],
[name: "Max-Out", proc: MaxPointsPolyOut, row: 0],
[name: "Poly-Out", proc: PointsPolyOut, row: 0],
[name: "IP-out", proc: IPOut, row: 0],
[name: "Skel-Off", proc: TogSkel, row: 1],
[name: "Pick-On", proc: TogPick, row: 1],
[name: "Splines-On", proc: TogSpline, row: 1],
[name: "Circles-Off", proc: TogCircles, row: 2],
[name: "Lines-Off", proc: TogLines, row: 2],
[name: "Frames-Off", proc: TogFrames, row: 2],
[name: "Normals-Off", proc: TogNormals, row: 2],
[name: "Curv-Off", proc: TogCurv, row: 2],
[name: "Vel-Off", proc: TogVel, row: 2],
[name: "Acc-Off", proc: TogAcc, row: 2]],
controls:
LIST[
d.hold.dx, d.hold.dy, d.hold.dz, d.hold.lng, d.hold.lat, d.hold.mag,
d.twist0, d.twist1, d.r0, d.r1, d.scal, d.eps, d.cres, d.lim,
d.cam.pan, d.cam.tilt, d.cam.roll, d.cam.zoom, d.cam.dx, d.cam.dy, d.cam.dz, d.cam.fov],
typeScript: TRUE,
graphicsHeight: 300,
graphicsProc: ScreenPick,
graphicsShow: Display,
data: d,
noOpen: TRUE];
d.entries ← NARROW[d.outer.data, Controls.OuterData].entries;
d.graphics ← NARROW[d.outer.data, Controls.OuterData].graphics;
d.graphicsData ← NARROW[d.graphics.data];
d.outer.icon ← Icons.NewIconFromFile["Tube.icon", 0];
Controls3d.FocusHold[d.pick.tan, d.hold];
ViewerOps.OpenIcon[d.outer];
};
Display: Controls.GraphicsShow ~ {
d: ProgramData ← NARROW[data];
Action:
PROC ~ {
d.view ← Controls3d.InitPix[context, w, h, d.view];
IF d.details.spline THEN TubeDisplay.ShowSplineEnds[d.tube, context, d.view];
TubeDisplay.ShowTube[d.tube, context, d.details, d.view];
IF d.details.pick
THEN Draw3d.
PV[d.pick.pos, d.pick.tan, , context, d.view,
IF d.pick.t IN (0.0..1.0) THEN cross ELSE none];
};
IF whatChanged # NIL AND d.noDraw THEN RETURN;
IF TubeDisplay.NVectors[d.tube, d.details] < d.lim.val
THEN Draw2d.DoWithBuffer[context, Action, w, h]
ELSE Draw2d.DoNoBuffer[context, Action, w, h];
};
Controller: Controls.ControlProc ~ {
Proc called as result of any slider or dial manipulation.
d: ProgramData ← NARROW[control.data];
MouseAction[d, control.mouse, control];
IF
NOT d.noDraw
THEN {
d.details.on ← NOT d.details.auto OR d.action = shape OR d.mouse.state # held;
IF d.action = spline
AND d.pick.dividePending
THEN {
TubePick.DivideSpline[d.pick];
Controls.ControlVal[d.hold.mag, Vector3d.Mag[d.pick.tubePt0.v1]];
};
SELECT control
FROM
d.scal => MakeDetails[d];
d.r0, d.r1 => ChangeRadii[d];
d.twist0 => ChangeTwist0[d];
d.twist1 => ChangeTwist1[d];
d.cres => TubeStructure.PropagateCircleRes[d.tube, Real.RoundI[d.cres.val]];
d.eps => MakeDetails[d];
d.hold.dx, d.hold.dy, d.hold.dz => ChangePosition[d];
d.hold.lng, d.hold.lat, d.hold.mag => ChangeTangent[d];
d.cam.pan, d.cam.tilt, d.cam.roll, d.cam.zoom, d.cam.dx, d.cam.dy, d.cam.dz, d.cam.fov => Controls3d.SetCamera[d.cam];
ENDCASE => NULL;
};
ViewerOps.PaintViewer[control.graphics, client, FALSE, control];
};
MakeDetails:
PROC [d: ProgramData] ~ {
TubeStructure.PropagateFrames[d.tube, d.scal.val, d.eps.val];
};
ChangePosition:
PROC [d: ProgramData] ~ {
TubePick.ChangePosition[d.pick, [d.hold.dx.val, d.hold.dy.val, d.hold.dz.val]];
IF d.details.on THEN MakeDetails[d];
};
ChangeTangent:
PROC [d: ProgramData] ~ {
v: Triple ← Vector3d.CartesianFromPolar[[d.hold.lng.val, d.hold.lat.val, d.hold.mag.val]];
TubePick.ChangeTangent[d.pick, v];
IF d.details.on THEN MakeDetails[d];
};
ChangeRadii:
PROC [d: ProgramData] ~ {
r, dr: REAL;
n: NAT ← TubePick.NumberPicked[d.pick];
IF n = 0 THEN RETURN;
r ← d.r0.val;
dr ← (d.r1.val-r)/REAL[n];
IF d.pick.tubePick0.prev # NIL THEN d.pick.tubePick0.prev.r1 ← r;
FOR s: Tube ← d.pick.tubePick0, s.next
WHILE s #
NIL
AND s # d.pick.tubePick1.next
DO
s.r0 ← r;
r ← r+dr;
s.r1 ← r;
ENDLOOP;
IF d.pick.tubePick1.next # NIL THEN d.pick.tubePick1.next.r0 ← r;
TubePick.RemakePicked[d.pick, d.scal.val, d.eps.val];
};
ChangeTwist0:
PROC [d: ProgramData] ~ {
nBefore: NAT ← TubePick.BeforePicked[d.pick];
change: REAL ← d.twist0.val-d.twist0.preval;
IF nBefore > 0
THEN {
dchange: REAL ← 0.0;
ddchange: REAL ← change/REAL[nBefore];
FOR s: Tube ← d.tube, s.next
WHILE s # d.pick.tubePick0
DO
s.twist0 ← s.twist0+dchange;
dchange ← dchange+ddchange;
s.twist1 ← s.twist1+dchange;
ENDLOOP;
};
FOR s: Tube ← d.pick.tubePick0, s.next
WHILE s #
NIL
DO
s.twist0 ← s.twist0+change;
s.twist1 ← s.twist1+change;
ENDLOOP;
IF d.pick.tubePick1 #
NIL
THEN Controls.ControlVal[d.twist1, d.pick.tubePick1.twist1];
IF d.details.on THEN MakeDetails[d];
};
ChangeTwist1:
PROC [d: ProgramData] ~ {
nPicked: NAT ← TubePick.NumberPicked[d.pick];
change: REAL ← d.twist1.val-d.twist1.preval;
IF nPicked > 0
THEN {
dchange: REAL ← 0.0;
ddchange: REAL ← change/REAL[nPicked];
FOR s: Tube ← d.pick.tubePick0, s.next
WHILE s # d.pick.tubePick1.next
DO
s.twist0 ← s.twist0+dchange;
dchange ← dchange+ddchange;
s.twist1 ← s.twist1+dchange;
ENDLOOP;
};
IF d.pick.tubePick1 #
NIL
THEN
FOR s: Tube ← d.pick.tubePick1.next, s.next
WHILE s #
NIL
DO
s.twist0 ← s.twist0+change;
s.twist1 ← s.twist1+change;
ENDLOOP;
IF d.details.on THEN MakeDetails[d];
};
ScreenPick: Controls.GraphicsProc ~ {
Proc called as result of mousing down in graphics viewer.
d: ProgramData ← NARROW[graphics.data];
MouseAction[d, graphics.mouse, graphics];
IF d.mouse.state = up THEN RETURN;
TubePick.ScreenPick[d.tube, d.mouse, d.view, d.pick];
IF d.mouse.button = left THEN Controls3d.FocusHold[d.pick.tan, d.hold];
FocusPick[d];
};
FocusPick:
PROC [d: ProgramData] ~ {
adjust controls to selected splines settings:
IF d.pick.tubePick0 #
NIL
THEN {
Controls.ControlVal[d.r0, d.pick.tubePick0.r0];
Controls.ControlVal[d.twist0, d.pick.tubePick0.twist0];
};
IF d.pick.tubePick1 #
NIL
THEN {
Controls.ControlVal[d.r1, d.pick.tubePick1.r1];
Controls.ControlVal[d.twist1, d.pick.tubePick1.twist1];
};
Controls3d.PaintControls[d.lng, d.lat, d.mag];
};
MouseAction:
PROC [d: ProgramData, mouse: Mouse, whatChanged:
REF
ANY] ~ {
wasDown: BOOL ← d.mouse.state = down;
d.mousePrev ← d.mouse;
d.mouse ← mouse;
d.action ←
SELECT whatChanged
FROM
d.entries => button,
d.graphicsData => select,
d.cam.roll, d.cam.pan, d.cam.tilt, d.cam.zoom, d.cam.fov => camera,
d.cam.dx, d.cam.dy, d.cam.dz => camera,
d.hold.dx, d.hold.dy, d.hold.dz, d.hold.lng, d.hold.lat, d.hold.mag => spline,
d.twist0, d.twist1, d.r0, d.r1, d.scal, d.cres => shape,
ENDCASE => none;
d.noDraw ← d.mouse.state = up AND wasDown AND d.action # button AND d.details.on;
Controls.TypeScriptClear[NARROW[d.outer.data, Controls.OuterData]];
};
Toggle:
PROC [clientData:
REF
ANY, type: DetailType, trueName, falseName: Rope.
ROPE] ~ {
outer: OuterData ← NARROW[clientData];
d: ProgramData ← NARROW[outer.data];
TubeDisplay.ToggleDetail[d.details, type, trueName, falseName, outer];
MouseAction [d, [0, 0, up, left], d.entries];
MakeDetails[d];
ViewerOps.PaintViewer[d.graphics, client, FALSE, d.entries];
};
TogLabel: Controls.ClickProc ~ {Toggle[clientData, label, "Label-On", "Label-Off"]};
TogAuto: Controls.ClickProc ~ {Toggle[clientData, auto, "Auto-On", "Auto-Off"]};
TogSkel: Controls.ClickProc ~ {Toggle[clientData, skel, "Skel-On", "Skel-Off"]};
TogPick: Controls.ClickProc ~ {Toggle[clientData, pick, "Pick-On", "Pick-Off"]};
TogSpline: Controls.ClickProc ~ {Toggle[clientData, spline, "Splines-On", "Splines-Off"]};
TogCircles: Controls.ClickProc ~ {Toggle[clientData, circles, "Circles-On", "Circles-Off"]};
TogLines: Controls.ClickProc ~ {Toggle[clientData, lines, "Lines-On", "Lines-Off"]};
TogFrames: Controls.ClickProc ~ {Toggle[clientData, frames, "Frames-On", "Frames-Off"]};
TogNormals: Controls.ClickProc ~ {Toggle[clientData, normals, "Normals-On", "Normals-Off"]};
TogCurv: Controls.ClickProc ~ {Toggle[clientData, curv, "Curv-On", "Curv-Off"]};
TogVel: Controls.ClickProc ~ {Toggle[clientData, vel, "Vel-On", "Vel-Off"]};
TogAcc: Controls.ClickProc ~ {Toggle[clientData, acc, "Acc-On", "Acc-Off"]};
IPOut: Controls.ClickProc ~ {
outer: Controls.OuterData ← NARROW[clientData];
d: ProgramData ← NARROW[outer.data];
TubeIO.QueryAndPrintTube[d.tube, d.details, d.view, d.wDir, outer];
};
PointsPolyOut: Controls.ClickProc ~ {
outer: Controls.OuterData ← NARROW[clientData];
d: ProgramData ← NARROW[outer.data];
TubeIO.QueryAndPointsPolyOut[d.tube, d.wDir, outer];
};
MaxPointsPolyOut: Controls.ClickProc ~ {
outer: Controls.OuterData ← NARROW[clientData];
d: ProgramData ← NARROW[outer.data];
TubeIO.QueryAndMaxPointsPolyOut[d.tube, d.wDir, outer];
};
Help: Controls.ClickProc ~ {
d: ProgramData ← NARROW[NARROW[clientData, Controls.OuterData].data];
helpMessage: Rope.ROPE ← "
Mouse use:
any button to manipulate sliders or dials
left button to select a point on a spline
middle button to select an initial spline
right button to select an ending spline
General approach:
use top row of controls to adjust viewing parameters
use middle row to control selected splines
use bottom row to control selected point location and tangent\n";
IO.PutF[d.out, helpMessage];
};
Commander.Register["///Commands/Tube", TubeCommand, "\nModel tubular structures."];
END.
..