File: SVHalfSpacesImpl.mesa
Author: Eric Bier on August 12, 1983 1:58 pm
Copyright © 1984 by Xerox Corporation. All rights reserved.
Last edited by Bier: January 9, 1985 3:52:12 pm PST
Contents: Implementation of the half-space object class
DIRECTORY
CastRays,
CSG,
CSGGraphics,
DisplayList3d,
Graphics,
IO,
Rope,
SV2d,
SV3d,
SVDraw3d,
SVHalfSpaces,
SVPolygon3d,
SVModelTypes,
SVRayTypes,
SVSceneTypes,
TFI3d;
SVHalfSpacesImpl:
PROGRAM
IMPORTS CastRays, CSG, CSGGraphics, DisplayList3d, IO, SVDraw3d, SVPolygon3d, TFI3d
EXPORTS SVHalfSpaces =
BEGIN
Assembly: TYPE = SVSceneTypes.Assembly;
BoundHedron: TYPE = SVModelTypes.BoundHedron;
CoordSystem: TYPE = SVModelTypes.CoordSystem;
Classification: TYPE = SVRayTypes.Classification;
LightSourceList: TYPE = SVModelTypes.LightSourceList;
Point2d: TYPE = SV2d.Point2d;
Ray: TYPE = SVRayTypes.Ray;
PlanarSurface: TYPE = REF PlanarSurfaceObj;
PlanarSurfaceObj: TYPE = SVSceneTypes.PlanarSurfaceObj;
PlanarSurfaceList: TYPE = SVSceneTypes.PlanarSurfaceList;
Plane: TYPE = SV3d.Plane;
Point3d: TYPE = SV3d.Point3d;
Poly3d: TYPE = SV3d.Poly3d;
Camera: TYPE = SVModelTypes.Camera;
MasterObjectClass: TYPE = SVSceneTypes.MasterObjectClass;
MasterObject: TYPE = SVSceneTypes.MasterObject;
Primitive: TYPE = SVRayTypes.Primitive;
Shape: TYPE = SVSceneTypes.Shape;
Surface: TYPE = REF ANY;
Vector: TYPE = SV3d.Vector;
BASIC SHAPES
HalfSpaceRec: TYPE = REF HalfSpaceRecObj;
HalfSpaceRecObj: TYPE = SVHalfSpaces.HalfSpaceRecObj;
PlaneSurface: TYPE = REF PlaneSurfaceObj;
PlaneSurfaceObj: TYPE = SVHalfSpaces.PlaneSurfaceObj;
SortedHalfSpaceSurface: TYPE = REF SortedHalfSpaceSurfaceObj;
SortedHalfSpaceSurfaceObj: TYPE = RECORD [i, j: INT];
halfSpaceClass: MasterObjectClass;
HalfSpaceBody:
PRIVATE
PROC
RETURNS [halfSpaceRec: HalfSpaceRec] = {
halfSpaceRec ← NEW[HalfSpaceRecObj];
halfSpaceRec.gridSide ← 72.0;
};
HalfSpaceMakeMasterObject:
PUBLIC
PROC [name: Rope.
ROPE]
RETURNS [mo: MasterObject] = {
mainBody: HalfSpaceRec ← HalfSpaceBody[];
lineBody: REF ANY ← mainBody;
shadeBody: REF ANY ← mainBody;
rayCastBody: REF ANY ← HalfSpaceGetRayCastBody[];
mo ← DisplayList3d.CreateMasterObject[name, halfSpaceClass, mainBody, lineBody, shadeBody, rayCastBody];
};
HalfSpaceBoundHedron:
PUBLIC
PROC [mo: MasterObject]
RETURNS [hedron: BoundHedron] = {
hedron ← NIL;
};
HalfSpaceGetRayCastBody:
PRIVATE
PROC []
RETURNS [planeS: PlaneSurface] = {
planeS ← NEW[PlaneSurfaceObj];
};
HalfSpaceRayCast:
PUBLIC
PROC [cameraPoint: Point2d, localRay: Ray, masterObject:
REF
ANY, prim: Primitive]
RETURNS [class: Classification] = {
mo: MasterObject ← NARROW[masterObject];
RETURN[HalfSpaceCastAux[localRay, NARROW[mo.rayCastBody], prim]];
};
HalfSpaceCastAux:
PRIVATE
PROC [localRay: Ray, plane: Surface, prim: Primitive]
RETURNS [class: Classification] = {
Do one ray-plane intersection test.
The half space ends at the xz plane (i.e. the plane with equation y = 0.
Ray parameterization is R = p + t*d. For y, this is:
y[t] = p[2]+t*d[2].
If d has no y component, this has no solution. Otherwise, we find t = -p[2]/d[2]. Check to see which side of the plane the ray originates on. Check to see that t is positive.
almostZero: REAL ← 1.0e-12;
t: REAL;
rayStartsOut: BOOL;
p: Point3d;
d: Vector;
class ← CastRays.GetClassFromPool[];
[p, d] ← CSG.GetLocalRay[localRay];
rayStartsOut ← p[2] >0;
IF Abs[d[2]] > almostZero
THEN {
t ← -p[2]/d[2];
IF t > 0
THEN {
The ray hits the plane.
class.count ← 1;
class.params[1] ← t;
class.surfaces[1] ← plane;
class.normals[1] ← [0,1,0];
class.primitives[1] ← prim;
IF rayStartsOut
THEN {
class.classifs[1] ← FALSE;
class.classifs[2] ← TRUE;
}
ELSE {
class.classifs[1] ← TRUE;
class.classifs[2] ← FALSE;
};
}
ELSE {
The plane is behind the ray.
class.count ← 0;
class.classifs[1] ← NOT rayStartsOut;
};
}
ELSE {
Ray is functionally parallel to the plane. If ray starts in the plane, this is a hit, but with a count of 0. Else, a complete miss.
class.count ← 0;
IF rayStartsOut THEN class.classifs[1] ← FALSE
ELSE class.classifs[1] ← TRUE;
};
}; -- end of HalfSpaceCastAux
Abs:
PROC [r:
REAL]
RETURNS [
REAL] = {
RETURN[IF r >= 0 THEN r ELSE -r];
};
HalfSpaceRayCastNoBBoxes:
PUBLIC
PROC [localRay: Ray, masterObject:
REF
ANY, prim: Primitive]
RETURNS [class: Classification] = {
mo: MasterObject ← NARROW[masterObject];
RETURN[HalfSpaceCastAux[localRay, NARROW[mo.rayCastBody], prim]];
};
HalfSpaceRayCastBoundingSpheres:
PUBLIC
PROC [localRay: Ray, masterObject:
REF
ANY, prim: Primitive]
RETURNS [class: Classification] = {
mo: MasterObject ← NARROW[masterObject];
RETURN[HalfSpaceCastAux[localRay, NARROW[mo.rayCastBody], prim]];
};
HalfSpaceFancyLineDraw:
PRIVATE
PROC[dc: Graphics.Context, data:
REF
ANY, camera: Camera, localCS: CoordSystem] = {
halfSpaceRec: HalfSpaceRec ← NARROW[data];
gridSide: REAL ← halfSpaceRec.gridSide;
plane: Plane ← SVPolygon3d.PlaneFromCoefficients[0,1,0,0];
CSGGraphics.DrawInfiniteLine[dc, [0,0,0], [1,0,0], camera, localCS];
CSGGraphics.DrawInfiniteLine[dc, [0,0,gridSide], [1,0,gridSide], camera, localCS];
CSGGraphics.DrawInfiniteLine[dc, [0,0,-gridSide], [1,0,-gridSide], camera, localCS];
CSGGraphics.DrawInfiniteLine[dc, [0,0,0], [0,0,1], camera, localCS];
CSGGraphics.DrawInfiniteLine[dc, [gridSide,0,0], [gridSide,0,1], camera, localCS];
CSGGraphics.DrawInfiniteLine[dc, [-gridSide,0,0], [-gridSide,0,1], camera, localCS];
CSGGraphics.DrawHorizonOfPlane[dc, plane, camera, localCS];
};
HalfSpaceLineDraw:
PUBLIC
PROC[dc: Graphics.Context, data:
REF
ANY, camera: Camera, localCS: CoordSystem] = {
halfSpaceRec: HalfSpaceRec ← NARROW[data];
gridSide: REAL ← halfSpaceRec.gridSide;
lineLen: REAL ← 100.0;
CSGGraphics.DrawLine[dc, [-lineLen,0,0], [lineLen,0,0], camera, localCS];
CSGGraphics.DrawLine[dc, [-lineLen,0,gridSide], [lineLen,0,gridSide], camera, localCS];
CSGGraphics.DrawLine[dc, [-lineLen,0,-gridSide], [lineLen,0,-gridSide], camera, localCS];
CSGGraphics.DrawLine[dc, [0,0,-lineLen], [0,0,lineLen], camera, localCS];
CSGGraphics.DrawLine[dc, [gridSide,0,-lineLen], [gridSide,0,lineLen], camera, localCS];
CSGGraphics.DrawLine[dc, [-gridSide,0,-lineLen], [-gridSide,0,lineLen], camera, localCS];
};
HalfSpaceDrawNormals:
PUBLIC
PROC[dc: Graphics.Context, data:
REF
ANY, camera: Camera, localCS: CoordSystem] = {
SVDraw3d.DrawLocalVector[dc, [0,1,0], [0,0,0], camera, localCS];
};
HalfSpaceCountSurf:
PUBLIC
PROC [masterObject: MasterObject]
RETURNS [len:
NAT] = {
len ← 4;
};
HalfSpaceCountVert:
PUBLIC
PROC [masterObject: MasterObject]
RETURNS [len:
NAT] = {
len ← 9;
};
HalfSpaceGetSurf: PUBLIC PROC [assembly: Assembly, camera: CoordSystem] RETURNS [psl: PlanarSurfaceList] = {
mo: MasterObject ← NARROW[assembly.shape, Shape].mo;
midPoint: Point3d ← CSGGraphics.LocalToCamera[[0,0,0], assembly.coordSys];
surface: PlanarSurface;
depth: REAL ← midPoint[3];
surface ← NEW[PlanarSurfaceObj ← [
NIL, assembly, mo, [0,1,0], depth]];
psl ← LIST[surface];
};
AverageDepthInCamera:
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;
};
HalfSpaceGetSurf:
PUBLIC
PROC [assembly: Assembly, camera: CoordSystem]
RETURNS [psl: PlanarSurfaceList] = {
poly: Poly3d ← SVPolygon3d.CreatePoly[4];
avgDepth: REAL;
shape: Shape ← NARROW[assembly.shape, Shape];
mo: MasterObject ← shape.mo;
localCS: CoordSystem ← shape.coordSys;
thisSortedSurface: PlanarSurface;
halfSpaceRec: HalfSpaceRec ← NARROW[mo.shadeBody];
gridSide: REAL ← halfSpaceRec.gridSide;
FOR i:
INT
IN [-1..0]
DO
FOR j:
INT
IN [-1..0]
DO
poly ← SVPolygon3d.AddPolyPoint[poly, [i*gridSide, 0, j*gridSide]];
poly ← SVPolygon3d.AddPolyPoint[poly, [i*gridSide, 0, (j+1)*gridSide]];
poly ← SVPolygon3d.AddPolyPoint[poly, [(i+1)*gridSide, 0, (j+1)*gridSide]];
poly ← SVPolygon3d.AddPolyPoint[poly, [(i+1)*gridSide, 0, j*gridSide]];
avgDepth ← AverageDepthInCamera[poly, localCS, camera];
thisSortedSurface ←
NEW[PlanarSurfaceObj ← [
whichSurface: NEW[SortedHalfSpaceSurfaceObj ← [i,j]],
assembly: assembly,
normal: [0,1,0],
mo: mo,
depth: avgDepth]];
psl ← CONS[thisSortedSurface, psl];
SVPolygon3d.ClearPoly[poly];
ENDLOOP;
ENDLOOP;
};
HalfSpaceDrawSurf: PUBLIC PROC [dc: Graphics.Context, ps: PlanarSurface, lightSources: LightSourceList, camera: Camera] = {
localCS: CoordSystem;
plane: Plane ← SVPolygon3d.PlaneFromCoefficients[0,1,0,0];
localCS ← ps.assembly.coordSys;
CSGGraphics.DrawInfinitePlaneShaded[dc, plane, ps.assembly.artwork, lightSources, camera, localCS];
};
HalfSpaceDrawSurf:
PUBLIC
PROC [dc: Graphics.Context, ps: PlanarSurface, lightSources: LightSourceList, camera: Camera] = {
i, j: INT;
poly: Poly3d ← SVPolygon3d.CreatePoly[4];
avgDepth: REAL;
shape: Shape;
localCS: CoordSystem;
thisHalfSpaceSurface: SortedHalfSpaceSurface;
mo: MasterObject;
halfSpaceRec: HalfSpaceRec;
gridSide: REAL;
thisHalfSpaceSurface ← NARROW[ps.whichSurface];
shape ← NARROW[ps.assembly.shape];
mo ← shape.mo;
halfSpaceRec ← NARROW[mo.shadeBody];
gridSide ← halfSpaceRec.gridSide;
localCS ← shape.coordSys;
i ← thisHalfSpaceSurface.i;
j ← thisHalfSpaceSurface.j;
avgDepth ← ps.depth;
poly ← SVPolygon3d.AddPolyPoint[poly, [i*gridSide, 0, j*gridSide]];
poly ← SVPolygon3d.AddPolyPoint[poly, [i*gridSide, 0, (j+1)*gridSide]];
poly ← SVPolygon3d.AddPolyPoint[poly, [(i+1)*gridSide, 0, (j+1)*gridSide]];
poly ← SVPolygon3d.AddPolyPoint[poly, [(i+1)*gridSide, 0, j*gridSide]];
CSGGraphics.DrawAreaNormalAbsolute[dc, ps.normal, poly, ps.assembly.artwork, lightSources, camera, localCS];
};
HalfSpaceFileout:
PUBLIC
PROC [f:
IO.
STREAM, mo: MasterObject] = {
HalfSpaces can be recovered from scratch.
f.PutChar[IO.TAB];
f.PutF["data: procedural\n"];
};
HalfSpaceFilein:
PUBLIC
PROC [f:
IO.
STREAM, name: Rope.
ROPE]
RETURNS [mo: MasterObject] = {
TFI3d.ReadRope[f, "data: procedural"];
TFI3d.ReadBlank[f];
mo ← HalfSpaceMakeMasterObject[name];
};
Init:
PROC = {
halfSpace: MasterObject;
halfSpaceClass ← DisplayList3d.RegisterMasterObjectClass[
"halfSpace",
HalfSpaceFilein,
HalfSpaceFileout,
DisplayList3d.NoOpFileoutPoly,
HalfSpaceRayCast,
HalfSpaceRayCastNoBBoxes,
HalfSpaceRayCastBoundingSpheres,
HalfSpaceBoundHedron,
DisplayList3d.NoOpPreprocess,
HalfSpaceLineDraw,
HalfSpaceDrawNormals,
HalfSpaceCountSurf,
HalfSpaceGetSurf,
HalfSpaceDrawSurf,
DisplayList3d.NoOpDrawSubBoxes,
DisplayList3d.NoOpDrawSubSpheres];
halfSpace ← HalfSpaceMakeMasterObject["halfSpace"];
DisplayList3d.RegisterMasterObject[halfSpace];
};
Init[];
END.