I have some problems with my bing maps.
The first one happens when I click on My Location - from almost all locations I were it worked fine, but there are some locations that returns null, why? (It happened me in a new building that hasn't address yet and also happened in a building with no internet connections).
The method:
private async void MyLocation_Click(object sender, RoutedEventArgs e)
{
Bing.Maps.Location location = await GeoLocation.GetCurrentLocationAsync();
MapLayer.SetPosition(_flagPin, location);
map.SetView(location, 15);
}
The first line calls to my static function:
public static async Task<Bing.Maps.Location> GetCurrentLocationAsync()
{
Geolocator geo = new Geolocator();
geo.DesiredAccuracy = PositionAccuracy.Default;
Geoposition currentPosition = null;
currentPosition = await geo.GetGeopositionAsync();
return new Bing.Maps.Location()
{
Latitude = currentPosition.Coordinate.Latitude,
Longitude = currentPosition.Coordinate.Longitude
};
}
What is the problem? How to fix it?
And the second question is about addresses.
When I get an Address object, there are many formats I can select such as FormattedAddress, CountryRegion, PostalTown, I selected The FormattedAddress and there is a problem with it.
My code:
GeocodeResponse GP = await GeoLocation.ReverseGeocodeAsync(location.Latitude, location.Longitude);
EventContext.Address = GP.Results[0].Address.FormattedAddress;
The problem is when I want to send an Address and get the Location.
Sometimes this code returns null, why?
GeocodeResponse GP = await GeoLocation.GeocodeAsync(EventContext.Address);
I thought that maybe the problem is that sometimes the Address (Formatted) is not good, sometimes it gives weird addresses, such as, "Street, st. Canada", which is not found and therefore, it returns null. But what can I do to send a correctly Address? Does FomattedAddress is good?
Here are the two GeoCodeAsync and ReverseGeocodeAsync functions:
public static async Task<GeocodeResponse> GeocodeAsync(string address)
{
GeocodeService.GeocodeRequest geocodeRequest = new GeocodeService.GeocodeRequest();
// Set credentials using a Bing Maps key
geocodeRequest.Credentials = new GeocodeService.Credentials();
geocodeRequest.Credentials.ApplicationId = Application.Current.Resources["BingCredentials"] as string;
// Set the address
geocodeRequest.Query = address;
// Make the geocode request
GeocodeService.GeocodeServiceClient geocodeService = new GeocodeServiceClient(GeocodeServiceClient.EndpointConfiguration.BasicHttpBinding_IGeocodeService);
GeocodeResponse geocodeResponse = await geocodeService.GeocodeAsync(geocodeRequest);
return geocodeResponse;
}
public static async Task<GeocodeResponse> ReverseGeocodeAsync(double latitude, double longitude)
{
ReverseGeocodeRequest reverseGeocodeRequest = new ReverseGeocodeRequest();
// Set credentials using a Bing Maps key
reverseGeocodeRequest.Credentials = new GeocodeService.Credentials();
reverseGeocodeRequest.Credentials.ApplicationId = Application.Current.Resources["BingCredentials"] as string;
// Set the coordinates
reverseGeocodeRequest.Location = new GeocodeService.GeocodeLocation() { Latitude = latitude, Longitude = longitude };
// Make the reverse geocode request
GeocodeServiceClient geocodeService = new GeocodeServiceClient(GeocodeServiceClient.EndpointConfiguration.BasicHttpBinding_IGeocodeService);
GeocodeResponse geocodeResponse = await geocodeService.ReverseGeocodeAsync(reverseGeocodeRequest);
return geocodeResponse;
}
To clarify your first issue, are you getting null from the GPS or is it the address information in the result that is null the issue? If the GPS is returning null then it's possible that your GPS isn't able to get the current position where you are. This has nothing to do with Bing Maps and more so just an issue which your mobile device getting a clear view to the GPS satellites. If the issue is that the address information in the result is null then this is to be expected with new buildings that might not yet be known in the Bing Maps data set. It usually takes several months for new buildings to be found and added to the map data set. If you have no internet connection then the mobile device won't be able to connect to Bing Maps to get the address information. Note that Bing Maps is over 9 Petabytes in size so there is no local copy of the data on your mobile device.
If you already have the coordinates and the address information you shouldn't be geocoding it again. This is a waste of time and will cause issues. The geocoder will sometimes return "street" or "ramp" if the coordinate in which you pass to the reverse geocoder is on an unnamed street. Note geocoders are not designed to clean/validate addresses. They are designed to take an address and return a coordinate. Reverse geocoders are designed to take a coordinate and find the nearest address. Mixing the results from one with the other can result in odd results as the coordinates for each could be significantly different. It rare cases it's possible to loop between both services and get different results each time as the results will slightly be different and end up "walking" along a street.
Related
I am trying to develop a control IP camera with ONVIF.But I have a little problem of connect PTZ server of ONVIF.
Here is my code:
private void PTZTest(DeviceClient client, double deviceTimeOffset, string ip, int port)
{
// Create Media object
string xaddr = string.Format("http://{0}/onvif/device_service", txtIP.Text);
MediaClient mediaService = OnvifServices.GetOnvifMediaClient(xaddr, deviceTimeOffset, txtUser.Text, txtPassword.Text);
// Create PTZ object
string xaddr2 = string.Format("http://{0}/onvif/ptz_service",txtIP.Text);
PTZClient ptzService = OnvifServices.GetOnvifPTZClient(xaddr2, deviceTimeOffset, txtUser.Text, txtPassword.Text);
// Get target profile
Profile[] mediaProfiles = mediaService.GetProfiles();
Profile mediaProfile = mediaService.GetProfile(mediaProfiles[0].token);
PTZConfigurationOptions ptzConfigurationOptions = ptzService.GetConfigurationOptions(mediaProfile.PTZConfiguration.token);
PTZ.PTZSpeed velocity = new PTZ.PTZSpeed();
velocity.Zoom = new PTZ.Vector1D() { x = speed * ptzConfigurationOptions.Spaces.ContinuousZoomVelocitySpace[0].XRange.Max };
When I set a breakpoint at the line
PTZConfigurationOptions ptzConfigurationOptions = ptzService.GetConfigurationOptions(mediaProfile.PTZConfiguration.token); I got this error message:
There was no listening endpoint on
http://192.168.123.2/onvif/ptz_service that could accept the message.
This is often due to an incorrect SOAP address or action. If present,
see the InnerException element for more information.
But I dont understand why I can have the list of the PTZ services and all the informations about the mediaService, but I couldn't get the ptzconfiguration option.
Does anyone know what's the problem exactly ? And how can I resolve it, please!
Not every onvif device will host its PTZ service on the same endpoint. Generally the approach to use is to query the GetServices/GetCapabilities calls from the DeviceService. This is the only service that usually always has the same URL - "http://ip/onvif/device_service"
Approach to use is therefore(in pseudocode)
var devService = OnvifServices.GetOnvifDeviceService("http://ip/onvif/device_service)
var services = devService.GetServices() or devService.GetCapabilities()
var ptzServiceInfo = services.Where(x => x.Name.Contains("Ptz));
var ptzServiceInfo = OnvifServices.GetPtzService(ptzServiceInfo.Url);
you do not use the device_server to do any ptz_service calls, you simply use it to do a lookup for the correct URL of the device service If you do the GetService call the response will include something like
<tds:Service> <tds:Namespace>onvif.org/ver20/ptz/wsdl</tds:Namespace> <tds:XAddr>ip/onvif/ptz</tds:XAddr> </tds:Service>
See onvif.org/specs/core/ONVIF-Core-Specification-v250.pdf for more details
I'm having a difficult time figuring out how to properly get distances between two Locations in Xamarin. At least I'm consistently getting the wrong results, according to almighty Google.
This code explains the problem.
public void OnLocationChanged(Location location)
{
// Longitude/Latitude of Tower Bridge.
location.Longitude = 51.5053446;
location.Latitude = -0.0765396;
foreach (var store in this.stores)
{
if (store.DistanceView != null)
{
Location store_loc = new Location(location.Provider);
//store_loc.Longitude = double.Parse(store.GPSN);
//store_loc.Latitude = double.Parse(store.GPSW);
// Longitude/Latitude of Big Ben.
store_loc.Longitude = 51.5005747;
store_loc.Latitude = -0.1247025;
var distance = location.DistanceTo(store_loc);
// Google Maps ("measure distance") says 3.44km.
// Xamarin (variable "distance") says 5351.983 meters.
store.DistanceView.Text = distance.ToString();
}
}
}
The actual locations I'm working with are different (for reasons of privacy), but the measurement error is similar, in that I'm getting a result that's not quite twice as high as measured by Google Maps, but somewhere in the vicinity. At any rate, the above measurements should match, and they don't.
I am developing a UWP app using the Maps control that allows a user to plan a route by adding waypoints on the map using various methods such as clicking on the UWP Map control. One of the ways I want to allow a user to add a waypoint or location is to search by actual address. I use the BING Maps REST services code below but if I don't supply the language and culture of where the app is currently being used it always returns American addresses first which are clearly no use to users not in the USA (Yes Microsoft, some of us actually live outside the USA - shock, horror!). I discovered if I supplied the language-culture string such as "en-AU" for Australia then it will search Australian addresses first, and this works really well.
public async Task<List<WayPoint>> FindAddress(string address)
{
List<WayPoint> matchingWaypoints = new List<WayPoint>();
//Create a Geocode request to submit to the BING Maps REST service.
var request = new GeocodeRequest()
{
Query = address.Trim(),
Culture = "en-AU", //HOW CAN I GET THIS FROM THE DEVICE'S CURRENT LOCATION???
IncludeIso2 = true,
IncludeNeighborhood = true,
MaxResults = 10,
BingMapsKey = MapServiceToken
};
//Process the request by using the BING Maps REST services.
var response = await ServiceManager.GetResponseAsync(request);
if (response != null &&
response.ResourceSets != null &&
response.ResourceSets.Length > 0 &&
response.ResourceSets[0].Resources != null &&
response.ResourceSets[0].Resources.Length > 0)
{
int wpNumber = 0;
foreach (BingMapsRESTToolkit.Location loc in response.ResourceSets[0].Resources)
matchingWaypoints.Add(new WayPoint(wpNumber++, loc.Address.FormattedAddress, loc.Point.Coordinates[0], loc.Point.Coordinates[1]));
}
return matchingWaypoints;
}
So what I obviously want to do is derive this string based on the device's current location (i.e: country) NOT from the device's region settings. So for example if someone is using the app the USA I want to specify en-US, if they're in New Zealand it would be en-NZ, if in France it would be "fr-FR" etc. Does anyone know how I could do this? All the stuff I've read about localisation uses the device settings NOT the current physical location so I'm still trying to work out how to do it.
If anyone can help out I'd really appreciate it :-)
There is an official sample of how to get location at https://github.com/Microsoft/Windows-universal-samples/tree/master/Samples/Geolocation
This will return the latitude and longitude. You can then use a different Bing API to get the country based on that lat/long.
This will give you a country name. With this you can lookup against a pre-generated list of codes to country names (created with CultureInfo.GetCultures() on your machine) or you could look at this for a way of doing this at runtime as GetCultures() isn't supported in UWP.
Using the Regional settings is simpler but if you want to use the actual location then this is the way to go. For devices where access to location isn't available then regional settings could be a good back up.
Another approach would be one of various public APIs which will give you information such as location based on IP address. This also isn't perfect though due to the use of proxies in different countries, etc.
Thanks for the reply Matt but I worked out how to do it with the help of the Bing Maps forum. Instead of using the REST API am using the FindLocationsAsync call as part of the UWP Map API passing in the address, the local geopoint to use a starting reference (aka a 'hint' location) and the max number of matches to return... here's the code I used which works perfectly. (Note that WayPoint is an object from my model to store various info about a waypoint on the route.)
public async Task<List<WayPoint>> FindAddress(string address)
{
List<WayPoint> matchingWaypoints = new List<WayPoint>();
// Use current location as a query hint so nearest addresses are returned.
BasicGeoposition queryHint = new BasicGeoposition();
queryHint.Latitude = this.CurrentLocation.Position.Latitude;
queryHint.Longitude = this.CurrentLocation.Position.Longitude;
Geopoint hintPoint = new Geopoint(queryHint);
MapLocationFinderResult result =
await MapLocationFinder.FindLocationsAsync(address.Trim(), hintPoint, 5);
// If the query returns results, store in collection of WayPoint objects.
string addresses = "";
if (result.Status == MapLocationFinderStatus.Success)
{
int i = 0;
foreach (MapLocation res in result.Locations)
{
matchingWaypoints.Add(new WayPoint(i++, res.Address.FormattedAddress, res.Point.Position.Latitude, res.Point.Position.Longitude));
}
}
return matchingWaypoints;
}
I currently have the following method being called whenever a location is selected.
Instead of passing the city name as the parameter to search by, I would like to search locations by using latitudes and longitudes.
I will be retrieving the latitude and longitude of the selected city.
How would I need to modify this code in order to obtain this?
Thank you
private void xgrdLocation_SelectedItemChanged(object sender, SelectedItemChangedEventArgs e)
{
this.Cursor = Cursors.AppStarting;
lblFooter.Content = "Searching ...";
pushpin = new MapPushpin();
if (xgrdLocation.SelectedItem != null)
{
City selectedCity = xgrdLocation.SelectedItem as City;
//GeocodeService.Location point = new GeocodeService.Location();
pushpin.Text = selectedCity.CityName;
searchDataProvider.Search(pushpin.Text);
//lblSelectedCity.Content = selectedCity.CityName;
}
}
If you want to get the city that a latitude/longitude value is in, you can use the Reverse Geocoding. The Bing Maps REST Location API has such a feature. https://msdn.microsoft.com/en-us/library/ff701710.aspx
You can also find documentation on how to use the REST services in .NET here: https://msdn.microsoft.com/en-us/library/jj819168.aspx
Not sure, but it looks like you might be using the old legacy SOAP services in your application to do the geocoding currently. Avoid the SOAP services, they are old, slow and nearing end of life.
I'm using ReverseGeocodeQuery class to get location names from coordinates:
ReverseGeocodeQuery query = new ReverseGeocodeQuery();
query.GeoCoordinate = new GeoCoordinate(latitude, longitude);
query.QueryCompleted += (sender, args) =>
{
var result = args.Result[0].Information.Address;
Location location = new Location(result.Street, result.City, result.State, result.Country);
};
query.QueryAsync();
The problem is that results are returned in the system language of the phone. Since I am using place names for tagging purposes, I need all of them in same language, preferably in english.
I have tried by setting the CurrentCulture to en-US:
Thread.CurrentThread.CurrentCulture = new CultureInfo("en-US");
But I'm still getting the results in the language configured as system language.
Is ther any way to get the results from ReverseGeocodeQuery in desired language?
The results are always using the system language. Maybe you can save the name of the place and also the lat long, or use a translation service to translate to englis
Just to complete Josue's answer. An alternative to get reverse geocode results in desided language is to use one of the public REST APIs that allow to specify it (e.g. Google or Nokia Here). While the use of them is simple and are very customizable, the downside is that it is necessary to register to the services in order to get the keys.
I have decided for using HERE's API. So, below you will find the code I have used to achieve the same result as using the code present in the question, but forcing the result to be in English:
using (HttpClient client = new HttpClient())
{
string url = String.Format("http://reverse.geocoder.cit.api.here.com/6.2/reversegeocode.json"
+ "?app_id={0}"
+ "&app_code={1}"
+ "&gen=1&prox={2},{3},100"
+ "&mode=retrieveAddresses"
+ "&language=en-US",
App.NOKIA_HERE_APP_ID, App.NOKIA_HERE_APP_CODE, latitude.ToString(CultureInfo.InvariantCulture), longitude.ToString(CultureInfo.InvariantCulture));
var response = await client.GetAsync(url);
var json = await response.Content.ReadAsStringAsync();
dynamic loc = JObject.Parse(json);
dynamic address = JObject.Parse(loc.Response.View[0].Result[0].Location.Address.ToString());
string street = address.Street;
string city = address.City;
string state = address.State;
string country = address.Country;
Location location = new Location(street, city, state, country);
}