Общий вид матрицы переноса. Общий вид матрицы масштабирования. Аффинные преобразования на плоскости

Страницы работы

Фрагмент текста работы

Лабораторная работа №3

«Аффинные преобразования на плоскости»

Цель работы: научиться выполнять простейшие аффинные преобразования на плоскости: перенос, сдвиг, поворот, масштабирование с зеркальным отражением. Написать программу, которая реализует последовательность этих преобразований для некоторого графического объекта.

Пусть имеется треугольник, однородные координаты вершин которого:

         

Выполним следующую последовательность преобразований:

1. Перенос на X = -3, Y = -5

2. Масштабирование относительно точки (1, 3):  kx = 1, ky = -1

3. Поворот относительно точки (0, 8)  на угол

4. Сдвиг относительно прямой  y = 4 вдоль оси OX с параметром сдвига

kx = 1

1. Перенос на X = -3, Y = -5:

Общий вид матрицы переноса:

в данном случае ,

После переноса координаты вершин треугольника:

            

2. Масштабирование относительно точки (1, 3):  kx = 1, ky = -1

Общий вид матрицы масштабирования:

Преобразование является сложным, поэтому надо выполнить последовательность преобразований:

а) перенос на X = -1, Y = -3

б) масштабирование с параметрами kx = 1, ky = -1

в) перенос на X = 1, Y = 3

Тогда матрица преобразования будет иметь вид:

    ,

После масштабирования координаты вершин треугольника:

                   

3. Поворот относительно точки (0, 8) на угол

Общий вид матрицы поворота:   

Преобразование является сложным, поэтому надо выполнить последовательность преобразований:

а) перенос на X = 0, Y = -8

б) поворот на угол

в) перенос на X = 0, Y = 8

Тогда матрица преобразования будет иметь вид:

После поворота координаты вершин треугольника:

         

4. Сдвиг относительно прямой  y = 4 вдоль оси OX с параметром сдвига

kx = 1

Общий вид матрицы сдвига вдоль оси X: 

Преобразование является сложным, поэтому надо выполнить последовательность преобразований:

а) перенос на X = 0, Y = -4

б) сдвиг вдоль оси OX с параметром сдвига kx = 1 в) перенос на X = 0, Y = 4

Тогда матрица преобразования будет иметь вид:

 

После сдвига координаты вершин треугольника:

          

Алгоритм работы программы:

Исходный текст программы на языке С#:

using System;

using System.Collections.Generic;

using System.ComponentModel;

using System.Data;

using System.Drawing;

using System.Text;

using System.Windows.Forms;

namespace FlatCurve

{

public partial class frmFlatCurve : Form

{

int aff_number = 0; //номер аффинного преобразования

int dkx = 20, dky = 20; // приращения в экранных точках при сдвиге начала координат

bool begin = false; //признак ввода начальных значений

float sizeX,sizeY; //масштаб по  x и y

float stepX, stepY; // приращение по x и y в одном пикселе

float relX, relY;   //координаты точки относительно начала координат

float[,] points = new float[3, 3]; // точки фигуры

PointF[] scr_points = new PointF[3];  // экранные точки

PointF XY = new PointF(); //текущая точка на экране

PointF center = new PointF(); // точка начала координат

public frmFlatCurve()

{

InitializeComponent();

center.X = pnlGrafik.Size.Width / 2-250;

center.Y = pnlGrafik.Size.Height / 2+150;

}

void mashtab(float kx,float ky)  //масштабирование

{

float[,] matr = { { kx, 0, 0 }, { 0, ky, 0 }, { 0, 0, 1 } };

points = matr_mult(matr, points);

}

void perenos(float tx, float ty)    //перенос

{

float[,] matr = { { 1, 0, tx }, { 0, 1, ty }, { 0, 0, 1 } };

points = matr_mult(matr, points);    

}

void povorot(float ugol)         //поворот на угол

{

float rad = (float) (ugol * Math.PI / 180);

float[,] matr = { {(float) Math.Cos(rad), (float)(-1*Math.Sin(rad)), 0 }, { (float) Math.Sin(rad), (float) Math.Cos(rad), 0 }, { 0, 0, 1 } };

points = matr_mult(matr, points);

}

void sdvig(float kx) //Сдвиг

{

float[,] matr = { { 1, kx, 0 }, { 0, 1, 0 }, { 0, 0, 1 } };

points = matr_mult(matr, points);

}

float[,] matr_mult(float[,] matr, float[,] points)  //умножение матриц

{

int i, j, k;

float[,] rez = new float[3, 3];

for (i = 0; i < 3; i++)

for (j = 0; j < 3; j++)

{

rez[i, j] = 0;

for (k = 0; k < 3; k++)

rez[i, j] += matr[i, k] * points[k, j];

}

for (i = 0; i < 3; i++)

for (j = 0; j < 3; j++) points[i, j] = rez[i, j];

return rez;

}

//графическое построение

private void pnlGrafik_Paint(object sender, PaintEventArgs e)

{

Pen OXY = new Pen(Color.Blue, 2); //перо оси XOY

Pen setka = new Pen(Color.Gray, 1); //перо масштабной сетки

Pen figur = new Pen(Color.Red, 3); //перо для рисования фигуры

Graphics g = e.Graphics;

Font txt = new Font("Arial", 14, FontStyle.Bold);

int count = 0;

float cx, cy;  //текущие точки плоскости XOY

g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality;

g.PixelOffsetMode = System.Drawing.Drawing2D.PixelOffsetMode.HighQuality;

g.FillRectangle(Brushes.White, 0, 0, pnlGrafik.Size.Width, pnlGrafik.Size.Height);

sizeX = int.Parse(mashtab_ox.Value.ToString());

sizeY = int.Parse(mashtab_oy.Value.ToString());

stepX = 1 / sizeX;

stepY = 1 / sizeY;

//рисование масштабной сетки по x

for (XY.X = center.X, count = 0; XY.X < pnlGrafik.Size.Width; XY.X += sizeX, count++)

{

g.DrawLine(setka, XY.X, 0, XY.X, pnlGrafik.Size.Height);

g.DrawString(count.ToString(), txt, Brushes.Black, XY.X - txt.Size, center.Y);

}

for (XY.X = center.X, count = 0; XY.X > 0; XY.X -= sizeX, count--)

{

g.DrawLine(setka, XY.X, 0, XY.X, pnlGrafik.Size.Height);

if (count != 0)

g.DrawString(count.ToString(), txt, Brushes.Black, XY.X - 1.5f * txt.Size, center.Y);

}

//по y

for (XY.Y = center.Y, count = 0; XY.Y > 0; XY.Y -= sizeY, count++)

{

g.DrawLine(setka, 0, XY.Y, pnlGrafik.Size.Width, XY.Y);

g.DrawString(count.ToString(), txt, Brushes.Black, center.X - txt.Size, XY.Y);

}

for (XY.Y = center.Y, count = 0; XY.Y < pnlGrafik.Size.Height; XY.Y += sizeY, count--)

{

g.DrawLine(setka, 0, XY.Y, pnlGrafik.Size.Width, XY.Y);

if (count != 0)

g.DrawString(count.ToString(), txt, Brushes.Black, center.X - 1.5f * txt.Size, XY.Y);

}

//рисование координатных осей

g.DrawLine(OXY, 0, center.Y, pnlGrafik.Size.Width, center.Y);

g.DrawLine(OXY, center.X, 0, center.X, pnlGrafik.Size.Height);

g.DrawString("0", txt, Brushes.Black, center.X - txt.Size, center.Y);

if (begin)

{

for (int i = 0; i < 3; i++) //преобразование точек плоскости в экранные

{

cx = points[0, i];

cy = points[1, i];

relX = cx / stepX;

relY = cy / stepY;

XY.X = relX + center.X;

XY.Y = center.Y - relY;

scr_points[i].X = XY.X;

scr_points[i].Y = XY.Y;

}

g.DrawLine(figur, scr_points[0], scr_points[1]); //рисование фигуры

g.DrawLine(figur, scr_points[1], scr_points[2]);

g.DrawLine(figur, scr_points[0], scr_points[2]);

}

}

//обновление после масштабирования изображения

private void btn_update_Click(object sender, EventArgs e)

{

this.pnlGrafik.Invalidate();

}

//сдвиг по оси X влево

private void btnXdown_Click(object sender, EventArgs e)

{

center.X += dkx;

this.pnlGrafik.Invalidate();

}

//сдвиг по оси X вправо

private void btnXup_Click(object sender, EventArgs e)

{

center.X -= dkx;

this.pnlGrafik.Invalidate();

}

//сдвиг по оси Y вниз

private void btnYdown_Click(object sender, EventArgs e)

{

center.Y -= dky;

this.pnlGrafik.Invalidate();

}

//сдвиг по оси Y вверх

private void btnYup_Click(object sender, EventArgs e)

{

center.Y += dky;

this.pnlGrafik.Invalidate();

}

//кнопка Выполнить

private void btnAFF_preob_Click(object sender, EventArgs e)

{

float kx, ky, rel_x,rel_y;

try

{

kx = float.Parse(txtparam_1.Text);

ky = float.Parse(txtparam_2.Text);

rel_x = float.Parse(txt_rel_point_x.Text);

rel_y = float.Parse(txt_rel_point_y.Text);

}

catch (Exception)

{

MessageBox.Show("Неправильно введены данные!");

return;

}

// в зависимости от выбранного преобразования

switch (aff_number)

{

case 1:

perenos(-rel_x, -rel_y);

perenos(kx, ky);

perenos(rel_x, rel_y);

break;

case 2:

perenos(-rel_x, -rel_y);

mashtab(kx, ky);

perenos(rel_x, rel_y);

break;

case 3:

perenos(-rel_x, -rel_y);

povorot(kx);

perenos(rel_x, rel_y);

break;

case 4:

perenos(0, -ky);

sdvig(kx);

perenos(0, ky);

label16.Visible = true;

label17.Visible = true;

label18.Visible = true;

txt_rel_point_x.Visible = true;

txt_rel_point_y.Visible = true;

break;

}

button_unlock();

this.pnlGrafik.Invalidate();

//вывод значений точек

txtX1.Text = points[0, 0].ToString();

txtX2.Text = points[0, 1].ToString();

txtX3.Text = points[0, 2].ToString();

txtY1.Text = points[1, 0].ToString();

txtY2.Text = points[1, 1].ToString();

txtY3.Text = points[1, 2].ToString();

}

void clear_txt()

{

txt_rel_point_x.Text = "0";

txt_rel_point_y.Text = "0";

txtparam_1.Text = "0";

txtparam_2.Text = "0";

}

private void btn_enter_Click(object sender, EventArgs e)

{

try

{

//X1,Y1

points[0, 0] = float.Parse(txtX1.Text);

points[1, 0] = float.Parse(txtY1.Text);

points[2, 0] = 1;

//X2,Y2

points[0, 1] = float.Parse(txtX2.Text);

points[1, 1] = float.Parse(txtY2.Text);

points[2, 1] = 1;

//X3,Y3

points[0, 2] = float.Parse(txtX3.Text);

points[1, 2] = float.Parse(txtY3.Text);

points[2, 2] = 1;

}

catch (Exception)

{

MessageBox.Show("Неправильно введены данные!");

return;

}

begin = true;

pnl_begin.Visible = false;

label4.Text = "Информация о точках:";

btn_enter.Visible = false;

clear_txt();

pnl_aff_preob.Visible = true;

pnlGrafik.Invalidate();

btnAFF_preob.BackColor = Color.FromArgb(150, 150, 150);

btnAFF_preob.Enabled = false;

}

void button_unlock()

{

btnAFF_preob.BackColor = Color.FromArgb(150, 150, 150);

btnAFF_preob.Enabled = false;

btn_translate.BackColor = Color.FromArgb(224, 224, 224);

btn_translate.Enabled = true;

btn_rotate.BackColor = Color.FromArgb(224, 224, 224);

btn_rotate.Enabled = true;

btn_mashtab.BackColor = Color.FromArgb(224, 224, 224);

btn_mashtab.Enabled = true;

btn_shift.BackColor = Color.FromArgb(224, 224, 224);

btn_shift.Enabled = true;

}

void button_lock()

{

btnAFF_preob.BackColor = Color.FromArgb(224, 224, 224);

btnAFF_preob.Enabled = true;

btn_translate.BackColor = Color.FromArgb(150, 150, 150);

btn_translate.Enabled = false;

btn_rotate.BackColor = Color.FromArgb(150, 150, 150);

btn_rotate.Enabled = false;

btn_mashtab.BackColor = Color.FromArgb(150, 150, 150);

btn_mashtab.Enabled = false;

btn_shift.BackColor = Color.FromArgb(150, 150, 150);

btn_shift.Enabled = false;

}

private void btn_translate_Click(object sender, EventArgs e)

{

aff_number = 1;

clear_txt();

label1.Text = "X = ";

label1.Visible = true;

txtparam_1.Visible = true;

label2.Text = "Y = ";

label2.Visible = true;

txtparam_2.Visible = true;

button_lock();

btn_translate.BackColor = Color.White;

}

private void btn_mashtab_Click(object sender, EventArgs e)

{

aff_number = 2;

clear_txt();

label1.Text = "kx = ";

label1.Visible = true;

txtparam_1.Visible = true;

label2.Text = "ky = ";

label2.Visible = true;

txtparam_2.Visible = true;

button_lock();

btn_mashtab.BackColor = Color.White;

}

private void btn_rotate_Click(object sender, EventArgs e)

{

aff_number = 3;

clear_txt();

label1.Text = "F = ";

label1.Visible = true;

txtparam_1.Visible = true;

label2.Visible = false;

txtparam_2.Visible = false;

button_lock();

btn_rotate.BackColor = Color.White;

}

private void btn_shift_Click(object sender, EventArgs e)

{

aff_number = 4;

clear_txt();

label1.Text = "kx = ";

label1.Visible = true;

label2.Text = "Y = ";

label2.Visible = true;

txtparam_2.Visible = true;

label16.Visible = false;

label17.Visible = false;

label18.Visible = false;

txt_rel_point_x.Visible = false;

txt_rel_point_y.Visible = false;

button_lock();

btn_shift.BackColor = Color.White;

}

private void pnlGrafik_Click(object sender, EventArgs e)

{

pnl_begin.Visible = true;

}

private void pnlGrafik_DoubleClick(object sender, EventArgs e)

{

pnl_begin.Visible = false;

}}

}

Работа программы: при запуске появляется окно, при этом необходимо задать начальные координаты объекта:

После ввода начальных координат появляется список преобразований:

Для выполнения преобразования необходимо нажать на соответствующую

Похожие материалы

Информация о работе