The Merriest of OSGeo Chapters

Here’s a thanks to the sparkling members of Cascadia Users of Geospatial Open Source (CUGOS), possibly the merriest of OSGeo chapters. This last year was an exciting one with the CUGOS 2011 Spring Fling, FOSS4G and UW GIS Day events. We also had some spectacular presentations at the monthly meetings.

Let the learning and hacking continue! Chatter at #cugos@irc.freenode.net or the google group.

For you geonerds, here’s some mappy-face art (FYI…these images do not reflect the thoughts and opinions of CUGOS. I am to blame).

 

 


 

Posted in Map Art Stuff | Comments Off

Working with Tile Caches and Tile Proxies using Mapserver, GDAL_WMS, TileCache and MapProxy (part 1 of 3)

Introduction

This is the first in a series of posts about tile caches and map proxies. The last month has been a smorgasboard of tiles and virtual private servers (VPS).

Mkgeomatics and I divided up some work to answer lingering questions we both had related to tiles, caches and other topics. I won’t try to explain what he investigated — check out his blog over here. But it’s safe to say mkgeomatics was hungry to understand Polymaps, TileStache, Dynamic and Cached SVG Vector Tiles, rendering OSM data with Mapnik, Apache benchmarking with JMeter and a cool Javascript library he introduced to me — Protovis. Wow, that’s a lot of stuff dude. Maybe someday I’ll understand it all too.

My job was to investigate building RESTful interfaces for my PostGIS data using GeoDjango, Mapserver renderings and seeding tile caches with a Python tool of the same name — TileCache.  I also really wanted to wrap my head around how a WMS server could be used to fuse together data from PostGIS and a GDAL_WMS. The tricky part here is that I wanted my GDAL_WMS pointing to an existing TMS cache — a different tiling scheme than the WMS standard. This last item led me to inadvertently explore MapProxy solutions. I might have to get into TileX depending on how well MapProxy resolves some conflicts with the GDAL_WMS workflow. Phew.

If none of that last paragraph made sense, don’t worry. This is just the intro. I’ll explain most of it below or in the coming parts.

The data I was using to explore these topics included OpenStreetMap and a dataset put together from the Bureau of Land Management that shows the National Park and US Forest Service boundaries for Oregon and Washington. Here’s a semi pretty picture of that data as viewed through QGIS.

Notice that the data above is being pulled (and styled) from two separate sources. One is OpenStreetMap TMS flavored tile cache and the other is my local box’s Mapserver WMS cache of parks data. See how the OSM data in the background looks grainy and bad. We’ll get back to that later.

MapServer and WMS

Naturally, I started with the easiest work — setting up a WMS server and client with MapServer. I resolved some build and install problems and began by creating a simple client map file that hooks into a server map file. The server map file is pointing at my PostGIS data. I’m using WGS84.

Here’s the server map file.

MAP
	###TESTING MAPSERVER OUTPUT###
	# http://www.osgeohacks.com/cgi-bin/mapserv?map=serverWMS.map&layer=states&mode=map
	###TESTING MAPSERVER WMS###
	# http://www.osgeohacks.com/cgi-bin/mapserv?map=serverWMS.map&SERVICE=WMS&VERSION=1.1.1&REQUEST=GetCapabilities
 
	NAME "WMS_Service_for_National_Parks_and_National_Forests_of_Oregon_and_Washington"
	CONFIG "MS_ERRORFILE" "/srv/www/osgeohacks.com/logs/ms_error.txt"
	STATUS ON
	SIZE 400 300
	EXTENT -180.0000 -90.0000 180.0000 83.6236
	IMAGECOLOR 255 255 255
	IMAGETYPE PNG24
	PROJECTION
   		"init=epsg:4326"
	END 
 
	WEB
		IMAGEPATH "/srv/www/osgeohacks.com/public_html/tmp/"
		IMAGEURL "/mapserv_temp/"
 
		METADATA
			"wms_title"           "Washington_Oregeon_NP_and_NF_WMS_Server"
			"wms_onlineresource"  "http://www.osgeohacks.com/cgi-bin/mapserv?map=serverWMS.map&"
			"wms_srs"             "EPSG:4326"
			"wms_extent"	      "-180 -90 180 83.6236"
		END
	END
 
	LAYER
		NAME   "nps_usfs"
		#DATA         "blm/WA_OR_NPS_USFS/BLM_WA_OR_NPS_USFS_4326.shp"
		CONNECTIONTYPE POSTGIS
		CONNECTION "host=localhost dbname=obm user=gisuser password=gisuser port=5432"
		DATA "geom from world_np_nf_or_wa using unique id using srid=4326"
		STATUS       DEFAULT
		TYPE         POLYGON
		METADATA
			"wms_title"           "NP_NF_LAYER"
			"wms_srs"             "EPSG:4326"
			"wms_extent"	      "-124.733 41.6249 -116.464 49.0009"
		END
		PROJECTION
   			"init=epsg:4326"
		END
 
		CLASSITEM "property_s"
		CLASS
			NAME       'national_parks'
			EXPRESSION 'NPS'
			STYLE
				COLOR 102 204 0
				OPACITY 5
				OUTLINECOLOR 77 102 51
			END
		END
		CLASS
			NAME       'national_forests'
			EXPRESSION 'USFS'
			STYLE
				COLOR 175 228 149
				OPACITY 5
				OUTLINECOLOR 77 102 51
			END
		END
		CLASS
			NAME       'no_value'
			EXPRESSION ''
			STYLE
				COLOR 255 255 204
				OPACITY 5
				OUTLINECOLOR 77 102 51
			END
		END
 
	END
 
	LAYER
		NAME   "states"
		#DATA         "states/US_shapefiles.shp"
		CONNECTIONTYPE POSTGIS
		CONNECTION "host=localhost dbname=obm user=gisuser password=gisuser port=5432"
		DATA "geom from world_states using unique id using srid=4326"
		STATUS       DEFAULT
		TYPE         POLYGON
		CLASS
			NAME       'states'
			STYLE
				OUTLINECOLOR   61 61 61
			END
		END
		PROJECTION
   			"init=epsg:4326"
		END
		METADATA
			"wms_title"           "STATES_LAYER"
			"wms_srs"             "EPSG:4326"
			"wms_extent"	      "-124.733 25.1188 -66.9499 49.3844"
		END
	END
 
	LAYER
		NAME   "world borders"
		#DATA         "world_borders/TM_WORLD_BORDERS-0.3.shp"
		CONNECTIONTYPE POSTGIS
		CONNECTION "host=localhost dbname=obm user=gisuser password=gisuser port=5432"
		DATA "geom from world_worldborders using unique id using srid=4326"
		STATUS       DEFAULT
		TYPE         POLYGON
		CLASS
			NAME       'world borders'
			STYLE
 
				OUTLINECOLOR   205 201 165
			END
		END
		PROJECTION
   			"init=epsg:4326"
		END
		METADATA
			"wms_title"           "WORLD_BORDER_LAYER"
			"wms_srs"             "EPSG:4326"
			"wms_extent"	      "-180 -90 180 83.6236"
		END
	END
 
END

Here’s the client map file.

MAP
	###TESTING MAPSERVER OUTPUT###
	# http://localhost/cgi-bin/mapserv?map=/var/www/mapserverWMS/public_html/clientWMS.map&layers=distro&mode=map
 
	NAME "WMS Client"
	CONFIG "MS_ERRORFILE" "/var/www/mapserverWMS/public_html/ms_clientwms_error.txt"
	STATUS ON
	SIZE 400 300
	EXTENT -124.733 41.6249 -116.464 49.0009
	SHAPEPATH "DATA/SHAPES"
	IMAGECOLOR 255 255 255
	IMAGETYPE PNG24
	PROJECTION
   		"init=epsg:4326"
	END 
 
	WEB
		IMAGEPATH "/var/www/mapserverWMS/public_html/tmp/mapserv_temp/"
		IMAGEURL "/mapserv_temp/"
	END
 
	LAYER
		NAME "distro"
		TYPE RASTER
		STATUS ON
		CONNECTION "http://localhost/cgi-bin/mapserv?map=serverWMS.map"
		CONNECTIONTYPE WMS
		METADATA
			"wms_srs"             "EPSG:4326"
			"wms_name"            "nps_usfs" #this corresponds to the LAYER--> NAME not the wms_title
			"wms_server_version"  "1.1.1"
			"wms_format"          "image/png"
		END
	END
 
END

I’m not going to dissect the Mapserver map file structure. If you want answers to those questions then look at official docs over here. The major thing to notice right now about the map file  is that all the rendering is being done in the server map file (the first one) that hooks into my PostGIS data. The second thing to note about the server map file is that each layer has a ‘STATUS’ of ‘DEFAULT’ which means that when I request one layer I’m going to get all those layers marked ‘DEFAULT’ returned as well.

Also notice the commented out #TESTING# portions at the top of each map file. This helps us test if our respective client and server map files are working.

###TESTING MAPSERVER OUTPUT###
#http://www.osgeohacks.com/cgi-bin/mapserv?map=serverWMS.map&layer=states&mode=map
###TESTING MAPSERVER WMS###
#http://www.osgeohacks.com/cgi-bin/mapserv?map=serverWMS.map&SERVICE=WMS&VERSION=1.1.1&REQUEST=GetCapabilities

In the server map file there are two URL(s) I can pass the server to make sure it’s working. The first is a simple request for a single layer (remember all layers in that file are marked default). We’ll get back a pretty picture if everything is working alright. NOTE: I DISABLED THE HTML TEMPLATES THAT ALLOW A CLIENT TO DO THE ‘BROWSE’ REQUEST. YOU MIGHT GET AN ERROR THAT LOOKS LIKE THIS: ‘mapserv(): Web application error. Traditional BROWSE mode requires a TEMPLATE in the WEB section, but none was provided.’

#Put this into the address bar
http://www.osgeohacks.com/cgi-bin/mapserv?map=serverWMS.map&layer=states&mode=map

The second test returns an XML file about this WMS server’s GetCapabilites — essentially the metadata about what this server map file can do. If it’s working then we should get back an XML dump like so.

#Put this in the address bar
http://www.osgeohacks.com/cgi-bin/mapserv?map=serverWMS.map&SERVICE=WMS&VERSION=1.1.1&REQUEST=GetCapabilities

The client map file URL request is essentially the same as the first server map file URL request. We’re going to request a layer from our server map file and the server map file is going to turn around and request a layer (remember they’re all marked default) from our PostGIS database. Therefore the picture we should get back is exactly the same as the returned from the first server URL request above.

#Put this into your browser
http://localhost/cgi-bin/mapserv?map=/var/www/mapserverWMS/public_html/clientWMS.map&layers=distro&mode=map

GDAL_WMS as a Mapserver Layer

Remember that ugly, grainy picture at the beginning of this post (also provided below for one more gander)?

I promise I wasn’t trying to do that on purpose. The idea is that I wanted to create a WMS server that dynamically grabbed OpenStreetMap data and rendered it beneath my other WMS layers. Why? No particular reason. Just because I wanted to try it and see how it worked. As we can see, it didn’t work too well.

Before we judge the solution based on the outcome we might want to see if I made any booboos that might have contributed to this horrible looking output.

Below is my server map file referencing two layers — one layer of National Forests and Parks data from PostGIS and one OpenStreetMap layer provided by GDAL_WMS.

MAP
	###TESTING MAPSERVER OUTPUT###
	# http://localhost/cgi-bin/mapserv?map=serverWMS_900913.map&layer=osm_tms&mode=map
	###TESTING MAPSERVER WMS###
	# http://localhost/cgi-bin/mapserv?map=/var/www/mapserverWMS/public_html/test.map&SERVICE=WMS&VERSION=1.1.1&REQUEST=GetCapabilities
 
	NAME "TEST_WMS_SERVICE"
	CONFIG "MS_ERRORFILE" "/var/www/mapserverWMS/public_html/ms_wms_server_error.txt"
	STATUS ON
	SIZE 400 300
	EXTENT -14545354.979047 5216980.053583 -12197209.470547 6261415.607884
	SHAPEPATH "DATA/SHAPES"
	IMAGECOLOR 255 255 255
	IMAGETYPE PNG24
	PROJECTION
   		"init=epsg:4326"
	END
 
	WEB
		TEMPLATE "/var/www/mapserverWMS/public_html/msbody.html"
      		HEADER "/var/www/mapserverWMS/public_html/msheader.html"
     		FOOTER "/var/www/mapserverWMS/public_html/msfooter.html"
		IMAGEPATH "/var/www/mapserverWMS/public_html/tmp/mapserv_temp/"
		IMAGEURL "/mapserv_temp/"
 
		METADATA
			"wms_title"           "WMS_Server"
			"wms_onlineresource"  "http://localhost/cgi-bin/mapserv?map=osmtmsWMS.map&"
			"wms_srs"             "EPSG:4326"
			"wms_extent" 	      "-124.733,41.6249,-116.464,49.0009"
		END
	END
 
	LAYER
		NAME   "nps_usfs"
		#DATA         "blm/WA_OR_NPS_USFS/BLM_WA_OR_NPS_USFS_4326.shp"
		CONNECTIONTYPE POSTGIS
		CONNECTION "host=localhost dbname=obm user=gisuser password=gisuser port=5432"
		DATA "geom from world_np_nf_or_wa using unique id using srid=4326"
		STATUS       OFF
		TYPE         POLYGON
		METADATA
			"wms_title"           "NP_NF_LAYER"
			"wms_srs"             "EPSG:4326"
			"wms_extent" 	      "-124.733,41.6249,-116.464,49.0009"
		END
		PROJECTION
   			"init=epsg:4326"
		END
 
		CLASSITEM "property_s"
		CLASS
			NAME       'national_parks'
			EXPRESSION 'NPS'
			STYLE
				COLOR 0 245 0
				OPACITY 5
				OUTLINECOLOR 77 102 51
			END
		END
		CLASS
			NAME       'national_forests'
			EXPRESSION 'USFS'
			STYLE
				COLOR 230 255 204
				OPACITY 5
				OUTLINECOLOR 77 102 51
			END
		END
		CLASS
			NAME       'national_parks'
			EXPRESSION ''
			STYLE
				COLOR 255 255 204
				OPACITY 5
				OUTLINECOLOR 77 102 51
			END
		END
 
	END
 
	LAYER
		DATA "osm_tms.xml"
		NAME "osm_tms"
		PROJECTION
      			"proj=merc" "a=6378137" "b=6378137" "lat_ts=0.0" "lon_0=0.0" "x_0=0.0" "y_0=0" "k=1.0" "units=m" "nadgrids=@null" "no_defs"
		END
		METADATA
		"wms_title"           "osm_tms_title"
		"wms_srs"             "EPSG:900913"
		"wms_extent"		      "-14545354.979047,5216980.053583,-12197209.470547,6261415.607884"
		END
		STATUS ON
		TYPE RASTER
		UNITS METERS
	END
 
END

Here’s what’s important about the above map file. The WMS server is advertising it’s capabilities to all clients in the WGS84 projection. This, according to the Mapserver documentation, is what the WMS server output projection is going to be. Look at the ‘WEB’ and first ‘PROJECTION’ tags.

PROJECTION
   		"init=epsg:4326"
END
 
	WEB
		TEMPLATE "/var/www/mapserverWMS/public_html/msbody.html"
      		HEADER "/var/www/mapserverWMS/public_html/msheader.html"
     		FOOTER "/var/www/mapserverWMS/public_html/msfooter.html"
		IMAGEPATH "/var/www/mapserverWMS/public_html/tmp/mapserv_temp/"
		IMAGEURL "/mapserv_temp/"
 
		METADATA
			"wms_title"           "WMS_Server"
			"wms_onlineresource"  "http://localhost/cgi-bin/mapserv?map=osmtmsWMS.map&"
			"wms_srs"             "EPSG:4326"
			"wms_extent" 	      "-124.733,41.6249,-116.464,49.0009"
		END
	END

Each layer also has it’s own ‘METADATA’ and ‘PROJECTION’ tag which references what projection that input layer’s data is coming in as. The national parks and forests are in WGS84 and the GDAL_WMS layer is coming in as spherical mercator (900913).

# National Parks and Forests Layer Metadata
METADATA
	"wms_title"           "NP_NF_LAYER"
	"wms_srs"             "EPSG:4326"
	"wms_extent" 	      "-124.733,41.6249,-116.464,49.0009"
END
PROJECTION
   	"init=epsg:4326"
END
 
##### BREAK #####
 
# OSM Layer Metadata
PROJECTION
      	"proj=merc" "a=6378137" "b=6378137" "lat_ts=0.0" "lon_0=0.0" "x_0=0.0" "y_0=0" "k=1.0" "units=m" "nadgrids=@null" "no_defs"
END
METADATA
	"wms_title"           "osm_tms_title"
	"wms_srs"             "EPSG:900913"
	"wms_extent"		      "-14545354.979047,5216980.053583,-12197209.470547,6261415.607884"
END

The GDAL_WMS layer is actually an XML configuration file (see below). It’s pointing to a TMS service (so already rendered tiles). Naturally, you’d think the graininess in the output picture is due to the on-the-fly reprojection of the OpenStreetMap tiles from spherical mercator to WGS84 right?

<GDAL_WMS>
<Service name="TMS">
<ServerUrl>http://tile.openstreetmap.org/${z}/${x}/${y}.png</ServerUrl>
</Service>
<DataWindow>
<UpperLeftX>-20037508.34</UpperLeftX>
<UpperLeftY>20037508.34</UpperLeftY>
<LowerRightX>20037508.34</LowerRightX>
<LowerRightY>-20037508.34</LowerRightY>
<TileLevel>19</TileLevel>
<TileCountX>1</TileCountX>
<TileCountY>1</TileCountY>
<YOrigin>top</YOrigin>
</DataWindow>
<Projection>EPSG:900913</Projection>
<BlockSizeX>256</BlockSizeX>
<BlockSizeY>256</BlockSizeY>
<BandsCount>3</BandsCount>
<Cache/>
</GDAL_WMS>

I tried to resolve problem then by changing output projections — really an easy fix. So now the national parks and forests data is going to be reprojected from WGS84 to spherical mercator and the TMS tiles will stay in the correct projection thus fixing their graininess — or so we think.

Here’s that new server map file:

MAP
	###TESTING MAPSERVER OUTPUT###
	# http://localhost/cgi-bin/mapserv?map=serverWMS_900913.map&amp;layer=osm_tms&amp;mode=map
	###TESTING MAPSERVER WMS###
	# http://localhost/cgi-bin/mapserv?map=/var/www/mapserverWMS/public_html/test.map&amp;SERVICE=WMS&amp;VERSION=1.1.1&amp;REQUEST=GetCapabilities
 
	NAME "TEST_WMS_SERVICE"
	CONFIG "MS_ERRORFILE" "/var/www/mapserverWMS/public_html/ms_wms_server_error.txt"
	STATUS ON
	SIZE 400 300
	EXTENT -14545354.979047 5216980.053583 -12197209.470547 6261415.607884
	SHAPEPATH "DATA/SHAPES"
	IMAGECOLOR 255 255 255
	IMAGETYPE PNG24
	#PROJECTION
   		#"init=epsg:4326"
	#END
	PROJECTION
      		"proj=merc" "a=6378137" "b=6378137" "lat_ts=0.0" "lon_0=0.0" "x_0=0.0" "y_0=0" "k=1.0" "units=m" "nadgrids=@null" "no_defs"
	END
 
	WEB
		TEMPLATE "/var/www/mapserverWMS/public_html/msbody.html"
      		HEADER "/var/www/mapserverWMS/public_html/msheader.html"
     		FOOTER "/var/www/mapserverWMS/public_html/msfooter.html"
		IMAGEPATH "/var/www/mapserverWMS/public_html/tmp/mapserv_temp/"
		IMAGEURL "/mapserv_temp/"
 
		METADATA
			"wms_title"           "WMS_Server"
			"wms_onlineresource"  "http://localhost/cgi-bin/mapserv?map=serverWMS_900913.map&amp;"
			#"wms_srs"             "EPSG:4326"
			 "wms_srs"             "EPSG:900913"
			#"wms_extent" 	      "-124.733,41.6249,-116.464,49.0009"
			"wms_extent"		      "-14545354.979047,5216980.053583,-12197209.470547,6261415.607884"
		END
	END
 
LAYER
		NAME   "nps_usfs"
		#DATA         "blm/WA_OR_NPS_USFS/BLM_WA_OR_NPS_USFS_4326.shp"
		CONNECTIONTYPE POSTGIS
		CONNECTION "host=localhost dbname=obm user=gisuser password=gisuser port=5432"
		DATA "geom from world_np_nf_or_wa using unique id using srid=4326"
		STATUS       DEFAULT
		TYPE         POLYGON
		METADATA
			"wms_title"           "NP_NF_LAYER"
			"wms_srs"             "EPSG:4326"
			"wms_extent" 	      "-124.733,41.6249,-116.464,49.0009"
		END
		PROJECTION
   			"init=epsg:4326"
		END
 
		CLASSITEM "property_s"
		CLASS
			NAME       'national_parks'
			EXPRESSION 'NPS'
			STYLE
				COLOR 0 245 0
				OPACITY 5
				OUTLINECOLOR 77 102 51
			END
		END
		CLASS
			NAME       'national_forests'
			EXPRESSION 'USFS'
			STYLE
				COLOR 230 255 204
				OPACITY 5
				OUTLINECOLOR 77 102 51
			END
		END
		CLASS
			NAME       'national_parks'
			EXPRESSION ''
			STYLE
				COLOR 255 255 204
				OPACITY 5
				OUTLINECOLOR 77 102 51
			END
		END
 
	END
 
	LAYER
		DATA "osm_tms.xml"
		NAME "osm_tms"
		PROJECTION
      			"proj=merc" "a=6378137" "b=6378137" "lat_ts=0.0" "lon_0=0.0" "x_0=0.0" "y_0=0" "k=1.0" "units=m" "nadgrids=@null" "no_defs"
		END
		METADATA
		"wms_title"           "osm_tms_title"
		"wms_srs"             "EPSG:900913"
		"wms_extent"		      "-14545354.979047,5216980.053583,-12197209.470547,6261415.607884"
		END
 
		PROCESSING "OVERSAMPLE_RATIO=1"  # the default is 2!
		PROCESSING "LOAD_FULL_RES_IMAGE=NO"
 
		STATUS DEFAULT
		TYPE RASTER
		UNITS METERS
	END
 
END

Unfortunately that didn’t work either as evidenced by this picture.

This is where this logical thread spins off into part 2 of 3. It seems like GDAL_WMS is not so nice to work with (maybe a naive and unfairly early judgement. But factual in terms of the number of man hours dedicated to solving what seems a trivial problem) and we’ll have to find a work around in two possible software solutions — TileX or MapProxy.

So let’s move onto the funnest part of this stuff — caches and OpenLayers!

Creating WMS Caches with TileCache


There’s three tools we’ll need to work with tile caches.

1) A viewer to display our stitched together tiles. This is going to be OpenLayers.

2) A tile caching software. There’s a lot of them, but here we’ll use TileCache.

3) A TileCache input layer. There’s a few to pick from, but basically we are focusing on WMS layers (of the Mapserver flavor) and TMS layers. I think you can also use a ‘Mapnik’ layer, though I don’t know what that’s about.

Let’s start by seeding a cache of tiles for the map server file that has a states, world borders and national park/forest layers.

TileCache is a software that sits in the /cgi-bin directory right next to the mapserver executable. It can create caches on-demand (at each request bounding) or pre-seed a number of zoom levels and then quickly return the tiles that make up our request bounding box.

To get things rolling we simply edit a tilecache.cfg file and add in the layers we want it to point to. In the example below we have created two WMS layers that point to map files in our /cgi-bin — serverWMS.map and serverWMS_900913.map.

# Rendering OpenStreetMap data with Mapnik; should use metaTiling to
# avoid labels across tile boundaries
# [osm]
# type=Mapnik
# mapfile=/home/user/osm-mapnik/osm.xml
# spherical_mercator=true
# tms_type=google
# metatile=yes
 
[basic]
type=WMS
url=http://labs.metacarta.com/wms/vmap0
extension=png
 
[serverWMS]
type=WMS
url=http://www.osgeohacks.com/cgi-bin/mapserv?map=serverWMS.map
extension=png
layers=nps_usfs
 
[serverWMS_900913]
type=WMS
url=http://www.osgeohacks.com/cgi-bin/mapserv?map=serverWMS_900913.map&amp;
extension=png
layers=osm_tms

serverWMS layer and the serverWMS.map is the file that renders our PostGIS data without brining in OSM data as a backdrop. serverWMS_900913 and serverWMS_900913.map is the file that makes an additional call to OSM TMS tiles through the GDAL_WMS proxy and inserts them into the background.

Since TileCache sits inbetween the client requests and the map file, our OpenLayers javascript will reference the TileCache layer in tilecache.cfg like so:

<html xmlns="http://www.w3.org/1999/xhtml">
  <head>
    <link rel="stylesheet" href="http://openlayers.org/dev/theme/default/style.css" type="text/css" />
    <link rel="stylesheet" href="http://openlayers.org/dev/examples/style.css" type="text/css" />
    <script src="http://openlayers.org/api/OpenLayers.js"></script>
    <script type="text/javascript">
        //-120.803,45.594
	var lon = -120.803;
        var lat = 45.594;
        var zoom =7;
        var map, layer;
 
        function init(){
            map = new OpenLayers.Map( 'map' );
            layer = new OpenLayers.Layer.WMS( "NPS USFS WMS",
                    "http://www.osgeohacks.com/cgi-bin/tilecache-2.11/tilecache.cgi?", {layers: 'serverWMS'} );
            map.addLayer(layer);
 
            map.setCenter(new OpenLayers.LonLat(lon, lat), zoom);
            map.addControl( new OpenLayers.Control.LayerSwitcher() );
        }
    </script>
  </head>
  <body onload="init()">
 
    <h1 id="title">A pre-seeded tile cache of a Mapserver WMS pointing to PostGIS</h1>
    <p id="shortdesc"></p>
 
    <div id="map" class="largemap"></div>
  </body>
</html>

All we have to do to pre-seed a cache of tiles is pass the tilecache_seed.py file a bounding box, the zoom levels and a tilecache.cfg layer to target… away it goes at creating the cache. The bounding boxes I’m using below are from each of my layers in the serverWMS.map file — one for states, one for world borders and one for parks/forests.

sudo su www-data -c "./tilecache_seed.py -f --bbox=-180,-90,180,83.6236 serverWMS 1 5"
sudo su www-data -c "./tilecache_seed.py -f --bbox=-124.733,25.1188,-66.9499,49.3844 serverWMS 1 5"
sudo su www-data -c "./tilecache_seed.py -f --bbox=-124.733,41.6249,-116.464,49.0009 serverWMS 5 10"

Here’s the final live OpenLayers viewer (though not much of a viewer):

And here’s the OpenLayers viewer for the serverWMS_900913.map file with grainy OSM backdrops. Notice that if you zoom past level 3 you’ll experience pink error tiles. This is because the tiling scripts tested fine on my localhost but didn’t work properly on the server even though both servers are mirrors of each other — exactly the same (except for Mapserver versions). I’ll deal with that later ;)

Posted in OSGeo Web Software | Tagged , , , , , , | Comments Off

Compiling Mapserver from Source on Ubuntu 10.10 — Attention pg_config and gdal-config

This post is for anyone scouring the interwebs right now because of a ‘make’ error when compiling mapserver-5.6.6 (01-17-11 release) on Ubuntu 10.10. If that ‘make’ error resembles one of the following two errors, then you can try what worked for me:

/usr/bin/ld: cannot find -lodbc
/usr/bin/ld: cannot find -lodbcinst
collect2: ld returned 1 exit status
make: *** [shp2img] Error 1 
 
/usr/bin/ld: cannot find -lxslt
/usr/bin/ld: cannot find -lpam
/usr/bin/ld: cannot find -lreadline
collect2: ld returned 1 exit status
make: *** [shp2img] Error 1

These errors are related to the configuration files associated with gdal-config (from GDAL/OGR install) and pg_config (from PostgreSQL/PostGIS install). These configuration files, among other things, tell users what dependent libraries GDAL was built with and uses. To view these dependent libraries for GDAL you can run this command:

$ gdal-config --dep-libs
-L/usr/local/lib -lgeos_c -lsqlite3 -lodbc -lodbcinst -lxerces-c -lpthread -ljasper -lhdf5 -lmfhdfalt -ldfalt -lgif -ljpeg -lpng -lnetcdf -L/usr/lib -lpq -lz -lpthread -lm -lrt -ldl -lcurl -Wl,-Bsymbolic-functions

The “-L” directive is telling the linker where to first look for the libraries that that immediately follow it. Those libraries are listed after the directive “-l” (in this case -l stands can be substituted for lib. So -lpq is actually libpq). There’s always fallback locations if the needed libraries aren’t found in this first location — usually /usr/lib.

For some reason — and it’s still eluding me — the ‘./configure’ command below creates a makefile that contains gdal-config’s –dep-libs. Is this supposed to happen this way? I’m not totally sure.

./configure --with-ogr=/usr/local/bin/gdal-config --with-gdal=/usr/local/bin/gdal-config --with-wcs --with-wfs --with-wfsclient --with-wmsclient --with-curl-config=/usr/local/bin/curl-config --with-proj=/usr/local --with-tiff --with-gd=/usr/local/  --with-jpeg --with-freetype=/usr/ --with-threads --with-postgis=/usr/bin/pg_config --with-geos=/usr/local/bin/geos-config --with-httpd=/usr/sbin/apache2 &gt; twinkie_config_log.txt

If you were to run ‘make’ on this configuration then you’d run into the trouble I detailed at the beginning of this post.

Lucky for me, a friendly person on the mapserver forums pointed out that mapserver really shouldn’t care about the dependent libraries of gdal — it only cares about the location of the gdal library output from this command:

$ gdal-config --libs
-L/usr/local/lib -lgdal

Taking that advice to heart, I began editing my makefile. I went from this:

---Before Makefile---
# Optional GDAL Support (provides read access to a variety of raster formats)
# See http://www.remotesensing.org/gdal/
GDAL=  -DUSE_GDAL
GDAL_LIB=  -L/usr/local/lib -lgdal -L/usr/local/lib -lgeos_c -lsqlite3 -lodbc -lodbcinst -lxerces-c -lpthread -ljasper -lhdf5 -lmfhdfalt -ldfalt -lgif -ljpeg -lpng -lnetcdf -L/usr/lib -lpq -lz -lpthread -lm -lrt -ldl -lcurl -Wl,-Bsymbolic-functions
GDAL_INC=  -I/usr/local/include

To:

---Edited Makefile---
# Optional GDAL Support (provides read access to a variety of raster formats)
# See http://www.remotesensing.org/gdal/
GDAL=  -DUSE_GDAL
GDAL_LIB=  -L/usr/local/lib -lgdal
GDAL_INC=  -I/usr/local/include

The postgis errors about libxslt, libpam and libreadline were more of problem. Running pg_config outputs a lot of information. But it doesn’t list dependencies separately. So i took a stab in the dark and made these changes to the makefile based on what I learned about gdal-config.

[WARNING: MAYBE I HAVEN'T SEEN THE FALLOUT FROM THE FOLLOWING CHANGES TO THE POSTGIS/MAPSERVER CONFIGURATION YET. SO ONLY DO THE NEXT STEPS IF YOU ARE OPEN TO EXPERIMENTATION.]

After all, I’m not entirely sure what I’m doing.

---Before Makefile---
# Optional PostGIS Support.  See http://postgis.refractions.net/
POSTGIS=      -DUSE_POSTGIS -DPOSTGIS_HAS_SERVER_VERSION
POSTGIS_LIB=  -L/usr/lib -lpq -lpgport -lxslt -lxml2 -lpam -lssl -lcrypto -lkrb5 -lcom_err -lgssapi_krb5 -lz -lreadline -lcrypt -ldl -lm
POSTGIS_INC=  -I/usr/include/postgresql
 
---Edited Makefile---
# Optional PostGIS Support.  See http://postgis.refractions.net/
POSTGIS=      -DUSE_POSTGIS -DPOSTGIS_HAS_SERVER_VERSION
POSTGIS_LIB=  -L/usr/lib -lpq
POSTGIS_INC=  -I/usr/include/postgresql

Now that we’ve changed the make file we can run ‘make’ and go get some coffee.

Posted in Installs and Builds, Ubuntu 10.10 | Tagged , , , | Comments Off

Open Source Geoprocessing Interop and Analysis (A quick comparison > GeoScript, OGR, Shapely)

Last fall I started a blog post with a simple geoprocessing project in mind.  I got a chance to return to the subject and investigate it more in preparation for a presentation at CUGOS. Here’s the blog version.

There’s a number of core libraries that help drive some well known open-source software. Here’s a few in blue:

Some of these libraries are geometry engines that describe basic spatial predicates (unary and binary) as well as the basic spatial analysis methods such as Intersection, Union, Difference. Other libraries are used for interoperability — to read and write to multiple file formats, both raster and vector, among other functions.

The geometry engines in this example ( GEOS, JTS and .NETTopolgySuite(.NTS) ) have a common history. GEOS and .NTS are both ports of the Java Topology Suite (JTS) and all three are compliant with the OGC’s Simple Features Specification for SQL.

Within their respective language domains these libraries also work together under the hood of well-known applications and OSGeo projects we are all familiar with.

There’s always a need for customization or batch geoprocessing in workflows. But not everyone is a C++ or Java programmer. So we need a way to talk to these libraries. Luckily, developers produce bindings in scripting languages like Python, Perl and PHP so others can leverage this functionality. Here’s some of those bindings.

GeoScript is a set of JavaScript, Groovy, Scala and Python wrappers for the JavaTopologySuite (JTS) and GeoTools. Shapley wraps Geometry Engine Open Source (GEOS). GDAL/OGR can be built with Python bindings.

Chances are that the applications have their own libraries and bindings as well.

For example, QGIS has Python bindings. That means that you can write scripts that leverage QGIS functionality, just as you would with ArcMap and the geoprocessor. You can read and write to multiple file formats as well as do spatial analysis. QGIS is built on many libraries and plugins. It therefore might have more functionality to expose through its bindings than any single library wrapper like Shapely — don’t really know since I haven’t started using QGIS bindings yet.

The same is true of other open GIS desktop software such as gvSIG. It has a scripting engine at version 2.0 that can speak Jython, JavaScript and Groovy. And GeoDjango has its own bindings written for GEOS, PROJ4 and GDAL libraries.

The diagram above might be a cluttered and confusing graphic, but the take-home-point for GIS Specialists and those open-source newbies is you have a lot of freaking ways to access this functionality. Maybe it’s even a little overwhelming.

I work in an ESRI shop and that means I don’t get a lot of time to play with open-source tools. So I’m trying to carve out a happy, cozy, fuzzy space for open source at my job. Being a GIS Analyst/Specialist isn’t the most exciting job in the world and I have to find ways to make it more educational. So there’s a couple areas where I can insert open-source GIS.

I have a list. The first list is geoprocessing calls I can’t make without an expensive ArcInfo ArcMap license. Here’ some of those.

That said, there’s usually manual workarounds (in red). Or there might be third party installs you can use for a price. Or there’s spatial database functions that might resolve these needs. Or there’s the ArcObjects Desktop API and SDK to program these solutions in C#.NET and Visual Studio.

The point, there’s a lot of options and open-source geoprocessing is another. The second list (above) describes some things I really don’t like about ArcGIS geoprocessing. I think my biggest conflict is that the cursor methods aren’t pythonic enough. There’s this mx.ODBC Python package that used to be free. You could pass a database a select statement and get a list of tuples in return. I’m using Python and I’d like to use lists of lists instead of getters and setters. Just sayin’.

These lists led me to start playing with GeoScript bindings about 8 or 9 months ago.

So let’s go through some very very basic geoprocessing to understand a little bit more about the difference between the GeoScript, Shapely and OGR Python bindings. This isn’t a tutorial. Nothing is going to be more educational than sitting down with these libraries and trying different geoprocessing moves on your own.

I want to find a very cheap way to do Polyline to Polygon conversion (or in OGC standards terminology LineString to Polygon conversion). When I say cheap I’m not talking about computationally inexpensive. I’m talking cheap like Walmart. Example 1 is the cheapest way I can think of to do the conversion.

So what is Well Known Text (WKT) string replacement? The best thing to do is show a quick example.  Let’s use an OpenLayers example to illustrate the conversion. If we go the example page on the OpenLayers web site and filter for WKT we should get one example back.

We can draw shapes on the map and then view their WKT or GeoJson data structures in the sidebox. Or we can cut and paste WKT and GeoJson to see what the outcome is going to be. In the picture below I drew a quick LineString. Naturally, the WKT representation to the right shows this as a LineString with it’s vertices.

To convert this LineString to a Polygon all we have to do is replace the world ‘LineString’ with the word ‘Polygon’ and slap an extra pair of brackets around the existing brackets. Like so.

That’s all we’re going to do in this simple GeoScript script. We’re going to read in a shapefile of our test data. Then we’re going to export each geometry into WKT and do a string.replace() method call. All LineString(s) will get replaced with Polygon plus a set of opening and closing brackets. All MultiLineString(s) will get replaced with just Polygon. Then we’ll create geometries based on those new WKT representations and write them out to a shapefile. Here’s the core function of the script that shows the reading, serializing, deserializing and writing:

def p2pWKT(inshp,outshapeDIR):
	shp = Shapefile(inshp)
	polySchema = changeSchemaType(os.path.splitext(os.path.split(inshp)[1])[0],geom.Polygon,shp)
	ws = Directory(outshapeDIR)
	polyLayer = ws.create(schema=polySchema)
	for f in shp.features():
		try:
			dictFeat = dict(f.iteritems())
			geomWKT = writeWKT(f.geom)
			if geomWKT.count('MULTI') != 0:
				polyWKT = geomWKT.replace('MULTILINESTRING ', 'POLYGON ')
			else:
				polyWKT = geomWKT.replace('LINESTRING', 'POLYGON (')+ ")"
			#Replace
			dictFeat['the_geom'] = polyWKT
			newFeat = polyLayer.schema.feature(dictFeat,f.id)
			#Report da shapez
			print ": "+writeWKT(f.geom)
			print "\n:   "+ polyWKT
			print "\n: "+writeWKT(newFeat.geom)
			polyLayer.add(newFeat)
		except TypeError, err:
			print "\n",err
			continue

Let’s take a look at our test data.

The LineStrings on the top are shapes that once they become Polygons I’m guessing will be pretty compatible with the OGC Simple Features Standard. The shapes on the bottom row are sketchy by the same standard. Let’s run the script to see how GeoScript handles them.

There’s a couple points I want to make here about the output. All the shapes did exactly what I expected them to. GeoScript managed to do the substitution on the top shapes and balked at the bottom ones. So that means that If we go look at the bash shell we’ll see the underlying library screaming at us that it can’t do what we already didn’t expect it to do (if you look closely at the last line of the bash shell picture below you’ll see the geometry couldn’t be coerced into com.vividsolutions.jts.geom.Geometry).

What’s wrong with the bottom shapes? A simplified version of the OGR Simple Feature Spec validation rules for polygons might go like this 1) Polygon cannot cross itself, 2) All inner rings cannot touch or overlap, 3) Inner rings can only touch the exterior shell at one point. There’s probably more nuanced geometrical assertions too, but that’s all we’ll need to talk about here.

Now let’s move to example 2 and do the exact same workflow but using OGR bindings. Why? Well, there’s a chance that the libraries make different assumptions about reading and writing geometries. Here’s the main function to do this work:

def polyline2Polygon(inShapeDIR, outShapeDIR):
    ogr.UseExceptions()
    try:
        #GET POLYLINE SHAPFILE
        inshp = ogr.Open(inShapeDIR)
        inlyr = inshp.GetLayer()
        #CREATE POLYGON SHAPEFILE
        drv = ogr.GetDriverByName( "ESRI Shapefile" )
        outshp = drv.CreateDataSource( outShapeDIR )
        outlyr =  outshp.CreateLayer(os.path.splitext(os.path.split(outShapeDIR)[1])[0], None, ogr.wkbPolygon )
        #FOR EACH POLYLINE FEATURE CREATE A POLYGON
        for n in range( 0 , inlyr.GetFeatureCount() ):
		infeat = inlyr.GetFeature(n)
		export = infeat.geometry().ExportToWkt()
		if export.count('MULTI') != 0:
			outgeoT = export.replace("MULTILINESTRING" , "POLYGON " )
		else:
			outgeoT = export.replace("LINESTRING", "POLYGON (") + ")"
		outgeo = ogr.CreateGeometryFromWkt(outgeoT)
		#REPORT DA SHAPEZ
		print ": "+export
		print "\n: "+outgeoT
		print "\n: "+ str(outgeo)
		featOut = ogr.Feature(outlyr.GetLayerDefn())
		featOut.SetGeometry(outgeo)
		outlyr.CreateFeature(featOut)
		featOut.Destroy()
    except:
        print "polyline2Polygon() FAIL boo...."
    finally:
        drv = None
	gdal.ErrorReset()

Whoa. That’s different than what I expected. OGR was able to create output for each of the geometries, even the screwball ones. Why would this happen? Let’s talk about a few things of interest. Look at what OGR did with the bottom left-most shape and the one to the right of it . It added an extra vertex and closed a LineString that was topologically unclosed in both cases. That’s exactly what OpenLayers does too! Not what I expected, or maybe even wanted, but it’s cool.

The second thing of interest is those funky Polygon shapes on the bottom row. How do they exist?

Above I said something about assertion rules for geometry in the OGC Simple Features Spec. How could we test if these geometries are valid by OGC Simple Features Spec standards? One method would be to use a tool in QGIS. Or there’s unary predicates in OGR, Shapely and GeoScript for each geometry that ask, “Am I valid?” and return a boolean.

The QGIS tool will list what’s wrong with each geometry (not sure if the validation rules toe the OGC Simple Feature Spec) like below. QGIS also used to prohibit editing geometries that were funky. In the newest version that has changed and even funky shapes are editable.

Of course the red shape is invalid for the reasons the tool points out.

The purple shape is an interesting one. The validation tool says it’s valid. In previous versions of QGIS this shape would be invalid. So it looks like QGIS might be interpreting this as a Polygon with a single touching node between the parts. Not sure.

I’m also uncertain why QGIS thinks this blue polygon has an unnested inner ring. There’s only one shared vertex and this should be allowed according to the Simple Features Spec.

I have two guesses why OGR is able to write these weird geometries out. My first guess is that GDAL/OGR was around before the Simple Features Specification. So while they offer simple feature access, they don’t necessary follow OGC standards strictly and will read and write a spectrum geometries.

Another guess I have is that the Simple Feature Spec mentions that each implementing library can handle validation checks and exceptions in their own desired way. Some, like OGR, might topologically close Polygons that have a border gap. Others, like JTS, might decide that an unclosed Polygon is a complete violation and throw an exception. Not entirely sure.

The take home point is that different libraries might read and write geometries, especially weird ones, differently. So pay attention.

Let’s see what would happen if we read the super funky red geometry back in with OGR.

There it is. OGR reads the geometry it created but throws a warning (so not a complete exception like GeoScript and JTS). The warning says, if you can see it, that there could be numerous problems with this feature including it might be a non-Polygon geometry. Exactly OGR, exactly.

The third example we are going to show deals with the Python bindings Shapely that wrap GEOS.

Shapely is a little bit different than OGR and GeoScript. One big difference is that you can’t read and write to file formats with it. The idea, at least the idea that I’ve taken from it’s website, is that Shapely is a “swiss-army-knife” spatial analysis tool — it does some things really really fast and pythonic but it isn’t going to fix a flat tire. Or something like that.

The coolo-neato things about Shapely include the ability to serialize/deserialize to/from data formats that implement a GeoJson-like interface and to/from numpy arrays. There’s also a couple helpful methods — linemerge and polygonize — that it wraps from the GEOS library.

These methods aren’t as easy to reach in GeoScript or OGR built with GEOS support off the proverbial ‘shelf’ because you’d have to call Java libraries in the case of GeoScript and C++ libraries using Python ctypes. Shapely makes using these methods easy, even though you could develop your own wrappers to get at them in GeoScript and OGR with GEOS support.

I want to say one last thing about Shapely, though it might reflect some naivete on my part about the functionality of this tool. It seems to me that you can do about 80% of what Shapely does if you build OGR against GEOS and use those bindings. Although it might be more pythonic, optimized in certain ways and syntactically simpler, I’m still unsure who the users are and why. I think the TileStache project uses this library on the backend. I’m interested to find more examples.

Since Shapely can’t read or write geometries we have to lean on an existing interop library. Example 3 will use OGR for reads and writes.

The idea behind the third example is simple. I want to do LineString to Polygon conversion again, but differently. There’s probably tons of ways to do this. The best option might be to use JTS’s QuadEdge data type or Topology. But I want to use Shapely.

I knew JTS had a Polygonizer and PolygonBuilder class. Since GEOS is a port of JTS, then it should naturally have similar classes. One day I was looking at Shapely’s API and I came across this method shapely.ops.polygonize(). Let’s see what that does on our test data. Here’s the main functions:

def ogrWkt2Shapely(inShpDIR):
	shapelyObjects=[]
	shp = ogr.Open(inShpDIR)
	lyr = shp.GetLayer()
	for n in range(0, lyr.GetFeatureCount()):
		feat = lyr.GetFeature(n)
		sFeat = loads(feat.geometry().ExportToWkt())
		shapelyObjects.append(sFeat)
 
	return shapelyObjects
 
def writeShp2Ogr(shp, outshpPATH, ogrType=ogr.wkbPolygon):
	drv = ogr.GetDriverByName( "ESRI Shapefile")
	ds = drv.CreateDataSource(os.path.split(outshpPATH)[0])
	lyr = ds.CreateLayer(os.path.splitext(os.path.split(outshpPATH)[1])[0], None, ogrType)
	newgeom = ogr.CreateGeometryFromWkt(shp.wkt)
	feat = ogr.Feature(lyr.GetLayerDefn())
	feat.SetGeometry(newgeom)
	lyr.CreateFeature(feat)
	feat.Destroy()	
 
def p2pPolygonize(shpPATH, outshpPATH):
	shps = ogrWkt2Shapely(shpPATH)
	try:
		polyList = list(polygonize(shps[0]))
		counter = 0
		for shp in polyList:
			writeShp2Ogr(shp, pthOutput + "TEST"+str(counter)+"_"+os.path.splitext(os.path.split(outshpPATH)[1])[0]+".shp")
			counter+=1
	except Exception, err:
		print "\n",err
		return
 
def runTests():
	shapes =  ["/WORKSPACE/p2p/DATA/tests/2_MLS.shp", "/WORKSPACE/p2p/DATA/tests/3_MLS.shp"]
	shapes.sort()
	deleteOutput()
	for shp in shapes:
		print pthOutput + " --&gt; " + os.path.split(shp)[1]
		p2pPolygonize(shp , pthOutput + os.path.split(shp)[1])
		print "\n\n\n"

shapely.ops.polygonize() can take a list of LineStrings and return Polygons. But I handed polygonize() a single Polygon geometry and it returned me three shapes — two inner ring polygons and the outer shell. A better explanation of what’s it’s doing can be found in the GEOS API. Regardless of why, this is pretty cool.

So how can we use polygonize() to our benefit? Well, what would happen if I passed the method a MultiPolygon? That’s the question behind example 4.

We want a cheap split function that can split any arbitrary Polygon. We’ll talk about the limitations of what we’re about to do in a second. But imagine that we want to split this polygon representing Mercer Island, Washington with the LineString on top of it.

One way to do this is to intersect our LineStrings with our Polygon. This returns us just the portion of the lines that overlap with Mercer Island. Then we buffer these lines 0.000001 of a meter (yes, it’s possible). Then we’ll do a difference (opposite of intersect) on our buffered lines (a polygon feature now) and Mercer Island polygon. This produces a MultiPolygon feature that looks like this:

The highlighted MultiPolygon feature is actually split even though it’s hard to see. Remember, that’s one record in the attribute table. This isn’t really a good outcome since I’d probably only want to split polygons with LineStrings to divide up an area into discrete parts and work with each part separately. Haha, let’s use polygonize() and see if it will return a collection of single polygons from our MultiPolygon geometry.

import osgeo.ogr as ogr
import osgeo.gdal as gdal
import shapely
from shapely.wkt import loads
import os, string, glob, sys
from shapely.ops import linemerge
from shapely.ops import polygonize
from shapely.geometry import asShape, asLineString, asMultiLineString
from shapely.geometry import LineString, Polygon, MultiPolygon,Point
 
pthSplitLines = "/WORKSPACE/p2p/DATA/topo/split_polylines.shp"
pthMercer = "/WORKSPACE/p2p/DATA/topo/mercer_island.shp"
pthOutput = "/WORKSPACE/p2p/DATA/output/topo/"
pthTopo = "/WORKSPACE/p2p/DATA/topo/topo020.shp"
 
def readOgr2Shply(inShpDIR):
	shapelyObjects=[]
	shp = ogr.Open(inShpDIR)
	lyr = shp.GetLayer()
	for n in range(0, lyr.GetFeatureCount()):
		feat = lyr.GetFeature(n)
		sFeat = loads(feat.geometry().ExportToWkt())
		shapelyObjects.append(sFeat)
	return shapelyObjects
 
def writeShply2Ogr(listShapelyShapes, outshpPTH, ogrWkbType=ogr.wkbPolygon):
	drv = ogr.GetDriverByName("ESRI Shapefile")
	ds = drv.CreateDataSource(os.path.split(outshpPTH)[0])
	lyr = ds.CreateLayer(os.path.splitext(os.path.split(outshpPTH)[1])[0], None, ogrWkbType)
	for shp in listShapelyShapes:
		ogrGeo = ogr.CreateGeometryFromWkt(shp.wkt)
		feat = ogr.Feature(lyr.GetLayerDefn())
		feat.SetGeometry(ogrGeo)
		lyr.CreateFeature(feat)
		feat.Destroy()
 
def deleteOutput():
	for shp in glob.glob(pthOutput+"*"):
		os.remove(shp)
 
def runPolygonize():
	lines = readOgr2Shply(pthTopo)
	writeShply2Ogr(polys, pthOutput + os.path.split(pthTopo)[1])
 
def runLineMerge():
	lines = readOgr2Shply(pthTopo)
	polys = list(linemerge(lines))
	writeShply2Ogr(polys, pthOutput + os.path.split(pthTopo)[1],ogr.wkbMultiLineString)
 
def writeSingleShape(listShapelyShapes, outshpPTH, ogrWkbType=ogr.wkbLineString):
	drv = ogr.GetDriverByName("ESRI Shapefile")
	ds = drv.CreateDataSource(outshpPTH)
	lyr = ds.CreateLayer(os.path.splitext(os.path.split(outshpPTH)[1])[0], None, ogrWkbType)
	for shp in listShapelyShapes:
		ogrGeo = ogr.CreateGeometryFromWkt(shp.wkt)
		feat = ogr.Feature(lyr.GetLayerDefn())
		feat.SetGeometry(ogrGeo)
		lyr.CreateFeature(feat)
		feat.Destroy()		
 
def runSplit():
	deleteOutput()
	splits = readOgr2Shply(pthSplitLines)
	splits = splits[0]
	poly = readOgr2Shply(pthMercer)
	poly = poly[0]
	intr = poly.intersection(splits)
	diff = [poly.difference(intr.buffer(0.0001))]
	print "\n\n"
	print diff
	print "\n\n"
	writeShply2Ogr(diff,pthOutput + "POLYGON_SPLIT.shp", ogrWkbType=ogr.wkbMultiPolygon)
 
	splits = readOgr2Shply(pthSplitLines)
	splits = splits[0]
	poly = readOgr2Shply(pthMercer)
	poly = poly[0]
	intr = poly.intersection(splits)
	diff = list(polygonize(poly.difference(intr.buffer(0.0001))))
	print "\n\n"
	print diff
	print "\n\n"
	writeShply2Ogr(diff,pthOutput + "POLYGON_SPLIT_POLYGONIZER.shp")

See what I mean? That’s pretty useful. It did return me each Polygon that made up the MultiPolygon. Now the bad news. This is a cheap method. If you were going to use this output for analysis you’d have to be very careful. Each polygon doesn’t share an edge along the splits. We buffered our lines remember? If you zoom way in you’ll see this:

The better way to do this might be using QuadEdge data types or Topology classes in GEOS and JTS. Maybe this is the next step — an unwritten example 5. We’ll see.

For the real brainiacs out there, you could write your own algorithm that traverses the edge of one polygon and for each segments asks if the split lines intersect it, split them at intersecting points, save off segments and reconstruct polygons. But that’s a way harder make-my-brain-hurt maths geometry stuffs.

Posted in OSGeo Spatial Libraries | Tagged , , , , , | Comments Off

Another Linux Fix — Repairing bash: /usr/bin/sudo: Permission denied on Ubuntu 10.10

Linux is so smart and powerful (or dumb) that a user can use the root command ‘sudo chmod’ to change permissions on the command ‘sudo’ itself, thereby rendering it useless.

You normally shouldn’t touch permissions on anything outside of home directory (what I’ve heard) for fear of hosing your system. But I’ve noticed that some permissions need to be set in /usr/local/lib, /usr/bin and /etc directories when building C/C++ libraries from source .

Last week I was reloading Postgresql (sudo /usr/init.d/postgres reload) when I got a permissions error deep inside /usr/bin. So I went about granting 777 read/write/execute access on that folder.

This also happens to be the place where ‘sudo’ command lives. And it wasn’t very happy after I did that. Every time I tried to use ‘sudo’ in the bash I got this error in return:

$ sudo -u postgres -i -H
bash: /usr/bin/sudo: Permission denied

Luckily, the nerds over at Ubuntu Forums had a possible fix for me. And it’s real cool. Here is the forum post and here is the abbreviated version for the fix:

1) Boot to your Ubuntu 10.10 install CD or flash drive and select the Ubuntu Trial Version instead of the install. Your bash screen will say ubuntu@ubuntu once your in.

2) Mount your partition

3) Compare the permissions on the directory you hosed from the mounted partition with what’s on CD as the default permissions.

4) You can then use the ‘sudo’ command from the booted CD to change permissions on the mounted partition. Say what?

That’s freaking sweet!

Posted in Ubuntu 10.10 | Tagged , , | Comments Off

Ubuntu 10.10 and it’s Mavericky Ways on Sony Vaio F Series Notebook

I started 2011 off with a fresh install of Ubuntu Maverick Meerkat on my Sony Vaio VPCF115FM laptop. I decided to do this because I was running Windows 7 as a host OS and VirtualBox Ubuntu 9.1 as the guest OS. This environment was slow when I was using Ubuntu to program and Windows to do various other things. The Sony Vaio F series is a pretty sweet computer for these reasons:

  1. Intel i7 processor (1.6 GHz)
  2. 6 GB RAM
  3. Nvidia GeForce 330M graphics card 1GB VRAM
  4. 500 GB hard drive

I thought I could get better performance out of it if I wiped it clean and free of Windows and just used it to program.

I also thought this was going to be an easy process.

I first started by installing Ubuntu 9.1 on the system which caused any number of driver issues:

  1. The recommended Nvidia drivers caused a screen blackout
  2. The WiFi driver was not working
  3. The fan speed was always on high even if Ubuntu was in suspend or hibernate
  4. A host of other issues that I didn’t even get time to explore

When I was solving the Nvidia driver issues I reinstalled Ubuntu 9.1 about three times because the new drivers caused a host of other problems like blinking terminal screens, blackouts and stalled logins.

The WiFi driver and fan speed issues were harder. I had to try to tell BIOS to disable fan speed so Ubuntu could take over the control of it. But Ubuntu couldn’t detect any sensor related to the fan and couldn’t identify the right modules to take over responsiblity. Ubuntu forums were full of conflicting advice on ways to fix the WiFi driver. I think I hosed my system a couple more times trying the various techniques. I had to reinstall at least two more times.

One Ubuntu forum helper told me to switch to 10.10 because it would solve the WiFi and fan speed issue. He was right.  But it created a whole set of other issues including:

  1. Inability to put computer in suspend or hibernate
  2. Fixed screen resolution and blackouts related to Nvidia recommended drivers
  3. Things I haven’t even discovered

The Nvidia drivers fix for both Ubuntu 9.1 and 10.10 came from this handy blog post.

I also came across a good blog post where the owner was experiencing similar problems on a very similar Vaio model. Based on that post it looks like some of these issues won’t be solved until the next Linux kernel release. Uh oh. I hope not.

Here is a possible fix that I still haven’t tried for the suspend and hibernate.

Despite all this I still love Ubuntu!

Posted in Ubuntu 10.10 | Tagged , , | Comments Off

<<< Goodbye 2010, Blah Blah Blah >>>


A month ago I was thinking about 2010 winding down. I got depressed about not doing as much open-source geospatial twiddling as I wanted. So I started a list of stuff — more of a long rant with links. When I was really hard on myself I looked at this list and wrote more things down. I started adding names of influential people and things I thought I learned. At some point I noticed 2010 wasn’t so bad in the education department.

Now when I look at this list the names of people jump out at me. They were crucial to my first year of learning in Seattle and are my teachers.  If it wasn’t for these people — the subterranean geonerds of the Northwest [1], my blogosphere faves, the list-serve helpers and the late-night repository commiters — then I might have been less of nerd today. This is for you guys and all your ridiculous ways. Here’s a paired down rant:

First, thanks to all the CUGOS members who provided monthly entertainment and brain food;  special thanks to mkgeomatics, peter ‘bulgolgi taco’, jared, dane, aaron, allison, karsten, jubal, roger and michael.

The conversations I had with mkgeomatics and peter were the catalyst for many project ideas. I’m not sure how many ideas were legitimately explored. But I’m sure it doesn’t really matter all the same. I learned a lot from those conversations and look forward to more of them.

Some open-source web map ideas included biking, food share and hiking wikis to rival the many Google mashups that actually exist and feel claustrophobic. There were those cool Python scripts mkgeomatics handed off to me that ran on my Android phone and POSTed my GPS movements to FeatureServer — never got that totally working. We talked about OSM rendering toolchains, image classification in GRASS, shaded reliefs, Nik2Img, OpenBaseMap . . . too many things to list.

One fun idea that stuck with me was about creating an svg icon collection similar to Brian Quinion’s for OSM except that ours would be totally ridiculous. The images you see here are from my first svg icon tests. I quickly learned making icons isn’t easy and requires skills I don’t have. These icons might be entitled “The Piano Has Been Drinking” or “Tom Waits Drank Here” or “Tom Wait Should Drink Here”. Perfect for hapless POI collection.

I think the basic idea is that map icons don’t have to be serious. I mean how else can you plot and make light of pot dispensaries, hipster hangouts, adult stores, drug dealer corners, high-density Abercrombie & Fitch zones or aesthetically displeasing buildings? Another added benefit of this site would be its absurdist approach to principles of cartographic design and the whole red-dot-mania-is-bad design thing. When you’re mapping weird stuff with ridiculous icons then cartographic principles are out the window and a whole world of potential absurdity opens up. I want to see a cluster of dots on a map about where Tom Waits might hang out or has hung out in Seattle . Anyway. . .

Jared introduced me to GeoScript and Justin. I played around with GeoScript and read through the binding classes.  I learned a lot about how to write Jython wrappers around Java libraries. Jared also gave a good introduction to the  long-standing tribal differences between the Java and C tribes of the OSGeo software world. I hope to learn more about both tribes, but this next year I think I want to focus on C++ and writing Python wrappers around C libraries. These topics also led me to really explore a whole set of Python bindings for GDAL, OGR and  GEOS such as Shapely and Django.

Dane and aaron showed me the fun of VirtualBox and Ubuntu. I’m never going back to Windows as a programming environment unless I have too. This spring I’m moving to Ubuntu as my full-time host OS because I found running Ubuntu on VirtualBox just isn’t fun enough. These two gave great advice on how to start contributing to open source projects through bug fixes, irc chatrooms and  code learning. I also learned about how the geospatial community interfaces with emergency response and humanitarian efforts through events/organizations/applications like CrisisCommons, Haiti OSM, HOT and GeoPlatform.

The presentations and ideas shared by roger, jubal and karsten gave me visions about what I want to be when i grow up. Thanks guys.

The boys at Stamen Design (mainly michal and aaron)  taught me that I should be fixing things that are broken or just damn ugly and making them pretty and functional.

Cartogrammer, the Axis Map folks, John Krygier and Dennis Hall gave me more than one psychogeography idea and typographic map project.

And finally, here’s to all you WhereCamp @ Where 2.0 presenters. That was fun, I look forward to 2011.

There’s much more, but I’m tired. Happy 2011!

NOTES:

[1] Only if your pacific northwest map  =
new OpenLayers.Map (‘map’ , {mapExtent: new OpenLayers.Bounds(
-13822686.872541215, 4373314.528989582, -13403811.957538474, 6373518.685155975), projection : “EPSG:3785″}) ;

Posted in Cross-Pollination, Map Art Stuff, Pyschogeography | Comments Off

Aptana Unified Builder Stall

This is a reblog of sorts. I’ve been experiencing a similar problem when running Apanta 2.0 on Ubuntu 9.1 and Windows 7. The problem occurs when I try to build and run a project using the default Aptana server. A process dialog will pop up saying that the project is building by ‘Invoking Aptana Unified Builder’. Then another process will start that says Firefox is waiting for the project to be built before it loads. This will go on indefinitely if you care to wait. I couldn’t find an easy solution online (it seems to be a problem that many people have had). After this problem started happening on Ubuntu I luckily ran across this post with a solution that works — thx Ernesto!

Posted in Uncategorized | Tagged , , | Comments Off

Choose Your Poison >>> The Many Paths of JavaScript Inheritance

I read a really great book during the November holiday weekend about object-oriented JavaScript. What do you know, it’s actually called “Object-Oriented JavaScript” and it’s by Stoyan Stefanov.

Chapter 4 & 6 were great because they simply explain the difference between JavaScript’s prototypal inheritance and classical language inheritance. Stoyan then goes through multiple flavors of JS inheritance (I think I counted 12) and talks about the benefits and drawbacks of each flavor. Douglas Crockford tackles similar topics on part of his website here. If you’re coming from a classical Java or C background then you have to take a look at this tutorial by Gavin Kistner because it’s absolutely sweet. It goes through using JavaScript inheritance but also shows how to mimic public, private and privileged access for member variables and functions.

What did I learn from Chapter 4 and 6? I learned that of the twelve ways to do JS inheritance two of them felt safe. The rest kind of scared me and supported my belief that JavaScript is the wild west of languages. I’m not sure I completely understood the nuanced benefits and drawbacks of each method. But the two JS inheritance methods that stuck with me can be summed up as follows 1) prototypal inheritance and 2) deep object copies:

//1 prototypal inheritance
function ProtoExtend(parentObject){
    function F(){};
    F.prototype = parentObject;
    F.prototype.uber = parentObject.constructor;
	F.constructor = F;
    return new F();
}
 
//2 deep copy
function DeepCopy(parentObject, childObject){
    for(i in parentObject){
        childObject.i = parentObject[i];
    }
    childObject.uber = parentObject;
    return childObject;
}

I prefer prototypal inheritance over the deep copy. So let’s look at a quick example given these few objects and a different flavor of prototypal inheritance that I’ll talk about in a second:

function ProtoExtendOoops(parentObject){
    function F(){};
    F.prototype = parentObject;
    F.prototype.uber = parentObject;
	F.constructor = F;
    return new F();
}
 
function Animal(){
	this.type = "animal";
	this.name = "generic";
	this.speak = function(){
	console.log( "I am an "+this.type+" and my name is "+this.name);
};
}
 
function Pig(){
this.name = "pigglet";
}

Now let’s use the FireBug console to explore these object relationships:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
>>> Pig.prototype = ProtoExtend(new Animal());
Object { type="animal", name="generic"}
>>> Pig.prototype.constructor = Pig;
Pig()
>>> var pig = new Pig();
undefined
>>> pig.type = "really a pig, but I guess mostly an animal";
"really a pig, but I guess mostly an animal"
>>> pig.speak();
I am an really a pig, but I guess mostly an animal and my name is pigglet
>>> delete pig.type;
true
>>> delete pig.name;
true
>>> pig.speak();
I am an animal and my name is generic
undefined
>>> pig.type = "PIG";
"PIG"
>>> pig.name = "pigglet2";
"pigglet2"
>>> pig.speak = function(){return "I'm outta here";}
function()
>>> pig.speak();
"I'm outta here"
>>> (new pig.uber).speak();
I am an animal and my name is generic
undefined
>>> (new pig.uber).type;
"animal"
>>> delete pig.uber
true
>>> pig.uber;
Animal()
>>> pig.constructor;
Pig()
>>> delete pig.type;
true
>>> delete pig.__proto__.type;
true
>>> pig.type
"animal"
>>> pig.__proto__.type = "what the heck";
"what the heck"
>>> pig.type;
"what the heck"

Lines 1 and 3 show the basic setup to using this type of inheritance. We have a constructor function called Pig (not an instance yet) and we are inheriting all the attributes of an animal object so that when we do instantiate a Pig we’ll get those attributes.

Line 3 is just one of those things you have to remember. If we don’t do this then our constructor for pig will still refer to Animal(). Line 5 I instantiate a pig object. Line 7 I create a pig attribute called ‘type’ anticipating that it will override the parent attribute of ‘type’ (also notice that Pig constructor function already had a ‘name’ attribute that should do the same thing).

Line 9 calls the ‘speak()’ function that pig inherits from animal but it’s using our local pig variable overrides. Lines 12 and 14 get rid of all pig attributes. Now when we call speak in Line 16 the parent’s attributes shine through. Lines 18, 20 and 22 add attributes back to the pig and override the ‘speak()’ function.

Line 24 shows that everything works great with our override. But what if we need to use functionality from the parent’s class? This is where our reference to the super class constructor comes in (uber in this case). Lines 26 and 28 show how to get at the parent’s functionality.

The rest of lines show that this methodology isn’t completely encapsulated, error proof or necessarily easy to understand. I don’t know how we still have attributes around once we ‘delete’ them. Maybe this is the wrong function. We can inadvertently change the parent’s attributes using the ‘__proto__’ reference. This is bad news. But from what I understand this reference only exists in FireFox JavaScript. So our parent object should be fairly encapsulated from writes as we should expect.

Now let’s run Lines 1 through 5 again but use our ProtoExtendOoops() function. The only difference here is that the ‘attribute’ uber will refer to the parent object instead of the parent’s constructor function. This has unexpected consequences because we can change the parent’s state. Then we’re really hosed. The take home point here is that the original ProtoExtend() function has ‘uber’ refer to the parent’s constructor. If we need to use parent functionality then we aren’t in danger of hosing our parent residing in the child’s prototype object like we do below.

>>> pig.uber.type = "giraffe";
"giraffe"
>>> pig.speak();
I am an giraffe and my name is generic
>>> console.log("Uh Oh!");
Uh Oh!

In the near future I’ll only be using JavaScript frameworks like ExtJS and Dojo. While I might not be designing any complicated OOAD patterns with JS objects soon at least I know something more about how to implement inheritance when the time comes :)

Posted in JavaScript, OO JavaScript | Tagged , | Comments Off

Map Art or DIY Blah

I’m tightening my spending and that means. . . abstract holiday map cards for everyone! I took the idea for this card from somewhere around the interwebs and I can’t find it again. This is the very first one for my girlfriend. I see way too many spelling mistakes in there.

Posted in Map Art Stuff | Comments Off