<> <> <> <> <> <> <> <<>> 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]; < RETURN[outline.parent = NIL OR outline.parent.parent = NIL];>> < RETURN[traj.parent.parent = NIL OR traj.parent.parent.parent = NIL];>> < RETURN[IsTopLevel[seq.traj.parent]];>> < 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; 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]; }; <> <> <> <> < {>> <<};>> < {>> <> <> <> <<};>> < ERROR;>> <> <<};>> <<>> 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; }; <> <> <> <> < {>> <<};>> < {>> <> <<};>> < ERROR;>> <> <<};>> <<>> 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; }; <> <> <> <> < {>> <> <> <<};>> < {};>> < ERROR;>> <> <<};>> <<>> 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]; <