DIRECTORY Args, Buttons, Commander, CommanderOps, Controls, Convert, Draw2d, FileNames, FS, G2dBasic, G3dBasic, G3dControl, G3dCubeDraw, G3dDraw, G3dMatrix, G3dOctree, G3dRayCube, G3dTool, G3dVector, G3dVoxel, Imager, ImagerSample, IO, MessageWindow, Real, Rope, ViewerClasses, ViewerOps; G3dVolumeCmdsBImpl: CEDAR PROGRAM IMPORTS Args, Buttons, CommanderOps, Controls, Convert, Draw2d, FileNames, FS, G3dControl, G3dCubeDraw, G3dDraw, G3dMatrix, G3dOctree, G3dRayCube, G3dTool, G3dVector, G3dVoxel, IO, ImagerSample, MessageWindow, Real, Rope, ViewerOps ~ BEGIN Control: TYPE ~ Controls.Control; ClickProc: TYPE ~ Controls.ClickProc; OuterData: TYPE ~ Controls.OuterData; Ray: TYPE ~ G3dBasic.Ray; Triple: TYPE ~ G3dBasic.Triple; Camera: TYPE ~ G3dControl.CameraControl; Hold: TYPE ~ G3dControl.Hold; Matrix: TYPE ~ G3dMatrix.Matrix; Tool: TYPE ~ G3dTool.Tool; Intersection: TYPE ~ G3dOctree.Intersection; IntersectionList: TYPE ~ G3dOctree.IntersectionList; Cube: TYPE ~ G3dOctree.Cube; CubeProc: TYPE ~ G3dOctree.CubeProc; Octree: TYPE ~ G3dOctree.Octree; OctreeRep: TYPE ~ G3dOctree.OctreeRep; RealSequence: TYPE ~ G3dVoxel.RealSequence; Reals2d: TYPE ~ G3dVoxel.Reals2d; Context: TYPE ~ Imager.Context; ROPE: TYPE ~ Rope.ROPE; Viewer: TYPE ~ ViewerClasses.Viewer; GridExtractCommand: Commander.CommandProc ~ { argv: CommanderOps.ArgumentVector ฌ CommanderOps.Parse[cmd]; IF argv.argc # 9 THEN RETURN[$Failure, gridExtractUsage] ELSE { ENABLE G3dVoxel.Error => IF reason = $NoSuchFile THEN GOTO NoFile; ReadGrid: PROC [in: ROPE] RETURNS [grid: G3dVoxel.Grid] ~ { IO.PutF1[cmd.out, "Reading %g . . .", IO.rope[argv[1]]]; grid ฌ G3dVoxel.ReadGridFromFile[FileNames.ResolveRelativePath[in]]; IO.PutRope[cmd.out, " done!\n"]; }; GetIndex0: PROC [reals: RealSequence, r: REAL] RETURNS [NAT] ~ { FOR n: NAT IN [1..reals.length) DO IF reals[n] > r THEN RETURN[n-1]; REPEAT FINISHED => RETURN[reals.length-2]; -- r at max, so i1 = length-1, i0 = length-2 ENDLOOP; }; g: G3dVoxel.Grid; in, out, x0, y0, z0, x1, y1, z1: Args.Arg; [in, out, x0, y0, z0, x1, y1, z1] ฌ Args.ArgsGet[cmd, "%ss%rrrrrr" ! Args.Error => {msg ฌ reason; GOTO Bad}]; g ฌ ReadGrid[in.rope]; IF g.evenlySpaced THEN RETURN[$Failure, "Sorry, this works for uneven spacing only"] ELSE { WriteRealSequence: PROC [key: Rope.ROPE, reals: RealSequence, i0, i1: NAT] ~ { IO.PutF[s, "%l%g~%l\n", IO.rope["b"], IO.rope[key], IO.rope["B"]]; FOR n: NAT IN [i0..i1] DO IO.PutF1[s, "%g\t", IO.real[reals[n]]]; ENDLOOP; IO.PutRope[s, "\n"]; }; ix0: NAT ฌ GetIndex0[g.x, x0.real]+1; ix1: NAT ฌ GetIndex0[g.x, x1.real]; iy0: NAT ฌ GetIndex0[g.y, y0.real]+1; iy1: NAT ฌ GetIndex0[g.y, y1.real]; iz0: NAT ฌ GetIndex0[g.z, z0.real]+1; iz1: NAT ฌ GetIndex0[g.z, z1.real]; s: IO.STREAM ฌ FS.StreamOpen[out.rope, $create]; IO.PutFL[s, "%lNumberOfIndices~%l\n%g\t%g\t%g\n", LIST[ IO.rope["b"], IO.rope["B"], IO.int[ix1-ix0+1], IO.int[iy1-iy0+1], IO.int[iz1-iz0+1]]]; WriteRealSequence["XLocations", g.x, ix0, ix1]; WriteRealSequence["YLocations", g.y, iy0, iy1]; WriteRealSequence["ZLocations", g.z, iz0, iz1]; IO.PutF[s, "%lValues~%l\n", IO.rope["b"], IO.rope["B"]]; FOR i: NAT IN [ix0..ix1] DO reals2d: Reals2d ฌ g.values[i]; FOR j: NAT IN [iy0..iy1] DO reals: RealSequence ฌ reals2d[j]; FOR k: NAT IN [iz0..iz1] DO IO.PutF1[s, "%g\t", IO.real[reals[k]]]; ENDLOOP; IO.PutRope[s, "\n"]; ENDLOOP; ENDLOOP; IO.Close[s]; }; EXITS NoFile => RETURN[$Failure, "\tno such file"]; Bad => RETURN[$Failure, msg]; }; }; DrawData: TYPE ~ RECORD [tool: Tool, inv: Matrix, xRes, yRes, zRes: INT, mode: ATOM]; GridDrawCommand: Commander.CommandProc ~ { argv: CommanderOps.ArgumentVector ฌ CommanderOps.Parse[cmd]; IF argv.argc # 4 THEN RETURN[$Failure, gridDrawUsage] ELSE { d: REF DrawData ฌ NEW[DrawData]; d.xRes ฌ Convert.IntFromRope[argv[1]]; d.yRes ฌ Convert.IntFromRope[argv[2]]; d.zRes ฌ Convert.IntFromRope[argv[3]]; d.mode ฌ $Circles; d.tool ฌ G3dTool.MakeTool[ name: "3d Grid Draw", ops: [TRUE, FALSE], extraButtons: LIST[Controls.ClickButton["Circles", Mode, d]], client: [data: d, draw: DrawDraw]]; }; }; Mode: Controls.ClickProc ~ { d: REF DrawData ฌ NARROW[clientData]; newName: ROPE; SELECT d.mode FROM $Taper => {d.mode ฌ $Circles; newName ฌ "Circles"}; $Circles => {d.mode ฌ $Nothing; newName ฌ "Nothing"}; ENDCASE => {d.mode ฌ $Taper; newName ฌ "Tapered"}; Controls.ButtonRelabel[d.tool.outerData, parent.name, newName]; IF mouseButton = blue THEN { d.tool.camera.mouse.state ฌ up; ViewerOps.PaintViewer[d.tool.graphics, client, FALSE, NIL]; }; }; DrawDraw: G3dTool.DrawProc ~ { Lines: PROC [tapered: BOOL] ~ { DrawSegment: PROC [p0, p1: Triple] ~ { IF tapered THEN G3dDraw.TaperedSegment[context, p0, p1, 0.01, 0.01, view, d.inv, vp] ELSE G3dDraw.Segment[context, p0, p1, view, vp]; }; FOR i: INT IN [0..d.xRes] DO x: REAL ฌ -xMax+i*size; FOR j: INT IN [0..d.yRes] DO y: REAL ฌ -yMax+j*size; DrawSegment[[x, y, -zMax], [x, y, zMax]]; ENDLOOP; ENDLOOP; FOR j: INT IN [0..d.yRes] DO y: REAL ฌ -yMax+j*size; FOR k: INT IN [0..d.zRes] DO z: REAL ฌ -zMax+k*size; DrawSegment[[-xMax, y, z], [xMax, y, z]]; ENDLOOP; ENDLOOP; FOR k: INT IN [0..d.zRes] DO z: REAL ฌ -zMax+k*size; FOR i: INT IN [0..d.xRes] DO x: REAL ฌ -xMax+i*size; DrawSegment[[x, -yMax, z], [x, yMax, z]]; ENDLOOP; ENDLOOP; }; Circles: PROC ~ { FOR i: INT IN [0..d.xRes] DO x: REAL ฌ -xMax+i*size; FOR j: INT IN [0..d.yRes] DO y: REAL ฌ -yMax+j*size; FOR k: INT IN [0..d.zRes] DO z: REAL ฌ -zMax+k*size; r: REAL ฌ G3dDraw.ScreenRadiusFromSphere[[[x, y, z], 0.01], view, d.inv, vp]; Draw2d.Circle[context, G3dMatrix.TransformD[[x, y, z], view], r, TRUE]; ENDLOOP; ENDLOOP; ENDLOOP; }; d: REF DrawData ฌ NARROW[clientData]; size: REAL ฌ 1.0/REAL[d.xRes]; xMax: REAL ฌ 0.5*d.xRes*size; yMax: REAL ฌ 0.5*d.yRes*size; zMax: REAL ฌ 0.5*d.zRes*size; d.inv ฌ G3dMatrix.Invert[view, d.inv]; IF d.tool.camera.mouse.state # up THEN Lines[FALSE] ELSE IF d.mode = $Taper THEN Lines[TRUE] ELSE {Lines[FALSE]; IF d.mode = $Circles THEN Circles[]}; }; RenderData: TYPE ~ RECORD [ tool: G3dTool.Tool, stop: BOOL ฌ FALSE, reals3d: G3dVoxel.Reals3d, cd: ImagerSample.SampleMap, cube: G3dOctree.Cube]; SetSphericalReals: PROC [reals3d: G3dVoxel.Reals3d, size: REAL] ~ { factor: REAL ฌ 1.0/G3dVector.Length[[0.5*size, 0.5*size, 0.5*size]]; FOR i: NAT IN [0..reals3d.length/2) DO reals2dA: G3dVoxel.Reals2d ฌ reals3d[i]; reals2dB: G3dVoxel.Reals2d ฌ reals3d[reals3d.length-1-i]; x: REAL ฌ size*(REAL[i]/REAL[reals3d.length-1]-0.5); FOR j: NAT IN [0..reals2dA.length/2) DO realsA: G2dBasic.RealSequence ฌ reals2dA[j]; realsB: G2dBasic.RealSequence ฌ reals2dA[reals2dA.length-1-j]; realsC: G2dBasic.RealSequence ฌ reals2dB[j]; realsD: G2dBasic.RealSequence ฌ reals2dB[reals2dA.length-1-j]; y: REAL ฌ size*(REAL[j]/REAL[reals2dA.length-1]-0.5); FOR k: NAT IN [0..realsA.length/2) DO z: REAL ฌ size*(REAL[k]/REAL[realsA.length-1]-0.5); kk: NAT ฌ realsA.length-1-k; realsA[k] ฌ realsA[kk] ฌ realsB[k] ฌ realsB[kk] ฌ realsC[k] ฌ realsC[kk] ฌ realsD[k] ฌ realsD[kk] ฌ 1.0-G3dVector.Length[[x, y, z]]*factor; ENDLOOP; ENDLOOP; ENDLOOP; }; GridRenderCommand: Commander.CommandProc ~ { d: REF RenderData ฌ NEW[RenderData]; d.reals3d ฌ G3dVoxel.AllocateGridValues[[70, 70, 70]]; d.cube ฌ G3dOctree.NewCube[1.0]; SetSphericalReals[d.reals3d, d.cube.size]; d.tool ฌ G3dTool.MakeTool[ name: "3d Grid Render", ops: [FALSE, FALSE], extraButtons: LIST[ Controls.ClickButton["Render", Render, d], Controls.ClickButton["Abort", Abort, d]], client: [data: d, draw: RenderDraw]]; }; Render: Controls.ClickProc ~ { d: REF RenderData ฌ NARROW[clientData]; view: Matrix ฌ d.tool.views[0].camera.matrix; height: CARDINAL ฌ ImagerSample.GetSize[d.cd].s; d.stop ฌ FALSE; FOR i: NAT IN [0..d.reals3d.length) DO reals2d: G3dVoxel.Reals2d ฌ d.reals3d[i]; z: REAL ฌ d.cube.size*(0.5-REAL[i]/REAL[d.reals3d.length-1]); FOR j: NAT IN [0..reals2d.length) DO reals: G2dBasic.RealSequence ฌ reals2d[j]; y: REAL ฌ d.cube.size*(REAL[j]/REAL[reals2d.length-1]-0.5); FOR k: NAT IN [0..reals.length) DO x: REAL ฌ d.cube.size*(REAL[k]/REAL[reals.length-1]-0.5); p: G2dBasic.Pair ฌ G3dMatrix.TransformD[[x, z, y], view]; ix: NAT ฌ Real.Round[p.x]; iy: NAT ฌ height-Real.Round[p.y]; val: CARDINAL ฌ Real.Round[255.0*reals[k]]; IF d.stop THEN RETURN; ENDLOOP; ENDLOOP; ENDLOOP; }; Abort: Controls.ClickProc ~ {NARROW[clientData, REF RenderData].stop ฌ TRUE}; RenderDraw: G3dTool.DrawProc ~ { d: REF RenderData ฌ NARROW[clientData]; G3dCubeDraw.SimpleCube[context, d.cube, d.tool.views[0].camera.matrix]; }; OctreeData: TYPE ~ REF OctreeDataRec; OctreeDataRec: TYPE ~ RECORD [ outer: Viewer ฌ NIL, -- parent viewer graphics: Viewer ฌ NIL, -- graphical display viewer view: Matrix ฌ NIL, -- view transformation cam: Camera ฌ NIL, -- camera hold: Hold ฌ NIL, -- ray control ray: Ray, -- the ray itself show: {all, terminal} ฌ terminal, -- display of Octree intersectionList: IntersectionList ฌ NIL, -- ray-Octree intersections octree: Octree ฌ NIL -- the Octree ]; OctreeTrace: Commander.CommandProc ~ { argv: CommanderOps.ArgumentVector ~ CommanderOps.Parse[cmd]; IF argv.argc # 2 THEN RETURN[$Failure, "usage: OctreeRayTrace "] ELSE { d: OctreeData ~ NEW[OctreeDataRec]; d.cam ฌ G3dControl.InitCameraControl[scale: 2.5, proc: OctreeCamera, clientData: d]; d.hold ฌ G3dControl.InitHold[OctreeHoldProc, d]; Controls.ControlRow[d.cam.proxy.xRot, 1]; d.outer ฌ Controls.OuterViewer[ name: Rope.Concat["Octree Trace", argv[1]], controls: LIST[ d.cam.proxySelect, d.cam.proxy.xMov, d.cam.proxy.yMov, d.cam.proxy.zMov, d.cam.proxy.xRot, d.cam.proxy.yRot, d.cam.proxy.zRot, d.cam.scale, d.cam.fieldOfView], buttons: LIST[ Button["IP Out", OctreeIPOut, 0], Button["ShowTerminal", OctreeChangeShow], Button["Ray Trace", OctreeButtonRayTrace]], graphicsHeight: 400, drawProc: OctreeDrawProc, clientData: d ].parent; d.graphics ฌ NARROW[d.outer.data, OuterData].graphics; G3dControl.SetHold[d.hold, [0.0, 0.0, 0.0], [0.5, 0.0, 0.0]]; d.octree ฌ NEW[OctreeRep]; d.octree.root ฌ G3dOctree.ReadCubesFromFile[argv[1]]; d.octree.terminalRadius ฌ 0.5*G3dOctree.MinSize[d.octree.root]; d.ray ฌ RayFromHold[d.hold]; Repaint[d.graphics]; }; }; OctreeHoldProc: G3dControl.ControlProc ~ { d: OctreeData ฌ NARROW[control.clientData]; d.ray ฌ RayFromHold[d.hold]; IF RespondNow[control] THEN OctreeRayTrace[d]; Repaint[d.graphics]; }; OctreeCamera: Controls.ControlProc ~ { d: OctreeData ~ NARROW[clientData]; G3dControl.UpdateCameraControl[d.cam]; IF RespondNow[control] THEN Repaint[d.graphics]; }; OctreeDrawProc: Draw2d.DrawProc ~ { d: OctreeData ~ NARROW[clientData]; Action: PROC ~ { }; Draw2d.DoWithBuffer[context, Action]; }; OctreeDrawAction: Draw2d.DrawProc ~ { cubeProc: CubeProc ~ { }; d: OctreeData ~ NARROW[clientData]; }; OctreeRayTrace: PROC [d: OctreeData] ~ { d.intersectionList ฌ G3dRayCube.IntersectRayWithOctree[d.ray, d.octree]; }; OctreeButtonRayTrace: ClickProc ~ { d: OctreeData ฌ NARROW[NARROW[clientData, OuterData].clientData]; OctreeRayTrace[d]; Repaint[d.graphics]; }; OctreeIPOut: ClickProc ~ {IPOut[clientData, OctreeDrawAction]}; OctreeChangeShow: ClickProc ~ { d: OctreeData ฌ NARROW[NARROW[clientData, OuterData].clientData]; d.show ฌ IF d.show = all THEN terminal ELSE all; Buttons.ReLabel[parent, IF d.show = all THEN "ShowAll" ELSE "ShowTerminal"]; IF mouseButton = blue THEN Repaint[d.graphics]; }; CubeData: TYPE ~ REF CubeDataRec; CubeDataRec: TYPE ~ RECORD [ outer: Viewer ฌ NIL, -- parent viewer graphics: Viewer ฌ NIL, -- graphical display viewer view: Matrix ฌ NIL, -- view transformation cam: Camera ฌ NIL, -- camera hold: Hold ฌ NIL, -- ray control x, y, z, size: Control ฌ NIL, -- location and size of cube ray: Ray, -- the ray itself tracePending: BOOL ฌ FALSE, -- some state intersection: Intersection, -- ray-cube intersection cube: Cube ฌ NIL -- a single cube ]; CubeTrace: Commander.CommandProc ~ { d: CubeData ~ NEW[CubeDataRec]; d.x ฌ Controls.NewControl["x", vSlider, d, -1.0, 1.0, 0.0, CubeAdjust]; d.y ฌ Controls.NewControl["y", vSlider, d, -1.0, 1.0, 0.0, CubeAdjust]; d.z ฌ Controls.NewControl["z", vSlider, d, -1.0, 1.0, 0.0, CubeAdjust]; d.size ฌ Controls.NewControl["size", vSlider, d, 0.0, 1.0, 0.2, CubeAdjust]; d.hold ฌ G3dControl.InitHold[CubeHoldProc, d]; d.cam ฌ G3dControl.InitCameraControl[fieldOfView: 40, scale: 2.5, proc: CubeCamera, clientData: d]; Controls.ControlRow[d.cam.par.xRot, 1]; d.outer ฌ Controls.OuterViewer[ name: "Cube Trace", controls: LIST[ d.x, d.y, d.z, d.size, d.hold.x, d.hold.y, d.hold.z, d.hold.pitch, d.hold.yaw, d.hold.mag, d.cam.par.xRot, d.cam.par.yRot, d.cam.par.zRot, d.cam.scale, d.cam.fieldOfView], graphicsHeight: 400, drawProc: CubeDrawProc, clientData: d ].parent; d.graphics ฌ NARROW[d.outer.data, OuterData].graphics; G3dControl.SetHold[d.hold, [0.0, 0.0, 0.0], [0.5, 0.0, 0.0]]; d.cube ฌ G3dOctree.NewCube[d.size.value, [d.x.value, d.y.value, d.z.value]]; d.ray ฌ RayFromHold[d.hold]; Repaint[d.graphics]; }; CubeAdjust: Controls.ControlProc ~ { d: CubeData ฌ NARROW[control.clientData]; d.cube ฌ G3dOctree.NewCube[d.size.value, [d.x.value, d.y.value, d.z.value]]; IF RespondNow[control] THEN { CubeRayTrace[d]; Repaint[d.graphics]; } ELSE d.tracePending ฌ TRUE; }; CubeHoldProc: G3dControl.ControlProc ~ { d: CubeData ฌ NARROW[control.clientData]; d.ray ฌ RayFromHold[d.hold]; IF RespondNow[control] THEN CubeRayTrace[d] ELSE d.tracePending ฌ TRUE; Repaint[d.graphics]; }; CubeCamera: Controls.ControlProc ~ { d: CubeData ~ NARROW[clientData]; G3dControl.UpdateCameraControl[d.cam]; IF RespondNow[control] THEN { IF d.tracePending THEN CubeRayTrace[d]; Repaint[d.graphics]; }; }; CubeDrawProc: Draw2d.DrawProc ~ { d: CubeData ~ NARROW[clientData]; Action: PROC ~ { }; Draw2d.DoWithBuffer[context, Action]; }; CubeDrawAction: Draw2d.DrawProc ~ { }; CubeRayTrace: PROC [d: CubeData] ~ { d.intersection ฌ G3dRayCube.IntersectRayWithCube[d.ray, d.cube]; d.tracePending ฌ FALSE; }; CubeIPOut: ClickProc ~ {IPOut[clientData, CubeDrawAction]}; RayFromHold: PROC [hold: Hold] RETURNS [l: Ray] ~ { l.base ฌ G3dControl.PositionFromHold[hold]; l.axis ฌ G3dControl.VectorFromHold[hold]; }; RayMessage: PROC [l: Ray] ~ { r: ROPE ฌ IO.PutFR["base: (%g, %g, %g)", IO.real[l.base.x], IO.real[l.base.y], IO.real[l.base.z]]; r ฌ IO.PutFLR["%g, axis: (%g, %g, %g)", LIST[IO.rope[r], IO.real[l.axis.x], IO.real[l.axis.y], IO.real[l.axis.z]]]; MessageWindow.Append[r, TRUE]; }; IPOut: PROC [clientData: REF ANY, drawAction: Draw2d.DrawProc] ~ { outerData: OuterData ~ NARROW[clientData]; fileName: ROPE ฌ Controls.TypescriptReadFileName[outerData.typescript]; Draw2d.IPOut[fileName, drawAction, outerData.clientData]; }; Button: PROC [ name: ROPE ฌ NIL, proc: ClickProc ฌ NIL, row, x, y, w, h: INTEGER ฌ 0, fork: BOOL ฌ TRUE, doc: ROPE ฌ NIL, guarded: BOOL ฌ FALSE, font: Imager.Font ฌ NIL, style: ATOM ฌ $BlackOnWhite] RETURNS [Controls.Button] ~ { RETURN[Controls.ClickButton[name, proc, , row, x, y, w, h, fork, guarded, doc, font, style]]; }; Repaint: PROC [v: Viewer, whatChanged: REF ANY ฌ NIL] ~ { ViewerOps.PaintViewer[v, client, FALSE, whatChanged]; }; RespondNow: PROC [control: Control] RETURNS [BOOL] ~ { RETURN[control.mouse.button = right]; }; gridExtractUsage: Rope.ROPE ฌ "GridExtract "; gridDrawUsage: Rope.ROPE ฌ "GridDraw "; gridRenderUsage: Rope.ROPE ฌ "GridRender (render a spherical function as a grid)"; G3dTool.Register["OctreeTrace", OctreeTrace, "OctreeTrace ."]; G3dTool.Register["OctreeCubeTrace", CubeTrace, "OctreeCubeTrace."]; G3dTool.Register["GridExtract", GridExtractCommand, gridExtractUsage]; G3dTool.Register["GridDraw", GridDrawCommand, gridDrawUsage]; G3dTool.Register["GridRender", GridRenderCommand, gridRenderUsage]; END. า G3dVolumeCmdsBImpl.mesa Copyright ำ 1985, 1992 by Xerox Corporation. All rights reserved. Bloomenthal, November 21, 1992 3:03 pm PST Extract a Sub Grid Command Drawing a Grid Rendering a Grid d.cd _ CtBasic.GetBWColorDisplayMap[]; get: CARDINAL _ CtBasic.GetBWPixel[d.cd, ix, iy]; CtBasic.PutBWBox[d.cd, ix, iy, ix+1, iy+1, IF get = 0 THEN val ELSE (get+val)/2]; Ray Tracing An Octree IF whatChanged = NIL THEN d.view ฌ G3dControl.InitContext[context, d.cam, viewer, , d.view]; OctreeDrawAction[context, clientData, whatChanged, viewer]; G3dCubeDraw.SimpleCube[ context, cube, d.view, vp, TRUE, IF cube.terminal THEN solid ELSE dashed]; IF d.show = all THEN G3dOctree.Apply[d.octree.root, cubeProc] ELSE G3dCubeDraw.TerminalCubes[context, d.octree.root, d.view, vp, solid]; IF d.intersectionList # NIL THEN FOR l: IntersectionList ฌ d.intersectionList, l.rest WHILE l # NIL DO G3dDraw.Mark[ context, l.first.point, d.view, vp,, IF l.first.type = entering THEN cross ELSE x]; ENDLOOP; G3dDraw.Vector[context, d.ray.base, d.ray.axis, d.view, vp,, 1.0,, asterisk, dotted]; Ray Tracing A Cube IF whatChanged = NIL THEN d.view ฌ G3dControl.InitContext[context, d.cam, viewer, , d.view]; CubeDrawAction[context, clientData, whatChanged, viewer]; d: CubeData ~ NARROW[clientData]; label: ROPE ฌ G3dOctree.RopeFromDirectionSelect[d.intersection.directionSelect]; G3dCubeDraw.SimpleCube[context, d.cube, d.view, vp, TRUE, solid]; G3dDraw.Pendant[context, d.view]; IF d.intersection.type # empty THEN G3dDraw.Mark[ context, d.intersection.point, d.view, vp,, IF d.intersection.type=entering THEN cross ELSE x]; G3dDraw.Vector[context, d.ray.base, d.ray.axis, d.view, vp, label, 1.0,, asterisk, dotted]; Ray Support Miscellaneous Support Start Code ส]•NewlineDelimiter –"cedarcode" style™™Jšœ ฯeœ6™BJ™*J˜Jšฯk œ—˜ J˜—šะblœžœž˜!Jšžœเ˜็J˜—šœž˜J˜Jšœ žœ˜#Jšœ žœ˜'Jšœ žœ˜&Jšœžœ˜Jšœžœ˜!Jšœžœ˜*Jšœžœ˜ Jšœžœ˜"Jšœžœ˜Jšœžœ˜-Jšœžœ˜4Jšœžœ˜Jšœ žœ˜%Jšœžœ˜"Jšœ žœ˜'Jšœ žœ˜+Jšœžœ˜#Jšœžœ˜!Jšžœžœžœ˜Jšœžœ˜&—headšฯl™šะbnœ˜-J˜<šžœ˜Jšžœžœ˜'šžœ˜Jšžœžœžœžœ˜Bšฯnœžœžœžœ˜;Jšžœ$žœ˜8J˜DJšžœ˜ J˜—š ข œžœžœžœžœ˜@šžœžœžœž˜"Jšžœžœžœ˜!Jšž˜Jšžœžœฯc,˜PJšžœ˜—J˜—Jšœ˜Jšœ*˜*˜BJšœžœ˜*—J˜šžœ˜Jšž œ7˜Bšžœ˜šขœžœ žœžœ˜NJšžœžœ žœ žœ ˜Bšžœžœžœ ž˜Jšžœžœ˜'Jšžœ˜—Jšžœ˜J˜—Jšœžœ˜%Jšœžœ˜#Jšœžœ˜%Jšœžœ˜#Jšœžœ˜%Jšœžœ˜#Jšœžœžœžœ˜0šžœ0žœ˜7Jš žœ žœ žœžœžœ˜V—J˜/J˜/J˜/Jšžœžœ žœ ˜8šžœžœžœ ž˜J˜šžœžœžœ ž˜J˜!šžœžœžœ ž˜Jšžœžœ˜'Jšžœ˜—Jšžœ˜Jšžœ˜—Jšžœ˜—Jšžœ ˜ J˜——šž˜Jšœ žœ˜-Jšœžœ˜—J˜——J˜——š ™š œ žœžœ-žœžœ˜UJ˜—šกœ˜*J˜<šžœ˜Jšžœžœ˜$šžœ˜Jšœžœ žœ ˜ J˜&J˜&J˜&J˜˜J˜Jšœžœžœ˜Jšœžœ+˜=Jšœ#˜#—J˜——J˜J˜—šขœ˜Jšœžœ žœ ˜%Jšœ žœ˜šžœž˜J˜3J˜5Jšžœ+˜2—Jšœ?˜?šžœžœ˜J˜Jšœ/žœžœ˜;J˜—J˜J˜—šขœ˜šขœžœ žœ˜šข œžœ˜&šžœ˜ JšžœE˜IJšžœ,˜0—J˜—šžœžœžœ ž˜Jšœžœ˜šžœžœžœ ž˜Jšœžœ˜Jšœ)˜)Jšžœ˜—Jšžœ˜—šžœžœžœ ž˜Jšœžœ˜šžœžœžœ ž˜Jšœžœ˜Jšœ)˜)Jšžœ˜—Jšžœ˜—šžœžœžœ ž˜Jšœžœ˜šžœžœžœ ž˜Jšœžœ˜Jšœ)˜)Jšžœ˜—Jšžœ˜—J˜—šขœžœ˜šžœžœžœ ž˜Jšœžœ˜šžœžœžœ ž˜Jšœžœ˜šžœžœžœ ž˜Jšœžœ˜JšœžœF˜MJšœAžœ˜GJšžœ˜—Jšžœ˜—Jšžœ˜—J˜—Jšœžœ žœ ˜%Jšœžœžœ ˜Jšœžœ˜Jšœžœ˜Jšœžœ˜J˜&šžœ˜!Jšžœžœ˜šžœžœ˜Jšžœžœ˜Jšžœžœžœžœ ˜9——J˜——š ™šœžœžœ˜Jšœ˜Jšœ žœžœ˜Jšœ˜J˜ J˜J˜—šขœžœ#žœ˜CJšœžœ8˜Dšžœžœžœž˜&J˜(J˜9Jšœžœ žœžœ˜4šžœžœžœž˜'J˜,J˜>J˜,J˜>Jšœžœ žœžœ˜5šžœžœžœž˜%Jšœžœ žœžœ˜3Jšœžœ˜J˜1˜1Jšœ'˜'—Jšžœ˜—Jšžœ˜—Jšžœ˜—J˜J˜—šกœ˜,Jšœžœžœ ˜$J˜6J˜ J™&J˜*˜J˜Jšœžœžœ˜šœžœ˜Jšœ*˜*Jšœ)˜)—J˜%—J˜J˜—šขœ˜Jšœžœžœ ˜'J˜-Jšœžœ ˜0Jšœ žœ˜šžœžœžœž˜&J˜)Jšœžœžœžœ˜=šžœžœžœž˜$J˜*Jšœžœžœžœ˜;šžœžœžœž˜"Jšœžœžœžœ˜9J˜9Jšœžœ˜Jšœžœ˜!Jšœžœ$™1Jšœžœ˜+Jšžœžœžœ˜Jšœ+žœ žœžœ™QJšžœ˜—Jšžœ˜—Jšžœ˜—J˜J˜—šขœžœ žœžœ˜MJ˜—šข œ˜ Jšœžœžœ ˜'J˜GJ˜——š ™Jšœ žœžœ˜'šœžœžœ˜Jšœžœฃ˜0Jšœžœฃ˜=Jšœžœฃ˜5Jšœžœฃ ˜'Jšœžœฃ˜,Jšœฃ˜)Jšœ*ฃ˜>Jšœ)žœฃ˜KJšœžœฃ ˜-J˜J˜—šฯb œ˜&J˜<šžœ˜Jšžœžœ.˜9šžœ˜Jšœžœ˜#J˜TJ˜0J˜)˜J˜+šœ žœ˜J˜HJ˜5J˜ —šœ žœ˜J˜!J˜)J˜+—J˜J˜J˜ J˜ —Jšœ žœ#˜6J˜=Jšœ žœ ˜J˜5J˜?J˜J˜J˜——J˜J˜—šขœ˜*Jšœžœ˜+J˜Jšžœžœ˜.J˜J˜J˜—šก œ˜&Jšœžœ ˜#J˜&Jšžœžœ˜0J˜J˜—šคœ˜#Jšœžœ ˜#šขœžœ˜šžœž™JšžœC™G—J™;J˜—J˜%J˜J˜—šขœ˜%šคœ˜™Jš œžœžœžœžœ ™J—J˜—Jšœžœ ˜#šžœ ™Jšžœ)™-JšžœF™J—šžœž™š žœžœ2žœžœž™J™ Jšœ%žœžœžœ™S—Jšžœ™——J™UJ˜J˜—šขœžœ˜(J˜HJ˜J˜—šขœ˜#Jšœžœžœ$˜AJ˜J˜J˜J˜—šข œ4˜?J˜—šขœ˜Jšœžœžœ$˜AJšœ žœžœ žœ˜0Jšœžœžœ žœ˜LJšžœžœ˜/J˜——š ™Jšœ žœžœ ˜#šœ žœžœ˜Jšœžœฃ˜/Jšœžœฃ˜PW