How To: Dynamically Draw Geometry when Picking Points
C++, .NET
Summary: Demonstrates how to derive a new class from CRhinoGetPoint to dynamically draw geometry during a point picking operation.
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.
C++
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; }
VB.NET
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
C#
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; }