Recursion challenge


I am not sure I understand the issue correctly, but could it be related to the “border” nodes being able to move the same distance of the second ring of nodes?

I don’t know if I implemented it correctly., because It is supposed that no outer node should be higher than an inner node?

But this line treat the first (outer) and second ring of nodes the same:

limit = (neighbors.count * pDragDistance) + 1


Just added an optional line to fix the outer ring distance.
So now, from out-in, each ring will move 1 unit distance.

Please let me know if this is correct or if the outer ring should have a fixed position. In that case we may be able to simplify other functions.

--limit = (neighbors.count * pDragDistance) + 1
limit = (neighbors.count * pDragDistance) + 1 - (mod neighbors[1].count 2)



but, as I said above, there is a problem with the “clamped” affective zone, which causes “holes” in the system:


I also decided to switch to a “weighted” moving algorithm instead of a “cascading” one…
so there will be a lot of changes in the new version.


Yes, I also noticed that, but I assumed it should be that way, because I don’t see a way to fix it (if it needs to be fixed), using the current logic.


Though the same thing. It might be better to weight the nodes, kind of soft selection, but not.

I’ve tried to improve the Update Z Pos Callback, but it is a nightmare of “not working properly” code. I can’t figure out what am I missing, but as usual have that felling that it is much simple than what I think, yet I don’t see it.

So, perhaps Weights is the answer. :+1:


Here is an example of the discontinuity. I was mistaken that it was at the x-axis. In this example, I selected a single object near the center and pulled down to the extent, and that works perfectly. Next, I grabbed the object selected in the image and pulled up. The colored objects behaved correctly, but the conformation should extend recursively so that there isn’t a gap where objects are more than 1 unit from the adjacent ones–as shown between the yellow and grey objects in the image.


In studying the code from @denisT and @PolyTools3D I was able to speed up my original test code. There are many gems in the combined efforts to learn from. Thank you both!

This is the expected functionality:

(red means a grid is at the upper limit, blue is lower limit)


Yes, that’s the same issue Denis and I mentioned. So, how should it be handled?

The problem is that, as you defined, the maximum influence distance, is determined by the distance from the selected node to the outer nodes. Or should any node affect the whole grid, regardless of their distance to the border?

I probably got the idea wrong.


Ah, it appears the node’s influence should go as far as it can, regardless of its distance to the perimeter. That’s a different story. Will check the code. That would prevent the gaps you mentioned.


I apologize for not making that more clear. I was thinking about it recursively, where it’s technically true that each cell has up to only 8 adjacent cells to conform, but if those cells get moved, they each have 8, etc. The way I had it setup with the callback, it was self managing in that regard at least.


it would be good to share the code…


Adding undo skipping helped the speed. Eliminating a finditem also seemed to help. I also changed the when callback parameter to obj from selection. I didn’t profile any of these individually, but the combination makes it work well enough.

Only minor issue now is that the cursor can get far away from where the object is supposed to be limited in height. The object still gets limited to the correct position, it just feels a little janky.

z_min = 0
z_max = 10
delta_z_limit = 1.0

z_pos = (z_max - z_min) * 0.5
x_grid_count = 9
y_grid_count = 21

spacing_x = 5.0
spacing_y = 5.0

function dist_from_edge input_cell axis_count = (
	midpoint = axis_count * .5 +.5
	dist = (midpoint - (abs (input_cell - midpoint) as integer)) as integer

function calc_max_delta x y = (
	-- calculate the maximum height this cell can be based on the dist from the edge
	max_x_delta = (dist_from_edge x x_grid_count) * delta_z_limit
	max_y_delta = (dist_from_edge y y_grid_count) * delta_z_limit
	-- use the lowest value
	max_delta = (z_max - z_min) * 0.5
	if max_x_delta < max_delta then max_delta = max_x_delta
	if max_y_delta < max_delta then max_delta = max_y_delta

function get_xy_from_objname objname = (
	y_grid = (substring objname 7 2) as integer
	x_grid = (substring objname 10 2) as integer


function get_adjacent_objs obj = (
	-- find all the objects within 1 grid cell
	xy_array = get_xy_from_objname
	x_grid = xy_array[1]
	y_grid = xy_array[2]
	--for s in selection do appendifunique selnames
	adjacent_list = #()
	for adj_y = y_grid - 1 to y_grid + 1 do(
		if adj_y > 0 and adj_y <= y_grid_count do(
			for adj_x = x_grid - 1 to x_grid + 1 do(
				if adj_x > 0 and adj_x <= x_grid_count do(
					x_string = (formattedPrint adj_x format:"02d")
					y_string = (formattedPrint adj_y format:"02d")
					adj_name = "Dummy_" + y_string + "_" + x_string		
					if not (adj_x == x_grid and adj_y == y_grid) do( 	-- don't add self
						--if (finditem selnames adj_name) == 0 then( -- don't add selected  -- this is slow
							append adjacent_list adj_name
	for c in adjacent_list collect getnodebyname c

function conform_adj_objs obj adj = (
	-- make sure any adjacent object is within delta_z_limit of the z position
	adj = get_adjacent_objs obj
	zpos = obj.pos.z	
	for a in adj do(
		if a.pos.z < (zpos - delta_z_limit) then(
			a.pos.z = zpos - delta_z_limit
		else if a.pos.z > (zpos + delta_z_limit) then(
			a.pos.z = zpos + delta_z_limit

function limit_z objects_in = (
	with undo off(
		-- set the max height of any grid cell to be no more than delta_z_limit * rows in from perimeter edge
		-- such that the slope of any adjacent object is no more than delta_z_limit
		for obj in objects_in do(
			xy_array = get_xy_from_objname
			max_delta = calc_max_delta xy_array[1] xy_array[2]
			half = (z_max - z_min) * 0.5
			cell_z_max = half + max_delta
			cell_z_min = half - max_delta
			if obj.pos.z > cell_z_max do(
				obj.pos.z = cell_z_max
			if obj.pos.z < cell_z_min do(
				obj.pos.z = cell_z_min
			if not REALTIMEMODE then(
				if obj.pos.z >= cell_z_max then obj.wirecolor = [255,64,64] -- upper limit, set to red
				else if obj.pos.z <= cell_z_min then obj.wirecolor = [64,64,255] -- lower limit, set to blue
					else obj.wirecolor = [0,255,0]
			-- now make sure the adjacent objects conform to the slope of delta_z_limit for the new height
			conform_adj_objs obj adj

function create_helper_array = (
	for y = 1 to y_grid_count do(
		for x = 1 to x_grid_count do(
			x_string = (formattedPrint x format:"02d")
			y_string = (formattedPrint y format:"02d")
			point_name = "Dummy_" + y_string + "_" + x_string
			new_point = point name:point_name = true
			new_point.axistripod = false
			new_point.cross = false
			new_point.wirecolor = [0,255,0]
			new_point.size = spacing_x * .2

			new_point.pos = [(x - 1) * spacing_x,(y - 1) * -spacing_y, z_pos ]
			setTransformLockFlags new_point #{1,2,4,5,6,7,8,9} -- only allow z transform, lock everything else
			when transform new_point changes handleAt: #redrawViews obj  do limit_z obj

delete $*



Some advances, not finished yet. The Grid is 41x41.


That looks really responsive and quick. Very nice.


temporary deleted