Could you please provide some more information so we know how to structure the script?
Hi Steve, thank you for your reply.
1. I will be running the script inside of Creator 4.2
2. This doesn't matter now because I am running it in Creator right?
3. I want those current children of the LOD to become children of the new switch
Here is a script that should do what you want. Let me know if you have any questions. I did not have a chance to test this in Creator 4.2 (that's quite old) but I believe all the script functions I used will be compatible. If not, let me know,
class NodeList: def __init__(self,nodeCode): self.nodes = list() self.nodeCode = nodeCode def ReportError(message): # prints twice, comment out whichever you don't want # this prints in the script editor log window print message # this prints to the Creator Status Log mgSendMessage(MMSG_ERROR, message) def GatherChildren(node): """return a simple list containing the child nodes of 'node'""" childList = list() child = mgGetChild(node) while child: childList.append(child) child = mgGetNext(child) return childList def InsertNodeAbove(nodes, nodeCode): """insert a node of type 'nodeCode' above each node in nodes list""" nodeCodeString = ddGetName(nodeCode) for node in nodes: parent = mgGetParent(node) # make sure we can attach a 'nodeCode' node to this nodes parent if mgValidAttach(mgGetCode(parent), nodeCode): # and that this node can be attached to new 'nodeCode' if mgValidAttach(nodeCode, mgGetCode(node)): newNode = mgNewRec(nodeCode) mgDetach(node) mgAppend(parent, newNode) mgAttach(newNode, node) else: ReportError("Error attaching {} to {}".format(mgGetName(node), nodeCodeString)) else: ReportError("Error attaching {} to {}".format(nodeCodeString, mgGetName(parent))) def InsertNodeBelow(nodes, nodeCode): """insert a node of type 'nodeCode' below each node in nodes list""" nodeCodeString = ddGetName(nodeCode) for node in nodes: # make sure we can attach a 'nodeCode' node to this node if mgValidAttach(mgGetCode(node), nodeCode): # grab current childen into a list children = GatherChildren(node) newNode = mgNewRec(nodeCode) mgAttach(node, newNode) # now move old children to be children of the new node for child in children: # move the child only if it can be a child of the new node if mgValidAttach(nodeCode, mgGetCode(child)): mgDetach(child) mgAppend(newNode, child) else: ReportError("Error moving child {} to {}".format(mgGetName(child), nodeCodeString)) else: ReportError("Error attaching {} to {}".format(nodeCodeString, mgGetName(node))) def PreWalkFunc (db, parent, rec, nodeList): if (mgGetCode(rec) == nodeList.nodeCode): nodeList.nodes.append(rec) return MG_TRUE def PostWalkFunc (db, parent, rec, nodeList): return MG_TRUE def AddGroupsAboveLods(db, lodList): InsertNodeAbove(lodList.nodes, fltGroup) def AddSwitchesBelowLods(db, lodList): InsertNodeBelow(lodList.nodes, fltSwitch) def GatherLODs(db): """walk database, collect and return a list of LOD nodes""" lodList = NodeList(fltLod) mgWalk (db, PreWalkFunc, PostWalkFunc, lodList, 0) return lodList db = mgGetCurrentDb () lodList = GatherLODs(db) AddGroupsAboveLods(db, lodList) AddSwitchesBelowLods(db, lodList)
Hi Steve,
The script is working like a charm on the first few files I've tested. I will batch it on 100 files on Monday and let you know how it goes.
Thank you so much!
Hi, after testing the script on 100 files, many are working well but I realized that my lightpoints are being deleted as they fall under LOD nodes
Is it possible to modify the script to exclude nodes of a specific name? I tried using: if mgGetRecByName (db, "headlights") but that broke the script instead.
Right now, I need to exclude all nodes (and their children) that has the name "headlights" or "blackout" or "bad". "headlights" and "blackout" are switches while "bad" is a group node
Hmmm... I'm puzzled why any nodes are getting deleted. The script only adds and moves nodes around, it does not delete nodes. Any child of the LOD before the script runs should be "moved" to be under the switch. But the script only does this if the child of the LOD "can be" attached to a switch. If it cannot be moved from the LOD to the switch, it should simply remain on the LOD. Perhaps the check for mgValideAttach is returning a FALSE positive in which case the child would get detached but then the mgAppend would fail. This would look like the child got "deleted" but not purposefully Do you see any messages in the Status Log to suggest this might be happening? I think this should be fixed instead of coming up with any sort of "exclude this node" mechanism which should NOT be needed if the script was working correctly.
I tried this script with a light point child of the LOD and see the light point getting moved properly from the LOD to the switch. Granted I am not using 4.2 but I can't imagine it's too different for you. Can you clarify what you're seeing, perhaps attach a file that is showing this? In the meantime, I can make some changes in the script to try to detect and correct this. But I'd really like to undertand what is really happening before making guesses.
I just installed Creator 4.2 and see what you're talking about. As I suspected mgValidAttach is returning a FALSE positive which leads the script to believe that attaching Light Points to Switches is OK, which in 4.2 it is not. Also in 4.2, attaching light points directly to LODs is forbidden as well. So when the script tries to move the light point from the LOD to the switch (even though mgValidAttach says its ok to do so) it fails. This results in the Light Point being detached (not deleted really). So if you're inside of Creator when you run the script, you'll see the Light Points detached in the hierarchy view, you can grab them and reattach them. If you run this in batch mode, howver, the detached nodes will be lost when the file is written.
So you're in a bit of a pickle. For one, you have a file that in Creator 4.2 is illegal in that you have light points attached directly to LODs. Not sure how you got such a file. I don't think you created it in CR 4.2, as it would not have allowed you. Either way you have a couple of options:
1) Go through all your files and insert object nodes between the light point and the LOD. Object nodes can be attached to both LOD and Switch nodes. In the long run this might be your best option unless for some reason your runtime would be negative impacted.
2) Use the updated script here. In this script I added my own version of mgValidAttach (called myValidAttach) which kinda fixes the problem. If you find other nodes that "go missing" you can add more cases to myValidAttach to fix them too.
class NodeList: def __init__(self,nodeCode): self.nodes = list() self.nodeCode = nodeCode def myValidAttach(parentCode, childCode): if parentCode == fltLod and childCode == fltLightPoint: return MG_FALSE if parentCode == fltSwitch and childCode == fltLightPoint: return MG_FALSE return mgValidAttach(parentCode, childCode) def ReportError(message): # prints twice, comment out whichever you don't want # this prints in the script editor log window print message # this prints to the Creator Status Log mgSendMessage(MMSG_ERROR, message) def GatherChildren(node): """return a simple list containing the child nodes of 'node'""" childList = list() child = mgGetChild(node) while child: childList.append(child) child = mgGetNext(child) return childList def InsertNodeAbove(nodes, nodeCode): """insert a node of type 'nodeCode' above each node in nodes list""" nodeCodeString = ddGetName(nodeCode) for node in nodes: parent = mgGetParent(node) # make sure we can attach a 'nodeCode' node to this nodes parent if myValidAttach(mgGetCode(parent), nodeCode): # and that this node can be attached to new 'nodeCode' if myValidAttach(nodeCode, mgGetCode(node)): newNode = mgNewRec(nodeCode) mgDetach(node) mgAppend(parent, newNode) mgAttach(newNode, node) else: ReportError("Error attaching " + mgGetName(node) + " to " + nodeCodeString) else: ReportError("Error attaching " + nodeCodeString + " to " + mgGetName(parent)) def InsertNodeBelow(nodes, nodeCode): """insert a node of type 'nodeCode' below each node in nodes list""" nodeCodeString = ddGetName(nodeCode) for node in nodes: # make sure we can attach a 'nodeCode' node to this node if myValidAttach(mgGetCode(node), nodeCode): # grab current childen into a list children = GatherChildren(node) newNode = mgNewRec(nodeCode) mgAttach(node, newNode) # now move old children to be children of the new node for child in children: # move the child only if it can be a child of the new node if myValidAttach(nodeCode, mgGetCode(child)): mgDetach(child) mgAppend(newNode, child) else: ReportError("Error moving child " + mgGetName(child) + " to " + nodeCodeString) else: ReportError("Error attaching " + nodeCodeString + " to " + mgGetName(node)) def PreWalkFunc (db, parent, rec, nodeList): if (mgGetCode(rec) == nodeList.nodeCode): nodeList.nodes.append(rec) return MG_TRUE def PostWalkFunc (db, parent, rec, nodeList): return MG_TRUE def AddGroupsAboveLods(db, lodList): InsertNodeAbove(lodList.nodes, fltGroup) def AddSwitchesBelowLods(db, lodList): InsertNodeBelow(lodList.nodes, fltSwitch) def GatherLODs(db): """walk database, collect and return a list of LOD nodes""" lodList = NodeList(fltLod) mgWalk (db, PreWalkFunc, PostWalkFunc, lodList, 0) return lodList db = mgGetCurrentDb () lodList = GatherLODs(db) AddGroupsAboveLods(db, lodList) AddSwitchesBelowLods(db, lodList)
Hi Steve, firstly my apologies for my late replies. I am working at the GMT time zone so I presume we are 12 hours apart.
The light points are no longer being affected, thanks! You're right, the light points must have been made in an older version.
I am trying to add more exceptions to myValidAttach. I have a group node named 'bad' in which I want it and its children to be excluded from the entire script. This is how I am trying to code it:
badParent = mgGetRecByName (db, "bad")
def myValidAttach(parentCode, childCode):
if parentCode == fltLod and childCode == fltLightPoint:
return MG_FALSE
if parentCode == fltSwitch and childCode == fltLightPoint:
return MG_FALSE
if parentCode == badParent and childCode == fltPolygon:
return MG_FALSE
It doesn't give an error but it doesn't exclude the group node 'bad' either. What am I doing wrong?
When you say you want certain groups "excluded from the entire script" can you be more specific? I assume you mean you just want to "freeze" that node and all its children. In other words "don't process any LODs you find under that group". If that is the case, you can try the update script below.
As to using myValidAttach to achieve this...
You can't do it here, by the time myValidAttach is called, it's way too late.
Also the parameters to myValidAttach are "codes" (or levels) like fltGroup, fltLod, fltSwitch, fltLightPoint, etc
These "codes" are returned by mgGetCode. So for a node that is a "group", mgGetCode(node) would return fltGroup. Again mgGetCode(node) returns the "level" of the node.
mgGetName(node) returns the "name" of the node. You are comparing a nodes "code" to its "name". That won't work.
In your code above badParent is a node, parentCode is a "level". They will never match.
class WalkController: def __init__(self): self.excludeNames = list() self._walkActiveStack = list() def Exclude(self,name): # add 'name' to list of node names we exclude from the script self.excludeNames.append(name) def IsExcluded(self,node): # returns True if this node is excluded name = mgGetName(node) return name in self.excludeNames def PreNode(self,node): # tell the controller you are starting to walk 'node' if (self.IsExcluded(node)): # if this node is excluded, push it on the stack self._walkActiveStack.append(node) def PostNode(self,node): # tell the controller you are done walking 'node' # if this node is currectly being excluded pop its name off the stack length = len(self._walkActiveStack) if (length > 0): if (self._walkActiveStack[length-1] == node): self._walkActiveStack.pop() def IsWalkActive(self): # if there are any nodes in the stack, that means we are excluding it # currently return len(self._walkActiveStack) == 0 class NodeList: def __init__(self,nodeCode,walkController): self.nodes = list() self.nodeCode = nodeCode self.walkController = walkController def myValidAttach(parentCode, childCode): if parentCode == fltLod and childCode == fltLightPoint: return MG_FALSE if parentCode == fltSwitch and childCode == fltLightPoint: return MG_FALSE return mgValidAttach(parentCode, childCode) def ReportError(message): # prints twice, comment out whichever you don't want # this prints in the script editor log window print (message) # this prints to the Creator Status Log mgSendMessage(MMSG_ERROR, message) def GatherChildren(node): """return a simple list containing the child nodes of 'node'""" childList = list() child = mgGetChild(node) while child: childList.append(child) child = mgGetNext(child) return childList def InsertNodeAbove(nodes, nodeCode): """insert a node of type 'nodeCode' above each node in nodes list""" nodeCodeString = ddGetName(nodeCode) for node in nodes: parent = mgGetParent(node) # make sure we can attach a 'nodeCode' node to this nodes parent if myValidAttach(mgGetCode(parent), nodeCode): # and that this node can be attached to new 'nodeCode' if myValidAttach(nodeCode, mgGetCode(node)): newNode = mgNewRec(nodeCode) mgDetach(node) mgAppend(parent, newNode) mgAttach(newNode, node) else: ReportError("Error attaching " + mgGetName(node) + " to " + nodeCodeString) else: ReportError("Error attaching " + nodeCodeString + " to " + mgGetName(parent)) def InsertNodeBelow(nodes, nodeCode): """insert a node of type 'nodeCode' below each node in nodes list""" nodeCodeString = ddGetName(nodeCode) for node in nodes: # make sure we can attach a 'nodeCode' node to this node if myValidAttach(mgGetCode(node), nodeCode): # grab current childen into a list children = GatherChildren(node) newNode = mgNewRec(nodeCode) mgAttach(node, newNode) # now move old children to be children of the new node for child in children: # move the child only if it can be a child of the new node if myValidAttach(nodeCode, mgGetCode(child)): mgDetach(child) mgAppend(newNode, child) else: ReportError("Error moving child " + mgGetName(child) + " to " + nodeCodeString) else: ReportError("Error attaching " + nodeCodeString + " to " + mgGetName(node)) def PreWalkFunc (db, parent, rec, nodeList): nodeList.walkController.PreNode(rec) if (nodeList.walkController.IsWalkActive()): if (mgGetCode(rec) == nodeList.nodeCode): nodeList.nodes.append(rec) return MG_TRUE def PostWalkFunc (db, parent, rec, nodeList): nodeList.walkController.PostNode(rec) return MG_TRUE def AddGroupsAboveLods(db, lodList): InsertNodeAbove(lodList.nodes, fltGroup) def AddSwitchesBelowLods(db, lodList): InsertNodeBelow(lodList.nodes, fltSwitch) def GatherLODs(db, walkController): """walk database, collect and return a list of LOD nodes""" lodList = NodeList(fltLod, walkController) mgWalk (db, PreWalkFunc, PostWalkFunc, lodList, 0) return lodList db = mgGetCurrentDb () # set up a list of names that the GatherLODs function will exclude from the script excludeNames = WalkController() # # Add the names of the nodes you want to exclude here # excludeNames.Exclude("bad") # add as many names as you want excludeNames.Exclude("bad2") # etc # pass the list of excluded names to GatherLODs lodList = GatherLODs(db, excludeNames) AddGroupsAboveLods(db, lodList) AddSwitchesBelowLods(db, lodList)
Hi Steve, it's working perfectly! And now I can even add my own exceptions. I am batching it on the rest of the few hundred models so far and they are turning out well.
You've been a great help to me and I can't stress how thankful I am!
That's great Wang, so glad you're having success. Any more questions, just let us know.
Hi Steve
i try understand your script for many times, and learn the 'class' on youtube for 1 week,
still getting lost in (nodes,node,list),although all function very well. but it is not a good way we always ask other people to write code for us....
i try disable some functions by #, trying to see each ' def ' does, but all func wont work.....
could u provide a simplified version, such as only add a switch under every LODs, still using your 'class'?
so that next time if we need extra stuff I can modify it,at least
maybe too many requirement since the script already works..
or maybe i better open another topic?
Have a good day :)
Yingbo
Wang
Hi all,
I am a 3D artist who has been tasked to process a database of hundreds of flight files for CDB. Most of them contains multiple LOD, switches and groups.
I need to batch-process these files but I am not trained in programming, and we can't afford to hire any programmers so I need your help please.
Could anyone show me a script to place a switch below every LOD node, or another script to place a group node above every LOD node, or preferably a script that does both functions together?
I am on Openflight 4.2 API.
Thank you very much!