Working on l-system embroideries

main
branchwelder 2022-02-27 18:45:33 -08:00
rodzic b1d2bcb402
commit 989cbdbcba
11 zmienionych plików z 364 dodań i 5 usunięć

Wyświetl plik

@ -1,3 +1,8 @@
{
"terminal.integrated.cwd": "${workspaceFolder}"
"terminal.integrated.cwd": "${workspaceFolder}",
"cSpell.words": [
"pyplot",
"xlabel",
"ylabel"
]
}

1
convo.svg 100644

File diff suppressed because one or more lines are too long

Po

Szerokość:  |  Wysokość:  |  Rozmiar: 21 KiB

91
embroiderTurtle.py 100644
Wyświetl plik

@ -0,0 +1,91 @@
import matplotlib.pyplot as plt
from math import pi, sin, cos, isnan
DEGREES_TO_RADIANS = pi / 180
def print_coords(coords):
for (x, y) in coords:
if isnan(x):
print("<gap>")
else:
print("({:.2f}, {:.2f})".format(x, y))
def turtle_to_coords(turtle_program, turn_amount=45):
# The state variable tracks the current location and angle of the turtle.
# The turtle starts at (0, 0) facing up (90 degrees).
state = (0.0, 0.0, 90.0)
# Throughout the turtle's journey, we "yield" its location. These coordinate
# pairs become the path that plot_coords draws.
yield (0.0, 0.0)
# Loop over the program, one character at a time.
for command in turtle_program:
x, y, angle = state
if command in "Ff": # Move turtle forward
state = (
x - cos(angle * DEGREES_TO_RADIANS),
y + sin(angle * DEGREES_TO_RADIANS),
angle,
)
if command == "f":
# Insert a break in the path so that
# this line segment isn't drawn.
yield (float("nan"), float("nan"))
yield (state[0], state[1])
elif command == "+": # Turn turtle clockwise without moving
state = (x, y, angle + turn_amount)
elif command == "-": # Turn turtle counter-clockwise without moving
state = (x, y, angle - turn_amount)
# Note: We silently ignore unknown commands
def plot_coords(coords, bare_plot=False):
if bare_plot:
# Turns off the axis markers.
plt.axis("off")
# Ensures equal aspect ratio.
plt.axes().set_aspect("equal", "datalim")
# Converts a list of coordinates into
# lists of X and Y values, respectively.
X, Y = zip(*coords)
# Draws the plot.
plt.plot(X, Y)
def transform_sequence(sequence, transformations):
return "".join(transformations.get(c, c) for c in sequence)
def transform_multiple(sequence, transformations, iterations):
for _ in range(iterations):
sequence = transform_sequence(sequence, transformations)
return sequence
def hilbert():
return turtle_to_coords(
transform_multiple("L", {"L": "-RF+LFL+FR-", "R": "+LF-RFR-FL+"}, 5), 90
)
if __name__ == "__main__":
plt.style.use("bmh") # Use some nicer default colors
plt.xlabel("x")
plt.ylabel("y")
plot_coords(
turtle_to_coords(
transform_multiple("L", {"L": "-RF+LFL+FR-", "R": "+LF-RFR-FL+"}, 5), 90
)
)
plt.show()

Wyświetl plik

@ -22,8 +22,15 @@ class Embryoid:
def add_stitch_block(self, block):
self.pattern.add_block(block)
def block_from_coords(self, coords):
block = []
for coord in coords:
block.append((coord[0], coord[1]))
self.pattern.add_block(block, "teal")
def parse_svg(self, fname):
paths, attributes = svg2paths(fname)
print(paths)
print(attributes)
for path in paths:
block = []
@ -43,15 +50,22 @@ def solid_block(x_len=100, y_len=100, num_stitches=20):
return stitches
def parse(fname):
def parse(fname, outname):
e = Embryoid()
e.parse_svg(INPUT_SVG + fname)
e.save_svg("linger_longer.svg")
e.save_pes("linger_longer.pes")
e.save_svg(outname + ".svg")
e.save_pes(outname + ".pes")
if __name__ == "__main__":
parse("linger_longer_audioplot.svg")
from embroiderTurtle import hilbert
e = Embryoid()
e.block_from_coords([*hilbert()])
e.save_pes("hilbert.pes")
e.save_svg("hilbert.svg")
print(*hilbert())
# parse("convo.svg", "convo")
# e = Embryoid()
# e.add_stitch_block(solid_block())
# e.save_svg("block_test.svg")

BIN
hilbert.pes 100644

Plik binarny nie jest wyświetlany.

1
hilbert.svg 100644

File diff suppressed because one or more lines are too long

Po

Szerokość:  |  Wysokość:  |  Rozmiar: 12 KiB

203
l-system.py 100644
Wyświetl plik

@ -0,0 +1,203 @@
import pygame
import math
# other = variables
# F,A = move n forward
# G = move n forward without drawing a line
# B = move n backwards
# - = turn left by angle
# + = turn right by angle
# [ = push position and angle
# ] = pop position and angle
# a,b,c,d = color 1,2,3,4
# 1-4 line size (std = 1)
#
rules = {}
rules["F"] = "F-F++F-F"
axiom = "F++F++F"
angle = 60
# rules['A'] = '+F-A-F+' # Sierpinsky
# rules['F'] = '-A+F+A-'
# axiom = 'A'
# angle = 60
# rules['F'] = 'F+F-F-F+F' # Koch curve 1
# axiom = 'F'
# angle = 60
# rules['F'] = 'F+F--F+F' # Koch curve 2
# axiom = 'F'
# angle = 60
# rules["X"] = "X+YF+" # Dragon curve
# rules["Y"] = "-FX-Y"
# axiom = "FX"
# angle = 90
# rules['X'] = 'F-[[X]+X]+F[+FX]-X' # Wheat
# rules['F'] = 'FF'
# axiom = 'X'
# angle = 25
# rules['F'] = 'a2FF-[c1-F+F+F]+[c1+F-F-F]' # Tree - colored
# axiom = 'F'
# angle = 23
# rules['X'] = 'F-[[X]-1X]+2F-[+3FX]+1X' # Wheat
# rules['F'] = 'X'
# axiom = 'X'
# angle = 25
iterations = 7 # number of iterations
step = 15 # step size / line length
color1 = (105, 46, 26) # brown 1
color2 = (201, 146, 127) # brown 2
color3 = (101, 250, 52) # green
color4 = (255, 255, 255) # white
angleoffset = 90
size = width, height = 10000, 10000 # display with/height
pygame.init() # init display
screen = pygame.Surface(size) # open screen
# startpos = 100, height - 225
# startpos = 50, height / 2 - 50
startpos = width / 2, height / 2
# startpos = 100, height / 2
# startpos = 10,10
def applyRule(input):
output = ""
for (
rule,
result,
) in rules.items(): # applying the rule by checking the current char against it
if input == rule:
output = result # Rule 1
break
else:
output = input # else ( no rule set ) output = the current char -> no rule was applied
return output
def processString(oldStr):
newstr = ""
for character in oldStr:
newstr = newstr + applyRule(character) # build the new string
return newstr
def createSystem(numIters, axiom):
startString = axiom
endString = ""
for i in range(numIters): # iterate with appling the rules
print("Iteration: {0}".format(i))
endString = processString(startString)
startString = endString
return endString
def polar_to_cart(theta, r, offx, offy):
x = r * math.cos(math.radians(theta))
y = r * math.sin(math.radians(theta))
return tuple([x + y for x, y in zip((int(x), int(y)), (offx, offy))])
def cart_to_polar(x, y):
return (math.degrees(math.atan(y / x)), math.sqrt(math.pow(x, 2) + math.pow(y, 2)))
def drawTree(input, oldpos):
a = 0 # angle
i = 0 # counter for processcalculation
processOld = 0 # old process
newpos = oldpos
num = [] # stack for the brackets
color = (255, 255, 255)
linesize = 1
xmax = 0
xmin = 0
ymax = 0
ymin = 0
for (
character
) in input: # process for drawing the l-system by writing the string to the screen
i += 1 # print process in percent
process = i * 100 / len(input)
if not process == processOld:
print(process, "%")
processOld = process
if character == "A": # magic happens here
newpos = polar_to_cart(a + angleoffset, step, oldpos[0], oldpos[1])
pygame.draw.line(screen, color, oldpos, newpos, linesize)
oldpos = newpos
elif character == "F":
newpos = polar_to_cart(a + angleoffset, step, oldpos[0], oldpos[1])
pygame.draw.line(screen, color, oldpos, newpos, linesize)
oldpos = newpos
elif character == "B":
newpos = polar_to_cart(-a + angleoffset, -step, oldpos[0], oldpos[1])
pygame.draw.line(screen, color, oldpos, newpos, linesize)
oldpos = newpos
elif character == "G":
newpos = polar_to_cart(a + angleoffset, step, oldpos[0], oldpos[1])
oldpos = newpos
elif character == "a":
color = color1
elif character == "b":
color = color2
elif character == "c":
color = color3
elif character == "d":
color = color4
elif character == "1":
linesize = 1
elif character == "2":
linesize = 2
elif character == "3":
linesize = 3
elif character == "4":
linesize = 4
elif character == "+":
a += angle
elif character == "-":
a -= angle
elif character == "[":
num.append((oldpos, a))
elif character == "]":
oldpos, a = num.pop()
if xmax < oldpos[0] - width / 2:
xmax = oldpos[0] - width / 2
if xmin > oldpos[0] - width / 2:
xmin = oldpos[0] - width / 2
if ymax < oldpos[1] - height / 2:
ymax = oldpos[1] - height / 2
if ymin > oldpos[1] - height / 2:
ymin = oldpos[1] - height / 2
crop = pygame.Surface((abs(xmax - xmin) + 100, abs(ymax - ymin) + 100))
crop.blit(
screen,
(50, 50),
(xmin + width / 2, ymin + height / 2, xmax + width / 2, ymax + height / 2),
)
pygame.image.save(crop, "screenshot.png")
if __name__ == "__main__":
# drawTree(createSystem(iterations, axiom), startpos)
tree = createSystem(iterations, axiom)
drawTree(tree, startpos)
# pygame.display.flip()
# pygame.image.save(screen, "screenshot.png")
# print "Finished"
while 1:
pass
exit() # uncommand

BIN
linger_longer.pes 100644

Plik binarny nie jest wyświetlany.

File diff suppressed because one or more lines are too long

Po

Szerokość:  |  Wysokość:  |  Rozmiar: 16 KiB

File diff suppressed because one or more lines are too long

Po

Szerokość:  |  Wysokość:  |  Rozmiar: 11 KiB

BIN
tests_pes/convo.pes 100644

Plik binarny nie jest wyświetlany.