Построение волнистой линии через Кривые Безье

в 14:54, , рубрики: .net, кривые безье, математика

Доброе время суток. Сегодня я хочу рассказать вам про рисование симметричной волнистой линии при помощи Кривых Безье, используя только 2 точки.

Предисловие

При создании CAD-систем, часто возникает необходимость рисования не просто прямых линий, а волнистых или ломаных. Так как в обоих случаях линия симметрична относительно прямой, проходящей через начальную и конечные точки, то необходимо вычислить точки, лежащие на параллельных главной прямых. О том, как это сделать, пойдет речь ниже.

Немного математики

Рассмотрим небольшой отрезок. Кривая Безье для этого отрезка должна отдаленно напоминать синусоиду. Хотя и не будет являться ей.
Пусть А — начальная точка, а B — конечная.
Известные точки
Точка C — середина отрезка АB
Середина AB
Точки D и E — середины отрезков AC и CB соответственно
Середина AC
Середина CB
Теперь необходимо получить точки D' и E'. У этих точек одно свойство — они принадлежат отрезкам, которые параллельны AB, но находятся на расстоянии от него.
Рассмотрим вектор Вектор AB. Необходимо найти два вектора, которые перпендикулярны вектору Вектор AB.
Координаты AB
Скалярное произведение векторов
Скалярное произведение векторов
Это обыкновенное линейное уравнение с двумя переменными, которое, как известно, имеет бесконечное множество решений.
Для нахождения первого решения примем image за параметр, влияющий на длину вектора.
Тогда координаты первого вектора image будут равны:
image
Второй перпендикулярный вектор вычисляется на основе первого.
image
Для получения координат точек D' и E', необходимо прибавить к координатам точки D координаты вектора image, а к координатам точки E — координаты вектора image.
Зная координаты точек A, D', E' и B, можно построить зигзаг или кривую Безье.

Немножко программирования

Нарисуем кривую Безье при помощи технологии GDI+ с использованием Windows Forms.
Для начала, опишем класс Vector2

public class Vector2
{
  public int X,Y //координаты вектора
  //конструктор
  public Vector2(int x,  int y)
  {
     X=x; 
     Y=y;
  }
}

Так же объявим пару переменных для хранения параметров

 int x0,y0;//координаты первой точки
 int x1,y1;//координаты второй точки
 int amplitude;//параметр a

 Pen pen = new Pen(new SolidBrush(Color.Black)); //кисть для рисования простой линии
  Pen pen2 = new Pen(new SolidBrush(Color.Red));//кисть для рисования кривой.

Теперь напишем код для рисования.

 public void Draw(Graphics g)
 {
            
            g.SmoothingMode = SmoothingMode.HighQuality; //включаем Anti-Aliasing
            // координаты стартовой точки
            Point mainStart = new Point(x0, y0);
            // координаты конечной точки
            Point mainEnd = new Point(x1, y1);
            //С - середина отрезка AB
            Point mainCenter0 = new Point((mainStart.X + mainEnd.X) / 2, (mainStart.Y + mainEnd.Y) / 2);
            //D- середина отрезка AС
            Point mainCenter1 = new Point((mainStart.X + mainCenter0.X) / 2, (mainStart.Y + mainCenter0.Y) / 2);
            //E- середина отрезка СB
            Point mainCenter2 = new Point((mainCenter0.X + mainEnd.X) / 2, (mainCenter0.Y + mainEnd.Y) / 2);
            //Вектор AB
            Vector2 lineVector = new Vector2(mainEnd.X - mainStart.X,  mainEnd.Y - mainStart.Y );
            //вектор a1
            Vector2 orthoVector1 = new Vector2( amplitude,  -lineVector.X * amplitude / lineVector.Y );
            //вектор a2
            Vector2 orthoVector2 = new Vector2(-orthoVector1.X, -orthoVector1.Y);

            //очищаем экран
            g.Clear(Color.White);
             
            //транслируем точку D в точку D'
            mainCenter1.Offset(orthoVector1.x, orthoVector1.y);
             
            //транслируем точку E в точку E'
            mainCenter2.Offset(orthoVector2.x, orthoVector2.y);
            
            //рисуем кривую Безье
            g.DrawBezier(pen2, mainStart, mainCenter1, mainCenter2, mainEnd);
            //рисуем простую линию
            g.DrawLine(pen, mainStart, mainEnd);
}

Теперь осталось вызвать этот метод для вашего объекта Graphics.

В результате работы метода должно получиться что-то подобное:
image

Всем спасибо за внимание.

Автор: denismaster

Источник


* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js