Script to toggle all surface normals outward?

We are developing a plug-in for Autodesk PowerMill to achieve fully autonomous CAM programming launched from Rhino. To succeed with autonomous 5-axis programming we need to make sure all the surface normals are facing outward in our models. The nature of our product dictates that many models are surface files and not closed polysurfaces. Has anyone written a script that toggles all surface normals outward? It’s on my to-do list, but I thought I would reach out to the Rhino community first and see if this already exists, or if anyone has suggestions on the best way to approach this.

Thanks in advance,


When the model, like the one here Cplane inconsistencies - #9 by DanBayn
can close into a solid, Brep.JoinBreps will orient the face normals outward.

Yes, but that model was a simplistic example of what I’m trying to do. Our typical models are much more complex and we can’t take the time to make sure they all will be closed polysurfaces. We process close to 90,000 unique CNC details a year. That’s why succeeding at full autonomous CAM programming is going to be such a game changer. But to automate 5-axis programming we need to control normal directions. We’ve always toggled them in the CAM software but that’s not going to be an option if we want this to be truly autonomous.

What is outwards in this context? Up, down, left, right…? If you can define this it will be much easier.

It would need to emulate the surface normal direction of a closed polysurface. So basically, pointing away from the center of the object.

Or to put another way, if you display the surface back faces, you shouldn’t see any.



This is quite complicated I think. First of all there is no such thing as an object center if it’s all surfaces. But even in a closed object, it’s quite possible that the surface points towards the object center. So outside is also a matter of relation to the neighboring surfaces. Can you share an example file of what you need to deal with? Will the surfaces always form a closed object, say if you join with low tolerance like 0.1? You then might use the joined object as reference, after joining, exploding it again and then find the matching surfaces on the original and match their normals.

Technically you are correct, if the object isn’t closed it doesn’t have a center. You are also correct that this is proving difficult.

If all our models were closeable this would be a lot easier as we would create a closed polysurface, colour the faces and the surface normal directions should be pointing the correct way for 5-axis machining. This isn’t an issue for us if we want to continue taking the time to program each one. Our CAM software has a button to force all surface normals in the proper direction. But to make the programming autonomous I need to emulate that behaviour in Rhino before exporting to STEP. If I can’t succeed at this then we’ll have to make a process change for the employees creating the models to use the Flip command and toggle the surfaces manually. We’re still going to succeed with this project, I was just hoping to avoid adding extra tasks to the modellers.

Since other softwares can do this with the press of a button I was hoping to replicate that as part of my export tool.

I’m away from the office until Monday, but i can post a couple of examples then. I have one already on another thread about Cplane inconsistencies. Pascal has something for me to try, so I’m still hopeful I may get this working.



Is not what you are looking for in Paneling Tools ? @rajaa
Paneling Tools → Paneling Utility

I was also going to suggest something like this - you don’t even need to have a closed object as a result of the join IMO. Join orients the normals of adjoining surfaces so that they are in the same direction at the joint. The result will be a collection of surfaces that will all face the same direction relative to each one’s neighbors; whether as a collection they face “in” or “out” relative to some outside point after that is the tricky part.

So you could join the surfaces via script in the background (RhinoCommon) and then explode them again, then check all of the surfaces’ “flip flag” and reverse those that are True by changing the UV directions so that the flip flag is then False. Then what you have is all of the surfaces “natural” normal directions will all be aligned.

However, at this point you do not know if they are all facing inside or outside relative to the machining direction, so you would need to figure out a way to determine that. Perhaps averaging all the normals and compare the average to an outside point. If they are facing the wrong way, flip all of them again.

This might be computationally expensive for something with 90K surfaces though. Just joining that many already takes a lot of time.

You’re right it doesn’t even need to be closed. Just need to make sure they connect at least at one edge.

I believe it was 90K unique parts not 90K surfaces :slight_smile:

Can you define the problem differently?

Should the surface normals be generally facing positive Z? For a milled top surface CNC machine, this might be useful. 5 axis, I’ve no idea what would be useful.

At the moment, all I can envisage is the surface below. It has no centre, and no way of defining what is the correct direction for the normals, even manually.

I appreciate all of the inputs on this topic. However, I think maybe I haven’t communicated what I’m trying to achieve very well. In the images below you will see a simple detail that illustrates what I’m hoping to achieve (which emulates what is already possible in our CAM product, but I need to accomplish it via scripting). Starting in the new year we will be changing our process to use closed polysurfaces with coloured faces as opposed to individual surfaces, so that process change alone will solve a lot of the simple details like this. But for the sake of trying to communicate what I’m after I present this:

The last illustration is the most important. In our CAM solution there is a one-button solution that toggles the surface directions so that they all face outside. That is my goal. Once the surface directions are facing outside, the file still maintains it’s original colouring (which indicates tolerancing to the machinist).


It’s the fact that other products can do this with a push of a button that has me not giving up on this in Rhino.

I hope this explains it a little better.



Hi Dan,


For models that can be joined into a solid It would be not that difficult to join a copy of the inputs into a solid and check each input if the normal is aligned with the newly created solid ( and flip if needed).

For cases with not closed input I see an option to still join into polysurface.
That new polysurface is probably easier analyzed for the normal being correct than the separate surfaces.
Once you have ensured the polysurface has the correct orientation you can do as above and check inputs against the polysurface.

In any case, determining the ‘correct’ orientation you need the know the topological relationship between the separate surfaces.
eg for a vertical surface you need to know what other surfaces it connects to, to define the correct orientation.

I think to tackle the non solid input cases you need to know the ‘type of openness’ -for lack of better wording-
Say if these open sides are always on the bottom you can infer the correct orientation from the top most flat most surface and work downward from there…

If you are going to give it a shot, make sure not to get caught by the flipping flag of orientations as mentioned before and the possibility of inward facing solids. IIRC Evaluating a face surface with reversed orientation can yield a different normal as the PolySurface it describes.

I leave the code snipped below as possible checks/solutions
Disclaimer I quicky dug these up in our codebase, make sure to test and evaluate properly.

if brep.SolidOrientation == Rhino.Geometry.BrepSolidOrientation.Inward:


for face in brep.Faces:
        # print face.OrientationIsReversed
        if face.OrientationIsReversed:



Hi Willem,

There are some great ideas and suggestions here.

Thank you for this,


Hi Willem,

I took a different direction on this, based off of your suggestion to join a copy of the surfaces. But instead of trying to flip the surface normals, I just passed the colour of each surface off to the newly exploded surfaces and deleted the original.

Thanks for the suggestion, and thanks to all for your input.


1 Like

great! :tada: