KEEP K.I.S.S.

tk's blog

对于断言 ASSERT 的理解

昨天看了《代码大全》的“防御式编程”章节,解惑了长期以来自己对于断言的理解。

书中给了使用断言的指导意见,如下

  1. 用错误处理代码来处理预期会发生的状况,用断言来处理绝不应该发生的状况。
  2. 避免把需要执行的代码放到断言中
  3. 用断言来注解并验证前条件和后条件
  4. 对于高健壮性的代码,应该先使用断言再处理错误
其中有一段话,很清晰地说出了断言的典型使用情况:
对来源于内部系统的可靠的数据使用断言,而不要对外部不可靠的数据使用断言,对于外部不可靠数据,应该使用错误处理代码。断言可以看成可执行的注释。
系统外部的数据(用户输入,文件,网络读取等等)都是不可信的,需要严格检查(通常是错误处理)才能放行到系统内部,这相当于一个守卫。而对于系统内部的交互(比如子程序调用),如果每次也都去处理输入的数据,也就相当于系统没有可信的边界了,会让代码变的臃肿复杂;而事实上,在系统内部,传递给子程序预期的恰当数据应该是调用者的责任,系统内的调用者应该确保传递给子程序的数据是恰当可以正常工作的。这样一来,就隔离了不可靠的外部环境和可靠的系统内部环境,降低复杂度。
 
但是在开发阶段,代码极可能包含缺陷,也许是处理外部数据的程序考虑的不够周全,也许是调用系统内部子程序的代码存在错误,造成子程序调用失败。这个时候,断言就可以发挥作用,用来确诊到底是那部分出现了问题而导致子程序调用失败。在清理了所有缺陷之后,内外有别的信用体系就建立起来。等到发行版时候,这些断言就应该没有存在必要。
 
附一个C++可以用的自定义断言
#ifndef _ASSERT_EX_H
#define _ASSERT_EX_H

#include <stdlib.h>
#include <stdio.h>

#ifdef _DEBUG
#define _ASSERT(exp, message) { \
if (!(exp)) {		\
        fprintf(stdout, "Assertion failed: \"%s\"\nMessage: \"%s\"\nline: %d\nfile: \"%s\"\n", \
                #exp, message, __LINE__, __FILE__); \
	exit(EXIT_FAILURE);						\
	 }     \
}
#else
#define _ASSERT(exp, message)
#endif

#endif //_ASSERT_EX_H
 

参心大地坐标与参心空间直角坐标的转换

参心大地坐标转换为参心空间直角坐标

$$\begin{cases} & X=(N+H)\cos{B}\cos{L} \\  & Y=(N+H)\cos{B}\sin{L} \\  & Z=[ N(1- \mathit{e}^2)+H) ]\sin{B} \end{cases}$$公式中,$N$  为椭球面卯酉圈的曲率半径,$\mathit{e}$  为椭球的第一偏心率:$$\mathit{e}^2 = \frac{a^2-b^2}{a^2}$$  $a$ ,$b$ 椭球的长短半径 $$N=\frac{a}{\sqrt{1-\mathit{e}^2\sin^2B}}$$

参心空间直角坐标转换为参心大地坐标

$$\begin{cases} & L=\arctan\left(\frac{Y}{X}\right) \\ & B=\arctan\left(\frac{Z\left(N+H\right)}{\sqrt{\left(X^2+Y^2 \right)\left[N\left(1-\mathit{e}^2 \right) + H \right]}}\right) \\ & H=\frac{Z}{\sin B}-N\left(1-\mathit{e}^2 \right) = \frac{\sqrt{X^2 + Y^2}}{\cos B} - N \end{cases} $$

大地经度 $L$ ,$B$ 求解要考虑 $Y$ 和 $Z$ 的正负。

大地纬度 $B$ 的计算比较复杂,变换后 $$\tan B = \frac{Z+N\mathit{e}^2\sin B}{\sqrt{X^2 + Y^2}}$$ 上式中右端有待定量 $B$ ,需要迭代计算。迭代时可取 $$\tan B_1=\frac{Z}{\sqrt{X^2+Y^2}}$$ 用 $B$ 的初值 $B_1$ 计算 $N_1$ 和 $\sin B_1$ ,然后继续迭代,直至最后两次 $B$ 值之差小于允许误差为止。

由于左、右两端具有不同的三角函数,这对于迭代很不方便。为克服这一缺点,建议采用下面的迭代公式:

$$N=\frac{c}{V}=\frac{c}{\sqrt{1+{e'}^2\cos^2 B}}$$

$$\frac{1}{\cos^2 B}=1+\tan^2 B$$

整理得 $$\tan B = \frac{Z}{\sqrt{X^2+Y^2}}+\frac{ce^2\tan B}{\sqrt{X^2+Y^2} \cdot \sqrt{1+{e'}^2+\tan^2 B}}$$ 因此,$$t_{i+1}=t_0+\frac{pt_i}{\sqrt{k+t_i^2}}$$ 式中 $$\begin{cases} & t_0=\frac{Z}{\sqrt{X^2+Y^2}}  \\ & p=\frac{ce^2}{\sqrt{X^2+Y^2}} \\ & k=1+{e'}^2  \\ & c=a\sqrt{1+{e'}^2} \\ & {e'}^2 = \frac{a^2-b^2}{b^2} \end{cases}$$  $t_i$ 为前一次迭代值,第一次迭代令 $t_i=t_0$ 。

 

参考资料:

《大地测量基准与坐标转换》,姚宜斌,武汉大学测绘学院卫星应用工程研究所,2006.03. PDF链接

《大地测量学基础》,孔祥元 郭际明 刘宗泉,武汉大学出版社, P103.

四参数转换使用的公式

设四参数转换 尺度 为 $k$,旋转角为$\theta$,坐标系位移量分别为$\Delta X$$\Delta Y$则单点转换公式为

\begin{bmatrix} X_1\\Y_1  \end{bmatrix} = \begin{bmatrix} \Delta X\\ \Delta Y  \end{bmatrix} +  \begin{bmatrix} k \cdot \cos\theta & - k \cdot \sin\theta \\ k \cdot \sin\theta & k \cdot \cos\theta \end{bmatrix} \begin{bmatrix} X_0\\Y_0  \end{bmatrix}

变换后的矩阵形式为

\begin{bmatrix}  1&0  & X_0 &-Y_0 \\   0&1  &Y_0  & X_0 \end{bmatrix} \begin{bmatrix} \Delta X \\ \Delta Y \\ k \cdot \cos\theta \\ k \cdot \sin\theta \end{bmatrix} = \begin{bmatrix}  X_1 \\ Y_1 \end{bmatrix}

这就是类似 \[BX=A\] 的平差式

所以可知

        \[X=\bigl(B^TB\bigr)^{-1}B^TA\]

 

PS:实验下学 \LaTeX{} 怎么写公式

DLL 导出函数以及DEF文件的作用相关链接

一下午都在研究 def 文件为什么能无修饰名的导出函数名到dll,然后找了好几篇文章,推荐两个:

http://archive.cnblogs.com/a/2196642/   编写DLL所学所思(1)——导出函数

http://hi.baidu.com/luosiyong/blog/item/3d68f3fc68a01098b801a045.html dll的def文件与__declspec(dllexport)导出函数方式比较

 

def 文件不会影响生成的导入库文件(.lib),def文件可以指定导出别名。在 C 和 C++ 混合DLL编程中就需要注意了,def 文件并不能很自然地 隐式链接调用DLL,因为头文件声明的函数名和导入库(.lib)中的符号名并不对应(除非使用 extern "C" 声明),因为 C 编译器和 C++编译器(或者不同C++编译器)中的函数名修饰规则并不相同。

Ruby 的小角度7参数转换简单描述

小角度7参数转换的 Ruby 使用 Matrix的简单描述

小角度的7参数坐标系转换可以化简原本的转换参数公式,最后如下图片描述

 

 

这是一段根据3个点对的坐标来求解转换额外一点的对应坐标的 Ruby代码,使用了Ruby标准库里的 Matrix,很方便的:

 

require 'matrix'

def buildBUnit(*p)
  a = []
  a[0, 7] = 1, 0, 0, p[0], 0, -p[2], p[1]
  a[7, 7] = 0, 1, 0, p[1], p[2], 0, -p[0]
  a[14, 7] = 0, 0, 1, p[2], -p[1], p[0], 0
  a
end

def cutDown(*p, count)
  a = []
  row = 0
  while row < (p.count.to_f / count).ceil
    a << p[row * count, count]
    row += 1
  end
  a
end

def buildB(*p)
  a = []
  p.each {|point| a += buildBUnit(*point) }
  Matrix[*(cutDown(*a, 7))]
end

def buildA(*p)
  Matrix.column_vector(p.flatten)
end

m = [[ 30.55876333, 117.2395818, 13.09], [30.55882632, 117.23958408, 13.188], [ 30.55876333, 117.23968333, 13.09]]
p = [[13.127, -3.579, 10.143], [13.090, 3.434, 10.200], [3.127, -3.579, 10.143]]
B = buildB(*p)
A = buildA(*m)

BT = B.transpose
temp = BT * B
X = temp.inv * BT * A

bas = [47.850, -0.020, 3.399]
trans = Matrix[*cutDown(*buildBUnit(*bas), 7)]
MM = trans * X
p MM

#够简单的。。。。