Файл: Афинные преобразования.docx

ВУЗ: Не указан

Категория: Не указан

Дисциплина: Не указана

Добавлен: 12.04.2024

Просмотров: 16

Скачиваний: 1

ВНИМАНИЕ! Если данный файл нарушает Ваши авторские права, то обязательно сообщите нам.

МИНОБРНАУКИ РОССИИ

Федеральное государственное бюджетное образовательное учреждение

высшего профессионального образования

«ЮГО-ЗАПАДНЫЙ ГОСУДАРСТВЕННЫЙ УНИВЕРСИТЕТ»

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

По дисциплине «Компьютерная графика»

На тему: «Афинные преобразования»

Выполнил: Студент группы ПО-91з

Нестеров С.Д.

Проверил: Преподаватель

Петрик Е.А.

Курск, 2022

Задание

Написать программу (на языке высокого уровня), позволяющую производить и отображать на экране масштабирование, поворот и перенос заданных 3 отрезков, а также трехмерной фигуры в виде куба. Координаты отрезков, длину стороны куба, коэффициенты для масштабирования и переноса должны задаваться пользователем.

Блок-схемы алгоритмов

Блок-схема переноса отрезка изображена Рисунок 1 – Блок-схема переноса отрезка.



Рисунок 1 – Блок-схема переноса отрезка

Блок-схема масштабирования отрезка изображена Рисунок 2 – Блок-схема масштабирования отрезка.



Рисунок 2 – Блок-схема масштабирования отрезка

Блок-схема поворота отрезка изображена Рисунок 3 – Блок-схема поворота отрезка.



Рисунок 3 – Блок-схема поворота отрезка

Блок-схема трёхмерного переноса изображена Рисунок 4 – Блок-схема трёхмерного переноса.



Рисунок 4 – Блок-схема трёхмерного переноса

Блок-схема трёхмерного масштабирования изображена Рисунок 5 – Блок-схема трёхмерного масштабирования.



Рисунок 5 – Блок-схема трёхмерного масштабирования

Блок-схема трёхмерного поворота изображена на рисунках Рисунок 6 – Блок-схема трёхмерного поворота и Рисунок 7 – Блок-схема трёхмерного поворота.



Рисунок 6 – Блок-схема трёхмерного поворота



Рисунок 7 – Блок-схема трёхмерного поворота

Листинг программы

public struct Pixel


{

private int _x;

private int _y;

public int X { get => _x; set => _x = value; }

public int Y { get => _y; set => _y = value; }

public Pixel(int x, int y)

{

_x = x;

_y = y;

}

}

public struct Point2D

{

private float _x;

private float _y;

public float X { get => _x; set => _x = value; }

public float Y { get => _y; set => _y = value; }

public Point2D(float x, float y)

{

_x = x;

_y = y;

}

public void Move(float dx, float dy)

{

_x += dx;

_y += dy;

}

public void Scale(float sx, float sy)

{

if (sx != 0) _x *= sx;

if (sx != 0) _y *= sy;

}

public void Rotate(float angle)

{

if (angle == 0) return;

double rAngle = angle * Math.PI / 180;

float tempX = _x * (float)Math.Cos(rAngle) - _y * (float)Math.Sin(rAngle);

_y = _x * (float)Math.Sin(rAngle) + _y * (float)Math.Cos(rAngle);

_x = tempX;

}

}

public struct Point3D

{

private float _x;

private float _y;

private float _z;

public float X { get => _x; set => _x = value; }

public float Y { get => _y; set => _y = value; }

public float Z { get => _z; set => _z = value; }

public Point3D(float x, float y, float z)

{

_x = x;

_y = y;

_z = z;

}

public void Move(float dx, float dy, float dz)

{

_x += dx;

_y += dy;

_z += dz;

}

public void Scale(float sx, float sy, float sz)

{

if (sx != 0) _x *= sx;

if (sy != 0) _y *= sy;

if (sz != 0) _z *= sz;

}

public void Rotate(float ax, float ay, float az)

{

double rAngle = 0;

float[][] r = null;

float[][] s = new float[][]

{

new float[]

{

_x,

_y,

_z,

1

},

};

if (ax != 0)

{

rAngle = ax * Math.PI / 180;

r = new float[][]

{

new float[]{1,0,0,0},

new float[]{0, (float)Math.Cos(rAngle), (float)Math.Sin(rAngle),0},

new float[]{0, -(float)Math.Sin(rAngle), (float)Math.Cos(rAngle),0},

new float[]{0,0,0,1}

};

s = MatrixMultiply(s, r);

}

if (ay != 0)

{

rAngle = ay * Math.PI / 180;

r = new float[][]

{

new float[]{ (float)Math.Cos(rAngle), 0, -(float)Math.Sin(rAngle), 0},

new float[]{0,1,0,0},

new float[]{ (float)Math.Sin(rAngle),0,(float)Math.Cos(rAngle),0},

new float[]{0,0,0,1}

};

s = MatrixMultiply(s, r);

}

if (az != 0)

{

rAngle = az * Math.PI / 180;

r = new float[][]

{

new float[]{ (float)Math.Cos(rAngle),(float)Math.Sin(rAngle),0, 0},

new float[]{ -(float)Math.Sin(rAngle), (float)Math.Cos(rAngle), 0,0},

new float[]{ 0,0,1,0},

new float[]{0,0,0,1}

};

s = MatrixMultiply(s, r);

}

_x = s[0][0];

_y = s[0][1];

_z = s[0][2];

}

}

public interface IGraficObject : INotifyPropertyChanged

{

Guid Id { get; }

Color Color { get; set; }

Pixel[] LastPixels { get; }

Pixel[] GetPixels();

}

public interface IFigure : IGraficObject

{

LineAlgType AlgType { get; set; }

int[] Edges { get; }

}

public interface IFigure2D : IFigure

{

float X { get; set; }

float Y { get; set; }

Point2D[] LocalVertexes { get; }

Point2D[] GlobalVertexes { get; set; }

void Move(float dx, float dy);

void Scale(float sx, float sy);

void Rotate(float angle);

}

public interface IFigure3D : IFigure

{

float X { get; set; }

float Y { get; set; }

float Z { get; set; }

float EdgeLength { get; set; }

ProjectionType ProjectionType { get; set; }

Point3D[] LocalVertexes { get; }

Point3D[] GlobalVertexes { get; }

void Move(float dx, float dy, float dz);

void Scale(float sx, float sy, float sz);

void Rotate(float ax, float ay, float az);

}

public abstract class BaseGraficObject : NotifyPropertyChange, IGraficObject

{

protected Color _color;

protected Pixel[] _lastPixels;


public Guid Id { get; } = Guid.NewGuid();

public Color Color

{

get => _color;

set

{

_color = value;

NotifyPropertyChanged(nameof(Color));

}

}

public Pixel[] LastPixels { get => _lastPixels; protected set => _lastPixels = value; }

public abstract Pixel[] GetPixels();
protected BaseGraficObject(Color color)

{

_color = color;

}

}

public abstract class BaseFigure : BaseGraficObject , IFigure

{

protected LineAlgType _algType;

protected int[] _edges;

public LineAlgType AlgType { get => _algType; set => Set(ref _algType, value); }

public int[] Edges { get => _edges; }
protected BaseFigure(LineAlgType algType, Color color) : base(color)

{

_algType = algType;

}

}

public abstract class BaseFigure2D : BaseFigure, IFigure2D

{

protected float _x;

protected float _y;

protected Point2D[] _localVertexes;

public float X { get => _x; set => Set(ref _x, value); }

public float Y { get => _y; set => Set(ref _y, value); }

public Point2D[] LocalVertexes

{

get => _localVertexes;

protected set

{

Set(ref _localVertexes, value);

NotifyPropertyChanged(nameof(GlobalVertexes));

}

}

public Point2D[] GlobalVertexes

{

get => LocalVertexes.Select(p => ToGlobal(p)).ToArray();

set => LocalVertexes = value.Select(p => ToLocal(p)).ToArray();

}

protected BaseFigure2D(float x, float y, LineAlgType algType, Color color) : base(algType, color)

{

_x = x;

_y = y;

}

protected BaseFigure2D(float x, float y, Color color) : this(x, y, LineAlgType.BrezenhamInteger, color) { }

protected BaseFigure2D(float x, float y, LineAlgType algType) : this(x, y, algType, Color.Black) { }

protected BaseFigure2D(float x, float y) : this(x, y, Color.Black) { }

public Point2D ToGlobal(Point2D point)

{

return new Point2D(point.X + _x, point.Y + _y);

}

public Point2D ToLocal(Point2D point)

{

return new Point2D(point.X - _x, point.Y - _y);

}

public override Pixel[] GetPixels()

{

return LastPixels = RasterizeService.GetPixels(GlobalVertexes, Edges, Enums.LineAlgType.DDA);

}

public void Move(float dx, float dy)

{

X += dx;

Y += dy;

NotifyPropertyChanged(nameof(GlobalVertexes));

}

public void Rotate(float angle)

{

for (int i = 0; i < _localVertexes.Length; i++)

{

_localVertexes[i].Rotate(angle);

}

NotifyPropertyChanged(nameof(LocalVertexes));

NotifyPropertyChanged(nameof(GlobalVertexes));

}

public void Scale(float sx, float sy)

{

for (int i = 0; i < _localVertexes.Length; i++)

{

_localVertexes[i].Scale(sx, sy);

}

NotifyPropertyChanged(nameof(LocalVertexes));

NotifyPropertyChanged(nameof(GlobalVertexes));

}

}

public abstract class BaseFigure3D : BaseFigure, IFigure3D

{

protected float _x;

protected float _y;

protected float _z;

protected float _edgeLength;

protected ProjectionType _projectionType;

protected Point3D[] _localVertexes;

public float X { get => _x; set => Set(ref _x, value); }

public float Y { get => _y; set => Set(ref _y, value); }

public float Z { get => _z; set => Set(ref _z, value); }

public float EdgeLength

{

get => _edgeLength; set

{

float scaleCoeff = value / _edgeLength;

if (scaleCoeff != 1) Scale(scaleCoeff, scaleCoeff, scaleCoeff);

}

}

public Point3D[] LocalVertexes { get => _localVertexes; }

public Point3D[] GlobalVertexes { get => _localVertexes.Select(p => ToGlobal(p)).ToArray(); }

public ProjectionType ProjectionType { get => _projectionType; set => Set(ref _projectionType, value); }
protected BaseFigure3D(float x, float y, float z, float edgeLength, LineAlgType algType, ProjectionType projectionType, Color color) : base(algType, color)

{

_x = x;

_y = y;

_z = z;

_edgeLength = edgeLength;

_projectionType = projectionType;

}

protected BaseFigure3D(float x, float y, float z, float edgeLength) : this(x, y, z, edgeLength, LineAlgType.BrezenhamInteger, ProjectionType.Ortogonal, Color.Black) { }


public Point3D ToGlobal(Point3D point)

{

return new Point3D(point.X + _x, point.Y + _y, point.Z + _z);

}

public Point3D ToLocal(Point3D point)

{

return new Point3D(point.X - _x, point.Y - _y, point.Z - _z);

}

public override Pixel[] GetPixels()

{

return LastPixels = RasterizeService.GetPixels(GlobalVertexes, Edges, Enums.LineAlgType.DDA);

}

public void Move(float dx, float dy, float dz)

{

X += dx;

Y += dy;

Z += dz;

NotifyPropertyChanged(nameof(GlobalVertexes));

}

public void Rotate(float ax, float ay, float az)

{

for (int i = 0; i < _localVertexes.Length; i++)

{

_localVertexes[i].Rotate(ax, ay, az);

}

NotifyPropertyChanged(nameof(LocalVertexes));

NotifyPropertyChanged(nameof(GlobalVertexes));

}

public void Scale(float sx, float sy, float sz)

{

for (int i = 0; i < _localVertexes.Length; i++)

{

_localVertexes[i].Scale(sx, sy, sz);

}

_edgeLength = (float)Math.Sqrt(

Math.Pow(LocalVertexes[_edges[1]].X - LocalVertexes[_edges[0]].X, 2) +

Math.Pow(LocalVertexes[_edges[1]].Y - LocalVertexes[_edges[0]].Y, 2) +

Math.Pow(LocalVertexes[_edges[1]].Z - LocalVertexes[_edges[0]].Z, 2)

);

NotifyPropertyChanged(nameof(EdgeLength));

NotifyPropertyChanged(nameof(LocalVertexes));

NotifyPropertyChanged(nameof(GlobalVertexes));

}

}

public class Line2D : BaseFigure2D

{

public Line2D(Point2D p0, Point2D p1, LineAlgType algType, Color color) :

base

(

(int)(p0.X + p1.X) / 2,

(int)(p0.Y + p1.Y) / 2,

algType,

color

)

{

_localVertexes = new Point2D[]

{

ToLocal(p0),

ToLocal(p1),

};

_edges = new int[]

{

0,1

};

}

public Line2D(int x0, int y0, int x1, int y1, LineAlgType algType, Color color) :

this(new Point2D(x0, y0), new Point2D(x1, y1), algType, color)

{ }

public Line2D(int x0, int y0, int x1, int y1, LineAlgType algType) :

this(x0, y0, x1, y1, algType, Color.Black)

{ }

public Line2D(int x0, int y0, int x1, int y1) :

this(x0, y0, x1, y1, LineAlgType.DDA)

{ }

}

public class Cube : BaseFigure3D

{

public Cube(float x, float y, float z, float edgeLength,

LineAlgType algType, ProjectionType projectionType, Color color) :

base(x, y, z, edgeLength, algType, projectionType, color)

{

_localVertexes = new Point3D[]

{

new Point3D(-edgeLength/2,-edgeLength/2,-edgeLength/2),//0

new Point3D(-edgeLength/2,-edgeLength/2,+edgeLength/2),//1

new Point3D(+edgeLength/2,-edgeLength/2,-edgeLength/2),//2

new Point3D(+edgeLength/2,-edgeLength/2,+edgeLength/2),//3

new Point3D(-edgeLength/2,+edgeLength/2,-edgeLength/2),//4

new Point3D(-edgeLength/2,+edgeLength/2,+edgeLength/2),//5

new Point3D(+edgeLength/2,+edgeLength/2,-edgeLength/2),//6

new Point3D(+edgeLength/2,+edgeLength/2,+edgeLength/2),//7

};

_edges = new int[]

{

0,1,

0,2,

0,4,

1,3,

1,5,

2,3,

2,6,

3,7,

4,5,

4,6,

5,7,

6,7,

};

}

}

public static class MatrixOperationService

{

public static float[][] MatrixMultiply(float[][] matrixA, float[][] matrixB)

{

int aRows = matrixA.Length; int aCols = matrixA[0].Length;

int bRows = matrixB.Length; int bCols = matrixB[0].Length;

if (aCols != bRows)

throw new Exception("Non-conformable matrices in MatrixProduct");

float[][] result = MatrixCreate(aRows, bCols);

Parallel.For(0, aRows, i =>

{

for (int j = 0; j < bCols; ++j)

for (int k = 0; k < aCols; ++k)

result[i][j] += matrixA[i][k] * matrixB[k][j];

}

);

return result;

}

public static float[][] MatrixCreate(int rows, int cols)

{

float[][] result = new float[rows][];

for (int i = 0; i < rows; ++i)

result[i] = new float[cols];

return result;

}

}

public static class RasterizeService

{

public static Pixel[] GetPixels(Point2D[] points, int[] edges, LineAlgType algType)


{

List
pixels = new List
();

for (int i = 0; i < edges.Length; i += 2)

{

Pixel[] tempPixels = GetPixels(points[edges[i]], points[edges[i + 1]], algType);

if (tempPixels?.Length > 0) pixels.AddRange(tempPixels);

}

return pixels.ToArray();

}

public static Pixel[] GetPixels(Point3D[] points, int[] edges, LineAlgType algType)

{

List
pixels = new List
();

Point2D[] points2D = points.Select(p => new Point2D(p.X, p.Y)).ToArray();

for (int i = 0; i < edges.Length; i += 2)

{

Pixel[] tempPixels = GetPixels(points2D[edges[i]], points2D[edges[i + 1]], algType);

if (tempPixels?.Length > 0) pixels.AddRange(tempPixels);

}

return pixels.ToArray();

}

public static Pixel[] GetPixels(Point2D p0, Point2D p1, LineAlgType algType)

{

switch (algType)

{

case LineAlgType.BrezenhamReal:

{

return CalcBrezenhamReal(p0, p1);

}

case LineAlgType.BrezenhamInteger:

{

return CalcBrezenhamInteger(p0, p1);

}

case LineAlgType.DDA:

default:

{

return CalcDDA(p0, p1);

}

}

}

private static Pixel[] CalcDDA(Point2D p0, Point2D p1)

{

List
result = new List
();

if (p0.X == p1.X && p0.Y == p1.Y)

{

return null;

}

double L = (Math.Abs(p1.X - p0.X) >= Math.Abs(p1.Y - p0.Y))

? Math.Abs(p1.X - p0.X)

: Math.Abs(p1.Y - p0.Y);

double dx = (p1.X - p0.X) / L;

double dy = (p1.Y - p0.Y) / L;

double x = p0.X + 0.5 * Math.Sign(dx);

double y = p0.Y + 0.5 * Math.Sign(dy);

for (int i = 1; i <= L + 1; i++)

{

result.Add(new Pixel((int)Math.Truncate(x), (int)Math.Truncate(y)));

x += dx;

y += dy;

}

return result.ToArray();

}

private static Pixel[] CalcBrezenhamReal(Point2D p0, Point2D p1)

{

List
result = new List
();

if (p0.X == p1.X && p0.Y == p1.Y)

{

return null;

}

var steep = Math.Abs(p1.Y - p0.Y) > Math.Abs(p1.X - p0.X);

bool rever = false;

if (steep)

{

p0 = new Point2D(p0.Y, p0.X);

p1 = new Point2D(p1.Y, p1.X);

rever = true;

}

if (p0.X > p1.X)

{

Swap(ref p0, ref p1);

}

float dx = p1.X - p0.X;

float dy = p1.Y - p0.Y;

float sx = Math.Sign(dx);

float sy = Math.Sign(dy);

dx = Math.Abs(dx);

dy = Math.Abs(dy);

bool flag = false;

if (dy > dx)

{

Swap(ref dx, ref dy);

flag = true;

}

float f = dy / dx - 0.5f;

float x = p0.X;

float y = p0.Y;

while (x <= p1.X)

{

result.Add(new Pixel

(

(rever) ? (int)Math.Truncate(y) : (int)Math.Truncate(x),

(rever) ? (int)Math.Truncate(x) : (int)Math.Truncate(y)

));

if (f >= 0)

{

if (flag)

{

x += sx;

}

else

{

y += sy;

}

f--;

}

else

{

if (flag)

{

y += sy;

}

else

{

x += sx;

}

f += dy / dx;

}

}

return result.ToArray();

}

private static Pixel[] CalcBrezenhamInteger(Point2D p0, Point2D p1)

{

List
result = new List
();

if (p0.X == p1.X && p0.Y == p1.Y)

{

return null;

}

var steep = Math.Abs(p1.Y - p0.Y) > Math.Abs(p1.X - p0.X);

bool rever = false;

if (steep)

{

p0 = new Point2D(p0.Y, p0.X);

p1 = new Point2D(p1.Y, p1.X);

rever = true;

}

if (p0.X > p1.X)

{

Swap(ref p0, ref p1);

}

float dx = p1.X - p0.X;

float dy = p1.Y - p0.Y;

int sx = Math.Sign(dx);

int sy = Math.Sign(dy);

dx = Math.Abs(dx);

dy = Math.Abs(dy);

bool flag = false;

if (dy > dx)

{

Swap(ref dx, ref dy);

flag = true;

}

float fu = 2 * dy - dx;

int x = (int)p0.X;

int y = (int)p0.Y;

while (x <= p1.X)

{

result.Add(new Pixel

(

(rever) ? y : x,

(rever) ? x : y

));

if (fu >= 0)

{

if (flag)

{

x += sx;