Offsetting Handles



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

    On 11/08/2012 at 12:44, xxxxxxxx wrote:

    User Information:
    Cinema 4D Version:   R13, R14 
    Platform:   Windows  ;   
    Language(s) :     C++  ;

    ---------
    Hello dear supporter-team and plugincaférs,

    I've been trying to get this to work for a few days now, but I can not get my head around it. The situation is the following:

    I have an object plugin that shows some handles in the editor. The handle detecting and moving is implemented by myself, so I do not use the GetHandle()/SetHandle() convenience functions (has several reasons).

    The handles work properly so far. But what I want to implement, is to move one of my virtually generated objects in relative space, and move the handles with it! Or more precisely, I want to align one of my virtual objects on one of the planes, and the handles must stay centered to the object.

    What I can do is to put the handles at the correct position (with their offset) and detecting them accordingly. The only thing that does not work is dragging the handle.

    To be more precise, my own GetHandle() and SetHandle() implementations return the position of the handles if they were not offset. The offset is retrieved by the subclasses implementation of ObjectData::GetDimension(). For DetectHandle() and Draw(), I just add the bounding-boxes mid-point to the handle's position. For the MoveHandle() method, I subtract the bounding-boxes mid-point from the handle's position. But that doesn't work properly.

    This is the code I use to draw, detect and move the handles. It's just some (for this topic) unimportant lines that have been removed.

    DRAWRESULT MyObjectData::Draw(BaseObject* op, DRAWPASS drawpass, BaseDraw* bd, BaseDrawHelp* bh) {  
      if (drawpass isnot DRAWPASS_HANDLES) return DRAWRESULT_OK;  
      
      bd->SetMatrix_Matrix(op, bh->GetMg());  
      
      // Obtain the object's bounding-box information.  
      Vector mp, size;  
      GetDimension(op, &mp, &size);  
      
      // Draw the handles onto screen.  
      LONG hitid = op->GetHighlightHandle(bd);  
      for (LONG i=0; i < get_handle_count(op); i++) {  
          HandleInfo info;  
          if (not get_handle(op, i, info)) continue;  
      
          // Offset the handle by the object's bounding-box center.  
          info.position += mp;  
      
          /// Handle drawing..  
          /// ...  
      }  
      
      return DRAWRESULT_OK;  
    }  
      
    LONG MyObjectData::DetectHandle(BaseObject* op, BaseDraw* bd, LONG x, LONG y, QUALIFIER qualifier) {  
      Matrix matrix = op->GetMg();  
      LONG handle = NOTOK;  
      bool shift = qualifier & QUALIFIER_SHIFT;  
      
      // Obtain the object's bounding-box information.  
      Vector mp, size;  
      GetDimension(op, &mp, &size);  
      
      // Iterate over each handle and check if one of theese match at  
      // the current mouse-position.  
      for (LONG i=0; i < get_handle_count(op); i++) {  
          HandleInfo info;  
          if (not get_handle(op, i, info)) continue;  
      
          // Offset the handle by the object's bounding-box center.  
          info.position += mp;  
      
          if (bd->PointInRange(info.position * matrix, x, y)) {  
              handle = i;  
      
              // Use this handle when SHIFT is not pressed (which means  
              // to use the first handle found). Otherwise, the last handle  
              // will be used.  
              if (shift) break;  
          }  
      }  
      
      return handle;  
    }  
      
    Bool MyObjectData::MoveHandle(BaseObject* op, BaseObject* undo, const Vector& mouse_pos, LONG hitid, QUALIFIER qualifier, BaseDraw* bd) {  
      if (not op) return False;  
      
      // Get the identified handle. Do not continue if get_handle() returned  
      // False.  
      HandleInfo info;  
      if (not get_handle(op, hitid, info)) return True;  
      
      // Compute the handles new position.  
      Matrix matrix = op->GetMg();  
      info.position = info.CalculateNewPosition(bd, matrix, mouse_pos);  
      
      // Offset the handle by the object's bounding-box center.  
      Vector mp, size;  
      GetDimension(op, &mp, &size);  
      info.position -= mp;  
      
      // Invoke the procedure that implements the data-processing of the handle.  
      return set_handle(op, hitid, info);  
    }
    

    Neither adding, nor subtracting the bounding-boxes mid-point to the handle's position in MoveHandle() achieves the desired behavior. The following video gives you some visual overview.

    YouTube Video
    About the video:
    The first part of the video is without modifieng the handle's position returned from get_handle(). The second part (after i shortly paused the video in Camtasia studio) is the MoveHandle() method as you can see it above. Instead of subtract, but adding mp to the handles position has the same effect, but reversed (when aligning to X+ it just gets insanely high increased (dragging on the + side) or lowered (dragging on the - side), when aligning to X- it does flicker weirdly).

    Does someone know how I can achieve the desired behavior? 🙂
    Any hints are very much appreciated. Thanks in advance,
    Niklas

    // Edit: I just appeared to me that the mouse is not shown in the video. Angry
    Basically, in the first part of the video, the mouse must be moved like if the handles were not offset. That's almost ok. When starting to drag the handle, the boxes' size is set to (almost) zero (because of limits I did set programmatically).
    In the second part when the box is aligned to the YZ plane on the X- side, dragging around with the mouse on the X+ side insanely increases the boxes' size. Dragging on the X- side somewhere around makes it shrink a little.
    When it is aligned to the YZ plane on the X+ side, the mouse position matches with the handle, but the box flickers awkwardly..

    Was that precise enough? If not, please tell me and I will make another video (trying to enable the mouse somehow).



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

    On 12/08/2012 at 08:00, xxxxxxxx wrote:

    Seems like there is some magic going on in the SetHandle()/GetHandle() convenience functions and the corresponding implementation of DetectHandle() and MoveHandle(). I have created a tag that does exactly the same but offset not the virtual objects but the actual object.I can use the tag on a normal cube object, it is offset correctly and the handle-dragging is like desired. But when putting it on my own primitive with my own DetectHandle()/MoveHandle() implementation, it is the same behaviour if I was offsetting it's virtual object's and adjust the handle's position just like above.

    What magic am I missing in the MoveHandle() function? 😢

    -Nik



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

    On 12/08/2012 at 08:19, xxxxxxxx wrote:

    Yeaaay! I got it working! 🙂
    But I don't understand the math behind it..

    Bool MyObjectData::MoveHandle(BaseObject* op, BaseObject* undo, const Vector& mouse_pos, LONG hitid, QUALIFIER qualifier, BaseDraw* bd) {  
      if (not op) return False;  
      
      // Get the identified handle. Do not continue if get_handle() returned  
      // False.  
      HandleInfo info;  
      if (not get_handle(op, hitid, info)) return True;  
      
      // Compute the handles new position.  
      //Matrix matrix = op->GetMg();  
        Matrix matrix = op->GetUpMg() * undo->GetMl();  
      info.position = info.CalculateNewPosition(bd, matrix, mouse_pos);  
      
      // Invoke the procedure that implements the data-processing of the handle.  
      return set_handle(op, hitid, info);  
    }
    

    I copied the red marked line from c4d_objectplugin.cpp and suddenly, it all works as expected and desired. I'm happy with it, but would really like to understand the math behind it..

    -Niklas


Log in to reply