DIRECTORY Basics, CodeTimer, CubicPaths, Feedback, FunctionCache, GGBasicTypes, GGBoundBox, GGBuiltinShapes, GGCircleCache, GGCircles, GGColorOps, GGContainer, GGCoreOps, GGCoreTypes, GGCubic2, GGDescribe, GGInterfaceTypes, GGModelTypes, GGOutline, GGParseIn, GGParseOut, GGSegment, GGSegmentTypes, GGShapes, GGSlice, GGSliceOps, GGTraj, GGTransform, GGUtility, Icons, Imager, ImagerBackdoor, ImagerBitmapContext, ImagerColor, ImagerColorFns, ImagerColorPrivate, ImagerSample, ImagerTransformation, IO, NamedColors, Real, RealFns, Rope, Vectors2d; GGUtilityImplA: CEDAR PROGRAM IMPORTS CodeTimer, Feedback, FunctionCache, GGBoundBox, GGCircles, GGColorOps, GGCoreOps, GGOutline, GGParseIn, GGParseOut, GGSegment, GGShapes, GGSlice, GGSliceOps, GGTraj, GGTransform, GGUtility, Imager, ImagerBackdoor, ImagerBitmapContext, ImagerColor, ImagerColorFns, ImagerColorPrivate, ImagerSample, IO, NamedColors, Real, RealFns, Rope, Vectors2d EXPORTS GGDescribe, GGUtility, GGBuiltinShapes, GGCircleCache = BEGIN AlignmentPoint: TYPE = GGInterfaceTypes.AlignmentPoint; Bitmap: TYPE = Imager.SampleMap; BitVector: TYPE = GGBasicTypes.BitVector; Cache: TYPE = FunctionCache.Cache; CachedCircle: TYPE = REF CachedCircleObj; CachedCircleObj: TYPE = GGCircleCache.CachedCircleObj; Color: TYPE = Imager.Color; Context: TYPE = Imager.Context; DefaultData: TYPE = GGModelTypes.DefaultData; FeatureData: TYPE = GGModelTypes.FeatureData; Path: TYPE = CubicPaths.Path; Point: TYPE = GGBasicTypes.Point; PointProc: TYPE = CubicPaths.PointProc; Range: TYPE = FunctionCache.Range; ROPE: TYPE = Rope.ROPE; Segment: TYPE = GGSegmentTypes.Segment; SegmentGenerator: TYPE = GGModelTypes.SegmentGenerator; Sequence: TYPE = GGModelTypes.Sequence; SequenceOfReal: TYPE = REF SequenceOfRealObj; SequenceOfRealObj: TYPE = GGCoreTypes.SequenceOfRealObj; Slice: TYPE = GGModelTypes.Slice; SliceDescriptor: TYPE = GGModelTypes.SliceDescriptor; SliceGenerator: TYPE = GGModelTypes.SliceGenerator; SliceParts: TYPE = GGModelTypes.SliceParts; Traj: TYPE = GGModelTypes.Traj; TrajData: TYPE = GGModelTypes.TrajData; Vector: TYPE = GGBasicTypes.Vector; Problem: PUBLIC SIGNAL [msg: Rope.ROPE] = CODE; EntityNotFound: PUBLIC SIGNAL = CODE; NotYetImplemented: PUBLIC SIGNAL = CODE; StartFeatureDataList: PUBLIC PROC [] RETURNS [entityList, ptr: LIST OF FeatureData] = { ptr _ entityList _ NIL; }; AddFeatureData: PUBLIC PROC [entity: FeatureData, entityList, ptr: LIST OF FeatureData] RETURNS [newList, newPtr: LIST OF FeatureData] = { 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; }; }; CopyFeatureDataList: PUBLIC PROC [l: LIST OF FeatureData] RETURNS [copyList: LIST OF FeatureData] = { z: LIST OF FeatureData _ NIL; IF l = NIL THEN RETURN[NIL]; copyList _ CONS[l.first, NIL]; z _ copyList; UNTIL (l _ l.rest) = NIL DO z.rest _ CONS[l.first, NIL]; z _ z.rest; ENDLOOP; }; FeatureDataNconc: PUBLIC PROC [l1, l2: LIST OF FeatureData] RETURNS [bigList: LIST OF FeatureData] = { z: LIST OF FeatureData _ l1; IF z = NIL THEN RETURN[l2]; UNTIL z.rest = NIL DO z _ z.rest; ENDLOOP; z.rest _ l2; RETURN[l1]; }; StartSequenceList: PUBLIC PROC [] RETURNS [entityList, ptr: LIST OF Sequence] = { ptr _ entityList _ NIL; }; AddSequence: PUBLIC PROC [entity: Sequence, entityList, ptr: LIST OF Sequence] RETURNS [newList, newPtr: LIST OF Sequence] = { 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; }; }; AppendSequenceList: PUBLIC PROC [list1, list2: LIST OF Sequence] RETURNS [result: LIST OF Sequence] = { pos: LIST OF Sequence; newCell: LIST OF Sequence; IF list1 = NIL THEN RETURN[list2]; result _ CONS[list1.first, NIL]; pos _ result; FOR l: LIST OF Sequence _ list1.rest, l.rest UNTIL l = NIL DO newCell _ CONS[l.first, NIL]; pos.rest _ newCell; pos _ newCell; ENDLOOP; pos.rest _ list2; }; -- end of AppendSequenceList DeleteSequenceFromList: PUBLIC PROC [seq: Sequence, seqList: LIST OF Sequence] RETURNS [smallerList: LIST OF Sequence] = { beforeEnt, ent, afterEnt: LIST OF Sequence; found: BOOL _ FALSE; [beforeEnt, ent, afterEnt, found] _ FindSequenceAndNeighbors[seq, seqList]; IF NOT found THEN RETURN[seqList]; IF beforeEnt = NIL THEN smallerList _ afterEnt ELSE { beforeEnt.rest _ afterEnt; smallerList _ seqList; }; }; -- end of DeleteSequenceFromList FindSequenceAndNeighbors: PROC [entity: Sequence, entityList: LIST OF Sequence] RETURNS [beforeEnt, ent, afterEnt: LIST OF Sequence, found: BOOL _ FALSE] = { lastE: LIST OF Sequence _ NIL; eList: LIST OF Sequence _ entityList; IF eList = NIL THEN RETURN; UNTIL eList = NIL DO IF eList.first = entity THEN { beforeEnt _ lastE; ent _ eList; afterEnt _ eList.rest; found _ TRUE; RETURN; }; lastE _ eList; eList _ eList.rest; ENDLOOP; }; StartSliceDescriptorList: PUBLIC PROC [] RETURNS [entityList, ptr: LIST OF SliceDescriptor] = { ptr _ entityList _ NIL; }; AddSliceDescriptor: PUBLIC PROC [entity: SliceDescriptor, entityList, ptr: LIST OF SliceDescriptor] RETURNS [newList, newPtr: LIST OF SliceDescriptor] = { 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; }; }; AppendSliceDescriptorList: PUBLIC PROC [list1, list2: LIST OF SliceDescriptor] RETURNS [result: LIST OF SliceDescriptor] = { pos: LIST OF SliceDescriptor; newCell: LIST OF SliceDescriptor; IF list1 = NIL THEN RETURN[list2]; result _ CONS[list1.first, NIL]; pos _ result; FOR l: LIST OF SliceDescriptor _ list1.rest, l.rest UNTIL l = NIL DO newCell _ CONS[l.first, NIL]; pos.rest _ newCell; pos _ newCell; ENDLOOP; pos.rest _ list2; }; DeleteSliceDescriptorFromList: PUBLIC PROC [sliceD: SliceDescriptor, sliceDList: LIST OF SliceDescriptor] RETURNS [smallerList: LIST OF SliceDescriptor] = { beforeEnt, ent, afterEnt: LIST OF SliceDescriptor; found: BOOL _ FALSE; [beforeEnt, ent, afterEnt, found] _ FindSliceDescriptorAndNeighbors[sliceD, sliceDList]; IF NOT found THEN RETURN[sliceDList]; IF beforeEnt = NIL THEN smallerList _ afterEnt ELSE { beforeEnt.rest _ afterEnt; smallerList _ sliceDList; }; }; FindSliceDescriptorAndNeighbors: PROC [sliceD: SliceDescriptor, sliceDList: LIST OF SliceDescriptor] RETURNS [beforeEnt, ent, afterEnt: LIST OF SliceDescriptor, found: BOOL _ FALSE] = { lastE: LIST OF SliceDescriptor _ NIL; eList: LIST OF SliceDescriptor _ sliceDList; IF eList = NIL THEN RETURN; UNTIL eList = NIL DO IF eList.first = sliceD THEN { beforeEnt _ lastE; ent _ eList; afterEnt _ eList.rest; found _ TRUE; RETURN; }; lastE _ eList; eList _ eList.rest; ENDLOOP; }; CopySliceDescriptorList: PUBLIC PROC [l1: LIST OF SliceDescriptor] RETURNS [val: LIST OF SliceDescriptor] = { z: LIST OF SliceDescriptor _ NIL; val _ NIL; IF l1 = NIL THEN RETURN[val]; val _ CONS[l1.first, val]; z _ val; UNTIL (l1 _ l1.rest) = NIL DO z.rest _ CONS[l1.first, z.rest]; z _ z.rest; ENDLOOP; RETURN[val]; }; -- of Append AllFalse: PUBLIC PROC [bitvec: BitVector] RETURNS [BOOL] = { FOR i: NAT IN [0..bitvec.len) DO IF bitvec[i] = TRUE THEN RETURN[FALSE]; ENDLOOP; RETURN[TRUE]; }; AllTrue: PUBLIC PROC [bitvec: BitVector] RETURNS [BOOL] = { FOR i: NAT IN [0..bitvec.len) DO IF bitvec[i] = FALSE THEN RETURN[FALSE]; ENDLOOP; RETURN[TRUE]; }; CopyPattern: PUBLIC PROC [pattern: SequenceOfReal] RETURNS [new: SequenceOfReal] = { IF pattern=NIL THEN RETURN[NIL]; new _ NEW[SequenceOfRealObj[pattern.len]]; FOR index: NAT IN [0..pattern.len) DO new[index] _ pattern[index]; ENDLOOP; }; EquivalentPatterns: PUBLIC PROC [p1, p2: SequenceOfReal] RETURNS [BOOL _ FALSE] = { IF p1.len # p2.len THEN RETURN[FALSE]; FOR i: NAT IN [0..p1.len) DO IF p1[i] # p2[i] THEN RETURN[FALSE]; ENDLOOP; RETURN[TRUE]; }; ChangeHue: PUBLIC PROC [startColor: Color, hueFrom: Color] RETURNS [newColor: Color] = { startHSV: ImagerColorFns.HSV; hue: REAL; IF startColor = NIL OR hueFrom = NIL THEN RETURN[NIL]; WITH startColor SELECT FROM startColorC: Imager.ConstantColor => { hueFromC: Imager.ConstantColor _ NARROW[hueFrom]; startHSV _ ImagerColorFns.HSVFromRGB[ImagerColorPrivate.RGBFromColor[startColorC]]; hue _ ImagerColorFns.HSVFromRGB[ImagerColorPrivate.RGBFromColor[hueFromC]].H; newColor _ ImagerColor.ColorFromRGB[ImagerColorFns.RGBFromHSV[[hue, startHSV.S, startHSV.V]]]; }; ENDCASE => newColor _ startColor; }; ColorToRope: PUBLIC PROC [color: Imager.Color] RETURNS [rope: Rope.ROPE] = { stream: IO.STREAM; stream _ IO.ROS[]; GGParseOut.WriteColor[stream, color]; rope _ IO.RopeFromROS[stream]; }; ColorFromRope: PUBLIC PROC [rope: Rope.ROPE] RETURNS [color: Imager.Color] = { stream: IO.STREAM; version: REAL _ GGUtility.version; stream _ IO.RIS[rope]; color _ GGParseIn.ReadColor[stream, version]; }; ColorToRGBRope: PUBLIC PROC [color: Imager.Color] RETURNS [rope: Rope.ROPE] = { ENABLE Feedback.Problem, Imager.Error => GOTO Abort; constantColor: Imager.ConstantColor _ NARROW[color]; red, green, blue: REAL; [red,green,blue] _ GGCoreOps.ExtractRGB[constantColor]; rope _ IO.PutFR["RGB: %1.3f %1.3f %1.3f", [real[red]], [real[green]], [real[blue]] ]; EXITS Abort => rope _ "RGB: none"; }; ColorToCMYKRope: PUBLIC PROC [color: Imager.Color] RETURNS [rope: Rope.ROPE] = { ENABLE Feedback.Problem, Imager.Error => GOTO Abort; constantColor: Imager.ConstantColor _ NARROW[color]; cyan, magenta, yellow, black: REAL; IF NOT ISTYPE[constantColor, ImagerColor.OpConstantColor] THEN GOTO Abort; [cyan, magenta, yellow, black] _ GGColorOps.ExtractCMYK[constantColor]; rope _ IO.PutFR["CMYK: %1.3f %1.3f %1.3f %1.3f", [real[cyan]], [real[magenta]], [real[yellow]], [real[black]] ]; EXITS Abort => rope _ "CMYK: none"; }; ColorToIntensityRope: PUBLIC PROC [color: Imager.Color] RETURNS [rope: Rope.ROPE] = { ENABLE Feedback.Problem, Imager.Error => GOTO Abort; constantColor: Imager.ConstantColor _ NARROW[color]; intensity: REAL _ GGColorOps.ExtractIntensity[constantColor]; rope _ IO.PutFR["Intensity: %1.3f", [real[intensity]] ]; EXITS Abort => rope _ "Intensity: none"; }; ColorToNameRope: PUBLIC PROC [color: Imager.Color] RETURNS [rope: Rope.ROPE] = { ENABLE Feedback.Problem, Imager.Error => GOTO Abort; constantColor: Imager.ConstantColor _ NARROW[color]; red, green, blue: REAL; [red,green,blue] _ GGCoreOps.ExtractRGB[constantColor]; rope _ NamedColors.HSLToRope[ImagerColorFns.HSLFromRGB[[red,green,blue]]]; EXITS Abort => rope _ "none"; }; PolygonInCircle: PUBLIC PROC [sideCount: NAT, origin: Point, radius: REAL, defaults: DefaultData] RETURNS [outline: Slice] = { traj: Traj; theta0, theta, deltaTheta, sin, cos: REAL; lastPoint, thisPoint: Point; success: BOOL; seg: Segment; IF sideCount = 0 THEN RETURN[NIL]; deltaTheta _ 360.0/sideCount; theta0 _ -90.0 + deltaTheta/2.0; sin _ RealFns.SinDeg[theta0]; cos _ RealFns.CosDeg[theta0]; thisPoint _ Vectors2d.Add[Vectors2d.Scale[[cos, sin], radius], origin]; traj _ GGTraj.CreateTraj[thisPoint]; lastPoint _ thisPoint; FOR i: NAT IN [1..sideCount) DO theta _ theta0 + i*deltaTheta; sin _ RealFns.SinDeg[theta]; cos _ RealFns.CosDeg[theta]; thisPoint _ Vectors2d.Add[Vectors2d.Scale[[cos, sin], radius], origin]; seg _ GGSegment.MakeLine[lastPoint, thisPoint, NIL]; GGSegment.SetDefaults[seg, defaults]; success _ GGTraj.AddSegment[traj, hi, seg, lo]; IF NOT success THEN SIGNAL Problem[msg: "Couldn't add segment"]; lastPoint _ thisPoint; ENDLOOP; sin _ RealFns.SinDeg[theta0]; cos _ RealFns.CosDeg[theta0]; thisPoint _ Vectors2d.Add[Vectors2d.Scale[[cos, sin], radius], origin]; seg _ GGSegment.MakeLine[lastPoint, thisPoint, NIL]; GGSegment.SetDefaults[seg, defaults]; GGTraj.CloseWithSegment[traj, seg, lo]; outline _ GGOutline.CreateOutline[traj, ImagerColor.ColorFromGray[0.5]]; GGSliceOps.SetStrokeJoint[outline, GGSliceOps.NewParts[outline, NIL, topLevel].parts, defaults.strokeJoint, NIL]; GGSliceOps.SetFillColor[outline, NIL, defaults.fillColor, $Set, NIL]; }; Box: PUBLIC PROC [origin: Point, sideLength: REAL, defaults: DefaultData] RETURNS [slice: Slice] = { halfSide: REAL _ sideLength/2.0; box: GGBoundBox.BoundBox _ GGBoundBox.CreateBoundBox[origin.x-halfSide, origin.y-halfSide, origin.x+halfSide, origin.y+halfSide]; sliceD: SliceDescriptor _ GGSlice.MakeBoxSlice[box, ul, GGTransform.Identity[] ]; completeSliceD: SliceDescriptor _ GGSliceOps.NewParts[sliceD.slice, NIL, slice]; slice _ sliceD.slice; GGSliceOps.SetDefaults[slice, completeSliceD.parts, defaults, NIL]; }; Circle: PUBLIC PROC [origin: Point, radius: REAL, defaults: DefaultData] RETURNS [slice: Slice] = { outerPoint: Point _ [origin.x + radius, origin.y]; sliceD: SliceDescriptor _ GGSlice.MakeCircleSlice[origin, outerPoint]; completeSliceD: SliceDescriptor _ GGSliceOps.NewParts[sliceD.slice, NIL, slice]; slice _ sliceD.slice; GGSliceOps.SetDefaults[slice, completeSliceD.parts, defaults, NIL]; }; KnotchedLine: PUBLIC PROC [p0, p1: Point, segmentCount: NAT] RETURNS [outline: Slice] = { delta: Vector; lastPoint, thisPoint: Point; traj: Traj; seg: Segment; success: BOOL; delta _ Vectors2d.Scale[Vectors2d.Sub[p1, p0], 1.0/segmentCount]; lastPoint _ p0; traj _ GGTraj.CreateTraj[lastPoint]; THROUGH [1..segmentCount) DO thisPoint _ Vectors2d.Add[lastPoint, delta]; seg _ GGSegment.MakeLine[lastPoint, thisPoint, NIL]; success _ GGTraj.AddSegment[traj, hi, seg, lo]; IF NOT success THEN SIGNAL Problem[msg: "Couldn't add segment"]; lastPoint _ thisPoint; ENDLOOP; thisPoint _ p1; seg _ GGSegment.MakeLine[lastPoint, thisPoint, NIL]; success _ GGTraj.AddSegment[traj, hi, seg, lo]; IF NOT success THEN SIGNAL Problem[msg: "Couldn't add segment"]; outline _ GGOutline.CreateOutline[traj, ImagerColor.ColorFromGray[0.5]]; }; DescribeTraj: PUBLIC PROC [traj: Traj] RETURNS [text: Rope.ROPE] = { trajData: TrajData _ NARROW[traj.data]; text _ SELECT trajData.role FROM open => IO.PutFR["a %g-segment open trajectory", [integer[trajData.segCount]]], fence => IO.PutFR["a %g-segment fence", [integer[trajData.segCount]]], hole => IO.PutFR["a %g-segment hole", [integer[trajData.segCount]]], ENDCASE => ""; }; DescribeJoint: PUBLIC PROC [traj: Traj, jointNum: NAT] RETURNS [text: Rope.ROPE] = { trajData: TrajData _ NARROW[traj.data]; end: BOOL _ FALSE; end _ GGTraj.IsEndJoint[traj, jointNum]; IF end THEN text _ IO.PutFR["end joint %g on ", [integer[jointNum]] ] ELSE text _ IO.PutFR["joint %g on ", [integer[jointNum]] ]; text _ Rope.Concat[text, DescribeSegment[traj, IF GGTraj.HiJoint[traj]=jointNum AND trajData.role=open THEN jointNum-1 ELSE jointNum]]; }; DescribeControlPoint: PUBLIC PROC [traj: Traj, segNum: NAT, cpNum: NAT] RETURNS [text: Rope.ROPE] = { text _ Rope.Cat[IO.PutFR["control point %g on ", [integer[cpNum]]], DescribeSegment[traj, segNum] ]; }; DescribeSegment: PUBLIC PROC [traj: Traj, segNum: NAT] RETURNS [text: Rope.ROPE] = { IF segNum=LAST[NAT] THEN text _ Rope.Cat["a segment on ", DescribeTraj[traj]] ELSE { seg: Segment _ GGTraj.FetchSegment[traj, segNum]; text _ Rope.Cat[seg.class.describe[seg, TRUE, TRUE, TRUE, NIL], IO.PutFR[" segment %g on ", [integer[segNum]]], DescribeTraj[traj]]; }; }; DescribeInterior: PUBLIC PROC [traj: Traj] RETURNS [text: Rope.ROPE] = { text _ Rope.Concat["The interior of ", DescribeTraj[traj]]; }; DescribeSequence: PUBLIC PROC [sliceD: SliceDescriptor] RETURNS [text: Rope.ROPE] = { text _ Rope.Cat[IO.PutFR["one or more parts of "], DescribeTraj[sliceD.slice]]; }; DescribeColor: PUBLIC PROC [color: Imager.Color] RETURNS [rope: Rope.ROPE] = { WITH color SELECT FROM constantColor: ImagerColor.ConstantColor => { op: ImagerColor.ColorOperator; colorType: GGColorOps.ColorType; [colorType, op] _ GGColorOps.GetColorType[color]; IF op#NIL THEN SELECT GGColorOps.GetOperatorType[op] FROM grayLinear, grayDensity, grayVisual => rope _ ColorAsIntensityAndNameRope[color]; map, buildMap, rgbLinear, colorMap => rope _ ColorAsRGBAndNameRope[color]; cmyk => rope _ ColorAsCMYKAndNameRope[color]; ENDCASE => rope _ "an unknown constant color operator type" ELSE SELECT colorType FROM constantSpecial => { special: ImagerColor.SpecialColor _ NARROW[constantColor]; rope _ SpecialColorAsRGBAndNameRope[special]; }; ENDCASE => rope _ "an unknown constant color type"; }; special: ImagerColor.SpecialColor => { rope _ special.name }; sampledBlack: ImagerColor.SampledBlack => { rope _ "a sampled black"; }; sampledColor: ImagerColor.SampledColor => { rope _ "a sampled color"; }; ENDCASE => { rope _ "an unknown color type"; }; }; SpecialColorAsRGBAndNameRope: PROC [color: Imager.SpecialColor] RETURNS [rope: Rope.ROPE] = { IF color#NIL THEN rope _ IO.PutFR["%g Name: %g %g %g", [rope[IF color.substitute=NIL THEN "No equivalent RGB " ELSE ColorToRGBRope[color.substitute]]], [rope[color.name]], [rope[ColorToCMYKRope[color.substitute]]], [rope[ColorToIntensityRope[color.substitute]]] ] ELSE rope _ "None"; }; ColorAsRGBAndNameRope: PROC [color: Imager.Color] RETURNS [rope: Rope.ROPE] = { cc: Imager.ConstantColor _ NARROW[color]; IF cc#NIL THEN rope _ IO.PutFR["%g CNS: %g %g %g", [rope[ColorToRGBRope[cc]]], [rope[ColorToNameRope[cc]]], [rope[ColorToCMYKRope[cc]]], [rope[ColorToIntensityRope[cc]]] ] ELSE rope _ "None"; }; ColorAsCMYKAndNameRope: PROC [color: Imager.Color] RETURNS [rope: Rope.ROPE] = { cc: Imager.ConstantColor _ NARROW[color]; IF cc#NIL THEN rope _ IO.PutFR["%g CNS: %g %g %g", [rope[ColorToCMYKRope[cc]]], [rope[ColorToNameRope[cc]]], [rope[ColorToRGBRope[cc]]], [rope[ColorToIntensityRope[cc]]] ] ELSE rope _ "None"; }; ColorAsIntensityAndNameRope: PROC [color: Imager.Color] RETURNS [rope: Rope.ROPE] = { cc: Imager.ConstantColor _ NARROW[color]; IF cc#NIL THEN rope _ IO.PutFR["%g CNS: %g %g %g", [rope[ColorToIntensityRope[cc]]], [rope[ColorToNameRope[cc]]], [rope[ColorToRGBRope[cc]]], [rope[ColorToCMYKRope[cc]]] ] ELSE rope _ "None"; }; ScalarButtonValuesToRope: PUBLIC PROC [names: LIST OF Rope.ROPE, values: LIST OF REAL, on: LIST OF BOOL] RETURNS [rope: Rope.ROPE] = { stream: IO.STREAM; stream _ IO.ROS[]; GGParseOut.WriteScalarButtonValues[stream, names, values, on]; rope _ IO.RopeFromROS[stream]; }; ScalarButtonValuesFromRope: PUBLIC PROC [rope: Rope.ROPE] RETURNS [names: LIST OF Rope.ROPE, values: LIST OF REAL, on: LIST OF BOOL] = { stream: IO.STREAM; version: REAL _ GGUtility.version; stream _ IO.RIS[rope]; [names, values, on] _ GGParseIn.ReadScalarButtonValues[stream, version]; }; FactoredTransformationToRope: PUBLIC PROC [transform: ImagerTransformation.Transformation] RETURNS [rope: Rope.ROPE] = { f: IO.STREAM _ IO.ROS[]; GGParseOut.WriteFactoredTransformation[f, transform]; rope _ IO.RopeFromROS[f]; }; FactoredTransformationFromRope: PUBLIC PROC [rope: Rope.ROPE] RETURNS [transform: ImagerTransformation.Transformation] = { f: IO.STREAM _ IO.RIS[rope]; transform _ GGParseIn.ReadFactoredTransformation[f]; }; alignmentColor: Imager.Color _ ImagerBackdoor.MakeStipple[145065B]; Create: PUBLIC PROC [] RETURNS [Cache] = { RETURN [FunctionCache.GlobalCache[] ]; }; Insert: PUBLIC PROC [x: Cache, radius: REAL] = { IF Lookup[x, radius]#NIL OR radius NOT IN [1.0..512.0] THEN RETURN ELSE { context: Imager.Context; argument: REF REAL _ NEW[REAL _ radius]; circle: GGBasicTypes.Circle; dummySize: NAT _ 0; side: INT _ 2*(Real.Fix[radius+1.0]+1); -- round up and add 1 bitmap: Bitmap _ ImagerSample.NewSampleMap[[max: [side, side]]]; cachedCircle: CachedCircle _ NEW[CachedCircleObj _ [bitmap: bitmap, cw: side, ch: side]]; context _ ImagerBitmapContext.Create[deviceSpaceSize: [side, side], scanMode: [down, right], surfaceUnitsPerInch: [72.0, 72.0], pixelUnits: TRUE]; ImagerBitmapContext.SetBitmap[context, bitmap]; context.SetColor[Imager.white]; context.MaskRectangle[ImagerBackdoor.GetBounds[context]]; context.SetColor[alignmentColor]; context.SetStrokeWidth[1.0]; circle _ GGCircles.CircleFromPointAndRadius[ [side/2, side/2], radius]; GGShapes.DrawCircle[dc: context, circle: circle ]; FunctionCache.Insert[x: x, argument: argument, value: cachedCircle, size: ImagerSample.WordsForMap[[side, side], 1] + 2, clientID: $GGCircle]; }; }; Lookup: PUBLIC PROC [x: Cache, radius: REAL] RETURNS [CachedCircle] = { FindRadius: FunctionCache.CompareProc = { arg: REAL _ NARROW[argument, REF REAL]^; RETURN [ABS[arg-radius] < 1.0E-3]; }; value: Range; ok: BOOL; [value, ok] _ FunctionCache.Lookup[x: x, compare: FindRadius, clientID: $GGCircle]; RETURN [IF ok THEN NARROW[value] ELSE NIL]; }; Remove: PUBLIC PROC [x: Cache, radius: REAL] = { FindRadius: FunctionCache.CompareProc = { arg: REAL _ NARROW[argument, REF REAL]^; RETURN [ABS[arg- radius] < 1.0E-3]; }; [] _ FunctionCache.Obtain[x: x, compare: FindRadius, limit: 1, clientID: $GGCircle]; }; RemoveAll: PUBLIC PROC [x: Cache] = { list: LIST OF FunctionCache.CacheEntry _ FunctionCache.Obtain[x: x, compare: FunctionCache.Any, limit: LAST[INT], clientID: $GGCircle]; UNTIL list=NIL DO list _ FunctionCache.Obtain[x: x, compare: FunctionCache.Any, limit: LAST[INT], clientID: $GGCircle]; ENDLOOP; }; DrawCachedCircle: PUBLIC PROC [context: Context, point: Point, circle: CachedCircle] = { DoDrawCachedCircle: PROC = { context.SetColor[Imager.black]; Imager.MaskBitmap[ context: context, bitmap: circle.bitmap, referencePoint: [circle.ch, 0], position: [Real.Round[point.x]-(circle.cw/2), Real.Round[point.y]-(circle.ch/2)] ]; }; Imager.DoSave[context, DoDrawCachedCircle]; }; Init: PROC [] ~ { [] _ CodeTimer.CreateTable[$Gargoyle]; versionRope _ "9106.27"; -- black text should not have NIL fill color version _ 9106.27; }; versionRope: PUBLIC Rope.ROPE; version: PUBLIC REAL; Init[]; END. bGGUtilityImplA.mesa Contents: Created from files GGUtilityImpl.mesa, GGCubic2Impl.mesa, GGContainerImpl.mesa, GGCircleCacheImpl.mesa, GGBuiltInShapesImpl.mesa, GGDescribeImpl.mesa October 12, 1987 Copyright Σ 1987, 1988, 1989 by Xerox Corporation. All rights reserved. Last edited by Bier on October 28, 1987 7:51:27 pm PST. Pier, August 15, 1991 3:57 pm PDT Bier, June 27, 1991 12:04 pm PDT Doug Wyatt, December 19, 1989 10:59:49 am PST Templates for List Operations Two Finger List Construction StartTypeList: PUBLIC PROC [] RETURNS [entityList, ptr: LIST OF Type] = { ptr _ entityList _ NIL; }; AddType: PUBLIC PROC [entity: Type, entityList, ptr: LIST OF Type] RETURNS [newList, newPtr: LIST OF Type] = { 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; }; }; AppendTypeList: PUBLIC PROC [list1, list2: LIST OF Type] RETURNS [result: LIST OF Type] = { pos: LIST OF Type; newCell: LIST OF Type; Non-destructive (copies the first list). IF list1 = NIL THEN RETURN[list2]; result _ CONS[list1.first, NIL]; pos _ result; FOR l: LIST OF Type _ list1.rest, l.rest UNTIL l = NIL DO newCell _ CONS[l.first, NIL]; pos.rest _ newCell; pos _ newCell; ENDLOOP; pos.rest _ list2; }; Destructive Delete DeleteTypeFromList: PUBLIC PROC [entity: Type, entityList: LIST OF Type] RETURNS [smallerList: LIST OF Type] = { beforeEnt, ent, afterEnt: LIST OF Type; found: BOOL _ FALSE; [beforeEnt, ent, afterEnt, found] _ FindTypeAndNeighbors[entity, entityList]; IF NOT found THEN RETURN[entityList]; IF beforeEnt = NIL THEN smallerList _ afterEnt ELSE { beforeEnt.rest _ afterEnt; smallerList _ entityList; }; }; FindTypeAndNeighbors: PROC [entity: Type, entityList: LIST OF Type] RETURNS [beforeEnt, ent, afterEnt: LIST OF Type, found: BOOL _ FALSE] = { lastE: LIST OF Type _ NIL; eList: LIST OF Type _ entityList; IF eList = NIL THEN RETURN; UNTIL eList = NIL DO IF eList.first = entity THEN { beforeEnt _ lastE; ent _ eList; afterEnt _ eList.rest; found _ TRUE; RETURN; }; lastE _ eList; eList _ eList.rest; ENDLOOP; }; Operations on LIST OF FeatureData Operations on LIST OF Sequence Non-destructive (copies the first list). IF eList = NIL THEN ERROR EntityNotFound; Operations on LIST OF SliceDescriptor Non-destructive (copies the first list). Operations on Bit Vectors Dash Patterns Colors GetSpecialColor and TrackPatch moved to GGPortImpl GGBuiltInShapes The bottom-most edge of the returned polygon will be horizontal. The polygon will be inscribed inside the circle with radius "radius" centered at "origin". Returns a trajectory with "segmentCount" straight line segments, all of the same length. The entire trajectory is a single straight line, from point p0 to p1. All of its segments are collinear. Knotched lines are useful as rulers. Text Descriptions of Simple Data Types Describes one of the possible two segments this joint is on GGCircleCache Returns NIL if lookup fails versionRope _ "8610.29"; versionRope _ "8612.04"; versionRope _ "8701.13"; versionRope _ "8701.135"; versionRope _ "8701.23"; versionRope _ "8701.26"; versionRope _ "8701.28"; versionRope _ "8701.30"; versionRope _ "8702.11"; versionRope _ "8702.26"; versionRope _ "8704.03"; versionRope _ "8705.14"; versionRope _ "8706.08"; versionRope _ "8706.16"; versionRope _ "8706.25"; versionRope _ "8708.21"; versionRope _ "8710.19"; versionRope _ "8802.04"; versionRope _ "8803.08"; versionRope _ "8803.24"; versionRope _ "8810.24"; versionRope _ "8811.30"; versionRope _ "8905.19"; versionRope _ "8906.16"; Κ"»•NewlineDelimiter – "cedar" style˜Icode™šΟbœ©™±K™HKšœ7™7Kšœ!™!K™ K™-—K˜šΟk ˜ Jšœιžœ.˜™—K˜šΟnœžœž˜Jšžœ«žœ-˜αKšžœ:ž˜F—˜Kšœžœ#˜7Jšœžœ˜ Kšœ žœ˜)Jšœžœ˜"Jšœžœžœ˜)Jšœžœ!˜6Jšœžœ˜Jšœ žœ˜Kšœ žœ˜-Kšœ žœ˜-Kšœžœ˜Jšœžœ˜!Kšœ žœ˜'Jšœžœ˜"Kšžœžœžœ˜Kšœ žœ˜'Kšœžœ!˜7Kšœ žœ˜'Kšœžœžœ˜-Kšœžœ!˜8Kšœžœ˜!Kšœžœ ˜5Kšœžœ˜3Kšœ žœ˜+Kšœžœ˜Kšœ žœ˜'Kšœžœ˜#—˜Kš Ÿœžœžœ žœžœ˜/KšŸœžœžœžœ˜%KšŸœžœžœžœ˜(K˜—Kšœ™Kš™š œ Ÿœžœžœžœžœžœ ™MKšœžœ™K™—šœ žœžœ#žœžœ žœžœžœ ™všžœžœžœ™Kš žœžœžœžœžœ™#Kšœžœ žœ™%Kšžœ™K™—šžœ™Kšœ™Kšœ žœ žœ™Kšœ™K™—K™—šŸœŸœžœžœžœžœ žœ žœžœ ™aKšœžœžœ™Kšœ žœžœ™K™(Kšžœ žœžœžœ™"Kšœ žœžœ™ Kšœ ™ š žœžœžœžœžœž™;Kšœ žœ žœ™Kšœ™Kšœ™—Kšžœ™Kšœ™KšœŸ™K™—Kš™šœ Ÿœžœžœžœžœ žœžœžœ ™xKšœžœžœ™)Kšœžœžœ™KšœO™OKšžœžœžœžœ ™%Kšžœ žœžœ™.šžœ™Kšœ™Kšœ™K™—Kšœ™K™—šœ Ÿ œžœžœžœ žœžœžœžœžœ™•Kšœžœžœ žœ™Kšœžœžœ™#Kšžœ žœžœžœ™šžœ žœž™šžœžœ™Kšœ™Kšœ ™ Kšœ™Kšœžœ™ Kšžœ™Kšœ™—Kšœ™Kšœ™—Kšžœ™Kšœ™—K™šœžœžœ ™!K™—š Ÿœžœžœžœžœžœ˜WKšœžœ˜K˜K˜—šŸœžœžœ(žœžœžœžœžœ˜Ššžœžœžœ˜Kš žœžœžœžœžœ˜#Kšœžœ žœ˜%Kšžœ˜K˜—šžœ˜Kšœ˜Kšœ žœ žœ˜Kšœ˜K˜—K˜—K˜šŸœžœžœžœžœžœ žœžœ˜eKšœžœžœžœ˜Kš žœžœžœžœžœ˜Kšœ žœ žœ˜Kšœ ˜ šžœžœž˜Kšœ žœ žœ˜K˜ Kšžœ˜—K˜K˜—šŸœžœžœ žœžœžœ žœžœ˜fKšœžœžœ˜Kšžœžœžœžœ˜Kšžœ žœžœ žœ˜*K˜ Kšžœ˜ K˜—K˜šœžœžœ ™K˜—š Ÿœžœžœžœžœžœ˜QKšœžœ˜K˜K˜—šŸ œžœžœ%žœžœ žœžœžœ˜~šžœžœžœ˜Kš žœžœžœžœžœ˜#Kšœžœ žœ˜%Kšžœ˜K˜—šžœ˜Kšœ˜Kšœ žœ žœ˜Kšœ˜K˜—K˜K˜—šŸœžœžœžœžœ žœ žœžœ˜gKšœžœžœ ˜Kšœ žœžœ ˜K™(Kšžœ žœžœžœ˜"Kšœ žœžœ˜ Kšœ ˜ š žœžœžœžœžœž˜=Kšœ žœ žœ˜Kšœ˜Kšœ˜—Kšžœ˜Kšœ˜KšœΟc˜K˜—šŸœžœžœžœžœ žœžœžœ˜zKšœžœžœ ˜+Kšœžœžœ˜KšœK˜KKšžœžœžœžœ ˜"Kšžœ žœžœ˜.šžœ˜Kšœ˜Kšœ˜K˜—Kšœ  ˜#K˜—šŸœžœ žœžœ žœžœžœžœžœ˜Kšœžœžœ žœ˜Kšœžœžœ˜%Kšžœ žœžœžœ™)Kšžœ žœžœžœ˜šžœ žœž˜šžœžœ˜Kšœ˜Kšœ ˜ Kšœ˜Kšœžœ˜ Kšžœ˜Kšœ˜—Kšœ˜Kšœ˜—Kšžœ˜Kšœ˜—K™šœžœžœ™%K˜—š Ÿœžœžœžœžœžœ˜_Kšœžœ˜K˜K˜—šŸœžœžœ,žœžœžœžœžœ˜ššžœžœžœ˜Kš žœžœžœžœžœ˜#Kšœžœ žœ˜%Kšžœ˜K˜—šžœ˜Kšœ˜Kšœ žœ žœ˜Kšœ˜K˜—K˜—šŸœžœžœžœžœžœ žœžœ˜|Kšœžœžœ˜Kšœ žœžœ˜!K™(Kšžœ žœžœžœ˜"Kšœ žœžœ˜ Kšœ ˜ š žœžœžœ&žœžœž˜DKšœ žœ žœ˜Kšœ˜Kšœ˜—Kšžœ˜Kšœ˜KšœŸ˜—šŸœžœžœ'žœžœžœžœžœ˜œKšœžœžœ˜2Kšœžœžœ˜KšœX˜XKšžœžœžœžœ ˜%Kšžœ žœžœ˜.šžœ˜Kšœ˜Kšœ˜K˜—Kšœ˜K˜—šŸœžœ'žœžœžœžœžœžœžœ˜ΉKšœžœžœžœ˜%Kšœžœžœ˜,Kšžœ žœžœžœ˜šžœ žœž˜šžœžœ˜Kšœ˜Kšœ ˜ Kšœ˜Kšœžœ˜ Kšžœ˜Kšœ˜—Kšœ˜Kšœ˜—Kšžœ˜Kšœ˜K˜—šŸœž œžœžœžœžœžœ˜mKšœžœžœžœ˜!Kšœžœ˜ Kšžœžœžœžœ˜Kšœžœ˜K˜šžœžœž˜Kšœ žœ˜ K˜ Kšžœ˜—Kšžœ˜ Kšœ  ˜—K˜šœ™K™—š Ÿœžœžœžœžœ˜<šžœžœžœž˜ Jš žœ žœžœžœžœ˜'—Jšžœ˜Jšžœžœ˜ K˜K˜—š Ÿœžœžœžœžœ˜;šžœžœžœž˜ Jš žœ žœžœžœžœ˜(—Jšžœ˜Jšžœžœ˜ K˜—K˜™ K˜—šŸ œžœžœžœ˜TKš žœ žœžœžœžœ˜ Kšœžœ!˜*šžœžœžœž˜%Kšœ˜Kšžœ˜—Kšœ˜K˜—šŸœž œžœž œ˜SKšžœžœžœžœ˜&šžœžœžœ ž˜Kšžœžœžœžœ˜$Kšžœ˜Kšžœžœ˜ —K˜—K˜proc™L˜—L™2L™šŸ œžœžœ%žœ˜XLšœžœ˜Lšœžœ˜ Lšžœžœžœ žœžœžœžœ˜6šžœ žœž˜šœ&˜&Lšœ!žœ ˜1LšœS˜SLšœM˜MLšœ^˜^L˜—Lšžœ˜!—L˜L˜—š Ÿ œžœžœžœ žœ˜LKšœžœžœ˜Kšœ žœžœ˜Kšœ%˜%Kšœžœ˜K˜K˜—š Ÿ œžœžœ žœžœ˜NKšœžœžœ˜Kšœ žœ˜"Kšœ žœžœ˜Kšœ-˜-K˜K˜—š Ÿœžœžœžœ žœ˜OKšžœ#žœ˜4Kšœ&žœ˜4Kšœžœ˜Kšœ7˜7KšœžœL˜Ušž˜Kšœ˜—K˜K˜—š Ÿœžœžœžœ žœ˜PKšžœ#žœ˜4Kšœ&žœ˜4Kšœžœ˜#Kš žœžœžœ-žœžœ˜JKšœG˜GKšœp˜pšž˜Kšœ˜—K˜K˜—š Ÿœžœžœžœ žœ˜UKšžœ#žœ˜4Kšœ&žœ˜4Kšœ žœ.˜=Kšœ8˜8šž˜Kšœ#˜#—K˜K˜—š Ÿœžœžœžœ žœ˜PKšžœ#žœ˜4Kšœ&žœ˜4Kšœžœ˜Kšœ7˜7KšœJ˜Jšž˜Kšœ˜—K˜—K™L™š Ÿœžœžœ žœžœžœ˜~K™œK˜ Kšœ%žœ˜*Kšœ˜Kšœ žœ˜K˜ Kšžœžœžœžœ˜"Kšœ˜Kšœ ˜ Kšœ˜Kšœ˜KšœG˜GKšœ$˜$Kšœ˜šžœžœžœž˜Kšœ˜Kšœ˜Kšœ˜KšœG˜GKšœ/žœ˜4Kšœ%˜%Kšœ/˜/Kšžœžœ žœžœ&˜@Kšœ˜Kšžœ˜—Kšœ˜Kšœ˜KšœG˜GKšœ/žœ˜4Kšœ%˜%Kšœ'˜'KšœH˜HKšœ@žœ)žœ˜qKšœ!žœžœ˜EK˜K˜—š Ÿœžœžœžœžœ˜dKšœ žœ˜ Kšœ˜KšœQ˜QKšœDžœ ˜PKšœ˜Kšœ>žœ˜CK˜K˜—š Ÿœžœžœžœžœ˜cKšœ2˜2KšœF˜FKšœDžœ ˜PKšœ˜Kšœ>žœ˜CK˜K˜—š Ÿ œžœžœžœžœ˜YK™ιK˜K˜Kšœ ˜ K˜ Kšœ žœ˜KšœA˜AKšœ˜Kšœ$˜$šžœž˜Kšœ,˜,Kšœ/žœ˜4Kšœ/˜/Kšžœžœ žœžœ&˜@Kšœ˜Kšžœ˜—Kšœ˜Kšœ/žœ˜4Kšœ/˜/Kšžœžœ žœžœ&˜@KšœH˜HK˜—L™L™&š Ÿ œžœžœžœ žœ˜DKšœžœ ˜'šœžœž˜ KšœžœE˜OKšœ žœ;˜FKšœžœ:˜DKšžœ˜—K˜K˜—š Ÿ œžœžœžœžœ žœ˜TKšœžœ ˜'Kšœž œ˜Kšœ(˜(Kšžœžœžœ0˜EKšžœžœ-˜;š œ/žœžœžœ žœ ˜‡K™;—K˜K˜—šŸœžœžœžœ žœžœ žœ˜eKšœžœR˜dK˜K˜—š Ÿœžœžœžœžœ žœ˜Tš žœžœžœžœ6žœ˜TKšœ1˜1Kš œ(žœžœžœžœžœB˜„K˜—K˜—K˜š Ÿœžœžœžœ žœ˜HKšœ;˜;K˜K˜—š Ÿœžœžœžœ žœ˜UKšœžœ=˜OK˜K˜—šŸ œž œžœ žœ˜Nšžœžœž˜˜-Kšœ˜Kšœ ˜ Kšœ1˜1š žœžœžœžœ ž˜9šœ&˜&Kšœ*˜*—šœ%˜%Kšœ$˜$—Kšœ-˜-Kšžœ4˜;—šžœžœ ž˜šœ˜Kšœ$žœ˜:Kšœ-˜-Kšœ˜—Kšžœ,˜3—K˜—˜'Lšœ˜Lšœ˜—šœ+˜+Lšœ˜L˜—šœ+˜+Lšœ˜L˜—šžœ˜ Lšœ˜L˜——K˜K˜—šŸœžœžœ žœ˜]šžœžœžœžœ˜7Kš œžœžœžœžœ$˜`Kšœ˜Kšœ*˜*Kšœ.˜.Kšœ˜—Kšžœ˜K˜K˜—šŸœžœžœ žœ˜OKšœžœ˜)šžœžœžœžœ˜5Kšœ˜Kšœ˜Kšœ˜Kšœ ˜ Kšœ˜—Kšžœ˜K˜K˜—šŸœžœžœ žœ˜PKšœžœ˜)šžœžœžœžœ˜5Kšœ˜Kšœ˜Kšœ˜Kšœ ˜ Kšœ˜—Kšžœ˜K˜K˜—šŸœžœžœ žœ˜UKšœžœ˜)šžœžœžœžœ˜5Kšœ!˜!Kšœ˜Kšœ˜Kšœ˜Kšœ˜—Kšžœ˜K˜K˜—šŸœžœžœ žœžœžœ žœžœžœžœžœžœžœ žœ˜†Kšœžœžœ˜Kšœ žœžœ˜Kšœ>˜>Kšœžœ˜K˜K˜—šŸœžœžœ žœžœ žœžœžœ žœžœžœžœžœžœ˜ˆKšœžœžœ˜Kšœ žœ˜"Kšœ žœžœ˜KšœH˜HK˜—J˜š Ÿœžœžœ2žœ žœ˜xKš œžœžœžœžœ˜Kšœ5˜5Kšœžœ˜K˜K˜—š Ÿœžœžœ žœžœ5˜zKš œžœžœžœžœ˜Kšœ4˜4K˜—K™Kšœ ™ KšœC˜CK˜šŸœžœžœžœ ˜*J•StartOfExpansion[]šžœ ˜&Jšœ˜J˜—šŸœžœžœžœ˜0Kš žœžœžœžœžœžœž˜Bšžœ˜K–‘[x: FunctionCache.Cache, argument: FunctionCache.Domain, value: FunctionCache.Range, size: INT, clientID: FunctionCache.ClientID _ NIL]šœ˜Kš œ žœžœžœžœ ˜(Kšœ˜Kšœ žœ˜Kšœžœ ˜=Kšœ@˜@Kšœžœ9˜YK–‘[x: FunctionCache.Cache, argument: FunctionCache.Domain, value: FunctionCache.Range, size: INT, clientID: FunctionCache.ClientID _ NIL]šœŒžœ˜’Kšœ/˜/K˜K˜9K˜!Kšœ˜KšœG˜GKšœ2˜2KšœŽ˜ŽK˜—Kšœ˜K˜—š Ÿœžœžœžœžœ˜GKšœžœ™–|[x: FunctionCache.Cache, compare: FunctionCache.CompareProc, limit: INT _ 1, clientID: FunctionCache.ClientID _ NIL]šŸ œ˜)Kš œžœžœ žœžœ˜(K–-[y: REAL, x: REAL, distance: [-126..0]]šžœžœ˜"K˜—K–j[x: FunctionCache.Cache, compare: FunctionCache.CompareProc, clientID: FunctionCache.ClientID _ NIL]˜ Kšœžœ˜ KšœS˜SKš žœžœžœžœžœžœ˜+Kšœ˜K˜—šŸœžœžœžœ˜0–|[x: FunctionCache.Cache, compare: FunctionCache.CompareProc, limit: INT _ 1, clientID: FunctionCache.ClientID _ NIL]šŸ œ˜)Kš œžœžœ žœžœ˜(K–-[y: REAL, x: REAL, distance: [-126..0]]šžœžœ˜#K˜—KšœT˜TKšœ˜K˜—šŸ œžœžœ˜%Kš œžœžœZžœžœ˜‡šžœžœž˜KšœEžœžœ˜eKšžœ˜—Kšœ˜K˜—šŸœžœžœ;˜XšŸœžœ˜K–’[context: Imager.Context, base: LONG POINTER, wordsPerLine: NAT, sMin: NAT, fMin: NAT, sSize: NAT, fSize: NAT, tx: INTEGER _ 0, ty: INTEGER _ 0]˜šœ˜Kšœ˜Kšœ˜Kšœ˜šœ-˜-Kšœ"˜"—Kšœ˜—K˜—Kšœ+˜+Kšœ˜—K˜šŸœžœ˜K˜&Kšœ™Kšœ™Kšœ™Kšœ™Kšœ™Kšœ™Kšœ™Kšœ™Kšœ™Kšœ™Kšœ™Kšœ™Kšœ™Kšœ™Kšœ™Kšœ™Kšœ™Kšœ™Kšœ™Kšœ™Kšœ™Kšœ™Kšœ™Kšœ™K˜Kšœ ,˜EKšœ˜K˜—K˜Lšœ žœžœ˜Lšœ žœžœ˜L˜K˜Kšžœ˜J˜—…—T„…‘