ImplicitTestCubeEdgesImpl.mesa
Copyright © 1985 by Xerox Corporation. All rights reserved.
Bloomenthal, April 17, 1992 9:45 am PDT
DIRECTORY Basics, Commander, IO, Rope;
ImplicitTestCubeEdgesImpl: CEDAR PROGRAM
IMPORTS Basics, Commander, IO
See /mesa/MinPoly/MinPolyImpl.mesa; see /mesa/Tests/TestCubeEdges.info.
~ BEGIN
Dir:   TYPE ~ {cw, ccw};
Face:   TYPE ~ {l, r, t, b, n, f};
Edge:   TYPE ~ {lb, lt, ln, lf, rb, rt, rn, rf, bn, bf, tn, tf};
Corner:  TYPE ~ {lbn, lbf, ltn, ltf, rbn, rbf, rtn, rtf};
TwoCorners: TYPE ~ RECORD [c1, c2: Corner];
Cube:   TYPE ~ ARRAY Corner OF BOOL;
CornerName: PROC [c: Corner] RETURNS [Rope.ROPE] ~ {
RETURN[SELECT c FROM
lbn => "lbn", lbf => "lbf", ltn => "ltn", ltf => "ltf",
rbn => "rbn", rbf => "rbf", rtn => "rtn", ENDCASE => "rtf"];
};
Bit: PROC [i: WORD, c: Corner] RETURNS [BOOL] ~ {
exp: NAT SELECT c FROM lbn=>0,lbf=>1,ltn=>2,ltf=>3,rbn=>4,rbf=>5,rtn=>6,ENDCASE=>7;
RETURN[IF Basics.BITAND[i, Basics.BITSHIFT[1, exp]] # 0 THEN TRUE ELSE FALSE];
};
NextCWEdge: PROC [edge: Edge, face: Face] RETURNS [ret: Edge] ~ {
ret ← SELECT edge FROM
lb   => IF face = l  THEN lf ELSE bn,
lt   => IF face = l  THEN ln ELSE tf,
ln   => IF face = l THEN lb ELSE tn,
lf   => IF face = l THEN lt ELSE bf,
rb   => IF face = r THEN rn ELSE bf,
rt   => IF face = r THEN rf ELSE tn,
rn   => IF face = r THEN rt ELSE bn,
rf   => IF face = r THEN rb ELSE tf,
bn   => IF face = b THEN rb ELSE ln,
bf   => IF face = b THEN lb ELSE rf,
tn   => IF face = t THEN lt ELSE rn,
ENDCASE => IF face = t THEN rt ELSE lf;
};
OtherFace: PROC [edge: Edge, face: Face] RETURNS [ret: Face] ~ {
ret ← SELECT edge FROM
lb   => IF face = b THEN l ELSE b,
lt   => IF face = l  THEN t ELSE l,
ln   => IF face = l  THEN n ELSE l,
lf   => IF face = f THEN l ELSE f,
rb   => IF face = r THEN b ELSE r,
rt   => IF face = t  THEN r ELSE t,
rn   => IF face = n THEN r ELSE n,
rf   => IF face = r THEN f ELSE r,
bn   => IF face = n THEN b ELSE n,
bf   => IF face = b THEN f ELSE b,
tn   => IF face = t  THEN n ELSE t,
ENDCASE => IF face = f THEN t ELSE f;
};
CornersFromEdge: PROC [e: Edge] RETURNS [tc: TwoCorners] ~ {
tc ← SELECT e FROM
lb => [lbn, lbf], lt => [ltn, ltf], ln => [lbn, ltn], lf => [lbf, ltf], rb => [rbn, rbf],
rt => [rtn, rtf], rn => [rbn, rtn], rf => [rtf, rbf], bn => [lbn, rbn], bf => [lbf, rbf],
tn => [ltn, rtn], ENDCASE => [ltf, rtf];
};
TestCubeEdgesCmd: Commander.CommandProc ~ {
CheckPolys: PROC [cube: Cube] ~ {
DirectedFace: PROC [edge: Edge, dir: Dir] RETURNS [face: Face] ~ {
negative to positive along edge is dir (cw or ccw) about face
Test: PROC [c: Corner] RETURNS [b: BOOL] ~ INLINE {
b ← IF dir = cw THEN cube[c] ELSE NOT cube[c];
};
face ← SELECT edge FROM
lb   => IF Test[lbn] THEN l ELSE b,
lt   => IF Test[ltn] THEN t ELSE l,
ln   => IF Test[lbn] THEN n ELSE l,
lf   => IF Test[lbf] THEN l ELSE f,
rb   => IF Test[rbn] THEN b ELSE r,
rt   => IF Test[rtn] THEN r ELSE t,
rn   => IF Test[rbn] THEN r ELSE n,
rf   => IF Test[rbf] THEN f ELSE r,
bn   => IF Test[lbn] THEN b ELSE n,
bf   => IF Test[lbf] THEN f ELSE b,
tn   => IF Test[ltn] THEN n ELSE t,
ENDCASE => IF Test[ltf] THEN t ELSE f;
};
VertexExists: PROC [e: Edge] RETURNS [BOOL] ~ {
tc: TwoCorners ← CornersFromEdge[e];
RETURN[cube[tc.c1] # cube[tc.c2]];
};
MakePolys: PROC [dir: Dir, output: BOOL ← TRUE] RETURNS [nPolys: INTEGER ← 0] ~ {
done: ARRAY Edge OF BOOLALL[FALSE];
IF output THEN IO.PutF[cmd.out, "\t%g: ", IO.rope[IF dir = cw THEN "cw" ELSE "ccw"]];
FOR edge: Edge IN Edge DO
IF NOT done[edge] AND VertexExists[edge] THEN {
nVertices: INTEGER ← 1;
e, start: Edge ← edge;
face: Face ← DirectedFace[e, dir];
nPolys ← nPolys+1;
DO
done[e ← NextCWEdge[e, face]] ← TRUE;
IF e = start THEN EXIT;
IF NOT VertexExists[e] THEN LOOP;
nVertices ← nVertices+1;
face ← OtherFace[e, face];
ENDLOOP;
IF output THEN {
IO.PutF[cmd.out, "#%g (%g verts), ", IO.int[nPolys], IO.int[nVertices]];
maxNVertices ← MAX[maxNVertices, nVertices];
maxNPolys ← MAX[maxNPolys, nPolys];
};
};
ENDLOOP;
IF output THEN IO.PutF[cmd.out, "\n"];
};
nPositive: INTEGER ← 0;
FOR c: Corner IN Corner DO IF cube[c] THEN nPositive ← nPositive+1; ENDLOOP;
[] ← MakePolys[IF nPositive > 4 THEN cw ELSE ccw];
[] MakePolys[IF MakePolys[cw, FALSE] > MakePolys[ccw, FALSE] THEN cw ELSE ccw];
};
cube: Cube;
maxNVertices, maxNPolys: INTEGER ← 0;
FOR i: INTEGER IN [0..256) DO
IO.PutF[cmd.out, "Test %g (+ corners = ", IO.int[i]];
FOR c: Corner IN Corner DO
IF (cube[c] ← Bit[i, c]) THEN IO.PutF[cmd.out, "%g ", IO.rope[CornerName[c]]];
ENDLOOP;
IO.EraseChar[cmd.out, ' ];
IO.PutF[cmd.out, ")\n"];
CheckPolys[cube];
ENDLOOP;
IO.PutF[cmd.out, "max # vertices per polygon = %g\n", IO.int[maxNVertices]];
IO.PutF[cmd.out, "max # polygons = %g\n", IO.int[maxNPolys]];
};
Commander.Register["TestCubeEdges", TestCubeEdgesCmd];
END.