<> <> <> <> <> DIRECTORY Basics USING [LongDivMod, LongNumber, BITXOR], ImagerBrick, ImagerSample, PriorityQueue USING [Ref, Item, Create, Insert, Remove, Empty], Real USING [Round], RealFns USING [CosDeg, SinDeg]; ImagerBrickImpl: CEDAR PROGRAM IMPORTS Basics, ImagerSample, PriorityQueue, Real, RealFns EXPORTS ImagerBrick = { OPEN ImagerBrick; QItem: TYPE = REF QItemRep; QItemRep: TYPE = RECORD [f, s: CARDINAL, val: REAL]; <> SortPred: PROC [x, y: PriorityQueue.Item, data: REF] RETURNS [BOOL] = { na: QItem _ NARROW[x]; nb: QItem _ NARROW[y]; RETURN[IF na.val=nb.val THEN RandomBool[NARROW[data]] ELSE na.val < nb.val] }; <> <> RandomHandle: TYPE = REF RandomRec; RandomRec: TYPE = RECORD [ <> w: INT _ -1978068312 ]; lowTap: INT = 10000000000B; highTap: INT = 100000000B; XorC: PROC [long: Basics.LongNumber] RETURNS [INT] = INLINE { long.lowbits _ Basics.BITXOR[long.lowbits, 514B]; RETURN[long.li]; }; RandomBool: PROC [r: RandomHandle] RETURNS [BOOLEAN] = { RETURN [0>(r.w _ IF r.w<0 THEN XorC[[li[r.w+r.w]]] ELSE r.w+r.w)] }; InitRandom: PROC [w: INT, n: INT] RETURNS [r: RandomHandle] = { r _ NEW[RandomRec _ [w]]; FOR i: INT IN [0..n) DO [] _ RandomBool[r] ENDLOOP; }; <> <> <> NewBrick: PUBLIC PROC [freq, angle: REAL, filter: FilterProc] RETURNS [brick: Brick] = { tInt: INTEGER; --temporary u,v: REAL _ 0.0; --u/v is tangent[angle] iu, iv: INTEGER _ 0; -- closest integer values of u,v iuvsqrd: INT _ 0; -- closest integer values of u,v absiu, absiv: INTEGER _ 0; -- absolute values of iu,iv riu, riv, riuvsqrd: REAL _ 0.0; --real versions of iu, iv, etc. sSize, fSize: INTEGER _0; --dimensions of halftone brick, fSize wide and sSize high a,b,c,d: REAL _ 0.0; --elements of the transform matrix LIndex, pIndex: INTEGER _ 0; x, y: INTEGER _ 0; --for receiving results of ExtendedEuclid. reali, realj, realiPrime, realjPrime: REAL _ 0.0; <> <> u _ freq*RealFns.SinDeg[angle]; v _ freq*RealFns.CosDeg[angle]; iu _ Real.Round[u];-- get nearest integer iv _ Real.Round[v]; IF iu = 0 AND iv = 0 THEN iu _ 1;--appearance error <> absiv _ ABS[iv]; absiu _ ABS[iu]; IF iu*iv < 0 THEN { tInt _ absiv; absiv _ absiu; absiu _ tInt }; [x, y, sSize] _ ExtendedEuclid[absiu, absiv];--computes GCD of arguments plus phase value arguments iuvsqrd _ INT[iu]*iu + INT[iv]*iv; fSize _ iuvsqrd/sSize;--calculate length of brick <> <> <> <> <> <<>> <<[ 2 0 ] [ cos -sin] [ a b ]>> <<[ ] * [ ] = [ ]>> <<[ 0 2 ] [ sin cos] [ c d ]>> riu _ iu; riv _ iv; riuvsqrd _ iuvsqrd; d _ a _ 2*riv/riuvsqrd ; c _ 2*riu/riuvsqrd; b _ -c; -- -2*riu/riuvsqrd <> brick _ NEW[BrickRep[fSize*sSize] _ [fSize: fSize, sSize: sSize, phase: 0, u: absiu, v: absiv, samples: ]]; brick.phase _ Mod[(x*absiv - y*absiu), fSize]; <> { -- so we can do some more declarations item: QItem; lxp: NAT = fSize*sSize; sliceInterval: REAL = 1.0/lxp; currentSlice: REAL _ 0; pQ: PriorityQueue.Ref _ PriorityQueue.Create[SortPred, NEW[RandomRec]]; FOR LIndex IN [0..fSize) DO reali _ LIndex+0.5; FOR pIndex IN [0..sSize) DO realj _ pIndex+0.5; realiPrime _ RealMod[(reali*a + realj*c), 2.0] - 1.0; realjPrime _ RealMod[(reali*b + realj*d), 2.0] - 1.0; item _ NEW[QItemRep]; item^ _ [f: LIndex, s: pIndex, val: filter[realiPrime, realjPrime]]; pQ.Insert[item]; ENDLOOP; ENDLOOP; FOR i: NAT IN [0..lxp) DO item _ NARROW[pQ.Remove]; brick[fSize*item.s + item.f] _ currentSlice; currentSlice _ currentSlice + sliceInterval; ENDLOOP; IF NOT pQ.Empty THEN ERROR; };--brick values };--BuildBrick ExtendedEuclid: PROC [u, v: INTEGER] RETURNS [u1, u2, u3: INTEGER] = { q, v1, v2, v3, t1, t2, t3: INTEGER; u1 _ 1; u2 _ 0; u3 _u; v1 _ 0; v2 _ 1; v3 _ v; DO IF (v3 = 0) THEN EXIT; q _ u3/v3; t1 _ u1-(v1*q); t2 _ u2-(v2*q); t3 _ u3-(v3*q); u1 _ v1; u2 _ v2; u3 _ v3; v1 _ t1; v2 _ t2; v3 _ t3; ENDLOOP; }; RealMod: PROC[a,b: REAL] RETURNS [REAL] = { RETURN[a - (FloorI[a/b])*b]};--RealMod FloorI: PROC[r: REAL] RETURNS [i: INT] = { i _ Real.Round[r]; IF i>r THEN i_i-1; };--FloorI Mod: PROC [n: INT, d: NAT] RETURNS [remainder: NAT] ~ { <> IF d#1 THEN { nn: Basics.LongNumber _ [li[n]]; WHILE nn.li < 0 DO nn.highbits _ nn.highbits + d ENDLOOP; WHILE nn.highbits >= d DO nn.highbits _ nn.highbits - d ENDLOOP; RETURN [Basics.LongDivMod[nn.lc, d].remainder]; } ELSE RETURN [remainder: 0]; }; GetElement: PUBLIC PROC[brick: Brick, s, f: NAT] RETURNS [REAL] = { row, col: CARDINAL _ 0; row _ GetRow[brick, f, s]; col _ GetCol[brick, f, s]; RETURN [brick[brick.fSize*row + col]]; };--GetElement GetRow: PROC[brick: Brick, x, y: CARDINAL] RETURNS [row: CARDINAL] = { RETURN [y MOD brick.sSize]; };--GetRow GetCol: PROC[brick: Brick, x, y: CARDINAL] RETURNS [col: CARDINAL] = { RETURN [Mod[(x - INT[brick.phase]*(y/brick.sSize)), brick.fSize]]; };--GetCol DotScreen: PUBLIC FilterProc ~ { tx: REAL _ (x-1)*(x-1)*(x+1)*(x+1); ty: REAL _ (y-1)*(y-1)*(y+1)*(y+1); RETURN[(tx+ty)/2]; }; LineScreen: PUBLIC FilterProc ~ { RETURN[(x-1)*(x-1)*(x+1)*(x+1)]; }; NewSquareBrick: PUBLIC PROC [size: NAT, p, q: INTEGER, pModulation, qModulation: REAL] RETURNS [Brick] ~ { max: REAL _ ABS[pModulation]+ABS[qModulation]; min: REAL _ -max; Screen: FilterProc ~ { x0: REAL _ (x+1)/2.0; y0: REAL _ (y+1)/2.0; u: REAL _ p * x0 + q * y0; v: REAL _ -q * x0 + p * y0; RETURN[(pModulation*RealFns.CosDeg[u*360] + qModulation*RealFns.CosDeg[v*360] - min)/(max-min)]; }; RETURN[NewBrick[size, 0, Screen]]; }; ThresholdsFromBrick: PUBLIC PROC [brick: Brick, max: Sample, scratch: SampleBuffer _ NIL] RETURNS [buffer: SampleBuffer] ~ { buffer _ ImagerSample.NewBuffer[brick.sSize, brick.fSize, scratch]; FOR s: NAT IN[0..brick.sSize) DO FOR f: NAT IN[0..brick.fSize) DO r: REAL ~ GetElement[brick, s, f]; sample: Sample ~ Real.Round[r*(max-1)]+1; buffer.PutSample[s, f, sample]; ENDLOOP; ENDLOOP; }; }. --of CGBrickImpl LOG <> <> <> <> <> <> <> <> <> <>