move StitchGroup into lib.stitch_plan

pull/1254/head
Lex Neva 2021-08-07 11:21:13 -04:00
rodzic 12ef0c84aa
commit 84cb4e2c33
11 zmienionych plików z 197 dodań i 183 usunięć

Wyświetl plik

@ -9,13 +9,14 @@ import traceback
from shapely import geometry as shgeo
from .element import param
from .fill import Fill
from .validation import ValidationWarning
from ..i18n import _
from ..stitch_plan import StitchGroup
from ..stitches import auto_fill
from ..svg.tags import INKSCAPE_LABEL
from ..utils import cache, version
from .element import StitchGroup, param
from .fill import Fill
from .validation import ValidationWarning
class SmallShapeWarning(ValidationWarning):

Wyświetl plik

@ -18,34 +18,6 @@ from ..svg.tags import INKSCAPE_LABEL, INKSTITCH_ATTRIBS
from ..utils import Point, cache
class StitchGroup:
"""A raw collection of stitches with attached instructions."""
def __init__(self, color=None, stitches=None, trim_after=False, stop_after=False, tie_modus=0, stitch_as_is=False):
self.color = color
self.stitches = stitches or []
self.trim_after = trim_after
self.stop_after = stop_after
self.tie_modus = tie_modus
self.stitch_as_is = stitch_as_is
def __add__(self, other):
if isinstance(other, StitchGroup):
return StitchGroup(self.color, self.stitches + other.stitches)
else:
raise TypeError("StitchGroup can only be added to another StitchGroup")
def __len__(self):
# This method allows `len(patch)` and `if patch:
return len(self.stitches)
def add_stitch(self, stitch):
self.stitches.append(stitch)
def reverse(self):
return StitchGroup(self.color, self.stitches[::-1])
class Param(object):
def __init__(self, name, description, unit=None, values=[], type=None, group=None, inverse=False,
options=[], default=None, tooltip=None, sort_index=0):

Wyświetl plik

@ -10,12 +10,13 @@ import re
from shapely import geometry as shgeo
from shapely.validation import explain_validity
from .element import EmbroideryElement, param
from .validation import ValidationError
from ..i18n import _
from ..stitch_plan import StitchGroup
from ..stitches import legacy_fill
from ..svg import PIXELS_PER_MM
from ..utils import cache
from .element import EmbroideryElement, StitchGroup, param
from .validation import ValidationError
class UnconnectedError(ValidationError):

Wyświetl plik

@ -6,11 +6,12 @@
from inkex import Path
from shapely import geometry as shgeo
from .element import EmbroideryElement, param
from .validation import ValidationWarning
from ..i18n import _
from ..stitch_plan import StitchGroup
from ..utils import cache
from ..utils.geometry import Point
from .element import EmbroideryElement, StitchGroup, param
from .validation import ValidationWarning
class PolylineWarning(ValidationWarning):

Wyświetl plik

@ -11,11 +11,12 @@ from shapely import affinity as shaffinity
from shapely import geometry as shgeo
from shapely.ops import nearest_points
from .element import EmbroideryElement, param
from .validation import ValidationError, ValidationWarning
from ..i18n import _
from ..stitch_plan import StitchGroup
from ..svg import line_strings_to_csp, point_lists_to_csp
from ..utils import Point, cache, collapse_duplicate_point, cut
from .element import EmbroideryElement, StitchGroup, param
from .validation import ValidationError, ValidationWarning
class SatinHasFillError(ValidationError):

Wyświetl plik

@ -7,11 +7,12 @@ import sys
import shapely.geometry
from .element import EmbroideryElement, param
from ..i18n import _
from ..stitch_plan import StitchGroup
from ..stitches import bean_stitch, running_stitch
from ..svg import parse_length_with_units
from ..utils import Point, cache
from .element import EmbroideryElement, StitchGroup, param
warned_about_legacy_running_stitch = False

Wyświetl plik

@ -3,6 +3,8 @@
# Copyright (c) 2010 Authors
# Licensed under the GNU GPL version 3.0 or later. See the file LICENSE for details.
from .stitch_plan import patches_to_stitch_plan, StitchPlan, ColorBlock
from .stitch_plan import patches_to_stitch_plan, StitchPlan
from .color_block import ColorBlock
from .stitch_group import StitchGroup
from .stitch import Stitch
from .read_file import stitch_plan_from_file

Wyświetl plik

@ -0,0 +1,142 @@
from .stitch import Stitch
from ..threads import ThreadColor
from ..utils.geometry import Point
from ..svg import PIXELS_PER_MM
class ColorBlock(object):
"""Holds a set of stitches, all with the same thread color."""
def __init__(self, color=None, stitches=None):
self.color = color
self.stitches = stitches or []
def __iter__(self):
return iter(self.stitches)
def __len__(self):
return len(self.stitches)
def __repr__(self):
return "ColorBlock(%s, %s)" % (self.color, self.stitches)
def __getitem__(self, item):
return self.stitches[item]
def __delitem__(self, item):
del self.stitches[item]
def __json__(self):
return dict(color=self.color, stitches=self.stitches)
def has_color(self):
return self._color is not None
@property
def color(self):
return self._color
@color.setter
def color(self, value):
if isinstance(value, ThreadColor):
self._color = value
elif value is None:
self._color = None
else:
self._color = ThreadColor(value)
@property
def last_stitch(self):
if self.stitches:
return self.stitches[-1]
else:
return None
@property
def num_stitches(self):
"""Number of stitches in this color block."""
return len(self.stitches)
@property
def num_trims(self):
"""Number of trims in this color block."""
return sum(1 for stitch in self if stitch.trim)
@property
def stop_after(self):
if self.last_stitch is not None:
return self.last_stitch.stop
else:
return False
@property
def trim_after(self):
# If there's a STOP, it will be at the end. We still want to return
# True.
for stitch in reversed(self.stitches):
if stitch.stop or stitch.jump:
continue
elif stitch.trim:
return True
else:
break
return False
def filter_duplicate_stitches(self):
if not self.stitches:
return
stitches = [self.stitches[0]]
for stitch in self.stitches[1:]:
if stitches[-1].jump or stitch.stop or stitch.trim or stitch.color_change:
# Don't consider jumps, stops, color changes, or trims as candidates for filtering
pass
else:
length = (stitch - stitches[-1]).length()
if length <= 0.1 * PIXELS_PER_MM:
# duplicate stitch, skip this one
continue
stitches.append(stitch)
self.stitches = stitches
def add_stitch(self, *args, **kwargs):
if not args:
# They're adding a command, e.g. `color_block.add_stitch(stop=True)``.
# Use the position from the last stitch.
if self.last_stitch:
args = (self.last_stitch.x, self.last_stitch.y)
else:
raise ValueError("internal error: can't add a command to an empty stitch block")
if isinstance(args[0], Stitch):
self.stitches.append(args[0])
elif isinstance(args[0], Point):
self.stitches.append(Stitch(args[0].x, args[0].y, *args[1:], **kwargs))
else:
if not args and self.last_stitch:
args = (self.last_stitch.x, self.last_stitch.y)
self.stitches.append(Stitch(*args, **kwargs))
def add_stitches(self, stitches, *args, **kwargs):
for stitch in stitches:
if isinstance(stitch, (Stitch, Point)):
self.add_stitch(stitch, *args, **kwargs)
else:
self.add_stitch(*stitch, *args, **kwargs)
def replace_stitches(self, stitches):
self.stitches = stitches
@property
def bounding_box(self):
minx = min(stitch.x for stitch in self)
miny = min(stitch.y for stitch in self)
maxx = max(stitch.x for stitch in self)
maxy = max(stitch.y for stitch in self)
return minx, miny, maxx, maxy

Wyświetl plik

@ -8,8 +8,7 @@ from ..utils.geometry import Point
class Stitch(Point):
def __init__(self, x, y=None, color=None, jump=False, stop=False, trim=False, color_change=False, tie_modus=0, no_ties=False):
self.x = x
self.y = y
Point.__init__(self, x, y)
self.color = color
self.jump = jump
self.trim = trim

Wyświetl plik

@ -0,0 +1,34 @@
class StitchGroup:
"""A collection of Stitch objects with attached instructions.
StitchGroups will later be combined to make ColorBlocks, which in turn are
combined to make a StitchPlan. Jump stitches are allowed between
StitchGroups, but not between stitches inside a StitchGroup. This means
that EmbroideryElement classes should produce multiple StitchGroups only if
they want to allow for the possibility of jump stitches to be added in
between them by the stitch plan generation code.
"""
def __init__(self, color=None, stitches=None, trim_after=False, stop_after=False, tie_modus=0, stitch_as_is=False):
self.color = color
self.stitches = stitches or []
self.trim_after = trim_after
self.stop_after = stop_after
self.tie_modus = tie_modus
self.stitch_as_is = stitch_as_is
def __add__(self, other):
if isinstance(other, StitchGroup):
return StitchGroup(self.color, self.stitches + other.stitches)
else:
raise TypeError("StitchGroup can only be added to another StitchGroup")
def __len__(self):
# This method allows `len(patch)` and `if patch:
return len(self.stitches)
def add_stitch(self, stitch):
self.stitches.append(stitch)
def reverse(self):
return StitchGroup(self.color, self.stitches[::-1])

Wyświetl plik

@ -3,11 +3,9 @@
# Copyright (c) 2010 Authors
# Licensed under the GNU GPL version 3.0 or later. See the file LICENSE for details.
from ..svg import PIXELS_PER_MM
from ..threads import ThreadColor
from ..utils.geometry import Point
from .stitch import Stitch
from .ties import add_ties
from .color_block import ColorBlock
from ..svg import PIXELS_PER_MM
def patches_to_stitch_plan(patches, collapse_len=None, disable_ties=False): # noqa: C901
@ -168,141 +166,3 @@ class StitchPlan(object):
return self.color_blocks[-1]
else:
return None
class ColorBlock(object):
"""Holds a set of stitches, all with the same thread color."""
def __init__(self, color=None, stitches=None):
self.color = color
self.stitches = stitches or []
def __iter__(self):
return iter(self.stitches)
def __len__(self):
return len(self.stitches)
def __repr__(self):
return "ColorBlock(%s, %s)" % (self.color, self.stitches)
def __getitem__(self, item):
return self.stitches[item]
def __delitem__(self, item):
del self.stitches[item]
def __json__(self):
return dict(color=self.color, stitches=self.stitches)
def has_color(self):
return self._color is not None
@property
def color(self):
return self._color
@color.setter
def color(self, value):
if isinstance(value, ThreadColor):
self._color = value
elif value is None:
self._color = None
else:
self._color = ThreadColor(value)
@property
def last_stitch(self):
if self.stitches:
return self.stitches[-1]
else:
return None
@property
def num_stitches(self):
"""Number of stitches in this color block."""
return len(self.stitches)
@property
def num_trims(self):
"""Number of trims in this color block."""
return sum(1 for stitch in self if stitch.trim)
@property
def stop_after(self):
if self.last_stitch is not None:
return self.last_stitch.stop
else:
return False
@property
def trim_after(self):
# If there's a STOP, it will be at the end. We still want to return
# True.
for stitch in reversed(self.stitches):
if stitch.stop or stitch.jump:
continue
elif stitch.trim:
return True
else:
break
return False
def filter_duplicate_stitches(self):
if not self.stitches:
return
stitches = [self.stitches[0]]
for stitch in self.stitches[1:]:
if stitches[-1].jump or stitch.stop or stitch.trim or stitch.color_change:
# Don't consider jumps, stops, color changes, or trims as candidates for filtering
pass
else:
length = (stitch - stitches[-1]).length()
if length <= 0.1 * PIXELS_PER_MM:
# duplicate stitch, skip this one
continue
stitches.append(stitch)
self.stitches = stitches
def add_stitch(self, *args, **kwargs):
if not args:
# They're adding a command, e.g. `color_block.add_stitch(stop=True)``.
# Use the position from the last stitch.
if self.last_stitch:
args = (self.last_stitch.x, self.last_stitch.y)
else:
raise ValueError("internal error: can't add a command to an empty stitch block")
if isinstance(args[0], Stitch):
self.stitches.append(args[0])
elif isinstance(args[0], Point):
self.stitches.append(Stitch(args[0].x, args[0].y, *args[1:], **kwargs))
else:
if not args and self.last_stitch:
args = (self.last_stitch.x, self.last_stitch.y)
self.stitches.append(Stitch(*args, **kwargs))
def add_stitches(self, stitches, *args, **kwargs):
for stitch in stitches:
if isinstance(stitch, (Stitch, Point)):
self.add_stitch(stitch, *args, **kwargs)
else:
self.add_stitch(*(list(stitch) + args), **kwargs)
def replace_stitches(self, stitches):
self.stitches = stitches
@property
def bounding_box(self):
minx = min(stitch.x for stitch in self)
miny = min(stitch.y for stitch in self)
maxx = max(stitch.x for stitch in self)
maxy = max(stitch.y for stitch in self)
return minx, miny, maxx, maxy