Find point in a particular distance

Hi,
Greetings!
I have a problem, I need to find a point in a particular distance

example:
consider a curve which has points on it
image

Consider this point on the curve, lets call A
image

Suppose if i need to find all the points which are at a distance of 8mm to 11 mm, but along the curve like this
image

but though the point D satisfy the condition, I dont want to be my output,
My expected output would be a list [B,C]
image

This article would help to find length of points along curve: Get distance between 2 points on line

My input would be list of guids of all point and guid of point A, expected output to be guid of Point B and Point C

Requesting help from all on the forum

Thanks in advance.

Please find the attachment
curve_with_equidistant_pts.stp (21.3 KB)

Requesting your help
@Mahdiyar @pascal @Helvetosaur @diff-arch

I hope this help:

import rhinoscriptsyntax as rs
import Rhino.Geometry as rg
def disOnCrv(crv, pt1, pt2):
    a = rs.CurveClosestPoint(crv, pt1)
    b = rs.CurveClosestPoint(crv, pt2)
    if a > b:
        a , b = b , a
    distance = rg.Curve.GetLength(rs.coercecurve(crv), rg.Interval(a, b))
    return min(distance, rs.CurveLength(crv) - distance)

crv = rs.GetCurveObject("Curve")[0]
pts = rs.GetObjects("All Points", rs.filter.point)
ptA = rs.GetObject("Point A", rs.filter.point)
minimum = rs.GetReal("minimum")
maximum = rs.GetReal("maximum")
indexes = []
for i in range(len(pts)):
    d = disOnCrv(crv, ptA, pts[i])
    if d >= minimum and d <= maximum:
        indexes.append(i)
print indexes
rs.SelectObjects(pts[min(indexes): max(indexes)])

Sumukha.py (741 Bytes)

Hi @Mahdiyar ,
Thank you for the reply,
The program behaves differently when chosen different starting point (ptA). Please let me know how i can tackle it.

Hello,

Did you know you can do this:

if minimum <= d <= maximum:
        indexes.append(i)

for even greater readability :smiley:

For more thinking on comparisons read here

1 Like
import rhinoscriptsyntax as rs
import Rhino.Geometry as rg
def disOnCrv(crv, pt1, pt2):
    a = rs.CurveClosestPoint(crv, pt1)
    b = rs.CurveClosestPoint(crv, pt2)
    if a > b:
        a , b = b , a
    distance = rg.Curve.GetLength(rs.coercecurve(crv), rg.Interval(a, b))
    return distance

crv = rs.GetCurveObject("Curve")[0]
pts = rs.GetObjects("All Points", rs.filter.point)
ptA = rs.GetObject("Point A", rs.filter.point)
minimum = rs.GetReal("minimum")
maximum = rs.GetReal("maximum")
indexes = []
for i in range(len(pts)):
    d = disOnCrv(crv, ptA, pts[i])
    if minimum <= d <= maximum:
        indexes.append(i)
print indexes
rs.SelectObjects(pts[min(indexes): max(indexes)])

Sumuk.py (711 Bytes)

Hi @sumuk, my guess it you need to move the (closed) curve seam to your test point and make sure to pass in the parameters to build the domain for measuring the two lengths along the curve in increasing order. Then take the shorter length of both. If the length is larger than 8 and smaller than 11, the search point is within the required distance.

@Mahdiyar, i think your example only can work if the curve is properly parameterized and the seam is very close to the test point.
_
c.

find_pts.gh (9.9 KB)

Hi @sumuk,
Here is a sample using Rhinocommon which seems to work for all cases, at least in your given example. To avoid errors when close to the seam, the curve is copied in memory and the seam is moved away from the picked point, if needed.
See if this helps:

import Rhino
import scriptcontext as sc

def findPointsOnCurveByDistance():
    
    # set distance
    dMinDistance = 8
    dMaxDistance = 11
    
    # get tolerance from document
    dTol = sc.doc.ModelAbsoluteTolerance
    
    # empty list to hold points that match distance
    arrPtsFound = []
    
    # get point
    rc, objRef = Rhino.Input.RhinoGet.GetOneObject("Pick start point on curve", False, Rhino.DocObjects.ObjectType.Point)
    if rc != Rhino.Commands.Result.Success: return rc
    
    ptPicked = objRef.Point().Location
    
    # get curve
    rc, objRef = Rhino.Input.RhinoGet.GetOneObject("Pick curve", False, Rhino.DocObjects.ObjectType.Curve)
    if rc != Rhino.Commands.Result.Success: return rc
    
    crvPicked = objRef.Curve()
    
    # duplicate curve, as we might move its seam
    crv = crvPicked.DuplicateCurve()
    
    # test if closed
    if crv.IsClosed:
        # test if ptPicked is too close to the curve seam
        if ptPicked.DistanceTo(crv.PointAtStart) <= dMaxDistance:
            # change the seam, as this curve is just a copy, this is safe to do
            crv.ChangeClosedCurveSeam(crv.Domain.Mid)
            
    # get all points
    rc, arrObjRefs = Rhino.Input.RhinoGet.GetMultipleObjects("Pick all points", False, Rhino.DocObjects.ObjectType.Point)
    if rc != Rhino.Commands.Result.Success:
        return rc
        
    arrPtPicked = [obj.Point().Location for obj in arrObjRefs]
    
    
    # determine length parameter of ptPicked along the curve
    bSuccess, dPickedParam = crv.ClosestPoint(ptPicked, dTol)
    if not bSuccess:
        print "ERROR: Picked point was not on the picked curve!"
        return Rhino.Commands.Result.Failure
    dPickedLength = crv.GetLength(Rhino.Geometry.Interval(crv.Domain.Min, dPickedParam))
    
    # iterate over all points
    for pt in arrPtPicked:
        # skip the picked point
        if pt.EpsilonEquals(ptPicked, dTol): continue
        
        # determine length parameter of pt along the curve
        _, dParam = crv.ClosestPoint(pt, dTol)
        dLength = crv.GetLength(Rhino.Geometry.Interval(crv.Domain.Min, dParam))
        
        # check if dLength is close to dPickedLength
        dDistanceToPicked = abs(dPickedLength - dLength)
        if dMinDistance <= dDistanceToPicked <= dMaxDistance:
            arrPtsFound.append(pt)
       
    # add found points to doc
    for pt in arrPtsFound:
        sc.doc.Objects.AddPoint(pt)
        
    # redraw the views
    sc.doc.Views.Redraw()
    
    
if __name__ == "__main__":
    findPointsOnCurveByDistance()