Рефераты
 

Разработка элемента управления для отображения векторных карт

Разработка элемента управления для отображения векторных карт

Введение

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

1. Разработка и анализ технического задания

1.1 Цель и назначение разработки

Целью разработки является создание элемента управления для отображения карт, представляющих собой векторные изображений в формате EPS (Encapsulated PostScript), удобного и простого в использовании. Работа векторными картами предоставляет возможность визуального представления информации связанной с геополитикой, геологическими исследованиями.

1.2 Основание разработки

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

1.3 Область применения

Данный комплекс элементов управления может использоваться при разработке программного обеспечения для работы с векторными картами в формате EPS (Encapsulated PostScript).

1.4 Требования предъявляемые к проекту

-элемент управления должен обеспечивать необходимую функциональность для работы с векторными картами.

- простой и понятный интерфейс для построения приложений использующих этот элемент.

- использование современных технологий разработки программного обеспечения.

- расширяемость, возможность усовершенствования, на ряду с основным назначением.

- выводом векторных карт в формате EPS (Encapsulated PostScript), необходимо предусмотреть вывод дополнительной информации.

Элемент управления должен предоставлять следующие основные функции:

- масштабирование

- автомасштабирование в пределах видимой области

- расположение изображения в пределах видимой области

- перемещение изображения

- выделение замкнутых областей по щелчку мыши

- раскрашивание выделенной замкнутой области

- автораскрашивание

- раскрашивание с учётом дополнительной информации

1.5 Требования к программному и техническому обеспечению

Операционная система Windows XP и выше.

Microsoft.NET Framework SDK v1.1или выше

Microsoft Visual Studio.NET 2003 или выше

Pentium 4 1800 Мгц, 512 оперативной памяти, 2Мб на жёстком диске.

1.6 Анализ технического задания

Исходя из требований проекта и учитывая изученные на данный момент языки программирования выбор делался из следующего перечня языков: Visual Basic, Borland Delphi, Borland C++ Builder, Visual C++, Visual Studio.Net 2003 Visual C#. Язык Visual Basic очень прост в освоении но его возможности ограничены он скорее подходит для быстрого создания красивых приложений, и приложений использующих пакет Microsoft Office. Данный язык не подходит по функциональности и сложен для реализации предъявляемых требований. Borland C++ Builder представляет классический язык С++ с набором библиотек. Основным недостатком является моральное устаревание и отсутствие поддержки современных технологий. Язык С++ прекрасно переноситься на другие платформы в частности Linux но так как в Borland C++ Builder присутствуют собственные библиотеки не реализованные в других платформах что не возможно осуществить переноску даже с открытым кодом, что ставит под сомнение коммерческое использование компонента. Visual C++ тоже отличается наличием собственных библиотек что более сильно связывает его с ОС Windows. Конечно в последних версия есть поддержка Framework обозначаемая как `управляемый С', но зачем использовать что-то подогнанное. По этому этот язык не подходит нам. Borland Delphi очень хороший язык. Функционален, имеются достаточные инструменты для реализации нашего проекта, в последних версия имеется поддержка технологии.Net разработанной компанией Microsoft что повышает переносимость программного обеспечения на другие платформы, конечно с реализованной технологией.Net на этой платформе. Если сравнить его с Visual C#. То видны неоспоримые преимущества последнего. Также идёт соперничество между двумя с моей точки зрения наиболее перспективными языками С# и Java. С# - это язык программирования, синтаксис которого очень похож на синтаксис Java (но не идентичен ему). Например, в С# (как в Java) определение класса состоит из одного файла (*.cs), в отличие от C++, где определение класса разбито на заголовок (*.h) и реализацию (*.срр). Однако называть С# клоном Java было бы неверно. Как С#, так и Java основаны на синтаксических конструкциях C++. Если Java во многих отношениях можно назвать очищенной версией C++, то С# можно охарактеризовать как очищенную версию Java. Синтаксические конструкции С# унаследованы не только от C++, но и от Visual Basic. Например, в С#, как и в Visual Basic, используются свойства класс сов. Как C++', С# позволяет производить перегрузку операторов для созданных вами типов (Java не поддерживает ни ту, ни другую возможность). С# -- это фактически гибрид разных языков. При этом С# синтаксически не менее (если не более) чист, чем Java, так же прост, как Visual Basic, и обладает практически той же мощью и гибкостью, что и C++. Подводя итоги, еще раз выделим основные особенности С#.

- Указатели больше не нужны! В программах на С#, как правило, нет необходимости в работе с ними (однако если вам это потребуется, пожалуйста, возможности для работы с указателями в вашем распоряжении).

- Управление памятью производится автоматически.

- В С# предусмотрены встроенные синтаксические конструкции для работы с перечислениями, структурами и свойствами классов.

- В С# осталась возможность перегружать операторы, унаследованные от C++. При этом значительная часть возникавших при этом сложностей ликвидирована.

- Предусмотрена полная поддержка использования программных интерфейсов. Однако в отличие от классического СОМ применение интерфейсов это не единственный способ работы с типами, используя различные двоичные модули..NET позволяет передавать объекты (как ссылки или как значения) через границы программных модулей.

- Также предусмотрена полная поддержка аспектно-ориентированных программных технологий (таких как атрибуты). Это позволяет присваивать типам характеристики (что во многом напоминает COM IDL) для описания в будущем поведения данной сущности. Возможно, самое важное, что необходимо сказать про язык С#, -- это то, что он генерирует код, предназначенный для выполнения только в среде выполнения. NET. Например, вы не сможете использовать С# для создания классического СОМ-сервера. Согласно терминологии Microsoft код, предназначенный для работы в среде выполнения.NET, -- это управляемый код (managed code).

2. Разработка архитектуры элемента управления

При разработке архитектуры было принято решение отдельно создать элемент управления который будет служить только для отображения векторных карт и хранения данных(цвет, набор координат замкнутых областей). Дополнительные элементы управления буду выдавать лишь набор цветов(выбранных по определённому алгоритму) для раскрашивания.

2.1 Основной элемент управления

При разработке элемента управления мы будем руководствоваться принципами Объектно-Ориентированного Программирования. Основная парадигма которого гласит: “Реши какие потребуются классы обеспечь полный набор операций ля каждого класса явно вырази общность через наследование”. В результате проведения объектной декомпозиции были выделены следующие классы:

Класс «элемент управления» CntrIm который наследуется от класса UserControl который предоставляет возможности создания элементов управления. Класс CntrIm выступует как класс в котором будет осуществляться отрисовка векторных изображений и обеспечиваться доступ к хранимой информации о изображении и вложенных объектах, осуществляется получение координат замкнутых областей из файла и передачу их в экземпляр класс MyMap для объединения в замкнутые области и хранения.

Класс MyMap. Для класса CntrIm является вложенным и будет являться своего рода диспетчером управляющим картой. Будет управлять вложенными объектами, осуществлять передачу необходимых данных в обоих направлениях, отвечать за систему координат, масштабирование изображения, переключение между выделенными областями, предоставление координат для отрисовки объектов на элементе управления. В нём будет хранится коллекция объектов обозначающих замкнутые области из которых составлена карта.

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

Класс PointD. Смысловая нагрузка этого класса это точка из которых создаются замкнутые области. Этот класс предназначен лишь для хранения координат полученных из файла. Иерархия представлена на Рис. 2.1

Рис. 2.1 Иерархия классов

2.2 Дополнительные элементы управления

Класс AutoColor. Взаимодействие этого класса с элементом управления представляет собой контрактную модель. Экземпляр класса AutoColor получает коллекцию областей для анализа (массив экземпляров класса PathD), анализирует данные и выдаёт массив экземпляров класса Color, то есть цвета в которые будут раскрашены области с учётом того что рядом расположенные области не будут одинаково раскрашены. Выбор цветов производится из условия оптимального раскрашивания. Массив экземпляров класса PathD хранится в экземпляре класса MyMap. Схема взаимодействия приведена на Рис. 2.2.1

Класс UserControl1. Является элементом управления унаследованным от класса UserControl. И создан для выдачи экземпляра класса Color то есть цвета в который будет окрашена выделенная в элементе управления CntrIm замкнутая область. Схема взаимодействия приседена на рисунку 2.2.2

Рис. 2.2.1 Схема взаимодействия c классом AutoColor

Класс SetDiapColor. Является элементом управления унаследованным от UserControl и предназначен для выдачи схемы раскраски замкнутых областей. Он получает количество замкнутых областей. В этом элементе управления каждой области присваивается число и задаются диапазоны для раскрашивания. В зависимости от этих параметров выдаётся массив типа Color. То есть номер экземпляра в массиве соответствует в какой цвет будет раскрашена замкнутая область.

Рис 2.2.2 Схема взаимодействия с классом UserControl1

Рис 2.2.3 Схема взаимодействия с классом SetDiapColor.

3. Разработка кода элемента управления

3.1 Класс PointD

Предназначен исключительно для хранения координат точек x и y и организации доступа к ним. Тип переменных в которых хранятся координаты определялся исходя из того что необходимо хранить числа с не менее чем 5ью знаками поле запятой.

Структура класса PointD:

public class PointD

{

private double x; //координата x

private double y; //координата y

public PointD() //конструктор по умолчанию

{ …

}

public PointD(double x,double y)

{…

}

public PuintD(PointD pd) //конструктор копирования

{…

}

public double X // свойство для доступа к координате X

{…

}

public double Y //свойство для доступа к координате Y

{…

}

3.2 Класс PathD

Класс PathD несёт смысловую нагрузку и представляет собой замкнутую область. В его структуру включен массив типа PointD в который добавляются точки которые формируют замкнутую область. Включены поля хранящие количество точек в замкнутой области, координаты центра замкнутой области, цвет замкнутой области. Центр области вычисляется по формуле Xc=(x1+x2+…+xn)/n, Yc=(y1+y2+…+yn)/n, где Xc,Yc-координаты центра фигуры, n-количество точек замкнутой фигуры, x1..xn координаты по оси X точек 1..n, y1..yn координаты по оси Y точек 1..n. Добавление точек осуществляется так: создается массив длинной n+1 экземпляры класса PoitD копируются в новый массив, в последний элемент массива записывается новый экземпляр класса PoitD. Старый массив уничтожается «сборщиком мусора» элементом среды в которой идёт выполнение.

Структура класса PathD

public class PathD

{

private int length; //количество точек в замкнутой области

private PointD[] msPtd; //массив точек

private PointD centr; //центр фигуры

private Color clr; //цвет в который будет раскрашена область при //при отрисовке

public PathD()

{…

}

public void AddPoint(PointD pointD) //метод добавляющий точку к

//области

{ …

}

public int Length

{ …

}

public PointD[] PathPoints //свойство выдающее массив точек области

{…

}

public PointD Centr //свойство выдающее центр области

{ …

}

public Color ColorP //свойство для получения и установки цвета

{ …

}

}

3.3 Класс MyMap

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

Стрктура класса MyMap:

public class MyMap

{

private double scale; //поле масштаба

private int length; //поле количество замкнутых областей

private int space; //отступ от границы элемента

private double kx; //коэффициент по оси х

private double ky; //коэффициент по оси y

private double dx; //смещение оси х

private double dy; //смещение оси y

private PathD [] msPthd; // массив замкнутых областей

private Pen [] msPn; //массив перьев для отрисовки обастей

// iой области соответствует iое перо

}

Метод public void AddPath(PathD pathD) предназначен для добавления замкнутой области к коллекции областей в качестве параметра ей передается объект типа (PathD

Свойство public PathD[] AllPaths выдаёт копию массива замкнутых областей

Свойство public Pen[] AllPen выдаёт копию массива перьев соответствующих каждой области.

Свойство public int Length выдаёт количество замкнутых областей

Свойство public double Scale выдаёт или устанавливает масштаб изображения

Метод public void SetAxes(double kX,double kY) предназначен для установки коэффициентов по координатным осям.

Метод public void SetXYAxes(double dX, double dY) предназначен для установки смещения координатных осей относительно исходных.

Свойство public double KX предназначен для установки и получения коэффициентов по оси X.

Свойство public double KY предназначен для установки и получения коэффициентов по оси Y.

Свойство public double DX предназначен для установки и получения смещения координатной оси X относительно исходного расположения.

Свойство public double DY предназначен для установки и получения смещения координатной оси Y относительно исходного расположения.

Метод public void SetXYtoView() предназначен для нахождения смещения координатных осей для расположения изображения в видимой области в исходной системе координат. То есть находятся минимальные координаты по оси X и Y затем из них вычитается смещение от границы. Смещение от границы сделано исключительно в эстетических целях.

Метод public void SetScaleToView(int height,int width) предназначен для вычисления и установки масштаба для вписывания в окно заданных размеров height, width. Вычисление происходит методом нахождения минимальных и максимальных координат в имеющихся замкнутых областях. Затем происходит выбор наиболее протяженной разницы между максимальной и минимальной координатой по X и Y. Вычисление масштаба по формуле scale = (height-space*2)/h по оси Y и scale = (width-space*2)/l по оси X.

Метод public void Allocate(int nPth,int type) предназначен для установки пера замкнутой области с номером nPth. Переменная type предназначена для представления какой тип выделения замкнутой области. Выделение одиночной или группы областей. В данном случае реализовано только для одиночного выделения областей. Алгоритм представлен ниже на блок схеме Рис. 3.3.

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

Рис. 3.3 блок-схема алгоритма метода public void Allocate(int nPth,int type)

Метод public void SetClrPth(int NPth, Color Clr) Предназначен для установки свойства замкнутой области с номером NPth в значение Clr.

Метод public int GetNamberPath (int crX, int crY) предназначен для определения какой замкнутой области принадлежности координаты точки. Если точка не принадлежит ни одной из областей то метод возвращает -1 в противном случае возвращает номер области.

Смысл определения принадлежности точки фигуре заключается в следующем:

Пусть у нас есть точка с координатами x,y: Принадлежность точки стороне проверяется просто: если концевые точки стороны A(x1,y1) и B(x2,y2), то, если точка Z(x,y) принадлежит стороне, то должно существовать такое число p, 0<=p<=1, что

x=p*x1+(1-p)*x2

y=p*y1+(1-p)*y2

(тут используется то, что если прямая проходит через A и B, то точки прямой имеют координаты (p*x1+(1-p)*x2, p*y1+(1-p)*y2), p действительное число. При 0<=p<=1 мы получаем отрезок между точками A и B).

Далее, проведем из точки Z прямую, параллельную оси OX (ее уравнение будет Y=y) и проверим, сколько сторон треугольника пересекает полулуч, идущий от точки Z, например, вправо. Если 0, то Z - вне треугольника, если 1 - то внутри, если 2 - то снаружи

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

Может быть 2 случая рассмотренных на Рис. 3.3.1.

Рис 3.3.1 2а случая пересечения лучом вершины

В случае 1, когда оба ребра, входящих в вершину A, лежат по одну сторону от прямой, количество пересечений можно считать равным двум (или нулю), в случае 2, когда ребра лежат по разные стороны от прямой, число пересечений примем равным 1. Если прямая проходит по стороне, то число пересечений будем считать равным 2. Алгоритм нахождения номера выделенной области рассмотрен на блок схеме Рис. 3.3.2.

Рис. 3.3.2 Блок-схема алгоритма нахождения номера выделенной области

3.4 Класс CmpView

Предназначен для отрисовки элементов векторной каты, открытия файла с векторным изображением и получения координат замкнутых областей. А также обеспечения взаимодействия с внешней средой.

public class CntrIm: System.Windows.Forms.UserControl

{

private string Path; //поле для хранения пути к файлу

private MyMap mapD; //поле для хранения объекта MyMap

private bool flag; //нажата кнопки мыши или нет

private bool flRec; //рисовать прямоугольник выделения

private int oldX; //координаты нажатия кнопки мыши

private int oldY;

private int curX; //текущее положение мыши

private int curY;

private double oldDx; //старое смещение координатных осей

private double oldDy;

public delegate void MapLoadEndDelegate(); //определение делегата

public event MapLoadEndDelegate MapLoadEnd; //определение события

}

Метод public void FileOpen(string Pth) предназначен для открывания файла векторного изображения и получении координат замкнутых областей. В начале создается новый экземпляр класса MyMap, устанавливается начальный масштаб и коэффициенты координатных осей. Затем идёт открытие потока для чтения где параметром вызова выступает строка с полным путем к файлу.

StreamReader StrmR = new StreamReader(Path);

Чтение из потока происходит по строчно, строка записывается в переменную str которая и будет использоваться для анализа, выделения команд и координат замкнутых областей. При поступлении набора символов предшествующего массивам координат замкнутых областей флаг flag устанавливается в значение true что говорит о том что начинается считывание координат замкнутых областей. Далее считывается следующая строка и происходит выделение координат. Пока не достигнут конец строки или не найден один из командных символов происходит выделение координат. Из строки по символьно читаются цифры до появления пробела что говорит об окончании значения координаты. Ведётся подсчёт считанных чисел для определения вида координаты по оси X или по оси Y. Не чётные числа означают координаты по оси X чётные числа - координаты по оси Y. Затем создается экземпляр типа PointD с полученными координатами и происходит добавление в экземпляр класса PathD. То есть формируется замкнутая область. Процесс считывания и добавления координат, формирование замкнутая области происходит до того как встречается следующая командная строка. В этот момент сформированная замкнутая область добавляется в коллекцию областей, передаётся в экземпляр класса MyMap а флаг flag устанавливается в значение false сигнализируя о том что чтение координат и формирование области закончено. Далее процесс повторяется пока не будет достигнут конец файла. После чего поток закрывается, ресурсы высвобождаются. Далее вызываются методы SetScaleToView(this.Height,this.Width) и SetXYtoView() экземпляра класса MyMap для масштабирования и расположения изображения в пределах окна. После чего если определёно то вызывается функция сопоставленная событию окончания чтения файла. Алгоритм чтения координат из файла представлен на блок-схеме Рис 3.4.

Метод private void CntrIm_MouseDown object sender, System.Windows.Forms.MouseEventArgs e) срабатывает когда происходит нажатие кнопки мыши. При этом flag устанавливается в значение true что означает кнопка нажата, и запоминаются текущие координаты мыши и смещение координатных осей.

Метод private void CntrIm_MouseUp(object sender, System.Windows.Forms.MouseEventArgs e) срабатывает когда происходит событие отпускание кнопки мыши. При этом flag устанавливается в значение false.

Метод private void CntrIm_MouseMove(object sender, System.Windows.Forms.MouseEventArgs e) срабатывает когда происходит передвижение мыши и запоминаются текущие координаты мыши. Необходимые для отрисовки прямоугольника выделения.

Метод public void ScaleToPoint(int crX,int crY,double sclN) предназначен для изменения масштаба изображения на заданную величину sclN в точку int crX,int crY.

Метод public void MovePoint(int oldx,int oldy, int crx,int cry) предназначен для перемещения изображения из точки с координатами oldx, oldy, в точку с координатами crx, cry.

Метод public void ScaleToRctangle(int oldx,int oldy,int crX,int crY) предназначен для вычисления масштаба для увеличения выделенной области до размеров экрана. Размеры выделенной области определяются первой: oldx,int oldy, и последней точкой int crX,int crY

Рис 3.4 Блок-схема чтения координат из файла

Метод public void VeiwInWindow() предназначен для показа изображения в окне элемента управления. В нем вызываются методы SetScaleToView(this.Height,this.Width) и SetXYtoView() экземпляра класса MyMap для масштабирования и расположения изображения в пределах окна.

Метод RealScale() предназначен для отображения изображения в натуральную величину. Реализовано через установку свойства экземпляра класса MyMap Scale=1 и вызова метода SetXYtoView().

Свойство public bool VeiwRect предназначено для установки значения поля flRec, разрешение или запрещение отрисовки прямоугольника выделения.

Метод public void Allocate(int nPth,int type) предназначен для выделения области указанной в значением параметра nPth, и тип выделения type путём вызова метода Allocate(int nPth,int type) экземпляра класса MyMap.

Метод public void SetClrPath (int NPth,Color Clr) предназначен для установки области с номером NPth цвета окраса Clr. Путём вызова метода SetClrPth(NPth,Clr) экземпляра класса MyMap.

Метод public Color GetClrPath(int NPth) предназначен для получения цвета окраса области с номером NPth.(пример: mapD.AllPaths[NPth].ColorP)

Метод private void CntrIm_SizeChanged(object sender, System.EventArgs e) срабатывает когда изменяются размеры элемента управления. В нем вызываются методы SetScaleToView(this.Height,this.Width) и SetXYtoView() экземпляра класса MyMap для масштабирования и расположения изображения в пределах окна.

Метод protected override void OnPaint(PaintEventArgs e) является перегруженный методом вызываемым при перерисовке элемента управления. Чтобы получить изображение нам необходимо нарисовать все замкнутые области, чтобы нарисовать замкнутую область нам необходимо для данной области простись по всем точкам соединяя каждую точку с последующей. Первый цикл осуществляет перемещение по набору областей а второй цикл осуществляет переход от точки к точке внутри области выбранной в предыдущем цикле. Через методы классов мы получаем доступ к координата конкретной точки.

tmP[j].X=Convert.ToInt32((mapD.AllPaths[k].PathPoints[j].X-

mapD.DX)*mapD.KX*mapD.Scale);

tmP[j].Y=Convert.ToInt32((mapD.AllPaths[k].PathPoints[j].Y-

mapD.DY)*mapD.KY*mapD.Scale);

Эти координаты конвертируются в текущую систему координат и конвертируются из типа double в тип int и заносятся в экземпляр типа Point который находится в массиве длинна которого равна количеству точек в текущей замкнутой области. Когда все координаты текущей замкнутой области перенесены через экземпляр класса PaintEventArgs осуществляется доступ к экземпляру класса Graphics с помощью которого и осуществляется рисование на элементе управления. Сначала заливается текущая облать выбранным стилем и цветом, затем осуществляется доступ к кисти которым должна быть отрисована данная область. Доступ осуществляется через свойство экземпляра класса MyMap AllPen с указанием номера области, то есть соответствующему ей перу.

SolidBrush dBr = new SolidBrush(mapD.AllPaths[k].ColorP);

e.Graphics.FillPolygon(dBr,tmP); Pen tPen;

if(mapD.AllPen[k]==null)

{

tPen=new Pen(Color.Black,1);

}

else

{

tPen=mapD.AllPen[k];

}

e.Graphics.DrawLines(tPen,tmP);

Если кисть не определена то отрисовка ведётся пером по умолчанию. После чего процесс повторяется для других областей. После этого осуществляется вывод в центре области порядкового номера этой области. Процесс доступа к точке центра области хранимой в каждом экземпляре PathD производится через методы и свойства экземпляра класса MyMap. Печать строки осуществляется с помощью метода экземпляра класса Graphics DrawString. Затем с помощью метода экземпляра класса Graphics DrawLines выводятся границы элемента. После проверки соответствующих булевых переменных происходит вывод прямоугольника выделения.

if (flRec==true&&flag==true)

{

Pen myP= new Pen(Color.Blue,1);

e.Graphics.DrawLine(myP,oldX,oldY,oldX,curY);

e.Graphics.DrawLine(myP,oldX,oldY,curX,oldY);

e.Graphics.DrawLine(myP,curX,oldY,curX,curY);

e.Graphics.DrawLine(myP,oldX,curY,curX,curY);

}

3.5 Класс AutoColor

public class AutoColor

{

public PathD [] msPth; //коллекция замкнутых областей

public Color [] msClr; //массив цветов областей

public AutoColor() //конструктор по умолчанию

{ msPth=null;

msClr=null;

}

}

Конструктор public AutoColor(PathD [] Pth) параметром для которого является коллекция областей для которой будет производиться автоматическое раскрашивание. Раскрашивание будет производиться по принципу оптимального использования цветов. В начальный момент времени создается массив типа Color в который будут заноситься цвета для раскрашивания соответствующих областей. Далее вызывается функция private int[,] GetMsGr() которая предназначена для создания матрицы пограничных областей. Строки и столбы этой матрицы представляют собой замкнутые области а узлы матрицы границы между областями.

Например у нас есть 4 ре области как показано на Рис 3.5.

Рис 3.5 Пример расположения областей.

Значит матрица пограничных областей будет выглядеть следующим образом

0 1 1 0

1 0 1 0

1 1 0 0

0 0 0 0

То есть если деве области имеют общую границу то в узле матрицы номер сроки и номер столбца которого соответствует граничащим областям будет находится 1, если же общей границы нет то в узе остаётся 0. Сам алгоритм проверки на существование общей границы таков: Первый цикл перебирает области которые нужно сравнить 2цикл, вложенный в него перебирает координаты которые сравнивает и запоминает их в переменный которые будут использоваться при сравнении. 3ий цикл вложенный во второй перебирает области с которыми надо сравнить исключая текущую область. 4ый вложенный цикл в 3ий перебирает сами координаты. Если координаты текущей точки текущей области совпадают со сравниваемыми координатами данной области то в узлах матрицы с соответствующими номерами столбцов и срок записывается 1. И так процесс повторяется для всех областей. Функция возвращает заполненную матрицу. Далее представлена часть кода функции GetMsGr() заполняющая матрицу

for (int i=0;i<msPth.Length;i++) //1ывй цикл

{

for(int j=0;j<msPth[i].Length;j++) //2ой вложенный цикл

{

x1 = msPth[i].PathPoints[j].X; //запоминание координат точки для сравнения

y1 = msPth[i].PathPoints[j].Y;

for (int k=0;k<msPth.Length;k++) //3ий вложенный цикл

{

for(int l=0;l<msPth[k].Length;l++) 4ый вложенный цикл

{

if(i!=k)

{

_x1 = msPth[k].PathPoints[l].X;

_y1 = msPth[k].PathPoints[l].Y;

if(x1==_x1&&y1==_y1) //сравнение координат текущей

{ //точки с запомненными

ms[i,k]=1;

}

Далее вызывается рекурсивная функция Run(i,ref mss); где параметрами являются i-номер области с которой надо начинать расчёт окраски, ref mss ссылка на массив пограничных объектов. Алгоритм работает следующим образом. В начале проверяется окрашен уже данная область или нет. Номер цвета содержится в диагонали матрицы. Если не окрашена область, то ищется цвет не принадлежащий окружающим эту область областям. Тесть выбирается jый цвет затем проходя по сроке ищет области которыми граничит и найдя такую область сравнивает текущий цвет с цветом этой области если совпадают то flag устанавливается из true в false а поиск продолжается по остальным областям. Если же нет то переход к следующей пограничной области. Если для данного j по всем граничащим областям не нашлось равного то данное число записывается как цвет данной области. Затем для всех областей в которые ёще не переходили и которые граничат с данной областью запускается рекурсивная функция Run(i,ref ms); а в узлы где номер столбца это область текущая а строка это область куда перейдём и наоборот записывается 2. Рекурсия повторяется. Пример массива на разных этапах при распределении цветов:

0 1 1 0 1 2 1 0 1 2 1 0 1 2 2 0 1 2 2 0

1 0 1 0 2 0 1 0 2 2 2 0 2 2 2 0 2 2 2 0

1 1 0 0 1 1 0 0 1 2 0 0 2 2 3 0 2 2 3 0

0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1

Затем в массив длинна которого равна количеству областей записываются соответствующие областям цвета. Массив записывается в поле msClr доступ к которому можно получить через свойство public Color [] GetMsClr. Алгоритм работы функции Run приведён в блок схеме Рис 3.5.1

Рис. 3.5.1 Блок-схема рекурсивного алгоритма распределения цветов.

3.6 Класс UserControl1

Как элемент управления предназначен для отображения цвета выбранного при вызове ColorDialog и хранения этого цвета с возможностью считывания этого цвета через свойство ClrSG(т.е. есть возможность последующего использования для окрашивания выделенной области в текущий цвет свойства ClrSG). А также для отображения цвета установленного из вне через это же свойство. Примечание: В данной работе применяется для отображения цвета выделенной области.

public class UserControl1: System.Windows.Forms.UserControl

{

private System.Windows.Forms.GroupBox groupBox1;

private System.Windows.Forms.Button button1;

private System.Windows.Forms.Label label1;

private int nomber; //число, отображается в label1

public UserControl1()

{

}

protected override void Dispose(bool disposing)

{ …

}

}

Объявление делегата и события на основе этого делегата. Событие наступает после закрывания окна выбора цвета ColorDialog. Необходимо для отслеживания смены цвета для своевременного перекрашивания выделенной области.

public delegate void ColorSetDelegate();

public event ColorSetDelegate ColorSet;

Метод private void button1_Click(object sender, System.EventArgs e) срабатывает когда нажата кнопка button1. Создаётся экземпляр класса ColorDialog окна для выбора цвета если результат закрытия окна “OK” то цвет кнопки button1 меняется на выбранный. Свойство кнопки button1 BackColor используется и для хранения текущего цвета. Происходит наступление события ColorSet.

ColorDialog ClrDlg = new ColorDialog();

if(ClrDlg.ShowDialog()==DialogResult.OK)

{

button1.BackColor=ClrDlg.Color;

if(ColorSet!=null)

ColorSet();

}

Свойство public Color ClrSG предназначено для считывания и установки текущего цвета.

Свойство public int Nomber предназначено для считывания и установки числа. Данное число отображается в объекте label1. в программе примере используется для отображения номера выделенной области.

3.7 Класс SetDiapColor

Предназначен для создания массива объектов типа Color (т.е. цветов). В начале через метод SetQuant(int Quant) мы устанавливаем в экземпляр типа SetDiapColor какое количество областей мы хотим раскрасить. Затем сопоставляя некоторые числа каждой области(эти числа могут означать что угодно например количество проживающих на данной области). Затем мы вводим диапазоны и сопоставляем каждому диапазону цвет в который будет окрашена область если число попадёт в заданный интервал. Когда закончен ввод. Нажимаем кнопку и начинается анализ. Каждое число сопоставленное области проверяется в какой интервал оно входит и в соответствии с этим цвет записывается в массив индекс ячейки в которую произведут запись цвета равен номеру рассматриваемой на данный момент области. Так происходит со всеми областями. Массив доступен через свойство GetMsClr. Затем перебирая ячейки массива передаём их в класс CntrIm через метод SetClrPath(i,msc[i]); где это номер области а msc[i] это элемент цвет в полученном массиве цветов.

public class SetDiapColor: System.Windows.Forms.UserControl

{

private System.Windows.Forms.Button button4;

private System.Windows.Forms.GroupBox groupBox2;

private System.Windows.Forms.Button button2;

private System.Windows.Forms.Button button1;

private System.Windows.Forms.ComboBox comboBox2;

private System.Windows.Forms.Button button3;

private System.Windows.Forms.GroupBox groupBox1;

private System.Windows.Forms.TextBox textBox1;

private System.Windows.Forms.ComboBox comboBox1;

private int QuantPaths; //количество областей

private double [] msCh; //сопоставленные каждой области число

private Color [] msChClr; // сопоставленные каждой области цвет

private double [] msDiap; //массив где i-ый член хранит верхнюю

//границу диапазона а i-1 нижнюю

private Color[] msClr; // сопоставленные диапазонам цвета

private int length; //длина массива диапазонов

private Color DefCol; // цвет по умолчанию

public SetDiapColor() //конструктор поумолчанию

{…

}

Определение делегата и события на основе делегата. Событие наступает по нажатии кнопки button4 “раскрасить”

public delegate void ColorRsDelegate();

public event ColorRsDelegate ColorRs;

Метод public void SetQuant(int Quant) предназначен для создании массива чисел сопоставляемых областям количество которых передано в параметре Quant. Инициализации переменных значениями.

Метод private void textBox1_KeyPress(object sender, System.Windows.Forms.KeyPressEventArgs e) вызывается когда фокус ввода находится на элементе управления textBox1 и осуществляется нажатие кнопки. Если нажатая кнопка не цифра и не “,” которую можно вводить не более 1 раза то textBox1 блокируется для ввода

Если же нажата клавиша перевода каретки то происходит конвертация значения в тип Double и запись этого значения в массив чисел сопоставленных областям. Номер области определяется по записи выделенной в ComboBox1.

Метод private void comboBox1_SelectedIndexChanged(object sender, System.EventArgs e) вызывается когда меняется выделенный индекс элемента управления comboBox1 и высвечивает в textBox1 число приписанное к данной области.

Страницы: 1, 2


© 2010 BANKS OF РЕФЕРАТ