From c1cf75d3627461e312775a988e2a432c78a094b3 Mon Sep 17 00:00:00 2001 From: deHarro Date: Mon, 26 Aug 2024 14:04:58 +0200 Subject: [PATCH 01/10] Added corrections for rounded corners from V3.6.6 --- pcb-gcode.ulp | 22 ++++++++++++++++++++-- source/pcb-gcode.h | 3 ++- 2 files changed, 22 insertions(+), 3 deletions(-) diff --git a/pcb-gcode.ulp b/pcb-gcode.ulp index dc99626..4f8b1f6 100644 --- a/pcb-gcode.ulp +++ b/pcb-gcode.ulp @@ -85,6 +85,7 @@ string g_cmd_temp; ////////// mlmSolutions added 29 Jan 14 real m_v_x[], m_v_y[], m_v_rad[]; +real m_v_xc[], m_v_yc[]; // JJ real m_tool_x, m_tool_y, m_vx1, m_vy1, m_vx2, m_vy2, m_rad; int m_v_index[], m_v_prev[], m_v_next[], m_v_step[], m_v_cont[], m_v_curve[], m_c_start[], m_c_end[]; int m_contours, m_cw, m_v_n=1, m_fwd, m_dist, m_dist_min, m_dist_min_index; @@ -593,6 +594,8 @@ void spot_drill(UL_BOARD B) real m_arc_begin_x; real m_arc_begin_y; real m_arc_radius; +real m_arc_center_x; +real m_arc_center_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_or_radius, real fr_xy, real fr_z) @@ -710,9 +713,19 @@ void device_draw(int x1, int y1, int x2, int y2, int state, real z_down_or_radiu ////////// mlmSolutions 5 Feb 14 + + case ST_ARC_CENTER: + sprintf(str, "ARC CENTER: rx1=%f, ry1=%f, rx2=%f, ry2=%f", rx1, ry1, rx2, ry2); + comm(str); + m_arc_center_x = rx1; + m_arc_center_y = ry1; + break; + case ST_ARC: - i_coord = (rx2 - rx1) / 2; - j_coord = (ry2 - ry1) / 2; + sprintf(str, "ARC: rx1=%f, ry1=%f, rx2=%f, ry2=%f, cx=%f, cy=%f", rx1, ry1, rx2, ry2, m_arc_center_x, m_arc_center_y); + comm(str); + i_coord = m_arc_center_x - rx1; + j_coord = m_arc_center_y - ry1; if (m_z_up){ rz(DEFAULT_Z_UP); rxy(rx1, ry1); @@ -1026,6 +1039,8 @@ void output_mill_code() // save arc data m_v_x[m_v_n] = P.arc.x1; m_v_y[m_v_n] = P.arc.y1; + m_v_xc[m_v_n] = P.arc.xc; + m_v_yc[m_v_n] = P.arc.yc; m_v_rad[m_v_n] = P.arc.radius; m_v_curve[m_v_n] = W.curve; m_v_prev[m_v_n] = m_v_n - 1; @@ -1036,6 +1051,8 @@ void output_mill_code() m_v_x[m_v_n] = P.arc.x2; m_v_y[m_v_n] = P.arc.y2; + m_v_xc[m_v_n] = P.arc.xc; + m_v_yc[m_v_n] = P.arc.yc; m_v_rad[m_v_n] = P.arc.radius; m_v_curve[m_v_n] = W.curve; m_v_prev[m_v_n] = m_v_n - 1; @@ -1143,6 +1160,7 @@ void output_mill_code() if (m_v_rad[m_j] > 0) { //its an arc if ((m_j % 2) == 0) m_cw = false; else m_cw = true; //if its the end of an Eagle arc, m_cw=false m_rad = m_v_rad[m_j]; if (abs(m_v_curve[m_j]) >180) m_rad = m_rad * -1; + device_draw(m_v_xc[m_j], m_v_yc[m_j], 0, 0, ST_ARC_CENTER, 0, 0, 0); device_draw(m_vx1, m_vy1, m_vx2, m_vy2, ST_ARC, MILLING_DEPTH, FEED_RATE_MILL_XY, FEED_RATE_MILL_Z); } else { //its a line device_draw(m_vx1, m_vy1, m_vx2, m_vy2, state, MILLING_DEPTH, FEED_RATE_MILL_XY, FEED_RATE_MILL_Z); diff --git a/source/pcb-gcode.h b/source/pcb-gcode.h index 870e5d0..03321d8 100755 --- a/source/pcb-gcode.h +++ b/source/pcb-gcode.h @@ -52,7 +52,8 @@ enum { ST_INVALID, ST_FILL, ST_ARC_BEGIN, ST_ARC_END, - ST_ARC}; + ST_ARC, + ST_ARC_CENTER}; enum { TOP = 0, BOTTOM = 1, MILL = 2, TEXT = 3, STENCIL = 4, ALL = 5 }; From 78b87c7df9acf725f4f17ed6165ee7f8f31c4208 Mon Sep 17 00:00:00 2001 From: deHarro Date: Mon, 26 Aug 2024 14:13:18 +0200 Subject: [PATCH 02/10] should not be copied to github --- pcb-gcode.ulp.bak | 1796 ++++++++++++++++++++++++++++++++++++++++ source/pcb-gcode.h.bak | 270 ++++++ 2 files changed, 2066 insertions(+) create mode 100644 pcb-gcode.ulp.bak create mode 100644 source/pcb-gcode.h.bak diff --git a/pcb-gcode.ulp.bak b/pcb-gcode.ulp.bak new file mode 100644 index 0000000..dc99626 --- /dev/null +++ b/pcb-gcode.ulp.bak @@ -0,0 +1,1796 @@ +// +// Generate g-code for milling PC boards. +// +// Copyright 2004-2014 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/library.h" +#include "source/drill.h" +#include "source/pcb-file-utils.h" +#include "source/filename_subs.h" + +#usage "
pcb-gcode™ Gcode Generation Utility
" + " Version 3.7.2-alpha

" + "Copyright© 2003 - 2022 by John Johnson Software, LLC
" + "All Rights Reserved

" + "

" + "Join the Groups pcb-gcode group " + "https://groups.io/g/pcbgcode" + "
or contact the author at pcbgcode@pcbgcode.org" + "
" + "


" + "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.

" + "It will create files for the outlines of tracks, drilling holes, and milling cutouts in the board." + "
See the readme.html file for more info.

" + "There are many options in the setup program.
" + "To setup which files are generated, and how, use the following command:
" + "run pcb-gcode --setup

" + "

" + "If you want to produce a set of files without changing options, you can run pcb-gcode directly." + "Usage is as follows:
" + "run pcb-gcode [option] [file]
" + "Where:\n" + "" + "" + "" + "" + "" + "" + "
OptionFunction
--helpShow this help screen
--setupRun the setup / configuration program
fileIs the optional root filename.\n
If not given, the board name is used as the root filename.
" + "" + "" + "


" + +g_tool_size = TOOL_SIZE; + +// Filename to output to. +string m_file_name = ""; + +// Which side we're currently working on. +g_side = TOP; + +// Index of current being used. +int m_current_tool_ndx = 0; + +// Current tool number being used (e.g. agrees with e.g. T02) +int m_current_tool_num = 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; + + + +////////// mlmSolutions added 29 Jan 14 + +real m_v_x[], m_v_y[], m_v_rad[]; +real m_tool_x, m_tool_y, m_vx1, m_vy1, m_vx2, m_vy2, m_rad; +int m_v_index[], m_v_prev[], m_v_next[], m_v_step[], m_v_cont[], m_v_curve[], m_c_start[], m_c_end[]; +int m_contours, m_cw, m_v_n=1, m_fwd, m_dist, m_dist_min, m_dist_min_index; +int m_wire_start, m_z_up, m_step, m_i, m_j, m_cont, m_border_contour; + +////////// + +// +// Save the maximum and minimum coordinates. +// +// Params: +// x, y Coordinates to be tested, and possibly saved as min or max values. +// Return: +// none +// +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); +} + +// +// Open the platform-specific previewer. +// +// Params: none +// Return: none +// +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 = PH_BOTTOM_OUT_GEN; + return; + } + if (g_phase == PH_BOTTOM_OUT_GEN && GENERATE_BOTTOM_OUTLINES != YES) { + g_phase = PH_TOP_DRILL; + 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++; + } + + // dlgMessageBox(fi("next_phase(): g_phase=%d", g_phase)); +} + +////////////////////////////////////////////////// +// +// Hole drilling routines. +// +////////////////////////////////////////////////// + +// +// Add a drill hole entry (size, x, y) to the stack. +// +// Params: +// Size Drill size. +// req_size Desired drill hole size. (May be subbed.) +// x x coordinate. +// y y coordinate. +// Returns: +// none +// Changes: +// the stack entry will have: +// drill_size \t tool_num \t x \t y \t requested_size +// +void push_hole_onto_stack(int req_size, int x, int y) +{ + string tempstr; + int tool_num; + int drill_size; + + tool_num = get_tool_for(req_size); + drill_size = get_tool_param_iu(tool_num, RACK_TOOL_SIZE); + + sprintf(tempstr, "%06d\t%06d\t%06d\t%06d\t%06d", drill_size, tool_num, x, y, req_size); + stack_push(tempstr); +} + +// +// Return the distance between two points. +// +// Params: +// x1, y1, x2, y2 coordinates for two points. +// Return: +// the distance between the points. +// +real distance(real x1, real y1, real x2, real y2) { + return (sqrt((x1-x2)*(x1-x2) + (y1-y2)*(y1-y2))); +} + +// +// Sorts a stack of drills in g_stack by distance from last hole. +// +// Params: none +// Return: none +// Changes: +// the stack +// +void pythagorean_sort_stack() { + real drill_size1; + real tool_num1; + real drill_x1; + real drill_y1; + real drill_size2; + real tool_num2; + real drill_x2; + real drill_y2; + real drill_size3; + real tool_num3; + real drill_x3; + real drill_y3; + int i; + int j; + string drill_args1[]; + string drill_args2[]; + string drill_args3[]; + string tmp; + + real before_distance; + real after_distance; + + // Sort by size, tool, x, then y + stack_sort(); + + for (i = 0; i <= stack_count(); i++) { + strsplit(drill_args1, stack_elem(i), '\t'); + drill_size1 = internals_to_user(my_strtol(drill_args1[DRILL_SIZE])); + tool_num1 = my_strtol(drill_args1[DRILL_TOOL_NUM]); + drill_x1 = scale_x(my_strtol(drill_args1[DRILL_X])); + drill_y1 = scale_y(my_strtol(drill_args1[DRILL_Y])); + + j = i + 2; + while (j <= stack_count()) { + strsplit(drill_args2, stack_elem(i+1), '\t'); + drill_size2 = internals_to_user(my_strtol(drill_args2[DRILL_SIZE])); + tool_num2 = my_strtol(drill_args2[DRILL_TOOL_NUM]); + drill_x2 = scale_x(my_strtol(drill_args2[DRILL_X])); + drill_y2 = scale_y(my_strtol(drill_args2[DRILL_Y])); + + strsplit(drill_args3, stack_elem(j), '\t'); + drill_size3 = internals_to_user(my_strtol(drill_args3[DRILL_SIZE])); + tool_num3 = my_strtol(drill_args3[DRILL_TOOL_NUM]); + drill_x3 = scale_x(my_strtol(drill_args3[DRILL_X])); + drill_y3 = scale_y(my_strtol(drill_args3[DRILL_Y])); + + if (drill_size2 != drill_size1 || drill_size3 != drill_size1 || + tool_num2 != tool_num1 || tool_num3 != tool_num1) + break; + + if (distance(drill_x1, drill_y1, drill_x3, drill_y3) < distance(drill_x1, drill_y1, drill_x2, drill_y2)) { + tmp = stack_elem(j); + stack_put(j, stack_elem(i+1)); + stack_put(i+1, tmp); + j = i + 1; + } + j++; + } + } +} + +/* + * Create a drill file for the desired side. + * + * Params: + * which_side Side to produce the file for. + * Returns: + * none + * Changes: + * m_current_tool_ndx + * g_side +*/ +void output_drill_file(int which_side) +{ + int num_lines; + int i; + real last_size; + string drill_args[]; + real drill_size_mm; + real drill_size_inch; + real drill_size; + real drill_x; + real drill_y; + real hole_size; + int drill_tool_num; + int last_drill_tool_num; + + m_current_tool_ndx = 0; + g_side = which_side; + + // + // Build a stack with all the holes. + // + board(B) { + B.holes(H) push_hole_onto_stack(H.drill, H.x, H.y); + B.signals(S) S.vias(V) push_hole_onto_stack(V.drill, V.x, V.y); + B.elements(E) { + E.package.contacts(C) { + if (C.pad) { + push_hole_onto_stack(C.pad.drill, C.pad.x, C.pad.y); + } + } + E.package.holes(H) push_hole_onto_stack(H.drill, H.x, H.y); + } + // B.elements + + // Dump the drill stack to a file for troubleshooting + // output(g_path + "/before_stack.txt", FILEMODE_WRITE_TEXT) { + // printf("before stack sort\n"); + // for (i=stack_fwd_iter(); i != END_OF_STACK; i=stack_fwd_next()) { + // printf("%s\n", stack_elem(i)); + // } + // } + + // Sorts the drills by size, tool_number, then distance from previous hole. + pythagorean_sort_stack(); + + // Dump the drill stack to a file for troubleshooting + // output(g_path + "/after_stack.txt", FILEMODE_WRITE_TEXT) { + // printf("after stack sort\n"); + // for (i=stack_fwd_iter(); i != END_OF_STACK; i=stack_fwd_next()) { + // printf("%s\n", stack_elem(i)); + // } + // } + + // + // Create the drill g-code file. + // + last_size = -1; + output(get_filename(), FILEMODE_WRITE_TEXT) { + output_file_preamble(); + + // + // Create a tool table at the beginning of the file. + // + comm("Rack file: " + elided_path(m_rack_file_name, 30)); + comm("Min Sub is the minimum hole size this tool was subbed for."); + comm("Max Sub is the maximum hole size this tool was subbed for."); + 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]); + drill_tool_num = my_strtol(drill_args[DRILL_TOOL_NUM]); + + if (drill_size_mm == 0.0) continue; + + if (drill_size != last_size || drill_tool_num != last_drill_tool_num) { + ++m_current_tool_ndx; + if (get_tool_param_iu(drill_tool_num, RACK_TOOL_TYPE) == RACK_TOOL_DRILL) { + out(TOOL_CHANGE_TABLE_FORMAT(drill_tool_num, + drill_size_mm, drill_size_inch, + g_min_subbed_for[drill_tool_num], g_max_subbed_for[drill_tool_num], + g_drill_sub_cnt[drill_tool_num], "")); + } + else { + out(TOOL_CHANGE_TABLE_FORMAT(drill_tool_num, + drill_size_mm, drill_size_inch, + g_min_subbed_for[drill_tool_num], g_max_subbed_for[drill_tool_num], + g_drill_sub_cnt[drill_tool_num], "THIS IS AN ENDMILL")); + } + } + last_size = drill_size; + last_drill_tool_num = drill_tool_num; + } + // for + + begin_gcode(SPINDLE_DRILL_RPM); + + // + // Generate drill code. + // + m_current_tool_ndx = 0; + for (i=stack_fwd_iter(); i != END_OF_STACK; i=stack_fwd_next()) { + strsplit(drill_args, stack_elem(i), '\t'); + drill_size = internals_to_user(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])); + hole_size = internals_to_user(my_strtol(drill_args[DRILL_HOLE_SIZE])); + drill_tool_num = my_strtol(drill_args[DRILL_TOOL_NUM]); + save_extents(drill_x, drill_y); + + if (drill_size == 0.0) continue; + + // + // Check to see if the drill size has changed, + // if so, output a tool change and optional zero code. + // + if (drill_size == last_size && drill_tool_num == last_drill_tool_num) { + if (get_tool_param_iu(m_current_tool_num, RACK_TOOL_TYPE) == RACK_TOOL_DRILL) { + output_drill_hole(drill_x, drill_y, DRILL_DEPTH); + } + else { + output_mill_hole(drill_x, drill_y, DRILL_DEPTH, hole_size, m_current_tool_num); + } + } + else { + m_current_tool_ndx++; + // Tool change routine + output_tool_change_begin(); + out(SPINDLE_OFF); + rz(TOOL_CHANGE_POS_Z); + rxy(TOOL_CHANGE_POS_X, TOOL_CHANGE_POS_Y); + m_current_tool_num = drill_tool_num; + out(fir(TOOL_CHANGE, m_current_tool_num, drill_size)); + output_tool_changed(); + + // Output zero steps and a pause + if (DO_TOOL_CHANGE_WITH_ZERO_STEP == YES) { + output_tool_zero_begin(); + fzr(0.000, FEED_RATE_DRILL_Z); + out(OPERATOR_PAUSE + EOL); + output_tool_zero_end(); + } + + rz(DEFAULT_Z_UP); + out(fr(SPINDLE_ON, SPINDLE_ON_TIME)); + output_tool_change_end(); + + if (get_tool_param_iu(m_current_tool_num, RACK_TOOL_TYPE) == RACK_TOOL_DRILL) { + output_drill_first_hole(drill_x, drill_y, DRILL_DEPTH); + } + else { + output_mill_hole(drill_x, drill_y, DRILL_DEPTH, hole_size, m_current_tool_num); + } + last_size = drill_size; + last_drill_tool_num = drill_tool_num; + } + // 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 + +// holds line segments generated for the previewer +string m_lines; + +// +// Format the coordinates of two points to be used by the previewer. +// +// Params: +// x1, y1, x2, y2 Two points. +// Return: +// Coordinates formatted for the previewer. +// + +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); +} + +// +// Generates gcode for spot drilling and previewing holes. +// +// Params: +// drill_size Size of the hole to drill. +// x, y Location of the hole. +// Return: none +// Changes: +// m_first_spot_drill +// m_lines +// g_side +// +int m_first_spot_drill = YES; +void spot_drill_hole(int drill_size, int x, int y) +{ + real drill_x; + real drill_y; + real offset; + + drill_x = scale_x(x); + drill_y = scale_y(y); + save_extents(drill_x, drill_y); + + if (SPOT_DRILL == YES) { + if (m_first_spot_drill) { + comm("spot drill holes"); + 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); + } + } + + offset = internals_to_user(drill_size) / 2; + + // + // Generate X's for drill preview if drills are turned on for this side. + // + if ((g_side == TOP && GENERATE_TOP_DRILL == YES) || + (g_side == BOTTOM && GENERATE_BOTTOM_DRILL == YES)) { + m_lines += coords(drill_x - offset, drill_y - offset, drill_x + offset, drill_y + offset); + m_lines += coords(drill_x - offset, drill_y + offset, drill_x + offset, drill_y - offset); + } +} + +// +// Enumerates all holes and generates spot drills for them. +// +// Params: +// B The board. +// Return: none +// Changes: +// m_lines +// +void spot_drill(UL_BOARD B) +{ + + m_lines += "# spot drills\n"; + + B.holes(H) spot_drill_hole(H.drill, H.x, H.y); + B.signals(S) S.vias(V) spot_drill_hole(V.drill, V.x, V.y); + B.elements(E) { + E.package.contacts(C) { + if (C.pad) { + spot_drill_hole(C.pad.drill, C.pad.x, C.pad.y); + } + } + E.package.holes(H) spot_drill_hole(H.drill, H.x, H.y); + } + // B.elements +} + +// +// "Draw" on the output device, i.e. the gcode file. +// +// Params: +// x1,y1 Start of the line. +// x2,y2 End of the line. +// state The state of the line being drawn, start, continue, etc. +// z_down_or_radius Z depth or radius of arc +// fr_xy XY feed rate +// fr_z Z feed rate +// Returns: +// none +// Changes: +// m_lines +// m_arc_begin_x +// m_arc_begin_y +// m_arc_radius +// +real m_arc_begin_x; +real m_arc_begin_y; +real m_arc_radius; +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_or_radius, real fr_xy, real fr_z) +{ + real rx1, ry1, rx2, ry2; + + string str; + + real i_coord; + real j_coord; + + 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_or_radius, fr_z); + fxyr(rx2, ry2, fr_xy); + 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; + m_arc_radius = internals_to_user(z_down_or_radius); + 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; + + rz(DEFAULT_Z_UP); + rxy(end_x, end_y); + fzr(z_down_or_radius, FEED_RATE_MILL_Z); + + // cx and cy are in absolute coords, convert to relative for I,J + i_coord = end_x - cx; + j_coord = end_y - cy; + + if (g_side == TOP || MIRROR_BOTTOM == YES) { + fcwr(m_arc_begin_x, m_arc_begin_y, i_coord, j_coord, fr_xy); + } + else { + fccwr(m_arc_begin_x, m_arc_begin_y, i_coord, j_coord, fr_xy); + } + break; + +////////// mlmSolutions 5 Feb 14 + + case ST_ARC: + i_coord = (rx2 - rx1) / 2; + j_coord = (ry2 - ry1) / 2; + if (m_z_up){ + rz(DEFAULT_Z_UP); + rxy(rx1, ry1); + fzr(z_down_or_radius, fr_z); + } + if (((g_side == TOP) && m_cw) || ((g_side != TOP) && !m_cw)) { + fcwr(rx2, ry2, i_coord, j_coord, fr_xy); + } + else { + fccwr(rx2, ry2, i_coord, j_coord, fr_xy); + } + 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 +// Changes: +// m_layer +// g_cmd +// +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 = internals_to_user(B.area.x1) - f; + real y1 = internals_to_user(B.area.y1) - f; + real x2 = internals_to_user(B.area.x2) + f; + real y2 = internals_to_user(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" + , + get_unit_of_measure(), + m_isolate, + g_tool_size, + m_layer, + OUTLINES_SIGNAL_NAME, g_tool_size, + x1, y1, x2, y1, x2, y2, x1, y2, x1, y1 + ); + g_cmd = g_cmd + cmd_temp; + return; + } + // board(B) +} +// generate_outlines + +// +// Output info and lines to a file for the previewer. +// +// Params: +// path Path and filename. +// mode File open mode. May be write or append. +// layer MILL, TEXT, etc. +// Returns: +// none +// Changes: +// none +// +void out_lines(string path, string mode, int layer) +{ + output(path, mode) { + if (m_pass_num == 0) { + printf("# board=%s\n", elided_path(get_filename(), 30)); + if (layer == MILL) { + printf("# depth=%f\n", MILLING_DEPTH); + } + else if (layer == TEXT) { + printf("# depth=%f\n", TEXT_DEPTH); + } + else { + printf("# tool size=%f\n", g_tool_size); + } + } + printf("# pass=%d\n", m_pass_num + 1); + printf("# preview window width=%d height=%d\n", PREVIEW_WINDOW_WIDTH, PREVIEW_WINDOW_HEIGHT); + printf(m_lines); + } +} + +// +// Output preview data to the platform specific files. +// +// Params: +// mode File open mode. May be write or append. +// Returns: +// none +// Changes: +// none +// +void output_preview_data(string mode, int layer) +{ + out_lines(g_path + "/viewer/data/optimize_me.txt", mode, layer); + out_lines(g_path + "/viewer/applet/data/optimize_me.txt", mode, layer); + out_lines(g_path + "/viewer/application.macosx/data/optimize_me.txt", mode, layer); + out_lines(g_path + "/viewer/application.linux/data/optimize_me.txt", mode, layer); + out_lines(g_path + "/viewer/application.windows/data/optimize_me.txt", mode, layer); +} + +// +// Write text from the Milling layer to a text engraving file. +// +// Params: +// none +// Return: +// none +// Changes: +// g_tool_size +// m_lines +// +void output_text_code() +{ + int state; + int old_x, old_y; + + board(B) { + output(get_filename(), FILEMODE_WRITE_TEXT) { + user_file_opened(get_filename(), FILEMODE_WRITE_TEXT); + + output_file_preamble(); + + // Initialize the device (i.e. the output file). + begin_gcode(SPINDLE_TEXT_RPM); + + // 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, W.arc.radius, FEED_RATE_TEXT_XY, FEED_RATE_TEXT_Z); + device_draw( W.arc.x2, W.arc.y2, W.arc.xc, W.arc.yc, ST_ARC_END, TEXT_DEPTH, FEED_RATE_TEXT_XY, FEED_RATE_TEXT_Z); + 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, FEED_RATE_TEXT_XY, FEED_RATE_TEXT_Z); + 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(), FILEMODE_WRITE_TEXT); + } + // board + g_tool_size = abs(TEXT_DEPTH); + output_preview_data(FILEMODE_WRITE_TEXT, TEXT); + preview(); + + m_lines = ""; +} +// output_text_code + + +////////// mlmSolutions added 21 Jan 14 + +// +// Checks if two vertices match. If yes, return true else return false. +// +// Params: +// X1, Y1, X2, Y2 +// Return: +// true or false +// Changes: +// nothing +// +int match(real X1, real Y1, real X2, real Y2) +{ + if ((X1 == X2) && (Y1 == Y2)) return true; else return false; +} + +// +// Removes a vertex from the linked list. +// +// Params: +// id - the id of the vertex to be removed +// Return: +// nothing +// Changes: +// pointers of previous and next entry +// +void vertex_remove(int id) +{ + m_v_next[m_v_prev[id]] = m_v_next[id]; + m_v_prev[m_v_next[id]] = m_v_prev[id]; +} + + +////////// + + +// +// Write layer data to mill files. +// +// Params: +// none +// Return: +// none +// Changes: +// g_tool_size +// m_lines +// +void output_mill_code() +{ + int state; + int old_x, old_y; + int first_run = true; + string str; + + board(B) { + output(get_filename(), FILEMODE_WRITE_TEXT) { + user_file_opened(get_filename(), FILEMODE_WRITE_TEXT); + + output_file_preamble(); + + // Initialize the device (i.e. the output file). + begin_gcode(SPINDLE_MILL_RPM); + + m_v_n =1; + + // 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 && !first_run) { + state = ST_CONTINUE_LINE; + } + else { + state = ST_START_LINE; + first_run = false; + } + + // if this is an arc, it is treated specially. + if (P.arc) { + sprintf(str, "# arc xc=%f yc=%f sang=%f eang=%f radius=%f\n", + scale_x(P.arc.xc), scale_y(P.arc.yc), P.arc.angle1, P.arc.angle2, scale_x(P.arc.radius)); + m_lines += str; + sprintf(str, "# debug W.x1=%8.5f W.y1=%8.5f W.x2=%8.5f W.y2=%8.5f W.curve=%f\n", + scale_x(W.x1), scale_y(W.y1), scale_x(W.x2), scale_y(W.y2), W.curve); + m_lines += str; + sprintf(str, "# debug P.arc.x1=%8.5f P.arc.y1=%8.5f P.arc.x2=%8.5f P.arc.y2=%8.5f\n", + scale_x(P.arc.x1), scale_y(P.arc.y1), scale_x(P.arc.x2), scale_y(P.arc.y2)); + m_lines += str; + m_lines += "# debug\n"; +// device_draw( P.arc.x1, P.arc.y1, P.arc.x2, P.arc.y2, ST_ARC_BEGIN, P.arc.radius, FEED_RATE_MILL_XY, FEED_RATE_MILL_Z); +// device_draw( P.arc.x2, P.arc.y2, P.arc.xc, P.arc.yc, ST_ARC_END, MILLING_DEPTH, FEED_RATE_MILL_XY, FEED_RATE_MILL_Z); + +////////// mlmSolutions added 5 Feb 14 + // As we cannot assume that "pieces" come from "wires" in any particular order or that they are contiguous + // we will have to save the start and end vertices. + // save arc data + m_v_x[m_v_n] = P.arc.x1; + m_v_y[m_v_n] = P.arc.y1; + m_v_rad[m_v_n] = P.arc.radius; + m_v_curve[m_v_n] = W.curve; + m_v_prev[m_v_n] = m_v_n - 1; + m_v_next[m_v_n] = 0; + m_v_next[m_v_n - 1] = m_v_n; + m_v_step[m_v_n] = 0; + ++m_v_n; + + m_v_x[m_v_n] = P.arc.x2; + m_v_y[m_v_n] = P.arc.y2; + m_v_rad[m_v_n] = P.arc.radius; + m_v_curve[m_v_n] = W.curve; + m_v_prev[m_v_n] = m_v_n - 1; + m_v_next[m_v_n] = 0; + m_v_next[m_v_n - 1] = m_v_n; + m_v_step[m_v_n] = 0; + ++m_v_n; +////////// + 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, FEED_RATE_MILL_XY, FEED_RATE_MILL_Z); + +////////// mlmSolutions added 5 Feb 14 + // save line data + m_v_x[m_v_n] = P.x1; + m_v_y[m_v_n] = P.y1; + m_v_rad[m_v_n] = 0; + m_v_curve[m_v_n] = 0; + m_v_prev[m_v_n] = m_v_n - 1; + m_v_next[m_v_n] = 0; + m_v_next[m_v_n - 1] = m_v_n; + m_v_step[m_v_n] = 0; + ++m_v_n; + + m_v_x[m_v_n] = P.x2; + m_v_y[m_v_n] = P.y2; + m_v_rad[m_v_n] = 0; + m_v_curve[m_v_n] = 0; + m_v_prev[m_v_n] = m_v_n - 1; + m_v_next[m_v_n] = 0; + m_v_next[m_v_n - 1] = m_v_n; + m_v_step[m_v_n] = 0; + ++m_v_n; + +////////// + 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 + +////////// mlmSolutions added 5 Feb 14 yyyy + + //Optimises the path using nearest neighbour + m_tool_x = X_HOME; + m_tool_y = Y_HOME; + m_step = 0; + // set direction of cut around contour + //if (((g_side == TOP) && !CLIMB_MILLING) || ((g_side == BOTTOM) && CLIMB_MILLING)) m_fwd = true; else m_fwd = false; + while (m_v_next[0] > 0){ + //find nearest vertex from current location + m_dist_min = 99999999; + m_i=0; //start from the head pointer + while (m_v_next[m_i] > 0){ // loop till end of unprocessed list + m_i = m_v_next[m_i]; //the index of the next unprocessed vertex + m_dist = distance(m_tool_x, m_tool_y, m_v_x[m_i], m_v_y[m_i]); + //m_dist = abs(m_tool_x - (m_v_x[m_i])) + abs(m_tool_y - (m_v_y[m_i])); //approximate to make faster + if (m_dist < m_dist_min){ + m_dist_min = m_dist; + m_dist_min_index = m_i; + } + } + m_i = m_dist_min_index; + m_v_step[m_i] = ++m_step; + vertex_remove(m_i); + //the next step must be the other end of this wire. If the vertex is odd, its the next vertex else its the previous. + if ((m_i % 2) == 1) ++m_i; else --m_i; + m_v_step[m_i] = ++m_step; + vertex_remove(m_i); + + //move the tool position to new location + m_tool_x = (m_v_x[m_i]); + m_tool_y = (m_v_y[m_i]); + } + + // Generate the gcode + // sort into step order + sort(m_v_n, m_v_index, m_v_step); + m_tool_x = X_HOME; m_tool_y = Y_HOME; + m_wire_start = true; //the vertices are stored in pairs. X1Y1 first then X2Y2 + first_run = true; + for (m_i=1; m_i 0) { //its an arc + if ((m_j % 2) == 0) m_cw = false; else m_cw = true; //if its the end of an Eagle arc, m_cw=false + m_rad = m_v_rad[m_j]; if (abs(m_v_curve[m_j]) >180) m_rad = m_rad * -1; + device_draw(m_vx1, m_vy1, m_vx2, m_vy2, ST_ARC, MILLING_DEPTH, FEED_RATE_MILL_XY, FEED_RATE_MILL_Z); + } else { //its a line + device_draw(m_vx1, m_vy1, m_vx2, m_vy2, state, MILLING_DEPTH, FEED_RATE_MILL_XY, FEED_RATE_MILL_Z); + } + m_tool_x = m_vx2; m_tool_y = m_vy2; //save the tools current location + } + m_wire_start = !m_wire_start; + } + +////////// + output_file_postamble(); + end_gcode(); + user_file_closing(); + } + // output + user_file_closed(get_filename(), FILEMODE_WRITE_TEXT); + } + // board + + g_tool_size = abs(MILLING_DEPTH); + output_preview_data(FILEMODE_WRITE_TEXT, MILL); + preview(); + + m_lines = ""; +} +// output_mill_code + + +// +// Write polygon lines to the file. +// +// Params: +// which_side Side of the board to work on. +// task +// Return: +// none +// Changes: +// g_side +// m_layer +// g_cmd +// g_debug +// +void write_outlines(int which_side, 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; + real spindle_speed; + real fr_xy; + real fr_z; + + if (m_pass_num == 0) { + mode = FILEMODE_WRITE_TEXT; + } + else { + mode = FILEMODE_APPEND_TEXT; + } + g_side = which_side; + switch (which_side) { + case TOP: + m_layer = TOP_LAYER; + spindle_speed = SPINDLE_ETCH_RPM; + fr_xy = FEED_RATE_ETCH_XY; + fr_z = FEED_RATE_ETCH_Z; + break; + case BOTTOM: + m_layer = BOTTOM_LAYER; + spindle_speed = SPINDLE_ETCH_RPM; + fr_xy = FEED_RATE_ETCH_XY; + fr_z = FEED_RATE_ETCH_Z; + break; + case MILL: + m_layer = MILL_LAYER; + spindle_speed = SPINDLE_MILL_RPM; + fr_xy = FEED_RATE_MILL_XY; + fr_z = FEED_RATE_MILL_Z; + break; + case TEXT: + m_layer = TEXT_LAYER; + spindle_speed = SPINDLE_TEXT_RPM; + fr_xy = FEED_RATE_TEXT_XY; + fr_z = FEED_RATE_TEXT_Z; + 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(); + g_side = BOTTOM; + output_mill_code(); + return; + } + else { + g_side = TOP; + output_text_code(); + g_side = BOTTOM; + output_text_code(); + 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, fr_xy, fr_z); + device_draw(W.x1, W.y1, W.x2, W.y2, ST_END_LINE, DEFAULT_Z_DOWN, fr_xy, fr_z); // fixme needed? + } + } + } + + m_v_n = 1; + + 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(spindle_speed); + } + else { + output_between_outline_passes(); + } + + switch (task) { + case TASK_OUTLINES: + P.contours(W) { + +////////// mlmSolutions added 12 Feb 14 xxxx + // Save the contour wires (Except the frame) + // Each wire from the contour has a start and end vertex but the X1Y1 of the next vertex + // will have the same value as the X2Y2 of the current one for any specific contour. + // In order to minimise the number of vertices stored, we will store the X1Y1 only. + // The last X2Y2 should be the same as the first X1Y1. + // When a vertex has been processed it will be removed from the linked list + + // record the start and end vertex index for each new contour + if ( first ){ + ++m_contours; + m_c_start[m_contours-1] = m_v_n; + x0 = W.x1; y0 = W.y1; // remember start vertex + first = false; + } else if (W.x2 == x0 && W.y2 == y0) { + m_c_end[m_contours-1] = m_v_n; + first = true; + } + m_v_x[m_v_n] = W.x1; + m_v_y[m_v_n] = W.y1; + m_v_prev[m_v_n] = m_v_n - 1; + m_v_next[m_v_n] = 0; //indicate end of list + m_v_next[m_v_n-1] = m_v_n; //point previous vertex to us + m_v_step[m_v_n] = 0; + m_v_cont[m_v_n] = m_contours; + ++m_v_n; + + if (((W.x1 == x1 || W.x1 == x2) && (W.y1 == y1 || W.y1 == y2))){ //its on the border + m_border_contour = m_contours; + } +////////// + } + // 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, fr_xy, fr_z); + } + break; + } + // switch(task) + + +////////// mlmSolutions added 12 Feb 14 + + //Remove the border contour if any + if (m_border_contour > 0){ + for (m_i = m_c_start[m_border_contour - 1]; m_i <= m_c_end[m_border_contour - 1]; ++m_i){ + vertex_remove(m_i); + } + } + + // Optimise the path using the nearest neighbour. + // Each vertex will be tagged with its step number (order of tool movement) + // Eagle guarantees that if we move from X1Y1 to X2Y2 of a contour wire that the track will be on the right of the direction of movement. + // We will define this as forward. We store vertex values in a "forward" direction for increasing index values. + // This is therefore moving clockwise around a track when viewed from the top. (Climb Milling) + m_cont = 0; //set contour number to an invalid value to force a shortest distance scan initially + m_tool_x = X_HOME; + m_tool_y = Y_HOME; + m_step = 0; + + // set direction of cut around contour + if (((g_side == TOP) && !CLIMB_MILLING) || ((g_side == BOTTOM) && CLIMB_MILLING)) m_fwd = true; else m_fwd = false; + + // from http://harald-sattler.de/html/pcb-gcode_-e-.htm + // Mill first pass as climb, the remainder as conventional + // for better edge finishes. + if (m_pass_num == 0) m_fwd ; else m_fwd = !m_fwd; + + while (m_v_next[0] > 0){ + + //find nearest vertex from current location + m_dist_min = 99999999; + m_i=0; //start from the head pointer + + while (m_v_next[m_i] > 0){ // loop till end of unprocessed list + m_i = m_v_next[m_i]; //the index of the next unprocessed vertex + //m_dist = distance(m_tool_x, m_tool_y, internals_to_user(m_v_x[m_i]), internals_to_user(m_v_y[m_i])); + //m_dist = abs(m_tool_x - internals_to_user(m_v_x[m_i])) + abs(m_tool_y - internals_to_user(m_v_y[m_i])); + m_dist = abs(m_tool_x - (m_v_x[m_i])) + abs(m_tool_y - (m_v_y[m_i])); //approximate to make faster + if (m_dist < m_dist_min){ + m_dist_min = m_dist; + m_dist_min_index = m_i; + } + } + + // as the wires of a specific contour are issued from Eagle consecutively, most of the time the next vertex to go to + // is the next or previous in the list. If we check for this first, we can avoid a scan through the whole list. + m_cont = m_v_cont[m_dist_min_index] - 1; + m_i = m_dist_min_index; + do { + m_v_step[m_i] = ++m_step; + vertex_remove(m_i); + // move on to next vertex in contour + if (m_fwd){ + ++m_i; + if (m_i > m_c_end[m_cont]) m_i = m_c_start[m_cont]; // we got to end of contour so loop to begining + } else { + --m_i; + if (m_i < m_c_start[m_cont]) m_i = m_c_end[m_cont]; // we got to begining of contour so loop to end + } + } while (m_i != m_dist_min_index); // stop when we are back to the place we started + + // add an extra step to close the contour back to the start + m_v_x[m_v_n] = m_v_x[m_i]; + m_v_y[m_v_n] = m_v_y[m_i]; + m_v_step[m_v_n] = ++m_step; + m_v_cont[m_v_n] = m_v_cont[m_i]; + ++m_v_n; + + //move the tool position to new location + m_tool_x = (m_v_x[m_dist_min_index]); + m_tool_y = (m_v_y[m_dist_min_index]); + } + + + // Generate the gcode + // As we move through the steps + // 1) a new contour requires a Z retract, G00 to new location, Z plunge + // 2) otherwise just proceed. + + sort(m_v_n, m_v_index, m_v_step); // sort into step order + + for (m_j = 0; m_v_step[m_v_index[m_j]] == 0; ++m_j); // find the first non zero step + + m_cont=0; + for (m_i = m_j; m_i < m_v_n; ++m_i){ + m_j = m_v_index[m_i]; + m_vx2 = m_v_x[m_j]; m_vy2 = m_v_y[m_j]; //get the current vertex + if (m_cont != m_v_cont[m_j]) { //its a new contour so do a Z retract and G00 move and Z plunge + m_cont = m_v_cont[m_j]; + first = true; + x0 = m_vx2; y0 = m_vy2; //remember the start vertex + } else { + if (first) { /// a new partial polygon is starting + state = ST_START_LINE; + first = false; + } + else if (m_vx2 == x0 && m_vy2 == y0) { /// this is the last wire of the partial polygon + state = ST_END_LINE; + } + else { + state = ST_CONTINUE_LINE; + } + + device_draw(m_vx1, m_vy1, m_vx2, m_vy2, state, DEFAULT_Z_DOWN, fr_xy, fr_z); + } + m_vx1 = m_vx2; m_vy1 = m_vy2; //remember the last vertex + } + +////////// + 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", + internals_to_user(x1), internals_to_user(y1), internals_to_user(x2), internals_to_user(y2) + ); + } + // polygons + } + // if(S.name == OUTLINES_SIGNAL_NAME) + } + // signals + } + // board + user_file_closing(); + } + // output + user_file_closed(get_filename(), mode); + output_preview_data(mode, g_side); + +} +// write_outlines + +// +// Write stencil toolpath to the file. +// +// Params: +// which_side Side of the board to work on. +// suffix Suffix of the file. +// Return: +// none +// +void write_stencil(int which_side, string suffix) +{ + real fr_xy; + real fr_z; + fr_xy = FEED_RATE_STENCIL_XY; + fr_z = FEED_RATE_STENCIL_Z; + + g_side = which_side; + switch (which_side) { + case TOP: + m_layer = TOP_CREAM_LAYER; + break; + case BOTTOM: + m_layer = BOTTOM_CREAM_LAYER; + break; + default: + sprintf(g_debug, "Illegal which_side %d in write_stencil", which_side); + Fatal("Sorry...", g_debug); + } + + output(get_filename(), "wt") { + board(B) { + user_file_opened(get_filename(), "wt"); + + output_file_preamble(); + begin_gcode(SPINDLE_STENCIL_RPM); + + int tool_dia = user_to_internals(STENCIL_TOOL_SIZE); + g_tool_size = STENCIL_TOOL_SIZE; + if(g_debug_flag) { + sprintf(g_debug, "Stencil tool diameter=%f", internals_to_user(tool_dia)); + comm(g_debug); + } // if (g_debug_flag) + + B.elements(E) { + E.package.contacts(C) { + if (C.smd && + ((C.smd.layer == LAYER_BOTTOM && m_layer == BOTTOM_CREAM_LAYER) || + (C.smd.layer == LAYER_TOP && m_layer == TOP_CREAM_LAYER))) { + int cx = C.smd.x, cy = C.smd.y; + int dx = C.smd.dx[m_layer], dy = C.smd.dy[m_layer]; + real alpha = C.smd.angle * PI / 180; + + if(g_debug_flag) { + sprintf(g_debug, "Pad: cx=%f cy=%f dx=%f dy=%f alpha=%f", + internals_to_user(cx), internals_to_user(cy), internals_to_user(dx), internals_to_user(dy), alpha); + comm(g_debug); + } // if (g_debug_flag) + + // Tool size compensation + dx -= tool_dia / 2; dy -= tool_dia / 2; + + // Carve out the pad + if (dx > 0 && dy > 0) { + int hx = dx / 2, hy = dy / 2; + + // rotate (-hx, hy) + int x1 = -hx * cos(alpha) - hy * sin(alpha), + y1 = -hx * sin(alpha) + hy * cos(alpha); + // rotate (hx, hy) + int x2 = hx * cos(alpha) - hy * sin(alpha), + y2 = hx * sin(alpha) + hy * cos(alpha); + // rotate (hx, -hy) + int x3 = hx * cos(alpha) + hy * sin(alpha), + y3 = hx * sin(alpha) - hy * cos(alpha); + // rotate (-hx, -hy) + int x4 = -hx * cos(alpha) + hy * sin(alpha), + y4 = -hx * sin(alpha) - hy * cos(alpha); + + device_draw(cx + x1, cy + y1, cx + x2, cy + y2, ST_START_LINE, DEFAULT_Z_DOWN, fr_xy, fr_z); + device_draw(cx + x2, cy + y2, cx + x3, cy + y3, ST_CONTINUE_LINE, DEFAULT_Z_DOWN, fr_xy, fr_z); + device_draw(cx + x3, cy + y3, cx + x4, cy + y4, ST_CONTINUE_LINE, DEFAULT_Z_DOWN, fr_xy, fr_z); + device_draw(cx + x4, cy + y4, cx + x1, cy + y1, ST_CONTINUE_LINE, DEFAULT_Z_DOWN, fr_xy, fr_z); + // Deburr + device_draw(cx + x1, cy + y1, cx + x2, cy + y2, ST_END_LINE, DEFAULT_Z_DOWN, fr_xy, fr_z); + } // if (dx > 0 && dy > 0) + } // if (C.smd) + } // package.contacts + } // elements + + output_file_postamble(); + rz(DEFAULT_Z_UP); + end_gcode(); + } + // board + user_file_closing(); + } + // output + user_file_closed(get_filename(), "wt"); + + output_preview_data(FILEMODE_WRITE_TEXT, STENCIL); + preview(); + +} // write_stencil + +/* 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. +// +if (!board) { + Fatal("No board!", "Please run this program from the board editor"); +} + +// +// Process command line arguments. +// +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[TOOL_SIZE_ARG]) { + g_tool_size = strtod(argv[TOOL_SIZE_ARG]); +} +else { + g_tool_size = TOOL_SIZE; +} + +// 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, 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, 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, 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, FILL); + break; + + case PH_TOP_STENCIL: + if (GENERATE_TOP_STENCIL == YES) + write_stencil(TOP, "tc"); + break; + case PH_BOTTOM_STENCIL: + if (GENERATE_BOTTOM_STENCIL == YES) + write_stencil(BOTTOM, "bc"); + break; + + case PH_TOP_DRILL: + if (GENERATE_TOP_DRILL == YES) + output_drill_file(TOP); + break; + case PH_BOTTOM_DRILL: + if (GENERATE_BOTTOM_DRILL == YES) + output_drill_file(BOTTOM); + break; + + case PH_MILL: + if (GENERATE_MILLING == YES) + write_outlines(MILL, MILL_BOARD); + break; + + case PH_TEXT: + if (GENERATE_TEXT == YES) + write_outlines(TEXT, 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 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" + "run '%s' '%s' '%f' '%f' '%d' '%d';\n", + g_cmd, + argv[PROGRAM_NAME_ARG], m_file_name, g_tool_size, m_isolate, + m_pass_num, g_phase + ); + exit(g_cmd); +} +else { + g_cmd = "window fit;\n"; + exit(g_cmd); +} diff --git a/source/pcb-gcode.h.bak b/source/pcb-gcode.h.bak new file mode 100644 index 0000000..870e5d0 --- /dev/null +++ b/source/pcb-gcode.h.bak @@ -0,0 +1,270 @@ +// -*- Mode: Eagle -*- +// +// Constants and enums for pcb-gcode.ulp. +// +// (Actually, they should be consts and typedefs, +// but Eagle doesn't support that.) +// + +// +// No users options here. +// + +#include "string.h" + +string RELEASE = "NOT SET"; +string REVISION = "000"; + +string g_path = ""; + +string BOARD_NAME; +board(B) { BOARD_NAME = B.name; } + +enum { + U_MICRONS = 0, + U_MILLIMETERS = 1, + U_MILS = 2, + U_INCHES = 3, + U_INTERNALS = 4 +}; + +enum { + OUTPUT_MICRONS = 0, + OUTPUT_MILLIMETERS = 1, + OUTPUT_MILS = 2, + OUTPUT_INCHES = 3, + OUTPUT_INTERNALS = 4 +}; + +enum { + HOLE_MILL_CONCENTRIC = 0, + HOLE_MILL_HELICAL = 1 +} + +enum { NO = 0, YES = 1 }; +enum { false = 0, true = 1 }; + +enum { TASK_INVALID, TASK_OUTLINES, TASK_FILL }; + +enum { ST_INVALID, + ST_START_LINE, ST_CONTINUE_LINE, ST_END_LINE, + ST_DRILL, + ST_FILL, + ST_ARC_BEGIN, + ST_ARC_END, + ST_ARC}; + +enum { TOP = 0, BOTTOM = 1, MILL = 2, TEXT = 3, STENCIL = 4, ALL = 5 }; + +int PROGRAM_NAME_ARG = 0; +int FILENAME_ARG = 1; +int TOOL_SIZE_ARG = 2; +int ISO_ARG = 3; +int PASS_ARG = 4; +int PHASE_ARG = 5; + +real COORD_TOLERANCE = 0.0001; + +string OUTLINES_SIGNAL_NAME = "_OUTLINES_"; + +int TOP_LAYER = 1; +int BOTTOM_LAYER = 16; +int TOP_CREAM_LAYER = 31; +int BOTTOM_CREAM_LAYER = 32; +int MILL_LAYER = 46; +int TEXT_LAYER = 46; // same as MILL_LAYER + +int OUTLINES = 1; +int FILL = 2; +int MILL_BOARD = 3; +int MILL_TEXT = 4; + +enum { + PH_INVALID = 0, + PH_TOP_OUT_GEN = 1, + PH_TOP_OUT_WRITE = 2, + PH_TOP_FILL_GEN = 3, + PH_TOP_FILL_WRITE = 4, + PH_TOP_STENCIL = 5, + PH_BOTTOM_OUT_GEN = 6, + PH_BOTTOM_OUT_WRITE = 7, + PH_BOTTOM_FILL_GEN = 8, + PH_BOTTOM_FILL_WRITE = 9, + PH_BOTTOM_STENCIL = 10, + PH_TOP_DRILL = 11, + PH_BOTTOM_DRILL = 12, + PH_MILL = 13, + PH_TEXT = 14, + + PH_LAST_PHASE = 15 +}; + +string FILEMODE_WRITE_TEXT = "wt"; +string FILEMODE_APPEND_TEXT = "at"; + +string PHASE_NAME[] = { + "invalid", + "Gen_Top_Outlines", "Write_Top_Outlines", + "Gen_Top_Fill", "Write_Top_Fill", + "Top_Stencil", + "Gen_Bottom_Outlines", "Write_Bottom_Outlines", + "Gen_Bottom_Fill", "Write_Bottom_Fill", + "Bottom_Stencil", + "Top_Drills", "Bottom_Drills", + "Milling", + "Text", + "Finished!" +}; + +string get_phase_name(int phase) +{ + return PHASE_NAME[phase]; +} + +// Used to convert a numeric state into a text name for that state. +string state_text[] = { + "ST_START_LINE", + "ST_CONTINUE_LINE", + "ST_END_LINE", + "ST_DRILL", + "ST_FILL" +}; + +real ROUND_FACTOR = 1000; + +real BORDER_SIZE = 0.001; + +/* + * Indexes for stack elements when used for drill holes. + */ +int DRILL_SIZE = 0; +int DRILL_TOOL_NUM = 1; +int DRILL_X = 2; +int DRILL_Y = 3; +int DRILL_HOLE_SIZE = 4; + + +real g_tool_size = 0.01; +int g_side = TOP; + +// Which phase of the process we're working on. +int g_phase; + +string IS_SETUP_FILE_NAME = "pcb_gcode_is_setup"; + +// Current profile array and indices for it. +string CURRENT_PROFILE[]; +enum { + FILE_NAME = 0, + AUTHOR = 1, + DESCRIPTION = 2 + } + +string get_current_profile() +{ + string files[]; + int num_files = fileglob(files, g_path + "/" + IS_SETUP_FILE_NAME); + if (num_files > 0) { + fileread(CURRENT_PROFILE, g_path + "/" + IS_SETUP_FILE_NAME); + } + else { + CURRENT_PROFILE[FILE_NAME] = "NONE"; + CURRENT_PROFILE[AUTHOR] = "NONE"; + CURRENT_PROFILE[DESCRIPTION] = "NONE"; + return "NONE"; + } + + return CURRENT_PROFILE[DESCRIPTION]; +} + +void set_current_profile(string profile_fields) +{ + strsplit(CURRENT_PROFILE, profile_fields, '\t'); + output(g_path + "/" + IS_SETUP_FILE_NAME) { + printf("%s\n", CURRENT_PROFILE[FILE_NAME]); + printf("%s\n", CURRENT_PROFILE[AUTHOR]); + printf("%s\n", CURRENT_PROFILE[DESCRIPTION]); + } +} + +int program_is_setup() +{ + if (get_current_profile() == "NONE") + return NO; + + return YES; +} + +void path_not_set_error() +{ + dlgMessageBox("There is a problem with your installation of pcb-gcode.\n" + + "You probably need to add the path to pcb-gcode's folder in " + + "EAGLE's Control Panel | Options | Directories | User Language Programs setting.\n" + "Please see the Configuration section of the manual"); + exit(-1); +} + + +// Find the path where all our files are located. It must be one of the directories in the +// Options | Directories | User Language Programs settings. + + +void get_path() +{ + int index = 0; + string last_g_path; + + board(B) g_path = filedir(B.name); + + last_g_path = g_path; + while (g_path > "") { + g_path = remove_last_dir(g_path); + if (filetime(g_path + "/source/pcb-gcode.h")) { + return; + } + if (last_g_path == g_path) { + break; + } + last_g_path = g_path; + } + + while (path_ulp[index] != "" && index < 10) { + if(filetime(path_ulp[index] + "/source/pcb-gcode.h")) { + g_path = path_ulp[index]; + return; + } + index++; + } +} + +get_path(); + +if (g_path == "") { + path_not_set_error(); +} +else { +// dlgMessageBox("g_path = " + g_path); +} + +// This reads the current profile into CURRENT_PROFILE, if available. +get_current_profile(); + +// I know, I know. No way around it that I see right now. +string g_real_to_string_string = ""; +string real_to_string(real n) +{ + sprintf(g_real_to_string_string, "%f", n); + return g_real_to_string_string; +} + +string g_int_to_string_string = ""; +string int_to_string(int n) +{ + sprintf(g_int_to_string_string, "%d", n); + return g_int_to_string_string; +} + + +// Used to show debugging information. +string g_debug; + From 17563543e9aedae92b3a00213b507987c1e43f7e Mon Sep 17 00:00:00 2001 From: deHarro Date: Mon, 26 Aug 2024 14:14:38 +0200 Subject: [PATCH 03/10] Update .gitignore no backup files to github --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 995dfdc..b75e8f6 100644 --- a/.gitignore +++ b/.gitignore @@ -17,3 +17,4 @@ viewer/applet/data/optimize_me.txt viewer/**/optimize_me.txt *.b#1 *.b#* +*.bak From aacf94bc411670552999f7cf4164a7d812ab3f04 Mon Sep 17 00:00:00 2001 From: deHarro Date: Mon, 26 Aug 2024 14:44:22 +0200 Subject: [PATCH 04/10] Delete source/pcb-gcode.h.bak no backup files on github --- source/pcb-gcode.h.bak | 270 ----------------------------------------- 1 file changed, 270 deletions(-) delete mode 100644 source/pcb-gcode.h.bak diff --git a/source/pcb-gcode.h.bak b/source/pcb-gcode.h.bak deleted file mode 100644 index 870e5d0..0000000 --- a/source/pcb-gcode.h.bak +++ /dev/null @@ -1,270 +0,0 @@ -// -*- Mode: Eagle -*- -// -// Constants and enums for pcb-gcode.ulp. -// -// (Actually, they should be consts and typedefs, -// but Eagle doesn't support that.) -// - -// -// No users options here. -// - -#include "string.h" - -string RELEASE = "NOT SET"; -string REVISION = "000"; - -string g_path = ""; - -string BOARD_NAME; -board(B) { BOARD_NAME = B.name; } - -enum { - U_MICRONS = 0, - U_MILLIMETERS = 1, - U_MILS = 2, - U_INCHES = 3, - U_INTERNALS = 4 -}; - -enum { - OUTPUT_MICRONS = 0, - OUTPUT_MILLIMETERS = 1, - OUTPUT_MILS = 2, - OUTPUT_INCHES = 3, - OUTPUT_INTERNALS = 4 -}; - -enum { - HOLE_MILL_CONCENTRIC = 0, - HOLE_MILL_HELICAL = 1 -} - -enum { NO = 0, YES = 1 }; -enum { false = 0, true = 1 }; - -enum { TASK_INVALID, TASK_OUTLINES, TASK_FILL }; - -enum { ST_INVALID, - ST_START_LINE, ST_CONTINUE_LINE, ST_END_LINE, - ST_DRILL, - ST_FILL, - ST_ARC_BEGIN, - ST_ARC_END, - ST_ARC}; - -enum { TOP = 0, BOTTOM = 1, MILL = 2, TEXT = 3, STENCIL = 4, ALL = 5 }; - -int PROGRAM_NAME_ARG = 0; -int FILENAME_ARG = 1; -int TOOL_SIZE_ARG = 2; -int ISO_ARG = 3; -int PASS_ARG = 4; -int PHASE_ARG = 5; - -real COORD_TOLERANCE = 0.0001; - -string OUTLINES_SIGNAL_NAME = "_OUTLINES_"; - -int TOP_LAYER = 1; -int BOTTOM_LAYER = 16; -int TOP_CREAM_LAYER = 31; -int BOTTOM_CREAM_LAYER = 32; -int MILL_LAYER = 46; -int TEXT_LAYER = 46; // same as MILL_LAYER - -int OUTLINES = 1; -int FILL = 2; -int MILL_BOARD = 3; -int MILL_TEXT = 4; - -enum { - PH_INVALID = 0, - PH_TOP_OUT_GEN = 1, - PH_TOP_OUT_WRITE = 2, - PH_TOP_FILL_GEN = 3, - PH_TOP_FILL_WRITE = 4, - PH_TOP_STENCIL = 5, - PH_BOTTOM_OUT_GEN = 6, - PH_BOTTOM_OUT_WRITE = 7, - PH_BOTTOM_FILL_GEN = 8, - PH_BOTTOM_FILL_WRITE = 9, - PH_BOTTOM_STENCIL = 10, - PH_TOP_DRILL = 11, - PH_BOTTOM_DRILL = 12, - PH_MILL = 13, - PH_TEXT = 14, - - PH_LAST_PHASE = 15 -}; - -string FILEMODE_WRITE_TEXT = "wt"; -string FILEMODE_APPEND_TEXT = "at"; - -string PHASE_NAME[] = { - "invalid", - "Gen_Top_Outlines", "Write_Top_Outlines", - "Gen_Top_Fill", "Write_Top_Fill", - "Top_Stencil", - "Gen_Bottom_Outlines", "Write_Bottom_Outlines", - "Gen_Bottom_Fill", "Write_Bottom_Fill", - "Bottom_Stencil", - "Top_Drills", "Bottom_Drills", - "Milling", - "Text", - "Finished!" -}; - -string get_phase_name(int phase) -{ - return PHASE_NAME[phase]; -} - -// Used to convert a numeric state into a text name for that state. -string state_text[] = { - "ST_START_LINE", - "ST_CONTINUE_LINE", - "ST_END_LINE", - "ST_DRILL", - "ST_FILL" -}; - -real ROUND_FACTOR = 1000; - -real BORDER_SIZE = 0.001; - -/* - * Indexes for stack elements when used for drill holes. - */ -int DRILL_SIZE = 0; -int DRILL_TOOL_NUM = 1; -int DRILL_X = 2; -int DRILL_Y = 3; -int DRILL_HOLE_SIZE = 4; - - -real g_tool_size = 0.01; -int g_side = TOP; - -// Which phase of the process we're working on. -int g_phase; - -string IS_SETUP_FILE_NAME = "pcb_gcode_is_setup"; - -// Current profile array and indices for it. -string CURRENT_PROFILE[]; -enum { - FILE_NAME = 0, - AUTHOR = 1, - DESCRIPTION = 2 - } - -string get_current_profile() -{ - string files[]; - int num_files = fileglob(files, g_path + "/" + IS_SETUP_FILE_NAME); - if (num_files > 0) { - fileread(CURRENT_PROFILE, g_path + "/" + IS_SETUP_FILE_NAME); - } - else { - CURRENT_PROFILE[FILE_NAME] = "NONE"; - CURRENT_PROFILE[AUTHOR] = "NONE"; - CURRENT_PROFILE[DESCRIPTION] = "NONE"; - return "NONE"; - } - - return CURRENT_PROFILE[DESCRIPTION]; -} - -void set_current_profile(string profile_fields) -{ - strsplit(CURRENT_PROFILE, profile_fields, '\t'); - output(g_path + "/" + IS_SETUP_FILE_NAME) { - printf("%s\n", CURRENT_PROFILE[FILE_NAME]); - printf("%s\n", CURRENT_PROFILE[AUTHOR]); - printf("%s\n", CURRENT_PROFILE[DESCRIPTION]); - } -} - -int program_is_setup() -{ - if (get_current_profile() == "NONE") - return NO; - - return YES; -} - -void path_not_set_error() -{ - dlgMessageBox("There is a problem with your installation of pcb-gcode.\n" + - "You probably need to add the path to pcb-gcode's folder in " + - "EAGLE's Control Panel | Options | Directories | User Language Programs setting.\n" - "Please see the Configuration section of the manual"); - exit(-1); -} - - -// Find the path where all our files are located. It must be one of the directories in the -// Options | Directories | User Language Programs settings. - - -void get_path() -{ - int index = 0; - string last_g_path; - - board(B) g_path = filedir(B.name); - - last_g_path = g_path; - while (g_path > "") { - g_path = remove_last_dir(g_path); - if (filetime(g_path + "/source/pcb-gcode.h")) { - return; - } - if (last_g_path == g_path) { - break; - } - last_g_path = g_path; - } - - while (path_ulp[index] != "" && index < 10) { - if(filetime(path_ulp[index] + "/source/pcb-gcode.h")) { - g_path = path_ulp[index]; - return; - } - index++; - } -} - -get_path(); - -if (g_path == "") { - path_not_set_error(); -} -else { -// dlgMessageBox("g_path = " + g_path); -} - -// This reads the current profile into CURRENT_PROFILE, if available. -get_current_profile(); - -// I know, I know. No way around it that I see right now. -string g_real_to_string_string = ""; -string real_to_string(real n) -{ - sprintf(g_real_to_string_string, "%f", n); - return g_real_to_string_string; -} - -string g_int_to_string_string = ""; -string int_to_string(int n) -{ - sprintf(g_int_to_string_string, "%d", n); - return g_int_to_string_string; -} - - -// Used to show debugging information. -string g_debug; - From b14de4256bc3d3a0dcb723929eb96daa71ca7743 Mon Sep 17 00:00:00 2001 From: deHarro Date: Mon, 26 Aug 2024 14:44:39 +0200 Subject: [PATCH 05/10] Delete pcb-gcode.ulp.bak no backup files on github --- pcb-gcode.ulp.bak | 1796 --------------------------------------------- 1 file changed, 1796 deletions(-) delete mode 100644 pcb-gcode.ulp.bak diff --git a/pcb-gcode.ulp.bak b/pcb-gcode.ulp.bak deleted file mode 100644 index dc99626..0000000 --- a/pcb-gcode.ulp.bak +++ /dev/null @@ -1,1796 +0,0 @@ -// -// Generate g-code for milling PC boards. -// -// Copyright 2004-2014 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/library.h" -#include "source/drill.h" -#include "source/pcb-file-utils.h" -#include "source/filename_subs.h" - -#usage "
pcb-gcode™ Gcode Generation Utility
" - " Version 3.7.2-alpha

" - "Copyright© 2003 - 2022 by John Johnson Software, LLC
" - "All Rights Reserved

" - "

" - "Join the Groups pcb-gcode group " - "https://groups.io/g/pcbgcode" - "
or contact the author at pcbgcode@pcbgcode.org" - "
" - "


" - "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.

" - "It will create files for the outlines of tracks, drilling holes, and milling cutouts in the board." - "
See the readme.html file for more info.

" - "There are many options in the setup program.
" - "To setup which files are generated, and how, use the following command:
" - "run pcb-gcode --setup

" - "

" - "If you want to produce a set of files without changing options, you can run pcb-gcode directly." - "Usage is as follows:
" - "run pcb-gcode [option] [file]
" - "Where:\n" - "" - "" - "" - "" - "" - "" - "
OptionFunction
--helpShow this help screen
--setupRun the setup / configuration program
fileIs the optional root filename.\n
If not given, the board name is used as the root filename.
" - "" - "" - "


" - -g_tool_size = TOOL_SIZE; - -// Filename to output to. -string m_file_name = ""; - -// Which side we're currently working on. -g_side = TOP; - -// Index of current being used. -int m_current_tool_ndx = 0; - -// Current tool number being used (e.g. agrees with e.g. T02) -int m_current_tool_num = 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; - - - -////////// mlmSolutions added 29 Jan 14 - -real m_v_x[], m_v_y[], m_v_rad[]; -real m_tool_x, m_tool_y, m_vx1, m_vy1, m_vx2, m_vy2, m_rad; -int m_v_index[], m_v_prev[], m_v_next[], m_v_step[], m_v_cont[], m_v_curve[], m_c_start[], m_c_end[]; -int m_contours, m_cw, m_v_n=1, m_fwd, m_dist, m_dist_min, m_dist_min_index; -int m_wire_start, m_z_up, m_step, m_i, m_j, m_cont, m_border_contour; - -////////// - -// -// Save the maximum and minimum coordinates. -// -// Params: -// x, y Coordinates to be tested, and possibly saved as min or max values. -// Return: -// none -// -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); -} - -// -// Open the platform-specific previewer. -// -// Params: none -// Return: none -// -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 = PH_BOTTOM_OUT_GEN; - return; - } - if (g_phase == PH_BOTTOM_OUT_GEN && GENERATE_BOTTOM_OUTLINES != YES) { - g_phase = PH_TOP_DRILL; - 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++; - } - - // dlgMessageBox(fi("next_phase(): g_phase=%d", g_phase)); -} - -////////////////////////////////////////////////// -// -// Hole drilling routines. -// -////////////////////////////////////////////////// - -// -// Add a drill hole entry (size, x, y) to the stack. -// -// Params: -// Size Drill size. -// req_size Desired drill hole size. (May be subbed.) -// x x coordinate. -// y y coordinate. -// Returns: -// none -// Changes: -// the stack entry will have: -// drill_size \t tool_num \t x \t y \t requested_size -// -void push_hole_onto_stack(int req_size, int x, int y) -{ - string tempstr; - int tool_num; - int drill_size; - - tool_num = get_tool_for(req_size); - drill_size = get_tool_param_iu(tool_num, RACK_TOOL_SIZE); - - sprintf(tempstr, "%06d\t%06d\t%06d\t%06d\t%06d", drill_size, tool_num, x, y, req_size); - stack_push(tempstr); -} - -// -// Return the distance between two points. -// -// Params: -// x1, y1, x2, y2 coordinates for two points. -// Return: -// the distance between the points. -// -real distance(real x1, real y1, real x2, real y2) { - return (sqrt((x1-x2)*(x1-x2) + (y1-y2)*(y1-y2))); -} - -// -// Sorts a stack of drills in g_stack by distance from last hole. -// -// Params: none -// Return: none -// Changes: -// the stack -// -void pythagorean_sort_stack() { - real drill_size1; - real tool_num1; - real drill_x1; - real drill_y1; - real drill_size2; - real tool_num2; - real drill_x2; - real drill_y2; - real drill_size3; - real tool_num3; - real drill_x3; - real drill_y3; - int i; - int j; - string drill_args1[]; - string drill_args2[]; - string drill_args3[]; - string tmp; - - real before_distance; - real after_distance; - - // Sort by size, tool, x, then y - stack_sort(); - - for (i = 0; i <= stack_count(); i++) { - strsplit(drill_args1, stack_elem(i), '\t'); - drill_size1 = internals_to_user(my_strtol(drill_args1[DRILL_SIZE])); - tool_num1 = my_strtol(drill_args1[DRILL_TOOL_NUM]); - drill_x1 = scale_x(my_strtol(drill_args1[DRILL_X])); - drill_y1 = scale_y(my_strtol(drill_args1[DRILL_Y])); - - j = i + 2; - while (j <= stack_count()) { - strsplit(drill_args2, stack_elem(i+1), '\t'); - drill_size2 = internals_to_user(my_strtol(drill_args2[DRILL_SIZE])); - tool_num2 = my_strtol(drill_args2[DRILL_TOOL_NUM]); - drill_x2 = scale_x(my_strtol(drill_args2[DRILL_X])); - drill_y2 = scale_y(my_strtol(drill_args2[DRILL_Y])); - - strsplit(drill_args3, stack_elem(j), '\t'); - drill_size3 = internals_to_user(my_strtol(drill_args3[DRILL_SIZE])); - tool_num3 = my_strtol(drill_args3[DRILL_TOOL_NUM]); - drill_x3 = scale_x(my_strtol(drill_args3[DRILL_X])); - drill_y3 = scale_y(my_strtol(drill_args3[DRILL_Y])); - - if (drill_size2 != drill_size1 || drill_size3 != drill_size1 || - tool_num2 != tool_num1 || tool_num3 != tool_num1) - break; - - if (distance(drill_x1, drill_y1, drill_x3, drill_y3) < distance(drill_x1, drill_y1, drill_x2, drill_y2)) { - tmp = stack_elem(j); - stack_put(j, stack_elem(i+1)); - stack_put(i+1, tmp); - j = i + 1; - } - j++; - } - } -} - -/* - * Create a drill file for the desired side. - * - * Params: - * which_side Side to produce the file for. - * Returns: - * none - * Changes: - * m_current_tool_ndx - * g_side -*/ -void output_drill_file(int which_side) -{ - int num_lines; - int i; - real last_size; - string drill_args[]; - real drill_size_mm; - real drill_size_inch; - real drill_size; - real drill_x; - real drill_y; - real hole_size; - int drill_tool_num; - int last_drill_tool_num; - - m_current_tool_ndx = 0; - g_side = which_side; - - // - // Build a stack with all the holes. - // - board(B) { - B.holes(H) push_hole_onto_stack(H.drill, H.x, H.y); - B.signals(S) S.vias(V) push_hole_onto_stack(V.drill, V.x, V.y); - B.elements(E) { - E.package.contacts(C) { - if (C.pad) { - push_hole_onto_stack(C.pad.drill, C.pad.x, C.pad.y); - } - } - E.package.holes(H) push_hole_onto_stack(H.drill, H.x, H.y); - } - // B.elements - - // Dump the drill stack to a file for troubleshooting - // output(g_path + "/before_stack.txt", FILEMODE_WRITE_TEXT) { - // printf("before stack sort\n"); - // for (i=stack_fwd_iter(); i != END_OF_STACK; i=stack_fwd_next()) { - // printf("%s\n", stack_elem(i)); - // } - // } - - // Sorts the drills by size, tool_number, then distance from previous hole. - pythagorean_sort_stack(); - - // Dump the drill stack to a file for troubleshooting - // output(g_path + "/after_stack.txt", FILEMODE_WRITE_TEXT) { - // printf("after stack sort\n"); - // for (i=stack_fwd_iter(); i != END_OF_STACK; i=stack_fwd_next()) { - // printf("%s\n", stack_elem(i)); - // } - // } - - // - // Create the drill g-code file. - // - last_size = -1; - output(get_filename(), FILEMODE_WRITE_TEXT) { - output_file_preamble(); - - // - // Create a tool table at the beginning of the file. - // - comm("Rack file: " + elided_path(m_rack_file_name, 30)); - comm("Min Sub is the minimum hole size this tool was subbed for."); - comm("Max Sub is the maximum hole size this tool was subbed for."); - 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]); - drill_tool_num = my_strtol(drill_args[DRILL_TOOL_NUM]); - - if (drill_size_mm == 0.0) continue; - - if (drill_size != last_size || drill_tool_num != last_drill_tool_num) { - ++m_current_tool_ndx; - if (get_tool_param_iu(drill_tool_num, RACK_TOOL_TYPE) == RACK_TOOL_DRILL) { - out(TOOL_CHANGE_TABLE_FORMAT(drill_tool_num, - drill_size_mm, drill_size_inch, - g_min_subbed_for[drill_tool_num], g_max_subbed_for[drill_tool_num], - g_drill_sub_cnt[drill_tool_num], "")); - } - else { - out(TOOL_CHANGE_TABLE_FORMAT(drill_tool_num, - drill_size_mm, drill_size_inch, - g_min_subbed_for[drill_tool_num], g_max_subbed_for[drill_tool_num], - g_drill_sub_cnt[drill_tool_num], "THIS IS AN ENDMILL")); - } - } - last_size = drill_size; - last_drill_tool_num = drill_tool_num; - } - // for - - begin_gcode(SPINDLE_DRILL_RPM); - - // - // Generate drill code. - // - m_current_tool_ndx = 0; - for (i=stack_fwd_iter(); i != END_OF_STACK; i=stack_fwd_next()) { - strsplit(drill_args, stack_elem(i), '\t'); - drill_size = internals_to_user(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])); - hole_size = internals_to_user(my_strtol(drill_args[DRILL_HOLE_SIZE])); - drill_tool_num = my_strtol(drill_args[DRILL_TOOL_NUM]); - save_extents(drill_x, drill_y); - - if (drill_size == 0.0) continue; - - // - // Check to see if the drill size has changed, - // if so, output a tool change and optional zero code. - // - if (drill_size == last_size && drill_tool_num == last_drill_tool_num) { - if (get_tool_param_iu(m_current_tool_num, RACK_TOOL_TYPE) == RACK_TOOL_DRILL) { - output_drill_hole(drill_x, drill_y, DRILL_DEPTH); - } - else { - output_mill_hole(drill_x, drill_y, DRILL_DEPTH, hole_size, m_current_tool_num); - } - } - else { - m_current_tool_ndx++; - // Tool change routine - output_tool_change_begin(); - out(SPINDLE_OFF); - rz(TOOL_CHANGE_POS_Z); - rxy(TOOL_CHANGE_POS_X, TOOL_CHANGE_POS_Y); - m_current_tool_num = drill_tool_num; - out(fir(TOOL_CHANGE, m_current_tool_num, drill_size)); - output_tool_changed(); - - // Output zero steps and a pause - if (DO_TOOL_CHANGE_WITH_ZERO_STEP == YES) { - output_tool_zero_begin(); - fzr(0.000, FEED_RATE_DRILL_Z); - out(OPERATOR_PAUSE + EOL); - output_tool_zero_end(); - } - - rz(DEFAULT_Z_UP); - out(fr(SPINDLE_ON, SPINDLE_ON_TIME)); - output_tool_change_end(); - - if (get_tool_param_iu(m_current_tool_num, RACK_TOOL_TYPE) == RACK_TOOL_DRILL) { - output_drill_first_hole(drill_x, drill_y, DRILL_DEPTH); - } - else { - output_mill_hole(drill_x, drill_y, DRILL_DEPTH, hole_size, m_current_tool_num); - } - last_size = drill_size; - last_drill_tool_num = drill_tool_num; - } - // 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 - -// holds line segments generated for the previewer -string m_lines; - -// -// Format the coordinates of two points to be used by the previewer. -// -// Params: -// x1, y1, x2, y2 Two points. -// Return: -// Coordinates formatted for the previewer. -// - -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); -} - -// -// Generates gcode for spot drilling and previewing holes. -// -// Params: -// drill_size Size of the hole to drill. -// x, y Location of the hole. -// Return: none -// Changes: -// m_first_spot_drill -// m_lines -// g_side -// -int m_first_spot_drill = YES; -void spot_drill_hole(int drill_size, int x, int y) -{ - real drill_x; - real drill_y; - real offset; - - drill_x = scale_x(x); - drill_y = scale_y(y); - save_extents(drill_x, drill_y); - - if (SPOT_DRILL == YES) { - if (m_first_spot_drill) { - comm("spot drill holes"); - 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); - } - } - - offset = internals_to_user(drill_size) / 2; - - // - // Generate X's for drill preview if drills are turned on for this side. - // - if ((g_side == TOP && GENERATE_TOP_DRILL == YES) || - (g_side == BOTTOM && GENERATE_BOTTOM_DRILL == YES)) { - m_lines += coords(drill_x - offset, drill_y - offset, drill_x + offset, drill_y + offset); - m_lines += coords(drill_x - offset, drill_y + offset, drill_x + offset, drill_y - offset); - } -} - -// -// Enumerates all holes and generates spot drills for them. -// -// Params: -// B The board. -// Return: none -// Changes: -// m_lines -// -void spot_drill(UL_BOARD B) -{ - - m_lines += "# spot drills\n"; - - B.holes(H) spot_drill_hole(H.drill, H.x, H.y); - B.signals(S) S.vias(V) spot_drill_hole(V.drill, V.x, V.y); - B.elements(E) { - E.package.contacts(C) { - if (C.pad) { - spot_drill_hole(C.pad.drill, C.pad.x, C.pad.y); - } - } - E.package.holes(H) spot_drill_hole(H.drill, H.x, H.y); - } - // B.elements -} - -// -// "Draw" on the output device, i.e. the gcode file. -// -// Params: -// x1,y1 Start of the line. -// x2,y2 End of the line. -// state The state of the line being drawn, start, continue, etc. -// z_down_or_radius Z depth or radius of arc -// fr_xy XY feed rate -// fr_z Z feed rate -// Returns: -// none -// Changes: -// m_lines -// m_arc_begin_x -// m_arc_begin_y -// m_arc_radius -// -real m_arc_begin_x; -real m_arc_begin_y; -real m_arc_radius; -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_or_radius, real fr_xy, real fr_z) -{ - real rx1, ry1, rx2, ry2; - - string str; - - real i_coord; - real j_coord; - - 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_or_radius, fr_z); - fxyr(rx2, ry2, fr_xy); - 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; - m_arc_radius = internals_to_user(z_down_or_radius); - 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; - - rz(DEFAULT_Z_UP); - rxy(end_x, end_y); - fzr(z_down_or_radius, FEED_RATE_MILL_Z); - - // cx and cy are in absolute coords, convert to relative for I,J - i_coord = end_x - cx; - j_coord = end_y - cy; - - if (g_side == TOP || MIRROR_BOTTOM == YES) { - fcwr(m_arc_begin_x, m_arc_begin_y, i_coord, j_coord, fr_xy); - } - else { - fccwr(m_arc_begin_x, m_arc_begin_y, i_coord, j_coord, fr_xy); - } - break; - -////////// mlmSolutions 5 Feb 14 - - case ST_ARC: - i_coord = (rx2 - rx1) / 2; - j_coord = (ry2 - ry1) / 2; - if (m_z_up){ - rz(DEFAULT_Z_UP); - rxy(rx1, ry1); - fzr(z_down_or_radius, fr_z); - } - if (((g_side == TOP) && m_cw) || ((g_side != TOP) && !m_cw)) { - fcwr(rx2, ry2, i_coord, j_coord, fr_xy); - } - else { - fccwr(rx2, ry2, i_coord, j_coord, fr_xy); - } - 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 -// Changes: -// m_layer -// g_cmd -// -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 = internals_to_user(B.area.x1) - f; - real y1 = internals_to_user(B.area.y1) - f; - real x2 = internals_to_user(B.area.x2) + f; - real y2 = internals_to_user(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" - , - get_unit_of_measure(), - m_isolate, - g_tool_size, - m_layer, - OUTLINES_SIGNAL_NAME, g_tool_size, - x1, y1, x2, y1, x2, y2, x1, y2, x1, y1 - ); - g_cmd = g_cmd + cmd_temp; - return; - } - // board(B) -} -// generate_outlines - -// -// Output info and lines to a file for the previewer. -// -// Params: -// path Path and filename. -// mode File open mode. May be write or append. -// layer MILL, TEXT, etc. -// Returns: -// none -// Changes: -// none -// -void out_lines(string path, string mode, int layer) -{ - output(path, mode) { - if (m_pass_num == 0) { - printf("# board=%s\n", elided_path(get_filename(), 30)); - if (layer == MILL) { - printf("# depth=%f\n", MILLING_DEPTH); - } - else if (layer == TEXT) { - printf("# depth=%f\n", TEXT_DEPTH); - } - else { - printf("# tool size=%f\n", g_tool_size); - } - } - printf("# pass=%d\n", m_pass_num + 1); - printf("# preview window width=%d height=%d\n", PREVIEW_WINDOW_WIDTH, PREVIEW_WINDOW_HEIGHT); - printf(m_lines); - } -} - -// -// Output preview data to the platform specific files. -// -// Params: -// mode File open mode. May be write or append. -// Returns: -// none -// Changes: -// none -// -void output_preview_data(string mode, int layer) -{ - out_lines(g_path + "/viewer/data/optimize_me.txt", mode, layer); - out_lines(g_path + "/viewer/applet/data/optimize_me.txt", mode, layer); - out_lines(g_path + "/viewer/application.macosx/data/optimize_me.txt", mode, layer); - out_lines(g_path + "/viewer/application.linux/data/optimize_me.txt", mode, layer); - out_lines(g_path + "/viewer/application.windows/data/optimize_me.txt", mode, layer); -} - -// -// Write text from the Milling layer to a text engraving file. -// -// Params: -// none -// Return: -// none -// Changes: -// g_tool_size -// m_lines -// -void output_text_code() -{ - int state; - int old_x, old_y; - - board(B) { - output(get_filename(), FILEMODE_WRITE_TEXT) { - user_file_opened(get_filename(), FILEMODE_WRITE_TEXT); - - output_file_preamble(); - - // Initialize the device (i.e. the output file). - begin_gcode(SPINDLE_TEXT_RPM); - - // 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, W.arc.radius, FEED_RATE_TEXT_XY, FEED_RATE_TEXT_Z); - device_draw( W.arc.x2, W.arc.y2, W.arc.xc, W.arc.yc, ST_ARC_END, TEXT_DEPTH, FEED_RATE_TEXT_XY, FEED_RATE_TEXT_Z); - 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, FEED_RATE_TEXT_XY, FEED_RATE_TEXT_Z); - 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(), FILEMODE_WRITE_TEXT); - } - // board - g_tool_size = abs(TEXT_DEPTH); - output_preview_data(FILEMODE_WRITE_TEXT, TEXT); - preview(); - - m_lines = ""; -} -// output_text_code - - -////////// mlmSolutions added 21 Jan 14 - -// -// Checks if two vertices match. If yes, return true else return false. -// -// Params: -// X1, Y1, X2, Y2 -// Return: -// true or false -// Changes: -// nothing -// -int match(real X1, real Y1, real X2, real Y2) -{ - if ((X1 == X2) && (Y1 == Y2)) return true; else return false; -} - -// -// Removes a vertex from the linked list. -// -// Params: -// id - the id of the vertex to be removed -// Return: -// nothing -// Changes: -// pointers of previous and next entry -// -void vertex_remove(int id) -{ - m_v_next[m_v_prev[id]] = m_v_next[id]; - m_v_prev[m_v_next[id]] = m_v_prev[id]; -} - - -////////// - - -// -// Write layer data to mill files. -// -// Params: -// none -// Return: -// none -// Changes: -// g_tool_size -// m_lines -// -void output_mill_code() -{ - int state; - int old_x, old_y; - int first_run = true; - string str; - - board(B) { - output(get_filename(), FILEMODE_WRITE_TEXT) { - user_file_opened(get_filename(), FILEMODE_WRITE_TEXT); - - output_file_preamble(); - - // Initialize the device (i.e. the output file). - begin_gcode(SPINDLE_MILL_RPM); - - m_v_n =1; - - // 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 && !first_run) { - state = ST_CONTINUE_LINE; - } - else { - state = ST_START_LINE; - first_run = false; - } - - // if this is an arc, it is treated specially. - if (P.arc) { - sprintf(str, "# arc xc=%f yc=%f sang=%f eang=%f radius=%f\n", - scale_x(P.arc.xc), scale_y(P.arc.yc), P.arc.angle1, P.arc.angle2, scale_x(P.arc.radius)); - m_lines += str; - sprintf(str, "# debug W.x1=%8.5f W.y1=%8.5f W.x2=%8.5f W.y2=%8.5f W.curve=%f\n", - scale_x(W.x1), scale_y(W.y1), scale_x(W.x2), scale_y(W.y2), W.curve); - m_lines += str; - sprintf(str, "# debug P.arc.x1=%8.5f P.arc.y1=%8.5f P.arc.x2=%8.5f P.arc.y2=%8.5f\n", - scale_x(P.arc.x1), scale_y(P.arc.y1), scale_x(P.arc.x2), scale_y(P.arc.y2)); - m_lines += str; - m_lines += "# debug\n"; -// device_draw( P.arc.x1, P.arc.y1, P.arc.x2, P.arc.y2, ST_ARC_BEGIN, P.arc.radius, FEED_RATE_MILL_XY, FEED_RATE_MILL_Z); -// device_draw( P.arc.x2, P.arc.y2, P.arc.xc, P.arc.yc, ST_ARC_END, MILLING_DEPTH, FEED_RATE_MILL_XY, FEED_RATE_MILL_Z); - -////////// mlmSolutions added 5 Feb 14 - // As we cannot assume that "pieces" come from "wires" in any particular order or that they are contiguous - // we will have to save the start and end vertices. - // save arc data - m_v_x[m_v_n] = P.arc.x1; - m_v_y[m_v_n] = P.arc.y1; - m_v_rad[m_v_n] = P.arc.radius; - m_v_curve[m_v_n] = W.curve; - m_v_prev[m_v_n] = m_v_n - 1; - m_v_next[m_v_n] = 0; - m_v_next[m_v_n - 1] = m_v_n; - m_v_step[m_v_n] = 0; - ++m_v_n; - - m_v_x[m_v_n] = P.arc.x2; - m_v_y[m_v_n] = P.arc.y2; - m_v_rad[m_v_n] = P.arc.radius; - m_v_curve[m_v_n] = W.curve; - m_v_prev[m_v_n] = m_v_n - 1; - m_v_next[m_v_n] = 0; - m_v_next[m_v_n - 1] = m_v_n; - m_v_step[m_v_n] = 0; - ++m_v_n; -////////// - 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, FEED_RATE_MILL_XY, FEED_RATE_MILL_Z); - -////////// mlmSolutions added 5 Feb 14 - // save line data - m_v_x[m_v_n] = P.x1; - m_v_y[m_v_n] = P.y1; - m_v_rad[m_v_n] = 0; - m_v_curve[m_v_n] = 0; - m_v_prev[m_v_n] = m_v_n - 1; - m_v_next[m_v_n] = 0; - m_v_next[m_v_n - 1] = m_v_n; - m_v_step[m_v_n] = 0; - ++m_v_n; - - m_v_x[m_v_n] = P.x2; - m_v_y[m_v_n] = P.y2; - m_v_rad[m_v_n] = 0; - m_v_curve[m_v_n] = 0; - m_v_prev[m_v_n] = m_v_n - 1; - m_v_next[m_v_n] = 0; - m_v_next[m_v_n - 1] = m_v_n; - m_v_step[m_v_n] = 0; - ++m_v_n; - -////////// - 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 - -////////// mlmSolutions added 5 Feb 14 yyyy - - //Optimises the path using nearest neighbour - m_tool_x = X_HOME; - m_tool_y = Y_HOME; - m_step = 0; - // set direction of cut around contour - //if (((g_side == TOP) && !CLIMB_MILLING) || ((g_side == BOTTOM) && CLIMB_MILLING)) m_fwd = true; else m_fwd = false; - while (m_v_next[0] > 0){ - //find nearest vertex from current location - m_dist_min = 99999999; - m_i=0; //start from the head pointer - while (m_v_next[m_i] > 0){ // loop till end of unprocessed list - m_i = m_v_next[m_i]; //the index of the next unprocessed vertex - m_dist = distance(m_tool_x, m_tool_y, m_v_x[m_i], m_v_y[m_i]); - //m_dist = abs(m_tool_x - (m_v_x[m_i])) + abs(m_tool_y - (m_v_y[m_i])); //approximate to make faster - if (m_dist < m_dist_min){ - m_dist_min = m_dist; - m_dist_min_index = m_i; - } - } - m_i = m_dist_min_index; - m_v_step[m_i] = ++m_step; - vertex_remove(m_i); - //the next step must be the other end of this wire. If the vertex is odd, its the next vertex else its the previous. - if ((m_i % 2) == 1) ++m_i; else --m_i; - m_v_step[m_i] = ++m_step; - vertex_remove(m_i); - - //move the tool position to new location - m_tool_x = (m_v_x[m_i]); - m_tool_y = (m_v_y[m_i]); - } - - // Generate the gcode - // sort into step order - sort(m_v_n, m_v_index, m_v_step); - m_tool_x = X_HOME; m_tool_y = Y_HOME; - m_wire_start = true; //the vertices are stored in pairs. X1Y1 first then X2Y2 - first_run = true; - for (m_i=1; m_i 0) { //its an arc - if ((m_j % 2) == 0) m_cw = false; else m_cw = true; //if its the end of an Eagle arc, m_cw=false - m_rad = m_v_rad[m_j]; if (abs(m_v_curve[m_j]) >180) m_rad = m_rad * -1; - device_draw(m_vx1, m_vy1, m_vx2, m_vy2, ST_ARC, MILLING_DEPTH, FEED_RATE_MILL_XY, FEED_RATE_MILL_Z); - } else { //its a line - device_draw(m_vx1, m_vy1, m_vx2, m_vy2, state, MILLING_DEPTH, FEED_RATE_MILL_XY, FEED_RATE_MILL_Z); - } - m_tool_x = m_vx2; m_tool_y = m_vy2; //save the tools current location - } - m_wire_start = !m_wire_start; - } - -////////// - output_file_postamble(); - end_gcode(); - user_file_closing(); - } - // output - user_file_closed(get_filename(), FILEMODE_WRITE_TEXT); - } - // board - - g_tool_size = abs(MILLING_DEPTH); - output_preview_data(FILEMODE_WRITE_TEXT, MILL); - preview(); - - m_lines = ""; -} -// output_mill_code - - -// -// Write polygon lines to the file. -// -// Params: -// which_side Side of the board to work on. -// task -// Return: -// none -// Changes: -// g_side -// m_layer -// g_cmd -// g_debug -// -void write_outlines(int which_side, 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; - real spindle_speed; - real fr_xy; - real fr_z; - - if (m_pass_num == 0) { - mode = FILEMODE_WRITE_TEXT; - } - else { - mode = FILEMODE_APPEND_TEXT; - } - g_side = which_side; - switch (which_side) { - case TOP: - m_layer = TOP_LAYER; - spindle_speed = SPINDLE_ETCH_RPM; - fr_xy = FEED_RATE_ETCH_XY; - fr_z = FEED_RATE_ETCH_Z; - break; - case BOTTOM: - m_layer = BOTTOM_LAYER; - spindle_speed = SPINDLE_ETCH_RPM; - fr_xy = FEED_RATE_ETCH_XY; - fr_z = FEED_RATE_ETCH_Z; - break; - case MILL: - m_layer = MILL_LAYER; - spindle_speed = SPINDLE_MILL_RPM; - fr_xy = FEED_RATE_MILL_XY; - fr_z = FEED_RATE_MILL_Z; - break; - case TEXT: - m_layer = TEXT_LAYER; - spindle_speed = SPINDLE_TEXT_RPM; - fr_xy = FEED_RATE_TEXT_XY; - fr_z = FEED_RATE_TEXT_Z; - 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(); - g_side = BOTTOM; - output_mill_code(); - return; - } - else { - g_side = TOP; - output_text_code(); - g_side = BOTTOM; - output_text_code(); - 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, fr_xy, fr_z); - device_draw(W.x1, W.y1, W.x2, W.y2, ST_END_LINE, DEFAULT_Z_DOWN, fr_xy, fr_z); // fixme needed? - } - } - } - - m_v_n = 1; - - 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(spindle_speed); - } - else { - output_between_outline_passes(); - } - - switch (task) { - case TASK_OUTLINES: - P.contours(W) { - -////////// mlmSolutions added 12 Feb 14 xxxx - // Save the contour wires (Except the frame) - // Each wire from the contour has a start and end vertex but the X1Y1 of the next vertex - // will have the same value as the X2Y2 of the current one for any specific contour. - // In order to minimise the number of vertices stored, we will store the X1Y1 only. - // The last X2Y2 should be the same as the first X1Y1. - // When a vertex has been processed it will be removed from the linked list - - // record the start and end vertex index for each new contour - if ( first ){ - ++m_contours; - m_c_start[m_contours-1] = m_v_n; - x0 = W.x1; y0 = W.y1; // remember start vertex - first = false; - } else if (W.x2 == x0 && W.y2 == y0) { - m_c_end[m_contours-1] = m_v_n; - first = true; - } - m_v_x[m_v_n] = W.x1; - m_v_y[m_v_n] = W.y1; - m_v_prev[m_v_n] = m_v_n - 1; - m_v_next[m_v_n] = 0; //indicate end of list - m_v_next[m_v_n-1] = m_v_n; //point previous vertex to us - m_v_step[m_v_n] = 0; - m_v_cont[m_v_n] = m_contours; - ++m_v_n; - - if (((W.x1 == x1 || W.x1 == x2) && (W.y1 == y1 || W.y1 == y2))){ //its on the border - m_border_contour = m_contours; - } -////////// - } - // 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, fr_xy, fr_z); - } - break; - } - // switch(task) - - -////////// mlmSolutions added 12 Feb 14 - - //Remove the border contour if any - if (m_border_contour > 0){ - for (m_i = m_c_start[m_border_contour - 1]; m_i <= m_c_end[m_border_contour - 1]; ++m_i){ - vertex_remove(m_i); - } - } - - // Optimise the path using the nearest neighbour. - // Each vertex will be tagged with its step number (order of tool movement) - // Eagle guarantees that if we move from X1Y1 to X2Y2 of a contour wire that the track will be on the right of the direction of movement. - // We will define this as forward. We store vertex values in a "forward" direction for increasing index values. - // This is therefore moving clockwise around a track when viewed from the top. (Climb Milling) - m_cont = 0; //set contour number to an invalid value to force a shortest distance scan initially - m_tool_x = X_HOME; - m_tool_y = Y_HOME; - m_step = 0; - - // set direction of cut around contour - if (((g_side == TOP) && !CLIMB_MILLING) || ((g_side == BOTTOM) && CLIMB_MILLING)) m_fwd = true; else m_fwd = false; - - // from http://harald-sattler.de/html/pcb-gcode_-e-.htm - // Mill first pass as climb, the remainder as conventional - // for better edge finishes. - if (m_pass_num == 0) m_fwd ; else m_fwd = !m_fwd; - - while (m_v_next[0] > 0){ - - //find nearest vertex from current location - m_dist_min = 99999999; - m_i=0; //start from the head pointer - - while (m_v_next[m_i] > 0){ // loop till end of unprocessed list - m_i = m_v_next[m_i]; //the index of the next unprocessed vertex - //m_dist = distance(m_tool_x, m_tool_y, internals_to_user(m_v_x[m_i]), internals_to_user(m_v_y[m_i])); - //m_dist = abs(m_tool_x - internals_to_user(m_v_x[m_i])) + abs(m_tool_y - internals_to_user(m_v_y[m_i])); - m_dist = abs(m_tool_x - (m_v_x[m_i])) + abs(m_tool_y - (m_v_y[m_i])); //approximate to make faster - if (m_dist < m_dist_min){ - m_dist_min = m_dist; - m_dist_min_index = m_i; - } - } - - // as the wires of a specific contour are issued from Eagle consecutively, most of the time the next vertex to go to - // is the next or previous in the list. If we check for this first, we can avoid a scan through the whole list. - m_cont = m_v_cont[m_dist_min_index] - 1; - m_i = m_dist_min_index; - do { - m_v_step[m_i] = ++m_step; - vertex_remove(m_i); - // move on to next vertex in contour - if (m_fwd){ - ++m_i; - if (m_i > m_c_end[m_cont]) m_i = m_c_start[m_cont]; // we got to end of contour so loop to begining - } else { - --m_i; - if (m_i < m_c_start[m_cont]) m_i = m_c_end[m_cont]; // we got to begining of contour so loop to end - } - } while (m_i != m_dist_min_index); // stop when we are back to the place we started - - // add an extra step to close the contour back to the start - m_v_x[m_v_n] = m_v_x[m_i]; - m_v_y[m_v_n] = m_v_y[m_i]; - m_v_step[m_v_n] = ++m_step; - m_v_cont[m_v_n] = m_v_cont[m_i]; - ++m_v_n; - - //move the tool position to new location - m_tool_x = (m_v_x[m_dist_min_index]); - m_tool_y = (m_v_y[m_dist_min_index]); - } - - - // Generate the gcode - // As we move through the steps - // 1) a new contour requires a Z retract, G00 to new location, Z plunge - // 2) otherwise just proceed. - - sort(m_v_n, m_v_index, m_v_step); // sort into step order - - for (m_j = 0; m_v_step[m_v_index[m_j]] == 0; ++m_j); // find the first non zero step - - m_cont=0; - for (m_i = m_j; m_i < m_v_n; ++m_i){ - m_j = m_v_index[m_i]; - m_vx2 = m_v_x[m_j]; m_vy2 = m_v_y[m_j]; //get the current vertex - if (m_cont != m_v_cont[m_j]) { //its a new contour so do a Z retract and G00 move and Z plunge - m_cont = m_v_cont[m_j]; - first = true; - x0 = m_vx2; y0 = m_vy2; //remember the start vertex - } else { - if (first) { /// a new partial polygon is starting - state = ST_START_LINE; - first = false; - } - else if (m_vx2 == x0 && m_vy2 == y0) { /// this is the last wire of the partial polygon - state = ST_END_LINE; - } - else { - state = ST_CONTINUE_LINE; - } - - device_draw(m_vx1, m_vy1, m_vx2, m_vy2, state, DEFAULT_Z_DOWN, fr_xy, fr_z); - } - m_vx1 = m_vx2; m_vy1 = m_vy2; //remember the last vertex - } - -////////// - 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", - internals_to_user(x1), internals_to_user(y1), internals_to_user(x2), internals_to_user(y2) - ); - } - // polygons - } - // if(S.name == OUTLINES_SIGNAL_NAME) - } - // signals - } - // board - user_file_closing(); - } - // output - user_file_closed(get_filename(), mode); - output_preview_data(mode, g_side); - -} -// write_outlines - -// -// Write stencil toolpath to the file. -// -// Params: -// which_side Side of the board to work on. -// suffix Suffix of the file. -// Return: -// none -// -void write_stencil(int which_side, string suffix) -{ - real fr_xy; - real fr_z; - fr_xy = FEED_RATE_STENCIL_XY; - fr_z = FEED_RATE_STENCIL_Z; - - g_side = which_side; - switch (which_side) { - case TOP: - m_layer = TOP_CREAM_LAYER; - break; - case BOTTOM: - m_layer = BOTTOM_CREAM_LAYER; - break; - default: - sprintf(g_debug, "Illegal which_side %d in write_stencil", which_side); - Fatal("Sorry...", g_debug); - } - - output(get_filename(), "wt") { - board(B) { - user_file_opened(get_filename(), "wt"); - - output_file_preamble(); - begin_gcode(SPINDLE_STENCIL_RPM); - - int tool_dia = user_to_internals(STENCIL_TOOL_SIZE); - g_tool_size = STENCIL_TOOL_SIZE; - if(g_debug_flag) { - sprintf(g_debug, "Stencil tool diameter=%f", internals_to_user(tool_dia)); - comm(g_debug); - } // if (g_debug_flag) - - B.elements(E) { - E.package.contacts(C) { - if (C.smd && - ((C.smd.layer == LAYER_BOTTOM && m_layer == BOTTOM_CREAM_LAYER) || - (C.smd.layer == LAYER_TOP && m_layer == TOP_CREAM_LAYER))) { - int cx = C.smd.x, cy = C.smd.y; - int dx = C.smd.dx[m_layer], dy = C.smd.dy[m_layer]; - real alpha = C.smd.angle * PI / 180; - - if(g_debug_flag) { - sprintf(g_debug, "Pad: cx=%f cy=%f dx=%f dy=%f alpha=%f", - internals_to_user(cx), internals_to_user(cy), internals_to_user(dx), internals_to_user(dy), alpha); - comm(g_debug); - } // if (g_debug_flag) - - // Tool size compensation - dx -= tool_dia / 2; dy -= tool_dia / 2; - - // Carve out the pad - if (dx > 0 && dy > 0) { - int hx = dx / 2, hy = dy / 2; - - // rotate (-hx, hy) - int x1 = -hx * cos(alpha) - hy * sin(alpha), - y1 = -hx * sin(alpha) + hy * cos(alpha); - // rotate (hx, hy) - int x2 = hx * cos(alpha) - hy * sin(alpha), - y2 = hx * sin(alpha) + hy * cos(alpha); - // rotate (hx, -hy) - int x3 = hx * cos(alpha) + hy * sin(alpha), - y3 = hx * sin(alpha) - hy * cos(alpha); - // rotate (-hx, -hy) - int x4 = -hx * cos(alpha) + hy * sin(alpha), - y4 = -hx * sin(alpha) - hy * cos(alpha); - - device_draw(cx + x1, cy + y1, cx + x2, cy + y2, ST_START_LINE, DEFAULT_Z_DOWN, fr_xy, fr_z); - device_draw(cx + x2, cy + y2, cx + x3, cy + y3, ST_CONTINUE_LINE, DEFAULT_Z_DOWN, fr_xy, fr_z); - device_draw(cx + x3, cy + y3, cx + x4, cy + y4, ST_CONTINUE_LINE, DEFAULT_Z_DOWN, fr_xy, fr_z); - device_draw(cx + x4, cy + y4, cx + x1, cy + y1, ST_CONTINUE_LINE, DEFAULT_Z_DOWN, fr_xy, fr_z); - // Deburr - device_draw(cx + x1, cy + y1, cx + x2, cy + y2, ST_END_LINE, DEFAULT_Z_DOWN, fr_xy, fr_z); - } // if (dx > 0 && dy > 0) - } // if (C.smd) - } // package.contacts - } // elements - - output_file_postamble(); - rz(DEFAULT_Z_UP); - end_gcode(); - } - // board - user_file_closing(); - } - // output - user_file_closed(get_filename(), "wt"); - - output_preview_data(FILEMODE_WRITE_TEXT, STENCIL); - preview(); - -} // write_stencil - -/* 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. -// -if (!board) { - Fatal("No board!", "Please run this program from the board editor"); -} - -// -// Process command line arguments. -// -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[TOOL_SIZE_ARG]) { - g_tool_size = strtod(argv[TOOL_SIZE_ARG]); -} -else { - g_tool_size = TOOL_SIZE; -} - -// 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, 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, 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, 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, FILL); - break; - - case PH_TOP_STENCIL: - if (GENERATE_TOP_STENCIL == YES) - write_stencil(TOP, "tc"); - break; - case PH_BOTTOM_STENCIL: - if (GENERATE_BOTTOM_STENCIL == YES) - write_stencil(BOTTOM, "bc"); - break; - - case PH_TOP_DRILL: - if (GENERATE_TOP_DRILL == YES) - output_drill_file(TOP); - break; - case PH_BOTTOM_DRILL: - if (GENERATE_BOTTOM_DRILL == YES) - output_drill_file(BOTTOM); - break; - - case PH_MILL: - if (GENERATE_MILLING == YES) - write_outlines(MILL, MILL_BOARD); - break; - - case PH_TEXT: - if (GENERATE_TEXT == YES) - write_outlines(TEXT, 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 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" - "run '%s' '%s' '%f' '%f' '%d' '%d';\n", - g_cmd, - argv[PROGRAM_NAME_ARG], m_file_name, g_tool_size, m_isolate, - m_pass_num, g_phase - ); - exit(g_cmd); -} -else { - g_cmd = "window fit;\n"; - exit(g_cmd); -} From d36d65e5c155bbd1789dd79a856f155e419087c5 Mon Sep 17 00:00:00 2001 From: deHarro Date: Mon, 26 Aug 2024 14:53:44 +0200 Subject: [PATCH 06/10] Update .gitignore edited to resolve conflicts with master --- .gitignore | 3 --- 1 file changed, 3 deletions(-) diff --git a/.gitignore b/.gitignore index b75e8f6..9cc28b6 100644 --- a/.gitignore +++ b/.gitignore @@ -10,11 +10,8 @@ docs/pcbgcode.lot docs/pcbgcode.out docs/pcbgcode.toc -*.b## -*.s## ~$*.xlsx viewer/applet/data/optimize_me.txt viewer/**/optimize_me.txt -*.b#1 *.b#* *.bak From 8eff251cf06287a76cc48f9fd0b06364e5435df9 Mon Sep 17 00:00:00 2001 From: deHarro Date: Mon, 26 Aug 2024 14:58:12 +0200 Subject: [PATCH 07/10] Update pcb-gcode.ulp edited to resolve conflicts with master --- pcb-gcode.ulp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pcb-gcode.ulp b/pcb-gcode.ulp index 4f8b1f6..d2f9dc2 100644 --- a/pcb-gcode.ulp +++ b/pcb-gcode.ulp @@ -721,7 +721,7 @@ void device_draw(int x1, int y1, int x2, int y2, int state, real z_down_or_radiu m_arc_center_y = ry1; break; - case ST_ARC: + case ST_ARC: sprintf(str, "ARC: rx1=%f, ry1=%f, rx2=%f, ry2=%f, cx=%f, cy=%f", rx1, ry1, rx2, ry2, m_arc_center_x, m_arc_center_y); comm(str); i_coord = m_arc_center_x - rx1; @@ -737,7 +737,7 @@ void device_draw(int x1, int y1, int x2, int y2, int state, real z_down_or_radiu else { fccwr(rx2, ry2, i_coord, j_coord, fr_xy); } - break; + break; ////////// } From a6ef95f9ab3a5b96bf9b3e119b8b211438a62b3d Mon Sep 17 00:00:00 2001 From: deHarro Date: Mon, 26 Aug 2024 15:00:33 +0200 Subject: [PATCH 08/10] Update pcb-gcode.h edited to resolve conflicts with master --- source/pcb-gcode.h | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/source/pcb-gcode.h b/source/pcb-gcode.h index 03321d8..61dc40d 100755 --- a/source/pcb-gcode.h +++ b/source/pcb-gcode.h @@ -46,14 +46,14 @@ enum { false = 0, true = 1 }; enum { TASK_INVALID, TASK_OUTLINES, TASK_FILL }; -enum { ST_INVALID, - ST_START_LINE, ST_CONTINUE_LINE, ST_END_LINE, - ST_DRILL, - ST_FILL, - ST_ARC_BEGIN, - ST_ARC_END, - ST_ARC, - ST_ARC_CENTER}; +enum { ST_INVALID, + ST_START_LINE, ST_CONTINUE_LINE, ST_END_LINE, + ST_DRILL, + ST_FILL, + ST_ARC_BEGIN, + ST_ARC_END, + ST_ARC, + ST_ARC_CENTER}; enum { TOP = 0, BOTTOM = 1, MILL = 2, TEXT = 3, STENCIL = 4, ALL = 5 }; From b4d2e8f380b3a6a98b3752521cff275470646322 Mon Sep 17 00:00:00 2001 From: deHarro Date: Mon, 26 Aug 2024 15:02:21 +0200 Subject: [PATCH 09/10] Update .gitignore edited to resolve conflicts with master --- .gitignore | 1 - 1 file changed, 1 deletion(-) diff --git a/.gitignore b/.gitignore index 9cc28b6..89a1cf0 100644 --- a/.gitignore +++ b/.gitignore @@ -14,4 +14,3 @@ docs/pcbgcode.toc viewer/applet/data/optimize_me.txt viewer/**/optimize_me.txt *.b#* -*.bak From 911bfe8174017421b0e9dec84a956a5ccc70d2fd Mon Sep 17 00:00:00 2001 From: deHarro Date: Sun, 8 Dec 2024 16:55:59 +0100 Subject: [PATCH 10/10] ignore VS15 project files --- .gitignore | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.gitignore b/.gitignore index 89a1cf0..49d586a 100644 --- a/.gitignore +++ b/.gitignore @@ -14,3 +14,8 @@ docs/pcbgcode.toc viewer/applet/data/optimize_me.txt viewer/**/optimize_me.txt *.b#* +.suo +*.sln +*.vcxproj +*.filters +*.user \ No newline at end of file