<<>> <> <> <> DIRECTORY G3dDraw, G3dRayTrace, Commander, Controls, Convert, Draw2d, FileNames, G3dBasic, G3dMatrix, G3dSpline, G3dTool, G3dTube, G3dVector, Imager, ImagerColor, ImplicitDefs, ImplicitDesign, ImplicitSurface, ImplicitTube, ImplicitValue, IO, Menus, MessageWindow, RealFns, Rope, ViewerOps, ViewerTools; ImplicitDesignCmdsAImpl: CEDAR PROGRAM IMPORTS G3dDraw, Controls, Convert, FileNames, G3dSpline, G3dTool, G3dTube, G3dVector, ImplicitDesign, ImplicitSurface, ImplicitTube, ImplicitValue, IO, MessageWindow, RealFns, Rope, ViewerOps, ViewerTools ~ BEGIN <> CommandProc: TYPE ~ Commander.CommandProc; ButtonList: TYPE ~ Controls.ButtonList; Control: TYPE ~ Controls.Control; ControlProc: TYPE ~ Controls.ControlProc; OuterData: TYPE ~ Controls.OuterData; DrawProc: TYPE ~ Draw2d.DrawProc; Pair: TYPE ~ G3dBasic.Pair; Triple: TYPE ~ G3dBasic.Triple; TripleSequence: TYPE ~ G3dBasic.TripleSequence; TripleSequenceRep: TYPE ~ G3dBasic.TripleSequenceRep; Quad: TYPE ~ G3dBasic.Quad; RayProc: TYPE ~ G3dRayTrace.RayProc; NearSpline: TYPE ~ G3dSpline.NearSpline; Tube: TYPE ~ G3dTube.Tube; NearSegment: TYPE ~ G3dVector.NearSegment; CubeOkProc: TYPE ~ ImplicitDefs.CubeOkProc; StartProc: TYPE ~ ImplicitDefs.StartProc; TextureProc: TYPE ~ ImplicitDefs.TextureProc; ValueProc: TYPE ~ ImplicitDefs.ValueProc; VertexOkProc: TYPE ~ ImplicitDefs.VertexOkProc; DocProc: TYPE ~ ImplicitDesign.DocProc; Tool: TYPE ~ ImplicitDesign.Tool; ClickProc: TYPE ~ Menus.ClickProc; ROPE: TYPE ~ Rope.ROPE; <> TubeData: TYPE ~ REF TubeDataRep; TubeDataRep: TYPE ~ RECORD [ spheres: TripleSequence ¬ NIL, nSpheresButton: Controls.Button ¬ NIL, tool: Tool ¬ NIL, lines: BOOL ¬ FALSE, tube: Tube ¬ NIL ]; TubeCommand: CommandProc ~ { d: TubeData ¬ NEW[TubeDataRep]; d.tool ¬ ImplicitDesign.MakeTool[ name: "Tube", startProc: TubeStart, valueProc: TubeValue, <> client: [draw: TubeDraw, data: d], extraButtons: LIST[ d.nSpheresButton ¬ Controls.TextButton["NSpheres: ", "00", TubeNSpheres, d], Controls.ClickButton["Lines: Off", ToggleLines, d], Controls.ClickButton["Get Tube", TubeGet, d], Controls.ClickButton["Read Tube", TubeRead, d]], toolSettings: [threshold: 0.5, measureMode: $Segment]]; }; ToggleLines: ClickProc ~ { d: TubeData ¬ NARROW[clientData]; Controls.ButtonToggle[ d.tool.renderTool.outerData, d.lines ¬ NOT d.lines, "Lines: On", "Lines: Off"]; }; TubeNSpheres: ClickProc ~ { d: TubeData ¬ NARROW[clientData]; nSpheres: CARD ¬ Convert.IntFromRope[ViewerTools.GetContents[d.nSpheresButton.textViewer]]; IF d.tube = NIL THEN RETURN; IF d.spheres = NIL OR nSpheres > d.spheres.maxLength THEN { d.spheres ¬ NEW[TripleSequenceRep[nSpheres]]; }; d.spheres.length ¬ nSpheres; FOR n: NAT IN [0..d.spheres.length) DO d.spheres[n] ¬ G3dSpline.Position[d.tube.spline, REAL[n]/REAL[d.spheres.length-1]]; ENDLOOP; }; TubeValue: ValueProc ~ { d: TubeData ¬ NARROW[clientData]; t: Tool ¬ d.tool; SELECT TRUE FROM d.tube = NIL => ImplicitDesign.StopTool[d.tool, "First get a tube."]; d.spheres # NIL AND d.spheres.length # 0 => { nSphere: NAT; max: REAL ¬ 100000.0; FOR n: NAT IN [0..d.spheres.length) DO dist: REAL ¬ G3dVector.SquareDistance[point, d.spheres[n]]; IF dist < max THEN {nSphere ¬ n; max ¬ dist}; ENDLOOP; value ¬ IF t.distanceMode = inverse THEN d.tube.r0/MAX[0.0001, RealFns.SqRt[max]] ELSE d.tube.r0*d.tube.r0/MAX[0.0001, max]; } ENDCASE => value ¬ ImplicitTube.SampleTube[ point, d.tube, t.measureMode, t.distanceMode, t.tolerance, t.spread].value; }; TubeTexture: TextureProc ~ { d: TubeData ¬ NARROW[clientData]; IF d.tube = NIL THEN ImplicitDesign.StopTool[d.tool, "First get a tube."] ELSE RETURN[ImplicitTube.TextureOfTube[vertex.point, d.tube]]; }; TubeStart: StartProc ~ { d: TubeData ¬ NARROW[clientData]; IF nFrames > 1 THEN { -- we do some self-styled animation: t: REAL ¬ REAL[frame]/REAL[nFrames]; angle: REAL ¬ 90.0-180.0*t; p1: Triple ¬ [RealFns.CosDeg[angle], RealFns.SinDeg[angle], 0.0]; d.tube ¬ NEW[G3dTube.TubeRep ¬ [p0:[0,-1,0], p1:[0,0,0], v0:[0,0.5,0], v1:[0,0.5,0]]]; d.tube.next ¬ NEW[G3dTube.TubeRep ¬ [p0:[0,0,0], p1:[0,1,0], v0:[0,0.5,0], v1:[0,0.5,0]]]; d.tube.branches ¬ NEW[G3dTube.TubeSequenceRep[1]]; d.tube.branches.length ¬ 1; d.tube.branches[0] ¬ NEW[G3dTube.TubeRep ¬ [p0:[0,0,0], p1:p1, v0:[0,1,0], v1:p1]]; G3dTube.SetSpline[d.tube]; G3dTube.SelectAll[d.tube]; G3dTube.SetRadii[d.tube, 0.1]; ImplicitTube.PrepareTube[d.tube, inverse, d.tool.measureMode]; } ELSE IF d.tube = NIL THEN {ImplicitDesign.StopTool[d.tool, "First get a tube."]; RETURN}; point ¬ IF d.spheres # NIL AND d.spheres.length # 0 AND G3dTube.NBranches[d.tube] = 0 THEN G3dVector.ScaleRay[[d.tube.p0,G3dVector.Unit[G3dVector.Ortho[d.tube.v0]]],d.tube.r0] ELSE ImplicitTube.StartPoint[d.tube, TubeValue, d.tool.threshold, d.tool.measureMode, .75, d]; }; TubeDraw: DrawProc ~ { d: TubeData ¬ NARROW[clientData]; view: G3dTool.View ¬ G3dTool.GetView[viewer]; G3dTube.DrawSplines[context, d.tube, view.camera.matrix, view.viewport]; IF d.lines THEN G3dTube.DrawLines[context, d.tube, view.camera.matrix, view.viewport]; }; TubeGet: ClickProc ~ {GetTube[NARROW[clientData]]}; TubeRead: ClickProc ~ { d: TubeData ¬ NARROW[clientData]; tube: Tube ¬ ReadTube[d.tool]; IF tube # NIL THEN NewTube[d, tube]; }; GetTube: PROC [d: TubeData] ~ { tube: Tube ¬ G3dTube.CopyEntireTube[G3dTube.First[G3dTube.LastTubePicked[]]]; IF tube = NIL THEN Blink["No selected tube -- try ReadTube"] ELSE NewTube[d, tube]; }; ReadTube: PROC [tool: Tool] RETURNS [tube: Tube] ~ { r: ROPE ¬ FileNames.ResolveRelativePath[Controls.TypescriptReadFileName[tool.typescript]]; tube ¬ G3dTube.TubeFromFile[r]; IF tube = NIL THEN Blink[IO.PutFR["Can't open %g\n", IO.rope[r]]]; }; NewTube: PROC [d: TubeData, tube: Tube] ~ { G3dTube.SelectAll[d.tube ¬ tube]; IF G3dTube.NBranches[d.tube] = 0 THEN d.tool.measureMode ¬ $Sum; ImplicitTube.PrepareTube[tube, d.tool.distanceMode, d.tool.measureMode]; ImplicitDesign.Reset[d.tool]; }; <> CurveData: TYPE ~ REF CurveDataRep; CurveDataRep: TYPE ~ RECORD [ tool: Tool ¬ NIL, tube: Tube ¬ NIL, mode: {points, spline, kspline} ¬ points, npoints: NAT ¬ 260, points: TripleSequence ¬ NIL ]; CurveCommand: CommandProc ~ { d: CurveData ¬ NEW[CurveDataRep]; d.tool ¬ ImplicitDesign.MakeTool[ name: "Curve", startProc: CurveStart, valueProc: CurveValue, client: [draw: CurveDraw, data: d], extraButtons: LIST[ Controls.ClickButton["NPoints", CurveNPoints, d], Controls.ClickButton["Points", CurveMode, d], Controls.ClickButton["Read Tube", CurveRead, d]], toolSettings: [threshold: 0.0] ]; }; CurveMode: ClickProc ~ { d: CurveData ¬ NARROW[clientData]; outerData: OuterData ¬ d.tool.renderTool.outerData; SELECT d.mode FROM points => {Controls.ButtonRelabel[outerData, "Points", "Spline"]; d.mode ¬ spline}; spline => {Controls.ButtonRelabel[outerData, "Spline", "KSpline"]; d.mode ¬ kspline}; kspline => {Controls.ButtonRelabel[outerData, "KSpline", "Points"]; d.mode ¬ points}; ENDCASE; }; CurveValue: ValueProc ~ { d: CurveData ¬ NARROW[clientData]; SELECT d.mode FROM points => { index: NAT; min: REAL ¬ 100000.0; FOR n: NAT IN [0..d.npoints) DO dist: REAL ¬ G3dVector.SquareDistance[d.points[n], point]; IF dist < min THEN {min ¬ dist; index ¬ n}; ENDLOOP; RETURN[0.05-RealFns.SqRt[min]]; }; spline => { near3d: NearSpline ¬ G3dSpline.PreciseNearestPoint[point, d.tube.spline]; RETURN[0.05-near3d.distance]; }; kspline => { near3d: NearSpline ¬ G3dSpline.PreciseNearestPoint[point, d.tube.spline]; rad: REAL ¬ G3dTube.Radius[d.tube, near3d.t]; k: REAL ¬ G3dSpline.CurvatureMag[d.tube.spline, near3d.t]; v: REAL ¬ ImplicitValue.OfPoint[point, near3d.point, rad, d.tool.distanceMode].value; f: REAL ¬ 1.0+RealFns.Log[10, MAX[0.1, k]]; RETURN[v+0.2*f-1.0]; }; ENDCASE; }; CurveStart: StartProc ~ { d: CurveData ¬ NARROW[clientData]; t: Tool ¬ d.tool; IF d.tube = NIL THEN ImplicitDesign.StopTool[d.tool, "First get a tube."]; SELECT d.mode FROM points, spline => { out: Triple ¬ G3dVector.ScaleRay[[d.tube.p0, G3dVector.Unit[G3dVector.Ortho[d.tube.v0]]], 0.1]; RETURN[ImplicitSurface.SurfacePoint[d.tube.p0, out, CurveValue, t.threshold, d]]; }; ENDCASE => RETURN[ ImplicitTube.StartPoint[d.tube, CurveValue, t.threshold, t.measureMode, t.spread, d]]; }; CurveDraw: DrawProc ~ { d: CurveData ¬ NARROW[clientData]; view: G3dTool.View ¬ G3dTool.GetView[viewer]; G3dTube.DrawSplines[context, d.tube, view.camera.matrix, view.viewport]; }; CurvePoints: PROC [d: CurveData] ~ { IF d.points = NIL OR d.points.length < d.npoints THEN d.points ¬ NEW[TripleSequenceRep[d.npoints]]; FOR n: NAT IN [0..d.npoints) DO d.points[n] ¬ G3dSpline.Position[d.tube.spline, REAL[n]/REAL[d.npoints-1]]; ENDLOOP; }; CurveNPoints: ClickProc ~ { d: CurveData ¬ NARROW[clientData]; d.npoints ¬ Controls.GetNat[d.tool.typescript, "NPoints", d.npoints]; CurvePoints[d]; }; CurveRead: ClickProc ~ { d: CurveData ¬ NARROW[clientData]; IF (d.tube ¬ ReadTube[d.tool]) # NIL THEN CurvePoints[d]; }; <> ConeData: TYPE ~ REF ConeDataRep; ConeDataRep: TYPE ~ RECORD [tool: Tool, w, h, x, tip, lim, ratio, rad, rad2, vok: REAL]; ConeCommand: CommandProc ~ { d: ConeData ¬ NEW[ConeDataRep]; ConeSet[d, 1.0, 0.75]; d.tool ¬ ImplicitDesign.MakeTool[ name: "Cone", startProc: ConeStart, valueProc: ConeValue, vertexOkProc: ConeVertexOk, client: [draw: ConeDraw, data: d], extraButtons: LIST[ Controls.TextButton["Width: ", "1.00", ConeButton, d], Controls.TextButton["Height: ", "0.75", ConeButton, d]], toolSettings: [threshold: 0.0]]; }; ConeButton: ClickProc ~ { E: PROC [rope: ROPE] RETURNS [BOOL] ~ {RETURN[Rope.Equal[button.name, rope, FALSE]]}; N: PROC [o: REAL] RETURNS [r: REAL] ~ { rope: ROPE ¬ ViewerTools.GetContents[button.textViewer]; r ¬ Convert.RealFromRope[rope ! Convert.Error => {Blink["Bad value"]; r ¬ o; CONTINUE}]; }; d: ConeData ¬ NARROW[clientData]; button: Controls.Button ¬ NARROW[ViewerOps.FetchProp[parent, $ButtonText]]; SELECT TRUE FROM E["Width: "] => d.w ¬ ABS[N[d.w]]; E["Height: "] => d.h ¬ ABS[N[d.h]]; ENDCASE => RETURN; ConeSet[d, d.w, d.h]; ImplicitDesign.Repaint[d.tool]; }; ConeSet: PROC [d: ConeData, w, h: REAL] ~ { d.ratio ¬ IF (d.w ¬ ABS[w]) # 0.0 THEN (d.h ¬ ABS[h])/d.w ELSE (d.h ¬ ABS[h]); d.rad ¬ d.h/8.0; d.rad2 ¬ d.rad*d.rad; d.vok ¬ -d.w-0.001; d.x ¬ -d.rad/d.ratio; d.tip ¬ 0.5*d.w; d.lim ¬ d.tip+d.rad; }; ConeVertexOk: VertexOkProc ~ { d: ConeData ¬ NARROW[clientData]; RETURN[point.x > d.vok]; }; <<>> ConeValue: ValueProc ~ { d: ConeData ¬ NARROW[clientData]; SELECT point.x FROM < -d.w, > d.lim => RETURN[-1.0]; < d.x => { r: REAL ¬ point.x*d.ratio; RETURN[r*r-(point.y*point.y+point.z*point.z)]; }; < d.tip => RETURN[d.rad2-(point.y*point.y+point.z*point.z)]; ENDCASE => { dx: REAL ¬ point.x-d.tip; RETURN[d.rad2-(dx*dx+point.y*point.y+point.z*point.z)]; }; }; ConeStart: StartProc ~ { d: ConeData ¬ NARROW[clientData]; RETURN[[-d.w, d.h, 0.0]]; }; ConeDraw: DrawProc ~ { d: ConeData ¬ NARROW[clientData]; view: G3dMatrix.Matrix ¬ G3dTool.GetView[viewer].camera.matrix; vp: G3dMatrix.Viewport ¬ G3dTool.GetView[viewer].viewport; G3dDraw.DrawCircle[context, [-d.w,d.h,0], [-d.w,0,d.h], [-d.w,-d.h,0], 30, view, vp]; G3dDraw.DrawSegment[context, [-d.w, d.h, 0], [0, 0, 0], view, vp]; G3dDraw.DrawSegment[context, [-d.w, 0, d.h], [0, 0, 0], view, vp]; G3dDraw.DrawSegment[context, [-d.w, -d.h, 0], [0, 0, 0], view, vp]; G3dDraw.DrawSegment[context, [-d.w, 0, -d.h], [0, 0, 0], view, vp]; G3dDraw.DrawSegment[context, [d.x, d.rad, 0], [d.tip, d.rad, 0], view, vp]; G3dDraw.DrawSegment[context, [d.x, -d.rad, 0], [d.tip, -d.rad, 0], view, vp]; G3dDraw.DrawSegment[context, [d.x, 0, d.rad], [d.tip, 0, d.rad], view, vp]; G3dDraw.DrawSegment[context, [d.x, 0, -d.rad], [d.tip, 0, -d.rad], view, vp]; G3dDraw.DrawCircle[context,[d.tip,d.rad,0],[d.tip+d.rad,0,0],[d.tip,-d.rad,0],10, view, vp]; G3dDraw.DrawCircle[context,[d.tip,0,d.rad],[d.tip+d.rad,0,0],[d.tip,0,-d.rad],10, view, vp]; }; <> <> <> < d.w THEN RETURN[-1.0] ELSE {>> <> <> <<};>> <<};>> <<>> <> <> <> < d.w THEN RETURN[-1.0] ELSE {>> <> <> <<};>> <<};>> <> <> <> <> <> <> <> <> <<};>> <> Stick: TYPE ~ RECORD [ p0, p1: Triple ¬ [0.0, 0.0, 0.0], acc: Quad ¬ [0.0, 0.0, 0.0, 0.0], r0, r1: REAL ¬ 0.0]; StickSequence: TYPE ~ REF StickSequenceRep; StickSequenceRep: TYPE ~ RECORD [ length: CARDINAL ¬ 0, element: SEQUENCE maxLength: CARDINAL OF Stick ]; StickData: TYPE ~ REF StickDataRep; StickDataRep: TYPE ~ RECORD [tool: Tool, sticks: StickSequence]; nullStick: Stick ¬ []; StickCommand: CommandProc ~ { d: StickData ¬ NEW[StickDataRep]; d.sticks ¬ NEW[StickSequenceRep[100]]; d.tool ¬ ImplicitDesign.MakeTool[ name: "Stick", startProc: StickStart, valueProc: StickValue, client: [draw: StickDraw, data: d], extraButtons: LIST[ Controls.ClickButton["Add Stick", StickAdd, d], Controls.ClickButton["Delete Stick", StickDelete, d], Controls.ClickButton["Delete All", StickAllDelete, d]]]; }; StickGet: PROC [tool: Tool] RETURNS [stick: Stick] ~ { n0, n1: NAT ¬ 0; reals: ARRAY [0..8) OF REAL; NextRope: PROC RETURNS [ROPE] ~ { IF (n0 ¬ Rope.SkipOver[reply, n1, " \t"]) = Rope.Length[reply] THEN RETURN[NIL]; n1 ¬ Rope.SkipTo[reply, n0, " \t"]; RETURN[Rope.Substr[reply, n0, n1-n0]]; }; reply: ROPE ¬ Controls.TypescriptRead[tool.typescript, "Add stick (x1,y1,z1,r1,x2,y2,z2,r2): "]; IF reply # NIL THEN FOR n: NAT IN [0..8) DO reals[n] ¬ Convert.RealFromRope[NextRope[] ! Convert.Error => GOTO BadFormat]; ENDLOOP; stick.p0 ¬ [reals[0], reals[1], reals[2]]; stick.p1 ¬ [reals[4], reals[5], reals[6]]; stick.r0 ¬ reals[3]; stick.r1 ¬ reals[7]; stick.acc ¬ G3dVector.NearnessAccelerator[stick.p0, stick.p1]; EXITS BadFormat => Controls.TypescriptWrite[tool.typescript, "Bad Format"]; }; StickAdd: ClickProc ~ { d: StickData ¬ NARROW[clientData]; stick: Stick ¬ StickGet[d.tool]; IF stick # nullStick THEN { d.sticks[d.sticks.length] ¬ stick; d.sticks.length ¬ d.sticks.length+1; ImplicitDesign.Repaint[d.tool]; }; }; StickDelete: ClickProc ~ { d: StickData ¬ NARROW[clientData]; stick: Stick ¬ StickGet[d.tool]; FOR n: NAT IN [0..d.sticks.length) DO IF d.sticks[n] = stick THEN { FOR nn: NAT IN [n..d.sticks.length-1) DO d.sticks[nn] ¬ d.sticks[nn+1]; ENDLOOP; d.sticks.length ¬ d.sticks.length-1; EXIT; }; ENDLOOP; ImplicitDesign.Repaint[d.tool]; }; StickAllDelete: ClickProc ~ { d: StickData ¬ NARROW[clientData]; d.sticks.length ¬ 0; ImplicitDesign.Repaint[d.tool]; }; StickValue: ValueProc ~ { d: StickData ¬ NARROW[clientData]; FOR n: NAT IN [0..d.sticks.length) DO s: Stick ¬ d.sticks[n]; near: NearSegment ¬ G3dVector.NearestToSegment[s.p0, s.p1, point, s.acc]; strength: REAL ¬ IF s.r0 # s.r1 THEN near.w0*s.r0+near.w1*s.r1 ELSE s.r0; value ¬ value+ImplicitValue.OfPoint[point, near.point, strength, inverseSqrd].value; ENDLOOP; }; StickStart: StartProc ~ { d: StickData ¬ NARROW[clientData]; s: Stick ¬ d.sticks[0]; pIn, pOut, v: Triple ¬ s.p0; v ¬ G3dVector.Unit[G3dVector.Ortho[G3dVector.Sub[s.p1, s.p0]]]; pOut ¬ G3dVector.ScaleRay[[s.p0, v], s.r0]; WHILE StickValue[pOut, d, NIL] > 0.0 DO pOut ¬ G3dVector.ScaleRay[[pOut, v], s.r0]; ENDLOOP; point ¬ ImplicitSurface.SurfacePoint[pIn, pOut, StickValue, d.tool.threshold, d]; }; StickDraw: DrawProc ~ { d: StickData ¬ NARROW[clientData]; v: G3dTool.View ¬ G3dTool.GetView[viewer]; FOR n: NAT IN [0..d.sticks.length) DO G3dDraw.DrawSegment[context, d.sticks[n].p0, d.sticks[n].p1, v.camera.matrix, v.viewport]; ENDLOOP; }; <> SteinerCommand: CommandProc ~ { [] ¬ ImplicitDesign.MakeTool[ name: "Steiner", startProc: SteinerStart, valueProc: SteinerValue, toolSettings: [trackSize: 0.02, threshold: 0.0]] }; SteinerValue: ValueProc ~ { xSq: REAL ¬ point.x*point.x; ySq: REAL ¬ point.y*point.y; zSq: REAL ¬ point.z*point.z; RETURN[xSq*ySq+xSq*zSq+ySq*zSq+point.x*point.y*point.z]; }; SteinerStart: StartProc ~ {RETURN[[0.0, 0.0, 0.0]]}; <> MiscData: TYPE ~ REF MiscDataRep; MiscDataRep: TYPE ~ RECORD [ tool: Tool ¬ NIL, aConstant: REAL ¬ 1.0, kConstant: REAL ¬ 1.0, vConstant: REAL ¬ 1.0 ]; MiscButtons: PROC [r: REF ANY] RETURNS [ButtonList] ~ { RETURN[LIST[ Controls.TextButton["A: ", "1.000", MiscButton, r], Controls.TextButton["K: ", "1.000", MiscButton, r], Controls.TextButton["V: ", "1.000", MiscButton, r]]]; }; MiscButton: ClickProc ~ { E: PROC [rope: ROPE] RETURNS [BOOL] ~ {RETURN[Rope.Equal[button.name, rope, FALSE]]}; N: PROC [o: REAL] RETURNS [r: REAL] ~ { rope: ROPE ¬ ViewerTools.GetContents[button.textViewer]; r ¬ Convert.RealFromRope[rope ! Convert.Error => {Blink["Bad value"]; r ¬ o; CONTINUE}]; }; m: MiscData ¬ NARROW[clientData]; button: Controls.Button ¬ NARROW[ViewerOps.FetchProp[parent, $ButtonText]]; SELECT TRUE FROM E["A: "] => m.aConstant ¬ N[m.aConstant]; E["K: "] => m.kConstant ¬ N[m.kConstant]; E["V: "] => m.vConstant ¬ N[m.vConstant]; ENDCASE; }; InterferenceCommand: CommandProc ~ { <> m: MiscData ¬ NEW[MiscDataRep]; <> }; InterferenceValue: ValueProc ~ { m: MiscData ¬ NARROW[clientData]; x2: REAL ~ point.x+point.x; xSq: REAL ~ point.x*point.x+1.0; ySq: REAL ~ point.y*point.y; zSq: REAL ~ point.z*point.z; IF NOT InBounds[point, 1.5] THEN RETURN[-1.0]; RETURN[ RealFns.Sin[m.kConstant*(xSq-x2+ySq+zSq)]+ RealFns.Sin[m.kConstant*(xSq+x2+ySq+zSq)]]; }; RippleCommand: CommandProc ~ { m: MiscData ¬ NEW[MiscDataRep]; <> }; RippleValue: ValueProc ~ { m: MiscData ¬ NARROW[clientData]; centers: ARRAY [0..4) OF Pair ~ [[0.0, 0.0], [0.2, 0.3], [-0.1, 0.4], [-0.2, -0.2]]; value ¬ m.vConstant*point.z; IF NOT InBounds[point, 1.5] THEN RETURN[-1.0]; FOR n: NAT IN [0..4) DO center: Pair ¬ centers[n]; y: REAL ~ center.y; dx: REAL ~ point.x-center.x; dy: REAL ~ point.y-center.y; dxSq: REAL ~ dx*dx; value ¬ value+ RealFns.Sin[m.kConstant*(dxSq+dy*dy)]*RealFns.Exp[-m.aConstant*(dxSq+y*y)]; ENDLOOP; }; <> InBounds: PROC [t: Triple, bound: REAL] RETURNS [ok: BOOL] ~ { ok ¬ t.x IN [-bound..bound] AND t.y IN [-bound..bound] AND t.z IN [-bound..bound]; }; Blink: PROC [message: ROPE] ~ { MessageWindow.Append[message, TRUE]; MessageWindow.Blink[]; }; <> ImplicitDesign.Register["Cone", ConeCommand, "explore a cone shape."]; ImplicitDesign.Register["Stick", StickCommand, "explore a stick shape."]; ImplicitDesign.Register["Steiner", SteinerCommand, "explore a steiner shape."]; ImplicitDesign.Register["Curve", CurveCommand, "explore various curve designs."]; ImplicitDesign.Register["Tube", TubeCommand, "explore various tube and web designs."]; ImplicitDesign.Register["Ripple", RippleCommand, "explore the shape of ripples."]; ImplicitDesign.Register["Interference", InterferenceCommand, "interference pattern shape."]; END.