Summary: Demonstrates how to dynamically draw text strings using the Rhino SDK.
On occasion, it is useful to dynamically display some text while in the middle of a point picking operation. Rhino's VariableFilletSrf command is a good example of a command that does this.
In order to add this capability to an SDK command, you will need to:
The following example code demonstrates how to derive a new class from CRhinoGetPoint, override the CRhinoGetPoint::DynamicDraw member, and draw text dynamically.
class CDrawStringGetPoint : public CRhinoGetPoint { public: CDrawStringGetPoint() {} void DynamicDraw( HDC hdc, CRhinoViewport& vp, const ON_3dPoint& pt ); }; void CDrawStringGetPoint::DynamicDraw( HDC hdc, CRhinoViewport& vp, const ON_3dPoint& pt ) { // Format active point as a string ON_wString str; RhinoFormatPoint( pt, str ); // Build world-to-screen coordinate transformation ON_Xform w2s; vp.VP().GetXform( ON::world_cs, ON::screen_cs, w2s ); // Transform point from world to screen coordinates ON_3dPoint screenpoint = w2s * pt; // Offset point so text does not overlap cursor screenpoint.x += 5.0; screenpoint.y += -5.0; // Draw string using the system font vp.DrawString( str, str.Length(), screenpoint, false, 0, 12, L"System" ); // Allow base class to draw CRhinoGetPoint::DynamicDraw( hdc, vp, pt ); }
public class CDrawStringGetPoint : MRhinoGetPoint { public override void DynamicDraw(System.IntPtr hdc, MRhinoViewport viewport, IOn3dPoint pt) { MRhinoDisplayPipeline dp = viewport.DisplayPipeline(); if( dp == null ) return; // get screen point On2dPoint screen_pt = dp.Engine().WorldToScreenPoint(pt); int x = OnUtil.ON_Round(screen_pt.x); int y = OnUtil.ON_Round(screen_pt.y); // offset point so text does not overlap cursor screen_pt.x += 5.0; screen_pt.y -= 5.0; string msg = string.Format("screen {0}, {1}", x, y); dp.DrawString(msg, viewport.DrawColor(), screen_pt); // Allow base class to draw base.DynamicDraw(hdc, viewport, pt); } }
Inherits MRhinoGetPoint Public Overrides Sub DynamicDraw(ByVal hdc As System.IntPtr, _ ByVal viewport As RMA.Rhino.MRhinoViewport, _ ByVal pt As RMA.OpenNURBS.IOn3dPoint) Dim dp As MRhinoDisplayPipeline = viewport.DisplayPipeline() If (dp Is Nothing) Then Exit Sub ' get screen point Dim screen_pt As On2dPoint = dp.Engine().WorldToScreenPoint(pt) Dim x As Integer = OnUtil.ON_Round(screen_pt.x) Dim y As Integer = OnUtil.ON_Round(screen_pt.y) ' offset point so text does not overlap cursor screen_pt.x += 5.0 screen_pt.y -= 5.0 Dim msg As String = String.Format("screen {0}, {1}", x, y) dp.DrawString(msg, viewport.DrawColor(), screen_pt) ' Allow base class to draw MyBase.DynamicDraw(hdc, viewport, pt) End Sub
End Class
You can use the above class as you would a CRhinoGetPoint object. Just create a new CDrawStringGetPoint object, initialize the class by calling base class members, and call it's GetPoint member. For example:
CRhinoCommand::result CCommandTest::RunCommand( const CRhinoCommandContext& context ) { CDrawStringGetPoint gp; gp.SetCommandPrompt( L"Pick test point" ); gp.GetPoint(); if( gp.CommandResult() != success ) return gp.CommandResult(); // TODO... return success; }
public override IRhinoCommand.result RunCommand(IRhinoCommandContext context) { CDrawStringGetPoint gp = new CDrawStringGetPoint(); gp.SetCommandPrompt( "Pick test point" ); gp.GetPoint(); if( gp.CommandResult() != IRhinoCommand.result.success ) return gp.CommandResult(); return IRhinoCommand.result.success; }
Public Overrides Function RunCommand(ByVal context As RMA.Rhino.IRhinoCommandContext) _ As RMA.Rhino.IRhinoCommand.result Dim gp As New CDrawStringGetPoint() gp.SetCommandPrompt("Pick test point") gp.GetPoint() If (gp.CommandResult() <> IRhinoCommand.result.success) Then Return gp.CommandResult() End If Return IRhinoCommand.result.success End Function