GetNumber:
PROC [in:
IO.
STREAM]
RETURNS [x:
INT ← 0] ~ {
negatif: BOOLEAN ← FALSE;
c: CHAR ← IO.GetChar[in];
IF c = '-
THEN {
negatif ← TRUE;
c ← IO.GetChar[in];
};
IF c = '+ THEN c ← IO.GetChar[in];
WHILE c
IN ['0..'9]
DO
x ← 10 * x + c - '0;
c ← IO.GetChar[in];
ENDLOOP;
IO.Backup[in, c];
IF negatif THEN x ← -x;
};
FindPosition:
PROC [fileInfo: FileInfo] ~ {
oldPos, pos: Vector;
d: CARD;
c: CHAR;
end: BOOLEAN ← FALSE;
length, maxLength: CARD ← 0;
in: IO.STREAM ← FS.StreamOpen[fileInfo.oldName];
WHILE
NOT
IO.EndOf[in]
DO
c ← IO.GetChar[in];
SELECT c
FROM
='X => {
pos.x ← GetNumber[in];
};
='Y => {
pos.y ← GetNumber[in];
};
='D => {
d ← GetNumber[in];
};
='* => {
-- Action takes place after a '*
SELECT d
FROM
=0 => d ← 0 ; --Not yet initialised
=1 => {
--Draw
fileInfo.min.x ← MIN[fileInfo.min.x, pos.x];
fileInfo.min.y ← MIN[fileInfo.min.y, pos.y];
fileInfo.max.x ← MAX[fileInfo.max.x, pos.x];
fileInfo.max.y ← MAX[fileInfo.max.y, pos.y];
length ← ABS[oldPos.x-pos.x]+ABS[oldPos.y-pos.y];
IF length > maxLength THEN { -- Takes the biggest line
maxLength ← length;
fileInfo.midLine.x ← (oldPos.x+pos.x)/2;
fileInfo.midLine.y ← (oldPos.y+pos.y)/2;
};
IF (length = maxLength)
AND (((oldPos.x+pos.x)/2 < fileInfo.midLine.x)
OR ((oldPos.y+pos.y)/2 < fileInfo.midLine.y))
THEN {
-- Order the lines of equal length
fileInfo.midLine.x ← (oldPos.x+pos.x)/2;
fileInfo.midLine.y ← (oldPos.y+pos.y)/2;
};
oldPos ← pos;
};
=2 => {
--Move
IF
NOT end
THEN {
-- Moves to 0,0 at the end of the file !
fileInfo.min.x ← MIN[fileInfo.min.x, pos.x];
fileInfo.min.y ← MIN[fileInfo.min.y, pos.y];
fileInfo.max.x ← MAX[fileInfo.max.x, pos.x];
fileInfo.max.y ← MAX[fileInfo.max.y, pos.y];
};
oldPos ← pos;
};
=3 => {
--Flash
fileInfo.min.x ← MIN[fileInfo.min.x, pos.x];
fileInfo.min.y ← MIN[fileInfo.min.y, pos.y];
fileInfo.max.x ← MAX[fileInfo.max.x, pos.x];
fileInfo.max.y ← MAX[fileInfo.max.y, pos.y];
};
ENDCASE;
};
ENDCASE;
ENDLOOP;
};
ModifyEachFile:
PROC [fileInfo: FileInfo, commands: Commands, dx:
CARD , dy:
CARD] ~ {
pos, rel: Vector;
c: CHAR;
in2: IO.STREAM;
aperture: CARD;
d: INT ← 0;
in: IO.STREAM ← FS.StreamOpen[fileInfo.oldName];
out: IO.STREAM ← FS.StreamOpen[fileInfo.newName, $create];
WHILE
NOT
IO.EndOf[in]
DO
c ← IO.GetChar[in];
SELECT c
FROM
='G => {
IO.PutChar[out, 'G];
PutNumber[out, GetNumber[in]];
};
='X => {
pos.x ← GetNumber[in];
IO.PutChar[out, 'X];
PutNumber[out, pos.x-fileInfo.midLine.x+dx];
};
='Y => {
pos.y ← GetNumber[in];
IO.PutChar[out, 'Y];
PutNumber[out, fileInfo.midLine.y-pos.y+dy];
};
='D => {
d ← GetNumber[in];
SELECT d
FROM
IN [1..2] => {
IO.PutChar[out, c];
PutNumber[out, d]; --Draw or Move
};
=3 => {
--Flash
}; -- Takes realy place after a *
IN [4..99] => {
--Select aperture
IO.PutChar[out, c];
PutNumber[out, d];
aperture ← GerberToWheelNumber[d];
};
ENDCASE => ERROR;
};
='\n => IO.PutChar[out, c];
='* => {
IF d # 3
THEN {
IO.PutChar[out, c]
}
ELSE {
IF commands.newCommand[aperture] = NIL
THEN {
IO.PutF[out, "D3*"];
}
ELSE {
in2 ← IO.RIS[commands.newCommand[aperture]];
WHILE
NOT
IO.EndOf[in2]
DO
c ← IO.GetChar[in2];
SELECT c
FROM
='X => {
rel.x ← GetNumber[in2];
IO.PutChar[out, 'X];
PutNumber[out, rel.x+pos.x-fileInfo.midLine.x+dx];
};
='Y => {
rel.y ← GetNumber[in2];
IO.PutChar[out, 'Y];
PutNumber[out, rel.y+fileInfo.midLine.y-pos.y+dy];
};
='\040 => {
-- Skips spaces
};
ENDCASE => {
IO.PutChar[out, c];
};
ENDLOOP;
IO.PutF[out, "\nG54D%g*X%gY%g", IO.card[WheelToGerberNumber[aperture]], IO.card[pos.x-fileInfo.midLine.x+dx], IO.card[fileInfo.midLine.y-pos.y+dy]];
};
};
};
ENDCASE;
ENDLOOP;
IO.Close[out];
};
ReadCommands:
PROC [commandFile:
ROPE]
RETURNS [commands: Commands] ~ {
r: ROPE;
fileInfo: FileInfo;
oldAperture: NAT;
in: IO.STREAM ← FS.StreamOpen[commandFile];
commands ← NEW[CommandsRep];
FOR i:
NAT
IN [1..24]
DO
commands.newCommand[i] ← NIL;
ENDLOOP;
WHILE
NOT
IO.EndOf[in]
DO
r ← NIL;
r ← IO.GetTokenRope[in! IO.EndOfStream => CONTINUE].token;
SELECT
TRUE
FROM
Rope.Equal[r, "ApertureModification",
FALSE] => {
oldAperture ← IO.GetCard[in];
commands.newCommand[oldAperture] ← IO.GetLineRope[in];
};
Rope.Equal[r, "File",
FALSE] => {
fileInfo ← NEW[FileInfoRep];
fileInfo.oldName ← IO.GetTokenRope[in].token;
fileInfo.newName ← IO.GetTokenRope[in].token;
commands.fileList ← CONS[fileInfo, commands.fileList];
};
r = NIL => r ← NIL;
ENDCASE => ERROR;
ENDLOOP;
};
ModifyGerberFilesProc: Commander.CommandProc =
BEGIN
min, max: Vector ← [0,0];
commandFile: ROPE ← IO.GetTokenRope[IO.RIS[cmd.commandLine]].token;
commands: Commands ← ReadCommands[commandFile];
commands.fileList ← NARROW[GList.Reverse[commands.fileList]];
IO.PutF[cmd.out, "Reading the source files to find how to justify them\n"];
FOR l: FileList ← commands.fileList, l.rest
UNTIL l =
NIL
DO
IO.PutF[cmd.out, "Reading %g \n", IO.rope[l.first.oldName]];
FindPosition[l.first];
ENDLOOP;
Taking the center of the longest line as reference what is the smallest rectangle fitting all the drawings
FOR l: FileList ← commands.fileList, l.rest
UNTIL l =
NIL
DO
min.x ← MIN[min.x, l.first.min.x - l.first.midLine.x];
min.y ← MIN[min.y, l.first.min.y - l.first.midLine.y];
max.x ← MAX[max.x, l.first.max.x - l.first.midLine.x];
max.y ← MAX[max.y, l.first.max.y - l.first.midLine.y];
ENDLOOP;
The new coordinates are:
newx ← oldx - midline.x - min.x + epsilon
newy ← midline.y - oldy + max.y + epsilon
IO.PutF[cmd.out, "Generating the new files\n"];
FOR l: FileList ← commands.fileList, l.rest
UNTIL l =
NIL
DO
IO.PutF[cmd.out, "Reading %g and writing %g\n", IO.rope[l.first.oldName], IO.rope[l.first.newName]];
ModifyEachFile[l.first, commands, -min.x+100, max.y+100];
ENDLOOP;
END;
Commander.Register[
key: "ModifyGerberFiles", proc: ModifyGerberFilesProc, doc: "Transform a set of gerber files to prepare them for photoploting (Invert the Y axis, justify the drawings and change some aperture shooting by an arbitrary pattern).\n"];