Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Random geographic coordinates (on land, avoid ocean)

Any clever ideas on how to generate random coordinates (latitude / longitude) of places on Earth? Latitude / Longitude. Precision to 5 points and avoid bodies of water.

    double minLat = -90.00;     double maxLat = 90.00;           double latitude = minLat + (double)(Math.random() * ((maxLat - minLat) + 1));     double minLon = 0.00;     double maxLon = 180.00;          double longitude = minLon + (double)(Math.random() * ((maxLon - minLon) + 1));     DecimalFormat df = new DecimalFormat("#.#####");             log.info("latitude:longitude --> " + df.format(latitude) + "," + df.format(longitude)); 

Maybe i'm living in a dream world and the water topic is unavoidable ... but hopefully there's a nicer, cleaner and more efficient way to do this?

EDIT

Some fantastic answers/ideas -- however, at scale, let's say I need to generate 25,000 coordinates. Going to an external service provider may not be the best option due to latency, cost and a few other factors.

like image 280
sdolgy Avatar asked Feb 01 '12 23:02

sdolgy


2 Answers

To deal with the body of water problem is going to be largely a data issue, e.g. do you just want to miss the oceans or do you need to also miss small streams. Either you need to use a service with the quality of data that you need, or, you need to obtain the data yourself and run it locally. From your edit, it sounds like you want to go the local data route, so I'll focus on a way to do that.

One method is to obtain a shapefile for either land areas or water areas. You can then generate a random point and determine if it intersects a land area (or alternatively, does not intersect a water area).

To get started, you might get some low resolution data here and then get higher resolution data here for when you want to get better answers on coast lines or with lakes/rivers/etc. You mentioned that you want precision in your points to 5 decimal places, which is a little over 1m. Do be aware that if you get data to match that precision, you will have one giant data set. And, if you want really good data, be prepared to pay for it.

Once you have your shape data, you need some tools to help you determine the intersection of your random points. Geotools is a great place to start and probably will work for your needs. You will also end up looking at opengis code (docs under geotools site - not sure if they consumed them or what) and JTS for the geometry handling. Using this you can quickly open the shapefile and start doing some intersection queries.

    File f = new File ( "world.shp" );     ShapefileDataStore dataStore = new ShapefileDataStore ( f.toURI ().toURL () );     FeatureSource<SimpleFeatureType, SimpleFeature> featureSource =          dataStore.getFeatureSource ();     String geomAttrName = featureSource.getSchema ()         .getGeometryDescriptor ().getLocalName ();      ResourceInfo resourceInfo = featureSource.getInfo ();     CoordinateReferenceSystem crs = resourceInfo.getCRS ();     Hints hints = GeoTools.getDefaultHints ();     hints.put ( Hints.JTS_SRID, 4326 );     hints.put ( Hints.CRS, crs );      FilterFactory2 ff = CommonFactoryFinder.getFilterFactory2 ( hints );     GeometryFactory gf = JTSFactoryFinder.getGeometryFactory ( hints );      Coordinate land = new Coordinate ( -122.0087, 47.54650 );     Point pointLand = gf.createPoint ( land );     Coordinate water = new Coordinate ( 0, 0 );     Point pointWater = gf.createPoint ( water );      Intersects filter = ff.intersects ( ff.property ( geomAttrName ),          ff.literal ( pointLand ) );     FeatureCollection<SimpleFeatureType, SimpleFeature> features = featureSource             .getFeatures ( filter );      filter = ff.intersects ( ff.property ( geomAttrName ),          ff.literal ( pointWater ) );     features = featureSource.getFeatures ( filter ); 

Quick explanations:

  1. This assumes the shapefile you got is polygon data. Intersection on lines or points isn't going to give you what you want.
  2. First section opens the shapefile - nothing interesting
  3. you have to fetch the geometry property name for the given file
  4. coordinate system stuff - you specified lat/long in your post but GIS can be quite a bit more complicated. In general, the data I pointed you at is geographic, wgs84, and, that is what I setup here. However, if this is not the case for you then you need to be sure you are dealing with your data in the correct coordinate system. If that all sounds like gibberish, google around for a tutorial on GIS/coordinate systems/datum/ellipsoid.
  5. generating the coordinate geometries and the filters are pretty self-explanatory. The resulting set of features will either be empty, meaning the coordinate is in the water if your data is land cover, or not empty, meaning the opposite.

Note: if you do this with a really random set of points, you are going to hit water pretty often and it could take you a while to get to 25k points. You may want to try to scope your point generation better than truly random (like remove big chunks of the Atlantic/Pacific/Indian oceans).

Also, you may find that your intersection queries are too slow. If so, you may want to look into creating a quadtree index (qix) with a tool like GDAL. I don't recall which index types are supported by geotools, though.

like image 182
philwb Avatar answered Sep 22 '22 12:09

philwb


This has being asked a long time ago and I now have the similar need. There are two possibilities I am looking into:

1. Define the surface ranges for the random generator.

Here it's important to identify the level of precision you are going for. The easiest way would be to have a very relaxed and approximate approach. In this case you can divide the world map into "boxes":

enter image description here

Each box has it's own range of lat lon. Then you first randomise to get a random box, then you randomise to get a random lat and random long within the boundaries of that box.

Precisions is of course not the best at all here... Though it depends:) If you do your homework well and define a lot of boxes covering most complex surface shapes - you might be quite ok with the precision.

2. List item

Some API to return continent name from coordinates OR address OR country OR district = something that WATER doesn't have. Google Maps API's can help here. I didn't research this one deeper, but I think it's possible, though you will have to run the check on each generated pair of coordinates and rerun IF it's wrong. So you can get a bit stuck if random generator keeps throwing you in the ocean.

Also - some water does belong to countries, districts...so yeah, not very precise.

For my needs - I am going with "boxes" because I also want to control exact areas from which the random coordinates are taken and don't mind if it lands on a lake or river, just not open ocean:)

like image 44
GeekSince1982 Avatar answered Sep 22 '22 12:09

GeekSince1982