<> <> <> <> DIRECTORY SVCastRays, SVRay, SV2d, SV3d, SVBoundBox, SVFaces, SVFacesCast, SVLines2d, SVPolygon2d, SVPolygon3d, SVSceneTypes, SVSweepCast, SVSweepGeometry; SVSweepCastImpl: CEDAR PROGRAM IMPORTS SVCastRays, SVRay, SVBoundBox, SVFaces, SVFacesCast, SVLines2d, SVPolygon2d, SVPolygon3d EXPORTS SVSweepCast = BEGIN Classification: TYPE = SVSceneTypes.Classification; Plane: TYPE = SV3d.Plane; Point2d: TYPE = SV2d.Point2d; Point3d: TYPE = SV3d.Point3d; Polygon: TYPE = SV2d.Polygon; Primitive: TYPE = SVSceneTypes.Primitive; Ray: TYPE = SVSceneTypes.Ray; Vector3d: TYPE = SV3d.Vector3d; Cone: TYPE = SVFaces.Cone; DiskRing: TYPE = SVFaces.DiskRing; Cylinder: TYPE = SVFaces.Cylinder; FaceHitRec: TYPE = SVFacesCast.FaceHitRec; LinearMesh: TYPE = REF LinearMeshRecord; LinearMeshRecord: TYPE = SVSweepGeometry.LinearMeshRecord; RevoluteMesh: TYPE = REF RevoluteMeshRecord; RevoluteMeshRecord: TYPE = SVSweepGeometry.RevoluteMeshRecord; RevoSweepFaces: TYPE = REF RevoSweepFacesObj; RevoSweepFacesObj: TYPE = SVSweepCast.RevoSweepFacesObj; SubBoxesBody: TYPE = SVSweepCast.SubBoxesBody; SubSpheresBody: TYPE = SVSweepCast.SubSpheresBody; RevoHitArray: TYPE = REF RevoHitArrayObj; RevoHitArrayObj: TYPE = SVSweepCast.RevoHitArrayObj; RevoHitRec: TYPE = REF RevoHitRecObj; RevoHitRecObj: TYPE = SVSweepCast.RevoHitRecObj; LinSweepFaces: TYPE = REF LinSweepFacesObj; LinSweepFacesObj: TYPE = SVSweepCast.LinSweepFacesObj; LinHitArray: TYPE = REF LinHitArrayObj; LinHitArrayObj: TYPE = SVSweepCast.LinHitArrayObj; LinHitRec: TYPE = REF LinHitRecObj; LinHitRecObj: TYPE = SVSweepCast.LinHitRecObj; globalRevoHits: RevoHitArray; globalLinHits: LinHitArray; almostZero: REAL = 1.0e-12; LinCast: PUBLIC PROC [localRay: Ray, prim: Primitive, linMesh: LinearMesh, faces: LinSweepFaces, positiveTOnly: BOOL _ TRUE] RETURNS [class: Classification] = { <> <> <> poly: Polygon; faceHit: FaceHitRec; class _ SVCastRays.GetClassFromPool[]; globalLinHits.count _ 0; <> <> poly _ faces.poly; faceHit _ RayXYPolygon[localRay, poly, linMesh.array[1][1][3], [0, 0, 1]]; IF faceHit.count = 1 THEN { globalLinHits.count _ globalLinHits.count + 1; globalLinHits.array[globalLinHits.count]^ _ [faceHit.params[1], faceHit.normals[1], 0]}; SVFacesCast.ReturnFaceHitToPool[faceHit]; <> faceHit _ RayXYPolygon[localRay, poly, linMesh.array[1][2][3], [0, 0, -1]]; IF faceHit.count = 1 THEN { globalLinHits.count _ globalLinHits.count + 1; globalLinHits.array[globalLinHits.count]^ _ [faceHit.params[1], faceHit.normals[1], linMesh.len+1]}; SVFacesCast.ReturnFaceHitToPool[faceHit]; <> FOR i: NAT IN [0..faces.len) DO faceHit _ SVFacesCast.EdgeOnRectCast[faces[i], localRay]; IF faceHit.count = 1 THEN { globalLinHits.count _ globalLinHits.count + 1; globalLinHits.array[globalLinHits.count]^ _ [faceHit.params[1], faceHit.normals[1], i+1]}; SVFacesCast.ReturnFaceHitToPool[faceHit]; ENDLOOP; <> SELECT globalLinHits.count FROM 0 => { -- miss. SVCastRays.MakeClassAMiss[class]}; 1 => { p: Point3d; d: Vector3d; pointClass: SVPolygon2d.PointPolyClass; <> [p, d] _ SVRay.GetLocalRay[localRay]; IF p[3] > linMesh.array[1][2][3] AND p[3] < linMesh.array[1][1][3] THEN { pointClass _ SVPolygon2d.BoysePointInPoly[[p[1], p[2]], poly]; IF pointClass = in THEN { class.count _ 1; class.params[1] _ globalLinHits.array[1].param; class.normals[1] _ globalLinHits.array[1].normal; class.surfaces[1] _ NIL; class.classifs[1] _ TRUE; class.classifs[2] _ FALSE; class.primitives[1] _ prim; } ELSE SVCastRays.MakeClassAMiss[class]; } ELSE SVCastRays.MakeClassAMiss[class]; }; ENDCASE => { <> iPlusOne: NAT; startI: NAT _ 1; SortLinHits[globalLinHits]; IF (globalLinHits.count/2)*2 # globalLinHits.count THEN { -- odd number of hits p: Point3d; d: Vector3d; pointClass: SVPolygon2d.PointPolyClass; [p, d] _ SVRay.GetLocalRay[localRay]; IF p[3] > linMesh.array[1][2][3] AND p[3] < linMesh.array[1][1][3] THEN { pointClass _ SVPolygon2d.BoysePointInPoly[[p[1], p[2]], poly]; IF pointClass = in THEN { startI _ 2; class.params[1] _ globalLinHits.array[1].param; class.normals[1] _ globalLinHits.array[1].normal; class.surfaces[1] _ NIL; class.classifs[1] _ TRUE; class.primitives[1] _ prim; } ELSE globalRevoHits.count _ globalLinHits.count - 1; } ELSE globalRevoHits.count _ globalLinHits.count - 1; }; class.count _ globalLinHits.count; FOR i: NAT _ startI, i+2 UNTIL i > globalLinHits.count DO iPlusOne _ i+1; class.params[i] _ globalLinHits.array[i].param; class.params[iPlusOne] _ globalLinHits.array[iPlusOne].param; class.normals[i] _ globalLinHits.array[i].normal; class.normals[iPlusOne] _ globalLinHits.array[iPlusOne].normal; class.surfaces[i] _ NIL; class.surfaces[iPlusOne] _ NIL; class.classifs[i] _ FALSE; class.classifs[iPlusOne] _ TRUE; class.primitives[i] _ prim; class.primitives[iPlusOne] _ prim; ENDLOOP; class.classifs[globalLinHits.count+1] _ FALSE; }; -- end of 2 or more hits }; -- end of LinCast RevoCast: PUBLIC PROC [cameraPoint: Point2d, localRay: Ray, prim: Primitive, faces: RevoSweepFaces, boxes: SubBoxesBody, positiveTOnly: BOOL _ TRUE] RETURNS [class: Classification] = { <> <> class _ SVCastRays.GetClassFromPool[]; globalRevoHits.count _ 0; FOR i: NAT IN[0..faces.len) DO WITH faces[i] SELECT FROM cone: Cone => { hits: FaceHitRec; IF NOT SVBoundBox.PointInBoundBox[cameraPoint, boxes[i]] THEN LOOP; hits _ SVFacesCast.ConeCast[cone, localRay]; FOR j: NAT IN[1..hits.count] DO globalRevoHits.count _ globalRevoHits.count + 1; globalRevoHits.array[globalRevoHits.count]^ _ [hits.params[j], hits.normals[j], i]; ENDLOOP; SVFacesCast.ReturnFaceHitToPool[hits]; }; disk: DiskRing => { hit: FaceHitRec; IF NOT SVBoundBox.PointInBoundBox[cameraPoint, boxes[i]] THEN LOOP; hit _ SVFacesCast.DiskRingCast[disk, localRay]; IF hit.count = 1 THEN { globalRevoHits.count _ globalRevoHits.count + 1; globalRevoHits.array[globalRevoHits.count]^ _ [hit.params[1], hit.normals[1], i]; }; SVFacesCast.ReturnFaceHitToPool[hit]; }; cyl: Cylinder => { hits: FaceHitRec; IF NOT SVBoundBox.PointInBoundBox[cameraPoint, boxes[i]] THEN LOOP; hits _ SVFacesCast.CylinderCast[cyl, localRay]; FOR j: NAT IN[1..hits.count] DO globalRevoHits.count _ globalRevoHits.count + 1; globalRevoHits.array[globalRevoHits.count]^ _ [hits.params[j], hits.normals[j], i]; ENDLOOP; SVFacesCast.ReturnFaceHitToPool[hits]; }; ENDCASE => ERROR; ENDLOOP;-- next face <> SELECT globalRevoHits.count FROM 0 => {-- miss. SVCastRays.MakeClassAMiss[class]}; 1 => {-- ray just skims one face. Treat as a miss. SVCastRays.MakeClassAMiss[class]}; ENDCASE => { <> iPlusOne: NAT; SortRevoHits[globalRevoHits]; IF (globalRevoHits.count/2)*2 # globalRevoHits.count THEN globalRevoHits.count _ globalRevoHits.count - 1; class.count _ globalRevoHits.count; FOR i: NAT _ 1, i+2 UNTIL i > globalRevoHits.count DO iPlusOne _ i+1; class.params[i] _ globalRevoHits.array[i].param; class.params[iPlusOne] _ globalRevoHits.array[iPlusOne].param; class.normals[i] _ globalRevoHits.array[i].normal; class.normals[iPlusOne] _ globalRevoHits.array[iPlusOne].normal; class.surfaces[i] _ NIL; class.surfaces[iPlusOne] _ NIL; class.classifs[i] _ FALSE; class.classifs[iPlusOne] _ TRUE; class.primitives[i] _ prim; class.primitives[iPlusOne] _ prim; ENDLOOP; class.classifs[globalRevoHits.count+1] _ FALSE; }; -- end of 2 or more hits }; -- end of RevoCast RevoCastNoBBoxes: PUBLIC PROC [localRay: Ray, prim: Primitive, faces: RevoSweepFaces, positiveTOnly: BOOL _ TRUE] RETURNS [class: Classification] = { <> <> class _ SVCastRays.GetClassFromPool[]; globalRevoHits.count _ 0; FOR i: NAT IN[0..faces.len) DO WITH faces[i] SELECT FROM cone: Cone => { hits: FaceHitRec; hits _ SVFacesCast.ConeCast[cone, localRay]; FOR j: NAT IN[1..hits.count] DO globalRevoHits.count _ globalRevoHits.count + 1; globalRevoHits.array[globalRevoHits.count]^ _ [hits.params[j], hits.normals[j], i]; ENDLOOP; SVFacesCast.ReturnFaceHitToPool[hits]; }; disk: DiskRing => { hit: FaceHitRec; hit _ SVFacesCast.DiskRingCast[disk, localRay]; IF hit.count = 1 THEN { globalRevoHits.count _ globalRevoHits.count + 1; globalRevoHits.array[globalRevoHits.count]^ _ [hit.params[1], hit.normals[1], i]; }; SVFacesCast.ReturnFaceHitToPool[hit]; }; cyl: Cylinder => { hits: FaceHitRec; hits _ SVFacesCast.CylinderCast[cyl, localRay]; FOR j: NAT IN[1..hits.count] DO globalRevoHits.count _ globalRevoHits.count + 1; globalRevoHits.array[globalRevoHits.count]^ _ [hits.params[j], hits.normals[j], i]; ENDLOOP; SVFacesCast.ReturnFaceHitToPool[hits]; }; ENDCASE => ERROR; ENDLOOP;-- next face <> SELECT globalRevoHits.count FROM 0 => {-- miss. SVCastRays.MakeClassAMiss[class]}; 1 => {-- ray just skims one face. Treat as a miss. SVCastRays.MakeClassAMiss[class]}; ENDCASE => {-- Sort the hits in order of depth along ray. Assume for now that the ray Doesn't skim edges or miss surfaces or go through cracks. Hence every other hit is an enter followed by an exit. If there is an odd number of hits, ignore the last one. iPlusOne: NAT; SortRevoHits[globalRevoHits]; IF (globalRevoHits.count/2)*2 # globalRevoHits.count THEN globalRevoHits.count _ globalRevoHits.count - 1; class.count _ globalRevoHits.count; FOR i: NAT _ 1, i+2 UNTIL i > globalRevoHits.count DO iPlusOne _ i+1; class.params[i] _ globalRevoHits.array[i].param; class.params[iPlusOne] _ globalRevoHits.array[iPlusOne].param; class.normals[i] _ globalRevoHits.array[i].normal; class.normals[iPlusOne] _ globalRevoHits.array[iPlusOne].normal; class.surfaces[i] _ NIL; class.surfaces[iPlusOne] _ NIL; class.classifs[i] _ FALSE; class.classifs[iPlusOne] _ TRUE; class.primitives[i] _ prim; class.primitives[iPlusOne] _ prim; ENDLOOP; class.classifs[globalRevoHits.count+1] _ FALSE; }; -- end of 2 or more hits }; -- end of RevoCast OddHits: ERROR = CODE; InOutsDontAlternate: ERROR = CODE; RevoCastBoundSpheres: PUBLIC PROC [localRay: Ray, prim: Primitive, faces: RevoSweepFaces, spheres: SubSpheresBody, positiveTOnly: BOOL _ TRUE] RETURNS [class: Classification] = { <> <> class _ SVCastRays.GetClassFromPool[]; globalRevoHits.count _ 0; FOR i: NAT IN[0..faces.len) DO WITH faces[i] SELECT FROM cone: Cone => { hits: FaceHitRec; IF NOT SVRay.RayHitsBoundSphere[localRay, spheres[i]] THEN LOOP; hits _ SVFacesCast.ConeCast[cone, localRay]; FOR j: NAT IN[1..hits.count] DO globalRevoHits.count _ globalRevoHits.count + 1; globalRevoHits.array[globalRevoHits.count]^ _ [hits.params[j], hits.normals[j], i]; ENDLOOP; SVFacesCast.ReturnFaceHitToPool[hits]; }; disk: DiskRing => { hit: FaceHitRec; IF NOT SVRay.RayHitsBoundSphere[localRay, spheres[i]] THEN LOOP; hit _ SVFacesCast.DiskRingCast[disk, localRay]; IF hit.count = 1 THEN { globalRevoHits.count _ globalRevoHits.count + 1; globalRevoHits.array[globalRevoHits.count]^ _ [hit.params[1], hit.normals[1], i]; }; SVFacesCast.ReturnFaceHitToPool[hit]; }; cyl: Cylinder => { hits: FaceHitRec; IF NOT SVRay.RayHitsBoundSphere[localRay, spheres[i]] THEN LOOP; hits _ SVFacesCast.CylinderCast[cyl, localRay]; FOR j: NAT IN[1..hits.count] DO globalRevoHits.count _ globalRevoHits.count + 1; globalRevoHits.array[globalRevoHits.count]^ _ [hits.params[j], hits.normals[j], i]; ENDLOOP; SVFacesCast.ReturnFaceHitToPool[hits]; }; ENDCASE => ERROR; ENDLOOP; -- next face <> SELECT globalRevoHits.count FROM 0 => {-- miss. SVCastRays.MakeClassAMiss[class]}; 1 => {-- ray originates inside of the sweep or is a glancing hit. See if ray base-point passes an inside-outside test. This boils down to a point-in-polygon test. <> <> class.count _ 1; class.params[1] _ globalRevoHits.array[1].param; class.surfaces[1] _ NIL; class.classifs[1] _ TRUE; class.classifs[2] _ FALSE; class.normals[1] _ globalRevoHits.array[1].normal; class.primitives[1] _ prim; }; ENDCASE => { <> iPlusOne: NAT; SortRevoHits[globalRevoHits]; IF (globalRevoHits.count/2)*2 # globalRevoHits.count THEN globalRevoHits.count _ globalRevoHits.count - 1; class.count _ globalRevoHits.count; FOR i: NAT _ 1, i+2 UNTIL i > globalRevoHits.count DO iPlusOne _ i+1; class.params[i] _ globalRevoHits.array[i].param; class.params[iPlusOne] _ globalRevoHits.array[iPlusOne].param; class.normals[i] _ globalRevoHits.array[i].normal; class.normals[iPlusOne] _ globalRevoHits.array[iPlusOne].normal; class.surfaces[i] _ NIL; class.surfaces[iPlusOne] _ NIL; class.classifs[i] _ FALSE; class.classifs[iPlusOne] _ TRUE; class.primitives[i] _ prim; class.primitives[iPlusOne] _ prim; ENDLOOP; class.classifs[globalRevoHits.count+1] _ FALSE; }; -- end of 2 or more hits }; -- end of RevoCastBoundSpheres HitsACrack: PRIVATE PROC [localRay: Ray, t, y: REAL, meshRecord: RevoluteMesh] RETURNS [matches: BOOL, index: NAT] = { x, z, r: REAL; p: Point3d; d: Vector3d; [p, d] _ SVRay.GetLocalRay[localRay]; FOR i: NAT IN[1..meshRecord.linesOfLatitude] DO IF AlmostEqualHeights[y, meshRecord.array[i][1][2]] THEN { x _ p[1] + t*d[1]; z _ p[3] + t*d[3]; r _ meshRecord.array[i][meshRecord.linesOfLongitude][1]; IF x*x + z*z = r*r THEN { matches _ TRUE; index _ i; RETURN} ELSE { matches _ FALSE; RETURN}}; ENDLOOP; matches _ FALSE; }; -- end of HitsACrack HitsNeighbors: PRIVATE PROC [localRay: Ray, index: NAT, mesh: RevoluteMesh] RETURNS [BOOL] = { IF index = 1 THEN RETURN[HitsDisk[localRay, mesh.array[2][1][2], mesh.array[2][mesh.linesOfLongitude][1]]]; IF index = mesh.linesOfLatitude THEN RETURN[HitsDisk[localRay, mesh.array[mesh.linesOfLatitude-1][1][2], mesh.array[mesh.linesOfLatitude-1][mesh.linesOfLongitude][1]]]; RETURN[ HitsDisk[localRay, mesh.array[index-1][1][2], mesh.array[index-1][mesh.linesOfLongitude][1]] OR HitsDisk[localRay, mesh.array[index+1][1][2], mesh.array[index+1][mesh.linesOfLongitude][1]] ]; }; HitsDisk: PRIVATE PROC [localRay: Ray, y: REAL, r: REAL] RETURNS [success: BOOL] = { <> <> <> <> <> x, z, t: REAL; p: Point3d; d: Vector3d; [p, d] _ SVRay.GetLocalRay[localRay]; success _ FALSE; IF Abs[d[2]] < almostZero THEN RETURN; -- ray parallel to plane of disk t _ (y - p[2])/d[2]; IF t > 0 THEN { x _ p[1] + t*d[1]; z _ p[3] + t*d[3]; IF x*x + z*z <= r*r THEN success _ TRUE; }; }; -- end of HitsDisk AlmostEqualParams: PRIVATE PROC [t1, t2: REAL] RETURNS [BOOL] = { RETURN[Abs[t2-t1] < 1.0e-2]; }; AlmostEqualHeights: PRIVATE PROC [h1, h2: REAL] RETURNS [BOOL] = { RETURN[Abs[h2-h1] < 1.0]; }; DeleteFromHits: PRIVATE PROC [hits: RevoHitArray, index: NAT] = { <> temp: RevoHitRec _ hits.array[index]; FOR i: NAT IN[index..hits.count-1] DO hits.array[i] _ hits.array[i+1]; ENDLOOP; hits.array[hits.count] _ temp;-- replace the storage for later use hits.count _ hits.count - 1; }; -- end of DeleteFromHits RayGoesIn: PRIVATE PROC [ray: Ray, hit: RevoHitRec] RETURNS [BOOL] = { <> hitPoint: Point3d; plane: Plane; basePt: Point3d; basePtOnNormalSide: BOOL; hitPoint _ SVRay.EvaluateLocalRay[ray, hit.param]; [basePt,] _ SVRay.GetLocalRay[ray]; plane _ SVPolygon3d.PlaneFromPointAndNormal[hitPoint, hit.normal]; basePtOnNormalSide _ SVPolygon3d.PointOnNormalSideOfPlane[basePt, plane]; <> RETURN[basePtOnNormalSide]; }; -- end of RayGoesIn SortLinHits: PROC [hits: LinHitArray] = { temp: LinHitRec; FOR i: NAT IN[1..hits.count-1] DO FOR j: NAT IN[1..hits.count-i] DO IF hits.array[j].param > hits.array[j+1].param THEN { temp _ hits.array[j]; hits.array[j] _ hits.array[j+1]; hits.array[j+1] _ temp;}; ENDLOOP; ENDLOOP; }; SortRevoHits: PROC [hits: RevoHitArray] = { temp: RevoHitRec; FOR i: NAT IN[1..hits.count-1] DO FOR j: NAT IN[1..hits.count-i] DO IF hits.array[j].param > hits.array[j+1].param THEN { temp _ hits.array[j]; hits.array[j] _ hits.array[j+1]; hits.array[j+1] _ temp;}; ENDLOOP; ENDLOOP; }; Abs: PROC [r: REAL] RETURNS [REAL] = { RETURN[IF r >= 0 THEN r ELSE -r]; }; Point3dToPoint2d: PRIVATE PROC [p3: Point3d] RETURNS [p2: Point2d] = { p2[1] _ p3[1]; p2[2] _ p3[2]; }; MakeLinSweepFaces: PUBLIC PROC [linMesh: LinearMesh] RETURNS [faces: LinSweepFaces] = { <> lastPoint, thisPoint: Point2d; seg: SV2d.TrigLineSeg; poly: Polygon _ SVPolygon2d.CreatePoly[linMesh.len]; <> FOR i: NAT IN[1..linMesh.len] DO poly _ SVPolygon2d.AddPolyPoint[poly, [linMesh.array[i][1][1], linMesh.array[i][1][2]] ]; ENDLOOP; <> faces _ NEW[LinSweepFacesObj[linMesh.len]]; faces.len _ linMesh.len; faces.poly _ poly; lastPoint _ Point3dToPoint2d[linMesh.array[linMesh.len][1]]; FOR i: NAT IN[1..linMesh.len] DO thisPoint _ Point3dToPoint2d[linMesh.array[i][1]]; seg _ SVLines2d.CreateTrigLineSeg[lastPoint, thisPoint]; faces[i-1] _ SVFaces.EdgeOnRectFromTrigLineSeg[seg: seg, frontZ: linMesh.array[1][1][3], backZ: linMesh.array[1][2][3]]; lastPoint _ thisPoint; ENDLOOP; }; MakeRevoSweepFaces: PUBLIC PROC [revMesh: RevoluteMesh] RETURNS [faces: RevoSweepFaces] = { <> lastPoint, thisPoint: Point2d; lastLong: NAT _ revMesh.linesOfLongitude; seg: SV2d.TrigLineSeg; faces _ NEW[RevoSweepFacesObj[revMesh.linesOfLatitude+1]]; faces.len _ revMesh.linesOfLatitude+1; <> lastPoint _ Point3dToPoint2d[revMesh.array[1][lastLong]]; seg _ SVLines2d.CreateTrigLineSeg[[0,lastPoint[2]], lastPoint]; faces[0] _ SVFaces.DiskRingFromTrigLineSeg[seg]; FOR i: NAT IN[2..revMesh.linesOfLatitude] DO -- the intermediate faces thisPoint _ Point3dToPoint2d[revMesh.array[i][lastLong]]; seg _ SVLines2d.CreateTrigLineSeg[lastPoint, thisPoint]; SELECT seg.line.theta FROM 0, 180 => -- make a disk faces[i-1] _ SVFaces.DiskRingFromTrigLineSeg[seg]; IN (0..90), IN (90..180), IN (-90..0), IN (-180..-90) => -- make a cone faces[i-1] _ SVFaces.ConeFromTrigLineSeg[seg]; 90, -90 => -- make a cylinder faces[i-1] _ SVFaces.CylinderFromTrigLineSeg[seg]; ENDCASE => ERROR; lastPoint _ thisPoint; ENDLOOP; <> seg _ SVLines2d.CreateTrigLineSeg[lastPoint, [0,lastPoint[2]]]; faces[revMesh.linesOfLatitude] _ SVFaces.DiskRingFromTrigLineSeg[seg]; faces.mesh _ revMesh; }; RayXYPolygon: PRIVATE PROC [localRay: Ray, poly: Polygon, depth: REAL, normal: Vector3d] RETURNS [linHit: FaceHitRec] = { <> <> <<(z-p3)/d3 = t;>> x, y, z, t: REAL; pointClass: SVPolygon2d.PointPolyClass; p: Point3d; d: Vector3d; linHit _ SVFacesCast.GetFaceHitFromPool[]; [p, d] _ SVRay.GetLocalRay[localRay]; z _ depth; IF Abs[d[3]] < almostZero THEN {linHit.count _ 0; RETURN}; t _ (z - p[3])/d[3]; IF t <= 0 THEN {linHit.count _ 0; RETURN}; x _ p[1] + t*d[1]; y _ p[2] + t*d[2]; pointClass _ SVPolygon2d.BoysePointInPoly[[x,y], poly]; IF pointClass = in OR pointClass = on THEN { linHit.count _ 1; linHit.params[1] _ t; linHit.normals[1] _ normal; } ELSE linHit.count _ 0; }; -- end of RayXYPolygon Init: PROC = { globalRevoHits _ NEW[RevoHitArrayObj]; globalRevoHits.count _ 0; FOR i: NAT IN[1..SVSweepGeometry.maxLinesOfLat+1] DO globalRevoHits.array[i] _ NEW[RevoHitRecObj]; ENDLOOP; globalLinHits _ NEW[LinHitArrayObj]; globalLinHits.count _ 0; FOR i: NAT IN[1..SVSweepGeometry.maxMeshLen-1] DO globalLinHits.array[i] _ NEW[LinHitRecObj]; ENDLOOP; }; Init[]; END.