User Tools

Site Tools


map_suite_routing_quick_start_guide

Map Suite Routing Quick Start Guide

Note: The page was created before Map Suite 10. Map Suite 10.0 organized many classes into new namespaces and assemblies as well as had a few minor breaks in compatibility. The majority of previously built code should work without modification assuming the new namespaces are added. For guidance on upgrading your existing code, please check out MapSuite 10 Upgrade Guide.

The Map Suite Routing Extension QuickStart Guide will guide you through the process of creating a simple routing application and will help you become familiar with Map Suite Routing. This edition of the QuickStart Guide supports Map Suite Routing 9.0.0.0 or higher, and shows you how to create a Winforms application. Note that to use the Routing Extension, the .NET Framework 4.0 and a Map Suite GIS component (Desktop, Web, Silverlight or Services Edition) version 9.0.0.0 or higher are required.

Welcome to Map Suite Routing from ThinkGeo, a full-featured extension of our Map Suite mapping controls that makes it easy for any Microsoft .NET developer to add routing features to a Map Suite-enabled Microsoft .NET application quickly and efficiently. Using the intuitive object model, even developers inexperienced in Geographic Information Systems (GIS) can have fully functional maps working in minutes.

The Map Suite Routing Extension provides interfaces and classes for determining the shortest or fastest route between two points, with the ability to add more routing options. You can retrieve the roads collection consisting of routes, turn-by-turn directions, as well as other information like total distance. You can also utilize many additional features, such as getting a service area around a location, adding sequential intermediate points, or making the route avoid certain areas or features.

The purpose of this guide is to help you get started building your own routing applications. Like any new software, there is some learning to be done.

Software Requirements

Before we get started, make sure that you have installed the ThinkGeo Product Center and that you have either started an evaluation or activated a full license of the following products:

  • Map Suite Routing
  • Map Suite Desktop Edition

While the Map Suite Routing extension takes care of the business of routing and providing directions, in order to display it on an interactive map you need to use a control like Map Suite Desktop Edition.

If you installed the ThinkGeo Product Center in the default location, your Map Suite Routing 9.0 assemblies will be located in C:\Program Files (x86)\ThinkGeo\Map Suite 9.0\Map Suite Routing.

Download Routing Explorer

Download the Sample

Setting up the Environment

Let's start with a new Windows Forms project in Microsoft Visual Studio (2012 or newer) and call it HelloWorld (see Figure 1). We can create the project with .NET Framework 4.0 or 4.5.


Figure 1. Creating a new project in Microsoft Visual Studio.

The project “HelloWorld” is created in a new solution called “HelloWorld”. The wizard creates a single Windows Form.

Note: Although it is not a ThinkGeo assembly, you also need to add “WindowsBase.dll” to the references. WindowsBase can be found on the .NET tab of the Add Reference dialog. If you don't do this, you will get the following error when you compile the project: “The type 'System.Collections.Specialized.INotifyCollectionChanged' is defined in an assembly that is not referenced. You must add a reference to assembly 'WindowsBase, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35'.”

Adding the Map Control to the Toolbar

1. When you first open Microsoft Visual Studio after installing Map Suite, you may not see the Map Suite Desktop Edition map control in the Toolbox. In this case, you will need to perform the following steps to add it.

Hover on the Toolbox and right click anywhere on the list of controls. You will get a pop-up menu. Select “Choose items…”

2. The Choose Toolbox Items dialogue will appear. You will need to select the “.NET Framework Components” tab and then click the “Browse…” button. Finally, navigate to the C:\Program Files (x86)\ThinkGeo\Map Suite 9.0\Map Suite Routing\Current Version\Managed Assemblies folder and select the “DesktopEdition.dll” file.

3. You should now have the Map control available in your Toolbox as shown below.


\\Figure 2. The Map Controls under the Toolbox window.

Draw the Map control on the form by clicking on the Map control in the Toolbox and then dragging the map onto the form. You can also size the map to your desired width and height. You can leave the name of Map control as winformMap1.

Adding References to the Map Suite Routing "Hello World" Sample

We now have the “DesktopEdition.dll” referenced. Next, we need to add “MapSuiteCore.dll” and “MapSuiteRouting.dll” to the references. Right-click the project in the Solution Explorer and select “Add Reference…”, navigate to the C:\Program Files (x86)\ThinkGeo\Map Suite 9.0\Map Suite Routing\Current Version\Managed Assemblies folder and select those two files.

Now we are ready to add code.

Map Suite Routing Extension "Hello World" Sample

After this section, you will be able to draw a map with the Map control and find the route using your own data. To begin, let's have a look at how to prepare the routing data.

Prepare Routing Data

The Map Suite Routing Extension supports multiple kinds of data sources, such as SQL Server 2008, Postgre Database, Oracle, etc., but they must include LineShape data only. We'll use a Shape File as the data source for this sample. First, though, we need to build the routing index file based on it.

Build the routing routable file(.routable.shp).

Build the routing index file (.rtg/.rtx) using the included Map Suite Routing Explorer tool. (See Figure 4)


Figure 4. Building the routing index file with Map Suite Routing Explorer.

(NOTE: The data used in this sample can be found in the attached sample project's App_Data folder. Please download the Map Suite Routing Explorer tool to acquire it.)

Map Suite Routing Extension "Hello World"

1. Our first step is to define the renderers for the map, route and stops. Let's assume we need to find the shortest route between the two roads with the feature IDs “4716” and “9638.” Below is the code that will make this happen. All of the following is written in the Form1_Load event of the windows form. Also, you'll need to add the namespaces used as such: using ThinkGeo.MapSuite.Core;, using ThinkGeo.MapSuite.DesktopEdition; and using ThinkGeo.MapSuite.Routing;.

private void Form1_Load(object sender, EventArgs e)
        {
            // Set the Map Unit and current extent
            winformsMap1.MapUnit = GeographyUnit.DecimalDegree;
            winformsMap1.CurrentExtent = new RectangleShape(-97.7970203443604, 30.3231958204346, -97.6787456556397, 30.2358201795654);
 
            // Define a new layer to render the the Austin streets
            ShapeFileFeatureLayer austinStreetsLayer = new ShapeFileFeatureLayer(@"..\..\App_Data\Austinstreets.shp ");
            austinStreetsLayer.ZoomLevelSet.ZoomLevel01.DefaultLineStyle = LineStyles.LocalRoad4;
            austinStreetsLayer.ZoomLevelSet.ZoomLevel01.ApplyUntilZoomLevel = ApplyUntilZoomLevel.Level20;
            LayerOverlay austinStreetOverlay = new LayerOverlay();
            austinStreetOverlay.Layers.Add("austinStreetsLayer", austinStreetsLayer);
            winformsMap1.Overlays.Add("austinStreetOverlay", austinStreetOverlay);
 
            // Define a Routing layer to render the route and stops
            RoutingLayer routingLayer = new RoutingLayer();
            austinStreetsLayer.Open();
            routingLayer.StartPoint = austinStreetsLayer.FeatureSource.GetFeatureById("4716", ReturningColumnsType.NoColumns).GetShape().GetCenterPoint();
            routingLayer.EndPoint = austinStreetsLayer.FeatureSource.GetFeatureById("9638", ReturningColumnsType.NoColumns).GetShape().GetCenterPoint();
            austinStreetsLayer.Close();
            LayerOverlay routingOverlay = new LayerOverlay();
            routingOverlay.Layers.Add("RoutingLayer", routingLayer);
            winformsMap1.Overlays.Add("RoutingOverlay", routingOverlay);
 
            winformsMap1.Refresh();
        }

(NOTE: The data used in this sample can be found in the attached sample above at “\AppData” folder)

Figure 4 shows what you'll see when you run your application.

qsg_routing_img08.jpg
Figure 4. Initialize the map for finding a route.

2. Find the shortest route and render it on the map.

Add a button named “Find The Shortest Path” and double-click it to add the click event. Next, enter the code below to find the shortest route and render it on the map.

private void button1_Click(object sender, EventArgs e)
        {
            ShapeFileFeatureSource featureSource = new ShapeFileFeatureSource(@"..\..\App_Data\Austinstreets.shp");
            RtgRoutingSource routingSource = new RtgRoutingSource(@"..\..\App_Data\Austinstreets.rtg");
            RoutingEngine routingEngine = new RoutingEngine(routingSource, featureSource);
            RoutingLayer routingLayer = (RoutingLayer)((LayerOverlay)winformsMap1.Overlays[["RoutingOverlay"]]).Layers[["RoutingLayer"]];
            winformsMap1.Overlays[["RoutingOverlay"]].Lock.EnterWriteLock();
            try
            {
                routingLayer.Routes.Clear();
                routingLayer.Routes.Add(routingEngine.GetRoute("4716", "9638").Route);
            }
            finally
            {
                winformsMap1.Overlays[["RoutingOverlay"]].Lock.ExitWriteLock();
            }
 
            winformsMap1.Refresh();
        }

Run the sample and click the “Find The Shortest Path” button. You will see the result as shown in Figure 5.

qsg_routing_img09.jpg
Figure 5. The shortest path between points has been generated.

(NOTE: We can also use InMemoryFeatureLayer to render the routing result; RoutingLayer is just a shortcut to make it more convenient.)

Finding The Shortest Path Using Coordinates

The Map Suite Routing Extension also supports finding a route between specified coordinates. Below is the sample code that will make this happen.

private void Form1_Load(object sender, EventArgs e)
        {
            // Set the Map Unit and current extent
            winformsMap1.MapUnit = GeographyUnit.DecimalDegree;
            winformsMap1.CurrentExtent = new RectangleShape(-97.7970203443604, 30.3231958204346, -97.6787456556397, 30.2358201795654);
 
            // Define a new layer to render the the Austin streets
            ShapeFileFeatureLayer austinStreetsLayer = new ShapeFileFeatureLayer(@"..\..\App_Data\Austinstreets.shp");
            austinStreetsLayer.ZoomLevelSet.ZoomLevel01.DefaultLineStyle = LineStyles.LocalRoad4;
            austinStreetsLayer.ZoomLevelSet.ZoomLevel01.ApplyUntilZoomLevel = ApplyUntilZoomLevel.Level20;
            LayerOverlay austinStreetOverlay = new LayerOverlay();
            austinStreetOverlay.Layers.Add("austinStreetsLayer", austinStreetsLayer);
            winformsMap1.Overlays.Add("austinStreetOverlay", austinStreetOverlay);
 
            // Define a Routing layer to render the path and stops
            RoutingLayer routingLayer = new RoutingLayer();
            austinStreetsLayer.Open();
 
            // The code that routes using coordinates
            routingLayer.StartPoint = new PointShape(-97.763184, 30.299407);
            routingLayer.EndPoint = new PointShape(-97.713382, 30.259609);
 
            austinStreetsLayer.Close();
            LayerOverlay routingOverlay = new LayerOverlay();
            routingOverlay.Layers.Add("RoutingLayer", routingLayer);
            winformsMap1.Overlays.Add("RoutingOverlay", routingOverlay);
 
            winformsMap1.Refresh();
        }
 
        private void button1_Click(object sender, EventArgs e)
        {
            ShapeFileFeatureSource featureSource = new ShapeFileFeatureSource(@"..\..\App_Data\Austinstreets.shp");
            RtgRoutingSource routingSource = new RtgRoutingSource(@"..\..\App_Data\Austinstreets.rtg");
            RoutingEngine routingEngine = new RoutingEngine(routingSource, featureSource);
            RoutingLayer routingLayer = (RoutingLayer)((LayerOverlay)winformsMap1.Overlays[["RoutingOverlay"]]).Layers[["RoutingLayer"]];
            winformsMap1.Overlays[["RoutingOverlay"]].Lock.EnterWriteLock();
            try
            {
                routingLayer.Routes.Clear();
                routingLayer.Routes.Add(routingEngine.GetRoute(routingLayer.StartPoint, routingLayer.EndPoint).Route);
            }
            finally
            {
                winformsMap1.Overlays[["RoutingOverlay"]].Lock.ExitWriteLock();
            }
 
            winformsMap1.Refresh();
        }

Now, you will see the same result as in Figure 5 after running.

Adding Sequential Intermediate Stops

With the help of a Routing Layer, it's easier to add sequential intermediate stops. Let's define two intermediate stops whose feature ids are “5137” and “8179.” Use the code below to accomplish this.

private void Form1_Load(object sender, EventArgs e)
        {
            // Set the Map Unit and current extent
            winformsMap1.MapUnit = GeographyUnit.DecimalDegree;
            winformsMap1.CurrentExtent = new RectangleShape(-97.7970203443604, 30.3231958204346, -97.6787456556397, 30.2358201795654);
 
            // Define a new layer to render the the Austin streets
            ShapeFileFeatureLayer austinStreetsLayer = new ShapeFileFeatureLayer(@"..\..\App_Data\Austinstreets.shp");
            austinStreetsLayer.ZoomLevelSet.ZoomLevel01.DefaultLineStyle = LineStyles.LocalRoad4;
            austinStreetsLayer.ZoomLevelSet.ZoomLevel01.ApplyUntilZoomLevel = ApplyUntilZoomLevel.Level20;
            LayerOverlay austinStreetOverlay = new LayerOverlay();
            austinStreetOverlay.Layers.Add("austinStreetsLayer", austinStreetsLayer);
            winformsMap1.Overlays.Add("austinStreetOverlay", austinStreetOverlay);
 
            // Define a Routing layer to render the path and stops
            RoutingLayer routingLayer = new RoutingLayer();
            austinStreetsLayer.Open();
            routingLayer.StartPoint = austinStreetsLayer.FeatureSource.GetFeatureById("4716", ReturningColumnsType.NoColumns).GetShape().GetCenterPoint();
            PointShape stopPoint1 = austinStreetsLayer.FeatureSource.GetFeatureById("5137", ReturningColumnsType.NoColumns).GetShape().GetCenterPoint();
            PointShape stopPoint2 = austinStreetsLayer.FeatureSource.GetFeatureById("8179", ReturningColumnsType.NoColumns).GetShape().GetCenterPoint();
            routingLayer.StopPoints.Add(stopPoint1);
            routingLayer.StopPoints.Add(stopPoint2);
            routingLayer.EndPoint = austinStreetsLayer.FeatureSource.GetFeatureById("9638", ReturningColumnsType.NoColumns).GetShape().GetCenterPoint();
            austinStreetsLayer.Close();
            LayerOverlay routingOverlay = new LayerOverlay();
            routingOverlay.Layers.Add("RoutingLayer", routingLayer);
            winformsMap1.Overlays.Add("RoutingOverlay", routingOverlay);
 
            winformsMap1.Refresh();
        }
 
        private void button1_Click(object sender, EventArgs e)
        {
            ShapeFileFeatureSource featureSource = new ShapeFileFeatureSource(@"..\..\App_Data\Austinstreets.shp");
            RtgRoutingSource routingSource = new RtgRoutingSource(@"..\..\App_Data\Austinstreets.rtg");
            RoutingEngine routingEngine = new RoutingEngine(routingSource, featureSource);
            RoutingLayer routingLayer = (RoutingLayer)((LayerOverlay)winformsMap1.Overlays[["RoutingOverlay"]]).Layers[["RoutingLayer"]];
            winformsMap1.Overlays[["RoutingOverlay"]].Lock.EnterWriteLock();
            try
            {
                routingLayer.Routes.Clear();
 
                // Generate all key points
                Collection<PointShape> keyPoints = new Collection<PointShape>();
                keyPoints.Add(routingLayer.StartPoint);
                foreach (PointShape stop in routingLayer.StopPoints)
                {
                    keyPoints.Add(stop);
                }
                keyPoints.Add(routingLayer.EndPoint);
 
                // Get the path for each segment between two key points
                for (int i = 0; i < keyPoints.Count - 1; i++)
                {
                    routingLayer.Routes.Add(routingEngine.GetRoute(keyPoints[[i]], keyPoints[[i|+ 1]]).Route);
                }
            }
            finally
            {
                winformsMap1.Overlays[["RoutingOverlay"]].Lock.ExitWriteLock();
            }
 
            winformsMap1.Refresh();
        }

(NOTE: Here we also need to have a using Collections.ObjectModel added to the application.)

Let's run the application and click the “Find The Shortest Path” button. You will see the path and stops rendered on the map as shown in Figure 6.

qsg_routing_img10.jpg
Figure 6. Finding path with intermediate stops.

(NOTE: The Map Suite Routing Extension doesn't support finding a path between Matrix points (Points-to-Points Route), so the intermediate stops must be added in order.)

Summary

You now know how to use the Map Suite Routing Extension to find the shortest route. Let's recap what we have learned about the objects' relationships and how the pieces of Map Suite work together:

  1. It is of the utmost importance to make sure the features in the routing data source (including Shape Files and other data sources like Oracle, Postgre Database, SQL Server 2008, etc.) are LineShapes.
  2. The RoutingEngine is the main class that contains all of the other objects that define how to find a route.
  3. The RoutingLayer is a convenient class for finding and rendering a route. It allows us to add sequential intermediate stops.

Download Sample Code From This Exercise (1.76 MB)

map_suite_routing_quick_start_guide.txt · Last modified: 2017/03/17 05:12 by tgwikiupdate