文章目录
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,让我们下次再见!
!!!有关空间前方交会基础知识详见百度百科链接: 空间前方交会