DIRECTORY Feedback, FeedbackTypes, FS, GGBasicTypes, GGBoundBox, GGCoreOps, GGCoreTypes, GGHistoryTypes, GGInterfaceTypes, GGModelTypes, GGOutline, GGParent, GGParseIn, GGParseOut, GGScene, GGSegmentTypes, GGSequence, GGShapes, GGSlice, GGSliceOps, GGTraj, GGUtility, Imager, ImagerPath, ImagerTransformation, IO, Rope, TextNode, TiogaImager; GGOutlineImplA: CEDAR PROGRAM IMPORTS Feedback, FS, GGBoundBox, GGCoreOps, GGOutline, GGParent, GGParseIn, GGParseOut, GGScene, GGSequence, GGShapes, GGSlice, GGSliceOps, GGTraj, GGUtility, Imager, IO, Rope EXPORTS GGSlice, GGOutline, GGParent = BEGIN AlignBag: TYPE = GGInterfaceTypes.AlignBag; BitVector: TYPE = GGBasicTypes.BitVector; BoundBox: TYPE = GGCoreTypes.BoundBox; Camera: TYPE = GGModelTypes.Camera; Circle: TYPE = GGBasicTypes.Circle; Color: TYPE = Imager.Color; ControlPointGenerator: TYPE = GGModelTypes.ControlPointGenerator; DefaultData: TYPE = GGModelTypes.DefaultData; EditConstraints: TYPE = GGModelTypes.EditConstraints; FeatureData: TYPE = GGInterfaceTypes.FeatureData; MsgRouter: TYPE = FeedbackTypes.MsgRouter; GGData: TYPE = GGInterfaceTypes.GGData; HistoryEvent: TYPE = GGHistoryTypes.HistoryEvent; HitType: TYPE = GGModelTypes.TrajPartType; Joint: TYPE = GGSegmentTypes.Joint; JointGenerator: TYPE = GGModelTypes.JointGenerator; Line: TYPE = GGCoreTypes.Line; OutlineData: TYPE = GGOutline.OutlineData; OutlineDataObj: TYPE = GGOutline.OutlineDataObj; OutlineHitData: TYPE = GGOutline.OutlineHitData; OutlineHitDataObj: TYPE = GGOutline.OutlineHitDataObj; OutlineParts: TYPE = GGOutline.OutlineParts; OutlinePartsObj: TYPE = GGOutline.OutlinePartsObj; Point: TYPE = GGBasicTypes.Point; PointAndDone: TYPE = GGModelTypes.PointAndDone; PointGenerator: TYPE = GGModelTypes.PointGenerator; PointGeneratorObj: TYPE = GGModelTypes.PointGeneratorObj; PointPairAndDone: TYPE = GGModelTypes.PointPairAndDone; PointPairGenerator: TYPE = GGModelTypes.PointPairGenerator; PointPairGeneratorObj: TYPE = GGModelTypes.PointPairGeneratorObj; PointWalkProc: TYPE = GGModelTypes.PointWalkProc; Scene: TYPE = GGModelTypes.Scene; Segment: TYPE = GGSegmentTypes.Segment; SegmentGenerator: TYPE = GGModelTypes.SegmentGenerator; SegmentGeneratorObj: TYPE = GGModelTypes.SegmentGeneratorObj; SelectionClass: TYPE = GGSegmentTypes.SelectionClass; SelectMode: TYPE = GGModelTypes.SelectMode; SequenceGenerator: TYPE = GGSequence.SequenceGenerator; SequenceOfReal: TYPE = GGCoreTypes.SequenceOfReal; Slice: TYPE = GGModelTypes.Slice; SliceClass: TYPE = GGModelTypes.SliceClass; SliceClassObj: TYPE = GGModelTypes.SliceClassObj; SliceDescriptor: TYPE = GGModelTypes.SliceDescriptor; SliceDescriptorGenerator: TYPE = GGModelTypes.SliceDescriptorGenerator; SliceGenerator: TYPE = GGModelTypes.SliceGenerator; SliceObj: TYPE = GGModelTypes.SliceObj; SliceParts: TYPE = GGModelTypes.SliceParts; StrokeEnd: TYPE = Imager.StrokeEnd; StrokeJoint: TYPE = Imager.StrokeJoint; Traj: TYPE = GGModelTypes.Traj; TrajData: TYPE = GGModelTypes.TrajData; TrajEnd: TYPE = GGModelTypes.TrajEnd; TrajParts: TYPE = GGModelTypes.TrajParts; TrajPartType: TYPE = GGModelTypes.TrajPartType; Transformation: TYPE = ImagerTransformation.Transformation; TriggerBag: TYPE = GGInterfaceTypes.TriggerBag; Vector: TYPE = GGBasicTypes.Vector; WalkProc: TYPE = GGModelTypes.WalkProc; MoveToProc: TYPE = ImagerPath.MoveToProc; LineToProc: TYPE = ImagerPath.LineToProc; CurveToProc: TYPE = ImagerPath.CurveToProc; ConicToProc: TYPE = ImagerPath.ConicToProc; ArcToProc: TYPE = ImagerPath.ArcToProc; ClusterData: TYPE = REF ClusterDataObj; ClusterDataObj: TYPE = GGSlice.ClusterDataObj; Problem: PUBLIC SIGNAL [msg: Rope.ROPE] = Feedback.Problem; BuildOutlineSliceClass: PUBLIC PROC [] RETURNS [class: SliceClass] = { class ¬ NEW[SliceClassObj ¬ [ type: $Outline, unlink: GGParent.Unlink, getBoundBox: GGParent.GetBoundBox, getTransformedBoundBox: GGParent.GetTransformedBoundBox, getTightBox: GGParent.GetTightBox, copy: OutlineCopy, restore: GGParent.Restore, buildPath: OutlineBuildPath, drawBorder: OutlineDrawBorder, drawParts: OutlineDrawParts, drawTransform: OutlineDrawTransform, drawSelectionFeedback: OutlineDrawSelectionFeedback, drawAttractorFeedback: GGParent.DrawAttractorFeedback, attractorFeedbackBoundBox: GGParent.AttractorFeedbackBoundBox, saveSelections: GGParent.SaveSelections, remakeSelections: GGParent.RemakeSelections, transform: GGParent.Transform, describe: OutlineDescribe, describeHit: GGParent.DescribeHit, fileout: OutlineFileout, filein: OutlineFilein, isEmptyParts: GGParent.IsEmptyParts, isCompleteParts: GGParent.IsCompleteParts, newParts: GGParent.NewParts, unionParts: GGParent.UnionParts, differenceParts: GGParent.DifferenceParts, movingParts: OutlineMovingParts, augmentParts: GGParent.AugmentParts, alterParts: GGParent.AlterParts, setSelectedFields: GGParent.SetSelectedFields, pointsInDescriptor: GGParent.PointsInDescriptor, walkPointsInDescriptor: GGParent.WalkPointsInDescriptor, pointPairsInDescriptor: GGParent.PointPairsInDescriptor, segmentsInDescriptor: GGParent.SegmentsInDescriptor, walkSegments: GGParent.WalkSegments, nextPoint: GGParent.NextPoint, nextPointPair: GGParent.NextPointPair, nextSegment: GGParent.NextSegment <<, closestPoint: GGParent.ClosestPoint, closestJointToHitData: GGParent.ClosestJointToHitData, closestPointAndTangent: GGSlice.NoOpClosestPointAndTangent, closestSegment: GGParent.ClosestSegment, lineIntersection: GGParent.LineIntersection, circleIntersection: GGParent.CircleIntersection, hitDataAsSimpleCurve: GGParent.HitDataAsSimpleCurve, setDefaults: GGParent.SetDefaults, setStrokeWidth: GGParent.SetStrokeWidth, getStrokeWidth: GGParent.GetStrokeWidth, setStrokeEnd: GGParent.SetStrokeEnd, getStrokeEnd: GGParent.GetStrokeEnd, setStrokeJoint: GGParent.SetStrokeJoint, getStrokeJoint: GGParent.GetStrokeJoint, setStrokeColor: GGParent.SetStrokeColor, getStrokeColor: GGParent.GetStrokeColor, setFillColor: GGParent.SetFillColor, getFillColor: OutlineGetFillColor, setArrows: GGSlice.NoOpSetArrows, getArrows: GGSlice.NoOpGetArrows, setDashed: GGParent.SetDashed, getDashed: GGParent.GetDashed >> ]]; GGSlice.BuildMoreOutlineSliceClass[class]; }; BuildClusterSliceClass: PUBLIC PROC [] RETURNS [class: SliceClass] = { class ¬ NEW[SliceClassObj ¬ [ type: $Cluster, unlink: GGParent.Unlink, getBoundBox: GGParent.GetBoundBox, getTransformedBoundBox: GGParent.GetTransformedBoundBox, getTightBox: GGParent.GetTightBox, copy: ClusterCopy, restore: GGParent.Restore, buildPath: GGSlice.NoOpBuildPath, drawBorder: GGSlice.NoOpDrawBorder, drawParts: GGParent.DrawParts, drawTransform: GGParent.DrawTransform, drawSelectionFeedback: ClusterDrawSelectionFeedback, drawAttractorFeedback: DrawAttractorFeedback, attractorFeedbackBoundBox: AttractorFeedbackBoundBox, saveSelections: GGParent.SaveSelections, remakeSelections: GGParent.RemakeSelections, transform: GGParent.Transform, describe: ClusterDescribe, describeHit: GGParent.DescribeHit, fileout: ClusterFileout, filein: ClusterFilein, isEmptyParts: GGParent.IsEmptyParts, isCompleteParts: GGParent.IsCompleteParts, newParts: GGParent.NewParts, unionParts: GGParent.UnionParts, differenceParts: GGParent.DifferenceParts, movingParts: ClusterMovingParts, augmentParts: GGParent.AugmentParts, alterParts: GGParent.AlterParts, setSelectedFields: GGParent.SetSelectedFields, pointsInDescriptor: GGParent.PointsInDescriptor, walkPointsInDescriptor: GGParent.WalkPointsInDescriptor, pointPairsInDescriptor: GGParent.PointPairsInDescriptor, segmentsInDescriptor: GGParent.SegmentsInDescriptor, walkSegments: GGParent.WalkSegments, nextPoint: GGParent.NextPoint, nextPointPair: GGParent.NextPointPair, nextSegment: GGParent.NextSegment <<, closestPoint: GGParent.ClosestPoint, closestJointToHitData: GGParent.ClosestJointToHitData, closestPointAndTangent: GGSlice.NoOpClosestPointAndTangent, closestSegment: GGParent.ClosestSegment, filledPathsUnderPoint: ClusterFilledPathsUnderPoint, lineIntersection: GGParent.LineIntersection, circleIntersection: GGParent.CircleIntersection, hitDataAsSimpleCurve: GGParent.HitDataAsSimpleCurve, setDefaults: GGParent.SetDefaults, setStrokeWidth: GGParent.SetStrokeWidth, getStrokeWidth: GGParent.GetStrokeWidth, setStrokeEnd: GGParent.SetStrokeEnd, getStrokeEnd: GGParent.GetStrokeEnd, setStrokeJoint: GGParent.SetStrokeJoint, getStrokeJoint: GGParent.GetStrokeJoint, setStrokeColor: GGParent.SetStrokeColor, getStrokeColor: GGParent.GetStrokeColor, setFillColor: GGParent.SetFillColor, getFillColor: GGParent.GetFillColor, setArrows: GGSlice.NoOpSetArrows, getArrows: GGSlice.NoOpGetArrows, setDashed: GGParent.SetDashed, getDashed: GGParent.GetDashed >> ]]; GGSlice.BuildMoreClusterSliceClass[class]; }; OutlineFromChildList: PROC [childList: LIST OF Slice, fillColor: Color, oddWrap: BOOL ¬ TRUE, fillText: TextNode.Ref, screenStyle: BOOL, version: REAL] RETURNS [outline: Slice] = { data: OutlineData ¬ NEW[OutlineDataObj ¬ [oddWrap: oddWrap, fillColor: fillColor, children: childList] ]; outline ¬ NEW[SliceObj ¬ [ class: GGSlice.FetchSliceClass[$Outline], parent: NIL, data: data, selectedInFull: [FALSE, FALSE, FALSE], tightBox: GGBoundBox.NullBoundBox[], boundBox: GGBoundBox.NullBoundBox[], boxValid: FALSE]]; FOR tL: LIST OF Slice ¬ childList, tL.rest UNTIL tL=NIL DO tL.first.parent ¬ outline; ENDLOOP; outline.nullDescriptor ¬ GGSlice.DescriptorFromParts[outline, NIL]; IF version<8802.04 THEN { -- have to calculate the forward bits from scratch. In older versions, trajectory direction was not important. [] ¬ GGSliceOps.SetOrientation[childList.first, NIL, ccw, NIL]; -- first child is ccw by convention FOR holeList: LIST OF Slice ¬ childList.rest, holeList.rest UNTIL holeList=NIL DO [] ¬ GGSliceOps.SetOrientation[holeList.first, NIL, cw, NIL]; -- other children are cw by convention ENDLOOP; }; GGOutline.SetFillText[outline, fillText, screenStyle, NIL]; }; ClusterFromChildList: PROC [childList: LIST OF Slice, frozen: BOOL, version: REAL] RETURNS [parent: Slice] = { data: OutlineData ¬ NEW[OutlineDataObj ¬ [oddWrap: FALSE, fillColor: NIL, children: childList, subclassData: NEW[ClusterDataObj ¬ [frozen: frozen]] ]]; parent ¬ NEW[SliceObj ¬ [ class: GGSlice.FetchSliceClass[$Cluster], parent: NIL, data: data, selectedInFull: [FALSE, FALSE, FALSE], tightBox: GGBoundBox.NullBoundBox[], boundBox: GGBoundBox.NullBoundBox[], boxValid: FALSE]]; FOR tL: LIST OF Slice ¬ childList, tL.rest UNTIL tL=NIL DO tL.first.parent ¬ parent; ENDLOOP; parent.nullDescriptor ¬ GGSlice.DescriptorFromParts[parent, NIL]; }; OutlineDescribe: PROC [sliceD: SliceDescriptor] RETURNS [rope: Rope.ROPE] = { RETURN[GGParent.Describe[sliceD, "outline"]]; }; ClusterDescribe: PROC [sliceD: SliceDescriptor] RETURNS [rope: Rope.ROPE] = { RETURN[GGParent.Describe[sliceD, "cluster"]]; }; ClusterCopy: PROC [slice: Slice, parts: SliceParts ¬ NIL] RETURNS [copy: LIST OF Slice] = { DoCreateCluster: PROC [newSlice: Slice] RETURNS [parent: Slice] = { newData: OutlineData; parent ¬ GGSlice.CreateCluster[]; GGSlice.AddChildToCluster[parent, newSlice, -1]; newData ¬ NARROW[parent.data]; newData.subclassData ¬ NEW[ClusterDataObj ¬ [frozen: oldClusterData.frozen]]; }; outlineParts: OutlineParts ¬ NARROW[parts]; oldData: OutlineData ¬ NARROW[slice.data]; oldClusterData: ClusterData ¬ NARROW[oldData.subclassData]; copy ¬ Copy[slice, parts, DoCreateCluster]; }; ClusterDrawSelectionFeedback: PUBLIC PROC [slice: Slice, selectedParts: SliceParts, hotParts: SliceParts, dc: Imager.Context, camera: Camera, dragInProgress, caretIsMoving, hideHot, quick: BOOL] = { slowNormal, slowHot, completeNormal, completeHot: BOOL ¬ FALSE; normalOutlineParts: OutlineParts ¬ NARROW[selectedParts]; hotOutlineParts: OutlineParts ¬ NARROW[hotParts]; boxDrawn: BOOL ¬ FALSE; IF caretIsMoving OR dragInProgress THEN RETURN; IF selectedParts=NIL AND hotParts=NIL THEN RETURN; completeNormal ¬ normalOutlineParts#NIL AND IsComplete[normalOutlineParts]; completeHot ¬ hotOutlineParts#NIL AND IsComplete[hotOutlineParts]; slowNormal ¬ selectedParts#NIL AND NOT (quick AND completeNormal); slowHot ¬ hotParts#NIL AND NOT (quick AND completeHot); GGParent.DrawSelectionFeedback[slice, selectedParts, hotParts, dc, camera, dragInProgress, caretIsMoving, hideHot, quick]; IF NOT slowNormal AND completeNormal THEN { boundBox: BoundBox ¬ GetBoundBox[slice, NIL]; GGShapes.DrawBoundBox[dc, boundBox, camera.cpScale]; GGShapes.DrawQuickSelectedJoint[dc, [boundBox.loX, boundBox.loY], normal, camera.cpScale]; boxDrawn ¬ TRUE; }; IF NOT slowHot AND completeHot THEN { boundBox: BoundBox ¬ GetBoundBox[slice, NIL]; GGShapes.DrawBoundBox[dc, boundBox, camera.cpScale]; GGShapes.DrawQuickSelectedJoint[dc, [boundBox.loX, boundBox.loY], hot, camera.cpScale]; boxDrawn ¬ TRUE; }; IF NOT boxDrawn AND (NOT IsEmpty[normalOutlineParts] OR NOT IsEmpty[hotOutlineParts]) THEN { boundBox: BoundBox ¬ GetBoundBox[slice, NIL]; GGShapes.DrawBoundBox[dc, boundBox, camera.cpScale]; }; }; ClusterFileout: PUBLIC PROC [slice: Slice, f: IO.STREAM] = { outlineData: OutlineData ¬ NARROW[slice.data]; clusterData: ClusterData ¬ NARROW[outlineData.subclassData]; f.PutRope["frozen: "]; GGParseOut.WriteBool[f, clusterData.frozen]; f.PutChar[IO.LF]; GGParent.Fileout[slice, f]; }; ClusterFilein: PUBLIC PROC [f: IO.STREAM, version: REAL, router: MsgRouter, camera: Camera] RETURNS [slice: Slice] = { frozen: BOOL ¬ TRUE; childList: LIST OF Slice; GGParseIn.ReadRope[f, "frozen:"]; frozen ¬ GGParseIn.ReadBool[f]; childList ¬ GGParent.Filein[f, version, router, camera]; IF childList#NIL THEN slice ¬ ClusterFromChildList[childList, frozen, version]; }; ClusterMovingParts: PROC [slice: Slice, selectedParts: SliceParts, editConstraints: EditConstraints, bezierDrag: GGInterfaceTypes.BezierDragRecord] RETURNS [background, overlay, rubber, drag: SliceDescriptor] = { outlineData: OutlineData ¬ NARROW[slice.data]; RETURN GGParent.MovingParts[slice, selectedParts, TRUE, editConstraints, bezierDrag]; }; Unlink: PUBLIC PROC [slice: Slice] = { IF slice.data#NIL THEN { outlineData: OutlineData ¬ NARROW[slice.data]; GGSlice.UnlinkSlice[slice]; FOR childList: LIST OF Slice ¬ outlineData.children, childList.rest UNTIL childList=NIL DO IF childList.first.data#NIL THEN GGSliceOps.Unlink[childList.first]; -- unlink circular structures. IMPORTANT ENDLOOP; outlineData.children ¬ NIL; }; }; GetBoundBox: PUBLIC PROC [slice: Slice, parts: SliceParts] RETURNS [box: BoundBox] = { IF slice.boxValid AND parts=NIL THEN RETURN[slice.boundBox] -- fast case ELSE { outlineParts: OutlineParts ¬ NARROW[parts]; outlineData: OutlineData ¬ NARROW[slice.data]; boundBoxList: LIST OF BoundBox; thisBoundBox: BoundBox; IF parts = NIL THEN FOR childList: LIST OF Slice ¬ outlineData.children, childList.rest UNTIL childList = NIL DO thisBoundBox ¬ GGSliceOps.GetBoundBox[childList.first]; boundBoxList ¬ CONS[thisBoundBox, boundBoxList]; ENDLOOP ELSE FOR list: LIST OF SliceDescriptor ¬ outlineParts.descriptors, list.rest UNTIL list = NIL DO IF list.first#NIL THEN { thisBoundBox ¬ GGSliceOps.GetBoundBox[list.first.slice, list.first.parts]; IF thisBoundBox # NIL THEN boundBoxList ¬ CONS[thisBoundBox, boundBoxList]; }; ENDLOOP; box ¬ GGBoundBox.BoundBoxOfBoxes[boundBoxList]; IF parts=NIL THEN { -- set up cache for fast case next time around GGSlice.KillBoundBoxOnly[slice.parent]; -- invalidate ancestor caches slice.boundBox ¬ box; slice.boxValid ¬ TRUE; }; }; }; GetTransformedBoundBox: PUBLIC PROC [slice: Slice, selectedParts: SliceParts, movingParts: SliceParts, transform: Transformation ¬ NIL] RETURNS [box: BoundBox] = { IF slice.boxValid AND selectedParts=NIL THEN RETURN[GGBoundBox.BoundBoxOfBoundBox[slice.boundBox, transform]] -- fast case ELSE { outlineSelectedParts: OutlineParts ¬ NARROW[selectedParts]; outlineMovingParts: OutlineParts ¬ NARROW[movingParts]; outlineData: OutlineData ¬ NARROW[slice.data]; boundBoxList: LIST OF BoundBox; thisBoundBox: BoundBox; IF selectedParts = NIL THEN FOR childList: LIST OF Slice ¬ outlineData.children, childList.rest UNTIL childList = NIL DO thisBoundBox ¬ GGSliceOps.GetTransformedBoundBox[childList.first, NIL, NIL, transform]; boundBoxList ¬ CONS[thisBoundBox, boundBoxList]; ENDLOOP ELSE { nextMovingList: LIST OF SliceDescriptor ¬ outlineMovingParts.descriptors; FOR list: LIST OF SliceDescriptor ¬ outlineSelectedParts.descriptors, list.rest UNTIL list = NIL DO nextMovingD: SliceDescriptor ¬ nextMovingList.first; -- parallel LIST walk IF list.first#NIL THEN { thisBoundBox ¬ GGSliceOps.GetTransformedBoundBox[list.first.slice, list.first.parts, nextMovingD.parts, transform]; boundBoxList ¬ CONS[thisBoundBox, boundBoxList]; }; nextMovingList ¬ nextMovingList.rest; ENDLOOP; }; box ¬ GGBoundBox.BoundBoxOfBoxes[boundBoxList]; }; }; GetTightBox: PUBLIC PROC [slice: Slice, parts: SliceParts] RETURNS [box: BoundBox] = { IF slice.tightBoxValid AND parts=NIL THEN RETURN[slice.tightBox] -- fast case ELSE { outlineParts: OutlineParts ¬ NARROW[parts]; outlineData: OutlineData ¬ NARROW[slice.data]; boundBoxList: LIST OF BoundBox; thisBoundBox: BoundBox; IF parts = NIL THEN FOR childList: LIST OF Slice ¬ outlineData.children, childList.rest UNTIL childList = NIL DO thisBoundBox ¬ GGSliceOps.GetTightBox[childList.first]; boundBoxList ¬ CONS[thisBoundBox, boundBoxList]; ENDLOOP ELSE FOR list: LIST OF SliceDescriptor ¬ outlineParts.descriptors, list.rest UNTIL list = NIL DO IF list.first#NIL THEN { thisBoundBox ¬ GGSliceOps.GetTightBox[list.first.slice, list.first.parts]; boundBoxList ¬ CONS[thisBoundBox, boundBoxList]; }; ENDLOOP; box ¬ GGBoundBox.BoundBoxOfBoxes[boundBoxList]; IF parts=NIL THEN { -- set up cache for fast case next time around GGSlice.KillTightBoxOnly[slice.parent]; -- invalidate ancestor caches slice.tightBox ¬ box; slice.tightBoxValid ¬ TRUE; }; }; }; OutlineCopy: PROC [slice: Slice, parts: SliceParts ¬ NIL] RETURNS [copy: LIST OF Slice] = { DoCreateOutline: PROC [newSlice: Slice] RETURNS [parent: Slice] = { newData: OutlineData; parent ¬ GGOutline.CreateOutline[newSlice, GGCoreOps.CopyColor[oldData.fillColor]]; newData ¬ NARROW[parent.data]; newData.oddWrap ¬ oldData.oddWrap; newData.fillText ¬ oldData.fillText; newData.screenStyle ¬ oldData.screenStyle; }; oldData: OutlineData ¬ NARROW[slice.data]; oldParts: OutlineParts ¬ NARROW[parts]; copy ¬ Copy[slice, parts, DoCreateOutline]; IF parts=NIL OR IsComplete[oldParts] THEN { -- if the whole thing is selected GGOutline.SetFillText[copy.first, oldData.fillText, oldData.screenStyle, NIL]; }; }; Copy: PUBLIC PROC [slice: Slice, parts: SliceParts ¬ NIL, create: PROC [newSlice: Slice] RETURNS [parent: Slice]] RETURNS [copy: LIST OF Slice] = { newParent, newSlice: Slice; oldData, newData: OutlineData; ptr, holeList: LIST OF Slice; outlineParts: OutlineParts ¬ NARROW[parts]; IF parts=NIL OR IsComplete[outlineParts] THEN { -- if the whole thing is selected AddChild: PROC [child: Slice] RETURNS [done: BOOL ¬ FALSE] = { IF newSlice = NIL THEN { newSlice ¬ GGSliceOps.Copy[child].first; newParent ¬ create[newSlice]; newData ¬ NARROW[newParent.data]; } ELSE { newSlice ¬ GGSliceOps.Copy[child].first; [holeList, ptr] ¬ GGUtility.AddSlice[newSlice, holeList, ptr]; newSlice.parent ¬ newParent; }; }; oldData ¬ NARROW[slice.data]; [holeList, ptr] ¬ GGUtility.StartSliceList[]; [] ¬ GGParent.WalkChildren[slice, first, AddChild]; IF holeList#NIL THEN newData.children ¬ GGUtility.AppendSliceList[newData.children, holeList]; copy ¬ LIST[newParent]; } ELSE { -- each run of each selected child becomes a new slice. CopyWholeTraj: PROC [child: Slice, enclose: BOOL ¬ FALSE] = { thisFillColor: Imager.Color ¬ GGCoreOps.CopyColor[GGSliceOps.GetFillColor[slice, NIL].color]; newChild: Slice ¬ GGSliceOps.Copy[child].first; IF enclose THEN newChild ¬ GGOutline.CreateOutline[newChild, thisFillColor]; copy ¬ GGUtility.AppendSliceList[copy, LIST[newChild]]; }; VisitChild: PROC [childD: SliceDescriptor] RETURNS [done: BOOL ¬ FALSE] = { nextChild: Slice ¬ childD.slice; childParts: SliceParts ¬ childD.parts; IF GGSliceOps.GetType[nextChild]#$Traj THEN { copy ¬ GGUtility.AppendSliceList[copy, GGSliceOps.Copy[nextChild, childParts]]; } ELSE { nextChildParts: TrajParts ¬ NARROW[childParts]; IF GGSequence.IsComplete[nextChildParts] THEN CopyWholeTraj[nextChild, TRUE] ELSE { nextRuns: GGSequence.SequenceGenerator ¬ GGSequence.RunsInSequence[nextChildParts].seqGen; FOR nextSeq: TrajParts ¬ GGSequence.NextSequence[nextRuns], GGSequence.NextSequence[nextRuns] UNTIL nextSeq=NIL DO IF NOT GGSequence.ContainsSomeSegment[nextSeq] THEN { router: MsgRouter ~ Feedback.EnsureRouter[$Gargoyle]; Feedback.Append[router, oneLiner, $Complaint, ". . . Cannot Fetch Joints or CPs by themselves"]; LOOP; }; newSlice ¬ GGTraj.CopyTrajFromRun[nextChild, nextSeq]; newSlice ¬ GGOutline.CreateOutline[newSlice, fillColor]; copy ¬ GGUtility.AppendSliceList[copy, LIST[newSlice]]; ENDLOOP; }; }; }; fillColor: Imager.Color ¬ GGCoreOps.CopyColor[GGSliceOps.GetFillColor[slice, NIL].color]; [] ¬ GGParent.WalkIncludedChildren[slice, parts, first, VisitChild]; }; }; Restore: PUBLIC PROC [from: Slice, to: Slice] = { IF to=NIL OR from=NIL THEN ERROR; IF to.class#from.class THEN ERROR; <> BEGIN fromSize: INT ¬ 0; fromData: OutlineData ¬ NARROW[from.data]; fromChildren: LIST OF Slice ¬ fromData.children; toSize: INT ¬ 0; toData: OutlineData ¬ NARROW[to.data]; toChildren: LIST OF Slice ¬ toData.children; lastToChildren: LIST OF Slice ¬ NIL; toData.oddWrap ¬ fromData.oddWrap; toData.fillColor ¬ fromData.fillColor; toData.fillText ¬ fromData.fillText; toData.screenStyle ¬ fromData.screenStyle; FOR fromList: LIST OF Slice ¬ fromChildren, fromList.rest UNTIL fromList=NIL DO fromSize ¬ fromSize+1; ENDLOOP; FOR toList: LIST OF Slice ¬ toChildren, toList.rest UNTIL toList=NIL DO toSize ¬ toSize+1; ENDLOOP; IF GGSlice.copyRestore THEN IF fromSize>=toSize THEN { UNTIL toChildren=NIL DO GGSliceOps.Restore[from: fromChildren.first, to: toChildren.first]; toChildren.first.parent ¬ to; -- must be restored in case it was reused at top level lastToChildren ¬ toChildren; fromChildren ¬ fromChildren.rest; toChildren ¬ toChildren.rest; ENDLOOP; IF lastToChildren#NIL THEN { -- put back the remaining "from" children. lastToChildren.rest ¬ fromChildren; -- hook up the lists FOR adoptees: LIST OF Slice ¬ fromChildren, adoptees.rest UNTIL adoptees=NIL DO adoptees.first.parent ¬ to; ENDLOOP; } } ELSE { -- fromSize= 8810.24 THEN GGParseIn.ReadRope[f, "Children:"] ELSE GGParseIn.ReadRope[f, "Trajectories:"]; GGParseIn.ReadChar[f, '[]; count ¬ GGParseIn.ReadNAT[f]; GGParseIn.ReadChar[f, ']]; IF count>0 THEN { [childList, ptr] ¬ GGUtility.StartSliceList[]; FOR i: NAT IN [0..count) DO nextChild ¬ GGSliceOps.FileinSlice[f, version, router, camera, IF version>=8802.04 THEN NIL ELSE trajClass]; -- older files had only trajectories as children of outlines IF someChild=NIL AND nextChild#NIL AND GGSliceOps.GetType[nextChild]=$Traj AND NARROW[nextChild.data, TrajData].role=circle THEN { fillColor ¬ NIL; -- needed for the transition from circle/disc class NARROW[nextChild.data, TrajData].role ¬ fence; -- fixup the kludge from TrajFilein }; IF nextChild#NIL THEN { someChild ¬ nextChild; [childList, ptr] ¬ GGUtility.AddSlice[nextChild, childList, ptr]; } ELSE ComplainAboutFile[f, "Parent", "NIL child detected", router]; ENDLOOP; RETURN[childList]; } ELSE ComplainAboutFile[f, "Parent", "parental object with no children detected", router]; }; OutlineFileout: PUBLIC PROC [slice: Slice, f: IO.STREAM] = { outlineData: OutlineData ¬ NARROW[slice.data]; f.PutRope["fillColor: "]; GGParseOut.WriteColor[f, outlineData.fillColor]; f.PutRope[" ow: "]; GGParseOut.WriteBool[f, outlineData.oddWrap]; f.PutRope[" fillText: "]; GGParseOut.WriteText[f, outlineData.fillText, outlineData.screenStyle]; f.PutChar[IO.LF]; GGParent.Fileout[slice, f]; }; OutlineFilein: PUBLIC PROC [f: IO.STREAM, version: REAL, router: MsgRouter, camera: Camera] RETURNS [slice: Slice] = { oddWrap: BOOL ¬ TRUE; fillColor: Color; fillText: TextNode.Ref; screenStyle: BOOL ¬ TRUE; childList: LIST OF Slice; IF trajClass=NIL THEN trajClass ¬ GGSlice.FetchSliceClass[$Traj]; GGParseIn.ReadRope[f, "fillColor:"]; fillColor ¬ GGParseIn.ReadColor[f, version]; IF version>=8802.04 THEN { GGParseIn.ReadRope[f, "ow:"]; oddWrap ¬ GGParseIn.ReadBool[f]; }; IF version>=8803.24 THEN { GGParseIn.ReadRope[f, "fillText:"]; [fillText, screenStyle] ¬ GGParseIn.ReadText[f, version]; }; IF version < 8702.26 THEN { -- read and discard StrokeEnd from older formats GGParseIn.ReadRope[f, "strokeEnd:"]; [] ¬ GGParseIn.ReadStrokeEnd[f]; }; childList ¬ GGParent.Filein[f, version, router, camera]; IF childList#NIL THEN slice ¬ OutlineFromChildList[childList, fillColor, oddWrap, fillText, screenStyle, version]; }; ComplainAboutFile: PROC [f: IO.STREAM, className, complaint: Rope.ROPE, router: MsgRouter] = { of: FS.OpenFile; fileName: Rope.ROPE ¬ NIL; of ¬ FS.OpenFileFromStream[f ! IO.Error => { fileName ¬ "not a file"; CONTINUE }; ]; IF fileName=NIL THEN fileName ¬ FS.GetName[of].fullFName; Feedback.PutFL[router, oneLiner, $Complaint, "Filein Error for %g: %g slice, %g", LIST[[rope[fileName]], [rope[className]], [rope[complaint]]] ]; }; IsEmptyParts: PUBLIC PROC [sliceD: SliceDescriptor] RETURNS [BOOL ¬ FALSE] = { realParts: OutlineParts ¬ NARROW[sliceD.parts]; RETURN[IsEmpty[realParts]]; }; IsEmpty: PUBLIC PROC [realParts: OutlineParts] RETURNS [BOOL ¬ FALSE] = { IF realParts=NIL THEN RETURN[TRUE]; -- NIL means Empty, Bier, June 29, 1990 FOR list: LIST OF SliceDescriptor ¬ realParts.descriptors, list.rest UNTIL list = NIL DO IF list.first#NIL AND NOT GGSliceOps.IsEmptyParts[list.first] THEN RETURN[FALSE]; ENDLOOP; RETURN[TRUE]; }; IsCompleteParts: PUBLIC PROC [sliceD: SliceDescriptor] RETURNS [BOOL ¬ FALSE] = { realParts: OutlineParts ¬ NARROW[sliceD.parts]; RETURN[IsComplete[realParts]]; }; IsComplete: PUBLIC PROC [realParts: OutlineParts] RETURNS [BOOL ¬ FALSE] = { IF realParts=NIL THEN RETURN[FALSE]; -- NIL means empty, Bier, June 29, 1990 FOR list: LIST OF SliceDescriptor ¬ realParts.descriptors, list.rest UNTIL list = NIL DO IF list.first=NIL OR NOT GGSliceOps.IsCompleteParts[list.first] THEN RETURN[FALSE]; ENDLOOP; RETURN[TRUE]; }; NewParts: PUBLIC PROC [slice: Slice, hitData: REF ANY, mode: SelectMode] RETURNS [sliceD: SliceDescriptor] = { outlineData: OutlineData ¬ NARROW[slice.data]; outlineHitData: OutlineHitData ¬ NARROW[hitData]; newParts: OutlineParts ¬ NEW[OutlinePartsObj]; SELECT mode FROM none, slice, topLevel => { -- build a complete descriptor ptr: LIST OF SliceDescriptor; [newParts.descriptors, ptr] ¬ GGUtility.StartSliceDescriptorList[]; FOR children: LIST OF Slice ¬ outlineData.children, children.rest UNTIL children=NIL DO child: Slice ¬ children.first; childD: SliceDescriptor ¬ IF mode=none THEN NIL ELSE GGSliceOps.NewParts[child, NIL, slice]; [newParts.descriptors, ptr] ¬ GGUtility.AddSliceDescriptor[childD, newParts.descriptors, ptr]; ENDLOOP; sliceD ¬ GGSlice.DescriptorFromParts[slice, newParts]; -- empty or complete parts }; ENDCASE => { -- all other cases need a legit hitData FOR children: LIST OF Slice ¬ outlineData.children, children.rest UNTIL children=NIL DO child: Slice ¬ children.first; IF child=outlineHitData.child THEN { childD: SliceDescriptor ¬ GGSliceOps.NewParts[child, outlineHitData.childHitData, mode]; sliceD ¬ GGParent.DescriptorFromChildDescriptor[slice, childD]; -- hit parts RETURN; }; ENDLOOP; SIGNAL Problem["Unmatched outline and hitData in OutlineNewParts"]; }; }; UnionParts: PUBLIC PROC [partsA: SliceDescriptor, partsB: SliceDescriptor] RETURNS [aPlusB: SliceDescriptor] = { realPartsA: OutlineParts ¬ NARROW[partsA.parts]; realPartsB: OutlineParts ¬ NARROW[partsB.parts]; IF partsA.parts = NIL THEN RETURN[partsB]; IF partsB.parts = NIL THEN RETURN[partsA]; IF IsEmpty[realPartsA] THEN RETURN[partsB]; IF IsEmpty[realPartsB] THEN RETURN[partsA]; IF IsComplete[realPartsA] THEN RETURN[partsA]; IF IsComplete[realPartsB] THEN RETURN[partsB]; BEGIN ptr: LIST OF SliceDescriptor; union: OutlineParts ¬ NEW[OutlinePartsObj]; listA: LIST OF SliceDescriptor ¬ realPartsA.descriptors; listB: LIST OF SliceDescriptor ¬ realPartsB.descriptors; [union.descriptors, ptr] ¬ GGUtility.StartSliceDescriptorList[]; UNTIL listA = NIL DO IF listA.first = NIL THEN [union.descriptors, ptr] ¬ GGUtility.AddSliceDescriptor[listB.first, union.descriptors, ptr] ELSE IF listB.first = NIL THEN [union.descriptors, ptr] ¬ GGUtility.AddSliceDescriptor[listA.first, union.descriptors, ptr] ELSE { newSeq: SliceDescriptor ¬ GGSliceOps.UnionParts[listA.first, listB.first]; [union.descriptors, ptr] ¬ GGUtility.AddSliceDescriptor[IF GGSliceOps.IsEmptyParts[newSeq] THEN NIL ELSE newSeq, union.descriptors, ptr]; }; listA ¬ listA.rest; listB ¬ listB.rest; ENDLOOP; aPlusB ¬ GGSlice.DescriptorFromParts[partsA.slice, union]; END; }; DifferenceParts: PUBLIC PROC [partsA: SliceDescriptor, partsB: SliceDescriptor] RETURNS [aMinusB: SliceDescriptor] = { realPartsA, realPartsB: OutlineParts; diff: OutlineParts; listA: LIST OF SliceDescriptor; listB: LIST OF SliceDescriptor; ptr: LIST OF SliceDescriptor; IF partsA.parts = NIL OR partsB = NIL OR partsB.parts = NIL THEN RETURN[partsA]; realPartsA ¬ NARROW[partsA.parts]; realPartsB ¬ NARROW[partsB.parts]; listA ¬ realPartsA.descriptors; listB ¬ realPartsB.descriptors; diff ¬ NEW[OutlinePartsObj]; [diff.descriptors, ptr] ¬ GGUtility.StartSliceDescriptorList[]; UNTIL listA = NIL DO IF listA.first = NIL THEN [diff.descriptors, ptr] ¬ GGUtility.AddSliceDescriptor[NIL, diff.descriptors, ptr] ELSE IF listB = NIL OR listB.first = NIL THEN [diff.descriptors, ptr] ¬ GGUtility.AddSliceDescriptor[listA.first, diff.descriptors, ptr] ELSE { newSeq: SliceDescriptor ¬ GGSliceOps.DifferenceParts[listA.first, listB.first]; [diff.descriptors, ptr] ¬ GGUtility.AddSliceDescriptor[IF GGSliceOps.IsEmptyParts[newSeq] THEN NIL ELSE newSeq, diff.descriptors, ptr]; }; listA ¬ listA.rest; listB ¬ listB.rest; ENDLOOP; aMinusB ¬ GGSlice.DescriptorFromParts[partsA.slice, diff]; }; OutlineMovingParts: PROC [slice: Slice, selectedParts: SliceParts, editConstraints: EditConstraints, bezierDrag: GGInterfaceTypes.BezierDragRecord] RETURNS [background, overlay, rubber, drag: SliceDescriptor] = { outlineData: OutlineData ¬ NARROW[slice.data]; filled: BOOL ¬ outlineData.fillColor#NIL OR outlineData.fillText#NIL; RETURN GGParent.MovingParts[slice, selectedParts, filled, editConstraints, bezierDrag]; }; MovingParts: PUBLIC PROC [slice: Slice, selectedParts: SliceParts, treatAsAUnit: BOOL ¬ FALSE, editConstraints: EditConstraints, bezierDrag: GGInterfaceTypes.BezierDragRecord] RETURNS [background, overlay, rubber, drag: SliceDescriptor] = { outlineData: OutlineData; outlineParts: OutlineParts ¬ NARROW[selectedParts]; bkgdParts, overParts, rubberParts, dragParts: OutlineParts; bkgdSeq, overSeq, rubberSeq, dragSeq: SliceDescriptor; bkgdPtr, overPtr, rubberPtr, dragPtr: LIST OF SliceDescriptor; children: LIST OF Slice; nullD: SliceDescriptor ¬ slice.nullDescriptor; forNow: BOOL ¬ TRUE; IF IsEmpty[outlineParts] THEN { background ¬ overlay ¬ rubber ¬ drag ¬ nullD; RETURN; }; IF IsComplete[outlineParts] THEN { background ¬ overlay ¬ rubber ¬ nullD; drag ¬ GGSlice.DescriptorFromParts[slice, selectedParts]; RETURN; }; bkgdParts ¬ NEW[OutlinePartsObj]; overParts ¬ NEW[OutlinePartsObj]; rubberParts ¬ NEW[OutlinePartsObj]; dragParts ¬ NEW[OutlinePartsObj]; [bkgdParts.descriptors, bkgdPtr] ¬ GGUtility.StartSliceDescriptorList[]; [overParts.descriptors, overPtr] ¬ GGUtility.StartSliceDescriptorList[]; [rubberParts.descriptors, rubberPtr] ¬ GGUtility.StartSliceDescriptorList[]; [dragParts.descriptors, dragPtr] ¬ GGUtility.StartSliceDescriptorList[]; outlineData ¬ NARROW[slice.data]; children ¬ outlineData.children; FOR list: LIST OF SliceDescriptor ¬ outlineParts.descriptors, list.rest UNTIL list = NIL DO IF list.first = NIL THEN { [rubberParts.descriptors, rubberPtr] ¬ GGUtility.AddSliceDescriptor[NIL, rubberParts.descriptors, rubberPtr]; [dragParts.descriptors, dragPtr] ¬ GGUtility.AddSliceDescriptor[NIL, dragParts.descriptors, dragPtr]; IF treatAsAUnit THEN { overSeq ¬ GGSliceOps.NewParts[children.first, NIL, slice]; -- complete descriptor [overParts.descriptors, overPtr] ¬ GGUtility.AddSliceDescriptor[overSeq, overParts.descriptors, overPtr]; [bkgdParts.descriptors, bkgdPtr] ¬ GGUtility.AddSliceDescriptor[NIL, bkgdParts.descriptors, bkgdPtr]; } ELSE { bkgdSeq ¬ GGSliceOps.NewParts[children.first, NIL, slice]; -- complete descriptor [bkgdParts.descriptors, bkgdPtr] ¬ GGUtility.AddSliceDescriptor[bkgdSeq, bkgdParts.descriptors, bkgdPtr]; [overParts.descriptors, overPtr] ¬ GGUtility.AddSliceDescriptor[NIL, overParts.descriptors, overPtr]; }; } ELSE { [bkgdSeq, overSeq, rubberSeq, dragSeq] ¬ GGSliceOps.MovingParts[list.first.slice, list.first.parts, editConstraints, bezierDrag]; -- for now bezierDrag is extra IF treatAsAUnit OR forNow THEN { [bkgdParts.descriptors, bkgdPtr] ¬ GGUtility.AddSliceDescriptor[NIL, bkgdParts.descriptors, bkgdPtr]; [overParts.descriptors, overPtr] ¬ GGUtility.AddSliceDescriptor[overSeq, overParts.descriptors, overPtr]; [rubberParts.descriptors, rubberPtr] ¬ GGUtility.AddSliceDescriptor[rubberSeq, rubberParts.descriptors, rubberPtr]; [dragParts.descriptors, dragPtr] ¬ GGUtility.AddSliceDescriptor[dragSeq, dragParts.descriptors, dragPtr]; } ELSE { [bkgdParts.descriptors, bkgdPtr] ¬ GGUtility.AddSliceDescriptor[overSeq, bkgdParts.descriptors, bkgdPtr]; [overParts.descriptors, overPtr] ¬ GGUtility.AddSliceDescriptor[NIL, overParts.descriptors, overPtr]; [rubberParts.descriptors, rubberPtr] ¬ GGUtility.AddSliceDescriptor[rubberSeq, rubberParts.descriptors, rubberPtr]; [dragParts.descriptors, dragPtr] ¬ GGUtility.AddSliceDescriptor[dragSeq, dragParts.descriptors, dragPtr]; }; }; children ¬ children.rest; ENDLOOP; background ¬ GGSlice.DescriptorFromParts[slice, bkgdParts]; overlay ¬ GGSlice.DescriptorFromParts[slice, overParts]; rubber ¬ GGSlice.DescriptorFromParts[slice, rubberParts]; drag ¬ GGSlice.DescriptorFromParts[slice, dragParts]; }; AugmentParts: PUBLIC PROC [sliceD: SliceDescriptor, selectClass: SelectionClass] RETURNS [more: SliceDescriptor] = { ptr: LIST OF SliceDescriptor; outlineParts: OutlineParts ¬ NARROW[sliceD.parts]; newParts: OutlineParts; IF outlineParts = NIL THEN RETURN[sliceD]; newParts ¬ NEW[OutlinePartsObj]; [newParts.descriptors, ptr] ¬ GGUtility.StartSliceDescriptorList[]; FOR nextParts: LIST OF SliceDescriptor ¬ outlineParts.descriptors, nextParts.rest UNTIL nextParts=NIL DO nextPart: SliceDescriptor ¬ nextParts.first; [newParts.descriptors, ptr] ¬ GGUtility.AddSliceDescriptor[IF nextPart#NIL THEN GGSliceOps.AugmentParts[nextPart, selectClass] ELSE NIL, newParts.descriptors, ptr]; ENDLOOP; more ¬ GGSlice.DescriptorFromParts[sliceD.slice, newParts]; }; AlterParts: PUBLIC PROC [sliceD: SliceDescriptor, action: ATOM] RETURNS [alteredD: SliceDescriptor] = { outlineParts: OutlineParts ¬ NARROW[sliceD.parts]; outlineData: OutlineData ¬ NARROW[sliceD.slice.data]; newParts: OutlineParts ¬ NEW[OutlinePartsObj]; childD: SliceDescriptor ¬ GGParent.FirstIncludedChild[sliceD.slice, sliceD.parts, first]; child: Slice ¬ childD.slice; BEGIN SELECT action FROM $Forward, $Backward => { IF IsComplete[outlineParts] THEN RETURN[NIL]; IF GGSliceOps.IsCompleteParts[childD] THEN { beforeEnt, ent, afterEnt: LIST OF Slice; [beforeEnt, ent, afterEnt, ----] ¬ GGUtility.FindSliceAndNeighbors[child, outlineData.children]; IF action = $Forward THEN alteredD ¬ IF afterEnt = NIL THEN NIL ELSE GGParent.DescriptorFromChild[sliceD.slice, afterEnt.first] ELSE alteredD ¬ IF beforeEnt = NIL THEN NIL ELSE GGParent.DescriptorFromChild[sliceD.slice, beforeEnt.first]; } ELSE GOTO Recurse; }; $Grow => { IF IsComplete[outlineParts] THEN RETURN[NIL]; IF GGSliceOps.IsCompleteParts[childD] THEN alteredD ¬ GGSliceOps.NewParts[sliceD.slice, NIL, slice] ELSE GOTO Recurse; }; $ShrinkForward => { IF IsComplete[outlineParts] THEN alteredD ¬ GGParent.DescriptorFromChild[sliceD.slice, OutlineLastChild[sliceD.slice]] ELSE GOTO Recurse; }; $ShrinkBackward => { IF IsComplete[outlineParts] THEN alteredD ¬ GGParent.DescriptorFromChild[sliceD.slice, OutlineFirstChild[sliceD.slice]] ELSE GOTO Recurse; }; ENDCASE => ERROR; EXITS Recurse => { alteredChildD: SliceDescriptor ¬ GGSliceOps.AlterParts[childD, action]; alteredD ¬ IF alteredChildD = NIL THEN NIL ELSE GGParent.DescriptorFromChildDescriptor[sliceD.slice, alteredChildD]; }; END; }; OutlineFirstChild: PROC [slice: Slice] RETURNS [child: Slice] = { outlineData: OutlineData ¬ NARROW[slice.data]; child ¬ outlineData.children.first; }; OutlineLastChild: PROC [slice: Slice] RETURNS [child: Slice] = { outlineData: OutlineData ¬ NARROW[slice.data]; FOR list: LIST OF Slice ¬ outlineData.children, list.rest UNTIL list = NIL DO child ¬ list.first; ENDLOOP; }; SetSelectedFields: PUBLIC PROC [sliceD: SliceDescriptor, selected: BOOL, selectClass: SelectionClass] = { outlineParts: OutlineParts ¬ NARROW[sliceD.parts]; IF outlineParts = NIL THEN RETURN; FOR nextParts: LIST OF SliceDescriptor ¬ outlineParts.descriptors, nextParts.rest UNTIL nextParts=NIL DO nextPart: SliceDescriptor ¬ nextParts.first; IF nextPart#NIL THEN GGSliceOps.SetSelectedFields[nextPart, selected, selectClass]; ENDLOOP; }; PointGeneratorData: TYPE = REF PointGeneratorDataObj; PointGeneratorDataObj: TYPE = RECORD [ seqPtr: LIST OF SliceDescriptor, pointGen: PointGenerator -- the point generator for the first sequence of seqPtr ]; PointPairGeneratorData: TYPE = REF PointPairGeneratorDataObj; PointPairGeneratorDataObj: TYPE = RECORD [ seqPtr: LIST OF SliceDescriptor, pointGen: PointPairGenerator -- the pair generator for first sequence of seqPtr ]; SegmentGeneratorData: TYPE = REF SegmentGeneratorDataObj; SegmentGeneratorDataObj: TYPE = RECORD [ seqPtr: LIST OF SliceDescriptor, segGen: SegmentGenerator -- the point generator for the first sequence of seqPtr ]; PointsInDescriptor: PUBLIC PROC [sliceD: SliceDescriptor] RETURNS [pointGen: PointGenerator] = { outlineParts: OutlineParts ¬ NARROW[sliceD.parts]; descriptors: LIST OF SliceDescriptor; childPointGen: PointGenerator; pointGenData: PointGeneratorData; descriptors ¬ IF outlineParts = NIL THEN NIL ELSE outlineParts.descriptors; childPointGen ¬ IF descriptors = NIL OR descriptors.first = NIL THEN NIL ELSE GGSliceOps.PointsInDescriptor[descriptors.first]; pointGenData ¬ NEW[PointGeneratorDataObj ¬ [descriptors, childPointGen]]; pointGen ¬ NEW[PointGeneratorObj ¬ [sliceD, 0, 0, pointGenData]]; }; WalkPointsInDescriptor: PUBLIC PROC [sliceD: SliceDescriptor, walkProc: PointWalkProc] = { outlineParts: OutlineParts ¬ NARROW[sliceD.parts]; descriptors: LIST OF SliceDescriptor; IF outlineParts = NIL THEN RETURN; descriptors ¬ outlineParts.descriptors; FOR descriptors: LIST OF SliceDescriptor ¬ outlineParts.descriptors, descriptors.rest UNTIL descriptors = NIL DO IF descriptors.first # NIL THEN GGSliceOps.WalkPointsInDescriptor[descriptors.first, walkProc]; ENDLOOP; }; PointPairsInDescriptor: PUBLIC PROC [sliceD: SliceDescriptor] RETURNS [pointPairGen: GGModelTypes.PointPairGenerator] = { outlineParts: OutlineParts ¬ NARROW[sliceD.parts]; descriptors: LIST OF SliceDescriptor; childPointPairGen: PointPairGenerator; pointPairGenData: PointPairGeneratorData; descriptors ¬ IF outlineParts = NIL THEN NIL ELSE outlineParts.descriptors; childPointPairGen ¬ IF descriptors = NIL OR descriptors.first = NIL THEN NIL ELSE GGSliceOps.PointPairsInDescriptor[descriptors.first]; pointPairGenData ¬ NEW[PointPairGeneratorDataObj ¬ [descriptors, childPointPairGen]]; pointPairGen ¬ NEW[PointPairGeneratorObj ¬ [sliceD, 0, 0, pointPairGenData]]; }; SegmentsInDescriptor: PUBLIC PROC [sliceD: SliceDescriptor] RETURNS [segGen: SegmentGenerator] = { outlineParts: OutlineParts ¬ NARROW[sliceD.parts]; descriptors: LIST OF SliceDescriptor ¬ IF outlineParts = NIL THEN NIL ELSE outlineParts.descriptors; IF descriptors#NIL THEN { segGenData: SegmentGeneratorData ¬ NEW[SegmentGeneratorDataObj ¬ [ seqPtr: descriptors, -- one descriptor per child in outline, including NILs for unincluded descriptors segGen: IF descriptors.first=NIL THEN NIL ELSE GGSliceOps.SegmentsInDescriptor[descriptors.first] -- segGen for first child ]]; segGen ¬ NEW[SegmentGeneratorObj ¬ [ toGo: 9999, -- for debugging sliceD: sliceD, completeSeq: FALSE, classSpecific: segGenData ]]; }; }; NextSegment: PUBLIC PROC [slice: Slice, segGen: SegmentGenerator] RETURNS [seg: Segment, transform: ImagerTransformation.Transformation] = { segGenData: SegmentGeneratorData ¬ NARROW[segGen.classSpecific]; descriptors: LIST OF SliceDescriptor ¬ segGenData.seqPtr; IF segGen.toGo#9999 THEN ERROR; -- for debugging WHILE TRUE DO IF descriptors.first # NIL THEN { -- maybe some seg left in this child [seg, transform] ¬ GGSliceOps.NextSegment[descriptors.first.slice, segGenData.segGen]; IF seg#NIL THEN { segGenData.seqPtr ¬ descriptors; RETURN; }; descriptors ¬ descriptors.rest; -- on to the next child }; UNTIL descriptors = NIL OR descriptors.first # NIL DO descriptors ¬ descriptors.rest ENDLOOP; IF descriptors = NIL THEN RETURN[NIL, NIL]; segGenData.segGen ¬ GGSliceOps.SegmentsInDescriptor[descriptors.first]; -- segGen for next child ENDLOOP; }; WalkSegments: PUBLIC PROC [slice: Slice, walkProc: WalkProc] RETURNS [sliceD: SliceDescriptor] = { ptr: LIST OF SliceDescriptor; outlineData: OutlineData ¬ NARROW[slice.data]; newParts: OutlineParts ¬ NEW[OutlinePartsObj]; [newParts.descriptors, ptr] ¬ GGUtility.StartSliceDescriptorList[]; FOR children: LIST OF Slice ¬ outlineData.children, children.rest UNTIL children=NIL DO child: Slice ¬ children.first; childD: SliceDescriptor ¬ GGSliceOps.WalkSegments[child, walkProc]; [newParts.descriptors, ptr] ¬ GGUtility.AddSliceDescriptor[childD, newParts.descriptors, ptr]; ENDLOOP; sliceD ¬ GGSlice.DescriptorFromParts[slice, newParts]; }; NextPoint: PUBLIC PROC [slice: Slice, pointGen: PointGenerator] RETURNS [pointAndDone: GGModelTypes.PointAndDone] = { pgd: PointGeneratorData ¬ NARROW[pointGen.classSpecific]; descriptors: LIST OF SliceDescriptor ¬ pgd.seqPtr; IF descriptors = NIL THEN RETURN[[[0,0], TRUE]]; WHILE TRUE DO IF descriptors.first # NIL THEN { -- maybe some point left in this child pointAndDone ¬ GGSliceOps.NextPoint[descriptors.first.slice, pgd.pointGen]; IF NOT pointAndDone.done THEN { pgd.seqPtr ¬ descriptors; RETURN; }; descriptors ¬ descriptors.rest; -- on to the next child }; UNTIL descriptors = NIL OR descriptors.first # NIL DO descriptors ¬ descriptors.rest ENDLOOP; IF descriptors = NIL THEN RETURN[[[0,0], TRUE]]; pgd.pointGen ¬ GGSliceOps.PointsInDescriptor[descriptors.first]; -- pointGen for next child ENDLOOP; }; NextPointPair: PUBLIC PROC [slice: Slice, pointPairGen: PointPairGenerator] RETURNS [pointPairAndDone: PointPairAndDone] = { pgd: PointPairGeneratorData ¬ NARROW[pointPairGen.classSpecific]; descriptors: LIST OF SliceDescriptor ¬ pgd.seqPtr; IF descriptors = NIL THEN RETURN[[[0,0], [0,0], TRUE]]; WHILE TRUE DO IF descriptors.first # NIL THEN { -- maybe some pair left in this child pointPairAndDone ¬ GGSliceOps.NextPointPair[descriptors.first.slice, pgd.pointGen]; IF NOT pointPairAndDone.done THEN { pgd.seqPtr ¬ descriptors; RETURN; }; descriptors ¬ descriptors.rest; -- on to the next child }; UNTIL descriptors = NIL OR descriptors.first # NIL DO descriptors ¬ descriptors.rest ENDLOOP; IF descriptors = NIL THEN RETURN[[[0,0], [0,0], TRUE]]; pgd.pointGen ¬ GGSliceOps.PointPairsInDescriptor[descriptors.first]; ENDLOOP; }; fillColor: PUBLIC Imager.Color ¬ Imager.MakeGray[0.5]; trajClass: SliceClass; -- filled in by OutlineFilein END. GGOutlineImplA.mesa Contents: Implementations of the Parent Meta-Class and the Outline class. Copyright Ó 1986, 1987, 1988, 1989, 1992 by Xerox Corporation. All rights reserved. Pier, June 19, 1992 10:19 pm PDT Eisenman, October 2, 1987 9:22:03 pm PDT Bier, February 23, 1993 7:14 pm PST Doug Wyatt, April 14, 1992 2:39 pm PDT The Outline Class Fundamentals Drawing Transforming Textual Description Parts Part Generators Hit Testing Hit Testing moved to GGOutlineImplB Style Style moved to GGOutlineImplB Fundamentals Drawing Transforming Textual Description Parts Part Generators Hit Testing Hit Testing moved to GGOutlineImplB Style Style moved to GGOutlineImplB Textual Description The Cluster Class Fundamentals Drawing Draw the big boxes for speed, if you can. Textual Description Parts The Parent Meta-Class Fundamentals GGModelTypes.SliceBoundBoxProc bound box of all the children GGModelTypes.SliceTransformedBoundBoxProc transformedBound box of all the children GGModelTypes.SliceBoundBoxProc bound box of all the children This PROC assumes that only Trajs can be copied in part. All other classes are copied in entirety. Since outlineParts represents a complete cluster or outline, copying a given child produces a single slice. Creates the parent and adds the child to its list of children. Since outlineParts represents a complete cluster or outline, copying a given child produces a single slice. Add the rest of the children to the list. GGModelTypes.SliceRestoreProc from and to must be nearly identically structured slices, probably because from was made as a copy of to. Restore the contents of "to", getting all non-REF values from "from". Good luck. CAN THIS LEAD TO OBSOLETE DESCRIPTORS?? Reparent !! Reparent !! to.nullDescriptor is always valid to.fullDescriptor is unused Drawing GGModelTypes.SliceBuildPathProc transformParts=NIL => complete parts. transform=NIL => don't transform any parts GGModelTypes.SliceDrawBorderProc drawParts=NIL => draw ALL parts. transformParts=NIL => transform ALL parts. transform=NIL => don't transform any parts. This routine assumes it is called without needing to transform any of its parts or needing to take EditConstraints into account. Currently draws entire outline. Draw the fill. Draw the strokes. Draw the fill text. Currently draws entire cluster. Draw children back to front. "parts" describes which children of slice are to be transformed (and which are to be drawn in place). If parts is NIL, then all children are to be transformed (or not if transform = NIL); Fill in the outline if appropriate. Draw the strokes. parts=NIL => transform entire slice If some joints are both normal and hot selected, a special symbol is drawn at them, and separate symbols are drawn at other joints. If the parent is entirely selected or entirely hot, and we are allowed to try fast feedback, a single large box is drawn for that selection type for the entire slice. IF caretIsMoving OR dragInProgress THEN RETURN; IF selectedParts=NIL AND hotParts=NIL THEN RETURN; Draw the big boxes for speed, if you can. The selectedParts are a hint as to what is being dragged. Attractor feedback for the moving part is suppressed if the attractor is part of something that is moving. Find out which parts of the child should not be highlighted (because they are moving). The selectedParts are a hint as to what is being dragged. Attractor feedback for the moving part is suppressed if the attractor is part of something that is moving. Find out which parts of the child should not be highlighted (because they are moving). Return which parts of child are mentioned in parts. GGModelTypes.SliceSaveSelectionsProc Ya gotta clear out them bits first because there may have been NO SELECTION! GGModelTypes.SliceRemakeSelectionsProc Transforming Call GGSliceOps.Transform on each child, with history=NIL so the children will not make history list entries. The outline will make one instead. This proc assumes that every Box in the outline is filled if any are filled This proc assumes that every Box in the outline is filled if any are filled Textual Description IF realParts describes exactly one child, return that child. Otherwise return NIL. An outlineHitData is now [child: Slice, childHitData: REF ANY]; Filein: PUBLIC PROC [f: IO.STREAM, version: REAL, router: MsgRouter, camera: Camera] RETURNS [children: LIST OF Slice] = { 8803.24, 8810.24 count: NAT _ 0; class: SliceClass; className: Rope.ROPE; someChild, nextChild: Slice; childList, ptr: LIST OF Slice; IF version >= 8810.24 THEN GGParseIn.ReadRope[f, "Children:"] ELSE GGParseIn.ReadRope[f, "Trajectories:"]; GGParseIn.ReadChar[f, '[]; count _ GGParseIn.ReadNAT[f]; GGParseIn.ReadChar[f, ']]; IF count>0 THEN { [childList, ptr] _ GGUtility.StartSliceList[]; FOR i: NAT IN [0..count) DO IF version>=8802.04 THEN { className _ GGParseIn.ReadWord[f]; class _ IF className=NIL THEN NIL ELSE GGSlice.FetchSliceClass[Atom.MakeAtom[className]]; IF class=NIL THEN {ComplainAboutFile[f, "unknown class", "NIL child detected", feedback]; LOOP;}; } ELSE { className _ "Traj"; class _ trajClass; }; nextChild _ class.filein[f, version, feedback, camera]; IF someChild=NIL AND nextChild#NIL AND class.type=$Traj AND NARROW[nextChild.data, TrajData].role=circle THEN { I think this is a bug (changing the global fillColor) but I don't know what its about and it is probably never happening so ... KAP. January 4, 1989 fillColor _ NIL; -- needed for the transition from circle/disc class NARROW[nextChild.data, TrajData].role _ fence; -- fixup the kludge from TrajFilein }; IF nextChild#NIL THEN { someChild _ nextChild; [childList, ptr] _ GGUtility.AddSlice[nextChild, childList, ptr]; } ELSE ComplainAboutFile[f, className, "NIL child detected", feedback]; ENDLOOP; RETURN[childList]; } ELSE ComplainAboutFile[f, "Parent", "parental object with no children detected", feedback]; }; I think this is a bug (changing the global fillColor) but I don't know what its about and it is probably never happening so ... KAP. January 4, 1989 8803.24, 8810.24 Parts An outlineHitData is now [child: Slice, childHitData: REF ANY]; Filled outlines have the property that if any of their subparts are on the overlay plane, then all of their parts are on the overlay plane. (For now, all outline children are either completely on the overlay or completely off -- Bier, March 14, 1988) Some parts are selected, but not all (the hard case) This trajectory is not at all selected. If this parent is to be treated as a unit, put it on the overlay. Otherwise, leave it in the background. Some or all of this trajectory is selected. If the outline is treatAsAUnit, put all on overlay. Otherwise, put non-moving parts on background. Like, if you (normal) select a segment, you should select its end joints as well. This PROC gives new classes a chance to invent their own rules for augmenting selections. Set the selected fields of all of the joints and segments mentioned in sliceD. Hit Testing It looks like GGSliceOps.WalkPointsInDescriptor has to return a "done" BOOLEAN for this to work properly. on to next non-NIL child end of the line ?? Takes a slice and calls the walkProc for each segment in the slice with the segment data and possibly an associated transformation. It returns a slice descriptor which describes all segments of the slice for which the walkProc returned TRUE. on to next non-NIL child on to next non-NIL child ÊBÈ–(cedarcode) style•NewlineDelimiter ˜codešœ™KšÏbœA™IKšœ ÏeœI™TK™ Kšœ(™(K™#K™&K™—šÏk ˜ KšœŸœ‘Ÿœ˜Ì—K˜šÏnœŸœŸ˜KšŸœ Ÿœ”Ÿœ˜°KšŸœ Ÿ˜-K˜Kšœ Ÿœ˜+Kšœ Ÿœ˜)Kšœ Ÿœ˜&KšœŸœ˜#KšœŸœ˜#KšœŸœ˜KšœŸœ&˜AKšœ Ÿœ˜-KšœŸœ ˜5Kšœ Ÿœ ˜1Kšœ Ÿœ˜*KšœŸœ˜'KšœŸœ˜1Kšœ Ÿœ˜*KšœŸœ˜#KšœŸœ˜3KšœŸœ˜Kšœ Ÿœ Ÿœ ˜*KšœŸœ˜0KšœŸœ˜0KšœŸœ˜6KšœŸœ˜,KšœŸœ˜2KšœŸœ˜!KšœŸœ˜/KšœŸœ˜3KšœŸœ"˜9KšœŸœ!˜7KšœŸœ#˜;KšœŸœ&˜AKšœŸœ˜1KšœŸœ˜!Kšœ Ÿœ˜'KšœŸœ!˜7KšœŸœ$˜=KšœŸœ!˜5Kšœ Ÿœ˜+KšœŸœ ˜7KšœŸœ˜2KšœŸœ˜!Kšœ Ÿœ˜+KšœŸœ˜1KšœŸœ ˜5KšœŸœ)˜GKšœŸœ˜3Kšœ Ÿœ˜'Kšœ Ÿœ˜+Iprocšœ Ÿœ˜#Kšœ Ÿœ˜'KšœŸœ˜Kšœ Ÿœ˜'Kšœ Ÿœ˜%Kšœ Ÿœ˜)KšœŸœ˜/KšœŸœ'˜;Kšœ Ÿœ˜/KšœŸœ˜#Kšœ Ÿœ˜'K˜Kšœ Ÿœ˜)Kšœ Ÿœ˜)Kšœ Ÿœ˜+Kšœ Ÿœ˜+Kšœ Ÿœ˜'K˜Lšœ ŸœŸœ˜'LšœŸœ˜.K˜Kš œŸœŸœ Ÿœ˜;—head1šœ™K™—š œŸœŸœŸœ˜FšœŸœ˜Kšœ˜Kšœ˜Kš ™ Kšœ"˜"K˜8Kšœ"˜"Kšœ˜K˜Kš™K˜K˜Kšœ˜Kšœ$˜$Kšœ4˜4Kšœ6˜6Kšœ>˜>K˜(Kšœ,˜,Kš ™ Kšœ˜Kš™Kšœ˜Kšœ"˜"Kšœ˜Kšœ˜Kš™Kšœ$˜$Kšœ*˜*Kšœ˜Kšœ ˜ Kšœ*˜*Kšœ ˜ Kšœ$˜$Kšœ ˜ Kšœ.˜.Kš™Kšœ0˜0K˜8Kšœ8˜8Kšœ4˜4Kšœ$˜$Kšœ˜Kšœ&˜&Kšœ!˜!šÏi˜KšÐbi ™ Kš¢#™#—Kš¡$˜$Kš¡6˜6Kš¡;˜;Kš¡(˜(Kš¡,˜,Kš¡0˜0š¡4˜4Kš¢™Kš¢™—Kš¡"˜"Kš¡(˜(Kš¡(˜(Kš¡$˜$Kš¡$˜$Kš¡(˜(Kš¡(˜(Kš¡(˜(Kš¡(˜(Kš¡$˜$Kš¡"˜"Kš¡!˜!Kš¡!˜!Kš¡˜Kš¡˜Kš¡˜K˜—Kš "œ˜*K˜K˜—š œŸœŸœŸœ˜FšœŸœ˜Kšœ˜Kšœ˜Kš ™ Kšœ"˜"K˜8Kšœ"˜"Kšœ˜K˜Kš™K˜!K˜#Kšœ˜Kšœ&˜&Kšœ4˜4Kšœ-˜-K˜5K˜(Kšœ,˜,Kš ™ Kšœ˜Kš™Kšœ˜Kšœ"˜"Kšœ˜Kšœ˜Kš™Kšœ$˜$Kšœ*˜*Kšœ˜Kšœ ˜ Kšœ*˜*Kšœ ˜ Kšœ$˜$Kšœ ˜ Kšœ.˜.Kš™Kšœ0˜0K˜8Kšœ8˜8Kšœ4˜4Kšœ$˜$Kšœ˜Kšœ&˜&Kšœ!˜!š¡˜Kš¢ ™ Kš¢#™#—Kš¡$˜$Kš¡6˜6Kš¡;˜;Kš¡(˜(Kš¡4˜4Kš¡,˜,Kš¡0˜0š¡4˜4Kš¢™Kš¢™—Kš¡"˜"Kš¡(˜(Kš¡(˜(Kš¡$˜$Kš¡$˜$Kš¡(˜(Kš¡(˜(Kš¡(˜(Kš¡(˜(Kš¡$˜$Kš¡$˜$Kš¡!˜!Kš¡!˜!Kš¡˜Kš¡˜K˜K˜—Kš "œ˜*K˜K˜—š œŸœ ŸœŸœ#ŸœŸœ'Ÿœ ŸœŸœ˜µKšœŸœR˜išœ Ÿœ ˜Kšœ)˜)KšœŸœ˜ K˜ KšœŸœŸœŸœ˜&Kšœ$˜$Kšœ$˜$Kšœ Ÿœ˜—š ŸœŸœŸœŸœŸœŸ˜:K˜KšŸœ˜—Kšœ>Ÿœ˜CšŸœŸœÏcn˜ˆKšœ0ŸœœŸœ£#˜cš Ÿœ ŸœŸœ'Ÿœ ŸœŸ˜QKšœ/ŸœœŸœ£&˜dKšŸœ˜—K˜—Kšœ6Ÿœ˜;Kšœ˜K˜—š œŸœ ŸœŸœŸœ ŸœŸœ˜oKš œŸœŸœ Ÿœ%Ÿœ'˜—šœ Ÿœ ˜Kšœ)˜)KšœŸœ˜ K˜ KšœŸœŸœŸœ˜&Kšœ$˜$Kšœ$˜$Kšœ Ÿœ˜—š ŸœŸœŸœŸœŸœŸ˜:K˜KšŸœ˜—Kšœ<Ÿœ˜AKšœ˜—K™Kšœ™š œŸœŸœ Ÿœ˜MKšŸœ'˜-K˜—š œŸœŸœ Ÿœ˜MKšŸœ'˜-K˜—M™Kšœ ™ š   œŸœ$ŸœŸœŸœŸœ ˜[š œŸœŸœ˜CKšœ˜K˜!Kšœ0˜0Kšœ Ÿœ˜KšœŸœ3˜MK˜—LšœŸœ˜+KšœŸœ ˜*KšœŸœ˜;L˜K˜+K˜—K˜Kšœ™š œŸ œ”Ÿœ˜ÆKšœ2ŸœŸœ˜?Kšœ#Ÿœ˜9Kšœ Ÿœ ˜1Kšœ ŸœŸœ˜K˜KšŸœŸœŸœŸœ˜/Kš ŸœŸœŸœ ŸœŸœŸœ˜2K˜Kšœ$ŸœŸœ ˜KKšœŸœŸœ˜BKš œŸœŸœŸœŸœ˜BKš œŸœŸœŸœŸœ˜7K˜Kšœz˜zKš)™)šŸœŸœ ŸœŸœ˜+Kšœ(Ÿœ˜-Kšœ4˜4KšœZ˜ZKšœ Ÿœ˜K˜—šŸœŸœ Ÿœ Ÿœ˜%Kšœ(Ÿœ˜-Kšœ4˜4KšœW˜WKšœ Ÿœ˜K˜—šŸœŸœ ŸœŸœŸœŸœŸœ˜\Kšœ(Ÿœ˜-Kšœ4˜4K˜—K˜—K˜Kšœ™š œŸ œŸœŸœ˜šŸœ ŸœŸœ˜˜(Kšœk™k—˜K™>—Kšœ Ÿœ˜!K˜—šŸœ˜˜(Kšœk™k—K˜>K˜K˜—K˜—Kšœ Ÿœ ˜L˜-K˜3šŸœ Ÿ˜KšŸœJ˜N—Kšœ)™)KšœŸœ ˜K˜—šŸœ£7˜>š  œŸœŸœŸœ˜=KšœQŸœ ˜]K˜/KšŸœ Ÿœ=˜LKšœ'Ÿœ ˜7Kšœ˜—š   œŸœŸœŸœŸœ˜KK˜ K˜&šŸœ%Ÿœ˜-Kšœ'œ˜OK˜—šŸœ˜KšœŸœ ˜/KšŸœ'ŸœŸœ˜LšŸœ˜K˜ZšŸœ[Ÿœ ŸœŸ˜ršŸœŸœ)Ÿœ˜5K˜5K˜`KšŸœ˜Kšœ˜—K˜6K˜8Kšœ'Ÿœ ˜7KšŸœ˜—K˜—K˜—K˜—KšœMŸœ ˜YK˜DK˜—K˜K˜—š œŸ œŸœ˜1Kšœ™K™¼Kš ŸœŸœŸœŸœŸœŸœ˜!KšŸœŸœŸœ˜"K˜KšœŸœŸœŸœ˜'Kš Ÿœ ŸœŸœ ŸœŸœŸœ˜1K˜šŸ˜Kšœ Ÿœ˜KšœŸœ ˜*KšœŸœŸœ˜0KšœŸœ˜KšœŸœ ˜&Kšœ ŸœŸœ˜,KšœŸœŸœ Ÿœ˜$K˜KšœÏtœ¤ œ¤˜"Kšœ¤œ¤ œ ¤˜&Kšœ¤œ¤ œ¤˜$Kšœ¤œ¤ œ ¤˜*K˜š Ÿœ ŸœŸœ%ŸœŸ˜OK˜KšŸœ˜—š Ÿœ ŸœŸœ!ŸœŸ˜GK˜KšŸœ˜—K˜šÑbklœ œ¥˜šŸœŸœ˜šŸœ ŸœŸ˜Kšœ œ1˜CKšœ£6˜TK˜K˜!K˜KšŸœ˜—šŸœŸœŸœ£*˜GKš£'™'šœ$£˜8K™ —š Ÿœ ŸœŸœ%Ÿœ ŸœŸ˜OK˜KšŸœ˜—K˜—K˜—šŸœ£˜šŸœŸœŸ˜Kšœ œ1˜CKšœ£6˜TK˜K˜!K˜KšŸœ˜—Kš ŸœŸœŸœŸœ£Q˜‡K˜K˜——š¥œ˜K™ š Ÿœ ŸœŸœ*Ÿœ ŸœŸ˜TK˜KšŸœ˜—Kšœ%£˜9K˜—K˜Kšœ)£˜:KšœŸœ£˜5KšœŸœ£˜2KšœŸœ£˜5KšœŸœ£˜4K™!K™K˜K˜&K˜K˜K˜K˜"K˜K˜ K™KšŸœ˜—K˜K˜K˜—K™šœ™K˜—š œŸ œÙ˜öKšœ™KšœP™PKšœŸœ ˜.Kšœ&Ÿœ˜=Kšœ Ÿœ Ÿœ˜"Kš œŸœ ŸœŸœŸœ˜:KšœŸœŸœŸœŸœŸœŸœŸœ#˜tš Ÿœ ŸœŸœ-Ÿœ ŸœŸ˜YKšœ Ÿœ,ŸœŸœ*˜mšŸœ Ÿœ£&˜9KšŸœ Ÿœ&ŸœŸœ;˜|KšŸœŸœŸœ&ŸœF˜ˆKšŸœ&ŸœŸœŸœŸœŸœ!ŸœŸœŸœŸœŸœF˜ëK˜—KšŸœŸœŸœ.˜LKšŸœ˜—K˜K˜—š œŸ œ‰ŸœŸœ.˜áKšœ ™ Kšœy™yKšœŸœ ˜.Kšœ!Ÿœ ˜3Kšœ&Ÿœ˜=Kšœ Ÿœ Ÿœ˜"Kš œŸœ ŸœŸœŸœ˜:Kšœ Ÿœ Ÿœ˜KšœŸœŸœŸœŸœŸœŸœŸœ#˜tKš œŸœŸœŸœ ŸœŸœŸœ˜_š Ÿœ ŸœŸœ-Ÿœ ŸœŸ˜Yš Ÿœ ŸœŸœŸœ£ ˜MKšŸœ Ÿœ'Ÿœ ŸœŸœŸœŸœŸœ%˜›KšŸœŸœŸœ'Ÿœ ŸœŸœŸœŸœ0˜§KšŸœ'Ÿœ ŸœŸœŸœŸœŸœŸœŸœŸœ!ŸœŸœŸœŸœŸœ0˜ŠK˜—KšŸœŸœŸœ.˜LKšŸœŸœŸœ$˜=KšŸœ˜—K˜—K˜š œŸ œNŸœ˜tK™€K™š  œ˜!š Ÿœ ŸœŸœ-Ÿœ ŸœŸ˜YKšœŸœ%˜1Kš ŸœŸœŸœœŸœŸœ2£˜KšŸœ˜—K˜—KšœŸœ ˜.Kš™šŸœŸœŸœ˜#Kšœ.˜.Kšœ7˜7K˜—Kš™š Ÿœ ŸœŸœ-Ÿœ ŸœŸ˜YKš œŸœŸœŸœŸœ˜NKšŸœ˜—Kš™šŸ˜š   œŸœŸœ ŸœŸœ˜BKšœ-˜-K˜—K˜;KšŸœ˜—K˜K˜—š  œŸœŸœNŸœ˜mK™K™KšœŸœ ˜.š Ÿœ ŸœŸœ-Ÿœ ŸœŸ˜YKšœ%Ÿœ˜=KšŸœ˜—K˜K™—š œŸ œ$Ÿœf˜®Kšœ¼™¼š  œ˜!Kšœ ŸœŸœ˜#Kšœ˜Kš œ ŸœŸœŸœŸœŸœ˜Iš Ÿœ ŸœŸœ-Ÿœ ŸœŸ˜YKšœŸœ ŸœŸœŸœŸœŸœŸœ˜aKšœŸœ ŸœŸœŸœŸœ ŸœŸœ˜FdefaultšŸœŸœ"˜(NšŸœs˜w—KšŸœ ŸœŸœ˜3KšŸœ˜—K˜—KšœŸœ ˜.KšœŸœ˜+Kšœ ŸœŸœ˜%Kšœ˜K˜Kš œŸœŸœŸœŸœŸœ˜KKš#™#šŸœŸœŸœ˜#KšŸœŸœ9˜YKšŸœ/˜3Kšœ7˜7K˜—Kš™šŸ˜Kšœ˜š Ÿœ ŸœŸœ-Ÿœ ŸœŸ˜YNšœŸœ ŸœŸœŸœŸœŸœŸœ˜cNšœŸœŸœŸœŸœŸœ ŸœŸœ˜JNšœ&Ÿœ!Ÿœ˜bKšŸœŸœŸœ ˜9KšŸœ˜—KšŸœ˜—K˜K˜—š  œŸœŸœ$Ÿœf˜§KšœŸœ™#KšœŸœ ˜.KšœŸœ˜+Kšœ ŸœŸœ˜#K˜Kšœ˜K˜'K˜Kš œ ŸœŸœŸœŸœŸœ˜Iš Ÿœ ŸœŸœ-Ÿœ ŸœŸ˜YK˜šŸœ ŸœŸœ£˜8Kšœ Ÿœ˜K˜K˜—š ŸœŸœŸœŸœ£˜:K˜#K˜K˜—šŸœ£˜$Kšœ Ÿœ˜KšœŸœ˜K˜—KšœP˜PKšŸœ Ÿ œ Ÿœ˜4KšŸœ˜—K˜K˜—š œŸ œ”Ÿœ˜¿K™«KšœŸœŸœ˜-Kšœ2ŸœŸœ˜?Kšœ#Ÿœ˜9Kšœ Ÿœ ˜1KšŸœŸœŸœŸœ™/Kš ŸœŸœŸœ ŸœŸœŸœ™2Kšœ$ŸœŸœ ˜KKšœŸœŸœ˜BKš œŸœŸœŸœŸœ˜BKš œŸœŸœŸœŸœ˜7šŸœ Ÿœ Ÿœ˜ K˜&šŸœ>Ÿœ ŸœŸ˜XšŸœŸœŸœ£<˜ZKš œ œ1ŸœŸœŸœŸœŸœP˜Ã—š ŸœŸœŸœŸœ£(˜GKšœ œŸœR˜‹—K˜KšŸœ˜—K˜—šŸœŸœ Ÿœ˜šŸœ>ŸœŸœŸ˜ZKš ŸœŸœŸœ œ1Ÿœ=˜°KšŸœ˜—K˜—šŸœŸœ Ÿœ˜šŸœ5Ÿœ ŸœŸ˜NKš ŸœŸœŸœ œŸœR˜§KšŸœ˜—K˜—K˜K˜—š œŸ œ”Ÿœ˜ÆKšœ2ŸœŸœ˜?Kšœ˜Kšœ#Ÿœ˜9Kšœ Ÿœ ˜1K˜KšŸœŸœŸœŸœ˜/Kš ŸœŸœŸœ ŸœŸœŸœ˜2K˜Kšœ$ŸœŸœ ˜KKšœŸœŸœ˜BKš œŸœŸœŸœŸœ˜BKš œŸœŸœŸœŸœ˜7K˜Kšœz˜zKš)™)šŸœŸœ ŸœŸœŸœ ŸœŸœ˜NKšœŸœŸœ&Ÿœ#˜‚K–([sliceD: GGModelTypes.SliceDescriptor]˜FK–F[slice: GGModelTypes.Slice, pointGen: GGModelTypes.PointGenerator]˜VKšœ˜—šŸœŸœ ŸœŸ˜)KšœH˜H—šŸœŸœ Ÿœ Ÿ˜#KšœE˜E—K˜K˜—šÐbnœŸ œWŸœK˜ÈJ™¥Kšœ ŸœŸœ˜Kšœ˜Kšœ˜KšœD£`˜¤KšŸœ ŸœŸœŸœ˜K™VKšœ œ%˜MKšœ~˜~K˜K˜—š œŸ œWŸœ4Ÿœ˜ÐJ™¥Kšœ ŸœŸœ˜Kšœ˜Kšœ˜KšœD£A˜…KšŸœ ŸœŸœŸœ˜K™VKšœ œ%˜MK˜„K˜K˜—š œŸœ1Ÿœ˜nKšœ3™3KšœŸœ˜+Kš ŸœŸœŸœŸœŸœŸœ˜+š ŸœŸœŸœ>Ÿœ ŸœŸ˜nKš ŸœŸœŸœŸœŸœ˜`KšŸœ˜—K˜K˜—š œŸ œC˜^Kšœ$™$K™LKšœ ŸœŸœ Ÿœ#˜Cš ŸœŸœŸœ&ŸœŸœŸ˜ZKšœ/Ÿœ£˜_KšŸœ˜—šŸœŸœŸœ£˜2KšœŸœ˜+KšœŸœŸœ˜'KšŸœŸœŸœŸœ˜"K˜*š ŸœŸœŸœ6ŸœŸœŸ˜lKšŸœŸœŸœ œF˜€KšŸœ˜—K˜—K˜K˜—š¦œŸ œ-Ÿœ˜iKšœ&™&Kšœ˜KšœŸœ˜2Kšœ ŸœŸœ˜KšœŸœŸœ˜Kšœ ŸœŸœ Ÿœ#˜CK˜Gš ŸœŸœŸœ%ŸœŸœŸ˜WKšœ'œ"˜YKšŸœŸœŸœ Ÿ˜&šŸœ˜K˜HKšœ Ÿœ˜K˜—˜!KšœD˜D—KšŸœ˜—KšŸœ ŸœŸœ Ÿœ˜9K˜—K™šœ ™ K˜—š  œŸ œ$Ÿœn˜«KšœŸœ˜+KšœŸœ ˜.Kšœ‘™‘šŸœŸœŸœ˜š ŸœŸœŸœ)ŸœŸœŸ˜MKšœ!ŸœÐbkœ˜GKšŸœ˜—K˜—šŸœ˜š ŸœŸœŸœ7ŸœŸœŸ˜[KšŸœ ŸœŸœV§œ˜qKšŸœ˜—K˜—Kšœ˜KšŸœŸœŸœŸœT˜ŠšŸœŸœŸœ˜$š  œŸœŸœŸœŸœ£˜VK™KK˜/Kš Ÿœ ŸœŸœŸœŸœ£˜>Kšœ6£˜TKšœ£&˜CKšŸœŸœ£˜!K˜—š   œŸœŸœŸœŸœ£˜UK™KšŸœŸœ£-˜QK˜TK˜3Kšœ;˜;K˜K˜—K˜—Kšœ˜KšœŸœŸœ˜*K˜K˜K˜JKšŸœŸœ>˜TKšœ˜—K˜—K˜šœ™K˜—š œŸœŸœ ˜XKšœS™Sš ŸœŸœŸœ4ŸœŸœŸ˜XšŸœ ŸœŸœ˜Kš Ÿœ ŸœŸœŸœŸœ£˜7KšŸœ˜K˜—KšŸœ˜—K˜K˜—š  œŸœŸœ+ŸœŸœ Ÿœ˜cKšœ˜Kšœ˜KšŸœŸœŸœŸœ ˜-Kšœ Ÿœ˜!šŸœ*ŸœŸœ˜6K˜%K˜—šŸœ˜š ŸœŸœŸœ4ŸœŸœŸ˜XKšŸœ ŸœŸœŸœ<˜YKšŸœ˜—K˜9K˜—K˜K˜—š   œŸ œŸœŸœŸœ Ÿœ˜WKšœŸœ ˜.Kšœ!Ÿœ ˜1KšœŸœ˜K™?š Ÿœ ŸœŸœ-Ÿœ ŸœŸ˜WK˜šŸœŸœ˜$KšœŸœ˜KšŸœŸœŸœ%˜WKšŸœŸœ!˜6KšŸœŸœŸœ.˜RK˜\KšŸœ˜K˜—K˜KšŸœ˜—KšŸœ@˜FK˜K˜—š œŸ œŸœŸœ˜5LšœŸœ ˜.LšœŸœ˜š Ÿœ ŸœŸœ.Ÿœ ŸœŸ˜\L˜LšŸœ˜—L˜.š Ÿœ ŸœŸœ.Ÿœ ŸœŸ˜\Lšœ-£/˜\LšŸœ˜—Lšœ˜L˜—š œŸœŸœŸœŸœ Ÿœ%Ÿœ ŸœŸœ ™zLšœ™LšœŸœ™Lšœ™KšœŸœ™L™LšœŸœŸœ™LšŸœŸœ#™=LšŸœ(™,L™L™L™šŸœŸœ™Lšœ.™.šŸœŸœŸœ Ÿ™šŸœŸœ™K™"Kš œŸœ ŸœŸœŸœŸœ3™YKšŸœŸœŸœI§œ™aK™—šŸœ™Kšœ™Kšœ™K™—Lšœ7™7šŸœ ŸœŸœ ŸœŸœŸœŸœ'Ÿœ™oKšœ•™•Kšœ Ÿœ£3™DKšŸœ)£#™RK™—šŸœ ŸœŸœ™Kšœ™KšœA™AK™—KšŸœA™ELšŸœ™—LšŸœ ™L™—LšŸœW™[L™K™—š œŸœŸœŸœŸœ Ÿœ%Ÿœ ŸœŸœ ˜zLšœŸœ˜L˜LšœŸœŸœ˜LšŸœŸœ#˜=LšŸœ(˜,L˜L˜L˜šŸœŸœ˜L˜.šŸœŸœŸœ Ÿ˜Lš œ?ŸœŸœŸœŸœ £<˜©–[slice: GGModelTypes.Slice]šŸœ ŸœŸœ ŸœŸœ%ŸœŸœ'Ÿœ˜‚Kšœ•™•Kšœ Ÿœ£3˜DKšŸœ)£#˜RK˜—šŸœ ŸœŸœ˜K˜K˜AK˜—K–[atom: ATOM]šŸœ>˜BLšŸœ˜—LšŸœ ˜L˜—LšŸœU˜YL˜K™—š œŸ œŸœŸœ˜Kšœ ŸœŸœ˜K˜.KšœŸœŸœ˜K˜šŸœŸœ˜K˜-KšŸœ˜K˜—šŸœŸœ˜"K˜&K˜9KšŸœ˜K˜K˜—Kš4™4Kšœ Ÿœ˜!Kšœ Ÿœ˜!KšœŸœ˜#Kšœ Ÿœ˜!K˜K˜HK˜HK˜LK˜HK˜KšœŸœ ˜!K˜ š ŸœŸœŸœ7ŸœŸœŸ˜[šŸœŸœŸœ˜Jš’™’KšœDŸœ&˜mKšœ@Ÿœ"˜ešŸœŸœ˜Kšœ.Ÿœ £˜QK˜iKšœ@Ÿœ"˜eK˜—šŸœ˜Kšœ.Ÿœ £˜QK˜iKšœ@Ÿœ"˜eK˜—K˜—šŸœ˜Jš™Kšœ‚£˜ šŸœŸœŸœ˜ Kšœ@Ÿœ"˜eK˜iK˜sK˜iK˜—šŸœ˜K˜iKšœ@Ÿœ"˜eK˜sK˜iK˜—K˜—K˜KšŸœ˜—K˜;K˜8K˜9K˜5K˜K˜—š  œŸ œ8Ÿœ˜tK™¬KšœŸœŸœ˜KšœŸœ˜2Kšœ˜KšŸœŸœŸœŸœ ˜*Kšœ Ÿœ˜ K˜Cš Ÿœ ŸœŸœ<Ÿœ ŸœŸ˜hK˜,Kš œ;Ÿœ ŸœŸœ œŸœŸœ˜¤KšŸœ˜—K˜;K˜K˜—š   œŸœŸœ#ŸœŸœ ˜gKšœŸœ˜2KšœŸœ˜5KšœŸœ˜.K˜YK˜šŸ˜šŸœŸ˜˜KšŸœŸœŸœŸœ˜-šŸœ$Ÿœ˜,KšœŸœŸœ˜(Kšœ£œA˜`šŸœŸ˜šœ Ÿœ ŸœŸœŸ˜%KšŸœ;˜?——šŸ˜šœ Ÿœ ŸœŸœŸ˜&KšŸœ=˜A——K˜—KšŸœŸœ ˜K˜—˜ KšŸœŸœŸœŸœ˜-šŸœ$Ÿ˜*Kšœ-Ÿœ˜8—KšŸœŸœ ˜K˜—˜šŸœŸ˜ K˜U—KšŸœŸœ ˜K˜—˜šŸœŸ˜ K˜V—KšŸœŸœ ˜K˜—KšŸœŸœ˜—šŸ˜˜ K˜Gšœ ŸœŸœŸœŸ˜*KšŸœE˜I—K˜——KšŸœ˜—K˜K˜—š œŸœŸœ˜AKšœŸœ ˜.K˜#K˜K˜—š œŸœŸœ˜@KšœŸœ ˜.š ŸœŸœŸœ)ŸœŸœŸ˜MK˜KšŸœ˜—K˜K˜—š œŸ œ%Ÿœ"˜iKšœN™NK™KšœŸœ˜2KšŸœŸœŸœŸœ˜"š Ÿœ ŸœŸœ<Ÿœ ŸœŸ˜hK˜,KšŸœ ŸœŸœ œ"˜SKšŸœ˜—K˜—K˜™ K™—KšœŸœŸœ˜5šœŸœŸœ˜&KšœŸœŸœ˜ Kšœ£7˜PKšœ˜K˜—KšœŸœŸœ˜=šœŸœŸœ˜*KšœŸœŸœ˜ Kšœ£2˜OKšœ˜K˜—KšœŸœŸœ˜9šœŸœŸœ˜(KšœŸœŸœ˜ Kšœ£7˜PKšœ˜—K˜š¦œŸ œŸœ˜`KšœŸœ˜2Kšœ ŸœŸœ˜%Kšœ˜Kšœ!˜!Kš œŸœŸœŸœŸœŸœ˜KKšœŸœŸœŸœŸœŸœŸœŸœ2˜KšœŸœ7˜IKšœ Ÿœ3˜AK˜K˜—š œŸ œ7˜ZKšœŸœ˜2Kšœ ŸœŸœ˜%KšŸœŸœŸœŸœ˜"K˜'š ŸœŸœŸœ>ŸœŸœŸ˜pKšŸœŸœŸœ œ˜_KšœGŸœ™iKšŸœ˜—K˜K˜—š¦œŸ œŸœ4˜yKšœŸœ˜2Kšœ ŸœŸœ˜%Kšœ&˜&Kšœ)˜)Kš œŸœŸœŸœŸœŸœ˜KKšœŸœŸœŸœŸœŸœŸœŸœ6˜‡KšœŸœ?˜UKšœŸœ;˜MK˜K˜—š¦œŸ œŸœ˜bKšœŸœ˜2Kšœ ŸœŸœŸœŸœŸœŸœŸœ˜d–[seq: GGModelTypes.Sequence]šŸœ ŸœŸœ˜šœ#Ÿœ˜BKšœ£Q˜fKšœŸœŸœŸœŸœŸœ œ£˜{Kšœ˜—šœ Ÿœ˜$Kšœ £˜Kšœ˜Kšœ Ÿœ˜Kšœ˜Kšœ˜—K˜—K˜K˜—š  œŸ œ*ŸœC˜ŒKšœ#Ÿœ˜@Kšœ ŸœŸœ%˜9KšŸœŸœŸœ£˜0šŸœŸœŸ˜ šŸœŸœŸœ£$˜FK–)[segGen: GGModelTypes.SegmentGenerator]šœ œ-˜VšŸœŸœŸœ˜K˜ KšŸœ˜K˜—Kšœ £˜7K˜—K™Kš ŸœŸœŸœŸœŸœ Ÿœ˜]K™Kš ŸœŸœŸœŸœŸœŸœ˜+K–[seq: GGModelTypes.Sequence]šœœ£˜`KšŸœ˜—K˜K˜—š  œŸ œ$Ÿœ˜bKšœíŸœ™òKšœŸœŸœ˜KšœŸœ ˜.KšœŸœ˜.K˜Cš Ÿœ ŸœŸœ-Ÿœ ŸœŸ˜WK˜Kšœ% œ˜CK˜^KšŸœ˜—K˜6K˜K˜—š¦ œŸ œ*Ÿœ.˜uKšœŸœ˜9Kšœ ŸœŸœ˜2Kš ŸœŸœŸœŸœ Ÿœ˜0šŸœŸœŸ˜ šŸœŸœŸœ£&˜HKšœ œ(˜KšŸœŸœŸœ˜K˜KšŸœ˜K˜—Kšœ £˜7K˜—K™Kš ŸœŸœŸœŸœŸœ Ÿœ˜]Kš ŸœŸœŸœŸœ Ÿœ˜0Kšœœ£˜[KšŸœ˜—K˜K˜—š¦ œŸ œ2Ÿœ)˜|KšœŸœ˜AKšœ ŸœŸœ˜2Kš ŸœŸœŸœŸœŸœ˜7šŸœŸœŸ˜ šŸœŸœŸœ£%˜GKšœ œ(˜SšŸœŸœŸœ˜#K˜KšŸœ˜K˜—Kšœ £˜7K˜—K™Kš ŸœŸœŸœŸœŸœ Ÿœ˜]Kš ŸœŸœŸœŸœŸœ˜7Kšœœ˜DKšŸœ˜—K˜—K˜Kšœ Ÿœ%˜6Kšœ£˜4K˜KšŸœ˜K˜—…—÷ Vü