SuperMap iObjects for C++ 入门详解(VS + Qt)

 

        SuperMap iObjects for C++ 提供了Window 、Linux(x86)  以及 Linux_Arm(银河麒麟系统+龙芯CPU/飞腾CPU)的产品包 ,从而支持跨平台使用。 本文主要介绍如何使用SuperMap iObjects for C++ 组件产品进行二次开发。主要包含以下几个方面的内容:

  • 产品包介绍
  • 开发工具说明
  • 示例程序使用
  • VS开发示例
  • Qt开发示例

1. 产品包介绍

    SuperMap iObjects for C++ 产品包包含下图中的内容:

  •  bin : 动态库目录,包含产品运行所需的动态库,该目录中提供了32位和64位的动态库,同时还都分别提供release和debug两个版本。如: /bin/bin是32位realease的库目录,而/bin/bind是32位debug的库目录
  • lib : 链接库目录,与bin目录一样,也分别提供了32位和64位的release和debug版本的链接库
  • include , include/private: 头文件目录,其中根据不同模块分别创建了目录;注意有些模块放在include/private目录中,注意将include/private也添加到项目的头文件目录设置中
  • license :本产品的使用许可声明,以及产品中用到的开源库的授权文件
  • sample :  示例程序,其中的 extensions4Qt 是基于Qt对SuperMap C++ 组件封装的了QMapControl等基本功能的库工程,gettingStarted 和 planeShow 是依赖于extensions4Qt的Qt应用示例,用于展示地图操作
  • help : 提供了产品入门文档和api文档
  • support :  提供了一些字体库和许可驱动包

   以上最常用到的是 include bin 和  lib,它们提供了C++开发的必要内容。

2. 开发工具说明

    SuperMap iObjects for C++ 的二次开发主要使用VS或Qt进行开发,适用的开发软件版本如下:

    Windows: 

           1) VS 2012 及以上版本,如 VS 2012, VS 2017

           2) Qt 5.3 及以上版本,如 Qt 5.2, Qt 5.6, Qt 5.9, Qt 5.12

           3) VS+Qt开发,在VS上安装合适版本的插件即可

    Linux:

           1) Qt 4.8.6 的编译器,通常需要使用源码编译

           2) Qt Creator4.4, 可根据情况安装,配置好Qt 4.8.6的编译器即可

3. 示例程序使用

       示例程序提供的是 Qt 工程,因此需要使用Qt。当然也可以在VS中安装插件,在VS中打开Qt工程,只不过需要重新对工程配置头文件,链接库等。此处简单说明一下,如何在Qt中运行示例工程,更详细的工程配置,请看后面的“Qt 开发示例”。以运行gettingStarted 为例。

   1. 在 Qt 中依次打开 extensions4Qt 和 gettingStarted

   2. 将需要使用的bin目录添加到构建环境PATH中,如下图所示,添加了 bin\bind_x64所在的目录

      

  3. 编译extensions4Qt,运行 gettingStarted即可

4. VS 开发示例

     1. 创建一个MFC工程: FirstSuperMap

         此处我们创建一个基于对话框的MFC应用,,如下图所示

         

         

     然后,从“资源视图”打开窗口布局,删除 文本和按钮控件,结果如下图所示:

        

     项目创建好后,接下来进行项目配置,此处以debug x64的为例。

     2. 配置运行库

        打开项目属性页,找到“配置属性 -> 调试 -> 环境”,将运行库(bin/bind_x64)的路径添加到项目运行环境中,如图:

         

        

        若不在工程上配置,也可在系统环境变量中配置,注意将其添加到PATH的最前面,并重启VS.

     3. 配置头文件目录

         在“ C/C++ -> 常规  -> 附加包含目录 中, 添加头文件目录(include 和 include/private),如图:

         

     4. 增加预编译宏(_UGUNICODE),

         在“C/C++  ->  预编译器” 中,增加预编译宏 _UGUNICODE, 如图:

         

     5. 启用宽字符

         在“C/C++ -> 语言 -> 将 Wchar 视为内置类型”,设置为“”,以启用宽字符,如图:

         

     6. x64 版本编译时“字节数超过对象格式限制: 请使用 /bigobj 进行编译”,设置如下:

         

     7. 配置连接库目录

         在链接器配置中,添加链接库目录(lib/libd_x64), 如图:

         

     8. 配置所需要的库文件名称

         在链接器配置中,添加所需的链接库库文件名称,如下:

SuBased.lib
SuElementd.lib
SuDrawingd.lib
SuEngined.lib
SuFileParserd.lib
SuGeometryd.lib
SuGraphicsd.lib
SuMapd.lib
SuMapEditord.lib
SuOGDCd.lib
SuToolkitd.lib
SuWorkspaced.lib
SuBase3Dd.lib
SuSpatialIndexd.lib
SuChartBased.lib

          配置如图:

         

    9. 实现地图窗口

         首先,创建一个 MapControl 类,用于实现对地图窗口的基本封装,也方便重复使用,并且使得 MapControl 同时支持 VS MFC 框架和 Qt 框架的窗口。

         (1) 在 MapControl.h 文件,如下所示:

#ifndef MAPCONTROL_H
#define MAPCONTROL_H

#include "MapEditor/UGMapEditorWnd.h"
#include "Graphics/UGGraphicsManager.h"
#include "Drawing/UGDrawParamaters.h"
#include "Geometry/UGGeoPoint.h"

using namespace UGC;

// For Callback
#if defined WIN32 || defined _WINDOWS
#define SuCALLBACK __stdcall
#else
#define SuCALLBACK
#endif

class  MapControl
{
	//Constructor
public:
	/*
	 *@en
	 *@pInvalidateCallBack  A callback function pointer through which to invalidate the Window if map content is updated
	 *@pWnd  the Window which owns the invalidate callback function
	*/
	MapControl(INVALIDATEPROC pInvalidateCallBack, void* pWnd);
	virtual ~MapControl();

...

};

         (2) 在 MapControl.cpp 文件,如下所示:

#include "stdafx.h"
#include "MapControl.h"


/************** 地图窗口相关 ****************/
/**************** Invalidate CallBack used in MapControl *********************/
void SuCALLBACK InvalidateCallbackMapControl(void * p)
{
	MapControl* pThis = (MapControl*)p;

	pThis->Invalidate();

}

MapControl::MapControl(INVALIDATEPROC pInvalidateCallBack, void* pView)
{
	m_pUGMapWnd = NULL;
	m_pGraphicsImage = NULL;
	m_pGraphicsImageOld = NULL;
	m_pInvalidateCallback = NULL;

	m_IsMinSized = false;

	m_pWnd = pView;
	m_pInvalidateCallback = pInvalidateCallBack;
	//Initialize(pInvalidateCallBack, pView);
	Initialize(InvalidateCallbackMapControl, this);

	/*UGWorkspace* pWorkspace = m_pUGMapWnd->m_mapWnd.m_Map.GetWorkspace();
	if(pWorkspace == NULL){
		pWorkspace = new UGWorkspace();
		m_pUGMapWnd->m_mapWnd.m_Map.SetWorkspace(pWorkspace);
	}*/

	m_pInnerWorkspace = new UGWorkspace();
	m_pWorkspace = NULL;
	SetWorkspace(m_pInnerWorkspace);

	mNeedRedraw = false;

	mIsInWorkspace = false;

}
...

        (3) 在 FirstSuperMapDlg.h 文件中,引入 MapControl.h,并声明一个 MapControl 指针  , 如所示:

// FirstSuperMapDlg.h

private:
	MapControl* m_pMapControl;

        (4) 在 FirstSuperMapDlg.cpp 文件定义一个全局的地图刷新回调函数,如下所示:     

// 地图刷新回调
void SuCALLBACK InvalidateCallBack(void* pWnd)
{

	// send message to view  for invalidating itself

	FirstSuperMapDlg *pView = (FirstSuperMapDlg *)pWnd;
	if (pView->m_hWnd != NULL && pView->IsWindowVisible())
		pView->Invalidate(false); // not redraw background
}

         (4) 在 FirstSuperMapDlg 的构造函数初始化 m_pMapControl,并且先检查了组件许可的检查是否有效,如下所示:

// FirstSuperMapDlg.cpp

FirstSuperMapDlg::FirstSuperMapDlg(CWnd* pParent /*=nullptr*/)
	: CDialogEx(IDD_FIRSTSUPERMAP_DIALOG, pParent)
{
	m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);

	bool isValid = UGLicense::VerifyLicense(UGLicense_iObjectsCppCore);
	if (isValid) {
		m_pMapControl = new MapControl(InvalidateCallBack, this);
	}
	else {
		m_pMapControl == NULL;
	}
	assert(m_pMapControl != NULL);
}

          (5) 修改 FirstSuperMapDlg::OnPaint() 函数,从而将地图绘制到窗口上,如图所示:

// FirstSuperMapDlg.cpp

void FirstSuperMapDlg::OnPaint()
{
	CPaintDC dc(this); // device context for painting
	CRect rect;
	GetClientRect(&rect);
	m_pMapControl->OnDraw(rect.left, rect.top, rect.right, rect.bottom, dc.m_hDC);

	CDialogEx::OnPaint();
}

           (6) 在 FirstSuperMapDlg.h 的 FirstSuperMapDlg 类声明需要的鼠标事件函数,如下所示:

// FirstSuperMapDlg.h

public:
	afx_msg void OnMouseMove(UINT nFlags, CPoint point);
	afx_msg BOOL OnMouseWheel(UINT nFlags, short zDelta, CPoint pt);
	afx_msg void OnLButtonDown(UINT nFlags, CPoint point);
	afx_msg void OnLButtonUp(UINT nFlags, CPoint point);
	afx_msg void OnLButtonDblClk(UINT nFlags, CPoint point);
	afx_msg void OnRButtonDown(UINT nFlags, CPoint point);
	afx_msg void OnRButtonUp(UINT nFlags, CPoint point);
	afx_msg void OnRButtonDblClk(UINT nFlags, CPoint point);
	afx_msg void OnSize(UINT nType, int cx, int cy);

           (7) 在 FirstSuperMapDlg.cpp 的 BEGIN_MESSAGE_MAP 增加上述事件命令,并实现对应函数,如下所示:


BEGIN_MESSAGE_MAP(FirstSuperMapDlg, CDialogEx)
	ON_WM_SYSCOMMAND()
	ON_WM_PAINT()
	ON_WM_QUERYDRAGICON()
	ON_WM_MOUSEMOVE()
	ON_WM_MOUSEWHEEL()
	ON_WM_LBUTTONDOWN()
	ON_WM_LBUTTONUP()
	ON_WM_LBUTTONDBLCLK()
	ON_WM_RBUTTONDOWN()
	ON_WM_RBUTTONUP()
	ON_WM_RBUTTONDBLCLK()
	ON_WM_SIZE()
END_MESSAGE_MAP()
// FirstSuperMapDlg.cpp

void FirstSuperMapDlg::OnMouseMove(UINT nFlags, CPoint point)
{
	// TODO: Add your message handler code here and/or call default
	//CPaintDC dc(this); 

	m_pMapControl->OnMouseMove(nFlags, point.x, point.y, ::GetDC(this->m_hWnd));
	CDialogEx::OnMouseMove(nFlags, point);
}


...

    10. 增加打开工作空间和地图的代码

         在地图窗口初始化成功后,打开工作空间,并打开地图, 如下:

// FirstSuperMapDlg.cpp

FirstSuperMapDlg::FirstSuperMapDlg(CWnd* pParent /*=nullptr*/)
	: CDialogEx(IDD_FIRSTSUPERMAP_DIALOG, pParent)
{
	m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);

	bool isValid = UGLicense::VerifyLicense(UGLicense_iObjectsCppCore);
	if (isValid) {
		m_pMapControl = new MapControl(InvalidateCallBack, this);

		// Open workspace file
		UGString wkPath = _U("E:\\SuperMap\\iObject_CPP\\1000\\sample\\data\\China400_E-map.smwu");

		UGWorkspaceConnection wkCon;

		wkCon.m_strServer = wkPath;
		wkCon.m_nWorkspaceType = UGWorkspace::WS_Version_SMWU;

		UGWorkspace* pWorkspace = m_pMapControl->GetWorkspace();
		if (pWorkspace->Open(wkCon))
		{
			if (pWorkspace->m_MapStorages.GetCount() > 0)
			{
				UGString mapName = pWorkspace->m_MapStorages.GetNameAt(0);
				UGbool isOpen = m_pMapControl->GetMapEditWnd()->m_mapWnd.m_Map.Open(mapName);
				m_pMapControl->Refresh();

			}
		}
	}
	else {
		m_pMapControl == NULL;
	}
	assert(m_pMapControl != NULL);
}

    11. 运行该工程, 如下图所示:

       

5. Qt 开发示例

     1. 创建Qt项目FirstSuperMap

     2. 项目设置中,增加环境变量,如 OBJECTSDIR , 用于指定SuperMap iObjects for C++ 所在目录,方便以后修改;如图:

     3. 将运行库(bin/bind_x64)的目录添加到PATH中,如图:

     4. 在.pro文件中,配置 预编译宏、宽字符、头文件和链接库等

        Windows 和 Linux 上配置略有不同,在此提供两种系统的配置,以便迁移到Linux系统, 增加的配置如下:

DEFINES += _UGUNICODE

# Include Path
OBJECTSDIR = "$$(OBJECTSDIR)"
#message($${OBJECTSDIR})

INCLUDEPATH +=$${OBJECTSDIR}/include\
    $${OBJECTSDIR}/include/private\
    ../../../Include

# x64 /bigobj
QMAKE_CXXFLAGS += /bigobj

win32{
    # wchar_t
    QMAKE_CXXFLAGS += -Zc:wchar_t

    # x64
    CONFIG(debug, debug|release){

    LIBPATH = $${OBJECTSDIR}/lib/libd_x64
    LIBS +=  -lSuBased            \
             -lSuElementd         \
             -lSuDrawingd         \
             -lSuEngined          \
             -lSuFileParserd      \
             -lSuGeometryd        \
             -lSuGraphicsd        \
             -lSuMapd             \
             -lSuMapEditord       \
             -lSuOGDCd            \
             -lSuToolkitd         \
             -lSuWorkspaced       \
             -lSuBase3Dd          \
             -lSuSpatialIndexd    \
             -lSuChartBased       \

    }else:CONFIG(release, debug|release){

    LIBPATH = $${OBJECTSDIR}/lib/lib_x64
    LIBS +=  -lSuBase            \
             -lSuElement         \
             -lSuDrawing         \
             -lSuEngine          \
             -lSuFileParser      \
             -lSuGeometry        \
             -lSuGraphics        \
             -lSuMap             \
             -lSuMapEditor       \
             -lSuOGDC            \
             -lSuToolkit         \
             -lSuWorkspace       \
             -lSuBase3D          \
             -lSuSpatialIndex    \
             -lSuChartBase       \
    }
}
unix:{
    # 16bit wchar
    QMAKE_CXXFLAGS =-fshort-wchar
    # 支持C++11
    QMAKE_CXXFLAGS += -std=c++11
    # 对std库使用旧ABI, 也可在头文件开始处使用#define _GLIBCXX_USE_CXX11_ABI 0, 如此只对该文件起作用;但独立的库更好管理;
    # 新ABI在库中的链接名称如_cxx11::std::string, 旧ABI在库中名称如std::string
    # GCC 默认值为1,使用新ABI;
    DEFINES += _GLIBCXX_USE_CXX11_ABI=0

    LIBS += -L$${OBJECTSDIR}/bin/bin \
  -lSuBase            \
             -lSuElement         \
             -lSuDrawing         \
             -lSuEngine          \
             -lSuFileParser      \
             -lSuGeometry        \
             -lSuGraphics        \
             -lSuMap             \
             -lSuMapEditor       \
             -lSuOGDC            \
             -lSuToolkit         \
             -lSuWorkspace       \
             -lSuBase3D          \
             -lSuSpatialIndex    \
             -lSuChartBase       \
}

     5. 实现地图窗口

         Qt中地图窗口的实现与VS中的类似,MapControl是一个完整的类,因此将其拷贝过来即可。注意,删除 MapContro.cpp 的第一行(#include "stdafx.h"),该行在Qt中不需要。

        (1) 在 .pro 文件增加 MapControl的源文件和头文件,以便Qt项目可使用,如下所示:

SOURCES += \
        main.cpp \
        MainWindow.cpp \
        MapControl.cpp

HEADERS += \
        MainWindow.h \
        MapControl.h

        (2) 在 MainWindow.h 文件添加 MapControl 的头文件(#include "MapControl.h"), 定义MapControl指针,如下所示:

private:
    MapControl* m_pMapControl;

        (3) 在 MainWindow.cpp 文件定义一个全局的地图刷新回调函数,如下所示:

/**************** Map Refresh CallBack *********************/
void SuCALLBACK InvalidateCallback(void * pWnd)
{
    MainWindow* pThis = (MainWindow*)pWnd;

    if(pThis != NULL)
        pThis->update();
}

        (4) 在 MainWindow 的构造函数中,初始化 m_pMapControl,并且先检查了组件许可的检查是否有效,如下所示:

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    bool isValid = UGLicense::VerifyLicense(UGLicense_iObjectsCppCore);;
    if(isValid)
    {
        m_pMapControl = new MapControl(InvalidateCallback, this);
    }else
    {
        m_pMapControl = NULL;
        qDebug("许可无效,请配置SuperMap组件许可.");
    }
    assert(m_pMapControl != NULL);

}

        (5)  在 MainWindow.h 声明绘制函数和鼠标事件函数,如下所示:


private:
    unsigned int getMouseOrKeyFlag(QMouseEvent* event);

protected:
    virtual void paintEvent(QPaintEvent* event);
    virtual void wheelEvent(QWheelEvent* event);
    virtual void mousePressEvent(QMouseEvent* event);
    virtual void mouseReleaseEvent(QMouseEvent* event);
    virtual void mouseMoveEvent(QMouseEvent* event);
    virtual void resizeEvent(QResizeEvent* event);
    virtual void keyPressEvent(QKeyEvent* event);
    virtual void mouseDoubleClickEvent(QMouseEvent *event);

       (6) 在 MainWindow.cpp 中实现上述函数,如下所示:

/*********** Override event functions ************/
void MainWindow::paintEvent(QPaintEvent* event)
{
    if(m_pMapControl == NULL){
        return;
    }
    m_pMapControl->OnDraw(0, 0, this->width(), this->height());
    uchar* imgData = m_pMapControl->GetImageBytes();
    if (imgData != NULL){
        QImage* pQImage = new QImage(imgData, this->width(), this->height(), QImage::Format_ARGB32);

        QColor background(255, 255, 255);
        QPainter painter;
        painter.begin(this);
        painter.fillRect(0, 0, this->width(), this->height(), background);
        painter.drawImage(QRectF(0, 0, this->width(), this->height()), *pQImage);

        // paint signal / slot
        painter.end();
        delete pQImage;
    }
    else {
        // no map data
    }
}
unsigned int MainWindow::getMouseOrKeyFlag(QMouseEvent* event)
{
    unsigned int flag = 0;
    if (event->modifiers() & Qt::ShiftModifier){
        flag = flag | UG_MK_SHIFT;
    }
    if ((event->modifiers() & Qt::ControlModifier)){
        flag = flag | UG_MK_CONTROL;
    }
    return flag;
}
void MainWindow::wheelEvent(QWheelEvent* event)
{
    if(m_pMapControl != NULL){
        m_pMapControl->OnMouseWheel(0, event->delta(), event->x(), event->y());
    }
}

...

      (7) 添加打开工作空间和地图的代码,如下所示:

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    bool isValid = UGLicense::VerifyLicense(UGLicense_iObjectsCppCore);
    if(isValid)
    {
        m_pMapControl = new MapControl(InvalidateCallback, this);
        // Open workspace file
        UGString wkPath = _U("E:\\SuperMap\\iObject_CPP\\1000\\sample\\data\\China400_E-map.smwu");

        UGWorkspaceConnection wkCon;

        wkCon.m_strServer = wkPath;
        wkCon.m_nWorkspaceType = UGWorkspace::WS_Version_SMWU;

        UGWorkspace* pWorkspace = m_pMapControl->GetWorkspace();
        if (pWorkspace->Open(wkCon))
        {
             if (pWorkspace->m_MapStorages.GetCount() > 0)
             {
                  UGString mapName = pWorkspace->m_MapStorages.GetNameAt(0);
                  UGbool isOpen = m_pMapControl->GetMapEditWnd()->m_mapWnd.m_Map.Open(mapName);
                  m_pMapControl->Refresh();

             }
        }
    }else
    {
        m_pMapControl = NULL;
        qDebug("许可无效,请配置SuperMap组件许可.");
    }
    assert(m_pMapControl != NULL);
}

     6. 运行该工程, 如下图所示:

       

      9. 在VS中使用Qt开发

          在VS中使用Qt开发,需要指定Qt模块 Core, GUI, Widgets, 其他工程配置和前面的MFC项目配置方式一样;若是打开已有的Qt项目,还需配置Qt的版本和需要的模块。右键项目,选择 Qt -> “Qt 设置选项”打开如下也页面进行配置。

 

      至此,关于 SuperMap iObjects for C++  的入门开发就介绍完了。示例数据是产品包中带有的,此处就不单独提供了,当然,也可以使用自己的数。示例程序请通过页面上方的资源下载。

更多功能,请参考GitHub项目https://github.com/Jun0x01/JunSuCpp

  • 3
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值