Draw3dImpl.mesa
Copyright © 1985 by Xerox Corporation. All rights reserved.
Bloomenthal, May 14, 1986 12:04:36 pm PDT
DIRECTORY Clip3d, Draw2d, Draw3d, Imager, Matrix3d, Spline3d, Rope, Vector3d;
Draw3dImpl: CEDAR PROGRAM
IMPORTS Clip3d, Draw2d, Imager, Matrix3d, Spline3d
EXPORTS Draw3d
~ BEGIN
Context: TYPE ~ Imager.Context;
Pair:  TYPE ~ Vector3d.Pair;
Triple: TYPE ~ Vector3d.Triple;
Quad:  TYPE ~ Vector3d.Quad;
Matrix: TYPE ~ Matrix3d.Matrix;
Coeffs: TYPE ~ Spline3d.Coeffs;
Bezier: TYPE ~ Spline3d.Bezier;
Mark: PUBLIC PROC [p: Triple, context: Context, m: Matrix, type: Draw2d.MarkType ← cross, label: Rope.ROPENIL] ~ {
IF type # none THEN {
q: Quad ← Matrix3d.TransformH[p, m];
IF q.z+q.w >= 0.0 THEN {
pp: Pair ← [q.x/q.w, q.y/q.w];
Draw2d.Mark[context, pp, type];
IF label # NIL THEN Draw2d.Label[context, pp, label];
};
};
};
PP: PUBLIC PROC [p0, p1: Triple, c: Context, m: Matrix, type: Draw2d.DrawType ← solid] ~ {
c0, c1: Pair;
IF Matrix3d.HasPerspective[m] THEN {
off: BOOL;
[c0, c1, off] ← Clip3d.NearH[Matrix3d.TransformH[p0, m], Matrix3d.TransformH[p1, m]];
IF NOT off THEN Draw2d.Draw[c, c0, c1, type];
}
ELSE {
c0 ← Matrix3d.TransformD[p0, m];
c1 ← Matrix3d.TransformD[p1, m];
Draw2d.Draw[c, c0, c1, type];
};
};
PV: PUBLIC PROC [p, v: Triple, label: Rope.ROPENIL, context: Context, m: Matrix, mark: Draw2d.MarkType ← none, scale: REAL ← 0.2] ~ {
c0, c1, d: Pair;
pp: Triple ← [p.x+v.x, p.y+v.y, p.z+v.z];
IF Matrix3d.HasPerspective[m] THEN {
off: BOOL;
[c0, c1, off] ← Clip3d.NearH[Matrix3d.TransformH[p, m], Matrix3d.TransformH[pp, m]];
IF off THEN RETURN;
IF mark # none THEN Mark[p, context, m, mark];
}
ELSE {
c0 ← Matrix3d.TransformD[p, m];
c1 ← Matrix3d.TransformD[pp, m];
IF mark # none THEN Draw2d.Mark[context, c0, mark];
};
d ← [c1.x-c0.x, c1.y-c0.y];
c1 ← [c0.x+scale*d.x, c0.y+scale*d.y];
Draw2d.Arrow[context, c1, c0];
IF label # NIL THEN Draw2d.Label[context, c1, label];
};
V: PUBLIC PROC [v: Triple, name: Rope.ROPENIL, context: Context, m: Matrix] ~ {
xv: Triple ← Matrix3d.TransformVec[v, m];
Draw2d.Solid[context, [m[3][0], m[3][1]], [xv.x, xv.y]];
Draw2d.Label[context, [xv.x, xv.y], name];
};
Axes: PUBLIC PROC [context: Context, m: Matrix] ~ {
PV[[0.0, 0.0, 0.0], [1.0, 0.0, 0.0], "X", context, m];
PV[[0.0, 0.0, 0.0], [0.0, 1.0, 0.0], "Y", context, m];
PV[[0.0, 0.0, 0.0], [0.0, 0.0, 1.0], "Z", context, m];
};
The following procedures are for drawing three-dimensional splines.
DrawCurve: PUBLIC PROC [c: Coeffs, context: Context, m: Matrix ← NIL] ~ {
IF c # NIL THEN {
persp: BOOL ← Matrix3d.HasPerspective[m];
xc: Coeffs ← IF m = NIL THEN c ELSE Matrix3d.Mul[c, m];
nSegs: INTEGER ← Spline3d.Resolution[xc, 1.0];
dif: Coeffs ← Spline3d.FwdDif[xc, nSegs];
nCoords: NATIF persp THEN 3 ELSE 1;
p0, p1: Pair ← [dif[0][0], dif[0][1]];
q0, q1: Quad ← [dif[0][0], dif[0][1], dif[0][2], dif[0][3]];
FOR i: INTEGER IN[0..nSegs) DO
IF persp
THEN q1 ← [q0.x+dif[1][0], q0.y+dif[1][1], q0.z+dif[1][2], q0.w+dif[1][3]]
ELSE p1 ← [p0.x+dif[1][0], p0.y+dif[1][1]];
FOR j: INTEGER IN[0..nCoords] DO
dif[1][j] ← dif[1][j]+dif[2][j];
dif[2][j] ← dif[2][j]+dif[3][j];
ENDLOOP;
IF persp THEN {
c0, c1: Pair;
offScreen: BOOL;
[c0, c1, offScreen] ← Clip3d.NearH[q0, q1];
IF NOT offScreen THEN Draw2d.Solid[context, c0, c1];
q0 ← q1;
}
ELSE {
Draw2d.Solid[context, p0, p1];
p0 ← p1;
};
ENDLOOP;
};
};
DotCurve: PUBLIC PROC [c: Coeffs, context: Context, m: Matrix ← NIL] ~ {
persp: BOOL ← Matrix3d.HasPerspective[m];
xc: Coeffs ← IF m = NIL THEN c ELSE Matrix3d.Mul[c, m];
nSegs: INTEGER ← 4*Spline3d.Resolution[xc, 1.0];
dif: Coeffs ← Spline3d.FwdDif[xc, nSegs];
nCoords: NATIF persp THEN 3 ELSE 1;
p: Pair ← [dif[0][0], dif[0][1]];
q: Quad ← [dif[0][0], dif[0][1], dif[0][2], dif[0][3]];
FOR i: INTEGER IN[0..nSegs) DO
IF persp
THEN {IF q.w+q.z >= 0.0 THEN Imager.MaskRectangle[context, [q.x/q.w, q.y/q.w, 1, 1]]}
ELSE Imager.MaskRectangle[context, [p.x, p.y, 1, 1]];
IF persp
THEN q ← [q.x+dif[1][0], q.y+dif[1][1], q.z+dif[1][2], q.w+dif[1][3]]
ELSE p ← [p.x+dif[1][0], p.y+dif[1][1]];
FOR j: INTEGER IN[0..nCoords] DO
dif[1][j] ← dif[1][j]+dif[2][j];
dif[2][j] ← dif[2][j]+dif[3][j];
ENDLOOP;
ENDLOOP;
};
DrawBezierPolygon: PUBLIC PROC [b: Bezier, context: Context, m: Matrix ← NIL, type: Draw2d.DrawType ← solid, close: BOOLFALSE] ~ {
PP[b.b0, b.b1, context, m, type];
PP[b.b1, b.b2, context, m, type];
PP[b.b2, b.b3, context, m, type];
IF close THEN PP[b.b0, b.b3, context, m, type];
};
END.
PerspPP: PUBLIC PROC [p0, p1: Triple, context: Context, focalLength, tanHalfFov: REAL] ~ {
Draw segment p0p1 with perspective determined by focalLength and the tangent of 1/2 the field of view.
ClipZ: PROC [p0, p1: Triple, zLim: REAL] RETURNS [c0, c1: Triple, off: BOOL] ~ {
dx, dy, dz: REAL;
a0: REAL ← 0.0;
a1: REAL ← 1.0;
IF p0.z < zLim THEN {
IF p1.z < zLim THEN RETURN[c0, c1, TRUE];
a0 ← p0.z/(p0.z-p1.z);
}
ELSE IF p1.z < zLim THEN a1 ← p0.z/(p0.z-p1.z);
IF a0 > a1 THEN RETURN[c0, c1, TRUE];
dx ← p1.x-p0.x;
dy ← p1.y-p0.y;
dz ← p1.z-p0.z;
RETURN[[p0.x+a0*dx,p0.y+a0*dy,p0.z+a0*dz], [p0.x+a1*dx,p0.y+a1*dy,p0.z+a1*dz], FALSE];
};
off: BOOL ← FALSE;
c0, c1: Triple;
[c0, c1, off] ← ClipZ[p0, p1, -focalLength+0.01];
IF NOT off THEN {
f0: REAL ← 1.0/(1.0+c0.z*tanHalfFov);
f1: REAL ← 1.0/(1.0+c1.z*tanHalfFov);
Draw2d.Solid[context, [f0*c0.x, f0*c0.y], [f1*c1.x, f1*c1.y]];
};
};