Exception raised on evaluator.getPointsAtParameters from parameters given by ev.

Exception raised on evaluator.getPointsAtParameters from parameters given by ev.

gscotti
Enthusiast Enthusiast
941 Views
7 Replies
Message 1 of 8

Exception raised on evaluator.getPointsAtParameters from parameters given by ev.

gscotti
Enthusiast
Enthusiast

This is the failing code:

           ev = curve.geometry.evaluator
            ret, params = ev.getParametersAtPoints(points)
            if not ret:
                raise AttributeError('invalid points in getParametersAtPoints')

            print(params,curve.geometry)
            ret, pts = ev.getPointsAtParameters(params)
            if not ret:
                raise AttributeError('invalid points in getPointsAtParameters')

I've attached the model I'm trying it with. Sketch1 works (circles) but Sketch2 fails (rectangles.

 

0 Likes
942 Views
7 Replies
Replies (7)
Message 2 of 8

ekinsb
Alumni
Alumni

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

Brian Ekins
Inventor and Fusion 360 API Expert
Mod the Machine blog
0 Likes
Message 3 of 8

gscotti
Enthusiast
Enthusiast

I ended up doing the same as you did. However, you are expected to get valid data from the API functions, don't you think?

 

0 Likes
Message 4 of 8

ekinsb
Alumni
Alumni

I think this is a case where "valid" is left up to some interpretation so returning a parameter on the boundless curve can be considered valid and it could be used to determine if the input point is one the curve or outside.  Whereas if we were to adjust the parameters to the bounded portion you couldn't do that.  But returning parameters within the bounded extents could also be considered "valid".  Regardless, of what we consider to be "correct", we'll leave the behavior the way it is in case people have taken advantage of the current behavior and we don't want to break them.  I will make a note to add some additional information to the documentation about the behavior though.


Brian Ekins
Inventor and Fusion 360 API Expert
Mod the Machine blog
0 Likes
Message 5 of 8

gscotti
Enthusiast
Enthusiast

I agree with your argument. However, getPointsAtParameters contradicts it.

Let me explain it better:

  getParametersAtPoint(pt) returns parameters beyond the curve, as you explained.

 

Using the same argument as you did, why getPointsAtParameters validates the parameters if its inverse function allows to return parameters beyond its curve extents? That sounds like contradictory. I would love to have both functions returning parameters beyond the curve. That's the whole point about parametrized curves, right?

 

 

0 Likes
Message 6 of 8

gscotti
Enthusiast
Enthusiast
And I hope you don't change the behavior of getParametersAtPoints, because I've been using it to get closest point at curves, for the lack of a better function. Which is not exactly the way you describe its purpose is. Is it correct to say "..could be used to determine if the input point is beyond the curve or not." Because is 'on' or 'outside' the curve is a open to interpretations.
0 Likes
Message 7 of 8

ekinsb
Alumni
Alumni

I agree that there is some contradiction in the behavior.  As I said, the API is using a general geometry and math library (actually AcGe which comes from AutoCAD) and we get that library's native behavior.  However, I just looked at the API source code and we're adding an extra check in getPointsAtParameters to validate if the input parameter is on the curve and if it's not it fails with the "invalid argument parameters" error.  So getPointsAtParameters cares about the bounds and getParametersAtPoint doesn't.  But I would be hesitant to change the behavior at this point but we should document it.

 

And yes, saying the point is "beyond the curve or not" is probably a better way to say it.  Anytime the point is off the curve though there could be some unexpected results for some cases.  For a line or arc it's simple because a boundless arc is always a circle and a boundless line is known.  However a spline can't necessarily be extended to infinity and can curve in unexpected ways when it is extended.  And it's possible there could be multiple correct answers.  For example, what parameter should be returned if you input the center point of a circle for the circle?  I know these are not typical cases but I'm just trying to say that it's best to use points that lie very near the curve to get the best results.


Brian Ekins
Inventor and Fusion 360 API Expert
Mod the Machine blog
0 Likes
Message 8 of 8

gscotti
Enthusiast
Enthusiast

Understood. I believe the whole point is that getParametersAtPoints should not return any parameter outside its parameters limits. From parametric math perspective, that's wrong, because the returned value is not within the curve's domain. Perhaps the whole point is to think that a bounded line is an infinite line, which in this case it is not.

 

 

To answer your question: I expect to get any parameter from the parametric circle if I give origin as reference point. Same thing happens if set any point inside the circle: you have two possible points, and whichever is returned is what I would expect as a valid answer. That's actually a good test case for the API. 🙂

 

0 Likes