PolyHackA.Mesa
Last Edited by: Spreitzer, September 19, 1985 7:27:18 pm PDT
DIRECTORY BiScrollers, Geom2D, Imager, ImagerBox, IO, Misp, PolyHackInsides, Process, Random, Real, RealFns, StructuredStreams, ViewerClasses, ViewerOps, ViewerSpecs;
PolyHackA:
CEDAR
MONITOR
IMPORTS Geom2D, Imager, ImagerBox, IO, Misp, PolyHackInsides, Process, Random, Reals: Real, RealFns, SS:StructuredStreams, ViewerOps
EXPORTS PolyHackInsides =
BEGIN OPEN PolyHackInsides;
Broken: ERROR = CODE;
rs: PUBLIC Random.RandomStream ← Random.Create[seed: -1];
whiteColoring: Coloring ← NEW [ColoringRep ← [color: Imager.white]];
PaintHack:
PUBLIC
PROC [self: Viewer, context: Imager.Context, whatChanged:
REF
ANY, clear:
BOOL]
RETURNS [quit:
BOOL ←
FALSE]
--ViewerClasses.PaintProc-- =
BEGIN
vd: ViewerData ← ViewerDataOf[self];
IF self.column # vd.oldColumn
THEN
{vd.color ← (vd.oldColumn ← self.column) = color};
IF whatChanged =
NIL
THEN
BEGIN
Imager.SetColor[context, Imager.black];
Imager.MaskBox[context, vd.bloatedBounds];
END
ELSE
FOR lora:
LORA ←
NARROW[whatChanged], lora.rest
WHILE lora #
NIL
DO
WITH lora.first
SELECT
FROM
da: DrawAreas =>
BEGIN
FOR pl: DetailedPathList ← da.areaPaths, pl.rest
WHILE pl #
NIL
DO
path: Imager.PathProc = {
p: Path ← pl.first.path;
IF p.length = 0 THEN RETURN;
moveTo[p[0]];
FOR i: INT IN (0 .. p.length) DO lineTo[p[i]] ENDLOOP;
};
Imager.SetColor[context, ColoringColor[pl.first.coloring]];
Imager.MaskFill[context: context, path: path, parity: TRUE]
ENDLOOP;
END;
ds: DrawStrokes =>
BEGIN
FOR pl: DetailedPathList ← ds.strokePaths, pl.rest
WHILE pl #
NIL
DO
path: Imager.PathProc = {
p: Path ← pl.first.path;
IF p.length = 0 THEN RETURN;
moveTo[p[0]];
FOR i: INT IN (0 .. p.length) DO lineTo[p[i]] ENDLOOP;
};
Imager.SetColor[context, ColoringColor[pl.first.coloring]];
Imager.MaskStroke[context: context, path: path, closed: FALSE];
ENDLOOP;
END;
dt: DrawTriangles =>
BEGIN
FOR polyList: PolyList ← vd.polys, polyList.rest
WHILE polyList #
NIL
DO
Imager.SetColor[context, ColoringColor[polyList.first.coloring]];
IF dt.strict THEN Trianglify[polyList.first, dt.trianglePath, vd, context]
ELSE Quadrify[polyList.first, dt.trianglePath, vd, context];
ENDLOOP;
END;
ENDCASE => Imager.MaskBox[context, [-100, -100, 100, 100]];
ENDLOOP;
END;
Quadrify:
PROC [poly: Poly, path: Path, vd: ViewerData, context: Imager.Context] =
BEGIN
FOR vr: VertexRing ← poly.vertices.next, vr.next
WHILE vr # poly.vertices
DO
AddVertex:
PROC [v: Vertex] =
INLINE
BEGIN
p: Point ← v.curLoc;
IF vd.ctlPanel.round THEN p ← RoundPoint[p];
ExtendPath[path, p];
END;
EnumPath: Imager.PathProc = {
IF path.length = 0 THEN RETURN;
moveTo[path[0]];
FOR i: INT IN (0 .. path.length) DO lineTo[path[i]] ENDLOOP;
};
ResetPath[path];
IF vr.paintHalf THEN {StepVertex[vr.vertex, vd.ctlPanel.speed]; LOOP};
IF vr.prev # poly.vertices THEN AddVertex[vr.prev.vertex];
AddVertex[vr.vertex];
IF vr.next # poly.vertices THEN AddVertex[vr.next.vertex];
StepVertex[vr.vertex, vd.ctlPanel.speed];
AddVertex[vr.vertex];
Imager.MaskFill[context: context, path: EnumPath, parity: TRUE];
ENDLOOP;
END;
Trianglify:
PROC [poly: Poly, path: Path, vd: ViewerData, context: Imager.Context] =
BEGIN
EnumPath: Imager.PathProc = {
IF path.length = 0 THEN RETURN;
moveTo[path[0]];
FOR i: INT IN (0 .. path.length) DO lineTo[path[i]] ENDLOOP;
};
FOR vr: VertexRing ← poly.vertices.next, vr.next
WHILE vr # poly.vertices
DO
first: BOOLEAN ← TRUE;
old: Point;
DoUnroundedTriangle:
PROC [v: Vertex] =
INLINE
BEGIN
ResetPath[path];
ExtendPath[path, v.curLoc];
ExtendPath[path, vr.vertex.curLoc];
ExtendPath[path, old];
Imager.MaskFill[context: context, path: EnumPath, parity: TRUE];
END;
DoRoundedTriangle:
PROC [v: Vertex] =
INLINE
BEGIN
ResetPath[path];
ExtendPath[path, RoundPoint[v.curLoc]];
ExtendPath[path, RoundPoint[vr.vertex.curLoc]];
ExtendPath[path, RoundPoint[old]];
Imager.MaskFill[context: context, path: EnumPath, parity: TRUE];
END;
IF vr.paintHalf THEN {StepVertex[vr.vertex, vd.ctlPanel.speed]; LOOP};
old ← vr.vertex.curLoc;
StepVertex[vr.vertex, vd.ctlPanel.speed];
IF vd.ctlPanel.round
THEN
BEGIN
IF vr.prev # poly.vertices THEN DoRoundedTriangle[vr.prev.vertex];
IF vr.next # poly.vertices THEN DoRoundedTriangle[vr.next.vertex];
END
ELSE
BEGIN
IF vr.prev # poly.vertices THEN DoUnroundedTriangle[vr.prev.vertex];
IF vr.next # poly.vertices THEN DoUnroundedTriangle[vr.next.vertex];
END;
ENDLOOP;
END;
RoundPoint:
PROC [p: Point]
RETURNS [rp: Point] =
INLINE {rp ← [
x: Reals.RoundLI[p.x],
y: Reals.RoundLI[p.y]]};
GetRunLock:
PUBLIC
ENTRY
PROC [vd: ViewerData]
RETURNS [run:
BOOLEAN] =
{IF (run ← NOT vd.running) THEN {vd.running ← TRUE; vd.runner ← Process.GetCurrent[]}};
UnRun:
PUBLIC
ENTRY
PROC [vd: ViewerData, unstop:
BOOL] = {
vd.running ← FALSE;
vd.runner ← NIL;
IF unstop THEN vd.ctlPanel.stop ← FALSE};
AbortRunner:
PUBLIC
ENTRY
PROC [vd: ViewerData]
RETURNS [wasRunning:
BOOL] = {
IF (wasRunning ← vd.runner # NIL) # vd.running THEN RETURN WITH ERROR Broken;
IF wasRunning THEN TRUSTED {Process.Abort[LOOPHOLE[vd.runner, UNSPECIFIED]]};
};
PrepareToRun:
PUBLIC
PROC [vd: ViewerData]
RETURNS [lda:
LORA, da: DrawAreas, ds: DrawStrokes] =
BEGIN
SELECT vd.ctlPanel.mode
FROM
sweep =>
BEGIN
SELECT vd.ctlPanel.method
FROM
polygons => lda ← LIST[da ← DAForPolys[vd.polys]];
triangles => lda ← LIST[NewDT[TRUE]];
quadrilaterals => lda ← LIST[NewDT[FALSE]];
ENDCASE => ERROR;
END;
trace =>
BEGIN
lda ← LIST[ds ← DSForTrace[vd.polys]];
END;
outline =>
BEGIN
lda ← LIST[ds ← DSForOutline[vd.polys]];
END;
fill =>
BEGIN
lda ← LIST[da ← DAForFill[vd.polys]];
END;
ENDCASE => ERROR;
END;
DAForPolys:
PROC [polyList: PolyList]
RETURNS [da: DrawAreas] =
BEGIN
da ← NEW [DrawAreasRep ← [PathsForPolys[polyList, 2]]];
END;
PathsForPolys:
PROC [polyList: PolyList, mult:
CARDINAL ← 1]
RETURNS [paths: DetailedPathList] =
BEGIN
last: DetailedPathList ← paths ← NIL;
FOR polyList ← polyList, polyList.rest
WHILE polyList #
NIL
DO
this: DetailedPathList ← LIST[[path: NewPath[size: 1 + 2*polyList.first.vertexCount], coloring: polyList.first.coloring]];
IF last = NIL THEN paths ← this ELSE last.rest ← this;
last ← this;
ENDLOOP;
END;
DAForFill:
PROC [polyList: PolyList]
RETURNS [da: DrawAreas] =
BEGIN
last: DetailedPathList ← NIL;
da ← NEW [DrawAreasRep ← [areaPaths: NIL]];
FOR polyList ← polyList, polyList.rest
WHILE polyList #
NIL
DO
this: DetailedPathList ← LIST[[coloring: polyList.first.coloring, path: NewPath[polyList.first.vertexCount + 1]]];
IF last = NIL THEN da.areaPaths ← this ELSE last.rest ← this;
last ← this;
ENDLOOP;
END;
DSForOutline:
PROC [polyList: PolyList]
RETURNS [ds: DrawStrokes] =
BEGIN
last: DetailedPathList ← NIL;
ds ← NEW [DrawStrokesRep ← [strokePaths: NIL]];
FOR polyList ← polyList, polyList.rest
WHILE polyList #
NIL
DO
this: DetailedPathList ← LIST[[coloring: polyList.first.coloring, path: NewPath[polyList.first.vertexCount + 1]]];
IF last = NIL THEN ds.strokePaths ← this ELSE last.rest ← this;
last ← this;
ENDLOOP;
END;
DSForTrace:
PROC [polyList: PolyList]
RETURNS [ds: DrawStrokes] =
BEGIN
last: DetailedPathList ← NIL;
ds ← NEW [DrawStrokesRep ← [strokePaths: NIL]];
FOR polyList ← polyList, polyList.rest
WHILE polyList #
NIL
DO
THROUGH [1 .. polyList.first.vertexCount]
DO
this: DetailedPathList ← LIST[[coloring: polyList.first.coloring, path: NewPath[2]]];
IF last = NIL THEN ds.strokePaths ← this ELSE last.rest ← this;
last ← this;
ENDLOOP;
ENDLOOP;
END;
StepCmd:
PUBLIC
PROC [vd: ViewerData] =
{
IF
NOT OKToRun[vd]
THEN
RETURN;
BEGIN ENABLE UNWIND => UnRun[vd, TRUE];
da: DrawAreas;
ds: DrawStrokes;
lda: LORA;
[lda, da, ds] ← PrepareToRun[vd];
StepHack[vd, lda, da, ds];
END;
UnRun[vd, TRUE];
};
NewDT:
PROC [strict:
BOOLEAN]
RETURNS [DrawTriangles] =
{RETURN [NEW [DrawTrianglesRep ← [strict, NewPath[4]]]]};
StepHack:
PUBLIC
PROC [vd: ViewerData, lda:
LORA, da: DrawAreas, ds: DrawStrokes] =
BEGIN
IF vd.ctlPanel.stop THEN ERROR ABORTED[];
Process.CheckForAbort[];
SELECT vd.ctlPanel.mode
FROM
sweep => SweepHack[vd, da, lda];
outline => OutlineHack[vd, ds, lda];
fill => FillHack[vd, da, lda];
trace => TraceHack[vd, ds, lda];
ENDCASE => ERROR;
END;
OutlineHack:
PROC [vd: ViewerData, ds: DrawStrokes, lda:
LORA] =
BEGIN
paths: DetailedPathList ← ds.strokePaths;
FOR polyList: PolyList ← vd.polys, polyList.rest
WHILE polyList #
NIL
DO
ResetPath[paths.first.path];
FOR vr: VertexRing ← polyList.first.vertices.next, vr.next
WHILE vr # polyList.first.vertices
DO
ExtendPath[paths.first.path, vr.vertex.curLoc];
StepVertex[vr.vertex, vd.ctlPanel.speed];
ENDLOOP;
StepPoly[polyList.first];
paths ← paths.rest;
ENDLOOP;
ViewerOps.PaintViewer[viewer: vd.viewer, hint: client, whatChanged: lda, clearClient: FALSE];
END;
FillHack:
PROC [vd: ViewerData, da: DrawAreas, lda:
LORA] =
BEGIN
paths: DetailedPathList ← da.areaPaths;
FOR polyList: PolyList ← vd.polys, polyList.rest
WHILE polyList #
NIL
DO
ResetPath[paths.first.path];
FOR vr: VertexRing ← polyList.first.vertices.next, vr.next
WHILE vr # polyList.first.vertices
DO
ExtendPath[paths.first.path, vr.vertex.curLoc];
StepVertex[vr.vertex, vd.ctlPanel.speed];
ENDLOOP;
StepPoly[polyList.first];
paths ← paths.rest;
ENDLOOP;
ViewerOps.PaintViewer[viewer: vd.viewer, hint: client, whatChanged: lda, clearClient: FALSE];
END;
TraceHack:
PROC [vd: ViewerData, ds: DrawStrokes, lds:
LORA] =
BEGIN
paths: DetailedPathList ← ds.strokePaths;
FOR polyList: PolyList ← vd.polys, polyList.rest
WHILE polyList #
NIL
DO
poly: Poly ← polyList.first;
last: VertexRing ← IF poly.closed THEN poly.vertices.prev ELSE poly.vertices;
FOR vr: VertexRing ← poly.vertices.next, vr.next
WHILE vr # last
DO
ResetPath[paths.first.path];
ExtendPath[paths.first.path, vr.vertex.curLoc];
StepVertex[vr.vertex, vd.ctlPanel.speed];
ExtendPath[paths.first.path, vr.vertex.curLoc];
paths ← paths.rest;
ENDLOOP;
IF poly.closed THEN StepVertex[last.vertex, vd.ctlPanel.speed];
StepPoly[polyList.first];
ENDLOOP;
ViewerOps.PaintViewer[viewer: vd.viewer, hint: client, whatChanged: lds, clearClient: FALSE];
END;
SweepHack:
PROC [vd: ViewerData, da: DrawAreas, lda:
LORA] =
BEGIN
SELECT vd.ctlPanel.method
FROM
polygons =>
BEGIN
paths: DetailedPathList;
paths ← da.areaPaths;
FOR polyList: PolyList ← vd.polys, polyList.rest
WHILE polyList #
NIL
DO
SweepPoly[polyList.first, vd, paths];
StepPoly[polyList.first];
paths ← paths.rest;
ENDLOOP;
END;
triangles, quadrilaterals => {
FOR polyList: PolyList ← vd.polys, polyList.rest
WHILE polyList #
NIL
DO
StepPoly[polyList.first];
ENDLOOP;
};
ENDCASE => ERROR;
ViewerOps.PaintViewer[viewer: vd.viewer, hint: client, whatChanged: lda, clearClient: FALSE];
END;
SweepPoly:
PROC [poly: Poly, vd: ViewerData, paths: DetailedPathList] =
BEGIN
AddVertex:
PROC [v: Vertex] =
INLINE
BEGIN
p: Point ← v.curLoc;
IF vd.ctlPanel.round THEN p ← RoundPoint[p];
ExtendPath[paths.first.path, p];
END;
firstLooked: BOOLEAN ← TRUE;
ResetPath[paths.first.path];
FOR vr: VertexRing ← poly.vertices.next, vr.next
WHILE vr # poly.vertices
DO
IF firstLooked
THEN
BEGIN
firstLooked ← FALSE;
IF NOT vr.paintHalf THEN AddVertex[vr.vertex];
END
ELSE AddVertex[vr.vertex];
StepVertex[vr.vertex, vd.ctlPanel.speed];
ENDLOOP;
firstLooked ← TRUE;
FOR vr: VertexRing ← poly.vertices.prev, vr.prev
WHILE vr # poly.vertices
DO
IF firstLooked
THEN
BEGIN
firstLooked ← FALSE;
IF vr.paintHalf THEN LOOP;
END;
AddVertex[vr.vertex];
ENDLOOP;
END;
StepVertex:
PROC [v: Vertex, speed:
REAL] =
INLINE
BEGIN
v.class.StepVertex[v, speed];
END;
bounceClass:
PUBLIC VertexClass ←
NEW [VertexClassRep ← [
name: "Bounce",
StepVertex: StepBounce,
Copy: CopyBounce,
WriteData: WriteBounce,
VertexBounds: BounceBounds]];
BounceBounds:
PROC [v: Vertex]
RETURNS [Box] =
BEGIN
b: Bounce ← NARROW[v.data];
RETURN [[xmin: b.xmin, ymin: b.ymin, xmax: b.xmax, ymax: b.ymax]];
END;
WriteBounce:
PROC [to:
IO.
STREAM, data: VertexData] =
BEGIN
b: Bounce ← NARROW[data];
to.PutF[", dx:%g, dy:%g", IO.real[b.dx], IO.real[b.dy]];
to.PutF[", box: [%g, %g, %g, %g]", IO.real[b.xmin], IO.real[b.ymin], IO.real[b.xmax], IO.real[b.ymax]];
END;
CopyBounce:
PROC [vd: VertexData]
RETURNS [VertexData] =
BEGIN
b: Bounce ← NARROW[vd];
RETURN [NEW [BounceRep ← b^]];
END;
StepBounce:
PROC [v: Vertex, s:
REAL] =
BEGIN
AddAndBounce:
PROC [zi, dzi, zmin, zmax:
REAL]
RETURNS [z, dz:
REAL] =
INLINE
BEGIN
z ← zi + s*dzi;
IF z <= zmin THEN {z ← 2*zmin-z; dz ← -dzi}
ELSE IF z >= zmax THEN {z ← 2*zmax-z; dz ← -dzi}
ELSE dz ← dzi;
END;
b: Bounce ← NARROW[v.data];
[v.curLoc.x, b.dx] ← AddAndBounce[v.curLoc.x, b.dx, b.xmin, b.xmax];
[v.curLoc.y, b.dy] ← AddAndBounce[v.curLoc.y, b.dy, b.ymin, b.ymax];
END;
MakeRandomBouncePoly:
PUBLIC
PROC [nVerts:
CARDINAL, xmax, ymax:
INT ← 400, dxmax, dymax:
INT ← 10, close:
BOOLEAN ←
TRUE]
RETURNS [poly: Poly] =
BEGIN
poly ← NewPoly[close, whiteColoring];
FOR n:
CARDINAL
IN [1 .. nVerts]
DO
v: Vertex ← RandomBounce[xmax, ymax, dxmax, dymax];
AddVertexToPoly[v, poly];
ENDLOOP;
Finish[poly];
END;
RandomBounce:
PUBLIC
PROC [xmax, ymax, dxmax, dymax:
INT]
RETURNS [v: Vertex] =
BEGIN
v ← NewBounce[
x: rs.ChooseInt[min: 0, max: xmax],
y: rs.ChooseInt[min: 0, max: ymax],
dx: PickVelocity[dxmax],
dy: PickVelocity[dymax],
xmin: 0, xmax: xmax, ymin: 0, ymax: ymax];
END;
NewBounce:
PUBLIC
PROC [x, y, dx, dy, xmin, ymin, xmax, ymax:
REAL]
RETURNS [v: Vertex] =
BEGIN
v ←
NEW [VertexRep ← [
curLoc: [x: x, y: y],
class: bounceClass,
data:
NEW [BounceRep ← [
dx: dx, dy: dy,
xmin: xmin, xmax: xmax, ymin: ymin, ymax: ymax]] ]];
END;
PickVelocity:
PROC [max:
INT]
RETURNS [v:
REAL
--[-max .. max]--] =
BEGIN
v ← rs.ChooseInt[min: -max, max: max] * rs.ChooseInt[min: 1, max: max] / REAL[max];
END;
NewSum:
PUBLIC
PROC [a, b: Vertex, aOld:
BOOLEAN]
RETURNS [c: Vertex] =
BEGIN
s: Sum ← NEW [SumRep ← [a, b, aOld]];
c ←
NEW [VertexRep ← [
curLoc: [x: a.curLoc.x + b.curLoc.x, y: a.curLoc.y + b.curLoc.y],
class: sumClass,
data: s]];
END;
Sum: TYPE = REF SumRep;
SumRep:
TYPE =
RECORD [
a, b: Vertex,
aOld: BOOLEAN];
sumClass: VertexClass ←
NEW [VertexClassRep ← [
name: "Sum",
StepVertex: StepSum,
Copy: CopySum,
WriteData: WriteSum,
VertexBounds: SumBounds]];
SumBounds:
PROC [v: Vertex]
RETURNS [b: Box] =
BEGIN
s: Sum ← NARROW[v.data];
b ← ImagerBox.BoxFromRect[Geom2D.SweepRects[
ImagerBox.RectFromBox[VertexBounds[s.a]],
ImagerBox.RectFromBox[VertexBounds[s.b]]
]];
END;
StepSum:
PROC [v: Vertex, speed:
REAL] =
BEGIN
s: Sum ← NARROW[v.data];
IF NOT s.aOld THEN StepVertex[s.a, speed];
StepVertex[s.b, speed];
v.curLoc.x ← s.a.curLoc.x + s.b.curLoc.x;
v.curLoc.y ← s.a.curLoc.y + s.b.curLoc.y;
END;
CopySum:
PROC [vd: VertexData]
RETURNS [new: VertexData] =
{new ← NEW [SumRep ← NARROW[vd, Sum]^]};
WriteSum:
PROC [to:
IO.
STREAM, data: VertexData] =
BEGIN
s: Sum ← NARROW[data];
to.PutRope[", "]; SS.Bp[ss: to, united: FALSE, offset: 4];
to.PutRope["a:"]; IF s.aOld THEN to.PutF["old(x:%g, y:%g)", IO.real[s.a.curLoc.x], IO.real[s.a.curLoc.y]] ELSE WriteVertex[to, s.a];
to.PutRope[", "]; SS.Bp[ss: to, united: FALSE, offset: 4];
to.PutRope["b:"]; WriteVertex[to, s.b];
END;
NewLisasjous:
PUBLIC
PROC [x, y: Sinusoid]
RETURNS [v: Vertex] =
BEGIN
l: Lisasjous ← NEW [LisasjousRep ← [x: x, y: y]];
v ← NEW [VertexRep ← [curLoc: [x: 0, y: 0], class: lisasjousClass, data: l]];
SetLisasjousXY[v, l];
END;
Lisasjous: TYPE = REF LisasjousRep;
LisasjousRep:
TYPE =
RECORD [
x, y: Sinusoid];
lisasjousClass: VertexClass ←
NEW [VertexClassRep ← [
name: "Lisasjous",
StepVertex: StepLisasjous,
Copy: CopyLisasjous,
WriteData: WriteLisasjous,
VertexBounds: LisasjousBounds]];
LisasjousBounds:
PROC [v: Vertex]
RETURNS [bounds: Box] =
BEGIN
l: Lisasjous ← NARROW[v.data];
[bounds.xmin, bounds.xmax] ← SinusoidBounds[l.x];
[bounds.ymin, bounds.ymax] ← SinusoidBounds[l.y];
END;
SinusoidBounds:
PROC [s: Sinusoid]
RETURNS [min, max:
REAL] =
BEGIN
IF s.stepSize = 0 THEN min ← max ← s.base + s.amplitude*RealFns.SinDeg[s.theta] ELSE {min ← s.base-ABS[s.amplitude]; max ← s.base+ABS[s.amplitude]};
END;
WriteLisasjous:
PROC [to:
IO.
STREAM, data: VertexData] =
BEGIN
l: Lisasjous ← NARROW[data];
to.PutRope[", "]; SS.Bp[ss: to, united: TRUE, offset: 4];
to.PutRope["x:"]; WriteSinusoid[to, l.x];
to.PutRope[", "]; SS.Bp[ss: to, united: TRUE, offset: 4];
to.PutRope["y:"]; WriteSinusoid[to, l.y];
END;
WriteSinusoid:
PROC [to:
IO.
STREAM, s: Sinusoid] =
BEGIN
SS.Begin[to];
to.PutF["[base:%g, ampl:%g, step:%g, theta:%g]", IO.real[s.base], IO.real[s.amplitude], IO.real[s.stepSize], IO.real[s.theta]];
SS.End[to];
END;
CopyLisasjous:
PROC [old: VertexData]
RETURNS [new: VertexData] =
BEGIN
s: Lisasjous ← NARROW[old];
new ← NEW [LisasjousRep ← s^];
END;
StepLisasjous:
PROC [v: Vertex, speed:
REAL] =
BEGIN
l: Lisasjous ← NARROW[v.data];
l.x.theta ← RealMod[l.x.theta + l.x.stepSize*speed, 360.0];
l.y.theta ← RealMod[l.y.theta + l.y.stepSize*speed, 360.0];
SetLisasjousXY[v, l];
END;
RealMod:
PROC [a, b:
REAL]
RETURNS [rem:
REAL] =
INLINE
BEGIN
n: INT ← Reals.RoundLI[a/b];
rem ← a - b*n;
END;
SetLisasjousXY:
PROC [v: Vertex, l: Lisasjous] =
BEGIN
v.curLoc.x ← EvalSinusoid[l.x];
v.curLoc.y ← EvalSinusoid[l.y];
END;
EvalSinusoid:
PROC [s: Sinusoid]
RETURNS [z:
REAL] =
INLINE
{z ← s.base + s.amplitude*RealFns.SinDeg[s.theta]};
constantClass:
PUBLIC VertexClass ←
NEW [VertexClassRep ← [
name: "Constant",
StepVertex: StepConstant,
Copy: CopyConstant,
WriteData: WriteConstant,
VertexBounds: ConstantBounds]];
StepConstant: PROC [Vertex, REAL] = {};
CopyConstant: PROC [VertexData] RETURNS [VertexData] = {RETURN [NIL]};
WriteConstant: PROC [IO.STREAM, VertexData] = {};
ConstantBounds:
PROC [v: Vertex]
RETURNS [bounds: Box] =
{bounds.xmin ← bounds.xmax ← v.curLoc.x; bounds.ymin ← bounds.ymax ← v.curLoc.y};
NewPoly:
PUBLIC
PROC [close:
BOOLEAN ←
TRUE, coloring: Coloring]
RETURNS [p: Poly] =
BEGIN
p ← NEW [PolyRep ← [closed: close, coloring: coloring]];
p.vertices ← NEW [VertexRingRep ← []];
p.vertices.next ← p.vertices.prev ← p.vertices;
END;
ColoringColor:
PUBLIC
PROC [c: Coloring]
RETURNS [color: Color] =
{color ← c.color};
StepPoly:
PUBLIC
PROC [p: Poly] = {
IF
NOT p.coloring.constant
THEN {
p.coloring.arg^ ← p.coloring.arg^ + 1.0;
UpdateColoring[p.coloring];
};
p ← p;
};
UpdateColoring:
PUBLIC
PROC [coloring: Coloring] = {
ra: REF ANY;
ra ← Misp.Eval[raw: coloring.form, environment: coloring.env, stack: coloring.stack];
WITH ra
SELECT
FROM
cr: Color => coloring.color ← cr;
ENDCASE => ERROR;
coloring ← coloring;
};
Finish:
PUBLIC
PROC [poly: Poly] =
BEGIN
IF poly.vertices.next # poly.vertices AND poly.closed THEN AddVertexToPoly[Copy[poly.vertices.next.vertex], poly];
END;
AddVertexToPoly:
PUBLIC
PROC [v: Vertex, p: Poly] =
BEGIN
vr: VertexRing ← NEW [VertexRingRep ← [next: p.vertices, prev: p.vertices.prev, vertex: v]];
vr.prev.next ← vr;
vr.next.prev ← vr;
p.vertexCount ← p.vertexCount + 1;
END;
NewPath:
PUBLIC
PROC [size:
NAT]
RETURNS [p: Path] = {
p ← NEW [PathRep[size]];
p.length ← 0;
};
ResetPath:
PUBLIC
PROC [p: Path] = {
p.length ← 0;
};
ExtendPath:
PUBLIC
PROC [path: Path, p: Point] = {
path[path.length] ← p;
path.length ← path.length + 1;
};
DefineHackAStuff:
PUBLIC
PROC [environment: Misp.Environment, vd: ViewerData] =
BEGIN
Misp.Bind[$sweep, NEW [Mode ← sweep], environment, TRUE];
Misp.Bind[$outline, NEW [Mode ← outline], environment, TRUE];
Misp.Bind[$fill, NEW [Mode ← fill], environment, TRUE];
Misp.Bind[$trace, NEW [Mode ← trace], environment, TRUE];
END;
Setup[];
END.