Конференция "Media" » Кривая Безье
 
  • dmk © (29.05.16 15:34) [0]
    Всем привет!

    Есть кубическая или квадратичная функция Безье. В ней есть параметр t =[0..1]. X и Y рассчитывается в зависимости от этого параметра. Все бы хорошо, но при одинаковом шаге (например 0.023) данная f(x) разница между X и предыдущем X может быть очень большая или очень маленькая. Хотелось бы узнать, если кто занимался этой функцией, возможно ли t сделать адаптивной переменной? Т.е. в зависимости от убывания/возрастания f(x) менять t или рассчитывать t от желаемого X или Y?

    Нужно для равномерности отрисовки самой Безье и заливки.
    Тут есть пример:
    https://cloud.mail.ru/public/8Bm6/CcsrjWdR3

    Включить следующие галочки:
    Мод. Безье
    Сглаживание
    Заливка
    Прозрачность

    Расстояние между вертикальными полосами и есть та самая t.

    Буду рад услышать любые дельные советы.
  • dmk © (29.05.16 15:42) [1]
    Если кому не хочется EXE запускать, то вот скриншот:
    http://hostingkartinok.com/show-image.php?id=4665d0de147e0c430b89d919af1e8e24

    Содрал пример у _Rouse, правда доработал до квадратичной и линейной версии + сглаживание. На начальный пример не похоже почти.
  • Pavia © (29.05.16 16:52) [2]
    Можно. Делайте.
    Есть 2 метода.
    1) Подбор шага
    2) Подбор разбиения

    1)  Подбор как и в разбиении. Или если вы знакомы с градиентным методом с переменным шагом. Шаг параметр увеличивается или уменьшается в зависимости от требуемой точности отображения. Обычно 0.5 пикселя иногда 1/8 пикселя. За управляющие векторы кривая никогда не выходит поэтому оценку ошибки для Бизье 4 порядка достаточно просто. Как сумма по абсолютному значению двух упрочивающих векторов.
    2) Разбиение. Любую кривую Безье можно представить в виде двух кривых со состыкованных в этой точке.
    http://antigrain.com/research/adaptive_bezier/
    Код переведенный на паскаль есть в aggpas
  • dmk © (05.06.16 16:20) [3]
    Сделал коррекцию точек на прямой. Вроде рисует все ровно, но вот есть одна неувязочка:
    http://hostingkartinok.com/show-image.php?id=ff6b6322ce61723727ab68088937c5f4

    На сильно острых углах функция не работает :(
    Вернее работает, если задать шаг 0.1, но это приводит к избыточности точек самой кривой.
    Можно ли определить, в каких случаях функция Безье так себя ведет?!

    >Pavia ©   (29.05.16 16:52) [2]
    AGG малость «тормознутая» библиотека. Кроме того у него все рисуется через рекурсивную безье. Жесть как медленно. Я рисую строго по функции и точками. Получается очень шустро.
  • Pavia © (05.06.16 18:51) [4]

    > Можно ли определить, в каких случаях функция Безье так себя
    > ведет?!

    Можно считайте углы. Если они тупые, то нормально. Если острые, и очень острые, то надо бить сильнее.


    >  AGG малость «тормознутая» библиотека. Кроме того у него
    > все рисуется через рекурсивную безье. Жесть как медленно.

    Не замечал, что медленно. Но вариант, да не самый быстрый. Быстрее всегда бить на 16 участков, а для сложных случаев хватает 32.
  • dmk © (05.06.16 19:37) [5]
    >Можно считайте углы.
    В безье нет углов к сожалению. Там кубическое возрастание и обратная квадратичная коррекция.
  • Pavia © (06.06.16 07:12) [6]
    Зато у кривых Безье, ест базовые и опорные точки. Вот они образуют ломанную. У этой ломаной есть углы.
  • dmk © (06.06.16 08:11) [7]
    Нет там ничего такого. Это просто функция, которая вычисляет X и Y.
    Просто в некоторых случаях происходит удлинение сегментов. Конечно же логических.
    Все соединяется точками.

    http://hostingkartinok.com/show-image.php?id=61d3b9c7681c1e689f593a11377272c4

     //Цикл отрисовки кривой Безье
     //for i := 0 to maxI do
     while (t <= 1) do
     begin
       //Получаем координаты текущей точки
       fP0 := GetFloatBezierPoint(pA, pA1, pB1, pB, t);

       //Коррекция коэффициента функции t
       //в зависимости от величины сегмента
       //для равномерного распределения точек по кривой
       //..............................................

       if (i mod seg) = 0 then
       begin
         //Конечная точка сегмента
         nt := t + ts;
         fP1 := GetFloatBezierPoint(pA, pA1, pB1, pB, nt);

         //Рисуем прямоугольник вокруг сегмента
         if i <> 0 then
         begin
           eR := NormalizeRegion(Round(fP0.X), Round(fP0.Y), Round(fP.X), Round(fP.Y));
           sBmp.RectAA(eR, crYellow, 255, 32);
         end;

         //Пиксел на кривой
         sBmp.FloatQPixel(fP0.X, fP0.Y, crWhite, 255, glvOpacity);
         sBmp.FloatQPixel(fP0.X, fP0.Y, crWhite, 255, glvOpacity);
         sBmp.FloatQPixel(fP0.X, fP0.Y, crWhite, 255, glvOpacity);
         sBmp.FloatQPixel(fP0.X, fP0.Y, crWhite, 255, glvOpacity);

         //Ширина и высота сегмента
         //образованного предыдущей и текущей точками
         fW := Abs(fP1.X - fP0.X);
         fH := Abs(fP1.Y - fP0.Y);

         h := (fW >= fH);

         //Длина сегмента
         if (fW <> 0) and (fH <> 0) then
         begin
           sqrtSL := sqrt(fW * fW + fH * fH);
           sc := 1 / sqrtSL; //Коррекция шага текущего сегмента
           TSL := TSL + sqrtSL; //Общая длина в пикселах (сумма квадратов)
         end;

         s1 := Ansistring(FloatToStrF(sc, ffNumber, 18, 2)); //Соотношение длины сегмента к t
         sBmp.DrawHText5x7(eR.EX + 3, eR.Y + (eR.H div 2) - 4, s1, 1, crWhite, 255, 32);

         fP := fP0;
       end;//if (i mod seg)

       inc(i);

       //..............................................

       //Рисуем кривую
       sBmp.FloatQPixel(fP0.X, fP0.Y, crLtGreen, 255, glvOpacity);

       //Смещаемся по функции
       t := t + (ts * sc); //Равномерное распределение точек
       //t := t + ts; //Неравномерное распределение точек
     end;



    Ну и сама кривая:
    [X,Y] = (1-t)^3A + 3t(1-t)^2A1 + 3t^2(1-t)B1 + Bt^3
  • dmk © (06.06.16 08:14) [8]
    Не знаю как математически отловить удлинение сегмента :(
  • Pavia © (06.06.16 19:27) [9]
    Вот вам примерный код.

    step:=0.1; // начальное разбиение. Сишком большим лучше не делать.
    while (t <= 1) do
     begin
    repeat
    P0 := GetFloatBezierPoint(pA, pA1, pB1, pB, t);
    P1 := GetFloatBezierPoint(pA, pA1, pB1, pB, t+step*0.5);
    P2 := GetFloatBezierPoint(pA, pA1, pB1, pB, t+step);
    dH:=DistancePointLine(p1, Line(P0,p2)); // Расстояние от точки до прямой.
    if (dh>=0.5) then step:=step*0.5; // Слишком большой изгиб.
    if (dh<=0.1) and (step<0.1) then step:=step*2; // слишком маленький шаг
    until (dh<0.5);
    DrawLine(P0,P2);
    t:=t+step;
    end;

  • dmk © (10.06.16 05:20) [10]
    Разобрался! Спасибо всем участникам.
    http://hostingkartinok.com/show-image.php?id=2e2f9dfa0d43ab1e16a67bfa9d6f5fc0
  • dmk © (12.06.16 02:47) [11]
    Можно её "потрогать" :)
    Тут EXE: https://cloud.mail.ru/public/HzV6/i3HrSJfJz

    А здесь посмотреть:
    http://hostingkartinok.com/show-image.php?id=7a4fee9f950305f203e0eb99c4ca45ff
 
Конференция "Media" » Кривая Безье
Есть новые Нет новых   [118455   +50][b:0][p:0.003]