Использование WPF для визуализации картографических объектов

Введение.
В связи с широким распространением компьютерных технологий, позволяющих осуществлять позиционирование объектов на земной поверхности, примерами которых являются GPS и ГЛОНАС, появилась уникальная возможность создавать такие компьютерные системы, которые можно использовать в повседневной деятельности предприятия без значительных затрат. Всем известны такие системы отслеживания автотранспортных средств автобусных предприятий, медицинских учреждений, а также персональные автомобильные навигаторы. Все эти системы объединяет то, что они все в своей основе имеют картографический модуль, отображающий интерактивную карту и позволяющий каким- либо способом отслеживать заданный объект. Наша фирма тоже разработала систему для контроля автотранспортных средств предприятий. Система состоит из нескольких частей. Отображение карты и автотранспортных средств осуществляет клиентский модуль, написанный на C# . Net 3. 5 WPF. Внешний вид клиентского модуля представлен на рисунке.

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

Хранилище данных
В настоящее время одним из самых широко распространенных форматов для хранения картографической информации являются файлы формата shp (ESRI Shapefile) [1]. Однако они не очень удобны в использовании, т. к. в стандарте не определены механизмы поиска и выборки объектов по определенным критериям. Хотя и сами разработчики и сторонние фирмы предпринимают попытки построения специальных индексных файлов для таких целей. Одним из таких бесплатно распространяемых компонентов является SharpMap [2]. Он позволяет осуществлять все необходимые действия при работе с геоинформационными данными, однако как показали тесты объем потребляемой памяти и производительность оставляют желать лучшего, кроме того компонент распространяется с лицензией LGPL, что не очень желательно для коммерческой разработки, т. к. при внесении изменений требуется осуществлять поставку с исходным кодом.

Геоинформационная система предполагает возможности изменения масштаба карты, а также перемещения и поиска картографических объектов, что вызывает ряд технических проблем, например, загрузка еще не загруженных областей, выгрузка неактуальной информации и т. п. Предварительные тесты показали неприемлемую производительность при использовании библиотеки SharpMap, поэтому было решено сделать импорт картографической информации в СУБД. В качестве СУБД на первоначальном этапе было решено использовать Microsoft SQL Server Compact Edition 3. 5 [3]. Эта СУБД является встраеваемой в приложение, входит в поставку VisualStudio 2008, не имеет ограничений на распространение, обеспечивает хорошую производительность, легко может быть заменена практически на любую другую СУБД, обеспечивающую большую производительность, например на Microsoft SQL Server 2008 [4]. Это решение является очень гибким, т. к. позволяет осуществлять сегментирование программного продукта, т. е. версия программы не предназначенная для работы в сети может использовать локальные базы данных с картами, а в сетевой версии карты хранятся на центральном сервере, что имеет ряд своих преимуществ, например, легкое обновление.
После того, как была написана процедура импорта из файлов формата shp в СУБД и получены первые результаты по отображению картографической информации, возникло непреодолимое желание сравнить разные встраиваемые СУБД на производительность. Это было сделать легко, т. к. теперь запросы на выборку объектов осуществляются на стандартном SQL. Мы протестировали Firebird, SqLite, DBF, MSSQL, результаты приведены в таблице 1.

Таблица 1. Сравнение различных СУДБ по средней производительности.
Место СУБД
1 MSSQL 2008 на выделенном сервере
2 MSSQL 2008 на одной машине с клиентом
3 DBF
4 MSSQL CE 3. 5
5 Firebird Embedded
6 SqLite

Подробности процедуры тестирования и обсуждение результатов выходят за рамки данной статьи. Внимательные читатели могут заметить, что мы не проводили испытания СУБД Oracle и могут провести эту процедуру сами. В рамках статьи мы будем рассматривать реализацию на MSSQL CE 3. 5.

Для реализации нашей системы вполне достаточно одной таблицы со структурой, представленной в таблице 2 .

Таблица 2. Структура таблицы базы данных.
Имя Тип данных Описание
Id Int Первичный ключ
Name Nvarchar(255) Имя объекта
Description Nvarchar(255) Описание объекта
Data Image Данные
ObjectType TinyInt Тип объекта
ElementType TinyInt Тип элементов объекта
Zoom TinyInt Масштаб
ObjectId Int Идентификатор объекта
ElementId Int Идентификатор элемента объекта
Complex Bit Признак составного елемента


Выборка объектов для отображения для нужного масштаба легко осуществляется запросом вида:

select ObjectId, ObjectType, Name as ObjectName, ElementType, Data, Description, Complex, ElementId from MapObject where @Zoom = Zoom order by ObjectType

Подробности реализации этой функциональности можно посмотреть в прилагаемом примере.

Дополнительные функции легко реализуются изменением этой таблички, и возможно добавлением нескольких других. В реальном приложении у нас имеется 5 таблиц, из которых 3 предназначены для поиска объектов.

Выбор способа отрисовки.
WPF использует векторную графику как формат отрисовки, это означает что специальным образом сохраняется и передается подсистемы вывода набор инструкций, которые описывают как именно необходимо выполнить отрисовку, используя графические примитивы, такие как набор линий, кривых и других команд. Это позволяет легко осуществлять масштабирование без потери качества.
WPF предоставляет на выбор два способа отрисовки. Это объекты Drawing и Shape. Объекты Shape представлены набором примитивов Rectangle, Ellipse и т. д. И легко могут быть использованы непосредственно в разметке xaml, поддерживают выравнивание и обработку событий, однако производительность системы при отрисовке достаточно большого количества таких объектов оставляет желать лучшего.
Объекты DrawingVisual обеспечивают максимальную производительность при отрисовке фигур, картинок или текста. Это достигается за счет того, что они не поддерживают компоновки и событий. К тому же их нельзя описать в разметке. Для их использования необходимо создать контейнер, унаследованный от класса FrameworkElement. Для хранения объектов DrawingVisual нужно использовать класс VisualCollection. Для обеспечения компоновки контейнера необходимо перекрыть две простых функции.

public class BaseRenderer : FrameworkElement

//member for optimize
protected VisualCollection ObjectChildrenList;

protected override int VisualChildrenCount

get

return ObjectChildrenList. Count;



protected override Visual GetVisualChild(int index)

return ObjectChildrenList[index];



Созданные объекты DrawingVisual должны быть помещены в коллекцию ObjectChildrenList для того чтобы графическая подсистема WPF смогла осуществить их отрисовку. Причем, для максимального быстродействия необходимо использовать функцию Add и добавлять объекты последовательно. В ином случае, например при использовании функции Insert осуществляется пересчет визуального родителя у всех элементов с индексом, большим чем индекс вставки. Аналоичным образом ведет себя функция Remove. Поэтому лучше очищать коллекцию полностью. В этом легко убедиться использую любой профилировщик, например jetBrance[5] или посмотрев исходные коды, например, используя Reflector [6]. Итак, вначале создается объект MapDrawingVisual, который является наследником объекта DrawingVisual и имеет ссылку на бизнес объект карты, для выполнения процедуры HitTesting (проверка попадания). Затем получается стиль для отрисовки объекта, создается геометрия и производится сама отрисовка.

private void CreateDrawing(MapElement element, bool closed)

MapDrawingVisual drawingVisual = new MapDrawingVisual();
drawingVisual. MapObject = element. MapObject;
DrawingContext drawingContext = drawingVisual. RenderOpen();

GeometryStyle style = StyleManager. GetStyle(element);

Geometry geometry = CreateBaseGeometry(element, closed);
drawingContext. DrawGeometry(style. Brush, style. Pen, geometry);
drawingContext. Close();

AddDrawingVisual(drawingVisual);


private void AddDrawingVisual(DrawingVisual drawingVisual)

ObjectChildrenList. Add(drawingVisual);


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

private static Geometry CreateGeometry(Point[] points, bool closed, bool freeze)

Geometry geometry = new StreamGeometry();
using (StreamGeometryContext ctx = ((StreamGeometry)geometry). Open())

ctx. BeginFigure(points[0], true, closed);
ctx. PolyLineTo(points, true, false);

// Freeze the geometry (make it unmodifiable)
// for additional performance benefits.
if (freeze)

geometry. Freeze();

return geometry;


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

public GeometryStyle Clone()

return new GeometryStyle

Brush = (Brush)Brush. GetCurrentValueAsFrozen(),
Pen = (Pen)Pen. GetCurrentValueAsFrozen()
;


В примере к статье не приведена реализация подписей объектов, однако этот вопрос заслуживает того, чтобы сказать о нем несколько слов. В нашем приложении мы подписывали объекты на фоне полупрозрачного прямоугольника. Его размеры зависят от величины текста. Однако логичное решение использовать ширину и высоту объекта FormattedText для отрисовки прямоугольника, а затем отрисовки текста выше него не оптимально. Пересчет происходит неоднократно. Чтобы этого избежать, нужно сначала выполнить отрисовку текста, отрисовку прямоугольника, а затем добавить полученные объекты DrawingVisual в коллекцию визуальных объектов в нужном порядке.
Перемещиние карты с помощью мыши является довольно простой задачей и фактически состоит в правильном вычислении параметров для класса TranslateTransform выполняющего сдвиг объектов. Используя транформации можно создать ряд довольно замысловатых эффектов, например изменениу угла обзора, вращение карты и прочее, однако производительность оставляет желать лучшего.
Кроме того было обнаружено очень сильное падение прозводительности при отрисовке линий. Это является серьезной проблемой, т. к. совершенно необходимо выполнять отрисовку таких картографических объектов как дороги, реки, границы регионов и прочее. Поиски решения данной поблемы не увенчались сколь каким-нибудь успехом, единственным найденным способом хоть как-то ускорить отрисовку явилась рекомендация использовать только целые числа для задания толщины пера. Еще одним непонятным фактом является то, что при отключении антиалисинга поизводительность значительно снижается.
RenderOptions. SetEdgeMode(this, EdgeMode. Aliased);
Я надеюсь, что найдутся читатели, которые смогут объяснить такое поведение системы, а также способы повышения прозводительности.
При создании приложений WPF полезно скачать инструменты для профилирования производительности, например WPF Perforator [7], а также ознакомиться с рекомендациями Micrsoft, которые можно найти в MSDN.

Проверка попадания курсора
Проверка попадания курсора (Hit testing) в описываемом случае является очень простой задачей, и реализуется буквально в несколько строк. Собственно для этого и был написан простейший класс
MapDrawingVisual:
public class MapDrawingVisual : DrawingVisual

public MapObject MapObject;

Полный код процедуры проверки попадания курсора приведен ниже:
public MapInfo GetInfo(Point point)

MapInfo info = new MapInfo();
VisualTreeHelper. HitTest(Viewer, null,
delegate(HitTestResult result)

if (result. VisualHit is MapDrawingVisual
&& ((MapDrawingVisual)result. VisualHit). MapObject != null)

MapObject mapObject =
((MapDrawingVisual)result. VisualHit). MapObject;
if (!String. IsNullOrEmpty(mapObject. ObjectName))

info. Name = mapObject. ObjectName;
info. Description = mapObject. Description;
return HitTestResultBehavior. Stop;


// Stop the hit test enumeration of objects in the visual tree.
return HitTestResultBehavior. Continue;

, new PointHitTestParameters(point));
return info;


Заключение
Хочется отметить, что с выходом WPF разработка приложений значительно упростилась. Предлагаемые WPF возможности анимации, компоновки, проверки попадания и прочих довольно сложных вещей теперь реализуется буквально в несколько строк. Использование WPF оправдано, если не требуется выполнять отрисовку тысяч визуальных объектов и позволяет добиться довольно интересных эффектов. При отрисовке довольно большого количества объектов сложной формы и особенно линий, приходится серьезно задумываться над вопросами производительности. Представляется возможным использовать WPF если компьютеры, на которых предполагается использовать приложение будут мощными и стоит задуматься об иной альтернативе если компьютеры будут слабыми. Например, с нашим приложением невозможно работать на комьютере Celeron 2000 с видеокартой GeForce 4 MX400 и памятью 1Гб, хотя на нем вполне можно играть в компьютерные игры, такие, как Counter Strike.
www. techzone. enterra-inc. com сайт компании-разработчика Вы можете связаться с нами по электронной почте.
00:28 25.03.2017



Отзывы и комментарии
Ваше имя (псевдоним):
Проверка на спам:

Введите символы с картинки:



Русский бидермейер. Дорога ли зубочистка в бисерном чехле?

Русский бидермейер. Дорога ли зубочистка в бисерном ...

«Чтения», «Беседа любителей русского слова», «Памятник отечественных муз», «Московский Телеграф», «Гирлянда»… Вряд ли эти назван...
Заработок в сети

Заработок в сети

Наверное каждый человек хоть раз в жизни задумывался о дополнительном заработке. Многие раньше до кризиса подрабатывали, причем весьма успешно, но кризис заставил искать другие альтернативы. Неплохой ...
Деньги решают всё

Деньги решают всё

     - Да, девочки, хорошо. Поцелуйтесь, обнимитесь. Ага. отлично. Это как раз то, что мне нужно. О! Великолепно! Наслаждайтесь друг другом. У-ух! Класс девчонки! Пока вы мне ...
Новое в лечении аллергии

Новое в лечении аллергии

В клинике Московского института кибернетической медицины разработана диагностическая программа «Жизнь без аллергии». Она способна значительно улучшить состояние пациентов. А в некоторых случаях – да...
Как появилась в Рунете первая поисковая система Рамблер?

Как появилась в Рунете первая поисковая система Рамб...

История Рамблера начинается в Институте биохимии и физиологии микроорганизмов РАН. В 1991 году, когда Интернет в России еще только начинал свое развитие, группа активных сотрудников Института решила с...
Где жили контрабандисты?

Где жили контрабандисты?

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

Вы решили создать сайт. С чего начать?

Если Вы решили создать сайт, то пройдите последовательно по следующим пунктам: Решите для себя с ка...

Виноделие в домашних условиях

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

Интернет меняет ориентацию: на смену эпохе web 2.0

Подходит смена цикла развития интернет-технологии, которая происходит каждые 2-3 года. Сейчас пох...

От «царской» болезни вылечат за считанные минуты

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

О мёде нам известно всё. Или..?

Не открывая истину (её и так все знают), можно уверенно констатировать, что натуральный пчелиный мёд...

Напитки для поднятия настроения. Какие рецепты?

Какие же мы, женщины, капризные… То голова болит, то нервы не в порядке, то дни у нас кр...

Правда о гаданиях и предсказаниях с помощью карт т

Гадание - есть таинство, которое происходит по своим, Вселенским законам. О которых и пойдет речь зд...

Индивидуальный предприниматель: выгоды организации

Если вы давно уже мечтаете организовать свое дело, время наступило. Сегодня для этого лучший момент,...

Бизнес-леди или просто мама. Как совместить два в

Один мой знакомый, прожив в браке почти 10 лет, вдруг решил развестись с женой. Изменила? Нет. Разлю...

Покупка металлочерепицы

Покупка металлочерепицы с одной стороны дело не хитрое, а с другой стороны на приобретение этого тов...



О информационном портале:

Наш сайт является ресурсом, который включает в себя широкий каталог информативных и интересных статей. Каждый гость отыщет для себя что-нибудь полезное. Современный дизайн позволяет вам моментально находить нужную информацию. Самые разнообразные тематические статьи дают возможность вам совершенствоваться в той или иной сфере. Быть более начитанным и грамотным. Современный дизайн сайта позволяет просматривать статьи на всех гаджетах. Теперь найти требуемую информацию стало совершенно легко.

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