[Closed] Spline shape Select
I’m back with another question.
Is there an easier way of selecting objects that would intersect a spline? Along a path.
For example I draw a spline shape across a floor and then select the spline shape and ideally hit “select” and as a result it selects the objects which lay on the spline. It would be nice to somehow step along the line that way the collected objects are in order from front to back.
I’ve thought of a few different solutions.
-
Create spheres along the path which have the same radius as the spline shape, then collect objects who test true for “intersects”
-
Do a volume select using a snapshot of the spline shape, then test the vert selection count and if true collect the object.
-
Use some math and calculate the distance of each knot to the center point of each object and if it falls within the range of the Spline radius then collect it.
pros/cons
-
solution 1 is quick and dirty, but has more setup with generating spheres along a spline path. This would work better with a large amount of objects, (3000)
-
solution 2, slow with large amounts of objects when adding volume select and testing vert selection
-
solution 3, seems ideal!
getting there. Solution 3 works very well surprisingly. Now I’ve gotta think of a good way to pick a point along the spline based on a sampling amount and use that to test for objects along the path. Anyone have any ideas?
Use below code with test scene in zip posted above.
fn fnSubdivide web idx steps = (
for subD = 1 to steps do
(
for s in (numSegments web idx) to 1 by - 1 do
(
knot = subdivideSegment web idx s 1
)
)
)
sp = copy $Line001
range = sp.render_thickness --diameter
clearlistener()
_objArr = for o in objects where superclassof o == GeometryClass collect o
_starters = #()
fnSubdivide sp 1 3
for i = 1 to (numKnots sp 1) do
(
knot = getKnotPoint sp 1 i
for o in _objArr do
(
if (distance o.center knot) <= range do
(
appendIfUnique _starters o
)
)
)
delete sp
r1 = random 1 3
r2 = random 1 3
for i = 1 to _starters.count do
(
val = [0,0,0]
val[r1] = i*10
val[r2] = i*10
_starters[i].wirecolor = val
)
Sample points along the curve (with interpCurve3D for example), find distance from sampled point to tile, find smallest distance, then divide it by Distance custom attribute and clamp to 0 – 1. And do it all in tile’s script controller, scale for example. Use result as uniform scale.
The funny thing is that it updates realtime right in viewport when you’re moving spline or tiles except when you’re moving vertices. But adding dependsOn solves this.
seems like it is not available for download to see how he is doing it?
[QUOTE=JokerMartini]
fn checkIntersects spline threshold:0.1 sel:on =
(
nodes = geometry as array
intersected = #()
s = (curveLength spline 1)*threshold/2
b = dummy name:"_intersect" boxsize:[s,s,s]
for k=0.0 to 1.0 by threshold do
(
b.pos = lengthInterp spline k
for n=nodes.count to 1 by -1 where intersects b nodes[n] do
(
append intersected nodes[n]
deleteitem nodes n
)
)
delete b
if sel do if intersected.count == 0 then clearselection() else select intersected
intersected
)
/*
checkIntersects $Line001 threshold:0.01
*/
this is another idea based on mesh boolean operation… any intersected geometries has to change the topology different way than just simple attach:
fn meshCkeckIntersects spline threshold:0.1 sel:on = undo off
(
nodes = geometry as array
intersected = #()
sp = copy spline
sp.render_displayRenderMesh = on
sp.render_viewport_rectangular = on
sp.render_thickness = threshold
mesh = snapshotasmesh sp
numfaces = mesh.numfaces
empty = trimesh()
for node in nodes do
(
m = snapshotasmesh node
m += trimesh()
update m
num = m.numfaces
m += copy mesh
if m.numfaces != (num + numfaces) do append intersected node
-- format "% + % = % ? %
" num numfaces (num + numfaces) m.numfaces
delete m
)
delete sp
delete mesh
if sel do if intersected.count == 0 then clearselection() else select intersected
intersected
)
/*
meshCkeckIntersects $Line001 threshold:0.1
*/
ps. the spline has to be moved lower…
Denis, thank you for showed us a very interesting solutions.
In John example, something like:
$Line.pos.z = nodes[i].center.z
I assume that Jonah Hawk in his video demonstration use similar method (like your first solution) and than apply to inersection nodes scale controller?
Check this out.
It works great and fast. The only downside is that it doesn’t seem to order the objects from the beginning of the spline to the end of the spline as well as the first example i did. Which i need them to be in order of the spline. Maybe you guys will have some ideas.
try(destroyDialog ::rlShapeOrder)catch()
rollout rlShapeOrder "Shape Order"
(
local theShape = undefined
fn fnShapeFilter obj = superclassof obj == Shape
fn fnShapeOrder = (
if theShape != undefined and isValidNode theShape do
(
_pathObjs = #()
_testObjs = for o in objects where superclassof o == GeometryClass collect o
range = sp.render_thickness --diameter
for o in _testObjs do
(
nodeCenter = o.center
pt = nearestPathParam theShape 1 nodeCenter steps:10 -- find the closest path parameter to the point obj.pos
x = pathInterp theShape 1 pt -- now find the point on the curve using parameter P
result = distance nodeCenter x
if result <= range do (appendIfUnique _pathObjs o)
)
--//wirecolor
r1 = random 1 3
r2 = random 1 3
for i = 1 to _pathObjs.count do
(
val = [0,0,0]
val[r1] = i*10
val[r2] = i*10
_pathObjs[i].wirecolor = val
)
)
)
label lbRedObjEdge "" style_sunkenedge:true width:162 height:24 pos:[7,10]
button btnClearRefObj "X" width:26 height:22 pos:[142,11]
pickbutton pbRefObj "Pick Reference Shape" width:134 height:22 pos:[8,11] filter:fnShapeFilter
button btnShapeOrder "Order Selection"width:160 height:30 pos:[10,40]
on pbRefObj picked obj do
(
theShape = if obj != undefined then obj else undefined
pbRefObj.text = if obj != undefined then obj.name else "Pick Reference Shape"
)
on btnClearRefObj pressed do
(
theShape = undefined
pbRefObj.text = "Pick Reference Shape"
)
on btnShapeOrder pressed do
(
fnShapeOrder()
)
)
createDialog rlShapeOrder 180 80 style:#(#style_SysMenu, #style_ToolWindow)
main calculating portion
nodeCenter = o.center
pt = nearestPathParam theShape 1 nodeCenter steps:10 -- find the closest path parameter to the point obj.pos
x = pathInterp theShape 1 pt -- now find the point on the curve using parameter P
result = distance nodeCenter x
if result <= range do (appendIfUnique _pathObjs o)
Is there a way to take the total length of the spline and then inch along the spline looking for objects close to it.
It’s looks promising. In line 13 change range = sp.render_thickness with
range = theShape.render_thickness.
The rest is all good. I don’t know what you plan next but i have an idea.
Maybe you can animate cracks along the path, something like this Procedural Surface Collapse.
But is better to use push method to move fragments in XY direction not z.