diff options
| -rw-r--r-- | lib/extensions/__init__.py | 4 | ||||
| -rw-r--r-- | lib/extensions/break_apart.py | 68 | ||||
| -rw-r--r-- | templates/break_apart.inx | 17 |
3 files changed, 88 insertions, 1 deletions
diff --git a/lib/extensions/__init__.py b/lib/extensions/__init__.py index cd8d79fb..53a6638a 100644 --- a/lib/extensions/__init__.py +++ b/lib/extensions/__init__.py @@ -1,4 +1,5 @@ from auto_satin import AutoSatin +from break_apart import BreakApart from convert_to_satin import ConvertToSatin from cut_satin import CutSatin from embroider import Embroider @@ -36,4 +37,5 @@ __all__ = extensions = [Embroider, AutoSatin, Lettering, Troubleshoot, - RemoveEmbroiderySettings] + RemoveEmbroiderySettings, + BreakApart] diff --git a/lib/extensions/break_apart.py b/lib/extensions/break_apart.py new file mode 100644 index 00000000..625ace55 --- /dev/null +++ b/lib/extensions/break_apart.py @@ -0,0 +1,68 @@ +from copy import deepcopy + +from shapely.geometry import Polygon + +import inkex + +from ..elements import AutoFill, Fill +from ..i18n import _ +from ..svg import get_correction_transform +from .base import InkstitchExtension + + +class BreakApart(InkstitchExtension): + def effect(self): # noqa: C901 + if not self.get_elements(): + return + + if not self.selected: + inkex.errormsg(_("Please select one or more fill areas to break apart.")) + return + + for element in self.elements: + if not isinstance(element, AutoFill) and not isinstance(element, Fill): + continue + if len(element.paths) <= 1: + continue + + polygons = [] + multipolygons = [] + holes = [] + + for path in element.paths: + polygons.append(Polygon(path)) + + # sort paths by size and convert to polygons + polygons.sort(key=lambda polygon: polygon.area, reverse=True) + + for shape in polygons: + if shape in holes: + continue + polygon_list = [shape] + + for other in polygons: + if shape != other and shape.contains(other) and other not in holes: + # check if "other" is inside a hole, before we add it to the list + if any(p.contains(other) for p in polygon_list[1:]): + continue + polygon_list.append(other) + holes.append(other) + multipolygons.append(polygon_list) + self.element_to_nodes(multipolygons, element) + + def element_to_nodes(self, multipolygons, element): + for polygons in multipolygons: + el = deepcopy(element) + d = "" + for polygon in polygons: + # copy element and replace path + el.node.set('id', self.uniqueId(element.node.get('id') + "_")) + d += "M" + for x, y in polygon.exterior.coords: + d += "%s,%s " % (x, y) + d += " " + d += "Z" + el.node.set('d', d) + el.node.set('transform', get_correction_transform(element.node)) + element.node.getparent().insert(0, el.node) + element.node.getparent().remove(element.node) diff --git a/templates/break_apart.inx b/templates/break_apart.inx new file mode 100644 index 00000000..2580ddc3 --- /dev/null +++ b/templates/break_apart.inx @@ -0,0 +1,17 @@ +<?xml version="1.0" encoding="UTF-8"?> +<inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension"> + <name>{% trans %}Break Apart and Retain Holes{% endtrans %}</name> + <id>org.inkstitch.break_apart.{{ locale }}</id> + <param name="extension" type="string" gui-hidden="true">break_apart</param> + <effect> + <object-type>all</object-type> + <effects-menu> + <submenu name="Ink/Stitch"> + <submenu name="{% trans %}Fill Tools{% endtrans %}" /> + </submenu> + </effects-menu> + </effect> + <script> + {{ command_tag | safe }} + </script> +</inkscape-extension> |
