一个企图用代码偷懒计算测量学闭合导线各项数据的屑是否有错

最近的测量学。
真的是。越来越过分了。计算量超大超大超大超大,作业提交频率贼高,啊这,每次计算的东西都恨不得能把计算器按出火星子。于是本懒人想出一个办法,能不能利用程序,每次只输入一堆数据,就能自动替我算结果?
答案是显而易见的。而且我甚至在脑海里想出了那种及其简便的场景~
步骤一:输入数据
在这里插入图片描述
步骤二:看答案
在这里插入图片描述
步骤三:美滋滋的看着同学还在按计算器焦头烂额儿,时不时嘲讽下结果算错了。
在这里插入图片描述
理想永远是美好的,对吧。
没错,这确实太香了,由于之后的测量学实习是要站在大太阳下面做的,我只想尽快的完成一次计算然后飞奔到凉快的地方。(本人不耐热)
所以一次好好荡荡的敲代码环节就开始了。
运用的语言是C语言,主要是按照测量学的计算步骤来划分的函数模块。
测量学的原理
这次计算的是导线闭合差,所以一切标准按照导线闭合差来算。
1、根据已知角以及各个观测角(右角)计算出各个点的坐标方位角 a = a 后 + 18 0 ° − a 右 a=a_后+180^{\degree}-a_右 a=a+180°a
2、根据闭合多边形内角和原理,计算出实际测量值和理论值之间的误差 f = ∑ a − ∑ a 理 f=\sum{a}-\sum{a_理} f=aa,然后得到改正数 v = − f / n v=-f/n v=f/n,再重新分配到每个角上,得到正确的角值。当然,不排除会有测量的角值误差超过限差的情况,因为现在是作业所需嘛,所以…
3、再由各个边的长度和坐标方位角知道各个点之间的坐标偏移值 Δ x = l c o s a , Δ y = l s i n a \Delta x=lcosa,\Delta y=lsina Δx=lcosa,Δy=lsina。但是,这个坐标偏移值同样需要矫正。 ∑ Δ x 理 = ∑ Δ y 理 = 0 \sum{\Delta x_理}=\sum{\Delta y_理}=0 Δx=Δy=0。所以根据这个我们就可以获得误差值 f x , f y f_x,f_y fx,fy。改正数 v x i = − f x ∗ l i / ∑ l v_{xi}=-f_x*l_i/\sum{l} vxi=fxli/l, v y i = − f y ∗ l i / ∑ l v_{yi}=-f_y*l_i/\sum{l} vyi=fyli/l,根据权重分配的误差值。同样再加上,才是真正的坐标偏移值。
4、通过起始点加上各个坐标偏移值得到各点坐标。
数据结构的提取
通过以上的问题,提取出了三种数据:
点,距离,角度。
尤其是角度,度分秒制转换贼头疼。给出以下几种数据结构,皆为带表头的单链表。

typedef struct Point
{
	double x;
	double y;
	Point* Next;
}Point;

typedef struct Points
{
	Point* Head;
	int Length;
}Points;

距离

typedef struct DistNode
{
	double dist;
	DistNode* Next;
}DistNode;

typedef struct Dist
{
	DistNode* Head;
	int Length;
}Dist;

角度(度分秒制)

typedef enum {Left,Right} Dir;
typedef struct Angle
{
	double Origin;
	int Degree;
	int Min;
	int Sec;
}Angle;

typedef struct AngleNode
{
	Angle A;
	Dir dir;
	AngleNode* Next;
}AngleNode;

typedef struct Angles
{
	AngleNode* Head;
	int Length;
}Angles;

接下来就是把上面的步骤变成函数分解了。再次我直接把我做的三个头文件按照顺序给出。

#include<stdio.h>
#include<stdlib.h>
#include"Dist.h"
typedef struct Point
{
	double x;
	double y;
	Point* Next;
}Point;

typedef struct Points
{
	Point* Head;
	int Length;
}Points;

Points* InitPoints()
{
	Points *p;
	Point* q;
	p=(Points*)malloc(sizeof(Points));
	q=(Point*)malloc(sizeof(Point));
	q->x=0;
	q->y=0;
	p->Head=q;
	q->Next=NULL;
	p->Length=0;
	return p;
}

bool InsertPoints(Points* PS,Point *p)
{
	Point* point;
	Point* q;
	point=p;
	q=PS->Head;
	while(q->Next)
	{
		q=q->Next;
	}
	point->Next=q->Next;
	q->Next=point;
	PS->Length++;
	printf("Inserted Point.\n");
	return true;
}

bool GetPoints(Points* PS)//从键盘获取若干点
{
	Point* D;
	printf("Input Points.Stop by input x or y larger than 10000\n");
	while(true)
	{
		D=(Point*)malloc(sizeof(Point));
		scanf("%lf,%lf",&D->x,&D->y);
		if(D->x>10000)
		{
			free(D);
			break;
		}
		InsertPoints(PS,D);
	}
	printf("GetPoints...\n");
	return true;
}

bool CountModP(Points *PS)//计算闭合导线坐标偏差
{
	Point* q=PS->Head->Next;
	double x=0;
	double y=0;
	while(q)
	{
		x+=q->x;
		y+=q->y;
		q=q->Next;
	}
	PS->Head->x=x;
	PS->Head->y=y;
	return true;
}

bool CountModPoints(Points *PS,Dist* DS)//改正坐标增量
{
	Point* p=PS->Head->Next;
	DistNode* d=DS->Head->Next;
	while(d)
	{
		p->x-=(d->dist*PS->Head->x)/DS->Head->dist;
		p->y-=(d->dist*PS->Head->y)/DS->Head->dist;
		p=p->Next;
		d=d->Next;
	}
	return true;
}

bool CountPointsByPC(Points *PS,Points *Change)//通过坐标增量计算坐标值
{
	Point *p,*q,*point;
	point=PS->Head->Next;
	q=Change->Head->Next;
	while(q)
	{
		p=(Point*)malloc(sizeof(Point));
		p->x=point->x+q->x;
		p->y=point->y+point->y;
		InsertPoints(PS,p);
		q=q->Next;
		point=point->Next;
	}
	printf("Counted Location\n");
	return true;
}

bool DisplayPoints(Points* PS)
{
	Point* p;
	p=PS->Head->Next;
	while(p)
	{
		printf("x:%lf,y:%lf\n",p->x,p->y);
		p=p->Next;
	}
	return true;
}

线

#ifndef _DIST_H
#define _DIST_H
#include<stdio.h>
#include<stdlib.h>

typedef struct DistNode
{
	double dist;
	DistNode* Next;
}DistNode;

typedef struct Dist
{
	DistNode* Head;
	int Length;
}Dist;

Dist* InitDist()
{
	Dist *p;
	DistNode* q;
	p=(Dist*)malloc(sizeof(Dist));
	q=(DistNode*)malloc(sizeof(DistNode));
	p->Head=q;
	q->dist=0;
	q->Next=NULL;
	p->Length=0;
	return p;
}

bool InsertDists(Dist* DS,double D)//插入边长
{
	DistNode* p=(DistNode*)malloc(sizeof(DistNode));
	DistNode* q;
	p->dist=D;
	q=DS->Head;
	while(q->Next)
	{
		q=q->Next;
	}
	p->Next=q->Next;
	q->Next=p;
	DS->Length++;
	printf("Inserted.\n");
	return true;
}

bool GetDists(Dist* DS)//从键盘获取若干边长
{
	double* D;
	printf("Input Dists.Stop by input Dist smaller than 0\n");
	while(true)
	{
		D=(double*)malloc(sizeof(double));
		scanf("%lf",D);
		if(*D<=0)
		{
			free(D);
			break;
		}
		InsertDists(DS,*D);
	}
	printf("GetDists...\n");
	return true;
}

bool SumDist(Dist* DS)
{
	DistNode* d;
	d=DS->Head->Next;
	while(d)
	{
		DS->Head->dist+=d->dist;
		d=d->Next;
	}
	printf("Summed Dist\n");
	return true;
}
#endif

角度(不要问我为什么角度会有这么多,其实我自己实现的时候变复杂了,本来只需要做出度分秒和小数点制互换就好了的)

#include<stdio.h>
#include<stdlib.h>
#include<math.h>
#include"Dist.h"
#include"Point.h"
#define RAD 3.1415936/180
//涉及到的是观测角的计算和矫正,同时涉及到坐标方位角的计算
//其中观测角的和会放入带表头的链表的第一个,坐标方位角的已知角也会放在第一个
typedef enum {Left,Right} Dir;
typedef struct Angle
{
	double Origin;
	int Degree;
	int Min;
	int Sec;
}Angle;

typedef struct AngleNode
{
	Angle A;
	Dir dir;
	AngleNode* Next;
}AngleNode;

typedef struct Angles
{
	AngleNode* Head;
	int Length;
}Angles;

Angle CreateAngle(int Degree,int Min,int Sec)
{
	Angle angle;
	angle.Degree=Degree;
	angle.Min=Min;
	angle.Sec=Sec;
	angle.Origin=angle.Degree+((double)angle.Min)/60+((double)angle.Sec)/3600;
	return angle;
}

Angle Aadd(Angle A,Angle B)//角度加法
{
	Angle angle;
	angle.Degree=A.Degree+B.Degree;
	angle.Min=A.Min+B.Min;
	if(angle.Min>=60)
	{
		angle.Degree++;
		angle.Min-=60;
	}
	angle.Sec=A.Sec+B.Sec;
	if(angle.Sec>=60)
	{
		angle.Min++;
		angle.Sec-=60;
		if(angle.Min>=60)
		{
			angle.Degree++;
			angle.Min-=60;
		}
	}
	angle.Origin=A.Origin+B.Origin;
	if(angle.Origin>360)
	{
		angle.Origin-=360;
		angle.Degree-=360;
	}
	if(angle.Origin>0)
	{
		if(angle.Sec<0)
		{
			angle.Sec+=60;
			angle.Min--;
		}
		if(angle.Min<0)
		{
			angle.Min+=60;
			angle.Degree--;
		}
	}
	return angle;
}

Angle Amin(Angle A,Angle B)//角度减法
{
	Angle angle;
	if(A.Origin>B.Origin)
	{
		angle.Sec=A.Sec-B.Sec;
		if(angle.Sec<0)
		{
			angle.Sec+=60;
			A.Min--;
		}
		angle.Min=A.Min-B.Min;
		if(angle.Min<0)
		{
			angle.Min+=60;
			A.Degree--;
		}
		angle.Degree=A.Degree-B.Degree;
	}
	else
	{
		angle.Sec=B.Sec-A.Sec;
		if(angle.Sec<0)
		{
			angle.Sec+=60;
			B.Min--;
		}
		angle.Min=B.Min-A.Min;
		if(angle.Min<0)
		{
			angle.Min+=60;
			B.Degree--;
		}
		angle.Degree=B.Degree-A.Degree;
		angle.Degree=0-angle.Degree;
		angle.Min=0-angle.Min;
		angle.Sec=0-angle.Sec;
	}
	angle.Origin=A.Origin-B.Origin;
	return angle;
}

Angle ADiv(Angle A,int D)
{
	Angle angle;
	angle.Sec=((A.Min+A.Degree%D*60)%D*60+A.Sec)/D;
	angle.Min=(A.Min+A.Degree%D*60)/D;
	angle.Degree=A.Degree/D;
	angle.Origin=A.Origin/D;
	return angle;
}

Angles* InitAngles()//初始化角链表
{
	AngleNode* p=(AngleNode*)malloc(sizeof(AngleNode));
	Angles* AS=(Angles*)malloc(sizeof(Angles));
	p->Next=NULL;
	AS->Head=p;
	AS->Length=0;
	printf("Init Angles.\n");
	return AS;
}

bool InsertAngles(Angles* AS,Angle A)//插入角度
{
	AngleNode* p=(AngleNode*)malloc(sizeof(AngleNode));
	AngleNode* q;
	p->A=A;
	q=AS->Head;
	while(q->Next)
	{
		q=q->Next;
	}
	p->Next=q->Next;
	q->Next=p;
	AS->Length++;
	printf("Inserted.\n");
	return true;
}

bool GetAngles(Angles* AS)//从键盘获取若干角度
{
	Angle* angle;
	printf("Input Angles.Stop by input Degree larger than 360\n");
	while(true)
	{
		angle=(Angle*)malloc(sizeof(Angle));
		scanf("%d,%d,%d",&angle->Degree,&angle->Min,&angle->Sec);
		if(angle->Degree>360)
		{
			free(angle);
			break;
		}
		angle->Origin=angle->Degree+((double)angle->Min)/60+((double)angle->Sec)/3600;
		InsertAngles(AS,*angle);
	}
	printf("GetAngles...\n");
	return true;
}

bool CountSum(Angles* AS)//计算总角和
{
	AngleNode* p=AS->Head->Next;
	Angle angle;
	angle.Degree=0;
	angle.Min=0;
	angle.Sec=0;
	angle.Origin=0;
	while(p)
	{
		angle.Degree+=p->A.Degree;
		angle.Min+=p->A.Min;
		if(angle.Min>=60)
		{
			angle.Min-=60;
			angle.Degree++;
		}
		angle.Sec+=p->A.Sec;
		if(angle.Sec>=60)
		{
			angle.Sec-=60;
			angle.Min++;
			if(angle.Min>=60)
			{
				angle.Min-=60;
				angle.Degree++;
			}
		}
		angle.Origin+=p->A.Origin;
		p=p->Next;
	}
	AS->Head->A=angle;
	printf("Counted AngleSum\n");
	return true;
}

Angle CountModA(Angles* AS)//计算改正数
{
	Angle A;
	Angle B;
	B.Degree=(AS->Length-2)*180;
	B.Min=0;
	B.Sec=0;
	B.Origin=B.Degree;
	CountSum(AS);
	A=Amin(AS->Head->A,B);
	return ADiv(A,AS->Length);
}

bool CountModAngle(Angles* AS)//计算改正后的各个角度
{
	AngleNode* p;
	p=AS->Head->Next;
	Angle Mod=CountModA(AS);
	while(p)
	{
		p->A=Amin(p->A,Mod);
		p=p->Next;
	}
	printf("Get Modified Angles\n");
	return true;
}
bool CountDirectAngle(Angles* AS,Angles* LOCA)//计算方位角
{
	if(LOCA->Head->A.Degree<0||LOCA->Head->A.Degree>360)
	{
		printf("You didn't init the locationangles.\n");
		exit(1);
	}
	AngleNode* p,*q;
	Angle n;
	Angle B;//180常量角
	B.Degree=180;
	B.Min=0;
	B.Sec=0;
	B.Origin=B.Degree;
	q=LOCA->Head;
	p=AS->Head->Next;
	while(p)//把计算出来的方位角插入
	{
		n=Amin(Aadd(q->A,B),p->A);//后角加180减去右角,适用于右角
		if(n.Degree>=360)
		{
			n.Degree-=360;
			n.Origin-=360;
		}
		if(n.Origin<0)
		{
			Angle a;
			a.Degree=360;
			a.Min=0;
			a.Sec=0;
			a.Origin=a.Degree;
			n=Aadd(n,a);
		}
		//printf("%d°%d′%d″ %lf\n",n.Degree,n.Min,n.Sec,n.Origin);
		InsertAngles(LOCA,n);
		q=q->Next;
		p=p->Next;
	}
	printf("Counted dir.\n");
	return true;
}
bool CountLOCbyAngle(Angles* AS,Dist* D,Points* PC)//计算各点坐标值增量
{
	AngleNode* angle;
	DistNode* dist;
	Point* point,*p;
	angle=AS->Head->Next;
	dist=D->Head->Next;
	while(angle)
	{
		point=(Point*)malloc(sizeof(Point));
		point->x=D->Head->Next->dist*cos(angle->A.Origin*RAD);
		point->y=D->Head->Next->dist*sin(angle->A.Origin*RAD);
		InsertPoints(PC,point);
		angle=angle->Next;
		dist=dist->Next;
	}
	printf("Counted Location Change\n");
	return true;
}

bool DisplayAngles(Angles* AS)
{
	AngleNode* p;
	p=AS->Head->Next;
	while(p)
	{
		printf("%d°%d′%d″ %lf\n",p->A.Degree,p->A.Min,p->A.Sec,p->A.Origin);
		p=p->Next;
	}
	return true;
}

以上就是已经亲测过使用的头文件,大概可以被称作api了吧hhh。
然后在主函数的使用部分:

#include<stdio.h>
#include<stdlib.h>
#include"Angle.h"
int main()
{
	Angles* AS,*LOCA;
	//Angle angle;
	//angle.Degree=100;
	//angle.Min=23;
	//angle.Sec=23;
	Angle angle;
	Dist *DS;
	Points *PS,*PC;
	AS=InitAngles();
	LOCA=InitAngles();
	DS=InitDist();
	PS=InitPoints();
	PC=InitPoints();
	LOCA->Head->A=CreateAngle(123,2,33);
	LOCA->Length++;
	//InsertAngles(AS,angle);
	GetAngles(AS);
	GetDists(DS);
	GetPoints(PS);

	//angle=Aadd(AS->Head->Next->A,AS->Head->Next->Next->A);
	//InsertAngles(AS,angle);
	DisplayAngles(AS);
	CountModAngle(AS);
	DisplayAngles(AS);
	CountDirectAngle(AS,LOCA);
	DisplayAngles(LOCA);

	CountLOCbyAngle(LOCA,DS,PC);
	printf("Origin Location Change:\n");
	DisplayPoints(PC);
	CountModP(PC);
	SumDist(DS);
	CountModPoints(PC,DS);	
	printf("Modified Location Change:\n");
	DisplayPoints(PC);
	CountPointsByPC(PS,PC);
	printf("Modified Location:\n");
	DisplayPoints(PS);
	return 0;
}

这就很简单的完成了上面的步骤(指做了一天一夜,昨晚凌晨三点睡的)。
很庆幸学过数据结构,对指针计算各种值都可以有很好的理解,不然面对这么恐怖的数据,我也不可能做下去了.jpg。
学生党的乐趣或许就在这里吧,这一套API可以继续扩建,毕竟基础的数据结构完成,剩下的只是算法的实现了,每次实现都会比上次简单不少,随着时间不断完善。而我现在只是吧最艰难的开头先摆出来了,至于后其的完善,或许会更新在这里的吧hhh。就这样了,我要睡了(不是)。

  • 3
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值