对象坐标

时间:2014-12-06 15:32:28

标签: c++ qt openscenegraph

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

当我点击添加按钮时,它会打开一个对话框窗口,其中我有一个textEdit对象。在此editText中传输coords。怎么可能这样呢?忘记添加此多维数据集是从广告文件导入的。可能它可以在任何地方提供帮助。

1 个答案:

答案 0 :(得分: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示例数据中的cessna;只有很多分数并使用LineIntersector(最快)几乎不可能获得成功。 Polytope将构建一个与您指定区域中的任何内容相交的截头体积(在构造Polytope时使用参数)。

此外,您可能需要使用发送到pick功能的参数,例如缓冲区大小。我使用ea.getXNormalized()pick()osgUtil::Intersector::PROJECTION值。

如果使用,例如osgUtil::Intersector::WINDOW值,则无需标准化鼠标值。如果您的视图中没有任何“奇怪”的转换,很可能PROJECTION值就是您所需要的。

最后,这段代码相当陈旧。对于较新的osg版本,可能会有一些版本被视为已弃用。我不确定,因为我还没有更新我的选择器代码。

现在,使用此代码,当找到itersection时,它会检索FIRST并通过emit发送点值。你只需要将这个发射器连接到你的SLOT并接收cliked point coords。

最后,要将某些内容转换为字符串,您可以使用Qt字符串函数QString::number(...)

例如:

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

将使用带有6位小数的定点格式对点的x-coord进行字符串化。