Do you know some utility or a web site where I can give US city,state and radial distance in miles as input and it would return me all the cities within that radius?
<I do not have a website, but we have implemented this both in Oracle as a database function and in SAS as a statistics macro. It only requires a database with all cities and their lat and long.
You can obtain a pretty good database of geolocated cities/placenames from http://geonames.usgs.gov - find an appropriate database dump, import it into your DB, and performing the kind of query your need is pretty straightforward, particularly if your DBMS supports some kind of spatial queries (e.g. like Oracle Spatial, MySQL Spatial Extensions, PostGIS or SQLServer 2008)
See also: how to do location based search
Here is how I do it.
You can obtain a list of city, st, zip codes and their latitudes and longitudes. (I can't recall off the top of my head where we got ours)
edit: http://geonames.usgs.gov/domestic/download_data.htm like someone mentioned above would probably work.
Then you can write a method to calculate the min and max latitude and longitudes based on a radius, and query for all cities between those min and max. Then loop through and calculate the distance and remove any that are not in the radius
double latitude1 = Double.parseDouble(zipCodes.getLatitude().toString());
double longitude1 = Double.parseDouble(zipCodes.getLongitude().toString());
//Upper reaches of possible boundaries
double upperLatBound = latitude1 + Double.parseDouble(distance)/40.0;
double lowerLatBound = latitude1 - Double.parseDouble(distance)/40.0;
double upperLongBound = longitude1 + Double.parseDouble(distance)/40.0;
double lowerLongBound = longitude1 - Double.parseDouble(distance)/40.0;
//pull back possible matches
SimpleCriteria zipCriteria = new SimpleCriteria();
zipCriteria.isBetween(ZipCodesPeer.LONGITUDE, lowerLongBound, upperLongBound);
zipCriteria.isBetween(ZipCodesPeer.LATITUDE, lowerLatBound, upperLatBound);
List zipList = ZipCodesPeer.doSelect(zipCriteria);
ArrayList acceptList = new ArrayList();
if(zipList != null)
{
for(int i = 0; i < zipList.size(); i++)
{
ZipCodes tempZip = (ZipCodes)zipList.get(i);
double tempLat = new Double(tempZip.getLatitude().toString()).doubleValue();
double tempLon = new Double(tempZip.getLongitude().toString()).doubleValue();
double d = 3963.0 * Math.acos(Math.sin(latitude1 * Math.PI/180) * Math.sin(tempLat * Math.PI/180) + Math.cos(latitude1 * Math.PI/180) * Math.cos(tempLat * Math.PI/180) * Math.cos(tempLon*Math.PI/180 -longitude1 * Math.PI/180));
if(d < Double.parseDouble(distance))
{
acceptList.add(((ZipCodes)zipList.get(i)).getZipCd());
}
}
}
There's an excerpt of my code, hopefully you can see what's happening. I start out with one ZipCodes( a table in my DB), then I pull back possible matches, and finally I weed out those who are not in the radius.
Maybe this can help. The project is configured in kilometers though. You can modify these in CityDAO.java
public List<City> findCityInRange(GeoPoint geoPoint, double distance) {
List<City> cities = new ArrayList<City>();
QueryBuilder queryBuilder = geoDistanceQuery("geoPoint")
.point(geoPoint.getLat(), geoPoint.getLon())
//.distance(distance, DistanceUnit.KILOMETERS) original
.distance(distance, DistanceUnit.MILES)
.optimizeBbox("memory")
.geoDistance(GeoDistance.ARC);
SearchRequestBuilder builder = esClient.getClient()
.prepareSearch(INDEX)
.setTypes("city")
.setSearchType(SearchType.QUERY_THEN_FETCH)
.setScroll(new TimeValue(60000))
.setSize(100).setExplain(true)
.setPostFilter(queryBuilder)
.addSort(SortBuilders.geoDistanceSort("geoPoint")
.order(SortOrder.ASC)
.point(geoPoint.getLat(), geoPoint.getLon())
//.unit(DistanceUnit.KILOMETERS)); Original
.unit(DistanceUnit.MILES));
SearchResponse response = builder
.execute()
.actionGet();
SearchHit[] hits = response.getHits().getHits();
scroll:
while (true) {
for (SearchHit hit : hits) {
Map<String, Object> result = hit.getSource();
cities.add(mapper.convertValue(result, City.class));
}
response = esClient.getClient().prepareSearchScroll(response.getScrollId()).setScroll(new TimeValue(60000)).execute().actionGet();
if (response.getHits().getHits().length == 0) {
break scroll;
}
}
return cities;
}
The "LocationFinder\src\main\resources\json\cities.json" file contains all cities from Belgium. You can delete or create entries if you want too. As long as you don't change the names and/or structure, no code changes are required.
Make sure to read the README https://github.com/GlennVanSchil/LocationFinder
Take a look at this web service advertised on xmethods.net. It requires a subscription to actually use, but claims to do what you need.
The advertised method in question's description:
GetPlacesWithin Returns a list of geo places within a specified distance from a given place. Parameters: place - place name (65 char max), state - 2 letter state code (not required for zip codes), distance - distance in miles, placeTypeToFind - type of place to look for: ZipCode or City (including any villages, towns, etc).
http://xmethods.net/ve2/ViewListing.po?key=uuid:5428B3DD-C7C6-E1A8-87D6-461729AF02C0
Oracle, PostGIS, mysql with GIS extensions, sqlite with GIS extensions all support this kind of queries.
If you don't have the dataset look at:
http://www.geonames.org/