<> <> <> <> <> 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 }; }; }; }; } } }; <> <> <> <<};>> <<>> <> <> <> <> <> <> <> <> <> <> <> <<};>> <<};>> <<>> <> <> <> <> <> <> <> <> <<>> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <<};>> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <<};>> <> <> <<};>> <<>>