Как я пытался починить поиск по картам для водителей. Часть 3 (финал)

    Итак, это третья часть моей попытки переосмыслить привычный поиск по картам. Первая часть тут, а вторая тут — они более технические, но пробежать глазами для лучшего понимания можно. Вкратце это звучит так: мне надоело ковыряться в картах за рулем, пытаясь среди мелких значков и рекламы найти ближайшую заправку. Вместо этого хотелось бы просто ехать, посматривая на экран приложения. Чтобы оно сортировало ближайшие места по времени езды, показывало списком, объясняло, какие из них по пути и какой к ним трафик. Такая вот идея.



    Собственно, к версии приложения 3.0 наконец получилось реализовать все основные функции, которые хотелось. После прошлой статьи из этой серии его скачало некоторое количество людей, и даже написали отзывы — спасибо, ко всем прислушался. Работал над новой версией месяца два интенсивно, все мелкие изменения не перечислить — по сути это на 80% новое приложение. С кардинально улучшенным интерфейсом, раза в 2 быстрее и значительно стабильнее. Опять же, приглашаю сочувствующих оценить и поругать. А под катом снова технические моменты.

    Вот тут ссылки на айфон и андроид

    Пробки


    Одной из ключевых претензий к предыдущей версии приложения был неправильный расчет времени — я реализовал его своими силами через Open Source Routing Machine, и он считал чистое время дороги. В периоды минимального трафика (например, ночью) мои цифры совпадали с тем, что выдавали те же гугловские карты, но в большинстве случаев оценка были как минимум крайне оптимистична. Это нивелировало собственно сам смысл приложения, и надо было что-то придумать.

    Пути решения здесь два: обратиться к стороннему апи или пытаться выкачать веса трафика откуда-то и импортировать к себе. Очень не хотелось от кого-то зависеть, поэтому какое-то время я потратил на поиск второго решения. Итоги оказались неутешительными: я нигде не нашел базу весов трафика с глобальным покрытием, которая была бы совместима с OpenStreetMap. Есть какие-то открытые базы по кускам Европы и Америки, которые в теории можно сшить с OSM через прыжки с бубном — но в итоге, поразмыслив, я решил не связываться. Конечно, возможность хостить у себя навигацию с трафиком прельщала, но отпугнули неполное покрытие, сложности с интеграцией, погрешности и сам факт, что трафик кеширован, а не в реальном времени. Короче, опять потратить кучу времени и получить мизер в итоге.

    Осознав, что в наше время без апи большого дяди никуда, я принялся искать адекватного и дешевого дядю. Потыкавшись, я остановил свой выбор на сервисах HERE — это бывшие карты нокии, потом их забрал к себе майкрософт, оставив в виде отдельного подразделения. Как я понял, они сейчас в основном работают с корпоративными клиентами (например по вопросам логистики) и имеют достаточно вменяемое и чистое апи. А главное, у них есть глобальный реалтаймовый трафик и достаточно щедрые квоты. Неочевидный выбор, но я решил попробовать.

    Интеграция в итоге оказалась довольно простой. Немалую роль здесь сыграла общая гибкость архитектуры, которую я наваял. При желании сейчас в нее несложно встроить хоть гугл, хоть яндекс пробки. Трафик из HERE я сделал отключаемым с фоллбэком в свою старую навигацию. Наконец, сравнивая значения без трафика (мои) и с трафиком, можно вывести общую оценку — пустая дорога, легкий трафик, средний и так далее.

    Карты — список


    Карты были второй главной претензией к приложению. Я угрохал какое-то невероятное количество времени на рисование собственных превьюшек маршрута и общей карты, и оно даже работало — но генерация растровых тайлов с модным дизайном колоссально просаживала сервер. Если в режиме тестирования картинки появлялись в пределах половины секунды, то с реальной аудиторией (даже небольшой), люди могли ждать до пяти или даже десяти (!!!!) секунд. Особенно, если кусок карты был крупный — тогда мой код пережевывал и рендерил кучу векторных данных. К тому же этот процесс особо не распараллелишь: там были узкие места, и все очереди все равно быстро забивались. В общем, печаль.

    Что делать, было очевидно — выкинуть превьюшки карт к чертовой матери. Я долго боролся с собой (весь я же так долго их делал), однако в итоге принял волевое решение и, в общем, правильно сделал. Когда огромные и зачастую не грузившиеся картинки ушли, стало спокойнее и освободилась куча места на экране. Даже заполнив его новыми данными и увеличив надписи, я смог втиснуть в экран в два раза больше результатов, чем ранее.



    Карты — новый режим


    А вот с общей картой я поступил иначе. Никто (включая меня самого) не мог понять, зачем, собственно, она нужна. Она была самопальной, корявой, грузилась вечность и вообще изначально создавалась для дебага. Однако визуальное изображение изохроны почему-то продолжало мне греть душу и в итоге осталось занимать место в интерфейсе. Тогда я решил: а давай попробуем сделать из этой бессмысленной картинки полноценный альтернативный режим просмотра. Если кому-то не нравится список и он легче читает карту — почему бы и нет? Тем более у меня оставалась парочка идей, которым больше нигде не нашлось места.

    Скрепя сердце, я выкинул свою картинку (стонущий от нагрузки сервак был благодарен за это). Вместо нее я встроил полноценную карту через плагин flutter_map — фоновые тайлы взял у Mapbox — и стал показывать на ней свой положение и точки результатов вокруг. Почти сразу всплыла необходимость эти точки кластеризовать, и я быстро набросал основанный на расстоянии код кластеризации. Он довольно примитивный, но 90% случаев покрывает. Под все это я опять подложил свою любимую зеленую кляксу изохроны. Наконец, легенда карты тоже стала интерактивной: тап по количеству результатов фокусирует карту на точках, а тап по времени — на изохроне. Довольно удобно.



    Одной из идей, в которой я чувствовал ценность, но никак не мог ее сформулировать, было отображение текущего маршрута и вектора движения автомобиля. Я пытался влепить это в карточки маршрутов разными способами, но нигде оно не выглядело органично и на своем месте. И вот наконец, почти отчаявшись, я понял: новый режим карты идеален для этой фишки. Потому что в режиме списка я пишу напрямую текстом, по пути какое-то место или нет — а вот на карте это всегда непонятно. Даже у гугла или эппла ты наблюдаешь постоянно вертящийся сектор компаса и долгое время не понимаешь, в каком направлении ты едешь.

    Воодушевленный, я сел работать. Пришлось попутно отрефакторить кучу кода, но спустя пару дней логика была готова. Я решил обновлять позицию не каждый 200 метров, как результаты, а гораздо чаще — через метров 10. Каждое обновление я пересчитываю вектор движения, и так он получается очень точным, поскольку зависит не от акселерометра, а от предыдущей позиции. Маршрут (то есть массив истории наших координат) я рисую на карте линией, а направление движение — стрелочкой. Все это обновляется почти в реальном времени, и вы даже не представляете, насколько карта преобразилась и стала удобней.



    Отдельным нюансом стал факт, что в первые секунды получения локации gps еще калибруется. Замечали, как точка ползает по карте какое-то время вначале? С моей логикой эти фантомные перемещения сразу давали бы ложные выводы о направлении движения. А с учетом того, что ближайшее обновление результатов аж через 200 метров, это бы здорово дезинформировало водителя. Решил я эту проблему очень просто: до первого обновления делать вид, что мы стоим. То есть не показывать на карте ни стрелочку (хотя точка все равно ползает), ни маршрут. А разблокировать эти данные уже после, когда мы переместились на какое-то существенное расстояние, прошло секунд 5 и шансы получить ложную информацию практически нулевые.

    Еще я добавил карточку, которая вылетает при выборе результата на карте. По сути это те же данные, что и в списке, но к ним добавлена превьюшка маршрута (да-да, она все-таки вернулась) и кнопка, запускающая навигацию.



    Интерфейс


    В целом интерфейс был основательно перекроен. Я не буду описывать, как переписал менюшки, заново отстроил цветовую палитру и все в таком духе. Сфокусируюсь на самых интересных моментах. Все надписи были пропорционально увеличены (мое падающее зрение тут пригодилось — увеличивал, пока сам с водительского кресла не увидел). Поменял шрифт на SF Pro Rounded — это закругленная вариация эппловского San Francisco. Качать тут, толковый шрифт. Настоятельно рекомендую в случаях, где у вас не сплошной текст, а крупные плашки, которые должны быть читаемы издалека.

    После некоторых раздумий принял неочевидное для себя решение убрать фильтр “По пути”. Как и фильтр по времени, поначалу он казался чуть ли не основной функцией аппа. Однако в какой-то момент я понял, что им не пользуюсь. В режиме списка и так прекрасно видно, какие места по пути, а в режиме карты он и вовсе сбивает с толку. Я какое-то время бессмысленно таскал этот переключатель по интерфейсам, после чего просто скрыл его и ничего не потерял. Плюс чисто технически он плодил нюансы, которые было муторно и совершенно необязательно решать.

    Данные


    Собственно, главная на данный момент проблема приложения — данные. Я по-прежнему беру их из OSM со всеми сопутствующими проблемами: неравномерное покрытие, куча устаревших данных, отсутствие часов работы, телефонов и так далее. Мой бекенд построен так, что интегрировать в него любое стороннее апи мест очень просто — только вот где его взять? Первый (и самый лучший) кандидат это Google Places, но после недавнего удорожания на 1400% (господи) я пока их не могу себе позволить. Все остальные — TripAdvisor, Foursquare и им подобные — тоже или дорогие, или с корявым апи. Некоторые сервисы (тот же Mapbox или HERE) под видом своих данных предоставляют пережеванные места из OSM, которые у меня самого есть.

    Из всей этой братии я решил попробовать прикрутить Yelp — он вроде недорогой и апи выглядело прилично. Я понимал, что это американский портал, соответственно, данных по другим частям света будет минимум, но это хотя бы какой-то прогресс. И выглядело все поначалу неплохо: я за пару часов все интегрировал, и даже почитал, что они заявляют покрытие чуть ли не половины мира. Однако не успел я обрадоваться, как начался какой-то цирк. Огромное количество мест в их данных имело неправильные координаты. Очевидно, они вводили места не через точки, а через адреса — и их геокодер расставлял координаты произвольно. В результате у меня какая-нибудь заправка находится в правильном месте, но кроме адреса почти не имеет данных; а у них есть и отзывы, и рейтинг, и часы работы — только вот координаты вообще какие-то левые. Единственные свойства, по которым наши данные можно свести, это имя и адрес. Причем зачастую и то, и то написано произвольно, с ошибками, неправильно форматировано и тд. Я попробовал сличать их через свой геокодер + fuzzy matching, и, в принципе, это сработало — хотя какой-то процент мест мы таким образом все же теряем.

    Но это оказалось лишь первой проблемой. Дальше посыпались остальные: у них очень нестабильный поиск по радиусу, куча багов (если почитать коменты людей в их гите, то там вообще ничего не работает) и так далее. В конце концов я проверил требования по брендингу — оказывается, ты обязан использовать их красные (!!!) звезды для рейтинга мест. Посмотрев, как это выглядит в моем интерфейсе, я плюнул и весь этот балаган отключил.



    В итоге, с данными прогресса особо нет. Собственно, единственное, что можно (и очень легко) сделать — это прикрутить Google Places. Там все отлично и с покрытием, и с координатами. Только вот это стоит теперь очень больших денег. Поэтому прошу вашего мнения: как бы вы отнеслись к платной подписке? В бесплатной версии было бы как сейчас, а за какую-то символическую сумму в месяц были бы доступны данные гугла или например яндекса (надо почитать, сколько у них стоит). Так я, наверное, не разорюсь.

    Итог


    В общем, я недавно прикинул: почти полтора года у меня заняло это приложение. Конечно, не все мое свободное время я на него тратил, но большую часть точно. Пару раз бросал на месяц, иногда казалось, что никогда не доделаю — но вот все-таки доделал. И, в принципе, сейчас оно выглядит именно так, как я хотел с самого начала. По пути освоил не одну новую технологию и получил очень много опыта. В общем, было интересно. Теперь я был бы рад, если бы результат кому-то пригодился.

    P.S.


    На правах саморекламы: в промежутке сделал для себя другое приложение, совсем маленькое — помощник при парковке. Я не перевел его на русский, но там однокнопочный интерфейс. Может, будет кому-то интересно.
    AdBlock похитил этот баннер, но баннеры не зубы — отрастут

    Подробнее
    Реклама

    Комментарии 12

      0
      Я привык ездить на заправки которые по пути, а надо на те, до которых добираться быстрее? Без полноценного навигатора как по мне приложение теряет смысл, у себя в городе я и так знаю где можно заправиться, если я поехал куда-то далеко, то я хотел бы видеть список АЗС вдоль моего маршрута.
        0
        Согласен. Ну тут скорее для кейсов, когда ты в незнакомом районе или городе. У меня как-то получается такой сценарий часто
        0
        Спасибо за статью и работу. Несколько идей мне подкинули. Попробовал ваше приложение. По парковкам… почему то показываются далеко не все парковки, имеющиеся в OSM. Вы по каким-то критериям ограничили выборку парковок?

        Сейчас поверхностно глянул на сервис HERE. Как думаете, можно средневзвешенный трафик посчитать для всех локаций одного крупного города (Москва, Питер и подобного)? Достаточно будет бесплатных лимитов?

        И вы затронули вопрос о платной подписке… У меня вообще уже первой статьи возник вопрос о монетизации, т.к. такие проекты имхо далеко выходят за рамки хобби. Требуют кучи времени, аренды нескольких серверов и возможно оплаты доступа к сторонним сервисам/данным. Честно говоря, я не представляю такой сервис без финансовой подпитки. Это ведь не просто локальное приложение, а полноценный сервис, требующий постоянной поддержки (обновление данных, обслуживание и пр.).
          0
          Спасибо за отзыв

          Теги для парковок: parking, parking_space, parking_entrance. Может, и другие есть, добавить легко в конфиг

          Я не уверен, что у вас получится выкачать таким образом средневзвешенный трафик. Тут дело не в лимитах, их апи заспамить реквестами нет проблем, но как эти значения превратить в веса для ребер графа — вот тут не знаю, надо думать.

          Ну да, вы правы — из своего кармана трачу на пару серверов на digitalocean. Не считал, сколько уже потратил, наверное немало. Просто мне нравится самому идея. Если соберется еще какое-то количество людей, которым понравится — можно думать, чтобы хоть как-то окупать
            0
            Теги для парковок: parking, parking_space, parking_entrance.


            Я к примеру вот эту парковку не вижу: #map=19/55.73326/37.81275
            В OSM она помечена как parking (вышеуказанную часть урла с координатами я из osm сейчас взял).

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

            ЗЫ:
            Меня заинтересовали упомянутые вами изохроны (поиск не по радиусу, а по полигону, учитывающему маршруты). Не подскажете, как вы эти изохроны из OSRM вытягиваете? Заранее спасибо.
              0
              С изохронами поможет github.com/mapbox/osrm-isochrone, там надо немного поколдовать, но в итоге заведется. Обратите внимание на параметр resolution, он контролирует гранулярность обсчёта (меньше значение — быстрее, но грубее изохрона). Рекомендую откалибровать его под ваш сервак, а полученный результат прогнать через concave hull алгоритм.

              А отсутствие данной парковки — это потому что я пару месяцев не синхронизировался с ОСМ. Написал скрипты, но пока не прикрутил еженедельную синхронизацию. Каюсь, надо взять себя в руки и добить

              Согласен насчет всего мира — я думал над этим, но пока не знаю, где это приложение бы понравилось. Если например в СНГ есть на такое спрос, то надо искать локальные цены на бензин, данные по зарядкам и тд (тот же яндекс или 2гис). А если нет спроса, то получается, зря потрачу еще полгода
                0
                С изохронами поможет github.com/mapbox/osrm-isochrone

                Да, спасибо. Глянул. Он на node.js, но с настройками вроде всё достаточно просто. Правда мне к питону надо будет прикручивать.

                Сейчас еще смотрю python-osrm. Там есть класс AccessIsochrone(point_origin, points_grid=250, size=0.4, url_config=RequestConfig). Как я понял, он запрашивает у OSRM матрицу расстояний, но что с ней делать, пока еще не понял. В отличие от osrm-isochrone, здесь не вижу параметра времени. Завтра наверно поэкспериментирую.

                А отсутствие данной парковки — это потому что я пару месяцев не синхронизировался с ОСМ


                Да, наверно из-за этого.

                я думал над этим, но пока не знаю, где это приложение бы понравилось. Если например в СНГ есть на такое спрос, то надо искать локальные цены на бензин, данные по зарядкам и тд

                Лично я бы наверно отталкивался от данных, которые смог бы добыть. Кстати, логично предположить, что для густонаселенных локаций открытых данных должно быть больше и спрос должен быть больше (больше плотность населения — больше спрос… вероятно).
                  0
                  Там есть класс AccessIsochrone(point_origin, points_grid=250, size=0.4, url_config=RequestConfig).

                  Да вот size это наверное время и есть. А points_grid это resolution

                  Лично я бы наверно отталкивался от данных, которые смог бы добыть.

                  Вообще можно же для начала просто у гугла брать данные — там все есть. Вопрос цены
                    0

                    Открытые данные плохо коррелируются с населением, скорее на оборот, чем меньше данных, тем проще их подготовить

            0
            Крутая статья!
            А какой State Management выбрали для приложения?
            Для генерации скриншотов приложения советую посмотреть на github.com/mmcc007/screenshots и frameit от Fastlane — очень спасает, удобно и автоматизировано, особенно для приложений с несколькими языками
              0
              Спасибо. Стейты все описал средствами флаттера, мне в принципе их хватило. В другом приложении использовал scoped_model — ничего такая штука
              0
              Спасибо за приложение. Установил, попробовал, понравилоь.

              Есть просьба — если задумаете монетизировать — лучше платное приложение, а не подписка. Я готов один раз заплатить больше, нот все эти подписки это просто пылесос какой-то. Подписки на всякие эппловские музыки дочке с женой, за приложения, за хостинг, за кабельное,… Скоро зарплату любой величины можно будет сразу переводить на оплату разных подписок.

              Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

              Самое читаемое