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 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