Skip to main content
decreasing the haystack
Source Link
Markus von Broady
  • 48.6k
  • 3
  • 44
  • 129

Resolution based sorting (pre B3.4)

Since there's another thread about sorting:

Sort points by distance from object (expanded: sort any field)

I decided it would be nice to include the solution of jst kiko so this thread is complete. However, in order to not just steal his answer, I decided to improve it to allow for multiple vertices on the same x, which requires resigning from Merge by Distance.

Since it's resolution based, the original geometry can be snapped into equal increments, and those can be scaled to be integers - this way X coordinate can be used as a Group Index in Accumulate Field to count similar X values. An additional copy of original geometry is arranged in stacks with differing Y coordinate which stores local index per stack and therefore allows for a second sorting criterion - original index. This allows to snap new vertices as in jst kiko's answer, but instead of removing overlapping vertices, remove only the excess - then snap again, this time using the stacks and supplying current local index as Y in source position.

Step 1

On the left, calculate the X coordinate by mapping the original range of this coordinate to the 0..resolution range. Then round it to the nearest integer.

On the bottom, just reposition the vertices using this rounded-integer X, and change YZ to 0.

On the top, additionally take advantage of the coordinate being an integer, and count how many vertices land on this X. Use Trailing as Y coordinate, which is a local index of this stack. Use Capture Attribute, otherwise the Accumulate Field would be recalculated later for the new positions.

Step 2

Spawn a mesh line with resolution number of verts. Position it in the same range as the one in Map Range output in the step 1. Delete edges. Since I don't use Geometry Proximity node like jst kiko, edges don't need to be removed - still, because some vertices will be removed, if you need edges, you have to add another step at the end where you recreate the mesh line and transfer calculated positions onto it.

Snap each vertex of this "high resolution line" onto the nearest point of the original geo (with x converted to integers and YZ=0). Save that x coordinate to avoid recalculating it later. This x allows you to target the stack. Just like in step 1, calculate local index on this stack and also save it. Now search for a vert on X=stack X; Y=local index - either you find a vertex exactly there and read associated vertex'es index, or you aim too far on Y, and read last stack's vertex'es index.

Step 3

Use the obtained index of the vertex, to read the size of the stack this vertex is in. Now check if currently evaluated local index is too high foroutdated answers that stack - if so, remove it, as it's one ofwould unnecessarily bury (possibly extremely manycurrently) excess vertices. Finally use the obtained index to transfer position fromobjectively the original-original, untouched input geometry.

Ending remarks

The obvious flaw of this approach is that you don't know what resolution you need in order to produce correct output. If your resolution is too low, not enough verts from middle green framebest "high definition mesh line" will be snapped on a stack. For example, if your geometry is a default plane with the edges subdivided, so each original edge is made of 100 verts, there's 100 verts on x=-1, and 2 verts on x=-0.98answer by quellenform. Therefore "high definition mesh line" needs 100 verts closer toYou can still access this answer by reading the former, at a coordinate lower than x=-0.99. So 100 verts for each 0.01, totalling 2/0.01 * 100 + 1 = 20'001 resolution.

The good news is that Suzanne lvl 2 with 7'956 vertices takes "only" 205'000 resolution to not lose any vertex in sorting, which takes only 60 ms to evaluate on my PC (ideally quellenform will measure on his PC for consistency with other tests). Resolution of 2 million takes 360 ms. 20 million: 3559 msprevious revision.

Resolution based sorting

Since there's another thread about sorting:

Sort points by distance from object (expanded: sort any field)

I decided it would be nice to include the solution of jst kiko so this thread is complete. However, in order to not just steal his answer, I decided to improve it to allow for multiple vertices on the same x, which requires resigning from Merge by Distance.

Since it's resolution based, the original geometry can be snapped into equal increments, and those can be scaled to be integers - this way X coordinate can be used as a Group Index in Accumulate Field to count similar X values. An additional copy of original geometry is arranged in stacks with differing Y coordinate which stores local index per stack and therefore allows for a second sorting criterion - original index. This allows to snap new vertices as in jst kiko's answer, but instead of removing overlapping vertices, remove only the excess - then snap again, this time using the stacks and supplying current local index as Y in source position.

Step 1

On the left, calculate the X coordinate by mapping the original range of this coordinate to the 0..resolution range. Then round it to the nearest integer.

On the bottom, just reposition the vertices using this rounded-integer X, and change YZ to 0.

On the top, additionally take advantage of the coordinate being an integer, and count how many vertices land on this X. Use Trailing as Y coordinate, which is a local index of this stack. Use Capture Attribute, otherwise the Accumulate Field would be recalculated later for the new positions.

Step 2

Spawn a mesh line with resolution number of verts. Position it in the same range as the one in Map Range output in the step 1. Delete edges. Since I don't use Geometry Proximity node like jst kiko, edges don't need to be removed - still, because some vertices will be removed, if you need edges, you have to add another step at the end where you recreate the mesh line and transfer calculated positions onto it.

Snap each vertex of this "high resolution line" onto the nearest point of the original geo (with x converted to integers and YZ=0). Save that x coordinate to avoid recalculating it later. This x allows you to target the stack. Just like in step 1, calculate local index on this stack and also save it. Now search for a vert on X=stack X; Y=local index - either you find a vertex exactly there and read associated vertex'es index, or you aim too far on Y, and read last stack's vertex'es index.

Step 3

Use the obtained index of the vertex, to read the size of the stack this vertex is in. Now check if currently evaluated local index is too high for that stack - if so, remove it, as it's one of (possibly extremely many) excess vertices. Finally use the obtained index to transfer position from the original-original, untouched input geometry.

Ending remarks

The obvious flaw of this approach is that you don't know what resolution you need in order to produce correct output. If your resolution is too low, not enough verts from middle green frame "high definition mesh line" will be snapped on a stack. For example, if your geometry is a default plane with the edges subdivided, so each original edge is made of 100 verts, there's 100 verts on x=-1, and 2 verts on x=-0.98. Therefore "high definition mesh line" needs 100 verts closer to the former, at a coordinate lower than x=-0.99. So 100 verts for each 0.01, totalling 2/0.01 * 100 + 1 = 20'001 resolution.

The good news is that Suzanne lvl 2 with 7'956 vertices takes "only" 205'000 resolution to not lose any vertex in sorting, which takes only 60 ms to evaluate on my PC (ideally quellenform will measure on his PC for consistency with other tests). Resolution of 2 million takes 360 ms. 20 million: 3559 ms.

Resolution based sorting (pre B3.4)

This is one of outdated answers that would unnecessarily bury (currently) objectively the best answer by quellenform. You can still access this answer by reading the previous revision.

Source Link
Markus von Broady
  • 48.6k
  • 3
  • 44
  • 129

Resolution based sorting

Since there's another thread about sorting:

Sort points by distance from object (expanded: sort any field)

I decided it would be nice to include the solution of jst kiko so this thread is complete. However, in order to not just steal his answer, I decided to improve it to allow for multiple vertices on the same x, which requires resigning from Merge by Distance.

Since it's resolution based, the original geometry can be snapped into equal increments, and those can be scaled to be integers - this way X coordinate can be used as a Group Index in Accumulate Field to count similar X values. An additional copy of original geometry is arranged in stacks with differing Y coordinate which stores local index per stack and therefore allows for a second sorting criterion - original index. This allows to snap new vertices as in jst kiko's answer, but instead of removing overlapping vertices, remove only the excess - then snap again, this time using the stacks and supplying current local index as Y in source position.

Step 1

On the left, calculate the X coordinate by mapping the original range of this coordinate to the 0..resolution range. Then round it to the nearest integer.

On the bottom, just reposition the vertices using this rounded-integer X, and change YZ to 0.

On the top, additionally take advantage of the coordinate being an integer, and count how many vertices land on this X. Use Trailing as Y coordinate, which is a local index of this stack. Use Capture Attribute, otherwise the Accumulate Field would be recalculated later for the new positions.

Step 2

Spawn a mesh line with resolution number of verts. Position it in the same range as the one in Map Range output in the step 1. Delete edges. Since I don't use Geometry Proximity node like jst kiko, edges don't need to be removed - still, because some vertices will be removed, if you need edges, you have to add another step at the end where you recreate the mesh line and transfer calculated positions onto it.

Snap each vertex of this "high resolution line" onto the nearest point of the original geo (with x converted to integers and YZ=0). Save that x coordinate to avoid recalculating it later. This x allows you to target the stack. Just like in step 1, calculate local index on this stack and also save it. Now search for a vert on X=stack X; Y=local index - either you find a vertex exactly there and read associated vertex'es index, or you aim too far on Y, and read last stack's vertex'es index.

Step 3

Use the obtained index of the vertex, to read the size of the stack this vertex is in. Now check if currently evaluated local index is too high for that stack - if so, remove it, as it's one of (possibly extremely many) excess vertices. Finally use the obtained index to transfer position from the original-original, untouched input geometry.

Ending remarks

The obvious flaw of this approach is that you don't know what resolution you need in order to produce correct output. If your resolution is too low, not enough verts from middle green frame "high definition mesh line" will be snapped on a stack. For example, if your geometry is a default plane with the edges subdivided, so each original edge is made of 100 verts, there's 100 verts on x=-1, and 2 verts on x=-0.98. Therefore "high definition mesh line" needs 100 verts closer to the former, at a coordinate lower than x=-0.99. So 100 verts for each 0.01, totalling 2/0.01 * 100 + 1 = 20'001 resolution.

The good news is that Suzanne lvl 2 with 7'956 vertices takes "only" 205'000 resolution to not lose any vertex in sorting, which takes only 60 ms to evaluate on my PC (ideally quellenform will measure on his PC for consistency with other tests). Resolution of 2 million takes 360 ms. 20 million: 3559 ms.