用VC++完成矢量地圖背景下的實(shí)時(shí)顯示
發(fā)表時(shí)間:2023-08-09 來源:明輝站整理相關(guān)軟件相關(guān)文章人氣:
[摘要]摘要 本文介紹了在VC++實(shí)現(xiàn)的實(shí)時(shí)顯示系統(tǒng)中,用OLE方式嵌入MapInfo矢量地圖的編程方法,簡要敘述了其實(shí)現(xiàn)過程! ∫、 前言 電子地圖應(yīng)用作為一門新興學(xué)科,已不僅限于地圖制作中。本文利用...
摘要 本文介紹了在VC++實(shí)現(xiàn)的實(shí)時(shí)顯示系統(tǒng)中,用OLE方式嵌入MapInfo矢量地圖的編程方法,簡要敘述了其實(shí)現(xiàn)過程。
一、 前言
電子地圖應(yīng)用作為一門新興學(xué)科,已不僅限于地圖制作中。本文利用VC++和OLE(Object Linking and Embedding, 對(duì)象連接和嵌入)編程技術(shù),實(shí)現(xiàn)了實(shí)時(shí)信息在矢量地圖背景上的顯示。
程序應(yīng)用于顯示處理終端,接收并處理網(wǎng)絡(luò)信息的部分在不同的系統(tǒng)中有不同的要求,這里不再贅述。
MapInfo矢量地圖用圖層方式進(jìn)行存儲(chǔ)和管理,每個(gè)圖層對(duì)應(yīng)地圖上的一類要素(如居民地,水系,鐵路,公路等),對(duì)于每個(gè)包含圖形信息的圖層,需要有4個(gè)文件(.dat, .tab, .map, .id)支持。
MapInfo地圖允許嵌入一個(gè)地圖窗口到任何能接受OLE對(duì)象的應(yīng)用程序中。從服務(wù)器(如MapInfo)插入一個(gè)OLE對(duì)象到容器應(yīng)用程序(如Microsoft Word),并在該應(yīng)用程序中對(duì)這個(gè)對(duì)象進(jìn)行處理。被嵌入的對(duì)象是來自服務(wù)器應(yīng)用程序的對(duì)象的一個(gè)副本。對(duì)象一旦位于容器中,它將不再被鏈接到源對(duì)象。
在VC++應(yīng)用程序中用OLE方式嵌入MapInfo進(jìn)程,需定義了一個(gè)MapInfo對(duì)象(DMapInfo類),DMapInfo類在MapInfo類型庫(Mapinfow.tlb)中定義。MapInfo軟件提供了自己的編程語言MapBasic, VC++對(duì)地圖進(jìn)程的操作主要通過發(fā)送MapBasic命令來實(shí)現(xiàn)。
二、 創(chuàng)建程序框架
程序框架是用MFC實(shí)現(xiàn)的,MFC 應(yīng)用程序向?qū)ВˋppWizard)生成了大部分的代碼,然后加入MapInfo進(jìn)程。步驟如下:
1. 創(chuàng)建一個(gè)新項(xiàng)目,項(xiàng)目類型選擇MFC AppWizard(exe),項(xiàng)目名稱設(shè)為MapApp,其它按照提示進(jìn)行設(shè)置即可。應(yīng)用程序向?qū)ё詣?dòng)生成了三個(gè)類:
CmapAppApp 應(yīng)用程序類
CmapAppDoc 文檔類
CmapAppView 視圖類
CmainFrame 主框架類
2. 添加MapInfo類型庫
運(yùn)行類向?qū),單擊增加類按鈕(Add Class …),選擇"From a type library",找到"Mapinfow.tlb"文件并打開,在"Confirm Classes"中選擇"DMapInfo"類,單擊OK確認(rèn)輸入并關(guān)閉對(duì)話框,F(xiàn)在MapApp應(yīng)用程序中已添加了DMapInfo類,并增加了"mapinfow.h"和"mapinfow.cpp"兩個(gè)源文件。
3. 用OLE方式嵌入MapInfo進(jìn)程
在"mapApp.cpp"中CMapAppApp theApp語句下面加入下面的語句:
DMapInfo mapinfo; file://mapinfo對(duì)象
在CMapAppApp::InitInstance() 函數(shù)中增加OLE的初始化,代碼如下:
程序清單1 MapApp.cpp文件
BOOL CMapAppApp::InitInstance()
{
if (!AfxOleInit()) file://OLE初始化
{ file://失敗
AfxMessageBox("OLE失敗!");
return FALSE;
}
if (!mapinfo.CreateDispatch("MapInfo.Application")) file://地圖窗口處理進(jìn)程
{ file://失敗
AfxMessageBox("Failed to create MapInfo dispatch class!");
file://::MessageBox(0, mapinfo.GetFullName(), "Amazing!", MB_OK);
return FALSE;
}
/*本處省略MFC自動(dòng)生成的代碼*/
}
將"mapbasic.h"文件拷貝到本項(xiàng)目的目錄中,在"stdafx.h"中增加以下代碼,把mapinfo說明為全局變量:
#include "mapbasic.h"
#include "mapinfow.h"
extern DMapInfo mapinfo; file://全局變量,地圖窗口對(duì)象
4. 顯示地圖窗口
為CmapAppView類增加地圖窗口的標(biāo)識(shí)和句柄變量,在MapAppView.h文件中添加如下代碼:
unsigned long m_lWindowid; file://地圖窗口標(biāo)識(shí)
HWND m_hWindowHwnd; file://地圖窗口句柄
打開類向?qū)Т翱,在Class Name下拉列表框中選擇類CmapAppView,Object Ids列表框中選擇CmapAppView,Messages列表框中選擇OnInitialUpdate,單擊Add Function為CmapAppView重載OnInitialUpdate()函數(shù),然后在函數(shù)中添加顯示地圖窗口的代碼。
程序清單2 MapAppView.cpp文件
void CMapAppView::OnInitialUpdate()
{
char str[256];
CView::OnInitialUpdate();
char str[256];
///創(chuàng)建航顯底圖
mapinfo.Do("Open Table \"F:\\Province.tab\" ReadOnly Interactive");
mapinfo.Do("Open Table \"f:\\Capitals.tab\" ReadOnly Interactive");
mapinfo.Do("Open Table \"f:\\China.tab\" ReadOnly Interactive");
sprintf(str,"Set Next Document Parent %lu Style 2 ",(long)(UINT)m_hWnd);
mapinfo.Do(str);//創(chuàng)建地圖窗口
/*設(shè)置地圖窗口的圖層,由最上一層開始是中國疆域,各省疆域,省會(huì)城市,并標(biāo)注上省會(huì)城市的名字*/
mapinfo.Do("Map From Capitals, Province, China");
mapinfo.Do("Set Map Layer 1 Label With Capital_Character_Name Parallel On Auto On Visibility On");
file://獲取地圖窗口的ID號(hào)和句柄
m_lWindowid = atol(mapinfo.Eval("WindowID(0)")); file://窗口ID
sprintf(str,"WindowInfo(0, %u)", WIN_INFO_WND); file://窗口HWND
m_hWindowHwnd = (HWND)atol(mapinfo.Eval(str));
file://調(diào)整地圖窗口尺寸,將地圖窗口放置在右半屏上
sprintf(str,
"Set Window %lu Position (8.3,0) Width 8.4 Height 6.05 ScrollBars Off SysMenuClose Off", m_lWindowid);
mapinfo.Do(str);
file://調(diào)整地圖窗口視野和中心點(diǎn)
double m_dView_center_x=113.35; file://地圖窗口中心點(diǎn),經(jīng)緯度
double m_dView_center_y=35.04;
double m_dView_zoom = 4000.0; file://地圖窗口視野,"km"
sprintf(str,"Set Map Window %lu Zoom %lf Units \"km\" Center (%lf,%lf) XY Units \"degree\"", m_lWindowid,m_dView_zoom,m_dView_center_x,m_dView_center_y);
mapinfo.Do(str);//設(shè)置地圖窗口中心點(diǎn)窗口視野
file://設(shè)置地圖窗口漫游縮放的右鍵菜單
mapinfo.Do("Create Menu \"MapshellShortcut\" ID 17 as \"漫游\" calling 1702,\"縮小\" calling 1706, \"放大\" calling 1705 ,\"(-\"");
file://創(chuàng)建實(shí)時(shí)航跡顯示圖層
mapinfo.Do("Create Table plane (ID Integer) File \"f:\\plane.tab\" ");
mapinfo.Do("Create Map For plane");
sprintf(str,"Add Map Window %lu Layer plane Animate",m_lWindowid);
mapinfo.Do(str); file://實(shí)時(shí)航跡圖層設(shè)置為快速刷新}
5. 編譯運(yùn)行軟件,將屏幕顯示分辨率設(shè)置為1600′1024,則在右半屏出現(xiàn)地圖窗口。現(xiàn)在剩下的工作只是加入接收目標(biāo)數(shù)據(jù)并轉(zhuǎn)換為經(jīng)緯度后進(jìn)行實(shí)時(shí)顯示,這里只給出同地圖窗口有關(guān)的部分,假設(shè)正在不斷接收目標(biāo)數(shù)據(jù),寫入全局變量中,并向CmapAppView類發(fā)送消息,調(diào)用CmapAppView類的ShowMapLine()函數(shù)。在MapApp.cpp文件中添加全局變量定義:
double global_long;//經(jīng)度
double global_lat;//緯度
double global_long_last;//上一點(diǎn)經(jīng)度
double global_lat_last;//上一點(diǎn)緯度
unsigned long global_num; file://接收點(diǎn)計(jì)數(shù)
在MapApp.h文件中添加全局變量說明:
extern double global_long;//經(jīng)度
extern double global_lat;//緯度
extern double global_long_last;//上一點(diǎn)經(jīng)度
extern double global_lat_last;//上一點(diǎn)緯度
extern unsigned long global_num; file://接收點(diǎn)計(jì)數(shù)
在CmapAppView::OnInitialUpdate()函數(shù)的結(jié)束部分添加如下代碼:
/////////////////定義mapinfo中所用的變量
mapinfo.Do("Dim obj1 As Object"); file://飛機(jī)圖標(biāo)點(diǎn)對(duì)象
mapinfo.Do("Dim Line1 As Object"); file://航跡線對(duì)象
global_num = 0; file://接收目標(biāo)數(shù)據(jù)計(jì)數(shù)初始化為0
在CmapAppView:: ShowMapLine()函數(shù)代碼如下:
程序清單3 MapAppView.cpp文件
void CMapAppView::ShowMapLine()
{
char str[256];
file://畫飛機(jī)圖標(biāo)
double m_angle = COPI*atan2((global_lat - global_lat_last),
(global_long - global_long_last))-90;//目標(biāo)角度
sprintf(str,
"Create Point Into Variable obj1 (%lf,%lf) Symbol (85,255,30,\"MapInfo Transportation\",0,%lf)",
global_long, global_lat, m_angle); file://設(shè)置飛機(jī)目標(biāo)顯示的樣式
mapinfo.Do(str); file://創(chuàng)建目標(biāo)圖標(biāo)對(duì)象
if (global_num >0 )
{/*收到的第一點(diǎn),在plane表中插入第一條記錄,后面的點(diǎn)都是更新第一條記錄*/
sprintf(str,
"Update plane Set Obj = obj1 Where RowID = %lu",1);}
else {
sprintf(str,
"Inset Into plane (ID,Obj) Values (%lu,Line1) ", global_num);
}
mapinfo.Do(str);//用obj1對(duì)象更新表中的記錄
file://畫各設(shè)備的航跡
sprintf(str,
"Create Line Into Variable Line1 (%lf,%lf) (%lf,%lf) Pen MakePen(2,2,255)",
global_long_last, global_lat_last , global_long, global_lat);
mapinfo.Do(str);//創(chuàng)建line1對(duì)象
if (global_num >0 )
{//第一個(gè)點(diǎn)不畫航跡
sprintf(str,"Fetch Last From plane");
mapinfo.Do(str);
file://插入line1到表中
sprintf(str,"Insert Into plane (ID,Obj) Values (%lu,Line1)",global_num);
mapinfo.Do(str);
}
global_num ++;
}
6. 編譯運(yùn)行軟件,
要保存plane表,可在CmapAppView類的析構(gòu)函數(shù)中添加下面的代碼:
程序清單4 MapAppView.cpp文件
CMapAppView::~CMapAppView()
{
char str[256];
if (m_hWindowHwnd) file://地圖窗口存在
{
sprintf(str,"Close Window %lu",m_lWindowid);
mapinfo.Do(str);
m_hWindowHwnd = NULL;
m_lWindowid = 0L;
mapinfo.Do("Commit Table plane");//保存實(shí)時(shí)航跡表
}
}
左屏顯示內(nèi)容的構(gòu)造,可根據(jù)各軟件系統(tǒng)的要求,顯示數(shù)據(jù),圖表等,由VC++編程實(shí)現(xiàn)。
三、 其它說明
上面程序清單2中
sprintf(str,"Add Map Window %lu Layer plane Animate",m_lWindowid);
語句中的Animate屬性一定要有,這表示將plane圖層設(shè)置為動(dòng)態(tài)(Animate)圖層,每個(gè)地圖窗口只能有一個(gè)動(dòng)態(tài)圖層,當(dāng)這個(gè)圖層上的對(duì)象變化時(shí),地圖窗口只刷新此圖層,以便可以實(shí)現(xiàn)快速刷新。
在應(yīng)用OLE技術(shù)嵌入地圖窗口的應(yīng)用中,還可根據(jù)需要加入多種工具,用于地圖信息的修改和查詢,如標(biāo)尺窗口,信息窗口,圖層控制,圖層選擇編輯等,但在實(shí)時(shí)接收數(shù)據(jù)并顯示的狀態(tài)下,有些功能的使用將會(huì)導(dǎo)致訪問沖突,以致程序出錯(cuò),如圖層控制、圖層編輯等,原因是實(shí)時(shí)數(shù)據(jù)正在對(duì)plane表進(jìn)行編輯,此時(shí)再改變其它圖層,就與mapInfo一次只能編輯一個(gè)圖層的原則產(chǎn)生了沖突。