kopia lustrzana https://github.com/hdacosta400/intelligent-textiles
Stitching of arbitrary curves and line segments
Next TODO: stitching of composite grids as well as rework of combine grids algorithmmain
rodzic
72a932b325
commit
0a08c8d4a4
Plik binarny nie jest wyświetlany.
|
@ -1,27 +1,8 @@
|
|||
from operator import is_
|
||||
from inkex.deprecated import INKEX_DIR
|
||||
from networkx.algorithms.graphical import is_graphical
|
||||
from networkx.algorithms.operators.binary import union
|
||||
import sys
|
||||
from base64 import b64decode
|
||||
from argparse import ArgumentParser, REMAINDER
|
||||
|
||||
import appdirs
|
||||
from argparse import ArgumentParser
|
||||
import inkex
|
||||
from inkex import Line, Rectangle, Path, Polyline, PathElement
|
||||
import wx
|
||||
import wx.adv
|
||||
from inkex import Polyline, PathElement
|
||||
from lxml import etree
|
||||
|
||||
class CombineGridsFrame(wx.Frame):
|
||||
DEFAULT_FONT = "small_font"
|
||||
def __init__(self, shape1, shape2, svg, *args, **kwargs):
|
||||
if sys.platform.startswith('win32'):
|
||||
import locale
|
||||
locale.setlocale(locale.LC_ALL, "C")
|
||||
lc = wx.Locale()
|
||||
lc.Init(wx.LANGUAGE_DEFAULT)
|
||||
pass
|
||||
|
||||
class Connector():
|
||||
'''
|
||||
|
@ -54,19 +35,22 @@ class Connector():
|
|||
|
||||
class CombineGridsEffect(inkex.Effect):
|
||||
def add_arguments(self, pars):
|
||||
pars.add_argument("--alignment", type=bool, help="The type of connection to make")
|
||||
pars.add_argument("--alignment", type=int, help="The type of connection to make")
|
||||
|
||||
def effect(self):
|
||||
arg_parser = ArgumentParser()
|
||||
self.add_arguments(arg_parser)
|
||||
args,_ = arg_parser.parse_known_args()
|
||||
combine_grids_worker = CombineGridsWorker(self.svg, args.alignment)
|
||||
inkex.errormsg("what is alignment:{}".format(args.alignment))
|
||||
is_horizontal_connection = True if args.alignment == 1 else False
|
||||
combine_grids_worker = CombineGridsWorker(self.svg, is_horizontal_connection)
|
||||
combine_grids_worker.run()
|
||||
|
||||
|
||||
class CombineGridsWorker():
|
||||
COMMANDS = ["combine_grids"]
|
||||
def __init__(self, svg, is_horizontal_connection):
|
||||
print("WORKER INIT")
|
||||
self.svg = svg
|
||||
self.is_horizontal_connection = is_horizontal_connection
|
||||
self.wires = []
|
||||
|
@ -306,6 +290,7 @@ class CombineGridsWorker():
|
|||
etree.SubElement(self.svg.get_current_layer(), inkex.addNS('path','svg'), line_attribs)
|
||||
|
||||
def run(self):
|
||||
|
||||
connector_pins = []
|
||||
connector_bbox = None
|
||||
for elem in self.svg.get_selected():
|
||||
|
@ -343,7 +328,6 @@ class Wire():
|
|||
def get_num_wire_joins(self, is_horizontal):
|
||||
'''
|
||||
Determines how many wires were horizontally joined together to create the current wire object
|
||||
|
||||
The default is 1
|
||||
'''
|
||||
point_counter = 1
|
||||
|
|
|
@ -12,14 +12,12 @@ MIN_GRID_SPACING = inkex.units.convert_unit(2.5, "mm")
|
|||
class CreateCustomGridEffect(inkex.Effect):
|
||||
|
||||
def add_arguments(self, pars):
|
||||
inkex.errormsg("HELOOOOOOOOOOO")
|
||||
pars.add_argument("--horizontal_wires", type=str,\
|
||||
help="The number of desired horizontal wires")
|
||||
pars.add_argument("--vertical_wires", type=str,\
|
||||
help="The number of desired vertical wires")
|
||||
|
||||
def effect(self):
|
||||
inkex.errormsg("HELOOOOOOOOOOO")
|
||||
arg_parser = ArgumentParser()
|
||||
self.add_arguments(arg_parser)
|
||||
args, _ = arg_parser.parse_known_args()
|
||||
|
@ -86,8 +84,6 @@ class CreateCustomGridWorker():
|
|||
points = ['{}, {}'.format(p.x, p.y) for p in [self.lower_left, self.lower_right]]
|
||||
self.create_path(points, "orange")
|
||||
|
||||
|
||||
|
||||
|
||||
def run(self):
|
||||
# self.draw_corners()
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension">
|
||||
<name>Create Grid</name>
|
||||
<name>Create BBox Grid</name>
|
||||
<id>org.inkscape.effect.create_grid</id>
|
||||
<effect>
|
||||
<effects-menu>
|
||||
|
|
|
@ -1,14 +1,6 @@
|
|||
import json
|
||||
import os
|
||||
import sys
|
||||
from base64 import b64decode
|
||||
from argparse import ArgumentParser, REMAINDER
|
||||
|
||||
import appdirs
|
||||
from argparse import ArgumentParser
|
||||
import inkex
|
||||
from inkex import Line, Rectangle, Path, Polyline
|
||||
import wx
|
||||
import wx.adv
|
||||
from inkex import Rectangle
|
||||
from lxml import etree
|
||||
import pyembroidery
|
||||
import matplotlib.pyplot as plt
|
||||
|
@ -63,59 +55,29 @@ class CreateGridEffect(inkex.Effect):
|
|||
shape_points = None
|
||||
rectangle = None
|
||||
for elem in self.svg.get_selected(): # PATH ELEMENT
|
||||
units = "mm" if type(elem) == Rectangle else "px"
|
||||
shape_points = [p for p in elem.path.end_points]
|
||||
bbox = elem.bounding_box()
|
||||
rectangle = BoundingBoxMetadata(inkex.units.convert_unit(bbox.width, 'mm'),
|
||||
inkex.units.convert_unit(bbox.height, 'mm'),
|
||||
inkex.units.convert_unit(bbox.top, 'mm'),
|
||||
inkex.units.convert_unit(bbox.bottom, 'mm'),
|
||||
inkex.units.convert_unit(bbox.left, 'mm'),
|
||||
inkex.units.convert_unit(bbox.right, 'mm'))
|
||||
inkex.errormsg("shape points, bbox:{} , {}".format(shape_points, bbox))
|
||||
rectangle = BoundingBoxMetadata(inkex.units.convert_unit(bbox.width, units),
|
||||
inkex.units.convert_unit(bbox.height, units),
|
||||
inkex.units.convert_unit(bbox.top, units),
|
||||
inkex.units.convert_unit(bbox.bottom, units),
|
||||
inkex.units.convert_unit(bbox.left, units),
|
||||
inkex.units.convert_unit(bbox.right, units))
|
||||
|
||||
create_grid_worker = CreateGridWorker(shape_points, rectangle, int(args.horizontal_wires), int(args.vertical_wires), self.svg, self.document)
|
||||
create_grid_worker = CreateGridWorker(shape_points, rectangle, int(args.horizontal_wires), int(args.vertical_wires), self.svg)
|
||||
create_grid_worker.run()
|
||||
|
||||
# parent = self.svg.get_current_layer()
|
||||
# self.draw_SVG_line(10,10,0,0, parent)
|
||||
|
||||
def draw_SVG_line(self, x1, y1, x2, y2, parent):
|
||||
color = "red"
|
||||
line_attribs = {
|
||||
'style' : "stroke: %s; stroke-width: 0.4; fill: none; stroke-dasharray:0.4,0.4" % color,
|
||||
# 'd' : 'M 55.3977 90.881 H 114.748 V 80.9478 H 46.3977 V 78.0146 H 114.748 V 75.0815 H 46.3977 V 72.1483 H 114.748 V 69.2151 H 46.3977 V 66.2819 H 114.748 V 63.3488 H 46.3977 V 60.4156 H 114.748 V 57.4824 H 46.3977',
|
||||
'points': 'M 0,0 9,9 5,5'
|
||||
}
|
||||
|
||||
line = etree.SubElement(parent, inkex.addNS('path','svg'), line_attribs)
|
||||
|
||||
points = ['0,0', '10,10']
|
||||
color = "red"
|
||||
path_str = ' '.join(points)
|
||||
poly = 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,
|
||||
})
|
||||
inkex.errormsg(str(poly.get_path()))
|
||||
|
||||
line_attribs = {
|
||||
'style' : "stroke: %s; stroke-width: 0.4; fill: none; stroke-dasharray:0.4,0.4" % color,
|
||||
'd': str(poly.get_path())
|
||||
}
|
||||
|
||||
etree.SubElement(self.svg.get_current_layer(), inkex.addNS('path','svg'), line_attribs)
|
||||
|
||||
# polyline(points,style=style)
|
||||
class CreateGridWorker():
|
||||
|
||||
def __init__(self, shape_points, rectangle, num_horizontal_wires, num_vertical_wires, svg, document):
|
||||
def __init__(self, shape_points, rectangle, num_horizontal_wires, num_vertical_wires, svg):
|
||||
self.shape_points = shape_points
|
||||
self.rectangle = rectangle
|
||||
self.num_horizontal_wires = num_horizontal_wires
|
||||
self.num_vertical_wires = num_vertical_wires
|
||||
self.svg = svg
|
||||
self.upper_left, self.upper_right,self.lower_left,self.lower_right = self.rectangle.get_rectangle_points()
|
||||
self.document = document
|
||||
|
||||
|
||||
def run(self):
|
||||
|
@ -157,12 +119,12 @@ class CreateGridWorker():
|
|||
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
|
||||
inkex.errormsg("coming to lay horsz points:{}".format(points))
|
||||
return self.create_path(points, is_horizontal=True)
|
||||
|
||||
def lay_vertical_wires(self, vertical_wire_spacing):
|
||||
|
@ -239,20 +201,12 @@ class MakeStitchesWorker():
|
|||
|
||||
intersection_points = sorted(intersection_points, key = lambda p: p[0])
|
||||
point_idx = 0
|
||||
# inkex.errormsg("num intersection points:{}".format(len(intersection_points)))
|
||||
# inkex.errormsg("what are intersection points:{},{}".format(intersection_points, len(intersection_points)))
|
||||
if p0.x < p1.x: #p0 is on the right
|
||||
row_stitch_array.append([(p0.x + intersection_points[point_idx][0]) // 2, p0.y])
|
||||
row_stitch_array.append([(p1.x + intersection_points[-1][0]) // 2, p1.y])
|
||||
|
||||
# pattern.add_stitch_absolute(pyembroidery.STITCH, (p0.x + intersection_points[point_idx][0]) // 2, p0.y)
|
||||
# pattern.add_stitch_absolute(pyembroidery.STITCH, (p1.x + intersection_points[-1][0]) // 2, p1.y)
|
||||
else:
|
||||
row_stitch_array.append([(p0.x + intersection_points[-1][0]) // 2, p0.y])
|
||||
row_stitch_array.append([(p1.x + intersection_points[0][0]) // 2, p1.y])
|
||||
|
||||
# pattern.add_stitch_absolute(pyembroidery.STITCH, (p0.x + intersection_points[-1][0]) // 2, p0.y)
|
||||
# pattern.add_stitch_absolute(pyembroidery.STITCH, (p1.x + intersection_points[0][0]) // 2, p1.y)
|
||||
inkex.errormsg("first and last endpoint x values: {} and {}".format(p0.x, p1.x))
|
||||
inkex.errormsg("first and last x values:{} and {}".format(intersection_points[point_idx][0], intersection_points[-1][0]))
|
||||
|
||||
|
@ -261,7 +215,6 @@ class MakeStitchesWorker():
|
|||
mid_x = (intersection_points[point_idx][0] + intersection_points[point_idx+1][0]) // 2
|
||||
point_idx += 1
|
||||
row_stitch_array.append([mid_x, p0.y])
|
||||
# pattern.add_stitch_absolute(pyembroidery.STITCH, mid_x, p0.y)
|
||||
|
||||
# need to stitch wire continously from bottom left to top right, so row_stitch array is reversed
|
||||
# depending on what side of the wire we started on for this iteration
|
||||
|
@ -277,22 +230,18 @@ class MakeStitchesWorker():
|
|||
for x, y in stitch_array:
|
||||
pattern.add_stitch_absolute(pyembroidery.STITCH, x, y)
|
||||
|
||||
inkex.errormsg("where are my stitches:{}, num_stitches = {}".format(pattern.stitches, len(pattern.stitches)))
|
||||
pyembroidery.write_pes(pattern, '/Users/hdacosta/Desktop/UROP/output/pattern.dst')
|
||||
|
||||
# sanity_check
|
||||
# inkex.errormsg("num intersections:{}".format(len(intersection_points)))
|
||||
self.visualize_stitches(pattern)
|
||||
|
||||
# self.visualize_stitches(pattern)
|
||||
def visualize_stitches(self, pattern):
|
||||
#visualize stitches
|
||||
stitch_info = np.asarray(pattern.stitches)
|
||||
#Extract info from np.array and convert to mm
|
||||
x_coord = stitch_info[:,0]/10
|
||||
inkex.errormsg("vis x coords:{}".format(x_coord))
|
||||
y_coord = stitch_info[:,1]/10
|
||||
num_of_stitches = len(x_coord)
|
||||
inkex.errormsg("NUM OF STITCHES:{}".format(num_of_stitches))
|
||||
#Plot the stitches
|
||||
stitch_loc = plt.scatter(x_coord, y_coord, s = 1, c = 'black')
|
||||
|
||||
|
@ -309,6 +258,7 @@ class MakeStitchesWorker():
|
|||
|
||||
#show the plot
|
||||
plt.show()
|
||||
|
||||
|
||||
def make_vertical_stitches(self):
|
||||
pass
|
||||
|
|
|
@ -0,0 +1,16 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension">
|
||||
<name>Make Stitches</name>
|
||||
<id>org.inkscape.effect.make_stitches</id>
|
||||
<effect>
|
||||
<effects-menu>
|
||||
<submenu name="Sensor Grid Tools" />
|
||||
</effects-menu>
|
||||
</effect>
|
||||
<param name="wire_type" type="optiongroup" appearance="radio" gui-text="Method">
|
||||
<option value="0">Straight</option>
|
||||
<option value="1">Curved</option>
|
||||
</param> <script>
|
||||
<command location="inx" interpreter="python">make_stitches.py</command>
|
||||
</script>
|
||||
</inkscape-extension>
|
|
@ -0,0 +1,193 @@
|
|||
import inkex
|
||||
from inkex.paths import Path
|
||||
import pyembroidery
|
||||
from argparse import ArgumentParser
|
||||
import numpy as np
|
||||
from matplotlib import pyplot as plt
|
||||
from lxml import etree
|
||||
import math
|
||||
from bezier import Curve
|
||||
from scipy import interpolate
|
||||
import simplepath
|
||||
|
||||
class MakeStitchesEffect(inkex.Effect):
|
||||
def add_arguments(self, pars):
|
||||
pars.add_argument("--wire_type", type=int)
|
||||
|
||||
def effect(self):
|
||||
arg_parser = ArgumentParser()
|
||||
self.add_arguments(arg_parser)
|
||||
args,_ = arg_parser.parse_known_args()
|
||||
wire = None
|
||||
|
||||
# add a case for multiple selections (grid stitching)
|
||||
for elem in self.svg.get_selected():
|
||||
wire = elem
|
||||
|
||||
# debugging for mapping out control and end points of a path
|
||||
# poi = [p for p in wire.path.end_points]
|
||||
# points = ['{},{}'.format(p.x,p.y) for p in poi]
|
||||
# self.create_path(points, True)
|
||||
# poi = [p for p in wire.path.control_points]
|
||||
# points = ['{},{}'.format(p.x,p.y) for p in poi]
|
||||
# self.create_path(points, False)
|
||||
|
||||
is_curve = True if args.wire_type == 1 else False
|
||||
make_stitches_worker = MakeStitchesWorker(wire, is_curve)
|
||||
make_stitches_worker.run()
|
||||
|
||||
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",
|
||||
'points': path_str,
|
||||
})
|
||||
|
||||
line_attribs = {
|
||||
'style' : "stroke: %s; stroke-width: 0.4; fill: none; stroke-dasharray:0.4,0.4" % color,
|
||||
'd': str(path.get_path())
|
||||
# 'points': 'M 0,0 9,9 5,5'
|
||||
}
|
||||
|
||||
etree.SubElement(self.svg.get_current_layer(), inkex.addNS('path','svg'), line_attribs)
|
||||
return path
|
||||
|
||||
class MakeStitchesWorker(inkex.Effect):
|
||||
def __init__(self, wire, is_curve):
|
||||
self.wire = wire
|
||||
self.is_curve = is_curve
|
||||
|
||||
self.control_points = []
|
||||
if self.is_curve:
|
||||
self.control_points = [p for p in wire.path.control_points]
|
||||
|
||||
self.end_points = [p for p in wire.path.end_points]
|
||||
self.wire_points = []
|
||||
if self.is_curve:
|
||||
points = []
|
||||
path = simplepath.parsePath(wire.path)
|
||||
for t, ele in path:
|
||||
for i in range(0,len(ele)-1,2):
|
||||
x = ele[i]
|
||||
y = ele[i+1]
|
||||
points.append([x,y])
|
||||
self.wire_points = points
|
||||
else:
|
||||
self.wire_points = self.end_points
|
||||
|
||||
|
||||
def stitch_curve(self):
|
||||
'''
|
||||
Bezier curves represented with 4 points
|
||||
We can use them and a general parametric equation to generate stitch points
|
||||
'''
|
||||
stitch_points = []
|
||||
|
||||
nodes = np.asfortranarray([
|
||||
# [p.x for p in self.wire_points],
|
||||
# [p.y for p in self.wire_points]
|
||||
[p[0] for p in self.wire_points],
|
||||
[p[1] for p in self.wire_points]
|
||||
]).astype('double')
|
||||
|
||||
curve = Curve.from_nodes(nodes, copy=True)
|
||||
|
||||
|
||||
t = 0.01
|
||||
point = curve.evaluate(t)
|
||||
x = point[0][0]
|
||||
y = point[1][0]
|
||||
stitch_points.append([x,y])
|
||||
for _ in range(99): # change this number to change pitch of stitches, may also convert to user input in the future
|
||||
point = curve.evaluate(t)
|
||||
x = point[0][0]
|
||||
y = point[1][0]
|
||||
stitch_points.append([x,y])
|
||||
t += .01
|
||||
return stitch_points
|
||||
|
||||
def compute_euclidean_distance(self, x1, y1, x2, y2):
|
||||
return math.sqrt((y2 - y1) ** 2 + (x2 - x1) ** 2)
|
||||
|
||||
def segment_line(self, line, num_points):
|
||||
'''
|
||||
Breaks line into num_points equal parts
|
||||
returns array of points
|
||||
|
||||
line: A shapely.LineString object (interpolation along line can be done manually but this is easier)
|
||||
'''
|
||||
points = []
|
||||
def parameterize_line(t):
|
||||
x_t = line[0][0] + (line[1][0] - line[0][0]) * t
|
||||
y_t = line[0][1] + (line[1][1] - line[0][1]) * t
|
||||
return x_t, y_t
|
||||
|
||||
segment_length = 1 / (num_points + 1)
|
||||
for i in range(1 ,num_points+2): # adjust from 0 to n+1 bc we cant put in 0 to the parameterized line equation
|
||||
x, y = parameterize_line(i * segment_length)
|
||||
points.append([x,y])
|
||||
return points
|
||||
|
||||
def stitch_segment(self):
|
||||
stitch_points = []
|
||||
for i in range(len(self.wire_points) - 1):
|
||||
p1 = self.wire_points[i]
|
||||
p2 = self.wire_points[i+1]
|
||||
stitch_points.append([p1.x, p1.y])
|
||||
line = [[p1.x, p1.y], [p2.x, p2.y]]
|
||||
num_points = 3 # could make this a user input somehow?
|
||||
stitch_points.extend(self.segment_line(line, num_points))
|
||||
return stitch_points
|
||||
|
||||
|
||||
|
||||
|
||||
def make_stitches(self, stitch_points):
|
||||
pattern = pyembroidery.EmbPattern()
|
||||
for x, y in stitch_points:
|
||||
pattern.add_stitch_absolute(pyembroidery.STITCH, x, y)
|
||||
pyembroidery.write_pes(pattern, '/Users/hdacosta/Desktop/UROP/output/pattern1.dst')
|
||||
self.visualize_stitches(pattern)
|
||||
|
||||
|
||||
def visualize_stitches(self, pattern):
|
||||
#visualize stitches
|
||||
stitch_info = np.asarray(pattern.stitches)
|
||||
#Extract info from np.array and convert to mm
|
||||
x_coord = stitch_info[:,0]/10
|
||||
y_coord = stitch_info[:,1]/10
|
||||
num_of_stitches = len(x_coord)
|
||||
#Plot the stitches
|
||||
stitch_loc = plt.scatter(x_coord, y_coord, s = 1, c = 'black')
|
||||
|
||||
#Add label to every ith stitch
|
||||
i = 0
|
||||
while i <= num_of_stitches - 1:
|
||||
plt.annotate(i, (x_coord[i], y_coord[i]))
|
||||
i += 5
|
||||
|
||||
#label axis
|
||||
plt.title("Stitch Vis")
|
||||
plt.xlabel('X Coordinates (mm)')
|
||||
plt.ylabel('Y Coordinates (mm)')
|
||||
|
||||
#show the plot
|
||||
plt.show()
|
||||
|
||||
def run(self):
|
||||
stitch_points = None
|
||||
if self.is_curve:
|
||||
stitch_points = self.stitch_curve()
|
||||
else:
|
||||
stitch_points = self.stitch_segment()
|
||||
self.make_stitches(stitch_points)
|
||||
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
MakeStitchesEffect().run()
|
Ładowanie…
Reference in New Issue