最近的测量学。
真的是。越来越过分了。计算量超大超大超大超大,作业提交频率贼高,啊这,每次计算的东西都恨不得能把计算器按出火星子。于是本懒人想出一个办法,能不能利用程序,每次只输入一堆数据,就能自动替我算结果?
答案是显而易见的。而且我甚至在脑海里想出了那种及其简便的场景~
步骤一:输入数据
步骤二:看答案
步骤三:美滋滋的看着同学还在按计算器焦头烂额儿,时不时嘲讽下结果算错了。
理想永远是美好的,对吧。
没错,这确实太香了,由于之后的测量学实习是要站在大太阳下面做的,我只想尽快的完成一次计算然后飞奔到凉快的地方。(本人不耐热)
所以一次好好荡荡的敲代码环节就开始了。
运用的语言是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=∑a−∑a理,然后得到改正数
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=−fx∗li/∑l,
v
y
i
=
−
f
y
∗
l
i
/
∑
l
v_{yi}=-f_y*l_i/\sum{l}
vyi=−fy∗li/∑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。就这样了,我要睡了(不是)。