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.