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.

-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
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.
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.

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