/// <summary>
        /// Generates a map based on the given tile location, generator settings and area spreads
        /// </summary>
        /// <param name="settings">Generator settings to modify the generation process</param>
        /// <param name="areas">Areas that should be placed on the map</param>
        /// <param name="tileColumn">Tile column index</param>
        /// <param name="tileRow">Tile row index</param>
        /// <returns>Returns a StreamedTileMap</returns>
        public StreamedTileMap GenerateMap(GeneratorSettings settings, AreaSpread[] areas, int tileColumn, int tileRow)
        {
            if (settings.Seed > 0)
            {
                random = new Random(settings.Seed);
            }
            else if (random == null)
            {
                throw new ArgumentOutOfRangeException();
            }

            this.settings = settings;
            spreads       = areas;

            double tilesPerGrid   = Math.Round(settings.MeterPerGrid / settings.MeterPerTile);
            int    tilesPerColumn = (int)tilesPerGrid;
            int    size           = tilesPerColumn * tilesPerColumn;
            int    gridsPerRow    = (int)Math.Ceiling(GetMapSize(settings) / tilesPerGrid);

            int gridColumn = (int)Math.Floor(tileColumn / tilesPerGrid);
            int gridRow    = (int)Math.Floor(tileRow / tilesPerGrid);

            Tile[][]            edgeOverrides = new Tile[9][];
            Tile[][]            maps          = new Tile[9][];
            List <ObjectTile>[] objectTiles   = new List <ObjectTile> [9];
            for (int i = 0; i < maps.Length; i++)
            {
                edgeOverrides[i] = new Tile[size];
                maps[i]          = new Tile[size];
                objectTiles[i]   = new List <ObjectTile>();
            }

            int[] suroundingGrids = CreateSuroundings(maps.Length, gridColumn, gridRow, gridsPerRow);

            StreamedTileMap streamedTileMap = new StreamedTileMap(this, tileRow, tileColumn, gridsPerRow, gridsPerRow, tilesPerColumn, tilesPerColumn, settings.TileSize);

            //Create Map
            foreach (LayerType currentLayerType in Enum.GetValues(typeof(LayerType)).Cast <LayerType>().OrderBy(k => (int)k))
            {
                for (int i = 0; i < suroundingGrids.Length; i++)
                {
                    AreaSpread[] layerAreas = areas.Where(a => a.Layer == currentLayerType).ToArray();
                    random = new Random(suroundingGrids[i] * settings.Seed);
                    for (int j = 0; j < layerAreas.Length; j++)
                    {
                        switch (layerAreas[j].Layer)
                        {
                        case LayerType.Height:
                        {
                            if (layerAreas[j].MaxSizeInMeter <= settings.MeterPerGrid / 2f)
                            {
                                CreateLayerOne(i, maps, edgeOverrides, (int)tilesPerGrid, (int)tilesPerGrid, settings.TileSize, settings.MeterPerTile, layerAreas[j], settings.RadiusOfCylinder);
                            }
                            else
                            {
                                throw new Exception("AreaSpread MaxSize must be smaller then (MetersPerGrid / 2)!");
                            }
                            break;
                        }

                        case LayerType.Biome:
                            CreateBiomeLayer(i, maps, layerAreas[j]);
                            break;

                        case LayerType.Paths:
                            CreateLayerFour();
                            break;

                        case LayerType.PointsOfInterest:
                        {
                            objectTiles[i].AddRange(CreateObjectLayer(maps[i], layerAreas[j], tilesPerColumn, tilesPerColumn));
                        }
                        break;
                        }
                    }
                }

                if (currentLayerType == LayerType.Height)
                {
                    //DefragementMap and add edgenoise
                    DefragmentMaps(maps, areas, suroundingGrids, (int)tilesPerGrid, (int)tilesPerGrid);

                    //Merge edgeOverrides
                    for (int k = 0; k < maps.Length; k++)
                    {
                        maps[k] = TileMathHelper.MergeMaps(maps[k], edgeOverrides[k]);
                    }
                }
            }

            CreateTileMapParts(maps, objectTiles, suroundingGrids, gridsPerRow, streamedTileMap);

            return(streamedTileMap);
        }