grep -p -po -c -i "(slice|sliceD)':\b(Slice|SliceDescriptor)\b='>" GG*.mesa!H grep -p -po -c -i "ISTYPE'[\w',\b(OutlineDescriptor|SliceDescriptor)" GG*.mesa!H grep -p -po -c -i "\w':\b(Slice|SliceDescriptor)\b='>" GG*.mesa!H 71 total locations found by grep. 12 need work. []<>candy>Bier.pa>Gargoyle>GGAlignImpl.mesa!19 (12170) UpdateBagsForNewSlices []<>candy>Bier.pa>Gargoyle>GGAlignImpl.mesa!19 (23194) IncrementalFilters []<>candy>Bier.pa>Gargoyle>GGAlignImpl.mesa!19 (30626) []<>candy>bier.pa>Gargoyle>GGBoundBoxImpl.mesa!5 (6406) BoundBoxOfSelected []<>candy>bier.pa>Gargoyle>GGBoundBoxImpl.mesa!5 (7196) BoundBoxOfMoving []<>candy>bier.pa>Gargoyle>GGCaretImpl.mesa!5 (2730) SittingOnEnd SittingOnEndNEWW ready when assumptions OK []<>candy>Bier.pa>Gargoyle>GGEventImplA.mesa!16 (51870) Close []<>candy>bier.pa>Gargoyle>GGEventImplB.mesa!9 (2761) Top []<>candy>bier.pa>Gargoyle>GGEventImplB.mesa!9 (3559) Bottom []<>candy>bier.pa>Gargoyle>GGEventImplB.mesa!9 (6226) LineWidth []<>candy>bier.pa>Gargoyle>GGEventImplB.mesa!9 (7821) LineEnds []<>candy>bier.pa>Gargoyle>GGEventImplB.mesa!9 (9300) TrajJoints []<>candy>bier.pa>Gargoyle>GGEventImplB.mesa!9 (10608) DashesFromSelection []<>candy>bier.pa>Gargoyle>GGEventImplB.mesa!9 (11794) DashesOff []<>candy>bier.pa>Gargoyle>GGEventImplB.mesa!9 (13387) PrintStrokeValues []<>candy>bier.pa>Gargoyle>GGEventImplB.mesa!10 (20966) MakeHot []<>candy>bier.pa>Gargoyle>GGEventImplB.mesa!9 (23118) MakeAllHot []<>candy>bier.pa>Gargoyle>GGEventImplC.mesa!10 (20058) DescribeCurve []<>candy>bier.pa>Gargoyle>GGEventImplC.mesa!10 (20839) AddControlPoint []<>candy>bier.pa>Gargoyle>GGEventImplC.mesa!10 (25150) AddJoint []<>candy>bier.pa>Gargoyle>GGEventImplC.mesa!10 (30555) DoTheTransforms []<>candy>bier.pa>Gargoyle>GGEventImplC.mesa!10 (32136) AreaSelectNewAndDelete GGEventImplC.AreaSelectNewAndDeleteNEWW should already compile []<>candy>bier.pa>Gargoyle>GGEventImplC.mesa!10 (34345) AreaSelectAux []<>candy>bier.pa>Gargoyle>GGEventImplC.mesa!10 (34971) AreaSelectAux GGEventImplC.AreaSelectAuxNEWW should already compile. []<>candy>Bier.pa>Gargoyle>GGEventImplD.mesa!12 (18248) AreaColorToColorTool []<>candy>Bier.pa>Gargoyle>GGEventImplD.mesa!12 (18996) LineColorToColorTool []<>candy>Bier.pa>Gargoyle>GGEventImplD.mesa!12 (23162) SelectMatchingAreaColor GGEventImplD.SelectMatchingAreaColorNEWW should already compile. []<>candy>Bier.pa>Gargoyle>GGEventImplD.mesa!12 (23162) SelectMatchingLineColor GGEventImplD.SelectMatchingLineColorNEWW should already compile.. []<>candy>Bier.pa>Gargoyle>GGEventImplD.mesa!12 (28017) PrintAreaColor []<>candy>Bier.pa>Gargoyle>GGEventImplD.mesa!12 (29326) PrintLineColor []<>candy>Bier.pa>Gargoyle>GGEventImplD.mesa!12 (31336) AreaColorAux []<>candy>Bier.pa>Gargoyle>GGEventImplD.mesa!12 (32022) LineColorAux []<>candy>Bier.pa>Gargoyle>GGEventImplD.mesa!12 (40422) DescribeCaretObject []<>candy>Bier.pa>Gargoyle>GGFileOutImpl.mesa!7 (3638) FileoutEntity goes away. []<>candy>Bier.pa>Gargoyle>GGFileOutImpl.mesa!7 () FileoutSlice FileoutSliceNEWW OK when assumptions are OK. []<>candy>bier.pa>Gargoyle>GGMouseEventImplA.mesa!34 (4249) SortNewEntities []<>candy>bier.pa>Gargoyle>GGMouseEventImplA.mesa!34 (4418) SortNewEntities []<>candy>bier.pa>Gargoyle>GGMouseEventImplA.mesa!34 (17887) SitOnFeature []<>candy>bier.pa>Gargoyle>GGMouseEventImplA.mesa!34 (21148) UpdateSceneForCopy []<>candy>bier.pa>Gargoyle>GGMouseEventImplA.mesa!34 (22751) TransformObjectsAfterMove []<>candy>bier.pa>Gargoyle>GGMouseEventImplA.mesa!34 (30917) SafelyGetCaretTraj GGMouseEventImplA.SafelyGetCaretTrajNEWW OK when assumptions are OK.. []<>candy>bier.pa>Gargoyle>GGMouseEventImplB.mesa!26 (8206) SelectAndDescribeTrajPart []<>candy>bier.pa>Gargoyle>GGRefreshImpl.mesa!17 (7504) RefreshOverlay []<>candy>bier.pa>Gargoyle>GGRefreshImpl.mesa!17 (10210) DrawAttractorFeedback []<>candy>bier.pa>Gargoyle>GGRefreshImpl.mesa!17 (18040) BackmostSelectedSlice []<>candy>bier.pa>Gargoyle>GGRefreshImpl.mesa!17 (19722) DrawObjects []<>candy>bier.pa>Gargoyle>GGRefreshImpl.mesa!17 (20954) DrawObjectsFiltered []<>candy>bier.pa>Gargoyle>GGRefreshImpl.mesa!17 (23569) PaintTightBoxes []<>candy>bier.pa>Gargoyle>GGRefreshImpl.mesa!17 (31026) SnapshotBackground []<>candy>bier.pa>Gargoyle>GGRefreshImpl.mesa!17 (31963) MoveToOverlay []<>candy>bier.pa>Gargoyle>GGRefreshImpl.mesa!17 (32747) MoveToBackground []<>candy>bier.pa>Gargoyle>GGRefreshImpl.mesa!17 (33169) MoveOverlayToBackground []<>candy>bier.pa>Gargoyle>GGRefreshImpl.mesa!17 (33752) OnOverlay []<>candy>bier.pa>Gargoyle>GGRefreshImpl.mesa!17 (33793) OnOverlay []<>candy>bier.pa>Gargoyle>GGRefreshImpl.mesa!17 (34206) OrderOverlayList []<>candy>bier.pa>Gargoyle>GGRefreshImpl.mesa!17 (34997) OrderOverlayList []<>candy>Bier.pa>Gargoyle>GGSceneImpl.mesa!8 (4104) EntityPriority []<>candy>Bier.pa>Gargoyle>GGSceneImpl.mesa!8 (4444) UpdatePriorities []<>candy>Bier.pa>Gargoyle>GGSceneImpl.mesa!8 (11417) UpOne []<>candy>Bier.pa>Gargoyle>GGSceneImpl.mesa!8 (12615) DownOne []<>candy>Bier.pa>Gargoyle>GGSceneImpl.mesa!8 (13558) []<>candy>Bier.pa>Gargoyle>GGSceneImpl.mesa!8 (15694) ListBoxesInScene []<>candy>Bier.pa>Gargoyle>GGSceneImpl.mesa!8 (16181) ListTightBoxesInScene []<>candy>Bier.pa>Gargoyle>GGSceneImpl.mesa!8 (17528) ListTrajsInScene ListTrajsInSceneNEWW OK after assumptions. []<>candy>Bier.pa>Gargoyle>GGSceneImpl.mesa!8 (17961) ListOutlinesInScene ListOutlinesInSceneNEWW OK after assumptions. []<>candy>Bier.pa>Gargoyle>GGSceneImpl.mesa!8 (18303) ListSlicesInScene ListSlicesInSceneNEWW OK after assumptions. []<>candy>bier.pa>Gargoyle>GGSelectImpl.mesa!7 (3429) SelectAll []<>candy>bier.pa>Gargoyle>GGSelectImpl.mesa!7 (6711) DeselectAll []<>candy>bier.pa>Gargoyle>GGSelectImpl.mesa!7 (7340) DeselectEntity []<>candy>bier.pa>Gargoyle>GGSelectImpl.mesa!7 (7404) DeselectEntity []<>candy>bier.pa>Gargoyle>GGSelectImpl.mesa!7 (13777) IsSelectedInFull IsSelectedInFullNEWW OK after assumptions (needs isComplete class proc) []<>candy>bier.pa>Gargoyle>GGSelectImpl.mesa!7 (14629) IsSelectedInPart []<>candy>bier.pa>Gargoyle>GGSelectImpl.mesa!7 (21042) SelectedOutlineSequences SelectedOutlineSequencesNEWW needs GGSelect.OutlineSequenceObj redefined. QFind -c "$Outline" GG*.mesa!H 14 matches with QFind. 9 more cases to worry about. 21 found so far. []<>mouse>bier.pa>Gargoyle>GGCaretImpl.mesa!6 (2788) SittingOnEnd []<>mouse>Bier.pa>Gargoyle>GGEventImplA.mesa!15 (51908) Close NEWW will work when assumptions are OK. []<>mouse>bier.pa>Gargoyle>GGEventImplC.mesa!10 (20889) AddControlPoint NEWW will work when attractor is a SliceDescriptor []<>mouse>bier.pa>Gargoyle>GGEventImplC.mesa!10 (25200) AddJoint NEWW will work when attractor is a SliceDescriptor []<>mouse>Bier.pa>Gargoyle>GGFileInImpl.mesa!6 (5839) FileinEntity Unify with GGFileInImpl.FileInSlice. Careful of version management. []<>mouse>bier.pa>Gargoyle>GGMouseEventImplB.mesa!26 (7263) EndSelectAux EndSelectAuxNEWW should work using SitTheCaretNEWW []<>mouse>bier.pa>Gargoyle>GGMouseEventImplB.mesa!26 (9649) SitTheCaret SitTheCaretNEWW should be checked for correctness []<>mouse>Bier.pa>Gargoyle>GGOutlineImplA.mesa!21 (4213) MakeOutlineClass Update as needed []<>mouse>bier.pa>Gargoyle>GGSelectImpl.mesa!7 (8082) DeselectEntireSlice NEWW version should work after assumptions []<>mouse>bier.pa>Gargoyle>GGSelectImpl.mesa!7 (13817) IsSelectedInFull []<>mouse>Bier.pa>Gargoyle>GGSliceImplA.mesa!12 (76656) UpdateDescriptorBoundBoxes This proc should go away when GGSlice.UpdateDescriptorBoundBoxes handles all types []<>mouse>Bier.pa>Gargoyle>GGSliceImplA.mesa!12 (77438) SegmentsInDescriptor NEWW version should compile now; will work when assumptions are OK []<>mouse>Bier.pa>Gargoyle>GGSliceImplA.mesa!12 (77858) WalkSegments NEWW version should compile now; will work when assumptions are OK ASSUMPTIONS: caret.chair becomes SliceDescriptor - GGInterfaceTypes caret.attractor becomes SliceDescriptor - GGInterfaceTypes GGSelect.SelectedStuff returns SliceDescriptorGenerator - is this different from GGSelect.SelectedSlices ?? GGScene.TopLevelEntitiesInScene returns SliceGenerator - is this different from TopLevelSlicesInScene ?? GGSelect.IsSelectedInFull takes Slice - GGSelectImpl Implement WalkSegments for Outline class - GGOutlineImplA. class fileout procs do everything except class name - GGFileOutImpl Check GGMouseEventImplB.EndSelectAuxNEW and SitTheCaretNEW for correctness. Check GGSelectImpl and collapse slice/outline specific procs as needed. Get rid of all the List.Mubles for LIST OF SliceDescriptor; use GGUtility instead. implement IsEmpty, IsComplete for all slices. GGSliceImpl* RENAME class proc emptyParts to IsEmpty - GGModelTypes. create new class proc IsComplete - GGModelTypes. write GGOutline.TrajectoriesOfOutline to return LIST OF Traj - GGOutlineImplB. scene.entities RETURNS LIST OF Slice - GGSceneType. GGOutline.SaveSelectionsInOutline, GGOutline.RemakeSelectionsFromOutline take slices. GGOutlineImplB. GGCaret.GetAttractor RETURNS SliceDescriptor. GGCaretImpl. ggData.drag.outlineToExtend goes away. GGInterfaceTypes GGOutline.UpdateDescriptorBoundBoxes replaced by new version of in GGSliceImplA.UpdateDescriptorBoundBoxes. GGOutlineImplB. Implement segmentsInDescriptor, nextSegment, walkSegments for outline types GGOutlineImplA. GGSelect.OutlineSequenceObj should contain slices. GGSelect. everything in GGOutline that used to take outlines take slices. GGOutline. Global Type Substitutions OutlineDescriptor SliceDescriptor OutlineDescriptorObj SliceDescriptorObj Outline Slice OutlineObj SliceObj OutlineClass SliceClass OutlineClassObj SliceClassObj EntityGenerator SliceGenerator EntityGeneratorObj SliceGeneratorObj OutlineGenerator SliceGenerator OutlineGeneratorObj SliceGeneratorObj OutlineDescriptorGenerator SliceDescriptorGenerator OutlineDescriptorGeneratorObj SliceDescriptorGeneratorObj OutlinePointGenerator PointGenerator OutlinePointGeneratorObj PointGeneratorObj OutlinePointPairGenerator PointPairGenerator OutlinePointPairGeneratorObj PointPairGeneratorObj Obsolete Code GGAlignImpl.mesa GGBoundBoxImpl.mesa GGBuiltinShapesImpl.mesa GGCaretImpl.mesa GGCircleCacheImpl.mesa GGCirclesImpl.mesa GGContainerImpl.mesa GGCubic2Impl.mesa GGDescribeImpl.mesa GGEditToolImpl.mesa GGEventImplA.mesa GGEventImplB.mesa GGEventImplC.mesa GGEventImplD.mesa GGFileInImpl.mesa GGFileOutImpl.mesa GGFontImpl.mesa GGFromImagerImpl.mesa GGGravityImpl.mesa GGInterfaceImpl.mesa GGMeasureImpl.mesa GGMenusImpl.mesa GGMouseEventImplA.mesa GGMouseEventImplB.mesa GGMultiGravityImpl.mesa GGOutlineImplA.mesa GGOutlineImplB.mesa GGParseInImpl.mesa GGParseOutImpl.mesa GGRefreshImpl.mesa GGSceneImpl.mesa GGSegmentImplA.mesa GGSegmentImplB.mesa GGSelectImpl.mesa GGSequenceImpl.mesa GGSessionLogImpl.mesa GGShapesImpl.mesa GGSliceImplA.mesa GGSliceImplB.mesa GGSliceImplC.mesa GGStateImpl.mesa GGTrajImpl.mesa GGTransformImpl.mesa GGUserInputImpl.mesa GGUserProfileImpl.mesa GGUtilityImpl.mesa GGViewerOpsImpl.mesa GGWindowImpl.mesa tAddAllHotOutlines: PROC [scene: Scene, triggerBag: TriggerBag] = { feature: FeatureData; outDGen: GGModelTypes.SliceDescriptorGenerator; outDGen _ GGSelect.SelectedOutlines[scene, hot]; FOR outlineD: SliceDescriptor _ GGSelect.NextSliceDescriptor[outDGen], GGSelect.NextSliceDescriptor[outDGen] UNTIL outlineD = NIL DO feature _ GGGravity.FeatureFromOutline[outlineD.slice, outlineD.parts]; AddFeature[feature, triggerBag]; ENDLOOP; }; RemoveMovingOutline: PUBLIC PROC [outlineD: SliceDescriptor, scene: Scene] RETURNS [stationary: SliceDescriptor] = { selSliceD: SliceDescriptor _ GGSelect.FindSelectedSlice[outlineD.slice, scene, normal]; background, overlay, rubber, drag, move: SliceDescriptor; IF selSliceD = NIL THEN RETURN[outlineD]; -- clearly nothing is moving [background, overlay, rubber, drag] _ outlineD.slice.class.movingParts[selSliceD.slice, selSliceD.parts]; move _ outlineD.slice.class.unionParts[rubber, drag]; stationary _ outlineD.slice.class.differenceParts[outlineD, move]; }; AddHotOutline: PUBLIC PROC [outlineD: SliceDescriptor, triggerBag: TriggerBag] RETURNS [feature: FeatureData] = { oldD, unionD: SliceDescriptor; oldD _ FindOldOutlineD[outlineD.slice, triggerBag.outlines]; IF oldD = NIL THEN { feature _ GGGravity.FeatureFromOutline[outlineD.slice, outlineD.parts]; triggerBag.outlines _ AppendFeature[feature, triggerBag.outlines]; } ELSE { unionD _ outlineD.slice.class.unionParts[oldD, outlineD]; triggerBag.outlines _ DeleteOutlineD[oldD, triggerBag.outlines]; feature _ GGGravity.FeatureFromOutline[outlineD.slice, unionD.parts]; triggerBag.outlines _ AppendFeature[feature, triggerBag.outlines]; }; }; IncrementalFilterOutline: PUBLIC PROC [outlineD: SliceDescriptor, filters: Filters, hideAlignments: BOOL, alignBag: AlignBag] RETURNS [alignObjects: LIST OF FeatureData] = { pointGen: GGModelTypes.PointGenerator; pointPairGen: GGModelTypes.PointPairGenerator; pointGen _ outlineD.slice.class.pointsInDescriptor[outlineD]; FOR next: GGModelTypes.PointAndDone _ outlineD.slice.class.nextPoint[pointGen], outlineD.slice.class.nextPoint[pointGen] UNTIL next.done DO alignObjects _ NARROW[GList.Nconc[PointFireRule[next.point, filters, alignBag], alignObjects]]; ENDLOOP; pointPairGen _ outlineD.slice.class.pointPairsInDescriptor[outlineD]; FOR next: GGModelTypes.PointPairAndDone _ outlineD.slice.class.nextPointPair[pointPairGen], outlineD.slice.class.nextPointPair[pointPairGen] UNTIL next.done DO alignObjects _ NARROW[GList.Nconc[SegmentFireRule[9999, next.lo, next.hi, filters, alignBag], alignObjects]]; ENDLOOP; }; IncrementalMidpointsOutline: PUBLIC PROC [outlineD: SliceDescriptor, midpoints: BOOL, alignBag: AlignBag] = { THIS CODE IS NO LONGER USED EXCEPT FOR PERFORMANCE BENCHMARKS; GGState.PrecomputeMidpoints[] is FALSE by default. Add to the object bag the midpoints of all segments in outlineD. outPointPairGen: GGModelTypes.PointPairGenerator; pairCount: NAT _ 0; IF NOT midpoints THEN RETURN; IF NOT GGState.PrecomputeMidpoints[] THEN RETURN; outPointPairGen _ outlineD.slice.class.pointPairsInDescriptor[outlineD]; FOR next: GGModelTypes.PointPairAndDone _ outlineD.slice.class.nextPointPair[outPointPairGen], outlineD.slice.class.nextPointPair[outPointPairGen] UNTIL next.done DO [] _ GGGravity.SegmentAddMidpoint[pairCount, next.lo, next.hi, alignBag]; pairCount _ pairCount + 1; ENDLOOP; }; RemoveHotOutline: PUBLIC PROC [outlineD: SliceDescriptor, triggerBag: TriggerBag] = { oldOut, diff: SliceDescriptor; feature: FeatureData; oldOut _ FindOldOutlineD[outlineD.slice, triggerBag.outlines]; IF oldOut#NIL THEN { diff _ outlineD.slice.class.differenceParts[oldOut, outlineD]; triggerBag.outlines _ DeleteOutlineD[oldOut, triggerBag.outlines]; IF NOT outlineD.slice.class.isEmptyParts[diff] THEN { feature _ GGGravity.FeatureFromOutline[outlineD.slice, diff.parts]; triggerBag.outlines _ AppendFeature[feature, triggerBag.outlines]; }; }; }; RemoveEntireHotOutline: PUBLIC PROC [outline: Slice, triggerBag: TriggerBag] RETURNS [oldD: SliceDescriptor] = { oldD _ FindOldOutlineD[outline, triggerBag.outlines]; IF oldD#NIL THEN { triggerBag.outlines _ DeleteOutlineD[oldD, triggerBag.outlines]; }; }; RemoveMentionOutline: PUBLIC PROC [outline: Slice, alignBag: AlignBag] = { Removes all alignment objects and midpoints that were triggered (only) by this outline. Removes mention of this outline from those alignment objects that are trigger by other triggers as well. line: AlignmentLine; FOR list: LIST OF FeatureData _ alignBag.slopeLines, list.rest UNTIL list = NIL DO line _ NARROW[list.first.shape]; ENDLOOP; }; RemoveMentionSlice: PUBLIC PROC [slice: Slice, alignBag: AlignBag] = { Removes all alignment objects and midpoints that were triggered (only) by this slice. Removes mention of this slice from those alignment objects that are trigger by other triggers as well. }; AddAllTrajectories: PROC [scene: Scene, triggerBag: TriggerBag] = { outlineGen: GGModelTypes.SliceGenerator; feature: FeatureData; outlineGen _ GGScene.OutlinesInScene[scene]; FOR outline: Slice _ GGScene.NextOutline[outlineGen], GGScene.NextOutline[outlineGen] UNTIL outline = NIL DO feature _ GGGravity.FeatureFromOutline[outline]; AddFeature[feature, triggerBag]; ENDLOOP; }; TAddTriggersFilter: PUBLIC PROC [triggerBag: TriggerBag, filterSeqProc: FilterSequenceProc, filterSliceProc: FilterSliceProc, ggData: GGData] = { When this procedure is called, all sequences in the scene are passed to filterSeqProc to see if they should be added (in all or in part). filterSeqProc should return those parts which should be added. AddSequenceTrigger adds these parts to triggerBag. A similar things happens for slices using the filterSliceProc and calls to AddSliceTrigger add: BOOL; seq: Sequence; sliceGen: SliceGenerator; trajGen: TrajGenerator _ GGScene.TrajsInScene[ggData.scene]; FOR traj: Traj _ GGScene.NextTraj[trajGen], GGScene.NextTraj[trajGen] UNTIL traj = NIL DO seq _ GGSequence.CreateComplete[traj]; filterSeqProc[seq]; -- keeps those parts of seq which should remain AddSequenceTrigger[seq, triggerBag]; ENDLOOP; sliceGen _ GGScene.SlicesInScene[ggData.scene]; FOR slice: Slice _ GGScene.NextSlice[sliceGen], GGScene.NextSlice[sliceGen] UNTIL slice = NIL DO add _ filterSliceProc[slice]; IF add THEN AddSliceTrigger[slice, triggerBag]; ENDLOOP; }; FindOldOutlineD: PROC [outline: 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 = outline THEN RETURN [NARROW[l.first.shape]]; ENDLOOP; RETURN [NIL]; }; FindOutlineDAndNeighbors: 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; }; FindSliceDAndNeighbors: 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; }; DeleteOutline: PROC [outline: Slice, featureList: LIST OF FeatureData] RETURNS [smallerList: LIST OF FeatureData, notFound: BOOL _ FALSE] = { before, at, after: LIST OF FeatureData; IF featureList = NIL THEN RETURN[NIL, TRUE]; [before, at, after] _ FindOutlineAndNeighbors[outline, featureList ! EntityNotFound => {notFound _ TRUE; CONTINUE}]; IF notFound THEN RETURN[featureList, TRUE]; IF before = NIL THEN smallerList _ after ELSE { before.rest _ after; smallerList _ featureList; }; }; DeleteOutlineD: PROC [outlineD: 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] _ FindOutlineAndNeighbors[outlineD.slice, featureList ! EntityNotFound => {notFound _ TRUE; CONTINUE}]; IF notFound THEN RETURN[featureList]; IF before = NIL THEN smallerList _ after ELSE { before.rest _ after; smallerList _ featureList; }; }; ReplaceObsoleteOutlineTrigger: PUBLIC PROC [ggData: GGData, oldOutline: Slice, newOutline: Slice] = { triggerBag: TriggerBag _ ggData.hitTest.triggerBag; alignBag: AlignBag _ ggData.hitTest.alignBag; sceneBag: TriggerBag _ ggData.hitTest.sceneBag; feature: FeatureData; hotD: SliceDescriptor; notFound: BOOL; First, get rid of all references to the obsolete outline. notFound _ FALSE; UNTIL notFound DO [sceneBag.outlines, notFound] _ DeleteOutline[oldOutline, sceneBag.outlines]; ENDLOOP; notFound _ FALSE; UNTIL notFound DO [triggerBag.outlines, notFound] _ DeleteOutline[oldOutline, triggerBag.outlines]; ENDLOOP; Next, add back any appropriate references to the new outline. Assume that the next operation will be a CaretPos. If this traj is hot, add its hot parts to the triggerBag. hotD _ GGSelect.FindSelectedOutline[newOutline, ggData.scene, hot]; IF hotD # NIL THEN { feature _ GGGravity.FeatureFromOutline[hotD.slice, hotD.parts]; AddFeature[feature, triggerBag]; }; Add the whole object to the scene bag. feature _ GGGravity.FeatureFromOutline[newOutline]; AddFeature[feature, sceneBag]; }; ComputeAllBoundingBoxes: PROC [sceneBag: TriggerBag] = { featureData: FeatureData; outlineD: SliceDescriptor; FOR list: LIST OF FeatureData _ sceneBag.outlines, list.rest UNTIL list = NIL DO featureData _ list.first; outlineD _ NARROW[featureData.shape]; GGSlice.UpdateDescriptorBoundBoxes[outlineD]; ENDLOOP; }; BoxEdge: PRIVATE PROC [bBox: BoundBox, index: NAT] RETURNS [edge: Edge] = { IF bBox.null OR bBox.infinite THEN ERROR; SELECT index FROM 0 => edge _ Lines2d.CreateEdge[[bBox.loX, bBox.loY], [bBox.loX, bBox.hiY]]; 1 => edge _ Lines2d.CreateEdge[[bBox.loX, bBox.hiY], [bBox.hiX, bBox.hiY]]; 2 => edge _ Lines2d.CreateEdge[[bBox.hiX, bBox.hiY], [bBox.hiX, bBox.loY]]; 3 => edge _ Lines2d.CreateEdge[[bBox.hiX, bBox.loY], [bBox.loX, bBox.loY]]; ENDCASE => ERROR; }; Polygon: PUBLIC PROC [sideCount: NAT, origin: Point, sideLength: REAL, defaults: DefaultData] RETURNS [outline: Slice] = { The bottom-most edge of the returned polygon will be horizontal. The polygon will be inscribed inside a circle centered at "origin". Each side of the polygon will have length "sideLength". }; For use by GGRefreshImpl. TellOnOverlay: PUBLIC PROC [caret: Caret, onOverlay: BOOL] = { caret.onOverlay _ onOverlay; }; IsOnOverlay: PUBLIC PROC [caret: Caret] RETURNS [BOOL] = { RETURN[caret.onOverlay]; }; SittingOnEndOLDD: PUBLIC PROC [caret: Caret] RETURNS [BOOL] = { success: BOOL; partType: TrajPartType; jointNum: NAT; traj: Traj; IF caret.chair = NIL THEN RETURN[FALSE]; WITH caret.chair SELECT FROM outlineD: SliceDescriptor => { [success, partType, traj, ----, jointNum] _ GGOutline.UnpackSimpleDescriptorOld[outlineD]; IF NOT success OR partType # joint THEN RETURN[FALSE]; RETURN[GGTraj.IsEndJoint[traj, jointNum]]; }; sliceD: SliceDescriptor => { IF sliceD.slice.class.type # $Slice THEN RETURN[FALSE]; [success, partType, traj, ----, jointNum] _ GGOutline.UnpackSimpleDescriptor[sliceD]; IF NOT success OR partType # joint THEN RETURN[FALSE]; RETURN[GGTraj.IsEndJoint[traj, jointNum]]; }; ENDCASE => ERROR; }; Touching. MakeJointTouchJoint: PROC [traj1, traj2: Traj, joint1, joint2: Joint, point: Point, ggData: GGData] = { touchGroup, group1, group2: TouchGroup; IF joint1.touchItem # NIL AND joint2.touchItem = NIL THEN { joint1 already belongs to a group. Add joint2 to this group. touchGroup _ GGTouch.TouchGroupOfItem[joint1.touchItem]; joint2.touchItem _ GGTouch.AddJoint[traj2, joint2, touchGroup]; } ELSE IF joint1.touchItem = NIL AND joint2.touchItem # NIL THEN { touchGroup _ GGTouch.TouchGroupOfItem[joint2.touchItem]; joint1.touchItem _ GGTouch.AddJoint[traj1, joint1, touchGroup]; } ELSE IF joint1.touchItem # NIL AND joint2.touchItem # NIL THEN { Merge the two groups. group1 _ GGTouch.TouchGroupOfItem[joint1.touchItem]; group2 _ GGTouch.TouchGroupOfItem[joint2.touchItem]; GGTouch.MergeGroups[group1, group2, ggData]; } ELSE { touchGroup _ GGTouch.CreateTouchGroup[ggData, point]; joint1.touchItem _ GGTouch.AddJoint[traj1, joint1, touchGroup]; joint2.touchItem _ GGTouch.AddJoint[traj2, joint2, touchGroup]; }; }; RatherClose: PROC [p1, p2: Point] RETURNS [BOOL] = { epsilon: REAL = 1.0e-5; RETURN[ABS[p1.x - p2.x] < epsilon OR ABS[p1.y - p2.y] < epsilon]; }; FindItemAtPoint: PROC [point: Point, touchItemList: LIST OF TouchItem] RETURNS [TouchItem] = { FOR list: LIST OF TouchItem _ touchItemList, list.rest UNTIL list = NIL DO IF RatherClose[list.first.segPoint, point] THEN RETURN[list.first] ENDLOOP; RETURN[NIL]; }; MakeJointTouchSegment: PROC [traj1, traj2: Traj, joint: Joint, seg: Segment, point: Point, ggData: GGData] = { samePointItem: TouchItem; touchGroup, group1, group2: TouchGroup; samePointItem _ FindItemAtPoint[point, seg.touchItemList]; IF joint.touchItem # NIL AND samePointItem = NIL THEN { touchGroup _ GGTouch.TouchGroupOfItem[joint.touchItem]; seg.touchItemList _ CONS[GGTouch.AddSegment[traj2, seg, point, touchGroup], seg.touchItemList]; } ELSE IF joint.touchItem = NIL AND samePointItem # NIL THEN { touchGroup _ GGTouch.TouchGroupOfItem[samePointItem]; joint.touchItem _ GGTouch.AddJoint[traj1, joint, touchGroup]; } ELSE IF joint.touchItem # NIL AND samePointItem # NIL THEN { group1 _ GGTouch.TouchGroupOfItem[joint.touchItem]; group2 _ GGTouch.TouchGroupOfItem[samePointItem]; GGTouch.MergeGroups[group1, group2, ggData]; } ELSE { touchGroup _ GGTouch.CreateTouchGroup[ggData, point]; joint.touchItem _ GGTouch.AddJoint[traj1, joint, touchGroup]; seg.touchItemList _ CONS[GGTouch.AddSegment[traj2, seg, point, touchGroup], seg.touchItemList]; }; }; MakeSegmentTouchSegment: PROC [chair, attractor: Traj, chairSeg, attractorSeg: Segment, point: Point, ggData: GGData] = { Not yet implemented. }; MakeChairTouchAttractor: PUBLIC PROC [caret: Caret, ggData: GGData] = { }; MakeChairTouchTrajJoint: PUBLIC PROC [caret: Caret, ggData: GGData, traj: Traj, jointNum: NAT] = { }; DescribeItem: PROC [f: IO.STREAM, item: TouchItem] = { SELECT item.touchingPartType FROM joint => f.PutF["Item: joint on %g", [rope[DescribeTraj[NARROW[item.traj]]]]]; segment => f.PutF["Item: segment on %g", [rope[DescribeTraj[NARROW[item.traj]]]]]; ENDCASE => ERROR; }; DescribeTouchGroup: PUBLIC PROC [group: TouchGroup] RETURNS [text: Rope.ROPE] = { f: IO.STREAM; touchGen: TouchItemGenerator; f _ IO.ROS[]; f.PutF["TouchGroup: (%1.2f, %1.2f)\n", [real[group.point.x]], [real[group.point.y]]]; touchGen _ GGTouch.AllTouchItems[group]; FOR item: TouchItem _ GGTouch.NextTouchItem[touchGen], GGTouch.NextTouchItem[touchGen] UNTIL item = NIL DO f.PutChar[IO.TAB]; DescribeItem[f, item]; f.PutChar[IO.CR]; ENDLOOP; text _ IO.RopeFromROS[f]; }; ShowFontValues: PUBLIC PROC [clientData: REF ANY, event: LIST OF REF ANY] = { Outputs string in the form transformation preferredSize ggData: GGData _ NARROW[clientData]; sliceDescGen: SliceDescriptorGenerator _ GGSelect.SelectedSlices[ggData.scene, normal]; sliceDesc: SliceDescriptor _ GGSelect.NextSliceDescriptor[sliceDescGen]; IF sliceDesc=NIL OR sliceDesc.slice.class.type#$Text OR GGSelect.NextSliceDescriptor[sliceDescGen]#NIL THEN { Feedback.AppendHerald[ggData.feedback, "Select a single text slice for font printing", oneLiner]; Feedback.Blink[ggData.feedback]; } ELSE Feedback.PutF[ggData.feedback, oneLiner, "Font Values: %g", [rope[GGSlice.GetFontDataRope[sliceDesc.slice]]] ]; }; ShowFontValuesLiteral: PUBLIC PROC [clientData: REF ANY, event: LIST OF REF ANY] = { Outputs string in the form ggData: GGData _ NARROW[clientData]; sliceDescGen: SliceDescriptorGenerator _ GGSelect.SelectedSlices[ggData.scene, normal]; sliceDesc: SliceDescriptor _ GGSelect.NextSliceDescriptor[sliceDescGen]; IF sliceDesc=NIL OR sliceDesc.slice.class.type#$Text OR GGSelect.NextSliceDescriptor[sliceDescGen]#NIL THEN { Feedback.AppendHerald[ggData.feedback, "Select a single text slice for font printing", oneLiner]; Feedback.Blink[ggData.feedback]; } ELSE Feedback.PutF[ggData.feedback, oneLiner, "Font Values: %g", [rope[GGSlice.GetFontLiteralDataRope[sliceDesc.slice]]] ]; }; OldDeleteAllSelected: PROC [ggData: GGData] RETURNS [bBox: BoundBox] = { sliceDescGen: SliceDescriptorGenerator; outSeqGen: GGSelect.OutlineSequenceGenerator; oldOutline: Slice; fenceSeq: Sequence; thisBox: BoundBox; bBox _ GGBoundBox.BoundBoxOfSelected[ggData.scene, normal]; Implemented enough for non-gargoyle slices only. sliceDescGen _ GGSelect.SelectedSlices[ggData.scene, normal]; FOR sliceD: SliceDescriptor _ GGSelect.NextSliceDescriptor[sliceDescGen], GGSelect.NextSliceDescriptor[sliceDescGen] UNTIL sliceD = NIL DO GGSelect.DeselectEntityAllClasses[sliceD.slice, ggData.scene]; GGSlice.DeleteSlice[ggData.scene, sliceD.slice]; ENDLOOP; Now delete selected sequences. outSeqGen _ GGSelect.SelectedOutlineSequences[ggData.scene, normal]; WHILE outSeqGen.list # NIL DO FOR outSeq: GGSelect.OutlineSequence _ GGSelect.NextOutlineSequences[outSeqGen], GGSelect.NextOutlineSequences[outSeqGen] UNTIL outSeq = NIL DO fenceSeq _ outSeq.fenceSeq; FOR holeSeq: Sequence _ GGSequence.NextSequence[outSeq.holeSeqs], GGSequence.NextSequence[outSeq.holeSeqs] UNTIL holeSeq = NIL DO [oldOutline,----] _ GGInterface.DeleteSequence[holeSeq, ggData.scene]; thisBox _ GGTraj.GetBoundBox[holeSeq.traj]; GGBoundBox.EnlargeByBox[bBox: bBox, by: thisBox]; GOTO SelectionsHaveChanged; ENDLOOP; IF fenceSeq # NIL THEN { [oldOutline,----] _ GGInterface.DeleteSequence[fenceSeq, ggData.scene]; IF fenceSeq.traj.role = open THEN { GGSequence.UpdateBoundBox[fenceSeq]; GGBoundBox.EnlargeByBox[bBox: bBox, by: fenceSeq.boundBox]; } ELSE { thisBox _ GGTraj.GetBoundBox[fenceSeq.traj]; GGBoundBox.EnlargeByBox[bBox: bBox, by: thisBox]; }; GOTO SelectionsHaveChanged; }; REPEAT SelectionsHaveChanged => { outSeqGen _ GGSelect.SelectedOutlineSequences[ggData.scene, normal]; }; ENDLOOP; ENDLOOP; }; DeleteAllSelected: PROC [ggData: GGData] RETURNS [bBox: BoundBox] = { DeleteRun: GGSelect.RunProc = { traj _ NIL; }; sliceDescGen: SliceDescriptorGenerator; thisBox: BoundBox; bBox _ GGBoundBox.BoundBoxOfSelected[ggData.scene, normal]; Implemented enough for non-gargoyle slices only. sliceDescGen _ GGSelect.SelectedSlices[ggData.scene, normal]; FOR sliceD: SliceDescriptor _ GGSelect.NextSliceDescriptor[sliceDescGen], GGSelect.NextSliceDescriptor[sliceDescGen] UNTIL sliceD = NIL DO GGSelect.DeselectEntityAllClasses[sliceD.slice, ggData.scene]; GGSlice.DeleteSlice[ggData.scene, sliceD.slice]; ENDLOOP; GGCaret.NoAttractor[ggData.caret]; Overly conservative. Just in case the caret was attracted to something that was just deleted. thisBox _ GGSelect.ForEachOutlineRun[ggData.scene, ggData.caret, normal, DeleteRun, FALSE]; GGBoundBox.EnlargeByBox[bBox: bBox, by: thisBox]; }; CloseOLDD: PUBLIC PROC [clientData: REF ANY, event: LIST OF REF ANY] = { ggData: GGData _ NARROW[clientData]; chair: REF ANY; traj: Traj; outline: Slice; firstPoint, lastPoint: Point; seg: Segment; success: BOOL; chair _ GGCaret.GetChair[ggData.caret]; BEGIN IF chair = NIL THEN GOTO NoCaretTraj; WITH chair SELECT FROM outlineD: SliceDescriptor => { [success, ----, traj] _ GGOutline.UnpackSimpleDescriptorOld[outlineD]; IF NOT success THEN ERROR; }; sliceD: SliceDescriptor => { IF sliceD.slice.class.type # $Slice THEN GOTO NoCaretTraj; [success, ----, traj] _ GGOutline.UnpackSimpleDescriptor[sliceD]; IF NOT success THEN GOTO NoCaretTraj; }; ENDCASE => ERROR; IF traj.role = fence OR traj.role = hole THEN GOTO AlreadyClosed; Feedback.AppendHerald[ggData.feedback, "The caret trajectory will be closed.", oneLiner]; outline _ GGOutline.OutlineOfTraj[traj]; firstPoint _ GGTraj.FetchJointPos[traj, 0]; lastPoint _ GGTraj.LastJointPos[traj]; IF firstPoint # lastPoint THEN { lastSeg: Segment _ GGTraj.FetchSegment[traj, GGTraj.HiSegment[traj]]; seg _ GGSegment.MakeLine[lastPoint, firstPoint, NIL]; GGSegment.CopyLooks[lastSeg, seg]; GGTraj.CloseWithSegment[traj, seg, lo]; [] _ GGSelect.ReselectTraj[traj, hi, ggData.scene, TRUE]; } ELSE { GGOutline.SaveSelectionsInOutline[outline, ggData.scene]; GGSelect.DeselectEntityAllClasses[outline, ggData.scene]; GGTraj.CloseByDistorting[traj, hi]; GGOutline.RemakeSelectionsFromOutline[outline, ggData.scene]; }; GGSelect.SelectTraj[traj, ggData.scene, normal]; GGCaret.SitOn[ggData.caret, NIL]; GGCaret.NoAttractor[caret: ggData.caret]; outline.class.setFillColor[outline, ggData.defaults.fillColor]; ggData.refresh.startBoundBox^ _ traj.boundBox^; GGWindow.RestoreScreenAndInvariants[paintAction: $ObjectChangedBoundBoxProvided, ggData: ggData, remake: triggerBag, backgndOK: FALSE, edited: TRUE, okToClearFeedback: FALSE]; N.B. It's a shame we have to remake the triggerBag here. This is because the closed trajectory might have been hot. Its hot sequence is obsolete. EXITS NoCaretTraj => { Feedback.AppendHerald[ggData.feedback, "There is no caret trajectory to close.", oneLiner]; Feedback.Blink[ggData.feedback]; }; AlreadyClosed => { Feedback.AppendHerald[ggData.feedback, "That trajectory is already closed.", oneLiner]; Feedback.Blink[ggData.feedback]; }; END; }; -- end Close ShowPoints: PUBLIC PROC [clientData: REF ANY, event: LIST OF REF ANY] = { ggData: GGData _ NARROW[clientData]; seqGen: SequenceGenerator _ GGSelect.SelectedSequences[ggData.scene, normal]; FOR seq: Sequence _ GGSequence.NextSequence[seqGen], GGSequence.NextSequence[seqGen] UNTIL seq = NIL DO seq.traj.visibleJoints _ TRUE; ENDLOOP; }; HidePoints: PUBLIC PROC [clientData: REF ANY, event: LIST OF REF ANY] = { ggData: GGData _ NARROW[clientData]; seqGen: SequenceGenerator _ GGSelect.SelectedSequences[ggData.scene, normal]; FOR seq: Sequence _ GGSequence.NextSequence[seqGen], GGSequence.NextSequence[seqGen] UNTIL seq = NIL DO seq.traj.visibleJoints _ FALSE; ENDLOOP; }; GetRadius: PUBLIC PROC [clientData: REF ANY, event: LIST OF REF ANY] = { ggData: GGData _ NARROW[clientData]; oldFoundButton: AtomButtons.ScalarButtonClient; seqGen: SequenceGenerator; segGen: SegmentGenerator; seq, next: Sequence; radius: REAL; seqGen _ GGSelect.SelectedSequences[ggData.scene, normal]; seq _ GGSequence.NextSequence[seqGen]; next _ GGSequence.NextSequence[seqGen]; IF seq = NIL OR next # NIL THEN { Feedback.Append[ggData.feedback, "Select a single segment for GetRadius.", oneLiner]; Feedback.Blink[ggData.feedback]; RETURN; }; segGen _ GGSequence.SegmentsInSequence[seq]; FOR seg: Segment _ GGSequence.NextSegment[segGen], GGSequence.NextSegment[segGen] UNTIL seg = NIL DO radius _ Vectors2d.Distance[seg.lo, seg.hi]/ggData.hitTest.scaleUnit; oldFoundButton _ AtomButtons.AddValueSorted[ggData, ggData.hitTest.radiusHeader, [NIL, radius, LIST[$ToggleRadius, NEW[REAL _ radius]], on], incr]; ENDLOOP; GGWindow.RestoreScreenAndInvariants[paintAction: $NewAlignmentsSelected, ggData: ggData, remake: objectBag, backgndOK: TRUE, edited: FALSE, okToClearFeedback: TRUE]; }; AddControlPointOLDD: PUBLIC PROC [clientData: REF ANY, event: LIST OF REF ANY] = { Adds a new control point to a segment ggData: GGData _ NARROW[clientData]; attractor: REF ANY; seg, newSeg: Segment; segNum: INT; traj, newRun, newTraj: Traj; refreshBox: BoundBox; success: BOOL; partType: TrajPartType; caretPos: Point _ GGCaret.GetPoint[ggData.caret]; attractor _ GGCaret.GetAttractor[ggData.caret]; BEGIN IF attractor = NIL THEN GOTO NotOnSpline; WITH attractor SELECT FROM oD: SliceDescriptor => { [success, partType, traj, ----, ----, ----, ----, seg, segNum] _ GGOutline.UnpackSimpleDescriptorOld[oD]; IF NOT success OR partType # segment THEN GOTO NotOnSpline; }; sD: SliceDescriptor => { IF sD.slice.class.type # $Slice THEN GOTO NotOnSpline; [success, partType, traj, ----, ----, ----, ----, seg, segNum] _ GGOutline.UnpackSimpleDescriptor[sD]; IF NOT success OR partType # segment THEN GOTO NotOnSpline; }; ENDCASE => ERROR; IF seg.class.type # $CubicSpline THEN GOTO NotOnSpline; Must save select data now so that segment copy (in CSControlPointAdd) will reflect selection data. GGSelect.DeselectAll[ggData.scene, normal]; GGTraj.SaveSelection[traj, normal, ggData.scene]; -- to clear field bits GGTraj.SaveSelection[traj, hot, ggData.scene]; -- to save hot field bits newSeg _ GGSegment.CSControlPointAdd[seg, caretPos]; newRun _ GGTraj.CreateTraj[newSeg.lo]; GGTraj.SetTrajStrokeJoint[newRun, traj.strokeJoint]; IF NOT GGTraj.AddSegment[newRun, hi, newSeg, lo] THEN ERROR; IF (segNum _ GGTraj.IndexOfSegment[seg, traj]) = -1 THEN ERROR; -- inconsistent [refreshBox, newTraj] _ GGSelect.SubstituteForSegment[traj, segNum, newRun, ggData.scene]; GGCaret.NoAttractor[ggData.caret]; GGCaret.SitOn[ggData.caret, NIL]; ggData.refresh.startBoundBox^ _ refreshBox^; GGWindow.RestoreScreenAndInvariants[paintAction: $ObjectChangedBoundBoxProvided, ggData: ggData, remake: triggerBag, backgndOK: FALSE, edited: TRUE, okToClearFeedback: TRUE]; EXITS NotOnSpline => { Feedback.Append[ggData.feedback, "Caret must lie on a cubic spline to add a control point", oneLiner]; Feedback.Blink[ggData.feedback]; }; END; }; AddJointOLDD: PUBLIC PROC [clientData: REF ANY, event: LIST OF REF ANY] = { ggData: GGData _ NARROW[clientData]; attractor: REF ANY; seg, newSeg1, newSeg2: Segment; segNum: INT; traj, newRun, newTraj: Traj; refreshBox, oldBox: BoundBox; newJoint: Joint; success: BOOL; partType: TrajPartType; caretPos: Point _ GGCaret.GetPoint[ggData.caret]; attractor _ GGCaret.GetAttractor[ggData.caret]; BEGIN IF attractor = NIL THEN GOTO NotASegment; WITH attractor SELECT FROM oD: SliceDescriptor => { [success, partType, traj, ----, ----, ----, ----, seg, segNum] _ GGOutline.UnpackSimpleDescriptorOld[oD]; IF NOT success OR partType # segment THEN GOTO NotASegment; }; sD: SliceDescriptor => { IF sD.slice.class.type # $Slice THEN GOTO NotASegment; [success, partType, traj, ----, ----, ----, ----, seg, segNum] _ GGOutline.UnpackSimpleDescriptor[sD]; IF NOT success OR partType # segment THEN GOTO NotASegment; }; ENDCASE => ERROR; IF seg.class.type=$Conic THEN GOTO ConicsAreNotDone; Save select data now so that segment copy (in CSControlPointAdd) will reflect selection data. GGSelect.DeselectAll[ggData.scene, normal]; GGTraj.SaveSelection[traj, normal, ggData.scene]; GGTraj.SaveSelection[traj, hot, ggData.scene]; [Artwork node; type 'ArtworkInterpress on' to command tool] [newSeg1, newSeg2] _ seg.class.addJoint[seg, caretPos]; newRun _ GGTraj.CreateTraj[newSeg1.lo]; IF NOT GGTraj.AddSegment[newRun, hi, newSeg1, lo] THEN ERROR; IF NOT GGTraj.AddSegment[newRun, hi, newSeg2, lo] THEN ERROR; newJoint _ GGTraj.FetchJoint[newRun, 1]; newJoint.TselectedInFull.normal _ TRUE; IF (segNum _ GGTraj.IndexOfSegment[seg, traj]) = -1 THEN ERROR; -- inconsistent oldBox _ seg.class.boundBox[seg]; [refreshBox, newTraj] _ GGSelect.SubstituteForSegment[traj, segNum, newRun, ggData.scene]; GGTraj.SetTrajStrokeJoint[newTraj, traj.strokeJoint]; GGBoundBox.EnlargeByBox[refreshBox, oldBox]; GGCaret.NoAttractor[ggData.caret]; GGCaret.SitOn[ggData.caret, NIL]; ggData.refresh.startBoundBox^ _ refreshBox^; GGWindow.RestoreScreenAndInvariants[paintAction: $ObjectChangedBoundBoxProvided, ggData: ggData, remake: triggerBag, backgndOK: FALSE, edited: TRUE, okToClearFeedback: TRUE]; EXITS NotASegment => { Feedback.Append[ggData.feedback, "Caret must lie on a segment to add a joint", oneLiner]; Feedback.Blink[ggData.feedback]; }; ConicsAreNotDone => { Feedback.Append[ggData.feedback, "Can't add joints to Conics", oneLiner]; Feedback.Blink[ggData.feedback]; }; END; }; AreaSelectNewAndDeleteOLDD: PUBLIC PROC [clientData: REF ANY, event: LIST OF REF ANY] = { ggData: GGData _ NARROW[clientData]; Select all objects within area(s) bounded by original selection(s) and delete original selection IF GGSelect.NoSelections[ggData.scene, normal] THEN RETURN ELSE { -- there were some original selections oldSelectedGen: SliceGenerator _ GGSelect.SelectedSlices[ggData.scene, normal]; -- save original selection startBox: BoundBox _ GGBoundBox.BoundBoxOfSelected[ggData.scene, normal]; AreaSelectAux[ggData: ggData, new: TRUE, paint: FALSE]; FOR formerSelected: REF ANY _ GGScene.NextEntity[oldSelectedGen], GGScene.NextEntity[oldSelectedGen] UNTIL formerSelected=NIL DO WITH formerSelected SELECT FROM outlineD: SliceDescriptor => { N.B.: DeleteOutline deletes too much GGSelect.DeselectEntityAllClasses[outlineD.slice, ggData.scene]; GGScene.DeleteOutline[ggData.scene, outlineD.slice]; }; sliceD: SliceDescriptor => { GGSelect.DeselectEntityAllClasses[sliceD.slice, ggData.scene]; GGSlice.DeleteSlice[ggData.scene, sliceD.slice]; }; ENDCASE => ERROR; ENDLOOP; GGCaret.NoAttractor[ggData.caret]; GGCaret.SitOn[ggData.caret, NIL]; ggData.refresh.startBoundBox^ _ startBox^; GGWindow.RestoreScreenAndInvariants[paintAction: $ObjectChangedBoundBoxProvided, ggData: ggData, remake: triggerBag, backgndOK: TRUE, edited: FALSE, okToClearFeedback: TRUE]; }; }; AreaSelectAuxOLDD: PROC [ggData: GGData, new: BOOL _ TRUE, paint: BOOL _ TRUE] = { Within: PROC [test, bound: GGBoundBox.BoundBox] RETURNS [BOOL] = { RETURN [ test.hiX <= bound.hiX AND test.loX >= bound.loX AND test.hiY <= bound.hiY AND test.loY >= bound.loY ]; }; selectedGen: SliceGenerator; sceneGen: SliceGenerator; IF GGSelect.NoSelections[ggData.scene, normal] THEN RETURN; selectedGen _ GGSelect.SelectedSlices[ggData.scene, normal]; IF new THEN GGSelect.DeselectAll[ggData.scene, normal]; -- get rid of old selection outer loop on each individual selected object FOR nextSelected: REF ANY _ GGScene.NextEntity[selectedGen], GGScene.NextEntity[selectedGen] UNTIL nextSelected=NIL DO sBox: BoundBox; currentEntity: REF ANY; WITH nextSelected SELECT FROM outlineD: SliceDescriptor => { sBox _ outlineD.slice.class.getBoundBox[outlineD.slice, outlineD.parts]; currentEntity _ outlineD.slice; }; sliceD: SliceDescriptor => { sBox _ sliceD.slice.class.getBoundBox[sliceD.slice, sliceD.parts]; currentEntity _ sliceD.slice; }; ENDCASE => ERROR; inner loop on each individual scene object sceneGen _ GGScene.TopLevelEntitiesInScene[ggData.scene]; FOR nextEntity: REF ANY _ GGScene.NextEntity[sceneGen], GGScene.NextEntity[sceneGen] UNTIL nextEntity=NIL DO IF nextEntity=currentEntity THEN LOOP; IF NOT GGSelect.IsSelectedInFull[nextEntity, ggData.scene, normal] THEN -- don't reprocess WITH nextEntity SELECT FROM outline: Slice => { IF Within[outline.class.getBoundBox[outline, NIL], sBox] THEN { GGSelect.SelectEntireSlice[outline, ggData.scene, normal]; }; }; slice: Slice => { IF Within[slice.class.getBoundBox[slice, NIL], sBox] THEN { GGSelect.SelectSlice[slice.class.newParts[slice, NIL, topLevel], ggData.scene, normal ]; }; }; ENDCASE => ERROR; ENDLOOP; ENDLOOP; IF paint THEN GGWindow.RestoreScreenAndInvariants[paintAction: $SelectionChanged, ggData: ggData, remake: none, backgndOK: TRUE, edited: FALSE, okToClearFeedback: TRUE]; }; -- end AreaSelectAux SelectMatchingAreaColor: PUBLIC PROC [clientData: REF ANY, event: LIST OF REF ANY] = { ggData: GGData _ NARROW[clientData]; rgb: ImagerColor.RGB; name: Rope.ROPE _ IF event.rest = NIL THEN ViewerTools.GetSelectionContents[] ELSE NARROW[event.rest.first]; entityGen: SliceGenerator _ GGScene.TopLevelEntitiesInScene[ggData.scene]; noneFlag: BOOL _ Rope.Equal[name, "none", FALSE]; IF NOT noneFlag THEN rgb _ SELECT event.first FROM $SelectMatchingAreaCNS => ImagerColorFns.RGBFromHSL[NamedColors.RopeToHSL[name ! NamedColors.UndefinedName => GOTO UndefinedName; NamedColors.BadGrammar => GOTO BadGrammar; ]], $SelectMatchingAreaRGB => RGBFromRope[name ! RGBFromRopeError => GOTO SyntaxError] ENDCASE => ERROR; GGSelect.DeselectAll[ggData.scene, normal]; FOR entity: REF ANY _ GGScene.NextEntity[entityGen], GGScene.NextEntity[entityGen] UNTIL entity = NIL DO WITH entity SELECT FROM outline: Slice => { fillColor: Imager.Color _ outline.class.getFillColor[outline]; IF RGBEqualsColor[rgb, fillColor, noneFlag] THEN GGSelect.SelectEntireOutline[outline, ggData.scene, normal]; }; slice: Slice => { fillColor: Imager.Color _ slice.class.getFillColor[slice]; IF RGBEqualsColor[rgb, fillColor, noneFlag] THEN GGSelect.SelectSlice[slice.class.newParts[slice, NIL, topLevel], ggData.scene, normal]; }; ENDCASE => ERROR; ENDLOOP; Feedback.PutFHerald[ggData.feedback, oneLiner, "Areas with fill color %g selected", [rope[name]] ]; GGWindow.RestoreScreenAndInvariants[paintAction: $SelectionChanged, ggData: ggData, remake: none, backgndOK: TRUE, edited: FALSE, okToClearFeedback: FALSE]; EXITS SyntaxError => {Feedback.AppendHerald[NARROW[clientData, GGData].feedback, "RGB Syntax is R: [0.0..1.0] G: [0.0..1.0] B: [0.0..1.0]", oneLiner]; Feedback.Blink[NARROW[clientData, GGData].feedback];}; UndefinedName => {Feedback.AppendHerald[NARROW[clientData, GGData].feedback, "Undefined Color Name", oneLiner]; Feedback.Blink[NARROW[clientData, GGData].feedback];}; BadGrammar => {Feedback.AppendHerald[NARROW[clientData, GGData].feedback, "Bad Color Name", oneLiner]; Feedback.Blink[NARROW[clientData, GGData].feedback];}; }; TestMultiGravity: PUBLIC PROC [clientData: REF ANY, event: LIST OF REF ANY] = { ggData: GGData _ NARROW[clientData]; Within the bounds of the viewer, randomly choose mouse positions. See if that mouse position is in range of any object. If so, draw a dot at that point. Repeat until 100 points have been drawn. xRandomStream, yRandomStream: Random.RandomStream; testPoint: Point; x, y: INT; totalCount: NAT _ 0; features: GGMultiGravity.NearFeatures; points: GGMultiGravity.NearPoints; distances: GGMultiGravity.NearDistances; currentObjects: AlignBag; sceneObjects: TriggerBag; count: NAT; xRandomStream _ Random.Create[ggData.actionArea.cw]; yRandomStream _ Random.Create[ggData.actionArea.ch]; GGAlign.SetBagsForAction[ggData, $CaretPos]; GGWindow.RestoreScreenAndInvariants[paintAction: $PaintAlign, ggData: ggData, remake: none, backgndOK: TRUE, edited: FALSE, okToClearFeedback: FALSE]; ggData.hitTest.hitCount _ 0; ggData.aborted[gravitytest] _ FALSE; -- in case there was one left over from prior abort UNTIL totalCount > 1000 DO IF ggData.aborted[gravitytest] THEN { ggData.aborted[gravitytest] _ FALSE; EXIT; }; x _ Random.NextInt[xRandomStream]; y _ Random.NextInt[yRandomStream]; testPoint _ [x, y]; testPoint _ GGWindow.ViewerToWorld[viewerPoint: testPoint, ggData: ggData]; ggData.refresh.spotPoint _ testPoint; currentObjects _ ggData.hitTest.alignBag; sceneObjects _ ggData.hitTest.sceneBag; [features, points, distances, count] _ GGMultiGravity.MultiMap[20, testPoint, ggData.hitTest.tolerance, currentObjects, sceneObjects, ggData, TRUE]; IF count > 0 THEN { FOR i: NAT IN [0..count-1] DO ggData.refresh.hitPoint _ points[i]; IF distances[i] > ggData.hitTest.tolerance THEN GOTO Done; GGWindow.RestoreScreenAndInvariants[paintAction: $PaintHitLine, ggData: ggData, remake: none, backgndOK: TRUE, edited: FALSE, okToClearFeedback: FALSE]; ggData.hitTest.hitCount _ ggData.hitTest.hitCount + 1; REPEAT Done => { IF i = 0 THEN GGWindow.RestoreScreenAndInvariants[paintAction: $PaintSpot, ggData: ggData, remake: none, backgndOK: TRUE, edited: FALSE, okToClearFeedback: FALSE]; }; ENDLOOP; } ELSE { GGWindow.RestoreScreenAndInvariants[paintAction: $PaintSpot, ggData: ggData, remake: none, backgndOK: TRUE, edited: FALSE, okToClearFeedback: FALSE]; }; totalCount _ totalCount + 1; ENDLOOP; Feedback.PutF[ggData.feedback, oneLiner, "Tested %g total points. %g were hits", [integer[totalCount]], [integer[ggData.hitTest.hitCount]]]; }; FileoutSceneAndOptionsOLDD: PUBLIC PROC [f: IO.STREAM, ggData: GGData, fileName: Rope.ROPE] = { entityGen: SliceGenerator _ GGScene.TopLevelEntitiesInScene[ggData.scene]; entityCount: NAT _ GGScene.EntityCount[entityGen]; fileName _ FileNames.GetShortName[fileName]; f.PutF["Gargoyle file for scene: %g\n", [rope[fileName]]]; f.PutF["Produced by version %g\n\n", [rope[versionRope]]]; FileoutAlignments[f, ggData]; f.PutF["Entities: [%g]:\n\n", [integer[entityCount]]]; FOR entity: REF ANY _ GGScene.NextEntity[entityGen], GGScene.NextEntity[entityGen] UNTIL entity = NIL DO FileoutEntity[f, entity]; ENDLOOP; }; FileoutSceneOnlyOLDD: PUBLIC PROC [f: IO.STREAM, scene: Scene, fileName: Rope.ROPE] = { entityGen: SliceGenerator _ GGScene.TopLevelEntitiesInScene[scene]; entityCount: NAT _ GGScene.EntityCount[entityGen]; fileName _ FileNames.GetShortName[fileName]; f.PutF["Gargoyle file for scene: %g\n", [rope[fileName]]]; f.PutF["Produced by version %g\n\n", [rope[versionRope]]]; FileoutAlignments[f, ggData]; f.PutChar[IO.CR]; f.PutChar[IO.CR]; f.PutF["Entities: [%g]:\n\n", [integer[entityCount]]]; FOR entity: REF ANY _ GGScene.NextEntity[entityGen], GGScene.NextEntity[entityGen] UNTIL entity = NIL DO FileoutEntity[f, entity]; ENDLOOP; }; FileoutEntityOLDD: PROC [f: IO.STREAM, entity: REF ANY] = { WITH entity SELECT FROM slice: Slice => FileoutSlice[f, slice]; outline: Slice => outline.class.fileout[outline, f]; ENDCASE => ERROR; }; FileoutSliceOLDD: PUBLIC PROC [f: IO.STREAM, slice: Slice] = { className: Rope.ROPE _ Atom.GetPName[slice.class.type]; f.PutF["Slice (class: %g) [%g]:\n", [rope[className]], [integer[0]]]; f.PutF["Data: "]; slice.class.fileout[slice, f]; f.PutChar[IO.CR]; f.PutChar[IO.CR]; }; AddLineIntersections: PROC [featureData: FeatureData, objectBag: AlignBag] = { iPoint: Point; parallel: BOOL; points: ARRAY[1..2] OF Point; hitCount: NAT; line: Line; WITH featureData.shape SELECT FROM l: Line => line _ l; aL: AlignmentLine => line _ aL.line; ENDCASE => ERROR Problem[msg: "Broken Invariant"]; FOR lineList: LIST OF FeatureData _ objectBag.slopeLines, lineList.rest UNTIL lineList = NIL DO [iPoint, parallel] _ Lines2d.LineMeetsLine[NARROW[lineList.first.shape, AlignmentLine].line, line]; IF NOT parallel THEN { AddIntersectionPointFeature[iPoint, featureData, lineList.first, objectBag]; }; ENDLOOP; FOR lineList: LIST OF FeatureData _ objectBag.angleLines, lineList.rest UNTIL lineList = NIL DO [iPoint, parallel] _ Lines2d.LineMeetsLine[NARROW[lineList.first.shape, AlignmentLine].line, line]; IF NOT parallel THEN { AddIntersectionPointFeature[iPoint, featureData, lineList.first, objectBag]; }; ENDLOOP; FOR dlineList: LIST OF FeatureData _ objectBag.distanceLines, dlineList.rest UNTIL dlineList = NIL DO [iPoint, parallel] _ Lines2d.LineMeetsLine[NARROW[dlineList.first.shape], line]; IF NOT parallel THEN { AddIntersectionPointFeature[iPoint, featureData, dlineList.first, objectBag]; }; ENDLOOP; FOR circleList: LIST OF FeatureData _ objectBag.radiiCircles, circleList.rest UNTIL circleList = NIL DO [points, hitCount] _ GGCircles.LineMeetsCircle[line, NARROW[circleList.first.shape, AlignmentCircle].circle]; FOR i: NAT IN [1..hitCount] DO AddIntersectionPointFeature[points[i], featureData, circleList.first, objectBag]; ENDLOOP; ENDLOOP; }; AddCircleIntersections: PROC [featureData: FeatureData, objectBag: AlignBag] = { points: ARRAY[1..2] OF Point; hitCount: NAT; circle: Circle _ NARROW[featureData.shape, AlignmentCircle].circle; FOR lineList: LIST OF FeatureData _ objectBag.slopeLines, lineList.rest UNTIL lineList = NIL DO [points, hitCount] _ GGCircles.LineMeetsCircle[NARROW[lineList.first.shape, AlignmentLine].line, circle]; FOR i: NAT IN [1..hitCount] DO AddIntersectionPointFeature[points[i], lineList.first, featureData, objectBag]; ENDLOOP; ENDLOOP; FOR lineList: LIST OF FeatureData _ objectBag.angleLines, lineList.rest UNTIL lineList = NIL DO [points, hitCount] _ GGCircles.LineMeetsCircle[NARROW[lineList.first.shape, AlignmentLine].line, circle]; FOR i: NAT IN [1..hitCount] DO AddIntersectionPointFeature[points[i], lineList.first, featureData, objectBag]; ENDLOOP; ENDLOOP; FOR dlineList: LIST OF FeatureData _ objectBag.distanceLines, dlineList.rest UNTIL dlineList = NIL DO [points, hitCount] _ GGCircles.LineMeetsCircle[NARROW[dlineList.first.shape], circle]; FOR i: NAT IN [1..hitCount] DO AddIntersectionPointFeature[points[i], dlineList.first, featureData, objectBag]; ENDLOOP; ENDLOOP; FOR circleList: LIST OF FeatureData _ objectBag.radiiCircles, circleList.rest UNTIL circleList = NIL DO [points, hitCount] _ GGCircles.CircleMeetsCircle[NARROW[circleList.first.shape, AlignmentCircle].circle, circle]; FOR i: NAT IN [1..hitCount] DO AddIntersectionPointFeature[points[i], circleList.first, featureData, objectBag]; ENDLOOP; ENDLOOP; }; AddIntersectionPointFeature: PRIVATE PROC [point: Point, feature1, feature2: FeatureData, objectBag: AlignBag] = { featureData: FeatureData; alignmentPoint: AlignmentPoint; featureData _ NEW[FeatureDataObj]; alignmentPoint _ NEW[AlignmentPointObj _ [point: point, curve1: feature1, curve2: feature2]]; featureData.type _ intersectionPoint; featureData.shape _ alignmentPoint; AddFeature[featureData, objectBag]; }; Map: PUBLIC PROC [testPoint: Point, criticalR: REAL, currentObjects: AlignBag, activeObjects: TriggerBag, ggData: GGData, intersections: BOOL] RETURNS [resultPoint: Point, feature: FeatureData] = { ENABLE UNWIND => ggData.gravityPool _ NewGravityPool[]; -- in case an ABORT happened while pool was in use [resultPoint, feature] _ GGMultiGravity.Map[testPoint, criticalR, currentObjects, activeObjects, ggData, intersections]; }; ExtractResultFromCurve: PROC [curve: GoodCurve, feature: FeatureData] = { SELECT feature.type FROM outline => feature.hitPart _ curve.hitData; slice => feature.hitPart _ curve.hitData; slopeLine, angleLine, radiiCircle, distanceLine => {}; ENDCASE => SIGNAL Problem[msg: "Unimplemented type."]; }; ExtractResultFromPoint: PROC [goodPoint: GoodPoint, feature: FeatureData] = { SELECT goodPoint.type FROM joint, controlPoint => feature.hitPart _ goodPoint.hitData; slice => feature.hitPart _ goodPoint.hitData; intersectionPoint => feature.hitPart _ NIL; midpoint => { midPoint features contain a reasonable segNum in their hitPart }; ENDCASE => SIGNAL Problem [msg: "Unimplemented result type."]; }; OverlapMenu: Menus.ClickProc = { ggData: GGData _ NARROW[clientData]; menu: LIST OF PopUpMenuEntry; menu _ LIST [ ["Top", ], ["Bottom", LIST [$Bottom]], ["UpOne", LIST [$UpOne]], ["DownOne", LIST [$DownOne]] ]; QueuePopUpMenuAction["Overlap", menu, ggData, mouseButton#blue]; }; UpdateSceneForCopy: PROC [scene: Scene, feedback: FeedbackData] RETURNS [newSlices: LIST OF Slice, success: BOOL _ TRUE] = { sliceDGen: SliceDescriptorGenerator; outSeqGen: GGSelect.OutlineSequenceGenerator; newOutline, outline: Slice; newTraj: Traj; newSlice: Slice; Copy selected slices. sliceDGen _ GGSelect.SelectedSlices[scene, normal]; FOR sliceD: SliceDescriptor _ GGSelect.NextSliceDescriptor[sliceDGen], GGSelect.NextSliceDescriptor[sliceDGen] UNTIL sliceD = NIL DO newSlice _ GGSlice.CopySlice[sliceD.slice]; -- make the new one GGSelect.DeselectSlice[sliceD.slice, sliceD.parts, scene, normal]; newSlices _ CONS[newSlice, newSlices]; newSlice.priority _ GGScene.SlicePriority[scene, sliceD.slice]; ENDLOOP; BEGIN outSeqGen _ GGSelect.SelectedOutlineSequences[scene, normal]; FOR outSeq: GGSelect.OutlineSequence _ GGSelect.NextOutlineSequences[outSeqGen], GGSelect.NextOutlineSequences[outSeqGen] UNTIL outSeq = NIL DO outline _ outSeq.outline; IF outSeq.fenceSeq # NIL THEN { IF NOT GGSequence.ContainsSomeSegment[outSeq.fenceSeq] THEN GOTO NoSegmentsSelected; If the whole outline is selected, copy it as a whole. IF GGSelect.IsSelectedInFull[outline, scene, normal] THEN { newOutline _ outline.class.copy[outline]; GGSelect.DeselectEntireSlice[outline, scene, normal]; -- deselect the old one newSlices _ CONS[newOutline, newSlices]; newOutline.priority _ outline.priority; LOOP; } Otherwise, each piece becomes a new slice. ELSE { newTraj _ GGTraj.CopyTrajFromRun[outSeq.fenceSeq]; newOutline _ GGOutline.CreateOutline[newTraj, outline.class.getFillColor[outline]]; GGSelect.DeselectSequence[outSeq.fenceSeq, scene, normal]; newSlices _ CONS[newOutline, newSlices]; newOutline.priority _ outline.priority; }; }; FOR holeSeq: Sequence _ GGSequence.NextSequence[outSeq.holeSeqs], GGSequence.NextSequence[outSeq.holeSeqs] UNTIL holeSeq = NIL DO IF NOT GGSequence.ContainsSomeSegment[holeSeq] THEN GOTO NoSegmentsSelected; newTraj _ GGTraj.CopyTrajFromRun[holeSeq]; newOutline _ GGOutline.CreateOutline[newTraj, outline.class.getFillColor[outline]]; GGSelect.DeselectSequence[holeSeq, scene, normal]; newSlices _ CONS[newOutline, newSlices]; newOutline.priority _ outline.priority; ENDLOOP; ENDLOOP; Sort the new slices newSlices _ SortNewEntities[scene, newSlices]; Add all the new slices to the scene. FOR sliceList: LIST OF Slice _ newSlices, sliceList.rest UNTIL sliceList = NIL DO allParts: SliceDescriptor; GGScene.AddSlice[scene, sliceList.first, -1]; allParts _ sliceList.first.class.newParts[sliceList.first, NIL, slice]; GGSelect.SelectSlice[allParts, scene, normal]; ENDLOOP; EXITS NoSegmentsSelected => { Feedback.AppendHerald[feedback, ". . . Cannot Copy Joints or CPs", begin]; Feedback.Blink[feedback]; GGSelect.DeselectAll[scene, normal]; We are about to self-abort. We deselect all so that we don't delete any of the original geometry (see AbortCopyAndDrag above). RETURN[NIL, FALSE]; }; END; }; SafelyGetCaretTrajOLDD: PROC [caret: Caret] RETURNS [outlineD: SliceDescriptor, partType: TrajPartType, traj: Traj, jointNum: NAT] = { chair: REF ANY; success: BOOL; chair _ GGCaret.GetChair[caret]; IF ISTYPE[chair, SliceDescriptor] THEN ERROR Problem[msg: "Slices are Outlines now. Update this code."]; outlineD _ NARROW[chair]; [success, partType, traj, ----, jointNum] _ GGOutline.UnpackSimpleDescriptorOld[outlineD]; IF NOT success OR partType # joint THEN ERROR Problem[msg: "Attempt to extend a trajectory without the caret on its end"]; }; EndSelectAuxOLDD: PROC [ggData: GGData, resultPoint: Point, feature: FeatureData, hitData: REF ANY, mode: SelectMode, opName: Rope.ROPE] = { Prepare for a subsequent Add operation and for Extend. IF feature = NIL THEN { GGCaret.SitOn[ggData.caret, NIL]; Feedback.PutFHerald[ggData.feedback, oneLiner, "No near %g found.", [rope[opName]]]; } ELSE { Make Selection and Prepare for Extend. SELECT mode FROM joint => ggData.drag.extendMode _ joint; segment => ggData.drag.extendMode _ segmentRange; traj => ggData.drag.extendMode _ traj; topLevel => ggData.drag.extendMode _ topLevel; ENDCASE => ERROR; SELECT feature.type FROM outline => { outlineD: SliceDescriptor _ NARROW[SelectSlicePart[feature, hitData, ggData, mode]]; SitTheCaret[ggData.caret, outlineD, hitData, mode]; IF mode = topLevel THEN Feedback.AppendHerald[ggData.feedback, "Top level outline selected.", oneLiner] ELSE Feedback.AppendHerald[ggData.feedback, Rope.Concat[outlineD.slice.class.describe[outlineD], " selected"], oneLiner]; ggData.drag.outlineToExtend _ outlineD; ggData.drag.sliceToExtend _ NIL; }; slice => { sliceD: SliceDescriptor _ NARROW[SelectSlicePart[feature, hitData, ggData, mode]]; IF sliceD.slice.class.type = $Slice THEN { ERROR Problem[msg: "Outlines must be Slices now."]; } ELSE { IF mode = traj OR mode = topLevel THEN GGCaret.SitOn[ggData.caret, NIL] ELSE GGCaret.SitOn[ggData.caret, sliceD]; }; Feedback.AppendHerald[ggData.feedback, Rope.Concat[sliceD.slice.class.describe[sliceD], " selected"], oneLiner]; ggData.drag.outlineToExtend _ NIL; ggData.drag.sliceToExtend _ sliceD; }; ENDCASE => ERROR Problem[msg: "Unexpected feature type"]; }; GGWindow.RestoreScreenAndInvariants[paintAction: $SelectionChanged, ggData: ggData, remake: none, backgndOK: TRUE, edited: FALSE, okToClearFeedback: FALSE]; }; -- end EndSelectAux SitTheCaretOLDD: PROC [caret: Caret, outlineD: SliceDescriptor, hitData: REF ANY, mode: SelectMode] = { SELECT mode FROM joint => GGCaret.SitOn[caret, outlineD]; segment, traj, topLevel => { jointParts: SliceParts; jointSeq: Sequence; jointD: SliceDescriptor; jointNum: NAT; traj: Traj; IF outlineD.slice.class.type = $Slice THEN { [jointNum, traj] _ GGOutline.NearestJointToHitData[hitData]; jointSeq _ GGSequence.CreateFromJoint[traj, jointNum]; jointParts _ GGOutline.PartsFromSequence[outlineD.slice, jointSeq]; jointD _ GGOutline.DescriptorFromParts[outlineD.slice, jointParts]; GGCaret.SitOn[caret, jointD]; } ELSE GGCaret.SitOn[caret, NIL]; }; ENDCASE => ERROR; }; OutlineDescribeProc: TYPE = GGModelTypes.OutlineDescribeProc; OutlineFileoutProc: TYPE = GGModelTypes.OutlineFileoutProc; OutlineFileinProc: TYPE = GGModelTypes.OutlineFileinProc; OutlineUnionPartsProc: TYPE = GGModelTypes.OutlineUnionPartsProc; OutlineDifferencePartsProc: TYPE = GGModelTypes.OutlineDifferencePartsProc; OutlineAugmentPartsProc: TYPE = GGModelTypes.OutlineAugmentPartsProc; OutlinePointsInDescriptorProc: TYPE = GGModelTypes.OutlinePointsInDescriptorProc; OutlinePointPairsInDescriptorProc: TYPE = GGModelTypes.OutlinePointPairsInDescriptorProc; OutlineNextPointProc: TYPE = GGModelTypes.OutlineNextPointProc; OutlineNextPointPairProc: TYPE = GGModelTypes.OutlineNextPointPairProc; OutlineClosestPointProc: TYPE = GGModelTypes.OutlineClosestPointProc; OutlineClosestPointAndTangentProc: TYPE = GGModelTypes.OutlineClosestPointAndTangentProc; OutlineClosestSegmentProc: TYPE = GGModelTypes.OutlineClosestSegmentProc; OutlineSetArrowsProc: TYPE = GGModelTypes.OutlineSetArrowsProc; OutlineGetArrowsProc: TYPE = GGModelTypes.OutlineGetArrowsProc; FetchSliceClass: PUBLIC PROC [name: ATOM] RETURNS [class: SliceClass] = { class _ globalOutlineClass; }; FetchOutlineClass: PROC [] RETURNS [class: SliceClass] = { class _ globalOutlineClass; }; globalOutlineClass: SliceClass; Init: PROC [] = { globalOutlineClass _ MakeOutlineClass[]; }; Init[]; OutlineDescribeProc: TYPE = GGModelTypes.OutlineDescribeProc; OutlineFileoutProc: TYPE = GGModelTypes.OutlineFileoutProc; OutlineFileinProc: TYPE = GGModelTypes.OutlineFileinProc; OutlineUnionPartsProc: TYPE = GGModelTypes.OutlineUnionPartsProc; OutlineDifferencePartsProc: TYPE = GGModelTypes.OutlineDifferencePartsProc; OutlineAugmentPartsProc: TYPE = GGModelTypes.OutlineAugmentPartsProc; OutlinePointsInDescriptorProc: TYPE = GGModelTypes.OutlinePointsInDescriptorProc; OutlinePointPairsInDescriptorProc: TYPE = GGModelTypes.OutlinePointPairsInDescriptorProc; OutlineNextPointProc: TYPE = GGModelTypes.OutlineNextPointProc; OutlineNextPointPairProc: TYPE = GGModelTypes.OutlineNextPointPairProc; OutlineClosestPointProc: TYPE = GGModelTypes.OutlineClosestPointProc; OutlineClosestPointAndTangentProc: TYPE = GGModelTypes.OutlineClosestPointAndTangentProc; OutlineClosestSegmentProc: TYPE = GGModelTypes.OutlineClosestSegmentProc; OutlineSetArrowsProc: TYPE = GGModelTypes.OutlineSetArrowsProc; OutlineGetArrowsProc: TYPE = GGModelTypes.OutlineGetArrowsProc; UnpackSimpleDescriptorOld: PUBLIC PROC [outlineD: SliceDescriptor] RETURNS [success: BOOL, partType: TrajPartType, traj: Traj, joint: Joint _ NIL, jointNum: NAT _ 999, cp: Point, cpNum: NAT _ 999, seg: Segment _ NIL, segNum: NAT _ 999] = { parts: OutlineParts; theSeq: Sequence; IF outlineD = NIL THEN RETURN[FALSE, joint, NIL, NIL, 999, [0,0]]; parts _ NARROW[outlineD.parts]; traj _ NIL; FOR list: LIST OF Sequence _ parts.seqs, list.rest UNTIL list = NIL DO IF list.first # NIL THEN { IF traj # NIL THEN RETURN[FALSE, joint, NIL, NIL, 999, [0,0]] ELSE { theSeq _ list.first; traj _ theSeq.traj; [success, partType, traj, joint, jointNum, cp, cpNum, seg, segNum] _ GGSequence.UnpackSimpleSequence[theSeq]; }; }; ENDLOOP; }; DescriptorFromParts: PUBLIC PROC [outline: Slice, sliceParts: SliceParts] RETURNS [sliceD: SliceDescriptor] = { sliceD _ NEW[SliceDescriptorObj _ [outline, sliceParts]]; }; AddHole: PUBLIC PROC [outline: Slice, hole: Traj] RETURNS [holier: Slice] = { Holes can be removed using DeleteSequence. Should check for duplicates. -- Bier, February 20 holier _ outline.class.copy[outline]; holier.children _ AppendTrajList[holier.children, LIST[hole]]; hole.parent _ holier; hole.role _ hole; UpdateBoundBox[holier]; }; UpdateDescriptorBoundBoxes: PUBLIC PROC [outlineD: SliceDescriptor] = { Update the bound boxes of all contained sequences. parts: OutlineParts _ NARROW[outlineD.parts]; FOR list: LIST OF Sequence _ parts.seqs, list.rest UNTIL list = NIL DO IF list.first # NIL THEN GGSequence.UpdateBoundBox[list.first]; ENDLOOP; }; AllSelectedOutlines: PROC [scene: Scene] RETURNS [selectedList: LIST OF Slice _ NIL] = { Puts all the selected (hot & normal) outlines in a list, and returns them ptr: LIST OF Slice; outDGen: GGModelTypes.SliceDescriptorGenerator; outDGen _ GGSelect.SelectedOutlines[scene, hot]; [selectedList, ptr] _ GGUtility.StartOutlineList[]; FOR outD: SliceDescriptor _ GGSelect.NextOutlineDescriptor[outDGen], GGSelect.NextOutlineDescriptor[outDGen] UNTIL outD = NIL DO [selectedList, ptr] _ GGUtility.AddOutline[outD.slice, selectedList, ptr]; ENDLOOP; outDGen _ GGSelect.SelectedOutlines[scene, normal]; FOR outD: SliceDescriptor _ GGSelect.NextOutlineDescriptor[outDGen], GGSelect.NextOutlineDescriptor[outDGen] UNTIL outD = NIL DO IF NOT GGSelect.IsSelectedInPart[outD.slice, scene, hot] THEN [selectedList, ptr] _ GGUtility.AddOutline[outD.slice, selectedList, ptr]; ENDLOOP; }; DrawCpsOfSelectedOutlines: PROC [dc: Imager.Context, scene: Scene, camera: CameraData, dragInProgress, caretIsMoving: BOOL] = { normalD, hotD: SliceDescriptor; normalParts, hotParts: SliceParts; outline: Slice; IF caretIsMoving OR dragInProgress THEN RETURN; FOR oList: LIST OF Slice _ AllSelectedOutlines[scene], oList.rest UNTIL oList=NIL DO outline _ oList.first; normalD _ GGSelect.FindSelectedOutline[outline, scene, normal]; hotD _ GGSelect.FindSelectedOutline[outline, scene, hot]; normalParts _ IF normalD # NIL THEN normalD.parts ELSE NIL; hotParts _ IF hotD # NIL THEN hotD.parts ELSE NIL; outline.class.drawSelectionFeedback[outline, normalParts, hotParts, dc, camera, dragInProgress, caretIsMoving, FALSE, caretIsMoving]; ENDLOOP; }; WhoCaresIfChairIsAttractor: PROC [ggData: GGData] RETURNS [attOn: GGInterfaceTypes.CaretOn, attractor: REF ANY, attJointNum: NAT, attSeg: Segment] = { For now, I'm going to allow highlighting of moving objects. You only live once. Eric. Note: this procedure fixes a bug with ChairIsNotAttractor. Namely, highlighting does not occur with ChairIsNotAttractor when the caret is positioned on a selected segment. [attractor: attractor, on: attOn, jointNum: attJointNum, seg: attSeg] _ GGCaret.GetAttractor[ggData.caret]; WITH attractor SELECT FROM oSliceD: SliceDescriptor => {}; aSliceD: SliceDescriptor => {}; ENDCASE => attOn _ nothing; }; ChairIsNotAttractor: PROC [ggData: GGData] RETURNS [attOn: GGInterfaceTypes.CaretOn, attractor: REF ANY, attJointNum: NAT, attSeg: Segment] = { This code figures out if the chair and the attractor are "identical" in a bunch of weird cases. It returns on=nothing if they are "identical" and returns the attractor data if not "identical". This is the wrong question to ask. The right thing to do is to take those objects that the caret is attracted to, and subtract away any parts that are moving. -- Bier, December 16, 1986. chair: REF ANY; chairOn: GGInterfaceTypes.CaretOn; attSegNum, chairJointNum, chairSegNum: NAT; chairSeg: Segment; [attractor: attractor, on: attOn, jointNum: attJointNum, seg: attSeg, segNum: attSegNum] _ GGCaret.GetAttractor[ggData.caret]; [chair: chair, on: chairOn, jointNum: chairJointNum, segNum: chairSegNum, seg: chairSeg] _ GGCaret.GetChair[ggData.caret]; WITH attractor SELECT FROM aTraj: Traj => { attSeg1, attSeg2, chairSeg1, chairSeg2: NAT; IF chair#attractor THEN RETURN; -- return attractor information attractor and chair are the same traj IF attOn=joint THEN { IF GGTraj.IsEndJoint[aTraj, attJointNum] THEN attSeg2 _ attSeg1 _ IF attJointNum=0 THEN 0 ELSE attJointNum-1 -- open traj, end joint ELSE { -- closed traj or not end joint attSeg1 _ attJointNum; attSeg2 _ GGTraj.PreviousSegmentNum[aTraj, attJointNum]; }; } ELSE IF attOn=seg OR attOn=cp THEN attSeg2 _ attSeg1 _ attSegNum; IF chairOn=joint THEN { IF GGTraj.IsEndJoint[aTraj, chairJointNum] THEN chairSeg2 _ chairSeg1 _ IF chairJointNum=0 THEN 0 ELSE chairJointNum-1 -- open traj, end joint ELSE { -- closed traj or not end joint chairSeg1 _ chairJointNum; chairSeg2 _ GGTraj.PreviousSegmentNum[aTraj, chairJointNum]; }; } ELSE IF chairOn=seg OR chairOn=cp THEN chairSeg2 _ chairSeg1 _ chairSegNum; IF attSeg1=chairSeg1 OR attSeg2=chairSeg1 OR attSeg1=chairSeg2 OR attSeg2=chairSeg2 THEN attOn _ nothing; }; aSliceD: SliceDescriptor => { -- if slices are the same (don't user parts) then chair=attractor WITH chair SELECT FROM chairSliceD: SliceDescriptor => IF aSliceD.slice=chairSliceD.slice THEN attOn _ nothing; ENDCASE; }; ENDCASE => attOn _ nothing; }; GetOutlineParts: PROC [sliceD: SliceDescriptor, atom: ATOM] RETURNS [parts: SliceDescriptor] = { parts _ SELECT atom FROM $DrawBackgroundBox => sliceD.slice.class.movingParts[sliceD.slice, sliceD.parts].background, $DrawOverlayBox => sliceD.slice.class.movingParts[sliceD.slice, sliceD.parts].overlay, $DrawRubberBox => sliceD.slice.class.movingParts[sliceD.slice, sliceD.parts].rubber, $DrawDragBox => sliceD.slice.class.movingParts[sliceD.slice, sliceD.parts].drag, ENDCASE => ERROR; }; TopLevelEntitiesInScene: PUBLIC PROC [scene: SceneRef] RETURNS [sliceGen: SliceGenerator] = { Generates all of the outlines and slices in the scene. sliceGen _ NEW[SliceGeneratorObj _ [ list: scene.entities ]]; }; NearestTrajectoryInScene: PUBLIC PROC [scene: SceneRef, worldPt: Point, ggData: GGData] RETURNS [traj: Traj] = { feature: GGModelTypes.FeatureData; resultPoint: Point; sceneObjects: GGInterfaceTypes.TriggerBag; sceneObjects _ NARROW[ggData.hitTest.sceneBag]; [resultPoint, feature] _ GGMultiGravity.StrictDistance[worldPt, ggData.hitTest.criticalR, GGAlign.emptyAlignBag, sceneObjects, ggData]; RETURN[IF feature=NIL OR feature.type=slice THEN NIL ELSE NARROW[feature.shape, Sequence].traj]; }; AddEntity: PUBLIC PROC [scene: SceneRef, entity: REF ANY, priority: INT] = { Adds the entity to the scene. If priority = 0, it becomes the rearmost entity. IF priority = -1, it becomes the frontmost entity. If the priority given is too high, we proceed as if priority = -1. IF priority = -1 THEN AppendEntity[scene, entity] ELSE IF priority = 0 THEN { scene.ptrValid _ FALSE; scene.entities _ CONS[entity, scene.entities]; } ELSE SIGNAL Problem["Not yet implemented."]; scene.prioritiesValid _ FALSE; }; DeleteEntity: PUBLIC PROC [scene: SceneRef, entity: REF ANY] = { Removes the named entity from the scene. If the entity is not on the list, no action is taken. scene.ptrValid _ FALSE; scene.entities _ List.DRemove[entity, scene.entities]; scene.prioritiesValid _ FALSE; }; NextEntity: PUBLIC PROC [g: SliceGenerator] RETURNS [next: REF ANY] = { IF g.list = NIL THEN RETURN[NIL] ELSE { next _ g.list.first; g.list _ g.list.rest; }; }; EntityCount: PUBLIC PROC [g: SliceGenerator] RETURNS [count: NAT] = { IF g.countValid THEN RETURN[g.count]; count _ 0; FOR list: LIST OF REF ANY _ g.list, list.rest UNTIL list = NIL DO count _ count + 1; ENDLOOP; }; ListTrajsInSceneOLDD: PROC [scene: SceneRef] RETURNS [allTrajs: LIST OF Traj] = { allTrajs _ NIL; FOR entities: LIST OF REF ANY _ scene.entities, entities.rest UNTIL entities = NIL DO WITH entities.first SELECT FROM slice: Slice => { }; outline: Slice => { FOR trajs: LIST OF Traj _ outline.children, trajs.rest UNTIL trajs = NIL DO allTrajs _ CONS[trajs.first, allTrajs]; ENDLOOP; }; ENDCASE => ERROR; ENDLOOP; }; ListOutlinesInSceneOLDD: PROC [scene: SceneRef] RETURNS [allOutlines: LIST OF Slice] = { allOutlines _ NIL; FOR entities: LIST OF REF ANY _ scene.entities, entities.rest UNTIL entities = NIL DO WITH entities.first SELECT FROM slice: Slice => { }; outline: Slice => { allOutlines _ CONS[outline, allOutlines]; }; ENDCASE => ERROR; ENDLOOP; }; ListSlicesInSceneOLDD: PROC [scene: SceneRef] RETURNS [allSlices: LIST OF Slice] = { allSlices _ NIL; FOR entities: LIST OF REF ANY _ scene.entities, entities.rest UNTIL entities = NIL DO WITH entities.first SELECT FROM slice: Slice => { Doesn't work on Gargoyle slices. allSlices _ CONS[slice, allSlices]; }; outline: Slice => {}; ENDCASE => ERROR; ENDLOOP; }; CurveMaskStroke: PROC [seg: Segment, dc: Imager.Context] = { GGSegmentTypes.MaskStrokeProc Draw yourself into dc as a stroke. Assume that strokeWidth and color are already set. path: CubicPaths.Path _ GetPath[seg]; pathProc: ImagerPath.PathProc = {CubicPaths.EnumeratePath[path, moveTo, curveTo]}; Imager.SetStrokeEnd[dc, seg.strokeEnd]; Imager.MaskStroke[dc, pathProc]; }; SetComponentSelectedFields: PROC [entity: REF ANY, selected: BOOL, selectClass: SelectionClass] = { WITH entity SELECT FROM sliceD: SliceDescriptor => { SetSliceField[sliceD.slice, selected, selectClass]; }; outlineD: SliceDescriptor => { outlineD.slice.class.setSelectedFields[outlineD, selected, selectClass]; }; traj: Traj => { -- this case needed for ReselectTraj joint: Joint; jointGen: JointGenerator; segGen: SegmentGenerator; jointGen _ GGSequence.JointsInTraj[traj]; Joint Fields. FOR jointNum: INT _ GGSequence.NextJoint[jointGen], GGSequence.NextJoint[jointGen] UNTIL jointNum = -1 DO joint _ NARROW[Rosary.Fetch[traj.joints, jointNum]]; SetJointField[joint, selected, selectClass]; ENDLOOP; Segment Fields. segGen _ GGSequence.SegmentsInTraj[traj]; FOR seg: Segment _ GGSequence.NextSegment[segGen], GGSequence.NextSegment[segGen] UNTIL seg = NIL DO SetSegmentField[seg, selected, selectClass]; ENDLOOP; }; ENDCASE => ERROR; }; ChangeDonkeyTailOutline: PROC [sliceD: SliceDescriptor, selectClass: SelectionClass] = { SELECT selectClass FROM normal => sliceD.slice.normalSelectedParts _ sliceD; hot => sliceD.slice.hotSelectedParts _ sliceD; active => sliceD.slice.activeSelectedParts _ sliceD; ENDCASE; }; NoDonkeyTailOutline: PROC [slice: Slice, selectClass: SelectionClass] = { SELECT selectClass FROM normal => slice.normalSelectedParts _ NIL; hot => slice.hotSelectedParts _ NIL; active => slice.activeSelectedParts _ NIL; ENDCASE; }; SelectOutline: PUBLIC PROC [sliceD: SliceDescriptor, scene: SceneRef, selectClass: SelectionClass] = { oldD, union: SliceDescriptor; slice: Slice _ sliceD.slice; IF slice.class.emptyParts[sliceD] THEN RETURN; oldD _ FindSelectedOutline[slice, scene, selectClass]; IF oldD # NIL THEN { union _ slice.class.unionParts[oldD, sliceD]; DeselectOutline[slice, oldD.parts, scene, selectClass]; -- throw away old selection } ELSE union _ sliceD; IF selectClass = normal THEN union _ slice.class.augmentParts[union, selectClass]; AppendSelection[scene, union, selectClass]; ChangeDonkeyTailOutline[union, selectClass]; }; -- end SelectOutline SelectEntireOutline: PUBLIC PROC [outline: Slice, scene: SceneRef, selectClass: SelectionClass] = { allParts: SliceDescriptor _ outline.class.newParts[outline, NIL, slice]; SelectOutline[allParts, scene, selectClass]; SelectEntireSlice[outline, scene, selectClass]; }; DeselectEntireSliceOLDD: PUBLIC PROC [slice: Slice, scene: SceneRef, selectClass: SelectionClass] = { If this is a non-gargoyle slice, then make sure it is on the list, and take it off. selSliceD: SliceDescriptor _ FindSelectedSlice[slice, scene, selectClass]; IF selSliceD#NIL THEN { IF selSliceD.slice.class.type = $Slice THEN ERROR NotYetImplemented; DeleteSelection[scene, selSliceD, selectClass]; NoDonkeyTail[selSliceD.slice, selectClass]; SetComponentSelectedFields[selSliceD, FALSE, selectClass]; }; }; DeselectOutline: PUBLIC PROC [outline: Slice, parts: SliceParts, scene: SceneRef, selectClass: SelectionClass] = { Deselect each of the component trajectories; oldD, newD, tempD: SliceDescriptor; oldD _ FindSelectedOutline[outline, scene, selectClass]; IF oldD # NIL THEN { tempD _ GGOutline.DescriptorFromParts[outline, parts]; newD _ outline.class.differenceParts[oldD, tempD]; DeleteSelection[scene, oldD, selectClass]; NoDonkeyTailOutline[outline, selectClass]; IF NOT outline.class.emptyParts[newD] THEN { IF selectClass = normal THEN newD _ outline.class.augmentParts[newD, selectClass]; AppendSelection[scene, newD, selectClass]; ChangeDonkeyTailOutline[newD, selectClass]; }; }; }; DeselectEntireOutline: PUBLIC PROC [outline: Slice, scene: SceneRef, selectClass: SelectionClass] = { Remove this outline from the selected list, and reset all selected fields. outlineD: SliceDescriptor _ FindSelectedOutline[outline, scene, selectClass]; IF outlineD # NIL THEN { DeleteSelection[scene, outlineD, selectClass]; NoDonkeyTailOutline[outlineD.slice, selectClass]; }; }; ListSelectedSequences: PROC [scene: SceneRef, selectClass: SelectionClass] RETURNS [selectedList: LIST OF Sequence] = { This can be sped up by keeping separate lists for the different types of selected object. seq: Sequence; selectedList _ NIL; FOR entityList: LIST OF REF ANY _ ListSelected[scene, selectClass], entityList.rest UNTIL entityList = NIL DO IF ISTYPE[entityList.first, Sequence] THEN { seq _ NARROW[entityList.first]; selectedList _ CONS[seq, selectedList]; }; ENDLOOP; }; IsSelectedInFullOLDD: PUBLIC PROC [entity: REF ANY, scene: SceneRef, selectClass: SelectionClass] RETURNS [BOOL] = { WITH entity SELECT FROM slice: Slice => { IF slice.class.type = $Slice THEN ERROR NotYetImplemented; SELECT selectClass FROM normal => RETURN[slice.selectedInFull.normal]; hot => RETURN[slice.selectedInFull.hot]; active => RETURN[slice.selectedInFull.active]; ENDCASE => ERROR; }; outline: Slice => { trajGen: TrajGenerator; trajGen _ GGOutline.TrajsInOutline[outline]; FOR traj: Traj _ GGScene.NextTraj[trajGen], GGScene.NextTraj[trajGen] UNTIL traj = NIL DO IF NOT IsSelectedInFull[traj, scene, selectClass] THEN RETURN[FALSE]; ENDLOOP; RETURN[TRUE]; }; traj: Traj => { seq: Sequence; seq _ FindSelectedSequence[traj, scene, selectClass]; IF seq = NIL THEN RETURN[FALSE]; RETURN[GGSequence.IsComplete[seq]]; }; ENDCASE => ERROR; }; FindSelectedOutline: PUBLIC PROC [outline: Slice, scene: SceneRef, selectClass: SelectionClass] RETURNS [outlineD: SliceDescriptor] = { SELECT selectClass FROM normal => outlineD _ IF outline.normalSelectedParts = NIL THEN NIL ELSE outline.normalSelectedParts; hot => outlineD _ IF outline.hotSelectedParts = NIL THEN NIL ELSE outline.hotSelectedParts; active => outlineD _ IF outline.activeSelectedParts = NIL THEN NIL ELSE outline.activeSelectedParts; ENDCASE => ERROR; }; SelectedStuff: PUBLIC PROC [scene: SceneRef, selectClass: SelectionClass] RETURNS [sliceDescGen: SliceDescriptorGenerator] = { ptr: LIST OF SliceDescriptor _ NIL; sliceDescGen _ NEW[SliceDescriptorGeneratorObj]; FOR sliceDList: LIST OF SliceDescriptor _ ListSelected[scene, selectClass], sliceDList.rest UNTIL sliceDList = NIL DO [sliceDescGen.list, ptr] _ AddSliceDescriptor[sliceDList.first, sliceDescGen.list, ptr]; ENDLOOP; }; SelectedSlices: PUBLIC PROC [scene: SceneRef, selectClass: SelectionClass] RETURNS [sliceDescGen: SliceDescriptorGenerator] = { sliceD: SliceDescriptor _ NIL; ptr: LIST OF SliceDescriptor _ NIL; sliceDescGen _ NEW[SliceDescriptorGeneratorObj]; FOR entityList: LIST OF REF ANY _ ListSelected[scene, selectClass], entityList.rest UNTIL entityList = NIL DO IF ISTYPE[entityList.first, SliceDescriptor] THEN { sliceD _ NARROW[entityList.first]; [sliceDescGen.list, ptr] _ AddSliceDescriptor[sliceD, sliceDescGen.list, ptr]; }; ENDLOOP; }; NextOutlineDescriptor: PUBLIC PROC [g: SliceDescriptorGenerator] RETURNS [next: SliceDescriptor] = { IF g.list = NIL THEN RETURN[NIL] ELSE { next _ g.list.first; g.list _ g.list.rest; }; }; AddOutlineDescriptor: PROC [entity: SliceDescriptor, entityList, ptr: LIST OF SliceDescriptor] RETURNS [newList, newPtr: LIST OF SliceDescriptor] = { IF ptr = NIL THEN { IF NOT entityList = NIL THEN ERROR; newPtr _ newList _ CONS[entity, NIL]; RETURN; } ELSE { newList _ entityList; ptr.rest _ CONS[entity, NIL]; newPtr _ ptr.rest; }; }; SelectedOutlineSequencesOLDD: PUBLIC PROC [scene: SceneRef, selectClass: SelectionClass] RETURNS [outSeqGen: OutlineSequenceGenerator] = { Returns a generator for all selected sequences, grouped by outline. holeSeqs, ptr: LIST OF Sequence; outSeqPtr: LIST OF OutlineSequence; outlineSeq: OutlineSequence; fenceSeq, seq: Sequence; entityGen: GGModelTypes.SliceGenerator; seqList: LIST OF Sequence; newSeqGen: SequenceGenerator; outSeqGen _ NEW[OutlineSequenceGeneratorObj]; [outSeqGen.list, outSeqPtr] _ StartOutlineSequenceList[]; entityGen _ SelectedStuff[scene, selectClass]; FOR entity: REF ANY _ GGScene.NextEntity[entityGen], GGScene.NextEntity[entityGen] UNTIL entity = NIL DO WITH entity SELECT FROM sliceD: SliceDescriptor => NULL; outlineD: SliceDescriptor => { fenceSeq _ NIL; [holeSeqs, ptr] _ GGUtility.StartSequenceList[]; seqList _ GGOutline.SequencesOfOutline[outlineD]; seq _ seqList.first; IF seq.traj.role = fence OR seq.traj.role = open THEN { fenceSeq _ seq; seqList _ seqList.rest; }; FOR list: LIST OF Sequence _ seqList, list.rest UNTIL list = NIL DO [holeSeqs, ptr] _ GGUtility.AddSequence[list.first, holeSeqs, ptr]; ENDLOOP; newSeqGen _ IF holeSeqs=NIL THEN nilSeqGen ELSE NEW[SequenceGeneratorObj _ [list: holeSeqs]]; outlineSeq _ NEW[OutlineSequenceObj _ [outline: outlineD.slice, fenceSeq: fenceSeq, holeSeqs: newSeqGen]]; [outSeqGen.list, outSeqPtr] _ AddOutlineSequence[outlineSeq, outSeqGen.list, outSeqPtr]; }; ENDCASE => ERROR; ENDLOOP; }; DoForEachSelectedOutline: PUBLIC PROC [scene: SceneRef, selectClass: SelectionClass, outlineProc: OutlineProc] = { outDGen: SliceDescriptorGenerator _ SelectedOutlines[scene, selectClass]; FOR outlineD: SliceDescriptor _ NextOutlineDescriptor[outDGen], NextOutlineDescriptor[outDGen] UNTIL outlineD = NIL DO outlineProc[outlineD]; ENDLOOP; }; SetSliceField: PROC [slice: Slice, selected: BOOL, selectClass: SelectionClass] = { SELECT selectClass FROM normal => slice.selectedInFull.normal _ selected; hot => slice.selectedInFull.hot _ selected; active => slice.selectedInFull.active _ selected; ENDCASE; }; UpdateDescriptorBoundBoxesOLDD: PUBLIC PROC [sliceD: SliceDescriptor] = { IF sliceD.slice.class.type = $Outline THEN SIGNAL Problem[msg: "Time to have this proc call GGOutline.UpdateDescriptorBoundBoxes"]; }; SegmentsInDescriptorOLDD: PUBLIC PROC [sliceD: SliceDescriptor] RETURNS [segGen: SegmentGenerator] = { IF sliceD.slice.class.type=$Outline THEN SIGNAL Problem[msg: "GGSlice.SegmentsInSlice called with Slice slice. ILLEGAL"] ELSE segGen _ sliceD.slice.class.segmentsInDescriptor[sliceD]; }; WalkSegmentsOLDD: PUBLIC PROC [slice: Slice, walkProc: WalkProc] RETURNS [sliceD: SliceDescriptor] = { Calls the slice class walkSegments proc. The walkProc is called with each segment in the slice. If walkProc returns TRUE, the part of the slice that corresponds to the segment will be in the SliceDescriptor returned by WalkSegments. IF slice.class.type=$Outline THEN SIGNAL Problem[msg: "GGSlice.WalkSegments called with Slice slice. ILLEGAL"] ELSE sliceD _ slice.class.walkSegments[slice, walkProc]; }; PlaceOrigin: PROC [viewer: Viewer] = { viewer is the ActionArea. The created bitmap contexts have their transformations concatted with the analogous BiScrollers transformation so that operations on the new bitmaps will match the viewer when they are finally displayed. clientToViewer: Imager.Transformation; ggData: GGData _ NARROW[BiScrollers.ClientDataOfViewer[viewer]]; [clientToViewer, ----] _ BiScrollers.GetStyle[].GetTransforms[BiScrollers.QuaBiScroller[viewer]]; BufferedRefresh.FitSandwichToScreen[ggData.refresh.sandwich, viewer.cw, viewer.ch]; }; ÊR"˜JšœM˜MJšœP˜PJšœA˜AJ˜J˜0J˜JšœM˜MJšœI˜IJšœ6˜6JšœJ˜JJšœH˜HšÏb5Ïn ˜AJšÐbn œ˜*—JšÏy=˜=Jšœ9˜9Jšœ<˜˜>Jšœ@˜@JšœJ˜JJšœ@˜@JšœH˜HJšœ?˜?JšœA˜AJšœE˜EJš G˜GJš @˜@JšœG˜Gš8ž˜NJšœ œ˜?—JšœE˜EšE˜EJšœ žœ˜6—JšœL˜LJšœL˜Lš8ž˜OJšœ œ˜@—š8ž˜OJšœ žœ˜A—JšœF˜FJšœF˜FJšœD˜DJšœD˜DJšœK˜Kš7ž ˜DJ˜ —š3ž ˜?Jšžœ˜,—JšœK˜KJšœK˜KJšœI˜IJšœO˜OJšœV˜Vš=Ÿ˜OJšœžœ˜E—JšœU˜UJšœF˜FJšœN˜NJšœN˜NJšœD˜DJšœL˜LJšœH˜HJšœK˜KJšœF˜FJšœI˜IJšœP˜PJšœB˜BJšœB˜BJšœI˜IJšœI˜IJšœC˜CJšœE˜EJšœ;˜;Jšœ=˜=Jš 5˜5JšœF˜FJšœK˜Kš6ž˜FJšžœ˜*—š6ž˜IJšžœ˜-—š6ž˜GJšžœ˜+—Jšœ?˜?JšœA˜AJšœD˜DJšœD˜Dš7ž˜GJšžœ3˜G—JšœG˜Gš7ž˜OJšžœ-˜I—J˜Jšœ˜J˜JšœF˜FJ˜Jš A˜Aš8Ÿ˜=J˜'—šG˜GJ˜2—š@˜@J˜2—š6Ÿ ˜BJšÐblC˜C—š<Ÿ ˜HJšŸ œ˜2—š<Ÿ ˜GJš¡1˜1—šœI˜IJš¡˜—š6Ÿ˜IJ˜*—Jš G˜Gš8Ÿ˜RJšœ&Ÿœ˜R—š8Ÿ˜LJ˜B—šD˜DJ˜B—J˜J˜˜ J˜6J˜:Jšœk˜kJšœh˜hJ˜4J˜:J˜CJ˜J˜J˜KJ˜GJ˜RJ˜J˜;J˜7J˜0Jšœžœ*˜OJ˜4Jš!œ%œ˜eJšœ;˜;Icodešœ7˜7Jšœ žœ,žœ˜{Jšœ[˜[Jšœ<˜™>š¢œ¢œ¢œ™Kšœ>™>KšœB™Bš¢œ¢œ)¢œ™5KšœC™CKšœB™BK™—K™—K™K™—šžœ¢œ¢œ*¢œ™pKšœ5™5š¢œ¢œ¢œ™Kšœ@™@K™—K™K™—šžœ¢œ¢œ)™JKšœÁ™ÁKšœ™š ¢œ¢œ¢œ.¢œ¢œ¢™RJšœ¢œ™ Jš¢œ™—K™K™—šžœ¢œ¢œ'™FKšœ½™½K™K™—šžœ¢œ+™CKšœ(™(Kšœ™Kšœ,™,š¢œS¢œ ¢œ¢™lKšœ0™0Kšœ ™ Kš¢œ™—K™K™—šžœ¢œ¢œr™‘KšœØ™ØKšœ¢œ™ Kšœ™K™Kšœ<™<š¢œC¢œ¢œ¢™YKšœ&™&Kšœ£/™CKšœ$™$Kš¢œ™—Kšœ/™/š¢œI¢œ ¢œ¢™`Kšœ™Kš¢œ¢œ$™/Kš¢œ™—K™K™—š žœ¢œ¢œ¢œ¢œ!™jš ¢œ¢œ¢œ¢œ¢œ¢™:Kš ¢œ¢œ1¢œ¢œ¢œ™^Kš¢œ™—Kš¢œ¢œ™ K™K™—šžœ¢œ¢œ¢œ¢œ¢œ¢œ™‹Kšœ¢œ¢œ¢œ™!Kšœ¢œ¢œ™(Kš¢œ ¢œ¢œ¢œ™)š¢œ ¢œ¢™Kš¢œ¢œ4¢œ™CKšœ7¢œ™?Kšœ™Kšœ™Kš¢œ™—Kš¢œ™Kšœ™K™—šžœ¢œ¢œ¢œ¢œ¢œ¢œ™‰Kšœ¢œ¢œ¢œ™!Kšœ¢œ¢œ™(Kš¢œ ¢œ¢œ¢œ™)š¢œ ¢œ¢™Kš¢œ¢œ4¢œ™CKšœ7¢œ™?Kšœ™Kšœ™Kš¢œ™—Kš¢œ™Kšœ™K™K™—šž œ¢œ¢œ¢œ¢œ¢œ¢œ¢œ¢œ™Kšœ¢œ¢œ ™'Kš ¢œ¢œ¢œ¢œ¢œ¢œ™,Kšœc¢œ¢œ™tKš¢œ ¢œ¢œ¢œ™+Kš¢œ ¢œ¢œ™(š¢œ™Kšœ™Kšœ™K™—Kšœ™K™—šžœ¢œ*¢œ¢œ¢œ¢œ¢œ™Kšœ¢œ¢œ ™'Kšœ ¢œ¢œ™Kš ¢œ¢œ¢œ¢œ¢œ™&Kšœj¢œ¢œ™{Kš¢œ ¢œ¢œ™%Kš¢œ ¢œ¢œ™(š¢œ™Kšœ™Kšœ™K™—Kšœ™K™—šžœ¢œ¢œ;™eKšœ3™3Kšœ-™-Kšœ/™/K™Kšœ™šœ ¢œ™Kš9™9—Kšœ ¢œ™š¢œ ¢™KšœM™MKš¢œ™—Kšœ ¢œ™š¢œ ¢™KšœQ™QKš¢œ™Kšq™qKš9™9—KšœC™Cš¢œ¢œ¢œ™Kšœ?™?Kšœ ™ K™Kš&™&—Kšœ3™3Kšœ™K™—šžœ¢œ™8Kšœ™Kšœ™š ¢œ¢œ¢œ,¢œ¢œ¢™PKšœ™Kšœ ¢œ™%Kšœ-™-Kš¢œ™—K™K™——˜š žœ¢œ¢œ¢œ¢œ™KKš¢œ ¢œ¢œ¢œ™)Kš¢œ¢™KšœK™KKšœK™KKšœK™KKšœK™KKš¢œ¢œ™K™K™——˜š žœ¢œ¢œ ¢œ¢œ¢œ™zK™¾K™K™K™——˜K™šž œ¢œ¢œ¢œ™>Kšœ™K™K™—š ž œ¢œ¢œ¢œ¢œ™:Kš¢œ™K™K™—š žœ¢œ¢œ¢œ¢œ™?Kšœ ¢œ™Kšœ™Kšœ ¢œ™K™ Kš ¢œ¢œ¢œ¢œ¢œ™(š¢œ ¢œ¢™šœ™Kšœ£œ<™ZKš ¢œ¢œ ¢œ¢œ¢œ¢œ™6Kš¢œ$™*K™—™Kš¢œ"¢œ¢œ¢œ™7Kšœ£œ7™UKš ¢œ¢œ ¢œ¢œ¢œ¢œ™6Kš¢œ$™*K™—Kš¢œ¢œ™—K™K™—™ K™—šžœ¢œN™gKšœ'™'š ¢œ¢œ¢œ¢œ¢œ™;Kšœ=™=Kšœ8™8Kšœ?™?K™—š ¢œ¢œ¢œ¢œ¢œ¢œ™@Kšœ8™8Kšœ?™?K™—š ¢œ¢œ¢œ¢œ¢œ¢œ™@K™Kšœ4™4Kšœ4™4Kšœ,™,K™—š¢œ™Kšœ5™5Kšœ?™?Kšœ?™?K™—K™K™—šž œ¢œ¢œ¢œ™4Kšœ ¢œ ™Kš¢œ¢œ¢œ¢œ™AK™K™—š žœ¢œ¢œ¢œ ¢œ™^š ¢œ¢œ¢œ&¢œ¢œ¢™JKš¢œ)¢œ¢œ ™B—Kš¢œ™Kš¢œ¢œ™ K™K™—šžœ¢œS™nK™Kšœ'™'Kšœ:™:š ¢œ¢œ¢œ¢œ¢œ™7Kšœ7™7Kšœ¢œG™_K™—š ¢œ¢œ¢œ¢œ¢œ¢œ™™>Kšœ0™0Jš¢œ™Jš™—JšœD™Dš¢œ¢œ¢™š¢œw¢œ ¢œ¢™Jšœ™š¢œh¢œ ¢œ¢™Kšœ £œ6™FKšœ+™+Kšœ1™1Kš¢œ™Jš¢œ™—š¢œ ¢œ¢œ™Kšœ £œ7™Gš¢œ¢œ™#Kšœ$™$Kšœ;™;K™—š¢œ™Kšœ,™,Kšœ1™1K™—Kš¢œ™K™—š¢™™JšœD™DJ™——š¢œ™J™——Jš¢œ™—K™K™—šžœ¢œ¢œ™Fšž œ™Jšœ¢œ™ J™—K™'K™šœ;™;Kš0™0—Kšœ=™=š¢œr¢œ ¢œ¢™ŠKšœ>™>Kšœ0™0Jš¢œ™—šœ"™"J™^—JšœT¢œ™[Kšœ1™1K™K™—šž œ¢œ¢œ¢œ¢œ ¢œ¢œ¢œ¢œ™HKšœ¢œ ™$Kšœ¢œ¢œ™Kšœ ™ Kšœ™Kšœ™K™ Kšœ ¢œ™Kšœ'™'š¢™Kš¢œ ¢œ¢œ¢œ ™%š¢œ¢œ¢™šœ™Kšœ £œ8™FKš¢œ¢œ ¢œ¢œ™K™—šœ™Kš¢œ"¢œ¢œ ™:Kšœ £œ3™AKš¢œ¢œ ¢œ¢œ ™%K™—Kš¢œ¢œ™—Kš¢œ¢œ¢œ¢œ™AKšœY™YKšœ(™(Kšœ+™+Kšœ&™&š¢œ¢œ™ KšœE™EKšœ0¢œ™5Kš"™"Kšœ'™'Kšœ3¢œ™9K™—š¢œ™Kšœ9™9Kšœ9™9Kšœ#™#Kšœ=™=K™—K•StartOfExpansionx[traj: GGModelTypes.Traj, gargoyleData: GGInterfaceTypes.GargoyleData, selectClass: GGSegmentTypes.SelectionClass]šœ0™0K–£[caret: GGInterfaceTypes.Caret, on: GGInterfaceTypes.CaretOn _ nothing, chair: REF ANY _ NIL, jointNum: NAT _ 999, cpNum: NAT _ 999, segNum: NAT _ 999]šœ¢œ™!K–![caret: GGInterfaceTypes.Caret]šœ)™)Kšœ?™?Kšœ/™/šœ€¢œ ¢œ¢œ™¯Kšœ”™”—š¢™™Kšœ[™[Kšœ ™ K™—šœ™KšœW™WKšœ ™ K™——Kš¢œ™—Kšœ£ ™K™—šž œ¢œ¢œ¢œ¢œ ¢œ¢œ¢œ¢œ™IKšœ¢œ ™$KšœM™Mš¢œR¢œ¢œ¢™gKšœ¢œ™Kš¢œ™—K™K™—šž œ¢œ¢œ¢œ¢œ ¢œ¢œ¢œ¢œ™IKšœ¢œ ™$KšœM™Mš¢œR¢œ¢œ¢™gKšœ¢œ™Kš¢œ™—K™———˜šž œ¢œ¢œ¢œ¢œ ¢œ¢œ¢œ¢œ™HKšœ¢œ ™$Kšœ/™/Kšœ™Kšœ™Kšœ™Kšœ¢œ™ Kšœ:™:Kšœ&™&Kšœ'™'š ¢œ¢œ¢œ¢œ¢œ™!KšœU™UKšœ ™ Kš¢œ™K™—Kšœ,™,š¢œO¢œ¢œ¢™dKšœE™EKš œR¢œ ¢œ¢œ¢œ™“Kš¢œ™—Kšœw¢œ ¢œ¢œ™¥Kšœ™K™——˜šžœ¢œ¢œ¢œ¢œ ¢œ¢œ¢œ¢œ™RJ™%Jšœ¢œ ™$Jšœ ¢œ¢œ™J™Jšœ¢œ™ J™J™Jšœ ¢œ™J™J™1J–![caret: GGInterfaceTypes.Caret]šœ/™/š¢™Jš¢œ ¢œ¢œ¢œ ™)š¢œ ¢œ¢™šœ™Jš œ£œ£œ£œ£œ9™iJš ¢œ¢œ ¢œ¢œ¢œ ™;J™—™Jš¢œ¢œ¢œ ™6Jš œ£œ£œ£œ£œ6™fJš ¢œ¢œ ¢œ¢œ¢œ ™;J™—Jš¢œ¢œ™—š¢œ¢œ¢œ ™7Jšb™b—Jšœ+™+Jšœ2£Ðcz£ ™HJšœ/£™HJ™4J™&Jšœ4™4Jš¢œ¢œ+¢œ¢œ™@¡’˜ r jHÄŽæ ¢ ¨ÅXeroxÅ TiogaFontsÅ Helvetica10£¡ “ •  —¡¡¨  Š¡²“Á attractor– k é r jÇÄ, a ¢ ¨ÅXeroxÅ TiogaFontsÅ Helvetica10£¡ “ •  —¡¡¨  Š¡²“ÁnewSeg1– k é r jÄ+[ ¢ ¨ÅXeroxÅ TiogaFontsÅ Helvetica10£¡ “ •  —¡¡¨  Š¡²“ÁnewSeg2– k é¢¯“¡¡¨¢·“¢°“-™ÄA ­Ä¥W—-—ÄvéÄKЇ—˜¢¯“¡¡¨¢·“¢°“¤3™÷—˜ r j½ý ¢ ¨ÅXeroxÅ TiogaFontsÅ Helvetica10£¡ “ •  —¡¡¨  Š¡²“ÁnewRun– k é r j °“¢¯“¡¡¨ÄbKQÄLî­ÄbKQÄ'ýS¡¹¢¯“¡¡¨ÄbKQÄ'ýSÄMé Ä'ýS¡¹¢¯“¡¡¨ÄMé Ä'ýSÄMé ÄLî­¡¹¢¯“¡¡¨ÄMé ÄLî­ÄbKQÄLî­¡¹ k é r jèÄE[ ¢ ¨ÅXeroxÅ TiogaFontsÅ Helvetica10£¡ “ •  —¡¡¨  Š¡²“ÁnewJoint– k é k é k é k gšœ=™=J™7J™'Jš¢œ¢œ,¢œ¢œ™=Jš¢œ¢œ,¢œ¢œ™=Jšœ(™(Jšœ"¢œ™'Jš¢œ2¢œ¢œ£™OJ™!JšœZ™ZJšœ5™5Jšœ,™,K–)[traj: GGModelTypes.Traj, index: NAT]šœ"™"Jšœ¢œ™!J™,Kšœ€¢œ ¢œ¢œ™®š¢™™JšœY™YKšœ ™ K™—™JšœI™IKšœ ™ K™——Kš¢œ™—J™J™—šžœ¢œ¢œ¢œ¢œ ¢œ¢œ¢œ¢œ™YKšœ¢œ ™$K™`K–K[scene: GGModelTypes.Scene, selectClass: GGSegmentTypes.SelectionClass]š¢œ-¢œ¢™:š¢œ£&™-KšœP£™jKšœI™IKšœ#¢œ ¢œ™7š ¢œ¢œ¢œJ¢œ¢œ¢™€š¢œ¢œ¢™–;[seq: GGModelTypes.Sequence, scene: GGModelTypes.Scene]šœ™Kš$™$Kšœ@™@Kšœ4™4K™—–>[scene: GGModelTypes.Scene, cluster: GGModelTypes.Cluster]šœ™Kšœ>™>Kšœ0™0Kšœ™—Kš¢œ¢œ™—Kš¢œ™—K–)[traj: GGModelTypes.Traj, index: NAT]šœ"™"Jšœ¢œ™!Kšœ*™*Kšœ€¢œ ¢œ¢œ™®Kšœ™—Kšœ™K™—š žœ¢œ¢œ¢œ ¢œ¢œ™Ršžœ¢œ$¢œ¢œ™BKš¢œ¢œ¢œ¢œ™oK™—Kšœ™Kšœ™K–_[gargoyleData: GGInterfaceTypes.GargoyleData, selectClass: GGInterfaceTypes.SelectionClass]š¢œ-¢œ¢œ™;Kšœ<™<š¢œ¢œ-£™SKš-™-—š ¢œ¢œ¢œE¢œ¢œ¢™wK™Kšœ¢œ¢œ™š¢œ¢œ¢™šœ™KšœH™HKšœ™K™—šœ™KšœB™BKšœ™K™—Kš¢œ¢œ™Kš*™*—Kšœ9™9š ¢œ ¢œ¢œ?¢œ ¢œ¢™mKš¢œ¢œ¢œ™&Kš¢œ¢œ=¢œ£™Zš¢œ ¢œ¢™šœ™š¢œ+¢œ ¢œ™?Kšœ:™:K™—Kšœ™—šœ™š¢œ'¢œ ¢œ™;Kšœ1¢œ$™XK™—Kšœ™—Kš¢œ¢œ™—Kš¢œ™—Kš¢œ™—Kš ¢œ¢œn¢œ ¢œ¢œ™©Kšœ£™K™——šœ˜šžœ¢œ¢œ¢œ¢œ ¢œ¢œ¢œ¢œ™VKšœ¢œ ™$Kšœ¢œ™Kš œ ¢œ¢œ¢œ¢œ$¢œ¢œ™lKšœJ™JKšœ ¢œ¢œ™1š ¢œ¢œ ¢œ¢œ ¢™3šœ™Kšœ6™6Kšœ¢œ™0Kšœ¢œ ™*K™—šœ™Kšœ'¢œ ™8—Kš¢œ¢œ™—Kšœ+™+š ¢œ ¢œ¢œ@¢œ ¢œ¢™hš¢œ¢œ¢™šœ™Kšœ>™>Kš¢œ*¢œ=™mK™—™Kšœ:™:Kš¢œ*¢œ2¢œ#™ˆK™—Kš¢œ¢œ™—Kš¢œ™—K–Û[feedback: ViewerClasses.Viewer, msgType: GGError.MsgType, format: ROPE _ NIL, v1: IO.Value _ [null[]], v2: IO.Value _ [null[]], v3: IO.Value _ [null[]], v4: IO.Value _ [null[]], v5: IO.Value _ [null[]]]šœc™cKšœm¢œ ¢œ¢œ™œš¢™Kšœ&¢œt¢œ!™ÇKšœ(¢œQ¢œ!™¦Kšœ%¢œK¢œ!™—K™K™—šžœ¢œ¢œ¢œ¢œ ¢œ¢œ¢œ¢œ™OKšœ¢œ ™$K™ÄKšœ2™2Kšœ™Kšœ¢œ™ Kšœ ¢œ™Kšœ&™&Kšœ"™"Kšœ(™(K™K™Kšœ¢œ™ Kšœ4™4Kšœ4™4Kšœ,™,Kšœg¢œ ¢œ¢œ™–Kšœ™Kšœ¢œ£3™Yš¢œ¢™š¢œ¢œ™%Kšœ¢œ™$Kš¢œ™K™—Kšœ"™"Kšœ"™"K™KšœK™KKšœ ™%Kšœ)™)Kšœ'™'Kšœ6œP¢œ™”š¢œ ¢œ™š¢œ¢œ¢œ¢™Kšœ ™$Kš¢œ)¢œ¢œ™:Kšœi¢œ ¢œ¢œ™˜Kšœ6™6š¢™šœ ™ Kš¢œ¢™ Kšœf¢œ ¢œ¢œ™•K™——Kš¢œ™—K™—š¢œ™Kšœf¢œ ¢œ¢œ™•K™—K™Kš¢œ™—Kšœ™K™K™——Nšœ˜šœ˜procš žœ¢œ¢œ¢œ¢œ!¢œ™_PšœJ™JPšœ ¢œ"™2Pšœ,™,Pšœ:™:Pšœ:™:P™Pšœ6™6š ¢œ ¢œ¢œ@¢œ ¢œ¢™hPšœ™Pš¢œ™—Pšœ™P™—š žœ¢œ¢œ¢œ¢œ¢œ™WPšœC™CPšœ ¢œ"™2Pšœ,™,Pšœ:™:Pšœ:™:P™Kšœ ¢œ¢œ™Kšœ ¢œ¢œ™Pšœ6™6š ¢œ ¢œ¢œ@¢œ ¢œ¢™hPšœ™Pš¢œ™—Pšœ™P™P™—š žœ¢œ¢œ¢œ ¢œ¢œ™<š¢œ¢œ¢™Pšœ'™'Pšœ4™4Pš¢œ¢œ™—Pšœ™P™—š žœ¢œ¢œ¢œ¢œ™>Pšœ¢œ#™7PšœE™EP™Pšœ™Pšœ ¢œ¢œ™Pšœ ¢œ¢œ™Pšœ™——Nšœ˜Nšœ˜šœ˜šžœ¢œ4™NK™Kšœ ¢œ™Kšœ¢œ¢œ™Kšœ ¢œ™K™ š¢œ¢œ¢™"Kšœ™Kšœ$™$Kš¢œ¢œ"™2—š ¢œ ¢œ¢œ3¢œ ¢œ¢™_Kšœ+¢œ2™cš¢œ¢œ ¢œ™KšœL™LK™—Kš¢œ™—š ¢œ ¢œ¢œ3¢œ ¢œ¢™_Kšœ+¢œ2™cš¢œ¢œ ¢œ™KšœL™LK™—Kš¢œ™—š ¢œ ¢œ¢œ7¢œ ¢œ¢™eKšœ+¢œ™Pš¢œ¢œ ¢œ™KšœM™MK™—Kš¢œ™—š ¢œ ¢œ¢œ7¢œ¢œ¢™gKšœ5¢œ2™mš¢œ¢œ¢œ¢™KšœQ™QKš¢œ™—Kš¢œ™—K™K™—šžœ¢œ4™PKšœ¢œ¢œ™Kšœ ¢œ™Kšœ¢œ,™Cš ¢œ ¢œ¢œ3¢œ ¢œ¢™_Kšœœ¢œ4™iš¢œ¢œ¢œ¢™KšœO™OKš¢œ™—Kš¢œ™—š ¢œ ¢œ¢œ3¢œ ¢œ¢™_Kšœœ¢œ4™iš¢œ¢œ¢œ¢™KšœO™OKš¢œ™—Kš¢œ™—š ¢œ ¢œ¢œ7¢œ ¢œ¢™eKšœœ¢œ!™Vš¢œ¢œ¢œ¢™KšœP™PKš¢œ™—Kš¢œ™—š ¢œ ¢œ¢œ7¢œ¢œ¢™gKšœœ¢œ:™qš¢œ¢œ¢œ¢™KšœQ™QKš¢œ™—Kš¢œ™—Kšœ™K™—šžœ¢œ¢œI™rKšœ™K™Kšœ¢œ™"Kšœ¢œI™]Kšœ%™%Kšœ#™#Kšœ#™#K™—š žœ¢œ¢œ¢œV¢œ¢œ/™ÅKš¢œ¢œ,£2™kKšœx™xK™K™—šžœ¢œ-™Iš¢œ¢™Kšœ+™+Kšœ)™)Kšœ6™6Kš¢œ¢œ%™6—K™K™—šžœ¢œ1™Mš¢œ¢™Kšœ;™;Kšœ-™-Kšœ'¢œ™+™ K™>K™—Kš¢œ¢œ-™>—K™——Nšœ˜Nšœ˜šœ˜šŸ œ™ Kšœ¢œ ™$Kšœ¢œ¢œ™šœ¢œ™ Kšœ ™ Kšœ ¢œ ™Kšœ ¢œ ™Kšœ ¢œ ™K™—Kšœ@™@K™K™——šœ˜šžœ¢œ(¢œ ¢œ¢œ¢œ¢œ™|Kšœ$™$K™-Kšœ™Kšœ™K™Kš™Kšœ+œ™3š¢œl¢œ ¢œ¢™„Jšœ,£™?JšœB™BJšœ ¢œ™&Jšœ?™?Jš¢œ™—š¢™Jšœ=™=š¢œw¢œ ¢œ¢™Jšœ™š¢œ¢œ¢œ™Kš¢œ¢œ1¢œ¢œ™TJš5™5š¢œ3¢œ™;Jšœ)™)Jšœ6£™MJšœ ¢œ™(Jšœ'™'JšÐbkœ™J™—Jš*™*š¢œ™Jšœ2™2J–f[traj: GGModelTypes.Traj, lineEnds: Imager.StrokeEnd _ square, fillColor: ImagerColorDefs.Color]šœS™SJšœ:™:Jšœ ¢œ™(Jšœ'™'J™—J™—š¢œh¢œ ¢œ¢™Kš¢œ¢œ)¢œ¢œ™LJšœ*™*J–f[traj: GGModelTypes.Traj, lineEnds: Imager.StrokeEnd _ square, fillColor: ImagerColorDefs.Color]šœS™SJšœ2™2Jšœ ¢œ™(Jšœ'™'Jš¢œ™—Jš¢œ™—Jš™Jšœ.™.Jš$™$š ¢œ ¢œ¢œ#¢œ ¢œ¢™QJšœ™Jšœ-™-Jšœ;¢œ ™GJšœ.™.Jš¢œ™—š¢™šœ™KšœJ™JKšœ™šœ$™$K™—Kš¢œ¢œ¢œ™J™——Jš¢œ™—™J™——šžœ¢œ¢œK¢œ™†Kšœ¢œ¢œ™Kšœ ¢œ™Kšœ ™ Kš¢œ¢œ¢œ¢œ=™iKšœ ¢œ™KšœZ™ZKš ¢œ¢œ ¢œ¢œ¢œM™zK™K™——šœ˜š žœ¢œE¢œ¢œ!¢œ™ŒKš6™6š¢œ ¢œ¢œ™Kšœ¢œ™!KšœT™TK™—š¢œ™Kš&™&š¢œ¢™Kšœ(™(Kšœ1™1Kšœ&™&Kšœ.™.Kš¢œ¢œ™—š¢œ¢™šœ ™ Kšœ¢œ2™TKšœ3™3Kš¢œ¢œP™gKš¢œu™yKšœ'™'Kšœ¢œ™ Kšœ™—™ Kšœ¢œ2™Rš¢œ"¢œ™*Kš¢œ.™3K™—š¢œ™Kš¢œ ¢œ¢œ¢œ™GKš¢œ%™)K™—Kšœp™pKšœ¢œ™"Kšœ#™#K™—Kš¢œ¢œ)™9—K™—Kšœm¢œ ¢œ¢œ™œKšœ£™K™—šžœ¢œ4¢œ¢œ™gš¢œ¢™Kšœ(™(™K™Kšœ™Kšœ™Kšœ ¢œ™K™ š¢œ$¢œ™,Kšœ<™Kšœ™Kšœ™Kšœ™Kšœ™K™—šžœ¢œ¢œ ™GK™2Kšœ¢œ™-š ¢œ¢œ¢œ"¢œ¢œ¢™FJš¢œ¢œ¢œ'™?Jš¢œ™—K™—K™—Nšœ˜Nšœ˜šœ˜š žœ¢œ¢œ¢œ¢œ ¢œ™XK™IKšœ¢œ¢œ™Kšœ/™/Kšœ,œ™1Kšœ3™3š¢œj¢œ¢œ¢™€KšœJ™JKš¢œ™—Kšœ,œ™4š¢œj¢œ¢œ¢™€Kš¢œ¢œ3¢œK™ˆKš¢œ™—K™K™—šžœ¢œW¢œ™Kšœ™J™"Jšœ™Jš¢œ¢œ¢œ¢œ™/š ¢œ¢œ¢œ0¢œ¢œ¢™TKšœ™Kšœ?™?Kšœ9™9Kš œ¢œ ¢œ¢œ¢œ¢œ™;Kš œ ¢œ¢œ¢œ ¢œ¢œ™2Kšœo¢œ™…Kš¢œ™—K™K™—š žœ¢œ¢œ.¢œ¢œ¢œ™–Kšœ†™†Kšœk™kš¢œ ¢œ¢™Kšœ™Kšœ™Kš¢œ™—K™K™—š žœ¢œ¢œ.¢œ¢œ¢œ™K™ÀKš¼™¼Kšœ¢œ¢œ™Kšœ"™"Kšœ'¢œ™+Kšœ™Kšœ~™~Kšœz™zš¢œ ¢œ¢™šœ™Kšœ(¢œ™,Kš¢œ¢œ¢œ£™?Kšœ%™%š¢œ ¢œ™K–)[traj: GGModelTypes.Traj, index: NAT]š ¢œ'¢œ¢œ¢œ¢œ£™„š¢œ£™&Kšœ™Kšœ8™8Kšœ™—K™—Kš¢œ¢œ ¢œ ¢œ™Aš¢œ¢œ™K–)[traj: GGModelTypes.Traj, index: NAT]š ¢œ)¢œ¢œ¢œ¢œ£™Žš¢œ£™&Kšœ™Kšœ<™K™K™—šžœ¢ œ$¢œ™fJ™(J™ÀKš¢œ¢œ¢œF™nKš¢œ4™8J™J™——Nšœ˜Nšœ˜Nšœ˜Nšœ˜Nšœ˜Nšœ˜Nšœ˜Nšœ˜Nšœ˜šœ˜šž œ¢œ™&Kšœæ™æKšœ&™&Kšœ¢œ)™@Kšœb™bK™KšœS™SKšœ™K™———…—*ê•€