Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
22780_ПОБУДОВА ФРАКТАЛЬНИХ ЗОБРАЖЕНЬ.doc
Скачиваний:
57
Добавлен:
14.02.2016
Размер:
2.91 Mб
Скачать

Крива Безьє

Саме крива Безьє використовується для побудови гладких кривих у всіх графічних програмах від PaintBrush до CorelDraw і PhotoShop. Для задання кривої Безьє n-ної степені (чим більша степінь, тим більш кривою може бути лінія; крива першої степені - відрізок) потрібно вказати n+1 точку. Перша і остання точки будуть початком і кінцем кривої, а всі інші точки задають її поведінку на других ділянках. Загалом, перша і остання точки задають кривизну кривої на її кінцях. В більшості програм використовується криві Безьє третього порядку. Починаючи з Delphi 5 таку криву можна намалювати при допомозі PolyBezier. Крива Безьє задається параметрично (x=x(t), y=y(t)). Це дозволяє їй поводитися абсолютно непередбачувано. Якщо б вона задавалася б як y(x), то вона не змогла б навіть зробити поворот на 180 градусів. Функція x(t) і y(t) виглядає так: x(t)= Cn0 * t0 * (1-t)n * x0 + Cn1 * t1 * (1-t)n-1 * x1 + Cn2 * t2 * (1-t)n-2 * x2 + ... + Cnn * tn * (1-t)0 * xn y(t)= Cn0 * t0 * (1-t)n * y0 + Cn1 * t1 * (1-t)n-1 * y1 + Cn2 * t2 * (1-t)n-2 * y2 + ... + Cnn * tn * (1-t)0 * yn де n - порядок кривої, Cni - коефіцієнти, t - параметр що змінюється від 0 до 1, xi, yi - координати опорних точок. Ця програма будує криву Безьє n-ного порядку. n задається користувачем (SpinEdit13). Всі вузли можна переміщувати на полі мишкою. Щоб створити новий вузол потрібно натиснути мишкою на пусте місце на полі, або збільшити порядок кривої(SpinEdit13).

uses Math;

const

RectSize = 5;

MaxN = 128;

var

n: integer = -1;

pt: array[0..MaxN] of TPoint;

C: array[0..MaxN] of single;

bm: TBitMap;

function GetBinomialCoefficient(m, i: integer): single;

function Factorial(x: integer): double;

var

i: integer;

begin

result := 1;

for i := 2 to x do

result := result * i;

end;

begin

result := Factorial(m) / (Factorial(i) * Factorial(m - i));

end;

procedure DrawBezier(Canvas: TCanvas; Count: integer);

type

TPointArray = array[word] of TPoint;

PPointArray = ^TPointArray;

var

p: PPointArray;

Step, qx, qy, t, q: single;

i, j: integer;

begin

GetMem(p, sizeof(TPoint) * (Count + 1));

Step := 1.0 / Count;

for i := 0 to Count do

begin

t := i * Step;

qx := 0;

qy := 0;

for j := 0 to n do

begin

q := C[j] * IntPower(1 - t, j) * IntPower(t, n - j);

qx := qx + q * pt[j].x;

qy := qy + q * pt[j].y;

end;

p[i] := Point(round(qx), round(qy));

end;

Canvas.Polyline(Slice(p^, Count + 1));

FreeMem(p);

end;

procedure DrawLines(canvas: TCanvas; const pt: array of TPoint);

var

i: integer;

begin

Canvas.Pen.Color := clGreen;

Canvas.Pen.Width := 1;

Canvas.MoveTo(pt[0].x, pt[0].y);

for i := 0 to n do

begin

Canvas.Rectangle(Bounds(pt[i].x - RectSize, pt[i].y - RectSize,

2 * RectSize, 2 * RectSize));

Canvas.LineTo(pt[i].x, pt[i].y);

end;

end;

procedure Redraw;

begin

with Form1.PaintBox1 do

begin

bm.Canvas.FillRect(Bounds(0, 0, Width, Height));

if Form1.CheckBox1.Checked then

DrawLines(bm.Canvas, pt);

bm.Canvas.PolyBezier(pt);

bm.Canvas.Pen.Color := clRed;

bm.Canvas.pen.Width := Form1.SpinEdit3.Value;

DrawBezier(bm.Canvas, Form1.SpinEdit2.Value);

Canvas.Draw(0, 0, bm);

end;

end;

var

moving: integer = -1;

oldr: TRect;

procedure FillRandom(NewN: integer);

var

i: integer;

begin

randomize;

for i := n + 1 to NewN do

pt[i] := Point(random(Form1.PaintBox1.Width - 20) + 10,

random(Form1.PaintBox1.Height - 20) + 10);

n := NewN;

end;

procedure TForm1.FormCreate(Sender: TObject);

begin

bm := TBitmap.Create;

bm.Width := PaintBox1.Width;

bm.Height := PaintBox1.height;

SpinEdit1.MinValue := 1;

SpinEdit1.MaxValue := MaxN;

SpinEdit1.Value := 3;

SpinEdit2.MinValue := 6;

SpinEdit2.MaxValue := MaxN * 4;

SpinEdit2.Value := 50;

SpinEdit2.OnChange := PaintBox1.OnPaint;

SpinEdit3.MinValue := 1;

SpinEdit3.MaxValue := 8;

SpinEdit3.Value := 3;

SpinEdit3.OnChange := PaintBox1.OnPaint;

CheckBox1.Checked := true;

CheckBox1.OnClick := PaintBox1.OnPaint;

end;

procedure TForm1.PaintBox1MouseDown(Sender: TObject; Button: TMouseButton;

Shift: TShiftState; X, Y: Integer);

var

i: integer;

r: TRect;

begin

if Button <> mbLeft then

Exit;

for i := 0 to n do

if (abs(X - pt[i].x) <= RectSize) and (abs(Y - pt[i].y) <= RectSize) then

begin

moving := i;

r.TopLeft := Form1.ClientToScreen(PaintBox1.BoundsRect.TopLeft);

r.BottomRight := Form1.ClientToScreen(PaintBox1.BoundsRect.BottomRight);

GetClipCursor(oldr);

ClipCursor(@r);

Exit;

end;

if moving < 0 then

begin

SpinEdit1.Value := SpinEdit1.Value + 1;

pt[n] := Point(X, Y);

Redraw;

end;

end;

procedure TForm1.PaintBox1MouseMove(Sender: TObject; Shift: TShiftState; X, Y:

Integer);

begin

if moving < 0 then

Exit;

pt[moving] := Point(X, Y);

Redraw;

end;

procedure TForm1.PaintBox1MouseUp(Sender: TObject; Button: TMouseButton;

Shift: TShiftState; X, Y: Integer);

begin

if (Button = mbLeft) and (moving >= 0) then

begin

moving := -1;

ClipCursor(@oldr);

end;

end;

procedure TForm1.SpinEdit1Change(Sender: TObject);

var

i: integer;

begin

FillRandom(SpinEdit1.Value);

SpinEdit2.MinValue := n * 2;

for i := 0 to n do

C[i] := GetBinomialCoefficient(n, i);

Redraw;

end;

procedure TForm1.PaintBox1Paint(Sender: TObject);

begin

Redraw;

end;

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]