How do I pass points to and from a custom node?
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
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
Support Staff 1 Posted by Frederik De Ble... on 13 Nov, 2017 09:11 AM
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.
Support Staff 2 Posted by john on 13 Nov, 2017 12:36 PM
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
Support Staff 3 Posted by Frederik De Ble... on 13 Nov, 2017 01:32 PM
Good to hear!