一个企图用代码偷懒计算测量学闭合导线各项数据的屑是否有错
最近的测量学。
真的是。越来越过分了。计算量超大超大超大超大,作业提交频率贼高,啊这,每次计算的东西都恨不得能把计算器按出火星子。于是本懒人想出一个办法,能不能利用程序,每次只输入一堆数据,就能自动替我算结果?
答案是显而易见的。而且我甚至在脑海里想出了那种及其简便的场景~
步骤一:输入数据
步骤二:看答案
步骤三:美滋滋的看着同学还在按计算器焦头烂额儿,时不时嘲讽下结果算错了。
理想永远是美好的,对吧。
没错,这确实太香了,由于之后的测量学实习是要站在大太阳下面做的,我只想尽快的完成一次计算然后飞奔到凉快的地方。(本人不耐热)
所以一次好好荡荡的敲代码环节就开始了。
运用的语言是C语言,主要是按照测量学的计算步骤来划分的函数模块。
测量学的原理
这次计算的是导线闭合差,所以一切标准按照导线闭合差来算。
1、根据已知角以及各个观测角(右角)计算出各个点的坐标方位角a=a后+180°−a右a=a_后+180^{\degree}-a_右a=a后+180°−a右。
2、根据闭合多边形内角和原理,计算出实际测量值和理论值之间的误差f=∑a−∑a理f=\sum{a}-\sum{a_理}f=∑a−∑a理,然后得到改正数v=−f/nv=-f/nv=−f/n,再重新分配到每个角上,得到正确的角值。当然,不排除会有测量的角值误差超过限差的情况,因为现在是作业所需嘛,所以…
3、再由各个边的长度和坐标方位角知道各个点之间的坐标偏移值Δx=lcosa,Δy=lsina\Delta x=lcosa,\Delta y=lsinaΔx=lcosa,Δy=lsina。但是,这个坐标偏移值同样需要矫正。∑Δx理=∑Δy理=0\sum{\Delta x_理}=\sum{\Delta y_理}=0∑Δx理=∑Δy理=0。所以根据这个我们就可以获得误差值fx,fyf_x,f_yfx,fy。改正数vxi=−fx∗li/∑lv_{xi}=-f_x*l_i/\sum{l}vxi=−fx∗li/∑l,vyi=−fy∗li/∑lv_{yi}=-f_y*l_i/\sum{l}vyi=−fy∗li/∑l,根据权重分配的误差值。同样再加上,才是真正的坐标偏移值。
4、通过起始点加上各个坐标偏移值得到各点坐标。
数据结构的提取
通过以上的问题,提取出了三种数据:
点,距离,角度。
尤其是角度,度分秒制转换贼头疼。给出以下几种数据结构,皆为带表头的单链表。
点:
距离:
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;接下来就是把上面的步骤变成函数分解了。再次我直接把我做的三个头文件按照顺序给出。
点
线
#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。
然后在主函数的使用部分:
这就很简单的完成了上面的步骤(指做了一天一夜,昨晚凌晨三点睡的)。
很庆幸学过数据结构,对指针计算各种值都可以有很好的理解,不然面对这么恐怖的数据,我也不可能做下去了.jpg。
学生党的乐趣或许就在这里吧,这一套API可以继续扩建,毕竟基础的数据结构完成,剩下的只是算法的实现了,每次实现都会比上次简单不少,随着时间不断完善。而我现在只是吧最艰难的开头先摆出来了,至于后其的完善,或许会更新在这里的吧hhh。就这样了,我要睡了(不是)。
总结
以上是生活随笔为你收集整理的一个企图用代码偷懒计算测量学闭合导线各项数据的屑是否有错的全部内容,希望文章能够帮你解决所遇到的问题。
- 上一篇: 简述导线平差计算的五个步骤_结点导线如何
- 下一篇: 闭合导线平差计算(表面)