DIRECTORY G3dBasic, G3dMatrix, G3dPatch, G3dSpline, G3dVector; G3dPatchImpl: CEDAR PROGRAM IMPORTS G3dSpline, G3dVector EXPORTS G3dPatch ~ BEGIN Triple: TYPE ~ G3dBasic.Triple; Matrix: TYPE ~ G3dMatrix.Matrix; Bezier: TYPE ~ G3dSpline.Bezier; Spline: TYPE ~ G3dSpline.Spline; ControlPoints: TYPE ~ G3dPatch.ControlPoints; ControlPointsRep: TYPE ~ G3dPatch.ControlPointsRep; FourPatches: TYPE ~ G3dPatch.FourPatches; Patch: TYPE ~ G3dPatch.Patch; PatchRep: TYPE ~ G3dPatch.PatchRep; FromBezier: PUBLIC PROC [cp: ControlPoints, out: Patch ¬ NIL] RETURNS [p: Patch] ~ { p ¬ IF out # NIL THEN out ELSE NEW[PatchRep]; p.controlPoints ¬ cp; FOR i: NAT IN [0..4) DO p.sCurves[i]¬G3dSpline.SplineFromBezier[[cp[i][0],cp[i][1],cp[i][2], cp[i][3]], p.sCurves[i]]; ENDLOOP; FOR i: NAT IN [0..4) DO p.tCurves[i]¬G3dSpline.SplineFromBezier[[cp[0][i],cp[1][i],cp[2][i], cp[3][i]], p.tCurves[i]]; ENDLOOP; }; Position: PUBLIC PROC [patch: Patch, s, t: REAL] RETURNS [Triple] ~ { Lerp: PROC [p, q: Triple] RETURNS [Triple] ~ INLINE { RETURN[[p.x+s*(q.x-p.x), p.y+s*(q.y-p.y), p.z+s*(q.z-p.z)]]; }; s0: Triple ¬ G3dSpline.Position[patch.sCurves[0], t]; s1: Triple ¬ G3dSpline.Position[patch.sCurves[1], t]; s2: Triple ¬ G3dSpline.Position[patch.sCurves[2], t]; s3: Triple ¬ G3dSpline.Position[patch.sCurves[3], t]; s12: Triple ¬ Lerp[s1, s2]; RETURN[Lerp[Lerp[Lerp[s0, s1], s12], Lerp[s12, Lerp[s2, s3]]]]; }; Normal: PUBLIC PROC [patch: Patch, s, t: REAL, unitize: BOOL ¬ TRUE] RETURNS [Triple] ~ { vs: Triple ¬ G3dSpline.Velocity[SCurve[patch, s], t]; vt: Triple ¬ G3dSpline.Velocity[SCurve[patch, t], s]; n: Triple ¬ G3dVector.Cross[vs, vt]; RETURN[IF unitize THEN G3dVector.Unit[n] ELSE n]; }; SplineFrom4: PROC [curves: ARRAY [0..4) OF Spline, t: REAL, out: Spline ¬ NIL] RETURNS [Spline] ~ { p0: Triple ¬ G3dSpline.Position[curves[0], t]; p1: Triple ¬ G3dSpline.Position[curves[1], t]; p2: Triple ¬ G3dSpline.Position[curves[2], t]; p3: Triple ¬ G3dSpline.Position[curves[3], t]; RETURN[G3dSpline.SplineFromBezier[[p0, p1, p2, p3], out]]; }; SCurve: PUBLIC PROC [patch: Patch, s: REAL, out: Spline ¬ NIL] RETURNS [Spline] ~ { RETURN[SplineFrom4[patch.tCurves, s, out]]; }; TCurve: PUBLIC PROC [patch: Patch, t: REAL, out: Spline ¬ NIL] RETURNS [Spline] ~ { RETURN[SplineFrom4[patch.sCurves, t, out]]; }; Subdivide: PUBLIC PROC [patch: Patch, s, t: REAL ¬ 0.5] RETURNS [fp: FourPatches] ~ { BezierDivide: PROC [b: Bezier, t: REAL] RETURNS [b1, b2: Bezier] ~ { Lerp: PROC [p, q: Triple] RETURNS [Triple] ~ INLINE { tt: REAL ¬ 1.0-t; RETURN[[tt*p.x+t*q.x, tt*p.y+t*q.y, tt*p.z+t*q.z]]; }; b01: Triple ¬ Lerp[b.b0, b.b1]; b12: Triple ¬ Lerp[b.b1, b.b2]; b23: Triple ¬ Lerp[b.b2, b.b3]; b0112: Triple ¬ Lerp[b01, b12]; b1223: Triple ¬ Lerp[b12, b23]; b01121223: Triple ¬ Lerp[b0112, b1223]; RETURN[[b.b0, b01, b0112, b01121223], [b01121223, b1223, b23, b.b3]]; }; PatchFromBezier: PROC [b0, b1, b2, b3: Bezier] RETURNS [p: Patch] ~ { RETURN[FromBezier[NEW[ControlPointsRep ¬ [ [b0.b0, b0.b1, b0.b2, b0.b3], [b1.b0, b1.b1, b1.b2, b1.b3], [b2.b0, b2.b1, b2.b2, b2.b3], [b3.b0, b3.b1, b3.b2, b3.b3]]]]]; }; cp: ControlPoints ¬ patch.controlPoints; s0, s1, s2, s3, s4, s5, s6, s7, t0, t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12, t13: Bezier; [s0, s1] ¬ BezierDivide[[cp[0][0], cp[0][1], cp[0][2], cp[0][3]], s]; [s2, s3] ¬ BezierDivide[[cp[1][0], cp[1][1], cp[1][2], cp[1][3]], s]; [s4, s5] ¬ BezierDivide[[cp[2][0], cp[2][1], cp[2][2], cp[2][3]], s]; [s6, s7] ¬ BezierDivide[[cp[3][0], cp[3][1], cp[3][2], cp[3][3]], s]; [t0, t1] ¬ BezierDivide[[s0.b0, s2.b0, s4.b0, s6.b0], t]; [t2, t3] ¬ BezierDivide[[s0.b1, s2.b1, s4.b1, s6.b1], t]; [t4, t5] ¬ BezierDivide[[s0.b2, s2.b2, s4.b2, s6.b2], t]; [t6, t7] ¬ BezierDivide[[s0.b3, s2.b3, s4.b3, s6.b3], t]; [t8, t9] ¬ BezierDivide[[s1.b1, s3.b1, s5.b1, s7.b1], t]; [t10, t11] ¬ BezierDivide[[s1.b2, s3.b2, s5.b2, s7.b2], t]; [t11, t12] ¬ BezierDivide[[s1.b3, s3.b3, s5.b3, s7.b3], t]; fp[0] ¬ PatchFromBezier[t0, t2, t4, t6]; fp[1] ¬ PatchFromBezier[t1, t3, t5, t7]; fp[2] ¬ PatchFromBezier[t6, t8, t10, t12]; fp[3] ¬ PatchFromBezier[t7, t9, t11, t13]; }; END. .. If ever we want forward differencing: Patch: TYPE ~ REF RECORD [ARRAY [0..4) OF ARRAY [0..4) OF ARRAY [0..4) OF REAL; Bezier: PUBLIC PROC [cp: ControlPoints, out: Patch ¬ NIL] RETURNS [p: Patch] ~ { b: PatchRep; p ¬ IF out # NIL THEN out ELSE NEW[PatchRep]; FOR k: NAT IN [0..4) DO IF k = 3 THEN FOR i: NAT IN [0..4) DO b[i][0][k] ¬ -cp[i][0][k]+3.0*cp[i][1][k]-3.0*cp[i][2][k]+cp[i][3][k]; b[i][1][k] ¬ 3.0*cp[i][0][k]-6.0*cp[i][1][k]+3.0*cp[i][2][k]; b[i][2][k] ¬ 3.0*cp[i][0][k]+3.0*cp[i][1][k]; b[i][3][k] ¬ 1.0; ENDLOOP ELSE FOR i: NAT IN [0..4) DO b[i][0][3] ¬ 0.0; b[i][1][3] ¬ 0.0; b[i][2][3] ¬ 6.0; b[i][3][3] ¬ 1.0; ENDLOOP; FOR j: NAT IN [0..4) DO p[0][j][k] ¬ -b[0][j][k]+3.0*b[1][j][k]-3.0*b[2][j][k]+b[3][j][k]; p[1][j][k] ¬ 3.0*b[0][j][k]-6.0*b[1][j][k]+3.0*b[2][j][k]; p[2][j][k] ¬ -3.0*b[0][j][k]+3.0*b[1][j][k]; p[3][j][k] ¬ b[0][j][k]; ENDLOOP; ENDLOOP; }; Draw: PUBLIC PROC [context: Context, view: Matrix, patch: Patch, nCurves, nSegments: NAT] ~ { tcoeff, ucoeff, temp, diff: PatchRep; curve: Spline; s1: REAL ¬ 1.0/REAL[nSegments]; s2: REAL ¬ s1*s1; s22: REAL ¬ s2+s2; s3: REAL ¬s2*s1; s36: REAL ¬ 6.0*s3; c1: REAL ¬ 1.0/REAL[nCurves]; c2: REAL ¬ c1*c1; c22: REAL ¬ c2+c2; c3: REAL ¬ c2*c1; c36: REAL ¬ 6.0*c3; sDirection: BOOL ¬ TRUE; FOR j: NAT IN [0..4) DO FOR i: NAT IN [0..4) DO FOR k: NAT IN [0..4) DO tcoeff[i][j][k] ¬ patch[i][j][0]*view[0][k]+ patch[i][j][1]*view[1][k]+ patch[i][j][2]*view[2][k]+ patch[i][j][3]*view[3][k]; ENDLOOP; ENDLOOP; ENDLOOP; FOR k: NAT IN [0..4) DO FOR i: NAT IN [0..4) DO temp[i][0][k] ¬ tcoeff[i][3][k]; temp[i][1][k] ¬ tcoeff[i][0][k]*c3+tcoeff[i][1][k]*c2+tcoeff[i][2][k]*c1; temp[i][3][k] ¬ tcoeff[i][0][k]*c36; temp[i][2][k] ¬ temp[i][3][k]+tcoeff[i][1][k]*c22; ENDLOOP; FOR j: NAT IN [0..4) DO diff[0][j][k] ¬ temp[3][j][k]; diff[1][j][k] ¬ s3*temp[0][j][k]+s2*temp[1][j][k]+s1*temp[2][j][k]; diff[3][j][k] ¬ s36*temp[0][j][k]; diff[2][j][k] ¬ diff[3][j][k]+s22*temp[1][j][k]; ENDLOOP; ENDLOOP; };  G3dPatchImpl.mesa Copyright Σ 1985, 1992 by Xerox Corporation. All rights reserved. Bloomenthal, October 21, 1992 4:35 pm PDT Types Creation Evaluation Subdivision split: Matrix _ NEW[MatrixRep _ [ [1.000, 0.000, 0.000, 0.000], [0.500, 0.500, 0.000, 0.000], [0.025, 0.500, 0.250, 0.000], [0.125, 0.375, 0.375, 0.125]]]; Subdivide: PUBLIC PROC [patch: Patch, s, t: REAL _ 0.5] RETURNS [fp: FourPatches] ~ { SubdivideS: PROC [p0, p1, p2, p3: Triple] RETURNS [q0, q1, q2, q3: Triple] ~ { p: Matrix _ G3dMatrix.ObtainMatrix[]; p^ _ [[p0.x, p0.y, p0.z, 1.], [p1.x, p1.y, p1.z, 1.], [p2.x, p2.y, p2.z, 1.], [p3.x, p3.y, p3.z, 1.]]; p _ G3dMatrix.Mul[split, p, p]; q0 _ [p[0][0], p[0][1], p[0][2], p[0][3]]; q0 _ [p[0][0], p[0][1], p[0][2], p[0][3]]; q0 _ [p[0][0], p[0][1], p[0][2], p[0][3]]; q0 _ [p[0][0], p[0][1], p[0][2], p[0][3]]; G3dMatrix.ReleaseMatrix[p]; }; Creation Postmultiply by Beziert: Premultiply by Bezier: Drawing Postmultiply patch by view: Postmultiply transformed patch by D[nCurves]T: Premultiply by D[nSegments]: Κ~•NewlineDelimiter –"cedarcode" style™™Jšœ Οeœ6™BJ™)J˜—šΟk œ5˜>J˜—šΠln œž ˜Jšžœ˜Jšžœ ˜J˜—Jšœž˜headšΟl™Jšœ žœ˜"Jšœ žœ˜#Jšœ žœ˜#šœ žœ˜#J˜—Jšœžœ˜.Jšœžœ˜3Jšœ žœ˜+Jšœž œ˜!Jšœ žœ˜&—š ™š Οn œžœžœ"žœžœ˜TJš œžœžœžœžœžœ ˜-J˜šžœžœžœž˜JšœOΟsœ˜^Jšžœ˜—šžœžœžœž˜JšœO’œ˜^Jšžœ˜—J˜——š  ™ š ‘œžœžœžœžœ ˜Eš‘œžœžœ žœ˜5Jšžœ6˜