Жарков В.А. - Visual C++ 2005, DirectX 9.0c и Microsoft Agent в компьютерной графике, мультимедиа и играх (Листинги книги) - 2005
.pdf120 Жарков В.А. Компьютерная графика, мультимедиа и игры на Visual C++ 2005
MatrixIdentity(ref r2);
L = (float)Math.Sqrt(d1 * d1 + d2 * d2 + d3 * d3); r2[2, 2] = D / L; r2[2, 3] = -d3 / L;
r2[3, 2] = -r2[2, 3]; r2[3, 3] = r2[2, 2]; MatrixIdentity(ref R2i);
R2i[2, 2] = r2[2, 2]; R2i[2, 3] = -r2[2, 3]; R2i[3, 2] = -r2[3, 2]; R2i[3, 3] = r2[3, 3]; //Вращаем вокруг линии (оси y):
MatrixYRotate(ref Rot3, theta); //Комбинируем матрицы: m3MatMultiply(ref M12, ref T, ref R1);
m3MatMultiply(ref M34, ref r2, ref Rot3); m3MatMultiply(ref M1234, ref M12, ref M34); m3MatMultiply(ref M56, ref R2i, ref R1i); m3MatMultiply(ref M567, ref M56, ref Ti); m3MatMultiply(ref M, ref M1234, ref M567);
}
//Строим матрицу преобразования (3-D transformation matrix) //для переноса на Tx, Ty, Tz:
public void MatrixTranslate(ref float[,] M, float Tx, float Ty, float Tz)
{
MatrixIdentity(ref M);
M[4, 1] = Tx; M[4, 2] = Ty; M[4, 3] = Tz;
}
//Строим матрицу преобразования (3-D transformation matrix) //для поворота вокруг оси y (угол - в радианах):
public void MatrixYRotate(ref float[,] M, float theta)
{
MatrixIdentity(ref M);
M[1, 1] = (float)Math.Cos(theta); M[3, 3] = M[1, 1];
M[3, 1] = (float)Math.Sin(theta); M[1, 3] = -M[3, 1];
}
//Применяем матрицу преобразования к точке, //где матрица не может иметь 0, 0, 0, 1 //в последнем столбце. Нормализуем только
//x и y компоненты результата, чтобы сохранить z информацию: public void MatrixApplyFull(ref float[] V, ref float[,] M, ref float[] Result)
{
int i, j; float value = 0;
Result = new float[5] { 0, 0, 0, 0, 0 }; for (i = 1; i <= 4; i++)
{
value = 0;
Глава 26. Изображение и управление объектами на VC# и VC++ |
121 |
for (j = 1; j <= 4; j++)
{
value = value + V[j] * M[j, i];
}
Result[i] = value;
}
//Повторно нормализуем точку (value = Result[4]): if (value != 0)
{
Result[1] = Result[1] / value; Result[2] = Result[2] / value;
}
else
{
//Не преобразовываем z - составляющую.
//Если значение z больше, чем от центра проекции, //эта точка будет удалена:
Result[3] = Single.MaxValue;
}
Result[4] = 1;
}
//Применяем матрицу преобразования к точке: public void MatrixApply(ref float[] V,
ref float[,] M, ref float[] Result)
{
Result[1] = V[1] * |
M[1, 1] + V[2] * M[2, 1] + |
V[3] * M[3, 1] |
+ M[4, 1]; |
Result[2] = V[1] * |
M[1, 2] + V[2] * M[2, 2] + |
V[3] * M[3, 2] |
+ M[4, 2]; |
Result[3] = V[1] * |
M[1, 3] + V[2] * M[2, 3] + |
V[3] * M[3, 3] + M[4, 3]; Result[4] = 1;
}
//Умножаем две матрицы. Матрицы //не могут содержать 0, 0, 0, 1 в последних столбцах:
public void m3MatMultiplyFull(ref float[,] Result, ref float[,] A, ref float[,] B)
{
int i, j, k; float value; Result = new float[5, 5]; for (i = 1; i <= 4; i++)
{
for (j = 1; j <= 4; j++)
{
value = 0;
for (k = 1; k <= 4; k++)
value = value + A[i, k] * B[k, j]; Result[i, j] = value;
122 Жарков В.А. Компьютерная графика, мультимедиа и игры на Visual C++ 2005
}
}
}
//Умножаем две матрицы:
public void m3MatMultiply(ref float[,] Result, ref float[,] A, ref float[,] B)
{
Result[1, 1] = A[1, 1] * B[1, 1] + A[1, 2] * B[2, 1] + A[1, 3] * B[3, 1];
Result[1, 2] = A[1, 1] * B[1, 2] + A[1, 2] * B[2, 2] + A[1, 3] * B[3, 2];
Result[1, 3] = A[1, 1] * B[1, 3] + A[1, 2] * B[2, 3]
+A[1, 3] * B[3, 3]; Result[1, 4] = 0;
Result[2, 1] = A[2, 1] * B[1, 1] + A[2, 2] * B[2, 1]
+A[2, 3] * B[3, 1];
Result[2, 2] = A[2, 1] * B[1, 2] + A[2, 2] * B[2, 2] + A[2, 3] * B[3, 2];
Result[2, 3] = A[2, 1] * B[1, 3] + A[2, 2] * B[2, 3]
+A[2, 3] * B[3, 3]; Result[2, 4] = 0;
Result[3, 1] = A[3, 1] * B[1, 1] + A[3, 2] * B[2, 1]
+A[3, 3] * B[3, 1];
Result[3, 2] = A[3, 1] * B[1, 2] + A[3, 2] * B[2, 2] + A[3, 3] * B[3, 2];
Result[3, 3] = A[3, 1] * B[1, 3] + A[3, 2] * B[2, 3]
+A[3, 3] * B[3, 3]; Result[3, 4] = 0;
Result[4, 1] = A[4, 1] * B[1, 1] + A[4, 2] * B[2, 1]
+A[4, 3] * B[3, 1] + B[4, 1];
Result[4, 2] = A[4, 1] * B[1, 2] + A[4, 2] * B[2, 2] + A[4, 3] * B[3, 2] + B[4, 2];
Result[4, 3] = A[4, 1] * B[1, 3] + A[4, 2] * B[2, 3] + A[4, 3] * B[3, 3] + B[4, 3];
Result[4, 4] = 1;
}
Листинг 26.4. Метод для печати изображения с элемента PictureBox.
private void printDocument1_PrintPage(object sender, System.Drawing.Printing.PrintPageEventArgs e)
{
e.Graphics.DrawImage(pictureBox1.Image, 0, 0);
}
Глава 27. Изображение объектов в проекте Visual C++ по данным из другого проекта
Visual C++, Visual Basic или Visual C#
На базе нового синтаксиса языка Visual C++ 2005 двухмерный массив с элементами типа значения объявляется и инициализируется так:
int N_x = 201; int N_y = 2; array<float,2>^ myArrayVC =
gcnew array<float,2>(N_x, N_y);
При инициализации двухмерного массива в правой части вместо N_x, N_y мы можем записать конкретные значения верхних границ индексов.
Перед объявлением массива мы должны еще подключить новое пространство имен (в верхней части автоматически сгенерированного пространства имен с именем нашего проекта):
using namespace stdcli::language;
Кроме этого, для использования класса StreamWriter в проекте Visual C++ 2005 мы должны подключить также пространство имен IO:
using namespace System::IO;
Для считывания координат изображения из файла, например, по адресу
D:\\MyDocs\\MyTest3D_Graphics.txt в массив myArrayVC[N_x, N_y] объявляем объ-
ект sr класса StreamReader и при помощи конструктора gcnew (согласно новому синтаксису Visual C++ 2005) создаем экземпляр этого объекта с параметром в виде пути к файлу с координатами изображения:
StreamReader^ sr = gcnew StreamReader( "D:\\MyDocs\\MyTest3D_Graphics.txt");
Листинг 27.1. Метод для рисования геометрических изображений.
private: System::Void pictureBox1_Paint( System::Object^ sender, System::Windows::Forms::PaintEventArgs^ e)
{
//Объявляем индексы элементов всех массивов: int i, j, k;
//Задаем границы индексов 1-го массива myArrayVC(i, j): int N_x = 201; int N_y = 2;
//Объявляем 1-й массив myArrayVC[i, j] переменных float, //когда i = 0,1,2,3,...,(N_x - 1);
// j = 0,1,2,3,...,(N_y - 1): array<float,2>^ myArrayVC =
gcnew array<float,2>(N_x, N_y); //Для считывания из файла
//по адресу D:\\MyDocs\\MyTest3D_Graphics.txt
124 Жарков В.А. Компьютерная графика, мультимедиа и игры на Visual C++ 2005
//координат изображения в массив myArrayVC(201, 2) //создаем объект sr класса StreamReader: StreamReader^ sr = gcnew StreamReader(
"D:\\MyDocs\\MyTest3D_Graphics.txt"); //Считываем из файла MyTest3D_Graphics.txt //координаты изображения в массив myArrayVC(201, 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();
//Рисуем первое изображение по координатам из массива. //Объявляем координаты двух точек:
float x1, y1, x2, y2;
//Будем рисовать пером myPen толщиной 3 пикселя: Pen^ myPen = gcnew Pen(Color::Black, 3); //Объявляем переменные для начала N_first_line //и конца N_last_line цикла при рисовании:
int N_first_line, N_last_line;
//Передаем переменным для начала и конца цикла //значения первых двух элементов массива myArrayVC: N_first_line = Convert::ToInt32(myArrayVC[0, 0]); N_last_line = Convert::ToInt32(myArrayVC[0, 1]); //Рисуем изображение, начиная с точки (1,0; 1,1): i = -1;
for (k = N_first_line; k <= N_last_line; 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(myPen, x1, y1, x2, y2);
}
//Задаем границы индексов 2-го массива myArrayVC_2(i, j): int N_x_2 = 201; int N_y_2 = 2;
//Объявляем 2-й массив myArrayVC_2(i, j) перем-х float, //когда i = 0,1,2,3,...,(N_x_2 - 1);
// j = 0,1,2,3,...,(N_y_2 - 1): array<float,2>^ myArrayVC_2 =
gcnew array<float,2>(N_x_2, N_y_2); //Для считывания из файла
//по адресу D:\\MyDocs\\MyTest3D_Graphics_2.txt //координат изображения в массив myArrayVC_2(201, 2) //создаем объект sr_2 класса StreamReader: StreamReader^ sr_2 = gcnew StreamReader(
Глава 27. Изображение объектов в проекте VC++ по данным VC++, VB, VC# 125
"D:\\MyDocs\\MyTest3D_Graphics_2.txt"); //Считываем из файла MyTest3D_Graphics_2.txt //координаты изображения в массив myArrayVC_2(201, 2) //при помощи метода ReadLine:
for (i = 0; i <= N_x - 1; i++) for (j = 0; j <= N_y - 1; j++)
myArrayVC_2[i, j] = Convert::ToSingle(sr_2->ReadLine());
sr_2->Close();
//Рисуем второе изображение по координатам из массива. //Будем рисовать пером myPen толщиной 1:
Pen^ myPen_2 = gcnew Pen(Color::Black, 1); //Объявляем переменные для начала N_first_line //и конца N_last_line цикла при рисовании: int N_first_line_2, N_last_line_2;
//Передаем переменным для начала и конца цикла //значения первых двух элементов массива myArrayVC: N_first_line_2 = Convert::ToInt32(myArrayVC_2[0, 0]); N_last_line_2 = Convert::ToInt32(myArrayVC_2[0, 1]);
//Рисуем изображение, начиная с точки (1,0; 1,1): i = -1;
for (k = N_first_line_2; k <= N_last_line_2; k++)
{
i = i + 2;
x1 = myArrayVC_2[i, 0]; y1 = myArrayVC_2[i, 1];
x2 = myArrayVC_2[i + 1, 0];y2 = myArrayVC_2[i + 1, 1]; e->Graphics->DrawLine(myPen_2, x1, y1, x2, y2);
}
}
Глава 28. Изображение объектов в проекте Visual C# по данным из проекта Visual C++, Visual Basic или Visual C#
Листинг 28.1. Метод для рисования геометрических изображений.
private void pictureBox1_Paint(object sender, PaintEventArgs e)
{
//Объявляем индексы элементов всех массивов: int i, j, k;
//Задаем границы индексов 1-го массива myArrayVC(i, j): int N_x = 201; int N_y = 2;
//Объявляем 1-й массив myArrayVC(i, j) переменных float, //когда i = 0,1,2,3,...,(N_x - 1);
// j = 0,1,2,3,...,(N_y - 1): float[,] myArrayVC = new float[N_x, N_y]; //Для считывания из файла
//по адресу D:\\MyDocs\\MyTest3D_Graphics.txt //координат изображения в массив myArrayVC(201, 2) //создаем объект sr класса StreamReader: StreamReader sr =
new StreamReader( @"D:\\MyDocs\\MyTest3D_Graphics.txt");
//Считываем из файла MyTest3D_Graphics.txt //координаты изображения в массив myArrayVC(201, 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();
//Рисуем первое изображение по координатам из массива. //Объявляем координаты двух точек:
float x1, y1, x2, y2;
//Будем рисовать пером myPen толщиной 3: Pen myPen = new Pen(Color.Black, 3);
//Объявляем переменные для начала N_first_line //и конца N_last_line цикла при рисовании: int N_first_line, N_last_line;
//Передаем переменным для начала и конца цикла //значения первых двух элементов массива myArrayVC: N_first_line = Convert.ToInt32(myArrayVC[0, 0]);
Глава 28. Изображение объектов в проекте VC# по данным VC++, VB, VC# 127
N_last_line = Convert.ToInt32(myArrayVC[0, 1]);
//Рисуем изображение, начиная с точки (1,0; 1,1): i = -1;
for (k = N_first_line; k <= N_last_line; 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(myPen, x1, y1, x2, y2);
}
//Задаем границы индексов 2-го массива myArrayVC_2(i, j): int N_x_2 = 201;
int N_y_2 = 2;
//Объявляем 2-й массив myArrayVC_2(i, j) перем-х float, //когда i = 0,1,2,3,...,(N_x_2 - 1);
//j = 0,1,2,3,...,(N_y_2 - 1):
float[,] myArrayVC_2 = new float[N_x_2, N_y_2]; //Для считывания из файла
//по адресу D:\\MyDocs\\MyTest3D_Graphics_2.txt //координат изображения в массив myArrayVC_2(201, 2) //создаем объект sr_2 класса StreamReader: StreamReader sr_2 = new StreamReader(
@"D:\\MyDocs\\MyTest3D_Graphics_2.txt");
//Считываем из файла MyTest3D_Graphics_2.txt //координаты изображения в массив myArrayVC_2(201, 2) //при помощи метода ReadLine:
for (i = 0; i <= N_x - 1; i++) for (j = 0; j <= N_y - 1; j++)
myArrayVC_2[i, j] = Convert.ToSingle(sr_2.ReadLine());
sr_2.Close();
//Рисуем второе изображение по координатам из массива. //Будем рисовать пером myPen толщиной 1:
Pen myPen_2 = new Pen(Color.Black, 1); //Объявляем переменные для начала N_first_line //и конца N_last_line цикла при рисовании: int N_first_line_2, N_last_line_2;
//Передаем переменным для начала и конца цикла //значения первых двух элементов массива myArrayVC: N_first_line_2 = Convert.ToInt32(myArrayVC_2[0, 0]); N_last_line_2 = Convert.ToInt32(myArrayVC_2[0, 1]);
128 Жарков В.А. Компьютерная графика, мультимедиа и игры на Visual C++ 2005
//Рисуем изображение, начиная с точки (1,0; 1,1): i = -1;
//for (k = 1; k <= 3; k++)
for (k = N_first_line_2; k <= N_last_line_2; k++)
{
i = i + 2;
x1 = myArrayVC_2[i, 0];
y1 = myArrayVC_2[i, 1];
x2 = myArrayVC_2[i + 1, 0];
y2 = myArrayVC_2[i + 1, 1]; e.Graphics.DrawLine(myPen_2, x1, y1, x2, y2);
}
}
Глава 29. Изображение и управление поверхностями в трехмерном пространстве на
Visual C# для интеграции с Visual C++, Visual Basic и другими языками
Листинг 29.1. Код выше и в теле метода Form1_Load.
//Вводим функцию для изображаемой поверхности z = f(x, y): double f1;
double f(double x, double y)
{
//Параметры поверхности z = f(x, y)для эллипсоида: double a = 1.03;
double b = 1.02; double c = 1.01;
//Уравнение поверхности z = f(x, y) в виде эллипсоида: f1 = Math.Sqrt(c * c * (200 - x * x / (a * a) –
y * y / (b * b)));
return f1;
}
//Точка наблюдения:
myClassPoint3D myEye = new myClassPoint3D();
//Концы числового интервала области задания поверхности: const int x_max = 20;
const int y_max = 20; const int x_min = -10; const int y_min = -10; //Массив узловых точек:
myClassPoint3D[,] Points = new myClassPoint3D[x_max + 1, y_max + 1];
//Точки на осях координат:
myClassPoint3D[] Axes = new myClassPoint3D[4];
//Загрузка данных и их инициализация:
private void Form1_Load(object sender, EventArgs e)
{
//Задаем координаты точки наблюдения: myEye = new myClassPoint3D(40, 20, 20);
//Объявляем координаты точки: double x, y, z; int i, j;
//В каждом (i,j)-м узле плоскости x,y
//рассчитываем координату z точки пов-ти z = f(x, y):