Расчет и изображение линий уровня на поверхности
Листинг 40.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_1(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:
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;
}
Ниже этого кода записываем следующие вспомогательные методы.
Листинг 40.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);
}
//Рассчитываем градиент:
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;
}
}
//Рисуем линию уровня 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 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;
//В бесконечном цикле do-while выходим через break:
int i = 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);
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);
break;
}
}
}
while (i < 1);
}
Таким образом, мы закончили разработку новой методологии создания графической системы на базе Visual C# для построения на экране монитора и печати на принтере линий уровня для разнообразных трехмерных поверхностей в трехмерном пространстве.
Аналогично по этой методологии можно разработать приложения для построения различных линий уровня на различных поверхностях.