ImplicitScatterCmdImpl.mesa
Copyright Ó 1989, 1990 by Xerox Corporation. All rights reserved.
Bloomenthal, August 11, 1992 4:06 pm PDT
DIRECTORY CedarProcess, Commander, Controls, Convert, Draw2d, FileNames, G2dContour, G2dVector, G3dBasic, G3dMatrix, G3dSpline, G3dTool, G3dTube, G3dVector, Imager, ImplicitDefs, ImplicitDesign, ImplicitTube, IO, MessageWindow, Rope, ViewerTools;
ImplicitScatterCmdImpl: CEDAR PROGRAM
IMPORTS CedarProcess, Controls, Convert, Draw2d, FileNames, G2dContour, G2dVector, G3dMatrix, G3dSpline, G3dTool, G3dTube, G3dVector, Imager, ImplicitDesign, ImplicitTube, IO, MessageWindow, Rope, ViewerTools
~ BEGIN
Button:    TYPE ~ Controls.Button;
ClickProc:   TYPE ~ Controls.ClickProc;
Pair:     TYPE ~ G3dBasic.Pair;
Triple:    TYPE ~ G3dBasic.Triple;
Matrix:    TYPE ~ G3dMatrix.Matrix;
Tube:     TYPE ~ G3dTube.Tube;
ROPE:     TYPE ~ Rope.ROPE;
Point:     TYPE ~ REF PointRep;
PointRep:    TYPE ~ RECORD [
history:      LIST OF Triple ¬ NIL,
pOld, pNew:     Triple ¬ [],
vOld, vNew:     REAL ¬ 0.0,
converged:     BOOL ¬ FALSE
];
Points:    TYPE ~ REF PointsRep;
PointsRep:   TYPE ~ RECORD [
length:      CARDINAL ¬ 0,
element:      SEQUENCE maxLength: CARDINAL OF Point
];
Data:     TYPE ~ REF DataRep;
DataRep:    TYPE ~ RECORD [
zDir:       Triple ¬ [],
nDisksB, deltaB, cResB:  Button ¬ NIL,
delta:       REAL ¬ 0.001,
nDisks, cRes:     INTEGER ¬ 100,
tube:       Tube ¬ NIL,
points:      Points ¬ NIL,
iterating, history:   BOOL ¬ FALSE,
tool:       ImplicitDesign.Tool ¬ NIL
];
ScatterCommand: Commander.CommandProc ~ {
d: Data ~ NEW[DataRep];
d.tool ¬ ImplicitDesign.MakeTool[
name: "Scatter Test",
startProc: Start,
valueProc: NIL,
client: [data: d, draw: Draw],
extraButtons: LIST[
Controls.ClickButton["Read Tube", ReadTube, d],
Controls.ClickButton["Reset", Setup, d],
Controls.ClickButton["Converge", Converge, d],
Controls.ClickButton["Step", Step, d],
d.nDisksB ¬ Controls.TextButton["NDisks", "10", Setup, d],
d.cResB ¬ Controls.TextButton["CRes", "06", Setup, d],
d.deltaB ¬ Controls.TextButton["Delta", Convert.RopeFromReal[d.delta], Setup, d],
Controls.ClickButton["History On", History, d],
Controls.ClickButton["IP Out", IPOut, d]]
];
};
Draw: Controls.DrawProc ~ {
Xform: PROC [p: Triple] RETURNS [Pair] ~ {RETURN[G3dMatrix.TransformD[p, view]]};
ScreenSize: PROC [p: Triple] RETURNS [r: REAL] ~ {
r ¬ G2dVector.Distance[Xform[p], Xform[G3dVector.ScaleRay[[p, d.zDir], 0.003]]];
r ¬ 0.5*r*r;
};
Mark: PROC [t: Triple] ~ {Draw2d.Circle[context, Xform[t], ScreenSize[t], TRUE]};
Segment: PROC [p0, p1: Triple] ~ {
Imager.SetStrokeWidth[context, MIN[ScreenSize[p0], ScreenSize[p1]]];
Imager.MaskVector[context, Xform[p0], Xform[p1]];
};
d: Data ¬ NARROW[clientData];
view: Matrix ¬ G3dTool.GetView[viewer].camera.matrix;
IF d.points = NIL THEN RETURN;
IF whatChanged = NIL THEN {
vMat: Matrix ¬ G3dMatrix.Transpose[view, G3dMatrix.ObtainMatrix[]];
d.zDir ¬ G3dVector.Unit[G3dVector.Ortho[G3dMatrix.TransformVec[[0.0, 1.0, 0.0], vMat]]];
G3dMatrix.ReleaseMatrix[vMat];
};
IF d.history
THEN FOR n: NAT IN [0..d.points.length) DO
FOR l: LIST OF Triple ¬ d.points[n].history, l.rest WHILE l # NIL DO
IF l.rest = NIL THEN Mark[l.first] ELSE Segment[l.first, l.rest.first];
ENDLOOP;
ENDLOOP
ELSE FOR n: NAT IN [0..d.points.length) DO
p: Point ¬ d.points[n];
IF d.iterating THEN Segment[p.pOld, p.pNew] ELSE Mark[d.points[n].pNew];
ENDLOOP;
};
ReadTube: ClickProc ~ {
d: Data ¬ NARROW[clientData];
r: ROPE ¬ FileNames.ResolveRelativePath[Controls.TypescriptReadFileName[d.tool.tool3d.typescript]];
tube: Tube ¬ G3dTube.TubeFromFile[r];
IF tube = NIL THEN {Blink[Rope.Cat["\tCan't open ", r, "\n"]]; RETURN};
G3dTube.SelectAll[d.tube ¬ tube];
DoSetup[d];
};
Setup: ClickProc ~ {d: Data ¬ NARROW[clientData]; IF d.tube # NIL THEN DoSetup[d]};
History: ClickProc ~ {
d: Data ¬ NARROW[clientData];
Controls.ButtonToggle[d.tool.tool3d.outerData,d.history¬NOT d.history,"History On","History Off"];
};
DoSetup: PROC [d: Data] ~ {
ENABLE Convert.Error => {Blink["\tBad value"]; GOTO Bad};
d.cRes ¬ Convert.IntFromRope[ViewerTools.GetContents[d.cResB.textViewer]];
d.delta ¬ Convert.RealFromRope[ViewerTools.GetContents[d.deltaB.textViewer]];
d.nDisks ¬ Convert.IntFromRope[ViewerTools.GetContents[d.nDisksB.textViewer]];
ImplicitTube.PrepareTube[d.tube, d.tool.distanceMode, d.tool.measureMode];
ScatterPoints[d];
ImplicitDesign.Reset[d.tool];
EXITS Bad => NULL;
};
Step: Controls.ClickProc ~ {
d: Data ¬ NARROW[clientData];
IF d.tube = NIL THEN Blink["\tNeed tube!"] ELSE [] ¬ Iterate[d];
};
IPOut: Controls.ClickProc ~ {
d: Data ¬ NARROW[clientData];
r: ROPE ¬ Controls.TypescriptReadFileName[NARROW[clientData, Data].tool.tool3d.typescript];
IF r # NIL THEN Draw2d.IPOut[r, Draw, clientData];
};
Converge: Controls.ClickProc ~ {
d: Data ¬ NARROW[clientData];
IF d.tube = NIL THEN {Blink["\tNeed tube!"]; RETURN};
[] ¬ ImplicitDesign.MaybeFork[d.tool, ConvergeFork];
};
ConvergeFork: CedarProcess.ForkableProc ~ {
d: Data ¬ NARROW[data];
MessageWindow.Append["\t# remaining:", TRUE];
d.iterating ¬ TRUE;
DO
CedarProcess.CheckAbort[];
IF Iterate[d] THEN EXIT;
ENDLOOP;
d.iterating ¬ FALSE;
};
Iterate: PROC [d: Data] RETURNS [allConverged: BOOL ¬ TRUE] ~ {
Sign: PROC [r: REAL] RETURNS [{pos, neg, zero}] ~ {
RETURN[SELECT r FROM > 0.0 => pos, < 0.0 => neg, ENDCASE => zero];
};
nToDo: NAT ¬ 0;
FOR n: NAT IN [0..d.points.length) DO
p: Point ¬ d.points[n];
IF NOT p.converged THEN {
gradient: Triple ¬ Gradient[d, p.pOld ¬ p.pNew, p.vOld ¬ p.vNew];
IF p.vOld < 0.0 THEN gradient ¬ G3dVector.Negate[gradient];
allConverged ¬ FALSE;
nToDo ¬ nToDo+1;
p.pNew ¬ G3dVector.Add[p.pOld, G3dVector.SetVectorLength[gradient, d.delta]];
p.vNew ¬ Value[d, p.pNew];
p.history ¬ CONS[p.pNew, p.history];
IF ABS[p.vNew] < 0.0001 OR p.vNew = p.vOld OR Sign[p.vNew] # Sign[p.vOld]
THEN p.converged ¬ TRUE
ELSE {
p.pNew ¬ G3dVector.Interp[p.vOld/(p.vOld-p.vNew), p.pOld, p.pNew];
p.vNew ¬ Value[d, p.pNew];
IF Sign[p.vNew] # Sign[p.vOld] THEN p.converged ¬ TRUE;
};
};
ENDLOOP;
MessageWindow.Append[IO.PutFR[" %g", IO.int[nToDo]]];
ImplicitDesign.Repaint[d.tool, $NoClear];
};
Gradient: PROC [d: Data, p: Triple, v: REAL] RETURNS [Triple] ~ {
RETURN[[
v-Value[d, [p.x+d.delta, p.y, p.z]],
v-Value[d, [p.x, p.y+d.delta, p.z]],
v-Value[d, [p.x, p.y, p.z+d.delta]]]];
};
Value: PROC [d: Data, p: Triple] RETURNS [REAL] ~ {
t: ImplicitDesign.Tool ¬ d.tool;
RETURN[ImplicitTube.SampleTube[
p, d.tube, t.measureMode, t.distanceMode, t.tolerance, t.spread].value];
};
ValueProc: ImplicitDefs.ValueProc ~ {RETURN[Value[NARROW[clientData], point]]};
ScatterPoints: PROC [d: Data] ~ {
Spot: TYPE ~ RECORD [xyz: Triple, t, aLen: REAL];
Spots: TYPE ~ RECORD [element: SEQUENCE maxLength: CARDINAL OF Spot];
MakePoints: G3dTube.TubeProc ~ {
Pos: PROC [t: REAL] RETURNS [p: Triple] ~ {p ¬ G3dSpline.Position[tube.spline, t]};
ApplyRefVec: G3dTube.TubeProc ~ {tube.refVec ¬ rv};
MakeDisk: PROC [t: REAL] ~ {
v: Triple ¬ G3dVector.Unit[G3dSpline.Velocity[tube.spline, t]];
triad: G3dBasic.Triad ¬ G3dTube.Basis[v, vv, rv];
vv ¬ v;
rv ¬ triad.n;
refM ¬ G3dTube.RefMatrix[Pos[t], triad, G3dTube.Radius[tube, t], 0, refM];
ApplyCircle[circle];
};
ApplyCircle: PROC [circle: G3dBasic.PairSequence] ~ {
FOR i: NAT IN [0..circle.length) DO
AddPoint[G3dMatrix.TransformPair[circle[i], refM]];
ENDLOOP;
};
AddPoint: PROC [point: Triple] ~ {
p: Point ¬ d.points[pIndex];
p.pNew ¬ point;
p.vNew ¬ Value[d, p.pNew];
p.history ¬ LIST[p.pNew];
p.converged ¬ FALSE;
pIndex ¬ pIndex+1;
};
rv: Triple ¬ tube.refVec;
vv: Triple ¬ G3dVector.Unit[tube.v0];
totalLen, interDiskLen, accumLen: REAL ¬ 0.0;
nDisks: NAT ¬ d.nDisks;
IF tube.prev = NIL THEN nDisks ¬ nDisks-1;
IF G3dTube.NBranches[tube, TRUE] # 0 THEN nDisks ¬ nDisks-1;
IF tube.prev = NIL THEN {
v: Triple ¬ G3dVector.Unit[tube.v0];
end: Triple ¬ G3dVector.Sub[tube.p0, G3dVector.SetVectorLength[tube.v0, tube.r0]];
mid: Triple ¬ G3dVector.Midpoint[end, tube.p0];
binormal: Triple ¬ G3dVector.Unit[G3dVector.Cross[v, rv]];
refM ¬ G3dTube.RefMatrix[mid, [v, rv, binormal], 0.5*tube.r0, 0, refM];
AddPoint[end];
ApplyCircle[smallCircle];
MakeDisk[0.0];
};
FOR i: NAT IN [1..nSpots) DO
spots[i].xyz ¬ G3dSpline.Position[tube.spline, spots[i].t ¬ REAL[i]/REAL[nSpots-1]];
spots[i].aLen ¬ G3dVector.Distance[spots[i].xyz, spots[i-1].xyz];
totalLen ¬ totalLen+spots[i].aLen;
ENDLOOP;
interDiskLen ¬ totalLen/(d.nDisks-1);
FOR n: NAT IN [1..nSpots-1) DO
IF (accumLen ¬ accumLen+spots[n].aLen) > interDiskLen
THEN {accumLen ¬ 0.0; MakeDisk[spots[n].t]};
ENDLOOP;
IF G3dTube.NBranches[tube] = 0 THEN {
v: Triple ¬ G3dVector.Unit[tube.v0];
end: Triple ¬ G3dVector.Add[tube.p1, G3dVector.SetVectorLength[tube.v1, tube.r1]];
mid: Triple ¬ G3dVector.Midpoint[end, tube.p1];
binormal: Triple ¬ G3dVector.Unit[G3dVector.Cross[v, rv]];
refM ¬ G3dTube.RefMatrix[mid, [v, rv, binormal], 0.5*tube.r1, 0, refM];
ApplyCircle[smallCircle];
AddPoint[end];
};
G3dTube.ApplyToBranches[tube, ApplyRefVec];
};
refM: G3dMatrix.Matrix ¬ G3dMatrix.ObtainMatrix[];
circle: G3dBasic.PairSequence ¬ G2dContour.Circle[d.cRes].pairs;
smallCircle: G3dBasic.PairSequence ¬ G2dContour.Circle[d.cRes-1].pairs;
nSpots: NAT ¬ 100*d.nDisks;
spots: REF Spots ¬ NEW[Spots[nSpots]];
pIndex: NAT ¬ 0;
nPoints: NAT ¬ (G3dTube.NTubes[d.tube]*d.nDisks)*d.cRes;
d.tube.refVec ¬ G3dVector.Unit[G3dVector.Ortho[d.tube.v0]];
IF d.points = NIL OR nPoints > d.points.length THEN {
d.points ¬ NEW[PointsRep[nPoints]];
FOR n: NAT IN [0..nPoints) DO d.points[n] ¬ NEW[PointRep]; ENDLOOP;
};
d.points.length ¬ nPoints;
G3dTube.ApplyToTube[d.tube, MakePoints];
G3dMatrix.ReleaseMatrix[refM];
};
Start: ImplicitDefs.StartProc ~ {
ImplicitDesign.StopTool[NARROW[clientData, Data].tool];
Blink["\tThis function disabled when scattering"];
};
Blink: PROC [r: ROPE] ~ {MessageWindow.Append[r, TRUE]; MessageWindow.Blink[]};
ImplicitDesign.Register["Scatter", ScatterCommand, "scatter points and converge."];
END.