diff --git a/lib/commands.py b/lib/commands.py index 8e35d7ee0..c735185f6 100644 --- a/lib/commands.py +++ b/lib/commands.py @@ -289,6 +289,10 @@ def add_connector(document, symbol, element): start_pos = (symbol.get('x'), symbol.get('y')) end_pos = element.shape.centroid + # Make sure the element's XML node has an id so that we can reference it. + if element.node.get('id') is None: + element.node.set('id', generate_unique_id(document, "object")) + path = inkex.etree.Element(SVG_PATH_TAG, { "id": generate_unique_id(document, "connector"), diff --git a/lib/elements/stroke.py b/lib/elements/stroke.py index 3ae2b1434..e0a0aaccb 100644 --- a/lib/elements/stroke.py +++ b/lib/elements/stroke.py @@ -1,11 +1,13 @@ import sys + import shapely.geometry -from .element import param, EmbroideryElement, Patch from ..i18n import _ -from ..utils import cache, Point from ..stitches import running_stitch, bean_stitch from ..svg import parse_length_with_units +from ..utils import cache, Point +from .element import param, EmbroideryElement, Patch + warned_about_legacy_running_stitch = False @@ -85,7 +87,11 @@ class Stroke(EmbroideryElement): @cache def shape(self): line_strings = [shapely.geometry.LineString(path) for path in self.paths] - return shapely.geometry.MultiLineString(line_strings) + + # Using convex_hull here is an important optimization. Otherwise + # complex paths cause operations on the shape to take a long time. + # This especially happens when importing machine embroidery files. + return shapely.geometry.MultiLineString(line_strings).convex_hull @property @param('manual_stitch', diff --git a/lib/svg/rendering.py b/lib/svg/rendering.py index 41ed53d7f..532748bf8 100644 --- a/lib/svg/rendering.py +++ b/lib/svg/rendering.py @@ -167,9 +167,7 @@ def get_correction_transform(svg): return transform -def color_block_to_realistic_stitches(color_block, svg): - paths = [] - +def color_block_to_realistic_stitches(color_block, svg, destination): for point_list in color_block_to_point_lists(color_block): if not point_list: continue @@ -177,7 +175,7 @@ def color_block_to_realistic_stitches(color_block, svg): color = color_block.color.visible_on_white.darker.to_hex_str() start = point_list[0] for point in point_list[1:]: - paths.append(inkex.etree.Element( + destination.append(inkex.etree.Element( SVG_PATH_TAG, {'style': simplestyle.formatStyle( { @@ -190,16 +188,23 @@ def color_block_to_realistic_stitches(color_block, svg): })) start = point - return paths - -def color_block_to_paths(color_block, svg): - paths = [] +def color_block_to_paths(color_block, svg, destination): # We could emit just a single path with one subpath per point list, but # emitting multiple paths makes it easier for the user to manipulate them. + first = True for point_list in color_block_to_point_lists(color_block): + if first: + first = False + else: + # If we try to import these above, we get into a mess of circular + # imports. + from ..commands import add_commands + from ..elements.stroke import Stroke + add_commands(Stroke(destination[-1]), ["trim"]) + color = color_block.color.visible_on_white.to_hex_str() - paths.append(inkex.etree.Element( + destination.append(inkex.etree.Element( SVG_PATH_TAG, {'style': simplestyle.formatStyle( {'stroke': color, @@ -207,16 +212,9 @@ def color_block_to_paths(color_block, svg): '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', + 'embroider_manual_stitch': 'true' })) - # no need to trim at the end of a thread color - if paths: - paths[-1].attrib.pop('embroider_trim_after') - - return paths - def render_stitch_plan(svg, stitch_plan, realistic=False): layer = svg.find(".//*[@id='__inkstitch_stitch_plan__']") @@ -232,17 +230,17 @@ def render_stitch_plan(svg, stitch_plan, realistic=False): # make sure the layer is visible layer.set('style', 'display:inline') + svg.append(layer) + for i, color_block in enumerate(stitch_plan): group = inkex.etree.SubElement(layer, SVG_GROUP_TAG, {'id': '__color_block_%d__' % i, INKSCAPE_LABEL: "color block %d" % (i + 1)}) if realistic: - group.extend(color_block_to_realistic_stitches(color_block, svg)) + color_block_to_realistic_stitches(color_block, svg, group) else: - group.extend(color_block_to_paths(color_block, svg)) - - svg.append(layer) + color_block_to_paths(color_block, svg, group) if realistic: defs = svg.find(SVG_DEFS_TAG)