一个企图用代码偷懒计算测量学闭合导线各项数据的屑是否有错
最近的測量學。
真的是。越來越過分了。計算量超大超大超大超大,作業提交頻率賊高,啊這,每次計算的東西都恨不得能把計算器按出火星子。于是本懶人想出一個辦法,能不能利用程序,每次只輸入一堆數據,就能自動替我算結果?
答案是顯而易見的。而且我甚至在腦海里想出了那種及其簡便的場景~
步驟一:輸入數據
步驟二:看答案
步驟三:美滋滋的看著同學還在按計算器焦頭爛額兒,時不時嘲諷下結果算錯了。
理想永遠是美好的,對吧。
沒錯,這確實太香了,由于之后的測量學實習是要站在大太陽下面做的,我只想盡快的完成一次計算然后飛奔到涼快的地方。(本人不耐熱)
所以一次好好蕩蕩的敲代碼環節就開始了。
運用的語言是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。就這樣了,我要睡了(不是)。
總結
以上是生活随笔為你收集整理的一个企图用代码偷懒计算测量学闭合导线各项数据的屑是否有错的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 简述导线平差计算的五个步骤_结点导线如何
- 下一篇: 闭合导线平差计算(表面)