netlib.narod.ru< Назад | Оглавление | Далее >

Вывод уравнений канонической кривой

Подобно кривой Безье канонический сплайн — это полином третьего порядка, который можно записать в виде параметрических уравнений общего вида:


x(t) = ax · t3 + bx · t2 + cx · t + dx

y(t) = ay · t3 + by · t2 + cy · t + dy


где t изменяется от 0 до 1. Первые производные этих уравнений будут таковы:


x'(t) = 3ax · t2 + 2bx · t + cx

y'(t) = 3ay · t2 + 2by · t + cy


Рассмотрим четыре точки, обозначенные p0, p1, p2 и p3. Я собираюсь вывести формулы для сегмента p1 – p2, форма которого определяется этой парой точек, а также парой соседних точек, p0 и p3. Во-первых, допустим, что кривая начинается в точке p1 и заканчивается в точке p2:


x(0) = x1

y(0) = y1

x(1) = x2

y(1) = y2


Из параметрических функций общего вида можно вывести такие уравнения:


dx = x1

dy = y1

ax + bx + cx + dx = x2

ay + by + cy + dy = y2


Другие допущения касаются угла наклона линии в точках p1 и p2. Допустим, угол наклона в точке p1 является произведением натяжения (обозначим его через T) и угла наклона прямой, проведенной через точки p0 и p2. Аналогично предполагается, что угол наклона в точке p1 равняется произведению натяжения на угол наклона прямой, проведенной через точки p1 и p3.


x'(0) = T(x2 – x0)

y'(0) = T(y2 – y0)

x'(1) = T(x3 – x1)

y'(1) = T(y3 – y1)


Из первых производных параметрических уравнений общего вида находим:


cx = T(x2 – x0)

cy = T(y2 – y0)

3ax + 2bx + cx = T(x3 – x1)

3ay + 2by + cy = T(y3 – y1)


Выполнив алгебраическое преобразование и решив систему уравнений, получаем:


ax = T(x2 – x0) + T(x3 – x1) + 2x1 – 2x2

ay = T(y2 – y0) + T(y3 – y1) + 2y1 – 2y2

bx = –2T(x2 – x0) – T(x3 – x1) – 3x1 + 3x2

by = –2T(y2 – y0) – T(y3 – y1) – 3y1 + 3y2

cx = T(x2 – x0)

cy = T(y2 – y0)

dx = x1

dy = y1


Программа CanonicalSplineManual позволяет убедиться, что мы не ошиблись при выводе этих констант.

CanonicalSplineManual.cs

  //------------------------------------------------------
  // CanonicalSplineManual.cs (C) 2001 by Charles Petzold
  //------------------------------------------------------
  using System;
  using System.Drawing;
  using System.Windows.Forms;

  class CanonicalSplineManual: CanonicalSpline
  {
      public new static void Main()
      {
          Application.Run(new CanonicalSplineManual());
      }
      public CanonicalSplineManual()
      {
          Text = "Canonical Spline \"Manually\" Drawn";
      }
      protected override void OnPaint(PaintEventArgs pea)
      {
          base.OnPaint(pea);

          CanonicalSpline(pea.Graphics, Pens.Red, apt, fTension);
      }
      void CanonicalSpline(Graphics grfx, Pen pen, Point[] apt, float T)
      {
          CanonicalSegment(grfx, pen, apt[0], apt[0], apt[1], apt[2], T);
          CanonicalSegment(grfx, pen, apt[0], apt[1], apt[2], apt[3], T);
          CanonicalSegment(grfx, pen, apt[1], apt[2], apt[3], apt[3], T);
      }
      void CanonicalSegment(Graphics grfx, Pen pen, Point pt0, Point pt1, 
                           Point pt2, Point pt3, float T)
      {
          Point[] apt = new Point[10];

          float SX1 = T * (pt2.X - pt0.X);
          float SY1 = T * (pt2.Y - pt0.Y);
          float SX2 = T * (pt3.X - pt1.X);
          float SY2 = T * (pt3.Y - pt1.Y);
          float AX = SX1 + SX2 + 2 * pt1.X - 2 * pt2.X;
          float AY = SY1 + SY2 + 2 * pt1.Y - 2 * pt2.Y;
          float BX = -2 * SX1 - SX2 - 3 * pt1.X + 3 * pt2.X;
          float BY = -2 * SY1 - SY2 - 3 * pt1.Y + 3 * pt2.Y;
          float CX = SX1;
          float CY = SY1;
          float DX = pt1.X;
          float DY = pt1.Y;

          for (int i = 0; i < apt.Length; i++)
          {
              float t = (float)i / (apt.Length - 1);
              apt[i].X = (int) (AX * t * t * t + BX * t * t + CX * t + DX);
              apt[i].Y = (int) (AY * t * t * t + BY * t * t + CY * t + DY);
          }
          grfx.DrawLines(pen, apt);
      }
  }

Здесь я хочу обратить ваше внимание на пару моментов. Метод CanonicalSpline обрабатывает только массивы из четырех элементов и трижды вызывает CanonicalSegment, рисуя каждый раз по одному сегменту. С первым и последним сегментами нужно обращаться по-особому, поскольку кривая задана всего лишь тремя точками, а не четырьмя.

Для рисования каждого сегмента метод CanonicalSegment использует массив из 10 структур Point. Этого маловато для получения гладкой кривой, но вполне достаточно, чтобы продемонстрировать, что он действительно неплохо воспроизводит метод DrawCurve, реализованный в классе Graphics.

В главах 15 и 19 мы еще встретимся с программами, использующими кривые Безье и канонические сплайны.


netlib.narod.ru< Назад | Оглавление | Далее >

Сайт управляется системой uCoz