aboutsummaryrefslogtreecommitdiff
path: root/src/PJ_hatano.c
blob: 34c70c0fd08c9ab97666f36e5c51656150aa9e69 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
#define PJ_LIB__
#include <projects.h>

PROJ_HEAD(hatano, "Hatano Asymmetrical Equal Area") "\n\tPCyl, Sph.";

#define NITER   20
#define EPS 1e-7
#define ONETOL 1.000001
#define CN  2.67595
#define CS  2.43763
#define RCN 0.37369906014686373063
#define RCS 0.41023453108141924738
#define FYCN    1.75859
#define FYCS    1.93052
#define RYCN    0.56863737426006061674
#define RYCS    0.51799515156538134803
#define FXC 0.85
#define RXC 1.17647058823529411764


static XY s_forward (LP lp, PJ *P) {           /* Spheroidal, forward */
    XY xy = {0.0,0.0};
    double th1, c;
    int i;
    (void) P;

    c = sin(lp.phi) * (lp.phi < 0. ? CS : CN);
    for (i = NITER; i; --i) {
        lp.phi -= th1 = (lp.phi + sin(lp.phi) - c) / (1. + cos(lp.phi));
        if (fabs(th1) < EPS) break;
    }
    xy.x = FXC * lp.lam * cos(lp.phi *= .5);
    xy.y = sin(lp.phi) * (lp.phi < 0. ? FYCS : FYCN);

    return xy;
}


static LP s_inverse (XY xy, PJ *P) {           /* Spheroidal, inverse */
    LP lp = {0.0,0.0};
    double th;

    th = xy.y * ( xy.y < 0. ? RYCS : RYCN);
    if (fabs(th) > 1.) {
        if (fabs(th) > ONETOL) {
            I_ERROR;
        } else {
            th = th > 0. ? M_HALFPI : - M_HALFPI;
        }
    } else {
        th = asin(th);
    }

    lp.lam = RXC * xy.x / cos(th);
    th += th;
    lp.phi = (th + sin(th)) * (xy.y < 0. ? RCS : RCN);
    if (fabs(lp.phi) > 1.) {
        if (fabs(lp.phi) > ONETOL) {
           I_ERROR;
        } else {
            lp.phi = lp.phi > 0. ? M_HALFPI : - M_HALFPI;
        }
    } else {
        lp.phi = asin(lp.phi);
    }

    return (lp);
}


static void *freeup_new (PJ *P) {                       /* Destructor */
    if (0==P)
        return 0;

    return pj_dealloc(P);
}

static void freeup (PJ *P) {
    freeup_new (P);
    return;
}


PJ *PROJECTION(hatano) {
    P->es = 0.;
    P->inv = s_inverse;
    P->fwd = s_forward;

    return P;
}

#ifdef PJ_OMIT_SELFTEST
int pj_hatano_selftest (void) {return 0;}
#else

int pj_hatano_selftest (void) {
    double tolerance_lp = 1e-10;
    double tolerance_xy = 1e-7;

    char s_args[] = {"+proj=hatano   +a=6400000    +lat_1=0.5 +lat_2=2"};

    LP fwd_in[] = {
        { 2, 1},
        { 2,-1},
        {-2, 1},
        {-2,-1}
    };

    XY s_fwd_expect[] = {
        { 189878.87894652804,  131409.8024406255
},
        { 189881.08195244463, -131409.14227607418
},
        {-189878.87894652804,  131409.8024406255
},
        {-189881.08195244463, -131409.14227607418
},
    };

    XY inv_in[] = {
        { 200, 100},
        { 200,-100},
        {-200, 100},
        {-200,-100}
    };

    LP s_inv_expect[] = {
        { 0.0021064624821817597,  0.00076095689425791926
},
        { 0.0021064624821676096, -0.00076095777439265377
},
        {-0.0021064624821817597,  0.00076095689425791926
},
        {-0.0021064624821676096, -0.00076095777439265377
},
    };

    return pj_generic_selftest (0, s_args, tolerance_xy, tolerance_lp, 4, 4, fwd_in, 0, s_fwd_expect, inv_in, 0, s_inv_expect);
}


#endif