Exemple #1
0
        /// <summary>
        /// Loads a vertex and returns true if found.
        /// </summary>
        /// <param name="vertexId"></param>
        /// <param name="latitude"></param>
        /// <param name="longitude"></param>
        /// <returns></returns>
        private bool LoadVertex(uint vertexId, out float latitude, out float longitude)
        {
            uint    blockId = CHBlock.CalculateId(vertexId, _blockSize);
            CHBlock block;

            if (!_blocks.TryGet(blockId, out block))
            { // damn block not cached!
                block = this.DeserializeBlock(blockId);
                if (block == null)
                { // oops even now the block is not found!
                    longitude = 0;
                    latitude  = 0;
                    return(false);
                }
                _blocks.Add(blockId, block);
            }
            uint blockIdx = vertexId - blockId;

            if (block.Vertices != null &&
                blockIdx < block.Vertices.Length)
            { // block is found and the vertex is there!
                latitude  = block.Vertices[blockIdx].Latitude;
                longitude = block.Vertices[blockIdx].Longitude;
                return(true);
            }
            // oops even now the block is not found!
            longitude = 0;
            latitude  = 0;
            return(false);
        }
        /// <summary>
        /// Loads all arcs but no shapes associated with the given vertex.
        /// </summary>
        /// <param name="vertexId"></param>
        /// <returns></returns>
        private KeyValuePair <uint, CHEdgeData>[] LoadArcsNoShapes(uint vertexId)
        {
            uint    blockId = CHBlock.CalculateId(vertexId, _blockSize);
            CHBlock block;

            if (!_blocks.TryGet(blockId, out block))
            { // damn block not cached!
                block = this.DeserializeBlock(blockId);
                if (block == null)
                { // oops even now the block is not found!
                    return(new KeyValuePair <uint, CHEdgeData> [0]);
                }
                _blocks.Add(blockId, block);
            }
            uint blockIdx = vertexId - blockId;

            if (block.Vertices != null &&
                blockIdx < block.Vertices.Length)
            { // block is found and the vertex is there!
                var arcs = new KeyValuePair <uint, CHEdgeData> [
                    block.Vertices[blockIdx].ArcCount];
                for (int arcIdx = block.Vertices[blockIdx].ArcIndex;
                     arcIdx < block.Vertices[blockIdx].ArcIndex + block.Vertices[blockIdx].ArcCount; arcIdx++)
                { // loop over all arcs.
                    var chArc    = block.Arcs[arcIdx];
                    var edgeData = new CHEdgeData(chArc.Value, chArc.Weight, chArc.Meta);
                    arcs[arcIdx - block.Vertices[blockIdx].ArcIndex] = new KeyValuePair <uint, CHEdgeData>(
                        chArc.TargetId, edgeData);
                }
                return(arcs);
            }
            // oops even now the block is not found!
            return(new KeyValuePair <uint, CHEdgeData> [0]);
        }
        /// <summary>
        /// Loads the edge between the given vertices.
        /// </summary>
        /// <param name="vertex1"></param>
        /// <param name="vertex2"></param>
        /// <param name="data"></param>
        /// <returns></returns>
        private bool LoadArc(uint vertex1, uint vertex2, out CHEdgeData data)
        {
            uint    blockId = CHBlock.CalculateId(vertex1, _blockSize);
            CHBlock block;

            if (!_blocks.TryGet(blockId, out block))
            { // damn block not cached!
                block = this.DeserializeBlock(blockId);
                if (block == null)
                { // oops even now the block is not found!
                    data = new CHEdgeData();
                    return(false);
                }
                _blocks.Add(blockId, block);
            }
            uint blockIdx = vertex1 - blockId;

            if (block.Vertices != null &&
                blockIdx < block.Vertices.Length)
            { // block is found and the vertex is there!
                for (int arcIdx = block.Vertices[blockIdx].ArcIndex;
                     arcIdx < block.Vertices[blockIdx].ArcIndex + block.Vertices[blockIdx].ArcCount; arcIdx++)
                { // loop over all arcs.
                    var chArc = block.Arcs[arcIdx];
                    if (chArc.TargetId == vertex2)
                    {
                        data = new CHEdgeData(chArc.Value, chArc.Weight, chArc.Meta);
                        return(true);
                    }
                }
            }
            blockId = CHBlock.CalculateId(vertex2, _blockSize);
            if (!_blocks.TryGet(blockId, out block))
            { // damn block not cached!
                block = this.DeserializeBlock(blockId);
                if (block == null)
                { // oops even now the block is not found!
                    data = new CHEdgeData();
                    return(false);
                }
                _blocks.Add(blockId, block);
            }
            blockIdx = vertex2 - blockId;
            if (block.Vertices != null &&
                blockIdx < block.Vertices.Length)
            { // block is found and the vertex is there!
                for (int arcIdx = block.Vertices[blockIdx].ArcIndex;
                     arcIdx < block.Vertices[blockIdx].ArcIndex + block.Vertices[blockIdx].ArcCount; arcIdx++)
                { // loop over all arcs.
                    var chArc = block.Arcs[arcIdx];
                    if (chArc.TargetId == vertex1)
                    {
                        data = new CHEdgeData(chArc.Value, chArc.Weight, chArc.Meta);
                        return(true);
                    }
                }
            }
            data = new CHEdgeData();
            return(false);
        }
Exemple #4
0
        /// <summary>
        /// Deserializes the given block of data.
        /// </summary>
        /// <param name="stream"></param>
        /// <param name="offset"></param>
        /// <param name="length"></param>
        /// <param name="decompress"></param>
        /// <returns></returns>
        internal CHBlock DeserializeBlock(Stream stream, long offset, int length, bool decompress)
        {
            CHBlock value = null;

            if (decompress)
            { // decompress the data.
                var buffer = new byte[length];
                stream.Seek(offset, SeekOrigin.Begin);
                stream.Read(buffer, 0, length);

                var memoryStream = new MemoryStream(buffer);
                var gZipStream   = new GZipStream(memoryStream, CompressionMode.Decompress);
                value = (CHBlock)_runtimeTypeModel.Deserialize(gZipStream, null, typeof(CHBlock));
            }
            else
            {
                value = (CHBlock)_runtimeTypeModel.Deserialize(
                    new CappedStream(stream, offset, length), null,
                    typeof(CHBlock));
            }
            return(value);
        }
        /// <summary>
        /// Loads the reverses for the given vertex.
        /// </summary>
        /// <param name="vertex"></param>
        /// <returns></returns>
        private uint[] LoadVertexReverses(uint vertex)
        {
            uint           blockId = CHBlock.CalculateId(vertex, _blockSize);
            CHBlockReverse blockReverses;

            if (!_blockReverses.TryGet(blockId, out blockReverses))
            { // damn block not cached!
                blockReverses = this.DeserializeReverse(blockId);
                if (blockReverses == null)
                { // oops even now the block is not found!
                    return(new uint[0]);
                }
                _blockReverses.Add(blockId, blockReverses);
                uint blockIdx = vertex - blockId;
                var  vertices = blockReverses.Vertices[blockIdx].Neighbours;
                if (vertices != null)
                {
                    return(vertices);
                }
            }
            return(new uint[0]);
        }
        /// <summary>
        /// Does the v2 serialization.
        /// </summary>
        /// <param name="stream"></param>
        /// <param name="graph"></param>
        /// <returns></returns>
        protected override void DoSerialize(LimitedStream stream,
                                            DynamicGraphRouterDataSource <CHEdgeData> graph)
        {
            // sort the graph.
            IDynamicGraph <CHEdgeData> sortedGraph = CHEdgeDataDataSourceSerializer.SortGraph(graph);

            // create the regions.
            SortedDictionary <ulong, List <uint> > regions = new SortedDictionary <ulong, List <uint> >();

            for (uint newVertexId = 1; newVertexId < sortedGraph.VertexCount + 1; newVertexId++)
            {
                // add to the CHRegions.
                float latitude, longitude;
                sortedGraph.GetVertex(newVertexId, out latitude, out longitude);
                Tile tile = Tile.CreateAroundLocation(new GeoCoordinate(
                                                          latitude, longitude), RegionZoom);
                List <uint> regionVertices;
                if (!regions.TryGetValue(tile.Id, out regionVertices))
                {
                    regionVertices = new List <uint>();
                    regions.Add(tile.Id, regionVertices);
                }
                regionVertices.Add(newVertexId);
            }

            // serialize the sorted graph.
            // [START_OF_BLOCKS][[SIZE_OF_REGION_INDEX][REGION_INDEX][REGIONS]][[SIZE_OF_BLOCK_INDEX][BLOCK_INDEX][BLOCKS]]
            // STRART_OF_BLOCKS:        4bytes

            // SIZE_OF_REGION_INDEX:    4bytes
            // REGION_INDEX:            see SIZE_OF_REGION_INDEX
            // REGIONS:                 see START_OF_BLOCKS - 4bytes

            // SIZE_OF_BLOCK_INDEX:     4bytes
            // BLOCK_INDEX:             see SIZE_OF_BLOCK_INDEX.
            // BLOCKS:                  from START_OF_BLOCKS + 4bytes + SIZE_OF_BLOCKS_INDEX until END.

            // serialize regions and build their index.
            CHVertexRegionIndex chRegionIndex = new CHVertexRegionIndex();

            chRegionIndex.LocationIndex = new int[regions.Count];
            chRegionIndex.RegionIds     = new ulong[regions.Count];
            var memoryStream = new MemoryStream();
            int regionIdx    = 0;

            foreach (KeyValuePair <ulong, List <uint> > region in regions)
            {
                // serialize.
                CHVertexRegion chRegion = new CHVertexRegion();
                chRegion.Vertices = region.Value.ToArray();
                _runtimeTypeModel.Serialize(memoryStream, chRegion);

                // set index.
                chRegionIndex.LocationIndex[regionIdx] = (int)memoryStream.Position;
                chRegionIndex.RegionIds[regionIdx]     = region.Key;
                regionIdx++;
            }
            stream.Seek(8, SeekOrigin.Begin);                   // move to beginning of [REGION_INDEX]
            _runtimeTypeModel.Serialize(stream, chRegionIndex); // write region index.
            int sizeRegionIndex = (int)(stream.Position - 8);   // now at beginning of [REGIONS]

            memoryStream.Seek(0, SeekOrigin.Begin);
            memoryStream.WriteTo(stream);                               // write regions.
            memoryStream.Dispose();
            int startOfBlocks = (int)stream.Position;                   // now at beginning of [SIZE_OF_BLOCK_INDEX]

            stream.Seek(0, SeekOrigin.Begin);                           // move to beginning
            stream.Write(BitConverter.GetBytes(startOfBlocks), 0, 4);   // write start position of blocks. Now at [SIZE_OF_REGION_INDEX]
            stream.Write(BitConverter.GetBytes(sizeRegionIndex), 0, 4); // write size of blocks index.

            // serialize the blocks and build their index.
            memoryStream = new MemoryStream();
            List <int> blockLocations = new List <int>();
            uint       vertexId       = 1;

            while (vertexId < sortedGraph.VertexCount)
            {
                uint            blockId       = vertexId;
                List <CHArc>    blockArcs     = new List <CHArc>();
                List <CHVertex> blockVertices = new List <CHVertex>();
                while (vertexId < blockId + BlockVertexSize &&
                       vertexId < sortedGraph.VertexCount + 1)
                { // create this block.
                    CHVertex chVertex = new CHVertex();
                    float    latitude, longitude;
                    sortedGraph.GetVertex(vertexId, out latitude, out longitude);
                    chVertex.Latitude  = latitude;
                    chVertex.Longitude = longitude;
                    chVertex.ArcIndex  = (ushort)(blockArcs.Count);
                    foreach (KeyValuePair <uint, CHEdgeData> sortedArc in sortedGraph.GetArcs(vertexId))
                    {
                        CHArc chArc = new CHArc();
                        chArc.TargetId   = sortedArc.Key;
                        chArc.ShortcutId = sortedArc.Value.ContractedVertexId;
                        chArc.Weight     = sortedArc.Value.Weight;
                        chArc.Direction  = sortedArc.Value.Direction;
                        blockArcs.Add(chArc);
                    }
                    chVertex.ArcCount = (ushort)(blockArcs.Count - chVertex.ArcIndex);
                    blockVertices.Add(chVertex);

                    vertexId++; // move to the next vertex.
                }

                // create block.
                CHBlock block = new CHBlock();
                block.Arcs     = blockArcs.ToArray();
                block.Vertices = blockVertices.ToArray(); // TODO: get rid of the list and create an array to begin with.

                // write blocks.
                _runtimeTypeModel.Serialize(memoryStream, block);
                blockLocations.Add((int)memoryStream.Position);
            }
            CHBlockIndex blockIndex = new CHBlockIndex();

            blockIndex.LocationIndex = blockLocations.ToArray();

            stream.Seek(startOfBlocks + 4, SeekOrigin.Begin);                  // move to beginning of [BLOCK_INDEX]
            _runtimeTypeModel.Serialize(stream, blockIndex);                   // write region index.
            int sizeBlockIndex = (int)(stream.Position - (startOfBlocks + 4)); // now at beginning of [BLOCKS]

            memoryStream.Seek(0, SeekOrigin.Begin);
            memoryStream.WriteTo(stream);                              // write blocks.
            memoryStream.Dispose();
            stream.Seek(startOfBlocks, SeekOrigin.Begin);              // move to [SIZE_OF_BLOCK_INDEX]
            stream.Write(BitConverter.GetBytes(sizeBlockIndex), 0, 4); // write start position of blocks. Now at [SIZE_OF_REGION_INDEX]
            stream.Flush();
        }
Exemple #7
0
        /// <summary>
        /// Does the v2 serialization.
        /// </summary>
        /// <param name="stream"></param>
        /// <param name="graph"></param>
        /// <returns></returns>
        protected override void DoSerialize(LimitedStream stream,
                                            DynamicGraphRouterDataSource <CHEdgeData> graph)
        {
            // sort the graph.
            var sortedGraph = graph;

            // create the regions.
            var regions = new SortedDictionary <ulong, List <uint> >();

            for (uint newVertexId = 1; newVertexId < sortedGraph.VertexCount + 1; newVertexId++)
            {
                // add to the CHRegions.
                float latitude, longitude;
                sortedGraph.GetVertex(newVertexId, out latitude, out longitude);
                var tile = Tile.CreateAroundLocation(new GeoCoordinate(
                                                         latitude, longitude), _regionZoom);
                List <uint> regionVertices;
                if (!regions.TryGetValue(tile.Id, out regionVertices))
                {
                    regionVertices = new List <uint>();
                    regions.Add(tile.Id, regionVertices);
                }
                regionVertices.Add(newVertexId);
            }

            // serialize the sorted graph.
            // [START_OF_BLOCKS][START_OF_SHAPES][START_OF_REVERSE][START_OF_TAGS][[SIZE_OF_REGION_INDEX][REGION_INDEX][REGIONS]]
            //                                                                    [[SIZE_OF_BLOCK_INDEX][BLOCK_INDEX][BLOCKS]]
            //                                                                    [[SIZE_OF_SHAPE_INDEX][SHAPE_INDEX][SHAPES]]
            //                                                                    [[SIZE_OF_REVERSE_INDEX][REVERSE_INDEX][REVERSE]]
            //                                                                    [TAGS]
            // START_OF_BLOCKS:         4bytes
            // START_OF_SHAPES:         4bytes
            // START_OF_STAGS:          4bytes
            // START_OF_REVERSE         4bytes

            // SIZE_OF_REGION_INDEX:    4bytes
            // REGION_INDEX:            see SIZE_OF_REGION_INDEX
            // REGIONS:                 see START_OF_BLOCKS - 4bytes

            // SIZE_OF_BLOCK_INDEX:     4bytes
            // BLOCK_INDEX:             see SIZE_OF_BLOCK_INDEX.
            // BLOCKS:                  from START_OF_BLOCKS + 4bytes + SIZE_OF_BLOCKS_INDEX until END.

            // serialize regions and build their index.
            var chRegionIndex = new CHVertexRegionIndex();

            chRegionIndex.LocationIndex = new int[regions.Count];
            chRegionIndex.RegionIds     = new ulong[regions.Count];
            var memoryStream = new MemoryStream();
            int regionIdx    = 0;

            foreach (var region in regions)
            {
                // serialize.
                var chRegion = new CHVertexRegion();
                chRegion.Vertices = region.Value.ToArray();
                _runtimeTypeModel.Serialize(memoryStream, chRegion);

                // set index.
                chRegionIndex.LocationIndex[regionIdx] = (int)memoryStream.Position;
                chRegionIndex.RegionIds[regionIdx]     = region.Key;
                regionIdx++;
            }
            stream.Seek(INDEX_SIZE, SeekOrigin.Begin);                 // move to beginning of [REGION_INDEX]
            _runtimeTypeModel.Serialize(stream, chRegionIndex);        // write region index.
            var sizeRegionIndex = (int)(stream.Position - INDEX_SIZE); // now at beginning of [REGIONS]

            memoryStream.Seek(0, SeekOrigin.Begin);
            memoryStream.WriteTo(stream);             // write regions.
            memoryStream.Dispose();
            var startOfBlocks = (int)stream.Position; // now at beginning of [SIZE_OF_BLOCK_INDEX]

            // serialize the blocks and build their index.
            memoryStream = new MemoryStream();
            var  blocks                = new List <CHBlock>();
            var  blockLocations        = new List <int>();
            var  blockShapeLocations   = new List <int>();
            var  blockReverseLocations = new List <int>();
            var  blockShapes           = new List <CHBlockCoordinates>();
            var  reverseNeighbours     = new Dictionary <uint, List <uint> >();
            uint vertexId              = 1;

            while (vertexId < sortedGraph.VertexCount + 1)
            {
                uint blockId             = vertexId;
                var  blockArcs           = new List <CHArc>();
                var  blockArcCoordinates = new List <CHArcCoordinates>();
                var  blockVertices       = new List <CHVertex>();
                while (vertexId < blockId + _blockVertexSize &&
                       vertexId < sortedGraph.VertexCount + 1)
                { // create this block.
                    var   chVertex = new CHVertex();
                    float latitude, longitude;
                    sortedGraph.GetVertex(vertexId, out latitude, out longitude);
                    chVertex.Latitude  = latitude;
                    chVertex.Longitude = longitude;
                    chVertex.ArcIndex  = (ushort)(blockArcs.Count);
                    List <uint> reverse = null;
                    foreach (var sortedArc in sortedGraph.GetEdges(vertexId))
                    {
                        var chArc = new CHArc();
                        chArc.TargetId = sortedArc.Neighbour;
                        chArc.Meta     = sortedArc.EdgeData.Meta;
                        chArc.Value    = sortedArc.EdgeData.Value;
                        chArc.Weight   = sortedArc.EdgeData.Weight;
                        blockArcs.Add(chArc);

                        var chArcCoordinates = new CHArcCoordinates();
                        chArcCoordinates.Coordinates = sortedArc.Intermediates.ToSimpleArray();
                        blockArcCoordinates.Add(chArcCoordinates);

                        if (sortedArc.EdgeData.RepresentsNeighbourRelations)
                        {
                            if (!reverseNeighbours.TryGetValue(sortedArc.Neighbour, out reverse))
                            {
                                reverse = new List <uint>();
                                reverseNeighbours[sortedArc.Neighbour] = reverse;
                            }
                            reverse.Add(vertexId);
                        }
                    }
                    chVertex.ArcCount = (ushort)(blockArcs.Count - chVertex.ArcIndex);
                    blockVertices.Add(chVertex);

                    vertexId++; // move to the next vertex.
                }

                // create block.
                var block = new CHBlock();
                block.Arcs     = blockArcs.ToArray();
                block.Vertices = blockVertices.ToArray(); // TODO: get rid of the list and create an array to begin with.
                blocks.Add(block);
                var blockCoordinates = new CHBlockCoordinates();
                blockCoordinates.Arcs = blockArcCoordinates.ToArray();

                // write blocks.
                var blockStream = new MemoryStream();
                _runtimeTypeModel.Serialize(blockStream, block);
                var compressed = GZipStream.CompressBuffer(blockStream.ToArray());
                blockStream.Dispose();

                memoryStream.Write(compressed, 0, compressed.Length);
                blockLocations.Add((int)memoryStream.Position);

                blockShapes.Add(blockCoordinates);
            }
            var blockIndex = new CHBlockIndex();

            blockIndex.BlockLocationIndex = blockLocations.ToArray();

            stream.Seek(startOfBlocks + 4, SeekOrigin.Begin);                  // move to beginning of [BLOCK_INDEX]
            _runtimeTypeModel.Serialize(stream, blockIndex);                   // write block index.
            int sizeBlockIndex = (int)(stream.Position - (startOfBlocks + 4)); // now at beginning of [BLOCKS]

            memoryStream.Seek(0, SeekOrigin.Begin);
            memoryStream.WriteTo(stream); // write blocks.
            memoryStream.Dispose();

            // write shapes and index.
            memoryStream = new MemoryStream();
            var startOfShapes = stream.Position;

            foreach (var blockCoordinates in blockShapes)
            {
                // write shape blocks.
                var blockShapeStream = new MemoryStream();
                _runtimeTypeModel.Serialize(blockShapeStream, blockCoordinates);
                var compressed = GZipStream.CompressBuffer(blockShapeStream.ToArray());
                blockShapeStream.Dispose();

                memoryStream.Write(compressed, 0, compressed.Length);
                blockShapeLocations.Add((int)memoryStream.Position);
            }
            blockIndex = new CHBlockIndex();
            blockIndex.BlockLocationIndex = blockShapeLocations.ToArray();

            stream.Seek(startOfShapes + 4, SeekOrigin.Begin);                  // move to beginning of [SHAPE_INDEX]
            _runtimeTypeModel.Serialize(stream, blockIndex);                   // write shape index.
            int sizeShapeIndex = (int)(stream.Position - (startOfShapes + 4)); // now at beginning of [SHAPE]

            memoryStream.Seek(0, SeekOrigin.Begin);
            memoryStream.WriteTo(stream); // write shapes.
            memoryStream.Dispose();

            // build reverse blocks.
            var         blockReverses   = new List <CHBlockReverse>();
            List <uint> storedReverses  = null;
            uint        currentVertexId = 0;

            for (int i = 0; i < blocks.Count; i++)
            {
                var blockReverse = new CHBlockReverse();
                blockReverse.Vertices = new CHArcReverse[blocks[i].Vertices.Length];
                for (int j = 0; j < blocks[i].Vertices.Length; j++)
                {
                    currentVertexId++;
                    var blockReverseArc = new CHArcReverse();
                    blockReverseArc.Neighbours = new uint[0];
                    if (reverseNeighbours.TryGetValue(currentVertexId, out storedReverses))
                    {
                        blockReverseArc.Neighbours = storedReverses.ToArray();
                    }
                    blockReverse.Vertices[j] = blockReverseArc;
                }
                blockReverses.Add(blockReverse);
            }

            // write reverse and index.
            memoryStream = new MemoryStream();
            var startOfReverses = stream.Position;

            foreach (var blockReverse in blockReverses)
            {
                // write reverse blocks.
                var blockReverseStream = new MemoryStream();
                _runtimeTypeModel.Serialize(blockReverseStream, blockReverse);
                var compressed = GZipStream.CompressBuffer(blockReverseStream.ToArray());
                blockReverseStream.Dispose();

                memoryStream.Write(compressed, 0, compressed.Length);
                blockReverseLocations.Add((int)memoryStream.Position);
            }
            blockIndex = new CHBlockIndex();
            blockIndex.BlockLocationIndex = blockReverseLocations.ToArray();

            stream.Seek(startOfReverses + 4, SeekOrigin.Begin);                    // move to beginning of [REVERSE_INDEX]
            _runtimeTypeModel.Serialize(stream, blockIndex);                       // write reverse index.
            int sizeReverseIndex = (int)(stream.Position - (startOfReverses + 4)); // now at beginning of [REVERSE]

            memoryStream.Seek(0, SeekOrigin.Begin);
            memoryStream.WriteTo(stream); // write reverses.
            memoryStream.Dispose();

            // write tags after reverses.
            int tagsPosition = (int)stream.Position;

            TagIndexSerializer.SerializeBlocks(stream, graph.TagsIndex, 10);

            stream.Seek(startOfBlocks, SeekOrigin.Begin);                // move to [SIZE_OF_BLOCK_INDEX]
            stream.Write(BitConverter.GetBytes(sizeBlockIndex), 0, 4);   // write start position of blocks.
            stream.Seek(startOfShapes, SeekOrigin.Begin);                // move to [SIZE_OF_BLOCK_INDEX]
            stream.Write(BitConverter.GetBytes(sizeShapeIndex), 0, 4);   // write start position of blocks.
            stream.Seek(startOfReverses, SeekOrigin.Begin);              // move to [SIZE_OF_REVERSE_INDEX]
            stream.Write(BitConverter.GetBytes(sizeReverseIndex), 0, 4); // write start position of blocks.

            // write index.
            stream.Seek(0, SeekOrigin.Begin);                           // move to beginning
            stream.Write(BitConverter.GetBytes(startOfBlocks), 0, 4);   // write start position of blocks.
            stream.Write(BitConverter.GetBytes(startOfShapes), 0, 4);   // write start position of shapes.
            stream.Write(BitConverter.GetBytes(startOfReverses), 0, 4); // write start position of shapes.
            stream.Write(BitConverter.GetBytes(tagsPosition), 0, 4);
            stream.Write(BitConverter.GetBytes(sizeRegionIndex), 0, 4); // write size of region index.
            stream.Flush();
        }
        /// <summary>
        /// Loads the edge between the given vertices.
        /// </summary>
        /// <param name="vertex1"></param>
        /// <param name="vertex2"></param>
        /// <param name="shape"></param>
        /// <returns></returns>
        private bool LoadArcShape(uint vertex1, uint vertex2, out ICoordinateCollection shape)
        {
            uint blockId = CHBlock.CalculateId(vertex1, _blockSize);
            CHBlockCoordinates blockCoordinates;

            if (!_blockShapes.TryGet(blockId, out blockCoordinates))
            { // damn block not cached!
                blockCoordinates = this.DeserializeShape(blockId);
                if (blockCoordinates == null)
                { // oops even now the block is not found!
                    shape = null;
                    return(false);
                }
                _blockShapes.Add(blockId, blockCoordinates);
            }
            CHBlock block;

            if (!_blocks.TryGet(blockId, out block))
            { // damn block not cached!
                block = this.DeserializeBlock(blockId);
                if (block == null)
                { // oops even now the block is not found!
                    shape = null;
                    return(false);
                }
                _blocks.Add(blockId, block);
            }
            uint blockIdx = vertex1 - blockId;

            if (block.Vertices != null &&
                blockIdx < block.Vertices.Length)
            { // block is found and the vertex is there!
                for (int arcIdx = block.Vertices[blockIdx].ArcIndex;
                     arcIdx < block.Vertices[blockIdx].ArcIndex + block.Vertices[blockIdx].ArcCount; arcIdx++)
                { // loop over all arcs.
                    var chArc = block.Arcs[arcIdx];
                    if (chArc.TargetId == vertex2)
                    {
                        var arcCoordinates = blockCoordinates.Arcs[arcIdx];
                        shape = null;
                        if (arcCoordinates.Coordinates != null)
                        {
                            shape = new CoordinateArrayCollection <GeoCoordinateSimple>(arcCoordinates.Coordinates);
                        }
                        return(true);
                    }
                }
            }
            blockId = CHBlock.CalculateId(vertex2, _blockSize);
            if (!_blocks.TryGet(blockId, out block))
            { // damn block not cached!
                block = this.DeserializeBlock(blockId);
                if (block == null)
                { // oops even now the block is not found!
                    shape = null;
                    return(false);
                }
                _blocks.Add(blockId, block);
            }
            if (!_blockShapes.TryGet(blockId, out blockCoordinates))
            { // damn block not cached!
                blockCoordinates = this.DeserializeShape(blockId);
                if (blockCoordinates == null)
                { // oops even now the block is not found!
                    shape = null;
                    return(false);
                }
                _blockShapes.Add(blockId, blockCoordinates);
            }
            blockIdx = vertex2 - blockId;
            if (block.Vertices != null &&
                blockIdx < block.Vertices.Length)
            { // block is found and the vertex is there!
                for (int arcIdx = block.Vertices[blockIdx].ArcIndex;
                     arcIdx < block.Vertices[blockIdx].ArcIndex + block.Vertices[blockIdx].ArcCount; arcIdx++)
                { // loop over all arcs.
                    var chArc = block.Arcs[arcIdx];
                    if (chArc.TargetId == vertex1)
                    {
                        var arcCoordinates = blockCoordinates.Arcs[arcIdx];
                        shape = null;
                        if (arcCoordinates.Coordinates != null)
                        {
                            shape = new CoordinateArrayCollection <GeoCoordinateSimple>(arcCoordinates.Coordinates);
                        }
                        return(true);
                    }
                }
            }
            shape = null;
            return(false);
        }