From 0797dbe61e096864a12e7179b4af258fd04d6eee Mon Sep 17 00:00:00 2001 From: Tomas Vajda Date: Fri, 29 Nov 2019 17:01:21 +0100 Subject: [PATCH 1/2] Add support for updating and deleting polyline feature --- core/include/tangram/data/clientDataSource.h | 8 ++- core/src/data/clientDataSource.cpp | 69 +++++++++++++++++- .../tangram/src/main/cpp/jniExports.cpp | 53 +++++++++++++- .../main/java/com/mapzen/tangram/MapData.java | 72 ++++++++++++++++++- .../com/mapzen/tangram/geometry/Geometry.java | 2 +- .../com/mapzen/tangram/geometry/Polyline.java | 17 +++-- 6 files changed, 207 insertions(+), 14 deletions(-) diff --git a/core/include/tangram/data/clientDataSource.h b/core/include/tangram/data/clientDataSource.h index 284a55a7a5..6b89ffe0fe 100644 --- a/core/include/tangram/data/clientDataSource.h +++ b/core/include/tangram/data/clientDataSource.h @@ -50,11 +50,17 @@ class ClientDataSource : public TileSource { void addPointFeature(Properties&& properties, LngLat coordinates); - void addPolylineFeature(Properties&& properties, PolylineBuilder&& polyline); + uint64_t addPolylineFeature(Properties&& properties, PolylineBuilder&& polyline); void addPolygonFeature(Properties&& properties, PolygonBuilder && polygon); + void updatePolylineFeature(uint64_t id, const Coordinates& coordinates); + + void updatePolylineFeature(uint64_t id, const Properties&& properties); + + void removePolylineFeature(uint64_t id); + // Transform added feature data into tiles. void generateTiles(); diff --git a/core/src/data/clientDataSource.cpp b/core/src/data/clientDataSource.cpp index 1590c9767c..788573374d 100644 --- a/core/src/data/clientDataSource.cpp +++ b/core/src/data/clientDataSource.cpp @@ -38,6 +38,7 @@ struct ClientDataSource::Storage { std::unique_ptr tiles; geometry::feature_collection features; std::vector properties; + std::map polylineIds; }; struct ClientDataSource::PolylineBuilderData : mapbox::geometry::line_string { @@ -260,14 +261,21 @@ void ClientDataSource::addPointFeature(Properties&& properties, LngLat coordinat m_store->properties.emplace_back(properties); } -void ClientDataSource::addPolylineFeature(Properties&& properties, PolylineBuilder&& polyline) { +uint64_t ClientDataSource::addPolylineFeature(Properties&& properties, PolylineBuilder&& polyline) { std::lock_guard lock(m_mutexStore); - uint64_t id = m_store->features.size(); + uint64_t i = m_store->features.size(); + uint64_t id = m_store->polylineIds.size(); + + properties.set("id", std::to_string(id)); + auto geom = std::move(polyline.data); - m_store->features.emplace_back(*geom, id); + m_store->features.emplace_back(*geom, i); m_store->properties.emplace_back(properties); + m_store->polylineIds.insert(std::pair(id, i)); + + return id; } void ClientDataSource::addPolygonFeature(Properties&& properties, PolygonBuilder&& polygon) { @@ -280,6 +288,61 @@ void ClientDataSource::addPolygonFeature(Properties&& properties, PolygonBuilder m_store->properties.emplace_back(properties); } +void ClientDataSource::updatePolylineFeature(uint64_t id, const Coordinates& coordinates) { + + std::lock_guard lock(m_mutexStore); + + std::map::iterator findIt = m_store->polylineIds.find(id); + + if (findIt != m_store->polylineIds.end() && findIt->second < m_store->features.size()) { + uint64_t i = findIt->second; + + geometry::line_string geom; + for (auto &p : coordinates) { + geom.emplace_back(p.longitude, p.latitude); + } + + m_store->features[i] = mapbox::geometry::feature(geom, i); + } +} + +void ClientDataSource::updatePolylineFeature(uint64_t id, const Properties&& properties) { + + std::lock_guard lock(m_mutexStore); + + std::map::iterator findIt = m_store->polylineIds.find(id); + + if (findIt != m_store->polylineIds.end() && findIt->second < m_store->properties.size()) { + uint64_t i = findIt->second; + + for (int j = 0; j < properties.items().size(); ++j) { + m_store->properties[i].set(properties.items()[j].key, + properties.getString(properties.items()[j].key)); + } + } +} + +void ClientDataSource::removePolylineFeature(uint64_t id) { + + std::lock_guard lock(m_mutexStore); + + std::map::iterator findIt = m_store->polylineIds.find(id); + + if (findIt != m_store->polylineIds.end() && findIt->second < m_store->features.size()) { + uint64_t i = findIt->second; + + m_store->features.erase(std::next(m_store->features.begin(), i)); + m_store->properties.erase(std::next(m_store->properties.begin(), i)); + + for (std::map::iterator it = m_store->polylineIds.begin(); it != m_store->polylineIds.end(); ++it) { + if (it->second > i) { + it->second = it->second - 1; + m_store->features[it->second].id = it->second; + } + } + } +} + struct add_geometry { static constexpr double extent = 4096.0; diff --git a/platforms/android/tangram/src/main/cpp/jniExports.cpp b/platforms/android/tangram/src/main/cpp/jniExports.cpp index ac154321e1..5ad13bc51e 100644 --- a/platforms/android/tangram/src/main/cpp/jniExports.cpp +++ b/platforms/android/tangram/src/main/cpp/jniExports.cpp @@ -556,7 +556,7 @@ void MapController(ClearTileSource)(JNIEnv* jniEnv, jobject obj, jlong mapPtr, j #define MapData(NAME) FUNC(MapData, NAME) -void MapData(AddFeature)(JNIEnv* jniEnv, jobject obj, jlong sourcePtr, jdoubleArray jcoordinates, +jlong MapData(AddFeature)(JNIEnv* jniEnv, jobject obj, jlong sourcePtr, jdoubleArray jcoordinates, jintArray jrings, jobjectArray jproperties) { auto_source(sourcePtr); @@ -579,6 +579,8 @@ void MapData(AddFeature)(JNIEnv* jniEnv, jobject obj, jlong sourcePtr, jdoubleAr auto* coordinates = jniEnv->GetDoubleArrayElements(jcoordinates, NULL); + uint64_t id = 0; + if (nRings > 0) { // If rings are defined, this is a polygon feature. auto* rings = jniEnv->GetIntArrayElements(jrings, NULL); @@ -602,13 +604,60 @@ void MapData(AddFeature)(JNIEnv* jniEnv, jobject obj, jlong sourcePtr, jdoubleAr for (size_t i = 0; i < nPoints; i++) { builder.addPoint(LngLat(coordinates[2 * i], coordinates[2 * i + 1])); } - source->addPolylineFeature(std::move(properties), std::move(builder)); + id = source->addPolylineFeature(std::move(properties), std::move(builder)); } else { // This is a point feature. source->addPointFeature(std::move(properties), LngLat(coordinates[0], coordinates[1])); } jniEnv->ReleaseDoubleArrayElements(jcoordinates, coordinates, JNI_ABORT); + + return id; +} + +void MapData(UpdatePolylinePoints)(JNIEnv* jniEnv, jobject obj, jlong sourcePtr, jlong id, jdoubleArray jcoordinates) { + + auto_source(sourcePtr); + + size_t n_points = jniEnv->GetArrayLength(jcoordinates) / 2; + + auto* coordinates = jniEnv->GetDoubleArrayElements(jcoordinates, NULL); + + std::vector lngLatCoordinates; + for (size_t i = 0; i < n_points; ++i) { + lngLatCoordinates.push_back({coordinates[2 * i], coordinates[2 * i + 1]}); + } + source->updatePolylineFeature(static_cast(id), lngLatCoordinates); + + jniEnv->ReleaseDoubleArrayElements(jcoordinates, coordinates, JNI_ABORT); +} + +void MapData(UpdatePolylineProperties)(JNIEnv* jniEnv, jobject obj, jlong sourcePtr, jlong id, jobjectArray jproperties) { + + auto_source(sourcePtr); + + size_t n_properties = (jproperties == NULL) ? 0 : jniEnv->GetArrayLength(jproperties) / 2; + + Properties properties; + + for (size_t i = 0; i < n_properties; ++i) { + jstring jkey = (jstring) (jniEnv->GetObjectArrayElement(jproperties, 2 * i)); + jstring jvalue = (jstring) (jniEnv->GetObjectArrayElement(jproperties, 2 * i + 1)); + auto key = stringFromJString(jniEnv, jkey); + auto value = stringFromJString(jniEnv, jvalue); + properties.set(key, value); + jniEnv->DeleteLocalRef(jkey); + jniEnv->DeleteLocalRef(jvalue); + } + + source->updatePolylineFeature(static_cast(id), std::move(properties)); +} + +void MapData(RemovePolyline)(JNIEnv* jniEnv, jobject obj, jlong sourcePtr, jlong id) { + + auto_source(sourcePtr); + + source->removePolylineFeature(static_cast(id)); } void MapData(AddGeoJson)(JNIEnv* jniEnv, jobject obj, jlong sourcePtr, jstring geojson) { diff --git a/platforms/android/tangram/src/main/java/com/mapzen/tangram/MapData.java b/platforms/android/tangram/src/main/java/com/mapzen/tangram/MapData.java index 7049bb4512..9e5c3db057 100644 --- a/platforms/android/tangram/src/main/java/com/mapzen/tangram/MapData.java +++ b/platforms/android/tangram/src/main/java/com/mapzen/tangram/MapData.java @@ -54,6 +54,72 @@ public void setFeatures(@NonNull final List features) { } } + /** + * Add a feature to this data collection. + * @param feature The feature to add + */ + public long addFeature(@NonNull final Geometry feature) { + final MapController map = mapController; + if (map == null) { + return 0; + } + synchronized (this) { + long id = nativeAddFeature(pointer, + feature.getCoordinateArray(), + feature.getRingArray(), + feature.getPropertyArray()); + nativeGenerateTiles(pointer); + return id; + } + } + + /** + * Update polyline coordinates + * @param id Id of polyline to update + * @param coordinates New coordinates of a polyline + */ + public void updatePolyline(long id, List coordinates) { + final MapController map = mapController; + if (map == null) { + return; + } + synchronized (this) { + nativeUpdatePolylinePoints(pointer, id, Polyline.toCoordinateArray(coordinates)); + nativeGenerateTiles(pointer); + } + } + + /** + * Update polyline coordinates + * @param id Id of polyline to update + * @param properties New properties of a polyline + */ + public void updatePolyline(long id, Map properties) { + final MapController map = mapController; + if (map == null) { + return; + } + synchronized (this) { + nativeUpdatePolylineProperties(pointer, id, Geometry.getStringMapAsArray(properties)); + nativeGenerateTiles(pointer); + } + } + + /** + * Remove polyline + * @param id Id of polyline to remove + */ + public void removePolyline(long id) { + final MapController map = mapController; + if (map == null) { + return; + } + synchronized (this) { + nativeRemovePolyline(pointer, id); + nativeGenerateTiles(pointer); + } + } + /** * Assign features described in a GeoJSON string to this collection. This will replace any previously assigned feature lists or GeoJSON data. * @param data A string containing a GeoJSON FeatureCollection @@ -103,7 +169,11 @@ public void clear() { } } - private native void nativeAddFeature(long sourcePtr, double[] coordinates, int[] rings, String[] properties); + private native long nativeAddFeature(long sourcePtr, double[] coordinates, int[] rings, String[] properties); private native void nativeAddGeoJson(long sourcePtr, String geoJson); private native void nativeGenerateTiles(long sourcePtr); + + private native void nativeUpdatePolylinePoints(long sourcePtr, long id, double[] coordinates); + private native void nativeUpdatePolylineProperties(long sourcePtr, long id, String[] properties); + private native void nativeRemovePolyline(long sourcePtr, long id); } diff --git a/platforms/android/tangram/src/main/java/com/mapzen/tangram/geometry/Geometry.java b/platforms/android/tangram/src/main/java/com/mapzen/tangram/geometry/Geometry.java index 52581baf99..7f1b3145e0 100644 --- a/platforms/android/tangram/src/main/java/com/mapzen/tangram/geometry/Geometry.java +++ b/platforms/android/tangram/src/main/java/com/mapzen/tangram/geometry/Geometry.java @@ -28,7 +28,7 @@ public String[] getPropertyArray() { } @NonNull - protected String[] getStringMapAsArray(@NonNull final Map properties) { + public static String[] getStringMapAsArray(@NonNull final Map properties) { final String[] out = new String[properties.size() * 2]; int i = 0; for (final Map.Entry entry : properties.entrySet()) { diff --git a/platforms/android/tangram/src/main/java/com/mapzen/tangram/geometry/Polyline.java b/platforms/android/tangram/src/main/java/com/mapzen/tangram/geometry/Polyline.java index 28c2c1cea3..5b2c028325 100644 --- a/platforms/android/tangram/src/main/java/com/mapzen/tangram/geometry/Polyline.java +++ b/platforms/android/tangram/src/main/java/com/mapzen/tangram/geometry/Polyline.java @@ -15,6 +15,16 @@ @Keep public class Polyline extends Geometry { + public static double[] toCoordinateArray(List polyline) { + double[] coordinates = new double[polyline.size() * 2]; + int i = 0; + for (final LngLat point : polyline) { + coordinates[i++] = point.longitude; + coordinates[i++] = point.latitude; + } + return coordinates; + } + /** * Create a polyline geometry with properties. * @param polyline A list of coordinates that define the line segments of the feature. @@ -22,12 +32,7 @@ public class Polyline extends Geometry { * the scene file used by the map; may be null. */ public Polyline(@NonNull final List polyline, @Nullable final Map properties) { - this.coordinates = new double[polyline.size() * 2]; - int i = 0; - for (final LngLat point : polyline) { - coordinates[i++] = point.longitude; - coordinates[i++] = point.latitude; - } + this.coordinates = toCoordinateArray(polyline); if (properties != null) { this.properties = getStringMapAsArray(properties); } From 013c045b13950cc036703f116e465503078ccfa0 Mon Sep 17 00:00:00 2001 From: Tomas Vajda Date: Mon, 11 May 2020 23:53:12 +0200 Subject: [PATCH 2/2] Add support for updating and deleting point and polygon features --- core/include/tangram/data/clientDataSource.h | 17 ++- core/src/data/clientDataSource.cpp | 135 +++++++++++++++++- .../tangram/src/main/cpp/jniExports.cpp | 88 +++++++++++- .../main/java/com/mapzen/tangram/MapData.java | 104 +++++++++++++- 4 files changed, 332 insertions(+), 12 deletions(-) diff --git a/core/include/tangram/data/clientDataSource.h b/core/include/tangram/data/clientDataSource.h index 6b89ffe0fe..678c6f81c7 100644 --- a/core/include/tangram/data/clientDataSource.h +++ b/core/include/tangram/data/clientDataSource.h @@ -48,19 +48,30 @@ class ClientDataSource : public TileSource { // Add geometry from a GeoJSON string void addData(const std::string& _data); - void addPointFeature(Properties&& properties, LngLat coordinates); + uint64_t addPointFeature(Properties&& properties, LngLat coordinates); uint64_t addPolylineFeature(Properties&& properties, PolylineBuilder&& polyline); - void addPolygonFeature(Properties&& properties, PolygonBuilder - && polygon); + uint64_t addPolygonFeature(Properties&& properties, PolygonBuilder&& polygon); + + void updatePointFeature(uint64_t id, const LngLat coordinate); void updatePolylineFeature(uint64_t id, const Coordinates& coordinates); + void updatePolygonFeature(uint64_t id, const Coordinates& coordinates); + + void updatePointFeature(uint64_t id, const Properties&& properties); + void updatePolylineFeature(uint64_t id, const Properties&& properties); + void updatePolygonFeature(uint64_t id, const Properties&& properties); + + void removePointFeature(uint64_t id); + void removePolylineFeature(uint64_t id); + void removePolygonFeature(uint64_t id); + // Transform added feature data into tiles. void generateTiles(); diff --git a/core/src/data/clientDataSource.cpp b/core/src/data/clientDataSource.cpp index 788573374d..ed78b0b09f 100644 --- a/core/src/data/clientDataSource.cpp +++ b/core/src/data/clientDataSource.cpp @@ -38,7 +38,9 @@ struct ClientDataSource::Storage { std::unique_ptr tiles; geometry::feature_collection features; std::vector properties; + std::map pointIds; std::map polylineIds; + std::map polygonIds; }; struct ClientDataSource::PolylineBuilderData : mapbox::geometry::line_string { @@ -250,15 +252,22 @@ void ClientDataSource::addData(const std::string& _data) { std::make_move_iterator(features.end())); } -void ClientDataSource::addPointFeature(Properties&& properties, LngLat coordinates) { +uint64_t ClientDataSource::addPointFeature(Properties&& properties, LngLat coordinates) { std::lock_guard lock(m_mutexStore); geometry::point geom {coordinates.longitude, coordinates.latitude}; - uint64_t id = m_store->features.size(); - m_store->features.emplace_back(geom, id); + uint64_t i = m_store->features.size(); + uint64_t id = m_store->pointIds.size(); + + properties.set("id", std::to_string(id)); + + m_store->features.emplace_back(geom, i); m_store->properties.emplace_back(properties); + m_store->pointIds.insert(std::pair(id, i)); + + return id; } uint64_t ClientDataSource::addPolylineFeature(Properties&& properties, PolylineBuilder&& polyline) { @@ -278,14 +287,36 @@ uint64_t ClientDataSource::addPolylineFeature(Properties&& properties, PolylineB return id; } -void ClientDataSource::addPolygonFeature(Properties&& properties, PolygonBuilder&& polygon) { +uint64_t ClientDataSource::addPolygonFeature(Properties&& properties, PolygonBuilder&& polygon) { std::lock_guard lock(m_mutexStore); - uint64_t id = m_store->features.size(); + uint64_t i = m_store->features.size(); + uint64_t id = m_store->polygonIds.size(); + + properties.set("id", std::to_string(id)); + auto geom = std::move(polygon.data); - m_store->features.emplace_back(*geom, id); + m_store->features.emplace_back(*geom, i); m_store->properties.emplace_back(properties); + m_store->polygonIds.insert(std::pair(id, i)); + + return id; +} + +void ClientDataSource::updatePointFeature(uint64_t id, const LngLat coordinate) { + + std::lock_guard lock(m_mutexStore); + + std::map::iterator findIt = m_store->pointIds.find(id); + + if (findIt != m_store->pointIds.end() && findIt->second < m_store->features.size()) { + uint64_t i = findIt->second; + + geometry::point geom {coordinate.longitude, coordinate.latitude}; + + m_store->features[i] = mapbox::geometry::feature(geom, i); + } } void ClientDataSource::updatePolylineFeature(uint64_t id, const Coordinates& coordinates) { @@ -306,6 +337,40 @@ void ClientDataSource::updatePolylineFeature(uint64_t id, const Coordinates& coo } } +void ClientDataSource::updatePolygonFeature(uint64_t id, const Coordinates& coordinates) { + + std::lock_guard lock(m_mutexStore); + + std::map::iterator findIt = m_store->polygonIds.find(id); + + if (findIt != m_store->polygonIds.end() && findIt->second < m_store->features.size()) { + uint64_t i = findIt->second; + + geometry::line_string geom; + for (auto &p : coordinates) { + geom.emplace_back(p.longitude, p.latitude); + } + + m_store->features[i] = mapbox::geometry::feature(geom, i); + } +} + +void ClientDataSource::updatePointFeature(uint64_t id, const Properties&& properties) { + + std::lock_guard lock(m_mutexStore); + + std::map::iterator findIt = m_store->pointIds.find(id); + + if (findIt != m_store->pointIds.end() && findIt->second < m_store->properties.size()) { + uint64_t i = findIt->second; + + for (int j = 0; j < properties.items().size(); ++j) { + m_store->properties[i].set(properties.items()[j].key, + properties.getString(properties.items()[j].key)); + } + } +} + void ClientDataSource::updatePolylineFeature(uint64_t id, const Properties&& properties) { std::lock_guard lock(m_mutexStore); @@ -322,6 +387,43 @@ void ClientDataSource::updatePolylineFeature(uint64_t id, const Properties&& pro } } +void ClientDataSource::updatePolygonFeature(uint64_t id, const Properties&& properties) { + + std::lock_guard lock(m_mutexStore); + + std::map::iterator findIt = m_store->polygonIds.find(id); + + if (findIt != m_store->polygonIds.end() && findIt->second < m_store->properties.size()) { + uint64_t i = findIt->second; + + for (int j = 0; j < properties.items().size(); ++j) { + m_store->properties[i].set(properties.items()[j].key, + properties.getString(properties.items()[j].key)); + } + } +} + +void ClientDataSource::removePointFeature(uint64_t id) { + + std::lock_guard lock(m_mutexStore); + + std::map::iterator findIt = m_store->pointIds.find(id); + + if (findIt != m_store->pointIds.end() && findIt->second < m_store->features.size()) { + uint64_t i = findIt->second; + + m_store->features.erase(std::next(m_store->features.begin(), i)); + m_store->properties.erase(std::next(m_store->properties.begin(), i)); + + for (std::map::iterator it = m_store->pointIds.begin(); it != m_store->pointIds.end(); ++it) { + if (it->second > i) { + it->second = it->second - 1; + m_store->features[it->second].id = it->second; + } + } + } +} + void ClientDataSource::removePolylineFeature(uint64_t id) { std::lock_guard lock(m_mutexStore); @@ -343,6 +445,27 @@ void ClientDataSource::removePolylineFeature(uint64_t id) { } } +void ClientDataSource::removePolygonFeature(uint64_t id) { + + std::lock_guard lock(m_mutexStore); + + std::map::iterator findIt = m_store->polygonIds.find(id); + + if (findIt != m_store->polygonIds.end() && findIt->second < m_store->features.size()) { + uint64_t i = findIt->second; + + m_store->features.erase(std::next(m_store->features.begin(), i)); + m_store->properties.erase(std::next(m_store->properties.begin(), i)); + + for (std::map::iterator it = m_store->polygonIds.begin(); it != m_store->polygonIds.end(); ++it) { + if (it->second > i) { + it->second = it->second - 1; + m_store->features[it->second].id = it->second; + } + } + } +} + struct add_geometry { static constexpr double extent = 4096.0; diff --git a/platforms/android/tangram/src/main/cpp/jniExports.cpp b/platforms/android/tangram/src/main/cpp/jniExports.cpp index 5ad13bc51e..7535027365 100644 --- a/platforms/android/tangram/src/main/cpp/jniExports.cpp +++ b/platforms/android/tangram/src/main/cpp/jniExports.cpp @@ -595,7 +595,7 @@ jlong MapData(AddFeature)(JNIEnv* jniEnv, jobject obj, jlong sourcePtr, jdoubleA } offset += nPointsInRing; } - source->addPolygonFeature(std::move(properties), std::move(builder)); + id = source->addPolygonFeature(std::move(properties), std::move(builder)); jniEnv->ReleaseIntArrayElements(jrings, rings, JNI_ABORT); } else if (nPoints > 1) { // If no rings defined but multiple points, this is a polyline feature. @@ -607,7 +607,7 @@ jlong MapData(AddFeature)(JNIEnv* jniEnv, jobject obj, jlong sourcePtr, jdoubleA id = source->addPolylineFeature(std::move(properties), std::move(builder)); } else { // This is a point feature. - source->addPointFeature(std::move(properties), LngLat(coordinates[0], coordinates[1])); + id = source->addPointFeature(std::move(properties), LngLat(coordinates[0], coordinates[1])); } jniEnv->ReleaseDoubleArrayElements(jcoordinates, coordinates, JNI_ABORT); @@ -615,6 +615,17 @@ jlong MapData(AddFeature)(JNIEnv* jniEnv, jobject obj, jlong sourcePtr, jdoubleA return id; } +void MapData(UpdatePointPoint)(JNIEnv* jniEnv, jobject obj, jlong sourcePtr, jlong id, jdoubleArray jcoordinates) { + + auto_source(sourcePtr); + + auto* coordinates = jniEnv->GetDoubleArrayElements(jcoordinates, NULL); + + source->updatePointFeature(static_cast(id), LngLat(coordinates[0], coordinates[1])); + + jniEnv->ReleaseDoubleArrayElements(jcoordinates, coordinates, JNI_ABORT); +} + void MapData(UpdatePolylinePoints)(JNIEnv* jniEnv, jobject obj, jlong sourcePtr, jlong id, jdoubleArray jcoordinates) { auto_source(sourcePtr); @@ -632,6 +643,44 @@ void MapData(UpdatePolylinePoints)(JNIEnv* jniEnv, jobject obj, jlong sourcePtr, jniEnv->ReleaseDoubleArrayElements(jcoordinates, coordinates, JNI_ABORT); } +void MapData(UpdatePolygonPoints)(JNIEnv* jniEnv, jobject obj, jlong sourcePtr, jlong id, jdoubleArray jcoordinates) { + + auto_source(sourcePtr); + + size_t n_points = jniEnv->GetArrayLength(jcoordinates) / 2; + + auto* coordinates = jniEnv->GetDoubleArrayElements(jcoordinates, NULL); + + std::vector lngLatCoordinates; + for (size_t i = 0; i < n_points; ++i) { + lngLatCoordinates.push_back({coordinates[2 * i], coordinates[2 * i + 1]}); + } + source->updatePolygonFeature(static_cast(id), lngLatCoordinates); + + jniEnv->ReleaseDoubleArrayElements(jcoordinates, coordinates, JNI_ABORT); +} + +void MapData(UpdatePointProperties)(JNIEnv* jniEnv, jobject obj, jlong sourcePtr, jlong id, jobjectArray jproperties) { + + auto_source(sourcePtr); + + size_t n_properties = (jproperties == NULL) ? 0 : jniEnv->GetArrayLength(jproperties) / 2; + + Properties properties; + + for (size_t i = 0; i < n_properties; ++i) { + jstring jkey = (jstring) (jniEnv->GetObjectArrayElement(jproperties, 2 * i)); + jstring jvalue = (jstring) (jniEnv->GetObjectArrayElement(jproperties, 2 * i + 1)); + auto key = stringFromJString(jniEnv, jkey); + auto value = stringFromJString(jniEnv, jvalue); + properties.set(key, value); + jniEnv->DeleteLocalRef(jkey); + jniEnv->DeleteLocalRef(jvalue); + } + + source->updatePointFeature(static_cast(id), std::move(properties)); +} + void MapData(UpdatePolylineProperties)(JNIEnv* jniEnv, jobject obj, jlong sourcePtr, jlong id, jobjectArray jproperties) { auto_source(sourcePtr); @@ -653,6 +702,34 @@ void MapData(UpdatePolylineProperties)(JNIEnv* jniEnv, jobject obj, jlong source source->updatePolylineFeature(static_cast(id), std::move(properties)); } +void MapData(UpdatePolygonProperties)(JNIEnv* jniEnv, jobject obj, jlong sourcePtr, jlong id, jobjectArray jproperties) { + + auto_source(sourcePtr); + + size_t n_properties = (jproperties == NULL) ? 0 : jniEnv->GetArrayLength(jproperties) / 2; + + Properties properties; + + for (size_t i = 0; i < n_properties; ++i) { + jstring jkey = (jstring) (jniEnv->GetObjectArrayElement(jproperties, 2 * i)); + jstring jvalue = (jstring) (jniEnv->GetObjectArrayElement(jproperties, 2 * i + 1)); + auto key = stringFromJString(jniEnv, jkey); + auto value = stringFromJString(jniEnv, jvalue); + properties.set(key, value); + jniEnv->DeleteLocalRef(jkey); + jniEnv->DeleteLocalRef(jvalue); + } + + source->updatePolygonFeature(static_cast(id), std::move(properties)); +} + +void MapData(RemovePoint)(JNIEnv* jniEnv, jobject obj, jlong sourcePtr, jlong id) { + + auto_source(sourcePtr); + + source->removePointFeature(static_cast(id)); +} + void MapData(RemovePolyline)(JNIEnv* jniEnv, jobject obj, jlong sourcePtr, jlong id) { auto_source(sourcePtr); @@ -660,6 +737,13 @@ void MapData(RemovePolyline)(JNIEnv* jniEnv, jobject obj, jlong sourcePtr, jlong source->removePolylineFeature(static_cast(id)); } +void MapData(RemovePolygon)(JNIEnv* jniEnv, jobject obj, jlong sourcePtr, jlong id) { + + auto_source(sourcePtr); + + source->removePolygonFeature(static_cast(id)); +} + void MapData(AddGeoJson)(JNIEnv* jniEnv, jobject obj, jlong sourcePtr, jstring geojson) { auto_source(sourcePtr); diff --git a/platforms/android/tangram/src/main/java/com/mapzen/tangram/MapData.java b/platforms/android/tangram/src/main/java/com/mapzen/tangram/MapData.java index 9e5c3db057..be7d4dbcdd 100644 --- a/platforms/android/tangram/src/main/java/com/mapzen/tangram/MapData.java +++ b/platforms/android/tangram/src/main/java/com/mapzen/tangram/MapData.java @@ -72,6 +72,53 @@ public long addFeature(@NonNull final Geometry feature) { return id; } } + + /** + * Update point coordinates + * @param id Id of point to update + * @param coordinate New coordinate of a point + */ + public void updatePoint(long id, LngLat coordinate) { + final MapController map = mapController; + if (map == null) { + return; + } + synchronized (this) { + nativeUpdatePointPoint(pointer, id, new double[] { coordinate.longitude, coordinate.latitude }); + nativeGenerateTiles(pointer); + } + } + + /** + * Update point properties + * @param id Id of point to update + * @param properties New properties of a point + */ + public void updatePoint(long id, Map properties) { + final MapController map = mapController; + if (map == null) { + return; + } + synchronized (this) { + nativeUpdatePointProperties(pointer, id, Geometry.getStringMapAsArray(properties)); + nativeGenerateTiles(pointer); + } + } + + /** + * Remove point + * @param id Id of point to remove + */ + public void removePoint(long id) { + final MapController map = mapController; + if (map == null) { + return; + } + synchronized (this) { + nativeRemovePoint(pointer, id); + nativeGenerateTiles(pointer); + } + } /** * Update polyline coordinates @@ -90,7 +137,7 @@ public void updatePolyline(long id, List coordinates) { } /** - * Update polyline coordinates + * Update polyline properties * @param id Id of polyline to update * @param properties New properties of a polyline */ @@ -119,6 +166,53 @@ public void removePolyline(long id) { nativeGenerateTiles(pointer); } } + + /** + * Update polygon coordinates + * @param id Id of polygon to update + * @param coordinate New coordinates of a polygon + */ + public void updatePolygon(long id, LngLat coordinate) { + final MapController map = mapController; + if (map == null) { + return; + } + synchronized (this) { + nativeUpdatePolygonPoints(pointer, id, new double[] { coordinate.longitude, coordinate.latitude }); + nativeGenerateTiles(pointer); + } + } + + /** + * Update polygon properties + * @param id Id of polygon to update + * @param properties New properties of a polygon + */ + public void updatePolygon(long id, Map properties) { + final MapController map = mapController; + if (map == null) { + return; + } + synchronized (this) { + nativeUpdatePolygonProperties(pointer, id, Geometry.getStringMapAsArray(properties)); + nativeGenerateTiles(pointer); + } + } + + /** + * Remove polygon + * @param id Id of polygon to remove + */ + public void removePolygon(long id) { + final MapController map = mapController; + if (map == null) { + return; + } + synchronized (this) { + nativeRemovePolygon(pointer, id); + nativeGenerateTiles(pointer); + } + } /** * Assign features described in a GeoJSON string to this collection. This will replace any previously assigned feature lists or GeoJSON data. @@ -173,7 +267,15 @@ public void clear() { private native void nativeAddGeoJson(long sourcePtr, String geoJson); private native void nativeGenerateTiles(long sourcePtr); + private native void nativeUpdatePointPoint(long sourcePtr, long id, double[] coordinate); + private native void nativeUpdatePointProperties(long sourcePtr, long id, String[] properties); + private native void nativeRemovePoint(long sourcePtr, long id); + private native void nativeUpdatePolylinePoints(long sourcePtr, long id, double[] coordinates); private native void nativeUpdatePolylineProperties(long sourcePtr, long id, String[] properties); private native void nativeRemovePolyline(long sourcePtr, long id); + + private native void nativeUpdatePolygonPoints(long sourcePtr, long id, double[] coordinates); + private native void nativeUpdatePolygonProperties(long sourcePtr, long id, String[] properties); + private native void nativeRemovePolygon(long sourcePtr, long id); }