[Closed] Mini-Challenge #3
found a way! (but still not so stable)
struct progUpdater (
count,
current = 0,
pb,
fn increment =
(
current += 1
pb.value = 100 * current / count
)
)
global pbManager
struct hcNode (
val = 0,
left,
right,
obj,
count = 1,
verts = 0,
fn init =
(
if obj != undefined then
val = obj.numVerts
else (
if left != undefined then (
val += left.val
val += right.val
verts = left.verts + right.verts + left.val + right.val
count = left.count + right.count
)
)
),
fn mergeChildren =
(
local att = meshop.attach
if left != undefined then (
local a = left.mergeChildren()
local b = right.mergeChildren()
left = undefined
right = undefined
att a b
obj = a
verts += val
) else
pbManager.increment()
obj
),
start = init()
)
fn sortByVertNum a b =
(
a.val - b.val
)
fn insertInPlace arr new start: end: =
(
if end - start < 0 then
append arr new
else if end - start == 0 then (
if arr[start].val > new.val then
insertItem new arr start
else
insertItem new arr (start + 1)
) else (
local i = amin (start + (end - start) / 2) (end - 1)
if arr[i].val > new.val then
insertInPlace arr new start:start end:i
else if arr[i].val < new.val then
insertInPlace arr new start:(i + 1) end:end
else
insertItem new arr i
)
)
struct treeMonitor (
roots,
next = 0,
count = 0,
source,
occupied = false,
fn getRoot =
(
next += 1
occupied = false
roots[next]
),
fn mergeRoots =
(
local att = meshop.attach
for o in roots do
att source o.obj
source = mesh mesh:source
convertTo source Editable_Poly
),
fn done =
(
count += 1
if count == roots.count then
mergeRoots()
redrawViews()
)
)
global hcMergeTreeFN
fn hcMergeTreeFN =
(
global hcTreeMonitor
if hcTreeMonitor != undefined then (
hcTreeMonitor.occupied = true
local root = hcTreeMonitor.getRoot()
root.mergeChildren()
hcTreeMonitor.done()
)
)
fn foo source nodes pb:pb1 =
(
local numThreads = 10 --sysInfo.cpuCount
local nodeArr = #()
for o in nodes do (
append nodeArr (hcNode obj:(snapshotAsMesh o))
delete o
)
qsort nodeArr sortByVertNum
while nodeArr.count > numThreads do (
local left = nodeArr[1]
local right = nodeArr[2]
deleteItem nodeArr 2
deleteItem nodeArr 1
local new = hcNode left:left right:right
insertInPlace nodeArr new start:1 end:nodeArr.count
)
local count = 0
for o in nodeArr do (
count += o.count
verts += o.verts
)
pbManager = progUpdater count:count pb:pb1
global hcTreeMonitor = treeMonitor roots:nodeArr source:(snapshotAsMesh source)
delete source
for i = 1 to numThreads do (
local newWorker = dotnetObject "System.ComponentModel.BackGroundWorker"
dotNet.addEventHandler newWorker "DoWork" hcMergeTreeFN
while hcTreeMonitor.occupied do ()
newWorker.RunWorkerAsync()
)
hcTreeMonitor.source
)
fn customAttach source nodes pb:pb1 =
(
count = nodes.count
foo source nodes pb:pb1
)
Interestingly enough, about 60% of the execution time when doing the whole thing with meshes, is the conversion back to poly in the end.
I’ve managed to get some scene interaction with background worker, by disabling ref messages.
Perhaps this could be used towards the attach algorithm.
Example:
workers = #()
fn createBox = box()
fn complete s e =
(
deleteItem workers (findItem workers s)
if workers.count==0 do enablerefmsgs()
)
disablerefmsgs()
for i = 1 to 8 do
(
local worker = dotnetObject "System.ComponentModel.BackGroundWorker"
dotNet.addEventHandler worker "DoWork" createBox
dotnet.addeventhandler worker "RunWorkerCompleted" complete
append workers worker
worker.RunWorkerAsync()
)
result: 8 boxes created, max doesn’t crash
i think that any max scene change or max UI change can be done in the same as application thread only. that means there is no way to do these operations using multithreading.
Here is a time to show my variant of fast attach. I call it “Caster” (don’t ask me why).
My idea is to have as less as possible number of updates. The ideal algorithm has to attach every time the nodes with minimum number of vertices. So we have to sort the node array every time before attach.
QSORT is very slow if we do it for every iteration of the loop. I’m using .net Sort (sorting second array using first as keys).
Also I don’t use deleteItem (which is also slow for big arrays).
I’m using GetHandleByAnim (to make .net array) and GetAnimByHandle (to speed up access to node’s pointer in an array).
As you can see my algorithm works much faster in situation where we have to attach small boxes to one high-poly box. Without sorting the cluster method has the similar problem as the max Linear method.
check the code and play with parameters…
Here is an optimized version of my version without the multithreading stuff.
It does the same thing Denis’s casterAttach method do but without the need of sorting the array (with or without dotnet’s help) every time and it looks like it works at the same speed if not a bit faster then the caster method.
The idea is taken from the Huffman code algorithm. At first I sort the objects once by vertex count, then I take the first 2 objects in the sorted array, attach them and delete them from the array. Now I use the insertInPlace function to insert a new object created from the 2 attached objects in it’s correct place in the array using a binary search technique. I repeat these steps until the array holds only 1 object. I also make sure I remember which object was originally the source to make sure it doesn’t get deleted.
Anyhow Denis’s method is still very cool and I learned some new stuff from it, tanks for that!
fn sortByVertNum a b =
(
a.val - b.val
)
struct s_Node (
obj,
val,
isSource = false,
fn init =
(
val = obj.numVerts
),
start = init()
)
fn insertInPlace arr new start: end: =
(
if end - start < 0 then
append arr new
else if end - start == 0 then (
if arr[start].val > new.val then
insertItem new arr start
else
insertItem new arr (start + 1)
) else (
local i = amin (start + (end - start) / 2) (end - 1)
if arr[i].val > new.val then
insertInPlace arr new start:start end:i
else if arr[i].val < new.val then
insertInPlace arr new start:(i + 1) end:end
else
insertItem new arr i
)
)
fn huffmanAttach source nodes pb:pb1 =
(
nodes = for o in nodes collect s_Node obj:o
append nodes (s_Node obj:source isSource:true)
qsort nodes sortByVertNum
local att = polyop.attach
local n = nodes.count
while nodes.count > 1 do (
if nodes[2].isSource then
swap nodes[1] nodes[2]
att nodes[1].obj nodes[2].obj
local newNode = s_Node obj:nodes[1].obj isSource:nodes[1].isSource
deleteItem nodes 2
deleteItem nodes 1
insertInPlace nodes newNode start:1 end:nodes.count
pb.value = 100.0 * (1.0 - 1.0 * nodes.count / n)
verts += newNode.val
)
)
fn customAttach source nodes pb:pb1 =
(
count = nodes.count
huffmanAttach source nodes pb:pb1
source
)
well… the Party Of Math Lovers won.
http://forums.cgsociety.org/showthread.php?f=98&t=985724