Clustering Google Maps Markers in iOS - ios

I have a map-based application, using Google Maps' iOS SDK. I need to store up to several thousand items in a core data database and display them with markers on the map. For performance and usability reasons, I need to cluster these markers when the user is zoomed out, but I need to make sure to place representative markers so the user knows where to zoom in to see more detail.
Each entry in my core data model has latitude/longitude double values stored. So what I thought of for clustering the items is to keep a separate entity where I strip the less significant parts of the geographic coordinates and store a count in it.
So whenever an item with lat/lon {44.9382719, -130.20293849} is inserted in the database, another "cluster" object with lat/lon {44.9, -130.2} has its count property incremented. The idea is that at low zooms (ie. zoomed out), I would only query the cluster objects and place those on the map instead of the actual items.
My question is: according to the NSManagedObject reference, you're not supposed to fetch stuff in awakeFromInsert, so how can I make sure that inserting a managed object of one kind updates the value of a corresponding managed object of another kind?

I have been searching library for Clustering Markers in Google Maps for iOS for three days, and finally I ended up with this https://github.com/googlemaps/google-maps-ios-utils, which is working nicely and very easy to use and understand.

Have a look at routeMe, this comes default
/** Whether the annotation should be clustered when map view clustering is enabled. Defaults toYES. */
#property (nonatomic, assign) BOOL clusteringEnabled;

Related

iOS Google maps dynamically update/remove programmatically created markers

I am stuck with some lack of xcode / iOS programming knowledge.
I have created a track in google maps for iOS, and programmatically created markers along this track. What I would like to do is update these markers with actual information in the .title / .snippet (ie. distance to go, time to go etc) or remove them all together.
But when you create markers in a loop there is no way of keeping track of them.
since the amount of markers can vary from 2 to 50 it would be strange in my opinion to create 50 different variables for each marker, I guess there must be another way?
You can keeping track of created markers.
Each GMSMarker has property userData. You can add some string tag or other custom object to identify this marker.
e.g.
marker.userData = #{#"key" : #"some tag"};

Efficent way of determining country polygon touches on a MKMapView?

When a user taps a point on an MKMapView in my application, I want to determine what country they tapped on. Speed is my priority, since a user will definitely notice the lag between a map touch and an annotation callout begin presented with the name of the country.
I have the polygon information for all the countries and I can parse/store them in any kind of data structure necessary. Currently, they are in GeoJSON format and have thousands of verticies. I also have bounding boxes computed and stored for each country.
One suggestion was to store an array of CGRects for each polygon's bounding box and first doing a CGRectContainsPoint search on all the bounding boxes to quickly narrow down the search. If that search returns multiple bounding boxes (common on country borders where the bounding boxes can overlap) then I can check the filtered country's full polygon for the point in question. Even on very congested overlapping areas, this full search would be 5 or less full country polygons to check.
To accomplish this, I'll need to store both a CGRect bounding box and a full, complex CGPath for each country. (and a country can have multiple polygons if it has territories) I don't know if storing these in-memory is a good idea, since there are potentially many thousands of polygons.
Compiling SpatiaLite is not an option because of the licensing requirements for GEOS. Compiling SQLite with the R-Tree extension is a possibility. The polygons do not change, so I'm able to precompute and store them on disk in any way that is suggested.
If I follow this suggestion, what is the best way to store and access all these CGRect and CGPaths for quick searching and access?
I'm open to any other suggestions people have.
I would recommend either using the Mapbox iOS SDK or at least using the RMInteractiveSource and RMMBTilesSource parts of it. You can use TileMill to turn your source data into raster tiles with encoded interactivity info on a per-pixel basis. Here's an example: https://github.com/mapbox/mapbox-ios-example The interactivity data is basically a highly efficient key-value store on a per-pixel basis. You can then convert a CGPoint at a given map zoom level and panning offset into the value.
Technology background: https://www.mapbox.com/developers/utfgrid/

iOS MapKit - defining irregular touchable regions

I'm working on an app that lets a user select locations on a map. The entire map is subdivided into irregular regions (administrative boundaries), and when a user touches a point on a map, I need to be able to figure out which region the point belongs to. Just to clarify, there is no finite set of points for a user to choose from, they just tap anywhere on the map.
What is the best way to achieve this? I have been looking at MKPolygon class but cannot really figure out if this is the way to go. If it is, would I be using intersectsMapRect: method of the MKOverlay protocol to check for a match? Are there any good tutorials on this kind of map operations?
A good approach here might be the MapBox iOS SDK and it's RMInteractiveSource, which is designed for this. Check out this sample app which shows interactive regions.
This is done by a space-optimized, offline-capable key-value store of sorts that keys pixels at varying zoom levels to arbitrary content values (region name, data, imagery, etc.)
In MapKit proper, you'll need some sort of spatial analysis (maybe Spatialite?) to determine intersections between points touched and irregularly-shaped regions.

How to find the inverse of the China transform in MKMapView?

It seems to be a known fact that MKMapView (and Google's maps in general) have a varying offset on 100-600m which makes annotations display incorrectly on the map.
According to this thread, Google has a private method called _applyChinaLocationShift, and it works, but apparently only for CLLocations that are given by CLLocationManager. For arbitrary CLLocations, it returns nil. The app I'm writing only needs to work in one city, so I've thought of pre-sampling the area using _applyChinaLocationShift and store the inverse transforms in the shipped app if that was possible.
So basically, is there any way to convert a coordinate to a coordinate that corresponds to the transformed China maps?
How about using location simulation in the Simulator and feeding it a bunch of coordinates in that particular city.

Core Plot - Drawing only the points in a specific range of the graph

I have a simple scatter plot with ~500,000 points on it. Having this many points on the graph really makes my app lag, which isn't surprising. I was wondering if there was a way to only draw the points for a specific x range (like 0-100 or 500-1000). The user will only be looking at certain points of the graph (via zooming in), so it would make it much less laggy if the program only had to plot a small amount of those points.
I've tried having the graph re-draw itself, every time the user zooms in/out or moves the axis, but this actually seems to make the app run slower. Is there a solution to this issue?
You'll have to filter the data and only provide the visible points to the plot in your datasource. Use a plot space delegate to detect when the visible area changes and adjust the data as needed. The best way to do this will depend on how your app stores its data internally. You'll want to use a data structure that lets you quickly determine which points need to be plotted.
You don't want to reload all of the data every time something changes. The plots have methods to insert and remove ranges of data points while preserving the rest of the data. If you're only changing a few points at a time, this is much faster than reloading all of the data every time. The "Real-Time Plot" demo in the Plot Gallery app shows one way to use these methods.

Resources