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

Жарков В.А. - Visual C++ 2005, DirectX 9.0c и Microsoft Agent в компьютерной графике, мультимедиа и играх (Листинги книги) - 2005

.pdf
Скачиваний:
306
Добавлен:
13.08.2013
Размер:
1.14 Mб
Скачать

150 Жарков В.А. Компьютерная графика, мультимедиа и игры на Visual C++ 2005

//координат изображения в массив myArrayVC[2001, 2] //создаем объект sr класса StreamReader:

String^ path = "D:\\MyDocs\\MyTest.txt"; StreamReader^ sr =

gcnew StreamReader(path);

//Считываем из файла MyTest.txt координаты изображения

//в массив myArrayVC(2001, 2) при помощи ReadLine: for (i = 0; i <= N_x - 1; i++)

for (j = 0; j <= N_y - 1; j++) myArrayVC[i, j] =

Convert::ToSingle(sr->ReadLine()); sr->Close();

//Рисуем поверхность z=f(x,y) из массива. //Объявляем координаты двух точек:

float x1, y1, x2, y2;

//Будем рисовать пером myPen толщиной 0: Pen^ myPen = gcnew Pen(Color::Black, 0);

//Рисуем линии поверхности, параллельные плоскости xz: i = -2;

for (int x = 0; x <= x_max; x++)

{

for (int y = 1; y <= y_max; y++)

{

i = i + 2;

x1 = myArrayVC[i, 0];

y1 = myArrayVC[i, 1];

x2 = myArrayVC[i + 1, 0];

y2 = myArrayVC[i + 1, 1]; e->Graphics->DrawLine(myPen, x1, y1, x2, y2);

}

}

N_1_myArray = i + 1; //Первая граница массива.

//Рисуем линии поверхности, параллельные плоскости yz: i = N_1_myArray - 1;

for (int y = 0; y <= y_max; y++)

{

for (int x = 1; x <= x_max; x++)

{

i = i + 2;

x1 = myArrayVC[i, 0];

y1 = myArrayVC[i, 1];

x2 = myArrayVC[i + 1, 0];

y2 = myArrayVC[i + 1, 1]; e->Graphics->DrawLine(myPen, x1, y1, x2, y2);

}

}

Глава 31. Изображение поверхностей на VC++ по данным VC# и VB

151

N_2_myArray = i + 1; //Вторая граница массива. //Рисуем оси координат:

Pen^ myPen2 = gcnew Pen(Color::Red, 0); i = N_2_myArray - 1;

for (int k = 1; k <= 3; k++)

{

i = i + 2;

x1 = myArrayVC[i, 0];

y1 = myArrayVC[i, 1];

x2 = myArrayVC[i + 1, 0];

y2 = myArrayVC[i + 1, 1]; e->Graphics->DrawLine(myPen2, x1, y1, x2, y2); N_3_myArray = i + 1; //Третья граница массива.

}

}

Глава 32. Расчет и изображение линий уровня поверхности на Visual C# для инте-

грации с Visual C++, Visual Basic и другими языками

Листинг 32.1. Код выше и в теле метода Form1_Load.

//Вводим функцию для поверхности z = f1 = f(x, y): public float f(float x, float y)

{

float f1;

f1 = 2 * x * x * x * x - 3 * x * x + 4 * y * y; return f1;

}

//Вводим функцию для частной производной df/dx: public float df_dx(float x, float y)

{

float f2;

f2 = 8 * x * x * x - 6 * x; return f2;

}

//Вводим функцию для частной производной df/dy: public float df_dy(float x, float y)

{

float f3; f3 = 8 * y; return f3;

}

//Объявляем перо для рисования линий уровня: Pen myPen;

private void Form1_Load(object sender, EventArgs e)

{

//Создаем экземпляр пера с цветом и толщиной: myPen = new Pen(Color.Black, 0);

//Связываем графический элемент PictureBox1 //с объектом g класса Graphics:

Bitmap bmp = new Bitmap(pictureBox1.ClientSize.Width, pictureBox1.ClientSize.Height);

Graphics g = Graphics.FromImage(bmp); //Определяем преобразования для масштабирования и //рисования линий на PictureBox в интервале

//-2 <= x <= 2, -1.5 <= y <= 1.5:

Глава 32. Расчет и изображение линий уровня на VC# для VC++ и VB

153

float x_min = -2f; float x_max = 2f; float y_min = -1.5f; float y_max = 1.5f;

g.ScaleTransform(bmp.Width / (x_max - x_min), bmp.Height / (y_max - y_min));

g.TranslateTransform(-x_min, -y_min, System.Drawing.Drawing2D.MatrixOrder.Prepend); //Вызываем функцию для рисования линий уровня: for (int LevelCurves = -3; LevelCurves <= 25;

LevelCurves++)

PlotLevelCurve(g, Convert.ToSingle( LevelCurves / 4),

-4f, 4f, -4f, 4f, 0.05f, 1f, 1f, 0.002f); //Показываем результат рисования: pictureBox1.Image = bmp;

}

Ниже этого кода записываем следующие вспомогательные методы.

Листинг 32.2. Вспомогательные методы.

//Находим точку на линии: float initial_delta = 0.1f;

private void FindPointOnCurve(ref float x, ref float y, float LevelCurves, float start_x, float start_y,

float tolerance)

{

float dx = 0, dy = 0, dz, delta, f_xy; int direction = 0;

//Начальная точка:

x = start_x; y = start_y; delta = initial_delta; //В бесконечном цикле do-while выходим через break: int i = 0;

do

{

f_xy = f(x, y); dz = LevelCurves - f_xy; if (Math.Abs(dz) < tolerance) break; //Анализируем направление:

if (Math.Sign(dz) != direction)

{

//Изменяем направление. Уменьшаем delta: delta = delta / 2;

direction = Math.Sign(dz);

}

//Рассчитываем градиент:

154 Жарков В.А. Компьютерная графика, мультимедиа и игры на Visual C++ 2005

Gradient(x, y, ref dx, ref dy);

if ((Math.Abs(dx) + Math.Abs(dy)) < 0.001) break; //Перемещаемся направо:

x = x + dx * delta * (float)direction; y = y + dy * delta * (float)direction;

}

while (i < 1);

}

//Рассчитываем градиент в этой точке: private void Gradient(float x, float y,

ref float dx, ref float dy)

{

float dist = 0;

dx = df_dx(x, y); dy = df_dy(x, y);

dist = Convert.ToSingle(Math.Sqrt(dx * dx + dy * dy)); if (Math.Abs(dist) < 0.0001)

{

dx = 0; dy = 0;

}

else

{

dx = dx / dist; dy = dy / dist;

}

}

//Программируем второй массив для передачи в файл: //Задаем границы индексов второго массива myArray_2(i, j): int N_x_2 = 20000; int N_y_2 = 2;

//Объявляем массив myArray_2[i, j] переменных типа float, //когда i = 0,1,2,3,...,(N_x-1); j = 0,1,2,3,...,(N_y-1). //Массив автомат-ки обнуляется:

float[,] myArray_2 = new float[20000, 2]; //Значение первой границы массива myArray_2: int N_1_myArray_2;

//Счетчик элементов массива: int ii = -1;

//Рисуем линию уровня f(x, y) = LevelCurves: private void PlotLevelCurve(Graphics g,

float LevelCurves, float x_min, float x_max, float y_min, float y_max, float step_size,

float start_x, float start_y, float tolerance)

{

//Объявляем индексы элементов всех массивов: int i, j;

//Программируем 1-й массив для рисования здесь. //Задаем границы индексов 1-го массива myArray(i, j):

Глава 32. Расчет и изображение линий уровня на VC# для VC++ и VB

155

int N_x = 2001; int N_y = 2;

//Объявляем 1-й массив myArray(i, j) переменных Single, //когда i = 0,1,2,3,...,N_x; j = 0,1,2,3,...,N_y. //Массив автомат-ки обнуляется:

float[,] myArray = new float[N_x, N_y]; //Значение первой границы массива myArray: int N_1_myArray = 0;

//Объявляем переменные для точек линий уровня: int num_points = 0;

float x0 = 0, y0 = 0, x1, y1, x2, y2, dx = 0, dy = 0; //Находим точку (x0, y0) на линии уровня LevelCurves: FindPointOnCurve(ref x0, ref y0, LevelCurves, start_x, start_y, tolerance);

//Начало: num_points = 1;

//Следующая линия уровня LevelCurves: x2 = x0; y2 = y0;

i = -1; //Задаем до цикла.

//В бесконечном цикле do-while выходим через break: int counter = 0;

do

{

x1 = x2; y1 = y2;

//Находим следующую точку на линии: Gradient(x2, y2, ref dx, ref dy);

if ((Math.Abs(dx) + Math.Abs(dy)) < 0.001) break; x2 = x2 + dy * step_size;

y2 = y2 - dx * step_size; FindPointOnCurve(ref x2, ref y2,

LevelCurves, x2, y2, tolerance);

//Можно рисовать и здесь (без массива) до этой тчк. //g.DrawLine(myPen, x1, y1, x2, y2);

//Записываем коорд-ты точек в 1-й массив для текущей //линии уровня, которую будем рисовать здесь:

i = i + 2; myArray[i, 0] = x1; myArray[i, 1] = y1;

myArray[i + 1, 0] = x2; myArray[i + 1, 1] = y2;

N_1_myArray = i + 1; //Значение границы массива. //Записываем координаты точек текущей линии //во 2-й массив, который будем экспортировать в файл: ii = ii + 2;

myArray_2[ii, 0] = x1; myArray_2[ii, 1] = y1; myArray_2[ii + 1, 0] = x2;

156 Жарков В.А. Компьютерная графика, мультимедиа и игры на Visual C++ 2005

myArray_2[ii + 1, 1] = y2;

N_1_myArray_2 = ii + 1; //Значение границы массива. //Задаем следующую точку:

num_points = num_points + 1;

//Смотрим,находится ли точка вне области рисования: if (x2 < x_min) break;

if (x2 > x_max) break; if (y2 < y_min) break; if (y2 > y_max) break;

//Если мы ушли более чем на 4 точки, то смотрим, //не пришли ли мы в начало:

if (num_points >= 4)

{

if (Math.Sqrt((x0 - x2) * (x0 - x2) +

(y0 - y2) * (y0 - y2)) <= step_size * 1.1)

{

//Можно рисовать и здесь (без массива): //g.DrawLine(myPen, x2, y2, x0, y0); //Записываем координаты точек в 1-й массив: i = i + 2;

myArray[i, 0] = x2; myArray[i, 1] = y2; myArray[i + 1, 0] = x0; myArray[i + 1, 1] = y0;

N_1_myArray = i + 1; //Граница массива. //Записываем координаты точек во 2-й массив, //который будем экспортировать в файл:

ii = ii + 2; myArray_2[ii, 0] = x2; myArray_2[ii, 1] = y2; myArray_2[ii + 1, 0] = x0; myArray_2[ii + 1, 1] = y0;

N_1_myArray_2 = ii + 1; //Граница массива. break;

}

}

} //Переход в начало цикла do-while. //Бесконечный цикл, т.к. всегда counter < 1: while (counter < 1);

//Начало N_first_line и конец N_last_line цикла

//при рисовании здесь из массива myArray: int N_first_line, N_last_line; N_first_line = 1;

N_last_line = N_1_myArray;

//Передаем значения начала N_first_line

//и конца цикла N_last_line в элементы массива

//myArray[0, 0] и myArray[0, 1]:

Глава 32. Расчет и изображение линий уровня на VC# для VC++ и VB

157

myArray[0, 0] = N_first_line; myArray[0, 1] = N_last_line;

//Рисуем при помощи массива координат myArray[20000, 2]: int k; i = -1;

for (k = N_first_line; k <= N_last_line; k++)

{

i = i + 2;

x1 = myArray[i, 0];

y1 = myArray[i, 1];

x2 = myArray[i + 1, 0];

y2 = myArray[i + 1, 1]; g.DrawLine(myPen, x1, y1, x2, y2);

}

//Начало N_first_line_2 и конец N_last_line_2 цикла

//при рисовании из массива myArray_2 в другом проекте: int N_first_line_2, N_last_line_2;

N_first_line_2 = 1; N_last_line_2 = N_1_myArray_2;

//Передаем значения начала N_first_line_2

//и конца цикла N_last_line_2 в элементы массива

//myArray_2[0, 0] и myArray_2[0, 1]: myArray_2[0, 0] = N_first_line_2; myArray_2[0, 1] = N_last_line_2;

//Записываем массив корд-т myArray_2[20000, 2] в файл. //Создаем объект sw класса StreamWriter

//для записи в файл D:\MyDocs\MyTest_LevelCurves.txt. //Файл автоматически создается и очищается: StreamWriter sw = new StreamWriter( @"D:\MyDocs\MyTest_LevelCurves.txt");

//Каждый элемент myArray_2[i, j] запис-м в файл //в виде отдельной строки при помощи WriteLine: for (i = 0; i <= (N_x_2-1); i++)

for (j = 0; j <= (N_y_2-1); j++) sw.WriteLine(myArray_2[i, j]);

sw.Close();

}

Глава 33. Расчет и изображение линий уровня поверхности на Visual Basic для ин-

теграции с Visual C++, Visual C# и другими языками

Листинг 33.1. Код выше и в теле процедуры Form1_Load.

'Вводим функцию для поверхности z = f = f(x, y):

Private Function f(ByVal x As Single, ByVal y As Single) _ As Single

f = 2 * x * x * x * x - 3 * x * x + 4 * y * y End Function

'Вводим функцию для частной производной df/dx: Private Function df_dx(ByVal x As Single, _ ByVal y As Single) As Single

df_dx = 8 * x * x * x - 6 * x End Function

'Вводим функцию для частной производной df/dy: Private Function df_dy(ByVal x As Single, _ ByVal y As Single) As Single

df_dy = 8 * y End Function

'Задаем перо для рисования линий уровня: Private myPen As Pen

'Загружаем функции для рисования линий уровня:

Private Sub Form1_Load(ByVal sender As System.Object, _ ByVal e As EventArgs) Handles MyBase.Load

'Задаем цвет пера:

myPen = New Pen(Color.Black, 0) 'Связываем графический элемент PictureBox1 'с объектом g класса Graphics:

Dim bmp As New Bitmap(PictureBox1.ClientSize.Width, _ PictureBox1.ClientSize.Height)

Dim g As Graphics = Graphics.FromImage(bmp) 'Определяем преобразования для масштабирования и 'рисования линий на PictureBox1 в интервале

'-1.5 <= x <= 1.5, -1.5 <= y <= 1.5: Const x_min As Single = -1.5

Const x_max As Single = 1.5

Const y_min As Single = -1.5

Const y_max As Single = 1.5

Глава 33. Расчет и изображение линий уровня на VB для VC++ и VC#

159

g.ScaleTransform(bmp.Width / (x_max - x_min), _ bmp.Height / (y_max - y_min)) g.TranslateTransform(-x_min, -y_min, _ System.Drawing.Drawing2D.MatrixOrder.Prepend) 'Вызываем функцию для рисования линий уровня: For LevelCurves As Integer = -3 To 10

PlotLevelCurve(g, CSng( _

LevelCurves / 4), -4, 4, -4, 4, 0.05, 1, 1, 0.002) Next

'Показываем результат рисования: PictureBox1.Image = bmp

End Sub

Ниже этого кода записываем следующие вспомогательные процедуры.

Листинг 33.2. Вспомогательные процедуры.

'Находим точку на линии:

Private Sub FindPointOnCurve(ByRef x As Single, _ ByRef y As Single, ByVal LevelCurves As Single, _ Optional ByVal start_x As Single = 0.1, _ Optional ByVal start_y As Single = 0.2, _ Optional ByVal tolerance As Single = 0.01, _ Optional ByVal initial_delta As Single = 0.1)

Dim dx As Single : Dim dy As Single Dim dz As Single : Dim dist As Single

Dim delta As Single : Dim f_xy As Single Dim direction As Integer

'Начальная точка:

x = start_x : y = start_y : delta = initial_delta 'Повторяем решение:

Do

f_xy = f(x, y) : dz = LevelCurves - f_xy If Abs(dz) < tolerance Then Exit Do 'Анализируем направление:

If Sign(dz) <> direction Then

'Изменяем направление. Уменьшаем delta: delta = delta / 2 : direction = Sign(dz)

End If

'Рассчитываем градиент: Gradient(x, y, dx, dy)

If Abs(dx) + Abs(dy) < 0.001 Then Exit Do 'Перемещаемся направо:

x = x + dx * delta * direction y = y + dy * delta * direction

Loop End Sub

Соседние файлы в предмете Программирование на C++