Министерство образования Республики Беларусь Учреждение образования «Гродненский государственный университет им. Янки Купалы»

advertisement
Министерство образования Республики Беларусь
Учреждение образования
«Гродненский государственный университет им. Янки Купалы»
Факультет математики и информатики
Кафедра информатики и вычислительной техники
ЧЕРНЫШОВ АЛЕКСЕЙ АКИМОВИЧ
РЕШЕНИЕ ПРИКЛАДНЫХ ЗАДАЧ НА ОСНОВЕ
КАРТОГРАФИЧЕСКИХ ДАННЫХ
Дипломная работа
студента 5 курса
“Допустить к защите “
Зав. кафедрой ИВТ
Научный руководитель
Кадан Александр Михайлович
доцент, кандидат технических наук
__ ___________ 20010 г.
Гродно 2010
2
РЕФЕРАТ
Дипломная работа.
КАРТОГРАФИЧЕСКАЯ СИСТЕМА, ВЫСОТНЫЕ ДАННЫЕ, ФОРМАТ
STRM, .NET FRAMEWORK, DIRECTX, 3-Х МЕРНАЯ ВИЗУАЛИЗАЦИЯ КАРТОГРАФИЧЕСКИХ ДАННЫХ.
Целью дипломной работы являлось создание картографической системы получения и обработки высотных данных с последующим построением 3-х мерной
модели на основе полученных данным SRTM, произвести решения задачи выделения области подтопления при подъеме уровня воды в водоемах.
Объект разработки – программа на платформе Microsoft.NET Framework.
Система состоит из двух частей: plug-in (дополнения) для программы NASA
World Wind для получения данных и самого приложения обрабатывающего и отображающего данные.
3
ОГЛАВЛЕНИЕ
ПЕРЕЧЕНЬ УСЛОВНЫХ ОБОЗНАЧЕНИЙ И ТЕРМИНОВ ...................................................4
ВВЕДЕНИЕ ....................................................................................................................................5
ЦЕЛИ И ЗАДАЧИ РАБОТЫ ........................................................................................................7
ГЛАВА 1. ОСНОВНЫЕ ПОЛОЖЕНИЯ ГЕОИНФОРМАЦИОННЫХ СИСТЕМ .................8
1.1. Классификация геоинформационных систем .............................................................8
1.2. История ГИС ..................................................................................................................9
1.3. Архитектура ГИС ..........................................................................................................9
1.4. Принципы функционирования ГИС ..........................................................................10
1.5. Применение ГИС .........................................................................................................12
Выводы .....................................................................................................................................14
ГЛАВА 2. СРЕДСТВА ПОСТРОЕНИЯ ГЕОИНФОРМАЦИОННЫХ СИСТЕМ В .NET ...15
2.1
Windows DMA и .NET.................................................................................................15
2.1.1.
Common Language Runtime .................................................................................15
2.1.2.
Microsoft Intermediate Language и компиляторы JITter ....................................15
2.1.3.
Преимущества и недостатки...............................................................................17
2.2
DirectX ..........................................................................................................................17
2.2.1.
История .................................................................................................................17
2.2.2.
DirectX API ...........................................................................................................17
2.2.3.
Интерфейсы DirectDraw и DirectDraw2 .............................................................18
2.2.3.1 Функции создания интерфейсов ....................................................................19
2.2.3.2 DirectX Viewer..................................................................................................19
2.2.3.3 Функции для работы с видеорежимами ........................................................20
2.2.3.4 Функции для работы с поверхностями..........................................................20
2.2.3.5 Функции для работы с частотой смены кадров ............................................21
Выводы .....................................................................................................................................22
ГЛАВА 3. РЕАЛИЗАЦИЯ КОМПОНЕНТОВ КАРТОГРАФИЧЕСКОЙ СИСТЕМЫ .........23
3.1. Введение в NASA World Wind ........................................................................................23
3.2. Создание plugin для NASA World Wind .........................................................................23
3.2.1. Необходимое программного обеспечения .............................................................24
3.2.3. Шаблон кода плагина ................................................................................................24
3.3 Отладка плагина ................................................................................................................25
3.4. Реализация плагина для получения высотных координат............................................26
3.4.1
Графическое выделения копируемой области ..............................................26
3.4.2
Пользовательский интерфейс плагина ..........................................................27
3.4.3
Интеграция в меню NASA World Wind .........................................................28
3.4.4
Экспорт данных ...............................................................................................30
3.5
Разработка приложения просмотра 3-хмерной модели. ..........................................31
3.5.1
Пользовательский интерфейс .........................................................................31
3.5.2
Управления приложением ..............................................................................36
3.5.3
Файл описания карт .........................................................................................36
3.5.4
Обработка файла высот...................................................................................37
3.5.5
Математические преобразования при обработке файла высот ...................40
Выводы .....................................................................................................................................42
ЗАКЛЮЧЕНИЕ............................................................................................................................43
СПИСОК ИСПОЛЬЗОВАННОЙ ЛИТЕРАТУРЫ....................................................................44
ПРИЛОЖЕНИЕ 1. «Пользовательский интерфейс приложения» ..............................45
ПРИЛОЖЕНИЕ 2. «Встраиваемый в NASA Код плагина» ........................................52
ПРИЛОЖЕНИЕ 3. «Метод экспорта данных плагином» ............................................70
4
ПЕРЕЧЕНЬ УСЛОВНЫХ ОБОЗНАЧЕНИЙ И ТЕРМИНОВ
ГИС – геоинформационные системы
АСНИ - автоматизированных систем научных исследований
САПР - систем автоматизированного проектирования
АСИС - автоматизированных справочно-информационных систем
АСУ - автоматизированных системы управления
СУБД – система управления базой данных
GPS - глобальная система позиционирования (Global Positioning System)
5
ВВЕДЕНИЕ
Современные картографические (геоинформационные) системы представляют собой новый тип интегрированных информационных систем, которые, с одной стороны, включают
методы обработки данных многих ранее существовавших автоматизированных систем
(АС), с другой - обладают спецификой в организации и обработке данных. Практически
это определяет ГИС как многоцелевые, многоаспектные системы.
В частности, как системы управления ГИС являются новой основой автоматизированных
систем управления (АСУ). Это обусловливает повышенное значение ГИС - современного
средства организации многих видов производств.
Определение ГИС как "компьютеризованной базы данных (БД)", "как системы управления", в которой хранятся "пространственные данные" , следует считать неверным либо
устаревшим по ряду причин. Во-первых, база данных ( и не одна) может входить в состав
ГИС, а полная технология обработки информации в ГИС значительно шире, чем работа с
базой данных. Во-вторых, современная ГИС рассчитана не просто на обработку данных, а
на проведение во многих ситуациях экспертных оценок. Другими словами, ГИС должна
включать в свой состав экспертную систему, а этого только на уровне базы данных достичь невозможно, так как экспертная система является более общей по отношению к БД.
Наконец, данные, которые обрабатывает и хранит ГИС, имеют не только пространственную, но и временную характеристику, что важно в первую очередь для географических
данных.
Хотя разработка картографических систем началась более 30 лет назад (тогда это были
чисто географические информационные системы), их бурное развитие и качественно новое представление произошло за последние 7-8 лет благодаря принятию за основу этих
систем идеологии и технологии систем автоматизированного проектирования, интеграции
всех процессов обработки данных на базе географических данных.
На основе анализа целей и задач различных ГИС, функционирующих в настоящее время,
более точным следует считать определение ГИС как геоинформационных систем, а не
как географических информационных систем. Это обусловлено и тем, что процент чисто
географических данных в таких системах незначителен, технологии обработки данных
имеют мало общего с традиционной обработкой географических данных и, наконец, географические данные служат лишь базой решения большого числа прикладных задач, цели
которых далеки от географии. Разумеется, это не исключает существование чисто географических информационных систем - аббревиатура та же - ГИС, однако в дальнейшем мы
будем понимать под ГИС геоинформационные системы.
Итак ГИС- автоматизированная информационная система, предназначенная для обработки пространственно-временных данных, основой интеграции которых служит
географическая информация.
В ГИС осуществляется комплексная обработка информации - от ее сбора до хранения, обновления и представления, в связи с этим следует рассмотреть ГИС с различных позиций.
Как системы управления ГИС предназначены для обеспечения принятия решений по оптимальному управлению землями и ресурсами, городским хозяйством, по управлению
транспортом и розничной торговлей, использованию океанов или других пространственных объектов. При этом для принятия решений в числе других всегда используют картографические данные.
В отличие от АСУ в ГИС появляется множество новых технологий пространственного
анализа данных. В силу этого ГИС служат мощным средством преобразования и синтеза
разнообразных данных для задач управления.
Как автоматизированные информационные системы ГИС объединяют ряд технологий
или технологических процессов известных информационных систем типа автоматизированных систем научных исследований (АСНИ), систем автоматизированного проектирования (САПР), автоматизированных справочно-информационных систем (АСИС) и др.
6
Основу интеграции технологий ГИС составляют технологии САПР. Поскольку технологии САПР достаточно апробированы, это, с одной стороны, обеспечило качественно более
высокий уровень развития ГИС, с другой - существенно упростило решение проблемы
обмена данными и выбора систем технического обеспечения. Этим самым ГИС стали в
один ряд с автоматизированными системами общего назначения типа САПР, АСНИ,
АСИС.
7
ЦЕЛИ И ЗАДАЧИ РАБОТЫ
Целью данной дипломной работы является создание модуля для получения вы-
сотных данных и картографической системы для их обработки с последующим построением 3-х мерной модели на основе полученных высотных данным, для решения задачи выделения области подтопления при подъеме уровня воды в водоемах.
В программной реализации работы используется свободно распространяемое программное обеспечение NASA World Wind.
Реализация данной картографической системы предполагает решение следующих
задач:
 поиска свободных источников высотных данных;
 организацию процесса получения свободно распространяемых высотных данных;
 формирования системы хранения полученных данных;
 разработка плагина для NASA World Wind для получения высотных данных о любых объектах поверхности планеты;
 создание системы подготовки к визуализации полученных данных;
 разработка средств визуализирования высотных данных;
 реализация системы обозначения области подтопления;
 создание пользовательского интерфейса для плагина;
 создание пользовательского интерфейса для системы обработки данных;
8
ГЛАВА 1. ОСНОВНЫЕ ПОЛОЖЕНИЯ ГЕОИНФОРМАЦИОННЫХ
СИСТЕМ
1.1. Классификация геоинформационных систем
Геоинформационные системы (также ГИС — географическая информационная система)
— системы, предназначенные для сбора, хранения, анализа и графической визуализации
пространственных данных и связанной с ними информации о представленных в ГИС объектах. Другими словами, это инструменты, позволяющие пользователям искать, анализировать и редактировать цифровые карты, а также дополнительную информацию об объектах, например высоту здания, адрес, количество жильцов.
ГИС включают в себя возможности систем управления базами данных (СУБД), редакторов растровой и векторной графики и аналитических средств и применяются в картографии, геологии, метеорологии, землеустройстве, экологии, муниципальном управлении,
транспорте, экономике, обороне и многих других областях.
По территориальному охвату различают глобальные ГИС, субконтинентальные ГИС,
национальные ГИС, зачастую имеющие статус государственных, региональные ГИС, субрегиональные ГИС и локальные, или местные ГИС.
ГИС различаются предметной областью информационного моделирования, к примеру,
городские ГИС, или муниципальные ГИС, природоохранные ГИС и т. п.; среди них особое наименование, как особо широко распространённые, получили земельные информационные системы. Проблемная ориентация ГИС определяется решаемыми в ней задачами
(научными и прикладными), среди них инвентаризация ресурсов (в том числе кадастр),
анализ, оценка, мониторинг, управление и планирование, поддержка принятия решений.
Интегрированные ГИС, ИГИС совмещают функциональные возможности ГИС и систем
цифровой обработки изображений (данных дистанционного зондирования) в единой интегрированной среде.
Полимасштабные, или масштабно-независимые ГИС основаны на множественных, или
полимасштабных представлениях пространственных объектов обеспечивая графическое
или картографическое воспроизведение данных на любом из избранных уровней масштабного ряда на основе единственного набора данных с наибольшим пространственным
разрешением. Пространственно-временные ГИС оперируют пространственновременными данными. Реализация геоинформационных проектов, создание ГИС в широком смысле слова, включает этапы: предпроектных исследований, в том числе изучение
требований пользователя и функциональных возможностей используемых программных
средств ГИС, технико-экономическое обоснование, оценку соотношения «затраты/прибыль»; системное проектирование ГИС, включая стадию пилот-проекта , разработку ГИС; её тестирование на небольшом территориальном фрагменте, или тестовом участке , прототипирование, или создание опытного образца, или прототипа ; внедрение ГИС;
эксплуатацию и использование. Научные, технические, технологические и прикладные
аспекты проектирования, создания и использования ГИС изучаются геоинформатикой.
9
1.2.История ГИС
a)
Начальный период (поздние 1950е — ранние 1970е гг.)
Исследование принципиальных возможностей, пограничных областей знаний и технологий, наработка эмпирического опыта, первые крупные проекты и теоретические работы.
 Появление электронных вычислительных машин (ЭВМ) в 50-х годах.
 Появление плоттеров, графических дисплеев и других периферийных устройств в 60-х.
 Создание программных алгоритмов и процедур графического отображения информации на дисплеях и с помощью плоттеров.
 Создание формальных методов пространственного анализа.
 Создание программных средств управления базами данных.
 Период государственных инициатив (нач. 1970е — нач. 1980е гг.)
Государственная поддержка ГИС стимулировала развитие экспериментальных работ в области ГИС, основанных на использовании баз данных по уличным сетям:
 Автоматизированные системы навигации.
 Системы вывоза городских отходов и мусора.
 Движение транспортных средств в чрезвычайных ситуациях и т. д.
b)
Период коммерческого развития (ранние 1980е — настоящее время)
Широкий рынок разнообразных программных средств, развитие настольных ГИС, расширение области их применения за счет интеграции с базами непространственных данных, появление сетевых приложений, появление значительного числа непрофессиональных пользователей, системы, поддерживающие индивидуальные наборы данных
на отдельных компьютерах, открывают путь системам, поддерживающим корпоративные и распределенные базы геоданных.
c)
Пользовательский период (поздние 1980е — настоящее время)
Повышенная конкуренция среди коммерческих производителей геоинформационных технологий услуг дает преимущества пользователям ГИС, доступность и «открытость»
программных средств позволяет использовать и даже модифицировать программы, появление пользовательских «клубов», телеконференций, территориально разобщенных,
но связанных единой тематикой пользовательских групп, возросшая потребность в геоданных, начало формирования мировой геоинформационной инфраструктуры.
1.3. Архитектура ГИС
Работающая ГИС включает в себя пять ключевых составляющих: аппаратные средства,
программное обеспечение, данные, исполнители и методы.
Аппаратные средства. Это компьютер, на котором запущена ГИС. В настоящее время
ГИС работают на различных типах компьютерных платформ, от централизованных серверов до отдельных или связанных сетью настольных компьютеров.
10
Программное обеспечение ГИС содержит функции и инструменты, необходимые для хранения, анализа и визуализации географической (пространственной) информации. Ключевыми компонентами программных продуктов являются: инструменты для ввода и оперирования географической информацией; система управления базой данных (DBMS или
СУБД); инструменты поддержки пространственных запросов, анализа и визуализации
(отображения); графический пользовательский интерфейс (GUI или ГИП) для легкого доступа к инструментам.
Данные. Это вероятно наиболее важный компонент ГИС. Данные о пространственном положении (географические данные) и связанные с ними табличные данные могут собираться и подготавливаться самим пользователем, либо приобретаться у поставщиков на коммерческой или другой основе. В процессе управления пространственными данными ГИС
интегрирует пространственные данные с другими типами и источниками данных, а также
может использовать СУБД, применяемые многими организациями для упорядочивания и
поддержки имеющихся в их распоряжении данных
Исполнители. Широкое применение технологии ГИС невозможно без людей, которые работают с программными продуктами и разрабатывают планы их использования при решении реальных задач. Пользователями ГИС могут быть как технические специалисты, разрабатывающие и поддерживающие систему, так и обычные сотрудники (конечные пользователи), которым ГИС помогает решать текущие каждодневные дела и проблемы.
Методы. Успешность и эффективность (в том числе экономическая) применения ГИС во
многом зависит от правильно составленного плана и правил работы, которые составляются в соответствии со спецификой задач и работы каждой организации.
1.4. Принципы функционирования ГИС
ГИС хранит информацию о реальном мире в виде набора тематических слоев, которые
объединены на основе географического положения. Этот простой, но очень гибкий подход
доказал свою ценность при решении разнообразных реальных задач: для отслеживания
передвижения транспортных средств и материалов, детального отображения реальной обстановки и планируемых мероприятий, моделирования глобальной циркуляции атмосферы и т.п..
Любая географическая информация содержит сведения о пространственном положении,
будь то привязка к географическим или другим координатам, или ссылки на адрес, почтовый индекс, избирательный округ или округ переписи населения, идентификатор земельного или лесного участка, название дороги и т.п. При использовании подобных ссылок
для автоматического определения местоположения или местоположений объекта (объектов) применяется процедура, называемая геокодированием. С ее помощью можно быстро
определить и посмотреть на карте где находится интересующий вас объект или явление,
такие как дом, в котором проживает ваш знакомый или находится нужная вам организация, где произошло землетрясение или наводнение, по какому маршруту проще и быстрее
добраться до нужного вам пункта или дома.
Векторная и растровая модели. ГИС может работать с двумя существенно отличающимися типами данных - векторными и растровыми. В векторной модели информация о точках,
линиях и полигонах кодируется и хранится в виде набора координат X,Y. Местоположение точки (точечного объекта), например буровой скважины, описывается парой координат (X,Y). Линейные объекты, такие как дороги, реки или трубопроводы, сохраняются как
наборы координат X,Y. Полигональные объекты, типа речных водосборов, земельных
11
участков или областей обслуживания, хранятся в виде замкнутого набора координат. Векторная модель особенно удобна для описания дискретных объектов и меньше подходит
для описания непрерывно меняющихся свойств, таких как типы почв или доступность
объектов. Растровая модель оптимальна для работы с непрерывными свойствами. Растровое изображение представляет собой набор значений для отдельных элементарных составляющих (ячеек), оно подобно отсканированной карте или картинке. Обе модели имеют свои преимущества и недостатки. Современные ГИС могут работать как с векторными,
так и с растровыми моделями.
ГИС общего назначения, в числе прочего, обычно выполняет пять процедур (задач) с
данными: ввод, манипулирование, управление, запрос и анализ, визуализацию.
Ввод. Для использования в ГИС данные должны быть преобразованы в подходящий цифровой формат. Процесс преобразования данных с бумажных карт в компьютерные файлы
называется оцифровкой. В современных ГИС этот процесс может быть автоматизирован с
применением сканерной технологии, что особенно важно при выполнении крупных проектов. При небольшом объеме работ, данные можно вводить с помощью дигитайзера.
Многие данные уже переведены в форматы, напрямую воспринимаемые ГИС-пакетами.
Манипулирование. Часто для выполнения конкретного проекта имеющиеся данные нужно
дополнительно видоизменить в соответствии с требованиями системы. Например, географическая информация может быть в разных масштабах (осевые линии улиц имеются в
масштабе 1: 100 000, границы округов переписи населения - в масштабе 1: 50 000, а жилые
объекты - в масштабе 1: 10 000). Для совместной обработки и визуализации все данные
удобнее представить в едином масштабе. ГИС-технология предоставляет разные способы
манипулирования пространственными данными и выделения данных, нужных для конкретной задачи.
Управление. В небольших проектах географическая информация может храниться в виде
обычных файлов. При увеличении объема информации и росте числа пользователей для
хранения, структурирования и управления данными эффективнее применять системы
управления базами данных (СУБД) с специальными компьютерными средствами для работы с интегрированными наборами данных (базами данных). В ГИС наиболее удобно
использовать реляционную структуру, при которой данные хранятся в табличной форме.
При этом для связывания таблиц применяются общие поля. Этот простой подход достаточно гибок и широко используется во многих, как ГИС, так и не ГИС приложениях.
Запрос и анализ. При наличии ГИС и географической информации имеется возможность
получать ответы простые вопросы (Кто владелец данного земельного участка? На каком
расстоянии друг от друга расположены эти объекты? Где расположена данная промзона?)
и более сложные, требующие дополнительного анализа, запросы (Где есть места для строительства нового дома? Каков основный тип почв под еловыми лесами? Как повлияет на
движение транспорта строительство новой дороги?). Запросы можно задавать как простым щелчком мышью на определенном объекте, так и с посредством развитых аналитических средств. С помощью ГИС можно выявлять и задавать шаблоны для поиска, проигрывать сценарии по типу “что будет, если…”. Современные ГИС имеют множество мощных инструментов для анализа, среди них наиболее значимы два: анализ близости и анализ наложения. Для проведения анализа близости объектов относительно друг друга в
ГИС применяется процесс, называемый буферизацией. Он помогает ответить на вопросы
типа: Сколько домов находится в пределах 100 м от этого водоема? Сколько покупателей
живет не далее 1 км от данного магазина? Процесс наложения включает интеграцию данных, расположенных в разных тематических слоях. В простейшем случае это операция
отображения, но при ряде аналитических операций данные из разных слоев объединяются
12
физически. Наложение, или пространственное объединение, позволяет, например, интегрировать данные о почвах, уклоне, растительности и землевладении со ставками земельного налога.
Визуализация. Для многих типов пространственных операций конечным результатом является представление данных в виде карты или графика. Карта - это очень эффективный и
информативный способ хранения, представления и передачи географической (имеющей
пространственную привязку) информации. Раньше карты создавались на столетия. ГИС
предоставляет новые удивительные инструменты, расширяющие и развивающие искусство и научные основы картографии. С ее помощью визуализация самих карт может быть
легко дополнена отчетными документами, трехмерными изображениями, графиками и
таблицами, фотографиями и другими средствами, например, мультимедийными.
Связанные технологии. ГИС тесно связана рядом других типов информационных систем.
Ее основное отличие заключается в способности манипулировать и проводить анализ пространственных данных. Хотя и не существует единой общепринятой классификации информационных систем, приведенное ниже описание должно помочь дистанциировать
ГИС от настольных картографических систем (desktop mapping), систем САПР (CAD), дистанционного зондирования (remote sensing), систем управления базами данных (СУБД
или DBMS) и технологии глобального позиционирования (GPS).
Системы настольного картографирования используют картографическое представление
для организации взаимодействия пользователя с данными. В таких системах все основано
на картах, карта является базой данных. Большинство систем настольного картографирования имеет ограниченные возможности управления данными, пространственного анализа
и настройки. Соответствующие пакеты работают на настольных компьютерах - PC,
Macintosh и младших моделях UNIX рабочих станций.
Системы САПР способны чертежи проектов и планы зданий и инфраструктуры. Для объединения в единую структуру они используют набор компонентов с фиксированными параметрами. Они основываются на небольшом числе правил объединения компонентов и
имеют весьма ограниченные аналитические функции. Некоторые системы САПР расширены до поддержки картографического представления данных, но, как правило, имеющиеся в них утилиты не позволяют эффективно управлять и анализировать большие базы
пространственных данных.
Дистанционное зондирование и GPS. Методы дистанционного зондирования - это искусство и научное направление для проведения измерений земной поверхности с использованием сенсоров, таких как различные камеры на борту летательных аппаратов, приемники
системы глобального позиционирования или других устройств. Эти датчики собирают
данные в виде изображений и обеспечивают специализированные возможности обработки, анализа и визуализации полученных изображений. Ввиду отсутствия достаточно мощных средств управления данными и их анализа, соответствующие системы вряд ли можно
отнести к настоящим ГИС.
Системы управления базами данных предназначены для хранения и управления всеми типами данных, включая географические (пространственные) данные. СУБД оптимизированы для подобных задач, поэтому во многие ГИС встроена поддержка СУБД. Эти системы
не имеют сходных с ГИС инструментов для анализа и визуализации.
1.5. Применение ГИС
Делать пространственные запросы и проводить анализ. Способность ГИС проводить поиск в базах данных и осуществлять пространственные запросы позволила многим компаниях сэкономить миллионы долларов. ГИС помогает сократить время получения ответов
на запросы клиентов; выявлять территории подходящие для требуемых мероприятий; вы-
13
являть взаимосвязи между различными параметрами (например, почвами, климатом и
урожайностью с/х культур); выявлять места разрывов электросетей. Риэлторы используют
ГИС для поиска, к примеру, всех домов на определенной территории, имеющих шиферные крыши, три комнаты и 10-метровые кухни, а затем выдать более подробное описание
этих строений. Запрос может быть уточнен введением дополнительных параметров,
например стоимостных. Можно получить список всех домов, находящих на определенном
расстоянии от определенной магистрали, лесопаркового массива или места работы.
Улучшить интеграцию внутри организации. Многие применяющие ГИС организации обнаружили, что одно из основных ее преимуществ заключается в новых возможностях
улучшения управления собственной организацией и ее ресурсами на основе географического объединения имеющихся данных и возможности их совместного использования и
согласованной модификации разными подразделениями. Возможность совместного использования и постоянно наращиваемая и исправляемая разными структурными подразделениями база данных позволяет повысить эффективность работы как каждого подразделения, так и организации в целом. Так, компания, занимающаяся инженерными коммуникациями, может четко спланировать ремонтные или профилактические работы, начиная с
получения полной информации и отображения на экране компьютера (или на бумажных
копиях) соответствующих участков, например водопровода, и заканчивая автоматическим
определением жителей, на которых эти работы повлияют, и уведомлением их о сроках
предполагаемого отключения или перебоев с водоснабжением.
Принятие более обоснованных решений. ГИС, как и другие информационные технологии,
подтверждает известную поговорку о том, что лучшая информированность помогает принять лучшее решение. Однако, ГИС - это не инструмент для выдачи решений, а средство,
помогающее ускорить и повысить эффективность процедуры принятия решений, обеспечивающее ответы на запросы и функции анализа пространственных данных, представления результатов анализа в наглядном и удобном для восприятия виде. ГИС помогает,
например, в решении таких задач, как предоставление разнообразной информации по запросам органов планирования, разрешение территориальных конфликтов, выбор оптимальных (с разных точек зрения и по разным критериям) мест для размещения объектов и
т. д. Требуемая для принятия решений информация может быть представлена в лаконичной картографической форме с дополнительными текстовыми пояснениями, графиками и
диаграммами. Наличие доступной для восприятия и обобщения информации позволяет
ответственным работникам сосредоточить свои усилия на поиске решения, не тратя значительного времени на сбор и осмысливание доступных разнородных данных. Можно достаточно быстро рассмотреть несколько вариантов решения и выбрать наиболее эффектный и эффективный.
Создание карт. Картам в ГИС отведено особое место. Процесс создания карт в ГИС
намного более прост и гибок, чем в традиционных методах ручного или автоматического
картографирования. Он начинается с создания базы данных. В качестве источника получения исходных данных можно пользоваться и оцифровкой обычных бумажных карт. Основанные на ГИС картографические базы данных могут быть непрерывными (без деления
на отдельные листы и регионы) и не связанными с конкретным масштабом. На основе таких баз данных можно создавать карты (в электронном виде или как твердые копии) на
любую территорию, любого масштаба, с нужной нагрузкой, с ее выделением и отображением требуемыми символами. В любое время база данных может пополняться новыми
данными (например, из других баз данных), а имеющиеся в ней данные можно корректировать по мере необходимости. В крупных организациях созданная топографическая база
данных может использоваться в качестве основы другими отделами и подразделениями,
при этом возможно быстрое копирование данных и их пересылка по локальным и глобальным сетям.
14
Выводы
В настоящее время происходит активное развитие картографических систем.
Учеными подсчитано, что 85% информации, с которой сталкивается человек в своей жизни, имеет территориальную привязку. Этим системам можно найти применение практически в любой сфере трудовой деятельности человека. ГИС эффективны во всех областях,
где осуществляется учет и управление территорией, и объектами на ней.
Вследствие быстрого развития ИТ, мобильных устройств и широком их распространению становится актуальной решение картографических задач, которых находят
применение как для личного пользования таки для организаций, малого и среднего бизнеса. К числу таких задач можно также отнести тематические задачи с дополнительными
косвенно привязанными к местности данными, например: распространение болезней и
эпидемий, выделение области подтопления при разливах рек. Последняя из перечисленных задач и является темой данной работы. Предполагается реализация приложения позволяющего наглядно видеть результаты повышения уровня воды в водоеме в 3-х мерном
виде с цветовой маркировкой областей имеющих потенциальную возможность затопления.
15
ГЛАВА 2. СРЕДСТВА ПОСТРОЕНИЯ ГЕОИНФОРМАЦИОННЫХ СИСТЕМ В
.NET
Вначале сравним .NET с другой более ранней средой разработки распределенных
приложений. Затем я перечислю возможности .NET, позволяющие создавать мощные распределенные приложения в сжатые сроки.
2.1 Windows DMA и .NET
Фраза, которой характеризуется .NET: "новая среда для создания и запуска надежных,
масштабируемых, распределенных приложений". Дело в том, что .NET является продолжением предыдущей попытки достичь этой цели. Та платформа называлась Windows
DNA. Однако перспектив у .NET по сравнению с Windows DNA несопоставимо больше.
Платформа Windows DNA была нацелена на решения для бизнеса посредством серверных
продуктов Microsoft. К Windows DNA порой применяли слово "клей" в таком, например,
контексте: "DNA — это клей, с помощью которого соединяются надежные, масштабируемые, распределенные системы". Однако, будучи только технической спецификацией,
Windows DNA не имело каких-то осязаемых компонентов. Это только одно из ряда основных различий между Windows DNA и .NET. В Microsoft .NET, кроме набора спецификаций, входит несколько реальных продуктов: компиляторы, библиотеки классов и даже целые приложения для конечных пользователей.
2.1.1. Common Language Runtime
Common Language Runtime (CLR) — это сердце технологии Microsoft .NET. Как следует
из названия, это среда времени выполнения кода, в которой обеспечивается эффективное
взаимодействие приложений, пересекающее границы разных языков программирования
(cross-language interoperability). Common Language Specification (CLS) — это набор правил,
которых должен придерживаться компилятор языка при создании .NET-приложений, запускаемых в среде CLR. Любой, кто захочет написать компилятор для .NET, должен следовать этим правилам, и приложения, сгенерированные этим компилятором, будут работать наряду с другими .NET-прило-жениями и будут иметь такую же возможность взаимодействия.
С CLR связана важная концепция управляемого кода (managed code) — кода, выполняемого только в среде CLR и управляемого ею. Напомню, что во время исполнения в нынешних ОС Microsoft Windows мы имеем дело с разнородными независимыми друг от
друга процессами. Единственное требование, которому должны отвечать приложения в
среде Windows, состоит в том, чтобы они правильно работали. Эти приложения создаются
совершенно разными компиляторами. Иначе говоря, приложения должны подчиняться
только наиболее общим правилам работы под Windows.
В среде Windows есть несколько глобальных правил поведения приложений, относящихся
к их взаимодействию друг с другом, распределению памяти, а также к привлечению
средств самой ОС для работы от их имени. Напротив, в среде управляемого кода есть
набор правил, обеспечивающих единообразное в глобальном смысле поведение всех приложений независимо от того, на каком языке они написаны. Единообразное поведение
.NET-приложений — характерная черта технологии .NET, и его нельзя игнорировать.
2.1.2. Microsoft Intermediate Language и компиляторы JITter
Для облегчения перевода языков в среду .NET в Microsoft разработан промежуточный
язык — Microsoft Intermediate Language (MSIL). Чтобы откомпилировать приложение для
.NET, компиляторы берут исходный код и создают из него MSIL-код. MSIL — это полноценный язык, пригодный для написания приложений.
16
Результатом компиляции приложения, написанного на С# или другом языке, который отвечает правилам CLS, является MSIL-код. Потом, при первом запуске приложения в среде
CLR, MSIL-код компилируется в машинные команды, специфичные для данного процессора. (На самом деле компилируются только функции, вызываемые впервые.)
Поскольку мы все пока новички в этой технологии, а книга наша посвящена С#, посмотрим по порядку, что же происходит с кодом.
Вы пишете исходный код на С#.
Затем вы компилируете его с помощью компилятора языка С# в ЕХЕ-файл.
Компилятор создает MSIL-код и помещает в раздел "только-на-чте-ние" выходного файла
стандартный РЕ-заголовок (признак машино-независимой выполняемой программы для
Win32). Но здесь появляется очень важная деталь: при создании выходного файла компилятор импортирует из CLR функцию _CorExeMain.
Когда приложение начинает выполняться, ОС загружает этот РЕ (впрочем, как и обычный
РЕ), а также все нужные DLL, в частности, библиотеку, которая экспортирует функцию
_CorExeMain (mscoree.dll).
Загрузчик ОС выполняет переход в точку входа РЕ, устанавливаемую компилятором. Это
ничем не отличается от процедуры загрузки в Windows любого другого РЕ.
Однако так как ОС не в состоянии выполнить MSIL-код, то фактически в точке входа содержится заглушка, в которой установлена команда перехода к функции jCorExeMain из
mscoree.dll.
Функция JCorExeMain переходит к выполнению MSIL-кода, помещенного в РЕ.
Так как MSIL-код не может быть выполнен непосредственно (ведь это не машинный код),
CLR компилирует его с помощью оперативного (just-in-time, или JIТ) компилятора (его
еще называют JITter) в команды процессора. Эта компиляция выполняется только для
непосредственно вызываемых методов программы. Откомпилированный выполняемый
код сохраняется на машине и перекомпилируется только в случае изменения исходного
кода. Для преобразования MSIL в настоящий машинный код можно применить один из
следующих JIТ-компиляторов.
Генератор кода при установке (Install-time code generation) Выполняет компиляцию всей
сборки в двоичный код, специфичный для данного процессора, подобно тому, как это делает компилятор С#. Сборка (assembly) — это комплект модулей кода, посылаемый компилятору. (О сборках подробнее я расскажу ниже в разделе "Развертывание".) Эта компиляция выполняется в ходе установки, когда обработка Сборки ЛТ-компилятором меньше
всего заметна для конечного пользователя. Достоинство этого типа генерации двоичного
кода в том, что компиляция всей сборки выполняется один раз еще до запуска приложения. Поскольку код скомпилирован, то о потере производительности при первом вызове
метода приложения можно не беспокоиться.
JIT Стандартный JITter, вызываемый при выполнении приложения каждый раз для впервые активизируемого метода (в порядке, описанном выше). Это напоминает плату в намеченный срок. Данный режим работает по умолчанию, если вы не запускаете явно компилятор РrеJIТ.
EconoJIT Включается во время выполнения приложения и предназначен специально для
систем, которые имеют ограниченные ресурсы, например, для портативных устройств с
малым размером памяти. Основное отличие этого компилятора от обычного JITter — в
объединении кодовых фрагментов (code pitching). Благодаря разбивке кода на фрагменты
EconoJIT может удалить сгенерированный (т. е. откомпилированный) код, если памяти
для запуска системы недостаточно. Достоинство этого компилятора в экономии памяти, а
недостаток в том, что если фрагментированный код загружается вновь, он должен быть
опять перекомпилирован как код, который еще никогда не вызывался.
17
2.1.3. Преимущества и недостатки
Microsoft .NET — это переход на вычислительную модель, в которой устройства, службы
и компьютеры работают совместно, обеспечивая создание решений для пользователей.
Центром этого перехода являются разработка .NET Framework и CLR .NET Framework содержит библиотеки классов, совместно используемые различными языками, которые компилируются для запуска в среде CLR. Поскольку С# разработан для CLR, вы не сможете
решить даже простейшие задачи без CLR и библиотек классов .NET Framework.
2.2 DirectX
2.2.1. История
Изначально нацеленный на разработку видеоигр, DirectX стал популярен и в других областях разработки программного обеспечения. К примеру, DirectX, наряду с OpenGL, получил очень широкое распространение в инженерном/математическом ПО.
В 1994 году Microsoft была практически готова выпустить следующую версию Windows
— Windows 95. Главным фактором, определяющим, насколько популярна будет новая ОС,
являлся набор программ, которые можно будет запускать под её управлением. В Microsoft
пришли к выводу, что, пока разработчики видят DOS более подходящей для написания
игровых приложений, коммерческий успех новой ОС весьма сомнителен.
DOS позволяла разработчику получить прямой доступ к видеокарте, клавиатуре/мыши/джойстику и прочим частям системы, в то время как Windows 95, с её защищённой моделью памяти, предоставляла более стандартизованный, но в то же время весьма
ограниченный доступ к устройствам. Microsoft нуждалась в новом способе дать разработчику всё, что ему необходимо.
Первый релиз DirectX был выпущен в сентябре 1995 года, под названием «Windows Game
SDK».
Ещё до появления DirectX, Microsoft включила OpenGL в ОС Windows NT. Direct3D позиционировался как замена OpenGL в игровой сфере. Отсюда берёт своё начало «священная
война» между сторонниками кросс-платформенной OpenGL и доступной лишь в Windows
Direct3D. Так или иначе, остальные части DirectX очень часто комбинируются с OpenGL в
компьютерных играх, так как OpenGL как таковой не подразумевает функциональность
уровня DirectX (например, доступ к клавиатуре/джойстику/мыши, поддержка звука, игры
по сети и т. д.).
DirectX является базой для Xbox API. Xbox API схож с DirectX 8.1, но обновление версии,
как и на других консолях того времени, невозможно.
В 2002 году Microsoft выпустила DirectX 9 с улучшенной и расширенной поддержкой
шейдеров. С 2002 года DirectX неоднократно обновлялся. В августе 2004 года в DirectX
была добавлена поддержка шейдеров версии 3.0 (DirectX 9.0c).
В апреле 2005 интерфейс DirectShow был перемещён в Microsoft Platform SDK.
2.2.2. DirectX API
Практически все части DirectX API представляют собой наборы COM-совместимых объектов.
В целом, DirectX подразделяется на:
 DirectX Graphics, набор интерфейсов, ранее (до версии 8.0) делившихся на:
 DirectDraw: интерфейс вывода растровой графики. (Его разработка давно прекращена)
 Direct3D (D3D): интерфейс вывода трёхмерных примитивов.
18









DirectInput: интерфейс, используемый для обработки данных, поступающих с клавиатуры, мыши, джойстика и пр. игровых контроллеров.
DirectPlay: интерфейс сетевой коммуникации игр.
DirectSound: интерфейс низкоуровневой работы со звуком (формата Wave)
DirectMusic: интерфейс воспроизведения музыки в форматах Microsoft.
DirectShow: интерфейс, используемый для ввода/вывода аудио и/или видео данных.
DirectX Instruments — технология, позволяющая на основе мультимедийного API
DirectX создавать и использовать программные синтезаторы. В отличие от DXплагинов, такие программы могут полностью управляться по MIDI и служат главным образом не для обработки, а для синтеза звука. Технология DXi была популярна в 2001—2004 гг., особенно в программных продуктах Cakewalk, но со временем проиграла «войну форматов» технологии VST от Steinberg.
DirectSetup: часть, ответственная за установку DirectX.
DirectX Media Objects: реализует функциональную поддержку потоковых объектов
(например, кодировщики/декодировщики)
Direct2D : интерфейс вывода двухмерной графики
2.2.3. Интерфейсы DirectDraw и DirectDraw2
В первоначальном варианте библиотеки DirectX (еще в те времена, когда она называлась
Game SDK) вся основная функциональность DirectDraw была сосредоточена в интерфейсе
DirectDraw. Позднее, с выходом DirectX 2, рабочий интерфейс был усовершенствован. В
соответствии со спецификацией СОМ интерфейс DirectDraw не изменился, а для работы с
новыми возможностями использовался новый интерфейс DirectDraw2.
Следует заметить, что интерфейс DirectDraw2 представляет собой расширение DirectDraw.
Он предоставляет все возможности интерфейса DirectDraw, а также ряд дополнительных.
При работе с DirectX версий 2 и выше можно выбирать между интерфейсом DirectDraw и
DirectDraw2. Поскольку DirectDraw2 делает все то же, что и DirectDraw, а также многое
другое, вряд ли можно найти какие-то доводы в пользу работы с DirectDraw. Кроме того,
Microsoft выступает против хаотичного, непоследовательного использования этих интерфейсов. По этим причинам во всех программах, приведенных в книге, будет использован
интерфейс DirectDraw2.
Ниже перечислены все функции интерфейсов DirectDraw и DirectDraw2 (в алфавитном
порядке):
Compact ()
CreateCIpper()
CreatePalette()
CreateSurface()
DuplicateSurface()
EnumDisplayModes()
EnumSurfaces()
FlipToGDISurface()
GetAvailableVidMem()
GetCaps()
GetDisplayMode()
GetFourCCCodes()
GetGDISurface()
GetMonitorFrequency()
GetScanLine()
GetVerticalBlankStatus()
19
RestoreDisplayMode()
SetCooperativeLevel()
SetDisplayMode()
WaitForVerticalBlank()
Далее рассмотрены важные для реализации приложения функции интерфейса DirectDraw.
Обратим внимание на то, что в оставшейся части этой главы термин интерфейс
DirectDraw относится как к интерфейсу DirectDraw, так и к DirectDraw2. Уточнения будут
приведены лишь в тех случаях, когда функция отличается в двух интерфейсах.
2.2.3.1 Функции создания интерфейсов
Интерфейс DirectDraw представляет саму библиотеку DirectDraw. Этот интерфейс является главным в том отношении, что в нем создаются экземпляры всех остальных интерфейсов DirectDraw. Интерфейс DirectDraw содержит три функции, предназначенные для создания экземпляров интерфейсов:
CreateClipper()
CreatePalette()
CreateSurface()
Функция CreateClipper создает экземпляры интерфейса DirectDrawClipper. Объекты отсечения (clipper) используются не всеми приложениями DirectDraw, так что в некоторых
программах эта функция может отсутствовать.
Функция CreatePalette создает экземпляры интерфейса DirectDrawPalette. Палитры, как и
интерфейс DirectDrawClipper, используются не всеми приложениями DirectDraw. Например, приложению, работающему только с 16-битными видеорежимами, палитра не понадобится. Тем не менее приложение, работающее в 8-битном видеорежиме, должно создать
хотя бы один экземпляр DirectDrawPalette.
Экземпляры интерфейса DirectDrawSurface создаются функцией CreateSurface. Поверхности обязательно присутствуют в любом приложении DirectDraw, работающем с графическими данными, поэтому данная функция используется очень часто.
Экземпляры самого интерфейса DirectDraw создаются функцией DirectDraw Create(),
DirectDrawCreate() — одна из немногих самостоятельных функций DirectDraw, не принадлежащих никакому СОМ-интерфейсу.
Функция GetCaps() инициализирует два экземпляра структуры DDCAPS. Первая структура показывает, какие возможности поддерживаются непосредственно видеокартой, а вторая — что доступно посредством программной эмуляции. Функция GetCaps() помогает
определить, поддерживаются ли нужные возможности.
DirectDraw автоматически использует аппаратную поддержку, если она имеется, и по
умолчанию в случае необходимости переключается на программную эмуляцию. Неудачей
заканчиваются вызовы лишь тех функций, которые не поддерживаются ни на аппаратном,
ни на программном уровне.
2.2.3.2 DirectX Viewer
В DirectX SDK входит программа DXVIEW, которая сообщает о возможностях всех компонентов DirectX, в том числе и DirectDraw. На большинстве компьютеров информация о
DirectDraw отображается в двух категориях: Primary Display Driver и Hardware Emulation
20
Layer. Первая категория сообщает о возможностях аппаратных видеосредств. Во второй
перечислены возможности, эмулируемые DirectDraw при отсутствии аппаратной поддержки. На компьютерах с двумя и более видеокартами, поддерживаемыми DirectDraw,
DXVIEW выводит сведения о способностях каждой из них.
Функция SetCooperativeLevelО определяет уровень кооперации — степень контроля над
видеокартой, необходимую для данного приложения. Например, нормальный (normal)
уровень кооперации означает, что приложение не сможет изменить текущий видеорежим
или задать содержимое всей системной палитры. Монопольный (exclusive) уровень допускает переключение видеорежимов и предоставляет приложению полный контроль над палитрой. Независимо от выбранного уровня вам необходимо вызвать SetCooperativeLevel().
2.2.3.3 Функции для работы с видеорежимами
Интерфейс DirectDraw содержит четыре функции для работы с видеорежимами:
С помощью функции EnumDisplayModes() можно получить от DirectDraw список доступных видеорежимов. По умолчанию EnumDisplayModes() перечисляет все видеорежимы,
но по описаниям можно исключить из списка режимы, не представляющие интереса. На
рынке существует огромное количество видеоустройств, каждое из которых обладает своими возможностями и ограничениями. Не стоит полагаться на автоматическую поддержку
любого конкретного видеорежима, за исключением принятого по умолчанию в Windows
режима 640х480х8.
Функция GetDisplayMode() получает сведения о текущем видеорежиме. Она заполняет
структуру DDSURFACEDESC информацией о горизонтальном и вертикальном разрешениях, глубине и формате пикселей текущего видеорежима. Ту же информацию можно получить и другими способами (например, по описанию первичной поверхности), поэтому
эта функция встречается не во всех программах.
Функция SetDisplayMode() активизирует заданный видеорежим. Версия SetDisplay Mode()
из интерфейса DirectDraw2 позволяет дополнительно задать частоту смены кадров. Этим
она отличается от функции из интерфейса DirectDraw, в которой можно задать только горизонтальное и вертикальное разрешения и глубину пикселей. Функция SetDisp1ayMode()
присутствует в любой программе, осуществляющей переключение видеорежимов.
Функция RestoreDisplayMode() восстанавливает видеорежим, действовавший до вызова
SetDisplayMode(). Перед вызовом функций SetDisplayMode() и RestoreDisplayMode()
необходимо предварительно установить монопольный уровень кооперации вызовом
функции SetCooperativeLevel ().
2.2.3.4 Функции для работы с поверхностями
Помимо функции CreateSurface() интерфейс DirectDraw содержит следующие функции
для работы с поверхностями:
Функция DuplicateSurface() создает копию существующей поверхности. Она копирует
только интерфейс поверхности, но не ее содержимое. Копия поверхности использует ту
же область памяти, поэтому модификация содержимого памяти приведет к изменению
изображения, представленного обеими поверхностями.
21
Функция EnumSurfaces() используется для перебора всех поверхностей, удовлетворяющих
заданному критерию. Если критерий не указан, составляется список всех существующих
поверхностей.
Функция FlipToGDISurface() используется перед завершением приложения, осуществляющего переключение страниц, чтобы обеспечить правильное восстановление первичной
поверхности. Вспомните о том, что при переключении страниц происходит попеременное
отображение двух поверхностей. Это означает, что приложение может завершиться, не
восстановив исходной поверхности, отображаемой на экране. Если это произойдет,
Windows будет осуществлять вывод на невидимую поверхность. Такой ситуации можно
легко избежать с помощью функции FlipToGDISurface().
Функция GetGDISurface возвращает указатель на единственную поверхность, с которой
работает GDI. Весь графический вывод Windows осуществляется именно на поверхность
GDI. Примером ситуации, когда эта функция может оказаться полезной, является программа копирования экрана, в которой DirectDraw используется для копирования произвольной части рабочего стола.
Функция GetAvailableVidMem() возвращает объем текущей доступной видеопамяти. Эта
функция присутствует в интерфейсе DirectDraw2, но отсутствует в DirectDraw. С ее помощью приложение может определить, сколько поверхностей ваше приложение сможет
создать в видеопамяти.
2.2.3.5 Функции для работы с частотой смены кадров
Интерфейс DirectDraw содержит четыре функции, относящихся не к видеокарте, а к
устройству отображения (монитору):
Говоря конкретно, эти функции относятся к механизму смены кадров на мониторе. С их
помощью можно реализовать анимации с минимальным мерцанием и задержками. Тем не
менее следует учесть, что эти функции поддерживаются не всеми комбинациями видеокарт и мониторов.
Функция GetMonitorFrequency() возвращает текущую частоту смены кадров монитора.
Эта частота обычно измеряется в герцах (Гц). Например, частота в 60 Гц означает, что состояние экрана обновляется 60 раз в секунду.
Функция GetScanLine() возвращает номер строки развертки (горизонтального ряда пикселей), обновляемой в данный момент. Она не поддерживается некоторыми комбинациями
видеокарт и мониторов. Если данная способность не поддерживается, функция возвращает код ошибки DDERR_UNSUPPORTED.
В высокопроизводительных графических приложениях обновление экрана обычно синхронизируется с процессом вертикальной развертки. Другими словами, первичную поверхность желательно обновлять в тот момент, когда монитор закончил очередное обновление экрана. В противном случае в одной части экрана будут отображаться новые данные, а в другой — старые. Подобный эффект называется расхождением (tearing). По
умолчанию DirectDraw автоматически синхронизирует обновление экрана с завершением
вертикальной развертки. В нестандартных ситуациях можно добиться синхронизации с
помощью функций GetVerticalBlankStatus() и WaitForVerticalBlank().
22
Выводы
Таким образом, данный набор средств, хорошо подходит для решения поставленной задачи создания приложения для получения высотных данных и реализации системы
обработки полученных высотных данных с последующим их графическим отображением.
Использование .NET Framework и DirectX даем простые и понятные интерфейсы
для взаимодействия с графической, файловой и многими другими системами компьютера
позволяя упростить разработку тем самым, уменьшая затрачиваемое время. Что, несомненно, всегда является неоспоримом плюсом при выборе платформы на которой предполагается разрабатывать приложение.
23
ГЛАВА 3. РЕАЛИЗАЦИЯ КОМПОНЕНТОВ КАРТОГРАФИЧЕСКОЙ СИСТЕМЫ
3.1. Введение в NASA World Wind
NASA World Wind — полностью трёхмерный интерактивный виртуальный глобус, созданный NASA. Использует спутниковые снимки NASA и аэрофотосъёмку USGS для построения трёхмерных моделей Земли, Луны, Марса, Венеры и Юпитера.
NASA World Wind использует несвободную лицензию с открытым исходным кодом. Из-за
используемых при разработке технологий (C#, DirectX) программа работает только под
управлением операционных систем семейства Windows NT.
Первоначально в программе содержатся карты с низким разрешением. При приближении
некоторой рассматриваемой области на карте, изображения с высоким разрешением скачиваются с серверов NASA.
Программа позволяет выбирать масштаб, направление и угол зрения, видимые слои, производить поиск по географическим названиям. Возможно отображение названий географических объектов и политических границ.
NASA World Wind имеет расширяемую архитектуру. Существуют плагины для работы с
GPS, для отображения облачности, землетрясений, ураганов в приближенно к реальному
времени и ряд других.
3.2. Создание plugin для NASA World Wind
Для решения поставленной задачи необходимо организовать получение, данных с которыми мы впоследствии будем работать. Для этого мы сначала разберем способ создание
типичного плагина для NASA World Wind , а после создадим свой плагин, который будет
позволять нам экспортировать данные из этой программы в удобный для нас формат.
24
Итак, самый простой способ разработки плагина, делать это внутри проекта NASA World
Wind.
3.2.1. Необходимое программного обеспечения
Следующее программное обеспечение должно быть установлено перед началом работы по
созданию плагина для NASA World Wind.
. NET Framework 2.0 SDK ( NET Framework 2.0 Software Development Kit (SDK) (x86) )
Примечание: Если у уже установлен Microsoft Visual Studio. NET 2005, то не нужно устанавливать. NET Framework SDK отдельно. Visual Studio. NET 2005 включает SDK.
Использование TortoiseSVN как средсво получения исходных кодов NASA Worl Wind.
Адрес репозитория SVN HTTPS: / / nasa-exp.svn.sourceforge.net/svnroot/nasaexp/trunk/WorldWind
3.2.3. Шаблон кода плагина
Теперь добавим пункт меню и простую функциональность, на этот пункт меню.
Добавим меню:
System.Windows.Forms.MenuItem menuItem;
Затем добавить следующие строки в ваш загрузочный метод:
menuItem = new System.Windows.Forms.MenuItem();
menuItem.Text = "Tutorial1 test";
menuItem.Click += new System.EventHandler(menuItem_Click);
ParentApplication.ToolsMenu.MenuItems.Add(menuItem);
Это позволит добавить пункт меню в главном меню World Wind .
Затем добавить следующие строки в метод выгрузки:
ParentApplication.ToolsMenu.MenuItems.Remove(menuItem);
Наконец мы будем добавлять функциональность к пункту меню. В настоящее время мы собираемся просто показать окна сообщения.
Добавить метод menuItem_Click так:
25
недействительным menuItem_Click (объект отправителя, EventArgs е)
(
System.Windows.Forms.MessageBox.Show ("Tutorial1 work.");
)
Конечный результат должен выглядеть примерно так:
namespace AnonDeveloper.Plugin
{
public class Tutorial1 : WorldWind.PluginEngine.Plugin
{
System.Windows.Forms.MenuItem menuItem;
public override void Load()
{
menuItem = new System.Windows.Forms.MenuItem();
menuItem.Text = "Tutorial1 test";
menuItem.Click += new System.EventHandler(menuItem_Click);
ParentApplication.ToolsMenu.MenuItems.Add(menuItem);
base.Load();
}
public override void Unload()
{
ParentApplication.ToolsMenu.MenuItems.Remove(menuItem);
base.Unload ();
}
void menuItem_Click(object sender, EventArgs e)
{
System.Windows.Forms.MessageBox.Show("Tutorial1 works.");
}
}
}
3.3 Отладка плагина
Запускаем на компиляцию наш проект плагина, плагин является новым и, следовательно, не загружаются автоматически. при запуске NASA World Wind, следовательно
надо его запустить:
26







В главном меню выберите пункт Plugins->Load/Unload.
Теперь надо найти Tutorial1 или имя, которое мы выбрали для нашего плагина в списке.
Нажимаем на него, и нажмите кнопку Загрузить.
Если все работает и наш плагин был успешно инициализирован, мы увидим,
что загорится зеленый индикатор слева от плагина.
Закрыть плагин менеджера.
Далее в выпадающем меню "Tools" в World Wind, можем видеть что появился пункт Tutorial test или другое название которое мы зададим.
Нажмаем на него для запуска плагина,
И как только плагин запустится, мы увидим наше тестовое сообщение.
3.4. Реализация плагина для получения высотных координат
Изучив приведенную документацию по интерфейсу WorldWind.PluginEngine.Plugin и способах взаимодействия с самим приложение Nasa World Wind приступим к непосредственной реализации плагина на языке c#.
Задачи плагина:
 Графически понятная для пользователя пометка области экспорта
 Создание пользовательского интерфейса плагина.
 Интеграция в систему NASA World Wind
 Разработка взаимодействия с программой построения 3-хмерной модели
 Создание функции экспорта данных
3.4.1
Графическое выделения копируемой области
Для отображения копируемой области будем использовать рамку прямоугольного вида
красного цвета.
27
3.4.2
Пользовательский интерфейс плагина
Разберем подробней интерфейс плагина.
На форме размещены поля ,широта и долгота которые указывают на координаты центра
обзора камеры, дальше видим регуляторы размера и угла наклона прямоугольника выделения. Ниже мы видим возможность копирования текстур , с выбором слоя с которого копировать текстуры и какого размера их делать. С права мы видим 2 кнопки для установки
контура выделения. И в самом низу формы мы можем задавать имя файла карты высот и
его описание. Также мы видим кнопку «Просмотр» который инициирует начало процесса
сохранения данных и вызов картографического приложения для отрисовки 3-хмерной модели.
28
3.4.3
Интеграция в меню NASA World Wind
Прежде чем наш плагин интегрируется в систему NASA World Wind нам необходимо его
скоприровать в иерархию папок программы. На рисунке помечена розовым фоном .
Откуда ее подхватит GIT компилятор .net framework и запустит. Но для этого также необходимо в настройках NASA World Wind включить загрузку нашего плагина . Зайдя в ме-
29
ню управления плагинами.
Выбрав наш плагин «Terrain Extractor» поставим галочку автоматического запуска и
нажмем кнопку «Load», которая запустит его в работу. После чего закрыв эту форму, и
зайдя в меню плагины мы увидим пункт меню «Плагин экспорта», который и является результатом труда на данном этапе.
30
3.4.4
Экспорт данных
Интеграцию плагина и приложения обрабатывающего данные в 3-х мерную модель мы
получим следующим образом. Разместим наше приложение в папке плагина и будем использовать туже иерархию каталогов что и плагин .
Такой подход позволит упростить обмен данными между приложениями, что даст более
стабильную и быструю работу приложения.
Экспорт данных из приложения NASA World Wind будет, осуществляется в папку
«maps» в формате бинарного файла и также текстуры. Эти файлы будет использовать в
дальнейшем наше приложение «TerrainViewer», которое и будет строить по ним 3хмерную модель.
Код экоспорта данных см. Приложение 3.
31
Разработка приложения просмотра 3-хмерной модели.
3.5
Разработка приложения Terrain Viewer началась с изучения возможностей DirectX, платформы .net и формата представления высотных данных SRTM. Для наглядности Рассмотрим территорию Гранд каньона США, поскольку резкие перепады высоты местности позволяют более явно наблюдать область затопления с учетом высот местности.
3.5.1
Пользовательский интерфейс
Мы видим меню, состоящее из: Файл, Карты, Вид, Текстуры, Края, Небо.
 Файл состоит из :

.
o Список карт - дает возможность выбора XML файла с описание карт и текстур.
o Выход - соответственно завершение работы приложения.
Карты состоит из списка карт, которые описаны в XML файле.
32
Например :
Код для генерации этого пункта меню:
public void InitializeMapList()
{
// Предварительная очистка меню
while(menuItemMaps.MenuItems.Count > 0) menuItemMaps.MenuItems.RemoveAt(0);
XmlTextReader reader = null;
// Загрузка о чтение XML файла настроек.
reader = new XmlTextReader(mapListFileName);
reader.WhitespaceHandling = WhitespaceHandling.None;
// Разбор файла настроек
while (reader.Read())
{
switch (reader.NodeType)
{
case XmlNodeType.Element:
switch(reader.Name)
{
case "map" :
if(reader["name"] != null)
// Добавление карты в меню
{
MenuItem mi = new MenuItem(reader["name"]);
mi.Click += new System.EventHandler(this.menuItemMaps_Click);
menuItemMaps.MenuItems.Add(mi);
}
break;
}
break;
}
}
reader.Close();
}

Вид состоит из
33
o Затенение – включает режим наложения теней (см. Приложение 1)
o Вода – включает отображение уровня океана (см. Приложение 1)
o Туман – включает графический эффект тумана (см. Приложение 1)
o Вращать - включает режим вращения камеры вокруг модели
o Вертикаль - состоит из списка величин с интервалов в 1. Служит в качестве
коэффициента для построения модели по высотной карте. Чем больше коэффициент тем выше строится модель. (см. Приложение 1)
Код для генерации этого пункта меню:
public void InitializeVerticalFactorMenu()
{
// Первым выбирается текущий
MenuItem mi = new MenuItem("(current)");
mi.Click += new System.EventHandler(this.menuItemVerticalFactor_Click);
menuItemVerticalFactor.MenuItems.Add(mi);
mi = new MenuItem("-");
menuItemVerticalFactor.MenuItems.Add(mi);
for(int i = 0; i <= 15; i++)
{
mi = new MenuItem("x" + i.ToString());
mi.Click += new System.EventHandler(this.menuItemVerticalFactor_Click);
menuItemVerticalFactor.MenuItems.Add(mi);
34
}
}

Текстуры – состоит из списка доступных текстур для наложения на модель, строится исходя из содержимого каталога «Colors» но по стандарту если вместе с картой высот была текстура, то выбирается именно она и отображается в самом верху
списка. (см. Приложение 1)
Пример меню:
Код для генерации этого пункта меню:
public void InitializeTexturesMenu()
{
// Первая ставится стандартная текстура для всех карт
MenuItem mi = new MenuItem("(default)");
mi.Click += new System.EventHandler(this.menuItemTextures_Click);
menuItemTextures.MenuItems.Add(mi);
mi = new MenuItem("-");
menuItemTextures.MenuItems.Add(mi);
// Считываение доступных текстур
string dir = "colors/";
DirectoryInfo di = new DirectoryInfo(dir);
FileInfo[] imgFiles = di.GetFiles("*.png");
for(int i = 0; i < imgFiles.Length; i++) // Добавление в меню
{
mi = new MenuItem(dir + imgFiles[i]);
mi.Click += new System.EventHandler(this.menuItemTextures_Click);
menuItemTextures.MenuItems.Add(mi);
}
}

Края - список текстур накладываемых на края модели, список строится аналогично
списку текстур. (см. Приложение 1)
35
Пример меню :
Код для генерации этого пункта меню:
public void InitializeSidesMenu()
{
// Первая ставится стандартная текстура старон для всех карт
MenuItem mi = new MenuItem("(default)");
mi.Click += new System.EventHandler(this.menuItemSides_Click);
menuItemSides.MenuItems.Add(mi);
mi = new MenuItem("-");
menuItemSides.MenuItems.Add(mi);
// Считываение доступных текстур
string dir = "colors/";
DirectoryInfo di = new DirectoryInfo(dir);
FileInfo[] imgFiles = di.GetFiles("*.png");
for(int i = 0; i < imgFiles.Length; i++) // Добавление в меню
{
mi = new MenuItem(dir + imgFiles[i]);
mi.Click += new System.EventHandler(this.menuItemSides_Click);
menuItemSides.MenuItems.Add(mi);
}
}

Небо - включает отображение изображения неба, строится исходя из файлов в каталоге «Skys» (см. Приложение 1)
Пример меню:
Код для генерации этого пункта меню:
36
public void InitializeSkyMenu()
{
// Первая ставится стандартная текстура неба
MenuItem mi = new MenuItem("(default)");
mi.Click += new System.EventHandler(this.menuItemSky_Click);
menuItemSky.MenuItems.Add(mi);
mi = new MenuItem("-");
menuItemSky.MenuItems.Add(mi);
// Считываение доступных текстур неба
string dir = "skys/";
DirectoryInfo di = new DirectoryInfo(dir);
FileInfo[] imgFiles = di.GetFiles("*.jpg");
for(int i = 0; i < imgFiles.Length; i++) // Добавление в меню jpg файлов
{
mi = new MenuItem(dir + imgFiles[i]);
mi.Click += new System.EventHandler(this.menuItemSky_Click);
menuItemSky.MenuItems.Add(mi);
}
imgFiles = di.GetFiles("*.png");
for(int i = 0; i < imgFiles.Length; i++) // Добавление в меню png файлов
{
mi = new MenuItem(dir + imgFiles[i]);
mi.Click += new System.EventHandler(this.menuItemSky_Click);
menuItemSky.MenuItems.Add(mi);
}
}
3.5.2
Управления приложением
Манипулятор мышь:
Мышь колесико: Приближение / отдаление
Левая клавиша мыши: Перемещение карты в плоскости x,y
Правая клавиша мыши: Изменение угла обзора
Обе клавиши вместе: смена позиции источника освещения в плоскости x,y
Клавиатура:
+ / - : Приближение / отдаление
Shift + / - : zoom камеры
Ctrl + / - : быстрая смена вертикального коэффициента
Up / down: двигать камеру вперед, назад
Left / right arrows: поворачивать модель влево, право
Shift left / right arrows: двигать камеру влево, право
Shift up / down arrows: поворачивать модель вверх, вниз
F / Shift F: включение тумана
L / Shift L: включение затенения
Ctrl L / Shift Ctrl L: выключить затенение
Enter / Space bar: включение, выключение вращения модели вокруг своей оси
3.5.3
Файл описания карт
Для описания данных о файле высот и используемых текстурах используется файл формата XML. Данный файл должен располагаться в одном каталоге с программой.
37
Разберем структуру данных подробней. XML файл имеет вид:
<maps>
<map name="Grand Canyon, Chuar Butte, USA - Colored, Geo">
<terrain demfile="maps\Grand_Canyon_Chuar_Butte_SRTM.bil" texturefile="colors\Geo_Water_1.png" altscale="1.0" centerlatitude="36.1950900669448" centerlongitude="-111.806173498171"/>
<sky skyfile="skys/Sky_Day1.jpg" />
</map>
<map name="Glacier National Park, USA - Colored, Geo">
<terrain demfile="maps\Galcier_Park_150_SRTM.bil" texturefile="colors\Geo_Water_1.png"
altscale="1.0" centerlatitude="48.6170532999835" centerlongitude="-113.536439102484" />
</map>
</maps>
Элемент map содержит атрибут name – отображаемое имя карты.
Внутри элемента map располагается элемент
o Terrain (описывает файл карты высот текстуры) с следующими атрибутами :
 demfile – файл карты высот
 texturefile – файл текстуры
 altscale – вертикальное увеличение
 centerlatitude – долгота центра данного куска карты
 centerlongitude – широта центра данного куска карты
o sky (описывает оформление эффекта неба) его атрибуты:
 skyfile – имя файла с текстурой неба
3.5.4
Обработка файла высот
После того как в меню выбирается нужная карта программа начинает загрузку карты высот из .bil файла.
1) Считывается бинарный 16 битный файл
2) С помощью функции FromArgb класса Color получаем цвет каждого пикселя высотной карты, что позже будет соответствовать высоте в данной точке. Чем темнее будет
цвет, тем выше будет точка.
3) Полученная битовая карта (Bitmap) отдается на отрисовку DirectX который строит поверхность по этим данным.
Код загрузки высотных данных:
private void LoadMap()
{
string errMsg = "";
// Установка имени карты в качестве заголовка приложения
this.Text = mapName + " - " + appName + " " + appVersion;
if(Path.GetExtension(terrainFileName) == ".bil" && mapSpan == 0) mapSpan
= GetSpanFromPath(terrainFileName);
if(worldRadius < 10000) worldRadius *= 1000; // Convert from Km to m
if(mapSpan != 0) mapWidth = (worldRadius * 2 * Math.PI) / 360 * mapSpan;
// Вычисление ширины карты в метрах
if(textureFileName == "") textureFileName = "colors/Geo_Water_1.png"; //
Выбор стандартной текстуры
if(sidesFileName == "" && textureFileName.StartsWith("colors")) sidesFileName = textureFileName;
if(sidesFileName == "") sidesFileName = "colors/Grid_1.png";
38
// Обновления света, води и тумана в
menuItemShowLight.Checked =
showLight;
menuItemShowWater.Checked = showWater;
menuItemShowFog.Checked = showFog;
// Обнавление меню текстур
MenuClearCheck(menuItemTextures);
for(int i = 0; i< menuItemTextures.MenuItems.Count; i++)
if(menuItemTextures.MenuItems[i].Text == textureFileName) menuItemTextures.MenuItems[i].Checked = true;
// Обновление меню боковых текстур
MenuClearCheck(menuItemSides);
for(int i = 0; i< menuItemSides.MenuItems.Count; i++)
if(menuItemSides.MenuItems[i].Text == sidesFileName) menuItemSides.MenuItems[i].Checked = true;
// Обновление меню неба
MenuClearCheck(menuItemSky);
for(int i = 0; i< menuItemSky.MenuItems.Count; i++)
if(menuItemSky.MenuItems[i].Text == skyFileName) menuItemSky.MenuItems[i].Checked = true;
// Открытие битовой карты высот
if(DEM != null) DEM.Dispose();
int width = 0;
int height = 0;
try
{
if(Path.GetExtension(terrainFileName) != ".bil")
{
DEM = new Bitmap(terrainFileName); // .jpg, .png
dem16 = false;
}
else
{
DEM = BitmapFromBil(terrainFileName); // .bil
dem16 = true;
}
width = DEM.Width;
height = DEM.Height;
// обновление максимальных и минимальных коэффициентов построение модели
FindAltitudeExtremes(DEM);
}
catch(Exception e)
{
errMsg += ((errMsg == "") ? "" : ", ") + "Error opening DEM file "
+ terrainFileName + " (" + e.Message + ")";
}
try
{
// Создание модели поверхности
BuildTerrainMesh();
}
catch(Exception e)
{
errMsg += ((errMsg == "") ? "" : ", ") + "Error creating terrain
tiles " + " (" + e.Message + ")";
}
// Создание боковых поверхностей модели
try
{
sidesMesh = TerrainSides(device, DEM);
}
catch(Exception e)
{
errMsg += ((errMsg == "") ? "" : ", ") + "Error building terrain
sides " + " (" + e.Message + ")";
39
}
// Создание поверхности воды
try
{
if(mapMinAlt < 0)
{
int slices = (int)Math.Max(3, (int)(mapSpan / 2.0));
waterMesh = PlaneMesh(device, DEM, slices, 0, waterColor);
}
}
catch(Exception e)
{
errMsg += ((errMsg == "") ? "" : ", ") + "Error building water
mesh " + " (" + e.Message + ")";
}
// Загрузка текстуры модели
try
{
if(textureFileName != "")
{
texture = TextureLoader.FromFile(device, textureFileName);
}
else
{
texture = TextureFromDem(device, DEM);
}
}
catch(Exception e)
{
errMsg += ((errMsg == "") ? "" : ", ") + "Error loading terrain
texture " + textureFileName + " (" + e.Message + ")";
}
// Загрузка боковой текстыры модели
try
{
if(sidesFileName != "")
{
sidesTexture = TextureLoader.FromFile(device, sidesFileName);
}
}
catch(Exception e)
{
errMsg += ((errMsg == "") ? "" : ", ") + "Error loading sides texture " + sidesFileName + " (" + e.Message + ")";
}
// Создание сферы неба и загрузка на нее текстуры
try
{
if(skyFileName != "")
{
skyTexture = TextureLoader.FromFile(device, skyFileName);
}
// Создание модели неба
float radius = (float)(Math.Max(width, height) / 2) + 70;
if(mapWidth != 0)
{
radius = (float)(mapWidth / 2 * Math.Sqrt(2));
radius = (float)Math.Sqrt(radius * radius + mapMaxAlt * mapMaxAlt);
}
skyMesh = TexturedDome(device, radius, 64, 32);
}
catch(Exception e)
40
{
errMsg += ((errMsg == "") ? "" : ", ") + "Error loading sky
skyFileName + " (" + e.Message + ")";
}
// Установка стандартного материала поверхности
material = new Material();
material.Diffuse = Color.FromArgb(0xff, 0xff, 0xff, 0xff);
material.Ambient = Color.White;
material.Specular = Color.White;
material.SpecularSharpness = 30.0f;
// Установка дистанции отрисовки в соответствии с масштабом карты
if(mapWidth > 0)
{
if(dist < mapWidth / 2 || dist > mapWidth * 3)
{
dist = (float)mapWidth * 1.5f;
}
if(Math.Abs(dx) > mapWidth || Math.Abs(dy) > mapWidth) dx =
0;
}
else
{
if(dist < width / 2 || dist > width * 3)
{
dist = (float)(width * 1.5);
}
if(Math.Abs(dx) > width || Math.Abs(dy) > height) dx = dy =
}
// Принудительный вызов обновления
redraw = true;
// Вывод сообщений об ошибках в процессе загрузки
if(errMsg != "")
{
this.Text = mapName + " (Error loading map !) - " + appName
+ appVersion;
}
}
3.5.5
" +
dy =
0;
+ " "
Математические преобразования при обработке файла высот
Формулы для проекции получены с использованием тригонометрии . Они написаны с
точки зрения долготы (λ) и широты (φ) на сфере . Определить радиус в сфере R и центром
точки (и происхождение ) проекции ( ). Уравнений для ортогональной проекции на плоскость (х, у) касательной плоскости сводятся к следующему:
Обратная формула имеет вид:
41
где
Методы для преобразования координат
public Vector2 ProjectToPlane(double lat, double lon, double lat0, double lon0, double
radius)
{
double degToRad = Math.PI / 180.0;
double latRad = lat * degToRad;
double lonRad = lon * degToRad;
double lat0Rad = lat0 * degToRad;
double lon0Rad = lon0 * degToRad;
double cosC = Math.Sin(lat0Rad) * Math.Sin(latRad) +
Math.Cos(lat0Rad) * Math.Cos(latRad) * Math.Cos(lonRad - lon0Rad);
if(cosC < 0) return Vector2.Empty;
Vector2 pnt = new Vector2();
pnt.X = (float)(radius * Math.Cos(latRad) * Math.Sin(lonRad lon0Rad));
pnt.Y = -(float)(radius * (Math.Cos(lat0Rad) * Math.Sin(latRad) Math.Sin(lat0Rad) * Math.Cos(latRad) * Math.Cos(lonRad - lon0Rad)));
return pnt;
}
public Vector2 SampleToLatLon(int x, int y, int samples, double centerLat, double centerLon, double span, double heading)
{
double degToRad = Math.PI / 180.0;
double nwLon = centerLon - span * 1.4142 * Math.Cos((double)(45 heading) * degToRad) / 2;
double nwLat = centerLat + span * 1.4142 * Math.Sin((double)(45 heading) * degToRad) / 2;
double stepSize = span / (samples - 1);
double ssin = stepSize * Math.Sin(heading
double scos = stepSize * Math.Cos(heading
Vector2 pnt = new Vector2();
pnt.Y = (float)(nwLon + ssin * y + scos *
pnt.X = (float)(nwLat - scos * y + ssin *
return pnt;
}
* degToRad);
* degToRad);
x); // Longitude
x); // Latitude
42
Выводы
43
ЗАКЛЮЧЕНИЕ
В результате выполнения данной дипломной работы были разработаны плагин для
получения данных из программы NASA World Wind и программа построения 3-хмерной
модели на основе полученных данных для графического отображения цветовой градацией
возможных областей
Для достижения поставленной цели был решен ряд задач:
 Изучения методов интеграции и взаимодействия с данными программы
NASA World Wind.
 Изучения формата SRTM.
 Разработан плагин интегрирующийся в NASA World Wind для получения
данных.
 Разработана программа визуализирования полученных плагином данных и
последующего их отображения с наложением цветового градиента для пометки областей подтопления.
44
СПИСОК ИСПОЛЬЗОВАННОЙ ЛИТЕРАТУРЫ
1. Снайдер, JP (1987). Картографических проекций-Рабочее руководство (US геологическая съемка профессиональная бумага 1395). Вашингтон, округ Колумбия:
US Government Printing Office. с. 145-153.
2. Снайдер, JP (1993). Сведение о Земле: 2000 лет картографических проекций.
Чикагский университет Press. ISBN 0-226-76747-7 (мягкая обложка) .
3. Сайт Wikipedia http://en.wikipedia.org/wiki/Orthographic_projection_(cartography)
4. Хаксольд В. Введение в городские географические информационные системы. Изд-во Оксфордского университета, 1991. - 321 с
5. Цветков В.Я. Геоинформационные системы и технологии (учебное
пособие). - М.: МИИГАиК, 1996. - 112 с.
6.
45
ПРИЛОЖЕНИЕ 1. «Пользовательский интерфейс приложения»
Затенение – включает режим наложения теней
Эффект затенения выключен
Эффект затенения включен
46
Вода – включает отображение уровня океана
Эффект «Вода» включен
Эффект «Вода» выключен
47
Туман – включает графический эффект тумана
Эффект туман включен
Эффект туман выключен
48
Вертикаль - коэффициента для построения модели по высотной карте
Стандартная вертикаль 0,75
Вертикаль увеличенная в 5 раз
49
Текстуры –список доступных текстур для наложения на модель
Выбран вариант текстурирования модели «Grid_Water_1.png»
Выбран вариант текстурирования модели «Geo_Water_1.png»
50
Края - список текстур накладываемых на края модели
Установлено оформление края модели в виде текстуры «Grid_Water_1.png»
Установлено оформление края модели в виде текстуры «Mars_Water_1.png»
51
Небо - включает отображение изображения неба
Выбран вид оформления неба в виде звезд «Space_1.jpg»
Выбран вид оформления неба в виде тучек «Sky_Day.jpg»
52
ПРИЛОЖЕНИЕ 2. «Встраиваемый в NASA Код плагина»
using
using
using
using
using
using
using
using
using
using
using
using
using
using
using
System;
System.Collections.Generic;
System.ComponentModel;
System.Drawing;
System.Text;
System.Windows.Forms;
System.IO;
System.Xml;
System.Diagnostics;
System.Globalization;
System.Collections;
Microsoft.DirectX;
Microsoft.DirectX.Direct3D;
WorldWind;
WorldWind.Renderable;
namespace TerrainViewer
{
public class TerrainExtractorForm : Form
{
private System.Windows.Forms.Button btnOK;
private System.Windows.Forms.Button btnCancel;
private
private
private
private
private
private
private
private
private
private
private
private
private
private
private
private
private
private
private
private
private
private
private
private
private
private
private
private
private
private
TerrainExtractorPlugin plugin;
Label label1;
Label label2;
Label label3;
NumericUpDown numCenterLat;
NumericUpDown numCenterLon;
Label label4;
TrackBar tbRotation;
NumericUpDown numRotation;
NumericUpDown numSize;
TrackBar tbSize;
Label label5;
Button btnReset;
Button btnRecenter;
Label label6;
Label label7;
TextBox tbFilename;
TextBox tbDescription;
Label label9;
Label label10;
Label label11;
Label label12;
ProgressBar pbarExportProgress;
ComboBox comboDEMSize;
CheckBox cbTexture;
ComboBox comboTextureSize;
ComboBox comboLayer;
Label label8;
GroupBox gbTexture;
Button btnRefreshList;
private System.ComponentModel.IContainer components = null;
protected override void Dispose(bool disposing)
{
53
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code
private void InitializeComponent()
{
this.btnOK = new System.Windows.Forms.Button();
this.btnCancel = new System.Windows.Forms.Button();
this.label1 = new System.Windows.Forms.Label();
this.label2 = new System.Windows.Forms.Label();
this.label3 = new System.Windows.Forms.Label();
this.numCenterLat = new System.Windows.Forms.NumericUpDown();
this.numCenterLon = new System.Windows.Forms.NumericUpDown();
this.label4 = new System.Windows.Forms.Label();
this.tbRotation = new System.Windows.Forms.TrackBar();
this.numRotation = new System.Windows.Forms.NumericUpDown();
this.numSize = new System.Windows.Forms.NumericUpDown();
this.tbSize = new System.Windows.Forms.TrackBar();
this.label5 = new System.Windows.Forms.Label();
this.btnReset = new System.Windows.Forms.Button();
this.btnRecenter = new System.Windows.Forms.Button();
this.label6 = new System.Windows.Forms.Label();
this.label7 = new System.Windows.Forms.Label();
this.tbFilename = new System.Windows.Forms.TextBox();
this.tbDescription = new System.Windows.Forms.TextBox();
this.label9 = new System.Windows.Forms.Label();
this.label10 = new System.Windows.Forms.Label();
this.label11 = new System.Windows.Forms.Label();
this.label12 = new System.Windows.Forms.Label();
this.pbarExportProgress = new System.Windows.Forms.ProgressBar();
this.comboDEMSize = new System.Windows.Forms.ComboBox();
this.cbTexture = new System.Windows.Forms.CheckBox();
this.comboTextureSize = new System.Windows.Forms.ComboBox();
this.comboLayer = new System.Windows.Forms.ComboBox();
this.label8 = new System.Windows.Forms.Label();
this.gbTexture = new System.Windows.Forms.GroupBox();
this.btnRefreshList = new System.Windows.Forms.Button();
((System.ComponentModel.ISupportInitialize)(this.numCenterLat)).BeginInit();
((System.ComponentModel.ISupportInitialize)(this.numCenterLon)).BeginInit();
((System.ComponentModel.ISupportInitialize)(this.tbRotation)).BeginInit();
((System.ComponentModel.ISupportInitialize)(this.numRotation)).BeginInit();
((System.ComponentModel.ISupportInitialize)(this.numSize)).BeginInit();
((System.ComponentModel.ISupportInitialize)(this.tbSize)).BeginInit();
this.gbTexture.SuspendLayout();
this.SuspendLayout();
this.btnOK.Location = new System.Drawing.Point(99, 275);
this.btnOK.Name = "btnOK";
this.btnOK.Size = new System.Drawing.Size(97, 23);
this.btnOK.TabIndex = 3;
this.btnOK.Text = "View selection";
this.btnOK.UseVisualStyleBackColor = true;
this.btnOK.Click += new System.EventHandler(this.btnOK_Click);
54
this.btnCancel.DialogResult = System.Windows.Forms.DialogResult.Cancel;
this.btnCancel.Location = new System.Drawing.Point(202, 275);
this.btnCancel.Name = "btnCancel";
this.btnCancel.Size = new System.Drawing.Size(75, 23);
this.btnCancel.TabIndex = 4;
this.btnCancel.Text = "Cancel";
this.btnCancel.UseVisualStyleBackColor = true;
this.btnCancel.Click += new System.EventHandler(this.btnCancel_Click);
this.label1.AutoSize = true;
this.label1.Font = new System.Drawing.Font("Microsoft Sans Serif",
8.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
this.label1.Location = new System.Drawing.Point(16, 9);
this.label1.Name = "label1";
this.label1.Size = new System.Drawing.Size(48, 13);
this.label1.TabIndex = 5;
this.label1.Text = "Center:";
this.label2.AutoSize = true;
this.label2.Location = new System.Drawing.Point(16, 30);
this.label2.Name = "label2";
this.label2.Size = new System.Drawing.Size(25, 13);
this.label2.TabIndex = 6;
this.label2.Text = "Lat:";
this.label3.AutoSize = true;
this.label3.Location = new System.Drawing.Point(13, 56);
this.label3.Name = "label3";
this.label3.Size = new System.Drawing.Size(28, 13);
this.label3.TabIndex = 7;
this.label3.Text = "Lon:";
this.numCenterLat.DecimalPlaces = 5;
this.numCenterLat.Increment = new decimal(new int[] {
1,
0,
0,
65536});
this.numCenterLat.Location = new System.Drawing.Point(46, 28);
this.numCenterLat.Maximum = new decimal(new int[] {
90,
0,
0,
0});
this.numCenterLat.Minimum = new decimal(new int[] {
90,
0,
0,
-2147483648});
this.numCenterLat.Name = "numCenterLat";
this.numCenterLat.Size = new System.Drawing.Size(82, 20);
this.numCenterLat.TabIndex = 8;
this.numCenterLat.ValueChanged += new System.EventHandler(this.numCenterLat_ValueChanged);
this.numCenterLon.DecimalPlaces = 5;
this.numCenterLon.Increment = new decimal(new int[] {
1,
0,
0,
65536});
this.numCenterLon.Location = new System.Drawing.Point(46, 54);
55
this.numCenterLon.Maximum = new decimal(new int[] {
180,
0,
0,
0});
this.numCenterLon.Minimum = new decimal(new int[] {
180,
0,
0,
-2147483648});
this.numCenterLon.Name = "numCenterLon";
this.numCenterLon.Size = new System.Drawing.Size(82, 20);
this.numCenterLon.TabIndex = 9;
this.numCenterLon.ValueChanged += new System.EventHandler(this.numCenterLon_ValueChanged);
this.label4.AutoSize = true;
this.label4.Font = new System.Drawing.Font("Microsoft Sans Serif",
8.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
this.label4.Location = new System.Drawing.Point(146, 73);
this.label4.Name = "label4";
this.label4.Size = new System.Drawing.Size(92, 13);
this.label4.TabIndex = 10;
this.label4.Text = "Rotation (deg):";
this.tbRotation.Location = new System.Drawing.Point(149, 89);
this.tbRotation.Maximum = 45;
this.tbRotation.Minimum = -45;
this.tbRotation.Name = "tbRotation";
this.tbRotation.Size = new System.Drawing.Size(160, 37);
this.tbRotation.SmallChange = 5;
this.tbRotation.TabIndex = 11;
this.tbRotation.TickFrequency = 15;
this.tbRotation.ValueChanged += new System.EventHandler(this.tbRotation_ValueChanged);
this.numRotation.Increment = new decimal(new int[] {
5,
0,
0,
0});
this.numRotation.Location = new System.Drawing.Point(315, 94);
this.numRotation.Maximum = new decimal(new int[] {
45,
0,
0,
0});
this.numRotation.Minimum = new decimal(new int[] {
45,
0,
0,
-2147483648});
this.numRotation.Name = "numRotation";
this.numRotation.Size = new System.Drawing.Size(69, 20);
this.numRotation.TabIndex = 12;
this.numRotation.ValueChanged += new System.EventHandler(this.numRotation_ValueChanged);
this.numSize.DecimalPlaces = 4;
this.numSize.Increment = new decimal(new int[] {
1,
0,
0,
65536});
this.numSize.Location = new System.Drawing.Point(315, 30);
56
this.numSize.Maximum = new decimal(new int[] {
60,
0,
0,
0});
this.numSize.Minimum = new decimal(new int[] {
1,
0,
0,
131072});
this.numSize.Name = "numSize";
this.numSize.Size = new System.Drawing.Size(69, 20);
this.numSize.TabIndex = 15;
this.numSize.Value = new decimal(new int[] {
10,
0,
0,
0});
this.numSize.ValueChanged += new System.EventHandler(this.numSize_ValueChanged);
this.tbSize.LargeChange = 500;
this.tbSize.Location = new System.Drawing.Point(149, 25);
this.tbSize.Maximum = 1778;
this.tbSize.Minimum = -2000;
this.tbSize.Name = "tbSize";
this.tbSize.Size = new System.Drawing.Size(160, 37);
this.tbSize.SmallChange = 100;
this.tbSize.TabIndex = 14;
this.tbSize.TickFrequency = 500;
this.tbSize.Value = 1000;
this.tbSize.ValueChanged += new System.EventHandler(this.tbSize_ValueChanged);
this.label5.AutoSize = true;
this.label5.Font = new System.Drawing.Font("Microsoft Sans Serif",
8.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
this.label5.Location = new System.Drawing.Point(146, 9);
this.label5.Name = "label5";
this.label5.Size = new System.Drawing.Size(68, 13);
this.label5.TabIndex = 13;
this.label5.Text = "Size (deg):";
this.btnReset.Location = new System.Drawing.Point(198, 142);
this.btnReset.Name = "btnReset";
this.btnReset.Size = new System.Drawing.Size(94, 39);
this.btnReset.TabIndex = 16;
this.btnReset.Text = "Reset area to camera view";
this.btnReset.UseVisualStyleBackColor = true;
this.btnReset.Click += new System.EventHandler(this.btnReset_Click);
this.btnRecenter.Location = new System.Drawing.Point(298, 142);
this.btnRecenter.Name = "btnRecenter";
this.btnRecenter.Size = new System.Drawing.Size(94, 39);
this.btnRecenter.TabIndex = 17;
this.btnRecenter.Text = "Recenter area to camera";
this.btnRecenter.UseVisualStyleBackColor = true;
this.btnRecenter.Click += new System.EventHandler(this.btnRecenter_Click);
this.label6.AutoSize = true;
this.label6.Font = new System.Drawing.Font("Microsoft Sans Serif",
8.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
this.label6.Location = new System.Drawing.Point(4, 86);
this.label6.Name = "label6";
57
this.label6.Size = new System.Drawing.Size(64, 13);
this.label6.TabIndex = 20;
this.label6.Text = "DEM size:";
this.label7.AutoSize = true;
this.label7.Location = new System.Drawing.Point(6, 45);
this.label7.Name = "label7";
this.label7.Size = new System.Drawing.Size(30, 13);
this.label7.TabIndex = 21;
this.label7.Text = "Size:";
this.tbFilename.Location = new System.Drawing.Point(75, 202);
this.tbFilename.Name = "tbFilename";
this.tbFilename.Size = new System.Drawing.Size(180, 20);
this.tbFilename.TabIndex = 25;
this.tbFilename.Text = "WW_Terrain";
this.tbDescription.Location = new System.Drawing.Point(75, 229);
this.tbDescription.Name = "tbDescription";
this.tbDescription.Size = new System.Drawing.Size(309, 20);
this.tbDescription.TabIndex = 26;
this.tbDescription.Text = "World Wind Terrain";
this.label9.AutoSize = true;
this.label9.Location = new System.Drawing.Point(18, 205);
this.label9.Name = "label9";
this.label9.Size = new System.Drawing.Size(52, 13);
this.label9.TabIndex = 27;
this.label9.Text = "Filename:";
this.label10.AutoSize = true;
this.label10.Location = new System.Drawing.Point(7, 232);
this.label10.Name = "label10";
this.label10.Size = new System.Drawing.Size(63, 13);
this.label10.TabIndex = 28;
this.label10.Text = "Description:";
this.label11.AutoSize = true;
this.label11.Location = new System.Drawing.Point(261, 205);
this.label11.Name = "label11";
this.label11.Size = new System.Drawing.Size(123, 13);
this.label11.TabIndex = 29;
this.label11.Text = "(extension will be added)";
this.label12.AutoSize = true;
this.label12.Font = new System.Drawing.Font("Microsoft Sans Serif",
8.25F, System.Drawing.FontStyle.Underline, System.Drawing.GraphicsUnit.Point,
((byte)(0)));
this.label12.Location = new System.Drawing.Point(108, 253);
this.label12.Name = "label12";
this.label12.Size = new System.Drawing.Size(160, 13);
this.label12.TabIndex = 30;
this.label12.Text = "Warning: overwrites existing files";
this.pbarExportProgress.Location = new System.Drawing.Point(2, 303);
this.pbarExportProgress.Name = "pbarExportProgress";
this.pbarExportProgress.Size = new System.Drawing.Size(392, 10);
this.pbarExportProgress.Step = 1;
this.pbarExportProgress.Style = System.Windows.Forms.ProgressBarStyle.Continuous;
this.pbarExportProgress.TabIndex = 31;
this.comboDEMSize.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
this.comboDEMSize.FormattingEnabled = true;
58
this.comboDEMSize.Items.AddRange(new object[] {
"150x150",
"257x257",
"513x513"});
this.comboDEMSize.Location = new System.Drawing.Point(65, 83);
this.comboDEMSize.Name = "comboDEMSize";
this.comboDEMSize.Size = new System.Drawing.Size(63, 21);
this.comboDEMSize.TabIndex = 32;
this.comboDEMSize.SelectedIndexChanged += new System.EventHandler(this.comboDEMSize_SelectedIndexChanged);
this.cbTexture.AutoSize = true;
this.cbTexture.Font = new System.Drawing.Font("Microsoft Sans Serif",
8.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
this.cbTexture.Location = new System.Drawing.Point(7, 112);
this.cbTexture.Name = "cbTexture";
this.cbTexture.Size = new System.Drawing.Size(69, 17);
this.cbTexture.TabIndex = 33;
this.cbTexture.Text = "Texture";
this.cbTexture.UseVisualStyleBackColor = true;
this.cbTexture.CheckedChanged += new System.EventHandler(this.cbTexture_CheckedChanged);
this.comboTextureSize.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
this.comboTextureSize.FormattingEnabled = true;
this.comboTextureSize.Items.AddRange(new object[] {
"512x512",
"1024x1024",
"2048x2048"});
this.comboTextureSize.Location = new System.Drawing.Point(35, 42);
this.comboTextureSize.Name = "comboTextureSize";
this.comboTextureSize.Size = new System.Drawing.Size(70, 21);
this.comboTextureSize.TabIndex = 34;
this.comboTextureSize.SelectedIndexChanged += new System.EventHandler(this.comboTextureSize_SelectedIndexChanged);
this.comboLayer.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
this.comboLayer.FormattingEnabled = true;
this.comboLayer.Location = new System.Drawing.Point(35, 12);
this.comboLayer.MaxDropDownItems = 100;
this.comboLayer.Name = "comboLayer";
this.comboLayer.Size = new System.Drawing.Size(147, 21);
this.comboLayer.TabIndex = 36;
this.comboLayer.SelectedIndexChanged += new System.EventHandler(this.comboLayer_SelectedIndexChanged);
this.label8.AutoSize = true;
this.label8.Location = new System.Drawing.Point(2, 16);
this.label8.Name = "label8";
this.label8.Size = new System.Drawing.Size(36, 13);
this.label8.TabIndex = 35;
this.label8.Text = "Layer:";
this.gbTexture.Controls.Add(this.btnRefreshList);
this.gbTexture.Controls.Add(this.comboLayer);
this.gbTexture.Controls.Add(this.label8);
this.gbTexture.Controls.Add(this.comboTextureSize);
this.gbTexture.Controls.Add(this.label7);
this.gbTexture.Enabled = false;
this.gbTexture.Location = new System.Drawing.Point(2, 126);
this.gbTexture.Name = "gbTexture";
this.gbTexture.Size = new System.Drawing.Size(188, 70);
this.gbTexture.TabIndex = 37;
59
this.gbTexture.TabStop = false;
this.btnRefreshList.Location = new System.Drawing.Point(111, 42);
this.btnRefreshList.Name = "btnRefreshList";
this.btnRefreshList.Size = new System.Drawing.Size(71, 23);
this.btnRefreshList.TabIndex = 37;
this.btnRefreshList.Text = "Refresh list";
this.btnRefreshList.UseVisualStyleBackColor = true;
this.btnRefreshList.Click += new System.EventHandler(this.btnRefreshList_Click);
this.AcceptButton = this.btnOK;
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.CancelButton = this.btnCancel;
this.ClientSize = new System.Drawing.Size(396, 315);
this.Controls.Add(this.gbTexture);
this.Controls.Add(this.cbTexture);
this.Controls.Add(this.comboDEMSize);
this.Controls.Add(this.pbarExportProgress);
this.Controls.Add(this.label12);
this.Controls.Add(this.label11);
this.Controls.Add(this.label10);
this.Controls.Add(this.label9);
this.Controls.Add(this.tbDescription);
this.Controls.Add(this.tbFilename);
this.Controls.Add(this.label6);
this.Controls.Add(this.btnRecenter);
this.Controls.Add(this.btnReset);
this.Controls.Add(this.numSize);
this.Controls.Add(this.tbSize);
this.Controls.Add(this.label5);
this.Controls.Add(this.numRotation);
this.Controls.Add(this.tbRotation);
this.Controls.Add(this.label4);
this.Controls.Add(this.numCenterLon);
this.Controls.Add(this.numCenterLat);
this.Controls.Add(this.label3);
this.Controls.Add(this.label2);
this.Controls.Add(this.label1);
this.Controls.Add(this.btnCancel);
this.Controls.Add(this.btnOK);
this.MaximizeBox = false;
this.Name = "TerrainExtractorForm";
this.SizeGripStyle = System.Windows.Forms.SizeGripStyle.Hide;
this.Text = "Select Area To Cut Out...";
((System.ComponentModel.ISupportInitialize)(this.numCenterLat)).EndInit();
((System.ComponentModel.ISupportInitialize)(this.numCenterLon)).EndInit();
((System.ComponentModel.ISupportInitialize)(this.tbRotation)).EndInit();
((System.ComponentModel.ISupportInitialize)(this.numRotation)).EndInit();
((System.ComponentModel.ISupportInitialize)(this.numSize)).EndInit();
((System.ComponentModel.ISupportInitialize)(this.tbSize)).EndInit();
this.gbTexture.ResumeLayout(false);
this.gbTexture.PerformLayout();
this.ResumeLayout(false);
this.PerformLayout();
}
#endregion
60
public TerrainExtractorForm(TerrainExtractorPlugin plugin)
{
InitializeComponent();
this.plugin = plugin;
this.ResetBox();
this.comboDEMSize.SelectedItem = this.comboDEMSize.Items[0];
this.comboTextureSize.SelectedItem = this.comboTextureSize.Items[0];
this.RefreshLayers(plugin.ParentApplication.WorldWindow.CurrentWorld.RenderableObj
ects);
this.comboLayer.SelectedItem = (this.comboLayer.Items.Count > 1) ?
this.comboLayer.Items[1] : this.comboLayer.Items[0];
plugin.ImageLayerName = (string)this.comboLayer.SelectedItem;
}
public int ProgBarValue
{
set { this.pbarExportProgress.Value = value; }
}
private void UpdateBox()
{
plugin.UpdateBox(numCenterLat.Value, numCenterLon.Value, numSize.Value, numRotation.Value);
}
private void ResetBox()
{
decimal centerLat;
decimal centerLon;
decimal size;
plugin.ResetArea(out centerLat, out centerLon, out size);
numCenterLat.Value = centerLat;
numCenterLon.Value = centerLon;
numSize.Value = size;
numRotation.Value = 0;
this.UpdateBox();
}
private void numCenterLat_ValueChanged(object sender, EventArgs e)
{
this.UpdateBox();
}
private void numCenterLon_ValueChanged(object sender, EventArgs e)
{
this.UpdateBox();
}
private void tbSize_ValueChanged(object sender, EventArgs e)
{
numSize.Value = (decimal)(Math.Pow(10, ((double)tbSize.Value /
1000)));
this.UpdateBox();
}
private void tbRotation_ValueChanged(object sender, EventArgs e)
{
numRotation.Value = -1 * (decimal)tbRotation.Value;
this.UpdateBox();
61
}
private void numSize_ValueChanged(object sender, EventArgs e)
{
tbSize.Value = (int)(Math.Log10((double)numSize.Value) * 1000);
this.UpdateBox();
}
private void numRotation_ValueChanged(object sender, EventArgs e)
{
tbRotation.Value = -1 * (int)numRotation.Value;
this.UpdateBox();
}
private void btnReset_Click(object sender, EventArgs e)
{
this.ResetBox();
}
private void btnOK_Click(object sender, EventArgs e)
{
if (comboTextureSize.SelectedIndex != 0)
{
if (MessageBox.Show("The selected texture size may take several minutes to export. Continue?", "Export Size Warning", MessageBoxButtons.YesNo, MessageBoxIcon.Warning) == DialogResult.Yes)
{
plugin.WriteData(tbFilename.Text, tbDescription.Text);
}
}
else
plugin.WriteData(tbFilename.Text, tbDescription.Text);
}
private void updownDemSize_SelectedItemChanged(object sender, EventArgs e)
{
}
private void btnRecenter_Click(object sender, EventArgs e)
{
decimal centerLat;
decimal centerLon;
plugin.Recenter(out centerLat, out centerLon);
numCenterLat.Value = centerLat;
numCenterLon.Value = centerLon;
this.UpdateBox();
}
private void btnCancel_Click(object sender, EventArgs e)
{
this.Close();
}
protected override void OnClosing(CancelEventArgs e)
{
plugin.FormClosed();
base.OnClosing(e);
}
private void comboDEMSize_SelectedIndexChanged(object sender, EventArgs e)
62
{
switch ((string)comboDEMSize.SelectedItem)
{
case "150x150":
plugin.NumTerrainSamples = 150;
break;
case "257x257":
plugin.NumTerrainSamples = 257;
break;
case "513x513":
plugin.NumTerrainSamples = 513;
break;
}
}
private void cbTexture_CheckedChanged(object sender, EventArgs e)
{
this.gbTexture.Enabled = cbTexture.Checked;
plugin.ExportTexture = cbTexture.Checked;
}
private void comboTextureSize_SelectedIndexChanged(object sender, EventArgs
e)
{
switch ((string)comboTextureSize.SelectedItem)
{
case "512x512":
plugin.NumImageSamples = 512;
break;
case "1024x1024":
plugin.NumImageSamples = 1024;
break;
case "2048x2048":
plugin.NumImageSamples = 2048;
break;
}
}
private void RefreshLayers(RenderableObjectList theList)
{
foreach (RenderableObject ro in theList.ChildObjects)
{
if (ro.IsOn)
{
if (ro is QuadTileSet)
{
QuadTileSet curLayer = (QuadTileSet)ro;
this.comboLayer.Items.Add(ro.Name);
break;
}
if (ro is RenderableObjectList)
{
RefreshLayers((RenderableObjectList)ro);
}
}
}
}
63
private void btnRefreshList_Click(object sender, EventArgs e)
{
this.comboLayer.Items.Clear();
this.RefreshLayers(plugin.ParentApplication.WorldWindow.CurrentWorld.RenderableObj
ects);
this.comboLayer.SelectedItem = (this.comboLayer.Items.Count > 1) ?
this.comboLayer.Items[1] : this.comboLayer.Items[0];
plugin.ImageLayerName = (string)this.comboLayer.SelectedItem;
}
private void comboLayer_SelectedIndexChanged(object sender, EventArgs e)
{
plugin.ImageLayerName = (string)comboLayer.SelectedItem;
}
}
public class TerrainExtractorPlugin : WorldWind.PluginEngine.Plugin
{
public
public
public
public
public
static string LayerName = "Select area";
int NumTerrainSamples = 150;
int NumImageSamples = 512;
string ImageLayerName = "I-Cubed ESAT World Landsat7 Mosaic";
bool ExportTexture = false;
private
private
private
private
private
private
private
LineFeature outline;
MenuItem menuItem;
TerrainExtractorForm teForm;
WorldWindow worldWindow;
WorldWind.Camera.CameraBase camera;
DrawArgs drawArgs;
double centerLat, centerLon, size, rotation;
private
private
private
private
private
string
string
string
string
string
exeFileName = "TerrainViewer.exe";
bilPath;
imgPath;
xmlPath;
exePath;
private Hashtable imageCache = new Hashtable();
private bool debug = false;
public override void Load()
{
worldWindow = ParentApplication.WorldWindow;
camera = worldWindow.DrawArgs.WorldCamera;
drawArgs = worldWindow.DrawArgs;
menuItem = new MenuItem("3D Cross Section...");
menuItem.Click += new EventHandler(menuItemClicked);
ParentApplication.PluginsMenu.MenuItems.Add(menuItem);
exePath = Path.Combine(PluginDirectory, exeFileName);
}
public override void Unload()
{
ParentApplication.PluginsMenu.MenuItems.Remove(menuItem);
if (outline != null)
64
ParentApplication.WorldWindow.CurrentWorld.RenderableObjects.Remove(outline);
}
void menuItemClicked(object sender, EventArgs e)
{
teForm = new TerrainExtractorForm(this);
teForm.Show();
}
public void UpdateBox(decimal cenLat, decimal cenLon, decimal s, decimal r)
{
centerLat = (double)cenLat;
centerLon = (double)cenLon;
size = (double)s;
rotation = (double)r;
double x = size * 1.4142 * Math.Cos((double)(45 - rotation) * 3.14159
/ 180.0) / 2;
double y = size * 1.4142 * Math.Sin((double)(45 - rotation) * 3.14159
/ 180.0) / 2;
Point3d
Point3d
Point3d
Point3d
nw
sw
se
ne
=
=
=
=
new
new
new
new
Point3d(centerLon
Point3d(centerLon
Point3d(centerLon
Point3d(centerLon
+
+
x,
y,
x,
y,
centerLat
centerLat
centerLat
centerLat
+
+
y,
x,
y,
x,
0);
0);
0);
0);
Point3d[] points = new Point3d[5];
points[0]
points[1]
points[2]
points[3]
points[4]
=
=
=
=
=
nw;
sw;
se;
ne;
nw;
if (outline == null)
{
outline = new LineFeature("3D Cross Section selection", worldWindow.CurrentWorld, points, Color.Red);
outline.AltitudeMode = AltitudeMode.RelativeToGround;
worldWindow.CurrentWorld.RenderableObjects.Add(outline);
}
else
{
outline.Points = points;
outline.IsOn = true;
}
}
public void WriteData(string filename,
{
string bilFileName = @"maps\" +
string imgFileName = @"maps\" +
string xmlFileName = filename +
string description)
filename + "_SRTM.bil";
filename + "_Texture.jpg";
".xml";
bilPath = Path.Combine(PluginDirectory, bilFileName);
imgPath = Path.Combine(PluginDirectory, imgFileName);
xmlPath = Path.Combine(PluginDirectory, xmlFileName);
try
{
65
FileStream fs = new FileStream(bilPath, FileMode.Create);
BinaryWriter bw = new BinaryWriter(fs);
double endLon =
Math.Cos((double)(45 - rotation) * 3.14159
double endLat =
Math.Sin((double)(45 - rotation) * 3.14159
double
double
double
double
centerLon - size * 1.4142 *
/ 180.0) / 2;
centerLat + size * 1.4142 *
/ 180.0) / 2;
stepSize = size / (NumTerrainSamples - 1);
sampsPerDegree = NumTerrainSamples / size;
ssin = stepSize * Math.Sin(rotation * 3.14159 / 180.0);
scos = stepSize * Math.Cos(rotation * 3.14159 / 180.0);
int totalSamps = NumTerrainSamples * NumTerrainSamples;
if (ExportTexture)
totalSamps += NumImageSamples * NumImageSamples;
int count = 0;
double progress = 0;
teForm.ProgBarValue = 0;
for (int y = 0; y < NumTerrainSamples; y++)
{
for (int x = 0; x < NumTerrainSamples; x++)
{
double lat = endLat + ssin * x;
double lon = endLon + scos * x;
if (lon < -180)
lon += 360;
if (lon > 180)
lon -= 360;
short elev =
(short)worldWindow.CurrentWorld.TerrainAccessor.GetElevationAt(lat, lon, sampsPerDegree);
bw.Write(elev);
count++;
progress = count / totalSamps * 95;
teForm.ProgBarValue = (int)progress;
}
endLat -= scos;
endLon += ssin;
}
bw.Close();
fs.Close();
if (ExportTexture)
{
QuadTileSet layer = (QuadTileSet)FindLayer(ParentApplication.WorldWindow.CurrentWorld.RenderableObjects,
ImageLayerName);
int level = 0;
Color layerPixel = GetColorAt(layer, centerLat, centerLon, level);
double tileSizePixel = 512;
if (imageCache.Count > 0)
{
foreach (Bitmap img in imageCache.Values) tileSizePixel = img.Width;
}
sampsPerDegree = NumImageSamples / size;
double layerSPD = tileSizePixel / layer.ImageStores[0].LevelZeroTileSizeDegrees;
66
while (level < layer.ImageStores[0].LevelCount - 1 &&
layerSPD < sampsPerDegree)
{
layerSPD *= 2;
level += 1;
}
if (level > layer.ImageStores[0].LevelCount) level =
layer.ImageStores[0].LevelCount;
endLon =
Math.Cos((double)(45 - rotation) * 3.14159
endLat =
Math.Sin((double)(45 - rotation) * 3.14159
centerLon - size * 1.4142 *
/ 180.0) / 2;
centerLat + size * 1.4142 *
/ 180.0) / 2;
stepSize = size / (NumImageSamples - 1);
ssin = stepSize * Math.Sin(rotation * 3.14159 / 180.0);
scos = stepSize * Math.Cos(rotation * 3.14159 / 180.0);
Bitmap image = new Bitmap(NumImageSamples, NumImageSamples, System.Drawing.Imaging.PixelFormat.Format32bppArgb);
debug = true;
for (int y = 0; y < NumImageSamples; y++)
{
for (int x = 0; x < NumImageSamples; x++)
{
double lat = endLat + ssin * x;
double lon = endLon + scos * x;
if (lon < -180)
lon += 360;
if (lon > 180)
lon -= 360;
Color color = GetColorAt(layer, lat, lon,
level);
debug = false;
image.SetPixel(x, y, color);
count++;
progress = count / totalSamps * 95;
teForm.ProgBarValue = (int)progress;
}
endLat -= scos;
endLon += ssin;
}
image.Save(imgPath, System.Drawing.Imaging.ImageFormat.Jpeg);
image.Dispose();
DisposeImageCache();
}
XmlDocument doc = new XmlDocument();
doc.CreateXmlDeclaration("1.0", "ISO-8859-1", null);
XmlElement root = doc.CreateElement("maps");
doc.AppendChild(root);
XmlElement map = doc.CreateElement("map");
map.SetAttribute("name", description);
root.AppendChild(map);
67
XmlElement terrain = doc.CreateElement("terrain");
terrain.SetAttribute("demfile", bilFileName);
if (ExportTexture)
terrain.SetAttribute("texturefile", imgFileName);
else
terrain.SetAttribute("texturefile",
@"colors\Geo_Water_1.png");
terrain.SetAttribute("altscale", "1.0");
terrain.SetAttribute("centerlatitude", centerLat.ToString(CultureInfo.InvariantCulture));
terrain.SetAttribute("centerlongitude", centerLon.ToString(CultureInfo.InvariantCulture));
terrain.SetAttribute("span",
size.ToString(CultureInfo.InvariantCulture));
terrain.SetAttribute("heading", rotation.ToString(CultureInfo.InvariantCulture));
terrain.SetAttribute("worldradius", worldWindow.CurrentWorld.EquatorialRadius.ToString(CultureInfo.InvariantCulture));
map.AppendChild(terrain);
doc.Save(xmlPath);
ProcessStartInfo ps = new ProcessStartInfo(exePath, xmlFileName);
ps.WorkingDirectory = PluginDirectory;
Process.Start(ps);
progress = 100;
teForm.ProgBarValue = (int)progress;
}
catch (Exception ex)
{
MessageBox.Show(ex.Message, "Export error");
}
}
public Color GetColorAt(QuadTileSet layer, double lat, double lon, int level)
{
Color color = Color.White;
double tileSizeDegree = layer.ImageStores[0].LevelZeroTileSizeDegrees;
if (level > 0) for (int i = 0; i < level; i++) tileSizeDegree /= 2;
int row = (int)Math.Floor((lat + 90) / tileSizeDegree);
int col = (int)Math.Floor((lon + 180) / tileSizeDegree);
double south = -90.0f + row * tileSizeDegree;
double north = south + tileSizeDegree;
double west = -180.0f + col * tileSizeDegree;
double east = west + tileSizeDegree;
string key = level.ToString() + row.ToString() + col.ToString();
Bitmap img = (Bitmap)imageCache[key];
if (img == null)
{
QuadTile qt = new QuadTile(south, north, west, east, level,
layer);
string tilePath = layer.ImageStores[0].GetLocalPath(qt);
if (File.Exists(tilePath))
{
Texture texture = layer.ImageStores[0].LoadFile(qt);
GraphicsStream gs = TextureLoader.SaveToStream(ImageFileFormat.Bmp, texture);
img = new Bitmap(gs);
imageCache.Add(key, img);
68
texture.Dispose();
}
qt.Dispose();
}
if (img != null)
{
double x = (lon - west) / tileSizeDegree * img.Width;
double y = (north - lat) / tileSizeDegree * img.Height;
if (x >= img.Width) x = img.Width - 1;
if (y >= img.Height) y = img.Height - 1;
if (x < 0) x = 0;
if (y < 0) y = 0;
int xNW = (int)Math.Floor(x);
int yNW = (int)Math.Floor(y);
float xFactor = (float)(x - xNW);
float yFactor = (float)(y - yNW);
Color NW = img.GetPixel(xNW, yNW);
Color NE = (xNW + 1) < img.Width ? img.GetPixel(xNW + 1, yNW)
: NW;
Color SW = (yNW + 1) < img.Height ? img.GetPixel(xNW, yNW + 1)
: NW;
Color SE = (xNW + 1) < img.Width && (yNW + 1) < img.Height ?
img.GetPixel(xNW + 1, yNW + 1) : NW;
Color N = Color.FromArgb(
(byte)((float)NW.R * (1f - xFactor) + (float)NE.R *
xFactor),
(byte)((float)NW.G * (1f - xFactor) + (float)NE.G *
xFactor),
(byte)((float)NW.B * (1f - xFactor) + (float)NE.B *
xFactor));
Color S = Color.FromArgb(
(byte)((float)SW.R * (1f - xFactor) + (float)SE.R *
xFactor),
(byte)((float)SW.G * (1f - xFactor) + (float)SE.G *
xFactor),
(byte)((float)SW.B * (1f - xFactor) + (float)SE.B *
xFactor));
color = Color.FromArgb(
(byte)((float)N.R * (1f - yFactor) + (float)S.R * yFactor),
(byte)((float)N.G * (1f - yFactor) + (float)S.G * yFactor),
(byte)((float)N.B * (1f - yFactor) + (float)S.B * yFactor));
}
return color;
}
public void DisposeImageCache()
{
if (imageCache.Count > 0)
{
foreach (Bitmap img in imageCache.Values) img.Dispose();
imageCache.Clear();
}
}
public RenderableObject FindLayer(RenderableObject ro, string name)
{
string s = "";
if(!ro.IsOn) return null;
if (ro is WorldWind.Renderable.RenderableObjectList)
{
RenderableObjectList rol = (RenderableObjectList)ro;
69
for (int i = 0; i < rol.ChildObjects.Count; i++)
{
RenderableObject l = (RenderableObject)rol.ChildObjects[i];
if (l is RenderableObjectList)
{
RenderableObject found = FindLayer(l, name);
if (found != null) return found;
}
else
{
s += l.Name + ", ";
if (l.Name.IndexOf(name) != -1 && l.IsOn) return
l;
}
}
}
else
{
if (ro.Name.IndexOf(name) != -1 && ro.IsOn) return ro;
}
return null;
}
public void ResetArea(out decimal cenLat, out decimal cenLon, out decimal
s)
{
centerLat = camera.Latitude.Degrees;
cenLat = (decimal)centerLat;
centerLon = camera.Longitude.Degrees;
cenLon = (decimal)centerLon;
size = 1.8 * 180.0 / 3.14159 * Math.Atan(camera.Altitude / worldWindow.CurrentWorld.EquatorialRadius * 0.4142);
if (size > 60)
size = 60;
if (size < 0.01)
size = 0.01;
s = (decimal)size;
}
public void Recenter(out decimal cenLat, out decimal cenLon)
{
centerLat = camera.Latitude.Degrees;
cenLat = (decimal)centerLat;
centerLon = camera.Longitude.Degrees;
cenLon = (decimal)centerLon;
}
public void ClearSelectionBox()
{
outline.Dispose();
outline = null;
}
public void FormClosed()
{
if(outline != null) {
outline.Points = new Point3d[0];
outline.IsOn = false;
}
}
}
}
70
ПРИЛОЖЕНИЕ 3. «Метод экспорта данных плагином»
public void WriteData(string filename,
{
string bilFileName = @"maps\" +
string imgFileName = @"maps\" +
string xmlFileName = filename +
string description)
filename + "_SRTM.bil";
filename + "_Texture.jpg";
".xml";
bilPath = Path.Combine(PluginDirectory, bilFileName);
imgPath = Path.Combine(PluginDirectory, imgFileName);
xmlPath = Path.Combine(PluginDirectory, xmlFileName);
try
{
// *** Преобразование данных в .bil файл
FileStream fs = new FileStream(bilPath, FileMode.Create);
BinaryWriter bw = new BinaryWriter(fs);
// широта и долгота в первой строке
double endLon = centerLon - size * 1.4142 * Math.Cos((double)(45 - rotation) * 3.14159 / 180.0) / 2;
double endLat = centerLat + size * 1.4142 * Math.Sin((double)(45 - rotation) * 3.14159 / 180.0) / 2;
// пример отступов в направлении строк
double stepSize = size / (NumTerrainSamples - 1);
double sampsPerDegree = NumTerrainSamples / size;
double ssin = stepSize * Math.Sin(rotation * 3.14159 / 180.0);
double scos = stepSize * Math.Cos(rotation * 3.14159 / 180.0);
int totalSamps = NumTerrainSamples * NumTerrainSamples;
if (ExportTexture)
totalSamps += NumImageSamples * NumImageSamples;
int count = 0;
double progress = 0;
teForm.ProgBarValue = 0;
for (int y = 0; y < NumTerrainSamples; y++)
{
for (int x = 0; x < NumTerrainSamples; x++)
{
// текущая широта и долгота
double lat = endLat + ssin * x;
double lon = endLon + scos * x;
if (lon < -180)
lon += 360;
if (lon > 180)
lon -= 360;
short elev =
(short)worldWindow.CurrentWorld.TerrainAccessor.GetElevationAt(lat, lon, sampsPerDegree);
bw.Write(elev);
count++;
progress = count / totalSamps * 95;
teForm.ProgBarValue = (int)progress;
}
// широта и долгота следующей строки
endLat -= scos;
endLon += ssin;
}
71
bw.Close();
fs.Close();
// Преобразование изображения
if (ExportTexture)
{
// поиск требуемого слоя изображения
QuadTileSet layer = (QuadTileSet)FindLayer(ParentApplication.WorldWindow.CurrentWorld.RenderableObjects,
ImageLayerName);
int level = 0;
Color layerPixel = GetColorAt(layer, centerLat, centerLon, level);
double tileSizePixel = 512;
if (imageCache.Count > 0)
{
foreach (Bitmap img in imageCache.Values) tileSizePixel =
img.Width;
}
sampsPerDegree = NumImageSamples / size;
double layerSPD = tileSizePixel / layer.ImageStores[0].LevelZeroTileSizeDegrees;
while (level < layer.ImageStores[0].LevelCount - 1 && layerSPD <
sampsPerDegree)
{
layerSPD *= 2;
level += 1;
}
if (level > layer.ImageStores[0].LevelCount) level = layer.ImageStores[0].LevelCount;
endLon = centerLon - size * 1.4142 * Math.Cos((double)(45 - rotation)
* 3.14159 / 180.0) / 2;
endLat = centerLat + size * 1.4142 * Math.Sin((double)(45 - rotation)
* 3.14159 / 180.0) / 2;
stepSize = size / (NumImageSamples - 1);
ssin = stepSize * Math.Sin(rotation * 3.14159 / 180.0);
scos = stepSize * Math.Cos(rotation * 3.14159 / 180.0);
Bitmap image = new Bitmap(NumImageSamples, NumImageSamples, System.Drawing.Imaging.PixelFormat.Format32bppArgb);
debug = true;
for (int y = 0; y < NumImageSamples; y++)
{
for (int x = 0; x < NumImageSamples; x++)
{
double lat = endLat + ssin * x;
double lon = endLon + scos * x;
if (lon < -180)
lon += 360;
if (lon > 180)
lon -= 360;
Color color = GetColorAt(layer, lat, lon, level);
debug = false;
image.SetPixel(x, y, color);
count++;
progress = count / totalSamps * 95;
teForm.ProgBarValue = (int)progress;
}
endLat -= scos;
72
endLon += ssin;
}
image.Save(imgPath, System.Drawing.Imaging.ImageFormat.Jpeg);
image.Dispose();
DisposeImageCache();
}
XmlDocument doc = new XmlDocument();
doc.CreateXmlDeclaration("1.0", "ISO-8859-1", null);
XmlElement root = doc.CreateElement("maps");
doc.AppendChild(root);
XmlElement map = doc.CreateElement("map");
map.SetAttribute("name", description);
root.AppendChild(map);
XmlElement terrain = doc.CreateElement("terrain");
terrain.SetAttribute("demfile", bilFileName);
if (ExportTexture)
terrain.SetAttribute("texturefile", imgFileName);
else
terrain.SetAttribute("texturefile", @"colors\Geo_Water_1.png");
terrain.SetAttribute("altscale", "1.0");
terrain.SetAttribute("centerlatitude", centerLat.ToString(CultureInfo.InvariantCulture));
terrain.SetAttribute("centerlongitude", centerLon.ToString(CultureInfo.InvariantCulture));
terrain.SetAttribute("span", size.ToString(CultureInfo.InvariantCulture));
terrain.SetAttribute("heading", rotation.ToString(CultureInfo.InvariantCulture));
terrain.SetAttribute("worldradius", worldWindow.CurrentWorld.EquatorialRadius.ToString(CultureInfo.InvariantCulture));
map.AppendChild(terrain);
doc.Save(xmlPath);
ProcessStartInfo ps = new ProcessStartInfo(exePath, xmlFileName);
ps.WorkingDirectory = PluginDirectory;
Process.Start(ps);
progress = 100;
teForm.ProgBarValue = (int)progress;
}
catch (Exception ex)
{
MessageBox.Show(ex.Message, "Export error");
}
}
Related documents
Download