<<>> <> <> <> 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.