From 9249a3ae7730e62cdff282a33e989c1da5d00411 Mon Sep 17 00:00:00 2001 From: Lex Neva Date: Sat, 29 Oct 2016 13:28:37 -0400 Subject: [PATCH] pep8 fixes --- PyEmb.py | 161 ++++++++++++---------- embroider.py | 318 +++++++++++++++++++++++--------------------- embroider_params.py | 6 +- 3 files changed, 255 insertions(+), 230 deletions(-) diff --git a/PyEmb.py b/PyEmb.py index 5ebbf0f38..585cbaf72 100644 --- a/PyEmb.py +++ b/PyEmb.py @@ -1,24 +1,25 @@ -#!python -#!/usr/bin/python +#!/usr/bin/env python # http://www.achatina.de/sewing/main/TECHNICL.HTM import math import sys from copy import deepcopy + class Point: + def __init__(self, x, y): self.x = x self.y = y def __add__(self, other): - return Point(self.x+other.x, self.y+other.y) + return Point(self.x + other.x, self.y + other.y) def __sub__(self, other): - return Point(self.x-other.x, self.y-other.y) + return Point(self.x - other.x, self.y - other.y) def mul(self, scalar): - return Point(self.x*scalar, self.y*scalar) + return Point(self.x * scalar, self.y * scalar) def __mul__(self, other): if isinstance(other, Point): @@ -36,13 +37,13 @@ class Point: raise ValueError("cannot multiply Point by %s" % type(other)) def __repr__(self): - return "Pt(%s,%s)" % (self.x,self.y) + return "Pt(%s,%s)" % (self.x, self.y) def length(self): - return math.sqrt(math.pow(self.x,2.0)+math.pow(self.y,2.0)) + return math.sqrt(math.pow(self.x, 2.0) + math.pow(self.y, 2.0)) def unit(self): - return self.mul(1.0/self.length()) + return self.mul(1.0 / self.length()) def rotate_left(self): return Point(-self.y, self.x) @@ -54,36 +55,40 @@ class Point: return Point(int(round(self.x)), int(round(self.y))) def as_tuple(self): - return (self.x,self.y) + return (self.x, self.y) def __cmp__(self, other): return cmp(self.as_tuple(), other.as_tuple()) + class Stitch(Point): - def __init__(self, x, y, color=None, jumpStitch=False): + + def __init__(self, x, y, color=None, jump_stitch=False): Point.__init__(self, x, y) self.color = color - self.jumpStitch = jumpStitch + self.jump_stitch = jump_stitch + class Embroidery: + def __init__(self, stitches, pixels_per_millimeter=1): self.stitches = deepcopy(stitches) - self.scale(1.0/pixels_per_millimeter) + self.scale(1.0 / pixels_per_millimeter) self.scale((1, -1)) self.translate_to_origin() def translate_to_origin(self): - if (len(self.stitches)==0): + if (len(self.stitches) == 0): return - (maxx,maxy) = (self.stitches[0].x,self.stitches[0].y) - (minx,miny) = (self.stitches[0].x,self.stitches[0].y) + (maxx, maxy) = (self.stitches[0].x, self.stitches[0].y) + (minx, miny) = (self.stitches[0].x, self.stitches[0].y) for p in self.stitches: - minx = min(minx,p.x) - miny = min(miny,p.y) - maxx = max(maxx,p.x) - maxy = max(maxy,p.y) - sx = maxx-minx - sy = maxy-miny + minx = min(minx, p.x) + miny = min(miny, p.y) + maxx = max(maxx, p.x) + maxy = max(maxy, p.y) + sx = maxx - minx + sy = maxy - miny self.translate(-minx, -miny) return (minx, miny) @@ -102,39 +107,39 @@ class Embroidery: def export_ksm(self): str = "" - self.pos = Point(0,0) + self.pos = Point(0, 0) lastColor = None for stitch in self.stitches: - if (lastColor!=None and stitch.color!=lastColor): + if (lastColor is not None and stitch.color != lastColor): mode_byte = 0x99 - #dbg.write("Color change!\n") + # dbg.write("Color change!\n") else: mode_byte = 0x80 - #dbg.write("color still %s\n" % stitch.color) + # dbg.write("color still %s\n" % stitch.color) lastColor = stitch.color new_int = stitch.as_int() old_int = self.pos.as_int() delta = new_int - old_int - assert(abs(delta.x)<=127) - assert(abs(delta.y)<=127) - str+=chr(abs(delta.y)) - str+=chr(abs(delta.x)) - if (delta.y<0): + assert(abs(delta.x) <= 127) + assert(abs(delta.y) <= 127) + str += chr(abs(delta.y)) + str += chr(abs(delta.x)) + if (delta.y < 0): mode_byte |= 0x20 - if (delta.x<0): + if (delta.x < 0): mode_byte |= 0x40 - str+=chr(mode_byte) + str += chr(mode_byte) self.pos = stitch return str def export_melco(self): self.str = "" self.pos = self.stitches[0] - #dbg.write("stitch count: %d\n" % len(self.stitches)) + # dbg.write("stitch count: %d\n" % len(self.stitches)) lastColor = None numColors = 0x0 for stitch in self.stitches[1:]: - if (lastColor!=None and stitch.color!=lastColor): + if (lastColor is not None and stitch.color != lastColor): numColors += 1 # color change self.str += chr(0x80) @@ -147,26 +152,28 @@ class Embroidery: old_int = self.pos.as_int() delta = new_int - old_int - def move(x,y): - if (x<0): x = x + 256 - self.str+=chr(x) - if (y<0): y = y + 256 - self.str+=chr(y) + def move(x, y): + if (x < 0): + x = x + 256 + self.str += chr(x) + if (y < 0): + y = y + 256 + self.str += chr(y) - while (delta.x!=0 or delta.y!=0): + while (delta.x != 0 or delta.y != 0): def clamp(v): - if (v>127): + if (v > 127): v = 127 - if (v<-127): + if (v < -127): v = -127 return v dx = clamp(delta.x) dy = clamp(delta.y) - move(dx,dy) + move(dx, dy) delta.x -= dx delta.y -= dy - #dbg.write("Stitch: %s delta %s\n" % (stitch, delta)) + # dbg.write("Stitch: %s delta %s\n" % (stitch, delta)) self.pos = stitch return self.str @@ -187,7 +194,7 @@ class Embroidery: int(stitch.color[1:3], 16), int(stitch.color[3:5], 16), int(stitch.color[5:7], 16)) - if stitch.jumpStitch: + if stitch.jump_stitch: self.str += '"*","JUMP","%f","%f"\n' % (stitch.x, stitch.y) self.str += '"*","STITCH","%f","%f"\n' % (stitch.x, stitch.y) lastStitch = stitch @@ -211,44 +218,48 @@ class Embroidery: if format == "melco": fp.write(self.export_melco()) elif format == "csv": - fp.write(self.export_csv()) + fp.write(self.export_csv()) elif format == "gcode": - fp.write(self.export_gcode()) + fp.write(self.export_gcode()) fp.close() + class Test: + def __init__(self): emb = Embroidery() - for x in range(0,301,30): - emb.addStitch(Point(x, 0)); - emb.addStitch(Point(x, 15)); - emb.addStitch(Point(x, 0)); + for x in range(0, 301, 30): + emb.addStitch(Point(x, 0)) + emb.addStitch(Point(x, 15)) + emb.addStitch(Point(x, 0)) - for x in range(300,-1,-30): - emb.addStitch(Point(x, -12)); - emb.addStitch(Point(x, -27)); - emb.addStitch(Point(x, -12)); + for x in range(300, -1, -30): + emb.addStitch(Point(x, -12)) + emb.addStitch(Point(x, -27)) + emb.addStitch(Point(x, -12)) fp = open("test.exp", "wb") fp.write(emb.export_melco()) fp.close() + class Turtle: + def __init__(self): self.emb = Embroidery() - self.pos = Point(0.0,0.0) - self.dir = Point(1.0,0.0) + self.pos = Point(0.0, 0.0) + self.dir = Point(1.0, 0.0) self.emb.addStitch(self.pos) def forward(self, dist): - self.pos = self.pos+self.dir.mul(dist) + self.pos = self.pos + self.dir.mul(dist) self.emb.addStitch(self.pos) def turn(self, degreesccw): - radcw = -degreesccw/180.0*3.141592653589 + radcw = -degreesccw / 180.0 * 3.141592653589 self.dir = Point( - math.cos(radcw)*self.dir.x-math.sin(radcw)*self.dir.y, - math.sin(radcw)*self.dir.x+math.cos(radcw)*self.dir.y) + math.cos(radcw) * self.dir.x - math.sin(radcw) * self.dir.y, + math.sin(radcw) * self.dir.x + math.cos(radcw) * self.dir.y) def right(self, degreesccw): self.turn(degreesccw) @@ -256,7 +267,9 @@ class Turtle: def left(self, degreesccw): self.turn(-degreesccw) + class Koch(Turtle): + def __init__(self, depth): Turtle.__init__(self) @@ -270,18 +283,20 @@ class Koch(Turtle): fp.close() def edge(self, depth, dist): - if (depth==0): + if (depth == 0): self.forward(dist) else: - self.edge(depth-1, dist/3.0) + self.edge(depth - 1, dist / 3.0) self.turn(-60.0) - self.edge(depth-1, dist/3.0) + self.edge(depth - 1, dist / 3.0) self.turn(120.0) - self.edge(depth-1, dist/3.0) + self.edge(depth - 1, dist / 3.0) self.turn(-60.0) - self.edge(depth-1, dist/3.0) + self.edge(depth - 1, dist / 3.0) + class Hilbert(Turtle): + def __init__(self, level): Turtle.__init__(self) @@ -294,20 +309,20 @@ class Hilbert(Turtle): # http://en.wikipedia.org/wiki/Hilbert_curve#Python def hilbert(self, level, angle): - if (level==0): + if (level == 0): return self.right(angle) - self.hilbert(level-1, -angle) + self.hilbert(level - 1, -angle) self.forward(self.size) self.left(angle) - self.hilbert(level-1, angle) + self.hilbert(level - 1, angle) self.forward(self.size) - self.hilbert(level-1, angle) + self.hilbert(level - 1, angle) self.left(angle) self.forward(self.size) - self.hilbert(level-1, -angle) + self.hilbert(level - 1, -angle) self.right(angle) -if (__name__=='__main__'): - #Koch(4) +if (__name__ == '__main__'): + # Koch(4) Hilbert(6) diff --git a/embroider.py b/embroider.py index 9a527d681..aed5007b6 100644 --- a/embroider.py +++ b/embroider.py @@ -45,12 +45,14 @@ PyEmb.dbg = dbg # a 0.5pt stroke becomes a straight line. STROKE_MIN = 0.5 + def parse_boolean(s): if isinstance(s, bool): return s else: return s and (s.lower() in ('yes', 'y', 'true', 't', '1')) + def get_param(node, param, default): value = node.get("embroider_" + param) @@ -59,11 +61,13 @@ def get_param(node, param, default): return value.strip() + def get_boolean_param(node, param, default=False): value = get_param(node, param, default) return parse_boolean(value) + def get_float_param(node, param, default=None): value = get_param(node, param, default) @@ -72,6 +76,7 @@ def get_float_param(node, param, default=None): except ValueError: return default + def get_int_param(node, param, default=None): value = get_param(node, param, default) @@ -80,6 +85,7 @@ def get_int_param(node, param, default=None): except ValueError: return default + def parse_path(node): path = cubicsuperpath.parsePath(node.get("d")) @@ -96,6 +102,7 @@ def parse_path(node): return path + def flatten(path, flatness): """approximate a path containing beziers with a series of points""" @@ -113,16 +120,17 @@ def flatten(path, flatness): return flattened + def csp_to_shapely_polygon(path): poly_ary = [] for sub_path in path: point_ary = [] last_pt = None for pt in sub_path: - if (last_pt!=None): - vp = (pt[0]-last_pt[0],pt[1]-last_pt[1]) - dp = math.sqrt(math.pow(vp[0],2.0)+math.pow(vp[1],2.0)) - #dbg.write("dp %s\n" % dp) + if (last_pt is not None): + vp = (pt[0] - last_pt[0], pt[1] - last_pt[1]) + dp = math.sqrt(math.pow(vp[0], 2.0) + math.pow(vp[1], 2.0)) + # dbg.write("dp %s\n" % dp) if (dp > 0.01): # I think too-close points confuse shapely. point_ary.append(pt) @@ -137,11 +145,12 @@ def csp_to_shapely_polygon(path): poly_ary.sort(key=lambda point_list: shgeo.Polygon(point_list).area, reverse=True) polygon = shgeo.MultiPolygon([(poly_ary[0], poly_ary[1:])]) - #print >> sys.stderr, "polygon valid:", polygon.is_valid + # print >> sys.stderr, "polygon valid:", polygon.is_valid return polygon class Patch: + def __init__(self, color=None, stitches=None): self.color = color self.stitches = stitches or [] @@ -152,7 +161,7 @@ class Patch: else: raise TypeError("Patch can only be added to another Patch") - def addStitch(self, stitch): + def add_stitch(self, stitch): self.stitches.append(stitch) def reverse(self): @@ -162,53 +171,53 @@ class Patch: def patches_to_stitches(patch_list, collapse_len_px=0): stitches = [] - lastStitch = None - lastColor = None + last_stitch = None + last_color = None for patch in patch_list: - jumpStitch = True + jump_stitch = True for stitch in patch.stitches: - if lastStitch and lastColor == patch.color: - l = (stitch - lastStitch).length() + if last_stitch and last_color == patch.color: + l = (stitch - last_stitch).length() if l <= 0.1: # filter out duplicate successive stitches - jumpStitch = False + jump_stitch = False continue - if jumpStitch: + if jump_stitch: # consider collapsing jump stitch, if it is pretty short if l < collapse_len_px: - #dbg.write("... collapsed\n") - jumpStitch = False + # dbg.write("... collapsed\n") + jump_stitch = False - #dbg.write("stitch color %s\n" % patch.color) + # dbg.write("stitch color %s\n" % patch.color) - newStitch = PyEmb.Stitch(stitch.x, stitch.y, patch.color, jumpStitch) + newStitch = PyEmb.Stitch(stitch.x, stitch.y, patch.color, jump_stitch) stitches.append(newStitch) - jumpStitch = False - lastStitch = stitch - lastColor = patch.color + jump_stitch = False + last_stitch = stitch + last_color = patch.color return stitches def stitches_to_paths(stitches): paths = [] - lastColor = None - lastStitch = None + last_color = None + last_stitch = None for stitch in stitches: - if stitch.jumpStitch: - if lastColor == stitch.color: + if stitch.jump_stitch: + if last_color == stitch.color: paths.append([None, []]) - if lastStitch is not None: - paths[-1][1].append(['M', lastStitch.as_tuple()]) + if last_stitch is not None: + paths[-1][1].append(['M', last_stitch.as_tuple()]) paths[-1][1].append(['L', stitch.as_tuple()]) - lastColor = None - if stitch.color != lastColor: + last_color = None + if stitch.color != last_color: paths.append([stitch.color, []]) paths[-1][1].append(['L' if len(paths[-1][1]) > 0 else 'M', stitch.as_tuple()]) - lastColor = stitch.color - lastStitch = stitch + last_color = stitch.color + last_stitch = stitch return paths @@ -216,69 +225,70 @@ def emit_inkscape(parent, stitches): for color, path in stitches_to_paths(stitches): dbg.write('path: %s %s\n' % (color, repr(path))) inkex.etree.SubElement(parent, - inkex.addNS('path', 'svg'), - { 'style':simplestyle.formatStyle( - { 'stroke': color if color is not None else '#000000', - 'stroke-width':"0.4", - 'fill': 'none' }), - 'd':simplepath.formatPath(path), - }) + inkex.addNS('path', 'svg'), + {'style': simplestyle.formatStyle( + {'stroke': color if color is not None else '#000000', + 'stroke-width': "0.4", + 'fill': 'none'}), + 'd': simplepath.formatPath(path), + }) class Embroider(inkex.Effect): + def __init__(self, *args, **kwargs): - #dbg.write("args: %s\n" % repr(sys.argv)) + # dbg.write("args: %s\n" % repr(sys.argv)) inkex.Effect.__init__(self) self.OptionParser.add_option("-r", "--row_spacing_mm", - action="store", type="float", - dest="row_spacing_mm", default=0.4, - help="row spacing (mm)") + action="store", type="float", + dest="row_spacing_mm", default=0.4, + help="row spacing (mm)") self.OptionParser.add_option("-z", "--zigzag_spacing_mm", - action="store", type="float", - dest="zigzag_spacing_mm", default=1.0, - help="zigzag spacing (mm)") + action="store", type="float", + dest="zigzag_spacing_mm", default=1.0, + help="zigzag spacing (mm)") self.OptionParser.add_option("-l", "--max_stitch_len_mm", - action="store", type="float", - dest="max_stitch_len_mm", default=3.0, - help="max stitch length (mm)") + action="store", type="float", + dest="max_stitch_len_mm", default=3.0, + help="max stitch length (mm)") self.OptionParser.add_option("--running_stitch_len_mm", - action="store", type="float", - dest="running_stitch_len_mm", default=3.0, - help="running stitch length (mm)") + action="store", type="float", + dest="running_stitch_len_mm", default=3.0, + help="running stitch length (mm)") self.OptionParser.add_option("-c", "--collapse_len_mm", - action="store", type="float", - dest="collapse_len_mm", default=0.0, - help="max collapse length (mm)") + action="store", type="float", + dest="collapse_len_mm", default=0.0, + help="max collapse length (mm)") self.OptionParser.add_option("-f", "--flatness", - action="store", type="float", - dest="flat", default=0.1, - help="Minimum flatness of the subdivided curves") + action="store", type="float", + dest="flat", default=0.1, + help="Minimum flatness of the subdivided curves") self.OptionParser.add_option("--hide_layers", - action="store", type="choice", - choices=["true","false"], - dest="hide_layers", default="true", - help="Hide all other layers when the embroidery layer is generated") + action="store", type="choice", + choices=["true", "false"], + dest="hide_layers", default="true", + help="Hide all other layers when the embroidery layer is generated") self.OptionParser.add_option("-O", "--output_format", - action="store", type="choice", - choices=["melco", "csv", "gcode"], - dest="output_format", default="melco", - help="File output format") + action="store", type="choice", + choices=["melco", "csv", "gcode"], + dest="output_format", default="melco", + help="File output format") self.OptionParser.add_option("-P", "--path", - action="store", type="string", - dest="path", default=".", - help="Directory in which to store output file") + action="store", type="string", + dest="path", default=".", + help="Directory in which to store output file") self.OptionParser.add_option("-b", "--max-backups", - action="store", type="int", - dest="max_backups", default=5, - help="Max number of backups of output files to keep.") + action="store", type="int", + dest="max_backups", default=5, + help="Max number of backups of output files to keep.") self.OptionParser.add_option("-p", "--pixels_per_mm", - action="store", type="int", - dest="pixels_per_millimeter", default=10, - help="Number of on-screen pixels per millimeter.") + action="store", type="int", + dest="pixels_per_millimeter", default=10, + help="Number of on-screen pixels per millimeter.") self.patches = [] def process_one_path(self, node, shpath, threadcolor, angle): - #self.add_shapely_geo_to_svg(shpath.boundary, color="#c0c000") + # self.add_shapely_geo_to_svg(shpath.boundary, color="#c0c000") flip = get_boolean_param(node, "flip", False) row_spacing_px = get_float_param(node, "row_spacing", self.options.row_spacing_mm) * self.options.pixels_per_millimeter @@ -287,11 +297,11 @@ class Embroider(inkex.Effect): rows_of_segments = self.intersect_region_with_grating(shpath, row_spacing_px, angle, flip) groups_of_segments = self.pull_runs(rows_of_segments, shpath, row_spacing_px) - + # "east" is the name of the direction that is to the right along a row east = PyEmb.Point(1, 0).rotate(-angle) - #print >> sys.stderr, len(groups_of_segments) + # print >> sys.stderr, len(groups_of_segments) patches = [] for group_of_segments in groups_of_segments: @@ -302,7 +312,7 @@ class Embroider(inkex.Effect): for segment in group_of_segments: # We want our stitches to look like this: - # + # # ---*-----------*----------- # ------*-----------*-------- # ---------*-----------*----- @@ -324,7 +334,7 @@ class Embroider(inkex.Effect): (beg, end) = segment if (swap): - (beg,end)=(end,beg) + (beg, end) = (end, beg) beg = PyEmb.Point(*beg) end = PyEmb.Point(*end) @@ -335,7 +345,7 @@ class Embroider(inkex.Effect): # only stitch the first point if it's a reasonable distance away from the # last stitch if last_end is None or (beg - last_end).length() > 0.5 * self.options.pixels_per_millimeter: - patch.addStitch(beg) + patch.add_stitch(beg) # Now, imagine the coordinate axes rotated by 'angle' degrees, such that # the rows are parallel to the X axis. We can find the coordinates in these @@ -357,11 +367,11 @@ class Embroider(inkex.Effect): offset = (first_stitch - beg).length() while offset < segment_length: - patch.addStitch(beg + offset * row_direction) + patch.add_stitch(beg + offset * row_direction) offset += max_stitch_len_px if (end - patch.stitches[-1]).length() > 0.1 * self.options.pixels_per_millimeter: - patch.addStitch(end) + patch.add_stitch(end) last_end = end swap = not swap @@ -383,7 +393,7 @@ class Embroider(inkex.Effect): direction = PyEmb.Point(1, 0).rotate(-angle) # and get a normal vector - normal = direction.rotate(math.pi/2) + normal = direction.rotate(math.pi / 2) # I'll start from the center, move in the normal direction some amount, # and then walk left and right half_length in each direction to create @@ -395,7 +405,7 @@ class Embroider(inkex.Effect): # angle degrees clockwise and ask for the new bounding box. The max # and min y tell me how far to go. - _, start, _, end = affinity.rotate(shpath, angle, origin='center', use_radians = True).bounds + _, start, _, end = affinity.rotate(shpath, angle, origin='center', use_radians=True).bounds # convert start and end to be relative to center (simplifies things later) start -= center.y @@ -450,7 +460,7 @@ class Embroider(inkex.Effect): # start a new patch. # Segments more than this far apart are considered not to be part of - # the same run. + # the same run. row_distance_cutoff = row_spacing_px * 1.1 def make_quadrilateral(segment1, segment2): @@ -470,10 +480,10 @@ class Embroider(inkex.Effect): return (intersection_area / quad_area) >= 0.9 - #for row in rows: + # for row in rows: # print >> sys.stderr, len(row) - #print >>sys.stderr, "\n".join(str(len(row)) for row in rows) + # print >>sys.stderr, "\n".join(str(len(row)) for row in rows) runs = [] count = 0 @@ -488,13 +498,13 @@ class Embroider(inkex.Effect): # TODO: only accept actually adjacent rows here if prev is not None and not is_same_run(prev, first): break - + run.append(first) prev = first rows[row_num] = rest - #print >> sys.stderr, len(run) + # print >> sys.stderr, len(run) runs.append(run) rows = [row for row in rows if len(row) > 0] @@ -515,7 +525,7 @@ class Embroider(inkex.Effect): if node.tag != self.svgpath: return - #dbg.write("Node: %s\n"%str((id, etree.tostring(node, pretty_print=True)))) + # dbg.write("Node: %s\n"%str((id, etree.tostring(node, pretty_print=True)))) if get_boolean_param(node, "satin_column"): self.patch_list.extend(self.satin_column(node)) @@ -523,9 +533,9 @@ class Embroider(inkex.Effect): stroke = [] fill = [] - if (self.get_style(node, "stroke")!=None): + if (self.get_style(node, "stroke") is not None): stroke = self.path_to_patch_list(node) - if (self.get_style(node, "fill")!=None): + if (self.get_style(node, "fill") is not None): fill = self.filled_region_to_patchlist(node) if get_boolean_param(node, "stroke_first", False): @@ -540,7 +550,7 @@ class Embroider(inkex.Effect): if (style_name not in style): return None value = style[style_name] - if (value==None or value=="none"): + if (value is None or value == "none"): return None return value @@ -615,7 +625,7 @@ class Embroider(inkex.Effect): emb.export(self.get_output_path(), self.options.output_format) new_layer = inkex.etree.SubElement(self.document.getroot(), - inkex.addNS('g', 'svg'), {}) + inkex.addNS('g', 'svg'), {}) new_layer.set('id', self.uniqueId("embroidery")) new_layer.set(inkex.addNS('label', 'inkscape'), 'Embroidery') new_layer.set(inkex.addNS('groupmode', 'inkscape'), 'layer') @@ -624,7 +634,7 @@ class Embroider(inkex.Effect): sys.stdout = old_stdout def hide_layers(self): - for g in self.document.getroot().findall(inkex.addNS("g","svg")): + for g in self.document.getroot().findall(inkex.addNS("g", "svg")): if g.get(inkex.addNS("groupmode", "inkscape")) == "layer": g.set("style", "display:none") @@ -637,8 +647,8 @@ class Embroider(inkex.Effect): stroke_width_str = stroke_width_str[:-2] stroke_width = float(stroke_width_str) dashed = self.get_style(node, "stroke-dasharray") is not None - #dbg.write("stroke_width is <%s>\n" % repr(stroke_width)) - #dbg.flush() + # dbg.write("stroke_width is <%s>\n" % repr(stroke_width)) + # dbg.flush() running_stitch_len_px = get_float_param(node, "stitch_length", self.options.running_stitch_len_mm) * self.pixels_per_millimeter zigzag_spacing_px = get_float_param(node, "zigzag_spacing", self.options.zigzag_spacing_mm) * self.options.pixels_per_millimeter @@ -655,10 +665,10 @@ class Embroider(inkex.Effect): for path in paths: path = [PyEmb.Point(x, y) for x, y in path] if (stroke_width <= STROKE_MIN or dashed): - #dbg.write("self.max_stitch_len_px = %s\n" % self.max_stitch_len_px) + # dbg.write("self.max_stitch_len_px = %s\n" % self.max_stitch_len_px) patch = self.stroke_points(path, running_stitch_len_px, 0.0, repeats, threadcolor) else: - patch = self.stroke_points(path, zigzag_spacing_px*0.5, stroke_width, repeats, threadcolor) + patch = self.stroke_points(path, zigzag_spacing_px * 0.5, stroke_width, repeats, threadcolor) patches.extend(patch) return patches @@ -687,19 +697,19 @@ class Embroider(inkex.Effect): # vector pointing along segment along = (p1 - p0).unit() # vector pointing to edge of stroke width - perp = along.rotate_left().mul(stroke_width*0.5) + perp = along.rotate_left().mul(stroke_width * 0.5) if stroke_width == 0.0 and last_segment_direction is not None: if abs(1.0 - along * last_segment_direction) > 0.5: # if greater than 45 degree angle, stitch the corner - #print >> sys.stderr, "corner", along * last_segment_direction + # print >> sys.stderr, "corner", along * last_segment_direction rho = zigzag_spacing_px - patch.addStitch(p0) + patch.add_stitch(p0) # iteration variable: how far we are along segment while (rho <= seg_len): - left_pt = p0+along.mul(rho)+perp.mul(fact) - patch.addStitch(left_pt) + left_pt = p0 + along.mul(rho) + perp.mul(fact) + patch.add_stitch(left_pt) rho += zigzag_spacing_px fact = -fact @@ -708,20 +718,20 @@ class Embroider(inkex.Effect): rho -= seg_len if (p0 - patch.stitches[-1]).length() > 0.1: - patch.addStitch(p0) + patch.add_stitch(p0) return [patch] def filled_region_to_patchlist(self, node): - angle = math.radians(float(get_float_param(node,'angle',0))) + angle = math.radians(float(get_float_param(node, 'angle', 0))) paths = flatten(parse_path(node), self.options.flat) shapelyPolygon = csp_to_shapely_polygon(paths) threadcolor = simplestyle.parseStyle(node.get("style"))["fill"] return self.process_one_path( - node, - shapelyPolygon, - threadcolor, - angle) + node, + shapelyPolygon, + threadcolor, + angle) def fatal(self, message): print >> sys.stderr, "error:", message @@ -733,7 +743,7 @@ class Embroider(inkex.Effect): if len(csp) != 2: self.fatal("satin column: object %s invalid: expected exactly two sub-paths, but there are %s" % (node_id, len(csp))) - if self.get_style(node, "fill")!=None: + if self.get_style(node, "fill") is not None: self.fatal("satin column: object %s has a fill (but should not)" % node_id) if len(csp[0]) != len(csp[1]): @@ -805,15 +815,15 @@ class Embroider(inkex.Effect): # if offset is negative, don't contract so far that pos1 # and pos2 switch places - if offset_px < -distance/2.0: - offset_px = -distance/2.0 + if offset_px < -distance / 2.0: + offset_px = -distance / 2.0 midpoint = (pos2 + pos1) * 0.5 pos1 = pos1 + (pos1 - midpoint).unit() * offset_px pos2 = pos2 + (pos2 - midpoint).unit() * offset_px - + return pos1, pos2 - + def walk_paths(spacing, offset): # Take a bezier segment from each path in turn, and plot out an # equal number of points on each side. Later code can alternate @@ -821,46 +831,46 @@ class Embroider(inkex.Effect): side1 = [] side2 = [] - + def add_pair(pos1, pos2): # Stitches in satin tend to pull toward each other. We can compensate # by spreading the points out. pos1, pos2 = offset_points(pos1, pos2, offset) side1.append(pos1) side2.append(pos2) - + remainder_path1 = [] remainder_path2 = [] - + for segment in xrange(1, len(path1)): # construct the current bezier segments - bezier1 = (path1[segment - 1][1], # point from previous 3-tuple - path1[segment - 1][2], # "after" control point from previous 3-tuple - path1[segment][0], # "before" control point from this 3-tuple - path1[segment][1], # point from this 3-tuple - ) - + bezier1 = (path1[segment - 1][1], # point from previous 3-tuple + path1[segment - 1][2], # "after" control point from previous 3-tuple + path1[segment][0], # "before" control point from this 3-tuple + path1[segment][1], # point from this 3-tuple + ) + bezier2 = (path2[segment - 1][1], path2[segment - 1][2], path2[segment][0], path2[segment][1], - ) - + ) + # Here's what I want to be able to do. However, beziertatlength is so incredibly slow that it's unusable. - #for stitch in xrange(num_zigzags): - # patch.addStitch(bezierpointatt(bezier1, beziertatlength(bezier1, stitch_len1 * stitch))) - # patch.addStitch(bezierpointatt(bezier2, beziertatlength(bezier2, stitch_len2 * (stitch + 0.5)))) - + # for stitch in xrange(num_zigzags): + # patch.add_stitch(bezierpointatt(bezier1, beziertatlength(bezier1, stitch_len1 * stitch))) + # patch.add_stitch(bezierpointatt(bezier2, beziertatlength(bezier2, stitch_len2 * (stitch + 0.5)))) + # Instead, flatten the beziers down to a set of line segments. subpath1 = remainder_path1 + flatten([[path1[segment - 1], path1[segment]]], self.options.flat)[0] subpath2 = remainder_path2 + flatten([[path2[segment - 1], path2[segment]]], self.options.flat)[0] - + len1 = shgeo.LineString(subpath1).length len2 = shgeo.LineString(subpath2).length - + subpath1 = [PyEmb.Point(*p) for p in subpath1] subpath2 = [PyEmb.Point(*p) for p in subpath2] - + # Base the number of stitches in each section on the _longest_ of # the two beziers. Otherwise, things could get too sparse when one # side is significantly longer (e.g. when going around a corner). @@ -868,73 +878,73 @@ class Embroider(inkex.Effect): # cram too many stitches on the short bezier. The user will need # to avoid this through careful construction of paths. num_points = max(len1, len2) / spacing - + spacing1 = len1 / num_points spacing2 = len2 / num_points - + def walk(path, start_pos, start_index, distance): # Move pixels along 's line segments. # is the index of the line segment in that # we're currently on. is where along that line # segment we are. Return a new position and index. - + pos = start_pos index = start_index - + if index >= len(path) - 1: # it's possible we'll go too far due to inaccuracy in the # bezier length calculation return start_pos, start_index - + while True: segment_end = path[index + 1] segment_remaining = (segment_end - pos) distance_remaining = segment_remaining.length() - + if distance_remaining > distance: return pos + segment_remaining.unit().mul(distance), index else: index += 1 - + if index >= len(path) - 1: return segment_end, index - + distance -= distance_remaining pos = segment_end - + pos1 = subpath1[0] i1 = 0 - + pos2 = subpath2[0] i2 = 0 - + # if num_zigzags >= 1.0: # for stitch in xrange(int(num_zigzags) + 1): for i in xrange(int(num_points)): add_pair(pos1, pos2) - + pos2, i2 = walk(subpath2, pos2, i2, spacing2) pos1, i1 = walk(subpath1, pos1, i1, spacing1) - + if i1 < len(subpath1) - 1: remainder_path1 = [pos1] + subpath1[i1 + 1:] else: remainder_path1 = [] - + if i2 < len(subpath2) - 1: remainder_path2 = [pos2] + subpath2[i2 + 1:] else: remainder_path2 = [] - + remainder_path1 = [p.as_tuple() for p in remainder_path1] remainder_path2 = [p.as_tuple() for p in remainder_path2] - + # We're off by one in the algorithm above, so we need one more # pair of points. We also want to add points at the very end to # make sure we match the vectors on screen as best as possible. # Try to avoid doing both if they're going to stack up too # closely. - + end1 = PyEmb.Point(*remainder_path1[-1]) end2 = PyEmb.Point(*remainder_path2[-1]) if (end1 - pos1).length() > 0.3 * spacing: @@ -963,13 +973,13 @@ class Embroider(inkex.Effect): patch = Patch(color=threadcolor) - sides = walk_paths(zigzag_spacing/2.0, -inset) - sides = [sides[0][::2] + list(reversed(sides[0][1::2])), sides[1][1::2] + list(reversed(sides[1][::2]))] + sides = walk_paths(zigzag_spacing / 2.0, -inset) + sides = [sides[0][::2] + list(reversed(sides[0][1::2])), sides[1][1::2] + list(reversed(sides[1][::2]))] # this fancy bit of iterable magic just repeatedly takes a point # from each list in turn for point in chain.from_iterable(izip(*sides)): - patch.addStitch(point) + patch.add_stitch(point) return patch @@ -984,7 +994,7 @@ class Embroider(inkex.Effect): sides = walk_paths(zigzag_spacing, pull_compensation) for point in chain.from_iterable(izip(*sides)): - patch.addStitch(point) + patch.add_stitch(point) return patch @@ -1012,7 +1022,7 @@ class Embroider(inkex.Effect): return [patch] if __name__ == '__main__': - sys.setrecursionlimit(100000); + sys.setrecursionlimit(100000) e = Embroider() e.affect() dbg.flush() diff --git a/embroider_params.py b/embroider_params.py index 20f6c222d..ffa14f938 100644 --- a/embroider_params.py +++ b/embroider_params.py @@ -14,7 +14,7 @@ import inkex class EmbroiderParams(inkex.Effect): def __init__(self, *args, **kwargs): inkex.Effect.__init__(self) - + self.params = ["zigzag_spacing", "stitch_length", "row_spacing", @@ -31,7 +31,7 @@ class EmbroiderParams(inkex.Effect): "satin_center_walk", "satin_zigzag_underlay_spacing", ] - + for param in self.params: self.OptionParser.add_option("--%s" % param, default="") @@ -40,7 +40,7 @@ class EmbroiderParams(inkex.Effect): for param in self.params: value = getattr(self.options, param).strip() param = "embroider_" + param - + if node.get(param) is not None and not value: # only overwrite existing params if they gave a value continue