<> <> <> <> <<>> DIRECTORY GGCircles, GGLines, GGGravity, GGModelTypes, GGInterfaceTypes, GGObjects, GGRefresh, GGShapes, GGVector, Imager, Real, RealFns; GGGravityImpl: CEDAR PROGRAM IMPORTS GGCircles, GGLines, GGObjects, GGRefresh, GGShapes, GGVector, Imager, RealFns EXPORTS GGGravity = BEGIN Angle: TYPE = GGModelTypes.Angle; BoundBox: TYPE = GGModelTypes.BoundBox; Camera: TYPE = GGModelTypes.Camera; Circle: TYPE = GGModelTypes.Circle; Edge: TYPE = GGModelTypes.Edge; FeatureData: TYPE = REF FeatureDataObj; FeatureDataObj: TYPE = GGGravity.FeatureDataObj; GargoyleData: TYPE = GGInterfaceTypes.GargoyleData; JointGenerator: TYPE = GGObjects.JointGenerator; Line: TYPE = GGModelTypes.Line; ObjectBag: TYPE = REF ObjectBagObj; ObjectBagObj: TYPE = GGGravity.ObjectBagObj; Segment: TYPE = GGModelTypes.Segment; SegmentGenerator: TYPE = GGObjects.SegmentGenerator; Sequence: TYPE = GGModelTypes.Sequence; SymmetryGroup: TYPE = GGGravity.SymmetryGroup; Traj: TYPE = GGModelTypes.Traj; Point: TYPE = GGModelTypes.Point; Vector: TYPE = GGModelTypes.Vector; Map: PUBLIC PROC [testPoint: Point, criticalR: REAL, environ: ObjectBag, gargoyleData: GargoyleData] RETURNS [resultPoint: Point, feature: FeatureData] = { <> SELECT gargoyleData.hitTest.gravityType FROM strictDistance => [resultPoint, feature] _ StrictDistance[testPoint, criticalR, environ]; innerCircle => [resultPoint, feature] _ InnerCircle[testPoint, criticalR, gargoyleData.hitTest.innerR, environ]; sectors => [resultPoint, feature] _ Sector[testPoint, criticalR, environ]; none => { resultPoint _ testPoint; feature _ NIL; }; ENDCASE => ERROR; }; <> <<>> NotYetImplemented: PUBLIC ERROR = CODE; NearestSegment: PROC [testPoint: Point, seq: Sequence, tolerance: REAL] RETURNS [bestDist: REAL, bestSeg: NAT, bestPoint: Point, success: BOOL] = { thisDist2, bestDist2: REAL; thisPoint: Point; segGen: SegmentGenerator; thisSuccess: BOOL; next: GGObjects.SegAndIndex; success _ FALSE; segGen _ GGObjects.SegmentsInSequence[seq]; next _ GGObjects.NextSegmentAndIndex[segGen]; IF next.seg = NIL THEN { -- The sequence is a single joint bestDist _ 99999.0; -- magic number meaning no segment bestSeg _ 999; -- magic number for debugging bestPoint _ [-1.0, -1.0]; RETURN; }; [bestPoint, thisSuccess] _ next.seg.class.closestPoint[next.seg, testPoint, tolerance]; IF NOT thisSuccess THEN { bestDist2 _ 99999.0; bestSeg _ 999; bestPoint _ [-1.0, -1.0]; } ELSE { bestDist2 _ GGVector.DistanceSquared[bestPoint, testPoint]; bestSeg _ 0; success _ TRUE; }; FOR next _ GGObjects.NextSegmentAndIndex[segGen], GGObjects.NextSegmentAndIndex[segGen] UNTIL next.seg = NIL DO [thisPoint, thisSuccess] _ next.seg.class.closestPoint[next.seg, testPoint, tolerance]; IF NOT thisSuccess THEN { thisDist2 _ 99999.0; thisPoint _ [-1.0, -1.0]; } ELSE { thisDist2 _ GGVector.DistanceSquared[thisPoint, testPoint]; success _ TRUE; }; IF thisDist2 < bestDist2 THEN { bestDist2 _ thisDist2; bestSeg _ next.index; bestPoint _ thisPoint; }; ENDLOOP; bestDist _ RealFns.SqRt[bestDist2]; }; NearestJoint: PROC [testPoint: Point, seq: Sequence] RETURNS [bestDist: REAL, bestJoint: NAT, bestPoint: Point] = { <> thisPoint: Point; thisDist2, bestDist2: REAL; index: INT; jointGen: JointGenerator; jointGen _ GGObjects.JointsInSequence[seq]; index _ GGObjects.NextJoint[jointGen]; bestPoint _ GGObjects.FetchJointPos[seq.traj, index]; bestDist2 _ GGVector.DistanceSquared[bestPoint, testPoint]; bestJoint _ index; FOR index _ GGObjects.NextJoint[jointGen], GGObjects.NextJoint[jointGen] UNTIL index = -1 DO thisPoint _ GGObjects.FetchJointPos[seq.traj, index]; thisDist2 _ GGVector.DistanceSquared[thisPoint, testPoint]; IF thisDist2 < bestDist2 THEN { bestDist2 _ thisDist2; bestJoint _ index; bestPoint _ thisPoint; }; ENDLOOP; bestDist _ RealFns.SqRt[bestDist2]; }; EmptyBag: PROC [objectBag: ObjectBag] RETURNS [BOOL] = { RETURN[ objectBag.seqs = NIL AND objectBag.slopeLines = NIL AND objectBag.symmetryLines = NIL AND objectBag.radiiCircles = NIL AND objectBag.distanceLines = NIL AND objectBag.vectors = NIL AND objectBag.intersectionPoints = NIL]; }; UpdateBestCurve: PROC [thisCurve, bestCurve: GoodCurve] = { bestCurve.dist _ thisCurve.dist; bestCurve.segNum _ 999; -- magic number for debugging bestCurve.point _ thisCurve.point; bestCurve.featureData _ thisCurve.featureData; }; UpdateBestPoint: PROC [thisPoint, bestPoint: GoodPoint] = { bestPoint.dist _ thisPoint.dist; bestPoint.point _ thisPoint.point; bestPoint.joint _ 999; -- magic number for debugging bestPoint.featureData _ thisPoint.featureData; }; BestPointAndCurve: PROC [objectBag: ObjectBag, testPoint: Point, tolerance: REAL] RETURNS [bestPoint: GoodPoint, bestCurve: GoodCurve] = { epsilon: REAL = 1.0e-3; thisPoint: GoodPoint; thisCurve: GoodCurve; featureData: FeatureData; success: BOOL; thisCurve _ NEW[GoodCurveObj]; bestCurve _ NEW[GoodCurveObj]; thisPoint _ NEW[GoodPointObj]; bestPoint _ NEW[GoodPointObj]; bestCurve.dist _ 99999.0; -- magic numbers for debugging bestPoint.dist _ 99999.0; -- magic numbers for debugging FOR slopeLines: LIST OF FeatureData _ objectBag.slopeLines, slopeLines.rest UNTIL slopeLines = NIL DO featureData _ slopeLines.first; thisCurve.dist _ GGLines.LineDistance[testPoint, featureData.line]; thisCurve.point _ GGLines.PointProjectedOntoLine[testPoint, featureData.line]; thisCurve.featureData _ featureData; IF thisCurve.dist < bestCurve.dist THEN UpdateBestCurve[thisCurve, bestCurve]; ENDLOOP; FOR dLines: LIST OF FeatureData _ objectBag.distanceLines, dLines.rest UNTIL dLines = NIL DO featureData _ dLines.first; thisCurve.dist _ GGLines.LineDistance[testPoint, featureData.line]; thisCurve.point _ GGLines.PointProjectedOntoLine[testPoint, featureData.line]; thisCurve.featureData _ featureData; IF thisCurve.dist < bestCurve.dist THEN UpdateBestCurve[thisCurve, bestCurve]; ENDLOOP; FOR iPoints: LIST OF FeatureData _ objectBag.intersectionPoints, iPoints.rest UNTIL iPoints = NIL DO featureData _ iPoints.first; thisPoint.dist _ GGVector.Distance[featureData.point, testPoint]; thisPoint.point _ featureData.point; thisPoint.featureData _ featureData; IF thisPoint.dist < bestPoint.dist THEN UpdateBestPoint[thisPoint, bestPoint]; ENDLOOP; FOR circles: LIST OF FeatureData _ objectBag.radiiCircles, circles.rest UNTIL circles = NIL DO featureData _ circles.first; thisCurve.dist _ GGCircles.CircleDistance[testPoint, featureData.circle]; thisCurve.point _ GGCircles.PointProjectedOntoCircle[testPoint, featureData.circle]; thisCurve.featureData _ featureData; IF thisCurve.dist < bestCurve.dist THEN UpdateBestCurve[thisCurve, bestCurve]; ENDLOOP; FOR trajs: LIST OF FeatureData _ objectBag.seqs, trajs.rest UNTIL trajs = NIL DO featureData _ trajs.first; [thisCurve.dist, thisCurve.segNum, thisCurve.point, success] _ NearestSegment[testPoint, featureData.tseq, tolerance]; IF success THEN { IF thisCurve.dist - epsilon <= bestCurve.dist THEN { -- so segments are preferred to slopelines bestCurve.dist _ thisCurve.dist; bestCurve.segNum _ thisCurve.segNum; bestCurve.point _ thisCurve.point; bestCurve.featureData _ featureData; }; }; [thisPoint.dist, thisPoint.joint, thisPoint.point] _ NearestJoint[testPoint, featureData.tseq]; IF thisPoint.dist - epsilon <= bestPoint.dist THEN {-- joints are preferred to intersection Points bestPoint.dist _ thisPoint.dist; bestPoint.point _ thisPoint.point; bestPoint.joint _ thisPoint.joint; bestPoint.featureData _ featureData; }; ENDLOOP; }; StrictDistance: PUBLIC PROC [testPoint: Point, criticalR: REAL, environ: ObjectBag] RETURNS [resultPoint: Point, feature: FeatureData] = { <> bestCurve: GoodCurve; bestPoint: GoodPoint; IF EmptyBag[environ] THEN { resultPoint _ testPoint; feature _ NIL; RETURN; }; [bestPoint, bestCurve] _ BestPointAndCurve[environ, testPoint, criticalR]; <> IF bestPoint.dist = 99999.0 THEN ERROR; IF bestCurve.dist = 99999.0 THEN ERROR; IF bestPoint.dist < criticalR AND bestPoint.dist <= bestCurve.dist THEN { -- use the best point feature _ bestPoint.featureData; ExtractResultFromPoint[bestPoint, feature]; resultPoint _ bestPoint.point; } ELSE IF bestCurve.dist < criticalR THEN { feature _ bestCurve.featureData; ExtractResultFromCurve[bestCurve, feature]; resultPoint _ bestCurve.point; } ELSE { feature _ NIL; resultPoint _ testPoint; }; }; -- StrictDistance GoodCurve: TYPE = REF GoodCurveObj; GoodCurveObj: TYPE = RECORD [ dist: REAL, -- the distance from point to testPoint segNum: NAT, -- the best segment of this curve (if it is a trajectory) point: Point, -- the best point on this curve featureData: FeatureData -- this curve ]; GoodPoint: TYPE = REF GoodPointObj; GoodPointObj: TYPE = RECORD [ dist: REAL, point: Point, joint: NAT, -- the joint of the trajectory mentioned in FeatureData (if this is a joint) featureData: FeatureData -- this point ]; ExtractResultFromCurve: PROC [curve: GoodCurve, feature: FeatureData] = { SELECT curve.featureData.type FROM sequence => { feature.segNum _ curve.segNum; feature.resultType _ segment; }; slopeLine => feature.resultType _ slopeLine; radiiCircle => feature.resultType _ radiiCircle; distanceLine => feature.resultType _ distanceLine; ENDCASE => ERROR NotYetImplemented; }; ExtractResultFromPoint: PROC [goodPoint: GoodPoint, feature: FeatureData] = { SELECT goodPoint.featureData.type FROM sequence => { feature.jointNum _ goodPoint.joint; feature.resultType _ joint; }; intersectionPoint => { feature.resultType _ intersectionPoint; }; ENDCASE => ERROR NotYetImplemented; }; InnerCircle: PUBLIC PROC [testPoint: Point, criticalR: REAL, innerR: REAL, environ: ObjectBag] RETURNS [resultPoint: Point, feature: FeatureData] = { <> bestCurve: GoodCurve; bestPoint: GoodPoint; IF EmptyBag[environ] THEN { resultPoint _ testPoint; feature _ NIL; RETURN; }; [bestPoint, bestCurve] _ BestPointAndCurve[environ, testPoint, criticalR]; <> <> <> IF bestPoint.dist < innerR OR (bestPoint.dist < criticalR AND bestPoint.dist <= bestCurve.dist) THEN { -- use the best point feature _ bestPoint.featureData; ExtractResultFromPoint[bestPoint, feature]; resultPoint _ bestPoint.point; } ELSE IF bestCurve.dist < criticalR THEN { feature _ bestCurve.featureData; ExtractResultFromCurve[bestCurve, feature]; resultPoint _ bestCurve.point; } ELSE { feature _ NIL; resultPoint _ testPoint; }; }; -- InnerCircle Sector: PUBLIC PROC [testPoint: Point, criticalR: REAL, environ: ObjectBag] RETURNS [resultPoint: Point, feature: FeatureData] = {}; <> <<>> CreateObjectBag: PUBLIC PROC [] RETURNS [objectBag: ObjectBag] = { objectBag _ NEW[ObjectBagObj _ [ seqs: NIL, slopeLines: NIL, symmetryLines: NIL, radiiCircles: NIL, distanceLines: NIL, vectors: NIL, intersectionPoints: NIL ]]; }; AddFeature: PRIVATE PROC [featureData: FeatureData, objectBag: ObjectBag] = { iPoint: Point; parallel: BOOL; points: ARRAY[1..2] OF Point; hitCount: NAT; SELECT featureData.type FROM sequence => { IF NOT featureData.tseq.all AND featureData.tseq.parts = NIL THEN ERROR; -- empty sequence objectBag.seqs _ CONS[featureData, objectBag.seqs]; }; distanceLine => objectBag.distanceLines _ CONS[featureData, objectBag.distanceLines]; slopeLine => objectBag.slopeLines _ CONS[featureData, objectBag.slopeLines]; symmetryLine => objectBag.symmetryLines _ CONS[featureData, objectBag.symmetryLines]; radiiCircle => objectBag.radiiCircles _ CONS[featureData, objectBag.radiiCircles]; intersectionPoint => objectBag.intersectionPoints _ CONS[featureData, objectBag.intersectionPoints]; ENDCASE => ERROR; <> <> IF featureData.type = slopeLine THEN { FOR lineList: LIST OF FeatureData _ objectBag.slopeLines.rest, lineList.rest UNTIL lineList = NIL DO [iPoint, parallel] _ GGLines.LineMeetsLine[lineList.first.line, featureData.line]; IF NOT parallel THEN { AddIntersectionPointFeature[iPoint, featureData, lineList.first, objectBag]; }; ENDLOOP; FOR circleList: LIST OF FeatureData _ objectBag.radiiCircles, circleList.rest UNTIL circleList = NIL DO [points, hitCount] _ GGCircles.LineMeetsCircle[featureData.line, circleList.first.circle]; FOR i: NAT IN [1..hitCount] DO AddIntersectionPointFeature[points[i], featureData, circleList.first, objectBag]; ENDLOOP; ENDLOOP; FOR dlineList: LIST OF FeatureData _ objectBag.distanceLines, dlineList.rest UNTIL dlineList = NIL DO [iPoint, parallel] _ GGLines.LineMeetsLine[dlineList.first.line, featureData.line]; IF NOT parallel THEN { AddIntersectionPointFeature[iPoint, featureData, dlineList.first, objectBag]; }; ENDLOOP; }; IF featureData.type = radiiCircle THEN { FOR lineList: LIST OF FeatureData _ objectBag.slopeLines, lineList.rest UNTIL lineList = NIL DO [points, hitCount] _ GGCircles.LineMeetsCircle[lineList.first.line, featureData.circle]; FOR i: NAT IN [1..hitCount] DO AddIntersectionPointFeature[points[i], lineList.first, featureData, objectBag]; ENDLOOP; ENDLOOP; FOR circleList: LIST OF FeatureData _ objectBag.radiiCircles.rest, circleList.rest UNTIL circleList = NIL DO [points, hitCount] _ GGCircles.CircleMeetsCircle[circleList.first.circle, featureData.circle]; FOR i: NAT IN [1..hitCount] DO AddIntersectionPointFeature[points[i], circleList.first, featureData, objectBag]; ENDLOOP; ENDLOOP; FOR dlineList: LIST OF FeatureData _ objectBag.distanceLines, dlineList.rest UNTIL dlineList = NIL DO [points, hitCount] _ GGCircles.LineMeetsCircle[dlineList.first.line, featureData.circle]; FOR i: NAT IN [1..hitCount] DO AddIntersectionPointFeature[points[i], dlineList.first, featureData, objectBag]; ENDLOOP; ENDLOOP; }; IF featureData.type = distanceLine THEN { FOR lineList: LIST OF FeatureData _ objectBag.slopeLines, lineList.rest UNTIL lineList = NIL DO [iPoint, parallel] _ GGLines.LineMeetsLine[lineList.first.line, featureData.line]; IF NOT parallel THEN { AddIntersectionPointFeature[iPoint, featureData, lineList.first, objectBag]; }; ENDLOOP; FOR circleList: LIST OF FeatureData _ objectBag.radiiCircles, circleList.rest UNTIL circleList = NIL DO [points, hitCount] _ GGCircles.LineMeetsCircle[featureData.line, circleList.first.circle]; FOR i: NAT IN [1..hitCount] DO AddIntersectionPointFeature[points[i], featureData, circleList.first, objectBag]; ENDLOOP; ENDLOOP; FOR dlineList: LIST OF FeatureData _ objectBag.distanceLines.rest, dlineList.rest UNTIL dlineList = NIL DO [iPoint, parallel] _ GGLines.LineMeetsLine[dlineList.first.line, featureData.line]; IF NOT parallel THEN { AddIntersectionPointFeature[iPoint, featureData, dlineList.first, objectBag]; }; ENDLOOP; }; }; <> <<>> SameCircle: PRIVATE PROC [point: Point, radius: REAL, list: LIST OF FeatureData] RETURNS [coincident: FeatureData] = { epsilon: REAL = 1.0e-5; FOR l: LIST OF FeatureData _ list, l.rest UNTIL l = NIL DO IF l.first.circle.origin = point AND l.first.circle.radius = radius THEN RETURN[l.first]; ENDLOOP; RETURN[NIL]; }; LineThru: PRIVATE PROC [point: Point, degrees: REAL, list: LIST OF FeatureData] RETURNS [coincident: FeatureData] = { epsilon: REAL = 1.0e-5; FOR l: LIST OF FeatureData _ list, l.rest UNTIL l = NIL DO IF l.first.degrees = degrees AND GGLines.LineDistance[point, l.first.line] < epsilon THEN RETURN[l.first]; ENDLOOP; RETURN[NIL]; }; JointAddSlopeLine: PUBLIC PROC [degrees: REAL, direction: Vector, point: Point, jointNum: NAT, traj: Traj, objectBag: ObjectBag] = { <> <> line: Line; featureData, coincident: FeatureData; coincident _ LineThru[point, degrees, objectBag.slopeLines]; IF coincident # NIL THEN { coincident.triggerPoints _ CONS[point, coincident.triggerPoints]; } ELSE { line _ GGLines.LineFromPointAndVector[point, direction]; featureData _ NEW[FeatureDataObj]; featureData.type _ slopeLine; featureData.line _ line; featureData.degrees _ degrees; featureData.triggerPoints _ CONS[point, NIL]; featureData.jointNum _ jointNum; featureData.traj _ traj; AddFeature[featureData, objectBag]; }; }; JointAddVector: PUBLIC PROC [vector: Vector, point: Point, jointNum: NAT, traj: Traj, objectBag: ObjectBag] = { <> <> }; JointAddCircle: PUBLIC PROC [radius: REAL, point: Point, jointNum: NAT, traj: Traj, objectBag: ObjectBag] = { <> <> circle: Circle; featureData, coincident: FeatureData; coincident _ SameCircle[point, radius, objectBag.radiiCircles]; IF coincident # NIL THEN { coincident.triggerPoints _ CONS[point, coincident.triggerPoints]; } ELSE { circle _ GGCircles.CircleFromPointAndRadius[point, radius]; featureData _ NEW[FeatureDataObj]; featureData.type _ radiiCircle; featureData.circle _ circle; featureData.triggerPoints _ CONS[point, NIL]; featureData.jointNum _ jointNum; featureData.traj _ traj; AddFeature[featureData, objectBag]; }; }; JointAddPoint: PUBLIC PROC [point: Point, jointNum: NAT, traj: Traj, objectBag: ObjectBag] = { <> }; <> <<>> SegmentAddTwoAngleLines: PUBLIC PROC [degrees: REAL, p1, p2: Point, segNum, traj: Traj, objectBag: ObjectBag] = { <> <> }; SegmentAddDistanceLines: PUBLIC PROC [distance: REAL, segNum: NAT, traj: Traj, objectBag: ObjectBag] = { <> line, leftLine, rightLine: Line; featureData: FeatureData; seg: Segment _ GGObjects.FetchSegment[traj, segNum]; line _ GGLines.LineFromPoints[seg.lo, seg.hi]; leftLine _ GGLines.LineLeftOfLine[line, distance]; featureData _ NEW[FeatureDataObj]; featureData.type _ distanceLine; featureData.line _ leftLine; featureData.segNum _ segNum; featureData.traj _ traj; AddFeature[featureData, objectBag]; IF ABS[distance] > 0.0 THEN { rightLine _ GGLines.LineRightOfLine[line, distance]; featureData _ NEW[FeatureDataObj]; featureData.type _ distanceLine; featureData.line _ rightLine; featureData.segNum _ segNum; featureData.traj _ traj; AddFeature[featureData, objectBag]; }; }; SegmentAddEdge: PUBLIC PROC [point: Point, jointNum: NAT, traj: Traj, objectBag: ObjectBag] = { <> }; AddTrajectory: PUBLIC PROC [traj: Traj, objectBag: ObjectBag] = { <> featureData: FeatureData; seq: Sequence _ GGObjects.CreateCompleteSequence[traj]; featureData _ NEW[FeatureDataObj]; featureData.type _ sequence; featureData.tseq _ seq; AddFeature[featureData, objectBag]; }; AddSequence: PUBLIC PROC [seq: Sequence, objectBag: ObjectBag] = { <> featureData: FeatureData; featureData _ NEW[FeatureDataObj]; featureData.type _ sequence; featureData.tseq _ seq; AddFeature[featureData, objectBag]; }; <> SymmetryAddLines: PUBLIC PROC [group: SymmetryGroup, entity: REF ANY, objectBag: ObjectBag] = { <<[group, entity] describes the group and the entity to which it belongs.>> <> }; SymmetryAddPoints: PUBLIC PROC [group: SymmetryGroup, entity: REF ANY, objectBag: ObjectBag] = { <<[group, entity] describes the group and the entity to which it belongs.>> <> }; <<>> <> <<>> CoordFrameAddPoint: PUBLIC PROC [point: Point, objectBag: ObjectBag] = { <> <> }; CoordFrameAddXLine: PUBLIC PROC [xVal: REAL, objectBag: ObjectBag] = { <> <> }; CoordFrameAddYLine: PUBLIC PROC [yVal: REAL, objectBag: ObjectBag] = { <> <> }; <<>> <> AddIntersectionPointFeature: PUBLIC PROC [point: Point, feature1, feature2: FeatureData, objectBag: ObjectBag] = { featureData: FeatureData; featureData _ NEW[FeatureDataObj]; featureData.type _ intersectionPoint; featureData.line _ NIL; featureData.line1Feature _ feature1; featureData.line2Feature _ feature2; featureData.degrees _ 999.0; featureData.seg _ NIL; featureData.point _ point; AddFeature[featureData, objectBag]; }; FlushObjectBag: PUBLIC PROC [objectBag: ObjectBag] = { ERROR NotYetImplemented; }; <> <<>> AdjustVisibilityPoint: PUBLIC PROC [testPoint: Point, tolerance: REAL, objectBag: ObjectBag] = { <> dist: REAL; feature: FeatureData; success: BOOL; FOR slopeLineList: LIST OF FeatureData _ objectBag.slopeLines, slopeLineList.rest UNTIL slopeLineList = NIL DO feature _ slopeLineList.first; dist _ GGLines.LineDistance[testPoint, feature.line]; IF dist < tolerance THEN feature.visible _ TRUE ELSE feature.visible _ FALSE; ENDLOOP; FOR seqList: LIST OF FeatureData _ objectBag.seqs, seqList.rest UNTIL seqList = NIL DO feature _ seqList.first; [dist, ----, ----, success] _ NearestSegment[testPoint, feature.tseq, tolerance]; IF success AND dist < tolerance THEN feature.visible _ TRUE ELSE feature.visible _ FALSE; ENDLOOP; FOR circleList: LIST OF FeatureData _ objectBag.radiiCircles, circleList.rest UNTIL circleList = NIL DO feature _ circleList.first; dist _ GGCircles.CircleDistance[testPoint, feature.circle]; IF dist < tolerance THEN feature.visible _ TRUE ELSE feature.visible _ FALSE; ENDLOOP; }; AdjustVisibilityBox: PUBLIC PROC [box: BoundBox, tolerance: REAL, objectBag: ObjectBag] = {}; DrawObjectBag: PUBLIC PROC [dc: Imager.Context, objectBag: ObjectBag, camera: Camera, gargoyleData: GargoyleData] = { <> feature: FeatureData; Imager.SetStrokeWidth[dc, 1.0]; Imager.SetColor[dc, Imager.MakeGray[0.6]]; FOR slopeLineList: LIST OF FeatureData _ objectBag.slopeLines, slopeLineList.rest UNTIL slopeLineList = NIL DO feature _ slopeLineList.first; IF feature.visible THEN GGShapes.DrawLine[dc, feature.line]; ENDLOOP; FOR seqList: LIST OF FeatureData _ objectBag.seqs, seqList.rest UNTIL seqList = NIL DO feature _ seqList.first; IF feature.visible THEN GGRefresh.DrawSequence[dc, feature.tseq, gargoyleData]; ENDLOOP; FOR circleList: LIST OF FeatureData _ objectBag.radiiCircles, circleList.rest UNTIL circleList = NIL DO feature _ circleList.first; IF feature.visible THEN GGShapes.DrawCircle[dc, feature.circle]; ENDLOOP; FOR dLineList: LIST OF FeatureData _ objectBag.distanceLines, dLineList.rest UNTIL dLineList = NIL DO feature _ dLineList.first; IF feature.visible THEN GGShapes.DrawLine[dc, feature.line]; ENDLOOP; }; DrawObjectBagRegardless: PUBLIC PROC [dc: Imager.Context, objectBag: ObjectBag, camera: Camera, gargoyleData: GargoyleData] = { <> feature: FeatureData; IF objectBag = NIL THEN RETURN; Imager.SetStrokeWidth[dc, 1.0]; Imager.SetColor[dc, Imager.MakeGray[0.6]]; FOR slopeLineList: LIST OF FeatureData _ objectBag.slopeLines, slopeLineList.rest UNTIL slopeLineList = NIL DO feature _ slopeLineList.first; GGShapes.DrawLine[dc, feature.line]; ENDLOOP; FOR seqList: LIST OF FeatureData _ objectBag.seqs, seqList.rest UNTIL seqList = NIL DO feature _ seqList.first; GGRefresh.DrawSequence[dc, feature.tseq, gargoyleData]; ENDLOOP; FOR circleList: LIST OF FeatureData _ objectBag.radiiCircles, circleList.rest UNTIL circleList = NIL DO feature _ circleList.first; GGShapes.DrawCircle[dc, feature.circle]; ENDLOOP; FOR dLineList: LIST OF FeatureData _ objectBag.distanceLines, dLineList.rest UNTIL dLineList = NIL DO feature _ dLineList.first; GGShapes.DrawLine[dc, feature.line]; ENDLOOP; }; END.