首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 更多程式語言 >> Delphi

Delphi 貝塞爾曲線繪製:PolyBezier 與 PolyBezierTo 完整指南

     編輯:Delphi

Canvas 貝塞爾曲線兩大函數深度解析:控制點、多段連續、當前位置管理

Canvas.PolyBezier 與 PolyBezierTo 是繪製三次貝塞爾曲線的核心函數。理解它們對控制點數量的要求、對「當前筆位」的不同處理、多段曲線連續繪製的規則,能創建平滑優雅的曲線圖形。

函數簽名與核心差異

單段曲線基礎範例


// PolyBezier:自行指定起點
procedure TForm1.Button1Click(Sender: TObject);
var
  Pts: array[0..3] of TPoint;
begin
  Canvas.Pen.Width := 2;
  Canvas.Pen.Color := clRed;
  Pts[0] := Point(10, 10);      // 起點
  Pts[1] := Point(60, 10);      // 控制點 1
  Pts[2] := Point(10, 100);     // 控制點 2
  Pts[3] := Point(60, 100);     // 終點
  Canvas.PolyBezier(Pts);

  // 驗證當前位置未變
  Canvas.Pen.Width := 1;
  Canvas.Pen.Color := clWhite;
  Canvas.LineTo(ClientWidth, ClientHeight); // 從 (0,0) 畫線
end;

// PolyBezierTo:以 MoveTo 設定起點
procedure TForm1.Button2Click(Sender: TObject);
var
  Pts: array[1..3] of TPoint;  // 索引從 1 開始
begin
  Canvas.Pen.Width := 2;
  Canvas.Pen.Color := clRed;
  Canvas.MoveTo(10 + 82, 10);   // 設定起點 (偏移 82 像素避開第一條)
  // Pts[0] 隱式為當前位置
  Pts[1] := Point(60 + 82, 10); // 控制點 1
  Pts[2] := Point(10 + 82, 100); // 控制點 2
  Pts[3] := Point(60 + 82, 100); // 終點
  Canvas.PolyBezierTo(Pts);

  // 當前位置已移至終點
  Canvas.Pen.Width := 1;
  Canvas.Pen.Color := clBlue;
  Canvas.LineTo(ClientWidth, ClientHeight); // 從終點畫線
end;

多段連續貝塞爾曲線


// PolyBezier 多段:3n+1 個點,終點自動成下段起點
procedure TForm1.Button1Click(Sender: TObject);
var
  Pts: array[0..6] of TPoint;  // 2 段曲線:3*2+1=7
begin
  Canvas.Pen.Width := 2;
  Canvas.Pen.Color := clRed;
  Pts[0] := Point(10, 10);
  Pts[1] := Point(60, 10);
  Pts[2] := Point(10, 100);
  Pts[3] := Point(40, 100);    // 第 1 段終點 = 第 2 段起點
  Pts[4] := Point(100, 10);
  Pts[5] := Point(55, 99);
  Pts[6] := Point(70, 10);     // 第 2 段終點
  Canvas.PolyBezier(Pts);
end;

// PolyBezierTo 多段:3n 個點,MoveTo 設定第 1 段起點
procedure TForm1.Button2Click(Sender: TObject);
var
  Pts: array[1..6] of TPoint;  // 2 段:3*2=6
begin
  Canvas.Pen.Width := 2;
  Canvas.Pen.Color := clRed;
  Canvas.MoveTo(10 + 82, 10);  // 第 1 段起點
  Pts[1] := Point(60 + 82, 10);
  Pts[2] := Point(10 + 82, 100);
  Pts[3] := Point(40 + 82, 100); // 第 1 段終點
  Pts[4] := Point(100 + 82, 10);
  Pts[5] := Point(55 + 82, 99);
  Pts[6] := Point(70 + 82, 10);  // 第 2 段終點
  Canvas.PolyBezierTo(Pts);
end;

貝塞爾曲線數學原理速覽

三次貝塞爾曲線由參數方程定義 (t ∈ [0,1]):


B(t) = (1-t)³P₀ + 3(1-t)²t P₁ + 3(1-t)t² P₂ + t³ P₃
// P₀=起點, P₁=控制點1, P₂=控制點2, P₃=終點
  • 曲線不經過控制點 P₁、P₂
  • 切線方向:起點指向 P₁,終點來自 P₂
  • 凸包性質:曲線完全包含在四點凸包內

進階應用:平滑折線圖 (樣條插值)


procedure DrawSmoothPolyline(ACanvas: TCanvas; const Points: array of TPoint);
var
  i: Integer;
  Pts: array of TPoint;
  P0, P1, P2, P3: TPoint;
begin
  if Length(Points) < 2 then Exit;
  SetLength(Pts, (Length(Points) - 1) * 3 + 1);
  
  // Catmull-Rom 轉貝塞爾控制點算法
  Pts[0] := Points[0];
  for i := 0 to Length(Points) - 2 do
  begin
    // 計算控制點 (簡化版)
    P0 := Points[i];
    P3 := Points[i+1];
    if i = 0 then
      P1 := Point(P0.X + (P3.X - P0.X) div 3, P0.Y)
    else
      P1 := Point(Points[i].X + (Points[i+1].X - Points[i-1].X) div 6, Points[i].Y);
    
    if i = Length(Points) - 2 then
      P2 := Point(P3.X - (P3.X - P0.X) div 3, P3.Y)
    else
      P2 := Point(Points[i+1].X - (Points[i+2].X - Points[i].X) div 6, Points[i+1].Y);
    
    Pts[i*3+1] := P1;
    Pts[i*3+2] := P2;
    Pts[i*3+3] := P3;
  end;
  ACanvas.PolyBezier(Pts);
end;

常見陷阱與避坑

  1. PolyBezierTo 陣列必須從 1 開始:array[1..N],array[0..N-1] 會導致第一段錯誤
  2. 多段點數計算錯誤:PolyBezier 需 3n+1,PolyBezierTo 需 3n
  3. 控制點過遠導致曲線過度彎曲:控制點距離建議不超過終點距離 1.5 倍
  4. Width > 1 時線條銳角處理:GDI 不自動圓滑連接,需自行處理

效能提示

  • PolyBezier 批次繪製比循環 PolyBezierTo 快 (單次 GDI 調用)
  • 大量曲線考慮 Path API (BeginPath/EndPath/StrokePath)
  • 動畫場景預計算控制點,幀間僅插值

精通 PolyBezier/PolyBezierTo 的控制點邏輯與多段連接規則,能繪製從簡單曲線到複雜樣條的各類平滑圖形。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved
特性PolyBezierPolyBezierTo
最少點數4 (起點 + 2控制點 + 終點)3 (2控制點 + 終點,以當前位置為起點)
陣列索引通常 0-based: pts[0..3]通常 1-based: pts[1..3] (0 留給當前位置)
改變當前位置否是 (移至最後終點)
多段曲線點數公式3n + 13n