Rhino Python help

Hi, I’m making a script to produce these objects inside a closed curve boundary. It keeps giving me error

Message : Parameter must be a Guid or string representing a Guid.

import rhinoscriptsyntax as rs
import math
from math import*
from scriptcontext import escape_test
import random
from random import randrange



###############################################
# SCRIPT TO CREATE NETWORKED HOUSING COMPLEX FROM ANY SITE

def move_start_point_angle( start_point , angle , distance ):
    start_x , start_y = start_point[0], start_point[1]
    new_x = cos(radians(angle))*distance + start_x
    new_y = sin(radians(angle))*distance + start_y
    
    return (new_x, new_y)




def explode_point(Start_Point,Distance,Number,Site):
    Count = 0
    Lines = [ ]
    P_end = [ ]
    while Count <= Number:
        Count += 1
        A = random.uniform(-Distance,Distance)
        B = random.uniform(-Distance,Distance)
        C = random.uniform(-Distance,Distance)
        P2 = ( Start_Point[0] + A , Start_Point[1] + B , Start_Point [2] + C )
        P2_point = rs.AddPoint(P2)
        if rs.PointInPlanarClosedCurve(P2_point,Site) == 1 :
            P_end.append(P2)
        if rs.PointInPlanarClosedCurve(P2_point,Site) == 0 :
            rs.DeleteObject(P2_point)
        Line = rs.AddLine(Start_Point , P2)
        Lines.append(Line)
    return (P_end)



def make_building ( start_point , point_b , point_c , Max_Height , Thickness ):
    

    mid_point = ( ( (start_point[0]+point_b[0]+point_c[0]) / 3) , ( (start_point[1]+point_b[1]+point_c[1]) / 3)  )

    points = start_point , point_b , point_c , mid_point

    for i in points:
        rs.AddPoint(i)

    line_1 = rs.AddLine( start_point , mid_point)
    line_2 = rs.AddLine( point_b , mid_point)
    line_3 = rs.AddLine( point_c , mid_point)

    vector = rs.AddLine( (0,0,0) , (0,0,Max_Height) )

    surface_1 = rs.ExtrudeCurve( line_1 , vector)
    surface_2 = rs.ExtrudeCurve( line_2 , vector)
    surface_3 = rs.ExtrudeCurve( line_3 , vector)

    rs.OffsetSurface( surface_1 , Thickness , tolerance = None, both_sides = True , create_solid = True)
    rs.OffsetSurface( surface_2 , Thickness , tolerance = None, both_sides = True , create_solid = True)
    rs.OffsetSurface( surface_3 , Thickness , tolerance = None, both_sides = True , create_solid = True)

def branch( start_point, end_point , angle_add , max_length , min_length):
    
    
    unit_block = []
    
    ### list points
    start_x , start_y   =  start_point[0], start_point[1] 
    end_x , end_y   =  end_point[0] , end_point[1]  

    ### gett angle of line_a
    line_a = rs.AddLine ( start_point , end_point )
    tangent_a = ( ( end_y - start_y ) / ( end_x - start_x ) )
    angle_a = degrees( math.atan ( tangent_a ) )
    
    ### add random angle to angle_a 
    angle_addition = random.uniform(10,angle_add)
    
    angle_b = angle_a + angle_addition
    angle_c = angle_a - angle_addition
    
    ### get end points
    point_b = move_start_point_angle(end_point, angle_b, max_length)
    if rs.PointInPlanarClosedCurve(point_b,Site) == 0 :
        rs.DeleteObject(point_b)

    point_c = move_start_point_angle(end_point, angle_c, max_length)
    if rs.PointInPlanarClosedCurve(point_c,Site) == 0 :
        rs.DeleteObject(point_c)
    
    Max_Height = 10
    Thickness = 10
    
    make_building(start_point,point_b,point_c,Max_Height,Thickness)



    ### looping
    distance = ( rs.Distance(start_point, point_b) + rs.Distance(start_point, point_c) ) / 2
    
    if distance > min_length:
        
        escape_test(True)
        
        angle_addition = random.uniform(10,angle_add)
        
        angle_b2 = angle_b + angle_addition
        angle_c2 = angle_c - angle_addition

        if rs.IsPoint(point_b):
            end_b = move_start_point_angle(point_b, angle_b2, max_length*.7)
            if rs.PointInPlanarClosedCurve(point_b,Site) == 1 :
                branch(point_b,end_b,angle_add, max_length*.7, min_length)
        if rs.IsPoint(point_c):
            end_c = move_start_point_angle(point_c, angle_c2, max_length*.7)
            if rs.PointInPlanarClosedCurve(point_c,Site) == 1 :
                branch(point_c,end_c,angle_add, max_length*.7, min_length)
        
        
        
    return(unit_block)

def object_color(objects):
    C = 0
    Inc = 255 / ( len( objects ) ) 
    for i in objects:
        A = random.randint(1,255)
        B = random.randint(1,255)
        C += Inc
        
        Color = rs.CreateColor((C,50,120))
        rs.AddMaterialToObject(i)
        rs.ObjectColor(i,Color)
        Index = rs.ObjectMaterialIndex(i)
        rs.MaterialColor(Index,Color)




    


###############################################

startpoints = rs.GetPoints()

Site = rs.GetObject('Site')

for i in startpoints:
    P2 = explode_point(i, 100 , 5 , Site) 
    for j in P2 :
        branch(i,j,20,100,60)

Does the error message give a line number?

Somewhere you’re likely passing an object, rather than the GUID of that object.

1 Like

Within branch() lines 89 to 94 are superfluous, because the two points point_b and point_c are not in fact points that were added to the Rhino document, but rather tuples containing a x- and y-coordinate that your move_start_point_angle() function has returned. You can only delete geometries that were added to the Rhino document and that you have a GUID (unique identifier) for.

def branch( start_point, end_point , angle_add , max_length , min_length):

    # ...
    
    ### get end points
    point_b = move_start_point_angle(end_point, angle_b, max_length)
    # if rs.PointInPlanarClosedCurve(point_b,Site) == 0 :
    #     rs.DeleteObject(point_b)

    point_c = move_start_point_angle(end_point, angle_c, max_length)
    # if rs.PointInPlanarClosedCurve(point_c,Site) == 0 :
    #     rs.DeleteObject(point_c)
   
    # ...    

If you comment those lines out, your script seems to run without raising any errors.

1 Like

here are the lines

Traceback:
line 890, in coerceguid, “C:\Users\user\AppData\Roaming\McNeel\Rhinoceros\6.0\Plug-ins\IronPython (814d908a-e25c-493d-97e9-ee3861957f49)\settings\lib\rhinoscript\utility.py”
line 77, in DeleteObject, “C:\Users\user\AppData\Roaming\McNeel\Rhinoceros\6.0\Plug-ins\IronPython (814d908a-e25c-493d-97e9-ee3861957f49)\settings\lib\rhinoscript\object.py”
line 91, in branch, “C:\Users\user\OneDrive\Documents\WOODBURY\22 SP\ARCH 431\WK15\branching 11.py”
line 191, in , “C:\Users\user\OneDrive\Documents\WOODBURY\22 SP\ARCH 431\WK15\branching 11.py”

OH! that seems to work!
Thank you very much kind stranger!
Hope the universe pays you back tenfold!

Also,
There is something wrong with the angle addition

angle_a = degrees( math.atan ( tangent_a ) )

### add random angle to angle_a 

angle_addition = random.uniform(10,angle_add)
angle_b = angle_a + angle_addition
angle_c = angle_a - angle_addition  

The branch goes nicely to right down, but it always stops early going top left.
I’m guessing it has to do with the math.atan(tangent_a)
but I’m not sure

I don’t get what you’re trying to do here. Could you explain please?

1 Like

here is a visual representation

This is a branching script.

the first part is explode_point which explodes 1 point(start_point) into X number of points(end_point)

the second part is move_start_point_angle which move a point at a angle and a distance.

the third part is branch which take the result of explode_point and create branching structure through the use of 2 move_start_point_angle (point b , point c)

to get the angle, I used math.atan to find the angle of the line (start_point , end_point) for the input of the next branch. However, maybe there is something wrong with the math that makes my branch going top left (quadrant 2 of cartesian) just stops abruptly while branches going to quadrant 4 develops nicely.

Hope that helps clear things out.

On line 79, shouldn’t tangent_a be another two-dimensional vector (or tuple with two items)? If I’m not mistaken it currently is a single float or int, resulting from tangent_a = ( ( end_y - start_y ) / ( end_x - start_x ) ), whereas it should probably be:

tangent_a = (end_x - start_x, end_y - start_y)  # (x, y)

In you case, you probably want to calculate the directed angle between two vectors:

angle_a = atan2(tangent_a[1], tangent_a[0])  # angle = atan2(y, x) = angle between tangent and world x-axis

When doing calculations with inverse tangents, please note that angles that differ by π (180°) have the same tangent. When you take the inverse tangent, you thus may need to add or subtract π (or 180°) to get the actual angle you want.
The inverse tangent will always give you an angle between π/2 (90°) and –π/2 (-90°). If your angle is not in this range, you have to add or subtract π (180°).

if angle_a > math.pi:
    angle_a -= math.pi
elif angle <= -math.pi:
    angle += math.pi

I see, so tan(a) gives the same value for angles with 180 deg difference. So, how do I get the angle of line_a (start_point,end_point)

So far I used math.atan to get the angle_a

     line_a = rs.AddLine ( start_point , end_point )
     tangent_a = ( ( end_y - start_y ) / ( end_x - start_x ) )
     angle_a = degrees( math.atan ( tangent_a ) )

YAS !

i used math.atan2 and get the correct angle. thank you so much again!

If you’re interested in branching and similar concepts, you could potentially look into the space colonization algorithm and Lindenmayer-systems. The great Rhino Python primer also has a chapter about three-dimensional recursive growth in in chapter 8 (cf. 8.6.2 Arcs). I guess I’ve already implemented part of the space colonization algorithm here, so that would probably make most sense. There’s lots of content about it online.

These are very helpful resources. I tried doing the example in the Rhino Python Primer but had trouble doing normals variation. This script, even though not there yet, I think is still ok for my final thesis.

You seem to be on the right track. :slight_smile: