Set<Tuple<int, int, int>> GetVisibleTilesSet() {
            int iLevel = GetBackgroundTileLevel();
            GridTraversal grid = new GridTraversal(GeomGraph.BoundingBox, iLevel);
            var tiles = new Set<Triple>();
            var visibleRectangle = GetVisibleRectangleInGraph();

            var t1 = grid.PointToTuple(visibleRectangle.LeftBottom);
            var t2 = grid.PointToTuple(visibleRectangle.RightTop);

            for (int ix = t1.Item1; ix <= t2.Item1; ix++)
                for (int iy = t1.Item2; iy <= t2.Item2; iy++) {
                    var t = new Triple(iLevel, ix, iy);

                    TileType tileType;
                    if (!_tileDictionary.TryGetValue(t, out tileType)) continue;
                    if (tileType == TileType.Image) tiles.Insert(t);
                }

            return tiles;
        }
        IEnumerable<Triple> VectorTiles() {
            int iLevel = GetBackgroundTileLevel();
            GridTraversal grid = new GridTraversal(GeomGraph.BoundingBox, iLevel);
            var visibleRectangle = GetVisibleRectangleInGraph();

            var t1 = grid.PointToTuple(visibleRectangle.LeftBottom);
            var t2 = grid.PointToTuple(visibleRectangle.RightTop);

            for (int ix = t1.Item1; ix <= t2.Item1; ix++)
                for (int iy = t1.Item2; iy <= t2.Item2; iy++) {
                    var t = new Triple(iLevel, ix, iy);
                    TileType tileType;
                    if (!_tileDictionary.TryGetValue(t, out tileType)) continue;
                    if (tileType == TileType.Vector) 
                        yield return t;
                }
        }
        internal int TryInsertingNodesAndRoutes(int numNodesToInsert,
            Dictionary<SymmetricTuple<LgNodeInfo>, List<Point>> trajectories,
            List<SymmetricSegment> oldSegments,  
            int zoomLevel, int numNodesOnPreviousLevel,
            GridTraversal grid, LgPathRouter pathRouter)
        {
            MarkAllNodesNotProcessed();
            _segmentTileTable = new Dictionary<Tuple<int, int>, int>();
            _nodeTileTable = new Dictionary<Tuple<int, int>, int>();

            var canAddOldSegments = TryAddingOldSegments(oldSegments, grid);
            if (!canAddOldSegments)
            {
                return 0;
            }

            AddOldNodes(numNodesOnPreviousLevel, grid);

            int i;
            for (i = numNodesOnPreviousLevel; i < numNodesToInsert; i++)
            {
                var ni = SortedLgNodeInfos[i];
                var nodeTile = grid.PointToTuple(ni.Center);
                if (!_nodeTileTable.ContainsKey(nodeTile))
                    _nodeTileTable[nodeTile] = 0;

                if (_nodeTileTable[nodeTile] >= MaxNodesPerTile(zoomLevel)) //test MaxAmountNodesPerTile
                {
                    ShowDebugInsertedSegments(grid, zoomLevel, ni, null, null);

                    break;
                }

                Set<VisibilityEdge> edges = GetSegmentsOnPathsToInsertedNeighborsNotOnOldTrajectories(ni, trajectories,
                    pathRouter);

                Set<SymmetricSegment> segments = new Set<SymmetricSegment>(
                    edges.Select(e => new SymmetricSegment(e.SourcePoint, e.TargetPoint)));

                var newToAdd = segments.Where(seg => !IsSegmentAlreadyAdded(seg)).ToList();

                Set<SymmetricSegment> insertedSegments;
                bool canInsertPaths = TryAddingSegmentsUpdateTiles(newToAdd, grid, out insertedSegments);

                if (canInsertPaths) {

                    AddSegmentsToRtree(newToAdd);
                    ni.Processed = true;
                    _nodeTileTable[nodeTile]++;
                    _insertedNodes.Add(ni);
                    continue;
                }
                //debug output
                //AddSegmentsToRtree(newToAdd);   //remove
            //    ShowDebugInsertedSegments(grid, zoomLevel, ni, newToAdd, segments);
                break;
            }

            var nextNode = numNodesToInsert < SortedLgNodeInfos.Count ? SortedLgNodeInfos[numNodesToInsert] :
            null;
           // ShowDebugInsertedSegments(grid, zoomLevel, nextNode, null, null);

            return i;
        }
        void UpdateTilesCountInsertedNodes(int level, GridTraversal grid) {
            foreach (var node in _insertedNodes) {
                var tuple = grid.PointToTuple(node.Center);
                if (!_nodeTileTable.ContainsKey(tuple))
                    _nodeTileTable[tuple] = 0;

                _nodeTileTable[tuple]++;
            }
        }
        int DrawNodesOnlyOnLevel(int level, int startInd)
        {
            int iLevel = (int) Math.Log(level, 2);
            GridTraversal grid= new GridTraversal(BoundingBox, iLevel);
            UpdateTilesCountInsertedNodesOnly(level, grid);
            for (int i = startInd; i < SortedLgNodeInfos.Count; i++) {
                var ni = SortedLgNodeInfos[i];
                var tuple = grid.PointToTuple(ni.Center);
                if (!_nodeTileTable.ContainsKey(tuple))
                    _nodeTileTable[tuple] = 0;

                if (_nodeTileTable[tuple] >= MaxNodesPerTile(level)) {
                    return i;
                }

                PerformNodeInsertion(ni, tuple);
                ni.ZoomLevel = level;
            }

            return SortedLgNodeInfos.Count;
        }
        private void AddOldNodes(int numNodesOnPreviousLevel, GridTraversal grid) {
            for (int i = 0; i < numNodesOnPreviousLevel; i++) {
                var ni = SortedLgNodeInfos[i];
                var nodeTile = grid.PointToTuple(ni.Center);
                if (!_nodeTileTable.ContainsKey(nodeTile))
                    _nodeTileTable[nodeTile] = 0;

                ni.Processed = true;
                _nodeTileTable[nodeTile]++;
                _insertedNodes.Add(ni);
            }
        }