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 Python

    def 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 0

    def 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 tempCount

    def main() :
        global PolyCount #for Output
        tempCount = 0
        PolyCount = 0 #from input

    if 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 count

    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. 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 count

    def 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,
    -Niklas

    PS: 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://plugincafe.maxon.net/topic/5830/5888_the-cache-while-rendering
    https://plugincafe.maxon.net/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 : )


Log in to reply