Maxon Developers Maxon Developers
    • Documentation
      • Cinema 4D Python API
      • Cinema 4D C++ API
      • Cineware API
      • ZBrush Python 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

    how to create polygonobj from selection [SOLVED]

    PYTHON Development
    0
    12
    1.8k
    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 18/05/2015 at 05:50, xxxxxxxx wrote:

      Hi Ronald,

      did Martin's solution work for you?

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

        On 18/05/2015 at 08:12, xxxxxxxx wrote:

        Hi Andreas,

        jes, it works fine.

        I hoped for a solutuion with reading the Points and then generating a new Object and build up new the Mesch.
        But this Code works also verry well.

        Thanks a lot to C4D-Plugin-Cafe 🙂

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

          On 18/05/2015 at 14:26, xxxxxxxx wrote:

          Hi Ronald,

          I didn´t test the performance, but this script rearranges points and polygons without a modeling command.
          Hope this is what you´re aiming for.

          Best wishes
          Martin

            
          import c4d  
          from c4d import utils  
            
          def AddPoly(op, newop, poly, count, occindex) :  
              
            pointcount = newop.GetPointCount()      
            index = ( poly.a, poly.b, poly.c, poly.d )  
            newindex = []  
                 
            #traversing through the actual point indices  
            #write unique points to the newobject   
            #write a new index list to assign them to the new polygon accordingly  
            for nr in index:             
                if nr not in occindex:  
                    occindex.append(nr)  
                    length = len(occindex)  
                    newop.ResizeObject(length,count+1)  
                    newop.SetPoint(length-1,op.GetPoint(nr))          
                    newindex.append(pointcount)  
                    pointcount +=1  
                else:  
                    newop.ResizeObject(pointcount,count+1)  
                    newindex.append(occindex.index(nr))  
              
            #write the new polygon  
            newop.SetPolygon(count,c4d.CPolygon(newindex[0],newindex[1],newindex[2],newindex[3]))          
            newop.Message (c4d.MSG_UPDATE)  
            return newop  
            
            
          def main() :  
              
            #validate object and selectiontag  
            if not op:return  
            if not op.IsInstanceOf(c4d.Opolygon) :return  
            polseltag = op.GetTag(c4d.Tpolygonselection)  
            if not polseltag: return  
            doc.StartUndo()  
              
            #deselect current polygonselection  
            polyselection = op.GetPolygonS()  
            doc.AddUndo(c4d.UNDOTYPE_CHANGE_NOCHILDREN,op)  
            polyselection.DeselectAll()  
            
            #select polygons from selectiontag  
            tagselection  =  polseltag.GetBaseSelect()  
            tagselection.CopyTo(polyselection)  
              
            #set up the new object, define an empty occupied pointindex list and a polycounter  
            maxpolies = op.GetPolygonCount()  
            newop = c4d.BaseObject(c4d.Opolygon)  
            occindex = []      
            count = 0  
              
            #travers through all polygons and extract those from the selection to a new polygonobject  
            for i in xrange(maxpolies) :  
                if polyselection.IsSelected(i) :   
                    newop = AddPoly(op, newop, op.GetPolygon(i), count, occindex)  
                    count +=1  
                      
                                 
            doc.InsertObject(newop)    
            doc.AddUndo(c4d.UNDOTYPE_NEW, newop)     
              
              
            #delete the polygons from selectiontag  
            utils.SendModelingCommand(command=c4d.MCOMMAND_DELETE,  
                                          list=[op],  
                                          mode=c4d.MODELINGCOMMANDMODE_POLYGONSELECTION,  
                                          doc=doc)    
                                            
            doc.EndUndo()   
            c4d.EventAdd()  
            
            
          if __name__=='__main__':  
            main()  
          
          1 Reply Last reply Reply Quote 0
          • H
            Helper
            last edited by

            On 19/05/2015 at 02:45, xxxxxxxx wrote:

            Hi Monkeytrack,

            I can't beleve what you are sending here.
               

            I will test it and report.

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

              On 19/05/2015 at 02:51, xxxxxxxx wrote:

              Hi Ronald,

              in the morning hours I did some speed tests and found a very fast solution with a dict.
              Actually it is a lot faster than the modeling command.
              Hope you are fine with this script.

              A question to the support team:
              Why is the modelling command that slow and could it be optimized?

              Best wishes
              Martin

                
              import c4d, time  
              from c4d import utils  
                
                
              def main() :  
                  
                #validate object and selectiontag  
                if not op:return  
                if not op.IsInstanceOf(c4d.Opolygon) :return  
                polseltag = op.GetTag(c4d.Tpolygonselection)  
                if not polseltag: return  
                doc.StartUndo()  
                  
                #deselect current polygonselection  
                polyselection = op.GetPolygonS()  
                doc.AddUndo(c4d.UNDOTYPE_CHANGE_NOCHILDREN,op)  
                polyselection.DeselectAll()  
                
                #select polygons from selectiontag  
                tagselection  =  polseltag.GetBaseSelect()  
                tagselection.CopyTo(polyselection)  
                  
                #v1 numerically  
                #v2 modelling command  
                v = 1  
                  
                t = time.time()  
                  
                if v == 1:  
                      
                    #V1  
                    #set up the new object, define an empty occupied pointindex list and a polycounter  
                    maxpolies = op.GetPolygonCount()  
                      
                    newop = c4d.BaseObject(c4d.Opolygon)  
                    pointindex = []    
                    polies = []  
                    pointcount = 0    
                    polycount = 0  
                  
                    #travers through all polygons and extract those from the selection to a new polygonobject  
                    for i in xrange(maxpolies) :  
                        if polyselection.IsSelected(i) :   
                            polycount +=1  
                            poly = op.GetPolygon(i)  
                            polies.append(poly)  
                              
                            if poly.IsTriangle() :  
                                pointindex.append(poly.a)  
                                pointindex.append(poly.b)  
                                pointindex.append(poly.c)  
                                  
                            else:  
                                pointindex.append(poly.a)  
                                pointindex.append(poly.b)  
                                pointindex.append(poly.c)  
                                pointindex.append(poly.d)  
                                  
                    index = list(set(pointindex))  
                    pointcount = len(index)  
                    newop.ResizeObject(pointcount, polycount)    
                      
                    pointdict = {}  
                    for i in xrange(pointcount) :  
                        point = index[i]  
                        pointdict[point] = i  
                        newop.SetPoint(i,op.GetPoint(point))   
                      
                    for p in xrange(polycount) :  
                        newop.SetPolygon(p,c4d.CPolygon(pointdict[polies[p].a],pointdict[polies[p].b],pointdict[polies[p].c],pointdict[polies[p].d]))  
                          
                      
                      
                    newop.Message (c4d.MSG_UPDATE)                 
                    doc.InsertObject(newop)    
                    doc.AddUndo(c4d.UNDOTYPE_NEW, newop)     
                    t1 = time.time() - t  
                    print "split numerically in "+ str(t1) + " sec"  
                  
                if v == 2:  
                    #V2  
                    #split: polygonselection to a new object  
                    sec = utils.SendModelingCommand(command=c4d.MCOMMAND_SPLIT,  
                                              list=[op],  
                                              mode=c4d.MODELINGCOMMANDMODE_POLYGONSELECTION,  
                                              doc=doc)  
                    if not sec: return        
                    doc.AddUndo(c4d.UNDOTYPE_NEW, sec[0])     
                    doc.InsertObject(sec[0])           
                      
                  
                    t1 = time.time() - t  
                    print "split modelling command in "+ str(t1) + " sec"  
                  
                  
                  
                #delete the polygons from selectiontag  
                utils.SendModelingCommand(command=c4d.MCOMMAND_DELETE,  
                                              list=[op],  
                                              mode=c4d.MODELINGCOMMANDMODE_POLYGONSELECTION,  
                                              doc=doc)    
                                                
                doc.EndUndo()   
                c4d.EventAdd()  
                
                
                
              if __name__=='__main__':  
                main()  
                
              
              1 Reply Last reply Reply Quote 0
              • H
                Helper
                last edited by

                On 19/05/2015 at 07:31, xxxxxxxx wrote:

                Hi Martin,

                first I'd like to say, the entire SDK Support team watched this thread and was pretty fascinated. Good job! Thanks for making our lifes easier.
                Regarding modelling command so slow, I have to admit, I don't know. I'm a bit confused about your result as well. Several options come to my mind (for example the actual overhead of SendModellingCommand) and one could probably do a lot of benchmarking on this (like is it just slower by a constant offset and this has less influence the larger the objects and selections get, or is the time scaling with size of object and selection). Unfortunately we are currently lacking the time to do such research. So I have to leave your question open. Sorry.

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

                  On 20/05/2015 at 01:18, xxxxxxxx wrote:

                  Nice observations and code Monkeytrack..

                  I observed this recently with MCOMMAND_DELETE among others, in C++,  refactoring and cleaning up some rough code from SMC to the Modeling library class, i hesitate to say this as it sounds ridiculous - but it was actually up to 4000 times faster.. 😕

                  Without testing it myself - what speed differences were you getting with the above code?

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

                    On 20/05/2015 at 11:58, xxxxxxxx wrote:

                    Thank you guys for your encouraging words!
                    I´m really glad I could help some people out there and push things further.

                    Benchmarking the algorithm and the modeling command it turns out that my algorithm gets less effective the more polygons are selected.
                    For most cases the algorithm is up to 25x faster, but in the worst case(every polygon is selected)
                    it´s up to 10x slower.
                    I guess in cases where more than half of the polygons are selected every experienced 3d artist would do an opposite operation, like clone the object and delete the inverse selection.
                    Nevertheless, the next step could be to implement an evaluation sequence at the beginning to decide which strategy is more effective.

                    @Eclectrik
                    This sounds really incredible 4000 times…

                    To improve the algorithm and in general I´m very interested in your approaches regarding the MCOMMAND_DELETE .
                    Could you please post a link or PM me some more information about it?

                    Best wishes
                    Martin

                    Edit:
                    Actually I benchmarked a 1000*1000*1000 6 million polygons standart cube
                    with a random selection of 3 million polygons and the modeling command was 185 times slower.
                    Now I can imagine that it took 4000 times...

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

                      On 20/05/2015 at 18:46, xxxxxxxx wrote:

                      Hi Monkeytack,

                      I know, it genuinely does sound unbelievable.  Looking back over my results and stepping back through my code it is not QUITE comparing like for like, because each time i refactored some code it might have a knock on effect and i was doing quite a lot of refactoring from rough proof of concept code with SMC to much more optimised routines with the Modeling library..

                      So with that said, these are the numbers i was getting as i progressed through the code, refactoring things as i went along:

                      TOTAL TIME [0] Clone Object       : 116.997
                      TOTAL TIME [1] Selection          : 0.147
                      TOTAL TIME [2] Expand Selection   : 84.621
                      TOTAL TIME [3] Expand+Toggle      : 59.416
                      TOTAL TIME [4] DeletePoints       : 4709.945
                      TOTAL TIME [5] Selection Copying  : 0.086
                      TOTAL TIME [6] SUBDIVIDE          : 198.487
                      TOTAL TIME [7] Invert+Delete      : 339.949
                      ----------------------------------------
                      TOTAL TIME [0]: 130.604
                      TOTAL TIME [1]: 0.147
                      TOTAL TIME [2]: 61.658
                      TOTAL TIME [3]: 52.876
                      TOTAL TIME [4]: 1.595 ( DELETE POLYS with MODELING LIB )
                      TOTAL TIME [5]: 0.719
                      TOTAL TIME [6]: 1226.877
                      TOTAL TIME [7]: 14430.343
                      -----------------------------------------------
                      TOTAL TIME [0]: 140.582
                      TOTAL TIME [1]: 0.168
                      TOTAL TIME [2]: 62.127
                      TOTAL TIME [3]: 53.323
                      TOTAL TIME [4]: 1.382 ( DELETE POINTS with MODELING LIB )
                      TOTAL TIME [5]: 0.792
                      TOTAL TIME [6]: 1226.605
                      TOTAL TIME [7]: 0.081  ( DELETE POLYS with MODELING LIB )
                      -----------------------------------------------
                      TOTAL TIME [0]: 134.465
                      TOTAL TIME [1]: 0.205
                      TOTAL TIME [2]: 76.892
                      TOTAL TIME [3]: 5.25  ( DELETE POLYS with MODELING LIB )
                      TOTAL TIME [4]: 0.011 ( DELETE POINTS with MODELING LIB )
                      TOTAL TIME [5]: 0.767
                      TOTAL TIME [6]: 1178.104
                      TOTAL TIME [7]: 0.071  ( DELETE POLYS with MODELING LIB )
                      -----------------------------------------------
                      TOTAL TIME [0]: 204.797
                      TOTAL TIME [1]: 0.857
                      TOTAL TIME [2]: 5.171  ( EXPAND SELECTION with MODELING LIB )
                      TOTAL TIME [3]: 0.024  ( DELETE POLYS with MODELING LIB )
                      TOTAL TIME [4]: 0.008 ( DELETE POINTS with MODELING LIB )
                      TOTAL TIME [5]: 0.791
                      TOTAL TIME [6]: 1113.044
                      TOTAL TIME [7]: 0.07  ( DELETE POLYS with MODELING LIB )
                      -----------------------------------------------
                      

                      These TOTAL TIME numbers are the accumulation of each chunk of code running on 12 separate threads, added together ( not averaged ).  The knock on effect can be seen as i change one part the next part might jump up considerably ( possibly due to switching from point to poly selections/ops or from a greater number of points/polys being passed down the chain ).  But still, massively substantial gains were got from going from what was pretty much a chain of SendModelingCommand's with lots of BaseSelect stuff inbetween, to more optimised Modeling class and similar code..

                      For the MCOMMAND_DELETE parts, basically i went from for example:

                      // Delete Outer Points
                      pointSel->ToggleAll(0,clone->GetPointCount());
                      ModelingCommandData cd3;
                      cd3.doc = doc;
                      cd3.op = clone;
                      cd3.mode = MODELINGCOMMANDMODE_POINTSELECTION;
                      SendModelingCommand(MCOMMAND_DELETE, cd3);
                      

                      To the following:

                      // Delete Outer Points - left with Fragment+
                      mod || !mod->InitObject(clone);
                      pointSel->ToggleAll(0,clone->GetPointCount());
                        
                      while (pointSel->GetRange(seg++,MAXLONGl,&a,&b))
                      {
                      	for (i=a; i<=b; ++i)
                      	{
                      		if (i>=pIndexStart && i<LONG(pLength+pIndexStart))
                      		{
                      			mod->DeletePoint(clone,i);
                      		}
                      	}
                      }
                      mod->Commit();
                      

                      This is all C++ code of course, but the Python equivalents aren't too different..

                      Also my initial attempt at speeding up the object Cloning looked like the following but was a bit slower than just using ->GetClone(COPYFLAGS_0,NULL) so will have to look at that some more:

                      //PolygonObject *clone = ToPoly(op->GetClone(COPYFLAGS_0, NULL));
                        
                      LONG pcnt = op->GetPointCount(),vcnt = op->GetPolygonCount();
                      AutoAlloc<PolygonObject> clone(pcnt,vcnt);
                      c4d_misc::BaseArray<LONG> pointindex;
                      c4d_misc::BaseArray<Ngon> polies;
                      const CPolygon *cpolyOP = op->GetPolygonR();
                      CPolygon *cpolyCLONE = clone->GetPolygonW();
                        
                      for (i=0; i<vcnt; i++)
                      {
                      	for (j=0;j<4;j++)
                      	{
                      		cpolyCLONE[i][j] = cpolyOP[i][j];
                      	}
                      }
                      

                      PS - The TOTAL TIME value above for DeletePoints at 4000+, i have no idea now why that was so high on that earlier run ( i did use the same test document throughout ) but the numbers were copy/pasted directly from the Console, so it did happen!  But either way it can be seen elsewhere in the numbers where huge time savings have been made..

                      PSPS - Please excuse any typos or mistakes in any of the above, i'm exposing my maverick coding style here - i do generally end up with nice clean code in the end 🙂

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

                        On 21/05/2015 at 12:03, xxxxxxxx wrote:

                        Hi Eclectrik,

                        thanks a million for sharing your development, code and results.
                        That really looks like a time saver.
                        As it would go beyond the scope of this thread´s topic, I´ll answer you by PM once I understand your development and did some research.

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