Picking Objects without CRhinoGetObject
Summary: Demonstrates an alternate technique to picking objects without using CRhinoGetObject.
Question
If I already have a 3-D point, is there way to pick all of the objects that are underneath it?
Answer
You can use CRhinoPickContext to build your own object picker. For more details on CRhinoPickContext, see rhinoSdkPick.h. With the CRhinoPickContext class, you can define the rules for picking. For example, you can specify a picking style (point, window, crossing). You can also specify a filter so you only pick the types of objects you want. The most important part is to define a pick chord, which starts on near clipping plane and ends on far clipping plane.
After you have created an CRhinoPickContext object and filled out is parameters, you then call CRhinoDoc::PickObjects. This function goes through list of eligible objects and intersects them with the pick frustum. If they hit the frustum in an acceptable manner, the object is added to a pick list passed in by the caller.
Here is a simple example of a function that might work for you:
C++
static int MyObjectPicker( CRhinoDoc& doc, CRhinoView* view, POINT point, CRhinoObjRefArray& pick_list ) { if( 0 == view ) return 0; CRhinoPickContext pick_context; pick_context.m_view = view; pick_context.m_pick_style = CRhinoPickContext::point_pick; CRhinoViewport& active_vp = view->ActiveViewport(); switch( active_vp.DisplayMode() ) { case ON::shaded_display: case ON::renderpreview_display: pick_context.m_pick_mode = CRhinoPickContext::shaded_pick; break; } int pick_count = 0; if( active_vp.GetPickXform(point.x, point.y, pick_context.m_pick_region.m_xform) ) { // adds objects to pick_list - does not change any status active_vp.VP().GetFrustumLine( point.x, point.y, pick_context.m_pick_line ); pick_context.UpdateClippingPlanes(); pick_count = doc.PickObjects( pick_context, pick_list ); } return pick_count; }
C#
public int MyObjectPicker(MRhinoDoc doc, MRhinoView view, System.Drawing.Point point, ref MRhinoObjRefArray pick_list) { if (view == null) return 0; MRhinoPickContext pick_context = new MRhinoPickContext(); pick_context.View = view; pick_context.Style = IRhinoPickContext.pick_style.point_pick; MRhinoViewport active_vp = view.ActiveViewport(); switch( active_vp.DisplayMode() ) { case IOn.display_mode.shaded_display: case IOn.display_mode.renderpreview_display: pick_context.Mode = IRhinoPickContext.pick_mode.shaded_pick; break; } int pick_count = 0; OnXform xform = new OnXform(); RMA.OpenNURBS.ValueTypes.Line line = new RMA.OpenNURBS.ValueTypes.Line(); if (active_vp.GetPickXform(point.X, point.Y, ref xform)) { pick_context.PickRegion.m_xform = xform; active_vp.VP().GetFrustumLine( point.X, point.Y, ref line ); pick_context.PickChord = line; pick_context.UpdateClippingPlanes(); pick_count = doc.PickObjects( pick_context, ref pick_list ); } return pick_count; }
And, here is a sample of its usage:
C++
CRhinoCommand::result CCommandTest::RunCommand( const CRhinoCommandContext& context ) { CRhinoGetPoint gp; gp.GetPoint(); if( gp.CommandResult() != CRhinoCommand::success ) return gp.CommandResult(); CRhinoView* view = gp.View(); if( 0 == view ) return failure; ON_Xform w2s; view->ActiveViewport().VP().GetXform( ON::world_cs, ON::screen_cs, w2s ); ON_3dPoint pt3d = gp.Point(); pt3d.Transform( w2s ); POINT pt2d; pt2d.x = (int)pt3d.x; pt2d.y = (int)pt3d.y; CRhinoObjRefArray pick_list; int pick_count = MyObjectPicker( context.m_doc, view, pt2d, pick_list ); for( int i = 0; i < pick_count; i++ ) { const CRhinoObject* obj = pick_list[i].Object(); if( obj ) obj->Select( true, true, true ); } context.m_doc.Redraw(); return CRhinoCommand::success; }
C#
public override IRhinoCommand.result RunCommand(IRhinoCommandContext context) { MRhinoGetPoint gp = new MRhinoGetPoint(); gp.GetPoint(); if (gp.CommandResult() != IRhinoCommand.result.success) return gp.CommandResult(); MRhinoView view = gp.View(); if (view == null) return IRhinoCommand.result.failure; OnXform w2s = new OnXform(); view.ActiveViewport().VP().GetXform(IOn.coordinate_system.world_cs, IOn.coordinate_system.screen_cs, ref w2s); On3dPoint pt3d = gp.Point(); pt3d.Transform(w2s); System.Drawing.Point pt2d = new System.Drawing.Point(); pt2d.X = (int)pt3d.x; pt2d.Y = (int)pt3d.y; MRhinoObjRefArray pick_list = new MRhinoObjRefArray(); int pick_count = MyObjectPicker(context.m_doc, view, pt2d, ref pick_list); for (int i = 0; i < pick_count; i++) { IRhinoObject obj = pick_list[i].Object(); if (obj != null) obj.Select(true, true, true); } context.m_doc.Redraw(); return IRhinoCommand.result.success; }