ContoursRandomImpl:
CEDAR
PROGRAM
IMPORTS Commander, Controls, Controls3d, Draw2d, Draw3d, Print3d, Random, Real, RealFns, Spline3d, SplineStructure, Vector3d, ViewerOps
~ BEGIN
gaussArray: Spline3d.RealSequence ← InitGaussSequence[1024];
Triple: TYPE ~ Vector3d.Triple;
Coeffs: TYPE ~ Spline3d.Coeffs;
Bezier: TYPE ~ Spline3d.Bezier;
Box: TYPE ~ RECORD [a, b, c, d: Triple];
BoxSequence: TYPE ~ REF BoxSequenceRec;
BoxSequenceRec: TYPE ~ RECORD [element: SEQUENCE maxLength: NAT OF Box];
SplineData: TYPE ~ SplineStructure.SplineData;
SplineDataRec: TYPE ~ SplineStructure.SplineDataRec;
ProgramData: TYPE ~ REF ProgramDataRec;
ProgramDataRec:
TYPE ~
RECORD [
out: IO.STREAM ← NIL,
outer, graphics: Controls.Viewer ← NIL,
entries: LIST OF Controls.Entry ← NIL,
mouse: SplineStructure.Mouse ← [0, 0, none, left],
cam: Controls3d.Camera, -- camera
hold: Controls3d.Hold, -- handle on a point and its tangent
nSpl: Controls.ControlData ← NIL, -- number of new splines from old one
nRec: Controls.ControlData ← NIL, -- number of recursive levels
graphicsData: Controls.GraphicsData ← NIL,
view: Matrix3d.Matrix ← NIL,
recurse: BOOL ← FALSE,
noPick: BOOL ← TRUE,
s: SplineData ← NIL, -- all the contour splines
pd: SplineStructure.PickData ← NIL
];
Contour: Commander.CommandProc ~ {
d: ProgramData ← NEW[ProgramDataRec];
d.out ← cmd.err;
d.pd ← NEW[SplineStructure.PickDataRec];
d.view ← NEW[Matrix3d.MatrixRep];
d.s ← NEW[SplineDataRec];
d.cam ← Controls3d.InitCamera[dz: 0.5, zoom: 3., fov: 0., proc: Controller, data: d];
d.hold ← Controls3d.InitHold[Controller, d];
d.pd.s ← SplineStructure.contour ← d.s;
d.s.c ← Spline3d.CoeffsFromHermite[[[-0.5, 0., 0.], [0.5, 0., 0.], [1., 1., 0.], [1., -1., 0.]]];
d.nSpl ← Controls.NewControl["nSpl", vert, , 2.0, 15.0, 4.0, TRUE, , , Controller, d];
d.nRec ← Controls.NewControl["nRec", vert, , 1.0, 15.0, 1.0, TRUE, , , Controller, d];
SplineStructure.PointPick[d.pd];
Controls3d.FocusHold[d.pd.tan, d.hold];
Controls.ControlRow[d.cam.pan, 2];
d.outer ← Controls.OuterViewer[
name: "Contour",
column: left,
entries:
LIST[
["Recurse", Recurse], ["Randomize", Randomize],
["PickToggle", PickToggle], ["Reset", Reset], ["PrintC", PrintC]],
controls:
LIST[
d.hold.x, d.hold.y, d.hold.z, d.hold.lng, d.hold.lat, d.hold.mag, d.nSpl, d.nRec,
d.cam.xRot, d.cam.yRot, d.cam.zRot, d.cam.scale, d.cam.x, d.cam.y, d.cam.z, d.cam.fov],
graphicsHeight: 300,
graphicsProc: ScreenPick,
graphicsShow: Display,
data: d];
d.entries ← NARROW[d.outer.data, Controls.OuterData].entries;
d.graphics ← NARROW[d.outer.data, Controls.OuterData].graphics;
d.graphicsData ← NARROW[d.graphics.data];
};
Controller:
PUBLIC Controls.ControlProc ~ {
d: ProgramData ← NARROW[control.data];
IF d.pd.dividePending
THEN {
SplineStructure.DivideSpline[d.pd];
Controls.ControlVal[d.hold.mag, Vector3d.Mag[d.pd.sPt0.v1]];
};
SELECT control
FROM
d.hold.x, d.hold.y, d.hold.z =>
SplineStructure.ChangePosition[d.s, d.pd, [d.hold.x.val, d.hold.y.val, d.hold.z.val]];
d.hold.lng, d.hold.lat, d.hold.mag =>
IF
NOT d.noPick
THEN SplineStructure.ChangeTangent[
d.s, d.pd, Vector3d.CartesianFromPolar[[d.hold.lng.val, d.hold.lat.val, d.hold.mag.val]]];
d.cam.xRot, d.cam.yRot, d.cam.zRot, d.cam.scale, d.cam.x, d.cam.y, d.cam.z, d.cam.fov => Controls3d.UpDateCamera[d.cam];
ENDCASE => NULL;
ViewerOps.PaintViewer[control.graphics, client, FALSE, control];
};
ScreenPick: Controls.GraphicsProc ~ {
d: ProgramData ← NARROW[graphics.data];
IF graphics.mouse.state = up THEN RETURN;
IF graphics.mouse.button = left
THEN {
SplineStructure.ScreenPick[d.s, graphics.mouse, d.view, d.pd];
Controls3d.FocusHold[d.pd.tan, d.hold];
};
};
PickToggle: Controls.ClickProc ~ {
d: ProgramData ← NARROW[NARROW[clientData, Controls.OuterData].data];
d.noPick ← NOT d.noPick;
ViewerOps.PaintViewer[d.graphics, client, FALSE, d];
};
PrintC: Controls.ClickProc ~ {
d: ProgramData ← NARROW[NARROW[clientData, Controls.OuterData].data];
FOR s: SplineData ← d.s, s.next WHILE s # NIL DO Print3d.Matrix[d.out, s.c]; ENDLOOP;
};
Reset: Controls.ClickProc ~ {
d: ProgramData ← NARROW[NARROW[clientData, Controls.OuterData].data];
SplineStructure.contour ← d.s ← NEW[SplineDataRec];
(d.pd.s ← d.s).c ← Spline3d.CoeffsFromHermite[[[-0.5,0.,0.], [0.5,0.,0.], [1.,1.,0.], [1.,-1.,0.]]];
ViewerOps.PaintViewer[d.graphics, client, FALSE, d];
};
Recurse: Controls.ClickProc ~ {
d: ProgramData ← NARROW[NARROW[clientData, Controls.OuterData].data];
d.recurse ← TRUE;
ViewerOps.PaintViewer[d.graphics, client, FALSE, d];
d.recurse ← FALSE;
};
Randomize: Controls.ClickProc ~ {
d: ProgramData ← NARROW[NARROW[clientData, Controls.OuterData].data];
s: SplineData ← d.s;
WHILE s #
NIL
DO
r: SplineData ← RandomizeSpline[s.c, Real.RoundI[d.nSpl.val]];
r.prev ← s.prev;
IF s.prev # NIL THEN s.prev.next ← r ELSE SplineStructure.contour ← d.s ← r;
WHILE r.next # NIL DO r ← r.next; ENDLOOP;
IF s.next # NIL THEN s.next.prev ← r;
s ← r.next ← s.next;
ENDLOOP;
ViewerOps.PaintViewer[d.graphics, client, FALSE, d];
};
InsertSpline:
PROC [insert, splines: SplineData]
RETURNS [SplineData] ~ {
Insert new SplineData (insert) at end of splines:
s: SplineData ← splines;
IF splines = NIL THEN RETURN[insert];
WHILE s.next # NIL DO s ← s.next; ENDLOOP;
insert.prev ← s;
insert.next ← s.next;
s.next ← insert;
IF insert.next # NIL THEN insert.next.prev ← insert;
RETURN[splines];
};
RandomizeSpline:
PROC [c: Coeffs, nSplines:
INTEGER ← 2]
RETURNS [SplineData] ~ {
splines: SplineData ← NIL;
coeffs: Spline3d.CoeffsSequence;
bez: Bezier ← Spline3d.BezierFromCoeffs[c];
boxes: BoxSequence ← BoxesFromBezier[bez, nSplines];
knots: Spline3d.KnotSequence ← NEW[Spline3d.KnotSequenceRep[nSplines+1]];
scale: REAL ← 3.0/REAL[MAX[1, nSplines]];
tan0: Triple ← Vector3d.Mul[Vector3d.Sub[bez.b1, bez.b0], scale];
tan1: Triple ← Vector3d.Mul[Vector3d.Sub[bez.b3, bez.b2], scale];
IF nSplines = 0 THEN RETURN[splines];
knots[0] ← bez.b0;
FOR n: NAT IN [1..nSplines) DO knots[n] ← RandomPtInBox[boxes[n-1]]; ENDLOOP;
knots[nSplines] ← bez.b3;
knots.length ← nSplines+1;
coeffs ← Spline3d.Interpolate[knots, tan0, tan1];
FOR n:
NAT
IN [0..nSplines)
DO
insert: SplineData ← NEW[SplineDataRec];
insert.c ← coeffs[n];
splines ← InsertSpline[insert, splines];
ENDLOOP;
RETURN[splines];
};
BoxesFromBezier:
PROC [bez: Bezier, nBoxes:
NAT]
RETURNS [BoxSequence] ~ {
boxes: BoxSequence ← NEW[BoxSequenceRec[nBoxes]];
p0: Triple ← bez.b0;
p1: Triple ← bez.b1;
dp0: Triple ← Vector3d.Div[Vector3d.Sub[bez.b3, bez.b0], REAL[nBoxes]];
dp1: Triple ← Vector3d.Div[Vector3d.Sub[bez.b2, bez.b1], REAL[nBoxes]];
FOR n:
NAT
IN [0..nBoxes)
DO
pp0: Triple ← Vector3d.Add[p0, dp0];
pp1: Triple ← Vector3d.Add[p1, dp1];
boxes[n] ← [p0, p1, pp1, pp0];
p0 ← pp0;
p1 ← pp1;
ENDLOOP;
RETURN[boxes];
};
RanR: PROC RETURNS [REAL] ~ {RETURN[gaussArray[Random.ChooseInt[min: 0, max: 1023]]]};
RandomPtInSegment:
PROC [p0, p1: Triple]
RETURNS[Triple] ~ {
w: REAL ← RanR[];
RETURN[Vector3d.Add[Vector3d.Mul[p0, w], Vector3d.Mul[p1, 1.0-w]]];
RandomPtInBox:
PROC [box: Box]
RETURNS[t: Triple] ~ {
w0: REAL ← RanR[];
w1: REAL ← RanR[];
w2: REAL ← RanR[];
w3: REAL ← RanR[];
n: REAL ← 1.0/(w0+w1+w2+w3);
w0 ← w0*n; w1 ← w1*n; w2 ← w2*n; w3 ← w3*n;
t.x ← box.a.x*w0+box.b.x*w1+box.c.x*w2+box.d.x*w3;
t.y ← box.a.y*w0+box.b.y*w1+box.c.y*w2+box.d.y*w3;
t.z ← box.a.z*w0+box.b.z*w1+box.c.z*w2+box.d.z*w3;
Function:
PROC [x:
REAL]
RETURNS [
REAL] ~ {
Input and output range [0..1].
x ← 2.0*3.1415926535*(x-0.5);
RETURN[0.5*(1.0+RealFns.Sin[x]+RealFns.Cos[x])];
};
Display: Controls.GraphicsShow ~ {
d: ProgramData ← NARROW[data];
Action:
PROC ~ {
d.view ← Controls3d.InitPix[context, w, h];
IF d.recurse THEN {
p, q: Triple ← [0.0, 0.0, 0.0];
FOR i:
NAT
IN [0..100)
DO
q.x ← REAL[i-50]/100.0;
q.y ← 0.5+q.x;
FOR n:
NAT
IN[1..Real.RoundI[d.nRec.val]]
DO
q.y ← Function[q.y];
ENDLOOP;
q.y ← 0.5*q.y;
IF i > 0 THEN Draw3d.PP[p, q, context, d.view];
p ← q;
ENDLOOP;
}
ELSE FOR s: SplineData ← d.s, s.next
WHILE s #
NIL
DO
Draw3d.DrawBezierPolygon[Spline3d.BezierFromCoeffs[s.c], context, d.view, dot];
Draw3d.DrawCurve[s.c, context, d.view];
ENDLOOP;
IF NOT d.noPick THEN Draw3d.PV[d.pd.pos, d.pd.tan,, context, d.view, IF d.pd.t IN(0.0..1.0) THEN cross ELSE none];
};
Draw2d.DoWithBuffer[context, Action, w, h]
};
InitGaussSequence:
PROC [nEntries:
NAT]
RETURNS [Spline3d.RealSequence] ~ {
x: REAL ← 0.0;
sigma: REAL ~ 0.16;
dx: REAL ← 1.0/REAL[nEntries];
ret: Spline3d.RealSequence ← NEW[Spline3d.RealSequenceRec[nEntries]];
FOR i:
NAT
IN [0..1024)
DO
xx: REAL ← x-0.5;
ret[i] ← RealFns.Exp[-xx*xx/(2.0*sigma*sigma)];
x ← x+dx;
ENDLOOP;
RETURN[ret];
};
Commander.Register["Contour", Contour, "\nTest some contour ideas."];
END.
..
RandomizeSpline: PROC [c: Coeffs, nSplines: INTEGER ← 2] RETURNS [SplineData] ~ {
splines: SplineData ← NIL;
nBoxes: NAT ← 2*nSplines-2;
bez: Bezier ← Spline3d.BezierFromCoeffs[c];
boxes: BoxSequence ← BoxesFromBezier[bez, nBoxes];
pts: TripleSequence ← NEW[TripleSequenceRec[nBoxes+2]];
ends: TripleSequence ← NEW[TripleSequenceRec[nSplines+1]];
pts[0] ← RandomPtInSegment[bez.b0, bez.b1];
pts[nBoxes+1] ← RandomPtInSegment[bez.b2, bez.b3];
FOR n: NAT IN [0..nBoxes) DO pts[n+1] ← RandomPtInBox[boxes[n]]; ENDLOOP;
ends[0] ← bez.b0;
ends[nSplines] ← bez.b3;
FOR n: NAT IN [1..nSplines) DO
ends[n] ← Ave[pts[n+n-1], pts[n+n]];
ENDLOOP;
FOR n: NAT IN [0..nSplines) DO
insert: SplineData ← NEW[SplineDataRec];
insert.c ← Spline3d.CoeffsFromBezier[[ends[n], pts[n+n], pts[n+n+1], ends[n+1]]];
splines ← InsertSpline[insert, splines];
ENDLOOP;
RETURN[splines];
};
MinMaxOfCurve: PROC [c: Coeffs, i: NAT] RETURNS [min, max: REAL] ~ {
CheckI: PROC [t: REAL] ~ {
t2: REAL ← t*t;
y: REAL ← t2*t*c[0][i]+t2*c[1][i]+t*c[2][i]+c[3][i];
min ← MIN[min, y];
max ← MAX[max, y];
};
roots: Quadratic.Roots ← Quadratic.RealRoots[3.0*c[0][i], 2.0*c[1][i], c[2][i]];
min ← max ← c[3][i];
CheckI[1.0];
IF roots.nRoots > 0 AND roots.r1 IN [0.0..1.0] THEN CheckI[roots.r1];
IF roots.nRoots > 1 AND roots.r2 IN [0.0..1.0] THEN CheckI[roots.r2];
};
Ave: PROC [a, b: Triple] RETURNS [Triple] ~ {
RETURN[[0.5*(a.x+b.x), 0.5*(a.y+b.y), 0.5*(a.z+b.z)]];
};