Remove instances from array of objects - feedback please


#1

So - let’s say a scene contains lots of instances of objects and say you don’t want to loop over already processed objects again and again, what would you do? This is probably a very naive approach but I think it does what I need it to.

Just curious what you all think - any potential problems? Is it not a scalable solution because I’m copying arrays?

(
    fn removeInstancesFromArray arr =
    (
        local objsToProcess = deepCopy arr
        for obj in arr where (InstanceMgr.GetInstances obj &instances) > 1 do
        (
            -- remove all clones except for one from objsToProcess
            for clonedObjCount = 2 to instances.count do
            (
                local index = (findItem objsToProcess instances[clonedObjCount])
                if index > 0 then deleteItem objsToProcess index
            )
        )
        objsToProcess
    )

    fn createTestScene =
    (
        resetMAXFile()
        tp = Teapot()
        tp1 = instance tp
        tp2 = instance tp

        s = Sphere()
        s1 = instance s
        s2 = instance s
    )

    createTestScene()
    select objects

    format "selection as array: %\n" (selection as array)
    local arrayWithoutInstances = removeInstancesFromArray (selection as array)
    format "arrayWithoutInstances: %\n" arrayWithoutInstances

    /*
        output:
            selection as array: #($Teapot:Teapot001 @ [0.000000,0.000000,0.000000], $Teapot:Teapot002 @ [0.000000,0.000000,0.000000], $Teapot:Teapot003 @ [0.000000,0.000000,0.000000], $Sphere:Sphere001 @ [0.000000,0.000000,0.000000], $Sphere:Sphere002 @ [0.000000,0.000000,0.000000], $Sphere:Sphere003 @ [0.000000,0.000000,0.000000])
            arrayWithoutInstances: #($Teapot:Teapot003 @ [0.000000,0.000000,0.000000], $Sphere:Sphere003 @ [0.000000,0.000000,0.000000])
        */

    -- now I'm ready to process array of unique objects without going over instances unnecessarily ...
)

#2

I have added two functions written by denisT and posted in the forum a while ago.

(
    fn removeInstancesFromArray arr =
    (
        local objsToProcess = deepCopy arr
        for obj in arr where (InstanceMgr.GetInstances obj &instances) > 1 do
        (
            -- remove all clones except for one from objsToProcess
            for clonedObjCount = 2 to instances.count do
            (
                local index = (findItem objsToProcess instances[clonedObjCount])
                if index > 0 then deleteItem objsToProcess index
            )
        )
        objsToProcess
    )
	
	--	find all instanc and reference objects
	function FindInstance n =
	(
		allInsts = #()
		for obj in n do
		(
			if (InstanceMgr.GetInstances obj &instances) > 1 do
			(
				if findItem allInsts obj == 0 do
					join allInsts instances
			)
		)
		--	remove the parsed object from the instantes list
-- 		if allInsts.count > 1 do
-- 		(
-- 			if (idx = findItem allInsts n) != 0 do
-- 			(
-- 				deleteItem allInsts idx
-- 			)
-- 		)
		--	
		allInsts
	)
	--	FInd one of each instance
	fn uniqueNodes nodes: = 
	(
		if nodes == unsupplied do nodes = objects as array

		local handles = #{}
		for node in nodes where not handles[GetHandleByAnim node] collect
		(
			InstanceMgr.GetInstances node &inst
			for i in inst do handles[GetHandleByAnim i] = on
			node
		)
	)

    fn createTestScene =
    (
        resetMAXFile()
        tp = Teapot()
        tp1 = instance tp
        tp2 = instance tp

        s = Sphere()
        s1 = instance s
        s2 = instance s
    )

    createTestScene()
    select objects

    format "selection as array: %\n" (selection as array)
--     local arrayWithoutInstances = removeInstancesFromArray (selection as array)
	local arrayWithoutInstances = uniqueNodes nodes:(selection as array)
    format "arrayWithoutInstances: %\n" arrayWithoutInstances

    /*
        output:
            selection as array: #($Teapot:Teapot001 @ [0.000000,0.000000,0.000000], $Teapot:Teapot002 @ [0.000000,0.000000,0.000000], $Teapot:Teapot003 @ [0.000000,0.000000,0.000000], $Sphere:Sphere001 @ [0.000000,0.000000,0.000000], $Sphere:Sphere002 @ [0.000000,0.000000,0.000000], $Sphere:Sphere003 @ [0.000000,0.000000,0.000000])
            arrayWithoutInstances: #($Teapot:Teapot003 @ [0.000000,0.000000,0.000000], $Sphere:Sphere003 @ [0.000000,0.000000,0.000000])
        */

    -- now I'm ready to process array of unique objects without going over instances unnecessarily ...
)

#3

Thank you! I googled but couldn’t find anything, and I specifically googled for denisT too but didn’t turn up any search results.

This is modifying the criteria for what to collect as it’s going through the loop? Clever