HideSweepImpl.mesa
Copyright © 1985 by Xerox Corporation. All rights reserved.
Greene, November 20, 1986 5:13:39 pm PST
DIRECTORY
Basics USING [Comparison],
Buttons USING [Button, ButtonProc, Create],
Commander USING [CommandProc, Register],
Containers USING [Container, Create],
Imager USING [black, Context, Color, ScaleT, RotateT, TranslateT, MaskFillTrajectory, MaskStrokeTrajectory, SetColor, SetStrokeWidth, metersPerInch],
ImagerInterpress USING [DoPage, Create, Close, Ref],
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, AlmostEqual, 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, ImagerInterpress, ImagerPath, ImagerColor, Menus, Real, RealFns, Rope, Sweep, ViewerOps, ViewerTools =
BEGIN OPEN Sweep;
leafBucketSize: CARDINAL ← 12;
branchingFactor: CARDINAL ← 4;
shade: BOOLEANTRUE;
diffuse: REAL ← .30;
tolerance: INT = -12;
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] * Scale --Spots per inch
ENDLOOP;
q[1] ← q[1] + 5*Scale; q[2] ← q[2] + 5*Scale
};
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;
};
ScalarMult: PROC [p: Point3, s: REAL] RETURNS [q: Point3] ~ {
FOR i: CARDINAL IN [1..3] DO
q[i] ← p[i]*s;
ENDLOOP;
};
Multiply: PROC [m1, m2: Matrix33] RETURNS [mp: Matrix33] ~ {
FOR i: CARDINAL IN [1..3] DO
FOR j: CARDINAL IN [1..3] DO
mp[i][j] ← 0;
FOR k: CARDINAL IN [1..3] DO
mp[i][j] ← mp[i][j] + m1[i][k]*m2[k][j];
ENDLOOP;
ENDLOOP;
ENDLOOP;
};
Facet: TYPE = REF FacetRec;
FacetRec: TYPE = RECORD [
number: CARDINAL,
a, b, c, n: Point3,
color: ImagerColor.RGB];
Scene: TYPE = LIST OF Facet;
Scale: INT = 1000;
State: TYPE = REF StateRec;
StateRec: TYPE = MONITORED RECORD [
outer: Containers.Container ← NIL,
menu: Menus.Menu,
fileInNameInput, fileOutNameInput,
rotateXInput, rotateYInput, rotateZInput,
eyeInput, screenSizeInput, eyeToScreenInput: ViewerClasses.Viewer,
sticks: BOOLEANTRUE,
surfaces: BOOLEANTRUE,
inner: ViewerClasses.Viewer,
scene: Scene ← NIL,
output: Graph];
ShowHide: Commander.CommandProc = {
my: State ← NEW[StateRec];
fileInNameButton, fileOutNameButton,
rotateXButton, rotateYButton, rotateZButton,
eyeButton, screenSizeButton, eyeToScreenButton: Buttons.Button;
my.menu ← Menus.CreateMenu[];
my.menu.AppendMenuEntry[Menus.CreateEntry["ClearView", ClearProc, my]];
my.menu.AppendMenuEntry[Menus.CreateEntry["ComputeView", ViewProc, my]];
my.menu.AppendMenuEntry[Menus.CreateEntry["PrintView", PrintProc, my]];
my.menu.AppendMenuEntry[Menus.CreateEntry["ToggleSticks", SticksProc, my]];
my.menu.AppendMenuEntry[Menus.CreateEntry["ToggleSurfaces", SurfacesProc, my]];
my.outer ← Containers.Create[[
name: "Hide",
menu: my.menu,
scrollable: FALSE]];
fileInNameButton ← Buttons.Create[
info:
[name: "Input File Name:",
wx: 10, wy: 10, wh: 15,
parent: my.outer,
border: FALSE],
proc: ForceInName,
clientData: my];
my.fileInNameInput ← ViewerTools.MakeNewTextViewer[[
parent: my.outer,
wx: fileInNameButton.wx + fileInNameButton.ww + 20,
wy: 10, wh: 15, ww: 200,
scrollable: FALSE,
border: FALSE]];
ViewerTools.SetContents[my.fileInNameInput, "[]<>sweep>Test.facets"];
fileOutNameButton ← Buttons.Create[
info:
[name: "Output File Name:",
wx: 300, wy: 10, wh: 15,
parent: my.outer,
border: FALSE],
proc: ForceOutName,
clientData: my];
my.fileOutNameInput ← ViewerTools.MakeNewTextViewer[[
parent: my.outer,
wx: fileOutNameButton.wx + fileOutNameButton.ww + 20,
wy: 10, wh: 15, ww: 200,
scrollable: FALSE,
border: FALSE]];
ViewerTools.SetContents[my.fileOutNameInput, "[]<>sweep>Test.ip"];
rotateXButton ← Buttons.Create[
info:
[name: "X:",
wx: 530, wy: 50, wh: 15,
parent: my.outer,
border: FALSE],
proc: ForceRotateX,
clientData: my];
my.rotateXInput ← ViewerTools.MakeNewTextViewer[[
parent: my.outer,
wx: rotateXButton.wx + rotateXButton.ww + 20,
wy: 50, wh: 15, ww: 200,
scrollable: FALSE,
border: FALSE]];
ViewerTools.SetContents[my.rotateXInput, "10.0"];
rotateYButton ← Buttons.Create[
info:
[name: "Y:",
wx: 530, wy: 80, 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: 80, wh: 15, ww: 200,
scrollable: FALSE,
border: FALSE]];
ViewerTools.SetContents[my.rotateYInput, "-60.0"];
rotateZButton ← Buttons.Create[
info:
[name: "Z:",
wx: 530, wy: 110, wh: 15,
parent: my.outer,
border: FALSE],
proc: ForceRotateZ,
clientData: my];
my.rotateZInput ← ViewerTools.MakeNewTextViewer[[
parent: my.outer,
wx: rotateZButton.wx + rotateZButton.ww + 20,
wy: 110, wh: 15, ww: 200,
scrollable: FALSE,
border: FALSE]];
ViewerTools.SetContents[my.rotateZInput, "5.0"];
eyeButton ← Buttons.Create[
info:
[name: "Eye:",
wx: 530, wy: 300, wh: 15,
parent: my.outer,
border: FALSE],
proc: ForceEye,
clientData: my];
my.eyeInput ← ViewerTools.MakeNewTextViewer[[
parent: my.outer,
wx: eyeButton.wx + eyeButton.ww + 20,
wy: 300, wh: 15, ww: 200,
scrollable: FALSE,
border: FALSE]];
ViewerTools.SetContents[my.eyeInput, "-6.0"];
screenSizeButton ← Buttons.Create[
info:
[name: "S. Size:",
wx: 530, wy: 330, wh: 15,
parent: my.outer,
border: FALSE],
proc: ForceScreenSize,
clientData: my];
my.screenSizeInput ← ViewerTools.MakeNewTextViewer[[
parent: my.outer,
wx: screenSizeButton.wx + screenSizeButton.ww + 20,
wy: 330, wh: 15, ww: 200,
scrollable: FALSE,
border: FALSE]];
ViewerTools.SetContents[my.screenSizeInput, ".2"];
eyeToScreenButton ← Buttons.Create[
info:
[name: "Eye to S.:",
wx: 530, wy: 360, wh: 15,
parent: my.outer,
border: FALSE],
proc: ForceEyeToScreen,
clientData: my];
my.eyeToScreenInput ← ViewerTools.MakeNewTextViewer[[
parent: my.outer,
wx: eyeToScreenButton.wx + eyeToScreenButton.ww + 20,
wy: 360, wh: 15, ww: 200,
scrollable: FALSE,
border: FALSE]];
ViewerTools.SetContents[my.eyeToScreenInput, "1.0"];
my.inner ← ViewerOps.CreateViewer[
flavor: $ShowHide,
info: [wx: 5, wy: 30, wh: 400, ww: 500, parent: my.outer, data: my]];
ViewerOps.PaintViewer[viewer: my.inner, hint: all];
};
ForceInName: 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.fileInNameInput];
};
ForceOutName: 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.fileOutNameInput];
};
ForceRotateX: 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.rotateXInput];
};
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];
};
ForceRotateZ: 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.rotateZInput];
};
ForceEye: 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.eyeInput];
};
ForceScreenSize: 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.screenSizeInput];
};
ForceEyeToScreen: 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.eyeToScreenInput];
};
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;
};
SticksProc: Menus.ClickProc = {
my: State ← NARROW[clientData];
SticksLocked[my];
ViewerOps.PaintViewer[viewer: my.inner, hint: all];
};
SticksLocked: ENTRY PROC[my: State] ~ {
ENABLE UNWIND => NULL;
my.sticks ← NOT my.sticks;
};
SurfacesProc: Menus.ClickProc = {
my: State ← NARROW[clientData];
SurfacesLocked[my];
ViewerOps.PaintViewer[viewer: my.inner, hint: all];
};
SurfacesLocked: ENTRY PROC[my: State] ~ {
ENABLE UNWIND => NULL;
my.surfaces ← NOT my.surfaces;
};
PrintProc: Menus.ClickProc = {
my: State ← NARROW[clientData];
Action: PROC [dc: Imager.Context] = {
dc.TranslateT[[0.0, 10.0]];
dc.RotateT[-90.0];
dc.ScaleT[.9/Scale];
PaintLocked[my, dc];
};
ip: ImagerInterpress.Ref ← ImagerInterpress.Create[ViewerTools.GetContents[my.fileOutNameInput] ];
ImagerInterpress.DoPage[ip, Action, Imager.metersPerInch];
ImagerInterpress.Close[ip];
};
ViewProc: Menus.ClickProc = {
my: State ← NARROW[clientData];
ViewLocked[my];
ViewerOps.PaintViewer[viewer: my.inner, hint: all];
};
overlapLimit: INTEGER = 12;
HideLine: TYPE = REF HideLineRec;
HideLineRec: TYPE = RECORD [
size: INTEGER ← 0,
front: Facet ← NIL,
changing: ARRAY [0..overlapLimit] OF Facet,
next: HideLine
];
hideInfinityRegion: HideLine = NEW[HideLineRec ← [size: 0]];
ViewLocked: ENTRY PROC[my: State] ~ {
ENABLE UNWIND => NULL;
freeHL: HideLine;
NewHL: PROC [size: INTEGER ← 0] RETURNS [alive: HideLine] ~ INLINE {
IF freeHL = NIL THEN RETURN[NEW[HideLineRec ← [size: size]]];
alive ← freeHL; alive.size ← size;
freeHL ← freeHL.next;
};
HideCopy: CopyLineProc = {
sI: HideLine ← NARROW[stateIn];
sO: HideLine ← NewHL[sI.size];
FOR i: INTEGER IN [0..sO.size) DO
sO.changing[i] ← sI.changing[i];
ENDLOOP;
RETURN[sO];
};
HideFlip: FlipLineProc = {
RETURN[stateIn]
};
HideCombine: CombineLineProc = {
s1: HideLine ← NARROW[state1];
s2: HideLine ← NARROW[state2];
RETURN[Union[s1, s2]];
};
Union: PROC [a, b: HideLine] RETURNS [c: HideLine] ~ {
merge according to pointer order, cancel duplicates
aPoint, bPoint: INTEGER ← 0;
c ← NewHL[];
UNTIL aPoint = a.size AND bPoint = b.size DO
BEGIN
IF aPoint = a.size THEN GOTO MoveFromB;
IF bPoint = b.size THEN GOTO MoveFromA;
IF a.changing[aPoint] = b.changing[bPoint] THEN {
aPoint ← aPoint + 1; --cancel duplicates
bPoint ← bPoint + 1;
LOOP};
IF LOOPHOLE[a.changing[aPoint], LONG CARDINAL] < LOOPHOLE[b.changing[bPoint], LONG CARDINAL] THEN GOTO MoveFromA ELSE GOTO MoveFromB;
EXITS
MoveFromA => {
c.changing[c.size] ← a.changing[aPoint];
c.size ← c.size + 1; aPoint ← aPoint + 1;
};
MoveFromB => {
c.changing[c.size] ← b.changing[bPoint];
c.size ← c.size + 1; bPoint ← bPoint + 1;
};
END;
ENDLOOP;
c ← c;
};
ComputeFront: PROC [r: HideLine] ~ {
IF r.size = 0 THEN RETURN;
r.front ← r.changing[0];
FOR i: INTEGER IN [1..r.size) DO
IF InFront[r.changing[i], r.front] THEN r.front ← r.changing[i];
ENDLOOP;
};
InFront: PROC [f,g: Facet] RETURNS [BOOLEAN] ~ {
zF, zG: REAL;
cumPoint: Point3 ← [0.0, 0.0, 0.0];
cumCount: INT ← 0;
ProjZ: PROC [p: Point3, f: Facet] RETURNS [z: REAL] ~ {
z ← - ((p[1] - f.a[1])*f.n[1] + (p[2] - f.a[2])*f.n[2])/ f.n[3] + f.a[3];
};
Inside: PROC [p: Point3, f: Facet] ~ {
v: Point3 ← Sub[p, f.a];
IF Cross[Sub[f.b, f.a], v][3] * f.n[3] <= 0 THEN RETURN;
IF Cross[v, Sub[f.c, f.a]][3] * f.n[3] <= 0 THEN RETURN;
IF Cross[Sub[f.c, f.b], Sub[p, f.b]][3] * f.n[3] <= 0 THEN RETURN;
cumPoint ← Add[cumPoint, p];
cumCount ← cumCount + 1;
};
Intersect: PROC [p1, p2, q1, q2: Point3] ~ {
dQ, dP, base, cross: Point3;
numer1, numer2: REAL;
OutsideZeroOne: PROC [r: REAL] RETURNS [BOOLEAN] ~ {
IF RealFns.AlmostZero[r, tolerance] THEN RETURN[FALSE];
IF RealFns.AlmostEqual[r, 1.0, tolerance] THEN RETURN[FALSE];
RETURN[ r < 0 OR r > 1.0 ];
};
dP ← Sub[p1, p2];
dQ ← Sub[q2, q1];
cross ← Cross[dP, dQ];
IF RealFns.AlmostZero[cross[3], tolerance] THEN RETURN;
base ← Sub[q2, p2];
numer1 ← Cross[base, dQ][3] / cross[3];
numer2 ← Cross[dP, base][3] / cross[3];
IF OutsideZeroOne[numer1] THEN RETURN;
IF OutsideZeroOne[numer2] THEN RETURN;
cumPoint ← Add[cumPoint, Add[p2, ScalarMult[dP, numer1]]];
cumCount ← cumCount + 1;
};
Inside[f.a, g]; Inside[f.b, g]; Inside[f.c, g];
Inside[g.a, f]; Inside[g.b, f]; Inside[g.c, f];
Intersect[f.a, f.b, g.a, g.b]; Intersect[f.a, f.b, g.b, g.c]; Intersect[f.a, f.b, g.c, g.a];
Intersect[f.b, f.c, g.a, g.b]; Intersect[f.b, f.c, g.b, g.c]; Intersect[f.b, f.c, g.c, g.a];
Intersect[f.c, f.a, g.a, g.b]; Intersect[f.c, f.a, g.b, g.c]; Intersect[f.c, f.a, g.c, g.a];
IF cumCount = 0 THEN RETURN[FALSE];
cumPoint ← ScalarMult[cumPoint, 1.0/ cumCount];
zF ← ProjZ[cumPoint, f];
zG ← ProjZ[cumPoint, g];
IF RealFns.AlmostEqual[zF, zG, tolerance] THEN RETURN[FALSE];
IF zF > zG THEN RETURN[FALSE] ELSE RETURN[TRUE];
};
HideStart: StartRegionProc = {
rP: HideLine ← 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: HideLine ← Union[rP, lR];
ComputeFront[rC];
FixLineState[rC, lineRight, rP];
RETURN[rC];
};
HideStop: StopRegionProc = {UselessTest[lineLeft]};
HideSplit: SplitRegionProc = {
FixLineState[NARROW[regionRight], lineLeft, NARROW[regionPrevious]];
RETURN[regionRight];
};
HideMerge: MergeRegionProc = {
IF NARROW[regionLeft, HideLine].size > 0 AND NARROW[regionLeft, HideLine].front # NARROW[regionRight, HideLine].front THEN ERROR;
End Testing Code
UselessTest[lineRight];
RETURN[regionRight];
};
HideLineChange: LineChangeRegionProc = {
IF side = left THEN {
UselessTest[lineOld];
}
ELSE
FixLineState[NARROW[regionCenter], lineNew, NARROW[regionPrevious]];
};
UselessTest: PROC [line: Line] ~ INLINE {
hideLine: HideLine ← NARROW[line.state];
IF hideLine.size = 0 THEN {
hideLine.next ← freeHL; freeHL ← hideLine;
RemoveLineFromEndPoints[line];
};
};
FixLineState: PROC [regionLeft: HideLine, lineCenter: Line, regionRight: HideLine] ~ {
lC: HideLine ← NARROW[lineCenter.state];
IF regionLeft.size = 0 THEN {
IF regionRight.size = 0 THEN {lC.size ← 0}
ELSE {lC.size ← 1; lC.changing[0] ← regionRight.front}
}
ELSE {
IF regionRight.size = 0 THEN {lC.size ← 1; lC.changing[0] ← regionLeft.front}
ELSE {
IF regionLeft.front = regionRight.front THEN lC.size ← 0
ELSE {
lC.size ← 2;
IF LOOPHOLE[regionRight.front, LONG CARDINAL] < LOOPHOLE[regionLeft.front, LONG CARDINAL] THEN {
lC.changing[0] ← regionRight.front;
lC.changing[1] ← regionLeft.front
}
ELSE {
lC.changing[0] ← regionLeft.front;
lC.changing[1] ← regionRight.front
};
};
};
};
};
input: Graph ← NewGraph[];
workLoad, newWorkLoad: LIST OF Graph ← NIL;
facetCount: LONG CARDINAL;
inputFile: IO.STREAMFS.StreamOpen[ViewerTools.GetContents[my.fileInNameInput]];
scanScene: Scene;
master: Matrix33;
sin, cos: REAL;
eye: REAL ← RealFromRope[ViewerTools.GetContents[my.eyeInput]]; --Eye is at (0, 0, eye)
eyeToScreen: REAL ← RealFromRope[ViewerTools.GetContents[my.eyeToScreenInput]];
screenSize: REAL ← RealFromRope[ViewerTools.GetContents[my.screenSizeInput]];
largestEyeToObject: REAL ← 200000.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)
};
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.rotateXInput]]];
cos ← RealFns.CosDeg[RealFromRope[ViewerTools.GetContents[my.rotateXInput]]];
master ← [[1.0, 0.0, 0.0], [0.0, cos, -sin], [0.0, sin, cos]];
sin ← RealFns.SinDeg[RealFromRope[ViewerTools.GetContents[my.rotateYInput]]];
cos ← RealFns.CosDeg[RealFromRope[ViewerTools.GetContents[my.rotateYInput]]];
master ← Multiply[ [[cos, 0.0, sin], [0.0, 1.0, 0.0], [-sin, 0.0, cos]], master];
sin ← RealFns.SinDeg[RealFromRope[ViewerTools.GetContents[my.rotateZInput]]];
cos ← RealFns.CosDeg[RealFromRope[ViewerTools.GetContents[my.rotateZInput]]];
master ← Multiply[ [[cos, -sin, 0.0], [sin, cos, 0.0], [0.0, 0.0, 1.0]], master];
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 ← [size: 1]];
nf.number ← facetCount;
lineState.changing[0] ← 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);
};
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]], HideCopy[lineState], HideFlip];
input ← input.LineTo[Round[nf.c[1]], Round[nf.c[2]], HideCopy[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];
my.output ← StraightenLines[my.output];
newWorkLoad ← CONS[my.output, newWorkLoad];
REPEAT
FreePass => {
newWorkLoad ← CONS[input, newWorkLoad];
my.output ← input;
};
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];
f: Facet;
IF rR.facet = NIL THEN {
IF lR.size = 0 THEN f ← NIL ELSE {IF lR.size # 1 THEN ERROR; f ← lR.changing[0]} }
ELSE {
IF lR.size = 1 THEN f ← NIL ELSE {
IF lR.size # 2 THEN ERROR;
IF lR.changing[0] = rR.facet THEN f ← lR.changing[1] ELSE {IF lR.changing[1] # rR.facet THEN ERROR; f ← lR.changing[0]}
};
};
IF f # NIL THEN
RETURN[NEW[TrapRegionRec ← [facet: f, 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];
};
DrawLine: LineActionProc ~ {
traj: Trajectory;
traj ← MoveTo[Vfp[l.above]].LineTo[Vfp[l.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 my.surfaces THEN
my.output ← Sweep[my.output, trapInfinityRegion, TrapStart, TrapStop, TrapSplit, TrapMerge, TrapLineChange];
IF my.sticks THEN {
context.SetColor[Imager.black];
context.SetStrokeWidth[0.015*Scale];
[] ← EnumerateLines[my.output, DrawLine];
};
};
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.