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��