Browse Source

- added a GUI for Excellon Search time for OR-TOOLS path optimization in Edit -> Preferences -> Excellon General -> Optimization Time
- more changes in Edit -> Preferences -> Geometry, Gerber and in CNCJob
- added new option for Cutout Tool Freeform Gaps in Edit -> Preferences -> Tools
- fixed Freeform Cutout gaps issue (it was double than the value set)

Marius Stanciu 7 years ago
parent
commit
be2ecaa152
4 changed files with 303 additions and 185 deletions
  1. 96 85
      FlatCAMApp.py
  2. 190 92
      FlatCAMGUI.py
  3. 4 1
      README.md
  4. 13 7
      flatcamTools/ToolCutout.py

+ 96 - 85
FlatCAMApp.py

@@ -313,20 +313,20 @@ class App(QtCore.QObject):
             "global_workspace": self.general_defaults_form.general_gui_group.workspace_cb,
             "global_workspace": self.general_defaults_form.general_gui_group.workspace_cb,
             "global_workspaceT": self.general_defaults_form.general_gui_group.wk_cb,
             "global_workspaceT": self.general_defaults_form.general_gui_group.wk_cb,
 
 
-            "gerber_plot": self.gerber_defaults_form.gerber_group.plot_cb,
-            "gerber_solid": self.gerber_defaults_form.gerber_group.solid_cb,
-            "gerber_multicolored": self.gerber_defaults_form.gerber_group.multicolored_cb,
-            "gerber_isotooldia": self.gerber_defaults_form.gerber_group.iso_tool_dia_entry,
-            "gerber_isopasses": self.gerber_defaults_form.gerber_group.iso_width_entry,
-            "gerber_isooverlap": self.gerber_defaults_form.gerber_group.iso_overlap_entry,
-
-            "gerber_combine_passes": self.gerber_defaults_form.gerber_group.combine_passes_cb,
-            "gerber_milling_type": self.gerber_defaults_form.gerber_group.milling_type_radio,
-            "gerber_noncoppermargin": self.gerber_defaults_form.gerber_group.noncopper_margin_entry,
-            "gerber_noncopperrounded": self.gerber_defaults_form.gerber_group.noncopper_rounded_cb,
-            "gerber_bboxmargin": self.gerber_defaults_form.gerber_group.bbmargin_entry,
-            "gerber_bboxrounded": self.gerber_defaults_form.gerber_group.bbrounded_cb,
-            "gerber_circle_steps": self.gerber_defaults_form.gerber_group.circle_steps_entry,
+            "gerber_plot": self.gerber_defaults_form.gerber_gen_group.plot_cb,
+            "gerber_solid": self.gerber_defaults_form.gerber_gen_group.solid_cb,
+            "gerber_multicolored": self.gerber_defaults_form.gerber_gen_group.multicolored_cb,
+            "gerber_circle_steps": self.gerber_defaults_form.gerber_gen_group.circle_steps_entry,
+
+            "gerber_isotooldia": self.gerber_defaults_form.gerber_opt_group.iso_tool_dia_entry,
+            "gerber_isopasses": self.gerber_defaults_form.gerber_opt_group.iso_width_entry,
+            "gerber_isooverlap": self.gerber_defaults_form.gerber_opt_group.iso_overlap_entry,
+            "gerber_combine_passes": self.gerber_defaults_form.gerber_opt_group.combine_passes_cb,
+            "gerber_milling_type": self.gerber_defaults_form.gerber_opt_group.milling_type_radio,
+            "gerber_noncoppermargin": self.gerber_defaults_form.gerber_opt_group.noncopper_margin_entry,
+            "gerber_noncopperrounded": self.gerber_defaults_form.gerber_opt_group.noncopper_rounded_cb,
+            "gerber_bboxmargin": self.gerber_defaults_form.gerber_opt_group.bbmargin_entry,
+            "gerber_bboxrounded": self.gerber_defaults_form.gerber_opt_group.bbrounded_cb,
 
 
             "excellon_plot": self.excellon_defaults_form.excellon_gen_group.plot_cb,
             "excellon_plot": self.excellon_defaults_form.excellon_gen_group.plot_cb,
             "excellon_solid": self.excellon_defaults_form.excellon_gen_group.solid_cb,
             "excellon_solid": self.excellon_defaults_form.excellon_gen_group.solid_cb,
@@ -337,6 +337,7 @@ class App(QtCore.QObject):
             "excellon_zeros": self.excellon_defaults_form.excellon_gen_group.excellon_zeros_radio,
             "excellon_zeros": self.excellon_defaults_form.excellon_gen_group.excellon_zeros_radio,
             "excellon_units": self.excellon_defaults_form.excellon_gen_group.excellon_units_radio,
             "excellon_units": self.excellon_defaults_form.excellon_gen_group.excellon_units_radio,
             "excellon_optimization_type": self.excellon_defaults_form.excellon_gen_group.excellon_optimization_radio,
             "excellon_optimization_type": self.excellon_defaults_form.excellon_gen_group.excellon_optimization_radio,
+            "excellon_search_time": self.excellon_defaults_form.excellon_gen_group.optimization_time_entry,
 
 
             "excellon_drillz": self.excellon_defaults_form.excellon_opt_group.cutz_entry,
             "excellon_drillz": self.excellon_defaults_form.excellon_opt_group.cutz_entry,
             "excellon_travelz": self.excellon_defaults_form.excellon_opt_group.travelz_entry,
             "excellon_travelz": self.excellon_defaults_form.excellon_opt_group.travelz_entry,
@@ -355,36 +356,38 @@ class App(QtCore.QObject):
             "excellon_slot_tooldia": self.excellon_defaults_form.excellon_opt_group.slot_tooldia_entry,
             "excellon_slot_tooldia": self.excellon_defaults_form.excellon_opt_group.slot_tooldia_entry,
             "excellon_gcode_type": self.excellon_defaults_form.excellon_opt_group.excellon_gcode_type_radio,
             "excellon_gcode_type": self.excellon_defaults_form.excellon_opt_group.excellon_gcode_type_radio,
 
 
-            "geometry_plot": self.geometry_defaults_form.geometry_group.plot_cb,
-            "geometry_segx": self.geometry_defaults_form.geometry_group.segx_entry,
-            "geometry_segy": self.geometry_defaults_form.geometry_group.segy_entry,
-            "geometry_cutz": self.geometry_defaults_form.geometry_group.cutz_entry,
-            "geometry_travelz": self.geometry_defaults_form.geometry_group.travelz_entry,
-            "geometry_feedrate": self.geometry_defaults_form.geometry_group.cncfeedrate_entry,
-            "geometry_feedrate_z": self.geometry_defaults_form.geometry_group.cncplunge_entry,
-            "geometry_feedrate_rapid": self.geometry_defaults_form.geometry_group.cncfeedrate_rapid_entry,
-            "geometry_cnctooldia": self.geometry_defaults_form.geometry_group.cnctooldia_entry,
-            "geometry_spindlespeed": self.geometry_defaults_form.geometry_group.cncspindlespeed_entry,
-            "geometry_dwell": self.geometry_defaults_form.geometry_group.dwell_cb,
-            "geometry_dwelltime": self.geometry_defaults_form.geometry_group.dwelltime_entry,
-            "geometry_ppname_g": self.geometry_defaults_form.geometry_group.pp_geometry_name_cb,
-            "geometry_toolchange": self.geometry_defaults_form.geometry_group.toolchange_cb,
-            "geometry_toolchangez": self.geometry_defaults_form.geometry_group.toolchangez_entry,
-            "geometry_toolchangexy": self.geometry_defaults_form.geometry_group.toolchangexy_entry,
-            "geometry_startz": self.geometry_defaults_form.geometry_group.gstartz_entry,
-            "geometry_endz": self.geometry_defaults_form.geometry_group.gendz_entry,
-            "geometry_multidepth": self.geometry_defaults_form.geometry_group.multidepth_cb,
-            "geometry_depthperpass": self.geometry_defaults_form.geometry_group.depthperpass_entry,
-            "geometry_extracut": self.geometry_defaults_form.geometry_group.extracut_cb,
-            "geometry_circle_steps": self.geometry_defaults_form.geometry_group.circle_steps_entry,
-
-            "cncjob_plot": self.cncjob_defaults_form.cncjob_group.plot_cb,
-            "cncjob_tooldia": self.cncjob_defaults_form.cncjob_group.tooldia_entry,
-            "cncjob_coords_decimals": self.cncjob_defaults_form.cncjob_group.coords_dec_entry,
-            "cncjob_fr_decimals": self.cncjob_defaults_form.cncjob_group.fr_dec_entry,
-            "cncjob_prepend": self.cncjob_defaults_form.cncjob_group.prepend_text,
-            "cncjob_append": self.cncjob_defaults_form.cncjob_group.append_text,
-            "cncjob_steps_per_circle": self.cncjob_defaults_form.cncjob_group.steps_per_circle_entry,
+            "geometry_plot": self.geometry_defaults_form.geometry_gen_group.plot_cb,
+            "geometry_cnctooldia": self.geometry_defaults_form.geometry_gen_group.cnctooldia_entry,
+            "geometry_circle_steps": self.geometry_defaults_form.geometry_gen_group.circle_steps_entry,
+
+            "geometry_segx": self.geometry_defaults_form.geometry_opt_group.segx_entry,
+            "geometry_segy": self.geometry_defaults_form.geometry_opt_group.segy_entry,
+            "geometry_cutz": self.geometry_defaults_form.geometry_opt_group.cutz_entry,
+            "geometry_travelz": self.geometry_defaults_form.geometry_opt_group.travelz_entry,
+            "geometry_feedrate": self.geometry_defaults_form.geometry_opt_group.cncfeedrate_entry,
+            "geometry_feedrate_z": self.geometry_defaults_form.geometry_opt_group.cncplunge_entry,
+            "geometry_feedrate_rapid": self.geometry_defaults_form.geometry_opt_group.cncfeedrate_rapid_entry,
+            "geometry_spindlespeed": self.geometry_defaults_form.geometry_opt_group.cncspindlespeed_entry,
+            "geometry_dwell": self.geometry_defaults_form.geometry_opt_group.dwell_cb,
+            "geometry_dwelltime": self.geometry_defaults_form.geometry_opt_group.dwelltime_entry,
+            "geometry_ppname_g": self.geometry_defaults_form.geometry_opt_group.pp_geometry_name_cb,
+            "geometry_toolchange": self.geometry_defaults_form.geometry_opt_group.toolchange_cb,
+            "geometry_toolchangez": self.geometry_defaults_form.geometry_opt_group.toolchangez_entry,
+            "geometry_toolchangexy": self.geometry_defaults_form.geometry_opt_group.toolchangexy_entry,
+            "geometry_startz": self.geometry_defaults_form.geometry_opt_group.gstartz_entry,
+            "geometry_endz": self.geometry_defaults_form.geometry_opt_group.gendz_entry,
+            "geometry_multidepth": self.geometry_defaults_form.geometry_opt_group.multidepth_cb,
+            "geometry_depthperpass": self.geometry_defaults_form.geometry_opt_group.depthperpass_entry,
+            "geometry_extracut": self.geometry_defaults_form.geometry_opt_group.extracut_cb,
+
+            "cncjob_plot": self.cncjob_defaults_form.cncjob_gen_group.plot_cb,
+            "cncjob_tooldia": self.cncjob_defaults_form.cncjob_gen_group.tooldia_entry,
+            "cncjob_coords_decimals": self.cncjob_defaults_form.cncjob_gen_group.coords_dec_entry,
+            "cncjob_fr_decimals": self.cncjob_defaults_form.cncjob_gen_group.fr_dec_entry,
+            "cncjob_steps_per_circle": self.cncjob_defaults_form.cncjob_gen_group.steps_per_circle_entry,
+
+            "cncjob_prepend": self.cncjob_defaults_form.cncjob_opt_group.prepend_text,
+            "cncjob_append": self.cncjob_defaults_form.cncjob_opt_group.append_text,
 
 
             "tools_ncctools": self.tools_defaults_form.tools_ncc_group.ncc_tool_dia_entry,
             "tools_ncctools": self.tools_defaults_form.tools_ncc_group.ncc_tool_dia_entry,
             "tools_nccoverlap": self.tools_defaults_form.tools_ncc_group.ncc_overlap_entry,
             "tools_nccoverlap": self.tools_defaults_form.tools_ncc_group.ncc_overlap_entry,
@@ -398,6 +401,7 @@ class App(QtCore.QObject):
             "tools_cutoutmargin": self.tools_defaults_form.tools_cutout_group.cutout_margin_entry,
             "tools_cutoutmargin": self.tools_defaults_form.tools_cutout_group.cutout_margin_entry,
             "tools_cutoutgapsize": self.tools_defaults_form.tools_cutout_group.cutout_gap_entry,
             "tools_cutoutgapsize": self.tools_defaults_form.tools_cutout_group.cutout_gap_entry,
             "tools_gaps_rect": self.tools_defaults_form.tools_cutout_group.gaps_radio,
             "tools_gaps_rect": self.tools_defaults_form.tools_cutout_group.gaps_radio,
+            "tools_gaps_ff": self.tools_defaults_form.tools_cutout_group.gaps_combo,
 
 
             "tools_painttooldia": self.tools_defaults_form.tools_paint_group.painttooldia_entry,
             "tools_painttooldia": self.tools_defaults_form.tools_paint_group.painttooldia_entry,
             "tools_paintoverlap": self.tools_defaults_form.tools_paint_group.paintoverlap_entry,
             "tools_paintoverlap": self.tools_defaults_form.tools_paint_group.paintoverlap_entry,
@@ -411,7 +415,7 @@ class App(QtCore.QObject):
         self.postprocessors = load_postprocessors(self)
         self.postprocessors = load_postprocessors(self)
 
 
         for name in list(self.postprocessors.keys()):
         for name in list(self.postprocessors.keys()):
-            self.geometry_defaults_form.geometry_group.pp_geometry_name_cb.addItem(name)
+            self.geometry_defaults_form.geometry_opt_group.pp_geometry_name_cb.addItem(name)
             # HPGL postprocessor is only for Geometry objects therefore it should not be in the Excellon Preferences
             # HPGL postprocessor is only for Geometry objects therefore it should not be in the Excellon Preferences
             if name == 'hpgl':
             if name == 'hpgl':
                 continue
                 continue
@@ -558,6 +562,7 @@ class App(QtCore.QObject):
             "tools_cutoutmargin": 0.1,
             "tools_cutoutmargin": 0.1,
             "tools_cutoutgapsize": 0.15,
             "tools_cutoutgapsize": 0.15,
             "tools_gaps_rect": "4",
             "tools_gaps_rect": "4",
+            "tools_gaps_ff": "8",
 
 
             "tools_painttooldia": 0.07,
             "tools_painttooldia": 0.07,
             "tools_paintoverlap": 0.15,
             "tools_paintoverlap": 0.15,
@@ -605,17 +610,19 @@ class App(QtCore.QObject):
             "units": self.general_options_form.general_app_group.units_radio,
             "units": self.general_options_form.general_app_group.units_radio,
             "global_gridx": self.general_options_form.general_gui_group.gridx_entry,
             "global_gridx": self.general_options_form.general_gui_group.gridx_entry,
             "global_gridy": self.general_options_form.general_gui_group.gridy_entry,
             "global_gridy": self.general_options_form.general_gui_group.gridy_entry,
-            "gerber_plot": self.gerber_options_form.gerber_group.plot_cb,
-            "gerber_solid": self.gerber_options_form.gerber_group.solid_cb,
-            "gerber_multicolored": self.gerber_options_form.gerber_group.multicolored_cb,
-            "gerber_isotooldia": self.gerber_options_form.gerber_group.iso_tool_dia_entry,
-            "gerber_isopasses": self.gerber_options_form.gerber_group.iso_width_entry,
-            "gerber_isooverlap": self.gerber_options_form.gerber_group.iso_overlap_entry,
-            "gerber_combine_passes": self.gerber_options_form.gerber_group.combine_passes_cb,
-            "gerber_noncoppermargin": self.gerber_options_form.gerber_group.noncopper_margin_entry,
-            "gerber_noncopperrounded": self.gerber_options_form.gerber_group.noncopper_rounded_cb,
-            "gerber_bboxmargin": self.gerber_options_form.gerber_group.bbmargin_entry,
-            "gerber_bboxrounded": self.gerber_options_form.gerber_group.bbrounded_cb,
+
+            "gerber_plot": self.gerber_options_form.gerber_gen_group.plot_cb,
+            "gerber_solid": self.gerber_options_form.gerber_gen_group.solid_cb,
+            "gerber_multicolored": self.gerber_options_form.gerber_gen_group.multicolored_cb,
+
+            "gerber_isotooldia": self.gerber_options_form.gerber_opt_group.iso_tool_dia_entry,
+            "gerber_isopasses": self.gerber_options_form.gerber_opt_group.iso_width_entry,
+            "gerber_isooverlap": self.gerber_options_form.gerber_opt_group.iso_overlap_entry,
+            "gerber_combine_passes": self.gerber_options_form.gerber_opt_group.combine_passes_cb,
+            "gerber_noncoppermargin": self.gerber_options_form.gerber_opt_group.noncopper_margin_entry,
+            "gerber_noncopperrounded": self.gerber_options_form.gerber_opt_group.noncopper_rounded_cb,
+            "gerber_bboxmargin": self.gerber_options_form.gerber_opt_group.bbmargin_entry,
+            "gerber_bboxrounded": self.gerber_options_form.gerber_opt_group.bbrounded_cb,
 
 
             "excellon_plot": self.excellon_options_form.excellon_gen_group.plot_cb,
             "excellon_plot": self.excellon_options_form.excellon_gen_group.plot_cb,
             "excellon_solid": self.excellon_options_form.excellon_gen_group.solid_cb,
             "excellon_solid": self.excellon_options_form.excellon_gen_group.solid_cb,
@@ -642,32 +649,34 @@ class App(QtCore.QObject):
             "excellon_startz": self.excellon_options_form.excellon_opt_group.estartz_entry,
             "excellon_startz": self.excellon_options_form.excellon_opt_group.estartz_entry,
             "excellon_endz": self.excellon_options_form.excellon_opt_group.eendz_entry,
             "excellon_endz": self.excellon_options_form.excellon_opt_group.eendz_entry,
 
 
-            "geometry_plot": self.geometry_options_form.geometry_group.plot_cb,
-            "geometry_segx": self.geometry_options_form.geometry_group.segx_entry,
-            "geometry_segy": self.geometry_options_form.geometry_group.segy_entry,
-            "geometry_cutz": self.geometry_options_form.geometry_group.cutz_entry,
-            "geometry_travelz": self.geometry_options_form.geometry_group.travelz_entry,
-            "geometry_feedrate": self.geometry_options_form.geometry_group.cncfeedrate_entry,
-            "geometry_feedrate_z": self.geometry_options_form.geometry_group.cncplunge_entry,
-            "geometry_feedrate_rapid": self.geometry_options_form.geometry_group.cncfeedrate_rapid_entry,
-            "geometry_spindlespeed": self.geometry_options_form.geometry_group.cncspindlespeed_entry,
-            "geometry_dwell": self.geometry_options_form.geometry_group.dwell_cb,
-            "geometry_dwelltime": self.geometry_options_form.geometry_group.dwelltime_entry,
-            "geometry_cnctooldia": self.geometry_options_form.geometry_group.cnctooldia_entry,
-            "geometry_ppname_g": self.geometry_options_form.geometry_group.pp_geometry_name_cb,
-            "geometry_toolchange": self.geometry_options_form.geometry_group.toolchange_cb,
-            "geometry_toolchangez": self.geometry_options_form.geometry_group.toolchangez_entry,
-            "geometry_toolchangexy": self.geometry_options_form.geometry_group.toolchangexy_entry,
-            "geometry_startz": self.geometry_options_form.geometry_group.gstartz_entry,
-            "geometry_endz": self.geometry_options_form.geometry_group.gendz_entry,
-            "geometry_depthperpass": self.geometry_options_form.geometry_group.depthperpass_entry,
-            "geometry_multidepth": self.geometry_options_form.geometry_group.multidepth_cb,
-            "geometry_extracut": self.geometry_options_form.geometry_group.extracut_cb,
-
-            "cncjob_plot": self.cncjob_options_form.cncjob_group.plot_cb,
-            "cncjob_tooldia": self.cncjob_options_form.cncjob_group.tooldia_entry,
-            "cncjob_prepend": self.cncjob_options_form.cncjob_group.prepend_text,
-            "cncjob_append": self.cncjob_options_form.cncjob_group.append_text,
+            "geometry_plot": self.geometry_options_form.geometry_gen_group.plot_cb,
+            "geometry_cnctooldia": self.geometry_options_form.geometry_gen_group.cnctooldia_entry,
+
+            "geometry_segx": self.geometry_options_form.geometry_opt_group.segx_entry,
+            "geometry_segy": self.geometry_options_form.geometry_opt_group.segy_entry,
+            "geometry_cutz": self.geometry_options_form.geometry_opt_group.cutz_entry,
+            "geometry_travelz": self.geometry_options_form.geometry_opt_group.travelz_entry,
+            "geometry_feedrate": self.geometry_options_form.geometry_opt_group.cncfeedrate_entry,
+            "geometry_feedrate_z": self.geometry_options_form.geometry_opt_group.cncplunge_entry,
+            "geometry_feedrate_rapid": self.geometry_options_form.geometry_opt_group.cncfeedrate_rapid_entry,
+            "geometry_spindlespeed": self.geometry_options_form.geometry_opt_group.cncspindlespeed_entry,
+            "geometry_dwell": self.geometry_options_form.geometry_opt_group.dwell_cb,
+            "geometry_dwelltime": self.geometry_options_form.geometry_opt_group.dwelltime_entry,
+            "geometry_ppname_g": self.geometry_options_form.geometry_opt_group.pp_geometry_name_cb,
+            "geometry_toolchange": self.geometry_options_form.geometry_opt_group.toolchange_cb,
+            "geometry_toolchangez": self.geometry_options_form.geometry_opt_group.toolchangez_entry,
+            "geometry_toolchangexy": self.geometry_options_form.geometry_opt_group.toolchangexy_entry,
+            "geometry_startz": self.geometry_options_form.geometry_opt_group.gstartz_entry,
+            "geometry_endz": self.geometry_options_form.geometry_opt_group.gendz_entry,
+            "geometry_depthperpass": self.geometry_options_form.geometry_opt_group.depthperpass_entry,
+            "geometry_multidepth": self.geometry_options_form.geometry_opt_group.multidepth_cb,
+            "geometry_extracut": self.geometry_options_form.geometry_opt_group.extracut_cb,
+
+            "cncjob_plot": self.cncjob_options_form.cncjob_gen_group.plot_cb,
+            "cncjob_tooldia": self.cncjob_options_form.cncjob_gen_group.tooldia_entry,
+
+            "cncjob_prepend": self.cncjob_options_form.cncjob_opt_group.prepend_text,
+            "cncjob_append": self.cncjob_options_form.cncjob_opt_group.append_text,
 
 
             "tools_ncctools": self.tools_options_form.tools_ncc_group.ncc_tool_dia_entry,
             "tools_ncctools": self.tools_options_form.tools_ncc_group.ncc_tool_dia_entry,
             "tools_nccoverlap": self.tools_options_form.tools_ncc_group.ncc_overlap_entry,
             "tools_nccoverlap": self.tools_options_form.tools_ncc_group.ncc_overlap_entry,
@@ -676,7 +685,8 @@ class App(QtCore.QObject):
             "tools_cutouttooldia": self.tools_options_form.tools_cutout_group.cutout_tooldia_entry,
             "tools_cutouttooldia": self.tools_options_form.tools_cutout_group.cutout_tooldia_entry,
             "tools_cutoutmargin": self.tools_options_form.tools_cutout_group.cutout_margin_entry,
             "tools_cutoutmargin": self.tools_options_form.tools_cutout_group.cutout_margin_entry,
             "tools_cutoutgapsize": self.tools_options_form.tools_cutout_group.cutout_gap_entry,
             "tools_cutoutgapsize": self.tools_options_form.tools_cutout_group.cutout_gap_entry,
-            "tools_gaps": self.tools_options_form.tools_cutout_group.gaps_radio,
+            "tools_gaps_rect": self.tools_options_form.tools_cutout_group.gaps_radio,
+            "tools_gaps_rect": self.tools_options_form.tools_cutout_group.gaps_combo,
 
 
             "tools_painttooldia": self.tools_options_form.tools_paint_group.painttooldia_entry,
             "tools_painttooldia": self.tools_options_form.tools_paint_group.painttooldia_entry,
             "tools_paintoverlap": self.tools_options_form.tools_paint_group.paintoverlap_entry,
             "tools_paintoverlap": self.tools_options_form.tools_paint_group.paintoverlap_entry,
@@ -688,7 +698,7 @@ class App(QtCore.QObject):
         }
         }
 
 
         for name in list(self.postprocessors.keys()):
         for name in list(self.postprocessors.keys()):
-            self.geometry_options_form.geometry_group.pp_geometry_name_cb.addItem(name)
+            self.geometry_options_form.geometry_opt_group.pp_geometry_name_cb.addItem(name)
             self.excellon_options_form.excellon_opt_group.pp_excellon_name_cb.addItem(name)
             self.excellon_options_form.excellon_opt_group.pp_excellon_name_cb.addItem(name)
 
 
         self.options = LoudDict()
         self.options = LoudDict()
@@ -773,7 +783,8 @@ class App(QtCore.QObject):
             "tools_cutouttooldia": 0.07,
             "tools_cutouttooldia": 0.07,
             "tools_cutoutmargin": 0.1,
             "tools_cutoutmargin": 0.1,
             "tools_cutoutgapsize": 0.15,
             "tools_cutoutgapsize": 0.15,
-            "tools_gaps": "4",
+            "tools_gaps_rect": "4",
+            "tools_gaps_ff": "8",
 
 
             "tools_painttooldia": 0.07,
             "tools_painttooldia": 0.07,
             "tools_paintoverlap": 0.15,
             "tools_paintoverlap": 0.15,

+ 190 - 92
FlatCAMGUI.py

@@ -916,12 +916,17 @@ class GerberPreferencesUI(QtWidgets.QWidget):
 
 
     def __init__(self, parent=None):
     def __init__(self, parent=None):
         QtWidgets.QWidget.__init__(self, parent=parent)
         QtWidgets.QWidget.__init__(self, parent=parent)
-        self.layout = QtWidgets.QVBoxLayout()
+        self.layout = QtWidgets.QHBoxLayout()
         self.setLayout(self.layout)
         self.setLayout(self.layout)
 
 
-        self.gerber_group = GerberPrefGroupUI()
-        self.gerber_group.setFixedWidth(260)
-        self.layout.addWidget(self.gerber_group)
+        self.gerber_gen_group = GerberGenPrefGroupUI()
+        self.gerber_gen_group.setFixedWidth(260)
+        self.gerber_opt_group = GerberOptPrefGroupUI()
+        self.gerber_opt_group.setFixedWidth(260)
+
+        self.layout.addWidget(self.gerber_gen_group)
+        self.layout.addWidget(self.gerber_opt_group)
+        self.layout.addStretch()
 
 
 
 
 class ExcellonPreferencesUI(QtWidgets.QWidget):
 class ExcellonPreferencesUI(QtWidgets.QWidget):
@@ -945,12 +950,17 @@ class GeometryPreferencesUI(QtWidgets.QWidget):
 
 
     def __init__(self, parent=None):
     def __init__(self, parent=None):
         QtWidgets.QWidget.__init__(self, parent=parent)
         QtWidgets.QWidget.__init__(self, parent=parent)
-        self.layout = QtWidgets.QVBoxLayout()
+        self.layout = QtWidgets.QHBoxLayout()
         self.setLayout(self.layout)
         self.setLayout(self.layout)
 
 
-        self.geometry_group = GeometryPrefGroupUI()
-        self.geometry_group.setFixedWidth(260)
-        self.layout.addWidget(self.geometry_group)
+        self.geometry_gen_group = GeometryGenPrefGroupUI()
+        self.geometry_gen_group.setFixedWidth(260)
+        self.geometry_opt_group = GeometryOptPrefGroupUI()
+        self.geometry_opt_group.setFixedWidth(260)
+
+        self.layout.addWidget(self.geometry_gen_group)
+        self.layout.addWidget(self.geometry_opt_group)
+        self.layout.addStretch()
 
 
 
 
 class ToolsPreferencesUI(QtWidgets.QWidget):
 class ToolsPreferencesUI(QtWidgets.QWidget):
@@ -981,12 +991,17 @@ class CNCJobPreferencesUI(QtWidgets.QWidget):
 
 
     def __init__(self, parent=None):
     def __init__(self, parent=None):
         QtWidgets.QWidget.__init__(self, parent=parent)
         QtWidgets.QWidget.__init__(self, parent=parent)
-        self.layout = QtWidgets.QVBoxLayout()
+        self.layout = QtWidgets.QHBoxLayout()
         self.setLayout(self.layout)
         self.setLayout(self.layout)
 
 
-        self.cncjob_group = CNCJobPrefGroupUI()
-        self.cncjob_group.setFixedWidth(260)
-        self.layout.addWidget(self.cncjob_group)
+        self.cncjob_gen_group = CNCJobGenPrefGroupUI()
+        self.cncjob_gen_group.setFixedWidth(260)
+        self.cncjob_opt_group = CNCJobOptPrefGroupUI()
+        self.cncjob_opt_group.setFixedWidth(260)
+
+        self.layout.addWidget(self.cncjob_gen_group)
+        self.layout.addWidget(self.cncjob_opt_group)
+        self.layout.addStretch()
 
 
 
 
 class OptionsGroupUI(QtWidgets.QGroupBox):
 class OptionsGroupUI(QtWidgets.QGroupBox):
@@ -1266,13 +1281,15 @@ class GeneralAppPrefGroupUI(OptionsGroupUI):
 
 
         # Units for FlatCAM
         # Units for FlatCAM
         self.unitslabel = QtWidgets.QLabel('<b>Units:</b>')
         self.unitslabel = QtWidgets.QLabel('<b>Units:</b>')
-        self.unitslabel.setToolTip("Those are units in which FlatCAM works.")
+        self.unitslabel.setToolTip("The default value for FlatCAM units.\n"
+                                   "Whatever is selected here is set every time\n"
+                                   "FLatCAM is started.")
         self.units_radio = RadioSet([{'label': 'IN', 'value': 'IN'},
         self.units_radio = RadioSet([{'label': 'IN', 'value': 'IN'},
                                      {'label': 'MM', 'value': 'MM'}])
                                      {'label': 'MM', 'value': 'MM'}])
 
 
         # Languages for FlatCAM
         # Languages for FlatCAM
         self.languagelabel = QtWidgets.QLabel('<b>Languages:</b>')
         self.languagelabel = QtWidgets.QLabel('<b>Languages:</b>')
-        self.languagelabel.setToolTip("Set the language used for FlatCAM texts.")
+        self.languagelabel.setToolTip("Set the language used throughout FlatCAM.")
         self.language_cb = FCComboBox()
         self.language_cb = FCComboBox()
         self.languagespace = QtWidgets.QLabel('')
         self.languagespace = QtWidgets.QLabel('')
         self.language_apply_btn = FCButton("Apply Language")
         self.language_apply_btn = FCButton("Apply Language")
@@ -1317,9 +1334,11 @@ class GeneralAppPrefGroupUI(OptionsGroupUI):
 
 
         # Select mouse pan button
         # Select mouse pan button
         self.panbuttonlabel = QtWidgets.QLabel('<b>Pan Button:</b>')
         self.panbuttonlabel = QtWidgets.QLabel('<b>Pan Button:</b>')
-        self.panbuttonlabel.setToolTip("Select the mouse button to use for panning.")
-        self.pan_button_radio = RadioSet([{'label': 'Middle But.', 'value': '3'},
-                                     {'label': 'Right But.', 'value': '2'}])
+        self.panbuttonlabel.setToolTip("Select the mouse button to use for panning:\n"
+                                       "- MMB --> Middle Mouse Button\n"
+                                       "- RMB --> Middle Mouse Button")
+        self.pan_button_radio = RadioSet([{'label': 'MMB', 'value': '3'},
+                                     {'label': 'RMB', 'value': '2'}])
 
 
         # Multiple Selection Modifier Key
         # Multiple Selection Modifier Key
         self.mselectlabel = QtWidgets.QLabel('<b>Multiple Sel:</b>')
         self.mselectlabel = QtWidgets.QLabel('<b>Multiple Sel:</b>')
@@ -1363,12 +1382,12 @@ class GeneralAppPrefGroupUI(OptionsGroupUI):
         self.layout.addLayout(self.form_box)
         self.layout.addLayout(self.form_box)
 
 
 
 
-class GerberPrefGroupUI(OptionsGroupUI):
+class GerberGenPrefGroupUI(OptionsGroupUI):
     def __init__(self, parent=None):
     def __init__(self, parent=None):
-        # OptionsGroupUI.__init__(self, "Gerber Options", parent=parent)
-        super(GerberPrefGroupUI, self).__init__(self)
+        # OptionsGroupUI.__init__(self, "Gerber General Preferences", parent=parent)
+        super(GerberGenPrefGroupUI, self).__init__(self)
 
 
-        self.setTitle(str("Gerber Options"))
+        self.setTitle(str("Gerber General"))
 
 
         ## Plot options
         ## Plot options
         self.plot_options_label = QtWidgets.QLabel("<b>Plot Options:</b>")
         self.plot_options_label = QtWidgets.QLabel("<b>Plot Options:</b>")
@@ -1407,6 +1426,17 @@ class GerberPrefGroupUI(OptionsGroupUI):
         self.circle_steps_entry = IntEntry()
         self.circle_steps_entry = IntEntry()
         grid0.addWidget(self.circle_steps_entry, 1, 1)
         grid0.addWidget(self.circle_steps_entry, 1, 1)
 
 
+        self.layout.addStretch()
+
+
+class GerberOptPrefGroupUI(OptionsGroupUI):
+    def __init__(self, parent=None):
+        # OptionsGroupUI.__init__(self, "Gerber Options Preferences", parent=parent)
+        super(GerberOptPrefGroupUI, self).__init__(self)
+
+        self.setTitle(str("Gerber Options"))
+
+
         ## Isolation Routing
         ## Isolation Routing
         self.isolation_routing_label = QtWidgets.QLabel("<b>Isolation Routing:</b>")
         self.isolation_routing_label = QtWidgets.QLabel("<b>Isolation Routing:</b>")
         self.isolation_routing_label.setToolTip(
         self.isolation_routing_label.setToolTip(
@@ -1416,15 +1446,16 @@ class GerberPrefGroupUI(OptionsGroupUI):
         self.layout.addWidget(self.isolation_routing_label)
         self.layout.addWidget(self.isolation_routing_label)
 
 
         # Cutting Tool Diameter
         # Cutting Tool Diameter
-        grid1 = QtWidgets.QGridLayout()
-        self.layout.addLayout(grid1)
+        grid0 = QtWidgets.QGridLayout()
+        self.layout.addLayout(grid0)
+
         tdlabel = QtWidgets.QLabel('Tool dia:')
         tdlabel = QtWidgets.QLabel('Tool dia:')
         tdlabel.setToolTip(
         tdlabel.setToolTip(
             "Diameter of the cutting tool."
             "Diameter of the cutting tool."
         )
         )
-        grid1.addWidget(tdlabel, 0, 0)
+        grid0.addWidget(tdlabel, 0, 0)
         self.iso_tool_dia_entry = LengthEntry()
         self.iso_tool_dia_entry = LengthEntry()
-        grid1.addWidget(self.iso_tool_dia_entry, 0, 1)
+        grid0.addWidget(self.iso_tool_dia_entry, 0, 1)
 
 
         # Nr of passes
         # Nr of passes
         passlabel = QtWidgets.QLabel('Width (# passes):')
         passlabel = QtWidgets.QLabel('Width (# passes):')
@@ -1432,9 +1463,9 @@ class GerberPrefGroupUI(OptionsGroupUI):
             "Width of the isolation gap in\n"
             "Width of the isolation gap in\n"
             "number (integer) of tool widths."
             "number (integer) of tool widths."
         )
         )
-        grid1.addWidget(passlabel, 1, 0)
+        grid0.addWidget(passlabel, 1, 0)
         self.iso_width_entry = IntEntry()
         self.iso_width_entry = IntEntry()
-        grid1.addWidget(self.iso_width_entry, 1, 1)
+        grid0.addWidget(self.iso_width_entry, 1, 1)
 
 
         # Pass overlap
         # Pass overlap
         overlabel = QtWidgets.QLabel('Pass overlap:')
         overlabel = QtWidgets.QLabel('Pass overlap:')
@@ -1443,9 +1474,9 @@ class GerberPrefGroupUI(OptionsGroupUI):
             "Example:\n"
             "Example:\n"
             "A value here of 0.25 means an overlap of 25% from the tool diameter found above."
             "A value here of 0.25 means an overlap of 25% from the tool diameter found above."
         )
         )
-        grid1.addWidget(overlabel, 2, 0)
+        grid0.addWidget(overlabel, 2, 0)
         self.iso_overlap_entry = FloatEntry()
         self.iso_overlap_entry = FloatEntry()
-        grid1.addWidget(self.iso_overlap_entry, 2, 1)
+        grid0.addWidget(self.iso_overlap_entry, 2, 1)
 
 
         milling_type_label = QtWidgets.QLabel('Milling Type:')
         milling_type_label = QtWidgets.QLabel('Milling Type:')
         milling_type_label.setToolTip(
         milling_type_label.setToolTip(
@@ -1453,17 +1484,17 @@ class GerberPrefGroupUI(OptionsGroupUI):
             "- climb / best for precision milling and to reduce tool usage\n"
             "- climb / best for precision milling and to reduce tool usage\n"
             "- conventional / useful when there is no backlash compensation"
             "- conventional / useful when there is no backlash compensation"
         )
         )
-        grid1.addWidget(milling_type_label, 3, 0)
+        grid0.addWidget(milling_type_label, 3, 0)
         self.milling_type_radio = RadioSet([{'label': 'Climb', 'value': 'cl'},
         self.milling_type_radio = RadioSet([{'label': 'Climb', 'value': 'cl'},
                                             {'label': 'Conv.', 'value': 'cv'}])
                                             {'label': 'Conv.', 'value': 'cv'}])
-        grid1.addWidget(self.milling_type_radio, 3, 1)
+        grid0.addWidget(self.milling_type_radio, 3, 1)
 
 
         # Combine passes
         # Combine passes
         self.combine_passes_cb = FCCheckBox(label='Combine Passes')
         self.combine_passes_cb = FCCheckBox(label='Combine Passes')
         self.combine_passes_cb.setToolTip(
         self.combine_passes_cb.setToolTip(
             "Combine all passes into one object"
             "Combine all passes into one object"
         )
         )
-        grid1.addWidget(self.combine_passes_cb, 4, 0)
+        grid0.addWidget(self.combine_passes_cb, 4, 0)
 
 
         ## Clear non-copper regions
         ## Clear non-copper regions
         self.clearcopper_label = QtWidgets.QLabel("<b>Clear non-copper:</b>")
         self.clearcopper_label = QtWidgets.QLabel("<b>Clear non-copper:</b>")
@@ -1473,8 +1504,8 @@ class GerberPrefGroupUI(OptionsGroupUI):
         )
         )
         self.layout.addWidget(self.clearcopper_label)
         self.layout.addWidget(self.clearcopper_label)
 
 
-        grid3 = QtWidgets.QGridLayout()
-        self.layout.addLayout(grid3)
+        grid1 = QtWidgets.QGridLayout()
+        self.layout.addLayout(grid1)
 
 
         # Margin
         # Margin
         bmlabel = QtWidgets.QLabel('Boundary Margin:')
         bmlabel = QtWidgets.QLabel('Boundary Margin:')
@@ -1484,9 +1515,9 @@ class GerberPrefGroupUI(OptionsGroupUI):
             "objects with this minimum\n"
             "objects with this minimum\n"
             "distance."
             "distance."
         )
         )
-        grid3.addWidget(bmlabel, 0, 0)
+        grid1.addWidget(bmlabel, 0, 0)
         self.noncopper_margin_entry = LengthEntry()
         self.noncopper_margin_entry = LengthEntry()
-        grid3.addWidget(self.noncopper_margin_entry, 0, 1)
+        grid1.addWidget(self.noncopper_margin_entry, 0, 1)
 
 
         # Rounded corners
         # Rounded corners
         self.noncopper_rounded_cb = FCCheckBox(label="Rounded corners")
         self.noncopper_rounded_cb = FCCheckBox(label="Rounded corners")
@@ -1494,23 +1525,23 @@ class GerberPrefGroupUI(OptionsGroupUI):
             "Creates a Geometry objects with polygons\n"
             "Creates a Geometry objects with polygons\n"
             "covering the copper-free areas of the PCB."
             "covering the copper-free areas of the PCB."
         )
         )
-        grid3.addWidget(self.noncopper_rounded_cb, 1, 0, 1, 2)
+        grid1.addWidget(self.noncopper_rounded_cb, 1, 0, 1, 2)
 
 
         ## Bounding box
         ## Bounding box
         self.boundingbox_label = QtWidgets.QLabel('<b>Bounding Box:</b>')
         self.boundingbox_label = QtWidgets.QLabel('<b>Bounding Box:</b>')
         self.layout.addWidget(self.boundingbox_label)
         self.layout.addWidget(self.boundingbox_label)
 
 
-        grid4 = QtWidgets.QGridLayout()
-        self.layout.addLayout(grid4)
+        grid2 = QtWidgets.QGridLayout()
+        self.layout.addLayout(grid2)
 
 
         bbmargin = QtWidgets.QLabel('Boundary Margin:')
         bbmargin = QtWidgets.QLabel('Boundary Margin:')
         bbmargin.setToolTip(
         bbmargin.setToolTip(
             "Distance of the edges of the box\n"
             "Distance of the edges of the box\n"
             "to the nearest polygon."
             "to the nearest polygon."
         )
         )
-        grid4.addWidget(bbmargin, 0, 0)
+        grid2.addWidget(bbmargin, 0, 0)
         self.bbmargin_entry = LengthEntry()
         self.bbmargin_entry = LengthEntry()
-        grid4.addWidget(self.bbmargin_entry, 0, 1)
+        grid2.addWidget(self.bbmargin_entry, 0, 1)
 
 
         self.bbrounded_cb = FCCheckBox(label="Rounded corners")
         self.bbrounded_cb = FCCheckBox(label="Rounded corners")
         self.bbrounded_cb.setToolTip(
         self.bbrounded_cb.setToolTip(
@@ -1519,7 +1550,7 @@ class GerberPrefGroupUI(OptionsGroupUI):
             "their radius is equal to\n"
             "their radius is equal to\n"
             "the margin."
             "the margin."
         )
         )
-        grid4.addWidget(self.bbrounded_cb, 1, 0, 1, 2)
+        grid2.addWidget(self.bbrounded_cb, 1, 0, 1, 2)
         self.layout.addStretch()
         self.layout.addStretch()
 
 
 
 
@@ -1738,16 +1769,41 @@ class ExcellonGenPrefGroupUI(OptionsGroupUI):
 
 
         form_box_excellon.addRow(self.excellon_optimization_label, self.excellon_optimization_radio)
         form_box_excellon.addRow(self.excellon_optimization_label, self.excellon_optimization_radio)
 
 
+        self.optimization_time_label = QtWidgets.QLabel('Optimization Time:   ')
+        self.optimization_time_label.setAlignment(QtCore.Qt.AlignLeft)
+        self.optimization_time_label.setToolTip(
+            "When OR-Tools Metaheuristic (MH) is enabled there is a\n"
+            "maximum threshold for how much time is spent doing the\n"
+            "path optimization. This max duration is set here."
+
+        )
+
+        self.optimization_time_entry = LengthEntry()
+        form_box_excellon.addRow(self.optimization_time_label, self.optimization_time_entry)
+
         current_platform = platform.architecture()[0]
         current_platform = platform.architecture()[0]
         if current_platform == '64bit':
         if current_platform == '64bit':
             self.excellon_optimization_label.setDisabled(False)
             self.excellon_optimization_label.setDisabled(False)
             self.excellon_optimization_radio.setDisabled(False)
             self.excellon_optimization_radio.setDisabled(False)
+            self.optimization_time_label.setDisabled(False)
+            self.optimization_time_entry.setDisabled(False)
+            self.excellon_optimization_radio.activated_custom.connect(self.optimization_selection)
+
         else:
         else:
             self.excellon_optimization_label.setDisabled(True)
             self.excellon_optimization_label.setDisabled(True)
             self.excellon_optimization_radio.setDisabled(True)
             self.excellon_optimization_radio.setDisabled(True)
+            self.optimization_time_label.setDisabled(True)
+            self.optimization_time_entry.setDisabled(True)
 
 
         self.layout.addStretch()
         self.layout.addStretch()
 
 
+    def optimization_selection(self):
+        if self.excellon_optimization_radio.get_value() == 'M':
+            self.optimization_time_label.setDisabled(False)
+            self.optimization_time_entry.setDisabled(False)
+        else:
+            self.optimization_time_label.setDisabled(True)
+            self.optimization_time_entry.setDisabled(True)
 
 
 class ExcellonOptPrefGroupUI(OptionsGroupUI):
 class ExcellonOptPrefGroupUI(OptionsGroupUI):
 
 
@@ -1944,12 +2000,12 @@ class ExcellonOptPrefGroupUI(OptionsGroupUI):
         self.layout.addStretch()
         self.layout.addStretch()
 
 
 
 
-class GeometryPrefGroupUI(OptionsGroupUI):
+class GeometryGenPrefGroupUI(OptionsGroupUI):
     def __init__(self, parent=None):
     def __init__(self, parent=None):
-        # OptionsGroupUI.__init__(self, "Geometry Options", parent=parent)
-        super(GeometryPrefGroupUI, self).__init__(self)
+        # OptionsGroupUI.__init__(self, "Geometry General Preferences", parent=parent)
+        super(GeometryGenPrefGroupUI, self).__init__(self)
 
 
-        self.setTitle(str("Geometry Options"))
+        self.setTitle(str("Geometry General"))
 
 
         ## Plot options
         ## Plot options
         self.plot_options_label = QtWidgets.QLabel("<b>Plot Options:</b>")
         self.plot_options_label = QtWidgets.QLabel("<b>Plot Options:</b>")
@@ -1991,6 +2047,16 @@ class GeometryPrefGroupUI(OptionsGroupUI):
         self.cnctooldia_entry = LengthEntry()
         self.cnctooldia_entry = LengthEntry()
         grid1.addWidget(self.cnctooldia_entry, 0, 1)
         grid1.addWidget(self.cnctooldia_entry, 0, 1)
 
 
+        self.layout.addStretch()
+
+
+class GeometryOptPrefGroupUI(OptionsGroupUI):
+    def __init__(self, parent=None):
+        # OptionsGroupUI.__init__(self, "Geometry Options Preferences", parent=parent)
+        super(GeometryOptPrefGroupUI, self).__init__(self)
+
+        self.setTitle(str("Geometry Options"))
+
         # ------------------------------
         # ------------------------------
         ## Create CNC Job
         ## Create CNC Job
         # ------------------------------
         # ------------------------------
@@ -2002,8 +2068,8 @@ class GeometryPrefGroupUI(OptionsGroupUI):
         )
         )
         self.layout.addWidget(self.cncjob_label)
         self.layout.addWidget(self.cncjob_label)
 
 
-        grid2 = QtWidgets.QGridLayout()
-        self.layout.addLayout(grid2)
+        grid1 = QtWidgets.QGridLayout()
+        self.layout.addLayout(grid1)
 
 
         # Cut Z
         # Cut Z
         cutzlabel = QtWidgets.QLabel('Cut Z:')
         cutzlabel = QtWidgets.QLabel('Cut Z:')
@@ -2011,16 +2077,16 @@ class GeometryPrefGroupUI(OptionsGroupUI):
             "Cutting depth (negative)\n"
             "Cutting depth (negative)\n"
             "below the copper surface."
             "below the copper surface."
         )
         )
-        grid2.addWidget(cutzlabel, 0, 0)
+        grid1.addWidget(cutzlabel, 0, 0)
         self.cutz_entry = LengthEntry()
         self.cutz_entry = LengthEntry()
-        grid2.addWidget(self.cutz_entry, 0, 1)
+        grid1.addWidget(self.cutz_entry, 0, 1)
 
 
         # Multidepth CheckBox
         # Multidepth CheckBox
         self.multidepth_cb = FCCheckBox(label='Multidepth')
         self.multidepth_cb = FCCheckBox(label='Multidepth')
         self.multidepth_cb.setToolTip(
         self.multidepth_cb.setToolTip(
             "Multidepth usage: True or False."
             "Multidepth usage: True or False."
         )
         )
-        grid2.addWidget(self.multidepth_cb, 1, 0)
+        grid1.addWidget(self.multidepth_cb, 1, 0)
 
 
         # Depth/pass
         # Depth/pass
         dplabel = QtWidgets.QLabel('Depth/Pass:')
         dplabel = QtWidgets.QLabel('Depth/Pass:')
@@ -2032,9 +2098,9 @@ class GeometryPrefGroupUI(OptionsGroupUI):
             "which has negative value."
             "which has negative value."
         )
         )
 
 
-        grid2.addWidget(dplabel, 2, 0)
+        grid1.addWidget(dplabel, 2, 0)
         self.depthperpass_entry = LengthEntry()
         self.depthperpass_entry = LengthEntry()
-        grid2.addWidget(self.depthperpass_entry, 2, 1)
+        grid1.addWidget(self.depthperpass_entry, 2, 1)
 
 
         self.ois_multidepth = OptionalInputSection(self.multidepth_cb, [self.depthperpass_entry])
         self.ois_multidepth = OptionalInputSection(self.multidepth_cb, [self.depthperpass_entry])
 
 
@@ -2044,9 +2110,9 @@ class GeometryPrefGroupUI(OptionsGroupUI):
             "Height of the tool when\n"
             "Height of the tool when\n"
             "moving without cutting."
             "moving without cutting."
         )
         )
-        grid2.addWidget(travelzlabel, 3, 0)
+        grid1.addWidget(travelzlabel, 3, 0)
         self.travelz_entry = LengthEntry()
         self.travelz_entry = LengthEntry()
-        grid2.addWidget(self.travelz_entry, 3, 1)
+        grid1.addWidget(self.travelz_entry, 3, 1)
 
 
         # Tool change:
         # Tool change:
         toolchlabel = QtWidgets.QLabel("Tool change:")
         toolchlabel = QtWidgets.QLabel("Tool change:")
@@ -2055,26 +2121,26 @@ class GeometryPrefGroupUI(OptionsGroupUI):
             "in G-Code (Pause for tool change)."
             "in G-Code (Pause for tool change)."
         )
         )
         self.toolchange_cb = FCCheckBox()
         self.toolchange_cb = FCCheckBox()
-        grid2.addWidget(toolchlabel, 4, 0)
-        grid2.addWidget(self.toolchange_cb, 4, 1)
+        grid1.addWidget(toolchlabel, 4, 0)
+        grid1.addWidget(self.toolchange_cb, 4, 1)
 
 
         # Toolchange Z
         # Toolchange Z
         toolchangezlabel = QtWidgets.QLabel('Toolchange Z:')
         toolchangezlabel = QtWidgets.QLabel('Toolchange Z:')
         toolchangezlabel.setToolTip(
         toolchangezlabel.setToolTip(
             "Toolchange Z position."
             "Toolchange Z position."
         )
         )
-        grid2.addWidget(toolchangezlabel, 5, 0)
+        grid1.addWidget(toolchangezlabel, 5, 0)
         self.toolchangez_entry = LengthEntry()
         self.toolchangez_entry = LengthEntry()
-        grid2.addWidget(self.toolchangez_entry, 5, 1)
+        grid1.addWidget(self.toolchangez_entry, 5, 1)
 
 
         # Toolchange X,Y
         # Toolchange X,Y
         toolchange_xy_label = QtWidgets.QLabel('Toolchange X,Y:')
         toolchange_xy_label = QtWidgets.QLabel('Toolchange X,Y:')
         toolchange_xy_label.setToolTip(
         toolchange_xy_label.setToolTip(
             "Toolchange X,Y position."
             "Toolchange X,Y position."
         )
         )
-        grid2.addWidget(toolchange_xy_label, 6, 0)
+        grid1.addWidget(toolchange_xy_label, 6, 0)
         self.toolchangexy_entry = FCEntry()
         self.toolchangexy_entry = FCEntry()
-        grid2.addWidget(self.toolchangexy_entry, 6, 1)
+        grid1.addWidget(self.toolchangexy_entry, 6, 1)
 
 
         # Start move Z
         # Start move Z
         startzlabel = QtWidgets.QLabel('Start move Z:')
         startzlabel = QtWidgets.QLabel('Start move Z:')
@@ -2082,9 +2148,9 @@ class GeometryPrefGroupUI(OptionsGroupUI):
             "Height of the tool just after starting the work.\n"
             "Height of the tool just after starting the work.\n"
             "Delete the value if you don't need this feature."
             "Delete the value if you don't need this feature."
         )
         )
-        grid2.addWidget(startzlabel, 7, 0)
+        grid1.addWidget(startzlabel, 7, 0)
         self.gstartz_entry = FloatEntry()
         self.gstartz_entry = FloatEntry()
-        grid2.addWidget(self.gstartz_entry, 7, 1)
+        grid1.addWidget(self.gstartz_entry, 7, 1)
 
 
         # End move Z
         # End move Z
         endzlabel = QtWidgets.QLabel('End move Z:')
         endzlabel = QtWidgets.QLabel('End move Z:')
@@ -2092,9 +2158,9 @@ class GeometryPrefGroupUI(OptionsGroupUI):
             "Height of the tool after\n"
             "Height of the tool after\n"
             "the last move at the end of the job."
             "the last move at the end of the job."
         )
         )
-        grid2.addWidget(endzlabel, 8, 0)
+        grid1.addWidget(endzlabel, 8, 0)
         self.gendz_entry = LengthEntry()
         self.gendz_entry = LengthEntry()
-        grid2.addWidget(self.gendz_entry, 8, 1)
+        grid1.addWidget(self.gendz_entry, 8, 1)
 
 
         # Feedrate X-Y
         # Feedrate X-Y
         frlabel = QtWidgets.QLabel('Feed Rate X-Y:')
         frlabel = QtWidgets.QLabel('Feed Rate X-Y:')
@@ -2102,9 +2168,9 @@ class GeometryPrefGroupUI(OptionsGroupUI):
             "Cutting speed in the XY\n"
             "Cutting speed in the XY\n"
             "plane in units per minute"
             "plane in units per minute"
         )
         )
-        grid2.addWidget(frlabel, 9, 0)
+        grid1.addWidget(frlabel, 9, 0)
         self.cncfeedrate_entry = LengthEntry()
         self.cncfeedrate_entry = LengthEntry()
-        grid2.addWidget(self.cncfeedrate_entry, 9, 1)
+        grid1.addWidget(self.cncfeedrate_entry, 9, 1)
 
 
         # Feedrate Z (Plunge)
         # Feedrate Z (Plunge)
         frz_label = QtWidgets.QLabel('Feed Rate Z:')
         frz_label = QtWidgets.QLabel('Feed Rate Z:')
@@ -2113,9 +2179,9 @@ class GeometryPrefGroupUI(OptionsGroupUI):
             "plane in units per minute.\n"
             "plane in units per minute.\n"
             "It is called also Plunge."
             "It is called also Plunge."
         )
         )
-        grid2.addWidget(frz_label, 10, 0)
+        grid1.addWidget(frz_label, 10, 0)
         self.cncplunge_entry = LengthEntry()
         self.cncplunge_entry = LengthEntry()
-        grid2.addWidget(self.cncplunge_entry, 10, 1)
+        grid1.addWidget(self.cncplunge_entry, 10, 1)
 
 
         # Feedrate rapids
         # Feedrate rapids
         fr_rapid_label = QtWidgets.QLabel('Feed Rate Rapids:')
         fr_rapid_label = QtWidgets.QLabel('Feed Rate Rapids:')
@@ -2123,9 +2189,9 @@ class GeometryPrefGroupUI(OptionsGroupUI):
             "Cutting speed in the XY\n"
             "Cutting speed in the XY\n"
             "plane in units per minute"
             "plane in units per minute"
         )
         )
-        grid2.addWidget(fr_rapid_label, 11, 0)
+        grid1.addWidget(fr_rapid_label, 11, 0)
         self.cncfeedrate_rapid_entry = LengthEntry()
         self.cncfeedrate_rapid_entry = LengthEntry()
-        grid2.addWidget(self.cncfeedrate_rapid_entry, 11, 1)
+        grid1.addWidget(self.cncfeedrate_rapid_entry, 11, 1)
 
 
         # End move extra cut
         # End move extra cut
         self.extracut_cb = FCCheckBox(label='Cut over 1st pt.')
         self.extracut_cb = FCCheckBox(label='Cut over 1st pt.')
@@ -2135,7 +2201,7 @@ class GeometryPrefGroupUI(OptionsGroupUI):
             "meet with last cut, we generate an\n"
             "meet with last cut, we generate an\n"
             "extended cut over the first cut section."
             "extended cut over the first cut section."
         )
         )
-        grid2.addWidget(self.extracut_cb, 12, 0)
+        grid1.addWidget(self.extracut_cb, 12, 0)
 
 
         # Spindle Speed
         # Spindle Speed
         spdlabel = QtWidgets.QLabel('Spindle speed:')
         spdlabel = QtWidgets.QLabel('Spindle speed:')
@@ -2143,9 +2209,9 @@ class GeometryPrefGroupUI(OptionsGroupUI):
             "Speed of the spindle\n"
             "Speed of the spindle\n"
             "in RPM (optional)"
             "in RPM (optional)"
         )
         )
-        grid2.addWidget(spdlabel, 13, 0)
+        grid1.addWidget(spdlabel, 13, 0)
         self.cncspindlespeed_entry = IntEntry(allow_empty=True)
         self.cncspindlespeed_entry = IntEntry(allow_empty=True)
-        grid2.addWidget(self.cncspindlespeed_entry, 13, 1)
+        grid1.addWidget(self.cncspindlespeed_entry, 13, 1)
 
 
         # Dwell
         # Dwell
         self.dwell_cb = FCCheckBox(label='Dwell:')
         self.dwell_cb = FCCheckBox(label='Dwell:')
@@ -2158,9 +2224,9 @@ class GeometryPrefGroupUI(OptionsGroupUI):
             "Number of milliseconds for spindle to dwell."
             "Number of milliseconds for spindle to dwell."
         )
         )
         self.dwelltime_entry = FCEntry()
         self.dwelltime_entry = FCEntry()
-        grid2.addWidget(self.dwell_cb, 14, 0)
-        grid2.addWidget(dwelltime, 15, 0)
-        grid2.addWidget(self.dwelltime_entry, 15, 1)
+        grid1.addWidget(self.dwell_cb, 14, 0)
+        grid1.addWidget(dwelltime, 15, 0)
+        grid1.addWidget(self.dwelltime_entry, 15, 1)
 
 
         self.ois_dwell = OptionalInputSection(self.dwell_cb, [self.dwelltime_entry])
         self.ois_dwell = OptionalInputSection(self.dwell_cb, [self.dwelltime_entry])
 
 
@@ -2170,10 +2236,10 @@ class GeometryPrefGroupUI(OptionsGroupUI):
             "The postprocessor file that dictates\n"
             "The postprocessor file that dictates\n"
             "Machine Code output."
             "Machine Code output."
         )
         )
-        grid2.addWidget(pp_label, 16, 0)
+        grid1.addWidget(pp_label, 16, 0)
         self.pp_geometry_name_cb = FCComboBox()
         self.pp_geometry_name_cb = FCComboBox()
         self.pp_geometry_name_cb.setFocusPolicy(Qt.StrongFocus)
         self.pp_geometry_name_cb.setFocusPolicy(Qt.StrongFocus)
-        grid2.addWidget(self.pp_geometry_name_cb, 16, 1)
+        grid1.addWidget(self.pp_geometry_name_cb, 16, 1)
 
 
         # Size of trace segment on X axis
         # Size of trace segment on X axis
         segx_label = QtWidgets.QLabel("Seg. X size:")
         segx_label = QtWidgets.QLabel("Seg. X size:")
@@ -2182,9 +2248,9 @@ class GeometryPrefGroupUI(OptionsGroupUI):
             "Useful for auto-leveling.\n"
             "Useful for auto-leveling.\n"
             "A value of 0 means no segmentation on the X axis."
             "A value of 0 means no segmentation on the X axis."
         )
         )
-        grid2.addWidget(segx_label, 17, 0)
+        grid1.addWidget(segx_label, 17, 0)
         self.segx_entry = FCEntry()
         self.segx_entry = FCEntry()
-        grid2.addWidget(self.segx_entry, 17, 1)
+        grid1.addWidget(self.segx_entry, 17, 1)
 
 
         # Size of trace segment on Y axis
         # Size of trace segment on Y axis
         segy_label = QtWidgets.QLabel("Seg. Y size:")
         segy_label = QtWidgets.QLabel("Seg. Y size:")
@@ -2193,19 +2259,19 @@ class GeometryPrefGroupUI(OptionsGroupUI):
             "Useful for auto-leveling.\n"
             "Useful for auto-leveling.\n"
             "A value of 0 means no segmentation on the Y axis."
             "A value of 0 means no segmentation on the Y axis."
         )
         )
-        grid2.addWidget(segy_label, 18, 0)
+        grid1.addWidget(segy_label, 18, 0)
         self.segy_entry = FCEntry()
         self.segy_entry = FCEntry()
-        grid2.addWidget(self.segy_entry, 18, 1)
+        grid1.addWidget(self.segy_entry, 18, 1)
 
 
         self.layout.addStretch()
         self.layout.addStretch()
 
 
 
 
-class CNCJobPrefGroupUI(OptionsGroupUI):
+class CNCJobGenPrefGroupUI(OptionsGroupUI):
     def __init__(self, parent=None):
     def __init__(self, parent=None):
-        # OptionsGroupUI.__init__(self, "CNC Job Options", parent=None)
-        super(CNCJobPrefGroupUI, self).__init__(self)
+        # OptionsGroupUI.__init__(self, "CNC Job General Preferences", parent=None)
+        super(CNCJobGenPrefGroupUI, self).__init__(self)
 
 
-        self.setTitle(str("CNC Job Options"))
+        self.setTitle(str("CNC Job General"))
 
 
         ## Plot options
         ## Plot options
         self.plot_options_label = QtWidgets.QLabel("<b>Plot Options:</b>")
         self.plot_options_label = QtWidgets.QLabel("<b>Plot Options:</b>")
@@ -2262,6 +2328,16 @@ class CNCJobPrefGroupUI(OptionsGroupUI):
         self.fr_dec_entry = IntEntry()
         self.fr_dec_entry = IntEntry()
         grid0.addWidget(self.fr_dec_entry, 4, 1)
         grid0.addWidget(self.fr_dec_entry, 4, 1)
 
 
+        self.layout.addStretch()
+
+
+class CNCJobOptPrefGroupUI(OptionsGroupUI):
+    def __init__(self, parent=None):
+        # OptionsGroupUI.__init__(self, "CNC Job Options Preferences", parent=None)
+        super(CNCJobOptPrefGroupUI, self).__init__(self)
+
+        self.setTitle(str("CNC Job Options"))
+
         ## Export G-Code
         ## Export G-Code
         self.export_gcode_label = QtWidgets.QLabel("<b>Export G-Code:</b>")
         self.export_gcode_label = QtWidgets.QLabel("<b>Export G-Code:</b>")
         self.export_gcode_label.setToolTip(
         self.export_gcode_label.setToolTip(
@@ -2293,8 +2369,7 @@ class CNCJobPrefGroupUI(OptionsGroupUI):
         self.append_text = FCTextArea()
         self.append_text = FCTextArea()
         self.layout.addWidget(self.append_text)
         self.layout.addWidget(self.append_text)
 
 
-        grid0 = QtWidgets.QGridLayout()
-        self.layout.addLayout(grid0)
+        self.layout.addStretch()
 
 
 
 
 class ToolsNCCPrefGroupUI(OptionsGroupUI):
 class ToolsNCCPrefGroupUI(OptionsGroupUI):
@@ -2444,10 +2519,12 @@ class ToolsCutoutPrefGroupUI(OptionsGroupUI):
         self.cutout_gap_entry = LengthEntry()
         self.cutout_gap_entry = LengthEntry()
         grid0.addWidget(self.cutout_gap_entry, 2, 1)
         grid0.addWidget(self.cutout_gap_entry, 2, 1)
 
 
-        gapslabel = QtWidgets.QLabel('Gaps:')
+        gapslabel = QtWidgets.QLabel('Gaps Rect:')
         gapslabel.setToolTip(
         gapslabel.setToolTip(
-            "Where to place the gaps, Top/Bottom\n"
-            "Left/Rigt, or on all 4 sides."
+            "Where to place the gaps when doing a Rectangular Cutout:\n"
+            " - 2 (T/B) --> Top/Bottom\n"
+            " - 2 (L/R) --> Left/Rigt\n"
+            " - 4       --> on each of all 4 sides."
         )
         )
         grid0.addWidget(gapslabel, 3, 0)
         grid0.addWidget(gapslabel, 3, 0)
         self.gaps_radio = RadioSet([{'label': '2 (T/B)', 'value': 'tb'},
         self.gaps_radio = RadioSet([{'label': '2 (T/B)', 'value': 'tb'},
@@ -2455,6 +2532,27 @@ class ToolsCutoutPrefGroupUI(OptionsGroupUI):
                                     {'label': '4', 'value': '4'}])
                                     {'label': '4', 'value': '4'}])
         grid0.addWidget(self.gaps_radio, 3, 1)
         grid0.addWidget(self.gaps_radio, 3, 1)
 
 
+        gaps_ff_label = QtWidgets.QLabel('Gaps FF:')
+        gaps_ff_label.setToolTip(
+            "Number of gaps used for the FreeForm cutout.\n"
+            "There can be maximum 8 bridges/gaps.\n"
+            "The choices are:\n"
+            "- lr    - left + right\n"
+            "- tb    - top + bottom\n"
+            "- 4     - left + right +top + bottom\n"
+            "- 2lr   - 2*left + 2*right\n"
+            "- 2tb  - 2*top + 2*bottom\n"
+            "- 8     - 2*left + 2*right +2*top + 2*bottom"
+        )
+        grid0.addWidget(gaps_ff_label, 4, 0)
+        self.gaps_combo = FCComboBox()
+        grid0.addWidget(self.gaps_combo, 4, 1)
+
+        gaps_items = ['LR', 'TB', '4', '2LR', '2TB', '8']
+        for it in gaps_items:
+            self.gaps_combo.addItem(it)
+            self.gaps_combo.setStyleSheet('background-color: rgb(255,255,255)')
+
         self.layout.addStretch()
         self.layout.addStretch()
 
 
 
 

+ 4 - 1
README.md

@@ -17,7 +17,10 @@ CAD program, and create G-Code for Isolation routing.
 - disabled the context menu in tools table on Paint Tool in case that the painting method is single.
 - disabled the context menu in tools table on Paint Tool in case that the painting method is single.
 - added protection when trying to do Intersection in Geometry Editor without having selected Geometry items.
 - added protection when trying to do Intersection in Geometry Editor without having selected Geometry items.
 - fixed the scale, mirror, rotate, skew functions to work with Geometry Objects of multi-geometry type.
 - fixed the scale, mirror, rotate, skew functions to work with Geometry Objects of multi-geometry type.
-
+- added a GUI for Excellon Search time for OR-TOOLS path optimization in Edit -> Preferences -> Excellon General -> Optimization Time
+- more changes in Edit -> Preferences -> Geometry, Gerber and in CNCJob
+- added new option for Cutout Tool Freeform Gaps in Edit -> Preferences -> Tools
+- fixed Freeform Cutout gaps issue (it was double than the value set)
 
 
 28.01.2018
 28.01.2018
 
 

+ 13 - 7
flatcamTools/ToolCutout.py

@@ -101,10 +101,9 @@ class ToolCutout(FlatCAMTool):
         # 8     - 2*left + 2*right +2*top + 2*bottom
         # 8     - 2*left + 2*right +2*top + 2*bottom
 
 
         # Gaps
         # Gaps
-        self.gaps = FCEntry()
-        self.gaps_label = QtWidgets.QLabel("Type of gaps:   ")
-        self.gaps_label.setToolTip(
-            "Number of gaps used for the cutout.\n"
+        gaps_ff_label = QtWidgets.QLabel('Gaps FF:      ')
+        gaps_ff_label.setToolTip(
+            "Number of gaps used for the FreeForm cutout.\n"
             "There can be maximum 8 bridges/gaps.\n"
             "There can be maximum 8 bridges/gaps.\n"
             "The choices are:\n"
             "The choices are:\n"
             "- lr    - left + right\n"
             "- lr    - left + right\n"
@@ -114,7 +113,13 @@ class ToolCutout(FlatCAMTool):
             "- 2tb  - 2*top + 2*bottom\n"
             "- 2tb  - 2*top + 2*bottom\n"
             "- 8     - 2*left + 2*right +2*top + 2*bottom"
             "- 8     - 2*left + 2*right +2*top + 2*bottom"
         )
         )
-        form_layout_2.addRow(self.gaps_label, self.gaps)
+
+        self.gaps = FCComboBox()
+        gaps_items = ['LR', 'TB', '4', '2LR', '2TB', '8']
+        for it in gaps_items:
+            self.gaps.addItem(it)
+            self.gaps.setStyleSheet('background-color: rgb(255,255,255)')
+        form_layout_2.addRow(gaps_ff_label, self.gaps)
 
 
         ## Buttons
         ## Buttons
         hlay = QtWidgets.QHBoxLayout()
         hlay = QtWidgets.QHBoxLayout()
@@ -215,7 +220,8 @@ class ToolCutout(FlatCAMTool):
             return "Could not retrieve object: %s" % name
             return "Could not retrieve object: %s" % name
 
 
         if cutout_obj is None:
         if cutout_obj is None:
-            self.app.inform.emit("[error_notcl]Object not found: %s" % cutout_obj)
+            self.app.inform.emit("[error_notcl]There is no object selected for Cutout.\nSelect one and try again.")
+            return
 
 
         try:
         try:
             dia = float(self.dia.get_value())
             dia = float(self.dia.get_value())
@@ -254,7 +260,7 @@ class ToolCutout(FlatCAMTool):
         lenghtx = (xmax - xmin) + (margin * 2)
         lenghtx = (xmax - xmin) + (margin * 2)
         lenghty = (ymax - ymin) + (margin * 2)
         lenghty = (ymax - ymin) + (margin * 2)
 
 
-        gapsize = gapsize + (dia / 2)
+        gapsize = gapsize / 2 + (dia / 2)
 
 
         if isinstance(cutout_obj,FlatCAMGeometry):
         if isinstance(cutout_obj,FlatCAMGeometry):
             # rename the obj name so it can be identified as cutout
             # rename the obj name so it can be identified as cutout