HideSweepImpl.mesa
Copyright © 1985 by Xerox Corporation. All rights reserved.
Greene, March 28, 1986 5:00:36 pm PST
DIRECTORY
Buttons USING [Button, ButtonProc, Create],
Commander USING [CommandProc, Register],
Containers USING [Container, Create],
Imager USING [black, Context, Color, ScaleT, MaskFillTrajectory, MaskStrokeTrajectory, SetColor, SetStrokeWidth],
ImagerColor USING [ColorFromRGB, RGB],
ImagerPath USING[LineTo, MoveTo, Trajectory],
FS USING [StreamOpen],
IO USING [Close, GetCedarTokenRope, GetReal, PutF, PutFR, PutRope, real, RIS, STREAM, TokenKind, EndOf],
Menus USING[CreateMenu, AppendMenuEntry, CreateEntry, Menu, ClickProc],
Real USING [Float, Round],
RealFns USING [AlmostZero, SinDeg, CosDeg, SqRt],
Rope USING [Cat, Equal, ROPE],
Sweep,
Vector2 USING [VEC],
ViewerClasses USING [ViewerClass, ViewerClassRec, Viewer, PaintProc, NotifyProc],
ViewerOps USING [CreateViewer, RegisterViewerClass, PaintViewer],
ViewerTools USING [MakeNewTextViewer, SetSelection, SetContents, GetContents];
HideSweepImpl: CEDAR MONITOR
LOCKS my USING my: State
IMPORTS Buttons, Containers, Commander, FS, IO, Imager, ImagerPath, ImagerColor, Menus, Real, RealFns, Rope, Sweep, ViewerOps, ViewerTools =
BEGIN OPEN Sweep;
leafBucketSize: CARDINAL ← 12;
branchingFactor: CARDINAL ← 4;
sticks: BOOLEANFALSE;
surfaces: BOOLEANTRUE;
shade: BOOLEANTRUE;
diffuse: REAL ← .30;
perspective: BOOLEANTRUE;
eye: REAL ← -6.0; --Eye is at (0, 0, eye)
eyeToScreen: REAL ← 1.0;
screenSize: REAL ← .2;
largestEyeToObject: REAL ← 20.0;
Perspective: PROC [i: Point3] RETURNS [o: Point3] ~ {
f: REAL ← screenSize * (i[3] - eye) / eyeToScreen;
o[1] ← i[1]/f;
o[2] ← i[2]/f;
o[3] ← (f - screenSize) / ( (1.0 - eyeToScreen/largestEyeToObject) * f)
};
Point3: TYPE = ARRAY [1..3] OF REAL;
Matrix33: TYPE = ARRAY [1..3] OF ARRAY [1..3] OF REAL;
Rotate: PROC [p: Point3, m: Matrix33 ] RETURNS [q: Point3] ~ {
FOR i: CARDINAL IN [1..3] DO
q[i] ← 0;
FOR j: CARDINAL IN [1..3] DO
q[i] ← q[i] + m[i][j]*p[j];
ENDLOOP;
ENDLOOP;
};
ScaleTranslate: PROC [p: Point3] RETURNS [q: Point3] ~ {
FOR i: CARDINAL IN [1..3] DO
q[i] ← p[i] * 2000.0 --Spots per inch
ENDLOOP;
q[1] ← q[1] + 10000.0; q[2] ← q[2] + 10000.0
};
Dot: PROC [p, q: Point3] RETURNS [s: REAL ← 0.0] ~ {
FOR i: CARDINAL IN [1..3] DO
s ← s + p[i] * q[i];
ENDLOOP;
};
Cross: PROC [p, q: Point3] RETURNS [r: Point3] ~ {
FOR i: CARDINAL IN [1..3] DO
n: CARDINAL ← (i MOD 3) + 1;
nn: CARDINAL ← (n MOD 3) + 1;
r[i] ← p[n]*q[nn] - p[nn]*q[n];
ENDLOOP;
};
Sub: PROC [p, q: Point3] RETURNS [r: Point3] ~ {
FOR i: CARDINAL IN [1..3] DO
r[i] ← p[i] - q[i];
ENDLOOP;
};
Add: PROC [p, q: Point3] RETURNS [r: Point3] ~ {
FOR i: CARDINAL IN [1..3] DO
r[i] ← p[i] + q[i];
ENDLOOP;
};
Facet: TYPE = REF FacetRec;
FacetRec: TYPE = RECORD [
a, b, c, n: Point3,
color: ImagerColor.RGB];
Scene: TYPE = LIST OF Facet;
Union: PROC [a, b: LIST OF Facet] RETURNS [c: LIST OF Facet ← NIL] ~ {
merge according to pointer order, cancel duplicates
t: LIST OF Facet ← NIL;
DO
IF a = NIL THEN {
IF b # NIL THEN
IF t = NIL THEN c ← b ELSE t.rest ← b;
RETURN};
IF b = NIL THEN {
IF a # NIL THEN
IF t = NIL THEN c ← a ELSE t.rest ← a;
RETURN};
IF a.first = b.first THEN {a ← a.rest; b ← b.rest} --cancel duplicates
ELSE {
IF LOOPHOLE[a.first, LONG CARDINAL] < LOOPHOLE[b.first, LONG CARDINAL] THEN {
IF t = NIL THEN {c ← LIST[a.first]; t ← c} ELSE {t.rest ← LIST[a.first]; t ← t.rest};
a ← a.rest}
ELSE {
IF t = NIL THEN {c ← LIST[b.first]; t ← c} ELSE {t.rest ← LIST[b.first]; t ← t.rest};
b ← b.rest};
};
ENDLOOP;
};
Copy: PROC [a: LIST OF Facet] RETURNS [b: LIST OF Facet ← NIL] ~ {
keep ordering of a
t: LIST OF Facet;
IF a = NIL THEN RETURN ELSE b ← t ← CONS[a.first, NIL];
a ← a.rest;
UNTIL a = NIL DO
t.rest ← CONS[a.first, NIL];
a ← a.rest; t ← t.rest;
ENDLOOP;
};
Change: PROC [a, b: LIST OF Facet, x, y: REAL] RETURNS [c: LIST OF Facet ← NIL] ~ {
c will reflect order of a toggling elements of b
IF b = NIL THEN RETURN[a];
c ← Copy[a];
UNTIL b = NIL DO
s, p: LIST OF Facet;
BEGIN
s ← c; p ← NIL;
DO
IF s = NIL THEN GOTO Insert;
IF s.first = b.first THEN EXIT;
p ← s; s ← s.rest;
ENDLOOP;
IF p = NIL THEN c ← s.rest ELSE p.rest ← s.rest;
EXITS
Insert => {
s ← c; p ← NIL;
IF s # NIL THEN
UNTIL InFront[b.first, s.first, x, y] DO
p ← s; s ← s.rest;
IF s = NIL THEN EXIT;
ENDLOOP;
IF p = NIL THEN c ← CONS[b.first, s] ELSE p.rest ← CONS[b.first, s];
}
END;
b ← b.rest;
ENDLOOP;
};
InFront: PROC [f,g: Facet, x, y: REAL] RETURNS [BOOLEAN] ~ {
fz, gz: REAL;
IF f.n[3] = 0 THEN RETURN[TRUE]; --f is end on
IF g.n[3] = 0 THEN RETURN[FALSE]; --g is end on
fz ← - ((x - f.a[1])*f.n[1] + (y - f.a[2])*f.n[2])/ f.n[3] + f.a[3];
gz ← - ((x - g.a[1])*g.n[1] + (y - g.a[2])*g.n[2])/ g.n[3] + g.a[3];
RETURN[ fz < gz ];
};
Scale: INT ← 2000;
State: TYPE = REF StateRec;
StateRec: TYPE = MONITORED RECORD [
outer: Containers.Container ← NIL,
menu: Menus.Menu,
fileNameInput, rotateYInput,
inner: ViewerClasses.Viewer,
scene: Scene ← NIL,
output: Graph];
ShowHide: Commander.CommandProc = {
my: State ← NEW[StateRec];
fileNameButton, rotateYButton: Buttons.Button;
my.menu ← Menus.CreateMenu[];
my.menu.AppendMenuEntry[Menus.CreateEntry["Clear", ClearProc, my]];
my.menu.AppendMenuEntry[Menus.CreateEntry["View", ViewProc, my]];
my.outer ← Containers.Create[[
name: "Hide",
menu: my.menu,
scrollable: FALSE]];
fileNameButton ← Buttons.Create[
info:
[name: "Input File Name:",
wx: 10, wy: 10, wh: 15,
parent: my.outer,
border: FALSE],
proc: ForceFileName,
clientData: my];
my.fileNameInput ← ViewerTools.MakeNewTextViewer[[
parent: my.outer,
wx: fileNameButton.wx + fileNameButton.ww + 20,
wy: 10, wh: 15, ww: 500,
scrollable: FALSE,
border: FALSE]];
ViewerTools.SetContents[my.fileNameInput, "[]<>sweep>Test.facets"];
rotateYButton ← Buttons.Create[
info:
[name: "Rotate Around Y:",
wx: 400, wy: 10, wh: 15,
parent: my.outer,
border: FALSE],
proc: ForceRotateY,
clientData: my];
my.rotateYInput ← ViewerTools.MakeNewTextViewer[[
parent: my.outer,
wx: rotateYButton.wx + rotateYButton.ww + 20,
wy: 10, wh: 15, ww: 500,
scrollable: FALSE,
border: FALSE]];
ViewerTools.SetContents[my.rotateYInput, "-60.0"];
my.inner ← ViewerOps.CreateViewer[
flavor: $ShowHide,
info: [wx: 5, wy: 30, wh: 400, ww: 630, parent: my.outer, data: my]];
ViewerOps.PaintViewer[viewer: my.inner, hint: all];
};
ForceFileName: Buttons.ButtonProc -- [parent: REF ANY, clientData: REF ANY ← NIL, mouseButton: Menus.MouseButton ← red, shift: BOOL ← FALSE, control: BOOL ← FALSE] -- = {
my: State ← NARROW[clientData];
ViewerTools.SetSelection[my.fileNameInput];
};
ForceRotateY: Buttons.ButtonProc -- [parent: REF ANY, clientData: REF ANY ← NIL, mouseButton: Menus.MouseButton ← red, shift: BOOL ← FALSE, control: BOOL ← FALSE] -- = {
my: State ← NARROW[clientData];
ViewerTools.SetSelection[my.rotateYInput];
};
ClearProc: Menus.ClickProc = {
my: State ← NARROW[clientData];
ClearLocked[my];
ViewerOps.PaintViewer[viewer: my.inner, hint: all];
};
ClearLocked: ENTRY PROC[my: State] ~ {
ENABLE UNWIND => NULL;
DestroyGraph[my.output];
my.output ← NIL;
};
ViewProc: Menus.ClickProc = {
my: State ← NARROW[clientData];
ViewLocked[my];
ViewerOps.PaintViewer[viewer: my.inner, hint: all];
};
HideLine: TYPE = REF HideLineRec;
HideLineRec: TYPE = RECORD [
changing: LIST OF Facet
];
HideRegion: TYPE = REF HideRegionRec;
HideRegionRec: TYPE = RECORD[
facets: LIST OF Facet ← NIL];
hideInfinityRegion: HideRegion = NEW[HideRegionRec ← [facets: NIL]];
HideCopy: CopyLineProc = {
RETURN[stateIn]
};
HideFlip: FlipLineProc = {
RETURN[stateIn]
};
HideCombine: CombineLineProc = {
s1: HideLine ← NARROW[state1];
s2: HideLine ← NARROW[state2];
sO: HideLine ← NEW[HideLineRec ← [
changing: Union[s1.changing, s2.changing]]];
RETURN[sO];
};
ViewLocked: ENTRY PROC[my: State] ~ {
ENABLE UNWIND => NULL;
HideStart: StartRegionProc = {
rP: HideRegion ← NARROW[regionPrevious];
lR: HideLine ← NARROW[lineRight.state];
x: REAL ← (lineRight.above.x + lineRight.below.x + lineLeft.below.x) / 3.0;
y: REAL ← (lineRight.above.y + lineRight.below.y + lineLeft.below.y) / 3.0;
rC: HideRegion ← NEW[HideRegionRec ← [facets: Change[rP.facets, lR.changing, x, y] ] ];
FixLineState[rC, lineRight, rP];
RETURN[rC];
};
HideStop: StopRegionProc = {
IF UselessTest[NARROW[lineLeft.state]] THEN RemoveLineFromEndPoints[lineLeft];
};
HideSplit: SplitRegionProc = {
FixLineState[NARROW[regionRight], lineLeft, NARROW[regionPrevious]];
RETURN[regionRight];
};
HideMerge: MergeRegionProc = {
IF UselessTest[NARROW[lineRight.state]] THEN RemoveLineFromEndPoints[lineRight];
RETURN[regionRight];
};
HideLineChange: LineChangeRegionProc = {
IF side = left THEN {
IF UselessTest[NARROW[lineOld.state]] THEN RemoveLineFromEndPoints[lineOld];
}
ELSE
FixLineState[NARROW[regionCenter], lineNew, NARROW[regionPrevious]];
};
UselessTest: PROC [line: HideLine] RETURNS [BOOL] ~ INLINE {
RETURN[line.changing = NIL]
};
FixLineState: PROC [regionLeft: HideRegion, lineCenter: Line, regionRight: HideRegion] ~ {
lF: LIST OF Facet ← IF regionLeft.facets = NIL THEN NIL ELSE LIST[regionLeft.facets.first];
rF: LIST OF Facet ← IF regionRight.facets = NIL THEN NIL ELSE LIST[regionRight.facets.first];
lineCenter.state ← NEW[HideLineRec ← [changing: Union[lF, rF]]];
};
input: Graph ← NewGraph[];
workLoad, newWorkLoad: LIST OF Graph ← NIL;
facetCount: LONG CARDINAL;
inputFile: IO.STREAMFS.StreamOpen[ViewerTools.GetContents[my.fileNameInput]];
scanScene: Scene;
master: Matrix33;
sin, cos: REAL;
my.scene ← NIL;
UNTIL inputFile.EndOf[] DO
f: Facet ← NEW[FacetRec];
sep: Rope.ROPE;
f.a[1] ← inputFile.GetReal[];
f.a[2] ← inputFile.GetReal[];
f.a[3] ← inputFile.GetReal[];
sep ← inputFile.GetCedarTokenRope[].token;
IF NOT Rope.Equal[sep, ","] THEN ERROR;
f.b[1] ← inputFile.GetReal[];
f.b[2] ← inputFile.GetReal[];
f.b[3] ← inputFile.GetReal[];
sep ← inputFile.GetCedarTokenRope[].token;
IF NOT Rope.Equal[sep, ","] THEN ERROR;
f.c[1] ← inputFile.GetReal[];
f.c[2] ← inputFile.GetReal[];
f.c[3] ← inputFile.GetReal[];
sep ← inputFile.GetCedarTokenRope[].token;
IF NOT Rope.Equal[sep, "/"] THEN ERROR;
f.color.R ← inputFile.GetReal[];
f.color.G ← inputFile.GetReal[];
f.color.B ← inputFile.GetReal[];
my.scene ← CONS[f, my.scene];
ENDLOOP;
sin ← RealFns.SinDeg[RealFromRope[ViewerTools.GetContents[my.rotateYInput]]];
cos ← RealFns.CosDeg[RealFromRope[ViewerTools.GetContents[my.rotateYInput]]];
master ← [[cos, 0.0, -sin], [0.0, 1.0, 0.0], [sin, 0.0, cos]];
DestroyGraph[my.output]; my.output ← NIL;
scanScene ← my.scene;
facetCount ← 1;
UNTIL scanScene = NIL DO
OPEN Real;
of: Facet ← scanScene.first;
nf: Facet ← NEW[FacetRec];
lineState: HideLine ← NEW[HideLineRec ← [LIST[nf]]];
nf.a ← Rotate[of.a, master]; nf.b ← Rotate[of.b, master]; nf.c ← Rotate[of.c, master]; nf.color ← of.color;
nf.n ← Cross[ Sub[nf.b, nf.a], Sub[nf.c, nf.a] ];
IF shade THEN {
length: REAL ← RealFns.SqRt[ABS[Dot[nf.n, nf.n]]];
cos ← IF RealFns.AlmostZero[length, -50] THEN 0.0 ELSE ABS[nf.n[3]/length];
nf.color.R ← nf.color.R*(cos*(1.0 - diffuse) + diffuse);
nf.color.G ← nf.color.G*(cos*(1.0 - diffuse) + diffuse);
nf.color.B ← nf.color.B*(cos*(1.0 - diffuse) + diffuse);
};
IF perspective THEN {
nf.a ← Perspective[nf.a]; nf.b ← Perspective[nf.b]; nf.c ← Perspective[nf.c];
nf.n ← Cross[ Sub[nf.b, nf.a], Sub[nf.c, nf.a] ];
};
nf.a ← ScaleTranslate[nf.a]; nf.b ← ScaleTranslate[nf.b]; nf.c ← ScaleTranslate[nf.c];
input ← NewPoint[input, Round[nf.a[1]], Round[nf.a[2]] ];
input ← input.LineTo[Round[nf.b[1]], Round[nf.b[2]], lineState, HideFlip];
input ← input.LineTo[Round[nf.c[1]], Round[nf.c[2]], lineState, HideFlip];
input ← input.LineTo[Round[nf.a[1]], Round[nf.a[2]], lineState, HideFlip];
IF facetCount MOD leafBucketSize = 0 THEN {
my.output ← Intersect[input, HideCopy, HideCombine, HideFlip];
my.output ← Sweep[my.output, hideInfinityRegion, HideStart, HideStop, HideSplit, HideMerge, HideLineChange];
workLoad ← CONS[my.output, workLoad];
input ← NewGraph[];
};
scanScene ← scanScene.rest;
facetCount ← facetCount + 1;
ENDLOOP;
IF input.points.size # 0 THEN {
my.output ← Intersect[input, HideCopy, HideCombine, HideFlip];
my.output ← Sweep[my.output, hideInfinityRegion, HideStart, HideStop, HideSplit, HideMerge, HideLineChange];
workLoad ← CONS[my.output, workLoad];
input ← NewGraph[];
};
DO
newWorkLoad ← NIL;
UNTIL workLoad = NIL DO
input ← NIL;
FOR i:CARDINAL IN [1..branchingFactor] DO
IF workLoad = NIL THEN {IF i = 2 THEN GOTO FreePass ELSE EXIT};
input ← MergeGraphs[input, workLoad.first];
workLoad ← workLoad.rest;
ENDLOOP;
my.output ← Intersect[input, HideCopy, HideCombine, HideFlip];
my.output ← Sweep[my.output, hideInfinityRegion, HideStart, HideStop, HideSplit, HideMerge, HideLineChange];
newWorkLoad ← CONS[my.output, newWorkLoad];
REPEAT
FreePass => {
newWorkLoad ← CONS[input, newWorkLoad];
};
ENDLOOP;
IF newWorkLoad.rest = NIL THEN EXIT ELSE workLoad ← newWorkLoad;
ENDLOOP;
};
EndOfLines: PROC [in: LIST OF Line] RETURNS [out: LIST OF Line] ~ INLINE {
IF in = NIL THEN RETURN[NIL];
UNTIL in.rest = NIL DO
in ← in.rest;
ENDLOOP;
RETURN[in];
};
RealFromRope: PROC [rawRope: Rope.ROPE] RETURNS [REAL] = INLINE {
OPEN IO;
RETURN [GetReal[RIS[rawRope]]] };
ShowHidePaint: ViewerClasses.PaintProc = {
my:State ← NARROW[self.data];
context.ScaleT[40.0/Scale];
PaintLocked[my, context];
};
TrapRegion: TYPE = REF TrapRegionRec;
TrapRegionRec: TYPE = RECORD [
facet: Facet ← NIL,
lastPointSeen: Point ← NIL,
lineLeft, lineRight: Line ← NIL
];
trapInfinityRegion: TrapRegion = NEW[TrapRegionRec ← [facet: NIL]];
PaintLocked: ENTRY PROC [my: State, context: Imager.Context] ~ {
OPEN Imager, ImagerPath;
ENABLE UNWIND => NULL;
TrapStart: StartRegionProc = {
lR: HideLine ← NARROW[lineRight.state];
rR: TrapRegion ← NARROW[regionPrevious];
cF: LIST OF Facet ← Change[IF rR.facet = NIL THEN NIL ELSE LIST[rR.facet], lR.changing, -1.0, -1.0];
IF cF # NIL THEN
RETURN[NEW[TrapRegionRec ← [facet: cF.first, lastPointSeen: lineLeft.above, lineLeft: lineLeft, lineRight: lineRight]]]
ELSE RETURN[trapInfinityRegion];
};
TrapStop: StopRegionProc = {
rC: TrapRegion ← NARROW[regionCenter];
IF rC # trapInfinityRegion THEN {
PaintTrap[rC.facet.color, rC.lastPointSeen.y, lineLeft.below.y, lineLeft, lineRight];
rC.lineLeft ← rC.lineRight ← NIL;
};
};
TrapSplit: SplitRegionProc = {
rR: TrapRegion ← NARROW[regionRight];
rL: TrapRegion;
point: Point ← lineRight.above;
IF rR # trapInfinityRegion THEN {
PaintTrap[rR.facet.color, rR.lastPointSeen.y, point.y, rR.lineLeft, rR.lineRight];
rR.lastPointSeen ← point;
rL ← NEW[TrapRegionRec ← [facet: rR.facet, lastPointSeen: point, lineLeft: rR.lineLeft, lineRight: lineLeft]];
rR.lineLeft ← lineRight;
RETURN[rL];
}
ELSE
RETURN[rR];
};
TrapMerge: MergeRegionProc = {
rL: TrapRegion ← NARROW[regionLeft];
rR: TrapRegion ← NARROW[regionRight];
point: Point ← lineLeft.below;
IF (rL # trapInfinityRegion) AND (rR # trapInfinityRegion) THEN {
PaintTrap[rL.facet.color, rL.lastPointSeen.y, point.y, rL.lineLeft, rL.lineRight];
PaintTrap[rR.facet.color, rR.lastPointSeen.y, point.y, rR.lineLeft, rR.lineRight];
rR.lastPointSeen ← point;
rR.lineLeft ← rL.lineLeft;
rL.lineLeft ← rL.lineRight ← NIL;
};
RETURN[IF rL = trapInfinityRegion THEN rL ELSE rR];
};
TrapLineChange: LineChangeRegionProc = {
rC: TrapRegion ← NARROW[regionCenter];
point: Point ← lineNew.above;
IF (rC # trapInfinityRegion) THEN {
PaintTrap[rC.facet.color, rC.lastPointSeen.y, point.y, rC.lineLeft, rC.lineRight];
rC.lastPointSeen ← point;
IF side = left THEN rC.lineLeft ← lineNew ELSE rC.lineRight ← lineNew;
};
};
PaintTrap: PROC [c: ImagerColor.RGB, aboveY, belowY: INT, lineLeft, lineRight: Line] ~ {
Trapaziods are easy to paint directly, the following is a slightly inacurate, and extremely inefficient way of painting them.
traj: Trajectory;
lowX: INTMIN[lineLeft.above.x, lineLeft.below.x];
highX: INTMAX[lineRight.above.x, lineRight.below.x];
top: Line ← NEW[LineRec ← [above: NEW[PointRec ← [x: highX, y: aboveY]], below: NEW[PointRec ← [x: lowX, y: aboveY]] ]];
bottom: Line ← NEW[LineRec ← [above: NEW[PointRec ← [x: highX, y: belowY]], below: NEW[PointRec ← [x: lowX, y: belowY]] ]];
topLeft, topRight, bottomLeft, bottomRight: Point;
IF aboveY = belowY THEN RETURN;
[topLeft, ] ← PairIntersection[top, lineLeft];
[topRight, ] ← PairIntersection[top, lineRight];
[bottomLeft, ] ← PairIntersection[bottom, lineLeft];
[bottomRight, ] ← PairIntersection[bottom, lineRight];
traj ← MoveTo[Vfp[topLeft]].LineTo[VfpR[topRight]].LineTo[VfpR[bottomRight]].LineTo[Vfp[bottomLeft]];
context.SetColor[ImagerColor.ColorFromRGB[c]];
MaskFillTrajectory[context, traj];
};
StickStart: StartRegionProc = {
DrawLine[lineRight];
};
StickSplit: SplitRegionProc = {
DrawLine[lineLeft];
};
StickLineChange: LineChangeRegionProc = {
IF side = right THEN DrawLine[lineNew];
};
DrawLine: PROC [line: Line] ~ {
traj: Trajectory;
traj ← MoveTo[Vfp[line.above]].LineTo[Vfp[line.below]];
context.MaskStrokeTrajectory[traj];
};
Vfp: PROC [p: Point] RETURNS [Vector2.VEC] ~ INLINE {
RETURN[[Real.Float[p.x], Real.Float[p.y]]];
};
VfpR: PROC [p: Point] RETURNS [Vector2.VEC] ~ INLINE {
RETURN[[Real.Float[p.x+1], Real.Float[p.y]]];
};
IF surfaces THEN
my.output ← Sweep[my.output, trapInfinityRegion, TrapStart, TrapStop, TrapSplit, TrapMerge, TrapLineChange];
IF sticks THEN {
context.SetColor[Imager.black];
context.SetStrokeWidth[20.0];
my.output ← Sweep[my.output, trapInfinityRegion, StickStart, NilStop, StickSplit, NilMerge, StickLineChange];
};
};
FacetCompile: PROC [in, out: Rope.ROPE] ~ {
inputFile: IO.STREAMFS.StreamOpen[in];
outputFile: IO.STREAMFS.StreamOpen[out, $create];
curve: ARRAY [0..100] OF Point3; position: CARDINAL;
origin, destination: Point3; color: Rope.ROPE;
token: Rope.ROPE; tokenKind: IO.TokenKind;
PutPoint: PROC [p: Point3] ~ {
outputFile.PutF["%g %g %g", IO.real[p[1]], IO.real[p[2]], IO.real[p[3]]];
};
[tokenKind, token,] ← inputFile.GetCedarTokenRope[];
UNTIL inputFile.EndOf[] DO
IF tokenKind # tokenID THEN ERROR;
IF Rope.Equal[token, "STRETCH"] THEN
BEGIN
position ← 0;
DO
curve[position][1] ← inputFile.GetReal[];
curve[position][2] ← inputFile.GetReal[];
curve[position][3] ← inputFile.GetReal[];
[tokenKind, token,] ← inputFile.GetCedarTokenRope[];
IF tokenKind # tokenSINGLE OR (NOT Rope.Equal[token, ","]) THEN EXIT;
position ← position + 1;
ENDLOOP;
IF (tokenKind # tokenID) OR (NOT Rope.Equal[token, "ALONG"]) THEN ERROR;
FOR i: CARDINAL IN [1..3] DO
origin[i] ← inputFile.GetReal[];
ENDLOOP;
[tokenKind, token,] ← inputFile.GetCedarTokenRope[];
IF (tokenKind # tokenSINGLE) OR (NOT Rope.Equal[token, ","]) THEN ERROR;
FOR i: CARDINAL IN [1..3] DO
destination[i] ← inputFile.GetReal[];
ENDLOOP;
[tokenKind, token,] ← inputFile.GetCedarTokenRope[];
IF (tokenKind # tokenSINGLE) OR (NOT Rope.Equal[token, "/"]) THEN ERROR;
color ← "/";
FOR i: CARDINAL IN [1..3] DO
component: REAL ← inputFile.GetReal[];
color ← color.Cat[IO.PutFR[" %g", IO.real[component]]];
ENDLOOP;
IF NOT inputFile.EndOf[] THEN [tokenKind, token,] ← inputFile.GetCedarTokenRope[];
FOR pos: CARDINAL IN [0..position] DO
outputFile.PutRope["
"];
PutPoint[Add[origin, curve[pos]]]; outputFile.PutRope[", "];
PutPoint[Add[origin, curve[(pos + 1) MOD (position + 1)]]]; outputFile.PutRope[", "];
PutPoint[Add[destination, curve[(pos + 1) MOD (position + 1)]]]; outputFile.PutRope[color];
outputFile.PutRope["
"];
PutPoint[Add[destination, curve[pos]]]; outputFile.PutRope[", "];
PutPoint[Add[origin, curve[pos]]]; outputFile.PutRope[", "];
PutPoint[Add[destination, curve[(pos + 1) MOD (position + 1)]]]; outputFile.PutRope[color];
ENDLOOP;
END;
ENDLOOP;
outputFile.Close[];
};
displayerClass: ViewerClasses.ViewerClass ← NEW[ViewerClasses.ViewerClassRec ←
[paint: ShowHidePaint]];
ViewerOps.RegisterViewerClass[$ShowHide, displayerClass];
Commander.Register[key: "ShowHide", proc: ShowHide, doc: "To Debug Hidden Lines"];
END.