Exit loop when bitarray stops changing

Become a member of the CGSociety

Connect, Share, and Learn with our Large Growing CG Art Community. It's Free!

THREAD CLOSED
 
Thread Tools Search this Thread Display Modes
Old 03 March 2013   #1
Red face Exit loop when bitarray stops changing

I'm trying to figure out how the best method for exiting a loop after a bitarray stops changing. For example if I'm growing a selection until it fills up the mesh's elements, I could grow to the total number of verts, edges, or faces getting the selection before you grow, and exit when the numberset of the current selection equals the numberset of the previous selection. I think using a for loop is the only way to go for this, but I'm not 100 percent sure. I was curious if anyone knows a better / faster method for this.

Here's a function using this method, which converts an edge selection to borders in editable mesh, by growing the edge selection once, and intersecting it with all open edges. -


 	fn GetBordersUsingEdgeMesh Obj:$ Sel:(getEdgeSelection $) = 
 	(
 		local AllBorderSel = (meshop.getOpenEdges Obj)
 		local BorderSel = (Sel * AllBorderSel) -- Select within borders
 		for i = 1 to (Obj.numFaces * 3) do
 		(
 			local OldNum = BorderSel.numberset -- Get past selection
 			BorderSel += ((meshop.getEdgesUsingVert Obj (meshop.getVertsUsingEdge Obj BorderSel)) * AllBorderSel) -- Grow edge selection once within border
 			if (BorderSel.numberset == OldNum) then exit -- Exit if selection doesn't change
 		) -- Convert edges to border
 		return BorderSel -- Get edges
 	)
 


It seems to work ok, but I'm thinking there has to be a more efficient way..
 
Old 03 March 2013   #2
It may be worth have a While loop and omitting the 'if' test that currently exits the loop. You already have the variable assignment necessary, so it'd basically be (pseduocode)

while BorderSel.numberset != OldNum do
(
grow border stuff
)

This way you avoid the (according to the maxscript documentation) slow 'exit' process, as well as save on generating the variable 'i' that it appears you actually don't need (though you could do this by simply omitting the 'i=' entirely - you can, I believe, simply do 'for 1 to 10 do' etc).
__________________

 
Old 03 March 2013   #3
Or, if you want to stay with for loop use this:

fn GetBordersUsingEdgeMesh Obj:$ Sel:(getEdgeSelection $) = 
	 (
		 local AllBorderSel = (meshop.getOpenEdges Obj)
		 local BorderSel = (Sel * AllBorderSel) -- Select within borders
		stopLoop = false
		 for i = 1 to (Obj.numFaces * 3) while stopLoop == false do
		 (
			 local OldNum = BorderSel.numberset -- Get past selection
			 BorderSel += ((meshop.getEdgesUsingVert Obj (meshop.getVertsUsingEdge Obj BorderSel)) * AllBorderSel) -- Grow edge selection once within border
			 if (BorderSel.numberset == OldNum) do  stopLoop = true
		 ) -- Convert edges to border
		 return BorderSel -- Get edges
	 )
 
Old 03 March 2013   #4
the method itself is OK but Obj:$ Sel:(getEdgeSelection $) is very bad for many reasons...
 
Old 03 March 2013   #5
Originally Posted by denisT: the method itself is OK but Obj:$ Sel:(getEdgeSelection $) is very bad for many reasons...

no... the method is also wrong.
 
Old 03 March 2013   #6
Originally Posted by denisT: the method itself is OK but Obj:$ Sel:(getEdgeSelection $) is very bad for many reasons...

Hi Denis, can you explain why this concept in not good
I supose that this is also bad
...Obj:$ Sel:($.selectededges as array)
__________________
Looking in the right side. [bgaTools]
 
Old 03 March 2013   #7
Originally Posted by gazybara: Hi Denis, can you explain why this concept in not good
I supose that this is also bad
...Obj:$ Sel:($.selectededges as array)

the idea is stop loop when edge collection stopped grow. right? but we check only size (numberset) of this collection. but there's possible topology when growing border edges doesn't change the number of new border edges. for example when you grow edges from pole of a sphere. got it?
 
Old 03 March 2013   #8
fn growEdgesToBorder node edges: show:on = if iskindof node editable_mesh or iskindof node trimesh do
(
	if edges == unsupplied do edges = node.selectededges as bitarray
	local 
		ee = #{},
		border = edges,
		opened = meshop.getopenedges node
	
	while not (border - ee).isEmpty do
	(
		ee = border
		border = edges - opened
		edges = meshop.getedgesusingvert node (meshop.getvertsusingedge node edges)
		border = edges - border
	)
	if show do node.selectededges = border
	border
)

any smarter solution is welcome...

Last edited by denisT : 03 March 2013 at 07:04 PM.
 
Old 03 March 2013   #9
Originally Posted by denisT: the idea is stop loop when edge collection stopped grow. right? but we check only size (numberset) of this collection. but there's possible topology when growing border edges doesn't change the number of new border edges. for example when you grow edges from pole of a sphere. got it?

Thanks Denis for the explanation and example. I don't think there is better solution.
Is it better(fester) to use meshOp and polyOp operations outside for-loop and while-loop as variable?
__________________
Looking in the right side. [bgaTools]
 
Old 03 March 2013   #10
Originally Posted by gazybara: Thanks Denis for the explanation and examle. I don't think there is better solution.
Is it better(fester) to use meshOp and polyOp operations outside for-loop and while-loop as variable?

it's better to local... not faster but saves a lot of memory
i didn't do it the sample to not confuse rookies...

so the pro version might look as
fn growEdgesToBorder node edges: show:on = if iskindof node editable_mesh or iskindof node trimesh do
(
	if edges == unsupplied do edges = node.selectededges as bitarray
	local 
		ee = #{},
		border = edges,
		opened = meshop.getopenedges node,
	
		getedgesusingvert = meshop.getedgesusingvert,
		getvertsusingedge = meshop.getvertsusingedge
	
	while not (border - ee).isEmpty do
	(
		ee = border
		border = edges - opened
		edges = getedgesusingvert node (getvertsusingedge node edges)
		border = edges - border
	)
	if show do node.selectededges = border
	border
) 

Last edited by denisT : 03 March 2013 at 07:40 PM.
 
Old 03 March 2013   #11
meshop.getedgesusingvert
meshop.getvertsusingedge

these particular functions don't really leak much, but in general it's safer to put any interface function in a local variable and call it from there.
I posted several samples on this forum which show the difference.
 
Old 03 March 2013   #12
Originally Posted by denisT: meshop.getedgesusingvert
meshop.getvertsusingedge

these particular functions don't really leak much, but in general it's safer to put any interface function in a local variable and call it from there.
I posted several samples on this forum which show the difference.

Yep. I already saw a few. Cheers!
__________________
Looking in the right side. [bgaTools]
 
Old 03 March 2013   #13
Wow, thanks for all the replies guys! And thanks denis for the examples.

I've noticed the assignment of operations to variables in the reference before, and I can definitely see the performance gain with that. I also didn't think about cases where your selection is outside of open borders, which would lead to an empty selection that wouldn't grow. I still think though that cases where the edge selection is on a pole would still grow, I don't see why it wouldn't.

One thing I don't understand is why using default values for node and the edge selection are bad, that's what I've used for all of my functions and their inputs, is default values, so I don't always need to specify them. Is specifying the default value in the function a lot safer?

Again, thanks for your help everyone.
 
Old 03 March 2013   #14
Originally Posted by Ian31R: One thing I don't understand is why using default values for node and the edge selection are bad, that's what I've used for all of my functions and their inputs, is default values, so I don't always need to specify them. Is specifying the default value in the function a lot safer?

look at what you have:
fn GetBordersUsingEdgeMesh Obj:$ Sel:(getEdgeSelection $)

i said there are reasons that make it bad... check yourself:
# what if noting selected
# what if multiple selection
# what if not an editable mesh selected

of course you can use default values for additional arguments and do it, but be sure that these values don't break the function before it goes to execution.

if you are absolutely sure that the function can never be called with wrong values where is a reason to give it defaults. does it make sense?
 
Old 03 March 2013   #15
Well I usually check for if an object is selected and if there are subobjects selected, I forgot to put the checks in this function. Although I should put in a check for multiple node selections.I haven't worried about checking the class of the the node in most of my functions, because I plan on checking that later, when I call the functions, depending on what the user has selected. That's also why I put Mesh at the end of the function name, so I know what its used for.

Having defaults in the functions just seems more flexible to me. Especially for functions that have a lot of parameters, and can do many different things. Its nice to not have to specify all of the parameters all the time.
 
Thread Closed share thread



Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

vB code is On
Smilies are On
[IMG] code is On
HTML code is Off
CGSociety
Society of Digital Artists
www.cgsociety.org

Powered by vBulletin
Copyright ©2000 - 2006,
Jelsoft Enterprises Ltd.
Minimize Ads
Forum Jump
Miscellaneous

All times are GMT. The time now is 05:12 AM.


Powered by vBulletin
Copyright ©2000 - 2017, Jelsoft Enterprises Ltd.