kopia lustrzana https://github.com/hdacosta400/intelligent-textiles
334 wiersze
14 KiB
Python
334 wiersze
14 KiB
Python
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, Path
|
|
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
|
|
import numpy as np
|
|
|
|
# minimum space apart for wires in grid to avoid interference / shorting
|
|
MIN_GRID_SPACING = 2.5
|
|
BBOX_SPACING = 5
|
|
class SensorGridFrame(wx.Frame):
|
|
DEFAULT_FONT = "small_font"
|
|
def __init__(self, shape_points, rectangle, wire_connector, 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.shape_points = shape_points
|
|
self.rectangle = rectangle
|
|
self.vertical_wire_connector, self.horizontal_wire_connector = wire_connector
|
|
self.upper_left, self.upper_right, self.lower_left, self.lower_right = self.rectangle.get_rectangle_points()
|
|
self.svg = svg
|
|
self.paths = []
|
|
|
|
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))
|
|
|
|
self.horizontal_wire = None
|
|
self.vertical_wire = None
|
|
|
|
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
|
|
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):
|
|
inkex.errormsg('''The horizontal wires must be at least {} mm apart
|
|
They are currently {} mm apart. Either decrease the
|
|
number of wires or increase the size of the grid and try again.'''.format(MIN_GRID_SPACING, horizontal_wire_spacing))
|
|
return
|
|
if (vertical_wire_spacing < MIN_GRID_SPACING):
|
|
inkex.errormsg('''The vertical wires must be at least {} mm apart
|
|
They are currently {} mm apart. Either decrease the
|
|
number of wires or increase the size of the grid and try again.'''.format(MIN_GRID_SPACING, vertical_wire_spacing))
|
|
return
|
|
self.lay_horizontal_wires(total_horizontal_spacing)
|
|
self.lay_vertical_wires(total_vertical_spacing)
|
|
|
|
def lay_horizontal_wires(self, horizontal_wire_spacing):
|
|
curr_point = list(self.lower_left)
|
|
wire_count = 0
|
|
points = []
|
|
while round(curr_point[1]) != round(self.rectangle.top + horizontal_wire_spacing):
|
|
curr_point[1] -= horizontal_wire_spacing
|
|
connections = []
|
|
if self.horizontal_wire_connector.has_available_wires():
|
|
connections = self.horizontal_wire_connector.connect_wire()
|
|
if wire_count % 2 == 0:
|
|
points.append('{},{}'.format(self.rectangle.left - BBOX_SPACING, curr_point[1]))
|
|
points.append('{},{}'.format(self.rectangle.right, curr_point[1]))
|
|
for p in connections:
|
|
points.append('{},{}'.format(p.x, p.y))
|
|
else:
|
|
points.append('{},{}'.format(self.rectangle.right, curr_point[1]))
|
|
points.append('{},{}'.format(self.rectangle.left - BBOX_SPACING, curr_point[1]))
|
|
|
|
wire_count += 1
|
|
|
|
self.create_path(points, is_horizontal=True)
|
|
|
|
def lay_vertical_wires(self, vertical_wire_spacing):
|
|
curr_point = list(self.upper_left)
|
|
wire_count = 0
|
|
points = []
|
|
while round(curr_point[0]) != round(self.rectangle.right - vertical_wire_spacing):
|
|
curr_point[0] += vertical_wire_spacing
|
|
connections = []
|
|
if self.vertical_wire_connector.has_available_wires():
|
|
connections = self.vertical_wire_connector.connect_wire()
|
|
if wire_count % 2 == 0:
|
|
points.append('{},{}'.format(curr_point[0], self.rectangle.top - BBOX_SPACING))
|
|
points.append('{},{}'.format(curr_point[0], self.rectangle.bottom))
|
|
for p in connections:
|
|
points.append('{},{}'.format(p.x, p.y))
|
|
else:
|
|
points.append('{},{}'.format(curr_point[0], self.rectangle.bottom))
|
|
points.append('{},{}'.format(curr_point[0], self.rectangle.top - BBOX_SPACING))
|
|
|
|
wire_count += 1
|
|
|
|
|
|
inkex.errormsg("vertical points:{}".format(points))
|
|
self.create_path(points, is_horizontal=False)
|
|
|
|
def create_path(self, points, is_horizontal):
|
|
'''
|
|
Creates a wire segment path given all of the points sequentially
|
|
'''
|
|
color = "red" if is_horizontal else "blue"
|
|
path_str = ' '.join(points)
|
|
path = inkex.Polyline(attrib={
|
|
'id': "wire_segment",
|
|
'style': "stroke: %s; stroke-width: 0.4; fill: none; stroke-dasharray:0.4,0.4" % color,
|
|
'points': path_str,
|
|
# 'transform': inkex.get_correction_transform(svg),
|
|
})
|
|
self.svg.get_current_layer().append(path)
|
|
# store wire objects for future use
|
|
if is_horizontal:
|
|
self.horizontal_wire = path
|
|
else:
|
|
self.vertical_wire = path
|
|
|
|
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 BoundingBoxMetadata():
|
|
'''
|
|
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 Connector():
|
|
'''
|
|
Object to represent connector of wires
|
|
'''
|
|
def __init__(self, connector_points):
|
|
self.connector_points = connector_points # all coords where wires need to route to
|
|
self.open_wire_idx = 0 # idx of next available wire
|
|
inkex.errormsg("num connectors:{}".format(len(self.connector_points)))
|
|
def has_available_wires(self):
|
|
return self.open_wire_idx <= len(self.connector_points) - 4 # every connector is 4 points
|
|
def connect_wire(self):
|
|
if self.has_available_wires():
|
|
points = self.connector_points[self.open_wire_idx:self.open_wire_idx + 4]
|
|
self.open_wire_idx += 2
|
|
return points
|
|
else:
|
|
inkex.errormsg("connector has no more open connections. Decrease the number of wires!")
|
|
return None
|
|
|
|
|
|
|
|
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)
|
|
def cancel(self):
|
|
self.cancelled = True
|
|
def effect(self):
|
|
|
|
rectangle = None
|
|
shape_points = None
|
|
connector_points = []
|
|
connectors = [] # list of connector objects
|
|
for elem in self.svg.get_selected(): # PATH ELEMENT
|
|
'''
|
|
need this for loop for when multiple elements are selected (object , 2 connectors[?])
|
|
for now it is just the object itself
|
|
'''
|
|
inkex.errormsg("things selected:{}".format(len(self.svg.get_selected())))
|
|
inkex.errormsg("type of elem:{}".format(type(elem)))
|
|
shape_points = [p for p in elem.path.end_points]
|
|
inkex.errormsg("points:{},{}".format(shape_points,len(shape_points)))
|
|
|
|
|
|
if len(shape_points) > 4 and rectangle is None: # use bounding box of OBJECT
|
|
#for now, this will differentiate the OBJECT from the CONNECTORS
|
|
bbox = elem.bounding_box()
|
|
rectangle = BoundingBoxMetadata(bbox.width, bbox.height, bbox.top, bbox.bottom, bbox.left, bbox.right)
|
|
inkex.errormsg("rect points:{}".format(rectangle.get_rectangle_points()))
|
|
elif len(shape_points) == 4:
|
|
# first and last points represent the ends that will be used for routing!
|
|
for p in shape_points:
|
|
connector_points.append(p)
|
|
if len(connector_points) == 64: # num of points making up a connector
|
|
connectors.append(Connector(connector_points))
|
|
connector_points = []
|
|
|
|
|
|
# if shape_points is not None and rectangle is not None and len(connectors) > 0:
|
|
if True:
|
|
app = wx.App()
|
|
frame = SensorGridFrame(shape_points, rectangle, connectors, 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)
|
|
else:
|
|
inkex.errormsg("Please make sure the shape and its connectors are selected!")
|
|
return
|
|
|
|
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()
|