MapBox water/land detection - ios

I am starting to use the MapBox iOS SDK.
Is there any possible way to query the MapView by a coordinate and get back the terrain-type (water, land) as a result?
I've been reading the API doc for quite a while now, but could not figure it out.
I know that there are (interim) solutions available to use a Google webservice, but I need this to work offline.
I am not bound to MapBox (but I like it) though, thank you for any hint!

No need to delve into runtime styling (see my other answer, false lead): very simple method using mapView.visibleFeatures(at: CGPoint, styleLayerIdentifiers: Set<String>) equivalent for javascript API is queryRenderedFeatures.
func mapView(_ mapView: MGLMapView, regionDidChangeAnimated animated: Bool)
{
let features = mapView.visibleFeatures(at: mapView.center, styleLayerIdentifiers: ["water"])
print(features)
}
Example output when moving around:
[]
[]
[]
[<MGLMultiPolygonFeature: 0x170284650>]
If empty result: no water, if polygon: water.

It seems to be possible:
Found on https://www.mapbox.com/ios-sdk/api/3.5.0/runtime-styling.html
There is the possibility of adapting the UI according to the position of the user (park, city, water, etc.) Unfortunately I don't know how! (will update as soon as I find out)
Map interactivity You can customize the map to the point of having it respond dynamically based on the actions your users are taking.
Increase the text size of streets while a user is driving, emphasize
points of interest tailored to a user’s preferences, or change your UI
if users are at parks, trails, landmarks, or rivers.
UI GIF demo

I made a sample code that can help you a little bit.
https://github.com/P0nj4/Coordinates-on-water-or-land
giving a coordinate, the app checks with google if it's land or water.

Related

How to use Google ARCore eastUpSouthQTarget

Im developing an app using Google ARCore.
I want to create an experience where you see objects in AR near you. for that, I need to place pre-created objects according to the user's location.
Google provides an API for that in ARCore.Geospatial
garSession.createAnchorOnTerrain(
coordinate: coordinate, // long, lat degrees
altitudeAboveTerrain: 0,
eastUpSouthQAnchor: eastUpSouthQTarget
)
My question is how to get the eastUpSouthQTarget parameter.
The example app gets this parameter using a call to the same session.
// Update the quaternion from landscape orientation to portrait orientation.
let rotationZquat = simd_quaternion(Float.pi / 2, simd_float3(0, 0, 1))
let geospatialTransform = self.garFrame.earth?.cameraGeospatialTransform
let eastUpSouthQPortraitCamera = simd_mul(geospatialTransform.eastUpSouthQTarget, rotationZquat)
But I need to know it beforehand and add objects from the data.
I can find long and lat on the google-maps.
But how can I get orientation? And how to transform it to this format?
The documentation explains the notation, but it doesn't help in understanding how to work with that outside the app.
It also shows that the previous method, getHeading(), which used to give you more traditional coordinates, is now deprecated. And the depreciation notice doesn't give clear instructions on how to use the new one.
I can find something connected to this transformation, but I can't see the whole picture.
For example, matlab func eul2quat. But it doesn't seem to use location, which is, as far as I can tell, important.

Prevent redundant operations in RxSwift

I'm starting my adventure with RxSwift, having small experience with React in js already. I think that my problem is common, but I'm not sure how to describe it in concise abstract way, so instead I will describe it on the example.
I'm building iOS app showing some charts. The part of interest consist of ChartAreaController, ChartInfoController, both embedded in ChartController. First controller is the area showing some graph(based on rx chartData property), and the second one among others will have a slider for user to restrict show x-value (rx selectedXRange property) which is restricted to be between some min and max. The min/max value is defined by the current chart data.
Behavior when slider change updates chart is defined in ChartController:
override func viewDidLoad() {
super.viewDidLoad()
(...)
chartInfoController.selectedXRange.asObservable()
.subscribe(onNext: { [unowned self] selectedXRange in
(...)
let chartData = self.filterChartData(from: self.rawChartData, in: selectedXRange)
self.chartAreaController.chartData.accept(chartData)
}).disposed(by: disposeBag)
The filterChartData() method just filters out data that is not in the range, but for the sake of the argument we can assume it is very costly and I don't want it to run twice when it is not necessary.
When user changes the chart he or she wants to show, the new data arrives from server (again ChartController):
private func handleNewData(_ rawChartData: ChartData) {
self.rawChartData = rawChartData
guard let allowedXRange = rawChartData.xRange() else { return }
let selectedXRange = chartInfoController.selectedXRange.value
let newSelectedXRange = calculateSelectedXRange(currentSelectedDays: selectedDaysRange, availableDaysRange: daysRange)
let chartData = filterChartData(from: rawChartData, in: selectedXRange)
self.chartInfoController.allowedXRange = allowedXRange //this line is not crucial
self.chartInfoController.selectedXRange.accept(newSelectedXRange)
self.chartAreaController.chartData.accept(rawChartData)
}
So upon new chart data arrival it may be the case that the currently selected xRange must be trimmed because of the new min/max values of the data. So the side effect of the method will be changing the selectedXRange and in turn running the subscription I pasted earlier. So when new data arrives the chartData is updated twice and I don't want it to happen.
Of course I can comment out last line of the handleNewData() method, but I don't like it very much, since main reason for existence of the handleNewData() is to set chartData, and with the line commented out it's goal would be achieved because of the side effect of the method (which is updating the slider). Not acceptable.
To chartData I added throttle anyways, because fast moving slider will result in many updates and this solves my problem partially(chartData updated only once). But as you may remember the filterChartData() method is costly, and this part will still be running twice.
So the one question is, if my general layout of tackling the problem is OK, or should it be handled way different? At this point I came to conclusion that I'm looking for some way of temporary disabling particular subscription on selectedXRange (without damaging other subscriptions to that variable). Temporary meaning:
(...)
//disable subscription
self.chartInfoController.selectedXRange.accept(newSelectedXRange)
self.chartAreaController.chartData.accept(rawChartData)
//enable subscription
(...)
This seem legit to me, since ChartController as an owner of the subscription and changer of the values may want to disable the subscription whenever it suits him(it?).
Does RxSwift support something like this? If not, then I think I can achieve it myself e.g. via bool property in ChartController, or via adding the subscription to separate disposeBag, which I would dispose and then recreate the subscription. But if it's good thing to do? For example bool solution may be prone to be ill handled when there is some error, and dispose/recreate may be somehow costly, and it may be the case that disposal was not intended to be used like that.
Is there a better practice to handle such situations? As I said I think the problem is common so I hope there is a canonical solution to it :) Thanks for any answer, sorry for the lengthy post.
So the one question is, if my general layout of tackling the problem is OK, or should it be handled way different?
A properly written UI input element observable will only fire when the user makes a change to the UI, not when the program makes a change. For example:
textField.rx.text.orEmpty.subscribe(onNext: { print($0) }) will only print a value when the user types in the textField, not when you call textField.text = "foo" or from a binding .bind(to: textfield.rx.text).
If you wrote the ChartInfoController, I suggest you modify it to work the way the other UI elements do. If you didn't write it, submit an issue to the developer/maintainer.
Does RxSwift support something like [temporarily disabling particular subscription]?
It depends on what you mean by "temporarily disabling". It doesn't support silently unsubscribing and resubscribing but there are plenty of operators that will filter out some events they receive while passing others along. For example filter, throttle, debounce, ignoreElements... There's a lot of them that do that.
Is there a better practice to handle such situations?
Then best solution is mentioned above.
When We have multiple subscriptions to the same Observable, it will re-execute for each subscription.
To stop re-execute for each subscription. RxSwift has several operators for this: share(), replay(), replayAll(), shareReplay(), publish(), and even shareReplayLatestWhileConnected().
read more at (RxSwift: share vs replay vs shareReplay)

Turn off Openlayers 3 Geolocation

So, my idea of turning off the Geolocation functionality in an Openlayers 3.9.0 map is to have a toggle button that when is clicked it stops the tracking and removes the feature from the geolocation layer
geolocation.setTracking('false');
featuresOverlay.getSource().clear();
and then to turn it on again it turns the tracking on, adds a feature to the geolocation layer, sets its coordinates and re-centers the map
geolocation.setTracking('true');
featuresOverlay.getSource().addFeature(positionFeature);
var coordinates = geolocation.getPosition();
positionFeature.setGeometry(coordinates ? new ol.geom.Point(coordinates) : null);
view.setCenter(coordinates);
Well, this technically does not count as turning on/off the geolocation because it removes all the visual elements, it does not actually turns on/off the API. Is there such a possibility, or the above are enough?
Sure it does, after one minor change.
Assuming that geolocation in your code references an instance of ol.Geolocation, calling geolocation.setTracking(false) will make the geolocation call clearWatch on the browsers geolocation API. The relevant code is here.
However, setTracking expects a boolean value. You send the string 'false', which is interpreted as a truthy value (since it's a non-empty string). Remove the quotation marks from the setTracking paramters, and it should work as expected.

How to manage map pins? iOS

From the server response comes to me with an update of coordinates every 5 second. This coordinates I add to map like pins. But existing coordinates of current object not removes, it coordinates just add as new. How to update coordinates of current object and remove object that have no coordinates for now?
I use native map. If you give any simple I'll be happy
The response from the server, I receive the coordinates of users if the user is, if not - nothing comes. I need an approach without removing all the coordinates and with management (delete or update), depending on the receipt of a new member eoordinaty or delete it
Use this :
[mapView removeAnnotations:mapView.annotations]
Before adding your annotation.
Hope it works :)

Varying content with CLPlacemark, administrativeArea, iOS6/iOS7

I'm planning to make an app for ios7, and have an issue with the administrativeArea Placemark Attribute.
For iOS6 i get the full name of the administrative area (ex. "California"), but for the iOS7, I get the value of "CA". This is a problem when its so varying. Is there any way I can control this input so its more consistent?
The apple docs doesnt eigher explain this in details..
http://developer.apple.com/library/mac/documentation/CoreLocation/Reference/CLPlacemark_class/Reference/Reference.html#//apple_ref/occ/instp/CLPlacemark/administrativeArea
Thanks!
You can only parse it to uoy needed value.
I can offer you find the list of administrative areas with full name and with little.
After you can add this in 2 .txt files, import them in project,create 2 NSArrays and initialize each array in cycle.
After you can check administrative area name and return right value.

Resources