Sunday, September 20, 2009

PostGIS

Here is an excellent guide to working with PostGIS. Some of my additional notes:

Load Shapefile to PostGIS

a) DB Connect:
psql -d gisdb -h localhost -U matt

b) Generate sql file from shapefile:

C:\Program files\PostgreSQL\8.2\bin>shp2pgsql.exe data\states > states.sql

c) Use pgAdmin to ru sql (tools -> query tool. In query tool open->go to the states.sql

Paul Ramsey wrote PostGIS. I recently shared some emails with him. Thought part of the discussion worth reprinting:

Q. What is the difference between PostGIS and ArcSDE?

A. At a very high level (or perhaps this is a very low level), PostGIS /
PostgreSQL is a database, and ArcSDE is not. ArcSDE is a "spatial
middleware", it runs as a separate process and talks to the real
database below it. PostGIS is a "dynamically loadable runtime" inside
the PostgreSQL process -- it runs inside the same address space as
PostgreSQL, from the point of view of the computer, it's the all the
same program.

PostGIS should be viewed in exactly the same way relative to
PostgreSQL as Oracle Spatial should vis-a-vis Oracle, SQL Server
Spatial vis-a-vis SQL Server, Informix Spatial Extender vis-a-vis
Informix, etc, etc, etc. It works exactly the same way as all those
other in-process spatial type extensions to relational databases. So,
call it an "extension", a "spatial type", a "data blade", etc.
Unfortunately, years of marketing by various vendors have muddied the
terminological water surrounding type extension mechanisms.

The most important functional differences with SDE have nothing to do
with spatial database functionality and everything to do with ESRI
product placement and marketing. You'll find that ESRI products talk
more directly to ArcSDE than they do to PostGIS (or Oracle Spatial or
SQL Server Spatial, for that matter) because ESRI is interested in
selling their whole stack (desktop + server + web apps) to their
clients, not just the ArcGIS component. It's a non-trivial benefit for a customer that (a) already has a lot of ESRI software and (b) can afford the maintenance overhead in dollars, time and expertise that ArcSDE extracts.

GeoDjango

Wikipedia defines Django as follows:

"Django's primary goal is to ease the creation of complex, database-driven websites. Django emphasizes reusability and "pluggability" of components, rapid development, and the principle of DRY (Don't Repeat Yourself). Python is used throughout, even for settings, files, and data models."

The two key links for GeoDjango:

GeoDjango Online Docs


Django Docs

WMS and Bing/Yahoo Basemap Overlays

Here is an interesting issue I found today with WMS overlay. When WMS layers are created in either Mapserver or Geoserver then added as overlays to Yahoo or Bing their alignment is wrong.

Let me step back. As mentioned in earlier posts. One can create a WMS layer in geoserver and through the excellent config interface add this as a layer to Google earth.



All align perfectly. Now adding the same WMS to Modest Maps and overlaying it on Yahoo shows the WMS misaligned:



Turning to Openlayers, I find the same problem:



In each of the latter cases the WMS layer also looks stretched. I'll find the fix and post it.

Saturday, September 19, 2009

Map Technology Overview

I've been on a technology review of late. Mostly driven by client requests. I never cease to be amazed by what is now available. So far my thoughts in brief:

Mapserver is a pain to configure. Manually writing mapfiles, takes me back to the days of ArcIMS and axl files. Geoserver is far easier in every respect. It has a terrific admin interface. Setting up basic map services, WMS, WFS is easy. Exporting in formats read by google maps etc is also a piece of cake. If it were not for the need of a full application server, the choice of geospatial server would be easy. Geoserver also allows for easy generation of Georss, KML and viewing of map layers in openlayers.

Caching and tiling is another area which favours Geoserver. Geowebcache is integrated into geoserver. No need for additional work. The config screen allows for easy seeding. Mapserver works with tilecache. From the work I have done so far you tile mapserver by calling tilecache and passing the mapserver url.

I'm still working with openlayers but am so far very impressed. One thing I already notice is how much is there. I really like the Modest Maps Flex library. But with a smaller community, it does not have the same depth of code. I'm still playing here, so more feedback later.

I'd like to know one of the big fours - mapquest, MSN, Yahoo and Google - API's. I lean towards mapquest, largely due to the feedback I have read and my impressions from conferences. I recently signed up for their developer account. A couple of people were soon emailing me with contact info. On one side I thought this great, since support might be more forthcoming. On the other side, money reared its ugly head. Use of this service beyond local testing has a price tag! Reminds me why I so favour open source.

Other areas on my radar at the moment beyond testing the mapquest API include:
- Geodjango testing
- PostGIS and shapefile write up
- Javascript to Flex/Flash communication

I'll write more on this in due course. I asked Paul Ramsey (OpenGeo and PostGIS author) his thoughts on Geoserver versus Mapserver. Here is his repy:

If you are deep into OGC standards, Geoserver has a big advantage in
completeness of implementations of things like SLD and WFS. (Less on
WMS).

I did a talk last year which, though tongue-in-cheek addresses the
more important differences. Which are philosophical more than anything
else. Scriptable web rendering engine vs complete spatial web
environment.

http://s3.cleverelephant.ca/geoweb-mapserver.pdf

Most of the speed differences are gone at this point, they perform
very comparably for common use cases.

Openlayers

The openlayers community seems to be becoming ever larger. Though I'm predominantly a Flex developer, its time I checked out Openlayers. On my recent WMS kick, I know combining WMS with other basemaps is well supported. Looking at the online docs I found this terrific examples page.
As a newbie I took out a few code examples:
1) Basic map

<html>
<head>
<title>OpenLayers Example</title>
<script
src="http://openlayers.org/api/OpenLayers.js"></script>
</head>
<body>
<div style="width:100%; height:100%" id="map"></div>
<script defer="defer" type="text/javascript">
var map = new OpenLayers.Map('map');
var wms = new OpenLayers.Layer.WMS( "OpenLayers WMS",
"http://labs.metacarta.com/wms/vmap0", {layers: 'basic'} );
map.addLayer(wms);
map.zoomToMaxExtent();
</script>
</body>
</html>

2) WMS map

<html>
<head>
<title>OpenLayers Example</title>
<script
src="http://openlayers.org/api/OpenLayers.js"></script>
</head>
<body>
<div style="width:100%; height:100%" id="map"></div>
<script defer="defer" type="text/javascript">
var map = new OpenLayers.Map('map');
var wms = new OpenLayers.Layer.WMS( "OpenLayers WMS",
"http://labs.metacarta.com/wms/vmap0", {layers: 'basic'} );
map.addLayer(wms);
map.zoomToMaxExtent();
</script>
</body>
</html>

3) Locally running WMS

<html xmlns="http://www.w3.org/1999/xhtml">
<script
src="http://openlayers.org/api/OpenLayers.js"></script>
</head>
<body>
<div style="width:100%; height:100%" id="map"></div>
<script defer="defer" type="text/javascript">
var map = new OpenLayers.Map('map');
var wms = new OpenLayers.Layer.WMS( "OpenLayers WMS",
"http://localhost:8080/geoserver/wms", {layers: 'topp:states_ugl'} );
map.addLayer(wms);
map.zoomToMaxExtent();
</script>
</html>

4) Local WMS with Bing (note you will need to copy the OpenLayers.js file from
http://openlayers.org/dev/OpenLayers.js)

<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>OpenLayers Bing Example</title>
<link rel="stylesheet" href="../theme/default/style.css" type="text/css" />
<link rel="stylesheet" href="style.css" type="text/css" />
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<script src="http://ecn.dev.virtualearth.net/mapcontrol/mapcontrol.ashx?v=6.2&mkt=en-us"></script>

<script src="OpenLayers.js"></script>

<script>

var map;

function init(){
map = new OpenLayers.Map("map");
map.addControl(new OpenLayers.Control.LayerSwitcher());

var shaded = new OpenLayers.Layer.VirtualEarth("Shaded", {
type: VEMapStyle.Shaded
});
var hybrid = new OpenLayers.Layer.VirtualEarth("Hybrid", {
type: VEMapStyle.Hybrid
});
var aerial = new OpenLayers.Layer.VirtualEarth("Aerial", {
type: VEMapStyle.Aerial
});

var wms = new OpenLayers.Layer.WMS( "OpenLayers WMS",
"http://localhost:8080/geoserver/wms", {layers: 'topp:states_ugl'},
{
'opacity': 0.4, visibility: true,
'isBaseLayer': false,'wrapDateLine': true
}
);

map.addLayers([wms,shaded, hybrid, aerial]);

map.setCenter(new OpenLayers.LonLat(-110, 45), 3);
}

</script>
</head>
<body onload="init()">
<h1 id="title">Bing Example</h1>

<div id="tags"></div>

<p id="shortdesc">
Demonstrates the use of Bing layers.
</p>

<div id="map" class="smallmap"></div>
<div id="docs">This example demonstrates the ability to create layers using tiles from Bing maps.</div>
</body>
</html>

4) Openlayers controls

For this example you'll need three files openlayers.js, style.css and theme/style.css. You'll need to create a theme directory for the latter. Note in theme/style.css the icons will need adding to a img directory. I have not done this here, so map icon will not appear.

<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>OpenLayers Map Controls Example</title>

<link rel="stylesheet" href="theme/style.css" type="text/css" />
<link rel="stylesheet" href="style.css" type="text/css" />
<script src="OpenLayers.js"></script>
<script type="text/javascript">
var map;
function init(){
map = new OpenLayers.Map('map', {
controls: [
new OpenLayers.Control.Navigation(),
new OpenLayers.Control.PanZoomBar(),
new OpenLayers.Control.LayerSwitcher({'ascending':false}),
new OpenLayers.Control.Permalink(),
new OpenLayers.Control.ScaleLine(),
new OpenLayers.Control.Permalink('permalink'),
new OpenLayers.Control.MousePosition(),
new OpenLayers.Control.OverviewMap(),
new OpenLayers.Control.KeyboardDefaults()
],
numZoomLevels: 6

});


var ol_wms = new OpenLayers.Layer.WMS( "OpenLayers WMS",
"http://labs.metacarta.com/wms/vmap0",
{layers: 'basic'} );
var jpl_wms = new OpenLayers.Layer.WMS( "NASA Global Mosaic",
"http://t1.hypercube.telascience.org/cgi-bin/landsat7",
{layers: "landsat7"});
var dm_wms = new OpenLayers.Layer.WMS( "DM Solutions Demo",
"http://www2.dmsolutions.ca/cgi-bin/mswms_gmap",
{layers: "bathymetry,land_fn,park,drain_fn,drainage," +
"prov_bound,fedlimit,rail,road,popplace",
transparent: "true", format: "image/png" });

jpl_wms.setVisibility(false);
dm_wms.setVisibility(false);

map.addLayers([ol_wms, jpl_wms, dm_wms]);
if (!map.getCenter()) map.zoomToMaxExtent();
}
</script>

</head>
<body onload="init()">
<h1 id="title">Map Controls Example</h1>

<div id="tags">
</div>

<p id="shortdesc">
Attach zooming, panning, layer switcher, overview map, and permalink map controls to an OpenLayers window.
</p>

<a style="float:right" href="" id="permalink">Permalink</a>
<div id="map" class="smallmap"></div>

<div id="docs"></div>
</body>
</html>

5) Georss

For this example you'll need to download this georss.xml feed (just copy source in your browser)

<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>OpenLayers GeoRSS Example</title>
<link rel="stylesheet" href="theme/style.css" type="text/css" />
<link rel="stylesheet" href="style.css" type="text/css" />
<script src="OpenLayers.js"></script>
<script type="text/javascript">
var map, layer;

OpenLayers.ProxyHost = "/proxy/?url=";
function init(){
map = new OpenLayers.Map('map', {maxResolution:'auto'});
layer = new OpenLayers.Layer.WMS( "OpenLayers WMS",
"http://labs.metacarta.com/wms/vmap0", {layers: 'basic'} );
map.addLayer(layer);
map.setCenter(new OpenLayers.LonLat(0, 0), 0);
map.addControl(new OpenLayers.Control.LayerSwitcher());
}
function addUrl() {
var urlObj = OpenLayers.Util.getElement('url');
var value = urlObj.value;
var parts = value.split("/");
var newl = new OpenLayers.Layer.GeoRSS( parts[parts.length-1], value);
map.addLayer(newl);
urlObj.value = "";
}
</script>
</head>

<body onload="init()">
<h1 id="title">GeoRSS Example</h1>

<div id="tags"></div>

<p id="shortdesc">
Display a couple of locally cached georss feeds on an a basemap.
</p>

<div id="map" class="smallmap"></div>

<div id="docs">
<p>This demo uses the OpenLayers GeoRSS parser, which supports GeoRSS Simple and W3C GeoRSS. Only points are
currently supported. The OpenLayers GeoRSS parser will automatically connect an information bubble to the map
markers, similar to Google maps. In addition, the parser can use custom PNG icons for markers. A sample GeoRSS
file (georss.xml) is included.

<form onsubmit="return false;">
GeoRSS URL: <input type="text" id="url" size="50" value="georss.xml" />
<input type="submit" onclick="addUrl(); return false;" value="Load Feed" onsubmit="addUrl(); return false;" />
</form>

<p>The above input box allows the input of a URL to a GeoRSS feed. This feed can be local to the HTML page --
for example, entering 'georss.xml' will work by default, because there is a local file in the directory called
georss.xml -- or, with a properly set up ProxyHost variable (as is used here), it will be able to load any
HTTP URL which contains GeoRSS and display it. Anything else will simply have no effect.</p>

</div>
</body>
</html>

There are so many examples online. I walked through some, here is a list of just some of the functionality:

Openlayers

Overview map
Random pan
Layers on off tab
Arcgis restful call
Arcims combine
Bing layers
Add box to map
Buffer how many tiles are included outside the view area
Map click events
Draggable rectangle
Fractional zoom (rectangle zoom)
Adding points, lines and polygons
Toolbar - points, lines and polygons
Digitising
Eventing
GeoRSS – Flickr, marker

Wednesday, September 16, 2009

TileCache and Google Maps

Found the following excellent entry from Christopher Schmidt blog. I'll give it a whirl and post my results.

MapServer and TileCache

Spent some time today looking at using TileCache with MapServer. I used in part these docs. Other useful docs are here from Metacarta. I walked through the following (note I am using my work with Mapserver described in an earlier post):

1) Installed Python

2) Downloaded TileCache

3) Unzipped the TileCache directory, ran the setup executable and copied the contents under the directory into C:\ms4w\Apache\cgi-bin

4) Opened C:\ms4w\Apache\cgi-bin\tilecache.cgi and changed the top line to:

#!C:/Python25/python.exe -u

5) I added the following to the C:\ms4w\Apache\cgi-bin\tilecache.cfg file

[mapserver]
type=WMS
url=http://localhost:81/cgi-bin/mapserv.exe?map=/ms4w/Apache/htdocs/wms_mapserver/data/ms_wms.map
extension=png
layers=states_ugl
SRS=EPSG:4326
bbox=-97.6169,39.9179,-81.745,51.0875

6) Running the following:

http://localhost:81/cgi-bin/tilecache.cgi?layers=mapserver&service=WMS&version=1.1.1&request=GetMap&srs=EPSG:4326&bbox=-97.6169,39.9179,-81.745,51.0875&format=image/png&width=400&height=300

gives the map image served by MapServer.

MapQuest Flex API Samples

Now leaning towards the Mapquest Flex api. I spied the following demo applications. This demonstrates with source code, some of the core functionality.

On a side note. The AIR application Tour de Flex is well worth installing if you build Flex apps. From a mapping perspective they demo a number of the main mapping API's.

Tuesday, September 15, 2009

Flex Developer List

Sometimes useful people to ask for solutions for those hard to solve problems. Here is one persons experts list.

Mapping API's

I'll admit to being somewhat locked into the Modest Maps Flex API. As recent blog entries suggest, I've started looking at combining WMS and WFS data - served from MapeServer or Geoserver - with basemaps. I've had a number of people approach me about this combination, plus I've wanted the excuse the exlpore further.

Another area which I have started investigating are other Flex/Flash mapping API's. The main four are ESRI ArcMap, Google maps, Yahoo and Mapquest. I came across the following article written by Kevin Hoyt of Adobe. He compared the Google, Yahoo and Mapquest last year. Finding Mapquest the richest and best supported. He did a presentation which included Modest maps and ESRI's API. Its worth a read.

For me, after chatting with Mapquest at Where 2.0 this year, and based on what I have read, I'll turn my attention here first.

Sunday, September 13, 2009

Modest Maps, WMS and Overview

Looking at the docs on wms and multiple providers the following proved a useful link:

http://getsatisfaction.com/modestmaps/topics/how_to_layer_two_maps_with_different_providers_for_blending_alpha_transparency_etc

I'll post my code in due course.

On a related note, here is a URL for an overview map with Modest maps

http://blog.modestmaps.com/2008/11/hello-world/

GeoServer and WMS

Geoserver is a truly fabulous open source geospatial server. Much easier to set and configure than Mapserver. The documentation provided is extremely comprehensive. See:

http://docs.geoserver.org/1.7.6/user/getting-started/web-admin-quickstart/index.html

Here are the notes I made as I walked through setting things up.

a) Setting up geoserver

I am using the portable gis control panel (see earlier blog entry). Once installed it sits directly under c:/.When you open it you have the option (under web modules) to start Geoserver.
Access Geoserver via:

http://localhost:8080/geoserver

admin/password are the default credentials. If you need to change them look at:

C:\Program Files\GeoServer 1.7.6\data_dir\security\user.properties

b) Adding shapefile

Under the data directory for geoserver add some new data in the data directory:

C:\Program Files\GeoServer 1.7.6\data_dir\data\

In the web interface click on data -> datastores -> new. Add name and type. Next screen add path to data and data name eg. nyc_roads.shp. Now click submit. The next screen should be the featuretype editor. Now from drop down select the type eg. line add the srs, then click generate. Now click submit and finally apply. Note these two steps in this order are critical in the process.

In the web interface under data->datastores you should now see your new data

You can view the data in welcome->demo->map preview

c) WMS

In config screen choose wms. Next choose contents and add the layer you just created in this screen. You can get the SRS info from the featuretype editor under data

One of the amazingly cool things about geoserver is the demos page in the web interface. From here you can view the results of various requests. Choose sample requests to see these options; wms, wfs etc. Also from here you can select map preview. From here you can see your newly loaded data. Another terrific thing about geoserver is the integration of openlayers. Data can be viewed directly in the geoserver interface with openlayers

d) Geowebcache

Another terrific part of geoserver is the integration of geowebcache. There is a nice guide to this here:
http://geoserver.org/display/GEOSDOC/GeoServer+GeoWebCache+Configuration

Key directory is C:\Program Files\GeoServer 1.7.6\data_dir\gwc. Go to:

http://localhost:8080/geoserver/gwc/demo


Here you can see all of your layers and ‘seed this layer’. Seeding is generating tiles. When you select seed this layer you will see under the gwc directory your newly generated tiles.
If you go to the demo page and view your data. In openlayers you have the option to view the data as a single image or tiled. The latter will show your newly generated tiles.

If you wish to see the data in google earth. Open Google earth, choose add->network link. Add a name and the url below to the pop up.

http://localhost:8080/geoserver/gwc/service/kml/topp:nyc_roads.png.kml

By selecting the named link in google earth (under my places) you should see your data.

Friday, September 11, 2009

WMS and MapServer

I'm in the process of setting up Mapserver to serve up maps via WMS. It has been a while. The steps I went through are as follows:

1) Download MS4W . This is a package which bundles Mapserver with PHP and Apache. Saves time on configuration. I set the Apache port to 81, since I already have another version running on 80. The default location of all installed files is c:/ms4w.

2) Installed Quantum GIS. Again you can use another bundled package which includes geoserver and many other open source tools. Alternatively you can get the software direct.

3) Quantum GIS contains a nifty plug in for generating .map or mapfiles for Mapserver (the alternative is to write them by hand which can be a major pain). This can be done via the plugin menu option. Once installed, this is the plug in window:



Two things to remember. First, create an empty .map file in your favourite text editor. In the plug in interface, you need to point to an existing .map file. The Quantum plug in will overwrite this file. Second, I found it easier to put the .map file and shapefiles (at least for this initial trial) in the same directory.

You should now have a working mapfile. Now for WMS. You will need to edit the generated mapfile to add additional parameters. This and the required url parameters are a pain. After much searching I found these two links very useful:

http://www.mapserver.org/ogc/wms_server.html#table-of-contents
http://ms.gis.umn.edu:8081/ms_plone/docs/howto/mapcontext

I'll not walk too much through the additions, but they mostly involve adding elements under the METADATA tag. Here is my working mapfile:

# Map file created from QGIS project file C:/matts/generatefile/test.qgs
# Edit this file to customize for your map interface
# (Created with PyQgis MapServer Export plugin)
MAP
NAME test
# Map image size
SIZE 400 300
#UNITS meters

EXTENT -97.616877 39.917875 -81.745000 51.087523
PROJECTION
'proj=longlat'
'ellps=WGS84'
'datum=WGS84'
'no_defs'
''
END

# Background color for the map canvas -- change as desired
# IMAGECOLOR 192 192 192
#IMAGEQUALITY 95
IMAGETYPE png
OUTPUTFORMAT
NAME png
DRIVER "GD/PNG"
MIMETYPE "image/png"
IMAGEMODE RGB
EXTENSION "png"
FORMATOPTION "INTERLACE=OFF"
END
# Legend
LEGEND
IMAGECOLOR 255 255 255
STATUS ON
KEYSIZE 18 12
LABEL
TYPE BITMAP
SIZE MEDIUM
COLOR 0 0 89
END
END

# Web interface definition. Only the template parameter
# is required to display a map. See MapServer documentation
WEB
# Set IMAGEPATH to the path where MapServer should
# write its output.
IMAGEPATH '/tmp/'

# Set IMAGEURL to the url that points to IMAGEPATH
# as defined in your web server configuration
IMAGEURL 'http://localhost:81/wms_mapserver/tmp'

# WMS server settings
METADATA
'wms_title' 'test'
'wms_onlineresource' 'http://localhost:81/cgi-bin/mapserv.exe?map=C:/ms4w/Apache/htdocs/wms_mapserver/data/ms_wms.map&'
'wms_srs' 'EPSG:4326'
"wms_extent" "201621.496941 -294488.285333 1425518.020722 498254.511514"
#"wfs_title" "test WFS Demo Server" ## REQUIRED
END

#Scale range at which web interface will operate
# Template and header/footer settings
# Only the template parameter is required to display a map. See MapServer documentation
END

LAYER
NAME 'states_ugl'
TYPE POLYGON
DATA 'C:/ms4w/Apache/htdocs/wms_mapserver/data/states_ugl.shp'
METADATA
"wms_name" "states"
"wms_server_version" "1.1.1"
"wms_format" "image/png"
"wms_srs" "EPSG:4326"
"wms_title" "States" ##required
"wms_extent" "201621.496941 -294488.285333 1425518.020722 498254.511514"
"wms_onlineresource" "http://localhost:81/cgi-bin/mapserv.exe?map=C:/ms4w/Apache/htdocs/wms_mapserver/data/ms_wms.map?"
#"wfs_version" "1.1.0"
# "wfs_srs" "EPSG:4326"
# "wfs_typename" "statefs"
# "wfs_request_method" "GET"
# "wfs_service" "WFS"
#"wfs_title" "statefs" ## REQUIRED
#"gml_featureid" "ID" ## REQUIRED
#"gml_include_items" "all" ## Optional (serves all attributes for layer)
END
#CONNECTIONTYPE WMS
STATUS ON
TRANSPARENCY 100
PROJECTION
'proj=longlat'
'ellps=WGS84'
'datum=WGS84'
'no_defs'
''
END
CLASS
NAME 'states_ugl'
STYLE
SYMBOL 0
SIZE 2
OUTLINECOLOR 0 0 0
COLOR 144 50 207
END
END
END

END


As you can see this sits in the following directory with my shapefile:

C:/ms4w/Apache/htdocs/wms_mapserver/data

I did my testing using Internet Explorer. As mentioned, the required url parameters are a pain. Here are the two key calls; getCapabilities:

http://localhost:81/cgi-bin/mapserv.exe?map=/ms4w/Apache/htdocs/wms_mapserver/data/ms_wms.map&SERVICE=WMS&VERSION=1.1.1&REQUEST=GetCapabilities

and getMap. Note all parameters except styles are required:

http://localhost:81/cgi-bin/mapserv.exe?map=/ms4w/Apache/htdocs/wms_mapserver/data/ms_wms.map&service=WMS&version=1.1.1&request=GetMap&layers=states_ugl&srs=EPSG:4326&bbox=-97.6169,39.9179,-81.745,51.0875&format=image/png&width=400&height=300&styles=default

I struggled for a while on the getMap call. One problem I realised was the BBox parameters you need to get from getCapabilities (I grabbed it directly from the mapfile). I also initially added connectiontype "wms" for the layer in the mapfile which broke everything - actually i could not generate an image. As soon as that was removed bingo.

Grab this source, unrar and place in your C:/ms4w/Apache/htdocs. You should now be able to run the above.