SuperMap IObjects C++组件学习笔记(二) - Qt接管下IObjectsC++组件的自定义地图绘制

Qt接管下iObjects C++组件的地图自定义绘制

一、什么为自定义绘制

自定义绘制,顾名思义,就是用自己的方法去绘制地图,由于部分地图绘制任务对地图刷新性能的高要求,如果采用GIS组件提供的内置绘制方法,其绘制过程中会有很多的计算和判断,从而消耗大量的不必要时间。
先要缩短地图绘制时间,我们可以使用自己的绘制方法,从两个方面出发去节省GIS组件绘制地图的时间:

  • 1.节约查询时间:

    GIS组件在刷新地图(地图需要绘制)的时候总会先查询出需要绘制的范围内的所有要素,然后再进行绘制,而如果使用自己的方法去绘制,我们可以预先查询得到我们的需要绘制的要素,保存下来,再需要进行绘制的时候,我们即可直接使用我们已有的要素信息来进行绘制。(当然,如果是进行缩放后重绘,我们也需要再判断哪些要素在重绘的图像边界内,但这个查询时间远低于对数据集的信息查询)。

  • 2.节约绘制时间:

    GIS组件在绘制地图时需要判断绘制的图像类型、准备画刷、然后再去绘制,其间会有大量的判断过程,当我们有数量巨大的同类型要素需要绘制时,绘制每一个要素的时候都需要进行这样的判断,这是一个非常浪费时间的过程。而如果我们使用自己的方法去绘制,已经知道我们要绘制的对象的类型,我们完全可以使用自己的办法去一次性绘制完成,这样那些不必要的判断时间就节约下来了。

二、Qt下的自定义绘制概述

Qt下使用SuperMap iObjects C++组件的总体思想是:利用GIS组件在进行GIS图像绘制(其间可能会有空间查询、分析等),将绘制好的图像传给Qt的界面组件,由Qt将我们的图像绘制到屏幕上。
而Qt也有自己的渲染器,不止可以完成图像的渲染、显示,同时还可以对图像进行绘制,所以说我们可以通过GIS组件绘制地图底图,并查询出业务数据,将底图和业务数据(需要自定义绘制的要素)都交给Qt,由Qt完成业务数据在底图上的绘制并显示出来。

三、地图自定义绘制的实现

3.1 地图自定义绘制需要实现的功能:

  • 空间数据的查询–用以得到要绘制的要素信息(主要是地理坐标信息)
  • 空间数据坐标准换–将查询得到的要素地理坐标转换到GIS组件底图所对应的显示设备坐标
  • 图像绘制–将要素按显示设备坐标绘制到显示的图像上

3.2 功能实现

这里以查询中国部分城市,并自定义绘制到屏幕上为例。

3.2.1 空间数据的查

  • 获取要查询的数据集
  • 构建查询信息
  • 查询并保存数据

实现示例代码

void JustDraw::getFieldPoints()
{
    UGVariant v;
    UGPoint2D point;
    //m_pWorkspace为之前加载地图时打开的Workspace,其中已经有名为"China400"的中国地理数据源,
    //数据源中有名为"China_CitDistrict_P"的点数据集
    UGDataSource* pDataSource = m_pWorkspace->GetDataSource(_U("China400"));
    //GetDataset()方法返回的是一个UGDataset类型,该类型为素有数据集类型的基类,
    //由于我已知我要得到的数据集是矢量数据,所以直接强转为UGDatasetVector
    UGDatasetVector* pDvNode = (UGDatasetVector*)(pDataSource->GetDataset(_U("China_CitDistrict_P")));

    //新建查询信息
    UGQueryDef qdf;
    qdf.m_nType = UGQueryDef::General;//查询类型:一般的属性条件查询
    qdf.m_nOptions = UGQueryDef::Both;//查询选项:几何对象(Geometry)和属性(Attribute)都查询
    qdf.m_nMode = UGQueryDef::GeneralQuery;//查询模式:一般查询(非模糊查询)
    qdf.m_nCursorType = UGQueryDef::OpenStatic;//游标类型:静态游标

    //查询
    //查询后,满足条件的要素会存到一个UGRecordset链表中,查询的返回值为该链表头的指针
    UGRecordset* pRsNewObjs = pDvNode->Query(qdf);

    //为确保我们得到的指针是链表表头,我们需要MoveFirst()一下,当然,当前代码中这句可省略
    pRsNewObjs->MoveFirst();
    qDebug()<<pRsNewObjs->IsEOF()<<"xxx"<<pRsNewObjs->GetRecordCount();
    //遍历,如果不为UGRecordset链表结尾
    while(!pRsNewObjs->IsEOF())
    {
        //从当前指针指向的链表记录中获取要绘制点的地理坐标
        if(pRsNewObjs->GetFieldValue(_U("smx"),v))
            point.x = v.ToDouble();
        if(pRsNewObjs->GetFieldValue(_U("smy"),v))
            point.y = v.ToDouble();

        //将地理坐标存入m_pGeoPoints的QList<QPointF>中并移动链表指针
        m_pGeoPoints->append(point);
        pRsNewObjs->MoveNext();
    }
}

3.2.2 空间数据坐标准换

在SuperMap iObjects组件中,空间坐标转换到显示坐标需要经过:

  • 地理坐标->>逻辑坐标->>显示坐标
  • 地理坐标–>逻辑坐标
    需要得到地图底图(UGMap)的DrawParamaters,其提供MPtoLP()方法可以将地理坐标转换为逻辑坐标
  • 逻辑坐标–>显示坐标
    需要得到地图绘制时使用的Graphics,该Graphics提供LPtoDP()方法,可将逻辑坐标转换为绘制图像时的显示坐标。注意:由于Graphics与图像是对应的,要得到正确的显示坐标,则必须使用底图绘制时使用的Graphics。

代码实现

//单个点地理坐标转屏幕坐标的方法
QPointF JustDraw::convertGPToDP(UGPoint2D geoPoint,UGGraphics* pGraphics,UGMap* pMap)
{
    QPointF p;
    UGPoint2D logicPoint;

    //从map中获取到绘图时使用的DrawParamaters,将地理坐标转换为逻辑坐标
    pMap->GetDrawing()->GetDrawParamaters()->MPtoLP(geoPoint,logicPoint);

    //使用我们绘制底图时的所使用的Graphics将逻辑坐标转换为绘制时的显示坐标
    pGraphics->LPtoDP(&logicPoint);

    p.setX(logicPoint.x);
    p.setY(logicPoint.y);

    return p;
}
//将获取到的所有点转换为屏幕坐标
void JustDraw::getPicPoints(UGGraphics *pGraphics, UGMap* pMap)
{
    //遍历我们保存下来的地理坐标List,并转换为屏幕坐标
    if(!m_pGeoPoints->isEmpty())
    {
        foreach (UGPoint2D gp, *m_pGeoPoints)
        {
            m_pPicPoints->append(convertGPToDP(gp, pGraphics, pMap));
        }
    }
}

3.2.3 图像绘制

将获取到的点,按显示坐标绘制到GIS组件绘制好的底图上,由于本示例只是简单的绘制点,所以直接调用Qt的QPainter的drawPoint()方法即可

实现代码

void JustDraw::drawPointsOnImage(QImage *pImage)
{
    //创建一个QPainter
    QPainter painter;
    //设定QPainter开始状态,并指定绘制设备(绘制设备即为我们传入的底图图像)
    painter.begin(pImage);
    //遍历需要绘制的点,并绘制到图像上
    foreach (QPointF p, *m_pPicPoints)
    {
        painter.drawPoint(p);
    }
    //绘制工作完成
    painter.end();
}

本文只写出了实现代码中的重点部分,若需要完整是可运行的代码,请至:http://download.csdn.net/detail/ufolr/8577297 下载

你可能感兴趣的:(Gis,qt,iobjects,supermap)