public TransportPathfindResult FindShortestPath(TransportPathfindOptions options)
        {
            var optionsInterop = options.ToInterop();

            var pathfindResultInterop = NativeTransportApi_FindShortestPath(NativePluginRunner.API, ref optionsInterop);

            if (pathfindResultInterop.IsPathFound)
            {
                // alloc and pin buffers
                var pathDirectedEdgeIdsBuffer         = new TransportDirectedEdgeIdInterop[pathfindResultInterop.PathDirectedEdgesSize];
                var pathDirectedEdgeIdsBufferGCHandle = GCHandle.Alloc(pathDirectedEdgeIdsBuffer, GCHandleType.Pinned);
                pathfindResultInterop.PathDirectedEdges = pathDirectedEdgeIdsBufferGCHandle.AddrOfPinnedObject();

                var pathPointsBuffer         = new DoubleVector3[pathfindResultInterop.PathPointsSize];
                var pathPointsBufferGCHandle = GCHandle.Alloc(pathPointsBuffer, GCHandleType.Pinned);
                pathfindResultInterop.PathPoints = pathPointsBufferGCHandle.AddrOfPinnedObject();

                var pathPointParamsBuffer         = new double[pathfindResultInterop.PathPointsSize];
                var pathPointParamsBufferGCHandle = GCHandle.Alloc(pathPointParamsBuffer, GCHandleType.Pinned);
                pathfindResultInterop.PathPointParams = pathPointParamsBufferGCHandle.AddrOfPinnedObject();

                var result = PopulateAndReleaseTransportPathfindResult(pathDirectedEdgeIdsBuffer, pathPointsBuffer, pathPointParamsBuffer, ref pathfindResultInterop);

                pathDirectedEdgeIdsBufferGCHandle.Free();
                pathPointsBufferGCHandle.Free();
                pathPointParamsBufferGCHandle.Free();

                return(result);
            }
            else
            {
                var failedResult = new TransportPathfindResult();
                return(failedResult);
            }
        }
        private IList <TransportDirectedEdge> BuildDirectedEdgesForCell(
            TransportNetworkType transportNetworkType,
            TransportCellKey cellKey
            )
        {
            var cellKeyInterop    = cellKey.ToInterop();
            int directedEdgeCount = NativeTransportApi_GetDirectedEdgeCountForNetworkInCell(NativePluginRunner.API, transportNetworkType, cellKeyInterop);

            if (directedEdgeCount <= 0)
            {
                return(new List <TransportDirectedEdge>());
            }

            // alloc and pin buffers
            var directedEdgeIdInteropBuffer         = new TransportDirectedEdgeIdInterop[directedEdgeCount];
            var directedEdgeIdInteropBufferGCHandle = GCHandle.Alloc(directedEdgeIdInteropBuffer, GCHandleType.Pinned);
            var directedEdgeIdInteropBufferPtr      = directedEdgeIdInteropBufferGCHandle.AddrOfPinnedObject();

            // populate buffers from C++ api
            var directedEdgeSuccess = NativeTransportApi_TryGetDirectedEdgeIdsForNetworkInCell(NativePluginRunner.API, transportNetworkType, cellKeyInterop, directedEdgeCount, directedEdgeIdInteropBufferPtr);

            if (!directedEdgeSuccess)
            {
                throw new System.ArgumentOutOfRangeException("incorrect buffer size passed for directed edge ids");
            }

            var directedEdges = FetchDirectedEdges(directedEdgeIdInteropBuffer);

            // free buffer
            directedEdgeIdInteropBufferGCHandle.Free();
            return(directedEdges);
        }
        private bool TryFetchNode(TransportNodeIdInterop nodeIdInterop, out TransportNode node)
        {
            int incidentDirectedEdgeCount = NativeTransportApi_GetIncidentDirectedEdgeCountForNode(NativePluginRunner.API, nodeIdInterop);

            if (incidentDirectedEdgeCount < 0)
            {
                node = TransportNode.MakeEmpty();
                return(false);
            }

            var incidentDirectedEdgeIdInteropBuffer         = new TransportDirectedEdgeIdInterop[incidentDirectedEdgeCount];
            var incidentDirectedEdgeIdInteropBufferGCHandle = GCHandle.Alloc(incidentDirectedEdgeIdInteropBuffer, GCHandleType.Pinned);
            var incidentDirectedEdgeIdInteropPtr            = incidentDirectedEdgeIdInteropBufferGCHandle.AddrOfPinnedObject();

            var nodeInterop = new TransportNodeInterop()
            {
                Id = nodeIdInterop,
                IncidentDirectedEdgeIdsSize = incidentDirectedEdgeCount,
                IncidentDirectedEdgeIds     = incidentDirectedEdgeIdInteropPtr
            };

            bool success = NativeTransportApi_TryGetNode(NativePluginRunner.API, ref nodeInterop);

            if (!success)
            {
                node = TransportNode.MakeEmpty();
                return(false);
            }

            var incidedDirectedEdgeIds = incidentDirectedEdgeIdInteropBuffer.Select(_x => _x.FromInterop()).ToList();

            node = new TransportNode(
                nodeInterop.Id.FromInterop(),
                nodeInterop.Point,
                incidedDirectedEdgeIds
                );

            incidentDirectedEdgeIdInteropBufferGCHandle.Free();

            return(true);
        }
        private IList <TransportDirectedEdgeIdInterop> FetchDirectedEdgeIdsForNetworkInCell(TransportNetworkType transportNetwork, MortonKeyInterop cellKeyInterop)
        {
            int directedEdgeCount = NativeTransportApi_GetDirectedEdgeCountForNetworkInCell(NativePluginRunner.API, transportNetwork, cellKeyInterop);

            if (directedEdgeCount <= 0)
            {
                return(new List <TransportDirectedEdgeIdInterop>());
            }

            var directedEdgeIdInteropBuffer         = new TransportDirectedEdgeIdInterop[directedEdgeCount];
            var directedEdgeIdInteropBufferGCHandle = GCHandle.Alloc(directedEdgeIdInteropBuffer, GCHandleType.Pinned);
            var directedEdgeIdInteropBufferPtr      = directedEdgeIdInteropBufferGCHandle.AddrOfPinnedObject();
            var directedEdgeSuccess = NativeTransportApi_TryGetDirectedEdgeIdsForNetworkInCell(NativePluginRunner.API, transportNetwork, cellKeyInterop, directedEdgeCount, directedEdgeIdInteropBufferPtr);

            if (!directedEdgeSuccess)
            {
                throw new System.ArgumentOutOfRangeException("incorrect buffer size passed for directed edge ids");
            }

            directedEdgeIdInteropBufferGCHandle.Free();

            return(directedEdgeIdInteropBuffer);
        }
        private bool TryFetchDirectedEdge(TransportDirectedEdgeIdInterop directedEdgeIdInterop, out TransportDirectedEdge directedEdge)
        {
            var directedEdgeInterop = new TransportDirectedEdgeInterop()
            {
                Id = directedEdgeIdInterop
            };

            bool success = NativeTransportApi_TryGetDirectedEdge(NativePluginRunner.API, ref directedEdgeInterop);

            if (!success)
            {
                directedEdge = TransportDirectedEdge.MakeEmpty();
                return(false);
            }

            directedEdge = new TransportDirectedEdge(
                directedEdgeInterop.Id.FromInterop(),
                directedEdgeInterop.NodeIdA.FromInterop(),
                directedEdgeInterop.NodeIdB.FromInterop(),
                directedEdgeInterop.WayId.FromInterop(),
                directedEdgeInterop.IsWayReversed
                );
            return(true);
        }