Distance Align Then Distribute

I would like a script that does two things with the option of doing both or each individually.

It is just like the Distribute tools for layers in Photoshop.

Example: You have a scene with a handful of objects that you want to distribute.

http://www.scriptspot.com/files/distance.png

Option 1: The script takes the selected objects and without moving/adjusting the end objects (which would be the two objects furthest from each other) the script would align them all. Think of it as if you made a straight line between the 2 end objects and then moved each object in between to match that line.

http://www.scriptspot.com/files/distancealign.png

Option 2: Would take all the objects except for the 2 end objects and then evenly distribute those objects along the virtual line that would be drawn between the 2 end objects. Which would result in all the objects being evenly space apart based on there pivot or bounding box.

http://www.scriptspot.com/files/distancedistribute.png

Thanks
JokerMartini

AttachmentSize
distance.png40.81 KB
distancealign.png40.78 KB
distancedistribute.png39.9 KB

Comments

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.
JokerMartini's picture

This is what I was looking for.

you'll have to make two objects as your start and end and the run the script on the selected objects. It is not a streamline thing just yet but I wanted to show you what i wrote as where i was going with this.

Make sure your start object is at 0,0,0

(
	local EndObj = $end
	local StartObj = $start
	local userSel = $Sphere003
	local averageVal = [0,0,0]
	local userSel = selection as array
 
	fn averagePos startVal endVal =
	(
		userSel = getCurrentSelection()
		averageVal += (startVal.position + endVal.position) ; averageVal /= (userSel.count+1)
	)
 
	if userSel.count > 0 do
	(
		Val = averagePos StartObj EndObj
		for i = 1 to selection.count do
		(
		   Obj = selection[i]
			print Val
		   Obj.position = [(Val.x*i),(Val.y*i),(Val.z*i)]
		)
 
	  completeRedraw()
	)
)

John Martini
Digital Artist
http://www.JokerMartini.com (new site)

Swordslayer's picture

This is exactly the same as

This is exactly the same as the alignAndDistribute2 function if passed the type:#evenly argument with the exception that here you have to specify one object extra (and have one object at [0,0,0] coordinates) and as you don't sort the objects, they're aligned not based on their positions but rather their positions in the selection array (i.e. you get random results depending on the way you select them. As for finding out both the "border" nodes, in some sitations it could work, but those would be quite special. You have to pick at least one object as the starting one - that's what I did. I'm not sure if you tried the function, be sure to do it and then we can discuss what you think is missing/not working as you imagined.

Swordslayer's picture

Here you go:

Here you go:

fn alignAndDistribute obj_arr distr_line type:#closest =
(
	obj_nr = obj_arr.count
 
	case type of
	(
		#closest:
		(
			fn pointLineProj pA pB pC =
			(
				local vAB = pB - pA
				local vAC = pC - pA
				local d = dot (normalize vAB) (normalize vAC)
				(pA + (vAB * (d * (length vAC/length vAB))))
			)
 
			for objs in obj_arr do
			(
				new_pos = (pointLineProj (getKnotPoint distr_line 1 1) (getKnotPoint distr_line 1 2) objs.pos)
				objs.pos = new_pos
			)
		)
		#evenly:
		(
			local start_pos = getKnotPoint distr_line 1 1
			local point_dist = (getKnotPoint distr_line 1 2 - getKnotPoint distr_line 1 1)/(obj_nr + 1)
			struct geom_item (obj, dist)
 
			fn compareDist obj1 obj2 =
				obj1.dist - obj2.dist
 
			dist_arr = for g in obj_arr collect geom_item obj:g dist:(distance g.pos start_pos)
 
			with redraw off
       			qsort dist_arr compareDist
 
			for objs in dist_arr do
			(
				start_pos += point_dist
				objs.obj.pos = start_pos
			)
		)
	)
)

Pass it some objects, a line (to keep it simple, it has to have 2 knots and 1 spline to work as expected) and distribution type. When object will be "out of the range" of the line (i.e. somewhere else than the other objects), the sorting may give unexpected results, but for the situation on your pictures, it will work. PointLineProj function implementation comes from prettyPixel.

Example usage: alignAndDistribute (selection as array) my_line type:#evenly

Swordslayer's picture

Well, looking at it again,

Well, looking at it again, looks like I should learn to read first :) Anyway, if you want to use it for object collection without a line, use this version instead:

fn alignAndDistribute2 obj_arr start_node type:#closest =
(
	obj_nr = obj_arr.count
	local start_pos = start_node.pos, end_pos, point_dist
	struct geom_item (obj, dist)
 
	fn compareDist obj1 obj2 =
		obj1.dist - obj2.dist
 
	dist_arr = for g in obj_arr collect geom_item obj:g dist:(distance g.pos start_pos)
 
	with redraw off
		qsort dist_arr compareDist
 
	end_pos = dist_arr[dist_arr.count].obj.pos
	point_dist = (end_pos - start_pos)/obj_nr
 
	deleteItem dist_arr dist_arr.count
 
	case type of
	(
		#closest:
		(
			fn pointLineProj pA pB pC =
			(
				local vAB = pB - pA
				local vAC = pC - pA
				local d = dot (normalize vAB) (normalize vAC)
				(pA + (vAB * (d * (length vAC/length vAB))))
			)
 
			for objs in dist_arr do
			(
				new_pos = (pointLineProj start_pos end_pos objs.obj.pos)
				objs.obj.pos = new_pos
			)
		)
		#evenly:
		(
			for objs in dist_arr do
			(
				start_pos += point_dist
				objs.obj.pos = start_pos
			)
		)
	)
)

Pass it some border object (it's hard to find one programatically in many situations when some coordinates you'd like to test against are the same and so on) and the rest of the objects to be aligned. Now it should be roughly what you wanted in the beginning.

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.