Векторная графика в dlib

На сайте LightHouse Software вышла очередная моя гостевая статья – “Векторая графика в dlib”. Рассматривается рендеринг многоугольников и фигур Безье средствами dlib.image, dlib.math и dlib.geometry.

Дуальные числа и касательная к кривой Безье

Дуальные числа, поддержка которых не так давно появилась в dlib (dlib.math.dual), обладают замечательным свойством: с их помощью можно реализовать автоматическое дифференцирование функций. Если производить вычисления не над вещественными, а над дуальными числами, то в вещественной части результата получается значение самой функции в заданной точке, а в дуальной – значение ее производной.
При этом если оформить функцию в виде шаблона, она без лишних телодвижений расширяется до множества дуальных чисел. Следующий пример показывает дифференцирование простейшей квадратичной функции:

import std.stdio;
import dlib.math.dual;

T parabola(T)(T x)
{
    return x*x;
}

void main()
{
    float x = 1.0f;

    Dualf eval = parabola(Dualf(x, 1.0f));
    float value = eval.re;
    float deriv = eval.du;
    
    writeln(deriv);
}

При запуске программа выдаст значение производной – 2 для точки 1. Правильность результата нетрудно проверить, зная формулу производной степенной функции: если f(x) = xn, то f ‘(x) = nxn-1. Следовательно, если f(x) = x2, то f ‘(x) = 2x.

Теперь начинается самое интересное. Попробуем вместо скалярных величин взять векторные и дифференцировать функцию кривой Безье (dlib.geometry.bezier) для двумерного случая:

import dlib.math.dual;
import dlib.math.vector;
import dlib.geometry.bezier;

alias DualVector2f = Vector!(Dualf, 2);

void main()
{
    float t = 0.5f;
    
    DualVector2f eval = bezierCurveFunc2D(
        DualVector2f(Dualf(0.0f), Dualf(0.0f)),
        DualVector2f(Dualf(1.0f), Dualf(1.0f)),
        DualVector2f(Dualf(2.0f), Dualf(1.0f)),
        DualVector2f(Dualf(3.0f), Dualf(0.0f)),
        Dualf(t, 1.0f));
}

Результирующий вектор eval будет содержать в вещественной части точку на кривой, а в дуальной – вектор касательной к кривой в этой точке, который нам остается только нормировать:

Vector2f point = Vector2f(eval.x.re, eval.y.re);
Vector2f tangent = Vector2f(eval.x.du, eval.y.du).normalized;

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

Обновление dlib

Состоялось серьезное обновление набора библиотек dlib. В числе нововведений:

  • Появилась начальная поддержка быстрого преобразования Фурье (FFT) в dlib.image. Возможна фильтрация и свертка изображений (со стороной 2^n) в частотной области;
  • Обновлен пакет dlib.math, добавлена реализация комплексных и дуальных чисел, а также внесены исправления и дополнения в dlib.math.matrix3x3 и dlib.math.matrix4x4;
  • Обновлен пакет dlib.geometry, добавлен класс ориентированных боксов (OBB), трехмерных треугольников и полигональных мешей. Реализована проверка на пересечение между сферой и треугольником, а также сферой и OBB. Добавлен модуль dlib.geometry.bezier с реализацией кривых Безье.

Иллюстрация FFT-свертки: быстрое синтетическое боке (оптическое размытие):

Изменения доступны в ревизии r21 и выше. В ближайшем будущем ожидается первый релиз проекта.

http://code.google.com/p/dlib/