work around shapely weirdness for closed paths

pull/252/head
Lex Neva 2018-07-31 08:55:36 -04:00
rodzic 1480bf73dc
commit 0c74bcb816
2 zmienionych plików z 37 dodań i 7 usunięć

Wyświetl plik

@ -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)

Wyświetl plik

@ -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 "