高斯投影正反算的代码

 
2008-05-28 16:03:29 | 高斯投影正反算的代码
 

//高斯投影正、反算
//6度带宽 54年北京坐标系
//高斯投影由经纬度(UnitD)反算大地坐标(含带号,Unit:Metres)
void GaussProjCal(double longitude, double latitude, double *X, double *Y)
{
int ProjNo=0; int ZoneWide; 带宽
double longitude1,latitude1, longitude0,latitude0, X0,Y0, xval,yval;
double a,f, e2,ee, NN, T,C,A, M, iPI;
iPI = 0.0174532925199433; 3.1415926535898/180.0;
ZoneWide = 6; 6度带宽
a=6378245.0; f=1.0/298.3; //54年北京坐标系参数
a=6378140.0; f=1/298.257; //80年西安坐标系参数
ProjNo = (int)(longitude / ZoneWide) ;
longitude0 = ProjNo * ZoneWide + ZoneWide / 2;
longitude0 = longitude0 * iPI ;
latitude0=0;
longitude1 = longitude * iPI ; //经度转换为弧度
latitude1 = latitude * iPI ; //纬度转换为弧度
e2=2*f-f*f;
ee=e2*(1.0-e2);
NN=a/sqrt(1.0-e2*sin(latitude1)*sin(latitude1));
T=tan(latitude1)*tan(latitude1);
C=ee*cos(latitude1)*cos(latitude1);
A=(longitude1-longitude0)*cos(latitude1);
M=a*((1-e2/4-3*e2*e2/64-5*e2*e2*e2/256)*latitude1-(3*e2/8+3*e2*e2/32+45*e2*e2
*e2/1024)*sin(2*latitude1)
+(15*e2*e2/256+45*e2*e2*e2/1024)*sin(4*latitude1)-(35*e2*e2*e2/3072)*sin(6*l
atitude1));
xval = NN*(A+(1-T+C)*A*A*A/6+(5-18*T+T*T+72*C-58*ee)*A*A*A*A*A/120);
yval = M+NN*tan(latitude1)*(A*A/2+(5-T+9*C+4*C*C)*A*A*A*A/24
+(61-58*T+T*T+600*C-330*ee)*A*A*A*A*A*A/720);
X0 = 1000000L*(ProjNo+1)+500000L;
Y0 = 0;
xval = xval+X0; yval = yval+Y0;
*X = xval;
*Y = yval;
}


//高斯投影由大地坐标(Unit:Metres)反算经纬度(UnitD)
void GaussProjInvCal(double X, double Y, double *longitude, double *latitude)

{
int ProjNo; int ZoneWide; 带宽
double longitude1,latitude1, longitude0,latitude0, X0,Y0, xval,yval;
double e1,e2,f,a, ee, NN, T,C, M, D,R,u,fai, iPI;
iPI = 0.0174532925199433; 3.1415926535898/180.0;
a = 6378245.0; f = 1.0/298.3; //54年北京坐标系参数
a=6378140.0; f=1/298.257; //80年西安坐标系参数
ZoneWide = 6; 6度带宽
ProjNo = (int)(X/1000000L) ; //查找带号
longitude0 = (ProjNo-1) * ZoneWide + ZoneWide / 2;
longitude0 = longitude0 * iPI ; //中央经线
X0 = ProjNo*1000000L+500000L;
Y0 = 0;
xval = X-X0; yval = Y-Y0; //带内大地坐标
e2 = 2*f-f*f;
e1 = (1.0-sqrt(1-e2))/(1.0+sqrt(1-e2));
ee = e2/(1-e2);
M = yval;
u = M/(a*(1-e2/4-3*e2*e2/64-5*e2*e2*e2/256));
fai = u+(3*e1/2-27*e1*e1*e1/32)*sin(2*u)+(21*e1*e1/16-55*e1*e1*e1*e1/32)*sin(
4*u)
+(151*e1*e1*e1/96)*sin(6*u)+(1097*e1*e1*e1*e1/512)*sin(8*u);
C = ee*cos(fai)*cos(fai);
T = tan(fai)*tan(fai);
NN = a/sqrt(1.0-e2*sin(fai)*sin(fai));
R = a*(1-e2)/sqrt((1-e2*sin(fai)*sin(fai))*(1-e2*sin(fai)*sin(fai))*(1-e2*sin
(fai)*sin(fai)));
D = xval/NN;
//计算经度(Longitude) 纬度(Latitude)
longitude1 = longitude0+(D-(1+2*T+C)*D*D*D/6+(5-2*C+28*T-3*C*C+8*ee+24*T*T)*D
*D*D*D*D/120)/cos(fai);
latitude1 = fai -(NN*tan(fai)/R)*(D*D/2-(5+3*T+10*C-4*C*C-9*ee)*D*D*D*D/24
+(61+90*T+298*C+45*T*T-256*ee-3*C*C)*D*D*D*D*D*D/720);
//转换为度 DD
*longitude = longitude1 / iPI;
*latitude = latitude1 / iPI;
}


几个重要参数的意义:

 

NN卯酉圈曲率半径,测量学里面用N表示

M为子午线弧长,测量学里用大X表示

fai为底点纬度,由子午弧长反算公式得到,测量学里用Bf表示

R为底点所对的曲率半径,测量学里用Nf表示

来自:http://www.eefocus.com/myspace/blog/show.php?id=150022 

本人没有自己验证

方法二:

高斯投影<->经纬度
2008年04月21日 星期一 13:06

/* 功能说明: 将绝对高斯坐标(y,x)转换成绝对的地理坐标(wd,jd)。        */
        // double y;     输入参数: 高斯坐标的横坐标,以米为单位
        // double x; 输入参数: 高斯坐标的纵坐标,以米为单位
        // short DH;     输入参数: 带号,表示上述高斯坐标是哪个带的
        // double *L;     输出参数: 指向经度坐标的指针,其中经度坐标以秒为单位
        // double *B;     输出参数: 指向纬度坐标的指针,其中纬度坐标以秒为单位
        void GaussToGeo(double y, double x, short DH, double* L, double* B, double LP)
        {
            double l0;    // 经差
            double tf;    // tf = tg(Bf0),注意要将Bf转换成以弧度为单位
            double nf;    // n = y * sqrt( 1 + etf ** 2) / c, 其中etf = e'**2 * cos(Bf0) ** 2
            double t_l0;   // l0,经差,以度为单位
            double t_B0;   // B0,纬度,以度为单位
            double Bf0;    // Bf0
            double etf;    // etf,其中etf = e'**2 * cos(Bf0) ** 2
            double X_3;

            double PI = 3.14159265358979;
            double b_e2 = 0.0067385254147;
            double b_c = 6399698.90178271;

            X_3 = x / 1000000.00 - 3;      // 以兆米(1000000)为单位
            // 对于克拉索夫斯基椭球,计算Bf0
            Bf0 = 27.11115372595 + 9.02468257083 * X_3 - 0.00579740442 * pow(X_3, 2)
                           - 0.00043532572 * pow(X_3, 3) + 0.00004857285 * pow(X_3, 4)
                           + 0.00000215727 * pow(X_3, 5) - 0.00000019399 * pow(X_3, 6);
            tf = tan(Bf0 * PI / 180);       // tf = tg(Bf),注意这里将Bf转换成以弧度为单位
            etf = b_e2 * pow(cos(Bf0 * PI / 180), 2);   // etf = e'**2 * cos(Bf) ** 2
            nf = y * sqrt(1 + etf) / b_c;     // n = y * sqrt( 1 + etf ** 2) / c
            // 计算纬度,注意这里计算出来的结果是以度为单位的
            t_B0 = Bf0 - (1.0 + etf) * tf / PI * (90.0 * pow(nf, 2)
                   - 7.5 * (5.0 + 3 * pow(tf, 2) + etf - 9 * etf * pow(tf, 2)) * pow(nf, 4)
                   + 0.25 * (61 + 90 * pow(tf, 2) + 45 * pow(tf, 4)) * pow(nf, 6));
            // 计算经差,注意这里计算出来的结果是以度为单位的
            t_l0 = (180 * nf - 30 * (1 + 2 * pow(tf, 2) + etf) * pow(nf, 3)
                     + 1.5 * (5 + 28 * pow(tf, 2) + 24 * pow(tf, 4)) * pow(nf, 5))
                     / (PI * cos(Bf0 * PI / 180));
            l0 = (t_l0 * 3600.0);       // 将经差转成秒

            if (LP == -1000)
            {
                *L = (double)((DH * 6 - 3) * 3600.0 + l0); // 根据带号计算出以秒为单位的绝对经度,返回指针
            }
            else
            {
                *L = LP * 3600.0 + l0; // 根据带号计算出以秒为单位的绝对经度,返回指针
            }
            //----------------------------------

            *B = (double)(t_B0 * 3600.0);     // 将纬差转成秒,并返回指针
        }

        /* 功能说明: (1)将地理坐标(wd,jd)转换成绝对的高斯坐标(y,x)
            (2)本函数支持基于六度带(或三度带)、克拉索夫斯基椭球进行转换                             */
        /* 适用范围: 本函数适用于将地球东半球中北半球(即东经0度到东经180度,北纬0度至90度)范围
            内所有地理坐标到高斯坐标的转换            */
        /* 使用说明: 调用本函数后返回的结果应在满足精度的条件下进行四舍五入      */
        // double jd;         输入参数: 地理坐标的经度,以秒为单位
        // double wd;         输入参数: 地理坐标的纬度,以秒为单位
        // short DH;      输入参数: 三度带或六度带的带号
        /* 六度带(三度带)的带号是这样得到的:从东经0度到东经180度自西向东按每6度(3度)顺序编号
        (编号从1开始),这个顺序编号就称为六度带(三度带)的带号。因此,六度带的带号的范围是1-30,
        三度带的带号的范围是1-60。
          如果一个点在图号为TH的图幅中,那麽该点所处的六度带的带号就可以这样得到:将该图号的
        第3、4位组成的字符串先转换成数字,再减去30。例如某点在图幅06490701中,该点所在的带号就
        是49-30,即19。
          如果调用本函数去进行一般的从地理坐标到基于六度带高斯坐标的变换(非邻带转换),则参
        数DH的选取按前一段的方法去确定。               
          如果调用本函数去进行基于六度带邻带转换,则参数DH的选取先按上述方法去确定,然后看是
        往前一个带还是后一个带进行邻带转换再确定是加1还是减1。         */
        void GeoToGauss(double jd, double wd, short DH, short DH_width, double* y, double* x, double LP)
        {
            double t;     // t=tgB
            double L;     // 中央经线的经度
            double l0;    // 经差
            double jd_hd, wd_hd; // 将jd、wd转换成以弧度为单位
            double et2;    // et2 = (e' ** 2) * (cosB ** 2)
            double N;     // N = C / sqrt(1 + et2)
            double X;     // 克拉索夫斯基椭球中子午弧长
            double m;     // m = cosB * PI/180 * l0
            double tsin, tcos;   // sinB,cosB

            double PI = 3.14159265358979;
            double b_e2 = 0.0067385254147;
            double b_c = 6399698.90178271;

            jd_hd = jd / 3600.0 * PI / 180.0;    // 将以秒为单位的经度转换成弧度
            wd_hd = wd / 3600.0 * PI / 180.0;    // 将以秒为单位的纬度转换成弧度

            // 如果不设中央经线(缺省参数: -1000),则计算中央经线,
            // 否则,使用传入的中央经线,不再使用带号和带宽参数
            //L = (DH - 0.5) * DH_width ;      // 计算中央经线的经度
            if (LP == -1000)
            {
                L = (DH - 0.5) * DH_width;      // 计算中央经线的经度
            }
            else
            {
                L = LP;
            }

            l0 = jd / 3600.0 - L;       // 计算经差
            tsin = sin(wd_hd);        // 计算sinB
            tcos = cos(wd_hd);        // 计算cosB
            // 计算克拉索夫斯基椭球中子午弧长X
            X = 111134.8611 / 3600.0 * wd - (32005.7799 * tsin + 133.9238 * pow(tsin, 3)
                  + 0.6976 * pow(tsin, 5) + 0.0039 * pow(tsin, 7)) * tcos;
            et2 = b_e2 * pow(tcos, 2);      // et2 = (e' ** 2) * (cosB ** 2)
            N = b_c / sqrt(1 + et2);      // N = C / sqrt(1 + et2)
            t = tan(wd_hd);         // t=tgB
            m = PI / 180 * l0 * tcos;       // m = cosB * PI/180 * l0
            *x = X + N * t * (0.5 * pow(m, 2)
                      + (5.0 - pow(t, 2) + 9.0 * et2 + 4 * pow(et2, 2)) * pow(m, 4) / 24.0
                      + (61.0 - 58.0 * pow(t, 2) + pow(t, 4)) * pow(m, 6) / 720.0);
            *y = N * (m + (1.0 - pow(t, 2) + et2) * pow(m, 3) / 6.0
                            + (5.0 - 18.0 * pow(t, 2) + pow(t, 4) + 14.0 * et2
                               - 58.0 * et2 * pow(t, 2)) * pow(m, 5) / 120.0);

        }

来自:http://hi.baidu.com/82085166/blog/item/18e3612a6202159e023bf66e.html

方法三

'高斯反算
Private Sub DadiFs()
Dim t As Double, Itp As Double, X0 As Double, Bf As Double, N As Double
Dim v As Double, ll As Double, W As Double, M As Double, L0 As Double
L0 = Radian(Lo)
X0 = x * 0.000001
y = y - 500000#
If Tq = 0 Then
a = 6378245 '54椭球参数
b = 6356863.01877305
ep = 0.006693421622966
ep1 = 0.006738525414683
f = (a - b) / a
c = a ^ 2 / b
d = b ^ 2 / a
If X0 < 3 Then
Bf = 9.04353301294 * X0 - 0.00000049604 * X0 ^ 2 - 0.00075310733 * X0 ^ 3 - 0.00000084307 * X0 ^ 4 - 0.00000426055 * X0 ^ 5 - 0.00000010148 * X0 ^ 6
ElseIf X0 < 6 Then
Bf = 27.11115372595 + 9.02468257083 * (X0 - 3) - 0.00579740442 * (X0 - 3) ^ 2 - 0.00043532572 * (X0 - 3) ^ 3 + 0.00004857285 * (X0 - 3) ^ 4 + 0.00000215727 * (X0 - 3) ^ 5 - 0.00000019399 * (X0 - 3) ^ 6
End If
Else
a = 6378140 '75椭球参数
b = 6356755.28815753
ep = 0.006694384999588
ep1 = 0.006739501819473
f = (a - b) / a
c = a ^ 2 / b
d = b ^ 2 / a
If X0 < 3 Then
Bf = 9.04369066313 * X0 - 0.00000049618 * X0 ^ 2 - 0.00075325505 * X0 ^ 3 - 0.0000008433 * X0 ^ 4 - 0.00000426157 * X0 ^ 5 - 0.0000001015 * X0 ^ 6
ElseIf X0 < 6 Then
Bf = 27.11162289465 + 9.02483657729 * (X0 - 3) - 0.00579850656 * (X0 - 3) ^ 2 - 0.00043540029 * (X0 - 3) ^ 3 + 0.00004858357 * (X0 - 3) ^ 4 + 0.00000215769 * (X0 - 3) ^ 5 - 0.00000019404 * (X0 - 3) ^ 6
End If
End If
Bf = Bf * Pi / 180#
t = Tan(Bf)
Itp = ep1 * Cos(Bf) ^ 2
W = Sqr(1 - ep * Sin(Bf) ^ 2)
v = Sqr(1 + ep1 * Cos(Bf) ^ 2)
M = c / v ^ 3
N = a / W
Lat = Bf - 0.5 * v ^ 2 * t * ((y / N) ^ 2 - (5 + 3 * t * t + Itp - 9 * Itp * t * t) * (y / N) ^ 4 / 12 + (61 + 90 * t * t + 45 * t ^ 4) * (y / N) ^ 6 / 360)
ll = ((y / N) - (1 + 2 * t * t + Itp) * (y / N) ^ 3 / 6 + (5 + 28 * t * t + 24 * t ^ 4 + 6 * Itp + 8 * Itp * t * t) * (y / N) ^ 5 / 120) / Cos(Bf)
r = y * t / N - y ^ 3 * t * (1 + t * t - Itp) / (3 * N ^ 3) + y ^ 5 * t * (2 + 5 * t * t + 3 * t ^ 4) / (15 * N ^ 5)
Lat = Degree(Lat)
Lon = Degree(L0 + ll)
r = Degree(r)
End Sub

可以精确到0.00000001秒
上面的Degree为将弧度化为DMS的自定义函数
'弧度化角度
Public Function Degree(a As Double) As Double
Dim Bo As Double
Dim Fs As Double
Dim Im As Integer
Dim Id As Integer
If a < 0 Then a = -a: t = 1
Bo = a
Call DMS(Bo, Id, Im, Fs)
If t = 1 Then Degree = -(Id + Im / 100# + Fs / 10000#) Else Degree = Id + Im / 100# + Fs / 10000#
End Function
Public Sub DMS(a As Double, Id As Integer, Im As Integer, Fs As Double)
Dim Bo As Double
Dim c As Double
c = a
c = 180# / Pi * c
Id = Int(c)
Bo = (c - Id) * 60
Im = Int(Bo)
Fs = (Bo - Im) * 60
End Sub

6
 

来自:http://www.othermap.com/dvbbs/dispbbs.asp?boardID=21&ID=6865

方法四

164
165 public class PointCoordinate
166    {
167        private double lon;
168        private double lat;
169        private double alt;
170        public double x;
171        public double y;
172        private static double minX = double.MaxValue;
173        private static double maxX = double.MinValue;
174        private static double minY = double.MaxValue;
175        private static double maxY = double.MinValue;
176        public static double minlon = double.MaxValue;
177        public static double minlat = double.MaxValue;
178        public static double minalt = double.MaxValue;
179        public static double maxlon = double.MinValue;
180        public static double maxlat = double.MinValue;
181        public static double maxalt = double.MinValue;
182
183        Attribute#region Attribute
184
185        public double Lon
186        {
187            get
188            {
189                return lon;
190            }
191            set
192            {
193                lon = value;
194            }
195        }
196        public double Lat
197        {
198            get
199            {
200                return lat;
201            }
202            set
203            {
204                lat = value;
205            }
206        }
207        public double Alt
208        {
209            get
210            {
211                return alt;
212            }
213            set
214            {
215                alt = value;
216            }
217        }
218
219        #endregion
220
221 ConStructions#region ConStructions
222
223        public PointCoordinate(double lon, double lat, double alt)
224        {
225            init(lon, lat, alt);
226        }
227        public PointCoordinate(string lon, string lat, string alt)
228        {
229            init(lon, lat, alt);
230        }
231        public PointCoordinate(string[] OnePoint)
232        {
233            init(OnePoint);
234        }
235
236        public PointCoordinate(string tuples)
237        {
238            init(tuples);
239        }
240
241        #endregion
242
243        Initilation#region Initilation
244
245        private void init(double lon, double lat, double alt)
246        {
247            this.lon = lon;
248            this.lat = lat;
249            this.alt = alt;
250            //LBXY lbxy = new LBXY(this.lon, this.lat);
251            //this.x = lbxy.x;
252            //this.y = lbxy.y;
253            //CheckRange();
254            CheckEarthRange();
255        }
256        private void init(string lon, string lat, string alt)
257        {
258            init(Convert.ToDouble(lon), Convert.ToDouble(lat), Convert.ToDouble(alt));
259        }
260        private void init(string[] OnePoint)
261        {
262            int CheckLen = OnePoint.Length;
263
264            if (CheckLen == 3)
265                init(OnePoint[0], OnePoint[1], OnePoint[2]);
266            else if(CheckLen==2)
267                init(OnePoint[0], OnePoint[1], "0.0");
268        }
269        private void init(string tuples)
270        {
271            string[] OnePoint = tuples.Split(',');
272            init(OnePoint);
273        }
274
275        #endregion
276
277        private void CheckEarthRange()
278        {
279            if (lon < minlon) minlon = lon;
280            if (lon > maxlon) maxlon = lon;
281            if (lat < minlat) minlat = lat;
282            if (lat > maxlat) maxlat = lat;
283            if (alt < minalt) minalt = alt;
284            if (alt > maxalt) maxalt = alt;
285        }
286        public void CheckRange()
287        {
288            if (x < minX) minX = x;
289            if (x > maxX) maxX = x;
290            if (y < minY) minY = y;
291            if (y > maxY) maxY = y;
292        }
293
294        //public double LonRatio
295        //{
296        //    get
297        //    {
298        //        if((maxlon - minlon)!=0)
299        //            return (lon - minlon) / (maxlon - minlon);
300        //        else
301        //            return 0.0;
302        //    }
303        //}
304        //public double LatRatio
305        //{
306        //    get
307        //    {
308        //        if((maxlat - minlat)!=0)
309        //            return (lat - minlat) / (maxlat - minlat);
310        //        else
311        //            return 0.0;
312        //    }
313        //}
314        public double xRatio
315        {
316            get
317            {
318                if ((maxX - minX) != 0)
319                    return (x - minX) / (maxX - minX);
320                else
321                    return 0.0;
322            }
323        }
324        public double yRatio
325        {
326            get
327            {
328                if ((maxY - minY) != 0)
329                    return (y - minY) / (maxY - minY);
330                else
331                    return 0.0;
332            }
333        }
334        public double lonRatio
335        {
336            get
337            {
338                if ((maxlon - minlon) != 0)
339                    return (lon - minlon) / (maxlon - minlon);
340                else
341                    return 0.0;
342            }
343        }
344        public double latRatio
345        {
346            get
347            {
348                if ((maxlat - minlat) != 0)
349                    return (lat - minlat) / (maxlat - minlat);
350                else
351                    return 0.0;
352            }
353        }
354
355    }
356
357    public class LBXY
358    {
359        public double l;//角度
360        public double b;//角度
361        private double L;//弧度
362        private double B;//弧度
363        private double l0;
364        private double L0;
365        public double x;
366        public double y;
367
368        public LBXY(double l, double b)
369        {
370            this.l = l;
371            this.b = b;
372            l0 = ML(l);
373            L0 = Deg2Arc(l0);
374            L = Deg2Arc(l);
375            B = Deg2Arc(b);
376            LB2XY();
377        }
378
379        public LBXY(PointCoordinate pc)
380        {
381            this.l = pc.Lon;
382            this.b = pc.Lat;
383            l0 = ML((PointCoordinate.maxlon + PointCoordinate.minlon) / 2.0);
384            L0 = Deg2Arc(l0);
385            L = Deg2Arc(l);
386            B = Deg2Arc(b);
387            LB2XY();
388            pc.x = this.y;
389            pc.y = this.x;
390            pc.CheckRange();
391        }
392
393        public double Arc2Deg(double arc)
394        {
395            return arc * 180 / Math.PI;
396        }
397        public double Deg2Arc(double deg)
398        {
399            return deg * Math.PI / 180;
400        }
401        public double ML(double lon)
402        {
403            int ZoneID=(int)(lon / 6) + 1;
404            double rev = (double)(ZoneID * 6 - 3);
405            return rev;
406        }
407
408        public void LB2XY()
409        {
410            double e2 = 0.006739501819;
411            double c = 6399596.65198801;//单位:m
412            //double e2 = 0.006738525415;
413            //double c = 6399698.9018;//单位:m
414
415            double t = Math.Tan(B);
416            double eta2 = e2 * Math.Cos(B) * Math.Cos(B);
417            double N = c / Math.Sqrt(1 + eta2);
418            double m = Math.Cos(B)*(L-L0);
419            double X = 111134.0047 * b
420                - (
421                32009.8575 * Math.Sin(B)
422                + 133.9602 * Math.Pow(Math.Sin(B), 3)
423                + 0.6976 * Math.Pow(Math.Sin(B), 5)
424                + 0.0039 * Math.Pow(Math.Sin(B), 7)
425                ) * Math.Cos(B);
426            double q1, q2, q3, q4;
427            q1 = t*t;
428            q2 = Math.Pow(t, 4);
429            q3 = m * m;
430            q4 = Math.Pow(m, 4);
431
432            x=X+N*t*q3*(0.5+(5-q1+9*eta2+4*eta2*eta2)*q3/24+(61-58*q1+q2)*q4/720);//纵轴,经线方向
433            y=N*m*(1+(1-q1+eta2)*q3/6+(5-18*q1+q2+14*eta2-58*eta2*q1)*q4/720);//横轴,赤道方向
434        }
435    }
436
437}

来自:http://tech.it168.com/msoft/2008-05-29/200805290928007_2.shtml

说明:本人没有自己验证

你可能感兴趣的:(GIS相关)