-- File CIFMann.mesa
-- Output module for Mann 3000, metric or english units
-- Written by Martin Newell, June 1980
-- Last updated: March 2, 1982 12:29 PM by Pasco
--The following dimensions are on the MASK which is assumed to be a factor
-- of 10 smaller than the reticles that the Mann machine generates
--In metric units
--1 Mann unit = 0.1 micron on the MASK
--Center of field at [50000,50000] Mann units
--In english units
--1 Mann unit = 0.001 mil on the MASK (but must be multiple of 5 units)
--Center of field at [200000,200000] Mann units
DIRECTORY
CIFControlDefs: FROM "CIFControlDefs" USING [DrawCIF],
CIFDevicesDefs: FROM "CIFDevicesDefs" USING [DeviceDescriptor,
DeviceDescriptorRecord, RegisterDevice, MaxLENGTHLayerArray,
GetCIFOutDevice],
CIFOutputDefs: FROM "CIFOutputDefs" USING [SetSorting],
CIFUtilitiesDefs: FROM "CIFUtilitiesDefs" USING [Rectangle,
SetClipRectangle, GetClipRectangle, DrawClipRectangle,
SetDisplayContext, GetDisplayContext],
Graphics: FROM "Graphics" USING [DisplayContext, NewContext, PushContext,
PopContext, Scale, Translate, CopyContext],
InlineDefs: FROM "InlineDefs" USING [BITAND, LowHalf],
IODefs: FROM "IODefs" USING [CR, WriteLine, WriteString,
WriteChar, GetOutputStream, SetOutputStream, WriteDecimal],
JaMFnsDefs: FROM "JaMFnsDefs" USING [PopString, PopInteger],
Real: FROM "Real" USING [Fix, RoundI, RoundLI],
RealFns: FROM "RealFns" USING [ArcTanDeg, SqRt],
StreamDefs: FROM "StreamDefs" USING [StreamHandle, NewByteStream, Write,
Append],
StringDefs: FROM "StringDefs" USING[AppendString, AppendLongNumber,
AppendDecimal, AppendChar, AppendLongDecimal];
CIFMann: PROGRAM
IMPORTS CIFControlDefs, CIFDevicesDefs, CIFOutputDefs, CIFUtilitiesDefs, Graphics, InlineDefs, IODefs, JaMFnsDefs, Real, RealFns, StreamDefs, StringDefs =
BEGIN OPEN CIFControlDefs, CIFDevicesDefs, CIFOutputDefs, CIFUtilitiesDefs, Graphics, InlineDefs, IODefs, JaMFnsDefs, Real, RealFns, StreamDefs, StringDefs;
-- Mann procedures
MannDeviceRecord: DeviceDescriptorRecord ← [
next:NIL,
name:"mann",
deviceSelect: MannSelect,
deviceDrawFrame: MannDrawFrame,
deviceSetScale: MannSetScale,
deviceSetClipRegion: MannSetClipRegion,
deviceOutput: MannOutput,
deviceLayer: MannLayer,
deviceLoadLayer: MannLoadLayer,
deviceRectangle: MannRectangle,
deviceStartPoly: MannStartPoly,
devicePolyVertex: MannPolyVertex,
deviceEndPoly: MannEndPoly,
deviceText: MannText
];
MannSelect: PROCEDURE RETURNS[BOOLEAN] =
BEGIN --expects <units> (0=metric, #0=english)
Units ← IF PopInteger[]=0 THEN metric ELSE english;
MannSetClipRegion[GetClipRectangle[]];
RETURN[TRUE];
END;
MannDrawFrame: PROCEDURE =
BEGIN
r: Rectangle ← GetClipRectangle[];
DrawClipRectangle[];
END;
OldMannSetScale: PROCEDURE [factor: REAL] =
BEGIN
dc: DisplayContext ← GetDisplayContext[];
PopContext[dc];
PushContext[dc];
Scale[dc, [factor,factor]];
END;
MannSetScale: PROCEDURE [factor: REAL] =
BEGIN --taken as pre-scale to convert stored coords to 0.01 micron
--useful if using english units and stored CIF file is not in units of 0.01 micron
MannScale ← factor;
END;
MannSetClipRegion: PROCEDURE [rt: Rectangle] =
BEGIN
SetClipRectangle[rt];
END;
MannOutput: PROCEDURE =
--expects <filename> (STRING)
BEGIN
fileName: STRING ← [100];
saveContext: DisplayContext ← GetDisplayContext[];
r: Rectangle ← GetClipRectangle[]; --clipping region in CIF units
s: REAL ← MannScale/MannCoords[Units];
PopString[fileName];
SetDisplayContext[mannContext];
PushContext[mannContext];
Translate[mannContext, [MannCenter[Units],MannCenter[Units]]]; --to center of Mann region
Scale[mannContext, [-1,1]]; --invert x
Scale[mannContext, [s,s]];
Translate[mannContext, [-(r.llx+r.urx)/2,-(r.lly+r.ury)/2]]; --window center to origin
--mannClipRectangle ← MapRectangle[r,mannContext,identityContext];
SetClipRectangle[r];
MannStart[fileName];
DrawCIF[Floor[r.llx],Floor[r.urx],Ceiling[r.lly],Ceiling[r.ury]];
MannEnd[];
PopContext[mannContext];
SetDisplayContext[saveContext];
SetClipRectangle[r];
END;
MannStart: PROCEDURE[fileName: STRING] =
BEGIN
baseFileName.length ← 0;
AppendString[baseFileName,fileName];
PolyGripe ← FALSE;
SmallGripe ← FALSE;
LayerStream ← ALL[NIL];
X ← ALL[-1];
Y ← ALL[-1];
H ← ALL[-1];
W ← ALL[-1];
A ← ALL[-1];
NRecs ← ALL[0];
SetSorting[incy];
MannCurrentLayer ← 32000; --i.e. not set
END;
MannEnd: PROCEDURE =
BEGIN
dir: StreamHandle;
save: StreamHandle ← GetOutputStream[];
fileNumber: INTEGER ← 0;
dirName: STRING ← [30];
name12: STRING ← [12];
FOR i:CARDINAL IN [0..baseFileName.length) UNTIL i=12 DO
ch:CHARACTER ← baseFileName[i];
AppendChar[name12,IF ch IN [’a..’z] THEN ch-40B ELSE ch];
ENDLOOP;
IF baseFileName.length<12 THEN THROUGH [0..12-baseFileName.length) DO
AppendChar[name12,’X];
ENDLOOP;
AppendString[dirName,baseFileName];
AppendString[dirName,".mann"];
dir ← NewByteStream[dirName, Write+Append];
--SetOutputStream[dir];
--***WriteString["<BOT>"];
--SetOutputStream[save];
WriteString[IF Units=metric THEN "Metric" ELSE "English"];
WriteLine[" format Mann output"];
WriteString["Mann directory on "];
WriteLine[dirName];
FOR i:CARDINAL IN [0..MaxLENGTHLayerArray) DO
s: StreamHandle ← LayerStream[i];
IF s#NIL THEN
{s.put[s,’$];
s.destroy[s];
SetOutputStream[dir];
WriteString[name12];
WriteLongNumberInField[
MIN[fileNumber←fileNumber+1,9999], 4];
WriteLongNumberInField[MIN[NRecs[i],9999], 4];
SetOutputStream[save];
WriteString["Mann layer file #"];
WriteDecimal[fileNumber];
WriteString[" from layer "];
WriteDecimal[i];
WriteString[" on file "];
WriteString[baseFileName];
WriteChar[’-];
WriteDecimal[i];
WriteString[".mann. Flash count: "];
WriteLongDecimal[NRecs[i]];
WriteChar[CR];
};
ENDLOOP;
dir.put[dir,’$];
dir.destroy[dir];
END;
MannLayer: PROCEDURE [layer: CARDINAL] =
BEGIN
IF layer#MannCurrentLayer THEN
BEGIN
IF LayerStream[layer]=NIL THEN
{fileName: STRING ← [100];
s: StreamHandle;
save: StreamHandle ← GetOutputStream[];
AppendString[fileName,baseFileName];
AppendChar[fileName,’-];
AppendDecimal[fileName,layer];
AppendString[fileName,".mann"];
s ← NewByteStream[fileName, Write+Append];
LayerStream[layer] ← s;
X[layer] ← -1;
Y[layer] ← -1;
H[layer] ← -1;
W[layer] ← -1;
A[layer] ← -1;
NRecs[layer] ← 0;
};
MannCurrentLayer ← layer;
END;
END;
MannLoadLayer: PROCEDURE[layer:CARDINAL, v0,v1,v2,v3: CARDINAL] =
-- meaningless
BEGIN
END;
MannText: PROCEDURE[text: STRING, x,y: REAL] =
--ignore it
BEGIN
END;
--Private procedures--
MannRectangle: PROCEDURE [r: Rectangle] =
--make two edges of appropriate types
BEGIN
left: LONG INTEGER ← Floor[r.llx];
bottom: LONG INTEGER ← Floor[r.lly];
right: LONG INTEGER ← Ceiling[r.urx];
top: LONG INTEGER ← Ceiling[r.ury];
width: LONG INTEGER ← right - left;
height: LONG INTEGER ← top - bottom;
small: LONG INTEGER ← Smallest[Units];
IF width<small OR height<small THEN
{IF ~SmallGripe THEN
{WriteLine["Rectangle too small to output"];
SmallGripe ← TRUE;
};
RETURN;
};
OutLargeRectangle[left,bottom,right,top, 0,1,0,0,0];
END;
NVerts: CARDINAL;
Vert: TYPE = RECORD[x,y: REAL];
P: ARRAY [0..4) OF Vert;
MannStartPoly: PROCEDURE [x,y: REAL] =
BEGIN
P[0] ← [x,y];
NVerts ← 1;
END;
MannPolyVertex: PROCEDURE [x,y: REAL] =
BEGIN
IF NVerts<4 THEN P[NVerts] ← [x,y];
NVerts ← NVerts + 1;
END;
MannEndPoly: PROCEDURE =
BEGIN
xaxis,yaxis,len,cos,sin: REAL;
left,bottom,right,top: REAL;
tranx,trany: LONG INTEGER;
angle: INTEGER;
IF NVerts#4 THEN
{WriteLine["Can’t handle non-rectangles"];
RETURN;
};
--find angle
xaxis ←
(P[1].x-P[0].x)+(P[2].x-P[3].x)+(P[3].y-P[0].y)+(P[2].y-P[1].y);
yaxis ←
(P[1].y-P[0].y)+(P[2].y-P[3].y)+(P[0].x-P[3].x)+(P[1].x-P[2].x);
len ← SqRt[xaxis*xaxis + yaxis*yaxis];
cos ← xaxis/len;
sin ← yaxis/len;
angle ← RoundI[10*ArcTanDeg[cos,sin]]; --in range -1800 to 1800
IF angle<0 THEN angle ← angle + 1800; --in range [0..1800)
IF angle#0 THEN --translate center to origin and rotate xaxis to x axis
{tranx ← RoundLI[(P[0].x + P[1].x + P[2].x + P[3].x)/4];
trany ← RoundLI[(P[0].y + P[1].y + P[2].y + P[3].y)/4];
FOR i:CARDINAL IN [0..4) DO
x: REAL ← P[i].x - tranx;
y: REAL ← P[i].y - trany;
px: REAL ← x*cos + y*sin;
P[i].y ← -x*sin + y*cos;
P[i].x ← px;
ENDLOOP;
}
ELSE {tranx ← trany ← 0;};
IF angle<900 THEN
{left ← (P[0].x + P[3].x)/2;
bottom ← (P[0].y + P[1].y)/2;
right ← (P[1].x + P[2].x)/2;
top ← (P[3].y + P[2].y)/2;
}
ELSE
{left ← (P[0].y + P[1].y)/2;
bottom ← (P[0].x + P[3].x)/2;
right ← (P[3].y + P[2].y)/2;
top ← (P[1].x + P[2].x)/2;
angle ← angle - 900;
};
--output it
OutLargeRectangle[Round[MIN[left,right]],Round[MIN[bottom,top]],
Round[MAX[left,right]],Round[MAX[bottom,top]],
angle,cos,sin,tranx,trany];
END;
OutLargeRectangle: PROCEDURE [left,bottom,right,top, angle: LONG INTEGER,
cos,sin: REAL,tranx,trany: LONG INTEGER] =
--Fragment and output the rectangle (left,bottom,right,top) rotated
-- counter clockwise about the origin by angle, and then translated
-- by (tranx,trany).
--angle is also given as (cos,sin).
--angle is in 0.1 degree for Mann coords
BEGIN
cx: LONG INTEGER ← (right + left)/2;
cy: LONG INTEGER ← (top + bottom)/2;
width: LONG INTEGER ← right - left;
height: LONG INTEGER ← top - bottom;
big: LONG INTEGER ← Biggest[Units];
save: StreamHandle ← GetOutputStream[];
SetOutputStream[LayerStream[MannCurrentLayer]];
IF width<=big AND height<=big THEN
OutRectangle[cx,cy,width,height, angle,cos,sin,tranx,trany]
ELSE
{wpieces,hpieces: LONG INTEGER;
dw,dh: LONG INTEGER;
l,b,r,t: LONG INTEGER;
wpieces ← (width-1)/big + 1;
hpieces ← (height-1)/big + 1;
dw ← (width-1)/wpieces + 1;
dh ← (height-1)/hpieces + 1;
FOR b ← bottom, t DO
t ← MIN[b+dh,top];
FOR l ← left, r DO
r ← MIN[l+dw,right];
OutRectangle[(l+r)/2,(b+t)/2,r-l,t-b, angle,cos,sin,tranx,trany];
IF r=right THEN EXIT;
ENDLOOP;
IF t=top THEN EXIT;
ENDLOOP;
};
SetOutputStream[save];
END;
OutRectangle: PROCEDURE [cx,cy,w,h, a: LONG INTEGER,
cos,sin: REAL,tranx,trany: LONG INTEGER] =
BEGIN
x,y: LONG INTEGER;
s: StreamHandle ← LayerStream[MannCurrentLayer];
IF BITAND[LowHalf[w],1]#0 THEN w ← w + 1; --make it even and bigger
IF BITAND[LowHalf[h],1]#0 THEN h ← h + 1; --make it even and bigger
IF a=0 THEN {x ← cx + tranx; y ← cy + trany}
ELSE
{x ← RoundLI[cx*cos - cy*sin + tranx];
y ← RoundLI[cx*sin + cy*cos + trany];
};
IF x#X[MannCurrentLayer] THEN
{WriteChar[’X]; WriteLongDecimal[x*OutScale[Units]];
X[MannCurrentLayer] ← x;
};
IF y#Y[MannCurrentLayer] THEN
{WriteChar[’Y]; WriteLongDecimal[y*OutScale[Units]];
Y[MannCurrentLayer] ← y;
};
IF w#W[MannCurrentLayer] THEN
{WriteChar[’W]; WriteLongDecimal[w*OutScale[Units]];
W[MannCurrentLayer] ← w;
};
IF h#H[MannCurrentLayer] THEN
{WriteChar[’H]; WriteLongDecimal[h*OutScale[Units]];
H[MannCurrentLayer] ← h;
};
IF a#A[MannCurrentLayer] THEN
{WriteChar[’A]; WriteLongDecimal[a];
A[MannCurrentLayer] ← a;
};
WriteChar[’;]; WriteChar[CR]; --WriteChar[LF];
NRecs[MannCurrentLayer] ← NRecs[MannCurrentLayer] + 1;
END;
Round: PROCEDURE[r: REAL] RETURNS[c: LONG INTEGER] = INLINE
BEGIN
IF r<0 THEN c ← -Fix[-r + 0.5]
ELSE c ← Fix[r+0.5];
END;
Ceiling: PROCEDURE[r: REAL] RETURNS[c: LONG INTEGER] = INLINE
BEGIN --"Truncate" r up to next integer
IF r>0 THEN
{b: LONG INTEGER ← Fix[r] + 1;
c ← Fix[r-b] + b;
}
ELSE c ← Fix[r];
END;
Floor: PROCEDURE[r: REAL] RETURNS[c: LONG INTEGER] = INLINE
BEGIN --"Truncate" r down to next integer
IF r<0 THEN
{b: LONG INTEGER ← -Fix[r] + 1;
c ← Fix[r+b] - b;
}
ELSE c ← Fix[r];
END;
WriteLongDecimal: PROCEDURE[n: LONG INTEGER] =
BEGIN
s: STRING ← [50];
AppendLongDecimal[s,n];
WriteString[s];
END;
WriteLongNumberInField: PROCEDURE[n: LONG UNSPECIFIED, field: CARDINAL] =
BEGIN
s: STRING ← [50];
AppendLongNumber[s,n,10];
IF s.length>field THEN
{THROUGH [1..field] DO WriteChar[’*]; ENDLOOP;
RETURN;
};
THROUGH [0..field-s.length) DO WriteChar[’0]; ENDLOOP;
WriteString[s];
END;
--Mann parameters
--mannClipRectangle: Rectangle;
identityContext: DisplayContext ← NewContext[GetCIFOutDevice[]];
mannContext: DisplayContext ← CopyContext[identityContext];
baseFileName: STRING ← [100];
PolyGripe: BOOLEAN;
SmallGripe: BOOLEAN;
MannCurrentLayer: CARDINAL;
MannScale: REAL ← 1;
UnitType: TYPE = {metric, english, unknown};
Units: UnitType ← unknown;
MannCoords: ARRAY UnitType OF REAL ← [10,1.27,1];
--MannCoords is used as divisor in MannOutput to convert CIF units (0.01 micron) to relevant output units
--For metric, "relevant output units" are 0.1 micron (on MASK)
--For english, "relevant output units" are .005 mil (on MASK), which
-- will be rounded and multiplied by 5 to give 0.001 mil units restricted
-- to multiples of 0.005 (see OutScale below)
-- [note: 1.27 = 2.54(to get 0.01 mil)*0.1(to get 0.001 mil)*5(to get 0.005 mil)]
OutScale: ARRAY UnitType OF INTEGER ← [1, 5, 1];
MannCenter: ARRAY UnitType OF REAL ← [50000, 40000, 0];
Smallest: ARRAY UnitType OF INTEGER ← [4, 4, 0]; --in steps
Biggest: ARRAY UnitType OF INTEGER ← [3000, 2400, 0]; --in steps
LayerStream: ARRAY [0..MaxLENGTHLayerArray) OF StreamHandle ← ALL[NIL];
X: ARRAY [0..MaxLENGTHLayerArray) OF LONG INTEGER ← ALL[-1];
Y: ARRAY [0..MaxLENGTHLayerArray) OF LONG INTEGER ← ALL[-1];
H: ARRAY [0..MaxLENGTHLayerArray) OF LONG INTEGER ← ALL[-1];
W: ARRAY [0..MaxLENGTHLayerArray) OF LONG INTEGER ← ALL[-1];
A: ARRAY [0..MaxLENGTHLayerArray) OF LONG INTEGER ← ALL[-1];
NRecs: ARRAY [0..MaxLENGTHLayerArray) OF LONG INTEGER ← ALL[0];
--set up context
RegisterDevice[@MannDeviceRecord];
END.