I use here-map sdk. I have db file with 16500 ! paths (coordinates of a point). I need to draw all paths on the map, when user activate function "show additional paths". But i think, if i try to fetch big number of path and add all poplilynes object on here map, it will take a huge amount of time.
Help to find the optimal solution.
I would filter your data based on the visible viewport and disable this functionality where it doesn't make much sense (continental or globe level).
So, let's assume you app shows the map on zoomlevel 16 or 17 (district level), you can retrieve the viewport as GeoBoundingBox from the Map instance (e.g. via mapView.getMap()) with getBoundingBox().
The GeoBoundingBox makes it easy for you now to check for collisions with your own objects, since it has several "contains()" methods.
So everything that collides with your viewport should be shown, everything else is ignored.
You can update whenever the map viewport changes with either listening for OnTransformListener in the Map class or register for the MapGesture events (get MapGesture via getMapGesture() and listen for zooming events via addOnGestureListener())
If the amount of data for filtering is still too big, you can also think about preparing your data for more efficient filtering, like partitioning (region based would be my first idea) so only a subset of your data needs to be filtered.
It seems that Custom Location Extension (https://developer.here.com/platform-extensions/documentation/custom-location/topics/what-is.html) can help with this case.
In short, it allows you to upload a custom data to the HERE backend and query it later.
Related
I'm creating an Android app using MapBox. I've already set up a simple map functionality with markers sourced from .json file. Next step is filtering the markers on the map, just like in this gl-js example here:
https://docs.mapbox.com/mapbox-gl-js/example/filter-markers/
I can't find any sdk examples anywhere, and since this is my first app I really can't figure it out on my own. Any help will be appreciated.
You can check out this example https://docs.mapbox.com/android/maps/examples/multiple-expressions-temperature-change/ that features two layers that fetch a min or max temperature from the data source and display it.
The filtering part is done here:
// Only display Maximum Temperature in this layer
maxTempLayer.setFilter(eq(get("element"), literal("All-Time Maximum Temperature")));
loadedMapStyle.addLayer(maxTempLayer);
Filters accept expressions as arguments, and here Expression.eq is used to compare "element" from the GeoJSON data source (referenced with the Expression.get) with the "All-Time Maximum Temperature" value. If it resolves to true, the feature is going to be displayed, otherwise, it's going to be hidden.
I have big KML file to a native Android application, please check the following details and give an advice.
KML file details:
size: 1.7 MB
total number of kml file elements: 500 elements
total number of polygon: 1000 polygon
Android app details:
the above details will be viewed in Fragment
I used the following support library to implement this screen
compile 'com.google.maps.android:android-maps-utils:0.4+'
some caluctations are done on loading the screens(like distance calculations)
Issue:
Take a lot of time to load the map and kml layer about 8 sec
create KMLLayer instance
What is the best practice to implement the above details with good performance?
please advise.
Best practice is doing long time operation in background (for example, on separate thread) and split complex tasks into small parts. So you can:
1) create and start load KML layer as soon as possible (e.g. on app create) and than just show it;
2) instead of one kml file with 500 elements and 1000 polygons, use 50 kml files with 10 elements and 100 polygons and load to layer only necessary files (for example you can split it by area location, or by semantic information, or by something else criteria);
3) combine 1 and 2 points;
4) precisely for google maps it's possible to create tiles with information from kml files and use TileProvider.
Since there's no actual answer, I'll post my own solution.
I've done mainly two things to optimize this.
Instead of using Google maps utils built-in method addLayerToMap - I've used my own custom implementation. I've done so, because parsing kml is relatively fast(in my case - ~5-10 seconds) and it can be done in background thread. Adding all the points to the map, however, takes more than 10 seconds, and must be done on UI thread. Basically, I've used KmlLayer class as a base, and parsed kml file by myself into polygonOptions and all other things I need.
Calculate which items are visible and which are not. Firstly, I filter which items are outside screen bounds. After that, I calculate each item's size(in pixels, no meters) - if item is smaller than threshold - item is also filtered out.
With these hacks applied, instead of freezing app for 15 seconds, user can freely navigate through map, and when he stops, after several seconds information will be displayed.
I just make some updates on the screen behavior to get good performance and good user experience by the following steps:
Divide the KML File to 65 files (the main areas on the map, for example, Zone A11 is located in one KML file and it contains all its details like Zone A11-1, Zone A11-2 and Zone A11-4 ...) and this division is done to be suitable the screen experience (for example user requirements)
on the first load, I am loading only the markers for all KMLs centers and that is not affecting the performance
When user click on the marker, I am loading the KML file for this area and zoom this area
When user zoom out, I am removing this layer from the map and load marker
When user moves the map I am calculating the nearest marker and load its KML layer
Note: preparing files on app launching will not provide better performance because the bad performance comes from adding the KML layer to the google map
Note2: using custom implementation for parsing and adding to Google map take a lot of time or need a lot of unit testing, and I think it's not recommended solution because it's better to leave this solution to be on Google Map utils build-in method (it's customized and always up to date)
I'd suggest you to make sure that you are constructing the KmlLayer on a background thread and addLayerToMap() has to be done on the main thread though like this
GlobalScope.launch {
val stringUrl: String = "https://saltwx.com/bath/SW_bath6.kml"
val inputStream: InputStream = URL(stringUrl).openStream()
val layer = KmlLayer(map,inputStream, applicationContext)
runOnUiThread {
try {
layer.addLayerToMap()
} catch (e: Exception) {
e.printStackTrace()
}
}}
Currently I am removing SKPolylines by tracking their setIdentifier(int) numbers when I create them, and then when I delete them I apply a new polyline to the map with the same identifier that is transparent. I have two issues with this:
I assume there should be a way to do mapView.removePolyline(int identifier); or mapView.removeAllPolylines();
I also assume there should be a way to do mapView.getAllPolylines() that returns a List<SKPolyine> because that is possible with POI's and annotations. At the very least mapView.getNumPolylines(); that returns the number of polylines so that I can delete them all with my original method, without having to track how many I have put down.
My question is: Am I missing either functionality described in 1/2? If those functionalities do not exist then is there a better way than my current method?
My application has separate algorithms to fetch data for scroll change and on user location change . For location change am using com.google.android.gms.location.LocationListener Which is working fine.
But for on user scroll, I am getting mMap.setOnCameraChangeListener(new OnCameraChangeListener(). But the issue is com.google.android.gms.location.LocationListene also triggers mMap.setOnCameraChangeListener(new OnCameraChangeListener().
So how to distinguish. Presently I am using Boolean values to differentiate, but it's not reliable and dirty.
I had the same issue, was trying all sorts of stuff like wrapping the view to intercept touches, or wrapping any calls to change the viewport and listening to when it started and stopped changing so I could tell if something else changed it, or matching the current viewport to what I last set it to... it's all rather fiddly. Then someone pointed me at this, and it looks promising update: has now worked flawlessly for us for months without a single issue:
map.setOnCameraMoveStartedListener { reasonCode ->
if (reasonCode == GoogleMap.OnCameraMoveStartedListener.REASON_GESTURE) {
// I will no longer keep updating the camera location because
// the user interacted with it. This is my field I check before
// snapping the camera location to the latest value.
tracking = false
}
}
I doubt that there's an easy, reliable, and real-time way to do this. IOW, I suspect that it is going to be "dirty".
If I had to try, I would supply my own LocationSource, so that I knew when the map would be changing based upon position. I would then try to ignore the next call (calls?) to my OnCameraChangeListener, as being ones tied to the location change.
(BTW, note that LocationListener was deprecated)
Or, I would try to change my data-fetching algorithm to treat all camera changes equally. After all, if my objective is to make sure that I have data on all sides of the map from the current center, it doesn't matter how I got to that center, just so long as I am there.
I'm writing android using couchdb. I have around 1000 documents. Every DB operation invokes a view,my view is taking a lot of time. Is there a way to optimize views in couch db? If there are less documents then fetching documents is working fast.
The main things to note with views are that both map and reduce values are cached in the view index (see http://horicky.blogspot.co.uk/2008/10/couchdb-implementation.html for details), that views are only rebuilt when you look at them, and that the CouchDB JavaScript engine is not particularly fast.
There's a few options to use all this for actual performance improvements:
Accept stale data in your views, and periodically rebuild the view index asynchronously. You can query views with ?stale=ok to immediately return the currently cached view index, from the last time the view was built, and then have some other background task querying with stale != ok to actually do the rebuild. The typical strategies for this are either to rebuild the view every X minutes or watch /db/_changes rebuild the view after every Y changes. Depends on your application.
Accept stale data and then always immediately rebuild the view asynchronously afterwards. This uses ?stale=update_after, which I believe will immediately return you a value and then do the view rebuild in the background. Whether to do this or the above depends on your use case and how important up to date values are to you; this might end up with your rebuilding the view far more than is really necessary, and thereby actually slowing down your queries. This does seem easier than the previous option though.
Push as much of your code into your map function as possible. This should improve performance in quickly changing databases, because map values are cached and don't need updating until the underlying document changes, whereas reduces need recalculating whenever one of a larger set of documents changes. I'm not sure exactly how reduce recalculation is tuned in CouchDB, i.e. how big the set that needs recalculating is, but it's definitely going to happen more the map recalculations, and potentially much much more.
Use built-in reduce functions (see http://wiki.apache.org/couchdb/Built-In_Reduce_Functions) instead of rewriting them in JavaScript. These fulfil many standard reduce cases, and are much much faster than writing the equivalent function yourself.
Rewrite your map/reduce in Erlang. See http://wiki.apache.org/couchdb/EnableErlangViews. This does require you to learn Erlang, but should just take away big percentage of your view rebuilding time.
The map function in a view is executed only once per document (plus as many times as you update the document). This happens at the first time you query the view. After that the result of the map function does not have to be computed anymore and therefore the query to the view should be extremely fast. As views are already efficient there is no general way to optimize them further.
This is not the case for temporary views. If you are using these, please store them in a design document to turn them into regular views.
Emit the smallest amount of data as possible in your document in the map function. You can access the entire document using the include_docs=true url parameter if you actually need the entire document
Good
{
map: function(doc) {
emit(doc._id, null)
}
}
Bad
{
map: function(doc) {
emit(doc._id, doc)
}
}