1 module geodesicd.geodesic_warper;
2 
3 private {
4 
5   extern(C){
6 
7   struct geod_geodesic {
8     double a;         
9     double f;         
10     double f1; 
11     double e2; 
12     double ep2; 
13     double n; 
14     double b; 
15     double c2; 
16     double etol2;
17     double[6] A3x;
18     double[15] C3x;
19     double[21] C4x;
20   };
21 
22   void geod_init( geod_geodesic* g, double a, double f);
23 
24   void geod_inverse(const geod_geodesic* g,
25             double lat1, double lon1, double lat2, double lon2,
26             double* ps12, double* pazi1, double* pazi2);
27 
28   void geod_direct(const geod_geodesic* g,
29            double lat1, double lon1, double azi1, double s12,
30            double* plat2, double* plon2, double* pazi2);
31 
32   }
33 
34 }
35 // WGS84 as default;
36 struct Ellipsoid{
37   double a = 6378137;
38   double f = 1/298.257223563; 
39 }
40 
41 struct LatLon{
42   double lat = 0.0;
43   double lon = 0.0;
44 }
45 
46 struct AzDist{
47   double az = 0.0;
48   double distance = 0.0;
49 }
50 
51 struct LatLonAz{
52   double lat = 0.0;
53   double lon = 0.0;
54   double az = 0.0;  
55 }
56 
57 struct DistAz1Az2{
58   double distance = 0.0;
59   double az1 = 0.0;  
60   double az2 = 0.0;  
61 }
62 
63 static Ellipsoid EllipsoidWGS84 = {6378137, 1/298.257223563};
64 
65 // D warper
66 struct Geodesic{
67 
68   private geod_geodesic g;
69   private Ellipsoid ellipsoid;
70   
71   this(double a, double f){
72      ellipsoid.a=a;
73      ellipsoid.f=f;
74      geod_init(&g, ellipsoid.a, ellipsoid.f);
75   }
76   
77   this(Ellipsoid e){
78     ellipsoid = e;
79     geod_init(&g,ellipsoid.a,ellipsoid.f);
80   }
81 
82   double[3] inverse(double lat1, double lon1, double lat2, double lon2){
83     double[3] v;
84     geod_inverse(&this.g, lat1, lon1, lat2, lon2, &v[0], &v[1], &v[2]);
85     return v;
86   }
87 
88   DistAz1Az2 inverse(LatLon p1, LatLon p2){
89     DistAz1Az2 v;
90     geod_inverse(&this.g, p1.lat, p1.lon, p2.lat, p2.lon, &v.distance, &v.az1, &v.az2);
91     return v;
92   }
93 
94   double[3] direct(double lat1, double lon1, double azi1, double s12){
95     double[3] v;
96     geod_direct(&this.g, lat1, lon1, azi1, s12, &v[0], &v[1], &v[2]);
97     return v;
98   }
99 
100   LatLonAz direct(LatLon p1, AzDist azd){
101     LatLonAz v;
102     geod_direct(&this.g, p1.lat, p1.lon, azd.az, azd.distance, &v.lat, &v.lon, &v.az);
103     return v;
104   }
105 
106 }
107 
108 // test init!
109 unittest{
110   import std.stdio;
111   auto g1 = Geodesic();
112   auto g2 = Geodesic(6378137, 1/298.257223563);
113   auto g3 = Geodesic(EllipsoidWGS84);
114 
115 //  writeln("OK");
116 
117 }
118 unittest{
119   import std.stdio;
120   import std.math;
121 
122   double a = 6378137, f = 1/298.257223563; /* WGS84 */
123   double lat1, lon1, azi1, lat2, lon2, azi2, s12;
124 
125   lat1 = 54.5;
126   lon1 = 18.5;
127   lat2 = 55.5;
128   lon2 = 17.5;
129 
130   auto g1 = Geodesic(a,f);
131   auto g_out1 = g1.inverse(lat1, lon1, lat2, lon2);
132   double [3] g_out1_test = [128403.130195, -29.483701, -30.302891];
133 
134   assert(abs(g_out1[0] - g_out1_test[0]) < 1e-6);
135   assert(abs(g_out1[1] - g_out1_test[1]) < 1e-6);
136   assert(abs(g_out1[2] - g_out1_test[2]) < 1e-6);
137 
138   auto g_out2 = g1.direct(lat1, lon1, 90.0, 50000.0);
139   double [3] g_out2_test = [54.497537, 19.271724, 90.628266];
140 
141   assert(abs(g_out2[0] - g_out2_test[0]) < 1e-6);
142   assert(abs(g_out2[1] - g_out2_test[1]) < 1e-6);
143   assert(abs(g_out2[2] - g_out2_test[2]) < 1e-6);
144 
145   //writefln("%f, %f, %f ", g_out2[0], g_out2[1],g_out2[2]);
146   //auto dd = g1.direct(lat1, lon1, 90.0, 50000.0);
147   //writeln(dd);
148 }
149 
150 unittest{
151   import std.stdio;
152   import std.math;
153 
154   auto g1 = Geodesic(EllipsoidWGS84);
155   auto p1 = LatLon(54.5, 18.5);
156   auto p2 = LatLon(55.5, 17.5);
157   auto g_out1 = g1.inverse(p1, p2);
158   DistAz1Az2 g_out1_test = {128403.130195, -29.483701, -30.302891};
159   //writeln(g_out1);
160   assert(abs(g_out1.distance - g_out1_test.distance) < 1e-6);
161   assert(abs(g_out1.az1 - g_out1_test.az1) < 1e-6);
162   assert(abs(g_out1.az2 - g_out1_test.az2) < 1e-6);
163 
164   auto g_out2 = g1.direct(p1, AzDist(90.0, 50000.0));
165   LatLonAz g_out2_test = {54.497537, 19.271724, 90.628266};
166   assert(abs(g_out2.lon - g_out2_test.lon) < 1e-6);
167   assert(abs(g_out2.lat - g_out2_test.lat) < 1e-6);
168   assert(abs(g_out2.az - g_out2_test.az) < 1e-6);
169   //writeln(g_out2);
170 }