首页 osgEarth添加图例
文章
取消

osgEarth添加图例

在osgEarth地图上添加图例

多的不说了直接上代码:

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
//由于该功能属于项目的一部分,所以部分使用到的外部变量可能看不懂
//根据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事件时调用即可)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
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());
}

附工具函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
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事件触发即刻调用更新,会导致地图还没来得及放缩,这个时候更新用的地图是原来的地图,肯定导致一定的误差。我的思路是:

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

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

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

本文由作者按照 CC BY 4.0 进行授权

osg添加插件--爬坑之路 无法定位程序输入点于动态库上

Qt查看源码总结帖