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

    Null object dimensions

    SDK Help
    0
    25
    13.2k
    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 11/09/2012 at 08:42, xxxxxxxx wrote:

      I thought it would be far more easy. But the rotation-stuff drives me crazy. I can't get it to work properly. 😠
      Could someone please help me on finding the correct algorithm? 🙂

      Here's a small video on what I have achieved so far. As you can hardly see, the rotation is not taken in account correctly.

      Here's the C4D File.

      Thanks in advance,
      Niklas

      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 12/09/2012 at 03:13, xxxxxxxx wrote:

        You need to bring the min max vectors of each object's bounding into global space. This can be done by multiplying with the global matrix of the object.

        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 12/09/2012 at 07:18, xxxxxxxx wrote:

          Hello Matthias,

          thanks for your answer. Hm.. I don't really get it. With the bbmin and bbmax I get two points that
          are "spanning" the bounding box of the object. But when those are rotated, other points of the
          box might be more outside of it. Hard to express. Maybe this video explains it a little more.

          I have tested this just for a single box for now. This is the code I used.

          def bounding_box(op) :  
            mg = op.GetMg()  
            bb = op.GetRad() * mg  
            mp = op.GetMp()  * mg  
            bbmin , bbmax = (mp - bb), (mp + bb)  
            
            mp = (bbmin + bbmax) * 0.5  
            bb = bbmax - mp  
            return bb, mp
          

          Thanks,
          Niklas

          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 12/09/2012 at 07:39, xxxxxxxx wrote:

            Hi,

            here a function I wrote.
            Note that it is not recursive - if you have a Null as a child it won't work properly.
            What it does is go through every points of every object in the group and save the min and max in global coordinates.

              
            # get min and max points of a group in global coordinates  
            def getMinAndMaxPoints(nullObj) :  
              if (nullObj.GetType() != c4d.Onull) :   
                  #no group  
                  children = [nullObj]  
              else:      
                  children = nullObj.GetChildren()  
                    
              groupPos = c4d.Vector(0)  
              groupSize = Vector(0)  
              groupMinPoint = Vector(0)  
              groupMaxPoint = Vector(0)  
                
              start = True  
              for child in children:  
                  mat = child.GetMg()  
                  globalPos = mat.off  
                  points =  child.GetAllPoints()  
                
                  for point in points:  
                        
                      #print(point + globalPos)  
                      point = point + globalPos  
                      if start == True:      
                          start = False  
                          groupMinPoint = Vector(point)  
                          groupMaxPoint = Vector(point)  
                      else:  
                          if groupMinPoint.x > point.x:  
                              groupMinPoint.x = point.x  
                          if groupMinPoint.y > point.y:  
                              groupMinPoint.y = point.y  
                          if groupMinPoint.z > point.z:  
                              groupMinPoint.z = point.z  
                                
                          if groupMaxPoint.x < point.x:  
                              groupMaxPoint.x = point.x  
                          if groupMaxPoint.y < point.y:  
                              groupMaxPoint.y = point.y  
                          if groupMaxPoint.z < point.z:  
                              groupMaxPoint.z = point.z  
                      #end else  
                  #end for points  
              #end for child  
                
              dico = dict()  
              dico["max"] = groupMaxPoint  
              dico["min"] = groupMinPoint  
              return dico  
            

            Alex

            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 12/09/2012 at 09:18, xxxxxxxx wrote:

              @Al3D: Thanks for your code. But this comes with the huge overhead of iterating over each point of
              each object. GetRad() and GetMp() call ObjectData::GetDimension() which does not necessarily iterate
              over each point in the mesh. On a cube for example, for GetRad(), it would just return the half of its
              size (PRIM_LEN_CUBE) instead of iterating over each point it has generated. Also, when using your
              technique, you could easily hit generator objects.

              I'm so sure there is a better technique, but the only one that comes into my mind is to convert the
              bounding-box retrieved by GetRad() and GetMp() into an 8 point cube, multiply each point with the
              matrix and then check each point. Is there a better way to do it?

              Thanks,
              Niklas

              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 12/09/2012 at 11:09, xxxxxxxx wrote:

                csto objs(hierarchy) -> join()   🙂

                Cheers
                Lennart

                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 12/09/2012 at 12:03, xxxxxxxx wrote:

                  @tca: Do you mean for converting the generators? 🙂
                  Well, I actually don't like the idea of using this method at all. In my current project I need to know the
                  BB size in a Tag. This kinda "brute-force" computation would be done every time the tag was
                  executed. I could live with that if it would be once or so :X

                  -Nik

                  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 12/09/2012 at 13:27, xxxxxxxx wrote:

                    The computation actually is very negligible up to rather decent setups.
                    One trick is to strip all tags on the returned csto/Cached hierarchy but
                    variable tags (the invisibles, points etc) before running the join command.
                    The other to run/store some base check data, like hierarchy count, sum
                    of vectors or whatever i.e. as well as compare time.

                    Just an idea anyhow, that I use at times anyway 🙂

                    Cheers
                    Lennart

                    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 13/09/2012 at 06:20, xxxxxxxx wrote:

                      Hey guys,

                      I created a AABBox class for another thread, but expanded it to allow you to add additional objects (cumulative bounding box).  It's in C++, but you're welcome to use/convert it if it's any use...

                        
                      //==================================================================================  
                      // AABBox Class - An implementation of an "Axis Aligned Bounding Box" class  
                      //  
                      // This implementation actually builds a OBB (Oriented Bounding Box) to use as the  
                      // source for generating the AABB.  
                      //  
                      // As implemented, if the object is an instance of a PointObject, it uses the  
                      // (Global-space) points of the object as the OBB.  
                      //  
                      // If it's not a PointObject, it generates a BBox (8-point cube) out of the min/max  
                      // extents of the object (again in Global-space) to use as the OBB.  
                      //  
                      // The class also has provisions for generating a bounding box for a combination of  
                      // multiple objects, as well as a simple collision-detection routine.  
                      //==================================================================================  
                      class AABBox  
                      {  
                      private:  
                        Vector    m_bbMin;  
                        Vector    m_bbMax;  
                        Bool    m_init;  
                        void GetAABBox(BaseObject *op, Vector *pMin, Vector *pMax);  
                        
                      public:  
                        Vector GetMin(void)                        { return m_bbMin; }  
                        Vector GetMax(void)                        { return m_bbMax; }  
                        Bool CollidesWith(BaseObject *op);  
                        void AddObject(BaseObject *op);  
                        void Init(BaseObject *op = NULL);  
                        AABBox(BaseObject *op);  
                        AABBox(void) {    m_init = false; }  
                        ~AABBox(void) {}  
                      };  
                        
                      AABBox::AABBox(BaseObject *op)  
                      {  
                        this->Init(op);  
                      }  
                        
                      void AABBox::Init(BaseObject *op)  
                      {  
                        m_init = false;  
                        m_bbMin = Vector();  
                        m_bbMax = Vector();  
                        if( !op )    return;  
                        
                        this->GetAABBox(op, &m_bbMin, &m_bbMax);  
                        
                        m_init = true;  
                      }  
                        
                      void AABBox::AddObject(BaseObject *op)  
                      {  
                        if( !op )    return;  
                        
                        if( !m_init )  
                        {  
                            this->Init(op);  
                        }  
                        else  
                        {  
                            // first store the old values...  
                            MinMax mm;  
                            mm.Init(m_bbMin);  
                            mm.AddPoint(m_bbMax);  
                        
                            // then add new object...  
                            this->GetAABBox(op, &m_bbMin, &m_bbMax);  
                            mm.AddPoint(m_bbMin);  
                            mm.AddPoint(m_bbMax);  
                        
                            // and determine new extents...  
                            m_bbMin = mm.GetMin();  
                            m_bbMax = mm.GetMax();  
                        }  
                      }  
                        
                      void AABBox::GetAABBox(BaseObject *op, Vector *pMin, Vector *pMax)  
                      {  
                        Matrix opgm = op->GetMgn();  
                        MinMax mm;  
                        
                        //--------------------------------------------------------------------------------------------  
                        // With this implementation, if the BaseObject being passed in is an instance of a PointObject,  
                        // then the OBB will be built from the actual Global-space points... this take longer if there  
                        // are more than 8 points, but gives a tighter fitting AABBox.  If this is too slow, you can  
                        // get rid of this top part and just always do 8 points, below.  
                        //  
                        // to see the difference in using the actual points and the 8 point box, see the image on the  
                        // second page of this article: http://www.gamasutra.com/view/feature/3426/when_two_hearts_collide_.php  
                        //--------------------------------------------------------------------------------------------  
                        if( op->IsInstanceOf(Opoint) )  
                        {  
                            const Vector *pPoints = ToPoint(op)->GetPointR();  
                            LONG i, numPoints = ToPoint(op)->GetPointCount();  
                            mm.Init();  
                            for(i=0; i<numPoints; i++)  
                            {  
                                mm.AddPoint(*pPoints * opgm);  
                                pPoints++;  
                            }  
                        }  
                        else  
                        {  
                            //--------------------------------------------------------------------------------------------  
                            // ...otherwise, generate an 8 point OBB from the Global-space extent vectors  
                            //--------------------------------------------------------------------------------------------  
                            *pMin = op->GetMp() - op->GetRad(); // Bounding-Box minimum extents (Local-space)  
                            *pMax = op->GetMp() + op->GetRad(); // Bounding-Box maximum extents (Local-space)  
                        
                            // bottom  
                            mm.Init(*pMin * opgm);  
                            mm.AddPoint(Vector(pMin->x, pMin->y, pMax->z) * opgm);  
                            mm.AddPoint(Vector(pMax->x, pMin->y, pMax->z) * opgm);  
                            mm.AddPoint(Vector(pMax->x, pMin->y, pMin->z) * opgm);  
                        
                            // top  
                            mm.AddPoint(*pMax * opgm);  
                            mm.AddPoint(Vector(pMax->x, pMax->y, pMin->z) * opgm);  
                            mm.AddPoint(Vector(pMin->x, pMax->y, pMin->z) * opgm);  
                            mm.AddPoint(Vector(pMin->x, pMax->y, pMax->z) * opgm);  
                        }  
                        
                        // convert to AABBox (described by min/max extent vectors)  
                        *pMin = mm.GetMin();  
                        *pMax = mm.GetMax();  
                        
                      //    GePrint(op->GetName()+" bbMin: "+utVecToString(*pMin)+" bbMax: "+utVecToString(*pMax));  
                      }  
                        
                      Bool AABBox::CollidesWith(BaseObject *op)  
                      {  
                        if( !m_init )    return false;  
                        
                        Vector bbMin; // Bounding-Box minimum extents  
                        Vector bbMax; // Bounding-Box maximum extents  
                        
                        this->GetAABBox(op, &bbMin, &bbMax);  
                        
                        Bool xlap, ylap, zlap;  
                        if( bbMin.x < m_bbMax.x && bbMax.x > m_bbMin.x )    xlap = true;    else xlap = false;  
                        if( bbMin.y < m_bbMax.y && bbMax.y > m_bbMin.y )    ylap = true;    else ylap = false;  
                        if( bbMin.z < m_bbMax.z && bbMax.z > m_bbMin.z )    zlap = true;    else zlap = false;  
                        
                        //==================================================================================  
                        // output for testing purposes - delete or comment out it not needed  
                        String slap = op->GetName();  
                        slap += " xlap: ";                slap += xlap ? "true" : "false";  
                        slap += " ylap: ";                slap += ylap ? "true" : "false";  
                        slap += " zlap: ";                slap += zlap ? "true" : "false";  
                        slap += " BBox Collision: ";    slap += (xlap && ylap && zlap) ? "true" : "false";   
                        GePrint(slap);  
                        //==================================================================================  
                        
                        return (xlap && ylap && zlap);  
                      }  
                        
                      //==================================================================================  
                      // simple testing routine... builds AABBox from first object in scene (actually,  
                      // whatever object you pass to it), then tests for collisions with all other  
                      // (root level) objects below it in scene (but doesn't really do anything with  
                      // the results)  
                      //==================================================================================  
                      void BBoxTest(BaseObject *op)  
                      {  
                        if( op )  
                        {  
                            AABBox aabb(op);  
                        
                            BaseObject *op2 = op->GetNext();  
                            LONG collisions = 0;  
                            while( op2 )  
                            {  
                                collisions += aabb.CollidesWith(op2);  
                                op2 = op2->GetNext();  
                            }  
                        }  
                      }  
                        
                      //==================================================================================  
                      // simple testing routine to recursively walk the heirarchy, adding each object to  
                      // the AABBox, to generate a single / cumulative bounding box.  
                      //==================================================================================  
                      void AccumulateBBox(AABBox *aabb, BaseObject *op)  
                      {  
                        if( !aabb )    return;  
                        
                        while(op)  
                        {  
                            aabb->AddObject(op);  
                            AccumulateBBox(aabb, op->GetDown());  
                            op = op->GetNext();  
                        }  
                      }  
                      

                      ...I didn't include any code to call the bottom two test routines, but it should be pretty straight-forward.  Note that you can also get the min/max vectors from the AABBox (which would be in Global-space).

                      Cheers.

                      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 13/09/2012 at 06:33, xxxxxxxx wrote:

                        Giblet, you made my day. Thank you very very much! 🍺
                        I actually need C++, I was just prototyping in Python. 🙂

                        -Niklas

                        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 13/09/2012 at 06:37, xxxxxxxx wrote:

                          Someone mentioned Generators (and Deformers and such)... I hadn't really looked into that, so you might still need to add code to ctso some objects, etc.  Alternatively, you might just doc->Polygonize() first and use that (ctso on the entire doc).

                          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 14/09/2012 at 08:15, xxxxxxxx wrote:

                            Hei folks,

                            in case someone needs it: Here's the working version of the above scene-file using Giblets method (but using GetRad()/GetMp() only!!)

                            Cheers,
                            -Niklas

                            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 14/09/2012 at 11:46, xxxxxxxx wrote:

                              Thanks - it's neat seeing it (working and) ported to Python :). Did you try the full object point-transform method?

                              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 14/09/2012 at 12:55, xxxxxxxx wrote:

                                Did you try the full object point-transform method?
                                Do you mean calculating the bounding-box of point-objects from its points? No. Because,

                                1. I'm pretty sure GetDimension() does this internally for polygon-objects.
                                2. For splines, the curves could exceed the bounding box defined only by the points.

                                -Nik

                                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 14/09/2012 at 13:17, xxxxxxxx wrote:

                                  Originally posted by xxxxxxxx

                                  ...1. I'm pretty sure GetDimension() does this internally for polygon-objects.

                                  Hmm...

                                  • Load your scene, delete the 2 cubes.
                                  • Add a "Tube" object.
                                  • Switch to Front view.
                                  • Rotate the Tube 30deg or so clockwise.
                                  • Make it editable (turn it into a Polygon Object).
                                  • Grab a point and (in Move mode), pull the point up (at that angle).
                                  • Observe that the top of the BBox is no longer 'tight' on the object (across the top/right sides).
                                    ...doing the point-transform method would tighten that box back up (if you needed that).
                                  1 Reply Last reply Reply Quote 0
                                  • H
                                    Helper
                                    last edited by

                                    On 26/06/2015 at 01:43, xxxxxxxx wrote:

                                    Oh i think this would solve my problem with this

                                    https://developers.maxon.net/forum/topic/6903/7745_eventadd-doesnt-update-c4d

                                    Not the topic the solution from NiklasR, but The Python c4d file is 404 missing, here.

                                    Anyhow does somebody have a multiple objects boundingbox Python Script Snippet?

                                    Kind regards
                                    mogh

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