how to create polygonobj from selection [SOLVED]



  • 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



  • 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



  • On 18/05/2015 at 05:50, xxxxxxxx wrote:

    Hi Ronald,

    did Martin's solution work for you?



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



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


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



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


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



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



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



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



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


Log in to reply