内容简介
本文主要内容包括本人编写附和导线平差程序的过程及附和导线平差程序源代码,在此记录,以供有兴趣的朋友参考学习。
过程简介
最近学习《C#(注:读音为C sharp)程序设计》这门课时,老师布置了一个设计导线平差程序的作业,一直在学python,好久没用类C语言了,很是头大,好在参考博主:流浪猪头拯救地球的一系列文章,终于是将程序编写出来。
(2020/12/7:初始版本优点是方便上手,缺点是还有很多地方可以优化,下一版本将在不久后更新,coding……)
程序源码
附和导线平差C#程序工程文件及用于测试的文本已上传至附和导线平差C#程序。
此程序一共用到三个类库,分别是矩阵类Matrix、点类Point、角类Angle。
矩阵类Matrix
此类库代码量过大,无法放入博文中,有兴趣的话可以从C#矩阵类库下载。
点类Point
using System;
using System.IO;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;//与PointF 联系起来了
namespace work //这里改成和您的namespace 名字一样即可
{
public class Point
{
//Define fields
public string name;
public double x; //coordinate
public double y;
public double z;
public string Name
{
get {
return name; } set {
name = value; } }
public double X
{
get {
return x; } set {
x = value; } }
public double Y
{
get {
return y; } set {
y = value; } }
public double Z
{
get {
return z; } set {
z = value; } }
//The constructor
public Point(double x = 0, double y = 0, double z = 0, string name = "0")
{
//构造函数1,将一串数据传到一个 Point 中
this.name = name;
this.x = x;
this.y = y;
this.z = z;
}
public Point(string[] sArry, int mod = 0)
{
//构造函数2,重载 Point函数,将一个字符串数组传到 Point 中
//mod 1带名字,0 不带名字,默认不带名字
int n = sArry.Length;
if (mod == 1)
{
this.name = sArry[0];
this.x = double.Parse(sArry[1]);
this.y = double.Parse(sArry[2]);
if (n < 4)
this.z = 0;
else
this.z = double.Parse(sArry[3]);
}
else
{
this.x = double.Parse(sArry[0]);
this.y = double.Parse(sArry[1]);
if (n < 3)
this.z = 0;
else
this.z = double.Parse(sArry[2]);
}
}
public Point(Point p1, double s, Angle a)
{
//构造函数3 已知基点,边长,方位角,求另一个点
this.x = p1.x + s * a.cos;
this.y = p1.y + s * a.sin;
this.z = p1.z;
this.name = "0";
}
public Point(PointF p1)
{
//构造函数4 将 PointF 转化为 Point, 需要using System.Drawing;
this.x = p1.X;
this.y = p1.Y;
this.z = 0;
this.name = "0";
}
public Point Add(Point p2)
{
//两点相加
return new Point(this.x + p2.x, this.y + p2.y, this.z + p2.z);
}
public Point Sub(Point p2)
{
//两点相减
return new Point(this.x - p2.x, this.y - p2.y, this.z - p2.z);
}
public Point Mut(double d)
{
//点与数相乘
return new Point(this.x * d, this.y * d, this.z * d);
}
public Point Div(double d)
{
//点与数相除
return new Point(this.x / d, this.y / d, this.z / d);
}
public double Dis(Point p2)
{
//求距离
return Math.Sqrt((this.x - p2.x) * (this.x - p2.x) + (this.y - p2.y) *
(this.y - p2.y) + (this.z - p2.z) * (this.z - p2.z));
}
public Angle getAn(Point p2)
{
//以此点为基点,得到其到另一个点的坐标方位角
return new Angle(arctan(this.x - p2.x, this.y - p2.y));
}
public bool IsClose0(Point p2)
{
//判断 其与p2 哪个和(0,0)更接近
if (Math.Abs(this.x) < Math.Abs(p2.x) &&
Math.Abs(this.y) < Math.Abs(p2.y) &&
Math.Abs(this.x) < Math.Abs(p2.x))
return true;
else
return false;
}
public static int find_Close0(Point[] p)
{
//找出一个点数组中最接近(0,0)的下标
int n = p.Length, index = 0;
for (int i = 1; i < n; i++)
{
if (p[i].IsClose0(p[index]))
index = i;
}
return index;
}
/*此函数用于求象限角
* 返回的是弧度,取值范围为[0,2*pi)
*/
public static double arctan(double dx, double dy)
{
double angle = 0;
if (dx == 0)
{
if (dy > 0) angle = Math.PI * 0.5;
else angle = Math.PI * 1.5;
return angle;
}
angle = Math.Atan2(Math.Abs(dy), Math.Abs(dx));
if (dx < 0)
{
if (dy < 0) angle = Math.PI + angle;
else angle = Math.PI - angle;
}
else if (dy < 0) angle = 2 * Math.PI - angle;
return angle;
}
public void show()
{
//打印出点坐标
Console.WriteLine("X {0:f3}, Y {1:f3}, Z {2:f3}, Name {3}", this.x, this.y, this.z, this.name);
}
public double Dis2To0()
{
//到原点距离的平方
return this.x * this.x + this.y * this.y + this.z * this.z;
}
public static Point[] ZXH(Point[] pt)
{
//坐标重心化,最后一个点存重心坐标
int n = pt.Length;
Point[] po = new Point[n + 1];
double x0 = 0, y0 = 0, z0 = 0;
for (int i = 0; i < n; i++)
{
x0 += pt[i].x;
y0 += pt[i].y;
z0 += pt[i].z;
}
x0 /= n; y0 /= n; z0 /= n;
for (int i = 0; i < n; i++)
{
po[i] = new Point();
po[i].name = pt[i].name;
po[i].x = pt[i].x - x0;
po[i].y = pt[i].y - y0;
po[i].z = pt[i].z - z0;
}
po[n] = new Point(x0, y0, z0, "ZX");
return po;
}
//重载一些操作符
public static Point operator +(Point m1, Point m2) {
return m1.Add(m2); }
public static Point operator -(Point m1, Point m2) {
return m1.Sub(m2); }
public static Point operator *(Point m1, double d) {
return m1.Mut(d); }
public static Point operator *(double d, Point m1) {
return m1.Mut(d); }
public static Point operator /(Point m1, double d) {
return m1.Div(d); }
//public static Point operator =(Point m1) {}
}
}
角类Angle
using System;
using System.Collections.Generic;
using System.Text;
//using work;
namespace work
{
public class Angle
{
//角类
public int d; //coordinate
public int f;
public double m;
public double ad;
public double rad;
public int D
{
get {
return d; } set {
d = value; } }
public int F
{
get {
return f; } set {
f = value; } }
public double M
{
get {
return m; } set {
m = value; } }
public double Rad
{
get {
return rad; } set {
rad = value; } }
public double Ad
{
get {
return ad; } set {
ad = value; } }
public double sin//正弦
{
get {
return Math.Sin(this.rad); } }
public double cos//余弦
{
get {
return Math.Cos(this.rad); } }
public double tan//正切
{
get {
return Math.Tan(this.rad); } }
public double csc//余割
{
get {
return 1 / Math.Sin(this.rad); } }
public double sec//正割
{
get {
return 1 / Math.Cos(this.rad); } }
public double cot//余切
{
get {
return 1 / Math.Tan(this.rad); } }
//The constructor 构造函数
public Angle(int d = 0, int f = 0, double m = 0)
{
//构造函数1,将一串数据传到一个 Angle 中,顺便算出弧度
this.d = d;
this.f = f;
this.m = m;
this.rad = (d + f / 60.0 + m / 3600) * Math.PI / 180;
this.ad = this.rad * 180 / Math.PI;
}
public Angle(double rad)
{
//构造函数2,将弧度传到一个 Angle 中,顺便算出度分秒
this.rad = rad; rad = rad / Math.PI * 180;//度
this.d = (int)rad; rad -= this.d; rad *= 60;//分
this.f = (int)rad; rad -= this.f; rad *= 60;//秒
this.m = rad;
this.ad = this.rad * 180 / Math.PI;
}
public Angle(string[] sArray)
{
//构造函数3,将字符数组传到一个 Angle 中,顺便算出弧度
this.d = int.Parse(sArray[0]);
this.f = int.Parse(sArray[1]);
this.m = double.Parse(sArray[2]);
this.rad = (d + f / 60.0 + m / 3600) * Math.PI / 180;
this.ad = this.rad * 180 / Math.PI;
}
public Angle(Angle other)
{
//拷贝构造函数
rad = other.rad;
d = other.d;
f = other.f;
m = other.m;
this.ad = this.rad * 180 / Math.PI;
}
public Angle(string str)
{
//构造函数4,将字符串传到一个 Angle 中,顺便算出弧度
string[] sArry = str.Split(new string[] {
" ", ",", ".", "°", "'", "\"" }, StringSplitOptions.RemoveEmptyEntries);
this.d = int.Parse(sArry[0]);
this.f = int.Parse(sArry[1]);
this.m = double.Parse(sArry[2]);
this.rad = (d + f / 60.0 + m / 3600) * Math.PI / 180;
this.ad = this.rad * 180 / Math.PI;
}
//运算函数
public Angle Add(Angle other)
{
Angle result = new Angle(this);
result.rad += other.rad;
result.rad = result.rad % (Math.PI * 2);
return new Angle(result.rad);
}
public Angle Subtract(Angle other)
{
Angle result = new Angle(this);
result.rad -= other.rad;
//result.rad = (result.rad + 2 * Math.PI) % (Math.PI * 2);
return new Angle(result.rad);
}
public Angle Multiply(double d)
{
Angle result = new Angle(this);
result.rad *= d;
result.rad = result.rad % (Math.PI * 2);
return new Angle(result.rad);
}
public Angle Divide(double d)
{
Angle result = new Angle(this);
result.rad /= d;
result.rad = result.rad % (Math.PI * 2);
return new Angle(result.rad);
}
public string ToString(string sDelim = null)
{
//将角转化为字符串,sDelim是分隔符,默认'°′″'
if (sDelim == null)
return d.ToString() + "°" + f.ToString() + "'" + Math.Round(m, 1).ToString() + "\"";
else return d.ToString() + sDelim + f.ToString() + sDelim + Math.Round(m, 1).ToString();
}
public void show()
{
//打印出点坐标
Console.WriteLine("D {0:d3}, F {1:d3}, M {2:f3}", this.d, this.f, this.m);
}
//重载运算符
public static Angle operator +(Angle m1, Angle m2) {
return m1.Add(m2); }
public static Angle operator -(Angle m1, Angle m2) {
return m1.Subtract(m2); }
public static Angle operator -(Angle m1) {
return new Angle(-m1.rad); }
public static Angle operator *(double d, Angle m1) {
return m1.Multiply(d); }
public static Angle operator *(Angle m1, double d) {
return m1.Multiply(d); }
public static Angle operator /(Angle m1, double d) {
return m1.Divide(d); }
public static Angle operator %(Angle m1, Angle m2) {
return new Angle(m1.rad % m2.rad); }
public static bool operator >(Angle m1, Angle m2) {
return m1.rad > m2.rad; }
public static bool operator <(Angle m1, Angle m2) {
return m1.rad < m2.rad; }
public static bool operator ==(Angle m1, Angle m2) {
return m1.rad == m2.rad; }
public static bool operator >=(Angle m1, Angle m2) {
return m1.rad >= m2.rad; }
public static bool operator <=(Angle m1, Angle m2) {
return m1.rad <= m2.rad; }
public static bool operator !=(Angle m1, Angle m2) {
return m1.rad != m2.rad; }
//旋转矩阵
public Matrix R2
{
//返回此角的二维旋转矩阵:数学坐标系顺时针旋转此角度
get
{
Matrix result = new Matrix(2, 2);
result[0, 0] = this.cos; result[0, 1] = this.sin;
result[1, 0] = -this.sin; result[1, 1] = this.cos;
return result;
}
}
public Matrix Rx
{
//返回此角的旋转矩阵:绕x轴顺时针旋转此角度
get
{
Matrix result = new Matrix(3, 3);
result[0, 0] = 1; result[0, 1] = 0; result[0, 2] = 0;
result[1, 0] = 0; result[1, 1] = this.cos; result[1, 2] = this.sin;
result[2, 0] = 0; result[2, 1] = -this.sin; result[2, 2] = this.cos;
return result;
}
}
public Matrix Ry
{
//返回此角的旋转矩阵:绕y轴顺时针旋转此角度
get
{
Matrix result = new Matrix(3, 3);
result[0, 0] = this.cos; result[0, 1] = 0; result[0, 2] = -this.sin;
result[1, 0] = 0; result[1, 1] = 1; result[1, 2] = 0;
result[2, 0] = this.sin; result[2, 1] = 0; result[2, 2] = this.cos;
return result;
}
}
public Matrix Rz
{
//返回此角的旋转矩阵:绕z轴顺时针旋转此角度
get
{
Matrix result = new Matrix(3, 3);
result[0, 0] = this.cos; result[0, 1] = this.sin; result[0, 2] = 0;
result[1, 0] = -this.sin; result[1, 1] = this.cos; result[1, 2] = 0;
result[2, 0] = 0; result[2, 1] = 0; result[2, 2] = 1;
return result;
}
}
}
}
主程序
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Threading.Tasks;
using System.Linq;
using System.Data.OleDb;
using work;
//测站类
public class GPoint
{
//Define fields
public Point pt;
public double s;//观测角(弧度表示),边长
public Angle an;//观测角
public Point Pt
{
get {
return pt; } set {
pt = value; } }
public Angle An
{
get {
return an; } set {
an = value; } }
public double S
{
get {
return s; } set {
s = value; } }
//The constructor
public GPoint(double h = 0, double s = 0, string name = "0", double x = 0, double y = 0, double z = 0)
{
//构造函数1
this.pt = new Point(x, y, z, name);
this.an = new Angle(h);
this.s = s;
}
public GPoint(Point pt, Angle an, double s)
{
//构造函数2
this.pt = pt;
this.an = an;
this.s = s;
}
//public GPoint(string[] sArry)
//{//构造函数3,将字符数组传到一个 GPoint 中,顺便算出弧度
// this.an.d = int.Parse(sArry[0]);
// this.an.f = int.Parse(sArry[1]);
// this.an.m = double.Parse(sArry[2]);
// this.an.rad = (an.d + an.f / 60.0 + an.m / 3600) * Math.PI / 180;
// this.an.ad = this.an.rad * 180 / Math.PI;
//}
}
public class Read
{
/*用sDelim 将str 分割成字符串数组
* @sDelim 可选参数,分隔符
*/
public static string[] Split(string str, string sDelim = null)
{
if (sDelim == null)//默认分割
return str.Split(new string[] {
" ", ",", "?", "->", " ", "\t" }, StringSplitOptions.RemoveEmptyEntries);
else//根据传入参数分割
return str.Split(new string[] {
sDelim }, StringSplitOptions.RemoveEmptyEntries);
}
/*得到一个文本文件的行数
*/
public static int getTextRows(string txt)
{
int n = 0;
StreamReader sR = new StreamReader(txt);
string str = sR.ReadLine();
while (str != null)
{
if (Split(str) != null) n++;
str = sR.ReadLine();
}
sR.Close();
return n;
}
/*读取txt至点数组中
*/
public static Point[] T2Po(string txt)
{
int i = 0, n = getTextRows(txt);
Point[] Pt = new Point[n];
StreamReader sR = new StreamReader(txt);
string str = sR.ReadLine();
while (str != null)
{
string[] sArray = Split(str);
if (sArray != null)
{
Point pt = new Point(sArray, 1);
Pt[i] = pt; i++;
}
str = sR.ReadLine();
}
sR.Close();
return Pt;
}
public static Angle[] T2An(string txt)
{
int i = 0, n = getTextRows(txt);
Angle[] Pt = new Angle[n];
StreamReader sR = new StreamReader(txt);
string str = sR.ReadLine();
while (str != null)
{
string[] sArray = Split(str);
if (sArray != null)
{
Angle pt = new Angle(sArray);
Pt[i] = pt; i++;
}
str = sR.ReadLine();
}
sR.Close();
return Pt;
}
public static double[] T2S(string txt)
{
int i = 0, n = getTextRows(txt);
double[] Pt = new double[n];
StreamReader sR = new StreamReader(txt);
string str = sR.ReadLine();
while (str != null)
{
string[] sArray = Split(str);
if (sArray != null)
{
double pt = double.Parse(sArray[0]);
Pt[i] = pt; i++;
}
str = sR.ReadLine();
}
sR.Close();
return Pt;
}
//public static GPoint[] T2GP(string txt)
//{
// int i = 0, n = getTextRows(txt);
// GPoint[] Pt = new GPoint[n];
// StreamReader sR = new StreamReader(txt);
// string str = sR.ReadLine();
// while (str != null)
// {
// string[] sArray = Split(str);
// if (sArray != null)
// {
// GPoint pt = new GPoint(sArray);
// Pt[i] = pt; i++;
// }
// str = sR.ReadLine();
// }
// sR.Close();
// return Pt;
//}
}
public class DXPC //导线平差
{
public static GPoint[] FHDX(GPoint[] data,Angle an1,Angle an2)//附和导线平差,an1、an2分别为始边、终边方位角
{
//Angle d360 = new Angle(360, 0, 0);
Angle d180 = new Angle(180, 0, 0);
Angle a = an1;
Angle b;
Angle fb;//角度闭合差
int n = data.Length;
Angle[] c= new Angle[n];
double[] dx = new double[n];//增量
double[] dy = new double[n];
double[] ddx = new double[n];//改正量
double[] ddy = new double[n];
double fx, fy, ex, ey;
double sums = 0;//导线全长
double fs;//全长闭合差
for (int i = 0;i < n;i++)//计算角度闭合差
{
a = data[i].an + a;
if(a>d180)
{
a = a - d180;
}
else
{
a = a + d180;
}
}
b = (an2 - a) / n;
fb = (an2 - a);
//fb.show();
a = an1;
for (int i = 0; i < n; i++)//进行角度改正
{
data[i].an = data[i].an + b;
a = data[i].an + a;
if (a > d180)
{
a = a - d180;
}
else
{
a = a + d180;
}
c[i] = a;
//a.show();
}
fx = data[0].pt.x;
fy = data[0].pt.y;
ex = data[n - 1].pt.x;
ey = data[n - 1].pt.y;
for (int i = 0; i < n-1; i++)//计算坐标增量及x、y方向的导线闭合差及导线全长
{
dx[i] = data[i].s * c[i].cos;
dy[i] = data[i].s * c[i].sin;
fx = fx + dx[i];
fy = fy + dy[i];
sums = sums + data[i].s;
}
fs = Math.Sqrt((ex - fx) * (ex - fx) + (ey - fy) * (ey - fy));//全长闭合差
for (int i = 0; i < n - 1; i++)//计算改正量并对增量改正
{
ddx[i] = (ex - fx) * data[i].s / sums;
ddy[i] = (ey - fy) * data[i].s / sums;
dx[i] = dx[i] + ddx[i];
dy[i] = dy[i] + ddy[i];
}
for (int i = 0; i < n - 1; i++)//计算最终坐标
{
data[i + 1].pt.x = data[i].pt.x + dx[i];
data[i + 1].pt.y = data[i].pt.y + dy[i];
}
if ((1.0 / (sums / fs) < 1.0 / 4000) && (Math.Abs(fb.rad) < new Angle(0, 0, 40 * Math.Sqrt(n)).rad))
//检测是否符合限差
{
Console.WriteLine("符合限差");
}
else
{
Console.WriteLine("不符合限差");
Console.WriteLine("fs:{0};sums:{1};fb:{2}", fs, sums, fb.m);
}
return data;
}
}
namespace Test2017
{
class Program
{
static void Main(string[] args)
{
string fo1 = @"C:\Users\Dr.z\Desktop\HTML\point.txt";
string fo2 = @"C:\Users\Dr.z\Desktop\HTML\angle.txt";
string fo3 = @"C:\Users\Dr.z\Desktop\HTML\s.txt";
Point[] po = Read.T2Po(fo1);//这里我是把T2Po放到一个Read类里面了。
Angle[] an = Read.T2An(fo2);
double[] s = Read.T2S(fo3);
int n = po.Length;
GPoint[] gpo = new GPoint[n];
for (int i = 0; i < n; i++)
{
gpo[i] = new GPoint(po[i],an[i],s[i]);
}
gpo = DXPC.FHDX(gpo, new Angle(298, 59, 12), new Angle(182, 10, 45));
for(int i = 0;i<n;i++)
{
gpo[i].pt.show();
}
Console.Read();
}
}
}