Find shortest lines between curve points and mesh face centers with GHPython?

hi everyone
I create lines between the centroid(each face) and some point on mesh with limited distance.
my problem is, to some point created more 1 line and want shortest one,
anybody have an idea to help me?

thanks for advance,Sara

model_point.gh (8.2 KB)model.3dm (64.3 KB)

To find the shortest line use sort list and choose the first item

1 Like

Hi @sara22.martin22,

Here’s a purely pythonic version, if you’re interested.

It uses the RTree algorithm to first find the closest mesh face centers for each curve division point. The shortest distance between these face centers and the individual curve division point is then evaluated. A line is drawn for the shortest distance only. However, other than in @anon39580149’s solution, only one closest line gets drawn, when multiple potential connections have the same distance, and thus no clear closest one is discernible.

This is what the script looks like:

import Rhino.Geometry as rg
import Grasshopper as gh

# Get the curve division points (including the end points)
crv_points = [Curve.PointAt(t) for t in Curve.DivideByCount(Count, True)]

# Get the mesh face centers
face_centers = [Mesh.Faces.GetFaceCenter(i) for i in xrange(Mesh.Faces.Count)]

# Initialise an RTree
rtree = rg.RTree()

# Populate the RTree with the mesh face centers and indices
for i, center_pt in enumerate(face_centers):
    rtree.Insert(center_pt, i)

# Evaluate the closest lines from each curve point to a mesh face center
lines = [] 
for pt in crv_points:
    # Find the closest mesh faces within the search radius
    closest_faces = [] # indices of closest faces
    search_sphere = rg.Sphere(pt, Radius)
    rtree_callback = lambda sender, args: closest_faces.append(args.Id)
    rtree.Search(search_sphere, rtree_callback)
    # Find the closest line
    if len(closest_faces) > 0:
        dists = [pt.DistanceTo(face_centers[i]) for i in closest_faces]
        sorted_faces = [f for _, f in sorted(zip(dists, closest_faces))]
        closest_line = rg.Line(pt, face_centers[sorted_faces[0]])
        lines.append(gh.Kernel.Types.GH_Line(closest_line))

# Outputs
a = lines

And here’s the GH file:
model_point_v3.gh (7.2 KB)

1 Like

thank you for your reply. I need to lines that is shortest from point on mesh to centroid but some line in this way did not include the result.

thank you so much. it’s awesome. any way exist to assign number of the line created to centroid?

You’re welcome. Outside of the GHPython component you can get the face center with the End (End Points) component. The centroids are the end points of the lines, since these were drawn from the curve points to the face centers.

In Python, you can do the following:

import Rhino.Geometry as rg
import Grasshopper as gh

# Get the curve division points (including the end points)
crv_points = [Curve.PointAt(t) for t in Curve.DivideByCount(Count, True)]

# Get the mesh face centers
face_centers = [Mesh.Faces.GetFaceCenter(i) for i in xrange(Mesh.Faces.Count)]

# Initialise an RTree
rtree = rg.RTree()

# Populate the RTree with the mesh face centers and indices
for i, center_pt in enumerate(face_centers):
    rtree.Insert(center_pt, i)

# Evaluate the closest lines from each curve point to a mesh face center
lines = []
faces = [] # face indices connected to by lines
for pt in crv_points:
    # Find the closest mesh faces within the search radius
    closest_faces = [] # indices of closest faces
    search_sphere = rg.Sphere(pt, Radius)
    rtree_callback = lambda sender, args: closest_faces.append(args.Id)
    rtree.Search(search_sphere, rtree_callback)
    # Find the closest line
    if len(closest_faces) > 0:
        dists = [pt.DistanceTo(face_centers[i]) for i in closest_faces]
        sorted_faces = [f for _, f in sorted(zip(dists, closest_faces))]
        closest_line = rg.Line(pt, face_centers[sorted_faces[0]])
        lines.append(gh.Kernel.Types.GH_Line(closest_line))
        faces.append(sorted_faces[0])

# # Outputs
a = lines
b = [face_centers[f] for f in faces] # centroids
c = [f for f in faces] # face indices

Please note that you need to add outputs b and c to your component.

Here’s the updated file:
model_point_v4.gh (11.4 KB)

that great, I’m very thankful, it’s very important for me and accepts my appreciation for the help. my last question is if want executes this script for any point(without curve and divide the that), can I input my point and in the first-line script use that [x for x in point]?

Yes, simply delete the line crv_points = [Curve.PointAt(t) for t in Curve.DivideByCount(Count, True)], and substitute the line for pt in crv_points: with for pt in >name_or_your_points_input<.
It’s also important to set your points input to List Access!
Now, you can get rid of the Curve and Count inputs as well.

thank’s again.

1 Like