【c#窗体】一篇文章学会编写空间前方交会小程序


1、前言

空间前方交会,是指恢复立体像对摄影时的光束和建立几何模型后,利用同名光线的交会确定模型点空间位置的方法。这篇文章使用c#编写窗体程序,实现了一个空间前方交会的小程序,可以实现以下三个功能:


1. 数据文件的导入与手动输入
2.空间前方交会计算
3.计算报告与示意图的生成


2、主要算法

Step1: 导入文本数据,包含两张相片的内外方位元素
Step2: 计算两个像点的像空间辅助坐标
Step3:获取两个投影系数
Step4:得到地面点的摄影测量坐标


3、变量介绍与函数说明

3.1. 结构类与计算类说明

3.1.1 结构类变量说明

代码如下(示例):

class data //存储相片的内外方位元素
{
public string name;// 名字
public double x, y, f, XS, YS, ZS, fai, omega, keppa;// x,y,f内方位元素,其余为外方位元素
}
class fuzhu // 存储像点的像空间辅助坐标
{
public double u, v, w;
}
class pm  // 存储地面点的摄影测量坐标
{
public double X, Y, Z;
}

3.1.2 计算类函数说明

代码如下(示例):

1.将角度转化为弧度

/// <summary>

/// 将角度转化为弧度

/// </summary>

/// <param name="angle"></param>

/// <returns></returns>

public static double du_hudu(double angle)

{

return angle *
Math.PI / 180;

}

 

2.利用内外方位元素计算像空间辅助坐标

/// <summary>

/// 利用内外方位元素计算像空间辅助坐标

/// </summary>

/// <param name="d1"></param>

/// <param name="fz1"></param>

public static void cal_fuzhu(data d1,
fuzhu fz1)

{

// 将三个角度转化为弧度制

double fai =
du_hudu(d1.fai);

double omege =
du_hudu(d1.omega);

double keppa =
du_hudu(d1.keppa);

// 计算旋转矩阵的九个系数

double a1 =
Math.Cos(fai) * Math.Cos(keppa) - Math.Cos(fai) * Math.Sin(omege) *
Math.Sin(keppa);

double
a2=-Math.Cos(fai)*Math.Sin(keppa)-Math.Sin(fai) * Math.Sin(omege) *
Math.Sin(keppa);

double a3 =
-Math.Sin(fai) * Math.Cos(omege);

double b1 =
Math.Sin(keppa) * Math.Cos(omege);

double b2 =
Math.Cos(keppa) * Math.Cos(omege);

double b3 =
-Math.Sin(omege);

double
c1=Math.Sin(fai)*Math.Cos(keppa)+ Math.Cos(fai) * Math.Sin(omege) *
Math.Sin(keppa);

double
c2=-Math.Sin(omege)*Math.Cos(keppa)+ Math.Cos(fai) * Math.Sin(omege) *
Math.Sin(keppa);

double c3 =
Math.Cos(fai) * Math.Cos(omege);

// 计算像空间辅助坐标

fz1.u = a1 * d1.x + a2 * d1.y + a3 *
d1.f;

fz1.v = b1 * d1.x + b2 * d1.y + b3 *
d1.f;

fz1.w = c1 * d1.x + c2 * d1.y + c3 *
d1.f;

}

3.利用线元素和辅助坐标计算两个投影系数

/// <summary>

/// 利用线元素和辅助坐标计算两个投影系数

/// </summary>

/// <param name="d1"></param>

/// <param name="d2"></param>

/// <param name="fz1"></param>

/// <param name="fz2"></param>

/// <param name="N1"></param>

/// <param name="N2"></param>

public static void cal_xishu(data d1,
data d2, fuzhu fz1, fuzhu fz2, ref double N1, ref double N2)

{

double Bu =
d2.XS - d1.XS;

double Bv =
d2.YS - d1.YS;

double Bw =
d2.ZS - d1.ZS;

N1 = (Bu * fz2.w - Bw * fz2.u) / (fz1.u *
fz2.w - fz1.w * fz2.u);

N2 = (Bu * fz1.w - Bw * fz1.u) / (fz1.u *
fz2.w - fz1.w * fz2.u);

}

4.得到地面点的摄影测量坐标

/// <summary>

/// 得到地面点的摄影测量坐标

/// </summary>

/// <param name="d1"></param>

/// <param name="d2"></param>

/// <param name="fz1"></param>

/// <param name="fz2"></param>

/// <param name="p"></param>

public static void cal_pm(data d1,
data d2, fuzhu fz1, fuzhu fz2, pm p,double N1,double N2)

{

p.X = d1.XS + N1 * fz1.u;

p.Y = 0.5 * (d1.YS + d2.YS + N1 * fz1.v +
N2 * fz2.v);

p.Z = d1.ZS + N1 * fz1.w;

}


3.2 绘图类说明

3.2.1 绘图类变量说明

static double minx, miny, maxx, maxy; // 测区x和y的最大最小值
static bool mousedowns; // 记录鼠标是否被按下
static Point startpoint, endpoint;// 记录移动的起始点和终止点
static Rectangle re; // 记录窗体的大小变化,便于示意图可以随时变化
static double dsx, dsy; // 记录坐标放缩的比例
static double margin; // 记录画布与窗体边缘的间隔
static double termge; // 记录示意图的内边距

3.2.2 绘图类函数说明

1.求坐标最值以及放缩比例
/// <summary>
/// 求坐标最值以及放缩比例,为画图做准备
/// </summary>
/// <param name="re"></param>
/// <param name="d1"></param>
/// <param name="d2"></param>
/// <param name="p"></param>
public static void create(Rectangle re, data d1, data d2, pm p)
{
minx = miny = double.MaxValue; maxx = maxy = double.MinValue;
if (d1.XS < minx) minx = d1.XS;
if (d1.XS > maxx) maxx = d1.XS;
if (d1.YS < miny) miny = d1.YS;
if (d1.YS > maxy) maxy = d1.YS;
if (d2.XS < minx) minx = d2.XS;
if (d2.XS > maxx) maxx = d2.XS;
if (d2.YS < miny) miny = d2.YS;
if (d2.YS > maxy) maxy = d2.YS;
if (p.X < minx) minx = p.X;
if (p.X > maxx) maxx = p.X;
if (p.Y < miny) miny = p.Y;
if (p.Y > maxy) maxy = p.Y;
margin = re.Height / 6;
termge = 10;
dsx = (maxx - minx) / (re.Width - 2 * margin);
dsy = (maxy - miny) / (re.Height - 2 * margin);
}

2.画出坐标轴以及示意图的基本元素
/// <summary>
/// 画出坐标轴以及示意图的基本元素
/// </summary>
/// <param name="re"></param>
/// <param name="ga"></param>
public static void draw_X(Rectangle re, Graphics ga)
{
// 创建画笔和字体
Pen pen1 = new Pen(Color.Black);
SolidBrush so1 = new SolidBrush(Color.Black);
Font f = new Font("宋体", 16, FontStyle.Bold);
// 画出坐标轴,标明两个轴代表意义
PointF[] pf1 = new PointF[3];
pf1[0] = new PointF((float)margin, (float)(margin));
pf1[1] = new PointF((float)margin, (float)(re.Height - margin));
pf1[2] = new PointF((float)(re.Width - margin), (float)(re.Height - margin));
// 画出x轴的箭头
PointF[] pf2 = new PointF[3];
pf2[0] = new PointF((float)(re.Width - margin - 10), (float)(re.Height - margin - 10));
pf2[1] = new PointF((float)(re.Width - margin), (float)(re.Height - margin));
pf2[2] = new PointF((float)(re.Width - margin - 10), (float)(re.Height - margin + 10));
ga.DrawLines(pen1, pf2);
// 画出y轴的箭头
PointF[] pf3 = new PointF[3];
pf3[0] = new PointF((float)(margin - 10), (float)(margin + 10));
pf3[1] = new PointF((float)margin, (float)(margin));
pf3[2] = new PointF((float)(margin + 10), (float)(margin + 10));
ga.DrawLines(pen1, pf3);
ga.DrawLines(pen1, pf1);
ga.DrawString("X", f, so1, new PointF((float)(re.Width - margin), (float)(re.Height - margin + 10)));
ga.DrawString("Y", f, so1, new PointF((float)(margin - 10), (float)margin));
// 画出刻度
int dx = (int)(re.Width - 2 * margin) / 6;
int dy = (int)(re.Height - 2 * margin) / 4;
//y轴的刻度分为4份
for (int i = 0; i < 4; i++)
{
double xx = (i + 1) * dx + margin;
ga.DrawLine(pen1, (float)xx, (float)(re.Height - margin), (float)xx, (float)(re.Height - margin - 10));
double x = (xx - margin) * dsx + minx;
ga.DrawString(x.ToString("0.000"), f, so1, (float)xx, (float)(re.Height - margin + 10));
}
// x轴的刻度分为6份
for (int i = 0; i < 6; i++)
{
double yy = re.Height - margin - (i + 1) * dy;
ga.DrawLine(pen1, (float)margin, (float)yy, (float)(margin + 10), (float)yy);
double y = miny + (i + 1) * dy * dsy;
ga.DrawString(y.ToString("0.000"), f, so1, (float)(margin - 10), (float)yy);
}
// 画出标题
ga.DrawString("空间前方交会计算示意图", f, so1, new PointF((float)(re.Width / 2 - 18), (float)(margin - 10)));
}
三.画出相片点和地面点,以及点名和连线
/// <summary>
/// 画出相片点和地面点,以及点名和连线
/// </summary>
/// <param name="d1"></param>
/// <param name="d2"></param>
/// <param name="p"></param>
/// <param name="re"></param>
/// <param name="ga"></param>
public static void draw_point(data d1, data d2, pm p, Rectangle re, Graphics ga, bool flag)
{
Pen pen1 = new Pen(Color.Black);
SolidBrush so1 = new SolidBrush(Color.Black);
Pen pen2 = new Pen(Color.Red);
SolidBrush so2 = new SolidBrush(Color.Red);
Font f = new Font("宋体", 10, FontStyle.Bold);
double xx1 = (d1.XS - minx) / dsx + margin + termge;
double yy1 = re.Height - margin - (d1.YS - miny) / dsy - termge;
double xx2 = (d2.XS - minx) / dsx + margin + termge;
double yy2 = re.Height - margin - (d2.YS - miny) / dsy - termge;
double xx3 = (p.X - minx) / dsx + margin + termge;
double yy3 = re.Height - margin - (p.Y - miny) / dsy - termge;
ga.FillEllipse(so1, (float)xx1, (float)yy1, 3, 3);
ga.DrawString("d1", f, so1, new PointF((float)(xx1 + 3), (float)(yy1 + 3)));
ga.FillEllipse(so1, (float)xx2, (float)yy2, 3, 3);
ga.DrawString("d2", f, so1, new PointF((float)(xx2 + 3), (float)(yy2 + 3)));
ga.FillEllipse(so2, (float)xx3, (float)yy3, 6, 6);
ga.DrawString("P", f, so2, new PointF((float)(xx3 + 3), (float)(yy3 + 3)));
if (flag)
{
ga.DrawLine(pen1, (float)xx1, (float)yy1, (float)xx3, (float)yy3);
ga.DrawLine(pen1, (float)xx2, (float)yy2, (float)xx3, (float)yy3);
ga.DrawLine(pen2, (float)xx1, (float)yy1, (float)xx2, (float)yy2);
}
}

四、程序运行示意图

1.文件导入界面
文件数据导入


** 2.手动输入界面
手动输入


**3.计算报告界面
计算报告


**4.示意图界面
示意图界面

5. 总结

这篇文章通过c#实现了一个空间前方交会窗体小程序,总的而言包含c#常用窗体控件的使用,文件流使用,绘图流操作,我是TF,让我们下次再见!


!!!有关空间前方交会基础知识详见百度百科链接: 空间前方交会

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

会飞的神里绫华

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值