C#: Отражение фигуры относительно прямой линии

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

На самом деле задача отражения фигуры относительно заданной прямой это три задачи. Первая — это сдвиг фигуры по оси X, Вторая — поворот фигуры на заданный угол, Третья — отражение фигуры относительно оси X.

Почему задачи три? Все просто. Само отражение фигуры (относительно оси X) — очень простая задача. Все что необходимо сделать — поменять знак координаты Y у всех точек фигуры. Если говорить об отражении относительно оси Y, то знак нужно менять у координат X. Однако в данном случае роль зеркала играет ось X (та самая прямая относительно которой нужно сделать поворот). Поэтому если мы говорим о задаче отражения фигуры относительно какой-либо прямой, то нам нужно проделать следующие шаги:

1) Сдвинуть прямую и отражаемую фигуру влево или вправо по оси X на N пикселей. Где N количество пикселей, чтобы прямая проходила через начало координат;
2) Повернуть прямую и отражаемую фигуру на alpha градусов, так чтобы наша прямая «слилась» с осью X;
3) Отразить нашу фигуру относительно нужной плоскости;
4) Повернуть прямую и отражаемую фигуру на -alpha градусов;
5) Сдвинуть прямую и отражаемую фигуру вправо или влево по оси X на N пикселей;

Так как в моем условии прямая проходила через начало координат, то пункты 1 и 5 в моем примере будут опущены.

Решение задачи выглядит так:
Создаем приложение Windows Forms и добавляем компонент PictureBox. Открываем код события загрузки формы Form1_Load и в нем пишем следующий код.

//Полагаем что начало координат это левый верхний угол формы.
pictureBox1.Image = new Bitmap(pictureBox1.Width, pictureBox1.Height);

Graphics g = Graphics.FromImage(pictureBox1.Image);

int x = 200, y = 300, w = 200, h = 100; //координаты прямоугольника исходные
int lineX = 400, lineY = 400; //координаты второй точки линии, проходящей через начало координат

g.DrawLine(Pens.LightBlue, new Point(0, 0), new Point(lineX, lineY)); //линия относительно которой отражаем
g.DrawRectangle(Pens.Black, x, y, w, h); //исходный прямоугольник

double rotate = -Math.Atan(lineX / lineY); //угол на который нужно повернуть фигуру, чтобы линия совпала с осью Ox

//поворачиваем прямоугольник на данный угол
var p = new PointF[] {
    new PointF((float)(x * Math.Cos(rotate) - y * Math.Sin(rotate)), (float)(x * Math.Sin(rotate) + y * Math.Cos(rotate))),
    new PointF((float)((x + w) * Math.Cos(rotate) - y * Math.Sin(rotate)), (float)((x + w) * Math.Sin(rotate) + y * Math.Cos(rotate))),
    new PointF((float)((x + w) * Math.Cos(rotate) - (y + h) * Math.Sin(rotate)), (float)((x + w) * Math.Sin(rotate) + (y + h) * Math.Cos(rotate))),
    new PointF((float)(x * Math.Cos(rotate) - (y + h) * Math.Sin(rotate)), (float)(x * Math.Sin(rotate) + (y + h) * Math.Cos(rotate))),
};

//зеркальное отражение относительно oX
for(int i = 0; i < p.Length; ++i)
{
    p[i].Y = -p[i].Y ;
}

//поворачиваем прямоугольник назад на тот же угол
rotate = -rotate;
var p3 = new PointF[] {
    new PointF((float)(p[0].X * Math.Cos(rotate) - p[0].Y * Math.Sin(rotate)), (float)(p[0].X * Math.Sin(rotate) + p[0].Y * Math.Cos(rotate))),
    new PointF((float)(p[1].X * Math.Cos(rotate) - p[1].Y * Math.Sin(rotate)), (float)(p[1].X * Math.Sin(rotate) + p[1].Y * Math.Cos(rotate))),
    new PointF((float)(p[2].X * Math.Cos(rotate) - p[2].Y * Math.Sin(rotate)), (float)(p[2].X * Math.Sin(rotate) + p[2].Y * Math.Cos(rotate))),
    new PointF((float)(p[3].X * Math.Cos(rotate) - p[3].Y * Math.Sin(rotate)), (float)(p[3].X * Math.Sin(rotate) + p[3].Y * Math.Cos(rotate))),

};

//рисуем отражение красным цветом
g.DrawPolygon(Pens.Red, p3);
Запись опубликована в рубрике C# с метками , , , , , , , , , . Добавьте в закладки постоянную ссылку.