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
max_delta
)
function get_xy_from_objname objname = (
y_grid = (substring objname 7 2) as integer
x_grid = (substring objname 10 2) as integer
#(x_grid,y_grid)
)
function get_adjacent_objs obj = (
-- find all the objects within 1 grid cell
xy_array = get_xy_from_objname obj.name
x_grid = xy_array[1]
y_grid = xy_array[2]
--for s in selection do appendifunique selnames s.name
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 obj.name
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
)
redrawviews()
--forcecompleteredraw()
)
)
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
new_point.box = 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 $*
clearlistener()
create_helper_array()
```