2018-03-31 00:37:11 +00:00
|
|
|
import math
|
|
|
|
|
2018-12-19 17:46:31 +00:00
|
|
|
from shapely.geometry import LineString, Point as ShapelyPoint
|
|
|
|
|
2018-02-28 00:43:15 +00:00
|
|
|
|
new extension: Auto-Route Satin Columns (#330)
**video demo:** https://www.youtube.com/watch?v=tbghtqziB1g
This branch adds a new extension, Auto-Route Satin Columns, implementing #214! This is a huge new feature that opens the door wide for exciting stuff like lettering (#142).
To use it, select some satin columns and run the extension. After a few seconds, it will replace your satins with a new set with a logical stitching order. Under-pathing and jump-stitches will be added as necessary, and satins will be broken to facilitate jumps. The resulting satins will retain all of the parameters you had set on the original satins, including underlay, zig-zag spacing, etc.
By default, it will choose the left-most extreme as the starting point and the right-most extreme as the ending point (even if these occur partway through a satin such as the left edge of a letter "o"). You can override this by attaching the new "Auto-route satin stitch starting/ending position" commands.
There's also an option to add trims instead of jump stitches. Any jump stitch over 1mm is trimmed. I might make this configurable in the future but in my tests it seems to do a good job. Trim commands are added to the SVG, so it's easy enough to modify/delete as you see fit.
2018-10-30 23:43:21 +00:00
|
|
|
def cut(line, distance, normalized=False):
|
2018-02-28 00:43:15 +00:00
|
|
|
""" Cuts a LineString in two at a distance from its starting point.
|
|
|
|
|
|
|
|
This is an example in the Shapely documentation.
|
|
|
|
"""
|
new extension: Auto-Route Satin Columns (#330)
**video demo:** https://www.youtube.com/watch?v=tbghtqziB1g
This branch adds a new extension, Auto-Route Satin Columns, implementing #214! This is a huge new feature that opens the door wide for exciting stuff like lettering (#142).
To use it, select some satin columns and run the extension. After a few seconds, it will replace your satins with a new set with a logical stitching order. Under-pathing and jump-stitches will be added as necessary, and satins will be broken to facilitate jumps. The resulting satins will retain all of the parameters you had set on the original satins, including underlay, zig-zag spacing, etc.
By default, it will choose the left-most extreme as the starting point and the right-most extreme as the ending point (even if these occur partway through a satin such as the left edge of a letter "o"). You can override this by attaching the new "Auto-route satin stitch starting/ending position" commands.
There's also an option to add trims instead of jump stitches. Any jump stitch over 1mm is trimmed. I might make this configurable in the future but in my tests it seems to do a good job. Trim commands are added to the SVG, so it's easy enough to modify/delete as you see fit.
2018-10-30 23:43:21 +00:00
|
|
|
if normalized:
|
|
|
|
distance *= line.length
|
|
|
|
|
2018-09-29 20:00:36 +00:00
|
|
|
if distance <= 0.0:
|
|
|
|
return [None, line]
|
|
|
|
elif distance >= line.length:
|
|
|
|
return [line, None]
|
|
|
|
|
2018-08-09 19:16:36 +00:00
|
|
|
coords = list(ShapelyPoint(p) for p in line.coords)
|
|
|
|
traveled = 0
|
|
|
|
last_point = coords[0]
|
|
|
|
for i, p in enumerate(coords[1:], 1):
|
|
|
|
traveled += p.distance(last_point)
|
|
|
|
last_point = p
|
|
|
|
if traveled == distance:
|
2018-02-28 00:43:15 +00:00
|
|
|
return [
|
2018-08-22 00:32:50 +00:00
|
|
|
LineString(coords[:i + 1]),
|
2018-02-28 00:43:15 +00:00
|
|
|
LineString(coords[i:])]
|
2018-08-09 19:16:36 +00:00
|
|
|
if traveled > distance:
|
2018-02-28 00:43:15 +00:00
|
|
|
cp = line.interpolate(distance)
|
|
|
|
return [
|
|
|
|
LineString(coords[:i] + [(cp.x, cp.y)]),
|
|
|
|
LineString([(cp.x, cp.y)] + coords[i:])]
|
|
|
|
|
2018-08-22 00:32:50 +00:00
|
|
|
|
2018-02-28 00:43:15 +00:00
|
|
|
def cut_path(points, length):
|
|
|
|
"""Return a subsection of at the start of the path that is length units long.
|
|
|
|
|
|
|
|
Given a path denoted by a set of points, walk along it until we've travelled
|
|
|
|
the specified length and return a new path up to that point.
|
|
|
|
|
|
|
|
If the original path isn't that long, just return it as is.
|
|
|
|
"""
|
|
|
|
|
|
|
|
if len(points) < 2:
|
|
|
|
return points
|
|
|
|
|
|
|
|
path = LineString(points)
|
|
|
|
subpath, rest = cut(path, length)
|
|
|
|
|
2018-03-31 00:37:11 +00:00
|
|
|
return [Point(*point) for point in subpath.coords]
|
|
|
|
|
|
|
|
|
new extension: Auto-Route Satin Columns (#330)
**video demo:** https://www.youtube.com/watch?v=tbghtqziB1g
This branch adds a new extension, Auto-Route Satin Columns, implementing #214! This is a huge new feature that opens the door wide for exciting stuff like lettering (#142).
To use it, select some satin columns and run the extension. After a few seconds, it will replace your satins with a new set with a logical stitching order. Under-pathing and jump-stitches will be added as necessary, and satins will be broken to facilitate jumps. The resulting satins will retain all of the parameters you had set on the original satins, including underlay, zig-zag spacing, etc.
By default, it will choose the left-most extreme as the starting point and the right-most extreme as the ending point (even if these occur partway through a satin such as the left edge of a letter "o"). You can override this by attaching the new "Auto-route satin stitch starting/ending position" commands.
There's also an option to add trims instead of jump stitches. Any jump stitch over 1mm is trimmed. I might make this configurable in the future but in my tests it seems to do a good job. Trim commands are added to the SVG, so it's easy enough to modify/delete as you see fit.
2018-10-30 23:43:21 +00:00
|
|
|
def collapse_duplicate_point(geometry):
|
2018-12-19 17:46:31 +00:00
|
|
|
if geometry.area < 0.01:
|
|
|
|
return geometry.representative_point()
|
new extension: Auto-Route Satin Columns (#330)
**video demo:** https://www.youtube.com/watch?v=tbghtqziB1g
This branch adds a new extension, Auto-Route Satin Columns, implementing #214! This is a huge new feature that opens the door wide for exciting stuff like lettering (#142).
To use it, select some satin columns and run the extension. After a few seconds, it will replace your satins with a new set with a logical stitching order. Under-pathing and jump-stitches will be added as necessary, and satins will be broken to facilitate jumps. The resulting satins will retain all of the parameters you had set on the original satins, including underlay, zig-zag spacing, etc.
By default, it will choose the left-most extreme as the starting point and the right-most extreme as the ending point (even if these occur partway through a satin such as the left edge of a letter "o"). You can override this by attaching the new "Auto-route satin stitch starting/ending position" commands.
There's also an option to add trims instead of jump stitches. Any jump stitch over 1mm is trimmed. I might make this configurable in the future but in my tests it seems to do a good job. Trim commands are added to the SVG, so it's easy enough to modify/delete as you see fit.
2018-10-30 23:43:21 +00:00
|
|
|
|
|
|
|
return geometry
|
|
|
|
|
|
|
|
|
2018-03-31 00:37:11 +00:00
|
|
|
class Point:
|
|
|
|
def __init__(self, x, y):
|
|
|
|
self.x = x
|
|
|
|
self.y = y
|
|
|
|
|
|
|
|
def __add__(self, other):
|
|
|
|
return Point(self.x + other.x, self.y + other.y)
|
|
|
|
|
|
|
|
def __sub__(self, other):
|
|
|
|
return Point(self.x - other.x, self.y - other.y)
|
|
|
|
|
|
|
|
def mul(self, scalar):
|
|
|
|
return Point(self.x * scalar, self.y * scalar)
|
|
|
|
|
|
|
|
def __mul__(self, other):
|
|
|
|
if isinstance(other, Point):
|
|
|
|
# dot product
|
|
|
|
return self.x * other.x + self.y * other.y
|
|
|
|
elif isinstance(other, (int, float)):
|
|
|
|
return Point(self.x * other, self.y * other)
|
|
|
|
else:
|
|
|
|
raise ValueError("cannot multiply Point by %s" % type(other))
|
|
|
|
|
2018-07-16 00:15:35 +00:00
|
|
|
def __neg__(self):
|
|
|
|
return self * -1
|
|
|
|
|
2018-03-31 00:37:11 +00:00
|
|
|
def __rmul__(self, other):
|
|
|
|
if isinstance(other, (int, float)):
|
|
|
|
return self.__mul__(other)
|
|
|
|
else:
|
|
|
|
raise ValueError("cannot multiply Point by %s" % type(other))
|
|
|
|
|
2018-05-27 01:26:40 +00:00
|
|
|
def __div__(self, other):
|
|
|
|
if isinstance(other, (int, float)):
|
|
|
|
return self * (1.0 / other)
|
|
|
|
else:
|
2018-08-22 01:43:09 +00:00
|
|
|
raise ValueError("cannot divide Point by %s" % type(other))
|
2018-05-27 01:26:40 +00:00
|
|
|
|
2018-03-31 00:37:11 +00:00
|
|
|
def __repr__(self):
|
|
|
|
return "Point(%s,%s)" % (self.x, self.y)
|
|
|
|
|
|
|
|
def length(self):
|
|
|
|
return math.sqrt(math.pow(self.x, 2.0) + math.pow(self.y, 2.0))
|
|
|
|
|
2018-09-29 20:00:36 +00:00
|
|
|
def distance(self, other):
|
|
|
|
return (other - self).length()
|
|
|
|
|
2018-03-31 00:37:11 +00:00
|
|
|
def unit(self):
|
|
|
|
return self.mul(1.0 / self.length())
|
|
|
|
|
|
|
|
def rotate_left(self):
|
|
|
|
return Point(-self.y, self.x)
|
|
|
|
|
|
|
|
def rotate(self, angle):
|
|
|
|
return Point(self.x * math.cos(angle) - self.y * math.sin(angle), self.y * math.cos(angle) + self.x * math.sin(angle))
|
|
|
|
|
|
|
|
def as_int(self):
|
|
|
|
return Point(int(round(self.x)), int(round(self.y)))
|
|
|
|
|
|
|
|
def as_tuple(self):
|
|
|
|
return (self.x, self.y)
|
|
|
|
|
|
|
|
def __cmp__(self, other):
|
|
|
|
return cmp(self.as_tuple(), other.as_tuple())
|
|
|
|
|
|
|
|
def __getitem__(self, item):
|
|
|
|
return self.as_tuple()[item]
|
2018-02-28 00:43:15 +00:00
|
|
|
|
2018-03-31 00:37:11 +00:00
|
|
|
def __len__(self):
|
|
|
|
return 2
|