Script to create boxes and cylinders


#1

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!


#2

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


#3

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!


#4

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


#5

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!


#6

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


#7

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?


#8

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


#9

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


#10

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()

#11

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()

#12

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