CDMEBESDropInImpl.mesa
Copyright © 1985 by Xerox Corporation. All rights reserved.
written by E. McCreight, November 2, 1983 6:03 pm
McCreight, May 1, 1987 6:38:41 pm PDT
Last Edited by: McCreight November 23, 1987 6:29:08 pm PST
This module drops a MEBES file into another MEBES file, one stripe at a time.
DIRECTORY
Atom, Basics, BasicTime, CDBasics, CDMEBES, CDMEBESScan, CStitching, FS, IO, Process, Rope;
CDMEBESDropInImpl: CEDAR PROGRAM IMPORTS Atom, Basics, BasicTime, CDBasics, CDMEBES, CDMEBESScan, CStitching, FS, IO, Process, Rope EXPORTS CDMEBES =
BEGIN OPEN CDMEBES;
InsertDropIn: PUBLIC PROC [ ms: MaskState, rects: Tesselation, di: DropIn, data: REF ] RETURNS [ newData: REF ] =
This procedure incorporates the mask information referenced in data, translated by di.pos and then clipped to ms.mebesStripeClip, into the MEBES stream in ms.s.
BEGIN
IF data = NIL THEN
data ←IO.PutFR[di.fileNamePattern, IO.rope[NARROW[ms.toolingSpec.GetPropFromList[ms.curMask.maskId], ToolingMaskSpec].maskNo]];
IF data = NIL THEN RETURN[NIL];
WITH data SELECT FROM
fileName: Rope.ROPE => {
tries: INT ← 0;
{ ENABLE FS.Error =>
SELECT error.code FROM
$connectionTimedOut, $connectionRejected =>
IF tries < 10 THEN {
tries ← tries+1;
Process.PauseMsec[10000];
RETRY;
}
ELSE REJECT;
ENDCASE => REJECT;
fileLen: INT ← -2;
did: REF ANY;
[bytes: fileLen] ← FS.FileInfo[fileName];
SELECT fileLen FROM
>= 2048 => did ← CDMEBESScan.ScanMebesPatternFile[fileName];
<= 0 => ERROR;
ENDCASE => {
s: IO.STREAMFS.StreamOpen[fileName];
token: Rope.ROPEIO.GetCedarTokenRope[s].token;
s.Close[];
IF Rope.Equal[token, "EmptyMebesPatternFile"] THEN did ← $NoInsert
ELSE ERROR;
};
newData ← InsertDropIn[ms, rects, di, did];
};
};
atom: ATOM => newData ← atom; -- don't actually DO anything
did: CDMEBESScan.DropInDescriptor => {
scaleNtoM: Rational = [num: 1, denom: ms.mebesPixelPitch]; -- from Nm to MEBESPixels
scaleMtoT: Rational = [num: ms.mebesPixelPitch*ms.tadsPerNm, denom: 1]; -- from MEBESPixels to Tads
mebesStripeClip: MEBESRect = ScaleRect[ms.tadStripeClip, [num: 1, denom: ms.mebesPixelPitch*ms.tadsPerNm]];
dropInClip: MEBESRect; -- the current output stripe, translated to drop-in space and clipped to drop-in boundary
dropInOffsetToReticleClip: MEBESPosition; -- position of drop-in file's [0,0] in reticleClip
mebesStripeClipFromDropIn: MEBESRect;
IF BasicTime.Period[did.lastChecked, BasicTime.Now[]] > 5*60 THEN {
WHILE FS.FileInfo[did.fileName].created # did.created DO
did ← CDMEBESScan.ScanMebesPatternFile[did.fileName]; -- needs updating
ENDLOOP;
did.lastChecked ← BasicTime.Now[];
};
IF ms.mebesPixelPitch -- nm -- *1.0E-9 > did.pixelSize -- Meters -- +5.0E-10 OR
ms.mebesPixelPitch*1.0E-9 < did.pixelSize-5.0E-10 THEN
ERROR; -- pixel sizes incompatible
dropInOffsetToReticleClip ← ScalePoint[CDBasics.AddPoints[CDBasics.AddPoints[di.pos, ms.dieOffset], CDBasics.BaseOfRect[ms.nmReticleClip]], scaleNtoM];
mebesStripeClipFromDropIn ← CDBasics.MoveRect[mebesStripeClip,
CDBasics.NegOffset[dropInOffsetToReticleClip]];
dropInClip ← CDBasics.Intersection[did.clip, mebesStripeClipFromDropIn];
IF CDBasics.NonEmpty[dropInClip] THEN {
s: IO.STREAM;
IF di.clearBackground THEN
rects.ChangeRect[
ScaleRect[CDBasics.MoveRect[dropInClip, dropInOffsetToReticleClip], scaleMtoT],
NIL];
FOR segment: CARDINAL ← dropInClip.x1/CDMEBES.maskWidth+segmentOrigin, segment+1 WHILE (segment-segmentOrigin)*CDMEBES.maskWidth < dropInClip.x2 DO
FOR stripe: CARDINAL ← dropInClip.y1/did.stripeHeight+stripeOrigin, stripe+1 WHILE (stripe-stripeOrigin)*did.stripeHeight <= dropInClip.y2 DO
offset: MEBESPosition = [x: (segment-segmentOrigin)*CDMEBES.maskWidth, y: (stripe-stripeOrigin)*did.stripeHeight];
IF did[segment][stripe] = [0, 0] THEN LOOP;
IF s = NIL THEN
s ← FS.StreamOpen[fileName: did.fileName, remoteCheck: FALSE];
s.SetIndex[CDMEBES.mebesBlockSize*(did[segment][stripe].firstBlock-1)+2*(did[segment][stripe].firstWordWithinBlock-1)];
ProcessStripe[source: s, dest: ms.s,
stripeClip: CDBasics.Intersection[
[x1: 0, y1: 0, x2: CDMEBES.maskWidth, y2: did.stripeHeight],
CDBasics.MoveRect[r: dropInClip, offset: CDBasics.NegOffset[offset]]
],
destTrans: CDBasics.AddPoints[offset, CDBasics.SubPoints[dropInOffsetToReticleClip, CDBasics.BaseOfRect[mebesStripeClip]]]
];
ENDLOOP; -- stripe
ENDLOOP; -- segment
s.Close[]; s ← NIL;
};
newData ← did;
};
ENDCASE => ERROR;
END;
rectCmd: REF DrawRectangle ← NEW[DrawRectangle];
trapCmd: REF DrawTrapezoid ← NEW[DrawTrapezoid];
ProcessStripe: PROC [ source, dest: IO.STREAM, stripeClip: MEBESRect, destTrans: MEBESPosition ] =
BEGIN
In this section, intervals are always closed on the left and open on the right, thus: [z1..z2).
MEBES16Pixels: TYPE = MEBESPixels; -- sixteenths of a MEBESPixel
According to a conversation with Perkin-Elmer, a pixel is turned on if and only if its integer is included in the 1/16-resolution range. For example, [3.5..5.25) turns on pixels 4 and 5.
InsertRectangle: PROC [ x, y, width, height: MEBESPixels ] = {
destRect: MEBESRect = CDBasics.Intersection[stripeClip, [x1: x, y1: y, x2: x+width, y2: y+height]];
IF CDBasics.NonEmpty[destRect] THEN {
rectCmd.h ← destRect.y2-destRect.y1;
rectCmd.w ← destRect.x2-destRect.x1;
rectCmd.x ← destRect.x1+destTrans.x;
rectCmd.y ← destRect.y1+destTrans.y;
SendCommand[dest, rectCmd];
};
};
InsertTrapezoid: PROC [ x, width: MEBES16Pixels, y, height: MEBESPixels, leftEdge, rightEdge: MEBES16Pixels ] = {
A conversation with Keith Wires of MicroFab (415-965-1750) on 20 November 86 leads me (EMM) to the following statement of the Perkin-Elmer core pixel fill algorithm. A pixel (x, y) is turned on if and only if its center point (x+0.4999.., y+0.4999..) lies within the plotted figure. If that's true, the trapezoid scan conversion algorithm used by Perkin-Elmer can be represented like this:
FOR dy: INT ← 1, dy+2 WHILE dy<2*height DO -- halves
x1: INT = x+((dy*leftEdge)/(2*height))); -- sixteenths
.. the left boundary at y-center of pixel row
x2: INT = x+width+((dy*rightEdge)/(2*height))); -- sixteenths
.. the right boundary at y-center of pixel row
x1Frac: INT = x1 MOD 16; -- sixteenths
FOR px: INT ← x1-x1Frac+(IF x1Frac<8 THEN 0 ELSE 16), px+16 WHILE px < x2 DO
FillPixelRectangle[x1: (px-8)/16, y1: y+(dy-1)/2, x2: (px+8)/16, y: y+(dy+1)/2];
ENDLOOP;
ENDLOOP;
x1b, x1t, x2b, x2t: MEBES16Pixels;
y1, y2: MEBESPixels;
sx1: MEBES16Pixels = 16*stripeClip.x1;
sx2: MEBES16Pixels = 16*stripeClip.x2;
Low: PROC [ i: INT ] RETURNS [ n: CARDINAL ] =
{RETURN[Basics.LowHalf[LOOPHOLE[i]]]};
High: PROC [ i: INT ] RETURNS [ n: [0..100B) ] =
BEGIN
hi: INTEGER;
TRUSTED {hi ← LOOPHOLE[Basics.HighHalf[i]]};
IF ~ (hi IN [-40B..40B) ) THEN ERROR;
RETURN[IF hi>=0 THEN hi ELSE hi+100B];
END;
Interpolate: PROC [ b1, b2, a1, ax, a2: INT ] RETURNS [ bx: INT ] = {
bx ← b1+((ax-a1)*(b2-b1))/(a2-a1);
};
BasicTrapezoid: PROC [ym1, ym2: MEBESPixels] = {
DoYSplit: PROC [ xb, xm, xt: MEBES16Pixels ] = {
ySplit: MEBESPixels = MAX[ym1+1, MIN[ym2-1, Interpolate[y1, y2, xb, xm, xt]]];
BasicTrapezoid[ym1, ySplit];
BasicTrapezoid[ySplit, ym2];
};
SELECT TRUE FROM
ym2 <= ym1 => RETURN; -- empty clipping region [ym1..ym2)
ym1 = ym2-1 => { -- a single row of pixels, approximate with rectangle
xm1: MEBESPixels ← Interpolate[x1b, x1t, y1, ym1, y2]/16;
xm2: MEBESPixels ← Interpolate[x2b, x2t, y1, ym1, y2]/16;
IF xm1 < xm2 THEN
InsertRectangle[xm1, ym1, xm2-xm1, 1];
};
ENDCASE => {
xm1b: MEBES16Pixels ← Interpolate[x1b, x1t, y1, ym1, y2];
xm2b: MEBES16Pixels ← Interpolate[x2b, x2t, y1, ym1, y2];
xm1t: MEBES16Pixels ← Interpolate[x1b, x1t, y1, ym2, y2];
xm2t: MEBES16Pixels ← Interpolate[x2b, x2t, y1, ym2, y2];
IF xm2b < xm1b OR xm2t < xm1t THEN ERROR;
SELECT TRUE FROM
Examine the left boundary of the trapezoid within the y-range.
xm1b < sx1+8 AND xm1t < sx1+8 =>
xm1b ← xm1t ← sx1;
.. both top and bottom of the trapezoid include the pixel stripeClip.x1
xm1b < sx1-8 OR xm1t < sx1-8 => {
Find the value of y where the [x1b, y1] - [x1t, y2] edge crosses the line x=stripeClip.x1, and output two trapezoids.
DoYSplit[x1b, sx1, x1t];
RETURN;
};
.. at this point, we know the [x1b, y1] - [x1t, y2] lies to the right of x=stripeClip.x1. Now check its relation to x=stripeClip.x2.
xm1b < sx2+8 AND xm1t < sx2+8 => NULL;
.. no pixel off beyond stripeClip.x2
xm1b < sx2-8 OR xm1t < sx2-8 => {
Find the value of y where the [x1b, y1] - [x1t, y2] edge crosses the line x=stripeClip.x2+0.5, and output two trapezoids.
DoYSplit[x1b, sx2, x1t];
RETURN;
};
ENDCASE => RETURN;
.. clips out to the right
SELECT TRUE FROM
Examine the right boundary of the trapezoid within the y-range.
sx2-8 <= xm2b AND sx2-8 <= xm2t => {
.. both top and bottom of the trapezoid include the rightmost pixel
xm2b ← MIN[MAX[xm1b+1, xm2b], sx2];
xm2t ← MIN[xm2t, sx2];
};
sx2+8 <= xm2b OR sx2+8 <= xm2t => {
Find the value of y where the [x2b, y1] - [x2t, y2] edge crosses the line x=stripeClip.x2, and output two trapezoids.
DoYSplit[x2b, sx2, x2t];
RETURN;
};
.. at this point, we know the [x2b, y1] - [x2t, y2] lies to the left of x=stripeClip.x2. Now check its relation to x=stripeClip.x1.
sx1-8 <= xm2b AND sx1-8 <= xm2t => {
.. no pixel off beyond stripeClip.x1
xm2b ← MAX[sx1, xm1b+1, xm2b];
xm2t ← MAX[sx1, xm1b+1, xm2t];
};
sx1+8 <= xm2b OR sx1+8 <= xm2t => {
Find the value of y where the [x2b, y1] - [x2t, y2] edge crosses the line x=stripeClip.x1, and output two trapezoids.
DoYSplit[x2b, sx1, x2t];
RETURN;
};
ENDCASE => RETURN;
.. clips out to the left
At this point we have a trapezoid clipped x entirely within [sx1..sx2) for y in [ym1..ym2).
IF xm2b <= xm1b -- width <= 0
OR xm2t < xm1t -- width < (dx1-dx2)
OR xm1b < sx1
OR xm1t < sx1
OR sx2 < xm2b
OR sx2 < xm2t THEN ERROR; -- just checking...
trapCmd^ ← [
h: ym2-ym1,
wLow: Low[xm2b-xm1b],
x1Low: Low[xm1b+16*destTrans.x],
deltaX2High: High[xm2t-xm2b],
y1: ym1+destTrans.y,
deltaX1Low: Low[xm1t-xm1b],
deltaX2Low: Low[xm2t-xm2b],
deltaX1High: High[xm1t-xm1b],
x1High: High[xm1b+16*destTrans.x],
wHigh: High[xm2b-xm1b]
];
SendCommand[dest, trapCmd];
};
}; -- end of BasicTrapezoid
We have a trapezoid in the source file whose corners are
[x/16, y], [(x+leftEdge)/16, y+height], [(x+width+rightEdge)/16, y+height], [(x+width)/16, y] in clockwise order.
IF (width<0 OR height<0 OR width+rightEdge<leftEdge) THEN ERROR;
trapezoid not in canonical form
x1b ← x;
x1t ← x+leftEdge;
x2b ← x+width;
x2t ← x+width+rightEdge;
y1 ← y;
y2 ← y+height;
BasicTrapezoid[MAX[y1, stripeClip.y1], MIN[y2, stripeClip.y2]];
};
DO
t1: CARDINAL ← CDMEBESScan.ReadMebesWord[source];
SELECT t1 MOD 100B FROM
16 => { -- Manhattan Rectangle
x, width, y, height: INT;
height ← t1/100B + 1;
width ← CDMEBESScan.ReadMebesWord[source];
x ← CDMEBESScan.ReadMebesWord[source];
y ← CDMEBESScan.ReadMebesWord[source];
InsertRectangle[x, y, width, height];
};
17 => { -- Parallelogram
tmp1, x, width, leftEdge, y, height: INT;
height ← t1/100B + 1;
width ← CDMEBESScan.ReadMebesWord[source];
x ← CDMEBESScan.ReadMebesWord[source];
y ← CDMEBESScan.ReadMebesWord[source];
leftEdge ← CDMEBESScan.ReadMebesWord[source];
tmp1 ← CDMEBESScan.ReadMebesWord[source];
width ← width + (tmp1 MOD 40B)*200000B;
tmp1 ← tmp1/40B;
x ← x + (tmp1 MOD 40B)*200000B;
tmp1 ← tmp1/40B;
leftEdge ←
leftEdge + (tmp1 MOD 100B)*200000B -
(IF tmp1/40B # 0 THEN 20000000B ELSE 0);
InsertTrapezoid[x, width, y, height, leftEdge, leftEdge];
};
18 => { -- Trapezoid 1
tmp1, x, width, leftEdge, y, height: INT;
height ← t1/100B + 1;
width ← CDMEBESScan.ReadMebesWord[source];
x ← CDMEBESScan.ReadMebesWord[source];
y ← CDMEBESScan.ReadMebesWord[source];
leftEdge ← CDMEBESScan.ReadMebesWord[source];
tmp1 ← CDMEBESScan.ReadMebesWord[source];
width ← width + (tmp1 MOD 40B)*200000B;
tmp1 ← tmp1/40B;
x ← x + (tmp1 MOD 40B)*200000B;
tmp1 ← tmp1/40B;
leftEdge ←
leftEdge + (tmp1 MOD 100B)*200000B -
(IF tmp1/40B # 0 THEN 20000000B ELSE 0);
InsertTrapezoid[x, width, y, height, leftEdge, 0];
};
19 => { -- Trapezoid 2
tmp1, x, width, rightEdge, y, height: INT;
height ← t1/100B + 1;
width ← CDMEBESScan.ReadMebesWord[source];
x ← CDMEBESScan.ReadMebesWord[source];
y ← CDMEBESScan.ReadMebesWord[source];
rightEdge ← CDMEBESScan.ReadMebesWord[source];
tmp1 ← CDMEBESScan.ReadMebesWord[source];
width ← width + (tmp1 MOD 40B)*200000B;
tmp1 ← tmp1/40B;
x ← x + (tmp1 MOD 40B)*200000B;
tmp1 ← tmp1/40B;
rightEdge ←
rightEdge + (tmp1 MOD 100B)*200000B -
(IF tmp1/40B # 0 THEN 20000000B ELSE 0);
InsertTrapezoid[x, width, y, height, 0, rightEdge];
};
20 => { -- Trapezoid 3
tmp1, x, width, leftEdge, rightEdge, y, height: INT;
height ← t1/100B + 1;
width ← CDMEBESScan.ReadMebesWord[source];
x ← CDMEBESScan.ReadMebesWord[source];
y ← CDMEBESScan.ReadMebesWord[source];
leftEdge ← CDMEBESScan.ReadMebesWord[source];
rightEdge ← CDMEBESScan.ReadMebesWord[source];
tmp1 ← CDMEBESScan.ReadMebesWord[source];
width ← width + (tmp1 MOD 40B)*200000B;
tmp1 ← tmp1/40B;
x ← x + (tmp1 MOD 40B)*200000B;
tmp1 ← tmp1/40B;
leftEdge ←
leftEdge + (tmp1 MOD 100B)*200000B -
(IF tmp1/40B # 0 THEN 20000000B ELSE 0);
tmp1 ← y/2000B;
y ← y MOD 2000B;
rightEdge ←
rightEdge + (tmp1 MOD 100B)*200000B -
(IF tmp1/40B # 0 THEN 20000000B ELSE 0);
InsertTrapezoid[x, width, y, height, leftEdge, rightEdge];
};
10, 7 => NULL; -- start of segment or small stripe number
2 => [] ← CDMEBESScan.ReadMebesWord[source]; -- start of large stripe number
8 => RETURN; -- end of stripe
4 => RETURN; -- end of drawing
9 => { -- end of buffer
i: INT = source.GetIndex[]+CDMEBES.mebesBlockSize-1;
source.SetIndex[i - (i MOD CDMEBES.mebesBlockSize)];
};
ENDCASE => ERROR CDMEBESScan.NotMEBESFormat;
ENDLOOP;
END;
warnIfUnimplGeom: BOOLTRUE;
UnimplementedGeom: PROC =
{IF warnIfUnimplGeom THEN SIGNAL UnImplementedGeometry};
UnImplementedGeometry: SIGNAL = CODE;
Module START code...
END. -- of CDMEBESDropInImpl