G3dCubeDrawImpl
Copyright Ó 1985, 1992 by Xerox Corporation. All rights reserved.
Bloomenthal, November 21, 1992 2:55 pm PST
DIRECTORY CedarProcess, Draw2d, G3dBasic, G3dCubeDraw, G3dMatrix, G3dOctree, G3dVector, Imager, ImagerPath, Process, Rope;
G3dCubeDrawImpl: CEDAR PROGRAM
IMPORTS CedarProcess, Draw2d, G3dMatrix, G3dOctree, G3dVector, Imager, ImagerPath, Process
EXPORTS G3dCubeDraw
~ BEGIN
DrawType:  TYPE ~ Draw2d.DrawType;
Pair:    TYPE ~ G3dBasic.Pair;
Quad:    TYPE ~ G3dBasic.Quad;
Triple:   TYPE ~ G3dBasic.Triple;
Matrix:   TYPE ~ G3dMatrix.Matrix;
Viewport:   TYPE ~ G3dMatrix.Viewport;
Corner:   TYPE ~ G3dOctree.Corner;
Corners:   TYPE ~ G3dOctree.Corners;
Cube:    TYPE ~ G3dOctree.Cube;
CubeProc:  TYPE ~ G3dOctree.CubeProc;
Direction:   TYPE ~ G3dOctree.Direction;
DirectionPairs: TYPE ~ G3dOctree.DirectionPairs;
Face:    TYPE ~ G3dOctree.Face;
Neighborhood: TYPE ~ G3dOctree.Neighborhood;
Octant:   TYPE ~ G3dOctree.Octant;
OctantPairs:  TYPE ~ G3dOctree.OctantPairs;
ThreeEdges:  TYPE ~ G3dOctree.ThreeEdges;
FourCorners:  TYPE ~ G3dOctree.FourCorners;
Context:   TYPE ~ Imager.Context;
ROPE:    TYPE ~ Rope.ROPE;
Transforming Points
TransformDirections: PUBLIC PROC [cube: Cube, view: Matrix, viewport: Viewport ¬ []]
RETURNS [pairs: DirectionPairs]
~ {
VP: PROC [p: Pair] RETURNS [x: Pair] ~ {
x ¬ [viewport.scale.x*p.x+viewport.translate.x, viewport.scale.y*p.y+viewport.translate.y];
};
d: REAL ~ 0.5*G3dOctree.Size[cube];
c: Triple ~ G3dOctree.Center[cube];
pairs[c] ¬ VP[G3dMatrix.TransformD[c, view]];
pairs[lbn] ¬ VP[G3dMatrix.TransformD[cube.corners[lbn].point,   view]];
pairs[lbf] ¬ VP[G3dMatrix.TransformD[cube.corners[lbf].point,   view]];
pairs[ltn] ¬ VP[G3dMatrix.TransformD[cube.corners[ltn].point,   view]];
pairs[ltf] ¬ VP[G3dMatrix.TransformD[cube.corners[ltf].point,   view]];
pairs[rbn] ¬ VP[G3dMatrix.TransformD[cube.corners[rbn].point,   view]];
pairs[rbf] ¬ VP[G3dMatrix.TransformD[cube.corners[rbf].point,   view]];
pairs[rtn] ¬ VP[G3dMatrix.TransformD[cube.corners[rtn].point,   view]];
pairs[rtf] ¬ VP[G3dMatrix.TransformD[cube.corners[rtf].point,   view]];
pairs[lb] ¬ VP[G3dMatrix.TransformD[[c.x-d, c.y-d,  c.z],   view]];
pairs[lt] ¬ VP[G3dMatrix.TransformD[[c.x-d, c.y+d, c.z],   view]];
pairs[ln] ¬ VP[G3dMatrix.TransformD[[c.x-d, c.y,  c.z-d],  view]];
pairs[lf] ¬ VP[G3dMatrix.TransformD[[c.x-d, c.y,  c.z+d],  view]];
pairs[rb] ¬ VP[G3dMatrix.TransformD[[c.x+d, c.y-d,  c.z],   view]];
pairs[rt] ¬ VP[G3dMatrix.TransformD[[c.x+d, c.y+d, c.z],   view]];
pairs[rn] ¬ VP[G3dMatrix.TransformD[[c.x+d, c.y,  c.z-d],  view]];
pairs[rf] ¬ VP[G3dMatrix.TransformD[[c.x+d, c.y,  c.z+d],  view]];
pairs[bn] ¬ VP[G3dMatrix.TransformD[[c.x,  c.y-d,  c.z-d], view]];
pairs[bf] ¬ VP[G3dMatrix.TransformD[[c.x,  c.y-d,  c.z+d], view]];
pairs[tn] ¬ VP[G3dMatrix.TransformD[[c.x,  c.y+d, c.z-d], view]];
pairs[tf] ¬ VP[G3dMatrix.TransformD[[c.x,  c.y+d, c.z+d], view]];
pairs[l] ¬  VP[G3dMatrix.TransformD[[c.x-d, c.y,  c.z],   view]];
pairs[r] ¬  VP[G3dMatrix.TransformD[[c.x+d, c.y,  c.z],   view]];
pairs[b] ¬ VP[G3dMatrix.TransformD[[c.x,  c.y-d,  c.z],  view]];
pairs[t] ¬  VP[G3dMatrix.TransformD[[c.x,  c.y+d, c.z],  view]];
pairs[n] ¬ VP[G3dMatrix.TransformD[[c.x,  c.y,  c.z-d], view]];
pairs[f] ¬  VP[G3dMatrix.TransformD[[c.x,  c.y,  c.z+d], view]];
};
TransformOctants: PUBLIC PROC [cube: Cube, view: Matrix, viewport: Viewport ¬ []]
RETURNS [pairs: OctantPairs]
~ {
VP: PROC [p: Pair] RETURNS [x: Pair] ~ {
x ¬ [viewport.scale.x*p.x+viewport.translate.x, viewport.scale.y*p.y+viewport.translate.y];
};
pairs[lbn] ¬ VP[G3dMatrix.TransformD[cube.corners[lbn].point, view]];
pairs[lbf] ¬ VP[G3dMatrix.TransformD[cube.corners[lbf].point, view]];
pairs[ltn] ¬ VP[G3dMatrix.TransformD[cube.corners[ltn].point, view]];
pairs[ltf] ¬ VP[G3dMatrix.TransformD[cube.corners[ltf].point, view]];
pairs[rbn] ¬ VP[G3dMatrix.TransformD[cube.corners[rbn].point, view]];
pairs[rbf] ¬ VP[G3dMatrix.TransformD[cube.corners[rbf].point, view]];
pairs[rtn] ¬ VP[G3dMatrix.TransformD[cube.corners[rtn].point, view]];
pairs[rtf] ¬ VP[G3dMatrix.TransformD[cube.corners[rtf].point, view]];
};
Drawing Face/Cube/Neighborhood
TerminalCubes: PUBLIC PROC [
context: Context,
cube: Cube,
view: Matrix,
viewport: Viewport ¬ [],
drawType: DrawType ¬ dashed]
~ {
cubeProc: CubeProc ~ {
Process.CheckForAbort[];
SimpleCube[context, cube, view, viewport, TRUE, drawType];
};
G3dOctree.ApplyToTerminal[cube, cubeProc];
};
RecursiveCubes: PUBLIC PROC [
context: Context,
cube: Cube,
view: Matrix,
viewport: Viewport ¬ [],
drawType: DrawType ¬ dashed,
terminalCenters: BOOL ¬ TRUE]
~ {
cubeProc: CubeProc ~ {
Process.CheckForAbort[];
IF cube.terminal AND terminalCenters
THEN CubeCenter[context, cube, view, viewport]
ELSE SimpleCube[context, cube, view, viewport, TRUE, drawType];
};
G3dOctree.Apply[cube, cubeProc];
};
SimpleCube: PUBLIC PROC [
context: Context,
cube: Cube,
view: Matrix,
viewport: Viewport ¬ [],
optimize: BOOL ¬ FALSE,
drawType: DrawType ¬ dashed]
~ {
IF cube # NIL AND view # NIL THEN SimpleCubeFromPairs[
context, TransformOctants[cube, view], IF optimize THEN cube ELSE NIL, drawType];
};
SimpleCubeFromPairs: PUBLIC PROC [
context: Context,
pairs: OctantPairs,
cube: Cube ¬ NIL,
drawType: DrawType ¬ dashed]
~ {
IF cube # NIL THEN {
l: Cube ~ G3dOctree.FaceNeighbor[cube, l];
r: Cube ~ G3dOctree.FaceNeighbor[cube, r];
b: Cube ~ G3dOctree.FaceNeighbor[cube, b];
t: Cube ~ G3dOctree.FaceNeighbor[cube, t];
n: Cube ~ G3dOctree.FaceNeighbor[cube, n];
f: Cube ~ G3dOctree.FaceNeighbor[cube, f];
rf: Cube ~ IF r # NIL THEN G3dOctree.FaceNeighbor[r, f] ELSE G3dOctree.FaceNeighbor[f, r];
rt: Cube ~ IF r # NIL THEN G3dOctree.FaceNeighbor[r, t] ELSE G3dOctree.FaceNeighbor[t, r];
tf: Cube ~ IF t # NIL THEN G3dOctree.FaceNeighbor[t, f] ELSE G3dOctree.FaceNeighbor[f, t];
Draw2d.Line[context, pairs[lbn], pairs[lbf], drawType];       -- lb
Draw2d.Line[context, pairs[lbn], pairs[ltn], drawType];       -- ln
Draw2d.Line[context, pairs[lbn], pairs[rbn], drawType];       -- bn
IF rf=NIL THEN Draw2d.Line[context, pairs[rbf], pairs[rtf], drawType];  -- rf
IF rt=NIL THEN Draw2d.Line[context, pairs[rtn], pairs[rtf], drawType];   -- rt
IF tf=NIL THEN Draw2d.Line[context, pairs[ltf], pairs[rtf], drawType];   -- tf
IF l=NIL AND t=NIL THEN Draw2d.Line[context, pairs[ltn], pairs[ltf], drawType]; -- lt
IF l=NIL AND f=NIL THEN Draw2d.Line[context, pairs[lbf], pairs[ltf], drawType]; -- lf
IF t=NIL AND n=NIL THEN Draw2d.Line[context, pairs[ltn], pairs[rtn], drawType];-- tn
IF b=NIL AND f=NIL THEN Draw2d.Line[context, pairs[lbf], pairs[rbf], drawType];-- bf
IF r=NIL AND n=NIL THEN Draw2d.Line[context, pairs[rbn], pairs[rtn], drawType];--rn
IF r=NIL AND b=NIL THEN Draw2d.Line[context, pairs[rbn], pairs[rbf], drawType];--rb
}
ELSE {
Draw2d.Line[context, pairs[lbn], pairs[lbf], drawType];    -- lb edge
Draw2d.Line[context, pairs[ltn], pairs[ltf], drawType];     -- lt edge
Draw2d.Line[context, pairs[lbn], pairs[ltn], drawType];    -- ln edge
Draw2d.Line[context, pairs[lbf], pairs[ltf], drawType];     -- lf edge
Draw2d.Line[context, pairs[lbn], pairs[rbn], drawType];    -- bn edge
Draw2d.Line[context, pairs[ltn], pairs[rtn], drawType];    -- tn edge
Draw2d.Line[context, pairs[lbf], pairs[rbf], drawType];    -- bf edge
Draw2d.Line[context, pairs[ltf], pairs[rtf], drawType];     -- tf edge
Draw2d.Line[context, pairs[rbn], pairs[rtn], drawType];    -- rn edge
Draw2d.Line[context, pairs[rbf], pairs[rtf], drawType];     -- rf edge
Draw2d.Line[context, pairs[rbn], pairs[rbf], drawType];    -- rb edge
Draw2d.Line[context, pairs[rtn], pairs[rtf], drawType];     -- rt edge
};
};
FaceOnly: PUBLIC PROC [
context: Context,
cube: Cube,
face: Face,
view: Matrix,
viewport: Viewport ¬ [],
drawType: DrawType ¬ dashed]
~ {
VP: PROC [p: Pair] RETURNS [x: Pair] ~ {
x ¬ [viewport.scale.x*p.x+viewport.translate.x, viewport.scale.y*p.y+viewport.translate.y];
};
corners: Corners ~ cube.corners;
faceCorners: ARRAY [0..4) OF Corner ¬ SELECT face FROM
l   => [corners[lbn], corners[lbf], corners[ltf], corners[ltn]],
r   => [corners[rbn], corners[rbf], corners[rtf], corners[rtn]],
b   => [corners[lbn], corners[lbf], corners[rbf], corners[rbn]],
t   => [corners[ltn], corners[ltf], corners[rtf], corners[rtn]],
n   => [corners[lbn], corners[ltn], corners[rtn], corners[rbn]],
ENDCASE => [corners[lbf], corners[ltf], corners[rtf], corners[rbf]];
p0: Pair ¬ VP[G3dMatrix.TransformD[faceCorners[3].point, view]];
FOR n: NAT IN [0..4) DO
p1: Pair ¬ VP[G3dMatrix.TransformD[faceCorners[n].point, view]];
Draw2d.Line[context, p0, p1, drawType];
p0 ¬ p1;
ENDLOOP;
};
FancyCube: PUBLIC PROC [
context: Context,
cube: Cube,
view: Matrix,
viewport: Viewport ¬ [],
label: BOOL ¬ TRUE,
markKids: BOOL ¬ FALSE]
~ {
IF cube = NIL OR view = NIL THEN RETURN;
FancyCubeFromPairs[context, TransformDirections[cube, view, viewport],,, dashed, label];
IF markKids THEN FOR o: Octant IN Octant DO
IF cube.kids[o] # NIL THEN CubeCenter[context, cube.kids[o], view, viewport];
ENDLOOP;
};
FancyCubeFromPairs: PUBLIC PROC [
context: Context,
pairs: DirectionPairs,
cornerConnect: DrawType ¬ solid,
edgeConnect: DrawType ¬ dashed,
faceConnect: DrawType ¬ dotted,
label: BOOL ¬ TRUE]
~ {
Draw2d.Line[context, pairs[lbn], pairs[rbn], cornerConnect];   -- left to right edges:
Draw2d.Line[context, pairs[lbf], pairs[rbf], cornerConnect];
Draw2d.Line[context, pairs[ltn], pairs[rtn], cornerConnect];
Draw2d.Line[context, pairs[ltf], pairs[rtf], cornerConnect];
Draw2d.Line[context, pairs[lb], pairs[rb], edgeConnect];
Draw2d.Line[context, pairs[lt], pairs[rt], edgeConnect];
Draw2d.Line[context, pairs[ln], pairs[rn], edgeConnect];
Draw2d.Line[context, pairs[lf], pairs[rf], edgeConnect];
Draw2d.Line[context, pairs[l], pairs[r], faceConnect];
Draw2d.Line[context, pairs[lbn], pairs[ltn], cornerConnect];  -- bottom to top edges:
Draw2d.Line[context, pairs[rbn], pairs[rtn], cornerConnect];
Draw2d.Line[context, pairs[lbf], pairs[ltf], cornerConnect];
Draw2d.Line[context, pairs[rbf], pairs[rtf], cornerConnect];
Draw2d.Line[context, pairs[lb], pairs[lt], edgeConnect];
Draw2d.Line[context, pairs[rb], pairs[rt], edgeConnect];
Draw2d.Line[context, pairs[bn], pairs[tn], edgeConnect];
Draw2d.Line[context, pairs[bf], pairs[tf], edgeConnect];
Draw2d.Line[context, pairs[b], pairs[t], faceConnect];
Draw2d.Line[context, pairs[lbn], pairs[lbf], cornerConnect];  -- near to far edges:
Draw2d.Line[context, pairs[rbn], pairs[rbf], cornerConnect];
Draw2d.Line[context, pairs[ltn], pairs[ltf], cornerConnect];
Draw2d.Line[context, pairs[rtn], pairs[rtf], cornerConnect];
Draw2d.Line[context, pairs[ln], pairs[lf], edgeConnect];
Draw2d.Line[context, pairs[rn], pairs[rf], edgeConnect];
Draw2d.Line[context, pairs[bn], pairs[bf], edgeConnect];
Draw2d.Line[context, pairs[tn], pairs[tf], edgeConnect];
Draw2d.Line[context, pairs[n], pairs[f], faceConnect];
IF label THEN LabelDirections[context, pairs];
};
Neighbors: PUBLIC PROC [
context: Context,
neighborhood: Neighborhood,
view: Matrix,
viewport: Viewport ¬ [],
drawType: DrawType ¬ dashed]
~ {
DirectionsToCheck: PROC [direction: Direction]
RETURNS [directionsToCheck: ARRAY Face OF Direction] ~ {
directionsToCheck ¬ SELECT direction FROM
center:
c  => [l,  r,  b,  t,  n,  f],
six face neighbors:
l  => [none, c,  lb,  lt,  ln, lf],
r  => [c,  none, rb, rt,  rn, rf],
b  => [lb, rb, none, c,  bn, bf],
t  => [lt,  rt,  c,  none, tn, tf],
n  => [ln, rn, bn, tn, none, c],
f  => [lf,  rf,  bf, tf,  c,  none],
twelve edge neighbors:
lb  => [none, b,  none, l,  lbn, lbf],
lt  => [none, t,  l,  none, ltn, ltf],
ln  => [none, n,  lbn, ltn, none, l],
lf  => [none, f,  lbf, ltf, l,  none],
rb  => [b,  none, none, r,  rbn, rbf],
rt  => [t,  none, r,  none, rtn, rtf],
rn  => [n,  none, rbn, rtn, none, r],
rf  => [f,  none, rbf, rtf, r,  none],
bn  => [lbn, rbn, none, n,  none, b],
bf  => [lbf, rbf, none, f,  b,  none],
tn  => [ltn, rtn, n,  none, none, t],
tf  => [ltf, rtf, f,  none, t,  none],
eight corner neighbors:
lbn => [none, bn, none, ln, none, lb],
lbf => [none, bf, none, lf,  lb,  none],
ltn => [none, tn, ln, none, none, lt],
ltf  => [none, tf,  lf,  none, lt,  none],
rbn => [bn, none, none, rn, none, rb],
rbf => [bf, none, none, rf,  rb, none],
rtn => [tn, none, rn, none, none, rt],
rtf  => [tf,  none, rf,  none, rt,  none],
ENDCASE => [none, none, none, none, none, none];
};
visible: ARRAY Face OF BOOL;
visible[r] ¬ NOT(visible[l] ¬ G3dVector.FrontFacingNoPerspective[[-1, 0, 0], view]);
visible[t] ¬ NOT(visible[b] ¬ G3dVector.FrontFacingNoPerspective[[0, -1, 0], view]);
visible[f] ¬ NOT(visible[n] ¬ G3dVector.FrontFacingNoPerspective[[0, 0, -1], view]);
FOR direction: Direction IN Direction DO
cube: Cube ~ neighborhood[direction];
IF cube # NIL THEN {
directionsToCheck: ARRAY Face OF Direction ¬ DirectionsToCheck[direction];
FOR face: Face IN Face DO
IF visible[face] THEN {
check: Direction ¬ directionsToCheck[face];
IF check = none OR neighborhood[check] = NIL
THEN FaceOnly[context, cube, face, view, viewport, drawType];
};
ENDLOOP;
};
ENDLOOP;
};
Hidden Lines Eliminated
HLEOctree: PUBLIC PROC [context: Context, root: Cube, view: Matrix, viewport: Viewport ¬ []]
~ {
VP: PROC [p: Pair] RETURNS [x: Pair] ~ {
x ¬ [viewport.scale.x*p.x+viewport.translate.x, viewport.scale.y*p.y+viewport.translate.y];
};
ApplyToCube: PROC [cube: Cube] ~ {
CedarProcess.CheckAbort[];
IF cube = NIL THEN RETURN;
IF cube.terminal
THEN {
DrawFace: PROC [face: Face] ~ {
fourCorners: FourCorners ¬ G3dOctree.FaceCorners[cube, face];
p0: Pair ¬ VP[G3dMatrix.TransformD[fourCorners.c0.point, view]];
p1: Pair ¬ VP[G3dMatrix.TransformD[fourCorners.c1.point, view]];
p2: Pair ¬ VP[G3dMatrix.TransformD[fourCorners.c2.point, view]];
p3: Pair ¬ VP[G3dMatrix.TransformD[fourCorners.c3.point, view]];
trajectory: Imager.Trajectory ¬ ImagerPath.MoveTo[p0];
trajectory ¬ ImagerPath.LineTo[trajectory, p1];
trajectory ¬ ImagerPath.LineTo[trajectory, p2];
trajectory ¬ ImagerPath.LineTo[trajectory, p3];
Imager.SetColor[context, Imager.white];
Imager.MaskFillTrajectory[context, trajectory];
Imager.SetColor[context, Imager.black];
Imager.MaskStrokeTrajectory[context, trajectory, TRUE];
};
DrawFace[f0];
DrawFace[f1];
DrawFace[f2];
}
ELSE FOR n: NAT IN [0..8) DO
ApplyToCube[cube.kids[o[n]]];
ENDLOOP;
};
x: Triple ¬ G3dMatrix.TransformVec[[1.0, 0.0, 0.0], view];
y: Triple ¬ G3dMatrix.TransformVec[[0.0, 1.0, 0.0], view];
z: Triple ¬ G3dMatrix.TransformVec[[0.0, 0.0, 1.0], view];
d0: Direction ¬ SELECT MAX[ABS[x.z], ABS[y.z], ABS[z.z]] FROM
ABS[x.z] => IF x.z < 0.0 THEN l ELSE r,
ABS[y.z] => IF y.z < 0.0 THEN b ELSE t,
ENDCASE => IF z.z < 0.0 THEN n ELSE f;
d1: Direction ¬ SELECT d0 FROM
l, r => IF ABS[y.z] > ABS[z.z]
THEN IF y.z < 0.0 THEN b ELSE t
ELSE IF z.z < 0.0 THEN n ELSE f,
b, t => IF ABS[x.z] > ABS[z.z]
THEN IF x.z < 0.0 THEN l ELSE r
ELSE IF z.z < 0.0 THEN n ELSE f,
ENDCASE => IF ABS[x.z] > ABS[y.z]
THEN IF x.z < 0.0 THEN l ELSE r
ELSE IF y.z < 0.0 THEN b ELSE t;
d2: Direction ¬ SELECT d0 FROM
l,r=> SELECT d1 FROM b,t=> IF z.z<0 THEN n ELSE f, ENDCASE => IF y.z<0 THEN b ELSE t,
b,t=> SELECT d1 FROM l,r=> IF z.z<0 THEN n ELSE f, ENDCASE => IF x.z<0 THEN l ELSE r,
n,f=> SELECT d1 FROM l,r=> IF y.z<0 THEN b ELSE t, ENDCASE => IF x.z<0 THEN l ELSE r,
ENDCASE => none;
d0Opp: Direction ¬ G3dOctree.OppositeDirection[d0];
d1Opp: Direction ¬ G3dOctree.OppositeDirection[d1];
d2Opp: Direction ¬ G3dOctree.OppositeDirection[d2];
edges: ThreeEdges;
f0: Face ¬ G3dOctree.FaceFromDirection[d0Opp];
f1: Face ¬ G3dOctree.FaceFromDirection[d1Opp];
f2: Face ¬ G3dOctree.FaceFromDirection[d2Opp];
o: ARRAY[0..8) OF Octant;
o[0] ¬ G3dOctree.OctantFromThreeDirections[d0,  d1,  d2];
o[1] ¬ G3dOctree.OctantFromThreeDirections[d0,  d1,  d2Opp];
o[2] ¬ G3dOctree.OctantFromThreeDirections[d0,  d1Opp, d2];
o[3] ¬ G3dOctree.OctantFromThreeDirections[d0,  d1Opp, d2Opp];
o[4] ¬ G3dOctree.OctantFromThreeDirections[d0Opp, d1,  d2];
o[5] ¬ G3dOctree.OctantFromThreeDirections[d0Opp, d1,  d2Opp];
o[6] ¬ G3dOctree.OctantFromThreeDirections[d0Opp, d1Opp, d2];
o[7] ¬ G3dOctree.OctantFromThreeDirections[d0Opp, d1Opp, d2Opp];
edges ¬ G3dOctree.EdgesFromOctant[o[7]];
Imager.SetStrokeWidth[context, 1.0];
ApplyToCube[root];
};
Labelling
LabelCube: PUBLIC PROC [
context: Context,
cube: Cube,
direction: Direction,
view: Matrix,
viewport: Viewport ¬ []]
~ {
VP: PROC [p: Pair] RETURNS [x: Pair] ~ {
x ¬ [viewport.scale.x*p.x+viewport.translate.x, viewport.scale.y*p.y+viewport.translate.y];
};
pair: Pair;
IF view[2][3] # 0.0
THEN {
q: G3dBasic.Quad ¬ G3dMatrix.TransformH[G3dOctree.Center[cube], view];
IF q.z+q.w < 0.0 THEN RETURN;
pair ¬ VP[[q.x/q.w, q.y/q.w]]
}
ELSE pair ¬ VP[G3dMatrix.TransformD[G3dOctree.Center[cube], view]];
Draw2d.Label[context, [pair.x+6, pair.y], G3dOctree.RopeFromDirection[direction]];
};
LabelDirections: PUBLIC PROC [context: Context, pairs: DirectionPairs] ~ {
Inner: PROC [direction: Direction, rope: ROPE] ~ {
Draw2d.Label[context, [pairs[direction].x+6, pairs[direction].y], rope];
Draw2d.Circle[context, pairs[direction], 2.0, TRUE];
Draw2d.Mark[context, pairs[direction], dot];
};
Inner[c, "c"];
Inner[lbn, "lbn"];
Inner[lbf, "lbf"];
Inner[ltn, "ltn"];
Inner[ltf, "ltf"];
Inner[rbn, "rbn"];
Inner[rbf, "rbf"];
Inner[rtn, "rtn"];
Inner[rtf, "rtf"];
Inner[lb, "lb"];
Inner[lt, "lt"];
Inner[ln, "ln"];
Inner[lf, "lf"];
Inner[rb, "rb"];
Inner[rt, "rt"];
Inner[rn, "rn"];
Inner[rf, "rf"];
Inner[bn, "bn"];
Inner[bf, "bf"];
Inner[tn, "tn"];
Inner[tf, "tf"];
Inner[l, "l"];
Inner[r, "r"];
Inner[b, "b"];
Inner[t, "t"];
Inner[n, "n"];
Inner[f, "f"];
};
LabelOctants: PUBLIC PROC [context: Context, pairs: OctantPairs] ~ {
Inner: PROC [octant: Octant, rope: ROPE] ~ {
Draw2d.Label[context, [pairs[octant].x+6, pairs[octant].y], rope];
Draw2d.Mark[context, pairs[octant], dot];
};
Inner[lbn, "lbn"];
Inner[lbf, "lbf"];
Inner[ltn, "ltn"];
Inner[ltf, "ltf"];
Inner[rbn, "rbn"];
Inner[rbf, "rbf"];
Inner[rtn, "rtn"];
Inner[rtf, "rtf"];
};
Marking
CubeCenter: PUBLIC PROC [context: Context, cube: Cube, view: Matrix, viewport: Viewport ¬[]]
~ {
VP: PROC [p: Pair] RETURNS [x: Pair] ~ {
x ¬ [viewport.scale.x*p.x+viewport.translate.x, viewport.scale.y*p.y+viewport.translate.y];
};
p: Pair;
IF view[2][3] # 0.0
THEN {
q: Quad ~ G3dMatrix.TransformH[G3dOctree.Center[cube], view];
IF q.z+q.w < 0.0 THEN RETURN;
p ¬ VP[[q.x/q.w, q.y/q.w]]
}
ELSE p ¬ VP[G3dMatrix.TransformD[G3dOctree.Center[cube], view]];
Draw2d.Circle[context, p, 5.0, TRUE];
Imager.MaskRectangle[context, [p.x-1, p.y-1, 3, 3]];
};
END.