Notifications
Clear all

[Closed] Fast way to get loop end edges/verts?

So I’m trying to go through an array of selected edges, on an Edit_Poly modifier, and find the ones which are attached to only 0-1 other selected edges. Unfortunately I’ve found doing this is extremely slow using the method posted below (processing just 3000 edges takes 4-5 seconds on my PC), and was wondering if there was a better method anyone could suggest?

objMod = modpanel.getCurrentObject()
allSelEdgesBIT = objMod.getSelection #Edge
allSelEdges = allSelEdgesBIT as array

gc()
t1 = timeStamp()
endEdges = #()
endVerts = #()
for edj in allSelEdges do (
    edjVrts = #((objMod.GetEdgeVertex edj 1), (objMod.GetEdgeVertex edj 2))
    endVrts = #()
    for vrt in edjVrts do (
        vrtEdjs = for i=1 to (objMod.GetVertexEdgeCount vrt) collect (objMod.GetVertexEdge vrt i)
        selVrtEdjs = ((vrtEdjs as bitarray) * allSelEdgesBIT)
        if selVrtEdjs.numberset == 1 do append endVrts vrt
    )
    if endVrts.count != 0 do ( append endEdges edj ; append endVerts endVrts )
)
format "maxscript\nresult:%\ntime:% ms\n" test (timeStamp() - t1)
--4608 ms for 3000 edges on Edit_Poly
21 Replies

How fast is this:

(
	objMod = modpanel.getCurrentObject()
	allSelEdgesBIT = objMod.getSelection #Edge
	allSelEdges = allSelEdgesBIT as array
	
	gev = objMod.GetEdgeVertex
	gevc = objMod.GetVertexEdgeCount
	gve = objMod.GetVertexEdge

	gc()
	t1 = timeStamp()
	endEdges = #()
	endVerts = #()
	for edj in allSelEdges do 
	(
		edjVrts = #((gev edj 1), (gev edj 2))
		endVrts = #()
		for vrt in edjVrts do 
		(
			gvec = (gevc vrt)
			vrtEdjs = for i=1 to gvec collect (gve vrt i)
			selVrtEdjs = ((vrtEdjs as bitarray) * allSelEdgesBIT)
			if selVrtEdjs.numberset == 1 do append endVrts vrt
		)
		if endVrts.count != 0 do ( append endEdges edj ; append endVerts endVrts )
	)
	format "maxscript\nresult:%\ntime:% ms\n" test (timeStamp() - t1)
)

Whoa! 0_0

I think you just blew my mind there Miauu. I can hardly believe assigning the commands like that gave such a massive performance boost; from 4608ms all the way down to 49ms. That’s just crazy.

Thank you so much, this will definitely be useful not just for this script but for many others in the future as well!

Glad to help.

yes… it’s known trick. it speeds up the method dramatically.

but check your algorithm –

you test all edges vertexes for “end” condition. but if you already know from previous edge that one of verts an “end” or not “end” vert what is the reason to test same verts again for another edge? so, potentially you can make your algorithm about two times faster for general case by changing the logic

here is another point of optimization:

(
	t0 = timestamp()
	h0 = heapfree

	for k=1 to 10000 do
	(
		a = #()
		append a 2
		append a 1000
		a as bitarray
	)

	format "time:% heap:%\n" (timestamp() - t0) (h0 - heapfree)
)
(
	t0 = timestamp()
	h0 = heapfree

	for k=1 to 10000 do
	(
		a = #{}
		append a 2
		append a 1000
	)

	format "time:% heap:%\n" (timestamp() - t0) (h0 - heapfree)
)
(
	t0 = timestamp()
	h0 = heapfree

	for k=1 to 10000 do
	(
		a = #{2, 1000}
	)

	format "time:% heap:%\n" (timestamp() - t0) (h0 - heapfree)
)

it might give you another 1.5-2 times of acceleration

Hey DenisT, I tried a few different methods to optimize the script further based on your advise, and was able to get it down to about 37ms (from 49ms) using this approach:

(
	objMod = modpanel.getCurrentObject()
	allSelEdgesBIT = objMod.getSelection #Edge
    allSelEdges = allSelEdgesBIT as array
    
    gev = modFullName.GetEdgeVertex
    gvec = modFullName.GetVertexEdgeCount
    gve = modFullName.GetVertexEdge
    
    gc()
    t1 = timeStamp()
    allEdjVrts = #{} ; for edj in allSelEdges do ( join allEdjVrts #{(gev edj 1), (gev edj 2)} )
    combinedEnds = #() --Each sub-array looks like this: #(endVertIndex, endEdgeIndex)
    checkedVrts = #()
    for vrt in allEdjVrts do (
        if (finditem checkedVrts vrt == 0) do (
            vrtEdjs = (for i=1 to (gvec vrt) collect (gve vrt i)) as bitarray
            selEdjs = vrtEdjs * allSelEdgesBIT
            if selEdjs.numberSet == 1 do (
                selEdj = (selEdjs as array)[1]
                selEdjVrts = #{(gev selEdj 1), (gev selEdj 2)}
                remainingVrt = ((selEdjVrts - #{vrt}) as array)[1]
                append combinedEnds #(vrt, selEdj)
                append checkedVrts remainingVrt
            )
        )
    )
    format "maxscript\nresult:%\ntime:% ms\n" test (timeStamp() - t1)
)

I don’t think I’ll be able to optimize it any further, but thankfully this is already easily fast enough for the purposes I intend to use it for. Thanks again guys for the help

make a test setup that we all be able to play under the same settings

ok … i made it:

delete objects
gc()

bx = box widthsegs:32 lengthsegs:32 heightsegs:32 name:#test isselected:on
ep = Edit_Poly()
addmodifier bx ep
max modify mode
modPanel.setCurrentObject ep

nume = ep.GetNumEdges()
numv = ep.GetNumVertices()
seed 0
ee = #{}
for k=1 to (nume/2) do append ee (random 1 nume)  

subobjectlevel = 2
ep.Select #edge ee 
ep.ButtonOp #SelectEdgeLoop
ep.Select #edge ee invert:on

now try any on the methods (find end edges), and give us the time and memory usage numbers

Ok, tried it. With 7508 edges selected;

First method: 11555 ms , heap size of -3152L
Second method: 191 ms, heap size of 1147880L
Third method: 103 ms, heap size of 3534192L

Heap size was all over the place during repeat testing, but was always much higher for the faster methods.

1 Reply
(@denist)
Joined: 11 months ago

Posts: 0

i updated my function to decrease memory usage

Page 1 / 2