diff options
| -rw-r--r-- | lib/extensions/convert_to_satin.py | 36 | ||||
| -rw-r--r-- | messages.po | 8 |
2 files changed, 37 insertions, 7 deletions
diff --git a/lib/extensions/convert_to_satin.py b/lib/extensions/convert_to_satin.py index b029b736..1eae69b1 100644 --- a/lib/extensions/convert_to_satin.py +++ b/lib/extensions/convert_to_satin.py @@ -1,6 +1,6 @@ import inkex from shapely import geometry as shgeo -from itertools import chain +from itertools import chain, groupby import numpy from numpy import diff, sign, setdiff1d from scipy.signal import argrelmin @@ -14,6 +14,10 @@ from ..elements import Stroke from ..utils import Point +class SelfIntersectionError(Exception): + pass + + class ConvertToSatin(InkstitchExtension): """Convert a line to a satin column of the same width.""" @@ -37,9 +41,17 @@ class ConvertToSatin(InkstitchExtension): style_args = self.join_style_args(element) for path in element.paths: + path = self.remove_duplicate_points(path) + + if len(path) < 2: + # ignore paths with just one point -- they're not visible to the user anyway + continue + + self.fix_loop(path) + try: rails, rungs = self.path_to_satin(path, element.stroke_width, style_args) - except ValueError: + except SelfIntersectionError: inkex.errormsg(_("Cannot convert %s to a satin column because it intersects itself. Try breaking it up into multiple paths.") % element.node.get('id')) # revert any changes we've made @@ -51,6 +63,24 @@ class ConvertToSatin(InkstitchExtension): parent.remove(element.node) + def fix_loop(self, path): + if path[0] == path[-1]: + # Looping paths seem to confuse shapely's parallel_offset(). It loses track + # of where the start and endpoint is, even if the user explicitly breaks the + # path. I suspect this is because parallel_offset() uses buffer() under the + # hood. + # + # To work around this we'll introduce a tiny gap by nudging the starting point + # toward the next point slightly. + start = Point(*path[0]) + next = Point(*path[1]) + direction = (next - start).unit() + start += 0.01 * direction + path[0] = start.as_tuple() + + def remove_duplicate_points(self, path): + return [point for point, repeats in groupby(path)] + def join_style_args(self, element): """Convert svg line join style to shapely parallel offset arguments.""" @@ -84,7 +114,7 @@ class ConvertToSatin(InkstitchExtension): # path intersects itself, when taking its stroke width into consideration. See # the last example for parallel_offset() in the Shapely documentation: # https://shapely.readthedocs.io/en/latest/manual.html#object.parallel_offset - raise ValueError() + raise SelfIntersectionError() # for whatever reason, shapely returns a right-side offset's coordinates in reverse left_rail = list(left_rail.coords) diff --git a/messages.po b/messages.po index 5de87d27..c8145586 100644 --- a/messages.po +++ b/messages.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PROJECT VERSION\n" "Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" -"POT-Creation-Date: 2018-07-31 08:40-0400\n" +"POT-Creation-Date: 2018-07-31 09:09-0400\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" "Language-Team: LANGUAGE <LL@li.org>\n" @@ -238,17 +238,17 @@ msgstr "" msgid "Please choose one or more commands to attach." msgstr "" -#: lib/extensions/convert_to_satin.py:25 +#: lib/extensions/convert_to_satin.py:29 msgid "Please select at least one line to convert to a satin column." msgstr "" #. : Convert To Satin extension, user selected one or more objects that were #. not lines. -#: lib/extensions/convert_to_satin.py:30 +#: lib/extensions/convert_to_satin.py:34 msgid "Only simple lines may be converted to satin columns." msgstr "" -#: lib/extensions/convert_to_satin.py:43 +#: lib/extensions/convert_to_satin.py:55 #, python-format msgid "" "Cannot convert %s to a satin column because it intersects itself. Try " |
