BuildNgonFromPolys() failing...



  • THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED

    On 10/03/2006 at 14:52, xxxxxxxx wrote:

    User Information:
    Cinema 4D Version:   9.1 
    Platform:   Windows  ;   
    Language(s) :     C++  ;

    ---------
    Me again :)...
    Ok, I've switched back to Riptide, while I wait on some responses about the selection-tag stuff.
    I'm trying to update Riptide (.obj import/export plugin) to work with R9+ Ngons and could use some help.
    At this time, as I scan over the input file, I'm keeping track of 'which' polygons have more than 4 edges and then breaking them up into triangles.  Once the PolygonObject has been created, I then loop through my ngon list and try to build the ngons, like so...
    ... snip ...
     op = PolygonObject::Alloc(m_numVerts,m_numFaces);
     padr = op->GetPoint();
     vadr = op->GetPolygon();

    // ...various other stuff happens here to read the file and build up the PolygonObject...
    if( m_numNgons )
     {
      op->ResizeObject(m_numVerts, m_numFaces, m_numNgons);
      pNgonBase = op->GetNgonBase();
      if( pNgonBase )
      {
       NgonLoader *pNgons = &m_pNgons[0]; // NgonLoader is my own structure
       for(i=0; i<m_numNgons; i++)
       {
        LONG cnt;
        cnt = pNgonBase->BuildNgonFromPolys(pNgons->polys, NULL, pNgons->polycnt, 0, vadr, padr);
        GePrint("cnt = "+LongToString(cnt));
        pNgons++;
       }
       pNgonBase->InitMap();
      }
     }
    ... snip ...
    ...so, in the above, pNgons->polys is an array of the sub-set of polygon indices that make up that ngon and pNgons->polycnt is the number of polygon indices in that array, for that ngon and vadr/padr are the face/point arrays for the entire PolygonObject.
    The problem is, BuildNgonFromPolys() is failing (returns NOTOK).  Can someone tell me where I went wrong?  According to the docs, the second param (LONG* outer) is optional, which I assume means that I don't need to supply it.
    Any help would be appreciated,
    Thanks.
    - Keith



  • THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED

    On 11/03/2006 at 04:31, xxxxxxxx wrote:

    A couple questions to go along with the above...
    1. Should I NOT be adding the triangles to the mesh, if I intend to BuildNgonFromPolys() as above?
    2. Should I use the modelling library (CreateNgon() with the points instead of polys), instead?
    3. If I do use the modelling library, should I add the triangle polygons (that make up the Ngons) to the PolygonObject, or not?
    ...I assumed or at least thought I understood that all the quads and triangular polygons still exist in the PolygonObject and that the Ngons are just stored as additional information in the PolygonObject (essentually just hiding some edges), but the example code for the Modelling Library uses CreateNgon() but doesn't add any tris/quads.
    Ideally, I'd prefer that the vertex and even polygon ordering not get changed - if that helps define the approach to use.  I was hoping that something as simple as the code above would work, but I have no idea why it's failing.
    Thanks.



  • THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED

    On 11/03/2006 at 04:39, xxxxxxxx wrote:

    ...it shouldn't really matter, but just some additional information - the pNgons->polys array in the top post above is an array of indices to a set of triangles that will be combined into the Ngon.
    The triangles themsleves are basically a 'fan', where they ALL join at one common point (the first point given in each case).  So the faces look like this:
    0,1,2
    0,2,3
    0,3,4
    0,4,5
    0,5,6
    etc.
    ...my test-case file has a total of 16 points around the fan, which makes up 13 triangular CPolygons.



  • THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED

    On 13/03/2006 at 04:12, xxxxxxxx wrote:

    I'm mostly guessing here.. but perhaps it helps.

    1. Should work with Tris and Quads, otherwise it would surely be mentioned in the docs.

    2. Whatever works best. CreateNgon will create the polys for you, so it might get messy if you have reqular quads/tris, too.. and is most likely slower.

    3. I'm pretty sure that CreateNgon will generate all necessary polys.

    Yes, quads and tris do exist for ngons. It is as you say, the ngon system is a layer ontop of the usual tris/quads data.

    I think the last info does matter. I don't think you can have a point ( the fan center ) in the middle of a ngon. Points are only at the boundary edges. Perhaps if you supply the edge info in the "outer" array, Cinema will detect this case and use it's own triangulation of the ngon. Anyway, i think if you want to preserve the fan structure, you can't use ngons.

    Another issue i just remembered is the ordering of ngon polys. I think they must be at the end of the polygon array, and arranged in blocks that make up the ngons. Like this:

      
    p1 ...      pa| pa+1 ... pb| pb+1 ... pc| ...  
    quads/tris    |   ngon1    |    ngon2   | ...  
    


  • THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED

    On 13/03/2006 at 05:22, xxxxxxxx wrote:

    Hi Michael,
    Thanks.. that gives me a few more things to try.  Except that the fan is not a wagon-wheel  (where the common vertex would be at the hub/center), it's more like a hand-held-fan... the shared vertex is on the outer edge.
    The polys are already grouped together by virtue of how/when they are created, but currently, they could be anywhere within the poly array, so maybe that's the thing that's tripping me up... I understand that C4D stores the ngon polys at the end of the polys array (?), but do you think the polys being fed to BuildNgonFromPolys() also need to be at the end of the list?
    Thanks again,
    - Keith



  • THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED

    On 13/03/2006 at 08:26, xxxxxxxx wrote:

    Ok, I boiled it down to a simple test plugin to try a few things.  Could someone tell me what I'm doing wrong?  Here's the tester plugin:

        
        
          
        //===============================================================  
        // Ngon Tester : MAIN MODULE  
        //===============================================================  
        #include "c4d.h"  
        // #include "c4d_symbols.h"
        
        
        
        
        enum  
        {  
         _FIRST_ELEMENT_      = 10000,  
         // Global string definitions start here  
         IDS_NGON,  
         // Global string definitions end here
        
        
        
        
         // End of symbol definition  
         _DUMMY_ELEMENT_  
        };  
        
        
        
        
        
        #define NGONTEST_PLUGID 1019532 
        
        
        
        
        class NgonPluginData : public CommandData  
        {  
         public:  
          virtual Bool Execute(BaseDocument *doc);  
          virtual LONG GetState(BaseDocument *doc);  
        };
        
        
        
        
        //===============================================================  
        // try to create an Ngon from the currently selected polygons  
        // of the currently selected PolygonObject.  
        //===============================================================  
        Bool NgonPluginData::Execute(BaseDocument *doc)  
        {  
         if( !doc )  
          return false;
        
        
        
        
         PolygonObject *pObj = ToPoly(doc->GetActiveObject());  
         if( !pObj )  
          return false;
        
        
        
        
         if( pObj->GetType() != Opolygon )  
          return false;
        
        
        
        
         BaseSelect *pBs = pObj->GetPolygonS();  
         if( !pBs )  
          return false;
        
        
        
        
         LONG selCnt = pBs->GetCount();  
         if( selCnt < 2 )  
          return false;
        
        
        
        
         Vector *pVerts = pObj->GetPoint();  
         CPolygon *pPolys = pObj->GetPolygon();
        
        
        
        
         LONG numVerts = pObj->GetPointCount();;  
         LONG numPolys = pObj->GetPolygonCount();  
         LONG numNgons = pObj->GetNgonCount();
        
        
        
        
         NgonBase *pNgonBase = pObj->GetNgonBase();  
         if( !pNgonBase )  
          return false;
        
        
        
        
         pObj->ResizeObject(numVerts, numPolys, numNgons+1);
        
        
        
        
         LONG *array = (LONG * )GeAlloc(selCnt * sizeof(LONG));  
         LONG i, j, a, b;
        
        
        
        
         j = 0;  
         for (i=0;pBs->GetRange(i,&a,&b);i++)  
         {  
          for (;a<=b;a++)  
          {  
           array[j++] = a;  
           if( j == selCnt ) j--; // sanity check  
          }  
         }
        
        
        
        
         LONG result = pNgonBase->BuildNgonFromPolys(array, NULL, selCnt, 0, pPolys, pVerts);  
         GePrint("result = "+LongToString(result));  
         pNgonBase->InitMap();  
         pObj->Message(MSG_UPDATE);  
         GeFree(array);
        
        
        
        
         return true;  
        }
        
        
        
        
          
        LONG NgonPluginData::GetState(BaseDocument *doc)  
        {  
         BaseObject *pbObj = doc->GetActiveObject();
        
        
        
        
         if( pbObj && pbObj->GetType() == Opolygon )  
          return CMD_ENABLED;  
         else  
          return 0;  
        }
        
        
        
        
          
        //===============================================================  
        // plugin stuff below  
        //===============================================================  
        Bool RegisterNgonTest(void)  
        {  
         String name=GeLoadString(IDS_NGON); if (!name.Content()) return TRUE;  
         return RegisterCommandPlugin(NGONTEST_PLUGID,name,0,"ngon.tif","",gNew NgonPluginData);  
        }
        
        
        
        
        Bool PluginStart(void)  
        {  
         LONG c4dversion = GetC4DVersion();  
         if (!resource.Init()) return FALSE;  
         if ( c4dversion < 9000 ) return false;  
         if (!RegisterNgonTest()) return false;  
         GePrint(String("Ngon Tester v1.0 by Keith Young"));  
         return true;  
        }
        
        
        
        
        void PluginEnd(void){}  
        Bool PluginMessage(LONG id, void *data){return false;}
        
        
        
        
        //-------- END OF FILE - SNIP HERE -------------------------  
        
    

    ...this plugin tries to combine the currently selected polygons into an Ngon - seems fairly straight forward, but does not work, so I assume that I'm just confused and/or missing some steps somewhere along the line.
    Any help would be appreciated - thanks,
    - Keith



  • THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED

    On 13/03/2006 at 08:38, xxxxxxxx wrote:

    "Another issue i just remembered is the ordering of ngon polys. I think they must be at the end of the polygon array, and arranged in blocks that make up the ngons. Like this:

        
        
          
        p1 ...      pa| pa+1 ... pb| pb+1 ... pc| ...  
        quads/tris    |   ngon1    |    ngon2   | ...  
        
    

    "

    ...hmm, are you saying that I need to add duplicates of the polygons that make up the Ngons to the end of the polygon list?  I assumed that BuildNgonFromPolys() would handle that.  If I do need to duplicate the polys myself, I'm not clear on what the ResizeObject() call should be... higher polycount + higher Ngon count?



  • THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED

    On 13/03/2006 at 09:16, xxxxxxxx wrote:

    I don't know if polys are dublicated.. i would say no, but it is possible.. I guess you are right that BuildNgonFromPolys() should handle this, or any reordering that might be nessesary.

    I would write that test plugin above, just in the same way you did, so i really don't know what is wrong.

    Perhaps you could look at an existing objects with ngons to see how the polys are ordered ( GetPolygonTranslationMap() )



  • THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED

    On 15/03/2006 at 07:18, xxxxxxxx wrote:

    Thanks Michael.
    Just to clarify - still no joy on this.  If someone from Maxon could look at my plugin above and explain why it's not working, I'd appreciate it.
    Thanks,
    - Keith



  • THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED

    On 15/03/2006 at 08:04, xxxxxxxx wrote:

    BuildNgonFromPolys needs the ngon outline passing in 'outer', the docs incorrectly state this is optional.
    To build an ngon, you can use the Modeling class and CreateNgon in which case it will create the ngon itself (the outline defining it) and the internal polygons that form the ngon. If you already have the polygons then you can use either the BuildNgon of BuildNgonFromPolys in which case you have the ngon already triangulated as polygons and just want to add the ngon outline.
    I took a quick look over your posted code, you don't need the ResizeObject and if you are not changing a value in ResizeObject then just pass NOTOK.



  • THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED

    On 15/03/2006 at 10:34, xxxxxxxx wrote:

    Great - Thanks!
    So, BuildNgonFromPolys() takes care of resizing the object - cool. I guess that leads me to my next question :)... if I need to pass the outer array, could you explain how that is built?  in other words, how are the edge indices computed?  per polygon passed in?  based on the set I pass in?  based on the entire list of polygons in the object?  Is there some sort of 'GetEdges()' helper function for a PolygonObject?
    I'll look through the docs again, but I don;t recall seeing anything on that subject (at least, related to BuildNgonFromPolys()).
    Thanks again,
    - Keith



  • THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED

    On 15/03/2006 at 10:50, xxxxxxxx wrote:

    ...actually, I'm not even clear on what the 'outer' array IS :).  Here's the SDK docs:
    LONG* outer
    > An optional array of the outline of the N-gon. You can use the internal mark (PGONEDGE_ENDSEGMENT) to mark segments in the N-gon outline. The caller owns the pointed array.
    >
    > ...so is outer an array of polygon indices?  an array of edge indices (and if so, where/how are they computed)? something else?
    >
    > Thanks.
    >
    >



  • THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED

    On 15/03/2006 at 13:44, xxxxxxxx wrote:

    The SDK doc is actually incorrect for the outer, unlike the BuildNgon function the BuildNgonFromPolys can not support holes so the 'outer' is simply an array of the ngon outer edges.
    If you need to use holes then BuildNgon must be used. Normally this function is used because you already know the ngon outline and have triangulated the ngon yourself so wish to pass the ngons outer edges and also the polygons for the triangulation (e.g. during file import).
    If you don't already know the ngon outline then you will need to find this based on whatever you do know, is that just a list of connected polygons? The Neighbor class might help if you just know the vertices or polygons.



  • THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED

    On 16/03/2006 at 02:13, xxxxxxxx wrote:

    Ahh, thanks again David... but related to the above:
    1. I don't need to create holes.
    2. I know exactly which polygon indices will make up the Ngon and those polys are already created.
    3. I know exactly which vertex (point) indices are used to make up the outer edge of the polygon.
    ...the issue that's still not clear to me is:
    >> ...so the 'outer' is simply an array of the ngon outer edges.
    ...sorry if I'm being dense, but I guess I still hadn't found a way to know what 'index' any particular edge a->b of a particular polygon IS.  It sounds like every edge found within the PolygonObject has a unique/numbered index and that that index value is what the array is made up from, but I don't know how to GET that index value for the edges in question.
    If it was simply an array of the POINT indices that make up the Ngon, that would be simple - I have those readily available.  But to get the edge indices, the round-about way I see so far would be to:
    - initialize a Neighbor object with the PolygonObject info
    - for each triangle that will make up the Ngon, call polyinfo = neighbor->GetPolyInfo()
    - In my particular case, the first two (outer) edges of each triangle are the ones I need an index for, so I get those two PolygonObject-relative 'edge index' values from polyinfo->edge[0] and polyinfo->edge[1] (???)
    ...is that right? Is that the uniquely numbered edge indices I need for the array passed to BuildNgonFromPolys() ? (from some initial tests, that doesn't seem to work).
    - Keith



  • THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED

    On 16/03/2006 at 02:17, xxxxxxxx wrote:

    ...also, if I don't call ResizeObject(), then my call to GetNgonBase() fails (at least if the object has ot yet been attached to the document... I can go ahead and add it to the document first, but I'm still fuzzy on building the edge-index array).



  • THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED

    On 16/03/2006 at 02:44, xxxxxxxx wrote:

    - In my particular case, the first two (outer) edges of each triangle are the ones I need an index for, so I get those two PolygonObject-relative 'edge index' values from polyinfo->edge[0] and polyinfo->edge[1] (???)
    ..sorry, I had typed that question in before I tried the code.  In my particular case (loading .obj files from disk and triangulating the Ngons and reversing the winding order to show up in C4D correctly...) what I actually needed was two edges from the last triangle (0,2), two edges from the first triangle (0,1) and just the middle edge (0) from the other triangles.
    But it's still not working.  And in fact, I'm crashing the app with what I'm doing....sigh.



  • THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED

    On 16/03/2006 at 03:12, xxxxxxxx wrote:

    The NgonBase is created only if Ngons are needed (to save memory), a way to force this to be created when you have no ngons but will be needing to add them is to call GetNgon. Once that has been called then GetNgonBase should return a valid pointer provided everything went ok. (see Modeling Library in the SDK docs)
    Edges are defined as the polygon index * 4 + (0 to 3) for each edge around the quad (see PolyInfo in the SDK docs). Building the ngons from what you have is just a case of passing the BuildNgonFromPolys the array of polygons and then an array of edges that form the outline of the ngon.
    The outline edges are easily found from the vertices using the Neighbor class. Take the first vertex in your array and use GetPointPolys to find all polygons associated with that vertex, then look at each one and find the edge that matches to the next vertex in your array, that will give you the edge. Repeat this around your vertices and you'll have an array of the corresponding edges. The outline array must be ordered so each edge is the next one around the ngon.
    You could also use the modeling library, delete all polygons that are part of each ngon and use CreateNgon with the vertices you have to rebuild the ngons. The Modeling library will then triangulate them itself on Commit.



  • THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED

    On 16/03/2006 at 03:20, xxxxxxxx wrote:

    Sorry for the spam-fest :)... I'm just at a loss for what's going on.  Has anyone ever used BuildNgonFromPolys() successfully?   I'd realy like to use that, because as far as I can tell, other methods of creating Ngons will end up re-ordering my vertices and/or polygons (which would break morph targets = a bad thing ).
    Would it be possible to get any sort of (known to be working) example code that uses BuildNgonFromPolys()?   This is just taking far too much of my time (and yours, I presume)  trying to devine meaning from the given documentation in present form.
    If it was just for me, I'd just blow off this feature all together (I don't need Ngons for my purposes - or this frustration), but I made a promise (to Maxon) to update Riptide to work with R9 and Ngons, so.... here we are.
    Your help is and has been much appreciated - thanks,
    - Keith



  • THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED

    On 16/03/2006 at 03:22, xxxxxxxx wrote:

    Good Morning David.. we cross-posted.. let me read through your latest reply and see if anything clicks.
    Thanks,
    - Keith



  • THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED

    On 16/03/2006 at 04:02, xxxxxxxx wrote:

    I did a search and could find no use of BuildNgonFromPolys in any CINEMA core source, it looks like an unused function. Reason is probably that is easier to use BuildNgon since you don't need to pass a list of polygons, just the outer edges or internal edges (in your case outer is easier to find). Both functions are actually just helpers, you could also just use the Create function and build the ngon edges yourself; however this means adding in the correct marked bits but in your case this is much easier since you have no holes.
    Generally it is much easier to use the modeling library and leave it to deal with the internal ngon data, however, in some case (like import when you have the polygons already) or generators (where you need speed) you have to use the direct ngon library itself which is more complicated.
    First thing to get right is to build your edge outline as I mentioned, once you have this then you have options on how to build/create an ngon. If you only need to keep your vertex order then you can use the CreateNgon of the modeling library, this will not change your vertex order. The modeling library always tries to keep the order of anything it can, even on deleting vertices it will only remap those that it needs to in order to fit the new point count. If you need to keep your polygons and vertices then you'll have to build the ngon manually from the edges.
    Here is a small cut of source that uses BuildNgon for import:

        
        
        LONG ngon_start=0,ngon_end=0,eind=0,lastface=NOTOK;  
        LONG *edges = (LONG* )GeAlloc(sizeof(LONG)*4*polyanz);  
        PolygonObject *pObj = obj;
        
        
        pObj->GetNgon(); // necessary to build variables
        
        
        NgonBase *pNgons=pObj->GetNgonBase();
        
        
        
        
        if (pNgons && edges)
        
        
        {
        
        
          pObj->Message(MSG_UPDATE);
        
        
        
        
          LONG i=0;
        
        
        
        
          for (t=0; t<=fmax;)
        
        
          {
        
            if (t<fmax)
        
        
            {
        
        
              f=(WFFace* )group->face.Get(t++); if (!f) { SetError(); break; }
        
              anz = f->fnum;
        
        
            }
        
        
            else
        
        
              anz = 3;
        
        
        
        
            if (anz==3 || anz==4)
        
        
            {
        
              if (lastface==NOTOK) lastface = f->realface;
        
        
        
        
              if (t==fmax || f->realface!=lastface)
        
        
              {
        
        
                if (ngon_end-ngon_start>1)
        
        
                {
        
        
                  if (pNgons->BuildNgon(edges,NULL,eind,0,pObj->GetPolygon(),pObj->GetPoint())==NOTINDEX)
        
        
                  {
        
        
                    // error
        
                  }
        
                }
        
        
        
        
                if (t==fmax) break;
        
        
        
        
                ngon_start=ngon_end=i;
        
        
                lastface=f->realface;
        
        
                eind=0;
        
        
              }
        
        
        
        
              if (f->bits&1) 
        
        
                edges[eind++] = 4*i+1;
        
        
        
        
              if (f->bits&2) 
        
        
                edges[eind++] = 4*i+0;
        
        
        
        
              if (f->bits&4) 
        
        
                edges[eind++] = 4*i+3;
        
        
        
        
              ngon_end=i;
        
        
        
        
              i++;
        
        
            }
        
        
        
        
            t += anz;
        
        
          }
        
        
        
        
          pNgons->InitMap();
        
        
          pNgons->SetFlags(NGON_FLAG_NOVALIDATION);
        
        
          pObj->Message(MSG_UPDATE);
        
        
        
        
        }
        
        
        
        
        GeFree(edges);
    

    Note the NGON_FLAG_NOVALIDATION is set prior to a MSG_UPDATE to inform the ngon handler that it does not need to check any of the structural changes to the object since the ngons are known to be valid. When ngons are found and MSG_UPDATE is called without this flag set then the ngon handler must check all polygon changes have no invalidated the ngon structures, if they have the invalid ngons are removed. This overhead is costly so it should be avoided when possible, e.g. on import when you know the data is correct.


Log in to reply