DIRECTORY Basics USING [LongNumber, BITXOR], ImagerBrick USING [Brick, BrickRep], PriorityQueue USING [Ref, Item, Create, Insert, Remove, Empty], Real USING [RoundLI], RealFns USING [CosDeg, SinDeg]; ImagerBrickImpl: CEDAR PROGRAM IMPORTS Basics, 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; }; BuildBrick: PUBLIC PROC [freq: REAL, angle: REAL, filter: PROC [x, y:REAL] RETURNS [fvalue: REAL]] RETURNS [brick: Brick] = { tInt: INTEGER; --temporary u,v: REAL _ 0.0; --u/v is tangent[angle] iu, iv, iuvsqrd: INTEGER _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.RoundLI[u];-- get nearest integer iv _ Real.RoundLI[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 _ iu*iu + iv*iv; fSize _ iuvsqrd/sSize;--calculate length of brick 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, cBrick: ]]; brick.phase _ (x*absiv - y*absiu) MOD 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.cBrick[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.RoundLI[r]; IF i>r THEN i_i-1; };--FloorI GetSize: PUBLIC PROC[brick: Brick] RETURNS [fSize, sSize: CARDINAL, phase: INTEGER] = { RETURN[brick.fSize, brick.sSize, brick.phase]; };--GetSize Modd: PROC[x, y: LONG INTEGER] RETURNS [LONG INTEGER] = { RETURN [IF x >= 0 THEN (x MOD y) ELSE ((y-1) + (x+1) MOD y)]; };--Modd GetElement: PUBLIC PROC[brick: Brick, x, y: CARDINAL] RETURNS [bElement: REAL] = { row, col: CARDINAL _ 0; row _ GetRow[brick,x,y]; col _ GetCol[brick,x,y]; RETURN [brick.cBrick[brick.fSize*row + col]]; };--GetElement GetRow: PUBLIC PROC[brick: Brick, x, y: CARDINAL] RETURNS [row: CARDINAL] = { RETURN [y MOD brick.sSize]; };--GetRow GetCol: PUBLIC PROC[brick: Brick, x, y: CARDINAL] RETURNS [col: CARDINAL] = { i: LONG INTEGER _ Modd[(x - LONG[brick.phase]*(y/brick.sSize)), brick.fSize]; RETURN [i]; };--GetCol }. --of CGBrickImpl LOG 2ImagerBrickImpl.mesa Copyright c 1984 Xerox Corporation. All rights reserved. Adapted from CGBrickImpl, by Ken Pier Michael Plass, July 7, 1983 10:14 am Doug Wyatt, July 20, 1984 2:39:04 pm PDT sorting function for halftone generator below Random bit generator Generates random bits using a shift register 30 bits long, (see Knuth ACM 3.2.2). This seed was generated by InitRandom[4, 1000000] Procedure BuildBrick is called with a halftone dot defined by its frequency in pixels/dot (may be REAL), rotation angle, and a filter function defined on the interval [-1..+1] in both x and y, returning values in the range [0..1]. define the parameters u and v of the "enclosing square" surrounding the rotated halftone dot now compute rotation for iu, iv into first quadrant now calculate the elements of the coord transformation from brick indexes into the elementary dot. This dot is 2 wide and 2 high centered about the origin. The transform is a concatenation of two transform matrices, one to normalize the brick by 2, and another to rotate the brick coordinates into elementary coordinates: [ 2 0 ] [ cos -sin] [ a b ] [ ] * [ ] = [ ] [ 0 2 ] [ sin cos] [ c d ] get brick instance now calculate the brick values brick is fSize long and sSize high created, 21-Oct-81 12:00:21, Pier changed matrix to store by rows instead of columns 26-Oct-81 15:24:40 fixed Modd to take LONG INTEGERs; added LONG in GetCol 8-Jan-82 13:27:38 changed system zone to CGStorage zone, Brick to REF, 13-Jan-82 reformatted, 18-JAN-82 changed to general purpose halftone brick, 23-Jan`82 changed definition of brick to use L,p,D field names, 2/22/82 Michael Plass, July 6, 1983 3:22 pm: Changed name from CGBrickImpl to ImagerBrickImpl; extensive modifications. Michael Plass, July 7, 1983 8:59 am: changed brick definition to use fSize, sSize, phase, cBrick field names, Brick and BrickRep instead of BrickHandle and Brick. Michael Plass, July 7, 1983 10:39 am: Replace use of RandomCard with a shift-register random bit generator, to make BuildBrick into a pure function. Êt˜šœ™Jšœ Ïmœ.™9Jšœ%™%J™$J™(—J˜šÏk ˜ Jšœžœžœ˜"Jšœ žœ˜$Jšœžœ,˜?Jšœžœ ˜Jšœžœ˜J˜—Jšœžœž˜Jšžœ%˜,Jšžœ˜Jšžœ ˜J˜Jšœžœžœ ˜Jš œ žœžœžœžœ˜4J˜šœ-™-š Ïnœžœ"žœžœžœ˜GJšœ žœ˜Jšœ žœ˜Jš žœžœžœ žœžœ˜KJšœ˜——J˜head2™J™SJ˜Jšœžœžœ ˜#šœ žœžœ˜Jšœ1™1Jšœžœ ˜Jšœ˜—J˜Jšœžœ˜Jšœ žœ˜J˜š Ÿœžœžœžœžœ˜=Jšœžœ˜1Jšžœ ˜Jšœ˜—J˜šŸ œžœžœžœ˜8Jšžœ žœžœžœ ˜AJšœ˜—J˜š Ÿ œžœžœžœžœ˜?Jšœžœ˜Jš žœžœžœžœžœ˜3Jšœ˜—J˜—JšœA™AJšœW™WJšœL™LJ˜šŸ œžœžœžœ žœ žœžœžœ žœ˜bJšžœ˜J˜JšœžœÏc ˜Jšœžœ ˜(Jšœžœ !˜=Jšœžœ ˜7Jšœžœ  ˜?Jšœžœ 9˜SJšœ žœ #˜7Jšœžœ˜Jšœžœ *˜=Jšœ&žœ˜1J˜Jšœ7™7Jšœ$™$J˜Jšœ?˜?Jšœ ˜+Jšœ˜Jšžœžœžœ ˜3Jšœ3™3Jšœžœžœ˜!Jšžœ žœ/˜@Jšœ- 6˜cJ˜Jšžœ ˜1J˜Jšœ;™;JšœD™DJšœB™BJšœ8™8JšœD™DJ™JšÏf#™#Jš¡#™#Jš¡#™#J˜Jšœ'˜'J˜J˜Jšœ ˜J˜Jšœ™Jšœžœ`˜kJšœ"žœ˜,J˜Jšœ™šœ &˜(J˜ Jšœžœ˜Jšœžœ ˜Jšœžœ˜Jšœ7žœ ˜Gšžœžœ ž˜J˜šžœžœ ž˜J˜J˜5J˜5Jšœžœ ˜J˜DJšœ˜Jšžœ˜—Jšžœ˜—šžœžœžœ ž˜Jšœžœ ˜Jšœ4˜4J˜,Jšžœ˜—Jšžœžœ žœžœ˜Jšœ ˜—Jšœ  ˜—J˜š Ÿœžœžœžœžœ˜FJšœžœ˜#J˜J˜šž˜Jšžœ žœžœ˜J˜ J˜/J˜J˜Jšžœ˜—Jšœ˜—J˜š Ÿœžœžœžœžœ˜)Jšœžœ  ˜(—J˜š Ÿœžœžœžœžœ˜*Jšœ˜Jšžœžœ˜Jšœ ˜ —J˜š Ÿœžœžœžœžœ žœ˜WJšœ"™"Jšžœ(˜.Jšœ  ˜ —J˜šŸœžœžœžœžœžœžœ˜9Jš žœžœžœžœžœžœ˜>Jšœ ˜—J˜š Ÿ œžœžœžœžœ žœ˜RJšœ žœ˜Jšœ˜Jšœ˜Jšžœ'˜-Jšœ  ˜—J˜š Ÿœžœžœžœžœžœ˜MJšžœžœ˜Jšœ ˜ —J˜š Ÿœžœžœžœžœžœ˜MJšœžœžœ žœ-˜MJšžœ˜ Jšœ ˜ —J˜Jšœ ˜J˜Jšž˜Jšœ!™!JšœE™EJšœI™IJšœ>™>Jšœ™Jšœ4™4Jšœ=™=Jšœo™oJšœ¢™¢Jšœ”™”J˜J˜—…—!¦