There can potentially be a lot (size^3) of voxels to check against so it might be slow, since we need to do it for each segment again and again.
Something like this might work for excluding the rest of the voxels, but it is good for short/orthogonal segments only ( compared to grid size ). Long diagonal segment ruins all the optimization we can get this way.
_min = GridIndexFromPoint (seg_pt1 - [ searchRadius, searchRadius, searchRadius ])
_max = GridIndexFromPoint (seg_pt2 + [ searchRadius, searchRadius, searchRadius ])
for z = _min.z to _max.z do
for y=_min.y to _max.y do
for x=_min.x to _max.x do
...
Anyway. Here’s some quick mxs code to play with if anyone is interested.
Capsule node linked to two dummies to help visualize what voxels are actually intersected at certain distance.
upd added voxel growth
try (destroydialog ShowIntersectionsRollout ) catch ()
rollout ShowIntersectionsRollout "" (
CheckButton showIntesections "show voxel intersections" width:150
fn ShowIntersectionPoints =
(
if ::GridIntersectionPoints != undefined do
(
gw.setTransform (matrix3 1)
for pt in GridIntersectionPoints do
(
gw.Marker pt #smallHollowBox color:yellow
)
)
)
on ShowIntersectionsRollout open do unregisterRedrawViewsCallback ShowIntersectionPoints
on showIntesections changed state do
(
if state then
(
unregisterRedrawViewsCallback ShowIntersectionPoints
registerRedrawViewsCallback ShowIntersectionPoints
) else unregisterRedrawViewsCallback ShowIntersectionPoints
redrawViews()
)
on ShowIntersectionsRollout close do unregisterRedrawViewsCallback ShowIntersectionPoints
)
fn VoxelTraversal pt_start pt_end size:1.0 intersections: maxcount:50 =
(
dirr = pt_end - pt_start
dir = normalize dirr
local visited_voxels = #()
current_voxel = [ floor ( pt_start.x / size ), floor ( pt_start.y / size ), floor ( pt_start.z / size ) ]
last_voxel = [ floor ( pt_end.x / size ), floor ( pt_end.y / size ), floor ( pt_end.z / size ) ]
format "FROM % TO %\n" current_voxel last_voxel
vec = pt_end - pt_start
stepX = if vec.x >= 0 then 1 else -1
stepY = if vec.y >= 0 then 1 else -1
stepZ = if vec.z >= 0 then 1 else -1
next_voxel_boundary_x = (current_voxel.x + stepX) * size;
next_voxel_boundary_y = (current_voxel.y + stepY) * size;
next_voxel_boundary_z = (current_voxel.z + stepZ) * size;
if stepX < 0 do next_voxel_boundary_x += size
if stepY < 0 do next_voxel_boundary_y += size
if stepZ < 0 do next_voxel_boundary_z += size
tMaxX = if vec.x != 0 then (next_voxel_boundary_x - pt_start.x) / vec.x else 1e10
tMaxY = if vec.y != 0 then (next_voxel_boundary_y - pt_start.y) / vec.y else 1e10
tMaxZ = if vec.z != 0 then (next_voxel_boundary_z - pt_start.z) / vec.z else 1e10
tDeltaX = if vec.x != 0 then size / vec.x * stepX else 1e10
tDeltaY = if vec.y != 0 then size / vec.y * stepY else 1e10
tDeltaZ = if vec.z != 0 then size / vec.z * stepZ else 1e10
diff = [0, 0, 0]
append visited_voxels (copy current_voxel)
count = 0
while (last_voxel != current_voxel) and count < maxcount do
(
count += 1
if (tMaxX < tMaxY) then
(
if (tMaxX < tMaxZ) then
(
intersection_point = pt_start + tMaxX * dirr
if intersections != unsupplied do append intersections intersection_point
current_voxel.x += stepX;
tMaxX += tDeltaX;
)
else
(
intersection_point = pt_start + tMaxZ * dirr
if intersections != unsupplied do append intersections intersection_point
current_voxel.z += stepZ;
tMaxZ += tDeltaZ;
)
)
else
(
if (tMaxY < tMaxZ) then
(
intersection_point = pt_start + tMaxY * dirr
if intersections != unsupplied do append intersections intersection_point
current_voxel.y += stepY;
tMaxY += tDeltaY;
)
else
(
intersection_point = pt_start + tMaxZ * dirr
if intersections != unsupplied do append intersections intersection_point
current_voxel.z += stepZ;
tMaxZ += tDeltaZ;
)
)
append visited_voxels (copy current_voxel)
)
visited_voxels
)
deleteAllChangeHandlers id:#gridUpdate
resetMaxFile #noprompt
max tool maximize
delete objects
delete helpers
gc()
viewport.SetGridVisibility viewport.activeViewport false
mtl = Standardmaterial opacity:1.0
mtl2 = Standardmaterial opacity:0.5
R = 6.0 -- voxel search radius
p1 = dummy pos:[2.42709,37.7306,51.936]
p2 = dummy pos:[55,65,45]
c = Capsule radius:R sides:8 name:#tmppt parent:p1 wirecolor:green
c.pivot += [0,0,c.radius]
c.pos = p1.pos
c.rotation.controller = LookAt_Constraint()
c.rotation.controller.target_axis = 2
c.rotation.controller.appendTarget p2 100.0
c.rotation.controller.upnode_axis = 1
c.material = mtl
dist_ctl = float_script()
dist_ctl.addNode "p1" p1
dist_ctl.addNode "p2" p2
dist_ctl.script = "distance p1.pos p2.pos"
c.height.controller = dist_ctl
c.rotation.controller.lookat_vector_length.controller = dist_ctl
CELL_SIZE = 10.0
MIN = [0,0,0]
DIMENSIONS = [10,10,10]
BOUNDS = (DIMENSIONS*CELL_SIZE)
EXPAND = 1
box width:BOUNDS.x length:BOUNDS.y height:BOUNDS.z pos:(MIN + [BOUNDS.x * 0.5, BOUNDS.y * 0.5,0]) wirecolor:green isfrozen:true showFrozenInGray:off boxmode:true
VOXELS = #()
VOXELS_COUNT = int (DIMENSIONS.x * DIMENSIONS.y * DIMENSIONS.z)
for z=1 to DIMENSIONS.z do
(
for y=1 to DIMENSIONS.y do
(
for x=1 to DIMENSIONS.x do
(
b = box width:CELL_SIZE length:CELL_SIZE height:CELL_SIZE pos:(MIN + [CELL_SIZE,CELL_SIZE,CELL_SIZE] * [x-1,y-1,z-1] + [CELL_SIZE * 0.5, CELL_SIZE * 0.5,0]) wirecolor:yellow material:mtl2 isfrozen:true showFrozenInGray:off ishidden:true
append VOXELS b
)
)
)
fn GetVoxelIndex index size =
(
1 + index.x + index.y * size.x + index.z * size.x * size.y
)
fn UpdateGRID =
(
times = [0,0,0,0]
t2 = timestamp()
try ( hide ::VOXELS ) catch()
times[1] += timeStamp() - t2
t2 = timestamp()
::GridIntersectionPoints = #()
intersected_voxels = VoxelTraversal p1.pos p2.pos size:CELL_SIZE intersections:GridIntersectionPoints
times[1] += timeStamp() - t2
processed_cells = #{}
for rawindex in intersected_voxels do
(
t2 = timestamp()
indexes = #()
for z=-EXPAND to EXPAND do
( for y=-EXPAND to EXPAND do
( for x=-EXPAND to EXPAND do
(
index = ([x,y,z] + rawindex)
if not (index.x < 0 or index.x >= DIMENSIONS.x or index.y < 0 or index.y >= DIMENSIONS.y or index.z < 0 or index.z >= DIMENSIONS.z) do
(
cell_index = GetVoxelIndex ([x,y,z] + rawindex) DIMENSIONS
append indexes cell_index
)
)
)
)
times[3] += timeStamp() - t2
t2 = timestamp()
unhide (
for index in indexes where not processed_cells[ index ] and index <= VOXELS_COUNT collect
(
processed_cells[ index ] = true
VOXELS[index]
)
)
times[4] += timeStamp() - t2
)
format "1. %\n2. %\n3. %\n4. %\n" (times[1]/1000 as float) (times[2]/1000 as float) (times[3]/1000 as float) (times[4]/1000 as float)
)
when transform c changes id:#gridUpdate do UpdateGRID()
UpdateGRID()
createDialog ShowIntersectionsRollout