Null object dimensions



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

    On 26/07/2012 at 02:06, xxxxxxxx wrote:

    User Information:
    Cinema 4D Version:   R13.061 
    Platform:   Windows  ;   
    Language(s) :       PYTHON  ;

    ---------
    Hi everybody,

    is there a way to retrieve a bounding box for a null object? I would like to get the dimensions of a non-empty group.
    The getRad() function returns (0,0,0).

    Thanks

    Alex



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

    On 26/07/2012 at 02:10, xxxxxxxx wrote:

    1. You're in the wrong subforum.
    2. I guess you need to calculate it recursively. Need a hint or a full solution?

    -Niklas



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

    On 26/07/2012 at 03:04, xxxxxxxx wrote:

    Hi Niklas,

    Sorry I'm kind of new here but this is the "SDK Help" forum and my question is non python-specific.
    I can calculate recursively - I thought there could be something cleverer to do.

    I guess from your answer there is not.

    Thanks



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

    On 26/07/2012 at 03:07, xxxxxxxx wrote:

    Ok, I agree with you. Sorry. :)
    I haven't found another way to do yet. And I don't think there is.

    -Nik



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

    On 26/07/2012 at 05:22, xxxxxxxx wrote:

    no problem Nick, you gave me the answer I needed 🙂



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

    On 26/07/2012 at 07:45, xxxxxxxx wrote:

    I'm afraid it must be done recursively. I've asked the developers to make sure. I'll post my findings.

    cheers,
    Matthias



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

    On 27/07/2012 at 04:57, xxxxxxxx wrote:

    FYI, recursive calculation is the "official" way indeed, at least that's what the Coordinate Managers Size+ mode is doing.

    cheers,
    Matthias



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

    On 27/07/2012 at 07:19, xxxxxxxx wrote:

    Originally posted by xxxxxxxx

    I guess you need to calculate it recursively. Need a hint or a full solution?
    -Niklas

    Hey Niklas,
    I would like a hint or a solution if you don't mind providing one.🙂
    Because in this case I don't really know what you guys mean by the term "recursive".
    The definition I know of for that word is calling a function from within the same function. But I don't see how that relates to finding the dimensions of a null.

    -ScottA



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

    On 27/07/2012 at 07:55, xxxxxxxx wrote:

    In this case recursive just means to traverse the given hierarchy. Then you can get the bounding box of each child object and use this to calculate the bounding box of the whole hierarchy.

    cheers,
    Matthias



  • 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



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



  • 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



  • 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



  • 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



  • 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



  • 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



  • 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



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



  • 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



  • 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).


Log in to reply