<> <> <> <> <> <> <<>> DIRECTORY GGBasicTypes, GGBoundBox, GGCoreTypes, GGModelTypes, GGOutline, GGParent, GGScene, GGSceneType, GGSegmentTypes, GGSelect, GGSequence, GGSlice, GGSliceOps, GGTraj, TextNode; GGSelectImpl: CEDAR PROGRAM IMPORTS GGBoundBox, GGOutline, GGParent, GGScene, GGSequence, GGSlice, GGSliceOps, GGTraj EXPORTS GGModelTypes, GGSelect = BEGIN BoundBox: TYPE = GGCoreTypes.BoundBox; Joint: TYPE = GGModelTypes.Joint; JointGenerator: TYPE = GGModelTypes.JointGenerator; OutlineParts: TYPE = GGOutline.OutlineParts; Scene: TYPE = GGModelTypes.Scene; SceneObj: PUBLIC TYPE = GGSceneType.SceneObj; SegAndIndex: TYPE = GGSequence.SegAndIndex; Segment: TYPE = GGSegmentTypes.Segment; SegmentGenerator: TYPE = GGModelTypes.SegmentGenerator; SelectionClass: TYPE = GGSegmentTypes.SelectionClass; Sequence: TYPE = GGModelTypes.Sequence; SequenceGenerator: TYPE = GGSequence.SequenceGenerator; SequenceGeneratorObj: TYPE = GGSequence.SequenceGeneratorObj; Slice: TYPE = GGModelTypes.Slice; SliceDescriptor: TYPE = GGModelTypes.SliceDescriptor; SliceDescriptorGenerator: TYPE = GGModelTypes.SliceDescriptorGenerator; SliceDescriptorGeneratorObj: TYPE = GGModelTypes.SliceDescriptorGeneratorObj; SliceDescriptorObj: TYPE = GGModelTypes.SliceDescriptorObj; SliceDescriptorWalkProc: TYPE = GGModelTypes.SliceDescriptorWalkProc; SliceGenerator: TYPE = GGModelTypes.SliceGenerator; SliceGeneratorObj: TYPE = GGModelTypes.SliceGeneratorObj; SliceParts: TYPE = GGModelTypes.SliceParts; SliceWalkProc: TYPE = GGModelTypes.SliceWalkProc; SlicePartsWalkProc: TYPE = GGModelTypes.SlicePartsWalkProc; TrajData: TYPE = GGModelTypes.TrajData; TrajEnd: TYPE = GGModelTypes.TrajEnd; TrajParts: TYPE = GGModelTypes.TrajParts; OutlineSequenceGenerator: TYPE = REF OutlineSequenceGeneratorObj; OutlineSequenceGeneratorObj: TYPE = RECORD [ list: LIST OF OutlineSequence ]; OutlineSequence: TYPE = REF OutlineSequenceObj; OutlineSequenceObj: TYPE = RECORD [ outline: Slice, -- the outline represented by this record fenceParts: TrajParts, -- included parts of the fence trajectory holeParts: LIST OF TrajParts -- included parts of holes ]; NotYetImplemented: PUBLIC SIGNAL = CODE; <> <> <> <> <> <<1) If a SliceDescriptor is on the selected list, all of the selectedInFull fields of its joints, segments, and control points should be TRUE. The selected fields are maintained for efficiency only. The information they represent is always obtainable from the selected list as well.>> <> <<2) Only one sequence per trajectory may appear on the selected list.>> <> <<3) A slice may only appear once on the selected list.>> <<4) Iff a sequence representing a trajectory is on the selected list, the "selectedInPart" field of the trajectory will TRUE.>> <<5) Iff a non-Outline slice is on the selected list, the "selectedInFull" field of that slice will be true.>> <> <<>> <> <<>> ChangeDonkeyTail: PROC [sliceD: SliceDescriptor, selectClass: SelectionClass] = { SELECT selectClass FROM normal => sliceD.slice.normalSelectedParts _ sliceD; hot => sliceD.slice.hotSelectedParts _ sliceD; active => sliceD.slice.activeSelectedParts _ sliceD; match => sliceD.slice.matchSelectedParts _ sliceD; ENDCASE; }; NoDonkeyTail: PROC [slice: Slice, selectClass: SelectionClass] = { SELECT selectClass FROM normal => slice.normalSelectedParts _ NIL; hot => slice.hotSelectedParts _ NIL; active => slice.activeSelectedParts _ NIL; match => slice.matchSelectedParts _ NIL; ENDCASE; }; SelectAll: PUBLIC PROC [scene: Scene, selectClass: SelectionClass] = { DoSelectSlice: PROC [slice: Slice] RETURNS [done: BOOL _ FALSE] = { SelectEntireSlice[slice, scene, selectClass]; }; [] _ GGScene.WalkSlices[scene, first, DoSelectSlice]; IF selectClass = normal THEN { IF scene.selected.normal = NIL OR scene.selected.normal.rest # NIL THEN scene.selected.normalLast _ NIL ELSE scene.selected.normalLast _ scene.selected.normal.first; }; }; SelectSliceFromParts: PUBLIC PROC [slice: Slice, parts: SliceParts, scene: Scene, selectClass: SelectionClass] = { sliceD: SliceDescriptor _ GGSlice.DescriptorFromParts[slice, parts]; SelectSlice[sliceD, scene, selectClass]; IF selectClass = normal THEN scene.selected.normalLast _ GGParent.TopLevelDescriptorFromChildDescriptor[sliceD]; }; SelectSlice: PUBLIC PROC [sliceD: SliceDescriptor, scene: Scene, selectClass: SelectionClass] = { oldSliceD, union: SliceDescriptor; IF sliceD=NIL OR sliceD.parts = NIL OR GGSliceOps.IsEmptyParts[sliceD] THEN RETURN; sliceD _ GGParent.TopLevelDescriptorFromChildDescriptor[sliceD]; oldSliceD _ FindSelectedSlice[sliceD.slice, selectClass]; IF oldSliceD#NIL THEN { union _ GGSliceOps.UnionParts[oldSliceD, sliceD]; DeselectSlice[sliceD.slice, oldSliceD.parts, scene, selectClass]; -- throw away old selection } ELSE union _ sliceD; IF selectClass = normal THEN union _ GGSliceOps.AugmentParts[union, selectClass]; AppendSelection[scene, union, selectClass]; ChangeDonkeyTail[union, selectClass]; IF selectClass = normal THEN scene.selected.normalLast _ GGParent.TopLevelDescriptorFromChildDescriptor[sliceD]; }; -- end SelectSlice SelectEntireSlice: PUBLIC PROC [slice: Slice, scene: Scene, selectClass: SelectionClass] = { allParts: SliceDescriptor _ GGSliceOps.NewParts[slice, NIL, slice]; SelectSlice[allParts, scene, selectClass]; }; <<>> DuplicateSelections: PUBLIC PROC [scene: Scene, fromClass: SelectionClass, toClass: SelectionClass] = { DoSelectSlice: PROC [sliceD: SliceDescriptor] RETURNS [done: BOOL _ FALSE] = { SelectSlice[sliceD, scene, toClass]; }; IF fromClass=toClass THEN RETURN; [] _ GGScene.WalkSelectedSlices[scene, first, DoSelectSlice, fromClass]; }; DeselectEntity: PUBLIC PROC [entity: REF ANY, scene: Scene, selectClass: SelectionClass] = { WITH entity SELECT FROM slice: Slice => DeselectEntireSlice[slice, scene, selectClass]; sliceD: SliceDescriptor => DeselectSlice[sliceD.slice, sliceD.parts, scene, selectClass]; ENDCASE => ERROR; }; DeselectEntityAllClasses: PUBLIC PROC [entity: REF ANY, scene: Scene] = { DeselectEntity[entity, scene, normal]; DeselectEntity[entity, scene, active]; DeselectEntity[entity, scene, hot]; DeselectEntity[entity, scene, match]; }; DeselectAll: PUBLIC PROC [scene: Scene, selectClass: SelectionClass] = { <> FOR sliceD: LIST OF SliceDescriptor _ ListSelected[scene, selectClass], sliceD.rest UNTIL sliceD = NIL DO NoDonkeyTail[sliceD.first.slice, selectClass]; ENDLOOP; SetSelectedList[scene, NIL, selectClass]; }; DeselectAllAllClasses: PUBLIC PROC [scene: Scene] = { DeselectAll[scene, normal]; DeselectAll[scene, active]; DeselectAll[scene, hot]; DeselectAll[scene, match]; }; DeselectEntireSlice: PUBLIC PROC [slice: Slice, scene: Scene, selectClass: SelectionClass] = { <> IF GGScene.IsTopLevel[slice] THEN { sliceD: SliceDescriptor _ FindSelectedSlice[slice, selectClass]; IF sliceD # NIL THEN { DeleteSelection[scene, sliceD, selectClass]; NoDonkeyTail[sliceD.slice, selectClass]; }; IF selectClass = normal THEN IF scene.selected.normalLast # NIL AND scene.selected.normalLast.slice = slice THEN scene.selected.normalLast _ NIL; } ELSE { entireD: SliceDescriptor _ GGSliceOps.NewParts[slice, NIL, slice]; DeselectSlice[entireD.slice, entireD.parts, scene, selectClass]; }; }; DeselectSlice: PUBLIC PROC [slice: Slice, parts: SliceParts, scene: Scene, selectClass: SelectionClass] = { oldD, newD, tempD: SliceDescriptor; tempD _ GGSlice.DescriptorFromParts[slice, parts]; tempD _ GGParent.TopLevelDescriptorFromChildDescriptor[tempD]; oldD _ FindSelectedSlice[tempD.slice, selectClass]; IF oldD#NIL THEN { newD _ GGSliceOps.DifferenceParts[oldD, tempD]; DeleteSelection[scene, oldD, selectClass]; NoDonkeyTail[oldD.slice, selectClass]; IF NOT GGSliceOps.IsEmptyParts[newD] THEN { IF selectClass = normal THEN newD _ GGSliceOps.AugmentParts[newD, selectClass]; AppendSelection[scene, newD, selectClass]; ChangeDonkeyTail[newD, selectClass]; }; IF selectClass = normal THEN { IF scene.selected.normalLast # NIL AND scene.selected.normalLast.slice = slice THEN scene.selected.normalLast _ GGSliceOps.DifferenceParts[scene.selected.normalLast, tempD]; IF scene.selected.normalLast = NIL OR GGSliceOps.IsEmptyParts[scene.selected.normalLast] THEN scene.selected.normalLast _ NIL; }; }; }; DeselectTraj: PROC [traj: Slice, scene: Scene, selectClass: SelectionClass] = { <> ancestor: Slice _ GGParent.GetTopLevelAncestor[traj]; oldD: SliceDescriptor _ FindSelectedSlice[ancestor, selectClass]; IF oldD#NIL THEN { newD: SliceDescriptor _ GGParent.RemoveTraj[oldD, traj]; DeleteSelection[scene, oldD, selectClass]; NoDonkeyTail[ancestor, selectClass]; IF NOT GGSliceOps.IsEmptyParts[newD] THEN { AppendSelection[scene, newD, selectClass]; ChangeDonkeyTail[newD, selectClass]; }; IF selectClass = normal THEN IF scene.selected.normalLast # NIL AND scene.selected.normalLast.slice = ancestor THEN { scene.selected.normalLast _ GGParent.RemoveTraj[scene.selected.normalLast, traj]; IF scene.selected.normalLast = NIL OR GGSliceOps.IsEmptyParts[scene.selected.normalLast] THEN scene.selected.normalLast _ NIL; }; }; }; <<>> <> <<>> SaveSelectionsInSliceAllClasses: PUBLIC PROC [slice: Slice, scene: Scene] = { sliceD: SliceDescriptor; sliceD _ FindSelectedSlice[slice, normal]; GGSliceOps.SaveSelections[slice, IF sliceD = NIL THEN NIL ELSE sliceD.parts, normal]; sliceD _ FindSelectedSlice[slice, hot]; GGSliceOps.SaveSelections[slice, IF sliceD = NIL THEN NIL ELSE sliceD.parts, hot]; sliceD _ FindSelectedSlice[slice, active]; GGSliceOps.SaveSelections[slice, IF sliceD = NIL THEN NIL ELSE sliceD.parts, active]; sliceD _ FindSelectedSlice[slice, match]; GGSliceOps.SaveSelections[slice, IF sliceD = NIL THEN NIL ELSE sliceD.parts, match]; }; RemakeSelections: PROC [slice: Slice, scene: Scene, selectClass: SelectionClass] RETURNS [isTopLevel: BOOL _ FALSE] = { parts: SliceParts _ GGSliceOps.RemakeSelections[slice, selectClass]; IF GGScene.IsTopLevel[slice] THEN { DeselectEntireSlice[slice, scene, selectClass]; -- get rid of old selection SelectSliceFromParts[slice, parts, scene, selectClass]; isTopLevel _ TRUE; }; }; ReselectSliceAllClasses: PUBLIC PROC [slice: Slice, scene: Scene] = { [] _ RemakeSelections[slice, scene, normal]; [] _ RemakeSelections[slice, scene, hot]; [] _ RemakeSelections[slice, scene, active]; [] _ RemakeSelections[slice, scene, match]; }; ReselectTraj: PUBLIC PROC [traj: Slice, trajEnd: TrajEnd, scene: Scene, extend: BOOL] RETURNS [newHot: Sequence] = { <> <> newTrajD: SliceDescriptor; selSeq: Sequence; newSeqParts, newHotParts: TrajParts; selSeq _ FindSelectedSequence[traj, scene, normal]; <> IF selSeq#NIL THEN { newSeqParts _ GGSequence.Augment[selSeq, trajEnd, extend]; DeselectTraj[selSeq.slice, scene, normal]; newTrajD _ GGSlice.DescriptorFromParts[traj, newSeqParts]; SelectSlice[newTrajD, scene, normal]; }; <> selSeq _ FindSelectedSequence[traj, scene, hot]; IF selSeq#NIL THEN { newHotParts _ newSeqParts _ GGSequence.Augment[selSeq, trajEnd, extend]; DeselectTraj[selSeq.slice, scene, hot]; -- assumes second level Traj newTrajD _ newHot _ GGSlice.DescriptorFromParts[traj, newSeqParts]; SelectSlice[newTrajD, scene, hot]; }; <> }; <> <<>> DeleteSelection: PROC [scene: Scene, entity: SliceDescriptor, selectClass: SelectionClass] = { <> SetSelectedList[scene, DRemove[entity, ListSelected[scene, selectClass]], selectClass]; }; <> <<>> ListSelected: PUBLIC PROC [scene: Scene, selectClass: SelectionClass] RETURNS [selectedList: LIST OF SliceDescriptor] = { SELECT selectClass FROM normal => selectedList _ scene.selected.normal; hot => selectedList _ scene.selected.hot; active => selectedList _ scene.selected.active; match => selectedList _ scene.selected.match; ENDCASE => ERROR; }; SetSelected: PUBLIC PROC [scene: Scene, selectClass: SelectionClass, selected: LIST OF SliceDescriptor] = { <> FOR list: LIST OF SliceDescriptor _ selected, list.rest UNTIL list = NIL DO SelectSlice[list.first, scene, selectClass]; ENDLOOP; }; SetJointField: PROC [joint: Joint, selected: BOOL, selectClass: SelectionClass] = { SELECT selectClass FROM normal => joint.TselectedInFull.normal _ selected; hot => joint.TselectedInFull.hot _ selected; active => joint.TselectedInFull.active _ selected; match => joint.TselectedInFull.match _ selected; ENDCASE; }; SetSegmentField: PROC [seg: Segment, selected: BOOL, selectClass: SelectionClass] = { SELECT selectClass FROM normal => seg.TselectedInFull.normal _ selected; hot => seg.TselectedInFull.hot _ selected; active => seg.TselectedInFull.active _ selected; match => seg.TselectedInFull.match _ selected; ENDCASE; }; <> <<>> AppendSelection: PROC [scene: Scene, entity: SliceDescriptor, selectClass: SelectionClass] = { <> SELECT selectClass FROM normal => { IF scene.selected.normal = NIL THEN { scene.selected.normal _ LIST[entity]; scene.selected.normalPtr _ scene.selected.normal; scene.selected.normalPtrValid _ TRUE; } ELSE IF scene.selected.normalPtrValid THEN { scene.selected.normalPtr.rest _ LIST[entity]; scene.selected.normalPtr _ scene.selected.normalPtr.rest; } ELSE { scene.selected.normalPtr _ LastSliceDescriptor[scene.selected.normal]; scene.selected.normalPtr.rest _ LIST[entity]; scene.selected.normalPtr _ scene.selected.normalPtr.rest; scene.selected.normalPtrValid _ TRUE; }; }; hot => { IF scene.selected.hot = NIL THEN { scene.selected.hot _ LIST[entity]; scene.selected.hotPtr _ scene.selected.hot; scene.selected.hotPtrValid _ TRUE; } ELSE IF scene.selected.hotPtrValid THEN { scene.selected.hotPtr.rest _ LIST[entity]; scene.selected.hotPtr _ scene.selected.hotPtr.rest; } ELSE { scene.selected.hotPtr _ LastSliceDescriptor[scene.selected.hot]; scene.selected.hotPtr.rest _ LIST[entity]; scene.selected.hotPtr _ scene.selected.hotPtr.rest; scene.selected.hotPtrValid _ TRUE; }; }; active => { IF scene.selected.active = NIL THEN { scene.selected.active _ LIST[entity]; scene.selected.activePtr _ scene.selected.active; scene.selected.activePtrValid _ TRUE; } ELSE IF scene.selected.activePtrValid THEN { scene.selected.activePtr.rest _ LIST[entity]; scene.selected.activePtr _ scene.selected.activePtr.rest; } ELSE { scene.selected.activePtr _ LastSliceDescriptor[scene.selected.active]; scene.selected.activePtr.rest _ LIST[entity]; scene.selected.activePtr _ scene.selected.activePtr.rest; scene.selected.activePtrValid _ TRUE; }; }; match => { IF scene.selected.match = NIL THEN { scene.selected.match _ LIST[entity]; scene.selected.matchPtr _ scene.selected.match; scene.selected.matchPtrValid _ TRUE; } ELSE IF scene.selected.matchPtrValid THEN { scene.selected.matchPtr.rest _ LIST[entity]; scene.selected.matchPtr _ scene.selected.matchPtr.rest; } ELSE { scene.selected.matchPtr _ LastSliceDescriptor[scene.selected.match]; scene.selected.matchPtr.rest _ LIST[entity]; scene.selected.matchPtr _ scene.selected.matchPtr.rest; scene.selected.matchPtrValid _ TRUE; }; }; ENDCASE => ERROR; }; LastSliceDescriptor: PROC [sliceDList: LIST OF SliceDescriptor] RETURNS [last: LIST OF SliceDescriptor] = { FOR last _ sliceDList, last.rest UNTIL last.rest = NIL DO ENDLOOP; }; SetSelectedList: PROC [scene: Scene, value: LIST OF SliceDescriptor, selectClass: SelectionClass] = { SELECT selectClass FROM normal => { scene.selected.normal _ value; scene.selected.normalPtrValid _ FALSE; }; hot => { scene.selected.hot _ value; scene.selected.hotPtrValid _ FALSE; }; active => { scene.selected.active _ value; scene.selected.activePtrValid _ FALSE; }; match => { scene.selected.match _ value; scene.selected.matchPtrValid _ FALSE; }; ENDCASE => ERROR; }; <> IsSelectedInFull: PUBLIC PROC [slice: Slice, scene: Scene, selectClass: SelectionClass] RETURNS [BOOL] = { donkeyTail: SliceDescriptor _ SELECT selectClass FROM match => slice.matchSelectedParts, active => slice.activeSelectedParts, hot => slice.hotSelectedParts, normal => slice.normalSelectedParts, ENDCASE => ERROR; IF donkeyTail = NIL THEN RETURN[FALSE]; RETURN[GGSliceOps.IsCompleteParts[donkeyTail]]; }; IsSelectedInPart: PUBLIC PROC [entity: REF ANY, scene: Scene, selectClass: SelectionClass] RETURNS [BOOL] = { <> <<1) entity is a slice. Some outline is selected all or in part.>> <<2) entity is an outline. Some trajectory is selected all or in part.>> <<3) entity is a trajectory. Some joint or segment is selected.>> <<4) entity is a sequence. Some joint or segment is selected.>> WITH entity SELECT FROM slice: Slice => { sliceD: SliceDescriptor _ FindSelectedSlice[slice, selectClass]; RETURN[sliceD # NIL]; }; traj: Slice => { seq: Sequence; seq _ FindSelectedSequence[traj, scene, selectClass]; RETURN[seq # NIL]; }; seq: Sequence => { selSeq: Sequence; selSeq _ FindSelectedSequence[seq.slice, scene, selectClass]; IF selSeq = seq THEN RETURN[TRUE]; IF selSeq = NIL THEN RETURN[FALSE]; RETURN[GGSequence.Overlap[seq, selSeq]]; }; ENDCASE => ERROR; }; <<>> NoSelections: PUBLIC PROC [scene: Scene, selectClass: SelectionClass] RETURNS [BOOL] = { SELECT selectClass FROM normal => RETURN[scene.selected.normal = NIL]; hot => RETURN[scene.selected.hot = NIL]; active => RETURN[scene.selected.active = NIL]; match => RETURN[scene.selected.match = NIL]; ENDCASE => ERROR; }; FindSelectedSequence: PROC [traj: Slice, scene: Scene, selectClass: SelectionClass] RETURNS [seq: Sequence] = { -- returns SliceDescriptor for a trajectory if selected LookForTraj: PROC [sliceD: SliceDescriptor] RETURNS [done: BOOL _ FALSE] = { IF sliceD.slice=traj THEN { seq _ sliceD; done _ TRUE; }; }; [] _ GGScene.WalkSelectedSlices[scene, leaf, LookForTraj, selectClass, $Traj]; }; FindSelectedSlice: PUBLIC PROC [slice: Slice, selectClass: SelectionClass] RETURNS [sliceD: SliceDescriptor] = { SELECT selectClass FROM normal => sliceD _ slice.normalSelectedParts; hot => sliceD _ slice.hotSelectedParts; active => sliceD _ slice.activeSelectedParts; match => sliceD _ slice.matchSelectedParts; ENDCASE => ERROR; }; GetLastSelection: PUBLIC PROC [scene: Scene] RETURNS [sliceD: SliceDescriptor] = { sliceD _ scene.selected.normalLast; }; SubstituteForSegment: PUBLIC PROC [traj: Slice, segNum: NAT, newRun: Slice, scene: Scene] RETURNS [bBox: BoundBox, newTraj: Slice] = { <> newOutlines: LIST OF Slice; trajData: TrajData _ NARROW[traj.data]; runParts: TrajParts _ GGSequence.CreateFromSegment[trajData, segNum]; run: SliceDescriptor _ GGSlice.DescriptorFromParts[traj, runParts]; oldOutline: Slice _ GGParent.GetParent[traj]; newOutline: Slice; priority: INT _ GGScene.GetPriority[scene, oldOutline]; GGOutline.SaveSelectionsInOutlineAllClasses[oldOutline]; DeselectTraj[traj, scene, normal]; DeselectTraj[traj, scene, hot]; newTraj _ GGTraj.SpliceIn[run, newRun]; newOutline _ GGParent.GetParent[newTraj]; GGScene.DeleteSlice[scene, oldOutline]; IF newOutline#NIL THEN { GGScene.AddSlice[scene, newOutline, priority]; ReselectSliceAllClasses[newOutline, scene]; }; bBox _ BoundBoxOfOutlines[newOutlines]; }; BoundBoxOfOutlines: PROC [outlines: LIST OF Slice] RETURNS [bBox: BoundBox] = { bBox _ GGBoundBox.NullBoundBox[]; FOR list: LIST OF Slice _ outlines, list.rest UNTIL list = NIL DO GGBoundBox.EnlargeByBox[bBox: bBox, by: GGSliceOps.GetBoundBox[list.first] ]; ENDLOOP; }; DRemove: 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]; }; END.