Notifications
Clear all

[Closed] Max Selection – Query

Hello Everyone,

I am just getting too curious to know how max selection makes an array. I have 5 boxes arranged in a line, every time i select them with a Rectangular Region Selection Tool,
and print out the names of the selection Array,
i get different nos, eg:-
Box03
Box04
Box05
Box01
Box02

on next its :

Box02
Box03
Box04
Box05
Box01

why so?? Boxes are arranged in ascending order from Left to Right and I select the same way…

Also if you could tell me what code to write to select the Paint Selection Tool rather than pressing Q to cycle till we get it?

Thank You

Videep

17 Replies

For your second question:
Go to Customize-Customize User Interface and assign a hotkey to Paint Selection Region to turn on paint selection in max.

actionMan.executeAction 0 “59236” – Selection: Paint Selection Region

Thank You Kostadin and Denis.

Really appreciate your help…

@DENIS : How did you get to know that its action number – 59236??
I tried this using macroRecorder and i pressed Q couple of times and ctrl+F also…

Also if you could tell me where these actions are saved and how can i read the code behind them?

Regards,

Videep

In general, the selection contains the objects in the order in which they have been selected. For example, if you have the 5 boxes and none is selected and you hold Ctrl and start clicking them in a specific order, says 3,4,1,5,2, the array will be sorted in that order.
When using the window/crossing methods, it most probably depends on the internal order in which MAX figures out what is in the selection. I haven’t seen that code, so I cannot explain why the results are what they are, but there isn’t much you can do about that part.

What you can do though it reorder the array after the selection has been done, depending on what order you expect to get. You could reorder the objects into their order of creation, you could sort them alphabetically by name, or you could sort them by their X coordinate in screen space to get them left-to-right regardless of where your viewpoint is.

One easy way to reorder them in the order of creation would be to run through the objects list of the scene and collect them again. For example,

theSel = selection as array --this is the original selection array
theSel = for o in objects where findItem theSel o > 0 collect o --this is in creation order

Note that parenting (linking/unlinking) objects changes their order in the objects list. Unlinking a parented object always drops it at the end of the list.

You can reorder the objects alphabetically by name using the sort() or qsort() functions. You cannot apply this to the objects themselves, but you can sort the names. In the case of sort(), you can collect the names of the objects, sort them, then convert the names back to scene nodes. For example

theSel = selection as array
theNames = for o in theSel collect o.name
sort theNames
theSel = for o in theNames collect getNodeByName o

The trouble with this approach is that if you have two objects with the same name, the first one found in the objects list will be resolved by getNodeByName, which might give you the wrong one… But you shouldn’t have duplicated names in your scene anyway.

For using qsort(), you can perform an indexed sort as described in the Help. Collect an array of indices. Then sort it by sending the names of the objects to a sorting function, and at the end recollect the selection array in the order of the sorted index array. This method does not use getNodeByName(), so it won’t be affected by eventual duplicated names. But it is the most complex to understand.
For example,

theSel = selection as array --original selection array
theIndices = for i = 1 to theSel.count collect i --index list from 1 to 5
	
--comparison function  - gets two indices to sort and the array of objects
fn compareFN v1 v2 valArray: = 
(  --it will swap the order if the first object has a greater name than the second
	if valArray[v1].name > valArray[v2].name then 1 else -1
)
qsort theIndices compareFN valArray:theSel --sort the indices using the fn and the array
theSel = for i in theIndices collect theSel[i] --recollect the objects in the order of sorted indices

Similarly, instead of qsorting using the names, you can qsort by the positions of the objects in any coordinate system. In your case, you would have to convert the position of the object into view space, compare the X coordinate and sort by that.
For example,

theSel = selection as array 
theIndices = for i = 1 to theSel.count collect i 
fn compareFN v1 v2 valArray: = 
(
	local theTM = viewport.getTM()
	local val1 = valArray[v1].pos * theTM
	local val2 = valArray[v2].pos * theTM
	if  val1.x > val2.x then 1 else -1
)
qsort theIndices compareFN valArray:theSel 
theSel = for i in theIndices collect theSel[i] 

If you rotate your view at 180 degrees and look from behind the row of boxes, they will be sorted 5,4,3,2,1. If you are looking from the front, you will get 1,2,3,4,5.

Hope this helps.

Thank You So much Bobo…

This was really helpful as I got to know more…

Also If you could tell me if I could anyway get the action man actions and script behind it??

I wrote the following code to reorder my selection according to the X AXIS in one of my previous tools… Can you tell me if I have to do it for 10000 objects, which is faster your code or mine???

CODE: –>
fn ArrangeObjects = (
mySelectedObjects = for o in selection collect o
myObjectPos = for o in mySelectedObjects collect o.pos.x
sortedObjectPos = sort myObjectPos
for i in 1 to sortedObjectPos.count do
(
for j in 1 to mySelectedObjects.count do
(
if sortedObjectPos[i] == mySelectedObjects[j].pos.x then
(
theSortedSelection[i] = mySelectedObjects[j]
)

		)
		
	)
)

Thank You

Regards,
Videep

On my machine, my code, modified to use the word X axis (EDIT: AND OPTIMIZED FOR SPEED) executed in 456 milliseconds for 10K objects.
Your code needed around 192 seconds (over 3 minutes).

Here is my code:

fn ArrangeObjects2 =
(	
local theSel = selection as array 
local theIndices = for i = 1 to theSel.count collect i 
fn compareFN v1 v2 valArray: = 
(
	local res = valArray[v1].pos.x - valArray[v2].pos.x 
	case of
	(
		(res > 0): 1 
		(res < 0): -1
		default: 0
	)
)
qsort theIndices compareFN valArray:theSel 
for i in theIndices collect theSel[i] 
)	
	
st = timestamp()	
ArrangeObjects2()
format "% ms
"	(timestamp()-st)

Your code assumes that each X is unique, which in my test wasn’t the case (I had 100 rows of 100 objects, so there were 100 objects with the same X for each X).

You would have to mark the objects you have found already as processed to avoid collecting the last object found 100 times for the same position. And you should be stopping the inner loop as soon as you find a match in order to collect the first match, not the last, and shorten the loop. So it is possible to make it faster. Even better, findItem() can perform the inner loop in C++ so it would be even faster.

Here is a variation:

fn ArrangeObjects = (
        local mySelectedObjects = for o in selection collect o
        local myObjectPos = sort (for o in mySelectedObjects collect o.pos.x)
		local theSortedSelection = #()
		for o in mySelectedObjects do
		(
			local theIndex = findItem myObjectPos o.pos.x
			theSortedSelection[theIndex] = o
			myObjectPos[theIndex] = undefined
		)
		theSortedSelection
    )
	
st = timestamp()	
ArrangeObjects()
format "% ms
"	(timestamp()-st)

The above code executed in 550 milliseconds.

Hey Thanks Bobo…

I now learn how to save time(which is very important in my new job)…

and that’s the difference between the professional and the Rookie…

Thanks once Again…


fn ArrangeObjects3 = 
(
	struct npos (node, pos)
	
	nodes = for node in objects as array collect npos node:node pos:node.pos.x
	fn sortbyX n1 n2 = if (n1.pos < n2.pos) then -1 else if (n1.pos > n2.pos) then 1 else 0
	qsort nodes sortbyX
	for node in nodes collect node.node
)

st = timestamp()	
ArrangeObjects3()
format "% ms
"	(timestamp()-st)

~250 ms on my machine for 10K objects.

1 Reply
(@bobo)
Joined: 11 months ago

Posts: 0

Me like!
I got consistently 210 ms on my machine.

Oh Thats another nice way to do it… Great…
Thank You Denis…

Can you also put some light on how to get through ActionMan and the script behind it???

Regards,

Videep

1 Reply
(@denist)
Joined: 11 months ago

Posts: 0
Page 1 / 2