Radial Sort In Line

I'd like to do a radial sort that apply an change on the first object and then increaingly all the way around till i reach the last object.

Check out the attached image to make more sense.

For example: I have an array of sphere and I'd like to change there diffuse color from white to black based on the radial array. Check out the image to make more sense. For the sake of the image i just did it by hand.

Thanks

JokerMartini

AttachmentSize
radialsort.png24.87 KB

Comments

Comment viewing options

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

And another one.

(
    local theObjects = getCurrentSelection()
    local count = theObjects.count
    local center = [0, 0, 0]
    for obj in theObjects do center += obj.pos
    center /= count
 
    point pos:center
 
    fn angularSort obj1 obj2 =
    in coordSys (transMatrix center)
    (
        local ang1 = atan2 obj1.pos.y obj1.pos.x
        local ang2 = atan2 obj2.pos.y obj2.pos.x
        ang1 - ang2
    )
 
    qsort theObjects angularSort
 
    for i = 1 to count do format "%\n" theObjects[i].name
)

The cross product didn't diffentiate vectors aligned in the same direction or in opposite directions.

Anubis's picture

this is better, thanks

it sort CCW and start from 14 (in my example .max). I modify the code and I'v got sorted CW result from 1 to 18 like this:

(
	local theObjects = getCurrentSelection()
    local count = theObjects.count
    local center = [0, 0, 0]
    for obj in theObjects do center += obj.pos
    center /= count
 
	fn angularSort obj1 obj2 = (
		in coordSys (transMatrix center)
			obj1[3][2][3].value - obj2[3][2][3].value
	)
 
	-- create points (in case the objects has not Z_Rotation controller)
	tmpPoints = for obj in theObjects collect
		Point pos:obj.pos name:(obj.name+"_")
 
	qsort tmpPoints angularSort
 
	sortedArray = #(); sortedArray.count = theObjects.count
	for i = 1 to tmpPoints.count do (
		sortedArray[i] = getNodeByName (trimRight tmpPoints[i].name "_")
	)
 
	delete tmpPoints
	print sortedArray
)

example

AttachmentSize
circarraysort.png 14.35 KB

my recent MAXScripts RSS (archive here)

Garp's picture

Well...

... once the objects are sorted, it's fairly trivial to shift the array and/or reverse it.

Also, this method doesn't care if the objects are in a circular pattern or not, not even if they are planar. It just sorts them by their angle as seen in the XY plane from their averaged position.

Anubis's picture

yes, nice catch

just looking for better way, nm :)

my recent MAXScripts RSS (archive here)

Garp's picture

And another thing.

With your modification, it looks like you're now sorting the objects based on their own rotation instead of their angle from the center.

Garp's picture

Different approach.

(
    local theObjects = getCurrentSelection()
    local count = theObjects.count
    local center = [0, 0, 0]
    for obj in theObjects do center += obj.pos
    center /= count
 
    fn radialSort obj1 obj2 =
        in coordSys (transMatrix center) (cross obj2.pos obj1.pos).z
 
    qsort theObjects radialSort
 
    --check resulting array
    for i = 1 to theObjects.count do format "%\n" theObjects[i].name
)

First a center is determined by averaging all the positions. Then the objects are sorted depending on the sense of rotation as seen from the center.
This is done in the XY plane (rotation around the Z axis).

JokerMartini's picture

alright

alright, ill do that. Quickly testing it is having a problem.

It's mainly just bugging out on this particular line of code.

is there an example scene that i could try testing it on that works for you?

obj1Pos = Point2 sortedArray[1].pos[1] sortedArray[1].pos[2]

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

Anubis's picture

Ok

Attaching a scene file to test it. Note that now I see so my function return correct result only if the objects center match the origin (ie 0,0,0). I like Garp approach (at the first look) but it not return the objects in circular order. In my test scene (with 18 boxes) if they are in CW, s'd been sorted - Box01, Box02 ... Box18, and if CCW - Box01, Box18, Box17 ... Box02. Garp function looks cool but return them in order - 8, 7, 6, 5, 4, 3, 2, 1, 9, 18, 17, 16, 15, 14, 13, 12, 11, 10. Ah, and very strange but if run Garp code line by line - the result is different - start with 17, next 16, 15, ... next to the last 1 and last 18, which is correct order, just start from 17.

AttachmentSize
circarraytester.max 80 KB

my recent MAXScripts RSS (archive here)

JokerMartini's picture

I've discovered why the error

It's erroring out because the array is empty.

I wrote this in (print sortedArray[1] and it is printing undefined.

	for o in objs where o.pos[1] == c[1] and o.pos[2] > c[2] do append sortedArray o
	print sortedArray[1]

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

Anubis's picture

Hi John

I have only one hypothesis about. Because the script get itself 1st object ("at 12 o'clock"), and if it X pos is not equal to the center X pos, then the script will fail. To test if this is the issue, enter in the Listener:
objs = $Sphere* as array;dir = 1
and then execute the code in the function line by line.

my recent MAXScripts RSS (archive here)

Comment viewing options

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