Notifications
Clear all

[Closed] For Loop & functions problem

hi all,

well i just got back into maxscript and i’m trying to get a function to work with in a for loop here is what i have. its been awhile i know this is probably a simple fix but i cant seem to get it to work.

for theMesh in selection do
   convertto $ editable_poly
   function countMuscleCSections = 
   (
   	theMesh.EditablePoly.SetSelection #Edge #{1}
   			
   	theMesh.SelectEdgeRing ()
   		
   	mainCSSelection = (polyOp.getEdgeSelection theMesh) as array
   				
   	return mainCSSelection.count
   )
   
   countMuscleCSections()

i am trying to get it to count the rings and loops of a poly object on the 1st and 2nd edge of a model that was a cylinder but converted to a ploy object so i can recreate a new cylinder with the same hight and length segments.
at this stage it seems to make the variable “theMesh” as undifined.
i m not sure whats going on but it seems not to work when i declare the function if i do it without the fuction it works fine. but i will need to incorperate this into a larger script that works on multiple objects.

any answer would be great.

cheers

john

10 Replies

Here is how MAXScript “sees” your code:


for theMesh in selection do
convertto $ editable_poly

  function countMuscleCSections = 
  (
      theMesh.EditablePoly.SetSelection #Edge #{1}
  theMesh.SelectEdgeRing ()
  mainCSSelection = (polyOp.getEdgeSelection theMesh) as array
  return mainCSSelection.count
  )
  -------------

countMuscleCSections()
————-

So first it finds a for loop which does not make sense:

for theMesh in selection do
convertto $ editable_poly

In this for loop, theMesh is assigned one object from the current selection at a time, but then in the body of the loop you convert to Editable_poly the whole selection.
(Using $ is usually a bad idea anyway).

At this point, the for loop is over because its body is just a single line and there are no parentheses defining a multi-line code block. Thus, the local loop variable theMesh is destroyed and released for garbage collection.

Then MAXScript finds a function definition and evaluates that. This is NOT in the loop’s body and should not be anyway.

Finally, the function call is encountered, also outside of the for loop, and of course theMesh is not defined inside the function because the for loop has long gone and destroyed its local counter variable…

Here is how you would have to do it:

(--start a local scope
  fn countMuscleCSections theMesh =  --pass the mesh as argument
  (
  	theMesh.SetSelection #Edge #{1} --select first edge
  	theMesh.SelectEdgeRing() --select edge ring
  	(polyOp.getEdgeSelection theMesh).numberset --return the number of set bitarray bits 
  )--end fn 
  for theMesh in selection do
  (
  	convertto theMesh editable_poly --collapse to EPoly
  	local theCount = countMuscleCSections theMesh --call the function
  	format "Object % has % Segments
" theMesh theCount --write it out
  )--end loop
  )--end script

thanks bobo much apreciated.

that makes scence i needed it to call the function within the for loop. and make sure my perenthasis where in the right place.
When you declared the the fuction “fn countMuscleCSections theMesh = ” why is “theMesh” nesisary after the fn name? is this just meaning that it will feed that variable through from the for loop?

here is what i did and it works nicely. Thanks a bunch now i can go and finish the rest of the script

(--start a local scope
   fn countMuscleCSections theMesh =  --pass the mesh as argument
   (
 	  theMesh.SetSelection #Edge #{1} --select first edge
 	  theMesh.SelectEdgeRing() --select edge ring
 	  (polyOp.getEdgeSelection theMesh).numberset --return the number of set bitarray bits 
   )--end fn 
   fn countMuscleFSections theMesh =  --pass the mesh as argument
   (
 	  theMesh.SetSelection #Edge #{2} --select second edge
 	  theMesh.SelectEdgeRing() --select edge ring
 	  (polyOp.getEdgeSelection theMesh).numberset --return the number of set bitarray bits 
   )--end fn 
   for theMesh in selection do
   (
 	  convertto theMesh editable_poly --collapse to EPoly
 	  local theCountCS = countMuscleCSections theMesh --call the function
 	local theCountFS = countMuscleFSections theMesh
 	  Cylinder heightsegs:theCountCS sides:theCountFS height:100 radius:10
   
   )--end loop
  
  )--end script

The function exists outside the scope of the for loop. ‘theMesh’ exists only inside the loop and is gone the moment the loop is over. So the function cannot have direct knowledge of the variable ‘theMesh’.
In order to tell the function what is currently the value in the loop variable ‘theMesh’, you can pass that value to the function as a parameter.
The name of the parameter DOES NOT have to be ‘theMesh’, it could be anything as it denotes a local variable in the scope of the function. So it could be ‘param1’, ‘theObjectToOperateOn’ or just ‘a’. I called it theMesh to make it obvious that the value of the for loop is passed to the function and would thus be seen inside the function, but technically speaking ‘theMesh’ in the for loop and ‘theMesh’ in the function are separate local variables (each living in the corresponding scope of the loop resp. function) which will happen to point at the same object in the context of your code.

thanks bobo

ok here my next problem i’m trying to isolate the edge next to edge #{1} but i cant seem to get it. in a cylinder the egde at 90degs is not always edge #{2} so i need to quiry the edges on face #{1}. i have manage to get the array of adges but i cant seem to find a way to select the highest value of the 4 edges selected from the face. as this would be the edge that would be 90deg from the edge #{1}.

i tried the

TheFaceEdges = polyOp.getEdgesUsingFace $cylinder01 #{2} as array

findItem TheFaceEdges 4

but this just gives you a true of false answer. is there anyway of getting at parts of the array?i cant find any split fuctions like python has to get the last number in the array.

any ideas? i tried looking for examples but no luck so far.

cheers

john

TheFaceEdges = (polyOp.getEdgesUsingFace $cylinder01 #{2}) as array
–> #(2, 5, 6, 7)
findItem TheFaceEdges 4 –> 0 –this means the value 4 is not in the array (2,5,6 and 7 are)
TheFaceEdges[TheFaceEdges.count] –> 7 –this is the last value in the array!

Of course, 7 is not the edge you are looking for, because polygon 2 is not the one edge 1 is in.

cool that worked.

my script works fine now i need to finish some error checking but its a script that creates ACT cgMuscles from a poly object. that way you can just model poly objects using poly tools and convert them later.

if you get a chance to read through my script let me know if i could or should do things differnetly here it is so far. if you creat a cylinder or sphere and modify it. then run the script it needs to have all quads if it has nonQuads it will delete those faces. you’ll need ACT plugin to run it of course.

--john Van Der Zalm 2007
   --email: john@kaffeineproductions.com
   --version 0.4
   
   --ChangeLog
   --fixed - max crashes because the cgMuscle has to meny or to little verts.
   --This is a hack function and it it will delete any polygon with more or less then 4 sides using cylinders as starting meshes is the best way to start
    
   
   (--start a local scope
     
     fn deleteNonQuads theMesh =
     (
   	local face_selection = #{}
   	local num_faces = polyop.getNumFaces theMesh
   	for f = 1 to num_faces do
   	(
   		local num_face_verts = polyop.getFaceDeg theMesh f
   	
   		if num_face_verts != 4 do face_selection[f] = true
   	)--end f loop3
   	polyop.setFaceSelection theMesh face_selection
   	max modify mode
   	subobjectlevel = 4
   	theMesh.EditablePoly.delete #Face
     )--end fn
     fn countMuscleCSections theMesh =  --pass the mesh as argument
     (
   	  theMesh.SetSelection #Edge #{1} --select first edge
   	  theMesh.SelectEdgeRing() --select edge ring
   	  (polyOp.getEdgeSelection theMesh).numberset --return the number of set bitarray bits 
     )--end fn 
     fn countMuscleFSections theMesh =  --pass the mesh as argument
     (
   	theMesh.SetSelection #Edge #{1}
   	theMesh.SelectEdgeloop()
   	(polyOp.getEdgeSelection theMesh).numberset
     )--end fn 
     for theMesh in selection do
     (
   	convertto theMesh editable_poly --collapse to EPoly
   	local delNonQuads = deleteNonQuads theMesh --calls the function for deleting all nonQuads
   	local theCountCS = countMuscleCSections theMesh --call the function to count crossections
   	local theCountFS = countMuscleFSections theMesh --call the function to count fibers
   	actCreateMuscle theCountCS theCountFS --creates the cgmuscle01 
   	$cgMuscle01.transform = theMesh.transform
   	theMeshsnap = snapshotAsMesh theMesh
   	for v = 1 to theMeshsnap.numverts by 1 do 
   	(
   		vertposition = meshop.getVert theMeshsnap v * inverse theMesh.transform
   		
   		actSetMusclePoint $cgMuscle01 1 v(vertposition)
   	)
   	$cgMuscle01.name = theMesh.name + "_CGmuscle"
     )--end loop
    

now i’m trying to get it to search the scene to make sure there is no scene object called cgMuscle01 as unfortunatly by default it makes the cgmuscle with that name and you have no name option i think to create it with a spacific name.

so i tried

for obj in objects do
   (
   	fn isCGmuscle obj=
   	(
   		if obj.Name is == "cgMuscle01" then return true else return false
   	)
   	
   	if isCGmuscle is == true then
   	(
   		print "please rename cgMuscle01"
   	)
   	else 
   	(
   		print "continue"
   	)
   )

this dosent seem right anyway i was trying to find a way to get it to just go through the objects and if it comes to a object with the name cgMuscle01 then it = true. and then call a diologue to warn the user to rename it to proceed.

cheers

john

1 Reply
(@bobo)
Joined: 11 months ago

Posts: 0

You don’t need a loop for that. Accessing a specific scene object as a path will return the object if it exists and undefined if it does not. Thus,

isValidNode $cgMuscle01 –> true if the object exists, false if it does not.

So you can say

if isValidNode $cgMuscle01 do $cgMuscle01.name = uniquename “myMuscleName”

There are many other ways to do the same, with and without loops.

Also, EVERY object constructor should support the name: keyword – I would be surprised if the ACT muscles do not. So you might be able to create your objects with the desired names from the beginning – have you TRIED? Just like with a standard primitive you can say

s = sphere name:“MySphere”

you should be able to construct any other creatable object, or assign the name later:

s = sphere()
s.name = “MySphere”

Hi bobo,

yeah i tryed the name option during creation and it dosent work. eg

actCreateMuscle 5 6 name:“mynewMuscle”

but the example you gave this time did work

s = sphere()
s.name = “MySphere”

although i tried that same thing earlier but i was getting node: undefined errors… but that could have been from the earlier problem i had with the for loop layout.

anyway thank you so much. its hard when you dont know the syntax that well and the simple things can really hold you up and drive you crazy.

cheers

john

John,

actCreateMuscle seems to be a function and not an object constructor. That’s probably why it doesn’t accept any of the parameters a constructor has. Have you checked if it returns a value? I suspect it returns the created node, so you should be able to store that in a variable and set any properties afterwards, like so:

theMuscle = actCreateMuscle 5 6
theMuscle.name = "mynewMuscle"

If that works, you can use the new variable theMuscle to access the object throughout the rest of your script as well (from your earlier post):

theMuscle.transform = theMesh.transform
...
actSetMusclePoint theMuscle 1 v(vertposition)

Hope this helps,
Martijn

thanks magicm

yeah thats what i ended up doing it all works now

here is the final working script if your interested

--john Van Der Zalm 2007
--email: john@kaffeineproductions.com
--version 0.5


--notes
-- fixed - max crashes because the cgMuscle has to meny or to little verts.
-- This is a hack function and it it will delete any polygon with more or less then 4 sides. usse cylinders or spheres to start modeling you muscles

--ChangeLog
-- v0.4non dependent on cgmuscle01 name fixed
-- v0.5 delete mesh objects implimented

macroScript convert_To_CgMuscle
	category:"ACTTools"
	toolTip:"convert To CgMuscle"
(--start a local scope
  
  fn deleteNonQuads theMesh =
  (
	local face_selection = #{}
	local num_faces = polyop.getNumFaces theMesh
	for f = 1 to num_faces do
	(
		local num_face_verts = polyop.getFaceDeg theMesh f
	
		if num_face_verts != 4 do face_selection[f] = true
	)--end f loop3
	polyop.deleteFaces theMesh face_selection	
	
  )--end fn
  fn countMuscleCSections theMesh =  --pass the mesh as argument
  (
	  theMesh.SetSelection #Edge #{1} --select first edge
	  theMesh.SelectEdgeRing() --select edge ring
	  (polyOp.getEdgeSelection theMesh).numberset --return the number of set bitarray bits 
  )--end fn 
  fn countMuscleFSections theMesh =  --pass the mesh as argument
  (
	theMesh.SetSelection #Edge #{1}
	theMesh.SelectEdgeloop()
	(polyOp.getEdgeSelection theMesh).numberset
  )--end fn 
  for theMesh in selection do
  (
	  convertto theMesh editable_poly --collapse to EPoly
	local delNonQuads = deleteNonQuads theMesh --calls the function for deleting all nonQuads
	local theCountCS = countMuscleCSections theMesh --call the function to count crossections
	local theCountFS = countMuscleFSections theMesh --call the function to count fibers
	cgmuscle = actCreateMuscle theCountCS theCountFS --creates the cgmuscle01 
	cgmuscle.transform = theMesh.transform
	theMeshsnap = snapshotAsMesh theMesh
	for v = 1 to theMeshsnap.numverts by 1 do 
	(
		vertposition = meshop.getVert theMeshsnap v * inverse theMesh.transform
		
		actSetMusclePoint cgmuscle 1 v(vertposition)
	)
	cgmuscle.name = theMesh.name + "_cgMuscle"
  )--end loop
  delete selection
 )--end script

thats it for now although i might make. afew more muscle creation scripts.
like softbody reactor muscle setup and also maybe a muscle max bone creator so it sets up squash and stretch.

thanks all for your help its greatly apreciated
now all i need is for somone to use the script maybe i’ll put it up on scriptspot

see if i have time if you have any other ideas let me know.:bounce:

cheers

john