diff options
| author | Lex Neva <lexelby@users.noreply.github.com> | 2025-01-29 12:04:07 -0500 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2025-01-29 12:04:07 -0500 |
| commit | 913c2700d1486284dba0583ae1b280b1aa237570 (patch) | |
| tree | c165b29d0794981b5e44ab46f9838baab16b06a4 /lib/sew_stack/stitch_layers/running_stitch | |
| parent | efe3b27f17686094f74462bd81763a8197b54c6e (diff) | |
Sew Stack first steps (#3133)
* handle more recursive cases
* scaffolding for stitch layers
* scaffolding for SewStack
* always use DotDict when parsing json params
* add DefaultDotDict + DotDict fixes
* first working SewStack (no UI yet)
* ignore inkstitch_debug.log and .svg
* refactor
* early WIP: property grid display temporarily in stitch plan preview
* start of sew stack editor extension
* add layer properties panel and splitter
* spacing and better icon
* handle checkbox
* add layer action buttons
* show selected property help text in an HtmlWindow
* rename
* rephrase help text for tolerance
* refactor into separate file
* simplify structure
* better property type handling
* add randomization button
* add random seed re-roll button
* simulator preview
* update preview in a few more cases
* always DotDict
* avoid ridiculously slow simulations
* preview selected layer or all layers
* edit multiple objects and save only modified properties into the SVG
* better preview handling
* add reverse and jitter
* add stitch path jitter
* fix types
* fix random shuffle button
* fixes
* fix repeats
* type hinting to please pycharm
* show layer description
* avoid exception in properties with multiple values
* fix typing
* fix new layer
* draw a box around property grid and help box
* confirm before closing
* rename properties and fix seed
* fix close/cancel logic
* add buttons to undo changes and reset to default value
* set not modified if default is original setting
* fix invisible icon
* more space for properties
* fix random properties
* better regulation of simulator rendering speed
* Fixed timer being passed a float
* fix get_json_param() default handling
* fix tests
* add checkbox for sew stack only
* fix property help
* adjustable stitch layer editor help box size, with persistence
* repeat exact stitches
* "fix" style
* adjust for new next_element stuff
---------
Co-authored-by: CapellanCitizen <thecapellancitizen@gmail.com>
Diffstat (limited to 'lib/sew_stack/stitch_layers/running_stitch')
| -rw-r--r-- | lib/sew_stack/stitch_layers/running_stitch/__init__.py | 1 | ||||
| -rw-r--r-- | lib/sew_stack/stitch_layers/running_stitch/running_stitch_layer.py | 126 |
2 files changed, 127 insertions, 0 deletions
diff --git a/lib/sew_stack/stitch_layers/running_stitch/__init__.py b/lib/sew_stack/stitch_layers/running_stitch/__init__.py new file mode 100644 index 00000000..4eda9659 --- /dev/null +++ b/lib/sew_stack/stitch_layers/running_stitch/__init__.py @@ -0,0 +1 @@ +from .running_stitch_layer import RunningStitchLayer diff --git a/lib/sew_stack/stitch_layers/running_stitch/running_stitch_layer.py b/lib/sew_stack/stitch_layers/running_stitch/running_stitch_layer.py new file mode 100644 index 00000000..0892ed44 --- /dev/null +++ b/lib/sew_stack/stitch_layers/running_stitch/running_stitch_layer.py @@ -0,0 +1,126 @@ +from copy import copy + +from ..mixins.path import PathMixin, PathPropertiesMixin +from ..mixins.randomization import RandomizationPropertiesMixin, RandomizationMixin +from ..stitch_layer import StitchLayer +from ..stitch_layer_editor import Category, Properties, Property +from ..stitch_layer_editor import StitchLayerEditor +from ....i18n import _ +from ....stitch_plan import StitchGroup +from ....stitches.running_stitch import running_stitch +from ....svg import PIXELS_PER_MM + + +class RunningStitchLayerEditor(StitchLayerEditor, RandomizationPropertiesMixin, PathPropertiesMixin): + @classmethod + @property + def properties(cls): + return Properties( + Category(_("Running Stitch"), help=_("Stitch along a path using evenly-spaced stitches.")).children( + Property("stitch_length", _("Stitch length"), + help=_('Length of stitches. Stitches can be shorter according to the stitch tolerance setting.'), + min=0.1, + unit="mm", + ), + Property("tolerance", _("Tolerance"), + help=_('Determines how closely the stitch path matches the SVG path. ' + + 'A lower tolerance means stitches will be closer together and ' + + 'fit the SVG path more precisely. A higher tolerance means ' + + 'some corners may be rounded and fewer stitches are needed.'), + min=0.01, + unit="mm", + ), + Category(_("Repeats")).children( + Property( + "repeats", _("Repeats"), + help=_('Defines how many times to run down and back along the path.'), + type=int, + min=1, + ), + Property( + "repeat_stitches", _("Repeat exact stitches"), + type=bool, + help=_('Should the exact same stitches be repeated in each pass? ' + + 'If not, different randomization settings are applied on each pass.'), + ), + ), + cls.path_properties(), + ), + cls.randomization_properties().children( + Property( + "stitch_length_jitter_percent", _('Stitch length variance'), + help=_('Enter a percentage. Stitch length will vary randomly by up to this percentage.'), + prefix="±", + unit="%", + ), + ), + ) + + +class RunningStitchLayer(StitchLayer, RandomizationMixin, PathMixin): + editor_class = RunningStitchLayerEditor + + @classmethod + @property + def defaults(cls): + defaults = dict( + name=_("Running Stitch"), + type_name=_("Running Stitch"), + stitch_length=2, + tolerance=0.2, + stitch_length_jitter_percent=0, + repeats=1, + repeat_stitches=True, + reverse_path=False, + ) + defaults.update(cls.randomization_defaults()) + + return defaults + + @property + def layer_type_name(self): + return _("Running Stitch") + + def get_num_copies(self): + if self.config.repeat_stitches: + # When repeating stitches, we use multiple copies of one pass of running stitch + return 1 + else: + # Otherwise, we re-run running stitch every time, so that + # randomization is different every pass + return self.config.repeats + + def running_stitch(self, path): + stitches = [] + + for i in range(self.get_num_copies()): + if i % 2 == 0: + this_path = path + else: + this_path = list(reversed(path)) + + stitches.extend(running_stitch( + this_path, + self.config.stitch_length * PIXELS_PER_MM, + self.config.tolerance * PIXELS_PER_MM, + (self.config.stitch_length_jitter_percent > 0), + self.config.stitch_length_jitter_percent, + self.get_random_seed() + )) + + self.offset_stitches(stitches) + + if self.config.repeats > 0 and self.config.repeat_stitches: + repeated_stitches = [] + for i in range(self.config.repeats): + if i % 2 == 0: + repeated_stitches.extend(copy(stitches)) + else: + # reverse every other pass + repeated_stitches.extend(reversed(copy(stitches))) + stitches = repeated_stitches + + return StitchGroup(stitches=stitches, color=self.stroke_color) + + def to_stitch_groups(self, previous_stitch_group, next_element): + return [self.running_stitch(path) for path in self.get_paths()] |
