Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
ИПОВС (2002) / ol / ol / Пояснительная записка_oll.doc
Скачиваний:
28
Добавлен:
16.04.2013
Размер:
3.64 Mб
Скачать

1.4.4 Разработка программы

Разработанные алгоритмы, приведенные в техническом проекте, реализовывались модулями программы. Модули создавались в среде BorlandDelphi5 [1]. Взаимодействие модулей программы рассмотрено на рис. 1.4.1.2. Ниже некоторые модули описаны подробнее.

Алгоритм ввода, сохранения и изменения информации, а также выдача информации по конкретному узлу генеалогического дерева реализован модулем info1.

1. Модуль info1 – это модуль информации по конкретным узлам.

Переменные, объявленные в модуле:

  • FUpdating– идентификатор выбора стиля текста;

  • miMinInfoCounter– идентификатор минимума вводимой информации;

  • MotherChanged, FatherChanged, HusChanged, ChiChanged – идентификаторы нажатых кнопок;

  • UrlCommaCounter– идентификатор ввода информации.

Процедуры и функции модуля (кроме процедур обработки нажатий кнопок):

  • procedure ClearAll – очищает все поля формы fmMainInfo;

  • procedure SaveInfo(Id: integer)– сохраняет информацию о персоне в массиве персон;

  • function LoadFromArFoto(id: integer; name: string):string– загружает фото для просмотра, в соответствии с информацией из массиваArFoto;

  • function LoadFromArVideo(id: integer; name: string):string – аналогично для видео;

  • function LoadFromArAudio(id: integer; name: string):string – аналогично для аудио;

  • procedure AddName(var list: TListBox;var KolMedia: integer; Name,path: string;var mas: array of TMedia) – сохраняет информацию в медиа массивы;

  • procedure FindAllMedia - находит все медиа файлы, относящиеся к персоне;

  • procedure httpConnect(Sender: TObject)– производит запуск Интернет-броузера;

  • procedure changepic(path:string) – «подгоняет» фото под размеры окна;

  • procedure ConvertData(data: string; live: integer) – инвертирует данные о дате в нужный формат.

  1. Модуль Pr1– модуль визуализации дерева. Также в этом модуле организована работа с мышью и масштабирование дерева.

Переменные, объявленные в модуле:

  • Width1, Height1– высота и ширина рисунка генеалогического дерева;

  • Kol_u– количество поколений в родословной;

  • sum: array [0..100] of integer– одномерный массив, в котором индекс соответствует номеру поколения, а элемент – это количество людей в этом поколении.

  • u_max, u_min – максимальный и минимальный номер поколения. Той персоне, с которой начали строить родословную присваивается нулевое поколение, следующему поколению на единицу больше. Соответственно меньшие поколения на единицу меньше, то есть они будут с отрицательным знаком, напр., -1, -2.

  • kx, kyкоэффициенты сжатия по оси Х иY.

  • SomeWife - идентификатор принимает значенияtrue(у персоны один супруг) иfalse(у персоны есть не один заключенный брак или дети вне брака).

Процедуры и функции модуля (кроме процедур обработки нажатий кнопок):

В алгоритм рисования дерева входят две основные процедуры CreateMas и DrawTree, в них еще несколько подпроцедур.

Процедура CreateMas: сначала устанавливаются идентификаторыkey иSomeWife. Второй идентификатор принимает значенияtrue(у персоны один супруг) иfalse(у персоны есть не один заключенный брак или дети вне брака).В начале работы алгоритма этому идентификатору присваивается значениеtrue. Далее вызывается функцияmax_z, которая подсчитывает общее количество поколений в родословной. Результат этой функции присваивается переменнойKol_u.Следующая процедураCreateArpok создает двумерный массив из одномерного массиваPersonAr. В получившемся массиве элементами одной строки являются люди одного поколения. Сортировка массива осуществляется процедуройSortArpok. Муж и жена в одной строке расположены рядом. ПроцедураFormXYформирует координаты узлов генеалогического дерева. Размеры рисунка дерева рассчитываются процедуройSizePanel. Для того, чтобы дерево находилось не в одной части экрана, если его размеры меньше размеров экрана монитора, его координаты корректируются таким образом, чтобы оно располагалось посередине. После проведенных действий массивpArpokсформирован должным образом.

Функция max_z: рассчитывает общее количество поколений в родословной. Здесь использован простой алгоритм нахождения максимума и минимума, когда на первом этапе за минимум берется заведомо большое числоmin1:= 1000, за максимум соответственно – маленькоеmax1:= -1000. Поиск минимума: первый элементPersonAr[k].pok сравнивается сmin1. Если он меньше, то он становитсяmin1, далее сравниваются остальные элементы. В итоге значениеmin1и есть меньшее поколение. Максимум находится аналогично. Общее количество поколений в родословнойmax_zесть разностьmax1и min1. Переменнымu_min присваивается значение меньшего поколения, переменнойu_max– значение старшего поколения.

Процедура CreateArpok:создает двумерный массивpArpokиз одномерного массиваPersonAr таким образом, чтобы в каждой строке массиваpArpokнаходились люди одного поколения. В начале формируется одномерный массивsum: array [0..100] of integer.В нем индексу соответствует номер поколения, а значению элемента массива с этим индексом соответствует количество людей в этом поколении. Далее в цикле поj(номер поколения) сначала для нулевого поколения заполняем нулевую строку массиваpArpok.Каждый элемент массиваPersonAr[k].pokсравнивается с номером поколенияj(сейчас равен 0). Те элементы, которые соответствуют этому поколению, заносятся наj-ую строку массиваpArpok.Одновременно с этим подсчитывается количество элементов на этой строке, если оно превосходит соответствующий этому поколению элемент массиваsum,то переходим к заполнению следующей строке-поколению.

procedure TfmTree.CreateArpok();

var s, i, j,k: integer;

begin

for j:=u_min to u_max do

begin

s:=0;

for i:=1 to Kol-1 do

if PersonAr[i].pok=j then формирование одномерного

begin массива sum

s:=s+1;

end;

sum[j-u_min]:=s;

end;

for j:=0 to Kol_U do

begin

s:=0;

for k:=1 to Kol do

begin заполнение

if PersonAr[k].pok=j+u_min then массива pArpok

begin

if (PersonAr[k].Fam<>'') or (PersonAr[k].Id<>0) then

begin

pArpok[j,s]:= PersonAr[k];

s:=s+1;

end;

if s=sum[j] then break;

end;

end;

end;

Процедура SortArpok:сортирует массив pArpokтак, чтобы супруги в одном поколении размещались рядом. В этой процедуре так же используется массивsum, упоминавшийся в предыдущей процедуре. Проходимся по строкам массиваpArpok.Сначала первый элемент запоминаем, какP, следующий, какP1. Если супругP-го элемента естьP1, то ставим их вместе. (Перемещение элемента осуществляет процедураChange(lvl,p1,p2: integer)).Если нет, тоP1 присваиваем значение следующего элемента и сравниваем снова. Достигнут конец строки, тогдаPприсваивается значение второго элемента, если замены не произошло и третьего элемента, если произошла замена, и продолжается сравнение.

Procedure SortArpok();

var j,i,m,a: integer;

P,P1: TPerson;

begin

for j:=0 to Kol_u do

begin

m:=0;

while m<sum[j] do

begin

P:=pArpok[j,m];

a:=0;

for i:=m+1 to sum[j]-1 do

begin

P1:=pArpok[j,i];

if P1.Husbend=p.Id then

begin

Change(j,m+1,i);

a:=a+1;

break;

end;

end;

if a>0 then m:=m+2

else m:=m+1;

end;

end;

end;

Procedure Change(lvl,p1,p2: integer);

var buf: TPerson;

begin

buf:=pArpok[lvl,p1];

pArpok[lvl,p1]:=pArpok[lvl,p2];

pArpok[lvl,p2]:=buf;

end;

На вход процедуры Change(lvl,p1,p2: integer) подается номер уровня lvl,расположение элемента на этой строкеp1 и расположение второго элементаp2, который будет ставиться рядом.

Процедура FormXY: формирует координаты узлов генеалогического дерева. Присваиваются каждому человеку координатыxиy. (Именно на месте этих координат будет отображен данный человек.) Заметим, что ближайшие люди находятся на расстоянии 200 пикселей по осиXи 90 пикселей по осиY. В этой же процедуре происходит выравнивание общего вида дерева.

Процедура DrawTree: осуществляет процесс визуализации генеалогического дерева. В начале заливается цветом фона прямоугольник размером с рисунок дерева, который рассчитывался ранее. На этом фоне рисуются узлы дерева кружочками (персона женского пола) или квадратиками (персона мужского пола). Для этого проходим по всем элементам массива данных и сравниваем поле записи элементаpArpok[j,i].pol со значением «жен» и «муж». Чтобы нарисовать линию, связывающую двух супругов, выполняются два цикла. Проходимся по строкам массиваpArpok, запоминаем идентификатор супруга рассматриваемой персоны. Затем ищем супруга в данной строке и запоминаем индекс этого элемента. Теперь, узнав индексы требуемых элементов, рисуем соединяющую их линию при помощи процедурыLinkOneLayer(xn,y,xk: integer).Так проверяем каждый элемент. Если найденный супруг персоны уже проверялся, то проверяем следующие элементы.

for j:=0 to Kol_U do

begin

for i:=0 to sum[j]-1 do

begin

d:=pArpok[j,i].Husbend;

if PersonAr[d].pok <> pArpok[j,i].pok then goto l;

if ((d=0) or (d= pArpok[j,i-1].Id)) then goto l;

for k:=0 to sum[j]-1 do

if (pArpok[j,k].Id = d) then d1:= k;

LinkOneLayer(pArpok[j,i].xp, pArpok[j,i].yp,pArpok[j,d1].xp);

l: d:= -1;

end;

end;

Рисование линии-связи «родители-ребенок» осуществляется похожим образом, что и линия, связывающая супругов. Только здесь следует учитывать, что детей может быть несколько и ребенок имеет указатель на следующего ребенка. Рисование происходит с помощью процедуры LinkTwoLayer(xn,y, xk, xsb,yk: integer) .

for j:=1 to Kol_U do

begin

for i:=0 to sum[j]-1 do

begin

d:=pArpok[j,i].Husbend;

if ((d=0) or (d= pArpok[j,i-1].Id)) then goto m1;

for k:=0 to sum[j]-1 do

if (pArpok[j,k].Id = d) then d1:= k;

d2:= pArpok[j,i].Children;

if d2=0 then goto m1;

if d2<> PersonAr[d].Children then goto m1;

for k:=0 to sum[j-1]-1 do

if (pArpok[j-1,k].Id = d2) then d3:= k;

LinkTwoLayer(pArpok[j,i].xp, pArpok[j,i].yp,pArpok[j,d1].xp, pArpok[j-1,d3].xp, pArpok[j-1,d3].yp);

d4:= pArpok[j-1,d3]. Sist_Broth;

while d4<>0 do

begin

for k:=0 to sum[j-1]-1 do

if (pArpok[j-1,k].Id = d4) then d3:= k;

LinkTwoLayer(pArpok[j,i].xp, pArpok[j,i].yp,pArpok[j,d1].xp, pArpok[j-1,d3].xp, pArpok[j-1,d3].yp);

d4:= pArpok[j-1,d3]. Sist_Broth;

end;

m1: d:= -1;

end;

end;

В этой процедуре необходимо охватить все связи между людьми, например, разное количество браков или внебрачные дети. Для этого есть идентификатор SomeWife, принимает значениеfalseв этом случае. Тогда, когда вызывается процедураLinkOneLayer(xn,y,xk: integer)происходит проверка на это идентификатор. В рассматриваемом случае эта линия будет рисоваться ниже и пунктиром.

Если известен только один родитель ребенка, то это тоже учитывается, при этом используется процедура Link(xn,yn, xk,yk: integer).Если супруги находятся на разных поколениях, то рисование линии, связывающей их, осуществляет процедураWrongLink(xn,yn, xk,yk: integer).

for i:=0 to Kol do

begin

m:= PersonAr[i].MotherId;

f:= PersonAr[i].FatherId;

if (((PersonAr[i].MotherId <> 0) and (PersonAr[i].FatherId = 0)) or ((PersonAr[i].MotherId = 0) and (PersonAr[i].FatherId <> 0))) then

begin

if PersonAr[i].MotherId <> 0 then Link(PersonAr[m].xp, PersonAr[m].yp,PersonAr[i].xp,PersonAr[i].yp)

else Link(PersonAr[f].xp, PersonAr[f].yp,PersonAr[i].xp,PersonAr[i].yp);

end;

end;

for i:=0 to Kol do

begin

h:= PersonAr[i].husbend;

if ((PersonAr[i].pok <> PersonAr[h].pok) and (h<>0)) then WrongLink(PersonAr[i].xp, PersonAr[i].yp, PersonAr[h].xp, PersonAr[h].yp);

end;

Процедура Image1MouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer): при движении мышки по узлу дерева данная процедура обеспечивает высвечивание подсказки с ФИО персоны этого узла. Сравниваются координаты мышки и узла дерева.

Процедура Image1MouseDown(Sender:TObject;Button:TMouseButton;

Shift:TShiftState; X, Y: Integer): при нажатии мышки на узел дерева появляется форма «Информация о конкретном узле дерева». Сама процедура аналогичнаImage1MouseMove.

Процедура N16Click: обеспечивает уменьшение размеров дерева до размеров экрана монитора. Рассчитываются коэффициенты сжатия по оси Х иY,kxиky.

kx:= fmTree.Width/Image1.Width;

ky:= (fmTree.Height-70)/Image1.Height;

Изменяются координаты всех дерева путем умножения на коэффициенты имееющихся координат.

Процедура N17Click: возвращает реальный размер дерева.

ПроцедурыPointM (x,y:integer;Image1:TImage;l:integer) и PointF(x,y:integer;Image1:TImage; l: integer): рисуют узлы дерева, кружочек – это женщина, квадратик – мужчина.

  1. Модуль SelFam – этот модуль реализует алгоритм выделения отдельной ветви дерева, описанный ранее в техническом проекте.

Этот алгоритм основан на рекурсивной процедуре Potomok(Id, pos).В качестве входных параметров в процедуреPotomok(Id,pos)номерId– тот, чьих потомков ищем,Pos– индекс в массивеMas – место, куда записывается очередной найденный потомок. Цель процедуры сформировать массивMas,в котором будут находиться только те, кто является потомком выбранного человека. На первое место массиваMasзаносится тот самый выбранный человек. Если у человека нет детей и сестер/братьев, то выходим из алгоритма.

Если есть сестры/братья, то проверяем одни ли у них родители. Родители одни – записываем найденного человека в массив Mas. После этого вызываем рекурсивно процедуруPotomok(Id,pos)уже для найденного человека. Так будет продолжаться, пока у найденных сестер/братьев будут находиться дети или их сестры /братья. Если таковых нет, то в массив заносится ребенок выбранного нами человека и вызывается процедура уже для него. Таким образом, в массивеMasокажутся все потомки выбранного пользователем человека. Можно рисовать. Но в рисовании есть тоже некоторые особенности, которые выполняет процедураDrawBranch.

function Potomok(id:integer; var pos:integer):boolean;

label l;

begin

if ((mas[pos].Children=0) and (mas[pos].Sist_Broth=0)) then

begin

roma:=true;

exit;

end;

while mas[pos].Sist_Broth<>0 do

begin

//if (((mas[pos].Husbend <> PersonAr[mas[pos].Sist_Broth].MotherId) and (mas[pos].Husbend = PersonAr[mas[pos].Sist_Broth].FatherId)) or ((mas[pos].Husbend = PersonAr[mas[pos].Sist_Broth].MotherId) and (mas[pos].Husbend <> PersonAr[mas[pos].Sist_Broth].FatherId)) or (mas[pos].Husbend=0)) then goto l;

if (((mas[pos].MotherId <> PersonAr[mas[pos].Sist_Broth].MotherId) and (mas[pos].FatherId = PersonAr[mas[pos].Sist_Broth].FatherId)) or ((mas[pos].MotherId = PersonAr[mas[pos].Sist_Broth].MotherId) and (mas[pos].FatherId <> PersonAr[mas[pos].Sist_Broth].FatherId)) {or (mas[pos].Husbend=0}) then goto l;

pos:=pos+1;

mas[pos]:=PersonAr[mas[pos-1].Sist_Broth];

Potomok(mas[pos].id,pos);

end;

l: pos:=pos+1;

mas[pos]:=PersonAr[PersonAr[id].Children];

Potomok(mas[pos].Id,pos);

end;

Процедура DrawBranch: осуществляет рисование ветви дерева в соответствии с массивомMas. Процедура выполняется аналогично процедуреDrawTree.

  1. Модуль Combine– модуль объединения деревьев. Модуль реализует алгоритм объединения деревьев, описанный в техническом проекте.

Главной процедурой этого модуля является процедура ReadFromFile (fname: string).На начальном этапе дерево, с которым мы работаем, находится в массивеPersonAr. В массивPersonAr1считываем дерево, с которым будем объединять. Сравниваем два массива на предмет общих людей. Присваиваем флажкуIdединичку, если общие люди есть. Затем делаем проверку на этот флажок, если не единица, то показываем формуfmSugestс предупреждением «В деревьях нет общих людей». Затем предлагается выбрать другое для объединения дерево или выйти из задачи объединения.

  1. Модуль files – это модуль, где описаны функции работы с файлами.

  2. Модуль prgenealogia_begin – это главный модуль программы.

  3. Модуль enterfam – это модуль информации по конкретным узлам.

  4. Модуль gedcom – это модуль чтения информации изGedComфайла.

  5. Модуль gedcom1 – это модуль записи информации вGedCom файл.

  6. Модуль people – это модуль выбора родственников. В нем предлагается выбрать нужного человека из предложенного списка, либо добавить нового человека. Выбрать можно супруга, мать, отца и детей. Эти действия реализуются процедурамиShowFather, ShowMother, ShowChildren, ShowHusbend. Процедуры аналогичны друг другу. Ниже приведена одна из этих процедур:

procedure TfmChoice.ShowHusbend;

var i: integer;

begin

if PersonAr[tecid].pol='жен' then

cmbPol.Text:='муж' else cmbPol.Text:='жен';

for i:=1 to Kol do

if ((PersonAr[i].Husbend=tecid) and (PersonAr[i].Id<>tecId)) then

lbPeople.Items.Add(IntToStr(PersonAr[i].id)+' '+PersonAr[i].Fam+' '+PersonAr[i].Name+' '+PersonAr[i].PatronName);

for i:=1 to Kol do

if PersonAr[i].Id<>tecId then

cmbChoice.Items.Add(IntToStr(PersonAr[i].id)+' '+PersonAr[i].Fam+' '+PersonAr[i].Name+' '+PersonAr[i].PatronName);

end;

  1. Модуль warningdel– это модуль предупреждения об удалении.

  2. Модуль name – это модуль ввода названия медиа объекта.

  3. Модуль husbend – это модуль вопроса о браке родителей.

  4. Модуль poisk – это модуль информации по конкретным узлам.

Всю информацию по модулю – см. в первой части работы.

  1. Модуль poisk1 – это модуль вывода ответа на вопрос пользователя.

Всю информацию по модулю – см. в первой части работы.

  1. Модуль statistic – это модуль статистики по текущей родословной.

Всю информацию по модулю – см. в первой части работы.

Тут вы можете оставить комментарий к выбранному абзацу или сообщить об ошибке.

Оставленные комментарии видны всем.

Соседние файлы в папке ol