目 录
摘 要 I
Abstract 2
1 绪 论 1
1.1 课题背景及意义 1
1.2 国内外研究现状 2
1.3 课题主要研究内容和目的 2
1.4 论文组织结构 3
2 系统需求分析 3
2.1 系统概述 3
2.2 路径规划限制 4
2.3 功能性需求 5
2.4 数据需求 7
2.5 非功能性需求 7
3 A算法概述 9
3.1 A算法基础 9
3.2 A算法详解 12
RELAX-EDGE 13
6. 13
PRINT-PATH(G,s,t) 13
3.2.2 A算法基本流程 13
- INITIALIZE-SOURCE(G,s,t) 13
-
13
- PRINT-PATH(G,s,t) 14
4 系统概要设计 16
4.1 概述 16
4.2 系统总体设计 16
4.3 系统模块设计 18
5 系统详细设计 25
5.1 工程管理设计 25
5.2 约束条件设计 28
5.3 预处理设计 29
5.4 线路规划设计 31
5.5 效果演示设计 37
6 实验结果演示 38
6.1 系统主界面 38
6.2 工程管理功能 38
6.3 约束条件功能 39
6.4 预处理功能 40
6.5 线路规划功能 40
6.6 规划结果演示 41
7 总结与展望 43
7.1 论文主要内容总结 43
7.2 不足与展望 43
参考文献 44
2 系统需求分析
2.1 系统概述
本系统在用户输入的DEM地形数据上按照地理环境和各种选线约束规划出一条最优路径并验证算法的正确性,为方便规划将各种规划约束条件整合到一张组合地图中,系统需要完成的主要任务有:
1)规划环境地形数据的预处理。将用户输入的数据格式转换为程序的内部各式并可视化为一张地图,建立规划威胁区和规划禁止区,并将这些信息写到规划用的组合地图中。电力线路可以通过但是代价较大的区域为威胁区,电力线路绝对不能通过的区域为禁止区。
2)规划约束区域的指定。为方便验证算法的正确性,规划约束区域人为指定。约定威胁区为圆形,禁止区域为矩形,实际情况中约束区域大多为不规则的形状,但是可以将这些形状简化为不规则的多变形。
3)实现规划算法。根据电力线路规划的特殊性和特殊要求在现有国内外路径规划研究的基础上确定一种适合电力线路规划的算法并改进算法,使算法在满足指定线路开始点,结束点和规划约束的条件下,以尽量少的时间规划出一条最优路径。
4)坐标转换。由于DEM数据给出的坐标是地球经纬度,不适合直接在系统中使用,所以必须将其转换系统方便处理的计算机屏幕坐标。
5)演示规划结果。当规划算法规划结束后将规划结果输出到文件保存,系统再从文件中将规划结果读取并显示在地图上以便选线人员分析。
2.2 路径规划限制
电力线路规划需要考虑很多因素,这些因素都对最终的规划结果有影响,在设计系统时必须充分考虑。主要因素有:
1)电力线路禁止进入沼泽地,水草地,盐碱地,炸药厂,鞭炮厂,采石场,采矿区,飞机场,军事禁区以及江河湖海等地区。
2)电力线路应该尽量避免进入村庄,规划区,零星房屋,成片森林等地区。
3)电力线路不能和道路,规划道路,高速公路,铁路,油气管线,输电线路重叠,但是可以交叉。
4)线路在高度上不能超过指定的爬升角度和下滑角度。
5)线路的转弯角度不能超过指定的转弯角度。
6)线路各个塔杆之间有最小距离与最大距离的约束。塔杆之间的距离不得小于最小距离也不得大于最大距离。
综上所述我们可以将规划限制总结为两类:地理限制和线路选择限制。地理限制是指某些地区不能通过,视为禁止区,某些地区应该避免通过但是可以通过,视为威胁区。线路选择限制是指对线路施工的要求,比如某个点的转弯角度不能过大,线路的爬升角度和下滑角度不能过大否则施工和维护难度将会增加或者根本不能施工。
2.3 功能性需求
本系统根据电力线路规划的特点和实际情况,以及规划环境,路径规划条件的限制,在数字高程地图的基础上对地图数据进行预处理,生成系统可以直接使用的地形海拔数据和组合地图数据,然后自动进行规划并对规划结果进行演示和观察。整个系统的结构流程如图2.1所示:
图2.1 系统整体结构流程图
本系统各个模块按照如图2.1所示的流程分工合作最终规划出一条合理的路径。工程管理模块负责打开原始数字高程图并将其可视化;约束条件模块负责指定规划的起止点,禁止区和威胁区;预处理模块负责将禁止区和威胁区的信息写到一张组合地图中并生成规划任务文件;线路规划模块负责根据任务文件和组合地图规划出一条合理路径并输出规划结果;结果演示模块将规划结果显示在可视化地图上。
/************************************************************************/
#include "mainwindow.h"
#include <QtGui>
#include "Coordinates2MapConverter.h"
#include "ReadMapFileOperation.h"
#include "ShortAllocate.h"
#include <cmath>
#include "paraminput.h"
#include "WriteComMapFile.h"
#include "APlanThread.h"
#include "ProgressBarShow.h"
#include "DataConvertThread.h"
#include "ComMapThread.h"
#include "XmlParse.h"
#include "StandardizeConstraint.h"
#include "CDibBitMap.h"
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
{
//初始化
CreateActions();
CreateMenus();
CreateToolBars();
//设置界面标题和图标
setWindowTitle("电力线路规划演示软件");
setWindowIcon(QIcon(":/Resources/system.png"));
//初始化图片显示器
imgVer = new ImageViewer(this);
setCentralWidget(imgVer);
//初始化内存映射大小初始为1400*1400个字节便于调试时观察是否有错误也可增大
memoryViewSize = 1600*1600;
//初始化工具栏菜单栏的状态
//规划线程初始化
athread = new APlanThread;
connect(athread , SIGNAL(finished()) , this , SLOT(APlanThreadFinished()));
//进度条
prgresAPlan = new ProgressBarShow(this);//A*
//数据转换线程
dcThread = new DataConvertThread;
connect(dcThread , SIGNAL(finished()) , this , SLOT(DataConvertThreadFinished()));
//数据转换进度条
prgresDataCvt = new ProgressBarShow(this);
//组合图生成线程
comMapThread = new ComMapThread;
prgresComMap = new ProgressBarShow(this);
connect(comMapThread , SIGNAL(finished()) , this , SLOT(ComMapThreadFinished()));
}
void MainWindow::ComMapThreadFinished()
{
prgresComMap->hide();
prgresComMap->Stop();
//检查线程结束标记
if (isEndThread)
{
comMapThread->errcode = 3;
isEndThread = false;
}
switch(comMapThread->errcode)
{
case 0:
QMessageBox::information(this , "提示" , "组合图生成成功" , QMessageBox::Yes);
break;
case 1:
QMessageBox::information(this , "提示" , "初始化组合图失败" , QMessageBox::Yes);
break;
case 2:
QMessageBox::information(this , "提示" , "生成组合图失败" , QMessageBox::Yes);
break;
case 3:
QMessageBox::information(this , "提示" , "线程被终止!" , QMessageBox::Yes);
break;
default:
QMessageBox::warning(this,"错误","未知类型的错误!");
}
comMapThread->errcode = 0;
}
void MainWindow::DataConvertThreadFinished()
{
prgresDataCvt->hide();
prgresDataCvt->Stop();
//检查线程结束标记
if (isEndThread)
{
dcThread->errcode = 3;
isEndThread = false;
}
switch(dcThread->errcode)
{
case 0:
QMessageBox::information(this , "提示" , "原始数据转换成MAP图成功\n打开此图即可!" , QMessageBox::Yes);
break;
case 1:
QMessageBox::information(this , "提示" , "原始数据转换成MAP图失败!" , QMessageBox::Yes);
break;
case 3:
QMessageBox::information(this , "提示" , "线程被终止!" , QMessageBox::Yes);
break;
default:
QMessageBox::warning(this,"错误","未知类型的错误!");
}
dcThread->errcode = 0;
}
void MainWindow::APlanThreadFinished()
{
//影藏进度条
prgresAPlan->hide();
prgresAPlan->Stop();
//检查线程结束标记
if (isEndThread)
{
athread->errcode = 3;
isEndThread = false;
}
switch(athread->errcode)
{
case 0:
QMessageBox::information(this , "提示" , "A*局部规划完成");
break;
case 1:
QMessageBox::warning(this,"Warning","请打开一个整体规划结果文件!");
break;
case 3:
QMessageBox::information(this , "提示" , "线程被终止!" , QMessageBox::Yes);
break;
case 4:
QMessageBox::information(this , "提示" , "规划失败!" , QMessageBox::Yes);
break;
default:
QMessageBox::warning(this,"错误","未知类型的错误!");
}
athread->errcode = 0;//还原
}
MainWindow::~MainWindow()
{
}
void MainWindow::CreateActions()
{
//数据转换
actOrgDataToMap = new QAction(QIcon(":/Resources/orgtomap.png"), "原始数据转换", this);
actOrgDataToMap->setShortcut(tr("Ctrl+N"));
connect(actOrgDataToMap, SIGNAL(triggered()), this, SLOT(OrgDataToMap()));
//打开工程文件
actOpenMapData = new QAction(QIcon(":/Resources/openmap.png"), "打开MAP文件",this);
actOpenMapData->setShortcut(tr("Ctrl+O"));
connect(actOpenMapData, SIGNAL(triggered()), this, SLOT(OpenMapData()));
//退出系统
actQuit = new QAction(QIcon(":/Resources/quit.png"), "退出系统", this);
actQuit->setShortcut(tr("Ctrl+Q"));
connect(actQuit, SIGNAL(triggered()), this, SLOT(Close()));
//线路规划
actBasicAStarPlan = new QAction(QIcon(":/Resources/baseastar.png"),"基本A*规划", this);
connect(actBasicAStarPlan, SIGNAL(triggered()), this, SLOT(BasicAStarPlan()));
//效果演示
actDisplay = new QAction(QIcon(":/Resources/display.png"),"效果演示", this);
connect(actDisplay, SIGNAL(triggered()), this, SLOT(Display()));
//组合图生成
actCreatComMap = new QAction(QIcon(":/Resources/commap.png"),"组合图生成", this);
connect(actCreatComMap, SIGNAL(triggered()), this, SLOT(CreatComMap()));
//引导A*规划
actGuidAStarPlan = new QAction(QIcon(":/Resources/guidastar.png"),"引导A*规划" , this);
connect(actGuidAStarPlan , SIGNAL(triggered()) , this , SLOT(GuidAStarPlan()));
//关闭工程
actClose = new QAction(QIcon(":/Resources/closepoj.png"),"关闭工程" , this);
connect(actClose , SIGNAL(triggered()) , this , SLOT(CloseProject()));
//画引导点
actGuidPoint = new QAction(QIcon(":/Resources/guidpoint.png"),"添加引导点", this);
connect(actGuidPoint , SIGNAL(triggered()) , this , SLOT(SetGuidPoint()));
//约束图层
actTask = new QAction(QIcon(":/Resources/confile.png"),"加载约束图层", this);
connect(actTask , SIGNAL(triggered()) , this , SLOT(OpenTask()));
}
void MainWindow::GuidAStarPlan()
{
QString fileName = QFileDialog::getOpenFileName(this,"打开需要规划的任务文件",
".\\Task",tr("XML Files (*.XML *.xml)"));
if(fileName.isEmpty())
{
return ;
}
//changed by hj 2013.11.11
athread->fileName = fileName;
athread->IsGuidePlan =true;
athread->start();//线程开始
//显示进度条
prgresAPlan->Start();//计时开始
prgresAPlan->thread = athread;
prgresAPlan->setWindowTitle("A*规划正在进行中,请稍等...");
prgresAPlan->exec();
//将画禁飞区威胁区关闭
imgVer->imgEditor->isForT = -1;
}
void MainWindow::OpenTask()
{
QString fileName = QFileDialog::getOpenFileName(this , "打开约束文件" , ".\\Task\\AutoRouteParameter.xml" , "*.xml;;*.*");
if (fileName.isEmpty())
{
return;
}
XmlParse xml;//将xml文件信息读出
imgVer->imgEditor->forbidAndThreatVector.clear();
if (!xml.readConstrain((char *)fileName.toStdString().c_str() , imgVer->imgEditor->forbidAndThreatVector))
{
QMessageBox::information(this , "提示" , "解析xml文件失败" , QMessageBox::Yes);
return;
}
//读起始点
GroundPoint ptS , ptE;
if (!xml.readETPoint((char *)fileName.toStdString().c_str() , ptS , ptE))
{
return ;
}
StandardizeConstraint standcos;//坐标转换,生成外接矩形
iPoint tmp;
standcos.PointLBToSC(ptS , tmp);
imgVer->imgEditor->start.setX(tmp.x);
imgVer->imgEditor->start.setY(tmp.y);
standcos.PointLBToSC(ptE , tmp);
imgVer->imgEditor->end.setX(tmp.x);
imgVer->imgEditor->end.setY(tmp.y );
//转换坐标
for (int i = 0 ; i < imgVer->imgEditor->forbidAndThreatVector.size() ; i++)
{
standcos.Standardize(imgVer->imgEditor->forbidAndThreatVector[i]);
}
imgVer->imgEditor->update();
XmlFileName = fileName;
}
void MainWindow::SetGuidPoint()
{
//清空容器为引导做准备
imgVer->imgEditor->guidPoint.clear();
imgVer->imgEditor->isForT = 1;
}
void MainWindow::CloseProject()
{
//换一张平凡图
imgVer->imgEditor->SetImage("");
imgVer->imgEditor->isForT = -1;
//关闭先前与图有关的句柄
CloseHandle(G_hGctDataFilemap);
CloseHandle(G_hZhtMapping);
//释放先前的图片内存
imgBuf.Delete();
//初始化工具栏菜单栏的状态
//清理初始点和终点
imgVer->imgEditor->start = QPoint(0 , 0);
imgVer->imgEditor->end = QPoint(0 , 0);
//清空数据
}
void MainWindow::CreateMenus()
{
//工程管理菜单
menuDataConvert = menuBar()->addMenu("数据转换");
menuDataConvert->addAction(actOrgDataToMap);
menuDataConvert->addAction(actOpenMapData);
menuDataConvert->addAction(actClose);
menuDataConvert->addSeparator();
menuDataConvert->addAction(actQuit);
//约束条件菜单
menuConstraintCondition = menuBar()->addMenu("约束条件");
menuConstraintCondition->addAction(actTask);
menuConstraintCondition->addAction(actGuidPoint);
//预处理
menuCreateComMap = menuBar()->addMenu("组合图");
menuCreateComMap->addAction(actCreatComMap);
//线路规划
menuAStarPlan = menuBar()->addMenu("线路规划");
menuAStarPlan->addAction(actBasicAStarPlan);
menuAStarPlan->addAction(actGuidAStarPlan);
//效果演示
menuDisplay = menuBar()->addMenu("效果演示");
menuDisplay->addAction(actDisplay);
}
void MainWindow::CreateToolBars()
{
//主工具栏
toolBar = addToolBar("toolBar");
//数据转换
toolBar->addAction(actOrgDataToMap);
toolBar->addAction(actOpenMapData);
toolBar->addAction(actClose);
toolBar->addSeparator();
//约束条件
toolBar->addAction(actTask);
toolBar->addAction(actGuidPoint);
toolBar->addSeparator();
//生成组合图
toolBar->addAction(actCreatComMap);
toolBar->addSeparator();
//路径规划A*
toolBar->addAction(actBasicAStarPlan);
toolBar->addAction(actGuidAStarPlan);
toolBar->addSeparator();
//效果演示
toolBar->addAction(actDisplay);
toolBar->addSeparator();
//退出系统
toolBar->addAction(actQuit);
toolBar->show();
}
//新建工程即将原始数据转换成map图
void MainWindow::OrgDataToMap()
{
QString fileName = QFileDialog::getOpenFileName(this , "打开原始文件" , ".\\dataorg\\testdata.txt" , "*.txt;;*.*");
if (fileName.isEmpty())
{
return;
}
//将原始数据转换成高程图
QString newFileName = QFileDialog::getSaveFileName(this , "新建MAP文件" , ".\\datamap\\gct.map" , "*.map;;*.*");
if (newFileName.isEmpty())
{
return;
}
//线程开始
dcThread->fileNameOrg = fileName;
dcThread->fileNameNew = newFileName;
dcThread->start();
//显示进度条
prgresDataCvt->Start();//计时开始
prgresDataCvt->thread = dcThread;
prgresDataCvt->setWindowTitle("正在进行数据转换请稍后...");
prgresDataCvt->exec();
}
//打开工程即打开已存在的map图
void MainWindow::OpenMapData()
{
QString fileName = QFileDialog::getOpenFileName(this , "打开MAP文件" , ".\\datamap\\gct.map" , "*.map;;*.*");
if (fileName.isEmpty())
{
return;
}
//关闭先前的工程
CloseProject();
ReadMapFileOperation rmf;
//打开原始文件
if (!rmf.OpenFileByRead(fileName.toStdString().c_str()))
return ;
MapFileHeader mfh;
//读文件头
if (!rmf.ReadMapFileHeader(mfh))
{
QMessageBox::information(this , "提示" , "打开MAP文件失败" , QMessageBox::Yes);
return;
}
rmf.Closefp();
// add by mj at 10-28
// SYSTEM_INFO sinf;
// GetSystemInfo(&sinf);
// G_dwGran = sinf.dwAllocationGranularity; //初始化系统分配粒度
// G_MAPL0 = mfh.xllcorner; // 全局地图左上角的经度
// G_MAPB0 = mfh.yllcorner; // 全局地图左上角的纬度
// G_WIDTH = mfh.nclos; // 全局规划地图的宽度
// G_HEIGHT = mfh.nrows; // 全局规划地图的高度
// G_RESOLVE = mfh.cellsize; //add by hj 2013.10.31
//每次读多少字节
memoryViewSize = mfh.nclos * sizeof(short);
//为地图数据准备内存
CShortAllocate shortBuf;
if (!shortBuf.Allocate(memoryViewSize/sizeof(short)))
{
QMessageBox::information(this , "提示" , "数据过大无法分配内存" , QMessageBox::Yes);
return;
}
APlanning apl;
if(!apl.getMapInfo(fileName.toStdWString().c_str()))
{
QMessageBox::information(this , "提示" , "获取地图信息失败" , QMessageBox::Yes);
return ;
}
// if(!CreateGctDataMap(fileName.toStdWString().c_str() , G_hGctDataFilemap))
// {
// QMessageBox::information(this , "提示" , "创建内存映射失败" , QMessageBox::Yes);
// return;
// }
//cnt计算一共要取多少次
int cnt1 = mfh.nclos*mfh.nrows*sizeof(short)/memoryViewSize;
int t = cnt1 - 1 ;
int dataSize = memoryViewSize;//每次映射的数据长度
//为图片分配临时内存
int extra = 0;
if (mfh.nclos % 4)
{
extra = 4 - mfh.nclos%4;
}
int iImageWidth = mfh.nclos +extra;//对齐
BYTE * pbImageBuf = new BYTE[mfh.nrows*iImageWidth];
if (pbImageBuf == NULL)
{
QMessageBox::information(this , "提示" , "分配地图内存失败" , QMessageBox::Yes);
return ;
}
ZeroMemory(pbImageBuf , mfh.nrows*iImageWidth);
__int64 iDataSizeMore = fileSize - memoryViewSize*cnt1-sizeof(MapFileHeader);
//新图写了多少行
int iNewRows = 0;
while (t >= 0)
{ //逐次读取原始数据
if(!MemoryMapView(G_hGctDataFilemap , sizeof(MapFileHeader) + memoryViewSize*t + iDataSizeMore , dataSize, shortBuf.m_pData))
{
QMessageBox::information(this , "提示" , "读取地图数据失败" , QMessageBox::Yes);
return;
}
//将高程值转换成图片颜色
for (int i = (dataSize/sizeof(short)) / mfh.nclos - 1 ; i >= 0 ; i--)
{
for (int j = 0 ; j < mfh.nclos ; j++)
{
int k = i * mfh.nclos + j;
if (mfh.NODATA_value == shortBuf.m_pData[k] || 0 == shortBuf.m_pData[k])
{
pbImageBuf[iNewRows*iImageWidth + j] = 0;
}
else
{
UCHAR fillData = fabs((/*log10*/((double)shortBuf.m_pData[k]-mfh.sMin+1)*255/ /*log10*/((double)mfh.sMax-mfh.sMin+1)));
pbImageBuf[iNewRows*iImageWidth + j] = fillData;
}
}
iNewRows++;
}
t--;
}