Использование 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



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

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



Шпионка

Шпионка

Вечер наступил, начиналась моя смена. Совсем недавно мне удалось устроиться на работу сторожем на военный завод. Работа непыльная, требовалось раз в несколько часов обходить территорию, проверять замк...
Семь плюсов при самостоятельном изучении иностранного языка

Семь плюсов при самостоятельном ...

Основное преимущество самостоятельного изучения иностранного языка − это полная независимость. Под этим подразумевается, что вы сами выбираете время занятий, их продолжительность. Вы можете прис...
Нужны ли в России якобы немецкие шнапсогонки?

Нужны ли в России якобы немецкие...

Любопытная по части смеха ситуация наблюдается нынче с самогоноварением. Всегда наказываемое это подпольное деяние ныне легализовано. Но каким манером? Думаю, не надо подробно говорить о том, что стр...
Как приготовить банановый хлеб? Просто, вкусно и очень полезно

Как приготовить банановый хлеб? ...

Один из любимейших американцами видов выпечки — banana bread (банановый хлеб), или, точнее сказать, банановый пирог, готовится из самых доступных продуктов, а с приготовлением справится даж...
Поход по принуждению

Поход по принуждению

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

О чем говорить с женщиной на пер...

Итак, чем же мужчине привлечь внимание женщины, как стать для неё интересным собеседником и произвести приятное впечатление? Согласитесь, если постоянно заниматься только тем, что говорить компли...
Еда и кулинарияМедицина и здоровьеДом, семья, детиИскусство и культураБизнесОбучениеКак сделать...ITСтроительство и ремонтСтатьи о товарах и услугахИнтимная жизнь
Самое интересное:

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

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

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