Click or drag to resize

Routing with ADAS Data

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

In this tutorial we will build a simple routing application, based on ADAS information and the Telogis.GeoBase.Adas namespace, to display the varying gradients of a road along a route. As an example, in the image below, the red sections of the route indicate an incline (in the direction of 'reference' to 'non-reference' along the street link), the green sections indicate a decline, and the yellow sections indicate that the road is level (that is, within ±0.5°).

ADAS 1
Note Note

GeoBase identifies gradient changes -- the slope of the road surface -- using street links. The two ends of any street link (short sections of street along a route, typically running between two intersections) are designated as being either 'reference' or 'non-reference' nodes. The left and right sides of a street link are also defined based on a theoretical observer standing on the 'reference' end of the link, looking out toward the 'non-reference' end.

The ADAS gradient data used by GeoBase assumes travel from the reference end toward the non-reference end of a street link. That is, if the altitude of the reference end is less than the non-reference end, the gradient of the link is inclined. However, this does not take into account the actual direction of travel. It is entirely possible that this will be in the opposite direction (non-reference to reference), in which case this incline will actually be a downward slope to the traveler.

For this reason it is important to compare the points along the direction of travel with the ADAS points and adjust the data presented accordingly. Information displayed to the end-user will then better reflect their anticipated navigation experience. The tutorial below demonstrates one approach to ensure slopes are correctly displayed to users based on route direction.

ADAS Information

ADAS stands for Advanced Driver Assistance Systems. An ADAS data file can be incorporated with the GeoBase platform to provide useful information for both the driver and in-vehicle safety systems, allowing for a more safer driving experience and environment.

Note Note

ADAS information currently only includes road slope information. Other ADAS information is expected to become available in the future.

The Telogis.GeoBase.Adas namespace provides classes to represent and query ADAS information. Namely:

  • AdasInfo - which represents ADAS information for a street link.
  • AdasQuery - used to obtain ADAS information for a given street link.

AdasInfo

The AdasInfo class provides the following useful properties:

  1. LinkID - a unique value identifying the street link
  2. Points - a series of measurement points along the street link. The slope of the road at location Points[n] can be found at Slopes[n] (see below).
  3. Slopes - each element of the Slopes array describes the slope of the road at the location specified by the corresponding element in the Points array. The slope is measured in degrees: positive values indicate an incline; negative a decline.

AdasQuery

The AdasQuery class provides the QueryLink(UInt64) method to retrieve ADAS information for a given street link; the street link is specified by the link ID.

Tutorial Overview

The main purpose of this tutorial is to demonstrate how to use ADAS information with the classes from the Telogis.GeoBase.Adas namespace. We will build a simple routing application, comprising a map control and a fixed route. The route will be displayed on the map with sections of the route colored according to the section's slope. For this tutorial, and to keep things simple, we will use just three colors: a red section of the route indicates an incline, a green section of the route will indicate a decline, and a yellow section will indicate that the road is level, to within ±0.5°.

To retrieve the slope value from a section of the road, we will call the AdasQuery's QueryLink method with the section's link ID, to return an AdasInfo, where, as mentioned above, each element of the Slopes array describes the slope of the road at the location specified by the corresponding element in the Points array.

We will split the tutorial into three steps:

  1. Add a map control
  2. Create a route
  3. Re-color route according to road gradient

Step 1 - Add a map control

Open a new instance of Visual Studio, and add geobase.net.dll as a reference.

Add a map control to the form. Rename the map control to 'mapMain', and set the 'Zoom' property to 3. Change the CenterLat and CenterLon properties to:

  • CenterLat: 34.058900
  • CenterLon: -118.253394

That's all there is to this step.

Step 2 - Create a route

In this section we will write the code to create:

  • a fixed route
  • a multirepository for the data files (both map and ADAS data files are required)
  • a Directions object for the route
  • a renderer list to display the route (and later, the re-colored route) on the map

Before we create the route, change to the code view in Visual Studio. To make the code simpler and more readable, add the following using directives to the top of the form:

C#
using Telogis.GeoBase;
using Telogis.GeoBase.Routing;
using Telogis.GeoBase.Adas;
using Telogis.GeoBase.Repositories;

Next, add the following code to the Form1 constructor, just after the InitializeComponent() statement. Ensure that your data files are located as per the parameter to the 'new MultiRepository()' statement. In this example, our data files are stored at 'C:\GeoBase\Data'.

Note Note

It is important to note that ADAS data is stored within specific ADAS map data files. ADAS data is not typically included in generic .gbfs map data files. If you do not currently have an ADAS file, an example can be downloaded from the Verizon Connect Spatial website.

C#
//Add start and stop route points
RouteStop rsStart = new RouteStop(new LatLon(34.00102,-118.27779));
RouteStop rsEnd = new RouteStop(new LatLon(34.07787,-118.23342));

//Set repository - this repository will include both map and ADAS data
MultiRepository mr = new MultiRepository(@"C:\GeoBase\Data\");
Repository.CurrentThreadRepository = mr;

//Calculate route            
Route myRoute = new Route(rsStart, rsEnd);

//Get directions
Directions myDirs = myRoute.GetDirections();

//Add directions to map    
RendererList rList = new RendererList();
rList.Add(myDirs);

//Add rendererlist
mapMain.Renderer = rList;

And that concludes step 2. You can build and run the application as it stands so far - you should see a map centered on LA, with a route displayed along the Harbor Freeway, as shown in the image below.

ADAS 2

Step 3 - Re-color route according to road gradient

In this section we will add the code to re-color the route depending on the road's gradient. This section comprises one class, AdasRenderer, which implements the IMapRenderer interface. To implement the IMapRenderer interface, we will add code for both Render(), and RequiredRenderModes(). RequiredRenderModes() simply tells the renderer when to render our images, within its three-stage render process, onto the map. For this application, we will select rendering to occur 'pre-labelling' - that is, map labels will be placed on the map after we have re-colored the route. The Render method will be responsible for the rest of the work of re-coloring the route according to the slope.

To begin with, add the AdasRenderer class as shown below underneath Form1. Notice that the RequiredRenderModes method has been implemented with the read-only RenderMode property being set to PreLabelling.

C#
public class AdasRenderer : IMapRenderer {

    public void Render(System.Drawing.Graphics graphics, RenderContext rc) {
    }

    public RenderMode RequiredRendermodes {
        get {
            return RenderMode.PreLabelling;
        }
    }    
}

In section 2, we created a route, and obtained the Directions from that route to display on the map. The Directions class provides a GetDirectionLinks() method from which we can obtain a list of DirectionLinks, and thus providing us with the necessary link IDs that will be used to find, ultimately, the slopes of the individual sections of the route. For that reason, we will need to instantiate the AdasRenderer with these Directions. Add the following code and constructor to the AdasRenderer class:

C#
public AdasRenderer(Directions myDirs) {
    DirectionLink[] dirlinks = myDirs.GetDirectionLinks();
}

The render method will perform the following tasks:

  • set the Pens to be used for coloring the route
  • create a list of link IDs from the direction links
  • create a list of AdasInfo using the list of link IDs
  • derive the direction of the slope for each point of the route from each AdasInfo

Next we determine whether the slope of the street link is incline or decline relative to the direction of travel.

This code should be placed in the AdasRenderer class, immediately below the 'DirectionLink[] dirlinks = myDirs.GetDirectionLinks();' statement.

C#
// This part determines the directionality of the route
for (int i = 0; i < dirlinks.Length - 1; i++) {
    var curr = dirlinks[i];

    // Get the first point of the directionLink which
    // has the same direction as the route
    double routeHeading = MathUtil.GetHeading(curr.Points.First(), curr.Points.Last());

    // Query the AdasInfo for the points
    AdasInfo[] info = AdasQuery.QueryLink(curr.LinkId);

    // Create the list of points and slopes from the AdasInfo
    List<LatLon> points = new List<LatLon>();
    List<float> slopes = new List<float>();
    foreach (var datum in info) {
        points.AddRange(datum.Points);
        slopes.AddRange(datum.Slopes);
    }

    DrawingInfo di = new DrawingInfo();

    if (info.Length != 0) {
        // If the points in the AdasInfo is in a different order from the
        // direction described by the direction link, we reverse the order
        double adasHeading = MathUtil.GetHeading(info[0].Points.First(), info[0].Points.Last());
        double adasHeadingBackwards = MathUtil.GetHeading(info[0].Points.Last(), info[0].Points.First());

        if (Math.Abs(routeHeading - adasHeading) > Math.Abs(routeHeading - adasHeadingBackwards)) {
            ReverseSlopes(slopes);
        }
        // Create the drawing info
    }

    di.points = points.ToArray();
    di.slopes = slopes.ToArray();

    dis.Add(di);
}

Copy the following code above the Render() method. The ReverseSlopes method performs the inversion of slope values when called.

The DrawingInfo structure is used to create an array of point locations and slope values which is saved to a list, then used by ReverseSlopes. This information is used to compare the slope of street links with the direction of travel along the route, allowing link color (green or red) to be switched when appropriate (ensuring a green decline is displayed as a red incline if traveling in the opposite direction).

C#
struct DrawingInfo {
    public LatLon[] points;
    public float[] slopes;
}

List<DrawingInfo> dis = new List<DrawingInfo>();

void ReverseSlopes(List<float> slopes) {
    for (int i = 0; i < slopes.Count; i++) {
        slopes[i] = -slopes[i];
    }
}

The following code should be added into the Render() method.

It set the Pens to be used for coloring the route. If the slope value is positive, then the section of the route is on an incline, and we will re-color it red. If the slope value is negative, then we will re-color the route green to indicate a decline. To indicate that the road is level, we will re-color the route yellow. For this example, we have chosen an arbitrary value, levelBand, of ±0.5°.

C#
//Set pen's line width
float lineWidth = 15 - (float)rc.Map.Zoom;

//Set band at which gradient is considered level (0.5 degrees in this example)
float levelBand = 0.5F;

//Set pen's colors
Pen inclinePen = new Pen(Color.Red, lineWidth);
Pen declinePen = new Pen(Color.Green, lineWidth);
Pen levelPen = new Pen(Color.Yellow, lineWidth);

Immediately below this, add the following code to derive the direction of the slope for each point of the route from each AdasInfo:

C#
foreach (DrawingInfo info in dis) {
    int nPoints = info.points.Length;
    Point[] points = new Point[nPoints];
    for (int idx = 0; idx < nPoints; idx++){
        int x;
        int y;
        rc.Map.LatLontoXY(out x, out y, info.points[idx]);
        points[idx] = new Point(x, y);
    }

    for (int idx = 1; idx < nPoints - 1; idx++) {
        //Check if slope is within the level band
        if (Math.Abs(info.slopes[idx]) < levelBand){
            graphics.DrawLines(levelPen, points);
        } else {
                graphics.DrawLines(info.slopes[idx] > 0 ? inclinePen : declinePen, points);    
        }
    }
}

That concludes the coding for the AdasRenderer class. Before we test the application, we still need to tell the map to use our AdasRenderer. Add the following code in the Form1 constructor, just before the 'mapMain.Renderer = rList;' statement.

C#
//Add ADAS Info to renderer list
AdasRenderer ar = new AdasRenderer(myDirs);
rList.Add(ar);

Build and run your application. You will be presented with the screen as shown below. Red sections of the route indicate the road is on an incline; green indicates a decline, and yellow indicates that the section is level. If any part of the route is not colored red, green, or yellow, then no ADAS information is available for that part of the route.

ADAS 3

Complete Code

The complete code for this example project is included below:

C#
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using Telogis.GeoBase;
using Telogis.GeoBase.Routing;
using Telogis.GeoBase.Adas;
using Telogis.GeoBase.Repositories;

namespace ADAS {

    public partial class Form1 : Form {

        public Form1() {

            InitializeComponent();
            //Add start and stop route points
            RouteStop rsStart = new RouteStop(new LatLon(34.00102, -118.27779));
            RouteStop rsEnd = new RouteStop(new LatLon(34.07787, -118.23342));

            //Set repository - this repository will include both map and ADAS data
            MultiRepository mr = new MultiRepository(@"C:\GeoBase\Data\");
            Repository.CurrentThreadRepository = mr;

            //Calculate route            
            Route myRoute = new Route(rsStart, rsEnd);

            //Get directions
            Directions myDirs = myRoute.GetDirections();

            //Add directions to map    
            RendererList rList = new RendererList();
            rList.Add(myDirs);

            //Add ADAS Info to renderer list
            AdasRenderer ar = new AdasRenderer(myDirs);
            rList.Add(ar);

            //Add rendererlist
            mapMain.Renderer = rList;

        }

        public class AdasRenderer : IMapRenderer {
            public AdasRenderer(Directions myDirs) {
                DirectionLink[] dirlinks = myDirs.GetDirectionLinks();

                // This part determines the directionality of the route
                for (int i = 0; i < dirlinks.Length - 1; i++) {
                    var curr = dirlinks[i];

                    // Get the first point of the directionLink which
                    // has the same direction as the route
                    double routeHeading = MathUtil.GetHeading(curr.Points.First(), curr.Points.Last());

                    // Query the AdasInfo for the points
                    AdasInfo[] info = AdasQuery.QueryLink(curr.LinkId);

                    // Create the list of points and slopes from the AdasInfo
                    List<LatLon> points = new List<LatLon>();
                    List<float> slopes = new List<float>();
                    foreach (var datum in info) {
                        points.AddRange(datum.Points);
                        slopes.AddRange(datum.Slopes);
                    }

                    DrawingInfo di = new DrawingInfo();

                    if (info.Length != 0) {
                        // If the points in the AdasInfo is in a different order from the
                        // direction described by the direction link, we reverse the order
                        double adasHeading = MathUtil.GetHeading(info[0].Points.First(), info[0].Points.Last());
                        double adasHeadingBackwards = MathUtil.GetHeading(info[0].Points.Last(), info[0].Points.First());

                        if (Math.Abs(routeHeading - adasHeading) > Math.Abs(routeHeading - adasHeadingBackwards)) {
                            ReverseSlopes(slopes);
                        }
                        // Create the drawing info
                    }

                    di.points = points.ToArray();
                    di.slopes = slopes.ToArray();

                    dis.Add(di);
                }
            }

            void ReverseSlopes(List<float> slopes) {
                for (int i = 0; i < slopes.Count; i++) {
                    slopes[i] = -slopes[i];
                }
            }

            struct DrawingInfo {
                public LatLon[] points;
                public float[] slopes;
            }

            List<DrawingInfo> dis = new List<DrawingInfo>();

            public void Render(System.Drawing.Graphics graphics, RenderContext rc) {

                //Set pen's line width
                float lineWidth = 15 - (float)rc.Map.Zoom;

                //Set band at which gradient is considered level (0.5 degrees in this example)
                float levelBand = 0.5F;

                //Set pen's colors
                Pen inclinePen = new Pen(Color.Red, lineWidth);
                Pen declinePen = new Pen(Color.Green, lineWidth);
                Pen levelPen = new Pen(Color.Yellow, lineWidth);

                foreach (DrawingInfo info in dis) {
                    int nPoints = info.points.Length;
                    Point[] points = new Point[nPoints];
                    for (int idx = 0; idx < nPoints; idx++) {
                        int x;
                        int y;
                        rc.Map.LatLontoXY(out x, out y, info.points[idx]);
                        points[idx] = new Point(x, y);
                    }

                    for (int idx = 1; idx < nPoints - 1; idx++) {
                        //Check if slope is within the level band
                        if (Math.Abs(info.slopes[idx]) < levelBand) {
                            graphics.DrawLines(levelPen, points);
                        } else {
                            graphics.DrawLines(info.slopes[idx] > 0 ? inclinePen : declinePen, points);
                        }
                    }
                }
            }

            public RenderMode RequiredRendermodes {
                get {
                    return RenderMode.PreLabelling;
                }
            }
        }
    }
}