ImplicitOctreeImpl.mesa
Copyright Ó 1985, 1990 by Xerox Corporation. All rights reserved.
Bloomenthal, February 26, 1993 3:06 pm PST
DIRECTORY Atom, BasicTime, CedarProcess, Commander, CommanderOps, Controls, Convert, Draw2d, FileNames, FS, G2dBasic, G2dVector, G3dBasic, G3dCubeDraw, G3dDraw, G3dMatrix, G3dOctree, G3dRayCube, G3dRayTrace, G3dRayTraceTool, G3dRender, G3dShade, G3dShape, G3dTool, G3dVector, G3dView, Icons, Imager, ImplicitDefs, ImplicitOctree, ImplicitDraw, ImplicitPolygons, ImplicitPoints, ImplicitRayTrace, ImplicitSurface, IO, MessageWindow, PFS, ProcessProps, Rope, TEditSelection, TiogaMenuOps, VFonts, ViewerClasses, ViewerOps;
ImplicitOctreeImpl: CEDAR PROGRAM
IMPORTS Atom, BasicTime, CedarProcess, Commander, CommanderOps, Controls, Convert, Draw2d, FileNames, G2dVector, G3dCubeDraw, G3dDraw, G3dMatrix, G3dOctree, G3dShade, G3dRayCube, G3dRayTrace, G3dRayTraceTool, G3dShape, G3dTool, G3dVector, Icons, Imager, ImplicitDraw, ImplicitPolygons, ImplicitPoints, ImplicitRayTrace, ImplicitSurface, IO, MessageWindow, PFS, ProcessProps, Rope, TEditSelection, TiogaMenuOps, VFonts, ViewerOps
EXPORTS ImplicitOctree
~ BEGIN
Types
ForkableProc:  TYPE ~ CedarProcess.ForkableProc;
CommandProc:  TYPE ~ Commander.CommandProc;
ButtonList:   TYPE ~ Controls.ButtonList;
ClickProc:   TYPE ~ Controls.ClickProc;
Triple:    TYPE ~ G3dBasic.Triple;
Matrix:    TYPE ~ G3dMatrix.Matrix;
Cube:     TYPE ~ G3dOctree.Cube;
RayData:    TYPE ~ G3dRayTrace.RayData;
DistanceMode:  TYPE ~ ImplicitDefs.DistanceMode;
EdgeMode:   TYPE ~ ImplicitDefs.EdgeMode;
StartProc:    TYPE ~ ImplicitDefs.StartProc;
Tool:     TYPE ~ ImplicitOctree.Tool;
ToolRep:    TYPE ~ ImplicitOctree.ToolRep;
ROPE:     TYPE ~ Rope.ROPE;
Viewer:    TYPE ~ ViewerClasses.Viewer;
ImplicitOctree Tool
icon: Icons.IconFlavor ¬ Icons.NewIconFromFile["ImplicitSurfaces.icon", 0];
gtool: Tool;
MakeTool: PUBLIC PROC [
name:    ROPE,
valueProc:  ImplicitDefs.ValueProc,
ops:    G3dTool.Operations ¬ G3dTool.allOps,
extraButtons:  ButtonList ¬ NIL,
extraControls: Controls.ControlList ¬ NIL,
controlSizes:  Controls.ControlSizes ¬ [],
useArcBalls:  BOOL ¬ TRUE,
arcBallSize:  INT ¬ 136,
client:    G3dTool.Client ¬ [],
graphicsHeight: INT ¬ 475,
background:  Triple ¬ [0.3, 0.3, 1.0],
noOpen:   BOOL ¬ FALSE,
startProc:   StartProc ¬ NIL,
cubeOkProc:  ImplicitDefs.CubeOkProc ¬ NIL,
vertexOkProc: ImplicitDefs.VertexOkProc ¬ NIL,
polygonOkProc: ImplicitDefs.PolygonOkProc ¬ NIL,
normalProc:  ImplicitDefs.NormalProc ¬ NIL,
colorProc:   ImplicitDefs.ColorProc ¬ NIL,
textureProc:  ImplicitDefs.TextureProc ¬ NIL,
rayProc:   G3dRayTrace.RayProc ¬ NIL,
docProc:   ImplicitDefs.DocProc ¬ NIL,
camera:   G3dView.CameraRep ¬ [[0.0, 2.0, 0.0], [], 1.0, 60.0],
nViews:   NAT ¬ 1,
toolSettings:  ToolRep ¬ []]
RETURNS [t: Tool]
~ {
AddButton: PROC [name: ROPE, proc: ClickProc, guarded: BOOL ¬ FALSE] ~ {
extraButtons ¬ CONS[Controls.ClickButton[name, proc, t, 1,,,,,, guarded], extraButtons];
};
cmd: Commander.Handle ¬ NARROW[ProcessProps.GetProp[$CommanderHandle]];
ref: REF ANY ¬ CommanderOps.GetProp[cmd, $Tool];
calledByMakeSurface: BOOL ¬ ref # NIL;
showTool: BOOL ¬ CommanderOps.GetProp[cmd, $ShowTool] # NIL;
t ¬ IF calledByMakeSurface THEN NARROW[ref] ELSE NEW[ToolRep ¬ toolSettings];
IF NOT calledByMakeSurface THEN { -- call originated with ImplicitOctree command
FOR l: ButtonList ¬ extraButtons, l.rest WHILE l # NIL DO
l.first.row ¬ MAX[2, l.first.row];
ENDLOOP;
AddButton["Flat", FlatnessButton];
AddButton["Octree", OctreeButton];
AddButton["HLE", HLEButton];
AddButton["RayTrace", RayTraceButton];
};
t.startProc ¬ startProc;
IF valueProc # NIL THEN t.valueProc ¬ valueProc;
IF cubeOkProc # NIL THEN t.cubeOkProc ¬ cubeOkProc;
IF vertexOkProc # NIL THEN t.vertexOkProc ¬ vertexOkProc;
IF polygonOkProc # NIL THEN t.polygonOkProc ¬ polygonOkProc;
IF normalProc # NIL THEN t.normalProc ¬ normalProc;
IF textureProc # NIL THEN t.textureProc ¬ textureProc;
IF colorProc # NIL THEN t.colorProc ¬ colorProc;
t.rayData ¬ NEW[G3dRayTrace.RayDataRep];
IF rayProc # NIL THEN t.rayProc ¬ rayProc;
t.rayData.clientData ¬ t;
t.rayData.finishProc ¬ RayTraceFinish;
IF docProc # NIL THEN t.docProc ¬ docProc;
t.client ¬ client;
gtool ¬ t;
IF NOT calledByMakeSurface OR showTool THEN {
t.tool3d ¬ G3dTool.MakeTool[
name: name,
nViews: nViews,
ops: ops,
extraButtons: extraButtons,
extraControls: extraControls,
controlSizes: controlSizes,
client: [data: t, draw: Draw, mouse: Mouse, camera: Camera, animate: Animate, stop: Stop, destroy: Destroy, change: Change],
useArcBalls: useArcBalls,
arcBallSize: arcBallSize,
graphicsHeight: graphicsHeight,
background: background,
icon: icon,
camera: camera];
IF toolSettings = [] THEN SetToolFromLog[t, name];
};
};
Camera: Controls.ControlProc ~ {
tool: Tool ¬ NARROW[clientData];
IF tool.client.camera # NIL THEN tool.client.camera[control, tool.client.data];
};
Change: G3dTool.ChangeProc ~ {
tool: Tool ¬ NARROW[clientData];
IF tool.client.change # NIL THEN tool.client.change[lastTool, activeTool, tool.client.data];
};
Destroy: Controls.DestroyProc ~ {
tool: Tool ¬ NARROW[clientData];
tool.destroyed ¬ TRUE;
IF tool.client.destroy # NIL THEN tool.client.destroy[viewer, reason, tool.client.data];
};
Mouse: Controls.MouseProc ~ {
m: G2dBasic.Pair ¬ [mouse.pos.x, mouse.pos.y];
nx, ny: G2dBasic.NearSegment;
tool: Tool ¬ NARROW[clientData];
view: Matrix ¬ G3dTool.GetView[NIL, tool.tool3d].camera.matrix;
r: RayData ¬ tool.rayData;
p: ARRAY[0..4) OF G2dBasic.Pair;
t: ARRAY[0..4) OF Triple;
[t[0], t[1], t[2], t[3]] ¬ G3dRayTrace.RayImageScreenCorners[r];
FOR n: NAT IN [0..4) DO p[n] ¬ G3dMatrix.TransformD[t[n], view]; ENDLOOP;
nx ¬ G2dVector.NearestToSegment[p[0], p[1], m];
ny ¬ G2dVector.NearestToSegment[p[1], p[2], m];
MessageWindow.Append[IO.PutFR["pixel (%g, %g)", IO.real[r.x+nx.w0*r.w], IO.real[r.y+ny.w0*r.h]], TRUE];
IF tool.client.mouse # NIL THEN tool.client.mouse[mouse, viewer, tool.client.data];
};
doc: ROPE ¬ "/PCedar/Documentation/ImplicitSurfacesDoc.tioga";
HelpButton: ClickProc ~ {
v: Viewer ¬ TiogaMenuOps.Open[doc,, right];
TEditSelection.FindRope[v, "Buttons and Controls"];
};
Tool Control
ToolBusy: PUBLIC PROC [tool: Tool] RETURNS [BOOL] ~ {
RETURN[G3dTool.ToolBusy[tool.tool3d]];
};
MaybeFork: PUBLIC PROC [tool: Tool, proc: ForkableProc] RETURNS [forked: BOOL] ~ {
RETURN[G3dTool.MaybeFork[tool.tool3d, proc, tool]];
};
Stop: G3dTool.StopProc ~ {StopTool[NARROW[clientData], reason]};
StopTool: PUBLIC PROC [tool: Tool, reason: ROPE ¬ NIL, waitTilAborted: BOOL ¬ FALSE] ~ {
G3dTool.Stop[tool.tool3d, reason, waitTilAborted];
IF tool.client.stop # NIL THEN tool.client.stop[tool.client.data, reason];
};
Display
radius:  REAL ¬ 0.002;
trick, reset: BOOL ¬ FALSE;
type:   Draw2d.DrawType ¬ solid;
Repaint: PUBLIC PROC [tool: Tool, whatChanged: REF ANY ¬ NIL] ~ {
G3dTool.Repaint[tool.tool3d, whatChanged, IF tool.drawOctree THEN single ELSE default];
};
Draw: G3dTool.DrawProc ~ {
DrawClient: PROC ~ {
IF t.client.draw # NIL
THEN t.client.draw[context, viewer, whatChanged, view, vp, v, tool, t.client.data];
};
DrawOctree: PROC ~ {
Inner: G3dOctree.CubeProc ~ {
IF ImplicitPoints.IsCrossed[cube ! ImplicitPoints.ValueNotSet => CONTINUE]
THEN G3dCubeDraw.SimpleCube[context, cube, view, vp, FALSE, solid];
};
IF whatChanged = $IPOut THEN Imager.SetGray[context, .65];
IF t.octree # NIL THEN G3dOctree.ApplyToTerminal[t.octree.root, Inner];
Imager.SetGray[context, 1.0];
};
DrawRoots: PROC ~ {
Imager.SetStrokeWidth[context, 1.5];
IF t.roots # NIL THEN FOR n: NAT IN [0..t.roots.length) DO
G3dCubeDraw.SimpleCube[context, t.roots[n], view, vp,, dashed];
ENDLOOP;
};
DrawAge: PROC ~ {
IF t.cubes # NIL THEN {
dgray: REAL ~ 1.0/REAL[2+t.cubes.length];
Imager.SetStrokeWidth[context, 4.0];
G3dCubeDraw.SimpleCube[context, t.cubes[0], view, vp,, dashed];
Imager.SetStrokeWidth[context, 1.5];
FOR n: NAT IN [1..t.cubes.length) DO
gray: REAL ¬ 1.0-0.75*REAL[n]/REAL[t.cubes.length];
Imager.SetGray[context, gray];
G3dCubeDraw.SimpleCube[context, t.cubes[n], view, vp,, solid];
ENDLOOP;
};
};
DrawPlayback: PROC ~ {
A: ImplicitPolygons.PolygonProc ~{ImplicitDraw.DrawPolygon[context, t.surface, polygon]};
inv: Matrix ¬ G3dMatrix.Invert[view];
IF t.cubes # NIL THEN
FOR n: NAT IN [0..t.cubes.length) DO
G3dCubeDraw.SimpleCube[context, t.cubes[n], view, vp];
ENDLOOP;
IF t.tool3d.shapes # NIL AND t.tool3d.shapes[0].vertices # NIL THEN
FOR n: NAT IN [0..t.tool3d.shapes[0].vertices.length) DO
pt: Triple ¬ t.tool3d.shapes[0].vertices[n].point;
r: REAL ¬ G3dDraw.ScreenRadiusFromSphere[[pt, radius], view, inv, vp];
Draw2d.Circle[context, G3dMatrix.TransformD[pt, view], r, TRUE];
ENDLOOP;
ImplicitPolygons.ApplyToSurfacePolygons[t.surface, A];
};
t: Tool ¬ NARROW[clientData];
IF v # NIL AND v.index = 0
THEN
SELECT whatChanged FROM
NIL, $IPOut, $NoClear, $Camera, $Scene => {
ImplicitPoints.SetVertexScreenCoordsInvalid[t.surface];
IF t.drawOctree THEN DrawOctree[];
IF t.drawOctree AND t.drawRoots
THEN Imager.SetStrokeWidth[context, 0.75];
IF t.drawAge THEN DrawAge[];
IF t.drawRoots THEN DrawRoots[];
DrawClient[];
IF t.showRayScreen THEN {
G3dRayTrace.DrawRayImageScreen[context, t.rayData, view, vp];
IF t.rayData.lights # NIL THEN FOR n: NAT IN [0..t.rayData.lights.length) DO
G3dDraw.Vector[context, t.rayData.eyePoint, t.rayData.lights[n].direction, view, vp, IO.PutFR1["LVec%g", IO.int[n]]];
ENDLOOP;
};
};
$Clear => Draw2d.Clear[context];
$Client => {Draw2d.Clear[context]; DrawClient[]};
$HLE=> G3dDraw.Segment[context, t.hleSegment.p0, t.hleSegment.p1, view, vp];
$HLEOctree => {t.context ¬ context; [] ¬ MaybeFork[t, HLEDrawOctree]};
$NewRay =>
IF t.showRays THEN G3dRayTrace.DrawRayTip[context, t.rayData, view, vp];
$Playback => DrawPlayback[];
$NewTriangle => {
tri: ImplicitOctree.Triangle ¬ t.currentTriangle;
G3dDraw.SetColor[context, [0.0, 0.7, 0.7]];
G3dDraw.Triangle[context, tri.p1, tri.p2, tri.p3, view, vp];
};
ENDCASE =>
ImplicitDraw.DiagramProgress[context, t.surface, whatChanged, IF t.currentCube # NIL THEN t.currentCube.refAny ELSE NIL, view, vp, t.currentCube,
t.drawOctree, TRUE, t.drawRoots]
ELSE SELECT whatChanged FROM
NIL, $IPOut, $NoClear, $Camera, $Scene, $Client => DrawClient[];
ENDCASE;
};
HLEDrawOctree: ForkableProc ~ {
t: Tool ¬ NARROW[data];
v: G3dTool.View ¬ G3dTool.GetView[NIL, t.tool3d];
G3dCubeDraw.HLEOctree[t.context, t.octree.root, v.camera.matrix, v.viewport];
};
Ray Tracing
RayTraceButton: ClickProc ~ {
t: Tool ¬ NARROW[clientData];
G3dRayTraceTool.RayTraceOptions[t.rayData, t.tool3d.typescript, DoRayTrace, t];
IF Controls.GetPopUpButton[] = right THEN Repaint[t];
};
RayTraceFinish: G3dRayTrace.ClientProc ~ {
t: Tool ¬ NARROW[clientData];
TSWrite[t, IO.PutFR1["Ray tracing finished at %g\n", IO.rope[Convert.RopeFromTime[BasicTime.Now[]]]]];
G3dTool.Finish[t.tool3d, "raytracing done"];
};
DoRayTrace: PROC [clientData: REF ANY] ~ {RayTrace[NARROW[clientData]]};
RayTrace: PUBLIC PROC [tool: Tool] ~ {
IF ToolBusy[tool]
THEN TSWrite[tool, "Tool is busy!\n"]
ELSE {
IF tool.octree = NIL
THEN TSWrite[tool, "First, need octree.\n"]
ELSE {
TSWrite[tool, IO.PutFR1["Ray tracing begun at %g\n", IO.rope[Convert.RopeFromTime[BasicTime.Now[]]]]];
G3dRayTrace.StartRayTracing[tool.rayData];
tool.tool3d.process ¬ tool.rayData.process;
};
};
};
ImplicitRayTraceProc: G3dRayTrace.RayProc ~ {
IntersectOctree: PROC [r:G3dBasic.Ray, o:G3dOctree.Octree] RETURNS [G3dRayTrace.RGB] ~ {
i: G3dOctree.Intersection ¬ G3dRayCube.IntersectRayWithCube[r, o.root];
RETURN[IF i.type = empty THEN [0.0, 0.0, 0.0] ELSE [1.0, 1.0, 1.0]];
};
t: Tool ¬ NARROW[clientData];
r: RayData ¬ t.rayData;
IF r.nextPixel.x = r.x THEN
MessageWindow.Append[IO.PutFR1["Starting line %g", IO.int[r.nextPixel.y]], TRUE];
IF t.showRays THEN Repaint[t, $NewRay];
SELECT TRUE FROM
r.traceOctree   => RETURN[IntersectOctree[ray, t.octree]];
t.rayProc # NIL  => RETURN[t.rayProc[ray, t.client.data]];
t.valueProc = NIL => RETURN[IntersectOctree[ray, t.octree]];
ENDCASE    => {
s: ImplicitRayTrace.SurfacePoint ¬
ImplicitRayTrace.RayAtSurface[ray, t.octree, t.valueProc, t.threshold,, t.client.data];
SELECT TRUE FROM
s.point = [] => rgb ¬ [0.0, 0.0, 0.0];
r.noShading => rgb ¬ [1.0, 1.0, 1.0];
ENDCASE  => {
intensity: REAL ¬
G3dShade.TotalSurfaceIntensity[s.normal, r.eyeView, r.lights, r.portionSpecular];
rgb ¬ [intensity, intensity, intensity];
};
};
};
Animation
Animate: G3dTool.AnimateProc ~ {
ENABLE ImplicitSurface.NoSurfacePoint => CONTINUE;
t: Tool ¬ NARROW[clientData];
SELECT t.animationUse FROM
client =>
[] ¬ t.startProc[t.client.data, animateClient, t.tool3d.frame, t.tool3d.nFrames];
surface => {
IF t.animateShapeName # NIL THEN t.saveShape ¬
IO.PutFR["%g.%g.shape", IO.rope[t.animateShapeName], IO.int[t.tool3d.frame]];
[] ¬ DoMakeOctree[t, animateSurface];
TSWrite[t, ", "];
[] ¬ DoMakePolygons[t, animateSurface];
};
ENDCASE;
IF t.client.animate # NIL THEN t.client.animate[frame, alpha, time, t.client.data];
};
Octree Operations
Reset: PUBLIC PROC [tool: Tool] ~ {
tool.octree ¬ NIL;
tool.surface ¬ NIL;
G3dTool.DeleteShape[tool.tool3d, "Imp"];
IF tool.cubes # NIL THEN tool.cubes.length ¬ 0;
IF tool.roots # NIL THEN tool.roots.length ¬ 0;
Repaint[tool];
};
MakeSurface: PUBLIC PROC [
command:    ROPE,
out:     IO.STREAM,
measureMode:  ATOM ¬ $Unspecified,
distanceMode:  ImplicitDefs.DistanceMode ¬ inverseSqrd,
tolerance:    REAL ¬ 0.0, 
spread:    REAL ¬ 0.75, 
threshold:   REAL ¬ 1.0,
octreeType:   G3dOctree.OctreeType ¬ track,
rootSize:    REAL ¬ 0.5,
trackSize:    REAL ¬ 0.02,
recurseMin:   NAT ¬ 1,
recurseMax:   NAT ¬ 5,
adaptAfterMax:  NAT ¬ 0,
adaptDuringMax: NAT ¬ 0,
octreeTolerance:  REAL ¬ 0.0001,
flatness:    REAL ¬ 30.0,
showTool:    BOOL ¬ FALSE]
RETURNS [ImplicitDefs.Surface]
~ {
result: REF;
msg: ROPE;
t: Tool ¬ NEW[ToolRep];
cmd: Commander.Handle ¬ NARROW[ProcessProps.GetProp[$CommanderHandle]];
t.measureMode ¬ measureMode;
t.distanceMode ¬ distanceMode;
t.tolerance ¬ tolerance;
t.threshold ¬ threshold;
t.spread ¬ spread;
t.octreeType ¬ octreeType;
t.rootSize ¬ rootSize;
t.trackSize ¬ trackSize;
t.recurseMin ¬ recurseMin;
t.recurseMax ¬ recurseMax;
t.adaptAfterMax ¬ adaptAfterMax;
t.adaptDuringMax ¬ adaptDuringMax;
t.octreeTolerance ¬ octreeTolerance;
t.flatness ¬ flatness;
cmd.out ¬ out;
Now things get a bit wild:
CommanderOps.PutProp[cmd, $Tool, t];
IF showTool THEN CommanderOps.PutProp[cmd, $ShowTool, $ShowTool];
cmd.commandLine ¬ command;
cmd.command ¬ "ImplicitOctree";
ExecuteOption calls MakeTool, which returns Tool to the command option. Thus, MakeTool must return before calling MakeAll, otherwise the command option may die if, e.g., its PaintProc is called with Tool = NIL.
[result, msg] ¬ ExecuteOption[cmd];
MakeAll[t];
[] ¬ CedarProcess.Join[t.tool3d.process];
IF showTool THEN ViewerOps.DestroyViewer[t.tool3d.outer];
IF result # NIL THEN IO.PutRope[out, msg];
RETURN[IF result = NIL THEN t.surface ELSE NIL];
};
OctreeButton: ClickProc ~ {
V: PROC [title, doc: ROPE, value: REAL] RETURNS [Controls.Request] ~ Controls.RealRequest;
t: Tool ¬ NARROW[clientData];
choice: INT ¬ Controls.PopUpRequest[["Octree Options"], LIST[
--1-- IF t.octreeType = track
    THEN ["converge", "Now Tracking"] ELSE ["track", "Now Converging"],
--2-- ["set distance mode", "Choose a distance mode (default is inverseSquared)"],
--3-- ["set measure mode", "Choose a measure mode (default is segment)"],
--4-- ["set edge mode", "Choose a edge convergence mode (default is binarySectioning)"],
--5-- V["tolerance", "Distance measurement error tolerance", t.tolerance],
--6-- V["threshold", "Set threshold (contour level) of surface", t.threshold],
--7-- V["spread", "Set radius of influence", t.spread],
--8-- V["post adapt limit", "Set max post octree adaptive subdiv", t.adaptAfterMax],
--9-- V["track adapt limit", "Set max adaptive tracking subdiv", t.adaptDuringMax],
--10-- V["adapt flatness", "Set polygon flatness criterion", t.flatness],
--11-- V["octree tolerance", "Set octree convergence tolerance", t.octreeTolerance],
--12-- V["min recusion", "Set min recursion depth of converging octree", t.recurseMin],
--13-- V["max recursion", "Set max recursion depth of converging octree", t.recurseMax],
--14-- V["tracking size", "Cube size for tracking surface", t.trackSize],
--15-- V["converging size", "Root cube size for converging octree", t.rootSize],
--16-- IF t.triangulate THEN ["polygons", "Now triangles"] ELSE ["triangles", "Now polygons"],
--17-- ["MAKE AND POLYGONIZE OCTREE", "Make and polygonize an octree"],
--18-- ["MAKE OCTREE ONLY", "Make an octree"],
--19-- ["POLYGONIZE OCTREE", "Polygonize the existing octree"],
--20-- Controls.RopeRequest["SaveShape", "Automatically save shape file", t.saveShape],
--21-- Controls.RopeRequest["SaveIP", "Automatically save Interpress file", t.saveIP],
--22-- Controls.RopeRequest["Shape name", "Base animated files", t.animateShapeName],
--23-- ["OUTPUT OCTREE", "Output the octree"],
--24-- ["READ OCTREE", "Read an octree from an octree file"],
--25-- IF t.animationUse = client
  THEN ["Animate surface", "now client"] ELSE ["Animate client", "now surface"],
--26-- Controls.BoolRequest[t.record, "Record"]]];
G3dTool.SetCursor[t.tool3d, TRUE];
SELECT choice FROM
1 => t.octreeType     ¬ IF t.octreeType = track THEN converge ELSE track;
2 => SetDistanceMode[t];
3 => SetMeasureMode[t];
4 => SetEdgeMode[t];
5 => t.tolerance    ¬ GetReal[t, "Sampling Tolerance", t.tolerance];
6 => t.threshold    ¬ GetReal[t, "Threshold", t.threshold];
7 => t.spread     ¬ GetReal[t, "Spread", t.spread];
8 => t.adaptAfterMax   ¬ GetNat[t, "AfterAdaptLimit", t.adaptAfterMax];
9 => t.adaptDuringMax  ¬ GetNat[t, "DuringAdaptLimit", t.adaptDuringMax];
10 => t.flatness     ¬ GetReal[t, "Flatness", t.flatness];
11 => t.octreeTolerance   ¬ GetReal[t, "Octree Tolerance", t.octreeTolerance];
12 => t.recurseMin    ¬ GetNat[t, "RecurseMin", t.recurseMin];
13 => t.recurseMax    ¬ GetNat[t, "RecurseMax", t.recurseMax];
14 => t.trackSize    ¬ GetReal[t, "TrackSize", t.trackSize];
15 => t.rootSize     ¬ GetReal[t, "ConvergeSize", t.rootSize];
16 => t.triangulate ¬ NOT t.triangulate;
17 => MakeAll[t];
18 => MakeOctree[t];
19 => MakePolygons[t];
20 =>  t.saveShape    ¬ Controls.TypescriptReadFileName[t.tool3d.typescript];
21 =>  t.saveIP     ¬ Controls.TypescriptReadFileName[t.tool3d.typescript];
22 =>  t.animateShapeName  ¬ Controls.TypescriptReadFileName[t.tool3d.typescript];
23 => IF t.octree = NIL
THEN Controls.TypescriptWrite[t.tool3d.typescript, "No octree to write.\n"]
ELSE G3dOctree.WriteCubesToFile[
Controls.TypescriptReadFileName[t.tool3d.typescript], t.octree.root, MiscInfo[t]];
24 => {
IF t.octree = NIL THEN t.octree ¬ NEW[G3dOctree.OctreeRep];
t.octree.root ¬
G3dOctree.ReadCubesFromFile[Controls.TypescriptReadFileName[t.tool3d.typescript]];
IF t.octree.root # NIL THEN {
G3dOctree.SetOctreeFields[t.octree];
IF t.surface = NIL THEN t.surface ¬ NEW[ImplicitDefs.SurfaceRep];
t.surface.octree ¬ t.octree;
Repaint[t];
};
};
25 => t.animationUse ¬ IF t.animationUse = client THEN surface ELSE client;
26 =>  t.record ¬ NOT t.record;
ENDCASE;
G3dTool.SetCursor[t.tool3d, FALSE];
IF choice IN [3..11] THEN MessageWindow.Append[ParametersMessage[t]];
};
SetDistanceMode: PROC [t: Tool] ~ {
header: ROPE ¬ Rope.Concat["Distance Mode, now ", RopeFromDistanceMode[t.distanceMode]];
t.distanceMode ¬ SELECT Controls.PopUpRequest[[header], LIST[
["Inverse", "Measure according to inverse distance"],
["InverseSquared", "Measure according to inverse distance squared"],
["WtInverse", "Measure according to inverse weighted distance"],
["WtInverseSquared", "Measure according to inverse weighted distance squared"]]] FROM
1 => inverse, 2 => inverseSqrd, 3 => wtInverse, 4 => wtInverseSqrd,
ENDCASE=> t.distanceMode;
};
SetMeasureMode: PROC [t: Tool] ~ {
r: ROPE ¬ Atom.GetPName[t.measureMode];
r ¬ Controls.TypescriptRead[t.tool3d.typescript, Rope.Cat["Measure Mode (now ", r, "): "]];
IF NOT Rope.IsEmpty[r] THEN {
c: CHAR ¬ Rope.Fetch[r];
r ¬ Rope.Concat[Rope.FromChar[IF c IN ['a..'z] THEN c-'a+'A ELSE c], Rope.Substr[r, 1]];
t.measureMode ¬ Atom.MakeAtom[r];
};
};
SetEdgeMode: PROC [t: Tool] ~ {
header: ROPE ¬ Rope.Concat["Edge Mode, now ", RopeFromEdgeMode[t.edgeMode]];
t.edgeMode ¬ SELECT Controls.PopUpRequest[[header], LIST[
["BinarySectioning", "Converge according to binary subdivision"],
["RegulaFalsi", "Converge according to linear estimation"]]] FROM
1 => binarySectioning, 2 => regulaFalsi, ENDCASE => t.edgeMode;
};
MakeAll:  PROC [t: Tool] ~ {[] ¬ MaybeFork[t, ForkMakeAll]};
MakeOctree: PROC [t: Tool] ~ {[] ¬ MaybeFork[t, ForkMakeOctree]};
MakePolygons: PROC [t: Tool] ~ {[] ¬ MaybeFork[t, ForkMakePolygons]};
ForkMakeAll: ForkableProc ~ {
time: REAL ¬ BasicTime.PulsesToSeconds[BasicTime.GetClockPulses[]];
t: Tool ¬ NARROW[data];
IF trick
THEN {Repaint[t, $Client]; Repaint[t, $Playback]; reset ¬ FALSE; Repaint[t]}
ELSE {
t.nImplicitEvaluations ¬ DoMakeOctree[t ! ImplicitSurface.NoSurfacePoint => GOTO Bad];
TSWrite[t, ", "];
t.nImplicitEvaluations ¬ t.nImplicitEvaluations+DoMakePolygons[t];
G3dTool.Finish[t.tool3d, IO.PutFR[" (%g seconds, %g evaluations)",
IO.real[BasicTime.PulsesToSeconds[BasicTime.GetClockPulses[]]-time],
IO.int[t.nImplicitEvaluations]]];
EXITS Bad => G3dTool.TSWrite[t.tool3d, "Can't find a starting point\n"];
};
};
ForkMakeOctree: ForkableProc ~ {
t: Tool ¬ NARROW[data];
t.nImplicitEvaluations ¬ DoMakeOctree[t ! ImplicitSurface.NoSurfacePoint => {
G3dTool.TSWrite[t.tool3d, "Can't find a starting point\n"];
GOTO Bad}];
TSWrite[t, IO.PutFR1[" (%g evaluations)\n", IO.int[t.nImplicitEvaluations]]];
EXITS Bad => NULL;
};
ForkMakePolygons: ForkableProc ~ {
t: Tool ¬ NARROW[data];
t.nImplicitEvaluations ¬ DoMakePolygons[t];
TSWrite[t, IO.PutFR1[" (%g evaluations)\n", IO.int[t.nImplicitEvaluations]]];
};
DoMakeOctree: PUBLIC PROC [t: Tool, use: ImplicitDefs.Use ¬ unknown]
RETURNS [nImplicitEvaluations: INT ¬ 0]
~ {
Status: ImplicitDefs.StatusProc ~ {
WITH ref SELECT FROM
c: Cube => {
IF t.cubeOkProc # NIL AND NOT t.cubeOkProc[c, t.client.data]
THEN RETURN[$RejectCube];
IF t.drawAge OR t.record
THEN t.cubes ¬ G3dOctree.AddToCubeSequence[c, t.cubes];
IF t.drawRoots THEN {
root: Cube ¬ G3dOctree.Root[c];
IF root # previousRoot THEN {
t.roots ¬ G3dOctree.AddToCubeSequence[previousRoot ¬ root, t.roots];
Repaint[t, $NewRoot];
};
};
t.currentCube ¬ c;
Repaint[t, surfaceState];
};
a: ATOM => surfaceState ¬ a;
r: ROPE => TSWrite[t, r];
ENDCASE;
CedarProcess.CheckAbort[];
IF t.destroyed OR CedarProcess.GetStatus[] = aborted THEN RETURN[$Abort];
};
Value: ImplicitDefs.ValueProc ~ {
nImplicitEvaluations ¬ nImplicitEvaluations+1;
RETURN[t.valueProc[point, clientData, corner]];
};
previousRoot: Cube ¬ NIL;
surfaceState: ATOM ¬ $Nothing;
guess: Triple ¬ IF t.startProc # NIL THEN t.startProc[t.client.data] ELSE [];
st: Triple ¬ ImplicitSurface.FindStart[guess, t.valueProc, t.trackSize, t.threshold, t.client.data];
mode: G3dOctree.OctreeMode ¬ IF t.octreeType = converge THEN
[t.adaptAfterMax,t.flatness,t.octreeTolerance, converge[t.rootSize,t.recurseMin,t.recurseMax]]
ELSE [t.adaptAfterMax, t.flatness, t.octreeTolerance, track[t.trackSize, st, t.adaptDuringMax]];
Reset[t];
t.drawOctree ¬ TRUE;
t.octree ¬
ImplicitSurface.MakeOctree[mode, Value, t.threshold, t.normalProc, Status, t.client.data];
t.drawOctree ¬ FALSE;
};
DoMakePolygons: PUBLIC PROC [t: Tool, use: ImplicitDefs.Use ¬ unknown]
RETURNS [nEvaluations: INT]
~ {
IF t.octree = NIL
THEN TSWrite[t, "First, need octree.\n"]
ELSE {
Save: PROC [name: ROPE, op: {ip, shape}] ~ {
TSWrite[t, Rope.Cat["Saving ", name, " . . . "]];
IF op = ip
THEN {
Action: Draw2d.DrawProc ~ {
v: G3dTool.View ¬ G3dTool.GetView[NIL, t.tool3d];
G3dTool.Draw[context, NIL, NIL, v.camera.matrix, v.viewport, v, t.tool3d, t];
};
Draw2d.IPOut[name, Action, t];
}
ELSE G3dShape.ShapeToFile[name, t.tool3d.shapes[0],,, MiscInfo[t]];
TSWrite[t, "done\n"];
IF op = ip THEN t.saveIP ¬ NIL ELSE t.saveShape ¬ NIL;
};
Status: ImplicitDefs.StatusProc ~ {
WITH ref SELECT FROM
c: Cube => {
t.currentCube ¬ c;
Repaint[t, surfaceState];
};
a: ATOM => IF (surfaceState ¬ a) = $MakePolygons THEN {
v: G3dTool.View ¬ G3dTool.GetView[NIL, t.tool3d];
ImplicitPoints.SetVertexScreenCoords[t.surface, v.camera.matrix, v.viewport];
};
r: ROPE => TSWrite[t, r];
ENDCASE;
CedarProcess.CheckAbort[];
IF t.destroyed OR CedarProcess.GetStatus[] = aborted THEN RETURN[$Abort];
};
surfaceState: ATOM;
t.surface ¬ NEW[ImplicitDefs.SurfaceRep ¬ [octree: t.octree]];
nEvaluations ¬ ImplicitSurface.MakePolygons[
t.surface, t.valueProc, t.threshold, t.triangulate, t.vertexOkProc, t.polygonOkProc,
t.normalProc, t.colorProc, t.textureProc, Status, t.octreeTolerance, t.edgeMode,
t.client.data];
AddShape[t, ImplicitSurface.ShapeFromSurface[t.surface]];
Repaint[t];
IF t.saveShape # NIL THEN Save[t.saveShape, shape];
IF t.saveIP # NIL THEN Save[t.saveIP, ip];
};
};
Hidden Line Elimination
HLEButton: ClickProc ~ {
t: Tool ¬ NARROW[clientData];
choice: INT ¬ Controls.PopUpRequest[["Display Options"], LIST[
[IO.PutFR1["hle z start (now %g)", IO.real[t.hleZStart]]],
[IO.PutFR1["hle z stop (now %g)", IO.real[t.hleZStop]]],
[IO.PutFR1["hle z delta (now %g)", IO.real[t.hleZDelta]]],
["DRAW HLE CONTOURS", "Draw contours with hidden lines eliminated"],
["DRAW HLE OCTREE", "Draw octree with hidden lines eliminated"]]];
G3dTool.SetCursor[t.tool3d, TRUE];
SELECT choice FROM
1 => t.hleZStart ¬ GetReal[t, "Z Start", t.hleZStart];
2 => t.hleZStop ¬ GetReal[t, "Z Stop", t.hleZStop];
3 => t.hleZDelta ¬ GetReal[t, "Z Delta", t.hleZDelta];
4 => [] ¬ MaybeFork[t, HLEContours];
5 => [] ¬ MaybeFork[t, HLEOctree];
ENDCASE;
G3dTool.SetCursor[t.tool3d, FALSE];
};
HLEOctree: ForkableProc ~ {
Repaint[NARROW[data], $HLEOctree];
};
HLEContours: ForkableProc ~ {
See: Ricci, '73 (hidden line elimination using planes perpendicular to the view direction).
Connect: ImplicitDefs.ConnectProc ~ {
t.hleSegment ¬ [p0: p0, p1: p1];
Repaint[t, $HLE];
};
t: Tool ¬ NARROW[data];
IF t.octree = NIL
THEN TSWrite[t, "First, need octree.\n"]
ELSE {
inverse: Matrix ¬ G3dMatrix.Invert[G3dTool.GetViewTransform[NIL, t.tool3d]];
normal: Triple ¬ G3dMatrix.TransformVec[[0.0, 0.0, 1.0], inverse];
normal ¬ G3dVector.Unit[normal];
ImplicitDraw.DoWithPlanarContours[t.octree, t.edgeMode, t.valueProc, t.threshold, Connect, t.client.data, normal, t.hleZStart, t.hleZStop, t.hleZDelta];
};
};
Support
AddShape: PROC [t: Tool, s: G3dShape.Shape] ~ {
IF s = NIL THEN RETURN;
s.name ¬ "Imp";
s.selected ¬ TRUE;
G3dTool.AddShape[t.tool3d, s];
};
GetReal: PROC [t: Tool, prompt: ROPE, value: REAL] RETURNS [REAL] ~ {
RETURN[Controls.GetReal[t.tool3d.typescript, prompt, value]];
};
GetNat: PROC [t: Tool, prompt: ROPE, value: NAT] RETURNS [NAT] ~ {
RETURN[Controls.GetNat[t.tool3d.typescript, prompt, value]];
};
Eq: PROC [r1, r2: ROPE] RETURNS [b: BOOL] ~ {b ¬ Rope.Equal[r1, r2, FALSE]};
TSWrite: PROC [t: Tool, rope: ROPE] ~ {Controls.TypescriptWrite[t.tool3d.typescript, rope]};
RopeFromDistanceMode: PUBLIC PROC [mode: DistanceMode] RETURNS [ROPE] ~ {
RETURN[SELECT mode FROM
inverse   => "Inverse",
inverseSqrd  => "InverseSquared",
wtInverse  => "WtInverse",
wtInverseSqrd => "WtInverseSquared",
ENDCASE => NIL];
};
RopeFromEdgeMode: PUBLIC PROC [mode: EdgeMode] RETURNS [ROPE] ~ {
RETURN[SELECT mode FROM
binarySectioning => "binarySectioning",
regulaFalsi   => "regulaFalsi",
ENDCASE => NIL];
};
Logging
logName: ROPE ¬ "ImplicitSurfaces.params";
ParametersMessage: PUBLIC PROC [t: Tool] RETURNS [ROPE] ~ {
sampleInfo: ROPE ¬ IO.PutFLR["tolerance: %g, threshold: %g, trackSize: %g, spread: %g",
LIST[IO.real[t.tolerance], IO.real[t.threshold], IO.real[t.trackSize], IO.real[t.spread]]];
adaptInfo: ROPE ¬ IO.PutFLR["adaptDuringMax: %g, adaptAfterMax: %g flatness: %g",
LIST[IO.int[t.adaptDuringMax], IO.int[t.adaptAfterMax], IO.real[t.flatness]]];
RETURN[Rope.Cat[sampleInfo, ", ", adaptInfo]];
};
MiscInfo: PROC [t: Tool] RETURNS [r: ROPE] ~ {
r ¬ ParametersMessage[t];
IF t.docProc # NIL THEN r ¬ Rope.Cat[r, " ", t.docProc[t.client.data]];
};
FullFileName: PROC [t: Tool, name: ROPE] RETURNS [PFS.PATH] ~ {
RETURN[PFS.PathFromRope[Rope.Concat[t.tool3d.directory, name]]];
};
UpdateLog: PUBLIC PROC [t: Tool, key, entry: ROPE] RETURNS [err: ROPE ¬ NIL] ~ {
in, out: IO.STREAM;
inRope: ROPE ¬ NIL;
found: BOOL ¬ FALSE;
inRope ¬ PFS.RopeOpen[FullFileName[t, logName] ! PFS.Error => CONTINUE].rope;
IF inRope # NIL THEN in ¬ IO.RIS[inRope];
out ¬ PFS.StreamOpen[FullFileName[t, logName], create];
IF in # NIL THEN WHILE NOT IO.EndOf[in] DO
line: ROPE ¬ IO.GetLineRope[in];
word: ROPE ¬ Rope.Substr[line,, Rope.SkipTo[line,, ": \t"]];
IF Eq[word, key]
THEN {
found ¬ TRUE;
IO.PutF[out, "%g: %g\n", IO.rope[key], IO.rope[entry]];
}
ELSE IO.PutF1[out, "%g\n", IO.rope[line]];
ENDLOOP;
IF NOT found THEN IO.PutF[out, "%g: %g\n", IO.rope[key], IO.rope[entry]];
IO.Close[out];
};
GetLogEntry: PUBLIC PROC [t: Tool, key: ROPE] RETURNS [r: ROPE ¬ NIL] ~ {
in: IO.STREAM;
IO.PutF1[t.tool3d.cmd.out, "full file name = %g\n", IO.rope[PFS.RopeFromPath[FullFileName[t, logName]]]];
in ¬ PFS.StreamOpen[FullFileName[t, logName] ! PFS.Error => CONTINUE];
IF in # NIL THEN WHILE NOT IO.EndOf[in] DO
line: ROPE ¬ IO.GetLineRope[in];
IF Eq[Rope.Substr[line,, Rope.SkipTo[line,, ": \t"]], key] THEN RETURN[line];
ENDLOOP;
};
SetToolFromLog: PROC [t: Tool, name: ROPE] ~ {
GetArg: PROC [key: ROPE] RETURNS [rope: ROPE ¬ NIL] ~ {
i: INT ¬ Rope.Find[entry, key,, FALSE];
IF i # -1 THEN {
ii: INT ¬ Rope.SkipOver[entry, i+Rope.Length[key], ": \t"];
rope ¬ Rope.Substr[entry, ii, Rope.SkipTo[entry, ii, ",: \t\n"]-ii];
};
};
GetInt: PROC [key: ROPE, defValue: INT] RETURNS [r: INT] ~ {
r ¬ Convert.IntFromRope[GetArg[key] ! Convert.Error => {r ¬ defValue; CONTINUE}];
};
GetReal: PROC [key: ROPE, defValue: REAL] RETURNS [r: REAL] ~ {
r ¬ Convert.RealFromRope[GetArg[key] ! Convert.Error => {r ¬ defValue; CONTINUE}];
};
entry: ROPE ¬ GetLogEntry[t, name];
IF entry = NIL THEN RETURN;
t.tolerance ¬ GetReal["tolerance", t.tolerance];
t.threshold ¬ GetReal["threshold", t.threshold];
t.trackSize ¬ GetReal["trackSize", t.trackSize];
t.spread ¬ GetReal["spread", t.spread];
t.adaptDuringMax ¬ GetInt["adaptDuringMax", t.adaptDuringMax];
t.adaptAfterMax ¬ GetInt["adaptAfterMax", t.adaptAfterMax];
t.flatness ¬ GetReal["flatness", t.flatness];
};
Registration and Dispatching
Registration: TYPE ~ RECORD [
command:   ROPE,         -- name of CommandTool command
function:    ROPE,         -- name of implicit function
action:    CommandProc,      -- proc to be called
doc:     ROPE         -- documentation of function
];
registry:  LIST OF Registration ¬ NIL;
RegistrationMatch: PROC [item: Registration, command, function: ROPE] RETURNS [BOOL] ~ {
RETURN[Eq[item.command, command] AND Eq[item.function, function]];
};
Register: PUBLIC PROC [
function: ROPE,
action: CommandProc,
doc: ROPE,
command: ROPE ¬ NIL]
~ {
item: Registration;
IF command = NIL THEN command ¬ "ImplicitOctree";
item ¬ [command, function, action, doc];
IF registry = NIL
THEN registry ¬ LIST[item]
ELSE FOR l: LIST OF Registration ¬ registry, l.rest WHILE l # NIL DO
IF RegistrationMatch[l.first, command, function] THEN {l.first ¬ item; EXIT};
IF l.rest = NIL THEN {l.rest ¬ LIST[item]; EXIT};
ENDLOOP;
Commander.Register[command, DesignCmd]; -- try that, Unix
};
ToolOptions: PUBLIC PROC [command: ROPE] RETURNS [toolOptions: ROPE ¬ NIL] ~ {
width: INT ¬ 2*VFonts.StringWidth["\t"];  -- VFonts says 12; but should be 24
FOR l: LIST OF Registration ¬ registry, l.rest WHILE l # NIL DO
IF Eq[l.first.command, command] THEN {
colonTabs: ROPE ¬ ":";
nTabs: INT ¬ 2+MAX[81-VFonts.StringWidth[Rope.Concat[l.first.function, ":"]], 0]/width;
THROUGH [1..nTabs] DO colonTabs ¬ Rope.Concat[colonTabs, "\t"]; ENDLOOP;
toolOptions ¬ Rope.Cat[toolOptions, "\n\t", l.first.function, colonTabs, l.first.doc];
};
ENDLOOP;
};
ExecuteOption: PUBLIC CommandProc ~ {
argv: CommanderOps.ArgumentVector ¬ CommanderOps.Parse[cmd];
IF argv.argc > 1 THEN SELECT TRUE FROM
Eq[argv[1], "reset"] => {
FOR l: LIST OF Registration ¬ registry, l.rest WHILE l # NIL DO
Commander.Register[l.first.command, NIL];
ENDLOOP;
registry ¬ NIL;
};
ENDCASE => {
command: ROPE ¬ FileNames.GetShortName[cmd.command];
FOR l: LIST OF Registration ¬ registry, l.rest WHILE l # NIL DO
IF RegistrationMatch[l.first, command, argv[1]] THEN {
[result, msg] ¬ l.first.action[cmd];
RETURN;
};
ENDLOOP;
RETURN[$Failure, "No such option."];
};
};
DesignCmd: PUBLIC CommandProc ~ {
argv: CommanderOps.ArgumentVector ¬ CommanderOps.Parse[cmd];
command: ROPE ¬ FileNames.GetShortName[cmd.command];
IF argv.argc < 2 THEN RETURN[$Failure, Rope.Concat[command, " <option | ?>"]];
IF Eq[argv[1], "?"]
THEN RETURN[, Rope.Cat[command, " <option>, options include:", ToolOptions[command]]]
ELSE [result, msg] ¬ ExecuteOption[cmd];
};
Start Code
Commander.Register["ImplicitOctree", DesignCmd, "ImplicitOctree <option | ?>"];
Reset:\t\t\t\tremove current options";
END.
..
DisplayButton: ClickProc ~ {
t: Tool ¬ NARROW[clientData];
choice: INT ¬ Controls.PopUpRequest[["Display Options"], LIST[
--1--  Controls.BoolRequest[t.drawOptions.client, "Client Display"],
--2--  Controls.BoolRequest[t.drawOptions.backFaces, "Back Faces"],
--3--  Controls.BoolRequest[t.drawOptions.polygons, "Polygon Display"],
--4--  Controls.BoolRequest[t.drawOptions.triangles, "Triangle Display"],
--5--  Controls.BoolRequest[t.drawOptions.vertices, "Vertices Display"],
--6--  Controls.BoolRequest[t.drawOptions.labels, "Vertices Label"],
--7--  Controls.BoolRequest[t.drawOptions.normals, "Normals Display"],
--8--  Controls.BoolRequest[t.drawOptions.dimFurtherLines, "Dim Further"],
--9--  Controls.BoolRequest[t.drawOptions.taperedLines, "Tapered Lines"],
--10-- Controls.BoolRequest[t.drawOptions.pendant, "Pendant"],
--11-- ["Redraw without clearing display"],
--12-- ["Render width and height"],
--13-  Controls.BoolRequest[t.drawOctree, "Octree: display"],
--14-- ["Octree: display mode", "Choose mode of octree display"],
--15-- Controls.BoolRequest[t.drawAge, "Octree: age display"],
--16-- Controls.BoolRequest[t.drawRoots, "Octree: roots display"],
--17-- ["Octree: playback", "play back the polygonization sequence"],
--18-- Controls.BoolRequest[t.showRayScreen, "Ray Trace: show Screen"],
--19-- Controls.BoolRequest[t.showRays, "Ray Trace: show rays"],
--20-- ["Ray Trace: orient line-drawing with ray view"]]];
SELECT choice FROM
1 => t.drawOptions.client ¬ NOT t.drawOptions.client;
2 => {
v: G3dTool.View ¬ G3dTool.GetFirstActiveView[t.tool3d];
t.drawOptions.backFaces ¬ NOT t.drawOptions.backFaces;
FOR n: NAT IN [0..t.tool3d.shapes.length) DO
t.tool3d.shapes[n].showBackfaces ¬ t.drawOptions.backFaces;
ENDLOOP;
t.shape.showBackfaces ¬ t.drawOptions.backFaces;
};
3 => t.drawOptions.polygons ¬ NOT t.drawOptions.polygons;
4 => {
t.drawOptions.triangles ¬ NOT t.drawOptions.triangles;
IF t.drawOptions.triangles AND NOT t.triangulated THEN Triangulate[t];
AddShape[t, IF t.drawOptions.triangles THEN t.triangulatedShape ELSE t.shape];
};
5 => t.drawOptions.vertices ¬ NOT t.drawOptions.vertices;
6 => t.drawOptions.labels ¬ NOT t.drawOptions.labels;
7 => t.drawOptions.normals ¬ NOT t.drawOptions.normals;
8 => t.drawOptions.dimFurtherLines ¬ NOT t.drawOptions.dimFurtherLines;
9 => t.drawOptions.taperedLines ¬ NOT t.drawOptions.taperedLines;
10 => t.drawOptions.pendant ¬ NOT t.drawOptions.pendant;
11 => {Repaint[t, $NoClear]; RETURN};
12 =>
t.tool3d.frameSize ¬ Controls.GetIntegerPair[t.tool3d.typescript, "render <width> <height>", t.tool3d.frameSize];
13 => t.drawOctree ¬ NOT t.drawOctree;
14 => t.directionSelect ¬ SELECT Controls.PopUpRequest[["Octree Display Mode"], LIST[
["x","Show just x"], ["y","Show just y"], ["z","Show just z"], ["xy","Show just xy"],
["xz","Show just xz"], ["yz","Show just yz"], ["xyz","Show all"]]] FROM
1=>x, 2=>y, 3=>z, 4=>xy, 5=>xz, 6=>yz, 7=>xyz, ENDCASE=>t.directionSelect;
15 => t.drawAge ¬ NOT t.drawAge;
16 => t.drawRoots ¬ NOT t.drawRoots;
17 => {Repaint[t, $Playback]; Repaint[t]; RETURN};
18 => t.showRayScreen ¬ NOT t.showRayScreen;
19 => t.showRays ¬ NOT t.showRays;
20 =>
t.tool3d.camera.matrix ¬ G3dView.WorldToViewFromVectors[
t.rayData.eyePoint, t.rayData.eyeView, t.rayData.upDirection,
t.rayData.fieldOfView, t.tool3d.camera.matrix];
ENDCASE => RETURN;
IF Controls.GetPopUpButton[] = right THEN Repaint[t];
};