# Confused about behavior of curve.ClosestPoint

This is likely a dumb question, so my apologies in advance.

Inside some GHPython code I’m trying to test points for whether they are on a given curve. Unfortunately it seems that all points say they’re on the curve.

If anyone could kindly explain what I’m doing wrong, that would be splendid.

I’ve attached a simple example showing my problem.

Thanks so much,
Marytest_point.3dm (25.9 KB)
test_point.gh (3.9 KB)

Hello @mary.baker,

First of all, there are no dumb questions!

When you call `curve.ClosestPoint(point, tolerance)` in your Python script, you get for instance `(True, 6.81)` returned. The first value informs about, wether the method was successfully called, and not about your points proximity to the curve. The second value is simply a curve parameter, of where the closest point to your point is situated on the curve.

So what you need to do, is simply take the parameter to get the closest point, measure the distance between the closest point and your point, and compare this distance to your tolerance value.

`curve.ClosestPoint()` is also not a method from rhinoscriptsyntax, but from RhinoCommon. Since, you already imported the rhinoscriptsyntax library, here’s how to solve your problem in it:

``````import rhinoscriptsyntax as rs

# Get the curve parameter
t = rs.CurveClosestPoint(curve, point)
# Get the closest point on the curve to your point
crv_pt = rs.EvaluateCurve(curve, t)
# Measure the distance between both points
dist = rs.Distance(point, crv_pt)

# Compare the distance to your tolerance
if dist <= tolerance:
print "Point was indeed within %.2f distance." %(tolerance)
a = True
else:
print "Point was not within %.2f distance." %(tolerance)
a = False
``````
2 Likes

Thank you so much! That is tremendously helpful, and now I better understand a few other RhinoCommon functions as well

Thanks again!
Mary

You’re welcome!

If your interested in a RhinoCommon version, it is done very similarly.
However, you might have to set your component inputs to curve and point inputs respectively, for it to work.

``````import Rhino.Geometry as rg

# Get the curve parameter
success, t = curve.ClosestPoint(point)
# Get the closest point on the curve to your point
crv_pt = curve.PointAt(t)
# Measure the distance between both points
dist = point.DistanceTo(crv_pt)

# Compare the distance to your tolerance
if dist <= tolerance:
print "Point was indeed within %.2f distance." %(tolerance)
a = True
else:
print "Point was not within %.2f distance." %(tolerance)
a = False
``````

In RhinoCommon, as you may already know, you call the methods/functions differently.
Rhinoscriptsyntax is basically a “repackaged” Python API of RhinoCommon that makes the latter more straightforward to use.
In order to understand the structural differences between both, you need to understand, what namespaces, classes, constructors, methods/functions, etc. are in programming.

Here’s a simple example:

`curve.ClosestPoint(point)` calls the method `ClosestPoint()` from the `Curves` class that exists in the `Rhino.Geometry` namespace. Your variable `curve` is in fact an instance of the `Curves` class and `ClosestPoint()` one of its class methods.
Your variable `point` is an instance of the `Point` class from `Rhino.Geometry` that has its own class methods to chose from.
This is also, why you need to change the inputs of your component to curve and point inputs. I’m not totally sure about this, but I guess that when you declare the types of your inputs, the component passes class instances to your code, which is essential for RhinoCommon.
The rhinoscriptsyntax, on the other hand mostly works with guids, some type of geometry reference (?), an identification of sorts of geometry objects (?). Why it doesn’t need the type declarations on component input level, is because it mostly does the conversions internally (see below).

In rhinoscriptsyntax, you basically call the method `CurveClosestPoint()` from the `rhinosciptsyntax` library that you previously imported.
And, here’s what happens under the hood (cf. source):

``````def CurveClosestPoint(curve_id, test_point, segment_index=-1 ):
"""Returns parameter of the point on a curve that is closest to a test point.
Parameters:
curve_id (guid): identifier of a curve object
point (point): sampling point
segment_index (number, optional): curve segment index if `curve_id` identifies a polycurve
Returns:
number: The parameter of the closest point on the curve
Example:
import rhinoscriptsyntax as rs
id = rs.GetObject("Select a curve")
if id:
point = rs.GetPointOnCurve(id, "Pick a test point")
if point:
param = rs.CurveClosestPoint(id, point)
print "Curve parameter:", param
EvaluateCurve
IsCurve
"""
curve = rhutil.coercecurve(curve_id, segment_index, True)
point = rhutil.coerce3dpoint(test_point, True)
rc, t = curve.ClosestPoint(point, 0.0)
if not rc: raise Exception("ClosestPoint failed")
return t
``````

First, the method converts its parameter `curve_id`, which is the guid of the passed-in curve, to an instance of the `Curve` class from `Rhino.Geometry`. The parameter `test_point` is converted to an instance of the `Point` class from `Rhino.Geometry` (?).
After that, the method simply calls the `CurveClosestPoint()` method, like I did in the RhinoCommon example above, from the instance of the `Curve` class, saved in the variable `curve`. Remember, the `Curve` class lives in the `Rhino.Geometry` namespace.

I’ve added a question marks between parenthesis to all the parts that I’m not 100% sure of.

5 Likes

Wow – thank you so much! Yes, that is exactly the kind of guidance I was missing. This will make so many things easier for me now.

Thanks again!
Mary

A universally unique identifier

Randomly generated with 128 random bits, ie approximately zero chance of any two objects in the world having the same value so you can safely use them without checking for naming conflicts.
`import uuid` to make your own or use this recipe

2 Likes

Thanks for clarifying!

Mary

Great explanation @diff-arch!!
Any idea on why Curve.ClosestPoint(Pt) does not work when calling Rhino Common from outside of Rhino (Pycharm)?
Btw, I`m using rhinoinside to call Rhino Common.

Ty!

Welcome @thomas.takeuchi,

The only thing I can think of, is that you might need to provide a second tolerance argument (i.e. 0.01), but I’m not exactly sure about this?
Generally, I don’t have a lot of experience with rhinoinside. What do you use it for? And does it use RhinoCommon, or compute_rhino3d, or even rhino3dm?

1 Like

I already answered the question in the other post from @thomas.takeuchi here Rhino inside Python

2 Likes