diff --git a/MaKe-stitch.py b/MaKe-stitch.py index 2af0a5c..0fd344a 100644 --- a/MaKe-stitch.py +++ b/MaKe-stitch.py @@ -5,15 +5,46 @@ # import wx -import sys import pyembroidery - +from wx.lib.embeddedimage import PyEmbeddedImage + +makestitch_icon = PyEmbeddedImage( + b'iVBORw0KGgoAAAANSUhEUgAAADIAAAAyCAYAAAAeP4ixAAAAAXNSR0IArs4c6QAAAARnQU1B' + b'AACxjwv8YQUAAAAJcEhZcwAADsQAAA7EAZUrDhsAAASwSURBVGhD1ZlLKLxfGMcf5J5bbNDE' + b'ROR+CVkgkVuSXMJOZGGjJBY2VoqSjYWikJBQLsl9IcREpsYlC5cyKMJC4xaG83+fx/n9/uln' + b'hmHM+/rU5JznnGne73ue5znPOYBJkOHhYQYAzNramnl6elIbPwEBAay5uZnPeovkhGg0Gnpo' + b'tVrNLa88Pz+z9vZ2JpfLabyuro6PvCI5IZ2dnUwmk/He++zv75OYqKgobmHMXDBICicnJzg7' + b'O+O99/Hx8cEFgPX1dSgqKiKbGaqhloQwMzODl5cX+vsROOfi4kKaQuLi4sDW1hbm5ua4RTel' + b'paUgxI/gaBJFeEamUCh4Tzc4x97eXnrB/oe+vj4S8xFarZbmSdK1DAFjycLCAkTPWl1dXSCk' + b'UQpa/Li6ukJhYSEsLS3xGfpZW1sDKysr8WJkdHSUXAI/NTU1bHFxkSmVStbb28syMjL+jtXX' + b'1/NvvE9xcTETUrA4MdLY2EgPiaWIPoaGhpidnR3Nrays5Nb/ubu7o7GTkxPTC7m/v6cfv76+' + b'5paPUalUzNvbm76XmprK5ufnqQLAflVVFc0xuZDa2loWExPDe4Zxfn7OCgoKmBBLzN3dnY2P' + b'j/MRZvqslZycDJGRkdDU1MQtxsHkWQvf20+8O5MLCQoKgt3dXd4zIuhapmRsbIyC1NiIsrPj' + b'xvf4+AiWlpbc8n1E2dnxPNHQ0MB7RoLWxcRg2jT2T4siBEEhAwMDvPd9RBPS2tpq1FURtYzH' + b'oBdKDSgpKeGWV46Pj2FnZwdOT09BKGWgoqKCj+hGVCEzMzOQnp6Oy0J9fPCFhQUSmJKSQpcL' + b'Dw8PkJWVReN6QSFigjVTTk4OW15eZh0dHezw8JDsgiDW09ND7c8g+glxdXUVtra2wNPTE4Rz' + b'CNmE8h6enp7ogPVZRD0hCuU4uZNCoYC8vDyydXd3g7W1tUEiCFoXEcBDE5Yrf8BHwZMhHpK+' + b'giiu1d/fD3K5HGJjY8mtNjY26B4rPz8fjo6OQCaT8Zmfx6RChKMpTE1Nkev4+vpSfNjY2EB8' + b'fDx4eHhAW1sblJeX/81ihmAyIfjWt7e3wcHBAW5ubsDZ2RlCQkL+efsY8NPT0waL+XEhmH0m' + b'Jibo/gnBO6i0tDRaCV2Eh4eTcEMe7UezFvq/ENTUxo3N398fsrOz9YpAVCoVlJWV0cbY0tLC' + b'rfr5kRXBVRAqXHoQbLu4uNBObSibm5sQFhZGbXQ3XEldGF3I3t4elRaYhW5vb+lm3cvLi49+' + b'jebmZqiurgZzc/PXm/d3MKqQyclJyky4CkLpAYmJiXzEOGCyCA4O5r23GEWIUB/R7oxpFUXg' + b'lY+bmxsfNQ3fFjI7OwtXV1ckwM/PD6Kjo/mIafmyEPw/H9ZKeIGAvpuZmUkrIhZfEiKU3KBW' + b'q6mNPhsaGkptMTFIiEajoTSo1WoppaamptIGJwU+LUSpVNLxE10pISGBaiMp8aEQDGKh3KY9' + b'ITAwULRg/gi9Qg4ODuhfYI6OjpCUlESFnlTRKQRjAU9veGYICAjgVunyj5DLy0sYGRmha01c' + b'hd/CGyErKyt05Z+bm0vu9JsgIahlcHCQduaIiAg+9LswE3ZohquAx83fC8B/QI+w8nkB9vAA' + b'AAAASUVORK5CYII=') # begin wxGlade: dependencies # end wxGlade # begin wxGlade: extracode # end wxGlade +MaKeStitchVersion = "0.2.0" +PMV_SCALE = 2.5 +PMV_CURVE = 75 + + class StitchPanel(wx.Panel): def __init__(self, *args, **kwds): @@ -32,6 +63,7 @@ def __init__(self, *args, **kwds): self.translate_y = 0 self.buffer = 0.1 self.grid = None + self.text_grid = None self.clicked_position = None self.drag_point = None @@ -62,9 +94,9 @@ def on_mouse_move(self, event): if self.drag_point is None: return mod_stitch = self.emb_pattern.stitches[self.drag_point] - position = self.get_pattern_point(event.GetPosition()) - mod_stitch[0] = position[0] - mod_stitch[1] = position[1] + position = self.scene_location_to_grid_position(event.GetPosition()) + mod_stitch[0] = position[0] * PMV_SCALE + mod_stitch[1] = position[1] * PMV_SCALE self.update_drawing() def on_mouse_down(self, event): @@ -73,7 +105,7 @@ def on_mouse_down(self, event): return position = event.GetPosition() nearest = self.get_nearest_point(position) - if nearest[1] > 25: + if nearest[1] > 100: event.Skip() self.drag_point = None return @@ -94,11 +126,11 @@ def on_right_double_click(self, event): new_stitch = stitch[:] new_stitch2 = stitch[:] new_stitch3 = stitch[:] - position = self.get_pattern_point(self.clicked_position) - new_stitch[0] = position[0] - new_stitch[1] = position[1] - new_stitch3[0] = position[0] - new_stitch3[1] = position[1] + position = self.scene_location_to_grid_position(self.clicked_position) + new_stitch[0] = position[0] * PMV_SCALE + new_stitch[1] = position[1] * PMV_SCALE + new_stitch3[0] = position[0] * PMV_SCALE + new_stitch3[1] = position[1] * PMV_SCALE stitches.insert(self.selected_point + 1, new_stitch) stitches.insert(self.selected_point + 2, new_stitch2) stitches.insert(self.selected_point + 3, new_stitch3) @@ -110,9 +142,9 @@ def on_left_double_click(self, event): self.clicked_position = event.GetPosition() nearest = self.get_nearest_point(self.clicked_position) if nearest[0] is None: # No nearest node. Must have no nodes. - position = self.get_pattern_point(self.clicked_position) + position = self.scene_location_to_grid_position(self.clicked_position) stitches = self.emb_pattern.stitches - stitches.append([position[0], position[1], pyembroidery.STITCH]) + stitches.append([position[0]*PMV_SCALE, position[1]*PMV_SCALE, pyembroidery.STITCH]) self.selected_point = 0 self.update_affines() self.update_drawing() @@ -123,9 +155,9 @@ def on_left_double_click(self, event): stitches = self.emb_pattern.stitches stitch = stitches[self.selected_point] new_stitch = stitch[:] - position = self.get_pattern_point(self.clicked_position) - new_stitch[0] = position[0] - new_stitch[1] = position[1] + position = self.scene_location_to_grid_position(self.clicked_position) + new_stitch[0] = position[0]*PMV_SCALE + new_stitch[1] = position[1]*PMV_SCALE stitches.insert(self.selected_point + 1, new_stitch) self.selected_point += 1 self.update_affines() @@ -222,26 +254,38 @@ def update_affine(self, width, height): max_x = max(extends[2], 100) max_y = max(extends[3], 35) - embroidery_width = (max_x - min_x) + (width * self.buffer) - embroidery_height = (max_y - min_y) + (height * self.buffer) + embroidery_width = (max_x - min_x) #+ (width * self.buffer) + embroidery_height = (max_y - min_y) #+ (height * self.buffer) scale_x = float(width) / embroidery_width scale_y = float(height) / embroidery_height - self.scale = min(scale_x, scale_y) - self.translate_x = -min_x + (width * self.buffer) / 2 - self.translate_y = -min_y + (height * self.buffer) / 2 + self.scale = min(scale_x, scale_y) * 2 + self.translate_x = -min_x + 3 + self.translate_y = -(min_y/2) self.grid = None + self.text_grid = None - def get_pattern_point(self, position): + def scene_location_to_grid_position(self, position): px = position[0] py = position[1] px /= self.scale py /= self.scale px -= self.translate_x py -= self.translate_y - px = round(px / 2.5) * 2.5 - py = round(py / 2.5) * 2.5 + px -= py * py / PMV_CURVE + px = round(px) + py = round(py) return px, py + def grid_position_to_scene_location(self, grid_x, grid_y): + x = grid_x + y = grid_y + x += grid_y * grid_y / PMV_CURVE + x += self.translate_x + y += self.translate_y + x *= self.scale + y *= self.scale + return x, y + @staticmethod def distance_sq(p0, p1): dx = p0[0] - p1[0] @@ -251,18 +295,12 @@ def distance_sq(p0, p1): return dx + dy def get_nearest_point(self, position): - scene_x = position[0] - scene_y = position[1] - scene_x /= self.scale - scene_y /= self.scale - scene_x -= self.translate_x - scene_y -= self.translate_y - click_point = (scene_x, scene_y) best_point = None best_index = None - best_distance = sys.maxint + best_distance = float('-inf') for i, stitch in enumerate(self.emb_pattern.stitches): - distance = self.distance_sq(click_point, stitch) + s_x, s_y = self.grid_position_to_scene_location(stitch[0]/PMV_SCALE, stitch[1]/PMV_SCALE) + distance = self.distance_sq(position, (s_x, s_y)) if best_point is None or distance < best_distance or ( distance == best_distance and self.selected_point == i): best_point = stitch @@ -284,47 +322,56 @@ def __do_layout(self): def perform_draw_grid(self, dc): if self.grid is None: self.build_grid() - dc.SetPen(wx.Pen(self.grid[0])) - dc.DrawLineList(self.grid[1]) + for g in self.grid: + dc.SetPen(wx.Pen(g[0])) + dc.DrawLineList(g[1]) + for t in self.text_grid: + font = wx.Font(10, wx.SWISS, wx.NORMAL, wx.BOLD) + dc.SetFont(font) + w, h = dc.GetTextExtent(t[0]) + if t[3] == 0: + dc.DrawText(t[0], wx.Point(t[1] - w, t[2]-h/2)) + elif t[3] == 1: + dc.DrawText(t[0], wx.Point(t[1] - w / 2, t[2]-h)) + else: + dc.DrawText(t[0], wx.Point(t[1] - w / 2, t[2])) def build_grid(self): - scale = self.scale - tran_x = self.translate_x - tran_y = self.translate_y - lines = [] + text = [] + black_lines = [] + grey_lines = [] + magenta_lines = [] + black = False for j in range(-14, 14 + 1): - x0 = 0 * 2.5 - y0 = j * 2.5 - x1 = 100 * 2.5 - y1 = j * 2.5 - - x0 += tran_x - y0 += tran_y - x1 += tran_x - y1 += tran_y - - x0 *= scale - y0 *= scale - x1 *= scale - y1 *= scale - lines.append([x0, y0, x1, y1]) - for k in range(0, 100): - x0 = k * 2.5 - y0 = -14 * 2.5 - x1 = k * 2.5 - y1 = +14 * 2.5 - - x0 += tran_x - y0 += tran_y - x1 += tran_x - y1 += tran_y - - x0 *= scale - y0 *= scale - x1 *= scale - y1 *= scale - lines.append([x0, y0, x1, y1]) - self.grid = ((0xFF, 0, 0), lines) + black = not black + x0, y0 = self.grid_position_to_scene_location(0, j) + x1, y1 = self.grid_position_to_scene_location(100,j) + text.append((str(j), x0, y0, 0)) + if j == 0: + magenta_lines.append([x0, y0, x1, y1]) + else: + if black: + black_lines.append([x0, y0, x1, y1]) + else: + grey_lines.append([x0, y0, x1, y1]) + black = False + for j in range(-14, 14): + for k in range(0, 100): + black = not black + x0, y0 = self.grid_position_to_scene_location(k, j) + x1, y1 = self.grid_position_to_scene_location(k, j+1) + if k % 5 == 0 and j == -14: + text.append((str(k), x0, y0, 1)) + if k % 5 == 0 and j == 13: + text.append((str(k), x1, y1, -1)) + if black: + black_lines.append([x0, y0, x1, y1]) + else: + grey_lines.append([x0, y0, x1, y1]) + self.grid = [((0xFF, 0, 0xFF), magenta_lines), + ((0x80, 0x80, 0x80), grey_lines), + ((0, 0, 0), black_lines)] + self.text_grid = text def perform_draw(self, dc): dc.SetBackground(wx.Brush("White")) @@ -333,22 +380,17 @@ def perform_draw(self, dc): if self.emb_pattern is None: return - scale = self.scale - tran_x = self.translate_x - tran_y = self.translate_y draw_data = [] for color in self.emb_pattern.get_as_colorblocks(): lines = [] last_x = None last_y = None for i, stitch in enumerate(color[0]): - current_x = stitch[0] + tran_x - current_y = stitch[1] + tran_y + current_x, current_y = self.grid_position_to_scene_location(stitch[0]/PMV_SCALE, stitch[1]/PMV_SCALE) if last_x is not None: - lines.append([last_x * scale, last_y * scale, current_x * scale, current_y * scale]) + lines.append([last_x, last_y, current_x, current_y]) last_x = current_x last_y = current_y - thread = color[1] draw_data.append(((0, 0, 0), lines)) current_stitch = self.current_stitch @@ -380,17 +422,24 @@ def perform_draw(self, dc): dc.SetBrush(wx.Brush("Blue")) dc.GetPen().SetWidth(1) for stitch in self.emb_pattern.stitches: - dc.DrawCircle((tran_x + stitch[0]) * scale, (tran_y + stitch[1]) * scale, scale * 3) + current_x, current_y = self.grid_position_to_scene_location(stitch[0]/PMV_SCALE, stitch[1]/PMV_SCALE) + dc.DrawCircle(current_x, current_y, 10) if self.selected_point is not None: + font = wx.Font(14, wx.SWISS, wx.NORMAL, wx.BOLD) + dc.SetFont(font) mod_stitch = self.emb_pattern.stitches[self.selected_point] - name = self.name_dict[mod_stitch[2]] + " " + str(self.selected_point) - dc.DrawText(name, 25, 25) + name = "%s %d (%g, %g)" % (self.name_dict[mod_stitch[2]], + int(self.selected_point), + float(mod_stitch[0]) / PMV_SCALE, + float(mod_stitch[1]) / PMV_SCALE) + dc.DrawText(name, 0, 0) dc.SetBrush(wx.Brush("Green")) - dc.DrawCircle((tran_x + mod_stitch[0]) * scale, (tran_y + mod_stitch[1]) * scale, scale * 3) + m_x, m_y = self.grid_position_to_scene_location(mod_stitch[0]/PMV_SCALE, mod_stitch[1]/PMV_SCALE) + dc.DrawCircle(m_x, m_y, 10) def on_paint(self, event): - dc = wx.BufferedPaintDC(self, self._Buffer) + wx.BufferedPaintDC(self, self._Buffer) def on_size(self, event): # The Buffer init is done here, to make sure the buffer is always @@ -458,7 +507,10 @@ def __init__(self, *args, **kwds): def __set_properties(self): # begin wxGlade: Stitcher.__set_properties - self.SetTitle("MK Stitch") + self.SetTitle("MK Stitch v%s" % MaKeStitchVersion) + _icon = wx.NullIcon + _icon.CopyFromBitmap(makestitch_icon.GetBitmap()) + self.SetIcon(_icon) # end wxGlade def __do_layout(self): @@ -473,7 +525,7 @@ def on_menu_import(self, event): files = "" for format in pyembroidery.supported_formats(): try: - if format["reader"] is not None and format["category"] is "stitch": + if format["reader"] is not None and format["category"] == "stitch": files += "*." + format["extension"] + ";" except KeyError: pass @@ -489,7 +541,7 @@ def on_menu_export(self, event): files = "" for format in pyembroidery.supported_formats(): try: - if format["writer"] is not None and format["category"] is "stitch": + if format["writer"] is not None and format["category"] == "stitch": files += format["description"] + "(*." + format["extension"] + ")|*." + format[ "extension"] + "|" except KeyError: diff --git a/README.md b/README.md index 23f66ca..1eb15e4 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,16 @@ # MaKe-stitch + +MaKe stitch is an open source stitch creator software that creates, reopens, edits and saves .pmv stitch files. These are common used in a series of brother sewing machines with customizable stitches. Other formats are currently unknown. + wxWidget stitch creator making pmv stitch files from scratch. +You can download a compiled copy of MaKe-stitch for windows in Releases. + +https://github.com/EmbroidePy/MaKe-stitch/releases + +Python +--- + Requires pyembroidery `pip install pyembroidery` @@ -9,10 +19,10 @@ Requires wxPython: `pip install wxPython` +Instructions --- - * MaKe-stitch.py GUI - for making .pmv stitch files (or other ones, but there aren't any other ones). - * ![make-stitch](https://user-images.githubusercontent.com/3302478/44017845-9e4cb12e-9e8e-11e8-9849-f9b9ba75d516.png) + * ![mkstitch](https://user-images.githubusercontent.com/3302478/99155566-e4644780-266d-11eb-9234-244d25132cee.png) * See tutorial video: https://youtu.be/HCiFgb9-JHQ * Left Double-Click inserts a stitch. * Middle Double-Click inserts a stitch. Note: Since Left Click selects a node, double clicking a node selects then inserts at that exact location which duplicates the node. Using middle click means it will allow double-backing on nodes without selecting them. @@ -25,3 +35,9 @@ Requires wxPython: * Delete button deletes selected node. * Right Arrow or 'd' moves to the next node in the list. * Left Arrow or 'a' moves to the next node in the list. ('a' & 'd' are WASD keys). + +Thanks +--- + +* Mark Kressin. +* PlantLily. diff --git a/makestitch.ico b/makestitch.ico new file mode 100644 index 0000000..14e23ed Binary files /dev/null and b/makestitch.ico differ diff --git a/makestitch.png b/makestitch.png new file mode 100644 index 0000000..0439669 Binary files /dev/null and b/makestitch.png differ