使用OSG碰撞檢測功能檢測兩點通視

在三維場景中有時需要對兩點求其是否可見,即兩點之間有沒有障礙物的遮擋。在OSG中則可使用碰撞檢測完成此功能。
核心的碰撞檢測代碼爲:

    // 創建需要進行檢測的兩點之間的線段
    osg::ref_ptr<osg::LineSegment> line = new osg::LineSegment(point1,point2);
    // 創建一個IV
    osgUtil::IntersectVisitor iv;
    // 把線段添加到IV中
    iv.addLineSegment(line);
    node->accept(iv);
    // 最後可以對iv.hits()的返回值進行判斷
    if (iv.hits())
    {
        // 兩點間有障礙
    }
    else
    {
    // 兩點間無障礙
    }
    ```
    完整的兩點通視代碼爲:lineanalysis.h
    ```c++
class LineAnalysis : public HandleAdapter
{
public:
    LineAnalysis(GraphicsView* view);
    ~LineAnalysis();

protected:
    virtual void slotPicked(osg::Vec3d pos);
    virtual void slotMoveing(osg::Vec3d pos);
    virtual void slotRightHandle();

private:
    void analysis(osg::Vec3d pos);
    osg::Vec3d getWorldCoord(osg::Vec3d pos);

private:
    osgEarth::Annotation::FeatureNode* m_pLine;
    osg::Vec3d m_firstPoint;
    osgEarth::Annotation::PlaceNode* m_pPlaceNode;
    osgEarth::Symbology::Style m_lineStyle;
    osgEarth::Symbology::Style m_textStyle;
};
實現代碼爲:lineanalysis.cpp
LineAnalysis::LineAnalysis(GraphicsView* view)
: HandleAdapter(view)
{
    m_pLine = NULL;
    m_firstPoint = osg::Vec3d();

    // init style
    m_lineStyle.getOrCreate<osgEarth::Symbology::LineSymbol>()
        ->stroke()->color() = osgEarth::Symbology::Color::Yellow;
    m_lineStyle.getOrCreate<osgEarth::Symbology::LineSymbol>()
        ->stroke()->width() = 2.0;
    m_lineStyle.getOrCreate<osgEarth::Symbology::LineSymbol>()
        ->tessellation() = 20.0;
    m_lineStyle.getOrCreate<osgEarth::Symbology::AltitudeSymbol>()
        ->clamping() = osgEarth::Symbology::AltitudeSymbol::CLAMP_ABSOLUTE;
    m_lineStyle.getOrCreate<osgEarth::Symbology::AltitudeSymbol>()
        ->technique() = osgEarth::Symbology::AltitudeSymbol::TECHNIQUE_MAP;
    m_lineStyle.getOrCreate<osgEarth::Symbology::AltitudeSymbol>()
        ->verticalOffset() = 0.1;

    m_textStyle.getOrCreate<osgEarth::Symbology::TextSymbol>()->alignment()
        = osgEarth::Symbology::TextSymbol::ALIGN_LEFT_TOP;
    m_textStyle.getOrCreate<osgEarth::Symbology::TextSymbol>()->encoding()
        = osgEarth::Symbology::TextSymbol::ENCODING_UTF8;
    m_textStyle.getOrCreate<osgEarth::Symbology::TextSymbol>()->declutter()
        = true;
    m_textStyle.getOrCreate<osgEarth::Symbology::TextSymbol>()->halo()
        = osgEarth::Symbology::Color::White;
    m_textStyle.getOrCreate<osgEarth::Symbology::TextSymbol>()->haloOffset() = 0.05;
    m_textStyle.getOrCreate<osgEarth::Symbology::TextSymbol>()->fill()->color()
        = osg::Vec4(1, 0.5, 0, 1);
    m_textStyle.getOrCreate<osgEarth::Symbology::RenderSymbol>()->lighting() = false;
    m_textStyle.getOrCreate<osgEarth::Symbology::TextSymbol>()->font() = "simhei.ttf";
    m_textStyle.getOrCreate<osgEarth::Symbology::TextSymbol>()->size() = 25.0;
}

LineAnalysis::~LineAnalysis()
{
}

void LineAnalysis::slotPicked(osg::Vec3d pos)
{
    m_firstPoint = pos;
}

void LineAnalysis::slotMoveing(osg::Vec3d pos)
{
    analysis(pos);
}

void LineAnalysis::slotRightHandle()
{
    endHandle();
}

void LineAnalysis::analysis(osg::Vec3d pos)
{
    if (m_firstPoint == osg::Vec3d())
    {
        return;
    }

    if (m_pLine == NULL)
    {
        osgEarth::Features::Feature* pFeature = new osgEarth::Features::Feature(
            new osgEarth::Features::LineString,
            m_pMap3D->getSRS(), m_lineStyle);

        m_pLine = new osgEarth::Annotation::FeatureNode(m_pMap3D->getMapNode(), pFeature);

        m_pPlaceNode = new osgEarth::Annotation::PlaceNode(
            m_pMap3D->getMapNode(), osgEarth::GeoPoint::GeoPoint(), "", m_textStyle);

        m_pLayerGroup->addChild(m_pLine);
        m_pLayerGroup->addChild(m_pPlaceNode);
    }

    osgEarth::Symbology::Geometry* pGeom = m_pLine->getFeature()->getGeometry();
    pGeom->clear();
    m_pLine->setStyle(m_lineStyle);
    pGeom->push_back(m_firstPoint);
    pGeom->push_back(pos);
    m_pLine->init();

    // 碰撞檢測
    QString str;
    osgUtil::IntersectVisitor iv;
    osg::ref_ptr<osg::LineSegment> line = new osg::LineSegment(
        getWorldCoord(osg::Vec3d(m_firstPoint.x(), m_firstPoint.y(), m_firstPoint.z() + 2)),
        getWorldCoord(osg::Vec3d(pos.x(), pos.y(), pos.z() + 2)));
    iv.addLineSegment(line);
    m_pMap3D->getMapNode()->getTerrain()->accept(iv);
    if (iv.hits())
    {
        str = QStringLiteral("兩點不可見");
    }
    else
    {
        str = QStringLiteral("兩點可見");
    }
    m_pPlaceNode->setText(str.toStdWString());
    m_pPlaceNode->setPosition(
        osgEarth::GeoPoint::GeoPoint(m_pMap3D->getSRS(), pos.x(), pos.y()));
}

osg::Vec3d LineAnalysis::getWorldCoord(osg::Vec3d pos)
{
    osg::Vec3d world;
    m_pMap3D->getSRS()->getEllipsoid()->convertLatLongHeightToXYZ(
        osg::DegreesToRadians(pos.y()),
        osg::DegreesToRadians(pos.x()),
        pos.z(), world.x(), world.y(), world.z());

    return world;
}

附:本人以上代碼以及前幾篇關於OSG的代碼均已上傳github,傳送門在此OSGDemo,歡迎各位!

發佈了55 篇原創文章 · 獲贊 118 · 訪問量 39萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章