bordering points of 2d point cloud?

This is traditionally via code / math a pretty complex problem to solve for, given a set of coordinates, finding the bordering points.

From what I’ve researched alpha hull’s and convex hulls are algorithms used in graphic design to do this but implementing these have been a bit beyond my abilities, and most examples seem to be very library heavy.

[url]http://www.enviral-design.com/blog/wp-content/uploads/2015/10/getBorder.png[/url]

Anyone have any ideas on a clever way to approach this problem that plays to touch’s strengths?
doesn’t have to be fast or real time, more just a matter of getting it to work somehow.

Thanks in advance!
Lucas
getBorderSmall.jpg

Not really an accurate solution, but if you use a copy SOP (or instancing) to render a large
polygon at each point, you might then capture the more ‘solid’ image in a render TOP, or
OP Viewer TOP, and use a Trace SOP to get the outline (assuming no interior holes).
The boundary will be bumpy and not line up with your original points, but will give you
a rough approximation.

Hey Rob, thanks for the suggestion, I was contemplating something similar with the edge TOP but I got somewhat stuck on generating some kind of triangulated mesh from the point set that didn’t look terrible.

The closest I got was using the ray SOP to shrink wrap a grid SOP to the points using nearest, but that left a lot of stretched triangles that caused the silhouette to be incorrect.

I tried to delete certain triangles via certain criteria like distance from neighboring points but nothing was really clean enough :confused:

I stumbled across a library I’ve not used before though: SciPy. A library that seems to have the tools already made to do exactly what I need built right in!

docs.scipy.org/doc/scipy-0.14.0/ … aunay.html
and
gist.github.com/hellpanderrr/2c … eed4782234

may just do it, have yet to test this out but will report back with how things go.

Its an interesting problem.

Does the solution need to be interactive/realtime?
If not, you could probably take your time with an executing Script SOP,
using Delaunay triangulation on the mesh points.
Likely several python solutions already out there I assume as well, or you could implement in a C++ CHOP.

Once its triangulated, you can use the Group SOP, Edges tab to select unshared edges.

Let me know what you come up with!

Rob

These still require filling in a bit of missing trig, but they look promising:

en.wikipedia.org/wiki/Gift_wrap … Pseudocode
(todo: determine if a point is on left or right side of a line)

or

en.wikipedia.org/wiki/Graham_scan#Pseudocode
(todo: sort a set of points by angle formed with another point).

If anyone’s up for the challenge.

Okay, got sucked into this problem :slight_smile:

Attached is a Script SOP implementation of the Graham Scan.
I may have an off-by-one error somewhere, but seems to work well from initial observation:
graham_bounds.1.toe (6.1 KB)

Woa! that’s pretty amazing, I haven’t even heard of those two algorithms, I like them, much easier to wrap my art brain around :smiley:

Thanks for the help on that, that works perfectly for convex hulls, which unfortunately as I’m finding out is only half the battle for the effect I’m going for…

What I’m actually doing with this is trying to come up with a way to mask the edges of led panels that have been mapped as points. the geometric panels are modular and several might form a larger cluster, that when viewed as a silhouette can form concavities, sometimes…

Sadly, the convex hull skips over these, so it doesn’t provide the desired effect in all situations.

Been working on this the last two days and not making much progress so THANK YOU!
I now have a planB, if concave doesn’t work, I can run this on a per panel basis and at least get a per panel outline that should work perfectly.

Lucas

Also, it’s ironic you pointed out the Group SOP’s ability to select unshared edges… that’s exactly the thing I’ve been stuck on all morning with scipy implementation.

I’ve managed to calculate the Delauney triangulation as an array of triangle coordinates, but having trouble getting unshared edges, which marks the boundary edge.

Two problems still with this though is :
A) I have to talk to another python process outside of touch because of library version issues for numpy/sciPy
B) I don’t believe that even if I get the border edges/points that they will be ordered to form a loop or multiple loops, but that might be doable with some simple path finding algorithm?

Will try this out and keep posted.

So a little progress, I got the library working and generated this delauney mesh:

closer!
currently, each triangle by means of the script sop is a separate poly, so there are lots of overlapping identical points, and nothing is actually connected.

This is my code in the script SOP:

[code]triList = op(“triList”)
def cook(scriptOp):
scriptOp.clear()

for x in range(triList.numRows):
	triPoints = [float(triList[x,0].val),float(triList[x,1].val),float(triList[x,2].val),float(triList[x,3].val),float(triList[x,4].val),float(triList[x,5].val)]
	#print(triPoints)
	poly = scriptOp.appendPoly(3)
	#poly = scriptOp.appendPoly(3, closed=True)
	p = poly[0].point
	p.x = triPoints[0]
	p.y = triPoints[1]

	p = poly[1].point
	p.x = triPoints[2]
	p.y = triPoints[3]

	p = poly[2].point
	p.x = triPoints[4]
	p.y = triPoints[5]
return[/code]

So how do I go from here, to a connected mesh?

I know it has something to do with points and vertices, but I’m still a bit fuzzy on the distinction between the two.

Are vertices references to 1 or more points?

I’ve attached the resulting toe with a locked SOP that was generated.
unconnectedFaces.1.toe (19.8 KB)

So what is the answer you’re looking to achieve in that specific case?
A single path/poly that outlines a thick letter ‘C’ ?
[EDIT: Or are you looking for 5 squares?]

A vertex is a reference to a single point.
Multiple vertices can all refer to the same point (shared vertices).

Since the squares are separated by a specified amount they’d be considered separately, but if they were within that threshold then ideally they’d be treated as one big unit.

I can see that with the script SOP I can add a polygon to the sop of N length, assuming that’s points. I can also see from your example how you can specify a polygon by making a loop, but if you want to create a tessellated surface with interconnected points, like the grid SOP is that possible?
Is there a way to define primitives and vertex’s on top of that?

ok! progress, but still not quite there.

I attached a file that illustrates the error I’m getting now.
I’m trying to do what was described in this thread:
[url]python-appendPoly with points=false crashes, example needed - #4 by vinz99 - General TouchDesigner Discussion - TouchDesigner forum

  1. Essentially I’m creating the points that were in the original mesh

  2. then iterating through triangle table, creating a poly for each tri.

  3. I leave addPoints=False, so that i can set vertex <> point reference right after

  4. I try to set point reference but I get error saying “td.error: Invalid Vertex object.”

Is this a bug? Or am I using it wrong?
I dug around in the wiki for a while trying to piece it together, but there’s not a whole bunch of info at the point/vertex/prim/poly level so I might have mis understood something.

Here’s the cook() script for reference as well:

[code]def cook(scriptOp):
scriptOp.clear()
listOfPointObjects = []

# create the points in a first pass, so that we don't have duplicates.
for point in range(triangulateThis.numRows):
	# Create and move points, then append to master list of point objects for later reference.
	pt = scriptOp.appendPoint()
	pt.x = triangulateThis[point,0]
	pt.y = triangulateThis[point,1]
	listOfPointObjects.append(pt)

# Now that points are made, iterate through triangles table and create polys / vert references to the existing point table.
for x in range(triList.numRows):
	
	# query point indicies from tri list (contains references to master point list)
	pt1 = int(triList[x,0].val)
	pt2 = int(triList[x,1].val)
	pt3 = int(triList[x,2].val)
	
	# create a single triangle poly, with out making new points.
	poly = scriptOp.appendPoly(3, closed=True, addPoints=False)
	
	# assign correct points to recently made poly. (This is doesn't work) 
	poly[0].point = pt1
	poly[1].point = pt2
	poly[2].point = pt3

return

[/code]

Lucas
issueWithScriptSop.2.toe (14.3 KB)

Hey! I just wanted to bump this thread - I’m so very close to a working solution and I’d be happy to upload that here after I get this working too :slight_smile:

Really just stuck on assigning point references to vertex’s - issue attached in last post. Any help would be massively appreciated!

Lucas

Hi Lucas.
As just mentioned in the other thread, the vertex issue is now fixed in the next upcoming build (56080+). You’ll still have to assign points to the vertex.point members, not ints though.

Just to be clear though, would the previous example outputting 5 squares be the solution you’re looking for?

Rob,
Thanks again!

That previous example with 5 squares is an example layout I ripped straight from the network I’m working on. Of course the layout could be literally anything, those squares might be edge to edge in a long rectangle too, and then the edge of the whole cluster would need to get highlighted instead.

That distinction between islands I’m planning to handle with some threshold logic using the area of each triangle and deleting ones that are too big.

Then after that getting the bordering points using the SOP method you mentioned should result in exactly what I need I think