Operators

Most applications require some way for the user to interact with the scene. Orbiting, zooming, and panning are all operations which commonly respond to user input. You can choose to handle this user input yourself with whatever GUI event system you employ, but HNP provides a number of ready-made operators for this purpose. An operator is simply an object that processes user input in a specific way.

The MFC Sandbox has these basic operators built in and ready to use. After loading a model, make sure you are on the “Operators” tab and you will see icons to activate the Orbit, Pan, Zoom, and Fly operators. Once active, each operator is used with a mouse click and drag in the main window.

In order for an operator to affect the scene, it must be instantiated and associated with an active HPS::View. It is the developer’s responsibility to make the connection between the GUI event system and the HNP event system. You can see an example of this here:

void CHPSView::OnLButtonDown(UINT nFlags, CPoint point)
{
	SetCapture();
	_canvas.GetWindowKey().GetEventDispatcher().InjectEvent(
		BuildMouseEvent(HPS::MouseEvent::Action::ButtonDown, HPS::MouseButtons::ButtonLeft(), point, nFlags, 1));

	CView::OnLButtonDown(nFlags, point);
}

In this code snippet, which handles a left button mouse click, a number of things are happening:

  1. We get a reference to the HPS::EventDispatcher associated with the Canvas.

  2. We build a HPS::MouseEvent which represents the click location using parameters sent by the GUI. The BuildMouseEvent function does some math to translate the click location between HNP’s internal coordinate systems.

  3. The HPS::MouseEvent is injected into HNP’s event system.

  4. The active operator will eventually receive the event and process it, if possible.

The sandbox sets up a number of operators by default which correspond to the common operations previously mentioned. You can see the following code in CHPSView.cpp:

void CHPSView::SetupDefaultOperators()
{
	// Orbit is on top and will be replaced when the operator is changed
	GetCanvas().GetFrontView().GetOperatorControl()
		.Push(new HPS::MouseWheelOperator(), Operator::Priority::Low)
		.Push(new HPS::ZoomOperator(MouseButtons::ButtonMiddle()))
		.Push(new HPS::PanOperator(MouseButtons::ButtonRight()))
		.Push(new HPS::OrbitOperator(MouseButtons::ButtonLeft()));
}

Notice we assign a mouse button to each operator which causes the operator to respond when pressed. In this case, if the user clicks and drags the left mouse button, the camera will orbit the scene. Clicking and dragging the right mouse button pans, and dragging the middle mouse button will zoom the model. Additionally, a fourth operator, HPS::MouseWheelOperator will zoom when the mouse wheel is scrolled, and is simply provided as an alternate method of zooming.

Also note that the operators are pushed onto a stack using HPS::OperatorControl::Push. It is important to understand that input events will be sent to the top operator on the stack. If that operator is able to handle the input, the event may be consumed. If it is not able to handle the input, it will pass the event to the next operator on the stack.

When you are finished with an operator, it can be detached from the View by calling HPS::Operator::DetachView().

Programmatic zoom

Normally, the camera is manipulated using an operator, but sometimes it is desirable to manipulate it programmatically. The “Home” button in the sandbox ribbon menu will reset the model to the default zoom and position, and apply a smooth transition while doing so:

void CHPSView::OnOperatorsHome()
{
	CHPSDoc * doc = GetCHPSDoc();
	HPS::CADModel cadModel = doc->GetCADModel();
	try
	{
		if (!cadModel.Empty())
			AttachViewWithSmoothTransition(cadModel.ActivateDefaultCapture().FitWorld());
		else
			_canvas.GetFrontView().SmoothTransition(doc->GetDefaultCamera());
	}
	catch(HPS::InvalidSpecificationException const &)
	{
		// SmoothTransition() can throw if there is no model attached
	}
}

This piece of code will take one of two paths, depending on if we’re viewing a CAD model or not. The main difference has to do with “default captures”. A default capture is a collection of settings that include visibility, materials, transformations, and camera. CAD models have default captures. Non-CAD models will have a default camera but no other associated settings.

The other piece of the “Home” button logic entails applying a smooth camera transition between the current camera orientation and the default camera orientation. The HPS::View::SmoothTransition function takes care of the math associated with the camera transition. AttachViewWithSmoothTransition is a helper function specific to the sandbox which transitions the camera and also activates the default capture.

If you dive into these camera reset functions, you’ll see how the existing view is replaced with a new layout and view combination. Your application could use this same logic, or reset the camera within the same view, if necessary.

Zoom Fit

The “Zoom Fit” button resets the camera zoom, but not the orientation. It does this by computing a bounding box for the model and the zooming to that bounding box, with a comfortable margin around the edges. Looking at the code, you’ll see it takes a HPS::KeyPath as a parameter. This object is a series of segment keys from the root of the scene graph to a specific segment. In this case, _zoomToKeyPath is a preconfigured path to the model segment, which enables the sandbox to zoom to a bounding box that encompasses the entire model. But by building a particular HPS::KeyPath, you can use this logic to zoom to any piece of the model.

void CHPSView::OnOperatorsZoomFit()
{
	HPS::View frontView = GetCanvas().GetFrontView();
	HPS::CameraKit zoomFitCamera;
	if (!_zoomToKeyPath.Empty())
	{
		HPS::BoundingKit bounding;
		_zoomToKeyPath.ShowNetBounding(true, bounding);
		frontView.ComputeFitWorldCamera(bounding, zoomFitCamera);
	}
	else
		frontView.ComputeFitWorldCamera(zoomFitCamera);
	frontView.SmoothTransition(zoomFitCamera);
}

For more information on the use of HPS::KeyPath, please see this section in our Programming Guide.

This concludes our overview of the operators available in the sandbox. A list of all operators is available here. Custom operators may also be created.