GE3 part 2: random furniture population with GHPython

We are going to put in place what we learn in the first part of the section about transforms. We are going to use transforms to randomly populate some portions of a plan with furnitures, in this case plants. The same principle can be adopted to add any kind of furniture to any type of shape or plan.

🦗⬇️⬇️⬇️ Download the script file here ⬇️⬇️⬇️🦗


Just show me the code

This is what the gh script will look like at the end:

The following is the final content of the main GHPython component:

import Rhino.Geometry as rg

# allocate a new empty list for the target planes
transformed_plants = []

# for each point ..
for i, pt in enumerate(i_pts):
    # retrieve a plant from the list
    plant_random_idx = i_rndm_plant_idx[i]
    plant_random = i_plants[plant_random_idx]
    
    # we need to duplicate the crv (otherwise we will work on the same object)
    plant_copy = plant_random.DuplicateCurve()

    # random rotate, scale and pln2pln
    random_angle = i_rndm_radians[i]
    random_scale_f = i_rndm_scale_fs[i]
    
    xform_rotate = rg.Transform.Rotation(random_angle, pt)
    xform_scale = rg.Transform.Scale(pt, random_scale_f)
    xform_pln2pln = rg.Transform.Translation(pt - i_plant_center[plant_random_idx])
    
    xform_random = xform_rotate * xform_scale * xform_pln2pln
    
    # apply the randomized transformations
    plant_copy.Transform(xform_random)

# output the list
o_transformed_plants = transformed_plants

Step-by-step guide

First things first, let’s start by designing our script with a simple dataflow diagram. It is very useful to put down the architecture of your program before starting (although this might change during the development!). This is called a DFD or Data Flow Diagram.

The goal is to populate a plane with a group of different furniture in such a manner that every furniture has an unique pose in the plan.

The next question you should ask yourself is “what are the steps needed in the code to achieve this goal?”. In other words, we need to identify what kind of data we need and how we need to process it to obtain the desired result. Take a piece of paper and sketch a diagram of your code’s structure. Here’s an example:

Note that we already highlight all the data and processes, as well as what will be realized in GH vanilla and GHPython components. Now we can start coding our little program.

First we extract the source and target planes. To do so we are going to get the centers for the furniture objects and for the target planes we are going to use boundary surface and populate geometry on the target shapes.

Next we are going to implement the code for randomizing the transform parameters (angles, scaling factor, index picking). To do so we are going to use the component Random. We just need to give a domain and this component will ouput a given number of randomly generated values.

And now to GHPython part, where we apply the transformations to the list of furnitures. To start we need to collect all the input objects and link them to the GHPython component with the correct associated object type. Note that we name our entries with i_name_object and our output variables are named with a o_name_object. This is just a convention to distinguish

Let’s start coding our transformer in python. First we need to import the library Rhino.Geometry with a shortcut rg to call the transform functions. Then we allocate a temporary empty list where we will store our result and assign it to our only output variable o_transformed_plants. This is the body of our script.

import Rhino.Geometry as rg

# allocate a new empty list for the target planes
transformed_plants = []

# for each point ..
for i, pt in enumerate(i_pts):
    # TO IMPLEMENT

# output the list
o_transformed_plants = transformed_plants

All the transformations will be applied in the loop. The length of the loop corresponds to the number of target points/planes so that every target will have a transform. Let’s see what’s inside the loop.

import Rhino.Geometry as rg

# allocate a new empty list for the target planes
transformed_plants = []

# for each point ..
for i, pt in enumerate(i_pts):
    # retrieve a plant from the list
    plant_random_idx = i_rndm_plant_idx[i]
    plant_random = i_plants[plant_random_idx]
    
    # we need to duplicate the crv (otherwise we will work on the same object)
    plant_copy = plant_random.DuplicateCurve()

    # the transformations come here ..

# output the list
o_transformed_plants = transformed_plants

As a first thing we need retrieve a plant curve randomly and we create a temporary copy of it. Otherwise the transformations will be later applied to the original plant curve.

import Rhino.Geometry as rg

# allocate a new empty list for the target planes
transformed_plants = []

# for each point ..
for i, pt in enumerate(i_pts):
    # retrieve a plant from the list
    plant_random_idx = i_rndm_plant_idx[i]
    plant_random = i_plants[plant_random_idx]
    
    # we need to duplicate the crv (otherwise we will work on the same object)
    plant_copy = plant_random.DuplicateCurve()

    # random rotate, scale and pln2pln
    random_angle = i_rndm_radians[i]
    random_scale_f = i_rndm_scale_fs[i]
    
    xform_rotate = rg.Transform.Rotation(random_angle, pt)
    xform_scale = rg.Transform.Scale(pt, random_scale_f)
    xform_pln2pln = rg.Transform.Translation(pt - i_plant_center[plant_random_idx])
    
    xform_random = xform_rotate * xform_scale * xform_pln2pln
    
    # apply the randomized transformations
    plant_copy.Transform(xform_random)

# output the list
o_transformed_plants = transformed_plants

Next, we create all the transformation objects from the rg library: rg.Transform.Rotation(), rg.Transform.Scale(), rg.Transform.Translation(). And we merge them in one unique transfomation that we apply to the object. Beware that order of which transformations are merged is important!

import Rhino.Geometry as rg

# allocate a new empty list for the target planes
transformed_plants = []

# for each point ..
for i, pt in enumerate(i_pts):
    # retrieve a plant from the list
    plant_random_idx = i_rndm_plant_idx[i]
    plant_random = i_plants[plant_random_idx]
    
    # we need to duplicate the crv (otherwise we will work on the same object)
    plant_copy = plant_random.DuplicateCurve()

    # random rotate, scale and pln2pln
    random_angle = i_rndm_radians[i]
    random_scale_f = i_rndm_scale_fs[i]
    
    xform_rotate = rg.Transform.Rotation(random_angle, pt)
    xform_scale = rg.Transform.Scale(pt, random_scale_f)
    xform_pln2pln = rg.Transform.Translation(pt - i_plant_center[plant_random_idx])
    
    xform_random = xform_rotate * xform_scale * xform_pln2pln
    
    # apply the randomized transformations
    plant_copy.Transform(xform_random)

# output the list
o_transformed_plants = transformed_plants

Finally we need to store the transformed object in the list and we are done!