Coding a pot full of flowers

Hi,

I am trying to code a bouquet of flowers. I took this up as an exercise because I am a beginner in python and wanted a project to have a steep learning curve.

The code is supposed to work like this:

  1. Creating a pot:
    Using a couple of simple operations I want to model a pot. This has been working out fine.
  2. Creating the halms/straws of the flowers:
    this was a little more challenging, but still manageble. Starting with a set of points as the seeds I generated positions for the blossoms and smooth curves connecting them.
  3. Creating the blossoms:
    I wanted to create a simple geometric representation of a blossom. Now, for me, this is challenging. I have decided to divide this process into 3 seperate steps:
    3.1: Pascals theorem:
    I am trying to model blossoms and as the fundamental geometry I want to use ellipses. Pascals theorem states, that from any ellipse I can get six tangents whos intersections have connecting lines that intersect in one point. This allows me to create concentric blossoms, that are not completely symmetric.
    3.2: creating petal rings:
    Each blossom is build up of rings of petals that are stacked into each other. I am trying to create these petal rings from the information that pascals theorem gave me.
    3.3: Creating a blossom:
    This again should be relativly easy: by stacking the petal rings they should create a blossom.
  4. Bringing everything together:
    Finally, the Blossoms should be attached to the straws.

I have been working on this code for the last few days. Unfortunately it seems like I am meeting no end with my debugging efforts. This is why I assume that fundamentally my coding style (for example using both rhinoscript and rhinocommon methods) is flawed.

I would like to ask you all for some advice, just when you observe this code. What could I fundamentally change for the better (to make my coding more fruitful)?

Thanks,

Merlin

The Code:

"""Grasshopper Script Instance"""
import sys as sys
import Rhino
import Grasshopper

import rhinoscriptsyntax as rs
import Rhino.Geometry as rg
import random as r

# I would like to make some flowers.
        
#############################################
# 0. Making a pot
#############################################
        
plane1 = rs.WorldXYPlane()
circle1 = rs.AddCircle(plane1, 0.2)
        
plane2 = rs.MovePlane(rs.WorldXYPlane(), [0,0,0.6])
circle2 = rs.AddCircle(plane2, 0.25)
        
plane3 = plane2
circle3 = rs.AddCircle(plane3, 0.2)
        
plane4 = rs.MovePlane(rs.WorldXYPlane(), [0,0,0.5])
circle4 = rs.AddCircle(plane4, 0.19)
        
loft_this = [circle1, circle2, circle3, circle4]
        
pot = rs.AddLoftSrf(loft_this, start=[0,0,0], 
                                end=[0,0,0.5], loft_type=2)
        
earth = rs.AddPlanarSrf(circle4)
        
#############################################
# 1. Creating the seeds
#############################################
        
# We have to plant seeds inside the pot.
# Unfortunately not all seeds will flourish, 
# if they are planted at too close a distance.
        
number_of_flowers = 10
        
seeds = []
        
for i in range(number_of_flowers):
        
    # Generate random (u, v) parameters
        
    u = r.random()
    v = r.random()
        
    # Evaluate the surface at (u, v) to get the 3D point
        
    point = rs.EvaluateSurface(earth, u, v)
        
    seeds.append(point)
        
#############################################
# 2. Create the positions for the flowerheads
#############################################
        
# Moving them in z-direction...
# ...and pushing the flowerhead positions outwards.
        
flower_height = 0.5
        
flowerheads = seeds
        
centroid = (rs.SurfaceAreaCentroid(earth)[0][0],
                    rs.SurfaceAreaCentroid(earth)[0][1],
                   flower_height)

flowerheads = rs.MoveObjects(flowerheads, [0,0,flower_height])
flowerheads = rs.ScaleObjects(flowerheads, centroid, [3,3,0], False)
        
#############################################
# 3. Creating the growth_paths
#############################################
        
# I do this by simply using interpolating curves,....
# ... which are perfect for this purpose:
# Define a starting point and vector and an end point and vector....
# .... and you will get a smooth cuve between the points....
# .... with the vectors as tangents.
        
# First creating the vetors...
        
flowerhead_vectors = []
        
for i,seed in enumerate(seeds):
    vector = rs.VectorCreate(seed, flowerheads[i])
    flowerhead_vectors.append(vector)
        
# ...then the growth_paths.
        
growth_paths = []
        
for i,seed in enumerate(seeds):
    growth_path = rs.AddInterpCurve(
                    [seed,flowerheads[i]], degree=3, knotstyle=0, 
                    start_tangent=(0,0,1), end_tangent = flowerhead_vectors[i])
    growth_paths.append(growth_path)
        
# Now, for creating the flower straws.
        
        
        
#############################################
# 4. Creating the flower_operation
#############################################

# 4.1 Pascals Operation
        
# Pascals Theorem states the following for every ellipse:
# If you draw 6 different tangents on the elipse ....
# ....and take their intersection points...
# .... you can create connecting lines between these points.....
# .... that will always intersect each other in one point.
        
# Using this theorem allows me to create flowerheads...
# ....with petals that all converge to one point.
        
        
def Pascal_Operation(x,y):

    ellipse_id = rs.AddEllipse(rs.WorldXYPlane(), x, y)
        
    # Calculate tangent lines .... only as point pairs because thats all we need for now
    tangent_lines = []
    for i in range(6):  # Divide curve into 6 equal parts to get tangent points
        param = i * rs.CurveLength(ellipse_id) / 6
        point = rs.EvaluateCurve(ellipse_id, param)
        tangent = rs.CurveTangent(ellipse_id, param)
        points_of_tangent_line = [
             point + x * tangent,
             point - x * tangent,
                ]
        tangent_lines.append(points_of_tangent_line)
        
    # Calculate intersections of neighboring tangents
    intersections_of_tangents = []
    for i in range(6):
        tangent_1 = tangent_lines[i]
        tangent_2 = tangent_lines[(i + 3) % 6]
    

        intersection = rs.LineLineIntersection(
            (tangent_1[0], tangent_1[1]), (tangent_2[0], tangent_2[1])
        )
        if intersection:
            intersections_of_tangents.append(intersection[0])
        
    # Calculate intersecting lines (again only as point pairs because thats all we need for now) and...
    # ...determine the intersection of just two lines (the third is automatically concurrent with the others).
        
    line_0 = intersections_of_tangents[0], intersections_of_tangents[3]
    line_1 = intersections_of_tangents[1], intersections_of_tangents[4]

    central_intersection = rs.LineLineIntersection(
        (line_0[0], line_0[1]), (line_1[0], line_1[1]))
        
    return tangent_lines, intersections_of_tangents, central_intersection
            
        
# now using this definition of pascals sentence...
# ... we make some nice flowers.
# Its gonna be fun!
        
# 4.2 Creating a function for what i like to call "petal_rings" 

def petal_ring(x,y, petal_division):

    ellipse_id = rs.AddEllipse(rs.WorldXYPlane(), x, y)
    
    rs.CurveSeam(ellipse_id, petal_division)

    intersections_of_tangents = Pascal_Operation(x,y)[1]
    central_intersection = Pascal_Operation(x,y)[2]

    convex_curves = rs.SplitCurve(ellipse_id, [i * 1/6 for i in range(6)])

    concave_curves = []

    # Creating the upper end of each petal...
    # ...by mirroring the ellipse-segments along the ellipse-tangents

    for i in range(6):

        start_point = intersections_of_tangents[i]
        end_point = intersections_of_tangents[(i+1) % 6 ]

        concave = rs.MirrorObject(convex_curves[i % 5], start_point, end_point, True)
        concave = rs.MoveObject(concave, [0,0, x * 1.5])
        concave_curves.append(concave)

    petals = []

    for i in range(6):

        petal = rs.AddLoftSrf([concave_curves[i % 5], convex_curves[i % 5]], 
                            loft_type=1)
        petals.append(petal)

    return ellipse_id, petals, central_intersection
    

# 4.3 Creating the flowerheads

def blossom(x,y):

    step_size = 0.03

    # generate the outer ring of petals

    outer_ring = petal_ring(x,y, 0)[1]

    # generate the inner, offset ring of petals

    outer_ring_center = petal_ring(x,y, 0)[2]

    x2 = x * 0.75
    y2 = y * 0.75

    inner_ring = petal_ring(x2,y2, 1/6)[1]

    inner_ring_center = petal_ring(x2,y2, 1/6)[2]

    # Aligning the inner and the outer ring
    direction = rs.VectorAdd(outer_ring_center - inner_ring_center, [0, 0, step_size])
    inner_ring = rs.MoveObjects(inner_ring, direction)

    # putting both rings together and creating the entire blossom
    double_ring = inner_ring | outer_ring

    blossom = []

    for i in range(6):
        ring = rs.ScaleObjects(double_ring, outer_ring_center, 0.5, copy=True)
        ring = rs.MoveObjects(ring, [0, 0, step_size])
        for i in ring:
            blossom.append(ring)

    return blossom, outer_ring_center

#############################################
# 5. Bringing it all together
#############################################

blossom_positioned = []

for i in range(number_of_flowers):
    
    #Create radii for the ellipses, within a certain boundary...
    # ...to create differently shaped flowerheads.

    u = r.uniform(0.05, 0.09)
    v = r.uniform(0.05, 0.09)

    flowerhead = blossom(u,v)

    # reorienting the flowerhead

    reference = [flowerhead[1], [0,0,1], [0,1,0]]

    for i in flowerhead:
        target = [flowerheads[i], flowerhead_vectors[i] + flowerheads[i], 
        rs.VectorCrossProduct(flowerheads[i], flowerhead_vectors[i] + flowerheads[i])]
        flowerhead = rs.OrientObject(flowerhead[0][i], reference, target, flags = 0)

        blossom_positioned.append(flowerhead)

#############################################
# 6. Visualizing it
#############################################

blossoms = blossom_positioned
pot = pot
earth = earth



Dear Anonymous @user2686

20 lines of description + 300 lines of code.
what s the minimal version that shows your issue / question ?
maybe a screenshot ? current result … but I want … - a sketch ?

Did you see the great resources at

??
Please offer us a lower barrier to be able to help you.

kind regards - tom

Hello,

It looks like you need all of the code to work perfectly from top to bottom before you can see any results. I would start with just a single blossom(), get that working, then a flowerhead, then …