Bladeren bron

- fixed the Tcl Command Geocutout to work with Gerber objects too (besides Geometry objects)

Marius Stanciu 7 jaren geleden
bovenliggende
commit
1a8db0b5d9
4 gewijzigde bestanden met toevoegingen van 154 en 51 verwijderingen
  1. 3 3
      FlatCAMEditor.py
  2. 1 0
      README.md
  3. 7 2
      camlib.py
  4. 143 46
      tclCommands/TclCommandGeoCutout.py

+ 3 - 3
FlatCAMEditor.py

@@ -106,21 +106,21 @@ class BufferSelectionTool(FlatCAMTool):
     def on_buffer(self):
         buffer_distance = self.buffer_distance_entry.get_value()
         # the cb index start from 0 but the join styles for the buffer start from 1 therefore the adjustment
-        # I populated the combobox such that the index coincide with the join styles value (whcih is really an INT)
+        # I populated the combobox such that the index coincide with the join styles value (which is really an INT)
         join_style = self.buffer_corner_cb.currentIndex() + 1
         self.draw_app.buffer(buffer_distance, join_style)
 
     def on_buffer_int(self):
         buffer_distance = self.buffer_distance_entry.get_value()
         # the cb index start from 0 but the join styles for the buffer start from 1 therefore the adjustment
-        # I populated the combobox such that the index coincide with the join styles value (whcih is really an INT)
+        # I populated the combobox such that the index coincide with the join styles value (which is really an INT)
         join_style = self.buffer_corner_cb.currentIndex() + 1
         self.draw_app.buffer_int(buffer_distance, join_style)
 
     def on_buffer_ext(self):
         buffer_distance = self.buffer_distance_entry.get_value()
         # the cb index start from 0 but the join styles for the buffer start from 1 therefore the adjustment
-        # I populated the combobox such that the index coincide with the join styles value (whcih is really an INT)
+        # I populated the combobox such that the index coincide with the join styles value (which is really an INT)
         join_style = self.buffer_corner_cb.currentIndex() + 1
         self.draw_app.buffer_ext(buffer_distance, join_style)
 

+ 1 - 0
README.md

@@ -25,6 +25,7 @@ CAD program, and create G-Code for Isolation routing.
 - combined the geocutout and cutout_any TCL commands - work in progress
 - added a new function (and shortcut key Escape) that when triggered it deselects all selected objects and delete the selection box(es) 
 - fixed bug in Excellon Gcode generation that made the toolchange X,Y always none regardless of the value in Preferences
+- fixed the Tcl Command Geocutout to work with Gerber objects too (besides Geometry objects)
 
 5.02.3019
 

+ 7 - 2
camlib.py

@@ -494,7 +494,7 @@ class Geometry(object):
     #
     #     return self.flat_geometry, self.flat_geometry_rtree
 
-    def isolation_geometry(self, offset, iso_type=2):
+    def isolation_geometry(self, offset, iso_type=2, corner=None):
         """
         Creates contours around geometry at a given
         offset distance.
@@ -503,6 +503,7 @@ class Geometry(object):
         :type offset: float
         :param iso_type: type of isolation, can be 0 = exteriors or 1 = interiors or 2 = both (complete)
         :type integer
+        :param corner: type of corner for the isolation: 0 = round; 1 = square; 2= beveled (line that connects the ends)
         :return: The buffered geometry.
         :rtype: Shapely.MultiPolygon or Shapely.Polygon
         """
@@ -537,7 +538,11 @@ class Geometry(object):
         if offset == 0:
             geo_iso = self.solid_geometry
         else:
-            geo_iso = self.solid_geometry.buffer(offset, int(int(self.geo_steps_per_circle) / 4))
+            if corner is None:
+                geo_iso = self.solid_geometry.buffer(offset, int(int(self.geo_steps_per_circle) / 4))
+            else:
+                geo_iso = self.solid_geometry.buffer(offset, int(int(self.geo_steps_per_circle) / 4), join_style=corner)
+
         # end of replaced block
 
         if iso_type == 2:

+ 143 - 46
tclCommands/TclCommandGeoCutout.py

@@ -55,6 +55,8 @@ class TclCommandGeoCutout(TclCommandSignaled):
                      "      geocutout BCu_margin_iso_exterior -dia 3 -gapsize 0.6 -gaps 4\n"]
     }
 
+    flat_geometry = []
+
     def execute(self, args, unnamed_args):
         """
 
@@ -63,10 +65,62 @@ class TclCommandGeoCutout(TclCommandSignaled):
         :return:
         """
 
+
         def subtract_rectangle(obj_, x0, y0, x1, y1):
             pts = [(x0, y0), (x1, y0), (x1, y1), (x0, y1)]
             obj_.subtract_polygon(pts)
 
+        def substract_rectangle_geo(geo, x0, y0, x1, y1):
+            pts = [(x0, y0), (x1, y0), (x1, y1), (x0, y1)]
+
+
+            def flatten(geometry=None, reset=True, pathonly=False):
+                """
+                Creates a list of non-iterable linear geometry objects.
+                Polygons are expanded into its exterior and interiors if specified.
+
+                Results are placed in flat_geometry
+
+                :param geometry: Shapely type or list or list of list of such.
+                :param reset: Clears the contents of self.flat_geometry.
+                :param pathonly: Expands polygons into linear elements.
+                """
+
+                if reset:
+                    self.flat_geometry = []
+
+                ## If iterable, expand recursively.
+                try:
+                    for geo in geometry:
+                        if geo is not None:
+                            flatten(geometry=geo,
+                                    reset=False,
+                                    pathonly=pathonly)
+
+                ## Not iterable, do the actual indexing and add.
+                except TypeError:
+                    if pathonly and type(geometry) == Polygon:
+                        self.flat_geometry.append(geometry.exterior)
+                        flatten(geometry=geometry.interiors,
+                                reset=False,
+                                pathonly=True)
+                    else:
+                        self.flat_geometry.append(geometry)
+
+                return self.flat_geometry
+
+            flat_geometry = flatten(geo, pathonly=True)
+
+            polygon = Polygon(pts)
+            toolgeo = cascaded_union(polygon)
+            diffs = []
+            for target in flat_geometry:
+                if type(target) == LineString or type(target) == LinearRing:
+                    diffs.append(target.difference(toolgeo))
+                else:
+                    log.warning("Not implemented.")
+            return cascaded_union(diffs)
+
         if 'name' in args:
             name = args['name']
         else:
@@ -116,20 +170,105 @@ class TclCommandGeoCutout(TclCommandSignaled):
         lenghtx = (xmax - xmin) + (margin * 2)
         lenghty = (ymax - ymin) + (margin * 2)
 
-        gapsize = gapsize + (dia / 2)
+        gapsize = gapsize / 2 + (dia / 2)
+
+        try:
+            gaps_u = int(gaps)
+        except ValueError:
+            gaps_u = gaps
 
         if isinstance(cutout_obj, FlatCAMGeometry):
             # rename the obj name so it can be identified as cutout
             cutout_obj.options["name"] += "_cutout"
+
+            if gaps_u == 8 or gaps_u == '2lr':
+                subtract_rectangle(cutout_obj,
+                                   xmin - gapsize,  # botleft_x
+                                   py - gapsize + lenghty / 4,  # botleft_y
+                                   xmax + gapsize,  # topright_x
+                                   py + gapsize + lenghty / 4)  # topright_y
+                subtract_rectangle(cutout_obj,
+                                   xmin - gapsize,
+                                   py - gapsize - lenghty / 4,
+                                   xmax + gapsize,
+                                   py + gapsize - lenghty / 4)
+
+            if gaps_u == 8 or gaps_u == '2tb':
+                subtract_rectangle(cutout_obj,
+                                   px - gapsize + lenghtx / 4,
+                                   ymin - gapsize,
+                                   px + gapsize + lenghtx / 4,
+                                   ymax + gapsize)
+                subtract_rectangle(cutout_obj,
+                                   px - gapsize - lenghtx / 4,
+                                   ymin - gapsize,
+                                   px + gapsize - lenghtx / 4,
+                                   ymax + gapsize)
+
+            if gaps_u == 4 or gaps_u == 'lr':
+                subtract_rectangle(cutout_obj,
+                                   xmin - gapsize,
+                                   py - gapsize,
+                                   xmax + gapsize,
+                                   py + gapsize)
+
+            if gaps_u == 4 or gaps_u == 'tb':
+                subtract_rectangle(cutout_obj,
+                                   px - gapsize,
+                                   ymin - gapsize,
+                                   px + gapsize,
+                                   ymax + gapsize)
+
+            cutout_obj.plot()
+            self.app.inform.emit("[success]Any-form Cutout operation finished.")
         elif isinstance(cutout_obj, FlatCAMGerber):
 
             def geo_init(geo_obj, app_obj):
                 try:
-                    geo_obj.solid_geometry = cutout_obj.isolation_geometry((dia / 2), iso_type=0)
+                    geo = cutout_obj.isolation_geometry((dia / 2), iso_type=0, corner=2)
                 except Exception as e:
                     log.debug("TclCommandGeoCutout.execute() --> %s" % str(e))
                     return 'fail'
 
+                if gaps_u == 8 or gaps_u == '2lr':
+                    geo = substract_rectangle_geo(geo,
+                                       xmin - gapsize,  # botleft_x
+                                       py - gapsize + lenghty / 4,  # botleft_y
+                                       xmax + gapsize,  # topright_x
+                                       py + gapsize + lenghty / 4)  # topright_y
+                    geo = substract_rectangle_geo(geo,
+                                       xmin - gapsize,
+                                       py - gapsize - lenghty / 4,
+                                       xmax + gapsize,
+                                       py + gapsize - lenghty / 4)
+
+                if gaps_u == 8 or gaps_u == '2tb':
+                    geo = substract_rectangle_geo(geo,
+                                       px - gapsize + lenghtx / 4,
+                                       ymin - gapsize,
+                                       px + gapsize + lenghtx / 4,
+                                       ymax + gapsize)
+                    geo = substract_rectangle_geo(geo,
+                                       px - gapsize - lenghtx / 4,
+                                       ymin - gapsize,
+                                       px + gapsize - lenghtx / 4,
+                                       ymax + gapsize)
+
+                if gaps_u == 4 or gaps_u == 'lr':
+                    geo = substract_rectangle_geo(geo,
+                                       xmin - gapsize,
+                                       py - gapsize,
+                                       xmax + gapsize,
+                                       py + gapsize)
+
+                if gaps_u == 4 or gaps_u == 'tb':
+                    geo = substract_rectangle_geo(geo,
+                                       px - gapsize,
+                                       ymin - gapsize,
+                                       px + gapsize,
+                                       ymax + gapsize)
+                geo_obj.solid_geometry = geo
+
             outname = cutout_obj.options["name"] + "_cutout"
             self.app.new_object('geometry', outname, geo_init)
 
@@ -138,48 +277,6 @@ class TclCommandGeoCutout(TclCommandSignaled):
             self.app.inform.emit("[ERROR]Cancelled. Object type is not supported.")
             return
 
-        try:
-            gaps_u = int(gaps)
-        except ValueError:
-            gaps_u = gaps
 
-        if gaps_u == 8 or gaps_u == '2lr':
-            subtract_rectangle(cutout_obj,
-                               xmin - gapsize,  # botleft_x
-                               py - gapsize + lenghty / 4,  # botleft_y
-                               xmax + gapsize,  # topright_x
-                               py + gapsize + lenghty / 4)  # topright_y
-            subtract_rectangle(cutout_obj,
-                               xmin - gapsize,
-                               py - gapsize - lenghty / 4,
-                               xmax + gapsize,
-                               py + gapsize - lenghty / 4)
-
-        if gaps_u == 8 or gaps_u == '2tb':
-            subtract_rectangle(cutout_obj,
-                               px - gapsize + lenghtx / 4,
-                               ymin - gapsize,
-                               px + gapsize + lenghtx / 4,
-                               ymax + gapsize)
-            subtract_rectangle(cutout_obj,
-                               px - gapsize - lenghtx / 4,
-                               ymin - gapsize,
-                               px + gapsize - lenghtx / 4,
-                               ymax + gapsize)
-
-        if gaps_u == 4 or gaps_u == 'lr':
-            subtract_rectangle(cutout_obj,
-                               xmin - gapsize,
-                               py - gapsize,
-                               xmax + gapsize,
-                               py + gapsize)
-
-        if gaps_u == 4 or gaps_u == 'tb':
-            subtract_rectangle(cutout_obj,
-                               px - gapsize,
-                               ymin - gapsize,
-                               px + gapsize,
-                               ymax + gapsize)
-
-        cutout_obj.plot()
-        self.app.inform.emit("[success]Any-form Cutout operation finished.")
+
+