<> <> <> <> <<>> DIRECTORY AtomButtonsTypes, CodeTimer, SVCoordSys, SVSceneToTree, Feedback, IO, SVMatrix3d, SVPreprocess3d, Real, RealFns, Rope, SV2d, SV3d, SVAssembly, SVCaret, SVCastRays, SVGravity, SVInterfaceTypes, SVLines3d, SVModelTypes, SVRay, SVScene, SVSceneTypes, SVSpheres, SVState, SVVector3d; SVGravityImpl: CEDAR PROGRAM IMPORTS CodeTimer, SVCoordSys, SVSceneToTree, Feedback, SVMatrix3d, SVPreprocess3d, RealFns, SVAssembly, SVCaret, SVCastRays, SVLines3d, SVRay, SVSpheres, SVState, SVVector3d EXPORTS SVGravity = BEGIN AlignBag: TYPE = SVInterfaceTypes.AlignBag; AlignmentLine: TYPE = SVInterfaceTypes.AlignmentLine; AlignmentPoint: TYPE = REF AlignmentPointObj; AlignmentPointObj: TYPE = SVInterfaceTypes.AlignmentPointObj; AlignmentSphere: TYPE = SVInterfaceTypes.AlignmentSphere; Camera: TYPE = SVSceneTypes.Camera; Classification: TYPE = SVSceneTypes.Classification; CSGTree: TYPE = SVSceneTypes.CSGTree; Edge3d: TYPE = SV3d.Edge3d; FeatureCycler: TYPE = REF FeatureCyclerObj; FeatureCyclerObj: TYPE = SVInterfaceTypes.FeatureCyclerObj; FeatureData: TYPE = REF FeatureDataObj; FeatureDataObj: TYPE = SVSceneTypes.FeatureDataObj; FeedbackData: TYPE = AtomButtonsTypes.FeedbackData; GoodPoint: TYPE = REF GoodPointObj; GoodPointObj: TYPE = SVInterfaceTypes.GoodPointObj; GravityType: TYPE = SVInterfaceTypes.GravityType; Line3d: TYPE = SV3d.Line3d; MasterObject: TYPE = SVSceneTypes.MasterObject; Matrix4by4: TYPE = SV3d.Matrix4by4; NearDistances: TYPE = REF NearDistancesObj; NearDistancesObj: TYPE = SVGravity.NearDistancesObj; NearFeatures: TYPE = REF NearFeaturesObj; NearFeaturesObj: TYPE = SVGravity.NearFeaturesObj; NearVertexEdgeAndFaces: TYPE = REF NearVertexEdgeAndFacesObj; NearVertexEdgeAndFacesObj: TYPE = SVInterfaceTypes.NearVertexEdgeAndFacesObj; Point2d: TYPE = SV2d.Point2d; Point3d: TYPE = SV3d.Point3d; PointAndDone: TYPE = SVSceneTypes.PointAndDone; PointGenerator: TYPE = SVSceneTypes.PointGenerator; Primitive: TYPE = SVSceneTypes.Primitive; Ray: TYPE = SVSceneTypes.Ray; Scene: TYPE = SVSceneTypes.Scene; SearchDepth: TYPE = SVSceneTypes.SearchDepth; Shape: TYPE = SVSceneTypes.Shape; Skitter: TYPE = SVSceneTypes.Skitter; Slice: TYPE = SVSceneTypes.Slice; SliceDescriptor: TYPE = SVSceneTypes.SliceDescriptor; Sphere: TYPE = SV3d.Sphere; TriggerBag: TYPE = SVInterfaceTypes.TriggerBag; Vector3d: TYPE = SV3d.Vector3d; SVData: TYPE = SVInterfaceTypes.SVData; Problem: PUBLIC SIGNAL [msg: Rope.ROPE] = Feedback.Problem; maxFeatures: NAT _ 20; BestPoints: TYPE = REF BestPointsObj; BestPointsObj: TYPE = RECORD [ size: NAT _ 0, max, min: REAL, bestTossed: REAL, -- the distance of the closest object that has been thrown away dTol: REAL, -- min + s innerR: REAL, -- find all curves within this radius even if they are not neighbors of the nearest s: REAL, -- the size of neighborhoods. BestPoints should contain all objects that have been seen such that min <= dist(o, q) <= min+s, unless BestPoints overflows. overflow: BOOL, points: SEQUENCE len: NAT OF GoodPoint]; MultiGravityPool: TYPE = REF MultiGravityPoolObj; MultiGravityPoolObj: TYPE = RECORD [ distances: NearDistances, features: NearFeatures, bestpoints: BestPoints, bestcurves: BestPoints, bestfaces: BestPoints ]; EmptyBag: PROC [alignBag: AlignBag] RETURNS [BOOL] = { RETURN[ alignBag.slopeLines = NIL AND alignBag.slopePlanes = NIL AND alignBag.anchor = NIL]; }; EmptyTriggers: PROC [triggerBag: TriggerBag] RETURNS [BOOL] = { RETURN[ triggerBag.slices = NIL AND triggerBag.anchor = NIL ]; }; RayMap: PUBLIC PROC [cameraPt: Point2d, t: REAL, alignBag: AlignBag, sceneBag: TriggerBag, svData: SVData, intersections: BOOL _ FALSE] RETURNS [surfacePtWorld: Point3d, normalWorld: Vector3d, feature: FeatureData, hitData: REF ANY] = { gravityType: GravityType _ SVState.GetGravityType[svData]; camera: Camera _ svData.camera; CodeTimer.StartInt[$RayMap, $Solidviews]; IF SVState.GetGravity[svData] THEN { SELECT gravityType FROM facesPreferred => [surfacePtWorld, normalWorld, feature, hitData] _ FacesPreferred[cameraPt, t, alignBag, sceneBag, svData]; linesPreferred => [surfacePtWorld, normalWorld, feature, hitData] _ LinesPreferred[cameraPt, t, alignBag, sceneBag, svData, intersections]; pointsPreferred => [surfacePtWorld, normalWorld, feature, hitData] _ PointsPreferred[cameraPt, t, alignBag, sceneBag, svData, intersections]; ENDCASE => ERROR; } ELSE { parallel: BOOL; [surfacePtWorld, normalWorld, parallel] _ RayMeetsCentralCameraPlane[cameraPt, camera]; feature _ NIL; hitData _ NIL; }; CodeTimer.StopInt[$RayMap, $Solidviews]; }; RayMapCycler: PUBLIC PROC [cameraPt: Point2d, t: REAL, alignBag: AlignBag, sceneBag: TriggerBag, svData: SVData, intersections: BOOL _ FALSE] RETURNS [featureCycler: FeatureCycler] = { gravityType: GravityType _ SVState.GetGravityType[svData]; camera: Camera _ svData.camera; IF SVState.GetGravity[svData] THEN { SELECT gravityType FROM facesPreferred => featureCycler _ FacesPreferredCycler[cameraPt, t, alignBag, sceneBag, svData]; linesPreferred => featureCycler _ LinesPreferredCycler[cameraPt, t, alignBag, sceneBag, svData, intersections]; pointsPreferred => featureCycler _ PointsPreferredCycler[cameraPt, t, alignBag, sceneBag, svData, intersections]; ENDCASE => ERROR; } ELSE { featureCycler _ EmptyCycler[cameraPt, camera]; }; }; EmptyCycler: PROC [cameraPt: Point2d, camera: Camera] RETURNS [featureCycler: FeatureCycler] = { featureCycler _ NEW[FeatureCyclerObj _ [ nearVEF: NIL, count: 0, index: -1, cameraPt: cameraPt, camera: camera ]]; }; FacesPreferred: PUBLIC PROC [cameraPt: Point2d, t: REAL, alignBag: AlignBag, sceneBag: TriggerBag, svData: SVData] RETURNS [surfacePtWorld: Point3d, normalWorld: Vector3d, feature: FeatureData, hitData: REF ANY] = { <> nearVEF: NearVertexEdgeAndFaces; camera: Camera _ svData.camera; count: NAT; [nearVEF, count] _ MultiFacesPreferred[cameraPt, t, alignBag, sceneBag, svData]; IF count = 0 THEN { parallel: BOOL; [surfacePtWorld, normalWorld, parallel] _ RayMeetsCentralCameraPlane[cameraPt, camera]; hitData _ NIL; RETURN; }; <> RETURN PrepareWinner[nearVEF, 0]; }; LinesPreferred: PUBLIC PROC [cameraPt: Point2d, t: REAL, alignBag: AlignBag, sceneBag: TriggerBag, svData: SVData, intersections: BOOL] RETURNS [surfacePtWorld: Point3d, normalWorld: Vector3d, feature: FeatureData, hitData: REF ANY] = { <> <> <> nearVEF: NearVertexEdgeAndFaces; count: NAT; camera: Camera _ svData.camera; [nearVEF, count] _ MultiLinesPreferred[cameraPt, t, alignBag, sceneBag, svData, intersections]; IF count = 0 THEN { parallel: BOOL; [surfacePtWorld, normalWorld, parallel] _ RayMeetsCentralCameraPlane[cameraPt, camera]; feature _ NIL; hitData _ NIL; RETURN; }; IF count = 1 THEN RETURN PrepareWinner[nearVEF, 0] ELSE { <> nearestDist: REAL _ -1; bestSceneObject: INT _ -1; neighborCount: NAT _ 1; s: REAL = 0.072; -- 1/1000 inches nearestDist _ nearVEF[0].dist; <> FOR i: NAT IN [1..count) DO IF nearVEF[i].dist - nearestDist < s THEN neighborCount _ neighborCount + 1; ENDLOOP; IF neighborCount = 1 THEN RETURN PrepareWinner[nearVEF, 0]; bestSceneObject _ -1; RETURN PrepareWinner[nearVEF, 0]; }; }; PointsPreferred: PUBLIC PROC [cameraPt: Point2d, t: REAL, alignBag: AlignBag, sceneBag: TriggerBag, svData: SVData, intersections: BOOL] RETURNS [surfacePtWorld: Point3d, normalWorld: Vector3d, feature: FeatureData, hitData: REF ANY] = { count: NAT; nearVEF: NearVertexEdgeAndFaces; [nearVEF, count] _ MultiPointsPreferred[cameraPt, t, alignBag, sceneBag, svData, intersections]; IF count = 0 THEN { parallel: BOOL; camera: Camera _ svData.camera; [surfacePtWorld, normalWorld, parallel] _ RayMeetsCentralCameraPlane[cameraPt, camera]; feature _ NIL; hitData _ NIL; RETURN; }; IF count = 1 THEN RETURN PrepareWinner[nearVEF, 0] ELSE { <> neighborCount: NAT _ 1; s: REAL = 0.072; -- 1/1000 inches nearestDist: REAL _ -1; nearestDist _ nearVEF[0].dist; FOR i: NAT IN [1..count) DO IF nearVEF[i].dist - nearestDist < s THEN neighborCount _ neighborCount + 1; ENDLOOP; IF neighborCount = 1 THEN RETURN PrepareWinner[nearVEF, 0]; FOR i: NAT IN [0..neighborCount) DO IF nearVEF[i].featureData.type = slice THEN { RETURN PrepareWinner[nearVEF, i]; }; REPEAT FINISHED => RETURN PrepareWinner[nearVEF, 0]; ENDLOOP; }; }; PrepareWinner: PROC [nearVEF: NearVertexEdgeAndFaces, index: NAT] RETURNS [surfacePtWorld: Point3d, normalWorld: Vector3d, feature: FeatureData, hitData: REF ANY] = { goodPoint: GoodPoint _ nearVEF[index]; surfacePtWorld _ goodPoint.point; normalWorld _ goodPoint.normal; feature _ goodPoint.featureData; hitData _ goodPoint.hitData; }; FacesPreferredCycler: PUBLIC PROC [cameraPt: Point2d, t: REAL, alignBag: AlignBag, sceneBag: TriggerBag, svData: SVData] RETURNS [featureCycler: FeatureCycler] = { <> nearVEF: NearVertexEdgeAndFaces; camera: Camera _ svData.camera; count: NAT; [nearVEF, count] _ MultiFacesPreferred[cameraPt, t, alignBag, sceneBag, svData]; IF count = 0 THEN RETURN[EmptyCycler[cameraPt, camera]]; <> featureCycler _ NEW[FeatureCyclerObj _ [ nearVEF: nearVEF, count: count, index: 0, cameraPt: cameraPt, camera: camera ]]; }; LinesPreferredCycler: PUBLIC PROC [cameraPt: Point2d, t: REAL, alignBag: AlignBag, sceneBag: TriggerBag, svData: SVData, intersections: BOOL, maxDimension: [0..2] _ 2] RETURNS [featureCycler: FeatureCycler] = { <> <> <> nearVEF: NearVertexEdgeAndFaces; count: NAT; camera: Camera _ svData.camera; BEGIN [nearVEF, count] _ MultiLinesPreferred[cameraPt, t, alignBag, sceneBag, svData, intersections, maxDimension]; IF count = 0 THEN RETURN[EmptyCycler[cameraPt, camera]]; IF count = 1 THEN GOTO MakeSimpleCycler ELSE { <> nearestDist: REAL _ -1; bestSceneObject: INT _ -1; neighborCount: NAT _ 1; s: REAL = 0.072; -- 1/1000 inches nearestDist _ nearVEF[0].dist; <> FOR i: NAT IN [1..count) DO IF nearVEF[i].dist - nearestDist < s THEN neighborCount _ neighborCount + 1; ENDLOOP; IF neighborCount = 1 THEN GOTO MakeSimpleCycler; bestSceneObject _ -1; featureCycler _ NEW[FeatureCyclerObj _ [ nearVEF: nearVEF, count: count, index: 0, cameraPt: cameraPt, camera: camera ]]; }; EXITS MakeSimpleCycler => { featureCycler _ NEW[FeatureCyclerObj _ [ nearVEF: nearVEF, count: count, index: 0, cameraPt: cameraPt, camera: camera ]]; }; END; }; PointsPreferredCycler: PUBLIC PROC [cameraPt: Point2d, t: REAL, alignBag: AlignBag, sceneBag: TriggerBag, svData: SVData, intersections: BOOL, maxDimension: [0..2] _ 2] RETURNS [featureCycler: FeatureCycler] = { count: NAT; nearVEF: NearVertexEdgeAndFaces; camera: Camera _ svData.camera; BEGIN [nearVEF, count] _ MultiPointsPreferred[cameraPt, t, alignBag, sceneBag, svData, intersections, maxDimension]; IF count = 0 THEN RETURN[EmptyCycler[cameraPt, camera]]; IF count = 1 THEN GOTO MakeSimpleCycler ELSE { <> neighborCount: NAT _ 1; s: REAL = 0.072; -- 1/1000 inches nearestDist: REAL _ -1; featureCycler _ NEW[FeatureCyclerObj _ [ nearVEF: nearVEF, count: count, index: -1,-- will be filled in below cameraPt: cameraPt, camera: camera ]]; nearestDist _ nearVEF[0].dist; FOR i: NAT IN [1..count) DO IF nearVEF[i].dist - nearestDist < s THEN neighborCount _ neighborCount + 1; ENDLOOP; IF neighborCount = 1 THEN GOTO MakeSimpleCycler; FOR i: NAT IN [0..neighborCount) DO IF nearVEF[i].featureData.type = slice THEN { featureCycler.index _ i; RETURN; }; REPEAT FINISHED => featureCycler.index _ 0; ENDLOOP; }; EXITS MakeSimpleCycler => { featureCycler _ NEW[FeatureCyclerObj _ [ nearVEF: nearVEF, count: count, index: 0, cameraPt: cameraPt, camera: camera ]]; }; END; }; FirstFeature: PUBLIC PROC [featureCycler: FeatureCycler] RETURNS [surfacePtWorld: Point3d, normalWorld: Vector3d, feature: FeatureData, hitData: REF ANY] = { RETURN GetFeature[featureCycler, 0]; }; NextFeature: PUBLIC PROC [featureCycler: FeatureCycler] RETURNS [surfacePtWorld: Point3d, normalWorld: Vector3d, feature: FeatureData, hitData: REF ANY] = { RETURN GetFeature[featureCycler, 1]; }; PreviousFeature: PUBLIC PROC [featureCycler: FeatureCycler] RETURNS [surfacePtWorld: Point3d, normalWorld: Vector3d, feature: FeatureData, hitData: REF ANY] = { RETURN GetFeature[featureCycler, -1]; }; GetFeature: PUBLIC PROC [featureCycler: FeatureCycler, move: [-1..1]] RETURNS [surfacePtWorld: Point3d, normalWorld: Vector3d, feature: FeatureData, hitData: REF ANY] = { IF featureCycler.count = 0 THEN { -- return a backdrop position parallel: BOOL; cameraPt: Point2d _ featureCycler.cameraPt; camera: Camera _ featureCycler.camera; [surfacePtWorld, normalWorld, parallel] _ RayMeetsCentralCameraPlane[cameraPt, camera]; feature _ NIL; hitData _ NIL; } ELSE { featureCycler.index _ (featureCycler.index + move + featureCycler.count) MOD featureCycler.count; [surfacePtWorld, normalWorld, feature, hitData] _ PrepareWinner[featureCycler.nearVEF, featureCycler.index]; }; }; MultiFacesPreferred: PROC [cameraPt: Point2d, t: REAL, alignBag: AlignBag, sceneBag: TriggerBag, svData: SVData] RETURNS [nearVEF: NearVertexEdgeAndFaces, count: NAT] = { camera: Camera _ svData.camera; bestFaces: BestPoints; [bestFaces, count] _ FacesInNeighborhoodPlus[alignBag, sceneBag, cameraPt, svData, t]; IF count > 0 THEN { nearVEF _ NEW[NearVertexEdgeAndFacesObj[count]]; FOR i: NAT IN [0..count) DO nearVEF[i] _ bestFaces[i]; ENDLOOP; }; }; MultiLinesPreferred: PUBLIC PROC [cameraPt: Point2d, t: REAL, alignBag: AlignBag, sceneBag: TriggerBag, svData: SVData, intersections: BOOL, maxDimension: [0..2] _ 2] RETURNS [nearVEF: NearVertexEdgeAndFaces, count: NAT] = { <> bestVerts, bestEdges, bestFaces: BestPoints; vertCount, edgeCount, faceCount, veCount: NAT; IF EmptyBag[alignBag] AND EmptyTriggers[sceneBag] THEN RETURN[NIL, 0]; IF maxDimension >= 2 THEN { [bestFaces, faceCount] _ FacesInNeighborhoodPlus[alignBag, sceneBag, cameraPt, svData, t]; SortFaces[bestFaces, faceCount]; } ELSE faceCount _ 0; [bestEdges, edgeCount] _ EdgesInNeighborhoodPlus[alignBag, sceneBag, cameraPt, svData, t, 0]; SortCurves[bestEdges, edgeCount]; [bestVerts, vertCount] _ VertsInNeighborhoodPlus[NIL, 0, NIL, 0, alignBag, sceneBag, cameraPt, t, svData, FALSE]; SortPoints[bestVerts, vertCount]; veCount _ MIN[vertCount + edgeCount, maxFeatures]; count _ MIN[veCount + faceCount, maxFeatures]; nearVEF _ NEW[NearVertexEdgeAndFacesObj[count]]; MergePointsAndCurves[bestVerts, vertCount, bestEdges, edgeCount, nearVEF, veCount]; MergeVEWithFaces[bestFaces, faceCount, nearVEF, veCount, maxFeatures]; }; MultiPointsPreferred: PUBLIC PROC [cameraPt: Point2d, t: REAL, alignBag: AlignBag, sceneBag: TriggerBag, svData: SVData, intersections: BOOL, maxDimension: [0..2] _ 2] RETURNS [nearVEF: NearVertexEdgeAndFaces, count: NAT] = { bestVerts, bestEdges, bestFaces: BestPoints; vertCount, edgeCount, faceCount, veCount: NAT; innerR: REAL _ t/2.0; IF EmptyBag[alignBag] AND EmptyTriggers[sceneBag] THEN RETURN[NIL, 0]; IF maxDimension >= 2 THEN { [bestFaces, faceCount] _ FacesInNeighborhoodPlus[alignBag, sceneBag, cameraPt, svData, t]; SortFaces[bestFaces, faceCount]; } ELSE faceCount _ 0; [bestEdges, edgeCount] _ EdgesInNeighborhoodPlus[alignBag, sceneBag, cameraPt, svData, t, innerR]; SortCurves[bestEdges, edgeCount]; [bestVerts, vertCount] _ VertsInNeighborhoodPlus[bestFaces, faceCount, bestEdges, edgeCount, alignBag, sceneBag, cameraPt, t, svData, intersections]; SortPoints[bestVerts, vertCount]; IF vertCount > 0 AND bestVerts[0].dist < innerR THEN { count _ vertCount; nearVEF _ NEW[NearVertexEdgeAndFacesObj[count]]; NearPointsFromPoints[bestVerts, vertCount, nearVEF]; } ELSE { veCount _ MIN[vertCount + edgeCount, maxFeatures]; count _ MIN[veCount + faceCount, maxFeatures]; nearVEF _ NEW[NearVertexEdgeAndFacesObj[count]]; MergePointsAndCurves[bestVerts, vertCount, bestEdges, edgeCount, nearVEF, veCount]; MergeVEWithFaces[bestFaces, faceCount, nearVEF, veCount, maxFeatures]; }; }; ResultsFromClassification: PROC [class: Classification, rayWorld: Ray, sceneBag: TriggerBag, searchDepth: NAT] RETURNS [surfacePtWorld: Point3d, normalWorld: Vector3d, feature: FeatureData, hitData: REF ANY] = { primitive: Primitive; assembly: Slice; [assembly, primitive] _ SVCastRays.NthAssemblyAndPrimitive[class, searchDepth]; IF class.count > 0 THEN [surfacePtWorld, normalWorld] _ SVCastRays.NthSurfacePointAndNormal[class, rayWorld, searchDepth]; feature _ FindFeature[assembly, sceneBag]; hitData _ SVCastRays.NthHitData[class, searchDepth]; }; FaceResultsFromClassification: PROC [class: Classification, rayShape: Ray] RETURNS [theseIFrames: LIST OF Matrix4by4, thisTangency: LIST OF BOOL] = { surfacePtWorld: Point3d; normalWorld: Vector3d; thisMat: Matrix4by4; theseIFrames _ NIL; thisTangency _ NIL; FOR i: NAT IN [1..class.count] DO [surfacePtWorld, normalWorld] _ SVCastRays.NthSurfacePointAndNormal[class, rayShape, i]; thisMat _ SVMatrix3d.MakeHorizontalMatFromZAxis[normalWorld, surfacePtWorld]; theseIFrames _ CONS[thisMat, theseIFrames]; thisTangency _ CONS[FALSE, thisTangency]; ENDLOOP; }; FacesInNeighborhoodPlus: PROC [alignBag: AlignBag, sceneBag: TriggerBag, cameraPt: Point2d, svData: SVData, t: REAL] RETURNS [h: BestPoints, count: NAT] = { CountStillFaces: PROC [class: Classification] RETURNS [stillCount: NAT _ 0] = { FOR i: NAT IN [1..class.count] DO IF class.stills[i] THEN stillCount _ stillCount + 1; ENDLOOP; }; goodPoint: GoodPoint _ NEW[GoodPointObj]; camera: Camera _ svData.camera; class: Classification; rayWorld: Ray; rayWorld _ GetWorldRayFromCameraPoint[cameraPt, camera]; -- from pool <> class _ SingleRay[rayWorld, cameraPt, sceneBag, camera, TRUE, NIL]; -- class from pool count _ CountStillFaces[class]; h _ BestFacesFromPool[svData]; FOR i: NAT IN [1..class.count] DO IF class.stills[i] THEN { [goodPoint.point, goodPoint.normal, goodPoint.featureData, goodPoint.hitData] _ ResultsFromClassification[class, rayWorld, sceneBag, i]; goodPoint.dist _ 0.0; goodPoint.dimension _ 2; MergeFace[goodPoint, h]; }; ENDLOOP; SVCastRays.ReturnClassToPool[class]; <> BEGIN points: ARRAY [1..2] OF Point3d; normals: ARRAY [1..2] OF Vector3d; hitCount: [0..2]; tangent: BOOL; FOR list: LIST OF FeatureData _ alignBag.spheres, list.rest UNTIL list = NIL DO alignmentSphere: AlignmentSphere _ NARROW[list.first.shape]; sphere: Sphere _ alignmentSphere.sphere; [points, normals, hitCount, tangent] _ SVSpheres.SphereMeetsRay[sphere, rayWorld]; FOR i: NAT IN [1..hitCount] DO goodPoint.point _ points[i]; goodPoint.normal _ normals[i]; goodPoint.featureData _ list.first; goodPoint.hitData _ NIL; goodPoint.dist _ 0.0; goodPoint.dimension _ 2; MergeFace[goodPoint, h]; count _ count + 1; ENDLOOP; ENDLOOP; END; SVRay.ReturnRayToPool[rayWorld]; }; EdgesInNeighborhoodPlus: PROC [alignBag: AlignBag, sceneBag: TriggerBag, q: Point2d, svData: SVData, t: REAL, innerR: REAL] RETURNS [h: BestPoints, curveCount: NAT] = { ProcessSlice: PROC [sliceD: SliceDescriptor, thisCurve: GoodPoint, featureData: FeatureData] = { success: BOOL; [thisCurve.dist, thisCurve.point, thisCurve.normal, thisCurve.hitData, success] _ SVAssembly.ClosestSegmentToLine[sliceD, q, line3d, t, camera]; IF success AND thisCurve.dist < t THEN { thisCurve.featureData _ featureData; thisCurve.dimension _ 1; dTol _ MergeCurve[thisCurve, h]; }; }; ProcessLine: PROC [line: Line3d, thisCurve: GoodPoint, featureData: FeatureData] = { thisCurve.dist _ SVLines3d.DistanceLineToLine[line, line3d]; IF thisCurve.dist < t THEN { pAlignment, pRay: Point3d; parallel: BOOL; thisCurve.featureData _ featureData; [pAlignment, pRay, parallel] _ SVLines3d.NearLinePoints[line, line3d]; thisCurve.point _ pAlignment; thisCurve.normal _ SVVector3d.Sub[pRay, pAlignment]; thisCurve.hitData _ NIL; dTol _ MergeCurve[thisCurve, h]; } }; line: Line3d; <> sliceD: SliceDescriptor; featureData: FeatureData; added: BOOL _ FALSE; thisCurve: GoodPoint _ NEW[GoodPointObj]; dTol: REAL _ t; camera: Camera _ svData.camera; line3d: Line3d; rayWorld: Ray _ GetWorldRayFromCameraPoint[q, camera]; -- from pool h _ BestCurvesFromPool[svData, t, innerR]; line3d _ LineFromRay[rayWorld]; <> FOR slopeLines: LIST OF FeatureData _ alignBag.slopeLines, slopeLines.rest UNTIL slopeLines = NIL DO featureData _ slopeLines.first; line _ NARROW[featureData.shape, AlignmentLine].line; ProcessLine[line, thisCurve, featureData]; ENDLOOP; <> FOR slices: LIST OF FeatureData _ sceneBag.slices, slices.rest UNTIL slices = NIL DO featureData _ slices.first; sliceD _ NARROW[featureData.shape, SliceDescriptor]; ProcessSlice[sliceD, thisCurve, featureData]; ENDLOOP; curveCount _ h.size; IF h.overflow THEN { CodeTimer.StartInt[$CurveOverflow, $Solidviews]; CodeTimer.StopInt[$CurveOverflow, $Solidviews]; }; SVRay.ReturnRayToPool[rayWorld]; }; -- end CurvesInNeighborhoodPlus VertsInNeighborhoodPlus: PROC [bestFaces: BestPoints, faceCount: NAT, bestCurves: BestPoints, curveCount: NAT, alignBag: AlignBag, sceneBag: TriggerBag, q: Point2d, t: REAL, svData: SVData, intersections: BOOL] RETURNS [h: BestPoints, pointCount: NAT] = { thisPoint: GoodPoint; ProcessPoint: PROC [thisPoint: GoodPoint, featureData: FeatureData] = { -- used for the anchor dSquared: REAL; dTolSquared: REAL _ dTol*dTol; dSquared _ SVLines3d.Distance2PointToLine[thisPoint.point, line3d]; thisPoint.hitData _ NIL; IF dSquared < dTolSquared THEN { anchor: Skitter _ NARROW[featureData.shape]; thisPoint.dist _ RealFns.SqRt[dSquared]; thisPoint.normal _ SVMatrix3d.ZAxisOfMatrix[SVCaret.GetPosition[anchor]]; thisPoint.featureData _ featureData; dTol _ MergePoint[thisPoint, h]; }; }; ProcessSlice: PROC [sliceD: SliceDescriptor, thisPoint: GoodPoint, featureData: FeatureData] = { [thisPoint.dist, thisPoint.point, thisPoint.normal, thisPoint.hitData, success] _ SVAssembly.ClosestPointToLine[sliceD, q, line3d, dTol, camera, TRUE]; IF success AND thisPoint.dist < dTol THEN { thisPoint.featureData _ featureData; thisPoint.dimension _ 0; dTol _ MergePoint[thisPoint, h]; }; }; sliceD: SliceDescriptor; featureData: FeatureData; success: BOOL _ FALSE; dTol: REAL _ t; midpoints: BOOL _ SVState.GetMidpoints[svData]; camera: Camera _ svData.camera; line3d: Line3d; rayWorld: Ray _ GetWorldRayFromCameraPoint[q, camera]; -- from pool thisPoint _ NEW[GoodPointObj]; h _ BestPointsFromPool[svData, t]; line3d _ LineFromRay[rayWorld]; IF intersections THEN dTol _ FindIntersections[bestFaces, faceCount, bestCurves, curveCount, thisPoint, line3d, dTol, h]; <> <> FOR slices: LIST OF FeatureData _ sceneBag.slices, slices.rest UNTIL slices = NIL DO featureData _ slices.first; sliceD _ NARROW[featureData.shape, SliceDescriptor]; ProcessSlice[sliceD, thisPoint, featureData]; ENDLOOP; featureData _ alignBag.anchor; IF featureData # NIL THEN { anchor: Skitter _ NARROW[featureData.shape]; IF NOT SVCaret.Exists[anchor] THEN ERROR; thisPoint.point _ SVMatrix3d.OriginOfMatrix[SVCaret.GetPosition[anchor]]; ProcessPoint[thisPoint, featureData]; }; pointCount _ h.size; IF h.overflow THEN { CodeTimer.StartInt[$PointOverflow, $Solidviews]; CodeTimer.StopInt[$PointOverflow, $Solidviews]; }; SVRay.ReturnRayToPool[rayWorld]; }; <<>> FindIntersections: PROC [bestFaces: BestPoints, faceCount: NAT, bestCurves: BestPoints, curveCount: NAT, thisPoint: GoodPoint, line: Line3d, tolerance: REAL, h: BestPoints] RETURNS [dTol: REAL] = { curveI, curveJ, faceJ: GoodPoint; theseIFrames: LIST OF Matrix4by4; thisTangency, tangentList: LIST OF BOOL; success: BOOL; dTol _ tolerance; <> FOR i: NAT IN [0..curveCount) DO curveI _ bestCurves[i]; FOR j: NAT IN [i+1..curveCount) DO curveJ _ bestCurves[j]; [theseIFrames, thisTangency] _ CurveMeetsCurve[curveI, curveJ]; tangentList _ thisTangency; <> FOR list: LIST OF Matrix4by4 _ theseIFrames, list.rest UNTIL list = NIL DO thisPoint.point _ SVMatrix3d.OriginOfMatrix[list.first]; thisPoint.normal _ SVMatrix3d.ZAxisOfMatrix[list.first]; thisPoint.dist _ SVLines3d.DistancePointToLine[thisPoint.point, line]; success _ thisPoint.dist <= tolerance; IF success THEN { featureData: FeatureData _ NEW[FeatureDataObj]; alignmentPoint: AlignmentPoint _ NEW[AlignmentPointObj _ [ point: thisPoint.point, tangent: tangentList.first, curve1: curveI.featureData, curve2: curveJ.featureData]]; featureData.type _ intersectionPoint; featureData.shape _ alignmentPoint; thisPoint.featureData _ featureData; IF curveI.featureData.type = slice THEN { thisPoint.hitData _ curveI.hitData; } ELSE IF curveJ.featureData.type = slice THEN { thisPoint.hitData _ curveJ.hitData; } ELSE thisPoint.hitData _ NIL; dTol _ MergePoint[thisPoint, h]; }; tangentList _ tangentList.rest; ENDLOOP; ENDLOOP; ENDLOOP; <> FOR i: NAT IN [0..curveCount) DO curveI _ bestCurves[i]; FOR j: NAT IN [0..faceCount) DO faceJ _ bestFaces[j]; [theseIFrames, thisTangency] _ CurveMeetsFace[curveI, faceJ]; tangentList _ thisTangency; <> FOR list: LIST OF Matrix4by4 _ theseIFrames, list.rest UNTIL list = NIL DO thisPoint.point _ SVMatrix3d.OriginOfMatrix[list.first]; thisPoint.normal _ SVMatrix3d.ZAxisOfMatrix[list.first]; thisPoint.dist _ SVLines3d.DistancePointToLine[thisPoint.point, line]; success _ thisPoint.dist <= tolerance; IF success THEN { featureData: FeatureData _ NEW[FeatureDataObj]; alignmentPoint: AlignmentPoint _ NEW[AlignmentPointObj _ [ point: thisPoint.point, tangent: tangentList.first, curve1: curveI.featureData, curve2: faceJ.featureData]]; featureData.type _ intersectionPoint; featureData.shape _ alignmentPoint; thisPoint.featureData _ featureData; IF curveI.featureData.type = slice THEN { thisPoint.hitData _ curveI.hitData; } ELSE IF faceJ.featureData.type = slice THEN { thisPoint.hitData _ faceJ.hitData; } ELSE thisPoint.hitData _ NIL; dTol _ MergePoint[thisPoint, h]; }; tangentList _ tangentList.rest; ENDLOOP; ENDLOOP; ENDLOOP; }; MergePoint: PROC [thisPoint: GoodPoint, h: BestPoints] RETURNS [dTol: REAL] = { d: REAL _ thisPoint.dist; n: NAT = maxFeatures; BEGIN SELECT TRUE FROM h.size < n => GOTO Add; h.size = n AND d <= h.dTol => GOTO ReplaceOrOverflow; h.size = n AND d > h.dTol => GOTO Toss; -- the caller is not taking our hints and is passing us trash ENDCASE => SIGNAL Problem[msg: "Impossible case."]; EXITS Add => { h[h.size]^ _ thisPoint^; h.size _ h.size + 1; h.min _ MIN[h.min, d]; dTol _ h.dTol _ h.min+h.s; }; ReplaceOrOverflow => { iWorst: NAT; worstDist: REAL _ 0.0; <> iWorst _ 0; worstDist _ 0.0; FOR i: NAT IN [0..maxFeatures-1] DO IF h[i].dist > worstDist THEN {iWorst _ i; worstDist _ h[i].dist}; ENDLOOP; IF d < worstDist THEN { -- do the replace h[iWorst].dist _ d; h[iWorst]^ _ thisPoint^; h.bestTossed _ MIN[h.bestTossed, worstDist]; h.min _ MIN[h.min, d]; dTol _ h.dTol _ h.min+h.s; h.overflow _ h.bestTossed <= dTol; } ELSE { -- toss the new item dTol _ h.dTol; h.bestTossed _ MIN[h.bestTossed, d]; h.overflow _ TRUE; }; }; Toss => { dTol _ h.dTol; h.bestTossed _ MIN[h.bestTossed, d]; h.overflow _ h.bestTossed <= dTol; }; END; }; MergeCurve: PROC [thisPoint: GoodPoint, h: BestPoints] RETURNS [dTol: REAL] = { d: REAL _ thisPoint.dist; n: NAT = maxFeatures; BEGIN SELECT TRUE FROM h.size < n => GOTO Add; h.size = n AND d <= h.dTol => GOTO ReplaceOrOverflow; h.size = n AND d > h.dTol => GOTO Toss; -- the caller is not taking our hints and is passing us trash ENDCASE => SIGNAL Problem[msg: "Impossible case."]; EXITS Add => { h[h.size]^ _ thisPoint^; h.size _ h.size + 1; h.min _ MIN[h.min, d]; dTol _ h.dTol _ MAX[h.min+h.s, h.innerR]; }; ReplaceOrOverflow => { iWorst: NAT; worstDist: REAL _ 0.0; <> iWorst _ 0; worstDist _ 0.0; FOR i: NAT IN [0..maxFeatures-1] DO IF h[i].dist > worstDist THEN {iWorst _ i; worstDist _ h[i].dist}; ENDLOOP; IF d < worstDist THEN { -- do the replace h[iWorst].dist _ d; h[iWorst]^ _ thisPoint^; h.bestTossed _ MIN[h.bestTossed, worstDist]; h.min _ MIN[h.min, d]; dTol _ h.dTol _ MAX[h.min+h.s, h.innerR]; h.overflow _ h.bestTossed <= dTol; } ELSE { -- toss the new item dTol _ h.dTol; h.bestTossed _ MIN[h.bestTossed, d]; h.overflow _ TRUE; }; }; Toss => { dTol _ h.dTol; h.bestTossed _ MIN[h.bestTossed, d]; h.overflow _ h.bestTossed <= dTol; }; END; }; MergeFace: PROC [thisPoint: GoodPoint, h: BestPoints] = { <> n: NAT = maxFeatures; IF h.size >= n THEN RETURN; h[h.size]^ _ thisPoint^; h.size _ h.size + 1; }; NearPointsFromPoints: PROC [bestPoints: BestPoints, pointCount: NAT, nearVEF: NearVertexEdgeAndFaces] = { FOR i: NAT IN [0..pointCount-1] DO nearVEF[i] _ bestPoints[i]; ENDLOOP; }; MergePointsAndCurves: PROC [bestPoints: BestPoints, pointCount: NAT, bestCurves: BestPoints, curveCount: NAT, nearVEF: NearVertexEdgeAndFaces, count: NAT] = { <> pointIndex, curveIndex: NAT; pointDist, curveDist: REAL; pointIndex _ curveIndex _ 0; FOR i: NAT IN [0..count-1] DO IF pointIndex >= pointCount THEN GOTO NoMorePoints; IF curveIndex >= curveCount THEN GOTO NoMoreCurves; pointDist _ bestPoints[i].dist; curveDist _ bestCurves[i].dist; IF pointDist <= curveDist THEN { nearVEF[i] _ bestPoints[pointIndex]; pointIndex _ pointIndex + 1; } ELSE { nearVEF[i] _ bestCurves[curveIndex]; curveIndex _ curveIndex + 1; }; REPEAT NoMorePoints => { -- finish up with Curves data FOR k: NAT _ i, k+1 UNTIL k >= count DO nearVEF[k] _ bestCurves[curveIndex]; curveIndex _ curveIndex + 1; ENDLOOP}; NoMoreCurves => { -- finish up with points data FOR k: NAT _ i, k+1 UNTIL k >= count DO nearVEF[k] _ bestPoints[pointIndex]; pointIndex _ pointIndex + 1; ENDLOOP}; ENDLOOP; }; MergeVEWithFaces: PROC [bestFaces: BestPoints, faceCount: NAT, nearVEF: NearVertexEdgeAndFaces, oldCount, maxCount: NAT] = { <> faceIndex, totalCount: NAT; totalCount _ MIN[oldCount + faceCount, maxCount]; faceIndex _ 0; FOR i: NAT IN [oldCount..totalCount-1] DO nearVEF[i] _ bestFaces[faceIndex]; faceIndex _ faceIndex + 1; ENDLOOP; }; <> ClassifyCurve: PROC [curve: GoodPoint] RETURNS [class: NAT, simpleCurve: REF ANY] = { feature: FeatureData _ curve.featureData; SELECT feature.type FROM slice => { sliceD: SliceDescriptor _ NARROW[feature.shape]; hitData: REF ANY _ curve.hitData; <> IF simpleCurve = NIL THEN { simpleCurve _ sliceD; class _ 3; RETURN; }; }; slopeLine => { class _ 1; simpleCurve _ NARROW[feature.shape, AlignmentLine].line; RETURN; }; ENDCASE => {class _ 0; simpleCurve _ NIL; RETURN}; WITH simpleCurve SELECT FROM edge: Edge3d => class _ 2; ENDCASE => ERROR; }; ClassifyFace: PROC [face: GoodPoint] RETURNS [class: NAT, simpleFace: REF ANY] = { feature: FeatureData _ face.featureData; WITH feature.shape SELECT FROM sliceD: SliceDescriptor => {simpleFace _ sliceD; class _ 2;}; alignmentSphere: AlignmentSphere => {simpleFace _ alignmentSphere.sphere; class _ 3;}; ENDCASE => ERROR; }; CurveMeetsCurve: PROC [c1, c2: GoodPoint] RETURNS [iFrames: LIST OF Matrix4by4, tangency: LIST OF BOOL] = { typeOfCurve1, typeOfCurve2: NAT; simpleCurve1, simpleCurve2: REF ANY; [typeOfCurve1, simpleCurve1] _ ClassifyCurve[c1]; [typeOfCurve2, simpleCurve2] _ ClassifyCurve[c2]; IF typeOfCurve1 >= typeOfCurve2 THEN [iFrames, tangency] _ ComputeIntersection[typeOfCurve1][typeOfCurve2][simpleCurve1, simpleCurve2] ELSE [iFrames, tangency] _ ComputeIntersection[typeOfCurve2][typeOfCurve1][simpleCurve2, simpleCurve1] }; CurveMeetsFace: PROC [c, f: GoodPoint] RETURNS [iFrames: LIST OF Matrix4by4, tangency: LIST OF BOOL] = { typeOfCurve, typeOfFace: NAT; simpleCurve, simpleFace: REF ANY; [typeOfCurve, simpleCurve] _ ClassifyCurve[c]; IF typeOfCurve > 1 THEN RETURN; [typeOfFace, simpleFace] _ ClassifyFace[f]; [iFrames, tangency] _ ComputeFaceIntersection[typeOfCurve][typeOfFace][simpleCurve, simpleFace]; }; IntersectionProc: TYPE = PROC [c1, c2: REF ANY] RETURNS [iFrames: LIST OF Matrix4by4, tangency: LIST OF BOOL]; ComputeIntersection: ARRAY [0..3] OF ARRAY [0..3] OF IntersectionProc = [ <<0) NoOp 1) Line 2) Edge 3) Slice>> [NoOpI, NIL, NIL, NIL], -- 0) NoOp [NoOpI, LinLinI, NIL, NIL], -- 1) Line [NoOpI, EdgLinI, EdgEdgI, NIL], -- 2) Edge [NoOpI, SlcLinI, NoOpI, NoOpI] -- 3) Slice ]; ComputeFaceIntersection: ARRAY [0..1] OF ARRAY [0..3] OF IntersectionProc = [ <<0) NoOp 1) Polygon 2) Slice 3) Sphere>> [NoOpI, NoOpI, NoOpI, NoOpI], -- 0) NoOp [NoOpI, NoOpI, LinSlcFI, LinSphFI] -- 1) Line ]; NoOpI: IntersectionProc = { iFrames _ NIL; tangency _ NIL; }; LinSlcFI: IntersectionProc = { <> line: Line3d _ NARROW[c1]; sliceD: SliceDescriptor _ NARROW[c2]; slice: Slice _ sliceD.slice; shape: Shape _ NARROW[slice.shape]; worldShape: Matrix4by4 _ SVCoordSys.FindWorldInTermsOf[shape.coordSys]; ray: Ray _ SVRay.GetRayFromPool[]; localRay: Ray; class: Classification; SVRay.StuffWorldOnlyRay[ray, line.base, line.direction]; localRay _ SVRay.TransformRay[ray, worldShape]; SVRay.ReturnRayToPool[ray]; class _ SVAssembly.RayCastNoBBoxes[localRay, sliceD, slice.prim, FALSE]; [iFrames, tangency] _ FaceResultsFromClassification[class, localRay]; SVRay.ReturnRayToPool[localRay]; SVCastRays.ReturnClassToPool[class]; }; LinSphFI: IntersectionProc = { <> line: Line3d _ NARROW[c1]; sphere: Sphere _ NARROW[c2]; points: ARRAY [1..2] OF Point3d; hitCount: [0..2]; tangent: BOOL _ FALSE; normal: Vector3d; [points, hitCount, tangent] _ SVSpheres.SphereMeetsLine[sphere, line]; FOR i: NAT IN [1..hitCount] DO normal _ SVVector3d.Sub[points[i], sphere.center]; iFrames _ CONS[SVMatrix3d.MakeHorizontalMatFromZAxis[normal, points[i]], iFrames]; tangency _ CONS[tangent, tangency]; ENDLOOP; }; LinLinI: IntersectionProc = { <> l1: Line3d _ NARROW[c1]; l2: Line3d _ NARROW[c2]; p1, p2: Point3d; parallel: BOOL; [p1, p2, parallel] _ SVLines3d.NearLinePoints[l1, l2]; IF parallel THEN GOTO NoIntersection ELSE IF AlmostEqualPoints[p1, p2] THEN { normal: Vector3d _ SVVector3d.Normalize[SVVector3d.CrossProduct[l1.direction, l2.direction]]; mat: Matrix4by4 _ SVMatrix3d.MakeHorizontalMatFromZAxis[normal, p1]; iFrames _ LIST[mat]; tangency _ LIST[FALSE];} ELSE GOTO NoIntersection; EXITS NoIntersection => {iFrames _ NIL; tangency _ NIL}; }; AlmostEqualPoints: PROC [p1, p2: Point3d] RETURNS [BOOL] = { epsilon: REAL = 1.0E-6; RETURN[SVVector3d.DistanceSquared[p1, p2] < epsilon]; }; EdgLinI: IntersectionProc = { <> edge: Edge3d _ NARROW[c1]; line: Line3d _ NARROW[c2]; edgePoint: Point3d; distance: REAL; epsilon: REAL = 1.0E-3; [distance, edgePoint] _ SVLines3d.DistanceAndPointLineToEdge[line, edge]; IF distance < epsilon THEN { normal: Vector3d _ SVVector3d.Normalize[SVVector3d.CrossProduct[edge.line.direction, line.direction]]; mat: Matrix4by4 _ SVMatrix3d.MakeHorizontalMatFromZAxis[normal, edgePoint]; iFrames _ LIST[mat]; tangency _ LIST[FALSE]} ELSE {iFrames _ NIL; tangency _ NIL}; }; EdgEdgI: IntersectionProc = { <> e1: Edge3d _ NARROW[c1]; e2: Edge3d _ NARROW[c2]; iFrames _ NIL; tangency _ NIL; }; SlcLinI: IntersectionProc = { <> <> <<[iPoints, ----] _ SVAssembly.LineIntersection[sliceD, line];>> <> <> <> iFrames _ NIL; tangency _ NIL; }; <<>> <> SortPoints: PROC [bestPoints: BestPoints, pointCount: NAT] = { <> temp: GoodPointObj; FOR i: NAT IN [0..pointCount-2] DO FOR j: NAT IN [1..pointCount-i-1] DO IF bestPoints[j-1].dist > bestPoints[j].dist THEN { temp _ bestPoints[j]^; bestPoints[j]^ _ bestPoints[j-1]^; bestPoints[j-1]^ _ temp; }; ENDLOOP; ENDLOOP; }; SortCurves: PROC [bestCurves: BestPoints, curveCount: NAT] = { <> temp: GoodPointObj; FOR i: NAT IN [0..curveCount-2] DO FOR j: NAT IN [1..curveCount-i-1] DO IF bestCurves[j-1].dist > bestCurves[j].dist THEN { temp _ bestCurves[j]^; bestCurves[j]^ _ bestCurves[j-1]^; bestCurves[j-1]^ _ temp; }; ENDLOOP; ENDLOOP; }; SortFaces: PROC [bestFaces: BestPoints, faceCount: NAT] = { }; <<>> <> <> <> <> <> <> <> <<>> <<[surfacePtWorld, normalWorld, feature, hitData] _ RayAtSurfaces[rayWorld, cameraPt, t, sceneBag, camera, searchDepth];>> <<[pointsPtWorld, pointsNormalWorld, pointsFeature, pointsHitData] _ RayAtPoints[rayWorld, cameraPt, t, sceneBag, camera, gravityType];>> <> <> <> <> <> <<};>> <> <<}>> <> <<}>> <> <<[surfacePtWorld, normalWorld, parallel] _ RayMeetsCentralCameraPlane[cameraPt, camera];>> <> <<};>> <> <<};>> <<>> LineFromRay: PROC [ray: Ray] RETURNS [line: Line3d] = { basePt: Point3d; direction: Vector3d; [basePt, direction] _ SVRay.GetWorldRay[ray]; line _ SVLines3d.LineFromPointAndVector[basePt, direction]; }; WithinTolerance: PROC [point: Point3d, rayWorld: Ray, t: REAL] RETURNS [BOOL] = { line: Line3d; dist: REAL; line _ LineFromRay[rayWorld]; dist _ SVLines3d.DistancePointToLine[point, line]; RETURN[dist <= t]; }; GetWorldRayFromCameraPoint: PROC [cameraPt: Point2d, camera: Camera] RETURNS [rayWorld: Ray] = { rayCamera: Ray; cameraWorld: Matrix4by4 _ SVCoordSys.WRTWorld[camera.coordSys]; rayCamera _ SVRay.GetRayFromPool[]; -- allocates ray from pool SVRay.StuffCameraRay[rayCamera, cameraPt, camera]; rayWorld _ SVRay.TransformRayToWorld[rayCamera, cameraWorld]; -- allocates ray from pool SVRay.ReturnRayToPool[rayCamera]; }; FindFeature: PROC [assembly: Slice, sceneBag: TriggerBag] RETURNS [feature: FeatureData] = { sliceD: SliceDescriptor; IF assembly = NIL THEN RETURN[NIL]; FOR list: LIST OF FeatureData _ sceneBag.slices, list.rest UNTIL list = NIL DO sliceD _ NARROW[list.first.shape]; IF sliceD.slice = assembly THEN RETURN[list.first]; ENDLOOP; RETURN[NIL]; }; AssemblyAndPrimitiveAtSearchDepth: PROC [class: Classification, searchDepth: SearchDepth, root: Slice] RETURNS [assembly: Slice, primitive: Primitive] = { SELECT searchDepth FROM first => [assembly, primitive] _ SVCastRays.NthAssemblyAndPrimitive[class, 1]; lastOfFirst => [assembly, primitive] _ SVCastRays.NthAssemblyAndPrimitive[class, 1]; last => [assembly, primitive] _ SVCastRays.NthAssemblyAndPrimitive[class, class.count]; lastOfLevel1 => [assembly, primitive] _ SVCastRays.LastTopLevelAssemAndPrim[class, root]; ENDCASE => ERROR; }; SurfacePointAndNormalAtSearchDepth: PROC [class: Classification, rayWorld: Ray, searchDepth: SearchDepth, root: Slice] RETURNS [surfacePtWorld: Point3d, normalWorld: Vector3d] = { SELECT searchDepth FROM first => [surfacePtWorld, normalWorld] _ SVCastRays.NthSurfacePointAndNormal[class, rayWorld, 1]; lastOfFirst => [surfacePtWorld, normalWorld] _ SVCastRays.LastOfFirstPointAndNormal[class, rayWorld]; last => IF class.count = 0 THEN ERROR ELSE [surfacePtWorld, normalWorld] _ SVCastRays.NthSurfacePointAndNormal[class, rayWorld, class.count]; lastOfLevel1 => [surfacePtWorld, normalWorld] _ SVCastRays.LastTopLevelPointAndNormal[class, rayWorld, root]; ENDCASE => ERROR; }; HitDataAtSearchDepth: PROC [class: Classification, searchDepth: SearchDepth, root: Slice] RETURNS [hitData: REF ANY] = { SELECT searchDepth FROM first => hitData _ SVCastRays.NthHitData[class, 1]; lastOfFirst => hitData _ SVCastRays.LastOfFirstHitData[class]; last => IF class.count = 0 THEN ERROR ELSE hitData _ SVCastRays.NthHitData[class, class.count]; lastOfLevel1 => hitData _ SVCastRays.LastTopLevelHitData[class, root]; ENDCASE => ERROR; }; SingleRay: PUBLIC PROC [rayWorld: Ray, cameraPt: Point2d, sceneBag: TriggerBag, camera: Camera, consolidate: BOOL _ TRUE, feedback: FeedbackData, makeStream: BOOL _ FALSE] RETURNS [class: Classification] = { tree: CSGTree _ sceneBag.tree; topNode: REF ANY; IF tree = NIL THEN { class _ SVCastRays.GetClassFromPool[]; SVCastRays.MakeClassAMiss[class]; RETURN; }; IF tree.outOfDate THEN { tree _ SVSceneToTree.AssemblyToTree[sceneBag.scene.assembly, sceneBag.scene, camera, tree, sceneBag.ignoreMoving]; [] _ SVPreprocess3d.PreprocessForInteraction[tree, camera]; tree.outOfDate _ FALSE; }; topNode _ tree.son; class _ SVCastRays.RayCast[cameraPt, rayWorld, topNode, consolidate, feedback, makeStream, 0]; }; -- end of SingleRay RayAtPoints: PROC [ray: Ray, cameraPt: Point2d, t: REAL, sceneBag: TriggerBag, camera: Camera, gravityType: GravityType] RETURNS [bestPoint: Point3d, bestNormal: Vector3d, bestFeature: FeatureData, bestHitData: REF ANY] = { line3d: Line3d; bestDist, thisDist: REAL; pointWorld: Point3d; normalWorld: Vector3d; feature: FeatureData; sliceD: SliceDescriptor; hitData: REF ANY; success: BOOL; scene: Scene _ sceneBag.scene; line3d _ LineFromRay[ray]; bestDist _ Real.LargestNumber; bestFeature _ NIL; IF gravityType = linesPreferred THEN { FOR list: LIST OF FeatureData _ sceneBag.slices, list.rest UNTIL list = NIL DO feature _ list.first; sliceD _ NARROW[feature.shape]; [thisDist, pointWorld, normalWorld, hitData, success] _ SVAssembly.ClosestSegmentToLine[sliceD, cameraPt, line3d, t, camera]; IF success AND thisDist < bestDist THEN { bestDist _ thisDist; bestPoint _ pointWorld; bestNormal _ normalWorld; bestHitData _ hitData; bestFeature _ feature; }; ENDLOOP; }; FOR list: LIST OF FeatureData _ sceneBag.slices, list.rest UNTIL list = NIL DO feature _ list.first; sliceD _ NARROW[feature.shape]; [thisDist, pointWorld, normalWorld, hitData, success] _ SVAssembly.ClosestPointToLine[sliceD, cameraPt, line3d, t, camera, TRUE]; IF success AND thisDist < bestDist THEN { bestDist _ thisDist; bestPoint _ pointWorld; bestNormal _ normalWorld; bestHitData _ hitData; bestFeature _ feature; }; ENDLOOP; <> }; RayMeetsCameraPlane: PROC [cameraPt: Point2d, depth: REAL, camera: Camera] RETURNS [planePtCamera: Point3d, parallel: BOOL] = { rayWorld: Ray; worldCamera: Matrix4by4; planePtWorld: Point3d; rayWorld _ SVRay.GetRayFromPool[]; SVRay.StuffWorldRayFromCamera[rayWorld, cameraPt, camera]; [planePtWorld, parallel] _ SVCastRays.RayMeetsPlaneOfCoordSystem[camera.coordSys, rayWorld, 3, depth]; worldCamera _ SVCoordSys.FindAInTermsOfB[SVCoordSys.Parent[camera.coordSys], camera.coordSys]; planePtCamera _ SVMatrix3d.Update[planePtWorld, worldCamera]; SVRay.ReturnRayToPool[rayWorld]; }; RayMeetsCentralCameraPlane: PROC [cameraPt: Point2d, camera: Camera] RETURNS [pointWorld: Point3d, normalWorld: Vector3d, parallel: BOOL] = { worldCAMERA: Matrix4by4 _ SVCoordSys.FindWorldInTermsOf[camera.coordSys]; originCAMERA: Point3d _ SVMatrix3d.OriginOfMatrix[worldCAMERA]; depth: REAL _ originCAMERA[3]; rayWorld: Ray; rayWorld _ SVRay.GetRayFromPool[]; SVRay.StuffWorldRayFromCamera[rayWorld, cameraPt, camera]; [pointWorld, parallel] _ SVCastRays.RayMeetsPlaneOfCoordSystem[camera.coordSys, rayWorld, 3, depth]; normalWorld _ SVMatrix3d.ZAxisOfMatrix[SVCoordSys.WRTWorld[camera.coordSys]]; SVRay.ReturnRayToPool[rayWorld]; }; NewGravityPool: PUBLIC PROC [] RETURNS [gravityPool: REF ANY] = { pool: MultiGravityPool _ NEW[MultiGravityPoolObj]; pool.distances _ NEW[NearDistancesObj[maxFeatures]]; pool.features _ NEW[NearFeaturesObj[maxFeatures]]; pool.bestpoints _ NEW[BestPointsObj[maxFeatures]]; pool.bestcurves _ NEW[BestPointsObj[maxFeatures]]; pool.bestfaces _ NEW[BestPointsObj[maxFeatures]]; FOR i: NAT IN [0..maxFeatures) DO pool.bestpoints[i] _ NEW[GoodPointObj]; pool.bestcurves[i] _ NEW[GoodPointObj]; pool.bestfaces[i] _ NEW[GoodPointObj]; ENDLOOP; RETURN[pool]; }; BestFacesFromPool: PROC [svData: SVData] RETURNS [h: BestPoints] = { h _ NARROW[svData.gravityPool, MultiGravityPool].bestfaces; h.size _ 0; h.overflow _ FALSE; FOR i: NAT IN [0..maxFeatures) DO h[i].dist _ Real.LargestNumber; h[i].featureData _ NIL; ENDLOOP; }; BestCurvesFromPool: PROC [svData: SVData, t: REAL, innerR: REAL] RETURNS [h: BestPoints] = { h _ NARROW[svData.gravityPool, MultiGravityPool].bestcurves; h.size _ 0; h.max _ 0; h.min _ Real.LargestNumber; h.dTol _ t; h.innerR _ innerR; h.s _ 0.072; -- 1/1000 inches h.bestTossed _ Real.LargestNumber; h.overflow _ FALSE; FOR i: NAT IN [0..maxFeatures-1] DO h[i].dist _ Real.LargestNumber; h[i].featureData _ NIL; ENDLOOP; }; BestPointsFromPool: PROC [svData: SVData, t: REAL] RETURNS [h: BestPoints] = { h _ NARROW[svData.gravityPool, MultiGravityPool].bestpoints; h.size _ 0; h.max _ 0; h.min _ Real.LargestNumber; h.dTol _ t; h.s _ 0.072; -- 1/1000 inches h.bestTossed _ Real.LargestNumber; h.overflow _ FALSE; FOR i: NAT IN [0..maxFeatures-1] DO h[i].dist _ Real.LargestNumber; h[i].featureData _ NIL; ENDLOOP; }; Init: PROC = { }; InitStats: PROC = { interval: CodeTimer.Interval; interval _ CodeTimer.CreateInterval[$RayMap]; CodeTimer.AddInt[interval, $Solidviews]; interval _ CodeTimer.CreateInterval[$PointOverflow]; CodeTimer.AddInt[interval, $Solidviews]; }; InitStats[]; Init[]; END.