Главная страница
Top.Mail.Ru    Яндекс.Метрика
Текущий архив: 2007.08.05;
Скачать: CL | DM;

Вниз

Кривые Безье   Найти похожие ветки 

 
Jimmy   (2006-10-31 18:58) [0]

Написал программу для построения графиков в векторном формате с помощью PolyBezier. Но чтобы приближение было хорошим, пришлось брать точки с очень маленьким шагом - в 2 пикселя. Если шаг больше, то кривые Безье в некотрых
местах сильно отличаются от настоящего графика. Вероятно, если кривизна не большая, то шаг можно увеличивать, если сильная - уменьшать. Но может быть существуют готовые алгоритмы выбора точек для качественной апроксимации
графиков кривыми Безье? Или я что-то не понимаю? Заранее спасибо.


 
MBo ©   (2006-10-31 19:35) [1]

Как ты рассчитываешь кривые Безье?


 
Jimmy   (2006-10-31 20:02) [2]

Сначала заполняю массив a:array[1..n]of TPoint. Перебираю значения пикселей по горизонтали с шагом, например 2, заношу в a[i].x, для каждого x нахожу с помощью функции соответствующее знаяение y в пикселях, заношу в a[i].y. И в конце один раз, что-то вроде PolyBezier(a,31).


 
Pavia ©   (2006-10-31 20:13) [3]


> Перебираю значения пикселей по горизонтали с шагом

Безье лучше строиться по другому. Как
x:=X(t);
y:=Y(t);
Число точек можешь выбрать как длина ломанной умноженная на Pi.


 
Pavia ©   (2006-10-31 21:38) [4]

Я перестраховался и на Pi можно и не множить.


 
Jimmy   (2006-10-31 21:39) [5]

Pavia! Не совсем понял Ваш ответ. Так следует строить кривые Безье с помощью команды PolyBezier или нет? Нельзя ли поподробнее описать алгоритм построения графика Вашим способом? Также непонятна фраза относительно числа точек.


 
Pavia ©   (2006-10-31 23:40) [6]


// Hарисовать кривую Безье
//R(t) = P0*(1-t)^3 + P1 * t * (1-t)^2 + P2 * t^2 * (1-t) + P3 * t^3 ,
//   где 0<=t<=1
//P0,P3 - опорные точки
//P1,P2 - управляющие точки и
procedure DrawBezier(Canvas:TCanvas; P0,P1,P2,P3:TPoint);
var
LenP,i:Integer;
Step,t,q0,q1,q2,q3,qx,qy:Real;
begin
LenP:=50;
//Можно
//LenP:=Round(LenLine(p0,p1)+LenLine(p1,p2)+LenLine(p2,p3))/10
//function LenLine(P0,P1:TPoint):Real;
//begin
//result:=sqrt(sqr(P0.X-P1.X)+sqr(P0.Y-P1.Y));
//end;

Step:=1/LenP;
Canvas.MoveTo(P0.X,P0.Y);
For i:=0 to LenP do
begin
t:=i*step;
q0:=(1-t)*(1-t)*(1-t);
q1:=3*(1-t)*(1-t)*t;
q2:=3*(1-t)*t*t;
q3:=t*t*t;
qx:=P0.X*q0+P1.X*q1+P2.X*q2+P3.X*q3;
qy:=P0.Y*q0+P1.Y*q1+P2.Y*q2+P3.Y*q3;
Canvas.LineTo(round(qx),round(qy));
end;

end;

procedure TForm1.Button1Click(Sender: TObject);
begin
DrawBezier(canvas,Point(0,0),Point(800,30),Point(10,600),Point(750,600));

end;



 
Pavia ©   (2006-10-31 23:43) [7]

И еще практика показывает что в компьютерной графике лучше при выводе округлять не так
Canvas.LineTo(round(qx),round(qy));
А так
Canvas.LineTo(trunc(qx),trunc(qy));


 
Ketmar ©   (2006-10-31 23:47) [8]

>[7] Pavia(c) 31-Oct-2006, 23:43
>Canvas.LineTo(trunc(qx),trunc(qy));
обоснуй.


 
Pavia ©   (2006-11-01 00:19) [9]

Пока нет обоснования, еще мало примеров набрал. И это проявляетя только при построении без сглаживания. Я думаю это связанно с дискретностью исходных данных. Но пока в серьез моии слова не воспринемать.


 
Ketmar ©   (2006-11-01 01:09) [10]

любое округление искажает. разница в том, что round() быстрее работает. %-)


 
MBo ©   (2006-11-01 06:59) [11]

Кривые Безье - графический примитив, позволяющий отрисовать кубические параметрические кривые. Для того, чтобы аппроксимировать график, можно их непосредственно рассчитать, но значительно проще использовать кубические сплайны - интерполяционные или сглаживающие (в инете есть исходники), а затем преобразовать полученный набор согласованных полиномов в форму Безье.


 
Наиль ©   (2006-11-01 09:30) [12]

> Canvas.LineTo(round(qx),round(qy));
> А так
> Canvas.LineTo(trunc(qx),trunc(qy));

С математической точки зрения
Round(qx)=Trunc(qx+0.5)
Так что, это одно и тоже, но с разницей в пол пиксела


 
Ketmar ©   (2006-11-01 18:38) [13]

>[12] Наиль(c) 1-Nov-2006, 09:30
>С математической точки зрения
а с программной round() шустрее. %-)


 
Gyrus ©   (2006-11-02 15:11) [14]

Интересно, с чего это Round быстрее trunc?


 
Gyrus ©   (2006-11-02 15:14) [15]

Действительно, быстрее, а по логике выполнения и не скажешь.


 
MBo ©   (2006-11-03 05:53) [16]

>Действительно, быстрее, а по логике выполнения и не скажешь.
Trunc устанавливает, а потом возвращает контрольное слово сопроцессора, поэтому и медленнее.
А вообще тут это оффтопик, тем более, что приведенный код рисования Безье нехороший.


 
Pavia ©   (2006-11-03 14:58) [17]


> код рисования Безье нехороший.

Почему?


 
MBo ©   (2006-11-03 15:09) [18]

>Почему?
Потому что он неадаптивный. И при простой кривой, и при сложной форме он будет рисовать заданное число отрезков с равномерным шагом по t, в то время как правильный алгоритм выводит немного отрезков на гладких участках, и тщательно прорисовывает участки с большой кривизной и особыми точками ( "клювиком").
Ведь в этих кривых выбран базис полиномов Бернштейна не только потому, что это дает интуитивное представление о форме кривой (направление в конечных точках), но и обеспечивает легкий способ деления - метод de Casteljau


 
Pavia ©   (2006-11-03 16:16) [19]


> Потому что он неадаптивный.

Не как раз адаптивный. Посмотри на рисунки. На прямых участках как раз немного отрезков а на изгибе их уже больше.
То что t с равномерном шагом это не означает что P(t) - будет с равномерным шагом.
Да и помойку у тебя первый абзац противоречит второму. Так что можешь привести пример как это по-твоему должно выглядеть?


 
Jimmy   (2006-11-04 22:38) [20]

Если я правильно понимаю, то векторный MetaCanvas понимает грубо говоря 2 типа объектов - Line и CurveBezier. Line, что приведено в примере, меня в принципе не устраивает. С помощью Line я могу нарисовать график "точно" и без всяких апроксимаций. А мне надо чтобы 1) При увеличении в 500% график оставался гладким (Line отпадает) 2) В последующей редакции в CorelDraw появлялись именно кривые Безье а не Lines. Итак вопросов появилось еще больше, пока 2 из них:
1. Учитывая это кроме PolyBezier ничего не подойдет или я не прав?
2. Как тогда все же выбирать шаг, чтобы учитывать кривизну?
Заранее спасибо.


 
MBo ©   (2006-11-05 16:26) [21]

Pavia
>На прямых участках как раз немного отрезков а на изгибе их уже больше
Тем не менее равномерный шаг по t не обеспечивает правильной обработки сложных участков. Конечно, при большом числе точек отрисовка будет нормальной, но адаптивный алгоритм позволит сделать отрисовку с меньшими усилиями, да и зачем писать самому то, что уже сделано в Windows

Jimmy
> Как тогда все же выбирать шаг, чтобы учитывать кривизну?
GDI правильно отрисует кривые, а твоя проблема - правильно задать их, так что существа проблемы ты так и не раскрыл. Кое-что я предположил в [11], но пока неясно, имеет ли это отношение к твоей задаче



Страницы: 1 вся ветка

Текущий архив: 2007.08.05;
Скачать: CL | DM;

Наверх




Память: 0.52 MB
Время: 0.029 c
1-1179831235
parasolka
2007-05-22 14:53
2007.08.05
Работа с несколькими мониторами.


1-1180168895
Zagaevskiy
2007-05-26 12:41
2007.08.05
Как открыть CD-ROM?


11-1167056057
mixail_shar
2006-12-25 17:14
2007.08.05
MCK UNICODE


2-1183887762
nord489
2007-07-08 13:42
2007.08.05
Работа с изображениями


4-1171840164
Незнайкак
2007-02-19 02:09
2007.08.05
Ёмкость CD