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

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

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

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

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

  • Что такое растровое изображение

  • Для чего нужны алгоритмы растеризации отрезков

  • Какие ещё алгоритмы растеризации отрезков существуют

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


    Скачать 417.87 Kb.
    НазваниеАлгоритмы растеризации отрезков
    АнкорКомпьютерная графика ЛР1
    Дата31.01.2023
    Размер417.87 Kb.
    Формат файлаdocx
    Имя файлаNesterov_S_D_PO-91z_LR_1.docx
    ТипЛабораторная работа
    #914086

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

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

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

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

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

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

    На тему: «Алгоритмы растеризации отрезков»

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

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

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

    Петрик Е.А.

    Курск, 2022

    Задание

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

    Реализовать:

    • алгоритм ЦДА;

    • алгоритм Брезенхема;

    • целочисленный алгоритм Брезенхема.



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

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



    Рисунок 1 – Блок-схема алгоритма ЦДА

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



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



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

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



    Рисунок 4 – Блок-схема целочисленного алгоритма Брезенхема



    Рисунок 5 – Блок-схема целочисленного алгоритма Брезенхема

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

    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 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 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 IFigure : IGraficObject

    {

    LineAlgType AlgType { get; set; }

    int[] Edges { get; }

    }

    public interface IGraficObject : INotifyPropertyChanged

    {

    Guid Id { get; }

    Color Color { get; set; }

    Pixel[] LastPixels { get; }

    Pixel[] GetPixels();

    }

    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 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 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 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);

    }

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

    {

    NotifyPropertyChanged(nameof(GraficObjects));

    }

    }

    public static class Swapper

    {

    public static void Swap(ref T variable0, ref T variable1)

    {

    (variable1, variable0) = (variable0, variable1);

    }

    }

    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(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();

    }

    }

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

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



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

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



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

    Добавление линии, построенной по алгоритму ЦДА изображено Рисунок 8 – Добавление линии, построенной по алгоритму ЦДА.



    Рисунок 8 – Добавление линии, построенной по алгоритму ЦДА

    Добавление линии, построенной по вещественному алгоритму Брезенхема изображено Рисунок 9 – Добавление линии, построенной по вещественному алгоритму Брезенхема.



    Рисунок 9 – Добавление линии, построенной по вещественному алгоритму Брезенхема

    Добавление линии, построенной по целочисленному алгоритму Брезенхема изображено Рисунок 10 – Добавление линии, построенной по целочисленному алгоритму Брезенхема.



    Рисунок 10 – Добавление линии, построенной по целочисленному алгоритму Брезенхема

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



    Рисунок 11 – Результат добавления линий

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


    1. Что такое пиксель?

    Пиксель – это минимальная единица, элемент, из чего состоит изображение – точка определенного цвета, которая выводится на экране в заданном месте.


    1. Что такое растровое изображение?

    Изображение, представляющее собой сетку пикселей - цветных точек на мониторе, бумаге и других отображающих устройствах.


    1. Для чего нужны алгоритмы растеризации отрезков?

    Графические примитивы имеют непрерывную (аналоговую) природу, а изображение строится, как правило, на экране растрового дисплея, то есть получаемое изображение носит дискретный характер.


    1. Какие ещё алгоритмы растеризации отрезков существуют?

    • Алгоритм DDA-линии – простой алгоритм, использующий вещественную арифметику.

    • Алгоритм Брезенхэма – оптимизированный алгоритм, использующий целочисленную арифметику и только операции сложения и вычитания.

    • Алгоритм Ву – модифицированный алгоритм Брезенхэма, обеспечивающий сглаживание.


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