Get all ngons [SOLVED]



  • On 23/11/2016 at 03:27, xxxxxxxx wrote:

    Is there a way for getting each group of ngon?

    Here my first attempt who is working 90% time but that mean the obj need to be inserted into the document and is not optimized at all on huge mesh.

    def deconnexion(obj) :
        doc = c4d.documents.GetActiveDocument()   
        
        settings = c4d.BaseContainer()
        settings[c4d.MDATA_DISCONNECT_PRESERVEGROUPS] = False
        test = c4d.utils.SendModelingCommand(command = c4d.MCOMMAND_DISCONNECT,
                                    list = [obj],
                                    mode = c4d.MODELINGCOMMANDMODE_POLYGONSELECTION,
                                    bc = settings,
                                    doc = doc)
      
    def get_ngnon(obj) :
        save_before = obj.GetClone()
        mode = doc.GetMode()
        doc.SetMode(c4d.Mpolygons)
        
        deconnexion(obj)
        selection = obj.GetPolygonS()
        selection.DeselectAll()
        
        buffer_all_ngons = []
        poly_to_check = range(0,obj.GetPolygonCount())
      
        for polygon_index in xrange(obj.GetPolygonCount()) :
            selection.DeselectAll()
            #Si notre l'index est dans le poly to check
            if polygon_index in poly_to_check:
                #On select notre poly
                selection.Select(polygon_index)
                
                # On selectionne les élements connecté
                c4d.CallCommand(12557)
                
                #Si il y a plus de 1 poly c'est que c'est un ngno
                if selection.GetCount() >= 2:
                    count = op.GetPolygonCount()
                    buffer = []
                    for i in xrange(count) :
                        if selection.IsSelected(i) :
                            if i in poly_to_check: poly_to_check.remove(i)
                            buffer.append(i)
                    buffer_all_ngons.append(buffer)
                    
        doc.SetMode(mode)
        save_before.CopyTo(obj,0)
                
        return buffer_all_ngons
    

    Here is another attempt here you can see my scene http://img4.hostingpics.net/pics/432338ngon.jpg
    poly id 0 = quad 
    all other are ngon

    In this attempt I only try to have all ngons.
    But finaly I would like to have the same output as my first attempt.

    def get_ngon_v2(obj) :
        edge_ngon = list(set(obj.GetNgonEdgesCompact()))
        all_ngons = []
        
        nbr = c4d.utils.Neighbor()
        nbr.Init(obj)
        for i in xrange(op.GetPolygonCount()) :
          pli = nbr.GetPolyInfo(i)["edge"]
          for edge in pli:
              if edge in edge_ngon:
                  all_ngons.append(i)
                  
        return list(set(all_ngons))
    

    Thanks in advance :)



  • On 25/11/2016 at 09:54, xxxxxxxx wrote:

    Hi,

    Are you trying to get all polygons inside one N-gon?

    You're first solution works with my tests but the second that uses PolygonObject.GetNgonEdgesCompact() can't work (the function doesn't return edge indices).

    N-gon support is limited in Python. C++ API PolygonObject::GetAndBuildNgon() gives information for all N-gons of an object.
    In Python it's only possible to get the number of N-gons via PolygonObject.GetNgonCount().



  • On 25/11/2016 at 11:04, xxxxxxxx wrote:

    Not sure if this helps.
    But here are a couple of scripts I've used to get n-gons.

    Example #1

    #This script retrieves a list that contains n-gon information for each selected polygon  
      
    import c4d  
    def main() :  
        
      obj = doc.GetActiveObject()  
      if obj is None: return False  
        
      ngons = []  
            
      EdgeS = obj.GetPolygonS()   
      polyCount = obj.GetPolygonCount()     
      allEdges = obj.GetNgonEdgesCompact()  
        
      for poly in xrange(polyCount) :  
          if EdgeS.IsSelected(poly) :   
              selPoly = poly  
              if allEdges[selPoly] !=0:  
                  #print "index: ",selPoly, "poly is an ngon"  
                  ngons.append(selPoly)  
        
      print ngons  
        
      c4d.EventAdd()  
      
    if __name__=='__main__':  
      main()
    

    Example #2

    #This script returns all of the polygons in an object that are n-gons using the mark option  
    #Not fully tested!! Might not work in every situation!!  
      
    import c4d  
    def main() :  
      
      obj = doc.GetActiveObject()  
      polys = obj.GetAllPolygons()  
      polyCount = obj.GetPolygonCount()  
        
      nbr = c4d.utils.Neighbor()  
      nbr.Init(obj)  
        
      for poly in xrange(polyCount) :          
          pli = nbr.GetPolyInfo(poly)  
          #print pli["mark"]  
        
          m = pli["mark"]  
          if m[0]==False and m[1]==True and m[2] == True and m[3]==True:  
              print "polygonID: ", poly, "is an ngon"  
            
          else: print "Not ngon"      
                
      c4d.EventAdd()  
      
    if __name__=='__main__':  
      main()
    

    -ScottA



  • On 27/11/2016 at 08:37, xxxxxxxx wrote:

    Yes I'm trying to get all polygons inside one N-Gon.
    I thinked about getting all ngon and then with GepolyInfo if polygon is in the all_ngon_list than do something but the porblem is if all ngon are connected that will never tell me wich polygon belong to wich ngon.

    Yes my first function work but not in all case. Anyway I will use it and optimize it using GetPolyInfo instead of selection which is not a great things ^^

    Yeah maybe I will port my code to C++ but I'm not an expert in C++ ^^'.
    Hooo so what are the value returned by GetNgonEdgesCompact()?.
    Anyway thanks for your highlight.

    Thanks scotta for yours scripts but both of them are not usefull in my case. Since my script change uv randomly by polygon. I need to know which polygon belong to wich ngon(like I do in my first script).
    Then I can random a whole ngon with the same seed.

    So I think I will stick to my first try and jsut optimize the selection function :)



  • On 28/11/2016 at 01:49, xxxxxxxx wrote:

    For people who want to try here is the optimized function. Maybe to much speedy for float in python since the first method( get_ngonv2) return me an execution time of 0.0. But I guess it's a float error.

    import c4d
    import time
      
    def deconnexion(obj) :
        doc = c4d.documents.GetActiveDocument()   
        
        settings = c4d.BaseContainer()
        settings[c4d.MDATA_DISCONNECT_PRESERVEGROUPS] = False
        test = c4d.utils.SendModelingCommand(command = c4d.MCOMMAND_DISCONNECT,
                                    list = [obj],
                                    mode = c4d.MODELINGCOMMANDMODE_POLYGONSELECTION,
                                    bc = settings,
                                    doc = doc)
                                    
    def get_ngon(obj) :
        save_before = obj.GetClone()
        mode = doc.GetMode()
        doc.SetMode(c4d.Mpolygons)
        
        deconnexion(obj)
        selection = obj.GetPolygonS()
        selection.DeselectAll()
        
        buffer_all_ngons = []
        poly_to_check = range(0,obj.GetPolygonCount())
      
        for polygon_index in xrange(obj.GetPolygonCount()) :
            selection.DeselectAll()
            if polygon_index in poly_to_check:
                selection.Select(polygon_index)
                
                c4d.CallCommand(12557)
      
                if selection.GetCount() >= 2:
                    count = obj.GetPolygonCount()
                    buffer = []
                    for i in xrange(count) :
                        if selection.IsSelected(i) :
                            if i in poly_to_check: poly_to_check.remove(i)
                            buffer.append(i)
                    buffer_all_ngons.append(buffer)
                    
        doc.SetMode(mode)
        save_before.CopyTo(obj,0)
                
        return buffer_all_ngons
        
    def get_poly_info(nbr,id_poly) :
        poly_connected = [] 
        pli = nbr.GetPolyInfo(id_poly)["face"]   
        for face in pli:
            if face != c4d.NOTOK:
                poly_connected.append(face)
                
        return list(set(poly_connected))
        
    def get_ngonv3(obj) :
        save_before = obj.GetClone()
      
        deconnexion(obj)
        
        all_poly_done = []
        all_ngons = []
        
        nbr = c4d.utils.Neighbor()
        nbr.Init(obj)
        for i in xrange(obj.GetPolygonCount()) :
            poly_to_do = []
            poly_ngon  = []
            poly_to_do.append(i)
            
            for id_poly in poly_to_do:
                if not id_poly in all_poly_done:
                    buffer_poly_info = get_poly_info(nbr,id_poly)
                    
                    poly_to_do += buffer_poly_info
                    
                    poly_ngon.append(id_poly)
                    
                    all_poly_done.append(id_poly)
                    
            if len(poly_ngon) :
                all_ngons.append(poly_ngon)
                    
        save_before.CopyTo(obj,0)
        return all_ngons
      
      
    def main() :
        t = time.time()    
        doc = c4d.documents.GetActiveDocument()
        obj = doc.GetActiveObject()
        print get_ngonv3(obj)
        print time.time() - t
        
        c4d.EventAdd()
      
        t = time.time()    
        doc = c4d.documents.GetActiveDocument()
        obj = doc.GetActiveObject()
        print get_ngon(obj)
        print time.time() - t
      
      
    if __name__=='__main__':
        main()
    

    As said before in some case it fail. Then be carefull using it !

    But looks like no one get a better idea so I will  deal with it and mark it as solved.



  • On 30/11/2016 at 03:31, xxxxxxxx wrote:

    Hi!

    I've investigated the return values of PolygonObject.GetNgonEdgesCompact(). These give information on Ngon edges for each polygon so this function can be used to retrieve all Ngons from a polygon object.

    The function returns a value (bit masked) for each polygon telling which of its edge(s) are actually from an Ngon. If the value is 0 the polygon isn't inside an Ngon.
    Note the statement in the docs about the hidden Ngon edges is wrong. It only gives information on Ngon edges.
    To check if a polygon edge is an Ngon edge use the condition:

    edgeValue & (1 << edgeIndex) == 0
    

    Where edgeValue is the value for a polygon returned by GetNgonEdgesCompact() and edgeIndex the polygon edge index between 0 and 3.

    The following script selects all Ngon edges of a polygon object.
    The function GetNgonEdges() is the most important part where the conversion from GetNgonEdgesCompact() 'local' edges values are converted to the actual polygon object indices.

    import c4d
    from c4d import utils
      
    def GetNgonEdges(op, nbr) :
       # Edge selection for the Ngon edges
        edgeSel = c4d.BaseSelect()
        
        # Retrieve Ngon edges 'local' values for each polygon
        edgesInfo = op.GetNgonEdgesCompact()
        
        # Process each polygon
        polyCount = op.GetPolygonCount()
        for polyIdx in xrange(polyCount) :
            edgeValue = edgesInfo[polyIdx]
            if edgeValue == 0:
                continue
            
            # Retrieve polygon and polygon information
            poly = op.GetPolygon(polyIdx)
            polyInfo = nbr.GetPolyInfo(polyIdx)
            
            # For each edge of polygon
            for edgeIdx in xrange(4) :
                # Check if edge has been already processed
                if polyInfo["mark"][edgeIdx]:
                    continue
                
                # Check if polygon edge is an Ngon edge
                if edgeValue & (1 << edgeIdx) == 0:
                    # Select polygon object Ngon edge
                    # polyInfo['edge'][edgeIdx] gives the polygon object edge index for the polygon edge at edgeIdx
                    edgeSel.Select(polyInfo['edge'][edgeIdx])
        
        return edgeSel
      
    def main() :
        if op is None or op.GetType() != c4d.Opolygon:
            return
        
        if op.GetNgonCount() == 0:
            return
        
        # Set Edges mode
        doc.SetMode(c4d.Medges)
        
        # Create and initialize a Neigbor instance for the object
        nbr = utils.Neighbor()
        nbr.Init(op)
        
        # Process polygon object and obtain Ngon edges
        edgeSel = GetNgonEdges(op, nbr)
      
        # Select Ngon edges
        op.SetSelectedEdges(nbr, edgeSel, c4d.EDGESELECTIONTYPE_SELECTION)
        c4d.EventAdd()
      
    if __name__=='__main__':
        main()
    

    Finally, GetNgonEdgesCompact() gives the info needed on Ngons and using it plus processing its data is fast.


Log in to reply