Delphi - объектно-ориентированный язык программирования, разработанный компанией Borland в 1995 году. Он основан на языке программирования Pascal, но имеет более расширенные возможности и добавлены новые функции.
Delphi является интегрированной средой разработки (IDE), которая позволяет разрабатывать программное обеспечение для различных платформ, включая Windows, macOS, Android и iOS. Delphi достигает многоплатформенности с помощью...
Как нарисовать кривую Безье. Именно она применяется для построения гладких кривых во всех графических программах - от PaintBrush до CorelDraw и PhotoShop. Для задания кривой Безье n-ной степени (чем больше степень, тем более кривой может быть линия; кривая первой степени - отрезок) нужно указать n+1 точку. Первая и последняя точки будут началом и концом кривой, а остальные точки задаю ее поведение на других участках. В частности, первая и n-ая точки задают касательные и кривизну кривой на ее концах. В большинстве программ используются кривые Безье третьего порядка. Начиная с Delphi5 такую кривую можно нарисовать при помощи функции 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 задается в SpinEdit1. Все узлы можно перемещать по полю мышью. Для создания нового узла нужно нажать мышью на пустое место на поле или увеличить порядок кривой. Скачать необходимые для компиляции файлы проекта можно на http://program.dax.ru
usesMath; 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
;