Clean-up of clone code (#2851)

pull/2872/head
capellancitizen 2024-04-23 18:09:32 -04:00 zatwierdzone przez GitHub
rodzic 275843c2b2
commit cca25ba679
Nie znaleziono w bazie danych klucza dla tego podpisu
ID klucza GPG: B5690EEEBB952194
2 zmienionych plików z 26 dodań i 19 usunięć

Wyświetl plik

@ -4,11 +4,10 @@
# Licensed under the GNU GPL version 3.0 or later. See the file LICENSE for details. # Licensed under the GNU GPL version 3.0 or later. See the file LICENSE for details.
from math import degrees from math import degrees
from copy import deepcopy
from contextlib import contextmanager from contextlib import contextmanager
from typing import Generator, List from typing import Generator, List
from inkex import Transform, BaseElement, Style from inkex import Transform, BaseElement
from shapely import MultiLineString from shapely import MultiLineString
from ..stitch_plan.stitch_group import StitchGroup from ..stitch_plan.stitch_group import StitchGroup
@ -43,7 +42,7 @@ class Clone(EmbroideryElement):
@property @property
@param('clone', _("Clone"), type='toggle', inverse=False, default=True) @param('clone', _("Clone"), type='toggle', inverse=False, default=True)
def clone(self): def clone(self):
return self.get_boolean_param("clone") return self.get_boolean_param("clone", True)
@property @property
@param('angle', @param('angle',
@ -81,6 +80,9 @@ class Clone(EmbroideryElement):
return elements return elements
def to_stitch_groups(self, last_stitch_group=None) -> List[StitchGroup]: def to_stitch_groups(self, last_stitch_group=None) -> List[StitchGroup]:
if not self.clone:
return []
with self.clone_elements() as elements: with self.clone_elements() as elements:
stitch_groups = [] stitch_groups = []
@ -123,22 +125,18 @@ class Clone(EmbroideryElement):
parent: BaseElement = self.node.getparent() parent: BaseElement = self.node.getparent()
source_node: BaseElement = self.node.href source_node: BaseElement = self.node.href
source_parent: BaseElement = source_node.getparent() source_parent: BaseElement = source_node.getparent()
cloned_node = deepcopy(source_node) cloned_node = source_node.copy()
if recursive: if recursive:
# Recursively resolve all clones as if the clone was in the same place as its source # Recursively resolve all clones as if the clone was in the same place as its source
source_parent.add(cloned_node) source_parent.add(cloned_node)
if is_clone(cloned_node): if is_clone(cloned_node):
resolved_cloned_node = Clone(cloned_node).resolve_clone() cloned_node = cloned_node.replace_with(Clone(cloned_node).resolve_clone())
cloned_node.getparent().remove(cloned_node)
# Replace the cloned_node with its resolved version
cloned_node = resolved_cloned_node
else: else:
clones: List[BaseElement] = [n for n in cloned_node.iterdescendants() if is_clone(n)] clones: List[BaseElement] = [n for n in cloned_node.iterdescendants() if is_clone(n)]
for clone in clones: for clone in clones:
Clone(clone).resolve_clone() clone.replace_with(Clone(clone).resolve_clone())
clone.getparent().remove(clone)
source_parent.remove(cloned_node) source_parent.remove(cloned_node)
@ -146,14 +144,10 @@ class Clone(EmbroideryElement):
parent.add(cloned_node) parent.add(cloned_node)
# The transform of a resolved clone is based on the clone's transform as well as the source element's transform. # The transform of a resolved clone is based on the clone's transform as well as the source element's transform.
# This makes intuitive sense: The clone of a scaled item is also scaled, the clone of a rotated item is also rotated, etc. # This makes intuitive sense: The clone of a scaled item is also scaled, the clone of a rotated item is also rotated, etc.
cloned_node.set('transform', Transform(self.node.get('transform')) @ Transform(cloned_node.get('transform'))) cloned_node.transform = self.node.transform @ cloned_node.transform
# Merge the style, if any: Note that the source node's style applies on top of the use's, not the other way around. # Merge the style, if any: Note that the source node's style applies on top of the use's, not the other way around.
clone_style = self.node.get('style') cloned_node.style = self.node.style + cloned_node.style
if clone_style:
merged_style = Style(clone_style)
merged_style.update(cloned_node.get('style'))
cloned_node.set('style', merged_style)
# Compute angle transform: # Compute angle transform:
# Effectively, this is (local clone transform) * (to parent space) * (from clone's parent space) # Effectively, this is (local clone transform) * (to parent space) * (from clone's parent space)
@ -174,7 +168,6 @@ class Clone(EmbroideryElement):
# Otherwise we'd have to calculate the transform of (0,0) and subtract it from the transform of (1,0) # Otherwise we'd have to calculate the transform of (0,0) and subtract it from the transform of (1,0)
angle_transform = Transform((transform.a, transform.b, transform.c, transform.d, 0.0, 0.0)) angle_transform = Transform((transform.a, transform.b, transform.c, transform.d, 0.0, 0.0))
elements = self.clone_to_elements(cloned_node)
for node in cloned_node.iter(): for node in cloned_node.iter():
# Only need to adjust angles on embroiderable nodes # Only need to adjust angles on embroiderable nodes
if node.tag not in EMBROIDERABLE_TAGS: if node.tag not in EMBROIDERABLE_TAGS:
@ -195,8 +188,6 @@ class Clone(EmbroideryElement):
node.set(INKSTITCH_ATTRIBS['angle'], round(element_angle, 6)) node.set(INKSTITCH_ATTRIBS['angle'], round(element_angle, 6))
return elements
@property @property
def shape(self): def shape(self):
path = self.node.get_path() path = self.node.get_path()

Wyświetl plik

@ -34,6 +34,22 @@ class CloneElementTest(TestCase):
stitch_groups = clone.to_stitch_groups(None) stitch_groups = clone.to_stitch_groups(None)
self.assertEqual(len(stitch_groups), 0) self.assertEqual(len(stitch_groups), 0)
def test_not_clone(self):
root: SvgDocumentElement = svg()
rect = root.add(Rectangle(attrib={
"width": "10",
"height": "10",
INKSTITCH_ATTRIBS["angle"]: "30"
}))
use = root.add(Use(attrib={
INKSTITCH_ATTRIBS["clone"]: "false"
}))
use.href = rect
clone = Clone(use)
stitch_groups = clone.to_stitch_groups(None)
self.assertEqual(len(stitch_groups), 0)
# These tests make sure the element cloning works as expected, using the `clone_elements` method. # These tests make sure the element cloning works as expected, using the `clone_elements` method.
def test_basic(self): def test_basic(self):