DidUpdateUserLocation event never gets called when displaying Map on Xamarin IOS - ios

I am currently trying to display my location using MKMapView on Xamarin IOS without much success. DidUpdateUserLocation event never gets called so no location coordinates are provided. I am using the below permission in my Info.plist file:
NSLocationWhenInUseUsageDescription
location
[Register("MapsViewController")]
public class MapsViewController : UIViewController {
private MKMapView mapView;
private CLLocationManager locationManager = newCLLocationManager();
private CLLocationCoordinate2D coords;
public override void ViewDidLoad() {
base.ViewDidLoad();
mapView = new MKMapView(new CGRect(0, 0, View.Frame.Width, View.Frame.Height));
mapView.ShowsUserLocation = true;
this.View.AddSubview(mapView);
locationManager.RequestWhenInUseAuthorization();
mapView.ShowsUserLocation = true;
mapView.DidUpdateUserLocation += (sender, e) => {
if (mapView.UserLocation != null) {
coords = mapView.UserLocation.Coordinate;
MKCoordinateSpan span = new MKCoordinateSpan(MilesToLatitudeDegrees(2),
MilesToLongitudeDegrees(2, coords.Latitude));
mapView.Region = new MKCoordinateRegion(coords, span);
}
};
}
public double MilesToLatitudeDegrees(double miles) {
double earthRadius = 3960.0;
double radiansToDegrees = 180.0 / Math.PI;
return (miles / earthRadius) * radiansToDegrees;
}
/// <summary>
/// Converts miles to longitudinal degrees at a specified latitude
/// </summary>
public double MilesToLongitudeDegrees(double miles, double atLatitude) {
double earthRadius = 3960.0;
double degreesToRadians = Math.PI / 180.0;
double radiansToDegrees = 180.0 / Math.PI;
// derive the earth's radius at that point in latitude
double radiusAtLatitude = earthRadius * Math.Cos(atLatitude * degreesToRadians);
return (miles / radiusAtLatitude) * radiansToDegrees;
}

Related

Why is the Polyline not showing?

Here is my whole code to show a simple line:
public class MapUIViewController : UIViewController
{
MKMapView map;
public override void ViewDidAppear(bool animated)
{
base.ViewDidAppear(animated);
CLLocationCoordinate2D loc = new CLLocationCoordinate2D(38.8895, -77.036168);
map = new MKMapView()
{
MapType = MKMapType.Hybrid,
Region = new MKCoordinateRegion(loc, new MKCoordinateSpan(0.1, 0.1)),
Frame = View.Bounds,
};
View = map;
ShowLine(loc, new CLLocationCoordinate2D(loc.Latitude + 1, loc.Longitude + 1));
}
void ShowLine(CLLocationCoordinate2D start, CLLocationCoordinate2D end)
{
MKGeodesicPolyline polyline = MKGeodesicPolyline.FromCoordinates(new CLLocationCoordinate2D[] { start, end });
map.AddOverlay(polyline);
map.OverlayRenderer = rend;
}
MKOverlayRenderer rend(MKMapView mapView, IMKOverlay overlay)
{
if (overlay is MKGeodesicPolyline line)
return new MKPolylineRenderer(line) { LineWidth = 3, StrokeColor = UIColor.Red, FillColor = UIColor.Brown, Alpha = 1 };
else
return null;
}
}
It shows the location specified, but does not show the line.
(The code is in C# (using Xamarin.ios) but it should be similar in Swift and Objective C, and my question is about the renderer which is an ios feature, not about a language feature).
I must be missing something, but I can't find it.
you need to assign the renderer BEFORE you add the line. Doing it the other way means that no renderer exists when the line is added so it will not be drawn
wrong
map.AddOverlay(polyline);
map.OverlayRenderer = rend;
right
map.OverlayRenderer = rend;
map.AddOverlay(polyline);

Control Positioning of AdMob Banner in iOS via libGDX/RoboVM

I created my libGDX iOS project and I'm trying to position my AdMob ads to the bottom center of the screen but have no idea how to accomplish this. I'm using the bindings via RoboVM and do not know any of the RoboVM methods to control my ads. I copied the tutorial from here Does anyone have any tips or tutorials to help me accomplish this? Right now the ad seems to me missing 1/4 of whole banner ad is more towards the right of the screen. Below is my code:
public class IOSLauncher extends IOSApplication.Delegate implements IActivityRequestHandler{
private static final Logger log = new Logger(IOSLauncher.class.getName(), Application.LOG_DEBUG);
private static final boolean USE_TEST_DEVICES = true;
private GADBannerView adview;
private boolean adsInitialized = false;
private IOSApplication iosApplication;
#Override
protected IOSApplication createApplication() {
IOSApplicationConfiguration config = new IOSApplicationConfiguration();
config.orientationLandscape = true;
config.orientationPortrait = false;
iosApplication = new IOSApplication(new TestProject(this), config);
return iosApplication;
}
public static void main(String[] argv) {
NSAutoreleasePool pool = new NSAutoreleasePool();
UIApplication.main(argv, null, IOSLauncher.class);
pool.close();
}
#Override
public void hide() {
initializeAds();
final CGSize screenSize = UIScreen.getMainScreen().getBounds().size();
double screenWidth = screenSize.width();
final CGSize adSize = adview.getBounds().size();
double adWidth = adSize.width();
double adHeight = adSize.height();
log.debug(String.format("Hidding ad. size[%s, %s]", adWidth, adHeight));
float bannerWidth = (float) screenWidth;
float bannerHeight = (float) (bannerWidth / adWidth * adHeight);
adview.setFrame(new CGRect(0, -bannerHeight, bannerWidth, bannerHeight));
}
#Override
public void show() {
initializeAds();
final CGSize screenSize = UIScreen.getMainScreen().getBounds().size();
double screenWidth = screenSize.width();
final CGSize adSize = adview.getBounds().size();
double adWidth = adSize.width();
double adHeight = adSize.height();
log.debug(String.format("Showing ad. size[%s, %s]", adWidth, adHeight));
float bannerWidth = (float) screenWidth;
float bannerHeight = (float) (bannerWidth / adWidth * adHeight);
adview.setFrame(new CGRect((screenWidth / 2) - adWidth / 2, 0, bannerWidth, bannerHeight));
}
public void initializeAds() {
if (!adsInitialized) {
log.debug("Initalizing ads...");
adsInitialized = true;
adview = new GADBannerView(GADAdSize.banner());
adview.setAdUnitID(Constants.AdUnitID); //put your secret key here
adview.setRootViewController(iosApplication.getUIViewController());
iosApplication.getUIViewController().getView().addSubview(adview);
final GADRequest request = GADRequest.create();
adview.setDelegate(new GADBannerViewDelegateAdapter() {
#Override
public void didReceiveAd(GADBannerView view) {
super.didReceiveAd(view);
log.debug("didReceiveAd");
}
#Override
public void didFailToReceiveAd(GADBannerView view,
GADRequestError error) {
super.didFailToReceiveAd(view, error);
log.debug("didFailToReceiveAd:" + error);
}
});
adview.loadRequest(request);
log.debug("Initalizing ads complete.");
}
}
#Override
public void showAds(boolean show) {
initializeAds();
final CGSize screenSize = UIScreen.getMainScreen().getBounds().size();
double screenWidth = screenSize.width();
final CGSize adSize = adview.getBounds().size();
double adWidth = adSize.width();
double adHeight = adSize.height();
log.debug(String.format("Hidding ad. size[%s, %s]", adWidth, adHeight));
float bannerWidth = (float) screenWidth;
float bannerHeight = (float) (bannerWidth / adWidth * adHeight);
if(show) {
adview.setFrame(new CGRect((screenWidth / 2) - adWidth / 2, 0, bannerWidth, bannerHeight));
} else {
adview.setFrame(new CGRect(0, -bannerHeight, bannerWidth, bannerHeight));
}
you set the ad position with
adview.setFrame(CGRect);
if you inspect the parameters of CGRect it's like;
CGRect(double x, double y, double width, double height)
0,0 coordinates (x,y) is top left. so, your code;
// center of screen
double adX = (screenWidth / 2) - (adWidth / 2);
// bottom of screen
double adY = screenHeight - bannerHeight;
adview.setFrame(new CGRect(adX, adY, bannerWidth, bannerHeight));
and the other important thing, you should not manipulate the positioning in two method! your showAds method should be like;
public void showAds(boolean show) {
if (show) {
show();
} else {
hide();
}
}

Find closest airport based on latitude and longitude

How do I find closest airport using longitude and latitude ?
Any specific web services and any database to achieve ?
One WebService I found is airports.pidgets.com
This is an example:
XML format
http://airports.pidgets.com/v1/airports?near=45.3515,9.3753
JSon format
http://airports.pidgets.com/v1/airports?near=45.3515,9.3753&format=json
[Edit]
Found another webservice on aviationweather.gov (only XML and CSV)
http://aviationweather.gov/adds/dataserver_current/httpparam?dataSource=stations&requestType=retrieve&format=xml&radialDistance=20;9.3753,45.3515
From both sites you can download a "static" airports list, to perform offline search.
Regards
You need a dataset with fields for the airport`s latitude and
longitude
Use the calculation for Great-Circle distance (GCD) as outlined on the page linked below
Wikipedia article on GCD
Please provide example code/specify the language if you would like further and more specific help
CODE:
Taken from another webpage (now defunct, used waybackmachine)
using System;
namespace HaversineFormula
{
/// <summary>
/// The distance type to return the results in.
/// </summary>
public enum DistanceType { Miles, Kilometers };
/// <summary>
/// Specifies a Latitude / Longitude point.
/// </summary>
public struct Position
{
public double Latitude;
public double Longitude;
}
class Haversine
{
/// <summary>
/// Returns the distance in miles or kilometers of any two
/// latitude / longitude points.
/// </summary>
/// <param name=”pos1″></param>
/// <param name=”pos2″></param>
/// <param name=”type”></param>
/// <returns></returns>
public double Distance(Position pos1, Position pos2, DistanceType type)
{
double R = (type == DistanceType.Miles) ? 3960 : 6371;
double dLat = this.toRadian(pos2.Latitude - pos1.Latitude);
double dLon = this.toRadian(pos2.Longitude - pos1.Longitude);
double a = Math.Sin(dLat / 2) * Math.Sin(dLat / 2) +
Math.Cos(this.toRadian(pos1.Latitude)) * Math.Cos(this.toRadian(pos2.Latitude)) *
Math.Sin(dLon / 2) * Math.Sin(dLon / 2);
double c = 2 * Math.Asin(Math.Min(1, Math.Sqrt(a)));
double d = R * c;
return d;
}
/// <summary>
/// Convert to Radians.
/// </summary>
/// <param name="val"></param>
/// <returns></returns>
private double toRadian(double val)
{
return (Math.PI / 180) * val;
}
}
}
Pseudocode:
This pseudocode should give you the answer you are looking for. I didn't test this and the C# will probably have syntactic errors but the gist of it should be clear.
/* Set parameters */
Position currentPosition = new Position();
Position airportPosition = new Position();
Double minDistance = Double.MaxValue;
String closestAirportName = "UNKNOWN";
Haversine hv = new Haversine();
/* Set current position, remains fixed throughout */
currentPosition.Latitude = 0.000;
currentPosition.Longitude = 0.000;
/* Compare distance to each airport with current location
* and save results if this is the closest airport so far*/
Foreach (airport in airports) {
airportPosition = new Position(airport.Lat, airport.Lon);
Double distanceToAirport = hv.Distance(currentPosition, airportPosition, DistanceType.Kilometers)
if (distanceToAirport < minDistance) {
minDistance = distanceToAirport
closestAirportName = airport.Name
}
}
On which platform are you coding, Durga? Is it Android?
In this case, you could use the Google Maps API:
https://developers.google.com/maps/
and, in particular, Google Places:
https://developers.google.com/places/
Broswe their documentation for details. In particular, check their license.
this.nearestAirport = this.airports.find((airport) => {
return (Math.round(airport.latitude) === Math.round(currentLocation.latitude) &&
Math.round(airport.longitude) === Math.round(currentLocation.longitude));
});
To Find nearest airport and to get directions to reach there from a specified point (Lat,Lan)
Here is a Google method,without any database to achieve this :
onclick="getNeighbourhood('<%= propLat %>','<%= propLan %>');"
For full code visit here FULL NEAREST AIRPORT SCRIPT AND STYLE
function getNeighbourhood(propLatQ,propLanQ) {
propLat=propLatQ;
propLan=propLanQ;
var myLatlng = new google.maps.LatLng(propLat,propLan);
var myOptions = {
zoom: 8,
center: myLatlng,
mapTypeId: google.maps.MapTypeId.ROADMAP
}
map = new google.maps.Map(document.getElementById("map"), myOptions);
places = new google.maps.places.PlacesService(map);
google.maps.event.addListener(map, 'tilesloaded', tilesLoaded);
autocomplete = new google.maps.places.Autocomplete(document.getElementById('autocomplete'));
google.maps.event.addListener(autocomplete, 'place_changed', function() {
showSelectedPlace();
});

Pinch Zoom images bound in Listbox

I am trying to implement pinch zoom in my application. I found this article (Correct Pinch-Zoom in Silverlight) and it works perfectly fine for one image. But the problem is, my images are within listbox as shown in below XAML:
<ListBox x:Name="lstImage" Margin="-20,-23,-12,32" Height="709" Width="480">
<ListBox.ItemTemplate>
<DataTemplate>
<Image Source="{Binding Path=ImageSource}" VerticalAlignment="Top" Margin="10,12,10,10" Width="640" Height="800">
</Image>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
I am not able to understand how to implement that solution. Thanks in advance.
Create a class with name PinchZomBehavior.cs and add the following code.
public class PinchZomBehavior : Behavior<Image>
{
private double _totalImageScale = 1d;
private Point _imagePosition = new Point(0, 0);
private const double MaxImageZoom = 5;
private Point _oldFinger1;
private Point _oldFinger2;
private double _oldScaleFactor;
private Image _imgZoom;
protected override void OnAttached()
{
_imgZoom = AssociatedObject;
_imgZoom.RenderTransform = new CompositeTransform { ScaleX = 1, ScaleY = 1, TranslateX = 0, TranslateY = 0 };
var listener = GestureService.GetGestureListener(AssociatedObject);
listener.PinchStarted += OnPinchStarted;
listener.PinchDelta += OnPinchDelta;
listener.DragDelta += OnDragDelta;
listener.DoubleTap += OnDoubleTap;
base.OnAttached();
}
#region Pinch and Zoom Logic
#region Event handlers
/// <summary>
/// Initializes the zooming operation
/// </summary>
private void OnPinchStarted(object sender, PinchStartedGestureEventArgs e)
{
_oldFinger1 = e.GetPosition(_imgZoom, 0);
_oldFinger2 = e.GetPosition(_imgZoom, 1);
_oldScaleFactor = 1;
}
/// <summary>
/// Computes the scaling and translation to correctly zoom around your fingers.
/// </summary>
private void OnPinchDelta(object sender, PinchGestureEventArgs e)
{
var scaleFactor = e.DistanceRatio / _oldScaleFactor;
if (!IsScaleValid(scaleFactor))
return;
var currentFinger1 = e.GetPosition(_imgZoom, 0);
var currentFinger2 = e.GetPosition(_imgZoom, 1);
var translationDelta = GetTranslationDelta(
currentFinger1,
currentFinger2,
_oldFinger1,
_oldFinger2,
_imagePosition,
scaleFactor);
_oldFinger1 = currentFinger1;
_oldFinger2 = currentFinger2;
_oldScaleFactor = e.DistanceRatio;
UpdateImageScale(scaleFactor);
UpdateImagePosition(translationDelta);
}
/// <summary>
/// Moves the image around following your finger.
/// </summary>
private void OnDragDelta(object sender, DragDeltaGestureEventArgs e)
{
var translationDelta = new Point(e.HorizontalChange, e.VerticalChange);
if (IsDragValid(1, translationDelta))
UpdateImagePosition(translationDelta);
}
/// <summary>
/// Resets the image scaling and position
/// </summary>
private void OnDoubleTap(object sender, GestureEventArgs e)
{
ResetImagePosition();
}
#endregion
#region Utils
/// <summary>
/// Computes the translation needed to keep the image centered between your fingers.
/// </summary>
private Point GetTranslationDelta(
Point currentFinger1, Point currentFinger2,
Point oldFinger1, Point oldFinger2,
Point currentPosition, double scaleFactor)
{
var newPos1 = new Point(
currentFinger1.X + (currentPosition.X - oldFinger1.X) * scaleFactor,
currentFinger1.Y + (currentPosition.Y - oldFinger1.Y) * scaleFactor);
var newPos2 = new Point(
currentFinger2.X + (currentPosition.X - oldFinger2.X) * scaleFactor,
currentFinger2.Y + (currentPosition.Y - oldFinger2.Y) * scaleFactor);
var newPos = new Point(
(newPos1.X + newPos2.X) / 2,
(newPos1.Y + newPos2.Y) / 2);
return new Point(
newPos.X - currentPosition.X,
newPos.Y - currentPosition.Y);
}
/// <summary>
/// Updates the scaling factor by multiplying the delta.
/// </summary>
private void UpdateImageScale(double scaleFactor)
{
_totalImageScale *= scaleFactor;
ApplyScale();
}
/// <summary>
/// Applies the computed scale to the image control.
/// </summary>
private void ApplyScale()
{
((CompositeTransform)_imgZoom.RenderTransform).ScaleX = _totalImageScale;
((CompositeTransform)_imgZoom.RenderTransform).ScaleY = _totalImageScale;
}
/// <summary>
/// Updates the image position by applying the delta.
/// Checks that the image does not leave empty space around its edges.
/// </summary>
private void UpdateImagePosition(Point delta)
{
var newPosition = new Point(_imagePosition.X + delta.X, _imagePosition.Y + delta.Y);
if (newPosition.X > 0) newPosition.X = 0;
if (newPosition.Y > 0) newPosition.Y = 0;
if ((_imgZoom.ActualWidth * _totalImageScale) + newPosition.X < _imgZoom.ActualWidth)
newPosition.X = _imgZoom.ActualWidth - (_imgZoom.ActualWidth * _totalImageScale);
if ((_imgZoom.ActualHeight * _totalImageScale) + newPosition.Y < _imgZoom.ActualHeight)
newPosition.Y = _imgZoom.ActualHeight - (_imgZoom.ActualHeight * _totalImageScale);
_imagePosition = newPosition;
ApplyPosition();
}
/// <summary>
/// Applies the computed position to the image control.
/// </summary>
private void ApplyPosition()
{
((CompositeTransform)_imgZoom.RenderTransform).TranslateX = _imagePosition.X;
((CompositeTransform)_imgZoom.RenderTransform).TranslateY = _imagePosition.Y;
}
/// <summary>
/// Resets the zoom to its original scale and position
/// </summary>
private void ResetImagePosition()
{
_totalImageScale = 1;
_imagePosition = new Point(0, 0);
ApplyScale();
ApplyPosition();
}
/// <summary>
/// Checks that dragging by the given amount won't result in empty space around the image
/// </summary>
private bool IsDragValid(double scaleDelta, Point translateDelta)
{
if (_imagePosition.X + translateDelta.X > 0 || _imagePosition.Y + translateDelta.Y > 0)
return false;
if ((_imgZoom.ActualWidth * _totalImageScale * scaleDelta) + (_imagePosition.X + translateDelta.X) < _imgZoom.ActualWidth)
return false;
if ((_imgZoom.ActualHeight * _totalImageScale * scaleDelta) + (_imagePosition.Y + translateDelta.Y) < _imgZoom.ActualHeight)
return false;
return true;
}
/// <summary>
/// Tells if the scaling is inside the desired range
/// </summary>
private bool IsScaleValid(double scaleDelta)
{
return (_totalImageScale * scaleDelta >= 1) && (_totalImageScale * scaleDelta <= MaxImageZoom);
}
#endregion
#endregion
}
And attach the behavior to image control like this
xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
<Image Stretch="Uniform" Source="{Binding Image}" CacheMode="BitmapCache">
<i:Interaction.Behaviors>
<Behaviors:PinchZomBehavior/>
</i:Interaction.Behaviors>
</Image>

Blackberry - change latitude and longitude on the device to test app

I want to test my app on the device. Is it possible to hard code the latitude and longitude values somewhere in the device settings so the app reads those instead of the current location?
I want to test my app for different locations other than my current location.
In the BB simulator you can go to Simulate > GPS Location. Click the Add button and enter in a name, latitude and longitude. Click save and the simulator will start feeding your new location to the apps. Note that whatever location is displayed in the drop down is the one that will be reported by the simulator.
Inside GPS mockup
If you have access to your application code, you can always create a mockup implementation for LocationProvider so it will read location and speed data from file or RecordStore and return it as a Location, something like
public class MockupLocationProvider extends LocationProvider {
public MockupLocationProvider() {
//prepare a file or RecordStore with locations here
}
public Location getLocation(int arg0) throws LocationException,
InterruptedException {
//read data from file or RecordStore
double latitude = 321;
double longitude = 34;
float altitude = 21;
//create and return location
Location result = new GPSLocation(latitude,
longitude, altitude);
return result;
}
public int getState() {
// mockup location provider always available
return LocationProvider.AVAILABLE;
}
public void reset() {
// your code
}
public void setLocationListener(LocationListener listener,
int interval, int timeout, int maxAge) {
// your code
}
}
and mockup for your Location
public class GPSLocation extends Location {
double _latitude, _longitude;
float _altitude, _horAcc = 0, _verAcc = 0, _speed;
public GPSLocation(double lat, double lon, float alt) {
init(lat, lon, alt);
}
public GPSLocation(double lat, double lon, float alt, float spd) {
init(lat, lon, alt);
_speed = spd;
}
private void init(double lat, double lon, float alt) {
_latitude = lat;
_longitude = lon;
_altitude = alt;
}
public QualifiedCoordinates getQualifiedCoordinates() {
QualifiedCoordinates c = new QualifiedCoordinates(_latitude,
_longitude, _altitude, _horAcc, _verAcc);
return c;
}
public float getSpeed() {
return _speed;
}
public String toString() {
String result = "Lat:" + String.valueOf(_latitude) + "|Lon:"
+ String.valueOf(_longitude) + "|Alt:"
+ String.valueOf(_altitude);
return result;
}
}
Then somewhere on the screen
MockupLocationProvider gpsProvider = new MockupLocationProvider();
GPSLocation loc = (GPSLocation)gpsProvider.getLocation(0);
add(new RichTextField(loc.toString()));
Outside GPS mockup
Another option is to generally mockup GPS signals.
Steps are:
configure device gps receiver for
bluetooth (for ex.)
setup some
opensource gps server on your desktop
to produce location data over
bluetooth
change configuration/code
of gps server to mockup location data
Other options
There is a possibility to uncontrolled change of location gps data by shielding gps receiver with some radio-material (like alluminium foil or so) :)

Resources