Brep.ClosestPoint strange result

There is a strange behavior that I am getting with Brep.ClosestPoint method in both Rhino 6 and Rhino 5.
I have a polysurface consisted of two, exactly the same (mirrored) surfaces.
There is a point in between them, lying in the middle of the brep edge that they share:

Judging by this reply from @menno, Brep.ClosestPoint is suppose to identify the closest point to be lying on the brep edge in the middle, which would then result in the normal of this point to be [0,0,1] (the average normal between two brep faces).

But for some reason Brep.ClosestPoint identifies that the closest point actually lies on one of the brep faces (brep face 1), which then incorrectly shows the normal to be the normal of that face.
Why is that so?
This is the example code:

import rhinoscriptsyntax as rs
import System
import Rhino
import clr

# inputs - brep, pt
brep_id = rs.GetObject("select brep")
pt_id = rs.GetObject("select pt")
brep = rs.coercegeometry(brep_id)
pt = rs.coerce3dpoint(pt_id)

# out parameters
closestPt_out = clr.StrongBox[Rhino.Geometry.Point3d]()
ci_out = clr.StrongBox[Rhino.Geometry.ComponentIndex]()
u_out = clr.StrongBox[System.Double]()
v_out = clr.StrongBox[System.Double]()
maxDist = 0
normal = clr.StrongBox[Rhino.Geometry.Vector3d]()

succ = Rhino.Geometry.Brep.ClosestPoint(brep, pt, closestPt_out, ci_out, u_out, v_out, maxDist, normal)

print "closest type: ", ci_out.ComponentIndexType  # prints "Rhino.Geometry.ComponentIndexType.BrepFace" instead of "Rhino.Geometry.ComponentIndexType.BrepEdge"

Any help would be welcomed.
Attached is the 3dm file brep closest pt.3dm (41.0 KB)

I would assume that your tolerance settings or accuracy of the surfaces play a part here,you asked for the closest point,it gave you that, and at that point on whatever surface was closest it gave you the normal on that surface at that point,I use this command all the time at sub micron tolerances and have never had a bad result,if you were looking for the normal to be vertical in your example, it does not exist on either surface,even if it had picked the edge of the other surface,the normal would be normal to the surface.

I hope this makes sense


You could take a point either side of the point you are interested in and average the 2 normals

Hi @philip_bayldon,
Pt’s coordinates are:
0, 48.2612111429905, 55.2791471846615

While the coordinates of start and end point of the brep edge on which it lies are:
0, 96.5224222859811, 55.2791471846615
0, 0, 55.2791471846615

So it should be fine I guess.

Hi @dale, @stevebaer, any help on this please?
Why does Brep.ClosestPoint return ComponentIndexType.BrepFace instead of ComponentIndexType.BrepEdge?
Any help would be appreciated.

Hi @dale, @stevebaer,

I am having the same problem even with the latest Rhino 6 release (2019-10-22).
Any advice please, as the problem is affecting my work. Thank you in advance for the reply.

I tried @menno’s C# code as well, but again Brep.ClosestPoint returns ComponentIndexType.BrepFace instead of ComponentIndexType.BrepEdge.

Any help is appreciated.

Hi @djordje,

There has always been confusion as to what Brep.ClosetPoint really does. This is totally our fault because the SDK comments are not clear at all.

The current description makes you think the method iterates all Brep components looking for the one that is closest to a test point. This is not the case.

The function searches all Brep faces looking for the one closest to a test point. When found, if the closest point falls in the inactive region of the face, then the function finds the face’s edge that is closest to the test point. Otherwise, it just returns the component index of the closest face.

I’ve created an issue to update the comments:

Hope this helps.

– Dale

Thank you @dale.

When is the point located in the inactive region of the face?

Does this mean that the following Brep.ClosestPoint example can not be used?

Hi @djordje,

Here is a simple case.

I don’t know anything about the example - sorry.

– Dale

1 Like

Thank you Dale.

1 Like

RH-55657 is fixed in the latest Service Release Candidate