2 * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
18 #include "mapzen_queue.h"
19 #include "mapzen_debug.h"
20 #include "mapzen_util.h"
21 #include "mapzen_restcurl.h"
24 #include "mapzen_plugin_internal.h"
25 #include "tangram_view.hpp"
27 #include <src/platform_tizen.h>
28 #include <Elementary.h>
33 #include <sys/syscall.h> // SYS_gettid
35 #define NORMAL_SCENE_FILE_PATH "/usr/share/maps/mapzen/scenes/bubble-wrap/bubble-wrap.yaml"
36 #define TERRAIN_SCENE_FILE_PATH "/usr/share/maps/mapzen/scenes/walkabout-style/walkabout-style.yaml"
39 TangramView::TangramView()
44 TangramView::~TangramView()
49 mapzen_error_e TangramView::create(maps_view_h view, maps_plugin_map_view_ready_cb callback, const char* providerKey)
52 return MAPZEN_ERROR_INVALID_PARAMETER;
55 int maps_error = MAPS_ERROR_NONE;
56 maps_error = maps_view_get_viewport(view, &m_image);
57 if (maps_error != MAPS_ERROR_NONE) {
58 return (mapzen_error_e)convert_maps_error_to_mapzen_error(maps_error);
61 maps_error = maps_view_get_screen_location(view, &m_x, &m_y, &m_w, &m_h);
62 if (maps_error != MAPS_ERROR_NONE) {
63 return (mapzen_error_e)convert_maps_error_to_mapzen_error(maps_error);
66 // Create an OpenGL context.
68 m_config = evas_gl_config_new();
70 MAPS_LOGE("evas_gl_config_new() failed");
71 return MAPZEN_ERROR_SERVICE_NOT_AVAILABLE;
74 m_config->color_format = EVAS_GL_RGBA_8888;
75 m_config->depth_bits = EVAS_GL_DEPTH_BIT_24;
76 m_config->stencil_bits = EVAS_GL_STENCIL_NONE;
77 m_config->options_bits = EVAS_GL_OPTIONS_DIRECT;
79 m_gl = evas_gl_new(evas_object_evas_get(m_image));
81 MAPS_LOGE("evas_gl_new() failed");
82 return MAPZEN_ERROR_SERVICE_NOT_AVAILABLE;
85 m_api = evas_gl_api_get(m_gl);
87 MAPS_LOGE("evas_gl_api_get() failed");
88 return MAPZEN_ERROR_SERVICE_NOT_AVAILABLE;
91 m_context = evas_gl_context_create(m_gl, nullptr);
93 MAPS_LOGE("evas_gl_context_create() failed");
94 return MAPZEN_ERROR_SERVICE_NOT_AVAILABLE;
98 // Set up rendering surface.
99 auto error = setupOpenGlSurface(view);
100 if (error != MAPZEN_ERROR_NONE) {
104 m_readyCb = callback;
105 // TODO: What to do for multiple instances
106 Tangram::setEvasGlAPI(m_api);
108 Tangram::UrlClient::Options urlOptions;
109 char* proxyAddress = NULL;
110 get_proxy_address(&proxyAddress);
112 urlOptions.proxyAddress = proxyAddress;
116 urlOptions.connectionTimeoutMs = 0;
117 urlOptions.requestTimeoutMs = 120000;
119 m_platform = std::make_shared<Tangram::TizenPlatform>(urlOptions);
121 m_uiThreadId = syscall(SYS_gettid);
123 m_platform->setRenderCallbackFunction([&]() {
125 if (m_uiThreadId == syscall(SYS_gettid)) {
127 evas_object_image_pixels_dirty_set(m_image, EINA_TRUE);
133 // NB: Since there is no safe way to use ecore_main_loop_thread_safe_call_async in a
134 // module that could be unloaded at runtime we use polling to check on the mainloop
135 // whether a render request came in.
136 // TODO only run timer when async tasks (Tile- and Scene-Loading) are in progress.
137 m_renderRequestTimer = ecore_timer_add(0.05, [](void *data){
138 auto tv = static_cast<TangramView*>(data);
141 evas_object_image_pixels_dirty_set((Evas_Object*)tv->m_image, EINA_TRUE);
146 // Set up the tangram map.
147 m_map.reset(new Tangram::Map(m_platform));
149 float scaleFactor = elm_config_scale_get();
150 MAPS_LOGD("evas_gl_context_create() set PixelScale %f", scaleFactor);
151 m_map->setPixelScale(scaleFactor);
154 m_providerKey = providerKey;
157 // Start loading the scene by setting the map type.
160 // Make the GL context current and perform GL setup.
161 evas_gl_make_current(m_gl, m_surface, m_context);
164 m_map->resize(m_w, m_h);
166 if (m_sceneLoaded && m_w > 1 && m_h > 1) {
167 readyMapCb((void*)view);
170 m_isInitialized = true;
172 return MAPZEN_ERROR_NONE;
175 mapzen_error_e TangramView::setupOpenGlSurface(maps_view_h view)
177 if (!view || !m_gl || !m_config || !m_image || !m_context) {
178 return MAPZEN_ERROR_INVALID_PARAMETER;
181 // Remove any previous pixel callback on the image.
182 evas_object_image_pixels_get_callback_set(m_image, nullptr, nullptr);
185 // Destroy the old surface.
186 evas_object_image_native_surface_set(m_image, nullptr);
187 evas_gl_surface_destroy(m_gl, m_surface);
193 evas_object_image_size_set(m_image, m_w, m_h);
195 Evas_Native_Surface native_surface;
196 m_surface = evas_gl_surface_create(m_gl, m_config, m_w, m_h);
198 MAPS_LOGE("evas_gl_surface_create() failed");
199 return MAPZEN_ERROR_SERVICE_NOT_AVAILABLE;
202 if (!evas_gl_native_surface_get(m_gl, m_surface, &native_surface)) {
203 // Could not get the native surface information, so destroy the surface and exit.
204 evas_gl_make_current(m_gl, nullptr, nullptr);
205 evas_gl_surface_destroy(m_gl, m_surface);
207 MAPS_LOGE("evas_gl_native_surface_get() failed");
208 return MAPZEN_ERROR_SERVICE_NOT_AVAILABLE;
211 // Set the native surface information and pixel callback on the image.
212 evas_object_image_native_surface_set(m_image, &native_surface);
213 evas_object_image_pixels_get_callback_set(m_image, pixelGetCb, view);
215 return MAPZEN_ERROR_NONE;
218 mapzen_error_e TangramView::destroy(maps_view_h view)
221 return MAPZEN_ERROR_INVALID_PARAMETER;
224 m_isInitialized = false;
225 m_sceneLoaded = false;
227 if (m_renderRequestTimer) {
228 ecore_timer_del(m_renderRequestTimer);
229 m_renderRequestTimer = nullptr;
233 evas_object_image_pixels_get_callback_set(m_image, nullptr, nullptr);
237 if (m_surface && m_context) {
238 evas_gl_make_current(m_gl, m_surface, m_context);
251 evas_object_image_native_surface_set(m_image, nullptr);
252 evas_gl_surface_destroy(m_gl, m_surface);
255 evas_gl_context_destroy(m_gl, m_context);
262 evas_gl_config_free(m_config);
265 return MAPZEN_ERROR_NONE;
268 mapzen_error_e TangramView::render(maps_view_h view, const maps_coordinates_h coord, double zoom, double angle)
270 if (!view || !coord) {
271 MAPS_LOGE("Render requested with invalid 'view' or 'coord'.");
272 return MAPZEN_ERROR_INVALID_PARAMETER;
275 if (!m_isInitialized) {
276 MAPS_LOGE("Render requested with view that is not initialized.");
277 return MAPZEN_ERROR_SERVICE_NOT_AVAILABLE;
282 int x = 0, y = 0, w = 0, h = 0;
283 maps_view_get_screen_location(view, &x, &y, &w, &h);
287 if (x != m_x || y != m_y || w != m_w || h != m_h) {
288 if ( (m_w <= 1 || m_h <= 1) && w > 1 && h > 1 && m_sceneLoaded) {
289 // Send a tangram view ready callback when we have a legit canvas size
290 readyMapCb((void*)view);
296 evas_gl_make_current(m_gl, m_surface, m_context);
297 m_map->resize(m_w, m_h);
298 setupOpenGlSurface(view);
301 if (m_zoom != zoom) {
303 m_map->setZoom(zoom);
306 if (m_angle != angle) {
308 m_map->setRotation(degrees_to_radians(angle));
311 double lng = 0, lat = 0;
312 maps_coordinates_get_longitude(coord, &lng);
313 maps_coordinates_get_latitude(coord, &lat);
315 if (m_lng != lng || m_lat != lat) {
318 m_map->setPosition(m_lng, m_lat);
321 m_map->getPlatform()->requestRender();
323 return MAPZEN_ERROR_NONE;
326 mapzen_error_e TangramView::moveCenter(maps_view_h view, int delta_x, int delta_y)
329 return MAPZEN_ERROR_INVALID_PARAMETER;
332 if (!m_isInitialized) {
333 return MAPZEN_ERROR_SERVICE_NOT_AVAILABLE;
336 if (delta_x == 0 && delta_y == 0) {
337 return MAPZEN_ERROR_NONE;
340 // The delta_x and delta_y values are in pixels, so we need to determine the equivalent displacement in
341 // longitude and latitude to set the new center position.
343 double x = 0.5 * m_w + (double)delta_x;
344 double y = 0.5 * m_h + (double)delta_y;
345 double lng = 0.0, lat = 0.0;
346 if (m_map->screenPositionToLngLat(x, y, &lng, &lat)) {
347 lng = wrap_longitude(lng);
348 lat = wrap_latitude(lat);
349 m_map->setPosition(lng, lat);
352 MAPS_LOGD("Moved with delta x: %d, y: %d to coordinates lon: %f, lat: %f", delta_x, delta_y, lng, lat);
354 return MAPZEN_ERROR_NONE;
357 mapzen_error_e TangramView::getCenter(maps_view_h view, maps_coordinates_h *center)
359 if (!view || !center) {
360 return MAPZEN_ERROR_INVALID_PARAMETER;
363 if (!m_isInitialized) {
364 return MAPZEN_ERROR_SERVICE_NOT_AVAILABLE;
367 double longitude = 0, latitude = 0;
368 m_map->getPosition(longitude, latitude);
370 longitude = wrap_longitude(longitude);
371 latitude = wrap_latitude(latitude);
372 if (*center == nullptr) {
373 maps_coordinates_create(latitude, longitude, center);
375 maps_coordinates_set_latitude(*center, latitude);
376 maps_coordinates_set_longitude(*center, longitude);
379 return MAPZEN_ERROR_NONE;
382 mapzen_error_e TangramView::setScalebarEnabled(maps_view_h view, bool enable)
384 return MAPZEN_ERROR_SERVICE_NOT_AVAILABLE;
387 mapzen_error_e TangramView::getScalebarEnabled(maps_view_h view, bool *enabled)
389 return MAPZEN_ERROR_SERVICE_NOT_AVAILABLE;
392 mapzen_error_e TangramView::convertScreenToGeolocation(maps_view_h view, int x, int y, maps_coordinates_h *coord)
394 if (!view || !coord) {
395 return MAPZEN_ERROR_INVALID_PARAMETER;
398 if (!m_isInitialized) {
399 return MAPZEN_ERROR_SERVICE_NOT_AVAILABLE;
402 double longitude = (double)x, latitude = (double)y;
403 m_map->screenPositionToLngLat(x, y, &longitude, &latitude);
405 longitude = wrap_longitude(longitude);
406 latitude = wrap_latitude(latitude);
407 if (*coord == nullptr) {
408 maps_coordinates_create(latitude, longitude, coord);
410 maps_coordinates_set_latitude(*coord, latitude);
411 maps_coordinates_set_longitude(*coord, longitude);
414 return MAPZEN_ERROR_NONE;
417 mapzen_error_e TangramView::convertGeolocationToScreen(maps_view_h view, const maps_coordinates_h coord, int *x, int *y)
419 if (!view || !coord) {
420 return MAPZEN_ERROR_INVALID_PARAMETER;
423 if (!m_isInitialized) {
424 return MAPZEN_ERROR_SERVICE_NOT_AVAILABLE;
428 maps_coordinates_get_latitude(coord, &lat);
429 maps_coordinates_get_longitude(coord, &lng);
431 double screenx, screeny;
432 m_map->lngLatToScreenPosition(lng, lat, &screenx, &screeny);
437 return MAPZEN_ERROR_NONE;
440 mapzen_error_e TangramView::getMinZoomLevel(maps_view_h view, int *zoom)
443 return MAPZEN_ERROR_NONE;
446 mapzen_error_e TangramView::getMaxZoomLevel(maps_view_h view, int *zoom)
449 return MAPZEN_ERROR_NONE;
452 mapzen_error_e TangramView::onViewObject(maps_view_h view, const maps_view_object_h object, maps_view_object_operation_e operation)
454 if (!view || !object || operation < MAPS_VIEW_OBJECT_ADD || operation > MAPS_VIEW_OBJECT_REMOVE) {
455 return MAPZEN_ERROR_INVALID_PARAMETER;
458 if (!m_isInitialized || !m_map) {
459 return MAPZEN_ERROR_SERVICE_NOT_AVAILABLE;
462 mapzen_error_e error = MAPZEN_ERROR_NONE;
464 TangramView *tv = nullptr;
465 int maps_error = maps_view_get_maps_plugin_view_handle(view, (void**)&tv);
466 if (maps_error != MAPS_ERROR_NONE || !tv) { return MAPZEN_ERROR_INVALID_PARAMETER; }
468 maps_view_object_type_e type = MAPS_VIEW_OBJECT_POLYLINE;
469 maps_view_object_get_type(object, &type);
471 if (type < MAPS_VIEW_OBJECT_POLYLINE || type > MAPS_VIEW_OBJECT_MARKER) { return MAPZEN_ERROR_INVALID_PARAMETER; }
473 auto& mapViewObjs = tv->mapViewObjects();
474 auto& mutex = tv->viewObjectMutex();
475 MapViewObjects::iterator iter;
476 MapViewObjects::iterator end;
478 std::lock_guard<std::mutex> lock(mutex);
479 iter = mapViewObjs.find(object);
480 end = mapViewObjs.end();
484 case MAPS_VIEW_OBJECT_ADD:
485 error = tv->addObject(object);
487 case MAPS_VIEW_OBJECT_SET_VISIBLE:
489 error = tv->setObjectVisible(object, iter->second);
492 case MAPS_VIEW_OBJECT_CHANGE:
494 error = tv->updateObject(object, iter->second);
497 case MAPS_VIEW_OBJECT_REMOVE:
498 error = tv->removeObject(object);
503 const char *oper_str[20] = { "ADD", "SET_VISIBLE", "MOVE", "CHANGE", "REMOVE"};
504 const char *type_str[20] = { "POLYLINE", "POLYGON", "MARKER", "UNKNOWN"};
506 MAPS_LOGD("Done Processing View Object: type=%s, operation=%s, object=%p",
507 (type >= MAPS_VIEW_OBJECT_POLYLINE && type <= MAPS_VIEW_OBJECT_MARKER) ? type_str[type] : "?",
508 (operation >= MAPS_VIEW_OBJECT_ADD && operation <= MAPS_VIEW_OBJECT_REMOVE) ? oper_str[operation] : "?",
511 if (error != MAPZEN_ERROR_NONE) {
512 MAPS_LOGD("Something went wrong in processing this ViewObject operation");
518 mapzen_error_e TangramView::addObject(maps_view_object_h object)
520 if (!object || !m_map) { return MAPZEN_ERROR_INVALID_PARAMETER; }
522 mapzen_error_e error = MAPZEN_ERROR_NONE;
523 Tangram::MarkerID tvMarker = 0;
524 maps_view_object_type_e type = MAPS_VIEW_OBJECT_POLYLINE;
526 maps_view_object_get_type(object, &type);
528 MapViewObjects::iterator iter;
529 MapViewObjects::iterator end;
532 std::lock_guard<std::mutex> lock(m_viewObjectMutex);
533 iter = m_mapViewObjs.find(object);
534 end = m_mapViewObjs.end();
537 tvMarker = m_map->markerAdd();
539 error = updateObject(object, tvMarker);
540 if (error == MAPZEN_ERROR_NONE) {
541 std::lock_guard<std::mutex> lock(m_viewObjectMutex);
542 m_mapViewObjs.insert(std::make_pair(object, tvMarker));
544 m_map->markerRemove(tvMarker);
553 mapzen_error_e TangramView::setObjectVisible(maps_view_object_h object, Tangram::MarkerID tvMarker)
555 if (!object || !tvMarker || !m_map) { return MAPZEN_ERROR_INVALID_PARAMETER; }
558 maps_view_object_get_visible(object, &visible);
560 m_map->markerSetVisible(tvMarker, visible);
561 return MAPZEN_ERROR_NONE;
564 mapzen_error_e TangramView::updateObject(maps_view_object_h object, Tangram::MarkerID tvMarker)
566 if (!object || !tvMarker || !m_map) { return MAPZEN_ERROR_INVALID_PARAMETER; }
568 mapzen_error_e error = MAPZEN_ERROR_NONE;
569 maps_view_object_type_e type = MAPS_VIEW_OBJECT_POLYLINE;
571 maps_view_object_get_type(object, &type);
574 case MAPS_VIEW_OBJECT_MARKER:
575 error = updateMarker(object, tvMarker);
577 case MAPS_VIEW_OBJECT_POLYLINE:
578 error = updatePolyline(object, tvMarker);
580 case MAPS_VIEW_OBJECT_POLYGON:
581 error = updatePolygon(object, tvMarker);
590 mapzen_error_e TangramView::getBitmapMarkerImage(maps_view_object_h object, unsigned char *&imgData, int &imgWidth, int &imgHeight) {
591 char *imgPath = nullptr;
592 Evas_Object *img = nullptr;
594 int error = MAPS_ERROR_NONE;
597 error = maps_view_object_marker_get_image_file(object, &imgPath);
598 if (error != MAPS_ERROR_NONE || !imgPath) { break; }
600 img = evas_object_image_add(evas_object_evas_get(m_image));
601 evas_object_image_file_set(img, imgPath, nullptr);
602 int err = evas_object_image_load_error_get(img);
603 if (err != EVAS_LOAD_ERROR_NONE) {
604 MAPS_LOGE("Failed to load marker image file: %s", imgPath);
610 evas_object_image_size_get(img, &imgWidth, &imgHeight);
611 imgSize = imgWidth * imgHeight * 4;
613 // Get Raw data pointer to the image
614 const unsigned char *srcData = (unsigned char *)evas_object_image_data_get(img, EINA_FALSE);
615 if (!srcData || imgSize <= 0) {
616 MAPS_LOGE("Failed to get image data from the evas image for the marker");
617 error = MAPS_ERROR_OUT_OF_MEMORY;
621 imgData = (unsigned char *)malloc(imgSize);
623 MAPS_LOGE("Failed to malloc!! for image data");
624 error = MAPS_ERROR_OUT_OF_MEMORY;
628 // convert data from rgba to bgra (also flip the image)
629 for (int i = 0; i < imgHeight; i++) {
630 for (int j = 0; j < imgWidth; j++) {
631 int offset = ((i * imgWidth) + j) * 4;
632 int offset_flip = (((imgHeight - 1 - i) * imgWidth) + j) * 4;
633 *(imgData + offset_flip) = *(srcData + offset + 2);
634 *(imgData + offset_flip + 1) = *(srcData + offset + 1);
635 *(imgData + offset_flip + 2) = *(srcData + offset);
636 *(imgData + offset_flip + 3) = *(srcData + offset + 3);
642 return (mapzen_error_e)convert_maps_error_to_mapzen_error(error);
645 mapzen_error_e TangramView::updateMarker(maps_view_object_h object, Tangram::MarkerID tvMarker)
647 maps_coordinates_h mapsCoord = nullptr;
648 double lat = 0.0, lng = 0.0;
649 int markerWidth = 0, markerHeight = 0;
650 int imgWidth = 0, imgHeight = 0;
651 int error = MAPS_ERROR_NONE;
652 unsigned char *imgData = nullptr;
654 const char styleFormat[] = "{ style: 'sdk-point-overlay', color: white, size: [%dpx, %dpx], collide: false, anchor: %s, transition: { [show, hide]: { time: 0s } } }";
656 static std::string anchor;
658 maps_view_marker_type_e type;
659 error = maps_view_object_marker_get_type(object, &type);
662 if (error != MAPS_ERROR_NONE || type < MAPS_VIEW_MARKER_PIN || type > MAPS_VIEW_MARKER_STICKER) { break; }
664 error = getBitmapMarkerImage(object, imgData, imgWidth, imgHeight);
666 if (error != MAPS_ERROR_NONE || !imgData) {
667 MAPS_LOGE("Failed getting image data from marker object, with error code: %d", error);
670 m_map->markerSetBitmap(tvMarker, imgWidth, imgHeight, reinterpret_cast<unsigned int *>(imgData));
674 if (type == MAPS_VIEW_MARKER_PIN) {
678 float scaleFactor = 1.0/elm_config_scale_get();
679 error = maps_view_object_marker_get_size(object, &markerWidth, &markerHeight);
680 if (error != MAPS_ERROR_NONE) { break; }
683 * - Sets the marker dimension to be image dimension if both the specified marker dimensions are zero
684 * - Sets the marker dimension such that aspect ratio is maintained when one of the marker dimensions is
687 if (markerWidth == 0 && markerHeight == 0) {
688 markerWidth = imgWidth;
689 markerHeight = imgHeight;
690 } else if (markerWidth == 0 && markerHeight > 0) {
691 markerWidth = (float)markerHeight * (float)imgWidth / (float)imgHeight;
692 } else if (markerWidth > 0 && markerHeight == 0) {
693 markerHeight = (float)markerWidth * (float)imgHeight / (float)imgWidth;
696 float scaledWidth = scaleFactor * markerWidth;
697 float scaledHeight = scaleFactor * markerHeight;
699 char styleString[256];
700 std::snprintf(styleString, sizeof(styleString), styleFormat, int(scaledWidth), int(scaledHeight), anchor.c_str());
702 MAPS_LOGD("Marker Style String: %s", styleString);
703 m_map->markerSetStylingFromString(tvMarker, styleString);
705 error = maps_view_object_marker_get_coordinates(object, &mapsCoord);
706 if (error != MAPS_ERROR_NONE) { break; }
708 error = maps_coordinates_get_longitude(mapsCoord, &lng);
709 if (error != MAPS_ERROR_NONE) {
710 maps_coordinates_destroy(mapsCoord);
714 error = maps_coordinates_get_latitude(mapsCoord, &lat);
715 if (error != MAPS_ERROR_NONE) {
716 maps_coordinates_destroy(mapsCoord);
720 maps_coordinates_destroy(mapsCoord);
721 m_map->markerSetPoint(tvMarker, Tangram::LngLat(lng, lat));
724 error = maps_view_object_marker_get_z_order(object, &drawOrder);
725 if (error != MAPS_ERROR_NONE) { break; }
726 m_map->markerSetDrawOrder(tvMarker, drawOrder);
729 return (mapzen_error_e)convert_maps_error_to_mapzen_error(error);
732 mapzen_error_e TangramView::updatePolyline(maps_view_object_h object, Tangram::MarkerID tvMarker)
734 int error = MAPS_ERROR_NONE;
735 Tangram::Coordinates coords = {};
736 unsigned char r = 0, g = 0, b = 0, a = 0;
739 const char styleFormat[] = "{ style: 'ux-route-line-overlay', color: [%d, %d, %d, %d], width: %dpx, order: 500 }";
742 error = maps_view_object_polyline_get_color(object, &r, &g, &b, &a);
743 if (error != MAPS_ERROR_NONE) { break; }
745 error = maps_view_object_polyline_get_width(object, &width);
746 if (error != MAPS_ERROR_NONE) { break; }
748 char styleString[256];
749 std::snprintf(styleString, sizeof(styleString), styleFormat, r, g, b, a, width);
751 MAPS_LOGD("Polyline Style String: %s", styleString);
753 m_map->markerSetStylingFromString(tvMarker, styleString);
755 error = maps_view_object_polyline_foreach_point(object, emplaceCoord, &coords);
756 if (error != MAPS_ERROR_NONE) { break; }
758 m_map->markerSetPolyline(tvMarker, coords.data(), static_cast<int>(coords.size()));
761 return (mapzen_error_e)convert_maps_error_to_mapzen_error(error);
764 mapzen_error_e TangramView::updatePolygon(maps_view_object_h object, Tangram::MarkerID tvMarker)
766 int error = MAPS_ERROR_NONE;
767 Tangram::Coordinates coords = {};
768 unsigned char r = 0, g = 0, b = 0, a = 0;
769 const char styleFormat[] = "{ style: 'polygons', color: [%d, %d, %d, %d] }";
772 error = maps_view_object_polygon_get_fill_color(object, &r, &g, &b, &a);
773 if (error != MAPS_ERROR_NONE) { break; }
775 char styleString[256];
776 std::snprintf(styleString, sizeof(styleString), styleFormat, r, g, b, a);
778 MAPS_LOGD("Polygon Style String: %s", styleString);
780 m_map->markerSetStylingFromString(tvMarker, styleString);
782 error = maps_view_object_polygon_foreach_point(object, emplaceCoord, &coords);
783 if (error != MAPS_ERROR_NONE) { break; }
785 int count = (int)coords.size();
786 m_map->markerSetPolygon(tvMarker, coords.data(), &count, 1);
789 return (mapzen_error_e)convert_maps_error_to_mapzen_error(error);
792 mapzen_error_e TangramView::removeObject(maps_view_object_h object)
794 if (!object || !m_map) { return MAPZEN_ERROR_INVALID_PARAMETER; }
796 mapzen_error_e error = MAPZEN_ERROR_NONE;
798 std::lock_guard<std::mutex> lock(m_viewObjectMutex);
799 auto iter = m_mapViewObjs.find(object);
800 if (iter != m_mapViewObjs.end()) {
802 m_map->markerRemove(iter->second);
804 iter = m_mapViewObjs.erase(iter);
805 error = MAPZEN_ERROR_NONE;
811 void TangramView::removeAllObjects()
813 std::lock_guard<std::mutex> lock(m_viewObjectMutex);
814 m_mapViewObjs.clear();
815 m_map->markerRemoveAll();
818 bool TangramView::emplaceCoord(int index, maps_coordinates_h coordinate, void *user_data)
820 if (!coordinate || !user_data) { return false; }
823 double lng = 0.0, lat = 0.0;
825 error = maps_coordinates_get_longitude(coordinate, &lng);
826 if (error != MAPS_ERROR_NONE) {
827 MAPS_LOGD("Not able to extract longitude from coordiate");
830 error = maps_coordinates_get_latitude(coordinate, &lat);
831 if (error != MAPS_ERROR_NONE) {
832 MAPS_LOGD("Not able to extract longitude from coordiate");
836 MAPS_LOGD("[%d] %f, %f", index+1, lng, lat);
838 Tangram::Coordinates *coords = static_cast<Tangram::Coordinates*>(user_data);
839 coords->emplace_back(lng, lat);
843 mapzen_error_e TangramView::captureSnapshot(maps_view_h view, void **data, int *width, int *height, maps_view_colorspace_type_e *cs)
846 return MAPZEN_ERROR_INVALID_PARAMETER;
849 if (!m_isInitialized) {
850 return MAPZEN_ERROR_SERVICE_NOT_AVAILABLE;
853 *data = (void*)malloc(m_w * m_h * sizeof(unsigned int));
855 return MAPZEN_ERROR_OUT_OF_MEMORY;
858 pixelGetCb(view, nullptr);
860 unsigned int *pixels = (unsigned int*)malloc(m_w * m_h * sizeof(unsigned int));
862 return MAPZEN_ERROR_OUT_OF_MEMORY;
865 m_map->captureSnapshot(pixels);
867 for (int i = 0; i < m_h; ++i) {
868 memcpy((unsigned int*)*data + m_w * i, pixels + m_w * (m_h - i - 1), m_w * sizeof(unsigned int));
871 *cs = MAPS_VIEW_COLORSPACE_RGBA8888;
876 return MAPZEN_ERROR_NONE;
880 void TangramView::setMapType(maps_view_h view)
886 std::vector<Tangram::SceneUpdate> sceneUpdates;
887 maps_view_type_e map_type;
888 maps_view_get_type(view, &map_type);
890 tangram_view_type newViewType = (tangram_view_type)convert_maps_view_type_to_tangram_view_type(map_type);
892 // If Scene is being reloaded then reset all the scene preferences to their defaults (building/transit/language/providerKey)
893 if (newViewType != m_viewType) {
894 m_buildingsEnabled = true;
895 m_publicTransitEnabled = false;
897 m_isProviderKeySet = false;
900 bool buildings_enabled = false;
901 maps_view_get_buildings_enabled(view, &buildings_enabled);
902 if (buildings_enabled != m_buildingsEnabled) {
903 m_buildingsEnabled = buildings_enabled;
904 if (m_buildingsEnabled) {
905 sceneUpdates.push_back( {"global.sdk_building_extrude", "true"} );
907 sceneUpdates.push_back( {"global.sdk_building_extrude", "false"} );
911 bool public_transit_enabled = false;
912 maps_view_get_public_transit_enabled(view, &public_transit_enabled);
913 if (public_transit_enabled != m_publicTransitEnabled) {
914 m_publicTransitEnabled = public_transit_enabled;
915 if (m_publicTransitEnabled) {
916 sceneUpdates.push_back( {"global.sdk_transit_overlay", "true"} );
918 sceneUpdates.push_back( {"global.sdk_transit_overlay", "false"} );
922 char* language = nullptr;
923 maps_view_get_language(view, &language);
924 if (m_language != language) {
925 m_language = language;
926 sceneUpdates.push_back( {"global.ux_language", m_language.substr(0, 2).c_str()} );
930 // set provider key for vector tiles
931 if (m_providerKey.size() > 0 && !m_isProviderKeySet) {
932 // block to hide key in log
933 //MAPS_LOGD("Queueing API key update: %s", m_providerKey.c_str());
934 sceneUpdates.push_back( {"global.sdk_mapzen_api_key", m_providerKey.c_str()} );
935 m_isProviderKeySet = true;
938 // Loading a new tangram scene resets the map states/caches.
939 if (newViewType != m_viewType) {
940 // When the scene is changed, update the 'sdk-point-overlay' style to remove it's texture;
941 // this allows us to use this style for markers with custom bitmaps.
942 sceneUpdates.push_back( {"styles.sdk-point-overlay.texture", "null"} );
944 const char* newSceneFile = NORMAL_SCENE_FILE_PATH;
945 switch(newViewType) {
946 case TANGRAM_VIEW_TERRAIN:
947 newSceneFile = TERRAIN_SCENE_FILE_PATH;
949 case TANGRAM_VIEW_NORMAL:
950 newSceneFile = NORMAL_SCENE_FILE_PATH;
955 m_viewType = newViewType;
956 m_map->loadSceneAsync(newSceneFile, false, sceneLoadedCb, (void*)view, sceneUpdates);
958 // bool traffic_enabled = false;
959 // maps_view_get_traffic_enabled(view, &traffic_enabled);
960 if (sceneUpdates.empty()) { return; }
961 m_map->queueSceneUpdate(sceneUpdates);
962 m_map->applySceneUpdates();
966 void TangramView::sceneLoadedCb(void *data) {
967 TangramView *tv = nullptr;
968 int maps_error = maps_view_get_maps_plugin_view_handle((maps_view_h)data, (void**)&tv);
969 if (maps_error != MAPS_ERROR_NONE || !tv) { return; }
971 // only do this for first scene load not for any sceneUpdates
972 if (!tv->isSceneLoaded()) {
973 if (tv->getWidth() > 1 && tv->getHeight() > 1) {
976 tv->setSceneLoaded(true);
980 void TangramView::readyMapCb(void *data)
982 TangramView *tv = nullptr;
983 int maps_error = maps_view_get_maps_plugin_view_handle((maps_view_h)data, (void**)&tv);
984 if (maps_error != MAPS_ERROR_NONE || !tv) { return; }
991 void TangramView::pixelGetCb(void *data, Evas_Object *obj)
993 TangramView *tv = nullptr;
994 int maps_error = maps_view_get_maps_plugin_view_handle(data, (void**)&tv);
995 if (maps_error != MAPS_ERROR_NONE || !tv) {
1001 if (!tv->m_gl || !tv->m_surface || !tv->m_context) {
1005 evas_gl_make_current(tv->m_gl, tv->m_surface, tv->m_context);
1006 tv->m_api->glViewport(0, 0, tv->m_w, tv->m_h);
1008 tv->m_map->update(0);
1009 tv->m_map->render();
1010 MAPS_LOGD("pixelGetCb called on TangramView");
1012 MAPS_LOGD("tv->m_map is null, in pixelGelCb");