From 038875f876d79d0f1e971886fe42f5bee4f9f31e Mon Sep 17 00:00:00 2001 From: Lex Neva Date: Tue, 21 Aug 2018 20:32:50 -0400 Subject: [PATCH] autopep8 --- lib/commands.py | 11 ++- lib/elements/auto_fill.py | 60 +++++++-------- lib/elements/element.py | 4 +- lib/elements/fill.py | 59 +++++++-------- lib/elements/polyline.py | 10 +-- lib/elements/satin_column.py | 72 +++++++++--------- lib/elements/stroke.py | 64 ++++++++-------- lib/extensions/__init__.py | 2 +- lib/extensions/base.py | 12 ++- lib/extensions/convert_to_satin.py | 27 +++---- lib/extensions/flip.py | 1 + lib/extensions/input.py | 11 ++- lib/extensions/install.py | 16 ++-- lib/extensions/layer_commands.py | 20 ++--- lib/extensions/object_commands.py | 54 +++++++------- lib/extensions/output.py | 1 + lib/extensions/print_pdf.py | 84 ++++++++++----------- lib/i18n.py | 5 ++ lib/inx/generate.py | 1 + lib/inx/utils.py | 7 +- lib/output.py | 24 +++--- lib/stitch_plan/stitch.py | 18 ++--- lib/stitches/auto_fill.py | 31 ++++---- lib/stitches/fill.py | 2 + lib/svg/path.py | 3 + lib/svg/realistic_rendering.py | 1 + lib/svg/svg.py | 38 +++++----- lib/svg/units.py | 21 +++--- lib/threads/catalog.py | 2 + lib/threads/color.py | 1 + lib/utils/cache.py | 2 + lib/utils/geometry.py | 3 +- lib/utils/inkscape.py | 1 + lib/utils/io.py | 2 + messages.po | 114 ++++++++++++++--------------- stub.py | 2 +- 36 files changed, 414 insertions(+), 372 deletions(-) diff --git a/lib/commands.py b/lib/commands.py index 214b5f404..7764539cd 100644 --- a/lib/commands.py +++ b/lib/commands.py @@ -26,8 +26,9 @@ COMMANDS = { "ignore_layer": N_("Ignore layer (do not stitch any objects in this layer)") } -OBJECT_COMMANDS = [ "fill_start", "fill_end", "stop", "trim", "ignore_object" ] -LAYER_COMMANDS = [ "ignore_layer" ] +OBJECT_COMMANDS = ["fill_start", "fill_end", "stop", "trim", "ignore_object"] +LAYER_COMMANDS = ["ignore_layer"] + class CommandParseError(Exception): pass @@ -50,7 +51,7 @@ class BaseCommand(object): else: raise CommandParseError("symbol is not an Ink/Stitch command") - def get_node_by_url(self,url): + def get_node_by_url(self, url): # url will be #path12345. Find the corresponding object. if url is None: raise CommandParseError("url is None") @@ -116,6 +117,7 @@ class StandaloneCommand(BaseCommand): self.parse_symbol() + def get_command_description(command): return _(COMMANDS[command]) @@ -138,6 +140,7 @@ def find_commands(node): return commands + def layer_commands(layer, command): """Find standalone (unconnected) command symbols in this layer.""" @@ -150,6 +153,7 @@ def layer_commands(layer, command): return commands + def standalone_commands(svg): """Find all unconnected command symbols in the SVG.""" @@ -165,5 +169,6 @@ def standalone_commands(svg): return commands + def is_command(node): return CONNECTION_START in node.attrib or CONNECTION_END in node.attrib diff --git a/lib/elements/auto_fill.py b/lib/elements/auto_fill.py index 79220a865..cfee6d7df 100644 --- a/lib/elements/auto_fill.py +++ b/lib/elements/auto_fill.py @@ -31,11 +31,11 @@ class AutoFill(Fill): @property @param('running_stitch_length_mm', - _('Running stitch length (traversal between sections)'), - tooltip=_('Length of stitches around the outline of the fill region used when moving from section to section.'), - unit='mm', - type='float', - default=1.5) + _('Running stitch length (traversal between sections)'), + tooltip=_('Length of stitches around the outline of the fill region used when moving from section to section.'), + unit='mm', + type='float', + default=1.5) def running_stitch_length(self): return max(self.get_float_param("running_stitch_length_mm", 1.5), 0.01) @@ -46,11 +46,11 @@ class AutoFill(Fill): @property @param('fill_underlay_angle', - _('Fill angle'), - tooltip=_('default: fill angle + 90 deg'), - unit='deg', - group=_('AutoFill Underlay'), - type='float') + _('Fill angle'), + tooltip=_('default: fill angle + 90 deg'), + unit='deg', + group=_('AutoFill Underlay'), + type='float') @cache def fill_underlay_angle(self): underlay_angle = self.get_float_param("fill_underlay_angle") @@ -62,43 +62,43 @@ class AutoFill(Fill): @property @param('fill_underlay_row_spacing_mm', - _('Row spacing'), - tooltip=_('default: 3x fill row spacing'), - unit='mm', - group=_('AutoFill Underlay'), - type='float') + _('Row spacing'), + tooltip=_('default: 3x fill row spacing'), + unit='mm', + group=_('AutoFill Underlay'), + type='float') @cache def fill_underlay_row_spacing(self): return self.get_float_param("fill_underlay_row_spacing_mm") or self.row_spacing * 3 @property @param('fill_underlay_max_stitch_length_mm', - _('Max stitch length'), - tooltip=_('default: equal to fill max stitch length'), - unit='mm', - group=_('AutoFill Underlay'), type='float') + _('Max stitch length'), + tooltip=_('default: equal to fill max stitch length'), + unit='mm', + group=_('AutoFill Underlay'), type='float') @cache def fill_underlay_max_stitch_length(self): return self.get_float_param("fill_underlay_max_stitch_length_mm") or self.max_stitch_length @property @param('fill_underlay_inset_mm', - _('Inset'), - tooltip=_('Shrink the shape before doing underlay, to prevent underlay from showing around the outside of the fill.'), - unit='mm', - group=_('AutoFill Underlay'), - type='float', - default=0) + _('Inset'), + tooltip=_('Shrink the shape before doing underlay, to prevent underlay from showing around the outside of the fill.'), + unit='mm', + group=_('AutoFill Underlay'), + type='float', + default=0) def fill_underlay_inset(self): return self.get_float_param('fill_underlay_inset_mm', 0) @property @param('expand_mm', - _('Expand'), - tooltip=_('Expand the shape before fill stitching, to compensate for gaps between shapes.'), - unit='mm', - type='float', - default=0) + _('Expand'), + tooltip=_('Expand the shape before fill stitching, to compensate for gaps between shapes.'), + unit='mm', + type='float', + default=0) def expand(self): return self.get_float_param('expand_mm', 0) diff --git a/lib/elements/element.py b/lib/elements/element.py index ebca90a41..5ca70cf6f 100644 --- a/lib/elements/element.py +++ b/lib/elements/element.py @@ -157,7 +157,7 @@ class EmbroideryElement(object): doc_width, doc_height = get_doc_size(svg) viewbox = svg.get('viewBox', '0 0 %s %s' % (doc_width, doc_height)) viewbox = viewbox.strip().replace(',', ' ').split() - return doc_width / float(viewbox[2]) + return doc_width / float(viewbox[2]) @property @cache @@ -230,7 +230,7 @@ class EmbroideryElement(object): return commands[0] elif len(commands) > 1: raise ValueError(_("%(id)s has more than one command of type '%(command)s' linked to it") % - dict(id=self.node.get(id), command=command)) + dict(id=self.node.get(id), command=command)) else: return None diff --git a/lib/elements/fill.py b/lib/elements/fill.py index 394f523e9..672f4db86 100644 --- a/lib/elements/fill.py +++ b/lib/elements/fill.py @@ -16,21 +16,21 @@ class Fill(EmbroideryElement): @property @param('auto_fill', - _('Manually routed fill stitching'), - tooltip=_('AutoFill is the default method for generating fill stitching.'), - type='toggle', - inverse=True, - default=True) + _('Manually routed fill stitching'), + tooltip=_('AutoFill is the default method for generating fill stitching.'), + type='toggle', + inverse=True, + default=True) def auto_fill(self): return self.get_boolean_param('auto_fill', True) @property @param('angle', - _('Angle of lines of stitches'), - tooltip=_('The angle increases in a counter-clockwise direction. 0 is horizontal. Negative angles are allowed.'), - unit='deg', - type='float', - default=0) + _('Angle of lines of stitches'), + tooltip=_('The angle increases in a counter-clockwise direction. 0 is horizontal. Negative angles are allowed.'), + unit='deg', + type='float', + default=0) @cache def angle(self): return math.radians(self.get_float_param('angle', 0)) @@ -41,21 +41,22 @@ class Fill(EmbroideryElement): return self.get_style("fill", "#000000") @property - @param('flip', - _('Flip fill (start right-to-left)'), - tooltip=_('The flip option can help you with routing your stitch path. When you enable flip, stitching goes from right-to-left instead of left-to-right.'), - type='boolean', - default=False) + @param( + 'flip', + _('Flip fill (start right-to-left)'), + tooltip=_('The flip option can help you with routing your stitch path. When you enable flip, stitching goes from right-to-left instead of left-to-right.'), + type='boolean', + default=False) def flip(self): return self.get_boolean_param("flip", False) @property @param('row_spacing_mm', - _('Spacing between rows'), - tooltip=_('Distance between rows of stitches.'), - unit='mm', - type='float', - default=0.25) + _('Spacing between rows'), + tooltip=_('Distance between rows of stitches.'), + unit='mm', + type='float', + default=0.25) def row_spacing(self): return max(self.get_float_param("row_spacing_mm", 0.25), 0.1 * PIXELS_PER_MM) @@ -65,20 +66,20 @@ class Fill(EmbroideryElement): @property @param('max_stitch_length_mm', - _('Maximum fill stitch length'), - tooltip=_('The length of each stitch in a row. Shorter stitch may be used at the start or end of a row.'), - unit='mm', - type='float', - default=3.0) + _('Maximum fill stitch length'), + tooltip=_('The length of each stitch in a row. Shorter stitch may be used at the start or end of a row.'), + unit='mm', + type='float', + default=3.0) def max_stitch_length(self): return max(self.get_float_param("max_stitch_length_mm", 3.0), 0.1 * PIXELS_PER_MM) @property @param('staggers', - _('Stagger rows this many times before repeating'), - tooltip=_('Setting this dictates how many rows apart the stitches will be before they fall in the same column position.'), - type='int', - default=4) + _('Stagger rows this many times before repeating'), + tooltip=_('Setting this dictates how many rows apart the stitches will be before they fall in the same column position.'), + type='int', + default=4) def staggers(self): return self.get_int_param("staggers", 4) diff --git a/lib/elements/polyline.py b/lib/elements/polyline.py index b9ffdc0b7..d32427954 100644 --- a/lib/elements/polyline.py +++ b/lib/elements/polyline.py @@ -21,13 +21,13 @@ class Polyline(EmbroideryElement): @property def points(self): - # example: "1,2 0,0 1.5,3 4,2" + # example: "1,2 0,0 1.5,3 4,2" - points = self.node.get('points') - points = points.split(" ") - points = [[float(coord) for coord in point.split(",")] for point in points] + points = self.node.get('points') + points = points.split(" ") + points = [[float(coord) for coord in point.split(",")] for point in points] - return points + return points @property @cache diff --git a/lib/elements/satin_column.py b/lib/elements/satin_column.py index 834509fd4..e13e11180 100644 --- a/lib/elements/satin_column.py +++ b/lib/elements/satin_column.py @@ -29,22 +29,23 @@ class SatinColumn(EmbroideryElement): @property @param('zigzag_spacing_mm', - _('Zig-zag spacing (peak-to-peak)'), - tooltip=_('Peak-to-peak distance between zig-zags.'), - unit='mm', - type='float', - default=0.4) + _('Zig-zag spacing (peak-to-peak)'), + tooltip=_('Peak-to-peak distance between zig-zags.'), + unit='mm', + type='float', + default=0.4) def zigzag_spacing(self): # peak-to-peak distance between zigzags return max(self.get_float_param("zigzag_spacing_mm", 0.4), 0.01) @property - @param('pull_compensation_mm', - _('Pull compensation'), - tooltip=_('Satin stitches pull the fabric together, resulting in a column narrower than you draw in Inkscape. This setting expands each pair of needle penetrations outward from the center of the satin column.'), - unit='mm', - type='float', - default=0) + @param( + 'pull_compensation_mm', + _('Pull compensation'), + tooltip=_('Satin stitches pull the fabric together, resulting in a column narrower than you draw in Inkscape. This setting expands each pair of needle penetrations outward from the center of the satin column.'), + unit='mm', + type='float', + default=0) def pull_compensation(self): # In satin stitch, the stitches have a tendency to pull together and # narrow the entire column. We can compensate for this by stitching @@ -65,12 +66,12 @@ class SatinColumn(EmbroideryElement): @property @param('contour_underlay_inset_mm', - _('Contour underlay inset amount'), - tooltip=_('Shrink the outline, to prevent the underlay from showing around the outside of the satin column.'), - unit='mm', - group=_('Contour Underlay'), - type='float', - default=0.4) + _('Contour underlay inset amount'), + tooltip=_('Shrink the outline, to prevent the underlay from showing around the outside of the satin column.'), + unit='mm', + group=_('Contour Underlay'), + type='float', + default=0.4) def contour_underlay_inset(self): # how far inside the edge of the column to stitch the underlay return self.get_float_param("contour_underlay_inset_mm", 0.4) @@ -94,23 +95,23 @@ class SatinColumn(EmbroideryElement): @property @param('zigzag_underlay_spacing_mm', - _('Zig-Zag spacing (peak-to-peak)'), - tooltip=_('Distance between peaks of the zig-zags.'), - unit='mm', - group=_('Zig-zag Underlay'), - type='float', - default=3) + _('Zig-Zag spacing (peak-to-peak)'), + tooltip=_('Distance between peaks of the zig-zags.'), + unit='mm', + group=_('Zig-zag Underlay'), + type='float', + default=3) def zigzag_underlay_spacing(self): return max(self.get_float_param("zigzag_underlay_spacing_mm", 3), 0.01) @property @param('zigzag_underlay_inset_mm', - _('Inset amount'), - tooltip=_('default: half of contour underlay inset'), - unit='mm', - group=_('Zig-zag Underlay'), - type='float', - default="") + _('Inset amount'), + tooltip=_('default: half of contour underlay inset'), + unit='mm', + group=_('Zig-zag Underlay'), + type='float', + default="") def zigzag_underlay_inset(self): # how far in from the edge of the satin the points in the zigzags # should be @@ -147,7 +148,6 @@ class SatinColumn(EmbroideryElement): else: return self.flatten_beziers_with_rungs() - def flatten_beziers_with_rungs(self): input_paths = [self.flatten([path]) for path in self.csp] input_paths = [shgeo.LineString(path[0]) for path in input_paths] @@ -176,16 +176,17 @@ class SatinColumn(EmbroideryElement): #print >> dbg, "rails and rungs", [str(rail) for rail in rails], [str(rung) for rung in rungs] if len(linestrings.geoms) < len(rungs.geoms) + 1: - self.fatal(_("satin column: One or more of the rungs doesn't intersect both rails.") + " " + _("Each rail should intersect both rungs once.")) + self.fatal(_("satin column: One or more of the rungs doesn't intersect both rails.") + + " " + _("Each rail should intersect both rungs once.")) elif len(linestrings.geoms) > len(rungs.geoms) + 1: - self.fatal(_("satin column: One or more of the rungs intersects the rails more than once.") + " " + _("Each rail should intersect both rungs once.")) + self.fatal(_("satin column: One or more of the rungs intersects the rails more than once.") + + " " + _("Each rail should intersect both rungs once.")) paths = [[Point(*coord) for coord in ls.coords] for ls in linestrings.geoms] result.append(paths) return zip(*result) - def simple_flatten_beziers(self): # Given a pair of paths made up of bezier segments, flatten # each individual bezier segment into line segments that approximate @@ -223,8 +224,8 @@ class SatinColumn(EmbroideryElement): if len(self.csp) == 2: if len(self.csp[0]) != len(self.csp[1]): - self.fatal(_("satin column: object %(id)s has two paths with an unequal number of points (%(length1)d and %(length2)d)") % \ - dict(id=node_id, length1=len(self.csp[0]), length2=len(self.csp[1]))) + self.fatal(_("satin column: object %(id)s has two paths with an unequal number of points (%(length1)d and %(length2)d)") % + dict(id=node_id, length1=len(self.csp[0]), length2=len(self.csp[1]))) def offset_points(self, pos1, pos2, offset_px): # Expand or contract two points about their midpoint. This is @@ -443,7 +444,6 @@ class SatinColumn(EmbroideryElement): return patch - def to_patches(self, last_patch): # Stitch a variable-width satin column, zig-zagging between two paths. diff --git a/lib/elements/stroke.py b/lib/elements/stroke.py index e84d5e795..183ef23b9 100644 --- a/lib/elements/stroke.py +++ b/lib/elements/stroke.py @@ -28,44 +28,45 @@ class Stroke(EmbroideryElement): @property @param('running_stitch_length_mm', - _('Running stitch length'), - tooltip=_('Length of stitches in running stitch mode.'), - unit='mm', - type='float', - default=1.5, - sort_index=3) + _('Running stitch length'), + tooltip=_('Length of stitches in running stitch mode.'), + unit='mm', + type='float', + default=1.5, + sort_index=3) def running_stitch_length(self): return max(self.get_float_param("running_stitch_length_mm", 1.5), 0.01) @property - @param('bean_stitch_repeats', - _('Bean stitch number of repeats'), - tooltip=_('Backtrack each stitch this many times. A value of 1 would triple each stitch (forward, back, forward). A value of 2 would quintuple each stitch, etc. Only applies to running stitch.'), - type='int', - default=0, - sort_index=2) + @param( + 'bean_stitch_repeats', + _('Bean stitch number of repeats'), + tooltip=_('Backtrack each stitch this many times. A value of 1 would triple each stitch (forward, back, forward). A value of 2 would quintuple each stitch, etc. Only applies to running stitch.'), + type='int', + default=0, + sort_index=2) def bean_stitch_repeats(self): return self.get_int_param("bean_stitch_repeats", 0) @property @param('zigzag_spacing_mm', - _('Zig-zag spacing (peak-to-peak)'), - tooltip=_('Length of stitches in zig-zag mode.'), - unit='mm', - type='float', - default=0.4, - sort_index=3) + _('Zig-zag spacing (peak-to-peak)'), + tooltip=_('Length of stitches in zig-zag mode.'), + unit='mm', + type='float', + default=0.4, + sort_index=3) @cache def zigzag_spacing(self): return max(self.get_float_param("zigzag_spacing_mm", 0.4), 0.01) @property @param('repeats', - _('Repeats'), - tooltip=_('Defines how many times to run down and back along the path.'), - type='int', - default="1", - sort_index=1) + _('Repeats'), + tooltip=_('Defines how many times to run down and back along the path.'), + type='int', + default="1", + sort_index=1) def repeats(self): return self.get_int_param("repeats", 1) @@ -86,11 +87,11 @@ class Stroke(EmbroideryElement): @property @param('manual_stitch', - _('Manual stitch placement'), - tooltip=_("Stitch every node in the path. Stitch length and zig-zag spacing are ignored."), - type='boolean', - default=False, - sort_index=0) + _('Manual stitch placement'), + tooltip=_("Stitch every node in the path. Stitch length and zig-zag spacing are ignored."), + type='boolean', + default=False, + sort_index=0) def manual_stitch_mode(self): return self.get_boolean_param('manual_stitch') @@ -121,9 +122,9 @@ class Stroke(EmbroideryElement): global warned_about_legacy_running_stitch if not warned_about_legacy_running_stitch: warned_about_legacy_running_stitch = True - print >> sys.stderr, _("Legacy running stitch setting detected!\n\nIt looks like you're using a stroke " + \ - "smaller than 0.5 units to indicate a running stitch, which is deprecated. Instead, please set " + \ - "your stroke to be dashed to indicate running stitch. Any kind of dash will work.") + print >> sys.stderr, _("Legacy running stitch setting detected!\n\nIt looks like you're using a stroke " + + "smaller than 0.5 units to indicate a running stitch, which is deprecated. Instead, please set " + + "your stroke to be dashed to indicate running stitch. Any kind of dash will work.") # still allow the deprecated setting to work in order to support old files return True @@ -174,7 +175,6 @@ class Stroke(EmbroideryElement): return Patch(self.color, stitches) - def to_patches(self, last_patch): patches = [] diff --git a/lib/extensions/__init__.py b/lib/extensions/__init__.py index 1606795c1..b865db4ce 100644 --- a/lib/extensions/__init__.py +++ b/lib/extensions/__init__.py @@ -19,4 +19,4 @@ for item in locals().values(): if inspect.isclass(item) and \ issubclass(item, InkstitchExtension) and \ item is not InkstitchExtension: - extensions.append(item) + extensions.append(item) diff --git a/lib/extensions/base.py b/lib/extensions/base.py index 1794b68c6..07eaa40cd 100644 --- a/lib/extensions/base.py +++ b/lib/extensions/base.py @@ -109,11 +109,11 @@ class InkstitchExtension(inkex.Effect): g.set("style", "display:none") def no_elements_error(self): - if self.selected: - inkex.errormsg(_("No embroiderable paths selected.")) - else: - inkex.errormsg(_("No embroiderable paths found in document.")) - inkex.errormsg(_("Tip: use Path -> Object to Path to convert non-paths.")) + if self.selected: + inkex.errormsg(_("No embroiderable paths selected.")) + else: + inkex.errormsg(_("No embroiderable paths found in document.")) + inkex.errormsg(_("Tip: use Path -> Object to Path to convert non-paths.")) def descendants(self, node, selected=False): nodes = [] @@ -176,7 +176,6 @@ class InkstitchExtension(inkex.Effect): return classes - def get_elements(self): self.elements = [] for node in self.get_nodes(): @@ -212,7 +211,6 @@ class InkstitchExtension(inkex.Effect): return svg_filename - def parse(self): """Override inkex.Effect to add Ink/Stitch xml namespace""" diff --git a/lib/extensions/convert_to_satin.py b/lib/extensions/convert_to_satin.py index dd5a9bc28..d27e42ccf 100644 --- a/lib/extensions/convert_to_satin.py +++ b/lib/extensions/convert_to_satin.py @@ -51,7 +51,9 @@ class ConvertToSatin(InkstitchExtension): try: rails, rungs = self.path_to_satin(path, element.stroke_width, style_args) 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')) + 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 self.document = deepcopy(self.original_document) @@ -84,7 +86,7 @@ class ConvertToSatin(InkstitchExtension): """Convert svg line join style to shapely parallel offset arguments.""" args = { - 'join_style': shgeo.JOIN_STYLE.round + 'join_style': shgeo.JOIN_STYLE.round } element_join_style = element.get_style('stroke-linejoin') @@ -113,7 +115,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 SelfIntersectionError() + raise SelfIntersectionError() # for whatever reason, shapely returns a right-side offset's coordinates in reverse left_rail = list(left_rail.coords) @@ -244,7 +246,7 @@ class ConvertToSatin(InkstitchExtension): # millimeters before this one. if last_rung_center is not None and \ (rung_center - last_rung_center).length() < 2 * PIXELS_PER_MM: - continue + continue else: last_rung_center = rung_center @@ -269,7 +271,6 @@ class ConvertToSatin(InkstitchExtension): return rungs - def satin_to_svg_node(self, rails, rungs, correction_transform): d = "" for path in chain(rails, rungs): @@ -279,11 +280,11 @@ class ConvertToSatin(InkstitchExtension): d += " " return inkex.etree.Element(SVG_PATH_TAG, - { - "id": self.uniqueId("path"), - "style": "stroke:#000000;stroke-width:1px;fill:none", - "transform": correction_transform, - "d": d, - "embroider_satin_column": "true", - } - ) + { + "id": self.uniqueId("path"), + "style": "stroke:#000000;stroke-width:1px;fill:none", + "transform": correction_transform, + "d": d, + "embroider_satin_column": "true", + } + ) diff --git a/lib/extensions/flip.py b/lib/extensions/flip.py index d8d78cb54..5bea510f5 100644 --- a/lib/extensions/flip.py +++ b/lib/extensions/flip.py @@ -7,6 +7,7 @@ from .base import InkstitchExtension from ..i18n import _ from ..elements import SatinColumn + class Flip(InkstitchExtension): def subpath_to_linestring(self, subpath): return shgeo.LineString() diff --git a/lib/extensions/input.py b/lib/extensions/input.py index cb5ac452b..e450bef68 100644 --- a/lib/extensions/input.py +++ b/lib/extensions/input.py @@ -28,12 +28,11 @@ class Input(object): trim=(command == pyembroidery.TRIM)) extents = stitch_plan.extents - svg = etree.Element("svg", nsmap=inkex.NSS, attrib= - { - "width": str(extents[0] * 2), - "height": str(extents[1] * 2), - "viewBox": "0 0 %s %s" % (extents[0] * 2, extents[1] * 2), - }) + svg = etree.Element("svg", nsmap=inkex.NSS, attrib={ + "width": str(extents[0] * 2), + "height": str(extents[1] * 2), + "viewBox": "0 0 %s %s" % (extents[0] * 2, extents[1] * 2), + }) render_stitch_plan(svg, stitch_plan) # rename the Stitch Plan layer so that it doesn't get overwritten by Embroider diff --git a/lib/extensions/install.py b/lib/extensions/install.py index 42a92113c..2863bef04 100644 --- a/lib/extensions/install.py +++ b/lib/extensions/install.py @@ -28,22 +28,21 @@ class InstallerFrame(wx.Frame): text_sizer = wx.BoxSizer(wx.HORIZONTAL) text = _('Ink/Stitch can install files ("add-ons") that make it easier to use Inkscape to create machine embroidery designs. These add-ons will be installed:') + \ - "\n\n • " + _("thread manufacturer color palettes") + \ - "\n • " + _("Ink/Stitch visual commands (Object -> Symbols...)") + "\n\n • " + _("thread manufacturer color palettes") + "\n • " + _("Ink/Stitch visual commands (Object -> Symbols...)") static_text = wx.StaticText(panel, label=text) font = wx.Font(12, wx.DEFAULT, wx.NORMAL, wx.NORMAL) static_text.SetFont(font) - text_sizer.Add(static_text, proportion=0, flag=wx.ALL|wx.EXPAND, border=10) - sizer.Add(text_sizer, proportion=3, flag=wx.ALL|wx.EXPAND, border=0) + text_sizer.Add(static_text, proportion=0, flag=wx.ALL | wx.EXPAND, border=10) + sizer.Add(text_sizer, proportion=3, flag=wx.ALL | wx.EXPAND, border=0) buttons_sizer = wx.BoxSizer(wx.HORIZONTAL) install_button = wx.Button(panel, wx.ID_ANY, _("Install")) install_button.SetBitmap(wx.ArtProvider.GetBitmap(wx.ART_TICK_MARK)) - buttons_sizer.Add(install_button, proportion=0, flag=wx.ALIGN_RIGHT|wx.ALL, border=5) + buttons_sizer.Add(install_button, proportion=0, flag=wx.ALIGN_RIGHT | wx.ALL, border=5) cancel_button = wx.Button(panel, wx.ID_CANCEL, _("Cancel")) - buttons_sizer.Add(cancel_button, proportion=0, flag=wx.ALIGN_RIGHT|wx.ALL, border=5) - sizer.Add(buttons_sizer, proportion=1, flag=wx.ALIGN_RIGHT|wx.ALIGN_BOTTOM) + buttons_sizer.Add(cancel_button, proportion=0, flag=wx.ALIGN_RIGHT | wx.ALL, border=5) + sizer.Add(buttons_sizer, proportion=1, flag=wx.ALIGN_RIGHT | wx.ALIGN_BOTTOM) panel.SetSizer(sizer) panel.Layout() @@ -63,7 +62,7 @@ class InstallerFrame(wx.Frame): try: self.install_addons('palettes') self.install_addons('symbols') - except Exception, e: + except Exception as e: wx.MessageDialog(self, _('Inkscape add-on installation failed') + ': \n' + traceback.format_exc(), _('Installation Failed'), @@ -97,6 +96,7 @@ class InstallerFrame(wx.Frame): for palette_file in files: shutil.copy(palette_file, dest) + class Install(inkex.Effect): def effect(self): app = wx.App() diff --git a/lib/extensions/layer_commands.py b/lib/extensions/layer_commands.py index 576af044b..b9be2b27d 100644 --- a/lib/extensions/layer_commands.py +++ b/lib/extensions/layer_commands.py @@ -36,15 +36,15 @@ class LayerCommands(CommandsExtension): self.ensure_symbol(command) node = inkex.etree.SubElement(self.current_layer, SVG_USE_TAG, - { - "id": self.uniqueId("use"), - INKSCAPE_LABEL: _("Ink/Stitch Command") + ": %s" % get_command_description(command), - XLINK_HREF: "#inkstitch_%s" % command, - "height": "100%", - "width": "100%", - "x": str(i * 20), - "y": "-10", - "transform": correction_transform - }) + { + "id": self.uniqueId("use"), + INKSCAPE_LABEL: _("Ink/Stitch Command") + ": %s" % get_command_description(command), + XLINK_HREF: "#inkstitch_%s" % command, + "height": "100%", + "width": "100%", + "x": str(i * 20), + "y": "-10", + "transform": correction_transform + }) namedview = self.document.xpath("//sodipodi:namedview", namespaces=inkex.NSS) diff --git a/lib/extensions/object_commands.py b/lib/extensions/object_commands.py index e9ee60634..483f2a0a8 100644 --- a/lib/extensions/object_commands.py +++ b/lib/extensions/object_commands.py @@ -24,18 +24,18 @@ class ObjectCommands(CommandsExtension): end_pos = element.shape.centroid path = inkex.etree.Element(SVG_PATH_TAG, - { - "id": self.uniqueId("connector"), - "d": "M %s,%s %s,%s" % (start_pos[0], start_pos[1], end_pos.x, end_pos.y), - "style": "stroke:#000000;stroke-width:1px;stroke-opacity:0.5;fill:none;", - CONNECTION_START: "#%s" % symbol.get('id'), - CONNECTION_END: "#%s" % element.node.get('id'), - CONNECTOR_TYPE: "polyline", + { + "id": self.uniqueId("connector"), + "d": "M %s,%s %s,%s" % (start_pos[0], start_pos[1], end_pos.x, end_pos.y), + "style": "stroke:#000000;stroke-width:1px;stroke-opacity:0.5;fill:none;", + CONNECTION_START: "#%s" % symbol.get('id'), + CONNECTION_END: "#%s" % element.node.get('id'), + CONNECTOR_TYPE: "polyline", - # l10n: the name of the line that connects a command to the object it applies to - INKSCAPE_LABEL: _("connector") - } - ) + # l10n: the name of the line that connects a command to the object it applies to + INKSCAPE_LABEL: _("connector") + } + ) symbol.getparent().insert(0, path) @@ -75,26 +75,26 @@ class ObjectCommands(CommandsExtension): pos = self.get_command_pos(element, i, len(commands)) group = inkex.etree.SubElement(element.node.getparent(), SVG_GROUP_TAG, - { - "id": self.uniqueId("group"), - INKSCAPE_LABEL: _("Ink/Stitch Command") + ": %s" % get_command_description(command), - "transform": get_correction_transform(element.node) - } + { + "id": self.uniqueId("group"), + INKSCAPE_LABEL: _("Ink/Stitch Command") + ": %s" % get_command_description(command), + "transform": get_correction_transform(element.node) + } ) symbol = inkex.etree.SubElement(group, SVG_USE_TAG, - { - "id": self.uniqueId("use"), - XLINK_HREF: "#inkstitch_%s" % command, - "height": "100%", - "width": "100%", - "x": str(pos.x), - "y": str(pos.y), + { + "id": self.uniqueId("use"), + XLINK_HREF: "#inkstitch_%s" % command, + "height": "100%", + "width": "100%", + "x": str(pos.x), + "y": str(pos.y), - # l10n: the name of a command symbol (example: scissors icon for trim command) - INKSCAPE_LABEL: _("command marker"), - } - ) + # l10n: the name of a command symbol (example: scissors icon for trim command) + INKSCAPE_LABEL: _("command marker"), + } + ) self.add_connector(symbol, element) diff --git a/lib/extensions/output.py b/lib/extensions/output.py index f3bb0a802..090cd3a9c 100644 --- a/lib/extensions/output.py +++ b/lib/extensions/output.py @@ -11,6 +11,7 @@ from ..stitch_plan import patches_to_stitch_plan from ..svg import render_stitch_plan, PIXELS_PER_MM from ..utils.io import save_stdout + class Output(InkstitchExtension): def __init__(self, *args, **kwargs): InkstitchExtension.__init__(self) diff --git a/lib/extensions/print_pdf.py b/lib/extensions/print_pdf.py index 6e2eff58a..ee3dc316e 100644 --- a/lib/extensions/print_pdf.py +++ b/lib/extensions/print_pdf.py @@ -44,7 +44,7 @@ def load_defaults(): with open(defaults_path(), 'r') as defaults_file: defaults = json.load(defaults_file) return defaults - except: + except BaseException: return {} @@ -196,11 +196,11 @@ class PrintPreviewServer(Thread): threads = [] for color_block in self.stitch_plan: threads.append({ - 'hex': color_block.color.hex_digits, - 'name': color_block.color.name, - 'manufacturer': color_block.color.manufacturer, - 'number': color_block.color.number, - }) + 'hex': color_block.color.hex_digits, + 'name': color_block.color.name, + 'manufacturer': color_block.color.manufacturer, + 'number': color_block.color.number, + }) return jsonify(threads) @@ -225,10 +225,10 @@ class PrintPreviewServer(Thread): break if self.last_request_time is not None and \ - (time.time() - self.last_request_time) > 3: - self.stop() - break - except: + (time.time() - self.last_request_time) > 3: + self.stop() + break + except BaseException: # seems like sometimes this thread blows up during shutdown pass @@ -244,7 +244,7 @@ class PrintPreviewServer(Thread): while True: try: self.app.run(self.host, self.port, threaded=True) - except socket.error, e: + except socket.error as e: if e.errno == errno.EADDRINUSE: self.port += 1 continue @@ -265,11 +265,11 @@ class PrintInfoFrame(wx.Frame): text = wx.StaticText(panel, label=_("A print preview has been opened in your web browser. This window will stay open in order to communicate with the JavaScript code running in your browser.\n\nThis window will close after you close the print preview in your browser, or you can close it manually if necessary.")) font = wx.Font(14, wx.DEFAULT, wx.NORMAL, wx.NORMAL) text.SetFont(font) - sizer.Add(text, proportion=1, flag=wx.ALL|wx.EXPAND, border=20) + sizer.Add(text, proportion=1, flag=wx.ALL | wx.EXPAND, border=20) stop_button = wx.Button(panel, id=wx.ID_CLOSE) stop_button.Bind(wx.EVT_BUTTON, self.close_button_clicked) - sizer.Add(stop_button, proportion=0, flag=wx.ALIGN_CENTER|wx.ALL, border=10) + sizer.Add(stop_button, proportion=0, flag=wx.ALIGN_CENTER | wx.ALL, border=10) panel.SetSizer(sizer) panel.Layout() @@ -289,13 +289,13 @@ class PrintInfoFrame(wx.Frame): class Print(InkstitchExtension): def build_environment(self): - if getattr( sys, 'frozen', False ) : + if getattr(sys, 'frozen', False): template_dir = os.path.join(sys._MEIPASS, "print", "templates") else: template_dir = os.path.realpath(os.path.join(os.path.dirname(__file__), "..", "..", "print", "templates")) env = Environment( - loader = FileSystemLoader(template_dir), + loader=FileSystemLoader(template_dir), autoescape=select_autoescape(['html', 'xml']), extensions=['jinja2.ext.i18n'] ) @@ -308,8 +308,8 @@ class Print(InkstitchExtension): def strip_namespaces(self, svg): # namespace prefixes seem to trip up HTML, so get rid of them for element in svg.iter(): - if element.tag[0]=='{': - element.tag = element.tag[element.tag.index('}',1) + 1:] + if element.tag[0] == '{': + element.tag = element.tag[element.tag.index('}', 1) + 1:] def render_svgs(self, stitch_plan, realistic=False): svg = deepcopy(self.document).getroot() @@ -352,25 +352,25 @@ class Print(InkstitchExtension): template = env.get_template('index.html') return template.render( - view = {'client_overview': False, 'client_detailedview': False, 'operator_overview': True, 'operator_detailedview': True}, - logo = {'src' : '', 'title' : 'LOGO'}, - date = date.today(), - client = "", - job = { - 'title': '', - 'num_colors': stitch_plan.num_colors, - 'num_color_blocks': len(stitch_plan), - 'num_stops': stitch_plan.num_stops, - 'num_trims': stitch_plan.num_trims, - 'dimensions': stitch_plan.dimensions_mm, - 'num_stitches': stitch_plan.num_stitches, - 'estimated_time': '', # TODO - 'estimated_thread': '', # TODO - }, - svg_overview = overview_svg, - color_blocks = stitch_plan.color_blocks, - palettes = ThreadCatalog().palette_names(), - selected_palette = selected_palette, + view={'client_overview': False, 'client_detailedview': False, 'operator_overview': True, 'operator_detailedview': True}, + logo={'src': '', 'title': 'LOGO'}, + date=date.today(), + client="", + job={ + 'title': '', + 'num_colors': stitch_plan.num_colors, + 'num_color_blocks': len(stitch_plan), + 'num_stops': stitch_plan.num_stops, + 'num_trims': stitch_plan.num_trims, + 'dimensions': stitch_plan.dimensions_mm, + 'num_stitches': stitch_plan.num_stitches, + 'estimated_time': '', # TODO + 'estimated_thread': '', # TODO + }, + svg_overview=overview_svg, + color_blocks=stitch_plan.color_blocks, + palettes=ThreadCatalog().palette_names(), + selected_palette=selected_palette, ) def effect(self): @@ -396,12 +396,12 @@ class Print(InkstitchExtension): html = self.render_html(stitch_plan, overview_svg, palette) print_server = PrintPreviewServer( - html=html, - metadata=self.get_inkstitch_metadata(), - stitch_plan=stitch_plan, - realistic_overview_svg=realistic_overview_svg, - realistic_color_block_svgs=realistic_color_block_svgs - ) + html=html, + metadata=self.get_inkstitch_metadata(), + stitch_plan=stitch_plan, + realistic_overview_svg=realistic_overview_svg, + realistic_color_block_svgs=realistic_color_block_svgs + ) print_server.start() time.sleep(1) diff --git a/lib/i18n.py b/lib/i18n.py index 419c03dc0..045fa1b2b 100644 --- a/lib/i18n.py +++ b/lib/i18n.py @@ -9,8 +9,11 @@ locale_dir = None # Use N_ to mark a string for translation but _not_ immediately translate it. # reference: https://docs.python.org/3/library/gettext.html#deferred-translations # Makefile configures pybabel to treat N_() the same as _() + + def N_(message): return message + def _set_locale_dir(): global locale_dir @@ -22,11 +25,13 @@ def _set_locale_dir(): locale_dir = os.path.join(locale_dir, 'locales') + def localize(languages=None): global translation, _ translation = gettext.translation("inkstitch", locale_dir, fallback=True) _ = translation.gettext + _set_locale_dir() localize() diff --git a/lib/inx/generate.py b/lib/inx/generate.py index f9ed799bc..1cf347f2d 100644 --- a/lib/inx/generate.py +++ b/lib/inx/generate.py @@ -5,6 +5,7 @@ from .outputs import generate_output_inx_files from .extensions import generate_extension_inx_files from .utils import iterate_inx_locales, inx_path + def generate_inx_files(): for locale in iterate_inx_locales(): generate_input_inx_files() diff --git a/lib/inx/utils.py b/lib/inx/utils.py index 6103f360c..6670cfcb3 100644 --- a/lib/inx/utils.py +++ b/lib/inx/utils.py @@ -13,10 +13,11 @@ template_path = os.path.join(_top_path, "templates") current_translation = default_translation current_locale = "en_US" + def build_environment(): env = Environment( - loader = FileSystemLoader(template_path), - autoescape = True, + loader=FileSystemLoader(template_path), + autoescape=True, extensions=['jinja2.ext.i18n'] ) @@ -25,11 +26,13 @@ def build_environment(): return env + def write_inx_file(name, contents): inx_file_name = "inkstitch_%s_%s.inx" % (name, current_locale) with open(os.path.join(inx_path, inx_file_name), 'w') as inx_file: print >> inx_file, contents + def iterate_inx_locales(): global current_translation, current_locale diff --git a/lib/output.py b/lib/output.py index 0d7f9918c..eed665edf 100644 --- a/lib/output.py +++ b/lib/output.py @@ -19,6 +19,7 @@ def get_command(stitch): else: return pyembroidery.NEEDLE_AT + def _string_to_floats(string): floats = string.split(',') return [float(num) for num in floats] @@ -32,7 +33,7 @@ def get_origin(svg): all_guides = namedview.findall(inkex.addNS('guide', 'sodipodi')) label_attribute = inkex.addNS('label', 'inkscape') guides = [guide for guide in all_guides - if guide.get(label_attribute, "").startswith("embroidery origin")] + if guide.get(label_attribute, "").startswith("embroidery origin")] # document size used below doc_size = list(get_doc_size(svg)) @@ -57,7 +58,6 @@ def get_origin(svg): position = Point(*_string_to_floats(guide.get('position'))) position.y = doc_size[1] - position.y - # This one baffles me. I think inkscape might have gotten the order of # their vector wrong? parts = _string_to_floats(guide.get('orientation')) @@ -98,17 +98,17 @@ def write_embroidery_file(file_path, stitch_plan, svg): # also multiply by 10 to get tenths of a millimeter as required by pyembroidery scale = 10 / PIXELS_PER_MM - settings = { - # correct for the origin - "translate": -origin, + settings = { + # correct for the origin + "translate": -origin, - # convert from pixels to millimeters - # also multiply by 10 to get tenths of a millimeter as required by pyembroidery - "scale": (scale, scale), + # convert from pixels to millimeters + # also multiply by 10 to get tenths of a millimeter as required by pyembroidery + "scale": (scale, scale), - # This forces a jump at the start of the design and after each trim, - # even if we're close enough not to need one. - "full_jump": True, - } + # This forces a jump at the start of the design and after each trim, + # even if we're close enough not to need one. + "full_jump": True, + } pyembroidery.write(pattern, file_path, settings) diff --git a/lib/stitch_plan/stitch.py b/lib/stitch_plan/stitch.py index 5230efec4..5fe10fb84 100644 --- a/lib/stitch_plan/stitch.py +++ b/lib/stitch_plan/stitch.py @@ -15,15 +15,15 @@ class Stitch(Point): def __repr__(self): return "Stitch(%s, %s, %s, %s, %s, %s, %s, %s%s)" % (self.x, - self.y, - self.color, - "JUMP" if self.jump else " ", - "TRIM" if self.trim else " ", - "STOP" if self.stop else " ", - "NO TIES" if self.no_ties else " ", - "FAKE " if self.fake_color_change else "", - "COLOR CHANGE" if self.color_change else " " - ) + self.y, + self.color, + "JUMP" if self.jump else " ", + "TRIM" if self.trim else " ", + "STOP" if self.stop else " ", + "NO TIES" if self.no_ties else " ", + "FAKE " if self.fake_color_change else "", + "COLOR CHANGE" if self.color_change else " " + ) def copy(self): return Stitch(self.x, self.y, self.color, self.jump, self.stop, self.trim, self.color_change, self.no_ties) diff --git a/lib/stitches/auto_fill.py b/lib/stitches/auto_fill.py index 097ab1d92..e777d026b 100644 --- a/lib/stitches/auto_fill.py +++ b/lib/stitches/auto_fill.py @@ -15,6 +15,7 @@ from ..utils.geometry import Point as InkstitchPoint, cut class MaxQueueLengthExceeded(Exception): pass + class PathEdge(object): OUTLINE_KEYS = ("outline", "extra", "initial") SEGMENT_KEY = "segment" @@ -39,6 +40,7 @@ class PathEdge(object): def is_segment(self): return self.key == self.SEGMENT_KEY + def auto_fill(shape, angle, row_spacing, end_row_spacing, max_stitch_length, running_stitch_length, staggers, starting_point, ending_point=None): stitches = [] @@ -65,7 +67,7 @@ def which_outline(shape, coords): point = shapely.geometry.Point(*coords) outlines = enumerate(list(shape.boundary)) - closest = min(outlines, key=lambda (index, outline): outline.distance(point)) + closest = min(outlines, key=lambda index_outline: index_outline[1].distance(point)) return closest[0] @@ -129,11 +131,11 @@ def build_graph(shape, segments, angle, row_spacing): # Tag each node with its index and projection. graph.add_node(node, index=outline_index, projection=outline_projection) - nodes = list(graph.nodes(data=True)) # returns a list of tuples: [(node, {data}), (node, {data}) ...] + nodes = list(graph.nodes(data=True)) # returns a list of tuples: [(node, {data}), (node, {data}) ...] nodes.sort(key=lambda node: (node[1]['index'], node[1]['projection'])) for outline_index, nodes in groupby(nodes, key=lambda node: node[1]['index']): - nodes = [ node for node, data in nodes ] + nodes = [node for node, data in nodes] # heuristic: change the order I visit the nodes in the outline if necessary. # If the start and endpoints are in the same row, I can't tell which row @@ -163,7 +165,6 @@ def build_graph(shape, segments, angle, row_spacing): if i % 2 == edge_set: graph.add_edge(node1, node2, key="extra") - if not networkx.is_eulerian(graph): raise Exception(_("Unable to autofill. This most often happens because your shape is made up of multiple sections that aren't connected.")) @@ -193,13 +194,13 @@ def bfs_for_loop(graph, starting_node, max_queue_length=2000): # get a list of neighbors paired with the key of the edge I can follow to get there neighbors = [ - (node, key) - for node, adj in graph.adj[ending_node].iteritems() - for key in adj - ] + (node, key) + for node, adj in graph.adj[ending_node].iteritems() + for key in adj + ] # heuristic: try grating segments first - neighbors.sort(key=lambda (dest, key): key == "segment", reverse=True) + neighbors.sort(key=lambda dest_key: dest_key[1] == "segment", reverse=True) for next_node, key in neighbors: # skip if I've already followed this edge @@ -295,6 +296,7 @@ def insert_loop(path, loop): path[i:i] = loop + def nearest_node_on_outline(graph, point, outline_index=0): point = shapely.geometry.Point(*point) outline_nodes = [node for node, data in graph.nodes(data=True) if data['index'] == outline_index] @@ -302,16 +304,18 @@ def nearest_node_on_outline(graph, point, outline_index=0): return nearest + def get_outline_nodes(graph, outline_index=0): - outline_nodes = [(node, data['projection']) \ - for node, data \ - in graph.nodes(data=True) \ + outline_nodes = [(node, data['projection']) + for node, data + in graph.nodes(data=True) if data['index'] == outline_index] - outline_nodes.sort(key=lambda (node, projection): projection) + outline_nodes.sort(key=lambda node_projection: node_projection[1]) outline_nodes = [node for node, data in outline_nodes] return outline_nodes + def find_initial_path(graph, starting_point, ending_point=None): starting_node = nearest_node_on_outline(graph, starting_point) @@ -340,6 +344,7 @@ def find_initial_path(graph, starting_point, ending_point=None): return path + def find_stitch_path(graph, segments, starting_point=None, ending_point=None): """find a path that visits every grating segment exactly once diff --git a/lib/stitches/fill.py b/lib/stitches/fill.py index 14971cb47..ac8b52ee0 100644 --- a/lib/stitches/fill.py +++ b/lib/stitches/fill.py @@ -37,6 +37,7 @@ def adjust_stagger(stitch, angle, row_spacing, max_stitch_length, staggers): return stitch - offset * east(angle) + def stitch_row(stitches, beg, end, angle, row_spacing, max_stitch_length, staggers): # We want our stitches to look like this: # @@ -163,6 +164,7 @@ def intersect_region_with_grating(shape, angle, row_spacing, end_row_spacing=Non return rows + def section_to_stitches(group_of_segments, angle, row_spacing, max_stitch_length, staggers): stitches = [] first_segment = True diff --git a/lib/svg/path.py b/lib/svg/path.py index 0a8dcb74b..51100e38e 100644 --- a/lib/svg/path.py +++ b/lib/svg/path.py @@ -3,6 +3,7 @@ import cubicsuperpath from .units import get_viewbox_transform + def apply_transforms(path, node): transform = get_node_transform(node) @@ -11,6 +12,7 @@ def apply_transforms(path, node): return path + def get_node_transform(node): # start with the identity transform transform = [[1.0, 0.0, 0.0], [0.0, 1.0, 0.0]] @@ -26,6 +28,7 @@ def get_node_transform(node): return transform + def get_correction_transform(node, child=False): """Get a transform to apply to new siblings or children of this SVG node""" diff --git a/lib/svg/realistic_rendering.py b/lib/svg/realistic_rendering.py index e31534daf..5af7e9a62 100644 --- a/lib/svg/realistic_rendering.py +++ b/lib/svg/realistic_rendering.py @@ -102,6 +102,7 @@ realistic_filter = """ """ + def realistic_stitch(start, end): """Generate a stitch vector path given a start and end point.""" diff --git a/lib/svg/svg.py b/lib/svg/svg.py index 48b1343a2..b1cc91d91 100644 --- a/lib/svg/svg.py +++ b/lib/svg/svg.py @@ -1,4 +1,6 @@ -import simpletransform, simplestyle, inkex +import simpletransform +import simplestyle +import inkex from .units import get_viewbox_transform from .tags import SVG_GROUP_TAG, INKSCAPE_LABEL, INKSCAPE_GROUPMODE, SVG_PATH_TAG, SVG_DEFS_TAG @@ -11,13 +13,13 @@ def color_block_to_point_lists(color_block): point_lists = [[]] for stitch in color_block: - if stitch.trim: - if point_lists[-1]: - point_lists.append([]) - continue + if stitch.trim: + if point_lists[-1]: + point_lists.append([]) + continue - if not stitch.jump and not stitch.color_change: - point_lists[-1].append(stitch.as_tuple()) + if not stitch.jump and not stitch.color_change: + point_lists[-1].append(stitch.as_tuple()) return point_lists @@ -51,13 +53,14 @@ def color_block_to_realistic_stitches(color_block, svg): 'stroke': 'none', 'filter': 'url(#realistic-stitch-filter)' }), - 'd': realistic_stitch(start, point), - 'transform': get_correction_transform(svg) - })) + 'd': realistic_stitch(start, point), + 'transform': get_correction_transform(svg) + })) start = point return paths + def color_block_to_paths(color_block, svg): paths = [] # We could emit just a single path with one subpath per point list, but @@ -68,13 +71,13 @@ def color_block_to_paths(color_block, svg): SVG_PATH_TAG, {'style': simplestyle.formatStyle( {'stroke': color, - 'stroke-width': "0.4", - 'fill': 'none'}), - 'd': "M" + " ".join(" ".join(str(coord) for coord in point) for point in point_list), - 'transform': get_correction_transform(svg), - 'embroider_manual_stitch': 'true', - 'embroider_trim_after': 'true', - })) + 'stroke-width': "0.4", + 'fill': 'none'}), + 'd': "M" + " ".join(" ".join(str(coord) for coord in point) for point in point_list), + 'transform': get_correction_transform(svg), + 'embroider_manual_stitch': 'true', + 'embroider_trim_after': 'true', + })) # no need to trim at the end of a thread color if paths: @@ -82,6 +85,7 @@ def color_block_to_paths(color_block, svg): return paths + def render_stitch_plan(svg, stitch_plan, realistic=False): layer = svg.find(".//*[@id='__inkstitch_stitch_plan__']") if layer is None: diff --git a/lib/svg/units.py b/lib/svg/units.py index 126027bce..585afab45 100644 --- a/lib/svg/units.py +++ b/lib/svg/units.py @@ -6,8 +6,9 @@ from ..utils import cache PIXELS_PER_MM = 96 / 25.4 # cribbed from inkscape-silhouette -def parse_length_with_units( str ): + +def parse_length_with_units(str): ''' Parse an SVG value which may or may not have units attached This version is greatly simplified in that it only allows: no units, @@ -39,8 +40,8 @@ def parse_length_with_units( str ): u = '%' s = s[:-1] try: - v = float( s ) - except: + v = float(s) + except BaseException: raise ValueError(_("parseLengthWithUnits: unknown unit %s") % s) return v, u @@ -53,16 +54,16 @@ def convert_length(length): return value if units == 'pt': - value /= 72 - units = 'in' + value /= 72 + units = 'in' if units == 'pc': - value /= 6 - units = 'in' + value /= 6 + units = 'in' if units == 'cm': - value *= 10 - units = 'mm' + value *= 10 + units = 'mm' if units == 'mm': value = value / 25.4 @@ -75,6 +76,7 @@ def convert_length(length): raise ValueError(_("Unknown unit: %s") % units) + @cache def get_viewbox(svg): return svg.get('viewBox').strip().replace(',', ' ').split() @@ -96,6 +98,7 @@ def get_doc_size(svg): return doc_width, doc_height + @cache def get_viewbox_transform(node): # somewhat cribbed from inkscape-silhouette diff --git a/lib/threads/catalog.py b/lib/threads/catalog.py index d9981dc6a..ece2f8acb 100644 --- a/lib/threads/catalog.py +++ b/lib/threads/catalog.py @@ -85,8 +85,10 @@ class _ThreadCatalog(Sequence): if palette.name == name: return palette + _catalog = None + def ThreadCatalog(): """Singleton _ThreadCatalog factory""" diff --git a/lib/threads/color.py b/lib/threads/color.py index cc6c0c48f..8c596e444 100644 --- a/lib/threads/color.py +++ b/lib/threads/color.py @@ -3,6 +3,7 @@ import re import colorsys from pyembroidery.EmbThread import EmbThread + class ThreadColor(object): hex_str_re = re.compile('#([0-9a-z]{3}|[0-9a-z]{6})', re.I) diff --git a/lib/utils/cache.py b/lib/utils/cache.py index 38fe8f2c5..3a2636f22 100644 --- a/lib/utils/cache.py +++ b/lib/utils/cache.py @@ -4,5 +4,7 @@ except ImportError: from backports.functools_lru_cache import lru_cache # simplify use of lru_cache decorator + + def cache(*args, **kwargs): return lru_cache(maxsize=None)(*args, **kwargs) diff --git a/lib/utils/geometry.py b/lib/utils/geometry.py index bfdcd3c06..eb1a28fac 100644 --- a/lib/utils/geometry.py +++ b/lib/utils/geometry.py @@ -17,7 +17,7 @@ def cut(line, distance): last_point = p if traveled == distance: return [ - LineString(coords[:i+1]), + LineString(coords[:i + 1]), LineString(coords[i:])] if traveled > distance: cp = line.interpolate(distance) @@ -25,6 +25,7 @@ def cut(line, distance): LineString(coords[:i] + [(cp.x, cp.y)]), LineString([(cp.x, cp.y)] + coords[i:])] + def cut_path(points, length): """Return a subsection of at the start of the path that is length units long. diff --git a/lib/utils/inkscape.py b/lib/utils/inkscape.py index 2d0298bc3..a650da69c 100644 --- a/lib/utils/inkscape.py +++ b/lib/utils/inkscape.py @@ -1,6 +1,7 @@ from os.path import realpath, expanduser, join as path_join import sys + def guess_inkscape_config_path(): if getattr(sys, 'frozen', None): path = realpath(path_join(sys._MEIPASS, "..", "..", "..")) diff --git a/lib/utils/io.py b/lib/utils/io.py index e5a246f3a..f51f629c0 100644 --- a/lib/utils/io.py +++ b/lib/utils/io.py @@ -19,6 +19,8 @@ def restore_stderr(): # It's probably possible to generalize this code, but when I tried, # the result was incredibly unreadable. + + def save_stdout(): null = open(os.devnull, 'w') sys.stdout_dup = os.dup(sys.stdout.fileno()) diff --git a/messages.po b/messages.po index 074159c4d..a5abfb668 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-08-20 20:42-0400\n" +"POT-Creation-Date: 2018-08-21 20:32-0400\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -146,45 +146,45 @@ msgid "" "Negative angles are allowed." msgstr "" -#: lib/elements/fill.py:45 +#: lib/elements/fill.py:46 msgid "Flip fill (start right-to-left)" msgstr "" -#: lib/elements/fill.py:46 +#: lib/elements/fill.py:47 msgid "" "The flip option can help you with routing your stitch path. When you " "enable flip, stitching goes from right-to-left instead of left-to-right." msgstr "" -#: lib/elements/fill.py:54 +#: lib/elements/fill.py:55 msgid "Spacing between rows" msgstr "" -#: lib/elements/fill.py:55 +#: lib/elements/fill.py:56 msgid "Distance between rows of stitches." msgstr "" -#: lib/elements/fill.py:68 +#: lib/elements/fill.py:69 msgid "Maximum fill stitch length" msgstr "" -#: lib/elements/fill.py:69 +#: lib/elements/fill.py:70 msgid "" "The length of each stitch in a row. Shorter stitch may be used at the " "start or end of a row." msgstr "" -#: lib/elements/fill.py:78 +#: lib/elements/fill.py:79 msgid "Stagger rows this many times before repeating" msgstr "" -#: lib/elements/fill.py:79 +#: lib/elements/fill.py:80 msgid "" "Setting this dictates how many rows apart the stitches will be before " "they fall in the same column position." msgstr "" -#: lib/elements/fill.py:112 +#: lib/elements/fill.py:113 #, python-format msgid "" "shape %s is so small that it cannot be filled with stitches. Please make" @@ -203,7 +203,7 @@ msgstr "" msgid "\"E\" stitch" msgstr "" -#: lib/elements/satin_column.py:32 lib/elements/stroke.py:52 +#: lib/elements/satin_column.py:32 lib/elements/stroke.py:53 msgid "Zig-zag spacing (peak-to-peak)" msgstr "" @@ -211,74 +211,74 @@ msgstr "" msgid "Peak-to-peak distance between zig-zags." msgstr "" -#: lib/elements/satin_column.py:43 +#: lib/elements/satin_column.py:44 msgid "Pull compensation" msgstr "" -#: lib/elements/satin_column.py:44 +#: lib/elements/satin_column.py:45 msgid "" "Satin stitches pull the fabric together, resulting in a column narrower " "than you draw in Inkscape. This setting expands each pair of needle " "penetrations outward from the center of the satin column." msgstr "" -#: lib/elements/satin_column.py:55 +#: lib/elements/satin_column.py:56 msgid "Contour underlay" msgstr "" -#: lib/elements/satin_column.py:55 lib/elements/satin_column.py:62 -#: lib/elements/satin_column.py:71 +#: lib/elements/satin_column.py:56 lib/elements/satin_column.py:63 +#: lib/elements/satin_column.py:72 msgid "Contour Underlay" msgstr "" -#: lib/elements/satin_column.py:62 lib/elements/satin_column.py:86 +#: lib/elements/satin_column.py:63 lib/elements/satin_column.py:87 msgid "Stitch length" msgstr "" -#: lib/elements/satin_column.py:68 +#: lib/elements/satin_column.py:69 msgid "Contour underlay inset amount" msgstr "" -#: lib/elements/satin_column.py:69 +#: lib/elements/satin_column.py:70 msgid "" "Shrink the outline, to prevent the underlay from showing around the " "outside of the satin column." msgstr "" -#: lib/elements/satin_column.py:79 +#: lib/elements/satin_column.py:80 msgid "Center-walk underlay" msgstr "" -#: lib/elements/satin_column.py:79 lib/elements/satin_column.py:86 +#: lib/elements/satin_column.py:80 lib/elements/satin_column.py:87 msgid "Center-Walk Underlay" msgstr "" -#: lib/elements/satin_column.py:91 +#: lib/elements/satin_column.py:92 msgid "Zig-zag underlay" msgstr "" -#: lib/elements/satin_column.py:91 lib/elements/satin_column.py:100 -#: lib/elements/satin_column.py:111 +#: lib/elements/satin_column.py:92 lib/elements/satin_column.py:101 +#: lib/elements/satin_column.py:112 msgid "Zig-zag Underlay" msgstr "" -#: lib/elements/satin_column.py:97 +#: lib/elements/satin_column.py:98 msgid "Zig-Zag spacing (peak-to-peak)" msgstr "" -#: lib/elements/satin_column.py:98 +#: lib/elements/satin_column.py:99 msgid "Distance between peaks of the zig-zags." msgstr "" -#: lib/elements/satin_column.py:108 +#: lib/elements/satin_column.py:109 msgid "Inset amount" msgstr "" -#: lib/elements/satin_column.py:109 +#: lib/elements/satin_column.py:110 msgid "default: half of contour underlay inset" msgstr "" -#: lib/elements/satin_column.py:146 +#: lib/elements/satin_column.py:147 #, python-format msgid "satin column: %(id)s: at least two subpaths required (%(num)d found)" msgstr "" @@ -293,22 +293,22 @@ msgstr "" msgid "satin column: One or more of the rungs doesn't intersect both rails." msgstr "" -#: lib/elements/satin_column.py:179 lib/elements/satin_column.py:181 +#: lib/elements/satin_column.py:180 lib/elements/satin_column.py:183 msgid "Each rail should intersect both rungs once." msgstr "" -#: lib/elements/satin_column.py:181 +#: lib/elements/satin_column.py:182 msgid "" "satin column: One or more of the rungs intersects the rails more than " "once." msgstr "" -#: lib/elements/satin_column.py:222 +#: lib/elements/satin_column.py:223 #, python-format msgid "satin column: object %s has a fill (but should not)" msgstr "" -#: lib/elements/satin_column.py:226 +#: lib/elements/satin_column.py:227 #, python-format msgid "" "satin column: object %(id)s has two paths with an unequal number of " @@ -327,40 +327,40 @@ msgstr "" msgid "Length of stitches in running stitch mode." msgstr "" -#: lib/elements/stroke.py:42 +#: lib/elements/stroke.py:43 msgid "Bean stitch number of repeats" msgstr "" -#: lib/elements/stroke.py:43 +#: lib/elements/stroke.py:44 msgid "" "Backtrack each stitch this many times. A value of 1 would triple each " "stitch (forward, back, forward). A value of 2 would quintuple each " "stitch, etc. Only applies to running stitch." msgstr "" -#: lib/elements/stroke.py:53 +#: lib/elements/stroke.py:54 msgid "Length of stitches in zig-zag mode." msgstr "" -#: lib/elements/stroke.py:64 +#: lib/elements/stroke.py:65 msgid "Repeats" msgstr "" -#: lib/elements/stroke.py:65 +#: lib/elements/stroke.py:66 msgid "Defines how many times to run down and back along the path." msgstr "" -#: lib/elements/stroke.py:89 +#: lib/elements/stroke.py:90 msgid "Manual stitch placement" msgstr "" -#: lib/elements/stroke.py:90 +#: lib/elements/stroke.py:91 msgid "" "Stitch every node in the path. Stitch length and zig-zag spacing are " "ignored." msgstr "" -#: lib/elements/stroke.py:124 +#: lib/elements/stroke.py:125 msgid "" "Legacy running stitch setting detected!\n" "\n" @@ -391,7 +391,7 @@ msgstr "" msgid "Only simple lines may be converted to satin columns." msgstr "" -#: lib/extensions/convert_to_satin.py:54 +#: lib/extensions/convert_to_satin.py:55 #, python-format msgid "" "Cannot convert %s to a satin column because it intersects itself. Try " @@ -405,7 +405,7 @@ msgid "" "Seeing a 'no such option' message? Please restart Inkscape to fix." msgstr "" -#: lib/extensions/flip.py:35 +#: lib/extensions/flip.py:36 msgid "Please select one or more satin columns to flip." msgstr "" @@ -420,37 +420,37 @@ msgstr "" msgid "thread manufacturer color palettes" msgstr "" -#: lib/extensions/install.py:32 +#: lib/extensions/install.py:31 msgid "Ink/Stitch visual commands (Object -> Symbols...)" msgstr "" -#: lib/extensions/install.py:41 +#: lib/extensions/install.py:40 msgid "Install" msgstr "" -#: lib/extensions/install.py:44 lib/extensions/params.py:380 +#: lib/extensions/install.py:43 lib/extensions/params.py:380 msgid "Cancel" msgstr "" -#: lib/extensions/install.py:58 +#: lib/extensions/install.py:57 msgid "Choose Inkscape directory" msgstr "" -#: lib/extensions/install.py:68 +#: lib/extensions/install.py:67 msgid "Inkscape add-on installation failed" msgstr "" -#: lib/extensions/install.py:69 +#: lib/extensions/install.py:68 msgid "Installation Failed" msgstr "" -#: lib/extensions/install.py:73 +#: lib/extensions/install.py:72 msgid "" "Inkscape add-on files have been installed. Please restart Inkscape to " "load the new add-ons." msgstr "" -#: lib/extensions/install.py:74 +#: lib/extensions/install.py:73 msgid "Installation Completed" msgstr "" @@ -611,7 +611,7 @@ msgstr "" #. If you translate this string, that will tell Ink/Stitch to #. generate menu items for this language in Inkscape's "Extensions" #. menu. -#: lib/inx/utils.py:43 +#: lib/inx/utils.py:46 msgid "Generate INX files" msgstr "" @@ -663,28 +663,28 @@ msgstr "" msgid "Stitch #" msgstr "" -#: lib/stitches/auto_fill.py:168 +#: lib/stitches/auto_fill.py:169 msgid "" "Unable to autofill. This most often happens because your shape is made " "up of multiple sections that aren't connected." msgstr "" -#: lib/stitches/auto_fill.py:393 +#: lib/stitches/auto_fill.py:398 msgid "" "Unexpected error while generating fill stitches. Please send your SVG " "file to lexelby@github." msgstr "" -#: lib/svg/svg.py:90 +#: lib/svg/svg.py:94 msgid "Stitch Plan" msgstr "" -#: lib/svg/units.py:44 +#: lib/svg/units.py:45 #, python-format msgid "parseLengthWithUnits: unknown unit %s" msgstr "" -#: lib/svg/units.py:76 +#: lib/svg/units.py:77 #, python-format msgid "Unknown unit: %s" msgstr "" diff --git a/stub.py b/stub.py index 9c316b997..6daaf5ae8 100644 --- a/stub.py +++ b/stub.py @@ -34,7 +34,7 @@ args[0] = binary_path try: extension = subprocess.Popen(args, stdout=subprocess.PIPE, stderr=subprocess.PIPE) stdout, stderr = extension.communicate() -except: +except BaseException: print >> sys.stderr, "Unexpected error launching Ink/Stitch." print >> sys.stderr, "If you're having trouble, please file an issue here, including the text below: https://github.com/inkstitch/inkstitch/issues\n" print >> sys.stderr, "Tried to launch:", binary_path