Tizen 2.0 Release
[framework/osp/locations.git] / src / FLocCoordinates.cpp
1 //
2 // Open Service Platform
3 // Copyright (c) 2012 Samsung Electronics Co., Ltd.
4 //
5 // Licensed under the Apache License, Version 2.0 (the License);
6 // you may not use this file except in compliance with the License.
7 // You may obtain a copy of the License at
8 //
9 //     http://www.apache.org/licenses/LICENSE-2.0
10 //
11 // Unless required by applicable law or agreed to in writing, software
12 // distributed under the License is distributed on an "AS IS" BASIS,
13 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 // See the License for the specific language governing permissions and
15 // limitations under the License.
16 //
17
18 #include <new>
19 #include <math.h>
20 #include <FBaseDouble.h>
21 #include <FBaseInteger.h>
22 #include <FBaseSysLog.h>
23 #include <FBaseUtilMath.h>
24 #include <FBaseUtilStringTokenizer.h>
25 #include <FLocCoordinates.h>
26 #include "FLoc_EllipsoidModel.h"
27 #include "FLoc_MathUtils.h"
28 #include "FLoc_Types.h"
29
30 using namespace Tizen::Base;
31 using namespace Tizen::Base::Utility;
32
33 namespace Tizen { namespace Locations
34 {
35 Coordinates::Coordinates(void)
36         : Tizen::Base::Object()
37         , __latitude(Tizen::Locations::NaN)
38         , __longitude(Tizen::Locations::NaN)
39         , __altitude(Tizen::Locations::NaN)
40         , __pImpl(null)
41 {
42         SysAssertf(Double::IsNaN(__latitude), "Latitude is not initialized to NaN");
43         SysAssertf(Double::IsNaN(__longitude), "Longitude is not initialized to NaN");
44         SysAssertf(Double::IsNaN(__altitude), "Altitude is not initialized to NaN");
45 }
46
47 Coordinates::Coordinates(const Coordinates& rhs)
48         : Tizen::Base::Object()
49         , __latitude(rhs.__latitude)
50         , __longitude(rhs.__longitude)
51         , __altitude(rhs.__altitude)
52         , __pImpl(null)
53 {
54 }
55
56 Coordinates::~Coordinates(void)
57 {
58 }
59
60 bool
61 Coordinates::Equals(const Tizen::Base::Object& rhs) const
62 {
63         const Coordinates* pRhs = dynamic_cast< const Coordinates* >(&rhs);
64
65         if (pRhs == null)
66         {
67                 return false;
68         }
69
70         bool latitudeCheck = false;
71         bool longitudeCheck = false;
72         bool altitudeCheck = false;
73
74         if (Double::IsNaN(__latitude) || Double::IsNaN(pRhs->__latitude))
75         {
76                 if (Double::IsNaN(__latitude) && Double::IsNaN(pRhs->__latitude))
77                 {
78                         latitudeCheck = true;
79                 }
80         }
81         else if (Double::Compare(__latitude, pRhs->__latitude) == 0)
82         {
83                 latitudeCheck = true;
84         }
85
86         if (Double::IsNaN(__longitude) || Double::IsNaN(pRhs->__longitude))
87         {
88                 if (Double::IsNaN(__longitude) && Double::IsNaN(pRhs->__longitude))
89                 {
90                         longitudeCheck = true;
91                 }
92         }
93         else
94         {
95                 if (Double::Compare(__longitude, pRhs->__longitude) == 0)
96                 {
97                         longitudeCheck = true;
98                 }
99                 // Min and max longitudes lines meet together. (longitude -180 == +180)
100                 else if (Double::Compare(fabs(__longitude) + fabs(pRhs->__longitude), MAX_LONGITUDE * 2) == 0)
101                 {
102                         SysLog(NID_LOC, "Both longitudes are equal as 180 is equal to -180");
103                         longitudeCheck = true;
104                 }
105         }
106
107         if (Double::IsNaN(__altitude) || Double::IsNaN(pRhs->__altitude))
108         {
109                 if (Double::IsNaN(__altitude) && Double::IsNaN(pRhs->__altitude))
110                 {
111                         altitudeCheck = true;
112                 }
113         }
114         else if (Double::Compare(__altitude, pRhs->__altitude) == 0)
115         {
116                 altitudeCheck = true;
117         }
118
119         return (latitudeCheck && longitudeCheck && altitudeCheck);
120 }
121
122 int
123 Coordinates::GetHashCode(void) const
124 {
125         int hashCode = Double::GetHashCode(__latitude) * 37;
126
127         hashCode += Double::GetHashCode(__longitude) * 37;
128         hashCode += Double::GetHashCode(__altitude) * 37;
129
130         return hashCode;
131 }
132
133 result
134 Coordinates::Set(double latitude, double longitude, double altitude)
135 {
136         SysTryReturn(NID_LOC, (MIN_LATITUDE <= latitude) && (latitude <= MAX_LATITUDE),
137                                  E_INVALID_ARG, E_INVALID_ARG, "[E_INVALID_ARG] The latitude(%lf) must be in the range [-90.0, 90.0].", latitude);
138
139         SysTryReturn(NID_LOC, (MIN_LONGITUDE <= longitude) && (longitude <= MAX_LONGITUDE),
140                                  E_INVALID_ARG, E_INVALID_ARG, "[E_INVALID_ARG] The longitude(%lf) must be in the range [-180.0, 180.0].", longitude);
141
142         __latitude = latitude;
143         __longitude = longitude;
144         __altitude = altitude;
145
146         return E_SUCCESS;
147 }
148
149 result
150 Coordinates::SetLatitude(double latitude)
151 {
152         SysTryReturn(NID_LOC, (MIN_LATITUDE <= latitude) && (latitude <= MAX_LATITUDE),
153                                  E_INVALID_ARG, E_INVALID_ARG, "[E_INVALID_ARG] The latitude(%lf) must be in the range [-90.0, 90.0].", latitude);
154
155         __latitude = latitude;
156         return E_SUCCESS;
157 }
158
159 result
160 Coordinates::SetLongitude(double longitude)
161 {
162         SysTryReturn(NID_LOC, (MIN_LONGITUDE <= longitude) && (longitude <= MAX_LONGITUDE),
163                                  E_INVALID_ARG, E_INVALID_ARG, "[E_INVALID_ARG] The longitude(%lf) must be in the range [-180.0, 180.0].", longitude);
164
165         __longitude = longitude;
166         return E_SUCCESS;
167 }
168
169 void
170 Coordinates::SetAltitude(double altitude)
171 {
172         __altitude = altitude;
173 }
174
175 double
176 Coordinates::GetLatitude(void) const
177 {
178         return __latitude;
179 }
180
181 double
182 Coordinates::GetLongitude(void) const
183 {
184         return __longitude;
185 }
186
187 double
188 Coordinates::GetAltitude(void) const
189 {
190         return __altitude;
191 }
192
193 double
194 Coordinates::GetAzimuth(const Coordinates& dest) const
195 {
196         if ((Double::IsNaN(dest.GetLatitude()) == true) || (Double::IsNaN(dest.GetLongitude()) == true) || (Double::IsNaN(__latitude) == true) || (Double::IsNaN(__longitude) == true))
197         {
198                 return Tizen::Locations::NaN;
199         }
200
201         if (Double::Compare(MAX_LATITUDE, GetLatitude()) == 0 && Double::Compare(MAX_LATITUDE, dest.GetLatitude()) != 0)
202         {
203                 return 180.0;
204         }
205
206         if (Double::Compare(MIN_LATITUDE, GetLatitude()) == 0 && Double::Compare(MIN_LATITUDE, dest.GetLatitude()) != 0)
207         {
208                 return 0.0;
209         }
210
211         if (Equals(dest) ||
212                 (Double::Compare(MIN_LATITUDE, GetLatitude()) == 0 && Double::Compare(MIN_LATITUDE, dest.GetLatitude()) == 0) ||
213                 (Double::Compare(MAX_LATITUDE, GetLatitude()) == 0 && Double::Compare(MAX_LATITUDE, dest.GetLatitude()) == 0))
214         {
215                 return 0.0;
216         }
217
218         return _EllipsoidModel::GetAzimuth(GetLatitude(), GetLongitude(), dest.GetLatitude(), dest.GetLongitude());
219 }
220
221 double
222 Coordinates::GetDistanceTo(const Coordinates& to) const
223 {
224         if ((Double::IsNaN(to.GetLatitude()) == true) || (Double::IsNaN(to.GetLongitude()) == true) || (Double::IsNaN(__latitude) == true) || (Double::IsNaN(__longitude) == true))
225         {
226                 return Tizen::Locations::NaN;
227         }
228
229         return _EllipsoidModel::GetDistance(GetLatitude(), GetLongitude(), to.GetLatitude(), to.GetLongitude());
230 }
231
232 result
233 Coordinates::ToString(double degree, CoordinateFormat format, Tizen::Base::String& string)
234 {
235         SysTryReturn(NID_LOC, format == COORDINATE_FORMAT_DEGREE_MINUTE || format == COORDINATE_FORMAT_DEGREE_MINUTE_SECOND, E_INVALID_ARG, E_INVALID_ARG,
236                                  "[E_INVALID_ARG] The specified format(%x) is not proper.", format);
237
238         SysTryReturn(NID_LOC, MIN_LONGITUDE <= degree && degree < MAX_LONGITUDE, E_INVALID_ARG, E_INVALID_ARG,
239                                  "[E_INVALID_ARG] The supplied degree(%lf) is out of [-180, 180] range.", degree);
240
241         double intPart = 0.0;
242         double fractionalPart = 0.0;
243
244         fractionalPart = modf(degree, &intPart);
245         int degreeValue = (int) intPart;
246
247         if (degree < 0)
248         {
249                 fractionalPart *= -1.0;
250         }
251
252         String ret;
253         const int bufferSize = 20;
254         if (format == COORDINATE_FORMAT_DEGREE_MINUTE)
255         {
256                 double minute = fractionalPart * 60;
257                 double minuteFraction = modf(minute, &intPart);
258
259                 if (Double::Compare(minuteFraction, 0.0) == 0)
260                 {
261                         ret.Format(bufferSize, L"%d:%02d", degreeValue, (int) minute);
262                 }
263                 else
264                 {
265                         ret.Format(bufferSize, L"%d:%02.5f", degreeValue, minute);
266                 }
267         }
268         else // if (COORDINATE_FORMAT_DEGREE_MINUTE_SECOND == outputType)
269         {
270                 fractionalPart = modf(fractionalPart * 60, &intPart);
271
272                 int minute = (int) intPart;
273                 double second = fractionalPart * 60;
274                 double secondFraction = modf(second, &intPart);
275
276                 if (Double::Compare(second, 0.0) == 0 && Double::Compare(secondFraction, 0.0) == 0)
277                 {
278                         ret.Format(bufferSize, L"%d:%02d", degreeValue, (int) minute);
279                 }
280                 else
281                 {
282                         if (Double::Compare(secondFraction, 0.0) == 0)
283                         {
284                                 ret.Format(bufferSize, L"%d:%02d:%02d", degreeValue, (int) minute, (int) second);
285                         }
286                         else
287                         {
288                                 ret.Format(bufferSize, L"%d:%02d:%02.3f", degreeValue, (int) minute, second);
289                         }
290                 }
291         }
292
293         string = ret;
294         return E_SUCCESS;
295 }
296
297 result
298 Coordinates::Parse(const Tizen::Base::String& string, double& degree)
299 {
300         result r = E_SUCCESS;
301         double ret = 0.0;
302         CoordinateFormat type = COORDINATE_FORMAT_DEGREE_MINUTE;
303
304         StringTokenizer tokenizer(string, L":");
305         SysTryReturn(NID_LOC, tokenizer.GetTokenCount() <= 3, E_INVALID_ARG, E_INVALID_ARG,
306                                  "[E_INVALID_ARG] The coordinate(%ls) is in invalid format.", string.GetPointer());
307
308         if (3 == tokenizer.GetTokenCount())
309         {
310                 type = COORDINATE_FORMAT_DEGREE_MINUTE_SECOND;
311         }
312
313         String degreeValue(L"0");
314         tokenizer.GetNextToken(degreeValue);
315
316         int sign = 1;
317         int degreeInt = 0;
318         r = Integer::Decode(degreeValue, degreeInt);
319         SysTryReturn(NID_LOC, r == E_SUCCESS, E_INVALID_ARG, E_INVALID_ARG, "[E_INVALID_ARG] Failed to decode the degree part.");
320         SysTryReturn(NID_LOC, MIN_LONGITUDE <= degreeInt && degreeInt <= MAX_LONGITUDE, E_INVALID_ARG, E_INVALID_ARG,
321                                  "[E_INVALID_ARG] Degree(%d) is out of [-180, 180] range.", degreeInt);
322
323         String minute(L"0");
324         if (E_OUT_OF_RANGE == tokenizer.GetNextToken(minute))
325         {
326                 degree = degreeInt;
327                 return E_SUCCESS;
328         }
329
330         if (degreeInt < 0)
331         {
332                 sign = -1;
333                 degreeInt *= sign;
334         }
335
336         if (COORDINATE_FORMAT_DEGREE_MINUTE == type) // "DD:MM.DM"
337         {
338                 SysTryReturn(NID_LOC, minute.GetLength() <= 8, E_INVALID_ARG, E_INVALID_ARG,
339                                          "[E_INVALID_ARG] Minute(%ls) is too long.", minute.GetPointer());
340
341                 double minuteDouble = 0.0;
342                 r = Double::Parse(minute, minuteDouble);
343                 SysTryReturn(NID_LOC, r == E_SUCCESS, E_INVALID_ARG, E_INVALID_ARG, "[E_INVALID_ARG] Failed to decode the minute part.");
344                 SysTryReturn(NID_LOC, 0.0 <= minuteDouble && minuteDouble < 60.0, E_INVALID_ARG, E_INVALID_ARG,
345                                          "[E_INVALID_ARG] Minute(%f) is out of [0, 60] range.", minuteDouble);
346                 ret = sign * (((double) degreeInt) + (minuteDouble / 60.0));
347         }
348         else // if (COORDINATE_FORMAT_DEGREE_MINUTE_SECOND == type) "DD:MM:SS.SM"
349         {
350                 String second(L"0");
351                 tokenizer.GetNextToken(second);
352                 SysTryReturn(NID_LOC, second.GetLength() <= 6, E_INVALID_ARG, E_INVALID_ARG,
353                                          "[E_INVALID_ARG] Second(%ls) is too long.", second.GetPointer());
354
355                 int minuteInt = 0;
356                 r = Integer::Decode(minute, minuteInt);
357                 SysTryReturn(NID_LOC, r == E_SUCCESS, E_INVALID_ARG, E_INVALID_ARG, "[E_INVALID_ARG] Failed to decode the minute part.");
358                 SysTryReturn(NID_LOC, 0 <= minuteInt && minuteInt <= 59, E_INVALID_ARG, E_INVALID_ARG,
359                                          "[E_INVALID_ARG] Minute(%d) is out of [0, 59] range.", minuteInt);
360
361                 double secondDouble = 0.0;
362                 r = Double::Parse(second, secondDouble);
363                 SysTryReturn(NID_LOC, r == E_SUCCESS, E_INVALID_ARG, E_INVALID_ARG, "[E_INVALID_ARG] Failed to decode the second part.");
364                 SysTryReturn(NID_LOC, 0.0 <= secondDouble && secondDouble < 60.0, E_INVALID_ARG, E_INVALID_ARG,
365                                          "[E_INVALID_ARG] Second(%f) is out of [0, 60] range.", secondDouble);
366
367                 ret = sign * (((double) degreeInt) + ((double) minuteInt / 60.0) + (secondDouble / 3600.0));
368         }
369
370         SysTryReturn(NID_LOC, MIN_LONGITUDE <= ret && ret < MAX_LONGITUDE, E_INVALID_ARG, E_INVALID_ARG,
371                                  "[E_INVALID_ARG] Converted coordinate(%f) is out of [-180, 180] range.", ret);
372
373         degree = ret;
374         return E_SUCCESS;
375 }
376
377 Coordinates&
378 Coordinates::operator =(const Coordinates& rhs)
379 {
380         if (this == &rhs)
381         {
382                 return *this;
383         }
384
385         __latitude = rhs.__latitude;
386         __longitude = rhs.__longitude;
387         __altitude = rhs.__altitude;
388
389         return *this;
390 }
391 }}