99 lines
2.6 KiB
ObjectPascal
99 lines
2.6 KiB
ObjectPascal
unit Bezier;
|
|
|
|
interface
|
|
|
|
uses Math;
|
|
|
|
|
|
type
|
|
BezierPoint = record
|
|
x, y: double;
|
|
end;
|
|
BezierRect = record
|
|
x0, y0, x1, y1: double;
|
|
end;
|
|
|
|
BezierPoints = array [0..3] of BezierPoint;
|
|
BezierWeights = array [0..3] of double;
|
|
|
|
procedure BezierCopy(src: BezierPoints; var tgt: BezierPoints);
|
|
procedure BezierSetRect(var points: BezierPoints; flip: boolean; rect: BezierRect);
|
|
procedure BezierUnsetRect(var points: BezierPoints; flip: boolean; rect: BezierRect);
|
|
|
|
procedure BezierSolve(t: double; src: BezierPoints; w: BezierWeights; var solution: BezierPoint);
|
|
function BezierFunc(t: double; src: BezierPoints; w: BezierWeights): double;
|
|
|
|
implementation
|
|
|
|
procedure BezierCopy(src: BezierPoints; var tgt: BezierPoints);
|
|
var
|
|
i, n: integer;
|
|
begin
|
|
n := Length(src);
|
|
for i := 0 to n - 1 do
|
|
tgt[i] := src[i];
|
|
end;
|
|
|
|
procedure BezierSetRect(var points: BezierPoints; flip: boolean; rect: BezierRect);
|
|
var
|
|
i, n: integer;
|
|
f: double;
|
|
begin
|
|
n := Length(points);
|
|
for i := 0 to n - 1 do
|
|
begin
|
|
if (flip) then f := 1 - points[i].y
|
|
else f := points[i].y;
|
|
|
|
points[i].x := points[i].x * (rect.x1 - rect.x0) + rect.x0;
|
|
points[i].y := f * (rect.y1 - rect.y0) + rect.y0;
|
|
end;
|
|
end;
|
|
|
|
procedure BezierUnsetRect(var points: BezierPoints; flip: boolean; rect: BezierRect);
|
|
var
|
|
i, n: integer;
|
|
f: double;
|
|
begin
|
|
if ((rect.x1 - rect.x0) = 0) or ((rect.y1 - rect.y0) = 0) then Exit;
|
|
|
|
n := Length(points);
|
|
for i := 0 to n - 1 do
|
|
begin
|
|
points[i].x := (points[i].x - rect.x0) / (rect.x1 - rect.x0);
|
|
points[i].y := (points[i].y - rect.y0) / (rect.y1 - rect.y0);
|
|
|
|
if (flip) then points[i].y := 1 - points[i].y;
|
|
end;
|
|
end;
|
|
|
|
procedure BezierSolve(t: double; src: BezierPoints; w: BezierWeights; var solution: BezierPoint);
|
|
var
|
|
s, s2, s3, t2, t3, nom_x, nom_y, denom: double;
|
|
begin
|
|
s := 1 - t;
|
|
s2 := s * s; s3 := s * s * s;
|
|
t2 := t * t; t3 := t * t * t;
|
|
|
|
nom_x := w[0] * s3 * src[0].x + w[1] * s2 * 3 * t * src[1].x +
|
|
w[2] * s * 3 * t2 * src[2].x + w[3] * t3 * src[3].x;
|
|
nom_y := w[0] * s3 * src[0].y + w[1] * s2 * 3 * t * src[1].y +
|
|
w[2] * s * 3 * t2 * src[2].y + w[3] * t3 * src[3].y;
|
|
denom := w[0] * s3 + w[1] * s2 * 3 * t + w[2] * s * 3 * t2 + w[3] * t3;
|
|
|
|
if (IsNaN(nom_x)) or (IsNaN(nom_y)) or (IsNaN(denom)) then Exit;
|
|
if denom = 0 then Exit;
|
|
|
|
solution.x := nom_x / denom;
|
|
solution.y := nom_y / denom;
|
|
end;
|
|
|
|
function BezierFunc(t: double; src: BezierPoints; w: BezierWeights): double;
|
|
var
|
|
p: BezierPoint;
|
|
begin
|
|
BezierSolve(t, src, w, p);
|
|
Result := p.y;
|
|
end;
|
|
end.
|