diff options
| author | Lex Neva <lexelby@users.noreply.github.com> | 2018-09-29 13:22:05 -0600 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2018-09-29 13:22:05 -0600 |
| commit | 5139c13fd7f43bb4d829e3c8225c51268e4d27d1 (patch) | |
| tree | 8d89cf6fc362aa261baf9f63d68653c50fe72aa5 | |
| parent | ee7ed8f679dd493bd8991ede51bc741c47567b51 (diff) | |
| parent | 5e9cb83a9375a2b6312f390e84e4ac8e778d04cb (diff) | |
Merge pull request #316 from inkstitch/lexelby/bug-fixes
more bug fixes
| -rw-r--r-- | Makefile | 2 | ||||
| -rw-r--r-- | lib/extensions/params.py | 127 | ||||
| -rw-r--r-- | lib/stitch_plan/stitch.py | 28 | ||||
| -rw-r--r-- | lib/stitch_plan/ties.py | 34 | ||||
| -rw-r--r-- | lib/svg/units.py | 5 |
5 files changed, 108 insertions, 88 deletions
@@ -60,4 +60,4 @@ locales: .PHONY: style style: - flake8 . --count --max-complexity=10 --max-line-length=150 --statistics --exclude=pyembroidery,__init__.py,simulator.py,params.py + flake8 . --count --max-complexity=10 --max-line-length=150 --statistics --exclude=pyembroidery,__init__.py diff --git a/lib/extensions/params.py b/lib/extensions/params.py index b1db1b31..1f3032ca 100644 --- a/lib/extensions/params.py +++ b/lib/extensions/params.py @@ -4,20 +4,18 @@ import os import sys import json import traceback -import time from threading import Thread, Event from copy import copy import wx from wx.lib.scrolledpanel import ScrolledPanel from collections import defaultdict -from functools import partial from itertools import groupby from .base import InkstitchExtension from ..i18n import _ from ..stitch_plan import patches_to_stitch_plan from ..elements import EmbroideryElement, Fill, AutoFill, Stroke, SatinColumn -from ..utils import save_stderr, restore_stderr, get_resource_dir +from ..utils import get_resource_dir from ..simulator import EmbroiderySimulator from ..commands import is_command @@ -39,7 +37,7 @@ def load_presets(): with open(presets_path(), 'r') as presets: presets = json.load(presets) return presets - except: + except IOError: return {} @@ -64,14 +62,14 @@ def delete_preset(name): save_presets(presets) -def confirm_dialog(parent, question, caption = 'ink/stitch'): +def confirm_dialog(parent, question, caption='ink/stitch'): dlg = wx.MessageDialog(parent, question, caption, wx.YES_NO | wx.ICON_QUESTION) result = dlg.ShowModal() == wx.ID_YES dlg.Destroy() return result -def info_dialog(parent, message, caption = 'ink/stitch'): +def info_dialog(parent, message, caption='ink/stitch'): dlg = wx.MessageDialog(parent, message, caption, wx.OK | wx.ICON_INFORMATION) dlg.ShowModal() dlg.Destroy() @@ -298,12 +296,12 @@ class ParamsTab(ScrolledPanel): self.description.SetLabel(self.description_text) self.description_container = box self.Bind(wx.EVT_SIZE, self.resized) - sizer.Add(self.description, proportion=0, flag=wx.EXPAND|wx.ALL, border=5) + sizer.Add(self.description, proportion=0, flag=wx.EXPAND | wx.ALL, border=5) box.Add(sizer, proportion=0, flag=wx.ALL, border=5) if self.toggle: toggle_sizer = wx.BoxSizer(wx.HORIZONTAL) - toggle_sizer.Add(self.create_change_indicator(self.toggle.name), proportion = 0, flag=wx.ALIGN_CENTER_VERTICAL|wx.RIGHT, border=5) + toggle_sizer.Add(self.create_change_indicator(self.toggle.name), proportion=0, flag=wx.ALIGN_CENTER_VERTICAL | wx.RIGHT, border=5) toggle_sizer.Add(self.toggle_checkbox, proportion=0, flag=wx.ALIGN_CENTER_VERTICAL) box.Add(toggle_sizer, proportion=0, flag=wx.BOTTOM, border=10) @@ -312,7 +310,7 @@ class ParamsTab(ScrolledPanel): description = wx.StaticText(self, label=param.description) description.SetToolTip(param.tooltip) - self.settings_grid.Add(description, proportion=1, flag=wx.EXPAND|wx.RIGHT|wx.ALIGN_CENTER_VERTICAL|wx.TOP, border=5) + self.settings_grid.Add(description, proportion=1, flag=wx.EXPAND | wx.RIGHT | wx.ALIGN_CENTER_VERTICAL | wx.TOP, border=5) if param.type == 'boolean': @@ -336,7 +334,7 @@ class ParamsTab(ScrolledPanel): self.param_inputs[param.name] = input - self.settings_grid.Add(input, proportion=1, flag=wx.ALIGN_CENTER_VERTICAL|wx.EXPAND|wx.LEFT, border=40) + self.settings_grid.Add(input, proportion=1, flag=wx.ALIGN_CENTER_VERTICAL | wx.EXPAND | wx.LEFT, border=40) self.settings_grid.Add(wx.StaticText(self, label=param.unit or ""), proportion=1, flag=wx.ALIGN_CENTER_VERTICAL) self.inputs_to_params = {v: k for k, v in self.param_inputs.iteritems()} @@ -365,6 +363,7 @@ class ParamsTab(ScrolledPanel): # end of class SatinPane + class SettingsFrame(wx.Frame): def __init__(self, *args, **kwargs): # begin wxGlade: MyFrame.__init__ @@ -471,14 +470,14 @@ class SettingsFrame(wx.Frame): stitch_plan=stitch_plan, on_close=self.simulate_window_closed, target_duration=5) - except: + except Exception: error = traceback.format_exc() try: # a window may have been created, so we need to destroy it # or the app will never exit - wx.Window.FindWindowByName("Preview").Destroy() - except: + wx.Window.FindWindowByName(_("Preview")).Destroy() + except Exception: pass info_dialog(self, error, _("Internal Error")) @@ -517,7 +516,7 @@ class SettingsFrame(wx.Frame): patches.extend(copy(node).embroider(None)) except SystemExit: raise - except: + except Exception: # Ignore errors. This can be things like incorrect paths for # satins or division by zero caused by incorrect param values. pass @@ -578,7 +577,6 @@ class SettingsFrame(wx.Frame): def overwrite_preset(self, event): self.add_preset(event, overwrite=True) - def _load_preset(self, preset_name): preset = self.check_and_load_preset(preset_name) if not preset: @@ -587,7 +585,6 @@ class SettingsFrame(wx.Frame): for tab in self.tabs: tab.load_preset(preset) - def load_preset(self, event): preset_name = self.get_preset_name() if not preset_name: @@ -597,7 +594,6 @@ class SettingsFrame(wx.Frame): event.Skip() - def delete_preset(self, event): preset_name = self.get_preset_name() if not preset_name: @@ -649,30 +645,32 @@ class SettingsFrame(wx.Frame): def __do_layout(self): # begin wxGlade: MyFrame.__do_layout sizer_1 = wx.BoxSizer(wx.VERTICAL) - #self.sizer_3_staticbox.Lower() + # self.sizer_3_staticbox.Lower() sizer_2 = wx.StaticBoxSizer(self.presets_box, wx.HORIZONTAL) sizer_3 = wx.BoxSizer(wx.HORIZONTAL) for tab in self.tabs: self.notebook.AddPage(tab, tab.name) - sizer_1.Add(self.notebook, 1, wx.EXPAND|wx.LEFT|wx.TOP|wx.RIGHT, 10) - sizer_2.Add(self.preset_chooser, 1, wx.ALIGN_CENTER_VERTICAL|wx.ALL, 5) - sizer_2.Add(self.load_preset_button, 0, wx.ALIGN_CENTER_VERTICAL|wx.ALL, 5) - sizer_2.Add(self.add_preset_button, 0, wx.ALIGN_CENTER_VERTICAL|wx.ALL, 5) - sizer_2.Add(self.overwrite_preset_button, 0, wx.ALIGN_CENTER_VERTICAL|wx.ALL, 5) - sizer_2.Add(self.delete_preset_button, 0, wx.ALIGN_CENTER_VERTICAL|wx.ALL, 5) - sizer_1.Add(sizer_2, 0, flag=wx.EXPAND|wx.ALL, border=10) - sizer_3.Add(self.cancel_button, 0, wx.ALIGN_RIGHT|wx.RIGHT, 5) - sizer_3.Add(self.use_last_button, 0, wx.ALIGN_RIGHT|wx.RIGHT|wx.BOTTOM, 5) - sizer_3.Add(self.apply_button, 0, wx.ALIGN_RIGHT|wx.RIGHT|wx.BOTTOM, 5) + sizer_1.Add(self.notebook, 1, wx.EXPAND | wx.LEFT | wx.TOP | wx.RIGHT, 10) + sizer_2.Add(self.preset_chooser, 1, wx.ALIGN_CENTER_VERTICAL | wx.ALL, 5) + sizer_2.Add(self.load_preset_button, 0, wx.ALIGN_CENTER_VERTICAL | wx.ALL, 5) + sizer_2.Add(self.add_preset_button, 0, wx.ALIGN_CENTER_VERTICAL | wx.ALL, 5) + sizer_2.Add(self.overwrite_preset_button, 0, wx.ALIGN_CENTER_VERTICAL | wx.ALL, 5) + sizer_2.Add(self.delete_preset_button, 0, wx.ALIGN_CENTER_VERTICAL | wx.ALL, 5) + sizer_1.Add(sizer_2, 0, flag=wx.EXPAND | wx.ALL, border=10) + sizer_3.Add(self.cancel_button, 0, wx.ALIGN_RIGHT | wx.RIGHT, 5) + sizer_3.Add(self.use_last_button, 0, wx.ALIGN_RIGHT | wx.RIGHT | wx.BOTTOM, 5) + sizer_3.Add(self.apply_button, 0, wx.ALIGN_RIGHT | wx.RIGHT | wx.BOTTOM, 5) sizer_1.Add(sizer_3, 0, wx.ALIGN_RIGHT, 0) self.SetSizer(sizer_1) sizer_1.Fit(self) self.Layout() # end wxGlade + class NoValidObjects(Exception): pass + class Params(InkstitchExtension): def __init__(self, *args, **kwargs): self.cancelled = False @@ -728,6 +726,41 @@ class Params(InkstitchExtension): return groupby(sorted(params, key=by_group_and_sort_index), by_group) + def sort_tabs(self, tabs): + def tab_sort_key(tab): + parent = tab.parent_tab or tab + + sort_key = ( + # For Stroke and SatinColumn, place the one that's + # enabled first. Place dependent tabs first too. + parent.toggle and parent.toggle_checkbox.IsChecked(), + + # If multiple tabs are enabled, make sure dependent + # tabs are grouped with the parent. + parent, + + # Within parent/dependents, put the parent first. + tab == parent + ) + + return sort_key + + tabs.sort(key=tab_sort_key, reverse=True) + + def pair_tabs(self, tabs): + for tab in tabs: + if tab.toggle and tab.toggle.inverse: + for other_tab in tabs: + if other_tab != tab and other_tab.toggle.name == tab.toggle.name: + tab.pair(other_tab) + other_tab.pair(tab) + + def assign_parents(self, tabs, parent_tab): + for tab in tabs: + if tab != parent_tab: + parent_tab.add_dependent_tab(tab) + tab.set_parent_tab(parent_tab) + def create_tabs(self, parent): tabs = [] nodes_by_class = self.get_nodes_by_class() @@ -744,49 +777,21 @@ class Params(InkstitchExtension): parent_tab = None new_tabs = [] for group, params in self.group_params(params): - tab = ParamsTab(parent, id=wx.ID_ANY, name=group or cls.element_name, params=list(params), nodes=nodes) + tab_name = group or cls.element_name + tab = ParamsTab(parent, id=wx.ID_ANY, name=tab_name, params=list(params), nodes=nodes) new_tabs.append(tab) if group is None: parent_tab = tab - for tab in new_tabs: - if tab != parent_tab: - parent_tab.add_dependent_tab(tab) - tab.set_parent_tab(parent_tab) - + self.assign_parents(new_tabs, parent_tab) tabs.extend(new_tabs) - for tab in tabs: - if tab.toggle and tab.toggle.inverse: - for other_tab in tabs: - if other_tab != tab and other_tab.toggle.name == tab.toggle.name: - tab.pair(other_tab) - other_tab.pair(tab) - - def tab_sort_key(tab): - parent = tab.parent_tab or tab - - sort_key = ( - # For Stroke and SatinColumn, place the one that's - # enabled first. Place dependent tabs first too. - parent.toggle and parent.toggle_checkbox.IsChecked(), - - # If multiple tabs are enabled, make sure dependent - # tabs are grouped with the parent. - parent, - - # Within parent/dependents, put the parent first. - tab == parent - ) - - return sort_key - - tabs.sort(key=tab_sort_key, reverse=True) + self.pair_tabs(tabs) + self.sort_tabs(tabs) return tabs - def cancel(self): self.cancelled = True diff --git a/lib/stitch_plan/stitch.py b/lib/stitch_plan/stitch.py index 5fe10fb8..462634cb 100644 --- a/lib/stitch_plan/stitch.py +++ b/lib/stitch_plan/stitch.py @@ -2,7 +2,7 @@ from ..utils.geometry import Point class Stitch(Point): - def __init__(self, x, y, color=None, jump=False, stop=False, trim=False, color_change=False, fake_color_change=False, no_ties=False): + def __init__(self, x, y=None, color=None, jump=False, stop=False, trim=False, color_change=False, no_ties=False): self.x = x self.y = y self.color = color @@ -10,20 +10,24 @@ class Stitch(Point): self.trim = trim self.stop = stop self.color_change = color_change - self.fake_color_change = fake_color_change self.no_ties = no_ties + # Allow creating a Stitch from a Point + if isinstance(x, Point): + point = x + self.x = point.x + self.y = point.y + def __repr__(self): - return "Stitch(%s, %s, %s, %s, %s, %s, %s, %s%s)" % (self.x, - self.y, - self.color, - "JUMP" if self.jump else " ", - "TRIM" if self.trim else " ", - "STOP" if self.stop else " ", - "NO TIES" if self.no_ties else " ", - "FAKE " if self.fake_color_change else "", - "COLOR CHANGE" if self.color_change else " " - ) + return "Stitch(%s, %s, %s, %s, %s, %s, %s, %s)" % (self.x, + self.y, + self.color, + "JUMP" if self.jump else " ", + "TRIM" if self.trim else " ", + "STOP" if self.stop else " ", + "NO TIES" if self.no_ties else " ", + "COLOR CHANGE" if self.color_change else " " + ) def copy(self): return Stitch(self.x, self.y, self.color, self.jump, self.stop, self.trim, self.color_change, self.no_ties) diff --git a/lib/stitch_plan/ties.py b/lib/stitch_plan/ties.py index 573469f5..1d759c0e 100644 --- a/lib/stitch_plan/ties.py +++ b/lib/stitch_plan/ties.py @@ -1,26 +1,37 @@ from copy import deepcopy from .stitch import Stitch -from ..utils import cut_path -from ..stitches import running_stitch +from ..svg import PIXELS_PER_MM def add_tie(stitches, tie_path): - if stitches[-1].no_ties: + if len(tie_path) < 2 or stitches[0].no_ties: # It's from a manual stitch block, so don't add tie stitches. The user # will add them if they want them. return - tie_path = cut_path(tie_path, 0.6) - tie_stitches = running_stitch(tie_path, 0.3) - tie_stitches = [Stitch(stitch.x, stitch.y) for stitch in tie_stitches] + to_previous = tie_path[1] - tie_path[0] + length = to_previous.length() + if length > 0.5 * PIXELS_PER_MM: + # Travel back one stitch, stopping halfway there. + # Then go forward one stitch, stopping halfway between + # again. - stitches.extend(deepcopy(tie_stitches[1:])) - stitches.extend(deepcopy(list(reversed(tie_stitches))[1:])) + # but travel at most 1.5mm + length = min(length, 1.5 * PIXELS_PER_MM) + + direction = to_previous.unit() + for delta in (0.5, 1.0, 0.5, 0): + stitches.append(Stitch(tie_path[0] + delta * length * direction)) + else: + # Too short to travel part of the way to the previous stitch; ust go + # back and forth to it a couple times. + for i in (1, 0, 1, 0): + stitches.append(deepcopy(tie_path[i])) def add_tie_off(stitches): - add_tie(stitches, list(reversed(stitches))) + add_tie(stitches, stitches[-1:-3:-1]) def add_tie_in(stitches, upcoming_stitches): @@ -36,10 +47,7 @@ def add_ties(stitch_plan): for i, stitch in enumerate(color_block.stitches): is_special = stitch.trim or stitch.jump or stitch.color_change or stitch.stop - # see stop.py for an explanation of the fake color change - is_fake = stitch.fake_color_change - - if is_special and not is_fake and not need_tie_in: + if is_special and not need_tie_in: add_tie_off(new_stitches) new_stitches.append(stitch) need_tie_in = True diff --git a/lib/svg/units.py b/lib/svg/units.py index c4ec82a0..0de410ab 100644 --- a/lib/svg/units.py +++ b/lib/svg/units.py @@ -80,7 +80,10 @@ def convert_length(length): @cache def get_viewbox(svg): - return svg.get('viewBox').strip().replace(',', ' ').split() + viewbox = svg.get('viewBox') + if viewbox is None: + viewbox = "0 0 0 0" + return viewbox.strip().replace(',', ' ').split() @cache |
