GGOutlineImplB.mesa
Copyright © 1986 by Xerox Corporation. All rights reserved.
Last edited by Bier on January 22, 1987
Contents: Procedures to implement the Outline Slice Class in Gargoyle. Outlines consist of Trajectories which in turn consist of Segments. Outline is the most important slice class.
DIRECTORY
GGBasicTypes, Feedback, GGInterfaceTypes, GGModelTypes, GGOutline, GGScene, GGSelect, GGSegmentTypes, GGSequence, GGSlice, GGTraj, GGUtility, GList, Imager, Rope;
GGOutlineImplB: CEDAR PROGRAM
IMPORTS Feedback, GGScene, GGSlice, GGOutline, GGSelect, GGSequence, GGTraj, GGUtility, GList
EXPORTS GGOutline = BEGIN
OPEN GGOutline;
BitVector: TYPE = GGBasicTypes.BitVector;
BoundBox: TYPE = GGBasicTypes.BoundBox;
CameraData: TYPE = GGModelTypes.CameraData;
Circle: TYPE = GGBasicTypes.Circle;
Color: TYPE = Imager.Color;
ControlPointGenerator: TYPE = GGModelTypes.ControlPointGenerator;
FeatureData: TYPE = GGInterfaceTypes.FeatureData;
GGData: TYPE = GGInterfaceTypes.GGData;
Joint: TYPE = GGSegmentTypes.Joint;
JointGenerator: TYPE = GGModelTypes.JointGenerator;
Line: TYPE = GGBasicTypes.Line;
AlignBag: TYPE = GGInterfaceTypes.AlignBag;
Outline: TYPE = REF OutlineObj;
OutlineObj: TYPE = GGModelTypes.OutlineObj;
OutlineClass: TYPE = REF OutlineClassObj;
OutlineClassObj: TYPE = GGModelTypes.OutlineClassObj;
OutlineData: TYPE = GGOutline.OutlineData;
OutlineDataObj: TYPE = GGOutline.OutlineDataObj;
OutlineDescriptor: TYPE = GGModelTypes.OutlineDescriptor;
OutlineDescriptorObj: TYPE = GGModelTypes.OutlineDescriptorObj;
OutlineParts: TYPE = REF OutlinePartsObj;
OutlinePartsObj: TYPE = GGOutline.OutlinePartsObj;
OutlineSequence: TYPE = GGSelect.OutlineSequence;
OutlineSequenceGenerator: TYPE = GGSelect.OutlineSequenceGenerator;
Point: TYPE = GGBasicTypes.Point;
PointGenerator: TYPE = GGModelTypes.PointGenerator;
PointPairGenerator: TYPE = GGModelTypes.PointPairGenerator;
Scene: TYPE = GGModelTypes.Scene;
Segment: TYPE = GGSegmentTypes.Segment;
SegmentGenerator: TYPE = GGModelTypes.SegmentGenerator;
SelectMode: TYPE = GGModelTypes.SelectMode;
SelectionClass: TYPE = GGSegmentTypes.SelectionClass;
Sequence: TYPE = GGModelTypes.Sequence;
Slice: TYPE = GGModelTypes.Slice;
SliceClass: TYPE = REF SliceClassObj;
SliceClassObj: TYPE = GGModelTypes.SliceClassObj;
SliceDescriptor: TYPE = GGModelTypes.SliceDescriptor;
SliceParts: TYPE = GGModelTypes.SliceParts;
Traj: TYPE = REF TrajObj;
TrajEnd: TYPE = GGModelTypes.TrajEnd;
TrajGenerator: TYPE = REF TrajGeneratorObj;
TrajGeneratorObj: TYPE = GGModelTypes.TrajGeneratorObj;
TrajObj: TYPE = GGModelTypes.TrajObj;
TrajPartType: TYPE = GGModelTypes.TrajPartType;
TriggerBag: TYPE = GGInterfaceTypes.TriggerBag;
Vector: TYPE = GGBasicTypes.Vector;
OutlineDescribeProc: TYPE = GGModelTypes.OutlineDescribeProc;
OutlineFileoutProc: TYPE = GGModelTypes.OutlineFileoutProc;
OutlineFileinProc: TYPE = GGModelTypes.OutlineFileinProc;
OutlineUnionPartsProc: TYPE = GGModelTypes.OutlineUnionPartsProc;
OutlineDifferencePartsProc: TYPE = GGModelTypes.OutlineDifferencePartsProc;
OutlineAugmentPartsProc: TYPE = GGModelTypes.OutlineAugmentPartsProc;
OutlinePointsInDescriptorProc: TYPE = GGModelTypes.OutlinePointsInDescriptorProc;
OutlinePointPairsInDescriptorProc: TYPE = GGModelTypes.OutlinePointPairsInDescriptorProc;
OutlineNextPointProc: TYPE = GGModelTypes.OutlineNextPointProc;
OutlineNextPointPairProc: TYPE = GGModelTypes.OutlineNextPointPairProc;
OutlineClosestPointProc: TYPE = GGModelTypes.OutlineClosestPointProc;
OutlineClosestPointAndTangentProc: TYPE = GGModelTypes.OutlineClosestPointAndTangentProc;
OutlineClosestSegmentProc: TYPE = GGModelTypes.OutlineClosestSegmentProc;
OutlineSetArrowsProc: TYPE = GGModelTypes.OutlineSetArrowsProc;
OutlineGetArrowsProc: TYPE = GGModelTypes.OutlineGetArrowsProc;
Problem: PUBLIC SIGNAL [msg: Rope.ROPE] = Feedback.Problem;
Outline-Only operations.
UnpackOnePointDescriptor: PUBLIC PROC [outlineD: SliceDescriptor] RETURNS [traj: Traj, isACP: BOOL, segNum, cpNum, jointNum: NAT] = {
outlineD describes either a single control point or a single joint. Return the [segNum, cpNum] pair or the jointNum as appropriate.
parts: OutlineParts;
theSeq: Sequence;
IF outlineD = NIL OR outlineD.slice.class.type#$Outline THEN RETURN[NIL, FALSE, 999, 999, 999];
parts ← NARROW[outlineD.parts];
traj ← NIL;
FOR list: LIST OF Sequence ← parts.seqs, list.rest UNTIL list = NIL DO
IF list.first # NIL THEN {
IF traj # NIL THEN RETURN[NIL, FALSE, 999, 999, 999]
ELSE {
theSeq ← list.first;
traj ← theSeq.traj;
[isACP, segNum, cpNum, jointNum] ← GGSequence.UnpackOnePointSequence[theSeq];
};
};
ENDLOOP;
};
UnpackSimpleDescriptorOld: PUBLIC PROC [outlineD: OutlineDescriptor] RETURNS [success: BOOL, partType: TrajPartType, traj: Traj, joint: Joint ← NIL, jointNum: NAT ← 999, cp: Point, cpNum: NAT ← 999, seg: Segment ← NIL, segNum: NAT ← 999] = {
parts: OutlineParts;
theSeq: Sequence;
IF outlineD = NIL THEN RETURN[FALSE, joint, NIL, NIL, 999, [0,0]];
parts ← NARROW[outlineD.parts];
traj ← NIL;
FOR list: LIST OF Sequence ← parts.seqs, list.rest UNTIL list = NIL DO
IF list.first # NIL THEN {
IF traj # NIL THEN RETURN[FALSE, joint, NIL, NIL, 999, [0,0]]
ELSE {
theSeq ← list.first;
traj ← theSeq.traj;
[success, partType, traj, joint, jointNum, cp, cpNum, seg, segNum] ← GGSequence.UnpackSimpleSequence[theSeq];
};
};
ENDLOOP;
};
UnpackSimpleDescriptor: PUBLIC PROC [outlineD: SliceDescriptor] RETURNS [success: BOOL, partType: TrajPartType, traj: Traj, joint: Joint ← NIL, jointNum: NAT ← 999, cp: Point, cpNum: NAT ← 999, seg: Segment ← NIL, segNum: NAT ← 999] = {
parts: OutlineParts; -- list of seq
theSeq: Sequence;
IF outlineD = NIL OR outlineD.slice.class.type#$Outline THEN RETURN[FALSE, joint, NIL, NIL, 999, [0,0]];
parts ← NARROW[outlineD.parts];
traj ← NIL;
FOR list: LIST OF Sequence ← parts.seqs, list.rest UNTIL list = NIL DO
IF list.first # NIL THEN {
IF traj # NIL THEN RETURN[FALSE, joint, NIL, NIL, 999, [0,0]]
ELSE {
theSeq ← list.first;
traj ← theSeq.traj;
[success, partType, traj, joint, jointNum, cp, cpNum, seg, segNum] ← GGSequence.UnpackSimpleSequence[theSeq];
};
};
ENDLOOP;
};
UnpackOneSegmentDescriptor: PUBLIC PROC [outlineD: SliceDescriptor] RETURNS [traj: Traj, segNum: NAT] = {
outlineD describes either a single control point or a single joint. Return the [segNum, cpNum] pair or the jointNum as appropriate.
parts: OutlineParts;
theSeq: Sequence;
IF outlineD = NIL OR outlineD.slice.class.type#$Outline THEN RETURN[NIL, 999];
parts ← NARROW[outlineD.parts];
traj ← NIL;
FOR list: LIST OF Sequence ← parts.seqs, list.rest UNTIL list = NIL DO
IF list.first # NIL THEN {
IF traj # NIL THEN RETURN[NIL, 999]
ELSE {
theSeq ← list.first;
traj ← theSeq.traj;
[segNum] ← GGSequence.UnpackOneSegmentSequence[theSeq];
};
};
ENDLOOP;
};
FindTrajInDescriptor: PUBLIC PROC [outlineD: OutlineDescriptor, traj: Traj] RETURNS [seq: Sequence] = {
outlineParts: OutlineParts;
outlineParts ← NARROW[outlineD.parts];
FOR list: LIST OF Sequence ← outlineParts.seqs, list.rest UNTIL list = NIL DO
IF list.first # NIL AND list.first.traj = traj THEN RETURN[list.first];
ENDLOOP;
RETURN[NIL];
};
PartsFromSequence: PUBLIC PROC [outline: Outline, seq: Sequence] RETURNS [sliceParts: SliceParts] = {
realParts: OutlineParts;
ptr: LIST OF Sequence;
trajGen: GGModelTypes.TrajGenerator;
sliceParts ← realParts ← NEW[OutlinePartsObj];
[realParts.seqs, ptr] ← GGUtility.StartSequenceList[];
trajGen ← TrajsInOutline[outline];
FOR traj: Traj ← GGScene.NextTraj[trajGen], GGScene.NextTraj[trajGen] UNTIL traj = NIL DO
IF traj = seq.traj THEN [realParts.seqs, ptr] ← GGUtility.AddSequence[seq, realParts.seqs, ptr]
ELSE [realParts.seqs, ptr] ← GGUtility.AddSequence[NIL, realParts.seqs, ptr];
ENDLOOP;
};
DescriptorFromSequence: PUBLIC PROC [outline: Outline, seq: Sequence] RETURNS [sliceD: OutlineDescriptor] = {
outlineParts: SliceParts;
outlineParts ← PartsFromSequence[outline, seq];
sliceD ← GGSlice.DescriptorFromParts[outline, outlineParts];
};
DescriptorFromParts: PUBLIC PROC [outline: Outline, sliceParts: SliceParts] RETURNS [sliceD: OutlineDescriptor] = {
sliceD ← NEW[OutlineDescriptorObj ← [outline, sliceParts]];
};
CopyParts: PUBLIC PROC [outline: Outline, parts: SliceParts] RETURNS [copy: SliceParts] = {
realParts, realCopyParts: OutlineParts;
copySeq: Sequence;
ptr: LIST OF Sequence;
realParts ← NARROW[parts];
copy ← realCopyParts ← NEW[OutlinePartsObj];
[realCopyParts.seqs, ptr] ← GGUtility.StartSequenceList[];
FOR list: LIST OF Sequence ← realParts.seqs, list.rest UNTIL list = NIL DO
IF list.first = NIL THEN [realCopyParts.seqs, ptr] ← GGUtility.AddSequence[NIL, realCopyParts.seqs, ptr]
ELSE {
copySeq ← GGSequence.Copy[list.first];
[realCopyParts.seqs, ptr] ← GGUtility.AddSequence[copySeq, realCopyParts.seqs, ptr]
};
ENDLOOP;
};
AddHole: PUBLIC PROC [outline: Outline, hole: Traj] RETURNS [holier: Outline] = {
Holes can be removed using DeleteSequence.
Should check for duplicates. -- Bier, February 20
holier ← outline.class.copy[outline];
holier.children ← AppendTrajList[holier.children, LIST[hole]];
hole.parent ← holier;
hole.role ← hole;
UpdateBoundBox[holier];
};
AddHole: PUBLIC PROC [outline: Outline, hole: Traj] RETURNS [holier: Outline] = {
Holes can be removed using DeleteSequence.
Should check for duplicates. -- Bier, February 20
holyData: OutlineData;
holier ← outline.class.copy[outline];
holyData ← NARROW[holier.data, OutlineData];
holyData.children ← AppendTrajList[holyData.children, LIST[hole]];
hole.parent ← holier;
hole.role ← hole;
UpdateBoundBox[holier];
};
ReplaceFence: PUBLIC PROC [outline: Outline, newFence: Traj] RETURNS [newOutline: Outline] = {
Like CopyOutline except in one place.
newData: OutlineData;
holeGen: TrajGenerator;
newTraj: Traj;
newOutline ← GGOutline.CreateOutline[newFence, NARROW[outline.data, OutlineData].fillColor];
newData ← NARROW[newOutline.data];
holeGen ← HolesOfOutline[outline];
FOR hole: Traj ← GGScene.NextTraj[holeGen], GGScene.NextTraj[holeGen] UNTIL hole = NIL DO
newTraj ← GGTraj.CopyTraj[hole];
newData.children ← AppendTrajList[newData.children, LIST[newTraj]];
newTraj.parent ← newOutline;
ENDLOOP;
UpdateBoundBox[newOutline];
};
ReplaceHole: PUBLIC PROC [outline: Outline, oldHole, newHole: Traj] RETURNS [newOutline: Outline] = {
Like CopyOutline except in one place.
newData: OutlineData;
holeGen: TrajGenerator;
newTraj, fence: Traj;
fence ← FenceOfOutline[outline];
newTraj ← GGTraj.CopyTraj[fence];
newOutline ← CreateOutline[newTraj, NARROW[outline.data, OutlineData].fillColor];
newData ← NARROW[newOutline.data];
holeGen ← HolesOfOutline[outline];
FOR hole: Traj ← GGScene.NextTraj[holeGen], GGScene.NextTraj[holeGen] UNTIL hole = NIL DO
IF hole = oldHole THEN {
newData.children ← AppendTrajList[newData.children, LIST[newHole]];
newHole.parent ← newOutline;
}
ELSE {
newTraj ← GGTraj.CopyTraj[hole];
newData.children ← AppendTrajList[newData.children, LIST[newTraj]];
newTraj.parent ← newOutline;
};
ENDLOOP;
UpdateBoundBox[newOutline];
};
OutlineOfTraj: PUBLIC PROC [traj: Traj] RETURNS [outline: Outline] = {
Finds the unique outline to which traj belongs.
outline ← traj.parent;
};
TrajectoriesOfOutline: PUBLIC PROC [outline: Slice] RETURNS [children: LIST OF Traj] = {
IF outline.class.type#$Outline THEN ERROR; -- temporary check
children ← NARROW[outline.data, OutlineData].children;
};
SaveSelectionsInOutline: PUBLIC PROC [outline: Slice, scene: Scene] = {
outlineD: OutlineDescriptor;
outlineParts: OutlineParts;
hotness.
IF outline.class.type#$Outline THEN ERROR;
outlineD ← GGSelect.FindSelectedSlice[outline, scene, hot];
ClearSelectionInOutline[outline, hot];
IF outlineD # NIL THEN {
outlineParts ← NARROW[outlineD.parts];
FOR seqList: LIST OF Sequence ← outlineParts.seqs, seqList.rest UNTIL seqList = NIL DO
IF seqList.first#NIL THEN GGTraj.SaveSelectionInSequence[seqList.first, hot];
ENDLOOP;
};
normal selection.
outlineD ← GGSelect.FindSelectedSlice[outline, scene, normal];
ClearSelectionInOutline[outline, normal];
IF outlineD # NIL THEN {
outlineParts ← NARROW[outlineD.parts];
FOR seqList: LIST OF Sequence ← outlineParts.seqs, seqList.rest UNTIL seqList = NIL DO
IF seqList.first#NIL THEN GGTraj.SaveSelectionInSequence[seqList.first, normal];
ENDLOOP;
};
active selection.
outlineD ← GGSelect.FindSelectedSlice[outline, scene, active];
ClearSelectionInOutline[outline, active];
IF outlineD # NIL THEN {
outlineParts ← NARROW[outlineD.parts];
FOR seqList: LIST OF Sequence ← outlineParts.seqs, seqList.rest UNTIL seqList = NIL DO
IF seqList.first#NIL THEN GGTraj.SaveSelectionInSequence[seqList.first, active];
ENDLOOP;
};
};
ClearSelectionInOutline: PROC [outline: Slice, selectClass: SelectionClass] = {
trajGen: GGModelTypes.TrajGenerator;
IF outline.class.type#$Outline THEN ERROR;
trajGen ← TrajsInOutline[outline];
FOR traj: Traj ← GGScene.NextTraj[trajGen], GGScene.NextTraj[trajGen] UNTIL traj = NIL DO
GGTraj.ClearSelection[traj, selectClass];
ENDLOOP;
};
RemakeSelectionsFromOutline: PUBLIC PROC [outline: Outline, scene: Scene] = {
This outline has just been created by copying parts from an existing outline. The selection information was copied as well. Make sequences from the selection bits, and select these sequences.
trajGen: GGModelTypes.TrajGenerator;
trajGen ← TrajsInOutline[outline];
FOR traj: Traj ← GGScene.NextTraj[trajGen], GGScene.NextTraj[trajGen] UNTIL traj = NIL DO
hotness.
GGTraj.RemakeSelection[traj, scene, hot];
normal selection.
GGTraj.RemakeSelection[traj, scene, normal];
active selection.
GGTraj.RemakeSelection[traj, scene, active];
ENDLOOP;
};
SequencesOfOutline: PUBLIC PROC [sliceD: OutlineDescriptor] RETURNS [seqList: LIST OF Sequence] = {
outlineParts: OutlineParts ← NARROW[sliceD.parts];
ptr: LIST OF Sequence;
[seqList, ptr] ← GGUtility.StartSequenceList[];
FOR list: LIST OF Sequence ← outlineParts.seqs, list.rest UNTIL list = NIL DO
IF list.first # NIL THEN [seqList, ptr] ← GGUtility.AddSequence[list.first, seqList, ptr];
ENDLOOP;
};
RemoveTraj: PUBLIC PROC [outlineD: OutlineDescriptor, traj: Traj] RETURNS [newD: OutlineDescriptor] = {
Used by GGSelect to do a DeselectTraj.
outlineParts: OutlineParts ← NARROW[outlineD.parts];
seq: Sequence;
FOR list: LIST OF Sequence ← outlineParts.seqs, list.rest UNTIL list = NIL DO
IF list.first#NIL AND list.first.traj = traj THEN {
seq ← list.first;
GOTO Done;
};
REPEAT
Done => {
newSeqs: LIST OF Sequence ← NARROW[GList.Subst[NIL, seq, outlineParts.seqs]];
newParts: SliceParts ← NEW[OutlinePartsObj ← [newSeqs]];
newD ← GGSlice.DescriptorFromParts[outlineD.slice, newParts];
};
FINISHED => newD ← outlineD;
ENDLOOP;
};
UnpackHitData: PUBLIC PROC [hitData: REF ANY] RETURNS [traj: Traj, hitType: TrajPartType, segNum, cpNum, jointNum: INT, hitPoint: Point] = {
This will go away when the Caret machinery is revised.
outlineHitData: OutlineHitData ← NARROW[hitData];
traj ← outlineHitData.traj;
hitType ← outlineHitData.hitType;
segNum ← outlineHitData.segNum;
cpNum ← outlineHitData.cpNum;
jointNum ← outlineHitData.jointNum;
hitPoint ← outlineHitData.hitPoint;
};
UpdateDescriptorBoundBoxes: PUBLIC PROC [outlineD: OutlineDescriptor] = {
Update the bound boxes of all contained sequences.
parts: OutlineParts ← NARROW[outlineD.parts];
FOR list: LIST OF Sequence ← parts.seqs, list.rest UNTIL list = NIL DO
IF list.first # NIL THEN GGSequence.UpdateBoundBox[list.first];
ENDLOOP;
};
Queries about Outlines.
HasHoles: PUBLIC PROC [outline: Outline] RETURNS [BOOL] = {
data: OutlineData ← NARROW[outline.data];
RETURN[data.children.rest # NIL];
};
FenceOfOutline: PUBLIC PROC [outline: Outline] RETURNS [fence: Traj] = {
Returns the unique fence trajectory of outline.
data: OutlineData ← NARROW[outline.data];
RETURN[data.children.first];
};
HolesOfOutline: PUBLIC PROC [outline: Outline] RETURNS [trajGen: TrajGenerator] = {
Generates all of the holes of outline.
data: OutlineData ← NARROW[outline.data];
list: LIST OF Traj ← data.children.rest;
trajGen ← NEW[TrajGeneratorObj ← [
list: list
]];
};
TrajsInOutline: PUBLIC PROC [outline: Outline] RETURNS [trajGen: TrajGenerator] = {
Generates the fence and all of the holes of outline.
data: OutlineData ← NARROW[outline.data];
list: LIST OF Traj ← data.children;
trajGen ← NEW[TrajGeneratorObj ← [
list: list
]];
};
END.