Compare commits

...

5 Commits

3
.gitignore vendored

@ -0,0 +1,3 @@
out/
__pycache__/
nft/

Binary file not shown.

@ -6,7 +6,7 @@ import random
from utils import circle_fill from utils import circle_fill
from utils import random_color from utils import random_color
WIDTH, HEIGHT = 1000, 1000 WIDTH, HEIGHT = 500, 500
ANGLE_RANDOM_MIN = -0.6 ANGLE_RANDOM_MIN = -0.6
ANGLE_RANDOM_MAX = 0.6 ANGLE_RANDOM_MAX = 0.6
# how much to shrink each consecutive circle # how much to shrink each consecutive circle
@ -87,7 +87,6 @@ def grow_subs(ctx, subs, branches):
for branch in subs: for branch in subs:
# create a sub branch based on length # create a sub branch based on length
sub_branches = len(branch.nodes) // 7 * 2 sub_branches = len(branch.nodes) // 7 * 2
print(f'creating {sub_branches} subs')
if sub_branches > 1: if sub_branches > 1:
created = True created = True
@ -143,8 +142,6 @@ def main():
return return
ctx.set_source_rgb(0.0, 0.0, 0.1*x) ctx.set_source_rgb(0.0, 0.0, 0.1*x)
subs = grow_subs(ctx, subs, branches) subs = grow_subs(ctx, subs, branches)
surface.write_to_png("out/hyphae.png") # Output to PNG
input('next')
finally: finally:
surface.write_to_png("out/hyphae.png") # Output to PNG surface.write_to_png("out/hyphae.png") # Output to PNG

@ -0,0 +1,217 @@
#!/usr/bin/env python3
import cairo
import math
import random
import threading
import time
import socket
import colorsys
from utils import circle_fill
from utils import circle_clip_fill
from utils import random_color
import numpy
WIDTH, HEIGHT = 1024, 1024
ANGLE_RANDOM_MIN = -0.6
ANGLE_RANDOM_MAX = 0.6
# how much to shrink each consecutive circle
SHRINK = 0.00004
start_r = 0.01
NODE_ARRAY = None
start_hue = 0
# should be ~ 1 px
MIN_RADIUS = ((1/WIDTH) + (1/HEIGHT)) / 2
def chunker(seq, size):
return (seq[pos:pos + size] for pos in range(0, len(seq), size))
class Branch():
def __init__(self, idx, ctx, x, y, r, ang, mother=None):
#ctx.set_source_rgb(255, 0, 0)
self.nodes = [Node(ctx, x, y, r, ang, dry=True)]
#ctx.set_source_rgb(0,0, 0)
self.idx = idx
self.ctx = ctx
self.ended = False
self.ignores = []
self.first = True
self.mother = mother
def _last_node(self):
return self.nodes[-1]
def set_ignores(self, ignores):
self.ignores = ignores
def place_next(self, branches):
if not self.ended:
last = self._last_node()
next_x = last.r * math.sin(last.ang) + last.x
next_y = last.r * math.cos(last.ang) + last.y
next_r = last.r - SHRINK
# too small?
if next_r < MIN_RADIUS:
self.ended = True
return False
# did we hit canvas edge?
# if next_x + next_r > 1 or next_x - next_r < 0:
if (math.pow(next_x - 0.5, 2) + math.pow(next_y - 0.5, 2)) > math.pow(0.4, 2):
self.ended = True
return False
if next_y + next_r > 1 or next_y - next_r < 0:
self.ended = True
return False
last_nodes = self.nodes[-2:]
# did we hit another circle?
# search radius is radius of biggest possible circle + our radius
search_radius = next_r + start_r
search_box_x1 = next_x - search_radius
search_box_x2 = next_x + search_radius
search_box_y1 = next_y - search_radius
search_box_y2 = next_y + search_radius
filtered = NODE_ARRAY[NODE_ARRAY['x'] > search_box_x1]
filtered = filtered[filtered['x'] < search_box_x2]
filtered = filtered[filtered['y'] > search_box_y1]
filtered = filtered[filtered['y'] < search_box_y2]
# remove previous nodes
for ln in last_nodes:
filtered = filtered[ (filtered['x'] != ln.x) & (filtered['y'] != ln.y) ]
for possible_hit in filtered:
if circles_intersect(*possible_hit, next_x, next_y, next_r):
self.ended = True
return False
next_ang = last.ang + (random.uniform(ANGLE_RANDOM_MIN, ANGLE_RANDOM_MAX) * (1 - 40*last.r))
self.nodes.append(Node(self.ctx, next_x, next_y, next_r, next_ang))
if self.first:
self.first = False
first = self.nodes[0]
if self.mother:
self.ctx.set_operator(cairo.Operator.DEST_OVER)
circle_fill(self.ctx, first.x, first.y, first.r)
self.ctx.set_operator(cairo.Operator.OVER)
else:
circle_fill(self.ctx, first.x, first.y, first.r)
return True
def circles_intersect(x1, y1, r1, x2, y2, r2):
distance = math.sqrt(math.pow(abs(x2 - x1), 2) + math.pow(abs(y2 - y1), 2))
combined_r = r1 + r2
return distance < combined_r
class Node():
def __init__(self, ctx, x, y, r, ang, dry=False):
global NODE_ARRAY
self.x = x
self.y = y
self.r = r
self.ang = ang
if not dry:
NODE_ARRAY = numpy.append(NODE_ARRAY,
numpy.array([(x, y, r)],
dtype=[('x', 'float'), ('y', 'float'), ('r', 'float')])
)
circle_fill(ctx, x, y, r)
def __ne__(self, other):
return self.x != other.x or self.y != other.y or self.r != other.r or self.ang != other.ang
def grow_sub(ctx, branch, branches, new_subs):
# create a sub branch based on length
sub_branches = len(branch.nodes) // 8 * 2
if sub_branches == 0: return
#sub_branches = 4
#print(f'creating {sub_branches} subs')
for i in range(sub_branches):
for n in range(20): # attempts at growing branches
found_ang = False
start_node = random.choice(branch.nodes)
for a_try in range(10):
# start perpendicular to our last angle
start_angle = start_node.ang + random.choice([90, -90]) + random.uniform(-30, 30)
start_x = (start_node.r * 1.2) * math.sin(start_angle) + start_node.x
start_y = (start_node.r * 1.2) * math.cos(start_angle) + start_node.y
start_r = start_node.r * 0.8
new_branch = Branch(0, ctx, start_x, start_y, start_r, start_angle, mother=start_node)
if new_branch.place_next(branches):
found_ang = True
break
if found_ang:
break
grow_branch_until_ended(new_branch, branches)
new_branch.set_ignores(branch.nodes)
branches.append(new_branch)
new_subs.append(new_branch)
def grow_branch_until_ended(branch, branches):
while not branch.ended:
branch.place_next([b for b in branches if b != branch])
def grow_subs(ctx, subs, branches):
source = ctx.get_source()
new_subs = []
for branch in subs:
grow_sub(ctx, branch, branches, new_subs)
#for branch in new_subs:
# grow_branch_until_ended(branch, branches)
return new_subs
def main():
global start_hue
global NODE_ARRAY
for run in range(32):
random.seed()
start_hue = random.uniform(0, 1)
surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, WIDTH, HEIGHT)
ctx = cairo.Context(surface)
ctx.scale(WIDTH, HEIGHT) # Normalizing the canvas
# place seeds
branches = []
r, g, b = colorsys.hsv_to_rgb(start_hue, 1.0, 1.0)
#r, g, b = random_color()
ctx.set_source_rgb(r, g, b)
branches.append(Branch(0, ctx, 0.5, 0.4, start_r, 180))
branches.append(Branch(1, ctx, 0.4, 0.5, start_r, 270))
branches.append(Branch(2, ctx, 0.6, 0.5, start_r, 90))
branches.append(Branch(3, ctx, 0.5, 0.6, start_r, 0))
NODE_ARRAY = numpy.array([
(0.5, 0.4, start_r),
(0.4, 0.5, start_r),
(0.6, 0.5, start_r),
(0.5, 0.6, start_r)
], dtype = [('x', 'float'), ('y', 'float'), ('r', 'float')])
# grow initial branches
print('growing initial branches')
for branch in branches:
grow_branch_until_ended(branch, branches)
subs = branches
rarity = 3 + random.randint(0, 5)
print(f'rarity: {rarity}')
try:
for x in range(rarity):
if subs == None:
return
r, g, b = colorsys.hsv_to_rgb(start_hue + x * 0.05, 1.0, 1.0)
ctx.set_source_rgb(r, g, b)
subs = grow_subs(ctx, subs, branches)
print(f'iteration {x} done')
#surface.write_to_png("out/hyphae.png") # Output to PNG
r, g, b = colorsys.hsv_to_rgb(start_hue - 0.05, 1.0, 0.2)
ctx.set_source_rgb(r, g, b)
ctx.set_operator(cairo.Operator.DEST_OVER)
circle_fill(ctx, 0.5, 0.5, 0.4)
finally:
surface.write_to_png(f"out/hyphae_{run}_{rarity}.png") # Output to PNG
print(f'run {run} complete')
if __name__ == '__main__':
main()

@ -6,11 +6,16 @@ import random
from utils import circle_fill from utils import circle_fill
from utils import draw_crater from utils import draw_crater
from utils import random_color from utils import random_color
from utils import moon_shade
WIDTH, HEIGHT = 1000, 1000 WIDTH, HEIGHT = 100, 100
def main(): def main():
import sys
seed = sys.argv[1]
random.seed(seed)
surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, WIDTH, HEIGHT) surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, WIDTH, HEIGHT)
ctx = cairo.Context(surface) ctx = cairo.Context(surface)
@ -48,10 +53,10 @@ def main():
# draw "shade" of the phase # draw "shade" of the phase
ctx.set_source_rgba(0.1, 0.1, 0.1, 0.95) ctx.set_source_rgba(0.1, 0.1, 0.1, 0.95)
phase_pos = random.uniform(-0.5, 1.5) phase_pos = random.uniform(-1.2, 1.2)
circle_fill(ctx, phase_pos, 0.5, 0.5) #circle_fill(ctx, phase_pos, 0.5, 0.5)
moon_shade(ctx, phase_pos)
surface.write_to_png("out/moon.png") # Output to PNG surface.write_to_png(f"nft/{seed}_moon.png") # Output to PNG
if __name__ == '__main__': if __name__ == '__main__':
main() main()

@ -5,7 +5,6 @@ def circle(ctx,x,y,r):
ctx.arc(x,y,r,0,math.pi*2.) ctx.arc(x,y,r,0,math.pi*2.)
ctx.stroke() ctx.stroke()
def circle_fill(ctx,x,y,r): def circle_fill(ctx,x,y,r):
ctx.arc(x,y,r,0,math.pi*2.) ctx.arc(x,y,r,0,math.pi*2.)
ctx.fill() ctx.fill()
@ -17,6 +16,34 @@ def draw_crater(ctx,x,y,r):
ctx.arc(x + off_x, y + off_y, r, 0, math.pi*2.) ctx.arc(x + off_x, y + off_y, r, 0, math.pi*2.)
ctx.fill() ctx.fill()
def moon_shade(ctx, phase, nothern=True):
#phase=-0.4
#x_max = 0.7
x_max = 1.
# the shadow always has to "hug" one side - pick which
ctx.move_to(0.5, 0.0)
if phase > 0:
ctx.curve_to(-0.2, 0, -0.2, 1, 0.5, 1)
elif phase < 0:
ctx.curve_to(1.2, 0, 1.2, 1, 0.5, 1)
else:
return
#ctx.close_path()
#ctx.fill()
#ctx.move_to(0.5, 0.0)
#ctx.curve_to(x_max*phase, 0.5-(0.5*phase), x_max*phase, 0.5+(0.5*phase), 0.5, 1)
#ctx.curve_to(0.5 + (x_max*phase), 0.5+(0.5*phase), 0.5+ (x_max*phase), 0.5-(0.5*phase), 0.5, 0)
# helper x is the same for both points
h_x = abs(x_max * phase)
h_y = abs(h_x - 0.5)
#y_c = (phase * 0.5)
#ctx.curve_to(x_max*phase, 0.5+abs(0.5*phase-0.5), (x_max*phase), 0.5-abs(0.5*phase-0.5), 0.5, 0)
ctx.curve_to(h_x, 0.5 + h_y, h_x, 0.5-h_y, 0.5, 0)
#ctx.close_path()
ctx.fill()
def random_color(): def random_color():

@ -104,8 +104,8 @@ def create_wpotd(output):
ctx.line_to(*points[0]) ctx.line_to(*points[0])
ctx.fill() ctx.fill()
lastpoints = points lastpoints = points
return surface #return surface
#surface.write_to_png(output) # Output to PNG surface.write_to_png(output) # Output to PNG
def main(): def main():
create_wpotd('out/waves.png') create_wpotd('out/waves.png')

Loading…
Cancel
Save