Transforming Map Data for Display

Now that we’ve got some map data it would be great to actually display it.  But that still isn’t an easy job.  The problem is that we’ve got two wildly different coordinate systems.  For the map data, we’ve got degrees latitude and degrees longitude and for our display surface we’ve got window coordinates with the origin at the top left with positive Y going down and positive X going right.  If we were simply to draw the map data directly into the window we wouldn’t even see the map. The longitude coordinates are all negative and the entire map would be off the screen.  Next, the Y coordinates go in entirely the wrong direction and the map would be upside down.  Finally, the map may not even fit in the window.  It may be to small to see the details, or it may not fit. 

In order to display the data we need massage the data some.  We need to shift and flip the map and we need to zoom in or out enough to be able to see it. It turns out that these are all what are known as linear transformations.  The math here is called linear algebra.  And each of these transformations can be accomplished by matrix multiplication.  Each transformation is represented by a matrix and you can multiply the vector by the transformation matrix and you get back the resulting vector.

Believe it or not, this is such a common operation in 2D drawing that there is already full support for this in C#.  You don’t really have to understand anything about matrices, how to build them, or how do to the multiplication.  You can build up your transformation matrix by using the  System.Media.Matrix class.  You can create a translation and scaling matrix simply by using the Translate and Scale methods. And if the data you need to transform is already and array of points, then you can apply the transformation by using the Transform method.  Imagine something like this:

// Do our transformations
Matrix scale = new Matrix();
scale.ScaleAt(4, -4, (minPoint.X + maxPoint.X) / 2, (minPoint.Y + maxPoint.Y) / 2);

minPoint = scale.Transform(minPoint);
maxPoint = scale.Transform(maxPoint);

Matrix translate = new Matrix();
translate.Translate(-minPoint.X, -maxPoint.Y);

minPoint = translate.Transform(minPoint);
maxPoint = translate.Transform(maxPoint);

for (Int32 index = 0; index < count; index++)
{
record = (PolygonRecord)shapeFileFactory.Shapes[index];
// We're going to display a projection, so we need to get the projected
// bounding box. We'll do that by projecting the extreme points and
// using the result as the new bounding box.

// Now build an array of points that have been projected with the Mercator projection
System.Windows.Point[] points = new System.Windows.Point[record.NumPoints];
for (Int32 index2 = 0; index2 < record.NumPoints; index2++)
{
points[index2] = MapProjection.Sinusodal(0, record.Points[index2].X, record.Points[index2].Y);
}

    // Do our transformations
scale.Transform(points);
translate.Transform(points);

}