Changes: gps controller uses labels for fake gps
[ptas] / zouba / src / location.cpp
1 #include "location.h"
2
3 #include "location_p.h"
4
5 #include "ytv.h"
6
7 #include <QString>
8 #include <QObject>
9 #include <QNetworkAccessManager>
10 #include <QUrl>
11 #include <QNetworkRequest>
12 #include <QNetworkReply>
13 #include <QXmlStreamReader>
14 #include <QDebug>
15 #include <QXmlStreamAttributes>
16 #include <QStringRef>
17 #include <QGeoPositionInfo>
18
19 #include <math.h>
20
21 const double Location::KkjZoneInfo[6][2] = {
22   {18.0,  500000.0},
23   {21.0, 1500000.0},
24   {24.0, 2500000.0},
25   {27.0, 3500000.0},
26   {30.0, 4500000.0},
27   {33.0, 5500000.0}
28 };
29
30 QTM_USE_NAMESPACE
31
32 Location::Location( const QString &x, const QString &y, const QString &label ) :
33   q( new LocationPrivate( x, y, label ) ),
34   manager( new QNetworkAccessManager(this) )
35 {
36   qDebug() << "Location::Location(" << x << "," << y << "," << label <<")";
37   connect(
38       manager, SIGNAL( finished(QNetworkReply*) ),
39       this, SLOT( replyFinished(QNetworkReply*) )
40       );
41 }
42
43 Location::Location( const QGeoPositionInfo &positionInfo, const QString &label ) :
44   q( new LocationPrivate( label ) ),
45   manager(0)
46 {
47   setLocation( positionInfo );
48 }
49
50 void Location::setLocation( const QGeoPositionInfo &positionInfo )
51 {
52   qreal latitude = positionInfo.coordinate().latitude();
53   qreal longitude = positionInfo.coordinate().longitude();
54
55   KKJ outX(0);
56   KKJ outY(0);
57
58   WGS84lola_to_KKJxy( longitude, latitude, &outX, &outY);
59
60   q->setX( outX );
61   q->setY( outY );
62   q->setValid( true );
63 }
64
65 Location::Location( const Location &from ) :
66   QObject(0),
67   q( new LocationPrivate( from.label() ) ),
68   manager(0)
69 {
70   qDebug() << "Location::Location( const Location [" << from.label() << "] )";
71   q->setAddress( from.address() );
72   q->setX( from.x() );
73   q->setY( from.y() );
74   q->setValid( from.isValid() );
75   if ( from.manager != 0 ) {
76     manager = new QNetworkAccessManager(this);
77     connect( manager, SIGNAL( finished(QNetworkReply*) ), this, SLOT( replyFinished(QNetworkReply*) ) );
78   }
79 }
80
81 Location::Location( const QString &label ) :
82   q( new LocationPrivate( label ) ),
83   manager( new QNetworkAccessManager(this) )
84 {
85   qDebug() << "Location::Location( const QString &label=" << label << " )";
86   connect( manager, SIGNAL( finished(QNetworkReply*) ), this, SLOT( replyFinished(QNetworkReply*) ) );
87 }
88
89 Location::~Location()
90 {
91   delete q;
92   q=0;
93   delete manager;
94   manager=0;
95 }
96
97 Location &Location::operator=( const Location &from )
98 {
99   qDebug() << "Location::Location( const Location &from )";
100   q = new LocationPrivate( from.label() );
101   q->setAddress( from.address() );
102   q->setX( from.x() );
103   q->setY( from.y() );
104   q->setValid( from.isValid() );
105
106   if ( from.manager != 0 ) {
107     manager = new QNetworkAccessManager(this);
108     connect( manager, SIGNAL( finished(QNetworkReply*) ), this, SLOT( replyFinished(QNetworkReply*) ) );
109   } else {
110     manager = 0;
111   }
112
113   return *this;
114 }
115
116 void Location::resolveAddress( const QString &address )
117 {
118   qDebug() << "resolving address";
119   qDebug() << address;
120
121   q->setAddress( address );
122   q->setValid( false );
123
124   QUrl fullUrl( Ytv::Url );
125
126   fullUrl.addEncodedQueryItem( "key", address.toAscii().toPercentEncoding() );
127   fullUrl.addQueryItem( "user", Ytv::Username );
128   fullUrl.addQueryItem( "pass", Ytv::Password );
129
130   manager->get( QNetworkRequest( fullUrl ) );
131   qDebug() << "waiting for reply from Ytv";
132 }
133
134 void Location::replyFinished( QNetworkReply * reply )
135 {
136   qDebug() << "address resolved";
137   q->parseReply( reply->readAll() );
138
139   if ( isValid() ) {
140     qDebug() << label() << "becomeValid";
141     emit( becomeValid() );
142   }
143 }
144
145 QString Location::x() const
146 {
147   return q->x();
148 }
149
150 QString Location::y() const
151 {
152   return q->y();
153 }
154
155 void Location::setLabel( const QString &label ) const
156 {
157   q->setLabel( label );
158 }
159
160 QString Location::label() const
161 {
162   return q->label();
163 }
164
165 void Location::setAddress( const QString &address ) const
166 {
167   qDebug() << "setting address to" << address;
168   q->setAddress( address );
169 }
170
171 QString Location::address() const
172 {
173   return q->address();
174 }
175
176 bool Location::isValid() const
177 {
178   return q->isValid();
179 }
180
181 // Degrees to radians
182 double Location::radians(double deg)
183 {
184   return deg * M_PI / 180.0;
185 }
186
187 // Radians to degrees
188 double Location::degrees(double rad)
189 {
190   return rad * 180.0 / M_PI;
191 }
192
193 // Function:  KKJ_Zone_I
194 int Location::KKJ_Zone_I(KKJ easting)
195 {
196   int zoneNumber = floor(easting / 1000000.0);
197   if (zoneNumber < 0 || zoneNumber > 5) {
198     zoneNumber = -1;
199   }
200
201   return zoneNumber;
202 }
203
204 // Function:  KKJ_Zone_Lo
205 int Location::KKJ_Zone_Lo(double kkjlo)
206 {
207   // determine the zonenumber from KKJ easting
208   // takes KKJ zone which has center meridian
209   // longitude nearest (in math value) to
210   // the given KKJ longitude
211   int zoneNumber = 5;
212   while (zoneNumber >= 0) {
213     if (fabs(kkjlo - KkjZoneInfo[zoneNumber][0]) <= 1.5) {
214       break;
215     }
216     zoneNumber--;
217   }
218
219   return zoneNumber;
220 }
221
222
223 // Function:  KKJlalo_to_WGS84lalo
224 void Location::KKJlola_to_WGS84lola(double kkjlo, double kkjla, double *outLongitude, double *outLatitude)
225 {
226   double dLa = radians(0.124867E+01 + -0.269982E+00 * kkjla + 0.191330E+00 * kkjlo + 0.356119E-02 * kkjla * kkjla + -0.122312E-02 * kkjla * kkjlo + -0.335514E-03 * kkjlo * kkjlo) / 3600.0;
227   double dLo = radians(-0.286111E+02 + 0.114183E+01 * kkjla + -0.581428E+00 * kkjlo + -0.152421E-01 * kkjla * kkjla + 0.118177E-01 * kkjla * kkjlo + 0.826646E-03 * kkjlo * kkjlo) / 3600.0;
228
229   *outLatitude = degrees(radians(kkjla) + dLa);
230   *outLongitude = degrees(radians(kkjlo) + dLo);
231 }
232
233
234 // Function:  WGS84lalo_to_KKJlalo
235 void Location::WGS84lola_to_KKJlola(double longitude, double latitude, double *outLongitude, double *outLatitude)
236 {
237   double dLa = radians(-0.124766E+01 + 0.269941E+00 * latitude + -0.191342E+00 * longitude + -0.356086E-02 * latitude * latitude + 0.122353E-02 * latitude * longitude + 0.335456E-03 * longitude * longitude) / 3600.0;
238   double dLo = radians(0.286008E+02 + -0.114139E+01 * latitude + 0.581329E+00 * longitude + 0.152376E-01 * latitude * latitude + -0.118166E-01 * latitude * longitude + -0.826201E-03 * longitude * longitude) / 3600.0;
239
240   *outLatitude = degrees(radians(latitude) + dLa);
241   *outLongitude = degrees(radians(longitude) + dLo);
242 }
243
244
245 // Function:  KKJlalo_to_KKJxy
246 void Location::KKJlola_to_KKJxy(double lon, double lat, int zoneNumber, KKJ *outX, KKJ *outY)
247 {
248   // Hayford ellipsoid
249   double a = 6378388.0;
250   double f  = 1.0 / 297.0;
251   double b  = (1.0 - f) * a;
252   double bb = b * b;
253   double c  = (a / b) * a;
254   double ee = (a * a - bb) / bb;
255   double n = (a - b) / (a + b);
256   double nn = n * n;
257
258   double Lo = radians(lon) - radians(KkjZoneInfo[zoneNumber][0]);
259   double cosLa = cos(radians(lat));
260   double NN = ee * cosLa * cosLa;
261   double LaF = atan(tan(radians(lat)) / cos(Lo * sqrt(1.0 + NN)));
262   double cosLaF = cos(LaF);
263   double t = (tan(Lo) * cosLaF) / sqrt(1.0 + ee * cosLaF * cosLaF);
264   double A = a / (1.0 + n);
265   double A1 = A * (1.0 + nn / 4.0 + nn * nn / 64.0);
266   double A2 = A * 1.5 * n * (1.0 - nn / 8.0);
267   double A3 = A * 0.9375 * nn * (1.0 - nn / 4.0);
268   double A4 = A * 35.0 / 48.0 * nn * n;
269
270   *outY = A1 * LaF - A2 * sin(2.0 * LaF) + A3 * sin(4.0 * LaF) - A4 * sin(6.0 * LaF);
271   *outX = c * log(t + sqrt(1.0 + t * t)) + 500000.0 + zoneNumber * 1000000.0;
272 }
273
274 // Function:  KKJxy_to_KKJlalo
275 void Location::KKJxy_to_KKJlola(KKJ x, KKJ y, double *outLongitude, double *outLatitude)
276 {
277   // Scan iteratively the target area, until find matching
278   // KKJ coordinate value.  Area is defined with Hayford Ellipsoid.
279   int zoneNumber = KKJ_Zone_I(x);
280   double minLo = radians(18.5);
281   double maxLo = radians(32.0);
282   double minLa = radians(59.0);
283   double maxLa = radians(70.5);
284
285   int i = 1;
286   KKJ tmpX, tmpY;
287
288   while (i < 35) {
289     double deltaLo = maxLo - minLo;
290     double deltaLa = maxLa - minLa;
291     *outLongitude = degrees(minLo + 0.5 * deltaLo);
292     *outLatitude = degrees(minLa + 0.5 * deltaLa);
293     KKJlola_to_KKJxy(*outLongitude, *outLatitude, zoneNumber, &tmpX, &tmpY);
294     if (tmpY < y) {
295       minLa = minLa + 0.45 * deltaLa;
296     } else {
297       maxLa = minLa + 0.55 * deltaLa;
298     }
299
300     if (tmpX < x) {
301       minLo = minLo + 0.45 * deltaLo;
302     } else {
303       maxLo = minLo + 0.55 * deltaLo;
304     }
305
306     i++;
307   }
308 }
309
310 void Location::WGS84lola_to_KKJxy(double longitude, double latitude, KKJ *outX, KKJ *outY)
311 {
312   double kkjlo, kkjla;
313
314   WGS84lola_to_KKJlola(longitude, latitude, &kkjlo, &kkjla);
315   int zoneNumber = KKJ_Zone_Lo(kkjlo);
316   KKJlola_to_KKJxy(kkjlo, kkjla, zoneNumber, outX, outY);
317 }
318
319 void Location::KKJxy_to_WGS84lola(KKJ x, KKJ y, double *outLongitude, double *outLatitude)
320 {
321   double kkjlo, kkjla;
322
323   KKJxy_to_KKJlola(x, y, &kkjlo, &kkjla);
324   KKJlola_to_WGS84lola(kkjlo, kkjla, outLongitude, outLatitude);
325
326 }
327