Justkez

Trying to be a consistent blog 
Filed under

gis

 

Projecting geographic coordinates in Processing

Processing is a an open source programming environment for, among other things, data visualisation.

I have a personal penchance for GIS visualisation (mapping, geographic projection, making something meaningful from seemingly random data), and there seems to be a shortage of information around working with Processing and the GIS space.

Processing's map() and coordinate systems?

Ben Fry - the author of "Visualizing Data" and co-conspirator for Processing has a chapter in his book about the map() method, which re-maps a number into a specified range. In his example he plots ZIP centroids in a Processing sketch.

A good example, but partly a convenience demonstration of the method, instead of a considered approach to projecting coordinates. This approach is also limited in that it is geographically bound by the coordinates available, and doesn't easily allow for a frame of reference (i.e. a map underneath the points).

Technically what we want to do is "plot a geographic coordinate system in a Cartesian space". More simply, draw lat/lon pairs on the screen. To give us a frame of reference, we will also draw over a map image, for which we know the geographic boundaries (thanks to the World File that comes with the image).

The image

We are using the image below to project some points on; you can click the link to take you through to the full-size image. The image has been exported from a GIS package, so we also have the World File defining the geographic extent.

UK_White_small

At the top of a new Processing sketch, you would insert information around the extent and dimensions of the image:

    public float NORTH = 63.0969111702827;
public float EAST = 6.2998078851688;
public float SOUTH = 46.7910568308996;
public float WEST = -13.1689892839019;

public int WIDTH = 991;
public int HEIGHT = 830;
  

You can calculate this information using my World File extent calculator, which takes image dimensions and a World File to determine the geographic bounds of the image.

You can then use image() to draw the image onto the sketch.

The code

There are two methods, and two (small) classes to add to the sketch.

The classes

The two classes hold lat/lon coordinates and x/y Cartesian coordinates:

    class latLon{
  float lat, lon;
  latLon(float latIn, float lonIn) {
    lat = latIn;
    lon = lonIn;
  }

  String toString()  {
    return lat + "," + lon;
  }
}

class Point {
  float x, y;
  Point(float x_in, float y_in) { x = x_in; y = y_in; }
}
  

Obviously you can substitute the classes/code to fit whatever you have already (such as GeoTools).

The two methods

    Point latlon_to_screen(latLon coordinates) {
 int i_lon = interpolate(0, WIDTH, WEST, EAST, coordinates.lon);
 int i_lat = interpolate(0, HEIGHT, NORTH, SOUTH, coordinates.lat);

 return new Point(i_lon, i_lat);
}

int interpolate(float lo_to, float hi_to, float lo_from, float hi_from, float current) {
  return round( lo_to + (current-lo_from) * (hi_to-lo_to)/(hi_from-lo_from));
}
  

The first method, latlon_to_screen, is just a wrapper around the second method.

This second method, which actually does the translation between geographic coordinates and screen coordinates is taken from Data Visualization with Ruby and RMagick - Where Are Those Bikes ?, which does the job nicely.

Once these classes and methods are included, adding a geographic point to the sketch is pretty straight forward. This is a very bare-bones draw() method for the sketch:

    void draw() {
  image(imgBg, 0, 0);
  Point london = latlon_to_screen(new latLon(51.5, -0.085));
  fill(100);
  ellipse(london.x, london.y, 10, 10);
}
  

This gives a sketch similar to:

london_on_map

What about converting mouse coordinates to geographic coordinates?

This is also fairly straightforward, and we can make use of Processing's map() method, which was mentioned earlier. Because we now know our geographic boundary/extent, and the X/Y position we want to "translate", we can use map() to fit the sketch coordinates into the range of the geographic coordinates.

To convert the coordinates:

    latLon screen_to_latlon(int x, int y) {  
  float lon_range = abs(WEST) + abs(EAST);
  float lat_range = (NORTH) - (SOUTH);

  float current_lon = map(x, 0, WIDTH, WEST, EAST);
  float current_lat = map(y, 0, HEIGHT, NORTH, SOUTH);

  return new latLon(current_lat, current_lon);
}
  

And then to make use of Processing's mouseMoved() method, we can print the coordinates to the sketch (in this case, the top left corner):

    void mouseMoved() {
  latLon ll = screen_to_latlon(mouseX, mouseY);
  fill(50);
  rectMode(CORNER);
  rect(0, 0, 170, 20);
  fill(255);
  text(ll.toString(), 5, 15); 
}
  

Remember to use textFont() to load a suitable font for your sketch. Also remember that there is toString() method for the previously created latLon class.

This gives a little black box in the top left corner:

coordinates_on_map

Limitations

There are is no consideration for the spherical nature of Earth. This doesn't present much of a problem on a small scale, but if you were doing a sketch of the whole world, you would need to factor that in.

You would need to play with ellipseMode() in Processing to make sure the drawing of your points is accurate (alternatively use point() with a larger strokeWidth()).

Download

You can download the standalone sketch here: Processing_Tutorial_UK - it includes all the images you need, and should work straight out of the box.

Any problems or comments, just drop me a note below.

Filed under  //   geographic   gis   mapping   processing   visualisation   visualization  

Comments [0]

World File Extent Calculator

Having posted about world file (worldfile) calculations in the past (see here), I thought it might be nice to share a little spreadsheet to make this process easier.

Simply put, this is an Excel file allowing you to paste in the contents of your worldfile and image dimensions, and it returns the North, East, South and West coordinates.

World.File.Extent.Calculator

The file is hosted on Google Docs at the moment:

Enjoy!

Filed under  //   gis   mapping   projection   visualization  

Comments [0]

Creating a Shapefile from C# .NET - what are the options?

Having spent not only the good part of today, but many hours of many other days, I thought it prudent to share some findings on where the world stands when it comes to creating and writing to a new Shapefile from a C# .NET environment.

As you probably know, a Shapefile is a file format synonymous with ESRI's ArcGIS/Map/Info suite of products; it has been around for ages. The file format is open, in that it is well documented if you want to construct the file programatically (as in, "let's create a binary file from scratch") - sod that.

So what are the options? Well, there are many options, and I spent some time exploring them in depth...

Create the file manually, according to the file spec

This is appealing if you have all the time in the world, are willing to learn all the nitty gritty of a file spec and understand all the niggles and caveats associated with doing this by hand. You can have a look at the file spec and make your own mind up. The idea of doing this would probably sit well with seriously experienced C/C++ old schoolers - not really what you want to be doing in something as high level as C# .NET 3.5.

SharpMap - A Geospatial Application Framework for the CLR

I really admire the idea of the project - bringing everything GIS together in one nice (albeit large) package for .NET developers. However, the reality for me was somewhat different. Considering myself at an average to intermediate programmer, I was full of frustration and anguish as I a) tried to navigate the site and find relevant documentation and b) match any forum posts/hints to a meaningful version of the distribution. The 0.9 release officially has no support for writing Shapefiles, whilst the 2.0 version does. It seems that SVN trunk is NOT current, so after getting the v2.0 branch, I fiddled around for a bit but still nothing - the (relatively) recent forum posts on the matter were referencing interfaces that didn't even show up.

So, this one was a no go. Perhaps when the project unites a bit more, something will come of it.

NetTopologySuite - port of the popular Java JTS GIS Suite

This one was a bit more promising - good sources and some unit tests to get some ideas from. Unfortunately it was again an issue with finding the right version of the right files, then interfacing them with seemingly non-existent classes. It was getting late in the day when I tried this, but it all just seemed so big and bulky for writing one simple polygon Shapefile. This suite implements some of GeoTools.NET, which it supposedly uses for "capabilities of read/write data from and to file formats such as Shapefile format" - this may be the case, but there are some many levels of abstraction away from what you actually want to do, that you get embroiled in a confusing web of inheritance, abstraction and implementation.

I'm sure it's possible, but it happens to be very hard to make possible.

GeoTools.net - set of .Net classes useful when handing geographic information

It is never very inspiring to see "recent activity" from 2005, but the Shapefile format is pretty tried and tested, so I gave it a spin.

By this point I was getting remarkably frustrated. I remember that this package didn't work, just not sure what the reason was.

Convert simple polygon shapes to KML using ogr2ogr

Seriously, I was starting to implement this thinking it was the easiest way around. Installed ogr2ogr and FWTools before I realised this was a ridiculous route to take.

.NET Wrapper for shapelib

shapelib is a C library for reading and writing Shapefiles - someone has done a .NET wrapper for it. I got pretty far on with this, but kept cocking up the sync between DBF and SHP; started to come a bit of a headache so I carried on looking.

Free tools included with shapelib

There are some multi-platform tools available freely from the shapelib author(s) - specifically in shapelib128_bin_win.zip over on the download page. Basically you get command line applications which allow you to create and write to Shapefiles and the associated DBF data files.

At last, a solution that understood my simple problem of "draw a polygon from a list of lat/longs". The final implementation is tiny static class in C# to create new Shapefiles and write polygons to them. I wasn't that keen on relying one external utilities to accomplish this, but after my ordeal I would happily ship a CD full of utilities with the software if it meant it worked quickly and easily. Also worth a look is this little user guide on AntholoGIS which gives a few more examples.

In conclusion

I may be a failed hardcore developer, but I have all my Shapefile creation needs satisfied in less than 100 lines of code. This is a trade off I can live with.

Thank you to everyone who was ever involved in the shapelib project - it is truly a perfect, elegant solution to what seems like it is a common problem (in the GIS programming world, anyway).

Filed under  //   c-sharp   development   gis   programming   shapefiles  

Comments [0]

Calculating lat/longs for projecting world files

This post details how to calculate the latitude and longitude for the south east corner of a world file. This means you can calculate all you need to overlay a correctly scaled image in systems such as Google Earth.

World files

A world file is a simple text file that accompanies a raster image enabling you to plot the image in it's correct geographic extent. It was introduced by GIS mammoth ESRI.

The snippet below represents the world file we will work on:

    0.004437536880778
0.000000000000000
0.000000000000000
-0.004437792567264
-103.206013320465620
40.059054557563236
  

It is a bit incomprehensible at first, but if we add a bit of descriptive text to it for demonstration purposes, it becomes a little clearer:

    0.004437536880778      <- Each X pixel represents this much longitude
0.000000000000000
0.000000000000000
-0.004437792567264     <- Each Y pixel represents this much latitude (negative)
-103.206013320465620   <- Longitude of the upper left pixel (West point)
40.059054557563236     <- Latitude of the upper left pixel (North point)
  

The information here allows you to easily understand the geographic position of the image (i.e. that area of the Earth that it represents), but it does not contain sufficient information to accurately plot the image in Google Earth, for example.

A world file image

A world file is accompanied by an image file - be it a BMP, GIF, JPG, PNG, TIFF - it doesn't really matter to the world file. In order to calculate the east and south coordinates we need to know the width and height of the image in computer terms - how many pixels wide and high it is.

For this example we will use an image that is 6526 x 5208.

Calculating the eastern point

Running on the above example of plotting a world file and it's image in Google Earth, we need to calculate the most easterly and southerly points. Along with the image file itself, we have enough information to make this simple calculation:

    east = west coordinate + (image width * line 1 of world file)
  

Remember that line 1 of the world file contains a number describing how much longitude 1 horizontal pixel of the image represents. So this would translate to:

    east = -103.206013320465620 + (6526 * 0.004437536880778)
east = -74.246647636508392
  

Calculating the southern point

Now all we need is the southerly point - as you might infer from the above point, it's pretty straightforward:

    south = north coordinate + (image height * line 4 of world file)
  

Again, line 4 contains the amount of latitude each pixel in the image's height represents - the geographic distance.

    south = 40.059054557563236 - 5280 * (-0.004437792567264)
south = 16.947031
  

And now we have enough information to plot the world file and it's image onto Google Earth, or any mapping system of choice.

I'm sure there are countless tools that do this as part of GIS packages, but it is nice to know how to go about it step by step. If you're going to be working with mapping without using other packages, this is also an essential process if you wish to convert latitude and longitude coordinates to the screen, as it gives them a bounding box in which to scale themselves.

Feel free to post any comments or insights below, and any links to interesting GIS programming related posts or pages - a domain fairly new to me.

Filed under  //   gis   programming   tutorial  

Comments [0]