- PVSM.RU - https://www.pvsm.ru -

Приложение Московское метро для Windows Store

Приложение Московское метро для Windows Store - 1

Сделать приложение Московского метро мне захотелось сразу же, как только Артемий Лебедев и его студия нарисовали схему метро в нынешнем виде.

1. Исходные данные

Сейчас официальную схему метро можно загрузить в PDF с официального сайта Московского метрополитена [1]. На момент создания приложения (середина 2013 года) схема была доступна в виде .ai файла (Adobe Illustrator) на сайте студии Лебедева. В любом случае, следующий этап — это подготовка данных в Illustrator'e.

2. Подготовка данных

Открываем PDF в Illustrator, включаем режим preview и падаем в обморок.

ужас-ужас

Приложение Московское метро для Windows Store - 2 [2]
(кликабельно)

После долгой и кропотливой работы (тут мне пригодился многолетний опыт работы в московской рекламной газете, сначала в отделе дизайна и вёрстки, затем в IT-отделе)

получилось следующее

Приложение Московское метро для Windows Store - 3 [3]
(кликабельно)

Что было сделано:

  • удален многочисленный мусор, надписи и пр.
  • каждая линия метро была разбита на участки между станциями. Линии разбивались под рисунками станций, чтобы при отрисовке построенных маршрутов не было видно стыков и разрывов.

вот так:

Приложение Московское метро для Windows Store - 4

— все «кусочки» линий и все станции, относящиеся к каждой линии, сгруппированы по слоям, в порядке их следования.

вот так:

Приложение Московское метро для Windows Store - 5

3. Преобразуем графику в XAML

Для перевода графики в XAML используется Microsoft Expression Design. [4] Тут всё просто — открываем ai-файл, экспортируем в XAML.

Microsoft Expression Design:

Приложение Московское метро для Windows Store - 6 [5]
(кликабельно)

4. Начинаем программирование (наконец-то)

В настоящий момент времени для разработки используется Visual Studio 2015 и MVVM-фреймворк MVVM-light. К сожалению, XAML-файл, полученный на предыдущем этапе, напрямую в приложении использовать не получится, кроме статичного слоя с реками и маршрутами «аэроэкспрессов».

Поэтому еще немного работы вручную — и в ресурсах приложения формируем окончательный XML-файл, используемый для рендеринга схемы метро. При его загрузке формируются объекты линий метро, станций метро, формируются связи между станциями в пределах одной линии, переходы между линиями, «замыкаются» кольцевые линии. К слову, переходы между линиями формируются программно. Между двумя станциями — проводятся линии с градиентом заливки, между тремя станциями — строятся дуги окружности, построенной по трём точкам — центрам станций, из которых состоит переход.

Пример View-слоя, отвечающего за отрисовку дуг переходов между тремя станциями (для краткости удалены ресурсы, отвечающие за анимацию и пр.):

<ItemsControl x:Name="ArcCrossings" ItemsSource="{Binding CrossingArcTypeList}" Visibility="Visible" Height="1760" Width="1765">
                    <ItemsControl.ItemTemplate>
                        <DataTemplate>
                            <Grid x:Name="grid" Opacity="{Binding Dimmed, Converter={StaticResource BooleanToOpacityConverter}}">
                                <Path StrokeThickness="7.7" Stroke="{Binding CrossBrush}">
                                    <Path.Data>
                                        <PathGeometry>
                                            <PathGeometry.Figures>
                                                <PathFigureCollection>
                                                    <PathFigure StartPoint="{Binding GradientLineStartPoint}">
                                                        <PathFigure.Segments>
                                                            <PathSegmentCollection>
                                                                <ArcSegment Point="{Binding GradientLineEndPoint}" Size="{Binding ArcSize}" SweepDirection="Clockwise"/>
                                                            </PathSegmentCollection>
                                                        </PathFigure.Segments>
                                                    </PathFigure>
                                                </PathFigureCollection>
                                            </PathGeometry.Figures>
                                        </PathGeometry>
                                    </Path.Data>
                                </Path>
                                <Path StrokeThickness="2.4" Stroke="{Binding SettingsVM.BackMainBrush, Source={StaticResource Locator}}">
                                    <Path.Data>
                                        <PathGeometry>
                                            <PathGeometry.Figures>
                                                <PathFigureCollection>
                                                    <PathFigure StartPoint="{Binding BlackLineStartPoint}">
                                                        <PathFigure.Segments>
                                                            <PathSegmentCollection>
                                                                <ArcSegment Point="{Binding BlackLineEndPoint}" Size="{Binding ArcSize}" SweepDirection="Clockwise"/>
                                                            </PathSegmentCollection>
                                                        </PathFigure.Segments>
                                                    </PathFigure>
                                                </PathFigureCollection>
                                            </PathGeometry.Figures>
                                        </PathGeometry>
                                    </Path.Data>
                                </Path>
                            </Grid>
                        </DataTemplate>
                    </ItemsControl.ItemTemplate>
                    <ItemsControl.ItemsPanel>
                        <ItemsPanelTemplate>
                            <Canvas/>
                        </ItemsPanelTemplate>
                    </ItemsControl.ItemsPanel>
                </ItemsControl>

Для поиска маршрутов используется волновой алгоритм с небольшими вариациями. Например, в случае, если находится оптимальный маршрут, содержащий два и более переходов, строятся дополнительные маршруты, в которых запрещено использовать «промежуточные» линии метро. В результате иногда получаются крайне парадоксальные и неожиданные варианты проезда (смотрите скриншоты ниже).

Для поиска необходимого вагона для удобного перехода на другую линию метро использовался следующий подход: у каждой линии установлено направление «вперед» и «назад». Соответственно, нам важно, с какой стороны мы подъехали к станции перехода, и иногда нам еще важно, в каком направлении мы поедем по той линии, на которую переходим.

Фрагмент XML-файла, описывающий станцию «Китай-город» Таганско-Краснопресненской линии и ее характерный переход на Калужско-Рижскую линию:

<Station name="Китай-город" lat="55.755361" lon="37.632361" Width="16.8277" Height="16.8282" Canvas.Left="1011.71" Canvas.Top="741.034" Data="F1 M 1017.45,746.771C 1015.97,748.25 1015.97,750.646 1017.45,752.125C 1018.93,753.604 1021.33,753.603 1022.8,752.125C 1024.29,750.646 1024.28,748.25 1022.81,746.77C 1021.33,745.292 1018.93,745.292 1017.45,746.771 Z M 1014.2,755.425C 1010.91,752.15 1010.88,746.824 1014.15,743.524C 1017.43,740.225 1022.75,740.2 1026.05,743.473C 1029.35,746.744 1029.38,752.071 1026.1,755.371C 1022.83,758.672 1017.51,758.695 1014.2,755.425 Z " TextLabel.Left="2" TextLabel.Top="-15" ShowPad="1" IsCrossPlatform="true" CrossPlatformColor="FFF37025">
          <transfers>
            <forward>
              <transfer LineID="400" station="Китай-город">
                <forward vagons="11111"/>
                <backward vagons="00100"/>
              </transfer>
            </forward>
            <backward>
              <transfer LineID="400" station="Китай-город">
                <forward vagons="00100"/>
                <backward vagons="11111"/>
              </transfer>
            </backward>
          </transfers>
</Station>

5. Несколько скриншотов построенных маршрутов (кликабельно)

Неожиданный маршрут от Киевской-кольцевой до Курской-Кольцевой:

Приложение Московское метро для Windows Store - 7 [6]

Ещё более неожиданный маршрут от Александровского сада до Боровицкой:

Приложение Московское метро для Windows Store - 8 [7]

От Охотного ряда до Площади Революции:

Приложение Московское метро для Windows Store - 9 [8]

Вполне заурядно от Шаболовской до Тульской

Приложение Московское метро для Windows Store - 10 [9]

6. Планы

На момент начала разработки приложения (напомню — это начало-середина 2013 года) речь шла об Windows 8 — 8.1. Собственно, приложение до сих пор «не-UWP». Соответственно, у приложения до сих пор есть «родимые пятна» Windows 8.1, в частности, неоднозначное расположение настроек приложения. Чего уж говорить, в Windows 10 «шарм» настроек «а-ля Windows 8.1» смотрится слегка чужеродно. Со временем, вероятно, это будет изменено.

как это сейчас:

Приложение Московское метро для Windows Store - 11

В последнее обновление пришлось «выпилить» информацию о выходах в город (т.е., сейчас нет подсказки, в какой вагон садиться, чтобы было удобно выйти в город). Это в ближайших планах.

Автор: infund

Источник [10]


Сайт-источник PVSM.RU: https://www.pvsm.ru

Путь до страницы источника: https://www.pvsm.ru/windows-store/310676

Ссылки в тексте:

[1] с официального сайта Московского метрополитена: http://mosmetro.ru/download/s.pdf

[2] Image: https://habrastorage.org/webt/eh/cr/q3/ehcrq3diqk18etnwi5jqhwybqhc.png

[3] Image: https://habrastorage.org/webt/ac/xd/-m/acxd-mmhmw9kzgdt-benemt11cs.png

[4] Microsoft Expression Design.: https://www.microsoft.com/en-us/download/details.aspx?id=36180

[5] Image: https://habrastorage.org/webt/es/3o/6m/es3o6mgupfhq9co8c_gltatyabk.png

[6] Image: https://habrastorage.org/webt/xo/f0/li/xof0litpgw8coavgd0gf3q9net4.png

[7] Image: https://habrastorage.org/webt/gp/b_/vq/gpb_vqh5v9xfu9axmmrigskcpdw.png

[8] Image: https://habrastorage.org/webt/at/n5/p4/atn5p4ioc9pq0doyamzm42miixg.png

[9] Image: https://habrastorage.org/webt/4d/do/eq/4ddoeqjhad3ylascwxv92wbvlco.png

[10] Источник: https://habr.com/ru/post/442698/?utm_campaign=442698