Просмотр исходного кода

- Geometry Editor: made the tool to be able to continuously move until the tool is exited either by ESC key or by right mouse button click
- Geometry Editor Move Tool: if no shape is selected when triggering this tool, now it is possible to make the selection inside the tool
- Gerber editor Move Tool: fixed a bug that repeated the plotting function unnecessarily
- Gerber editor Move Tool: if no shape is selected the tool will exit

Marius Stanciu 6 лет назад
Родитель
Сommit
28fce82432
4 измененных файлов с 163 добавлено и 46 удалено
  1. 4 0
      README.md
  2. 1 1
      camlib.py
  3. 88 39
      flatcamEditors/FlatCAMGeoEditor.py
  4. 70 6
      flatcamEditors/FlatCAMGrbEditor.py

+ 4 - 0
README.md

@@ -15,6 +15,10 @@ CAD program, and create G-Code for Isolation routing.
 - added move action for solid_geometry stored in the gerber_obj.apertures
 - fixed camlib.Gerber skew, rotate, offset, mirror functions to work for geometry stored in the Gerber apertures
 - fixed Gerber Editor follow_geometry reconstruction
+- Geometry Editor: made the tool to be able to continuously move until the tool is exited either by ESC key or by right mouse button click
+- Geometry Editor Move Tool: if no shape is selected when triggering this tool, now it is possible to make the selection inside the tool
+- Gerber editor Move Tool: fixed a bug that repeated the plotting function unnecessarily 
+- Gerber editor Move Tool: if no shape is selected the tool will exit
 
 7.05.2019
 

+ 1 - 1
camlib.py

@@ -7269,13 +7269,13 @@ class CNCjob(Geometry):
 
         self.create_geometry()
 
+
 def get_bounds(geometry_list):
     xmin = Inf
     ymin = Inf
     xmax = -Inf
     ymax = -Inf
 
-    #print "Getting bounds of:", str(geometry_set)
     for gs in geometry_list:
         try:
             gxmin, gymin, gxmax, gymax = gs.bounds()

+ 88 - 39
flatcamEditors/FlatCAMGeoEditor.py

@@ -18,6 +18,7 @@ from FlatCAMTool import FlatCAMTool
 from flatcamGUI.ObjectUI import LengthEntry, RadioSet
 
 from shapely.geometry import LineString, LinearRing, MultiLineString
+# from shapely.geometry import mapping
 from shapely.ops import cascaded_union, unary_union
 import shapely.affinity as affinity
 
@@ -29,6 +30,7 @@ from flatcamGUI.GUIElements import OptionalInputSection, FCCheckBox, FCEntry, FC
     FCTable, FCDoubleSpinner, FCButton, EvalEntry2, FCInputDialog
 from flatcamParsers.ParseFont import *
 
+# from vispy.io import read_png
 import gettext
 import FlatCAMTranslation as fcTranslate
 
@@ -1861,7 +1863,6 @@ class DrawTool(object):
     def __init__(self, draw_app):
         self.draw_app = draw_app
         self.complete = False
-        self.start_msg = "Click on 1st point..."
         self.points = []
         self.geometry = None  # DrawToolShape or None
 
@@ -1939,7 +1940,6 @@ class FCCircle(FCShapeTool):
         self.cursor = QtGui.QCursor(QtGui.QPixmap('share/aero_circle_geo.png'))
         QtGui.QGuiApplication.setOverrideCursor(self.cursor)
 
-        self.start_msg = _("Click on Center point ...")
         self.draw_app.app.inform.emit(_("Click on Center point ..."))
         self.steps_per_circ = self.draw_app.app.defaults["geometry_circle_steps"]
 
@@ -1991,7 +1991,6 @@ class FCArc(FCShapeTool):
         self.cursor = QtGui.QCursor(QtGui.QPixmap('share/aero_arc.png'))
         QtGui.QGuiApplication.setOverrideCursor(self.cursor)
 
-        self.start_msg = _("Click on Center point ...")
         self.draw_app.app.inform.emit(_("Click on Center point ..."))
 
         # Direction of rotation between point 1 and 2.
@@ -2210,12 +2209,13 @@ class FCRectangle(FCShapeTool):
         self.cursor = QtGui.QCursor(QtGui.QPixmap('share/aero.png'))
         QtGui.QGuiApplication.setOverrideCursor(self.cursor)
 
-        self.start_msg = _("Click on 1st corner ...")
+        self.draw_app.app.inform.emit( _("Click on 1st corner ..."))
 
     def click(self, point):
         self.points.append(point)
 
         if len(self.points) == 1:
+            self.draw_app.app.inform.emit(_("Click on opposite corner to complete ..."))
             return "Click on opposite corner to complete ..."
 
         if len(self.points) == 2:
@@ -2262,14 +2262,14 @@ class FCPolygon(FCShapeTool):
         self.cursor = QtGui.QCursor(QtGui.QPixmap('share/aero.png'))
         QtGui.QGuiApplication.setOverrideCursor(self.cursor)
 
-        self.start_msg = _("Click on 1st point ...")
+        self.draw_app.app.inform.emit(_("Click on 1st corner ..."))
 
     def click(self, point):
         self.draw_app.in_action = True
         self.points.append(point)
 
         if len(self.points) > 0:
-            self.draw_app.app.inform.emit(_("Click on next Point or click Right mouse button to complete ..."))
+            self.draw_app.app.inform.emit(_("Click on next Point or click right mouse button to complete ..."))
             return "Click on next point or hit ENTER to complete ..."
 
         return ""
@@ -2445,21 +2445,33 @@ class FCMove(FCShapeTool):
         FCShapeTool.__init__(self, draw_app)
         self.name = 'move'
 
-        # self.shape_buffer = self.draw_app.shape_buffer
-        if not self.draw_app.selected:
-            self.draw_app.app.inform.emit(_("[WARNING_NOTCL] Move cancelled. No shape selected."))
-            return
+        try:
+            QtGui.QGuiApplication.restoreOverrideCursor()
+        except:
+            pass
+
+        self.storage = self.draw_app.storage
+
         self.origin = None
         self.destination = None
-        self.start_msg = _("Click on reference point.")
+
+        if len(self.draw_app.get_selected()) == 0:
+            self.draw_app.app.inform.emit(_("[WARNING_NOTCL] MOVE: No shape selected. Select a shape to move ..."))
+        else:
+            self.draw_app.app.inform.emit(_(" MOVE: Click on reference point ..."))
 
     def set_origin(self, origin):
-        self.draw_app.app.inform.emit(_("Click on destination point."))
+        self.draw_app.app.inform.emit(_(" Click on destination point ..."))
         self.origin = origin
 
     def click(self, point):
         if len(self.draw_app.get_selected()) == 0:
-            return "Nothing to move."
+            # self.complete = True
+            # self.draw_app.app.inform.emit(_("[WARNING_NOTCL] Move cancelled. No shape selected."))
+            self.select_shapes(point)
+            self.draw_app.replot()
+            self.draw_app.app.inform.emit(_(" MOVE: Click on reference point ..."))
+            return
 
         if self.origin is None:
             self.set_origin(point)
@@ -2517,6 +2529,58 @@ class FCMove(FCShapeTool):
         # return DrawToolUtilityShape([affinity.translate(geom.geo, xoff=dx, yoff=dy)
         #                              for geom in self.draw_app.get_selected()])
 
+    def select_shapes(self, pos):
+        # list where we store the overlapped shapes under our mouse left click position
+        over_shape_list = []
+
+        try:
+            _, closest_shape = self.storage.nearest(pos)
+        except StopIteration:
+            return ""
+
+        over_shape_list.append(closest_shape)
+
+        try:
+            # if there is no shape under our click then deselect all shapes
+            # it will not work for 3rd method of click selection
+            if not over_shape_list:
+                self.draw_app.selected = []
+                self.draw_app.draw_shape_idx = -1
+            else:
+                # if there are shapes under our click then advance through the list of them, one at the time in a
+                # circular way
+                self.draw_app.draw_shape_idx = (FlatCAMGeoEditor.draw_shape_idx + 1) % len(over_shape_list)
+                try:
+                    obj_to_add = over_shape_list[int(FlatCAMGeoEditor.draw_shape_idx)]
+                except IndexError:
+                    return
+
+                key_modifier = QtWidgets.QApplication.keyboardModifiers()
+                if self.draw_app.app.defaults["global_mselect_key"] == 'Control':
+                    # if CONTROL key is pressed then we add to the selected list the current shape but if it's
+                    # already in the selected list, we removed it. Therefore first click selects, second deselects.
+                    if key_modifier == Qt.ControlModifier:
+                        if obj_to_add in self.draw_app.selected:
+                            self.draw_app.selected.remove(obj_to_add)
+                        else:
+                            self.draw_app.selected.append(obj_to_add)
+                    else:
+                        self.draw_app.selected = []
+                        self.draw_app.selected.append(obj_to_add)
+                else:
+                    if key_modifier == Qt.ShiftModifier:
+                        if obj_to_add in self.draw_app.selected:
+                            self.draw_app.selected.remove(obj_to_add)
+                        else:
+                            self.draw_app.selected.append(obj_to_add)
+                    else:
+                        self.draw_app.selected = []
+                        self.draw_app.selected.append(obj_to_add)
+
+        except Exception as e:
+            log.error("[ERROR] Something went bad. %s" % str(e))
+            raise
+
 
 class FCCopy(FCMove):
     def __init__(self, draw_app):
@@ -2550,7 +2614,7 @@ class FCText(FCShapeTool):
         self.draw_app = draw_app
         self.app = draw_app.app
 
-        self.start_msg = _("Click on the Destination point...")
+        self.draw_app.app.inform.emit(_("Click on 1st corner ..."))
         self.origin = (0, 0)
 
         self.text_gui = TextInputTool(self.app)
@@ -2602,7 +2666,7 @@ class FCBuffer(FCShapeTool):
         self.draw_app = draw_app
         self.app = draw_app.app
 
-        self.start_msg = _("Create buffer geometry ...")
+        self.draw_app.app.inform.emit(_("Create buffer geometry ..."))
         self.origin = (0, 0)
         self.buff_tool = BufferSelectionTool(self.app, self.draw_app)
         self.buff_tool.run()
@@ -2720,7 +2784,7 @@ class FCPaint(FCShapeTool):
         self.draw_app = draw_app
         self.app = draw_app.app
 
-        self.start_msg = _("Create Paint geometry ...")
+        self.draw_app.app.inform.emit(_("Create Paint geometry ..."))
         self.origin = (0, 0)
         self.draw_app.paint_tool.run()
 
@@ -2734,7 +2798,7 @@ class FCTransform(FCShapeTool):
         self.draw_app = draw_app
         self.app = draw_app.app
 
-        self.start_msg = _("Shape transformations ...")
+        self.draw_app.app.infrom.emit(_("Shape transformations ..."))
         self.origin = (0, 0)
         self.draw_app.transform_tool.run()
 
@@ -3159,6 +3223,9 @@ class FlatCAMGeoEditor(QtCore.QObject):
         :return: None
         """
 
+        if shape is None:
+            return
+
         # List of DrawToolShape?
         if isinstance(shape, list):
             for subshape in shape:
@@ -3280,8 +3347,6 @@ class FlatCAMGeoEditor(QtCore.QObject):
                         self.tools[t]["button"].setChecked(False)
 
                 self.active_tool = self.tools[tool]["constructor"](self)
-                if not isinstance(self.active_tool, FCSelect):
-                    self.app.inform.emit(self.active_tool.start_msg)
             else:
                 self.app.log.debug("%s is NOT checked." % tool)
                 for t in self.tools:
@@ -3341,6 +3406,7 @@ class FlatCAMGeoEditor(QtCore.QObject):
 
             # Selection with left mouse button
             if self.active_tool is not None and event.button is 1:
+
                 # Dispatch event to active_tool
                 msg = self.active_tool.click(self.snap(self.pos[0], self.pos[1]))
 
@@ -3348,28 +3414,11 @@ class FlatCAMGeoEditor(QtCore.QObject):
                 if isinstance(self.active_tool, FCShapeTool) and self.active_tool.complete:
                     self.on_shape_complete()
 
-                    # MS: always return to the Select Tool if modifier key is not pressed
-                    # else return to the current tool
-                    key_modifier = QtWidgets.QApplication.keyboardModifiers()
-                    if self.app.defaults["global_mselect_key"] == 'Control':
-                        modifier_to_use = Qt.ControlModifier
-                    else:
-                        modifier_to_use = Qt.ShiftModifier
-
                     if isinstance(self.active_tool, FCText):
                         self.select_tool("select")
                     else:
                         self.select_tool(self.active_tool.name)
 
-
-                    # if modifier key is pressed then we add to the selected list the current shape but if
-                    # it's already in the selected list, we removed it. Therefore first click selects, second deselects.
-                    # if key_modifier == modifier_to_use:
-                    #     self.select_tool(self.active_tool.name)
-                    # else:
-                    #     self.select_tool("select")
-                    #     return
-
                 if isinstance(self.active_tool, FCSelect):
                     # self.app.log.debug("Replotting after click.")
                     self.replot()
@@ -3616,13 +3665,13 @@ class FlatCAMGeoEditor(QtCore.QObject):
             self.selected.remove(shape)  # TODO: Check performance
 
     def on_move(self):
+        # if not self.selected:
+        #     self.app.inform.emit(_("[WARNING_NOTCL] Move cancelled. No shape selected."))
+        #     return
         self.app.ui.geo_move_btn.setChecked(True)
         self.on_tool_select('move')
 
     def on_move_click(self):
-        if not self.selected:
-            self.app.inform.emit(_("[WARNING_NOTCL] Move cancelled. No shape selected."))
-            return
         self.on_move()
         self.active_tool.set_origin(self.snap(self.x, self.y))
 

+ 70 - 6
flatcamEditors/FlatCAMGrbEditor.py

@@ -2,6 +2,7 @@ from PyQt5 import QtGui, QtCore, QtWidgets
 from PyQt5.QtCore import Qt, QSettings
 
 from shapely.geometry import LineString, LinearRing, MultiLineString
+# from shapely.geometry import mapping
 from shapely.ops import cascaded_union, unary_union
 import shapely.affinity as affinity
 
@@ -19,6 +20,9 @@ from FlatCAMTool import FlatCAMTool
 
 from numpy.linalg import norm as numpy_norm
 
+# from vispy.io import read_png
+# import pngcanvas
+
 import gettext
 import FlatCAMTranslation as fcTranslate
 
@@ -1449,11 +1453,18 @@ class FCApertureMove(FCShapeTool):
         self.destination = None
         self.selected_apertures = []
 
+        if len(self.draw_app.get_selected()) == 0:
+            self.draw_app.app.inform.emit(_("[WARNING_NOTCL] Nothing selected to move ..."))
+            self.complete = True
+            self.draw_app.select_tool("select")
+            return
+
         if self.draw_app.launched_from_shortcuts is True:
             self.draw_app.launched_from_shortcuts = False
             self.draw_app.app.inform.emit(_("Click on target location ..."))
         else:
             self.draw_app.app.inform.emit(_("Click on reference location ..."))
+
         self.current_storage = None
         self.geometry = []
 
@@ -1485,6 +1496,37 @@ class FCApertureMove(FCShapeTool):
             self.draw_app.select_tool("select")
             return
 
+    # def create_png(self):
+    #     """
+    #     Create a PNG file out of a list of Shapely polygons
+    #     :return:
+    #     """
+    #     if len(self.draw_app.get_selected()) == 0:
+    #         return None
+    #
+    #     geo_list = [geoms.geo for geoms in self.draw_app.get_selected()]
+    #     xmin, ymin, xmax, ymax = get_shapely_list_bounds(geo_list)
+    #
+    #     iwidth = (xmax - xmin)
+    #     iwidth = int(round(iwidth))
+    #     iheight = (ymax - ymin)
+    #     iheight = int(round(iheight))
+    #     c = pngcanvas.PNGCanvas(iwidth, iheight)
+    #
+    #     pixels = []
+    #     for geom in self.draw_app.get_selected():
+    #         m = mapping(geom.geo.exterior)
+    #         pixels += [[coord[0], coord[1]] for coord in m['coordinates']]
+    #         for g in geom.geo.interiors:
+    #             m = mapping(g)
+    #             pixels += [[coord[0], coord[1]] for coord in m['coordinates']]
+    #         c.polyline(pixels)
+    #         pixels = []
+    #
+    #     f = open("%s.png" % 'D:\\shapely_image', "wb")
+    #     f.write(c.dump())
+    #     f.close()
+
     def make(self):
         # Create new geometry
         dx = self.destination[0] - self.origin[0]
@@ -1499,13 +1541,14 @@ class FCApertureMove(FCShapeTool):
                     self.geometry.append(DrawToolShape(affinity.translate(select_shape.geo, xoff=dx, yoff=dy)))
                     self.current_storage.remove(select_shape)
                     sel_shapes_to_be_deleted.append(select_shape)
-                    self.draw_app.on_grb_shape_complete(self.current_storage)
+                    self.draw_app.on_grb_shape_complete(self.current_storage, noplot=True)
                     self.geometry = []
 
             for shp in sel_shapes_to_be_deleted:
                 self.draw_app.selected.remove(shp)
             sel_shapes_to_be_deleted = []
 
+        self.draw_app.plot_all()
         self.draw_app.build_ui()
         self.draw_app.app.inform.emit(_("[success] Done. Apertures Move completed."))
 
@@ -1531,8 +1574,9 @@ class FCApertureMove(FCShapeTool):
 
         dx = data[0] - self.origin[0]
         dy = data[1] - self.origin[1]
-        for geom in self.draw_app.get_selected():
-            geo_list.append(affinity.translate(geom.geo, xoff=dx, yoff=dy))
+        # for geom in self.draw_app.get_selected():
+        #     geo_list.append(affinity.translate(geom.geo, xoff=dx, yoff=dy))
+        geo_list = [affinity.translate(geom.geo, xoff=dx, yoff=dy) for geom in self.draw_app.get_selected()]
         return DrawToolUtilityShape(geo_list)
 
 
@@ -3188,7 +3232,7 @@ class FlatCAMGrbEditor(QtCore.QObject):
         self.options[key] = self.sender().isChecked()
         return self.options[key]
 
-    def on_grb_shape_complete(self, storage=None, specific_shape=None):
+    def on_grb_shape_complete(self, storage=None, specific_shape=None, noplot=False):
         self.app.log.debug("on_shape_complete()")
 
         if specific_shape:
@@ -3209,8 +3253,9 @@ class FlatCAMGrbEditor(QtCore.QObject):
         self.delete_utility_geometry()
         self.tool_shape.clear(update=True)
 
-        # Replot and reset tool.
-        self.plot_all()
+        if noplot is False:
+            # Replot and reset tool.
+            self.plot_all()
 
     def add_gerber_shape(self, shape, storage):
         """
@@ -4860,3 +4905,22 @@ class TransformEditorTool(FlatCAMTool):
         else:
             self.app.inform.emit(
                 _("[WARNING_NOTCL] Geometry shape skew Y cancelled..."))
+
+
+def get_shapely_list_bounds(geometry_list):
+    xmin = Inf
+    ymin = Inf
+    xmax = -Inf
+    ymax = -Inf
+
+    for gs in geometry_list:
+        try:
+            gxmin, gymin, gxmax, gymax = gs.bounds
+            xmin = min([xmin, gxmin])
+            ymin = min([ymin, gymin])
+            xmax = max([xmax, gxmax])
+            ymax = max([ymax, gymax])
+        except:
+            log.warning("DEVELOPMENT: Tried to get bounds of empty geometry.")
+
+    return [xmin, ymin, xmax, ymax]