DIRECTORY Basics USING [LongNumber, BITXOR], ImagerBrick, 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 þImagerBrickImpl.mesa Adapted from CGBrickImpl by Ken Pier Michael Plass, July 7, 1983 10:14 am Edited by Doug Wyatt, November 22, 1983 11:57 am 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. Êc˜Jšœ™Jšœ$™$J™$J™0J˜šÏ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˜—…—è!I