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; 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] = { 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. ` GGSelectImpl.mesa Contents: Procedures dealing selecting and deselecting objects, including both selection actions and selection feedback. Copyright Σ 1988, 1992 by Xerox Corporation. All rights reserved. Pier, November 10, 1988 4:41:22 pm PST Kurlander August 28, 1986 7:54:12 pm PDT Bier, June 22, 1989 9:22:07 pm PDT Implementation Notes (updated July 6, 1987, by Bier) The Selection mechanism maintains two "structures" which must be kept consistent. The first is a list of selected SliceDescriptors: scene.selected. The second is the set of "selectedInFull" fields in each of the selected slices. To efficiently answer IsSelectedInFull queries, "selectedInFull" fields are found in slices, segments, joints, and control points. IsSelectedInFull is expensive for trajectories, and more expensive for outlines. To efficiently answer IsSelectedInPart queries, the selectedInFull field does double duty in segments, joints, control points, and slices. IsSelectedInPart is somewhat expensive for outlines. The following invariants should be maintained: 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. Converse of 1: If no sequence representing a given joint, segment, or control point is on the selected list, then the selectedInFull field of that entity should be FALSE. 2) Only one sequence per trajectory may appear on the selected list. Corollary of 1 and 2: Any given selected flag is caused by a single element of the selected list. GetSelectedSequence will find that element (for joint, segments, and control points). A selected slice is its own cause. 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. These invariants will be maintained with the help of SetComponentSelectedFields. Basic Selecting and Deselecting Clear all flags that indicate the selection of each object. Remove this slice from the selected list, and reset all selected fields. Very much like DeselectSlice, but optimized for the single Traj case. Updating Selections When Sequences Become Obsolete This routine propogates the former selection (say, hotness) to a newly extended traj and extends the selection to its end if extend = TRUE. newOutlineD: SliceDescriptor; normal selections hot selections Ignore active and match selections Utilities Deletes entity from list. If it is not on the list, do nothing. Operations which dispatch on the SelectionClass: For each SliceDescriptor in selected that is not obsolete, re-establish that selection. Remember to call DeselectAll[scene, selectClass] if you wish to replace any existing selections. OPERATIONS THAT ALTER THE SELECTED LISTS Build the selection list in the proper order and keep it that way. Enumerate Selected Objects Returns TRUE if all or part of entity is selected. These are the cases: 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. Replaces a segment with a new run. If newRun is not NIL, then only one trajectory is modified, and the new trajectory is returned. Also returned is the bbox of modified Outlines. ΚZ•NewlineDelimiter –(cedarcode) style™codešœ™KšΟnœq™yKšœ Οeœ8™CKšœ&™&Kšœ%Οk™(K™"K™—šŸ ˜ Kšœ¬˜¬K˜—š œŸœŸ˜KšŸœR˜YKšŸœŸ˜&—˜Kšœ Ÿœ˜&KšœŸœ˜!KšœŸœ˜3KšœŸœ˜,KšœŸœ˜!Kšœ ŸœŸœ˜-Kšœ Ÿœ˜+Kšœ Ÿœ˜'KšœŸœ!˜7KšœŸœ!˜5Kšœ Ÿœ˜'KšœŸœ ˜7KšœŸœ#˜=KšœŸœ˜!KšœŸœ ˜5KšœŸœ)˜GKšœŸœ,˜MKšœŸœ#˜;KšœŸœ(˜EKšœŸœ˜3KšœŸœ"˜9Kšœ Ÿœ˜+KšœŸœ˜1KšœŸœ#˜;Kšœ Ÿœ˜'Kšœ Ÿœ˜%Kšœ Ÿœ˜)K˜KšœŸœŸœ˜AšœŸœŸœ˜,KšœŸœŸœ˜K˜—KšœŸœŸœ˜/šœŸœŸœ˜#KšœΟc)˜:Kšœ )˜AKšœ ˜7K˜K˜——K˜KšœŸœŸœŸœ˜(Iheadšœ4™4Kšœζ™ζKš œUΟbœ‘œ‘œ‘œS™ΤKšœΐ™ΐ™.KšœˆŸœ™›Kšœ₯Ÿœ™«K™EKšœέ™έK™6KšœxŸœ™}Kšœk™k—šœP™PK™—K˜K™K™šœŸœ;˜QšŸœ Ÿ˜K˜4K˜.K˜4K˜2KšŸœ˜—K˜K˜—š œŸœ0˜BšŸœ Ÿ˜Kšœ&Ÿœ˜*Kšœ Ÿœ˜$Kšœ&Ÿœ˜*Kšœ$Ÿœ˜(KšŸœ˜—K˜—K˜š œŸœŸœ0˜Fš  œŸœŸœŸœŸœ˜CKšœ-˜-K˜—Kšœ$Οtœ ’˜5šŸœŸœ˜šŸœŸœŸœŸ˜BKšŸœŸ˜$KšŸœ9˜=—K˜—K˜K˜—šœŸœŸœQ˜rK˜DKšœ(˜(KšŸœŸœT˜pK˜K˜—š œŸœŸœI˜aKšœ"˜"KšŸœŸœŸœŸœŸœ!ŸœŸœ˜SK˜@K˜9šŸœ ŸœŸœ˜K˜1KšœB ˜]K˜—KšŸœ˜KšŸœŸœ5˜QKšœ+˜+Kšœ%˜%KšŸœŸœT˜pKšœ ˜K˜—šœŸœŸœ>˜\Kšœ7Ÿœ ˜CKšœ*˜*K˜K™—šœŸœŸœG˜gš  œŸœŸœŸœŸœ˜NKšœ$˜$K˜—KšŸœŸœŸœ˜!Kšœ,’œ ’œ ’˜H˜K˜——š œŸœŸœ ŸœŸœ0˜\šŸœŸœŸ˜Kšœ?˜?KšœY˜YKšŸœŸœ˜—K˜K˜—š œŸœŸœ ŸœŸœ˜IKšœ&˜&Kšœ&˜&Kšœ#˜#Kšœ%˜%K˜K˜—š œŸœŸœ0˜HK™;š Ÿœ ŸœŸœAŸœ ŸœŸ˜iKšœ.˜.KšŸœ˜—KšœŸœ˜)K˜K˜—šœŸœŸœ˜5Kšœ˜Kšœ˜Kšœ˜Kšœ˜K˜K˜—šœŸœŸœ>˜^KšœH™HšŸœŸœ˜#K˜@šŸœ ŸœŸœ˜Kšœ,˜,Kšœ(˜(K˜—šŸœŸ˜šŸœŸœŸœ(˜NKšŸœŸœ˜%——K˜—šŸœ˜Kšœ6Ÿœ ˜BKšœ@˜@K˜—K˜K˜—š œŸœŸœQ˜kKšœ#˜#K•StartOfExpansion?[slice: GGModelTypes.Slice, parts: GGModelTypes.SliceParts]˜2K˜>K˜3šŸœŸœŸœ˜K˜/Kšœ*˜*Kšœ&˜&šŸœŸœŸœ˜+KšŸœŸœ3˜OKšœ*˜*Kšœ$˜$K˜—šŸœŸœ˜KšŸœŸœŸœ(˜NKšŸœZ˜^šŸœŸœŸœ3˜XKšŸœŸœ˜%—K˜—K˜—K˜K˜—š œŸœ=˜OKšœE™EK˜5K˜AšŸœŸœŸœ˜K˜8Kšœ*˜*Kšœ$˜$šŸœŸœŸœ˜+Kšœ*˜*Kšœ$˜$K˜—šŸœŸ˜šŸœŸœŸœ+˜QšŸœ˜K˜QšŸœŸœŸœ3˜XKšŸœŸœ˜%—K˜———K˜—K˜—K™™2K™—šœŸœŸœ!˜MK˜Kšœ"’œ˜*Kš œ!Ÿœ ŸœŸœŸœŸœ’œ˜UKšœ"’œ˜'Kš œ!Ÿœ ŸœŸœŸœŸœ’œ˜RKšœ"’œ˜*Kš œ!Ÿœ ŸœŸœŸœŸœ’œ˜UKšœ"’œ˜)Kš œ!Ÿœ ŸœŸœŸœŸœ’œ˜TKšœ˜K˜—š œŸœ;ŸœŸœŸœ˜wK–h[slice: GGModelTypes.Slice, scene: GGModelTypes.Scene, selectClass: GGSegmentTypes.SelectionClass]˜DšŸœŸœ˜#Kšœ0 ˜KKšœ7˜7Kšœ Ÿœ˜K˜—K˜K˜—šœŸœŸœ!˜EKšœ$‘œ˜,Kšœ$‘œ˜)Kšœ$‘œ˜,Kšœ$‘œ˜+K˜K˜—š  œŸœŸœ7ŸœŸœ˜tK™‹Kšœ™Kšœ˜Kšœ˜Kšœ$˜$K˜3Kš‘™šŸœŸœŸœ˜K˜:Kšœ*˜*K˜:Kšœ%˜%K˜—Kš‘™K˜0šŸœŸœŸœ˜K˜HKšœ( ˜DK˜CKšœ"˜"K˜—Kš‘"™"K˜—K˜™ K™—šœŸœI˜^K™@šœ˜Kšœ2˜2Kšœ ˜ —K˜K˜—šœ0™0K™—š  œŸœŸœ-ŸœŸœŸœ˜yšŸœ Ÿ˜K˜/K˜)K˜/K˜-KšŸœŸœ˜—K˜K˜—š  œŸœŸœ7ŸœŸœ˜kKšœΉ™Ήš ŸœŸœŸœ'ŸœŸœŸ˜KKšœ,˜,KšŸœ˜—K˜K˜—š œŸœŸœ#˜TšŸœ Ÿ˜K˜2K˜,K˜2K˜0KšŸœ˜—K˜K˜—šœŸœŸœ#˜VšŸœ Ÿ˜K˜0K˜*K˜0K˜.KšŸœ˜—K˜K˜—K™(K™šœŸœI˜^K™BšŸœ Ÿ˜šœ ˜ šŸœŸœŸœ˜%KšœŸœ ˜%K˜1Kšœ Ÿœ˜%K˜—šŸœŸœŸœ˜,Kšœ Ÿœ ˜-K˜9K˜—šŸœ˜K˜FKšœ Ÿœ ˜-K˜9Kšœ Ÿœ˜%K˜—K˜—šœ˜šŸœŸœŸœ˜"KšœŸœ ˜"K˜+KšœŸœ˜"K˜—šŸœŸœŸœ˜)KšœŸœ ˜*K˜3K˜—šŸœ˜K˜@KšœŸœ ˜*K˜3KšœŸœ˜"K˜—K˜—šœ ˜ šŸœŸœŸœ˜%KšœŸœ ˜%K˜1Kšœ Ÿœ˜%K˜—šŸœŸœŸœ˜,Kšœ Ÿœ ˜-K˜9K˜—šŸœ˜K˜FKšœ Ÿœ ˜-K˜9Kšœ Ÿœ˜%K˜—K˜—šœ ˜ šŸœŸœŸœ˜$KšœŸœ ˜$K˜/KšœŸœ˜$K˜—šŸœŸœŸœ˜+KšœŸœ ˜,K˜7K˜—šŸœ˜K˜DKšœŸœ ˜,K˜7KšœŸœ˜$K˜—K˜—KšŸœŸœ˜—K˜K˜—šœŸœŸœŸœŸœŸœŸœ˜kKš ŸœŸœ ŸœŸœŸœ˜BK˜K˜—šœŸœŸœŸœ2˜ešŸœ Ÿ˜šœ ˜ K˜Kšœ Ÿœ˜&K˜—šœ˜K˜KšœŸœ˜#K˜—šœ ˜ K˜Kšœ Ÿœ˜&K˜—šœ ˜ K˜KšœŸœ˜%K˜—KšŸœŸœ˜—K˜—K˜™K˜—š œŸœŸœ;ŸœŸœ˜jšœŸœ Ÿ˜5Kšœ"˜"Kšœ$˜$Kšœ˜Kšœ$˜$KšŸœŸœ˜—Kš ŸœŸœŸœŸœŸœ˜'KšŸœ)˜/K˜K˜—šœŸœŸœ ŸœŸœ-ŸœŸœ˜mKšœŸœ<™HKšœ@™@KšœF™FKšœ?™?Kšœ=™=KšŸœŸœŸ˜šœ˜K˜@KšŸœ Ÿœ˜K˜—šœ˜Kšœ˜K˜5KšŸœŸœ˜K˜—šœ˜Kšœ˜K˜=KšŸœŸœŸœŸœ˜"Kš Ÿœ ŸœŸœŸœŸœ˜#KšŸœ"˜(K˜—KšŸœŸœ˜K˜K™—š  œŸœŸœ-ŸœŸœ˜XšŸœ Ÿ˜Kšœ ŸœŸœ˜.KšœŸœŸœ˜(Kšœ ŸœŸœ˜.Kšœ ŸœŸœ˜,KšŸœŸœ˜—K˜K˜—šœŸœ:Ÿœ 7˜§š  œŸœŸœŸœŸœ˜LšŸœŸœ˜K˜ KšœŸœ˜ K˜—K˜—Kšœ+’œ’˜NK˜K˜—šœŸœŸœ-Ÿœ˜pšŸœ Ÿ˜K˜-K˜'K˜-K˜+KšŸœŸœ˜—Kšœ˜K˜—šœŸœŸœŸœ˜RK˜#K˜K˜—š œŸœŸœŸœŸœ%˜†Jšœ5Ÿœ|™΄Kšœ ŸœŸœ˜KšœŸœ ˜'K˜EK˜CK˜-Kšœ˜Kšœ Ÿœ*˜7K˜Kšœ8˜8K˜"K˜K˜'K˜)Kšœ'˜'šŸœ ŸœŸœ˜Kšœ.˜.Kšœ+˜+K˜—K˜'K˜K˜—š œŸœ ŸœŸœŸœ˜OK˜!š ŸœŸœŸœŸœŸœŸ˜AK–<[bBox: GGBasicTypes.BoundBox, by: GGBasicTypes.BoundBox]šœM˜MKšŸœ˜—K˜—K˜šœŸœŸœŸœŸœŸœŸœ˜iKšœŸœŸœŸœ˜%K˜ šŸœŸœŸ˜šŸœ Ÿœ˜Kš ŸœŸœŸœŸœ  ˜@K˜KšŸœ˜ Kšœ˜—K˜K˜ KšŸœ˜—KšŸœ˜Kšœ˜—K˜KšŸœ˜—…—GΈjr