DIRECTORY GGBasicTypes, GGBoundBox, GGInterfaceTypes, GGModelTypes, GGOutline, GGParent, GGScene, GGSceneType, GGSegmentTypes, GGSelect, GGSlice, GGSliceOps, GGTraj, GGUtility, Imager, ImagerPath, Rope, TextNode; GGSceneImpl: CEDAR MONITOR IMPORTS GGBoundBox, GGParent, GGScene, GGOutline, GGSelect, GGSlice, GGSliceOps, GGTraj, GGUtility EXPORTS GGScene, GGModelTypes = BEGIN BoundBox: TYPE = GGModelTypes.BoundBox; BoundBoxGenerator: TYPE = GGModelTypes.BoundBoxGenerator; BoundBoxGeneratorObj: TYPE = GGModelTypes.BoundBoxGeneratorObj; Camera: TYPE = GGModelTypes.Camera; CameraObj: TYPE = GGModelTypes.CameraObj; 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] ]; }; 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]]; 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 => { DoDeleteParts: PROC [childD: SliceDescriptor] RETURNS [done: BOOL _ FALSE] = { affectedBox: BoundBox; IF GGSliceOps.IsCompleteParts[childD] THEN { smallerCluster: Slice; affectedBox _ GGSliceOps.GetBoundBox[childD.slice, NIL]; smallerCluster _ GGSlice.RemoveChild[sliceD.slice, childD.slice]; -- fast case } ELSE { newSlices: LIST OF Slice; priority: INT _ GGParent.GetChildPriority[sliceD.slice, childD.slice]; [newSlices, affectedBox] _ DeleteSliceParts[childD]; [] _ GGSlice.RemoveChild[sliceD.slice, childD.slice]; GGSlice.AddChildrenToCluster[sliceD.slice, newSlices, priority]; }; GGBoundBox.EnlargeByBox[bBox, affectedBox]; }; IF GGSliceOps.IsCompleteParts[sliceD] THEN RETURN[NIL, bBox]; [] _ GGParent.WalkIncludedChildren[sliceD.slice, sliceD.parts, first, DoDeleteParts]; newSlices _ LIST[sliceD.slice]; }; $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 by Xerox Corporation. All rights reserved. Stone, August 5, 1985 4:13:18 pm PDT Pier, February 4, 1991 1:56 pm PST Kurlander August 28, 1986 6:15:29 pm PDT Bier, May 29, 1990 9:59:21 am PDT 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. 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. Κ$Δ˜Icode™šΟnœ;™CKšœB™BKšœ!Οk™$Kšœ"™"Kšœ%ž™(Kšœ!™!—K™šž ˜ JšœΚ˜ΚK˜—š œžœž˜Jšžœ[˜bKšžœž˜%—˜Kšœ žœ˜'Kšœžœ"˜9Kšœžœ%˜?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žœ˜GK˜K˜—šœžœžœ˜3Kšœžœ žœ˜Kšœžœ žœ˜#K˜K˜K˜—š œžœžœ˜5Kšœžœ žœ˜!Kšœ žœ žœ˜%K˜Kšœžœ˜Kšœ žœ˜Kšœ;˜;KšœžœŸ ˜$K˜Kšœ0˜0Kšœ*˜*K˜KšœUžœ˜ZKšœžœ˜Kšœ žœ˜&KšœOžœ˜TKšœžœ˜Kšœžœ˜#KšœUžœ˜ZKšœžœ˜Kšœ žœ˜&KšœSžœ˜XKšœžœ˜Kšœžœ˜%K˜Kšœžœ˜#K˜Kšœ_žœ˜dKšœ žœ˜$Kšœ%žœ˜+KšœYžœ˜^Kšœžœ˜!Kšœ"žœ˜(Kšœ_žœ˜dKšœ žœ˜$Kšœ%žœ˜+Kšœ]žœ˜bKšœžœ˜#Kšœ$žœ˜*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šœS˜SK˜K˜—š œžœ˜"Kš žœžœžœ žœž˜/š žœžœžœ#žœžœž˜EK˜Kšžœ˜—Kšœžœ˜Kšœ˜—K˜™ K™—šœžœžœ$žœ žœžœ žœ˜nKšœl™lš  œžœžœžœžœ˜NJšœžœžœ5˜Dš žœžœžœžœžœž˜?KšœC˜CKšœB˜BKšžœ˜—Kšœ˜—Jšœžœžœ žœ˜Jšœ0Οtœ  œ ˜IJšœ:Ÿ$˜^Jšœ&˜&JšΟb<™<š žœ žœžœ#žœ žœž˜QJšœ/˜/Jšœ=˜=Jšžœ˜—K˜K˜—™K™—šœžœ˜)š œžœžœžœžœ˜>Jšœ˜Jšœ˜J˜—Jšœžœ˜Kšœ$ œ ˜0Jšœžœ˜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šœF˜FK˜K˜—š œžœžœ"˜:Kšœžœ˜Kšœžœ˜Kšœ0˜0KšœF˜FK˜K˜—š œžœžœ&žœ"žœžœ ˜|K–:[scene: GGModelTypes.Scene, slice: GGModelTypes.Slice]šœ žœ˜Kšœ˜Kšœ˜Kšœ&˜&Kšœ8˜8K–:[scene: GGModelTypes.Scene, slice: GGModelTypes.Slice]šœ2˜2Kšœ'‘œ˜;Kšžœžœžœžœ˜MKšžœ žœžœ)˜@Kšœ˜š žœžœžœ žœžœž˜DKšœ4˜4Kšžœ˜—K˜K˜—š œžœ žœžœžœ ˜gKšœžœžœ˜Kšœ˜Kšœ žœžœ žœ%˜EKšœ0˜0š žœ žœžœ"žœ žœž˜PKšžœžœžœ˜&Kšœ2˜2KšœPžœ ˜\KšœF˜FKšžœ˜—K˜K˜—Kšœ žœžœ˜šœžœžœ˜0K™PKš œ žœžœžœžœ˜#Kšœ žœžœ˜Kšžœ žœžœ˜Kšœ ˜ Kšœžœ˜Kšœ˜KšœžœŸA˜Wšžœ žœžœžœžœ"žœžœž˜Pš žœžœžœ!žœžœž˜CKšžœžœžœ Ÿ!˜]Kšžœ˜—Kšžœ˜—š žœžœžœžœžœž˜?Kšžœžœžœ Ÿ!˜]Kšžœ˜—K˜K˜—š œžœžœžœ˜RKšœ žœžœ˜4KšœM˜MKšœl˜lKšœc˜cKšœl˜lKšœi˜iK˜—K™šœŸ ™*K˜K˜—š œžœžœFžœžœžœ žœžœ˜ŒKšœ–žœE™ήš žœ žœžœ%žœ žœž˜MKšœ žœ$˜2Kšœ™š žœžœ2žœžœžœžœ˜yKšœ"˜"Kšžœ žœžœ˜K˜—K™š žœžœžœžœžœ!žœ˜yKšœK˜KKšžœ žœžœ˜K˜—Jšžœ˜—K˜K˜—šœžœžœmžœžœžœ žœžœ˜»Kšœ–žœN™ηš žœžœžœHžœžœž˜lKšœ$˜$Kšœ)˜)Kšœ žœ!˜/Kšœ™š žœžœžœžœžœ/žœ˜vKšœ ˜ Kšžœ žœžœ˜K˜—Kšœ™š žœžœžœžœžœžœ˜vKšœ[˜[Kšžœ žœžœ˜K˜—Jšžœ˜—K˜K˜—š œžœžœ-žœžœžœ žœžœ ˜vKšœžœžœ˜š  œžœžœžœžœ˜CKšœ=˜=K˜—Kšœ.˜.Kšœ8˜8K˜K˜—šœžœžœJžœžœžœžœžœ˜¨Kšœžœžœ˜š  œžœžœžœžœ˜NKšœN˜NK˜—Kšœ;˜;KšœM˜MK˜K™—š œžœžœ-žœžœžœ žœ ˜mš œžœžœžœžœ˜=Kšœ˜K˜—Kšœ2˜2K˜K˜—šœžœžœJžœžœžœ žœ ˜’š œžœžœžœžœ˜HKšœ˜K˜—KšœG˜GK˜K˜—š œž œJžœžœžœ˜šš œžœžœžœžœ˜QKšœ˜Kšžœžœ˜ K˜—KšœP˜PK˜K˜—š œž œJžœžœžœ˜™š œžœžœžœžœ˜PKšœ˜K˜—KšœO˜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šœA˜AKšœ0Ÿ"˜RK˜K˜—šœžœžœžœ˜HKšœžœ ™KšœA˜AKšœ0Ÿ"˜RK˜—K™š œžœžœ<žœžœžœ˜‹Kšœ˜š  œžœžœžœžœ˜MKšœ ˜ šžœ'˜)Kš žœ&žœžœžœžœ˜MKš žœ&žœžœžœžœ˜N—Kšœ3˜3J˜—Kšœ#˜#Kšœ, œ  œ  ˜IK˜K˜—š œžœžœBžœžœžœ˜Kšœ˜š  œžœžœžœžœ˜MKš œ‘ œžœ žœžœžœ˜YKšœ3˜3J˜—Kšœ#˜#Kšœ, œ  œ  ˜IK˜K˜—š œžœžœBžœžœžœ˜Kšœb™bKšœ˜š  œžœžœžœžœ˜MKš œ‘ œžœ žœžœžœ˜YKšœ3˜3J˜—Kšœ#˜#Kšœ, œ  œ  ˜IK˜K˜—Kšœ žœžœ˜šœžœžœ”žœ˜ΟKšœŒžœ*žœ™ΪK˜Kšœ˜š  œžœžœžœžœ˜MKšœ>™>Kšœ4˜4KšœŸœk˜pKšœ5˜5Kšœ7˜7KšœB˜BKšœ3˜3J˜—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˜—Jšœ+˜+J˜—Jšœ˜Jšœ1˜1Kšœ4˜4Kšœ, œ œ ˜FKšœ˜K˜—š œžœžœ žœžœ˜gK™/Kšœ!˜!šžœ"ž˜,Kšœ žœ˜˜ š  œžœžœžœžœ˜NJšœ˜–h[slice: GGModelTypes.Slice, scene: GGModelTypes.Scene, selectClass: GGSegmentTypes.SelectionClass]šžœ$žœ˜,K–:[scene: GGModelTypes.Scene, slice: GGModelTypes.Slice]˜Kšœ3žœ˜8KšœBŸ ˜NK˜—šžœ˜Kšœ žœžœ˜Kšœ žœ9˜FKšœ4˜4Kšœ5˜5Kšœ@˜@K˜—Jšœ+˜+J˜—Kšžœ$žœžœžœ˜=Kšœ΄™΄KšœU˜UKšœ žœ˜K˜—˜ Jšœ˜Kšœ˜K˜Kšœ˜Kšœžœžœ˜ K˜Kšœ˜Kšœ˜KšœŸ#˜;KšœC˜Cšžœ žœž˜šžœ*žœ˜2šžœ$žœ˜,Kšœ‘ œžœ˜=J˜—šžœ˜Jšœ%‘œ ˜