DIRECTORY Draw2d, Imager, ImagerBackdoor, ImagerDevice, ImagerDeviceWorks, ImagerFont, ImagerInterpress, ImagerPath, ImagerRaster, ImagerState, ImagerTransformation, Prop, Real, RealFns, Rope, SF, Vector2, ViewerClasses; Draw2dImpl: CEDAR PROGRAM IMPORTS Imager, ImagerBackdoor, ImagerDeviceWorks, ImagerFont, ImagerInterpress, ImagerPath, ImagerRaster, ImagerTransformation, Prop, Real, RealFns, SF, Vector2 EXPORTS Draw2d ~ BEGIN ROPE: TYPE ~ Rope.ROPE; VEC: TYPE ~ Imager.VEC; -- RECORD [x, y: REAL] Context: TYPE ~ Imager.Context; Viewer: TYPE ~ ViewerClasses.Viewer; DrawProc: TYPE ~ Draw2d.DrawProc; DrawType: TYPE ~ Draw2d.DrawType; IntegerBox: TYPE ~ Draw2d.IntegerBox; MarkType: TYPE ~ Draw2d.MarkType; PixelProc: TYPE ~ Draw2d.PixelProc; Zip: TYPE ~ Draw2d.Zip; ZipRep: TYPE ~ Draw2d.ZipRep; BoxFromContext: PUBLIC PROC [context: Imager.Context] RETURNS [IntegerBox] ~ { bounds: Imager.Rectangle ¬ ImagerBackdoor.GetBounds[context]; x: ImagerTransformation.Transformation ¬ ImagerBackdoor.GetTransformation[context, client, surface]; r: Imager.Rectangle ¬ ImagerTransformation.TransformRectangle[x, bounds]; ImagerTransformation.Destroy[x]; RETURN[[Real.Round[r.x], Real.Round[r.y], Real.Round[r.w], Real.Round[r.h]]]; }; ScreenScale: PUBLIC PROC [viewer: Viewer, aspectRatio: REAL ¬ 4.0/3.0] RETURNS [REAL] ~ { RETURN[MIN[viewer.cw, viewer.ch*aspectRatio]]; }; Clear: PUBLIC PROC [context: Context, color: Imager.Color ¬ Imager.white] ~ { old: Imager.Color ¬ ImagerBackdoor.GetColor[context ! Imager.Error => GOTO Bad]; Imager.SetColor[context, color]; Imager.MaskRectangle[context, ImagerBackdoor.GetBounds[context ! Imager.Error => GOTO Bad]]; Imager.SetColor[context, old]; EXITS Bad => NULL; }; Label: PUBLIC PROC [context: Context, position: VEC, rope: ROPE] ~ { IF rope = NIL THEN RETURN; AssureFont[context]; Imager.SetXY[context, position]; Imager.ShowRope[context, rope]; }; AssureFont: PUBLIC PROC [context: Context] ~ { font: Imager.Font ¬ NIL; font ¬ ImagerBackdoor.GetFont[context ! Imager.Error => CONTINUE]; IF font = NIL THEN Imager.SetFont[context, ImagerFont.Find["xerox/tiogafonts/helvetica10"]]; }; DoWithBuffer: PUBLIC PROC [context: Context, action: PROC, clear: BOOL ¬ TRUE] ~ { zip: Zip ¬ GetZip[context]; noRect: BOOL ¬ FALSE; rect: Imager.Rectangle; rect ¬ ImagerBackdoor.GetBounds[context ! Imager.Error => {noRect ¬ TRUE; CONTINUE}]; context.propList ¬ Prop.Put[context.propList, $Zip, zip]; IF noRect THEN action[] ELSE Imager.DoWithBuffer[context, action, 0, 0, Real.Round[rect.w], Real.Round[rect.h], IF clear THEN Imager.white ELSE NIL]; context.propList ¬ Prop.Rem[context.propList, $Zip]; ReleaseZip[zip]; }; IPOut: PUBLIC PROC [fileName: ROPE, drawProc: DrawProc, clientData: REF ANY ¬ NIL] ~ { IF fileName # NIL THEN { ref: ImagerInterpress.Ref ¬ ImagerInterpress.Create[fileName]; ContextProc: PROC [context: Context] ~ { Imager.ScaleT[context, Imager.metersPerPoint]; Imager.SetStrokeWidth[context, 1.0]; Imager.SetStrokeEnd[context, round]; AssureFont[context]; Imager.TranslateT[context, [0.0, 0.5*11.0*Imager.pointsPerInch]]; drawProc[context, clientData, $IPOut, NIL]; }; ImagerInterpress.DoPage[ref, ContextProc]; ImagerInterpress.Close[ref]; }; }; ContextOk: PROC [context: Context] RETURNS [BOOL] ~ INLINE { state: REF ¬ context.state; -- sidestep the Compiler WITH state SELECT FROM st: REF ImagerState.StateRep => IF st.rasterData = NIL THEN RETURN[FALSE]; ENDCASE => RETURN[FALSE]; RETURN[ImagerBackdoor.GetReal[context, strokeWidth ! Imager.Error => GOTO Bad] = 0]; EXITS Bad => RETURN[FALSE]; }; GetZip: PUBLIC PROC [context: Context, zip: Zip ¬ NIL] RETURNS [Zip] ~ { box: SF.Box; IF NOT ContextOk[context] THEN RETURN[NIL]; box ¬ ImagerRaster.GetClipper[context].clipBox; IF SF.Empty[box] THEN RETURN[NIL]; IF zip = NIL THEN zip ¬ NEW[ZipRep]; zip.box ¬ [[box.min.s+1, box.min.f+1], [box.max.s-1, box.max.f-1]]; zip.transform ¬ ImagerBackdoor.GetTransformation[context, client, device]; zip.rasterDevice ¬ ImagerRaster.GetDevice[context] # NIL; RETURN[zip]; }; ReleaseZip: PUBLIC PROC [zip: Zip] ~ { IF zip # NIL AND zip.transform # NIL THEN ImagerTransformation.Destroy[zip.transform]; }; Line: PUBLIC PROC [ context: Context, vec0, vec1: VEC, drawType: DrawType ¬ solid, zip: Zip ¬ NIL] ~ { IF zip = NIL THEN zip ¬ NARROW[Prop.Get[context.propList, $Zip]]; SELECT drawType FROM solid => Solid[context, vec0, vec1, zip]; dashed => Dash[context, vec0, vec1, zip]; dotted => Dot[context, vec0, vec1]; ENDCASE => NULL; }; DoWithLine: PUBLIC PROC [vec0, vec1: VEC, pixelProc: PixelProc] ~ { x0: INTEGER ¬ Real.Round[vec0.x]; y0: INTEGER ¬ Real.Round[vec0.y]; x1: INTEGER ¬ Real.Round[vec1.x]; y1: INTEGER ¬ Real.Round[vec1.y]; dyPos: BOOL ~ y1 > y0; dxPos: BOOL ~ x1 > x0; dy: INTEGER ¬ IF dyPos THEN y1-y0 ELSE y0-y1; dx: INTEGER ¬ IF dxPos THEN x1-x0 ELSE x0-x1; eincy: INTEGER ~ dy+dy; eincx: INTEGER ~ dx+dx; x, y, incx, incy: INTEGER; SELECT TRUE FROM dy = 0 => { IF NOT dxPos THEN {t: INTEGER ¬ x0; x0 ¬ x1; x1 ¬ t}; FOR x: INTEGER IN [x0..x1] DO IF NOT pixelProc[x, y0] THEN RETURN; ENDLOOP; }; dx = 0 => { IF NOT dyPos THEN {t: INTEGER ¬ y0; y0 ¬ y1; y1 ¬ t}; FOR y: INTEGER IN [y0..y1] DO IF NOT pixelProc[x0, y] THEN RETURN; ENDLOOP; }; dy > dx => { e: INTEGER ¬ eincx-dy; IF dyPos THEN {y ¬ y0; x ¬ x0; incx ¬ IF dxPos THEN 1 ELSE -1} ELSE {y ¬ y1; x ¬ x1; incx ¬ IF dxPos THEN -1 ELSE 1}; WHILE dy >= 0 DO IF NOT pixelProc[x, y] THEN RETURN; IF e > 0 THEN {x ¬ x+incx; e ¬ e-eincy}; e ¬ e+eincx; y ¬ y+1; dy ¬ dy-1; ENDLOOP; }; ENDCASE => { e: INTEGER ¬ eincy-dx; IF dxPos THEN {x ¬ x0; y ¬ y0; incy ¬ IF dyPos THEN 1 ELSE -1} ELSE {x ¬ x1; y ¬ y1; incy ¬ IF dyPos THEN -1 ELSE 1}; WHILE dx >= 0 DO IF NOT pixelProc[x, y] THEN RETURN; IF e > 0 THEN {y ¬ y+incy; e ¬ e-eincx}; e ¬ e+eincy; x ¬ x+1; dx ¬ dx-1; ENDLOOP; }; }; strokeWidth: REAL ¬ 1.0; -- hack because Imager is client unfriendly Dot: PROC [context: Context, vec0, vec1: VEC] ~ { stepInc: VEC; delta: VEC ¬ [vec1.x-vec0.x, vec1.y-vec0.y]; nSteps: INTEGER ¬ Real.Round[0.2*RealFns.SqRt[delta.x*delta.x+delta.y*delta.y]]; strokeWidth ¬ ImagerBackdoor.GetReal[context, strokeWidth ! Imager.Error => CONTINUE]; IF nSteps < 1 THEN RETURN; IF strokeWidth < 1.0 THEN strokeWidth ¬ 1.0; -- this new, needed in 1988; Imager change? stepInc ¬ [delta.x/nSteps, delta.y/nSteps]; FOR n: NAT IN [0..nSteps) DO Imager.MaskRectangle[context, [vec0.x, vec0.y, strokeWidth, strokeWidth]]; vec0 ¬ [vec0.x+stepInc.x, vec0.y+stepInc.y]; ENDLOOP; }; Dash: PROC [context: Context, vec0, vec1: VEC, zip: Zip] ~ { delta: VEC ¬ [vec1.x-vec0.x, vec1.y-vec0.y]; nSteps: INTEGER ¬ Real.Round[0.10*RealFns.SqRt[delta.x*delta.x+delta.y*delta.y]]; IF nSteps > 0 THEN { stepInc: VEC ¬ [delta.x/nSteps, delta.y/nSteps]; drawInc: VEC ¬ [0.5*stepInc.x, 0.5*stepInc.y]; FOR n: NAT IN[0..nSteps) DO Solid[context, vec0, [vec0.x+drawInc.x, vec0.y+drawInc.y], zip]; vec0 ¬ [vec0.x+stepInc.x, vec0.y+stepInc.y]; ENDLOOP; }; }; Solid: PROC [context: Context, vec0, vec1: VEC, zip: Zip ¬ NIL] ~ { Boxes: PROC [boxAction: SF.BoxAction] ~ {DoSolid[d0, d1, boxAction]}; Action: PROC [device: ImagerDevice.Device, clipper: ImagerDevice.DeviceClipper] ~ { ImagerDeviceWorks.MaskBoxes[device: device, bounds: box, boxes: Boxes]; }; d0, d1, min, max: VEC; box: SF.Box; transform: ImagerTransformation.Transformation; IF zip = NIL THEN { IF NOT ContextOk[context] OR ImagerRaster.GetDevice[context] = NIL THEN GOTO CantDo; box ¬ ImagerRaster.GetClipper[context].clipBox; transform ¬ ImagerBackdoor.GetTransformation[context, client, device]; IF SF.Empty[box] THEN RETURN; box.min.s ¬ box.min.s+1; -- simplify clipping box.min.f ¬ box.min.f+1; box.max.s ¬ box.max.s-1; box.max.f ¬ box.max.f-1; } ELSE { IF NOT zip.rasterDevice OR ImagerBackdoor.GetReal[context, strokeWidth ! Imager.Error => GOTO CantDo] # 0 THEN GOTO CantDo; box ¬ zip.box; transform ¬ zip.transform; }; d0 ¬ ImagerTransformation.Transform[transform, vec0]; d1 ¬ ImagerTransformation.Transform[transform, vec1]; d0.x ¬ d0.x-1; d1.x ¬ d1.x-1; IF d0.x < box.min.s THEN { IF d1.x < box.min.s THEN RETURN; d0.y ¬ d0.y+(box.min.s-d0.x)*(d1.y-d0.y)/(d1.x-d0.x); d0.x ¬ box.min.s; } ELSE IF d0.x > box.max.s THEN { IF d1.x > box.max.s THEN RETURN; d0.y ¬ d0.y+(box.max.s-d0.x)*(d1.y-d0.y)/(d1.x-d0.x); d0.x ¬ box.max.s; }; IF d1.x < box.min.s THEN { IF d0.x < box.min.s THEN RETURN; d1.y ¬ d1.y+(box.min.s-d1.x)*(d0.y-d1.y)/(d0.x-d1.x); d1.x ¬ box.min.s; } ELSE IF d1.x > box.max.s THEN { IF d0.x > box.max.s THEN RETURN; d1.y ¬ d1.y+(box.max.s-d1.x)*(d0.y-d1.y)/(d0.x-d1.x); d1.x ¬ box.max.s; }; IF d0.y < box.min.f THEN { IF d1.y < box.min.f THEN RETURN; d0.x ¬ d0.x+(box.min.f-d0.y)*(d1.x-d0.x)/(d1.y-d0.y); d0.y ¬ box.min.f; } ELSE IF d0.y > box.max.f THEN { IF d1.y > box.max.f THEN RETURN; d0.x ¬ d0.x+(box.max.f-d0.y)*(d1.x-d0.x)/(d1.y-d0.y); d0.y ¬ box.max.f; }; IF d1.y < box.min.f THEN { IF d0.y < box.min.f THEN RETURN; d1.x ¬ d1.x+(box.min.f-d1.y)*(d0.x-d1.x)/(d0.y-d1.y); d1.y ¬ box.min.f; } ELSE IF d1.y > box.max.f THEN { IF d0.y > box.max.f THEN RETURN; d1.x ¬ d1.x+(box.max.f-d1.y)*(d0.x-d1.x)/(d0.y-d1.y); d1.y ¬ box.max.f; }; min ¬ [MIN[d0.x, d1.x], MIN[d0.y, d1.y]]; max ¬ [MAX[d0.x, d1.x], MAX[d0.y, d1.y]]; box.min ¬ [Real.Floor[min.x]-1, Real.Floor[min.y]-1]; box.max ¬ [Real.Ceiling[max.x]+1, Real.Ceiling[max.y]+1]; ImagerRaster.DoWithDevice[context, box, Action]; IF zip = NIL THEN ImagerTransformation.Destroy[transform]; EXITS CantDo => Imager.MaskVector[context, vec0, vec1]; }; DoSolid: PROC [d0, d1: VEC, box: SF.BoxAction] ~ { -- Bresenham's method s0: INTEGER ¬ Real.Round[d0.x]; f0: INTEGER ¬ Real.Round[d0.y]; s1: INTEGER ~ Real.Round[d1.x]; f1: INTEGER ~ Real.Round[d1.y]; dsPos: BOOL ~ s1 > s0; dfPos: BOOL ~ f1 > f0; ds: INTEGER ¬ IF dsPos THEN s1-s0 ELSE s0-s1; df: INTEGER ¬ IF dfPos THEN f1-f0 ELSE f0-f1; eincs: INTEGER ~ ds+ds; eincf: INTEGER ~ df+df; len: INTEGER ¬ 0; s, f, incf, incs: INTEGER; SELECT TRUE FROM ds = 0 => { f ¬ IF dfPos THEN f0 ELSE f1; box[[[s0, f], [s0+1, f+df]]]; }; df = 0 => { s ¬ IF dsPos THEN s0 ELSE s1; box[[[s, f0], [s+ds, f0+1]]]; }; ds > df => { -- more vertical line e: INTEGER ¬ eincf-ds; IF dsPos THEN {s ¬ s0; f ¬ f0; incf ¬ IF dfPos THEN 1 ELSE -1} ELSE {s ¬ s1; f ¬ f1; incf ¬ IF dfPos THEN -1 ELSE 1}; WHILE ds >= 0 DO len ¬ len+1; IF e > 0 THEN { box[[[s, f], [s+len, f+1]]]; f ¬ f+incf; e ¬ e-eincs; s ¬ s+len; len ¬ 0; }; e ¬ e+eincf; ds ¬ ds-1; ENDLOOP; IF len > 0 THEN box[[[s, f], [s+len, f+1]]]; }; ENDCASE => { -- more horizontal line e: INTEGER ¬ eincs-df; IF dfPos THEN {f ¬ f0; s ¬ s0; incs ¬ IF dsPos THEN 1 ELSE -1} ELSE {f ¬ f1; s ¬ s1; incs ¬ IF dsPos THEN -1 ELSE 1}; WHILE df >= 0 DO len ¬ len+1; IF e > 0 THEN { box[[[s, f], [s+1, f+len]]]; s ¬ s+incs; e ¬ e-eincf; f ¬ f+len; len ¬ 0; }; e ¬ e+eincs; df ¬ df-1; ENDLOOP; IF len > 0 THEN box[[[s, f], [s+1, f+len]]]; }; }; Mark: PUBLIC PROC [ context: Context, position: VEC, markType: MarkType ¬ cross, zip: Zip ¬ NIL] ~ { Action: PROC ~ { X: PROC ~ { Solid[context, [position.x-4.0, position.y-4.0], [position.x+4.0, position.y+4.0], zip]; Solid[context, [position.x+4.0, position.y-4.0], [position.x-4.0, position.y+4.0], zip]; }; Cross: PROC ~ { Solid[context, [position.x-5.0, position.y], [position.x+5.0, position.y], zip]; Solid[context, [position.x, position.y-5.0], [position.x, position.y+5.0], zip]; }; SELECT markType FROM dot => Imager.MaskRectangle[context, [position.x, position.y, 1, 1]]; x => X[]; cross => Cross[]; asterisk => {Cross[]; X[]}; ENDCASE => NULL; }; Imager.DoSave[context, Action]; }; Square: PUBLIC PROC [context: Context, center: VEC, size: REAL] ~ { size2: REAL ¬ size+size; Imager.MaskRectangle[context, [center.x-size-1, center.y-size, size2, size2]]; }; Circle: PUBLIC PROC [context: Context, center: VEC, radius: REAL, fill: BOOL ¬ FALSE] ~ { t: Imager.Trajectory ¬ ImagerPath.MoveTo[[center.x+radius, center.y]]; t ¬ ImagerPath.ArcTo[t, [center.x-radius, center.y], [center.x+radius, center.y]]; IF fill THEN Imager.MaskFillTrajectory[context, t] ELSE Imager.MaskStrokeTrajectory[context, t, TRUE]; }; Arrow: PUBLIC PROC [ context: Context, tail, head: VEC, drawType: DrawType ¬ solid, vary: BOOL ¬ TRUE, zip: Zip ¬ NIL] ~ { v: VEC ¬ Vector2.Sub[head, tail]; mul: REAL ¬ IF v.x*v.x+v.y*v.y > 75.0*75.0 THEN -0.175*75.0/Vector2.Length[v] ELSE -0.175; vv: VEC ¬ Vector2.Mul[v, mul]; p0: VEC ¬ Vector2.Add[Vector2.Add[head, vv], [0.5*vv.y, -0.5*vv.x]]; p1: VEC ¬ Vector2.Add[p0, [-vv.y, vv.x]]; Line[context, head, tail, drawType, zip]; Line[context, head, p0, drawType, zip]; Line[context, head, p1, drawType, zip]; }; END. .. DoSolidSym: PROC [a1, b1, a2, b2: INTEGER, box: SF.BoxAction] ~ { -- Bresenham's ala Wyvill reverse: BOOL; incr1, incr2, d, x, y, xEnd, c, pixelsLeft, m1, m2, x1, y1, signX, signY, step, i: INTEGER; dx: INTEGER ¬ a2-a1; dy: INTEGER ¬ b2-b1; IF dx < 0 THEN {signX ¬ -1; dx ¬ -dx} ELSE signX ¬ 1; IF dy < 0 THEN {signY ¬ -1; dy ¬ -dy} ELSE signY ¬ 1; step ¬ IF signX = signY THEN 1 ELSE -1; -- decide increment sign by slope sign: IF dy > dx THEN { -- chooses axis of greatest movement (make dx) temp: INTEGER; temp ¬ a1; a1 ¬ b1; b1 ¬ temp; temp ¬ a2; a2 ¬ b2; b2 ¬ temp; temp ¬ dx; dx ¬ dy; dy ¬ temp; reverse ¬ TRUE; } ELSE reverse ¬ FALSE; IF a1 > a2 -- start from the smaller coordinate THEN {x ¬ a2; y ¬ b2; x1 ¬ a1; y1 ¬ b1} ELSE {x ¬ a1; y ¬ b1; x1 ¬ a2; y1 ¬ b2}; xEnd ¬ (dx-1)/4; pixelsLeft ¬ (dx-1) MOD 4; -- number of pixels left over at the end Plot[x, y, reverse]; Plot[x1, y1, reverse]; -- plot first two points incr2 ¬ 4*dy-2*dx; IF incr2 < 0 -- slope less than 1/2 THEN { c ¬ dy+dy; incr1 ¬ c+c; d ¬ incr1-dx; FOR i: INTEGER ¬ 0, i+1 WHILE i < xEnd DO -- plotting loop x ¬ x+1; x1 ¬ x1-1; IF d < 0 THEN { Plot[x, y, reverse]; x ¬ x+1; Plot[x, y, reverse]; -- pattern 1 forwards Plot[x1, y1, reverse]; x1 ¬ x1-1; Plot[x1, y1, reverse]; -- pattern 1 backwards d ¬ d+incr1; } ELSE { IF d < c THEN { Plot[x, y, reverse]; x ¬ x+1; y ¬ y+step; Plot[x, y, reverse]; -- pattern 2 forwards Plot[x1, y1, reverse]; x1 ¬ x1-1; y1 ¬ y1-step; Plot[x1, y1, reverse]; -- pattern 2 backwards } ELSE { y ¬ y+step; Plot[x, y, reverse]; x ¬ x+1; Plot[x, y, reverse]; -- pattern 3 forwards y1 ¬ y1-step; Plot[x1, y1, reverse]; x1 ¬ x1-1; Plot[x1, y1, reverse]; -- pattern 3 backwards }; d ¬ d+incr2; }; ENDLOOP; IF pixelsLeft THEN { IF d < 0 THEN { Plot[++x,y,reverse]; -- pattern 1 IF pixelsLeft > 1 THEN {x ¬ x+1; Plot[x, y, reverse]}; IF pixelsLeft > 2 THEN {x1 ¬ x1-1; Plot[x1, y1, reverse]}; } ELSE { IF d < c THEN { x ¬ x+1; Plot[x, y, reverse]; -- pattern 2 IF pixelsLeft > 1 THEN {x ¬ x+1; y ¬ y+step; Plot[x, y, reverse]}; IF pixelsLeft > 2 THEN {x1 ¬ x1-1; Plot[x1, y1, reverse]}; } ELSE { x ¬ x+1; y ¬ y+step; Plot[x, y, reverse]; -- pattern 3 IF pixelsLeft > 1 THEN {x ¬ x+1; Plot[x, y, reverse]}; IF pixelsLeft > 2 THEN {x1 ¬ x1-1; y1 ¬ y1-step Plot[x1, y1, reverse]}; } }; } } -- end slope < 1/2 ELSE { -- slope greater than 1/2 c ¬ 2*(dy-dx); incr1 ¬ c+c; d ¬ incr1+dx; FOR i: INTEGER ¬ 0, i+1 WHILE i < xEnd DO x ¬ x+1; x1 ¬ x1-1; IF d > 0 THEN { y ¬ y+step; Plot[x, y, reverse]; x ¬ x+1; y ¬ y+step; Plot[x, y, reverse]; -- pattern 4 forwards y1 ¬ y1-step; Plot[x1, y1, reverse]; x1 ¬ x1-1; y1 ¬ y1-step; Plot[x1, y1, reverse]; -- pattern 4 backwards d ¬ d+incr1; } ELSE { IF d < c THEN { Plot[x, y, reverse]; x ¬ x+1; y ¬ y+step; Plot[x, y, reverse]; -- pattern 2 forwards Plot[x1, y1, reverse]; x1 ¬ x1-1; y1 ¬ y1-step; Plot[x1, y1, reverse]; -- pattern 2 backwards } ELSE { y ¬ y+step; Plot[x, y, reverse]; x ¬ x+1; Plot[x, y, reverse]; -- pattern 3 forwards IF d = c THEN { -- plot step 2 backwards Plot[x1, y1, reverse]; x1 ¬ x1-1; y1 ¬ y1-step; Plot[x1, y1, reverse]; } ELSE { -- pattern 3 backwards y1 ¬ y1-step; Plot[x1, y1, reverse]; x1 ¬ x1-1; Plot[x1, y1, reverse]; -- pattern 3 backwards } } d ¬ d+incr2; } IF pixelsLeft # 0 THEN { IF d > 0 THEN { x ¬ x+1; y ¬ y+step; Plot[x, y, reverse]; -- pattern 4 IF pixelsLeft > 1 THEN {x ¬ x+1; y ¬ y+step; Plot[x ,y, reverse]}; IF pixelsLeft > 2 THEN {x1 ¬ x1-1; y1 ¬ y1-step; Plot[x1, y1, reverse]} } ELSE { x ¬ x+1; IF d < c THEN { Plot[x, y, reverse]; -- pattern 2 IF (pixelsLeft>1) THEN {x ¬ x+1; y ¬ y+step; Plot[x, y, reverse]; IF (pixelsLeft>2) THEN {x1 ¬ x1-1; Plot[x1, y1, reverse]}; } ELSE { y ¬ y+step; Plot[x, y, reverse]; -- pattern 3 IF pixelsLeft > 1 THEN {x ¬ x+1; Plot[x, y, reverse]}; IF pixelsLeft > 2 THEN { x1 ¬ x1-1; IF d > c THEN {y1 ¬ y1-step; Plot[x1, y1, reverse]}; -- step 3 ELSE Plot[x1, y1, reverse]; -- step 2 }; }; }; }; } } }; Draw2dImpl.mesa Copyright Σ 1985, 1989, 1992 by Xerox Corporation. All rights reserved. Pier, November 22, 1989 12:43:30 pm PST Bloomenthal, July 13, 1992 2:17 pm PDT Doug Wyatt, April 9, 1992 2:36 pm PDT Type Declarations General Utility Procedures Line Drawing Procedures Dealing with context.state is awkward, below, because Imager defines it as an opaque type. An alternative is to access context.state directly (see ImagerRasterImpl): State: TYPE ~ ImagerState.State; StateRep: PUBLIC TYPE ~ ImagerState.StateRep; -- export to Imager.StateRep IF context.state.rasterData . . . However, this would require Draw2dImpl to EXPORT ImagerState, which is undesirable. PatternProc: PROC [i: NAT] RETURNS [REAL] ~ {RETURN[2]}; dash: Imager.Trajectory _ ImagerPath.MoveTo[vec0]; dash _ ImagerPath.LineTo[dash, vec1]; Imager.MaskDashedStrokeTrajectory[context, dash, 2, PatternProc, 0, 20]; Clip: temp _ [[Real.Round[d0.x], Real.Round[d0.y]], [Real.Round[d1.x], Real.Round[d1.y]]]; box.min _ [MIN[temp.min.s, temp.max.s], MIN[temp.min.f, temp.max.f]]; box.max _ [MAX[temp.min.s, temp.max.s], MAX[temp.min.f, temp.max.f]]; ImagerRaster.MaskDeviceBoxes[context, box, Boxes]; Miscellaneous Procedures Should check for dx=0 here. Note dx=n implies 0-n or (dx+1) pixels to be set (!?) go round loop dx/4 times THEN plot last 0,1,2 or 3 pixels in fact (dx-1)/4 as 2 pixels are already plottted Fix for case where line exactly divides pixel: IdentityTransform: PROC [matrix: ImagerTransformation.Transformation] RETURNS [BOOL] ~ { RETURN[matrix.a = 1.0 AND matrix.e = 1.0 AND matrix.b = 0.0 AND matrix.c = 0.0 AND matrix.d = 0.0 AND matrix.f = 0.0]; }; Circle: PUBLIC PROC [context: Context, vec: VEC, radius: REAL, fill: BOOL _ FALSE] ~ { data: Data _ ContextOK[context]; IF data # NIL AND NOT fill THEN DoCircle[context, vec, radius, fill] ELSE { t: Imager.Trajectory _ ImagerPath.MoveTo[[vec.x+radius, vec.y]]; t _ ImagerPath.ArcTo[t, [vec.x, vec.y+radius], [vec.x-radius, vec.y]]; t _ ImagerPath.ArcTo[t, [vec.x, vec.y-radius], [vec.x+radius, vec.y]]; Imager.SetStrokeWidth[context, 1.15]; IF fill THEN Imager.MaskFillTrajectory[context, t] ELSE Imager.MaskStrokeTrajectory[context, t, TRUE]; }; }; DoCircle: PROC [context: Context, vec: VEC, radius: REAL, fill: BOOL] ~ { Imager.Trajectory is slightly faster for fill; this is about 1.7 faster for no fill. r: INTEGER _ Real.Round[radius]; xc: INTEGER _ Real.Round[vec.x]; yc: INTEGER _ Real.Round[vec.y]; x: INTEGER _ 0; y: INTEGER _ r; d: INTEGER _ 3-r-r; IF fill THEN WHILE x <= y DO xPlusX: INTEGER _ xc+x; xMinusX: INTEGER _ xc-x; xPlusY: INTEGER _ xc+y; xMinusY: INTEGER _ xc-y; yPlusX: INTEGER _ yc+x; yMinusX: INTEGER _ yc-x; yPlusY: INTEGER _ yc+y; yMinusY: INTEGER _ yc-y; Solid[context, [xMinusX, yPlusY], [xPlusX, yPlusY]]; Solid[context, [xMinusY, yPlusX], [xPlusY, yPlusX]]; Solid[context, [xMinusX, yMinusY], [xPlusX, yMinusY]]; Solid[context, [xMinusY, yMinusX], [xPlusY, yMinusX]]; The following produces somewhat diamond-shaped circles, why? IF d < 0 THEN d _ d+4*(x+6) ELSE { d _ d+4*(x-y)+10; y _ y-1; }; x _ x+1; ENDLOOP ELSE WHILE x <= y DO xPlusX: INTEGER _ xc+x; xMinusX: INTEGER _ xc-x; xPlusY: INTEGER _ xc+y; xMinusY: INTEGER _ xc-y; yPlusX: INTEGER _ yc+x; yMinusX: INTEGER _ yc-x; yPlusY: INTEGER _ yc+y; yMinusY: INTEGER _ yc-y; Imager.MaskRectangle[context, [xMinusX, yPlusY, 1, 1]]; Imager.MaskRectangle[context, [xPlusX, yPlusY, 1, 1]]; Imager.MaskRectangle[context, [xMinusY, yPlusX, 1, 1]]; Imager.MaskRectangle[context, [xPlusY, yPlusX, 1, 1]]; Imager.MaskRectangle[context, [xMinusX, yMinusY, 1, 1]]; Imager.MaskRectangle[context, [xPlusX, yMinusY, 1, 1]]; Imager.MaskRectangle[context, [xMinusY, yMinusX, 1, 1]]; Imager.MaskRectangle[context, [xPlusY, yMinusX, 1, 1]]; IF d < 0 THEN d _ d+4*(x+6) ELSE { d _ d+4*(x-y)+10; y _ y-1; }; x _ x+1; ENDLOOP; }; Κž•NewlineDelimiter –(cedarcode) style˜šœ™Jšœ Οeœ=™HJ™'J™&J™%J˜JšΟk œΈžœ˜άJ˜—šΠbl œžœž˜Jšžœžœ ˜‘Jšžœ˜J˜—Jšœž˜headšΟl™Jšžœžœžœ˜Jš žœžœ žœΟcΠcs‘’‘˜5Jšœ žœ˜ Jšœ žœ˜%J˜Jšœ žœ˜!Jšœ žœ˜!Jšœ žœ˜%Jšœ žœ˜!Jšœ žœ˜$Jšœžœ˜Jšœ žœ˜—š ™šΟnœžœžœžœ˜NJ˜=˜(J˜;—J˜IJ˜ JšžœG˜MJ˜J˜—š £ œžœžœžœ žœžœ˜YJšžœžœ$˜.J˜J˜—š£œžœžœ;˜MJšœFžœ˜PJšœ ˜ šœ@˜@Jšœžœ˜—Jšœ˜Jšžœžœ˜J˜J˜—š £œžœžœžœžœ˜DJšžœžœžœžœ˜Jšœ˜Jšœ ˜ Jšœ˜J˜J˜—š£ œž œ˜.Jšœžœ˜Jšœ8žœ˜BJšžœžœJ˜\J˜J˜—š £ œžœžœžœ žœžœ˜RJ˜Jšœžœžœ˜Jšœ˜JšœDžœžœ˜UJ˜9šžœ˜ Jšžœ ˜ Jš žœTžœžœžœžœ˜}—J˜4J˜J˜J˜—š£œžœžœ žœ"žœžœžœ˜Všžœ žœžœ˜J˜>š£ œžœ˜(Jšœ.˜.J˜$J˜$J˜JšœA˜AJšœ&žœ˜+Jšœ˜—Jšœ*˜*Jšœ˜J˜—J˜——š ™š £ œžœžœžœžœ˜žœ ˜NJšžœžœ˜——J˜J˜J˜——J˜5J˜5J˜J˜J™šžœžœ˜Jšžœžœžœ˜ J˜5J˜J˜—šžœžœžœ˜Jšžœžœžœ˜ J˜5J˜J˜—šžœžœ˜Jšžœžœžœ˜ J˜5J˜J˜—šžœžœžœ˜Jšžœžœžœ˜ J˜5J˜J˜—šžœžœ˜Jšžœžœžœ˜ J˜5J˜J˜—šžœžœžœ˜Jšžœžœžœ˜ J˜5J˜J˜—šžœžœ˜Jšžœžœžœ˜ J˜5J˜J˜—šžœžœžœ˜Jšžœžœžœ˜ J˜5J˜J˜—Jšœžœžœ˜)Jšœžœžœ˜)J˜5J˜9J™TJšœ žœžœ™EJšœ žœžœ™EJšœ2™2Jšœ ¦ œ˜0Jšžœžœžœ)˜:šž˜Jšœ1˜1—Jšœ˜J˜—š £œžœ žœžœ‘˜JJšœžœ˜Jšœžœ˜Jšœžœ˜Jšœžœ˜Jšœžœ ˜Jšœžœ ˜Jš œžœžœžœžœ˜-Jš œžœžœžœžœ˜-Jšœžœ ˜Jšœžœ ˜Jšœžœ˜Jšœžœ˜šžœžœž˜šœ ˜ Jšœžœžœžœ˜Jšœ˜Jšœ˜—šœ ˜ Jšœžœžœžœ˜Jšœ˜Jšœ˜—šœ‘˜#Jšœžœ ˜šžœ˜Jšžœžœžœžœ˜5Jšžœžœžœžœ˜7—šžœ ž˜J˜ šžœžœ˜Jšœ˜J˜ J˜ J˜ J˜Jšœ˜—J˜ J˜ Jšžœ˜—Jšžœ žœ˜,J˜—šžœ‘˜%Jšœžœ ˜šžœ˜Jšžœžœžœžœ˜5Jšžœžœžœžœ˜7—šžœ ž˜J˜ šžœžœ˜Jšœ˜J˜ J˜ J˜ J˜Jšœ˜—J˜ J˜ Jšžœ˜—Jšžœ žœ˜,J˜——Jšœ˜——š ™š£œžœžœ˜Jšœ˜Jšœ žœ˜J˜Jšœ žœ˜Jšœ˜š£œžœ˜š£œžœ˜ JšœX˜XJšœX˜XJ˜—š£œžœ˜JšœP˜PJšœP˜PJ˜—šžœ ž˜JšœE˜EJ˜ J˜J˜Jšžœžœ˜—J˜—J˜J˜J˜—š £œžœžœžœžœ˜CJšœžœ ˜JšœN˜NJ˜J˜—š £œž œžœ žœžœžœ˜YJ˜FJ˜Ršžœ˜Jšžœ'˜+Jšžœ)žœ˜3—J˜J˜—š£œž œ˜Jšœ˜Jšœ žœ˜J˜Jšœžœžœ˜Jšœ žœ˜J˜Jšœžœ˜!Jš œžœžœžœžœ˜ZJšœžœ˜Jšœžœ=˜DJšœžœ"˜)Jšœ)˜)Jšœ'˜'Jšœ'˜'J˜—J˜—Jšžœ˜J˜˜š £ œžœžœžœ‘˜[Jšœ žœ˜JšœSžœ˜[Jšœžœ ˜Jšœžœ ˜Jšžœžœžœ ˜5Jšžœžœžœ ˜5Jšœžœžœžœ‘'˜Ošžœ˜ šžœ‘.˜6Jšœžœ˜J˜J˜J˜Jšœ žœ˜Jšœ˜—Jšžœ žœ˜—Jšœ™šžœ‘$˜8Jšžœ#˜'Jšžœ%˜)—šœ5™5Jšœžœ™9Jšœ1™1—J˜Jšœžœ‘(˜DJšœ˜Jšœ‘˜0J˜šžœ‘˜&šžœ˜ J˜ J˜ J˜ š žœžœ žœ žœ‘˜;J˜J˜ šžœ˜šžœ˜Jšœ˜J˜Jšœ‘˜+Jšœ˜J˜ Jšœ‘˜-J˜ Jšœ˜—šžœ˜šžœ˜šžœ˜Jšœ˜J˜J˜ Jšœ‘˜+Jšœ˜J˜ J˜ Jšœ‘˜-Jšœ˜—šžœ˜J˜ Jšœ˜J˜Jšœ‘˜+J˜ Jšœ˜J˜ Jšœ‘˜.Jšœ˜——J˜ Jšœ˜——Jšžœ˜—šžœ žœ˜šžœ˜šžœ˜Jšœ‘ ˜!Jšžœžœ ˜6Jšžœžœ$˜:Jšœ˜—šžœ˜šžœ˜šžœ˜J˜Jšœ‘ ˜#Jšžœžœ,˜BJšžœžœ$˜:Jšœ˜—šžœ˜J˜J˜ Jšœ‘ ˜!Jšžœžœ!˜7Jšžœžœ2˜HJšœ˜——Jšœ˜——Jšœ˜—Jšœ‘˜—šžœ‘˜#J˜J˜ J˜ šžœžœ žœ ž˜)J˜šžœ˜šžœ˜J˜ Jšœ˜J˜Jšœ‘˜+J˜ Jšœ˜J˜Jšœ‘˜.J˜ Jšœ˜——šžœ˜šžœ˜šžœ˜Jšœ˜J˜Jšœ‘˜+Jšœ˜J˜Jšœ‘˜-Jšœ˜—šžœ˜J˜ Jšœ˜J˜Jšœ‘˜+Jšœ‘-™.šžœžœ‘˜)Jšœ˜J˜Jšœ˜Jšœ˜———šžœ‘˜J˜ Jšœ˜J˜ Jšœ‘˜.Jšœ˜——Jšœ˜J˜ Jšœ˜šžœžœ˜šžœ˜šžœ˜J˜Jšœ‘ ˜!Jšžœžœ,˜BJšžœžœ1˜GJšœ˜—šžœ˜J˜šžœ˜šžœ˜Jšœ‘ ˜"Jšžœžœ+˜AJšžœžœ$˜:Jšœ˜—šžœ˜J˜ Jšœ‘ ˜!Jšžœžœ!˜7šžœžœ˜J˜ šžœ˜Jšžœ(‘ ˜5Jšžœ‘ ˜%—Jšœ˜—Jšœ˜——Jšœ˜—Jšœ˜——Jšœ˜—Jšœ˜—Jšœ˜—J˜—š£œžœ/žœžœ™Xšžœžœ™(Jšžœžœžœžœ™M—J™J™—š £œž œžœ žœžœžœ™VJšœ žœ™ šžœžœžœžœ™Jšžœ%™)šžœ™J™@J™FJ™FJšœ%™%Jšžœžœ'™3Jšžœ)žœ™3J™——J™J™—š £œžœžœ žœžœ™IJ™TJšœžœ™ Jšœžœ™ Jšœžœ™ Jšœžœ™Jšœžœ™Jšœžœ ™J™šžœ™šžœžœž™Jšœžœ™Jšœžœ™Jšœžœ™Jšœžœ™Jšœžœ™Jšœžœ™Jšœžœ™Jšœžœ™J™6J™6J™7J™7Jš¦<™<šžœ™Jšžœ™šžœ™J™J™J™——J™Jšž™—šžœžœž™Jšœžœ™Jšœžœ™Jšœžœ™Jšœžœ™Jšœžœ™Jšœžœ™Jšœžœ™Jšœžœ™J™7J™6J™7J™6J™8J™7J™8J™7šžœ™Jšžœ™šžœ™J™J™J™——J™Jšžœ™——J™J™——J˜—…—@Κhv