فهرست منبع

jpcgt/flatcam/Beta слито с Beta

Camellan 6 سال پیش
والد
کامیت
4a98e694c1

+ 111 - 61
FlatCAMApp.py

@@ -1198,8 +1198,8 @@ class App(QtCore.QObject):
             # Keyword list
             # Keyword list
             "util_autocomplete_keywords": 'Desktop, Documents, FlatConfig, FlatPrj, Marius, My Documents, Paste_1, '
             "util_autocomplete_keywords": 'Desktop, Documents, FlatConfig, FlatPrj, Marius, My Documents, Paste_1, '
                                           'Repetier, Roland_MDX_20, Toolchange_Custom, Toolchange_Probe_MACH3, '
                                           'Repetier, Roland_MDX_20, Toolchange_Custom, Toolchange_Probe_MACH3, '
-                                          'Toolchange_manual, Users, all, angle_x, angle_y, axis, axisoffset, box, '
-                                          'center_x, center_y, columns, combine, connect, contour, default, '
+                                          'Toolchange_manual, Users, all, angle_x, angle_y, axis, auto, axisoffset, '
+                                          'box, center_x, center_y, columns, combine, connect, contour, default, '
                                           'depthperpass, dia, diatol, dist, drilled_dias, drillz, dwell, dwelltime, '
                                           'depthperpass, dia, diatol, dist, drilled_dias, drillz, dwell, dwelltime, '
                                           'feedrate_z, grbl_11, grbl_laser, gridoffsety, gridx, gridy, has_offset, '
                                           'feedrate_z, grbl_11, grbl_laser, gridoffsety, gridx, gridy, has_offset, '
                                           'holes, hpgl, iso_type, line_xyz, margin, marlin, method, milled_dias, '
                                           'holes, hpgl, iso_type, line_xyz, margin, marlin, method, milled_dias, '
@@ -1586,6 +1586,19 @@ class App(QtCore.QObject):
 
 
         # ### End of Data ####
         # ### End of Data ####
 
 
+        # ##############################################
+        # ######### SETUP OBJECT COLLECTION ############
+        # ##############################################
+
+        self.collection = ObjectCollection(self)
+        self.ui.project_tab_layout.addWidget(self.collection.view)
+
+        # ### Adjust tabs width ## ##
+        # self.collection.view.setMinimumWidth(self.ui.options_scroll_area.widget().sizeHint().width() +
+        #     self.ui.options_scroll_area.verticalScrollBar().sizeHint().width())
+        self.collection.view.setMinimumWidth(290)
+        self.log.debug("Finished creating Object Collection.")
+
         # ###############################################
         # ###############################################
         # ############# SETUP Plot Area #################
         # ############# SETUP Plot Area #################
         # ###############################################
         # ###############################################
@@ -1607,9 +1620,7 @@ class App(QtCore.QObject):
         start_plot_time = time.time()   # debug
         start_plot_time = time.time()   # debug
         self.plotcanvas = None
         self.plotcanvas = None
 
 
-        # this is a list just because when in legacy it is needed to add multiple cursors
-        # each gets deleted when the axes are deleted therefore there is a need of one for each
-        self.app_cursor = []
+        self.app_cursor = None
         self.hover_shapes = None
         self.hover_shapes = None
 
 
         self.on_plotcanvas_setup()
         self.on_plotcanvas_setup()
@@ -1639,19 +1650,6 @@ class App(QtCore.QObject):
                 self.trayIcon = FlatCAMSystemTray(app=self, icon=QtGui.QIcon('share/flatcam_icon32_green.png'),
                 self.trayIcon = FlatCAMSystemTray(app=self, icon=QtGui.QIcon('share/flatcam_icon32_green.png'),
                                                   parent=self.parent_w)
                                                   parent=self.parent_w)
 
 
-        # ##############################################
-        # ######### SETUP OBJECT COLLECTION ############
-        # ##############################################
-
-        self.collection = ObjectCollection(self)
-        self.ui.project_tab_layout.addWidget(self.collection.view)
-
-        # ### Adjust tabs width ## ##
-        # self.collection.view.setMinimumWidth(self.ui.options_scroll_area.widget().sizeHint().width() +
-        #     self.ui.options_scroll_area.verticalScrollBar().sizeHint().width())
-        self.collection.view.setMinimumWidth(290)
-        self.log.debug("Finished creating Object Collection.")
-
         # ###############################################
         # ###############################################
         # ############# Worker SETUP ####################
         # ############# Worker SETUP ####################
         # ###############################################
         # ###############################################
@@ -2109,17 +2107,17 @@ class App(QtCore.QObject):
                                   'join_geometry', 'list_sys', 'listsys', 'milld', 'mills', 'milldrills', 'millslots',
                                   'join_geometry', 'list_sys', 'listsys', 'milld', 'mills', 'milldrills', 'millslots',
                                   'mirror', 'ncc',
                                   'mirror', 'ncc',
                                   'ncc_clear', 'ncr', 'new', 'new_geometry', 'non_copper_regions', 'offset',
                                   'ncc_clear', 'ncr', 'new', 'new_geometry', 'non_copper_regions', 'offset',
-                                  'open_excellon', 'open_gcode', 'open_gerber', 'open_project', 'options', 'paint',
-                                  'pan', 'panel', 'panelize', 'plot_all', 'plot_objects', 'quit_flatcam',
+                                  'open_excellon', 'open_gcode', 'open_gerber', 'open_project', 'options', 'origin',
+                                  'paint', 'pan', 'panel', 'panelize', 'plot_all', 'plot_objects', 'quit_flatcam',
                                   'save', 'save_project',
                                   'save', 'save_project',
-                                  'save_sys', 'scale',
-                                  'set_active', 'set_sys', 'setsys', 'skew', 'subtract_poly', 'subtract_rectangle',
+                                  'save_sys', 'scale', 'set_active', 'set_origin', 'set_sys',
+                                  'setsys', 'skew', 'subtract_poly', 'subtract_rectangle',
                                   'version', 'write_gcode'
                                   'version', 'write_gcode'
                                   ]
                                   ]
 
 
         self.default_keywords = ['Desktop', 'Documents', 'FlatConfig', 'FlatPrj', 'Marius', 'My Documents', 'Paste_1',
         self.default_keywords = ['Desktop', 'Documents', 'FlatConfig', 'FlatPrj', 'Marius', 'My Documents', 'Paste_1',
                                  'Repetier', 'Roland_MDX_20', 'Toolchange_Custom', 'Toolchange_Probe_MACH3',
                                  'Repetier', 'Roland_MDX_20', 'Toolchange_Custom', 'Toolchange_Probe_MACH3',
-                                 'Toolchange_manual', 'Users', 'all', 'angle_x', 'angle_y', 'axis', 'axisoffset',
+                                 'Toolchange_manual', 'Users', 'all', 'angle_x', 'angle_y', 'auto', 'axis', 'axisoffset',
                                  'box', 'center_x', 'center_y', 'columns', 'combine', 'connect', 'contour', 'default',
                                  'box', 'center_x', 'center_y', 'columns', 'combine', 'connect', 'contour', 'default',
                                  'depthperpass', 'dia', 'diatol', 'dist', 'drilled_dias', 'drillz', 'dwell',
                                  'depthperpass', 'dia', 'diatol', 'dist', 'drilled_dias', 'drillz', 'dwell',
                                  'dwelltime', 'feedrate_z', 'grbl_11', 'grbl_laser', 'gridoffsety', 'gridx', 'gridy',
                                  'dwelltime', 'feedrate_z', 'grbl_11', 'grbl_laser', 'gridoffsety', 'gridx', 'gridy',
@@ -2486,10 +2484,17 @@ class App(QtCore.QObject):
         self.isHovering = False
         self.isHovering = False
         self.notHovering = True
         self.notHovering = True
 
 
+        # Window geometry
+        self.x_pos = None
+        self.y_pos = None
+        self.width = None
+        self.height = None
+
         # Event signals disconnect id holders
         # Event signals disconnect id holders
         self.mp = None
         self.mp = None
         self.mm = None
         self.mm = None
         self.mr = None
         self.mr = None
+        self.mp_zc = None
 
 
         # when True, the app has to return from any thread
         # when True, the app has to return from any thread
         self.abort_flag = False
         self.abort_flag = False
@@ -3774,6 +3779,16 @@ class App(QtCore.QObject):
         self.defaults["global_def_notebook_width"] = notebook_width
         self.defaults["global_def_notebook_width"] = notebook_width
         self.save_defaults()
         self.save_defaults()
 
 
+    def restore_main_win_geom(self):
+        try:
+            self.ui.setGeometry(self.defaults["global_def_win_x"],
+                                self.defaults["global_def_win_y"],
+                                self.defaults["global_def_win_w"],
+                                self.defaults["global_def_win_h"])
+            self.ui.splitter.setSizes([self.defaults["global_def_notebook_width"], 0])
+        except KeyError as e:
+            log.debug("App.restore_main_win_geom() --> %s" % str(e))
+
     def message_dialog(self, title, message, kind="info"):
     def message_dialog(self, title, message, kind="info"):
         """
         """
         Builds and show a custom QMessageBox to be used in FlatCAM.
         Builds and show a custom QMessageBox to be used in FlatCAM.
@@ -5546,15 +5561,33 @@ class App(QtCore.QObject):
         self.report_usage("on_fullscreen()")
         self.report_usage("on_fullscreen()")
 
 
         if self.toggle_fscreen is False:
         if self.toggle_fscreen is False:
-            if sys.platform == 'win32':
-                self.ui.showFullScreen()
+            # self.ui.showFullScreen()
+            self.ui.setWindowFlags(self.ui.windowFlags() | Qt.FramelessWindowHint)
+            a = self.ui.geometry()
+            self.x_pos = a.x()
+            self.y_pos = a.y()
+            self.width = a.width()
+            self.height = a.height()
+
+            # set new geometry to full desktop rect
+            # Subtracting and adding the pixels below it's hack to bypass a bug in Qt5 and OpenGL that made that a
+            # window drawn with OpenGL in fullscreen will not show any other windows on top which means that menus and
+            # everything else will not work without this hack. This happen in Windows.
+            # https://bugreports.qt.io/browse/QTBUG-41309
+            rec = QtWidgets.QApplication.desktop().screenGeometry()
+            h = rec.height() + 2
+            w = rec.width() + 2
+            self.ui.setGeometry(-1, -1, w, h)
+            self.ui.show()
+
             for tb in self.ui.findChildren(QtWidgets.QToolBar):
             for tb in self.ui.findChildren(QtWidgets.QToolBar):
                 tb.setVisible(False)
                 tb.setVisible(False)
             self.ui.splitter_left.setVisible(False)
             self.ui.splitter_left.setVisible(False)
             self.toggle_fscreen = True
             self.toggle_fscreen = True
         else:
         else:
-            if sys.platform == 'win32':
-                self.ui.showNormal()
+            self.ui.setWindowFlags(self.ui.windowFlags() & ~Qt.FramelessWindowHint)
+            self.ui.setGeometry(self.x_pos, self.y_pos, self.width, self.height)
+            self.ui.showNormal()
             self.restore_toolbar_view()
             self.restore_toolbar_view()
             self.ui.splitter_left.setVisible(True)
             self.ui.splitter_left.setVisible(True)
             self.toggle_fscreen = False
             self.toggle_fscreen = False
@@ -6783,16 +6816,56 @@ class App(QtCore.QObject):
             pass
             pass
         self.replot_signal[list].connect(origin_replot)
         self.replot_signal[list].connect(origin_replot)
 
 
-    def on_set_zero_click(self, event):
-        # this function will be available only for mouse left click
+    def on_set_zero_click(self, event, location=None, noplot=False, use_thread=True):
+        """
 
 
-        if self.is_legacy is False:
-            event_pos = event.pos
-        else:
-            event_pos = (event.xdata, event.ydata)
+        :param event:
+        :param location:
+        :param noplot:
+        :param use_thread:
+        :return:
+        """
+        noplot_sig = noplot
+
+        def worker_task():
+            with self.proc_container.new(_("Setting Origin...")):
+                for obj in self.collection.get_list():
+                    obj.offset((x, y))
+                    self.object_changed.emit(obj)
+
+                    # Update the object bounding box options
+                    a, b, c, d = obj.bounds()
+                    obj.options['xmin'] = a
+                    obj.options['ymin'] = b
+                    obj.options['xmax'] = c
+                    obj.options['ymax'] = d
+                self.inform.emit('[success] %s...' %
+                                 _('Origin set'))
+                if noplot_sig is False:
+                    self.replot_signal.emit([])
+
+        if location is not None:
+            if len(location) != 2:
+                self.inform.emit('[ERROR_NOTCL] %s...' %
+                                 _("Origin coordinates specified but incomplete."))
+                return 'fail'
+
+            x, y = location
+
+            if use_thread is True:
+                self.worker_task.emit({'fcn': worker_task, 'params': []})
+            else:
+                worker_task()
+            self.should_we_save = True
+            return
 
 
-        pos_canvas = self.plotcanvas.translate_coords(event_pos)
         if event.button == 1:
         if event.button == 1:
+            if self.is_legacy is False:
+                event_pos = event.pos
+            else:
+                event_pos = (event.xdata, event.ydata)
+            pos_canvas = self.plotcanvas.translate_coords(event_pos)
+
             if self.grid_status() == True:
             if self.grid_status() == True:
                 pos = self.geo_editor.snap(pos_canvas[0], pos_canvas[1])
                 pos = self.geo_editor.snap(pos_canvas[0], pos_canvas[1])
             else:
             else:
@@ -6801,23 +6874,10 @@ class App(QtCore.QObject):
             x = 0 - pos[0]
             x = 0 - pos[0]
             y = 0 - pos[1]
             y = 0 - pos[1]
 
 
-            def worker_task():
-                with self.proc_container.new(_("Setting Origin...")):
-                    for obj in self.collection.get_list():
-                        obj.offset((x, y))
-                        self.object_changed.emit(obj)
-
-                        # Update the object bounding box options
-                        a, b, c, d = obj.bounds()
-                        obj.options['xmin'] = a
-                        obj.options['ymin'] = b
-                        obj.options['xmax'] = c
-                        obj.options['ymax'] = d
-                    self.inform.emit('[success]%s...' %
-                                     _('Origin set'))
-                    self.replot_signal.emit([])
-
-            self.worker_task.emit({'fcn': worker_task, 'params': []})
+            if use_thread is True:
+                self.worker_task.emit({'fcn': worker_task, 'params': []})
+            else:
+                worker_task()
             self.should_we_save = True
             self.should_we_save = True
 
 
     def on_jump_to(self, custom_location=None, fit_center=True):
     def on_jump_to(self, custom_location=None, fit_center=True):
@@ -10482,16 +10542,6 @@ class App(QtCore.QObject):
                         if silent is False:
                         if silent is False:
                             self.log.debug("  " + param + " OK!")
                             self.log.debug("  " + param + " OK!")
 
 
-    def restore_main_win_geom(self):
-        try:
-            self.ui.setGeometry(self.defaults["global_def_win_x"],
-                                self.defaults["global_def_win_y"],
-                                self.defaults["global_def_win_w"],
-                                self.defaults["global_def_win_h"])
-            self.ui.splitter.setSizes([self.defaults["global_def_notebook_width"], 0])
-        except KeyError as e:
-            log.debug("App.restore_main_win_geom() --> %s" % str(e))
-
     def plot_all(self, zoom=True):
     def plot_all(self, zoom=True):
         """
         """
         Re-generates all plots from all objects.
         Re-generates all plots from all objects.

+ 1 - 1
FlatCAMObj.py

@@ -85,7 +85,7 @@ class FlatCAMObj(QtCore.QObject):
         if self.app.is_legacy is False:
         if self.app.is_legacy is False:
             self.shapes = self.app.plotcanvas.new_shape_group()
             self.shapes = self.app.plotcanvas.new_shape_group()
         else:
         else:
-            self.shapes = ShapeCollectionLegacy(obj=self, app=self.app, name='application')
+            self.shapes = ShapeCollectionLegacy(obj=self, app=self.app, name=name)
 
 
         # self.mark_shapes = self.app.plotcanvas.new_shape_collection(layers=2)
         # self.mark_shapes = self.app.plotcanvas.new_shape_collection(layers=2)
         self.mark_shapes = {}
         self.mark_shapes = {}

+ 13 - 0
README.md

@@ -9,6 +9,18 @@ CAD program, and create G-Code for Isolation routing.
 
 
 =================================================
 =================================================
 
 
+23.09.2019
+
+- in legacy graphic engine, fixed bug that made the old object disappear when a new object was loaded
+- in legacy graphic engine, fixed bug that crashed the app when creating a new project
+- in legacy graphic engine, fixed a bug that when deleting an object all objects where deleted
+- added a new TclCommand named "set_origin" which will set the origin for all loaded objects to zero if the -auto True argument is used and to a certain x,y location if the format is: set_origin 5,7
+- added a new TclCommand named "bounds" which will return a list of bounds values from a supplied list of objects names. For use in Tcl Scripts
+- updated strings in the translations and the .POT file
+- added the new keywords to the default keywords list
+- fixed the FullScreen option not working for the 3D graphic engine (due bug of Qt5 when OpenGL window is fullscreen) by creating a sort of fullscreen
+- added a final fix that allow full coverage of the screen in FullScreen in Windows and still the menus are working
+
 22.09.2019
 22.09.2019
 
 
 - fixed zoom directions legacy graphic engine (previous commit)
 - fixed zoom directions legacy graphic engine (previous commit)
@@ -29,6 +41,7 @@ CAD program, and create G-Code for Isolation routing.
 - updated and corrected the Romanian and Spanish translations
 - updated and corrected the Romanian and Spanish translations
 - updated the .PO files for the rest of the translations, they need to be filled in.
 - updated the .PO files for the rest of the translations, they need to be filled in.
 - fixed crash when trying to set a workspace in FlatCAM in the Legacy engine 2D mode by disabling this function for the case of 2D mode
 - fixed crash when trying to set a workspace in FlatCAM in the Legacy engine 2D mode by disabling this function for the case of 2D mode
+- fixed exception when trying to Fit View (shortcut key 'V') with no object loaded, in legacy graphic engine
 
 
 21.09.2019
 21.09.2019
 
 

+ 1 - 1
camlib.py

@@ -5041,7 +5041,7 @@ class Excellon(Geometry):
     def bounds(self):
     def bounds(self):
         """
         """
         Returns coordinates of rectangular bounds
         Returns coordinates of rectangular bounds
-        of Gerber geometry: (xmin, ymin, xmax, ymax).
+        of Excellon geometry: (xmin, ymin, xmax, ymax).
         """
         """
         # fixed issue of getting bounds only for one level lists of objects
         # fixed issue of getting bounds only for one level lists of objects
         # now it can get bounds for nested lists of objects
         # now it can get bounds for nested lists of objects

+ 18 - 1
flatcamGUI/PlotCanvasLegacy.py

@@ -306,10 +306,21 @@ class PlotCanvasLegacy(QtCore.QObject):
         self.figure.add_axes(self.axes)
         self.figure.add_axes(self.axes)
         self.axes.set_aspect(1)
         self.axes.set_aspect(1)
         self.axes.grid(True)
         self.axes.grid(True)
+        self.axes.axhline(color=(0.70, 0.3, 0.3), linewidth=2)
+        self.axes.axvline(color=(0.70, 0.3, 0.3), linewidth=2)
+
+        self.adjust_axes(-10, -10, 100, 100)
 
 
         # Re-draw
         # Re-draw
         self.canvas.draw_idle()
         self.canvas.draw_idle()
 
 
+    def redraw(self):
+        """
+        Created only to serve for compatibility with the VisPy plotcanvas (the other graphic engine, 3D)
+        :return:
+        """
+        self.clear()
+
     def adjust_axes(self, xmin, ymin, xmax, ymax):
     def adjust_axes(self, xmin, ymin, xmax, ymax):
         """
         """
         Adjusts all axes while maintaining the use of the whole canvas
         Adjusts all axes while maintaining the use of the whole canvas
@@ -329,6 +340,12 @@ class PlotCanvasLegacy(QtCore.QObject):
 
 
         # FlatCAMApp.App.log.debug("PC.adjust_axes()")
         # FlatCAMApp.App.log.debug("PC.adjust_axes()")
 
 
+        if not self.app.collection.get_list():
+            xmin = -10
+            ymin = -10
+            xmax = 100
+            ymax = 100
+
         width = xmax - xmin
         width = xmax - xmin
         height = ymax - ymin
         height = ymax - ymin
         try:
         try:
@@ -588,7 +605,7 @@ class PlotCanvasLegacy(QtCore.QObject):
         :param position: Mouse event position
         :param position: Mouse event position
         :return: Tuple with mouse position
         :return: Tuple with mouse position
         """
         """
-        return (position[0], position[1])
+        return position[0], position[1]
 
 
     def on_draw(self, renderer):
     def on_draw(self, renderer):
 
 

BIN
locale/de/LC_MESSAGES/strings.mo


تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 213 - 209
locale/de/LC_MESSAGES/strings.po


BIN
locale/en/LC_MESSAGES/strings.mo


تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 213 - 209
locale/en/LC_MESSAGES/strings.po


BIN
locale/es/LC_MESSAGES/strings.mo


تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 213 - 209
locale/es/LC_MESSAGES/strings.po


BIN
locale/pt_BR/LC_MESSAGES/strings.mo


تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 215 - 211
locale/pt_BR/LC_MESSAGES/strings.po


BIN
locale/ro/LC_MESSAGES/strings.mo


تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 213 - 209
locale/ro/LC_MESSAGES/strings.po


BIN
locale/ru/LC_MESSAGES/strings.mo


تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 212 - 208
locale/ru/LC_MESSAGES/strings.po


تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 212 - 208
locale_template/strings.pot


+ 81 - 0
tclCommands/TclCommandBounds.py

@@ -0,0 +1,81 @@
+from tclCommands.TclCommand import TclCommand
+from ObjectCollection import *
+
+from camlib import get_bounds
+
+import gettext
+import FlatCAMTranslation as fcTranslate
+import builtins
+
+fcTranslate.apply_language('strings')
+if '_' not in builtins.__dict__:
+    _ = gettext.gettext
+
+
+class TclCommandBounds(TclCommand):
+    """
+    Tcl shell command to return the bounds values for a supplied list of objects (identified by their names).
+    example:
+
+    """
+
+    # List of all command aliases, to be able use old names for backward compatibility (add_poly, add_polygon)
+    aliases = ['get_bounds', 'bounds']
+
+    # Dictionary of types from Tcl command, needs to be ordered
+    arg_names = collections.OrderedDict([
+        ('objects', str)
+    ])
+
+    # Dictionary of types from Tcl command, needs to be ordered , this  is  for options  like -optionname value
+    option_types = collections.OrderedDict([
+    ])
+
+    # array of mandatory options for current Tcl command: required = {'name','outname'}
+    required = []
+
+    # structured help for current command, args needs to be ordered
+    help = {
+        'main': "Will return a list of bounds values, each set of bound values is "
+                "a list itself: [xmin, ymin, xmax, ymax].",
+        'args': collections.OrderedDict([
+            ('objects', 'A list of object names separated by comma without spaces.'),
+        ]),
+        'examples': ['bounds a_obj.GTL,b_obj.DRL']
+    }
+
+    def execute(self, args, unnamed_args):
+        """
+
+        :param args:
+        :param unnamed_args:
+        :return:
+        """
+
+        obj_list = list()
+        if 'objects' in args:
+            try:
+                obj_list = [str(obj_name) for obj_name in str(args['objects']).split(",") if obj_name != '']
+            except AttributeError as e:
+                log.debug("TclCommandBounds.execute --> %s" % str(e))
+
+            if not obj_list:
+                self.raise_tcl_error('%s: %s:' % (
+                    _("Expected a list of objects names separated by comma. Got"), str(args['objects'])))
+                return 'fail'
+        else:
+            self.raise_tcl_error('%s: %s:' % (
+                _("Expected a list of objects names separated by comma. Got"), str(args['objects'])))
+            return 'fail'
+
+        result_list = list()
+        for name in obj_list:
+            obj = self.app.collection.get_by_name(name)
+
+            xmin, ymin, xmax, ymax = obj.bounds()
+            result_list.append([xmin, ymin, xmax, ymax])
+
+        self.app.inform.emit('[success] %s ...' %
+                             _('TclCommand Bounds done.'))
+
+        return result_list

+ 1 - 0
tclCommands/TclCommandCopperClear.py

@@ -136,6 +136,7 @@ class TclCommandCopperClear(TclCommand):
             tools = [float(eval(dia)) for dia in tooldia.split(",") if dia != '']
             tools = [float(eval(dia)) for dia in tooldia.split(",") if dia != '']
         except AttributeError:
         except AttributeError:
             tools = [float(tooldia)]
             tools = [float(tooldia)]
+
         # store here the default data for Geometry Data
         # store here the default data for Geometry Data
         default_data = {}
         default_data = {}
         default_data.update({
         default_data.update({

+ 88 - 0
tclCommands/TclCommandSetOrigin.py

@@ -0,0 +1,88 @@
+from tclCommands.TclCommand import TclCommand
+from ObjectCollection import *
+
+from camlib import get_bounds
+
+import gettext
+import FlatCAMTranslation as fcTranslate
+import builtins
+
+fcTranslate.apply_language('strings')
+if '_' not in builtins.__dict__:
+    _ = gettext.gettext
+
+
+class TclCommandSetOrigin(TclCommand):
+    """
+    Tcl shell command to set the origin to zero or to a specified location for all loaded objects in FlatCAM.
+
+    example:
+
+    """
+
+    # List of all command aliases, to be able use old names for backward compatibility (add_poly, add_polygon)
+    aliases = ['set_origin', 'origin']
+
+    # Dictionary of types from Tcl command, needs to be ordered
+    arg_names = collections.OrderedDict([
+        ('loc', str)
+    ])
+
+    # Dictionary of types from Tcl command, needs to be ordered , this  is  for options  like -optionname value
+    option_types = collections.OrderedDict([
+        ('auto', bool)
+    ])
+
+    # array of mandatory options for current Tcl command: required = {'name','outname'}
+    required = []
+
+    # structured help for current command, args needs to be ordered
+    help = {
+        'main': "Will set the origin at the specified x,y location.",
+        'args': collections.OrderedDict([
+            ('loc', 'Location to offset all the selected objects. No spaces between x and y pair. Use like this: 2,3'),
+            ('auto', 'If set to 1 it will set the origin to the minimum x, y of the object selection bounding box.'
+                     '-auto=1 is not correct but -auto 1 or -auto True is correct.')
+        ]),
+        'examples': ['set_origin 3,2', 'set_origin -auto 1']
+    }
+
+    def execute(self, args, unnamed_args):
+        """
+
+        :param args:
+        :param unnamed_args:
+        :return:
+        """
+
+        loc = list()
+        if 'auto' in args:
+            if args['auto'] == 1:
+                objs = self.app.collection.get_list()
+                minx, miny, __, ___ = get_bounds(objs)
+
+                loc.append(0 - minx)
+                loc.append(0 - miny)
+            else:
+                loc = [0, 0]
+        elif 'loc' in args:
+            try:
+                location = [float(eval(coord)) for coord in str(args['loc']).split(",") if coord != '']
+            except AttributeError as e:
+                log.debug("TclCommandSetOrigin.execute --> %s" % str(e))
+                location = (0, 0)
+
+            loc.append(location[0])
+            loc.append(location[1])
+
+            if len(location) != 2:
+                self.raise_tcl_error('%s: %s' % (
+                    _("Expected a pair of (x, y) coordinates. Got"), str(len(location))))
+                return 'fail'
+        else:
+            loc = [0, 0]
+
+        self.app.on_set_zero_click(event=None, location=loc, noplot=True, use_thread=False)
+        self.app.inform.emit('[success] Tcl %s: %s' %
+                             (_('Origin set by offsetting all loaded objects with '),
+                              '{0:.4f}, {0:.4f}'.format(loc[0], loc[1])))

+ 2 - 0
tclCommands/__init__.py

@@ -10,6 +10,7 @@ import tclCommands.TclCommandAddRectangle
 import tclCommands.TclCommandAlignDrill
 import tclCommands.TclCommandAlignDrill
 import tclCommands.TclCommandAlignDrillGrid
 import tclCommands.TclCommandAlignDrillGrid
 import tclCommands.TclCommandBbox
 import tclCommands.TclCommandBbox
+import tclCommands.TclCommandBounds
 import tclCommands.TclCommandClearShell
 import tclCommands.TclCommandClearShell
 import tclCommands.TclCommandCncjob
 import tclCommands.TclCommandCncjob
 import tclCommands.TclCommandCopperClear
 import tclCommands.TclCommandCopperClear
@@ -53,6 +54,7 @@ import tclCommands.TclCommandSaveProject
 import tclCommands.TclCommandSaveSys
 import tclCommands.TclCommandSaveSys
 import tclCommands.TclCommandScale
 import tclCommands.TclCommandScale
 import tclCommands.TclCommandSetActive
 import tclCommands.TclCommandSetActive
+import tclCommands.TclCommandSetOrigin
 import tclCommands.TclCommandSetSys
 import tclCommands.TclCommandSetSys
 import tclCommands.TclCommandSkew
 import tclCommands.TclCommandSkew
 import tclCommands.TclCommandSubtractPoly
 import tclCommands.TclCommandSubtractPoly

برخی فایل ها در این مقایسه diff نمایش داده نمی شوند زیرا تعداد فایل ها بسیار زیاد است