Свой редактор для ОСМ

Пустых значений быть не должно, это кривости, считай что отсутствует.

Eugene, простите про название просмотрел)
Даже и не знаю… Пару лет назад назвал папку со старым проектом “Road Flow”)
Правда я тогда пытался собрать оболочку для PcCar… на форуме www.pccar.ru начитался)

Сделал простенькую триангуляцию… вот по этим исходникам.
Толком не разбирался… просто типы поменял на double, точность получше поставил и структуру вертекса свою.
Работает хорошо, достаточно быстро. Правда, насколько я понял, без дырок в полигонах.
Дырки думаю можно прикрутить.

Вот границу Москвы пилит где-то за 30-70 мс…

результат, правда, не очень нравится. Поскольку на выходе получаю набор отдельных треугольников, что довольно не экономно расходует память.
В идеале лучше бы разбивать многоугольник на выпуклые многоугольники, а потом рисовать их как GL_POLYGON, или GL_TRIANGLE_FAN.
Пересчитывать разбиение нужно при изменении многоугольника.
Надеюсь, позже этим займусь.

Вот прикручиваю дырки и возник вопрос:
Если у меня полигон имеет дырку… например в море остров как дырка.
Но в этой дырке есть полигон… на острове озеро)
То в этой ситуации это озеро уже новый полигон и никакими релейшенами с морем и островом не связано? Или же это “дырка в дырке”)

Приделал консоль, вполне можно юзать… даже довольно удобно!)
Нету правда восстановления команд по кнопкам вверх или вниз, как во всех нормальных консолях…

Сейчас питон понимает все простые типы… node, way, relation
и соответственно все типы, которые в них входят… т.е. tag, member
понимает коллекции… не знаю что это в питоне, но аналог в C++ std::vector<>
И поэтому есть доступ к объекту dataController в котором все ноды, веи и релейшены карты.
У меня уже было в каком-то посте упоминание… там он назывался mapData.

Теперь хочу простенький редактор приделать, чтобы не построчно, а сразу скриптом можно было код выполнять. Сохранять в файлы, загружать… добавлять в автозапуск и т.д.
Ну и в идеале нужно сделать возможность назначать выполнение скрипта из такого-то файлика по событию…
Например, по нажатию кнопки на тулбаре, или перед отправкой данных на сервак осма.
Это даст возможность писать на питоне много полезных инструментов, проверялок, подсказывалок и т.д.
В питоне доступен Qt… т.е. при большом желании можно создавать свои диалоги, формы и т.д. в Qt много всего)
С формами, наверное, нужно будет запускать интерпретатор питона в отдельном потоке… чтобы не подвесило. Я этот момент еще не проверял.
А вообще куча идей для плагинов… от рисовалок, до получалок ошибок на карте от юзеров через какой-нибудь сервак)))

При встраивании питона я использую Boost.Python, а для “опитонивания” Qt разработчики использовали SIP, поэтому, например, QString из PyQt не работает с бустом… Но все простые типы, конечно, понимает, включая std::string… поэтому вполне удобно и так. Возиться со скриптами рановато, поскольку сейчас даже выбирать ничего нельзя и карту двигать по-нормальному, но мне нужна связка питона и С++ для проекта на работе, поэтому и углубился в это дело.

PS: скриншот по размеру меньше… тут он чего-то сам растягивается. Надеюсь только у меня так)

Потестил простенькое выделение, толку от него никакого, только оценил производительность… пока только на вершинах
Приделал “редактор” питоновских скриптов… как я и думал для создания нормальных Qt’шных форм из питона нужно создавать QApplication в скрипте…
Но такая штука не работает( Для того чтобы использовать Qt думаю нужно передать в скрипт указатель на основную форму из C++… а поскольку Boost.Python и SIP несовместимы этого сделать не могу(
Есть довольно молодой проект PySide, который использует Boost.Python в качестве обертки над Qt
Вот при его использовании, думаю, таких проблем не будет, но под винду они пока Qt не собрали…
Select tool
Все тот же центр Москвы, ~100’000 вершин. Ищет вершины входящие в прямоугольник вроде без тормозов… как двигаю мышкой, так и выделяет сразу.

Для хранения данных пытаюсь использовать boost::multi_index_container, пока на нем и сделано, но толком в нем еще не разобрался, некоторые вещи не понимаю, есть глюки)

у qt есть собственный механизм плагабельных модулей (ака плагинов)
насколько помню особенных хависимостей на интерфейсы там нет.
т.е. вполне можно плагин на pyqt подрубить к прилаге на C++ QT
хотя возможно я и ошибаюсь
тему эту глядел поверхностно

Не знаю точно можно ли прикрутить PyQT’ешные плагины к С++ проге… поиск в инете толком ничего не дал.

Вот небольшая заметка для программеров, потом может попробую в вики написать.
Для отправки запросов на сервак OSM’а где нужна авторизация (например при изменении данных) использую такую штуку на Qt:

OSMQHttp.hpp


#pragma once
#include <QHttp>
#include <QString>
#include <QEventLoop>

class OSMResponse
{
public:
    bool error;
    QHttp::Error errorType;
    QString errorMessage;
    QString response;

    OSMResponse()
    {
        error = false;
        errorType = QHttp::NoError;
        errorMessage = "";
        response = "";
    }
};

class OSMQHttp : public QObject
{
    Q_OBJECT

public:
    OSMQHttp(QString login = "", QString password = "", QString softwareId = "");
    virtual ~OSMQHttp();

    void SetUser(QString login, QString password);
    void SetSoftwareId(QString softwareId);

    // send PUT request and wait until finished
    OSMResponse sendPut(QString path, QString data);

private:
    QHttp *http;
    QHttpRequestHeader header;
    OSMResponse response;
    int requestID;        // id of current request
    QEventLoop loop;    // event loop used to block until request finished

private slots:
    void httpRequestFinished(int requestId, bool error);
};

OSMQHttp.cpp


#include "OSMQHttp.hpp"
#include <iostream>
#include <QUrl>

OSMQHttp::OSMQHttp(QString login, QString password, QString softwareId)
{
    http = new QHttp();
    requestID = -1;

    http->setUser(login, password);
    connect(http, SIGNAL(requestFinished(int, bool)), SLOT(httpRequestFinished(int, bool)));

    header.setValue("Content-Type", "text/xml");
    header.setValue("User-Agent", softwareId);
    header.setValue("Accept", "text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2");
    header.setValue("Connection", "keep-alive");
}

OSMQHttp::~OSMQHttp() { }

void OSMQHttp::SetUser(QString login, QString password)
{
    http->setUser(login, password);
}

void OSMQHttp::SetSoftwareId(QString softwareId)
{
    header.setValue("User-Agent", softwareId);
}

OSMResponse OSMQHttp::sendPut(QString path, QString content)
{
    QByteArray data = content.toAscii();

    QUrl url(path);
    QHttp::ConnectionMode mode = url.scheme().toLower() == "https" ? QHttp::ConnectionModeHttps : QHttp::ConnectionModeHttp;

    http->setHost(url.host(), mode, url.port() == -1 ? 0 : url.port());

    header.setRequest("PUT", url.toEncoded(QUrl::RemoveScheme | QUrl::RemoveAuthority));
    header.setValue("Host", url.host());
    header.setValue("Content-Length", QString::number(data.size()));

    requestID = http->request(header, data);

    /// block until the request is finished
    loop.exec();

    return response;
}

void OSMQHttp::httpRequestFinished(int requestId, bool error)
{
    /// check to see if it’s the request we made
    if(requestId != requestID) return;

    OSMResponse response;
    response.error = error;

    if(error){
        response.errorMessage = http->errorString();
        response.errorType = http->error();
        //std::cout << "Error: " << http->errorString().toStdString().data() << "   " << requestId << std::endl;
    }else{
        QByteArray data = http->readAll();
        response.response = QString(data);
        //std::cout << "Response: " << QString(data).toStdString().data() << std::endl;
    }

    this->response = response;

    /// end the loop
    loop.exit();
}

Испльзовать можно так:


#include <stdlib.h>
#include <QApplication>
#include "OSMQHttp.hpp"

int main(int argc, char *argv[])
{    
    setlocale(LC_ALL, "Russian");

    QApplication qapp(argc, argv);

    QString login("MyLogin");
    QString password("MyPass");

    QString url("http://api.openstreetmap.org/api/0.6/changeset/create");
    QString content("<?xml version='1.0' encoding='UTF-8'?>\n<osm version='0.6' generator='JOSM'>\n<changeset  id='0' open='false'>\n<tag k='created_by' v='MyNewEditor' />\n<tag k='comment' v='editor test' />\n</changeset>\n</osm>");

    OSMQHttp osmhttp;
    osmhttp.SetUser(login, password);
    osmhttp.SetSoftwareId("MyNewEditor");

    OSMResponse response = osmhttp.sendPut(url, content);
    std::cout << "OSMResponse: " << response.response.toStdString().data() << std::endl;

    return qapp.exec();
}

Присоединяюсь к вопросу: когда будет репозиторий?
Лично я бы предпочёл GitHub…

Upliner, репозиторий есть, но исходники пока закрыты. Открывать исходники с целью получить поддержку программистов сообщества рано, да и наверное пока не нужно… а с целью просто их показать не хотелось бы. Открывают исходники для того чтобы их кто-то улучшал используя в своих проектах, а не потому что опенсорсеры такие добрые) У меня на данный момент улучшать нечего… ничего работающего еще нет(

В идеале классно бы было выделить несколько “подпроектов” небольших…
А именно пытаюсь сделать такое:

  1. написать хорошую связку С++ и питона. Впринципе оно есть и работает через Boost.Python, но написать, например, виджеты на PyQt в скриптах, которые выполняет встроенный интерпретатор, не получается.
    Хочу добавить возможности использовать PyQt или PySide (но его еще нет под виндой) в скриптах и можно выделить такую штуку в отдельную GPL или даже LGPL либу.
  2. сделать либу - набор виджетов Qt… по аналогии с modo. Вот примеры интерфейса http://www.google.com/images?q=modo
    т.е. сделать удобные виджеты и повозможности прикрутить к ним обертку для питона чтобы их можно было использовать из плагинов. И тоже отправить это все сообществу под LGPL. Как-то находил тему насчет виджетов из blender’а… читал вроде бы в каком-то последующем релизе будет вынесен весь GUI из исходников проекта в отдельную либу, но пока вроде все вместе. Еще давно немного листал его исходники… на мой взгляд там творился ужас) Написано было на С, рисовалось вроде в одном OpenGL контексте… не очень красиво на мой взгляд, но ведь “снаружи” выглядит и работает все довольно классно.

Эти две идеи не касаются ОСМ’а или редактора карт вообще. Они подойдут для многих задач.
А что касательно ОСМ’а, то тут пока пробую сделать загружалку данных с сервера и на него на С++… кусочек кода для работы с сетью уже привел выше.
Это тоже можно было бы выделить в либу.

Появился вопрос по организации ОСМ’а:

У каждого объекта в осме (node, way, relation… может и вместе с changeset’ами, юзерами и т.д) есть свой id. Вот мне хотелось бы узнать уникален ли он для всех объектов вообще или только для объектов определенного типа. т.е., например, могут ли существовать в базе node и way с одинаковыми id?

Могут существовать

Это не Blender 2.5a ли, случайно? Там как раз GUI начали перепиливать.

liosha, спасибо! Для меня вопрос был довольно важный…

Hind, В 2.5 GUI вроде бы только перерисовали, но код в отдельную библиотеку не вынесли. Пишут что полная модульность будет только в 3.0.
Надо бы посмотреть последние исходники… старые помню у меня скомпилились без проблем почти с первого раза)
Вот две темы нашел по этому вопросу… кому интересно:
http://www.blender.org/forum/viewtopic.php?t=14357
http://www.blender.org/forum/viewtopic.php?t=16513

Вот, кстати, нашел такую штуку:
http://wiki.blender.org/index.php/Dev:Source/GameEngine/BlendX
Пойду смотреть/компилить… похоже на то что я давно искал))

Эх, сделал бы кто-нибудь для начала просто быстрый удобный виджет для отображения векторных карт и виджет для редактирования, которые можно было бы предложить тому-же Merkaartor’у (по-моему, там с этим делом некоторые проблемы), QLandkarte GT и прочим… :roll_eyes:

asaw, в этом-то вся и проблема) Сделать редактировалку качественную…

Стараюсь делать так чтобы было как можно более быстрее

Например, при удалении точки из карты нужно сделать несколько действий:
Посмотреть не принадлежит ли она каким полигонам, если принадлежит, то удалить ее из списка точек этих полигонов, а потом в каждом таком полигоне проверить не опустел ли он после удаления этой точки… если в нем точек не осталось, ну или осталось только две, то удалить его тоже…
тоже самое с незамкнутыми веями и релейшенами

Поиск полигонов в которые входит точка - это (если в лоб) перебор всех полигонов и просмотр их списка точек… это же много времени нужно если карта большая! Поэтому приходится делать списки идентификаторов поликов в которые входит данная точка для каждой точки чтобы обеспечить очень быстрый поиск. На это тратится много оперативки, но зато все очень быстро. Тут нужно выбирать либо съедаем много оперативы, либо медленнее работаем)
У каждой палки два конца, везде нужно искать оптимальный вариант.

До меня доходит все на третьи сутки!)))
Наткнулся на меркатор сейчас, а он оказывается опенсорс!)))) и на Qt написан…
Полистал исходнички, вполне можно разобраться, довольно понятно что к чему.
Если оттуда чего выдерну перелезу на github или sourceforge т.к. меркатор GPL.

Нашел хорошую триангуляцию http://code.google.com/p/poly2tri/
Работает даже с дырками. На сайте есть demo в exe, которому можно скармливать файлы с точками, а он покажет, как он разбил на треугольники.

P.S. Как я понял список точек полигона (наверное и дырок тоже) нужно задавать в порядке против часовой стрелки.

P.S.S. Там для Си несколько вариантов. Лучше брать тот, что сделан с namespace p2t. Я именно их переделывал под Ogre.
При желании могу выслать исходники, которые у меня получилось скомпилировать под Ogre

P.S.S.S. Только что дошло, что про Ogre - это я форумом ошибся. В данном случае такие переделки не нужны. :slight_smile:

Нужно делать не чтобы быстро работало, а чтобы работать было удобно. Редактор-то для людей делается.
По поводу проверки принадлежности точки вею - можно использовать хеширование, r-деревья, bsp-деревья и т.д. Но нужно смотреть на выигрыш в памяти/скорость работы/сложность реализации.

Я читал ругательства в адрес josm и удивлялся - чем народу не угодил этот замечательный редактор?
Удивлялся, пока не попробовал занятся обкликиванием водоёмов на работе (в простой меня загнали). Оказалось, что на четвёртом целероне 2.4 ГГц это происходит мучительно медленно. :frowning:
Быстродействие это тоже удобство. И немалое!

Джава любит память.

Джосму и 8 бывает мало.

Ура, товарищи!!! Мы на линуксе!!!)

Ubuntu 9.10 x64, полет нормальный!)
То что на скрине рисуется где-то 3-5 фпс. Но рисуется примитивно через glBegin(GL_POINTS); и glBegin(GL_LINE_STRIP);!!!
Абсолютно никакой оптимизации… с VBO, отсеивалками и т.д. практически уверен, что никаких тормозов не будет вообще.
Прикручу их попозже… тут я от радости решил схалтурить и сделать как попало лишь бы заработало под убунтой)
Мне почему-то казалось что OpenGL под линухом будет медленнее или вообще не будет))
Питон на линухе тоже завелся без проблем… работает!

С такими загруженными данными процесс захавал почти 300 метров, но, думаю, в будущем оперативки для аналогичной сцены нужно будет побольше… поскольку нужно будет хранить данные для быстрого поиска, истории изменений, кеша тайлов и т.д. Хотя часть уйдет в память видюшки.

Если сравнивать с ДЖОСМ’ом или просто с площадью, которою можно загрузить с сервера за один раз, то для редактирования таких данных ресурсов нужно значительно меньше… можно и без особо навороченных алгоритмов оптимизации сделать)

Есть и неприятный момент: у меня выгорела плашка памяти на 2 гига! Но это не связано с особенностями работы моей тулзы)))

Данные центра Москвы подгружались прямо с сервачка, правда кусками… т.к. большую область он не дает за раз скачать.
Прикрутил “выбиралку” места редактирования.

Пытаюсь сделать чтобы карт загружать и редактировать можно было много… как картинки в фотошопе.
Назвал их пейперами… типа бумага на которой чертят карты)

Прикрутил слои, правда пока только с данными.
Авторизация, загружалка данных на сервер есть, но пока очень примитивная… не сильно отличается от того что я выкладывал.

Вот такие вот дела.

Красивенько!

А с проекциями вы чего решили? Взяли proj4? Что-то другое? Или что-то свое?