Notifications
Clear all

[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.

  1. Create spheres along the path which have the same radius as the spline shape, then collect objects who test true for “intersects”

  2. Do a volume select using a snapshot of the spline shape, then test the vert selection count and if true collect the object.

  3. 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!

28 Replies

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
)

3 Replies
 3ak
(@3ak)
Joined: 11 months ago

Posts: 0

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.

(@gazybara)
Joined: 11 months ago

Posts: 0

That’s it. Thanks 3ak.
John are you find the answer?

 3ak
(@3ak)
Joined: 11 months ago

Posts: 0

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.

link leads me no where…?

1 Reply
(@gazybara)
Joined: 11 months ago

Posts: 0

Try now.Sorry for that

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…

1 Reply
(@gazybara)
Joined: 11 months ago

Posts: 0

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.

Page 1 / 3