关闭

OSG获取鼠标点选事件的位置

3761人阅读 评论(7) 收藏 举报
分类:

OSG点选操作的思路是从osgGA::GUIEventHandler继承,并重新实现虚函数virtual bool handle(const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& aa);。获取到点选信息后,此处我们不进行处理,而是单一的传出去,由外部需要此点选信息的地方进行处理。对于传出信息,我选择了Qt的信号槽操作,因而,在继承osgGA::GUIEventHandler的同时,我们还需要继承QObject。
代码如下:pickhandle.h

class PickHandle : public QObject, public osgGA::GUIEventHandler
{
    Q_OBJECT
public:
    PickHandle(const osgEarth::SpatialReference* srs);
    ~PickHandle();

protected:
    virtual bool handle(const osgGA::GUIEventAdapter& ea,
        osgGA::GUIActionAdapter& aa);

private:
    osg::Vec3d getPos(const osgGA::GUIEventAdapter& ea,
        osgGA::GUIActionAdapter& aa, osg::Vec3d& pos);

signals:
    // 经纬度信息
    void signalPicked(osg::Vec3d pos);
    void signalMoving(osg::Vec3d pos);

    // 世界坐标信息
    void signalPickedXYZ(osg::Vec3d pos);
    void signalMovingXYZ(osg::Vec3d pos);

    void signalRightPicked();

private:
    osg::Vec3d m_vecPostion;
    const osg::EllipsoidModel* m_pEllipsoid;
};

此处提供了世界坐标和经纬度坐标两套信息供外部选择。
实现代码:pickhandle.cpp

PickHandle::PickHandle(const osgEarth::SpatialReference* srs)
{
    m_pEllipsoid = srs->getGeodeticSRS()->getEllipsoid();
}

PickHandle::~PickHandle()
{

}

bool PickHandle::handle(const osgGA::GUIEventAdapter& ea,
    osgGA::GUIActionAdapter& aa)
{
    // 存储经纬度信息
    osg::Vec3d vecPos;
    switch (ea.getEventType())
    {
        // 点击事件
        case osgGA::GUIEventAdapter::PUSH:
        {
            osg::Vec3d pos = getPos(ea, aa, vecPos);
            // 鼠标左键
            if (ea.getButton() == osgGA::GUIEventAdapter::LEFT_MOUSE_BUTTON)
            {
                m_vecPostion = pos;
            }
            break;
        }

        // 鼠标移动事件
        case osgGA::GUIEventAdapter::MOVE:
        {
            osg::Vec3d pos = getPos(ea, aa, vecPos);
            emit signalMoving(vecPos);
            emit signalMovingXYZ(pos);
            break;
        }

        // 鼠标释放事件
        case osgGA::GUIEventAdapter::RELEASE:
        {
            osg::Vec3d pos = getPos(ea, aa, vecPos);
            // 鼠标左键
            if (ea.getButton() == osgGA::GUIEventAdapter::LEFT_MOUSE_BUTTON)
            {
                // 如果释放的点和点击的点同一,则发送单击事件发生的位置
                if (m_vecPostion == pos && m_vecPostion != osg::Vec3d(0, 0, 0))
                {
                    emit signalPicked(vecPos);
                    emit signalPickedXYZ(pos);
                }
            }
            else if (ea.getButton() == osgGA::GUIEventAdapter::RIGHT_MOUSE_BUTTON)
            {
                emit signalRightPicked();
            }
            break;
        }
    }

    return false;
}

osg::Vec3d PickHandle::getPos(const osgGA::GUIEventAdapter& ea,
    osgGA::GUIActionAdapter& aa, osg::Vec3d& pos)
{
    pos = osg::Vec3d(0, 0, 0);
    osgViewer::Viewer* pViewer = dynamic_cast<osgViewer::Viewer*>(&aa);
    if (pViewer == NULL)
    {
        return osg::Vec3d(0, 0, 0);
    }
    // 获取当前点
    osgUtil::LineSegmentIntersector::Intersections intersection;
    double x = ea.getX();
    double y = ea.getY();
    pViewer->computeIntersections(ea.getX(), ea.getY(), intersection);
    osgUtil::LineSegmentIntersector::Intersections::iterator iter
        = intersection.begin();
    if (iter != intersection.end())
    {
        m_pEllipsoid->convertXYZToLatLongHeight(
            iter->getWorldIntersectPoint().x(), iter->getWorldIntersectPoint().y(), iter->getWorldIntersectPoint().z(),
            pos.y(), pos.x(), pos.z());
        pos.x() = osg::RadiansToDegrees(pos.x());
        pos.y() = osg::RadiansToDegrees(pos.y());
        return iter->getWorldIntersectPoint();
    }
    return osg::Vec3d(0, 0, 0);
}

我在处理PUSH和RELEASE事件时,只有两者的点完全一致,我才认为发生了点选操作,否则则忽略此事件。

1
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:114622次
    • 积分:1503
    • 等级:
    • 排名:千里之外
    • 原创:44篇
    • 转载:0篇
    • 译文:0篇
    • 评论:101条
    文章分类
    最新评论