Draw2dImpl.mesa
Copyright © 1985 by Xerox Corporation. All rights reserved.
Bloomenthal, June 9, 1986 5:23:16 pm PDT
DIRECTORY Draw2d, Imager, ImagerBackdoor, ImagerDevice, ImagerFont, ImagerOps, ImagerRasterPrivate, ImagerState, ImagerTransformation, IO, Real, Rope, Vector2;
Draw2dImpl: CEDAR PROGRAM
IMPORTS Imager, ImagerFont, ImagerOps, ImagerRasterPrivate, ImagerTransformation, Real, Vector2
EXPORTS Draw2d, Imager
~ BEGIN
VEC:   TYPE ~ Vector2.VEC;
MarkType: TYPE ~ Draw2d.MarkType;
DrawType: TYPE ~ Draw2d.DrawType;
InitFont: PUBLIC PROC [context: Imager.Context] ~ {
font: ImagerFont.Font ← ImagerFont.Scale[ImagerFont.Find["xerox/pressfonts/helvetica-mrr"], 12.0];
Imager.SetFont[context, font];
};
Label: PUBLIC PROC [context: Imager.Context, p: VEC, rope: Rope.ROPE] ~ {
Imager.SetXY[context, p];
Imager.ShowRope[context, rope];
};
DoWithBuffer: PUBLIC PROC [context: Imager.Context, action: PROC, w, h: INTEGER] ~ {
InitFont[context];
Imager.SetStrokeWidth[context, 0.0];
ImagerOps.DoWithBuffer[context, action, 0, 0, w, h];
};
once: BOOLFALSE;
pixelBuffer: Pixels.PixelBuffer;
DoNoBuffer: PUBLIC PROC [context: Imager.Context, action: PROC, w, h: INTEGER] ~ {
InitFont[context];
IF NOT once THEN {
once ← TRUE;
[pixelBuffer, ] ← Pixels.GetFromImagerContext[context, FALSE, FALSE];
Imager.PutProp[context, $PixelBuffer, NEW[Pixels.PixelBuffer ← pixelBuffer]];
};
action[];
};
ShowList: PUBLIC PROC [list: LIST OF VEC, context: Imager.Context] ~ {
p0: VEC;
IF list # NIL THEN p0 ← list.first ELSE RETURN;
FOR l: LIST OF VEC ← list.rest, l.rest WHILE l # NIL DO
Solid[context, p0, l.first];
p0 ← l.first;
ENDLOOP;
};
ClearContext: PUBLIC PROC [context: Imager.Context, x, y, w, h: INTEGER] ~ {
Imager.SetColor[context, Imager.white];
Imager.MaskRectangleI[context, 0, 0, w, h];
Imager.SetColor[context, Imager.black];
};
Mark: PUBLIC PROC [context: Imager.Context, p: VEC, type: MarkType ← cross] ~ {
Action: PROC ~ {
Dot: PROC ~ {Imager.MaskRectangle[context, [p.x-1, p.y-1, 3, 3]]};
X: PROC ~ {
Solid[context, [p.x-4.0, p.y-4.0], [p.x+4.0, p.y+4.0]];
Solid[context, [p.x+4.0, p.y-4.0], [p.x-4.0, p.y+4.0]];
};
Cross: PROC ~ {
Solid[context, [p.x-5.0, p.y], [p.x+5.0, p.y]];
Solid[context, [p.x, p.y-5.0], [p.x, p.y+5.0]];
};
IF invert THEN Imager.SetColor[context, ImagerBackdoor.invert];
SELECT type FROM
dot => Dot[];
x => X[];
cross => Cross[];
asterisk => {Cross[]; X[];};
ENDCASE => NULL;
};
Imager.DoSave[context, Action];
};
Draw: PUBLIC PROC [context: Imager.Context, p0, p1: VEC, type: DrawType ← solid] ~ {
SELECT type FROM
solid => Solid[context, p0, p1];
dot => Dot[context, p0, p1];
dash => Dash[context, p0, p1];
ENDCASE => NULL;
};
Data:  TYPE ~ ImagerRasterPrivate.Data;
State:  TYPE ~ ImagerState.State;
StateRep: PUBLIC TYPE ~ ImagerState.StateRep;       -- export to Imager.StateRep
Solid: PUBLIC PROC [context: Imager.Context, p0, p1: VEC] ~ {  -- Crow's method
pixelValue: Pixels.SampleSet ← Pixels.GetSampleSet[1];
-- pixelBuffer ← NARROW[Imager.GetProp[context, $PixelBuffer], REF Pixels.PixelBuffer]^;
pixelValue[0] ← 255;
ScanConvert.PutLine[pixelBuffer, [Real.FixC[p0.x], Real.FixC[p0.y]], [Real.FixC[p1.x], Real.FixC[p1.y]], pixelValue];
};
Solid: PUBLIC PROC [context: Imager.Context, p0, p1: VEC] ~ {  -- Bresenham's method
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;
bounds: ImagerDevice.DeviceBox ← data.clientClipBox;
IF bounds.smin = bounds.smax OR bounds.fmin = bounds.fmax THEN RETURN;
bounds.smax ← MAX[bounds.smin, bounds.smax-1];    -- simplify clipping
bounds.fmax ← MAX[bounds.fmin, bounds.fmax-1];
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 {
d0: VEC ← ImagerTransformation.Transform[data.clientToDevice, p0];
d1: VEC ← ImagerTransformation.Transform[data.clientToDevice, p1];
Boxes: PROC [box: ImagerDevice.BoxProc] ~ {
DoSolid[d0, d1, data.clientClipBox, box];
};
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];
RETURN;
};
};
ENDCASE => NULL;
Imager.MaskVector[context, p0, p1];
};
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: INTEGERIF dsPos THEN s1-s0 ELSE s0-s1;
df: INTEGERIF dfPos THEN f1-f0 ELSE f0-f1;
eincs: INTEGER ~ ds+ds;
eincf: INTEGER ~ df+df;
len: INTEGER ← 0;
s, f, incf, incs: INTEGER;
IF ds = 0 THEN {
f ← IF dfPos THEN f0 ELSE f1;
box[[smin: s0, fmin: f, smax: s0+1, fmax: f+df]];
RETURN;
};
IF df = 0 THEN {
s ← IF dsPos THEN s0 ELSE s1;
box[[smin: s, fmin: f0, smax: s+ds, fmax: f0+1]];
RETURN;
};
IF ds > df
THEN {
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]];
}
ELSE {
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]];
};
};
Dot: PUBLIC PROC [context: Imager.Context, p0, p1: VEC] ~ {
stepInc: VEC;
delta: VEC ← [p1.x-p0.x, p1.y-p0.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, [p0.x, p0.y, 1, 1]];
p0 ← [p0.x+stepInc.x, p0.y+stepInc.y];
ENDLOOP;
};
Dash: PUBLIC PROC [context: Imager.Context, p0, p1: VEC] ~ {
drawInc, stepInc: VEC;
delta: VEC ← [p1.x-p0.x, p1.y-p0.y];
nSteps: INTEGER ← Real.RoundI[0.10*Real.SqRt[delta.x*delta.x+delta.y*delta.y]];
IF nSteps < 1 THEN RETURN;
stepInc ← [delta.x/nSteps, delta.y/nSteps];
drawInc ← [0.5*stepInc.x, 0.5*stepInc.y];
FOR n: NAT IN[0..nSteps) DO
Solid[context, p0, [p0.x+drawInc.x, p0.y+drawInc.y]];
p0 ← [p0.x+stepInc.x, p0.y+stepInc.y];
ENDLOOP;
};
Arrow: PUBLIC PROC [context: Imager.Context, head, tail: VEC] ~ {
v: VEC ← Vector2.Mul[Vector2.Sub[head, tail], -0.175];
p0: VEC ← Vector2.Add[Vector2.Add[head, v], [0.5*v.y, -0.5*v.x]];
p1: VEC ← Vector2.Add[p0, [-v.y, v.x]];
Solid[context, head, tail];
Solid[context, head, p0];
Solid[context, head, p1];
};
Square: PUBLIC PROC [context: Imager.Context, x, y, size: REAL] ~ {
Imager.MaskRectangle[context, [x-size-1, y-size, 2*size, 2*size]];
};
debugStream: IO.STREAMNIL;
Debug: PUBLIC PROC [s: IO.STREAM] ~ {debugStream ← s};
END.