📄 gr32_transforms.pas
字号:
procedure TProjectiveTransformation.TransformFixed(SrcX, SrcY: TFixed;
out DstX, DstY: TFixed);
var
Z: TFixed;
Zf: TFloat;
begin
Z := FixedMul(FFixedMatrix[0,2], SrcX) +
FixedMul(FFixedMatrix[1,2], SrcY) +
FFixedMatrix[2,2];
if Z = 0 then Exit;
DstX := FixedMul(FFixedMatrix[0,0], SrcX) +
FixedMul(FFixedMatrix[1,0], SrcY) +
FFixedMatrix[2,0];
DstY := FixedMul(FFixedMatrix[0,1], SrcX) +
FixedMul(FFixedMatrix[1,1], SrcY) +
FFixedMatrix[2,1];
if Z <> FixedOne then
begin
EMMS;
Zf := FixedOne / Z;
DstX := Round(DstX * Zf);
DstY := Round(DstY * Zf);
end;
end;
procedure TProjectiveTransformation.TransformFloat(SrcX, SrcY: TFloat;
out DstX, DstY: TFloat);
var
X, Y, Z: TFloat;
begin
EMMS;
X := DstX; Y := DstY;
Z := FMatrix[0,2] * X + FMatrix[1,2] * Y + FMatrix[2,2];
if Z = 0 then Exit
else if Z = 1 then
begin
DstX := FMatrix[0,0] * X + FMatrix[1,0] * Y + FMatrix[2,0];
DstY := FMatrix[0,1] * X + FMatrix[1,1] * Y + FMatrix[2,1];
end
else
begin
Z := 1 / Z;
DstX := (FMatrix[0,0] * X + FMatrix[1,0] * Y + FMatrix[2,0]) * Z;
DstY := (FMatrix[0,1] * X + FMatrix[1,1] * Y + FMatrix[2,1]) * Z;
end;
end;
{ TTwirlTransformation }
constructor TTwirlTransformation.Create;
begin
FTwirl := 0.03;
end;
function TTwirlTransformation.GetTransformedBounds(const ASrcRect: TFloatRect): TRect;
var
Cx, Cy, R: TFloat;
begin
Cx := (ASrcRect.Left + ASrcRect.Right) / 2;
Cy := (ASrcRect.Top + ASrcRect.Bottom) / 2;
R := Max(Cx - ASrcRect.Left, Cy - ASrcRect.Top);
Result.Left := Round(Cx - R * Pi/2);
Result.Right := Round(Cx + R * Pi/2);
Result.Top := Round(Cy - R * Pi/2);
Result.Bottom := Round(Cy + R * Pi/2);
end;
procedure TTwirlTransformation.PrepareTransform;
begin
with FSrcRect do
begin
Frx := (Right - Left) / 2;
Fry := (Bottom - Top) / 2;
end;
end;
procedure TTwirlTransformation.ReverseTransformFloat(DstX, DstY: TFloat;
out SrcX, SrcY: TFloat);
var
xf, yf, r, t: Single;
begin
xf := DstX - Frx;
yf := DstY - Fry;
r := Sqrt(Sqr(xf) + Sqr(yf));
t := ArcTan2(yf, xf) + r * FTwirl;
SinCos(t, yf, xf);
SrcX := Frx + r * xf;
SrcY := Fry + r * yf;
end;
procedure TTwirlTransformation.SetTwirl(const Value: TFloat);
begin
FTwirl := Value;
Changed;
end;
{ TBloatTransformation }
constructor TBloatTransformation.Create;
begin
FBloatPower := 0.3;
end;
procedure TBloatTransformation.PrepareTransform;
begin
FPiW := (Pi / (FSrcRect.Right - FSrcRect.Left));
FPiH := (Pi / (FSrcRect.Bottom - FSrcRect.Top));
FBP := FBloatPower * Max(FSrcRect.Right - FSrcRect.Left, FSrcRect.Bottom - FSrcRect.Top);
end;
procedure TBloatTransformation.ReverseTransformFloat(DstX, DstY: TFloat;
out SrcX, SrcY: TFloat);
var
SinY, CosY, SinX, CosX, t: Single;
begin
SinCos(FPiH * DstY, SinY, CosY);
SinCos(FPiW * DstX, SinX, CosX);
t := FBP * SinY * SinX;
SrcX := DstX + t * CosX;
SrcY := DstY + t * CosY;
end;
procedure TBloatTransformation.SetBloatPower(const Value: TFloat);
begin
FBloatPower := Value;
Changed;
end;
{ TFishEyeTransformation }
procedure TFishEyeTransformation.PrepareTransform;
begin
with FSrcRect do
begin
Frx := (Right - Left) / 2;
Fry := (Bottom - Top) / 2;
if Frx <= Fry then
begin
FMinR := Frx;
Sx := 1;
Sy:= 1 / (Fry / Frx);
end
else
begin
FMinR := Fry;
Sx:= 1 / (Frx / Fry);
Sy := 1;
end;
Fsr := 1 / FMinR;
Faw := ArcSin(Constrain(FMinR * Fsr, -1, 1));
if Faw <> 0 then Faw := 1 / Faw;
Faw := Faw * FMinR
end;
end;
procedure TFishEyeTransformation.ReverseTransformFloat(DstX, DstY: TFloat;
out SrcX, SrcY: TFloat);
var
d, Xrx, Yry: TFloat;
begin
Yry := (DstY - Fry) * sy;
Xrx := (DstX - Frx) * sx;
d := Sqrt(Sqr(Xrx) + Sqr(Yry));
if (d < FMinR) and (d > 0) then
begin
d := ArcSin(d * Fsr) * Faw / d;
SrcX := Frx + Xrx * d;
SrcY := Fry + Yry * d;
end
else
begin
SrcX := DstX;
SrcY := DstY;
end;
end;
{ TDisturbanceTransformation }
function TDisturbanceTransformation.GetTransformedBounds(
const ASrcRect: TFloatRect): TRect;
var
R: TFloatRect;
begin
R := ASrcRect;
InflateRect(R, 0.5 * FDisturbance, 0.5 * FDisturbance);
Result := MakeRect(R);
end;
procedure TDisturbanceTransformation.ReverseTransformFloat(DstX,
DstY: TFloat; out SrcX, SrcY: TFloat);
begin
SrcX := DstX + (Random - 0.5) * FDisturbance;
SrcY := DstY + (Random - 0.5) * FDisturbance;
end;
procedure TDisturbanceTransformation.SetDisturbance(const Value: TFloat);
begin
FDisturbance := Value;
Changed;
end;
{ TRemapTransformation }
constructor TRemapTransformation.Create;
begin
inherited;
FScalingFixed := FixedPoint(1, 1);
FScalingFloat := FloatPoint(1, 1);
FOffset := FloatPoint(0,0);
FVectorMap := TVectorMap.Create;
//Ensuring initial setup to avoid exceptions
FVectorMap.SetSize(1, 1);
end;
destructor TRemapTransformation.Destroy;
begin
FVectorMap.Free;
inherited;
end;
function TRemapTransformation.GetTransformedBounds(const ASrcRect: TFloatRect): TRect;
begin
// We can't predict the ultimate bounds without transforming each vector in
// the vector map, return the absolute biggest possible transformation bounds
Result := Rect(-MaxInt, -MaxInt, MaxInt, MaxInt);
end;
function TRemapTransformation.HasTransformedBounds: Boolean;
begin
Result := False;
end;
procedure TRemapTransformation.PrepareTransform;
begin
if IsRectEmpty(SrcRect) then raise Exception.Create('SrcRect is empty!');
if IsRectEmpty(FMappingRect) then raise Exception.Create('MappingRect is empty!');
with SrcRect do
begin
FSrcTranslationFloat.X := Left;
FSrcTranslationFloat.Y := Top;
FSrcScaleFloat.X := 1 / ((FVectorMap.Width - 1) / (Right - Left));
FSrcScaleFloat.Y := 1 / ((FVectorMap.Height - 1) / (Bottom - Top));
FSrcTranslationFixed := FixedPoint(FSrcTranslationFloat);
FSrcScaleFixed := FixedPoint(FSrcScaleFloat);
end;
with FMappingRect do
begin
FDstTranslationFloat.X := Left;
FDstTranslationFloat.Y := Top;
FDstScaleFloat.X := (FVectorMap.Width - 1) / (Right - Left);
FDstScaleFloat.Y := (FVectorMap.Height - 1) / (Bottom - Top);
FCombinedScalingFloat.X := FDstScaleFloat.X * FScalingFloat.X;
FCombinedScalingFloat.Y := FDstScaleFloat.Y * FScalingFloat.Y;
FCombinedScalingFixed := FixedPoint(FCombinedScalingFloat);
FDstTranslationFixed := FixedPoint(FDstTranslationFloat);
FDstScaleFixed := FixedPoint(FDstScaleFloat);
end;
end;
procedure TRemapTransformation.ReverseTransformFixed(DstX, DstY: TFixed;
out SrcX, SrcY: TFixed);
begin
with FVectorMap.FixedVectorX[DstX - FOffsetFixed.X, DstY - FOffsetFixed.Y] do
begin
DstX := DstX - FDstTranslationFixed.X;
DstX := FixedMul(DstX , FDstScaleFixed.X);
DstX := DstX + FixedMul(X, FCombinedScalingFixed.X);
DstX := FixedMul(DstX, FSrcScaleFixed.X);
SrcX := DstX + FSrcTranslationFixed.X;
DstY := DstY - FDstTranslationFixed.Y;
DstY := FixedMul(DstY, FDstScaleFixed.Y);
DstY := DstY + FixedMul(Y, FCombinedScalingFixed.Y);
DstY := FixedMul(DstY, FSrcScaleFixed.Y);
SrcY := DstY + FSrcTranslationFixed.Y;
end;
end;
procedure TRemapTransformation.ReverseTransformFloat(DstX, DstY: TFloat;
out SrcX, SrcY: TFloat);
begin
with FVectorMap.FloatVectorF[DstX - FOffset.X, DstY - FOffset.Y] do
begin
DstX := DstX - FDstTranslationFloat.X;
DstY := DstY - FDstTranslationFloat.Y;
DstX := DstX * FDstScaleFloat.X;
DstY := DstY * FDstScaleFloat.Y;
DstX := DstX + X * FCombinedScalingFloat.X;
DstY := DstY + Y * FCombinedScalingFloat.Y;
DstX := DstX * FSrcScaleFloat.X;
DstY := DstY * FSrcScaleFloat.Y;
SrcX := DstX + FSrcTranslationFloat.X;
SrcY := DstY + FSrcTranslationFloat.Y;
end;
end;
procedure TRemapTransformation.ReverseTransformInt(DstX, DstY: Integer;
out SrcX, SrcY: Integer);
begin
with FVectorMap.FixedVector[DstX - FOffsetInt.X, DstY - FOffsetInt.Y] do
begin
DstX := DstX * FixedOne - FDstTranslationFixed.X;
DstY := DstY * FixedOne - FDstTranslationFixed.Y;
DstX := FixedMul(DstX, FDstScaleFixed.X);
DstY := FixedMul(DstY, FDstScaleFixed.Y);
DstX := DstX + FixedMul(X, FCombinedScalingFixed.X);
DstY := DstY + FixedMul(Y, FCombinedScalingFixed.Y);
DstX := FixedMul(DstX, FSrcScaleFixed.X);
DstY := FixedMul(DstY, FSrcScaleFixed.Y);
SrcX := FixedRound(DstX + FSrcTranslationFixed.X);
SrcY := FixedRound(DstY + FSrcTranslationFixed.Y);
end;
end;
procedure TRemapTransformation.Scale(Sx, Sy: TFloat);
begin
FScalingFixed.X := Fixed(Sx);
FScalingFixed.Y := Fixed(Sy);
FScalingFloat.X := Sx;
FScalingFloat.Y := Sy;
Changed;
end;
procedure TRemapTransformation.SetMappingRect(Rect: TFloatRect);
begin
FMappingRect := Rect;
Changed;
end;
procedure TRemapTransformation.SetOffset(const Value: TFloatVector);
begin
FOffset := Value;
FOffsetInt := Point(Value);
FOffsetFixed := FixedPoint(Value);
Changed;
end;
procedure RasterizeTransformation(Vectormap: TVectormap;
Transformation: TTransformation; DstRect: TRect;
CombineMode: TVectorCombineMode = vcmAdd;
CombineCallback: TVectorCombineEvent = nil);
var
I, J: Integer;
P, Q, Progression: TFixedVector;
ProgressionX, ProgressionY: TFixed;
MapPtr: PFixedPointArray;
begin
IntersectRect(DstRect, VectorMap.BoundsRect, DstRect);
if IsRectEmpty(DstRect) then Exit;
if not TTransformationAccess(Transformation).TransformValid then
TTransformationAccess(Transformation).PrepareTransform;
case CombineMode of
vcmAdd:
begin
with DstRect do
for I := Top to Bottom - 1 do
begin
MapPtr := @VectorMap.Vectors[I * VectorMap.Width];
for J := Left to Right - 1 do
begin
P := FixedPoint(J - Left, I - Top);
Q := Transformation.ReverseTransform(P);
Inc(MapPtr[J].X, Q.X - P.X);
Inc(MapPtr[J].Y, Q.Y - P.Y);
end;
end;
end;
vcmReplace:
begin
with DstRect do
for I := Top to Bottom - 1 do
begin
MapPtr := @VectorMap.Vectors[I * VectorMap.Width];
for J := Left to Right - 1 do
begin
P := FixedPoint(J - Left, I - Top);
Q := Transformation.ReverseTransform(P);
MapPtr[J].X := Q.X - P.X;
MapPtr[J].Y := Q.Y - P.Y;
end;
end;
end;
else // vcmCustom
ProgressionX := Fixed(1 / (DstRect.Right - DstRect.Left - 1));
ProgressionY := Fixed(1 / (DstRect.Bottom - DstRect.Top - 1));
Progression.Y := 0;
with DstRect do for I := Top to Bottom - 1 do
begin
Progression.X := 0;
MapPtr := @VectorMap.Vectors[I * VectorMap.Width];
for J := Left to Right - 1 do
begin
P := FixedPoint(J - Left, I - Top);
Q := Transformation.ReverseTransform(P);
Q.X := Q.X - P.X;
Q.Y := Q.Y - P.Y;
CombineCallback(Q, Progression, MapPtr[J]);
Inc(Progression.X, ProgressionX);
end;
Inc(Progression.Y, ProgressionY);
end;
end;
end;
{ Matrix conversion routines }
function FixedMatrix(const FloatMatrix: TFloatMatrix): TFixedMatrix;
begin
Result[0,0] := Round(FloatMatrix[0,0] * FixedOne);
Result[0,1] := Round(FloatMatrix[0,1] * FixedOne);
Result[0,2] := Round(FloatMatrix[0,2] * FixedOne);
Result[1,0] := Round(FloatMatrix[1,0] * FixedOne);
Result[1,1] := Round(FloatMatrix[1,1] * FixedOne);
Result[1,2] := Round(FloatMatrix[1,2] * FixedOne);
Result[2,0] := Round(FloatMatrix[2,0] * FixedOne);
Result[2,1] := Round(FloatMatrix[2,1] * FixedOne);
Result[2,2] := Round(FloatMatrix[2,2] * FixedOne);
end;
function FloatMatrix(const FixedMatrix: TFixedMatrix): TFloatMatrix;
begin
Result[0,0] := FixedMatrix[0,0] * FixedToFloat;
Result[0,1] := FixedMatrix[0,1] * FixedToFloat;
Result[0,2] := FixedMatrix[0,2] * FixedToFloat;
Result[1,0] := FixedMatrix[1,0] * FixedToFloat;
Result[1,1] := FixedMatrix[1,1] * FixedToFloat;
Result[1,2] := FixedMatrix[1,2] * FixedToFloat;
Result[2,0] := FixedMatrix[2,0] * FixedToFloat;
Result[2,1] := FixedMatrix[2,1] * FixedToFloat;
Result[2,2] := FixedMatrix[2,2] * FixedToFloat;
end;
end.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -