Help with curve for Curve.CreateFilletCurves

Hi,
I am trying to fillet some specified (not user selected) lines. I have a problem generating a “curve” reference, not a guid. This is based on the rhino common fillet example

Highlight of the problem is:

  1. Curve1Guid = rs.AddLine( pt1, pt2)
  2. curve1Obj = Rhino.DocObjects.ObjRef(Curve1Guid)
  3. curve1 = rs.coercecurve(Curve1Guid)
  4. curve1_point = rs.CurveMidPoint( Curve1Guid)
  5. (duplicate this for 2nd line)
  6. fillet_curve = Curve.CreateFilletCurves(Curve1Guid, curve1_point, Curve2Guid, curve2_point, Fradius,True, True, True, doc.ModelAbsoluteTolerance, doc.ModelAngleToleranceDegrees)
  • using 1st/3rd paramater of Curve1Guid => Message: expected Curve, got Guid
  • using 1st/3rd paramater of curve1Obj => Message: expected Curve, got ObjRef
  • using 1st/3rd paramater of curve1 => Message: expected Curve, got float

fillet lines.py (4.5 KB)

Here is the code with correct curves being passed. This works except that the lines should be trimmed:

fillet lines 2.py (2.5 KB)

Thanks for any help,

.CreateFilletCurves takes curve geometry, not guids. If I change your code to take curve1 (curve geo) and curve2 (not sure), then I get your 3rd error message, because curve2 is 0.0.

I’m not sure what you are trying to get with this:

curve2Obj =  Rhino.DocObjects.ObjRef(Curve2Guid)
a,curve2 = curve2Obj.CurveParameter()

but you are assigning a, curve2 to:

(<Rhino.Geometry.LineCurve object at 0x00000000000000AA [Rhino.Geometry.LineCurve]>, 0.0)

so indeed you are assigning curve2 to 0.0.

If I put curve2 = rs.coercecurve(Curve2Guid), like you did with curve1, then that part of that call runs.

If I comment out the other stuff that throws exceptions then rhino builds:

image

I’m also not sure what you are trying to return to your message boxes.

Hope that helps.

Hi Nathan,
Thanks for the help. Glad that it was silly coding error and my confusion over obj, guid and curve.

  1. How do you get the debug information that you quoted?
  2. My message boxes were trying to confirm the success creation of fillet. createfillet returns curves, not guid. How do i get the guid of the result?

After making sure i pass the geometry, it does indeed work and generate the image you have. Your result is almost what i want.

The change i want is to have the straight lines trimmed and only have the rounded corner. this should be the 2nd of 3 booleans), but changing the parameter does not change the result. I am using rhinoV5 if that makes a difference.

In the built-in editor, if you set a breakpoint - click in the vertical gray bar next to the line number, a red dot will appear - when you run the script, it will stop at the breakpoint and all the current variable values will be displayed in the lower pane. You can drill down into any one of them. It’s extremely useful.

GUIDs only exist for objects that are in the document. Rhinoscript methods mostly work on GUIDS, that is to say they reference existing objects in the document and either modify or create/add new ones.

RhinoCommon works on “virtual” geometry - objects that do not exist in the document, and therefore do not have a GUID. To get a GUID, you have to add the RhinoCommon object(s) to the document using the various Add… methods, they will return a GUID.

To reference the various objects in the active document, it’s easiest to use the scriptcontext module (often imported as sc). For example to find an object for which you have the GUID, you can query the object table with
sc.doc.Objects.Find(GUID)
which is the equivalent of
Rhino.DocObjects.Tables.ObjectTable.Find(Guid) for the active document

To add an object back to the document and return a GUID, there are object-type specific methods, for example to add a RhinoCommon curve object it wold be:
guid=sc.doc.Objects.AddCurve(crv_obj)
which is the equivalent of
Rhino.DocObjects.Tables.ObjectTable.AddCurve(crv_obj) for the active document

HTH, --Mitch

Helvetosaur:
click in the vertical gray bar next to the line number, a red dot will appear

Aha on the debugging breakpoints. This is very helpful and saves trying to do this all with print and message boxes.

Can you do any variable manipulation? simple math / or rhino call like say AddPoint( new coords).

Helvetosaur:
RhinoCommon works on “virtual” geometry

This explanation helps clear up why functions are returning curves and not GUIDs.

Remaining Question:
fillet_curve = Curve.CreateFilletCurves(curve1, curve1_point, curve2, curve2_point, Fradius,join, trimboolean, arcExtension, doc.ModelAbsoluteTolerance, doc.ModelAngleToleranceDegrees)

The change i want is to have the straight lines trimmed and only have the rounded corner. this should be the 2nd of 3 booleans), but changing the trimboolean parameter does not change the result.

No, not in the debugger… So I usually add a line of code just before to do those things - if you assign the result to a variable, it will be visible in the debugger.

Don’t know why this isn’t working, will try to create a quick example and check here.

The following seems to work on the two lines in the file below:

import rhinoscriptsyntax as rs
import scriptcontext as sc
import Rhino.Geometry as rg

def TestFilletCurves():
    #see rhinoscriptsyntax help for what GetCurveObject() returns
    crvd0=rs.GetCurveObject("Pick first curve near end to fillet")
    crvd1=rs.GetCurveObject("Pick second curve near end to fillet")
    if not crvd0 or not crvd1: return
    
    #get RhinoCommon geometry for curves to fillet
    c0=rs.coercecurve(crvd0[0])
    c1=rs.coercecurve(crvd1[0])
    #these are the pick points from GetCurveObject()
    p0=crvd0[3]
    p1=crvd1[3]
    
    #params
    rad=10.0
    tol=sc.doc.ModelAbsoluteTolerance
    atol=sc.doc.ModelAngleToleranceRadians
    #run the method
    result=rg.Curve.CreateFilletCurves(c0,p0,c1,p1,rad,False,True,False,tol,atol)
    if result:
        #should be a list of 3 curves, the two trimmed lines and the fillet
        #add all three to the document
        for crv in result:
            sc.doc.Objects.AddCurve(crv)
        #delete the two original lines
        rs.DeleteObjects([crvd0[0],crvd1[0]])
        sc.doc.Views.Redraw()
TestFilletCurves()

FilletCurves.3dm (304.3 KB)

Ah, so the trim parameter does not remove the lines from current document, just in the virtual rhinoCommon.

Answers:

  1. For quick things such as this I just usually print things to see what they are.

  2. As Helvetosaur said, you don’t get a guid until they are added to the document. I think understanding how to transition from doc to geometry (rhinocommon) and back is one of the trickiest aspects of working with Python and Rhino. Generally, the rhinoscript functions work with guids, and they kind of hide the geometry parts. A good way to learn about it is to look at the rhinoscript source and see what they do.

I rarely use rhinoscript to do any geometry calculations or generation. I use it quite a bit for input/interaction and coercion down to the geometry layer, but then I stay there until done, then bring back what I want into the document.

Back to your questions though:

The lines are showing up because they are being added to the doc in the drawline function:

def drawline(x1,y1,z1,x2,y2,z2): 
    pt1 = (x1,y1,z1)
    pt2 = (x2,y2,z2)
    if pt1 == pt2:
        rs.MessageBox("Line ends are equal: " + str(x) +", "+ str(y) +", "+ str(z) )
        guid = None
    else:
       guid = rs.AddLine( pt1, pt2)  <- this adds the lines to the document
    return guid

Like Helvetosaur said, you probably want to use ‘virtual’ lines here and return the geometry, something like (untested):

def make_line(x1, y1, z1, x2, y2, z2):
    start = Rhino.Geometry.Point3d(x1, y1, z1)
    end = Rhino.Geometry.Point3d(x2, y2, z2)
    line = Rhino.Geometry.LineCurve(start, end)
    return line

For the message box, get the guid(s) when you add them to the doc here:

doc.Objects.AddCurve(fillet_curve[0])

This returns the guid:

And return them. If you want all 3 pieces of the fillet, then you have to process the returned list of curves.

I haven’t done much filleting in code so I explored the CreateFilletCurves function a little:

import Rhino
import rhinoscriptsyntax as rs
import scriptcontext as sc


# get some curves
guid1 = rs.GetObject('curve 1')
guid2 = rs.GetObject('curve 2')

# check
print (guid1, guid2)

# get curve geo
geo1 = rs.coercegeometry(guid1)
geo2 = rs.coercegeometry(guid2)

# check
print (geo1, geo2)

# get points on curves
geo1_point = geo1.PointAtNormalizedLength(1.0)
geo2_point = geo2.PointAtNormalizedLength(0.0)

# check
print (geo1_point)
print (geo2_point)

# add points to doc to see if they are on the correct sides of the curves
sc.doc.Objects.AddPoint(geo1_point)
sc.doc.Objects.AddPoint(geo2_point)

# try the CreateFilletCurves function with hard coded radius
fillet_curve_array = Rhino.Geometry.Curve.CreateFilletCurves(geo1, 
                                                             geo1_point, 
                                                             geo2, 
                                                             geo2_point, 
                                                             2, 
                                                             False, 
                                                             True, 
                                                             True, 
                                                             sc.doc.ModelAbsoluteTolerance,
                                                             sc.doc.ModelAngleToleranceDegrees
                                                             )

# check what it gives you
print(fillet_curve_array)

# add cuves to doc, keeping their returned guids
guids = []
for c in fillet_curve_array:
    curve_guid = sc.doc.Objects.AddCurve(c)
    guids.append(curve_guid)
    
# print the guids
print(guids)

Changing the Join param and Boolean seemed to work as expected. Join=False, Boolean=True example:

image

Which I think is what you are after?

Thanks, you have answered my questions so i can add fillet (and remove the old lines) and i now understand some of the rhinoCommon vs document issues. I am sure more will come up in the future.

I understand the outlined process. It is not clear why i would want to add virtual lines, and then transfer them to my document.

Correct. In RhinoCommon, you are working with pure virtual geometry which no longer has any reference to objects in the document itself. The advantage here is that you don’t add any unneeded geometry to the document during intermediate stages, only what you really want to keep at the end. Reading from and writing to the document is slow, and if the user bails on the script somewhere in the middle, you don’t need to clean up any unneeded objects you might have left behind.

I think I probably don’t understand what you want drawn as the end result. I was assuming you just wanted the fillet parts in the document, but if you want to draw all the lines then rs.AddLine works great.

Nathan, i am adding lines to the document and only a few of them will have fillets.

It seems the right way for my process would probably be to:

  1. add line2 as virtual line,
  2. fillet if needed, (because when adding line 2: line 1 is already created and i know whether to use a fillet to join.)
  3. then add the resulting curve to the document