Hello,
Since nobody was able to help me with this problem, I just wanted to let the followers of this post know that I’ve finally figured it out myself. I guess being stubborn really helps from time to time.
For everybody interested, on how you can draw Fibonacci squares and the spiral with GHPython, here’s the script:
"""Pythonic generator of sequential Fibonacci squares and their corresponding nautilus spiral.
Inputs:
P: start point of the spiral and the sequence of squares
L: list of Fibonacci numbers, corresponding to the side length of the squares
Output:
V: tree with L-branches of 5 3d points, representing the squares vertices
C: list of closed, planar polylines representing the squares as cells
S: list of arcs, representing the spiral fragment per square
F: numbers of the used Fibonacci sequence"""
__author__ = "P1r4t3b0y"
ghenv.Component.Name = "Pythonic Fibonacci Squares And Spiral Generator"
ghenv.Component.NickName = 'pyFibSpiral'
from Grasshopper import DataTree as Tree
from Grasshopper.Kernel.Data import GH_Path as Path
from System import Array
import rhinoscriptsyntax as rs
import math
def list_to_tree(input, none_and_holes=True, source=[0]):
"""Transforms nestings of lists or tuples to a Grasshopper DataTree"""
# written by Giulio Piacentino, giulio@mcneel.com
def proc(input,tree,track):
path = Path(Array[int](track))
if len(input) == 0 and none_and_holes: tree.EnsurePath(path); return
for i,item in enumerate(input):
if hasattr(item, '__iter__'): #if list or tuple
track.append(i); proc(item,tree,track); track.pop()
else:
if none_and_holes: tree.Insert(item,path,i)
elif item is not None: tree.Add(item,path)
if input is not None: t=Tree[object]();proc(input,t,source[:]);return t
def tree_to_list(input, retrieve_base = lambda x: x[0]):
"""Returns a list representation of a Grasshopper DataTree"""
# written by Giulio Piacentino, giulio@mcneel.com
def extend_at(path, index, simple_input, rest_list):
target = path[index]
if len(rest_list) <= target: rest_list.extend([None]*(target-len(rest_list)+1))
if index == path.Length - 1:
rest_list[target] = list(simple_input)
else:
if rest_list[target] is None: rest_list[target] = []
extend_at(path, index+1, simple_input, rest_list[target])
all = []
for i in range(input.BranchCount):
path = input.Path(i)
extend_at(path, 0, input.Branch(path), all)
return retrieve_base(all)
def squares_sequence_vtx(start_pt, side_lengths, directions):
"""Returns a list of lists with vertices per square.
Keyword arguments:
- start_pt : 3D Point (start point of the spiral and sequence)
- side_lengths : List of float/integer numbers (fibonacci sequence of numbers)
- directions : List of 3D points (directions for the vertices)"""
tmp_next_vtx = 0
rot_idx = 0 # rotation index
square_vtx = []
for s in range(len(side_lengths)): # loops over the Fibonacci sequence
vtx = []
for v in range(4): # the loop runs 4 times for 4 vtx per square
new_vtx = rs.coerce3dpoint(start_pt) + (side_lengths[s] * directions[rot_idx][v])
vtx.append(new_vtx)
if v == 2:
tmp_next_vtx = new_vtx
elif v == 3: # append start point as last point for each square
new_vtx = rs.coerce3dpoint(start_pt) + (side_lengths[s] * directions[rot_idx][0])
vtx.append(new_vtx)
start_pt = tmp_next_vtx
rot_idx += 1
square_vtx.append(vtx)
if rot_idx > 3:
# resets rotation index for next row of directions
rot_idx = 0
return square_vtx
def pt_on_circle(center_pt, radius, angle):
"""Returns a 3d point on a circle and its guid.
Keyword arguments:
- center_pt : 3D Point (origin of the circle)
- radius : Float/Integer (radius of the circle)
- angle : Float/Integer (angle in degrees)"""
x = center_pt[0] + radius * math.cos(math.radians(angle))
y = center_pt[1] + radius * math.sin(math.radians(angle))
z = center_pt[2]
pt_id = rs.AddPoint((x,y,z))
pt = rs.coerce3dpoint(pt_id)
return pt, pt_id
if __name__ == "__main__":
# SQUARE SEQUENCE VERTICES GENERATION
dirs_lt = [
[(0,0,0), (1,0,0), (1,-1,0), (0,-1,0)],
[(0,0,0), (0,-1,0), (-1,-1,0), (-1,0,0)],
[(0,0,0), (-1,0,0), (-1,1,0), (0,1,0)],
[(0,0,0), (0,1,0), (1,1,0), (1,0,0)]]
# converts the list of coordinates to 3d points
dir_pts = []
for dt in dirs_lt:
dir_pt = []
for s in dt:
pt_id = rs.AddPoint(s)
pt = rs.coerce3dpoint(pt_id)
dir_pt.append(pt)
dir_pts.append(dir_pt)
fibo_nums = L[1:] # 0 at the beginning of the Fibonacci number sequence is omitted
square_vtx = squares_sequence_vtx(P, fibo_nums, dir_pts)
# SPIRAL ARCS GENERATION
square_crvs = []
spiral_arcs = []
for i, vtx in enumerate(square_vtx):
arc_pt1 = vtx[0]
arc_pt2 = vtx[2]
radius = fibo_nums[i]
center_pt = rs.coerce3dpoint(vtx[3])
crv = rs.AddPolyline(vtx)
arc_pton, arc_pton_id = None, None
# evaluates a point on each arc
for i in range(4):
angle = 45 + (i * 90)
test_pt_params = pt_on_circle(center_pt, radius, angle)
test = rs.PointInPlanarClosedCurve(test_pt_params[0], crv)
if test == 1: # point inside fibonacci box
arc_pton, arc_pton_id = test_pt_params
arc = rs.AddArc3Pt(arc_pt1, arc_pt2, arc_pton)
spiral_arcs.append(arc)
break
square_crvs.append(crv)
# OUTPUTS
V = list_to_tree(square_vtx)
C = square_crvs
S = spiral_arcs
F = fibo_nums
I’m by no means an expert programmer, but the script works like a charm.