Паззл из стран Mercator. Подготовка данных (ruby)

Jul 18, 2013 21:28 · 394 words · 2 minute read mercator

Содержание:

KML лого Итак, у нас есть XML файл с координатами стран, теперь хорошо бы его загнать в базу данных. В нашем случае это PostgreSQL. Делать мы это будем с помощью замечательного языка Ruby. Для этого установим gem для работы с Postgres по имени pg (неожиданно, правда?):

$ gem install pg

Но для начала создадим структуру БД:

-- создадим пользователя mercator
CREATE ROLE mercator LOGIN NOSUPERUSER INHERIT CREATEDB NOCREATEROLE NOREPLICATION;

-- добавим ему схему
CREATE SCHEMA mercator AUTHORIZATION mercator;

-- последовательность для таблицы стран
CREATE SEQUENCE countries_seq INCREMENT 1 MINVALUE 1 MAXVALUE 9223372036854775807
  START 1 CACHE 1;
ALTER TABLE countries_seq OWNER TO mercator;

-- создадим таблицу стран
CREATE TABLE "Countries"(
 "ID" integer NOT NULL DEFAULT nextval('countries_seq'::regclass),
 "Name" character varying(50) NOT NULL, -- имя страны
 "Level" character varying, -- кажется, масштаб, но пока не используется
 "Polygon" character varying[], -- список полигонов в виде строк
 "Available" boolean, -- доступность для игры
 "Answer" character varying(50), -- хранение ответа
 CONSTRAINT "CountriesID" PRIMARY KEY ("ID" )
) WITH (OIDS=FALSE);
ALTER TABLE "Countries" OWNER TO mercator;

Теперь можно попробовать подключиться через пользователя mercator/mercator:

require 'pg'
$connection = PG::Connection.new( :host => '127.0.0.1', :port => 5432,
  :dbname => 'mercator', :user => 'mercator', :password => 'mercator')
$connection.prepare('stm', 'INSERT INTO "Countries"("Name", "Polygon", "Answer") values ($1, ARRAY[$2], $3)')

Знак доллара в имени переменной означает, что она глобальна. Осталось распарсить KML-файл, преобразовать полигоны из массива в строку (для каждой страны!), сгенерировать ответ и поместить всё это добро в таблицу:

require 'rexml/document'
xmldoc = Document.new(File.new("countries_world.xml"))
xmldoc.elements.each("kml/Document/Placemark"){
 |e|
  name = e.elements["name"].text
  puts "Processing " + name
  gmapPolygon = getPolygons(e)
  answer = getAnswer(e)
  $connection.exec_prepared('stm', [name, gmapPolygon, answer])
}

Целиком код можно посмотреть на github. Уточню разве что небольшие детали:

  • конвертация из массива координат в строку для GoogleMapsAPI делал этой утилитой, причём там важно следить что идёт первым в кортеже - широта или долгота;
  • ответ представляет собой 4 координаты (прямоугольник), в который помещается страна. Для упрощения задачи игроку я прибавил с каждой стороны по одному градусу (долготы или широты). В связи с этим, кстати, возникла проблема с Канадой и Россией - у них северные координаты располагаются уж больно близко к полюсу и попасть в такой прямоугольник становится невозможно.

Теперь у нас есть страны в базе данных. В следующей статье посмотрим как их можно доставать с помощью erlang, генерировать js и отдавать клиенту.

UPD

GeoPuzzle Проект переписан на другие технологии, улучшен и запущен на сайте https://geopuzzle.org.