kopia lustrzana https://github.com/inkstitch/inkstitch
Add selection to knockdown fill extension (#3526)
rodzic
10fdc509f5
commit
ff073a4bd6
File diff suppressed because one or more lines are too long
Po Szerokość: | Wysokość: | Rozmiar: 46 KiB |
|
@ -30,6 +30,7 @@ from .install import Install
|
|||
from .install_custom_palette import InstallCustomPalette
|
||||
from .jump_to_stroke import JumpToStroke
|
||||
from .jump_to_trim import JumpToTrim
|
||||
from .knockdown_fill import KnockdownFill
|
||||
from .layer_commands import LayerCommands
|
||||
from .lettering import Lettering
|
||||
from .lettering_along_path import LetteringAlongPath
|
||||
|
@ -103,6 +104,7 @@ __all__ = extensions = [About,
|
|||
InstallCustomPalette,
|
||||
JumpToStroke,
|
||||
JumpToTrim,
|
||||
KnockdownFill,
|
||||
LayerCommands,
|
||||
Lettering,
|
||||
LetteringAlongPath,
|
||||
|
|
|
@ -0,0 +1,106 @@
|
|||
# Authors: see git history
|
||||
#
|
||||
# Copyright (c) 2025 Authors
|
||||
# Licensed under the GNU GPL version 3.0 or later. See the file LICENSE for details.
|
||||
|
||||
from inkex import Boolean, Path, PathElement
|
||||
from shapely import union_all
|
||||
from shapely.geometry import LineString, Polygon
|
||||
|
||||
from ..stitches.ripple_stitch import ripple_stitch
|
||||
from ..svg import PIXELS_PER_MM, get_correction_transform
|
||||
from ..utils.geometry import ensure_multi_polygon
|
||||
from .base import InkstitchExtension
|
||||
|
||||
|
||||
class KnockdownFill(InkstitchExtension):
|
||||
'''
|
||||
This extension generates a shape around all selected shapes and inserts it into the document
|
||||
'''
|
||||
def __init__(self, *args, **kwargs):
|
||||
InkstitchExtension.__init__(self, *args, **kwargs)
|
||||
self.arg_parser.add_argument("--notebook")
|
||||
self.arg_parser.add_argument("-k", "--keep-holes", type=Boolean, default=True, dest="keep_holes")
|
||||
self.arg_parser.add_argument("-o", "--offset", type=float, default=0, dest="offset")
|
||||
self.arg_parser.add_argument("-j", "--join-style", type=str, default="1", dest="join_style")
|
||||
self.arg_parser.add_argument("-m", "--mitre-limit", type=float, default=5.0, dest="mitre_limit")
|
||||
# TODO: Layer options: underlay, row spacing, angle
|
||||
|
||||
def effect(self):
|
||||
if not self.get_elements():
|
||||
return
|
||||
|
||||
polygons = []
|
||||
for element in self.elements:
|
||||
if element.name == "FillStitch":
|
||||
# take expand value into account
|
||||
shape = element.shrink_or_grow_shape(element.shape, element.expand)
|
||||
# MultiPolygon
|
||||
for polygon in shape.geoms:
|
||||
polygons.append(polygon)
|
||||
elif element.name == "SatinColumn":
|
||||
# plot points on rails, so we get the actual satin size (including pull compensation)
|
||||
rail_pairs = zip(*element.plot_points_on_rails(
|
||||
0.3,
|
||||
element.pull_compensation_px,
|
||||
element.pull_compensation_percent / 100)
|
||||
)
|
||||
rails = []
|
||||
for rail in rail_pairs:
|
||||
rails.append(LineString(rail))
|
||||
polygon = Polygon(list(rails[0].coords) + list(rails[1].reverse().coords)).buffer(0)
|
||||
polygons.append(polygon)
|
||||
elif element.name == "Stroke":
|
||||
if element.stroke_method == 'ripple_stitch':
|
||||
# for ripples this is going to be a bit complicated, so let's follow the stitch plan
|
||||
stitches = ripple_stitch(element)
|
||||
linestring = LineString(stitches)
|
||||
polygons.append(linestring.buffer(0.15 * PIXELS_PER_MM, cap_style='flat'))
|
||||
elif element.stroke_method == 'zigzag_stitch':
|
||||
# zigzag stitch depends on the width of the stroke and pull compensation settings
|
||||
polygons.append(element.as_multi_line_string().buffer((element.stroke_width + element.pull_compensation) / 2, cap_style='flat'))
|
||||
else:
|
||||
polygons.append(element.as_multi_line_string().buffer(0.15 * PIXELS_PER_MM, cap_style='flat'))
|
||||
combined_shape = union_all(polygons)
|
||||
combined_shape = combined_shape.buffer(
|
||||
self.options.offset * PIXELS_PER_MM,
|
||||
cap_style=int(self.options.join_style),
|
||||
join_style=int(self.options.join_style),
|
||||
mitre_limit=int(self.options.mitre_limit)
|
||||
)
|
||||
combined_shape = combined_shape.simplify(0.3)
|
||||
combined_shape = ensure_multi_polygon(combined_shape)
|
||||
|
||||
self.insert_knockdown_elements(combined_shape)
|
||||
|
||||
def insert_knockdown_elements(self, combined_shape):
|
||||
first = self.svg.selection.rendering_order()[0]
|
||||
try:
|
||||
parent = first.getparent()
|
||||
index = parent.index(first)
|
||||
except AttributeError:
|
||||
parent = self.svg
|
||||
index = 0
|
||||
transform = get_correction_transform(first)
|
||||
|
||||
for polygon in combined_shape.geoms:
|
||||
d = str(Path(polygon.exterior.coords))
|
||||
if self.options.keep_holes:
|
||||
for interior in polygon.interiors:
|
||||
d += str(Path(interior.coords))
|
||||
|
||||
path = PathElement()
|
||||
path.set('d', d)
|
||||
path.label = self.svg.get_unique_id('Knockdown ')
|
||||
path.set('transform', transform)
|
||||
|
||||
path.set('inkstitch:row_spacing_mm', '2.6')
|
||||
path.set('inkstitch:fill_underlay_angle', '60 -60')
|
||||
path.set('inkstitch:fill_underlay_max_stitch_length_mm', '3')
|
||||
path.set('inkstitch:fill_underlay_row_spacing_mm', '2.6')
|
||||
path.set('inkstitch:underlay_underpath', 'False')
|
||||
path.set('inkstitch:underpath', 'False')
|
||||
path.set('inkstitch:staggers', '2')
|
||||
path.set('style', 'fill:black;')
|
||||
|
||||
parent.insert(index, path)
|
|
@ -0,0 +1,40 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<inkscape-extension translationdomain="inkstitch" xmlns="http://www.inkscape.org/namespace/inkscape/extension">
|
||||
<name>Selection to Knockdown Fill</name>
|
||||
<id>org.{{ id_inkstitch }}.knockdown_fill</id>
|
||||
<param name="extension" type="string" gui-hidden="true">knockdown_fill</param>
|
||||
<effect>
|
||||
<object-type>all</object-type>
|
||||
<icon>{{ icon_path }}inx/fill_knockdown.svg</icon>
|
||||
<menu-tip>Generates a knockdown stitch with a specified offset around selection</menu-tip>
|
||||
<effects-menu>
|
||||
<submenu name="{{ menu_inkstitch }}" translatable="no">
|
||||
<submenu name="Tools: Fill" />
|
||||
</submenu>
|
||||
</effects-menu>
|
||||
</effect>
|
||||
<param name="notebook" type="notebook">
|
||||
<page name="options" gui-text="Options">
|
||||
<param name="keep-holes" type="bool" gui-text="Keep holes">true</param>
|
||||
<param name="offset" type="float" gui-text="Offset">1</param>
|
||||
<param name="join-style" type="optiongroup" gui-text="Method">
|
||||
<option value="1">Round</option>
|
||||
<option value="2">Mitre</option>
|
||||
<option value="3">Bevel</option>
|
||||
</param>
|
||||
<param name="mitre-limit" type="float" gui-text="Mitre limit">5.0</param>
|
||||
</page>
|
||||
<page name="info" gui-text="Help">
|
||||
<label appearance="header">This extension generates a knockdown fill area with a specified offset around selected elements.</label>
|
||||
<label>* Select elements of any kind</label>
|
||||
<label>* Open this extension and apply with desired settings</label>
|
||||
<label>* Adapt fill settings in the params dialog</label>
|
||||
<spacer />
|
||||
<label>More information on our website</label>
|
||||
<label appearance="url">https://inkstitch.org/docs/fill-tools/#knockdown-fill</label>
|
||||
</page>
|
||||
</param>
|
||||
<script>
|
||||
{{ command_tag | safe }}
|
||||
</script>
|
||||
</inkscape-extension>
|
Ładowanie…
Reference in New Issue