Draw tangent circle for each arc within polycurve

I have a drawing made of many polylines with arcs. I need to draw circles that are tangent to each arc in the polylines. Doing this manually, I am drawing each circle by hovering by each arc, using the center snap command to draw the center of the circle and then the perp snap to bring the edge tangent to the line at that point.

This is taking forever and I’m hoping to write a script to iterate through each arc for each polyline. It’s been a few years since I scripted, so I’m a bit rusty on the functions. Thank you so much for any help!

Here is some pseudocode with the steps I think this will require

#Select polylines
id = rs.GetObject(“Select Polylines”)
#Identify arcs on polylines
#For each arc, find ArcCenterPoint
#For each center point, draw a circle at this point with the edge at the point perp to that arc

Hi Noami, if all the arcs are in the active construction plane, this should work in a Grasshopper Python component:

import Rhino
import rhinoscriptsyntax as rs
import scriptcontext as sc

try:
    sc.doc = Rhino.RhinoDoc.ActiveDoc
    objs = rs.ObjectsByType(4)
    
    for obj in objs:
        if rs.IsArc(obj):
            center = rs.ArcCenterPoint(obj)
            radius = rs.ArcRadius(obj)
            rs.AddCircle(center, radius)
            # relies on "active construction plane"
finally:
    sc.doc = ghdoc

Hi James,

Thank you so much for this. I haven’t used Grasshopper Python components before. Do I need to implement the script in Grasshopper or will it execute in Rhino without the additional integration?

You’re welcome. It can implemented in Grasshopper, but it needn’t be. It’s simpler to take out the try/finally and sc.doc and just use Rhino Python:

import Rhino
import rhinoscriptsyntax as rs

objs = rs.ObjectsByType(4)

for obj in objs:
    if rs.IsArc(obj):
        center = rs.ArcCenterPoint(obj)
        radius = rs.ArcRadius(obj)
        rs.AddCircle(center, radius)
        # relies on "active construction plane"

This is so helpful, thanks! I tried to implement it, but think I have an issue because my objects are polylines made of arcs, but not arcs themselves. The IsArc() operation is false for all of my lines, but IsPolyCurve() is true.

Do you know how to identify each arc making up the polyline, and then execute the remaining code from there?

1 Like

Ah right. Polylines are fine, so e.g. if you want a circle through the vertices of a polyline, there’s a circle from three points function that should do it easily (then you don’t ned to worry about the normal or plane).

But I’ve not used Polycurves, so if you want to sort of do something else, e.g. circumscribe the inside of a polyline, then I’m not sure how that geometry has a unique solution, so I need a more precise definition

Ah I see. They are kind of on the vertex, except I’m using the arc function of polyline to build the curve, not lines.

I’ve been able to use PolyCurveCount which is identifying all of the curves making up the polycurve.

Now, I’m not sure how to iterate through each of these to find the arc center point of each curve.

Well, this might be a bit advanced, but… a little RhinoCommon is sometimes helpful.

import rhinoscriptsyntax as rs
import scriptcontext as sc
import Rhino

def AddCirclesToPolyCurve():
    obj_ids=rs.GetObjects("Select polycurves to process",4,preselect=True)
    if not obj_ids: return
    
    for obj_id in obj_ids:
        #get the RhinoCommon curve object geometry
        crv=rs.coercecurve(obj_id)
        #find all the subsegments
        segs=crv.DuplicateSegments()
        #loop and check each segment to see if it is an arc curve
        for seg in segs:
            if isinstance(seg,Rhino.Geometry.ArcCurve):
                #segment is an arc curve, get underlying arc plane and radius
                radius=seg.Arc.Radius
                plane=seg.Arc.Plane
                #make new circles with arc data
                circle=Rhino.Geometry.Circle(plane,radius)
                #add the circles to the document
                sc.doc.Objects.AddCircle(circle)
        sc.doc.Views.Redraw()
AddCirclesToPolyCurve()

Just in case, here is a rhinoscriptsyntax-only version which does not need any knowledge of RhinoCommon. Only difference is the segments are first duplicated and added to the document, then deleted at the end, which could take slightly longer if there are thousands, otherwise you probably won’t notice the difference.

import rhinoscriptsyntax as rs

def AddCirclesToPolyCurve():
    obj_ids=rs.GetObjects("Select polycurves to process",4,preselect=True)
    if not obj_ids: return
    
    rs.EnableRedraw(False)
    for obj_id in obj_ids:
        seg_ids=rs.ExplodeCurves(obj_id) #makes a copy, doesn't delete original
        for seg_id in seg_ids:
            if rs.IsArc(seg_id):
                #segment is an arc curve
                radius=rs.ArcRadius(seg_id)
                plane=rs.CurvePlane(seg_id)
                #make new circles with arc data
                circle_id=rs.AddCircle(plane,radius)
        #delete the copied segments after
        rs.DeleteObjects(seg_ids)

AddCirclesToPolyCurve()