ScreenRadiusFromSphere:
PUBLIC PROC [
sphere: G3dBasic.Sphere,
view: Matrix,
viewInverse: Matrix ¬ NIL,
viewport: Viewport ¬ []]
RETURNS [s: REAL]
~ {
x: Matrix ¬
IF viewInverse #
NIL
THEN viewInverse ELSE G3dMatrix.Invert[G3dMatrix.ObtainMatrix[]];
eyePt: Triple ¬ G3dMatrix.Transform[[0.0, 0.0, 0.0], x];
v: Triple ¬ G3dVector.Unit[G3dVector.Ortho[G3dVector.Sub[sphere.center, eyePt]]];
pp: Triple ¬ G3dVector.Add[sphere.center, G3dVector.Mul[v, sphere.radius]];
s ¬ G2dVector.Distance[
G3dMatrix.TransformD[sphere.center, view], G3dMatrix.TransformD[pp, view]];
IF viewInverse = NIL THEN G3dMatrix.ReleaseMatrix[x];
IF viewport # [] THEN s ¬ 0.5*viewport.scale.x;
};
Plane:
PUBLIC PROC [
context: Context,
plane: G3dPlane.Plane,
view: Matrix,
viewport: Viewport,
size: REAL ¬ 0.1,
drawType: DrawType ¬ solid]
~ {
VP: PROC [p: Pair] RETURNS [x: IntegerPair] ~ INLINE {x ¬ RndPairAndVP[p, viewport]};
z: Triple ¬ [plane.x, plane.y, plane.z];
useCG6: UseCG6 ¬ GetUseCG6[context];
IF NOT plane.normalized THEN z ¬ G3dVector.Unit[z];
IF z # origin
THEN {
a: ARRAY [0..4) OF IntegerPair;
q: ARRAY [0..4) OF Pair ¬ [[-size, size], [size, size], [size, -size], [-size, -size]];
crosser: Triple ¬ IF z # [0.0, 1.0, 0.0] THEN [0.0, 1.0, 0.0] ELSE [1.0, 0.0, 0.0];
x: Triple ¬ G3dVector.Unit[G3dVector.Cross[z, crosser]];
y: Triple ¬ G3dVector.Unit[G3dVector.Cross[z, x]];
o: Triple ¬ G3dPlane.CenterOfPlane[plane];
m: Matrix ¬ G3dMatrix.ObtainMatrix[];
m ¬ G3dMatrix.MakeFromTriad[x, y, z, o, FALSE, m];
m ¬ G3dMatrix.Mul[m, view];
FOR i: INT IN [0..4) DO a[i] ¬ VP[G3dMatrix.TransformPairD[q[i], m]]; ENDLOOP;
FOR i: INT IN [0..4) DO Line2d[context, a[i], a[(i+1) MOD 4], drawType, useCG6]; ENDLOOP;
Vector[context, o, z, view, viewport];
G3dMatrix.ReleaseMatrix[m];
};
};
Circle:
PUBLIC PROC [
context: Context,
p0, p1, p2: Triple,
nVertices: INT,
view: Matrix,
viewport: Viewport,
drawType: DrawType]
~ {
VP:
PROC [p: Pair]
RETURNS [x: Pair] ~
INLINE {
x ¬ G3dMatrix.TransformByViewport[p, viewport];
};
plane: G3dPlane.Plane ¬ G3dPlane.FromThreePoints[p0, p1, p2];
n: Triple ¬ [plane.x, plane.y, plane.z];
v0: Triple ¬ G3dVector.Unit[G3dVector.Cross[G3dVector.Sub[p0, p1], n]];
v1: Triple ¬ G3dVector.Unit[G3dVector.Cross[G3dVector.Sub[p1, p2], n]];
dot: REAL ¬ G3dVector.Dot[v0, v1];
IF dot # 1.0
THEN {
m0: Triple ¬ G3dVector.Midpoint[p0, p1];
m1: Triple ¬ G3dVector.Midpoint[p1, p2];
dm: Triple ¬ G3dVector.Sub[m1, m0];
t: REAL ¬ (dot*G3dVector.Dot[v0, dm]-G3dVector.Dot[v1, dm])/(1.-dot*dot);
center: Triple ¬ G3dVector.ScaleRay[[m1, v1], t];
radius: REAL ¬ G3dVector.Distance[center, p0];
x: Triple ¬ G3dVector.Sub[center, p0];
y: Triple ¬ G3dVector.Mul[G3dVector.Unit[G3dVector.Cross[x, n]], radius];
PI: REAL ~ 3.1415926535;
dAngle: REAL ¬ 2.0*PI/nVertices;
angle: REAL ¬ dAngle;
pp0: Triple ¬ G3dVector.Add[center, x];
FOR n:
INT IN [0..nVertices)
DO
cos: REAL ¬ RealFns.Cos[angle];
sin: REAL ¬ RealFns.SqRt[1.0-cos*cos];
pp1: Triple ¬ pp0;
IF angle > PI THEN sin ¬ -sin;
pp0 ¬ [center.x+cos*x.x+sin*y.x,center.y+cos*x.y+sin*y.y,center.z+cos*x.z+sin*y.z];
Segment[context, pp0, pp1, view, viewport, drawType];
angle ¬ angle+dAngle;
ENDLOOP;
};
};
Cube:
PUBLIC PROC [
context: Context,
center: Triple,
size: REAL,
view: Matrix,
viewport: Viewport,
drawType: DrawType ¬ solid]
~ {
VP: PROC [p: Pair] RETURNS [x: IntegerPair] ~ INLINE {x ¬ RndPairAndVP[p, viewport]};
rad: REAL ¬ 0.5*size;
l: REAL ¬ center.x-rad;
r: REAL ¬ center.x+rad;
t: REAL ¬ center.y-rad;
b: REAL ¬ center.y+rad;
n: REAL ¬ center.z-rad;
f: REAL ¬ center.z+rad;
lbn: IntegerPair ¬ VP[G3dMatrix.TransformD[[l, b, n], view]];
lbf: IntegerPair ¬ VP[G3dMatrix.TransformD[[l, b, f], view]];
ltn: IntegerPair ¬ VP[G3dMatrix.TransformD[[l, t, n], view]];
ltf: IntegerPair ¬ VP[G3dMatrix.TransformD[[l, t, f], view]];
rbn: IntegerPair ¬ VP[G3dMatrix.TransformD[[r, b, n], view]];
rbf: IntegerPair ¬ VP[G3dMatrix.TransformD[[r, b, f], view]];
rtn: IntegerPair ¬ VP[G3dMatrix.TransformD[[r, t, n], view]];
rtf: IntegerPair ¬ VP[G3dMatrix.TransformD[[r, t, f], view]];
useCG6: UseCG6 ¬ GetUseCG6[context];
Line2d[context, lbn, lbf, drawType, useCG6]; -- lb edge
Line2d[context, ltn, ltf, drawType, useCG6]; -- lt edge
Line2d[context, lbn, ltn, drawType, useCG6]; -- ln edge
Line2d[context, lbf, ltf, drawType, useCG6]; -- lf edge
Line2d[context, lbn, rbn, drawType, useCG6]; -- bn edge
Line2d[context, ltn, rtn, drawType, useCG6]; -- tn edge
Line2d[context, lbf, rbf, drawType, useCG6]; -- bf edge
Line2d[context, ltf, rtf, drawType, useCG6]; -- tf edge
Line2d[context, rbn, rtn, drawType, useCG6]; -- rn edge
Line2d[context, rbf, rtf, drawType, useCG6]; -- rf edge
Line2d[context, rbn, rbf, drawType, useCG6]; -- rb edge
Line2d[context, rtn, rtf, drawType, useCG6]; -- rt edge
};
DoGetSpherePoints:
PROC [center:
Triple,
radius:
REAL,
nCircles:
INT,
points:
TripleSequence]
~
{
delta: REAL ¬ 2.0/REAL[nCircles-1];
points.length ¬ 2+nCircles*(nCircles-2);
points[0] ¬ [center.x, center.y, center.z-radius];
points[points.length-1] ¬ [center.x, center.y, center.z+radius];
FOR i:
INT IN [0..(nCircles/2)-1)
DO
offset: REAL ¬ REAL[i+1]*delta;
offsetZ: REAL ¬ radius*offset;
z1: REAL ¬ center.z-radius+offsetZ;
z2: REAL ¬ center.z+radius-offsetZ;
nOffset: INT ¬ i*nCircles;
index1: INT ¬ 1+nOffset;
index2: INT ¬ points.length-1-nCircles-nOffset;
sin: REAL ¬ 1.0-offset;
s: REAL ¬ radius*RealFns.SqRt[1.0-sin*sin];
FOR j:
INT IN [0..nCircles)
DO
points[index1+j] ¬ [s, 0.0, z1];
points[index2+j] ¬ [s, 0.0, z2];
ENDLOOP;
ENDLOOP;
FOR i:
INT IN [0..nCircles-2)
DO
index: INT ¬ 1+i*nCircles;
middle: BOOL ¬ (nCircles MOD 2) = 1 AND i = (nCircles/2)-1;
s: REAL ¬ IF middle THEN radius ELSE points[index].x;
z: REAL ¬ IF middle THEN center.z ELSE points[index].z;
FOR j:
INT IN [0..nCircles)
DO
aa: REAL ¬ REAL[j]*360.0/REAL[nCircles];
x: REAL ¬ center.x+s*RealFns.CosDeg[aa];
y: REAL ¬ center.y+s*RealFns.SinDeg[aa];
points[index+j] ¬ [x, y, z];
ENDLOOP;
ENDLOOP;
};
Sphere:
PUBLIC PROC [
context: Context,
center: Triple,
radius: REAL,
nCircles: INT,
view: Matrix,
viewport: Viewport,
points: TripleSequence ¬ NIL,
drawType: DrawType ¬ solid]
~ {
pts: TripleSequence ¬ IF points # NIL THEN points ELSE ObtainTriples[2+nCircles*(nCircles-2)];
IF points = NIL THEN DoGetSpherePoints[center, radius, nCircles, pts];
FOR i:
INT IN [0..nCircles-2)
DO
index: INT ¬ 1+i*nCircles;
p0: Triple ¬ pts[index+nCircles-1];
FOR j:
INT IN [0..nCircles)
DO
p1: Triple ¬ pts[index+j];
Segment[context, p0, p1, view, viewport, drawType];
p0 ¬ p1;
ENDLOOP;
ENDLOOP;
FOR i:
INT IN [0..nCircles)
DO
p0: Triple ¬ pts[0];
FOR j:
INT IN [0..nCircles-2)
DO
p1: Triple ¬ pts[1+nCircles*j+i];
Segment[context, p0, p1, view, viewport, drawType];
p0 ¬ p1;
ENDLOOP;
Segment[context, p0, pts[pts.length-1], view, viewport, drawType];
ENDLOOP;
IF points = NIL THEN ReleaseTriples[pts];
};