ВУЗ: Не указан
Категория: Не указан
Дисциплина: Не указана
Добавлен: 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;