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 Point Positions of Selected N-Gon or Polygon

    General Talk
    5
    11
    2.5k
    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.
    • ferdinandF
      ferdinand
      last edited by ferdinand

      Hi,

      you forgot to tag your question, but from your history I assume this a Python question. There is PolygonObject. GetPolygonTranslationMap and PolygonObject.GetNGonTranslationMap which will allow you to translate between Ngon and Quads/Tri indices. Which in turn will you allow to infer the point indices.

      But note that there is no Ngon type in Python. Which means that interacting with them is quite limited. One workaround is to use SendModellingCommand to let Cinema's core do whatever you are trying to do with the Ngons.

      Cheers,
      zipit

      MAXON SDK Specialist
      developers.maxon.net

      1 Reply Last reply Reply Quote 0
      • CairynC
        Cairyn
        last edited by

        Speaking of PolygonObject.GetNGonTranslationMap, the Python description seems to be wrong (copied from the C++ docs?). The doc says

        ngoncnt (int) – The number of N-gons. Pass the length of the list returned by GetPolygonTranslationMap(), not the value given by GetNgonCount().
        

        but the number needed here is not the length of the list (second return value), but the first return value of GetPolygonTranslationMap.

        For the return value, the doc explains

        The number of polygons in N-gon i is stored in list[i][0].
        Then the polygon indices are stored in list[i][j] where j goes from 1 to list[i][0].
        

        but the number of polygons is not stored at all. The sublists are simply the polygon indices, and the number must be inferred with the len() function.

        (Newest online docs, tested with R21)

        1 Reply Last reply Reply Quote 1
        • ManuelM
          Manuel
          last edited by Manuel

          hello,

          you have a old post explaining what are ngons here

          I've assumed the selected polygon or ngon are done by the user. If so, every polygon that compose a N-gon will be selected.
          Ngon doesn't exist in c4d, there's only tri and quads. Ngon are a group of tri or quads.

          In the object itself, we manage quads and tri.

          So you have to retrieve the selected polygon, convert that selection to points selection. Retrieves the coordinates of the selected points.

          This is the code without error check but it make it shorter and easier to understand.

          import c4d
          from c4d import gui
          # Welcome to the world of Python
          
          
          def ConvertFromPolyToPoint(obj):
              #Retrieves the selected polygons
              bs = obj.GetPolygonS()
              #Gets All Points and point count
              points = obj.GetAllPoints()
              pcnt = obj.GetPointCount()
              
              # Gets the Boolean array for every polygons
              selectedPolygon = bs.GetAll(pcnt)
              # Creates a BaseSelect for points (convert polygon selection to point selection)
              bsPoint = c4d.BaseSelect()
              
              # Checks all polygon to see if they are selected
              for i, selected in enumerate(selectedPolygon):
                  if selected:
                      # select all the points that belong to that polygon
                      cPoly = op.GetPolygon(i)
                      bsPoint.Select( cPoly.a)
                      bsPoint.Select( cPoly.b)
                      bsPoint.Select( cPoly.c)
                      bsPoint.Select( cPoly.d)
              # Retrieves the selected point as an array
              selectedPoint = bsPoint.GetAll(pcnt)
              return selectedPoint
             
          
          def GetSelectedPointPosition (obj):
              # Converts the selected polygon to an array of selected points
              selectedPoint = ConvertFromPolyToPoint(obj)
              # Retrieves all the points
              points = obj.GetAllPoints()
              
              pointsPosition = []
              for point, selected in zip(points, selectedPoint):
                  if selected:
                      pointsPosition.append(point)
              
              return pointsPosition
          # Main function
          def main():
              pointsPosition = GetSelectedPointPosition(op)
              print (len (pointsPosition), pointsPosition)
             
             
              # Execute main()
          if __name__=='__main__':
              main()
          

          Of course, if you want to retrieve the position of all the ngons of an object than you have to retrieves the ngon list first.

          @Cairyn
          you are absolutely right, i will update the documentation right now.

          Cheers,
          Manuel

          MAXON SDK Specialist

          MAXON Registered Developer

          1 Reply Last reply Reply Quote 0
          • N
            noseman
            last edited by

            Thank you everyone, and I'll make sure to tag my posts next time.

            1 Reply Last reply Reply Quote 0
            • X
              x_nerve
              last edited by x_nerve

              HI:
              I found a way to get the global coordinates and indexes of all the points on N_gons.The Python script can select all N_gons faces, select points on all N_gons faces, and get the global coordinates and index of the points.

              Two Suggestions by the way:

              1.GetAllPoints() is used to get all the coordinates, but these are local coordinates, which need to be converted to global coordinates, and the results converted to global coordinates are usually correct.However, it is difficult to obtain the global coordinates of all points in the cache. Can you provide global coordinate parameters for all points?

              1. After the polygon object is baked as. ABC file, if the number of polygons is 0, the objects in the cache will change from polygons to blank objects.Can the cache still be a polygon object if the number of points is zero?

              The script code is as follows:

              import c4d
              from c4d import utils
              
              def main():
                  
                  Polygons = op.GetAllPolygons()
              
                  Selected_Polygon = op.GetPolygonS()
                  
                  #Determines whether n-gons edges exist on all polygon faces of the current object.
                  N_gons = op.GetNgonEdgesCompact()
              
                  Polygons_index  = [i for i,o in enumerate(Polygons)]
                  
                  #N-gons edge Numbers on all N-Gons faces.
                  N_gons_Edge_number = [h for h,z in enumerate(N_gons) if z > 0]
              
                  #select N-gons face.
                  Selected_Polygon.DeselectAll()
                  sele = [ Selected_Polygon.Select(ty) for ty in N_gons_Edge_number
                          if len(Polygons_index) == len(N_gons) ]
                  
                  #Toggle select mode.
                  bc = c4d.BaseContainer()
                  bc.SetData(c4d.MDATA_CONVERTSELECTION_LEFT, 2)        #ConvertSelection's Left "Polygons" option in memory
                  bc.SetData(c4d.MDATA_CONVERTSELECTION_RIGHT, 0)       #ConvertSelection's Right "Edges" option in memory
                  #bc.SetData(c4d.MDATA_CONVERTSELECTION_TOLERANT, True) #Select the selection->ConvertSelection's "Tolerant" option in memory
                  utils.SendModelingCommand(c4d.MCOMMAND_CONVERTSELECTION, 
                                              list = [op], 
                                              mode = c4d.MODELINGCOMMANDMODE_POLYGONSELECTION, 
                                              bc=bc, 
                                              doc = doc)
              
                  #Gets the global coordinates and index of the points on the N-gons plane.
                  All_Point = op.GetAllPoints()
                  PointS = op.GetPointS()
                  Pointe_Array = PointS.GetAll(op.GetPointCount())
              
                  All_posits = [(Arra,index) 
                                  for Arra,index in enumerate(All_Point)]
                                  
                  posit = [(Array,indexe) 
                          for Array,indexe in enumerate(All_Point) 
                          if Pointe_Array[Array] == 1]
              
                  #The global matrix of the current object.
                  op_matrix = op.GetMg()
              
                  matrix = []
                  for orientation in posit:
                      mt = c4d.Matrix()
                      mt.off = orientation[1]
                      m_mt = op_matrix * mt
                      matrix.append((orientation[0],m_mt))
                  
                  #Global coordinates and index of points on the N-GONS plane.
                  point_position = [(t[0],t[1].off) for t in matrix]
                  print point_position
                  
                  #Select all points on the N-gons side.
                  PointS.DeselectAll()
                  sele_point = [ PointS.Select(ty[0]) 
                              for ty in point_position]
                  
                  c4d.EventAdd()
              
              if __name__=='__main__':
                  main()
              N 1 Reply Last reply Reply Quote 0
              • N
                noseman @x_nerve
                last edited by

                @x_nerve Thanks!

                1 Reply Last reply Reply Quote 0
                • ManuelM
                  Manuel
                  last edited by

                  @x_nerve said in Get Point Positions of Selected N-Gon or Polygon:

                  1.GetAllPoints() is used to get all the coordinates, but these are local coordinates, which need to be converted to global coordinates, and the results converted to global coordinates are usually correct.However, it is difficult to obtain the global coordinates of all points in the cache. Can you provide global coordinate parameters for all points?

                  2.After the polygon object is baked as. ABC file, if the number of polygons is 0, the objects in the cache will change from polygons to blank objects.Can the cache still be a polygon object if the number of points is zero?

                  1. yes i forgot it was local coordinate but global coordinates are just the matrix of the object * the local coordinates:
                      points = op.GetAllPoints()
                      mg = op.GetMg()
                      points = [mg * i for i in points]
                      print points
                  

                  If you retrieve the cache, you will retrieve a polygon object. So i don't understand why it will be difficult to retrieve the points's position. Retrieving an updated cache yes, it can sometimes be a kind of headache. Can you be a bit more clear about that ?

                  2- I didn't checked the result of the export alembic file (nor our code) but what do you mean "as blank objects" a null object ?
                  If you have a good argument for that, i will be happy to add a suggestion in our database and ping our devs to change that. Unless they have a really good reason to return a blank object they will be also happy to update it.

                  Cheers,
                  Manuel

                  MAXON SDK Specialist

                  MAXON Registered Developer

                  1 Reply Last reply Reply Quote 0
                  • X
                    x_nerve
                    last edited by

                    HI:
                    I found that if a polygon object has zero points on frame 0, using Alembic baking, it will only bake into blank objects.But as long as the initial number of points is not zero, the baking is normal.

                    The Python Tag script code is as follows, really just baking into blank objects.

                    
                    import c4d
                    
                    def main():
                    
                        obj = op.GetObject()
                        frame = doc.GetTime().GetFrame(doc.GetFps())
                    
                        if frame >= 25:
                            obj.ResizeObject(4,1)
                            points = [c4d.Vector(0, 0, 0),c4d.Vector(-100, 0, 0),
                                    c4d.Vector(-100, 100, 0),c4d.Vector(0, 100, 0)]
                    
                            obj.SetAllPoints(points)
                    
                            cpolygon = c4d.CPolygon(0,1,2,3)
                    
                            obj.SetPolygon(0,cpolygon)
                    
                            obj.Message(c4d.MSG_UPDATE)
                            c4d.EventAdd()
                    
                        else:
                            obj.ResizeObject(0, 0)
                            obj.Message(c4d.MSG_UPDATE)
                            c4d.EventAdd()
                    
                        if frame >= 65:
                            obj.ResizeObject(0, 0)
                            obj.Message(c4d.MSG_UPDATE)
                            c4d.EventAdd()
                    
                    if __name__=='__main__':
                        main()
                    1 Reply Last reply Reply Quote 0
                    • ManuelM
                      Manuel
                      last edited by

                      @x_nerve said in Get Point Positions of Selected N-Gon or Polygon:

                      I found that if a polygon object has zero points on frame 0, using Alembic baking, it will only bake into blank objects.But as long as the initial number of points is not zero, the baking is normal.

                      Thanks a lot for the feedback, I could reproduce that on S22 but not on R23, so it's seems to be already fixed.

                      If you found some other bugs, feel free to report them to our support team -> https://support.maxon.net/index.php?lang=en_US
                      This one in particular isn't related to our API so there's no need to report to us.

                      Cheers,
                      Manuel

                      MAXON SDK Specialist

                      MAXON Registered Developer

                      1 Reply Last reply Reply Quote 0
                      • X
                        x_nerve
                        last edited by

                        Hi:

                        This is a bit of a hassle, but can still be scripted, who CARES about an extra polygon.

                        import c4d
                        
                        def main():
                        
                            polygons = op.GetAllPolygons()
                            points = op.GetAllPoints()
                            point = [c4d.Vector(10000, 10000, 10000),c4d.Vector(9999, 10000,10000),
                                    c4d.Vector(9999, 10000, 10001),c4d.Vector(10000, 10000, 10001)]
                        
                            point_indexe = [[len(points) + i ,point[i]]
                                            for i in range(len(point))]
                        
                            op.ResizeObject(len(points) + len(point),len(polygons) + 1)
                        
                            set_point = [op.SetPoint(k[0], k[1])
                                            for k in point_indexe]
                        
                            op.Message(c4d.MSG_UPDATE)
                            c4d.EventAdd()
                        
                        if __name__=='__main__':
                            main()
                        1 Reply Last reply Reply Quote 0
                        • First post
                          Last post