2014-12-06 106 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