Plugin Cafe Homepage
Forum Home Forum Home > Plugin Cafe > PYTHON Development
  New Posts New Posts
  FAQ FAQ  Forum Search

Get all ngons [SOLVED]

Author
Message
  Topic Search Topic Search
gr4ph0s View Drop Down
Member
Member


Joined: 2015 Jul 07
Location: France
Online Status: Offline
Posts: 437
Direct Link To This Post Topic: Get all ngons [SOLVED]
    Posted: 2016 Nov 23 at 3:27am
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 :)


Edited by gr4ph0s - 2016 Nov 28 at 1:49am
Back to Top
Yannick Puech View Drop Down
Forum Moderator
Forum Moderator


Joined: 2011 Apr 13
Location: Spain
Online Status: Offline
Posts: 1143
Direct Link To This Post Posted: 2016 Nov 25 at 9:54am
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().



MAXON
Developer Support
Back to Top
ScottA View Drop Down
Member
Member


Joined: 2011 Jan 07
Online Status: Offline
Posts: 2288
Direct Link To This Post Posted: 2016 Nov 25 at 11:04am
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
Back to Top
gr4ph0s View Drop Down
Member
Member


Joined: 2015 Jul 07
Location: France
Online Status: Offline
Posts: 437
Direct Link To This Post Posted: 2016 Nov 27 at 8:37am
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 :)


Edited by gr4ph0s - 2016 Nov 28 at 1:48am
Back to Top
gr4ph0s View Drop Down
Member
Member


Joined: 2015 Jul 07
Location: France
Online Status: Offline
Posts: 437
Direct Link To This Post Posted: 2016 Nov 28 at 1:49am
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.


Edited by gr4ph0s - 2016 Nov 28 at 1:49am
Back to Top
Yannick Puech View Drop Down
Forum Moderator
Forum Moderator


Joined: 2011 Apr 13
Location: Spain
Online Status: Offline
Posts: 1143
Direct Link To This Post Posted: 2016 Nov 30 at 3:31am
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.





Edited by Yannick Puech - 2016 Nov 30 at 3:35am
MAXON
Developer Support
Back to Top

Forum Jump Forum Permissions View Drop Down

Bulletin Board Software by Web Wiz Forums® version 9.61 [Free Express Edition]
Copyright ©2001-2009 Web Wiz

This page was generated in 0.141 seconds.