Start a new topic
Solved

how to batch rename nodes under particular nodes in python?

I am new to python,

1. now I want to batch rename Group nodes just under the LOD nodes, and ignore the other group nodes,

as shown in the pic.

I wrote a script trying to do that.

(Thanks to the God-like Steve to help!!)

right now it can batch rename certain type of nodes, but just can't point the 'parents',

which i only  want change node name under these 'parents'

here is my code,


(I know the problem is,i dont understand the callback funtion which mgwalk using.

but after learning mgwalk and learning define class for a week,nealy no way to try).


2 .How to iterate nodes without using this mgwalk function? i am using creator18


thanks a lot if any advice!


Yingbo in singapore


py
(1.04 KB)
rename.JPG
(26.4 KB)

The mgWalk function may seem intimidating but it's really not. It's explained in great detail in the OpenFlight API Developers Guide and OpenFlight API Reference. And there are tons of samples. But to put it simply, you call mgWalk and pass it a root node. mgWalk will traverse this root node and every node below it. For every node it visits, mgWalk "hits" that node twice, once on its way down the traversal and another on the way up the traversal. When mgWalk first hits a node (on its way down the traversal) it calls the pre-function on that node. After traversing that node and its children it comes back up to that node and calls the post-function on that node. The pre and post functions return MG_TRUE or MG_FALSE depending on whether you want the traversal to continue. Return MG_TRUE to tell mgWalk to continue traversing. Return MG_FALSE to tell mgWalk to stop traversing immediately.

For what you want to do, using that other script I sent you as a starter was a bit overkill and may cause confusion. That script attached new nodes to existing nodes. This is well explained in the docs but in general you can't change the hierarchy during the mgWalk. Since that other script wanted to attach new nodes to LODs, it could not do the attach in the walk function (that would violate the rule about NOT changing the hierarchy during the mgWalk). Instead that other script used the mgWalk just to collect a list of LODs. Adding lods to a list does not change the hierarchy. When the mgWalk was done and the LOD list was built, the script then looped through the lods in the list. At this time, attaching or detaching nodes to each lod in the list is fine. Again, if you attach and detach nodes while you are traversing, you can see how that could mess up the traversal. The scene graph hierarchy should NOT change during the mgWalk. There are exceptions to this noted in the docs, but to keep it simple DON'T change the hierarchy in your mgWalk callbacks.


So given that, I would start with a fresh script. Don't try to reuse that other one as it is not appropriate for the simple task you want to do now.


I would change your call to mgWalk to have just one callback, a pre-walk function and make your post-walk function MG_NULL.

In your pre-walk function do this:

1) query the node being visited (the 3rd parameter, normally called 'rec') to see if it is a group under a LOD. This is quite easy. The walk function is passed the node and its parent. Simply ask if the node is a fltGroup and the parent is a fltLod. This looks like this:  

def PreCallback (db, parent, rec, b):
   if ((mgGetCode(rec) == fltGroup) and (mgGetCode(parent) == fltLod)):
      # rec is a group and rec's parent is a LOD, rename this node here
 ...
   return MG_TRUE  # tell mgWalk to continue to travers

 The rest of your "rename" code looks fine.  


Give this a try and let us know if you still have questions.


1 person likes this

Hi, I'd be glad to help. I can see where  you got confused. Your PreCallback function has some issues. For review, the precallback function will be called for every node in the database as the walk function iterates them. The iteration is a depth first iteration and the iteration will stop whenever your precallback function returns MG_FALSE.


I took the liberty to simplify it for you. I modified it so you only have one simple callback function that stores a list of lod nodes.  From this, it is easy to get the children and modify their names etc...


Try the code below and let me know if it works and/or if you have any questions about it.


 

def GatherChildren(nod):
	childList = list()
	child = mgGetChild(nod)	
	print mgGetName (child)
	while child:
		childList.append(child)
		child = mgGetNext(child)
	return childList

def PostCallback (db, parent, rec, userList):	
	code = mgGetCode(rec)
	if mgIsCode(rec, fltLod):
		userList.append(rec)
	return MG_TRUE

db = mgGetCurrentDb ()
lodList = list()
mgWalk (db, None, PostCallback, lodList, MWALK_NONESTED)
n = 0
if lodList:
	for lodrec in lodList:		
		childList = GatherChildren(lodrec)
		if childList:
			for groupRec in childList:
				if mgIsCode(groupRec, fltGroup):
					newname = 'AB'+str(n)
					n = n + 1
					mgSetName(groupRec, newname)

 





1 person likes this

Hi,Steve

 it works :D 

Thanks a lot for this detailed explain! after read what u said back and forth, finally absorb a bit, 

i tried to using prewalk,and postwalk at the same time, just for learning purpose,and it can works ,too:)


base on my understanding,(might be wrong):

1.mgwalk seem just works like a 'filter',to define what i want, if i really want to do some action,better use a normal funtion,is that right?

2.the argument inside prewalk,postwalk,seem can share.the parent nodes are the same and the void* are the same,i can extract a list from prewalk, and use in postwalk, is that allowed to do so?


for the API Developer Guide, all wriiten by C++ ,i guess.

for ppl like me,just understand a bit python,really hard to translate...


Steve,quite happy it works after pull my hair for days.(I know it simple),but your informations presious for me cos i can't find from internet.

Many Thanks :)


Yingbo

py
(487 Bytes)
py
(304 Bytes)

Hi,Chris

after type your code line by line ,it works:) 

but why it works i just base on guessing...


1st step: get a parent list, by PostCallback func, (which stored in userList.)

2nd step: we got a lodList = list() , given by mgwalk

3rd step:  get children nodes,by GatherChildren funtion ,

4th step: loop the children nodes,  rename each children.


the most confusion thing is where the lodList data coming from?, i guess is a 'gift' from mgwalk.

so nice to have another way to grab parent and children nodes,

Thanks a lot for help :D


Yingbo


py

Wang, I'm glad Steve and I were able to give you some information that is working for you.


As to  your question, lodList if first just created in the line

lodList = list()


Then when we do the mgWalk, we pass it in as user data. This user data will be available to the walk function for every node it iterates. You can see it in my walk function PostWalk, I call it userList. This is the lodList, just with a different name. The walk function then checks the current node to see if it is an LOD node, then adds it to this list if true. The magic happens because mgWalk will call our walk function on every node we care about in the database. When the walk is finished, the lodList contains every lod node in the database. Then we can do what we want with the nodes.




1 person likes this

1.mgwalk seem just works like a 'filter',to define what i want, if i really want to do some action,better use a normal funtion,is that right?

It depends on what you are doing. If you need to look through the entire scene graph, mgWalk is certainly the easiest way to do that. You can use mgGetChild, mgGetNext, etc to manually traverse nodes but that can be cumbersome and you have to worry about subfaces, instances, external references etc. When you do use mgWalk the callback functions are called for each node visited. See the description of mgWalk in the OpenFlight API Reference (HTML). How mgWalk traverses the scene graph and how pre and post callbacks differ is explained very well here with an example. When mgWalk "hits" a node in the traversal, it calls your callback function and passes 4 parameters that describe the state of the traversal (the current node being visited). The first param is the db that contains the node currently being visited. The second parameter is the parent of the node currently being visited. The third parameter is the node currently being visisted. Finally, the fourth parameter is the "user data" you passed to mgWalk. This "user data" is a common pattern for callback-based functions. The walk flags you pass to mgWalk does allow some "filtering" of the nodes you want visited. For example do you want instances and external references to be visited? Do you want vertices to be visited? You can't filter, for example, to visit just LOD nodes or just Group Nodes. If you only want to visit LOD nodes only, you have to check the code of the node being visited yourself, process just LOD nodes and ignore the other kinds.


2.the argument inside prewalk,postwalk,seem can share.the parent nodes are the same and the void* are the same,i can extract a list from prewalk, and use in postwalk, is that allowed to do so?

I'm not sure I understand your question. Perhaps my answer to your previous question also answered this one. The first and fourth parameters of the callback functions are always the same. The db and user data do not change per node. The 2nd and 3rd parameters will be different for each invocation of the callbacks depending on which node is currently being visited. As I noted above, the 2nd parameter is the parent of the current node being visited and the 3rd parameter is the node itself.


for the API Developer Guide, all wriiten by C++ ,i guess.

for ppl like me,just understand a bit python,really hard to translate...
The C/C++ function names are exactly the same names as the OpenFlight Script function names. The only difference may be the calling syntax (just due to how C and Python differ slightly). While the Developer Guide is useful to understand the high level concepts of the API (for example conceptually, mgWalk is exactly the same in C and Python), what I find much more useful is the OpenFlight API Reference Guide. Once I know which function I want to use (from the Developer Guide), I look at the Reference Page for that function to see exactly how to call it in C and/or Python. The Reference Guide gives you the exact syntax for both languages. 


Stick with it, it gets easier the more you use the API. If you have further questions just let us know.


1 person likes this

Hi Chris

as a newbie i am a bit blur,but what u explained is what i guess: userList  and lodList really same thing!

and i can add a bit more condition with your help, such as only process the nodes with certain name etc.

Thanks a lot for help :)


Wang 


Hi, Steve

 I just wait for your reply then will 'Mark as Solved', Then your answers came:D

mgwalk seems  'intimidating' but after u explained i understand it better.  


as u said ' OpenFlight API Reference ' does more useful ,because it has python example ,

now i try using mgfind ,can return a list for me just like mgwalk did.


before your explain, i dare not try anything in Creator API (0 working experience in any API..)

Many thanks , U almost like a teacher teaching a student :-)


yingbo 

Login to post a comment