<> <> <> <> <> <> <> <<>> DIRECTORY GGAlign, GGBasicTypes, GGBoundBox, GGInterfaceTypes, GGModelTypes, GGMultiGravity, GGObjects, GGOutline, GGSceneType, GGSegment, GGSegmentTypes, GGSelect, GGSequence, GGTraj, GGUtility, GList, Imager, ImagerPath, List, Rope; GGObjectsImpl: CEDAR PROGRAM IMPORTS GGAlign, GGBoundBox, GGMultiGravity, GGObjects, GGOutline, GGSegment, GGSelect, GGSequence, GGTraj, GGUtility, GList, Imager, List EXPORTS GGObjects, GGModelTypes = BEGIN BoundBox: TYPE = GGModelTypes.BoundBox; BoundBoxGenerator: TYPE = REF BoundBoxGeneratorObj; BoundBoxGeneratorObj: TYPE = GGModelTypes.BoundBoxGeneratorObj; CurveType: TYPE = {line, bezier, conic}; EntityGenerator: TYPE = REF EntityGeneratorObj; EntityGeneratorObj: TYPE = GGModelTypes.EntityGeneratorObj; Joint: TYPE = REF JointObj; JointGenerator: TYPE = REF JointGeneratorObj; JointGeneratorObj: TYPE = GGModelTypes.JointGeneratorObj; JointObj: TYPE = GGSegmentTypes.JointObj; Outline: TYPE = REF OutlineObj; OutlineObj: TYPE = GGModelTypes.OutlineObj; OutlineDescriptor: TYPE = GGModelTypes.OutlineDescriptor; OutlineGenerator: TYPE = REF OutlineGeneratorObj; OutlineGeneratorObj: TYPE = GGModelTypes.OutlineGeneratorObj; Point: TYPE = GGBasicTypes.Point; 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; 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; GargoyleData: TYPE = GGInterfaceTypes.GargoyleData; <> <> SceneRef: TYPE = REF SceneObj; SceneObj: PUBLIC TYPE = GGSceneType.SceneObj; NotYetImplemented: PUBLIC SIGNAL = CODE; Problem: PUBLIC SIGNAL [msg: Rope.ROPE] = CODE; fillColor: PUBLIC Imager.Color _ Imager.MakeGray[0.5]; <> <<>> <> <> <> <> <<>> 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 AppendEntity[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 AppendEntity[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; }; AddEntities: PUBLIC PROC [scene: SceneRef, entities: LIST OF REF ANY, priority: INT _ -1] = { <> IF priority = -1 THEN { FOR list: LIST OF REF ANY _ entities, list.rest UNTIL list = NIL DO AppendEntity[scene, list.first]; ENDLOOP; } ELSE SIGNAL Problem["Not yet implemented."]; scene.prioritiesValid _ FALSE; }; AddEntity: PUBLIC PROC [scene: SceneRef, entity: REF ANY, priority: INT] = { <> 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; }; AppendEntity: PROC [scene: SceneRef, entity: REF ANY] = { IF NOT scene.ptrValid THEN { -- restore ptr IF scene.entities=NIL THEN scene.ptr _ NIL ELSE FOR list: LIST OF REF ANY _ scene.entities, list.rest UNTIL list=NIL DO scene.ptr _ list; ENDLOOP; scene.ptrValid _ TRUE; }; [scene.entities, scene.ptr] _ GGUtility.AddEntity[entity, scene.entities, scene.ptr]; }; EntityPriority: PUBLIC PROC [scene: SceneRef, entity: REF ANY] RETURNS [priority: INT] = { IF NOT scene.prioritiesValid THEN UpdatePriorities[scene]; WITH entity SELECT FROM outline: Outline => priority _ outline.priority; slice: Slice => priority _ slice.priority; ENDCASE => ERROR; }; UpdatePriorities: PROC [scene: SceneRef] = { entityGen: GGModelTypes.EntityGenerator; index: NAT _ 0; entityGen _ TopLevelEntitiesInScene[scene]; FOR entity: REF ANY _ GGObjects.NextEntity[entityGen], GGObjects.NextEntity[entityGen] UNTIL entity = NIL DO WITH entity SELECT FROM slice: Slice => slice.priority _ index; outline: Outline => outline.priority _ index; ENDCASE => ERROR; index _ index + 1; ENDLOOP; scene.prioritiesValid _ TRUE; }; DeleteEntity: PUBLIC PROC [scene: SceneRef, entity: REF ANY] = { <> scene.ptrValid _ FALSE; scene.entities _ List.DRemove[entity, scene.entities]; scene.prioritiesValid _ FALSE; }; DeleteOutline: PUBLIC PROC [scene: SceneRef, outline: Outline] = { DeleteEntity[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.fillColor]; 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 _ GGObjects.NextTraj[trajGen], GGObjects.NextTraj[trajGen] UNTIL traj = NIL DO IF traj = except THEN LOOP; newTraj _ GGTraj.CopyTraj[traj]; newOutline _ GGOutline.CreateOutline[newTraj, outline.fillColor]; [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.fillColor]; holeGen _ GGOutline.HolesOfOutline[outline]; FOR hole: Traj _ GGObjects.NextTraj[holeGen], GGObjects.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] = { <> CopyList: PROC [list: LIST OF REF ANY] RETURNS [copy: LIST OF REF ANY] = { entityList, ptr: LIST OF REF ANY; [entityList, ptr] _ GGUtility.StartList[]; FOR entity: LIST OF REF ANY _ list, entity.rest UNTIL entity=NIL DO [entityList, ptr] _ GGUtility.AddEntity[entity.first, entityList, ptr]; ENDLOOP; copy _ entityList; }; tList: LIST OF LIST OF REF ANY; scene.oldEntities _ CONS[ CopyList[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, entity: REF ANY] = { <> ExchangeWithNextEntity: PROC [scene: SceneRef, entity: REF ANY] = { previous, next: LIST OF REF ANY _ NIL; FOR list: LIST OF REF ANY _ scene.entities, list.rest UNTIL list = NIL DO IF list.first=entity 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; }; trueEntity: REF ANY; WITH entity SELECT FROM slice: Slice => trueEntity _ slice; outline: Outline => trueEntity _ outline; traj: Traj => trueEntity _ GGOutline.OutlineOfTraj[traj]; seq: Sequence => trueEntity _ GGOutline.OutlineOfTraj[seq.traj]; ENDCASE => ERROR; ExchangeWithNextEntity[scene, trueEntity]; }; DownOne: PUBLIC PROC [scene: SceneRef, entity: REF ANY] = { <> ExchangeWithPreviousEntity: PROC [scene: SceneRef, entity: REF ANY] = { preprev, previous: LIST OF REF ANY _ NIL; FOR list: LIST OF REF ANY _ scene.entities, list.rest UNTIL list=NIL DO IF list.first=entity 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; }; trueEntity: REF ANY; WITH entity SELECT FROM slice: Slice => trueEntity _ slice; outline: Outline => trueEntity _ outline; traj: Traj => trueEntity _ GGOutline.OutlineOfTraj[traj]; seq: Sequence => trueEntity _ GGOutline.OutlineOfTraj[seq.traj]; ENDCASE => ERROR; ExchangeWithPreviousEntity[scene, trueEntity]; }; <<>> <> TopLevelEntitiesInScene: PUBLIC PROC [scene: SceneRef] RETURNS [entityGenerator: EntityGenerator] = { <> <> entityGenerator _ NEW[EntityGeneratorObj _ [ list: scene.entities, countValid: FALSE, count: 0 ]]; }; 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; }; IsTopLevel: PUBLIC PROC [entity: REF ANY] RETURNS [BOOL] = { <> WITH entity SELECT FROM slice: Slice => RETURN[slice.parent = NIL]; 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; }; 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; allBoxes _ NIL; FOR entities: LIST OF REF ANY _ scene.entities, entities.rest UNTIL entities = NIL DO WITH entities.first SELECT FROM slice: Slice => { thisBox _ slice.class.getBoundBox[slice, NIL]; allBoxes _ CONS[thisBox, allBoxes]; }; outline: Outline => { thisBox _ outline.class.getBoundBox[outline, NIL]; allBoxes _ CONS[thisBox, allBoxes]; }; ENDCASE => ERROR; ENDLOOP; }; ListTightBoxesInScene: PROC [scene: SceneRef] RETURNS [allBoxes: LIST OF BoundBox] = { thisBox: BoundBox; allBoxes _ NIL; FOR entities: LIST OF REF ANY _ scene.entities, entities.rest UNTIL entities = NIL DO WITH entities.first SELECT FROM slice: Slice => { thisBox _ slice.class.getTightBox[slice, NIL]; allBoxes _ CONS[thisBox, allBoxes]; }; outline: Outline => { thisBox _ outline.class.getTightBox[outline, NIL]; allBoxes _ CONS[thisBox, allBoxes]; }; ENDCASE => ERROR; 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: PUBLIC 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; }; ListOutlinesInScene: PUBLIC 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; }; ListSlicesInScene: PUBLIC 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 => { <> allSlices _ CONS[slice, allSlices]; }; outline: Outline => {}; ENDCASE => ERROR; ENDLOOP; }; ListTrajsInOutline: PROC [outline: Outline] RETURNS [trajList: LIST OF Traj] = { trajList _ outline.children; }; ListHolesOfOutline: PROC [outline: Outline] RETURNS [trajList: LIST OF Traj] = { trajList _ outline.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, gargoyleData: GargoyleData] RETURNS [traj: Traj] = { feature: GGModelTypes.FeatureData; resultPoint: Point; sceneObjects: GGInterfaceTypes.TriggerBag; sceneObjects _ NARROW[gargoyleData.hitTest.sceneBag]; [resultPoint, feature] _ GGMultiGravity.StrictDistance[worldPt, gargoyleData.hitTest.criticalR, GGAlign.emptyObjectBag, sceneObjects, gargoyleData]; RETURN[IF feature=NIL OR feature.type=slice THEN NIL ELSE NARROW[feature.shape, Sequence].traj]; }; <> <<>> SaveSelections: PUBLIC PROC [scene: SceneRef] = { scene.savedSelected.normal _ List.Append[scene.selected.normal, NIL]; <> }; RestoreSelections: PUBLIC PROC [scene: SceneRef] = { normalSelectedList: LIST OF REF ANY _ scene.savedSelected.normal; GGSelect.DeselectAll[scene, normal]; -- get rid of any transient selections FOR list: LIST OF REF ANY _ normalSelectedList, list.rest UNTIL list = NIL DO WITH list.first SELECT FROM cD: SliceDescriptor => GGSelect.SelectSlice[cD, scene, normal]; oD: OutlineDescriptor => GGSelect.SelectOutline[oD, scene, normal]; ENDCASE => ERROR; ENDLOOP; }; GetSelections: PUBLIC PROC [scene: SceneRef, selectClass: GGSegmentTypes.SelectionClass] RETURNS [selected: LIST OF REF ANY] = { SELECT selectClass FROM normal => selected _ scene.selected.normal; hot => selected _ scene.selected.hot; active => selected _ scene.selected.active; ENDCASE => ERROR; }; END. <<>> <> <> <> <>