Script to create boxes and cylinders

Hi,

I want to create a large number of boxes and cylinders (around 1000 objects in total). I have the x,y,z coordinates of these objects and their sizes. Is there a way to write a script to create multiple objects, given that I know all the coordinate dimensions?

Thanks!

Certainly… The questions are:

In what form are the coordinates? A text or CSV file?
Sounds like all the boxes are different - so as above, how are the sizes stored - also a text or CSV file?

Once the data is organized, the rest is not too hard, you have to read each line in the file and create a box according to the imported data…

–Mitch

Thanks for your reply. I probably will have to arrange the file in the correct format. It’s a text file, which contains cylinders and boxes in the following format

BOX
x y z
dx dy dz

CYLINDER
x y z
diameter dz

Explanation of the above format: the file first list whether the object is a Box or a Cylinder. If it is a box, the next line gives the x,y,z coordinates of the bottom left corner of the box. The second line gives the length in these respective coordinate directions (dx,dy,dz).

For a cylinder, the line following gives the x,y,z coordinates of the cylinder centre point, and the second line gives the cylinder diameter and the cylinder height (dz).

What I would like to know is what format does Rhino require these input files to be in? And writing the script to read them. I could probably write a perl/python script to arrange my text file to the required format.

Many thanks!

Well, the text could be parsed as it is, but it would certainly be easier if it was all on on line:

BOX x y z dx dy dz CYLINDER x y z diameter dz etc.
All you need is a simple text file. This would still need to be imported with a custom script in Rhino though (someone could easily write that for you though). The only way you could do it without a custom script would be via ReadCommandFile and with that you would need to actually convert the lines into something that could be interpreted as Rhino commands:

_Box x,y,z dx dy dz _Cylinder x,y,z dia. dz etc.

The above assumes that before importing, you need to set the Cylinder radius/diameter toggle to diameter. The x,y,z represent the initial point coordinates and must be separated by commas, the rest are spaces.

–Mitch

Many thanks for the quick reply. I believe it’s possible to re-format my files so that the data are in

_Box x,y,z dx dy dz
_Cylinder x,y,z dia. dz
etc.

How would I set the set the Cylinder radius/diameter toggle to diameter?

Thanks!

Just run the command once before reading the file, and set it to Diameter, make a dummy cylinder somewhere then Undo. The Diameter setting will “stick” for the remainder of the session.

–Mitch

Thanks Mitch. I found a problem, the cylinders are actually defined in the following way`

CYLINDER
x y z
diameter length
x

where it gives the diameter and length of the cylinder. The last line gives the cylinder axis (previously I had assumed that it is always the z-axis, which is not always the case). The cylinder axis will be either x, y or z (i.e. they are always aligned to one of the three coordinate axes).

How I can specify the cylinder axis during Rhino import?

Ouch… That will make it virtually impossible to use via ReadCommandFile - you can’t specify a cylinder via an axis like that - so it would need to be interpreted as a second point. that would mean that the line would look like this:

_Cylinder x,y,z dia length,0,0 (for along X axis)
_Cylinder x,y,z dia 0,length,0 (for along Y axis)
_Cylinder x,y,z dia 0,0,length (for along Z axis)

For this to work, you would also need to toggle the cylinder direction constraint to “None” before running the script - by default it’s “Vertical”.

Otherwise, a custom Python script in Rhino might just be easier to directly read your text file, parse the data and interpret it and create the geometry…

–Mitch

Thanks! Really appreciate it. I shall have a look at writing a custom python script.

Well, here is a Rhino/Python script to get you started… Not having a file to test if I got it right, I had to guess a bit and create my own test file… So no guarantees… --Mitch

(edited out the “print” statements which were left in for debug)

import rhinoscriptsyntax as rs
import Rhino

def BoxPoints(origin,x,y,z):
    pts=[]
    pts.append(origin)
    pts.append(origin+Rhino.Geometry.Point3d(x,0,0))
    pts.append(origin+Rhino.Geometry.Point3d(x,y,0))
    pts.append(origin+Rhino.Geometry.Point3d(0,y,0))
    pts.append(origin+Rhino.Geometry.Point3d(0,0,z))
    pts.append(origin+Rhino.Geometry.Point3d(x,0,z))
    pts.append(origin+Rhino.Geometry.Point3d(x,y,z))
    pts.append(origin+Rhino.Geometry.Point3d(0,y,z))
    return pts
    
def StringToPoint(text):
    pt_list=text.split(" ")
    return rs.coerce3dpoint(pt_list)

def ReadFileMakeBoxesCylinders():
    filename=rs.OpenFileName("Text file to import", "Text Files (*.txt)|*.txt")
    if not filename: return
    file=open(filename)
    if not file: return
    
    text=file.read()
    line_list=text.split("\n")
    #should have a list of lines
    for i in range(len(line_list)):
        
        if line_list[i].strip().lower()=="box":
            #next 2 lines are box data
            orig=StringToPoint(line_list[i+1])
            sides=line_list[i+2].split(" ")
            sides=[float(side) for side in sides]
            box_points=BoxPoints(orig,*sides)
            rs.AddBox(box_points)
            
        elif line_list[i].strip().lower()=="cylinder":
            #next 3 lines are cylinderdata
            orig=StringToPoint(line_list[i+1])
            if line_list[i+3].strip().lower()=="x":
                plane=rs.WorldZXPlane()
            elif line_list[i+3].strip().lower()=="y":
                plane=rs.WorldYZPlane()
            elif line_list[i+3].strip().lower()=="z":
                plane=rs.WorldXYPlane()
            else:
                #something went wrong
                print "Unable to determine cylinder plane"
                continue
            plane.Origin=orig
            cyl_data=line_list[i+2].strip().split(" ")
            #data is diameter, length
            rs.AddCylinder(plane,float(cyl_data[1]),0.5*float(cyl_data[0]),True)
            
        else:
            continue
ReadFileMakeBoxesCylinders()

Thanks! That works brilliantly.

I made some small changes, bascially the YZ and ZX planes

if line_list[i+3].strip().lower()=="x":
                plane=rs.WorldYZPlane()
            elif line_list[i+3].strip().lower()=="y":
                plane=rs.WorldZXPlane()

Oh, yeah, sorry, I mixed up the planes… Glad it works for you!
–Mitch