Apophysis-AV/Core/Bezier.pas

99 lines
2.6 KiB
ObjectPascal
Raw Normal View History

2022-03-08 12:25:51 -05:00
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
2022-03-08 12:25:51 -05:00
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;
2022-03-08 12:25:51 -05:00
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;
2022-03-08 12:25:51 -05:00
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;
2022-03-08 12:25:51 -05:00
function BezierFunc(t: double; src: BezierPoints; w: BezierWeights): double;
var
p: BezierPoint;
begin
BezierSolve(t, src, w, p);
Result := p.y;
end;
end.