ImplicitSliceImpl.mesa
Copyright Ó 1985, 1990 by Xerox Corporation. All rights reserved.
Bloomenthal, August 10, 1992 5:30 pm PDT
DIRECTORY Buttons, CedarProcess, CtBasic, Commander, CommanderOps, Controls, Convert, Draw2d, FileNames, FS, G3dBasic, G3dControl, G3dMatrix, G3dTool, Icons, Imager, ImagerBackdoor, ImagerFont, ImplicitSlice, MessageWindow, Real, Rope, SF, TEditSelection, TiogaMenuOps, VFonts, ViewerClasses, ViewerOps, ViewerTools;
ImplicitSliceImpl: CEDAR PROGRAM
IMPORTS Buttons, CedarProcess, CtBasic, Commander, CommanderOps, Controls, Convert, Draw2d, FileNames, FS, G3dControl, G3dMatrix, G3dTool, Icons, Imager, ImagerBackdoor, ImagerFont, MessageWindow, Real, Rope, TEditSelection, TiogaMenuOps, VFonts, ViewerOps, ViewerTools
EXPORTS ImplicitSlice
~ BEGIN
Types
CommandProc:  TYPE ~ Commander.CommandProc;
ButtonList:    TYPE ~ Controls.ButtonList;
ClickProc:    TYPE ~ Controls.ClickProc;
Control:     TYPE ~ Controls.Control;
ControlList:    TYPE ~ Controls.ControlList;
SampleMap:   TYPE ~ CtBasic.SampleMap;
SampleMaps:   TYPE ~ CtBasic.SampleMaps;
DrawProc:    TYPE ~ Draw2d.DrawProc;
Pair:      TYPE ~ G3dBasic.Pair;
Triple:     TYPE ~ G3dBasic.Triple;
Slice:     TYPE ~ G3dControl.Slice;
Context:    TYPE ~ Imager.Context;
Function:    TYPE ~ ImplicitSlice.Function;
Pix:     TYPE ~ ImplicitSlice.Pix;
PixRep:    TYPE ~ ImplicitSlice.PixRep;
PixSequence:   TYPE ~ ImplicitSlice.PixSequence;
Tool:     TYPE ~ ImplicitSlice.Tool;
ToolRep:    TYPE ~ ImplicitSlice.ToolRep;
ROPE:     TYPE ~ Rope.ROPE;
Viewer:     TYPE ~ ViewerClasses.Viewer;
Implicit Slice Tool Creation
icon: Icons.IconFlavor ← Icons.NewIconFromFile["ImplicitSurfaces.icon", 0];
MakeTool: PUBLIC PROC [
toolName: ROPE,
functions: LIST OF Function ← NIL,
clientDraw: DrawProc ← NIL,
clientData: REF ANYNIL,
extraControls: ControlList ← NIL,
extraButtons: ButtonList ← NIL]
RETURNS [t: Tool]
~ {
t ← NEW[ToolRep];
t.clientDraw ← clientDraw;
t.clientData ← clientData;
t.slice ← G3dControl.InitSlice[proc: SliceControl, data: t];
t.slice.phi.value ← 90.0;
FOR b: ButtonList ← extraButtons, b.rest WHILE b # NIL DO b.first.row ← 1; ENDLOOP;
extraButtons ← CONS[Controls.ClickButton["Help", Help, t, 0], extraButtons];
extraButtons ← CONS[Controls.ClickButton["IP Out", IPOut, t, 0], extraButtons];
extraButtons ← CONS[Controls.ClickButton["Display-Ops", DisplayOps, t, 0], extraButtons];
extraButtons ← CONS[Controls.TextButton["MoveSlice: ","-.03", CheckValue, t, 0], extraButtons];
extraButtons ← CONS[Controls.TextButton["H: ", "80 ", CheckValue, t, 0], extraButtons];
extraButtons ← CONS[Controls.TextButton["W: ", "80 ", CheckValue, t, 0], extraButtons];
extraButtons ← CONS[Controls.ClickButton["Name", NamePix, t, 0], extraButtons];
extraButtons ← CONS[Controls.ClickButton["STOP", Stop, t, 0], extraButtons];
extraButtons ← CONS[Controls.ClickButton["StartAndMove", StartAndMove, t, 0], extraButtons];
extraButtons ← CONS[Controls.ClickButton["Start", Start, t, 0], extraButtons];
extraButtons ← CONS[Controls.ClickButton["Mode: Slice", ToggleMode, t, 0], extraButtons];
extraControls ← CONS[t.slice.size, extraControls];
extraControls ← CONS[t.slice.theta, extraControls];
extraControls ← CONS[t.slice.phi, extraControls];
extraControls ← CONS[t.slice.z, extraControls];
extraControls ← CONS[t.slice.y, extraControls];
extraControls ← CONS[t.slice.x, extraControls];
FOR f: LIST OF Function ← functions, f.rest WHILE f # NIL DO AddPix[t, f.first]; ENDLOOP;
t.renderTool ← G3dTool.MakeTool[
name: toolName,
ops: [TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE],
extraButtons: extraButtons,
extraControls: extraControls,
controlSizes: [15, 200, 60, 20, 60, 150, 150],
arcBallSize: 80,
nViews: 3,
client: [mouse: Mouse3d, destroy: Destroy, draw: Draw, data: t],
noOpen: TRUE];
t.viewer2d ← Controls.OuterViewer[mouse: Mouse2d, clientData: t, destroy: Destroy];
t.renderTool.outer.icon ← icon;
t.typescript ← t.renderTool.typescript;
t.valueViewer ← ViewerOps.CreateViewer[
flavor: $ValueViewer, paint: FALSE, info: [data: t, scrollable: FALSE, wx: 510, wy: 16, ww: 80, wh: 80, border: FALSE, parent: t.renderTool.outer]];
ViewerOps.AddProp[t.valueViewer, $CreatedInOuterViewer, $True];
ViewerOps.OpenIcon[t.renderTool.outer];
};
Destroy: Controls.DestroyProc ~ {NARROW[clientData, Tool].stop ← TRUE};
User Interaction
SliceControl: Controls.ControlProc ~ {
t: Tool ← NARROW[control.clientData];
t.pixPicked ← NIL;
G3dControl.UpdateSlice[t.slice];
IF control.whatChanged = $TypedIn OR control.mouse.button = right THEN Repaint[t, $Slice];
};
Mouse3d: Controls.MouseProc ~ {
t: Tool ← NARROW[clientData];
IF mouse.controlKey THEN {
x: G3dMatrix.Matrix ← G3dTool.GetView[viewer, t.renderTool].camera.matrix;
t.pixPicked ← t.pixes[0];
t.point ← SELECT t.mode FROM
slice => G3dMatrix.TripleFromScreenAndPlane[[mouse.pos.x, mouse.pos.y], t.slice.plane, x],
ENDCASE => t.renderTool.sprite;
IF t.pixPicked # NIL AND t.pixPicked.valueProc # NIL THEN {
t.value ← t.pixPicked.valueProc[t.point, t.clientData];
ViewerOps.PaintViewer[t.valueViewer, client, FALSE];
};
};
};
Mouse2d: Controls.MouseProc ~ {
t: Tool ~ NARROW[clientData];
IF mouse.state = up AND mouse.pos.y <= t.ySize THEN
FOR n: NAT IN [0..t.pixes.length) DO
t.pixPicked ← t.pixes[n];
IF mouse.pos.x IN [t.pixPicked.box.min.f..t.pixPicked.box.max.f] THEN {
t.point ← GetPixPoint[t, t.pixPicked, mouse.pos.x, mouse.pos.y];
Repaint[t, $PixPicked];
EXIT;
};
ENDLOOP;
};
Display
Repaint: PUBLIC PROC [tool: Tool, whatChanged: REF ANYNIL] ~ {
G3dTool.Repaint[tool.renderTool, whatChanged];
};
PaintValueViewer: ViewerClasses.PaintProc ~ {
Action: PROC ~ {
IF whatChanged = NIL THEN Draw2d.Circle[context, [size, size], size];
Draw2d.Circle[context, [size, size], radius, t.value > 0.0];
};
t: Tool ← NARROW[self.data];
size: INTEGER ← self.ww/2;
radius: REALABS[t.value]*self.ww;
Draw2d.DoWithBuffer[context, Action];
};
Draw: DrawProc ~ {
t: Tool ~ NARROW[data];
DiagramPix: PROC [pix: Pix] ~ {
IF v.index = 0 AND pix # NIL AND pix.diagramProc # NIL
THEN pix.diagramProc[context, t.point, t.clientData, whatChanged, viewer];
};
DrawSlice: PROC ~ {
IF t.mode = slice AND t.showSlice
THEN G3dControl.DrawSlice[context, t.slice, v.camera.matrix, vp];
};
v: G3dTool.View ← G3dTool.GetView[viewer, t.renderTool];
vp: G3dMatrix.Viewport ← G3dView.GetViewport[viewer];
SELECT whatChanged FROM
$Clear => Draw2d.Clear[context];
$Slice => G3dTool.Restore[context, v];
$FinishingTouches => {DiagramPix[t.pixPicked]; DrawSlice[]};
ENDCASE =>
IF t.clientDraw # NIL THEN t.clientDraw[context, t.clientData, whatChanged, viewer];
IF t.cdContext # NIL THEN context ← t.cdContext;
};
Parameters and Options
DisplayOps: ClickProc ~ {
t: Tool ← NARROW[clientData];
SELECT Controls.PopUpRequest[["Display Options"], LIST[
Controls.BoolRequest[t.showSlice, "Show Slice"]]] FROM
1 => t.showSlice ← NOT t.showSlice;
ENDCASE => RETURN;
IF Controls.GetPopUpButton[] = right THEN Repaint[t];
};
ToggleMode: ClickProc ~ {
t: Tool ← NARROW[clientData];
IF t.mode = slice
THEN {t.mode ← sprite; Buttons.ReLabel[parent, "Mode: Sprite"]}
ELSE {t.mode ← slice; Buttons.ReLabel[parent, "Mode: Slice"]};
t.renderTool.drawSprite ← t.mode = sprite;
Repaint[t];
};
doc: ROPE ← FileNames.StripVersionNumber[FS.FileInfo["ImplicitSurfacesDoc.tioga"].fullFName];
Help: ClickProc ~ {
v: Viewer ← TiogaMenuOps.Open[doc,, right];
TEditSelection.FindRope[v, "ImplicitSlice Buttons and Controls"];
};
IPOut: ClickProc ~ {
t: Tool ← NARROW[clientData];
Draw2d.IPOut[Controls.TypescriptReadFileName[t.typescript], Draw, t];
};
NamePix: ClickProc ~ {SetUpPix[NARROW[clientData], 0.5, FALSE, TRUE]};
SetParameters: PROC [t: Tool] ~ {
FOR b: LIST OF Controls.Button ← t.renderTool.buttons, b.rest WHILE b # NIL DO
E: PROC [r: ROPE] RETURNS [BOOL] ~ {RETURN[Rope.Equal[b.first.name, r, FALSE]]};
N: PROC [o: REAL] RETURNS [i: REAL] ~ {
r: ROPE ← ViewerTools.GetContents[b.first.textViewer];
i ← Convert.RealFromRope[r ! Convert.Error => {Blink["Bad value"]; i ← o; CONTINUE}];
};
SELECT TRUE FROM
E["MoveSlice: "] => t.moveSlice ← N[t.moveSlice];
E["W: "]  => t.xSize ← Real.Round[N[t.xSize]];
E["H: "]  => t.ySize ← Real.Round[N[t.ySize]];
ENDCASE;
ENDLOOP;
ResizePixes[t];
};
CheckValue: ClickProc ~ {
button: Controls.Button ← NARROW[ViewerOps.FetchProp[parent, $ButtonText]];
IF button # NIL THEN {
r: ROPE ← ViewerTools.GetContents[button.textViewer];
[] ← Convert.RealFromRope[r ! Convert.Error => {Blink["Bad value"]; CONTINUE}];
};
};
Shading
Stop: ClickProc ~ {
t: Tool ← NARROW[clientData];
t.stop ← TRUE;
Controls.TypescriptWrite[t.typescript, " . . . aborted.\n"];
};
Start: ClickProc ~ {StartShade[NARROW[clientData], Shade]};
StartAndMove: ClickProc ~ {StartShade[NARROW[clientData], ShadeAndMoveSlice]};
StartShade: PROC [t: Tool, proc: CedarProcess.ForkableProc] ~ {
t.stop ← FALSE;
SetParameters[t];
[] ← CedarProcess.Fork[proc, t, [background, TRUE]];
t.stop ← FALSE;
};
Shade: CedarProcess.ForkableProc ~ {
t: Tool ← NARROW[data];
SetUpPix[t, 0.0, TRUE, TRUE];
FOR y: NAT IN [1..t.ySize-1) DO
FOR x: NAT IN [1..t.xSize-1) DO
t.point ← GetPixPoint[t, t.pixes[0], x, y];
FOR n: NAT IN [0..t.pixes.length) DO
pix: Pix ← t.pixes[n];
value: REAL ← pix.valueProc[t.point, t.clientData];
pVal: CARDINAL ← Real.Round[MIN[255.0, MAX[0., 255.0*value]]];
xx: NAT ← x+pix.box.min.f;
yy: NAT ← y+pix.box.min.s;
IF t.stop THEN RETURN;
SELECT pix.maps.bpp FROM
8 => CtBasic.PutBWPixel[pix.maps[0].map, xx, yy, pVal];
24 => CtBasic.PutRGBPixel[pix.maps, xx, yy, [pVal, pVal, pVal]];
ENDCASE;
ENDLOOP;
ENDLOOP;
ENDLOOP;
};
ShadeAndMoveSlice: CedarProcess.ForkableProc ~ {
t: Tool ← NARROW[data];
box: SF.Box ← t.cdMaps.box;
FOR y: NAT ← box.min.s, y+t.ySize WHILE y < box.max.s DO
FOR x: NAT ← box.min.f, x+t.xSize WHILE x < box.max.f DO
FOR n: NAT IN [0..t.pixes.length) DO
IF t.stop THEN RETURN;
t.pixes[n].maps ← CtBasic.CopyOfMaps[t.cdMaps, x, y, t.xSize, t.ySize];
ENDLOOP;
[] ← Shade[t];
G3dControl.MoveSliceInZ[t.slice, t.moveSlice];
Repaint[t];
ENDLOOP;
ENDLOOP;
};
ImagerShade: CedarProcess.ForkableProc ~ {
t: Tool ← NARROW[data];
t.cdContext ← CtBasic.InitCd[gray];
Repaint[t, $Clear];
[] ← Shade[t];
t.cdContext ← CtBasic.InitCd[smooth];
Repaint[t];
t.cdContext ← NIL;
};
Pix Procs
AddPix: PROC [t: Tool, f: Function] ~ {
xStart: NATIF t.pixes # NIL THEN t.xSize*t.pixes.length ELSE 0;
pix: Pix ← NEW[PixRep];
new: REF PixSequence ← NEW[PixSequence[IF t.pixes # NIL THEN t.pixes.length+1 ELSE 1]];
FOR n: NAT IN [0..new.length-1) DO new[n] ← t.pixes[n]; ENDLOOP;
t.pixes ← new;
pix.name ← f.name;
pix.diagramProc ← f.diagramProc;
pix.valueProc ← f.valueProc;
SetPixSize[pix, xStart, 0, t.xSize, t.ySize, t.cdMaps];
t.pixes[t.pixes.length-1] ← pix;
};
SetPixSize: PROC [pix: Pix, x, y, w, h: NAT, cd: SampleMaps] ~ {
pix.maps ← CtBasic.CopyOfMaps[cd, x, y, w, h];
pix.box ← pix.maps.box;
pix.context ← CtBasic.InitCd[smooth, TRUE, FALSE, FALSE];
CtBasic.TransformContextToMap[
pix.context, SELECT pix.maps.bpp FROM 8 => pix.maps[0].map ENDCASE => pix.maps[1].map];
pix.start ← ImagerFont.RopeEscapement[ImagerBackdoor.GetFont[pix.context], pix.name];
pix.start ← [-0.5*pix.start.x, -0.9];
};
ResizePixes: PROC [t: Tool] ~ {
IF t.pixes # NIL THEN FOR n: NAT IN [0..t.pixes.length) DO
SetPixSize[t.pixes[n], n*t.xSize, 0, t.xSize, t.ySize, t.cdMaps];
ENDLOOP;
};
GetPixPoint: PROC [t: Tool, pix: Pix, x, y: NAT] RETURNS [Triple] ~ {
map: SampleMap ← IF pix.maps.bpp = 8 THEN pix.maps[0].map ELSE pix.maps[1].map;
realPair: CtBasic.RealPair ← CtBasic.PairFromMapCoords[x, y, map];
RETURN[G3dMatrix.TransformPair[[realPair.x, realPair.y], t.slice.matrix]];
};
SetUpPix: PROC [t: Tool, gray: REAL, clear, name: BOOL] ~ {
FOR n: NAT IN [0..t.pixes.length) DO
pix: Pix ← t.pixes[n];
Imager.SetGray[pix.context, gray];
Imager.SetStrokeWidth[pix.context, 0.02];
IF clear THEN CtBasic.FillMaps[pix.maps, 100, 100, 100, 100];
IF name THEN Draw2d.Label[pix.context, pix.start, pix.name];
ENDLOOP;
};
Support Procs
Blink: PROC [rope: ROPE] ~ {
MessageWindow.Append[rope, TRUE];
MessageWindow.Blink[];
};
PixelValueFromValue: PROC [value: REAL] RETURNS [CARDINAL] ~ {
RETURN[Real.Round[MIN[255.0, MAX[0.0, 255.0*value]]]];
};
ViewerCoordsFromPair: PROC [p: Pair, viewer: Viewer] RETURNS [Pair] ~ {
RETURN[[viewer.cx+0.5*viewer.cw*(s.x+1.0), viewer.cy+0.5*viewer.ch*(s.y+1.0)]];
};
PairFromViewerCoords: PROC [pos: Pos, viewer: Viewer] RETURNS [Pair] ~ {
RETURN[[REAL[pos.x+pos.x]/viewer.cw-1.0, REAL[pos.y+pos.y]/viewer.ch-1.0]];
};
Registration and Dispatching
Registration: TYPE ~ RECORD [
name:     ROPE,        -- name of option
command:   CommandProc,     -- proc to be called
doc:     ROPE        -- documentation of option
];
registry:  LIST OF Registration ← NIL;
font:   VFonts.Font ~ VFonts.EstablishFont["Tioga", 10];
tabWidth:  INT ← 2*VFonts.StringWidth["\t"];  -- VFonts says 12; but should be 24
toolOptions: ROPENIL;
toolUsage:  ROPE ← "ImplicitSlice <option | ?>";
Register: PUBLIC PROC [name: ROPE, command: CommandProc, doc: ROPE] ~ {
colonTabs: ROPE ← ":";
nTabs: INT ← 2+MAX[84-VFonts.StringWidth[Rope.Cat[name, ":"]], 0]/tabWidth;
FOR n: INT IN [1..nTabs] DO colonTabs ← Rope.Concat[colonTabs, "\t"]; ENDLOOP;
FOR l: LIST OF Registration ← registry, l.rest WHILE l # NIL DO
IF NOT Rope.Equal[l.first.name, name, FALSE] THEN LOOP;
l.first ← [name, command, doc];
RETURN;
ENDLOOP;
registry ← CONS[[name, command, doc], registry];
toolOptions ← Rope.Cat[toolOptions, "\n\t", name, colonTabs, doc];
};
ToolOptions: PUBLIC PROC RETURNS [ROPE] ~ {RETURN[toolOptions]};
ExecuteOption: PUBLIC CommandProc ~ {
argv: CommanderOps.ArgumentVector ← CommanderOps.Parse[cmd];
IF argv.argc > 1 THEN SELECT TRUE FROM
Rope.Equal[argv[1], "reset", FALSE] => {
registry ← NIL;
toolOptions ← NIL;
};
ENDCASE => {
FOR l: LIST OF Registration ← registry, l.rest WHILE l # NIL DO
IF Rope.Equal[l.first.name, argv[1], FALSE] THEN {
[result, msg] ← l.first.command[cmd];
RETURN;
};
ENDLOOP;
RETURN[$Failure, "No such option."];
};
};
ImplicitSliceCmd: CommandProc ~ {
argv: CommanderOps.ArgumentVector ← CommanderOps.Parse[cmd];
IF argv.argc < 2 THEN RETURN[$Failure, toolUsage];
SELECT TRUE FROM
Rope.Equal[argv[1], "?"] =>
RETURN[$Failure, Rope.Cat["ImplicitSlice <option>, options include:\n", toolOptions]];
ENDCASE => [result, msg] ← ExecuteOption[cmd];
};
Start Code
ViewerOps.RegisterViewerClass[
$ValueViewer, NEW[ViewerClasses.ViewerClassRec ← [paint: PaintValueViewer]]];
Commander.Register["ImplicitSlice", ImplicitSliceCmd, toolUsage];
END.