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");
}
}
}