params simulate window

when you change params, a simulate window opens to preview the results right
away
pull/10/head
Lex Neva 2017-12-30 16:05:21 -05:00
rodzic 42b83d4ec4
commit 61ed1da1cf
3 zmienionych plików z 114 dodań i 22 usunięć

Wyświetl plik

@ -121,7 +121,7 @@ class EmbroideryElement(object):
if param.endswith('_mm'): if param.endswith('_mm'):
# print >> dbg, "get_float_param", param, value, "*", self.options.pixels_per_mm # print >> dbg, "get_float_param", param, value, "*", self.options.pixels_per_mm
value = value * self.options.pixels_per_mm value = value * getattr(self.options, "pixels_per_mm", 10)
return value return value
@ -133,7 +133,7 @@ class EmbroideryElement(object):
return default return default
if param.endswith('_mm'): if param.endswith('_mm'):
value = int(value * self.options.pixels_per_mm) value = int(value * getattr(self.options, "pixels_per_mm", 10))
return value return value
@ -207,7 +207,7 @@ class EmbroideryElement(object):
path = deepcopy(path) path = deepcopy(path)
cspsubdiv(path, self.options.flat) cspsubdiv(path, getattr(self.options, "flat", 0.1))
flattened = [] flattened = []
@ -500,7 +500,7 @@ class Fill(EmbroideryElement):
# only stitch the first point if it's a reasonable distance away from the # only stitch the first point if it's a reasonable distance away from the
# last stitch # last stitch
if not patch.stitches or (beg - patch.stitches[-1]).length() > 0.5 * self.options.pixels_per_mm: if not patch.stitches or (beg - patch.stitches[-1]).length() > 0.5 * getattr(self.options, "pixels_per_mm", 10):
patch.add_stitch(beg) patch.add_stitch(beg)
first_stitch = self.adjust_stagger(beg, angle, row_spacing, max_stitch_length) first_stitch = self.adjust_stagger(beg, angle, row_spacing, max_stitch_length)
@ -515,7 +515,7 @@ class Fill(EmbroideryElement):
patch.add_stitch(beg + offset * row_direction) patch.add_stitch(beg + offset * row_direction)
offset += max_stitch_length offset += max_stitch_length
if (end - patch.stitches[-1]).length() > 0.1 * self.options.pixels_per_mm: if (end - patch.stitches[-1]).length() > 0.1 * getattr(self.options, "pixels_per_mm", 10):
patch.add_stitch(end) patch.add_stitch(end)
@ -1000,7 +1000,7 @@ class AutoFill(Fill):
patch.add_stitch(PyEmb.Point(*outline.interpolate(pos).coords[0])) patch.add_stitch(PyEmb.Point(*outline.interpolate(pos).coords[0]))
end = PyEmb.Point(*end) end = PyEmb.Point(*end)
if (end - patch.stitches[-1]).length() > 0.1 * self.options.pixels_per_mm: if (end - patch.stitches[-1]).length() > 0.1 * getattr(self.options, "pixels_per_mm", 10):
patch.add_stitch(end) patch.add_stitch(end)
print >> dbg, "end connect_points" print >> dbg, "end connect_points"
@ -1941,5 +1941,3 @@ if __name__ == '__main__':
print >> dbg, traceback.format_exc() print >> dbg, traceback.format_exc()
dbg.flush() dbg.flush()
dbg.close()

Wyświetl plik

@ -5,6 +5,7 @@ import os
import sys import sys
import json import json
import traceback import traceback
from copy import copy
from cStringIO import StringIO from cStringIO import StringIO
import wx import wx
from wx.lib.scrolledpanel import ScrolledPanel from wx.lib.scrolledpanel import ScrolledPanel
@ -13,7 +14,7 @@ import inkex
from embroider import Param, EmbroideryElement, Fill, AutoFill, Stroke, SatinColumn, descendants from embroider import Param, EmbroideryElement, Fill, AutoFill, Stroke, SatinColumn, descendants
from functools import partial from functools import partial
from itertools import groupby from itertools import groupby
from embroider_simulate import EmbroiderySimulator
def presets_path(): def presets_path():
try: try:
@ -128,8 +129,14 @@ class ParamsTab(ScrolledPanel):
def set_parent_tab(self, tab): def set_parent_tab(self, tab):
self.parent_tab = tab self.parent_tab = tab
def is_dependent_tab(self):
return self.parent_tab is not None
def enabled(self):
return self.toggle_checkbox.IsChecked()
def update_toggle_state(self, event=None, notify_pair=True): def update_toggle_state(self, event=None, notify_pair=True):
enable = self.toggle_checkbox.IsChecked() enable = self.enabled()
# print self.name, "update_toggle_state", enable # print self.name, "update_toggle_state", enable
for child in self.settings_grid.GetChildren(): for child in self.settings_grid.GetChildren():
widget = child.GetWindow() widget = child.GetWindow()
@ -137,7 +144,7 @@ class ParamsTab(ScrolledPanel):
child.GetWindow().Enable(enable) child.GetWindow().Enable(enable)
if notify_pair and self.paired_tab: if notify_pair and self.paired_tab:
self.paired_tab.pair_changed(self.toggle_checkbox.IsChecked()) self.paired_tab.pair_changed(enable)
for tab in self.dependent_tabs: for tab in self.dependent_tabs:
tab.dependent_enable(enable) tab.dependent_enable(enable)
@ -149,7 +156,7 @@ class ParamsTab(ScrolledPanel):
# print self.name, "pair_changed", value # print self.name, "pair_changed", value
new_value = not value new_value = not value
if self.toggle_checkbox.IsChecked() != new_value: if self.enabled() != new_value:
self.set_toggle_state(not value) self.set_toggle_state(not value)
self.toggle_checkbox.changed = True self.toggle_checkbox.changed = True
self.update_toggle_state(notify_pair=False) self.update_toggle_state(notify_pair=False)
@ -170,7 +177,7 @@ class ParamsTab(ScrolledPanel):
values = {} values = {}
if self.toggle: if self.toggle:
checked = self.toggle_checkbox.IsChecked() checked = self.enabled()
if self.toggle_checkbox in self.changed_inputs and not self.toggle.inverse: if self.toggle_checkbox in self.changed_inputs and not self.toggle.inverse:
values[self.toggle.name] = checked values[self.toggle.name] = checked
@ -192,10 +199,16 @@ class ParamsTab(ScrolledPanel):
for name, value in values.iteritems(): for name, value in values.iteritems():
node.set_param(name, value) node.set_param(name, value)
def on_change(self, callable):
self.on_change_hook = callable
def changed(self, event): def changed(self, event):
self.changed_inputs.add(event.GetEventObject()) self.changed_inputs.add(event.GetEventObject())
event.Skip() event.Skip()
if self.on_change_hook:
self.on_change_hook(self)
def load_preset(self, preset): def load_preset(self, preset):
preset_data = preset.get(self.name, {}) preset_data = preset.get(self.name, {})
@ -311,6 +324,11 @@ class SettingsFrame(wx.Frame):
self.notebook = wx.Notebook(self, wx.ID_ANY) self.notebook = wx.Notebook(self, wx.ID_ANY)
self.tabs = self.tabs_factory(self.notebook) self.tabs = self.tabs_factory(self.notebook)
for tab in self.tabs:
tab.on_change(self.params_changed)
self.simulate_window = None
self.presets_box = wx.StaticBox(self, wx.ID_ANY, label="Presets") self.presets_box = wx.StaticBox(self, wx.ID_ANY, label="Presets")
self.preset_chooser = wx.ComboBox(self, wx.ID_ANY) self.preset_chooser = wx.ComboBox(self, wx.ID_ANY)
@ -341,6 +359,56 @@ class SettingsFrame(wx.Frame):
self.__do_layout() self.__do_layout()
# end wxGlade # end wxGlade
def params_changed(self, tab):
patches = self.generate_patches()
if not patches:
return
if self.simulate_window:
self.simulate_window.stop()
self.simulate_window.load(patches=patches)
else:
my_rect = self.GetRect()
simulator_pos = my_rect.GetTopRight()
simulator_pos.x += 5
try:
self.simulate_window = EmbroiderySimulator(None, -1, "Embroidery Simulator", simulator_pos, size=(300, 300), patches=patches, on_close=self.simulate_window_closed)
except:
with open('/tmp/params_debug.log', 'a') as log:
print >> log, traceback.format_exc()
log.flush()
self.simulate_window.Show()
wx.CallLater(10, self.Raise)
wx.CallAfter(self.simulate_window.go)
def simulate_window_closed(self):
self.simulate_window = None
def generate_patches(self):
patches = []
for tab in self.tabs:
tab.apply()
try:
if tab.enabled() and not tab.is_dependent_tab():
for node in tab.nodes:
# Making a copy of the embroidery element is an easy
# way to drop the cache in the @cache decorators used
# for many params in embroider.py.
patches.extend(copy(node).to_patches(None))
except:
# Ignore errors. This can be things like incorrect paths for
# satins or division by zero caused by incorrect param values.
pass
return patches
def update_preset_list(self): def update_preset_list(self):
preset_names = load_presets().keys() preset_names = load_presets().keys()
preset_names = [preset for preset in preset_names if preset != "__LAST__"] preset_names = [preset for preset in preset_names if preset != "__LAST__"]
@ -430,10 +498,12 @@ class SettingsFrame(wx.Frame):
event.Skip() event.Skip()
def apply(self, event): def _apply(self):
for tab in self.tabs: for tab in self.tabs:
tab.apply() tab.apply()
def apply(self, event):
self._apply()
save_preset("__LAST__", self.get_preset_data()) save_preset("__LAST__", self.get_preset_data())
self.Close() self.Close()
@ -442,6 +512,10 @@ class SettingsFrame(wx.Frame):
self.apply(event) self.apply(event)
def close(self, event): def close(self, event):
if self.simulate_window:
self.simulate_window.stop()
self.simulate_window.Close()
self.Close() self.Close()
def __set_properties(self): def __set_properties(self):

Wyświetl plik

@ -3,6 +3,7 @@ import os
import numpy import numpy
import wx import wx
import inkex import inkex
import simplestyle
from embroider import patches_to_stitches, stitches_to_polylines from embroider import patches_to_stitches, stitches_to_polylines
@ -10,10 +11,12 @@ class EmbroiderySimulator(wx.Frame):
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
stitch_file = kwargs.pop('stitch_file', None) stitch_file = kwargs.pop('stitch_file', None)
patches = kwargs.pop('patches', None) patches = kwargs.pop('patches', None)
self.on_close_hook = kwargs.pop('on_close', None)
self.frame_period = kwargs.pop('frame_period', 80) self.frame_period = kwargs.pop('frame_period', 80)
self.stitches_per_frame = kwargs.pop('stitches_per_frame', 1) self.stitches_per_frame = kwargs.pop('stitches_per_frame', 1)
wx.Frame.__init__(self, *args, **kwargs) wx.Frame.__init__(self, *args, **kwargs)
self.panel = wx.Panel(self, wx.ID_ANY) self.panel = wx.Panel(self, wx.ID_ANY)
self.panel.SetFocus() self.panel.SetFocus()
@ -30,15 +33,19 @@ class EmbroiderySimulator(wx.Frame):
self.panel.Bind(wx.EVT_PAINT, self.on_paint) self.panel.Bind(wx.EVT_PAINT, self.on_paint)
self.panel.Bind(wx.EVT_KEY_DOWN, self.on_key_down) self.panel.Bind(wx.EVT_KEY_DOWN, self.on_key_down)
self.timer = None
self.last_pos = None self.last_pos = None
self.Bind(wx.EVT_CLOSE, self.on_close)
def load(self, stitch_file=None, patches=None): def load(self, stitch_file=None, patches=None):
if stitch_file: if stitch_file:
self.segments = self._parse_stitch_file(stitch_file) self.segments = self._parse_stitch_file(stitch_file)
elif patches: elif patches:
self.segments = self._patches_to_stitches(patches) self.segments = self._patches_to_segments(patches)
else: else:
raise TypeError("EmbroiderySimulator requires a stitch_file or list of patches") return
self.width, self.height = self.get_dimensions() self.width, self.height = self.get_dimensions()
@ -76,18 +83,22 @@ class EmbroiderySimulator(wx.Frame):
return string return string
def _patches_to_segments(patches): def _patches_to_segments(self, patches):
stitches = patches_to_stitches(patches) stitches = patches_to_stitches(patches)
segments = [] segments = []
last_pos = None last_pos = None
last_color = None last_color = None
pen = None
for stitch in stitches: for stitch in stitches:
pos = (stitch.x, stitch.y)
if stitch.color == last_color: if stitch.color == last_color:
pos = (stitch.x, stitch.y) segments.append(((last_pos, pos), pen))
segments.append(((last_pos, pos), stitch.color)) else:
pen = wx.Pen(simplestyle.parseColor(stitch.color))
last_pos = pos last_pos = pos
last_color = stitch.color last_color = stitch.color
@ -138,8 +149,8 @@ class EmbroiderySimulator(wx.Frame):
width = 0 width = 0
height = 0 height = 0
for stitch in self.segments: for segment in self.segments:
(start_x, start_y), (end_x, end_y) = stitch[0] (start_x, start_y), (end_x, end_y) = segment[0]
width = max(width, start_x, end_x) width = max(width, start_x, end_x)
height = max(height, start_y, end_y) height = max(height, start_y, end_y)
@ -153,8 +164,17 @@ class EmbroiderySimulator(wx.Frame):
self.timer = wx.PyTimer(self.draw_one_frame) self.timer = wx.PyTimer(self.draw_one_frame)
self.timer.Start(self.frame_period) self.timer.Start(self.frame_period)
def on_close(self, event):
self.stop()
if self.on_close_hook:
self.on_close_hook()
self.Destroy()
def stop(self): def stop(self):
self.timer.Stop() if self.timer:
self.timer.Stop()
def clear(self): def clear(self):
self.dc.SetBackground(wx.Brush('white')) self.dc.SetBackground(wx.Brush('white'))