Sunday, March 28, 2010

Using Java Map Projection Library in Android

Recently I was writing a little mapping application on Android, which basically takes Open Street Map tiles as base layer, and also has the ability to overlay some vector features on top. In this application there is need to convert coordinates back and forth between WGS84 and Mercator projection, so I need certain library to do the job. Given the popularity of PROJ.4, the pure Java port of it, Java Map Projection Library (name it “PROJ4Java” below), seems to be an obvious choice so I spend some hours during the weekend to see how it works.
First you can get the latest version (1.0.6) of PROJ4Java from this link. The size of the library is very small and lightweight with only 1.17MB for complete source code and 247KB for compiled jar file. If you’re familiar with PROJ.4 itself then this Java version should be quite straight forward, otherwise there isn’t much sample code or tutorial on its homepage. But the basic workflow is quite simple as described by its project homepage:
To use the library, you need to create a projection, either directly by calling its constructor or via one of the factory methods. Once you have a Projection, you can use it to convert between latitude/longitude and projected map units (by default, metres) by calling the transform and transformInverse methods.
A major issue of using PROJ4Java on Android is that out of box it can’t be run due to the fact that it is using some classes in java.awt.geom.* which is not available in Android SDK. But since the only major AWT class used by PROJ4Java is Point2D, it’s not difficult at all to work around by replacing it with your own 2D point class. In my case I use the point class from JTS library. After taking out all Java awt class references from source code and replacing them with JTS class, everything works pretty well on Android.
Another thing I modifies on the source code is to get rid of those projection implementations I don’t need. Mercator projection is the only one I need so far so that I am able to reduce the size of compile jar file to only 168KB. Here is a list of classes I extracted from original source code to support only Mercator projection:
    • com.jhlabs.map.*
    • com.jhlabs.map.proj.CylindricalProjection
    • com.jhlabs.map.proj.Ellipsoid
    • com.jhlabs.map.proj.MercatorProjection
    • com.jhlabs.map.proj.Projection
    • com.jhlabs.map.proj.ProjectionFactory
    • com.jhlabs.map.proj.ProjectionException
    • com.jhlabs.map.proj.Ellipsoid
ProjectionFactory class is the entry point for you to use PROJ4Java, which provides several static methods to create an instance of Projection. Below are some use cases I figured out by briefly reading through the source code:
(1) ProjectionFactory.getNamedPROJ4CoordinateSystem(String name) takes a well-known projection code like “epsg:4326” and returns a Projection:
1: String name = "epsg:3785";    
2: Projection proj = ProjectionFactory.getNamedPROJ4CoordinateSystem(name);
(2) ProjectionFactory.fromPROJ4Specification(String[] params) takes a set of PROJ.4 parameters and returns a Projection:
1: String[] params = {
2:     "proj=tmerc",
3:     "lat_0=37.5",
4:     "lon_0=-85.66666666666667",
5:     "k=0.999966667",
6:     "x_0=99999.99989839978",
7:     "y_0=249999.9998983998",
8:     "ellps=GRS80",
9:     "datum=NAD83",
10:     "to_meter=0.3048006096012192",
11:     "no_defs"
12: };
13: ProjectionFactory.fromPROJ4Specification(params);
(3) Create an instance of customized projection. All supported projection definition strings (PROJ.4 parameters for ) for PROJ4Java are listed in text files under folder “nad” that is coming with the library. These files are “epsg”, “esri”, “nad27”, “nad83”, and “world”, and a sample projection definition string is like below:
1: <2965> +proj=tmerc +lat_0=37.5 +lon_0=-85.66666666666667 +k=0.999966667 +x_0=99999.99989839978 +y_0=249999.9998983998 +ellps=GRS80 +datum=NAD83 +to_meter=0.3048006096012192 +no_defs
2: 
To add a new customized projection just create a definition string (usually modify certain parameter values upon an existing projection) and add it into one of those files, or create a new text file under “nad” folder with the definition string, then use the code below:
1: Projection proj = null;
2: try {
3:     // assume that "epsg:900913" projection defintion 
4:     //   has been added in text file "others"
5:     proj = ProjectionFactory.readProjectionFile("others", "900913");    
6: } catch(IOException e) {
7:     e.printStackTrace();
8: }
(4) Transform between lat/lon and projection units with a Projection instance:
1: Projection epsg3785 = ProjectionFactory.getNamedPROJ4CoordinateSystem("epsg:3785");    
2:               
3: System.out.println("transform from latlon to epsg:3785");
4: System.out.println("latlon: -117.5931084, 34.1063989");
5: Point pEpsg3785 = epsg3785.transform(-117.5931084, 34.1063989);
6: System.out.println("epsg:3785: " + pEpsg3785.getX() + ", " + pEpsg3785.getY());
7:     
8: System.out.println("transform from epsg:3785 to latlon");
9: System.out.println("epsg:3785: " + pEpsg3785.getX() + ", " + pEpsg3785.getY());
10: Point latlon = epsg3785.inverseTransform(pEpsg3785);
11: System.out.println("latlon: " + latlon.getX() + ", " + latlon.getY());
12: 
13:   

Tuesday, March 9, 2010

WMS TIME support in MapServer

In context of my last blog, I’m looking at the WMS TIME support in OSGeo MapServer. MapServer has a very concise and helpful doc on the scope and usage of WMS TIME in its implementation. It is always a good idea to briefly go through the documentation first before you spend a lot time trying something that may not be even  implemented.
My test data (in shapefile format) is very simple such that the picture below tells all about it:
0
Each point feature has a field “TIME” which has time value in syntax “YYYY-MM-DD HH:MM:SS”. This is valid ISO8601 time format and supported by MapServer. All points have a time stamp within day 2010-02-16. To enable time on WMS in MapServer is straight forward given that you have some experience of publishing shapefile as a WMS in MapServer. The only extra thing you need to configure is to specify time field, time extent and default time value in map file. That’s it and MapServer documentation is very clear on how to do that.
1: LAYER
2:     NAME 'points'
3:     METADATA
4:         "ows_title" "points"
5:         "gml_include_items"   "all"
6:         "wms_include_items"   "all"
7:         # TIME Related
8:         "wms_title"          "points"
9:         "wms_timeextent"     "2010-02-16T00:00:00Z/2010-02-17T00:00:00Z/P1H"
10:         "wms_timeitem"       "TIME"
11:         "wms_timedefault"     "2010-02-16T12:00:00Z,2010-02-16T18:00:00Z"
12:     END
13: ...
14: END
After saving the map file and refresh the GetCapabilities response you will notice information of time dimension is advertised.
1: <Dimension name="time" units="ISO8601" default="2010-02-16T12:00:00Z,2010-02-16T18:00:00Z" nearestValue="0">
2:     2010-02-16T00:00:00Z/2010-02-17T00:00:00Z/P1H
3: </Dimension>
4: 
The time extent value in <Dimension> is whatever you specified in “wms_timeextent” so it doesn’t smart enough to calculate the extent from data, and neither does MapServer do any validation on the time extent string. A trick I did in map file is to provide a special default time value “2010-02-16T12:00:00Z, 2010-02-16T18:00:00Z,”, which will inform me if certain time string is not correctly processed by MapServer thus default value is used.

Now it’s time to try a few requests against this time enabled WMS. According to doc the supported request syntax for time are “t”, “t1,t2…”, “t1/t2”, and “t1/t2,t3/t4…” and “t” should be any valid ISO8601 time string. I skipped the time zone because there is nowhere indicating it is implemented (you can not configure time zone at server-side thus it makes no sense to request from client). Below is a list of different time values that have been tried:
  • …&TIME=2010 (not recognized, default time value is returned)
  • …&TIME=2010-02 (not recognized, default time value is returned)
  • …&TIME=2010-02-16 (recognized, only point of “2010-02-16 00:00:00” returned)
  • …&TIME=2010-02-16T12 (recognized, only point of “2010-02-16 12:00:00” returned)
  • …&TIME=2010-02-16T12:00 (recognized, only point of “2010-02-16 12:00:00” returned)
  • …&TIME=2010-02-16T12:00:00 (recognized, only point of “2010-02-16 12:00:00” returned)
  • …&TIME=2010-02-16T14:59:59 (recognized, only point of “2010-02-16 14:59:59” returned)
  • …&TIME=2010-02-16T15:00:01 (recognized, only point of “2010-02-16 15:00:01” returned)
  • …&TIME=2010-02-16T15:00:00.000 (recognized, only point of “2010-02-16 15:00:00” returned)
  • …&TIME=2009/2010 (not recognized, default time value is returned)
  • …&TIME=2010/2011 (not recognized, default time value is returned)
  • …&TIME=2010-02/2010-03 (not recognized, default time value is returned)
  • …&TIME=2010-02-16/2010-02-17 (recognized, all points returned)
The test results above actually proves the time interpretation described in the documentation:
When MapServer receives a request with a TIME parameter, it transforms the time requests into valid expressions that are assigned to the filter parameter on layers that are time-aware.
Here are some examples of how different types of requests are treated (wms_timeitem is defined here as being “time_field”):
single value (2004-10-12) transforms to (`[time_field]` eq `2004-10-12`)
multiple values (2004-10-12, 2004-10-13) transform to (`[time_field]` eq `2004-10-12` OR `[time_field]` eq `2004-10-13`)
single range : 2004-10-12/2004-10-13 transforms to ((`[time_field]` ge `2004-10-12`) AND (`[time_field]` le `2004-10-13`))
multiple ranges (2004-10-12/2004-10-13, 2004-10-15/2004-10-16) transform to ((`[time_field]` ge `2004-10-12` AND `[time_field]` le `2004-10-13`) OR (`[time_field]` ge `2004-10-15` AND `[time_field]` le `2004-10-16`))
As shown in the above examples, all fields and values are written inside back tics (`) - this is the general way of specifying time expressions inside MapServer.
Overall it’s doing a good job and the only thing missing point is that requests like “TIME=2010” and “TIME=2010/2011” should be properly handled.

If you read carefully, MapServer documentation has another slightly different time interpretation for PostGIS layer, to test that I followed up and applied the same requests on a PostGIS layer.

Things I need to configure before I can finally send the same set of WMS time requests to PostGIS layer are listed below:
  • Use “shp2pgsql” command line to convert shape file into pgsql file;
  • Use “psql” command line to load pgsql file into PostGIS database;
  • Add another new column of type “timestamp without time zone”;
  • Copy time value from original column to the new column;
  • Modify map file to use new column of of type “timestamp without time zone” for WMS time;
  • Modify the map file to point to PostGIS table instead of shape file;
All of above are straight forward except that a WMS layer based on PostGIS doesn’t seem to recognize the temporal field if it is of type “character varying”, which force me to add an extra column in type “timestamp without time zone” and copy over those original time values in string. After all of those it worked and below are the results of same WMS TIME requests on shapefile layer:
  • …&TIME=2010 (not recognized, default time value is returned)
  • …&TIME=2010-02 (not recognized, default time value is returned)
  • …&TIME=2010-02-16 (recognized, all points with time stamp within 2010-02-16 returned)
  • …&TIME=2010-02-16T12 (recognized, points between 12:00:00 and 13:00:00 on 2010-02-16 returned, not including points on 13:00:00)
  • …&TIME=2010-02-16T12:00 (recognized, only point of “2010-02-16 12:00:00” returned)
  • …&TIME=2010-02-16T12:00:00 (recognized, only point of “2010-02-16 12:00:00” returned)
  • …&TIME=2010-02-16T14:59:59 (recognized, only point of “2010-02-16 14:59:59” returned)
  • …&TIME=2010-02-16T15:00:01 (recognized, only point of “2010-02-16 15:00:01” returned)
  • …&TIME=2010-02-16T15:00:00.000 (recognized, only point of “2010-02-16 15:00:00” returned)
  • …&TIME=2009/2010 (not recognized, default time value is returned)
  • …&TIME=2010/2011 (not recognized, default time value is returned)
  • …&TIME=2010-02/2010-03 (not recognized, default time value is returned)
  • …&TIME=2010-02-16/2010-02-17 (recognized, all points returned)
So it proves what it says in the doc about PostGIS layer:
For PostGIS/PostgreSQL layers, the time expression built uses the date_trunc function available in PostgreSQL. For example, if the user passes a time value of ‘2004-10-12’, the expression set in the filter is date_trunc(‘day’, time_field) = ‘2004-10-12’. The use of the date_trunc function allows requests to use the concept of time resolution. In the example above, for a request of ‘2004-10-12’, MapServer determines that the resolution is “day” by parsing the time string and the result gives all records matching the date 2004-10-12 regardless of the values set for Hours/Minutes/Seconds in the database. For more information on the date_trunc function, please refer to the PostgreSQL documentation.

Thursday, March 4, 2010

Two ambiguities about TIME in OGC WMS specification

OGC WMS specification had included “TIME” dimension since version 1.1.0, in which it guides the WMS implementations on how “TIME” is involved in filtering feature that will finally be visible in either a result map or a query result (aka. GetFeatureInfo result). To me, what it defines about “TIME” dimension in WMS spec seems to be both accurate and ambiguous. It is accurate because it introduces the ISO 8601 standard to cover the exchange of date and time related parameters between a WMS server and a WMS client, which eliminate the risk of misinterpretation where numeric representation of dates and times are interchanged across national boundaries, and to avoid the confusion and other consequential errors or losses (quoted from wiki ISO8601 entry). But it’s also ambiguous in two places (1) where an interpretation is needed for an ISO standard time string; (2) where a temporal attribute has different meanings for different types of features. In this blog let’s skip the accurate part that I am happy with, but discuss the ambiguous part using a few examples. 

The first ambiguity is actually not a problem of WMS spec itself but comes from the nature of the data when a temporal attribute value has different meanings for different types of features. Basically time values can ne divided into two different types: time as a individual time point and time as a time window.  Time as a time point doesn’t have any relation to its history or future, one good example is a rocket feature with a time attribute called “launch” that has a value of “2000-03-04T00:00:00Z”. It means the rocket launched at Mar.4th 2000 at 12 am which has nothing to do with any time before it or after. But time as a time window instead expand backward or forward. One example is a house feature that has time attribute called “built” with a value of “2000”, it actually affects the time after 2000 because the house exists since then. Another example is an animal species with time attribute “extinct” of value “2000”, which actually affects the time before 2000 because the animal species had existed before 2000.  Given the fact that all of those single time values are treated the same in database, it will potentially affect the result of a query on those features.

The second ambiguity in WMS spec, as I mentioned above is the interpretation for a time value. For example, when you send a WMS request like “http://…/…request=GETMAP&…&TIME=2010”, what does it exactly mean? It sounds like a stupid question because everyone knows “2010” meaning year 2010, which is clearly defined in ISO8601 as valid. But how do you interpret this request is ambiguous. Assume you’re a time-enabled WMS server and you have some features with time stamps between 2010 and 2011 (any month, day, hour, minute, or second within 2010), will you include those features in the map response to request “…&TIME=2010”? I bet you answer yes without hesitation because naturally “TIME=2010” means within 2010. But will you give it a second thought if I give a different request “http://…/…request=GETMAP&…&TIME=2010-12-10T12” on the same set of features? Do you still think you should include all the features between 12pm and 1pm on 2010-12-10? I don’t think so but that’s actually the same logic you used when you process request “http://…/…request=GETMAP&…&TIME=2010”.

If you’re implementing a TIME-enabled WMS at server-side you probably already encountered those two problems, and I don’t think the solution is simply throwing the TIME values to database for string comparison even if the database is aware of date/time type. The best way I can think of is always using time window internally (even though sometimes that time window is very small) for both feature temporal attributes and time parameter in the WMS request. To be more specific, when serving out you data if you have a rocket feature launched at “2000-03-04T00:00:00Z” then explicitly treat it as “2000-03-04T00:00:00.000Z/2000-03-04T00:00:00.999Z”; if you have a house built on “2010” then explicitly treat it as “2010/far future”; and finally if you have an animal species extinct in 2000 then explicitly treat it as “long ago/2000”. Now when it comes to time parameter in WMS request, the spec allows syntaxes like “TIME=time1”, “TIME=time_start/time_end”, “TIME=time1,time2” and “TIME=time_start1/time_end1,time_start2/time_end2” but no matter what client sends to you, my suggestion is to always treat each single time value as a time window based on its smallest interval. For example, if “TIME=2000” then treat it as “TIME=2000/2001” (the smallest time interval is year); if “TIME=2000-03-04T00:05Z” treat it as “2000-03-04T00:05Z/2000-03-04T00:06Z” (the smallest time interval is minute) and so on. By using this mechanism every time relate value is a time window, which makes the query more straight forward, just include the feature either in map or query results if the query time window touches, intersects or contains the time window of feature temporal attribute. Although it won’t totally solve the ambiguity above, it helps improve the accuracy.

Monday, February 22, 2010

Setup a http based SVN repository with TortoiseSVN and Apache http server

It is very useful to setup a http based SVN repository on your local machine just for daily check in and out of source code. I am pretty sure there are plenty of materials over the web that explain how to do it for different combinations. Here is the one which I went through and it works pretty good for me.
1. Install and configure TortoiseSVN
2. Install Apache HTTP Server
    • Download Apache HTTP Server from its' website at http://httpd.apache.org/download.cgi#apache22, and the version I’m using is 2.2.14 (either the one with or without ssl); try avoid using 1.x or 3.x which either doesn’t work well or hasn’t been tried by many people. So apache 2.2 is the best pick for now;
    • Install Apache http server by following the wizards;
    • Change the Apache HTTP Server listening port if necessary in conf.
    • After installation, just test it by launching http://localhost:port/ in browser and you should see a “It works!” page; (you can also monitor the apache http service in Apache Service Monitor)
3. Install Subversion
    • Download the latest version of the Subversion Win32 binaries for Apache. Be sure to get the right version to integrate with your version of Apache, otherwise you will get an obscure error message when you try to restart. If you have Apache 2.2.x go to http://subversion.tigris.org/servlets/ProjectDocumentList?folderID=8100;
    • !!!DON'T!!! use the msi version of subversion (it doesn't work somehow), instead use the zip version; (after unzip the subversion folder to your local disk, you also need to add the bin path to 'path' system environment variable)
    • Using the windows explorer, go to the installation directory of Subversion and find the files /httpd/mod_dav_svn.so and mod_authz_svn.so. Copy these files to the Apache modules directory;
    • Copy the file /bin/libdb*.dll and /bin/intl3_svn.dll from the Subversion installation directory to the Apache bin directory;
4. Configure Subversion and Apache HTTP Server
Edit Apache's configuration file (usually C:\Program Files\Apache Group\Apache2\conf\httpd.conf) with a text editor such as Notepad and make the following changes:
Uncomment (remove the '#' mark) the following lines:
    #LoadModule dav_fs_module modules/mod_dav_fs.so
    #LoadModule dav_module modules/mod_dav.so
Add the following two lines to the end of the LoadModule section.
        LoadModule dav_svn_module modules/mod_dav_svn.so
    LoadModule authz_svn_module modules/mod_authz_svn.so
b. At the end of the config file add the following lines:
    <Location /svn>
         DAV svn
         SVNListParentPath on
         SVNParentPath D:\SVN
         #SVNIndexXSLT "/svnindex.xsl"
         AuthType Basic
         AuthName "Subversion repositories"
         AuthUserFile passwd
         #AuthzSVNAccessFile svnaccessfile
         Require valid-user
     </Location>

c. This configures Apache so that all your Subversion repositories are physically located below D:\SVN. The repositories are served to the outside world from the URL: http://MyServer/svn/ . Access is restricted to known users/passwords listed in the passwd file.

d. To create the passwd file, open the command prompt (DOS-Box) again, change to the apache2 folder (usually c:\program files\apache group\apache2) and create the file by entering

           bin\htpasswd -c passwd <username>

This will create a file with the name passwd which is used for authentication. Additional users can be added with

          bin\htpasswd passwd <username>

e. Restart the Apache service again;

f. Point your browser to http://MyServer/svn/MyNewRepository (where MyNewRepository is the name of the Subversion repository you created before). If all went well you should be prompted for a username and password, then you can see the contents of your repository.
5. Create SVN repository and access it through HTTP
    • Create a folder on your local disk (under the folder where you specify in Apache http server to be the root folder of your SVN);
    • Right click on the folder and use the TortoiseSVN context menu “Create Repository Here”;
    • Access your SVN repository through HTTP as http://server:port/svn/repositoryName/ (you need to type in username and password).

Wednesday, February 3, 2010

Google Latitude finally locates me

I joined Google Latitude more than half year ago but no matter whether I’m at home (Rancho Cucamonga, CA) or at my office (Redlands, CA), it always tells me that I’m in Hague Netherlands, which I assume is what my friends will see too. Recently it finally corrects the location to Rancho Cucamonga or Redlands. Since I am not using Google Latitude on my mobile device, the only way Google Latitude can rely on should be the IP address and associated ISP. Just wonder why there could be such a big mistake.

Friday, January 22, 2010

First experience of armchair mapping using Mapzen and JSOM WMS plug-in

In previous post I shared my first experience of making changes to OSM database with Potlatch and JOSM. As I mentioned there both of them are good tools but neither is perfect so I’m still looking for some alternatives.

Mapzen caught my eye recently probably because it becomes quite a popular buzz word in blogs and news feedings so I decided to give it a try. At first glance, Mapzen looks quite similar to Potlatch (CloudMade who hosts Mapzen is founded by the same person who started OSM):

1. It requires an account (you can register it for free) to work with;

2. A peek at source of Mapzen front page shows it’s based on Flex too;

3. It uses OSM map as base layer in view mode;

4. It uses Yahoo Imagery as based layer in edit mode; (by the way, Yahoo Aerial Imagery is probably the only imagery available for free which has decent globe coverage. I never see other options, do you?)

Mapzen in view mode:

1

Mapzen in edit mode:

2

I like the way it categorize those pre-defined features in Points, Lines and Shapes and each one of the feature types has a meaningful icon associated. Of course it lacks some of the advanced editing functionalities that are available in Potlatch (it seems to have a tool to line up points) and JOSM, but it has more than enough for majority of the users. Another thing I like Mapzen over Potlatch is the look and feel when you draw the geometry on map. With Potlatch I always feel like using a big brush for wall painting, where all I actually need is pencil for sketch. The only weakness though is that I didn’t find a way to upload data as input for my editing, either through an osm file or a gpx track while Potlatch provides that option. Everything must be hand drawn. But anyway you can always combine the power of both.

After editing simply click “Save Map” button at corner (you might want to input some notes for this particular editing). The picture above shows the hand-draw building and foot way of my house using Mapzen, as well as a BBQ island garden “August Town” (named after my boy).

JOSM with its WMS plugin (with the Yahoo Aerial Imagery extension) is another option I tried after Mapzen, which I probably rank the highest among all three of them (Potlatch, Mapzen and JOSM). Like I mentioned before, the lack of a decent base imagery is a huge bottleneck which makes it almost impossible for armchair mapping, but the WMS plug-in with Yahoo Aerial Imagery extension overcomes it like magic. So let’s equip with it first by following the instructions here. A brief list of steps:

Install WMS plugin itself:

With the plugin manager

You can easily install plugins from within JOSM as follows

  1. Start JOSM, open the preferences window (Edit->Preferences or use the toolbar icon) and select the plugins tab.
  2. Click on "Download List" to download the list of available plugins.
  3. Check the plugins you want installed.
  4. Click the accept button. All new plugins should start downloading and installing.
  5. Restart JOSM.
Manually

With older versions (up until 277), you have to install the plugins manually.

  1. Download the plugin file from wherever the plugin is hosted. Look in the plugin page or the 'Plugins' page on the JOSM wiki site for the location of this file.
  2. The file should have an ".jar" extension. If it doesn't, rename the downloaded file so that it ends with ".jar". Internet Explorer, for instance, may rename some files to ".zip".
  3. Move the .jar file to the JOSM preferences directory ("%APPDATA%/JOSM" in windows, "~/.josm/plugins/" in Unix/MacOS.)
  4. Start JOSM, open the preferences window (Edit->Preferences) and select the plugins tab.
  5. Activate the plugin in the plugins tab.
  6. Restart JOSM.

Install Yahoo! Aerial Imagery Downloader

On Windows use the WebKit based downloader called webkit-image as follows

  • Download webkit-image.zip
  • Unzip it.
  • Move the contents so that the DLL files and the EXE file are somewhere "on your system path" (eg. c:\windows ). The best way to achieve this might be to place them alongside josm-latest.jar Keep the 'imageformats' subfolder alongside too (so all the contents of the zip).
  • Restart JOSM
  • Do 'WMS' menu -> YAHOO (Webkit)

You should start to get Yahoo! imagery (may take up to 30 seconds to start showing). If not, it may not be finding the DLL files correctly.

Note: If you don't want to place webkit-image in your system path or the JOSM directory you don't have to. By editing the download program you can specify an absolute or relative path to the webkit-image executable. Examples:

  • webkit/webkit-image {0} - loads webkit-image.exe from the subdirectory webkit relative to the JOSM installation directory
  • D:/webkit/webkit-image {0} - uses webkit-image D:\webkit\webkit-image.exe

After a successful install, restart JOSM and you should a new menu called “WMS” like below:

3

Now download your data from OSM database as usual first, and after select the “WMS” menu and select “Yahoo Sat”. Wait for about 5, 6 seconds you will see a nice aerial imagery base layer underneath your OSM data.

4

Well done! And this is perfect for armchair mapping. Now enjoy your smooth mapping experience with powerful tools in JOSM. I didn’t try out the WMS layer and rectified image yet which can definitely be better base layer options for specific area.

After the editing simply click upload button (right next to download button) and upload the changes. (you may need to set your OSM account username and password)

6

5

So my conclusion is that JOSM with WMS plugin is an obvious winner due to the smooth and rich desktop UI experience if you’re doing armchair mapping at home. But Potlatch and Mapzen have their own advantages of being browser based and easy to use for non-professional users.

Wednesday, January 20, 2010

Install Apache HTTP Server + PHP5 on Windows 7 (64bit)

Recent installation of dokuwiki (a simple web-based wiki engine) requires a combination of Apache HTTP Server + PHP5 on my 64-bit Windows 7 machine, but setup process didn’t seem to be as simple as “following the wizards”. So I decide to jot a few lines down such that I don’t have to search on the web again when I need to repeat the installation.

1. Install Apache HTTP Server; (just go to the official site and pick up .msi, and install in default path C:\Program Files(x86)\Apache Software Foundation\ seems to be ok)
2. Install PHP5;

This worth a short paragraph. My understanding of the install steps on PHP website is that it should be automatically taken care of by the installation wizards if it is for a popular http server like apache, and the install wizard UI does indicate that too. But unfortunately I didn’t get it to work in which I either got an general error message or no error message but just not working. So I switch to the zip version of PHP5 which is suggested by some article online and following the steps below makes it work properly:
2.1 Unzip the the zip version of PHP5 to your local disk; (unzip it to C:\Program Files(x86)\PHP5 seems to be working too)
2.2 Open httpd.conf file of Apache HTTP server in a text editor;
2.3 At the end of the http.conf file add following lines to make Apache HTTP Server be aware of PHP5; (adjust you path accordingly)
1: # Begin enable php5
2: LoadModule php5_module "C:/Program Files (x86)/PHP5/php5apache2_2.dll"
3: AddType application/x-httpd-php .php
4: PHPIniDir "C:/Program Files (x86)/PHP5"
5: # End enable php5
2.4 Save the change and restart Apache HTTP Server, and if successful you should see
“Apache/2.2.14(Win32) PHP/5.3.1” in the status bar of Apache Service Monitor.
Now your Apache HTTP Server should be able to display php content, at least my php based dokuwiki is running perfect.