Get Point Positions of Selected N-Gon or Polygon



  • What's the simplest way to get all point positions of a selected Polygon (including N-Gons)?
    Cheers



  • 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



  • 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)



  • 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



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



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


  • @x_nerve Thanks!



  • @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



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


  • @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



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

Log in to reply