Winphone 8 GPS weirdness - windows-phone-8

I'm writing a POC for WinPhone 8 (I have a Nokia 928 running the 8.1 release).
One of the features I'm working with is GeoLocator and I'm noticing some odd behavior. My app gets your current location and then tracks your movement and calculates the distance between the two points. The odd behavior is that I'm sitting still and the PositionChanged event is firing! What gives? I've yet to move and my app already says the distance from the origin and my current location is ~9Meters.
Is this normal behavior for GPS? If so, what is the recommended method of dealing with it?
Here is how my GeoLocator is setup:
_Geolocator = new Geolocator();
_Geolocator.DesiredAccuracy = PositionAccuracy.High;
_Geolocator.MovementThreshold = 5;
_Geolocator.ReportInterval = 1000;
I have a button that gets the current location and starts the position changed event (chopping code for brevity):
Geoposition position = await _Geolocator.GetGeopositionAsync();
_trackLocation = true;
_currentLocation = position;
OrigLongitude = _currentLocation.Coordinate.Longitude;
OrigLatitude = _currentLocation.Coordinate.Latitude;
_Geolocator.PositionChanged += _Geolocator_PositionChanged;
Message = "tracking location";
and the PositionChanged event:
_currentLocation = args.Position;
//calculate the distance
double d = _pointTracker.DistanceTo(_currentLocation.Coordinate.Latitude, _currentLocation.Coordinate.Longitude);
double accuracy = _currentLocation.Coordinate.Accuracy;
if (true == show.Contains("tracking X"))
{
show = "tracking Y " + accuracy.ToString();
}
else
{
show = "tracking X " + accuracy.ToString();
}
DispatcherHelper.CheckBeginInvokeOnUI(() => { Distance = d; });
DispatcherHelper.CheckBeginInvokeOnUI(() => { Message = show; });
DispatcherHelper.CheckBeginInvokeOnUI(() => { Longitude = _currentLocation.Coordinate.Longitude; });
DispatcherHelper.CheckBeginInvokeOnUI(() => { Latitude = _currentLocation.Coordinate.Latitude; });
The show junk just lets me see that a message showing that the event is firing. the only thing of interest in it is the GPS accuracy I'm getting back (usually it's about 3 meters, in doors it is 9 meters).
Any direction or help would be greatly appreciated.
TIA

Related

Problems calculating duration & distance after changing setAvoid() in DirectionFinder

I receive the same duration & distance whether or not I am expecting to avoid highways or tolls
I suspect the issue is either in my order of operations, or the way I am calculating distance & duration
I have tried setting up setAvoid in two different ways (see code), as well as changed my if statements to accommodate what the HTML form (check box) might return.
I have also tried switching the if statement to "return formObject.avoid1"
this showed me that the if statement is functioning properly - so either the .setAvoid is not working the way I have written it, or the distance & duration calculations are not considering the setAvoid
function processForm(formObject) {
var allDestinations = [formObject.destination1, formObject.destination2, formObject.destination3, formObject.destination4];
var allDest = [formObject.dest1, formObject.dest2, formObject.dest3, formObject.dest4];
var numWaypoints = 0;
var waypoints = [];
for (var i=0; i<=allDestinations.length; ++i){
if (allDestinations[i] == "TRUE"){
numWaypoints ++;
waypoints.push(allDest[i]);
}
}
var mapObj = Maps.newDirectionFinder();
mapObj.setOrigin(formObject.origin)
.setDestination('my address, never changes');
//the purpose of legOne is to get the distance & duration from me to the input origin. I will always be the first and last stop. I do it this way because the input origin always needs to be the first stop. This prevents 'optimize waypoints' from altering the input origin.
var legOne = mapObj.getDirections();
var totalDistance = legOne["routes"][0]["legs"][0]["distance"]["value"];
var totalDuration = legOne["routes"][0]["legs"][0]["duration"]["value"];
for (var cc=0; cc<numWaypoints; ++cc){
mapObj.addWaypoint(waypoints[cc]);
}
if (formObject.optimize == "true"){
mapObj.setOptimizeWaypoints(true);
}
if (formObject.avoid1 == "yes"){
mapObj.setAvoid(Maps.DirectionFinder.Avoid.HIGHWAYS);
}
if (formObject.avoid2 == "yes"){
mapObj.setAvoid("tolls");
}
var directions = mapObj.getDirections();
var bestRoute = directions["routes"][0];
var numLegs = bestRoute["legs"].length;
for (var c=0; c<numLegs; ++c){
var legNum = directions["routes"][0]["legs"][c];
var legDistance = legNum["distance"]["value"];
var legDuration = legNum["duration"]["value"];
totalDistance += legDistance;
totalDuration += legDuration;
}
var miles = totalDistance * 0.000621371;
var driveTime = totalDuration / 60 / 60;
var numPallets = formObject.numPallets;
var parkTime = numWaypoints * (1/6);
var onOffLoadTime = numPallets * .5;
var totalTime = driveTime + parkTime + onOffLoadTime;
var dataArray = [miles, totalTime, driveTime, numPallets, onOffLoadTime, numWaypoints, parkTime];
return dataArray;
}
If we are in fact avoiding highways, I expect the duration to increase, but I get the same duration whether or not we avoid highways
Only one mode of setAvoid() can be set at a time, i.e., it is possible to avoid highways OR tolls, but not both. Workarounds for this exist within the API, but from what I've tested don't seem to be available in Apps Script.
Some testing:
var directions = Maps.newDirectionFinder()
.setOrigin('Times Square, New York, NY')
.setDestination('Space Needle, Seattle, WA')
Logger.log(directions.getDirections().routes[0].legs[0].duration.text) //1 day 18 hours
directions.setAvoid("highways")
Logger.log(directions.getDirections().routes[0].legs[0].duration.text) //2 days 8 hours
directions.setAvoid("tolls")
Logger.log(directions.getDirections().routes[0].legs[0].duration.text) //1 day 20 hours
This implies that either your if statements should be:
if (formObject.avoid1 == "yes"){
mapObj.setAvoid(Maps.DirectionFinder.Avoid.HIGHWAYS);
} else if (formObject.avoid2 == "yes"){
mapObj.setAvoid(Maps.DirectionFinder.Avoid.TOLLS);
}
(Prioritizes avoiding highways), or alternatively, your form should only include a single option for avoid (e.g., mapObj.setAvoid(formObj.avoid);). With your code as given, it's likely that avoid2 being "yes" causes setAvoid() to be set to avoid tolls, which may not be a factor along your route.

Xamarin Maps Pins Invisible

I have a very strange issue where the map pins do not show up on the map.
I am using Xamarin.Forms.Maps
I am setting up a map with
map = new CustomMap(
MapSpan.FromCenterAndRadius(
new Position(37, -122), Distance.FromMiles(0.3)), this)
{
IsShowingUser = true,
HeightRequest = 100,
WidthRequest = 960,
VerticalOptions = LayoutOptions.FillAndExpand
};
Then I create an absolute layout and add map to it and set the absoluteLayout to be the content
var absoluteLayout = new AbsoluteLayout
{
BackgroundColor = Color.Red.WithLuminosity(0.9),
VerticalOptions = LayoutOptions.FillAndExpand
};
AbsoluteLayout.SetLayoutBounds(map, new Rectangle(0, 0, 1, 1));
AbsoluteLayout.SetLayoutFlags(map, AbsoluteLayoutFlags.All);
absoluteLayout.Children.Add(map);
absoluteLayout.Children.Add(btn);
Content = absoluteLayout;
I also add an initial pin to the map
PinInfo firstInfo = new PinInfo
{
pinId = "1",
Description = "First Description",
};
var pin = new Pin
{
Type = PinType.Place,
Position = position,
Label = "custom pin",
Address = "custom detail info",
BindingContext = firstInfo,
};
pin.Clicked += async (sender, e) =>
{
await DisplayAlert(pin.Label, "The address is: " + pin.Address, "Cancel");
};
map.Pins.Add(pin);
However, in the app I can see the map, but it is not zoomed to the initial area, adding pins does nothing, and I cannot see the initial Pin.
I've been trying to search online for a very long time now, but for some reason have not found anyone with a similar issue...
Any help is very much appreciated.
Depends on where you are placing your Pin. In other words, what is stored position?
Try the following after adding your Pin:
map.MoveToRegion(MapSpan.FromCenterAndRadius(position, Distance.FromMiles(0.3)));

How to Use Xamarin.Forms and GoogleMaps/GeoLocation

I am writing a Xamarin.Forms PCL app, to support iOS and Android OS for my app.
In the root project, I have a view containing a ViewList and a map (from Xamarin.Forms.Maps).
I learnt I have to use CustomRenderer for each platform to add customized behavior. What I am trying to achieve to add a LocationManager/GeoLocation to identify the users position via GPS and show his position with a pin/marker. Additionally to that, I get positions from the root project of several persons which pins must also be shown within the map.
Should I have to use an interface exporting functionality or use an appropriate custom map renderer?
I have no idea to achieve that, the examples at the Xamarin.Forms website and research within Stackoverflow do not give a hint.
Here is some code I have so far (extract):
using System;
using Awesome;
using Xamarin.Forms;
using Xamarin.Forms.Maps;
using System.Collections.ObjectModel;
using System.Collections.Generic;
using Plugin.Geolocator;
using System.Threading.Tasks;
namespace KiLa
{
public class KidsFinder : ContentPage, ITabPage
{
public string TabIcon => FontAwesome.FAMapMarker;
public string SelectedTabIcon => FontAwesome.FAMapMarker;
private Boolean _showKidsList;
private ListView _listView;
public ObservableCollection<KidsViewModel> kidsList = new ObservableCollection<KidsViewModel>();
public KidsFinder ()
{
Title = "KidsFinder";
// Define listView
// Any near/identified kids? Mockup
// TODO: get real data
Boolean kidsPresent = true;
// Initial height of map
double mapHeight = 300.0;
// coordinates of Beuth Hochschule, Haus Gauss
double latitude = 52.543100;
double longitude = 13.351450;
// Show/hide kidsList (listView)
//Boolean showKidsList = false;
_showKidsList = false;
// Define toggleButton
Button toggleButton = new Button();
toggleButton.Text = "Verstecke Liste";
toggleButton.Clicked += new EventHandler(OnClickEvent);
if(kidsPresent == true)
{
toggleButton.IsVisible = true;
mapHeight = 200.0;
_showKidsList = true;
} else
{
toggleButton.IsVisible = false;
mapHeight = 300.0;
_showKidsList = false;
}
// Mockup some kids
Position pos1 = new Position(latitude + 0.002, longitude + 0.002);
Position pos2 = new Position (latitude - 0.002, longitude - 0.002);
kidsList.Add(new KidsViewModel{Name="Tim", ActualPositon=pos1, DistanceToEducator=5.4});
kidsList.Add(new KidsViewModel{Name="Sabine", ActualPositon=pos2, DistanceToEducator=20.4});
_listView = new ListView();
_listView.ItemsSource = kidsList;
//listView.VerticalOptions = LayoutOptions.FillAndExpand;
_listView.ItemTemplate = new DataTemplate (typeof(KidsCustomCell));
_listView.RowHeight = 50;
if (_showKidsList == false) {
_listView.IsVisible = false;
} else {
_listView.IsVisible = true;
}
// Define mapView
var kidsMap = new KidsMap ();
kidsMap.MapType = MapType.Street;
kidsMap.WidthRequest = 960;
kidsMap.HeightRequest = mapHeight;
kidsMap.MoveToRegion(MapSpan.FromCenterAndRadius(new Position(latitude,longitude), Distance.FromMiles(0.3)));
// Set label of pins with kids names,
foreach (KidsViewModel kvm in kidsList) {
Pin pin = new Pin() {
Label = kvm.Name,
Position = kvm.ActualPositon
};
kidsMap.Pins.Add(pin);
}
You should use GetLocation and declare the permissions necessary to use the LocationServices
[assembly: UsesPermission(Manifest.Permission.AccessFineLocation)]
[assembly: UsesPermission(Manifest.Permission.AccessCoarseLocation)]
This is not strictly necessary for obtaining the GPS coordinates of the device, but this example will attempt to provide a street address for the current location:
[assembly: UsesPermission(Manifest.Permission.Internet)]
Add a method called InitializeLocationManager to activity
void InitializeLocationManager()
{
_locationManager = (LocationManager) GetSystemService(LocationService);
Criteria criteriaForLocationService = new Criteria
{
Accuracy = Accuracy.Fine
};
IList<string> acceptableLocationProviders = _locationManager.GetProviders(criteriaForLocationService, true);
if (acceptableLocationProviders.Any())
{
_locationProvider = acceptableLocationProviders.First();
}
else
{
_locationProvider = string.Empty;
}
Log.Debug(TAG, "Using " + _locationProvider + ".");
}
The LocationManager class will listen for GPS updates from the device and notify the application by way of events. In this example we ask Android for the best location provider that matches a given set of Criteria and provide that provider to LocationManager.
For more details how to get current location using Xamarin Forms, follow this link: https://developer.xamarin.com/recipes/android/os_device_resources/gps/get_current_device_location/

windows phone 8 Map API GeocodeQuery.SearchTerm not english got nothing

I use GeocodeQuery to look up the coordinates of a search term.
// Get your current position
var myPosition = await new Geolocator().GetGeopositionAsync(TimeSpan.FromMinutes(1), TimeSpan.FromSeconds(10));
// Define search
var geoQuery = new GeocodeQuery();
geoQuery.SearchTerm = "Taipei";
geoQuery.GeoCoordinate = new GeoCoordinate(myPosition.Coordinate.Latitude, myPosition.Coordinate.Longitude);
geoQuery.QueryCompleted += (s, e) => {
if (e.Error == null && e.Result.Count > 0) {
// e.Result will contain a list of coordinates of matched places.
// You can show them on a map control , e.g.
myMap.Center = e.Result[0].GeoCoordinate;
myMap.ZoomLevel = 2;
}
}
geoQuery.QueryAsync();
It works well! I got some location about "Taipei" successfully,
But, when I search "Taipei" in tranditional chinese "台北",
I got nothing in callback function geoQuery.QueryCompleted,
e.Result.Count = 0
How should I handle the GeocodeQuery search in different language??
Thanks for any help!
The geocodequery use the system language to perform search. If you change your phone language to Chinese you should get results.

Google maps - how to get building's polygon coordinates from address?

How to implement the following:
User defines an address
User defines a color
Service searches for a corresponding building on the google map
Service fills the found building on the map with the color
I know how to:
1.find lat/long of the address
2.draw the polygon
So, to do the task I need to get polygon coordinates of building from address. How to?
(1) Acquire image tile
(2) Segment buildings based on pixel color (here, 0xF2EEE6).
(3) Image cleanup (e.g. erosion then dilation) + algorithm to acquire pixel coordinates of polygon corners.
(4) Mercator projection to acquire lat/long of pixel
You can convert the address to geographic coordinates by the use of the Google Geocoding API.
https://maps.googleapis.com/maps/api/geocode/json?address=SOME_ADDRESS&key=YOUR_API_KEY
Then, you can use Python and a styled static map to obtain the polygon of the building (in pixel coordinates) at some location:
import numpy as np
from requests.utils import quote
from skimage.measure import find_contours, points_in_poly, approximate_polygon
from skimage import io
from skimage import color
from threading import Thread
center_latitude = None ##put latitude here
center_longitude = None ##put longitude here
mapZoom = str(20)
midX = 300
midY = 300
# Styled google maps url showing only the buildings
safeURL_Style = quote('feature:landscape.man_made|element:geometry.stroke|visibility:on|color:0xffffff|weight:1')
urlBuildings = "http://maps.googleapis.com/maps/api/staticmap?center=" + str_Center + "&zoom=" + mapZoom + "&format=png32&sensor=false&size=" + str_Size + "&maptype=roadmap&style=visibility:off&style=" + safeURL_Style
mainBuilding = None
imgBuildings = io.imread(urlBuildings)
gray_imgBuildings = color.rgb2gray(imgBuildings)
# will create inverted binary image
binary_imageBuildings = np.where(gray_imgBuildings > np.mean(gray_imgBuildings), 0.0, 1.0)
contoursBuildings = find_contours(binary_imageBuildings, 0.1)
for n, contourBuilding in enumerate(contoursBuildings):
if (contourBuilding[0, 1] == contourBuilding[-1, 1]) and (contourBuilding[0, 0] == contourBuilding[-1, 0]):
# check if it is inside any other polygon, so this will remove any additional elements
isInside = False
skipPoly = False
for othersPolygon in contoursBuildings:
isInside = points_in_poly(contourBuilding, othersPolygon)
if all(isInside):
skipPoly = True
break
if skipPoly == False:
center_inside = points_in_poly(np.array([[midX, midY]]), contourBuilding)
if center_inside:
# approximate will generalize the polygon
mainBuilding = approximate_polygon(contourBuilding, tolerance=2)
print(mainBuilding)
Now, you can convert the pixel coordinates to latitude and longitude by the use of little JavaScript, and the Google Maps API:
function point2LatLng(point, map) {
var topRight = map.getProjection().fromLatLngToPoint(map.getBounds().getNorthEast());
var bottomLeft = map.getProjection().fromLatLngToPoint(map.getBounds().getSouthWest());
var scale = Math.pow(2, map.getZoom());
var worldPoint = new google.maps.Point(point.x / scale + bottomLeft.x, point.y / scale + topRight.y);
return map.getProjection().fromPointToLatLng(worldPoint);
}
var convertedPointsMain = [];
for (var i = 0; i < pxlMainPolygons[p].length; i++) {
var conv_point = {
x: Math.round(pxlMainPolygons[p][i][1]),
y: Math.round(pxlMainPolygons[p][i][0])
};
convertedPointsMain[i] = point2LatLng(conv_point, map);
}
console.log(convertedPointsMain);
Might I humbly suggest you use OpenStreetMaps for this instead ?
It's a lot easier, because then you can use the OverPass API.
However, polygons might not match with google-maps or with state survey.
The latter also holds true if you would use google-maps.
// https://wiki.openstreetmap.org/wiki/Overpass_API/Overpass_QL
private static string GetOqlBuildingQuery(int distance, decimal latitude, decimal longitude)
{
System.Globalization.NumberFormatInfo nfi = new System.Globalization.NumberFormatInfo()
{
NumberGroupSeparator = "",
NumberDecimalSeparator = ".",
CurrencyGroupSeparator = "",
CurrencyDecimalSeparator = ".",
CurrencySymbol = ""
};
// [out: json];
// way(around:25, 47.360867, 8.534703)["building"];
// out ids geom meta;
string oqlQuery = #"[out:json];
way(around:" + distance.ToString(nfi) + ", "
+ latitude.ToString(nfi) + ", " + longitude.ToString(nfi)
+ #")[""building""];
out ids geom;"; // ohne meta - ist minimal
return oqlQuery;
}
public static System.Collections.Generic.List<Wgs84Point> GetWgs84PolygonPoints(int distance, decimal latitude, decimal longitude)
{
string[] overpass_services = new string[] {
"http://overpass.osm.ch/api/interpreter",
"http://overpass.openstreetmap.fr/api/interpreter",
"http://overpass-api.de/api/interpreter",
"http://overpass.osm.rambler.ru/cgi/interpreter",
// "https://overpass.osm.vi-di.fr/api/interpreter", // offline...
};
// string url = "http://overpass.osm.ch/api/interpreter";
// string url = "http://overpass-api.de/api/interpreter";
string url = overpass_services[s_rnd.Next(0, overpass_services.Length)];
System.Collections.Specialized.NameValueCollection reqparm = new System.Collections.Specialized.NameValueCollection();
reqparm.Add("data", GetOqlBuildingQuery(distance, latitude, longitude));
string resp = PostRequest(url, reqparm);
// System.IO.File.WriteAllText(#"D:\username\Documents\visual studio 2017\Projects\TestPlotly\TestSpatial\testResponse.json", resp, System.Text.Encoding.UTF8);
// System.Console.WriteLine(resp);
// string resp = System.IO.File.ReadAllText(#"D:\username\Documents\visual studio 2017\Projects\TestPlotly\TestSpatial\testResponse.json", System.Text.Encoding.UTF8);
System.Collections.Generic.List<Wgs84Point> ls = null;
Overpass.Building.BuildingInfo ro = Overpass.Building.BuildingInfo.FromJson(resp);
if (ro != null && ro.Elements != null && ro.Elements.Count > 0 && ro.Elements[0].Geometry != null)
{
ls = new System.Collections.Generic.List<Wgs84Point>();
for (int i = 0; i < ro.Elements[0].Geometry.Count; ++i)
{
ls.Add(new Wgs84Point(ro.Elements[0].Geometry[i].Latitude, ro.Elements[0].Geometry[i].Longitude, i));
} // Next i
} // End if (ro != null && ro.Elements != null && ro.Elements.Count > 0 && ro.Elements[0].Geometry != null)
return ls;
} // End Function GetWgs84Points
I've been working on this for hours, the closest I have come is finding a request uri that returns a result with a polygon in it. I believe it specifies the building(boundary) by editids parameter. We just need a way to get the current editids from a building(boundary).
The URI I have is:
https://www.google.com/mapmaker?hl=en&gw=40&output=jsonp&ll=38.934911%2C-92.329359&spn=0.016288%2C0.056477&z=14&mpnum=0&vpid=1354239392511&editids=nAlkfrzSpBMuVg-hSJ&xauth=YOUR_XAUTH_HERE&geowiki_client=mapmaker&hl=en
Part of the result has what is needed:
"polygon":[{"gnew":{"loop":[{"vertex":[{"lat_e7":389364691,"lng_e7":-923341133},{"lat_e7":389362067,"lng_e7":-923342783},{"lat_e7":389361075,"lng_e7":-923343356},{"lat_e7":389360594,"lng_e7":-923342477},
I was intrigued on this problem and wrote a solution to it. See my github project.
The Google Maps API contains a GeocoderResults object that might be what you need. Specifically the data returned in the geometry field.