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 09/05/2015 at 10:14, xxxxxxxx wrote:

      Hi to all here,
      I'm trying to create a new polygon-object with the polygons selected in a selection-Tag.
      After creating the new object i want to delete the selected polygons.

      Can anybody give me some advice how to do this?

      Thanks a lot.

      Ronald

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

        On 09/05/2015 at 11:51, xxxxxxxx wrote:

        Hi Ronald,

        something like this:

          
        import c4d  
        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  
          
          #deselect current polygonselection  
          polyselection = op.GetPolygonS()  
          polyselection.DeselectAll()  
          
          #select polygons from selectiontag  
          tagselection  =  polseltag.GetBaseSelect()  
          tagselection.CopyTo(polyselection)  
          
          #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                       
          sec[0].InsertUnder(op)  
            
          #delete the polygons from selectiontag  
          utils.SendModelingCommand(command=c4d.MCOMMAND_DELETE,  
                                        list=[op],  
                                        mode=c4d.MODELINGCOMMANDMODE_POLYGONSELECTION,  
                                        doc=doc)  
          c4d.EventAdd()  
                
        if __name__=='__main__':  
          main()  
        

        Best wishes
        Martin

        1 Reply Last reply Reply Quote 0
        • 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