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: June 30, 1987 4:07:39 pm PDT
Contents: Implementation of the half-space object class
DIRECTORY
CoordSys, Imager, IO, Rope, SV2d, SV3d, SVBasicTypes, SVCastRays, SVDraw3d, SVGraphics, SVHalfSpaces, SVMasterObject, SVModelTypes, SVPolygon3d, SVRay, SVScene, SVSceneTypes, TFI3d;
SVHalfSpacesImpl:
CEDAR PROGRAM
IMPORTS CoordSys, SVCastRays, SVRay, SVGraphics, IO, SVDraw3d, SVMasterObject, SVPolygon3d, SVScene, TFI3d
EXPORTS SVHalfSpaces =
BEGIN
Slice: TYPE = SVSceneTypes.Slice;
SliceDescriptor: TYPE = SVSceneTypes.SliceDescriptor;
BoundHedron: TYPE = SVBasicTypes.BoundHedron;
CoordSystem: TYPE = SVModelTypes.CoordSystem;
Classification: TYPE = SVSceneTypes.Classification;
LightSourceList: TYPE = SVModelTypes.LightSourceList;
Point2d: TYPE = SV2d.Point2d;
Ray: TYPE = SVSceneTypes.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;
MasterObjectClassObj: TYPE = SVSceneTypes.MasterObjectClassObj;
MasterObject: TYPE = SVSceneTypes.MasterObject;
Primitive: TYPE = SVSceneTypes.Primitive;
Shape: TYPE = SVSceneTypes.Shape;
Surface: TYPE = REF ANY;
Vector3d: TYPE = SV3d.Vector3d;
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 ← SVScene.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, sliceD: SliceDescriptor, prim: Primitive]
RETURNS [class: Classification] = {
mo: MasterObject ← prim.mo;
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: Vector3d;
class ← SVCastRays.GetClassFromPool[];
[p, d] ← SVRay.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] ← d[2] < 0; -- the ray is heading into the half-space.
};
}
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, sliceD: SliceDescriptor, prim: Primitive]
RETURNS [class: Classification] = {
mo: MasterObject ← prim.mo;
RETURN[HalfSpaceCastAux[localRay, NARROW[mo.rayCastBody], prim]];
};
HalfSpaceRayCastBoundingSpheres:
PUBLIC
PROC [localRay: Ray, sliceD: SliceDescriptor, prim: Primitive]
RETURNS [class: Classification] = {
mo: MasterObject ← prim.mo;
RETURN[HalfSpaceCastAux[localRay, NARROW[mo.rayCastBody], prim]];
};
HalfSpaceFancyLineDraw:
PRIVATE
PROC[dc: Imager.Context, data:
REF
ANY, camera: Camera, localCS: CoordSystem, clippedBy: Imager.Rectangle] = {
halfSpaceRec: HalfSpaceRec ← NARROW[data];
gridSide: REAL ← halfSpaceRec.gridSide;
plane: Plane ← SVPolygon3d.PlaneFromCoefficients[0,1,0,0];
SVGraphics.DrawInfiniteLine[dc, [0,0,0], [1,0,0], camera, localCS, clippedBy];
SVGraphics.DrawInfiniteLine[dc, [0,0,gridSide], [1,0,gridSide], camera, localCS, clippedBy];
SVGraphics.DrawInfiniteLine[dc, [0,0,-gridSide], [1,0,-gridSide], camera, localCS, clippedBy];
SVGraphics.DrawInfiniteLine[dc, [0,0,0], [0,0,1], camera, localCS, clippedBy];
SVGraphics.DrawInfiniteLine[dc, [gridSide,0,0], [gridSide,0,1], camera, localCS, clippedBy];
SVGraphics.DrawInfiniteLine[dc, [-gridSide,0,0], [-gridSide,0,1], camera, localCS, clippedBy];
SVGraphics.DrawHorizonOfPlane[dc, plane, camera, localCS];
};
HalfSpaceLineDraw:
PUBLIC PROC [slice: Slice, dc: Imager.Context, camera: Camera] = {
mo: MasterObject ← NARROW[slice.shape, Shape].mo;
halfSpaceRec: HalfSpaceRec ← NARROW[mo.lineBody];
gridSide: REAL ← halfSpaceRec.gridSide;
lineLen: REAL ← 100.0;
localCS: CoordSystem ← slice.coordSys;
SVGraphics.DrawLine[dc, [-lineLen,0,0], [lineLen,0,0], camera, localCS];
SVGraphics.DrawLine[dc, [-lineLen,0,gridSide], [lineLen,0,gridSide], camera, localCS];
SVGraphics.DrawLine[dc, [-lineLen,0,-gridSide], [lineLen,0,-gridSide], camera, localCS];
SVGraphics.DrawLine[dc, [0,0,-lineLen], [0,0,lineLen], camera, localCS];
SVGraphics.DrawLine[dc, [gridSide,0,-lineLen], [gridSide,0,lineLen], camera, localCS];
SVGraphics.DrawLine[dc, [-gridSide,0,-lineLen], [-gridSide,0,lineLen], camera, localCS];
};
HalfSpaceDrawNormals:
PUBLIC
PROC[dc: Imager.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: Slice, camera: CoordSystem] RETURNS [psl: PlanarSurfaceList] = {
mo: MasterObject ← NARROW[assembly.shape, Shape].mo;
midPoint: Point3d ← SVGraphics.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, cameraCS: 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 ← SVGraphics.LocalToCamera[localPoint, localCS, cameraCS];
sum ← sum + localPoint[3];
ENDLOOP;
avgDepth ← sum/realLen;
};
HalfSpaceGetSurf:
PUBLIC
PROC [slice: Slice, camera: CoordSystem]
RETURNS [psl: PlanarSurfaceList] = {
poly: Poly3d ← SVPolygon3d.CreatePoly[4];
avgDepth: REAL;
shape: Shape ← NARROW[slice.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: slice,
normal: [0,1,0],
mo: mo,
depth: avgDepth]];
psl ← CONS[thisSortedSurface, psl];
SVPolygon3d.ClearPoly[poly];
ENDLOOP;
ENDLOOP;
};
HalfSpaceDrawSurf: PUBLIC PROC [dc: Imager.Context, ps: PlanarSurface, lightSources: LightSourceList, camera: Camera] = {
localCS: CoordSystem;
plane: Plane ← SVPolygon3d.PlaneFromCoefficients[0,1,0,0];
localCS ← ps.assembly.coordSys;
SVGraphics.DrawInfinitePlaneShaded[dc, plane, ps.assembly.artwork, lightSources, camera, localCS];
};
HalfSpaceDrawSurf:
PUBLIC
PROC [dc: Imager.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]];
SVGraphics.DrawAreaNormalAbsolute[dc, ps.normal, poly, ps.assembly.artwork, lightSources, camera, CoordSys.WRTWorld[localCS], CoordSys.WRTCamera[localCS, camera.coordSys]];
};
HalfSpaceFileout:
PUBLIC
PROC [f:
IO.
STREAM, mo: MasterObject] = {
HalfSpaces can be recovered from scratch.
f.PutChar[IO.TAB];
f.PutF["data: procedural\n"];
};
HalfSpaceUpdate:
PUBLIC
PROC [mo: MasterObject, updateData:
REF
ANY] = {
};
HalfSpaceFilein:
PUBLIC
PROC [f:
IO.
STREAM, name: Rope.
ROPE, version:
REAL]
RETURNS [mo: MasterObject] = {
TFI3d.ReadRope[f, "data: procedural"];
TFI3d.ReadBlank[f];
mo ← HalfSpaceMakeMasterObject[name];
};
Init:
PROC = {
halfSpace: MasterObject;
halfSpaceClass ←
NEW[MasterObjectClassObj ← [
name: "halfSpace",
update: HalfSpaceUpdate,
filein: HalfSpaceFilein,
fileout: HalfSpaceFileout,
fileoutPoly: SVMasterObject.NoOpFileoutPoly,
rayCast: HalfSpaceRayCast,
rayCastNoBBoxes: HalfSpaceRayCastNoBBoxes,
rayCastBoundingSpheres: HalfSpaceRayCastBoundingSpheres,
getHedron: HalfSpaceBoundHedron,
preprocess: SVMasterObject.NoOpPreprocess,
lineDraw: HalfSpaceLineDraw,
normalsDraw: HalfSpaceDrawNormals,
countSurf: HalfSpaceCountSurf,
getSurf: HalfSpaceGetSurf,
pointsInDescriptor: SVMasterObject.NoOpPointsInDescriptor,
nextPoint: SVMasterObject.NoOpNextPoint,
drawSurf: HalfSpaceDrawSurf,
drawSubBoxes: SVMasterObject.NoOpDrawSubBoxes,
drawSubSpheres: SVMasterObject.NoOpDrawSubSpheres
]];
SVMasterObject.RegisterMasterObjectClass[halfSpaceClass];
halfSpace ← HalfSpaceMakeMasterObject["halfSpace"];
SVMasterObject.RegisterMasterObject[halfSpace];
};
Init[];
END.