kopia lustrzana https://github.com/inkstitch/inkstitch
143 wiersze
4.4 KiB
Python
143 wiersze
4.4 KiB
Python
# Authors: see git history
|
|
#
|
|
# Copyright (c) 2010 Authors
|
|
# Licensed under the GNU GPL version 3.0 or later. See the file LICENSE for details.
|
|
|
|
from shapely import geometry as shgeo
|
|
|
|
from ..utils.geometry import Point
|
|
|
|
|
|
class Stitch(Point):
|
|
"""A stitch is a Point with extra information telling how to sew it."""
|
|
|
|
def __init__(
|
|
self,
|
|
x, y=None,
|
|
color=None,
|
|
jump=False,
|
|
stop=False,
|
|
trim=False,
|
|
color_change=False,
|
|
min_stitch_length=None,
|
|
tags=None
|
|
):
|
|
# DANGER: if you add new attributes, you MUST also set their default
|
|
# values in __new__() below. Otherwise, cached stitch plans can be
|
|
# loaded and create objects without those properties defined, because
|
|
# unpickling does not call __init__()!
|
|
|
|
base_stitch = None
|
|
if isinstance(x, Stitch):
|
|
# Allow creating a Stitch from another Stitch. Attributes passed as
|
|
# arguments will override any existing attributes.
|
|
base_stitch = x
|
|
self.x: float = base_stitch.x
|
|
self.y: float = base_stitch.y
|
|
elif isinstance(x, (Point, shgeo.Point)):
|
|
# Allow creating a Stitch from a Point
|
|
point = x
|
|
self.x: float = point.x
|
|
self.y: float = point.y
|
|
else:
|
|
Point.__init__(self, x, y)
|
|
|
|
self._set('color', color, base_stitch)
|
|
self._set('jump', jump, base_stitch)
|
|
self._set('trim', trim, base_stitch)
|
|
self._set('stop', stop, base_stitch)
|
|
self._set('color_change', color_change, base_stitch)
|
|
self._set('min_stitch_length', min_stitch_length, base_stitch)
|
|
|
|
self.tags = set()
|
|
self.add_tags(tags or [])
|
|
if base_stitch is not None:
|
|
self.add_tags(base_stitch.tags)
|
|
|
|
def __new__(cls, *args, **kwargs):
|
|
instance = super().__new__(cls)
|
|
|
|
# Set default values for any new attributes here (see note in __init__() above)
|
|
# instance.foo = None
|
|
|
|
return instance
|
|
|
|
def __repr__(self):
|
|
return "Stitch(%s, %s, %s, %s, %s, %s, %s, %s)" % (
|
|
self.x,
|
|
self.y,
|
|
self.color,
|
|
self.min_stitch_length,
|
|
"JUMP" if self.jump else " ",
|
|
"TRIM" if self.trim else " ",
|
|
"STOP" if self.stop else " ",
|
|
"COLOR CHANGE" if self.color_change else " "
|
|
)
|
|
|
|
def _set(self, attribute, value, base_stitch):
|
|
# Set an attribute. If the caller passed a Stitch object, use its value, unless
|
|
# they overrode it with arguments.
|
|
if base_stitch is not None:
|
|
setattr(self, attribute, getattr(base_stitch, attribute))
|
|
if value or base_stitch is None:
|
|
setattr(self, attribute, value)
|
|
|
|
@property
|
|
def is_terminator(self) -> bool:
|
|
return self.trim or self.stop or self.color_change
|
|
|
|
def add_tags(self, tags):
|
|
for tag in tags:
|
|
self.add_tag(tag)
|
|
|
|
def add_tag(self, tag):
|
|
"""Store arbitrary information about a stitch.
|
|
|
|
Tags can be used to store any information about a stitch. This can be
|
|
used by other parts of the code to keep track of where a Stitch came
|
|
from. The Stitch treats tags as opaque.
|
|
|
|
Use strings as tags. Python automatically optimizes this kind of
|
|
usage of strings, and it doesn't have to constantly do string
|
|
comparisons. More details here:
|
|
|
|
https://stackabuse.com/guide-to-string-interning-in-python
|
|
"""
|
|
self.tags.add(tag)
|
|
|
|
def has_tag(self, tag):
|
|
return tag in self.tags
|
|
|
|
def copy(self):
|
|
return Stitch(
|
|
self.x,
|
|
self.y,
|
|
self.color,
|
|
self.jump,
|
|
self.stop,
|
|
self.trim,
|
|
self.color_change,
|
|
self.min_stitch_length,
|
|
self.tags
|
|
)
|
|
|
|
def offset(self, offset: Point):
|
|
out = self.copy()
|
|
out.x += offset.x
|
|
out.y += offset.y
|
|
return out
|
|
|
|
def __json__(self):
|
|
attributes = dict(vars(self))
|
|
attributes['tags'] = list(attributes['tags'])
|
|
return attributes
|
|
|
|
def __getstate__(self):
|
|
# This is used by pickle. We want to sort the tag list so that the
|
|
# pickled representation is stable, since it's used to generate cache
|
|
# keys.
|
|
state = self.__json__()
|
|
state['tags'].sort()
|
|
|
|
return state
|