Trouble with Python Script I'm Creating


#1

I’m trying to create a script that will allow me to select some curves, 1 or more, and run a pipe command on them with dialog boxes that give options for tubing diameter and wall thickness. I’m having trouble getting the script to just run the pipe command on curves one after another. Getting guid issues, which I thought I could fix by using coercecurve to translate the guid to an actual curve:

import rhinoscriptsyntax as rs
import scriptcontext as sc
import Rhino

def createTube():
	unitSystem = rs.UnitSystem()
	tol=sc.doc.ModelAbsoluteTolerance
	aTol=sc.doc.ModelAngleToleranceRadians

	crvID = rs.GetObjects("Choose Curves to Create Tubing From", 4, rs.filter.curve, preselect=True)
	
	# Tubing Parameters
	tubeDiameter = ["2.0", "1.875", "1.75", "1.675", "1.5", "1.25", "1.0", "0.875",  "0.75", "0.675", "0.5"]
	wallThickness = ["0.035", "0.049", "0.065", "0.083", "0.095", "0.120", "0.156", "0.188", "0.250"]
	tubeDiameter = rs.ListBox(tubeDiameter, "Choose Tube Diameter", default = "2.0", title = "DOM Tubing")
	wallThickness = rs.ListBox(wallThickness, "Choose Wall Thickness", default = "0.095", title = "DOM Tubing")
    	
	tubeDiameterIndex = tubeDiameter.index(tubeDiameter)
	wallThicknessIndex = wallThickness.index(wallThickness)
	
	
        for crv in crvID:
			curve = rs.coercecurve(crv)
			rs.UnselectAllObjects()
			rs.SelectObject(curve)
			layer = rs.ObjectLayer(curve)
			Rhino.Geometry.Brep.CreatePipe(curve,(0.0,1.0),(tubeDiameterIndex,tubeDiameterIndex),True,0,False,tol,aTol)
        print "Tubes Created"

createTube()

I’m sure I have messed the script up royally by now trying to fix it, but any tips on how to do this more efficiently would be appreciated. Thank you.

Carl


#2

Well, a method for creating wallthickness hollow pipes is not exposed in RhinoCommon yet, so all that can be currently made with either python rhinoscriptsyntax or RhinoCommon is solid pipes. This method is already exposed for (vb) Rhinoscript in V5, so there is definite hope that it will be there in Python when Rhino V6 hits the market…

There are a couple of possible workarounds for V5 currently -

  1. using rhinoscriptsyntax, script the creation of both inner and outer pipe diameters, add two planar surfaces for the end caps and join all together

  2. script the Rhino Pipe command with does have command line options for creating thick pipes.

If you want, I can try hacking away at one or the other in a bit…

–Mitch


#3

Thanks for the reply.

I do want to learn a bit more about this, so maybe instead of creating a proper pipe command, I can try just a solid one for now since that’s all that Rhino supports. If that’s the case, I still have the failure when going from Guid to object which I need help with.

Alternatively, I could create a script that creates 2 pipes, one with the correct outer diameter, and one with the correct inner diameter, and does a boolean between the 2, but might get messy near the ends.

Another method would be to create the circles of appropriate diameters, align to the end of the curve, and sweep them along the curve creating a pipe.


#4

I would not recommend Boolean operations because they might take longer to execute and might be less reliable…

Yes, also a way to do this. I suggested using the AddPipe() method as it allows you to create open pipes and then you can fill in the ends with planar surfaces - it is a bit tricky to get the end curves, but doable.

I will toss up a multi solid pipe script here as an example in a bit - I see I don’t actually have one in my library…

Edit: something like this maybe…

import rhinoscriptsyntax as rs

#encapsulate in function definition to ensure graceful exit if user bails out
def TestMultiPipe():
    crvIDs = rs.GetObjects("Choose Curves to Create Tubing From", 4, preselect=True)
    #if no curves chosen, exit
    if not crvIDs: return
    # Tubing Parameters
    dia_list=["2.0","1.875","1.75","1.675","1.5","1.25","1.0","0.875", "0.75","0.675","0.5"]
    resp=rs.ListBox(dia_list, "Choose Tube Diameter", default = "2.0", title = "DOM Tubing")
    #if no response from listbox, exit
    if not resp: return
    #the return from the listbox will be a string, need to convert to a float (double)
    tube_dia=float(resp)
    #counter
    pipes_created=0
    #main loop
    for crv in crvIDs:
        #get parameter of curve start and end
        dom_start,dom_end=rs.CurveDomain(crv)
        #simple case for one single diameter of pipe
        pipe=rs.AddPipe(crv,dom_start,tube_dia/2.0,0,1,False)
        #increment counter if pipe got made
        if pipe: pipes_created +=1
    print "{} Tubes Created".format(pipes_created)
TestMultiPipe()

–Mitch


#5

And here is a quickie hackie version of a multi hollow tube script using your listboxes:

import rhinoscriptsyntax as rs

def TestMultiHollowPipe():
    crvIDs = rs.GetObjects("Choose Curves to Create Tubing From", 4, preselect=True)
    if not crvIDs: return
    # Tubing Parameters
    dia_list=["2.0","1.875","1.75","1.675","1.5","1.25","1.0","0.875", "0.75","0.675","0.5"]
    thk_list=["0.035", "0.049", "0.065", "0.083", "0.095", "0.120", "0.156", "0.188", "0.250"]
    resp=rs.ListBox(dia_list, "Choose Tube Diameter", default = "2.0", title = "DOM Tubing")
    if not resp: return
    tube_rad_outer=float(resp)*0.5
    resp=rs.ListBox(thk_list, "Wall thickness?", default = "2.0", title = "DOM Tubing")
    if not resp: return
    tube_rad_inner=tube_rad_outer-(2*float(resp))
    
    #main loop
    pipes_created=0
    rs.EnableRedraw(False)
    for crv in crvIDs:
        dom_start,dom_end=rs.CurveDomain(crv)
        outer_pipe=rs.AddPipe(crv,dom_start,tube_rad_outer,0,0,False)
        inner_pipe=rs.AddPipe(crv,dom_start,tube_rad_inner,0,0,False)
        bord_0=rs.DuplicateSurfaceBorder(outer_pipe)
        bord_1=rs.DuplicateSurfaceBorder(inner_pipe)
        ec_0=rs.AddPlanarSrf([bord_0[0],bord_1[0]])
        ec_1=rs.AddPlanarSrf([bord_0[1],bord_1[1]])
        h_pipe=rs.JoinSurfaces([outer_pipe,inner_pipe,ec_0,ec_1],True)
        rs.DeleteObjects(bord_0)
        rs.DeleteObjects(bord_1)
        #increment counter if pipe got made
        if h_pipe: pipes_created +=1
    print "{} Tubes Created".format(pipes_created)
TestMultiHollowPipe()

(I did not do any real error checking here, and there are definitely some more elegant ways to do this…)

HTH, --Mitch


#6

@carljarrett,

below is another one using the wall thickness…

ThicknessTubes.py (2.7 KB)

some notes: you might just create floats and pass them to the list boxes. It looks like it does the conversion, so you can use the values directly later in your script. Below lines made no sense to me:

tubeDiameterIndex = tubeDiameter.index(tubeDiameter)
wallThicknessIndex = wallThickness.index(wallThickness)

The ListBox returns the selected item, there is no need to get the index again to obtain the value. Also it might be a good idea to add some error checking to your script. In my example above, a final tube is only added if there are no errors for the current curve, eg. closed ones.

Also note that in difference to the example above from Mitch, only the final tube is added to the doc. Apart from this, the technique is the same.

c.


#7

That’s great thank you. The index was taken from another script, when I was trying to get mine to work, ust left it in I guess.

Give me some time tonight and I’ll review yours and Mitch’s! Thanks again, will be a big help and help me learn as well.

Carl


#8

@clement Thanks for putting up the clean variation, my version above was just a quick 10 minute hack before I had to pack up my stuff and get on a plane. I was planning on re-doing it properly this morning, but you beat me to it… :grinning:

–Mitch


#9

Works very well thanks. I’m dissecting it to figure out how it works. This section:

outer_radii = System.Array.CreateInstance(float, 1)

Basically you’re converting the listbox value output from a string into a float, correct?


#10

Hi Carl, no it is a float already as the list of values passed to the listbox was changed to floats instead of strings. (See my first reply). The line creates an empy array of floats with one value, then in the next line, i am assigning the actual float value to the first item in the array:

 outer_radii = System.Array.CreateInstance(float, 1)
 outer_radii[0] = diameter * 0.5

Since your pipes are having a constant radius along the curve, a single curve parameter and a single radius value seems to be enough, so you could pass the param and the radius as a single float value too.


@stevebaer, the bad thing i think is that the second version of

Rhino.Geometry.Brep.CreatePipe()

method needs multiple params and radii to be filled in with a

System.Collections.Generic.IEnumerable(Double)

I mean this is not required in the script above, but just in case of a pipe radius which changes along the curve, the CreatePipe method should accept a list of parameters and radii without doing the conversion from a list of floats to an array of floats.

c.


(Steve Baer) #11

I’m surprised it doesn’t; a python list of floats should work for an IEnumerable parameter


#12

Thanks @stevebaer, today i am even more surprised as it now accepts my lists with a single float value for the parameter and radius :blush:

@carljarrett, here is an updated version without using the double > float conversion:

ThicknessTubes.py (2.5 KB)

btw. i re-checked, the type of the value returned from rs.ListBox() is float, even that the python helpfile mentions that the return value is a string.

c.


#13

Bizarre, when I was doing mine and I set a breakpoint and looked at the return, it was a string…


#14

Mitch, your dia_list contains strings. In my version, i changed the list content to floats. I made the ListBox() default value a float as well, otherwise it did not work.

c.


#15

Aha! I see the difference now. Thank you.

This is working well, I tried to make a change to the script, so it would perform it’s actions in decimal inches as the units, and then revert back to the original units the scene was in. It didn’t seem to work.

At the beginning we have:

unitSystem = rs.UnitSystem(8, True, True)

Which allows me to set it to inches. What I tried to do was add a new line which captured the current units of the scene:

originalUnits = rs.UnitSystem()

Then at the end of the script perform change back to the original units:

rs.UnitSystem() = originalUnits

I know this is an ignorant approach, but all of the searching I’ve done I couldn’t find any way to temporarily work in a certain unit system or make determinations of what list values are in inches such as:L

tubeDiameter = [2.0in, 1.75in, etc…

Thanks,
Carl