File: CatastropheClassImpl.mesa
Last edited by Bier on January 10, 1985 5:22:13 pm PST
Author: Dennis Arnon and Eric Bier on January 17, 1985 3:42:30 pm PST
DIRECTORY
CastRays,
CSG,
DisplayList3d,
IO,
Polynomial,
Rope,
SV2d,
SV3d,
SVModelTypes,
SVRayTypes,
SVSceneTypes,
TFI3d;
CatastropheClassImpl: PROGRAM
IMPORTS CastRays, CSG, DisplayList3d, IO, Polynomial, TFI3d
EXPORTS =
BEGIN
Camera: TYPE = SVModelTypes.Camera;
Point2d: TYPE = SV2d.Point2d;
Point3d: TYPE = SV3d.Point3d;
Shape: TYPE = SVSceneTypes.Shape;
Vector: TYPE = SV3d.Vector;
RAY CASTING TYPES
Assembly: TYPE = SVSceneTypes.Assembly;
Classification: TYPE = SVRayTypes.Classification;
Composite: TYPE = SVRayTypes.Composite;
MasterObject: TYPE = SVSceneTypes.MasterObject;
MasterObjectClass: TYPE = SVSceneTypes.MasterObjectClass;
MasterObjectClassList: TYPE = SVSceneTypes.MasterObjectClassList; -- LIST OF MasterObjectClass
Primitive: TYPE = SVRayTypes.Primitive;
Ray: TYPE = SVRayTypes.Ray;
globalPoly: Polynomial.Ref;
catastropheClass: MasterObjectClass;
CatastropheCast: PUBLIC PROC [cameraPoint: Point2d, localRay: Ray, masterObject: REF ANY, prim: Primitive]
RETURNS [class: Classification] = {
The Catastrophe surface is:
3
F(x,y,z) = z - x z + y

1/17/85 - modified to only do cell (3,3,4) of the cad.
catastropheData: CatastropheRec;
realRoots: Polynomial.ShortRealRootRec; -- optional
realRoots: ARRAY[0..3] OF REAL;
realRootsOneOrigin: ARRAY[1..4] OF REAL;
rootCount: NAT;
x0, x1, y0, y1, z0, z1: REAL;
a3,a2,a1,a0: REAL;
p: Point3d;
d: Vector;
onSection, bool1, bool2, bool3: BOOL;
x, y, z: REAL;
j: NAT;
CatastropheGrad: PROC [x, y, z: REAL] RETURNS [Vector] ~ {
gradx, grady, gradz: REAL;
gradx ← - z;
grady ← 1;
gradz ← 3. * z * z - x;
RETURN [[gradx, grady, gradz]];
};
class ← CastRays.GetClassFromPool[];
catastropheData ← NARROW[catastropheRec];
[p, d] ← CSG.GetLocalRay[localRay]; -- p is base point, d is directiona
x0 ← p[1]; x1 ← d[1];
y0 ← p[2]; y1 ← d[2];
z0 ← p[3]; z1 ← d[3];
The result of substituting
F, x: x1 * t + x0, y: y1 * t + y0, z: z1 * t + z0;
in Macsyma:

3 3 2 2 2 2 3
(d3) t z1 + 3 t z0 z1 + 3 t z0 z1 - t x1 z1 - t x0 z1 + z0 - t x1 z0

- x0 z0 + t y1 + y0

a3 ← z1 * z1 * z1;
a2 ← 3. * z1 * (z0 * z1 - x1 );
a1 ← 3. * z0 * z0 * z1 - x0 * z1 - x1 * z0 + y1;
a0 ← z0 * ( z0 * z0 - x0) + y0 ;
realRoots ← PositiveRoots[a3,a2,a1,a0];
onSection ← FALSE; j ← 1;
WHILE NOT onSection AND j <= realRoots.nRoots DO
x ← x0 + realRoots.realRoot[j-1]*x1;
y ← y0 + realRoots.realRoot[j-1]*y1;
z ← z0 + realRoots.realRoot[j-1]*z1;
bool1 ← x > 0.0;
bool2 ← 27. * y * y - 4. * x * x * x < 0.0 ;
bool3 ← 3. * z * z - x < 0.0;
onSection ← bool1 AND bool2 AND bool3; -- apply the defining formula for cell (3,3,4)
j ← j + 1;
ENDLOOP;
IF onSection THEN {
class.count ← 1;
class.params[1] ← realRoots.realRoot[0];
class.surfaces[1] ← NIL;
class.classifs[1] ← FALSE; class.classifs[2] ← TRUE;
class.primitives[1] ← prim;
class.normals[1] ← CatastropheGrad[x, y, z];
To normalize, divide by norm. (I won't do this since the lighting model normalizes anyway)
}
ELSE {
class.count ← 0;
class.classifs[1] ← FALSE;
};
};
PositiveRoots: PROCEDURE [a3, a2, a1, a0: REAL] RETURNS [rootArray: Polynomial.ShortRealRootRec] = {
Use only the positive roots.
i: NAT ← 1;
globalPoly[3] ← a3; -- optional
globalPoly[2] ← a2; -- optional
globalPoly[1] ← a1; -- optional
globalPoly[0] ← a0; -- optional
rootArray ← Polynomial.CheapRealRoots[globalPoly]; -- optional
[realRootsOneOrigin, rootCount] ← Roots.RealQuartic[a4, a3, a2, a1, a0]; -- no possibility of applicability since catastrophe surface is cubic
realRoots[0] ← realRootsOneOrigin[1]; realRoots[1] ← realRootsOneOrigin[2];
realRoots[2] ← realRootsOneOrigin[3]; realRoots[3] ← realRootsOneOrigin[4];
IF rootArray.nRoots = 0 THEN RETURN;
WHILE i <= rootArray.nRoots DO
IF rootArray.realRoot[i-1] <= 0 THEN {
FOR j: NAT IN [i..rootArray.nRoots-1] DO
rootArray.realRoot[j-1] ← rootArray.realRoot[j];
ENDLOOP;
rootArray.nRoots ← rootArray.nRoots - 1;
}
ELSE {i ← i + 1};
ENDLOOP;
};
MakeMasterObject: PROC [name: Rope.ROPE] RETURNS [mo: MasterObject] = {
mainBody: REF ANYNIL;
lineBody: REF ANYNIL;
shadeBody: REF ANY ← lineBody;
rayCastBody: REF ANYNIL;
mo ← DisplayList3d.CreateMasterObject[name, catastropheClass, mainBody, lineBody, shadeBody, rayCastBody];
};
CatastropheFileout: PUBLIC PROC [f: IO.STREAM, mo: MasterObject] = {
Catastrophes can be built from scratch.
f.PutChar[IO.TAB];
f.PutF["data: procedural\n"];
};
CatastropheFilein: PUBLIC PROC [f: IO.STREAM, name: Rope.ROPE] RETURNS [mo: MasterObject] = {
TFI3d.ReadRope[f, "data: procedural"];
TFI3d.ReadBlank[f];
mo ← MakeMasterObject[name];
};
Init: PROC = {
catastrophe: MasterObject;
globalPoly ← Polynomial.Cubic[[0,0,0,0]];
catastropheClass ← DisplayList3d.RegisterMasterObjectClass[
"catastrophe",
CatastropheFilein,
CatastropheFileout,
DisplayList3d.NoOpFileoutPoly,
CatastropheCast,
DisplayList3d.NoOpRayCastNoBBoxes,
DisplayList3d.NoOpRayCastBoundingSpheres,
DisplayList3d.NoOpBoundHedron,
DisplayList3d.NoOpPreprocess,
DisplayList3d.NoOpLineDraw,
DisplayList3d.NoOpNormalsDraw,
DisplayList3d.NoOpCountPlanarSurfaces,
DisplayList3d.NoOpGetPlanarSurfaces,
DisplayList3d.NoOpDrawPlanarSurface,
DisplayList3d.NoOpDrawSubBoxes,
DisplayList3d.NoOpDrawSubSpheres];
catastrophe ← MakeMasterObject["catastrophe"];
DisplayList3d.RegisterMasterObject[catastrophe];
};
Init[];
END.