Store Locator using Java

We would like to write a program to find the closest store to an input address. The program is provided with a list of locations; it asks for an input address, and then outputs the closet store location.

The dataset here contains geographical locations of McDonald’s in North America. It is a CSV (Comma-Separated Values) file with three columns: latitude, longitude, and address.

1
2
3
4
-122.994495, 49.281079, 4805 E Hastings St Burnaby BC V5C 2L1
-123.029985, 49.281001, 3444 E Hastings Street Vancouver BC V5K 2A6
-123.024074, 49.265642, 3695 Lougheed Hwy Vancouver BC V5M 2A6
......

Solution

The basic idea is as below:

  • Design a Store class, and load all data into an ArrayList of Stores.
  • Ask the user for an address, and find its geographical location.
  • Scan through the ArrayList of all stores to find the closest one.

First, we define the Location class with the following attributes and methods:

  • String address
  • double latitude
  • double longitude
  • public Location(String addr, double lat, double lng)
  • double distanceTo(Location loc): computes the distance to loc
  • String toString(): displays the location
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
public class Location
{
    private String      address;
    private double      latitude;
    private double      longitude;
 
    public Location(String addr, double lat, double lng)
    {
        address = addr;
        latitude = lat;
        longitude = lng;
    }
 
    // Compute the distance in meters
    public double distanceTo(Location loc)
    {
        double earthRadius = 3958.75;
        double dLat = Math.toRadians(latitude - loc.latitude);
        double dLng = Math.toRadians(longitude - loc.longitude);
        double a = Math.sin(dLat/2) * Math.sin(dLat/2) +
            Math.cos(Math.toRadians(latitude)) *
            Math.cos(Math.toRadians(latitude)) *
            Math.sin(dLng/2) * Math.sin(dLng/2);
        double c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a));
        double dist = earthRadius * c;
        return dist * 1609;
    }
 
    public String toString()
    {
        return address + " (" + latitude + ", " + longitude + ")";
    }
}

Now we define a tool class LocationTool. It has the following methods:

  • ArrayList loadData(String urlString): reads data from the url
  • Location makeLocation(String addr): creates a location object from an address. We use Google’s geocoding services to find the latitude and longitude of an address string.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
import java.io.IOException;
import java.net.URL;
import java.net.URLEncoder;
import java.util.Scanner;
public class LocationTool
{
    // Read from URL and return the content in a String
    public static String readURLContent(String urlString)
        throws IOException
    {
        URL url = new URL(urlString);
        Scanner scan = new Scanner(url.openStream());
        String content = new String();
        while (scan.hasNext())
            content += scan.nextLine();
        scan.close();
        return content;
    }
     
    // Extract the middle part of a string from "open" to "close"
    public static String extractMiddle(String str,
        String open, String close)
    {
        int begin = str.indexOf(open) + open.length();
        int end = str.indexOf(close, begin);
        return str.substring(begin, end);      
    }
     
    // Extract the middle part of a string from "open" to the end
    public static String extractMiddle(String str, String open)
    {
        int begin = str.indexOf(open) + open.length();
        return str.substring(begin);       
    }
     
    // Make a Location object from a string address
    public static Location makeLocation(String addr)
        throws IOException
    {
        String url =
"http://maps.google.com/maps/api/geocode/json?sensor=false&address=";
        url += URLEncoder.encode(addr, "UTF-8");
        String content = readURLContent(url);
        String formatted_address = extractMiddle(content,
            "\"formatted_address\" : \"", "\",");
        String latlng = extractMiddle(content,
            "\"location\" : {", "},");
        double lat = Double.parseDouble(extractMiddle(latlng,
            "\"lat\" :", ","));
        double lng = Double.parseDouble(extractMiddle(latlng,
            "\"lng\" :"));
        return new Location(formatted_address, lat, lng);
    }
}

Finally we build the main program Locator with a main method. As the program starts, it loads the data; then it asks for an input address, finds its geographical location, and searches for the closet store.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
import java.io.IOException;
import java.util.ArrayList;
import java.util.Scanner;
public class Locator
{
    public static void main(String[] args) throws IOException
    {
        String urlStr =
"http://www.theoryapp.com/wp-content/uploads/2013/01/mcdonalds.csv";
        ArrayList<Location> stores = LocationTool.loadData(urlStr);      
        Scanner scan = new Scanner(System.in);
        while (true)
        {
            System.out.println("Please type in an address:");
            String  addr = scan.nextLine();
            if (addr.length() == 0)
                break;
             
            Location loc = LocationTool.makeLocation(addr);
            System.out.println("Your location is at: " + loc);
 
            double distance = -1;
            Location nearStore = null;
            for (Location e : stores)
            {
                double d = loc.distanceTo(e);
                if (d <= distance || distance < 0)
                {
                    distance = d;
                    nearStore = e;
                }
            }
            System.out.println("The closet McDonald is at: "
                + nearStore);
            System.out.println("The distance is " +
                (int) distance + " m");
        }
    }
}

Related Posts

Comments

comments