c++ 求解球面距离

【需求规格说明】

1、题目

求解球面距离:
1)地球的平均半径为6371千米,已知地球上两个城市A、B的经度和纬度,编程序求出这两个城市之间的球面距离(一般来说,球面上任意两点A和B都可以与球心确定唯一的大圆,而在大圆上连接这两点的较短的一条弧的长度就是球面距离)。要求:定义坐标点类,地球类。
2)读入武汉市某地区的坐标点数据,输入任意两个点的ID,能够快速计算两点之间的球面距离。
3)输出所求点之间的球面距离到文本文件中。

(注:这里的实验数据 用的是武汉市洪山区的POI数据,大概格式如下图所示,数据量 emm 大概14w+,不知道会不会涉及到什么比较严重的问题,所以 保守起见,我就不全都分享出来了哈哈~😜)
在这里插入图片描述

2、问题描述

本题要求我们求解两点之间的球面距离。
其中第一问要求我们并分别定义坐标点类和地球类用以计算;第二问要求我们读取文件中的信息,并可以通过输入任意两个点的ID实现计算;第三问要求我们把计算得出的信息输入到文本文件中。

3、问题分析

首先对于第一问,我们要定义一个坐标点类,该类应具备x,y两个数据成员变量,我们还要定义一个地球类,该类则是要实现计算两点之间的球面距离,所以该类中就应有计算球面距离的函数;接下来,我们要读取文件中的信息,这里我们就需要用“,”来区分两个数据,此外,文件中的数据我们读取出来都是都是字符串型,为了计算,我们则要把字符串型转换成浮点型,这些都要在主函数中实现;最后,第三问要求我们把计算出的信息输入到文本文件中,那么我们只需在工程文件夹中新建一个文本文件,然后再把计算出的数据输入其中即可。

【算法设计】

1、设计思想

首先第一问要求我们分别定义坐标点类Point和地球点类Earth用以计算。所以在类Point中我们要定义两个成员变量来表示坐标,为方便后续计算球面距离,我们要在Point类里把数据转化成弧度制;在类Earth中定义了三个成员变量,其中有两个point类的对象,和一个常成员变量r,即地球平均半径——6371千米,在类Earth中我们还需定义一个成员函数calc()用以计算球面距离。
其次第二问要求我们读取文件中的信息。所以在主函数里,我先定义了一个动态数组a,用来暂时存储文件中某一行的数据信息;接着我定义了Point类的对象,把数据存放在Point类型的静态数组里,但是由于静态数组存放在栈里容量有限,所以在定义时要new一下把数组存放在堆里;然后我们利用ifstream 来打开文件hubei_wuhan_hongshan_POIs.csv,打开文件后,我们要利用“,”来区分两个数据,这里我利用了(char*)str.c_str()把字符型数据转化成char*型,此外,我们读取到的数据都是字符型,而我们计算都需要用double型,所以我利用atof()函数把字符型数据转化成double型数据。
最后第三问实现计算并把结果输出到文本文件中,这里我们用了文件输出流ofstream,然后用了一个do while循环来判断你是否多次计算,在循环内,利用earth类的对象调用计算球面距离的函数calc()即可。
最后把new的point类型的数组delete掉,完毕。

2、设计表示

在这里插入图片描述
Ps:
1、getradx()和getrady()函数用以把数据转换成弧度制
2、calc()函数用以实现计算球面距离

主函数流程图如下:
在这里插入图片描述

【调试报告】

调试问题1

在完成第一问后,即定义完Point类和Earth类后,我在主函数中分别定义了两个类的对象进行了测试,但是测试结果和老师给的参考数据不一样,后来,经过我的调试以及和同学的讨论,我发现在类Point类中中我们有把数据进行弧度制转化,以至于在套入公式计算时导致计算错误。

调试问题2

在定义Point类型的数组时,我原本直接定义了一个静态数组,形如“ Point p[144593]”,但是在花老师的帮助下,我了解到,由于我们要定义的数据大小较大,而静态数组的存放在栈里,容量有限,所以就要在定义时要new一下,把数据存放在堆里,这样就避免了容量有限而导致内存泄漏的bug。

调试问题3

在语句char p = strtok_s((char)str.c_str(), “,”, &next_token);中,我运用了强制转化,不然运行时一直报错。因为函数str.c_str()是只是把字符型转化成常量char型,而我们要把字符型转化成char型,所以加一个强制转换,用(char*)str.c_str()把字符型数据转化成char*型。

调试问题4

针对语句data = ear.calc(poi[A-1], poi[B-1]);起初我编写的语句是data = ear.calc(poi[A], poi[B]);但是经过数据测试我发现,最后一行(144593行)无法与任意行进行计算,经过调试与思考,我找出了问题所在,由于我将数据储存在数组中,而文件中的第一行对应是是数组中的0,所以我要将数组元素元素减一,这样就可是实现根据文件中的信息进行计算。

【附录】

1、源代码

#include "stdafx.h"
#include<iostream>
#include<math.h>
#include<string>
#include<fstream>
#include<vector>
using namespace std;

double PI = 3.1415926;

class Point{
private:
	double x;
	double y;
public:
	Point(){};
	~Point(){};
	Point(double x, double y) :x(x), y(y){};
	double getradx(){ return abs(x / 180 * PI); };
	double getrady(){ return abs(y / 180 * PI); };
};

class Earth{
public:
	Earth(){};
	~Earth(){};
	Earth(Point p1, Point p2) :p1(p1), p2(p2){};
	double calc(Point p1, Point p2);
private:
	Point p1;
	Point p2;
	const double r = 6371000;
};

double Earth::calc(Point p1, Point p2){
	double cosr;
	double d;
	cosr = cos(p1.getrady())*cos(p2.getrady())*cos(abs(p1.getradx() - p2.getradx())) + sin(p1.getrady())*sin(p2.getrady());
	d = r*acos(cosr);
	return d;
}

int _tmain(int argc, _TCHAR* argv[])
{
	vector<string> a;
	Point *poi = new Point[144593];
	Earth ear;
	string str;
	ifstream myfile("hubei_wuhan_hongshan_POIs.csv");
	char *next_token = NULL;

	for (int i = 0; i < 144593; i++){
		a.clear();
		getline(myfile, str);
		char *p = strtok_s((char*)str.c_str(), ",", &next_token);//(char*)str.c_str()把字符型数据转化成char*型  str.c_str()只有这个是把字符型转化成常量char*型
		while (p != NULL)
		{
			a.push_back(p);
			p = strtok_s(NULL, ",", &next_token);
		}
		poi[i] = Point(atof(a[0].c_str()), atof(a[1].c_str())); //atof()是C++中把字符型数据转化成double型数据的函数
	}
	myfile.close();

	char ch = '0';
	int A, B;
	double data;
	ofstream myfile1("myfile.txt");
	do{
		cout << "请输入需要计算的两个位置的行号(2-144593)" << endl;
		cin >> A >> B;
		data = ear.calc(poi[A-1], poi[B-1]);
		cout <<"计算结果为:"<< data << endl;

		myfile1 <<"第"<<A<<"行与第"<<B<<"行这两点之间的球面距离是:" << data <<"m"<< endl;
		cout << "若继续计算,请输入1" << endl;
		cin >> ch;
	} while (ch == '1');
	cout << "计算结束。" << endl;

	myfile1.close();
	delete[]poi;
	return 0;
}

2、测试数据

测试了两组数据,分别为数据的第一行和最后一行(即文件中的第2行和144593行)(看文件是否能成功读到最后一行)以及4行和72这样任意的两行数据。

3、运行结果

在这里插入图片描述
在这里插入图片描述

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值