在三維場景中有時需要對兩點求其是否可見,即兩點之間有沒有障礙物的遮擋。在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,歡迎各位!