Tizen C++ Coding Rules
[platform/core/location/maps-plugin-here.git] / src / here_view_objects.cpp
1 /*
2  * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 #include "here_view_objects.h"
18 #include "here_utils.h"
19
20 #include <graphic/Grp_Util.h>
21 #include <maps/GeoMapObjectMarker.h>
22 #include <maps/GeoMapObjectPolygon.h>
23 #include <maps/GeoMapObjectPolyline.h>
24
25
26 using namespace HERE_PLUGIN_NAMESPACE_PREFIX;
27
28 HERE_PLUGIN_BEGIN_NAMESPACE
29
30 HereViewObjects::HereViewObjects()
31 {
32         pthread_mutex_init(&__mutex, NULL);
33 }
34
35 HereViewObjects::~HereViewObjects()
36 {
37         pthread_mutex_destroy(&__mutex);
38 }
39
40 void HereViewObjects::set(GeoTiledMap *map, Evas *evas)
41 {
42         if (!map && !evas) removeAll();
43         __map = map;
44         __evas = evas;
45 }
46
47 here_error_e HereViewObjects::add(maps_view_object_h hObj)
48 {
49         if (!hObj) return HERE_ERROR_INVALID_PARAMETER;
50
51         here_error_e error = HERE_ERROR_INVALID_PARAMETER;
52         if (__currentObjects.find(hObj) == __currentObjects.end())
53                 error = __add(hObj);
54
55         if (error == HERE_ERROR_NONE) __invalidate(hObj);
56         return error;
57 }
58
59 here_error_e HereViewObjects::__add(maps_view_object_h hObj)
60 {
61         if (!hObj) return HERE_ERROR_INVALID_PARAMETER;
62         if (!__map) return HERE_ERROR_INVALID_OPERATION;
63
64         here_error_e error = HERE_ERROR_NONE;
65         GeoMapObject *hereObject = NULL;
66         maps_view_object_type_e type;
67         maps_view_object_get_type(hObj, &type);
68
69         switch(type) {
70         case MAPS_VIEW_OBJECT_MARKER:
71                 hereObject = new (std::nothrow) GeoMapObjectMarker;
72                 error = __updateMarker(hObj, (GeoMapObjectMarker*)hereObject);
73                 break;
74
75         case MAPS_VIEW_OBJECT_POLYGON:
76                 hereObject = new (std::nothrow) GeoMapObjectPolygon;
77                 error = __updatePolygon(hObj, (GeoMapObjectPolygon*)hereObject);
78                 break;
79
80         case MAPS_VIEW_OBJECT_POLYLINE:
81                 hereObject = new (std::nothrow) GeoMapObjectPolyline;
82                 error = __updatePolyline(hObj, (GeoMapObjectPolyline*)hereObject);
83                 break;
84 #ifdef TIZEN_3_0_NEXT_MS
85         case MAPS_VIEW_OBJECT_ROUTE:
86                 for (int i=0; i < 2; i++) {
87                         hereObject = new (std::nothrow) GeoMapObjectPolyline;
88                         if (hereObject) {
89                                 __map->AddObject(hereObject);
90                                 error = __updateRoute(hObj);
91                                 if (error != HERE_ERROR_NONE) break;
92                                 pthread_mutex_lock(&__mutex);
93                                 __currentObjects.insert(std::make_pair(hObj, (GeoMapObjectPolyline*)hereObject));
94                                 pthread_mutex_unlock(&__mutex);
95                         }
96
97                         hereObject = new (std::nothrow) GeoMapObjectMarker;
98                         if (hereObject) {
99                                 __map->AddObject(hereObject);
100                                 error = __updateRoute(hObj);
101                                 if (error != HERE_ERROR_NONE) break;
102                                 pthread_mutex_lock(&__mutex);
103                                 __currentObjects.insert(std::make_pair(hObj, (GeoMapObjectMarker*)hereObject));
104                                 pthread_mutex_unlock(&__mutex);
105                         }
106                 }
107                 break;
108 #endif /* TIZEN_3_0_NEXT_MS */
109         default:
110                 error = HERE_ERROR_INVALID_PARAMETER;
111                 break;
112         }
113
114         if (error != HERE_ERROR_NONE) {
115                 if (hereObject) delete hereObject;
116                 hereObject = NULL;
117         }
118
119         if (hereObject
120 #ifdef TIZEN_3_0_NEXT_MS
121                 && type != MAPS_VIEW_OBJECT_ROUTE
122 #endif /* TIZEN_3_0_NEXT_MS */
123         ) {
124                 __map->AddObject(hereObject);
125                 pthread_mutex_lock(&__mutex);
126                 __currentObjects.insert(std::make_pair(hObj, hereObject));
127                 pthread_mutex_unlock(&__mutex);
128         }
129
130         return error;
131 }
132
133 here_error_e HereViewObjects::remove(maps_view_object_h hObj)
134 {
135         here_error_e error = __remove(hObj);
136         if (error == HERE_ERROR_NONE) __invalidate(hObj);
137         return error;
138 }
139
140 here_error_e HereViewObjects::__remove(maps_view_object_h hObj)
141 {
142         if (!hObj) return HERE_ERROR_INVALID_PARAMETER;
143         if (!__map) return HERE_ERROR_INVALID_OPERATION;
144
145         here_error_e error = HERE_ERROR_NOT_FOUND;
146
147         VisualObjects::iterator it;
148         pthread_mutex_lock(&__mutex);
149         while ((it = __currentObjects.find(hObj)) != __currentObjects.end()) {
150                 __map->RemoveObject((GeoMapObject*)it->second);
151                 it = __currentObjects.erase(it);
152                 error = HERE_ERROR_NONE;
153         }
154         pthread_mutex_unlock(&__mutex);
155
156         return error;
157 }
158
159 here_error_e HereViewObjects::removeAll()
160 {
161         pthread_mutex_lock(&__mutex);
162         __currentObjects.clear();
163         __map->ClearMapObjects();
164         pthread_mutex_unlock(&__mutex);
165         __invalidate();
166
167         return HERE_ERROR_NONE;
168 }
169
170 here_error_e HereViewObjects::move(maps_view_object_h hObj)
171 {
172         if (!hObj) return HERE_ERROR_INVALID_PARAMETER;
173
174         VisualObjects::iterator it;
175         while ((it = __currentObjects.find(hObj)) != __currentObjects.end())
176                 MAPS_LOGD("TODO: implement moving");
177
178         return HERE_ERROR_NONE;
179 }
180
181 here_error_e HereViewObjects::update(maps_view_object_h hObj)
182 {
183         if (!hObj) return HERE_ERROR_INVALID_PARAMETER;
184
185         here_error_e error = HERE_ERROR_NOT_FOUND;
186
187         VisualObjects::iterator it = __currentObjects.find(hObj);
188         if (it != __currentObjects.end())
189                 error = __update(hObj, (GeoMapObject*)(it->second));
190
191         if (error == HERE_ERROR_NONE) __invalidate(hObj);
192         return error;
193 }
194
195 here_error_e HereViewObjects::__update(maps_view_object_h hObj, GeoMapObject *hereObject)
196 {
197         if (!hObj) return HERE_ERROR_INVALID_PARAMETER;
198
199         here_error_e error = HERE_ERROR_UNKNOWN;
200
201         do {
202                 maps_view_object_type_e type;
203                 maps_view_object_get_type(hObj, &type);
204
205                 switch(type) {
206                 case MAPS_VIEW_OBJECT_MARKER:
207                         error = __updateMarker(hObj, (GeoMapObjectMarker*)hereObject);
208                         break;
209
210                 case MAPS_VIEW_OBJECT_POLYGON:
211                         error = __updatePolygon(hObj, (GeoMapObjectPolygon*)hereObject);
212                         break;
213
214                 case MAPS_VIEW_OBJECT_POLYLINE:
215                         error = __updatePolyline(hObj, (GeoMapObjectPolyline*)hereObject);
216                         break;
217
218 #ifdef TIZEN_3_0_NEXT_MS
219                 case MAPS_VIEW_OBJECT_ROUTE:
220                         error = __updateRoute(hObj);
221                         break;
222 #endif /* TIZEN_3_0_NEXT_MS */
223
224                 default:
225                         break;
226                 }
227         } while (0);
228
229         return error;
230 }
231
232 here_error_e HereViewObjects::__updateMarker(maps_view_object_h hMarker, GeoMapObjectMarker *hereMarker)
233 {
234         if (!hMarker || !hereMarker)
235                 return HERE_ERROR_INVALID_PARAMETER;
236
237         if (!__evas || !__map)
238                 return HERE_ERROR_INVALID_OPERATION;
239
240
241         int error = MAPS_ERROR_NONE;
242         maps_view_marker_type_e type;
243         int nSize = 0, w, h;
244         char *szPath = NULL;
245         double lat, lng;
246         maps_coordinates_h mapsCoord;
247         Evas_Object *img = NULL;
248
249
250         do {
251                 /* image */
252                 error = maps_view_object_marker_get_type(hMarker, &type);
253                 if (error != MAPS_ERROR_NONE || type < MAPS_VIEW_MARKER_PIN || type > MAPS_VIEW_MARKER_STICKER) break;
254
255                 error = maps_view_object_marker_get_image_file(hMarker, &szPath);
256                 if (error != MAPS_ERROR_NONE || !szPath) break;
257
258                 img = evas_object_image_add(__evas);
259                 evas_object_image_file_set(img, szPath, NULL);
260                 int err = evas_object_image_load_error_get(img);
261
262                 if (err != EVAS_LOAD_ERROR_NONE) {
263                         MAPS_LOGE("Failed to load the image file for new marker. '%s'",
264                                 (szPath ? szPath : "null"));
265                         g_free(szPath);
266                         break;
267                 }
268                 g_free(szPath);
269
270                 evas_object_image_size_get(img, &w, &h);
271                 nSize = w * h * 4;
272
273                 unsigned char *src = (unsigned char*)evas_object_image_data_get(img, EINA_FALSE);
274                 if (!src || nSize <= 0) {
275                         MAPS_LOGE("Failed to get the image buffer of new marker");
276                         error = MAPS_ERROR_OUT_OF_MEMORY;
277                         break;
278                 }
279
280                 unsigned char *dst = (unsigned char*)malloc(nSize);
281                 if (!dst) {
282                         error = MAPS_ERROR_OUT_OF_MEMORY;
283                         break;
284                 }
285                 memcpy(dst, src, nSize);
286
287                 /* resize the marker image */
288                 int nw = 0, nh = 0;
289                 if (__resizeMarker(hMarker, w, h, &nw, &nh, &dst)) {
290                         w = nw;
291                         h = nh;
292                         nSize = w * h * 4;
293                         maps_view_object_marker_set_size(hMarker, w, h);
294                 }
295
296                 /* convert RGBA to BGRA for GL */
297                 _Util::ConvertRGBA2BGRA(dst, (unsigned)w, (unsigned)h);
298
299                 Bitmap bmp;
300                 bmp.Construct((const unsigned char*)dst, nSize, Dimension(w, h));
301                 hereMarker->SetBitmap(bmp);
302                 g_free(dst);
303
304
305                 /* position */
306                 maps_view_object_marker_get_coordinates(hMarker, &mapsCoord);
307                 maps_coordinates_get_latitude(mapsCoord, &lat);
308                 maps_coordinates_get_longitude(mapsCoord, &lng);
309                 maps_coordinates_destroy(mapsCoord);
310
311                 if (!HereUtils::IsValidCoord(lat, lng)) {
312                         error = MAPS_ERROR_INVALID_PARAMETER;
313                         break;
314                 }
315
316                 hereMarker->SetPosition(GeoCoordinates(lat, lng));
317
318                 /* origin */
319                 Tizen::Maps::FloatPoint fpntOrigin(0.5, 0.5);
320                 if (type == MAPS_VIEW_MARKER_PIN)
321                         fpntOrigin.y = 1.0;
322                 hereMarker->SetMarkerOrigin(fpntOrigin);
323
324                 /* z-order */
325                 int z_order = 0;
326                 maps_view_object_marker_get_z_order(hMarker, &z_order);
327                 hereMarker->SetZorder(z_order);
328         } while (0);
329
330         if (img) evas_object_del(img);
331         return (here_error_e)ConvertToHereError(error);
332 }
333
334 here_error_e HereViewObjects::__updatePolyline(maps_view_object_h hPolyline, GeoMapObjectPolyline *herePolyline)
335 {
336         if (!hPolyline || !herePolyline)
337                 return HERE_ERROR_INVALID_PARAMETER;
338
339         int error = MAPS_ERROR_NONE;
340         GeoCoordinateList coordList;
341         unsigned char r, g, b, a;
342         int nThickness;
343
344         do {
345                 error = maps_view_object_polyline_foreach_point(hPolyline, __foreachForCoordinates, &coordList);
346                 if (error != MAPS_ERROR_NONE) break;
347                 herePolyline->SetPath(coordList);
348
349                 error = maps_view_object_polyline_get_color(hPolyline, &r, &g, &b, &a);
350                 if (error != MAPS_ERROR_NONE) break;
351                 herePolyline->SetStrokeColor(Color(r, g, b, a));
352
353                 error = maps_view_object_polyline_get_width(hPolyline, &nThickness);
354                 if (error != MAPS_ERROR_NONE) break;
355                 herePolyline->SetStrokeThickness(nThickness);
356         } while (0);
357
358         return (here_error_e)ConvertToHereError(error);
359 }
360
361 here_error_e HereViewObjects::__updatePolygon(maps_view_object_h hPolygon, GeoMapObjectPolygon *herePolygon)
362 {
363         if (!hPolygon || !herePolygon)
364                 return HERE_ERROR_INVALID_PARAMETER;
365
366         int error = MAPS_ERROR_NONE;
367         GeoCoordinateList coordList;
368         unsigned char r, g, b, a;
369
370         do {
371                 error = maps_view_object_polygon_foreach_point(hPolygon, __foreachForCoordinates, &coordList);
372                 if (error != MAPS_ERROR_NONE) break;
373                 herePolygon->SetPath(coordList);
374
375                 error = maps_view_object_polygon_get_fill_color(hPolygon, &r, &g, &b, &a);
376                 if (error != MAPS_ERROR_NONE) break;
377                 herePolygon->SetFillColor(Color(r, g, b, a));
378         } while (0);
379
380         return (here_error_e)ConvertToHereError(error);
381 }
382
383 here_error_e HereViewObjects::__updateRoute(maps_view_object_h hRoute)
384 {
385 #ifdef TIZEN_3_0_NEXT_MS
386         if (!hRoute) return HERE_ERROR_INVALID_PARAMETER;
387
388         VisualObjects::iterator it;
389
390         if ((it = __currentObjects.find(hRoute)) != __currentObjects.end()) {
391                 maps_route_h route = NULL;
392                 int ret = maps_view_object_route_get_content(hRoute, &route);
393                 if (ret !=  MAPS_ERROR_NONE || !route)
394                         return HERE_ERROR_NONE;
395
396                 GeoCoordinateList coordList;
397                 GeoMapObjectPolyline *polyline_path = NULL, *polyline_seg = NULL;
398
399                 if (it->second->GetType() == GeoMapObject::GMO_Polyline) {
400                         if (!polyline_path) {
401                                 MAPS_LOGD("Route Path");
402                                 polyline_path = (GeoMapObjectPolyline*)it->second;
403                                 maps_route_foreach_path(route, __foreachForCoordinates, &coordList);
404                                 polyline_path->SetPath(coordList);
405                                 polyline_path->SetStrokeColor(Tizen::Maps::Color(255, 0, 0, 255));
406                                 polyline_path->SetStrokeThickness(3);
407                         } else if (!polyline_seg) {
408                                 MAPS_LOGD("Route Segments");
409                                 polyline_seg = (GeoMapObjectPolyline*)it->second;
410                                 maps_route_foreach_path(route, __foreachForCoordinates, &coordList);
411                                 polyline_seg->SetPath(coordList);
412                                 polyline_seg->SetStrokeColor(Tizen::Maps::Color(0, 255, 0, 255));
413                                 polyline_seg->SetStrokeThickness(3);
414                         }
415                 } else if (it->second->GetType() == GeoMapObject::GMO_Marker) {
416                         // to implement
417                 }
418                 maps_route_destroy(route);
419         }
420
421 #endif /* TIZEN_3_0_NEXT_MS */
422         return HERE_ERROR_NONE;
423 }
424
425 here_error_e HereViewObjects::setVisible(maps_view_object_h hObj)
426 {
427         if (!hObj) return HERE_ERROR_INVALID_PARAMETER;
428
429         bool visible;
430         maps_view_object_get_visible(hObj, &visible);
431         return __setVisible(hObj, visible);
432 }
433
434 here_error_e HereViewObjects::__setVisible(maps_view_object_h hObj, bool bVisible)
435 {
436         if (!hObj) return HERE_ERROR_INVALID_PARAMETER;
437
438         here_error_e error = HERE_ERROR_NOT_FOUND;
439
440         VisualObjects::iterator it;
441         for (it = __currentObjects.begin(); it != __currentObjects.end(); it++) {
442                 if (it->first == hObj) {
443                         ((GeoMapObject*)it->second)->SetVisible(bVisible);
444                         error = HERE_ERROR_NONE;
445                 }
446         }
447
448         if (error == HERE_ERROR_NONE) __invalidate(hObj);
449         return error;
450 }
451
452 bool HereViewObjects::__foreachForCoordinates(int index, maps_coordinates_h point, void *user_data)
453 {
454         if (!point || !user_data)
455                 return false;
456
457         if (!HereUtils::IsValid(*(maps_coordinates_s*)point))
458                 return false;
459
460         int error;
461         double lat = 0.0, lng = 0.0;
462
463         do {
464                 error = maps_coordinates_get_latitude(point, &lat);
465                 if (error != MAPS_ERROR_NONE) break;
466
467                 error = maps_coordinates_get_longitude(point, &lng);
468                 if (error != MAPS_ERROR_NONE) break;
469         } while (0);
470
471         MAPS_LOGD("[%d] %f,%f", index+1, lat, lng);
472
473         GeoCoordinateList *coordList = (GeoCoordinateList*)user_data;
474         coordList->push_back(GeoCoordinates(lat, lng));
475         return true;
476 }
477
478 bool HereViewObjects::__foreachForAddingGroupObjects(int index, int total, maps_view_object_h object, void *user_data)
479 {
480         if (!user_data) return false;
481
482         HereViewObjects *hereViewObjects = (HereViewObjects*)user_data;
483         here_error_e error = hereViewObjects->add(object);
484         return (error == HERE_ERROR_NONE);
485 }
486
487 bool HereViewObjects::__foreachForRemovingGroupObjects(int index, int total, maps_view_object_h object, void *user_data)
488 {
489         if (!user_data) return false;
490
491         HereViewObjects *hereViewObjects = (HereViewObjects*)user_data;
492         here_error_e error = hereViewObjects->remove(object);
493         return (error == HERE_ERROR_NONE);
494 }
495
496 bool HereViewObjects::__foreachForUpdatingGroupObjects(int index, int total, maps_view_object_h object, void *user_data)
497 {
498         if (!user_data) return false;
499
500         HereViewObjects *hereViewObjects = (HereViewObjects*)user_data;
501         here_error_e error = hereViewObjects->update(object);
502         return (error == HERE_ERROR_NONE);
503 }
504
505 bool HereViewObjects::__foreachForSettingVisibleGroupObjects(int index, int total, maps_view_object_h object, void *user_data)
506 {
507         if (!user_data) return false;
508
509         HereViewObjects *hereViewObjects = (HereViewObjects*)user_data;
510         here_error_e error = hereViewObjects->setVisible(object);
511         return (error == HERE_ERROR_NONE);
512 }
513
514 bool HereViewObjects::__resizeMarker(maps_view_object_h hMarker,
515                                         const int originWidth, const int originHeight,
516                                         int *newWidth, int *newHeight, unsigned char **bitmap)
517 {
518         if (!hMarker || !newWidth || !newHeight || !bitmap || !*bitmap)
519                 return false;
520
521         int resizedWidth = 0, resizedHeight = 0;
522         maps_view_object_marker_get_size(hMarker, &resizedWidth, &resizedHeight);
523
524         if (__resizeBitmap(bitmap, originWidth, originHeight, resizedWidth, resizedHeight)) {
525                 *newWidth = resizedWidth;
526                 *newHeight = resizedHeight;
527                 return true;
528         }
529         return false;
530 }
531
532 bool HereViewObjects::__resizeBitmap(unsigned char **curBmp, int curWidth, int curHeight, int newWidth, int newHeight)
533 {
534         if (!curBmp || curWidth <= 0 || curHeight <= 0 || newWidth <= 0 || newHeight <= 0) return false;
535         if (curWidth == newWidth && curHeight == newHeight) return false;
536
537         unsigned char* newBmp = new unsigned char[newWidth * newHeight * 4];
538
539         double scaleWidth =  (double)newWidth / (double)curWidth;
540         double scaleHeight = (double)newHeight / (double)curHeight;
541
542         int newPixel, curPixel;
543
544         for (int y = 0; y < newHeight; y++) {
545             for (int x = 0; x < newWidth; x++) {
546                 newPixel = (y * (newWidth *4)) + (x * 4);
547                 curPixel = (((int)(y / scaleHeight) * (curWidth * 4)) + ((int)(x / scaleWidth) * 4));
548
549                 newBmp[newPixel    ] =  (*curBmp)[curPixel    ];
550                 newBmp[newPixel + 1] =  (*curBmp)[curPixel + 1];
551                 newBmp[newPixel + 2] =  (*curBmp)[curPixel + 2];
552                 newBmp[newPixel + 3] =  (*curBmp)[curPixel + 3];
553             }
554         }
555
556         delete [] *curBmp;
557         *curBmp = newBmp;
558         return true;
559 }
560
561 void HereViewObjects::__invalidate(maps_view_object_h hObj)
562 {
563         maps_view_object_type_e type;
564         maps_view_object_get_type(hObj, &type);
565
566         if (!hObj || type != MAPS_VIEW_OBJECT_MARKER)
567                 __map->InvalidateMapObjects();
568         else
569                 __map->InvalidateMapMarkers();
570 }
571
572 HERE_PLUGIN_END_NAMESPACE