Add transform extension which also transforms the fill angles (#3657)

pull/3673/head
Kaalleen 2025-04-15 18:27:06 +02:00 zatwierdzone przez GitHub
rodzic 0f1c83f8ef
commit bc0943c6c8
Nie znaleziono w bazie danych klucza dla tego podpisu
ID klucza GPG: B5690EEEBB952194
5 zmienionych plików z 154 dodań i 2 usunięć

Wyświetl plik

@ -311,7 +311,7 @@ class FillStitch(EmbroideryElement):
type='float',
sort_index=21,
select_items=[('fill_method', 'tartan_fill')],
default=45)
default=-45)
@cache
def tartan_angle(self):
return self.get_float_param('tartan_angle', -45)

Wyświetl plik

@ -72,6 +72,7 @@ from .stroke_to_satin import StrokeToSatin
from .tartan import Tartan
from .test_swatches import TestSwatches
from .thread_list import ThreadList
from .transform_elements import TransformElements
from .troubleshoot import Troubleshoot
from .unlink_clone import UnlinkClone
from .update_svg import UpdateSvg
@ -148,6 +149,7 @@ extensions = [
Tartan,
TestSwatches,
ThreadList,
TransformElements,
Troubleshoot,
UnlinkClone,
UpdateSvg,

Wyświetl plik

@ -49,7 +49,7 @@ class JumpToStroke(InkstitchExtension):
next_elements = self.elements[1:] + next_elements
for element, next_element in zip(self.elements, next_elements):
layer, group = self._get_element_layer_and_group(element)
stitch_groups = element.to_stitch_groups(last_stitch_group, next_element)
stitch_groups = element.embroider(last_stitch_group, next_element)
multiple = not self.options.merge_subpaths and stitch_groups
if multiple:

Wyświetl plik

@ -0,0 +1,112 @@
# Authors: see git history
#
# Copyright (c) 2025 Authors
# Licensed under the GNU GPL version 3.0 or later. See the file LICENSE for details.
import json
from typing import Optional
from inkex import (Boolean, PathElement, ShapeElement, Transform, Vector2d,
errormsg)
from ..i18n import _
from ..tartan.utils import get_tartan_settings
from .base import InkstitchExtension
class TransformElements(InkstitchExtension):
'''
This will apply transformations while also transforming fill angles.
'''
def __init__(self, *args, **kwargs):
InkstitchExtension.__init__(self, *args, **kwargs)
self.arg_parser.add_argument("--notebook")
self.arg_parser.add_argument("-r", "--rotate", type=float, default=0, dest="rotate")
self.arg_parser.add_argument("-f", "--flip-horizontally", type=Boolean, default=False, dest="horizontal_flip")
self.arg_parser.add_argument("-v", "--flip-vertically", type=Boolean, default=False, dest="vertical_flip")
def effect(self) -> None:
if not self.svg.selection:
errormsg(_("Please select one or more elements."))
return
selection_center = self.svg.selection.bounding_box().center
nodes = self.get_nodes()
for node in nodes:
parent_transform = node.composed_transform() @ -node.transform
if self.options.rotate != 0:
self.rotate_node(node, parent_transform, selection_center)
if self.options.horizontal_flip:
self.flip_node_horizontally(node, parent_transform, selection_center)
if self.options.vertical_flip:
self.flip_node_vertically(node, parent_transform, selection_center)
# Apply transform to path elements, simply because it's possible and nicer
if isinstance(node, PathElement):
node.apply_transform()
def flip_node_vertically(self, node: ShapeElement, parent_transform: Transform, center: Vector2d) -> None:
node.transform = (
-parent_transform @
Transform(f'translate({center[0], center[1]}) scale(1, -1) translate({-center[0], -center[1]})') @
node.composed_transform()
)
self.adapt_fill_angle(node, -1)
def flip_node_horizontally(self, node: ShapeElement, parent_transform: Transform, center: Vector2d) -> None:
node.transform = (
-parent_transform @
Transform(f'translate({center[0], center[1]}) scale(-1, 1) translate({-center[0], -center[1]})') @
node.composed_transform()
)
self.adapt_fill_angle(node, -1)
def rotate_node(self, node: ShapeElement, parent_transform: Transform, center: Vector2d) -> None:
node.transform = (
-parent_transform @
Transform(f'rotate({self.options.rotate}, {center[0]}, {center[1]})') @
node.composed_transform()
)
self.adapt_fill_angle(node, None, self.options.rotate)
def adapt_fill_angle(self, node: ShapeElement, multiplier: Optional[int] = None, rotation: Optional[float] = None) -> None:
if not node.style("fill", "black"):
return
self._apply_angle(node, "inkstitch:fill_underlay_angle", None, multiplier, rotation)
if node.get('inkstitch:fill_method', None) == "tartan_fill":
if rotation is None:
self._apply_angle(node, "inkstitch:tartan_angle", "-45", multiplier, rotation)
# Also rotate tartan pattern rotation setting
self._rotate_tartan_pattern(node, multiplier, rotation)
elif node.get('inkstitch:fill_method', None) == "meander_fill":
self._apply_angle(node, "inkstitch:meander_angle", "0", multiplier, rotation)
else:
self._apply_angle(node, "inkstitch:angle", "0", multiplier, rotation)
def _apply_angle(self, node: ShapeElement, attrib: str, default: Optional[str], multiplier: Optional[int], rotation: Optional[float]) -> None:
angle_string = node.get(attrib, default)
if angle_string is None:
return
try:
angle = float(angle_string)
except ValueError:
return
if multiplier is not None:
angle *= multiplier
elif rotation is not None:
angle -= rotation
node.set(attrib, str(angle))
def _rotate_tartan_pattern(self, node: ShapeElement, multiplier: Optional[int], rotation: Optional[float]) -> None:
settings = get_tartan_settings(node)
tartan_rotation = settings['rotate']
if multiplier is not None:
tartan_rotation *= multiplier
elif rotation is not None:
tartan_rotation += rotation
settings['rotate'] = tartan_rotation
node.set("inkstitch:tartan", json.dumps(settings))

Wyświetl plik

@ -0,0 +1,38 @@
<?xml version="1.0" encoding="UTF-8"?>
<inkscape-extension translationdomain="inkstitch" xmlns="http://www.inkscape.org/namespace/inkscape/extension">
<name>Transform</name>
<id>org.{{ id_inkstitch }}.transform_elements</id>
<param name="extension" type="string" gui-hidden="true">transform_elements</param>
<param name="notebook" type="notebook">
<page name="options" gui-text="Options">
<param name="rotate" type="float" precision="2" min="-180" max="180" appearance="full"
gui-text="Rotate">0</param>
<param name="flip-horizontally" type="bool" gui-text="Flip horizontally">false</param>
<param name="flip-vertically" type="bool" gui-text="Flip vertically">false</param>
</page>
<page name="info" gui-text="Help">
<label>
This extension applies transformations while also adjusting the fill angles
</label>
<spacer />
<label>More information on our website</label>
<label appearance="url">https://inkstitch.org/docs/edit/#transform</label>
</page>
</param>
<effect>
<object-type>all</object-type>
<icon>{{ icon_path }}inx/break_apart_fill.svg</icon>
<menu-tip>Break apart and repair (broken) fill shapes</menu-tip>
<effects-menu>
<submenu name="{{ menu_inkstitch }}" translatable="no">
<submenu name="Edit" />
</submenu>
</effects-menu>
</effect>
<script>
{{ command_tag | safe }}
</script>
</inkscape-extension>