Обработка и визуализация геоданных

Косточко Дмитрий

Обработка и визуализация геоданных

Косточко Дмитрий

Задача

Создание игрового мира и его отображение на странице.

Плюсы решения

Архитектура приложения

Генерация мира

  1. Разбиваем плоскость на полигоны.
  2. Определяем является ли полигон сушей.
  3. Генерируем карту высот.
  4. Генерируем реки.
  5. Рассчитываем биомы.
  6. Генерируем игровые объекты (города, страны).

Генерация случайных точек

Релаксация Ллойда

Строим диаграмму Вороного и нормализируем ребра

Создаем континенты, используя шум Перлина

Шум Перлина

Алгоритм генерации процедурной текстуры псевдослучайным методом. Используется в компьютерной графике для увеличения реализма текстур, генерации эффектов дыма, тумана и т.д.

Строим карту высот

Создание рек

Расчет осадков

Диаграмма биомов

Определяем биомы

Добавляем города и страны

Используемые библиотеки

Геоданные

Информация, которая имеет географическую (пространственную) привязку.

Преобразуем координаты

PostgreSQL/PostGIS + GeoDjango

			from django.contrib.gis.db import models
			 
			 
			class Biome(models.Model):
			    name = models.CharField(max_length=100)
			    biome = models.CharField(max_length=50, choices=BIOMES)
			    geom = models.MultiPolygonField(srid=4326)  # WGS 84
			 
			    objects = models.GeoManager()
			 
		

Mapnik

Открытая библиотека для рендеринга растровых карт из векторных данных.

http://mapnik.org/

mapnik_config.xml

			<Map>
			    <Style>
			        <Rule/>
			    <Style/>
			    <Layer>
			        <StyleName/>
			        <Datasource/>
			    </Layer>
			</Map>
		

mapnik_config.xml

		    <Rule>
		        <PolygonSymbolizer fill="#abceff"/>
		        <LineSymbolizer stroke="#abceff" stroke-width="1"  stroke-linejoin="round"/>
		        <Filter>[biome] = 'OCEAN'</Filter>
		    </Rule>
		     
		    <Rule>
		        <PolygonPatternSymbolizer file="./tiles/GRASSLAND.png"/>
		        <LineSymbolizer stroke-width="0"/>
		        <Filter>[biome] = 'GRASSLAND'</Filter>
		    </Rule>
		

CartoCSS (TileMill)

			#buildings {
			  [zoom >= 13] {
			    polygon-fill: @building-low-zoom;
			    polygon-clip: false;
			    [zoom >= 15] {
			      line-color: @building-line;
			      polygon-fill: @building-fill;
			      line-width: .75;
			      line-clip: false;
			    }
			  }
			}
		

Hillshade

Карта высот (2000 полигонов + шум)

Тайлы

Тайловый сервер

Рендерит и сохраняет в кэше тайлы, отдает их клиенту.

Подключаем карту на страницу с помощью Leaflet

			<div id="map" style="width: 1200px; height: 900px" />
			<script>
        	    var map = L.map('map').setView([0, 0], 4);
        	    L.tileLayer('http://127.0.0.1:8080/map/{z}/{x}/{y}.png').addTo(map);
        	</script>
		

GeoJSON

			{
			  "type": "Feature",
			  "geometry": {
			    "type": "Point",
			    "coordinates": [-10.3, 10.1]
			  },
			  "properties": {
			    "name": "Some capital",
			    "population": 10000
			  }
			}
		

Получаем данные в GeoJSON из базы данных

			from django.core.serializers import serialize
			 
			 
			def regions_data(request):
			    output = serialize('geojson', Region.objects.all(),
			                       geometry_field='geom', fields=('name', 'geom'))
			    return HttpResponse(output, content_type='text/json')
			 
		

Показываем страны на карте

	        $.getJSON(regionsURL, function(data) {
	            L.geoJson(data, {
	                onEachFeature: function (feature, layer) {
	                    layer.bindPopup(feature.properties.name, {maxWidth: 200});
	                },
	                style: function(feature) {
	                    return {
	                        "color": randomColor()
	                    };
	                }
	            }).addTo(map);
	        });
		

Что можно улучшить

Спасибо

Посмотреть код: https://github.com/Alerion/fantasy_map

Описание алгоритма: http://www-cs-students.stanford.edu/~amitp/game-programming/polygon-map-generation/