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 BOOL ← ALL[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];