<> <> <> <> <> <> <> 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; <> <> <> <> <<};>> <> <> <> <> <> <<}>> <> <> <> <> <<};>> <<};>> <> <> <> <> <> <> <> <> <> <> <> <> <> <<}; >> <<>> <> <> <> <> <<[beforeEnt, ent, afterEnt, found] _ FindTypeAndNeighbors[entity, entityList];>> <> <> <> <> <> <<};>> <<};>> <<>> <> <> <> <> <> <> <> <> <> <> <> <<};>> <> <> <> <<};>> <<>> <> <<>> 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.