Главная страница
Навигация по странице:

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

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

  • Ответы на контрольные вопросы Что такое афинные преобразования

  • С помощью каких формул задаются афинные преобразования

  • Компьютерная графика ЛР2. Афинные преобразования


    Скачать 0.66 Mb.
    НазваниеАфинные преобразования
    АнкорКомпьютерная графика ЛР2
    Дата31.01.2023
    Размер0.66 Mb.
    Формат файлаdocx
    Имя файлаNesterov_S_D_PO-91z_LR_3.docx
    ТипЛабораторная работа
    #914088

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

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

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

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

    Лабораторная работа №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;

    }

    else

    {

    y += sy;

    }

    fu -= 2 * dx;

    }

    else

    {

    if (flag)

    {

    y += sy;

    }

    else

    {

    x += sx;

    }

    fu += 2 * dy;

    }

    }

    return result.ToArray();

    }

    public static Pixel[] CirclePixels(Point2D center, float radius)

    {

    List
    result = new List
    ();

    float x = 0;

    float y = radius;

    float delta = 1 - 2 * radius;

    float error = 0;

    while (y >= x)

    {

    result.Add(new Pixel((int)(center.X + x), (int)(center.Y + y)));

    result.Add(new Pixel((int)(center.X + x), (int)(center.Y - y)));

    result.Add(new Pixel((int)(center.X - x), (int)(center.Y + y)));

    result.Add(new Pixel((int)(center.X - x), (int)(center.Y - y)));

    result.Add(new Pixel((int)(center.X + y), (int)(center.Y + x)));

    result.Add(new Pixel((int)(center.X + y), (int)(center.Y - x)));

    result.Add(new Pixel((int)(center.X - y), (int)(center.Y + x)));

    result.Add(new Pixel((int)(center.X - y), (int)(center.Y - x)));

    error = 2 * (delta + y) - 1;

    if ((delta < 0) && (error <= 0))

    {

    delta += 2 * ++x + 1;

    continue;

    }

    if ((delta > 0) && (error > 0))

    {

    delta -= 2 * --y + 1;

    continue;

    }

    delta += 2 * (++x - --y);

    }

    return result.ToArray();

    }

    }

    public class CustomCanvas : NotifyPropertyChange

    {

    protected Bitmap _dataCanvas;

    protected ObservableCollection _graficObjects = new ObservableCollection();

    private readonly int _width;

    private readonly int _height;

    protected readonly int _length;

    protected readonly Color _color;

    public Bitmap DataCanvas

    {

    get { return _dataCanvas; }

    private set

    {

    Set(ref _dataCanvas, value);

    }

    }

    public ObservableCollection GraficObjects

    {

    get => _graficObjects;

    set

    {

    Set(ref _graficObjects, value);

    }

    }

    public int Width => _width;

    public int Height => _height;

    public CustomCanvas(int width, int height, int length, Color color)

    {

    DataCanvas = new Bitmap(width, height);

    _width = width;

    _height = height;

    _length = length;

    _color = color;

    ClearCanvas(DataCanvas);

    GraficObjects.CollectionChanged += GraficObjects_CollectionChanged;

    }

    protected void ClearCanvas(Bitmap bitmap)

    {

    using (var g = Graphics.FromImage(bitmap))

    {

    g.Clear(_color);

    }

    }

    public void DrawPixel(Bitmap bitmap, int x, int y, Color color)

    {

    if (x >= DataCanvas.Width || y >= DataCanvas.Height || x <= 0 || y <= 0)

    {

    return;

    }

    bitmap.SetPixel(x, y, color);

    }

    public void DrawGraficObject(IGraficObject graficObject)

    {

    Bitmap result = new Bitmap(Width, Height);

    ClearCanvas(result);

    if (!_graficObjects.Any(p => p.Id == graficObject.Id))

    {

    _graficObjects.Add(graficObject);

    graficObject.PropertyChanged += GraficObject_PropertyChanged;

    }

    RedrawCanvas(result);

    DataCanvas = result;

    }

    private void RedrawCanvas(Bitmap bitmap)

    {

    foreach (IGraficObject graficObject in _graficObjects)

    {

    Pixel[] pixels = null;

    switch (graficObject)

    {

    case IFigure3D f3D:

    Point3D[] points = ProjectionService.Project(f3D, _camera);

    pixels = RasterizeService.GetPixels(points, f3D.Edges, f3D.AlgType);

    break;

    case IFigure2D f2D:

    case IGraficObject go:

    default:

    pixels = graficObject.GetPixels();

    break;

    }

    DrawPixels(bitmap, pixels, graficObject.Color);

    }

    }

    public void DrawPixels(Bitmap bitmap, Pixel[] pixels, Color color)

    {

    foreach (Pixel p in pixels)

    {

    DrawPixel(bitmap, p.X, p.Y, color);

    }

    }

    private void GraficObject_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)

    {

    DrawGraficObject(sender as IGraficObject);

    }

    public void Move(IFigure2D figure, float dx, float dy)

    {

    figure.Move(dx, dy);

    DrawGraficObject(figure);

    }

    public void Scale(IFigure2D figure, float sx, float sy)

    {

    figure.Scale(sx, sy);

    DrawGraficObject(figure);

    }

    public void Rotate(IFigure2D figure, float angle)

    {

    figure.Rotate(angle);

    DrawGraficObject(figure);

    }

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

    {

    figure.Move(dx, dy, dz);

    DrawGraficObject(figure);

    }

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

    {

    figure.Scale(sx, sy, sz);

    DrawGraficObject(figure);

    }

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

    {

    figure.Rotate(ax, ay, az);

    DrawGraficObject(figure);

    }

    private void GraficObjects_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)

    {

    NotifyPropertyChanged(nameof(GraficObjects));

    }

    }

    Пример работы программы

    Главное окно приложения изображено Рисунок 8 – Главное окно программы.



    Рисунок 8 – Главное окно программы

    Окно добавления фигур изображено Рисунок 9 – Окно добавления фигуры.



    Рисунок 9 – Окно добавления фигуры

    Добавление линии изображено Рисунок 10 – Добавление линии.



    Рисунок 10 – Добавление линии

    Добавление куба изображено Рисунок 11 – Добавление .



    Рисунок 11 – Добавление куба

    Результат добавления фигур изображён Рисунок 12 – .



    Рисунок 12 – Результат добавления фигур

    Результат масштабирования линии изображён Рисунок 13 – .



    Рисунок 13 – Результат масштабирования линии

    Смещение линии изображено Рисунок 14 – Смещение линии изображено.



    Рисунок 14 – Смещение линии изображено

    Поворот линии изображён Рисунок 15 – Поворот линии.



    Рисунок 15 – Поворот линии

    Результат масштабирования куба изображён Рисунок 16 – Результат масштабирования куба.



    Рисунок 16 – Результат масштабирования куба

    Смещение куба изображено Рисунок 17 – Смещение куба.



    Рисунок 17 – Смещение куба

    Результат поворота куба изображён Рисунок 18 – Результат поворота куба.



    Рисунок 18 – Результат поворота куба

    Ответы на контрольные вопросы


    1. Что такое афинные преобразования?

    Аффинными преобразованиями называют три базовые операции:

    • перенос (перемещение) изображения;

    • масштабирование (увеличение или уменьшение размеров) изображения;

    • поворот изображения (употребляют также термины вращение, изменение ориентации).


    1. С помощью каких формул задаются афинные преобразования?

    Двумерные аффинные преобразования

    Параллельный перенос



    Масштабирование



    Поворот



    1. Приведите пример расчетов двумерных афинных преобразований для отрезка (координаты выбрать самостоятельно)

    P1 = [10 ; 20]

    P2 = [30 ; 50]

    Перенос по x на 10, по y на 12

    x′1 = 10 +10 = 20

    y′1 = 20 +12 = 32

    x′2 = 30 +10 = 40

    y′2 = 50 +12 = 62

    P′1 = [20 ; 32]

    P′2 = [40 ; 62]

    Масштабирование в 1.5 по обеим координатам

    x′1 = 10 * 1.5 = 15

    y′1 = 20 * 1.5 = 30

    x′2 = 30 * 1.5 = 45

    y′2 = 50 * 1.5 = 75

    P′1 = [15 ; 30]

    P′2 = [45 ; 75]

    Поворот на 75⁰

    x′1 = 10 * 0.259 – 30 * 0.966 = -16.73

    y′1 = 10 * 0.966 + 30 * 0.259 = 14.836

    x′2 = 30 * 0.259 – 50 * 0.966 = -40.532

    y′2 = 30 * 0.966 + 50 * 0.259 = 41.919

    P′1 = [-16.73 ; 14.836]

    P′2 = [-40.532 ; 41.919]


    написать администратору сайта