kopia lustrzana https://github.com/inkstitch/inkstitch
Clean-up of clone code (#2851)
rodzic
275843c2b2
commit
cca25ba679
|
@ -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()
|
||||||
|
|
|
@ -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):
|
||||||
|
|
Ładowanie…
Reference in New Issue