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 = [ [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 = [ [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 = { 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] = { }; 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. `SVGravityImpl.mesa Copyright c 1986 by Xerox Corporation. All rights reserved. Last edited by Bier on February 17, 1987 11:19:15 pm PST Contents: Routines to snap the skitter to faces, segments, and points in the scene. Find the nearest face hit by the cursor ray. If the ray hits no faces, find the nearest face that passes within t screen units of the ray. Ideally, this would be implemented by a "nearest face to line" routine that would find the nearest edge of a face in the same way that Solidviews finds the nearest endpoint of an edge. Failing this, we can just combine ray-tracing with an edge finder. SortByDepth[nearVEF]; Find the nearest line and any that are almost as near, if any lines exist with radius t. Choose one of these lines. If the winner is an edge, use the surface normal of the face that owns that edge, whose normal most nearly points toward the eyepoint. If no lines exist within t, then choose the nearest face hit by the cursor ray, if any. If still no object is found, use the background plane. Otherwise, let's do arbitration. Find how many nearest neighbors there are. Otherwise, let's do arbitration. Find the nearest face hit by the cursor ray. If the ray hits no faces, find the nearest face that passes within t screen units of the ray. Ideally, this would be implemented by a "nearest face to line" routine that would find the nearest edge of a face in the same way that Solidviews finds the nearest endpoint of an edge. Failing this, we can just combine ray-tracing with an edge finder. SortByDepth[nearVEF]; Find the nearest line and any that are almost as near, if any lines exist with radius t. Choose one of these lines. If the winner is an edge, use the surface normal of the face that owns that edge, whose normal most nearly points toward the eyepoint. If no lines exist within t, then choose the nearest face hit by the cursor ray, if any. If still no object is found, use the background plane. Otherwise, let's do arbitration. Find how many nearest neighbors there are. Otherwise, let's do arbitration. Find the nearest slice if one is close enough. Otherwise, start with the nearest alignment object. Find the nearest line to ray and those lines that are not much farther. If intersections is TRUE, compute the intersections of surfaces that are within the cone whose radius at the screen is innerR. (For now assume intersections is false). Handle the Slices Handle the Alignment Objects circle: Circle; Align Bag Scene Bag. IF intersections AND midpoints THEN dTol _ FindMidpoints[bestCurves, curveCount, thisPoint, q, dTol, h]; Find Curve-Curve intersections. Check each intersection against the test line. Find Curve-Face intersections. Check each intersection against the test line. Replace the worst element with the new one if the new is better. Replace the worst element with the new one if the new is better. Faces are handed to MergeFace in order. Use the size field of h to remember where to put the next face. Merge the bestPoints and the bestCurves. There will be count elements in the result. Add the faces onto the end. Computing Intersections simpleCurve _ SVAssembly.HitDataAsSimpleCurve[sliceD.slice, hitData]; 0) NoOp 1) Line 2) Edge 3) Slice 0) NoOp 1) Polygon 2) Slice 3) Sphere IntersectionProc: TYPE = PROC [c1, c2: REF ANY] RETURNS [iFrames: LIST OF Matrix4by4, tangency: LIST OF BOOL]; IntersectionProc: TYPE = PROC [c1, c2: REF ANY] RETURNS [iFrames: LIST OF Matrix4by4, tangency: LIST OF BOOL]; IntersectionProc: TYPE = PROC [c1, c2: REF ANY] RETURNS [iFrames: LIST OF Matrix4by4, tangency: LIST OF BOOL]; IntersectionProc: TYPE = PROC [c1, c2: REF ANY] RETURNS [iFrames: LIST OF SVMatrix3d, tangency: LIST OF BOOL]; IntersectionProc: TYPE = PROC [c1, c2: REF ANY] RETURNS [iFrames: LIST OF SVMatrix3d, tangency: LIST OF BOOL]; sliceD: SliceDescriptor _ NARROW[c1]; line: Line _ NARROW[c2]; [iPoints, ----] _ SVAssembly.LineIntersection[sliceD, line]; FOR list: LIST OF Point3d _ iPoints, list.rest UNTIL list = NIL DO tangency _ CONS[FALSE, tangency]; ENDLOOP; Utilities Sort the points in order of increasing distance. Since n is likely to be small, bubble sort is sensible: Sort the curves in order of increasing distance. Since n is likely to be small, bubble sort is sensible: PointsOrSurfaces: PROC [cameraPt: Point2d, t: REAL, sceneBag: TriggerBag, camera: Camera, searchDepth: SearchDepth, gravityType: GravityType] RETURNS [surfacePtWorld: Point3d, normalWorld: Vector3d, feature: FeatureData, hitData: REF ANY] = { pointsPtWorld: Point3d; pointsNormalWorld: Vector3d; pointsFeature: FeatureData; parallel: BOOL; pointsHitData: REF ANY; rayWorld: Ray _ GetWorldRayFromCameraPoint[cameraPt, camera]; -- from pool [surfacePtWorld, normalWorld, feature, hitData] _ RayAtSurfaces[rayWorld, cameraPt, t, sceneBag, camera, searchDepth]; [pointsPtWorld, pointsNormalWorld, pointsFeature, pointsHitData] _ RayAtPoints[rayWorld, cameraPt, t, sceneBag, camera, gravityType]; IF pointsFeature # NIL AND WithinTolerance[pointsPtWorld, rayWorld, t] THEN { surfacePtWorld _ pointsPtWorld; IF pointsFeature # feature THEN { normalWorld _ pointsNormalWorld; feature _ pointsFeature; }; hitData _ pointsHitData; } ELSE IF feature # NIL THEN { } ELSE { [surfacePtWorld, normalWorld, parallel] _ RayMeetsCentralCameraPlane[cameraPt, camera]; hitData _ NIL; }; SVRay.ReturnRayToPool[rayWorld]; }; bestNormal _ SVMatrix3d.ZAxisOfMatrix[SVCoordSys.WRTWorld[camera.coordSys]]; Ê4n˜J˜Icodešœ™Kšœ Ïmœ1™K™iKšœ˜šžœžœžœž˜"šžœžœžœž˜$šžœ+žœ˜3Kšœ˜Kšœ"˜"Kšœ˜K˜—Kšžœ˜—Kšžœ˜—˜K˜——šŸ œžœ&žœ˜>K™iKšœ˜šžœžœžœž˜"šžœžœžœž˜$šžœ+žœ˜3Kšœ˜Kšœ"˜"Kšœ˜K˜—Kšžœ˜—Kšžœ˜—K˜K˜—šŸ œžœ$žœ˜;K˜K™—šŸœžœžœ\žœ ¡œ¡œ+žœžœ™òKšœ¡œ ™Kšœ ¡œ ™Kšœ™Kšœ žœ™Kšœžœžœ™Kšœ¡œB™JK™Kš œ ¡œ¡œ¢ œ¡œ.™vKš œ ¡œ¡œ"¢ œ¡œ.™…š žœžœžœ¡œ¡œžœ™MKšœ ¡œ ¡œ™šžœžœ™!Kšœ¡œ¡œ™ Kšœ™K™—Kšœ™K™—šžœžœ žœžœ™K™—šžœ™Kšœ ¡œ¡œ;™WKšœ žœ™K™—Kšœ¡œ™ K™K™—K˜šŸ œžœ žœ˜7Kšœ˜Kšœ˜Kšœžœ˜-Kšœ;˜;K˜K˜—š Ÿœžœ¡œ žœžœžœ˜QKšœ ˜ Kšœžœ˜ Kšœ¡œ˜Kšœ2˜2Kšžœ ˜K˜K˜—šŸœžœ%žœ¡œ ˜`Lšœ¡œ˜Lšœ¡œ4˜?Lšœ¡œžœ ˜>Lšžœ¡œ˜2Lš œ¡œžœ¡œ¡œ ˜XLšžœ¡œ˜!K˜K˜—šŸ œžœ)žœ˜\Jšœ˜Jš žœ žœžœžœžœ˜#š žœžœžœ*žœžœž˜NJšœ žœ˜"Jšžœžœžœ ˜3Jšžœ˜—Jšžœžœ˜ J˜J˜—š¤Ÿ œžœ@žœ,˜šJšžœ ž˜Jšœ,¢œ ˜NJšœ2¢œ ˜TJšœ+¢œ˜WJšœ3¢œ˜YJšžœžœ˜J˜J˜—š ¤Ÿ œžœ¡œ.žœ ¡œ¡œ˜³Jšžœ ž˜šœ˜Jš œ ¡œ¡œ¢œ ¡œ˜X—šœ˜Jš œ ¡œ¡œ¢œ ¡œ˜V—šœ˜Jšžœžœž˜Jš žœ ¡œ¡œ¢œ ¡œ˜g—šœ˜Jš œ ¡œ¡œ¢œ ¡œ˜]—Jšžœžœ˜J˜J˜—š Ÿœžœ@žœ žœžœ˜xJšžœ ž˜šœ˜Jšœ*˜*—šœ˜Jšœ/˜/—šœ˜Jšžœžœž˜Jšžœ5˜9—šœ˜Jšœ6˜6—Jšžœžœ˜J˜J˜—šŸ œžœžœWžœžœ&žœžœžœ˜ÏLšœ˜Lšœ žœž˜J˜šžœžœžœ˜Jšœ&˜&Jšœ!˜!Jšžœ˜J˜—šžœžœ˜Jšœr˜rJšœ;˜;Jšœžœ˜J˜J˜—Lšœ˜Lšœ(¡œ1˜^Lšœ ˜—K˜š Ÿ œžœ"žœBžœSžœžœ˜ßKšœ˜Kšœžœ˜Kšœ¡œ ˜Kšœ¡œ ˜Kšœ˜K˜Kšœ žœžœ˜Kšœ žœ˜Kšœ˜K˜Kšœ˜Kšœ˜Kšœžœ˜šžœžœ˜&š žœžœžœ*žœžœž˜NKšœ˜Kšœ žœ˜Kšœ¡œ¡œ[˜}šžœ žœžœ˜)Kšœ˜Kšœ¡œ˜Kšœ¡œ˜Kšœ˜Kšœ˜K˜—Kšžœ˜—K˜—š žœžœžœ*žœžœž˜NKšœ˜Kšœ žœ˜Kšœ¡œ¡œYžœ˜šžœ žœžœ˜)Kšœ˜Kšœ¡œ˜Kšœ¡œ˜Kšœ˜Kšœ˜K˜—Kšžœ˜—KšœL™LK˜K˜—K˜š Ÿœžœžœžœ ¡œžœ˜Jšœ¡œ˜Jšœ¡œ ˜Jšœ¡œ ˜Jšœ¡œžœ˜"Jšžœ¡œ˜:Jšœ¡œH¡œ ˜fJšœ¡œS˜^Jšœ¡œ¡œ¡œ˜=Jšžœ¡œ˜ J˜J˜—š Ÿœžœ%žœ¡œ¡œžœ˜Kšœ¡œ>˜IKšœ¡œ+¡œ˜?Kšœžœ ¡œ˜Jšœ¡œ˜Jšœ¡œžœ˜"Jšžœ¡œ˜:Jšœ¡œH¡œ ˜dKšœ¡œB˜MJšžœ¡œ˜ K˜—K˜š Ÿœžœžœžœžœžœ˜AKšœžœ˜2Kšœžœ ˜4Kšœžœ˜2Kšœžœ˜2Kšœžœ˜2Kšœžœ˜1šžœžœžœž˜!Kšœžœ˜'Kšœžœ˜'Kšœžœ˜&Kšžœ˜—Kšžœ˜ K˜—K˜šŸœžœžœ˜DKšœžœ1˜;Kšœ ˜ Kšœ žœ˜šžœžœžœž˜!Jšœ˜Jšœžœ˜Jšžœ˜—J˜J˜—š Ÿœžœžœ žœžœ˜\Kšœžœ2˜