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.
��¾��GGObjectsImpl.mesa
Copyright c 1985 by Xerox Corporation.  All rights reserved.
Last edited by Bier on March 10, 1987 7:23:43 pm PST
Contents:  The procedural interface to the Gargoyle object modeler.
Stone, August 5, 1985 4:13:18 pm PDT
Pier, March 16, 1987 6:40:41 pm PST
Kurlander August 28, 1986 6:15:29 pm PDT

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.
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.
Removes the named entity from the scene.  If the entity is not on the list, no action is taken.

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 entity one step closer to the front in the priority order.
Moves the named entity 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.
list: LIST OF REF ANY _ List.Reverse[scene.entities]; -- KAP October 22, 1986
Returns the unique fence trajectory of outline.
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.
Doesn't work on Gargoyle slices.
Hit Testing -- Outline-Specific routines.  These should go away when Outlines become Slices.

Selections

this is a trick to make a copy of the list quickly. The list will be modified in place later on.

Pier, December 5, 1985 10:13:59 am PST
changes to: removed camera from definitions
Bier, January 7, 1986 4:42:32 pm PST
changes to: Reordered procedures to match GGObjects.
Ê ��˜�code™Kšœ
Ïmœ1™<K™4K™CK™$K™#K™(—K™�šÏk	˜	Jšœà˜àK˜�—šÏn
œžœž˜Jšžœƒ˜ŠKšžœž˜'—˜�Kšœ
žœ˜'Kšœžœžœ˜3Kšœžœ%˜?Kšœžœ˜(Kšœžœžœ˜/Kšœžœ#˜;Kšœžœžœ
˜Kšœžœžœ˜-Kšœžœ"˜9Kšœ
žœ˜)Kšœ	žœžœ˜Kšœžœ˜+Kšœžœ"˜9Kšœžœžœ˜1Kšœžœ$˜=Kšœžœ˜!Kšœ	žœžœ˜Kšœžœ!˜7Kšœžœ˜-Kšœ
žœžœ
˜!Kšœžœ"˜9Kšœ
žœ˜-Kšœžœ˜!Kšœžœ ˜5Kšœžœžœ˜-Kšœžœ"˜9Kšœžœžœ	˜Kšœ	žœÏc˜2Kšœžœžœ˜+Kšœžœ!˜7Kšœ	žœ˜%Kšœžœ˜#K˜�Kšœžœ!˜3K˜�šœÔžœÀ™™K™a—Kšœ
žœžœ
˜Kšœ
žœ˜-—K˜�KšŸœžœžœžœ˜(Kš
Ÿœžœžœžœžœ˜/Kšœžœ%˜6K˜�KšœÏb™ K™�KšŸœžœžœžœžœžœžœ™QKšŸœžœžœžœžœžœžœ™RK˜�Kšœ¡™K˜�KšœÃ™ÃK™�šŸœžœžœžœ˜9Kšœ	žœžœ˜3K˜K˜�—šŸ
œžœžœ/žœ
˜SKšœÂ™ÂKšžœžœ˜2šžœžœžœ˜Kšœžœ˜Kšœžœ˜/K˜—Kšžœžœ!˜,Kšœžœ˜K˜K˜�—šŸœžœžœ+žœ
˜MKšœ™Kšžœžœ˜0šžœžœžœ˜Kšœžœ˜Kšœžœ˜-K˜—Kšžœžœ!˜,Kšœžœ˜K˜K˜�—šŸœžœžœžœžœžœžœžœ
˜]KšœHžœÝ™§šžœžœ˜šžœžœžœžœžœžœžœž˜CKšœ ˜ Kšžœ˜—K˜—Kšžœžœ!˜,Kšœžœ˜K˜K˜�—šŸ	œžœžœžœžœžœ˜LKšœÇ™ÇKšžœžœ˜1šžœžœžœ˜Kšœžœ˜Kšœžœ˜.K˜—Kšžœžœ!˜,Kšœžœ˜K˜K˜�—šŸœžœžœžœ˜9šžœžœžœ ˜+Kš	žœžœžœ
žœž˜/šžœžœžœžœžœžœžœž˜GK˜Kšžœ˜—Kšœžœ˜Kšœ˜—KšœU˜UK˜K˜�—šŸœžœžœžœžœžœžœ˜ZKšžœžœžœ˜:šžœžœž˜Kšœ0˜0Kšœ*˜*Kšžœžœ˜—K˜K˜�—šŸœžœ˜,Jšœ(˜(Jšœžœ˜Jšœ+˜+šžœ	žœžœDžœ
žœž˜lšžœžœž˜Jšœ'˜'Jšœ-˜-Jšžœžœ˜—Jšœ˜Jšžœ˜—Jšœžœ˜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šœ<˜<Kšœžœ˜%—Kšœ˜KšœD˜DKšœžœ˜,Kšžœ˜—K˜K™�—š
Ÿœžœ"žœžœžœ
˜kK˜Kšœ˜Kšœ˜Kšœžœžœ	˜Kšœ,˜,Kšœ(˜(šžœGžœžœž˜]Kšžœžœžœ˜Kšœ ˜ KšœA˜AKšœD˜DKšžœ˜—K˜K˜�—šŸœžœ"žœ˜YK˜Kšœ˜Kšœ*˜*Kšœ!˜!KšœA˜AKšœ,˜,šžœGžœžœž˜]Kšžœžœžœ˜Kšœ ˜ Kšœ4˜4Kšžœ˜—K˜K˜�—šŸœžœžœžœ
žœ
žœžœ
˜ZK™(Kšœžœžœ	˜Kšœ	žœžœ	˜Kšžœ	žœžœžœ˜"Kšœ	žœžœ˜ Kšœ
˜
šžœžœžœžœžœž˜<Kšœ
žœ
žœ˜Kšœ˜Kšœ˜Kšžœ˜—Kšœ˜K˜K˜�—š
Ÿœžœžœžœžœ
˜HKšœžœ˜K˜K˜�—šŸœžœ$žœžœ
žœžœžœ
˜yšžœžœžœ˜Kš
žœžœžœžœžœ˜#Kšœžœ	žœ˜%Kšžœ˜K˜—šžœ˜Kšœ˜Kšœžœ	žœ˜Kšœ˜K˜—K˜K˜�——Kšœžœ /˜GšŸ	œžœžœ˜,K™WšŸœžœžœžœžœžœžœžœžœžœžœ˜JKš	œžœžœžœžœ˜!Kšœ*˜*šžœ	žœžœžœžœžœžœž˜CKšœG˜GKšžœ˜—Kšœ˜K˜—Kšœžœžœžœžœžœ˜šœžœ˜Kšœ˜Kšœ˜—Kšœ˜Kšžœžœžœžœžœžœžœžœ˜UKš	žœžœžœžœ ˜BK˜K˜�—š
Ÿœžœžœžœžœ˜AKšžœžœžœžœ˜=K˜K˜�—šŸœžœžœ˜+K™KKšžœžœžœ˜%Kšœ)˜)Kšœžœ˜Kšœ+˜+K˜K˜�—šŸœžœžœ#žœ˜[Kšœžœžœ˜4Kšœžœ.˜HKšœžœ<˜]Kšœžœ6˜TKšœžœ<˜]K˜K˜�—š
Ÿœžœžœžœžœ˜9K™JšÐbnœžœžœžœ˜CKšœžœžœžœžœžœ˜&šžœžœžœžœžœž˜Išžœžœ .˜JK˜Kš	žœžœžœžœ +˜DKšœ)˜)Kšžœ
žœžœžœ˜EK˜—Kšžœ˜Kšžœ˜—K˜—Kšœžœžœ˜šžœžœž˜Kšœ#˜#Kšœ)˜)Kšœ9˜9Kšœ@˜@Kšžœžœ˜—Kšœ*˜*K˜K˜�—š
Ÿœžœžœžœžœ˜;K™IšŸœžœžœžœ˜GKšœžœžœžœžœžœ˜)šžœžœžœžœžœžœžœž˜Gšžœžœ 2˜Nšžœžœž˜Kš
œžœžœ
žœžœ ˜Dšœžœžœ
žœ #˜EKšœIžœ˜PK˜—Kš
œžœžœ
žœžœ ˜>šœžœžœ
žœ %˜GKšœHžœ˜OKšœ˜—Kšžœžœ ˜)—K˜—Kšžœ+˜/Kšžœ˜—K˜—Kšœžœžœ˜šžœžœž˜Kšœ#˜#Kšœ)˜)Kšœ9˜9Kšœ@˜@Kšžœžœ˜—Kšœ.˜.K˜K˜�—K™�Kšœ ¡
™*K˜�šŸœžœžœžœ(˜fK™6Kš	œžœžœžœžœ8™Mšœžœ˜,Kšœ˜Kšœžœ˜K˜K˜—K˜K˜�—šŸ
œžœžœžœžœžœ˜HKš
žœ
žœžœžœžœ˜ šžœ˜Kšœ˜K˜K˜—K˜K˜�—š
Ÿœžœžœžœ	žœ˜FKšžœžœžœ
˜%Kšœ
˜
šžœžœžœžœžœžœžœž˜AKšœ˜Kšžœ˜—K˜K˜�—šŸ
œžœžœ
žœžœžœžœ˜<Kšœ/™/Kšžœžœž˜Kšœžœžœ˜+Kš	œžœžœžœžœ˜PKš	œžœžœžœžœ˜RKšœžœ˜5Kšžœžœ˜K˜K˜�—šŸœžœžœžœ˜QK™DKšœžœžœ ˜-šœ
žœ˜"Kšœ
˜
K˜—K˜K˜�—šŸœžœžœžœ$˜ZK™@Kšœžœžœ&˜3šœ
žœ˜(Kšœ
˜
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šœ˜Kšœžœ˜šžœžœžœžœžœ!žœžœž˜Ušžœžœž˜šœ˜Kšœ)žœ˜.Kšœžœ˜#K˜—˜Kšœ-žœ˜2Kšœžœ˜#K˜—Kšžœžœ˜—Kšžœ˜—K˜K˜�—š
Ÿœžœžœžœžœ˜VKšœ˜Kšœžœ˜šžœžœžœžœžœ!žœžœž˜Ušžœžœž˜šœ˜Kšœ)žœ˜.Kšœžœ˜#K˜—˜Kšœ-žœ˜2Kšœžœ˜#K˜—Kšžœžœ˜—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˜�—šŸœžœžœžœžœžœ
˜TKšœžœ˜šžœžœžœžœžœ!žœžœž˜Ušžœžœž˜šœ˜K˜—˜šžœžœžœ%žœ	žœž˜KKšœžœ˜'—Kšžœ˜K˜—Kšžœžœ˜—Kšžœ˜—K˜K˜�—šŸœžœžœžœžœžœ
˜]Kšœžœ˜šžœžœžœžœžœ!žœžœž˜Ušžœžœž˜šœ˜K˜—˜Kšœžœ˜)K˜—Kšžœžœ˜—Kšžœ˜—K˜K˜�—šŸœžœžœžœ
žœžœ˜WKšœžœ˜šžœžœžœžœžœ!žœžœž˜Ušžœžœž˜šœ˜K™ Kšœžœ˜#K˜—K˜Kšžœžœ˜—Kšžœ˜—K˜K˜�—š
Ÿœžœžœžœžœ˜QKšœ˜K˜K˜�—š
Ÿœžœžœžœžœ˜QKšœ!˜!K˜K˜�—š
Ÿœžœžœžœžœ
˜LKšœ
žœ˜š	žœžœž
œžœž˜7Kšœ
žœ(˜6Kšžœ˜—K˜—K˜�K™\K™�šŸœžœžœ?žœ˜|Kšœ"˜"Kšœ˜Jšœ*˜*Jšœžœ ˜5Kšœ”˜”Kšžœžœ	žœžœžœžœžœžœ ˜`K˜K˜�—K˜�K™
K™�šŸœžœžœ˜1šœ@žœ˜EK™`—K˜K˜�—šŸœžœžœ˜4Kš	œžœžœžœžœ˜AKšœ& &˜Lšžœžœžœžœžœ!žœžœž˜Mšžœžœž˜Kšœ?˜?KšœC˜CKšžœžœ˜—Jšžœ˜—K˜K˜�—šŸ
œžœžœ?žœžœžœžœžœ˜€šžœ
ž˜Kšœ+˜+Kšœ%˜%Kšœ+˜+Kšžœžœ˜—K˜K˜�—Kšžœ˜K™�™&Kšœ+™+—™$KšœÏr(™4——�…—����Ot��€R��