By Rupert
Posts tagged mapserver
iPhone Note #20:Integrating Mapserver/TileCache to RouteMe
Jan 14th
Below is a summary of how I was able to implement Mapserver, TileCache and Route-Me iPhone Mapping Framework.
1. Assuming you have a working Mapserver/TileCache setup. Take note of the ff parameters: resolution and bbox. Below is my tilecache.cfg:
61 [mapserver_australia_3857] 62 type=MapServerLayer 63 mapfile=/Users/rupert/projects/pelicancorp/DMOB/trunk/map/australia_3857.map 64 layers=all 65 extension=jpg 66 bbox=-20037508.34, -20037508.34, 20037508.34, 20037508.34 68 maxResolution=156543.033928041 70 levels=20 71 srs=EPSG:3857 72 tms_type=google 73 extent_type=loose 74 spherical_mercator=true
2. Grab the RMGenericMercatorWMSSource from http://groups.google.com/group/route-me-map/browse_thread/thread/b58fa1d20cf15823/e30c42d9c90a8170?lnk=gst&q=Generic#e30c42d9c90a8170
3. By default without any changes, the RMGenericMercatorWMSSource could display Mapserver WMS Tiles. This is possible by passing an NSDictionary *parameters, which contains arrayValues and arrayKeys for creating an http 256×256 image request to the http://127.0.0.1/cgi-bin/mapserv binary.
//This would request to http://127.0.0.1/cgi-bin/mapserv NSArray *arrayValues = [[NSArray alloc] initWithObjects:@"/path-to/australia_3857.map", @"all", @"png", @"EPSG:3857",nil]; NSArray *arrayKeys = [[NSArray alloc] initWithObjects:@"MAP", @"LAYERS", @"FORMAT", @"SRS", nil]; NSDictionary *wmsParameters = [[NSDictionary alloc] initWithObjects: arrayValues forKeys:arrayKeys ];
Resulting http requests to the mapserv binary:
http://192.168.1.193:81/tilecache/tilecache.py?LAYERS=australia_3857&SRS=EPSG:3857&REQUEST=GetMap&SERVICE=WMS&STYLES=&EXCEPTIONS=application%2Fvnd.ogc.se_inimage&FORMAT=png&VERSION=1.1.1&WIDTH=256&HEIGHT=256&BBOX=16828376.000000,-4006523.000000,16833268.000000,-4001631.000000
Note that the bbox values does not contain decimal places. Nevertheless, it still works on Mapserver.
4. Now, assuming we have a valid tilecache running. And it is tested from browser, i.e http://127.0.0.1/map/tilecache_3857.html, open up firebug to see the requests. Below is a sample…
http://192.168.1.193:81/tilecache/tilecache.py?LAYERS=australia_3857&FORMAT=jpg&SERVICE=WMS&VERSION=1.1.1&REQUEST=GetMap&STYLES=&EXCEPTIONS=application%2Fvnd.ogc.se_inimage&SRS=EPSG%3A3857&BBOX=16123932.497377,-4539747.9811239,16143500.376618,-4520180.1018829&WIDTH=256&HEIGHT=256
But it seems, route-me is not supplying the bbox values accurately, as the decimal values is truncated (BBOX=16828376.000000,-4006523.000000,16833268.000000,-4001631.000000) from our previous request(3).
After changing the wmsParameter values to create a tilecache request, I noticed that route-me is not displaying the tiles correctly.
//Testing for Windows:TileCache - ? NSArray *arrayValues = [[NSArray alloc] initWithObjects:@"australia_3857", @"png", @"EPSG:3857",nil]; //for WIndows //TileCache URL Parameters: NSArray *arrayKeys = [[NSArray alloc] initWithObjects:@"LAYERS", @"FORMAT", @"SRS", nil];
5. The workaround is to use “double” instead of “floats” in the RMGenericMercatorWMSSource. You can download the zip from RMGenericMercatorWMSSource.zip. I have modified “initialResolution” and “originShift” to both use “double”.
typedef struct { double x; double y; } CGDoublePoint; typedef struct { CGDoublePoint ul; CGDoublePoint lr; } CGXYRect;
Afterwards, I copied the maxResolution and bbox (tilecache) and specified it for the initialResoultion and originShift respectively.
#import "RMGenericMercatorWMSSource.h" CGFloat DegreesToRadians(CGFloat degrees) {return degrees * M_PI / 180;}; CGFloat RadiansToDegrees(CGFloat radians) {return radians * 180/ M_PI;}; @implementation RMGenericMercatorWMSSource -(id) initWithBaseUrl:(NSString *)baseUrl parameters:(NSDictionary *)params { if (![super init]) return nil; // 156543.03392804062 for sideLength 256 pixels // initialResolution = 2 * M_PI * 6378137 / [self tileSideLength]; // specify here whatever the resolution is from tilecache. initialResolution = 156543.033928041; // 20037508.342789244 //originShift = 2 * M_PI * 6378137 / 2; //originShift = 20037508.342789244f; // specify here whatever the bbox is from tilecache. originShift = 20037508.32; NSLog(@"test initialResolution:%f originShift:%f", initialResolution, originShift); // setup default parameters // use official EPSG:3857 by default, user can override to 900913 if needed. wmsParameters = [[NSMutableDictionary alloc] initWithObjects:[[[NSArray alloc] initWithObjects:@"EPSG:3857",@"image/png",@"GetMap",@"1.1.1",@"WMS",nil] autorelease] forKeys:[[[NSArray alloc] initWithObjects:@"SRS",@"FORMAT",@"REQUEST",@"VERSION",@"SERVICE",nil] autorelease]]; [wmsParameters addEntriesFromDictionary:params]; // build WMS request URL template urlTemplate = [NSString stringWithString:baseUrl]; NSEnumerator *e = [wmsParameters keyEnumerator]; NSString *key; NSString *delimiter = @""; while (key = [e nextObject]) { urlTemplate = [urlTemplate stringByAppendingFormat:@"%@%@=%@", delimiter, [[key uppercaseString] stringByAddingPercentEscapesUsingEncoding:NSASCIIStringEncoding], [[wmsParameters objectForKey:key] stringByAddingPercentEscapesUsingEncoding:NSASCIIStringEncoding]]; delimiter = @"&"; } int sideLength = [self tileSideLength]; urlTemplate = [[urlTemplate stringByAppendingFormat:@"&WIDTH=%d&HEIGHT=%d",sideLength,sideLength] retain]; return self; } // implement in subclass? -(NSString*) uniqueTilecacheKey { return @"AbstractMercatorWMSSource"; } -(NSString *)shortName { return @"Generic WMS Source"; } -(NSString *)longDescription { return @"Generic WMS Source"; } -(NSString *)shortAttribution { return @"Generic WMS Source"; } -(NSString *)longAttribution { return @"Generic WMS Source"; } -(float) minZoom { return 1.0f; } -(float) maxZoom { return 19.0f; } // Converts given lat/lon in WGS84 Datum to XY in Spherical Mercator EPSG:3857 -(CGPoint) LatLonToMeters: (CLLocationCoordinate2D) latlon { CGPoint meters; meters.x = latlon.longitude * originShift / 180; meters.y = (log( tan((90.0 + latlon.latitude) * M_PI / 360.0 )) / (M_PI / 180.0)) * originShift / 180; return meters; } //Converts XY point from Spherical Mercator EPSG:3857 to lat/lon in WGS84 Datum -(CLLocationCoordinate2D) MetersToLatLon: (CGPoint) meters { CLLocationCoordinate2D latlon; latlon.longitude = (meters.x / originShift) * 180.0; latlon.latitude = (meters.y / originShift) * 180.0; //latlon.latitude = - 180 / M_PI * (2 * atan( exp( latlon.latitude * M_PI / 180.0)) - M_PI / 2.0); latlon.latitude = 180 / M_PI * (2 * atan( exp( latlon.latitude * M_PI / 180.0)) - M_PI / 2.0); return latlon; } // Converts pixel coordinates in given zoom level of pyramid to EPSG:3857 -(CGDoublePoint) PixelsToMeters: (int) px PixelY:(int)py atZoom:(int)zoom { double resolution = [self ResolutionAtZoom: zoom]; CGDoublePoint meters; double x = (px * resolution - originShift); double y = (py * resolution - originShift); meters.x = x; meters.y = y; NSLog(@"px: %d py: %d resolution: %f originShift: %f x: %f y: %f", px, py, resolution, originShift, x, y); return meters; } -(NSString*) tileURL: (RMTile) tile { //RMLatLongBounds tileBounds = [self TileLatLonBounds:tile]; // Get BBOX coordinates in meters CGXYRect tileBounds = [self TileBounds:tile]; NSString *url = [urlTemplate stringByAppendingFormat:@"&BBOX=%f,%f,%f,%f", tileBounds.ul.x, tileBounds.lr.y, tileBounds.lr.x, tileBounds.ul.y]; NSLog(@"Tile %d,%d,%d yields %@",tile.zoom, tile.x, tile.y, url); return url; } //Returns bounds of the given tile in EPSG:3857 coordinates -(CGXYRect) TileBounds: (RMTile) tile { int sideLength = [self tileSideLength]; int zoom = tile.zoom; long twoToZoom = pow(2,zoom); CGXYRect tileBounds; tileBounds.ul = [self PixelsToMeters: (tile.x * sideLength) PixelY: ((twoToZoom-tile.y) * sideLength) atZoom: zoom ]; tileBounds.lr = [self PixelsToMeters: ((tile.x+1) * sideLength) PixelY: ((twoToZoom-tile.y-1) * sideLength) atZoom: zoom]; return tileBounds; } //Resolution (meters/pixel) for given zoom level (measured at Equator) -(double) ResolutionAtZoom : (int) zoom { return initialResolution / pow(2,zoom); } @end
6. Download TileCache_RouteMe.zip Note: You need a valid mapserver and tilecache running.
Installing Chinese Font for Mapserver
Jul 28th
We wanted to use a different font for mapserver which is Microsoft Yahei instead of zysong. Apparently, mapserver have some issues with path problems or with the ttf having more than one word as a font name.
Thanks to Martin Hosken’s perl modules for fonts, we were able to rename the Microsoft Yahei TTF to msyh.ttf.
1. Download: (a) Font-TTF-0.45 (b) Font-TTF-Scripts-0.11.1
2. Unzip
#perl Makefile.pl #make #make install
3. ttfname
rupert:Desktop rupert$ ttfname Usage: ttfname [-f "full_name"] -n "name" [-t num] [-q] infile.ttf outfile.ttf Renames the TTF with the given name and outputs the newly named font to out.ttf. Options: -f "name" specifies new full name (optional) as opposed to the default calculated form. -l lang language number to use (default all langs) if specified name entries will be added for all platforms and encodings covered by the cmap if not already there -n "name" specifies new font family name (not optional) -q disable signon message -s filename overrides -n and gets string from file. Useful for -t -t num overrides the normal naming areas to change another string -f becomes inactive. #ttfname -f "Microsoft YaHei" -n "msyh" Microsoft\ YaHei.ttf msyh.ttf

Installing Mapserver on MacOSX (by source)
Jul 26th
Just noticed that William of kyngchaos has updated the mapserver binary for MacOSX.
But right now, I need to tile these images bought from GeoEye, so I need TIFF support. Below is a summary of getting Mapserver installed by source. Note that I have the necessary GEOS, GDAL from kyngchaos as well from this ealier post.
1. Download the ff files:
-rw-r--r--@ 1 rupert admin 564313 Jul 26 10:32 agg-2.5.tar.gz
-rw-r--r--@ 1 rupert admin 1345700 Jul 26 10:22 gd-2.0.35.tar.gz
-rw-r--r--@ 1 rupert admin 613261 Jul 26 10:22 jpegsrc.v6b.tar.gz
-rw-r--r--@ 1 rupert admin 796551 Jul 26 10:22 libpng-1.2.29.tar.gz
-rw-r--r--@ 1 rupert admin 1948751 Jul 26 09:55 mapserver-5.2.0.tar.gz
-rw-r--r--@ 1 rupert admin 1336295 Jul 26 11:11 tiff-3.8.2.tar.gz
2. Install in the ff order:
- jpegsrc
- libpng
- gd (if you have trouble installing gd, then follow this pdf:installing_gd2_on_os_x_server)
- agg (make only)
- tiff
- mapserver
3. For mapserver, please install using the ff configure switches:
./configure \ --with-agg=/myhome/rupert/mapserver/agg-2.5 \ --with-jpeg \ --with-gd \ --with-freetype \ --with-png \ --with-ogr \ --with-proj \ --with-gd \ --with-httpd=/usr/local/apache2/bin/httpd \ --with-tiff \ --with-wfs \ --with-wcs \ --with-sos \ --with-wmsclient \ --with-wfsclient \ --with-tiff \ --with-gdal=/usr/local/bin/gdal/gdal-config \ --with-geos=/usr/local/bin/geos-config \ --with-postgis=/usr/local/pgsql/bin/pg_config
4. Mapserver output
rupert:mapserver-5.2.0 rupert$ ./mapserv -v MapServer version 5.2.0 OUTPUT=GIF OUTPUT=PNG OUTPUT=JPEG OUTPUT=WBMP OUTPUT=SVG SUPPORTS=PROJ SUPPORTS=AGG SUPPORTS=FREETYPE SUPPORTS=ICONV SUPPORTS=WMS_SERVER SUPPORTS=WMS_CLIENT SUPPORTS=WFS_SERVER SUPPORTS=WFS_CLIENT SUPPORTS=WCS_SERVER SUPPORTS=SOS_SERVER SUPPORTS=GEOS INPUT=TIFF INPUT=EPPL7 INPUT=POSTGIS INPUT=OGR INPUT=GDAL INPUT=SHAPEFILE
Installing Mapserver on MacOSX Leopard (the easy way)
May 6th
The easiest way to install mapserver on your Leopard is by downloading and installing dmg files from www.kyngchaos.com (courtesy of William Kyngesburye). These binaries were also noted from Mapserver’s Download Page.
1. Download the ff binaries in order (please note the version numbers at the time of writing):
1. UnixImageIO_Framework-1.0.22a.dmg
2. FreeType_Framework-2.3.5-3.dmg
3. GEOS_Framework-3.0.0-2.dmg
4. PROJ_Framework-4.6.0-1.dmg
5. SQLite3_Framework-3.5.7-1.dmg
6. MapServer-5.0.2-2.dmg
2. Once installed, you can copy the mapserv binaries to your apache cgi-bin
sudo cp /Library/WebServer/CGI-Executables/mapserv /usr/local/apache2/cgi-bin/
3. Check the mapserv output
rupert:~ rupert$ /usr/local/apache2/cgi-bin/mapserv -v MapServer version 5.0.2 OUTPUT=GIF OUTPUT=PNG OUTPUT=JPEG OUTPUT=WBMP OUTPUT=SWF OUTPUT=SVG SUPPORTS=PROJ SUPPORTS=AGG SUPPORTS=FREETYPE SUPPORTS=WMS_SERVER SUPPORTS=WMS_CLIENT SUPPORTS=WFS_SERVER SUPPORTS=WFS_CLIENT SUPPORTS=WCS_SERVER SUPPORTS=SOS_SERVER SUPPORTS=FASTCGI SUPPORTS=GEOS INPUT=EPPL7 INPUT=POSTGIS INPUT=OGR INPUT=GDAL INPUT=SHAPEFILE
This is actually the first time I was able to install mapserver NOT BY SOURCE and still achieve the same binaries that I wanted (with AGG support). Full credit should be given to William.
Using TileCache, OpenLayers, Mapserver for Projection 900913
Apr 8th
I had a few problems with TileCache the other week which I am eager to blog about, since I knew for sure that later on, I might encounter the same. I don’t have the exact errors with me right now, so I’m jotting this down from my head…
- Classic Resolutions problem. Use extent_type=loose
- Can not set image type
UPDATED (JAN 11, 2010): Classic Resolutions problem:
How are resolutions calculated? Assuming we have:
Original:
Lower Left (LL) or minx, miny: 12453557, -5434940
Upper Right (UR) or max, maxy: 16980842, -1180729
maxResolution = (max – minx)/tilesize = (16980842 – 12453557)/512 = 8842.353
where tilesize = 512.
Therefore, we can set/guess for max so that we have maxResolution as a whole number.
Adjusted:
minx, miny: 12453557, -5434940
maxx, maxy: 16980661, -1180729
gives a maxResolution (whole number) of 8842.
Now, you can use 8842 in both the TileCache.cfg and OpenLayers Javascript. More >
Comments