Site Tools


Showing Dynamic Object Transformations

.NET

Version: Rhino 4.0
Summary: Demonstrates how to show objects transformating dynamically.
NOTICE: The Rhino.NET SDK is deprecated in Rhino 5. This example adapted for the new RhinoCommon SDK is here

Overview

One of the more common questions we receive is how to show dynamic object transformations. This is, how can one write commands, such as Rhino's Move, Copy, Scale, Mirror, etc., that show how an object will be transformed from one location to another. There have been several transformation-specific examples posted on the Rhino developer newsgroup and on the developer wiki. Most of these examples show how to inherit from MRhinoGetPoint and override its OnMouseMove and DynamicDraw members to show objects transformations.

In an effort to provide reusable code, we would like to present the following abstract class that you can use in your .NET plug-ins to help you show objects transforming dynamically. The abstract RhinoGetTransform class inherits from MRhinoGetObject and has a single abstract member function, CalculateTransform that you have to implement. The following sample code is in C#, but it should not take much effort to port this to VB.NET. It should also be noted that this class will show grips transforming dynamically, as well as regular Rhino objects, such as curves and surfaces.

///////////////////////////////////////////////////////////////////////////
// Abstract class used to show objects transforming dynamically
public abstract class RhinoGetTransform : RMA.Rhino.MRhinoGetPoint
{
  protected MRhinoXformObjectList m_list;
  protected OnXform m_xform;
  protected bool m_bHaveXform;
  protected On3dPoint m_base;
 
  /////////////////////////////////////////////////////////////////////////
  // Constructor
  public RhinoGetTransform() : base()
  {
    m_list = new MRhinoXformObjectList();
    m_xform = new OnXform();
    m_xform.Identity();
    m_bHaveXform = false;
    m_base = new On3dPoint();
    m_base.Set(0,0,0);
  }
 
  /////////////////////////////////////////////////////////////////////////
  // STEP 1: Use MRhinoGet member functions to specify command prompt
 
  /////////////////////////////////////////////////////////////////////////
  // STEP 2: Use MRhinoGet member functions to specify what types of
  //         alternate input can be accepted.
 
  /////////////////////////////////////////////////////////////////////////
  // STEP 3: Add any objects you want transformed and grips you want
  //         transformed.  Make sure no duplicates are in the list
  //         and that no grip owners are passed in as objects.
  public void AppendObjects(IRhinoGetObject go)
  {
    m_list.AddObjects(go, true);
  }
 
  public void AppendObjects(IRhinoXformObjectList list)
  {
    m_list = (MRhinoXformObjectList)list;
  }
 
  public void AppendObject(IRhinoObject obj)
  {
    m_list.AddObject(obj);
  }
 
  /////////////////////////////////////////////////////////////////////////
  // STEP 4: Override this abstract function to provide your own custom
  //         transformation method. Call this function to retrieve
  //         the final transformation.
  public abstract bool CalculateTransform(MRhinoViewport vp, IOn3dPoint point, ref OnXform xform);
 
  /////////////////////////////////////////////////////////////////////////
  // STEP 5: Override this virtual function to provide your own custom
  //         method get a transform object.
  public virtual IRhinoGet.result GetXform()
  {
    IRhinoGet.result res = base.GetPoint();
    if (res == IRhinoGet.result.cancel)
    {
      for (int i = 0; i < m_list.m_grip_owners.Length; i++)
      {
        MRhinoObjectGrips grips = m_list.m_grip_owners[i].m_grips;
        if (grips != null)
          grips.Reset();
      }
    }
    return res;
  }
 
  /////////////////////////////////////////////////////////////////////////
  // Overridden MRhinoGetPoint::SetBasePoint
  public new void SetBasePoint(IOn3dPoint base_point)
  {
    m_base = (On3dPoint)base_point;
    base.SetBasePoint(base_point);
  }
 
  /////////////////////////////////////////////////////////////////////////
  // Overridden MRhinoGetPoint::OnMouseMove
  public override void OnMouseMove(MRhinoViewport vp, uint flags, IOn3dPoint pt, System.Drawing.Point view_wnd_point)
  {
    m_bHaveXform = CalculateTransform(vp, pt, ref m_xform);
    if (!m_bHaveXform)
      m_xform.Identity();
 
    for (int i = 0; i < m_list.m_grips.Length; i++)
      m_list.m_grips[i].MoveGrip(m_xform);
 
    base.OnMouseMove(vp, flags, pt, view_wnd_point);
  }
 
  /////////////////////////////////////////////////////////////////////////
  // Overridden MRhinoGetPoint::DynamicDraw
  public override void DynamicDraw(IntPtr hdc, MRhinoViewport vp, IOn3dPoint pt)
  {
    MRhinoDisplayPipeline dp = vp.DisplayPipeline();
    if (dp != null)
    {
      dp.PushObjectColor(0);
      dp.DrawObjects(m_list.m_objects, m_xform);
      dp.DrawObjects(m_list.m_grip_owners);
      dp.PopObjectColor();
      base.DynamicDraw(hdc, vp, pt);
    }
  }
 
  /////////////////////////////////////////////////////////////////////////
  // Returns the object list
  public MRhinoXformObjectList ObjectList()
  {
    return m_list;
  }
}

Example

To use the above RhinoGetTransform class, all you need to do is declare a new class that inherits from this class. Then, implement the CalculateTransform member function to calculate the transformation you want. For example, lets say that we want to write our own Move command. We could write a RhinoGetTransform inherited class as follows:

public class RhinoGetTranslation : RhinoGetTransform
{
  public override bool CalculateTransform(MRhinoViewport vp, IOn3dPoint point, ref OnXform xform)
  {
    bool bResult = false;
    On3dVector v = new On3dVector();
    On3dPoint pt = new On3dPoint(point);
    v = pt - m_base;
    if (!v.IsZero())
    {
      xform.Translation(v);
      bResult = xform.IsValid();
    }
    return bResult;
  }
}

Then, we could write our own version of Move as follows:

public override IRhinoCommand.result RunCommand(IRhinoCommandContext context)
{
  MRhinoGetObject go = new MRhinoGetObject();
  go.SetCommandPrompt("Select objects to move");
  go.GetObjects(1, 0);
  if (go.CommandResult() != IRhinoCommand.result.success)
    return go.CommandResult();
 
  MRhinoXformObjectList list = new MRhinoXformObjectList();
  if (list.AddObjects(go, true) < 1)
    return IRhinoCommand.result.failure;
 
  MRhinoGetPoint gp = new MRhinoGetPoint();
  gp.SetCommandPrompt("Point to move from");
  gp.GetPoint();
  if (gp.CommandResult() != IRhinoCommand.result.success)
    return gp.CommandResult();
 
  RhinoGetTranslation gt = new RhinoGetTranslation();
  gt.SetCommandPrompt("Point to move to");
  gt.AppendObjects(list);
  gt.SetBasePoint(gp.Point());
  gt.DrawLineFromPoint(gp.Point(), true);
  gt.GetXform();
  if (gt.CommandResult() != IRhinoCommand.result.success)
    return gt.CommandResult();
 
  OnXform xform = new OnXform();
  if (gt.CalculateTransform(gt.View().ActiveViewport(), gt.Point(), ref xform))
  {
    // TODO: do object transformation here.
  }
 
  return IRhinoCommand.result.success;
}
developer/sdksamples/rhinogettransform.txt ยท Last modified: 2014/01/23 (external edit)