-- 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.