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

    Neighbor class and disconnected polygons

    SDK Help
    0
    22
    11.9k
    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

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

      On 06/07/2012 at 10:25, xxxxxxxx wrote:

      Well... a Cinema 4D SDK "Bool" is actually typdef'd as an 'int', which would be a 32bit or 64bit value, but the typical use of such a variable is just to store true or false, 1 or 0... which only needs a single bit to represent, but the compiler/cpu can access a 32bit/64bit value just as fast.

      Since a Bool is either 32bits or 64bits (depending on the OS and Compiler options), I am using an 8bit 'unsigned character' (a UCHAR) instead, to save some memory.  I am just using it to store 1 or 0 - true or false.

      So, because of the way C/C++ works, I can test the byte for being 'non-zero'...

        
      UCHAR b = 0;  
        
      if( b ) ...  // would evaluate to false.  
        
      b = 1;  
        
      if( b ) ... // b is now 'non-zero', so it evaluates to true.  
        
      b = 255;  
        
      if( b ) ... // b is still non-zero, so it evaluates to true.  
        
      char *ptr = NULL;  
        
      if( ptr ) ... // since ptr is NULL ( zero ), it evaluates to false.  
        
      char mystring[] = "hello world";  
      ptr = mystring; // or ptr = &mystring[0];  
        
      if( ptr ) ... // since ptr now points to something, it has a non-zero/non-NULL value, so it evaluates to true.  
        
      String c4dStr = String(mystring);        // convert char C string to Cinema 4D String  
      String c4dStr = String("hello world"); // that also works  
      String c4dStr = "hello world";             // so does that  
        
      String c4dStr = "hello";  
      c4dStr += " world";                           // you can also concatenate...  
        
      String c4dStr = String("hello")+String(" world");  // but you might have to use the String() form to add/concatenate on the same statement.  
        
      

      ...basically any value except 0 (or NULL, for pointers) evaluates to true.

      For ASCII values, do a google search to find a chart like this one... where you can see (for example) the ASCII value for the character '0' is the value 48 decimal, so...

        
      char mystring[12];  
      mystring[0] =   72;  // H  
      mystring[1] =  101;  // e  
      mystring[2] =  108;  // l  
      mystring[3] =  108;  // l  
      mystring[4] =  111;  // o  
      mystring[5] =   32;  // <space>  
      mystring[6] =   87;  // W  
      mystring[7] =  111;  // o  
      mystring[8] =  114;  // r  
      mystring[9] =  108;  // l  
      mystring[10] =  100; // d  
      mystring[11] =    0; // null termination.  
        
      String c4dStr = String(mystring);  
      GePrint(c4dStr);   // prints...    "Hello World" (without the quotes)  
      
      1 Reply Last reply Reply Quote 0
      • H
        Helper
        last edited by

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

        On 06/07/2012 at 11:10, xxxxxxxx wrote:

        Thanks for the explanation.
        I understand how you're getting the BOOL now.👍

        I think I was misunderstanding what a UCHAR is. Please check my thinking on this.
        UCHAR is used to store values. Specifically positive values. Not characters as the name seems to imply.
        The same way a DWORD stores unsigned long values. Not strings as the name seems to imply.
        So there is no such thing as converting a UCHAR to a string.

        Is that correct?

        -ScottA

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

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

          On 06/07/2012 at 11:13, xxxxxxxx wrote:

          ...Just for completeness (I'm still not clear exactly what you're asking/trying to accomplish)...

          If you literally want to print the values of a UCHAR array, you can still do that fairly easily...

            
              GePrint(String("PolyProcessed[0] = ")+LongToString((LONG)PolyProcessed[0]));  
          

          ...you could even leave out the (LONG) cast (it would get cast anyway - I just added it for clarity).

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

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

            On 06/07/2012 at 11:15, xxxxxxxx wrote:

            Originally posted by xxxxxxxx

            Thanks for the explanation.
            I understand how you're getting the BOOL now.👍

            I think I was misunderstanding what a UCHAR is. Please check my thinking on this.
            UCHAR is used to store values. Specifically positive values. Not characters as the name seems to imply.
            The same way a DWORD stores unsigned long values. Not strings as the name seems to imply.
            So there is no such thing as converting a UCHAR to a string.

            Is that correct?

            -ScottA

            Yes - you are correct - I'm using it to just store some value between 0 - 255 (and in this case, just either 1 or 0).

            An array of UCHARs is actually a C string, by definition and can be used as such as long as it's null-terminated (erm... and as long as it contains printable characters 🙂 - but not how I'm using it).

            Again, just for completeness/correctness... you can in fact store characters in a UCHAR array...

              
            mystring[0] =  'H';  // H  
            mystring[1] =  'e';  // e  
            mystring[2] =  'l';  // l  
            mystring[3] =  'l';  // l  
            mystring[4] =  'o';  // o  
            mystring[5] =  ' ';  // <space>  
            mystring[6] =  'W';  // W  
            mystring[7] =  'o';  // o  
            mystring[8] =  'r';  // r  
            mystring[9] =  'l';  // l  
            mystring[10] =  'd'; // d  
            mystring[11] = '\0'; // null termination.  
            

            ...the above is equivalent to my previous post, just using characters instead of the equivalent  ASCII values that represent those same characters.

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

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

              On 06/07/2012 at 12:05, xxxxxxxx wrote:

              Thanks a lot for explaining this stuff.
              I did some searching on WCHAR to see If it could help me learn more about UCHAR. But you've eplained it quite well.

              Thank you. 🍺
              -ScottA

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

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

                On 03/08/2012 at 04:43, xxxxxxxx wrote:

                Just a heads up: there is a slight bug in your ConnectedPolyGroup.Init() method.  I've moved ++m_GroupCount to below ProcessConnectedPolys() or your groupIDs are set too high in that method.  Now it appears to be working as expected.

                    Bool    done =                FALSE;  
                  for(LONG polyNdx = 0L; polyNdx != m_numPolys; ++polyNdx)  
                  {  
                      if (m_pDstPolyProcessed[polyNdx])    continue;  
                  
                      // set group index/ID  
                      m_pGroupIDs[polyNdx] =                m_GroupCount;  
                      // mark this one off...  
                      m_pDstPolyProcessed[polyNdx] =        1;  
                      ++m_numMappedPolys;  
                  
                      // set all neighbors to same group index/ID  
                      done =                                this->ProcessConnectedPolys();  
                      // bump group index/ID for next group  
                // THIS HAS BEEN MOVED TO BELOW ProcessConnectedPolys()!  
                      ++m_GroupCount;  
                      if (done)                            break;  
                  }
                
                1 Reply Last reply Reply Quote 0
                • H
                  Helper
                  last edited by

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

                  On 03/08/2012 at 10:03, xxxxxxxx wrote:

                  Hmm... I don't see any difference in what you posted and the latest posted code above (?).  Maybe I found/fixed the post after you had already grabbed the code?  Or am I missing something?

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

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

                    On 03/08/2012 at 10:11, xxxxxxxx wrote:

                    Hehe...... 😉  Must have grabbed an earlier version of the code.  Good that you found it too! 🙂

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

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

                      On 03/08/2012 at 10:22, xxxxxxxx wrote:

                      I thought that might be the case :).  I don't recall what other changes I made (and whether or not any changes were bug-fixes), so you might want to compare the rest of that to what you're using as well.

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

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

                        On 03/08/2012 at 10:33, xxxxxxxx wrote:

                        Just for completeness, here is the latest in-use code...

                          
                        class ConnectedPolyGroup  
                        {  
                        private:  
                          Bool        m_bInit;  
                          LONG        m_numVerts;  
                          LONG        m_numPolys;  
                          LONG        m_numMappedPolys;  
                          LONG        m_GroupCount;  
                          CPolygon    *m_pDstPolys;  
                          UCHAR        *m_pDstPolyProcessed;  
                          UCHAR        *m_pNeighborsAdded;  
                          LONG        *m_pGroupIDs;  
                          Neighbor    m_dstNbr;  
                          
                          Bool ProccessConnectedPolys(void);  
                        public:  
                          void FreeData(void);  
                          BaseSelect *SelectGroup(LONG GroupID);  
                          LONG NumPolys(void)                        { return m_numPolys; }  
                          LONG NumConnectedGroups(void)            { return m_GroupCount; }  
                          LONG GroupID(LONG polyNdx)                { if(!m_bInit || polyNdx >= m_numPolys) return NOTOK;    return  m_pGroupIDs[polyNdx]; }  
                          Bool Init(PolygonObject *pPolyObj);  
                          
                          ConnectedPolyGroup(void);  
                          ~ConnectedPolyGroup(void);  
                        };  
                          
                        ConnectedPolyGroup::ConnectedPolyGroup(void)  
                        {  
                          m_bInit = false;  
                          m_GroupCount = 0;  
                          m_pDstPolyProcessed = NULL;  
                          m_pNeighborsAdded = NULL;  
                          m_pGroupIDs = NULL;  
                        }  
                          
                        ConnectedPolyGroup::~ConnectedPolyGroup(void)  
                        {  
                          this->FreeData();  
                        }  
                          
                        void ConnectedPolyGroup::FreeData(void)  
                        {  
                          bDelete(m_pDstPolyProcessed);  
                          bDelete(m_pNeighborsAdded);  
                          bDelete(m_pGroupIDs);  
                          m_numMappedPolys = 0;  
                          m_GroupCount = 0;  
                          m_numVerts = 0;  
                          m_numPolys = 0;  
                          m_bInit = false;  
                        }  
                          
                        // generate a BaseSelect based on connected GroupID - caller owns returned BaseSelect pointer  
                        BaseSelect *ConnectedPolyGroup::SelectGroup(LONG GroupID)  
                        {  
                          if(!m_bInit || GroupID >= m_GroupCount)    return NULL;  
                          
                          BaseSelect *pSel = BaseSelect::Alloc();  
                          if( !pSel )                                return NULL;  
                          pSel->DeselectAll();    // <-- shouldn't actually be needed  
                          
                          LONG polyNdx;  
                          for(polyNdx=0; polyNdx<m_numPolys; polyNdx++)  
                          {  
                              if( m_pGroupIDs[polyNdx] == GroupID )  
                                  pSel->Select(polyNdx);  
                          }  
                          return pSel;  
                        }  
                          
                        Bool ConnectedPolyGroup::Init(PolygonObject *pPolyObj)  
                        {  
                          this->FreeData();  
                          
                          m_numVerts = pPolyObj->GetPointCount();  
                          m_numPolys = pPolyObj->GetPolygonCount();  
                          m_pDstPolys = pPolyObj->GetPolygonW();  
                          
                          // track which polys have been processed.  
                          m_pDstPolyProcessed = bNew UCHAR[m_numPolys];  
                          if( !m_pDstPolyProcessed )        return false;  
                          
                          // track which polys have had their neighbors added.  
                          m_pNeighborsAdded = bNew UCHAR[m_numPolys];  
                          if( !m_pNeighborsAdded )        return false;  
                          
                          // track which 'connected group' each poly belongs to  
                          m_pGroupIDs = bNew LONG[m_numPolys];  
                          if( !m_pGroupIDs )                return false;  
                          
                          // initialize Neighbor class  
                          if( !m_dstNbr.Init(m_numVerts, m_pDstPolys, m_numPolys, NULL) )    return false;  
                          
                          ClearMem(m_pDstPolyProcessed, m_numPolys * sizeof(UCHAR), 0);  
                          ClearMem(m_pNeighborsAdded, m_numPolys * sizeof(UCHAR), 0);  
                          ClearMem(m_pGroupIDs, m_numPolys * sizeof(LONG), 0);  
                          
                          LONG polyNdx;  
                          Bool done = false;  
                          for(polyNdx=0; polyNdx<m_numPolys; polyNdx++)  
                          {  
                              if( m_pDstPolyProcessed[polyNdx] )    continue;  
                          
                              m_pGroupIDs[polyNdx] = m_GroupCount;                        // set group index/ID  
                              m_pDstPolyProcessed[polyNdx] = 1;                            // mark this one off...  
                              m_numMappedPolys++;  
                          
                              done = this->ProccessConnectedPolys();                        // set all neighbors to same group index/ID  
                          
                              m_GroupCount++;                                                // bump group index/ID for next group  
                              if( done )    break;  
                          }  
                          
                          // done with these...  
                          bDelete(m_pDstPolyProcessed);  
                          bDelete(m_pNeighborsAdded);  
                          m_bInit = true;  
                          return true;  
                        }  
                          
                        Bool ConnectedPolyGroup::ProccessConnectedPolys(void)  
                        {  
                          Bool morePolys = true;  
                          while( morePolys )  
                          {  
                              morePolys = false;  
                              LONG polyNdx;  
                              for(polyNdx=0; polyNdx<m_numPolys; polyNdx++)  
                              {  
                                  if( !m_pDstPolyProcessed[polyNdx] )    continue;    // only adding/processing neighbors of previously matched/valid polys  
                                  if( m_pNeighborsAdded[polyNdx] )    continue;    // don't add/process neighbors if already added  
                          
                        //            CPolygon *pDstPoly = &m_pDstPolys[polyNdx];  
                                  PolyInfo *pDstPolyInfo = m_dstNbr.GetPolyInfo(polyNdx);  
                                  LONG side;  
                                  for(side=0; side<4; side++)  
                                  {  
                                          LONG dstNbrNdx = pDstPolyInfo->face[side];  
                                      if( dstNbrNdx == NOTOK )                continue;    // skip any sides that don't exist  
                                      if( m_pDstPolyProcessed[dstNbrNdx] )    continue;    // only adding neighbors not already added  
                          
                                      m_pGroupIDs[dstNbrNdx] = m_GroupCount;        // all connected polys get the same index/ID  
                                      m_pDstPolyProcessed[dstNbrNdx] = 1;            // mark this one off...  
                                      m_numMappedPolys++;  
                                      morePolys = true;                            // since we added / processed another poly, make sure we loop again to get _it's_ neighbors  
                                  }  
                                  m_pNeighborsAdded[polyNdx] = 1;                    // we've processed this polys neighbors  
                          
                                  if( m_numMappedPolys == m_numPolys )  
                                  {  
                                      morePolys = false;  
                                      break;    // return true?  
                                  }  
                              }  
                          }  
                          if( m_numMappedPolys == m_numPolys )  
                              return true;  
                          return false;  
                        }  
                        

                        ...I _think_ the only difference in that and what's posted above is that I go ahead and free a couple (no-longer-needed) arrays inside Init() instead of waiting for the Destructor.

                        As an aside, based on some later use of this base code (in this thread), I think that I determined that I didn't really need the m_pNeighborsAdded array/checking/tracking at all.

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

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

                          On 04/08/2012 at 07:55, xxxxxxxx wrote:

                          Will compare code and update as needed.  Thanks!

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