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
Martinimport 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
Martinimport 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
MartinEdit:
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.