How do I pass points to and from a custom node?

john's Avatar

john

09 Nov, 2017 11:47 AM

Frederik,

I have just made a custom node that finds a convex hull. Given a set of points it returns the subset of outer points which "wrap" all the interior points inside the simplest possible closed, convex path - like a rubber band.

My problem? I had a terrible time feeding points into the custom node, and an equally terrible time getting them out again. Python doesn't seem to like NodeBox points.

The only way I could get the points in was to convert them into two separate lists of x and y values. In my Python code I then zip the two lists together to make Python points and run them through the algorithm. I then import the Point function from nodebox.graphics and step through the Python array to turn it back into an array of NodeBox points.

But my trouble is not over. The output comes out like this: [x1,y1, x2,y2, x3,y3]. If I view it in Viewer mode I see a set of points, but in Data mode it is treated like a single string. If I try feeding the output directly to a point node or connect node I get errors. My desperate solution was to create an "unpack" subnet which uses substring to remove the brackets, make_numbers to pull out the values between commas, take-every to separate the x's and y's, and make_point to put them back together as valid points.

So it works, but to use my custom node you have to feed separate x and y lists into the node and then feed the output into this silly unpack subnet. There must be a better way!

Is there some magic Python code that can make sense of a direct list of NodeBox points? It has to be a list, not one value at a time. And is there some more magic Python code the can transform a Python array into something that NodeBox will recognize as a list of points?

Even though I found a workaround, for future projects it would be nice to know the correct way to pass points to and from a custom node.

Thanks!

John

P.S. Here is my current Python code:


from nodebox.graphics import Point

def convex_hull(x,y):
    mypoints = zip(x,y)
    points = sorted(set(mypoints))

    if len(points) <= 1:
        return x[0],y[0]

    # 2D cross product of OA and OB vectors, i.e. z-component of their 3D cross product.
    # Returns a positive value, if OAB makes a counter-clockwise turn,
    # negative for clockwise turn, and zero if the points are collinear.
    def cross(o, a, b):
        return (a[0] - o[0]) * (b[1] - o[1]) - (a[1] - o[1]) * (b[0] - o[0])

    # Build lower hull 
    lower = []
    for p in points:
        while len(lower) >= 2 and cross(lower[-2], lower[-1], p) <= 0:
            lower.pop()
        lower.append(p)

    # Build upper hull
    upper = []
    for p in reversed(points):
        while len(upper) >= 2 and cross(upper[-2], upper[-1], p) <= 0:
            upper.pop()
        upper.append(p)

    # Concatenation of the lower and upper hulls gives the convex hull.
    # Last point of each list is omitted because it is repeated at the beginning of the other list. 
    hull = lower[:-1] + upper[:-1]

    hullPoints = []
    for h in hull:
        hullPoints.append(Point(h[0],h[1]))

    return hullPoints
  1. Support Staff 1 Posted by Frederik De Ble... on 13 Nov, 2017 09:11 AM

    Frederik De Bleser's Avatar

    That's weird. From Python, your list of points should just look like a list of Point objects.

    I've tried this out. I needed to set the input on points to be a list (not a value) and do the same with the output; that should give you a list both in and out.

    from nodebox.graphics import Point
    from random import seed as _seed, uniform
    
    def mover(points, distance, seed):
        _seed(seed)
        new_points = []
        for point in points:
            x = point.x + uniform(-distance, distance)
            y = point.y + uniform(-distance, distance)
            new_points.append(Point(x, y))
        return new_points
    
  2. Support Staff 2 Posted by john on 13 Nov, 2017 12:36 PM

    john's Avatar

    HI Frederik,

    Thanks for responding. I've got it working now.

    The inputs of my custom node were set to list, but not the output. Setting the output to list solved that part of the problem. Not sure how I missed it - I thought I had done that.

    I finally determined that the inout problem was in my Python code. I was eventually able to find a workaround inside the Python code by separating out the x's and y's and re-zipping them. Crazy, but it was the only way I could get it to work.

    So now I have a custom node that takes in a list of points and spits out an ordered subset of those points. Works like a charm.

    Thanks again,

    John

  3. Support Staff 3 Posted by Frederik De Ble... on 13 Nov, 2017 01:32 PM

    Frederik De Bleser's Avatar

    Good to hear!

Reply to this discussion

Internal reply

Formatting help / Preview (switch to plain text) No formatting (switch to Markdown)

Attaching KB article:

»

Attached Files

You can attach files up to 10MB

If you don't have an account yet, we need to confirm you're human and not a machine trying to post spam.

Keyboard shortcuts

Generic

? Show this help
ESC Blurs the current field

Comment Form

r Focus the comment reply box
^ + ↩ Submit the comment

You can use Command ⌘ instead of Control ^ on Mac

Recent Discussions

18 Oct, 2019 01:06 AM
10 Oct, 2019 01:11 AM
02 Oct, 2019 09:51 PM
30 Sep, 2019 08:21 AM
29 Sep, 2019 02:02 PM

 

03 Sep, 2019 01:35 AM
24 Aug, 2019 03:14 AM
08 Aug, 2019 04:13 AM
02 Aug, 2019 09:27 PM
18 Jul, 2019 10:05 AM
12 Jul, 2019 10:39 PM