Statistics
| Revision:

root / trunk / libraries / libFMap / src / com / iver / cit / gvsig / fmap / tools / geo / Geo.java @ 20098

History | View | Annotate | Download (4.52 KB)

1
package com.iver.cit.gvsig.fmap.tools.geo;
2

    
3
/**
4
 * <p>Mathematical utilities to work with geographical data:
5
 *  <ul>
6
 *  <li>Geographical constants:
7
 *   <ul>
8
 *    <li>PI / 2.</li>
9
 *    <li>Degrees per radian.</li>
10
 *    <li>Square miles per spherical degree.</li>
11
 *    <li>Square kilometres per spherical degree.</li>
12
 *    <li>Square metres per spherical degree.</li>
13
 *   </ul>
14
 *  </li>
15
 *  <li>Decimal degrees equivalent to <i>m</i> meters.</li>
16
 *  <li>The area of a spherical polygon in spherical degrees, given the latitudes and longitudes 
17
 *   of <i>n</i> points, according the <a href="http://en.wikipedia.org/wiki/Haversine_formula">Haversine function</a>.
18
 *  </ul>
19
 * </p> 
20
 *
21
 * @author Vicente Caballero Navarro
22
 */
23
public class Geo {
24
        /**
25
         * <i>PI / 2</i>, having PI = 3.14159265358979323846
26
         */
27
        public static double HalfPi = 1.5707963267948966192313;
28

    
29
    /**
30
     * Degrees per radian.
31
     */
32
        public static double Degree = 57.295779513082320876798; /* degrees per radian */
33

    
34
    /**
35
     *  Square miles per spherical degree.
36
     */
37
        public static double SqMi = 273218.4; /* Square mi per spherical degree. */
38

    
39
    /**
40
     * Square kilometres per spherical degree.
41
     */
42
        public static double SqKm = 707632.4; /* Square km per spherical degree. */
43

    
44
    /**
45
     * Square metres per spherical degree.
46
     */
47
        public static double SqM = 707632400000.0; /* Square M per spherical degree. */
48

    
49

    
50
        /**
51
         * <p>Gets the decimal degrees equivalent to the <i>m</i> meters.</p>
52
         * <p>Uses this formula:</br>
53
         * <b><i>m * R * PI</i></b>, having R = Radius of the Earth at the equator
54
         * </p>
55
         * 
56
         * @param m distance value in meters
57
         * 
58
         * @return <i>m</i> * Radius at the equator
59
         */
60
        public static double getDecimalDegrees(double m) {
61
            ///(m*180)/ (6378137.0 * Math.PI)
62
            return (m*8.983152841195214E-6);
63
    }
64

    
65
    /**
66
     * <p>Operation for calculate the <a href="http://en.wikipedia.org/wiki/Haversine_formula">Haversine function</a>:
67
     *  <b><i>hav(x)= (1-cos(x))/2</i></b>.</p>
68
     * 
69
     * @param X length between the difference of a coordinate of two points
70
     */
71
        private static double hav(double X){
72
        return (1.0 - Math.cos(X)) / 2.0;
73
    }
74

    
75
    /**
76
     * <p>Returns the area of a spherical polygon in spherical degrees,
77
     *  given the latitudes and longitudes in <i>lat</i> and <i>lon</i>, respectively.</p>
78
     *
79
     * <p>The <i>n</i> data points have indexes which range from 0 to N-1.</p>
80
     *
81
     * <p>Uses the <a href="http://en.wikipedia.org/wiki/Haversine_formula">Haversine function</a> for calculating the
82
     *  spherical area of the polygon.</p>
83
     *  
84
     * @param lat latitude of the vertexes <i>(must be in radians)</i>
85
     * @param lon longitude of the vertexes <i>(must be in radians)</i>
86
     * @param n number of vertexes in the polygon
87
     * 
88
     * @return the area of a spherical polygon in spherical degrees
89
     */
90
    public static double sphericalPolyArea(double[] lat, double[] lon, int n) {
91
        int j;
92
        int k;
93
        double lam1;
94
        double lam2 = 0;
95
        double beta1;
96
        double beta2 = 0;
97
        double cosB1;
98
        double cosB2 = 0;
99
        double havA;
100
        double t;
101
        double a;
102
        double b;
103
        double c;
104
        double s;
105
        double sum;
106
        double excess;
107

    
108
        sum = 0;
109

    
110
        for (j = 0; j <= n; j++) {
111
            k = j + 1;
112

    
113
            if (j == 0) {
114
                lam1 = lon[j];
115
                beta1 = lat[j];
116
                lam2 = lon[j + 1];
117
                beta2 = lat[j + 1];
118
                cosB1 = Math.cos(beta1);
119
                cosB2 = Math.cos(beta2);
120
            } else {
121
                k = (j + 1) % (n + 1);
122
                lam1 = lam2;
123
                beta1 = beta2;
124
                lam2 = lon[k];
125
                beta2 = lat[k];
126
                cosB1 = cosB2;
127
                cosB2 = Math.cos(beta2);
128
            }
129

    
130
            if (lam1 != lam2) {
131
                havA = hav(beta2 - beta1) + (cosB1 * cosB2 * hav(lam2 - lam1));
132
                a = 2 * Math.asin(Math.sqrt(havA));
133
                b = HalfPi - beta2;
134
                c = HalfPi - beta1;
135
                s = 0.5 * (a + b + c);
136
                t = Math.tan(s / 2) * Math.tan((s - a) / 2) * Math.tan((s - b) / 2) * Math.tan((s -
137
                        c) / 2);
138

    
139
                excess = Math.abs(4 * Math.atan(Math.sqrt(Math.abs(t)))) * Degree;
140

    
141
                if (lam2 < lam1) {
142
                    excess = -excess;
143
                }
144

    
145
                sum = sum + excess;
146
            }
147
        }
148
        return Math.abs(sum);
149
    } /*        SphericalPolyArea. */
150
}