diff options
| author | Lex Neva <github.com@lexneva.name> | 2019-02-22 22:07:15 -0500 |
|---|---|---|
| committer | Lex Neva <github.com@lexneva.name> | 2019-03-08 19:57:11 -0500 |
| commit | 4ba3cd708561870a731d9634d9cdd5c18579cac7 (patch) | |
| tree | cd901daa9bd9f1901f3dbbca57940a981215267d /lib/svg | |
| parent | 3611e2340997b917cc89e7d405b3c7d9bc86aab5 (diff) | |
refactor add_commands() out into commands module
Diffstat (limited to 'lib/svg')
| -rw-r--r-- | lib/svg/__init__.py | 7 | ||||
| -rw-r--r-- | lib/svg/rendering.py (renamed from lib/svg/realistic_rendering.py) | 129 | ||||
| -rw-r--r-- | lib/svg/svg.py | 127 |
3 files changed, 141 insertions, 122 deletions
diff --git a/lib/svg/__init__.py b/lib/svg/__init__.py index df76c0d2..0b4a6ee4 100644 --- a/lib/svg/__init__.py +++ b/lib/svg/__init__.py @@ -1,4 +1,5 @@ -from .svg import color_block_to_point_lists, render_stitch_plan -from .units import * -from .path import apply_transforms, get_node_transform, get_correction_transform, line_strings_to_csp, point_lists_to_csp from .guides import get_guides +from .path import apply_transforms, get_node_transform, get_correction_transform, line_strings_to_csp, point_lists_to_csp +from .rendering import color_block_to_point_lists, render_stitch_plan +from .svg import get_document, generate_unique_id +from .units import *
\ No newline at end of file diff --git a/lib/svg/realistic_rendering.py b/lib/svg/rendering.py index 73da3a09..41ed53d7 100644 --- a/lib/svg/realistic_rendering.py +++ b/lib/svg/rendering.py @@ -1,8 +1,17 @@ -import simplepath import math -from .units import PIXELS_PER_MM +import inkex +import simplepath +import simplestyle +import simpletransform + +from ..i18n import _ from ..utils import Point +from ..utils import cache +from .tags import SVG_GROUP_TAG, INKSCAPE_LABEL, INKSCAPE_GROUPMODE, SVG_PATH_TAG, SVG_DEFS_TAG +from .units import PIXELS_PER_MM +from .units import get_viewbox_transform + # The stitch vector path looks like this: # _______ @@ -10,7 +19,6 @@ from ..utils import Point # # It's 0.32mm high, which is the approximate thickness of common machine # embroidery threads. - # 1.216 pixels = 0.32mm stitch_height = 1.216 @@ -128,3 +136,118 @@ def realistic_stitch(start, end): simplepath.translatePath(path, stitch_center.x - rotation_center_x, stitch_center.y - rotation_center_y) return simplepath.formatPath(path) + + +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 not stitch.jump and not stitch.color_change: + point_lists[-1].append(stitch.as_tuple()) + + # filter out empty point lists + point_lists = [p for p in point_lists if p] + + return point_lists + + +@cache +def get_correction_transform(svg): + transform = get_viewbox_transform(svg) + + # we need to correct for the viewbox + transform = simpletransform.invertTransform(transform) + transform = simpletransform.formatTransform(transform) + + return transform + + +def color_block_to_realistic_stitches(color_block, svg): + paths = [] + + for point_list in color_block_to_point_lists(color_block): + if not point_list: + continue + + 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( + SVG_PATH_TAG, + {'style': simplestyle.formatStyle( + { + 'fill': color, + 'stroke': 'none', + 'filter': 'url(#realistic-stitch-filter)' + }), + '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 + # emitting multiple paths makes it easier for the user to manipulate them. + for point_list in color_block_to_point_lists(color_block): + color = color_block.color.visible_on_white.to_hex_str() + paths.append(inkex.etree.Element( + 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', + })) + + # 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__']") + if layer is None: + layer = inkex.etree.Element(SVG_GROUP_TAG, + {'id': '__inkstitch_stitch_plan__', + INKSCAPE_LABEL: _('Stitch Plan'), + INKSCAPE_GROUPMODE: 'layer'}) + else: + # delete old stitch plan + del layer[:] + + # make sure the layer is visible + layer.set('style', 'display:inline') + + 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)) + else: + group.extend(color_block_to_paths(color_block, svg)) + + svg.append(layer) + + if realistic: + defs = svg.find(SVG_DEFS_TAG) + + if defs is None: + defs = inkex.etree.SubElement(svg, SVG_DEFS_TAG) + + defs.append(inkex.etree.fromstring(realistic_filter)) diff --git a/lib/svg/svg.py b/lib/svg/svg.py index 3fceebfb..0ec43f75 100644 --- a/lib/svg/svg.py +++ b/lib/svg/svg.py @@ -1,124 +1,19 @@ -import inkex -import simplestyle -import simpletransform - -from ..i18n import _ from ..utils import cache -from .realistic_rendering import realistic_stitch, realistic_filter -from .tags import SVG_GROUP_TAG, INKSCAPE_LABEL, INKSCAPE_GROUPMODE, SVG_PATH_TAG, SVG_DEFS_TAG -from .units import get_viewbox_transform - - -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 not stitch.jump and not stitch.color_change: - point_lists[-1].append(stitch.as_tuple()) - - # filter out empty point lists - point_lists = [p for p in point_lists if p] - - return point_lists @cache -def get_correction_transform(svg): - transform = get_viewbox_transform(svg) - - # we need to correct for the viewbox - transform = simpletransform.invertTransform(transform) - transform = simpletransform.formatTransform(transform) - - return transform - - -def color_block_to_realistic_stitches(color_block, svg): - paths = [] - - for point_list in color_block_to_point_lists(color_block): - if not point_list: - continue - - 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( - SVG_PATH_TAG, - {'style': simplestyle.formatStyle( - { - 'fill': color, - 'stroke': 'none', - 'filter': 'url(#realistic-stitch-filter)' - }), - '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 - # emitting multiple paths makes it easier for the user to manipulate them. - for point_list in color_block_to_point_lists(color_block): - color = color_block.color.visible_on_white.to_hex_str() - paths.append(inkex.etree.Element( - 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', - })) - - # 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__']") - if layer is None: - layer = inkex.etree.Element(SVG_GROUP_TAG, - {'id': '__inkstitch_stitch_plan__', - INKSCAPE_LABEL: _('Stitch Plan'), - INKSCAPE_GROUPMODE: 'layer'}) - else: - # delete old stitch plan - del layer[:] - - # make sure the layer is visible - layer.set('style', 'display:inline') - - 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)) - else: - group.extend(color_block_to_paths(color_block, svg)) +def get_document(node): + return node.getroottree().getroot() - svg.append(layer) - if realistic: - defs = svg.find(SVG_DEFS_TAG) +def generate_unique_id(document, prefix="path"): + doc_ids = {node.get('id') for node in document.iterdescendants() if 'id' in node.attrib} - if defs is None: - defs = inkex.etree.SubElement(svg, SVG_DEFS_TAG) + i = 1 + while True: + new_id = "%s%d" % (prefix, i) + if new_id not in doc_ids: + break + i += 1 - defs.append(inkex.etree.fromstring(realistic_filter)) + return new_id |
