DIRECTORY Basics USING [BITAND, BITOR, BITSHIFT, bitsPerWord, BITXOR, LongDiv, LongMult], ImagerManhattan USING [CreateFromBox, CreateFromRuns], ImagerPath USING [PathProc, Transform], ImagerPixelMap USING [BoundedWindow, Intersect, DeviceRectangle, PixelMap], ImagerScanConverter USING [Function], ImagerScanConverterPrivate USING [BucketTable, BucketTableRec, DevicePathRep, Direction, PieceRep, Point, PointTable, PointTableRec, SegmentRep], ImagerTransformation USING [Transformation], PrincOps USING [BBptr, BBTableSpace], PrincOpsUtils USING [AlignedBBTable, BITBLT], Real USING [FixC, FScale, RoundC, RoundI], RealFns USING [ArcTan, Cos, Sin, SqRt], Vector2 USING [VEC]; ImagerScanConverterImpl: CEDAR PROGRAM IMPORTS Basics, ImagerManhattan, ImagerPath, ImagerPixelMap, PrincOpsUtils, Real, RealFns EXPORTS ImagerScanConverter ~ BEGIN Bezier: TYPE ~ RECORD [s0, f0, s1, f1, s2, f2, s3, f3: REAL]; Pair: TYPE ~ RECORD [s, f: REAL]; PixelMap: TYPE ~ ImagerPixelMap.PixelMap; DevicePath: TYPE ~ REF DevicePathRep; DevicePathRep: PUBLIC TYPE ~ ImagerScanConverterPrivate.DevicePathRep; BucketTable: TYPE ~ ImagerScanConverterPrivate.BucketTable; BucketTableRec: TYPE ~ ImagerScanConverterPrivate.BucketTableRec; Direction: TYPE ~ ImagerScanConverterPrivate.Direction; PieceRep: TYPE ~ ImagerScanConverterPrivate.PieceRep; Point: TYPE ~ ImagerScanConverterPrivate.Point; PointTable: TYPE ~ ImagerScanConverterPrivate.PointTable; PointTableRec: TYPE ~ ImagerScanConverterPrivate.PointTableRec; SegmentRep: TYPE ~ ImagerScanConverterPrivate.SegmentRep; Function: TYPE ~ ImagerScanConverter.Function; VEC: TYPE ~ Vector2.VEC; DeviceRectangle: TYPE ~ ImagerPixelMap.DeviceRectangle; lgFScale: NAT ~ 6; fScale: NAT ~ 64; -- must be a power of two. flatness: REAL _ 4; -- 1/max allowed error in pixels. retainScratch: INT _ 30; BITAND: PROC [a, b: CARDINAL] RETURNS[CARDINAL] ~ INLINE {RETURN[Basics.BITAND[a, b]]}; BITANDI: PROC [a, b: INTEGER] RETURNS[INTEGER] ~ INLINE {RETURN[LOOPHOLE[Basics.BITAND[LOOPHOLE[a], LOOPHOLE[b]]]]}; BITOR: PROC [a, b: CARDINAL] RETURNS[CARDINAL] ~ INLINE {RETURN[Basics.BITOR[a, b]]}; BITXOR: PROC [a, b: CARDINAL] RETURNS[CARDINAL] ~ INLINE {RETURN[Basics.BITXOR[a, b]]}; Shift: PROC [a: CARDINAL, b: INTEGER] RETURNS [CARDINAL] ~ INLINE {RETURN[Basics.BITSHIFT[a, b]]}; ShortScaledFloor: PROC [a: CARDINAL] RETURNS [INTEGER] ~ INLINE {RETURN[Basics.BITSHIFT[a, -lgFScale]]}; Mid: PROC [a, b: CARDINAL] RETURNS[CARDINAL] ~ INLINE {RETURN[Basics.BITSHIFT[(a+b),-1]]}; FloorI: PROC [r: REAL] RETURNS [t: INTEGER] ~ INLINE {t _ Real.RoundI[r]; IF t > r THEN t _ t-1}; CeilingI: PROC [r: REAL] RETURNS [t: INTEGER] ~ INLINE {t _ Real.RoundI[r]; IF t < r THEN t _ t+1}; deltaWrap: ARRAY Direction OF INTEGER ~ [1, -1]; FValueFor: PROC [piece: LIST OF PieceRep, sMinusHalf: INTEGER] RETURNS [ans: INTEGER] ~ { ShortPair: TYPE ~ RECORD [a, b: CARDINAL]; p: PieceRep _ piece.first; sRel: CARDINAL _ NAT[(sMinusHalf - p.sOrg) * p.sScale + Shift[p.sScale, -1] - p.sOffset]; IF sRel > p.s3 THEN RETURN [ShortScaledFloor[p.f3]+p.fOrg]; THROUGH [0..p.iterationsUntilFlat) DO sAB, fAB, sBC, fBC: CARDINAL; IF p.s3 > LAST[CARDINAL]/8 THEN { p.s3 _ Shift[p.s3, -1]; p.s2 _ Shift[p.s2, -1]; p.s1 _ Shift[p.s1, -1]; sRel _ Shift[sRel, -1]; }; fAB _ p.f0 + 2*p.f1 + p.f2; sAB _ 2*p.s1 + p.s2; fBC _ p.f1 + 2*p.f2 + p.f3; sBC _ p.s1 + 2*p.s2 + p.s3; IF Shift[sRel, 3] < sAB+sBC THEN { [p.s3, p.f3] _ ShortPair[Shift[sAB+sBC+3, -2], Shift[fAB+fBC+7, -3]]; [p.s2, p.f2] _ ShortPair[Shift[sAB, -1], Shift[fAB+3, -2]]; p.f1 _ Shift[p.f0+p.f1, -1]; sRel _ 2*sRel; } ELSE { sShift: CARDINAL _ Shift[sAB+sBC+3, -2]; p.f0 _ Shift[fAB+fBC+7, -3]; [p.s1, p.f1] _ ShortPair[Shift[sBC, -1] - sShift, Shift[fBC+3, -2]]; [p.s2, p.f2] _ ShortPair[p.s2+p.s3 - sShift, Shift[p.f2+p.f3, -1]]; p.s3 _ 2*p.s3 - sShift; sRel _ 2*sRel - sShift; }; ENDLOOP; IF sRel > p.s3 THEN ERROR; IF p.s3=0 OR BITAND[BITXOR[p.f0, p.f3], LAST[CARDINAL]-(fScale-1)] = 0 THEN ans _ ShortScaledFloor[p.f0] + p.fOrg ELSE IF p.f3>p.f0 THEN ans _ p.fOrg + ShortScaledFloor[p.f0 + Basics.LongDiv[Basics.LongMult[sRel, p.f3-p.f0], p.s3]] ELSE ans _ p.fOrg + ShortScaledFloor[p.f3 + Basics.LongDiv[Basics.LongMult[p.s3-sRel, p.f0-p.f3], p.s3]]; }; SlowIterationsUntilFlat: PROC [b: Bezier] RETURNS [iterationsUntilFlat: NAT] ~ INLINE { deltaX: REAL ~ b.s3 - b.s0; deltaY: REAL ~ b.f3 - b.f0; theta: REAL ~ RealFns.ArcTan[deltaY, deltaX]; cos: REAL ~ RealFns.Cos[theta]; sin: REAL ~ RealFns.Sin[theta]; y1: REAL ~ (b.f1-b.f0)*cos - (b.s1-b.s0)*sin; y2: REAL ~ (b.f2-b.f0)*cos - (b.s2-b.s0)*sin; r: REAL ~ IF ABS[y2] > 0 THEN y1/y2 ELSE 10.0; e: REAL _ MAX[ABS[y1], ABS[y2]]*flatness; iterationsUntilFlat _ 0; WHILE e>1 DO iterationsUntilFlat _ iterationsUntilFlat+1; e _ Real.FScale[e, -1]; ENDLOOP; IF r IN [0.5..2.0] THEN iterationsUntilFlat _ (iterationsUntilFlat * 695 + 1023)/1024; }; IterationsUntilFlat: PROC [b: Bezier] RETURNS [iterationsUntilFlat: NAT] ~ { deltaX: REAL ~ b.s3 - b.s0; deltaY: REAL ~ b.f3 - b.f0; dSqr: REAL ~ deltaX*deltaX + deltaY*deltaY; y1d: REAL ~ deltaX*(b.f1-b.f0) - deltaY*(b.s1-b.s0); y2d: REAL ~ deltaX*(b.f2-b.f0) - deltaY*(b.s2-b.s0); ed: REAL ~ MAX[ABS[y1d], ABS[y2d]]*flatness; eded: REAL _ ed*ed; iterationsUntilFlat _ 0; WHILE eded>dSqr DO iterationsUntilFlat _ iterationsUntilFlat+1; eded _ Real.FScale[eded, -2]; ENDLOOP; IF iterationsUntilFlat > 2 AND ((y1d>=0) = (y2d>=0)) AND ABS[y1d] IN [Real.FScale[ABS[y2d], -1]..Real.FScale[ABS[y2d], 1]] THEN { iterationsUntilFlat _ (iterationsUntilFlat * 695 + 1023)/1024; }; }; marginSize: REAL _ 8.0; Interpolate: PROC [t: REAL, a, b: Pair] RETURNS [r: Pair] ~ {RETURN [[a.s*(1-t)+b.s*t, a.f*(1-t)+b.f*t]]}; SubDivide: PROC [b: Bezier, t: REAL] RETURNS [low, high: Bezier] ~ { b0: Pair ~ [b.s0, b.f0]; b1: Pair ~ [b.s1, b.f1]; b2: Pair ~ [b.s2, b.f2]; b3: Pair ~ [b.s3, b.f3]; q1, q2, q3, qp1, qp2, q: Pair; q1 _ Interpolate[t, b0, b1]; q2 _ Interpolate[t, b1, b2]; q3 _ Interpolate[t, b2, b3]; qp1 _ Interpolate[t, q1, q2]; qp2 _ Interpolate[t, q2, q3]; q _ Interpolate[t, qp1, qp2]; low _ [b0.s, b0.f, q1.s, q1.f, qp1.s, qp1.f, q.s, q.f]; high _ [q.s, q.f, qp2.s, qp2.f, q3.s, q3.f, b3.s, b3.f]; }; GetScratchSegmentList: PROC [scratch: DevicePath] RETURNS [s: LIST OF SegmentRep] ~ { IF scratch = NIL THEN RETURN [NIL]; s _ scratch.segmentList; scratch.segmentList _ NIL; IF scratch.scratchSegmentList # NIL THEN { IF s = NIL THEN s _ scratch.scratchSegmentList ELSE { t: LIST OF SegmentRep _ s; UNTIL t.rest = NIL DO t _ t.rest; ENDLOOP; t.rest _ scratch.scratchSegmentList; }; scratch.scratchSegmentList _ NIL; }; }; GetScratchPieceList: PROC [scratch: DevicePath] RETURNS [s: LIST OF PieceRep] ~ { IF scratch = NIL THEN RETURN [NIL]; s _ scratch.pieceList; scratch.pieceList _ NIL; IF scratch.scratchPieceList # NIL THEN { IF s = NIL THEN s _ scratch.scratchPieceList ELSE { t: LIST OF PieceRep _ s; UNTIL t.rest = NIL DO t _ t.rest; ENDLOOP; t.rest _ scratch.scratchPieceList; }; scratch.scratchPieceList _ NIL; }; }; TrimScratchSegmentList: PROC [s: LIST OF SegmentRep] RETURNS [trimmed: LIST OF SegmentRep] ~ { trimmed _ s; IF s # NIL AND retainScratch > 0 THEN { last: LIST OF SegmentRep _ s; FOR i: INT IN [1..retainScratch) UNTIL last = NIL DO last _ last.rest; ENDLOOP; IF last # NIL THEN { s _ last.rest; last.rest _ NIL; } ELSE s _ NIL; }; WHILE s # NIL DO t: LIST OF SegmentRep _ s; s _ t.rest; t.rest _ NIL; ENDLOOP; }; TrimScratchPieceList: PROC [s: LIST OF PieceRep] RETURNS [trimmed: LIST OF PieceRep] ~ { trimmed _ s; IF s # NIL AND retainScratch > 0 THEN { last: LIST OF PieceRep _ s; FOR i: INT IN [1..retainScratch) UNTIL last = NIL DO last _ last.rest; ENDLOOP; IF last # NIL THEN { s _ last.rest; last.rest _ NIL; } ELSE s _ NIL; }; WHILE s # NIL DO t: LIST OF PieceRep _ s; s _ t.rest; t.rest _ NIL; ENDLOOP; }; CreatePath: PUBLIC PROC [ path: ImagerPath.PathProc, transformation: ImagerTransformation.Transformation, clipBox: DeviceRectangle, scratch: DevicePath _ NIL -- for re-use of storage ] RETURNS [DevicePath] ~ { devicePath: DevicePathRep; scratchSegmentList: LIST OF SegmentRep _ GetScratchSegmentList[scratch]; scratchPieceList: LIST OF PieceRep _ GetScratchPieceList[scratch]; AppendSegment: PROC [s0, f0, s1, f1: REAL] ~ { segment: SegmentRep; IF NOT s0 IN [sOuterMin..sOuterMax] AND f0 IN [fOuterMin..fOuterMax] AND s1 IN [sOuterMin..sOuterMax] AND f1 IN [fOuterMin..fOuterMax] THEN ERROR; IF s1 < s0 THEN { segment.direction _ decreasing; segment.s0 _ s1; segment.f0 _ f1; segment.s1 _ s0; segment.f1 _ f0; } ELSE { segment.direction _ increasing; segment.s0 _ s0; segment.f0 _ f0; segment.s1 _ s1; segment.f1 _ f1; }; segment.sFirstScan _ CeilingI[segment.s0-0.5]; segment.scanCount _ CeilingI[segment.s1-0.5] - segment.sFirstScan; IF segment.scanCount # 0 THEN { devicePath.scanLineCrossings _ devicePath.scanLineCrossings + segment.scanCount; IF segment.sFirstScan < devicePath.sMin THEN devicePath.sMin _ segment.sFirstScan; IF segment.sFirstScan + INTEGER[segment.scanCount] > devicePath.sMax THEN devicePath.sMax _ segment.sFirstScan + segment.scanCount; devicePath.fMin _ MIN[devicePath.fMin, FloorI[segment.f0], FloorI[segment.f1]]; devicePath.fMax _ MAX[devicePath.fMax, CeilingI[segment.f0], CeilingI[segment.f1]]; IF scratchSegmentList = NIL THEN devicePath.segmentList _ CONS[segment, devicePath.segmentList] ELSE { t: LIST OF SegmentRep _ scratchSegmentList; scratchSegmentList _ t.rest; t.rest _ devicePath.segmentList; t.first _ segment; devicePath.segmentList _ t; }; }; }; AppendMonotoneShortPiece: PROC [b: Bezier, fMin: REAL] ~ { iterationsUntilFlat: NAT _ IterationsUntilFlat[b]; IF iterationsUntilFlat = 0 THEN AppendSegment[b.s0, b.f0, b.s3, b.f3] ELSE { piece: PieceRep; fOrg: REAL ~ (piece.fOrg _ FloorI[fMin-0.5]); sDelta: REAL _ ABS[b.s0-b.s3]; sMin, sOrg: REAL; lgSScale: CARDINAL _ 0; piece.sScale _ 1; WHILE piece.sScale<LAST[CARDINAL]/8 AND sDelta < LAST[CARDINAL]/16 DO piece.sScale _ 2*piece.sScale; lgSScale _ lgSScale + 1; sDelta _ Real.FScale[sDelta, 1]; ENDLOOP; IF b.s3 < b.s0 THEN { t: Bezier _ [b.s3, b.f3, b.s2, b.f2, b.s1, b.f1, b.s0, b.f0]; b _ t; piece.direction _ decreasing} ELSE piece.direction _ increasing; sMin _ b.s0; sOrg _ piece.sOrg _ FloorI[sMin]; piece.f0 _ Real.RoundC[Real.FScale[b.f0-fOrg, lgFScale]]; piece.f1 _ Real.RoundC[Real.FScale[b.f1-fOrg, lgFScale]]; piece.f2 _ Real.RoundC[Real.FScale[b.f2-fOrg, lgFScale]]; piece.f3 _ Real.RoundC[Real.FScale[b.f3-fOrg, lgFScale]]; piece.sOffset _ Real.FixC[Real.FScale[sMin-sOrg, lgSScale]]; piece.s1 _ Real.RoundC[Real.FScale[b.s1-sMin, lgSScale]]; piece.s2 _ Real.RoundC[Real.FScale[b.s2-sMin, lgSScale]]; piece.s3 _ Real.RoundC[Real.FScale[b.s3-sMin, lgSScale]]; piece.iterationsUntilFlat _ iterationsUntilFlat; piece.sFirstScan _ CeilingI[sMin-0.5]; piece.scanCount _ CeilingI[b.s3-0.5] - piece.sFirstScan; IF piece.scanCount # 0 THEN { devicePath.scanLineCrossings _ devicePath.scanLineCrossings + piece.scanCount; IF piece.sFirstScan < devicePath.sMin THEN devicePath.sMin _ piece.sFirstScan; IF piece.sFirstScan + INTEGER[piece.scanCount] > devicePath.sMax THEN devicePath.sMax _ piece.sFirstScan + piece.scanCount; IF piece.fOrg < devicePath.fMin THEN devicePath.fMin _ piece.fOrg; devicePath.fMax _ MAX[devicePath.fMax, piece.fOrg + ShortScaledFloor[MAX[piece.f0, piece.f1, piece.f2, piece.f3]]+1]; IF scratchPieceList = NIL THEN devicePath.pieceList _ CONS[piece, devicePath.pieceList] ELSE { t: LIST OF PieceRep _ scratchPieceList; scratchPieceList _ t.rest; t.rest _ devicePath.pieceList; t.first _ piece; devicePath.pieceList _ t; }; }; }; }; sInnerMin: REAL _ MAX[-REAL[LAST[NAT]-2], REAL[clipBox.sMin]]; sInnerMax: REAL _ MIN[REAL[LAST[NAT]-2], REAL[clipBox.sMin] + clipBox.sSize]; fInnerMin: REAL _ MAX[-REAL[LAST[NAT]-2], REAL[clipBox.fMin]]; fInnerMax: REAL _ MIN[REAL[LAST[NAT]-2], REAL[clipBox.fMin] + clipBox.fSize]; sOuterMin: REAL _ MAX[-REAL[LAST[NAT]-1], sInnerMin - marginSize]; sOuterMax: REAL _ MIN[REAL[LAST[NAT]-1], sInnerMax + marginSize]; fOuterMin: REAL _ MAX[-REAL[LAST[NAT]-1], fInnerMin - marginSize]; fOuterMax: REAL _ MIN[REAL[LAST[NAT]-1], fInnerMax + marginSize]; ClipS: PROC [s: REAL] RETURNS [REAL] ~ {RETURN[MAX[MIN[s, sOuterMax], sOuterMin]]}; ClipF: PROC [f: REAL] RETURNS [REAL] ~ {RETURN[MAX[MIN[f, fOuterMax], fOuterMin]]}; AppendMonotoneBezier: PROC [bezier: Bezier] ~ { SubDivide: PROC ~ { Mid: PROC [a, b: REAL] RETURNS[REAL] ~ INLINE {RETURN[Real.FScale[a+b, -1]]}; a: Pair _ [Mid[bezier.s0, bezier.s1], Mid[bezier.f0, bezier.f1]]; b: Pair _ [Mid[bezier.s1, bezier.s2], Mid[bezier.f1, bezier.f2]]; c: Pair _ [Mid[bezier.s2, bezier.s3], Mid[bezier.f2, bezier.f3]]; ab: Pair _ [Mid[a.s, b.s], Mid[a.f, b.f]]; bc: Pair _ [Mid[b.s, c.s], Mid[b.f, c.f]]; abc: Pair _ [Mid[ab.s, bc.s], Mid[ab.f, bc.f]]; AppendMonotoneBezier[[bezier.s0, bezier.f0, a.s, a.f, ab.s, ab.f, abc.s, abc.f]]; AppendMonotoneBezier[[abc.s, abc.f, bc.s, bc.f, c.s, c.f, bezier.s3, bezier.f3]]; }; fMin: REAL ~ MIN[bezier.f0, bezier.f1, bezier.f2, bezier.f3]; fMax: REAL ~ MAX[bezier.f0, bezier.f1, bezier.f2, bezier.f3]; sEndMin: REAL ~ MIN[bezier.s0, bezier.s3]; sMin: REAL ~ MIN[sEndMin, bezier.s1, bezier.s2]; sMax: REAL ~ MAX[bezier.s0, bezier.s1, bezier.s2, bezier.s3]; sMinRegion: INTEGER _ SELECT sMin FROM < sOuterMin => -2, < sInnerMin => -1, <= sInnerMax => 0, <= sOuterMax => 1, ENDCASE => 2; fMinRegion: INTEGER _ SELECT fMin FROM < fOuterMin => -2, < fInnerMin => -1, <= fInnerMax => 0, <= fOuterMax => 1, ENDCASE => 2; sMaxRegion: INTEGER _ SELECT sMax FROM < sOuterMin => -2, < sInnerMin => -1, <= sInnerMax => 0, <= sOuterMax => 1, ENDCASE => 2; fMaxRegion: INTEGER _ SELECT fMax FROM < fOuterMin => -2, < fInnerMin => -1, <= fInnerMax => 0, <= fOuterMax => 1, ENDCASE => 2; IF MAX[ABS[sMinRegion], ABS[fMinRegion], ABS[sMaxRegion], ABS[fMaxRegion]] <= 1 THEN { IF sMax-sMin <= LAST[CARDINAL]/8 AND bezier.s1 >= sEndMin AND bezier.s2 >= sEndMin AND fMax-fMin <= LAST[CARDINAL]/(8*fScale) THEN AppendMonotoneShortPiece[bezier, fMin] ELSE SubDivide[]; } ELSE IF sMinRegion > 0 OR sMaxRegion < 0 OR fMinRegion > 0 OR fMaxRegion < 0 THEN AppendMonotoneBezier[[ ClipS[bezier.s0], ClipF[bezier.f0], ClipS[bezier.s1], ClipF[bezier.f1], ClipS[bezier.s2], ClipF[bezier.f2], ClipS[bezier.s3], ClipF[bezier.f3] ]] ELSE SubDivide[]; }; AppendBezier: PROC [b: Bezier] ~ { c0: REAL ~ b.s0; c1: REAL ~ 3*(b.s1 - c0); t: REAL ~ 3*(b.s2 - b.s1); c2: REAL ~ t - c1; c3: REAL ~ b.s3 - c0 - t; d0: REAL ~ c1; d1: REAL ~ 2*c2; d2: REAL ~ 3*c3; t0, t1: REAL _ -1; tt0, tt1: REAL _ -1; IF ABS[d2] > 0 THEN { b: REAL ~ d1/d2; c: REAL ~ d0/d2; d: REAL ~ b*b-4*c; IF d>=0 THEN { sqrt: REAL ~ RealFns.SqRt[d]; t0 _ (-b-(IF b>0 THEN sqrt ELSE -sqrt))/2.0; t1 _ IF ABS[t0] > 0 THEN c/t0 ELSE 0.0; }; } ELSE IF ABS[d1] > 0 THEN t0 _ -d0/d1; t0 _ MIN[1.0, MAX[0.0, t0]]; t1 _ MIN[1.0, MAX[0.0, t1]]; IF t0 > t1 THEN {t: REAL _ t0; t0 _ t1; t1 _ t}; IF 0.0 < t0 AND t0 < t1 AND t1 < 1.0 THEN { low, middle, high: Bezier; [middle, high] _ SubDivide[b, t1]; [low, middle] _ SubDivide[middle, t0/t1]; low.s2 _ low.s3; middle.s1 _ middle.s0; middle.s2 _ middle.s3; high.s1 _ high.s0; AppendMonotoneBezier[low]; AppendMonotoneBezier[middle]; AppendMonotoneBezier[high]; } ELSE IF t0 IN (0.0..1.0) OR t1 IN (0.0..1.0) THEN { low, high: Bezier; [low, high] _ SubDivide[b, IF t0 IN (0.0..1.0) THEN t0 ELSE t1]; low.s2 _ low.s3; high.s1 _ high.s0; AppendMonotoneBezier[low]; AppendMonotoneBezier[high]; } ELSE AppendMonotoneBezier[b]; }; firstPoint, lastPoint: Pair; started: BOOLEAN _ FALSE; Move: PROC[p: VEC] ~ { firstPoint _ lastPoint _ [p.x, p.y]; }; Line: PROC[p: VEC] ~ { s: REAL ~ p.x; f: REAL ~ p.y; b1, b2: Pair; IF lastPoint.s IN [sOuterMin..sOuterMax] AND lastPoint.f IN [fOuterMin..fOuterMax] AND s IN [sOuterMin..sOuterMax] AND f IN [fOuterMin..fOuterMax] THEN AppendSegment[lastPoint.s, lastPoint.f, s, f] ELSE { b1 _ Interpolate[0.333333, lastPoint, [s, f]]; b2 _ Interpolate[0.666667, lastPoint, [s, f]]; AppendBezier[[lastPoint.s, lastPoint.f, b1.s, b1.f, b2.s, b2.f, s, f]]; }; lastPoint _ [s, f]; }; Curve: PROC[p1, p2, p3: VEC] ~ { AppendBezier[[lastPoint.s, lastPoint.f, p1.x, p1.y, p2.x, p2.y, p3.x, p3.y]]; lastPoint _ [p3.x, p3.y]; }; Close: PROC ~ { IF lastPoint # firstPoint THEN Line[[firstPoint.s, firstPoint.f]]; }; devicePath.scanLineCrossings _ 0; devicePath.sMin _ LAST[INTEGER]; devicePath.sMax _ FIRST[INTEGER]; devicePath.fMin _ LAST[INTEGER]; devicePath.fMax _ FIRST[INTEGER]; ImagerPath.Transform[path: path, m: transformation, moveTo: Move, lineTo: Line, curveTo: Curve, close: Close]; IF devicePath.sMin > devicePath.sMax THEN devicePath.sMin _ devicePath.sMax _ devicePath.fMin _ devicePath.fMax _ 0; IF scratch # NIL THEN { devicePath.pointTable _ scratch.pointTable; devicePath.bucketTable _ scratch.bucketTable; devicePath.scratchSegmentList _ TrimScratchSegmentList[scratchSegmentList]; devicePath.scratchPieceList _ TrimScratchPieceList[scratchPieceList]; scratch^ _ devicePath; RETURN [scratch] }; RETURN [NEW[DevicePathRep _ devicePath]]; }; shellD: ARRAY [1..11] OF CARDINAL ~ [1, 4, 13, 40, 121, 364, 1093, 3280, 9841, 29524, 65535]; Key: PROC [point: Point] RETURNS [CARDINAL] ~ TRUSTED INLINE {RETURN[LOOPHOLE[point]]}; ShellSort: PROC [table: PointTable, start, length: NAT] ~ TRUSTED { IF length>0 THEN { passesPlusOne: [1..11] _ 1; startPtr: LONG POINTER TO Point _ @(table[start]); endPtr: LONG POINTER TO Point _ @(table[start+length-1]) + SIZE[Point]; UNTIL shellD[passesPlusOne _ passesPlusOne+1] >= length DO NULL ENDLOOP; FOR pass: NAT DECREASING IN [1..passesPlusOne) DO h: NAT _ shellD[pass]; hTimesSize: CARDINAL _ h*SIZE[Point]; FOR iPtr: LONG POINTER TO Point _ startPtr, iPtr + SIZE[Point] UNTIL iPtr = endPtr DO a: Point _ iPtr^; jPtr: LONG POINTER TO Point _ iPtr; b: LONG POINTER TO Point; WHILE LOOPHOLE[(b _ jPtr-hTimesSize), LONG CARDINAL] >= LOOPHOLE[startPtr, LONG CARDINAL] AND Key[a] < Key[b^] DO jPtr^ _ b^; jPtr _ b; ENDLOOP; jPtr^ _ a; ENDLOOP; ENDLOOP; }; }; InitialBucketTable: PROC [devicePath: DevicePath, smin: INTEGER, smax: INTEGER, scratch: BucketTable] RETURNS [bucketTable: BucketTable] ~ { bucketTableSize: NAT _ smax - smin + 2; bucketTable _ IF scratch # NIL AND scratch.maxLength >= bucketTableSize THEN scratch ELSE NEW [BucketTableRec[bucketTableSize]]; bucketTable.length _ bucketTableSize; FOR i: NAT IN [0..bucketTableSize) DO bucketTable.seq[i] _ 0; ENDLOOP; FOR s: LIST OF SegmentRep _ devicePath.segmentList, s.rest UNTIL s = NIL DO start: INTEGER ~ MAX[s.first.sFirstScan, smin] - smin; end: INTEGER ~ MIN[s.first.sFirstScan+s.first.scanCount, smax] - smin; IF end > start THEN { bucketTable.seq[start] _ bucketTable.seq[start] + 1; bucketTable.seq[end] _ bucketTable.seq[end] - 1; }; ENDLOOP; FOR p: LIST OF PieceRep _ devicePath.pieceList, p.rest UNTIL p = NIL DO start: INTEGER ~ MAX[p.first.sFirstScan, smin] - smin; end: INTEGER ~ MIN[p.first.sFirstScan+p.first.scanCount, smax] - smin; IF end > start THEN { bucketTable.seq[start] _ bucketTable.seq[start] + 1; bucketTable.seq[end] _ bucketTable.seq[end] - 1; }; ENDLOOP; {sum, sumSum: NAT _ 0; FOR i: NAT IN [0..bucketTable.length) DO sum _ sum + bucketTable.seq[i]; bucketTable.seq[i] _ sumSum; IF sumSum > maxPointTableSize THEN { bucketTable.length _ i+1; RETURN; }; sumSum _ sumSum + sum; ENDLOOP; }; }; BoundingBox: PUBLIC PROC [devicePath: DevicePath] RETURNS [DeviceRectangle] ~ { RETURN [[devicePath.sMin, devicePath.fMin, devicePath.sMax-devicePath.sMin, devicePath.fMax-devicePath.fMin]] }; NumberOfRuns: PUBLIC PROC [devicePath: DevicePath] RETURNS [numberOfRuns: INT] ~ { numberOfRuns _ devicePath.scanLineCrossings/2; }; maxBucketTableSize: NAT _ 808; maxPointTableSize: NAT _ 808*4; Convert: PROC [ devicePath: DevicePath, resultProc: PROC [devicePath: DevicePath, sStart, sEnd: INTEGER], clipBox: DeviceRectangle ] ~ { sStart: INTEGER _ MAX[clipBox.sMin, devicePath.sMin]; sFinal: INTEGER ~ MIN[INT[clipBox.sMin+clipBox.sSize], devicePath.sMax]; sEnd: INTEGER _ sFinal; fOrigin: INTEGER _ devicePath.fMin; bucketTable: BucketTable; WHILE sStart < sFinal DO IF sEnd - sStart > maxBucketTableSize THEN sEnd _ sStart + maxBucketTableSize; bucketTable _ devicePath.bucketTable _ InitialBucketTable[devicePath, sStart, sEnd, devicePath.bucketTable]; IF bucketTable.seq[bucketTable.length-1] > maxPointTableSize THEN { sEnd _ sStart; WHILE bucketTable.seq[sEnd-sStart] < maxPointTableSize DO sEnd _ sEnd+1; ENDLOOP; IF sEnd > sStart+1 THEN sEnd _ sEnd - 1; bucketTable _ devicePath.bucketTable _ InitialBucketTable[devicePath, sStart, sEnd, devicePath.bucketTable]; }; CHECKED { scanLineCrossings: NAT ~ bucketTable.seq[bucketTable.length-1]; pointTable: PointTable ~ devicePath.pointTable _ IF devicePath.pointTable # NIL AND devicePath.pointTable.maxLength >= scanLineCrossings THEN devicePath.pointTable ELSE NEW[PointTableRec[scanLineCrossings]]; points: NAT _ 0; FOR p: LIST OF SegmentRep _ devicePath.segmentList, p.rest UNTIL p = NIL DO firstScan: INTEGER ~ MAX[p.first.sFirstScan, sStart]; endScan: INTEGER ~ MIN[p.first.sFirstScan+p.first.scanCount, sEnd]; IF endScan > firstScan THEN TRUSTED { direction: Direction ~ p.first.direction; w: REAL ~ MAX[ABS[p.first.f1-p.first.f0], ABS[p.first.s1-p.first.s0]]; sDelta: INTEGER _ Real.RoundI[16536*(p.first.s1-p.first.s0)/w]; fDelta: INTEGER ~ Real.RoundI[16536*(p.first.f1-p.first.f0)/w]; fAbsDelta: INTEGER ~ ABS[fDelta]; fSignDelta: INTEGER ~ IF fAbsDelta = fDelta THEN 1 ELSE -1; sReal: REAL ~ firstScan + 0.5; fReal: REAL ~ p.first.f0 + (sReal-p.first.s0)*(p.first.f1-p.first.f0)/(p.first.s1-p.first.s0); f: INTEGER _ FloorI[fReal+0.5]; e: INTEGER _ IF fAbsDelta = fDelta THEN Real.RoundI[(f+0.5-fReal)*sDelta] ELSE Real.RoundI[(fReal-f+0.5)*sDelta]; bPtr: LONG POINTER TO INTEGER _ @(bucketTable.seq[firstScan-sStart]); IF sDelta <= 0 THEN { IF sDelta < 0 OR endScan # firstScan + 1 THEN ERROR; sDelta _ fAbsDelta; }; FOR s: INTEGER IN [firstScan..endScan) DO pointTable[bPtr^] _ [fRel: MAX[f-fOrigin, 0], direction: direction]; bPtr^ _ bPtr^ + 1; points _ points + 1; bPtr _ bPtr + SIZE[INTEGER]; e _ e - fAbsDelta; WHILE e<0 DO f _ f + fSignDelta; e _ e + sDelta; ENDLOOP; ENDLOOP; }; ENDLOOP; FOR p: LIST OF PieceRep _ devicePath.pieceList, p.rest UNTIL p = NIL DO firstScan: INTEGER ~ MAX[p.first.sFirstScan, sStart]; endScan: INTEGER ~ MIN[p.first.sFirstScan+p.first.scanCount, sEnd]; direction: Direction _ p.first.direction; FOR s: INTEGER IN [firstScan..endScan) DO f: INTEGER _ FValueFor[p, s]; TRUSTED { bPtr: LONG POINTER TO INTEGER _ @(bucketTable.seq[s-sStart]); pointTable[bPtr^] _ [fRel: f-fOrigin, direction: direction]; bPtr^ _ bPtr^ + 1; points _ points + 1; }; ENDLOOP; ENDLOOP; IF points # scanLineCrossings THEN ERROR; resultProc[devicePath, sStart, sEnd]; }; sStart _ sEnd; sEnd _ sFinal; ENDLOOP; }; ConvertToRuns: PUBLIC PROC [ devicePath: DevicePath, runProc: PROC [sMin, fMin: INTEGER, fSize: NAT], clipBox: DeviceRectangle, parityFill: BOOLEAN _ FALSE ] ~ { Result: PROC [devicePath: DevicePath, sStart, sEnd: INTEGER] ~ { bucketTable: BucketTable ~ devicePath.bucketTable; pointTable: PointTable ~ devicePath.pointTable; parityMask: CARDINAL ~ IF parityFill THEN 1 ELSE LAST[CARDINAL]; scanLineCrossings: NAT ~ bucketTable.seq[bucketTable.length-1]; fOrigin: INTEGER ~ devicePath.fMin; wrap: INTEGER _ 0; pointNumber: NAT _ 0; FOR line: NAT IN [0..bucketTable.length) DO s: INTEGER ~ sStart + line; firstPointOnNextLine: NAT ~ bucketTable.seq[line]; numberOfPointsOnLine: NAT ~ firstPointOnNextLine - pointNumber; fStart: INTEGER; IF numberOfPointsOnLine = 2 THEN { p1, p2: Point; IF Key[p1 _ pointTable[pointNumber]] > Key[p2 _ pointTable[pointNumber+1]] THEN {pointTable[pointNumber] _ p2; pointTable[pointNumber+1] _ p1} } ELSE ShellSort[pointTable, pointNumber, numberOfPointsOnLine]; WHILE pointNumber < firstPointOnNextLine DO point: Point ~ pointTable[pointNumber]; pointNumber _ pointNumber + 1; IF BITANDI[wrap, parityMask] = 0 THEN fStart _ point.fRel + fOrigin; wrap _ wrap + deltaWrap[point.direction]; IF BITANDI[wrap, parityMask] = 0 THEN { fMin: INTEGER _ MAX[fStart, clipBox.fMin]; fMax: INTEGER _ MIN[point.fRel + fOrigin, clipBox.fMin+clipBox.fSize]; IF fMax > fMin THEN runProc[s, fMin, fMax-fMin]; }; ENDLOOP; IF wrap # 0 THEN ERROR; ENDLOOP; }; Convert[devicePath, Result, clipBox]; }; ConvertToPixels: PUBLIC PROC [ devicePath: DevicePath, pixelMap: PixelMap, value: CARDINAL, parityFill: BOOLEAN, function: Function ] ~ { clipBox: DeviceRectangle _ ImagerPixelMap.BoundedWindow[pixelMap]; lgBitsPerPixel: INTEGER _ pixelMap.refRep.lgBitsPerPixel; rast: CARDINAL _ pixelMap.refRep.rast; bbTableSpace: PrincOps.BBTableSpace; bbPtr: PrincOps.BBptr _ InitBBTable[]; InitBBTable: PROC RETURNS [bb: PrincOps.BBptr] ~ TRUSTED INLINE { bb _ PrincOpsUtils.AlignedBBTable[@bbTableSpace]; bb^ _ [ dst: [word: NIL, bit: 0], dstBpl: rast*Basics.bitsPerWord, src: [word: @replicatedPixel, bit: 0], srcDesc: [gray[[yOffset: 0, widthMinusOne: 0, heightMinusOne: 0]]], height: 1, width: 0, flags: [direction: forward, disjoint: TRUE, disjointItems: TRUE, gray: TRUE, srcFunc: function.srcFunc, dstFunc: function.dstFunc] ]; }; replicatedPixel: CARDINAL _ BITAND[value, Shift[1, Shift[1, lgBitsPerPixel]]-1] * ( SELECT lgBitsPerPixel FROM 0 => 0FFFFH, 1 => 05555H, 2 => 01111H, 3 => 00101H, 4 => 00001H, ENDCASE => ERROR ); pointer: LONG POINTER ~ pixelMap.refRep.pointer; words: LONG CARDINAL ~ pixelMap.refRep.words; fBase: INTEGER ~ pixelMap.fOrigin; destLine: LONG POINTER _ pointer; sDest: INTEGER _ pixelMap.sOrigin; Run: PROC [sMin, fMin: INTEGER, fSize: NAT] ~ TRUSTED { bitIndex: CARDINAL _ Shift[fMin-fBase, lgBitsPerPixel]; bbPtr.width _ Shift[fSize, lgBitsPerPixel]; IF sMin = sDest + 1 THEN { destLine _ destLine + rast; sDest _ sMin; } ELSE IF sMin # sDest THEN { destLine _ pointer + Basics.LongMult[sMin-pixelMap.sOrigin, rast]; sDest _ sMin; }; bbPtr.dst.word _ destLine + bitIndex / Basics.bitsPerWord; bbPtr.dst.bit _ bitIndex MOD Basics.bitsPerWord; IF bbPtr.dst.word-pointer < 0 OR bbPtr.dst.word-pointer+NAT[bbPtr.width+15]/16 > words THEN ERROR; PrincOpsUtils.BITBLT[bbPtr]; }; ConvertToRuns[devicePath, Run, clipBox, parityFill]; }; TryBox: PROC [devicePath: DevicePath, clipBox: DeviceRectangle] RETURNS [isBox: BOOL _ FALSE, box: DeviceRectangle _ [0,0,0,0]] ~ { segList: LIST OF SegmentRep _ devicePath.segmentList; IF devicePath.pieceList # NIL OR segList = NIL OR segList.rest = NIL OR segList.rest.rest # NIL THEN RETURN ELSE { seg0: SegmentRep _ segList.first; seg1: SegmentRep _ segList.rest.first; fMin: REAL _ MIN[seg0.f0, seg1.f0]; fMax: REAL _ MAX[seg0.f0, seg1.f0]; IF seg0.f0 # seg0.f1 THEN RETURN; IF seg1.f0 # seg1.f1 THEN RETURN; isBox _ TRUE; box.sMin _ seg0.sFirstScan; box.sSize _ seg0.scanCount; box.fMin _ FloorI[fMin+0.5]; box.fSize _ FloorI[fMax+0.5]-box.fMin; box _ ImagerPixelMap.Intersect[box, clipBox]; }; }; ConvertToManhattanPolygon: PUBLIC PROC [ devicePath: DevicePath, clipBox: DeviceRectangle, parityFill: BOOLEAN ] RETURNS [LIST OF DeviceRectangle] ~ { Runs: PROC [ run: PROC [sMin, fMin: INTEGER, fSize: NAT], repeat: PROC [timesToRepeatScanline: NAT]] ~ { ConvertToRuns[devicePath, run, clipBox, parityFill]; }; isBox: BOOL; box: DeviceRectangle; [isBox, box] _ TryBox[devicePath, clipBox]; IF isBox THEN RETURN [ImagerManhattan.CreateFromBox[box]] ELSE RETURN [ImagerManhattan.CreateFromRuns[Runs]]; }; END. ���¼��ImagerScanConverterImpl.mesa Copyright c 1984, 1985 by Xerox Corporation. All rights reserved. Michael Plass, November 26, 1985 5:23:01 pm PST Doug Wyatt, March 7, 1985 6:16:47 pm PST -- These parameters control the precision with which the inner loop b subdivision is done. -- This parameter controls how much scratch storage a devicePath retains. -- Some inlines for basic bit-hacking operations. Not used now, but a little easier to uderstand than the real one below. this could be speeded up, if necessary In this case, the convergence is faster. First find the coefficients of the s projection. Now find the coefficients of the derivative. Find where the derivative vanishes. Now break it up as needed force monotonicity, in case of roundoff error force monotonicity, in case of roundoff error w cannot be exactly zero, since otherwise endScan = firstScan. Only one scan line, so sDelta just needs to be positive to avoid an infinite loop. �Ê#¸��˜�codešœ™Kšœ Ïmœ7™BK™/K™(—K˜�šÏk ˜ Kšœžœžœžœžœžœ˜OKšœžœ!˜6Kšœžœ˜'Kšœžœ7˜KKšœžœ˜%Kšœžœq˜‘Kšœžœ˜,Kšœ žœ˜%Kšœžœžœ˜-Kšœžœ ˜*Kšœžœ˜'Kšœžœžœ˜—K˜�KšÐblœž ˜&KšžœR˜YKšžœ˜šœž˜K˜�Kšœžœžœ"žœ˜=Kšœžœžœžœ˜!Kšœ žœ˜)Kšœžœžœ˜%Kšœžœžœ,˜FKšœ žœ*˜;Kšœžœ-˜AKšœžœ(˜7Kšœ žœ'˜5Kšœžœ$˜/Kšœžœ)˜9Kšœžœ,˜?Kšœžœ)˜9Kšœ žœ ˜.Kšžœžœžœ˜šœžœ"˜7K˜�—šœ[™[Kšœ žœ˜KšœžœÏc˜,Kšœ žœ !˜5K˜�—šœJ™JKšœžœ˜K™�—™1š Ðknœžœžœžœžœ˜/Kšœžœžœžœ ˜'K˜�—š ¡œžœžœžœžœ˜.Kš œžœžœžœžœžœžœ˜EK˜�—š ¡œžœžœžœžœ˜.Kšœžœžœžœ ˜&K˜�—š ¡œžœžœžœžœ˜/Kšœžœžœžœ ˜'K˜�—šÏnœžœžœžœžœžœ˜8Kšœžœžœžœ ˜)K˜�—š ¢œžœžœžœžœ˜6Kšœžœžœžœ˜1K˜�—š ¢œžœžœžœžœ˜,Kšœžœžœžœ ˜-K˜�—š ¢œžœžœžœžœ˜+Kšœžœžœžœ ˜5K˜�—š ¢œžœžœžœžœ˜-Kšœžœžœžœ ˜5K˜�——Kšœžœžœžœ˜0š¢ œžœ žœžœžœžœžœ˜YKšœžœžœžœ˜*Kšœ˜KšœžœžœE˜YKšžœ žœžœ!˜;šžœž˜%Kšœžœ˜šžœžœžœžœ˜!Kšœ˜Kšœ˜Kšœ˜Kšœ˜Kšœ˜—Kšœ˜Kšœ˜Kšœ˜Kšœ˜šžœžœ˜"KšœE˜EKšœ;˜;Kšœ˜Kšœ˜Kšœ˜—šžœ˜Kšœžœ˜(Kšœ˜KšœD˜DKšœC˜CKšœ˜Kšœ˜Kšœ˜—Kšžœ˜—Kšžœ žœžœ˜šžœžœžœžœ žœžœ˜FKšžœ&˜*—šžœžœ ˜Kšžœ_˜cKšžœe˜i—Kšœ˜K˜�—š ¢œžœ žœžœžœ˜WK™GKšœžœ˜Kšœžœ˜K™&Kšœžœ"˜-Kšœžœ˜Kšœžœ˜Kšœžœ%˜-Kšœžœ%˜-Kšœžœžœžœ žœžœ˜.Kš œžœžœžœžœ˜)Kšœ˜šžœž˜Kšœ,˜,Kšœ˜Kšžœ˜—Kšžœžœžœ?˜VKšœ˜J˜�—š¢œžœ žœžœ˜LKšœžœ˜Kšœžœ˜Kšœžœ!˜+Kšœžœ+˜4Kšœžœ+˜4Kš œžœžœžœžœ˜,Kšœžœ ˜Kšœ˜šžœž˜Kšœ,˜,Kšœ˜Kšžœ˜—šžœžœžœžœžœžœžœžœ˜J™(Jšœ>˜>Jšœ˜—Kšœ˜J˜�—Kšœžœ˜š¢œžœžœžœ˜;Kšœžœ'˜.K˜�—š¢ œžœžœžœ˜DK˜K˜K˜K˜K˜K˜K˜K˜K˜K˜K˜Kšœ7˜7Kšœ8˜8Kšœ˜K˜�—š ¢œžœžœžœžœ˜UKš žœžœžœžœžœ˜#Kšœ˜Kšœžœ˜šžœžœžœ˜*Kšžœžœžœ˜.šžœ˜Kšœžœžœ˜šžœ žœž˜Jšœ˜Jšžœ˜—Jšœ$˜$Jšœ˜—Jšœžœ˜!Jšœ˜—Kšœ˜K˜�—š ¢œžœžœžœžœ˜QKš žœžœžœžœžœ˜#Kšœ˜Kšœžœ˜šžœžœžœ˜(Kšžœžœžœ˜,šžœ˜Kšœžœžœ˜šžœ žœž˜Jšœ˜Jšžœ˜—Jšœ"˜"Jšœ˜—Jšœžœ˜Jšœ˜—Kšœ˜K˜�—š¢œžœžœžœ žœžœžœ˜^Kšœ˜šžœžœžœžœ˜'Kšœžœžœ˜šžœžœžœžœžœž˜4Jšœ˜Jšžœ˜—šžœžœžœ˜Jšœ˜Jšœžœ˜Jšœ˜—Jšžœžœ˜ Jšœ˜—šžœžœž˜Kšœžœžœ˜Kšœ˜Kšœ žœ˜ Kšžœ˜—Kšœ˜K˜�—š¢œžœžœžœžœžœžœ˜XKšœ˜šžœžœžœžœ˜'Kšœžœžœ˜šžœžœžœžœžœž˜4Jšœ˜Jšžœ˜—šžœžœžœ˜Jšœ˜Jšœžœ˜Jšœ˜—Jšžœžœ˜ Jšœ˜—šžœžœž˜Kšœžœžœ˜Kšœ˜Kšœ žœ˜ Kšžœ˜—Kšœ˜K˜�—š¢ œžœžœ˜Kšœ˜K˜4Kšœ˜Kšœžœ ˜2Kšœžœ˜Kšœ˜Kšœžœžœ-˜HKšœžœžœ)˜Bš¢ œžœžœ˜.Kšœ˜Kšžœžœžœžœžœžœžœžœžœžœžœ˜’šžœ žœ˜Kšœ˜Kšœ˜Kšœ˜Kšœ˜Kšœ˜Kšœ˜—šžœ˜Kšœ˜Kšœ˜Kšœ˜Kšœ˜Kšœ˜Kšœ˜—Kšœ.˜.Kšœžœ:˜Bšžœžœ˜KšœP˜PKšžœ&žœ&˜RKšžœžœ&žœ:˜ƒKšœžœ:˜OKšœžœ>˜Sšžœžœž˜ Kšœžœ!˜>—šžœ˜Kšœžœžœ!˜+Kšœ˜Kšœ ˜ Kšœ˜Kšœ˜Kšœ˜—Kšœ˜—Kšœ˜—š¢œžœžœ˜:Kšœžœ˜2Kšžœžœ&˜Ešžœ˜Kšœ˜Kšœžœ#˜-Kšœžœžœ˜Kšœžœ˜Kšœ žœ˜Kšœ˜š žœžœžœžœ žœžœž˜EKšœ˜Kšœ˜Kšœ ˜ Kšžœ˜—šžœ žœ˜Kšœ=˜=Kšœ˜Kšœ˜—Kšžœ˜"Kšœ˜Kšœ!˜!Kšœ9˜9Kšœ9˜9Kšœ9˜9Kšœ9˜9Kšœ<˜<Kšœ9˜9Kšœ9˜9Kšœ9˜9Kšœ0˜0Kšœ&˜&Kšœžœ2˜8šžœžœ˜KšœN˜NKšžœ$žœ$˜NKšžœžœ$žœ6˜{Kšžœžœ˜BKšœžœ0žœ-˜ušžœžœž˜Kšœžœ˜8—šžœ˜Kšœžœžœ˜'Kšœ˜Kšœ˜Kšœ˜Kšœ˜Kšœ˜—Kšœ˜—K˜—Kšœ˜—Kš œžœžœžœžœžœžœ˜>Kš œžœžœžœžœžœžœ ˜MKš œžœžœžœžœžœžœ˜>Kš œžœžœžœžœžœžœ ˜MKšœžœžœžœžœžœ˜BKšœžœžœžœžœžœ˜AKšœžœžœžœžœžœ˜BKšœžœžœžœžœžœ˜AKš¢œžœžœžœžœžœžœžœ˜SKš¢œžœžœžœžœžœžœžœ˜Sš¢œžœ˜/š¢ œžœ˜Kš¢œžœžœžœžœžœžœ˜MKšœA˜AKšœA˜AKšœA˜AKšœ*˜*Kšœ*˜*Kšœ/˜/KšœQ˜QKšœQ˜QK˜—Kšœžœžœ-˜=Kšœžœžœ-˜=Kšœ žœžœ˜*Kšœžœžœ ˜0Kšœžœžœ-˜=šœžœžœž˜&K˜K˜K˜K˜Kšžœ˜ —šœžœžœž˜&K˜K˜K˜K˜Kšžœ˜ —šœžœžœž˜&K˜K˜K˜K˜Kšžœ˜ —šœžœžœž˜&K˜K˜K˜K˜Kšžœ˜ —Kšžœžœžœžœžœžœ˜Ošžœ˜Kšžœžœžœžœžœžœžœžœ žœ'˜©Kšžœ ˜Kšœ˜—šžœžœžœžœžœž˜Qšœ˜Kšœ#˜#Kšœ#˜#Kšœ#˜#Kšœ"˜"Kšœ˜——Kšžœ ˜K˜—š¢œžœ˜"™0Kšœžœ˜Kšœžœ˜Kšœžœ˜Kšœžœ ˜Kšœžœ˜—™,Kšœžœ˜Kšœžœ˜Kšœžœ˜—™#Kšœžœ˜Kšœ žœ˜šžœžœ žœ˜Kšœžœ ˜Kšœžœ ˜Kšœžœ˜šžœžœ˜Kšœžœ˜Kšœ žœžœžœ ˜,Kš œžœžœ žœžœ˜'Kšœ˜—Kšœ˜—Kšžœžœžœ žœ ˜%—™Kšœžœžœ˜Kšœžœžœ˜Kšžœ žœžœ˜0šžœ žœ žœ žœ˜+Kšœ˜Kšœ"˜"Kšœ)˜)™-Kšœ˜Kšœ˜Kšœ˜Kšœ˜—Kšœ˜Kšœ˜Kšœ˜Kšœ˜—šžœžœžœžœžœžœ˜3Kšœ˜Kš œžœžœžœžœ˜@™-Kšœ˜Kšœ˜—Kšœ˜Kšœ˜Kšœ˜—Kšžœ˜—Kšœ˜—Kšœ˜Kšœ žœžœ˜š¢œžœžœ˜Kšœ$˜$Kšœ˜—š¢œžœžœ˜Kšœžœžœ˜K˜ Kšžœ žœžœ žœ˜RKšžœžœžœžœ˜?Kšžœ.˜2šžœ˜Kšœ.˜.Kšœ.˜.KšœG˜GK˜—Kšœ˜Kšœ˜—š¢œžœ žœ˜ KšœM˜MKšœ˜Kšœ˜—š¢œžœ˜Kšžœžœ$˜BKšœ˜—Kšœ!˜!Kšœžœžœ˜ Kšœžœžœ˜!Kšœžœžœ˜ Kšœžœžœ˜!šœ3˜3Kšœ:˜:—šžœ#ž˜)KšœJ˜J—šžœžœžœ˜Kšœ+˜+Kšœ-˜-KšœK˜KKšœE˜EKšœ˜Kšžœ ˜Kšœ˜—Kšžœžœ˜)Kšœ˜K˜�—Kšœžœ žœžœ<˜]Kš¢œžœžœžœžœžœžœžœ ˜Wš¢ œžœ$žœžœ˜Cšžœ žœ˜Kšœ˜Kšœ žœžœžœ˜2Kš œžœžœžœ$žœ˜GKšžœ3žœžœžœ˜Hš žœžœž œžœž˜1Kšœžœ˜Kšœžœžœ˜%šžœžœžœžœžœž˜UKšœ˜Kšœžœžœžœ˜#Kšœžœžœžœ˜šžœžœžœžœžœžœžœžœž˜qKšœ˜Kšœ ˜ Kšžœ˜—Kšœ ˜ Kšžœ˜—Kšžœ˜—Kšœ˜—Kšœ˜—š ¢œžœ žœžœžœ˜ŒKšœžœ˜'š œžœžœžœ&žœ˜TKšžœžœ#˜+—Kšœ%˜%šžœžœžœž˜%Kšœ˜Kšžœ˜—šžœžœžœ-žœžœž˜KKšœžœžœ"˜6Kšœžœžœ4˜Fšžœ žœ˜Kšœ4˜4Kšœ0˜0Kšœ˜—Kšžœ˜—šžœžœžœ)žœžœž˜GKšœžœžœ"˜6Kšœžœžœ4˜Fšžœ žœ˜Kšœ4˜4Kšœ0˜0Kšœ˜—Kšžœ˜—šœžœ˜šžœžœžœž˜(Kšœ˜Kšœ˜šžœžœ˜$Jšœ˜Jšžœ˜Jšœ˜—Kšœ˜Kšžœ˜—K˜—Kšœ˜—š¢œžœžœžœ˜OKšžœg˜mKšœ˜—š ¢œžœžœžœžœ˜RKšœ.˜.Kšœ˜—Kšœžœ˜Kšœžœ ˜š¢œžœ˜Kšœ˜Kšœžœžœžœ˜AKšœ˜Kšœ˜Kšœžœžœ ˜5Kšœžœžœžœ/˜HKšœžœ ˜Kšœ žœ˜#Kšœ˜šžœž˜Kšžœ$žœ$˜NKšœl˜lšžœ;žœ˜CKšœ˜šžœ2ž˜9Kšœ˜Kšžœ˜—Kšžœžœ˜(Kšœl˜lKšœ˜—šžœ˜ Kšœžœ)˜?šœ.ž˜0Kšžœž˜Kšžœ5˜8Kšžœ˜Kšžœžœ#˜+—Kšœžœ˜šžœžœžœ-žœžœž˜KKšœžœžœ˜5Kšœ žœžœ-˜Cšžœžœžœ˜%Kšœ)˜)š œžœžœžœžœ˜FKšœ>™>—Kšœžœ0˜?Kšœžœ0˜?Kšœžœžœ ˜!Kš œžœžœžœžœ˜;Kšœžœ˜KšœžœS˜^Kšœžœ˜šœžœ˜Kšžœ˜Kšžœ"˜&Kšžœ#˜'—Kš œžœžœžœžœ(˜Ešžœ žœ˜Kšžœžœžœžœ˜4šœ˜KšœR™R—Kšœ˜—šžœžœžœž˜)Kšœžœ&˜DKšœ˜K˜Kšœžœžœ˜Kšœ˜šžœž˜Kšœ˜Kšœ˜Kšžœ˜—Kšžœ˜—Kšœ˜—Kšžœ˜—šžœžœžœ)žœžœž˜GKšœžœžœ˜5Kšœ žœžœ-˜CKšœ)˜)šžœžœžœž˜)Kšœžœ˜šžœ˜ Kš œžœžœžœžœ ˜=Kšœ<˜<Kšœ˜K˜Kšœ˜—Kšžœ˜—Kšžœ˜—Kšžœžœžœ˜)Kšœ%˜%Kšœ˜—Kšœ˜Kšœ˜Kšžœ˜—Kšœ˜K˜�—š¢ œžœžœ˜Kšœ˜Kšœ žœžœ žœ˜0Kšœ˜Kšœžœž˜Kšœ˜š¢œžœžœžœ˜@Kšœ2˜2Kšœ/˜/Kš œžœžœžœžœžœžœ˜@Kšœžœ)˜?Kšœ žœ˜#Kšœžœ˜Kšœ žœ˜šžœžœžœž˜+Kšœžœ˜Kšœžœ˜2Kšœžœ&˜?Kšœžœ˜šžœžœ˜"K˜šžœIž˜OKšœ>˜>—K˜—Kšžœ:˜>šžœ$ž˜+Kšœ'˜'Kšœ˜Kšžœžœžœ˜DKšœ)˜)šžœžœžœ˜'Kšœžœžœ˜*Kšœžœžœ3˜FKšžœ žœ˜0K˜—Kšžœ˜—Kšžœ žœžœ˜Kšžœ˜—Kšœ˜—Kšœ%˜%Kšœ˜K˜�—š¢œžœžœ˜Kšœ˜Kšœ˜Kšœžœ˜Kšœžœ˜Kšœ˜Kšœ˜KšœB˜BKšœžœ"˜9Kšœžœ˜&K˜$Kšœ&˜&š ¢œžœžœžœžœ˜AKšœ1˜1˜Kšœžœ ˜Kšœ ˜ Kšœ&˜&KšœC˜CK˜ Kšœ ˜ Kšœ&žœžœžœ7˜‚K˜—Kšœ˜—šœžœ˜šžœ1˜7šžœž˜KšœÏfœ˜Kšœ£œ˜Kšœ£œ˜Kšœ£œ˜Kšœ£œ˜Kšžœž˜—Kšœ˜——Kšœ žœžœ˜0Kšœžœžœ˜-Kšœžœ˜"Kšœ žœžœ˜!Kšœžœ˜"š ¢œžœžœ žœžœ˜7Kšœ žœ%˜7Kšœ+˜+šžœžœ˜Jšœ˜Jšœ ˜ Jšœ˜—šžœžœžœ˜JšœB˜BJšœ ˜ Jšœ˜—Kšœ:˜:Kšœžœ˜0Kš žœžœžœžœžœ˜bKšœžœ˜Kšœ˜—Kšœ4˜4Kšœ˜K˜�—š ¢œžœ4žœ žœžœ'˜ƒKšœ žœžœ%˜5Kšžœžœžœžœžœžœžœžœžœž˜kšžœ˜Kšœ!˜!Kšœ&˜&Kšœžœžœ˜#Kšœžœžœ˜#Kšžœžœžœ˜!Kšžœžœžœ˜!Kšœžœ˜ Kšœ˜Kšœ˜Kšœ˜Kšœ&˜&Kšœ-˜-Kšœ˜—Kšœ˜K˜�—š¢œžœžœ˜(Kšœ˜K˜Kšœž˜Kšœžœžœžœ˜'š¢œžœ˜Kšœžœžœ žœ˜,Kšœžœžœ˜.Kšœ4˜4Kšœ˜—Kšœžœ˜Kšœ˜Kšœ+˜+Kšžœžœžœ%˜9Kšžœžœ(˜3Kšœ˜K˜�——Kšžœ˜—�…—����jæ��’Z��