Click or drag to resize

Drill-down Geocoder Tutorial

Verizon Connect Logo
Print this page
Learn more about Verizon Connect GeoBase.
Get information about the latest release
Introduction

A drill-down geocoder (see DrillDownGeoCoder) allows the user to perform a forward geocode by successively 'drilling down' through decreasingly smaller search regions. A drill-down geocoder can rapidly narrow a search to a street; this is often useful when a complete address is unknown. As an example, a customer's voice might be difficult to understand over the phone - using a drill-down geocoder, an intelligent guess can often be made when given the appropriate options.

The drill-down geocoder works by allowing the user to select successively smaller regions, 'drilling-down' towards a target street. To demonstrate this procedure, consider the following drill-down:

  • California
  • Orange
  • Aliso Viejo
  • Enterprise

At the conclusion of this search, Enterprise (in Aliso Viejo, Orange, California) will have been located. California, Orange and Aliso Viejo are all regions, whereas Enterprise is a street. California (a top-level region) is assigned a region level of zero. Each child region has a region level one higher than its parent region. For example, Aliso Viejo has a region level of 2.

In this tutorial we will create an application to find a street using the drill-down geocoder, and pin-point the street on a map using a BalloonPushPin. To find the street the user will first select a state, then a county, then a city, then the street name.

The code in this tutorial will request an array of regions in a given region level using the GetRegions(Int32) method. If the user selects a region from the list box, we will set that region in the drill-down geocoder using the SetRegion(RegionData) method. After all the regions have been set, we will perform a street search using the GetStreets method.

Form layout

Open Visual Studio and create a new Windows application called DrillDown Geocoder, and add a reference to geobase.net.dll.

Create the drill-down geocoder form as laid out below.

DDGC form layout
Control typeRoleName
ListBoxDisplay list of regions / addresses to choose fromlistBoxResults
ListBoxDisplay user's search / selection historylistBoxHistory
TextBoxEnter characters to searchtextBoxSearch
ButtonReset search, and clear list boxesbtnReset
MapCtrlView search results - map zooms in as search regions are setmapCtrl1
LabelInformative label. Set its text to Drill down geocoder results.
LabelInformative label. Set its text to Selection History.
LabelInformative label. Set its text to Search.
Code

In Form1.cs, add the directive 'using Telogis.GeoBase' to access the Telogis.GeoBase namespace, and then add the following member properties:

C#
//Drill-down geocoder
DrillDownGeoCoder ddgc;

//Balloon push pin to highlight search result
BalloonPushPin bpp = new BalloonPushPin(new LatLon(34,-118));

//Rendererlist for bpp
RendererList renderList = new RendererList();

//Keep track of which region level we're on
int regionLevel;

Edit the Form1 constructor as shown below:

C#
public Form1() {
    InitializeComponent();

    //Change the country if you're not in the USA
    ddgc = new DrillDownGeoCoder(Country.USA);

    //RegionLevel will be incremented as we drill-down towards street level
    regionLevel = 0;

    //Load top-level regions into our listbox
    Filter();

    //Draw the balloon push pin on the map
    renderList.Add(bpp);
    mapCtrl1.Renderer = renderList;
}

Add a Text Changed event to the textBoxSearch text box. Modify the Text Changed method to contain the following code.

C#
private void textBoxSearch_TextChanged(object sender, EventArgs e) {
    //Add search term to history
    AddHistory();
    Filter();
}

The AddHistory method is called to add the search term to the history listbox (listBoxHistory), while the Filter method will update the regions, and streets, displayed in the drill-down geocoder results' listbox (listBoxResults) when the user enters search text.

C#
private void AddHistory() {
    //Add search term to history
    if(textBoxSearch.Text.Length > 0) {
        listBoxHistory.Items.Add(textBoxSearch.Text);
    }
}

The following Filter method will use the contents of the textbox (the filter) to display regions at the selected region level. Regions will be displayed in the results' listbox. The method begins by checking if all the region levels have been set - if they have, then a list of streets is displayed based on the current filter. If all the region levels have not been set, then the child regions of the parent region are displayed in the results' (listBoxResults) listbox.

C#
private void Filter() {
    string filterText = textBoxSearch.Text;

    //If all regions have been set, search for a street
    if (regionLevel >= ddgc.NumRegionLevels) {
        listBoxResults.Items.Clear();

        if (filterText.Length == 0) {
            filterText = "a";
        }

        //Get an array of streets
        StreetData[] sd = ddgc.GetStreets(filterText).Results;

        //Add the filtered streets to the listbox
        for (int i = 0; i < sd.Length; i++) {
            listBoxResults.Items.Add(sd[i].ToString());
        }
    }

    //...otherwise, set remaining region levels
    else if (regionLevel < ddgc.NumRegionLevels) {

        listBoxResults.Items.Clear();

        //Get an array of filtered regions
        RegionData[] rd;

        if (filterText.Length > 0) {
            rd = ddgc.GetRegions(regionLevel, filterText).Results;
        } else {
            rd = ddgc.GetRegions(regionLevel).Results;
        }

        //Add the filtered regions to the listbox
        for (int i = 0; i < rd.Length; i++) {
            listBoxResults.Items.Add(rd[i].ToString());
        }
    }
}

Add a Selected Index Changed event to the listBoxResults listbox to respond to the user selecting a region, or street.

The method begins by testing to see if we're at street or region level. If we are at region level, then the region level is set (using SetRegion), and incremented (regionLevel++;). The map then centers and zooms on the selected region.

If we're at street level, then we get the streets available based on the filter (search) text: StreetData[] sd = ddgc.GetStreets(filterText).Results;, and then center and zoom the map to the selected location. Finally, we add a balloon push pin at the selected address.

Modify the event to match the following:

C#
private void listBoxResults_SelectedIndexChanged(object sender, EventArgs e) {

    if (listBoxResults.SelectedItem != null) {

        //Are we at region level or street level?
        if (regionLevel < ddgc.NumRegionLevels) {

            //At region level. Set the selected region
            RegionData rd = ddgc.GetRegions(
                        regionLevel,
                        listBoxResults.SelectedItem.ToString()).Results[0];

            ddgc.SetRegion(rd);

            //Add to history
            listBoxHistory.Items.Add(listBoxResults.SelectedItem.ToString());

            //Update region level
            regionLevel++;
            textBoxSearch.Text = "";

            //Center and zoom the map on the selected region.
            //As we drill down, the map will zoom closer and closer.
            mapCtrl1.Center = rd.Location;
            int zoom = 4 * (ddgc.NumRegionLevels - regionLevel);
            mapCtrl1.Zoom = 1 + zoom; // = 1 at street level

            Filter(); // Filter on the next region level

        } else {
            //Must be at street level        
            //Show the location on the map

            string filterText;
            string address = listBoxResults.SelectedItem.ToString();

            //Add result to history
            AddHistory();

            //Set search term
            filterText = textBoxSearch.Text;

            StreetData[] sd = ddgc.GetStreets(filterText).Results;

            //Set latlon based on chosen listbox item
            LatLon ll = sd[listBoxResults.SelectedIndex].GetLocation();
            mapCtrl1.Center = ll;
            mapCtrl1.Zoom = 0.8;

            //Put a balloon at the address
            bpp.Name = "Drill-Down Search Result";
            bpp.Information = address;
            bpp.Location = ll;
        }
    }
}

Finally, add a Click event to the btnReset button. Modify the Click event method to contain the following code.

private void btnReset_Click(object sender, EventArgs e)
    {      
        // Clear searchbox and history           
        textBoxSearch.Clear();            
        listBoxHistory.Items.Clear();            

        // reset DDGC and repopulate listbox with states            
        ddgc.Reset();            
        regionLevel = 0;            
        Filter();            

        // Clear any existing pins, recenter/zoom map            
        bpp.Information = null;            
        bpp.Location = new LatLon();            
        mapCtrl1.Center = new LatLon(34.0, -118.0);            
        mapCtrl1.Zoom = 1000;            

        // Refresh map            
        mapCtrl1.Invalidate();        
    }
Testing

Build and run your application. The form will open with a list of regions in the 'Drill-down geocode results' listbox (listBoxResults), as shown below. You can drill-down through successive region levels either by selecting from the list box (listBoxResults), or by typing in the search text box (textBoxSearch). Notice how your selections are recorded in the history listbox (listBoxHistory). When a single address is selected, its location will be displayed on the map with the balloon push pin.

DDGC load
DDGC result