📄 gr32_transforms.pas
字号:
if (Right > Left) and (Bottom > Top) and
(Left < ClipRect.Right) and (Top < ClipRect.Bottom) and
(Right > ClipRect.Left) and (Bottom > ClipRect.Top) then
begin
Dec(Right);
Dec(Bottom);
for I := Left to Right do
begin
ABitmap[I, Top] := ABitmap[I, Top] and $00FFFFFF;
ABitmap[I, Bottom] := ABitmap[I, Bottom] and $00FFFFFF;
end;
for I := Top to Bottom do
begin
ABitmap[Left, I] := ABitmap[Left, I] and $00FFFFFF;
ABitmap[Right, I] := ABitmap[Right, I] and $00FFFFFF;
end;
Changed;
end;
end;
{ TTransformation }
function TTransformation.GetTransformedBounds: TRect;
begin
Result := GetTransformedBounds(FSrcRect);
end;
procedure TTransformation.Changed;
begin
TransformValid := False;
inherited;
end;
function TTransformation.GetTransformedBounds(const ASrcRect: TFloatRect): TRect;
begin
Result := MakeRect(ASrcRect);
end;
function TTransformation.HasTransformedBounds: Boolean;
begin
Result := True;
end;
procedure TTransformation.PrepareTransform;
begin
// Dummy
end;
function TTransformation.ReverseTransform(const P: TFloatPoint): TFloatPoint;
begin
if not TransformValid then PrepareTransform;
ReverseTransformFloat(P.X, P.Y, Result.X, Result.Y);
end;
function TTransformation.ReverseTransform(const P: TFixedPoint): TFixedPoint;
begin
if not TransformValid then PrepareTransform;
ReverseTransformFixed(P.X, P.Y, Result.X, Result.Y);
end;
function TTransformation.ReverseTransform(const P: TPoint): TPoint;
begin
if not TransformValid then PrepareTransform;
ReverseTransformInt(P.X, P.Y, Result.X, Result.Y);
end;
procedure TTransformation.ReverseTransformFixed(DstX, DstY: TFixed;
out SrcX, SrcY: TFixed);
var
X, Y: TFloat;
begin
ReverseTransformFloat(DstX * FixedToFloat, DstY * FixedToFloat, X, Y);
SrcX := Fixed(X);
SrcY := Fixed(Y);
end;
procedure TTransformation.ReverseTransformFloat(DstX, DstY: TFloat;
out SrcX, SrcY: TFloat);
begin
// ReverseTransformFloat is the top precisionlevel, all decendants must override at least this level!
raise ETransformNotImplemented.Create(Format('Reverse transformation is not implemented in %s.', [Self.Classname]));
end;
procedure TTransformation.ReverseTransformInt(DstX, DstY: Integer;
out SrcX, SrcY: Integer);
var
X, Y: TFixed;
begin
ReverseTransformFixed(DstX shl 16, DstY shl 16, X, Y);
SrcX := FixedRound(X);
SrcY := FixedRound(Y);
end;
procedure TTransformation.SetSrcRect(const Value: TFloatRect);
begin
FSrcRect := Value;
Changed;
end;
function TTransformation.Transform(const P: TFloatPoint): TFloatPoint;
begin
If not TransformValid then PrepareTransform;
TransformFloat(P.X, P.Y, Result.X, Result.Y);
end;
function TTransformation.Transform(const P: TFixedPoint): TFixedPoint;
begin
If not TransformValid then PrepareTransform;
TransformFixed(P.X, P.Y, Result.X, Result.Y);
end;
function TTransformation.Transform(const P: TPoint): TPoint;
begin
If not TransformValid then PrepareTransform;
TransformInt(P.X, P.Y, Result.X, Result.Y);
end;
procedure TTransformation.TransformFixed(SrcX, SrcY: TFixed; out DstX,
DstY: TFixed);
var
X, Y: TFloat;
begin
TransformFloat(SrcX * FixedToFloat, SrcY * FixedToFloat, X, Y);
DstX := Fixed(X);
DstY := Fixed(Y);
end;
procedure TTransformation.TransformFloat(SrcX, SrcY: TFloat; out DstX, DstY: TFloat);
begin
// TransformFloat is the top precisionlevel, all decendants must override at least this level!
raise ETransformNotImplemented.Create(Format('Forward transformation is not implemented in %s.', [Self.Classname]));
end;
procedure TTransformation.TransformInt(SrcX, SrcY: Integer; out DstX, DstY: Integer);
var
X, Y: TFixed;
begin
TransformFixed(SrcX shl 16, SrcY shl 16, X, Y);
DstX := FixedRound(X);
DstY := FixedRound(Y);
end;
{ TAffineTransformation }
procedure TAffineTransformation.Clear;
begin
Matrix := IdentityMatrix;
Changed;
end;
constructor TAffineTransformation.Create;
begin
Clear;
end;
function TAffineTransformation.GetTransformedBounds(const ASrcRect: TFloatRect): TRect;
var
V1, V2, V3, V4: TVector3f;
begin
V1[0] := ASrcRect.Left; V1[1] := ASrcRect.Top; V1[2] := 1;
V2[0] := ASrcRect.Right; V2[1] := V1[1]; V2[2] := 1;
V3[0] := V1[0]; V3[1] := ASrcRect.Bottom; V3[2] := 1;
V4[0] := V2[0]; V4[1] := V3[1]; V4[2] := 1;
V1 := VectorTransform(Matrix, V1);
V2 := VectorTransform(Matrix, V2);
V3 := VectorTransform(Matrix, V3);
V4 := VectorTransform(Matrix, V4);
Result.Left := Round(Min(Min(V1[0], V2[0]), Min(V3[0], V4[0])) - 0.5);
Result.Right := Round(Max(Max(V1[0], V2[0]), Max(V3[0], V4[0])) + 0.5);
Result.Top := Round(Min(Min(V1[1], V2[1]), Min(V3[1], V4[1])) - 0.5);
Result.Bottom := Round(Max(Max(V1[1], V2[1]), Max(V3[1], V4[1])) + 0.5);
end;
procedure TAffineTransformation.PrepareTransform;
begin
FInverseMatrix := Matrix;
Invert(FInverseMatrix);
// calculate a fixed point (65536) factors
FInverseFixedMatrix := FixedMatrix(FInverseMatrix);
FFixedMatrix := FixedMatrix(Matrix);
TransformValid := True;
end;
procedure TAffineTransformation.Rotate(Cx, Cy, Alpha: TFloat);
var
S, C: TFloat;
M: TFloatMatrix;
begin
if (Cx <> 0) or (Cy <> 0) then Translate(-Cx, -Cy);
Alpha := DegToRad(Alpha);
S := Sin(Alpha); C := Cos(Alpha);
M := IdentityMatrix;
M[0,0] := C; M[1,0] := S;
M[0,1] := -S; M[1,1] := C;
Matrix := Mult(M, Matrix);
if (Cx <> 0) or (Cy <> 0) then Translate(Cx, Cy);
Changed;
end;
procedure TAffineTransformation.Scale(Sx, Sy: TFloat);
var
M: TFloatMatrix;
begin
M := IdentityMatrix;
M[0,0] := Sx;
M[1,1] := Sy;
Matrix := Mult(M, Matrix);
Changed;
end;
procedure TAffineTransformation.Skew(Fx, Fy: TFloat);
var
M: TFloatMatrix;
begin
M := IdentityMatrix;
M[1, 0] := Fx;
M[0, 1] := Fy;
Matrix := Mult(M, Matrix);
Changed;
end;
procedure TAffineTransformation.ReverseTransformFloat(
DstX, DstY: TFloat;
out SrcX, SrcY: TFloat);
begin
SrcX := DstX * FInverseMatrix[0,0] + DstY * FInverseMatrix[1,0] + FInverseMatrix[2,0];
SrcY := DstX * FInverseMatrix[0,1] + DstY * FInverseMatrix[1,1] + FInverseMatrix[2,1];
end;
procedure TAffineTransformation.ReverseTransformFixed(
DstX, DstY: TFixed;
out SrcX, SrcY: TFixed);
begin
SrcX := FixedMul(DstX, FInverseFixedMatrix[0,0]) + FixedMul(DstY, FInverseFixedMatrix[1,0]) + FInverseFixedMatrix[2,0];
SrcY := FixedMul(DstX, FInverseFixedMatrix[0,1]) + FixedMul(DstY, FInverseFixedMatrix[1,1]) + FInverseFixedMatrix[2,1];
end;
procedure TAffineTransformation.TransformFloat(
SrcX, SrcY: TFloat;
out DstX, DstY: TFloat);
begin
DstX := SrcX * Matrix[0,0] + SrcY * Matrix[1,0] + Matrix[2,0];
DstY := SrcX * Matrix[0,1] + SrcY * Matrix[1,1] + Matrix[2,1];
end;
procedure TAffineTransformation.TransformFixed(
SrcX, SrcY: TFixed;
out DstX, DstY: TFixed);
begin
DstX := FixedMul(SrcX, FFixedMatrix[0,0]) + FixedMul(SrcY, FFixedMatrix[1,0]) + FFixedMatrix[2,0];
DstY := FixedMul(SrcX, FFixedMatrix[0,1]) + FixedMul(SrcY, FFixedMatrix[1,1]) + FFixedMatrix[2,1];
end;
procedure TAffineTransformation.Translate(Dx, Dy: TFloat);
var
M: TFloatMatrix;
begin
M := IdentityMatrix;
M[2,0] := Dx;
M[2,1] := Dy;
Matrix := Mult(M, Matrix);
Changed;
end;
{ TProjectiveTransformation }
function TProjectiveTransformation.GetTransformedBounds(const ASrcRect: TFloatRect): TRect;
begin
Result.Left := Round(Min(Min(Wx0, Wx1), Min(Wx2, Wx3)) - 0.5);
Result.Right := Round(Max(Max(Wx0, Wx1), Max(Wx2, Wx3)) + 0.5);
Result.Top := Round(Min(Min(Wy0, Wy1), Min(Wy2, Wy3)) - 0.5);
Result.Bottom := Round(Max(Max(Wy0, Wy1), Max(Wy2, Wy3)) + 0.5);
end;
procedure TProjectiveTransformation.PrepareTransform;
var
dx1, dx2, px, dy1, dy2, py: TFloat;
g, h, k: TFloat;
R: TFloatMatrix;
begin
px := Wx0 - Wx1 + Wx2 - Wx3;
py := Wy0 - Wy1 + Wy2 - Wy3;
if (px = 0) and (py = 0) then
begin
// affine mapping
FMatrix[0,0] := Wx1 - Wx0;
FMatrix[1,0] := Wx2 - Wx1;
FMatrix[2,0] := Wx0;
FMatrix[0,1] := Wy1 - Wy0;
FMatrix[1,1] := Wy2 - Wy1;
FMatrix[2,1] := Wy0;
FMatrix[0,2] := 0;
FMatrix[1,2] := 0;
FMatrix[2,2] := 1;
end
else
begin
// projective mapping
dx1 := Wx1 - Wx2;
dx2 := Wx3 - Wx2;
dy1 := Wy1 - Wy2;
dy2 := Wy3 - Wy2;
k := dx1 * dy2 - dx2 * dy1;
if k <> 0 then
begin
g := (px * dy2 - py * dx2) / k;
h := (dx1 * py - dy1 * px) / k;
FMatrix[0,0] := Wx1 - Wx0 + g * Wx1;
FMatrix[1,0] := Wx3 - Wx0 + h * Wx3;
FMatrix[2,0] := Wx0;
FMatrix[0,1] := Wy1 - Wy0 + g * Wy1;
FMatrix[1,1] := Wy3 - Wy0 + h * Wy3;
FMatrix[2,1] := Wy0;
FMatrix[0,2] := g;
FMatrix[1,2] := h;
FMatrix[2,2] := 1;
end
else
begin
FillChar(FMatrix, SizeOf(FMatrix), 0);
end;
end;
// denormalize texture space (u, v)
R := IdentityMatrix;
R[0,0] := 1 / (SrcRect.Right - SrcRect.Left);
R[1,1] := 1 / (SrcRect.Bottom - SrcRect.Top);
FMatrix := Mult(FMatrix, R);
R := IdentityMatrix;
R[2,0] := -SrcRect.Left;
R[2,1] := -SrcRect.Top;
FMatrix := Mult(FMatrix, R);
FInverseMatrix := FMatrix;
Invert(FInverseMatrix);
FInverseFixedMatrix := FixedMatrix(FInverseMatrix);
FFixedMatrix := FixedMatrix(FMatrix);
TransformValid := True;
end;
procedure TProjectiveTransformation.SetX0(Value: TFloat);
begin
Wx0 := Value;
Changed;
end;
procedure TProjectiveTransformation.SetX1(Value: TFloat);
begin
Wx1 := Value;
Changed;
end;
procedure TProjectiveTransformation.SetX2(Value: TFloat);
begin
Wx2 := Value;
Changed;
end;
procedure TProjectiveTransformation.SetX3(Value: TFloat);
begin
Wx3 := Value;
Changed;
end;
procedure TProjectiveTransformation.SetY0(Value: TFloat);
begin
Wy0 := Value;
Changed;
end;
procedure TProjectiveTransformation.SetY1(Value: TFloat);
begin
Wy1 := Value;
Changed;
end;
procedure TProjectiveTransformation.SetY2(Value: TFloat);
begin
Wy2 := Value;
Changed;
end;
procedure TProjectiveTransformation.SetY3(Value: TFloat);
begin
Wy3 := Value;
Changed;
end;
procedure TProjectiveTransformation.ReverseTransformFloat(
DstX, DstY: TFloat;
out SrcX, SrcY: TFloat);
var
X, Y, Z: TFloat;
begin
EMMS;
X := DstX; Y := DstY;
Z := FInverseMatrix[0,2] * X + FInverseMatrix[1,2] * Y + FInverseMatrix[2,2];
if Z = 0 then Exit
else if Z = 1 then
begin
SrcX := FInverseMatrix[0,0] * X + FInverseMatrix[1,0] * Y + FInverseMatrix[2,0];
SrcY := FInverseMatrix[0,1] * X + FInverseMatrix[1,1] * Y + FInverseMatrix[2,1];
end
else
begin
Z := 1 / Z;
SrcX := (FInverseMatrix[0,0] * X + FInverseMatrix[1,0] * Y + FInverseMatrix[2,0]) * Z;
SrcY := (FInverseMatrix[0,1] * X + FInverseMatrix[1,1] * Y + FInverseMatrix[2,1]) * Z;
end;
end;
procedure TProjectiveTransformation.ReverseTransformFixed(DstX, DstY: TFixed;
out SrcX, SrcY: TFixed);
var
Z: TFixed;
Zf: TFloat;
begin
Z := FixedMul(FInverseFixedMatrix[0,2], DstX) +
FixedMul(FInverseFixedMatrix[1,2], DstY) +
FInverseFixedMatrix[2,2];
if Z = 0 then Exit;
SrcX := FixedMul(FInverseFixedMatrix[0,0], DstX) +
FixedMul(FInverseFixedMatrix[1,0], DstY) +
FInverseFixedMatrix[2,0];
SrcY := FixedMul(FInverseFixedMatrix[0,1], DstX) +
FixedMul(FInverseFixedMatrix[1,1], DstY) +
FInverseFixedMatrix[2,1];
if Z <> FixedOne then
begin
EMMS;
Zf := FixedOne / Z;
SrcX := Round(SrcX * Zf);
SrcY := Round(SrcY * Zf);
end;
end;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -