Trouble with creating silhouette outlines of solids with Python

I’ve had a lot of help in the past (thanks mainly to Helvetosaur) in writing a script which splits a solid into layers of constant thickness. Then it creates a silhouette outline on each layer from which I derive an offset outline (used for CNC machining the final solid when it’s all put back together). I’ve used this a lot, and it sometimes has trouble getting the silhouette for some shapes. But the latest solid I’m using it seems to fail with every layer. I don’t know if the shape is too complex, but there’s no benefit in using the script if it fails for all layers. And when it works, it’s wonderful and saves lots of time. I’ll copy the script in and the solid I’m using to see if anyone can help point out a way to make this more reliable. There’s a bit of other stuff going on in the script, but it’s the CreateOffsetOutlines which fails (it needs to be run taking the slices from the Top View as that’s what the machine and I do.

Thanks, Ben
Combined Slices and Outline.py (4.2 KB)
Test Model.3dm (5.3 MB)

I ran just the CreateOffsetOutlines routine on your object and stopped after the creation of all the silhouette curves but before it got to the CreateBooleanRegions part; I added the silhouette curves to the document to see what you were getting as input to CreateBooleanRegions

This is what I see:

Note the lower right hand corner:

Part of the silhouette is missing there, therefore CreateBooleanRegions can’t find a complete outer region. This is odd because the native Rhino Silhouette command does find the complete outer outline… So something is either buggy in the Silhouette.Compute()... for this object, or maybe some other problem… Will look a bit further.

Edit:
I cannot get it to work with RhinoCommon Silhouette.Compute(), no matter what options I tried, it still leaves that one corner out. To test I re-wrote the routine using rs.Command(“_Silhouette”) and that works… I don’t know what else to do at this point, I guess a bug report needs to be written up.

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

def CreateOffsetOutlineView(ObjectID,OffsetDistance):
    rs.EnableRedraw(False)
    #store current view
    prev_view=rs.CurrentView()
    #set top view for Silhouette command
    rs.CurrentView("Top")
    rs.UnselectAllObjects()
    rs.SelectObject(ObjectID)
    rs.Command("_Silhouette")
    lco=rs.LastCreatedObjects()
    if lco:
        xform=rs.XformPlanarProjection(rg.Plane.WorldXY)
        crv_ids=rs.TransformObjects(lco,xform)
        if not crv_ids:
            rs.DeleteObjects(lco)
            return
            
    tol=scriptcontext.doc.ModelAbsoluteTolerance
    atol=scriptcontext.doc.ModelAngleToleranceRadians
        
    crvs=[rs.coercecurve(crv_id) for crv_id in crv_ids]
    rs.DeleteObjects(crv_ids)
    regions = rg.Curve.CreateBooleanRegions(crvs,rg.Plane.WorldXY,True,tol)
    a = regions.RegionCurves(0)
    outline_id=scriptcontext.doc.Objects.AddCurve(a[0])
    
    #restore previous current view
    rs.CurrentView(prev_view)
    
    if outline_id:
        wz_vec=Rhino.Geometry.Plane.WorldXY.ZAxis
        offset_id=rs.OffsetCurve(outline_id,[4000,4000,0],OffsetDistance,wz_vec)
        rs.DeleteObject(outline_id)
        if offset_id: return offset_id


obj_id=rs.GetObject("Select volume for offset outline",8+16,preselect=True)
test=CreateOffsetOutlineView(obj_id,10)
print test
1 Like

Thanks. I’ll put that in and see what happens here. Incidentally, when I run that model with 100mm slices, the outlines it comes up with are way off and bizarre (though it works). 50mm slices crashes it and that’s what I need to do at the moment. I’ll try with your new code (it is such a comfort that there are people like you who really know their way around these quite esoteric areas!).

Thanks again