ImplicitSimpleCmdImpl.mesa
Copyright Ó 1985, 1990 by Xerox Corporation. All rights reserved.
Bloomenthal, February 20, 1993 6:06 pm PST
DIRECTORY Commander, Controls, G3dBasic, G3dDraw, G3dOctree, G3dTool, G3dVector, ImplicitDesign, ImplicitMinimal, ImplicitValue, MessageWindow, RealFns, Rope, Vector2, ViewerClasses;
ImplicitSimpleCmdImpl: CEDAR PROGRAM
IMPORTS Controls, G3dDraw, G3dTool, G3dVector, ImplicitDesign, ImplicitValue, MessageWindow, RealFns, Rope, Vector2
~ BEGIN
Types
Triple:    TYPE ~ G3dBasic.Triple;
TripleSequence:  TYPE ~ G3dBasic.TripleSequence;
Tool:     TYPE ~ ImplicitDesign.Tool;
Function:    TYPE ~ ImplicitMinimal.Function;
Source3dSequence: TYPE ~ ImplicitValue.Source3dSequence;
ROPE:     TYPE ~ Rope.ROPE;
ClickProc:   TYPE ~ ViewerClasses.ClickProc;
Simple Surfaces
Op:   TYPE ~ {union, sphere, cylinder, torus, plane, wiffle, blob,
       fourPoleBlob, ellipsoid, doubleCone, saddle, tubularCorner, teapotTop};
SimpleData:   TYPE ~ REF SimpleDataRep;
SimpleDataRep:  TYPE ~ RECORD [
tool:       Tool ¬ NIL,
op:       Op ¬ sphere,      -- which of simple objects
points:      TripleSequence ¬ NIL,   -- for quick drawing of sphere
cylLength:     REAL ¬ 0.0,      -- half length of cylinder
r:        REAL ¬ 0.0,      -- radius of cylinder, sphere, torus
r2:        REAL ¬ 0.0,      -- radius squared
rr:        REAL ¬ 0.0,      -- minor torus radius
rr2, r4, rr4, a, b, c:   REAL ¬ 0.0,      -- accelerators for torus
blobSeparation:    REAL ¬ 0.185,     -- distance between blob centers
blobbiness:     REAL ¬ 0.0,      -- blobbiness between two centers
blobSources:     Source3dSequence ¬ NIL,  -- blob centers
sphereCount:     INTEGER ¬ 0
savedOctreeType:   OctreeType ¬ track,
doInspect:     BOOL ¬ FALSE,     -- inspect a cube?
doDual:      BOOL ¬ FALSE,     -- ??
root:       Cube ¬ NIL,      -- the root of the octree
inspect:      Cube ¬ NIL,      -- moving, inspecting cube
oldInspect:     Cube ¬ NIL,      -- previous inspecting cube
doClip:      BOOL ¬ FALSE,     -- clip the sphere?
];
SimpleCommand: Commander.CommandProc ~ {
s: SimpleData ~ NEW[SimpleDataRep];
Setup[s, 0.1];
s.tool ¬ ImplicitDesign.MakeTool[
name: "Simple",
function: Value,
start: Start,
client: [draw: Draw, data: s],
extraButtons: LIST[
Controls.ClickButton["Radius", Radius, s],
Controls.ClickButton["BSep", BlobSeparation, s],
Controls.ClickButton["Bness", Blobbiness, s],
Controls.ClickButton["L", Move, s],
Controls.ClickButton["R", Move, s],
Controls.ClickButton["B", Move, s],
Controls.ClickButton["T", Move, s],
Controls.ClickButton["N", Move, s],
Controls.ClickButton["F", Move, s],
Controls.ClickButton["Up", Up, s],
Controls.ClickButton["Down", Down, s],
Controls.ClickButton["?", Query, s],
Controls.ClickButton["Type: sphere", SimpleCycle, s]],
useArcBalls: FALSE,
camera: [[0, 2, 0], [], 2.5, 60],
toolSettings: [level: 0.0]
];
};
Start: ImplicitDesign.StartProc ~ {
s: SimpleData ¬ NARROW[clientData];
point ¬ IF s.op = wiffle THEN [0.6605536, -1.449449, 1.804281] ELSE [];
};
Setup: PROC [s: SimpleData, radius: REAL] ~ {
s.r ¬ radius;    -- radius for sphere, cylinder, major radius for torus
s.cylLength ¬ 2.0*s.r;
s.points ¬ G3dDraw.GetSpherePoints[[0.0, 0.0, 0.0], s.r, 10];
s.rr ¬ 0.2*radius;  -- minor radius for torus
s.r2 ¬ s.r*s.r;
s.rr2 ¬ s.rr*s.rr;
s.r4 ¬ s.r2*s.r2;
s.rr4 ¬ s.rr2*s.rr2;
s.a ¬ s.r2+s.rr2;
s.b ¬ s.r2-s.rr2;
s.c ¬ s.r2*s.rr2;
s.blobSources ¬ NEW[ImplicitValue.Source3dSequenceRep[2]];
s.blobSources.length ¬ 2;
s.blobSources[0] ¬ [[-0.5*s.blobSeparation, 0.0, 0.0], s.r, 1.0/(s.r*s.r)];
s.blobSources[1] ¬ [[0.5*s.blobSeparation, 0.0, 0.0], 0.5*s.r, 1.0/(0.5*0.5*s.r*s.r)];
After surface computed: SetBlobColors[p.surface, blobSources];
};
Value: Function ~ {
s: SimpleData ¬ NARROW[clientData];
SELECT s.op FROM
union => {
size: 0.1
c1: Triple ¬ [-.15, 0, 0]; r1: REAL ¬ 0.35;
c2: Triple ¬ [0.5, 0, 0];  r2: REAL ¬ 0.5;
RETURN[MAX[r1-G3dVector.Distance[point, c1], r2-G3dVector.Distance[point, c2]]];
};
blob => {
IF s.blobbiness < 0.0
THEN FOR n: NAT IN [0..s.blobSources.length) DO
b: ImplicitValue.Source3d ¬ s.blobSources[n];
rSqrd: REAL ¬ G3dVector.SquareDistance[b.p, point];
rR: REAL ¬ rSqrd*b.sInvSqrd;
exp: REAL ¬ s.blobbiness*(rR-1.0);
IF exp > 50.0 THEN RETURN[1000.0];
IF exp > -50.0 THEN value ¬ value+RealFns.Exp[exp];
ENDLOOP
ELSE value ¬ ImplicitValue.OfSources3d[point, s.blobSources, inverseSqrd];
value ¬ value-1.0;
};
wiffle => {
ax: REAL ¬ point.x/2.4; bx: REAL ¬ point.x/2.0;
ay: REAL ¬ point.y/2.4; by: REAL ¬ point.y/2.0;
az: REAL ¬ point.z/2.4; bz: REAL ¬ point.z/2.0;
bx2: REAL ¬ bx*bx; by2: REAL ¬ by*by; bz2: REAL ¬ bz*bz;
bx4: REAL ¬ bx2*bx2; by4: REAL ¬ by2*by2; bz4: REAL ¬ bz2*bz2;
terma: REAL ¬ ax*ax+ay*ay+az*az;
termb: REAL ¬ bx4*bx4+by4*by4+bz4*bz4;
terma2: REAL ¬ terma*terma; termb2: REAL ¬ termb*termb;
terma6: REAL ¬ terma2*terma2*terma2; termb6: REAL ¬ termb2*termb2*termb2;
value ¬ (1.0-termb6-1.0/terma6);
};
sphere => {
s.sphereCount ¬ s.sphereCount+1;
value ¬ s.r2-G3dVector.Square[point];
value ¬ IF s.doClip AND point.x < -0.321
THEN -1.0 ELSE s.r2-G3dVector.Square[point];
};
cylinder => value ¬ s.r2-(SELECT point.x FROM
< -s.cylLength => G3dVector.SquareDistance[point, [-s.cylLength, 0.0, 0.0]],
> s.cylLength => G3dVector.SquareDistance[point, [ s.cylLength, 0.0, 0.0]],
ENDCASE => Vector2.Square[[point.y, point.z]]);
torus => {
Try (x2+y2+z2+R2-r2)2-4R2(y2+z2)
x2: REAL ~ point.x*point.x;
y2: REAL ~ point.y*point.y;
z2: REAL ~ point.z*point.z;
u: REAL ¬ x2+y2+z2+s.r2-s.rr2;
value ¬ u*u-4*s.r2*(y2+z2);
-(x2*x2+y2*y2+z2*z2+s.r4+s.rr4+2.*(x2*y2+x2*z2+y2*z2-s.a*x2+s.b*y2-s.a*z2-s.c));
};
plane => value ¬ point.y;
fourPoleBlob => {
x2: REAL ¬ point.x*point.x;
y2: REAL ¬ point.y*point.y;
z2: REAL ¬ point.z*point.z;
value ¬ x2*y2+x2*z2+y2*z2+7.0*point.x*point.y*point.z+x2+y2+z2-1;
};
ellipsoid => value ¬ point.x*point.x+point.y*point.y+4.0*point.z*point.z-1.0;
doubleCone => value ¬ point.x*point.x+point.y*point.y-0.8*point.z*point.z-0.3;
saddle => value ¬ 3.0*point.x*point.x-point.y*point.y+2.0*point.z;
tubularCorner => {
x2: REAL ¬ point.x*point.x;
y2: REAL ¬ point.y*point.y;
z2: REAL ¬ point.z*point.z;
value ¬ x2*y2+x2*z2+y2*z2+point.x+point.y-point.z+1.0;
};
teapotTop => {
z2: REAL ¬ point.z*point.z;
value ¬ point.x*point.x+point.y*point.y+point.z*z2+1.8*z2-1.0;
};
ENDCASE;
};
Radius: ClickProc ~ {
s: SimpleData ¬ NARROW[clientData];
s.r ¬ ReadValue[s.tool, "Radius", s.r];
Setup[s, s.r];
};
BlobSeparation: ClickProc ~ {
s: SimpleData ¬ NARROW[clientData];
s.blobSeparation ¬ ReadValue[s.tool, "Blob separation", s.blobSeparation];
s.blobSources[0].p ¬ [-0.5*s.blobSeparation, 0.0, 0.0];
s.blobSources[1].p ¬ [0.5*s.blobSeparation, 0.0, 0.0];
};
Blobbiness: ClickProc ~ {
s: SimpleData ¬ NARROW[clientData];
s.blobbiness ¬ ReadValue[s.tool, "Blobbiness (< 0)", s.blobbiness];
};
Draw: G3dTool.DrawProc ~ {
s: SimpleData ¬ NARROW[clientData];
SELECT s.op FROM
blob => {
G3dDraw.Sphere[context, s.blobSources[0].p, s.blobSources[0].strength, 8, view, vp];
G3dDraw.Sphere[context, s.blobSources[1].p, s.blobSources[1].strength, 8, view, vp];
};
sphere => G3dDraw.Sphere[context, [0.0, 0.0, 0.0], s.r, 10, view, vp, s.points];
ENDCASE;
};
SimpleCycle: ClickProc ~ {
Roper: PROC [op: Op] RETURNS [name: ROPE] ~ {
name ¬ Rope.Concat["Type: ", SELECT op FROM
sphere => "sphere",
cylinder => "cylinder",
torus => "torus",
plane => "plane",
wiffle => "wiffle",
union => "union",
blob => "blob",
fourPoleBlob => "four pole blob",
ellipsoid => "ellipsoid",
doubleCone => "double cone",
saddle => "saddle",
tubularCorner => "tubular corner",
teapotTop => "teapot top",
ENDCASE => NIL];
};
requests: LIST OF Controls.Request ¬ LIST[
--1-- ["sphere", "a sphere of the given radius"],
--2-- ["cylinder", "a cylinder of the given radius"],
--3-- ["torus", "a torus of given minor and major radii"],
--4-- ["plane", "the xz plane"],
--5-- ["wiffle", "the rounded edges of a cube"],
--6-- ["union", "the union of two spheres"],
--7-- ["blob", "the blobby combination of sources"],
--8-- ["fourPoleBlob", "blobby of four elements"],
--9-- ["ellipsoid", "ellipsoidal shape"],
--10-- ["doubleCone", "two cones"],
--11-- ["saddle", "saddle surface"],
--12-- ["tubularCorner", "corners"],
--13-- ["teapotTop", "top of a teapot"]
];
d: SimpleData ~ NARROW[clientData];
old: Op ~ d.op;
d.op ¬ SELECT Controls.PopUpRequest[["Simple Functions"], requests] FROM
1 => sphere, 2 => cylinder, 3 => torus, 4 => plane, 5 => wiffle, 6 => union, 7 => blob,
8 => fourPoleBlob, 9 => ellipsoid, 10 => doubleCone, 11 => saddle, 12 => tubularCorner,
13 => teapotTop,
ENDCASE => d.op;
IF old = blob THEN d.tool.octreeType ¬ d.savedOctreeType;
IF d.op = blob THEN {
d.savedOctreeType ¬ d.tool.octreeType;
d.tool.octreeType ¬ track;
};
Controls.ButtonRelabel[d.tool.tool3d.outerData, Roper[old], Roper[d.op]];
IF mouseButton = blue THEN ImplicitDesign.Repaint[d.tool, $Client];
};
Support
TSWrite: PROC [s: SimpleData, r: ROPE] ~{G3dTool.TSWrite[s.tool.tool3d, r]};
Blink: PROC [message: ROPE] ~ {
MessageWindow.Append[message, TRUE];
MessageWindow.Blink[];
};
ReadValue: PROC [t: Tool, prompt: ROPE, value: REAL] RETURNS [REAL] ~ {
RETURN[Controls.TypescriptReadValue[t.tool3d.typescript, prompt, value]];
};
Initialization
ImplicitDesign.Register["Simple", SimpleCommand, "plane, sphere, cylinder, torus, blob."];
END.
..
GetDataAndTestRoot: PROC [clientData: REF ANY] RETURNS [s: SimpleData] ~ {
s ¬ NARROW[clientData];
IF s.tool.octree.root # s.root THEN s.inspect ¬ s.root ¬ s.tool.octree.root;
};
Move: ClickProc ~ {
s: SimpleData ~ GetDataAndTestRoot[clientData];
direction: G3dOctree.Direction ~ G3dOctree.DirectionFromRope[parent.name];
new: Cube ~ G3dOctree.Neighbor[s.inspect, direction];
IF new = NIL THEN Blink["Can't move in that direction."]
ELSE {
s.oldInspect ¬ s.inspect;
s.inspect ¬ new;
ImplicitDesign.Repaint[s.tool, $Client];
};
};
Up: ClickProc ~ {
s: SimpleData ~ GetDataAndTestRoot[clientData];
IF s.inspect.parent = NIL
THEN Blink["No parent."]
ELSE {
s.oldInspect ¬ s.inspect;
s.inspect ¬ s.inspect.parent;
ImplicitDesign.Repaint[s.tool, $Client];
};
};
Down: ClickProc ~ {
s: SimpleData ~ GetDataAndTestRoot[clientData];
IF s.inspect.terminal
THEN Blink["No children."]
ELSE {
s.oldInspect ¬ s.inspect;
s.inspect ¬ s.inspect.kids[lbn];
ImplicitDesign.Repaint[s.tool, $Client];
};
};
Query: ClickProc ~ {
s: SimpleData ~ NARROW[clientData];
c: Cube ¬ s.inspect;
roundness: REAL ¬ ImplicitAdapt.Roundness[c, Value, s.tool.threshold, NIL];
TSWrite[s, IO.PutFR1["\n%4.3f round", IO.real[roundness]]];
TSWrite[s, IO.PutFR1[", %4.3f error", IO.real[ImplicitAdapt.LinearDeviation[c]]]];
};
IF whatChanged = NIL
THEN {
IF s.doInspect THEN G3dCubeDraw.SimpleCube[context, s.inspect, view, vp,, solid];
IF s.doDual THEN {
size: REAL ¬ G3dOctree.Size[s.root];
center: Triple ¬ G3dOctree.Center[s.root];
clip: Cube ¬ G3dOctree.NewCube[size, [center.x+0.5*size, center.y, center.z]];
IF NOT s.tool.surface.curvesValid
THEN ImplicitSurface.SetSurfaceCurves[s.tool.surface];
FOR n: NAT IN [0..s.tool.surface.curves.length) DO
c: G3dSpline.Spline ¬ s.tool.surface.curves[n];
p0: Triple ¬ G3dSpline.Position[c, 0.0];
p1: Triple ¬ G3dSpline.Position[c, 1.0];
IF p0.x < 0.0 OR p1.x < 0.0 THEN G3dDraw.Curve[context, c, view, vp];
ENDLOOP;
};
}
ELSE IF s.doInspect THEN {
Show: PROC [cube: Cube, color: Imager.Color, width: REAL] ~ {
IF cube = NIL THEN RETURN;
Imager.SetColor[context, color];
Imager.SetStrokeWidth[context, width];
G3dCubeDraw.SimpleCube[context, cube, view, vp,, solid];
};
Show[s.oldInspect, Imager.white, 2.0];
Show[s.oldInspect, Imager.black, 1.0];
Show[s.inspect, Imager.black, 2.0];
Imager.SetStrokeWidth[context, 0.0];
};
Toggle: PROC [data: REF ANY, button: ViewerClasses.MouseButton, name: ROPE] ~ {
d: SimpleData ~ NARROW[data];
bool: BOOL ¬ SELECT TRUE FROM
Rope.Equal[name, "Inspect"] => (d.doInspect ¬ NOT d.doInspect),
Rope.Equal[name, "Dual"]  => (d.doInspect ¬ NOT d.doInspect),
Rope.Equal[name, "Clip"]  => (d.doClip ¬ NOT d.doClip),
ENDCASE => FALSE;
Controls.ButtonToggle[d.tool.tool3d.outerData, bool, Rope.Concat[name, "-On"], Rope.Concat[name, "-Off"]];
IF button = blue THEN [] ¬ ImplicitDesign.Repaint[d.tool];
};
SphereNormal: NormalProc ~ {RETURN[point]};
SphereTexture: TextureProc ~ {
polar: Triple ~ G3dVector.PolarFromCartesian[vertex.point];
RETURN[[polar.x/360.0, polar.y/360.0]];
};
SetBlobColors: PROC [surface: Surface, blobSources: Source3dSequence] ~ {
p0: Triple ~ blobSources[0].p;
p1: Triple ~ blobSources[1].p;
r0Sqd: REAL ~ blobSources[0].strength*blobSources[0].strength;
r1Sqd: REAL ~ blobSources[1].strength*blobSources[1].strength;
FOR n: NAT IN [0..surface.vertices.length) DO
v: Vertex ~ surface.vertices[n];
pot0: REAL ~ r0Sqd/MAX[0.0001, G3dVector.SquareDistance[p0, v.point]];
pot1: REAL ~ r1Sqd/MAX[0.0001, G3dVector.SquareDistance[p1, v.point]];
[[v.rgb.x, v.rgb.y, v.rgb.z]] ¬ ImagerColorFns.RGBFromHSL[[pot0/(pot0+pot1), 1.0, 0.5]];
ENDLOOP;
surface.vertexValidities.color ¬ TRUE;
};
ToggleInspect: ClickProc ~ {Toggle[clientData, mouseButton, "Inspect"]};
ToggleDual:  ClickProc ~ {Toggle[clientData, mouseButton, "Dual"]};
ToggleClip:  ClickProc ~ {Toggle[clientData, mouseButton, "Clip"]};
Controls.ClickButton["Inspect-Off", ToggleInspect, s],
Controls.ClickButton["Dual-Off", ToggleDual, s],
Controls.ClickButton["Clip-Off", ToggleClip, s],
Controls.ClickButton["PrintSphereCount", PrintSphereCount, s],
PrintSphereCount: ClickProc ~ {
s: SimpleData ¬ NARROW[clientData];
TSWrite[s, IO.PutFR["sphere count: %g",IO.int[s.sphereCount]]];
};