Добавил:
ivanov666
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз:
Предмет:
Файл:Практический курс математического и компьютерного моделирования. Учебно-практическое пособие
.pdf
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
Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]
