分享

平面四参数转换图文教程!

 今天George 2018-03-31

我们求出四参数到底有什么意义呢
假如我们用C#写一个画图的程序,比如在picturebox中画一个某一边是尖头的矩形。我们知道,picturebox的坐标系的原点在它的左上角,X轴是向指向右边的,Y轴是指向下边的。而测量坐标系中,X是指向上边的(北),Y是指向右边的(东),原点在左下角,为了方便用户设计图形,我们就用测量的坐标系来设计。
在船体坐标系中,如下图3(新坐标系,用户定义的坐标系):

我们知道四参数后,就可以把测量坐标系的几个点转换成picturebox坐标,然后画出来。当然也可以改变picturebox控件的坐标,但是这样效率很低,也不容易理解,特别是图形旋转的话也很难弄。

原始坐标系是: Xo-Yo  经过尺度缩放,坐标系旋转,然后再平移,变成了Xt-Yt坐标系。如《控制测量》上的图1:

1中,我们要注意的是:
1. X的方向是向右的,Y是向上的。
2. 旋转角是以顺时针方向为正的
这两点非常重要。如果X是向上的,那么四参数将会不一样;而如果旋转角是逆时针方向为正的,四参数也不一样。X有可能是向左或者向下的甚至是向任意方向的,所以关键是我们一定要能画出图形,并且推导出公式。
如《控制测量》书上的推导图就很典型可以做为参考,如图2:

这个图的优点就在于,它的源坐标系旋转后就成为水平和垂直的轴线,非常便于平移理解。

需要注意的是,图2中,源坐标系X向任意方向,Y轴的正方向和X轴的正方向逆时针旋转90度的方向一致,定义旋转角顺时针方向为正时。其实应该有4种情况,图上是下面提到的情况C。
假如源坐标系的X是向上的(其实X轴向哪个方向都没有关系,只要Y轴的正方向和X轴的正方向顺时针旋转90度的方向一致),Y是向右的,定义的旋转角逆时针旋转是正的,平面转换四参数的计算公式如下(公式1):

其中 为新坐标, 为两个平移参数,(1 m)为尺度,为旋转角,为原坐标。这就是下面提到的情况A。公式1也可以用在情况C。

  ,

则四参数公式可以写成:

(公式2)

为了求解四参数,把所有已知的和未知的矩阵写在一起,构造出:
 的形式,然后再利用 求解。
公式2经过展开,变成下面的形式:


写成矩阵的形式(公式3):

这样我们就构造成了 的形式,其中,  为原坐标系下某点的坐标,  分别为原坐标系到新坐标系的平移量, , ,其中(1 m)是尺度, 为旋转角。
公式三就这样变成了一个单纯的矩阵运算,2个点的话恰好能求出四参数,无法计算残差,如果大于等于3个点,就可以计算出残差,这实际上用了最小二乘法。

现在,我们来根据图1的实际情况假设几个比较接近情况的四参数:


假如原坐标系上有5个点,P1(0, 15) P2(0, 5) P3(3, 0) P4(6, 5) P5(6, 15)
其中P1(0, 15)表示在原坐标系下,点P1的X坐标为0, Y坐标为15。
现在,把原坐标系(整个坐标系:包括原点,X轴,Y轴)的X,Y轴都缩短为原来的1/2,然后把整个坐标系逆时针旋转30度,再把两条坐标轴或者说整个坐标系向X轴的负方向移动(旋转以后的X轴的正方向的反方向)4米(如果是负数,那么应该向旋转后的X轴的正方向移动个单位);同理,向Y轴的负方向移动3米(如果是负数就向正方向),经过这3个步骤,原坐标系变成了新的坐标系,原来的5个点,它们在新坐标系下的坐标分别是:
P1(-11.0, 28.981) P2(-1.0, 11.660) P3(9.196, 6.0) P4(9.392, 17.660) P5(-0.608, 34.981)
注意:P1 P2 P3 P4 P5 并不同原坐标系一起旋转!

我们来看使用四参数的计算过程:
double c = fourP.Scale * Math.Cos(fourP.Rotate);
double d = fourP.Scale * Math.Sin(fourP.Rotate);
公式4:
aPtfNew.X = fourP.Xdelta (c * aPtfOld.X - d * aPtfOld.Y);
aPtfNew.Y = fourP.Ydelta (d * aPtfOld.X c * aPtfOld.Y);

只有同意了这个公式才能讨论下面的问题。


那么,我们求出四参数到底有什么意义呢
假如我们用C#写一个画图的程序,比如在picturebox中画一个某一边是尖头的矩形。我们知道,picturebox的坐标系的原点在它的左上角,X轴是向指向右边的,Y轴是指向下边的。而测量坐标系中,X是指向上边的(北),Y是指向右边的(东),原点在左下角,为了方便用户设计图形,我们就用测量的坐标系来设计。
在船体坐标系中,如下图3(新坐标系,用户定义的坐标系):

如果我们把图3中的船体坐标系去掉,沿着船的矩形边缘建立一个类似于C#中的Picturebox的坐标系,那么在picturebox中各点坐标如下,如图4(源坐标系,它恰好是下面提到的4种情况的情况A):

这个过程到底是什么转换的呢?或许有些人一眼就看出了是picturebox坐标系先逆时针转90度,然后再下方移动15个单位就变成了船体的坐标系。但是大多数人反应毕竟没有那么快,还是有点晕的。所以现在我们看看可否通过四参数的求解,而不用画图或者凭借空间想象力来探讨坐标系的变换:

我们利用其中的两个点的两套坐标系,求出坐标系的变换参数:
P1(0, 15)    P2(0, 5)   两个点在源的坐标系中的坐标(picturebox坐标系)
P1(0, 0)     P2(10, 0)  两个点在新的坐标系中的坐标(船体坐标系/用户坐标系)

求得的四参数是:(源坐标系的X向右,Y向下,逆时针旋转Rotate为正)
X平移 = 15.0
Y平移 = 0.0
旋转(度) = 90 (逆时针)
尺度 = 1.0
我们用刚才对四参数的解释来理解(按次序):1.不缩放 2.逆时针旋转90度 3.向此刻的坐标系(仅是尺度变化和旋转以后的形成的坐标系)的X方向的反方向移动15个单位。
这里有一个误区,是很容易让人混淆的地方。因为源坐标系和以前定义的不一样了,X,Y的方向分别是向右和向下的,逆时针旋转为正的。

我通过作图,得出的结论是存在4种情况:
情况A.
不管X是向哪个方向的(向上,向下,向左,向右或者任意方向),只要Y轴的正方向和X轴的正方向顺时针旋转90度的方向一致,而且定义旋转角逆时针方向为正,那么用的公式也是公式1。测量上用得最多的情况是X向上,Y向右;也是实例中的picturebox的坐标系的情况。


情况B.
 X向任意方向,Y轴的正方向和X轴的正方向顺时针旋转90度的方向一致,定义旋转角顺时针方向为正(数学坐标系用得比较多),那么公式是:


显然,情况C的四参数计算和求解完全和情况A不同,需要重新推导,如果直接用公式3来求四参数和公司4来计算点在新坐标系下的xy,计算出来的结果和理解的肯定不一样。

情况C.
X向任意方向,Y轴的正方向和X轴的正方向逆时针旋转90度的方向一致,定义旋转角顺时针方向为正时,得出的也是公式1。如前面的图2显示,公式同情况A是:


情况A和情况C都可以用公式3来求四参数,用公式4来计算点在新坐标系下的XY坐标。
情况D.
 如果,X向任意方向,Y轴的正方向和X轴的正方向逆时针旋转90度的方向一致,定义旋转角逆时针方向为正,那么公式同情况B是:


显然,情况D的四参数计算和求解完全和情况A不同,需要重新推导,否则计算出来的结果和理解的肯定是错的。

回到刚才讨论的应用的例子(船体坐标系和picturebox的转换)这和视觉上看起来是一样的,比较容易理解。这就恰恰是四参数的用武之地。

而在C#的picturebox中,我们是如何利用四参数来为我们服务的呢?
我们的想法是:重新定义picturebox的坐标系,让它变成船体坐标系,然后直接在picturebox上面画出5个船体坐标点的连线:P1(0, 0) P2(10, 0) P3(15, 3) P4(10, 6) P5(0, 6)

这其实有3个步骤(这要求我们把源坐标系和新坐标系颠倒过来看,就是说把picturebox坐标系当做源坐标系,这样四参数就反过来了。而当源坐标系的X向右,Y向下,逆时针旋转时,四参数的计算公式和源坐标X向):
1. 先在picShip的paint事件中利用ScaleTransform把比例尺调整成我们需要的坐标范围,它本来是用象素做单位的,写入e.Graphics.ScaleTransform(picShip.Width / 6, picShip.Height / 15)
把它的水平轴范围调整成[0,6],垂直的范围调整成[0, 15]

2. e.Graphics.RotateTransform(-90.0F); // 此句运行之后picShip的X坐标向上了,Y向右了。可视区域的范围是x[-6, 0] y[0, 15]

3. e.Graphics.TranslateTransform(-15, 0); // 把旋转之后的坐标系再向下移动15个单位

这些我花了将近一两个星期的时间,始终不能理解,现在回头过来探讨1年前弄不清楚半知半解的东西——有点或然开朗的感觉。

这些都不太好理解,挺恶心,但是为了以后不再恐惧,我们不如多花点时间把它彻底弄清楚,增强我们的信心和实力。试验分析如下:
假如picturebox的长为400象素,高为300象素。
1. ScaleTransform(10, 10)的作用是,把picturebox的水平轴X轴拉长10倍,垂直轴也拉长10倍。那么picturebox现在能显示的范围就变成了:水平[0, 40] 垂直[0, 30]。 而如果e.Graphics.ScaleTransform(0.1F, 0.1F)之后,picturebox可显示的范围放大了10倍将变成:水平[0, 4000] 垂直[0,3000]
// ScaleTransform的作用是对坐标轴X轴和Y轴进行缩放

// pic能表达的范围缩小了10倍

e.Graphics.ScaleTransform(10, 10);

e.Graphics.DrawLine(Pens.Blue, new PointF(0, 0), new PointF(39, 29));

2.
// 作用把当前的坐标系改变,新坐标系的原点在源坐标系的[100, 10]位置

// 也就是说现在picturebox的左上角的坐标是[-100, -10]

// pic现在能表达的范围是: 水平[-100, 300] 垂直[-10, 290]

// 所以画出的两个点故意缩进了一下,这样就能看到整条线的面貌。

e.Graphics.TranslateTransform(100, 10);

e.Graphics.DrawLine(Pens.Blue, new PointF(-95, -5), new PointF(295, 285));

3.
// RotateTransform的作用是对坐标系进行顺时针的旋转

// 这个比较复杂,而且不好理解

// 假如是顺时针旋转30度后形成新的坐标系,

// 那么当前pic的右上角的点在新坐标系下的坐标是(346.4, -200)

// pic的左下角点在新坐标系中的坐标是[150, 259.8]

// pic的右下角点在新坐标系中的坐标是[496.4, 59.8]

e.Graphics.RotateTransform(30.0F);
// 连接到pic的右上角的点

e.Graphics.DrawLine(Pens.Blue, new PointF(5, 5), new PointF(340, -190));
// 连接到pic的左下角的点

e.Graphics.DrawLine(Pens.Blue, new PointF(5, 5), new PointF(155, 250));
// 连接到pic的右下角的点

e.Graphics.DrawLine(Pens.Blue, new PointF(5, 5), new PointF(485, 51));

最后,我们要注意的是:使用或者求解四参数之前,应该弄明白源坐标是如何定义的,X轴是向哪个方向,Y轴和X轴呈什么关系,旋转角是逆时针转为正还是正时针转为正,得自己推导一下公式。如果情况A和情况C,就可以用上面的公式3求解四参数,用公式4来计算xy,否则会出错的。所以会推导公式才是最重要的,千万不要乱用,乱猜,或者知之而不能言而乱言。

 

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多