Hello everyone,
I am working on a function that will join a collection of curves into a single closed curve, based upon the closest endpoints.
You can read more detailed comments in the .gh file, but the basic algorithm is as follows:
- Collect up all the endpoints of the curves
- If it’s not already present, then add each point and the point that is closest to it to a separate list
- Draw line segments between every pair of points in this separate list.
- Convert everything to nurbs curves, and join the new segments with the original curves.
Here you can see an example, with the segments below, and the intended closed polyline (highlighted in yellow) above.
It works great 50% of the time, but as I test the input curves to see how robust the algorithm is, I start getting invalid polycurves and I can’t figure out exactly why.
My guess is that it has something to do with point tolerances, and I am creating microsopic lines… but I can’t quite figure out what’s up.
Here is the invalid curve segment
Any ideas?
201111_CloseDisjointCurves.3dm (29.0 KB) 201111_CloseDisjointCurves.gh (10.6 KB)
Here is the code:
import rhinoscriptsyntax as rs import Rhino as rc import scriptcontext as sc def checkIfListIncludesPoint(listOfPoints,pointToTest): sc.doc = rc.RhinoDoc.ActiveDoc functionTolerance = sc.doc.ModelAbsoluteTolerance sc.doc = ghdoc counter = 0 for pt in listOfPoints: if pt.EpsilonEquals(pointToTest, 1) == True: counter = counter + 1 if counter > 0: return True if counter == 0: return False def sortListOfPointsByDistanceToPoint(listOfPoints,pointToTest): listOfDistances = [] for testPt in listOfPoints: listOfDistances.append(pointToTest.DistanceTo(testPt)) sortedPts = [x for distance,x in sorted(zip(listOfDistances,listOfPoints))] return sortedPts #Create a function that will attemp to close several curves by connecting them to #the closest endpoints of the curves nearby #Create an empty list for all the end points allEndPoints = [] #Create a list where you will place the points as they are sorted sortedEndPoints = [] #Create a pointcloud for fast processing of point proximity pointCloud = rc.Geometry.PointCloud() #Create a list of all nurbsCurves for joining at the end allNurbsCurves = [] #Define the tolerance as the rhino doc tolerance sc.doc = rc.RhinoDoc.ActiveDoc tolerance = sc.doc.ModelAbsoluteTolerance sc.doc = ghdoc #Load up the list of all endpoints with the start and end points of all the curves. for curve in Curves: allEndPoints.append(curve.PointAtStart) allEndPoints.append(curve.PointAtEnd) nurbsCrv = rc.Geometry.NurbsCurve.ToNurbsCurve(curve) allNurbsCurves.append(nurbsCrv) #Load up the point cloud with points you just collected pointCloud.AddRange(allEndPoints) #Iterate over all the points in allEndPoints for i, pt3D in enumerate(allEndPoints): #For each point, sort all the points in order of their distance pointsAescendingDistances = sortListOfPointsByDistanceToPoint(allEndPoints,pt3D) #If the point itself is not already in the list, #then add both the test point and the test point's closest neighbor to a new list if checkIfListIncludesPoint(sortedEndPoints,pt3D) == False: sortedEndPoints.append(pointsAescendingDistances[0]) sortedEndPoints.append(pointsAescendingDistances[1]) #Iterate over every other item in this list to make the lines: for i in range(0, len(sortedEndPoints), 2): line = rc.Geometry.Line(sortedEndPoints[i],sortedEndPoints[i+1]) nurbsCurve = line.ToNurbsCurve() allNurbsCurves.append(nurbsCurve) joinedCurves = rc.Geometry.Curve.JoinCurves(allNurbsCurves, tolerance, True)[0] print joinedCurves #Return the new list a = sortedEndPoints