First Post! R12 python Node, advice on cleanup.
-
THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED
On 02/03/2012 at 09:51, xxxxxxxx wrote:
Hi all.
This is my first post here. I've tried on and off again to begin coding, never being able to get over that first major hump. I've finally been able to put together some code well enough that I can start to ask advice without feeling like I'm goin' "deeerp, how you do code?!?!"Now, This code is from a R12 python node in XPresso. It is functional, but probably pretty damn ugly. It would be great if someone could look it over and say "This huge chunk could have been this one line dummy!" Or "Why would you even DO that?"
Its function is to take an input 'link' and return the total poly count of the objects entire hierarchy, be they prim, generated, or whatever.
import c4d
#Welcome to the world of Pythondef polyCheck(op) : # successfully gets polys from poly prims, and polygon objects. Ignores splines and nulls. probably pretty clunky
if c4d.C4DAtom.GetType(op) == 5100:
print op.GetName() + " Poly"
return op.GetPolygonCount()
elif op.GetCache() != None and (op.GetRealSpline()) == None:
print op.GetName() + " non-poly poly"
return op.GetCache().GetPolygonCount()
elif op.GetCache() != None and (op.GetRealSpline()) != None:
print op.GetName() + " spline"
return 0
else:
print "none"
return 0def addition(tempCount,op,placement) :
print "#" + str(op.GetName()) + " polycount of " + str(tempCount) + " runs at " + str(placement)def count(op,base,tempCount) : #Runs through hierarchy, real ugly I bet.
print "-----New 'def count'-----"while (op.GetDown() != None) and (op != base) :
tempCount = tempCount + polyCheck(op)
addition(tempCount,op,1)
op = op.GetDown()
if op.GetDown() == None and (op != base) and op.GetNext() == None:
tempCount = tempCount + polyCheck(op)
addition(tempCount,op,2)
if op.GetNext() != None and (op != base) :
tempCount = tempCount + polyCheck(op)
addition(tempCount,op,3)
op = op.GetNext()
if op.GetNext() == None and (op != base) and op.GetDown() == None:
tempCount = tempCount + polyCheck(op)
addition(tempCount,op,4)
tempCount = count(op,base,tempCount)else:
if op.GetNext() == None and op.GetDown() == None and op.GetPred() == None and op.GetUp() == base:
tempCount = tempCount + polyCheck(op)while op.GetNext() == None and (op != base) :
op = op.GetUp()if op.GetNext() != None and (op != base) :
op = op.GetNext()
if op.GetNext() == None and op.GetDown() == None:
tempCount = tempCount + polyCheck(op)
tempCount = count(op,base,tempCount)
else:
tempCount = count(op,base,tempCount)print str(tempCount) + " COUNT5"
return tempCountdef main() :
global PolyCount #for Output
tempCount = 0
PolyCount = 0 #from inputif ConnectObject.GetDown() == None:
PolyCount = PolyCount + polyCheck(ConnectObject)
else:
PolyCount = count(ConnectObject.GetDown(),ConnectObject,tempCount)
PolyCount = PolyCount + polyCheck(ConnectObject)
print PolyCount
print "--Done--"Thanks in advance for any advice on cleaning this up. I'm excited to finally be able to post something!
Chris Schmidt
-
THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED
On 02/03/2012 at 10:47, xxxxxxxx wrote:
Hello Chris,
here are some things you should take care of:
- You can call op.GetType() directly, instead of using c4d.C4DAtom.GetType(op). Anyway, both are equivalent.
- Never compare against True, False or None. Always use the implicit testing, using either if var: or if not var:.
- Instead of concatenating strings and converting values, you can use the C-style formatting using the % operator. print "Digit: %d, Float with 3 post-decimal digits: %.3f, String: %s, Repr: %r" % (var, var, var, var)
- You do not need to enclose comparisons in parantheses
- Your code can be shrinked down easily by implementing a recursive function, see below.
import c4d def getPolygonCountRec(op) : """ Returns the number of polygons for an object recursively. Always succeeds, for generator and polygon-objects. Returns an integer. """ # Return the number of polyogns when the object is a PolygonObject. if op.CheckType(c4d.Opolygon) : return op.GetPolygonCount() # Return zero when the object is a spline. elif op.CheckType(c4d.Ospline) : return 0 # Or go on recursively if both do not apply else: cache = op.GetCache() if not cache: return 0 count = getPolygonCountRec(cache) for child in cache.GetChildren() : count += getPolygonCountRec(child) return count def main() : global PolyCount if not InputObject: PolyCount = 0 else: PolyCount = getPolygonCountRec(InputObject)
The code expects the variable InputObject to be available in the global scope (i.e. an input-port in the XPresso node). The value of the polygon-count will be assigned to the variable PolyCount, so you need to create an output-port named like this.
Greetings,
Niklas -
THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED
On 08/03/2012 at 18:59, xxxxxxxx wrote:
Thanks so much Niklas! Incredibly generous and helpful.
We've tried to rework the code so that we can iterate through a hierarchy. It seems to work perfectly with the exception of HyperNURBS ( and symmetry object) Where the count is always off. Is there some special way to treat these types of generator objects?
import c4d
def childLoop(op,count) :
#Goes down children recursively
for child in op.GetChildren() :
count += getPolygonCountRec(child)
return countdef getPolygonCountRec(op) :
""" Returns the number of polygons for an object recursively. Always
succeeds, for generator and polygon-objects. Returns an integer. """# Return the number of polyogns when the object is a PolygonObject. Goes down children recursively
count = 0
if op.CheckType(c4d.Opolygon) :
count = op.GetPolygonCount()
count = childLoop(op,count)
return count# Return zero when the object is a spline. Goes down children recursively
elif op.CheckType(c4d.Ospline) :
count = childLoop(op,count)
return count# Or go on recursively if both do not apply. Goes down children recursively
else:
cache = op.GetCache()
count = childLoop(op,count)
if cache:
if not cache.GetChildren() :
count += getPolygonCountRec(cache)
if cache:
count = childLoop(cache,count)
return countdef main() :
global PolyCount
if not ConnectObject:
PolyCount = 0
else:
PolyCount = getPolygonCountRec(ConnectObject) #(InputObject)Thanks again for any help!
-
THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED
On 09/03/2012 at 10:12, xxxxxxxx wrote:
What do you mean by "The count is always off" ? The code works for me.
Cheers,
-NiklasPS: Cleaned it up a bit.
import c4d def recursion(op) : count = 0 for child in op.GetChildren() : count += recursion(child) if op.CheckType(c4d.Opolygon) : return op.GetPolygonCount() + count elif op.CheckType(c4d.Ospline) : return count else: cache = op.GetCache() if not cache: return count return recursion(cache) + count def main() : global PolyCount if ConnectObject: PolyCount = recursion(ConnectObject) else: PolyCount = 0 return True
-
THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED
On 09/03/2012 at 23:05, xxxxxxxx wrote:
Thanks once again Niklas, I have much to learn. Your new code works perfectly!
The problem with the count I was referencing is if you take a single polygon and put in as child of a HyperNURB the code returns 5. Same problem with symmetry object. I assume it's because it's counting the HyperNURB AND the single polygon, however if you use something like a cloner it works just fine. Just wondering what the reason for that is and if there was any way around it.
Chris
-
THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED
On 10/03/2012 at 02:43, xxxxxxxx wrote:
Hi Chris,
I see, no it doesn't work correctly. I get 102 polygons for a HyperNurbs with a cube of 6 faces. It should be 96 polygons, but + 6 of the cube = 102. To work around this we'd need to know if the object we're currently at is a generator object based on children or not.. We could collect all the objects doing this, but then we don't include plugins that do so, etc.
I'm not sure, but when registering an object plugin to c4d you must tell it that your plugin works with the children and maybe there is a possibility to get that flag from Python..? (Looking over to maxon..)
~~I don't think the whole thing will be of use for you. Unfortuneately, we can not access the cache when rendering.. Or, at least not in the first frame or .. ah i don't understand it.
Refer to this threads:https://developers.maxon.net/forum/topic/5830/5888_the-cache-while-rendering
https://developers.maxon.net/forum/topic/6272/6658_no-attributes starting at post #9~~Edit: It works while rendering when setting the Priority to Generators. Thanks to Lennart!
I added a few debugging lines to the code to see what happens when rendering:
import c4d def recursion(op, i = 0) : print " " * i + op.GetName() + " :: " + op.GetTypeName() count = 0 for child in op.GetChildren() : count += recursion(child, i+4) if op.CheckType(c4d.Opolygon) : return op.GetPolygonCount() + count elif op.CheckType(c4d.Ospline) : return count else: cache = op.GetCache() if not cache: return count print " " * (i+5) + "--- cache ---" return recursion(cache, i+5) + count def main() : global PolyCount if ConnectObject: PolyCount = recursion(ConnectObject) else: PolyCount = 0 return True
This is the output in the editor:
HyperNURBS :: HyperNURBS Würfel :: Würfel --- cache --- Würfel :: Polygon-Objekt --- cache --- Würfel :: Polygon-Objekt
This is the output when rendering:
HyperNURBS :: HyperNURBS Würfel :: Würfel
You notice there is no cache available?
The polygoncount is zero (for only primitves, we can still access polygonobjects from he OM).Cheers,
Niklas -
THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED
On 12/03/2012 at 15:22, xxxxxxxx wrote:
The Priority to Generators bit is over my head, as my HyperNURBS still returns the wrong number. But I learned some useful things from your debugging! And your previous code seems to suite my puposes perfectly! Now I'm off to write more code : )