Maxon Developers Maxon Developers
    • Documentation
      • Cinema 4D Python API
      • Cinema 4D C++ API
      • Cineware API
      • ZBrush GoZ API
      • Code Examples on Github
    • Forum
    • Downloads
    • Support
      • Support Procedures
      • Registered Developer Program
      • Plugin IDs
      • Contact Us
    • Categories
      • Overview
      • News & Information
      • Cinema 4D SDK Support
      • Cineware SDK Support
      • ZBrush 4D SDK Support
      • Bugs
      • General Talk
    • Unread
    • Recent
    • Tags
    • Users
    • Login

    Get all ngons [SOLVED]

    PYTHON Development
    0
    6
    1.3k
    Loading More Posts
    • Oldest to Newest
    • Newest to Oldest
    • Most Votes
    Reply
    • Reply as topic
    Log in to reply
    This topic has been deleted. Only users with topic management privileges can see it.
    • H
      Helper
      last edited by

      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 🙂

      1 Reply Last reply Reply Quote 0
      • H
        Helper
        last edited by

        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().

        1 Reply Last reply Reply Quote 0
        • H
          Helper
          last edited by

          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

          1 Reply Last reply Reply Quote 0
          • H
            Helper
            last edited by

            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 🙂

            1 Reply Last reply Reply Quote 0
            • H
              Helper
              last edited by

              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.

              1 Reply Last reply Reply Quote 0
              • H
                Helper
                last edited by

                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.

                1 Reply Last reply Reply Quote 0
                • First post
                  Last post