Thursday, March 12, 2009

Simple example of defining parsing rules for geocoding in GeoMedia

Part of the workflow to setup GeoMedia geocoding functions to work is to define parsing rules to handle address conventions in your specific locality. Basically, the rules define how to break up an address string sequence into smaller parts - so-called tokens in GeoMedia geocoding terminology. For example, the string '123 James Street' can be parsed into the tokens house number '123', road name 'James' and road type 'Street'. 

As you can imagine, in real life the rules can be very complex in order to handle actual addresses. To aid in the rules definition process, GeoMedia comes with a hidden executable DefParsingRules.exe in the {GeoMedia product}\Program folder. The utility will save the rules as XML files that will be be used by GeoMedia's Publish Address Geocoding Index Utility to create the address geocoding index files (*.agi) . 

In this posting, I will show you how to use the Define Parsing Rules Utility to handle a simple example - 6 digits postal code strings. We will define a rule to output one 'postal code' token from input text strings. Perhaps in future I can post a more complex example. 
  1. Run the Define Parsing Rules Utility by double clicking the DefParsingRules.exe in the GeoMedia's program folder.

    The Define Parsing Rules Utility dialog box appears


  2. Click the Add button to add a new token.

    The Token dialog box appears.


  3. In the Name field, type in a token name e.g. POSTALCODE. In the Type drop down list, select Pattern.

    Note: the postal codes are all digits and a simple regular expression pattern would be more than sufficient to detect the postal code from the input text strings

    At this point, the Token dialog box may look like this.


  4.  Click the Pattern tab. In the Regular expression to match field, enter \d{6}

    Note: the \d{6} pattern will consider strings with 6 digits as postal codes

    The Token dialog box may look like this now



  5. Click OK to close the Token dialog box.

    The new token is created and added to the Tokens list.


  6. Click the Training Data tab.

    Note: you have to add in training data to 'train' the parser to detect the postal code strings



  7. Click the Add button 

    The Training Sample dialog box appears.

  8. In the Sample text field, type in a representative postal code string e.g. 123456. Click Parse

    The Training Sample dialog box should like this.

  9. If the Parsed token sequence list is still empty, then you can aid the training process by double clicking POSTALCODE in the Available tokens list. Click Parse again. 

    The sample text is parsed and added to the Parsed token sequence list.


  10. Click Replace Training Sequence.

    The Training Sample dialog box should look like this



  11. Click OK to close the Training Sample dialog box.

    Note: if the training is successful, the bottom right of the Define Parsing Rules Utility dialog box should show a neon green box with the Valid text

  12. In the Define Parsing Rules Utility dialog box, click the Output tab. 

  13. Click the Add button 

    The Output Entity dialog box appears.

    Note: You have to define how you want to format the result tokens of the parsing. If you have multiple tokens, you can choose to have space, comma, or semi-colon separators. This dialog box is where it happens

  14. Toggle on POSTALCODE in the At least one of the checked tokens must be present in this entity list. 

  15. Click the Output Elements tab.


  16. Click the Add button 

    The Output Element dialog box appears.

  17. Double click on POSTALCODE in the Available tokens list. Click OK.

    The Output Element dialog box should look like this.

  18. Click OK to close the Output Element dialog box.

    The element is added to the Output Entity list.

  19. Click OK to close the Output Entity dialog box.

    The Entity is added to the Output list.

  20. Click the Testing Data tab.


  21. You can now choose to test the rule against strings in text files, a database table, or a GeoMedia warehouse. In this example, we are going to test against a standard text file which has the contents shown below. As you can see, I have a few strings that satisfy the rule and some that don't. 


    In the File field, click Browse and select the text file.


  22. Click Run.

    Note: The rule is applied against the selected text file and 2 entries appear in the Token sequences list - Unparsed and POSTALCODE as shown below.


    When Unparsed is selected, the Strings yielding the sequence list shows the unmatched strings from the test file such as 123, ABCDEF, 1234567. 

    When POSTALCODE is selected, the Strings yielding the sequence list shows the matched strings from the test file, all having 6 digits. 

  23. Select File > Save As and save the parsing rules into an XML file. 
You have now created a parsing rule XML file which can be used later in the GeoMedia Publish to Address Index Utility

Tuesday, March 3, 2009

Export KML to DXF with GeoMedia

GeoMedia 6.1 can read and display KML files. Once you are able to connect to the KML warehouse, you can use any GeoMedia command to manipulate the KML features. The Output to Feature Class and Export Warehouse commands are also available for you to convert KML features into other formats such as Access, Shape files, DGN, DWG, etc. However, I encountered some difficulty in exporting KML features to DXF. If you tried to run the Export to DXF command as shown below, you will encounter this "Exporting query on image feature class not supported" error message.


This posting describes a method that I used to manipulate the data to enable GeoMedia to export the KML features to DXF successfully. The issue is that the KML format supports embedded raster images while the Export to DXF command is not able to handle raster geometries. So the workaround is to import the KML features into an Access warehouse first, delete the raster geometry database field, update the metadata, then export the KML features in Access to DXF. Details are below.

Import KML features into Access 
  1. In GeoMedia, select Warehouse | New Connection.

    The New Connection dialog box appears.


  2. In the Connection type list box, select KML.



  3. In the KML file field, click Browse and select a KML file. You can leave the Warehouse configuration file field blank.

  4. Click OK.

    GeoMedia is now connected to the KML file.

  5. Select Warehouse | Output to Feature Classes.

    The Output to Feature Classes dialog box appears.

  6. In the Source features to output box, toggle on the KML feature. In the Target connection drop down list, select a read/write Access warehouse connection. Note: If you don't have one, then connect to one or create a new Access Warehouse first.

    The Output to Feature Classes dialog box may look this.


  7. Click the Advanced tab.

  8. In the Target Feature Class field, type in a new name e.g. google if you do not like the default name.

    The Output to Feature Classes dialog box may look like this.


  9. Click OK and Yes when prompted.


    The KML features are imported into the target Access warehouse. Notice that the KML feature has 3 geometry types - text, raster and compound.


  10. Exit GeoMedia.
Delete the KML feature's Raster geometry field
  1. In Microsoft Access, select File | Open.

    The Open dialog box appears.

  2. In the File name field, type in the name of the Access warehouse file and click Open.

    The selected database is opened in Microsoft Access.

  3. In Microsoft Access, select the KML table name imported from the KML file previously, e.g. google.

  4. Click Design.

    The Table form is displayed.

  5. Click the gray box on the left of the RasterGeometry field name.

    The RasterGeometry row is highlighted.


  6. On the keyboard, press Delete. Click Yes when prompted.

    The RasterGeometry field is removed from the form.


  7. Close the table form and click Yes when prompted.

    The RasterGeometry field is deleted from the table.

  8. Exit Microsoft Access
Update the Access Warehouse Metadata
  1. On the Windows desktop, select Start | All Programs | GeoMedia | Utilities | Database Utilities.

    The Database Connection dialog box appears.

  2. In the Access database name field, click Browse and select the Access warehouse file.

    The Database Connection dialog box may look like this.


  3. Click OK.

    The Database Utilities dialog box appears.


  4. Click Delete Feature Class Metadata.

    The Delete Feature Class Metadata dialog box appears.


  5. In the Feature classes list box, select the KML feature e.g. google. Click OK.

    The metadata for the KML feature is removed.

  6. In the Database Utilities dialog box, click Insert Feature Class metadata.

    The Insert Feature Class Metadata dialog box appears.

  7. In the Available tables/views list box, select the KML feature. Click the '>' button.

    The Insert Feature Class Metadata dialog box may look like this.


  8. Click OK.

    The Select Coordinate System dialog box appears.


  9. Click Assign and close the dialog box.

    The KML feature metadata is regenerated and added back this time without the metadata for the rasterGeometry field.

  10. Close the Database Utilities dialog box.

Export to DXF
Now you can perform the export to DXF successfully.
  1. In GeoMedia, open up the connection to the Access warehouse again.

  2. Select Warehouse | Export to | AutoCAD.

    The Export to AutoCAD dialog box appears.


  3. In the Features to export field, select the KML feature. Change any other settings if you wish.

    The dialog box may look like this.


  4. Click Apply.

    The KML feature is exported to DXF

Thursday, February 26, 2009

Creating and using GeoMedia WebMap Geocoding with the sample dataset

GeoMedia WebMap 6.1 can be used to create and provide geocoding web services. Here are the steps to create the geocoding web service.
  1. On the Windows desktop, select Start > All Programs > GeoMedia WebMap > Publisher > Server Configuration Utility.

    The Publisher Server Configuratin Utility dialog box appears.

  2. Click Add.

    The GeoMedia WebMap Publisher Application And Service Wizard appears.

  3. In the drop down list, select Location Utility Web Service.

    The GeoMedia WebMap Publisher Application And Service Wizard should like the screen below.

  4. Click Next.

    The New Location Utility Web Service Wizard appears.

  5.  If you want to use the sample data in the new web service, then toggle on Include demo data in the web service.

    The New Location Utility Web Service Wizard may look like the screen below.


  6. Click Next five times to complete the wizard. If you want to change the default Location, website and virtual directory alias name, then please do so when prompted.

    The new web service is created.

    If you choose to use the sample dataset, then the following address geocoding index files would be copied over to the default WebMap Publisher Project folder as shown below.

Once the Location Utility Web Service has been created, you can write a web page or a Windows application to connect to and perform geocoding requests to the web service. An example Windows Console program is shown below. All the program does is to submit the address string: "1818 Lake Avenue, Knoxville, 37916" to the web service and prints out the results of the geocoding matches from the web service. 


The c# code snippet for this simple example is shown below.

//Get a pointer to the geocoding web service
localhost.WSILocationUtility theWebSvc = new localhost.WSILocationUtility();
theWebSvc.Url = "http://localhost/locationutilityservice/locate.asmx";

//Get information about the address geocoding datasets. 
//There are 2 sets in the sample dataset.
localhost.LocationUtilityDatasetInfo[] dsInfo = theWebSvc.GetAllDatasetInfo();

//Form the street address to submit to the geocoding web service
localhost.StreetAddress streetAddr = new localhost.StreetAddress();
streetAddr.Street = "1818 Lake Avenue";
streetAddr.Municipality = "Knoxville";
streetAddr.PostalCode = "37916";

//Just print out some informative messages
Console.WriteLine ("Street to geocode is '" + streetAddr.Street + "'");
Console.WriteLine("Municipality to geocode is '" + streetAddr.Municipality + "'");
Console.WriteLine("Postal code to geocode is '" + streetAddr.PostalCode + "'");

//Add the street address to an array of addresses. 
//We can submit more than one address to the web service. 
localhost.Address[] addresses;
addresses = new localhost.Address[1];
addresses[0] = streetAddr;

//Set the parameters to control the geocoding matching
localhost.GeocodeSpec spec = new localhost.GeocodeSpec();
// We want to query the 2nd dataset which is TN or Tennessee";
spec.DatasetName = dsInfo[1].Name; 
spec.MaxResultCount = 5;
spec.MinimumCandidateScore = 80;
spec.ReturnMatchedAddress = true;
spec.ReturnPointGeometry = true;            

localhost.GeocodeResult[] geocodeResults;

try
{
//Submit the addresses to the geocoding web service
   geocodeResults = theWebSvc.Geocode(spec, addresses);
   Console.WriteLine("Found " + geocodeResults.Length.ToString() + " match(es).");
//If there are any matches...
   if (geocodeResults.Length > 0)
   {
      for (int i = 0; i < geocodeResults.Length; i++)
      {
         localhost.GeocodeResult result = geocodeResults[i];
         localhost.GeocodedAddress[] resultAddrs = result.GeocodedAddresses;

//For each geocoded result...
         for (int j = 0; j < resultAddrs.Length; j++)
         {
            localhost.GeocodedAddress resultAddr = resultAddrs[j];
            localhost.Address matchAddr = resultAddr.MatchedAddress;
            localhost.StreetAddress matchStAddr = (localhost.StreetAddress) matchAddr;                    
            localhost.Address standardAddr = resultAddr.StandardizedAddress;

//Get the geocoded point location
            localhost.PointPropertyType pntPropTyp = resultAddr.PointGeometry;
            string matchStats = resultAddr.MatchStatus;
            Console.WriteLine("Matching status message is '" + matchStats + "'");
            Console.WriteLine("Matched street address is '" + matchStAddr.Street + "'");
            Console.WriteLine("Geocoded point location is " + pntPropTyp.Point.coordinates.Value);
         }
      }
   }
}
catch (Exception ex)
   {
       Console.WriteLine(ex.Message);
       Console.WriteLine(ex.StackTrace);
   }

Tuesday, February 10, 2009

Javascript code to read GeoMedia WebMap 6.1 generated tiles

In my previous post, I talk about using GeoMedia WebMap 6.1 to pre-generate map tiles in png format for use in Google Maps. After you have created all the png map tiles, it will no longer be necessary to start up the GeoMedia WebMap service to serve the png map tiles to the Internet browser clients. All you need to do is to write your own web page and Javascript code to wrap the png map tiles into a custom Google Maps tile layer.
Assuming you have created the png map tiles in the following folder C:\WebMap Publisher Projects\mygooglemaps\tilecache\ and the files are all named in the following naming convention mygooglemaps_1_(zoom)_(x)_(y).png, as shown in the figure above, we can write the following Javascript code. 


//If the tiles I have created have zoom levels ranging from 10 to 18 and the 
//geographical area ranges from 103 deg E to 104 deg E and 
//1 deg N to 2 deg N, then I can code in the constants as follows. 



var minZoom = 10;
var maxZoom = 18;
var minLng = 103;
var maxLng = 104;
var minLat = 1;
var maxLat = 2 ;

var copyright;
var copyrights;
var tileLayer;
var tileLayers;
var custommap;

//Get a pointer to the Google Maps canvas area on the web page.
//The id is "map" in this example.
map = new GMap(document.getElementById("map"));

//Display the large zoom slider control
map.addControl(new GLargeMapControl());

//Create a new copyright within the data's geographical extents
copyright = new GCopyright ( 1, 
new GLatLngBounds ( new GLatLng(minLng, minLat),new GLatLng(maxLng, maxLat)), 
minZoom, 
'Copyright 2009 dominoc');
copyrights = new GCopyrightCollection('dominoc Copyrights');
copyrights.addCopyright ( copyright);

//Create a new map tile layer that has the zoom levels of the png 
//map tiles and copyrights
tileLayers = [ new GTileLayer (copyrights, minZoom, maxZoom)];

//Define the callback function for retrieving the png map tiles
tileLayers[0].getTileUrl = function ( tile, zoom) {
var url =  "http://localhost/mygooglemaps/tilecache/mygooglemaps_1" + "_" + zoom + "_" + tile.x + "_" + tile.y + ".png";
return url;
};
tileLayers[0].isPng = function() { return true; }
tileLayers[0].getOpacity = function() { return 1.0; }
tileLayers[0].minResolution = function() { return minZoom; }
tileLayers[0].maxResolution = function() { return maxZoom; }
//Finally, create the new map type for the map tiles with
//the button named "dominoc" and display it.
//Display the message "No data available" where there are no
//tiles.
custommap = new GMapType ( tileLayers, new GMercatorProjection(maxZoom + 1), "dominoc", {errorMessage: "No data available"});
map.addMapType(custommap);
map.addControl(new GMapTypeControl());


A sample display of the result in shown in the screen shot below. 

Monday, February 2, 2009

Generate Google Maps tiles with GeoMedia WebMap 6.1

You can use GeoMedia WebMap 6.1 to create Google Maps mashups map tiles with data from GeoMedia warehouses. The WebMap Publisher commands that come out of the box allow you to quickly publish a mashup site, all through easy to use graphical wizards. Although GeoMedia WebMap can dynamically generate the map tiles as users browse the mashup, it can be really slow for users, instead of the couple of seconds wait that they are accustomed to on the public Google Maps site. To improve the performance of the mashup site, there are a couple of things you can do: (a) pre-create the map tiles before hand and (b) group the legend entries. If you don't group the legend entries, each legend entry will have its own set of map tiles; so by grouping the legend entries into a single group, only a single set of map tiles will be generated per zoom scale.

GeoMedia WebMap version 6.1 has a couple of bugs which will give you with some grief. One of them is that the Publisher graphical commands are unable to group the legend entries eventhough there is an option for it on the graphical user interface. The other is that the batch tile generation script has some syntax errors. I have gone through that frustration and will be able to share the steps to actually generate the map tiles successfully in batch and as a group. The steps can be broken down into 3 major tasks: (a) Create a blank Publisher Web Application site, (b) Publish a GeoMedia Workspace to the Web Application, and (c) Generate the map tiles in batch.

Create a blank Publisher Web Application
  1. On the Windows desktop, select Start > All Programs > GeoMedia WebMap > Publisher > Server Configuration Utility.

    The Publisher Server Configuration Utility dialog box appears.

  2. Click Add.

    The GeoMedia WebMap Publisher Application And Service Wizard appears.

  3. Click Next.

    The New Web Application and Service Wizard appears.

  4. Click Next and in the Name field type in a name, e.g. mygooglemaps


  5. Click Next in the following screens until the wizard is completed.










  6. Click Next.

    The new web site is created.
Publish a GeoMedia Workspace
  1. In GeoMedia, open up a workspace with your warehouses connected and features displayed in the map window.


  2. In the Legend, click the Groups tab.


  3. In the Legend, right click on the white space.

    A context menu appears.

  4. Select New Group. Name the group as Group1 if you like. Drag and drop the legend entries onto the group so that they appear underneath the group node, as shown below.


  5. Click the GeoMedia WebMap Publisher Administrator button.

    The Open Application dialog box appears.

  6. In the Open Application dialog box, select a Publisher Web Application, e.g. mygooglemaps.
  7. Click Open.

    The GeoMedia WebMap Publisher Administrator dockable toolbar appears.

  8. Click the Map Content button.

    The Map Content dialog box appears.

  9. Click the Themes node.


  10. Click Add Theme.


  11. In the tree field, right click on the Theme1 node.


  12. Select Add Map.


  13. Click Get from active map window.


  14. Expand the Map1 node.


  15. Click on the Legend node.


  16. Click Synchronize Legend.


  17. Expand the Legend node and click the Group1 node. Toggle on Publish this group as a single layer in mashups.

    Note: in version 6.1, this option does not work properly. Each legend entry will be pulished as a single map tile layer per zoom scale on the mashup web site eventhough the group option is on.


  18. Click OK.
  19. In the GeoMedia WebMap Publisher Administrator toolbar, click the Settings button.

    The Settings dialog box appears.

  20. Click the Map tab.


  21. In the Map format field, select PNG.
  22. In the Viewer type field, select Browser (GM Mashups).


  23. Click OK.
  24. In the GeoMedia WebMap Publisher Administrator toolbox, click Publish and Populate the GeoWorkspace button and select Publish the GeoWorkspace Contents to the Metadata.

    The contents are published to the web site.
  25. Close GeoMedia if you like.
Generate the Map Tiles in Batch
  1. In Windows Explorer, browse to the GeoMedia WebMap folder containing the batch tile generation files tilegen.bat and tilegen.vbs (in C:\Program Files\GeoMedia WebMap\Publisher\TileGen\) as shown below.


  2. Copy the TileGen folder to your mashup web site folder C:\WebMap Publisher Projects\mygooglemaps\ as shown below.


  3. Using your favorite text editor, create the file tilegen.xml and placed in the folder containing the batch tilegen files e.g. C:\WebMap Publisher Projects\mygooglemaps\TileGen\.

    Note: An example of the contents of the tilegen.xml file is as follows:



    <?xml version="1.0" encoding="utf-8" ?>
    <tilegen appname="wpgm"
    minzoom="1"
    maxzoom="4"
    xmin="-180"
    xmax="180"
    ymin="85.0511287798066"
    ymax="-85.0511287798066"
    autorange="no"
    overwrite="no">
    <le>1</le>
    <le>2</le>
    </tilegen>


    However, the ymin and ymax attributes do not work properly because of a coding error in the tilegen.vbs script. You can modify the tilegen.vbs file to correct the error if you like if you want to use the range to limit the map tiles generation.
  4. I prefer to use the following as the tilegen.xml file. Replace appname="mygooglemaps" with the name of your Publisher Web Application. You can define the min and max zoom levels of map tiles to generate (the levels range from 1 to 17, I think). I set autorange to "yes" to let GeoMedia WebMap automatically determine the range of the map tiles to generate.


    <?xml version="1.0" encoding="utf-8" ?>
    <tilegen appname="mygooglemaps"
    minzoom="1"
    maxzoom="4"
    autorange="yes"
    overwrite="no">
    </tilegen>


  5. Open up a command prompt and change the directory to the location of my tilegen files. Type in the following:

    C:\> tilegen tilegen.vbs


  6. At the end of the process, you can browse the tilecache folder to see the generated map tiles as shown below.