The API exposes some underlying math and geometry tools and we get whatever their native behavior is. In this case it appears that the getParameterAtPoints ignores the limits of the curve and returns parameters as if the curve was not bounded. For example, it treats a line as infinite length and an arc as a circle. But the getPointAtParameter expects the input parameter to be within the bounded portion of the curve and that's why it's failing. I modified your function so it now checks if the parameter is within the bounded range and if not, adjusts it to the closest end. I tried on various shapes and it seems to work now.
def findClosestPoints(self, points):
n = len(points)
ptsOnCurve = [{} for i in range(n)]
for curve in self.curves:
ev = adsk.core.CurveEvaluator3D.cast(curve.geometry.evaluator)
ret, minExtent, maxExtent = ev.getParameterExtents()
ret, params = ev.getParametersAtPoints(points)
if not ret:
raise AttributeError('invalid points in getParametersAtPoints')
newParams = []
for param in params:
if param < minExtent:
newParams.append(minExtent)
elif param > maxExtent:
newParams.append(maxExtent)
else:
newParams.append(param)
print(params,curve.geometry)
if len(newParams) > 0:
ret, pts = ev.getPointsAtParameters(newParams)
if not ret:
raise AttributeError('invalid points in getPointsAtParameters')
for i in range(n):
d = points[i].distanceTo(pts[i])
ptsOnCurve[i][d] = (pts[i],curve)
# query min points
output = []
if len(ptsOnCurve[0]) > 0:
for i in range(n):
dmin = min(ptsOnCurve[i])
pt,curve = ptsOnCurve[i][dmin]
output.append((pt,curve))
return output