地图导航系统

一饭多吃.jpg
放个最初版本,A*求最短路

#include "Logger.h"
#include "ColorUtils.h"
#include "ImgUtils.h"
#include<graphics.h>
#include<windows.h>
#include<iostream>
#include<conio.h>
#include<cstdio>
#include<cmath>
#include<queue>
#include <thread>
#define DIS_PERCENT 1.2
#define WALK_PERCENT 65
#define INF 1000
using namespace std;
unsigned int unWidth = 0, unHeight = 0;
const double sqrt2 = sqrt(2.0);
IMAGE Map;
int lu[2333][2333], vis[2333][2333];
double dis[2333][2333];
string lastInf;
bool selected = false;

void mapToSpot()
{
	memset(lu, 0, sizeof(lu));
	for (int i = 0; i < unWidth; ++i)
		for (int j = 0; j < unHeight; ++j)
			if (ColorUtils::isTarget(i, j))lu[i][j] = 1;
}
struct dian
{
	int x, y;
	double dis_from, dis_to;
	friend bool operator <(const dian& a, const dian& b)
	{
		return a.dis_from + a.dis_to > b.dis_from + b.dis_to;
	}
}from[2333][2333];//用来找回来的路径
priority_queue<dian>q;
int dx[10] = { 0,-1,-1,1,1,-1,0,0,1 };
int dy[10] = { 0,-1,1,-1,1,0,-1,1,0 };
void DIJ(int X1, int Y1, int X2, int Y2)
{
	while (!q.empty())q.pop();
	memset(from, 0, sizeof(from));
	memset(vis, 0, sizeof(vis));
	for (int i = 0; i < unWidth; ++i)
		for (int j = 0; j < unHeight; ++j) dis[i][j] = 114514;
	
	dian now, to; double tmp_dis; now.x = X1; now.y = Y1; now.dis_from = 0;
	dis[now.x][now.y] = 0;
	q.push(now);
	bool flag = false;
	while (!q.empty() && !flag)
	{	
		now = q.top(); q.pop();
		if (vis[now.x][now.y])continue; vis[now.x][now.y] = 1;
		setfillcolor(RGB(255, 0, 0));
		solidcircle(now.x, now.y, 1);
		for (int i = 1; i <= 8; ++i)
		{
			to.x = now.x + dx[i]; to.y = now.y + dy[i];
			if (i <= 4)tmp_dis = now.dis_from + sqrt2;
			else tmp_dis = now.dis_from + 1.0;
			if (to.x < 0 || unWidth <= to.x || to.y < 0 || unHeight <= to.y || lu[to.x][to.y] == 0 || dis[to.x][to.y] <= tmp_dis)continue;
			dis[to.x][to.y] = tmp_dis; to.dis_from = tmp_dis;
			
			//Sleep(2);//用来展示寻路过程

			to.dis_to = sqrt((double)(X2 - to.x) * (X2 - to.x) + (Y2 - to.y) * (Y2 - to.y));
			from[to.x][to.y] = now;
			q.push(to);
			if (to.x == X2 && to.y == Y2) flag = true;
		}
	}
	now.x = X2; now.y = Y2;
	int prepts[5000] = { 0 };
	putimage(0, 0, &Map);
	while (now.x != X1 || now.y != Y1)
	{
		//Sleep(2);
		setfillcolor(RGB(0, 0, 255));
		solidcircle(now.x, now.y, 2);
		now = from[now.x][now.y];
	}
}

ExMessage m1, m2, m3;
void watch() 
{
	if (!selected) 
	{
		cin >> m1.x >> m1.y;
		cin >> m2.x >> m2.y;
		selected = true;
	}
}

void showMouse() 
{
	while (1) 
	{
		ExMessage m;
		if (peekmessage(&m)) 
		{
			setfillcolor(BLACK);
			solidrectangle(0, 0, 170, 30);
			setfillcolor(RGB(255, 0, 0));
			string ch = "Mouse: " + to_string(m.x) + ' ' + to_string(m.y);
			if (ColorUtils::isTarget(m.x, m.y)) 
			{
				ch += " Yes";
			}
			else 
			{
				ch += " No";
			}
			int num = MultiByteToWideChar(0, 0, ch.c_str(), -1, NULL, 0);
			wchar_t* wide = new wchar_t[num];
			MultiByteToWideChar(0, 0, ch.c_str(), -1, wide, num);
			outtextxy(0, 0, wide);
		}
	}
}

int main()
{

	ImgUtils::GetPicWidthHeight("./ChangZhou.png", &unWidth, &unHeight);
	initgraph(unWidth, unHeight, EW_SHOWCONSOLE);
	setlinestyle(PS_SOLID | PS_ENDCAP_FLAT | PS_JOIN_BEVEL, 3);
	loadimage(&Map, _T(".\\ChangZhou.png"));
	putimage(0, 0, &Map);
	Logger::logInfo("预处理地图中...");
	mapToSpot();
	Logger::logSuccess("加载完毕!可以开始选点了!");
	thread mouse(showMouse);
	mouse.detach();
	while (1) 
	{
		selected = false;
		setfillcolor(RGB(255, 0, 0));
		thread input(watch);
		input.detach();
		while (!selected)
		{
			if (peekmessage(&m1)) 
			{
				if (m1.message == WM_LBUTTONDOWN && ColorUtils::isTarget(m1.x, m1.y)) 
				{
					solidcircle(m1.x, m1.y, 4);
					if (m1.ctrl != true) break;
				}
			}
		}
		lastInf = "第一个点的坐标为: " + to_string(m1.x);
		lastInf += "  " + to_string(m1.y);
		Logger::logInfo(lastInf);
		while (!selected)
		{
			if (peekmessage(&m2)) 
			{
				if (m2.message == WM_LBUTTONDOWN && ColorUtils::isTarget(m2.x, m2.y)) 
				{
					solidcircle(m2.x, m2.y, 4);
					selected = true;
					break;
				}
			}
		}
		lastInf = "第二个点的坐标为: " + to_string(m2.x);
		lastInf += "  " + to_string(m2.y);
		Logger::logInfo(lastInf);

		double dur;
		clock_t start, end;
		start = clock();
		Logger::logInfo("Starting A*...");
		DIJ(m1.x, m1.y, m2.x, m2.y);
		end = clock();
		dur = (double)(end - start);
		Logger::logSuccess("Use Time: " + to_string(dur / CLOCKS_PER_SEC));
		while (1)
		{
			if (peekmessage(&m3)&& m3.message == WM_LBUTTONDOWN)break;
		}
		putimage(0, 0, &Map);
	}
	return 0;
}

最新版本

#include "Logger.h"
#include "ImgUtils.h"
#include<graphics.h>
#include<windows.h>
#include<iostream>
#include<conio.h>
#include<cstdio>
#include<cmath>
#include<queue>
#include <thread>
#define DIS_PERCENT 1.2
#define WALK_PERCENT 65
#define INF 1000
using namespace std;
unsigned int unWidth = 0, unHeight = 0;
const double sqrt2 = sqrt(2.0);
IMAGE Map;
int tot,cnt;
int lu[2333][2333], vis[2333 * 2333], headEdge[2333 * 2333],from[2333 * 2333],id[2333][2333],wei[2333 * 2333][2];
double dis[2333* 2333];
string lastInf;
bool selected = false;
struct dian
{
	int hao;double dis_from,dis_to;
	friend bool operator <(const dian& a, const dian& b) { return a.dis_from+ a.dis_to > b.dis_from+b.dis_to; }//A*找最短路
};
priority_queue<dian>q;
struct bian
{
	int to, nt; double len;
}e[1000000];

void addEdge(int x, int y, double len)//链式前向星存边 其实可以不存边的,这样做是为了以后方便拓展功能
{
	e[++tot].to = y; e[tot].len = len; e[tot].nt = headEdge[x]; headEdge[x] = tot;
}
bool isTarget(int x, int y)//根据像素颜色判断是不是路
{
	COLORREF col = getpixel(x, y);
	int r = GetRValue(col),g = GetGValue(col),b = GetBValue(col);
	if (r > 250 && g > 250 && b > 250)return true;
	else return false;
}
void mapToGraph()//将像素转化为图论中点
{
	memset(lu, 0, sizeof(lu));
	for (int i = 0; i < unWidth; ++i)
		for (int j = 0; j < unHeight; ++j)
			if (isTarget(i, j))lu[i][j] = 1;//判断是不是路
	for (int i = 0; i < unWidth; ++i)
		for (int j = 0; j < unHeight; ++j)id[i][j] = ++cnt,wei[cnt][0]=i,wei[cnt][1]=j;//给每个像素编一个号
	int tox, toy;
	for (int x = 0; x < unWidth; ++x)
		for (int y = 0; y < unHeight; ++y)
			for(int dx = -1;dx <= 1; ++dx)
				for (int dy = -1; dy <= 1; ++dy)
				{
					tox = x + dx; toy = y + dy;
					if (x == tox && y == toy)continue;
					if (tox < 0 || unWidth <= tox || toy < 0 || unHeight <= toy || lu[tox][toy] == 0 )continue;
					addEdge(id[x][y], id[tox][toy], abs(dx) + abs(dy) == 2 ? sqrt2 : 1.0);//图论加边
				}
}

void DIJ(int X1, int Y1, int X2, int Y2)//堆优化DIJ
{
	while (!q.empty())q.pop();
	memset(from, 0, sizeof(from));
	memset(vis, 0, sizeof(vis));
	for (int i = 1; i <= cnt; ++i)dis[i] = 114514;//初始化
	
	double tmp_dis; int nowId; dian nowDian;
	dis[id[X1][Y1]] = 0;
	nowDian.hao = id[X1][Y1]; nowDian.dis_from = 0; nowDian.dis_to = 0; q.push(nowDian);

	while (!q.empty())
	{	
		nowId = q.top().hao; q.pop();//取堆顶
		if (vis[nowId])continue; vis[nowId] = 1;
		if (wei[nowId][0]==X2&& wei[nowId][1]==Y2)break;
		
		//setfillcolor(RGB(255, 0, 0));solidcircle(wei[nowId][0], wei[nowId][1], 1);//画一下寻路过程
		//Sleep(1);//取消这句话的注释可以看清楚寻路过程
		for (int i = headEdge[nowId]; i; i = e[i].nt)
		{
			if (dis[e[i].to] > dis[nowId] + e[i].len)//更新最短路
			{
				dis[e[i].to] = dis[nowId] + e[i].len;
				nowDian.hao = e[i].to; nowDian.dis_from = dis[e[i].to]; nowDian.dis_to = sqrt((double)(X2 - wei[e[i].to][0]) * (X2 - wei[e[i].to][0]) + (Y2 - wei[e[i].to][1]) * (Y2 - wei[e[i].to][1]));; q.push(nowDian);
				from[e[i].to] = nowId;
			}
		}
	}
	nowId = id[X2][Y2];
	putimage(0, 0, &Map);
	while (nowId != id[X1][Y1])//把路程画出来
	{
		//Sleep(2);
		setfillcolor(RGB(0, 0, 255));
		solidcircle(wei[nowId][0], wei[nowId][1], 2);
		nowId = from[nowId];
	}
}

ExMessage m1, m2, m3;
void watch() 
{
	if (!selected) 
	{
		cin >> m1.x >> m1.y;
		cin >> m2.x >> m2.y;
		selected = true;
	}
}
int cntJing;
struct jingdian
{
	int l, r, u, d;
	string jieshao;
}jing[233];
void jingInit()
{
	jing[++cntJing].l = 216;  jing[cntJing].r = 309; jing[cntJing].u = 451; jing[cntJing].d = 470; jing[cntJing].jieshao = "    青枫公园——是个集“生态、科普、活力”三大主题于一身的城市森林公园,与常州市钟楼区政府隔街相望,位置得天独厚,依托运河、白鹤河、童子河而建,不仅是广大市民休闲健身的适宜场所,也是展示常州城市形象的重要窗口。";
	jing[++cntJing].l = 365;  jing[cntJing].r = 521; jing[cntJing].u = 498; jing[cntJing].d = 514; jing[cntJing].jieshao = "    龙城天街是龙湖集团在全国布局的主要商业地产品牌,定位为面向中等收入新兴家庭的区域型购物中心,是集购物、餐饮、休闲、娱乐等多业态的一站式商业综合体。随着天街品牌化运营,未来龙湖天街将成为越来越多城市转念即达的欢乐入口。";
	jing[++cntJing].l = 605;  jing[cntJing].r = 746; jing[cntJing].u = 731; jing[cntJing].d = 747; jing[cntJing].jieshao = "    中天钢铁体育馆位于清潭路、劳动路和广化街的交界处,南倚清潭荆川居民区,北临市中心区域繁华商业街,东西两翼均为商铺云集,人流量密集路段。体育中心下辖常州市体育馆和常州市人民体育场,是常州市中心的标志性建筑。";
	jing[++cntJing].l = 830;  jing[cntJing].r = 918; jing[cntJing].u = 244; jing[cntJing].d = 261; jing[cntJing].jieshao = "    万达广场包含大型购物中心、五星级酒店、国际电影城、室内外步行街、餐饮娱乐风情街等多种业态的大型城市综合体,打造常州首个集购物、餐饮、文化、娱乐、商务、休闲等多种业态于一体的大型城市商业中心";
	jing[++cntJing].l = 919;  jing[cntJing].r = 1024;   jing[cntJing].u = 17;  jing[cntJing].d = 32; jing[cntJing].jieshao = "    江南环球港分成环球广场,太阳大厅,花园中庭和世界港口小镇四个区域,集“文、旅、商”三大中心功能于一体,是长三角“集大成”之超级商业航母。江南环球港是一个文旅商全面发展的新型综合体,涵盖了吃住行游购娱的旅游全产业链。";
	jing[++cntJing].l = 1100; jing[cntJing].r = 1205; jing[cntJing].u = 186; jing[cntJing].d = 200; jing[cntJing].jieshao = "    中华恐龙园是常州市环球恐龙城休闲旅游区的一部分,也是一座集科普、游乐、演艺、住宿、购物于一体的主题乐园,有“东方侏罗纪”之称。由七大主题区域组成,分别是魔幻雨林、库克苏克、中华恐龙馆、鲁布拉、梦幻庄园、冒险港、疯狂恐龙人。";
	jing[++cntJing].l = 864; jing[cntJing].r = 950; jing[cntJing].u = 687; jing[cntJing].d = 702; jing[cntJing].jieshao = "    红梅公园分三区八景。在公园的南部是文物古迹区,有红梅阁和文笔塔;在公园的西北部是娱乐活动区,有运动场、春晖茶室、青少年活动场所、游艇、听松楼和舞厅;在公园的东部是科普教育区,有动物园、盆景园、月季园和屠一道根艺藏珍馆等。";
	jing[++cntJing].l = 897; jing[cntJing].r = 968; jing[cntJing].u = 765; jing[cntJing].d = 780; jing[cntJing].jieshao = "    东坡园,是苏东坡当年弃舟登岸入城之地。舣舟亭位于园内南山顶,亭不大但造型精美,乾隆皇帝下江南时,亲笔题“玉局风流”匾额。公园内绕过曲廊,豁然开朗,林木蔚秀,水石清奇,呈现出我国古典园林风格。大运河绕园东流,使其更富江南景色";
	jing[++cntJing].l = 1146; jing[cntJing].r = 1236; jing[cntJing].u = 517; jing[cntJing].d = 532; jing[cntJing].jieshao = "    紫荆公园以东经一百二十度经线这一地理特色为建设主题。这条线线是“北京时间”的基准经线,而常州是该经线唯一穿越城区的地级市。这条线将紫荆公园、中华恐龙园串联在一起,共同构筑了一条集旅游、生态、科普于一体的旅游线路。";
	jing[++cntJing].l = 907; jing[cntJing].r = 967; jing[cntJing].u = 259; jing[cntJing].d = 294; jing[cntJing].jieshao = "    河海大学常州校区,位于常州国家级高新技术产业开发区,与常州市行政中心毗邻,是河海大学具有较完整办学功能的重要组成部分,是学校建设高水平特色研究型大学的重要力量";
	jing[++cntJing].l = 1031; jing[cntJing].r = 1133; jing[cntJing].u = 259; jing[cntJing].d = 290; jing[cntJing].jieshao = "    常州工学院,位于江苏省常州市,是江苏省主管的一所全日制普通本科院校,入选国家“十三五”产教融合发展工程立项高校和首批启动高校,教育部和江苏省卓越工程师教育培养计划试点高校,江苏省服务外包人才培养试点高校。";
}
void showString(int posX,int posY,string s)
{
	int num = MultiByteToWideChar(0, 0, s.c_str(), -1, NULL, 0);
	wchar_t* wide = new wchar_t[num];
	MultiByteToWideChar(0, 0, s.c_str(), -1, wide, num);
	outtextxy(posX, posY, wide);
}
void showMouse() 
{
	while (1) 
	{
		ExMessage m;
		if (peekmessage(&m)) 
		{
			setfillcolor(BLACK);
			solidrectangle(0, 0, 170, 30);
			setfillcolor(RGB(255, 0, 0));
			string ch = "Mouse: " + to_string(m.x) + ' ' + to_string(m.y);
			if (isTarget(m.x, m.y)) ch += " Yes";
			else ch += " No";
			showString(0, 0, ch); ch = "                                                      ";
			for (int i = 1; i <= 9;++i)showString(0, i*15, ch);
			
			for (int i = 1; i <= cntJing; ++i)//在左上角输出景点信息
				if (jing[i].l <= m.x && m.x <= jing[i].r && jing[i].u <= m.y && m.y <= jing[i].d)
				{
					int nowStringPos = 0,hang,j;
					for (hang = 1;; ++hang)
					{
						ch = "";
						for (j= nowStringPos; j < jing[i].jieshao.length(); ++j)
						{
							ch += jing[i].jieshao[j];
							if (j - nowStringPos == 25)break;//25字节换一行
						}
						nowStringPos = j+1;
						showString(0, hang*15, ch);
						if (nowStringPos >= jing[i].jieshao.length())break;
					}
				}
		}
	}
}

int main()
{

	ImgUtils::GetPicWidthHeight("./ChangZhou.png", &unWidth, &unHeight);
	initgraph(unWidth, unHeight, EW_SHOWCONSOLE);
	setlinestyle(PS_SOLID | PS_ENDCAP_FLAT | PS_JOIN_BEVEL, 3);
	loadimage(&Map, _T(".\\ChangZhou.png"));
	putimage(0, 0, &Map);
	Logger::logInfo("预处理地图中...");
	mapToGraph(); jingInit();
	Logger::logSuccess("加载完毕!可以开始选点了!");
	thread mouse(showMouse);
	mouse.detach();
	while (1) 
	{
		selected = false;
		setfillcolor(RGB(255, 0, 0));
		thread input(watch);
		input.detach();
		while (!selected)
		{
			if (peekmessage(&m1)) 
			{
				if (m1.message == WM_LBUTTONDOWN && isTarget(m1.x, m1.y)) 
				{
					solidcircle(m1.x, m1.y, 4);
					if (m1.ctrl != true) break;
				}
			}
		}
		lastInf = "第一个点的坐标为: " + to_string(m1.x);
		lastInf += "  " + to_string(m1.y);
		Logger::logInfo(lastInf);
		while (!selected)
		{
			if (peekmessage(&m2)) 
			{
				if (m2.message == WM_LBUTTONDOWN && isTarget(m2.x, m2.y)) 
				{
					solidcircle(m2.x, m2.y, 4);
					selected = true;
					break;
				}
			}
		}
		lastInf = "第二个点的坐标为: " + to_string(m2.x);
		lastInf += "  " + to_string(m2.y);
		Logger::logInfo(lastInf);

		double dur;
		clock_t start, end;
		start = clock();
		Logger::logInfo("Starting A*...");
		DIJ(m1.x, m1.y, m2.x, m2.y);
		end = clock();
		dur = (double)(end - start);
		Logger::logSuccess("Use Time: " + to_string(dur / CLOCKS_PER_SEC));
		while (1)
		{
			if (peekmessage(&m3)&& m3.message == WM_LBUTTONDOWN)break;
		}
		putimage(0, 0, &Map);
	}
	return 0;
}
posted @ 2023-05-26 23:08  wljss  阅读(33)  评论(0编辑  收藏  举报