Skip to content

Instantly share code, notes, and snippets.

@tshirtman
Last active June 16, 2022 02:14
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save tshirtman/6301662 to your computer and use it in GitHub Desktop.
Save tshirtman/6301662 to your computer and use it in GitHub Desktop.
from kivy.app import App
from kivy.lang import Builder
from kivy.properties import ListProperty, StringProperty, NumericProperty
from kivy.graphics import Mesh
from kivy.core.window import Window
from kivy.core.image import Image
from math import sin, cos, pi
texture_tree = Image('texture_tree.png').texture
kv = '''
FloatLayout:
Widget:
id: drawing
BoxLayout:
size_hint_x: None
pos_hint: {'right': 1, 'y': 0}
orientation: 'vertical'
Label:
text: 'segment width'
Slider:
value: app.segment_width
on_value: app.segment_width = args[1]
min: 0
max: 500
Label:
text: 'segment length'
Slider:
value: app.segment_length
on_value: app.segment_length = args[1]
min: 0
max: 500
Label:
text: 'angle'
Slider:
value: app.angle
on_value: app.angle = args[1]
min: 0
max: 2
Label:
text: 'dangle'
Slider:
value: app.dangle
on_value: app.dangle = args[1]
min: 0
max: .2
Label:
text: 'branch frequency'
Slider:
value: app.branch_frequency
on_value: app.branch_frequency = args[1]
min: 0
max: .3
'''
class Tree(App):
vertices = ListProperty([])
indices = ListProperty([])
mode = StringProperty('points')
segment_length = NumericProperty(100)
segment_width = NumericProperty(100)
angle = NumericProperty(.5)
dangle = NumericProperty(.05)
branch_frequency = NumericProperty(.1)
def build_segment(self, p, w, a):
p1 = p[0] + cos(a + pi / 2) * w, p[1] + sin(a + pi / 2) * w
p2 = p[0] + cos(a - pi / 2) * w, p[1] + sin(a - pi / 2) * w
return p1, p2
def build_branch(self, pos=(0, 0), angle=(pi/2), dangle=(pi/10),
prob_branch=.1, segment_length=50, segment_width=20,
branch_attenuation=.1, width_limit=1
):
w = segment_width
a = angle
p = pos
l = segment_length
vertices = []
indices = []
c = 0
while w > width_limit:
point1, point2 = self.build_segment(p, w, a)
vertices.extend((point1[0], point1[1], 0, 0))
indices.append(len(indices))
vertices.extend((point2[0], point2[1], 1, 0))
indices.append(len(indices))
a += dangle
p = p[0] + cos(a) * l, p[1] + sin(a) * l
w *= (1 - branch_attenuation)
l *= (1 - branch_attenuation)
c += 1
if c * prob_branch >= 1:
c = 0
self.build_branch(p, a, -dangle, prob_branch, l, w,
branch_attenuation, width_limit)
with self.root.ids.drawing.canvas:
Mesh(vertices=vertices,
indices=indices, mode='triangle_strip',
texture=texture_tree)
def build(self):
self.root = Builder.load_string(kv)
self.update()
self.bind(segment_length=self.update,
segment_width=self.update,
angle=self.update,
dangle=self.update,
branch_frequency=self.update,
#attenuation=self.update
)
return self.root
def update(self, *args):
self.root.ids.drawing.canvas.clear()
self.build_branch(
pos=(Window.width/2, 0),
segment_length=self.segment_length,
segment_width=self.segment_width,
angle=self.angle * pi,
dangle=self.dangle * pi,
branch_attenuation=.05,
prob_branch=self.branch_frequency
)
if __name__ == '__main__':
Tree().run()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment