Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

Практический курс математического и компьютерного моделирования. Учебно-практическое пособие

.pdf
Скачиваний:
0
Добавлен:
08.09.2026
Размер:
2 Мб
Скачать
II. Программная реализация математической модели
end; end; // if ( SHADOWED = FALSE )... // отражение (рекурсивные вызовы): if ( recursion <= depth_recursion ) then begin spec := sphere[id].get_value_spec; if ( spec > 0.0 ) then begin plus_color := trace( trace_point, reflect ); plus_color := mult_colors( plus_color, spec ); color := mix_colors( color, plus_color ); end; end; trace_point.Free; light_direction.Free; reflect.Free; end; // else if( id = numb_spheres + 1 )... result := color; end; // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - procedure delete_scene; var i: integer; begin lamp.Free; for i := 1 to numb_spheres do sphere[i].Free; end; // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - end. // конец файла traceUnit.pas
II.8.7. Головной файл
// головной файл mainUnit.pas unit mainUnit; interface uses
91
Математическое и компьютерное моделирование
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, vectorUnit, figureUnit, rayUnit, colorUnit, ComCtrls, ExtCtrls, StdCtrls, traceUnit, Menus, ExtDlgs; // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - type TmainForm = class( TForm ) Panel : TPanel; StatusBar : TStatusBar; renderButton : TButton; cameraBox1 : TGroupBox; cameraEdit_x : TEdit; cameraEdit_y : TEdit; cameraEdit_z : TEdit; Label1 : TLabel; Label2 : TLabel; Label3 : TLabel; MainMenu1 : TMainMenu; menu_file : TMenuItem; menu_exit : TMenuItem; menu_help : TMenuItem; menu_about : TMenuItem; SavePictDialog : TSavePictureDialog; save_picture : TMenuItem; procedure FormPaint( Sender: TObject ); procedure renderButtonClick( Sender: TObject ); procedure menu_exitClick(Sender: TObject); procedure menu_aboutClick(Sender: TObject); procedure save_pictureClick(Sender: TObject); procedure FormCreate(Sender: TObject); procedure FormCanResize( Sender : TObject; var NewWidth, NewHeight: Integer; var Resize : Boolean ); private { Private declarations } public { Public declarations } end;
92
II. Программная реализация математической модели
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - var mainForm : TmainForm; ImageWidth, ImageHeight : integer; bitmap : TBitmap; EmptyBMP : boolean; implementation {$R *.dfm} // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // обновление холста при перерисовке формы // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - procedure TmainForm.FormPaint( Sender: TObject ); begin canvas.Brush.Color := mainForm.Color; canvas.FillRect( rect( 0, 0, mainForm.ClientWidth, mainForm.ClientHeight ) ); ImageWidth := mainForm.ClientWidth - panel.Width - 20; ImageHeight := mainForm.ClientHeight - StatusBar.Height - 20; Canvas.Rectangle( 10, 10, ImageWidth + 10, ImageHeight + 10 ); StatusBar.SimpleText := ' '; if ( EmptyBMP = FALSE ) then Canvas.Draw( 10, 10, bitmap ); end; //==================================================== // РЕНДЕР //==================================================== procedure TmainForm.renderButtonClick( Sender: TObject ); var i, j : integer; x, y : double; ray : Tvector; ray_direction : Tvector; R_G_B : Tcvet; begin try // обработка ошибок ввода данных: begin // установка камеры: eye_position.x := StrToFloat( cameraEdit_x.Text ); eye_position.y := StrToFloat( cameraEdit_y.Text ); eye_position.z := StrToFloat( cameraEdit_z.Text ); end
93
Математическое и компьютерное моделирование
4
except on EConvertError do begin ShowMessage( 'Неверный ввод данных' + #13#10 + 'проверьте десятичную ./,' ); RenderButton.Enabled := TRUE; exit; end; end; // конец обработки ошибок ввода данных; init_scene; RenderButton.Enabled := FALSE; bitmap := TBitmap.Create; bitmap.Width := ImageWidth; bitmap.Height := ImageHeight; ray := Tvector.birth( eye_position ); for i := 10 to ImageHeight + 10 do begin y := -(i/( ImageHeight - 1 )*2 - 1 ); StatusBar.SimpleText := ' трассируется строка '+IntToStr(i) +'/'+IntToStr( ImageHeight ) ; for j := 10 to ImageWidth + 10 do begin x := (j/(ImageWidth - 1) - 0.5)*2*ImageWidth/ImageHeight; ray_direction := Tvector.birth( x, y, 3 ); ray_direction.normalization; recursion := 1; R_G_B := trace( ray, ray_direction ); ray_direction.Free; Canvas.Pixels[ j, I ] := RGB( R_G_B.R, R_G_B.G, R_G_B.B ); bitmap.Canvas.Pixels[ j - 10, I - 10 ] := RGB( R_G_B.R, R_G_B.G, R_G_B.B ); end; end; ray.Free; delete_scene; EmptyBMP := FALSE; RenderButton.Enabled := TRUE; StatusBar.SimpleText := 'конец трассировки';
9
II. Программная реализация математической модели
5
end; //==================================================== procedure TmainForm.menu_exitClick( Sender: TObject ); begin close; end; // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - procedure TmainForm.menu_aboutClick(Sender: TObject); begin ShowMessage( 'Трассировка лучей' + #13#10 + 'учебный пример' + #13#10 + 'Зенкин В.И., 2005 г.'); end; // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - procedure TmainForm.save_pictureClick( Sender: TObject ); begin if ( EmptyBMP ) then ShowMessage('нет картинки!') else if ( SavePictDialog.Execute ) then bitmap.SaveToFile( SavePictDialog.FileName ); end; // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - procedure TmainForm.FormCreate( Sender: TObject ); begin EmptyBMP := TRUE; end; // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // перерисовка картинки при изменении размера формы // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - procedure TmainForm.FormCanResize( Sender : TObject; var NewWidth, NewHeight : Integer; var Resize : Boolean ); begin if ( EmptyBMP = FALSE ) then Canvas.Draw( 10, 10, bitmap ); end; // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - end. // конец файла mainUnit.pas
9
6
()(
=
=
III. ПРИЕМЫ И МЕТОДЫ ПРОГРАММИРОВАНИЯ
Идея, примененная однажды, порождает искусственный
прием, примененная дважды, она становится методом.
Д. Пойа, Г. Сеге [36].
В этой главе описаны различные методы и приемы, помо­гающие при программировании, отладке и тестировании, не­зависимо от выбранного подхода к проектированию програм­мы. Примеры программ, за исключением проекта для демон­страции анимации, написаны для консольного режима работы.
III.1. Базовые схемы
На практике при программировании особого внимания и аккуратности требуют те участки кода, которые описывают длинные повторяющиеся действия. Опишем основные схемы для решения такого рода задач.
III.1.1. Итерации
В математике итерация — результат повторного примене­ния какой-либо математической операции. Так, если
def
),()(
1
xfxfy ==
то функции
()
=
)
...,)()(...,,)()(,)()(
xffxfxffxfxffxf
12312
nn
9
III. Приемы и методы программирования
7
=
=
=−=
называют соответственно второй, третьей, …, n-й итерациями. Переход от функции
f1(x) к f2(x), f3(x), …итерированием.
Итерации широко применяются в самых различных алгорит­мических процедурах.
Программно итерирование реализуется посредством цик­лов различных типов и состоит в том, что строится преобразо­вание которого начального элемента получен элемент
T, которое последовательно применяется, начиная с не-
x
, до тех пор, пока не будет
0
x
с требуемыми свойствами:
n
=
).(,...),(),(
xTxxTxxTx
11201
nn
Естественно, с самого начала должна быть уверенность, что такой элемент найдется за разумное число шагов и прием­лемое время.
III.1.2. Рекурсия
Рекурсия
— способ задания функции, или процедуры, при котором ее значения от некоторых аргументов выражаются через значения от других аргументов.
В программировании рекурсии соответствует ситуация, когда программа вызывает сама себя — либо непосредствен­но, либо через другие программы. Применение рекурсии ста­новится возможным, когда при анализе некоторую задачу уда­лось свести к точно
такой же подзадаче, но с другими исход-
ными данными. Рассмотрим конкретные примеры.
Пример 1. Вычисление факториала. По определению
nnn
.1!0,)!1(!
function Factorial( n: word ): LongInt; begin if ( n <= 1 ) then result := 1 else result := n*Factorial( n - 1 ); // рекурсивный вызов;
9
Математическое и компьютерное моделирование
end;
Пример 2. Обращение строки символов.
procedure Reverse; // перед вызовом про- var letter: Char; // цедуры нужно begin // ввести с консоли if ( not eoln ) then // строку символов; begin read( letter ); Reverse; // рекурсивный вызов; write( letter ); end end;
Обычно в языках программирования высокого уровня нет никаких ограничений на рекурсию, но нужно принять во вни­мание, что любой рекурсивный вызов приводит к образованию новой копии локальных объектов подпрограммы, которые ди­намически размещаются в памяти, в программном стеке, кото­рый будет тем больше, чем длиннее цепочка вызовов. Рекур­сивная форма
записи обычно выглядит изящнее и компактнее, чем итерационная, но, как правило, работает медленнее и мо­жет вызвать переполнение стека, если не принять специаль­ных мер предосторожности.
III.1.3. Проектирование цикла с помощью инварианта
Это — разновидность метода итераций, при котором связь между меняющимися в теле цикла параметрами выражается в виде неизменного условия (инварианта).
Практически необходимо:
придумать стратегию решения задачи;
четко сформулировать условие окончания цикла;
— описать взаимосвязи между всеми параметрами, изме­няющимися в ходе выполнения цикла в виде инварианта.
98
III. Приемы и методы программирования
Пример 3. Средневековая задача. В куче находится 50 спи-
чек. Два игрока по очереди могут брать из кучи от 1 до 6 спи­чек. Противники видят все ходы друг друга. Выигрывает тот, кто возьмет последнюю спичку. Составить программу, кото­рая будет всегда выигрывать (компьютер делает первый ход в игре).
Стратегия решения находится очень просто, если «
загля­нуть» в конец игры — очевидно, что выиграет тот, кто оставит противнику 7 спичек. А поскольку за компьютером первый ход, стратегия такова: всегда, на каждом ходу оставлять про­тивнику количество спичек, кратное 7 (это в данном случае и есть инвариант).
// файл Middle_game.dpr, Cредневековая игра. program Middle_game; {$APPTYPE CONSOLE} uses SysUtils; const Pile = 50; var comp, user, cash: integer; BEGIN cash := Pile; writeln( ' Pile Computer User' ); while ( cash > 0 ) do begin comp := 1; while ( ( cash - comp ) mod 7 <> 0 ) do // ход inc( comp ); // компьютера; write( ' ', cash, ' ', comp, ' ' ); if ( cash = comp ) then begin writeln; write( 'I win!, hit <Enter> to exit' ); readln; break; end;
99
Математическое и компьютерное моделирование
0
=
=
=
(
−=−
=
repeat // ход read( user ); // пользователя; until ( user <= 6 ) and ( user >= 1 ); cash := cash - comp - user; end; // while ( cash > 0 )... readln; END. // конец файла Middle_game.dpr end;
III.1.4. Вычисление инвариантной функции
Пусть для функции f существует преобразование T такое,
что
,любыхдля)())(( xxfxTf
тогда функцию f называют инвариантной.
Практически вычисление инвариантной функции сводится к нахождению преобразования T, переводящего элемент x, для которого ищется f(x), в некоторый другой элемент x торого значение функции f(x
) легко находится.
0
, для ко-
0
Пример 4. Найти наибольший общий делитель (НОД) не­отрицательных целых чисел a, b.
Здесь x = (a, b). Очевидно, что
,),0(НОД,)0,(НОД bbaa
и, таким образом, в случае, если a или b равно 0, то легко мож­но вычислить НОД(a, b) = a + b. Следовательно, осталось придумать преобразование T, «сохраняющее» НОД. Посколь­ку ясно, что
)
,,НОД),(НОД),(НОД ababbaba
то искомое преобразование определим так:
>
;0),,(
=
),(
10
baT
⎨ ⎩
baеслиbba
>
.0),,(
abеслиaba
Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]