ImagerMaskImpl.mesa
Last Edited by: Crow, May 31, 1983 3:20 pm
DIRECTORY
Environment   USING [LongNumber],
Inline     USING [BITOR, BITAND, HighHalf],
ImagerBasic   USING [Context, Path, IntVec, IntRectangle, PixelArray, ClipperRecord,
        TransformRecord],
ImagerTransform USING [IntTransform],
Imager;
ImagerMaskImpl: CEDAR PROGRAM
IMPORTS ImagerTransform, Inline
EXPORTS Imager
= BEGIN OPEN ImagerBasic;
Client-called Procedures
MaskStroke: PUBLIC PROC [context: Context, path: Path] = {};
Form a stencil of "width" thickness around a spine defined by "path".
Connected path segments will be mitered together. If the first and last points of a trajectory coincide, the path will be closed and mitered.
MaskFill: PUBLIC PROC [context: Context, path: Path] = {};
Use the path to outline an area to be filled with the source
MaskPixel: PUBLIC PROC [context: Context, pixelArray: PixelArray] = {};
Use the supplied pixel array as the stencil. The origin of the pixel array will be placed at the origin of the client space. The samples will be assumed to be placed at one unit intervals in the client space.
Fast Track. The width of lines, etc. is device dependent, approximately .1% page height.
MoveTo: implemented in Imager.mesa
DrawTo: PUBLIC PROC [context: Context, p: IntVec] = {
Draw line using source for color
q: IntVec ← p;        -- hold onto untransformed point
p ← ImagerTransform.IntTransform[context.transform, p];
IF context.noClip
THEN { OPEN context;
  deviceProcs.drawLine[currentIntPosition, p, currentSource.pxlValue]; }
ELSE IF context.clipper.type = rectangle
THEN { in: BOOLEAN; a, b: IntVec;
[in, a, b] ← ClipEdgeByRectangle[context.clipper, context.currentIntPosition, p];
IF in THEN context.deviceProcs.drawLine[a, b, context.currentSource.pxlValue];
}
ELSEERROR;      -- until paths are worked out - M. Plass?
context.currentIntPosition ← p;
};
DrawPath: PUBLIC PROC [context: Context, path: Path] = {
Draw whole path using source for color
};
FillRectangle: PUBLIC PROC [context: Context, area: IntRectangle] = {
Fill rectangular area with source
};
Unpublicized Procedures
Internal Procedures
ClipEdgeByRectangle: PROC [clipper: ClipperRecord, a, b: IntVec]
        RETURNS [BOOLEAN, IntVec, IntVec] = {
Out: TYPE = RECORD[bottom, top, left, right: BOOLEAN];
noneOut: Out = [FALSE, FALSE, FALSE, FALSE];
Code: PROC [x, y: INTEGER] RETURNS [Out] = INLINE {
OPEN clipper;
out: Out ← noneOut;
IF x < xMin THEN out.left ← TRUE;  IF x > xMax THEN out.right ← TRUE;
IF y > yMax THEN out.top ← TRUE;  IF y < yMin THEN out.bottom ← TRUE;
RETURN [ out ];
};
ClipY: PROC [a, b: IntVec, xPos: INTEGER] RETURNS [INTEGER] = INLINE {
t: Environment.LongNumber;
t.high ← LOOPHOLE[xPos - a.x];  t.low ← LOOPHOLE[0];
RETURN[ a.y + LOOPHOLE[
Inline.HighHalf[ LOOPHOLE[t, LONG INTEGER] / (b.x - a.x) * (b.y - a.y)], INTEGER] ];
};
ClipX: PROC [a, b: IntVec, yPos: INTEGER] RETURNS [INTEGER] = INLINE {
t: Environment.LongNumber;
t.high ← LOOPHOLE[yPos - a.y];  t.low ← LOOPHOLE[0];
RETURN[ a.x + LOOPHOLE[
Inline.HighHalf[ LOOPHOLE[t, LONG INTEGER] / (b.y - a.y) * (b.x - a.x)], INTEGER] ];
};
aCode, bCode, out: Out;
c: IntVec;
WHILE TRUE DO
aCode ← Code[a.x, a.y];  bCode ← Code[b.x, b.y];
Trivial acceptance test
IF Inline.BITOR[LOOPHOLE[aCode], LOOPHOLE[bCode]] = LOOPHOLE[0]
THEN RETURN[TRUE, a, b];
Trivial rejection test
IF Inline.BITAND[LOOPHOLE[aCode], LOOPHOLE[bCode]] # LOOPHOLE[0]
THEN RETURN[ FALSE, a, b];
Actual clipping necessary
out ← IF aCode # noneOut THEN aCode ELSE bCode;
SELECT TRUE FROM
out.left => { c.x ← clipper.xMin;
     c.y ← ClipY[a, b, clipper.xMin]; };
out.right => {  c.x ← clipper.xMax;
     c.y ← ClipY[a, b, clipper.xMax]; };
out.bottom => { c.y ← clipper.yMin;
     c.x ← ClipX[a, b, clipper.yMin]; };
out.top => { c.y ← clipper.yMax;
     c.x ← ClipX[a, b, clipper.yMax]; }
ENDCASE;
IF aCode = out THEN a ← c ELSE b ← c;
ENDLOOP;
ERROR;     -- can't get here, supposedly
};
END.