DIRECTORY Draw2d, GGBasicTypes, GGCaret, GGCoreTypes, GGModelTypes, GGSegmentTypes, GGShapes, GGStoragePools, Imager, ImagerTransformation, Lines2d, Real, SF, Vectors2d; GGShapesImpl: CEDAR PROGRAM IMPORTS Draw2d, GGStoragePools, Lines2d, Vectors2d, Imager, Real EXPORTS GGShapes = BEGIN BoundBox: TYPE = GGCoreTypes.BoundBox; Circle: TYPE = GGBasicTypes.Circle; Line: TYPE = GGCoreTypes.Line; Point: TYPE = GGBasicTypes.Point; Ray: TYPE = GGBasicTypes.Ray; Vector: TYPE = GGBasicTypes.Vector; SelectionClass: TYPE = GGSegmentTypes.SelectionClass; jointSize: INTEGER = Real.Round[GGModelTypes.jointSize]; halfJointSize: REAL = GGModelTypes.halfJointSize; hotJointSize: INTEGER = Real.Round[GGModelTypes.hotJointSize]; halfHotJointSize: REAL = GGModelTypes.halfHotJointSize; DrawWhiteRectangle: PUBLIC PROC [dc: Imager.Context, loX, loY, hiX, hiY: REAL, strokeWidth: REAL ¬ 1.0] = { DoDrawRect: PROC = { strokeWidth2: REAL ¬ strokeWidth+strokeWidth; width: REAL ¬ hiX-loX; height: REAL ¬ hiY-loY; Imager.SetColor[dc, Imager.black]; Imager.MaskRectangle[dc, [loX-strokeWidth, loY-strokeWidth, width+strokeWidth2, height+strokeWidth2]]; Imager.SetColor[dc, Imager.white]; Imager.MaskRectangle[dc, [loX, loY, width, height]]; }; Imager.DoSave[dc, DoDrawRect]; }; DrawRectangle: PUBLIC PROC [dc: Imager.Context, loX, loY, hiX, hiY: REAL, strokeWidth: REAL ¬ 1.0] = { DoDrawRect: PROC = { RectanglePath: Imager.PathProc = { moveTo[[loX, loY]]; lineTo[[loX, hiY]]; lineTo[[ hiX, hiY]]; lineTo[[ hiX, loY]]; lineTo[[loX, loY]]; }; Imager.SetStrokeWidth[dc, strokeWidth]; Imager.SetStrokeEnd[dc, square]; Imager.SetStrokeJoint[dc, round]; Imager.MaskStroke[dc, RectanglePath, TRUE]; }; Imager.DoSave[dc, DoDrawRect]; }; DrawFilledRectangle: PUBLIC PROC [dc: Imager.Context, loX, loY, hiX, hiY: REAL] = { DoDrawFilledRectangle: PROC = { Imager.SetXY[dc, [loX, loY]]; -- set the current position Imager.Move[dc]; -- move the origin to the current position Imager.SetColor[dc, Imager.black]; Imager.MaskRectangle[dc, [0, 0, hiX-loX, hiY-loY]]; }; Imager.DoSave[dc, DoDrawFilledRectangle]; }; DrawSquare: PUBLIC PROC [dc: Imager.Context, center: Point, side: REAL, strokeWidth: REAL ¬ 1.0] = { halfSide: REAL ¬ side/2.0; DoDrawSquare: PROC = { SquarePath: Imager.PathProc = { moveTo[[- halfSide, - halfSide]]; lineTo[[- halfSide, halfSide]]; lineTo[[ halfSide, halfSide]]; lineTo[[ halfSide, - halfSide]]; lineTo[[- halfSide, - halfSide]]; }; Imager.SetXY[dc, [center.x, center.y]]; Imager.Move[dc]; Imager.SetStrokeWidth[dc, strokeWidth]; Imager.SetStrokeEnd[dc, square]; Imager.SetStrokeJoint[dc, round]; Imager.MaskStroke[dc, SquarePath, TRUE]; }; Imager.DoSave[dc, DoDrawSquare]; }; DrawPlus: PUBLIC PROC [dc: Imager.Context, center: Point] = { halfSide: REAL = 5.0; DoDrawPlus: PROC = { Horiz: Imager.PathProc = { moveTo[[-halfSide, 0.0]]; lineTo[[halfSide, 0.0]]; }; Vert: Imager.PathProc = { moveTo[[0.0, -halfSide]]; lineTo[[0.0, halfSide]]; }; Imager.SetXY[dc, [center.x, center.y]]; Imager.Move[dc]; Imager.SetStrokeWidth[dc, 2.0]; Imager.SetStrokeEnd[dc, square]; Imager.MaskStroke[dc, Horiz, FALSE]; Imager.MaskStroke[dc, Vert, FALSE]; }; Imager.DoSave[dc, DoDrawPlus]; }; DrawBoundBox: PUBLIC PROC [dc: Imager.Context, bBox: BoundBox, strokeWidth: REAL ¬ 1.0] = { DrawRectangle[dc, bBox.loX, bBox.loY, bBox.hiX, bBox.hiY, strokeWidth]; }; DrawFilledSquare: PUBLIC PROC [dc: Imager.Context, center: Point, side: REAL] = { halfSide: REAL ¬ side/2.0; DoDrawFilledSquare: PROC = { Imager.SetXY[dc, [center.x, center.y]]; -- set the current position Imager.Move[dc]; -- move the origin to the current position Imager.SetColor[dc, Imager.black]; Imager.MaskRectangle[dc, [- halfSide, - halfSide, side, side]]; }; Imager.DoSave[dc, DoDrawFilledSquare]; }; DrawEmptySquare: PROC [dc: Imager.Context, center: Point, side: REAL, strokeWidth: REAL] = { DoDrawEmptySquare: PROC = { Imager.SetXY[dc, [center.x, center.y]]; Imager.Move[dc]; -- move the origin to the current position Imager.SetColor[dc, Imager.black]; Imager.MaskRectangle[dc, [-halfSide, -halfSide, side, side]]; Imager.SetColor[dc, Imager.white]; Imager.MaskRectangle[dc, [-halfSide+strokeWidth, -halfSide+strokeWidth, side-width2, side-width2]]; }; halfSide, width2: REAL; side ¬ side; halfSide ¬ side/2.0; width2 ¬ 2.0*strokeWidth; Imager.DoSave[dc, DoDrawEmptySquare]; }; DrawSpot: PUBLIC PROC [dc: Imager.Context, point: Point] = { DoDrawSpot: PROC = { Imager.SetXY[dc, [point.x, point.y]]; Imager.Move[dc]; Imager.MaskRectangle[dc, [0.0, 0.0, 1.0, 1.0]]; }; Imager.DoSave[dc, DoDrawSpot]; }; DrawLine: PUBLIC PROC [dc: Imager.Context, line: Line, clippedBy: Imager.Rectangle, strokeWidth: REAL ¬ 1.0, zip: Draw2d.Zip ¬ NIL] = { count: NAT; ray: Ray; params: ARRAY[1..2] OF REAL; p1, p2, basePoint: Point; direction: Vector; p1 ¬ [clippedBy.x, clippedBy.y]; p2 ¬ [clippedBy.x + clippedBy.w, clippedBy.y + clippedBy.h]; basePoint ¬ Lines2d.PointOnLine[line]; direction ¬ Lines2d.DirectionOfLine[line]; ray ¬ AllocateRay[basePoint, direction]; [count, params] ¬ Lines2d.LineRayMeetsBox[ray, p1.x, p1.y, p2.x, p2.y]; IF count = 2 THEN { p1 ¬ Lines2d.EvalRay[ray, params[1]]; p2 ¬ Lines2d.EvalRay[ray, params[2]]; Imager.SetStrokeWidth[dc, strokeWidth]; Draw2d.Line[dc, p1, p2, solid, zip]; }; DoFreeRay[rayPool, ray]; }; DrawLittleLine: PUBLIC PROC [dc: Imager.Context, line: Line, point: Point] = { }; DrawFilledLoLeftSquare: PUBLIC PROC [dc: Imager.Context, loLeft: Point, side: REAL] = { DoDrawRect: PROC = { Imager.SetXY[dc, [loLeft.x, loLeft.y]]; Imager.Move[dc]; Imager.MaskRectangle[dc, [0.0, 0.0, side, side]]; }; Imager.DoSave[dc, DoDrawRect]; }; DrawCircle: PUBLIC PROC [dc: Imager.Context, circle: Circle] = { leftSide, rightSide: Point; DoDrawCircle: PROC = { CirclePath: Imager.PathProc = { moveTo[[leftSide.x, leftSide.y]]; arcTo[[rightSide.x, rightSide.y], [ leftSide.x, leftSide.y]]; }; Imager.SetStrokeWidth[dc, 1.0]; Imager.SetStrokeEnd[dc, round]; Imager.MaskStroke[dc, CirclePath, TRUE]; }; leftSide ¬ [circle.origin.x - circle.radius, circle.origin.y]; rightSide ¬ [circle.origin.x + circle.radius, circle.origin.y]; Imager.DoSave[dc, DoDrawCircle]; }; starBurstsOn: BOOL ¬ TRUE; starBurstWidth: REAL ¬ 0.0; tryDraw2d: BOOL ¬ TRUE; R: REAL ¬ 7.0; cos30: REAL = 0.8660254; sin30: REAL = 0.5; yR: REAL ¬ cos30*R; xR: REAL ¬ sin30*R; DrawStarburst: PUBLIC PROC [dc: Imager.Context, point: Point, scale: REAL ¬ 1.0, zip: Draw2d.Zip ¬ NIL] = { DoDrawGlow: PROC = { leftX, loX, hiX, rightX, loY, hiY: REAL; scaledR, scaledXR, scaledYR: REAL; Imager.SetColor[dc, Imager.black]; Imager.SetStrokeWidth[dc, starBurstWidth]; scaledR ¬ R*scale; scaledXR ¬ xR*scale; scaledYR ¬ yR*scale; leftX ¬ point.x-scaledR; loX ¬ point.x-scaledXR; hiX ¬ point.x+scaledXR; rightX ¬ point.x+scaledR; loY ¬ point.y-scaledYR; hiY ¬ point.y+scaledYR; IF tryDraw2d THEN { Draw2d.Line[dc, [leftX, point.y], [rightX, point.y], solid, zip]; Draw2d.Line[dc, [loX, loY], [hiX, hiY], solid, zip]; Draw2d.Line[dc, [hiX, loY], [loX, hiY], solid, zip]; } ELSE { Imager.MaskVector[dc, [leftX, point.y], [rightX, point.y]]; Imager.MaskVector[dc, [loX, loY], [hiX, hiY]]; Imager.MaskVector[dc, [hiX, loY], [loX, hiY]]; }; }; IF starBurstsOn THEN Imager.DoSave[dc, DoDrawGlow]; }; DrawArrow: PUBLIC PROC [dc: Imager.Context, tip: Point, base: Point, strokeWidth: REAL] = { OPEN Vectors2d; DrawArrowAux: Imager.PathProc = { moveTo[tip]; lineTo[Sub[tip, Add[Scale[axis, height], Scale[perp, halfWidth]]]]; lineTo[Sub[tip, Add[Scale[axis, height], Scale[perp, -halfWidth]]]]; lineTo[tip]; }; axis: Vector; perp: Vector; height: REAL ¬ strokeWidth+5.0; halfWidth: REAL ¬ strokeWidth+3.0; IF tip = base THEN RETURN; axis ¬ Normalize[Vectors2d.Sub[tip, base]]; perp ¬ [axis.y, -axis.x]; Imager.MaskFill[context: dc, path: DrawArrowAux, oddWrap: FALSE] }; ArrowSize: PUBLIC PROC [strokeWidth: REAL] RETURNS [height, halfWidth: REAL] = { height ¬ strokeWidth+5.0; halfWidth ¬ strokeWidth+3.0; }; DrawCaret: PUBLIC PROC [dc: Imager.Context, point: Point, normal: Vector, scale: REAL ¬ 1.0] = { halfWidth: REAL = GGCaret.caretWidth/2.0; fullHeight: REAL = GGCaret.caretHeight; caretDirection: Vector; point1, point2, midPoint: Point; DoDrawCaret: PROC = { CaretPath: Imager.PathProc = { moveTo[point1]; lineTo[point]; lineTo[point2]; }; Imager.SetStrokeWidth[dc, 0.0]; Imager.MaskStroke[dc, CaretPath, FALSE]; }; caretDirection ¬ Vectors2d.Normalize[normal]; midPoint ¬ Vectors2d.Add[point, Vectors2d.Scale[caretDirection, fullHeight*scale]]; caretDirection ¬ Vectors2d.Scale[caretDirection, halfWidth*scale]; point1.x ¬ midPoint.x + caretDirection.y; point1.y ¬ midPoint.y - caretDirection.x; point2.x ¬ midPoint.x - caretDirection.y; point2.y ¬ midPoint.y + caretDirection.x; Imager.DoSave[dc, DoDrawCaret]; }; DrawAnchor: PUBLIC PROC [dc: Imager.Context, point: Point, normal: Vector, scale: REAL ¬ 1.0] = { DoDrawAnchor: PROC = { ArmPath: Imager.PathProc = { moveTo[[nearX, stroke]]; lineTo[[farX, stroke]]; lineTo[[midX, bottom]]; lineTo[[midX, -stroke]]; lineTo[[nearX, -stroke]]; }; side: REAL ¬ 3.5*scale; insideWing: REAL ¬ 7.0*scale; width: REAL ¬ 6.0*scale; height: REAL ¬ 8.0*scale; bottom: REAL ¬ -8.5*scale; stroke: REAL ¬ 0.5*scale; nearX, midX, farX: REAL; degrees: REAL; epsilon: REAL = 0.1; Imager.SetXY[dc, [point.x, point.y]]; -- set the current position degrees ¬ Vectors2d.AngleFromVector[normal] + 90.0; Imager.Move[dc]; IF ABS[degrees] > epsilon THEN Imager.RotateT[dc, degrees]; Imager.SetColor[dc, Imager.black]; Imager.SetStrokeEnd[dc, square]; Imager.SetStrokeWidth[dc, scale]; Imager.MaskVector[dc, [-side, -side], [-side, side]]; Imager.MaskVector[dc, [-side, side], [side, side]]; Imager.MaskVector[dc, [side, side], [side, -side]]; Imager.MaskVector[dc, [side, -side], [-side, -side]]; nearX ¬ side; midX ¬ insideWing; farX ¬ insideWing+width; Imager.MaskFill[dc, ArmPath]; nearX ¬ -side; midX ¬ -insideWing; farX ¬ -insideWing-width; Imager.MaskFill[dc, ArmPath]; }; Imager.DoSave[dc, DoDrawAnchor]; }; DrawCP: PUBLIC PROC [dc: Imager.Context, point: Point, scale: REAL ¬ 1.0] = { <> DrawEmptySquare[dc, point, jointSize*scale, scale]; }; DrawJoint: PUBLIC PROC [dc: Imager.Context, point: Point, scale: REAL ¬ 1.0] = { <> { DrawEmptySquare[dc, point, jointSize*scale, scale]; DrawFilledSquare[dc, point, 2.0*scale]; }; }; DrawSelectedJoint: PUBLIC PROC [dc: Imager.Context, point: Point, selectClass: SelectionClass, scale: REAL ¬ 1.0] = { <> IF selectClass=hot THEN DrawEmptySquare[dc, point, hotJointSize*scale, scale] ELSE IF selectClass=normal THEN DrawFilledSquare[dc, point, jointSize*scale] ELSE ERROR; }; DrawQuickSelectedJoint: PUBLIC PROC [dc: Imager.Context, point: Point, selectClass: SelectionClass, scale: REAL] = { IF selectClass=normal THEN { scaleJOver2: REAL ¬ scale*halfJointSize; DrawFilledRectangle[dc, point.x-3.0*scaleJOver2, point.y-scaleJOver2, point.x+scaleJOver2, point.y+scaleJOver2]; } ELSE IF selectClass=hot THEN { scaleHJOver2: REAL ¬ scale*halfHotJointSize; Imager.SetColor[dc, Imager.black]; DrawWhiteRectangle[dc, point.x-scale*(halfHotJointSize+jointSize), point.y-scaleHJOver2, point.x+scaleHJOver2, point.y+scaleHJOver2, scale]; } ELSE ERROR; }; rayPool: GGStoragePools.StoragePool; rayPoolClass: GGStoragePools.StoragePoolClass; RayPool: TYPE = REF RayPoolObj; RayPoolObj: TYPE = RECORD [ index: NAT ¬ 0, rays: SEQUENCE len: NAT OF Ray ]; maxRays: NAT = 6; AllocateRay: PROC [base: Point, direction: Vector] RETURNS [ray: Ray] = { ray ¬ NARROW[DoAllocateRay[rayPool]]; ray.p ¬ base; ray.d ¬ direction; }; MakeRayStorage: PROC [pool: GGStoragePools.StoragePool] = { realPool: RayPool ¬ NEW[RayPoolObj[maxRays]]; FOR i: NAT IN [0..5] DO realPool[i] ¬ Lines2d.CreateRay[[0,0], [0,0]]; ENDLOOP; realPool.index ¬ maxRays; pool.data ¬ realPool; }; DoAllocateRay: PROC [pool: GGStoragePools.StoragePool] RETURNS [item: REF ANY] = { realPool: RayPool ¬ NARROW[pool.data]; IF realPool.index = 0 THEN item ¬ Lines2d.CreateRay[[0,0], [0,0]] -- pool is empty, allocate one ELSE { realPool.index ¬ realPool.index - 1; item ¬ realPool[realPool.index]; }; }; DoFreeRay: PROC [pool: GGStoragePools.StoragePool, item: REF ANY] = { realPool: RayPool ¬ NARROW[pool.data]; realItem: Ray ¬ NARROW[item]; IF realPool.index = maxRays THEN RETURN; -- pool is full. Toss ray on the floor. realPool[realPool.index] ¬ realItem; realPool.index ¬ realPool.index + 1; }; Init: PROC = { rayPoolClass ¬ GGStoragePools.CreateClass[$RayPool, DoAllocateRay, DoFreeRay]; rayPool ¬ GGStoragePools.CreatePool[rayPoolClass, MakeRayStorage]; }; Init[]; END. Ϊ GGShapesImpl.mesa Contents: Predefined shapes for use in Gargoyle (e.g. squares for control points). Copyright Σ 1988, 1992 by Xerox Corporation. All rights reserved. Pier, January 18, 1988 3:48:16 pm PST Eisenman, July 24, 1987 5:21:27 pm PDT Bier, October 24, 1988 3:46:50 pm PDT Generic Draws the indicated rectangle (not filled). Draws the indicated rectangle (not filled). Imager.Trans[dc]; Imager.Trans[dc]; Draws an outer black square of length "side", and an inner white square of length "side-2*strokeWidth" Draw a short line (1 inch) centered on point, parallel to line. Draw a six pointed starburst of outer radius R and inner radius r. r: REAL _ 3.0; xr: REAL _ cos30*r; yr: REAL _ sin30*r; Draw2d.Line[dc, [0.0, r], [0.0, R], solid, zip]; Draw2d.Line[dc, [0.0, -r], [0.0, -R], solid, zip]; Draw2d.Line[dc, [xr, yr], [xR, yR], solid, zip]; Draw2d.Line[dc, [-xr, -yr], [-xR, -yR], solid, zip]; Draw2d.Line[dc, [-xr, yr], [-xR, yR], solid, zip]; Draw2d.Line[dc, [xr, -yr], [xR, -yR], solid, zip]; Imager.MaskVector[dc, [0.0, r], [0.0, R]]; Imager.MaskVector[dc, [0.0, -r], [0.0, -R]]; Imager.MaskVector[dc, [xr, yr], [xR, yR]]; Imager.MaskVector[dc, [-xr, -yr], [-xR, -yR]]; Imager.MaskVector[dc, [-xr, yr], [-xR, yR]]; Imager.MaskVector[dc, [xr, -yr], [xR, -yR]]; The arrowhead will fit in a box of size height by (halfWidth*2). Gargoyle-specified Scale the caret by "scale" about "point" before drawing it. Draw the square in the middle. Draw the two wings. The Pool of Rays Κ—•NewlineDelimiter –(cedarcode) style™codešœ™KšΟnœJ™RKšœ Οeœ7™BKšœ%™%Kšœ&™&K™%—K˜šΟk ˜ Kšœ‘Ÿœ ˜ŸK˜—š œŸœŸ˜KšŸœ9˜@KšŸœ Ÿ˜—K˜Kšœ Ÿœ˜&KšœŸœ˜#KšœŸœ˜KšœŸœ˜!KšœŸœ˜KšœŸœ˜#KšœŸœ!˜5K˜Kšœ Ÿœ&˜8KšœŸœ˜1KšœŸœ)˜>KšœŸœ!˜7K˜K™š œŸœŸœ*ŸœŸœ ˜kKšœ+™+š œŸœ˜KšœŸœ˜-KšœŸœ ˜KšœŸœ ˜Kšœ"˜"šœ˜KšœM˜M—Kšœ"˜"Kšœ4˜4Kšœ˜—Kšœ˜Kšœ˜K˜—š  œŸœŸœ*ŸœŸœ ˜fKšœ+™+š œŸœ˜š œ˜"Kšœ˜Kšœ˜Kšœ˜Kšœ˜Kšœ˜Kšœ˜—Kšœ'˜'Kšœ ˜ Kšœ!˜!Kšœ%Ÿœ˜+Kšœ˜—Kšœ˜Kšœ˜K˜—šœŸ œ*Ÿœ˜SšœŸœ˜Kšœ Οc˜;Kšœ *˜=Kšœ"˜"Kšœ3˜3Kšœ˜—Kšœ)˜)Kšœ˜K˜—š  œŸœŸœ+ŸœŸœ ˜dKšœ Ÿœ ˜š œŸœ˜š œ˜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˜—š œŸœŸœ3Ÿœ ˜[KšœG˜GK˜K˜—K˜šœŸ œ+Ÿœ˜QKšœ Ÿœ ˜šœŸœ˜Kšœ* ˜EKšœ *˜=Kšœ"˜"Kšœ?˜?K˜—Kšœ&˜&K˜K˜—šœŸœ+ŸœŸœ˜\Kšœ-™-Kšœ8™8šœŸœ˜Kšœ'˜'Kšœ *˜=Kšœ"˜"Kšœ=˜=K˜"Kšœc˜cK˜—KšœŸ˜K˜ K˜K˜Kšœ%˜%K˜K˜—šœŸœŸœ'˜<š œŸœ˜Kšœ%˜%Kšœ˜Kšœ/˜/K˜—Kšœ˜K˜K˜—š œŸœŸœLŸœŸœ˜‡KšœŸœ˜ K˜ KšœŸœŸœŸœ˜Kšœ˜K˜K˜ K˜˜>K˜—Kšœ˜Kšœ˜Kšœ"Ÿœ˜(K˜—K˜>K˜?Kšœ ˜ K˜K˜—IprocšœŸœŸœ˜LšœŸœ˜Lšœ ŸœŸœ˜LšœŸœ˜LšœŸœ ˜LšœŸœ˜LšœŸœ ˜LšœŸœ ˜L˜L˜š  œŸœŸœ+ŸœŸœ˜kL™Bš œŸœ˜LšœŸœ™LšœŸœ ™LšœŸœ ™Lšœ#Ÿœ˜(LšœŸœ˜"Lšœ"˜"Lšœ*˜*L˜L˜L˜L˜L˜L˜L˜L˜L˜šŸœ Ÿœ˜LšœA˜ALšœ4˜4Lšœ4˜4Lšœ0™0Lšœ2™2Lšœ0™0Lšœ4™4Lšœ2™2Lšœ2™2L˜—šŸœ˜Lšœ;˜;Lšœ.˜.Lšœ.˜.Lšœ*™*Lšœ,™,Lšœ*™*Lšœ.™.Lšœ,™,Lšœ,™,L˜—L˜—LšŸœŸœ˜3L˜L˜—š œŸœŸœ<Ÿœ˜[KšŸœ ˜š œ˜!Kšœ ˜ KšœC˜CKšœD˜DKšœ ˜ K˜—Kšœ ˜ Kšœ ˜ KšœŸœ˜Kšœ Ÿœ˜"KšŸœ ŸœŸœ˜K˜+K˜K•StartOfExpansionP[context: Imager.Context, path: ImagerPath.PathProc, parity: BOOL _ FALSE]šœ:Ÿœ˜@K˜K˜—š  œŸœŸœŸœŸœŸœ˜PKšœ@™@K˜K˜K˜—K™K™š œŸœŸœ;Ÿœ ˜`Kšœ;™;Kšœ Ÿœ˜)Kšœ Ÿœ˜'Kšœ˜Kšœ ˜ š œŸœ˜š œ˜Kšœ˜Kšœ˜Kšœ˜Kšœ˜—Kšœ˜Kšœ!Ÿœ˜(Kšœ˜—K˜K˜-K˜SK˜BK˜)K˜)K˜)K˜)Kšœ˜Kšœ˜—š œŸœŸœ;Ÿœ ˜aš œŸœ˜šœ˜Kšœ˜Kšœ˜Kšœ˜Kšœ˜Kšœ˜K˜—KšœŸœ ˜Kšœ Ÿœ ˜KšœŸœ ˜KšœŸœ ˜KšœŸœ˜KšœŸœ ˜KšœŸœ˜Kšœ Ÿœ˜Kšœ Ÿœ˜Kšœ( ˜CK˜3Kšœ˜KšŸœŸœŸœ˜;Kšœ"˜"Kšœ ˜ Kšœ!˜!KšΟb™Kšœ5˜5Kšœ3˜3Kšœ3˜3Kšœ5˜5Kš‘™˜9Kšœ˜—˜