osg 拖拽器


漫游器中世界不动,观察者相机在动。再三维世界中需要对对象的平移、选择缩放操作,
注意:需要对三维物体设置一个父对象,对父节点操作很桥当
为了便于用户操作,引入Command设计模式,它属于一种对象行为模式。将一系列对象操作push到一个队列中。

包括:

  • 接收者 Receiver
  • 触发者 Invoker
  • 命令本身 Command

在osgManipulator中,可以将Dragger本身定义为触发者 Invoker,它负责用户的平移、选择缩放灯。
接收者为Selection类,它是实际待操作对象的父节点;
控制命令使用 MotionCommand表达
并使用一个 CommandManager对所有操控命令以及拖拽器与接收者进行绑定关系。
osgManipulator::MotionCommand 类

MotionCommand() 默认构造函数

bool execute() 虚函数 执行/撤销一个命令

bool unexecute()
void applyConstraint(const Constraint *) 虚函数。添加命令的约束条件
void addSelection(Selection *) 添加/删除一个命令作用的备选对象
void removeSelection(Selection *)
osg::Matrix getMotionMatrix() const 虚函数。获取命令的结果的矩阵

void setStage(const Stage s) 设置/获取设置的执行阶段类型,包括START MOVE FINISH 3种
执行命令阶段包括 鼠标按下选中 START 、拖拽 MOVE 以至于FINISH 这一过程。不同执行阶段的输出结果不一样。
Constraint类表示约束条件,用户通过自定义来实现约束功能。
一个命令的执行可以作用在多个备选对象上。

osgManipulator::CommandManager 类

CommandManager() 默认构造函数
bool connect(Dragger& dragger,Selection& selection) 虚函数,绑定拖拽器与一个备选对象
bool connect(Dragger& dragger,Constraint& constrain) 虚函数,绑定拖拽器或一个约束对象
bool disconnect(Dragger & dragger) 虚函数 取消所有与当前拖拽器有关的备选对象和约束对象
void dispath(MotionCommand &) 虚函数 分发一个命令,即执行一个命令

void addSelectionsToCommand(MotionCommand& command,Dragger& dragger) 设置一个命令的发送者和接收者

注意:一个对象不能被多个多拽器影响。可以使用 CompositeDragger实现这一功能。
当命令执行的时候,接收者Selections负责接收和实现命令效果。由于Selection节点是作为被操控的物体的父节点催你在的。

osgManipulator::Selection 类

Selection() 默认构造函数
bool receive(const MotionCommand&) 对各种命令(MotionCommand及其派生类)的接收函数

osgManipulator::Dragger类

void setCommandManager(CommandManager*)
CommandManager * getCommandManager() 设置/获取命令管理器,用于分发命令
void setParentDragger(Dragger*) 设置/获取父拖拽器。对于一个单独的拖拽器,其父拖拽器就是它自己
bool handle(const PointerInfo&,const GUIEventAdapter&,GUIActionAdapter&) 虚函数,根据用户交互事件,触发操控命令

注意:PointerInfo表示鼠标选中待操控对象上的某个点,以及当前相机的观察矩阵和投影矩阵等,都需要及时反馈到这个输入参数种,以便
实例:、
PickModelHandler

//PickModelHandler.h
#pragma once
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
class PickModelHandler :public osgGA::GUIEventHandler
{
public:
	PickModelHandler();
	~PickModelHandler();
	bool handle(const osgGA::GUIEventAdapter & ea,osgGA::GUIActionAdapter& aa,osg::Object*,osg::NodeVisitor*);
protected:
	osgManipulator::Dragger* _activeDragger;
	osgManipulator::PointerInfo* _pointer ;//拖拽器 输入的信息集合 Dragger类种的handler参数

};



PickModelHandler.cpp

#include "PickModelHandler.h"

PickModelHandler::PickModelHandler() :_activeDragger(0) {
	_pointer = new osgManipulator::PointerInfo;
}

PickModelHandler::~PickModelHandler() {}
 
bool PickModelHandler::handle(const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& aa, osg::Object*, osg::NodeVisitor*) {
	osgViewer::View * view = dynamic_cast(&aa);
	if (!view)return false;

	switch (ea.getEventType())
	{
		case osgGA::GUIEventAdapter::PUSH: {
			_pointer->reset();
			//创建线条?
			osgUtil::LineSegmentIntersector::Intersections hits;
			if (view->osgViewer::View::computeIntersections(ea.getX(), ea.getY(), hits)) {
				_pointer->setCamera(view->getCamera());
				_pointer->setMousePosition(ea.getX(), ea.getY());

				osgUtil::LineSegmentIntersector::Intersections::iterator hitr;//线段访问器
				for (hitr = hits.begin(); hitr != hits.end(); ++hitr) {
					_pointer->addIntersection(hitr->nodePath, hitr->getLocalIntersectPoint());//添加线段信息
				}
				osg::NodePath::iterator itr;
				for (itr = _pointer->_hitList.front().first.begin();
					itr != _pointer->_hitList.front().first.end();
					++itr) {
					osgManipulator::Dragger* dragger = dynamic_cast(*itr);//获取输入参数 Dragger
					if (dragger) {
						dragger->handle((*_pointer), ea, aa);
						_activeDragger = dragger;
						break;
					}

				} 
			}
			break;
		}
		case osgGA::GUIEventAdapter::DRAG:
		case osgGA::GUIEventAdapter::RELEASE: {
			if (_activeDragger) {
				_pointer->_hitIter = _pointer->_hitList.begin();
				_pointer->setCamera(view->getCamera());
				_pointer->setMousePosition(ea.getX(), ea.getY());
				_activeDragger->handle((*_pointer),ea,aa);
			}
			if (ea.getEventType() == osgGA::GUIEventAdapter::RELEASE) {
				_activeDragger = NULL;
				_pointer->reset();
			}
			break;
		}
		default:
			break;
	}
	return true;
}

main

/**
* 拖拽器示例 实现使用鼠标拖动物体上X Y轴箭头
* 继承 osgGA::GUIEventHandler 的 handler 方法
* 1 使用 view->computeIntersections 判断鼠标与场景中的对象交点
* 2 将交点位置传染 PointerInfo对象,作为拖拽器的对象参数
* 3 实现 handler 的 PUSH 鼠标按下 REALSE 鼠标释放事件
* 在main方法中 
* 1 将对象放入 Selection 之下
* 2 定义 XYZ的拖拽器 TranslateAxisDragger (三个方向的箭头,可以相应事件的交点)
* 3 定义命令管理器 CommandManager 实现拖拽器和Selection关联
*/
int main(int argc, char** argv) {
	osg::ArgumentParser arguments(&argc,argv);
	osg::Node* model = osgDB::readNodeFiles(arguments);
	if (!model) {
		model = osgDB::readNodeFile("cow.osg");
	}
	//定义接收者
	osg::ref_ptr selection = new osgManipulator::Selection;
	//添加备用节点
	selection->addChild(model);
	//缩放比例
	float scale = model->getBound().radius() * 1.6;
	osg::ref_ptr dragger = new osgManipulator::TranslateAxisDragger;
	dragger->setupDefaultGeometry();
	dragger->setMatrix(osg::Matrix::scale(scale, scale, scale) *
		osg::Matrix::translate(model->getBound().center()));

	osg::ref_ptr root = new osg::Group;
	root->addChild(dragger.get());
	root->addChild(selection.get());
	root->addChild(osgDB::readNodeFile("axes.osg"));
	
	osg::ref_ptr manager = new osgManipulator::CommandManager;
	manager->connect(*dragger,*selection);

	osg::ref_ptr viewer = new osgViewer::Viewer();
	viewer->addEventHandler(new PickModelHandler);
	viewer->setSceneData(root.get());
	return viewer->run();

}

osg