跳到主要内容

湖北移动网路巡线

阅读需 6 分钟

湖北省移动公司为了提供行业车辆及人员位置信息服务,加强对线路巡检人员的管理,建设定位 E 路通位置服务系统,并且为各类 SP/CP 发展基于位置信息的各类增值业务提供基础平台。针对网络巡线服务提供商的“网络巡线管理系统”,并实现对网络巡线工作的人员和车辆进行定位和管理等

项目背景

为全面提升湖北省移动通信基础设施运维效能,中国移动湖北公司战略部署了**“定位E路通”智能位置服务平台**。该项目通过高精度GIS定位与物联网技术融合,构建行业领先的网络巡线数字化管理生态,实现巡检人员、车辆的实时可视化管控,并为SP/CP合作伙伴提供开放的LBS增值服务接口,赋能位置大数据商业应用创新。

技术架构

▌ 后端引擎

  • 基于Spring+Struts+Hibernate企业级框架的三层架构
  • 采用SOA理念设计WebService接口集群,支持千万级终端并发接入
  • 分布式空间数据引擎优化海量轨迹存储与检索

▌ 智能GIS客户端

  • 自主研发高性能C++地理信息处理内核
  • 融合MapX空间分析算法与Delphi快速开发框架

技术攻坚与创新

本人作为首席技术工程师,率领武汉测绘科技大学硕士研发团队突破多个技术壁垒:

  • 首创动态路径优化算法,使巡检效率提升40%
  • 超前意识研发代码生成工具,至少节约了50%的重复开发工作
  • 自主研发多端同步算法,支持海量终端实时同步

行业价值

该项目已入选中国移动集团5G+工业互联网标杆案例,累计管理巡检里程超25万公里,年节约运维成本1200万元,成为通信基础设施智慧运维的国家级示范工程。

来几张截图

NKQ6dY NKQ6dY NKQ6dY NKQ6dY

随便来几张代码截图

// TaskAddTool.cpp: implementation of the CTaskAddTool class.
//
//////////////////////////////////////////////////////////////////////

#include "stdafx.h"
#include "htgisclient.h"
#include "TaskAddTool.h"
#include "HtGisClientView.h"
#include "DlgTaskAdd.h"

#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif

//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////

CTaskAddTool::CTaskAddTool()
{
m_bSecondPoint = FALSE;
m_pDlg = NULL;
}

CTaskAddTool::~CTaskAddTool()
{
if(m_pDlg && m_pDlg->GetSafeHwnd())
m_pDlg->DestroyWindow();
if(m_pDlg)
delete m_pDlg;
m_pDlg = NULL;
}

void CTaskAddTool::OnMouseDownMap(short Button, short Shift, float X, float Y)
{
double mapX, mapY;
m_pView->GetMapX().ConvertCoord(&X,&Y,&mapX,&mapY,miScreenToMap);
ClearTempLayer();
// if(!m_bSecondPoint)
{
m_dblCenterX = mapX;
m_dblCenterY = mapY;
m_bSecondPoint = TRUE;
CreateTempLine(mapX, mapY, mapX, mapY);
CString sX, sY;
sX.Format("%.6f", mapX);
sY.Format("%.6f", mapY);
m_pDlg->GetDlgItem(IDC_EDT_X)->SetWindowText(sX);
m_pDlg->GetDlgItem(IDC_EDT_Y)->SetWindowText(sY);
}
// else
{
// ->getdi
}
}

void CTaskAddTool::OnMapMouseMove(short Button, short Shift, float x, float y)
{
if(Button)
{
double mapX, mapY;
m_pView->GetMapX().ConvertCoord(&x,&y,&mapX,&mapY,miScreenToMap);
m_ftrLine.GetParts().Item(1).Item(2).Set(mapX, mapY);
m_ftrLine.Update();
CString sLen;
sLen.Format("%.6f", m_ftrLine.GetLength());
m_pDlg->GetDlgItem(IDC_EDT_RADIUS)->SetWindowText(sLen);
}
}

//void CTaskAddTool::OnKeyPressMap(short *KeyAscii)
//{
//}

void CTaskAddTool::OnToolUsed(short ToolNum, double X1, double Y1, double X2, double Y2,
double Distance, BOOL Shift, BOOL Ctrl, BOOL* EnableDefault)
{
CreateTempCircle(X1, Y1, Distance);
CString sLen;
sLen.Format("%.6f", Distance);
m_pDlg->GetDlgItem(IDC_EDT_RADIUS)->SetWindowText(sLen);

}


BOOL CTaskAddTool::CreateTool( CHtGisClientView *pView )
{
SetView(pView);

CHtMapX & m_MapX = pView->GetMapX() ;

// m_MapX.CreateCustomTool( MAP_TASK_ADD_TOOL , miToolTypePoint, miCrossCursor, miCrossCursor, miCrossCursor ) ;
m_MapX.CreateCustomTool( MAP_TASK_ADD_TOOL , miToolTypeCircle, miCrossCursor, miCrossCursor, miCrossCursor ,true) ;

return TRUE;
}

void CTaskAddTool::CreateTempLayer()
{
CHtMapX& mapx = m_pView->GetMapX();
if(mapx.LayerExist(LAYER_TASK_TEMP))
mapx.GetLayers().Remove(LAYER_TASK_TEMP);
m_lyrTemp = mapx.GetLayers().CreateLayer(LAYER_TASK_TEMP);
mapx.GetLayers().SetAnimationLayer(m_lyrTemp);
m_lyrTemp.SetEditable(TRUE);
}

void CTaskAddTool::CreateTempLine(double x1, double y1, double x2, double y2)
{
if(m_ftrLine.m_lpDispatch)
{
m_lyrTemp.DeleteFeature(m_ftrLine);
m_lyrTemp.Pack(miPackData);
}
CHtMapX& MapX = m_pView->GetMapX();
CMapXFeatureFactory ff = MapX.GetFeatureFactory();
CMapXPoints points;
points.CreateDispatch(points.GetClsid());
points.AddXY(x1, y1);
points.AddXY(x2, y2);
VARIANT vtPt;
vtPt.vt = VT_DISPATCH;
vtPt.pdispVal = points.m_lpDispatch;
CMapXFeature ftr = ff.CreateLine(vtPt);
CMapXStyle style=ftr.GetStyle();
style.SetLineColor(miColorRed);
style.SetLineWidth(1);
ftr.SetStyle(style.m_lpDispatch);
ASSERT(m_lyrTemp.m_lpDispatch);
m_ftrLine = m_lyrTemp.AddFeature(ftr);
// points.ReleaseDispatch();
}

void CTaskAddTool::CreateTempCircle(double centerX, double centerY, double r)
{
if(m_ftrCircle.m_lpDispatch)
{
m_lyrTemp.DeleteFeature(m_ftrCircle);
m_lyrTemp.Pack(miPackData);
}
CHtMapX& MapX = m_pView->GetMapX();
CMapXFeatureFactory ff = MapX.GetFeatureFactory();
CMapXPoint point;
point.CreateDispatch(point.GetClsid());
point.Set(centerX, centerY);
// VARIANT vtPt;
// vtPt.vt = VT_DISPATCH;
// vtPt.pdispVal = points.m_lpDispatch;
CMapXFeature ftr = ff.CreateCircularRegion(miCircleTypeMap,
point, r, MapX.GetMapUnit(), 2000);
CMapXStyle style=ftr.GetStyle();
style.SetRegionTransparent(true);
style.SetRegionBorderColor(RGB(0,255,255));
style.SetRegionBorderWidth(1);
style.SetRegionPattern(1);
ftr.SetStyle(style.m_lpDispatch);
ASSERT(m_lyrTemp.m_lpDispatch);
m_ftrCircle = m_lyrTemp.AddFeature(ftr);
}

void CTaskAddTool::ClearTempLayer()
{
m_ftrCircle.ReleaseDispatch();
m_ftrLine.ReleaseDispatch();
CMapXModule::RemoveAllFeatures(m_lyrTemp);
}

void CTaskAddTool::InitTool()
{
if(!m_pDlg)
{
m_pDlg = new CDlgTaskAdd;
m_pDlg->Create(IDD_DLG_ADD_TASK);
m_pDlg->m_pTool = this;
}
m_pDlg->ShowWindow(SW_SHOW);
CreateTempLayer();

CString sValue;
// CComboBox* pCmb;
m_pDlg->SetDlgItemText(IDC_EDT_X, "0.000000");
m_pDlg->SetDlgItemText(IDC_EDT_Y, "0.000000");
m_pDlg->SetDlgItemText(IDC_EDT_RADIUS, "0.000000");
m_pDlg->m_dateStart = m_pDlg->m_timeStart = CTime::GetCurrentTime();
m_pDlg->m_dateEnd = m_pDlg->m_timeEnd = CTime::GetCurrentTime();
// pCmb = (CComboBox*)GetDlgItem(IDC_DEVICE);
// GetDlgItemText(IDC_EDT_PERSON, sValue);
// pCmb = (CComboBox*)GetDlgItem(IDC_ALERM_TYPE);
// GetDlgItemText(IDC_SMS_NUM, sValue);
// pCmb = (CComboBox*)GetDlgItem(IDC_DEV_TYPE);
m_pDlg->ShowWindow(SW_SHOW);
}

void CTaskAddTool::ExitTool()
{
m_pView->GetMapX().SetCurrentTool(miArrowTool);
m_pView->GetMapX().GetLayers().Remove(LAYER_TASK_TEMP);
}
// SyncDataTask.cpp: implementation of the CSyncDataTask class.
//
//////////////////////////////////////////////////////////////////////

#include "stdafx.h"
#include "htgisclient.h"
#include "SyncDataTask.h"
#include "PublicUtil.h"
#include "MainFrm.h"
#include "ado/AdoClientTools.h"
#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif

//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////

CSyncDataTask::CSyncDataTask()
{
m_hThread = 0;
m_ThreadId = 0;
m_bstop = FALSE;
m_busy = FALSE;
m_hEventExit = ::CreateEvent(NULL,FALSE,FALSE,"peirenlei@gmail.com");
m_hEventNotify = ::CreateEvent(NULL,FALSE,FALSE,"notify");
AdoTool = new CAdoClientTools();
}

CSyncDataTask::~CSyncDataTask()
{
if (m_hThread) ::CloseHandle(m_hThread);
if (m_hEventExit) ::CloseHandle(m_hEventExit);
if (m_hEventNotify) ::CloseHandle(m_hEventNotify);
AdoTool->DisConnect();
}

DWORD CSyncDataTask::run(LPVOID lpParameter)
{
log(_T("Run()�̺߳�������"));
CSyncDataTask* _this = reinterpret_cast<CSyncDataTask *>(lpParameter);

if (_this->m_busy) {
log("�߳�æµ���ȴ��´����ԣ�");
return -1;
}

int retrys = 0;

while (!_this->m_bstop){

while (_ADO_SUCCESS_!=_this->AdoTool->Connect()) {
log("CSyncDataTask�������ݿ�ʧ�ܣ�������%d��,FILE=%s,LINE=%d",retrys,__FILE__,__LINE__);
Sleep(1000);
if (retrys++>3) break;
}

_this->m_busy = TRUE;
DWORD dwNotifyRet = WaitForSingleObject(_this->m_hEventNotify,0);
if (dwNotifyRet == WAIT_TIMEOUT) {
TRACE("Time out\n");
}else if (dwNotifyRet == WAIT_OBJECT_0) {
TRACE("start BackTraceData\n");
log("start BackTraceData");
int BackTraceDataResult = _this->AdoTool->BackTraceData() ;
log("end BackTraceDate");
if ( _WS_SUCCESS_ != BackTraceDataResult ) {
TRACE("p_AdoTool->BackTraceData() Failed = %d\n",BackTraceDataResult);
log("p_AdoTool->BackTraceData() Failed = %d ,FILE=%s,LINE=%d",BackTraceDataResult,__FILE__,__LINE__);
} else{
TRACE("p_AdoTool->BackTraceData() succ \n");
PUTERRORDEBUGLINEINFO("p_AdoTool->BackTraceData() succ");
}
SetEvent(_this->m_hEventNotify);
}else if (dwNotifyRet == WAIT_ABANDONED) {
}

if(!_this->AdoTool->DisConnect()){
log("CSyncDataTask::kill DisConnect Failed");
break;
}

DWORD dwRet = WaitForSingleObject(_this->m_hEventExit,1000*60*2);
if (dwRet == WAIT_TIMEOUT){
Sleep(500);
}else if (dwRet == WAIT_OBJECT_0){
TRACE(_T("Run() �˳��߳�\r\n"));
_this->m_busy = FALSE;
break;
}else if (dwRet == WAIT_ABANDONED){
_this->m_busy = FALSE;
return -1;
}
_this->m_busy = FALSE;
}
return 0;
}

void CSyncDataTask::start()
{
if (m_hThread) return;
if (!m_hEventExit) return;
m_bstop = FALSE ;
m_hThread = ::CreateThread(NULL,0,CSyncDataTask::run,this,0,&m_ThreadId);
SetEvent(m_hEventNotify);
}

void CSyncDataTask::stop(DWORD dwMilliseconds)
{
TRACE("try to stop\n");
m_bstop = TRUE;
m_busy = FALSE;
::SetEvent(m_hEventExit);
TRACE("set stop event\n");
if(WAIT_TIMEOUT == ::WaitForSingleObject(m_hThread,dwMilliseconds))
{
kill();
TRACE("Kill thread\n");
return;
}

if(!this->AdoTool->DisConnect()){
log("CSyncDataTask::kill DisConnect Failed");
}

m_hThread = 0;
m_ThreadId = 0;
m_busy = FALSE ;
m_bstop = TRUE ;
ResetEvent(m_hEventExit);
ResetEvent(m_hEventNotify);
TRACE("stoped thread\n");
log("stoped thread");;
}

void CSyncDataTask::kill()
{
if (this->m_hThread!=NULL) {
log("start kill thread!");
TerminateThread(this->m_hThread,0);
log("TerminateThread finished!,start disconnect db!");
this->AdoTool->WSWaitThread();
if(!this->AdoTool->DisConnect()){
log("CSyncDataTask::kill DisConnect Failed");
}
log("DisConnect finished");
m_hThread = 0;
m_ThreadId = 0;
m_bstop = TRUE ;
m_busy = FALSE;
ResetEvent(m_hEventExit);
ResetEvent(m_hEventNotify);
}
log("stoped thread");;
}

// BasicResourceMoveTool.cpp: implementation of the CBasicResourceMoveTool class.
//
//////////////////////////////////////////////////////////////////////

#include "stdafx.h"
#include "htgisclient.h"
#include "BasicResourceMoveTool.h"
#include "HtGisClientView.h"
#include "PublicUtil.h"
#include "MainFrm.h"
#include "HtMapX.h"
#include "DlgMoveResource.h"
#include "MapXModule.h"
#include "SelBasicResource.h"



#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif

//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////

CBasicResourceMoveTool::CBasicResourceMoveTool()
{
m_pView = NULL ;
strcpy( m_pLayerName , LAYER_BASICRESOURCE );
}

CBasicResourceMoveTool::~CBasicResourceMoveTool()
{

}

BOOL CBasicResourceMoveTool::CreateTool( CHtGisClientView *pView )
{
if ( pView ) {

SetView( pView );

CHtMapX & m_MapX = pView->GetMapX() ;

m_MapX.CreateCustomTool( MAP_BASICRESOURCE_MOVE_TOOL , miToolTypePoint, miCrossCursor, miCrossCursor, miCrossCursor ,true) ;

return TRUE;

}

return FALSE ;
}

BOOL CBasicResourceMoveTool::OnMapMouseMove(short Button, short Shift,
OLE_XPOS_PIXELS x, OLE_YPOS_PIXELS y)
{
if(!IsCurrentTool()) return FALSE ;

float screenX,screenY ;
double mapX,mapY ;

screenX = x;

screenY = y;

CHtMapX & m_MapX = m_pView->GetMapX() ;

m_MapX.ConvertCoord(&screenX,&screenY,&mapX,&mapY,miScreenToMap);

SelectStyle SelectSet;
CLT_SelectStyle SelectSetList;

SelectSet.LayerName.Format(LAYER_BASICRESOURCE);
SelectSet.SearcheType = miSearchResultPoint;
SelectSet.FeatureType = 0;
SelectSetList.AddTail(SelectSet);

MouseMoveSelectByLayer(m_MapX,mapX,mapY,SelectSetList);
return TRUE;
}

void CBasicResourceMoveTool::OnFinishedTool()
{
if ( !IsCurrentTool() ) return ;
}

void CBasicResourceMoveTool::OnMouseDownMap(short Button, short Shift, float X, float Y)
{
if ( !IsCurrentTool() ) return ;

CHtMapX & m_MapX = m_pView->GetMapX() ;

float screenX,screenY ;
double mapX,mapY ;

screenX = X;

screenY = Y;

m_MapX.ConvertCoord(&screenX,&screenY,&mapX,&mapY,miScreenToMap);

CStringList layerList;
layerList.AddTail( LAYER_BASICRESOURCE );
CMapXFeatures SerachResultFtrs ;
if ( !SerachObjAtPointInLayers( m_MapX , mapX , mapY , layerList , SerachResultFtrs ) )
{
return ;
}

CSelBasicResource selBasicResourceDlg ;
CLT_ResourceShare & ResourceShareList = selBasicResourceDlg.GetResourceShareList();
if(R_FALSE==CMapXModule::GetResourceShares(m_MapX,SerachResultFtrs,ResourceShareList)) return;
if ( IDOK != selBasicResourceDlg.DoModal() ) return ;

TB_ResourceShare ResourceShare = selBasicResourceDlg.GetSelResourceShare();

CMapXDataset dataset;
dataset = m_MapX.GetDatasets().Item( DS_BASICRESOURCE ) ;

CMapXFeature SerachResultFtr = SerachResultFtrs.Item(selBasicResourceDlg.SelIndex+1);
CAdoClientTools& g_AdoTool = ((CMainFrame *)AfxGetMainWnd())->g_AdoTool;
if ( _ADO_SUCCESS_ == g_AdoTool.GetOneRecord(ResourceShare) )
{
CDlgMoveResource dlg;
dlg.m_dblX = ResourceShare.F_Coord_X;
dlg.m_dblY = ResourceShare.F_Coord_Y;
dlg.m_sRsName = ResourceShare.SV_Name;
if(dlg.DoModal() == IDOK)
{
//Update basic resource
m_MapX.GetLayers().Item(LAYER_BASICRESOURCE).SetEditable(TRUE);
SerachResultFtr.Offset(dlg.m_dblX - SerachResultFtr.GetPoint().GetX(),
dlg.m_dblY - SerachResultFtr.GetPoint().GetY());
SerachResultFtr.Update();
ResourceShare.F_Coord_X = dlg.m_dblX;
ResourceShare.F_Coord_Y = dlg.m_dblY;
memset(ResourceShare.IfSkip, true, sizeof(ResourceShare.IfSkip));
ResourceShare.IfSkip[4] = ResourceShare.IfSkip[5] = false;
g_AdoTool.ModifyOneRecord(ResourceShare);
//Update connectors
MoveConnector(ResourceShare.AU_CID, dlg.m_dblX, dlg.m_dblY);
//Update cables
MoveCable(ResourceShare.AU_CID);
m_MapX.GetLayers().Item(LAYER_BASICRESOURCE).SetEditable(FALSE);
ShowSucMsg("��Դ����λ�ɹ�");
}
}
}

void CBasicResourceMoveTool::MoveConnector(int nBrID, double newX, double newY)
{
CHtMapX& MapX = m_pView->GetMapX();
CMapXLayer lyrCur = MapX.GetLayers().Item(LAYER_LINKPOINT);
CString sQuery;
sQuery.Format("ResourceId=%d", nBrID);
CMapXFeatures ftrs = lyrCur.Search(sQuery);
lyrCur.SetEditable(TRUE);
for(int i = 0; i < ftrs.GetCount(); i++)
{
CMapXFeature ftr = ftrs.Item(i+1);
ftr.Offset(newX - ftr.GetPoint().GetX(), newY - ftr.GetPoint().GetY());
ftr.Update();
}
}

void CBasicResourceMoveTool::MoveCable(int nBrID)
{
CLT_CableLineInfo LineInfoList;
CAdoClientTools & g_AdoTool = ((CMainFrame *)AfxGetMainWnd())->g_AdoTool ;
int iResult = g_AdoTool.GetBatchRecord(LineInfoList, 0, nBrID);
if(iResult < 0)
{
TRACE("Get cable line info error!\n");
}
POSITION pos = LineInfoList.GetHeadPosition();
while(pos)
{
TB_CableLineInfo& info = LineInfoList.GetAt(pos);
RefreshCableFeature(info.I_CI_CID);
LineInfoList.GetNext(pos);
}
}

void CBasicResourceMoveTool::RefreshCableFeature(int nCableID)
{
CMapXLayer lyrCable = m_pView->GetMapX().GetLayers().Item(LAYER_CABLE);
CString sQuery;
sQuery.Format("C_ID=%d", nCableID);
CMapXFeatures Searchs = lyrCable.Search(sQuery);
for(int i = 0; i < Searchs.GetCount(); i++)
{
lyrCable.DeleteFeature(Searchs.Item(i+1).GetFeatureKey());
}
lyrCable.Pack(miPackData);
DS_Full_Cable FullCable;
FullCable.MainTable.AU_CID = nCableID;
CMapXFeature ftr;
CAdoClientTools& g_AdoTool = ((CMainFrame *)AfxGetMainWnd())->g_AdoTool;
if(g_AdoTool.GetOneRecord(FullCable) == _ADO_SUCCESS_)
{
CMapXModule::CreateMapxCable(m_pView->GetMapX(), FullCable, ftr);
FullCable.MainTable.F_Cable_Length = ftr.GetLength();
memset(FullCable.MainTable.IfSkip, true, sizeof(FullCable.MainTable.IfSkip));
FullCable.MainTable.IfSkip[2] = false;
if(_ADO_SUCCESS_ != g_AdoTool.ModifyOneRecord(FullCable.MainTable))
{
TRACE("Modify cable length error!\n");
}
}
}

BOOL CBasicResourceMoveTool::IsCurrentTool()
{

if ( !m_pView ) return FALSE ;

CHtMapX & m_MapX = m_pView->GetMapX() ;

if ( m_MapX.GetCurrentTool() != GetToolNum() ) return FALSE;

return TRUE ;
}

Loading Comments...