-- File: SweepGeometryImpl.mesa -- Last edited by Bier on December 18, 1982 1:31 am -- Author: Eric Allan Bier on July 3, 1983 1:29 pm -- Contents: Implementation of a simple, straight-line, sweep geometry package for fast interactive graphics DIRECTORY CoordSys, DisplayList3d, Draw3d, CSGGraphics, Graphics, Matrix3d, RealFns, Shading, SV2d, SVPolygon2d, SVPolygon3d, SweepGeometry, SVVector3d; SweepGeometryImpl: PROGRAM IMPORTS CSGGraphics, Draw3d, RealFns, SVPolygon2d, SVPolygon3d, SVVector3d EXPORTS SweepGeometry = BEGIN Camera: TYPE = CSGGraphics.Camera; Poly3d: TYPE = REF Poly3dObj; Poly3dObj: TYPE = SVPolygon3d.Poly3dObj; Point2d: TYPE = SV2d.Point2d; Point3d: TYPE = Matrix3d.Point3d; Vector: TYPE = SVVector3d.Vector; LinearMesh: TYPE = REF LinearMeshRecord; LinearMeshRecord: TYPE = SweepGeometry.LinearMeshRecord; RevoluteMesh: TYPE = REF RevoluteMeshRecord; RevoluteMeshRecord: TYPE = SweepGeometry.RevoluteMeshRecord; ToroidalMesh: TYPE = REF ToroidalMeshRecord; ToroidalMeshRecord: TYPE = SweepGeometry.ToroidalMeshRecord; LightSource: TYPE = REF LightSourceObj; LightSourceObj: TYPE = Shading.LightSourceObj; LightSourceList: TYPE = LIST OF LightSource; MasterObject: TYPE = REF MasterObjectRec; MasterObjectRec: TYPE = DisplayList3d.MasterObjectRec; Path: TYPE = REF PathObj; PathObj: TYPE = SV2d.PathObj; Polygon: TYPE = REF PolygonObj; PolygonObj: TYPE = SV2d.PolygonObj; Assembly: TYPE = REF AssemblyObj; AssemblyObj: TYPE = DisplayList3d.AssemblyObj; CoordSystem: TYPE = REF CoordSysObj; CoordSysObj: TYPE = CoordSys.CoordSysObj; PlanarSurface: TYPE = REF PlanarSurfaceObj; PlanarSurfaceObj: TYPE = DisplayList3d.PlanarSurfaceObj; PlanarSurfaceList: TYPE = DisplayList3d.PlanarSurfaceList; TooFewPointsForShadedSweep: SIGNAL = CODE; LinearSweep: PUBLIC PROC [poly: Polygon, frontDepth: REAL _ 0.5, backDepth: REAL _ -0.5] RETURNS [meshRecord: LinearMesh] = { frontToBack, clockWise, thisNorm: Vector; iPlusOne: NAT; IF NOT SVPolygon2d.IsClockwisePoly[poly] THEN SVPolygon2d.InvertPolyInPlace[poly]; meshRecord _ NEW[LinearMeshRecord]; FOR i: NAT IN[1..poly.len] DO FOR j: NAT IN[1..2] DO meshRecord.array[i][j][1] _ poly[i-1][1]; meshRecord.array[i][j][2] _ poly[i-1][2]; ENDLOOP; meshRecord.array[i][1][3] _ frontDepth; meshRecord.array[i][2][3] _ backDepth; ENDLOOP; meshRecord.len _ poly.len; -- now iterate over all surfaces and find their normals. -- front and back surfaces are trivial since we know there normals are aligned with the z axis. -- If len <=2, then there are no front and back surfaces. IF poly.len <=2 THEN SIGNAL TooFewPointsForShadedSweep; meshRecord.surfaces.front.normal _ [0,0,1]; meshRecord.surfaces.back.normal _ [0,0,-1]; -- for simplicity, I make the path be clockwise when determining outward pointing normal. -- with linear sweep shapes, the [i][1] to [i][2] and [i][1] to [i+1][1] vectors are orthogonal. -- Their cross product is the surface normal. It will have a zero z component, initially. FOR i: NAT IN[1..poly.len] DO iPlusOne _ IF i = poly.len THEN 1 ELSE i + 1; frontToBack _ SVVector3d.Difference[meshRecord.array[i][2],meshRecord.array[i][1]]; clockWise _ SVVector3d.Difference[meshRecord.array[iPlusOne][1],meshRecord.array[i][1]]; thisNorm _ SVVector3d.CrossProduct[clockWise,frontToBack]; meshRecord.surfaces.sides[i].normal _ thisNorm; ENDLOOP; }; -- end of ShadedLinearSweep RevoluteSweep: PUBLIC PROC [path: Path, linesOfLongitude: NAT _ 10] RETURNS [meshRecord: RevoluteMesh] = { leftToRight, rightToLeft, thisNorm: Vector; degreesPerLong: REAL; thisAngle: REAL; jPlusOne: NAT; poly: Polygon; -- Add two points to path (the extensions of the first and last points to the y axis) and make it a polygon. poly _ SVPolygon2d.CreatePoly[path.len+2]; poly _ SVPolygon2d.PutPolyPoint[poly, 0 , [0, path[0][2]]]; poly _ SVPolygon2d.PutPolyPoint[poly, path.len + 1, [0, path[path.len -1][2]]]; poly _ SVPolygon2d.PartPolyGetsPartPath[path, 0, poly, 1, path.len]; -- Correct the data if necessary so all x's are positive. Then make sure the poly is clockwise. FOR i: NAT IN[0..poly.len) DO IF poly[i][1] < 0 THEN poly[i][1] _ -poly[i][1]; ENDLOOP; IF NOT SVPolygon2d.IsClockwisePoly[poly] THEN SVPolygon2d.InvertPolyInPlace[poly]; path _ SVPolygon2d.SubPathOfPoly[poly, 1, path.len]; -- CREATE A NEW REVOLUTE SWEEP from the points in poly degreesPerLong _ 360.0/linesOfLongitude; meshRecord _ NEW[RevoluteMeshRecord]; FOR i: NAT IN[1..path.len] DO FOR j: NAT IN[1..linesOfLongitude] DO -- for each line of latitude, for each point of longitude, calculate its position in 3-space by "sweeping" the source point of array2d by the appropriate angle. sin, cos: REAL; thisAngle _ j*degreesPerLong; sin _ RealFns.SinDeg[thisAngle]; cos _ RealFns.CosDeg[thisAngle]; meshRecord.array[i][j][1] _ path[i-1][1]*cos; -- assign new x from source x meshRecord.array[i][j][3] _ -path[i-1][1]*sin; -- assign new z from source x meshRecord.array[i][j][2] _ path[i-1][2]; -- assign new y directly from source y ENDLOOP; -- next point of longitude ENDLOOP; -- next line of latitude meshRecord.linesOfLongitude _ linesOfLongitude; meshRecord.linesOfLatitude _ path.len; -- FIND THE NORMALS. I assume for now that the shape was drawn top to bottom, when determing normals -- the top and bottom surfaces are trivial since their normals are aligned with the y-axis. meshRecord.surfaces.top.normal _ [0,1,0]; meshRecord.surfaces.bottom.normal _ [0,-1,0]; -- Now, iterate over the side faces -- the [i][j] (upper-left corner) to the [i+1][j+1] (lower-right corner) diagonal vector -- and [i][j+1] (upper right) to the [i+1][j] (lower left) diagonal vector -- are two vectors lying in the plane. Their cross-product is a surface normal. FOR i: NAT IN[1..path.len-1] DO FOR j: NAT IN[1..linesOfLongitude] DO jPlusOne _ IF j = linesOfLongitude THEN 1 ELSE j + 1; leftToRight _ SVVector3d.Difference[meshRecord.array[i+1][jPlusOne], meshRecord.array[i][j]]; rightToLeft _ SVVector3d.Difference[meshRecord.array[i+1][j], meshRecord.array[i][jPlusOne]]; thisNorm _ SVVector3d.CrossProduct[rightToLeft,leftToRight]; meshRecord.surfaces.sides[i][j].normal _ thisNorm; ENDLOOP; ENDLOOP; }; -- end of ShadedRevoluteSweep ToroidalSweep: PUBLIC PROC [poly: Polygon, linesOfLongitude: NAT _ 10] RETURNS [meshRecord: ToroidalMesh] = { leftToRight, rightToLeft, thisNorm: Vector; degreesPerLong: REAL; thisAngle: REAL; iPlusOne, jPlusOne: NAT; -- Correct the data if necessary so all x's are positive. Then make sure the poly is clockwise. FOR i: NAT IN[0..poly.len) DO IF poly[i][1] < 0 THEN poly[i][1] _ -poly[i][1]; ENDLOOP; IF NOT SVPolygon2d.IsClockwisePoly[poly] THEN SVPolygon2d.InvertPolyInPlace[poly]; -- CREATE A NEW TOROIDAL SWEEP from the points in poly degreesPerLong _ 360.0/linesOfLongitude; meshRecord _ NEW[ToroidalMeshRecord]; FOR i: NAT IN[1..poly.len] DO FOR j: NAT IN[1..linesOfLongitude] DO -- for each line of latitude, for each point of longitude, calculate its position in 3-space by "sweeping" the source point of array2d by the appropriate angle. sin, cos: REAL; thisAngle _ j*degreesPerLong; sin _ RealFns.SinDeg[thisAngle]; cos _ RealFns.CosDeg[thisAngle]; meshRecord.array[i][j][1] _ poly[i-1][1]*cos; -- assign new x from source x meshRecord.array[i][j][3] _ -poly[i-1][1]*sin; -- assign new z from source x meshRecord.array[i][j][2] _ poly[i-1][2]; -- assign new y directly from source y ENDLOOP; -- next point of longitude ENDLOOP; -- next line of latitude meshRecord.linesOfLongitude _ linesOfLongitude; meshRecord.linesOfLatitude _ poly.len; -- FIND THE NORMALS. I assume for now that the shape was drawn top to bottom, when determing normals -- Iterate over the side faces -- the [i][j] (upper-left corner) to the [i+1][j+1] (lower-right corner) diagonal vector -- and [i][j+1] (upper right) to the [i+1][j] (lower left) diagonal vector -- are two vectors lying in the plane. Their cross-product is a surface normal. FOR i: NAT IN[1..poly.len] DO iPlusOne _ IF i = poly.len THEN 1 ELSE i + 1; FOR j: NAT IN[1..linesOfLongitude] DO jPlusOne _ IF j = linesOfLongitude THEN 1 ELSE j + 1; leftToRight _ SVVector3d.Difference[meshRecord.array[iPlusOne][jPlusOne], meshRecord.array[i][j]]; rightToLeft _ SVVector3d.Difference[meshRecord.array[iPlusOne][j], meshRecord.array[i][jPlusOne]]; thisNorm _ SVVector3d.CrossProduct[rightToLeft,leftToRight]; meshRecord.surfaces.sides[i][j].normal _ thisNorm; ENDLOOP; ENDLOOP; }; -- end of ToroidalSweep GetLinearPoly: PUBLIC PROC [linMesh: LinearMesh] RETURNS [poly: Polygon] = { -- use the front (linMesh.array[i][1]) polygon ignoring z ([3]) values. poly _ SVPolygon2d.CreatePoly[linMesh.len]; FOR i: NAT IN[1..linMesh.len] DO poly[i-1] _ [linMesh.array[i][1][1], linMesh.array[i][1][2]]; ENDLOOP; poly.len _ linMesh.len; }; -- end of GetLinearPoly GetRevolutePath: PUBLIC PROC [revMesh: RevoluteMesh] RETURNS [path: Path] = { -- ignore z values in the [i][revMesh.linesOfLongitude] elements path _ SVPolygon2d.CreatePath[revMesh.linesOfLatitude]; FOR i: NAT IN[1..revMesh.linesOfLatitude] DO path[i - 1] _ [revMesh.array[i][revMesh.linesOfLongitude][1], revMesh.array[i][revMesh.linesOfLongitude][2]]; ENDLOOP; path.len _ revMesh.linesOfLatitude; }; -- end of GetRevolutePath LineDrawLinearSweep: PUBLIC PROC [dc: Graphics.Context, meshRecord: LinearMesh, camera: Camera, localCS: CoordSystem] = { -- cx, cy: REAL; (to draw debugging numbers at vertices) IF meshRecord.len <= 0 THEN RETURN; CSGGraphics.SetCP[dc, meshRecord.array[1][1], camera, localCS]; -- First Point of front plane FOR i: NAT IN[2..meshRecord.len] DO -- Draw front plane CSGGraphics.DrawTo[dc, meshRecord.array[i][1], camera, localCS]; ENDLOOP; CSGGraphics.DrawTo[dc, meshRecord.array[1][1], camera, localCS]; CSGGraphics.SetCP[dc, meshRecord.array[1][2], camera, localCS]; -- First point of rear plane FOR i: NAT IN[2..meshRecord.len] DO -- Draw rear plane CSGGraphics.DrawTo[dc, meshRecord.array[i][2], camera, localCS]; ENDLOOP; CSGGraphics.DrawTo[dc, meshRecord.array[1][2], camera, localCS]; FOR i: NAT IN[1..meshRecord.len] DO -- Draw Lines between Planes CSGGraphics.SetCP[dc, meshRecord.array[i][1], camera, localCS]; CSGGraphics.DrawTo[dc, meshRecord.array[i][2], camera, localCS]; ENDLOOP; }; LineDrawRevoluteSweep: PUBLIC PROC [dc: Graphics.Context, meshRecord: RevoluteMesh, camera: Camera, localCS: CoordSystem] = { -- To draw a revolute sweep shape, we simple draw a line from each meshArray[i][j] to each four mesh neighbors meshArray[i-1][j], meshArray[i+1][j], meshArray[i][j-1], meshArray[i][j+1] with provision for wraparound at the extremes of j but not i. -- Draw Lines Of Latitude FOR lat: NAT IN [1..meshRecord.linesOfLatitude] DO CSGGraphics.SetCP[dc, meshRecord.array[lat][1], camera, localCS]; -- First point of this line of latitude FOR long: NAT IN[2..meshRecord.linesOfLongitude] DO CSGGraphics.DrawTo[dc, meshRecord.array[lat][long], camera, localCS]; ENDLOOP; -- Wrap around to first point of this line of latitude CSGGraphics.DrawTo[dc, meshRecord.array[lat][1], camera, localCS]; ENDLOOP; -- Draw Lines Of Longitude FOR long: NAT IN[1..meshRecord.linesOfLongitude] DO CSGGraphics.SetCP[dc, meshRecord.array[1][long], camera, localCS]; -- First point of this line of longitude FOR lat: NAT IN[1..meshRecord.linesOfLatitude] DO CSGGraphics.DrawTo[dc, meshRecord.array[lat][long], camera, localCS]; ENDLOOP; -- no wrap around for longitude ENDLOOP; }; LineDrawToroidalSweep: PUBLIC PROC [dc: Graphics.Context, meshRecord: ToroidalMesh, camera: Camera, localCS: CoordSystem] = { -- To draw a toroidal sweep shape, we simple draw a line from each meshArray[i][j] to each four mesh neighbors meshArray[i-1][j], meshArray[i+1][j], meshArray[i][j-1], meshArray[i][j+1] with provision for wraparound at the extremes of i and j. -- Draw Lines Of Latitude FOR lat: NAT IN [1..meshRecord.linesOfLatitude] DO CSGGraphics.SetCP[dc, meshRecord.array[lat][1], camera, localCS]; -- First point of this line of latitude FOR long: NAT IN[2..meshRecord.linesOfLongitude] DO CSGGraphics.DrawTo[dc, meshRecord.array[lat][long], camera, localCS]; ENDLOOP; -- Wrap around to first point of this line of latitude CSGGraphics.DrawTo[dc, meshRecord.array[lat][1], camera, localCS]; ENDLOOP; -- Draw Lines Of Longitude FOR long: NAT IN[1..meshRecord.linesOfLongitude] DO CSGGraphics.SetCP[dc, meshRecord.array[1][long], camera, localCS]; -- First point of this line of longitude FOR lat: NAT IN[1..meshRecord.linesOfLatitude] DO CSGGraphics.DrawTo[dc, meshRecord.array[lat][long], camera, localCS]; ENDLOOP; CSGGraphics.DrawTo[dc, meshRecord.array[1][long], camera, localCS]; ENDLOOP; }; -- end of LineDrawToroidalSweep AverageVertex: PRIVATE PROC [meshRecord: LinearMesh] RETURNS [pt: Point2d] = { pt _ [meshRecord.array[1][1][1], meshRecord.array[1][1][2]]; FOR i: NAT IN [1..meshRecord.len] DO pt[1] _ pt[1] + meshRecord.array[i][1][1]; pt[2] _ pt[2] + meshRecord.array[i][1][2]; ENDLOOP; pt[1] _ pt[1]/meshRecord.len; pt[2] _ pt[2]/meshRecord.len; }; DrawNormalsLinearSweep: PUBLIC PROC [dc: Graphics.Context, meshRecord: LinearMesh, camera: Camera, localCS: CoordSystem] = { thisNorm: Vector; upperLeftPoint, lowerRightPoint, midPoint: Point3d; iPlusOne: NAT; midPoint2d: Point2d; -- draw front vector thisNorm _ meshRecord.surfaces.front.normal; midPoint2d _ AverageVertex[meshRecord]; midPoint _ [midPoint2d[1], midPoint2d[2], meshRecord.array[1][1][3]]; Draw3d.DrawLocalVector[dc,thisNorm,midPoint,camera,localCS]; -- draw bottom vector thisNorm _ meshRecord.surfaces.back.normal; midPoint _ [midPoint2d[1], midPoint2d[2], meshRecord.array[1][2][3]]; Draw3d.DrawLocalVector[dc,thisNorm,midPoint,camera,localCS]; -- draw side vectors FOR i: NAT IN[1..meshRecord.len] DO iPlusOne _ IF i = meshRecord.len THEN 1 ELSE i + 1; thisNorm _ meshRecord.surfaces.sides[i].normal; upperLeftPoint _ meshRecord.array[iPlusOne][1]; lowerRightPoint _ meshRecord.array[i][2]; midPoint _ SVVector3d.Add[upperLeftPoint,lowerRightPoint]; midPoint _ SVVector3d.Scale[midPoint,0.5]; -- we have the normal in local coordinates. Draw3d.DrawLocalVector[dc,thisNorm,midPoint,camera,localCS]; ENDLOOP; }; -- end of DrawLinearNormals DrawNormalsRevoluteSweep: PUBLIC PROC [dc: Graphics.Context, meshRecord: RevoluteMesh, camera: Camera, localCS: CoordSystem] = { thisNorm: Vector; upperLeftPoint, lowerRightPoint, midPoint: Point3d; iPlusOne, jPlusOne: NAT; -- draw top normal thisNorm _ meshRecord.surfaces.top.normal; midPoint _ [0, meshRecord.array[1][1][2], 0]; Draw3d.DrawLocalVector[dc,thisNorm,midPoint,camera,localCS]; -- draw bottom normal thisNorm _ meshRecord.surfaces.bottom.normal; midPoint _ [0, meshRecord.array[meshRecord.linesOfLatitude][1][2], 0]; Draw3d.DrawLocalVector[dc,thisNorm,midPoint,camera,localCS]; -- draw the side normals FOR i: NAT IN[1..meshRecord.linesOfLatitude-1] DO iPlusOne _ i + 1; FOR j: NAT IN[1..meshRecord.linesOfLongitude] DO jPlusOne _ IF j = meshRecord.linesOfLongitude THEN 1 ELSE j + 1; thisNorm _ meshRecord.surfaces.sides[i][j].normal; upperLeftPoint _ meshRecord.array[i][j]; lowerRightPoint _ meshRecord.array[iPlusOne][jPlusOne]; midPoint _ SVVector3d.Add[upperLeftPoint,lowerRightPoint]; midPoint _ SVVector3d.Scale[midPoint,0.5]; -- we have the normal in local coordinates. Draw3d.DrawLocalVector[dc,thisNorm,midPoint,camera,localCS]; ENDLOOP; ENDLOOP; }; -- end of DrawNormalsRevoluteSweep DrawNormalsToroidalSweep: PUBLIC PROC [dc: Graphics.Context, meshRecord: ToroidalMesh, camera: Camera, localCS: CoordSystem] = {thisNorm: Vector; upperLeftPoint, lowerRightPoint, midPoint: Point3d; iPlusOne, jPlusOne: NAT; FOR i: NAT IN[1..meshRecord.linesOfLatitude] DO iPlusOne _ IF i = meshRecord.linesOfLatitude THEN 1 ELSE i + 1; FOR j: NAT IN[1..meshRecord.linesOfLongitude] DO jPlusOne _ IF j = meshRecord.linesOfLongitude THEN 1 ELSE j + 1; thisNorm _ meshRecord.surfaces.sides[i][j].normal; upperLeftPoint _ meshRecord.array[i][j]; lowerRightPoint _ meshRecord.array[iPlusOne][jPlusOne]; midPoint _ SVVector3d.Add[upperLeftPoint,lowerRightPoint]; midPoint _ SVVector3d.Scale[midPoint,0.5]; -- we have the normal in local coordinates. Draw3d.DrawLocalVector[dc,thisNorm,midPoint,camera,localCS]; ENDLOOP; ENDLOOP; }; -- end of DrawNormalsToroidalSweep CountPlanarSurfacesLinearSweep: PUBLIC PROC [meshRecord: LinearMesh] RETURNS [len: NAT] = { len _ meshRecord.len + 2; }; CountVerticesLinearSweep: PUBLIC PROC [meshRecord: LinearMesh] RETURNS [len: NAT] = { len _ 2*meshRecord.len; }; SortedLinearSurface: TYPE = REF SortedLinearSurfaceObj; SortedLinearSurfaceObj: TYPE = RECORD [post: NAT, meshRecord: LinearMesh]; PlanarSurfacesLinearSweep: PUBLIC PROC [meshRecord: LinearMesh, assembly: Assembly, cameraCS: CoordSystem] RETURNS [psl: PlanarSurfaceList] = { poly: Poly3d _ SVPolygon3d.CreatePoly[meshRecord.len]; iPlusOne: NAT; avgDepth: REAL; mo: MasterObject _ NARROW[assembly.object]; localCS: CoordSystem _ assembly.coordSys; thisSortedSurface: PlanarSurface; -- Top is [0]. Bottom is [len+1]. -- put front face on the list FOR i: NAT IN[1..meshRecord.len] DO poly _ SVPolygon3d.AddPolyPoint[poly, meshRecord.array[i][1]]; ENDLOOP; avgDepth _ AverageDepth[poly, localCS, cameraCS]; thisSortedSurface _ NEW[PlanarSurfaceObj _ [whichSurface: NEW[SortedLinearSurfaceObj _ [0, meshRecord]], assembly: assembly, normal: meshRecord.surfaces.front.normal, mo: mo, depth: avgDepth]]; psl _ CONS[thisSortedSurface, psl]; -- put back face on the list SVPolygon3d.ClearPoly[poly]; FOR i: NAT IN[1..meshRecord.len] DO poly _ SVPolygon3d.AddPolyPoint[poly, meshRecord.array[i][2]]; ENDLOOP; avgDepth _ AverageDepth[poly, localCS, cameraCS]; thisSortedSurface _ NEW[PlanarSurfaceObj _ [whichSurface: NEW[SortedLinearSurfaceObj _ [meshRecord.len+1, meshRecord]], assembly: assembly, normal: meshRecord.surfaces.back.normal, mo: mo, depth: avgDepth]]; psl _ CONS[thisSortedSurface, psl]; -- put side faces on the list FOR i: NAT IN[1..meshRecord.len] DO SVPolygon3d.ClearPoly[poly]; iPlusOne _ IF i = meshRecord.len THEN 1 ELSE i + 1; poly _ SVPolygon3d.AddPolyPoint[poly, meshRecord.array[i][1]]; poly _ SVPolygon3d.AddPolyPoint[poly, meshRecord.array[i][2]]; poly _ SVPolygon3d.AddPolyPoint[poly, meshRecord.array[iPlusOne][2]]; poly _ SVPolygon3d.AddPolyPoint[poly, meshRecord.array[iPlusOne][1]]; avgDepth _ AverageDepth[poly,localCS, cameraCS]; thisSortedSurface _ NEW[PlanarSurfaceObj _ [whichSurface: NEW[SortedLinearSurfaceObj _ [i, meshRecord]], assembly: assembly, normal: meshRecord.surfaces.sides[i].normal, mo: mo, depth: avgDepth]]; psl _ CONS[thisSortedSurface, psl]; ENDLOOP; }; -- end of PlanarSurfacesLinearSweep DrawPlanarSurfaceLinearSweep: PUBLIC PROC [dc: Graphics.Context, ps: PlanarSurface, lightSources: LightSourceList, camera: Camera] = { poly3d: Poly3d; post, postPlusOne: NAT; avgDepth: REAL; meshRecord: LinearMesh; thisLinSurface: SortedLinearSurface; localCS: CoordSystem; thisLinSurface _ NARROW[ps.whichSurface]; meshRecord _ thisLinSurface.meshRecord; localCS _ ps.assembly.coordSys; post _ thisLinSurface.post; avgDepth _ ps.depth; SELECT post FROM 0 => {-- draw front face poly3d _ SVPolygon3d.CreatePoly[meshRecord.len]; FOR i: NAT IN[1..meshRecord.len] DO poly3d _ SVPolygon3d.AddPolyPoint[poly3d, meshRecord.array[i][1]]; ENDLOOP; CSGGraphics.DrawAreaNormalAbsolute[dc, ps.normal, poly3d, ps.assembly.artwork, lightSources, camera, localCS]; }; meshRecord.len + 1 => { -- draw back face poly3d _ SVPolygon3d.CreatePoly[meshRecord.len]; FOR i: NAT IN[1..meshRecord.len] DO poly3d _ SVPolygon3d.AddPolyPoint[poly3d, meshRecord.array[i][2]]; ENDLOOP; CSGGraphics.DrawAreaNormalAbsolute[dc, ps.normal, poly3d, ps.assembly.artwork, lightSources, camera, localCS]; }; IN [1..meshRecord.len] => {-- draw side face poly3d _ SVPolygon3d.CreatePoly[4]; postPlusOne _ IF post = meshRecord.len THEN 1 ELSE post + 1; poly3d _ SVPolygon3d.AddPolyPoint[poly3d, meshRecord.array[post][1]]; poly3d _ SVPolygon3d.AddPolyPoint[poly3d, meshRecord.array[post][2]]; poly3d _ SVPolygon3d.AddPolyPoint[poly3d, meshRecord.array[postPlusOne][2]]; poly3d _ SVPolygon3d.AddPolyPoint[poly3d, meshRecord.array[postPlusOne][1]]; CSGGraphics.DrawAreaNormalAbsolute[dc, ps.normal, poly3d, ps.assembly.artwork, lightSources, camera, localCS]; }; ENDCASE => ERROR; }; -- end of DrawPlanarSurfaceLinearSweep MaxDepth: PROC [poly: Poly3d] RETURNS [maxDepth: REAL] = { maxDepth _ poly[0][3]; FOR i: NAT IN[1..poly.len) DO IF poly[i][3] < maxDepth THEN maxDepth _ poly[i][3]; ENDLOOP; }; AverageDepth: PROC [poly: Poly3d, localCS, camera: CoordSystem] RETURNS [avgDepth: REAL] = { sum: REAL _ 0; realLen: REAL _ poly.len; localPoint: Point3d; FOR i: NAT IN[0..poly.len) DO localPoint _ poly[i]; localPoint _ CSGGraphics.LocalToCamera[localPoint, localCS]; sum _ sum + localPoint[3]; ENDLOOP; avgDepth _ sum/realLen; }; SortedRevoluteSurface: TYPE = REF SortedRevoluteSurfaceObj; SortedRevoluteSurfaceObj: TYPE = RECORD [lat, long: NAT, meshRecord: RevoluteMesh]; CountPlanarSurfacesRevoluteSweep: PUBLIC PROC [meshRecord: RevoluteMesh] RETURNS [len: NAT] = { len _ (meshRecord.linesOfLongitude)*(meshRecord.linesOfLatitude-1) + 2; }; CountVerticesRevoluteSweep: PUBLIC PROC [meshRecord: RevoluteMesh] RETURNS [len: NAT] = { len _ meshRecord.linesOfLongitude*meshRecord.linesOfLatitude; }; PlanarSurfacesRevoluteSweep: PUBLIC PROC [meshRecord: RevoluteMesh, assembly: Assembly, cameraCS: CoordSystem] RETURNS [psl: PlanarSurfaceList] = { poly3d: Poly3d _ SVPolygon3d.CreatePoly[meshRecord.linesOfLongitude]; avgDepth: REAL; thisSortedSurface: PlanarSurface; mo: MasterObject _ NARROW[assembly.object]; jPlusOne: NAT; localCS: CoordSystem _ assembly.coordSys; psl _ NIL; -- Put the top surface on the list SVPolygon3d.ClearPoly[poly3d]; FOR j: NAT IN[1..meshRecord.linesOfLongitude] DO poly3d _ SVPolygon3d.AddPolyPoint[poly3d, meshRecord.array[1][j]]; ENDLOOP; avgDepth _ AverageDepth[poly3d, localCS,cameraCS]; thisSortedSurface _ NEW[PlanarSurfaceObj _ [whichSurface: NEW[SortedRevoluteSurfaceObj _ [0,0,meshRecord]], assembly: assembly, normal: meshRecord.surfaces.top.normal, mo: mo, depth: avgDepth]]; psl _ CONS[thisSortedSurface, psl]; -- Put the bottom surface on the list SVPolygon3d.ClearPoly[poly3d]; FOR j: NAT IN[1..meshRecord.linesOfLongitude] DO poly3d _ SVPolygon3d.AddPolyPoint[poly3d, meshRecord.array[meshRecord.linesOfLatitude][j]]; ENDLOOP; avgDepth _ AverageDepth[poly3d, localCS, cameraCS]; thisSortedSurface _ NEW[PlanarSurfaceObj _ [whichSurface: NEW[SortedRevoluteSurfaceObj _ [meshRecord.linesOfLatitude,0,meshRecord]], assembly: assembly, normal: meshRecord.surfaces.bottom.normal, mo: mo, depth: avgDepth]]; psl _ CONS[thisSortedSurface, psl]; -- Put side surfaces on the list FOR i: NAT IN[1..meshRecord.linesOfLatitude-1] DO FOR j: NAT IN[1..meshRecord.linesOfLongitude] DO SVPolygon3d.ClearPoly[poly3d]; jPlusOne _ IF j = meshRecord.linesOfLongitude THEN 1 ELSE j + 1; poly3d _ SVPolygon3d.AddPolyPoint[poly3d, meshRecord.array[i][j]]; poly3d _ SVPolygon3d.AddPolyPoint[poly3d, meshRecord.array[i][jPlusOne]]; poly3d _ SVPolygon3d.AddPolyPoint[poly3d, meshRecord.array[i+1][jPlusOne]]; poly3d _ SVPolygon3d.AddPolyPoint[poly3d, meshRecord.array[i+1][j]]; avgDepth _ AverageDepth[poly3d, localCS, cameraCS]; thisSortedSurface _ NEW[PlanarSurfaceObj _ [whichSurface: NEW[SortedRevoluteSurfaceObj _ [i,j,meshRecord]], assembly: assembly, normal: meshRecord.surfaces.sides[i][j].normal, mo: mo, depth: avgDepth]]; psl _ CONS[thisSortedSurface, psl]; ENDLOOP; ENDLOOP; }; -- end of PlanarSurfacesRevoluteSweep DrawPlanarSurfaceRevoluteSweep: PUBLIC PROC [dc: Graphics.Context, ps: PlanarSurface, lightSources: LightSourceList, camera: Camera] = { thisRevSurface: SortedRevoluteSurface; meshRecord: RevoluteMesh; lat, long, longPlusOne: NAT; poly3d: Poly3d; avgDepth: REAL; localCS: CoordSystem; thisRevSurface _ NARROW[ps.whichSurface]; meshRecord _ thisRevSurface.meshRecord; localCS _ ps.assembly.coordSys; lat _ thisRevSurface.lat; long _ thisRevSurface.long; -- we have surface [lat][long] avgDepth _ ps.depth; IF long = 0 THEN -- either top or bottom surface {IF lat = 0 THEN -- top surface -- Draw the top surface {poly3d _ SVPolygon3d.CreatePoly[meshRecord.linesOfLongitude]; FOR j: NAT IN[1..meshRecord.linesOfLongitude] DO poly3d _ SVPolygon3d.AddPolyPoint[poly3d, meshRecord.array[1][j]]; ENDLOOP; CSGGraphics.DrawAreaNormalAbsolute[dc, ps.normal, poly3d, ps.assembly.artwork, lightSources, camera, localCS]} ELSE -- Draw the bottom surface {poly3d _ SVPolygon3d.CreatePoly[meshRecord.linesOfLongitude]; FOR j: NAT IN[1..meshRecord.linesOfLongitude] DO poly3d _ SVPolygon3d.AddPolyPoint[poly3d, meshRecord.array[meshRecord.linesOfLatitude][j]]; ENDLOOP; CSGGraphics.DrawAreaNormalAbsolute[dc, ps.normal, poly3d, ps.assembly.artwork, lightSources, camera, localCS]}; } ELSE {-- Draw the side face poly3d _ SVPolygon3d.CreatePoly[4]; longPlusOne _ IF long = meshRecord.linesOfLongitude THEN 1 ELSE long + 1; poly3d _ SVPolygon3d.AddPolyPoint[poly3d, meshRecord.array[lat][long]]; poly3d _ SVPolygon3d.AddPolyPoint[poly3d, meshRecord.array[lat][longPlusOne]]; poly3d _ SVPolygon3d.AddPolyPoint[poly3d, meshRecord.array[lat+1][longPlusOne]]; poly3d _ SVPolygon3d.AddPolyPoint[poly3d, meshRecord.array[lat+1][long]]; CSGGraphics.DrawAreaNormalAbsolute[dc, ps.normal, poly3d, ps.assembly.artwork, lightSources, camera, localCS]; }; }; -- end of DrawPlanarSurfaceRevoluteSweep SortedToroidalSurface: TYPE = REF SortedToroidalSurfaceObj; SortedToroidalSurfaceObj: TYPE = RECORD [lat, long: NAT, meshRecord: ToroidalMesh]; CountPlanarSurfacesToroidalSweep: PUBLIC PROC [meshRecord: ToroidalMesh] RETURNS [len: NAT] = { len _ (meshRecord.linesOfLongitude)*(meshRecord.linesOfLatitude); }; CountVerticesToroidalSweep: PUBLIC PROC [meshRecord: ToroidalMesh] RETURNS [len: NAT] = { len _ meshRecord.linesOfLongitude*meshRecord.linesOfLatitude; }; PlanarSurfacesToroidalSweep: PUBLIC PROC [meshRecord: ToroidalMesh, assembly: Assembly, cameraCS: CoordSystem] RETURNS [psl: PlanarSurfaceList] = { iPlusOne, jPlusOne: NAT; poly3d: Poly3d _ SVPolygon3d.CreatePoly[4]; avgDepth: REAL; mo: MasterObject _ NARROW[assembly.object]; localCS: CoordSystem _ assembly.coordSys; thisSortedSurface: PlanarSurface; -- Put side surfaces on the list FOR i: NAT IN[1..meshRecord.linesOfLatitude] DO iPlusOne _ IF i = meshRecord.linesOfLatitude THEN 1 ELSE i + 1; FOR j: NAT IN[1..meshRecord.linesOfLongitude] DO SVPolygon3d.ClearPoly[poly3d]; jPlusOne _ IF j = meshRecord.linesOfLongitude THEN 1 ELSE j + 1; poly3d _ SVPolygon3d.AddPolyPoint[poly3d, meshRecord.array[i][j]]; poly3d _ SVPolygon3d.AddPolyPoint[poly3d, meshRecord.array[i][jPlusOne]]; poly3d _ SVPolygon3d.AddPolyPoint[poly3d, meshRecord.array[iPlusOne][jPlusOne]]; poly3d _ SVPolygon3d.AddPolyPoint[poly3d, meshRecord.array[iPlusOne][j]]; avgDepth _ AverageDepth[poly3d, localCS, cameraCS]; thisSortedSurface _ NEW[PlanarSurfaceObj _ [whichSurface: NEW[SortedToroidalSurfaceObj _ [i,j,meshRecord]], assembly: assembly, normal: meshRecord.surfaces.sides[i][j].normal, mo: mo, depth: avgDepth]]; psl _ CONS[thisSortedSurface, psl]; ENDLOOP; ENDLOOP; }; -- end of PlanarSurfacesToroidalSweep DrawPlanarSurfaceToroidalSweep: PUBLIC PROC [dc: Graphics.Context, ps: PlanarSurface, lightSources: LightSourceList, camera: Camera] = { lat, long, longPlusOne, latPlusOne: NAT; poly3d: Poly3d _ SVPolygon3d.CreatePoly[4]; avgDepth: REAL; localCS: CoordSystem; meshRecord: ToroidalMesh; thisTorSurface: SortedToroidalSurface; thisTorSurface _ NARROW[ps.whichSurface]; localCS _ ps.assembly.coordSys; meshRecord _ thisTorSurface.meshRecord; lat _ thisTorSurface.lat; long _ thisTorSurface.long; -- we have surface [lat][long] avgDepth _ ps.depth; -- Draw the side face latPlusOne _ IF lat = meshRecord.linesOfLatitude THEN 1 ELSE lat + 1; longPlusOne _ IF long = meshRecord.linesOfLongitude THEN 1 ELSE long + 1; poly3d _ SVPolygon3d.AddPolyPoint[poly3d, meshRecord.array[lat][long]]; poly3d _ SVPolygon3d.AddPolyPoint[poly3d, meshRecord.array[lat][longPlusOne]]; poly3d _ SVPolygon3d.AddPolyPoint[poly3d, meshRecord.array[latPlusOne][longPlusOne]]; poly3d _ SVPolygon3d.AddPolyPoint[poly3d, meshRecord.array[latPlusOne][long]]; CSGGraphics.DrawAreaNormalAbsolute[dc, ps.normal, poly3d, ps.assembly.artwork, lightSources, camera, localCS]; }; -- end of DrawPlanarSurfaceToroidalSweep END. Κ ‚– "Mesa" style˜procšγΟcτœΟk œ²žœžœEžœžœ žœžœžœžœ#žœžœžœ#žœžœ%žœ1žœžœ)žœ3žœžœ)žœ3žœžœ!žœ,žœžœžœžœžœ#žœ(žœžœžœžœžœžœžœžœžœ+žœžœžœ(žœžœ%žœ6žœBžœžœΟn œžœžœžœžœ žœTžœžœžœ#žœ6žœžœžœžœžœžœžœžœžœažœ\žœ!9œ`œ:œžœžœžœx]œaœ[œžœžœžœžœžœžœžœ­žœœŸ œžœžœ žœžœ^žœžœ žœmœaœžœžœžœžœžœžœžœžœžœ#žœa7œ8žœžœžœžœžœžœžœžœžœ‘œ žœœœ2œ.'œžœœžœœ\fœ\œ]$œYœKœQœžœžœžœžœžœžœžœžœžœžœžœΰžœžœœŸ œžœžœ#žœžœ^žœžœžœaœžœžœžœžœžœžœžœžœžœ#žœ)7œ8žœžœžœžœžœžœžœžœžœ‘œ žœœœ2œ.'œžœœžœœ\fœœYœKœQœžœžœžœžœžœžœžœ žœžœžœžœžœžœžœκžœžœœŸ œžœžœžœHœ.žœžœžœžœBžœœŸœžœžœžœAœ:žœžœžœžœyžœ+œŸœžœžœ[9œžœžœžœCœžœžœžœžœ˜ΗMJšœDžœC˜Ž—š œDœžœžœžœžœ˜™JšœDžœB˜—KšœžœžœžœžœœŠžœ Ÿœžœžœ]ψœœžœžœžœ!žœE(œžœžœžœ!žœLžœ7œHžœœžœžœžœ!žœF)œžœžœžœ žœLžœ œžœŸœžœžœ]τœœžœžœžœ!žœE(œžœžœžœ!žœLžœ7œFžœœžœžœžœ!žœF)œžœžœžœ žœLžœIžœ œŸ œžœžœžœRžœžœžœžœ\žœEŸœžœžœ­žœœέœ³œžœžœžœžœžœžœžœ„,œ@žœœŸœžœžœΉžœœšœΆœžœžœžœ"žœžœžœžœ!žœžœ!žœžœ”,œBžœžœ#œŸœžœžœ·žœžœžœžœ žœžœ žœžœ žœžœžœ!žœžœ!žœžœ”,œBžœžœ#œŸœžœžœžœžœ%Ÿœžœžœžœžœ:žœžœ1žœžœžœŸœžœžœEžœbžœ žœžœb#œœžœžœžœžœCžœJžœ&žœœžœœžœžœžœžœCžœJžœ&žœͺžœœžœžœžœžœ-žœžœžœγžœ&žœŸžœžœ$œŸœžœžœ„žœ žœlžœ“žœžœ œ6žœžœžœžœKžœ‘œ7žœžœžœžœKžœ{žœœ6žœžœžœ°žœžœ'œŸœžœžœ žœžœžœžœžœžœžœžœŸ œžœ.žœ žœ žœžœ$žœžœžœžœvžœ8žœžœ5žœžœ žœŸ œžœžœžœžœUŸœžœžœžœžœJŸœžœžœGžœpžœ9žœžœ6žœ#œ!žœžœžœ!žœGžœKžœ&žœžœ&œ!žœžœžœ!žœcžœLžœ&žœΎžœ!œžœžœžœ"žœžœžœžœ!žœ1žœ!žœžœ€žœ(žœ―žœžœžœ&œŸœžœžœΊžœžœ+žœ•œžœ žœ œžœ žœœœFžœžœžœ!žœMžœvžœœFžœžœžœ!žœlžœzžœœ8žœ$žœžœΔ)œžœžœ5žœžœ žœŸ œžœžœžœžœPŸœžœžœžœžœKŸœžœžœGžœ3žœ:žœžœf!œžœžœžœ žœžœ žœžœ žœžœžœ!žœ1žœ!žœžœŠžœ(žœ―žœžœžœ&œŸœžœžœƒžœ:žœnžœ•œœžœ"žœžœžœ$žœžœΏ)œžœ˜••—…—s}ž