DIRECTORY BasicTime, GGBasicTypes, GGBoundBox, GGInterfaceTypes, GGModelTypes, GGOutline, GGParent, GGScene, GGSceneType, GGSegmentTypes, GGSelect, GGSlice, GGSliceOps, GGTraj, GGUtility, Imager, ImagerPath, Rope, TextNode; GGSceneImpl: CEDAR MONITOR IMPORTS BasicTime, GGBoundBox, GGOutline, GGParent, GGScene, GGSelect, GGSlice, GGSliceOps, GGTraj, GGUtility, Imager EXPORTS GGScene, GGModelTypes = BEGIN BoundBox: TYPE = GGModelTypes.BoundBox; BoundBoxGenerator: TYPE = GGModelTypes.BoundBoxGenerator; BoundBoxGeneratorObj: TYPE = GGModelTypes.BoundBoxGeneratorObj; Camera: TYPE = GGModelTypes.Camera; CameraObj: TYPE = GGModelTypes.CameraObj; Color: TYPE = Imager.Color; CurveType: TYPE = {line, bezier, conic}; FeatureCycler: TYPE = GGInterfaceTypes.FeatureCycler; GGData: TYPE = GGInterfaceTypes.GGData; Joint: TYPE = GGSegmentTypes.Joint; JointGenerator: TYPE = GGModelTypes.JointGenerator; JointGeneratorObj: TYPE = GGModelTypes.JointGeneratorObj; JointObj: TYPE = GGSegmentTypes.JointObj; OutlineData: TYPE = GGOutline.OutlineData; Point: TYPE = GGBasicTypes.Point; Scene: TYPE = GGModelTypes.Scene; SceneObj: PUBLIC TYPE = GGSceneType.SceneObj; -- export of opaque type SelectedData: PUBLIC TYPE = GGSceneType.SelectedData; -- export of opaque type SelectionClass: TYPE = GGSegmentTypes.SelectionClass; Segment: TYPE = GGModelTypes.Segment; SegmentGenerator: TYPE = GGModelTypes.SegmentGenerator; SegmentObj: TYPE = GGSegmentTypes.SegmentObj; Slice: TYPE = GGModelTypes.Slice; SliceParts: TYPE = GGModelTypes.SliceParts; SlicePartsWalkProc: TYPE = GGModelTypes.SlicePartsWalkProc; SliceDescriptor: TYPE = GGModelTypes.SliceDescriptor; SliceDescriptorGenerator: TYPE = GGModelTypes.SliceDescriptorGenerator; SliceDescriptorWalkProc: TYPE = GGModelTypes.SliceDescriptorWalkProc; SliceGenerator: TYPE = GGModelTypes.SliceGenerator; SliceGeneratorObj: TYPE = GGModelTypes.SliceGeneratorObj; SliceWalkProc: TYPE = GGScene.SliceWalkProc; Traj: TYPE = GGModelTypes.Traj; TrajData: TYPE = GGModelTypes.TrajData; TrajParts: TYPE = GGModelTypes.TrajParts; TrajEnd: TYPE = GGModelTypes.TrajEnd; -- {lo, hi}; Vector: TYPE = GGBasicTypes.Vector; WalkLevel: TYPE = GGModelTypes.WalkLevel; Problem: PUBLIC SIGNAL [msg: Rope.ROPE] = CODE; CreateScene: PUBLIC PROC [entities: LIST OF Slice ¬ NIL] RETURNS [scene: Scene] = { scene ¬ NEW[SceneObj ¬ [entities: entities, prioritiesValid: FALSE, backgroundColor: Imager.white] ]; scene.lastEditTime ¬ BasicTime.ExtendedNow[]; }; SetScene: PUBLIC PROC [from: Scene, to: Scene] = { to2: REF SceneObj ¬ NARROW[to]; from1: REF SceneObj ¬ NARROW[from]; to2­ ¬ from1­; }; CreateDefaultCamera: PUBLIC PROC [] RETURNS [camera: Camera] = { camera ¬ NEW[CameraObj]; }; AddSlice: PUBLIC PROC [scene: Scene, slice: Slice, priority: INT ¬ -1] = { IF slice=NIL THEN RETURN; slice.parent ¬ NIL; IF priority = -1 OR TopPriority[scene] RETURN; -- entity already on bottom preprev=NIL AND previous#NIL => { -- special case. Second from bottom previous.rest ¬ list.rest; list.rest ¬ previous; scene.entities ¬ list; RETURN; }; preprev#NIL AND previous=NIL => ERROR; -- Assert: can't happen preprev#NIL AND previous#NIL => { -- usual case. Exchange list elements previous.rest ¬ list.rest; list.rest ¬ previous; preprev.rest ¬ list; RETURN; }; ENDCASE => ERROR; -- Assert: can't happen } ELSE { preprev ¬ previous; previous ¬ list; }; ENDLOOP; }; scene.ptrValid ¬ scene.prioritiesValid ¬ FALSE; ExchangeWithPreviousEntity[scene, slice]; }; PutBehind: PUBLIC PROC [scene: Scene, slice: Slice, slices: LIST OF Slice] = { IF slice#NIL AND slices#NIL THEN { beforeEnt, ent, afterEnt, slicesRest: LIST OF Slice; found: BOOL ¬ FALSE; [beforeEnt, ent, afterEnt, found] ¬ GGUtility.FindSliceAndNeighbors[slice, scene.entities]; IF found THEN { IF ent.first#slice THEN ERROR; -- debugging test scene.ptrValid ¬ FALSE; scene.prioritiesValid ¬ FALSE; IF beforeEnt#NIL THEN beforeEnt.rest ¬ slices ELSE scene.entities ¬ slices; -- beforeEnt is really part of scene.entities. Splice in new slices before the existing slice FOR sList: LIST OF Slice ¬ slices, sList.rest UNTIL sList=NIL DO slicesRest ¬ sList; ENDLOOP; slicesRest.rest ¬ ent; -- add on the original slice and the remaining entities }; }; }; ReplaceSlice: PUBLIC PROC [scene: Scene, slice: Slice, slices: LIST OF Slice] = { beforeEnt, ent, afterEnt, slicesRest: LIST OF Slice; found: BOOL ¬ FALSE; IF slice#NIL AND slices#NIL THEN { [beforeEnt, ent, afterEnt, found] ¬ GGUtility.FindSliceAndNeighbors[slice, scene.entities]; IF found THEN { IF ent.first#slice THEN ERROR; -- debugging test scene.ptrValid ¬ FALSE; scene.prioritiesValid ¬ FALSE; IF beforeEnt#NIL THEN beforeEnt.rest ¬ slices ELSE scene.entities ¬ slices; -- beforeEnt is really part of scene.entities. Splice in new slices before the existing slice FOR sList: LIST OF Slice ¬ slices, sList.rest UNTIL sList=NIL DO slicesRest ¬ sList; ENDLOOP; slicesRest.rest ¬ afterEnt; }; }; }; PutAtPriority: PUBLIC PROC [scene: Scene, slice: Slice, priority: INT ¬ -1] = { RemoveSlice[scene, slice]; AddSlice[scene, slice, priority]; }; GetAtPriority: PUBLIC PROC [scene: Scene, priority: INT] RETURNS [slice: Slice] = { IF NOT scene.prioritiesValid THEN UpdatePriorities[scene]; IF priority = -1 THEN { -- special case: frontmost IF NOT scene.ptrValid THEN UpdatePtr[scene]; RETURN[scene.ptr.first]; } ELSE IF priority = 0 THEN RETURN[scene.entities.first] -- special case: rear-most ELSE { -- somewhere in the middle count: INT ¬ 1; FOR sliceList: LIST OF Slice ¬ scene.entities.rest, sliceList.rest UNTIL sliceList=NIL DO IF count=priority THEN RETURN[sliceList.first]; count ¬ count+1; ENDLOOP; IF NOT scene.ptrValid THEN UpdatePtr[scene]; RETURN[scene.ptr.first]; }; }; DeleteAtPriority: PUBLIC PROC [scene: Scene, priority: INT] RETURNS [deleted: Slice] = { deleted ¬ GetAtPriority[scene, priority]; DeleteSlice[scene, deleted]; }; RemoveSlice: PUBLIC PROC [scene: Scene, slice: Slice] = { scene.ptrValid ¬ FALSE; scene.prioritiesValid ¬ FALSE; scene.entities ¬ GGUtility.DeleteSliceFromList[slice, scene.entities]; }; DeleteSlice: PUBLIC PROC [scene: Scene, slice: Slice] = { scene.ptrValid ¬ FALSE; scene.prioritiesValid ¬ FALSE; GGSelect.DeselectEntityAllClasses[slice, scene]; scene.entities ¬ GGUtility.DeleteSliceFromList[slice, scene.entities]; }; DeleteSequence: PUBLIC PROC [seq: SliceDescriptor, scene: Scene] RETURNS [oldOutline: Slice, newOutlines: LIST OF Slice] = { priority: INT; traj: Slice ¬ seq.slice; smallerOutline: Slice; oldOutline ¬ GGParent.GetParent[traj]; GGOutline.SaveSelectionsInOutlineAllClasses[oldOutline]; priority ¬ GGScene.GetPriority[scene, oldOutline]; [smallerOutline, newOutlines] ¬ GGTraj.DeleteSequence[seq]; IF smallerOutline # NIL THEN newOutlines ¬ CONS[smallerOutline, newOutlines]; IF newOutlines#NIL THEN AddSlices[scene, newOutlines, priority]; DeleteSlice[scene, oldOutline]; FOR list: LIST OF Slice ¬ newOutlines, list.rest UNTIL list = NIL DO GGSelect.ReselectSliceAllClasses[list.first, scene]; ENDLOOP; }; OutlinesFromOutlineExcept: PROC [outline: Slice, except: Traj] RETURNS [newOutlines: LIST OF Slice] = { ptr: LIST OF Slice; newSlice, newOutline: Slice; children: LIST OF Slice ¬ NARROW[outline.data, OutlineData].children; [newOutlines, ptr] ¬ GGUtility.StartSliceList[]; FOR childList: LIST OF Slice ¬ children, childList.rest UNTIL childList = NIL DO IF childList.first = except THEN LOOP; newSlice ¬ GGSliceOps.Copy[childList.first].first; newOutline ¬ GGOutline.CreateOutline[newSlice, GGSliceOps.GetFillColor[outline, NIL].color]; [newOutlines, ptr] ¬ GGUtility.AddSlice[newOutline, newOutlines, ptr]; ENDLOOP; }; noGarbage: BOOL ¬ FALSE; MakeSceneGarbage: PUBLIC PROC [scene: Scene] = { oldEntities: LIST OF LIST OF Slice; entities: LIST OF Slice; IF noGarbage THEN RETURN; oldEntities ¬ scene.oldEntities; scene.oldEntities ¬ NIL; entities ¬ scene.entities; scene.entities ¬ NIL; -- in case a screen refresh is attempted while we are doing this. FOR sllist: LIST OF LIST OF Slice ¬ oldEntities, sllist.rest UNTIL sllist=NIL DO FOR list: LIST OF Slice ¬ sllist.first, list.rest UNTIL list=NIL DO IF list.first.class#NIL THEN GGSliceOps.Unlink[list.first]; -- if class=NIL, already unlinked ENDLOOP; ENDLOOP; FOR list: LIST OF Slice ¬ entities, list.rest UNTIL list=NIL DO IF list.first.class#NIL THEN GGSliceOps.Unlink[list.first]; -- if class=NIL, already unlinked ENDLOOP; }; MergeScenes: PUBLIC PROC [back: Scene, front: Scene] RETURNS [combined: Scene] = { combined ¬ NEW[SceneObj ¬ [prioritiesValid: FALSE, backgroundColor: back.backgroundColor]]; combined.entities ¬ GGUtility.AppendSliceList[back.entities, front.entities]; combined.selected.normal ¬ GGUtility.AppendSliceDescriptorList[back.selected.normal, front.selected.normal]; combined.selected.hot ¬ GGUtility.AppendSliceDescriptorList[back.selected.hot, front.selected.hot]; combined.selected.active ¬ GGUtility.AppendSliceDescriptorList[back.selected.active, front.selected.active]; combined.selected.match ¬ GGUtility.AppendSliceDescriptorList[back.selected.match, front.selected.match]; }; WalkSlices: PUBLIC PROC [scene: Scene, level: WalkLevel, walkProc: SliceWalkProc, classType: ATOM ¬ NIL] RETURNS [aborted: BOOL ¬ FALSE] = { FOR slices: LIST OF Slice ¬ scene.entities, slices.rest UNTIL slices = NIL DO thisType: ATOM ¬ GGSliceOps.GetType[slices.first]; IF (level # leaf OR GGParent.IsLeafOfClass[slices.first, classType]) AND (classType = NIL OR thisType = classType) THEN { aborted ¬ walkProc[slices.first]; IF aborted THEN RETURN; }; IF (level = all OR level = leaf OR (level = highest AND thisType # classType)) AND GGParent.IsParent[slices.first] THEN { aborted ¬ GGParent.WalkChildren[slices.first, level, walkProc, classType]; IF aborted THEN RETURN; }; ENDLOOP; }; WalkSelectedSlices: PUBLIC PROC [scene: Scene, level: WalkLevel, walkProc: SliceDescriptorWalkProc, selectClass: SelectionClass, classType: ATOM ¬ NIL] RETURNS [aborted: BOOL ¬ FALSE] = { FOR list: LIST OF SliceDescriptor ¬ GGSelect.ListSelected[scene, selectClass], list.rest UNTIL list = NIL DO thisSlice: Slice ¬ list.first.slice; thisParts: SliceParts ¬ list.first.parts; thisType: ATOM ¬ GGSliceOps.GetType[thisSlice]; IF (classType = NIL OR thisType = classType) AND (level # leaf OR GGParent.IsLeafOfClass[thisSlice, classType]) THEN { aborted ¬ walkProc[list.first]; IF aborted THEN RETURN; }; IF (level = all OR level = leaf OR (level = highest AND thisType # classType)) AND GGParent.IsParent[thisSlice] THEN { aborted ¬ GGParent.WalkIncludedChildren[thisSlice, thisParts, level, walkProc, classType]; IF aborted THEN RETURN; }; ENDLOOP; }; ListSlices: PUBLIC PROC [scene: Scene, level: WalkLevel, classType: ATOM ¬ NIL] RETURNS [sliceList: LIST OF Slice] = { ptr: LIST OF Slice; DoAppendSlice: PROC [slice: Slice] RETURNS [done: BOOL ¬ FALSE] = { [sliceList, ptr] ¬ GGUtility.AddSlice[slice, sliceList, ptr]; }; [sliceList, ptr] ¬ GGUtility.StartSliceList[]; [] ¬ WalkSlices[scene, level, DoAppendSlice, classType]; }; ListSelectedSlices: PUBLIC PROC [scene: Scene, level: WalkLevel, selectClass: SelectionClass, classType: ATOM ¬ NIL] RETURNS [selectedList: LIST OF SliceDescriptor] = { ptr: LIST OF SliceDescriptor; DoAppendSlice: PROC [childD: SliceDescriptor] RETURNS [done: BOOL ¬ FALSE] = { [selectedList, ptr] ¬ GGUtility.AddSliceDescriptor[childD, selectedList, ptr]; }; [selectedList, ptr] ¬ GGUtility.StartSliceDescriptorList[]; [] ¬ WalkSelectedSlices[scene, level, DoAppendSlice, selectClass, classType]; }; CountSlices: PUBLIC PROC [scene: Scene, level: WalkLevel, classType: ATOM ¬ NIL] RETURNS [count: INT ¬ 0] = { AddEmUp: PROC [child: Slice] RETURNS [done: BOOL ¬ FALSE] = { count ¬ count + 1; }; [] ¬ WalkSlices[scene, level, AddEmUp, classType]; }; CountSelectedSlices: PUBLIC PROC [scene: Scene, level: WalkLevel, selectClass: SelectionClass, classType: ATOM ¬ NIL] RETURNS [count: INT ¬ 0] = { AddEmUp: PROC [childD: SliceDescriptor] RETURNS [done: BOOL ¬ FALSE] = { count ¬ count + 1; }; [] ¬ WalkSelectedSlices[scene, level, AddEmUp, selectClass, classType]; }; FirstSelectedSlice: PUBLIC PROC [scene: Scene, level: WalkLevel, selectClass: SelectionClass, classType: ATOM ¬ NIL] RETURNS [sliceD: SliceDescriptor] = { StopAtFirstSlice: PROC [childD: SliceDescriptor] RETURNS [done: BOOL ¬ FALSE] = { sliceD ¬ childD; RETURN[TRUE]; }; [] ¬ WalkSelectedSlices[scene, level, StopAtFirstSlice, selectClass, classType]; }; LastSelectedSlice: PUBLIC PROC [scene: Scene, level: WalkLevel, selectClass: SelectionClass, classType: ATOM ¬ NIL] RETURNS [sliceD: SliceDescriptor] = { StopAtLastSlice: PROC [childD: SliceDescriptor] RETURNS [done: BOOL ¬ FALSE] = { sliceD ¬ childD; }; [] ¬ WalkSelectedSlices[scene, level, StopAtLastSlice, selectClass, classType]; }; IsTopLevel: PUBLIC PROC [slice: Slice] RETURNS [BOOL] = { RETURN[slice.parent = NIL]; }; BoundBoxesInScene: PUBLIC PROC [scene: Scene] RETURNS [bBoxGen: BoundBoxGenerator] = { list: LIST OF BoundBox; thisBox: BoundBox; FOR entities: LIST OF Slice ¬ scene.entities, entities.rest UNTIL entities = NIL DO IF GGSliceOps.GetType[entities.first]=$Outline THEN { -- multiple bound boxes wanted outlineData: OutlineData ¬ NARROW[entities.first.data]; FOR children: LIST OF Slice ¬ outlineData.children, children.rest UNTIL children=NIL DO thisBox ¬ GGSliceOps.GetBoundBox[children.first, NIL]; list ¬ CONS[thisBox, list]; ENDLOOP; } ELSE { thisBox ¬ GGSliceOps.GetBoundBox[entities.first, NIL]; list ¬ CONS[thisBox, list]; }; ENDLOOP; bBoxGen ¬ NEW[BoundBoxGeneratorObj ¬ [ list: list ]]; }; TightBoxesInScene: PUBLIC PROC [scene: Scene] RETURNS [bBoxGen: BoundBoxGenerator] = { list: LIST OF BoundBox; thisBox: BoundBox; FOR entities: LIST OF Slice ¬ scene.entities, entities.rest UNTIL entities = NIL DO thisBox ¬ GGSliceOps.GetTightBox[entities.first, NIL]; list ¬ CONS[thisBox, list]; ENDLOOP; bBoxGen ¬ NEW[BoundBoxGeneratorObj ¬ [ list: list ]]; }; NextBox: PUBLIC PROC [g: BoundBoxGenerator] RETURNS [next: BoundBox] = { IF g.list = NIL THEN RETURN[NIL] ELSE { next ¬ g.list.first; g.list ¬ g.list.rest; }; }; BoundBoxOfScene: PUBLIC PROC [scene: Scene] RETURNS [bBox: BoundBox] = { bbGen: GGModelTypes.BoundBoxGenerator ¬ BoundBoxesInScene[scene]; bBox ¬ GGBoundBox.BoundBoxOfBoxes[bbGen.list]; -- cheating to go inside generator }; TightBoxOfScene: PUBLIC PROC [scene: Scene] RETURNS [bBox: BoundBox] = { bbGen: GGModelTypes.BoundBoxGenerator ¬ TightBoxesInScene[scene]; bBox ¬ GGBoundBox.BoundBoxOfBoxes[bbGen.list]; -- cheating to go inside generator }; SelectionBoxOfSelected: PUBLIC PROC [scene: Scene, selectClass: SelectionClass ¬ normal, full: BOOL ¬ FALSE] RETURNS [bigBox: BoundBox] = { nextBox: BoundBox; DoEnlargeBox: PROC [sliceD: SliceDescriptor] RETURNS [done: BOOL ¬ FALSE] = { nextBox ¬ IF GGSliceOps.GetType[sliceD.slice]=$Text THEN GGSliceOps.GetTightBox[sliceD.slice, IF full THEN NIL ELSE sliceD.parts] ELSE GGSliceOps.GetBoundBox[sliceD.slice, IF full THEN NIL ELSE sliceD.parts]; GGBoundBox.EnlargeByBox[bBox: bigBox, by: nextBox]; }; bigBox ¬ GGBoundBox.NullBoundBox[]; [] ¬ GGScene.WalkSelectedSlices[scene, first, DoEnlargeBox, selectClass]; }; BoundBoxOfSelected: PUBLIC PROC [scene: Scene, selectClass: SelectionClass ¬ normal, sliceLevel: BOOL ¬ FALSE] RETURNS [bigBox: BoundBox] = { nextBox: BoundBox; DoEnlargeBox: PROC [sliceD: SliceDescriptor] RETURNS [done: BOOL ¬ FALSE] = { nextBox ¬ GGSliceOps.GetBoundBox[sliceD.slice, IF sliceLevel THEN NIL ELSE sliceD.parts]; GGBoundBox.EnlargeByBox[bBox: bigBox, by: nextBox]; }; bigBox ¬ GGBoundBox.NullBoundBox[]; [] ¬ GGScene.WalkSelectedSlices[scene, first, DoEnlargeBox, selectClass]; }; TightBoxOfSelected: PUBLIC PROC [scene: Scene, selectClass: SelectionClass ¬ normal, sliceLevel: BOOL ¬ FALSE] RETURNS [bigBox: BoundBox] = { nextBox: BoundBox; DoEnlargeBox: PROC [sliceD: SliceDescriptor] RETURNS [done: BOOL ¬ FALSE] = { nextBox ¬ GGSliceOps.GetTightBox[sliceD.slice, IF sliceLevel THEN NIL ELSE sliceD.parts]; GGBoundBox.EnlargeByBox[bBox: bigBox, by: nextBox]; }; bigBox ¬ GGBoundBox.NullBoundBox[]; [] ¬ GGScene.WalkSelectedSlices[scene, first, DoEnlargeBox, selectClass]; }; useSelected: BOOL ¬ FALSE; BoundBoxOfMoving: PUBLIC PROC [scene: Scene, editConstraints: GGModelTypes.EditConstraints, bezierDrag: GGInterfaceTypes.BezierDragRecord, selectClass: SelectionClass ¬ normal] RETURNS [bigBox: BoundBox] = { nextBox: BoundBox; DoEnlargeBox: PROC [sliceD: SliceDescriptor] RETURNS [done: BOOL ¬ FALSE] = { overlay, rubber, drag, movingParts: SliceDescriptor; [----, overlay, rubber, drag] ¬ GGSliceOps.MovingParts[sliceD.slice, sliceD.parts, editConstraints, bezierDrag]; movingParts ¬ GGSliceOps.UnionParts[overlay, rubber]; movingParts ¬ GGSliceOps.UnionParts[movingParts, drag]; nextBox ¬ GGSliceOps.GetBoundBox[sliceD.slice, movingParts.parts]; GGBoundBox.EnlargeByBox[bBox: bigBox, by: nextBox]; }; IF useSelected THEN RETURN[BoundBoxOfSelected[scene, selectClass]]; bigBox ¬ GGBoundBox.NullBoundBox[]; [] ¬ GGScene.WalkSelectedSlices[scene, first, DoEnlargeBox, selectClass]; }; DeleteAllSelected: PUBLIC PROC [scene: Scene] RETURNS [bBox: BoundBox] = { DeleteTopLevel: PROC [topLevelD: SliceDescriptor] RETURNS [done: BOOL ¬ FALSE] = { IF GGSliceOps.IsCompleteParts[topLevelD] THEN { affectedBox ¬ GGSliceOps.GetBoundBox[topLevelD.slice, NIL]; DeleteSlice[scene, topLevelD.slice]; -- fast case } ELSE { newSlices: LIST OF Slice; priority: INT ¬ GetPriority[scene, topLevelD.slice]; GGSelect.SaveSelectionsInSliceAllClasses[topLevelD.slice, scene]; [newSlices, affectedBox] ¬ DeleteSliceParts[topLevelD]; DeleteSlice[scene, topLevelD.slice]; AddSlices[scene, newSlices, priority]; FOR list: LIST OF Slice ¬ newSlices, list.rest UNTIL list = NIL DO GGSelect.ReselectSliceAllClasses[list.first, scene]; GGSelect.DeselectEntireSlice[list.first, scene, active]; -- do this in case some active selections remain for parts which were not deleted. This fixes a problem when a control point is selected (not a joint) and DEL is invoked but the CP is not deleted. ENDLOOP; }; GGBoundBox.EnlargeByBox[bBox, affectedBox]; }; affectedBox: BoundBox; bBox ¬ GGScene.BoundBoxOfSelected[scene, normal]; GGSelect.DuplicateSelections[scene, normal, active]; [] ¬ GGScene.WalkSelectedSlices[scene, first, DeleteTopLevel, active]; }; DeleteSliceParts: PROC [sliceD: SliceDescriptor] RETURNS [newSlices: LIST OF Slice, bBox: BoundBox] = { bBox ¬ GGBoundBox.NullBoundBox[]; SELECT GGSliceOps.GetType[sliceD.slice] FROM $Traj => ERROR; $Cluster => { newChildren: LIST OF Slice; IF GGSliceOps.IsCompleteParts[sliceD] THEN RETURN[NIL, bBox]; FOR children: LIST OF Slice _ GGParent.ListChildren[sliceD.slice, first], children.rest UNTIL children=NIL DO thisChild: Slice _ children.first; -- the next child, also possibly a cluster thisChildD: SliceDescriptor ¬ GGParent.ChildDescriptorFromDescriptor[sliceD, thisChild]; IF thisChildD=NIL OR GGSliceOps.IsEmptyParts[thisChildD] THEN newChildren ¬ GGUtility.AppendSliceList[newChildren, LIST[thisChild]] ELSE { newBox: BoundBox; newChildSlices: LIST OF Slice; [newChildSlices, newBox] ¬ DeleteSliceParts[thisChildD]; -- RECURSIVE CALL IF newChildSlices#NIL THEN { newChildren ¬ GGUtility.AppendSliceList[newChildren, newChildSlices]; GGBoundBox.EnlargeByBox[bBox: bBox, by: newBox]; }; }; ENDLOOP; IF newChildren=NIL THEN RETURN[NIL, bBox] ELSE { newCluster: Slice ¬ GGSlice.CreateCluster[frozen: GGSlice.GetFrozen[sliceD.slice]]; GGSlice.AddChildrenToCluster[newCluster, newChildren, -1]; RETURN[LIST[newCluster], bBox]; }; }; $Outline => { thisBox: BoundBox; childD: SliceDescriptor; outlineParts: SliceParts; original, outline: Slice; openTrajOutlines: LIST OF Slice; original ¬ sliceD.slice; outlineParts ¬ sliceD.parts; outline ¬ sliceD.slice; -- gets smaller with each iteration childD ¬ GGParent.FirstIncludedChild[outline, outlineParts, first]; UNTIL childD = NIL DO IF GGSliceOps.GetType[childD.slice] = $Traj THEN { IF GGSliceOps.IsCompleteParts[childD] THEN { outline ¬ GGOutline.ReplaceChild[outline, childD.slice, NIL]; } ELSE { [outline, openTrajOutlines] ¬ GGTraj.DeleteSequence[childD]; newSlices ¬ GGUtility.AppendSliceList[openTrajOutlines, newSlices]; }; } ELSE { -- $Box or $Circle screenStyle: BOOL ¬ TRUE; fillText: TextNode.Location; GGBoundBox.EnlargeByBox[bBox: bBox, by: GGSliceOps.GetBoundBox[outline]]; [fillText, screenStyle] ¬ GGSlice.GetBoxText[outline]; outline ¬ GGOutline.ReplaceChild[outline, childD.slice, NIL]; IF outline # NIL THEN GGOutline.SetFillText[outline, fillText.node, screenStyle, NIL]; }; IF outline = NIL THEN childD ¬ NIL ELSE { outlineParts ¬ GGSliceOps.RemakeSelections[outline, active]; childD ¬ GGParent.FirstIncludedChild[outline, outlineParts, first]; }; ENDLOOP; IF outline # NIL THEN newSlices ¬ CONS[outline, newSlices]; -- filled outline backmost thisBox ¬ BoundBoxOfSlices[newSlices]; GGBoundBox.EnlargeByBox[bBox: bBox, by: thisBox]; }; ENDCASE => { newSlices ¬ NIL; }; }; BoundBoxOfSlices: PROC [sliceList: LIST OF Slice] RETURNS [bBox: BoundBox] = { bBox ¬ GGBoundBox.NullBoundBox[]; FOR list: LIST OF Slice ¬ sliceList, list.rest UNTIL list = NIL DO GGBoundBox.EnlargeByBox[bBox: bBox, by: GGSliceOps.GetBoundBox[list.first, NIL]]; ENDLOOP; }; SaveSelections: PUBLIC PROC [scene: Scene] = { scene.savedSelected.normal ¬ GGUtility.CopySliceDescriptorList[scene.selected.normal]; scene.savedSelected.featureCycler ¬ scene.selected.featureCycler; }; RestoreSelections: PUBLIC PROC [scene: Scene] = { GGSelect.DeselectAll[scene, normal]; -- get rid of any transient selections FOR list: LIST OF SliceDescriptor ¬ scene.savedSelected.normal, list.rest UNTIL list = NIL DO GGSelect.SelectSlice[list.first, scene, normal]; ENDLOOP; scene.selected.featureCycler ¬ scene.savedSelected.featureCycler; }; SelectInBox: PUBLIC PROC [scene: Scene, box: BoundBox, selectClass: SelectionClass ¬ normal] = { SelectSlice: PROC [slice: Slice] RETURNS [done: BOOL ¬ FALSE] = { IF GGSliceOps.WithinBoundBox[slice, box] THEN GGSelect.SelectEntireSlice[slice, scene, selectClass]; }; [] ¬ GGScene.WalkSlices[scene, first, SelectSlice]; }; SelectPartsInBox: PUBLIC PROC [scene: Scene, box: BoundBox, selectClass: SelectionClass ¬ normal] = { inParts: SliceDescriptor; SelectSliceParts: PROC [slice: Slice] RETURNS [done: BOOL ¬ FALSE] = { inParts ¬ GGSliceOps.PartsInBoundBox[slice, box]; IF inParts # NIL THEN GGSelect.SelectSlice[inParts, scene, selectClass]; }; [] ¬ GGScene.WalkSlices[scene, first, SelectSliceParts]; }; <> END. † GGSceneImpl.mesa Contents: The procedural interface to the Gargoyle object modeler. Copyright Σ 1985, 1988, 1992 by Xerox Corporation. All rights reserved. Stone, August 5, 1985 4:13:18 pm PDT Pier, January 14, 1993 1:25 pm PST Kurlander August 28, 1986 6:15:29 pm PDT Bier, February 5, 1993 3:27 pm PST The scene object has a list of entities, a "finger" REF (ptr) to the end of the list for quick appends, and a BOOL which is TRUE when ptr in fact points to the end. ptr MUST BE invalidated by setting ptrValid _ FALSE whenever a remove or delete is done from the entities. Any use of ptr must check ptrValid and recalculate its value if it is invalid. The only place that happens in here is in AppendEntity. entities are kept in back to front order so that the list can be painted with a single traversal. Creating, Modifying Scenes The list scene.entities is kept in back to front order. Hence, newly added objects are usually added to the end of the list. This list may be mutated freely. Copies of it are made when needed. Add the given slice to the scene with the given priority (the higher the priority number, the closer the slice is to the front of the scene). If priority is -1, the slice will be the front-most entity. If the priority given is too high, we proceed as if priority = -1. Adds the slices, assumed to be in back to front order, to the scene. IF priority = -1, they become the frontmost entities. Otherwise, the specified priority becomes the priority of the first entity in the list, if possible. If the priority given is too high, we proceed as if priority = -1. Copy incoming list to avoid mutations by PutBehind holes should not have parents. May create obsolete sequences, so be careful. Manipulations on Multiple Scenes Copy all parts that are current selectedly in "from" and place the copies in "to" at the frontmost priority. Add all of the new slices to the "to" scene and select them. Priority order If returned priority is 0, the slice is the back-most entity. Returns the priority of the frontmost position in the scene. Moves the named slice one step closer to the front in the priority order. Destructively splices slices into scene Moves the named slice one step closer to the back in the priority order. Destructively splices slices into scene Removes slice from scene and puts back-to-front slices in its place. Destructively splices slices into scene If priority is 0, the slice will be the back-most entity. If priority is -1, the slice will be the front-most entity. If the priority given is too high, we proceed as if priority = -1. or off the scale Ruthlessly destroy an entire scene so the Cedar gargbage collector can sweep up. Browsing the Scene Hierarchy -- Generators Built-in classes include: $Cluster, $Outline, $Traj, $Box, $Circle, $Text, and $IP. This routine finds all such slices, even within clusters. class=NIL => all classes. Use level=all to walk every slice of a given class. Top level classes Depth first walk Built-in classes include: $Cluster, $Outline, $Traj, $Box, $Circle, $Text, and $IP. This routine finds all such slices, even within clusters. class=NIL => all classes. Use level=all to walk every selected slice of a given class. Top level classes Depth first walk Bounding Boxes Generates all of the boundBoxes in the scene, wherever they occur. Generates all of the boundBoxes in the scene, whereever they occur. list: LIST OF BoundBox _ ListTightBoxesInScene[scene]; box is in local IP coordinates box is in local IP coordinates Returns the composite tight box for all selected parts, or all selected slices if sliceLevel=TRUE. routine called to calculate the boundBox of all objects that are about to move; that is, all selected slices, selected CPs, selected joints AND the dangling segments of selected joints AND the segments of selected CPs. In the common case, drag will be the only non-null descriptor. Selections Returns bounding box of area requiring refresh. This is a partially-selected cluster. We will return a single cluster, that differs from the original in that DeleteSliceParts has been recursively applied to all of its children. Unfortunately, we have to leave the original Cluster children list structure intact for purposes of Undo, so we will have to carefully construct a new cluster to return. build a new list of children from old children that are not selected plus modified copies of old children that are selected. Do not change the list structure of the old children in this Cluster. Walk the first level slices in this cluster, building a new list of children. Call DeleteSliceParts recursively. The only legitimate way to walk the old children and build a new child list is to make child descriptors and walk those recursively. ChildDescriptorFromDescriptor will return NIL for an unselected child child is not to be deleted. Put on new list. some piece of child is to be deleted. Recurse. Check for the case that the last child has been removed from the cluster and return NIL if it has. Select all slices that are completely contained within or on the edge of box. Select all slice parts that are completely contained within or on the surface of box. Getting Exclusive Access to a Scene Name is an indication of what you are going to do while you have locked the scene (e.g., $Get, or $Gravity). Locking is provided to prevent the TIP Notify process from performing spatial calculations on a scene while the Slack process is garbage collecting it. Κ1Y–(cedarcode) style•NewlineDelimiter ™code™KšΟnœ;™CKšœ Οeœ=™HKšœ!Οk™$K™"Kšœ%Ÿ™(K™"K™—šŸ ˜ J˜ΥK˜—š œŸœŸ˜JšŸœn˜uKšŸœŸ˜%—˜Kšœ Ÿœ˜'KšœŸœ"˜9KšœŸœ%˜?KšœŸœ˜#Kšœ Ÿœ˜)KšœŸœ˜Kšœ Ÿœ˜(KšœŸœ"˜5KšœŸœ˜'KšœŸœ˜#KšœŸœ˜3KšœŸœ"˜9Kšœ Ÿœ˜)Kšœ Ÿœ˜*KšœŸœ˜!KšœŸœ˜!Kšœ ŸœŸœΟc˜FKšœŸœŸœ ˜NKšœŸœ!˜5Kšœ Ÿœ˜%KšœŸœ!˜7Kšœ Ÿœ˜-KšœŸœ˜!Kšœ Ÿœ˜+KšœŸœ#˜;KšœŸœ ˜5KšœŸœ)˜GKšœŸœ(˜EKšœŸœ˜3KšœŸœ"˜9KšœŸœ˜,KšœŸœ˜Kšœ Ÿœ˜'Kšœ Ÿœ˜)Kšœ Ÿœ  ˜2KšœŸœ˜#Kšœ Ÿœ˜)K˜š œ4Ÿœ7Ÿœ Ÿœ*ŸœŸœ#Ÿœΐ™™K™a—K˜—Kš œŸœŸœ ŸœŸœ˜/K™šœ™K˜KšœΓ™ΓK™—š œŸœŸœ ŸœŸœ ŸœŸœ˜SKšœ Ÿœ2Ÿœ#˜fK˜-K˜K˜—šœŸœŸœ˜3KšœŸœ Ÿœ˜KšœŸœ Ÿœ˜#K˜K˜K˜—šœŸœŸœŸœ˜@Kšœ Ÿœ ˜K˜K˜—šœŸœŸœ(Ÿœ ˜JKšœŽ™ŽKšŸœŸœŸœŸœ˜KšœŸœ˜KšŸœŸœŸœ˜NšŸœŸœŸœ˜KšœŸœ˜KšœŸœ˜KšœŸœ˜-K˜—KšŸœ2Ÿœ ˜CK˜K˜—š  œŸœŸœŸœŸœŸœ ˜TKšœFŸœέ™₯KšŸœŸœŸœŸœ˜š ŸœŸœŸœŸœŸœŸ˜?KšœŸœ˜KšŸœ˜—šŸœŸœŸœ˜6š ŸœŸœŸœŸœŸœŸ˜?Kšœ˜KšŸœ˜—K˜—šŸœŸœŸœ˜KšœŸœ˜KšœŸœ˜KšœD ˜\K˜—šŸœ˜Kšœ2™2KšœŸœŸœ)˜>Kšœ?˜?K˜—K˜K˜—šœŸœŸœ-Ÿœ˜\K˜.K•StartOfExpansion:[scene: GGModelTypes.Scene, slice: GGModelTypes.Slice]šœ Ÿœ-˜:KšŸœŸœŸœ˜$K˜+Kš œŸœ ŸœŸœŸœ˜BKšœ˜Kšœ"˜"K˜K˜—š  œŸœŸœŸœŸœ ˜CK™MKšœŸœ˜0š Ÿœ ŸœŸœŸœ ŸœŸ˜HKšœGŸœ˜]K˜ KšŸœ*Ÿœ*˜ZKšŸœ˜—Kšœ˜K˜K˜—š œŸœ!˜2KšœŸœ˜KšŸœŸœŸœ˜,K˜SK˜K˜—š œŸœ˜"Kš ŸœŸœŸœ ŸœŸ˜/š ŸœŸœŸœ#ŸœŸœŸ˜EK˜KšŸœ˜—KšœŸœ˜Kšœ˜K˜—šœŸœŸœ!˜@K˜K˜—šœŸœŸœŸœ˜IK˜K˜—šœŸœŸœ0˜NK˜K˜—šœŸœŸœŸœ"˜WK˜K˜—K˜™ K™—šœŸœŸœ$Ÿœ ŸœŸœ Ÿœ˜nKšœl™lš  œŸœŸœŸœŸœ˜NKšœŸœŸœ5˜Dš ŸœŸœŸœŸœŸœŸ˜?K˜CK˜BKšŸœ˜—Kšœ˜—KšœŸœŸœ Ÿœ˜Kšœ0Οtœ ‘œ‘˜IKšœ: $˜^Kšœ&˜&JšΟb<™<š Ÿœ ŸœŸœ#Ÿœ ŸœŸ˜QKšœ/˜/Kšœ=˜=KšŸœ˜—K˜K˜—™K™—šœŸœ˜)š œŸœŸœŸœŸœ˜>K˜K˜K˜—KšœŸœ˜Kšœ$‘œ‘˜0KšœŸœ˜Kšœ˜K˜—š  œŸœŸœŸœ Ÿœ˜QKšœ=™=KšŸœŸœŸœ˜:K˜K˜K˜—š  œŸœŸœŸœ Ÿœ˜CKšœ<™K˜K˜—šœŸœŸœ!˜3KšœI™IšœŸœ!˜=KšœŸœŸœ Ÿœ˜$š ŸœŸœŸœ#ŸœŸœŸ˜GšŸœŸœ .˜IK˜Kš ŸœŸœŸœŸœ +˜DK˜)KšŸœ ŸœŸœŸœ˜EK˜—KšŸœ˜KšŸœ˜—K˜—Kšœ)Ÿœ˜/Kšœ%˜%K˜K˜—š  œŸœŸœ&ŸœŸœ ˜OKšœ'™'š ŸœŸœŸœŸœŸœ˜"Kšœ&ŸœŸœ˜4KšœŸœŸœ˜K˜[šŸœŸœ˜KšŸœŸœŸœ ˜0KšœŸœ˜KšœŸœ˜Kšœ W˜jš ŸœŸœŸœŸœŸœŸ˜@K˜KšŸœ˜—K˜K˜—K˜—K˜K˜—šœŸœŸœ!˜5KšœH™HšœŸœ!˜AKšœŸœŸœ Ÿœ˜'š ŸœŸœŸœ#ŸœŸœŸ˜EšŸœŸœ 2˜MšŸœŸœŸ˜Kš œŸœŸœ ŸœŸœ ˜DšœŸœŸœ Ÿœ #˜EKšœIŸœ˜PK˜—Kš œŸœŸœ ŸœŸœ ˜>šœŸœŸœ Ÿœ %˜GKšœHŸœ˜OKšœ˜—KšŸœŸœ ˜)—K˜—KšŸœ+˜/KšŸœ˜—K˜—Kšœ)Ÿœ˜/Kšœ)˜)K˜K˜—š  œŸœŸœ&ŸœŸœ ˜NKšœ'™'š ŸœŸœŸœŸœŸœ˜"Kšœ&ŸœŸœ˜4KšœŸœŸœ˜K˜[šŸœŸœ˜KšŸœŸœŸœ ˜0KšœŸœ˜KšœŸœ˜Kš Ÿœ ŸœŸœŸœ ]˜©š ŸœŸœŸœŸœŸœŸ˜@K˜KšŸœ˜—Kšœ 7˜NK˜—Kšœ˜—Kšœ˜K˜—š  œŸœŸœ&ŸœŸœ ˜QKšœD™DKšœ'™'Kšœ&ŸœŸœ˜4KšœŸœŸœ˜š ŸœŸœŸœŸœŸœ˜"K˜[šŸœŸœ˜KšŸœŸœŸœ ˜0KšœŸœ˜KšœŸœ˜Kš Ÿœ ŸœŸœŸœ ]˜©š ŸœŸœŸœŸœŸœŸ˜@K˜KšŸœ˜—K˜K˜—K˜—K˜K˜—š œŸœŸœ(Ÿœ ˜OKšœΊ™ΊKšœ˜Kšœ!˜!K˜K˜—š  œŸœŸœŸœŸœ˜SKšŸœŸœŸœ˜:šŸœŸœ ˜2KšŸœŸœŸœ˜,KšŸœ˜K˜—Kš ŸœŸœŸœŸœ ˜QšŸœ ˜!KšœŸœ˜š Ÿœ ŸœŸœ-Ÿœ ŸœŸ˜YKšŸœŸœŸœ˜/K˜KšŸœ˜—Kšœ™KšŸœŸœŸœ˜,KšŸœ˜K˜—K˜K˜—š œŸœŸœŸœŸœ˜XK˜)K–<[scene: GGSceneImpl.SceneRef, slice: GGModelTypes.Slice]šœ˜K˜—K˜š œŸœŸœ"˜:KšœŸœ˜KšœŸœ˜K˜FK˜K˜—š œŸœŸœ"˜:KšœŸœ˜KšœŸœ˜Kšœ0˜0K˜FK˜K˜—š œŸœŸœ&Ÿœ"ŸœŸœ ˜|K–:[scene: GGModelTypes.Scene, slice: GGModelTypes.Slice]šœ Ÿœ˜K˜Kšœ˜K˜&Kšœ8˜8K–:[scene: GGModelTypes.Scene, slice: GGModelTypes.Slice]˜2Kšœ'’œ˜;KšŸœŸœŸœŸœ˜MKšŸœ ŸœŸœ)˜@Kšœ˜š ŸœŸœŸœ ŸœŸœŸ˜DKšœ4˜4KšŸœ˜—K˜K˜—š œŸœ ŸœŸœŸœ ˜gKšœŸœŸœ˜Kšœ˜Kšœ ŸœŸœ Ÿœ%˜EK˜0š Ÿœ ŸœŸœ"Ÿœ ŸœŸ˜PKšŸœŸœŸœ˜&K˜2KšœPŸœ ˜\K˜FKšŸœ˜—K˜K˜—Kšœ ŸœŸœ˜šœŸœŸœ˜0K™PKš œ ŸœŸœŸœŸœ˜#Kšœ ŸœŸœ˜KšŸœ ŸœŸœ˜K˜ KšœŸœ˜K˜KšœŸœ A˜WšŸœ ŸœŸœŸœŸœ"ŸœŸœŸ˜Pš ŸœŸœŸœ!ŸœŸœŸ˜CKšŸœŸœŸœ  !˜]KšŸœ˜—KšŸœ˜—š ŸœŸœŸœŸœŸœŸ˜?KšŸœŸœŸœ  !˜]KšŸœ˜—K˜K˜—š œŸœŸœŸœ˜RKšœ ŸœŸœ*˜[K˜MK˜lK˜cK˜lK˜iK˜—K™šœ  ™*K˜K˜—š œŸœŸœFŸœŸœŸœ ŸœŸœ˜ŒKšœ–ŸœE™ήš Ÿœ ŸœŸœ%Ÿœ ŸœŸ˜MKšœ Ÿœ$˜2Kšœ™š ŸœŸœ2ŸœŸœŸœŸœ˜yK˜"KšŸœ ŸœŸœ˜K˜—K™š ŸœŸœŸœŸœŸœ!Ÿœ˜yK˜KKšŸœ ŸœŸœ˜K˜—KšŸœ˜—K˜K˜—šœŸœŸœmŸœŸœŸœ ŸœŸœ˜»Kšœ–ŸœN™ηš ŸœŸœŸœHŸœŸœŸ˜lK˜$K˜)Kšœ Ÿœ!˜/Kšœ™š ŸœŸœŸœŸœŸœ/Ÿœ˜vK˜ KšŸœ ŸœŸœ˜K˜—Kšœ™š ŸœŸœŸœŸœŸœŸœ˜vK˜[KšŸœ ŸœŸœ˜K˜—KšŸœ˜—K˜K˜—š œŸœŸœ-ŸœŸœŸœ ŸœŸœ ˜vKšœŸœŸœ˜š  œŸœŸœŸœŸœ˜CK˜=K˜—K˜.K˜8K˜K˜—šœŸœŸœJŸœŸœŸœŸœŸœ˜¨KšœŸœŸœ˜š  œŸœŸœŸœŸœ˜NK˜NK˜—K˜;K˜MK˜K™—š œŸœŸœ-ŸœŸœŸœ Ÿœ ˜mš œŸœŸœŸœŸœ˜=K˜K˜—K˜2K˜K˜—šœŸœŸœJŸœŸœŸœ Ÿœ ˜’š œŸœŸœŸœŸœ˜HK˜K˜—K˜GK˜K˜—š œŸ œJŸœŸœŸœ˜šš œŸœŸœŸœŸœ˜QK˜KšŸœŸœ˜ K˜—K˜PK˜K˜—š œŸ œJŸœŸœŸœ˜™š œŸœŸœŸœŸœ˜PK˜K˜—K˜OK˜K˜—š  œŸœŸœŸœŸœ˜9KšŸœŸœ˜K˜K˜—K™™K™—šœŸœŸœŸœ!˜VK™BKšœŸœŸœ ˜Kšœ˜š Ÿœ ŸœŸœ'Ÿœ ŸœŸ˜SšŸœ-Ÿœ ˜TKšœŸœ˜8š Ÿœ ŸœŸœ-Ÿœ ŸœŸ˜WKšœ1Ÿœ˜6KšœŸœ˜KšŸœ˜—K˜—šŸœ˜Kšœ1Ÿœ˜6KšœŸœ˜K˜—KšŸœ˜—šœ Ÿœ˜&Kšœ ˜ K˜—K˜K˜—šœŸœŸœŸœ!˜VK™CKšœŸœŸœ)™6KšœŸœŸœ ˜Kšœ˜š Ÿœ ŸœŸœ'Ÿœ ŸœŸ˜SKšœ1Ÿœ˜6KšœŸœ˜KšŸœ˜—šœ Ÿœ˜&Kšœ ˜ K˜—K˜K˜—šœŸœŸœŸœ˜HKš Ÿœ ŸœŸœŸœŸœ˜ šŸœ˜K˜K˜K˜—K˜—K™šœŸœŸœŸœ˜HKšœŸœ ™K˜AKšœ0 "˜RK˜K˜—šœŸœŸœŸœ˜HKšœŸœ ™K˜AKšœ0 "˜RK˜—K™š œŸœŸœ<ŸœŸœŸœ˜‹Kšœ˜š  œŸœŸœŸœŸœ˜MK˜ šŸœ'˜)Kš Ÿœ&ŸœŸœŸœŸœ˜MKš Ÿœ&ŸœŸœŸœŸœ˜N—Kšœ3˜3K˜—K˜#Kšœ,‘œ ‘œ ‘˜IK˜K˜—š œŸœŸœBŸœŸœŸœ˜Kšœ˜š  œŸœŸœŸœŸœ˜MKš œ’ œŸœ ŸœŸœŸœ˜YKšœ3˜3K˜—K˜#Kšœ,‘œ ‘œ ‘˜IK˜K˜—š œŸœŸœBŸœŸœŸœ˜Kšœb™bKšœ˜š  œŸœŸœŸœŸœ˜MKš œ’ œŸœ ŸœŸœŸœ˜YKšœ3˜3K˜—K˜#Kšœ,‘œ ‘œ ‘˜IK˜K˜—Kšœ ŸœŸœ˜šœŸœŸœ”Ÿœ˜ΟKšœŒŸœ*Ÿœ™ΪK˜Kšœ˜š  œŸœŸœŸœŸœ˜MKšœ>™>Kšœ4˜4Kšœ œk˜pK˜5K˜7K˜BKšœ3˜3K˜—KšŸœ ŸœŸœ)˜CK˜#Kšœ,‘œ ‘œ ‘˜IK˜—K˜™ K™—šœŸœŸœŸœ˜Jš œŸœŸœŸœŸœ˜R–h[slice: GGModelTypes.Slice, scene: GGModelTypes.Scene, selectClass: GGSegmentTypes.SelectionClass]šŸœ'Ÿœ˜/K–:[scene: GGModelTypes.Scene, slice: GGModelTypes.Slice]šœ6Ÿœ˜;Kš’ œ  ˜1K˜—šŸœ˜Kšœ ŸœŸœ˜Kšœ Ÿœ'˜4KšœA˜AKšœ’œ ˜7Kš’ œ˜$Kš’ œ˜&š ŸœŸœŸœŸœŸœŸ˜BKšœ4˜4Kšœ9 Ε˜ώKšŸœ˜—K˜—Kšœ+˜+K˜—Kšœ˜K˜1Kšœ4˜4Kšœ,‘œ‘œ‘˜FKšœ˜K˜—š œŸœŸœ ŸœŸœ˜gK™/K˜!šŸœ"Ÿ˜,Kšœ Ÿœ˜• CharProps Postfix10 pt backgroundAscent 4 pt backgroundDescent .95 backgroundBrightness .5 backgroundSaturation .08 backgroundHue 1 outlineBoxBearoff˜ K–Postfix10 pt backgroundAscent 4 pt backgroundDescent .95 backgroundBrightness .5 backgroundSaturation .08 backgroundHue 1 outlineBoxBearoffšœ ŸœŸœ˜K–=Postfix10 pt backgroundAscent 4 pt backgroundDescent .95 backgroundBrightness .5 backgroundSaturation .08 backgroundHue 1 outlineBoxBearoffšŸœ$ŸœŸœŸœ˜=K™ί˜K™ΓKšœTœ“™χ—–mPostfix10 pt backgroundAscent 4 pt backgroundDescent .95 backgroundBrightness .5 backgroundSaturation .08 backgroundHue 1 outlineBoxBearoffš Ÿœ ŸœŸœCŸœ ŸœŸ˜mK–MPostfix10 pt backgroundAscent 4 pt backgroundDescent .95 backgroundBrightness .5 backgroundSaturation .08 backgroundHue 1 outlineBoxBearoffšœ# *˜M–XPostfix10 pt backgroundAscent 4 pt backgroundDescent .95 backgroundBrightness .5 backgroundSaturation .08 backgroundHue 1 outlineBoxBearoff˜XK™E—–=Postfix10 pt backgroundAscent 4 pt backgroundDescent .95 backgroundBrightness .5 backgroundSaturation .08 backgroundHue 1 outlineBoxBearoffšŸœ ŸœŸœ%Ÿ˜=K™-K–Ί Postfix10 pt backgroundAscent 4 pt backgroundDescent .95 backgroundBrightness .5 backgroundSaturation .08 backgroundHue 1 outlineBoxBearoffPostfix0 1 1 textColor7Postfix10 pt backgroundAscent 4 pt backgroundDescent .95 backgroundBrightness .5 backgroundSaturation .08 backgroundHue 1 outlineBoxBearoffšœ5Ÿœ ˜E—–Postfix10 pt backgroundAscent 4 pt backgroundDescent .95 backgroundBrightness .5 backgroundSaturation .08 backgroundHue 1 outlineBoxBearoffšŸœ˜K™/K–Postfix10 pt backgroundAscent 4 pt backgroundDescent .95 backgroundBrightness .5 backgroundSaturation .08 backgroundHue 1 outlineBoxBearoff˜K–Postfix10 pt backgroundAscent 4 pt backgroundDescent .95 backgroundBrightness .5 backgroundSaturation .08 backgroundHue 1 outlineBoxBearoffšœŸœŸœ˜K–JPostfix10 pt backgroundAscent 4 pt backgroundDescent .95 backgroundBrightness .5 backgroundSaturation .08 backgroundHue 1 outlineBoxBearoffšœ’œ ˜J–Postfix10 pt backgroundAscent 4 pt backgroundDescent .95 backgroundBrightness .5 backgroundSaturation .08 backgroundHue 1 outlineBoxBearoffšŸœŸœŸœ˜K–EPostfix10 pt backgroundAscent 4 pt backgroundDescent .95 backgroundBrightness .5 backgroundSaturation .08 backgroundHue 1 outlineBoxBearoff˜EK–0Postfix10 pt backgroundAscent 4 pt backgroundDescent .95 backgroundBrightness .5 backgroundSaturation .08 backgroundHue 1 outlineBoxBearoff˜0K–Postfix10 pt backgroundAscent 4 pt backgroundDescent .95 backgroundBrightness .5 backgroundSaturation .08 backgroundHue 1 outlineBoxBearoff˜—K–Postfix10 pt backgroundAscent 4 pt backgroundDescent .95 backgroundBrightness .5 backgroundSaturation .08 backgroundHue 1 outlineBoxBearoff˜—K–Postfix10 pt backgroundAscent 4 pt backgroundDescent .95 backgroundBrightness .5 backgroundSaturation .08 backgroundHue 1 outlineBoxBearoffšŸœ˜—K™bK–)Postfix10 pt backgroundAscent 4 pt backgroundDescent .95 backgroundBrightness .5 backgroundSaturation .08 backgroundHue 1 outlineBoxBearoffš Ÿœ ŸœŸœŸœŸœ˜)–Postfix10 pt backgroundAscent 4 pt backgroundDescent .95 backgroundBrightness .5 backgroundSaturation .08 backgroundHue 1 outlineBoxBearoffšŸœ˜K–SPostfix10 pt backgroundAscent 4 pt backgroundDescent .95 backgroundBrightness .5 backgroundSaturation .08 backgroundHue 1 outlineBoxBearoff˜SK–:Postfix10 pt backgroundAscent 4 pt backgroundDescent .95 backgroundBrightness .5 backgroundSaturation .08 backgroundHue 1 outlineBoxBearoff˜:K–Postfix10 pt backgroundAscent 4 pt backgroundDescent .95 backgroundBrightness .5 backgroundSaturation .08 backgroundHue 1 outlineBoxBearoffšŸœŸœ˜K–Postfix10 pt backgroundAscent 4 pt backgroundDescent .95 backgroundBrightness .5 backgroundSaturation .08 backgroundHue 1 outlineBoxBearoff˜—K–Postfix10 pt backgroundAscent 4 pt backgroundDescent .95 backgroundBrightness .5 backgroundSaturation .08 backgroundHue 1 outlineBoxBearoff˜—˜ Kšœ˜Kšœ˜K˜Kšœ˜KšœŸœŸœ˜ K˜K˜K˜Kšœ #˜;K˜CšŸœ ŸœŸ˜šŸœ*Ÿœ˜2šŸœ$Ÿœ˜,Kšœ’ œŸœ˜=K˜—šŸœ˜Kšœ%’œ ˜