ImplicitDesignCmdsAImpl.mesa
Copyright Ó 1985, 1990 by Xerox Corporation. All rights reserved.
Bloomenthal, August 11, 1992 4:06 pm PDT
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
Types
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;
Tube Design
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,
textureProc: TubeTexture,
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];
};
Curve Design
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];
};
Cone Design
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];
};
ConeValue: ValueProc ~ {
d: ConeData ¬ NARROW[clientData];
ax: REAL ¬ ABS[point.x];
IF ax > d.w THEN RETURN[-1.0] ELSE {
r: REAL ¬ ax*d.ratio;
RETURN[r*r-(point.y*point.y+point.z*point.z)];
};
};
ConeValue: ValueProc ~ {
d: ConeData ¬ NARROW[clientData];
ax: REAL ¬ ABS[point.x]+0.05;
IF ax > d.w THEN RETURN[-1.0] ELSE {
r: REAL ¬ ax*ax*d.ratio;
RETURN[0.05+r*r-(point.y*point.y+point.z*point.z)];
};
};
ConeDraw: DrawProc ~ {
d: ConeData ¬ NARROW[data];
G3dDraw.DrawCircle[context, [-d.w,d.h,0], [-d.w,0,d.h], [-d.w,-d.h,0], 30, d.tool.view];
G3dDraw.DrawCircle[context, [d.w,d.h,0], [d.w,0,d.h], [d.w,-d.h,0], 30, d.tool.view];
G3dDraw.DrawSegment[context, [-d.w, d.h, 0], [d.w, -d.h, 0], d.tool.view];
G3dDraw.DrawSegment[context, [-d.w, 0, d.h], [d.w, 0, -d.h], d.tool.view];
G3dDraw.DrawSegment[context, [-d.w, -d.h, 0], [d.w, d.h, 0], d.tool.view];
G3dDraw.DrawSegment[context, [-d.w, 0, -d.h], [d.w, 0, d.h], d.tool.view];
};
Stick Design
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;
};
Steiner Surface
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]]};
Miscellaneous Designs
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 ~ {
Kevin's pattern.
m: MiscData ¬ NEW[MiscDataRep];
m.tool ¬ ImplicitDesign.MakeTool[toolName: "Interference", valueProc: InterferenceValue, clientData: m, extraButtons: MiscButtons[m], toolSettings: [threshold: 0.0]];
};
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];
m.tool ¬ ImplicitDesign.MakeTool[toolName: "Implicit Ripple", valueProc: RippleValue,clientData: m, extraButtons: MiscButtons[m]];
};
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;
};
Support
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[];
};
Start Code
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.