Page 1 of 1

Geocoding application Geocode address and preview result in Google Maps

#1 FlashM  Icon User is offline

  • D.I.C Lover
  • member icon

Reputation: 382
  • View blog
  • Posts: 1,195
  • Joined: 03-December 09

Post icon  Posted 29 December 2009 - 03:55 PM

Since I'm a GIS software developer, I though I should contribute some GIS tutorial to DIC community. This tutorial is going to show how to make a simple but yet powerful geocoding application. This tutorial requires you to register for Yahoo Developer Account (this is totally free). By registering you get your own API Key which is used to make geocoding API calls to their geocoding service http://developer.yahoo.com/

Geocoding is process when user provides some geo data (eg: street name, house number, postal code, city name, state name, etc...). This data can sometimes be incomplete or even some pieces of data misspelled. Geocoder on the other hand is usually some service that implements mechanisms to parse this input data, corrects misspelled words (not allways) and finally returns user correct address and the most important - Latitude and Longitude information. This latitude/longitude coordinate represents a coordinate on the planet Earth where this particular address is located.

You all know devices like Garmin, TomTom etc, which is used to help you find the way. And those devices use some sort of geocoder, that converts your input data into coordinate, calculates the neares or most economic way and takes you right on the spot. Actually there is much more to that on how this calculations are made, but for the sake of simplicity, let's leave that for now :-)

There is maybe one more interesting thing to mention. Devices like Garmin, TomTom etc... don't exactly know where the building you are looking for is located. The database know only where the starting point and ending point of the street is, what is the starting house number and ending house number and it assumes that all houses are exactly the same measurements and equally spaced. But that is good enough to take you to location desired.

OK, enough of this theory, let's start building our app. Create a Windows Forms Application. On your form, add the following controls:

Attached Image

I named my controls as follows:
txtStreet
txtCity
txtState
btnGeocode
dgvAddresses



Now go to the code view and add the following using statement:
using System.Xml;
using System.Data;
using System.Globalization;



Now before the public partial class Form1 : Form add the struct that will be used to hold the geocoded address data:
public struct Address
{
	public string Street;
	public string City;
	public string State;
	public string Zip;
	public string Country;
	public double Latitude;
	public double Longitude;
}



Before the Form1 constructor add the following two global variables. Notice the NumberFormatInfo class. I used it to correctly convert the value of latitude and longitude from string to double.
private DataTable table = null;
private NumberFormatInfo format = null;



After that, create a private method named InitCustomComponents.
private void InitCustomComponents()
{
	//Initialize format provider
	format = new NumberFormatInfo();

	//Set the decimal separator (you might have to change
	//this to comma, since it depends on your local settings
	format.NumberDecimalSeparator = ".";

	//Initialize table for addresses and add the columns
	table = new DataTable();
	table.Columns.Add("Street", typeof(string));
	table.Columns.Add("City", typeof(string));
	table.Columns.Add("State", typeof(string));
	table.Columns.Add("Zip", typeof(string));
	table.Columns.Add("Country", typeof(string));
	table.Columns.Add("Latitude", typeof(double));
	table.Columns.Add("Longitude", typeof(double));
}



When you have done so, create an AddAddress method which is used to create and populate a row in table with data retrieved by geocoding service.
private void AddAddress(Address a)
{
	//Add a row with geocoded data to our table
	table.Rows.Add(a.Street, a.City, a.State, a.Zip, a.Country, a.Latitude, a.Longitude);
}



Now the most important part of application is the method GeocodeAddress which does all the work. It calls the geocoding service, passing it user inputs from textboxes. Geocoder then returns the XML schema object back to user and we need to parse this data using a simple XmlTextReader, iterating through all the lines in given XML.
private void GeocodeAddress(string street, string city, string state)
{
	//Create a new instance for holding geocoded data
	Address address = new Address();

	//Geocoder returns data in XML format so we need to
	//create a new instance of XMLTextReader and provide an url
	XmlTextReader reader = new XmlTextReader
		("http://local.yahooapis.com/MapsService/V1/geocode?appid=ENTER_YOUR_YAHOO_DEVELOPER_API_KEY_HERE&street=" + street + "&city=" + city + "&state=" + state);

	//Specify the way how white space is handled
	reader.WhitespaceHandling = WhitespaceHandling.Significant;

	//Start reading geocoded data
	while (reader.Read())
	{
		string node = reader.Name.ToString();  //current node in XML document
		string value = reader.ReadString();  //value/inner text of current XML node

		switch (node)
		{
			case "Address":
				address.Street = value;
				break;
			case "City":
				address.City = value;
				break;
			case "State":
				address.State = value;
				break;
			case "Zip":
				address.Zip = value;
				break;
			case "Country":
				address.Country = value;
				break;
			case "Latitude":
				address.Latitude = double.Parse(value, format);
				break;
			case "Longitude":
				address.Longitude = double.Parse(value, format);
				break;
			default:
				continue;
		}
	}

	//Add geocoded address to our table
	AddAddress(address);
}



Now there are only two things left to do. First is the button click event that at first clears all the data in Data Table that was left there from last geocoding request, that calls the GeocodeAddress method with new inputs and finally sets the data grid view DataSource property and tells it to use the data table with all the geocoded addresses for given address.
private void btnGeocode_Click(object sender, EventArgs e)
{
	//Clear the table
	table.Rows.Clear();

	//Call the GeocodeAddress method with values from text boxes
	GeocodeAddress(txtStreet.Text, txtCity.Text, txtState.Text);

	//Attach table with geocoded data to our Data Grid View as its data source
	dgvAddresses.DataSource = table;
}




Finally I implemented another method that is triggered when user double clicks on the row in data grid view. If the row with a geocoded address is clicked, this address and its location is opened in Google Maps using the default user's web browser.
private void dgvAddresses_CellMouseDoubleClick(object sender, DataGridViewCellMouseEventArgs e)
{
	//Verify that index of clicked row is not negative
	if (!e.RowIndex.Equals(-1))
	{
		//Extract the complete row that was clicked and its data
		DataGridViewRow row = dgvAddresses.Rows[e.RowIndex];

		//Verify that clicked row is not an empty row (usually the last row)
		if (!row.IsNewRow)
		{
			//Extract the latitude and longitude from the clicked row
			double lat = (double)dgvAddresses["Latitude", e.RowIndex].Value;
			double lng = (double)dgvAddresses["Longitude", e.RowIndex].Value;

			//Show the geocoded result in Google Maps using your default browser
			System.Diagnostics.Process.Start(string.Format("http://maps.google.com/maps?q={0},{1}", lat.ToString(format), lng.ToString(format)));
		}
	}
}




Final solution looks like this:
using System;
using System.Windows.Forms;
using System.Xml;
using System.Data;
using System.Globalization;

namespace GeocoderApp
{
	//Structure that will hold data from geocoded address
	public struct Address
	{
		public string Street;
		public string City;
		public string State;
		public string Zip;
		public string Country;
		public double Latitude;
		public double Longitude;
	}

	public partial class Form1 : Form
	{
		//Data table that will hold all the addresses returned by geocoder
		//Note that same street with same house number may exist within
		//the same city and same state
		private DataTable table = null;

		//Format provider is needed to correctly convert number as string
		//into double
		private NumberFormatInfo format = null;

		public Form1()
		{
			InitializeComponent();

			//Initialize our custom components
			InitCustomComponents();
		}

		private void InitCustomComponents()
		{
			//Initialize format provider
			format = new NumberFormatInfo();

			//Set the decimal separator (you might have to change
			//this to comma, since it depends on your local settings
			format.NumberDecimalSeparator = ".";

			//Initialize table for addresses and add the columns
			table = new DataTable();
			table.Columns.Add("Street", typeof(string));
			table.Columns.Add("City", typeof(string));
			table.Columns.Add("State", typeof(string));
			table.Columns.Add("Zip", typeof(string));
			table.Columns.Add("Country", typeof(string));
			table.Columns.Add("Latitude", typeof(double));
			table.Columns.Add("Longitude", typeof(double));
		}


		private void GeocodeAddress(string street, string city, string state)
		{
			//Create a new instance for holding geocoded data
			Address address = new Address();

			//Geocoder returns data in XML format so we need to
			//create a new instance of XMLTextReader and provide an url
			XmlTextReader reader = new XmlTextReader
				("http://local.yahooapis.com/MapsService/V1/geocode?appid=ENTER_YOUR_YAHOO_DEVELOPER_API_KEY_HERE&street=" + street + "&city=" + city + "&state=" + state);

			//Specify the way how white space is handled
			reader.WhitespaceHandling = WhitespaceHandling.Significant;

			//Start reading geocoded data
			while (reader.Read())
			{
				string node = reader.Name.ToString();  //current node in XML document
				string value = reader.ReadString();  //value/inner text of current XML node

				switch (node)
				{
					case "Address":
						address.Street = value;
						break;
					case "City":
						address.City = value;
						break;
					case "State":
						address.State = value;
						break;
					case "Zip":
						address.Zip = value;
						break;
					case "Country":
						address.Country = value;
						break;
					case "Latitude":
						address.Latitude = double.Parse(value, format);
						break;
					case "Longitude":
						address.Longitude = double.Parse(value, format);
						break;
					default:
						continue;
				}
			}

			//Add geocoded address to our table
			AddAddress(address);
		}

		private void AddAddress(Address a)
		{
			//Add a row with geocoded data to our table
			table.Rows.Add(a.Street, a.City, a.State, a.Zip, a.Country, a.Latitude, a.Longitude);
		}

		private void btnGeocode_Click(object sender, EventArgs e)
		{
			//Clear the table
			table.Rows.Clear();

			//Call the GeocodeAddress method with values from text boxes
			GeocodeAddress(txtStreet.Text, txtCity.Text, txtState.Text);

			//Attach table with geocoded data to our Data Grid View as its data source
			dgvAddresses.DataSource = table;
		}


		//Handle the mouse double click when user clicks on address in data grid view
		private void dgvAddresses_CellMouseDoubleClick(object sender, DataGridViewCellMouseEventArgs e)
		{
			//Verify that index of clicked row is not negative
			if (!e.RowIndex.Equals(-1))
			{
				//Extract the complete row that was clicked and its data
				DataGridViewRow row = dgvAddresses.Rows[e.RowIndex];

				//Verify that clicked row is not an empty row (usually the last row)
				if (!row.IsNewRow)
				{
					//Extract the latitude and longitude from the clicked row
					double lat = (double)dgvAddresses["Latitude", e.RowIndex].Value;
					double lng = (double)dgvAddresses["Longitude", e.RowIndex].Value;

					//Show the geocoded result in Google Maps using your default browser
					System.Diagnostics.Process.Start(string.Format("http://maps.google.com/maps?q={0},{1}", lat.ToString(format), lng.ToString(format)));
				}
			}
		}
	}
}




Final result of our work looks something very similar to this:
Attached Image


I hoped you enjoyed this tutorial. If you have any questions or need assistance, feel free to drop a comment.

Is This A Good Question/Topic? 3
  • +

Replies To: Geocoding application

#2 agent1  Icon User is offline

  • D.I.C Head
  • member icon

Reputation: 7
  • View blog
  • Posts: 73
  • Joined: 09-July 10

Posted 22 August 2010 - 07:31 AM

thank dude, i enjoyed doing this tutorial before, now im using it again to help me with an app im doing
Was This Post Helpful? 0
  • +
  • -

#3 FlashM  Icon User is offline

  • D.I.C Lover
  • member icon

Reputation: 382
  • View blog
  • Posts: 1,195
  • Joined: 03-December 09

Posted 25 August 2010 - 02:09 PM

great to hear that! :-) keep up the good work!
Was This Post Helpful? 0
  • +
  • -

#4 benjamin9x  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 1
  • Joined: 03-October 12

Posted 03 October 2012 - 09:21 AM

How to get number of request per second? and can you show me how to test status code result (ok, zezo_results, over_query_limit)
Help me.
Thanks.
Was This Post Helpful? 0
  • +
  • -

Page 1 of 1