User:Zverik/Imagery Calibration
Итак, у нас есть проблема: отсутствие базы данных смещений, из-за чего каждому пользователю приходится снова и снова двигать подложку по трекам, и у каждого получается своё смещение. После изучения матчасти я выявил два решения этой проблемы:
Объекты для калибрации
Обычные объект на карте, который отрисован с идеальной точностью. По нему можно выровнять любую подложку, даже ту, что не была открыта на момент рисования объекта. Объект может быть точкой (например, перекрёсток дорог или памятник), либо линией (пруд с чёткими берегами, узкая просека).
Пользователю требуется быстро показать такой объект. Для этого есть два способа:
- Специальный тег, calibration=yes. Скачав часть данных и добавив слой снимков, пользователь включает фильтр в редакторе и привязывает снимок не по трекам, но по этому объекту.
- Внешняя база таких объектов. Пользователь может нажать кнопку, и через базу редактор найдёт ближайший объект.
Минусы:
- привязка всё равно будет неточной, хотя погрешность получится значительно меньше, чем при привязке по трекам;
- кто-нибудь может подвинуть калибрационный объект под снимок, ггг. Ну, или вообще удалить.
Плюсы:
- не зависит от снимка и масштаба;
- можно использовать без плагина, просто через фильтр по тегам.
База пользовательских меток
Во внешней базе ведётся список точек с фиксированными координатами. В этих точках указывается смещение для подложки, а также дата, комментарий пользователя, все дела. При подключении подложки пользователю выдаются ближайшие смещения с комментариями, и он может выбрать подходящее. Соответственно, он может сохранить текущее смещение в этой базе, а также поставить флаг устаревания. Те смещения, которым более месяца не снимали флаг устаревания, удаляются из базы.
Минусы:
- очевидно, зависит не только от снимка, но даже от текущего масштаба: на разных масштабах снимки могут быть разными;
- требуется внешняя база и отдельный плагин, либо встроенная поддержка редактором;
- идентификация подложек -- непростая задача, особенно в разных редакторах;
- единицы для смещения могут отличаться между редакторами.
Плюсы:
- интуитивно понятное решение с минимальными требованиями к пользователю;
- одинаковые смещения у всех, с абсолютной точностью;
- не зависит от данных OSM: не загрязняет базу, не может быть испорчено случайно.
То и то
Оба способа по-своему хороши, поэтому их можно совместить. Например, во внешней базе хранить не только точки с конкретными смещениями, но и точки посреди калибрационного объекта, с соответствующим комментарием. И пользователю можно предложить выбор -- воспользоваться готовым, или привязать самостоятельно. Написать соответствующее предупреждение, все дела.
Даза банных
В базе всё хранится в единой таблице. Да. Можно было бы и в двух, но дублирование информации? Планировать можно по частям.
Общие свойства
- lat, lon (fixed point, 3.7)
- date (только день, отображать вообще месяц)
- author (ник, id нафиг нужен)
- description
Смещение подложки
- imlat, imlon (координаты этой точки на подложке)
- imagery — название или base url подложки (bing, latlon.org/?layer=irs)
- min_zoom, max_zoom (может быть NULL)
- abandon_date — отметка, что точка устарела
Калибровочный объект
- objtype — тип объекта (точка или линия)
- objid
- lastuser — последний, кто правил точки объекта (чтобы можно было предупредить об изменении)
То и то
Собственно, вполне нормальная процедура: выделить калибровочный объект и залить в базу одновременно и его, и смещение. Но имеет ли смысл хранить это в одной строке базы, или лучше разделить? И делать ли три таблицы с двумя связями 1:1, или обойтись одной? По мне, лучше второй вариант.
API
Взаимодействие с сервером -- через HTTP GET. Формат запросов — /<action>?lat=...&lon=... и т.п. Вместо <action> могут быть такие варианты:
- get -- запрашивает смещения для точки. Возвращает xml, но есть вариант json.
- store -- добавляет или изменяет смещение в базе;
- deprecate / undeprecate -- ставит или убирает флаг устаревания смещения.
Параметры для get:
- lat, lon -- координаты центра окна редактора;
- imagery -- идентификатор подложки;
- radius -- необязательный параметр, радиус опроса в километрах.
- format -- xml/json. Для последнего можно добавить jsonp=<функция>.
Для store параметры те же, плюс:
- author -- никнейм пользователя;
- description -- описание точки
- imlat, imlon, imagery, minzoom, maxzoom -- параметры для смещения;
- object=node/way, id -- тип и идентификатор объекта.
Для deprecate необходимо указать идентификатор точки (id) и причину (reason). Undeprecate причины не требует, но нужно подумать, как ограничить это всё. Undeprecate должен обновлять дату.
Сервер возвращает XML со всеми ключами, описанными выше. Пустые необязательные ключи не включаются. Пример для смещения:
<?xml version="1.0" encoding="utf-8" ?>
<imagery-offsets>
<offset lat="35.01923" lon="60.12341">
<id>1</id>
<author>Zverik</author>
<description>Проверка работы сервера смещений</description>
<date>2012-02-13</date>
<imagery minzoom="10" maxzoom="20">bing</imagery>
<imagery-position lat="35.01854" lon="60.123" />
</offset>
<calibration-object lat="35.01923" lon="60.12341" obsolete="no">
<id>999</id>
<author>Zverik</author>
<description>По этому перекрёстку можно привязать подложку</description>
<date>2012-02-21</date>
<object type="node">62348713</object>
<last-user>156987</last-user>
</calibration-object>
</imagery-offsets>
Также, режим «без головы»: на запрос координат со всеми параметрами возвращает значение смещения, без объетов калибрации. Нужно указать четыре параметра: координаты, название подложки и масштаб.
/nearest?lat=...&lon=...&imagery=....&zoom=...
Возвращается одно значение для смещения, либо пустой массив.
Аппроксимация смещений — зло, потому что разница смещений может быть обусловлена сменой снимка, и нет способа это отследить.
Калибрация, заново
Раз для смещений делаем отдельную базу, зачем хранить в ней ссылки на OSM-объекты для калибрации? Это же простые объекты: точки или полигоны (а незамкнутые линии?). Список точек можно просто передать в параметре. Таким образом, запрос на добавление полигона калибрации выглядит так:
/store?author=...&description=...&geometry=lon1+lat1,lon2+lat2,lon3+lat3,lon1+lat1
Координаты пишутся через пробел (кодируемый в '+'), разделяются запятой. Для замкнутой линии последняя координата равна первой. Для точки координата только одна. Заметьте, что нет параметров lat и lon: они вычисляются как среднее арифметическое переданных координат.
Пример возвращаемого объекта:
<calibration-object lat="35.01923" lon="60.12341">
<id>999</id>
<author>Zverik</author>
<description>По этому дому можно привязать подложку</description>
<date>2012-02-21</date>
<geometry>
<node lat="35.01923" lon="60.12341" />
</geometry>
</calibration-object>
В json будет похоже:
{
"type" : "calibration_object",
"id" : 999,
"lat" : 35.01923,
"lon" : 60.12341,
"author" : "Zverik",
"description" : "По этому дому можно привязать подложку",
"date" : "2012-02-21",
"geometry" : [[60.12341, 35.01923]]
}
URL в Imagery
Значение строки Imagery строится из адреса подложки тремя способами, в зависимости от типа подложки. Эта схема проверена на списке от основных редакторов. Сначала требуется определить тип подложки.
TMS
Протокол и изменяемые части адреса вида /{zoom}, /{y}.jpg (да, вместе с расширением и слэшем) отбрасываются:
http://tile.openstreetmap.org/{zoom}/{x}/{y}.png -> tile.openstreetmap.org http://mapproxy.sosm.ch:8080/tiles/sogis2007/EPSG900913/$z/$x/$y.png?origin=nw -> mapproxy.sosm.ch:8080/tiles/sogis2007/EPSG900913?origin=nw
Все изменяемые фрагменты адреса отбрасываются. Если они оставляют «..» или точку в начале, лишнюю точку нужно удалить.
http://oatile{switch:1,2,3,4}.mqcdn.com/tiles/1.0.0/sat/{zoom}/{x}/{y}.png -> oatile.mqcdn.com/tiles/1.0.0/sat http://{switch:a,b,c,d}.tile.osm-tools.org/osm_then/{zoom}/{x}/{y}.png -> tile.osm-tools.org/osm_then
Все параметры адреса, в которых присутствуют изменяемые части, отбрасываются. Остальные параметры сортируются в алфавитном порядке, ключи переводятся в нижний регистр:
http://maps.kosmosnimki.ru/TileService.ashx?Request=gettile&layerName=19195FD1&apikey=FAIL&crs=epsg:3857&z={zoom}&x={x}&y={y} -> maps.kosmosnimki.ru/TileService.ashx?apikey=FAIL&crs=epsg:3857&layername=19195FD1&request=gettile
Пример работы алгоритма для подложки Bing с quadtiles, но сама подложка должна идентифицироваться по ключу «bing» (см. ниже). Обращаю внимание, что в этом случае параметры остаются, поскольку неизвестно, влияют ли они на получаемые тайлы в общем случае.
http://ecn.t${0|1|2|3}.tiles.virtualearth.net/tiles/a$quadkey.jpeg?g=587&mkt=en-gb&n=z -> ecn.t.tiles.virtualearth.net/tiles/a?g=587&mkt=en-gb&n=z
WMS
Протокол отбрасывается, из всех параметров остаются только map и layers, которое пишутся в нижнем регистре в порядке layers=&map= (по алфавиту):
http://wms.craig.fr/osm?service=wms&request=getmap&version=1.1.1&layers=auvergne&format=image/jpeg&SRS={proj}&WIDTH={width}&HEIGHT={height}&BBOX={bbox} -> wms.craig.fr/osm?layers=auvergne http://sit.provincia.lodi.it/mapserver/mapserv.exe?map=ortofoto_wgs84.map&SERVICE=WMS&VERSION=1.1.1&REQUEST=GetMap&SRS={proj}&LAYERS=Terraitaly%20Ortofoto%202007&STYLES=%2C%2C&FORMAT=image/png&TRANSPARENT=TRUE&WIDTH={width}&HEIGHT={height}&BBOX={bbox} -> sit.provincia.lodi.it/mapserver/mapserv.exe?layers=Terraitaly%20Ortofoto%202007&map=ortofoto_wgs84.map
Словарь
Некоторые распространённые подложки идентифицируются по ключевым словам. Такие слова могут содержать только символы [a-z0-9_], и обязательно должны документироваться (на другой странице, это пример).
- bing
- scanex_irs
- yahoo