DIRECTORY Draw2d, Imager, ImagerBackdoor, ImagerDevice, ImagerFont, ImagerPath, ImagerOps, ImagerRasterPrivate, ImagerState, ImagerTransformation, IO, Real, Rope, Vector2; Draw2dImpl: CEDAR PROGRAM IMPORTS Imager, ImagerBackdoor, ImagerFont, ImagerOps, ImagerPath, ImagerRasterPrivate, ImagerTransformation, Real, Vector2 EXPORTS Draw2d, Imager ~ BEGIN ROPE: TYPE ~ Rope.ROPE; Context: TYPE ~ Imager.Context; VEC: TYPE ~ Imager.VEC; -- RECORD [x, y: REAL] DrawType: TYPE ~ Draw2d.DrawType; MarkType: TYPE ~ Draw2d.MarkType; PixelProc: TYPE ~ Draw2d.PixelProc; Clear: PUBLIC PROC [context: Context] ~ { Imager.SetColor[context, Imager.white]; Imager.MaskRectangle[context, ImagerBackdoor.GetBounds[context]]; Imager.SetColor[context, Imager.black]; }; Label: PUBLIC PROC [context: Context, vec: VEC, rope: ROPE] ~ { font: Imager.Font _ NIL; font _ ImagerBackdoor.GetFont[context ! Imager.Error => CONTINUE]; IF font = NIL THEN Imager.SetFont[context, ImagerFont.Find["xerox/tiogafonts/helvetica10"]]; Imager.SetXY[context, vec]; Imager.ShowRope[context, rope]; }; DoWithBuffer: PUBLIC PROC [context: Context, action: PROC, clear: BOOL _ TRUE] ~ { rect: Imager.Rectangle _ ImagerBackdoor.GetBounds[context]; color: Imager.Color _ IF clear THEN Imager.white ELSE NIL; Imager.SetStrokeWidth[context, 0.0]; ImagerOps.DoWithBuffer[context, action, 0, 0, Real.RoundI[rect.w], Real.RoundI[rect.h], color]; }; Line: PUBLIC PROC [context: Context, vec0, vec1: VEC, drawType: DrawType _ solid] ~ { SELECT drawType FROM solid => Solid[context, vec0, vec1]; dotted => Dot[context, vec0, vec1]; dashed => Dash[context, vec0, vec1]; ENDCASE => NULL; }; DoWithLine: PUBLIC PROC [vec0, vec1: VEC, pixelProc: PixelProc] ~ { x0: INTEGER _ Real.RoundI[vec0.x]; y0: INTEGER _ Real.RoundI[vec0.y]; x1: INTEGER _ Real.RoundI[vec1.x]; y1: INTEGER _ Real.RoundI[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; }; }; Dot: PROC [context: Context, vec0, vec1: VEC] ~ { stepInc: VEC; delta: VEC _ [vec1.x-vec0.x, vec1.y-vec0.y]; nSteps: INTEGER _ Real.RoundI[0.2*Real.SqRt[delta.x*delta.x+delta.y*delta.y]]; IF nSteps < 1 THEN RETURN; stepInc _ [delta.x/nSteps, delta.y/nSteps]; FOR n: NAT IN [0..nSteps) DO Imager.MaskRectangle[context, [vec0.x, vec0.y, 1, 1]]; vec0 _ [vec0.x+stepInc.x, vec0.y+stepInc.y]; ENDLOOP; }; Dash: PROC [context: Context, vec0, vec1: VEC] ~ { delta: VEC _ [vec1.x-vec0.x, vec1.y-vec0.y]; nSteps: INTEGER _ Real.RoundI[0.10*Real.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]]; vec0 _ [vec0.x+stepInc.x, vec0.y+stepInc.y]; ENDLOOP; }; }; Data: TYPE ~ ImagerRasterPrivate.Data; State: TYPE ~ ImagerState.State; StateRep: PUBLIC TYPE ~ ImagerState.StateRep; -- export to Imager.StateRep ContextOK: PROC [context: Context] RETURNS [Data] ~ { state: State ~ context.state; needs: ImagerRasterPrivate.Flags ~ [clientToDevice: TRUE, clientClipper: TRUE, deviceColor: TRUE, devicePriority: TRUE]; WITH context.data SELECT FROM data: Data => { device: ImagerDevice.Device ~ data.device; IF state.changed # ImagerState.notChanged THEN ImagerRasterPrivate.NoteStateChanges[data, state]; IF ImagerRasterPrivate.AndFlags[data.valid, needs] # needs THEN ImagerRasterPrivate.ValidateIfNeeded[data, state, needs]; IF state.np.strokeWidth = 0 AND data.clientClipBoxOnly AND device.class.MaskBoxes#NIL THEN RETURN[data]; }; ENDCASE => NULL; RETURN[NIL]; }; Solid: PROC [context: Context, vec0, vec1: VEC] ~ { -- Bresenham's method data: Data _ ContextOK[context]; IF data # NIL THEN { Boxes: PROC [box: ImagerDevice.BoxProc] ~ { DoSolid[d0, d1, data.clientClipBox, box]; }; device: ImagerDevice.Device ~ data.device; bounds: ImagerDevice.DeviceBox _ data.clientClipBox; d0: VEC _ ImagerTransformation.Transform[data.clientToDevice, vec0]; d1: VEC _ ImagerTransformation.Transform[data.clientToDevice, vec1]; IF bounds.smin = bounds.smax OR bounds.fmin = bounds.fmax THEN RETURN; bounds.smin _ bounds.smin+1; -- simplify clipping bounds.fmin _ bounds.fmin+1; bounds.smax _ bounds.smax-1; bounds.fmax _ bounds.fmax-1; IF d0.x < bounds.smin THEN { IF d1.x < bounds.smin THEN RETURN; d0.y _ d0.y+(bounds.smin-d0.x)*(d1.y-d0.y)/(d1.x-d0.x); d0.x _ bounds.smin; } ELSE IF d0.x > bounds.smax THEN { IF d1.x > bounds.smax THEN RETURN; d0.y _ d0.y+(bounds.smax-d0.x)*(d1.y-d0.y)/(d1.x-d0.x); d0.x _ bounds.smax; }; IF d1.x < bounds.smin THEN { IF d0.x < bounds.smin THEN RETURN; d1.y _ d1.y+(bounds.smin-d1.x)*(d0.y-d1.y)/(d0.x-d1.x); d1.x _ bounds.smin; } ELSE IF d1.x > bounds.smax THEN { IF d0.x > bounds.smax THEN RETURN; d1.y _ d1.y+(bounds.smax-d1.x)*(d0.y-d1.y)/(d0.x-d1.x); d1.x _ bounds.smax; }; IF d0.y < bounds.fmin THEN { IF d1.y < bounds.fmin THEN RETURN; d0.x _ d0.x+(bounds.fmin-d0.y)*(d1.x-d0.x)/(d1.y-d0.y); d0.y _ bounds.fmin; } ELSE IF d0.y > bounds.fmax THEN { IF d1.y > bounds.fmax THEN RETURN; d0.x _ d0.x+(bounds.fmax-d0.y)*(d1.x-d0.x)/(d1.y-d0.y); d0.y _ bounds.fmax; }; IF d1.y < bounds.fmin THEN { IF d0.y < bounds.fmin THEN RETURN; d1.x _ d1.x+(bounds.fmin-d1.y)*(d0.x-d1.x)/(d0.y-d1.y); d1.y _ bounds.fmin; } ELSE IF d1.y > bounds.fmax THEN { IF d0.y > bounds.fmax THEN RETURN; d1.x _ d1.x+(bounds.fmax-d1.y)*(d0.x-d1.x)/(d0.y-d1.y); d1.y _ bounds.fmax; }; device.class.MaskBoxes[device: device, bounds: bounds, boxes: Boxes]; } ELSE Imager.MaskVector[context, vec0, vec1]; }; DoSolid: PROC [d0, d1: VEC, clip: ImagerDevice.DeviceBox, box: ImagerDevice.BoxProc] ~ { s0: INTEGER _ Real.RoundI[d0.x]; f0: INTEGER _ Real.RoundI[d0.y]; s1: INTEGER ~ Real.RoundI[d1.x]; f1: INTEGER ~ Real.RoundI[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[[smin: s0, fmin: f, smax: s0+1, fmax: f+df]]; }; df = 0 => { s _ IF dsPos THEN s0 ELSE s1; box[[smin: s, fmin: f0, smax: s+ds, fmax: f0+1]]; }; ds > df => { 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[[smin: s, fmin: f, smax: s+len, fmax: 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[[smin: s, fmin: f, smax: s+len, fmax: f+1]]; }; ENDCASE => { 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[[smin: s, fmin: f, smax: s+1, fmax: 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[[smin: s, fmin: f, smax: s+1, fmax: f+len]]; }; }; Mark: PUBLIC PROC [context: Context, vec: VEC, markType: MarkType _ cross] ~ { Action: PROC ~ { Dot: PROC ~ {Imager.MaskRectangle[context, [vec.x-1, vec.y-1, 3, 3]]}; X: PROC ~ { Solid[context, [vec.x-4.0, vec.y-4.0], [vec.x+4.0, vec.y+4.0]]; Solid[context, [vec.x+4.0, vec.y-4.0], [vec.x-4.0, vec.y+4.0]]; }; Cross: PROC ~ { Solid[context, [vec.x-5.0, vec.y], [vec.x+5.0, vec.y]]; Solid[context, [vec.x, vec.y-5.0], [vec.x, vec.y+5.0]]; }; SELECT markType FROM dot => Dot[]; x => X[]; cross => Cross[]; asterisk => {Cross[]; X[];}; ENDCASE => NULL; }; Imager.DoSave[context, Action]; }; Square: PUBLIC PROC [context: Context, vec: VEC, size: REAL] ~ { size2: REAL _ size+size; Imager.MaskRectangle[context, [vec.x-size-1, vec.y-size, size2, size2]]; }; Circle: PUBLIC PROC [context: Context, vec: VEC, radius: REAL, fill: BOOL _ FALSE] ~ { 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]; }; Arrow: PUBLIC PROC [ context: Context, tail, head: VEC, drawType: DrawType _ solid, vary: BOOL _ TRUE] ~ { 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]; Line[context, head, p0, drawType]; Line[context, head, p1, drawType]; }; END. .. LDraw2dImpl.mesa Copyright c 1985 by Xerox Corporation. All rights reserved. Bloomenthal, October 21, 1986 1:21:46 pm PDT Type Declarations General Procedures Line Drawing Procedures Miscellaneous Procedures 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.RoundI[radius]; xc: INTEGER _ Real.RoundI[vec.x]; yc: INTEGER _ Real.RoundI[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; }; Κ8˜šœ™Jšœ Οmœ1™˜XJšœžœ˜ Jšœžœ˜ Jšœžœ˜ Jšœžœ˜ Jšœžœ ˜Jšœžœ ˜Jš œžœžœžœžœ˜-Jš œžœžœžœžœ˜-Jšœžœ ˜Jšœžœ ˜Jšœžœ˜Jšœžœ˜J˜šžœžœž˜šœ ˜ Jšœžœžœžœ˜Jšœ1˜1Jšœ˜—šœ ˜ Jšœžœžœžœ˜Jšœ1˜1Jšœ˜—šœ ˜ Jšœžœ ˜šžœ˜Jšžœžœžœžœ˜5Jšžœžœžœžœ˜7—šžœ ž˜J˜ šžœžœ˜Jšœ0˜0Jšœ ˜ Jšœ ˜ Jšœ ˜ J˜Jšœ˜—Jšœ ˜ J˜ Jšžœ˜—Jšžœ žœ1˜@J˜—šžœ˜ Jšœžœ ˜šžœ˜Jšžœžœžœžœ˜5Jšžœžœžœžœ˜7—šžœ ž˜J˜ šžœžœ˜Jšœ0˜0Jšœ ˜ Jšœ ˜ Jšœ ˜ Jšœ˜Jšœ˜—Jšœ ˜ J˜ Jšžœ˜—Jšžœ žœ1˜@J˜——Jšœ˜——š ™š£œžœžœžœ!˜Nš£œžœ˜Jš£œžœ=˜Fš£œžœ˜ Jšœ?˜?Jšœ?˜?J˜—š£œžœ˜Jšœ7˜7Jšœ7˜7J˜—šžœ ž˜J˜ J˜ J˜J˜Jšžœžœ˜—J˜—J˜J˜J˜—š £œžœžœžœžœ˜@Jšœžœ ˜JšœH˜HJ˜J˜—š £œž œžœ žœžœžœ˜VJ˜@J˜FJ˜FJšœ%˜%Jšžœžœ'˜3Jšžœ)žœ˜3J˜J˜—J˜š£œž œ˜Jšœ˜Jšœ žœ˜Jšœ˜Jšœžœžœ˜J˜Jšœžœ˜!Jš œžœžœžœžœ˜ZJšœžœ˜Jšœžœ=˜DJšœžœ"˜)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™———…—&?Œ