2021-10-25 17:09:15 +00:00
|
|
|
from .base import InkstitchExtension
|
|
|
|
import json
|
|
|
|
import os
|
|
|
|
import sys
|
|
|
|
from base64 import b64decode
|
|
|
|
from argparse import ArgumentParser, REMAINDER
|
|
|
|
|
|
|
|
import appdirs
|
|
|
|
import inkex
|
|
|
|
from inkex import Line, Rectangle
|
|
|
|
import wx
|
|
|
|
import wx.adv
|
|
|
|
from lxml import etree
|
|
|
|
|
|
|
|
from ..elements import nodes_to_elements
|
|
|
|
from ..gui import PresetsPanel, SimulatorPreview, info_dialog
|
|
|
|
from ..i18n import _
|
|
|
|
from ..lettering import Font, FontError
|
|
|
|
from ..svg import get_correction_transform
|
|
|
|
from ..svg.tags import (INKSCAPE_LABEL, INKSTITCH_LETTERING, SVG_GROUP_TAG,
|
|
|
|
SVG_PATH_TAG)
|
|
|
|
from ..utils import DotDict, cache, get_bundled_dir, get_resource_dir
|
|
|
|
from .commands import CommandsExtension
|
|
|
|
from .lettering_custom_font_dir import get_custom_font_dir
|
|
|
|
|
|
|
|
import svgwrite
|
|
|
|
from svgwrite.extensions import Inkscape
|
|
|
|
|
|
|
|
# minimum space apart for wires in grid to avoid interference / shorting
|
|
|
|
MIN_GRID_SPACING = 2.5
|
|
|
|
class SensorGridFrame(wx.Frame):
|
|
|
|
DEFAULT_FONT = "small_font"
|
|
|
|
def __init__(self, rectangle, svg, *args, **kwargs):
|
|
|
|
if sys.platform.startswith('win32'):
|
|
|
|
import locale
|
|
|
|
locale.setlocale(locale.LC_ALL, "C")
|
|
|
|
lc = wx.Locale()
|
|
|
|
lc.Init(wx.LANGUAGE_DEFAULT)
|
|
|
|
# self.group = kwargs.pop('group')
|
|
|
|
# self.parent_node = parent_node
|
|
|
|
self.rectangle = rectangle
|
|
|
|
self.upper_left, self.upper_right, self.lower_left, self.lower_right = self.rectangle.get_rectangle_points()
|
|
|
|
self.svg = svg
|
2021-10-27 20:44:50 +00:00
|
|
|
self.paths = []
|
2021-10-25 17:09:15 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
inkex.errormsg("dims in GUI: {} x {}".format(self.rectangle.width, self.rectangle.height))
|
|
|
|
|
|
|
|
self.cancel_hook = kwargs.pop('on_cancel', None)
|
|
|
|
wx.Frame.__init__(self, None, wx.ID_ANY,
|
|
|
|
_("Ink/Stitch Sensor Grid")
|
|
|
|
)
|
|
|
|
self.preview = SimulatorPreview(self, target_duration=1)
|
|
|
|
# self.presets_panel = PresetsPanel(self)
|
|
|
|
|
|
|
|
self.vertical_wire_spinner = wx.SpinCtrl(self, wx.ID_ANY, min = 1, initial = 1);
|
|
|
|
self.vertical_wire_spinner.Bind(wx.EVT_SPINCTRL, lambda event: self.on_change("vertical_wires", event))
|
|
|
|
|
|
|
|
self.horizontal_wire_spinner = wx.SpinCtrl(self, wx.ID_ANY, min = 1, initial = 1);
|
|
|
|
self.horizontal_wire_spinner.Bind(wx.EVT_SPINCTRL, lambda event: self.on_change("horizontal_wires", event))
|
|
|
|
|
2021-10-27 20:44:50 +00:00
|
|
|
self.horizontal_wire = None
|
|
|
|
self.vertical_wire = None
|
2021-10-25 17:09:15 +00:00
|
|
|
|
|
|
|
self.cancel_button = wx.Button(self, wx.ID_ANY, _("Cancel"))
|
|
|
|
self.cancel_button.Bind(wx.EVT_BUTTON, self.cancel)
|
|
|
|
self.Bind(wx.EVT_CLOSE, self.cancel)
|
|
|
|
|
|
|
|
self.apply_button = wx.Button(self, wx.ID_ANY, _("Apply and Quit"))
|
|
|
|
self.apply_button.Bind(wx.EVT_BUTTON, self.apply)
|
|
|
|
|
|
|
|
self.__do_layout()
|
|
|
|
self.load_settings()
|
|
|
|
self.apply_settings()
|
|
|
|
|
|
|
|
|
|
|
|
def load_settings(self):
|
|
|
|
"""
|
|
|
|
Load settings into SVG Group element
|
|
|
|
"""
|
|
|
|
self.settings = DotDict({
|
|
|
|
"vertical_wires": 0,
|
|
|
|
"horizontal_wires": 0
|
|
|
|
})
|
|
|
|
|
|
|
|
def apply_settings(self):
|
|
|
|
self.vertical_wire_spinner.SetValue(self.settings.vertical_wires)
|
|
|
|
self.horizontal_wire_spinner.SetValue(self.settings.horizontal_wires)
|
|
|
|
|
|
|
|
|
|
|
|
def on_change(self, attribute, event):
|
|
|
|
self.settings[attribute] = event.GetEventObject().GetValue()
|
|
|
|
self.preview.update()
|
|
|
|
|
|
|
|
|
|
|
|
def apply(self, event):
|
|
|
|
self.preview.disable()
|
|
|
|
self.create_grid_layout()
|
|
|
|
# self.save_settings()
|
|
|
|
self.close()
|
|
|
|
|
|
|
|
def create_grid_layout(self):
|
|
|
|
# check vertical and horizontal spacing
|
2021-10-27 20:44:50 +00:00
|
|
|
total_horizontal_spacing = self.rectangle.height / (self.horizontal_wire_spinner.GetValue() + 1)
|
|
|
|
total_vertical_spacing = self.rectangle.width / (self.vertical_wire_spinner.GetValue() + 1)
|
|
|
|
# can only actually add wires within boundaries of rectangle
|
|
|
|
horizontal_wire_spacing = (self.rectangle.height - total_horizontal_spacing) / self.horizontal_wire_spinner.GetValue()
|
|
|
|
vertical_wire_spacing = (self.rectangle.width - total_vertical_spacing) / self.vertical_wire_spinner.GetValue()
|
|
|
|
if (horizontal_wire_spacing < MIN_GRID_SPACING):
|
2021-10-25 17:09:15 +00:00
|
|
|
inkex.errormsg('''The horizontal wires must be at least {} mm apart
|
|
|
|
They are currently {} mm apart. Either decrease the
|
2021-10-27 20:44:50 +00:00
|
|
|
number of wires or increase the size of the grid and try again.'''.format(MIN_GRID_SPACING, horizontal_wire_spacing))
|
2021-10-25 17:09:15 +00:00
|
|
|
return
|
2021-10-27 20:44:50 +00:00
|
|
|
if (vertical_wire_spacing < MIN_GRID_SPACING):
|
2021-10-25 17:09:15 +00:00
|
|
|
inkex.errormsg('''The vertical wires must be at least {} mm apart
|
|
|
|
They are currently {} mm apart. Either decrease the
|
2021-10-27 20:44:50 +00:00
|
|
|
number of wires or increase the size of the grid and try again.'''.format(MIN_GRID_SPACING, vertical_wire_spacing))
|
|
|
|
self.lay_horizontal_wires(total_horizontal_spacing)
|
|
|
|
self.lay_vertical_wires(total_vertical_spacing)
|
2021-10-25 17:09:15 +00:00
|
|
|
|
2021-10-27 20:44:50 +00:00
|
|
|
def lay_horizontal_wires(self, horizontal_wire_spacing):
|
|
|
|
'''
|
|
|
|
vert spacing:2.9, curr_point_top: 26.509441, bottom: 38.099998
|
2021-10-25 17:09:15 +00:00
|
|
|
|
2021-10-27 20:44:50 +00:00
|
|
|
4 curr_point_top: 38.09999799999999, bottom: 38.099998
|
|
|
|
'''
|
|
|
|
curr_point = list(self.upper_left)
|
|
|
|
inkex.errormsg("vert spacing:{}, curr_point_top: {}, bottom: {}".format(horizontal_wire_spacing, curr_point[1], self.rectangle.bottom))
|
|
|
|
wire_count = 0
|
|
|
|
points = []
|
|
|
|
while round(curr_point[1]) != round(self.rectangle.bottom - horizontal_wire_spacing):
|
|
|
|
curr_point[1] += horizontal_wire_spacing
|
|
|
|
inkex.errormsg(" 1 curr_point_top: {}, bottom: {}".format(curr_point[1], self.rectangle.bottom))
|
|
|
|
# self.create_wire_segment(curr_point, self.rectangle.width, True)
|
|
|
|
points.append('{},{}'.format(curr_point[0], curr_point[1]))
|
|
|
|
wire_count += 1
|
|
|
|
if wire_count < self.horizontal_wire_spinner.GetValue(): # avoid last wire to prevent shorting
|
|
|
|
if wire_count % 2 == 1: # need to draw joining segment on right side
|
|
|
|
# self.create_wire_joiner([self.rectangle.right, curr_point[1]], horizontal_wire_spacing, is_horizontal=False)
|
|
|
|
points.append('{},{}'.format(self.rectangle.right, curr_point[1]))
|
|
|
|
points.append('{},{}'.format(self.rectangle.right, curr_point[1] + horizontal_wire_spacing))
|
|
|
|
else: # need to draw joining segment on left side
|
|
|
|
# self.create_wire_joiner([self.rectangle.left, curr_point[1]], horizontal_wire_spacing, is_horizontal=False)
|
|
|
|
points.append('{},{}'.format(self.rectangle.left, curr_point[1]))
|
|
|
|
points.append('{},{}'.format(self.rectangle.left, curr_point[1] + horizontal_wire_spacing))
|
|
|
|
inkex.errormsg("points:{}".format(points))
|
|
|
|
self.create_path(points, is_horizontal=True)
|
|
|
|
|
|
|
|
def lay_vertical_wires(self, vertical_wire_spacing):
|
|
|
|
curr_point = list(self.upper_left)
|
|
|
|
inkex.errormsg("vert spacing:{}, curr_point_top: {}, bottom: {}".format(vertical_wire_spacing, curr_point[1], self.rectangle.right))
|
|
|
|
wire_count = 0
|
|
|
|
points = []
|
|
|
|
while round(curr_point[0]) != round(self.rectangle.right - vertical_wire_spacing):
|
|
|
|
curr_point[0] += vertical_wire_spacing
|
|
|
|
points.append('{},{}'.format(curr_point[0], curr_point[1]))
|
|
|
|
inkex.errormsg(" 1 curr_point_top: {}, bottom: {}".format(curr_point[0], self.rectangle.right))
|
|
|
|
# self.create_wire_segment(curr_point, self.rectangle.height, False)
|
|
|
|
wire_count += 1
|
|
|
|
if wire_count < self.vertical_wire_spinner.GetValue():
|
|
|
|
if wire_count % 2 == 1: # need to draw joining segment on bottom side
|
|
|
|
# self.create_wire_joiner([curr_point[0], self.rectangle.bottom], vertical_wire_spacing, is_horizontal=True)
|
|
|
|
points.append('{},{}'.format(curr_point[0], self.rectangle.bottom))
|
|
|
|
points.append('{},{}'.format(curr_point[0] + vertical_wire_spacing, self.rectangle.bottom))
|
|
|
|
else: # need to draw joining segment on top side
|
|
|
|
# self.create_wire_joiner([curr_point[0], self.rectangle.top], vertical_wire_spacing, is_horizontal=True)
|
|
|
|
points.append('{},{}'.format(curr_point[0], self.rectangle.top))
|
|
|
|
points.append('{},{}'.format(curr_point[0] + vertical_wire_spacing, self.rectangle.top))
|
|
|
|
self.create_path(points, is_horizontal=False)
|
|
|
|
|
|
|
|
def create_path(self, points, is_horizontal):
|
2021-10-25 17:09:15 +00:00
|
|
|
'''
|
2021-10-27 20:44:50 +00:00
|
|
|
Creates a wire segment path given all of the points sequentially
|
2021-10-25 17:09:15 +00:00
|
|
|
'''
|
|
|
|
color = "red" if is_horizontal else "blue"
|
2021-10-27 20:44:50 +00:00
|
|
|
path_str = ' '.join(points)
|
|
|
|
path = inkex.Polyline(attrib={
|
2021-10-25 17:09:15 +00:00
|
|
|
'id': "wire_segment",
|
|
|
|
'style': "stroke: %s; stroke-width: 0.4; fill: none; stroke-dasharray:0.4,0.4" % color,
|
2021-10-27 20:44:50 +00:00
|
|
|
'points': path_str,
|
2021-10-25 17:09:15 +00:00
|
|
|
# 'transform': inkex.get_correction_transform(svg),
|
|
|
|
})
|
|
|
|
self.svg.get_current_layer().append(path)
|
2021-10-27 20:44:50 +00:00
|
|
|
# store wire objects for future use
|
|
|
|
if is_horizontal:
|
|
|
|
self.horizontal_wire = path
|
|
|
|
else:
|
|
|
|
self.vertical_wire = path
|
|
|
|
|
|
|
|
# OLD DISJOING CODE -- will save just in case it is needed for routing???
|
|
|
|
# def create_wire_segment(self, start_point, length, is_horizontal):
|
|
|
|
# color = "red" if is_horizontal else "blue"
|
|
|
|
# direction = "h" if is_horizontal else "v"
|
|
|
|
# # length = self.rectangle.width if is_horizontal else self.rectangle.height
|
|
|
|
# path = inkex.PathElement(attrib={
|
|
|
|
# 'id': "wire_segment",
|
|
|
|
# 'style': "stroke: %s; stroke-width: 0.4; fill: none; stroke-dasharray:0.4,0.4" % color,
|
|
|
|
# 'd': "m {},{} {} {} ".format(str(start_point[0]), str(start_point[1]), direction, length),
|
|
|
|
# # 'transform': inkex.get_correction_transform(svg),
|
|
|
|
# })
|
|
|
|
# self.svg.get_current_layer().append(path)
|
|
|
|
|
2021-10-25 17:09:15 +00:00
|
|
|
|
2021-10-27 20:44:50 +00:00
|
|
|
# def create_wire_joiner(self, start_point, length, is_horizontal):
|
|
|
|
# '''
|
|
|
|
# joins two wires going in the same direction for continuous sowing
|
|
|
|
# '''
|
|
|
|
# color = "blue" if is_horizontal else "red"
|
|
|
|
# direction = "h" if is_horizontal else "v"
|
|
|
|
# path = inkex.PathElement(attrib={
|
|
|
|
# 'id': "wire_segment",
|
|
|
|
# 'style': "stroke: %s; stroke-width: 0.4; fill: none; stroke-dasharray:0.4,0.4" % color,
|
|
|
|
# 'd': "m {},{} {} {} ".format(str(start_point[0]), str(start_point[1]), direction, length),
|
|
|
|
# # 'transform': inkex.get_correction_transform(svg),
|
|
|
|
# })
|
|
|
|
# self.svg.get_current_layer().append(path)
|
|
|
|
|
|
|
|
|
|
|
|
|
2021-10-25 17:09:15 +00:00
|
|
|
def close(self):
|
|
|
|
self.preview.close()
|
|
|
|
self.Destroy()
|
|
|
|
|
|
|
|
def cancel(self, event):
|
|
|
|
if self.cancel_hook:
|
|
|
|
self.cancel_hook()
|
|
|
|
|
|
|
|
self.close()
|
|
|
|
|
|
|
|
def __do_layout(self):
|
|
|
|
outer_sizer = wx.BoxSizer(wx.VERTICAL)
|
|
|
|
wire_sizer = wx.BoxSizer(wx.HORIZONTAL)
|
|
|
|
wire_sizer.Add(wx.StaticText(self, wx.ID_ANY, "Number of vertical wires"), 0, wx.LEFT | wx.ALIGN_CENTRE_VERTICAL, 0)
|
|
|
|
wire_sizer.Add(self.vertical_wire_spinner, 0, wx.LEFT, 10)
|
|
|
|
wire_sizer.Add(wx.StaticText(self, wx.ID_ANY, "Number of horizontal wires"), 0, wx.LEFT | wx.ALIGN_CENTRE_VERTICAL, 0)
|
|
|
|
wire_sizer.Add(self.horizontal_wire_spinner, 0, wx.LEFT, 10)
|
|
|
|
outer_sizer.Add(wire_sizer, 0, wx.EXPAND | wx.LEFT | wx.TOP | wx.RIGHT, 10)
|
|
|
|
|
|
|
|
|
|
|
|
buttons_sizer = wx.BoxSizer(wx.HORIZONTAL)
|
|
|
|
buttons_sizer.Add(self.cancel_button, 0, wx.RIGHT, 10)
|
|
|
|
buttons_sizer.Add(self.apply_button, 0, wx.RIGHT | wx.BOTTOM, 10)
|
|
|
|
outer_sizer.Add(buttons_sizer, 0, wx.ALIGN_RIGHT, 10)
|
|
|
|
|
|
|
|
self.SetSizerAndFit(outer_sizer)
|
|
|
|
self.Layout()
|
|
|
|
size = self.GetSize()
|
|
|
|
size.height = size.height + 200
|
|
|
|
self.SetSize(size)
|
|
|
|
|
|
|
|
class RectangleMetadata():
|
|
|
|
'''
|
|
|
|
Storage class to hold important information about rectangle
|
|
|
|
'''
|
|
|
|
def __init__(self, width, height, top, bottom, left, right):
|
|
|
|
self.width = width
|
|
|
|
self.height = height
|
|
|
|
self.top = top
|
|
|
|
self.bottom = bottom
|
|
|
|
self.left = left
|
|
|
|
self.right = right
|
|
|
|
|
|
|
|
def get_rectangle_points(self):
|
|
|
|
'''
|
|
|
|
returns upper_left , upper_right, lower_left, lower_right points as list of tuples
|
|
|
|
in that order
|
|
|
|
'''
|
|
|
|
return [
|
|
|
|
(self.left, self.top),
|
|
|
|
(self.right, self.top),
|
|
|
|
(self.left, self.bottom),
|
|
|
|
(self.right, self.bottom)
|
|
|
|
]
|
|
|
|
|
|
|
|
class SensorGrid(InkstitchExtension):
|
|
|
|
COMMANDS = ["grid"]
|
|
|
|
def __init__(self, *args, **kwargs):
|
|
|
|
self.cancelled = False
|
|
|
|
InkstitchExtension.__init__(self, *args, **kwargs)
|
|
|
|
for command in self.COMMANDS:
|
|
|
|
self.arg_parser.add_argument("--%s" % command, type=inkex.Boolean)
|
|
|
|
# self.arg_parser.add_argument("--horizontal_wires")
|
|
|
|
# self.arg_parser.add_argument("--vertical_wires")
|
|
|
|
# self.num_horizontal_wires = self.options.horizontal_wires
|
|
|
|
# self.num_vertical_wires = self.options.vertical_wires
|
|
|
|
# inkex.errormsg("params:{}, {}".format(self.num_horizontal_wires, self.num_vertical_wires))
|
|
|
|
|
|
|
|
|
|
|
|
def cancel(self):
|
|
|
|
self.cancelled = True
|
|
|
|
def effect(self):
|
|
|
|
|
|
|
|
# if not self.svg.selected:
|
|
|
|
# inkex.errormsg(_("Please select a single rectangle to apply a grid."))
|
|
|
|
# return
|
|
|
|
|
|
|
|
# get dims of user's grid in MM (for now, have users select mm as measurement)
|
|
|
|
# TODO: do conversion for later version??
|
|
|
|
rectangle = None
|
|
|
|
|
|
|
|
for elem in self.svg.get_selected():
|
|
|
|
if not isinstance(elem, Rectangle):
|
|
|
|
inkex.errormsg("type of elem:{}, path:{}, style:{}".format(type(elem), elem.get_path(), elem.style))
|
|
|
|
inkex.errormsg(_("Please select a rectangle"))
|
|
|
|
return
|
|
|
|
inkex.errormsg("top {}, bottom {}, left {}, right {}".format(elem.top, elem.bottom, elem.left, elem.right))
|
|
|
|
inkex.errormsg("path {}".format(elem.path))
|
|
|
|
rectangle = RectangleMetadata(elem.width, elem.height, elem.top, elem.bottom, elem.left, elem.right)
|
|
|
|
# try to draw line from here?
|
|
|
|
# parent = elem.getparent()
|
|
|
|
# inkex.errormsg("what is parent:{} --> {}".format(parent, type(parent)))
|
|
|
|
# def draw_SVG_line(x1, y1, x2, y2):
|
|
|
|
# # line_style = { 'stroke': 'dashed',
|
|
|
|
# # 'stroke-width':str(5),
|
|
|
|
# # 'fill': 'none'
|
|
|
|
# # }
|
|
|
|
|
|
|
|
# # line_attribs = {'style' : line_style,
|
|
|
|
# # inkex.addNS('label','inkscape') : name,
|
|
|
|
# node = inkex.Rectangle()
|
|
|
|
# d = "path M 50.18 26.5094 h 10.16 v 11.5906 h -10.16 z"
|
|
|
|
# node.set("d", d)
|
|
|
|
# dasharray = inkex.Style("stroke-dasharray:0.5,0.5;")
|
|
|
|
# node.set("style","stroke-dasharray:0.5,0.5;")
|
|
|
|
# inkex.errormsg("NODE PATH:{}".format(node.get_path()))
|
|
|
|
# return node
|
|
|
|
# node = draw_SVG_line(elem.left + 1, elem.top, elem.left + 1, elem.bottom)
|
|
|
|
# elem = inkex.etree.SubElement(parent, node)
|
|
|
|
# self.get_current_layer().append(elem)
|
|
|
|
# path = inkex.PathElement(attrib={
|
|
|
|
# 'id': "HERE",
|
|
|
|
# 'style': "stroke: %s; stroke-width: 0.4; fill: none;" % "red",
|
|
|
|
# 'd': "m 0,86.039999 h 30.48 l 45.719999,22.86 ",
|
|
|
|
# # 'transform': inkex.get_correction_transform(svg),
|
|
|
|
# })
|
|
|
|
# self.svg.get_current_layer().append(path)
|
|
|
|
# for elem in self.svg.get_selected():
|
|
|
|
# elem.style['fill'] = 'green'
|
|
|
|
# elem.style["stroke"] = 'dashed'
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
app = wx.App()
|
|
|
|
frame = SensorGridFrame(rectangle, self.svg, on_cancel=self.cancel)
|
|
|
|
|
|
|
|
# position left, center
|
|
|
|
current_screen = wx.Display.GetFromPoint(wx.GetMousePosition())
|
|
|
|
display = wx.Display(current_screen)
|
|
|
|
display_size = display.GetClientArea()
|
|
|
|
frame_size = frame.GetSize()
|
|
|
|
frame.SetPosition((int(display_size[0]), int(display_size[3] / 2 - frame_size[1] / 2)))
|
|
|
|
|
|
|
|
frame.Show()
|
|
|
|
app.MainLoop()
|
|
|
|
|
|
|
|
if self.cancelled:
|
|
|
|
# This prevents the superclass from outputting the SVG, because we
|
|
|
|
# may have modified the DOM.
|
|
|
|
sys.exit(0)
|
|
|
|
|
|
|
|
def path_style(self, element):
|
|
|
|
color = element.style('stroke', '#000000')
|
|
|
|
return "stroke:%s;stroke-width:1px;fill:none" % (color)
|
|
|
|
'''
|
|
|
|
|
|
|
|
|
|
|
|
top 26.509441, bottom 38.099998, left 43.18, right 53.34
|
|
|
|
path M 43.18 26.5094 h 10.16 v 11.5906 h -10.16 z
|
|
|
|
dims in GUI: 10.16 x 11.590557
|
|
|
|
|
|
|
|
'''
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if __name__ == '__main__':
|
|
|
|
inkex.errormsg(sys.argv[1:])
|
|
|
|
parser = ArgumentParser()
|
|
|
|
parser.add_argument("--horizontal_wires")
|
|
|
|
parser.add_argument("--vertical_wires")
|
|
|
|
parser.add_argument('args', nargs=REMAINDER)
|
|
|
|
args, _ = parser.parse_known_args()
|
|
|
|
inkex.errormsg("args:{}".format(args))
|
|
|
|
SensorGrid(args.horizontal_wires, args.vertical_wires).run()
|