Sorting by distance with Titanium alloy models - javascript

I recently used Titanium and Alloy to develop an android application. Now I'm trying (for the first time) to sort a bound backbone collection by distance with a comparator function, but it doesn't work.
comparator: function(game) {
var lon1, lat1, lat2, lon2;
if (Ti.Geolocation.locationServicesEnabled) {
Ti.Geolocation.getCurrentPosition(function(e) {
if (e.error) {
Ti.API.error('Error:' + e.error);
return 0;
} else {
Ti.API.info(e.coords);
lon1 = e.coords.longitude;
lat1 = e.coords.latitude;
Titanium.Geolocation.forwardGeocoder(game.get("camp"), function(e) {
if (e.success) {
lat2 = e.latitude;
lon2 = e.longitude;
var R = 6371; // km
var dLat = (lat2 - lat1) * Math.PI / 180;
var dLon = (lon2 - lon1) * Math.PI / 180;
var a = Math.sin(dLat / 2) * Math.sin(dLat / 2) +
Math.cos(lat1 * Math.PI / 180) * Math.cos(lat2 * Math.PI / 180) *
Math.sin(dLon / 2) * Math.sin(dLon / 2);
var c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
var d = R * c;
console.log("KM: " + parseInt(d));
return parseInt(d);
} else {
console.log("Unable to find address");
return 0;
}
});
}
});
} else {
console.log('please enable location services')
return 0;
}
}
In my controller, I use:
var games = Alloy.Collections.allGames;
games.sort();
games.fetch();
Can you tell me what is wrong?

I don't use neither Titanium or Alloy, but I can see why your comparator function won't work.
Backbone collection's comparator property
First, to see why it doesn't work, you need to understand what's the collection's comparator property, what's available and how to implement one.
There are (at least) 3 types of value a collection's comparator property can take.
The name of an attribute as a string
comparator: 'fieldName'
A sortBy function which takes a single argument
comparator: function(model) {
// return a numeric or string value by which the model
// should be ordered relative to others.
return Math.sin(model.get('myNumber'));
}
A sort function that expects two arguments
comparator: compare(modelA, modelB) {
var field = 'myNumber',
numA = modelA.get(field),
numB = modelB.get(field);
if (numA < numB) {
return -1;
}
if (numA > numB) {
return 1;
}
// a must be equal to b
return 0;
}
Why yours fails?
The short answer: It only ever returns undefined or 0 depending on the value of Ti.Geolocation.locationServicesEnabled.
You have made a convoluted function to sort your models in which you use asynchronous functions (getCurrentPosition, forwardGeocoder) and you put all the logic inside callbacks which are evaluated when the collection has already finished sorting.

Related

TypeScript/Javascript - TypeError this.function is not a function

I'm a bit new to TypeScript but know JavaScript from before. I have my code for a wheel mini-game for my app and I get the following error on my console.
this.easeOut is not a function
The code is the following (only what is important to the problem I think):
spin() {
const spinAngleStart = Math.random() * 10 + 10;
this.spinTime = 0;
this.spinTimeTotal = Math.random() * 3 + 4 * 1000;
this.rotateWheel(spinAngleStart);
}
rotateWheel(spinAngleStart: number){
this.spinTime += 30;
if(this.spinTime >= this.spinTimeTotal) {
this.stopRotateWheel();
return;
}
*const spinAngle = spinAngleStart - this.easeOut(this.spinTime, 0, spinAngleStart, this.spinTimeTotal);*
this.startAngle += (spinAngle * Math.PI / 180);
this.drawRouletteWheel();
console.log(this.spinTimeTotal);
console.log(this.spinTime);
this.spinTimeout = setTimeout(this.rotateWheel, 30);
}
easeOut(t, b, c, d) {
const ts = (t /= d) * t;
const tc = ts * t;
console.log(ts);
console.log(tc);
return (b+c * (tc + -3*ts + 3*t));
}
As you can see easeOut() does exists inside the same hierarchy of my rotateWheel() function and everything else if not sending any errors, so I do not why it sends an error.
the error is sent to the line with the asterisks
You either want setTimeout(() => this.rotateWheel(), 30) or setTimeout(this.rotateWheel.bind(this), 30);. Otherwise, when rotateWheel is called, this is bound to the window object (or global object in node).

Properly including math.js library in a .js file

I want to use the math.js library in my javascript file - say it's called webpage.js.
What I did so far is having a script tag in the main html file that calls math.js, and then another that calls webpage.js. The script tags are as follows:
<script
src="https://cdnjs.cloudflare.com/ajax/libs/mathjs/6.2.5/math.min.js"
integrity="sha256-fWwwg2Pf3Ox5xhm9xCE7O+czkI2dSkqN6gUZumzGrx0="
crossorigin="anonymous"></script>
<script src="js/lat-long.js"></script>
Is that it? Can I now go to my webpage.js file and use "Math.whatever" without having to 'import' or 'include' anything at the beginning of the file?
The reason I am asking this is because I have the following code which is not working properly (anything using Math.something is returning a NaN, which I assumed was because Math.js was not imported properly).
Here is the code for reference:
function getDistanceFromLatLonInKm(lat1, lon1, lat2, lon2) {
var R = 6371; // Radius of the earth in km
var dLat = deg2rad(lat2 - lat1); // deg2rad below
var dLon = deg2rad(lon2 - lon1);
console.log("dLat------------------" + dLat);
var a =
Math.sin(dLat / 2) * Math.sin(dLat / 2) +
Math.cos(deg2rad(lat1)) *
Math.cos(deg2rad(lat2)) *
Math.sin(dLon / 2) *
Math.sin(dLon / 2);
var c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
var d = R * c; // Distance in km
console.log("d is " + d);
return d;
}
function deg2rad(deg) {
return deg * (Math.PI / 180);
}
var distance = getDistanceFromLatLonInKm(
locationLatUser,
locationLongUser,
supplier.latLng.latitude,
supplier.latLng.longitude
);
//all the values used in the function call exist and are defined.
console.log("distance between user and supplier: " + distance);
Console logging any value in the above code gives me a NaN.

Math.sin incorrect results even when converted to degrees

I'm trying to use sin on a variable and I saw you can convert it by using / (Math.PI / 180) but that seems contradictory if you want to convert it to degrees.. How do I properly convert and use sin in degree form? (On an iPhone calculator, for example it returns ~.707 from an input of 45, while this returns ~.806).
function click25() {
if (vi === 0) {
reactant = Math.sin(reactant / (Math.PI / 180))
}
}
You need to multiply the value in degree by (pi/180) to convert into the equivalent value in radians
var reactant = 45;
var vi = 0;
function click25() {
if (vi === 0) {
reactant = Math.sin(reactant * (Math.PI / 180))
}
console.log(reactant);
}
click25();

Calculation geolocation distance returns NaN

I am trying to work out the distance between a user and the coordinates below, I am not sure what I have done wrong, but I get the response 'NaN' (not a number)
HTML:
<h3>Come visit</h3>
<p>You're only <span class="distance"> </span>km away</p>
JS File:
// Location
if($('#content').hasClass('contact_page')) {
var localSearch = new GlocalSearch();
var sharp_hq = {
lat: 53.639993,
lng: -1.782354
};
// calculate the distance between me and thee
var calculate_distance = function(location) {
return Math.round(3959 * 1.609344
* Math.acos(Math.cos(0.0174532925 * location.y)
* Math.cos(0.0174532925 * sharp_hq.lat)
* Math.cos((0.0174532925 * sharp_hq.lng) - (location.x * 0.0174532925))
+ Math.sin(0.0174532925 * location.y)
* Math.sin(0.0174532925 * sharp_hq.lat)));
};
// geo location
if(navigator.geolocation) {
navigator.geolocation.getCurrentPosition(function(position) {
initialLocation = new google.maps.LatLng(position.coords.latitude, position.coords.longitude);
//display in .distance <span>
$('.distance', '.location').html(calculate_distance(initialLocation));
$('p', '.location').css({ display: 'block' });
});
}
}
this works for me;
$(document).ready(function(){
var sharp_hq = {
lat: 53.639993,
lng: -1.782354
};
// geo location
if(navigator.geolocation) {
navigator.geolocation.getCurrentPosition(function(position) {
$('.distance').html( gc(position.coords.latitude,position.coords.longitude,sharp_hq.lat,sharp_hq.lng).toFixed(2) );
$('p', '.location').css({ display: 'block' });
});
}
} ) ;
/** Converts numeric degrees to radians */
if (typeof (Number.prototype.toRad) === "undefined") {
Number.prototype.toRad = function () {
return this * (Math.PI / 180);
}
};
function gc(lat1, lon1, lat2, lon2) {
// returns the distance in km between the pair of latitude and longitudes provided in decimal degrees
var R = 6371; // km
var dLat = (lat2 - lat1).toRad();
var dLon = (lon2 - lon1).toRad();
var a = Math.sin(dLat / 2) * Math.sin(dLat / 2) +
Math.cos(lat1.toRad()) * Math.cos(lat2.toRad()) *
Math.sin(dLon / 2) * Math.sin(dLon / 2);
var c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
var d = R * c;
return d;
}
A google.maps.LatLng object doesn't have .x or .y properties
Looks like you might still be expecting the Google Maps Javascript API v2 to work (it has been replaced by a wrapper for v3).
Instead of location.x/location.y use location.lat() for the latitude and location.lng() for the longitude. Or make your own anonymous object with .x and .y properties (but don't expect it to be interchangeable with a google.maps.LatLng object).
Note: the Google Maps Javascript API v3 has a library to calculate distance.
You can use a function called google.maps.geometry.computeDistanceBetween() that finds the distance between two latlng objects.
https://developers.google.com/maps/documentation/javascript/geometry
Replace the call to the calculate_distance function with
var distance = google.maps.geometry.spherical.computeDistanceBetween(
new google.maps.LatLng(sharp_hq.lat, sharphq.lng),
initialLocation
) / 1000;
$('.distance').text(distance);
Returns the distance in meters so divide by 1000.
In your formula, the value of (0.0174532925 * sharp_hq.lng) - (location.x * 0.0174532925) could be < 0 causing NaN.
You need to pre-process it to 0 if it is <0 to avoid the exception.
I wish this resolves your issue without changing the whole formula.

Calculate distance between 2 co-ordinates [duplicate]

How do you calculate the distance between two markers in Google maps V3? (Similar to the distanceFrom function inV2.)
Thanks..
If you want to calculate it yourself, then you can use the Haversine formula:
var rad = function(x) {
return x * Math.PI / 180;
};
var getDistance = function(p1, p2) {
var R = 6378137; // Earth’s mean radius in meter
var dLat = rad(p2.lat() - p1.lat());
var dLong = rad(p2.lng() - p1.lng());
var a = Math.sin(dLat / 2) * Math.sin(dLat / 2) +
Math.cos(rad(p1.lat())) * Math.cos(rad(p2.lat())) *
Math.sin(dLong / 2) * Math.sin(dLong / 2);
var c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
var d = R * c;
return d; // returns the distance in meter
};
There actually seems to be a method in GMap3. It's a static method of the google.maps.geometry.spherical namespace.
It takes as arguments two LatLng objects and will utilize a default Earth radius of 6378137 meters, although the default radius can be overridden with a custom value if necessary.
Make sure you include:
<script type="text/javascript" src="http://maps.google.com/maps/api/js?sensor=false&v=3&libraries=geometry"></script>
in your head section.
The call will be:
google.maps.geometry.spherical.computeDistanceBetween (latLngA, latLngB);
Example using GPS latitude/longitude of 2 points.
var latitude1 = 39.46;
var longitude1 = -0.36;
var latitude2 = 40.40;
var longitude2 = -3.68;
var distance = google.maps.geometry.spherical.computeDistanceBetween(new google.maps.LatLng(latitude1, longitude1), new google.maps.LatLng(latitude2, longitude2));
Just add this to the beginning of your JavaScript code:
google.maps.LatLng.prototype.distanceFrom = function(latlng) {
var lat = [this.lat(), latlng.lat()]
var lng = [this.lng(), latlng.lng()]
var R = 6378137;
var dLat = (lat[1]-lat[0]) * Math.PI / 180;
var dLng = (lng[1]-lng[0]) * Math.PI / 180;
var a = Math.sin(dLat/2) * Math.sin(dLat/2) +
Math.cos(lat[0] * Math.PI / 180 ) * Math.cos(lat[1] * Math.PI / 180 ) *
Math.sin(dLng/2) * Math.sin(dLng/2);
var c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a));
var d = R * c;
return Math.round(d);
}
and then use the function like this:
var loc1 = new GLatLng(52.5773139, 1.3712427);
var loc2 = new GLatLng(52.4788314, 1.7577444);
var dist = loc2.distanceFrom(loc1);
alert(dist/1000);
//p1 and p2 are google.maps.LatLng(x,y) objects
function calcDistance(p1, p2) {
var d = (google.maps.geometry.spherical.computeDistanceBetween(p1, p2) / 1000).toFixed(2);
console.log(d);
}
Here is the c# implementation of the this forumula
public class DistanceAlgorithm
{
const double PIx = 3.141592653589793;
const double RADIO = 6378.16;
/// <summary>
/// This class cannot be instantiated.
/// </summary>
private DistanceAlgorithm() { }
/// <summary>
/// Convert degrees to Radians
/// </summary>
/// <param name="x">Degrees</param>
/// <returns>The equivalent in radians</returns>
public static double Radians(double x)
{
return x * PIx / 180;
}
/// <summary>
/// Calculate the distance between two places.
/// </summary>
/// <param name="lon1"></param>
/// <param name="lat1"></param>
/// <param name="lon2"></param>
/// <param name="lat2"></param>
/// <returns></returns>
public static double DistanceBetweenPlaces(
double lon1,
double lat1,
double lon2,
double lat2)
{
double dlon = Radians(lon2 - lon1);
double dlat = Radians(lat2 - lat1);
double a = (Math.Sin(dlat / 2) * Math.Sin(dlat / 2)) + Math.Cos(Radians(lat1)) * Math.Cos(Radians(lat2)) * (Math.Sin(dlon / 2) * Math.Sin(dlon / 2));
double angle = 2 * Math.Atan2(Math.Sqrt(a), Math.Sqrt(1 - a));
return (angle * RADIO) * 0.62137;//distance in miles
}
}
With google you can do it using the spherical api, google.maps.geometry.spherical.computeDistanceBetween (latLngA, latLngB);.
However, if the precision of a spherical projection or a haversine solution is not precise enough for you (e.g. if you're close to the pole or computing longer distances), you should use a different library.
Most information on the subject I found on Wikipedia here.
A trick to see if the precision of any given algorithm is adequate is to fill in the maximum and minimum radius of the earth and see if the difference might cause problems for your use case. Many more details can be found in this article
In the end the google api or haversine will serve most purposes without problems.
Using PHP, you can calculate the distance using this simple function :
// to calculate distance between two lat & lon
function calculate_distance($lat1, $lon1, $lat2, $lon2, $unit='N')
{
$theta = $lon1 - $lon2;
$dist = sin(deg2rad($lat1)) * sin(deg2rad($lat2)) + cos(deg2rad($lat1)) * cos(deg2rad($lat2)) * cos(deg2rad($theta));
$dist = acos($dist);
$dist = rad2deg($dist);
$miles = $dist * 60 * 1.1515;
$unit = strtoupper($unit);
if ($unit == "K") {
return ($miles * 1.609344);
} else if ($unit == "N") {
return ($miles * 0.8684);
} else {
return $miles;
}
}
// function ends here
OFFLINE SOLUTION - Haversine Algorithm
In Javascript
var _eQuatorialEarthRadius = 6378.1370;
var _d2r = (Math.PI / 180.0);
function HaversineInM(lat1, long1, lat2, long2)
{
return (1000.0 * HaversineInKM(lat1, long1, lat2, long2));
}
function HaversineInKM(lat1, long1, lat2, long2)
{
var dlong = (long2 - long1) * _d2r;
var dlat = (lat2 - lat1) * _d2r;
var a = Math.pow(Math.sin(dlat / 2.0), 2.0) + Math.cos(lat1 * _d2r) * Math.cos(lat2 * _d2r) * Math.pow(Math.sin(dlong / 2.0), 2.0);
var c = 2.0 * Math.atan2(Math.sqrt(a), Math.sqrt(1.0 - a));
var d = _eQuatorialEarthRadius * c;
return d;
}
var meLat = -33.922982;
var meLong = 151.083853;
var result1 = HaversineInKM(meLat, meLong, -32.236457779983745, 148.69094705162837);
var result2 = HaversineInKM(meLat, meLong, -33.609020205923713, 150.77061469270831);
C#
using System;
public class Program
{
public static void Main()
{
Console.WriteLine("Hello World");
var meLat = -33.922982;
double meLong = 151.083853;
var result1 = HaversineInM(meLat, meLong, -32.236457779983745, 148.69094705162837);
var result2 = HaversineInM(meLat, meLong, -33.609020205923713, 150.77061469270831);
Console.WriteLine(result1);
Console.WriteLine(result2);
}
static double _eQuatorialEarthRadius = 6378.1370D;
static double _d2r = (Math.PI / 180D);
private static int HaversineInM(double lat1, double long1, double lat2, double long2)
{
return (int)(1000D * HaversineInKM(lat1, long1, lat2, long2));
}
private static double HaversineInKM(double lat1, double long1, double lat2, double long2)
{
double dlong = (long2 - long1) * _d2r;
double dlat = (lat2 - lat1) * _d2r;
double a = Math.Pow(Math.Sin(dlat / 2D), 2D) + Math.Cos(lat1 * _d2r) * Math.Cos(lat2 * _d2r) * Math.Pow(Math.Sin(dlong / 2D), 2D);
double c = 2D * Math.Atan2(Math.Sqrt(a), Math.Sqrt(1D - a));
double d = _eQuatorialEarthRadius * c;
return d;
}
}
Reference:
https://en.wikipedia.org/wiki/Great-circle_distance
Had to do it... The action script way
//just make sure you pass a number to the function because it would accept you mother in law...
public var rad = function(x:*) {return x*Math.PI/180;}
protected function distHaversine(p1:Object, p2:Object):Number {
var R:int = 6371; // earth's mean radius in km
var dLat:Number = rad(p2.lat() - p1.lat());
var dLong:Number = rad(p2.lng() - p1.lng());
var a:Number = Math.sin(dLat/2) * Math.sin(dLat/2) +
Math.cos(rad(p1.lat())) * Math.cos(rad(p2.lat())) * Math.sin(dLong/2) * Math.sin(dLong/2);
var c:Number = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a));
var d:Number = R * c;
return d;
}
In my case it was best to calculate this in SQL Server, since i wanted to take current location and then search for all zip codes within a certain distance from current location. I also had a DB which contained a list of zip codes and their lat longs. Cheers
--will return the radius for a given number
create function getRad(#variable float)--function to return rad
returns float
as
begin
declare #retval float
select #retval=(#variable * PI()/180)
--print #retval
return #retval
end
go
--calc distance
--drop function dbo.getDistance
create function getDistance(#cLat float,#cLong float, #tLat float, #tLong float)
returns float
as
begin
declare #emr float
declare #dLat float
declare #dLong float
declare #a float
declare #distance float
declare #c float
set #emr = 6371--earth mean
set #dLat = dbo.getRad(#tLat - #cLat);
set #dLong = dbo.getRad(#tLong - #cLong);
set #a = sin(#dLat/2)*sin(#dLat/2)+cos(dbo.getRad(#cLat))*cos(dbo.getRad(#tLat))*sin(#dLong/2)*sin(#dLong/2);
set #c = 2*atn2(sqrt(#a),sqrt(1-#a))
set #distance = #emr*#c;
set #distance = #distance * 0.621371 -- i needed it in miles
--print #distance
return #distance;
end
go
--get all zipcodes within 2 miles, the hardcoded #'s would be passed in by C#
select *
from cityzips a where dbo.getDistance(29.76,-95.38,a.lat,a.long) <3
order by zipcode
//JAVA
public Double getDistanceBetweenTwoPoints(Double latitude1, Double longitude1, Double latitude2, Double longitude2) {
final int RADIUS_EARTH = 6371;
double dLat = getRad(latitude2 - latitude1);
double dLong = getRad(longitude2 - longitude1);
double a = Math.sin(dLat / 2) * Math.sin(dLat / 2) + Math.cos(getRad(latitude1)) * Math.cos(getRad(latitude2)) * Math.sin(dLong / 2) * Math.sin(dLong / 2);
double c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
return (RADIUS_EARTH * c) * 1000;
}
private Double getRad(Double x) {
return x * Math.PI / 180;
}
/**
* Calculates the haversine distance between point A, and B.
* #param {number[]} latlngA [lat, lng] point A
* #param {number[]} latlngB [lat, lng] point B
* #param {boolean} isMiles If we are using miles, else km.
*/
function haversineDistance(latlngA, latlngB, isMiles) {
const squared = x => x * x;
const toRad = x => (x * Math.PI) / 180;
const R = 6371; // Earth’s mean radius in km
const dLat = toRad(latlngB[0] - latlngA[0]);
const dLon = toRad(latlngB[1] - latlngA[1]);
const dLatSin = squared(Math.sin(dLat / 2));
const dLonSin = squared(Math.sin(dLon / 2));
const a = dLatSin +
(Math.cos(toRad(latlngA[0])) * Math.cos(toRad(latlngB[0])) * dLonSin);
const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
let distance = R * c;
if (isMiles) distance /= 1.609344;
return distance;
}
I found a version online which is 80% right but plugged in the wrong parameter and is inconsistent in using the inputs, this version fixed that completely
It's Quite easy using Google Distance Matrix service
First step is to activate Distance Matrix service from google API console.
it returns distances between a set of locations.
And apply this simple function
function initMap() {
var bounds = new google.maps.LatLngBounds;
var markersArray = [];
var origin1 = {lat:23.0203, lng: 72.5562};
//var origin2 = 'Ahmedabad, India';
var destinationA = {lat:23.0436503, lng: 72.55008939999993};
//var destinationB = {lat: 23.2156, lng: 72.6369};
var destinationIcon = 'https://chart.googleapis.com/chart?' +
'chst=d_map_pin_letter&chld=D|FF0000|000000';
var originIcon = 'https://chart.googleapis.com/chart?' +
'chst=d_map_pin_letter&chld=O|FFFF00|000000';
var map = new google.maps.Map(document.getElementById('map'), {
center: {lat: 55.53, lng: 9.4},
zoom: 10
});
var geocoder = new google.maps.Geocoder;
var service = new google.maps.DistanceMatrixService;
service.getDistanceMatrix({
origins: [origin1],
destinations: [destinationA],
travelMode: 'DRIVING',
unitSystem: google.maps.UnitSystem.METRIC,
avoidHighways: false,
avoidTolls: false
}, function(response, status) {
if (status !== 'OK') {
alert('Error was: ' + status);
} else {
var originList = response.originAddresses;
var destinationList = response.destinationAddresses;
var outputDiv = document.getElementById('output');
outputDiv.innerHTML = '';
deleteMarkers(markersArray);
var showGeocodedAddressOnMap = function(asDestination) {
var icon = asDestination ? destinationIcon : originIcon;
return function(results, status) {
if (status === 'OK') {
map.fitBounds(bounds.extend(results[0].geometry.location));
markersArray.push(new google.maps.Marker({
map: map,
position: results[0].geometry.location,
icon: icon
}));
} else {
alert('Geocode was not successful due to: ' + status);
}
};
};
for (var i = 0; i < originList.length; i++) {
var results = response.rows[i].elements;
geocoder.geocode({'address': originList[i]},
showGeocodedAddressOnMap(false));
for (var j = 0; j < results.length; j++) {
geocoder.geocode({'address': destinationList[j]},
showGeocodedAddressOnMap(true));
//outputDiv.innerHTML += originList[i] + ' to ' + destinationList[j] + ': ' + results[j].distance.text + ' in ' + results[j].duration.text + '<br>';
outputDiv.innerHTML += results[j].distance.text + '<br>';
}
}
}
});
}
Where origin1 is your location and destinationA is destindation location.you can add above two or more data.
Rad Full Documentation with an example
To calculate distance on Google Maps, you can use Directions API. That will be one of the easiest way to do it. To get data from Google Server, you can use Retrofit or Volley. Both has their own advantage. Take a look at following code where I have used retrofit to implement it:
private void build_retrofit_and_get_response(String type) {
String url = "https://maps.googleapis.com/maps/";
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(url)
.addConverterFactory(GsonConverterFactory.create())
.build();
RetrofitMaps service = retrofit.create(RetrofitMaps.class);
Call<Example> call = service.getDistanceDuration("metric", origin.latitude + "," + origin.longitude,dest.latitude + "," + dest.longitude, type);
call.enqueue(new Callback<Example>() {
#Override
public void onResponse(Response<Example> response, Retrofit retrofit) {
try {
//Remove previous line from map
if (line != null) {
line.remove();
}
// This loop will go through all the results and add marker on each location.
for (int i = 0; i < response.body().getRoutes().size(); i++) {
String distance = response.body().getRoutes().get(i).getLegs().get(i).getDistance().getText();
String time = response.body().getRoutes().get(i).getLegs().get(i).getDuration().getText();
ShowDistanceDuration.setText("Distance:" + distance + ", Duration:" + time);
String encodedString = response.body().getRoutes().get(0).getOverviewPolyline().getPoints();
List<LatLng> list = decodePoly(encodedString);
line = mMap.addPolyline(new PolylineOptions()
.addAll(list)
.width(20)
.color(Color.RED)
.geodesic(true)
);
}
} catch (Exception e) {
Log.d("onResponse", "There is an error");
e.printStackTrace();
}
}
#Override
public void onFailure(Throwable t) {
Log.d("onFailure", t.toString());
}
});
}
Above is the code of function build_retrofit_and_get_response for calculating distance. Below is corresponding Retrofit Interface:
package com.androidtutorialpoint.googlemapsdistancecalculator;
import com.androidtutorialpoint.googlemapsdistancecalculator.POJO.Example;
import retrofit.Call;
import retrofit.http.GET;
import retrofit.http.Query;
public interface RetrofitMaps {
/*
* Retrofit get annotation with our URL
* And our method that will return us details of student.
*/
#GET("api/directions/json?key=AIzaSyC22GfkHu9FdgT9SwdCWMwKX1a4aohGifM")
Call<Example> getDistanceDuration(#Query("units") String units, #Query("origin") String origin, #Query("destination") String destination, #Query("mode") String mode);
}
I hope this explains your query. All the best :)
Source: Google Maps Distance Calculator
First, are you referring to distance as in length of the entire path or you want to know only the displacement (straight line distance)? I see no one is pointing the difference between distance and displacement here. For distance calculate each route point given by JSON/XML data, as for displacement there is a built-in solution using Spherical class
//calculates distance between two points in km's
function calcDistance(p1, p2) {
return (google.maps.geometry.spherical.computeDistanceBetween(p1, p2) / 1000).toFixed(2);
}
In PHP, with Google Map Distance Matrix API:
//Get the Driving(Mode) distance between two Geo-location points(Latitude, Longitude) pair.
function get_distance($lat1, $lat2, $long1, $long2)
{
$url = "https://maps.googleapis.com/maps/api/distancematrix/json?origins=".$lat1.",".$long1."&destinations=".$lat2.",".$long2."&mode=driving"."&units=imperial";
//You can request distance data for different travel modes, request distance data in different units such as kilometers or miles, and estimate travel time in traffic.
try{
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_PROXYPORT, 3128);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0);
$response = curl_exec($ch);
curl_close($ch);
$response_a = json_decode($response, true);
//Invalid request OR Empty response
if(isset($response_a['error_message']) || empty($response_a['rows']))
throw new Exception($response_a['error_message']);
} catch(Exception $e){
//Handle error here.
return [];
}
//The unit parameter in the request URL only affects the text displayed within distance fields. The distance fields in response also contain values that are always expressed in meters.
$dist = $response_a['rows'][0]['elements'][0]['distance']['text'];
$time = $response_a['rows'][0]['elements'][0]['duration']['text'];
return ['distance' => $dist, 'time' => $time];
}
Reference: Distance Matrix API request and response

Categories