<> <> <> <> <> DIRECTORY Algebra3d, SVCastRays, SVObjectCast, SVRay, SV3d, SVSceneTypes, SVVector3d; SVObjectCastImplB: CEDAR PROGRAM IMPORTS Algebra3d, SVCastRays, SVRay EXPORTS SVObjectCast = BEGIN Classification: TYPE = SVSceneTypes.Classification; Point3d: TYPE = SV3d.Point3d; Primitive: TYPE = SVSceneTypes.Primitive; Ray: TYPE = SVRay.Ray; SurfaceArray: TYPE = SVSceneTypes.SurfaceArray; Vector3d: TYPE = SV3d.Vector3d; HitRec: TYPE = REF HitRecObj; HitRecObj: TYPE = RECORD [ t: REAL, normal: Vector3d]; HitArray: TYPE = REF HitArrayObj; HitArrayObj: TYPE = ARRAY[1..2] OF HitRec; globalPlaneHit: HitRec; globalConeHitArray: HitArray; globalConeHitCount: NAT; almostZero: REAL = 1.0e-12; d1d1, d2d2, d3d3: REAL; p1p1, p2p2, p3p3: REAL; p1d1, p2d2, p3d3: REAL; xd2, zd2: REAL; a, b, c: REAL; x0, y0, z0: REAL; normal: Vector3d; PositiveRoots: PROCEDURE [a, b, c: REAL] RETURNS [rootArray: ARRAY[1..2] OF REAL, rootCount: NAT] = { <> i: NAT _ 1; [rootArray, rootCount] _ Algebra3d.QuadraticFormula[a, b, c]; IF rootCount = 0 THEN RETURN; WHILE i <= rootCount DO IF rootArray[i] <= 0 THEN { FOR j: NAT IN [i..rootCount-1] DO rootArray[j] _ rootArray[j+1]; ENDLOOP; rootCount _ rootCount - 1; } ELSE {i _ i + 1}; ENDLOOP; }; ConeCast: PUBLIC PROC [localRay: Ray, surfaces: SurfaceArray, prim: Primitive] RETURNS [class: Classification] = { <<1 ray-disk test and 1 ray-cone test.>> <> <> << y = p[2] + t*d[2]>> << z = p[3] + t*d[3]>> <> <> <> <> <> <> d: Vector3d; p: Point3d; hitDisk: BOOL _ FALSE; planeT: REAL; coneT1: REAL; realRoots: ARRAY[1..2] OF REAL; rootCount: NAT; [p, d] _ SVRay.GetLocalRay[localRay]; class _ SVCastRays.GetClassFromPool[]; IF Abs[d[2]] > almostZero THEN { xd2 _ p[1]*d[2] -p[2]*d[1]; zd2 _ p[3]*d[2] -p[2]*d[3]; IF xd2*xd2 + zd2*zd2 <= d[2]*d[2] THEN { planeT _ -p[2]/d[2]; IF planeT > 0 THEN { hitDisk _ TRUE; globalPlaneHit^ _ [planeT, [0,-1.0, 0] ]; }; }; }; <> <> <> <> <> <> d1d1 _ d[1]*d[1]; d2d2 _ d[2]*d[2]; d3d3 _ d[3]*d[3]; p1p1 _ p[1]*p[1]; p2p2 _ p[2]*p[2]; p3p3 _ p[3]*p[3]; p1d1 _ p[1]*d[1]; p2d2 _ p[2]*d[2]; p3d3 _ p[3]*d[3]; a _ d1d1 + d3d3 - d2d2; b _ 2*(p1d1 + p3d3 + d[2] - p2d2); c _ p1p1 + p3p3 - 1 + 2*p[2] - p2p2; <> [realRoots, rootCount] _ PositiveRoots[a, b, c]; <> globalConeHitCount _ 0; FOR i: NAT IN [1..rootCount] DO y0 _ p[2] + realRoots[i]*d[2]; IF y0 > 0.0 AND y0 <= 1 THEN { <> x0 _ p[1] + realRoots[i]*d[1]; z0 _ p[3] + realRoots[i]*d[3]; normal _ [x0, 1-y0, z0]; globalConeHitCount _ globalConeHitCount+1; globalConeHitArray[globalConeHitCount]^ _ [realRoots[i], normal]; }; ENDLOOP; SELECT globalConeHitCount FROM 0 => {-- ray missed cone completely or scraped an edge. Count as miss class.count _ 0; class.classifs[1] _ FALSE; }; 1 => { <> <> coneT1 _ globalConeHitArray[1].t; IF hitDisk THEN { class.count _ 2; IF coneT1 < planeT THEN { class.params[1] _ coneT1; class.params[2] _ planeT; class.normals[1] _ globalConeHitArray[1].normal; class.normals[2] _ globalPlaneHit.normal; class.surfaces[1] _ surfaces[1]; class.surfaces[2] _ surfaces[2];} ELSE { class.params[2] _ coneT1; class.params[1] _ planeT; class.normals[2] _ globalConeHitArray[1].normal; class.normals[1] _ globalPlaneHit.normal; class.surfaces[2] _ surfaces[1]; class.surfaces[1] _ surfaces[2]; }; class.classifs[1] _ FALSE; class.classifs[2] _ TRUE; class.classifs[3] _ FALSE; class.primitives[1] _ class.primitives[2] _ prim; } ELSE {-- count as a miss class.count _ 0; class.classifs[1] _ FALSE; }; }; -- end of one shroud hit. 2 => { <> <> class.count _ 2; IF globalConeHitArray[1].t < globalConeHitArray[2].t THEN { class.params[1] _ globalConeHitArray[1].t; class.params[2] _ globalConeHitArray[2].t; class.normals[1] _ globalConeHitArray[1].normal; class.normals[2] _ globalConeHitArray[2].normal} ELSE { class.params[2] _ globalConeHitArray[1].t; class.params[1] _ globalConeHitArray[2].t; class.normals[2] _ globalConeHitArray[1].normal; class.normals[1] _ globalConeHitArray[2].normal}; class.surfaces[1] _ surfaces[1]; class.surfaces[2] _ surfaces[1]; class.classifs[1] _ FALSE; class.classifs[2] _ TRUE; class.classifs[3] _ FALSE; class.primitives[1] _ class.primitives[2] _ prim; }; 3, 4 => { <> class.count _ 0; class.classifs[1] _ FALSE; }; ENDCASE => ERROR; }; -- end of ConeCast Abs: PROC [r: REAL] RETURNS [REAL] = { RETURN [IF r>=0 THEN r ELSE -r]; }; Init: PROC = { globalPlaneHit _ NEW[HitRecObj]; globalConeHitArray _ NEW[HitArrayObj]; FOR i: NAT IN[1..2] DO globalConeHitArray[i] _ NEW[HitRecObj]; ENDLOOP; }; Init[]; END.