Работа со списками

1



Государственное образовательное учреждение высшего профессионального образования «Московский государственный технический университет им. Н.Э. Баумана»

Калужский филиал

	Факультет"Фундаментальных Наук"

Кафедра "Программного обеспечения ЭВМ, информационных технологий и прикладной математики" (ФН1-КФ)















КУРСОВАЯ РАБОТА

ПО КУРСУ: «ПРОГРАММИРОВАНИЕ НА С++»

На тему: «Работа со списками»

























Калуга - 2008


АННОТАЦИЯ



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

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




ИССЛЕДОВАТЕЛЬСКАЯ ЧАСТЬ



 Постановка задачи



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



Способы реализации



Для реализации поставленной задачи используется стек (он представляет собой список типа LIFO, в котором последний добавленный элемент считывается первым), а также обратная стеку динамическая структура – очередь (FIFO). В программе используются методы объектно-ориентированного программирования для облегчения способа решения задачи: шаблоны классов (для записи в список элементов различного типа), наследование (для сокращения объема программного кода), виртуальные функции (для корректного переопределения методов различных классов), абстрактный класс (для общего описания основных функций).



Исследование поставленной задачи



1.3.1 Создание стека

Стек представляет собой список типа LIFO, в котором последний добавленный элемент считывается первым. Для создания стека в программе используется структура List, содержащая поле ссылки на следующий элемент и шаблонный тип данных в качестве информационного поля. Для программной реализации стека необходимо описать 2 переменные указанного выше типа List: p (указатель на текущий элемент) и top (указатель на вершину списка). При добавлении элемента в стек, новому элементу присваивается ссылка на вершину стека, а затем и он сам становится вершиной. Таким образом, стек растет как бы назад:



p=new list;

p->next=top;

p->inf=value;

top=p;



1.3.2 Создание очереди

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



top=new list;

top->next=NULL;

p=top;



Добавление элемента в очередь тоже отличается от добавления элемента в стек. Здесь вершина списка остается на своем месте, меняется только положение текущего указателя, а элементы заносятся в прямом порядке, и ссылка на новый элемент создается из текущего, а не наоборот, как было в стеке, после чего новый элемент становится текущим:



 p->next=new list;

 p->next->next=NULL;

 p->inf=value;

 p=p->next;

 Актуальность поставленной задачи



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




2. КОНСТРУКТОРСКАЯ ЧАСТЬ



2.1 Обоснование выбора средства программирования



Для написания данной курсовой работы был использован язык Borland C++ Builder 6. C++ Builder позволяет быструю визуальную разработку приложений на языке C++. Профессиональные средства языка C++ интегрированы в визуальную среду разработки. Интегрированная среда разработки объединяет редактор форм, инспектор объектов, палитру компонент, администратор проекта и полностью интегрированные редактор кода и отладчик – инструменты быстрой разработки программных приложений, обеспечивающие полный контроль над кодом и ресурсами. C++Builder воплощает важнейшие аспекты объектно-ориентированного программирования в удобном для пользования инструменте визуального проектирования, что лучше всего подходит для реализации и отображения результатов работы программы.

Для удобной работы со списком необходимо представить его как отдельный тип данных. C++ позволяет определять пользовательские типы, а также определять набор операций, производимых над экземплярами этого типа. Ключевым понятием C++ является класс. Класс – это тип данных, определяемый пользователем, переменные которого являются объектами. Т.о., в программе, созданной на C++, определение класса должно быть определением типа данных, содержащим информацию о значениях, которые могут храниться в его переменных, а также о функциях-членах этого класса. 

Механизм наследования позволяет определять новые классы на основе уже имеющихся. Класс, на основе которого создаётся новый класс, называется базовым (родительским) классом, а новый – производным (наследником). Непосредственным базовым классом называется такой класс, который входит в список базовых классов при определении класса. Любой производный класс может в свою очередь стать базовым для других создаваемых классов. Т.о. формируется направленный граф иерархии классов, а при объявлении объектов и иерархия объектов. В иерархии объектов производный объект имеет возможность доступа к элементам данных и методам объектов, типизированных базовым классом.

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

Виртуальные функции являются средством позднего связывания в языке С++.

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

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

Т.о. язык С++ содержит все необходимые возможности для реализации списковой структуры, а также возможность работы с ней как со встроенным типом данных, который к тому же может быть со временем преобразован и расширен.



2.2 Функциональное назначение



Программа может применяться для создания графических изображений

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

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



2.3 Описание логической структуры



Курсовая работа представляет собой программу, написанную на C++ Builder 6. Для упрощения программного кода используется иерархия классов.

Абстрактный класс Spisok содержит основные свойства и методы, которые необходимы всем его наследникам, то есть, общие для всех списков данные: структура List, указатели *top и *p, чисто-виртуальные функции:

add(Data value, AnsiString name). Добавление элемента с именем «Name», содержащего информацию «Data». Data – это шаблонный тип данных, который может принять значение любого переданного в класс типа. Это позволяет использовать один и тот же класс списка для хранения данных разных типов. Функция не возвращает значений.

remove(int index). Удаляет элемент с порядковым номером «Index» из списка. Для этого создается дополнительный указатель на удаляемый элемент, а ссылка с предыдущего элемента переносится на следующий, после чего, отделенный от списка элемент удаляется из памяти стандартной процедурой delete(*list). Функция не возвращает значений.

change(int index, Data value). Изменяет значение элемента с порядковым номером «Index» на значение «Data».

int count(). Возвращает число элементов в списке. Подсчет производится с помощью цикла с предусловием до тех пор, пока не будет достигнут конец списка. На каждом шаге цикла происходит инкремент счетчика.

Data getvalue(int index). Возвращает информационное поле элемента с порядковым номером «Index». Происходит обход списка до тех пор, пока не будет достигнут порядковый номер (цикл с параметром). После этого возвращается информационное поле.

AnsiString getname(int index). Возвращает имя элемента с порядковым номером «Index». Работает аналогично предыдущей функции.

int search (AnsiString name). Возвращает порядковый номер первого найденного элемента с именем «Name».

Класс Spisok является абстрактным, так как он содержит выше указанные чисто-виртуальные функции.

Класс Stack – наследник класса Spisok. В нем переопределяются все чисто-виртуальные функции предка, им присваивается описанное выше назначение.

Класс Queue – очередь - наследник класса Spisok. Этот класс может использовать все функции предка применительно к своим свойствам, но очередь все же отличается от стека своим созданием и добавлением элементов, поэтому функция добавления элементов в этом классе переопределяется еще раз, уже для очереди.

Класс TLine – линия. Это основной графический примитив программы. Остальные объекты строятся из линий. Линия передается в качестве информационного поля в классы списков. Линия имеет несколько свойств:

p1, p2 – точки, каждая из которых имеет 2 координаты: x и y. Это конечные точки линии (отрезка). Точка описывается отдельной структурой point.

Color – цвет линии. Используется стандартный тип C++ Builder – TColor.

Secondary – логическая переменная, показывающая, является ли данная линия вспомогательной для построения объекта, либо она основная. Для более наглядного представления способа построения объектов в программе используются вспомогательные линии, которые при желании пользователь может отключать.

Методы класса TLine:

setline(point p1,point p2,long int col,bool sec). Устанавливает значения свойств линии в соответствии с переданными параметрами.

point cut(float k). Возвращает точку на линии, которая находится на расстоянии, равном k*<длина линии> от ее первого конца.

Класс BCurve – Кривая Безье. Среди свойств объекта: имя, цвет основных и вспомогательных линий, 2 опорные линии и коэффициент гладкости k (чем больше коэффициент, тем больше линия похожа на ломаную. Максимум k=0.99, минимум – 0.01. Оптимальное значение k=0.25). Класс имеет 2 функции:

queue <Tline> Create(float,Tline,Tline,TColor,TColor,bool,AnsiString). Возвращает список линий, принадлежащих созданной по переданным параметрам кривой Безье.

queue <Tline> Load().Возвращает список линий, принадлежащих созданной по заранее установленным параметрам кривой Безье.

Класс TRectangle – Прямоугольник. Создает список из 4-х линий по переданным параметрам с помощью функции: queue <Tline> Create(int x1,int y1,int x2,int y2,TColor col).




2.4 Абстрактные типы данных, определенные в программе



АТД  тип данных, определяемый только через операции, которые могут выполняться над соответствующими объектами безотносительно к способу представления этих объектов.



2.4.1 ADT Spisok

Данные 

Указатель на вершину списка элементов и на текущий элемент;

Структура, описывающая список элементов;

Операции

Add:

Вход: значение, имя;

Предусловие: нет;

Процесс: добавление элемента в список;

Выход: нет;

Постусловия: нет;

Remove:

Вход: порядковый номер;

Предусловие: нет;

Процесс: удаление элемента из списка;

Выход: нет;

Постусловия: нет;

Search:

Вход: имя;

Предусловие: нет;

Процесс: поиск элемента в списке;

Выход: порядковый номер найденного элемента;

Постусловия: нет;

Change:

Вход: порядковый номер, значение;

Предусловие: нет;

Процесс: изменение выбранного элемента на элемент с переданным значением;

Выход: нет;

Постусловия: нет;

Count:

Вход: нет;

Предусловие: нет;

Процесс: подсчет количества элементов в списке;

Выход: количество элементов в списке;

Постусловия: нет;

Getvalue:

Вход: порядковый номер;

Предусловие: нет;

Процесс: получение информационного поля элемента;

Выход: информационное поле элемента;

Постусловия: нет;

Getname:

Вход: порядковый номер;

Предусловие: нет;

Процесс: получение имени элемента;

Выход: имя элемента;

Постусловия: нет;

Конец ADT Spisok



2.4.2 ADT Tline

Данные 

2 конечные точки, цвет, тип линии;

Операции

Setline:

Вход: 2 конечные точки, цвет, тип линии;

Предусловие: нет;

Процесс: установка данных объекта;

Выход: нет;

Постусловия: нет;

Cut:

Вход: коэффициент k;

Предусловие: нет;

Процесс: вычисление точки на линии, которая находится на расстоянии, равном k*<длина линии> от ее первого конца;

Выход: точка на линии, которая находится на расстоянии, равном k*<длина линии> от ее первого конца;

Постусловия: нет;

Конец ADT TLine



2.4.3 ADT BCurve

Данные 

Цвет вспомогательных и основных линий, 2 базовые линии, коэффициент, имя;

Операции

Create:

Вход: Цвет вспомогательных и основных линий, 2 базовые линии, коэффициент, имя;

Предусловие: нет;

Процесс: создание кривой Безье;

Выход: Список линий, принадлежащих данной кривой;

Постусловия: нет;

Load:

Вход: нет;

Предусловие: нет;

Процесс: создание кривой Безье на основе уже имеющихся в классе данных;

Выход: Список линий, принадлежащих данной кривой;

Постусловия: нет;

Конец ADT BCurve



2.4.4 ADT TRectangle

Данные 

нет;

Операции

Create:

Вход: Цвет 4 координаты и цвет;

Предусловие: нет;

Процесс: создание прямоугольника;

Выход: Список линий, принадлежащих данному прямоугольнику;

Постусловия: нет;

Конец ADT TRectangle


ТЕХНОЛОГИЧЕСКАЯ ЧАСТЬ



		Руководство программиста



		Назначение и условия применения программы

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



		Минимальные системные требования: 

64 Мб оперативной памяти.

100 Кб свободного места на жёстком диске

Клавиатура и манипулятор мышь

Операционная система Windows 9x/ME/NT/2000/XP



		Установка программы

Чтобы установить программу, нужно целиком скопировать на целевой компьютер *.exe файл программы.

Запустить файл Editor.exe.



		Структура программы.

Алгоритм программы

При запуске программы выполняются действия:

Выбор объекта с помощью клавиатуры или с помощью мыши.

Указание места расположения объекта на плоскости рисунка с помощью мыши (2 или 3 клика).

Работа с объектами: их выделение с помощью ListBox-элемента и изменение их параметров или удаление объектов или их частей.

Окончание программы происходит при закрытии окна.

Создание объектов

После того, как указано место расположения объекта, происходит его создание. Каждый объект представляет собой список линий, поэтому, для создания любого объекта программа создает новый экземпляр класса очереди (Queue), если он не был создан до этого, и добавляет в него полученный из функции Create(<параметры объекта>) соответствующего объекта список линий. Для того чтобы предоставить пользователю возможность работы с полученным списком (а значит и объектом), этот список заносится в ListBox-элемент на форме, где пользователь сможет получить к нему доступ.

Изменение объектов и их частей

Для изменения объектов используется функция класса списков Change(int, Data). При выборе пользователем элемента ListBox’а (отдельной линии-части объекта), в эту функцию передается порядковый номер выбранной линии и новые ее параметры, установленные пользователем.

Удаление объекта или его части

Для удаления объектов необходимо удалить из списка соответствующие им элементы. Это осуществляется при помощи функции класса списков Remove(int). В функцию передается порядковый номер выбранной линии.



		Тестирование программы

Для выполнения тестирования программы следует произвести следующие действия:

Запустить файл “Editor.exe”.

Выбрать объект 

Установить его параметры с помощью ComboBox-элементов

Установить положение объекта на плоскости путем 2-х или 3-х кликов мышкой на белой области формы

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

В ListBox’е «Все линии» выбрать различные линии. Они будут выделяться на объекте цветом выделения, который также можно интерактивно изменить

При щелчке на объекте в списке «Объекты» будет выделена первая линия выделенного объекта в списке вверху

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

Закрыть окно для выхода из программы



Руководство оператора



В данной главе приводится описание действий оператора (пользователя) для достижения нужных результатов.



Запуск программы

Чтобы запустить программу, нужно из папки с программой открыть файл «Editor.exe».

При запуске программы перед Вами находиться следующее окно:






Рис. 1. Вид главного окна приложения



Создание объекта

Выбрать объект 

Установить его параметры с помощью ComboBox-элементов

Установить положение объекта на плоскости путем 2-х или 3-х кликов мышкой на белой области формы

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



Выделение и удаление объектов

В ListBox’е «Все линии» выбрать различные линии. Они будут выделяться на объекте цветом выделения, который также можно интерактивно изменить

При щелчке на объекте в списке «Объекты» будет выделена первая линия выделенного объекта в списке вверху

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

Изменение объекта

Для изменения параметров объекта необходимо выделить его в списке объектов и установить новые значения цветов с помощью ComboBox-элементов.



	Завершение программы

Чтобы выйти из программы, нужно нажать на кнопку с изображением крестика в правом верхнем углу окна.



3.3 Сообщения оператору



Вся работа со списком объектов отображается на экране. При добавлении линии или объекта, он появляется на экране, при удалении – исчезает оттуда, при выделении – меняет цвет на цвет выделения.




СПИСОК ЛИТЕРАТУРЫ



	Дейтел Х., Дейтел П. Как программировать на С++: пер. с англ. – М.: «Издательство Бином», 2003 г.

	Кондратьева С.Д. Введение в структуры данных: лекции и упражнения по курсу. – М.: Издательство МГТУ им. Н. Э. Баумана, 2000 г.

	Стивенс Р. Delphi. Готовые алгоритмы: Пер. с англ. – М.: Издательство ДМК Пресс, 2001.–384с.

	Рейсдорф Кент и Хендерсон Кен Borland C++ Builder. Освой самостоятельно: [Электронный ресурс].




ПРИЛОЖЕНИЕ



//---------------------------------------------------------------------------

#include <vcl.h>

#pragma hdrstop

#include <stdio.h>

#include "Unit1.h"

//---------------------------------------------------------------------------

#pragma package(smart_init)

#pragma resource "*.dfm"

TfrmMain *frmMain;

//==========================================

// CLASSES FOR WORK WITH LISTS. IT-41 2007

//==========================================

//*****Structures*****

struct point {

int x,y;

};//end struct

//==========================================

//1. Abstract class Spisok

//==========================================

template <class Data> class spisok {

protected:

struct list {

Data inf;

AnsiString name;

list*next;

};//end struct list



list *top,*p;

public:

virtual void add(Data value, AnsiString name)=0;

virtual void remove(int index)=0;

virtual void change(int index, Data value)=0;

virtual int count()=0;

virtual Data getvalue(int index)=0;

virtual AnsiString getname(int index)=0;

virtual int search (AnsiString name)=0;

};//end class spisok

//==========================================

//2. CLASS STACK

//==========================================

template <class Data> class stack: public spisok <Data>{

public:

//***************CONSTRUCTORS************************

stack(){top=new list;top=NULL;}

~stack(){}

//***************OPERATIONS************************

int count(){

int i=0;

p=top;

while (p!=NULL){

i++;

 p=p->next;

}//end while

return(i);

}//end stack count



void add(Data value, AnsiString name){

p=new list;

p->next=top;

p->inf=value;

p->name=name;

top=p;

}//end stack add



int search (AnsiString name){

int i=0;

p=top;

while (p!=NULL){

i++;

 if (p->name==name) return(i);

}//end while

return(0);

}//end function



void remove(int index){

list*q;

p=top;

for (int i=1;i<index-1;i++) p=p->next;

q=p->next;

if (q==NULL) delete(q); else {p->next=p->next->next;delete(q);}

}//end stack remove



void change(int index, Data value){

p=top;

for (int i=1;i<index;i++) p=p->next;

p->inf=value;

}//end stack change



Data getvalue(int index){

if (index<=this->count()){

p=top;

for (int i=1;i<index;i++) p=p->next;

return(p->inf);

}//end if

}//end function



AnsiString getname(int index){

p=top;

for (int i=1;i<index;i++) p=p->next;

return(p->name);

}//end function



void clear(){



}//end function

};//end class stack

//==========================================

//3. CLASS QUEUE

//==========================================

template <class Data> class queue: public stack <Data> {

public:

 queue(){top=new list;top->next=NULL;p=top;}

 ~queue(){}

 void add(Data value, AnsiString name){

 p->next=new list;

 p->next->next=NULL;

 p->inf=value;

 p->name=name;

 p=p->next;

 }//end function



 int count(){

 int i=0;

 p=top;

while (p->next!=NULL){

i++;

 p=p->next;

}//end while

 return(i);

}//end queue count

};//end queue class

//==========================================

//4. CLASS LINE

//==========================================

class Tline {

public:

point p1,p2;

TColor color;

bool secondary;

Tline(){color=0;secondary=0;}

~Tline(){}

void setline(point p1,point p2,long int col,bool sec);

point cut(float k);

};//end line class

//------------------------------------------

point Tline::cut(float k){

point p;

p.x=p1.x+k*(p2.x-p1.x);

p.y=p1.y+k*(p2.y-p1.y);

return(p);

}//end function



void Tline::setline(point Point1,point Point2,long int col,bool sec){

p1.x=Point1.x;p1.y=Point1.y;

p2.x=Point2.x;p2.y=Point2.y;

color=col;secondary=sec;

}//end function

//==========================================

//5. CLASS Bezie Curve

//==========================================

class BCurve {

protected:

bool show_secondary;

public:

TColor color;

AnsiString Name;

TColor scol;

float k;

Tline l1,l2;

BCurve(){}

queue <Tline> Create(float,Tline,Tline,TColor,TColor,bool,AnsiString);

queue <Tline> Load();

};//end BCurve Class



queue <Tline> BCurve::Create(float koef,Tline line1,Tline line2,TColor col, TColor colsec, bool sec, AnsiString NameOfCurve)

{

queue <Tline> L;

point p1,p2;

Tline l;

k=koef; l1=line1,l2=line2;color=col;show_secondary=sec;scol=colsec;

l1.secondary=true;l2.secondary=true;l1.color=colsec;l2.color=colsec;Name=NameOfCurve;

if (show_secondary) {L.add(l1,Name);L.add(l2,Name);}

while (!(l.p1.x==l.p2.x && l.p1.y==l.p2.y)){

 p1=l1.cut(k);p2=l2.cut(k);

 l.setline(p1,p2,colsec,1);

 if (show_secondary) L.add(l,Name);

 l2.p1=p2;p2=l.cut(k);p1=l1.p1;

 l.setline(p1,p2,color,0);L.add(l,Name);

 l1.p1=p2;l1.p2=l2.p1;

}//end while

return (L);

}//end function



queue <Tline> BCurve::Load(){

return(this->Create(k,l1,l2,color,scol,show_secondary,Name));

}//end function



class TRectangle {

public:

queue <Tline> Create(int x1,int y1,int x2,int y2,TColor col);

};//end rectangle class



queue <Tline> TRectangle::Create(int x1,int y1,int x2,int y2,TColor col){

 queue <Tline> Lines;

 Tline l1;

 l1.p1.x=x1;l1.p1.y=y1;l1.p2.x=x2;l1.p2.y=y1;l1.color=col;l1.secondary=false;

 Lines.add(l1,"Rectangle");

 l1.p1.x=x2;l1.p1.y=y1;l1.p2.x=x2;l1.p2.y=y2;l1.color=col;l1.secondary=false;

 Lines.add(l1,"Rectangle");

 l1.p1.x=x2;l1.p1.y=y2;l1.p2.x=x1;l1.p2.y=y2;l1.color=col;l1.secondary=false;

 Lines.add(l1,"Rectangle");

 l1.p1.x=x1;l1.p1.y=y2;l1.p2.x=x1;l1.p2.y=y1;l1.color=col;l1.secondary=false;

 Lines.add(l1,"Rectangle");

 return (Lines);

}//end function



//=========

//Переменные

queue <Tline> LineBufer;

int n=0;

Tline l1,l2;

queue <int> Objects;

//=========

//---------------------------------------------------------------------------

__fastcall TfrmMain::TfrmMain(TComponent* Owner)

 : TForm(Owner)

{

}

//---------------------------------------------------------------------------

void LoadLines(bool sec){

Tline l1;

int checkedItem=frmMain->ListBox1->ItemIndex;

frmMain->ListBox1->Clear();

frmMain->lstObjects->Clear();

 for (int i=1;i<=LineBufer.count();i++){

 l1=LineBufer.getvalue(i);

 frmMain->lblPicture->Canvas->Pen->Color=l1.color;

 if ((sec && l1.secondary)||!l1.secondary){

 if (l1.secondary) frmMain->lblPicture->Canvas->Pen->Style=2; else frmMain->lblPicture->Canvas->Pen->Style=0;

 frmMain->lblPicture->Canvas->MoveTo(l1.p1.x,l1.p1.y);

 frmMain->lblPicture->Canvas->LineTo(l1.p2.x,l1.p2.y);

 }//end if

frmMain->ListBox1->Items->Add(IntToStr(l1.p1.x)+";"+IntToStr(l1.p1.y)+" - "+IntToStr(l1.p2.x)+";"+IntToStr(l1.p2.y));

}//next i

frmMain->ListBox1->ItemIndex=checkedItem;

for (int i=1;i<=Objects.count();i++){

 if (Objects.getvalue(i)==1)frmMain->lstObjects->Items->Add("Line (1 lines)"); else

 if (Objects.getvalue(i)==4)frmMain->lstObjects->Items->Add("Rectangle (4 lines)"); else

 frmMain->lstObjects->Items->Add("Bezie Curve ("+IntToStr(Objects.getvalue(i))+" lines)");

}//next i

}//end function

//---------------------------------------------------------------------------



void __fastcall TfrmMain::lblPictureMouseDown(TObject *Sender,

 TMouseButton Button, TShiftState Shift, int X, int Y)

{

if (cboObject->Text=="Кривая Безье"){

n++;

if (n==1) {l1.p1.x=X;l1.p1.y=Y;}

if (n==2) {l1.p2.x=X;l1.p2.y=Y;l2.p1.x=X;l2.p1.y=Y;}

if (n==3) {

BCurve CurveBufer;

queue <Tline> Lines;

int firstNumber=0;

l2.p2.x=X;l2.p2.y=Y;

Lines=CurveBufer.Create(0.25,l1,l2,clbColor->Selected,clbSecond->Selected,1,"Bezie");

n=0;

firstNumber=LineBufer.count();

for (int i=0;i<=Lines.count();i++) LineBufer.add(Lines.getvalue(i),"Bezie");

LoadLines(chkSecondary->Checked);

firstNumber=LineBufer.count()-firstNumber;

Objects.add(firstNumber,"Bezie");

lstObjects->Items->Add("Bezie Curve ("+IntToStr(firstNumber)+" lines)");

}//end if n==3

}//end if Curve



if (cboObject->Text=="Линия"){

n++;

frmMain->Canvas->Pen->Color=clbColor->Selected;

if (n==1) {l1.p1.x=X;l1.p1.y=Y;}

if (n==2) {

l1.p2.x=X;l1.p2.y=Y;

LineBufer.add(l1,"");

Objects.add(1,"Line");

LoadLines(chkSecondary->Checked);

n=0;

}//end if n==2

}//End if Line



if (cboObject->Text=="Прямоугольник"){

n++;

queue <Tline> Lines;

TRectangle Rect;

if (n==1) {l1.p1.x=X;l1.p1.y=Y;}

if (n==2) {

l1.p2.x=X;l1.p2.y=Y;

Lines=Rect.Create(l1.p1.x,l1.p1.y,l1.p2.x,l1.p2.y,clbColor->Selected);

for (int i=0;i<=Lines.count();i++) LineBufer.add(Lines.getvalue(i),"");

Objects.add(4,"Rectangle");

LoadLines(chkSecondary->Checked);

n=0;

}//end if n==2;

}//end if rectangle;

}

//---------------------------------------------------------------------------

void __fastcall TfrmMain::chkSecondaryClick(TObject *Sender)

{

frmMain->lblPicture->Refresh();

LoadLines(chkSecondary->Checked);

}

//---------------------------------------------------------------------------

void __fastcall TfrmMain::clbColorChange(TObject *Sender)

{

Tline l1;

int begin=0;

for (int i=0;i<lstObjects->ItemIndex;i++)begin+=Objects.getvalue(i);

for (int i=begin;i<=begin+Objects.getvalue(lstObjects->ItemIndex+1);i++){

 l1=LineBufer.getvalue(i);

 if (!l1.secondary){

 l1.color=clbColor->Selected;

 LineBufer.change(i,l1);

 }//end if

}//next i

LoadLines(chkSecondary->Checked);

}

//---------------------------------------------------------------------------

void __fastcall TfrmMain::clbSecondChange(TObject *Sender)

{

Tline l1;

int begin=0;

for (int i=0;i<lstObjects->ItemIndex;i++)begin+=Objects.getvalue(i);

for (int i=begin;i<=begin+Objects.getvalue(lstObjects->ItemIndex+1);i++){

 l1=LineBufer.getvalue(i);

 if (l1.secondary){

 l1.color=clbSecond->Selected;

 LineBufer.change(i,l1);

 }//end if

}//next i

LoadLines(chkSecondary->Checked);

}



//---------------------------------------------------------------------------

int WhichObject (int number) {

int object=0;

int i=0;

while (i<number){object++;i+=Objects.getvalue(object);}

if (object==0) object=1;

return (object);

}//end function

//---------------------------------------------------------------------------



void __fastcall TfrmMain::ListBox1Click(TObject *Sender)

{

Tline l1;

l1=LineBufer.getvalue(ListBox1->ItemIndex+1);

frmMain->lblPicture->Refresh();

LoadLines(chkSecondary->Checked);

for (int i=2;i>0;i--){

frmMain->lblPicture->Canvas->Pen->Color=clbSelect->Selected;

frmMain->lblPicture->Canvas->Ellipse(l1.p1.x-i,l1.p1.y-i,l1.p1.x+i,l1.p1.y+i);

frmMain->lblPicture->Canvas->Ellipse(l1.p2.x-i,l1.p2.y-i,l1.p2.x+i,l1.p2.y+i);

frmMain->lblPicture->Canvas->MoveTo(l1.p1.x,l1.p1.y);

frmMain->lblPicture->Canvas->LineTo(l1.p2.x,l1.p2.y);

}//next

}

//---------------------------------------------------------------------------

void __fastcall TfrmMain::ListBox1KeyDown(TObject *Sender, WORD &Key,

 TShiftState Shift)

{

if (Key==46){

int object=WhichObject(ListBox1->ItemIndex+1);

frmMain->lblPicture->Refresh();

int z=ListBox1->ItemIndex;

LineBufer.remove(ListBox1->ItemIndex+1);ListBox1->Items->Delete(ListBox1->ItemIndex);

ListBox1->ItemIndex=z;

Objects.change(object,Objects.getvalue(object)-1);

if (Objects.getvalue(object)==0) {Objects.remove(object);lstObjects->Items->Delete(object-1);}

LoadLines(chkSecondary->Checked);

}//end if

}

//---------------------------------------------------------------------------



void __fastcall TfrmMain::lstObjectsClick(TObject *Sender)

{

int begin=0;

for (int i=0;i<lstObjects->ItemIndex;i++)begin+=Objects.getvalue(i);

ListBox1->ItemIndex=begin;

}

//---------------------------------------------------------------------------



void __fastcall TfrmMain::lblPictureMouseMove(TObject *Sender,

 TShiftState Shift, int X, int Y)

{

lblCoords->Caption=IntToStr(X)+"; "+IntToStr(Y);

}

//---------------------------------------------------------------------------