can geolocation fields be used to calculate and display distance?

You can use the DISTANCE and GEOLOCATION formula functions to create a custom field that will calculate the distance in miles to a fixed location. Then you can use this field in your Visualforce pages as required.

DISTANCE(acme_distribution__c, GEOLOCATION(37.775,-122.418), "mi")

Failing that, you can do the haversine formula calculation yourself in Apex:

public Decimal calculateHaversineDistance(Decimal lat1, Decimal lon1, Decimal lat2, Decimal lon2){
    // Earth's radius varies from 6356.752 km at the poles to 6378.137 km at the equator
    Double radius = 6371.00;
    Double dLat = toRadians(lat2-lat1);
    Double dLon = toRadians(lon2-lon1);
    Double a = Math.sin(dLat/2) * Math.sin(dLat/2) +
        Math.cos(toRadians(lat1)) * Math.cos(toRadians(lat2)) *
        Math.sin(dLon/2) * Math.sin(dLon/2);
    Double c = 2 * Math.asin(Math.sqrt(a));

    double kmToMiles = 0.621371;
    return radius * c * kmToMiles;
}

private Double toRadians(Decimal degree){
    return degree * 3.1415926 / 180;
}

Note that this includes the conversion from kilometres to miles in case you are in one of the three countries in the world that don't use the metric system :)

You may want to work to, say, 4 significant figures, as there are a number of simplifications in this approach.


Yes, this is possible without an external API using the Location class, which can be instantiated with a latitude and longitude or queried from the database. Here's the example from the documentation.

// Select and access the Location field. MyLocation__c is the name of a geolocation field on Account.
Account[] records = [SELECT id, MyLocation__c FROM Account LIMIT 10];
for(Account acct : records) {
   Location loc = acct.MyLocation__c;
   Double lat = loc.latitude;
   Double lon = loc.longitude;
}

// Instantiate new Location objects and compute the distance between them in different ways.
Location loc1 = Location.newInstance(28.635308,77.22496);
Location loc2 = Location.newInstance(37.7749295,-122.4194155);
Double dist = Location.getDistance(loc1, loc2, 'mi');
Double dist2 = loc1.getDistance(loc2, 'mi');

As of Spring '16 release, you can now use the DISTANCE function in SOQL SELECT clause so you can easily display distance in your query results. Do note, this is the haversine distance that @Daniel Ballinger already mentioned in his answer instead of "driving distance".

From the release notes...

DISTANCE() Support with Location-based SOQL Queries

The DISTANCE function is now supported with location-based queries. DISTANCE() now works with location and address fields. You can retrieve a specific distance (say, of a store from a contact’s location) and display it to the user. For example:

SELECT Id, Name, Location, DISTANCE(Location, GEOLOCATION(latitude, longitude), 'mi') FROM CONTACT;

Sample Apex Code

// Assuming your accounts have their billing address geocoded
// such that BillingLatitude and BillingLongitude are not null
// then this query finds the nearest 3 accounts to a particular location
Decimal latitude = 10;
Decimal longitude = 10;

List<Account> accounts = new List<Account>([
    SELECT
        id, name, billingStreet, billingCity, billingState, billingPostalCode,
        // Using DISTANCE function in SELECT statement, aliasing field as 'dist'
        DISTANCE( BillingAddress, GEOLOCATION( :latitude, :longitude ), 'mi' ) dist
    FROM
        Account
    ORDER BY
        DISTANCE( BillingAddress, GEOLOCATION( :latitude, :longitude ), 'mi' )
    LIMIT 3
]);

// To display the distance value from SELECT statement
// use the 'get' function instead of dot notation.
// This is similar to retrieving field results from aggregate queries.
for ( Account acct : accounts ) {
    System.debug( acct.get('dist' ) );
}

Tags:

Geolocation