1116 lines
25 KiB
Plaintext
1116 lines
25 KiB
Plaintext
|
|
//
|
||
|
|
// Generate g-code for milling PC boards.
|
||
|
|
//
|
||
|
|
// Copyright 2004-2013 by John Johnson Software, LLC.
|
||
|
|
// See readme.html for copyright information.
|
||
|
|
//
|
||
|
|
// See pcb-defaults.h, gcode-defaults.h and pcb-machine.h for options.
|
||
|
|
//
|
||
|
|
|
||
|
|
#include "source/pcb-gcode.h"
|
||
|
|
#include "source/pcb-gcode-stack.h"
|
||
|
|
#include "settings/pcb-defaults.h"
|
||
|
|
#include "settings/pcb-machine.h"
|
||
|
|
#include "settings/gcode-defaults.h"
|
||
|
|
#include "settings/pcb-gcode-options.h"
|
||
|
|
#include "settings/user-gcode.h"
|
||
|
|
#include "source/math.h"
|
||
|
|
#include "source/drill.h"
|
||
|
|
#include "source/library.h"
|
||
|
|
#include "source/pcb-file-utils.h"
|
||
|
|
#include "source/filename_subs.h"
|
||
|
|
|
||
|
|
#usage "<center><b>pcb-gcode™ Gcode Generation Utility</b><br>"
|
||
|
|
" Version 3.6.0.4<p>"
|
||
|
|
"Copyright© 2004 - 2013 by John Johnson Software, LLC<br>"
|
||
|
|
"All Rights Reserved</center>"
|
||
|
|
"<p>"
|
||
|
|
"Join the Yahoo! pcb-gcode group "
|
||
|
|
"<a href=http://groups.yahoo.com/group/pcb-gcode>http://groups.yahoo.com/group/pcb-gcode</a>"
|
||
|
|
"<br>or contact the author at <a href=mailto:pcbgcode@pcbgcode.org>pcbgcode@pcbgcode.org</a>"
|
||
|
|
"<br>"
|
||
|
|
"<hr>"
|
||
|
|
"This program generates g-code for 'mechanically etching' PC boards. "
|
||
|
|
"Using a CNC router or milling machine, you can make PC boards without using etching chemicals.<p />"
|
||
|
|
"It will create files for the outlines of tracks, drilling holes, and milling cutouts in the board."
|
||
|
|
"<br>See the <a href=file://readme.html>readme.html</a> file for more info.<p>"
|
||
|
|
"There are <em>many</em> options in the setup program.<br />"
|
||
|
|
"To setup which files are generated, and how, use the following command:<br>"
|
||
|
|
"<code>run pcb-gcode --setup</code><p>"
|
||
|
|
"<p/>"
|
||
|
|
"If you want to produce a set of files without changing options, you can run pcb-gcode directly."
|
||
|
|
"Usage is as follows:<br>"
|
||
|
|
"<code>run pcb-gcode [option] [file]</code><br>"
|
||
|
|
"Where:\n"
|
||
|
|
"<table>"
|
||
|
|
"<tr><td><em>Option</em></td><td><em>Function</em></td></tr>"
|
||
|
|
"<tr><td><code>--help</code></td><td>Show this help screen</td></tr>"
|
||
|
|
"<tr><td><code>--setup</code></td><td>Run the setup / configuration program</td></tr>"
|
||
|
|
"<tr><td><code>file</code></td><td>Is the optional root filename.\n</td></tr>"
|
||
|
|
"<tr><td></td><td>If not given, the board name is used as the root filename.</td></tr>"
|
||
|
|
"</table>"
|
||
|
|
"</td></tr>"
|
||
|
|
"</table>"
|
||
|
|
"<hr>"
|
||
|
|
|
||
|
|
g_width = DEFAULT_WIDTH;
|
||
|
|
|
||
|
|
// Filename to output to.
|
||
|
|
string m_file_name = "";
|
||
|
|
|
||
|
|
// Which side we're currently working on.
|
||
|
|
g_side = TOP;
|
||
|
|
|
||
|
|
// Tool currently being used.
|
||
|
|
int m_current_tool = 0;
|
||
|
|
|
||
|
|
// Amount to isolate traces.
|
||
|
|
real m_isolate = 0.0;
|
||
|
|
|
||
|
|
// Used to pass the pass info to the next pass of the program.
|
||
|
|
int m_pass_num;
|
||
|
|
|
||
|
|
// The layer being worked on.
|
||
|
|
int m_layer;
|
||
|
|
|
||
|
|
// Used to create command strings.
|
||
|
|
string g_cmd;
|
||
|
|
string g_cmd_temp;
|
||
|
|
|
||
|
|
// Save the maximum and minimum coordinates.
|
||
|
|
real m_max_x;
|
||
|
|
real m_max_y;
|
||
|
|
real m_min_x;
|
||
|
|
real m_min_y;
|
||
|
|
void save_extents(real x, real y)
|
||
|
|
{
|
||
|
|
m_max_x = max(m_max_x, x);
|
||
|
|
m_max_y = max(m_max_y, y);
|
||
|
|
m_min_x = min(m_min_x, x);
|
||
|
|
m_min_y = min(m_min_y, y);
|
||
|
|
}
|
||
|
|
|
||
|
|
void preview()
|
||
|
|
{
|
||
|
|
if (SHOW_PREVIEW) {
|
||
|
|
switch(get_os()) {
|
||
|
|
case OS_MACOSX:
|
||
|
|
system(g_path + "/viewer/application.macosx/viewer.app/Contents/MacOS/JavaApplicationStub");
|
||
|
|
break;
|
||
|
|
case OS_LINUX:
|
||
|
|
system(g_path + "/source/viewer.linux.sh");
|
||
|
|
break;
|
||
|
|
case OS_WINDOWS:
|
||
|
|
system(g_path + "/viewer/application.windows/viewer.exe");
|
||
|
|
dlgMessageBox("Close this window when you have finished with the preview");
|
||
|
|
break;
|
||
|
|
default:
|
||
|
|
Fatal("Oops!", "Can't figure out which OS you have.");
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
//
|
||
|
|
// Determine the next phase, and set g_phase accordingly.
|
||
|
|
//
|
||
|
|
// Params: none
|
||
|
|
// Return: none
|
||
|
|
//
|
||
|
|
void next_phase(void)
|
||
|
|
{
|
||
|
|
if (g_phase == PH_TOP_OUT_GEN && GENERATE_TOP_OUTLINES != YES) {
|
||
|
|
g_phase += 2;
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
if (g_phase == PH_BOTTOM_OUT_GEN && GENERATE_BOTTOM_OUTLINES != YES) {
|
||
|
|
g_phase += 2;
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
if (g_phase == PH_TOP_OUT_WRITE || g_phase == PH_BOTTOM_OUT_WRITE) {
|
||
|
|
if (m_isolate < ISO_MAX && !SINGLE_PASS) {
|
||
|
|
m_isolate += ISO_STEP;
|
||
|
|
m_pass_num++;
|
||
|
|
g_phase--;
|
||
|
|
}
|
||
|
|
else {
|
||
|
|
m_isolate = ISO_MIN;
|
||
|
|
m_pass_num = 0;
|
||
|
|
g_phase++;
|
||
|
|
|
||
|
|
preview();
|
||
|
|
}
|
||
|
|
}
|
||
|
|
else {
|
||
|
|
g_phase++;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
//////////////////////////////////////////////////
|
||
|
|
//
|
||
|
|
// Hole drilling routines.
|
||
|
|
//
|
||
|
|
//////////////////////////////////////////////////
|
||
|
|
|
||
|
|
//
|
||
|
|
// Add a hole drilling command to the command string.
|
||
|
|
//
|
||
|
|
// Params:
|
||
|
|
// Size Drill size.
|
||
|
|
// x x coordinate.
|
||
|
|
// y y coordinate.
|
||
|
|
// Returns:
|
||
|
|
// none
|
||
|
|
// Changes:
|
||
|
|
// the stack
|
||
|
|
//
|
||
|
|
void add_hole(int req_size, int x, int y)
|
||
|
|
{
|
||
|
|
string tempstr;
|
||
|
|
int drill_size;
|
||
|
|
|
||
|
|
drill_size = get_drill_for(req_size);
|
||
|
|
|
||
|
|
sprintf(tempstr, "%06d\t%06d\t%06d", drill_size, x, y);
|
||
|
|
stack_push(tempstr);
|
||
|
|
}
|
||
|
|
|
||
|
|
/*
|
||
|
|
* Create a drill file for the desired side.
|
||
|
|
*
|
||
|
|
* Params:
|
||
|
|
* which_side Side to produce the file for.
|
||
|
|
* suffix Suffix to use for the file name (i.e. bd).
|
||
|
|
* Returns:
|
||
|
|
* none
|
||
|
|
* Changes:
|
||
|
|
* side
|
||
|
|
*/
|
||
|
|
void drill(int which_side, string suffix)
|
||
|
|
{
|
||
|
|
int num_lines;
|
||
|
|
int i;
|
||
|
|
real last_size;
|
||
|
|
string drill_args[];
|
||
|
|
m_current_tool = 0;
|
||
|
|
real drill_size_mm;
|
||
|
|
real drill_size_inch;
|
||
|
|
real drill_size;
|
||
|
|
real drill_x;
|
||
|
|
real drill_y;
|
||
|
|
int drill_tool_num;
|
||
|
|
|
||
|
|
g_side = which_side;
|
||
|
|
|
||
|
|
//
|
||
|
|
// Build a stack with all the holes.
|
||
|
|
//
|
||
|
|
board(B) {
|
||
|
|
B.holes(H) add_hole(H.drill, H.x, H.y);
|
||
|
|
B.signals(S) S.vias(V) add_hole(V.drill, V.x, V.y);
|
||
|
|
B.elements(E) {
|
||
|
|
E.package.contacts(C) {
|
||
|
|
if (C.pad) {
|
||
|
|
add_hole(C.pad.drill, C.pad.x, C.pad.y);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
E.package.holes(H) add_hole(H.drill, H.x, H.y);
|
||
|
|
}
|
||
|
|
// B.elements
|
||
|
|
|
||
|
|
// Sorts the drills by size, x and y.
|
||
|
|
stack_sort();
|
||
|
|
|
||
|
|
//
|
||
|
|
// Create the drill g-code file.
|
||
|
|
//
|
||
|
|
last_size = -1;
|
||
|
|
output(get_filename(), "wt") {
|
||
|
|
output_file_preamble();
|
||
|
|
|
||
|
|
//
|
||
|
|
// Create a tool table at the beginning of the file.
|
||
|
|
//
|
||
|
|
out(TOOL_CHANGE_TABLE_HEADER);
|
||
|
|
for (i=stack_fwd_iter(); i != END_OF_STACK; i=stack_fwd_next()) {
|
||
|
|
if (i==END_OF_STACK) break;
|
||
|
|
strsplit(drill_args, stack_elem(i), '\t');
|
||
|
|
drill_size_inch = u2inch(my_strtol(drill_args[DRILL_SIZE]));
|
||
|
|
drill_size_mm = u2mm(my_strtol(drill_args[DRILL_SIZE]));
|
||
|
|
drill_size = my_strtol(drill_args[DRILL_SIZE]);
|
||
|
|
|
||
|
|
if (drill_size != last_size) {
|
||
|
|
++m_current_tool;
|
||
|
|
drill_tool_num = get_tool_num_for(my_strtol(drill_args[DRILL_SIZE]), m_current_tool);
|
||
|
|
out(TOOL_CHANGE_TABLE_FORMAT(drill_tool_num,
|
||
|
|
drill_size_mm, drill_size_inch,
|
||
|
|
g_mins[drill_tool_num], g_maxs[drill_tool_num],
|
||
|
|
g_drill_sub_cnt[drill_tool_num]));
|
||
|
|
}
|
||
|
|
last_size = drill_size;
|
||
|
|
}
|
||
|
|
// for
|
||
|
|
|
||
|
|
// Set the mode for the user's UOM.
|
||
|
|
out(get_mode());
|
||
|
|
out(ABSOLUTE_MODE);
|
||
|
|
|
||
|
|
//
|
||
|
|
// Generate drill code.
|
||
|
|
//
|
||
|
|
m_current_tool = 0;
|
||
|
|
for (i=stack_fwd_iter(); i != END_OF_STACK; i=stack_fwd_next()) {
|
||
|
|
strsplit(drill_args, stack_elem(i), '\t');
|
||
|
|
drill_size = units(my_strtol(drill_args[DRILL_SIZE]));
|
||
|
|
drill_x = scale_x(my_strtol(drill_args[DRILL_X]));
|
||
|
|
drill_y = scale_y(my_strtol(drill_args[DRILL_Y]));
|
||
|
|
save_extents(drill_x, drill_y);
|
||
|
|
|
||
|
|
if (drill_size == last_size) {
|
||
|
|
output_drill_hole(drill_x, drill_y, DRILL_DEPTH);
|
||
|
|
}
|
||
|
|
else {
|
||
|
|
m_current_tool++;
|
||
|
|
// Tool change routine
|
||
|
|
output_tool_change_begin();
|
||
|
|
out(SPINDLE_OFF);
|
||
|
|
rz(TOOL_CHANGE_POS_Z);
|
||
|
|
rxy(TOOL_CHANGE_POS_X, TOOL_CHANGE_POS_Y);
|
||
|
|
out(fir(TOOL_CHANGE, get_tool_num_for(my_strtol(drill_args[DRILL_SIZE]), m_current_tool), drill_size));
|
||
|
|
output_tool_changed();
|
||
|
|
|
||
|
|
if (DO_TOOL_CHANGE_WITH_ZERO_STEP == YES) {
|
||
|
|
output_tool_zero_begin();
|
||
|
|
fzr(0.000, FEED_RATE_Z);
|
||
|
|
// fixme: wondering about the following line
|
||
|
|
out(fir(TOOL_CHANGE, m_current_tool, drill_size));
|
||
|
|
output_tool_zero_end();
|
||
|
|
}
|
||
|
|
|
||
|
|
rz(DEFAULT_Z_UP);
|
||
|
|
out(fr(SPINDLE_ON, SPINDLE_ON_TIME));
|
||
|
|
output_tool_change_end();
|
||
|
|
|
||
|
|
output_drill_first_hole(drill_x, drill_y, DRILL_DEPTH);
|
||
|
|
last_size = drill_size;
|
||
|
|
}
|
||
|
|
// if drill_size != last_size
|
||
|
|
}
|
||
|
|
// for
|
||
|
|
|
||
|
|
output_file_postamble();
|
||
|
|
|
||
|
|
// End of file
|
||
|
|
// change back to tool 1
|
||
|
|
out(fi(TOOL_CODE + EOL, 1));
|
||
|
|
end_gcode();
|
||
|
|
}
|
||
|
|
// output
|
||
|
|
}
|
||
|
|
// Board
|
||
|
|
}
|
||
|
|
// drill
|
||
|
|
|
||
|
|
int m_first_spot_drill = YES;
|
||
|
|
void spot_drill_hole(int x, int y)
|
||
|
|
{
|
||
|
|
real drill_x;
|
||
|
|
real drill_y;
|
||
|
|
|
||
|
|
drill_x = scale_x(x);
|
||
|
|
drill_y = scale_y(y);
|
||
|
|
save_extents(drill_x, drill_y);
|
||
|
|
|
||
|
|
if (m_first_spot_drill) {
|
||
|
|
output_drill_first_hole(drill_x, drill_y, SPOT_DRILL_DEPTH);
|
||
|
|
m_first_spot_drill = NO;
|
||
|
|
}
|
||
|
|
else {
|
||
|
|
output_drill_hole(drill_x, drill_y, SPOT_DRILL_DEPTH);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
void spot_drill(UL_BOARD B)
|
||
|
|
{
|
||
|
|
if (SPOT_DRILL == NO) { return; }
|
||
|
|
|
||
|
|
B.holes(H) spot_drill_hole(H.x, H.y);
|
||
|
|
B.signals(S) S.vias(V) spot_drill_hole(V.x, V.y);
|
||
|
|
B.elements(E) {
|
||
|
|
E.package.contacts(C) {
|
||
|
|
if (C.pad) {
|
||
|
|
spot_drill_hole(C.pad.x, C.pad.y);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
E.package.holes(H) spot_drill_hole(H.x, H.y);
|
||
|
|
}
|
||
|
|
// B.elements
|
||
|
|
}
|
||
|
|
|
||
|
|
string m_lines;
|
||
|
|
string LINE_SEP = "\n";
|
||
|
|
string COORD_SEP = ",";
|
||
|
|
string COORD_FMT = "%8.5f";
|
||
|
|
|
||
|
|
string coords(real x1, real y1, real x2, real y2)
|
||
|
|
{
|
||
|
|
return frrrr(COORD_FMT + COORD_SEP + COORD_FMT + COORD_SEP +
|
||
|
|
COORD_FMT + COORD_SEP + COORD_FMT + LINE_SEP, x1, y1, x2, y2);
|
||
|
|
}
|
||
|
|
|
||
|
|
//
|
||
|
|
// "Draw" on the output device, i.e. the gcode file.
|
||
|
|
//
|
||
|
|
// Params:
|
||
|
|
// x1,y1 Start of the line.
|
||
|
|
// x2,y2 End of the line.
|
||
|
|
// state
|
||
|
|
// z_down
|
||
|
|
// Returns:
|
||
|
|
// none
|
||
|
|
//
|
||
|
|
real m_arc_begin_x;
|
||
|
|
real m_arc_begin_y;
|
||
|
|
int pair_count = 0;
|
||
|
|
int MAX_COORDS_PER_LINE = 4;
|
||
|
|
void device_draw(int x1, int y1, int x2, int y2, int state, real z_down)
|
||
|
|
{
|
||
|
|
real rx1, ry1, rx2, ry2;
|
||
|
|
|
||
|
|
rx1 = scale_x(x1);
|
||
|
|
ry1 = scale_y(y1);
|
||
|
|
rx2 = scale_x(x2);
|
||
|
|
ry2 = scale_y(y2);
|
||
|
|
save_extents(rx1, ry1);
|
||
|
|
save_extents(rx2, ry2);
|
||
|
|
|
||
|
|
// Output g-code based on the current state.
|
||
|
|
switch(state) {
|
||
|
|
|
||
|
|
// Start of a new line.
|
||
|
|
case ST_START_LINE:
|
||
|
|
user_track_begin(rx1, ry1, rx2, ry2);
|
||
|
|
|
||
|
|
m_lines += coords(rx1, ry1, rx2, ry2);
|
||
|
|
|
||
|
|
rz(DEFAULT_Z_UP);
|
||
|
|
rxy(rx1, ry1);
|
||
|
|
fzr(z_down, FEED_RATE_Z);
|
||
|
|
fxyr(rx2, ry2, FEED_RATE);
|
||
|
|
pair_count = 0;
|
||
|
|
break;
|
||
|
|
|
||
|
|
// A fill line.
|
||
|
|
case ST_FILL:
|
||
|
|
Fatal("Programmer Error", "The Fill functions are no longer supported.");
|
||
|
|
break;
|
||
|
|
|
||
|
|
// Continue a line.
|
||
|
|
// End a line.
|
||
|
|
case ST_CONTINUE_LINE:
|
||
|
|
user_track_continue(rx1, ry1, rx2, ry2);
|
||
|
|
|
||
|
|
m_lines += coords(rx1, ry1, rx2, ry2);
|
||
|
|
|
||
|
|
if (COMPACT_GCODE == YES) {
|
||
|
|
if (pair_count == 0) {
|
||
|
|
fxy(rx2, ry2);
|
||
|
|
}
|
||
|
|
else {
|
||
|
|
xy(rx2, ry2);
|
||
|
|
}
|
||
|
|
pair_count++;
|
||
|
|
}
|
||
|
|
else {
|
||
|
|
fxy(rx2, ry2);
|
||
|
|
}
|
||
|
|
break;
|
||
|
|
|
||
|
|
case ST_END_LINE:
|
||
|
|
user_track_end(rx1, ry1, rx2, ry2);
|
||
|
|
|
||
|
|
m_lines += coords(rx1, ry1, rx2, ry2);
|
||
|
|
|
||
|
|
|
||
|
|
if (COMPACT_GCODE == YES) {
|
||
|
|
xy(rx2, ry2);
|
||
|
|
pair_count = 0;
|
||
|
|
}
|
||
|
|
else {
|
||
|
|
fxy(rx2, ry2);
|
||
|
|
}
|
||
|
|
break;
|
||
|
|
|
||
|
|
// Drill a hole.
|
||
|
|
// todo is this valid?
|
||
|
|
case ST_DRILL:
|
||
|
|
printf("cause an error if used %d");
|
||
|
|
// printf("drill (%f, %f)\n", rx2, ry2);
|
||
|
|
break;
|
||
|
|
|
||
|
|
// Create an arc.
|
||
|
|
case ST_ARC_BEGIN:
|
||
|
|
user_arc_begin(rx1, ry1, rx2, ry2);
|
||
|
|
m_arc_begin_x = rx1;
|
||
|
|
m_arc_begin_y = ry1;
|
||
|
|
break;
|
||
|
|
|
||
|
|
// Finish an arc.
|
||
|
|
case ST_ARC_END:
|
||
|
|
user_arc_end(rx1, ry1, rx2, ry2);
|
||
|
|
real cx = rx2;
|
||
|
|
real cy = ry2;
|
||
|
|
real end_x = rx1;
|
||
|
|
real end_y = ry1;
|
||
|
|
|
||
|
|
if (1 /* USE_IJ_RELATIVE */) {
|
||
|
|
cx = rx2 - rx1;
|
||
|
|
cy = ry2 - ry1;
|
||
|
|
}
|
||
|
|
|
||
|
|
rz(DEFAULT_Z_UP);
|
||
|
|
rxy(end_x, end_y);
|
||
|
|
fzr(z_down, FEED_RATE_Z);
|
||
|
|
if (g_side == TOP || MIRROR_BOTTOM == YES) {
|
||
|
|
out(frrrr(CIRCLE_TOP, m_arc_begin_x, m_arc_begin_y, cx, cy));
|
||
|
|
}
|
||
|
|
else {
|
||
|
|
out(frrrr(CIRCLE_BOTTOM, m_arc_begin_x, m_arc_begin_y, cx, cy));
|
||
|
|
}
|
||
|
|
break;
|
||
|
|
|
||
|
|
}
|
||
|
|
// switch(state)
|
||
|
|
}
|
||
|
|
// device_draw
|
||
|
|
|
||
|
|
|
||
|
|
//
|
||
|
|
// Generate polygons for outline or fill.
|
||
|
|
// This creates a series of commands for Eagle and puts them
|
||
|
|
// in g_cmd to be passed when we exit from this phase of pcb-gcode.
|
||
|
|
//
|
||
|
|
// Params:
|
||
|
|
// which_side The side to operate on.
|
||
|
|
// Return:
|
||
|
|
// none
|
||
|
|
//
|
||
|
|
void generate_outlines(int which_side)
|
||
|
|
{
|
||
|
|
string cmd_temp = "";
|
||
|
|
|
||
|
|
g_cmd = "";
|
||
|
|
|
||
|
|
if (which_side == TOP)
|
||
|
|
m_layer = TOP_LAYER;
|
||
|
|
else
|
||
|
|
m_layer = BOTTOM_LAYER;
|
||
|
|
|
||
|
|
board(B) {
|
||
|
|
real f = BORDER_SIZE;
|
||
|
|
real x1 = units(B.area.x1) - f;
|
||
|
|
real y1 = units(B.area.y1) - f;
|
||
|
|
real x2 = units(B.area.x2) + f;
|
||
|
|
real y2 = units(B.area.y2) + f;
|
||
|
|
|
||
|
|
B.signals(S) {
|
||
|
|
if (S.name == OUTLINES_SIGNAL_NAME) {
|
||
|
|
sprintf(cmd_temp, "delete (%f %f) (%f %f);\n",
|
||
|
|
x1, y1, x2, y2);
|
||
|
|
g_cmd = g_cmd + cmd_temp;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
sprintf(cmd_temp, "grid %s;\n"
|
||
|
|
"change isolate %f;\n"
|
||
|
|
"change rank 6;\n"
|
||
|
|
"change pour solid;\n"
|
||
|
|
"change width %f;\n"
|
||
|
|
"change orphans on;\n"
|
||
|
|
"layer %d;\n"
|
||
|
|
"polygon %s %f (%f %f) (%f %f) (%f %f) (%f %f) (%f %f);\n"
|
||
|
|
"ratsnest;\n"
|
||
|
|
,
|
||
|
|
UNIT_OF_MEASURE,
|
||
|
|
m_isolate,
|
||
|
|
g_width,
|
||
|
|
m_layer,
|
||
|
|
OUTLINES_SIGNAL_NAME, g_width,
|
||
|
|
x1, y1, x2, y1, x2, y2, x1, y2, x1, y1
|
||
|
|
);
|
||
|
|
g_cmd = g_cmd + cmd_temp;
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
// board(B)
|
||
|
|
}
|
||
|
|
// generate_outlines
|
||
|
|
|
||
|
|
void out_lines(string path, string mode)
|
||
|
|
{
|
||
|
|
output(path, mode) {
|
||
|
|
if (m_pass_num == 0) {
|
||
|
|
printf("# board=%s\n", elided_path(get_filename(), 30));
|
||
|
|
printf("# tool size=%f\n", g_width);
|
||
|
|
}
|
||
|
|
printf("# pass=%d\n", m_pass_num + 1);
|
||
|
|
printf(m_lines);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
//
|
||
|
|
// Write text from the Milling layer to a text engraving file.
|
||
|
|
//
|
||
|
|
// Params:
|
||
|
|
// file_name Output filename.
|
||
|
|
// Return:
|
||
|
|
// none
|
||
|
|
//
|
||
|
|
void output_text_code(string file_name)
|
||
|
|
{
|
||
|
|
int state;
|
||
|
|
int old_x, old_y;
|
||
|
|
|
||
|
|
board(B) {
|
||
|
|
output(get_filename(), "wt") {
|
||
|
|
user_file_opened(get_filename(), "wt");
|
||
|
|
|
||
|
|
output_file_preamble();
|
||
|
|
|
||
|
|
// Initialize the device (i.e. the output file).
|
||
|
|
begin_gcode();
|
||
|
|
|
||
|
|
// Process all the wires.
|
||
|
|
B.texts(T) T.wires(W) {
|
||
|
|
if ((T.mirror && g_side == BOTTOM) || (! T.mirror && g_side == TOP)) {
|
||
|
|
// If this is a text layer, check if we should continue
|
||
|
|
// a line, or start a new one.
|
||
|
|
if (W.layer == TEXT_LAYER) {
|
||
|
|
if (W.x1 == old_x && W.y1 == old_y) {
|
||
|
|
state = ST_CONTINUE_LINE;
|
||
|
|
}
|
||
|
|
else {
|
||
|
|
state = ST_START_LINE;
|
||
|
|
}
|
||
|
|
|
||
|
|
// if this is an arc, it is treated specially.
|
||
|
|
if (W.arc) {
|
||
|
|
device_draw( W.arc.x1, W.arc.y1, W.arc.x2, W.arc.y2, ST_ARC_BEGIN, TEXT_DEPTH);
|
||
|
|
device_draw( W.arc.x2, W.arc.y2, W.arc.xc, W.arc.yc, ST_ARC_END, TEXT_DEPTH);
|
||
|
|
save_extents(W.x1, W.y1);
|
||
|
|
save_extents(W.x2, W.y2);
|
||
|
|
state = ST_START_LINE;
|
||
|
|
}
|
||
|
|
else {
|
||
|
|
// Draw the line (i.e. output the gcode for the line).
|
||
|
|
device_draw(W.x1, W.y1, W.x2, W.y2, state, TEXT_DEPTH);
|
||
|
|
old_x = W.x2;
|
||
|
|
old_y = W.y2;
|
||
|
|
save_extents(W.x1, W.y1);
|
||
|
|
save_extents(W.x2, W.y2);
|
||
|
|
}
|
||
|
|
// if (W.arc)
|
||
|
|
}
|
||
|
|
// if (W.layer == TEXT_LAYER)
|
||
|
|
}
|
||
|
|
// if (top and bottom check)
|
||
|
|
}
|
||
|
|
// T.wires
|
||
|
|
output_file_postamble();
|
||
|
|
end_gcode();
|
||
|
|
user_file_closing();
|
||
|
|
}
|
||
|
|
// output
|
||
|
|
user_file_closed(get_filename(), "wt");
|
||
|
|
}
|
||
|
|
// board
|
||
|
|
g_width = abs(TEXT_DEPTH);
|
||
|
|
out_lines(g_path + "/viewer/data/optimize_me.txt", "wt");
|
||
|
|
out_lines(g_path + "/viewer/applet/data/optimize_me.txt", "wt");
|
||
|
|
out_lines(g_path + "/viewer/application.macosx/data/optimize_me.txt", "wt");
|
||
|
|
out_lines(g_path + "/viewer/application.linux/data/optimize_me.txt", "wt");
|
||
|
|
out_lines(g_path + "/viewer/application.windows/data/optimize_me.txt", "wt");
|
||
|
|
|
||
|
|
preview();
|
||
|
|
|
||
|
|
m_lines = "";
|
||
|
|
}
|
||
|
|
// output_text_code
|
||
|
|
|
||
|
|
|
||
|
|
//
|
||
|
|
// Write layer data to mill files.
|
||
|
|
//
|
||
|
|
// Params:
|
||
|
|
// file_name Output filename.
|
||
|
|
// Return:
|
||
|
|
// none
|
||
|
|
//
|
||
|
|
void output_mill_code(string file_name)
|
||
|
|
{
|
||
|
|
int state;
|
||
|
|
int old_x, old_y;
|
||
|
|
|
||
|
|
board(B) {
|
||
|
|
output(get_filename(), "wt") {
|
||
|
|
user_file_opened(get_filename(), "wt");
|
||
|
|
|
||
|
|
output_file_preamble();
|
||
|
|
|
||
|
|
// Initialize the device (i.e. the output file).
|
||
|
|
begin_gcode();
|
||
|
|
|
||
|
|
// Process all the wires.
|
||
|
|
B.wires(W) W.pieces(P) {
|
||
|
|
// If this is a mill layer, check if we should continue
|
||
|
|
// a line, or start a new one.
|
||
|
|
if (P.layer == MILL_LAYER) {
|
||
|
|
if (P.x1 == old_x && P.y1 == old_y) {
|
||
|
|
state = ST_CONTINUE_LINE;
|
||
|
|
}
|
||
|
|
else {
|
||
|
|
state = ST_START_LINE;
|
||
|
|
}
|
||
|
|
|
||
|
|
// if this is an arc, it is treated specially.
|
||
|
|
if (P.arc) {
|
||
|
|
device_draw( P.arc.x1, P.arc.y1, P.arc.x2, P.arc.y2, ST_ARC_BEGIN, MILLING_DEPTH);
|
||
|
|
device_draw( P.arc.x2, P.arc.y2, P.arc.xc, P.arc.yc, ST_ARC_END, MILLING_DEPTH);
|
||
|
|
save_extents(P.x1, P.y1);
|
||
|
|
save_extents(P.x2, P.y2);
|
||
|
|
state = ST_START_LINE;
|
||
|
|
}
|
||
|
|
else {
|
||
|
|
// Draw the line (i.e. output the gcode for the line).
|
||
|
|
device_draw(P.x1, P.y1, P.x2, P.y2, state, MILLING_DEPTH);
|
||
|
|
old_x = P.x2;
|
||
|
|
old_y = P.y2;
|
||
|
|
save_extents(P.x1, P.y1);
|
||
|
|
save_extents(P.x2, P.y2);
|
||
|
|
}
|
||
|
|
// if (P.arc)
|
||
|
|
}
|
||
|
|
// if (P.layer == MILL_LAYER)
|
||
|
|
}
|
||
|
|
// pieces
|
||
|
|
output_file_postamble();
|
||
|
|
end_gcode();
|
||
|
|
user_file_closing();
|
||
|
|
}
|
||
|
|
// output
|
||
|
|
user_file_closed(get_filename(), "wt");
|
||
|
|
}
|
||
|
|
// board
|
||
|
|
|
||
|
|
g_width = abs(MILLING_DEPTH);
|
||
|
|
out_lines(g_path + "/viewer/data/optimize_me.txt", "wt");
|
||
|
|
out_lines(g_path + "/viewer/applet/data/optimize_me.txt", "wt");
|
||
|
|
out_lines(g_path + "/viewer/application.macosx/data/optimize_me.txt", "wt");
|
||
|
|
out_lines(g_path + "/viewer/application.linux/data/optimize_me.txt", "wt");
|
||
|
|
out_lines(g_path + "/viewer/application.windows/data/optimize_me.txt", "wt");
|
||
|
|
|
||
|
|
preview();
|
||
|
|
|
||
|
|
m_lines = "";
|
||
|
|
}
|
||
|
|
// output_mill_code
|
||
|
|
|
||
|
|
|
||
|
|
//
|
||
|
|
// Write polygon lines to the file.
|
||
|
|
//
|
||
|
|
// Params:
|
||
|
|
// which_side Side of the board to work on.
|
||
|
|
// suffix Suffix of the file.
|
||
|
|
// task
|
||
|
|
// Return:
|
||
|
|
// none
|
||
|
|
//
|
||
|
|
void write_outlines(int which_side, string suffix, int task)
|
||
|
|
{
|
||
|
|
string mode;
|
||
|
|
int x1 = INT_MAX, y1 = INT_MAX, x2 = INT_MIN, y2 = INT_MIN;
|
||
|
|
int x0, y0;
|
||
|
|
int first = 1;
|
||
|
|
int frame_wire;
|
||
|
|
int state;
|
||
|
|
|
||
|
|
if (m_pass_num == 0) {
|
||
|
|
mode = "wt";
|
||
|
|
}
|
||
|
|
else {
|
||
|
|
mode = "at";
|
||
|
|
}
|
||
|
|
g_side = which_side;
|
||
|
|
switch (which_side) {
|
||
|
|
case TOP:
|
||
|
|
m_layer = TOP_LAYER;
|
||
|
|
break;
|
||
|
|
case BOTTOM:
|
||
|
|
m_layer = BOTTOM_LAYER;
|
||
|
|
break;
|
||
|
|
case MILL:
|
||
|
|
m_layer = MILL_LAYER;
|
||
|
|
break;
|
||
|
|
case TEXT:
|
||
|
|
m_layer = TEXT_LAYER;
|
||
|
|
break;
|
||
|
|
default:
|
||
|
|
sprintf(g_debug, "Illegal which_side %d in write_outlines", which_side);
|
||
|
|
Fatal("Sorry...", g_debug);
|
||
|
|
}
|
||
|
|
|
||
|
|
if (m_layer == MILL_LAYER || m_layer == TEXT_LAYER) {
|
||
|
|
if (which_side == MILL) {
|
||
|
|
g_side = TOP;
|
||
|
|
output_mill_code(m_file_name + "mt" + DEFAULT_EXTENSION);
|
||
|
|
g_side = BOTTOM;
|
||
|
|
output_mill_code(m_file_name + "mb" + DEFAULT_EXTENSION);
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
else {
|
||
|
|
g_side = TOP;
|
||
|
|
output_text_code(m_file_name + "tt" + DEFAULT_EXTENSION);
|
||
|
|
g_side = BOTTOM;
|
||
|
|
output_text_code(m_file_name + "tb" + DEFAULT_EXTENSION);
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
// if m_layer == MILL_LAYER
|
||
|
|
|
||
|
|
output(get_filename(), mode) {
|
||
|
|
board(B) {
|
||
|
|
user_file_opened(get_filename(), mode);
|
||
|
|
|
||
|
|
int rubout_layer = -1;
|
||
|
|
B.layers(L) {
|
||
|
|
if (strstr(strlwr(L.name), "rubout") != -1) {
|
||
|
|
if (strstr(strlwr(L.name), "top") != -1 && which_side == TOP) {
|
||
|
|
rubout_layer = L.number;
|
||
|
|
}
|
||
|
|
else if (strstr(strlwr(L.name), "bot") != -1 && which_side == BOTTOM) {
|
||
|
|
rubout_layer = L.number;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
if (rubout_layer != -1) {
|
||
|
|
B.wires(W) {
|
||
|
|
if (W.layer == rubout_layer) {
|
||
|
|
device_draw(W.x1, W.y1, W.x2, W.y2, ST_START_LINE, DEFAULT_Z_DOWN);
|
||
|
|
device_draw(W.x1, W.y1, W.x2, W.y2, ST_END_LINE, DEFAULT_Z_DOWN); // fixme needed?
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
B.signals(S) {
|
||
|
|
if (S.name == OUTLINES_SIGNAL_NAME) {
|
||
|
|
S.polygons(P) {
|
||
|
|
P.wires(W) {
|
||
|
|
x1 = min(x1, W.x1);
|
||
|
|
x2 = max(x2, W.x1);
|
||
|
|
y1 = min(y1, W.y1);
|
||
|
|
y2 = max(y2, W.y1);
|
||
|
|
}
|
||
|
|
if (m_pass_num == 0) {
|
||
|
|
output_file_preamble();
|
||
|
|
begin_gcode();
|
||
|
|
}
|
||
|
|
else {
|
||
|
|
output_between_outline_passes();
|
||
|
|
}
|
||
|
|
|
||
|
|
switch (task) {
|
||
|
|
case TASK_OUTLINES:
|
||
|
|
// P.contours jtj
|
||
|
|
P.contours(W) {
|
||
|
|
if (first) {
|
||
|
|
x0 = W.x1;
|
||
|
|
y0 = W.y1;
|
||
|
|
frame_wire = (x0 == x1 || x0 == x2) && (y0 == y1 || y0 == y2);
|
||
|
|
state = ST_START_LINE;
|
||
|
|
first = 0;
|
||
|
|
}
|
||
|
|
else if (W.x2 == x0 && W.y2 == y0) {
|
||
|
|
state = ST_END_LINE;
|
||
|
|
first = 1;
|
||
|
|
}
|
||
|
|
else {
|
||
|
|
state = ST_CONTINUE_LINE;
|
||
|
|
}
|
||
|
|
|
||
|
|
if (!frame_wire) {
|
||
|
|
device_draw(W.x1, W.y1, W.x2, W.y2, state, DEFAULT_Z_DOWN);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
// P.contours(W)
|
||
|
|
break;
|
||
|
|
|
||
|
|
case TASK_FILL:
|
||
|
|
P.fillings(W) {
|
||
|
|
device_draw(W.x1, W.y1, W.x2, W.y2, ST_START_LINE, DEFAULT_Z_DOWN);
|
||
|
|
}
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
// switch(task)
|
||
|
|
|
||
|
|
if (m_isolate >= ISO_MAX || SINGLE_PASS || task == TASK_FILL) {
|
||
|
|
output_file_postamble();
|
||
|
|
rz(DEFAULT_Z_UP);
|
||
|
|
spot_drill(B);
|
||
|
|
end_gcode();
|
||
|
|
}
|
||
|
|
|
||
|
|
sprintf(g_cmd, "delete (%f %f) (%f %f);\n",
|
||
|
|
units(x1), units(y1), units(x2), units(y2)
|
||
|
|
);
|
||
|
|
}
|
||
|
|
// polygons
|
||
|
|
}
|
||
|
|
// if(S.name == OUTLINES_SIGNAL_NAME)
|
||
|
|
}
|
||
|
|
// signals
|
||
|
|
}
|
||
|
|
// board
|
||
|
|
user_file_closing();
|
||
|
|
}
|
||
|
|
// output
|
||
|
|
user_file_closed(get_filename(), mode);
|
||
|
|
out_lines(g_path + "/viewer/data/optimize_me.txt", mode);
|
||
|
|
out_lines(g_path + "/viewer/applet/data/optimize_me.txt", mode);
|
||
|
|
out_lines(g_path + "/viewer/application.macosx/data/optimize_me.txt", mode);
|
||
|
|
out_lines(g_path + "/viewer/application.linux/data/optimize_me.txt", mode);
|
||
|
|
out_lines(g_path + "/viewer/application.windows/data/optimize_me.txt", mode);
|
||
|
|
|
||
|
|
}
|
||
|
|
// write_outlines
|
||
|
|
|
||
|
|
/* string get_phase_name(int phase)
|
||
|
|
{
|
||
|
|
return PHASE_NAME[phase];
|
||
|
|
}
|
||
|
|
*/
|
||
|
|
void gen_progress_menu(int phase)
|
||
|
|
{
|
||
|
|
output(path_scr[0] + '/' + "source/pcb-gcode-prg.scr") {
|
||
|
|
printf("MENU \\\n");
|
||
|
|
for(int i = 1; i < PH_LAST_PHASE; i++) {
|
||
|
|
if (i == phase) {
|
||
|
|
printf("--%s-- \\\n", get_phase_name(i));
|
||
|
|
// " (for TextMate)
|
||
|
|
}
|
||
|
|
else {
|
||
|
|
printf(" %s \\\n", get_phase_name(i));
|
||
|
|
}
|
||
|
|
}
|
||
|
|
printf(";\n");
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// Make sure a board is available to work on.
|
||
|
|
// todo move towards bottom
|
||
|
|
if (!board) {
|
||
|
|
Fatal("No board!", "Please run this program from the board editor");
|
||
|
|
}
|
||
|
|
|
||
|
|
//
|
||
|
|
// Process command line arguments.
|
||
|
|
//
|
||
|
|
switch (OUTPUT_UNITS) {
|
||
|
|
case U_MICRONS:
|
||
|
|
UNIT_OF_MEASURE = "mic";
|
||
|
|
break;
|
||
|
|
case U_MILLIMETERS:
|
||
|
|
UNIT_OF_MEASURE = "mm";
|
||
|
|
break;
|
||
|
|
case U_MILS:
|
||
|
|
UNIT_OF_MEASURE = "mil";
|
||
|
|
break;
|
||
|
|
case U_INCHES:
|
||
|
|
UNIT_OF_MEASURE = "inch";
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
|
||
|
|
if (argv[FILENAME_ARG] == "--setup") {
|
||
|
|
exit("run pcb-gcode-setup");
|
||
|
|
}
|
||
|
|
|
||
|
|
if (argv[FILENAME_ARG] == "--attr") {
|
||
|
|
string attrs;
|
||
|
|
board(B) {
|
||
|
|
B.attributes(A) {
|
||
|
|
attrs = attrs + A.name + "\t" + A.value + "\n";
|
||
|
|
}
|
||
|
|
}
|
||
|
|
dlgMessageBox(attrs);
|
||
|
|
exit(0);
|
||
|
|
}
|
||
|
|
|
||
|
|
if (argv[FILENAME_ARG] == "--help") {
|
||
|
|
int choice = dlgMessageBox(usage, "+Return to Eagle", "Run Setup Now");
|
||
|
|
switch (choice) {
|
||
|
|
|
||
|
|
// return to eagle
|
||
|
|
case 0:
|
||
|
|
exit(0);
|
||
|
|
break;
|
||
|
|
|
||
|
|
// Run setup now
|
||
|
|
case 1:
|
||
|
|
exit("run pcb-gcode-setup");
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
exit(0);
|
||
|
|
}
|
||
|
|
|
||
|
|
// Be sure a filename is specified.
|
||
|
|
if (argv[FILENAME_ARG]) {
|
||
|
|
m_file_name = argv[FILENAME_ARG];
|
||
|
|
if (filedir(m_file_name) == "") {
|
||
|
|
board(B) m_file_name = filedir(B.name) + m_file_name;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
else {
|
||
|
|
board(B) m_file_name = filesetext(B.name, "");
|
||
|
|
}
|
||
|
|
|
||
|
|
if (FILENAMES_8_CHARACTERS) {
|
||
|
|
m_file_name = filedir(m_file_name) + strsub(filename(m_file_name), 0, 5);
|
||
|
|
}
|
||
|
|
|
||
|
|
// Use a default width if one is not given.
|
||
|
|
if (argv[WIDTH_ARG]) {
|
||
|
|
g_width = strtod(argv[WIDTH_ARG]);
|
||
|
|
}
|
||
|
|
else {
|
||
|
|
g_width = DEFAULT_WIDTH;
|
||
|
|
}
|
||
|
|
|
||
|
|
// Get the isolate parameter or use the default.
|
||
|
|
if (argv[ISO_ARG]) {
|
||
|
|
m_isolate = strtod(argv[ISO_ARG]);
|
||
|
|
}
|
||
|
|
else {
|
||
|
|
m_isolate = ISO_MIN;
|
||
|
|
}
|
||
|
|
|
||
|
|
// Get the pass number, or default to first pass (0).
|
||
|
|
if (argv[PASS_ARG]) {
|
||
|
|
m_pass_num = strtol(argv[PASS_ARG]);
|
||
|
|
}
|
||
|
|
else {
|
||
|
|
m_pass_num = 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
// Get the phase we are processing, or default to the first one.
|
||
|
|
if (argv[PHASE_ARG]) {
|
||
|
|
g_phase = strtol(argv[PHASE_ARG]);
|
||
|
|
}
|
||
|
|
else {
|
||
|
|
g_phase = PH_TOP_OUT_GEN;
|
||
|
|
}
|
||
|
|
|
||
|
|
get_current_profile();
|
||
|
|
if (g_phase == PH_TOP_OUT_GEN && m_pass_num == 0 && program_is_setup() == NO)
|
||
|
|
{
|
||
|
|
exit("run pcb-gcode-setup");
|
||
|
|
}
|
||
|
|
|
||
|
|
//
|
||
|
|
// Do what we need to for this phase.
|
||
|
|
//
|
||
|
|
switch (g_phase) {
|
||
|
|
case PH_TOP_OUT_GEN:
|
||
|
|
if (GENERATE_TOP_OUTLINES == YES)
|
||
|
|
generate_outlines(TOP);
|
||
|
|
break;
|
||
|
|
case PH_TOP_OUT_WRITE:
|
||
|
|
if (GENERATE_TOP_OUTLINES == YES)
|
||
|
|
write_outlines(TOP, "top", OUTLINES);
|
||
|
|
break;
|
||
|
|
|
||
|
|
case PH_TOP_FILL_GEN:
|
||
|
|
if (GENERATE_TOP_FILL == YES)
|
||
|
|
generate_outlines(TOP);
|
||
|
|
break;
|
||
|
|
case PH_TOP_FILL_WRITE:
|
||
|
|
if (GENERATE_TOP_FILL == YES)
|
||
|
|
write_outlines(TOP, "tf", FILL);
|
||
|
|
break;
|
||
|
|
|
||
|
|
case PH_BOTTOM_OUT_GEN:
|
||
|
|
if (GENERATE_BOTTOM_OUTLINES == YES)
|
||
|
|
generate_outlines(BOTTOM);
|
||
|
|
break;
|
||
|
|
case PH_BOTTOM_OUT_WRITE:
|
||
|
|
if (GENERATE_BOTTOM_OUTLINES == YES)
|
||
|
|
write_outlines(BOTTOM, "bot", OUTLINES);
|
||
|
|
break;
|
||
|
|
|
||
|
|
case PH_BOTTOM_FILL_GEN:
|
||
|
|
if (GENERATE_BOTTOM_FILL == YES)
|
||
|
|
generate_outlines(BOTTOM);
|
||
|
|
break;
|
||
|
|
case PH_BOTTOM_FILL_WRITE:
|
||
|
|
if (GENERATE_BOTTOM_FILL == YES)
|
||
|
|
write_outlines(BOTTOM, "bf", FILL);
|
||
|
|
break;
|
||
|
|
|
||
|
|
case PH_TOP_DRILL:
|
||
|
|
if (GENERATE_TOP_DRILL == YES)
|
||
|
|
drill(TOP, "td");
|
||
|
|
break;
|
||
|
|
case PH_BOTTOM_DRILL:
|
||
|
|
if (GENERATE_BOTTOM_DRILL == YES)
|
||
|
|
drill(BOTTOM, "bd");
|
||
|
|
break;
|
||
|
|
|
||
|
|
case PH_MILL:
|
||
|
|
if (GENERATE_MILLING == YES)
|
||
|
|
write_outlines(MILL, "mil", MILL_BOARD);
|
||
|
|
break;
|
||
|
|
|
||
|
|
case PH_TEXT:
|
||
|
|
if (GENERATE_TEXT == YES)
|
||
|
|
write_outlines(TEXT, "txt", MILL_TEXT);
|
||
|
|
break;
|
||
|
|
|
||
|
|
default:
|
||
|
|
sprintf(g_debug, "Illegal phase %d in main routine", g_phase);
|
||
|
|
Fatal("Sorry...", g_debug);
|
||
|
|
}
|
||
|
|
|
||
|
|
// Set things up for the next phase.
|
||
|
|
next_phase();
|
||
|
|
|
||
|
|
if (SHOW_PROGRESS == YES) {
|
||
|
|
gen_progress_menu(g_phase);
|
||
|
|
}
|
||
|
|
|
||
|
|
// If this is not the last phase, exit with a command line for
|
||
|
|
// Eagle to process. The command includes running this program again.
|
||
|
|
if (g_phase < PH_LAST_PHASE) {
|
||
|
|
sprintf(g_cmd,
|
||
|
|
"%s"
|
||
|
|
"window fit;\n"
|
||
|
|
"%s"
|
||
|
|
"run '%s' '%s' '%f' '%f' '%d' '%d';\n",
|
||
|
|
g_cmd,
|
||
|
|
(SHOW_PROGRESS) ? "script pcb-gcode-prg.scr;\n" : "",
|
||
|
|
argv[PROGRAM_NAME_ARG], m_file_name, g_width, m_isolate,
|
||
|
|
m_pass_num, g_phase
|
||
|
|
);
|
||
|
|
exit(g_cmd);
|
||
|
|
}
|
||
|
|
else {
|
||
|
|
g_cmd = "window fit;\n";
|
||
|
|
if (SHOW_PROGRESS) {
|
||
|
|
if (RESTORE_MENU_FILE != "") {
|
||
|
|
g_cmd = g_cmd + "script " + RESTORE_MENU_FILE + ";\n";
|
||
|
|
}
|
||
|
|
else {
|
||
|
|
g_cmd = g_cmd + "menu;\n";
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
exit(g_cmd);
|
||
|
|
}
|