CurveNormal function doesn't appear to be behaving as expected


I have a problem, I think, with the CurveNormal function in both Python and VBScript.
I’ve attached an example 3DM file which contains a curve. This curve was generated by projecting a straight line (not a curve) onto a surface from above (Z direction).
Using the curve analysis tools you’ll notice a slight curve to the line in approximately the Z-X plane.
You’ll also notice that the line is straight when viewed from the Top view (s expected).

Now when I run a python or VB script using the CurveNormal function as per:

import rhinoscriptsyntax as rs

object = rs.GetObject(“Select a planar curve”)
if rs.IsCurve(object) and rs.IsCurvePlanar(object):
normal = rs.CurveNormal(object)
if normal: print “Curve Normal:”, normal

I get a result close to [0,0,1]
This does not seem correct as I would expect it to be something more around [0,1,0]

Could someone please review and let me know if I’m crazy or not? Thx.

p.s. If I take the same curve and rotate it in the Top view so that it is parallel to the X-axis, I get the Normal value I would expect!
CurvePlane.3dm (439.3 KB)

Many Thanks,


@dale are you able to help me on this one as it’s currently holding up a major re-write I’m doing from VBS to Python? Many Thanks.


Hi @shanew06,

Here is the code behind rs.CurveNormal:

Keep in mind that, technically, curves do not have normals. But if the curve is planar, then the above-mentioned function returns the normal to the plane on which the curve lies.

Hope this helps.

– Dale

Thanks Dale.

Yep fully get that. My issue is that the plane that the curve lies on should have a normal something like [0,1,0] as it is planar and curves along the Z-X plane. However the function is returning the normal to be something more like [0,0,1]. When also running the CurvePlane function, it appears to be calculating an incorrect plane that the curve lives in as well.



Could this be a tolerance issue?


So a quick test showed that Yes, it is a tolerance issue.
Once I decreased the absolute tolerance of Rhino down from "0.01"mm to "0.0001"mm the function worked as expected.

Thanks for your help Dale as the code you provided showed me that there was some reliance on tolerance for this function.



Beware of this reasoning for a general solution. Yes, this is a tolerance issue in the sense that as written, CurveNormal tries to find a unique plane which a curve lies in (and hence the normal) - within the file absolute tolerance. Your sample curve deviates from a straight line by .004mm, and your file tolerance is .01mm - therefore it is still a straight line as far as Rhino is concerned (SimplifyCrv works to make it so).

Straight lines do not have a unique plane - they lie in an infinite number of planes rotated around the line’s axis. It is therefore impossible to determine one single plane for a line. The flaw in the CurveNormal function is that when presented with a line, it returns one of those planes, which is “pulled out of a hat” according to some in-built criteria. IMO, it should just fail and return None.

If you reduce the file tolerance to where the .004 deviation from a line is larger than the file tolerance, then CurveNormal might find a plane. However, depending on how small the difference is between the file tolerance and the deviation from a straight line, the plane it returns might also be arbitrary, because your are in the “fuzz” of floating point math and NURBS mathematics.

1 Like

Yes, thanks. All of that makes absolute sense.

I also agree that the function should return None in this situation rather than a random guess at a plane.

Many Thanks for your input.