Filleting Tangent Surfaces

For those Rhino users who use the FilletSrf command and would like the process to be a little less tedious here is a Python script that will make strings of fillets that expands FilletSrf capability when filleting tangent surfaces: (40.1 KB)

This script works the same as the filletsrf command - just pick 2 surfaces that you want to connect by a fillet. The difference is the script will continue to make all the tangent fillets connected to the first fillet until it runs out of tangent surfaces.

The best strategy for making lots of fillets quickly is to create two sets of tangent surfaces that you wish to connect with fillets.
The script only makes the string of tangent fillets, its up to the user to then follow up with the necessary trimming and joining. As long as the base surfaces are tangent the fillets will join. Often the joined fillet string can be used as the cutter to trim the base surfaces.

The enclosed file shows several examples that can be filleted with just 2 clicks of the mouse.:fillsrf_examples.3dm (1.0 MB)

Most of the models in the above file were posted to this forum by Rhino users complaining that Filletedge failed to make the fillets correctly. The two sets of tangent surfaces In each example have different colors to indicate the two sets of surfaces that can be connected by a string of round fillets. In all of these examples 1mm fillet will work. Other Fillets radii will also work but there are limits to how big or small a radius any particular topology will support. In most of the examples after you make the string of fillets you can join them and then trim the base surfaces using the string of fillets as the cutter.

This script doesn’t do anything that you can’t do yourself without it. It does it 1000 times faster.


fantastic. nice work. congratulations

just to link to other fillet-topics:

for sure @Joshua_Kennedy will like above approach.

I always dreamt of some interactive way to overcome the weakness of filletEdge - for example to precisely end the rails at one tangent point. “pointy fillet”.
I miss a command for selecting naked Edges - or an option for _selChain to only select naked Edges
(would be great for your trimming case)…

thanks for sharing the script.

-kind regards -tom


This is a great plug-in that should have been included as a native tool in Rhino! I shared your plug-in in some Facebook pages and forums to make it more popular across the Rhino community. I also made a short overview video on YouTube. It’s a truly remarkable job from you! Thanks for the effort!

P.S.: The red colour (RGB: 255, 99, 71) you choose is spot on! Very easy for the eyes, just the right amount of saturation.


Cool ! :+1:

But, to be precise, I wouldn’t have mentioned edges.
Af far as I understand, it works on surfaces.
Edges are not required, nor are they (when present) related in any way to the fillet surfaces built by the script. :slight_smile:

Sure !


Good point. Not sure why I wrote edges instead. Maybe because it creates fillet edges. :rofl:


I ask Rhino developers: does it take that long to make a tool like this?


Here is a version of the script that produces the edge curves. (40.4 KB)

The crvs are not joined. So to trim side A you can run this macro:
selnone -selname “sidecrvA*” pause join enter trim

substitute “sidecrvB*” for trimming side B.

I find that usually trimming with the fillet surfaces themselves is the most reliable way to trim and join using this macro:
-selname “fillet*” pause join enter trim

I would try trimming with the fillet surfaces before trying to trim with curves.

I noticed you were getting the “Gap” text dot on some edges between fillets. That indicates the underlying surfaces were not precisely tangent. You can usually fix the gap with this macro for matching.

-matchsrf pause pause Mode=Position PreserveOtherEnd=Tangency MatchByClosestPoints=No
RefineMatch=No AverageSurfaces=Yes IsocurveDirection=Keep enter

Also the textdots have the name “check”. I use this macro:

! selnone
-selname “check”
pause delete
-RunPythonScript “[Your File Path]\”

That clears out any Gap marks from the previous fillet when making a new fillet string.


From my experience I get the best results by splitting the surfaces with surface edges. I use the following macro for that purpose:
! _Split _Pause _Curve

I prefer that one over using surfaces, because sometimes Rhino will produce incorrect splitting of a surface by another tangent surface (either a fillet or a surface matched to another surface with the “OnSurface=Yes” option).


Why not use Trim command instead of split?
Deleting the part you don’t want after splitting is just an extra step…

Yes absolutely, splitting using any other type of Rhino tangent surface is hopeless.
We are talking about true arc radius fillets. You need to understand how much more accurate a true fillet is than ordinary tangent surfaces.

Also we may not be talking about the same version of Rhino.
I’m still using Rhino6 because Rhino7 has lots of visible problems with edge definitions of joined surfaces.

All I can tell you is for versions prior to Rhino7 trimming the base surfaces using the fillet is a more reliable way to trim and join. I’ve done lots of testing to reach that conclusion. From what little experience I have with version 7 trimming with the surface still seems to work better, but feel free to post examples where that is not true.

Ultimately, the real issue for most Rhino users is how well the surfaces join after splitting and trimming. Joining things into water tight solids can be a nightmare if the boundary definitions get screwed up by whatever technique you use to get to the point of joining. Also, many Rhino users need to export their models (I do) and that also can be a nightmare if you don’t get the boundary definitions right.


I prefer to split instead of trim, because sometimes I need both halves of the model. Also, trimming may lead to an unwanted removal of the incorrect part of the model due to issues of Rhino to understand which object is closer to the camera, especially if multiple surfaces meet there (I often use rebuilt duplicates, extended duplicates or partially trimmed duplicates that I want to further split in some area). I had cases where I trimmed some models that should not and lost them in the process. Splitting requires preselection of the surface or polysurface to be split, so it’s the safer method for my workflow.
I’m aware that I ca create new layers and place each new duplicate there and hide it or lock it, however, that takes much more time than just hitting the Delete key. :slight_smile:

Also, in many occasions trimming of surfaces and especially polysurfaces is impossible even while using precise arc fillets. Using edges or duplicated border solves the problem.

As for joining of the surfaces, I use 0,001 mm and 0,1 degrees as the default file tolerance, which gives me pretty much great results in 99% of the time. I often export models that would be used by other people or companies in different CAD programs, so my tight tolerances guarantee watertight models when converted to another file format. I noticed that the scene provided by you in the original post is set to 1 degree tolerance, but even that produces .

By the way, is it possible to make your plug-in so that the output fillets have their isocurves hidden by default? Despite that my custom template file is set to hide the isocuves of newly created objects, the only times I see those and I’m forced to manually change the settings for them is either when I create a text object (surfaces or solids) or surface fillets with your plug-in. ! _TextObject in Rhino 7 bring that bug since the very beginning and it’s still not resolved.

And another question. Could your plug-in be made so that the resulting fillet surfaces get joined together or at least put into a common group? Currently, I have to use '_SelLast and ! _Join or '_SelLast and ! _Group to do so. If you are going to expand the functionality of this plug-in with some Command line or floating window options, I would love to see: “Join” and “Group” (not joined) options to choose from. something like what the ! _TextObject command offers.


Great to see that in rhino! :ok_hand:
Now what is needed in this command is the option to connect properly the edge ends of the fillet. Like that:

In many cases, there would be many less mouse clicks to finish the model.

1 Like

I like Trim because it allows preselection of the cutter. I use this macro to trim the side surfaces:
selnone -selname “fillet*” pause join enter trim

Try it, you may find it works a lot better than you think.

The advantage of trimming with the fillet surfaces is that when it does work and then you join the fillets to the side surfaces, you can be sure you haven’t introduced any inaccuracy.

When you trim with curves the trimming may work fine, but the trimmed edges may be out-of-tolerance. A curve doesn’t have to be within tolerance of a surface for the trimming or splitting to succeed.

That is good. That is the tolerance I use also. I don’t believe the angle tolerance has anything to do with making fillets or trimming and joining surfaces. Angle tolerance is used very little. The only thing I can think of is the Gcon command.

I don’t think so. If you have new objects set to isocurves off and Rhino is making new objects with isocurves turned on that sounds like a bug that McNeel should fix.

I avoid doing that because the fillet string can have small gaps. The gaps are almost always the result of poor edge continuity of the surfaces being filleted.
The tiny gaps are also going to be what may cause problems with trimming and joining.
What I’m saying is if the fillets don’t join its almost always the fault of the geometry to which the fillets are applied. So if you want the fillets joined its your mess you join them and if that fails its not my fault.

What I should do is turn the script into a Rhp file. That will allow you to run the script inside your own macro that will do the joining or grouping or whatever else you want to do with them. So far, I have not explored what might be involved in doing that.


Yes it would not be too difficult to add code that would extend the ends of a fillet string that is not a closed loop. I just haven’t worked out all the logistics of doing that.

In a situation like your picture often there will come another fillet later that wraps around that one and that trims off the end.


Yes, for that reason I proposed a “Group” option along with “Join”, because the former will keep the newly created fillets as individual surfaces.

Does it work on Rhino 6?

1 Like

Yes, this python script was written for Rhino 6.
The real question is how well does it work in Rhino7. From what I have observed the edge and vertex definitions are pretty screwed up in Rhino7 and the WIP8. It seems to me that those new edge definitions are bound to cause errors that don’t exist in previous versions.

The example file I posted earlier is a Rhino6 file: fillsrf_examples.3dm (1.0 MB)
As far as I can tell Rhino7 and 8 make very close to the same fillets on these models as Rh6 does, but I don’t know how well it will perform on models created in Rh7 and Rh8. Maybe there will be some Rhino7 user feedback on that question.

Yes I understand what want to do.

The way I look at it you should be able to use a macro (on a button or alias) that goes something like this:
! selnone -selname “check” pause delete
-RunPythonScript “[put your File Path here]\Test\” _MultiPause
_selnone -selname “fillet*” group
selnone -selname “sidecrvA*” pause -selname “sidecrvB*” pause
join enter

But that doesn’t work because Rhino thinks the last lines of the macro is the user attempt at input for the script.
I think that is a bug. At the very least the _MultiPause command should prevent the macro from proceeding to the next line until the RunPythonScript command is finished.

IMO this is a bug but I imagine McNeel will claim it is done by design for unfathomable reasons.

So for now you will need to create a different button or alias that has whatever macro you want to run after the Runscript completes and that will add one unnecessary step to the process. .


I also noticed that macros could be added before a script, not not after it. This is pity, because so many scrips could benefit from some extra macro… :slight_smile:

1 Like

great video, you can trim by a surface edge as crv input without duplicating the borders, simply type CRV in the command line when asked for trim input.

you can also double click an edge to select a chain.


I use both of the methods you mentioned above, this is why I made the macro I mentioned in post #8 (! _Split _Pause _Curve), which I use most often from splitting.
Couple of years ago I also made a dedicated topic with a request for the hidden options “crv” and “srf” to be finally made visible. :slight_smile:


Even faster if you use sub object select on the surface edge!