osgEarth添加图例

在osgEarth地图上添加图例

多的不说了直接上代码:

首先是添加控件(使用的是自带控件Control)

//由于该功能属于项目的一部分,所以部分使用到的外部变量可能看不懂
//根据API更替为自己的变量即可
osg::ref_ptr<osg::Group> MAP_GR_CreateScale::createScale()
{
    using namespace osgEarth::Util::Controls;
    osg::ref_ptr<VBox> center = new VBox(Control::ALIGN_RIGHT, Control::ALIGN_BOTTOM, 0, 0);
    // Add a text label:
    {
        osg::ref_ptr<HBox> labelBox = new HBox();
        labelBox->setHorizFill( true );
        labelBox->setChildVertAlign( Control::ALIGN_LEFT );
        labelBox->setMargin(0);
        osg::ref_ptr<LabelControl> label1 = new LabelControl( "0" );
        label1->setFont( osgEarth::Registry::instance()->getDefaultFont() );
        label1->setFontSize( 10.0f );
        label1->setHorizAlign( Control::ALIGN_LEFT );
        label1->setMargin( 0 );
        labelBox->addControl( label1.get() );

        osg::ref_ptr<LabelControl> label2 = new LabelControl( "1000km" );
        label2->setFont( osgEarth::Registry::instance()->getDefaultFont() );
        label2->setFontSize( 10.0f );
        label2->setHorizAlign( Control::ALIGN_CENTER );
        label2->setMargin( 0 );
        labelBox->addControl( label2.get() );

        osg::ref_ptr<LabelControl> label3 = new LabelControl( "2000km" );
        label3->setFont( osgEarth::Registry::instance()->getDefaultFont() );
        label3->setFontSize( 10.0f );
        label3->setHorizAlign( Control::ALIGN_RIGHT );
        label3->setMargin( 0 );
        labelBox->addControl( label3.get() );

        center->addControl(labelBox.get());

        m_label2 = label2;
        m_label3 = label3;
    }

    //Add Bar
    {
        osg::ref_ptr<HBox> barBox = new HBox();
        barBox->setChildSpacing(0);
        barBox->setChildVertAlign( Control::ALIGN_LEFT );
        barBox->setMargin(0);

        osg::ref_ptr<HBox> bar1 = new HBox();
        bar1->setSize(m_defaultPixel, 10);
        bar1->setBackColor( osgEarth::Symbology::Color::Blue );
        bar1->setMargin(0);

        osg::ref_ptr<HBox> bar2 = new HBox();
        bar2->setSize(m_defaultPixel, 10);
        bar2->setBackColor( Color::White );
        bar2->setMargin(0);

        barBox->addChild(bar1);
        barBox->addChild(bar2);
        center->addControl(barBox.get());

        m_bar1 = bar1;
        m_bar2 = bar2;
    }

    auto l_mapData = MAP_GLOBALDATA_APPData::getInstance()->g_mapData;
    if(!l_mapData->valid)
        return nullptr;
    osg::ref_ptr<ControlCanvas> cs = ControlCanvas::getOrCreate( l_mapData->pView );
    cs->addControl(center.get());

    m_pScale = center;
    m_pCanvas = cs;
    return m_pCanvas;
}

然后是实时更新(注册一个handler,在Scroll事件时调用即可)

void MAP_GR_CreateScale::calScale()
{
    if(!m_pCanvas)
        return;
    //默认的像素值(80)对应的距离
    int defaultPixelDistance = MAP_OSG_OSGTool::getDistanceDifferByPixel(m_defaultPixel);
//    qDebug() << defaultPixelDistance;
    //计算默认距离对应有效数字为一位的距离(显示数值)
    int bit = QString::number(defaultPixelDistance).size();
    double value = std::round(defaultPixelDistance / pow(10, bit - 1));
    double nearDistance = value * pow(10, bit - 1);
    double width = MAP_OSG_OSGTool::getPixelByDistance(nearDistance);
    m_bar1->setWidth(width);
    m_bar1->dirty();
    m_bar2->setWidth(width);
    m_bar2->dirty();

    QString label1;
    QString label2;
    // km
    double showValue = nearDistance / 1000;
    if(showValue < 1.0)
    {
        label1 = QString::number(showValue * 1000) + "m";
        label2 = QString::number(2 * showValue * 1000) + "m";
    }
    else
    {
        label1 = QString::number(showValue) + "km";
        label2 = QString::number(2 * showValue) + "km";
    }
    m_label2->setText(label1.toStdString());
    m_label3->setText(label2.toStdString());
}

附工具函数

osg::Vec2 MAP_OSG_OSGTool::getLatLongDegree(double x, double y)
{
    osg::Vec2 pos(0.0, 0.0);
    auto l_mapData = MAP_GLOBALDATA_APPData::getInstance()->g_mapData;
    if(!l_mapData->valid)
        return osg::Vec2();
    osgViewer::View* l_pViewer = l_mapData->pView;
    auto l_mapNode = osgEarth::MapNode::findMapNode(l_pViewer->getSceneData());
    osg::NodePath l_nodePath;
    l_nodePath.push_back(l_mapNode->getTerrainEngine());

    // 获取当前点
    osgUtil::LineSegmentIntersector::Intersections intersection;
    l_pViewer->computeIntersections(x, y, l_nodePath, intersection);
    osgUtil::LineSegmentIntersector::Intersections::iterator iter
            = intersection.begin();
    if (iter != intersection.end())
    {
        osgEarth::GeoPoint point;
        point.fromWorld(l_mapNode->getMap()->getSRS(), iter->getWorldIntersectPoint());
        pos.x() = point.x();
        pos.y() = point.y();

        return pos;
    }
    return osg::Vec2();
}

osg::Vec3 MAP_OSG_OSGTool::windowsXYToLatLongDegree(double x, double y)
{
    auto l_mapData = MAP_GLOBALDATA_APPData::getInstance()->g_mapData;
    if(!l_mapData->valid)
        return osg::Vec3();
    auto camera = l_mapData->pView->getCamera();
    osg::Matrix VPW = camera->getViewMatrix() *
                      camera->getProjectionMatrix() *
                      camera->getViewport()->computeWindowMatrix();
    osg::Matrix inverseVPW;
    inverseVPW.invert(VPW);
    osg::Vec3d world = osg::Vec3d(x,y,0) * inverseVPW;
    osgEarth::GeoPoint point;
    point.fromWorld(l_mapData->pMapSRS, world);
    return osg::Vec3(point.x(), point.y(), point.z());
}

osg::Vec2 MAP_OSG_OSGTool::LatLongDegreeToWindowsXY(double latDegree, double longDegree)
{
    auto l_mapData = MAP_GLOBALDATA_APPData::getInstance()->g_mapData;
    if(!l_mapData->valid)
        return osg::Vec2();
    auto camera = l_mapData->pView->getCamera();
    osg::Matrix VPW = camera->getViewMatrix() *
                      camera->getProjectionMatrix() *
                      camera->getViewport()->computeWindowMatrix();

    osg::Vec3d world;
    bool b = l_mapData->pMapSRS->transformToWorld(osg::Vec3d(longDegree, latDegree, 0.0), world);
    if(!b)
        return osg::Vec2();
    auto windows = world * VPW;
    return osg::Vec2(windows.x(), windows.y());
}

osg::Vec2d MAP_OSG_OSGTool::getLatLongDifferByPixel(double hPixel, double vPixel)
{
    osg::Vec2d differ(0.0, 0.0);
    auto widget = MAP_GLOBALDATA_APPData::getInstance()->g_osgWidget;
    if(!widget)
        return differ;

    double centerX = widget->width() / 2;
    double centerY = widget->height() / 2;
    osg::Vec2 centerLatLong = getLatLongDegree(centerX, centerY);

    double differX = centerX + hPixel;
    double differY = centerY + vPixel;
    osg::Vec2 differLatLong = getLatLongDegree(differX, differY);

    differ.x() = abs(differLatLong.x() - centerLatLong.x());
    differ.y() = abs(differLatLong.y() - centerLatLong.y());
    return differ;
}

double MAP_OSG_OSGTool::getDistanceDifferByPixel(double hPixel)
{
    auto widget = MAP_GLOBALDATA_APPData::getInstance()->g_osgWidget;
    if(!widget)
        return -1;

    double centerX = widget->width() / 2;
    double centerY = widget->height() / 2;
    osg::Vec2 centerLatLong = getLatLongDegree(centerX, centerY);

    double differX = centerX + hPixel;
    osg::Vec2 differLatLong = getLatLongDegree(differX, centerY);

    return osgEarth::GeoMath::distance(osg::Vec3(centerLatLong.x(), centerLatLong.y(), 0),
                                       osg::Vec3(differLatLong.x(), differLatLong.y(), 0),
                                       MAP_GLOBALDATA_APPData::getInstance()->g_mapData->pMapSRS);
}

double MAP_OSG_OSGTool::getPixelByDistance(double distance)
{
    auto widget = MAP_GLOBALDATA_APPData::getInstance()->g_osgWidget;
    if(!widget)
        return -1;
    double centerX = widget->width() / 2;
    double centerY = widget->height() / 2;
    osg::Vec2 centerLatLong = getLatLongDegree(centerX, centerY);

    double nextLat = 0;
    double nextLong = 0;
    osgEarth::GeoMath::destination(osg::DegreesToRadians(centerLatLong.y()),
                                   osg::DegreesToRadians(centerLatLong.x()),
                                   90, distance, nextLat, nextLong);
    nextLat = osg::RadiansToDegrees(nextLat);
    nextLong = osg::RadiansToDegrees(nextLong);

    auto nextWindowXY = MAP_OSG_OSGTool::LatLongDegreeToWindowsXY(nextLat, nextLong);
    return distanceByPoints(osg::Vec2(centerX, centerY), nextWindowXY);
}

double MAP_OSG_OSGTool::distanceByPoints(osg::Vec3 first, osg::Vec3 second)
{
    return std::sqrt(pow(first.x() - second.x(), 2) + pow(first.y() - second.y(), 2) +
                     pow(first.z() - second.z(), 2));
}

double MAP_OSG_OSGTool::distanceByPoints(osg::Vec2 first, osg::Vec2 second)
{
    return std::sqrt(pow(first.x() - second.x(), 2) + pow(first.y() - second.y(), 2));
}

另,有一个小问题,就是如果是在handler中Scroll事件触发即刻调用更新,会导致地图还没来得及放缩,这个时候更新用的地图是原来的地图,肯定导致一定的误差。我的思路是:

void MAP_GR_CreateScale::updateScale()
{
    QTimer::singleShot(100, this, &MAP_GR_CreateScale::calScale);
}

对,没错,就是万能的Timer~

代码较为离散,毕竟是抠出来的一部分啦~

你可能感兴趣的:(OSG)