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();
}