When using Rhino, you have probably noticed that many of the object creation commands, such as Line and Circle, and transformation commands, such as Move and Copy, dynamically draw objects as they are being created or transformed. This operation is performed by deriving a new class from Rhino's point pick class, CRhinoGetPoint, and overriding two member functions: OnMouseMove() and DynamicDraw().
OnMouseMove() is called every time the mouse moves. This is a great place to perform calculations, such as transformations.
DynamicDraw() is called as the mouse moves, as well. Every time the mouse moves, DynamicDraw() will be called once per viewport. Note, Rhino calls DynamicDraw() happen the call to OnMouseMove().
The following example demonstrates how to derive a new class from CRhinoGetPoint and override OnMouseMove() and DynamicDraw() to dynamically draw geometry. In this example, we are going to dynamically draw a circle while the user is specifying its radius.
First, here is the CRhinoGetPoint derived class declaration and definition:
class CGetCircleRadiusPoint : public CRhinoGetPoint
{
public:
CGetCircleRadiusPoint();
void SetCenterPoint( const ON_3dPoint center_point );
bool CalculateCircle( CRhinoViewport& vp, const ON_3dPoint& pt );
void OnMouseMove( CRhinoViewport& vp,
UINT flags,
const ON_3dPoint& pt,
const CPoint* pt2d );
void DynamicDraw( HDC hDC, CRhinoViewport& vp, const ON_3dPoint& pt );
const ON_Circle& Circle() const;
private:
ON_Circle m_circle;
ON_3dPoint m_center_point;
bool m_draw_circle;
};
CGetCircleRadiusPoint::CGetCircleRadiusPoint()
{
m_draw_circle = false;
}
void CGetCircleRadiusPoint::SetCenterPoint( const ON_3dPoint center_point )
{
m_center_point = center_point;
}
bool CGetCircleRadiusPoint::CalculateCircle( CRhinoViewport& vp, const ON_3dPoint& pt )
{
double radius = m_center_point.DistanceTo( pt );
if( radius < ON_SQRT_EPSILON )
return false;
ON_Plane plane = vp.ConstructionPlane().m_plane;
plane.SetOrigin( m_center_point );
m_circle.Create( plane, radius );
return m_circle.IsValid() ? true : false;
}
void CGetCircleRadiusPoint::OnMouseMove( CRhinoViewport& vp,
UINT flags,
const ON_3dPoint& pt,
const CPoint* pt2d )
{
m_draw_circle = CalculateCircle( vp, pt );
CRhinoGetPoint::OnMouseMove( vp, flags, pt, pt2d );
}
void CGetCircleRadiusPoint::DynamicDraw( HDC hDC,
CRhinoViewport& vp,
const ON_3dPoint& pt )
{
if( m_draw_circle )
{
ON_Color color = RhinoApp().AppSettings().TrackingColor();
ON_Color saved_color = vp.SetDrawColor( color );
vp.DrawCircle( m_circle );
vp.SetDrawColor( saved_color );
}
CRhinoGetPoint::DynamicDraw( hDC, vp, pt );
}
const ON_Circle& CGetCircleRadiusPoint::Circle() const
{
return m_circle;
}
Finally, here is our CRhinoGetPoint derived class in action:
CRhinoCommand::result CCommandTest::RunCommand(const CRhinoCommandContext& context)
{
CRhinoGetPoint gp;
gp.SetCommandPrompt( L"Center point" );
gp.ConstrainToConstructionPlane( FALSE );
gp.GetPoint();
if( gp.CommandResult() != CRhinoCommand::success )
return gp.CommandResult();
ON_3dPoint center_point = gp.Point();
CGetCircleRadiusPoint gc;
gc.SetCommandPrompt( L"Radius" );
gc.ConstrainToConstructionPlane( FALSE );
gc.SetBasePoint( center_point );
gc.DrawLineFromPoint( center_point, TRUE );
gc.SetCenterPoint( center_point );
gc.GetPoint();
if( gc.CommandResult() != CRhinoCommand::success )
return gc.CommandResult();
if( gc.CalculateCircle( gc.View()->Viewport(), gc.Point() ))
{
ON_Circle circle = gc.Circle();
context.m_doc.AddCurveObject( circle );
context.m_doc.Redraw();
}
return CRhinoCommand::success;
}
First, here is the MRhinoGetPoint derived class declaration and definition:
Public Class CGetCircleRadiusPoint
Inherits MRhinoGetPoint
Private m_circle As OnCircle
Private m_center_point As On3dPoint
Private m_draw_circle As Boolean
Public Sub New()
m_circle = New OnCircle()
m_center_point = New On3dPoint()
m_draw_circle = False
End Sub
Public Sub SetCenterPoint(ByVal center_point As IOn3dPoint)
m_center_point = New On3dPoint(center_point)
End Sub
Public Function CalculateCircle(ByVal vp As MRhinoViewport, ByVal pt As IOn3dPoint) _
As Boolean
Dim radius As Double = m_center_point.DistanceTo(pt)
If (radius < OnUtil.On_SQRT_EPSILON) Then Return False
Dim plane As New OnPlane(vp.ConstructionPlane().m_plane)
plane.SetOrigin(m_center_point)
m_circle.Create(plane, radius)
Return m_circle.IsValid()
End Function
Public Overrides Sub OnMouseMove(ByVal vp As MRhinoViewport, _
ByVal nFlags As UInteger, _
ByVal point As IOn3dPoint, _
ByVal view_wnd_point As System.Drawing.Point)
m_draw_circle = CalculateCircle(vp, point)
MyBase.OnMouseMove(vp, nFlags, point, view_wnd_point)
End Sub
Public Overrides Sub DynamicDraw(ByVal hdc As IntPtr, _
ByVal viewport As MRhinoViewport, _
ByVal pt As IOn3dPoint)
If (m_draw_circle) Then
Dim color As OnColor = RhUtil.RhinoApp().AppSettings().TrackingColor()
Dim saved_color As OnColor = viewport.SetDrawColor(CType(color, UInteger))
viewport.DrawCircle(m_circle)
viewport.SetDrawColor(CType(saved_color, UInteger))
End If
MyBase.DynamicDraw(hdc, viewport, pt)
End Sub
Public Function Circle() As IOnCircle
Return m_circle
End Function
End Class
Finally, here is our MRhinoGetPoint derived class in action:
Public Overrides Function RunCommand(ByVal context As IRhinoCommandContext) _
As IRhinoCommand.result
Dim gp As New MRhinoGetPoint()
gp.SetCommandPrompt("Center point")
gp.ConstrainToConstructionPlane(False)
gp.GetPoint()
If (gp.CommandResult() <> IRhinoCommand.result.success) Then
Return gp.CommandResult()
End If
Dim center_point As On3dPoint = gp.Point()
Dim gc As New CGetCircleRadiusPoint()
gc.SetCommandPrompt("Radius")
gc.ConstrainToConstructionPlane(False)
gc.SetBasePoint(center_point)
gc.DrawLineFromPoint(center_point, True)
gc.SetCenterPoint(center_point)
gc.GetPoint()
If (gc.CommandResult() <> IRhinoCommand.result.success) Then
Return gc.CommandResult()
End If
If (gc.CalculateCircle(gc.View().ActiveViewport(), gc.Point())) Then
Dim circle As IOnCircle = gc.Circle()
context.m_doc.AddCurveObject(circle)
context.m_doc.Redraw()
End If
Return IRhinoCommand.result.success
End Function
First, here is the MRhinoGetPoint derived class declaration and definition:
public class CGetCircleRadiusPoint : MRhinoGetPoint
{
private OnCircle m_circle;
private On3dPoint m_center_point;
private bool m_draw_circle;
public CGetCircleRadiusPoint()
{
m_circle = new OnCircle();
m_center_point = new On3dPoint();
m_draw_circle = false;
}
public void SetCenterPoint(IOn3dPoint center_point)
{
m_center_point = new On3dPoint(center_point);
}
public bool CalculateCircle(MRhinoViewport vp, IOn3dPoint pt)
{
double radius = m_center_point.DistanceTo(pt);
if (radius < OnUtil.On_SQRT_EPSILON)
return false;
OnPlane plane = new OnPlane(vp.ConstructionPlane().m_plane);
plane.SetOrigin(m_center_point);
m_circle.Create(plane, radius);
return m_circle.IsValid();
}
public override void OnMouseMove(MRhinoViewport vp,
uint nFlags,
IOn3dPoint point,
System.Drawing.Point view_wnd_point)
{
m_draw_circle = CalculateCircle(vp, point);
base.OnMouseMove(vp, nFlags, point, view_wnd_point);
}
public override void DynamicDraw(System.IntPtr hdc,
MRhinoViewport viewport,
IOn3dPoint pt)
{
if (m_draw_circle)
{
OnColor color = RhUtil.RhinoApp().AppSettings().TrackingColor();
OnColor saved_color = viewport.SetDrawColor(color);
viewport.DrawCircle(m_circle);
viewport.SetDrawColor(saved_color);
}
base.DynamicDraw(hdc, viewport, pt);
}
public IOnCircle Circle()
{
return m_circle;
}
}
Finally, here is our MRhinoGetPoint derived class in action:
public override IRhinoCommand.result RunCommand(IRhinoCommandContext context)
{
MRhinoGetPoint gp = new MRhinoGetPoint();
gp.SetCommandPrompt("Center point");
gp.ConstrainToConstructionPlane(false);
gp.GetPoint();
if(gp.CommandResult() != IRhinoCommand.result.success)
return gp.CommandResult();
On3dPoint center_point = gp.Point();
CGetCircleRadiusPoint gc = new CGetCircleRadiusPoint();
gc.SetCommandPrompt("Radius");
gc.ConstrainToConstructionPlane(false);
gc.SetBasePoint(center_point);
gc.DrawLineFromPoint(center_point, true);
gc.SetCenterPoint(center_point);
gc.GetPoint();
if(gc.CommandResult() != IRhinoCommand.result.success)
return gc.CommandResult();
if(gc.CalculateCircle(gc.View().ActiveViewport(), gc.Point()))
{
IOnCircle circle = gc.Circle();
context.m_doc.AddCurveObject(circle);
context.m_doc.Redraw();
}
return IRhinoCommand.result.success;
}