Neighbor class and disconnected polygons
-
THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED
On 06/07/2012 at 09:58, xxxxxxxx wrote:
Thanks.
I'm new to this whole ASCII, Unicode, etc.. stuff. And I'm trying to figure it all out.-I still don't see how you're getting a BOOL value from a UCHAR array.
-I would also like to know how to convert a UCHAR value to a String value. If that's possible.-ScottA
-
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)
-
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
-
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).
-
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.
-
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 -
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; }
-
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?
-
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!
-
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.
-
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.
-
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!