This step reviews how to select/highlight, and manipulate 3D objects.
HOOPS/MVO contains several operators that provide support for manipulating 3D geometry. They include HOpObjectRotate and HOpObjectTranslate, which rotate and translate objects in the selection list. Before hooking up and expermenting with these operators, we first need to review some of their limitations:
So, before we can rotate or translate anything, we need to first select on an object, it needs to be of type 'segment', and there can only be 1 object in the list. However, as reviewed in the first '2D' tutorial, the default selection mode for the HOpSelect<selection_type> operators is such that they will select on individual geometry entities (not segments). Therefore, we first need to customize the selection support in our 'Spheres' application to provide 'segment-level' selection.
Similar to the 2D Tutorial, we'll abstract our Spheres application's selection functionality to provide 2 levels of selection: 'entity' and 'segment'. The code, while similar to the 2D tutorial, is a bit different since our Spheres application doesn't have the concept of selecting on 'layers'.
The HOOPS/MVO HSelectionSet class already defines an enumerated type called HSelectLevel which we can utilize. We'll extend the existing HSpheresSelectionSet class to add a new member called m_SelectLevel along with methods to Get/Set the selection level.
(Contents of spheres/HSpheresSelectionSet.h)
class HSpheresSelectionSet : public HSelectionSet { private: HSelectLevel m_SelectLevel; public: HSpheresSelectionSet(HBaseView* view); ~HSpheresSelectionSet(); virtual void Select(HC_KEY key, int num_include_keys, HC_KEY * include_keys, bool emit_message = false); virtual void DeSelect(HC_KEY key, int num_include_keys, HC_KEY * include_keys, bool emit_message = false); virtual void DeSelect(HC_KEY key, bool emit_message = false); virtual void SelectFromMessage(HC_KEY key, int num_include_keys, HC_KEY * include_keys, bool emit_message = false); virtual void DeSelectFromMessage(HC_KEY key, int num_include_keys, HC_KEY * include_keys, bool emit_message = false); void SetSelectLevel(HSelectLevel level) { m_SelectLevel = level; } const HSelectLevel GetSelectLevel() { return (m_SelectLevel);} };
First, we set the starting segment level to 'Segment':
HSpheresSelectionSet::HSpheresSelectionSet(HBaseView* view) : HSelectionSet(view) { m_SelectLevel = Segment; }
Next, we overload the HSpheresSelectionSet::Select and HSoccerSelectionSet::DeSelect, and HSoccerSelectionSet::IsSelected methods to first check whether we are in 'segment' selection mode. We check for this because perhaps our application will have a regular 'entity' selection mode to allow the user to select on individual pieces of geometry, in which case we don't want to filter for 'segment'.
If we are in segment selection mode, we check if the key is of type 'segment'. If it isn't, we get its owner. The Select method code is as follows:
void HSpheresSelectionSet::Select(HC_KEY key, int num_include_keys, HC_KEY * include_keys, bool emit_message) { char keyType[MVO_BUFFER_SIZE]; // if we are in 'Segment' selection mode, do some checking if (m_SelectLevel == Segment) { // Get the key type HC_Show_Key_Type(key, keyType); // if they key isn't to a segment (which means it's to an entity) // then we get its parent if (!streq("segment", keyType)) key = HC_KShow_Owner_By_Key(key); } HSelectionSet::Select(key, num_include_keys, include_keys, emit_message); }
The DeSelect methods will contain similar code as above.
Now that the application can select/deselect segments, we can manipulate them using the HOpObject<manipulation_type> operators. Let's hook up the rotate operator by adding a new GUI button that is mapped to the following method:
void CSpheresView::OnRotate() { LocalSetOperator(new HOpObjectRotate(m_pHView)); }
Test out the rotate operator by first selecting an object (remember that the rotate operator will only work if a single entity is selected).