Page 1 of 1

PTV Developer / Routing API - how to determine distance per country?

Posted: Mon Feb 05, 2024 4:49 pm
by Bernd Welter
I've been asked how I'd recommend to compute the "distance per country" in a PTV Developer Routing API client application (as this info is not native part of the response).
PTV Developer.distancePerCountry.png
Here's my approach - based on Border_Events and Waypoint_Events.
Feedback is welcome - especially if you detect an error ;-)

Code: Select all

       
// for a proper aggregation of country-wise data we need to use BORDER_EVENTS and WAYPOINT_EVENTS
if ((results.Contains(Routing.Model.Results.BORDER_EVENTS)) && (results.Contains(Routing.Model.Results.WAYPOINT_EVENTS)))
{                        
    Dictionary<string, double> dictDistancePerCountry = new Dictionary<string, double>();
    List<Routing.Model.Event> lstWaypointEvents = lstEvents.Where(ev => ev.Waypoint != null).ToList();
    Routing.Model.Event firstWaypoint = lstWaypointEvents.First(), lastWaypoint = lstWaypointEvents.Last();
    // convenience method : in some countries like "US" we use a combined string such as "US-CA" to refer to a subunit.
    string getCountry(Routing.Model.Event ev)
    {
        return ev.CountryCode.Split('-')[0];
    }
    // are there any border crossings?
    if (lstEvents.Any(ev => ev.Border != null))
    {
        List<Routing.Model.Event> lstBorderEvents = lstEvents.Where(ev => ev.Border != null).ToList();
        Routing.Model.Event firstBorder = lstBorderEvents.First() , lastBorder = lstBorderEvents.Last();
        dictDistancePerCountry.Add(getCountry( firstWaypoint ), firstBorder.DistanceFromStart);
        double lastPart = lastWaypoint.DistanceFromStart - lastBorder.DistanceFromStart;
        
        if (dictDistancePerCountry.ContainsKey(getCountry( lastBorder)))
            dictDistancePerCountry[getCountry(lastBorder)] += lastPart;
        else
            dictDistancePerCountry.Add(getCountry(lastBorder), lastPart);
        for (int index = 1; index < lstBorderEvents.Count; index++)
        {
            double leg = lstBorderEvents[index].DistanceFromStart - lstBorderEvents[index - 1].DistanceFromStart;
            string country = getCountry(lstBorderEvents[index-1]);
            if (dictDistancePerCountry.ContainsKey(country))
                dictDistancePerCountry[country] += leg;
            else
                dictDistancePerCountry.Add(country, leg);
        }
    }
    else // no border crossings
    {
        dictDistancePerCountry.Add(getCountry(lastWaypoint), lastWaypoint.DistanceFromStart);
    }
    // visualization of aggregates.
    chartRouting_CustomAGgregates_DistancePerCountry.Series.First().Points.Clear();
    foreach (string key in dictDistancePerCountry.Keys)
    {
        string label = "Country=" + key + "\r\ndistance=" + Tools.displayDistance(dictDistancePerCountry[key], routeResponse.Distance);
        DataPoint dataPoint = new DataPoint { 
            ToolTip = label,
            Label = label,
            YValues = new double[] { dictDistancePerCountry[key] }
        };
        chartRouting_CustomAGgregates_DistancePerCountry.Series.First().Points.Add(dataPoint);
    }
    foreach (DataPoint dp in chartRouting_CustomAGgregates_DistancePerCountry.Series.First().Points)
    { 
        dp.Color = System.Drawing.Color.FromArgb(128,dp.Color);
    }
    dgvRouting_CustomAGgregates_DistancePerCountry.DataSource = dictDistancePerCountry.Keys.Select(k => new {
        k,
        distance = dictDistancePerCountry[k],
        RelativeDistance = Tools.displayDistance(dictDistancePerCountry[k], routeResponse.Distance)
    }).ToArray();
}