
Жарков В.А. - Visual C++ 2005, DirectX 9.0c и Microsoft Agent в компьютерной графике, мультимедиа и играх (Листинги книги) - 2005
.pdf130 Жарков В.А. Компьютерная графика, мультимедиа и игры на Visual C++ 2005
for (i = 0; i <= x_max; i++)
{
x = i + x_min;
for (j = 0; j <= y_max; j++)
{
y = j + y_min;
//Координата z точек пов-ти z = f(x, y): z = f(x, y);
Points[i, j] = new myClassPoint3D(x, y, z);
}
}
//Инициализация осей (axes) координат: Axes[0] = new myClassPoint3D(0, 0, 0); Axes[1] = new myClassPoint3D(30, 0, 0); Axes[2] = new myClassPoint3D(0, 30, 0); Axes[3] = new myClassPoint3D(0, 0, 30);
}
Листинг 29.2. Методо pictureBox1_Paint для рисования поверхности.
private void pictureBox1_Paint(object sender, PaintEventArgs e)
{
//Масштабируем все графические объекты на PictureBox1. //Коэффициенты масштабирования:
float M_1 = 29; float M_2 = 31; e.Graphics.ScaleTransform(pictureBox1.Width / M_1, -pictureBox1.Height / M_2, MatrixOrder.Append); float M_3 = 2; float M_4 = 2;
e.Graphics.TranslateTransform(pictureBox1.Width / M_3, pictureBox1.Height / M_4, MatrixOrder.Append); //Задавая M_1, M_2, M_3, M_4 другие значения,
//мы будем смещать поверхность по отношению к осям x,y,z. //Матрица преобразования (transformation matrix): myClassMatrix3D tr = CalculateTransformation(); //Применяем матрицу преобразования к точкам:
for (int x = 0; x <= x_max; x++) for (int y = 0; y <= y_max; y++)
Points[x, y].Transformation(tr); //Объявляем индексы массива myArrayVCsharp[i, j]: int i, j;
//Задаем границы индексов массива myArrayVCsharp[i, j]: int N_x = 2000; int N_y = 1;
//Задаем массив myArrayVCsharp[i, j]переменных Single, //когда i = 0,1,2,3,...,N_x; j = 0,1,2,3,...,N_y: float[,] myArrayVCsharp = new float[N_x + 1, N_y + 1];
Глава 29. Изображение и управление поверхностями на VC# для VC++, VB 131
//Первая, вторая и третья границы массива, разделяющие //линии поверхности, параллельные xz, yz, и оси:
int N_1_myArrayCsharp = 0, N_2_myArrayCsharp = 0, N_3_myArrayCsharp = 0;
//Рассчитываем элементы массива myArrayVCsharp[i, j] //для рисования линий поверхности,
//параллельных плоскости координат xz: float x1, y1, x2, y2;
Pen myPen = new Pen(Color.Black, 0); i = -2;//Задаем до циклов.
for (int x = 0; x <= x_max; x++)
{
x2 =
Convert.ToSingle(Points[x, 0].trans_coord[0]); y2 =
Convert.ToSingle(Points[x, 0].trans_coord[1]); for (int y = 1; y <= y_max; y++)
{
x1 = x2; y1 = y2;
x2 =
Convert.ToSingle(Points[x, y].trans_coord[0]); y2 =
Convert.ToSingle(Points[x, y].trans_coord[1]); //Можно рисовать линии поверхности и здесь:
//e.Graphics.DrawLine(myPen, x1, y1, x2, y2); //Записываем в массив координат:
i = i + 2; myArrayVCsharp[i, 0] = x1; myArrayVCsharp[i, 1] = y1;
myArrayVCsharp[i + 1, 0] = x2; myArrayVCsharp[i + 1, 1] = y2;
N_1_myArrayCsharp = i + 1; //1-я гран. в массиве.
}
}
//Рассчитываем элементы массива myArrayVCsharp[i, j] //для рисования линий поверхности,
//параллельных плоскости координат yz: i = N_1_myArrayCsharp - 1;
for (int y = 0; y <= y_max; y++)
{
x2 =
Convert.ToSingle(Points[0, y].trans_coord[0]); y2 =
Convert.ToSingle(Points[0, y].trans_coord[1]); for (int x = 1; x <= x_max; x++)
{
132 Жарков В.А. Компьютерная графика, мультимедиа и игры на Visual C++ 2005
x1 = x2; y1 = y2;
x2 =
Convert.ToSingle(Points[x, y].trans_coord[0]); y2 =
Convert.ToSingle(Points[x, y].trans_coord[1]); //Можно рисовать линии поверхности и здесь: //e.Graphics.DrawLine(myPen,x1,y1, x2, y2); //Записываем в массив координат:
i = i + 2; myArrayVCsharp[i, 0] = x1; myArrayVCsharp[i, 1] = y1;
myArrayVCsharp[i + 1, 0] = x2; myArrayVCsharp[i + 1, 1] = y2;
N_2_myArrayCsharp = i + 1; //2-я гран. в массиве.
}
}
//Преобразовываем оси(axes): for (int k = 0; k <= 3; k++)
Axes[k].Transformation(tr);
//Рассчитываем элементы массива для рисования осей: Pen myPenAxes = new Pen(Color.Red, 0);
i = N_2_myArrayCsharp - 1;
x1 = Convert.ToSingle(Axes[0].trans_coord[0]);
y1 = Convert.ToSingle(Axes[0].trans_coord[1]); for (int k = 1; k <= 3; k++)
{
x2 = Convert.ToSingle(Axes[k].trans_coord[0]);
y2 = Convert.ToSingle(Axes[k].trans_coord[1]); //Можно рисовать оси координат и здесь: //e.Graphics.DrawLine(myPenAxes, x1, y1, x2, y2); //Записываем в массив координат:
i = i + 2; myArrayVCsharp[i, 0] = x1; myArrayVCsharp[i, 1] = y1;
myArrayVCsharp[i + 1, 0] = x2; myArrayVCsharp[i + 1, 1] = y2;
N_3_myArrayCsharp = i + 1; //Число чисел в массиве.
}
//Рисуем при помощи массива
//координат myArrayVCsharp[2000, 1]. //Рисуем линии, параллельные плоскости xz: i = -2;
for (int x = 0; x <= x_max; x++)
{
for (int y = 1; y <= y_max; y++)
{
i = i + 2;
Глава 29. Изображение и управление поверхностями на VC# для VC++, VB 133
x1 = myArrayVCsharp[i, 0];
y1 = myArrayVCsharp[i, 1];
x2 = myArrayVCsharp[i + 1, 0];
y2 = myArrayVCsharp[i + 1, 1]; e.Graphics.DrawLine(myPen, x1, y1, x2, y2);
}
}
//Рисуем линии, параллельные плоскости yz: i = N_1_myArrayCsharp - 1;
for (int y = 0; y <= y_max; y++)
{
for (int x = 1; x <= x_max; x++)
{
i = i + 2;
x1 = myArrayVCsharp[i, 0];
y1 = myArrayVCsharp[i, 1];
x2 = myArrayVCsharp[i + 1, 0];
y2 = myArrayVCsharp[i + 1, 1]; e.Graphics.DrawLine(myPen, x1, y1, x2, y2);
}
}
//Рисуем три оси координат: i = N_2_myArrayCsharp - 1;
Pen myPen2 = new Pen(Color.Red, 0); for (int k = 1; k <= 3; k++)
{
i = i + 2;
x1 = myArrayVCsharp[i, 0];
y1 = myArrayVCsharp[i, 1];
x2 = myArrayVCsharp[i + 1, 0];
y2 = myArrayVCsharp[i + 1, 1]; e.Graphics.DrawLine(myPen2, x1, y1, x2, y2);
}
//Записываем массив myArrayVCsharp[2000, 2] в файл. //Создаем объект sw класса StreamWriter
//для записи в файл по адресу D:\MyDocs\MyTest.txt. //Файл автоматически очищается:
StreamWriter sw =
new StreamWriter("D:\\MyDocs\\MyTest.txt"); //Каждый элемент myArrayVCsharp[i, j] записываем в файл //в виде отдельной строки при помощи процедуры WriteLine: for (i = 0; i <= N_x; i++)
for (j = 0; j <= N_y; j++) sw.WriteLine(myArrayVCsharp[i, j]);
sw.Close();
}//Конец метода pictureBox1_Paint.
134 Жарков В.А. Компьютерная графика, мультимедиа и игры на Visual C++ 2005
Листинг 29.3. Метод ProcessCmdKey для вращения поверхности.
protected override bool ProcessCmdKey(
ref System.Windows.Forms.Message msg, System.Windows.Forms.Keys keyData)
{
//Задаем шаг поворота поверхности: const double delta_theta = Math.PI / 32; const double delta_phi = Math.PI / 16;
//Вычисляем сферич-е коорд-ты (spherical coordinates) //точки наблюдения:
double theta = Math.Atan2(myEye.orig_coord[1], myEye.orig_coord[0]);
double r1 = Math.Sqrt(myEye.orig_coord[0] * myEye.orig_coord[0]
+ myEye.orig_coord[1] * myEye.orig_coord[1]); double r2 = Math.Sqrt(myEye.orig_coord[0] *
myEye.orig_coord[0] + myEye.orig_coord[1] * myEye.orig_coord[1] +
myEye.orig_coord[2] * myEye.orig_coord[2]); double phi = Math.Atan2(myEye.orig_coord[2], r1); //Корректируем углы phi и theta:
switch (keyData)
{
case Keys.Left:
theta = theta - delta_theta; break;
case Keys.Up:
phi = phi - delta_phi;
if (phi < -Math.PI / 2) phi = -Math.PI / 2; break;
case Keys.Right:
theta = theta + delta_theta; break;
case Keys.Down:
phi = phi + delta_phi;
if (phi > Math.PI / 2) phi = Math.PI / 2; break;
}
//Изменяем координаты точки наблюдения: myEye.orig_coord[0] = r1 * Math.Cos(theta); myEye.orig_coord[1] = r1 * Math.Sin(theta); myEye.orig_coord[2] = r2 * Math.Sin(phi); //Перерисовываем изображение внутри PictureBox1: pictureBox1.Invalidate();
Глава 29. Изображение и управление поверхностями на VC# для VC++, VB 135
return true;
}
Ниже записываем следующий метод.
Листинг 29.4. Метод CalculateTransformation.
//Метод для вычисления матрицы преобразования //для текущей точки наблюдения: myClassMatrix3D CalculateTransformation()
{
//Поворачиваем вокруг оси z,
//чтобы точка наблюдения оказалась в плоскости y-z: myClassMatrix3D transformation1 =
myClassMatrix3D.GetZRotPointToYZ(myEye); //Поворачиваем вокруг оси x,
//чтобы точка наблюдения оказалась на оси z: myClassMatrix3D transformation2 =
myClassMatrix3D.GetXRotPointToZ(myEye); //Проецируем по оси z, игнорируя координату z. //Для этого умножаем матрицы преобразования:
return (transformation1.TimesMatrix(transformation2));
}
Ниже этого автоматически сгенерированного класса Form1: public partial class Form1 : System.Windows.Forms.Form
{
}
вводим два новых класса с методами преобразования систем координат.
Листинг 29.5. Два новых класса.
//Вводим класс с методами преобразования систем координат //в трехмерном пространстве:
public class myClassPoint3D
{
//Массив из 4-х элементов для первоначальных координат
//(original coordinates); нулевой индекс используем: public double[] orig_coord = new double[4];
//Массив для преобразованных координат: public double[] trans_coord = new double[4];
//Создаем неинициализирующий конструктор этого класса: public myClassPoint3D()
{
}
//Создаем инициализирующий конструктор:
public myClassPoint3D(double x, double y, double z)
{
136 Жарков В.А. Компьютерная графика, мультимедиа и игры на Visual C++ 2005
orig_coord[0] = x; orig_coord[1] = y; orig_coord[2] = z; double myScale;
myScale = 1; //Масштаб. orig_coord[3] = myScale;
}
//Матрица преобразования (transformation matrix): bool normalize = true;
public void Transformation(myClassMatrix3D matrix)
{
double value = 0;
myClassPoint3D result = new myClassPoint3D(); int i, j;
for (i = 0; i <= 3; i++)
{
value = 0;
for (j = 0; j <= 3; j++)
value = value + orig_coord[j] * matrix.M[j, i]; trans_coord[i] = value;
}
//Повторно нормализуем точку: if (normalize == true)
{
//После выхода из цикла value = trans_coord[4]: trans_coord[0] = trans_coord[0] / value; trans_coord[1] = trans_coord[1] / value; trans_coord[2] = trans_coord[2] / value; trans_coord[3] = 1;
}
}
} //Конец класса public class myClassPoint3D.
//Вводим класс с методами преобразования координат точки //в трехмерном пространстве:
public class myClassMatrix3D
{
//Матрица (matrix) в виде массива размера 4x4: public double[,] M = new double[4, 4];
//Создаем неинициализирующий конструктор этого класса: public myClassMatrix3D()
{
}
//Создаем конструктор, инициализирующий матрицу: public myClassMatrix3D(
double m00, double m01, double m02, double m03, double m10, double m11, double m12, double m13,
Глава 29. Изображение и управление поверхностями на VC# для VC++, VB 137
double m20, double m21, double m22, double m23, double m30, double m31, double m32, double m33)
{
M[0, 0] = m00; M[0, 2] = m02; M[1, 0] = m10; M[1, 2] = m12; M[2, 0] = m20; M[2, 2] = m22; M[3, 0] = m30; M[3, 2] = m32;
M[0, 1] = m01; M[0, 3] = m03; M[1, 1] = m11; M[1, 3] = m13; M[2, 1] = m21; M[2, 3] = m23; M[3, 1] = m31; M[3, 3] = m33;
}
//Метод для умножения матрицы на матрицу справа: public myClassMatrix3D TimesMatrix(
myClassMatrix3D right_matrix)
{
myClassMatrix3D result = new myClassMatrix3D(); double value; int i, j, k;
for (i = 0; i <= 3; i++)
{
for (j = 0; j <= 3; j++)
{
value = 0;
for (k = 0; k <= 3; k++)
{
value = value + M[i, k] * right_matrix.M[k, j];
}
result.M[i, j] = value;
}
}
return result;
}
//Метод для поворота вокруг оси z //до точки в y-z плоскости:
public static myClassMatrix3D GetZRotPointToYZ( myClassPoint3D pt)
{
double R = Math.Sqrt(
pt.orig_coord[0] * pt.orig_coord[0] + pt.orig_coord[1] * pt.orig_coord[1]);
double stheta = pt.orig_coord[0] / R; double ctheta = pt.orig_coord[1] / R; return new myClassMatrix3D(
ctheta, stheta, 0, 0, -stheta, ctheta, 0, 0, 0, 0, 1, 0,
138 Жарков В.А. Компьютерная графика, мультимедиа и игры на Visual C++ 2005
0, 0, 0, 1);
}
//Метод для поворота вокруг оси x до точки на оси z: public static myClassMatrix3D GetXRotPointToZ(myClassPoint3D pt)
{
double R1 = Math.Sqrt(
pt.orig_coord[0] * pt.orig_coord[0] + pt.orig_coord[1] * pt.orig_coord[1]);
double R2 = Math.Sqrt(
pt.orig_coord[0] * pt.orig_coord[0] + pt.orig_coord[1] * pt.orig_coord[1] + pt.orig_coord[2] * pt.orig_coord[2]);
double sphi = -R1 / R1;
double cphi = -pt.orig_coord[2] / R2; return new myClassMatrix3D(
1, 0, 0, 0,
0, cphi, sphi, 0, 0, -sphi, cphi, 0, 0, 0, 0, 1);
}
} //Конец класса class myClassMatrix3D.
Глава 30. Изображение и управление поверхностями в трехмерном пространстве на
Visual Basic для интеграции с Visual C++, Visual C# и другими языками
Листинг 30.1. Код выше и в теле процедуры Form1_Load.
'Вводим функцию для изображаемой поверхности z = f(x, y): Public Function f(ByVal x As Double, ByVal y As Double) _ As Double
'Параметры поверхности z = f(x, y)для эллипсоида: Dim a As Double = 1.03
Dim b As Double = 1.02
Dim c As Double = 1.01
'Уравнение поверхности z = f(x, y) в виде эллипсоида: f = Sqrt(c * c * (200 - x * x / (a * a) - _
y * y / (b * b)))
End Function 'Точка наблюдения:
Private myEye As myClassPoint3D
'Концы числового интервала области задания поверхности: Private Const x_max As Integer = 20
Private Const y_max As Integer = 20
Private Const x_min As Integer = -10
Private Const y_min As Integer = -10 'Массив узловых точек:
Private Points(x_max, y_max) As myClassPoint3D 'Точки на осях координат:
Private Axes(3) As myClassPoint3D
'Загрузка данных и их инициализация:
Private Sub Form1_Load(ByVal sender As System.Object, _ ByVal e As EventArgs) Handles MyBase.Load
'Задаем координаты точки наблюдения: myEye = New myClassPoint3D(40, 20, 20) 'Объявляем координаты точки:
Dim x, y, z As Double : Dim i, j As Integer 'В каждом (i,j)-м узле плоскости x,y
'рассчитываем координату z точки поверхности z = f(x, y): For i = 0 To x_max
x = i + x_min
For j = 0 To y_max