Find Path on Transport Network

Find a path between two points on a transport network.

To run this example, open the Wrld/Demo/Examples.unity scene, click the Play button, and select Find Path on Transport Network from the dropdown.

Find a path between two points on a transport network.
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
using Wrld;
using Wrld.Space;
using Wrld.Transport;

public class FindPathOnTransportNetwork : MonoBehaviour
{
    private readonly LatLong m_inputPositionA = LatLong.FromDegrees(37.802345, -122.419721);
    private readonly LatLong m_inputPositionB = LatLong.FromDegrees(37.802311, -122.417294);
    private readonly float m_lineVerticalOffsetMeters = 1.0f;

    private TransportPositioner m_transportPositionerA;
    private TransportPositioner m_transportPositionerB;
    private LineRenderer m_pathLineRenderer;

    private bool m_foundPath = false;

    private void OnEnable()
    {
        CreateLineRendererGameObject();

        m_transportPositionerA = CreatePositioner(m_inputPositionA);
        m_transportPositionerB = CreatePositioner(m_inputPositionB);
        m_transportPositionerA.OnPointOnGraphChanged += OnPointOnGraphChanged;
        m_transportPositionerB.OnPointOnGraphChanged += OnPointOnGraphChanged;
    }

    private void OnDisable()
    {
        GameObject.Destroy(m_pathLineRenderer);
        m_transportPositionerA.OnPointOnGraphChanged -= OnPointOnGraphChanged;
        m_transportPositionerA.Discard();

        m_transportPositionerB.OnPointOnGraphChanged -= OnPointOnGraphChanged;
        m_transportPositionerB.Discard();
    }

    private TransportPositioner CreatePositioner(LatLong location)
    {
        var options = new TransportPositionerOptionsBuilder()
            .SetInputCoordinates(location.GetLatitude(), location.GetLongitude())
            .Build();

        return Api.Instance.TransportApi.CreatePositioner(options);
    }

    private void OnPointOnGraphChanged()
    {
        if (m_foundPath)
        {
            return;
        }

        if (!m_transportPositionerA.IsMatched() || !m_transportPositionerB.IsMatched())
        {
            return;
        }

        var pathfindOptions = new TransportPathfindOptionsBuilder()
            .SetPointOnGraphA(m_transportPositionerA.GetPointOnGraph())
            .SetPointOnGraphB(m_transportPositionerB.GetPointOnGraph())
            .Build();

        var pathfindResult = Api.Instance.TransportApi.FindShortestPath(pathfindOptions);

        if (pathfindResult.IsPathFound)
        {
            m_foundPath = true;

            CreatePathLines(pathfindResult);

            var pathResultDirectedEdges = BuildPathResultDirectedEdges(pathfindResult);
            var pathResultWays = BuildPathResultWays(pathResultDirectedEdges);
            var pathResultNodes = BuildPathResultNodes(pathResultDirectedEdges);
            LogPathInformation(m_inputPositionA, m_inputPositionB, pathfindResult, pathResultWays, pathResultNodes);
        }
        
    }

    private void CreatePathLines(TransportPathfindResult result)
    {
        var points = new List<Vector3>();

        foreach(var pointEcef in result.PathPoints)
        {
            var lla = LatLongAltitude.FromECEF(pointEcef);
            lla.SetAltitude(lla.GetAltitude() + m_lineVerticalOffsetMeters);
            var worldPoint = Api.Instance.SpacesApi.GeographicToWorldPoint(lla);
            points.Add(worldPoint);
        }

#if UNITY_5_6_OR_NEWER
        m_pathLineRenderer.positionCount = points.Count;
#else
        m_pathLineRenderer.numPositions = points.Count;
#endif
        m_pathLineRenderer.SetPositions(points.ToArray());
    }

    
    private static List<TransportDirectedEdge> BuildPathResultDirectedEdges(TransportPathfindResult pathfindResult)
    {
        var directedEdges = new List<TransportDirectedEdge>();
        foreach (var directedEdgeId in pathfindResult.PathDirectedEdgeIds)
        {
            TransportDirectedEdge directedEdge;
            if (!Api.Instance.TransportApi.TryGetDirectedEdge(directedEdgeId, out directedEdge))
            {
                throw new System.ArgumentOutOfRangeException("unable to fetch TransportDirectedEdge");
            }
            directedEdges.Add(directedEdge);
        }
        return directedEdges;
    }

    private static List<TransportWay> BuildPathResultWays(IList<TransportDirectedEdge> directedEdges)
    { 
        var ways = new List<TransportWay>();
        foreach (var directedEdge in directedEdges)
        {
            TransportWay way;
            if (!Api.Instance.TransportApi.TryGetWay(directedEdge.WayId, out way))
            {
                throw new System.ArgumentOutOfRangeException("unable to fetch TransportWay");
            }
            ways.Add(way);
        }
        return ways;
    }

    private static List<TransportNode> BuildPathResultNodes(IList<TransportDirectedEdge> directedEdges)
    {
        var nodes = new List<TransportNode>();

        if (directedEdges.Any())
        {
            TransportNode node;
            if (!Api.Instance.TransportApi.TryGetNode(directedEdges.First().NodeIdA, out node))
            {
                throw new System.ArgumentOutOfRangeException("unable to fetch TransportNode");
            }
            nodes.Add(node);
        }

        foreach (var directedEdge in directedEdges)
        {
            TransportNode node;
            if (!Api.Instance.TransportApi.TryGetNode(directedEdge.NodeIdB, out node))
            {
                throw new System.ArgumentOutOfRangeException("unable to fetch TransportNode");
            }
            nodes.Add(node);
        }


        return nodes;
    }

    private static void LogPathInformation(
        LatLong inputPositionA, 
        LatLong inputPositionB, 
        TransportPathfindResult pathfindResult, 
        List<TransportWay> pathResultWays,
        List<TransportNode> pathResultNodes)
    {
        Debug.Log(string.Format("Found path from {0} to {1}: distance {2:0.00}m",
            inputPositionA.ToString(),
            inputPositionB.ToString(),
            pathfindResult.DistanceMeters));

        foreach (var way in pathResultWays)
        {
            Debug.Log(string.Format("Way id [{0}] has classification {1}, length {2:0.00}m, width {3:0.00}m",
                Api.Instance.TransportApi.WayIdToString(way.Id),
                way.Classification,
                way.LengthMeters,
                way.HalfWidthMeters * 2
                ));
        }

        foreach (var node in pathResultNodes)
        {
            Debug.Log(string.Format("Node id [{0}] at {1} has {2} incident edges",
                Api.Instance.TransportApi.NodeIdToString(node.Id),
                LatLongAltitude.FromECEF(node.Point).ToString(),
                node.IncidentDirectedEdges.Count
                ));

        }

    }

    private void CreateLineRendererGameObject()
    {
        m_pathLineRenderer = gameObject.AddComponent<LineRenderer>();
        m_pathLineRenderer.useWorldSpace = true;
        m_pathLineRenderer.startColor = Color.green;
        m_pathLineRenderer.endColor = Color.red;
        m_pathLineRenderer.material = new Material(Shader.Find("Sprites/Default"));
        m_pathLineRenderer.shadowCastingMode = UnityEngine.Rendering.ShadowCastingMode.Off;
        m_pathLineRenderer.receiveShadows = false;
    }
}
v0.8.17