DIRECTORY GGAlign, GGBasicTypes, GGBoundBox, GGInterfaceTypes, GGModelTypes, GGMultiGravity, GGScene, GGOutline, GGSceneType, GGSegment, GGSegmentTypes, GGSelect, GGSequence, GGTraj, GGUtility, GList, ImagerPath, Rope; GGSceneImpl: CEDAR PROGRAM IMPORTS GGAlign, GGBoundBox, GGMultiGravity, GGScene, GGOutline, GGSegment, GGSelect, GGSequence, GGTraj, GGUtility, GList EXPORTS GGScene, GGModelTypes = BEGIN BoundBox: TYPE = GGModelTypes.BoundBox; BoundBoxGenerator: TYPE = REF BoundBoxGeneratorObj; BoundBoxGeneratorObj: TYPE = GGModelTypes.BoundBoxGeneratorObj; CurveType: TYPE = {line, bezier, conic}; Joint: TYPE = REF JointObj; JointGenerator: TYPE = REF JointGeneratorObj; JointGeneratorObj: TYPE = GGModelTypes.JointGeneratorObj; JointObj: TYPE = GGSegmentTypes.JointObj; Outline: TYPE = REF OutlineObj; OutlineData: TYPE = GGOutline.OutlineData; OutlineObj: TYPE = GGModelTypes.OutlineObj; OutlineDescriptor: TYPE = GGModelTypes.OutlineDescriptor; OutlineGenerator: TYPE = REF OutlineGeneratorObj; OutlineGeneratorObj: TYPE = GGModelTypes.OutlineGeneratorObj; Point: TYPE = GGBasicTypes.Point; SceneObj: PUBLIC TYPE = GGSceneType.SceneObj; -- export of opaque type SceneRef: TYPE = REF SceneObj; Segment: TYPE = REF SegmentObj; SegmentGenerator: TYPE = GGModelTypes.SegmentGenerator; SegmentObj: TYPE = GGSegmentTypes.SegmentObj; Sequence: TYPE = REF SequenceObj; SequenceGenerator: TYPE = GGModelTypes.SequenceGenerator; SequenceObj: TYPE = GGModelTypes.SequenceObj; Slice: TYPE = GGModelTypes.Slice; SliceDescriptor: TYPE = GGModelTypes.SliceDescriptor; SliceDescriptorGenerator: TYPE = GGModelTypes.SliceDescriptorGenerator; SliceGenerator: TYPE = REF SliceGeneratorObj; SliceGeneratorObj: TYPE = GGModelTypes.SliceGeneratorObj; Traj: TYPE = REF TrajObj; TrajEnd: TYPE = GGModelTypes.TrajEnd; -- {lo, hi}; TrajGenerator: TYPE = REF TrajGeneratorObj; TrajGeneratorObj: TYPE = GGModelTypes.TrajGeneratorObj; TrajObj: TYPE = GGModelTypes.TrajObj; Vector: TYPE = GGBasicTypes.Vector; GGData: TYPE = GGInterfaceTypes.GGData; NotYetImplemented: PUBLIC SIGNAL = CODE; Problem: PUBLIC SIGNAL [msg: Rope.ROPE] = CODE; CreateScene: PUBLIC PROC [] RETURNS [scene: SceneRef] = { scene _ NEW[SceneObj _ [prioritiesValid: FALSE] ]; }; AddOutline: PUBLIC PROC [scene: SceneRef, outline: Outline, priority: INT _ -1] = { IF priority = -1 THEN AppendSlice[scene, outline] ELSE IF priority = 0 THEN { scene.ptrValid _ FALSE; scene.entities _ CONS[outline, scene.entities]; } ELSE SIGNAL Problem["Not yet implemented."]; scene.prioritiesValid _ FALSE; }; AddSlice: PUBLIC PROC [scene: SceneRef, slice: Slice, priority: INT _ -1] = { IF priority = -1 THEN AppendSlice[scene, slice] ELSE IF priority = 0 THEN { scene.ptrValid _ FALSE; scene.entities _ CONS[slice, scene.entities]; } ELSE SIGNAL Problem["Not yet implemented."]; scene.prioritiesValid _ FALSE; }; AddSlices: PUBLIC PROC [scene: SceneRef, slice: LIST OF Slice, priority: INT _ -1] = { IF priority = -1 THEN { FOR list: LIST OF Slice _ slice, list.rest UNTIL list = NIL DO AppendSlice[scene, list.first]; ENDLOOP; } ELSE SIGNAL Problem["Not yet implemented."]; scene.prioritiesValid _ FALSE; }; AppendSlice: PROC [scene: SceneRef, slice: Slice] = { IF NOT scene.ptrValid THEN { -- restore ptr IF scene.entities=NIL THEN scene.ptr _ NIL ELSE FOR list: LIST OF Slice _ scene.entities, list.rest UNTIL list=NIL DO scene.ptr _ list; ENDLOOP; scene.ptrValid _ TRUE; }; [scene.entities, scene.ptr] _ GGUtility.AddSlice[slice, scene.entities, scene.ptr]; }; SlicePriority: PUBLIC PROC [scene: SceneRef, slice: Slice] RETURNS [priority: INT] = { IF NOT scene.prioritiesValid THEN UpdatePriorities[scene]; priority _ slice.priority; }; UpdatePriorities: PROC [scene: SceneRef] = { sliceGen: SliceGenerator _ GGScene.TopLevelSlicesInScene[scene]; index: NAT _ 0; FOR slice: Slice _ GGScene.NextSlice[sliceGen], GGScene.NextSlice[sliceGen] UNTIL slice = NIL DO slice.priority _ index; index _ index + 1; ENDLOOP; scene.prioritiesValid _ TRUE; }; DeleteSlice: PUBLIC PROC [scene: SceneRef, slice: Slice] = { scene.ptrValid _ FALSE; scene.entities _ NARROW[GList.Remove[slice, scene.entities]]; scene.prioritiesValid _ FALSE; }; DeleteOutline: PUBLIC PROC [scene: SceneRef, outline: Outline] = { GGScene.DeleteSlice[scene, outline]; scene.prioritiesValid _ FALSE; }; DeleteSequence: PUBLIC PROC [seq: Sequence, scene: SceneRef] RETURNS [oldOutline: Outline, newOutlines: LIST OF Outline] = { oldOutline _ GGOutline.OutlineOfTraj[seq.traj]; SELECT seq.traj.role FROM hole => { smallerOutline: Outline; newOutlines _ OutlinesOfTrajMinusSequence[seq]; smallerOutline _ OutlineMinusHole[oldOutline, seq.traj]; AddOutline[scene, smallerOutline, -1]; AddOutlinesToScene[newOutlines, scene]; -- put the deflated holes on top. newOutlines _ CONS[smallerOutline, newOutlines]; }; open => { newOutlines _ OutlinesOfTrajMinusSequence[seq]; AddOutlinesToScene[newOutlines, scene]; }; fence => { fenceParts, freedHoles: LIST OF Outline; fenceParts _ OutlinesOfTrajMinusSequence[seq]; AddOutlinesToScene[fenceParts, scene]; freedHoles _ OutlinesFromOutlineExcept[oldOutline, seq.traj]; AddOutlinesToScene[freedHoles, scene]; newOutlines _ AppendOutlines[fenceParts, freedHoles]; }; ENDCASE => ERROR; DeleteOutline[scene, oldOutline]; }; AddOutlinesToScene: PROC [outlines: LIST OF Outline, scene: SceneRef] = { FOR list: LIST OF Outline _ outlines, list.rest UNTIL list = NIL DO AddOutline[scene, list.first, -1]; ENDLOOP; }; OutlinesOfTrajMinusSequence: PROC [seq: Sequence] RETURNS [newOutlines: LIST OF Outline] = { diff, wholeTraj: Sequence; IF GGSequence.IsComplete[seq] THEN RETURN[NIL]; wholeTraj _ GGSequence.CreateComplete[seq.traj]; IF NOT GGSequence.IsEmpty[seq] AND seq.traj.segCount=1 THEN GGSegment.OpenUpSegment[GGTraj.FetchSegment[seq.traj, 0]]; -- cyclic segments must become acyclic diff _ GGSequence.Difference[wholeTraj, seq]; [newOutlines] _ GroupPieces[diff]; }; GroupPieces: PROC [seq: Sequence] RETURNS [newOutlines: LIST OF Outline] = { seqGen: SequenceGenerator; newTraj: Traj; newOutline, oldOutline: Outline; runCount: NAT; joint: Joint; newOutlines _ NIL; oldOutline _ GGOutline.OutlineOfTraj[seq.traj]; [seqGen, runCount] _ GGSequence.RunsInSequence[seq]; FOR run: Sequence _ GGSequence.NextSequence[seqGen], GGSequence.NextSequence[seqGen] UNTIL run = NIL DO IF run.segCount=0 THEN LOOP; -- special case needed by BS command. [newTraj] _ GGTraj.CopyTrajFromRun[run]; joint _ GGTraj.FetchJoint[newTraj, 0]; joint.TselectedInFull.active _ FALSE; joint _ GGTraj.FetchJoint[newTraj, GGTraj.HiJoint[newTraj]]; joint.TselectedInFull.active _ FALSE; newTraj.role _ open; newOutline _ GGOutline.CreateOutline[newTraj, oldOutline.class.getFillColor[oldOutline] ]; newOutlines _ CONS[newOutline, newOutlines]; ENDLOOP; }; OutlinesFromOutlineExcept: PROC [outline: Outline, except: Traj] RETURNS [newOutlines: LIST OF Outline] = { trajGen: TrajGenerator; newTraj: Traj; newOutline: Outline; ptr: LIST OF Outline; trajGen _ GGOutline.TrajsInOutline[outline]; [newOutlines, ptr] _ StartOutlineList[]; FOR traj: Traj _ GGScene.NextTraj[trajGen], GGScene.NextTraj[trajGen] UNTIL traj = NIL DO IF traj = except THEN LOOP; newTraj _ GGTraj.CopyTraj[traj]; newOutline _ GGOutline.CreateOutline[newTraj, outline.class.getFillColor[outline] ]; [newOutlines, ptr] _ AddOutlineToList[newOutline, newOutlines, ptr]; ENDLOOP; }; OutlineMinusHole: PROC [outline: Outline, except: Traj] RETURNS [newOutline: Outline] = { holeGen: TrajGenerator; newTraj, fence: Traj; fence _ GGOutline.FenceOfOutline[outline]; newTraj _ GGTraj.CopyTraj[fence]; newOutline _ GGOutline.CreateOutline[newTraj, outline.class.getFillColor[outline] ]; holeGen _ GGOutline.HolesOfOutline[outline]; FOR hole: Traj _ GGScene.NextTraj[holeGen], GGScene.NextTraj[holeGen] UNTIL hole = NIL DO IF hole = except THEN LOOP; newTraj _ GGTraj.CopyTraj[hole]; newOutline _ GGOutline.AddHole[newOutline, newTraj]; ENDLOOP; }; AppendOutlines: PROC [list1, list2: LIST OF Outline] RETURNS [result: LIST OF Outline] = { pos: LIST OF Outline; newCell: LIST OF Outline; IF list1 = NIL THEN RETURN[list2]; result _ CONS[list1.first, NIL]; pos _ result; FOR l: LIST OF Outline _ list1.rest, l.rest UNTIL l = NIL DO newCell _ CONS[l.first, NIL]; pos.rest _ newCell; pos _ newCell; ENDLOOP; pos.rest _ list2; }; StartOutlineList: PROC [] RETURNS [entityList, ptr: LIST OF Outline] = { ptr _ entityList _ NIL; }; AddOutlineToList: PROC [entity: Outline, entityList, ptr: LIST OF Outline] RETURNS [newList, newPtr: LIST OF Outline] = { 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; }; }; undeleteSize: INT _ 20; -- temporarily hardwired size of undelete stack PushScene: PUBLIC PROC [scene: SceneRef] = { CopySliceList: PROC [list: LIST OF Slice] RETURNS [copy: LIST OF Slice] = { entityList, ptr: LIST OF Slice; [entityList, ptr] _ GGUtility.StartSliceList[]; FOR entity: LIST OF Slice _ list, entity.rest UNTIL entity=NIL DO [entityList, ptr] _ GGUtility.AddSlice[entity.first, entityList, ptr]; ENDLOOP; copy _ entityList; }; tList: LIST OF LIST OF Slice; scene.oldEntities _ CONS[CopySliceList[scene.entities], scene.oldEntities]; tList _ scene.oldEntities; FOR index: INT IN [0..undeleteSize) DO IF tList#NIL THEN tList _ tList.rest; ENDLOOP; IF tList#NIL THEN tList.rest _ NIL; -- truncate the undelete stack }; EmptySceneStack: PUBLIC PROC [scene: SceneRef] RETURNS [BOOL] = { RETURN[scene.oldEntities=NIL OR scene.oldEntities.first=NIL]; }; PopScene: PUBLIC PROC [scene: SceneRef] = { IF EmptySceneStack[scene] THEN ERROR; scene.entities _ scene.oldEntities.first; scene.ptrValid _ FALSE; scene.oldEntities _ scene.oldEntities.rest; }; MergeScenes: PUBLIC PROC [back: SceneRef, front: SceneRef] RETURNS [combined: SceneRef] = { combined _ NEW[SceneObj _ [prioritiesValid: FALSE]]; combined.entities _ NARROW[GList.Append[back.entities, front.entities]]; combined.selected.normal _ NARROW[GList.Append[back.selected.normal, front.selected.normal]]; combined.selected.hot _ NARROW[GList.Append[back.selected.hot, front.selected.hot]]; combined.selected.active _ NARROW[GList.Append[back.selected.active, front.selected.active]]; }; UpOne: PUBLIC PROC [scene: SceneRef, slice: Slice] = { ExchangeWithNextEntity: PROC [scene: SceneRef, slice: Slice] = { previous, next: LIST OF Slice _ NIL; FOR list: LIST OF Slice _ scene.entities, list.rest UNTIL list = NIL DO IF list.first=slice THEN { -- exchange this entity with its next neighbor next _ list.rest; IF next=NIL THEN RETURN; -- entity already at end (i.e. top) of list list.rest _ next.rest; next.rest _ list; IF previous#NIL THEN previous.rest _ next ELSE scene.entities _ next; } ELSE previous _ list; ENDLOOP; }; ExchangeWithNextEntity[scene, slice]; }; DownOne: PUBLIC PROC [scene: SceneRef, slice: Slice] = { ExchangeWithPreviousEntity: PROC [scene: SceneRef, slice: Slice] = { preprev, previous: LIST OF Slice _ NIL; FOR list: LIST OF Slice _ scene.entities, list.rest UNTIL list=NIL DO IF list.first=slice THEN { -- exchange this entity with its previous neighbor SELECT TRUE FROM preprev=NIL AND previous=NIL => 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; }; ExchangeWithPreviousEntity[scene, slice]; }; TopLevelEntitiesInScene: PUBLIC PROC [scene: SceneRef] RETURNS [sliceGen: SliceGenerator] = { sliceGen _ NEW[SliceGeneratorObj _ [ list: scene.entities ]]; }; TopLevelSlicesInScene: PUBLIC PROC [scene: SceneRef] RETURNS [sliceGen: SliceGenerator] = { sliceGen _ NEW[SliceGeneratorObj _ [ list: scene.entities ]]; }; IsTopLevel: PUBLIC PROC [slice: Slice] RETURNS [BOOL] = { RETURN[slice.parent = NIL]; }; TrajsInScene: PUBLIC PROC [scene: SceneRef] RETURNS [trajGen: TrajGenerator] = { list: LIST OF Traj _ ListTrajsInScene[scene]; trajGen _ NEW[TrajGeneratorObj _ [ list: list ]]; }; OutlinesInScene: PUBLIC PROC [scene: SceneRef] RETURNS [outlineGen: OutlineGenerator] = { list: LIST OF Outline _ ListOutlinesInScene[scene]; outlineGen _ NEW[OutlineGeneratorObj _ [ list: list ]]; }; NextTraj: PUBLIC PROC [g: TrajGenerator] RETURNS [next: Traj] = { IF g.list = NIL THEN RETURN[NIL] ELSE { next _ g.list.first; g.list _ g.list.rest; }; }; NextOutline: PUBLIC PROC [g: OutlineGenerator] RETURNS [next: Outline] = { IF g.list = NIL THEN RETURN[NIL] ELSE { next _ g.list.first; g.list _ g.list.rest; }; }; SlicesInScene: PUBLIC PROC [scene: SceneRef] RETURNS [sliceGen: SliceGenerator] = { list: LIST OF Slice _ ListSlicesInScene[scene]; sliceGen _ NEW[SliceGeneratorObj _ [ list: list ]]; }; NextSlice: PUBLIC PROC [g: SliceGenerator] RETURNS [next: Slice] = { IF g.list = NIL THEN RETURN[NIL] ELSE { next _ g.list.first; g.list _ g.list.rest; }; }; BoundBoxesInScene: PUBLIC PROC [scene: SceneRef] RETURNS [bBoxGen: BoundBoxGenerator] = { list: LIST OF BoundBox _ ListBoxesInScene[scene]; bBoxGen _ NEW[BoundBoxGeneratorObj _ [ list: list ]]; }; TightBoxesInScene: PUBLIC PROC [scene: SceneRef] RETURNS [bBoxGen: BoundBoxGenerator] = { list: LIST OF BoundBox _ ListTightBoxesInScene[scene]; 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; }; }; ListBoxesInScene: PROC [scene: SceneRef] RETURNS [allBoxes: LIST OF BoundBox] = { thisBox: BoundBox; FOR entities: LIST OF Slice _ scene.entities, entities.rest UNTIL entities = NIL DO thisBox _ entities.first.class.getBoundBox[entities.first, NIL]; allBoxes _ CONS[thisBox, allBoxes]; ENDLOOP; }; ListTightBoxesInScene: PROC [scene: SceneRef] RETURNS [allBoxes: LIST OF BoundBox] = { thisBox: BoundBox; FOR entities: LIST OF Slice _ scene.entities, entities.rest UNTIL entities = NIL DO thisBox _ entities.first.class.getTightBox[entities.first, NIL]; allBoxes _ CONS[thisBox, allBoxes]; ENDLOOP; }; BoundBoxOfScene: PUBLIC PROC [scene: SceneRef] RETURNS [bBox: BoundBox] = { bbGen: GGModelTypes.BoundBoxGenerator _ BoundBoxesInScene[scene]; bBox _ GGBoundBox.BoundBoxOfBoxes[bbGen.list]; -- cheating to go inside generator }; TightBoxOfScene: PUBLIC PROC [scene: SceneRef] RETURNS [bBox: BoundBox] = { bbGen: GGModelTypes.BoundBoxGenerator _ TightBoxesInScene[scene]; bBox _ GGBoundBox.BoundBoxOfBoxes[bbGen.list]; -- cheating to go inside generator }; AppendTrajs: PUBLIC PROC [l1, l2: LIST OF Traj] RETURNS [result: LIST OF Traj] = { z: LIST OF Traj _ l1; IF z = NIL THEN RETURN[l2]; UNTIL z.rest = NIL DO z _ z.rest; ENDLOOP; z.rest _ l2; RETURN[l1]; }; AppendBoxes: PUBLIC PROC [l1, l2: LIST OF BoundBox] RETURNS [result: LIST OF BoundBox] = { z: LIST OF BoundBox _ l1; IF z = NIL THEN RETURN[l2]; UNTIL z.rest = NIL DO z _ z.rest; ENDLOOP; z.rest _ l2; RETURN[l1]; }; ListTrajsInScene: PROC [scene: SceneRef] RETURNS [allTrajs: LIST OF Traj] = { FOR slices: LIST OF Slice _ scene.entities, slices.rest UNTIL slices = NIL DO IF slices.first.class.type#$Outline THEN LOOP; FOR trajs: LIST OF Traj _ GGOutline.TrajectoriesOfOutline[slices.first], trajs.rest UNTIL trajs = NIL DO allTrajs _ CONS[trajs.first, allTrajs]; ENDLOOP; ENDLOOP; }; ListOutlinesInScene: PROC [scene: SceneRef] RETURNS [allOutlines: LIST OF Slice] = { FOR slices: LIST OF Slice _ scene.entities, slices.rest UNTIL slices = NIL DO IF slices.first.class.type=$Outline THEN allOutlines _ CONS[slices.first, allOutlines]; ENDLOOP; }; ListSlicesInScene: PROC [scene: SceneRef] RETURNS [allSlices: LIST OF Slice] = { FOR slices: LIST OF Slice _ scene.entities, slices.rest UNTIL slices = NIL DO allSlices _ CONS[slices.first, allSlices]; ENDLOOP; }; ListTrajsInOutline: PROC [outline: Outline] RETURNS [trajList: LIST OF Traj] = { outlineData: OutlineData _ NARROW[outline.data]; trajList _ outlineData.children; }; ListHolesOfOutline: PROC [outline: Outline] RETURNS [trajList: LIST OF Traj] = { outlineData: OutlineData _ NARROW[outline.data]; trajList _ outlineData.children.rest; }; ListSegmentsInTraj: PROC [traj: Traj] RETURNS [segList: LIST OF Segment] = { segList _ NIL; FOR i: NAT DECREASING IN [0..GGTraj.HiSegment[traj]] DO segList _ CONS[GGTraj.FetchSegment[traj, i], segList]; ENDLOOP; }; 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]; }; DeleteAllSelected: PUBLIC PROC [scene: SceneRef] RETURNS [bBox: BoundBox] = { DeleteRun: GGSelect.RunProc = { traj _ NIL; }; sliceDescGen: GGModelTypes.SliceDescriptorGenerator; thisBox: BoundBox; bBox _ GGBoundBox.BoundBoxOfSelected[scene, normal]; sliceDescGen _ GGSelect.SelectedSlices[scene, normal]; FOR sliceD: SliceDescriptor _ GGSelect.NextSliceDescriptor[sliceDescGen], GGSelect.NextSliceDescriptor[sliceDescGen] UNTIL sliceD = NIL DO IF sliceD.slice.class.type=$Outline THEN LOOP; -- OUTLINES ARE TAKEN CARE OF BY ForEachOutlineRun CALL FOLLOWING !! GGSelect.DeselectEntireSlice[sliceD.slice, scene, hot]; GGScene.DeleteSlice[scene, sliceD.slice]; ENDLOOP; thisBox _ GGSelect.ForEachOutlineRun[scene, normal, DeleteRun, FALSE]; GGSelect.DeselectAll[scene, normal]; GGBoundBox.EnlargeByBox[bBox: bBox, by: thisBox]; }; SaveSelections: PUBLIC PROC [scene: SceneRef] = { scene.savedSelected.normal _ ListCopy[scene.selected.normal]; }; RestoreSelections: PUBLIC PROC [scene: SceneRef] = { 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; }; GetSelections: PUBLIC PROC [scene: SceneRef, selectClass: GGSegmentTypes.SelectionClass] RETURNS [selected: LIST OF SliceDescriptor] = { SELECT selectClass FROM normal => selected _ scene.selected.normal; hot => selected _ scene.selected.hot; active => selected _ scene.selected.active; ENDCASE => ERROR; }; ListCopy: PROC [l1: LIST OF SliceDescriptor] RETURNS [val: LIST OF SliceDescriptor] = { z: LIST OF SliceDescriptor _ NIL; val _ NIL; IF l1 = NIL THEN RETURN[val]; val _ CONS[l1.first, val]; z _ val; UNTIL (l1 _ l1.rest) = NIL DO z.rest _ CONS[l1.first, z.rest]; z _ z.rest; ENDLOOP; RETURN[val]; }; -- of Append END. ΦGGSceneImpl.mesa Copyright c 1985 by Xerox Corporation. All rights reserved. Last edited by Bier on April 6, 1987 10:43:23 pm PDT Contents: The procedural interface to the Gargoyle object modeler. Stone, August 5, 1985 4:13:18 pm PDT Pier, May 14, 1987 3:30:44 pm PDT Kurlander August 28, 1986 6:15:29 pm PDT Scene: TYPE = GGModelTypes.Scene; 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. Building and Destroying Clusters MakeCluster: PUBLIC PROC [entities: LIST OF REF ANY] RETURNS [newCluster: Slice]; BreakCluster: PUBLIC PROC [oldCluster: Slice] RETURNS [entities: LIST OF REF ANY]; 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 outline to the scene with the given priority (the lower the priority number, the closer the outline is to the front. If priority is -1, the outline will be the rear-most entity. If an entity with the given priority already exists, all priority numbers greater than or equal to it will be increased by one. Add the given slice to the scene with the given priority (the higher the priority number, the closer the outline 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 entities, 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. 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; }; Takes the trajectory of which seq is a part. What is the role of this trajectory? If role = hole, then create a new outline (and new trajectories), identical to seq.traj.outline, but without the hole. The index corresponding to this outline will be 0. Make separate outlines corresponding to those parts of the hole which were not deleted. The index for each of these outlines will be the segment number, in the original hole traj, of segment 0 in the new outline. The old outline (and all of its parts) is now obsolete. If role = fence, then create new outlines and new trajectories for all of the parts of seq.traj.outline which remain. The index for each of these outlines will be the segment number, in the original fence traj, of segment 0 in the new outline. The old outline (and all of its parts) is now obsolete. If role = open, then create new outlines and new trajectories for all of the parts of seq.traj which remain. The index for each of these outlines will be the segment number, in the original fence traj, of segment 0 in the new outline. The old outline is obsolete. The parts of the hole become top level parts of the scene. The rest of the outline is replaced by a single new outline. Parts of the trajectory are in the sequence. Take the segments which remain, and all the joints that they touch. Make sure the end joints of the run are not active selected. They can be normal or hot selected. This is important for the delete operation. Non-destructive (copies the first list). Makes a copy of the current scene list, and pushes it on a stack. For use in Undelete. Lets scene be the most recently pushed scene, that has not yet been popped. Moves the named slice one step closer to the front in the priority order. Moves the named slice one step closer to the back in the priority order. Browsing the Scene Hierarchy -- Generators Generates all of the outlines and slices in the scene. Generates all of the outlines and slices in the scene. NextEntity: PUBLIC PROC [g: EntityGenerator] 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: EntityGenerator] 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; }; outline: Outline => RETURN[outline.parent = NIL OR outline.parent.parent = NIL]; traj: Traj => RETURN[traj.parent.parent = NIL OR traj.parent.parent.parent = NIL]; seq: Sequence => RETURN[IsTopLevel[seq.traj.parent]]; ENDCASE => ERROR; Generates all of the trajectories in the scene, wherever they occur. Generates all of the outlines in the scene, wherever they occur. Bounding Boxes Generates all of the boundBoxes in the scene, whereever they occur. Generates all of the boundBoxes in the scene, whereever they occur. box is in local IP coordinates box is in local IP coordinates Utility Routines Destructive append. Destructive append. 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: Outline => { 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 Outline] = { allOutlines _ NIL; FOR entities: LIST OF REF ANY _ scene.entities, entities.rest UNTIL entities = NIL DO WITH entities.first SELECT FROM slice: Slice => { }; outline: Outline => { 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: Outline => {}; ENDCASE => ERROR; ENDLOOP; }; Hit Testing -- Outline-Specific routines. These should go away when Outlines become Slices. Selections SELECT ... sliceD Make a copy of the list quickly. The list will be modified in place later on. ListDRemove: PROC [ref: SliceDescriptor, list: LIST OF SliceDescriptor] RETURNS[LIST OF SliceDescriptor] = { l, l1: LIST OF SliceDescriptor _ NIL; l _ list; UNTIL l = NIL DO IF l.first=ref THEN { IF l1 = NIL THEN RETURN[l.rest]; -- ref was first object on list l1.rest _ l.rest; RETURN[list]; }; l1 _ l; l _ l.rest; ENDLOOP; RETURN [list]; }; ΚΖ˜code™Kšœ Οmœ1™Kšœ˜Kšžœ˜—K˜—Kšžœžœ!˜,Kšœžœ˜K˜K˜—š Ÿ œžœžœžœžœ žœ™LKšœΗ™ΗKšžœžœ™1šžœžœžœ™Kšœžœ™Kšœžœ™.K™—Kšžœžœ!™,Kšœžœ™K™K™—šŸ œžœ$˜5šžœžœžœ ˜+Kš žœžœžœ žœž˜/š žœžœžœ#žœžœž˜EK˜Kšžœ˜—Kšœžœ˜Kšœ˜—Kšœ(Ÿœ#˜SK˜K˜—š Ÿ œžœžœ!žœ žœ˜VKšžœžœžœ˜:Kšœ˜K˜K˜—šŸœžœ˜,Jšœ@˜@Jšœžœ˜šžœIžœ ž˜`Jšœ˜Jšœ˜Jšžœ˜—Jšœžœ˜Kšœ˜K˜—šŸ œžœžœ%˜=Kšœžœ˜Kšœžœ&˜=Kšœžœ˜K˜K˜—š Ÿ œžœžœžœžœ™@K™_Kšœžœ™Kšœ6™6Kšœžœ™K™K™—šŸ œžœžœ)˜CKšœ$˜$Kšœžœ˜K˜K™—š Ÿœžœžœ"žœ$žœžœ ˜|K™RK™ΉK™­K™‰K˜Kšœ/˜/šžœž˜šœ ˜ Kšœ˜K™:šœ/˜/Kš‘<™<—Kšœ8˜8Kšœ&˜&Kšœ( !˜IKšœžœ˜0K˜—šœ ˜ Kšœ/˜/Kšœ'˜'K˜—šœ ˜ Kšœžœžœ ˜(Kšœ.˜.Kšœ&˜&Kšœ=˜=Kšœ&˜&Kšœ5˜5K˜—Kšžœžœ˜—Kšœ!˜!K˜K˜šŸœžœ žœžœ˜Iš žœžœžœžœžœž˜CKšœ"˜"Kšžœ˜—K˜K˜—š Ÿœžœžœžœžœ ˜\Kšœ˜šžœžœžœžœ˜/K™q—Kšœ0˜0Kšžœžœ1žœ< &˜Kšœ-˜-Kšœ"˜"K˜K˜—š Ÿ œžœžœžœžœ ˜LKšœ˜Kšœ˜Kšœ ˜ Kšœ žœ˜K˜ Kšœžœ˜Kšœ/˜/Kšœ4˜4šžœRžœžœž˜gKšžœžœžœ %˜BKšœ(˜(š‘Ž™ŽKšœ&˜&Kšœžœ˜%Kšœ<˜šœžœžœ žœ %˜GKšœHžœ˜OKšœ˜—Kšžœžœ ˜)—K˜—Kšžœ+˜/Kšžœ˜—K˜—Kšœ)˜)K˜K˜—K™Kšœ ‘ ™*K˜šŸœžœžœžœ ˜^K™6šœ žœ˜$Kšœ˜K˜—K˜K˜—šŸœžœžœžœ ˜\K™6šœ žœ˜$Kšœ˜K˜—K˜K˜—š Ÿ œžœžœžœžœžœ™HKš žœ žœžœžœžœ™ šžœ™Kšœ™K™K™—K™K™—š Ÿ œžœžœžœ žœ™FKšžœžœžœ ™%Kšœ ™ šžœžœžœžœžœžœžœž™AKšœ™Kšžœ™—K™K™—š Ÿ œžœžœžœžœ˜9Kšžœžœ˜Kš œžœžœžœžœ™PKš œžœžœžœžœ™RKšœžœ™5Kšžœžœ™K˜K˜—šŸ œžœžœžœ˜QK™DKšœžœžœ ˜-šœ žœ˜"Kšœ ˜ K˜—K˜K˜—šŸœžœžœžœ$˜ZK™@Kšœžœžœ&˜3šœ žœ˜(Kšœ ˜ K˜—K˜K˜—šŸœžœžœžœ˜AKš žœ žœžœžœžœ˜ šžœ˜Kšœ˜K˜K˜—K˜K˜—šŸ œžœžœžœ˜JKš žœ žœžœžœžœ˜ šžœ˜Kšœ˜K˜K˜—K˜K˜—šŸ œžœžœžœ˜SKšœžœžœ"˜/šœ žœ˜$Kšœ ˜ K˜—K˜K˜—šŸ œžœžœžœ˜DKš žœ žœžœžœžœ˜ šžœ˜Kšœ˜K˜K˜—K˜K˜—K™K™šŸœžœžœžœ!˜YK™CKšœžœžœ$˜1šœ žœ˜&Kšœ ˜ K˜—K˜K˜—šŸœžœžœžœ!˜YK™CKšœžœžœ)˜6šœ žœ˜&Kšœ ˜ K˜—K˜K˜—šŸœžœžœžœ˜HKš žœ žœžœžœžœ˜ šžœ˜Kšœ˜K˜K˜—K˜—K™š Ÿœžœžœ žœžœ˜QKšœ˜š žœ žœžœ'žœ žœž˜SKšœ;žœ˜@Kšœ žœ˜#Kšžœ˜—K˜K˜—š Ÿœžœžœ žœžœ˜VKšœ˜š žœ žœžœ'žœ žœž˜SKšœ;žœ˜@Kšœ žœ˜#Kšžœ˜—K˜K˜—šŸœž œžœ˜KKšΠbc™KšœA˜AKšœ0 "˜RK˜K˜—šŸœž œžœ˜KKš£™KšœA˜AKšœ0 "˜RK˜K˜—K™K™K™šŸ œžœžœ žœžœžœ žœžœ ˜RK™Kšœžœžœ ˜Kšžœžœžœžœ˜Kšžœ žœžœ žœ˜*Kšœ ˜ Kšžœ˜ Kšœ˜K˜—šŸ œžœžœ žœžœ žœ žœžœ˜ZK™Kšœžœžœ˜Kšžœžœžœžœ˜Kšžœ žœžœ žœ˜*Kšœ ˜ Kšžœ˜ Kšœ˜K˜—š Ÿœžœžœ žœžœ ™QKšœ žœ™šžœ žœžœžœžœ!žœ žœž™Ušžœžœž™šœ™K™—™š žœžœžœ%žœ žœž™KKšœ žœ™'—Kšžœ™K™—Kšžœžœ™—Kšžœ™—K™K™—š Ÿœžœžœ žœžœ ˜Mš žœ žœžœ%žœ žœž˜MKšžœ"žœžœ˜.šžœžœžœžœ Ÿœžœ žœž˜hKšœ žœ˜'Kšžœ˜—Kšžœ˜—K˜K˜—š Ÿœžœžœžœžœ ™ZKšœžœ™šžœ žœžœžœžœ!žœ žœž™Ušžœžœž™šœ™K™—™Kšœžœ™)K™—Kšžœžœ™—Kšžœ™—K™K™—š Ÿœžœžœžœžœ ˜Tš žœ žœžœ%žœ žœž˜MKšžœ"žœžœ˜WKšžœ˜—K˜K˜—š Ÿœžœžœ žœžœ ™TKšœ žœ™šžœ žœžœžœžœ!žœ žœž™Ušžœžœž™šœ™K™ Kšœ žœ™#K™—K™Kšžœžœ™—Kšžœ™—K™K™—š Ÿœžœžœ žœžœ ˜Pš žœ žœžœ%žœ žœž˜MKšœ žœ˜*Kšžœ˜—K˜K˜—š Ÿœžœžœ žœžœ ˜QKšœžœ˜0Kšœ ˜ K˜K˜—š Ÿœžœžœ žœžœ ˜QKšœžœ˜0Kšœ%˜%K˜K˜—š Ÿœžœžœ žœžœ ˜LKšœ žœ˜š žœžœž œžœž˜7Kšœ žœ(˜6Kšžœ˜—K˜—K˜K™\K™šŸœžœžœ3žœ˜pKšœ"˜"Kšœ˜Jšœ*˜*Jšœžœ˜/Kšœ‡˜‡Kšžœžœ žœžœžœžœžœžœ ˜`K˜K˜—K˜K™ K™šŸœž œžœ˜MšŸ œ˜Jšœžœ˜ J˜—K˜4K˜Kšœ4˜4Kš‘™Kšœ6˜6šžœržœ žœž˜ŠKšžœ"žœžœ £A˜sKšœ7˜7Kšœ)˜)Jšžœ˜—Jšœ?žœ˜FJšœ$˜$Kšœ1˜1K˜K˜—šŸœžœžœ˜1šœ=˜=K™M—K˜K˜—šŸœžœžœ˜4Kšœ& &˜Lš žœžœžœ9žœžœž˜]Kšœ0˜0Jšžœ˜—K˜K˜—š Ÿ œžœžœ?žœ žœžœ˜ˆšžœ ž˜Kšœ+˜+Kšœ%˜%Kšœ+˜+Kšžœžœ˜—K˜K˜—š Ÿœžœžœžœžœ˜WKšœžœžœ˜!Kšœžœ˜ Kšžœžœžœžœ˜Kšœžœ˜K˜šžœžœž˜Kšœ žœ˜ K˜ Kšžœ˜—Kšžœ˜ Kšœ  ˜K˜—š Ÿ œžœžœžœžœ™mKšœžœžœ™%K™ šžœžœž™šžœ žœ™Kš žœžœžœžœ  ™@K™Kšžœ™ Kšœ™—K™K™ Kšžœ™—Kšžœ™Kšœ™—K˜Kšžœ˜—…—Jz…