2014-12-06 164 views
1

我正在QT应用程序中使用OSGWidget。我如何获取osg viewer中拾取对象的坐标,并将其传输到对话窗口中的QT textEdit中。你能否给出建议如何从查看器中提取选定对象的osg :: Vec3d将其转换为字符串并将其显示出来?例如。我有这些场景: Scene对象坐标

当我点击添加按钮,它会打开一个对话框窗口,我有一个textEdit对象。在此editText中传输坐标。这怎么可能完成?忘了补充一点,这个多维数据集是从广告文件导入的。可能它可以帮助在任何地方。

回答

2

为了从您的场景中检索对象的坐标,您需要为您的查看器添加新的事件处理程序。我们称之为PickHandler

这里有一个基本的代码,可以帮助你开始。您需要添加“包含”并进行修改以适合您的需求。 (请注意,我没有测试过,我是通过“记忆”来写的,但是如果有任何错误,应该很容易修复)。

PickHandler.h

class PickHandler: public QObject, public osgGA::GUIEventHandler { 
    Q_OBJECT 
public: 
    PickHandler(); 
    virtual bool handle(const osgGA::GUIEventAdapter& ea, 
        osgGA::GUIActionAdapter& aa); 
    signals: 
    void query(osg::Vec3f); 
protected: 
    virtual ~PickHandler() 
    { 
    } 

    bool pick(const double x, const double y, osgViewer::Viewer* viewer); 
private: 
    bool getPickedPoint(const double x, const double y, float buffer, 
        osgViewer::Viewer* viewer, osg::Vec3f& point); 
}; 

PickHandler.cpp

PickHandler::PickHandler() : osgGA::GUIEventHandler() 
{ 
} 

bool PickHandler::handle(const osgGA::GUIEventAdapter &ea, 
         osgGA::GUIActionAdapter &aa) 
{ 
    osgViewer::View* viewer = dynamic_cast<osgViewer::Viewer*>(&aa); 

    if(!viewer) { 
     return false; 
    } 
    switch(ea.getEventType()) { 
     default: 
     break; 
     case osgGA::GUIEventAdapter::RELEASE: { 
     if(pick(ea.getXnormalized(), ea.getYnormalized(), 
       viewer)) 
     { 
      return true; 
     } 
     break; 
     } 
    } 
    return false; 
} 

bool PickHandler::pick(const double x, const double y, 
        osgViewer::Viewer* viewer) 
{ 

    if(!viewer->getSceneData()) { 
     return false; 
    } 

    osg::Vec3f point; 
    float buffer = 0.005f; 

    if(getPickedPoint(x, y, buffer, viewer, point)) { 
     emit query(point); 
    } 
    return false; 
} 

bool PickHandler::getPickedPoint(const double x, const double y, float buffer, 
           osgViewer::Viewer* viewer, 
           osg::Vec3f& point) 
{ 
    osg::ref_ptr<osgUtil::PolytopeIntersector> intersector(0); 
    try { 
     intersector = new osgUtil::PolytopeIntersector(
       osgUtil::Intersector::PROJECTION, 
       x - buffer, y - buffer, x + buffer, 
       y + buffer) 
     ; 
    } catch(const std::bad_alloc&) { 
     return false; 
    } 

    // DimZero = check only for points 
    intersector->setDimensionMask(osgUtil:: PolytopeIntersector::DimZero); 
    // 
    intersector->setIntersectionLimit(osgUtil::Intersector::LIMIT_NEAREST); 
    osgUtil::IntersectionVisitor iv(intersector); 
    viewer->getCamera()->accept(iv); 

    if(intersector->containsIntersections()) { 
     osgUtil::PolytopeIntersector::Intersection intersection = 
      *(intersector->getIntersections().begin()) 
     ; 

     const osg::Vec3f& P = intersection.intersectionPoints[ 0 ]; 

     if(P.isNaN()) { 
      return false; 
     } 

     point.set(P[ 0 ], P[ 1 ], P[ 2 ]); 
     return true; 
    } 

    return false; 
} 

我使用的是PolytopeIntersector,因为我没有任何实体模型,像塞斯纳OSG的示例数据;只有很多点和使用LineIntersector(最快)几乎是不可能的。 Polytope将构建一个与任何指定区域中的任何物体(与构建Polytope时的参数相交)。另外,您可能需要使用发送到选取功能的参数(如缓冲区大小)进行播放。我使用ea.getXNormalized()pick()osgUtil::Intersector::PROJECTION值。

如果您使用的是osgUtil::Intersector::WINDOW值,则无需对鼠标值进行归一化。如果您在视图中没有任何“奇怪”转换,那么很可能您所需的值就是PROJECTION

最后一件事,这段代码太旧了。随着更新的osg版本,也许一些将被视为已弃用。我不确定,因为我还没有更新我的选择器代码。

现在,通过这段代码,当找到了一个itersection时,它会检索到第一个并通过发射发送点值。你只需要连接这个发射到你的SLOT并接收尖锐的点坐标。

最后,为了将某些东西转换为字符串,可以使用Qt字符串函数QString::number(...)

例如:

const QString x = QString::number(point[0], 'd', 6); 

将字符串化使用定点格式与6个小数位点的x坐标。

+0

哇!感谢你的例子。我会研究它,并尝试应用到我的项目 – 2014-12-06 18:16:36

+0

好的。我想补充一点,你需要将'osg :: Viewer * viewer'改为'osg :: View * viewer',否则动态转换将不起作用。 – 2016-06-23 09:01:06

+0

@DanielR。感谢您指出!我现在就改变它。 – 2016-06-23 09:35:14