Added Origami extensions
This commit is contained in:
parent
2dd642795b
commit
e368b32f07
112
extensions/OrigamiPatterns/Hypar.py
Normal file
112
extensions/OrigamiPatterns/Hypar.py
Normal file
@ -0,0 +1,112 @@
|
|||||||
|
#! /usr/bin/env python3
|
||||||
|
|
||||||
|
import numpy as np
|
||||||
|
from math import pi, tan, sqrt, sin, cos
|
||||||
|
import inkex
|
||||||
|
from Path import Path
|
||||||
|
from Pattern import Pattern
|
||||||
|
|
||||||
|
class Hypar(Pattern):
|
||||||
|
def __init__(self):
|
||||||
|
Pattern.__init__(self) # Must be called in order to parse common options
|
||||||
|
self.add_argument("-p", "--pattern", default="template1", help="Origami pattern")
|
||||||
|
self.add_argument("--radius", type=float, default=10.0, help="Radius of tower (mm)")
|
||||||
|
self.add_argument("--sides", type=int, default=4, help="Number of polygon sides")
|
||||||
|
self.add_argument("--rings", type=int, default=7, help="Number of rings")
|
||||||
|
self.add_argument("--simplify_center", type=inkex.Boolean, default=0, help="Simplify center")
|
||||||
|
|
||||||
|
def generate_path_tree(self):
|
||||||
|
""" Specialized path generation for your origami pattern
|
||||||
|
"""
|
||||||
|
# retrieve saved parameters
|
||||||
|
unit_factor = self.calc_unit_factor()
|
||||||
|
vertex_radius = self.options.vertex_radius * unit_factor
|
||||||
|
pattern = self.options.pattern
|
||||||
|
radius = self.options.radius * unit_factor
|
||||||
|
sides = self.options.sides
|
||||||
|
rings = self.options.rings
|
||||||
|
simplify_center = self.options.simplify_center
|
||||||
|
sin_ = sin(pi / float(sides))
|
||||||
|
a = radius*sin_ # half of length of polygon side
|
||||||
|
H = radius*sqrt(1 - sin_**2)
|
||||||
|
|
||||||
|
polygon = Path.generate_polygon(sides, radius, 'e')
|
||||||
|
|
||||||
|
# # OLD diagonals generation with universal creases
|
||||||
|
# diagonals = []
|
||||||
|
# for i in range(sides):
|
||||||
|
# diagonals.append(Path([(0, 0), polygon.points[i]], 'u'))
|
||||||
|
# points = [(x, y) for x, y in polygon.points]
|
||||||
|
# diagonals = diagonals + [Path.generate_separated_paths(points, 'm')]
|
||||||
|
|
||||||
|
# # modify center if needed
|
||||||
|
# if simplify_center:
|
||||||
|
# for i in range(sides):
|
||||||
|
# if i % 2 == 0:
|
||||||
|
# p2 = diagonals[i].points[1]
|
||||||
|
# diagonals[i].points[0] = (1. / (rings + 1) * p2[0], 1. / (rings + 1) * p2[1])
|
||||||
|
|
||||||
|
# separate generic closed ring to create edges
|
||||||
|
self.edge_points = polygon.points
|
||||||
|
|
||||||
|
# vertex and diagonal lines creation
|
||||||
|
vertex_line = []
|
||||||
|
diagonal_line = []
|
||||||
|
for i in range(1, rings + 2):
|
||||||
|
y1 = a * (float(i - 1) / (rings + 1.))
|
||||||
|
x1 = H * float(i - 1) / (rings + 1.)
|
||||||
|
y2 = a * (float(i) / (rings + 1.))
|
||||||
|
x2 = H * float(i) / (rings + 1.)
|
||||||
|
vertex_line.append((Path((x2, y2), style='p', radius=vertex_radius)))
|
||||||
|
diagonal_line.append((Path([(x1, y1), (x2, y2)], style='m' if i % 2 else 'v')))
|
||||||
|
|
||||||
|
# rotation of vertices and diagonals for completing the drawing
|
||||||
|
diagonals = []
|
||||||
|
vertices = [Path((0, 0), style='p', radius=vertex_radius)]
|
||||||
|
for i in range(sides):
|
||||||
|
vertices = vertices+Path.list_rotate(vertex_line, i * 2 * pi / float(sides))
|
||||||
|
diagonals = diagonals+[Path.list_rotate(diagonal_line, i * 2 * pi / float(sides))]
|
||||||
|
|
||||||
|
# modify center if needed
|
||||||
|
if simplify_center:
|
||||||
|
for i in range(sides):
|
||||||
|
if i % 2 == 0:
|
||||||
|
del diagonals[i][0]
|
||||||
|
|
||||||
|
# inkex.debug(len(diagonals))
|
||||||
|
# inkex.debug(len(diagonals[0]))
|
||||||
|
# diagonals = diagonals + diagonal
|
||||||
|
|
||||||
|
# scale generic closed ring to create inner rings
|
||||||
|
inner_rings = []
|
||||||
|
for i in range(rings + 1):
|
||||||
|
inner_rings.append(polygon * (float(i)/(rings+1)))
|
||||||
|
inner_rings[i].style = 'v' if i % 2 else 'm'
|
||||||
|
|
||||||
|
# create points for zig zag pattern
|
||||||
|
zig_zags = []
|
||||||
|
if pattern != "classic":
|
||||||
|
zig_zag = []
|
||||||
|
for i in range(1, rings + 1):
|
||||||
|
y_out = a * ((i + 1.) / (rings + 1.))
|
||||||
|
y_in = a * (float(i) / (rings + 1.))
|
||||||
|
x_out = H * (i + 1.) / (rings + 1.)
|
||||||
|
x_in = H * float(i) / (rings + 1.)
|
||||||
|
|
||||||
|
if pattern == "alternate_asymmetric" and i % 2:
|
||||||
|
zig_zag.append(Path([(x_in, -y_in), (x_out, +y_out)], style='u'))
|
||||||
|
else:
|
||||||
|
zig_zag.append(Path([(x_in, +y_in), (x_out, -y_out)], style='u'))
|
||||||
|
|
||||||
|
# reflect zig zag pattern to create all sides
|
||||||
|
zig_zags.append(zig_zag)
|
||||||
|
for i in range(sides - 1):
|
||||||
|
points = diagonals[i][0].points
|
||||||
|
zig_zags.append(Path.list_reflect(zig_zags[i], points[0], points[1]))
|
||||||
|
|
||||||
|
self.translate = (radius, radius)
|
||||||
|
self.path_tree = [diagonals, zig_zags, inner_rings, vertices]
|
||||||
|
|
||||||
|
# Main function, creates an instance of the Class and calls inkex.affect() to draw the origami on inkscape
|
||||||
|
if __name__ == '__main__':
|
||||||
|
Hypar().run()
|
154
extensions/OrigamiPatterns/Kresling.py
Normal file
154
extensions/OrigamiPatterns/Kresling.py
Normal file
@ -0,0 +1,154 @@
|
|||||||
|
#! /usr/bin/env python3
|
||||||
|
|
||||||
|
from math import pi, sin, cos, tan, acos, sqrt
|
||||||
|
import inkex
|
||||||
|
from Path import Path
|
||||||
|
from Pattern import Pattern
|
||||||
|
|
||||||
|
class Kresling(Pattern):
|
||||||
|
def __init__(self):
|
||||||
|
Pattern.__init__(self) # Must be called in order to parse common options
|
||||||
|
self.add_argument("-p", "--pattern", default="kresling", help="Origami pattern")
|
||||||
|
self.add_argument("--lines", type=int, default=1, help="Number of lines")
|
||||||
|
self.add_argument("--sides", type=int, default=3, help="Number of polygon sides")
|
||||||
|
self.add_argument("--add_attachment", type=inkex.Boolean, default=False, help="Add attachment?")
|
||||||
|
self.add_argument("--attachment_percentage", type=float, default=100., help="Length percentage of extra facet")
|
||||||
|
self.add_argument("--mirror_cells", type=inkex.Boolean, default=False, help="Mirror odd cells?")
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def generate_kresling_zigzag(sides, radius, angle_ratio, add_attachment):
|
||||||
|
|
||||||
|
theta = (pi / 2.) * (1 - 2. / sides)
|
||||||
|
l = 2. * radius * cos(theta * (1. - angle_ratio))
|
||||||
|
a = 2. * radius * sin(pi / sides)
|
||||||
|
# b = sqrt(a * a + l * l - 2 * a * l * cos(angle_ratio * theta))
|
||||||
|
# phi = abs(acos((l * l + b * b - a * a) / (2 * l * b)))
|
||||||
|
# gamma = pi / 2 - angle_ratio * theta - phi
|
||||||
|
dy = l * sin(theta * angle_ratio)
|
||||||
|
dx = l * cos(theta * angle_ratio) - a
|
||||||
|
|
||||||
|
points = []
|
||||||
|
styles = []
|
||||||
|
|
||||||
|
for i in range(sides):
|
||||||
|
points.append((i * a, 0))
|
||||||
|
points.append(((i + 1) * a + dx, -dy))
|
||||||
|
styles.append('v')
|
||||||
|
if i != sides - 1:
|
||||||
|
styles.append('m')
|
||||||
|
elif add_attachment:
|
||||||
|
points.append((sides * a, 0))
|
||||||
|
styles.append('m')
|
||||||
|
|
||||||
|
path = Path.generate_separated_paths(points, styles)
|
||||||
|
return path
|
||||||
|
|
||||||
|
def generate_path_tree(self):
|
||||||
|
""" Specialized path generation for Waterbomb tesselation pattern
|
||||||
|
"""
|
||||||
|
unit_factor = self.calc_unit_factor()
|
||||||
|
vertex_radius = self.options.vertex_radius * unit_factor
|
||||||
|
lines = self.options.lines
|
||||||
|
sides = self.options.sides
|
||||||
|
radius = self.options.radius * unit_factor
|
||||||
|
angle_ratio = self.options.angle_ratio
|
||||||
|
mirror_cells = self.options.mirror_cells
|
||||||
|
|
||||||
|
theta = (pi/2.)*(1 - 2./sides)
|
||||||
|
l = 2.*radius*cos(theta*(1.-angle_ratio))
|
||||||
|
a = 2.*radius*sin(pi/sides)
|
||||||
|
# b = sqrt(a*a + l*l - 2*a*l*cos(angle_ratio*theta))
|
||||||
|
# phi = abs(acos((l*l + b*b - a*a)/(2*l*b)))
|
||||||
|
# gamma = pi/2 - angle_ratio*theta - phi
|
||||||
|
# dy = b*cos(gamma)
|
||||||
|
# dx = b*sin(gamma)
|
||||||
|
dy = l * sin(theta * angle_ratio)
|
||||||
|
dx = l * cos(theta * angle_ratio) - a
|
||||||
|
|
||||||
|
add_attachment = self.options.add_attachment
|
||||||
|
attachment_percentage = self.options.attachment_percentage/100.
|
||||||
|
attachment_height = a*(attachment_percentage-1)*tan(angle_ratio*theta)
|
||||||
|
|
||||||
|
vertices = []
|
||||||
|
for i in range(sides + 1):
|
||||||
|
for j in range(lines + 1):
|
||||||
|
if mirror_cells:
|
||||||
|
vertices.append(Path((dx*((lines - j)%2) + a*i, dy*j), style='p', radius=vertex_radius))
|
||||||
|
else:
|
||||||
|
vertices.append(Path((dx*(lines - j) + a*i, dy*j), style='p', radius=vertex_radius))
|
||||||
|
|
||||||
|
# create a horizontal grid, then offset each line according to angle
|
||||||
|
grid_h = Path.generate_hgrid([0, a * sides], [0, dy * lines], lines, 'm')
|
||||||
|
|
||||||
|
|
||||||
|
if not mirror_cells:
|
||||||
|
# shift every mountain line of the grid to the right by increasing amounts
|
||||||
|
grid_h = Path.list_add(grid_h, [(i * dx, 0) for i in range(lines - 1, 0, -1)])
|
||||||
|
else:
|
||||||
|
# shift every OTHER mountain line of the grid a bit to the right
|
||||||
|
grid_h = Path.list_add(grid_h, [((i%2)*dx, 0) for i in range(lines-1, 0, -1)])
|
||||||
|
if add_attachment:
|
||||||
|
for i in range(lines%2, lines-1, 2):
|
||||||
|
# hacky solution, changes length of every other mountain line
|
||||||
|
grid_h[i].points[1-i%2] = (grid_h[i].points[1-i%2][0] + a*attachment_percentage, grid_h[i].points[1-i%2][1])
|
||||||
|
|
||||||
|
|
||||||
|
# create MV zigzag for Kresling pattern
|
||||||
|
zigzag = Kresling.generate_kresling_zigzag(sides, radius, angle_ratio, add_attachment)
|
||||||
|
zigzags = []
|
||||||
|
|
||||||
|
# duplicate zigzag pattern for desired number of cells
|
||||||
|
if not mirror_cells:
|
||||||
|
for i in range(lines):
|
||||||
|
zigzags.append(Path.list_add(zigzag, (i * dx, (lines - i) * dy)))
|
||||||
|
else:
|
||||||
|
zigzag_mirror = Path.list_reflect(zigzag, (0, lines * dy / 2), (dx, lines * dy / 2))
|
||||||
|
for i in range(lines):
|
||||||
|
if i % 2 == 1:
|
||||||
|
zigzags.append(Path.list_add(zigzag_mirror, (0, -(lines - i + (lines-1)%2) * dy)))
|
||||||
|
else:
|
||||||
|
zigzags.append(Path.list_add(zigzag, (0, (lines - i) * dy)))
|
||||||
|
|
||||||
|
# create edge strokes
|
||||||
|
if not mirror_cells:
|
||||||
|
self.edge_points = [
|
||||||
|
(a * sides , dy * lines), # bottom right
|
||||||
|
(0 , dy * lines), # bottom left
|
||||||
|
(dx * lines , 0), # top left
|
||||||
|
(dx * lines + a * sides, 0)] # top right
|
||||||
|
|
||||||
|
if add_attachment:
|
||||||
|
for i in range(lines):
|
||||||
|
x = dx * (lines - i) + a * (sides + attachment_percentage)
|
||||||
|
self.edge_points.append((x, dy * i))
|
||||||
|
self.edge_points.append((x, dy * i - attachment_height))
|
||||||
|
if i != lines - 1:
|
||||||
|
self.edge_points.append((x-dx-a*attachment_percentage, dy * (i + 1)))
|
||||||
|
pass
|
||||||
|
|
||||||
|
else:
|
||||||
|
self.edge_points = [(a * sides + (lines % 2)*dx, 0)]
|
||||||
|
|
||||||
|
for i in range(lines+1):
|
||||||
|
self.edge_points.append([((lines+i) % 2)*dx, dy*i])
|
||||||
|
|
||||||
|
self.edge_points.append([a * sides + ((lines+i) %2)*dx, lines*dy])
|
||||||
|
|
||||||
|
if add_attachment:
|
||||||
|
for i in range(lines + 1):
|
||||||
|
|
||||||
|
if not i%2 == 0:
|
||||||
|
self.edge_points.append([a*sides + (i%2)*(dx+a*attachment_percentage), dy*(lines - i) - (i%2)*attachment_height])
|
||||||
|
self.edge_points.append([a*sides + (i%2)*(dx+a*attachment_percentage), dy*(lines - i)])
|
||||||
|
if (i != lines):
|
||||||
|
self.edge_points.append([a * sides + (i % 2) * (dx + a * attachment_percentage), dy * (lines - i) + (i % 2) * attachment_height])
|
||||||
|
else:
|
||||||
|
self.edge_points.append([a * sides + (i % 2) * (dx + a * attachment_percentage), dy * (lines - i)])
|
||||||
|
else:
|
||||||
|
for i in range(lines + 1):
|
||||||
|
self.edge_points.append([a*sides + (i%2)*dx, dy*(lines - i)])
|
||||||
|
|
||||||
|
self.path_tree = [grid_h, zigzags, vertices]
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
Kresling().run()
|
89
extensions/OrigamiPatterns/Kresling_full.py
Normal file
89
extensions/OrigamiPatterns/Kresling_full.py
Normal file
@ -0,0 +1,89 @@
|
|||||||
|
#! /usr/bin/env python3
|
||||||
|
|
||||||
|
from math import sin, cos, sqrt, asin, pi, ceil
|
||||||
|
import inkex
|
||||||
|
from Path import Path
|
||||||
|
from Pattern import Pattern
|
||||||
|
from Kresling import Kresling
|
||||||
|
|
||||||
|
|
||||||
|
class Kresling_Full(Kresling):
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
""" Constructor
|
||||||
|
"""
|
||||||
|
Kresling.__init__(self) # Must be called in order to parse common options
|
||||||
|
|
||||||
|
self.add_argument('--measure_value', type=float, default=10.0, help="Length")
|
||||||
|
self.add_argument('--measure_type', default=60, help="Type of length")
|
||||||
|
self.add_argument('--parameter_type', default=60, help="Type of parameter")
|
||||||
|
self.add_argument('--radial_ratio', type=float, default=0.5, help="Radial ratio")
|
||||||
|
self.add_argument('--angle_ratio', type=float, default=0.5, help="Anle ratio")
|
||||||
|
self.add_argument('--lambdatheta', type=float, default=45, help="lambdatheta")
|
||||||
|
|
||||||
|
def generate_path_tree(self):
|
||||||
|
""" Convert radial to angular ratio, then call regular Kresling constructor
|
||||||
|
"""
|
||||||
|
n = self.options.sides
|
||||||
|
theta = pi*(n-2)/(2*n)
|
||||||
|
# define ratio parameter
|
||||||
|
parameter = self.options.parameter_type
|
||||||
|
if parameter == 'radial_ratio':
|
||||||
|
radial_ratio = self.options.radial_ratio
|
||||||
|
max_radial_ratio = sin((pi/4)*(1. - 2./n))
|
||||||
|
if radial_ratio > max_radial_ratio:
|
||||||
|
inkex.errormsg(_("For polygon of {} sides, the maximal radial ratio is = {}".format(n, max_radial_ratio)))
|
||||||
|
radial_ratio = max_radial_ratio
|
||||||
|
self.options.angle_ratio = 1 - 2*n*asin(radial_ratio)/((n-2)*pi)
|
||||||
|
|
||||||
|
elif parameter == 'lambdatheta':
|
||||||
|
lambdatheta = self.options.lambdatheta
|
||||||
|
angle_min = 45. * (1 - 2. / n)
|
||||||
|
angle_max = 2 * angle_min
|
||||||
|
if lambdatheta < angle_min:
|
||||||
|
inkex.errormsg(_(
|
||||||
|
"For polygon of {} sides, phi must be between {} and {} degrees, \nsetting lambda*theta = {}\n".format(
|
||||||
|
n, angle_min, angle_max, angle_min)))
|
||||||
|
lambdatheta = angle_min
|
||||||
|
elif lambdatheta > angle_max:
|
||||||
|
inkex.errormsg(_(
|
||||||
|
"For polygon of {} sides, phi must be between {} and {} degrees, \nsetting lambda*theta = {}\n".format(
|
||||||
|
n, angle_min, angle_max, angle_max)))
|
||||||
|
lambdatheta = angle_max
|
||||||
|
self.options.angle_ratio = lambdatheta * n / (90. * (n - 2.))
|
||||||
|
|
||||||
|
|
||||||
|
# define some length
|
||||||
|
mtype = self.options.measure_type
|
||||||
|
mvalue = self.options.measure_value
|
||||||
|
angle_ratio = self.options.angle_ratio
|
||||||
|
if mtype == 'a':
|
||||||
|
radius = 0.5*mvalue / (sin(pi/n))
|
||||||
|
if mtype == 'b':
|
||||||
|
A = cos(theta*(1-angle_ratio))
|
||||||
|
B = sin(pi/n)
|
||||||
|
C = cos(theta*angle_ratio)
|
||||||
|
radius = 0.5*mvalue / sqrt(A**2 + B**2 - 2*A*B*C)
|
||||||
|
elif mtype == 'l':
|
||||||
|
radius = 0.5*mvalue/cos(theta*(1-angle_ratio))
|
||||||
|
elif mtype == 'radius_external':
|
||||||
|
radius = mvalue
|
||||||
|
elif mtype == 'radius_internal':
|
||||||
|
radius = mvalue/(sin(theta*(1-angle_ratio)))
|
||||||
|
elif mtype == 'diameter_external':
|
||||||
|
radius = 0.5*mvalue
|
||||||
|
elif mtype == 'diameter_internal':
|
||||||
|
radius = 0.5*mvalue/sin(theta*(1-angle_ratio))
|
||||||
|
|
||||||
|
# inkex.errormsg(_("Value = {}, Mode = {}, Radius = {}".format(mvalue, mtype, radius)))
|
||||||
|
|
||||||
|
if self.options.pattern == 'mirrowed':
|
||||||
|
self.options.mirror_cells = True
|
||||||
|
else:
|
||||||
|
self.options.mirror_cells = False
|
||||||
|
self.options.radius = radius
|
||||||
|
|
||||||
|
Kresling.generate_path_tree(self)
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
Kresling_Full().run()
|
466
extensions/OrigamiPatterns/Path.py
Normal file
466
extensions/OrigamiPatterns/Path.py
Normal file
@ -0,0 +1,466 @@
|
|||||||
|
#! /usr/bin/env python3
|
||||||
|
|
||||||
|
import inkex
|
||||||
|
from lxml import etree
|
||||||
|
from math import sin, cos, pi
|
||||||
|
|
||||||
|
class Path:
|
||||||
|
""" Class that defines an svg stroke to be drawn in Inkscape
|
||||||
|
|
||||||
|
Attributes
|
||||||
|
---------
|
||||||
|
points: tuple or list of tuples
|
||||||
|
Points defining stroke lines.
|
||||||
|
style: str
|
||||||
|
Single character defining style of stroke. Default values are:
|
||||||
|
'm' for mountain creases
|
||||||
|
'v' for valley creases
|
||||||
|
'e' for edge borders
|
||||||
|
Extra possible values:
|
||||||
|
'u' for universal creases
|
||||||
|
's' for semicreases
|
||||||
|
'c' for kirigami cuts
|
||||||
|
closed: bool
|
||||||
|
Tells if desired path should contain a last stroke from the last point to the first point, closing the path
|
||||||
|
radius: float
|
||||||
|
If only one point is given, it's assumed to be a circle and radius sets the radius
|
||||||
|
|
||||||
|
|
||||||
|
Methods
|
||||||
|
---------
|
||||||
|
invert(self)
|
||||||
|
Inverts path
|
||||||
|
|
||||||
|
Overloaded Operators
|
||||||
|
---------
|
||||||
|
__add__(self, offsets)
|
||||||
|
Adding a tuple to a Path returns a new path with all points having an offset defined by the tuple
|
||||||
|
|
||||||
|
__mul__(self, transform)
|
||||||
|
Define multiplication of a Path to a vector in complex exponential representation
|
||||||
|
|
||||||
|
|
||||||
|
Static Methods
|
||||||
|
---------
|
||||||
|
draw_paths_recursively(path_tree, group, styles_dict)
|
||||||
|
Draws strokes defined on "path_tree" to "group". Styles dict maps style of path_tree element to the definition
|
||||||
|
of the style. Ex.:
|
||||||
|
if path_tree[i].style = 'm', styles_dict must have an element 'm'.
|
||||||
|
|
||||||
|
generate_hgrid(cls, xlims, ylims, nb_of_divisions, style, include_edge=False)
|
||||||
|
Generate list of Path instances, in which each Path is a stroke defining a horizontal grid dividing the space
|
||||||
|
xlims * ylims nb_of_divisions times.
|
||||||
|
|
||||||
|
generate_vgrid(cls, xlims, ylims, nb_of_divisions, style, include_edge=False)
|
||||||
|
Generate list of Path instances, in which each Path is a stroke defining a vertical grid dividing the space
|
||||||
|
xlims * ylims nb_of_divisions times.
|
||||||
|
|
||||||
|
generate_separated_paths(cls, points, styles, closed=False)
|
||||||
|
Generate list of Path instances, in which each Path is the stroke between each two point tuples, in case each
|
||||||
|
stroke must be handled separately
|
||||||
|
|
||||||
|
reflect(cls, path, p1, p2)
|
||||||
|
Reflects each point of path on line defined by two points and return new Path instance with new reflected points
|
||||||
|
|
||||||
|
list_reflect(cls, paths, p1, p2)
|
||||||
|
Generate list of new Path instances, rotation each path by transform
|
||||||
|
|
||||||
|
list_rotate(cls, paths, theta, translation=(0, 0))
|
||||||
|
Generate list of new Path instances, rotation each path by transform
|
||||||
|
|
||||||
|
list_add(cls, paths, offsets)
|
||||||
|
Generate list of new Path instances, adding a different tuple for each list
|
||||||
|
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self, points, style, closed=False, invert=False, radius=0.1, separated=False):
|
||||||
|
""" Constructor
|
||||||
|
|
||||||
|
Parameters
|
||||||
|
---------
|
||||||
|
points: list of 2D tuples
|
||||||
|
stroke will connect all points
|
||||||
|
style: str
|
||||||
|
Single character defining style of stroke. For use with the OrigamiPatterns class (probably the only
|
||||||
|
project that will ever use this file) the default values are:
|
||||||
|
'm' for mountain creases
|
||||||
|
'v' for valley creases
|
||||||
|
'e' for edge borders
|
||||||
|
closed: bool
|
||||||
|
if true, last point will be connected to first point at the end
|
||||||
|
invert: bool
|
||||||
|
if true, stroke will start at the last point and go all the way to the first one
|
||||||
|
"""
|
||||||
|
if type(points) == list and len(points) != 1:
|
||||||
|
self.type = 'linear'
|
||||||
|
if invert:
|
||||||
|
self.points = points[::-1]
|
||||||
|
else:
|
||||||
|
self.points = points
|
||||||
|
|
||||||
|
elif (type(points) == list and len(points) == 1):
|
||||||
|
self.type = 'circular'
|
||||||
|
self.points = points
|
||||||
|
self.radius = radius
|
||||||
|
|
||||||
|
elif (type(points) == tuple and len(points) == 2):
|
||||||
|
self.type = 'circular'
|
||||||
|
self.points = [points]
|
||||||
|
self.radius = radius
|
||||||
|
|
||||||
|
else:
|
||||||
|
raise TypeError("Points must be tuple of length 2 (for a circle) or a list of tuples of length 2 each")
|
||||||
|
|
||||||
|
self.style = style
|
||||||
|
self.closed = closed
|
||||||
|
|
||||||
|
def invert(self):
|
||||||
|
""" Inverts path
|
||||||
|
"""
|
||||||
|
self.points = self.points[::-1]
|
||||||
|
|
||||||
|
"""
|
||||||
|
Draw path recursively
|
||||||
|
- Static method
|
||||||
|
- Draws strokes defined on "path_tree" to "group"
|
||||||
|
- Inputs:
|
||||||
|
-- path_tree [nested list] of Path instances
|
||||||
|
-- group [etree.SubElement]
|
||||||
|
-- styles_dict [dict] containing all styles for path_tree
|
||||||
|
"""
|
||||||
|
@staticmethod
|
||||||
|
def draw_paths_recursively(path_tree, group, styles_dict):
|
||||||
|
""" Static method, draw list of Path instances recursively
|
||||||
|
"""
|
||||||
|
for subpath in path_tree:
|
||||||
|
if type(subpath) == list:
|
||||||
|
if len(subpath) == 1:
|
||||||
|
subgroup = group
|
||||||
|
else:
|
||||||
|
subgroup = etree.SubElement(group, 'g')
|
||||||
|
Path.draw_paths_recursively(subpath, subgroup, styles_dict)
|
||||||
|
else:
|
||||||
|
if styles_dict[subpath.style]['draw']:
|
||||||
|
if subpath.type == 'linear':
|
||||||
|
|
||||||
|
points = subpath.points
|
||||||
|
path = 'M{},{} '.format(*points[0])
|
||||||
|
for i in range(1, len(points)):
|
||||||
|
path = path + 'L{},{} '.format(*points[i])
|
||||||
|
if subpath.closed:
|
||||||
|
path = path + 'L{},{} Z'.format(*points[0])
|
||||||
|
|
||||||
|
attribs = {'style': str(inkex.Style(styles_dict[subpath.style])), 'd': path}
|
||||||
|
etree.SubElement(group, inkex.addNS('path', 'svg'), attribs)
|
||||||
|
else:
|
||||||
|
attribs = {'style': str(inkex.Style(styles_dict[subpath.style])),
|
||||||
|
'cx': str(subpath.points[0][0]), 'cy': str(subpath.points[0][1]),
|
||||||
|
'r': str(subpath.radius)}
|
||||||
|
etree.SubElement(group, inkex.addNS('circle', 'svg'), attribs)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def generate_hgrid(cls, xlims, ylims, nb_of_divisions, style, include_edge=False):
|
||||||
|
""" Generate list of Path instances, in which each Path is a stroke defining
|
||||||
|
a horizontal grid dividing the space xlims * ylims nb_of_divisions times.
|
||||||
|
|
||||||
|
All lines are alternated, to minimize Laser Cutter unnecessary movements
|
||||||
|
|
||||||
|
Parameters
|
||||||
|
---------
|
||||||
|
xlims: tuple
|
||||||
|
Defines x_min and x_max for space that must be divided.
|
||||||
|
ylims: tuple
|
||||||
|
Defines y_min and y_max for space that must be divided.
|
||||||
|
nb_of_divisions: int
|
||||||
|
Defines how many times it should be divided.
|
||||||
|
style: str
|
||||||
|
Single character defining style of stroke.
|
||||||
|
include_edge: bool
|
||||||
|
Defines if edge should be drawn or not.
|
||||||
|
|
||||||
|
Returns
|
||||||
|
---------
|
||||||
|
paths: list of Path instances
|
||||||
|
"""
|
||||||
|
rect_len = (ylims[1] - ylims[0])/nb_of_divisions
|
||||||
|
hgrid = []
|
||||||
|
for i in range(1 - include_edge, nb_of_divisions + include_edge):
|
||||||
|
hgrid.append(cls([(xlims[0], ylims[0]+i*rect_len),
|
||||||
|
(xlims[1], ylims[0]+i*rect_len)],
|
||||||
|
style=style, invert=i % 2 == 0))
|
||||||
|
return hgrid
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def generate_vgrid(cls, xlims, ylims, nb_of_divisions, style, include_edge=False):
|
||||||
|
""" Generate list of Path instances, in which each Path is a stroke defining
|
||||||
|
a vertical grid dividing the space xlims * ylims nb_of_divisions times.
|
||||||
|
|
||||||
|
All lines are alternated, to minimize Laser Cutter unnecessary movements
|
||||||
|
|
||||||
|
Parameters
|
||||||
|
---------
|
||||||
|
-> refer to generate_hgrid
|
||||||
|
|
||||||
|
Returns
|
||||||
|
---------
|
||||||
|
paths: list of Path instances
|
||||||
|
"""
|
||||||
|
rect_len = (xlims[1] - xlims[0])/nb_of_divisions
|
||||||
|
vgrid = []
|
||||||
|
for i in range(1 - include_edge, nb_of_divisions + include_edge):
|
||||||
|
vgrid.append(cls([(xlims[0]+i*rect_len, ylims[0]),
|
||||||
|
(xlims[0]+i*rect_len, ylims[1])],
|
||||||
|
style=style, invert=i % 2 == 0))
|
||||||
|
return vgrid
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def generate_polygon(cls, sides, radius, style, center=(0, 0)):
|
||||||
|
points = []
|
||||||
|
for i in range(sides):
|
||||||
|
points.append((radius * cos((1 + i * 2) * pi / sides),
|
||||||
|
radius * sin((1 + i * 2) * pi / sides)))
|
||||||
|
return Path(points, style, closed=True)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def generate_separated_paths(cls, points, styles, closed=False):
|
||||||
|
""" Generate list of Path instances, in which each Path is the stroke
|
||||||
|
between each two point tuples, in case each stroke must be handled separately.
|
||||||
|
|
||||||
|
Returns
|
||||||
|
---------
|
||||||
|
paths: list
|
||||||
|
list of Path instances
|
||||||
|
"""
|
||||||
|
paths = []
|
||||||
|
if type(styles) == str:
|
||||||
|
styles = [styles] * (len(points) - 1 + int(closed))
|
||||||
|
elif len(styles) != len(points) - 1 + int(closed):
|
||||||
|
raise TypeError("Number of paths and styles don't match")
|
||||||
|
for i in range(len(points) - 1 + int(closed)):
|
||||||
|
j = (i+1)%len(points)
|
||||||
|
paths.append(cls([points[i], points[j]],
|
||||||
|
styles[i]))
|
||||||
|
return paths
|
||||||
|
|
||||||
|
def __add__(self, offsets):
|
||||||
|
""" " + " operator overload.
|
||||||
|
Adding a tuple to a Path returns a new path with all points having an offset
|
||||||
|
defined by the tuple
|
||||||
|
"""
|
||||||
|
if type(offsets) == list:
|
||||||
|
if len(offsets) != 1 or len(offsets) != len(self.points):
|
||||||
|
raise TypeError("Paths can only be added by a tuple of a list of N tuples, "
|
||||||
|
"where N is the same number of points")
|
||||||
|
|
||||||
|
elif type(offsets) != tuple:
|
||||||
|
raise TypeError("Paths can only be added by tuples")
|
||||||
|
else:
|
||||||
|
offsets = [offsets] * len(self.points)
|
||||||
|
|
||||||
|
# if type(self.points) == list:
|
||||||
|
points_new = []
|
||||||
|
for point, offset in zip(self.points, offsets):
|
||||||
|
points_new.append((point[0]+offset[0],
|
||||||
|
point[1]+offset[1]))
|
||||||
|
|
||||||
|
if self.type == 'circular':
|
||||||
|
radius = self.radius
|
||||||
|
else:
|
||||||
|
radius = 0.2
|
||||||
|
|
||||||
|
# if self.type == 'circular' else 0.1
|
||||||
|
|
||||||
|
return Path(points_new, self.style, self.closed, radius=radius)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def list_add(cls, paths, offsets):
|
||||||
|
""" Generate list of new Path instances, adding a different tuple for each list
|
||||||
|
|
||||||
|
Parameters
|
||||||
|
---------
|
||||||
|
paths: Path or list
|
||||||
|
list of N Path instances
|
||||||
|
offsets: tuple or list
|
||||||
|
list of N tuples
|
||||||
|
|
||||||
|
Returns
|
||||||
|
---------
|
||||||
|
paths_new: list
|
||||||
|
list of N Path instances
|
||||||
|
"""
|
||||||
|
if type(paths) == Path and type(offsets) == tuple:
|
||||||
|
paths = [paths]
|
||||||
|
offsets = [offsets]
|
||||||
|
elif type(paths) == list and type(offsets) == tuple:
|
||||||
|
offsets = [offsets] * len(paths)
|
||||||
|
elif type(paths) == Path and type(offsets) == list:
|
||||||
|
paths = [paths] * len(offsets)
|
||||||
|
elif type(paths) == list and type(offsets) == list:
|
||||||
|
if len(paths) == 1:
|
||||||
|
paths = [paths[0]] * len(offsets)
|
||||||
|
elif len(offsets) == 1:
|
||||||
|
offsets = [offsets[0]] * len(paths)
|
||||||
|
elif len(offsets) != len(paths):
|
||||||
|
raise TypeError("List of paths and list of tuples must have same length. {} paths and {} offsets "
|
||||||
|
" where given".format(len(paths), len(offsets)))
|
||||||
|
else:
|
||||||
|
pass
|
||||||
|
|
||||||
|
paths_new = []
|
||||||
|
for path, offset in zip(paths, offsets):
|
||||||
|
paths_new.append(path+offset)
|
||||||
|
|
||||||
|
return paths_new
|
||||||
|
|
||||||
|
def __mul__(self, transform):
|
||||||
|
""" " * " operator overload.
|
||||||
|
Define multiplication of a Path to a vector in complex exponential representation
|
||||||
|
|
||||||
|
Parameters
|
||||||
|
---------
|
||||||
|
transform: float of tuple of length 2 or 4
|
||||||
|
if float, transform represents magnitude
|
||||||
|
Example: path * 3
|
||||||
|
if tuple length 2, transform[0] represents magnitude and transform[1] represents angle of rotation
|
||||||
|
Example: path * (3, pi)
|
||||||
|
if tuple length 4, transform[2],transform[3] define a different axis of rotation
|
||||||
|
Example: path * (3, pi, 1, 1)
|
||||||
|
"""
|
||||||
|
points_new = []
|
||||||
|
|
||||||
|
# "temporary" (probably permanent) compatibility hack
|
||||||
|
try:
|
||||||
|
long_ = long
|
||||||
|
except:
|
||||||
|
long_ = int
|
||||||
|
|
||||||
|
if isinstance(transform, (int, long_, float)):
|
||||||
|
for p in self.points:
|
||||||
|
points_new.append((transform * p[0],
|
||||||
|
transform * p[1]))
|
||||||
|
|
||||||
|
elif isinstance(transform, (list, tuple)):
|
||||||
|
if len(transform) == 2:
|
||||||
|
u = transform[0]*cos(transform[1])
|
||||||
|
v = transform[0]*sin(transform[1])
|
||||||
|
x_, y_ = 0, 0
|
||||||
|
elif len(transform) == 4:
|
||||||
|
u = transform[0]*cos(transform[1])
|
||||||
|
v = transform[0]*sin(transform[1])
|
||||||
|
x_, y_ = transform[2:]
|
||||||
|
else:
|
||||||
|
raise IndexError('Paths can only be multiplied by a number or a tuple/list of length 2 or 4')
|
||||||
|
|
||||||
|
for p in self.points:
|
||||||
|
x, y = p[0]-x_, p[1]-y_
|
||||||
|
points_new.append((x_ + x * u - y * v,
|
||||||
|
y_ + x * v + y * u))
|
||||||
|
else:
|
||||||
|
raise TypeError('Paths can only be multiplied by a number or a tuple/list of length 2 or 4')
|
||||||
|
|
||||||
|
if self.type == 'circular':
|
||||||
|
radius = self.radius
|
||||||
|
else:
|
||||||
|
radius = 0.2
|
||||||
|
|
||||||
|
return Path(points_new, self.style, self.closed, radius=radius)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def list_rotate(cls, paths, theta, translation=(0, 0)):
|
||||||
|
""" Generate list of new Path instances, rotation each path by transform
|
||||||
|
|
||||||
|
Parameters
|
||||||
|
---------
|
||||||
|
paths: Path or list
|
||||||
|
list of N Path instances
|
||||||
|
theta: float (radians)
|
||||||
|
angle of rotation
|
||||||
|
translation: tuple or list 2
|
||||||
|
axis of rotation
|
||||||
|
|
||||||
|
Returns
|
||||||
|
---------
|
||||||
|
paths_new: list
|
||||||
|
list of N Path instances
|
||||||
|
"""
|
||||||
|
if len(translation) != 2:
|
||||||
|
TypeError("Translation must have length 2")
|
||||||
|
|
||||||
|
if type(paths) != list:
|
||||||
|
paths = [paths]
|
||||||
|
|
||||||
|
paths_new = []
|
||||||
|
for path in paths:
|
||||||
|
paths_new.append(path*(1, theta, translation[0], translation[1]))
|
||||||
|
|
||||||
|
if len(paths_new) == 1:
|
||||||
|
paths_new = paths_new[0]
|
||||||
|
return paths_new
|
||||||
|
|
||||||
|
# TODO:
|
||||||
|
# Apparently it's not working properly, must be debugged and tested
|
||||||
|
@classmethod
|
||||||
|
def reflect(cls, path, p1, p2):
|
||||||
|
""" Reflects each point of path on line defined by two points and return new Path instance with new reflected points
|
||||||
|
|
||||||
|
Parameters
|
||||||
|
---------
|
||||||
|
path: Path
|
||||||
|
p1: tuple or list of size 2
|
||||||
|
p2: tuple or list of size 2
|
||||||
|
|
||||||
|
Returns
|
||||||
|
---------
|
||||||
|
path_reflected: Path
|
||||||
|
"""
|
||||||
|
|
||||||
|
(x1, y1) = p1
|
||||||
|
(x2, y2) = p2
|
||||||
|
|
||||||
|
if x1 == x2 and y1 == y2:
|
||||||
|
ValueError("Duplicate points don't define a line")
|
||||||
|
elif x1 == x2:
|
||||||
|
t_x = [-1, 0, 2*x1, 1]
|
||||||
|
t_y = [0, 1, 0, 1]
|
||||||
|
else:
|
||||||
|
m = (y2 - y1)/(x2 - x1)
|
||||||
|
t = y1 - m*x1
|
||||||
|
t_x = [1 - m**2, 2*m, -2*m*t, m**2 + 1]
|
||||||
|
t_y = [2*m, m**2 - 1, +2*t, m**2 + 1]
|
||||||
|
|
||||||
|
points_new = []
|
||||||
|
for p in path.points:
|
||||||
|
x_ = (t_x[0]*p[0] + t_x[1]*p[1] + t_x[2]) / t_x[3]
|
||||||
|
y_ = (t_y[0]*p[0] + t_y[1]*p[1] + t_y[2]) / t_y[3]
|
||||||
|
points_new.append((x_, y_))
|
||||||
|
|
||||||
|
return Path(points_new, path.style, path.closed)
|
||||||
|
|
||||||
|
# TODO:
|
||||||
|
# Apparently it's not working properly, must be debugged and tested
|
||||||
|
@classmethod
|
||||||
|
def list_reflect(cls, paths, p1, p2):
|
||||||
|
""" Generate list of new Path instances, rotation each path by transform
|
||||||
|
|
||||||
|
Parameters
|
||||||
|
---------
|
||||||
|
paths: Path or list
|
||||||
|
list of N Path instances
|
||||||
|
p1: tuple or list of size 2
|
||||||
|
p2: tuple or list of size 2
|
||||||
|
|
||||||
|
Returns
|
||||||
|
---------
|
||||||
|
paths_new: list
|
||||||
|
list of N Path instances
|
||||||
|
"""
|
||||||
|
|
||||||
|
if type(paths) == Path:
|
||||||
|
paths = [paths]
|
||||||
|
|
||||||
|
paths_new = []
|
||||||
|
for path in paths:
|
||||||
|
paths_new.append(Path.reflect(path, p1, p2))
|
||||||
|
|
||||||
|
return paths_new
|
249
extensions/OrigamiPatterns/Pattern.py
Normal file
249
extensions/OrigamiPatterns/Pattern.py
Normal file
@ -0,0 +1,249 @@
|
|||||||
|
#! /usr/bin/env python3
|
||||||
|
|
||||||
|
import os
|
||||||
|
from abc import abstractmethod
|
||||||
|
from lxml import etree
|
||||||
|
from Path import Path, inkex
|
||||||
|
|
||||||
|
class Pattern(inkex.Effect):
|
||||||
|
@abstractmethod
|
||||||
|
def generate_path_tree(self):
|
||||||
|
""" Generate nested list of Path instances
|
||||||
|
Abstract method, must be defined in all child classes
|
||||||
|
"""
|
||||||
|
pass
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
inkex.Effect.__init__(self) # initialize the super class
|
||||||
|
self.add_argument = self.arg_parser.add_argument
|
||||||
|
self.add_argument("-u", "--units", default='mm', help="Units this dialog is using")
|
||||||
|
|
||||||
|
# self.add_argument("-a", "--add_attachment", type=inkex.Boolean, default=False, help="command line help")
|
||||||
|
# self.add_argument("", "--accuracy", type=int, default=0, help="command line help")
|
||||||
|
|
||||||
|
# --------------------------------------------------------------------------------------------------------------
|
||||||
|
# mountain options
|
||||||
|
self.add_argument('-m', '--mountain_stroke_color', default=4278190335, help='The mountain creases color.')
|
||||||
|
self.add_argument('--mountain_stroke_width', type=float, default=0.1, help='Width of mountain strokes.')
|
||||||
|
self.add_argument('--mountain_dashes_len', type=float, default=1.0, help='Mountain dash + gap length.')
|
||||||
|
self.add_argument('--mountain_dashes_duty', type=float, default=0.5, help='Mountain dash duty cycle.')
|
||||||
|
self.add_argument('--mountain_dashes_bool', type=inkex.Boolean, default=True, help='Dashed strokes?')
|
||||||
|
self.add_argument('--mountain_bool', type=inkex.Boolean, default=True, help='Draw mountains?')
|
||||||
|
|
||||||
|
# --------------------------------------------------------------------------------------------------------------
|
||||||
|
# valley options
|
||||||
|
self.add_argument('-v', '--valley_stroke_color', default=65535, help='The valley creases color.')
|
||||||
|
self.add_argument('--valley_stroke_width', type=float, default=0.1, help='Width of valley strokes.')
|
||||||
|
self.add_argument('--valley_dashes_len', type=float, default=1.0, help='Valley dash + gap length.')
|
||||||
|
self.add_argument('--valley_dashes_duty', type=float, default=0.25, help='Valley dash duty cycle.')
|
||||||
|
self.add_argument('--valley_dashes_bool', type=inkex.Boolean, default=True, help='Dashed strokes?')
|
||||||
|
self.add_argument('--valley_bool', type=inkex.Boolean, default=True, help='Draw valleys?')
|
||||||
|
|
||||||
|
# --------------------------------------------------------------------------------------------------------------
|
||||||
|
# edge options
|
||||||
|
self.add_argument('-e', '--edge_stroke_color', default=255, help='The mountain creases color.')
|
||||||
|
self.add_argument('--edge_stroke_width', type=float, default=0.1, help='Width of edge strokes.')
|
||||||
|
self.add_argument('--edge_dashes_len', type=float, default=1.0, help='Edge dash + gap length.')
|
||||||
|
self.add_argument('--edge_dashes_duty', type=float, default=0.25, help='Edge dash duty cycle.')
|
||||||
|
self.add_argument('--edge_dashes_bool', type=inkex.Boolean, default=False, help='Dashed strokes?')
|
||||||
|
self.add_argument('--edge_bool', type=inkex.Boolean, default=True, help='Draw edges?')
|
||||||
|
self.add_argument('--edge_single_path', type=inkex.Boolean, default=True, help='Edges as single path?')
|
||||||
|
|
||||||
|
# --------------------------------------------------------------------------------------------------------------
|
||||||
|
# universal crease options
|
||||||
|
self.add_argument('--universal_stroke_color', default=4278255615, help='The universal creases color.')
|
||||||
|
self.add_argument('--universal_stroke_width', type=float, default=0.1, help='Width of universal strokes.')
|
||||||
|
self.add_argument('--universal_dashes_len', type=float, default=1.0, help='Universal dash + gap length.')
|
||||||
|
self.add_argument('--universal_dashes_duty', type=float, default=0.25, help='Universal dash duty cycle.')
|
||||||
|
self.add_argument('--universal_dashes_bool', type=inkex.Boolean, default=False, help='Dashed strokes?')
|
||||||
|
self.add_argument('--universal_bool', type=inkex.Boolean, default=True, help='Draw universal creases?')
|
||||||
|
|
||||||
|
# --------------------------------------------------------------------------------------------------------------
|
||||||
|
# semicrease options
|
||||||
|
self.add_argument('--semicrease_stroke_color', default=4294902015, help='The semicrease creases color.')
|
||||||
|
self.add_argument('--semicrease_stroke_width', type=float, default=0.1, help='Width of semicrease strokes.')
|
||||||
|
self.add_argument('--semicrease_dashes_len', type=float, default=1.0, help='Semicrease dash + gap length.')
|
||||||
|
self.add_argument('--semicrease_dashes_duty', type=float,default=0.25, help='Semicrease dash duty cycle.')
|
||||||
|
self.add_argument('--semicrease_dashes_bool', type=inkex.Boolean, default=False, help='Dashed strokes?')
|
||||||
|
self.add_argument('--semicrease_bool', type=inkex.Boolean, default=True, help='Draw semicreases?')
|
||||||
|
|
||||||
|
# --------------------------------------------------------------------------------------------------------------
|
||||||
|
# cut options
|
||||||
|
self.add_argument('--cut_stroke_color', default=16711935, help='The cut creases color.')
|
||||||
|
self.add_argument('--cut_stroke_width', type=float, default=0.1, help='Width of cut strokes.')
|
||||||
|
self.add_argument('--cut_dashes_len', type=float, default=1.0, help='Cut dash + gap length.')
|
||||||
|
self.add_argument('--cut_dashes_duty', type=float, default=0.25, help='Cut dash duty cycle.')
|
||||||
|
self.add_argument('--cut_dashes_bool', type=inkex.Boolean, default=False, help='Dashed strokes?')
|
||||||
|
self.add_argument('--cut_bool', type=inkex.Boolean, default=True, help='Draw cuts?')
|
||||||
|
|
||||||
|
# --------------------------------------------------------------------------------------------------------------
|
||||||
|
# vertex options
|
||||||
|
self.add_argument('--vertex_stroke_color', default=255, help='Vertices\' color.')
|
||||||
|
self.add_argument('--vertex_stroke_width', type=float, default=0.1, help='Width of vertex strokes.')
|
||||||
|
self.add_argument('--vertex_radius', type=float, default=0.1, help='Radius of vertices.')
|
||||||
|
self.add_argument('--vertex_bool', type=inkex.Boolean, default=True, help='Draw vertices?')
|
||||||
|
# here so we can have tabs - but we do not use it directly - else error
|
||||||
|
self.add_argument('--active-tab', default='title', help="Active tab.")
|
||||||
|
|
||||||
|
self.path_tree = []
|
||||||
|
self.edge_points = []
|
||||||
|
self.translate = (0, 0)
|
||||||
|
|
||||||
|
def effect(self):
|
||||||
|
""" Main function, called when the extension is run.
|
||||||
|
"""
|
||||||
|
# construct dictionary containing styles
|
||||||
|
self.create_styles_dict()
|
||||||
|
|
||||||
|
# get paths for selected origami pattern
|
||||||
|
self.generate_path_tree()
|
||||||
|
|
||||||
|
# ~ accuracy = self.options.accuracy
|
||||||
|
# ~ unit_factor = self.calc_unit_factor()
|
||||||
|
# what page are we on
|
||||||
|
# page_id = self.options.active_tab # sometimes wrong the very first time
|
||||||
|
|
||||||
|
# Translate according to translate attribute
|
||||||
|
g_attribs = {inkex.addNS('label', 'inkscape'): '{} Origami pattern'.format(self.options.pattern),
|
||||||
|
# inkex.addNS('transform-center-x','inkscape'): str(-bbox_center[0]),
|
||||||
|
# inkex.addNS('transform-center-y','inkscape'): str(-bbox_center[1]),
|
||||||
|
inkex.addNS('transform-center-x', 'inkscape'): str(0),
|
||||||
|
inkex.addNS('transform-center-y', 'inkscape'): str(0),
|
||||||
|
'transform': 'translate(%s,%s)' % self.translate}
|
||||||
|
|
||||||
|
# add the group to the document's current layer
|
||||||
|
if type(self.path_tree) == list and len(self.path_tree) != 1:
|
||||||
|
self.topgroup = etree.SubElement(self.get_layer(), 'g', g_attribs)
|
||||||
|
else:
|
||||||
|
self.topgroup = self.get_layer()
|
||||||
|
|
||||||
|
if len(self.edge_points) == 0:
|
||||||
|
Path.draw_paths_recursively(self.path_tree, self.topgroup, self.styles_dict)
|
||||||
|
elif self.options.edge_single_path:
|
||||||
|
edges = Path(self.edge_points, 'e', closed=True)
|
||||||
|
Path.draw_paths_recursively(self.path_tree + [edges], self.topgroup, self.styles_dict)
|
||||||
|
else:
|
||||||
|
edges = Path.generate_separated_paths(self.edge_points, 'e', closed=True)
|
||||||
|
Path.draw_paths_recursively(self.path_tree + edges, self.topgroup, self.styles_dict)
|
||||||
|
|
||||||
|
# self.draw_paths_recursively(self.path_tree, self.topgroup, self.styles_dict)
|
||||||
|
|
||||||
|
# compatibility hack
|
||||||
|
def get_layer(self):
|
||||||
|
try:
|
||||||
|
return self.svg.get_current_layer() # new
|
||||||
|
except:
|
||||||
|
return self.current_layer # old
|
||||||
|
|
||||||
|
def create_styles_dict(self):
|
||||||
|
""" Get stroke style parameters and use them to create the styles dictionary, used for the Path generation
|
||||||
|
"""
|
||||||
|
unit_factor = self.calc_unit_factor()
|
||||||
|
|
||||||
|
# define colour and stroke width
|
||||||
|
mountain_style = {'draw': self.options.mountain_bool,
|
||||||
|
'stroke': self.get_color_string(self.options.mountain_stroke_color),
|
||||||
|
'fill': 'none',
|
||||||
|
'stroke-width': self.options.mountain_stroke_width*unit_factor}
|
||||||
|
|
||||||
|
valley_style = {'draw': self.options.valley_bool,
|
||||||
|
'stroke': self.get_color_string(self.options.valley_stroke_color),
|
||||||
|
'fill': 'none',
|
||||||
|
'stroke-width': self.options.valley_stroke_width*unit_factor}
|
||||||
|
|
||||||
|
universal_style = {'draw': self.options.universal_bool,
|
||||||
|
'stroke': self.get_color_string(self.options.universal_stroke_color),
|
||||||
|
'fill': 'none',
|
||||||
|
'stroke-width': self.options.universal_stroke_width*unit_factor}
|
||||||
|
|
||||||
|
semicrease_style = {'draw': self.options.semicrease_bool,
|
||||||
|
'stroke': self.get_color_string(self.options.semicrease_stroke_color),
|
||||||
|
'fill': 'none',
|
||||||
|
'stroke-width': self.options.semicrease_stroke_width*unit_factor}
|
||||||
|
|
||||||
|
cut_style = {'draw': self.options.cut_bool,
|
||||||
|
'stroke': self.get_color_string(self.options.cut_stroke_color),
|
||||||
|
'fill': 'none',
|
||||||
|
'stroke-width': self.options.cut_stroke_width*unit_factor}
|
||||||
|
|
||||||
|
edge_style = {'draw': self.options.edge_bool,
|
||||||
|
'stroke': self.get_color_string(self.options.edge_stroke_color),
|
||||||
|
'fill': 'none',
|
||||||
|
'stroke-width': self.options.edge_stroke_width*unit_factor}
|
||||||
|
|
||||||
|
vertex_style = {'draw': self.options.vertex_bool,
|
||||||
|
'stroke': self.get_color_string(self.options.vertex_stroke_color),
|
||||||
|
'fill': 'none',
|
||||||
|
'stroke-width': self.options.vertex_stroke_width*unit_factor}
|
||||||
|
|
||||||
|
# check if dashed option selected
|
||||||
|
if self.options.mountain_dashes_bool:
|
||||||
|
dash = self.options.mountain_dashes_len*self.options.mountain_dashes_duty*unit_factor
|
||||||
|
gap = abs(dash - self.options.mountain_dashes_len*unit_factor)
|
||||||
|
mountain_style['stroke-dasharray'] = "{},{}".format(dash, gap)
|
||||||
|
if self.options.valley_dashes_bool:
|
||||||
|
dash = self.options.valley_dashes_len * self.options.valley_dashes_duty*unit_factor
|
||||||
|
gap = abs(dash - self.options.valley_dashes_len*unit_factor)
|
||||||
|
valley_style['stroke-dasharray'] = "{},{}".format(dash, gap)
|
||||||
|
if self.options.edge_dashes_bool:
|
||||||
|
dash = self.options.edge_dashes_len * self.options.edge_dashes_duty*unit_factor
|
||||||
|
gap = abs(dash - self.options.edge_dashes_len*unit_factor)
|
||||||
|
edge_style['stroke-dasharray'] = "{},{}".format(dash, gap)
|
||||||
|
if self.options.universal_dashes_bool:
|
||||||
|
dash = self.options.universal_dashes_len * self.options.universal_dashes_duty*unit_factor
|
||||||
|
gap = abs(dash - self.options.universal_dashes_len*unit_factor)
|
||||||
|
universal_style['stroke-dasharray'] = "{},{}".format(dash, gap)
|
||||||
|
if self.options.semicrease_dashes_bool:
|
||||||
|
dash = self.options.semicrease_dashes_len * self.options.semicrease_dashes_duty*unit_factor
|
||||||
|
gap = abs(dash - self.options.semicrease_dashes_len*unit_factor)
|
||||||
|
semicrease_style['stroke-dasharray'] = "{},{}".format(dash, gap)
|
||||||
|
if self.options.cut_dashes_bool:
|
||||||
|
dash = self.options.cut_dashes_len * self.options.cut_dashes_duty*unit_factor
|
||||||
|
gap = abs(dash - self.options.cut_dashes_len*unit_factor)
|
||||||
|
cut_style['stroke-dasharray'] = "{},{}".format(dash, gap)
|
||||||
|
|
||||||
|
self.styles_dict = {'m': mountain_style,
|
||||||
|
'v': valley_style,
|
||||||
|
'u': universal_style,
|
||||||
|
's': semicrease_style,
|
||||||
|
'c': cut_style,
|
||||||
|
'e': edge_style,
|
||||||
|
'p': vertex_style}
|
||||||
|
|
||||||
|
def get_color_string(self, longColor, verbose=False):
|
||||||
|
""" Convert the long into a #RRGGBB color value
|
||||||
|
- verbose=true pops up value for us in defaults
|
||||||
|
conversion back is A + B*256^1 + G*256^2 + R*256^3
|
||||||
|
"""
|
||||||
|
# compatibility hack, no "long" in Python 3
|
||||||
|
try:
|
||||||
|
longColor = long(longColor)
|
||||||
|
if longColor < 0: longColor = long(longColor) & 0xFFFFFFFF
|
||||||
|
hexColor = hex(longColor)[2:-3]
|
||||||
|
except:
|
||||||
|
longColor = int(longColor)
|
||||||
|
hexColor = hex(longColor)[2:-2]
|
||||||
|
inkex.debug = inkex.utils.debug
|
||||||
|
|
||||||
|
hexColor = '#' + hexColor.rjust(6, '0').upper()
|
||||||
|
if verbose: inkex.debug("longColor = {}, hex = {}".format(longColor,hexColor))
|
||||||
|
|
||||||
|
return hexColor
|
||||||
|
|
||||||
|
def add_text(self, node, text, position, text_height=12):
|
||||||
|
""" Create and insert a single line of text into the svg under node.
|
||||||
|
"""
|
||||||
|
line_style = {'font-size': '%dpx' % text_height, 'font-style':'normal', 'font-weight': 'normal',
|
||||||
|
'fill': '#F6921E', 'font-family': 'Bitstream Vera Sans,sans-serif',
|
||||||
|
'text-anchor': 'middle', 'text-align': 'center'}
|
||||||
|
line_attribs = {inkex.addNS('label','inkscape'): 'Annotation',
|
||||||
|
'style': str(Inkex.style(line_style)),
|
||||||
|
'x': str(position[0]),
|
||||||
|
'y': str((position[1] + text_height) * 1.2)
|
||||||
|
}
|
||||||
|
line = etree.SubElement(node, inkex.addNS('text','svg'), line_attribs)
|
||||||
|
line.text = text
|
||||||
|
|
||||||
|
|
||||||
|
def calc_unit_factor(self):
|
||||||
|
return self.svg.unittouu(str(1.0) + self.options.units)
|
91
extensions/OrigamiPatterns/Pleat_Circular.py
Normal file
91
extensions/OrigamiPatterns/Pleat_Circular.py
Normal file
@ -0,0 +1,91 @@
|
|||||||
|
#! /usr/bin/env python3
|
||||||
|
|
||||||
|
import inkex
|
||||||
|
import numpy as np
|
||||||
|
from math import pi, sin, cos
|
||||||
|
from Path import Path
|
||||||
|
from Pattern import Pattern
|
||||||
|
|
||||||
|
|
||||||
|
# Select name of class, inherits from Pattern
|
||||||
|
# TODO:
|
||||||
|
# 1) Implement __init__ method to get all custom options and then call Pattern's __init__
|
||||||
|
# 2) Implement generate_path_tree to define all of the desired strokes
|
||||||
|
|
||||||
|
class PleatCircular(Pattern):
|
||||||
|
def __init__(self):
|
||||||
|
Pattern.__init__(self)
|
||||||
|
self.add_argument("-p", "--pattern", default="pleat_circular", help="Origami pattern")
|
||||||
|
self.add_argument("--radius", type=float, default=55.0, help="Radius of circle")
|
||||||
|
self.add_argument("--ratio", type=float, default=0.4, help="Opening ratio")
|
||||||
|
self.add_argument("--rings", type=int, default=15, help="Number of rings")
|
||||||
|
self.add_argument("--simulation_mode", type=inkex.Boolean, default=True, help="Approximate circle and draw semicreases for simulation?")
|
||||||
|
self.add_argument("--sides", type=int, default=20, help="Number of sides for polygon approximating half circle")
|
||||||
|
|
||||||
|
def generate_path_tree(self):
|
||||||
|
""" Specialized path generation for your origami pattern
|
||||||
|
"""
|
||||||
|
# retrieve saved parameters
|
||||||
|
unit_factor = self.calc_unit_factor()
|
||||||
|
R = self.options.radius * unit_factor
|
||||||
|
ratio = self.options.ratio
|
||||||
|
r = R * ratio
|
||||||
|
rings = self.options.rings
|
||||||
|
dr = (1.-ratio)*R/rings
|
||||||
|
self.translate = (R, R)
|
||||||
|
|
||||||
|
if not self.options.simulation_mode:
|
||||||
|
inner_circles = []
|
||||||
|
for i in range(1, rings):
|
||||||
|
inner_circles.append(Path((0, 0), radius=r + i*dr, style='m' if i % 2 else 'v'))
|
||||||
|
|
||||||
|
edges = [Path((0, 0), radius=R, style='e'),
|
||||||
|
Path((0, 0), radius=r, style='e')]
|
||||||
|
|
||||||
|
self.path_tree = [inner_circles, edges]
|
||||||
|
|
||||||
|
# append semicreases for simulation
|
||||||
|
else:
|
||||||
|
sides = self.options.sides
|
||||||
|
dtheta = pi / sides
|
||||||
|
# create diagonals
|
||||||
|
diagonals = []
|
||||||
|
for i in range(sides):
|
||||||
|
p1 = (0, 0)
|
||||||
|
p2 = (R * cos((1 + i * 2) * dtheta), R * sin((1 + i * 2) * dtheta))
|
||||||
|
diagonals.append(Path([p1, p2], 'u'))
|
||||||
|
|
||||||
|
s = sin(dtheta)
|
||||||
|
c = cos(dtheta)
|
||||||
|
|
||||||
|
# Edge
|
||||||
|
paths = [Path([(c * R, -s * R), (R, 0), (c * R, s * R)], style='e'),
|
||||||
|
Path([(c * r, -s * r), (r, 0), (c * r, s * r)], style='e')]
|
||||||
|
|
||||||
|
# MV circles
|
||||||
|
for i in range(1, rings):
|
||||||
|
r_i = r + i * dr
|
||||||
|
paths.append(Path([(c * r_i, -s * r_i), (r_i, 0), (c * r_i, s * r_i)],
|
||||||
|
style='m' if i % 2 else 'v'))
|
||||||
|
|
||||||
|
# Semicreases
|
||||||
|
top = []
|
||||||
|
bottom = []
|
||||||
|
for i in range(rings + 1):
|
||||||
|
r_i = r + i*dr
|
||||||
|
top.append((r_i*(1 + (i % 2)*(c-1)), -(i % 2)*s*r_i))
|
||||||
|
bottom.append((r_i*(1 + (i % 2)*(c-1)), (i % 2)*s*r_i))
|
||||||
|
paths = paths + [Path([(r, 0), (R, 0)], 's'), # straight line 1
|
||||||
|
Path([(r*c, r*s), (R*c, R*s)], 's', invert=True), # straight line 2
|
||||||
|
Path(top, 's'), # top half of semicrease pattern
|
||||||
|
Path(bottom, 's')] # bottom half of semicrease pattern
|
||||||
|
|
||||||
|
all_paths = [paths]
|
||||||
|
for i in range(1, sides):
|
||||||
|
all_paths.append(Path.list_rotate(all_paths[0], i*2*dtheta))
|
||||||
|
|
||||||
|
self.path_tree = all_paths
|
||||||
|
|
||||||
|
# Main function, creates an instance of the Class and calls inkex.affect() to draw the origami on inkscape
|
||||||
|
if __name__ == '__main__':
|
||||||
|
PleatCircular().run()
|
97
extensions/OrigamiPatterns/Template.py
Normal file
97
extensions/OrigamiPatterns/Template.py
Normal file
@ -0,0 +1,97 @@
|
|||||||
|
#! /usr/bin/env python3
|
||||||
|
|
||||||
|
import numpy as np
|
||||||
|
from math import pi
|
||||||
|
import inkex
|
||||||
|
from Path import Path
|
||||||
|
from Pattern import Pattern
|
||||||
|
|
||||||
|
# Select name of class, inherits from Pattern
|
||||||
|
# TODO:
|
||||||
|
# 1) Implement __init__ method to get all custom options and then call Pattern's __init__
|
||||||
|
# 2) Implement generate_path_tree to define all of the desired strokes
|
||||||
|
|
||||||
|
class Template(Pattern):
|
||||||
|
def __init__(self):
|
||||||
|
Pattern.__init__(self)
|
||||||
|
self.add_argument('-p', '--pattern', default="template1", help="Origami pattern")
|
||||||
|
self.add_argument('--length', type=float, default=10.0, help="Length of grid square")
|
||||||
|
self.add_argument('--theta', type=int, default=0, help="Rotation angle (degree)")
|
||||||
|
|
||||||
|
def generate_path_tree(self):
|
||||||
|
""" Specialized path generation for your origami pattern
|
||||||
|
"""
|
||||||
|
# retrieve conversion factor for selected unit
|
||||||
|
unit_factor = self.calc_unit_factor()
|
||||||
|
|
||||||
|
# retrieve saved parameters, and apply unit factor where needed
|
||||||
|
length = self.options.length * unit_factor
|
||||||
|
vertex_radius = self.options.vertex_radius * unit_factor
|
||||||
|
pattern = self.options.pattern
|
||||||
|
theta = self.options.theta * pi / 180
|
||||||
|
|
||||||
|
# create all Path instances defining strokes
|
||||||
|
# first define its points as a list of tuples...
|
||||||
|
mountain_h_stroke_points = [(length / 2, 0),
|
||||||
|
(length / 2, length)]
|
||||||
|
mountain_v_stroke_points = [(0, length / 2),
|
||||||
|
(length, length / 2)]
|
||||||
|
|
||||||
|
# ... and then create the Path instances, defining its type ('m' for mountain, etc...)
|
||||||
|
mountains = [Path(mountain_h_stroke_points, 'm' if pattern == 'template1' else 'v'),
|
||||||
|
Path(mountain_v_stroke_points, 'm' if pattern == 'template1' else 'v')]
|
||||||
|
|
||||||
|
# doing the same for valleys
|
||||||
|
valley_1st_stroke_points = [(0, 0),
|
||||||
|
(length, length)]
|
||||||
|
valley_2nd_stroke_points = [(0, length),
|
||||||
|
(length, 0)]
|
||||||
|
valleys = [Path(valley_1st_stroke_points, 'v' if pattern == 'template1' else 'm'),
|
||||||
|
Path(valley_2nd_stroke_points, 'v' if pattern == 'template1' else 'm')]
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
vertices = []
|
||||||
|
for i in range(3):
|
||||||
|
for j in range(3):
|
||||||
|
vertices.append(Path(((i/2.) * length, (j/2.) * length), style='p', radius=vertex_radius))
|
||||||
|
|
||||||
|
# multiplication is implemented as a rotation, and list_rotate implements rotation for list of Path instances
|
||||||
|
vertices = Path.list_rotate(vertices, theta, (1 * length, 1 * length))
|
||||||
|
mountains = Path.list_rotate(mountains, theta, (1 * length, 1 * length))
|
||||||
|
valleys = Path.list_rotate(valleys, theta, (1 * length, 1 * length))
|
||||||
|
|
||||||
|
# if Path constructor is called with more than two points, a single stroke connecting all of then will be
|
||||||
|
# created. Using method generate_separated_paths, you can instead return a list of separated strokes
|
||||||
|
# linking each two points
|
||||||
|
# create a list for edge strokes
|
||||||
|
edge_points = [(0 * length, 0 * length), # top left
|
||||||
|
(1 * length, 0 * length), # top right
|
||||||
|
(1 * length, 1 * length), # bottom right
|
||||||
|
(0 * length, 1 * length)] # bottom left
|
||||||
|
|
||||||
|
# create path from points to be able to use the already built rotate method
|
||||||
|
edges = Path(edge_points, 'e', closed=True)
|
||||||
|
edges = Path.list_rotate(edges, theta, (1 * length, 1 * length))
|
||||||
|
|
||||||
|
# division is implemented as a reflection, and list_reflect implements it for a list of Path instances
|
||||||
|
# here's a commented example:
|
||||||
|
# line_reflect = (0 * length, 2 * length, 1 * length, 1 * length)
|
||||||
|
# mountains = Path.list_reflect(mountains, line_reflect)
|
||||||
|
# valleys = Path.list_reflect(valleys, line_reflect)
|
||||||
|
# edges = Path.list_reflect(edges, line_reflect)
|
||||||
|
|
||||||
|
# IMPORTANT: at the end, save edge points as "self.edge_points", to simplify selection of single or multiple
|
||||||
|
# strokes for the edge
|
||||||
|
self.edge_points = edges.points
|
||||||
|
|
||||||
|
# IMPORTANT: the attribute "path_tree" must be created at the end, saving all strokes
|
||||||
|
self.path_tree = [mountains, valleys, vertices]
|
||||||
|
# if you decide not to declare "self.edge_points", then the edge must be explicitly created in the path_tree:
|
||||||
|
# self.path_tree = [mountains, valleys, vertices, edges]
|
||||||
|
|
||||||
|
|
||||||
|
# Main function, creates an instance of the Class and calls self.draw() to draw the origami on inkscape
|
||||||
|
# self.draw() is either a call to inkex.affect() or to svg.run(), depending on python version
|
||||||
|
if __name__ == '__main__':
|
||||||
|
Template().run()
|
103
extensions/OrigamiPatterns/Waterbomb.py
Normal file
103
extensions/OrigamiPatterns/Waterbomb.py
Normal file
@ -0,0 +1,103 @@
|
|||||||
|
#! /usr/bin/env python3
|
||||||
|
|
||||||
|
import math
|
||||||
|
import numpy as np
|
||||||
|
import inkex
|
||||||
|
from Path import Path
|
||||||
|
from Pattern import Pattern
|
||||||
|
|
||||||
|
# TODO:
|
||||||
|
# Add fractional column number option
|
||||||
|
|
||||||
|
class Waterbomb(Pattern):
|
||||||
|
def __init__(self):
|
||||||
|
Pattern.__init__(self)
|
||||||
|
self.add_argument("-p", "--pattern", default="waterbomb", help="Origami pattern")
|
||||||
|
self.add_argument("--pattern_first_line", default="waterbomb", help="Origami pattern")
|
||||||
|
self.add_argument("--pattern_last_line", default="waterbomb", help="Origami pattern")
|
||||||
|
self.add_argument("--lines", type=int, default=8, help="Number of lines")
|
||||||
|
self.add_argument("--columns", type=int, default=16, help="Number of columns")
|
||||||
|
self.add_argument("--length", type=float, default=10.0, help="Length of grid square")
|
||||||
|
self.add_argument('--phase_shift', type=inkex.Boolean, default=True, help='Shift phase of tesselation.')
|
||||||
|
|
||||||
|
def generate_path_tree(self):
|
||||||
|
""" Specialized path generation for Waterbomb tesselation pattern
|
||||||
|
"""
|
||||||
|
unit_factor = self.calc_unit_factor()
|
||||||
|
length = self.options.length * unit_factor
|
||||||
|
vertex_radius = self.options.vertex_radius * unit_factor
|
||||||
|
cols = self.options.columns
|
||||||
|
lines = self.options.lines
|
||||||
|
phase_shift = self.options.phase_shift
|
||||||
|
pattern_first_line = self.options.pattern_first_line
|
||||||
|
pattern_last_line = self.options.pattern_last_line
|
||||||
|
|
||||||
|
# create vertices
|
||||||
|
vertex_line_types = [[Path(((i / 2.) * length, 0), style='p', radius=vertex_radius) for i in range(2*cols + 1)],
|
||||||
|
[Path((i * length, 0), style='p', radius=vertex_radius) for i in range(cols + 1)],
|
||||||
|
[Path(((i + 0.5) * length, 0), style='p', radius=vertex_radius) for i in range(cols)]]
|
||||||
|
|
||||||
|
vertices = []
|
||||||
|
for i in range(2*lines + 1):
|
||||||
|
if i % 2 == 0 or (pattern_first_line == 'magic_ball' and i == 1) or (pattern_last_line == 'magic_ball' and i == 2*lines - 1):
|
||||||
|
type = 0
|
||||||
|
elif(i/2 + phase_shift) % 2 == 0:
|
||||||
|
type = 1
|
||||||
|
else:
|
||||||
|
type = 2
|
||||||
|
vertices = vertices + Path.list_add(vertex_line_types[type], (0, 0.5*i*length))
|
||||||
|
|
||||||
|
# create a list for the horizontal creases and another for the vertical creases
|
||||||
|
# alternate strokes to minimize laser cutter path
|
||||||
|
corr_fist_line = length/2 if pattern_first_line == 'magic_ball' else 0
|
||||||
|
corr_last_line = length/2 if pattern_last_line == 'magic_ball' else 0
|
||||||
|
grid = [Path.generate_hgrid([0, length*cols], [0, length*lines], lines, 'm'),
|
||||||
|
Path.generate_vgrid([0, length*cols], [corr_fist_line, length*lines-corr_last_line], 2*cols, 'm')]
|
||||||
|
|
||||||
|
vgrid_a = Path.generate_vgrid([0, length * cols], [0, length / 2], 2 * cols, 'v')
|
||||||
|
vgrid_b = Path.list_add(vgrid_a, (0, (lines - 0.5) * length))
|
||||||
|
if pattern_first_line == 'magic_ball' and pattern_last_line == 'magic_ball':
|
||||||
|
grid[1] = [[vgrid_a[i], grid[1][i], vgrid_b[i]] if i % 2 == 0 else
|
||||||
|
[vgrid_b[i], grid[1][i], vgrid_a[i]] for i in range(len(grid[1]))]
|
||||||
|
elif pattern_first_line == 'magic_ball':
|
||||||
|
grid[1] = [[vgrid_a[i], grid[1][i]] if i % 2 == 0 else
|
||||||
|
[grid[1][i], vgrid_a[i]] for i in range(len(grid[1]))]
|
||||||
|
elif pattern_last_line == 'magic_ball':
|
||||||
|
grid[1] = [[grid[1][i], vgrid_b[i]] if i % 2 == 0 else
|
||||||
|
[vgrid_b[i], grid[1][i]] for i in range(len(grid[1]))]
|
||||||
|
|
||||||
|
# create generic valley Path lines, one pointing up and other pointing down
|
||||||
|
valley_types = [Path([(i * length / 2, (1 - i % 2) * length / 2) for i in range(2 * cols + 1)], 'v'),
|
||||||
|
Path([( i*length/2, (i % 2)*length/2) for i in range(2 * cols + 1)], 'v')]
|
||||||
|
|
||||||
|
# define which lines must be of which type, according to parity and options
|
||||||
|
senses = np.array([bool((i % 2+i)/2 % 2) for i in range(2*lines)])
|
||||||
|
senses = 1*senses # converts bool array to 0's and 1's
|
||||||
|
if phase_shift:
|
||||||
|
senses = np.invert(senses)
|
||||||
|
if pattern_first_line == "magic_ball":
|
||||||
|
senses[0] = ~senses[0]
|
||||||
|
if pattern_last_line == "magic_ball":
|
||||||
|
senses[-1] = ~senses[-1]
|
||||||
|
valleys = [valley_types[senses[i]] + (0, i * length / 2) for i in range(2*lines)]
|
||||||
|
|
||||||
|
# convert first and last lines to mountains if magic_ball
|
||||||
|
if pattern_first_line == "magic_ball":
|
||||||
|
valleys[0].style = 'm'
|
||||||
|
if pattern_last_line == "magic_ball":
|
||||||
|
valleys[-1].style = 'm'
|
||||||
|
|
||||||
|
# invert every two lines to minimize laser cutter movements
|
||||||
|
for i in range(1, 2*lines, 2):
|
||||||
|
valleys[i].invert()
|
||||||
|
|
||||||
|
self.edge_points = [(0*length*cols, 0*length*lines), # top left
|
||||||
|
(1*length*cols, 0*length*lines), # top right
|
||||||
|
(1*length*cols, 1*length*lines), # bottom right
|
||||||
|
(0*length*cols, 1*length*lines)] # bottom left
|
||||||
|
|
||||||
|
self.path_tree = [grid, valleys, vertices]
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
Waterbomb().run()
|
0
extensions/OrigamiPatterns/__init__.py
Normal file
0
extensions/OrigamiPatterns/__init__.py
Normal file
92
extensions/fablabchemnitz_origami_patterns_kresling.inx
Normal file
92
extensions/fablabchemnitz_origami_patterns_kresling.inx
Normal file
@ -0,0 +1,92 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension">
|
||||||
|
<_name>Origami Pattern - Kresling tower</_name>
|
||||||
|
<id>fablabchemnitz.de.origami_patterns.kresling_full</id>
|
||||||
|
<param name='active-tab' type="notebook">
|
||||||
|
<page name="title" _gui-text="Options">
|
||||||
|
<param name="pattern" type="optiongroup" _gui-text="Type of Kresling tower" >
|
||||||
|
<_option value="regular">Regular</_option>
|
||||||
|
<_option value="mirrowed">Mirror odd cells</_option>
|
||||||
|
</param>
|
||||||
|
<_param name="help" type="description" xml:space="preserve">------------------------------------------------------------</_param>
|
||||||
|
<param name="lines" type="int" min="1" max="100" _gui-text="Number of cells">3</param>
|
||||||
|
<param name="sides" type="int" min="3" max="100" _gui-text="Number of polygon sides">6</param>
|
||||||
|
<_param name="help" type="description" xml:space="preserve">------------------------------------------------------------</_param>
|
||||||
|
<param name="measure_value" type="float" max="10000" precision="3" _gui-text="Measure value:">10.0</param>
|
||||||
|
<param name="measure_type" type="optiongroup" appearance="minimal" _gui-text="Measure type:">
|
||||||
|
<option value="a">Polygon side (a)</option>
|
||||||
|
<option value="b">Vertical mountain crease (b)</option>
|
||||||
|
<option value="l">Diagonal valley crease (l)</option>
|
||||||
|
<option value="radius_external">External radius</option>
|
||||||
|
<option value="radius_internal">Internal radius (totally closed)</option>
|
||||||
|
<option value="diameter_external">External diameter</option>
|
||||||
|
<option value="diameter_internal">Internal diameter (totally closed)</option>
|
||||||
|
<!--
|
||||||
|
<option value="a_l_angle">Angle between valley crease and horizontal polygon side</option>
|
||||||
|
-->
|
||||||
|
</param>
|
||||||
|
<param name="units" type="optiongroup" appearance="minimal" _gui-text="">
|
||||||
|
<option value="mm">mm</option>
|
||||||
|
<option value="cm">cm</option>
|
||||||
|
<option value="in">in</option>
|
||||||
|
<option value="pt">pt</option>
|
||||||
|
<option value="px">px</option></param>
|
||||||
|
<_param name="help" type="description" xml:space="preserve">------------------------------------------------------------</_param>
|
||||||
|
<param name="parameter_type" type="optiongroup" appearance="full" _gui-text="Parameter type:">
|
||||||
|
<option value="angle_ratio">Angle ratio (lambda)</option>
|
||||||
|
<option value="radial_ratio">Radial ratio</option>
|
||||||
|
<option value="lambdatheta">Angle between a and l (lambda * theta)</option></param>
|
||||||
|
<param name="radial_ratio" type="float" min="0" max="0.7" precision="3" _gui-text="Radial ratio:">0.5</param>
|
||||||
|
<param name="angle_ratio" type="float" min="0.5" max="1" precision="3" _gui-text="Angle ratio:">0.5</param>
|
||||||
|
<param name="lambdatheta" type="float" min="15" max="90" precision="2" _gui-text="Angle between a and l">60.0</param>
|
||||||
|
<!-- <option value="angle">Angle between l and a</option>-->
|
||||||
|
</page>
|
||||||
|
<page name="extra_options" _gui-text="Extra Options">
|
||||||
|
<param name="add_attachment" type="boolean" _gui-text="Add one more facet to close tower?">false</param>
|
||||||
|
<param name="attachment_percentage" type="float" min="0" max="100" precision="1" appearance="full" _gui-text="Length percentage of extra facet">100</param>
|
||||||
|
<_param name="help" type="description" xml:space="preserve">------------------------------------------------------------</_param>
|
||||||
|
</page>
|
||||||
|
<page name="mountains" _gui-text="Mountain creases">
|
||||||
|
<param name="mountain_bool" type="boolean" _gui-text="Draw mountains?">true</param>
|
||||||
|
<param name="mountain_dashes_bool" type="boolean" _gui-text="Dashed strokes?">true</param>
|
||||||
|
<param name="mountain_dashes_len" type="float" min="0.1" max="10" appearance="full" precision="2" _gui-text="Mountain dash + gap length">1</param>
|
||||||
|
<param name="mountain_dashes_duty" type="float" min="0.1" max="1" appearance="full" precision="2" _gui-text="Mountain dash duty cycle">0.5</param>
|
||||||
|
<param name="mountain_stroke_width" type="float" min="0.01" max="3" appearance="full" _gui-text="Width of mountain strokes">0.1</param>
|
||||||
|
<param name="mountain_stroke_color" type="color" gui-text="Mountain creases color: ">4278190335</param>
|
||||||
|
</page>
|
||||||
|
<page name="valleys" _gui-text="Valley creases">
|
||||||
|
<param name="valley_bool" type="boolean" _gui-text="Draw valley?">true</param>
|
||||||
|
<param name="valley_dashes_bool" type="boolean" _gui-text="Dashed strokes?">true</param>
|
||||||
|
<param name="valley_dashes_len" type="float" min="0.1" max="10" appearance="full" precision="2" _gui-text="Valley dash + gap length">1</param>
|
||||||
|
<param name="valley_dashes_duty" type="float" min="0.1" max="1" appearance="full" precision="2" _gui-text="Valley dash duty cycle">0.25</param>
|
||||||
|
<param name="valley_stroke_width" type="float" min="0.01" max="3" appearance="full" _gui-text="Width of valley strokes">0.1</param>
|
||||||
|
<param name="valley_stroke_color" type="color" gui-text="Valley creases color: ">65535</param>
|
||||||
|
</page>
|
||||||
|
<page name="edge" _gui-text="Edge">
|
||||||
|
<param name="edge_bool" type="boolean" _gui-text="Draw edges?">true</param>
|
||||||
|
<param name="edge_single_path" type="boolean" _gui-text="Edges as single path?">true</param>
|
||||||
|
<param name="edge_dashes_bool" type="boolean" _gui-text="Dashed strokes?">false</param>
|
||||||
|
<param name="edge_dashes_len" type="float" min="0.1" max="10" appearance="full" precision="2" _gui-text="Edge dash + gap length">1</param>
|
||||||
|
<param name="edge_dashes_duty" type="float" min="0.1" max="1" appearance="full" precision="2" _gui-text="Edge dash duty cycle">0.25</param>
|
||||||
|
<param name="edge_stroke_width" type="float" min="0.01" max="3" appearance="full" _gui-text="Width of edge strokes">0.1</param>
|
||||||
|
<param name="edge_stroke_color" type="color" gui-text="Edge color: ">255</param>
|
||||||
|
</page>
|
||||||
|
<page name="vertices" _gui-text="Vertices">
|
||||||
|
<param name="vertex_bool" type="boolean" _gui-text="Draw vertices?">false</param>
|
||||||
|
<param name="vertex_radius" type="float" min="0.01" max="50" appearance="full" _gui-text="Radius of vertices">0.1</param>
|
||||||
|
<param name="vertex_stroke_width" type="float" min="0.01" max="3" appearance="full" _gui-text="Width of vertex strokes">0.1</param>
|
||||||
|
<param name="vertex_stroke_color" type="color" gui-text="Vertices\' color: ">255</param>
|
||||||
|
</page>
|
||||||
|
</param>
|
||||||
|
<effect>
|
||||||
|
<object-type>all</object-type>
|
||||||
|
<effects-menu>
|
||||||
|
<submenu _name="FabLab Chemnitz">
|
||||||
|
<submenu _name="Paper/Cardboard Boxes"/>
|
||||||
|
</submenu>
|
||||||
|
</effects-menu>
|
||||||
|
</effect>
|
||||||
|
<script>
|
||||||
|
<command reldir="extensions" interpreter="python">OrigamiPatterns/Kresling_full.py</command>
|
||||||
|
</script>
|
||||||
|
</inkscape-extension>
|
@ -0,0 +1,67 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension">
|
||||||
|
<_name>Origami Pattern - Circular</_name>
|
||||||
|
<id>fablabchemnitz.de.origami_patterns.pleat_circular</id>
|
||||||
|
<param name='active-tab' type="notebook">
|
||||||
|
<page name="title" _gui-text="Options">
|
||||||
|
<param name="radius" type="float" max="10000" precision="3" _gui-text="Radius of circle">55.0</param>
|
||||||
|
<param name="units" type="optiongroup" appearance="minimal" _gui-text="">
|
||||||
|
<option value="mm">mm</option>
|
||||||
|
<option value="cm">cm</option>
|
||||||
|
<option value="in">in</option>
|
||||||
|
<option value="pt">pt</option>
|
||||||
|
<option value="px">px</option></param>
|
||||||
|
<param name="ratio" type="float" min="0" max="1" precision="3" _gui-text="Opening ratio">0.4</param>
|
||||||
|
<param name="rings" type="int" min="3" max="100" _gui-text="Number of rings">15</param>
|
||||||
|
<_param name="help" type="description" xml:space="preserve">------------------------------</_param>
|
||||||
|
<param name="simulation_mode" type="boolean" _gui-text="Simulation mode">true</param>
|
||||||
|
<_param name="help" type="description" xml:space="preserve">To simulate with OrigamiSimulator, semicreases (or facet creases) must be added to properly simulate paper, and the circles must be approximated as polygons.</_param>
|
||||||
|
<param name="sides" type="int" min="10" max="100" _gui-text="Number of sides for polygon approximating half circle">20</param>
|
||||||
|
</page>
|
||||||
|
<page name="mountains" _gui-text="Mountain creases">
|
||||||
|
<param name="mountain_bool" type="boolean" _gui-text="Draw mountains?">true</param>
|
||||||
|
<param name="mountain_dashes_bool" type="boolean" _gui-text="Dashed strokes?">true</param>
|
||||||
|
<param name="mountain_dashes_len" type="float" min="0.1" max="10" appearance="full" precision="2" _gui-text="Mountain dash + gap length">1</param>
|
||||||
|
<param name="mountain_dashes_duty" type="float" min="0.1" max="1" appearance="full" precision="2" _gui-text="Mountain dash duty cycle">0.5</param>
|
||||||
|
<param name="mountain_stroke_width" type="float" min="0.01" max="3" appearance="full" _gui-text="Width of mountain strokes">0.1</param>
|
||||||
|
<param name="mountain_stroke_color" type="color" gui-text="Mountain creases color: ">4278190335</param>
|
||||||
|
</page>
|
||||||
|
<page name="valleys" _gui-text="Valley creases">
|
||||||
|
<param name="valley_bool" type="boolean" _gui-text="Draw valley?">true</param>
|
||||||
|
<param name="valley_dashes_bool" type="boolean" _gui-text="Dashed strokes?">true</param>
|
||||||
|
<param name="valley_dashes_len" type="float" min="0.1" max="10" appearance="full" precision="2" _gui-text="Valley dash + gap length">1</param>
|
||||||
|
<param name="valley_dashes_duty" type="float" min="0.1" max="1" appearance="full" precision="2" _gui-text="Valley dash duty cycle">0.25</param>
|
||||||
|
<param name="valley_stroke_width" type="float" min="0.01" max="3" appearance="full" _gui-text="Width of valley strokes">0.1</param>
|
||||||
|
<param name="valley_stroke_color" type="color" gui-text="Valley creases color: ">65535</param>
|
||||||
|
</page>
|
||||||
|
<page name="edge" _gui-text="Edge">
|
||||||
|
<param name="edge_bool" type="boolean" _gui-text="Draw edges?">true</param>
|
||||||
|
<param name="edge_single_path" type="boolean" _gui-text="Edges as single path?">true</param>
|
||||||
|
<param name="edge_dashes_bool" type="boolean" _gui-text="Dashed strokes?">false</param>
|
||||||
|
<param name="edge_dashes_len" type="float" min="0.1" max="10" appearance="full" precision="2" _gui-text="Edge dash + gap length">1</param>
|
||||||
|
<param name="edge_dashes_duty" type="float" min="0.1" max="1" appearance="full" precision="2" _gui-text="Edge dash duty cycle">0.25</param>
|
||||||
|
<param name="edge_stroke_width" type="float" min="0.01" max="3" appearance="full" _gui-text="Width of edge strokes">0.1</param>
|
||||||
|
<param name="edge_stroke_color" type="color" gui-text="Edge color: ">255</param>
|
||||||
|
</page>
|
||||||
|
<page name="semicrease" _gui-text="Semicreases">
|
||||||
|
<param name="semicrease_bool" type="boolean" _gui-text="Draw semicreases?">true</param>
|
||||||
|
<param name="semicrease_dashes_bool" type="boolean" _gui-text="Dashed strokes?">false</param>
|
||||||
|
<param name="semicrease_dashes_len" type="float" min="0.1" max="10" appearance="full" precision="2" _gui-text="Semicrease dash + gap length">1</param>
|
||||||
|
<param name="semicrease_dashes_duty" type="float" min="0.1" max="1" appearance="full" precision="2" _gui-text="Semicrease dash duty cycle">0.25</param>
|
||||||
|
<param name="semicrease_stroke_width" type="float" min="0.01" max="3" appearance="full" _gui-text="Width of semicrease strokes">0.1</param>
|
||||||
|
<param name="semicrease_stroke_color" type="color" gui-text="Semicreases color: ">4294902015</param>
|
||||||
|
</page>
|
||||||
|
|
||||||
|
</param>
|
||||||
|
<effect>
|
||||||
|
<object-type>all</object-type>
|
||||||
|
<effects-menu>
|
||||||
|
<submenu _name="FabLab Chemnitz">
|
||||||
|
<submenu _name="Paper/Cardboard Boxes"/>
|
||||||
|
</submenu>
|
||||||
|
</effects-menu>
|
||||||
|
</effect>
|
||||||
|
<script>
|
||||||
|
<command reldir="extensions" interpreter="python">OrigamiPatterns/Pleat_Circular.py</command>
|
||||||
|
</script>
|
||||||
|
</inkscape-extension>
|
78
extensions/fablabchemnitz_origami_patterns_pleat_hypar.inx
Normal file
78
extensions/fablabchemnitz_origami_patterns_pleat_hypar.inx
Normal file
@ -0,0 +1,78 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension">
|
||||||
|
<_name>Origami Pattern - N-sided Hypar</_name>
|
||||||
|
<id>fablabchemnitz.de.origami_patterns.pleat_hypar</id>
|
||||||
|
<param name='active-tab' type="notebook">
|
||||||
|
<page name="title" _gui-text="Options">
|
||||||
|
<param name="pattern" type="optiongroup" _gui-text="Type of Hypar" >
|
||||||
|
<_option value="classic">Classic Hypar</_option>
|
||||||
|
<_option value="asymmetric">Asymmetric triangulation</_option>
|
||||||
|
<_option value="alternate_asymmetric">Alternating asymmetric triangulation</_option>
|
||||||
|
</param>
|
||||||
|
<param name="radius" type="float" max="10000" precision="3" _gui-text="Radius of polygon">100.0</param>
|
||||||
|
<param name="units" type="optiongroup" appearance="minimal" _gui-text="">
|
||||||
|
<option value="mm">mm</option>
|
||||||
|
<option value="cm">cm</option>
|
||||||
|
<option value="in">in</option>
|
||||||
|
<option value="pt">pt</option>
|
||||||
|
<option value="px">px</option></param>
|
||||||
|
<param name="sides" type="int" min="3" max="100" _gui-text="Number of polygon sides">4</param>
|
||||||
|
<param name="rings" type="int" min="1" max="100" _gui-text="Number of rings">7</param>
|
||||||
|
<param name="simplify_center" type="boolean" _gui-text="Simplify center (probably not suited for odd number of sides)">false</param>
|
||||||
|
<_param name="help" type="description" xml:space="preserve">Implements Hypar (classical hyperbolic paraboloid approximate).

Classic Hypar is the easiest one to fold. However, it's not rigid foldable. More information in:
Demaine, E. D., Demaine, M. L., Hart, V., Price, G. N., & Tachi, T. (2011). (Non)Existence of Pleated Folds: How Paper Folds Between Creases. Graphs and Combinatorics, 27(3), 377–397. https://doi.org/10.1007/s00373-011-1025-2</_param>
|
||||||
|
|
||||||
|
</page>
|
||||||
|
<page name="mountains" _gui-text="Mountain creases">
|
||||||
|
<param name="mountain_bool" type="boolean" _gui-text="Draw mountains?">true</param>
|
||||||
|
<param name="mountain_dashes_bool" type="boolean" _gui-text="Dashed strokes?">true</param>
|
||||||
|
<param name="mountain_dashes_len" type="float" min="0.1" max="10" appearance="full" precision="2" _gui-text="Mountain dash + gap length">1</param>
|
||||||
|
<param name="mountain_dashes_duty" type="float" min="0.1" max="1" appearance="full" precision="2" _gui-text="Mountain dash duty cycle">0.5</param>
|
||||||
|
<param name="mountain_stroke_width" type="float" min="0.01" max="3" appearance="full" _gui-text="Width of mountain strokes">0.1</param>
|
||||||
|
<param name="mountain_stroke_color" type="color" gui-text="Mountain creases color: ">4278190335</param>
|
||||||
|
</page>
|
||||||
|
<page name="valleys" _gui-text="Valley creases">
|
||||||
|
<param name="valley_bool" type="boolean" _gui-text="Draw valley?">true</param>
|
||||||
|
<param name="valley_dashes_bool" type="boolean" _gui-text="Dashed strokes?">true</param>
|
||||||
|
<param name="valley_dashes_len" type="float" min="0.1" max="10" appearance="full" precision="2" _gui-text="Valley dash + gap length">1</param>
|
||||||
|
<param name="valley_dashes_duty" type="float" min="0.1" max="1" appearance="full" precision="2" _gui-text="Valley dash duty cycle">0.25</param>
|
||||||
|
<param name="valley_stroke_width" type="float" min="0.01" max="3" appearance="full" _gui-text="Width of valley strokes">0.1</param>
|
||||||
|
<param name="valley_stroke_color" type="color" gui-text="Valley creases color: ">65535</param>
|
||||||
|
</page>
|
||||||
|
<page name="universal" _gui-text="Universal creases">
|
||||||
|
<param name="universal_bool" type="boolean" _gui-text="Draw universal creases?">true</param>
|
||||||
|
<param name="universal_dashes_bool" type="boolean" _gui-text="Dashed strokes?">false</param>
|
||||||
|
<param name="universal_dashes_len" type="float" min="0.1" max="10" appearance="full" precision="2" _gui-text="Universal dash + gap length">1</param>
|
||||||
|
<param name="universal_dashes_duty" type="float" min="0.1" max="1" appearance="full" precision="2" _gui-text="Universal dash duty cycle">0.25</param>
|
||||||
|
<param name="universal_stroke_width" type="float" min="0.01" max="3" appearance="full" _gui-text="Width of universal strokes">0.1</param>
|
||||||
|
<param name="universal_stroke_color" type="color" gui-text="Universal creases color: ">4278255615</param>
|
||||||
|
</page>
|
||||||
|
<page name="edge" _gui-text="Edge">
|
||||||
|
<param name="edge_bool" type="boolean" _gui-text="Draw edges?">true</param>
|
||||||
|
<param name="edge_single_path" type="boolean" _gui-text="Edges as single path?">true</param>
|
||||||
|
<param name="edge_dashes_bool" type="boolean" _gui-text="Dashed strokes?">false</param>
|
||||||
|
<param name="edge_dashes_len" type="float" min="0.1" max="10" appearance="full" precision="2" _gui-text="Edge dash + gap length">1</param>
|
||||||
|
<param name="edge_dashes_duty" type="float" min="0.1" max="1" appearance="full" precision="2" _gui-text="Edge dash duty cycle">0.25</param>
|
||||||
|
<param name="edge_stroke_width" type="float" min="0.01" max="3" appearance="full" _gui-text="Width of edge strokes">0.1</param>
|
||||||
|
<param name="edge_stroke_color" type="color" gui-text="Edge color: ">255</param>
|
||||||
|
</page>
|
||||||
|
<page name="vertices" _gui-text="Vertices">
|
||||||
|
<param name="vertex_bool" type="boolean" _gui-text="Draw vertices?">false</param>
|
||||||
|
<param name="vertex_radius" type="float" min="0.01" max="50" appearance="full" _gui-text="Radius of vertices">0.1</param>
|
||||||
|
<param name="vertex_stroke_width" type="float" min="0.01" max="3" appearance="full" _gui-text="Width of vertex strokes">0.1</param>
|
||||||
|
<param name="vertex_stroke_color" type="color" gui-text="Vertices\' color: ">255</param>
|
||||||
|
</page>
|
||||||
|
|
||||||
|
</param>
|
||||||
|
<effect>
|
||||||
|
<object-type>all</object-type>
|
||||||
|
<effects-menu>
|
||||||
|
<submenu _name="FabLab Chemnitz">
|
||||||
|
<submenu _name="Paper/Cardboard Boxes"/>
|
||||||
|
</submenu>
|
||||||
|
</effects-menu>
|
||||||
|
</effect>
|
||||||
|
<script>
|
||||||
|
<command reldir="extensions" interpreter="python">OrigamiPatterns/Hypar.py</command>
|
||||||
|
</script>
|
||||||
|
|
||||||
|
</inkscape-extension>
|
90
extensions/fablabchemnitz_origami_patterns_template.inx
Normal file
90
extensions/fablabchemnitz_origami_patterns_template.inx
Normal file
@ -0,0 +1,90 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension">
|
||||||
|
<_name>Origami Pattern - Template effect</_name>
|
||||||
|
<id>fablabchemnitz.de.origami_patterns.template</id>
|
||||||
|
<param name='active-tab' type="notebook">
|
||||||
|
<page name="title" _gui-text="Options">
|
||||||
|
<param name="pattern" type="optiongroup" _gui-text="Type of template" >
|
||||||
|
<_option value="template1">Template pattern 1</_option>
|
||||||
|
<_option value="template2">Template pattern 2</_option>
|
||||||
|
</param>
|
||||||
|
<param name="length" type="float" max="10000" precision="3" _gui-text="Length of grid square">10.0</param>
|
||||||
|
<param name="units" type="optiongroup" appearance="minimal" _gui-text="">
|
||||||
|
<option value="mm">mm</option>
|
||||||
|
<option value="cm">cm</option>
|
||||||
|
<option value="in">in</option>
|
||||||
|
<option value="pt">pt</option>
|
||||||
|
<option value="px">px</option></param>
|
||||||
|
<param name="theta" type="int" min="0" max="360" _gui-text="Rotation angle (degree)">0</param>
|
||||||
|
<_param name="help" type="description" xml:space="preserve">The .inx file defines the bridge between Inkscape's interface and the python script.</_param>
|
||||||
|
|
||||||
|
</page>
|
||||||
|
<page name="mountains" _gui-text="Mountain creases">
|
||||||
|
<param name="mountain_bool" type="boolean" _gui-text="Draw mountains?">true</param>
|
||||||
|
<param name="mountain_dashes_bool" type="boolean" _gui-text="Dashed strokes?">true</param>
|
||||||
|
<param name="mountain_dashes_len" type="float" min="0.1" max="10" appearance="full" precision="2" _gui-text="Mountain dash + gap length">1</param>
|
||||||
|
<param name="mountain_dashes_duty" type="float" min="0.1" max="1" appearance="full" precision="2" _gui-text="Mountain dash duty cycle">0.5</param>
|
||||||
|
<param name="mountain_stroke_width" type="float" min="0.01" max="3" appearance="full" _gui-text="Width of mountain strokes">0.1</param>
|
||||||
|
<param name="mountain_stroke_color" type="color" gui-text="Mountain creases color: ">4278190335</param>
|
||||||
|
</page>
|
||||||
|
<page name="valleys" _gui-text="Valley creases">
|
||||||
|
<param name="valley_bool" type="boolean" _gui-text="Draw valley?">true</param>
|
||||||
|
<param name="valley_dashes_bool" type="boolean" _gui-text="Dashed strokes?">true</param>
|
||||||
|
<param name="valley_dashes_len" type="float" min="0.1" max="10" appearance="full" precision="2" _gui-text="Valley dash + gap length">1</param>
|
||||||
|
<param name="valley_dashes_duty" type="float" min="0.1" max="1" appearance="full" precision="2" _gui-text="Valley dash duty cycle">0.25</param>
|
||||||
|
<param name="valley_stroke_width" type="float" min="0.01" max="3" appearance="full" _gui-text="Width of valley strokes">0.1</param>
|
||||||
|
<param name="valley_stroke_color" type="color" gui-text="Valley creases color: ">65535</param>
|
||||||
|
</page>
|
||||||
|
<page name="edge" _gui-text="Edge">
|
||||||
|
<param name="edge_bool" type="boolean" _gui-text="Draw edges?">true</param>
|
||||||
|
<param name="edge_single_path" type="boolean" _gui-text="Edges as single path?">true</param>
|
||||||
|
<param name="edge_dashes_bool" type="boolean" _gui-text="Dashed strokes?">false</param>
|
||||||
|
<param name="edge_dashes_len" type="float" min="0.1" max="10" appearance="full" precision="2" _gui-text="Edge dash + gap length">1</param>
|
||||||
|
<param name="edge_dashes_duty" type="float" min="0.1" max="1" appearance="full" precision="2" _gui-text="Edge dash duty cycle">0.25</param>
|
||||||
|
<param name="edge_stroke_width" type="float" min="0.01" max="3" appearance="full" _gui-text="Width of edge strokes">0.1</param>
|
||||||
|
<param name="edge_stroke_color" type="color" gui-text="Edge color: ">255</param>
|
||||||
|
</page>
|
||||||
|
<page name="vertices" _gui-text="Vertices">
|
||||||
|
<param name="vertex_bool" type="boolean" _gui-text="Draw vertices?">true</param>
|
||||||
|
<param name="vertex_radius" type="float" min="0.01" max="50" appearance="full" _gui-text="Radius of vertices">0.1</param>
|
||||||
|
<param name="vertex_stroke_width" type="float" min="0.01" max="3" appearance="full" _gui-text="Width of vertex strokes">0.1</param>
|
||||||
|
<param name="vertex_stroke_color" type="color" gui-text="Vertices\' color: ">255</param>
|
||||||
|
</page>
|
||||||
|
<!-- UNCOMMENT UNIVERSAL CREASES, CUTS AND/OR SEMICREASES IF NEEDED-->
|
||||||
|
<!-- <page name="universal" _gui-text="Universal creases">-->
|
||||||
|
<!-- <param name="universal_bool" type="boolean" _gui-text="Draw universal creases?">true</param>-->
|
||||||
|
<!-- <param name="universal_dashes_bool" type="boolean" _gui-text="Dashed strokes?">false</param>-->
|
||||||
|
<!-- <param name="universal_dashes_len" type="float" min="0.1" max="10" appearance="full" precision="2" _gui-text="Universal dash + gap length">1</param>-->
|
||||||
|
<!-- <param name="universal_dashes_duty" type="float" min="0.1" max="1" appearance="full" precision="2" _gui-text="Universal dash duty cycle">0.25</param>-->
|
||||||
|
<!-- <param name="universal_stroke_width" type="float" min="0.01" max="3" appearance="full" _gui-text="Width of universal strokes">0.1</param> -->
|
||||||
|
<!-- <param name="universal_stroke_color" type="color" gui-text="Universal creases color: ">4278255615</param>-->
|
||||||
|
<!-- </page>-->
|
||||||
|
<!-- <page name="semicrease" _gui-text="Semicreases">-->
|
||||||
|
<!-- <param name="semicrease_bool" type="boolean" _gui-text="Draw semicreases?">true</param>-->
|
||||||
|
<!-- <param name="semicrease_dashes_bool" type="boolean" _gui-text="Dashed strokes?">false</param>-->
|
||||||
|
<!-- <param name="semicrease_dashes_len" type="float" min="0.1" max="10" appearance="full" precision="2" _gui-text="Semicrease dash + gap length">1</param>-->
|
||||||
|
<!-- <param name="semicrease_dashes_duty" type="float" min="0.1" max="1" appearance="full" precision="2" _gui-text="Semicrease dash duty cycle">0.25</param>-->
|
||||||
|
<!-- <param name="semicrease_stroke_width" type="float" min="0.01" max="3" appearance="full" _gui-text="Width of semicrease strokes">0.1</param>-->
|
||||||
|
<!-- <param name="semicrease_stroke_color" type="color" gui-text="Semicreases color: ">4294902015</param>-->
|
||||||
|
<!-- </page>-->
|
||||||
|
<!-- <page name="cuts" _gui-text="Cuts">-->
|
||||||
|
<!-- <param name="cut_bool" type="boolean" _gui-text="Draw cuts?">true</param>-->
|
||||||
|
<!-- <param name="cut_dashes_bool" type="boolean" _gui-text="Dashed strokes?">false</param>-->
|
||||||
|
<!-- <param name="cut_dashes_len" type="float" min="0.1" max="10" appearance="full" precision="2" _gui-text="Cut dash + gap length">1</param>-->
|
||||||
|
<!-- <param name="cut_dashes_duty" type="float" min="0.1" max="1" appearance="full" precision="2" _gui-text="Cut dash duty cycle">0.25</param>-->
|
||||||
|
<!-- <param name="cut_stroke_width" type="float" min="0.01" max="3" appearance="full" _gui-text="Width of cut strokes">0.1</param>-->
|
||||||
|
<!-- <param name="cut_stroke_color" type="color" gui-text="Cut creases color: ">16711935</param>-->
|
||||||
|
<!-- </page>-->
|
||||||
|
</param>
|
||||||
|
<effect>
|
||||||
|
<object-type>all</object-type>
|
||||||
|
<effects-menu>
|
||||||
|
<submenu _name="FabLab Chemnitz">
|
||||||
|
<submenu _name="Paper/Cardboard Boxes"/>
|
||||||
|
</submenu>
|
||||||
|
</effects-menu>
|
||||||
|
</effect>
|
||||||
|
<script>
|
||||||
|
<command reldir="extensions" interpreter="python">OrigamiPatterns/Template.py</command>
|
||||||
|
</script>
|
||||||
|
</inkscape-extension>
|
73
extensions/fablabchemnitz_origami_patterns_waterbomb.inx
Normal file
73
extensions/fablabchemnitz_origami_patterns_waterbomb.inx
Normal file
@ -0,0 +1,73 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension">
|
||||||
|
<_name>Origami Pattern - Waterbomb</_name>
|
||||||
|
<id>fablabchemnitz.de.origami_patterns.magic_ball</id>
|
||||||
|
<param name='active-tab' type="notebook">
|
||||||
|
<page name="title" _gui-text="Options">
|
||||||
|
<param name="pattern_first_line" type="optiongroup" _gui-text="First line:" >
|
||||||
|
<_option value="waterbomb">Regular waterbomb</_option>
|
||||||
|
<_option value="magic_ball">Magic ball</_option>
|
||||||
|
</param>
|
||||||
|
<param name="pattern_last_line" type="optiongroup" _gui-text="Last line:" >
|
||||||
|
<_option value="waterbomb">Regular waterbomb</_option>
|
||||||
|
<_option value="magic_ball">Magic ball</_option>
|
||||||
|
</param>
|
||||||
|
<param name="phase_shift" type="boolean" _gui-text="Shift phase?">false</param>
|
||||||
|
<_param name="help" type="description" xml:space="preserve">------------------------------</_param>
|
||||||
|
<param name="lines" type="int" min="1" max="100" _gui-text="Number of lines">8</param>
|
||||||
|
<param name="columns" type="int" min="1" max="100" _gui-text="Number of columns">16</param>
|
||||||
|
<_param name="help" type="description" xml:space="preserve">------------------------------</_param>
|
||||||
|
<param name="length" type="float" max="10000" precision="3" _gui-text="Length of grid square">10.0</param>
|
||||||
|
<param name="units" type="optiongroup" appearance="minimal" _gui-text="">
|
||||||
|
<option value="mm">mm</option>
|
||||||
|
<option value="cm">cm</option>
|
||||||
|
<option value="in">in</option>
|
||||||
|
<option value="pt">pt</option>
|
||||||
|
<option value="px">px</option></param>
|
||||||
|
<_param name="help" type="description" xml:space="preserve">"Waterbomb tessellation" creates a simple tessellation pattern repeating the Waterbomb base, with a half-step phase shift between each line.
The Magic ball is a different design that inverts both the upper half of the first line and the bottom half of the last line.</_param>
|
||||||
|
|
||||||
|
</page>
|
||||||
|
<page name="mountains" _gui-text="Mountain creases">
|
||||||
|
<param name="mountain_bool" type="boolean" _gui-text="Draw mountains?">true</param>
|
||||||
|
<param name="mountain_dashes_bool" type="boolean" _gui-text="Dashed strokes?">true</param>
|
||||||
|
<param name="mountain_dashes_len" type="float" min="0.1" max="10" appearance="full" precision="2" _gui-text="Mountain dash + gap length">1</param>
|
||||||
|
<param name="mountain_dashes_duty" type="float" min="0.1" max="1" appearance="full" precision="2" _gui-text="Mountain dash duty cycle">0.5</param>
|
||||||
|
<param name="mountain_stroke_width" type="float" min="0.01" max="3" appearance="full" _gui-text="Width of mountain strokes">0.1</param>
|
||||||
|
<param name="mountain_stroke_color" type="color" gui-text="Mountain creases color: ">4278190335</param>
|
||||||
|
</page>
|
||||||
|
<page name="valleys" _gui-text="Valley creases">
|
||||||
|
<param name="valley_bool" type="boolean" _gui-text="Draw valley?">true</param>
|
||||||
|
<param name="valley_dashes_bool" type="boolean" _gui-text="Dashed strokes?">true</param>
|
||||||
|
<param name="valley_dashes_len" type="float" min="0.1" max="10" appearance="full" precision="2" _gui-text="Valley dash + gap length">1</param>
|
||||||
|
<param name="valley_dashes_duty" type="float" min="0.1" max="1" appearance="full" precision="2" _gui-text="Valley dash duty cycle">0.25</param>
|
||||||
|
<param name="valley_stroke_width" type="float" min="0.01" max="3" appearance="full" _gui-text="Width of valley strokes">0.1</param>
|
||||||
|
<param name="valley_stroke_color" type="color" gui-text="Valley creases color: ">65535</param>
|
||||||
|
</page>
|
||||||
|
<page name="edge" _gui-text="Edge">
|
||||||
|
<param name="edge_bool" type="boolean" _gui-text="Draw edges?">true</param>
|
||||||
|
<param name="edge_single_path" type="boolean" _gui-text="Edges as single path?">true</param>
|
||||||
|
<param name="edge_dashes_bool" type="boolean" _gui-text="Dashed strokes?">false</param>
|
||||||
|
<param name="edge_dashes_len" type="float" min="0.1" max="10" appearance="full" precision="2" _gui-text="Edge dash + gap length">1</param>
|
||||||
|
<param name="edge_dashes_duty" type="float" min="0.1" max="1" appearance="full" precision="2" _gui-text="Edge dash duty cycle">0.25</param>
|
||||||
|
<param name="edge_stroke_width" type="float" min="0.01" max="3" appearance="full" _gui-text="Width of edge strokes">0.1</param>
|
||||||
|
<param name="edge_stroke_color" type="color" gui-text="Edge color: ">255</param>
|
||||||
|
</page>
|
||||||
|
<page name="vertices" _gui-text="Vertices">
|
||||||
|
<param name="vertex_bool" type="boolean" _gui-text="Draw vertices?">false</param>
|
||||||
|
<param name="vertex_radius" type="float" min="0.01" max="50" appearance="full" _gui-text="Radius of vertices">0.1</param>
|
||||||
|
<param name="vertex_stroke_width" type="float" min="0.01" max="3" appearance="full" _gui-text="Width of vertex strokes">0.1</param>
|
||||||
|
<param name="vertex_stroke_color" type="color" gui-text="Vertices\' color: ">255</param>
|
||||||
|
</page>
|
||||||
|
</param>
|
||||||
|
<effect>
|
||||||
|
<object-type>all</object-type>
|
||||||
|
<effects-menu>
|
||||||
|
<submenu _name="FabLab Chemnitz">
|
||||||
|
<submenu _name="Paper/Cardboard Boxes"/>
|
||||||
|
</submenu>
|
||||||
|
</effects-menu>
|
||||||
|
</effect>
|
||||||
|
<script>
|
||||||
|
<command reldir="extensions" interpreter="python">OrigamiPatterns/Waterbomb.py</command>
|
||||||
|
</script>
|
||||||
|
</inkscape-extension>
|
Reference in New Issue
Block a user