<> <> <> DIRECTORY Clip3d, Draw2d, Draw3d, Imager, ImagerBackdoor, IO, Matrix3d, Polygons3d, Real, Rope, Spline3d, Vector2, Vector3d; Draw3dImpl: CEDAR PROGRAM IMPORTS Clip3d, Draw2d, Imager, ImagerBackdoor, IO, Matrix3d, Real, Polygons3d, Spline3d, Vector2, Vector3d EXPORTS Draw3d ~ BEGIN OPEN Draw3d; <> PairClip: TYPE ~ RECORD [pair: Pair, clipped: BOOL]; TransformAndClip: PROC [point: Triple, matrix: Matrix] RETURNS [PairClip] ~ { IF matrix[2][3] # 0.0 THEN { q: Quad _ Matrix3d.TransformH[point, matrix]; IF q.z+q.w < 0.0 THEN RETURN[[[0.0, 0.0], TRUE]]; RETURN[[[q.x/q.w, q.y/q.w], FALSE]]; } ELSE RETURN[[Matrix3d.TransformD[point, matrix], FALSE]]; }; Mark: PUBLIC PROC [ context: Context, point: Triple, matrix: Matrix, label: ROPE _ NIL, markType: MarkType _ cross] ~ { IF markType # none OR label # NIL THEN { pairClip: PairClip ~ TransformAndClip[point, matrix]; IF pairClip.clipped THEN RETURN; IF markType # none THEN Draw2d.Mark[context, pairClip.pair, markType]; IF label # NIL THEN Draw2d.Label[context, [pairClip.pair.x+6, pairClip.pair.y], label]; }; }; DoWithPoint: PUBLIC PROC [ context: Context, point: Triple, matrix: Matrix, pointProc: PointProc] ~ { pairClip: PairClip ~ TransformAndClip[point, matrix]; IF NOT pairClip.clipped THEN pointProc[context, pairClip.pair]; }; <> Segment: PUBLIC PROC [ context: Context, point0, point1: Triple, matrix: Matrix, drawType: DrawType _ solid] ~ { c0, c1: Pair; IF Matrix3d.HasPerspective[matrix] THEN { off: BOOL; [c0, c1, off] _ Clip3d.NearH[Matrix3d.TransformH[point0, matrix], Matrix3d.TransformH[point1, matrix]]; IF NOT off THEN Draw2d.Line[context, c0, c1, drawType]; } ELSE { c0 _ Matrix3d.TransformD[point0, matrix]; c1 _ Matrix3d.TransformD[point1, matrix]; Draw2d.Line[context, c0, c1, drawType]; }; }; Vector: PUBLIC PROC [ context: Context, base, vector: Triple, matrix: Matrix, label: ROPE _ NIL, scale: REAL _ 0.2, markType: MarkType _ none, drawType: DrawType _ solid] ~ { c0, c1, d: Pair; end: Triple _ Vector3d.Add[base, vector]; IF Matrix3d.HasPerspective[matrix] THEN { off: BOOL; [c0, c1, off] _ Clip3d.NearH[Matrix3d.TransformH[base, matrix], Matrix3d.TransformH[end, matrix]]; IF off THEN RETURN; IF markType # none THEN Mark[context, base, matrix, , markType]; } ELSE { c0 _ Matrix3d.TransformD[base, matrix]; c1 _ Matrix3d.TransformD[end, matrix]; IF markType # none THEN Draw2d.Mark[context, c0, markType]; }; d _ [scale*(c1.x-c0.x), scale*(c1.y-c0.y)]; c1 _ [c0.x+d.x, c0.y+d.y]; Draw2d.Arrow[context, c0, c1, drawType]; IF label # NIL THEN { Draw2d.Label[ context, IF d = [0, 0] THEN c1 ELSE Vector2.Add[[c1.x, c1.y-4], Vector2.Mul[Vector2.Unit[d], 6]], label]; }; }; Axes: PUBLIC PROC [context: Context, matrix: Matrix] ~ { Vector[context, [0.0, 0.0, 0.0], [1.0, 0.0, 0.0], matrix, "X"]; Vector[context, [0.0, 0.0, 0.0], [0.0, 1.0, 0.0], matrix, "Y"]; Vector[context, [0.0, 0.0, 0.0], [0.0, 0.0, 1.0], matrix, "Z"]; }; <> Curve: PUBLIC PROC [context: Context, coeffs: Coeffs, matrix: Matrix _ NIL] ~ { IF coeffs # NIL THEN { persp: BOOL _ Matrix3d.HasPerspective[matrix]; xc: Coeffs _ IF matrix = NIL THEN coeffs ELSE Matrix3d.Mul[coeffs, matrix]; nSegs: INTEGER _ Spline3d.Resolution[xc, 1.0]; dif: Coeffs _ Spline3d.FwdDif[xc, nSegs]; nCoords: NAT _ IF 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.Line[context, c0, c1]; q0 _ q1; } ELSE { Draw2d.Line[context, p0, p1]; p0 _ p1; }; ENDLOOP; }; }; DotCurve: PUBLIC PROC [context: Context, coeffs: Coeffs, matrix: Matrix _ NIL] ~ { IF coeffs # NIL THEN { persp: BOOL _ Matrix3d.HasPerspective[matrix]; xc: Coeffs _ IF matrix = NIL THEN coeffs ELSE Matrix3d.Mul[coeffs, matrix]; nSegs: INTEGER _ 4*Spline3d.Resolution[xc, 1.0]; dif: Coeffs _ Spline3d.FwdDif[xc, nSegs]; nCoords: NAT _ IF 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; }; }; BezierPolygon: PUBLIC PROC [ context: Context, bezier: Bezier, matrix: Matrix _ NIL, drawType: Draw2d.DrawType _ solid, close: BOOL _ FALSE] ~ { Segment[context, bezier.b0, bezier.b1, matrix, drawType]; Segment[context, bezier.b1, bezier.b2, matrix, drawType]; Segment[context, bezier.b2, bezier.b3, matrix, drawType]; IF close THEN Segment[context, bezier.b0, bezier.b3, matrix, drawType]; }; <> Triangle: PUBLIC PROC [ context: Context, p0, p1, p2: Triple, view: Matrix] ~ { pp0: Pair _ Matrix3d.TransformD[p0, view]; pp1: Pair _ Matrix3d.TransformD[p1, view]; pp2: Pair _ Matrix3d.TransformD[p2, view]; Draw2d.Line[context, pp0, pp1]; Draw2d.Line[context, pp1, pp2]; Draw2d.Line[context, pp2, pp0]; }; <<>> FrontFacingTriangle: PUBLIC PROC [ context: Context, p0, p1, p2: Triple, view: Matrix, normal: Triple _ origin] ~ { IF normal = origin THEN normal _ Polygons3d.TriangleNormal[p0, p1, p2]; IF normal.x*view[0][2]+normal.y*view[1][2]+normal.z*view[2][2] >= 0.0 THEN Triangle[context, p0, p1, p2, view]; }; <> PolygonPairs: PUBLIC PROC [ triples: TripleSequence, view: Matrix, pairs: PairSequence _ NIL] RETURNS [PairSequence] ~ { IF triples # NIL AND view # NIL THEN { IF pairs = NIL OR pairs.length < triples.length THEN pairs _ NEW[PairSequenceRep[triples.length]]; pairs.length _ triples.length; FOR n: NAT IN[0..triples.length) DO pairs[n] _ Matrix3d.TransformD[triples[n], view]; ENDLOOP; }; RETURN[pairs]; }; << >> Polygon: PUBLIC PROC [ context: Context, poly: REF NatSequence, pairs: PairSequence _ NIL, triples: TripleSequence _ NIL, view: Matrix _ NIL] ~ { stop: CARDINAL ~ poly.length-1; IF pairs = NIL AND view # NIL AND triples # NIL THEN { pairs _ NEW[PairSequenceRep[triples.length]]; FOR n: NAT IN [0..poly.length) DO i: NAT ~ poly[n]; pairs[i] _ Matrix3d.TransformD[triples[i], view]; ENDLOOP; }; IF pairs # NIL AND poly # NIL AND poly.length > 0 THEN { FOR i: NAT IN[0..stop) DO Draw2d.Line[context, pairs[poly[i]], pairs[poly[i+1]]]; ENDLOOP; Draw2d.Line[context, pairs[poly[stop]], pairs[poly[0]]]; }; }; <<>> FrontFacingPolygon: PUBLIC PROC [ context: Context, poly: REF NatSequence, view: Matrix, normal: Triple _ origin, pairs: PairSequence _ NIL, triples: TripleSequence _ NIL] ~ { IF normal = origin AND triples = NIL THEN RETURN; IF normal = origin THEN { vertices: TripleSequence _ NEW[TripleSequenceRep[poly.length]]; FOR n: NAT IN [0..poly.length) DO vertices[n] _ triples[poly[n]]; ENDLOOP; normal _ Polygons3d.PolygonNormal[vertices]; }; IF normal.x*view[0][2]+normal.y*view[1][2]+normal.z*view[2][2] >= 0.0 THEN Polygon[context, poly, pairs, triples, view]; }; <<>> Polygons: PUBLIC PROC [ context: Context, polygons: REF NatTable, pairs: PairSequence _ NIL, triples: TripleSequence _ NIL, view: Matrix _ NIL] ~ { IF pairs = NIL AND view # NIL AND triples # NIL THEN { pairs _ NEW[PairSequenceRep[triples.length]]; FOR n: NAT IN [0..triples.length) DO pairs[n] _ Matrix3d.TransformD[triples[n], view]; ENDLOOP; }; IF polygons # NIL AND pairs # NIL THEN FOR n: NAT IN[0..polygons.length) DO poly: REF NatSequence ~ polygons[n]; stop: CARDINAL ~ poly.length-1; IF poly = NIL OR poly.length < 1 THEN LOOP; FOR i: NAT IN[0..stop) DO Draw2d.Line[context, pairs[poly[i]], pairs[poly[i+1]]]; ENDLOOP; Draw2d.Line[context, pairs[poly[stop]], pairs[poly[0]]]; ENDLOOP; }; <<>> FrontFacingPolygons: PUBLIC PROC [ context: Context, polygons: REF NatTable, view: Matrix, normals: TripleSequence, pairs: PairSequence _ NIL, triples: TripleSequence _ NIL] ~ { IF polygons = NIL OR view = NIL OR normals = NIL OR (pairs = NIL AND triples = NIL) THEN RETURN; IF pairs = NIL THEN { pairs _ NEW[PairSequenceRep[triples.length]]; FOR n: NAT IN [0..triples.length) DO pairs[n] _ Matrix3d.TransformD[triples[n], view]; ENDLOOP; }; FOR n: NAT IN[0..polygons.length) DO poly: REF NatSequence _ polygons[n]; IF poly = NIL OR poly.length < 1 THEN LOOP; IF normals[n].x*view[0][2]+normals[n].y*view[1][2]+normals[n].z*view[2][2] < 0.0 THEN LOOP; FOR i: NAT IN[0..poly.length-1) DO Draw2d.Line[context, pairs[poly[i]], pairs[poly[i+1]]]; ENDLOOP; Draw2d.Line[context, pairs[poly[poly.length-1]], pairs[poly[0]]]; ENDLOOP; }; <> Pendant: PUBLIC PROC [ context: Context, view: Matrix, size: REAL _ .07, wPos, hPos: REAL _ .7, names: ARRAY [0..6) OF ROPE _ ALL[NIL]] ~ { mx: REAL _ 0.0; v: ARRAY [0..6) OF V; V: TYPE ~ RECORD[rope: ROPE, vec: Triple]; axes: ARRAY [0..6) OF Triple ~ [[1, 0, 0], [0, 1, 0], [0, 0, 1], [-1, 0, 0], [0, -1, 0], [0, 0, -1]]; c: Pair; rect: Imager.Rectangle _ [0.0, 0.0, 600.0, 400.0]; rect _ ImagerBackdoor.GetBounds[context ! Imager.Error => CONTINUE]; c _ [rect.w*(1+wPos)/2, rect.h*(1+hPos)/2]; FOR n: NAT IN [0..6) DO v[n] _ [names[n], Matrix3d.TransformVec[axes[n], view]]; ENDLOOP; FOR n: NAT IN [0..6) DO mx _ MAX[mx, Vector2.Square[[v[n].vec.x, v[n].vec.y]]]; ENDLOOP; mx _ MAX[rect.w, rect.h]*size/Real.SqRt[mx]; FOR n: NAT IN [0..6) DO v[n].vec _ Vector3d.Mul[v[n].vec, mx]; ENDLOOP; DO -- order v by increasing z: d: BOOL _ FALSE; FOR n: NAT IN [0..5) DO IF v[n].vec.z> <> <> <> <<[xpoint, ] _ ThreeDScenes.XfmPtToEyeSpace[context3d, point];>> <> <<};>> <<>> <> <> <<>> <> <> <> <> <<>> <> <> <> <<}>> <> < a1 THEN RETURN[c0, c1, TRUE];>> <<>> <> <> <> <> <<};>> <> <> <<[c0, c1, off] _ ClipZ[p0, p1, -focalLength+0.01];>> <> <> <> <> <<};>> <<};>> <<>>