<> <> <> <> DIRECTORY AtomButtons, CodeTimer, Feedback, GGAlign, GGBasicTypes, GGCaret, GGGravity, GGInterfaceTypes, GGModelTypes, GGScene, GGOutline, GGSegmentTypes, GGSelect, GGSequence, GGSlice, GGState, GGTraj, GList, Imager, Process, Rope, Vectors2d; GGAlignImpl: CEDAR PROGRAM IMPORTS CodeTimer, Feedback, GGCaret, GGGravity, GGScene, GGOutline, GGSelect, GGSequence, GGSlice, GGState, GGTraj, GList, Process, Vectors2d EXPORTS GGAlign = BEGIN AlignmentLine: TYPE = GGInterfaceTypes.AlignmentLine; AlignmentObject: TYPE = GGModelTypes.AlignmentObject; Angle: TYPE = GGBasicTypes.Angle; Caret: TYPE = GGInterfaceTypes.Caret; Circle: TYPE = GGBasicTypes.Circle; ControlPointGenerator: TYPE = GGModelTypes.ControlPointGenerator; Edge: TYPE = GGBasicTypes.Edge; EntityGenerator: TYPE = GGScene.EntityGenerator; FeatureData: TYPE = REF FeatureDataObj; FeatureDataObj: TYPE = GGModelTypes.FeatureDataObj; FilterOutlineProc: TYPE = GGAlign.FilterOutlineProc; FilterSliceProc: TYPE = GGAlign.FilterSliceProc; Filters: TYPE = GGInterfaceTypes.Filters; GGData: TYPE = GGInterfaceTypes.GGData; Joint: TYPE = GGModelTypes.Joint; JointGenerator: TYPE = GGModelTypes.JointGenerator; Line: TYPE = GGBasicTypes.Line; AlignBag: TYPE = GGInterfaceTypes.AlignBag; AlignBagObj: TYPE = GGInterfaceTypes.AlignBagObj; Outline: TYPE = GGModelTypes.Outline; OutlineData: TYPE = GGOutline.OutlineData; OutlineDescriptor: TYPE = REF OutlineDescriptorObj; OutlineDescriptorObj: TYPE = GGModelTypes.OutlineDescriptorObj; Point: TYPE = GGBasicTypes.Point; PointAndDone: TYPE = GGModelTypes.PointAndDone; PointGenerator: TYPE = GGModelTypes.PointGenerator; PointPairGenerator: TYPE = GGModelTypes.PointPairGenerator; ScalarButtonClient: TYPE = AtomButtons.ScalarButtonClient; Scene: TYPE = GGModelTypes.Scene; Segment: TYPE = GGSegmentTypes.Segment; SegmentGenerator: TYPE = GGModelTypes.SegmentGenerator; SelectionClass: TYPE = GGInterfaceTypes.SelectionClass; Sequence: TYPE = GGModelTypes.Sequence; SequenceGenerator: TYPE = GGModelTypes.SequenceGenerator; Slice: TYPE = GGModelTypes.Slice; SliceDescriptor: TYPE = REF SliceDescriptorObj; SliceDescriptorObj: TYPE = GGModelTypes.SliceDescriptorObj; SliceDescriptorGenerator: TYPE = GGModelTypes.SliceDescriptorGenerator; SliceGenerator: TYPE = GGModelTypes.SliceGenerator; SliceParts: TYPE = GGModelTypes.SliceParts; Traj: TYPE = GGModelTypes.Traj; TrajEnd: TYPE = GGModelTypes.TrajEnd; TrajGenerator: TYPE = GGScene.TrajGenerator; TriggerBag: TYPE = REF TriggerBagObj; TriggerBagObj: TYPE = GGInterfaceTypes.TriggerBagObj; Vector: TYPE = GGBasicTypes.Vector; Problem: SIGNAL [msg: Rope.ROPE] = Feedback.Problem; <> <> <> <> <> <> <> <> <> <<>> EntityNotFound: PUBLIC SIGNAL = CODE; UnexpectedType: PUBLIC ERROR = CODE; BrokenInvariant: PUBLIC ERROR = CODE; << [Artwork node; type 'ArtworkInterpress on' to command tool] >> <> emptyTriggerBag: PUBLIC TriggerBag; CreateTriggerBag: PUBLIC PROC [] RETURNS [triggerBag: TriggerBag] = { triggerBag _ NEW[TriggerBagObj _ [slices: NIL, intersectionPoints: NIL, anchor: NIL]]; }; FlushTriggerBag: PUBLIC PROC [triggerBag: TriggerBag] = { <> triggerBag.slices _ NIL; triggerBag.intersectionPoints _ NIL; triggerBag.anchor _ NIL; }; CopyTriggerBag: PUBLIC PROC [triggerBag: TriggerBag] RETURNS [copy: TriggerBag] = { copy _ CreateTriggerBag[]; <> copy.slices _ NARROW[GList.Copy[triggerBag.slices]]; copy.intersectionPoints _ NIL; copy.anchor _ triggerBag.anchor; }; <> emptyAlignBag: PUBLIC AlignBag; CreateAlignBag: PUBLIC PROC [] RETURNS [alignBag: AlignBag] = { alignBag _ NEW[AlignBagObj _ [ slopeLines: NIL, angleLines: NIL, radiiCircles: NIL, distanceLines: NIL, midpoints: NIL, intersectionPoints: NIL, anchor: NIL ]]; }; FlushAlignBag: PUBLIC PROC [alignBag: AlignBag] = { alignBag.slopeLines _ NIL; alignBag.angleLines _ NIL; alignBag.radiiCircles _ NIL; alignBag.distanceLines _ NIL; alignBag.midpoints _ NIL; alignBag.intersectionPoints _ NIL; alignBag.anchor _ NIL; }; <> FillStaticTriggerBag: PUBLIC PROC [anchor: Caret, scene: Scene, heuristics: BOOL, triggerBag: TriggerBag] = { AddAnchorTrigger[anchor, triggerBag]; <> AddAllHotSlices[scene, triggerBag]; }; FillDynamicTriggerBag: PUBLIC PROC [anchor: Caret, scene: Scene, heuristics: BOOL, triggerBag: TriggerBag] = { AddAnchorTrigger[anchor, triggerBag]; <> AddAllHotSlices[scene, triggerBag]; AddHeuristics[scene, heuristics, $Drag, triggerBag]; -- nothing is being dragged RemoveMoving[scene, triggerBag]; -- nothing is moving }; <> FillStaticSceneBag: PUBLIC PROC [scene: Scene, sceneBag: TriggerBag] = { <> AddAllSlices[scene, sceneBag]; ComputeAllBoundingBoxes[sceneBag]; }; FillDynamicSceneBag: PUBLIC PROC [scene: Scene, sceneBag: TriggerBag] = { <> AddAllSlices[scene, sceneBag]; RemoveMoving[scene, sceneBag]; ComputeAllBoundingBoxes[sceneBag]; }; <> FillStaticAlignBag: PUBLIC PROC [triggerBag: TriggerBag, sceneBag: TriggerBag, filters: Filters, hideAlignments: BOOL, midpoints: BOOL, alignBag: AlignBag] = { BuiltInFilters[triggerBag, filters, hideAlignments, alignBag]; AddAllMidpoints[sceneBag, midpoints, alignBag]; }; FillDynamicAlignBag: PUBLIC PROC [triggerBag: TriggerBag, sceneBag: TriggerBag, filters: Filters, hideAlignments: BOOL, midpoints: BOOL, action: ATOM, alignBag: AlignBag] = { BuiltInFilters[triggerBag, filters, hideAlignments, alignBag]; AddAllMidpoints[sceneBag, midpoints, alignBag]; }; <<>> <> SetStaticBags: PUBLIC PROC [ggData: GGData] = { <> <> <> <> triggerBag: TriggerBag _ ggData.hitTest.triggerBag; alignBag: AlignBag _ ggData.hitTest.alignBag; sceneBag: TriggerBag _ ggData.hitTest.sceneBag; scene: Scene _ ggData.scene; anchor: Caret _ ggData.anchor; heuristics: BOOL _ GGState.Heuristics[ggData]; filters: Filters _ ggData.hitTest; hideAlignments: BOOL _ NOT GGState.ShowAlignments[ggData]; midpoints: BOOL _ GGState.Midpoints[ggData]; IF hideAlignments THEN { FlushAlignBag[alignBag]; FlushTriggerBag[sceneBag]; FillStaticSceneBag[scene, sceneBag]; } ELSE { CodeTimer.StartInt[$SetBagsForAction, $Gargoyle]; <> FlushTriggerBag[triggerBag]; FillStaticTriggerBag[anchor, scene, heuristics, triggerBag]; <> FlushTriggerBag[sceneBag]; FillStaticSceneBag[scene, sceneBag]; <> FlushAlignBag[alignBag]; FillStaticAlignBag[triggerBag, sceneBag, filters, hideAlignments, midpoints, alignBag]; CodeTimer.StopInt[$SetBagsForAction, $Gargoyle]; }; }; SetDynamicBags: PUBLIC PROC [ggData: GGData, action: ATOM] = { <> <> <> <> triggerBag: TriggerBag _ ggData.hitTest.triggerBag; alignBag: AlignBag _ ggData.hitTest.alignBag; sceneBag: TriggerBag _ ggData.hitTest.sceneBag; scene: Scene _ ggData.scene; anchor: Caret _ ggData.anchor; heuristics: BOOL _ GGState.Heuristics[ggData]; filters: Filters _ ggData.hitTest; hideAlignments: BOOL _ NOT GGState.ShowAlignments[ggData]; midpoints: BOOL _ GGState.Midpoints[ggData]; IF hideAlignments THEN { FlushAlignBag[alignBag]; FlushTriggerBag[sceneBag]; FlushTriggerBag[triggerBag]; -- added March 30, 1987. KAP FillDynamicSceneBag[scene, sceneBag]; } ELSE { CodeTimer.StartInt[$SetBagsForAction, $Gargoyle]; <> FlushTriggerBag[triggerBag]; FillDynamicTriggerBag[anchor, scene, heuristics, triggerBag]; <> FlushTriggerBag[sceneBag]; FillDynamicSceneBag[scene, sceneBag]; <> FlushAlignBag[alignBag]; FillDynamicAlignBag[triggerBag, sceneBag, filters, hideAlignments, midpoints, action, alignBag]; CodeTimer.StopInt[$SetBagsForAction, $Gargoyle]; }; }; StaticToDynamicBags: PUBLIC PROC [ggData: GGData] RETURNS [repaintForeground: BOOL] = { <> <> <> <> <> triggerBag: TriggerBag _ ggData.hitTest.triggerBag; sceneBag: TriggerBag _ ggData.hitTest.sceneBag; alignBag: AlignBag _ ggData.hitTest.alignBag; heuristics: BOOL _ GGState.Heuristics[ggData]; filters: Filters _ ggData.hitTest; hideAlignments: BOOL _ NOT GGState.ShowAlignments[ggData]; midpoints: BOOL _ GGState.Midpoints[ggData]; repaintForeground _ SomeSelectedIsHot[ggData.scene] OR GGState.Heuristics[ggData]; IF ggData.camera.hideAlignments THEN { <> repaintForeground _ FALSE; FlushAlignBag[alignBag]; ggData.hitTest.oldSceneBag _ sceneBag; sceneBag _ StaticToDynamicSceneBag[ggData.scene, sceneBag]; ggData.hitTest.sceneBag _ sceneBag; } ELSE { CodeTimer.StartInt[$UpdateBagsForAction, $Gargoyle]; <> ggData.hitTest.oldTriggerBag _ triggerBag; triggerBag _ CopyTriggerBag[triggerBag]; AddHeuristics[ggData.scene, heuristics, $Drag, triggerBag]; RemoveMoving[ggData.scene, triggerBag]; ggData.hitTest.triggerBag _ triggerBag; <> ggData.hitTest.oldSceneBag _ sceneBag; sceneBag _ StaticToDynamicSceneBag[ggData.scene, sceneBag]; ggData.hitTest.sceneBag _ sceneBag; <> ggData.hitTest.oldAlignBag _ alignBag; alignBag _ CreateAlignBag[]; BuiltInFilters[triggerBag, filters, hideAlignments, alignBag]; AddAllMidpoints[sceneBag, midpoints, alignBag]; ggData.hitTest.alignBag _ alignBag; CodeTimer.StopInt[$UpdateBagsForAction, $Gargoyle]; }; }; StaticToDynamicSceneBag: PROC [scene: Scene, sceneBag: TriggerBag] RETURNS [newBag: TriggerBag] = { newBag _ CopyTriggerBag[sceneBag]; RemoveMoving[scene, newBag]; CodeTimer.StartInt[$ComputeBoundBoxes, $Gargoyle]; ComputeAllBoundingBoxes[newBag]; CodeTimer.StopInt[$ComputeBoundBoxes, $Gargoyle]; }; DynamicToStaticBags: PUBLIC PROC [ggData: GGData] RETURNS [repaintForeground: BOOL] = { triggerBag: TriggerBag; sceneBag: TriggerBag; alignBag: AlignBag _ ggData.hitTest.alignBag; filters: Filters _ ggData.hitTest; hideAlignments: BOOL _ NOT GGState.ShowAlignments[ggData]; midpoints: BOOL _ GGState.Midpoints[ggData]; <> triggerBag _ ggData.hitTest.triggerBag _ ggData.hitTest.oldTriggerBag; sceneBag _ ggData.hitTest.sceneBag _ ggData.hitTest.oldSceneBag; ComputeAllBoundingBoxes[sceneBag]; <> alignBag _ CreateAlignBag[]; BuiltInFilters[triggerBag, filters, hideAlignments, alignBag]; AddAllMidpoints[sceneBag, midpoints, alignBag]; ggData.hitTest.alignBag _ alignBag; repaintForeground _ TRUE; }; UpdateBagsForAdd: PUBLIC PROC [oldOutline: Outline, newOutline: Outline, trajEnd: TrajEnd, ggData: GGData] RETURNS [repaintForeground: BOOL] = { <> <> <> <> <> triggerBag: TriggerBag _ ggData.hitTest.triggerBag; sceneBag: TriggerBag _ ggData.hitTest.sceneBag; alignBag: AlignBag _ ggData.hitTest.alignBag; scene: Scene _ ggData.scene; newHot, oldHot, newWhole, oldWhole, hotMinusOldHot: OutlineDescriptor; hideAlignments: BOOL _ NOT GGState.ShowAlignments[ggData]; midpoints: BOOL _ GGState.Midpoints[ggData]; alignObjects: LIST OF FeatureData; <> <> oldHot _ RemoveEntireHotSlice[oldOutline, triggerBag]; newHot _ GGSelect.FindSelectedSlice[newOutline, scene, hot]; <> <> <> IF newHot # NIL THEN [] _ AddHotSlice[newHot, triggerBag]; <> <> oldWhole _ RemoveEntireHotSlice[oldOutline, sceneBag]; newWhole _ newOutline.class.newParts[newOutline, NIL, slice]; GGSlice.UpdateDescriptorBoundBoxes[newWhole]; <<[] _ AddHotOutline[newWhole, sceneBag];>> [] _ AddHotSlice[newWhole, sceneBag]; <> <> IF newHot = NIL THEN hotMinusOldHot _ NIL ELSE { mask: Sequence; maskD: OutlineDescriptor; newOutlineData: OutlineData _ NARROW[newOutline.data]; traj: Traj _ newOutlineData.children.first; IF trajEnd = lo THEN mask _ GGSequence.Union[GGSequence.CreateFromSegment[traj, 0], GGSequence.CreateFromJoint[traj, 0]] ELSE mask _ GGSequence.Union[GGSequence.CreateFromSegment[traj, GGTraj.HiSegment[traj]], GGSequence.CreateFromJoint[traj, GGTraj.HiJoint[traj]]]; maskD _ GGOutline.DescriptorFromSequence[newOutline, mask]; hotMinusOldHot _ newOutline.class.differenceParts[newHot, newOutline.class.differenceParts[newWhole, maskD]]; <> alignObjects _ IncrementalFilterSlice[hotMinusOldHot, ggData.hitTest, hideAlignments, alignBag]; }; <> IncrementalMidpointsSlice[newWhole, midpoints, alignBag]; <> <> <> <> }; UpdateBagsForNewSlices: PUBLIC PROC [newSlices: LIST OF Slice, ggData: GGData] = { <> <> <> <> triggerBag: TriggerBag _ ggData.hitTest.triggerBag; sceneBag: TriggerBag _ ggData.hitTest.sceneBag; alignBag: AlignBag _ ggData.hitTest.alignBag; scene: Scene _ ggData.scene; hideAlignments: BOOL _ NOT GGState.ShowAlignments[ggData]; midpoints: BOOL _ GGState.Midpoints[ggData]; <> FOR list: LIST OF Slice _ newSlices, list.rest UNTIL list = NIL DO wholeD: SliceDescriptor _ list.first.class.newParts[list.first, NIL, slice]; GGSlice.UpdateDescriptorBoundBoxes[wholeD]; [] _ AddHotSlice[wholeD, sceneBag]; IncrementalMidpointsSlice[wholeD, midpoints, alignBag]; ENDLOOP; }; <> <<>> <<};>> <<>> <<>> <> <<>> AddAnchorTrigger: PROC [anchor: Caret, triggerBag: TriggerBag] = { [] _ CreateAnchorTrigger[anchor, triggerBag]; }; <> <> <> <> <> <> <> <> <<};>> <<>> AddAllHotSlices: PROC [scene: Scene, triggerBag: TriggerBag] = { feature: FeatureData; sliceDescGen: SliceDescriptorGenerator _ GGSelect.SelectedSlices[scene, hot]; FOR sliceD: SliceDescriptor _ GGSelect.NextSliceDescriptor[sliceDescGen], GGSelect.NextSliceDescriptor[sliceDescGen] UNTIL sliceD = NIL DO feature _ GGGravity.FeatureFromSlice[sliceD.slice, sliceD.parts]; AddFeature[feature, triggerBag]; ENDLOOP; }; AddHeuristics: PROC [scene: Scene, heuristics: BOOL, atom: ATOM, triggerBag: TriggerBag] = { feature: FeatureData; IF NOT heuristics THEN RETURN; SELECT atom FROM $Drag => { <> sliceDGen: GGModelTypes.SliceDescriptorGenerator _ GGSelect.SelectedSlices[scene, normal]; <> <> <> <> FOR sliceD: SliceDescriptor _ GGSelect.NextSliceDescriptor[sliceDGen], GGSelect.NextSliceDescriptor[sliceDGen] UNTIL sliceD = NIL DO feature _ GGGravity.FeatureFromSlice[sliceD.slice, NIL]; AddFeature[feature, triggerBag]; ENDLOOP; }; $CaretPos => NULL; ENDCASE => ERROR UnexpectedType; }; <> <> <> <> <<[background, overlay, rubber, drag] _ outlineD.slice.class.movingParts[selSliceD.slice, selSliceD.parts];>> <> <> <<};>> <<>> RemoveMovingSlice: PUBLIC PROC [sliceD: SliceDescriptor, scene: Scene] RETURNS [stationary: SliceDescriptor] = { selSliceD: SliceDescriptor _ GGSelect.FindSelectedSlice[sliceD.slice, scene, normal]; background, overlay, rubber, drag, move: SliceDescriptor; IF selSliceD = NIL THEN RETURN[sliceD]; -- clearly nothing is moving [background, overlay, rubber, drag] _ sliceD.slice.class.movingParts[selSliceD.slice, selSliceD.parts]; move _ sliceD.slice.class.unionParts[rubber, drag]; stationary _ sliceD.slice.class.differenceParts[sliceD, move]; }; RemoveMoving: PROC [scene: Scene, triggerBag: TriggerBag] = { <> DeleteTriggersFilter[triggerBag, scene, --RemoveMovingOutline,-- RemoveMovingSlice]; }; BuiltInFilters: PUBLIC PROC [triggerBag: TriggerBag, filters: Filters, hideAlignments: BOOL, alignBag: AlignBag] = { <> anchor: Caret; anchorFeature: FeatureData; sliceD: SliceDescriptor; <> pointGen: PointGenerator; pointPairGen: PointPairGenerator; <> <> index: NAT _ 0; CodeTimer.StartInt[$BuiltInFilters, $Gargoyle]; IF hideAlignments THEN { FlushAlignBag[alignBag]; RETURN; }; <> anchorFeature _ triggerBag.anchor; IF anchorFeature # NIL AND GGCaret.Exists[(anchor _ NARROW[anchorFeature.shape, Caret])] THEN { point: Point _ GGCaret.GetPoint[anchor]; AddAnchorObject[anchorFeature, alignBag]; [] _ PointFireRule[point, filters, alignBag]; }; <> <> <> <> <> <<[] _ PointFireRule[next.point, filters, alignBag];>> <> <> <> <> <<[] _ SegmentFireRule[index, next.lo, next.hi, filters, alignBag];>> <> <> <> <> FOR l: LIST OF FeatureData _ triggerBag.slices, l.rest UNTIL l = NIL DO sliceD _ NARROW[l.first.shape]; pointGen _ sliceD.slice.class.pointsInDescriptor[sliceD]; FOR next: GGModelTypes.PointAndDone _ sliceD.slice.class.nextPoint[pointGen], sliceD.slice.class.nextPoint[pointGen] UNTIL next.done DO [] _ PointFireRule[next.point, filters, alignBag]; ENDLOOP; pointPairGen _ sliceD.slice.class.pointPairsInDescriptor[sliceD]; index _ 0; FOR next: GGModelTypes.PointPairAndDone _ sliceD.slice.class.nextPointPair[pointPairGen], sliceD.slice.class.nextPointPair[pointPairGen] UNTIL next.done DO [] _ SegmentFireRule[9999, next.lo, next.hi, filters, alignBag]; index _ index + 1; ENDLOOP; ENDLOOP; CodeTimer.StopInt[$BuiltInFilters, $Gargoyle]; }; <<>> AddAllMidpoints: PUBLIC PROC [sceneBag: TriggerBag, midpoints: BOOL, alignBag: AlignBag] = { <> sliceD: SliceDescriptor; <> pointPairGen: PointPairGenerator; <> CodeTimer.StartInt[$AddAllMidpoints, $Gargoyle]; IF NOT GGState.PrecomputeMidpoints[] THEN RETURN; alignBag.midpoints _ NIL; IF NOT midpoints THEN RETURN; <> <> <> <> <> <> <<[] _ GGGravity.SegmentAddMidpoint[pairCount, next.lo, next.hi, alignBag];>> <> <> <> <> FOR l: LIST OF FeatureData _ sceneBag.slices, l.rest UNTIL l = NIL DO pairCount: NAT _ 0; sliceD _ NARROW[l.first.shape]; pointPairGen _ sliceD.slice.class.pointPairsInDescriptor[sliceD]; FOR next: GGModelTypes.PointPairAndDone _ sliceD.slice.class.nextPointPair[pointPairGen], sliceD.slice.class.nextPointPair[pointPairGen] UNTIL next.done DO [] _ GGGravity.SegmentAddMidpoint[pairCount, next.lo, next.hi, alignBag]; pairCount _ pairCount+1; ENDLOOP; ENDLOOP; CodeTimer.StopInt[$AddAllMidpoints, $Gargoyle]; }; <> CreateAnchorTrigger: PUBLIC PROC [anchor: Caret, triggerBag: TriggerBag] RETURNS [feature: FeatureData] = { feature _ GGGravity.FeatureFromAnchor[anchor]; AddFeature[feature, triggerBag]; }; <> <> <> <> <> <> <<}>> <> <> <> <> <> <<};>> <<};>> AddHotSlice: PUBLIC PROC [sliceD: SliceDescriptor, triggerBag: TriggerBag] RETURNS [feature: FeatureData] = { oldD, unionD: SliceDescriptor; oldD _ FindOldSlice[sliceD.slice, triggerBag.slices]; IF oldD = NIL THEN { feature _ GGGravity.FeatureFromSlice[sliceD.slice, sliceD.parts]; triggerBag.slices _ AppendFeature[feature, triggerBag.slices]; } ELSE { unionD _ sliceD.slice.class.unionParts[oldD, sliceD]; triggerBag.slices _ DeleteSlice[oldD.slice, triggerBag.slices]; feature _ GGGravity.FeatureFromSlice[sliceD.slice, unionD.parts]; triggerBag.slices _ AppendFeature[feature, triggerBag.slices]; }; }; IncrementalFilterSlice: PUBLIC PROC [sliceD: SliceDescriptor, filters: Filters, hideAlignments: BOOL, alignBag: AlignBag] RETURNS [alignObjects: LIST OF FeatureData] = { pointGen: PointGenerator; pointPairGen: PointPairGenerator; pointGen _ sliceD.slice.class.pointsInDescriptor[sliceD]; FOR next: GGModelTypes.PointAndDone _ sliceD.slice.class.nextPoint[pointGen], sliceD.slice.class.nextPoint[pointGen] UNTIL next.done DO alignObjects _ NARROW[GList.Nconc[PointFireRule[next.point, filters, alignBag], alignObjects]]; ENDLOOP; pointPairGen _ sliceD.slice.class.pointPairsInDescriptor[sliceD]; FOR next: GGModelTypes.PointPairAndDone _ sliceD.slice.class.nextPointPair[pointPairGen], sliceD.slice.class.nextPointPair[pointPairGen] UNTIL next.done DO alignObjects _ NARROW[GList.Nconc[SegmentFireRule[9999, next.lo, next.hi, filters, alignBag], alignObjects]]; ENDLOOP; }; <> <> <> <> <> <> <> <> <> <> <> <<};>> <<>> <> <> <> <> <> <<>> <> <> <> <> <<[] _ GGGravity.SegmentAddMidpoint[pairCount, next.lo, next.hi, alignBag];>> <> <> <<};>> <<>> IncrementalMidpointsSlice: PUBLIC PROC [sliceD: SliceDescriptor, midpoints: BOOL, alignBag: AlignBag] = { <> <> pointPairGen: GGModelTypes.PointPairGenerator; pairCount: NAT _ 0; IF NOT midpoints THEN RETURN; IF NOT GGState.PrecomputeMidpoints[] THEN RETURN; pointPairGen _ sliceD.slice.class.pointPairsInDescriptor[sliceD]; FOR next: GGModelTypes.PointPairAndDone _ sliceD.slice.class.nextPointPair[pointPairGen], sliceD.slice.class.nextPointPair[pointPairGen] UNTIL next.done DO [] _ GGGravity.SegmentAddMidpoint[pairCount, next.lo, next.hi, alignBag]; pairCount _ pairCount + 1; ENDLOOP; }; IncrementalFilters: PUBLIC PROC [trigger: FeatureData, filters: Filters, hideAlignments: BOOL, alignBag: AlignBag] RETURNS [alignObjects: LIST OF FeatureData] = { <> alignObjects _ NIL; IF hideAlignments THEN { FlushAlignBag[alignBag]; RETURN; }; WITH trigger.shape SELECT FROM sliceD: SliceDescriptor => { alignObjects _ IncrementalFilterSlice[sliceD, filters, hideAlignments, alignBag]; }; < {>> <> <<};>> anchor: Caret => { <> IF GGCaret.Exists[anchor] THEN { point: Point _ GGCaret.GetPoint[anchor]; [] _ PointFireRule[point, filters, alignBag]; }; }; ENDCASE => ERROR; }; <<>> <<>> <> RemoveAnchorTrigger: PUBLIC PROC [triggerBag: TriggerBag] = { triggerBag.anchor _ NIL; }; <> <> <> <> <<};>> <<};>> <<>> <> <> <> <> <> <> <> <> <> <> <<};>> <<};>> <<};>> <<>> RemoveEntireHotSlice: PUBLIC PROC [slice: Slice, triggerBag: TriggerBag] RETURNS [oldSliceD: SliceDescriptor]= { oldSliceD _ FindOldSlice[slice, triggerBag.slices]; IF oldSliceD#NIL THEN { triggerBag.slices _ DeleteSlice[oldSliceD.slice, triggerBag.slices]; }; }; RemoveHotSlice: PUBLIC PROC [sliceD: SliceDescriptor, triggerBag: TriggerBag] = { oldSliceD, diff: SliceDescriptor; feature: FeatureData; oldSliceD _ FindOldSlice[sliceD.slice, triggerBag.slices]; IF oldSliceD#NIL THEN { diff _ sliceD.slice.class.differenceParts[oldSliceD, sliceD]; triggerBag.slices _ DeleteSliceD[oldSliceD, triggerBag.slices]; IF NOT sliceD.slice.class.isEmptyParts[diff] THEN { feature _ GGGravity.FeatureFromSlice[sliceD.slice, diff]; triggerBag.slices _ AppendFeature[feature, triggerBag.slices]; }; }; }; <> <> <> <> <> <> <<};>> <<>> <> <> <<>> <<};>> <<>> <> <<>> <> AddFeature: PROC [featureData: FeatureData, triggerBag: TriggerBag] = { Process.CheckForAbort[]; SELECT featureData.type FROM < {>> <> <<};>> outline, slice => { triggerBag.slices _ CONS[featureData, triggerBag.slices]; }; anchor => { triggerBag.anchor _ featureData; }; ENDCASE => ERROR; }; DeleteTriggersFilter: PROC [triggerBag: TriggerBag, scene: Scene, --filterOutlineProc: FilterOutlineProc,-- filterSliceProc: FilterSliceProc] = { <> <> sliceD, newSliceD: SliceDescriptor; <> sliceFeatures: LIST OF FeatureData _ triggerBag.slices; newFeature: FeatureData; <> triggerBag.slices _ NIL; <> <> <> <> <> <> <<};>> <> FOR sliceList: LIST OF FeatureData _ sliceFeatures, sliceList.rest UNTIL sliceList = NIL DO sliceD _ NARROW[sliceList.first.shape]; newSliceD _ filterSliceProc[sliceD, scene]; IF NOT sliceD.slice.class.isEmptyParts[newSliceD] THEN { newFeature _ GGGravity.FeatureFromSlice[newSliceD.slice, newSliceD.parts]; triggerBag.slices _ CONS[newFeature, triggerBag.slices]; }; ENDLOOP; }; <> <<>> <> <> <> <> <> <> <> <> <<};>> <<>> ComputeAllBoundingBoxes: PROC [sceneBag: TriggerBag] = { featureData: FeatureData; outlineD: OutlineDescriptor; FOR list: LIST OF FeatureData _ sceneBag.slices, list.rest UNTIL list = NIL DO featureData _ list.first; outlineD _ NARROW[featureData.shape]; GGSlice.UpdateDescriptorBoundBoxes[outlineD]; ENDLOOP; }; <> <> <> <> <> <> <> <> <<};>> <<>> AddAllSlices: PROC [scene: Scene, triggerBag: TriggerBag] = { feature: FeatureData; sliceGen: SliceGenerator _ GGScene.SlicesInScene[scene]; FOR slice: Slice _ GGScene.NextSlice[sliceGen], GGScene.NextSlice[sliceGen] UNTIL slice = NIL DO feature _ GGGravity.FeatureFromSlice[slice]; AddFeature[feature, triggerBag]; ENDLOOP; }; <<>> <> AddAnchorObject: PROC [anchorFeature: FeatureData, alignBag: AlignBag] = { alignBag.anchor _ anchorFeature; }; PointFireRule: PROC [point: Point, filters: Filters, alignBag: AlignBag] RETURNS [alignObjects: LIST OF FeatureData] = { firstButton: ScalarButtonClient; feature: FeatureData; alignObjects _ NIL; <> firstButton _ filters.slopeHeader.scalarButtons; FOR thisButton: ScalarButtonClient _ firstButton, thisButton.next UNTIL thisButton = NIL DO IF thisButton.on THEN { feature _ GGGravity.JointAddSlopeLine[ degrees: thisButton.value, direction: Vectors2d.VectorFromAngle[thisButton.value], point: point, objectBag: alignBag ]; IF feature # NIL THEN alignObjects _ CONS[feature, alignObjects]; }; ENDLOOP; <> firstButton _ filters.radiusHeader.scalarButtons; FOR thisButton: ScalarButtonClient _ firstButton, thisButton.next UNTIL thisButton = NIL DO IF thisButton.on THEN { feature _ GGGravity.JointAddCircle[ radius: thisButton.value*filters.scaleUnit, point: point, objectBag: alignBag ]; IF feature # NIL THEN alignObjects _ CONS[feature, alignObjects]; }; ENDLOOP; }; SegmentFireRule: PROC [segNum: NAT, lo, hi: Point, filters: Filters, alignBag: AlignBag] RETURNS [alignObjects: LIST OF FeatureData] = { firstButton: ScalarButtonClient; line1, line2: FeatureData; alignObjects _ NIL; <> firstButton _ filters.distanceHeader.scalarButtons; FOR thisButton: ScalarButtonClient _ firstButton, thisButton.next UNTIL thisButton = NIL DO IF thisButton.on THEN { [line1, line2] _ GGGravity.SegmentAddDistanceLines[ distance: thisButton.value*filters.scaleUnit, segNum: segNum, lo: lo, hi: hi, objectBag: alignBag]; IF line1 # NIL THEN alignObjects _ CONS[line1, alignObjects]; IF line2 # NIL THEN alignObjects _ CONS[line2, alignObjects]; }; ENDLOOP; <> firstButton _ filters.angleHeader.scalarButtons; FOR thisButton: ScalarButtonClient _ firstButton, thisButton.next UNTIL thisButton = NIL DO IF thisButton.on THEN { [line1, line2] _ GGGravity.SegmentAddTwoAngleLines[degrees: thisButton.value, segNum: segNum, lo: lo, hi: hi, objectBag: alignBag]; IF line1 # NIL THEN alignObjects _ CONS[line1, alignObjects]; IF line2 # NIL THEN alignObjects _ CONS[line2, alignObjects]; }; ENDLOOP; }; <<>> <> SomeSelectedIsHot: PROC [scene: Scene] RETURNS [BOOL] = { sliceDescGen: SliceDescriptorGenerator _ GGSelect.SelectedSlices[scene, normal]; FOR sliceD: SliceDescriptor _ GGSelect.NextSliceDescriptor[sliceDescGen], GGSelect.NextSliceDescriptor[sliceDescGen] UNTIL sliceD=NIL DO IF GGSelect.IsSelectedInPart[sliceD.slice, scene, hot] THEN RETURN[TRUE]; ENDLOOP; RETURN[FALSE]; }; <> <> <> <> <> <> <> <> <> <> <> <> <> < {>> <> <<};>> < {>> <> <<};>> < ERROR;>> <> <> <> <<};>> <<>> <> <> <> <> <> <> <> <> <> <> < {>> <> <<};>> < {>> <> <<};>> < ERROR;>> <> <> <> <<};>> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <<};>> <<>> <<>> <> <<>> <> <> <> <> <> <<};>> <<>> FindOldSlice: PROC [slice: Slice, list: LIST OF FeatureData] RETURNS [oldSliceD: SliceDescriptor] = { FOR l: LIST OF FeatureData _ list, l.rest UNTIL l = NIL DO IF NARROW[l.first.shape, SliceDescriptor].slice = slice THEN RETURN [NARROW[l.first.shape]]; ENDLOOP; RETURN [NIL]; }; FindSequenceAndNeighbors: PROC [entity: Sequence, entityList: LIST OF FeatureData] RETURNS [beforeEnt, ent, afterEnt: LIST OF FeatureData] = { lastE: LIST OF FeatureData _ NIL; eList: LIST OF FeatureData _ entityList; IF eList = NIL THEN ERROR EntityNotFound; UNTIL eList = NIL DO IF NARROW[eList.first.shape, Sequence] = entity THEN { beforeEnt _ lastE; ent _ eList; afterEnt _ eList.rest; RETURN}; lastE _ eList; eList _ eList.rest; ENDLOOP; SIGNAL EntityNotFound; }; FindOutlineAndNeighbors: PROC [entity: Outline, entityList: LIST OF FeatureData] RETURNS [beforeEnt, ent, afterEnt: LIST OF FeatureData] = { lastE: LIST OF FeatureData _ NIL; eList: LIST OF FeatureData _ entityList; IF eList = NIL THEN ERROR EntityNotFound; UNTIL eList = NIL DO IF NARROW[eList.first.shape, OutlineDescriptor].slice = entity THEN { beforeEnt _ lastE; ent _ eList; afterEnt _ eList.rest; RETURN}; lastE _ eList; eList _ eList.rest; ENDLOOP; SIGNAL EntityNotFound; }; <> <> <> <> <> <> <> <> <> <> <> <<};>> <<>> FindSliceAndNeighbors: PROC [entity: Slice, entityList: LIST OF FeatureData] RETURNS [beforeEnt, ent, afterEnt: LIST OF FeatureData] = { lastE: LIST OF FeatureData _ NIL; eList: LIST OF FeatureData _ entityList; IF eList = NIL THEN ERROR EntityNotFound; UNTIL eList = NIL DO IF NARROW[eList.first.shape, SliceDescriptor].slice = entity THEN { beforeEnt _ lastE; ent _ eList; afterEnt _ eList.rest; RETURN}; lastE _ eList; eList _ eList.rest; ENDLOOP; SIGNAL EntityNotFound; }; <> <> <> <> <> <> <> <> <> <> <> <<};>> <<>> <<>> <> <> <> <<[before, at, after] _ FindOutlineAndNeighbors[outline, featureList ! EntityNotFound => {notFound _ TRUE; CONTINUE}];>> <> <> <> <> <> <<};>> <<};>> <<>> <> <> <> <> <<[before, at, after] _ FindOutlineAndNeighbors[outlineD.slice, featureList ! EntityNotFound => {notFound _ TRUE; CONTINUE}];>> <> <> <> <> <> <<};>> <<};>> <<>> DeleteSliceD: PROC [sliceD: SliceDescriptor, featureList: LIST OF FeatureData] RETURNS [smallerList: LIST OF FeatureData] = { before, at, after: LIST OF FeatureData; notFound: BOOL _ FALSE; IF featureList = NIL THEN RETURN[NIL]; [before, at, after] _ FindSliceAndNeighbors[sliceD.slice, featureList ! EntityNotFound => {notFound _ TRUE; CONTINUE}]; IF notFound THEN RETURN[featureList]; IF before = NIL THEN smallerList _ after ELSE { before.rest _ after; smallerList _ featureList; }; }; DeleteSlice: PROC [slice: Slice, featureList: LIST OF FeatureData] RETURNS [smallerList: LIST OF FeatureData] = { before, at, after: LIST OF FeatureData; notFound: BOOL _ FALSE; [before, at, after] _ FindSliceAndNeighbors[slice, featureList]; IF notFound THEN RETURN[featureList]; IF before = NIL THEN smallerList _ after ELSE { before.rest _ after; smallerList _ featureList; }; }; -- end of DeleteSlice AppendFeature: PUBLIC PROC [feature: FeatureData, featureList: LIST OF FeatureData] RETURNS [biggerList: LIST OF FeatureData] = { Process.CheckForAbort[]; biggerList _ CONS[feature, featureList]; }; <> <<>> <> <> <> <> <> <> <> <> <> <> <<[sceneBag.outlines, notFound] _ DeleteOutline[oldOutline, sceneBag.outlines];>> <> <> <> <<[triggerBag.outlines, notFound] _ DeleteOutline[oldOutline, triggerBag.outlines];>> <> <> <> <> <> <> <> <<};>> <> <> <> <<};>> <<>> <> InitStats: PROC [] = { boundBoxes, bags, interval: CodeTimer.Interval; boundBoxes _ CodeTimer.CreateInterval[$ComputeBoundBoxes]; bags _ CodeTimer.CreateInterval[$UpdateBagsForAction, LIST[boundBoxes]]; CodeTimer.AddInt[bags, $Gargoyle]; bags _ CodeTimer.CreateInterval[$SetBagsForAction, NIL]; CodeTimer.AddInt[bags, $Gargoyle]; interval _ CodeTimer.CreateInterval[$BuiltInFilters, NIL]; CodeTimer.AddInt[interval, $Gargoyle]; interval _ CodeTimer.CreateInterval[$AddAllMidpoints, NIL]; CodeTimer.AddInt[interval, $Gargoyle]; }; Init: PROC [] = { emptyTriggerBag _ CreateTriggerBag[]; emptyAlignBag _ CreateAlignBag[]; }; InitStats[]; Init[]; <<>> END.