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
108
109
110
111
112
113
114
|
# 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 math import degrees
from inkex import DirectedLineSegment, PathElement, errormsg
from shapely.geometry import Point
from shapely.ops import nearest_points
from ..commands import add_commands
from ..elements import FillStitch
from ..elements.gradient_fill import gradient_shapes_and_attributes
from ..i18n import _
from ..svg import get_correction_transform
from ..svg.tags import INKSTITCH_ATTRIBS
from .commands import CommandsExtension
from .duplicate_params import get_inkstitch_attributes
class GradientBlocks(CommandsExtension):
'''
This will break apart fill objects with a gradient fill into solid color blocks with end_row_spacing.
'''
COMMANDS = ['fill_start', 'fill_end']
def __init__(self, *args, **kwargs):
CommandsExtension.__init__(self, *args, **kwargs)
self.arg_parser.add_argument("--notebook", type=str, default=0.0)
self.arg_parser.add_argument("--options", type=str, default=0.0)
self.arg_parser.add_argument("--info", type=str, default=0.0)
self.arg_parser.add_argument("-e", "--end-row-spacing", type=float, default=0.0, dest="end_row_spacing")
def effect(self):
if not self.svg.selection:
errormsg(_("Please select at least one object with a gradient fill."))
return
if not self.get_elements():
return
elements = [element for element in self.elements if (isinstance(element, FillStitch) and self.has_gradient_color(element))]
if not elements:
errormsg(_("Please select at least one object with a gradient fill."))
return
for element in elements:
parent = element.node.getparent()
correction_transform = get_correction_transform(element.node)
style = element.node.style
index = parent.index(element.node)
fill_shapes, attributes = gradient_shapes_and_attributes(element, element.shape)
# reverse order so we can always insert with the same index number
fill_shapes.reverse()
attributes.reverse()
previous_color = None
previous_element = None
for i, shape in enumerate(fill_shapes):
color = attributes[i]['color']
style['fill'] = color
end_row_spacing = attributes[i]['end_row_spacing'] or None
angle = degrees(attributes[i]['angle'])
d = "M " + " ".join([f'{x}, {y}' for x, y in list(shape.exterior.coords)]) + " Z"
block = PathElement(attrib={
"id": self.uniqueId("path"),
"style": str(style),
"transform": correction_transform,
"d": d,
INKSTITCH_ATTRIBS['angle']: f'{angle: .2f}'
})
# apply parameters from original element
params = get_inkstitch_attributes(element.node)
for attrib in params:
block.attrib[attrib] = str(element.node.attrib[attrib])
# set end_row_spacing
if end_row_spacing:
if self.options.end_row_spacing != 0:
end_row_spacing = self.options.end_row_spacing
block.set('inkstitch:end_row_spacing_mm', f'{end_row_spacing: .2f}')
else:
block.pop('inkstitch:end_row_spacing_mm')
# disable underlay and underpath
block.set('inkstitch:fill_underlay', False)
block.set('inkstitch:underpath', False)
parent.insert(index, block)
if previous_color == color:
current = FillStitch(block)
previous = FillStitch(previous_element)
nearest = nearest_points(current.shape, previous.shape)
pos_current = self._get_command_postion(current, nearest[0])
pos_previous = self._get_command_postion(previous, nearest[1])
add_commands(current, ['fill_end'], pos_current)
add_commands(previous, ['fill_start'], pos_previous)
previous_color = color
previous_element = block
parent.remove(element.node)
def has_gradient_color(self, element):
return element.color.startswith('url') and "linearGradient" in element.color
def _get_command_postion(self, fill, point):
center = fill.shape.centroid
line = DirectedLineSegment((center.x, center.y), (point.x, point.y))
pos = line.point_at_length(line.length + 20)
return Point(pos)
if __name__ == '__main__':
e = GradientBlocks()
e.effect()
|