[Path] preserve cap extensions in normalized form, and scale them with scale()
This commit is contained in:
parent
1bcf5901d6
commit
3beadd2bf0
3 changed files with 52 additions and 2 deletions
|
|
@ -453,6 +453,8 @@ class Path(Shape):
|
||||||
def scale_by(self, c: float) -> 'Path':
|
def scale_by(self, c: float) -> 'Path':
|
||||||
self.vertices *= c
|
self.vertices *= c
|
||||||
self.width *= c
|
self.width *= c
|
||||||
|
if self.cap_extensions is not None:
|
||||||
|
self.cap_extensions *= c
|
||||||
return self
|
return self
|
||||||
|
|
||||||
def normalized_form(self, norm_value: float) -> normalized_shape_tuple:
|
def normalized_form(self, norm_value: float) -> normalized_shape_tuple:
|
||||||
|
|
@ -476,13 +478,15 @@ class Path(Shape):
|
||||||
reordered_vertices = rotated_vertices
|
reordered_vertices = rotated_vertices
|
||||||
|
|
||||||
width0 = self.width / norm_value
|
width0 = self.width / norm_value
|
||||||
|
cap_extensions0 = None if self.cap_extensions is None else tuple(float(v) / norm_value for v in self.cap_extensions)
|
||||||
|
|
||||||
return ((type(self), reordered_vertices.data.tobytes(), width0, self.cap),
|
return ((type(self), reordered_vertices.data.tobytes(), width0, self.cap, cap_extensions0),
|
||||||
(offset, scale / norm_value, rotation, False),
|
(offset, scale / norm_value, rotation, False),
|
||||||
lambda: Path(
|
lambda: Path(
|
||||||
reordered_vertices * norm_value,
|
reordered_vertices * norm_value,
|
||||||
width=width0 * norm_value,
|
width=width0 * norm_value,
|
||||||
cap=self.cap,
|
cap=self.cap,
|
||||||
|
cap_extensions=None if cap_extensions0 is None else tuple(v * norm_value for v in cap_extensions0),
|
||||||
))
|
))
|
||||||
|
|
||||||
def clean_vertices(self) -> 'Path':
|
def clean_vertices(self) -> 'Path':
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,7 @@ from ..pattern import Pattern
|
||||||
from ..error import LibraryError, PatternError
|
from ..error import LibraryError, PatternError
|
||||||
from ..ports import Port
|
from ..ports import Port
|
||||||
from ..repetition import Grid
|
from ..repetition import Grid
|
||||||
|
from ..shapes import Path
|
||||||
from ..file.utils import preflight
|
from ..file.utils import preflight
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
|
|
@ -243,3 +244,18 @@ def test_library_get_name() -> None:
|
||||||
|
|
||||||
name2 = lib.get_name("other")
|
name2 = lib.get_name("other")
|
||||||
assert name2 == "other"
|
assert name2 == "other"
|
||||||
|
|
||||||
|
|
||||||
|
def test_library_dedup_shapes_does_not_merge_custom_capped_paths() -> None:
|
||||||
|
lib = Library()
|
||||||
|
pat = Pattern()
|
||||||
|
pat.shapes[(1, 0)] += [
|
||||||
|
Path(vertices=[[0, 0], [10, 0]], width=2, cap=Path.Cap.SquareCustom, cap_extensions=(1, 2)),
|
||||||
|
Path(vertices=[[20, 0], [30, 0]], width=2, cap=Path.Cap.SquareCustom, cap_extensions=(3, 4)),
|
||||||
|
]
|
||||||
|
lib["top"] = pat
|
||||||
|
|
||||||
|
lib.dedup(norm_value=1, threshold=2)
|
||||||
|
|
||||||
|
assert not lib["top"].refs
|
||||||
|
assert len(lib["top"].shapes[(1, 0)]) == 2
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
from numpy.testing import assert_equal
|
from numpy.testing import assert_equal, assert_allclose
|
||||||
|
|
||||||
from ..shapes import Path
|
from ..shapes import Path
|
||||||
|
|
||||||
|
|
@ -79,3 +79,33 @@ def test_path_scale() -> None:
|
||||||
p.scale_by(2)
|
p.scale_by(2)
|
||||||
assert_equal(p.vertices, [[0, 0], [20, 0]])
|
assert_equal(p.vertices, [[0, 0], [20, 0]])
|
||||||
assert p.width == 4
|
assert p.width == 4
|
||||||
|
|
||||||
|
|
||||||
|
def test_path_scale_custom_cap_extensions() -> None:
|
||||||
|
p = Path(vertices=[[0, 0], [10, 0]], width=2, cap=Path.Cap.SquareCustom, cap_extensions=(1, 2))
|
||||||
|
p.scale_by(3)
|
||||||
|
|
||||||
|
assert_equal(p.vertices, [[0, 0], [30, 0]])
|
||||||
|
assert p.width == 6
|
||||||
|
assert p.cap_extensions is not None
|
||||||
|
assert_allclose(p.cap_extensions, [3, 6])
|
||||||
|
assert_equal(p.to_polygons()[0].get_bounds_single(), [[-3, -3], [36, 3]])
|
||||||
|
|
||||||
|
|
||||||
|
def test_path_normalized_form_preserves_width_and_custom_cap_extensions() -> None:
|
||||||
|
p = Path(vertices=[[0, 0], [10, 0]], width=2, cap=Path.Cap.SquareCustom, cap_extensions=(1, 2))
|
||||||
|
|
||||||
|
intrinsic, _extrinsic, ctor = p.normalized_form(5)
|
||||||
|
q = ctor()
|
||||||
|
|
||||||
|
assert intrinsic[-1] == (0.2, 0.4)
|
||||||
|
assert q.width == 2
|
||||||
|
assert q.cap_extensions is not None
|
||||||
|
assert_allclose(q.cap_extensions, [1, 2])
|
||||||
|
|
||||||
|
|
||||||
|
def test_path_normalized_form_distinguishes_custom_caps() -> None:
|
||||||
|
p1 = Path(vertices=[[0, 0], [10, 0]], width=2, cap=Path.Cap.SquareCustom, cap_extensions=(1, 2))
|
||||||
|
p2 = Path(vertices=[[0, 0], [10, 0]], width=2, cap=Path.Cap.SquareCustom, cap_extensions=(3, 4))
|
||||||
|
|
||||||
|
assert p1.normalized_form(1)[0] != p2.normalized_form(1)[0]
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue