Wednesday, December 06, 2006

Fun with MapServer

I just started a project trying to implement a mapping solution on the web using MapServer. I like it a lot. Not only is it very powerful in itself but the ability to add in data from WMS and WFS servers from all across the world make it just awesome.

I originally started with the CGI implementation. It seemed like the quickest wayt to get going in a hurry. The learning curve is based around learnng which instructions to pass into it in a GET request The other option is using Mapscript. Being in a .NET shop, I didn't want to dabble with php or perl as I thought it was limited to. As it turns out there is a c# version that was produced through a neat little utility called SWIG, a description of which is beyond the scope of this article.

The Mapscript API is a little intimidating at first. A lot of the examples are in PHP for more of the obscure functions. But a tutorial and headstart provided by Paolo Corti, proved most helpful. I pretty much just adapted his tutorial to suit my needs. I only had to hack around those stupid checkbox errors that keep popping up without reason.

His technique is to give each user their own mapObj, which represents a map in MS and to store it in Session. One page controls the map and possibly modifies it (setting zoom values, turning on layers, setting queries) and another page writes to the Reponse.outputStream(???). So instead of having to define html templates and link to them in the map file like you would with the CGI based apps, you make requests of the mapObj's drawing functions. You can make it draw your legends, which it will read from the defined layers in the map file. You can make it draw a queried area.

At the heart of mapServer is the map file. It tells mapserver what data makes what layers and how to output them, and configures little extras, such as legend, scale(which it can embed within the map).

The mapObj layer takes the path to the map file in its constructor. Once you have created a mapObj this way you can do all kinds of fun stuff:

using(imageObj image = map.draw()){
byte[] img = image.getBytes();
using (MemoryStream ms = new MemoryStream(img))
{
System.Drawing.Image mapimage = System.Drawing.Image.FromStream(ms);
Bitmap bitmap = (Bitmap)mapimage;
bitmap.Save(Response.OutputStream, System.Drawing.Imaging.ImageFormat.Jpeg);
}
}
NOTE: The draw method can be replaced with drawQuery() to draw the result of a query, or drawLegend(), to get an image of the embeded layers described in color. One thing I thought was neat was I could have two layers defined for say the same shp file, but I could have one check a particular attribute and color them accordingly. So I could have one layer of just fields, and one where the fields are a different color based on the crops planted on them.

In order to set up a query you need to set up the query first:
layerObj qLayer = map.getLayerByName("fields");
qLayer.queryByAttributes(map, "Crop", "Corn", mapscript.MS_MULTIPLE);
NOTE: This will query the map's layer called "fields" and search for an attribute called "Crop" for the value "Corn" and select all of them instead of the closest or first. When the drawQuery method is called it will draw the results as you have defined the class in the QUERYMAP entry in the map file. Be careful about the order of the layers if two reference the same data. If you query "fields" and "fields2" is after it (like the previously described colored by crop layer), the class for "fields2" overrides the querymap highlighting.

I have played around with mapserver before but this is my first time really learning stuff for later use, as opposed to just trying out. I thought it was need to be able to add lables to the map, with just a few lines in the map file. The following entry adds a little notice at the bottom left hand side of a 600X600 image. Notice you can use pixes there. Another example that I came across put a point on a lat long instead, but that was a point type feature instead of an annotation type.
LAYER
NAME Copyright
STATUS DEFAULT
TYPE annotation
TRANSFORM false
FEATURE
POINTS 100 590 END
TEXT "MyCompany 2006"
END
CLASS
STYLE
COLOR 0 0 0
END
LABEL
TYPE bitmap
END
END
END



WMS Layers
The ability to simply configure and use MS as a WMS clintis maybe the most exiting thing for me about MapServer. We can provide our clients with really relevant information from a variety of sources from all across the world. Matt Perry has a wonderful list and demonstration (as well as the map file that produces them) on his blog PerryGeo.

I'm vaguely aware of what Projections are but here is a little more about them:
We can set our map file PROJECTION object using either “raw” Proj.4
parameters or specifying an EPSG reference number. This “reference system”
was created by the European Petroleum Survey Group (EPSG, hence the name)
and contains geodetic parameters for several projections. It’s become a standard
reference system, used in WMS applications. Unfortunately, most of the
projections defined in the EPSG file are for smaller areas (larger scale maps) than
[larger areas].

Sometimes I would add WMS layers and they seemed to not have any effect. This was either from selecting a feature layer or the scale wasn't at the point where the features are visible.

One Error I got while trying different wms layers was this: "EPPL7 support is not available". This is somewhat misleading. This is just the last driver tried on the returning result. It could be failing for any number of reasons.

Continuing.....


Some Useful Mapserver Links
UM Site

MapServer Tutorial for C# mapscript (ASP .NET)

Glossary from MapMart (at the bottom of the FAQ)

WIP

Labels:

0 Comments:

Post a Comment

<< Home