File: GerberToIP.mesa
Copyright Ó 1988 by Xerox Corporation. All rights reserved.
Christophe Cuenod March 8, 1988 10:02:44 am PST
DIRECTORY
Commander USING [CommandProc, Register, Handle],
Convert USING [CardFromRope, RealFromRope],
FS USING [Error, FileInfo, StreamOpen],
IO,
Rope USING [Cat, Equal, ROPE],
Imager USING [Color, Context, MaskVector, SetColor, SetStrokeEnd, SetStrokeWidth, StrokeEnd, VEC, white, black, MakeGray],
ImagerColor USING[ColorFromRGB],
ImagerInterpress USING [Close, Create, DoPage, Ref];
GerberToIP: CEDAR PROGRAM
IMPORTS Commander, Convert, FS, Imager, ImagerColor, ImagerInterpress, IO, Rope =
BEGIN
ROPE: TYPE = Rope.ROPE;
FileHandleRep: TYPE = RECORD[
ip: ROPE,
parameters: ROPE,
gerber: ROPE
];
FileHandle: TYPE = REF FileHandleRep;
Shape: TYPE = {standard, donut, thermalRelief, target};
Aperture: TYPE = RECORD[
dx1, dx2: REAL ← 0,
dy1, dy2: REAL ← 0,
shape: Shape,
color: Imager.Color,
strokeEnd: Imager.StrokeEnd
];
Parameters: TYPE = RECORD[
invertAxis: BOOLEAN,
scale: REAL,
xSym: REAL,
ySym: REAL,
xTransl: REAL,
yTransl: REAL,
aperture: ARRAY[1..24] OF Aperture
];
BadCommandLine: SIGNAL [];
CmdTokenBreak: PROC [char: CHAR] RETURNS [IO.CharClass] = {
IF char = '← THEN RETURN [break];
IF char = ' OR char = '\t OR char = ', OR char = '; OR char = '\n THEN RETURN [sepr];
RETURN [other];
};
GetCmdToken: PROC [stream: IO.STREAM] RETURNS [rope: ROPE] = {
rope ← NIL;
rope ← stream.GetTokenRope[CmdTokenBreak ! IO.EndOfStream => CONTINUE].token;
};
ReadCommandLine: PROC [cmd: Commander.Handle] RETURNS [filehandle: FileHandle] ~ {
file: ROPE;
stream: IO.STREAM;
filehandle ← NEW[FileHandleRep];
stream ← IO.RIS[cmd.commandLine];
file ← GetCmdToken[stream];
filehandle.ip ← Rope.Cat[file, ".ip"];
filehandle.gerber ← Rope.Cat[file, ".gerber"];
filehandle.parameters ← Rope.Cat[file, ".parameters"];
[] ← FS.FileInfo[filehandle.gerber ! FS.Error => {
IF error.group = user THEN {
cmd.out.PutRope[Rope.Cat[error.explanation, "\n"]];
SIGNAL BadCommandLine[];
CONTINUE;
};
}];
[] ← FS.FileInfo[filehandle.parameters ! FS.Error => {
IF error.group = user THEN {
cmd.out.PutRope[Rope.Cat[error.explanation, "\n"]];
SIGNAL BadCommandLine[];
CONTINUE;
};
}];
IF file = NIL THEN {
cmd.out.PutRope["Usage:\nGerberToIP Filename\n(Transform the file Filename.gerber, into the file Filename.ip )\n"];
SIGNAL BadCommandLine[];
};
};
GetNumber: PROC [in: IO.STREAM] RETURNS [x: CARD ← 0] ~ {
c: CHARIO.GetChar[in];
WHILE c IN ['0..'9] DO
x ← 10 * x + c - '0;
c ← IO.GetChar[in];
ENDLOOP;
IO.Backup[in, c];
};
SetAperture: PROC [d: CARD] RETURNS [number: CARD] ~ {
SELECT d FROM
IN[10..19] => number ← d-9; --This is Gerber standard definitions of apertures.
IN[70..71] => number ← d-59;
IN[20..29] => number ← d-7;
IN[72..73] => number ← d-49;
ENDCASE => ERROR;
};
TokenProc: IO.BreakProc = {
RETURN [SELECT char FROM
'[, '], '(, '), '{, '}, '", '*, '/, '@, '← => break,
IN [IO.NUL .. IO.SP] => sepr,
',, ':, '; => sepr,
ENDCASE => other];
};
ReadParameters: PROC [parametersFile: ROPE] RETURNS [parameters: Parameters] ~ {
r, s: ROPE;
index: CARD;
in: IO.STREAMFS.StreamOpen[parametersFile];
parameters.invertAxis ← FALSE;
parameters.scale ← 1.0;
parameters.xSym ← 1.0;
parameters.ySym ← 1.0;
parameters.xTransl ← 0.0;
parameters.yTransl ← 0.0;
WHILE NOT IO.EndOf[in] DO
r ← NIL;
r ← IO.GetTokenRope[in! IO.EndOfStream => CONTINUE].token;
SELECT TRUE FROM
Rope.Equal[r, "invertaxis", FALSE]  => {
parameters.invertAxis ← TRUE;
};
Rope.Equal[r, "scale", FALSE]  => {
parameters.scale ← Convert.RealFromRope[IO.GetTokenRope[in].token];
};
Rope.Equal[r, "xSymetry", FALSE]  => {
parameters.xSym ← -1.0;
};
Rope.Equal[r, "ySymetry", FALSE]  => {
parameters.ySym ← -1.0;
};
Rope.Equal[r, "xTranslation", FALSE]  => {
parameters.xTransl ← Convert.RealFromRope[IO.GetTokenRope[in, TokenProc].token];
};
Rope.Equal[r, "yTranslation", FALSE]  => {
parameters.yTransl ← Convert.RealFromRope[IO.GetTokenRope[in, TokenProc].token];
};
Rope.Equal[r, "aperture", FALSE]  => {
index ← Convert.CardFromRope[IO.GetTokenRope[in].token];
s ← IO.GetTokenRope[in].token;
SELECT TRUE FROM
Rope.Equal[s, "standard", FALSE]  => {
parameters.aperture[index].shape ← standard;
};
Rope.Equal[s, "donut", FALSE]  => {
parameters.aperture[index].shape ← donut;
};
Rope.Equal[s, "thermalRelief",FALSE]  => {
parameters.aperture[index].shape ← thermalRelief;
};
Rope.Equal[s, "target",FALSE]  => {
parameters.aperture[index].shape ← target;
};
ENDCASE => ERROR;
s ← IO.GetTokenRope[in].token;
SELECT TRUE FROM
Rope.Equal[s, "round", FALSE]  => {
parameters.aperture[index].strokeEnd ← round;
parameters.aperture[index].dx1 ← Convert.CardFromRope[IO.GetTokenRope[in].token]/2;
parameters.aperture[index].dx2 ← parameters.aperture[index].dx1;
parameters.aperture[index].dy1 ← parameters.aperture[index].dx1;
parameters.aperture[index].dy2 ← parameters.aperture[index].dx1;
};
Rope.Equal[s, "square", FALSE]  => {
parameters.aperture[index].strokeEnd ← square;
parameters.aperture[index].dx1 ← Convert.CardFromRope[IO.GetTokenRope[in].token]/2;
parameters.aperture[index].dx2 ← parameters.aperture[index].dx1;
parameters.aperture[index].dy1 ← parameters.aperture[index].dx1;
parameters.aperture[index].dy2 ← parameters.aperture[index].dx1;
};
Rope.Equal[s, "rectangle", FALSE]  => {
parameters.aperture[index].strokeEnd ← square;
parameters.aperture[index].dx1 ← Convert.CardFromRope[IO.GetTokenRope[in].token];
parameters.aperture[index].dx2 ← Convert.CardFromRope[IO.GetTokenRope[in].token];
parameters.aperture[index].dy1 ← Convert.CardFromRope[IO.GetTokenRope[in].token];
parameters.aperture[index].dy2 ← Convert.CardFromRope[IO.GetTokenRope[in].token];
};
ENDCASE => ERROR;
s ← IO.GetTokenRope[in].token;
SELECT TRUE FROM
Rope.Equal[s, "White", FALSE]  => {
parameters.aperture[index].color ← Imager.white;
};
Rope.Equal[s, "Gray", FALSE]  => {
parameters.aperture[index].color ← Imager.MakeGray[0.5];
};
Rope.Equal[s, "Black", FALSE]  => {
parameters.aperture[index].color ← Imager.black;
};
Rope.Equal[s, "Red", FALSE]  => {
parameters.aperture[index].color ← ImagerColor.ColorFromRGB[[1, 0, 0]];
};
Rope.Equal[s, "Green", FALSE]  => {
parameters.aperture[index].color ← ImagerColor.ColorFromRGB[[0, 1, 0]];
};
Rope.Equal[s, "Blue", FALSE]  => {
parameters.aperture[index].color ← ImagerColor.ColorFromRGB[[0, 0, 1]];
};
Rope.Equal[s, "Cyan", FALSE]  => {
parameters.aperture[index].color ← ImagerColor.ColorFromRGB[[0, 1, 1]];
};
Rope.Equal[s, "Magenta", FALSE]  => {
parameters.aperture[index].color ← ImagerColor.ColorFromRGB[[1, 0, 1]];
};
Rope.Equal[s, "Yellow", FALSE]  => {
parameters.aperture[index].color ← ImagerColor.ColorFromRGB[[1, 1, 0]];
};
ENDCASE => ERROR;
};
ENDCASE;
ENDLOOP;
};
ProduceIPMaster: PROC [cmd: Commander.Handle, fileHandle: FileHandle] ~ {
DoPrint: PROC [context: Imager.Context] ~ {
SetParam: PROC [] ~ {
IF param.aperture[index].color = NIL THEN {
IO.PutF[cmd.out, "The aperture %g is used in the %g file and is not defined in the %g file.\n", IO.card[index], IO.rope[fileHandle.gerber], IO.rope[fileHandle.parameters]];
param.aperture[index].color ← Imager.white;
}
ELSE {
IF currentColor # param.aperture[index].color THEN {
currentColor ← param.aperture[index].color;
Imager.SetColor[context, currentColor];
};
IF currentStrokeEnd # param.aperture[index].strokeEnd THEN {
currentStrokeEnd ← param.aperture[index].strokeEnd;
Imager.SetStrokeEnd[context, currentStrokeEnd];
};
widthx ← param.aperture[index].dx1+param.aperture[index].dx2;
widthy ← param.aperture[index].dy1+param.aperture[index].dy2;
width ← MIN[widthx, widthy];
IF widthx # widthy THEN {
delta1.x ← param.aperture[index].dx1-width/2;
delta2.x ← param.aperture[index].dx2-width/2;
delta1.y ← param.aperture[index].dy1-width/2;
delta2.y ← param.aperture[index].dy2-width/2;
IF param.invertAxis THEN {
temp ← delta1.x;
delta1.x ← delta1.y;
delta1.y ← temp;
temp ← delta2.x;
delta2.x ← delta2.y;
delta2.y ← temp;
}
}
ELSE {
delta1.x ← width/1000;
delta2.x ← 0;
delta1.y ← 0;
delta2.y ← 0;
};
IF currentStrokeWidth # MIN[widthx, widthy] THEN {
currentStrokeWidth ← MIN[widthx, widthy];
Imager.SetStrokeWidth[context, currentStrokeWidth];
};
};
};
currentStrokeEnd: Imager.StrokeEnd;
currentStrokeWidth: REAL;
currentColor: Imager.Color;
index: CARD;
c: CHAR;
d: INT;
widthx, widthy, width, temp: REAL;
p1, p2: Imager.VEC;
oldPos, pos, delta1, delta2: Imager.VEC;
in: IO.STREAMFS.StreamOpen[fileHandle.gerber];
d ← 0;
WHILE NOT IO.EndOf[in] DO
c ← IO.GetChar[in];
SELECT c FROM
='X  => {
IF NOT param.invertAxis THEN {
pos.x ←param.xTransl+param.xSym*GetNumber[in];
}
ELSE {
pos.y ←param.yTransl+param.ySym*GetNumber[in];
};
};
='Y  => {
IF NOT param.invertAxis THEN {
pos.y ←param.yTransl+param.ySym*GetNumber[in];
}
ELSE {
pos.x ←param.xTransl+param.xSym*GetNumber[in];
};
};
='D  => d ← GetNumber[in];
='*  => {  -- Action takes place after a '*
SELECT d FROM
=0 => d ← 0 ; --Not yet initialised
=1 => { --Draw
SetParam[];
Imager.MaskVector[context, oldPos, pos];
oldPos ← pos;
};
=2 => { --Move
oldPos ← pos;
};
=3 => { --Flash
SetParam[];
p1.x ← pos.x-delta1.x;
p1.y ← pos.y-delta1.y;
p2.x ← pos.x+delta2.x;
p2.y ← pos.y+delta2.y;
Imager.MaskVector[context, p1, p2];
oldPos ← pos;
IF param.aperture[index].shape = target THEN { --add 2 white offset squares
currentStrokeEnd ← square;
Imager.SetStrokeEnd[context, currentStrokeEnd];
currentColor ← Imager.white;
Imager.SetColor[context, currentColor];
p1.x ← pos.x-currentStrokeWidth*.5;
p1.y ← pos.y-currentStrokeWidth*.5;
p2.x ← pos.x-currentStrokeWidth*.6;
p2.y ← pos.y-currentStrokeWidth*.5;
Imager.MaskVector[context, p1, p2];
p1.x ← pos.x+currentStrokeWidth*.5;
p1.y ← pos.y+currentStrokeWidth*.5;
p2.x ← pos.x+currentStrokeWidth*.6;
p2.y ← pos.y+currentStrokeWidth*.5;
Imager.MaskVector[context, p1, p2];
};
IF param.aperture[index].shape = donut OR param.aperture[index].shape = thermalRelief THEN { --add a white center
currentStrokeWidth ← currentStrokeWidth*.6;
Imager.SetStrokeWidth[context, currentStrokeWidth];
currentColor ← Imager.white;
Imager.SetColor[context, currentColor];
Imager.MaskVector[context, p1, p2];
};
IF param.aperture[index].shape = thermalRelief THEN { --add a white cross
currentStrokeEnd ← square;
Imager.SetStrokeEnd[context, currentStrokeEnd];
currentStrokeWidth ← currentStrokeWidth/3;
Imager.SetStrokeWidth[context, currentStrokeWidth];
p1.x ← pos.x-currentStrokeWidth*2.1;
p1.y ← pos.y;
p2.x ← pos.x+currentStrokeWidth*2.1;
p2.y ← pos.y;
Imager.MaskVector[context, p1, p2];
p1.x ← pos.x;
p1.y ← pos.y-currentStrokeWidth*2.1;
p2.x ← pos.x;
p2.y ← pos.y+currentStrokeWidth*2.1;
Imager.MaskVector[context, p1, p2];
};
};
IN[4..99] => {
index ← SetAperture[d];
IF param.aperture[index].color = NIL THEN {
IO.PutF[cmd.out, "The aperture %g is selected in the %g file and is not defined in the %g file.\n", IO.card[index], IO.rope[fileHandle.gerber], IO.rope[fileHandle.parameters]];
param.aperture[index].color ← Imager.white;
}
};
ENDCASE => ERROR;
};
ENDCASE;
ENDLOOP;
};
pressScale: REAL;
param: Parameters ← ReadParameters[fileHandle.parameters];
ip: ImagerInterpress.Ref ← ImagerInterpress.Create[fileHandle.ip];
pressScale ← param.scale*0.0000256;
ImagerInterpress.DoPage[ip, DoPrint, pressScale];
ImagerInterpress.Close[ip];
};
GerberToIPProc: Commander.CommandProc = BEGIN
fault: BOOLEANFALSE;
fileHandle: FileHandle;
fileHandle ← ReadCommandLine[cmd ! BadCommandLine => {
fault ← TRUE;
CONTINUE;
}];
IF fault THEN RETURN;
ProduceIPMaster[cmd, fileHandle];
END;
Commander.Register[
key: "GerberToIP", proc: GerberToIPProc, doc: "Transform a gerber file into an interpress file.\n"];
END.