summaryrefslogtreecommitdiff
path: root/lib/extensions/stitch_plan_preview.py
blob: fbfe3628eced5e9763b6733c9043de240e91e3c6 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
# Authors: see git history
#
# Copyright (c) 2010 Authors
# Licensed under the GNU GPL version 3.0 or later.  See the file LICENSE for details.

from inkex import Boolean, Style
from lxml import etree

from ..stitch_plan import stitch_groups_to_stitch_plan
from ..svg import render_stitch_plan
from ..svg.tags import (INKSCAPE_GROUPMODE, INKSTITCH_ATTRIBS,
                        SODIPODI_INSENSITIVE, SVG_DEFS_TAG, SVG_GROUP_TAG,
                        SVG_PATH_TAG)
from .base import InkstitchExtension
from .stitch_plan_preview_undo import reset_stitch_plan


class StitchPlanPreview(InkstitchExtension):
    def __init__(self, *args, **kwargs):
        InkstitchExtension.__init__(self, *args, **kwargs)
        self.arg_parser.add_argument("-s", "--move-to-side", type=Boolean, default=True, dest="move_to_side")
        self.arg_parser.add_argument("-v", "--layer-visibility", type=int, default=0, dest="layer_visibility")
        self.arg_parser.add_argument("-n", "--needle-points", type=Boolean, default=False, dest="needle_points")
        self.arg_parser.add_argument("-i", "--insensitive", type=Boolean, default=False, dest="insensitive")
        self.arg_parser.add_argument("-c", "--visual-commands", type=Boolean, default="symbols", dest="visual_commands")

    def effect(self):
        # delete old stitch plan
        svg = self.document.getroot()
        reset_stitch_plan(svg)

        # create new stitch plan
        if not self.get_elements():
            return

        realistic = False
        visual_commands = self.options.visual_commands
        self.metadata = self.get_inkstitch_metadata()
        collapse_len = self.metadata['collapse_len_mm']
        min_stitch_len = self.metadata['min_stitch_len_mm']
        patches = self.elements_to_stitch_groups(self.elements)
        stitch_plan = stitch_groups_to_stitch_plan(patches, collapse_len=collapse_len, min_stitch_len=min_stitch_len)
        render_stitch_plan(svg, stitch_plan, realistic, visual_commands)

        # apply options
        layer = svg.find(".//*[@id='__inkstitch_stitch_plan__']")

        # update layer visibility 0 = unchanged, 1 = hidden, 2 = lower opacity
        groups = self.document.getroot().findall(SVG_GROUP_TAG)
        if self.options.layer_visibility == 1:
            self.set_invisible_layers_attribute(groups, layer)
            self.hide_all_layers()
            layer.style['display'] = "inline"
        elif self.options.layer_visibility == 2:
            for g in groups:
                style = g.specified_style()
                # check groupmode and exclude stitch_plan layer
                # exclude objects which are not displayed at all or already have opacity < 0.4
                if (g.get(INKSCAPE_GROUPMODE) == "layer" and not g == layer and
                        float(style.get('opacity', 1)) > 0.4 and not style.get('display', 'inline') == 'none'):
                    g.style['opacity'] = 0.4

        if self.options.insensitive is True:
            layer.set(SODIPODI_INSENSITIVE, True)
        else:
            layer.pop(SODIPODI_INSENSITIVE)

        # translate stitch plan to the right side of the canvas
        if self.options.move_to_side:
            layer.set('transform', 'translate(%s)' % svg.get('viewBox', '0 0 800 0').split(' ')[2])
        else:
            layer.set('transform', None)

        # display needle points
        if self.options.needle_points:
            markers = 'marker-mid:url(#inkstitch-needle-point);marker-start:url(#inkstitch-needle-point);marker-end:url(#inkstitch-needle-point)'
            for element in layer.iterdescendants(SVG_PATH_TAG):
                style = element.style + Style(markers)
                element.set('style', style)
            self.ensure_marker()

    def set_invisible_layers_attribute(self, groups, layer):
        invisible_layers = []
        for g in groups:
            if g.get(INKSCAPE_GROUPMODE) == "layer" and 'display' in g.style and g.style['display'] == 'none':
                invisible_layers.append(g.get_id())
        layer.set(INKSTITCH_ATTRIBS['invisible_layers'], ",".join(invisible_layers))

    def ensure_marker(self):
        xpath = ".//svg:marker[@id='inkstitch-needle-point']"
        point_marker = self.document.getroot().xpath(xpath)

        if not point_marker:
            # get or create def element
            defs = self.document.find(SVG_DEFS_TAG)
            if defs is None:
                defs = etree.SubElement(self.document, SVG_DEFS_TAG)

            # insert marker
            marker = """<marker
                      orient="auto"
                      id="inkstitch-needle-point">
                         <circle
                                 cx="0" cy="0" r="1.5"
                                 style="fill:context-stroke;opacity:0.8;" />
                     </marker>"""
            defs.append(etree.fromstring(marker))