unit
TransformMatrix;
(*
****************************************************************************
* *
* 本单元定义平面几何变换类 *
* *
* 编制人: 湖北省公安县统计局 毛泽发 2010.10 *
* *
****************************************************************************
*)
interface
{
$IF RTLVersion >= 17.00
}
{
$inline auto
}
{
$IFEND
}
uses
Windows, SysUtils, Gdiplus;
type
//
几何变换矩阵结构
PMatrixElements
=
Gdiplus.PMatrixElements;
TMatrixElements
=
Gdiplus.TMatrixElements;
//
平面几何变换类
TTransformMatrix
=
class
(TObject)
private
FElements: TMatrixElements;
function
GetIdentity: Boolean;
function
GetInvertible: Boolean;
procedure
SetElements(
const
Value: TMatrixElements);
function
GetIdentityElements: TMatrixElements;
procedure
ElementsMultiply(
const
e: TMatrixElements);
public
//
建立一个新实例,并初始化为单位矩阵 Elements
=
1
,
0
,
0
,
1
,
0
,
0
constructor
Create;
overload
;
//
建立一个新实例,并复制matrix的元素
constructor
Create(matrix: TTransformMatrix);
overload
;
//
建立一个按指定的元素初始化的新实例
constructor
Create(m11, m12, m21, m22, dx, dy: Single);
overload
;
//
重置对象为单位矩阵
procedure
Reset;
//
将对象与matrix相乘
procedure
Multiply(
const
matrix: TTransformMatrix);
//
设置平移
procedure
Translate(offsetX, offsetY: Single);
//
设置缩放
procedure
Scale(scaleX, scaleY: Single);
//
设置按角度angle沿原点旋转
procedure
Rotate(angle: Single);
//
设置按角度angle沿中心点centerX, centerY旋转
procedure
RotateAt(angle: Single; centerX, centerY: Single);
//
设置剪切,注意不要将shearX, shearY同时设置为1
procedure
Shear(shearX, shearY: Single);
//
如果此对象是可逆转的,则逆转该对象。
procedure
Invert;
//
按给定的大小计算并返回实施变换后的尺寸
procedure
GetTransformSize(width, height: Integer;
var
fx, fy, fwidth, fheight: Single);
//
按给定的大小计算并返回实施变换后的尺寸
function
GetTransformRect(width, height: Integer): TRect;
//
判断对象是否是可逆转的
property
IsInvertible: Boolean
read
GetInvertible;
//
判断此对象是否是单位矩阵
property
IsIdentity: Boolean
read
GetIdentity;
//
获取或设置对象元素
property
Elements: TMatrixElements
read
FElements
write
SetElements;
//
获取对象的x偏移量
property
OffsetX: Single
read
FElements.dx
write
FElements.dx;
//
获取对象的y偏移量
property
OffsetY: Single
read
FElements.dy
write
FElements.dy;
end
;
implementation
{
TTransformMatrix
}
constructor
TTransformMatrix.Create;
begin
FElements.m11 :
=
1.0
;
FElements.m22 :
=
1.0
;
end
;
constructor
TTransformMatrix.Create(matrix: TTransformMatrix);
begin
FElements :
=
matrix.Elements;
end
;
constructor
TTransformMatrix.Create(m11, m12, m21, m22, dx, dy: Single);
begin
FElements.m11 :
=
m11;
FElements.m12 :
=
m12;
FElements.m21 :
=
m21;
FElements.m22 :
=
m22;
FElements.dx :
=
dx;
FElements.dy :
=
dy;
end
;
procedure
TTransformMatrix.ElementsMultiply(
const
e: TMatrixElements);
var
m11, m12: Single;
begin
m11 :
=
FElements.m11;
m12 :
=
FElements.m12;
FElements.m11 :
=
e.m11
*
m11
+
e.m12
*
FElements.m21;
FElements.m12 :
=
e.m11
*
m12
+
e.m12
*
FElements.m22;
FElements.m21 :
=
e.m21
*
m11
+
e.m22
*
FElements.m21;
FElements.m22 :
=
e.m21
*
m12
+
e.m22
*
FElements.m22;
end
;
function
TTransformMatrix.GetIdentity: Boolean;
begin
Result :
=
(FElements.m11
=
1.0
)
and
(FElements.m12
=
0.0
)
and
(FElements.m21
=
0.0
)
and
(FElements.m22
=
1.0
)
and
(FElements.dx
=
0.0
)
and
(FElements.dy
=
0.0
);
end
;
function
TTransformMatrix.GetIdentityElements: TMatrixElements;
begin
FillChar(Result, Sizeof(TMatrixElements),
0
);
Result.m11 :
=
1.0
;
Result.m22 :
=
1.0
;
end
;
function
TTransformMatrix.GetInvertible: Boolean;
begin
Result :
=
Round((FElements.m11
*
FElements.m22
-
FElements.m12
*
FElements.m21)
*
1000.0
)
<>
0
;
end
;
function
TTransformMatrix.GetTransformRect(width, height: Integer): TRect;
var
fx, fy, fwidth, fheight: Single;
begin
GetTransformSize(width, height, fx, fy, fwidth, fheight);
Result.Left :
=
Trunc(fx);
Result.Top :
=
Trunc(fy);
Result.Right :
=
Trunc(fwidth
+
fx
+
0.999999
);
Result.Bottom :
=
Trunc(fheight
+
fy
+
0.999999
);
end
;
procedure
TTransformMatrix.GetTransformSize(width, height: Integer;
var
fx, fy,
fwidth, fheight: Single);
var
fxs, fys:
array
[
0
..
2
]
of
Single;
v: Single;
i: Integer;
begin
fxs[
0
] :
=
width;
fxs[
1
] :
=
0.0
;
fxs[
2
] :
=
width;
fys[
0
] :
=
0.0
;
fys[
1
] :
=
height;
fys[
2
] :
=
height;
fx :
=
0.0
;
fy :
=
0.0
;
fwidth :
=
0.0
;
fheight :
=
0.0
;
for
i :
=
0
to
2
do
begin
v :
=
fxs[i]
*
FElements.m11
+
fys[i]
*
FElements.m21;
if
v
<
fx
then
fx :
=
v
else
if
v
>
fwidth
then
fwidth :
=
v;
v :
=
fxs[i]
*
FElements.m12
+
fys[i]
*
FElements.m22;
if
v
<
fy
then
fy :
=
v
else
if
v
>
fheight
then
fheight :
=
v;
end
;
fwidth :
=
fwidth
-
fx;
fheight :
=
fheight
-
fy;
fx :
=
fx
+
FElements.dx;
fy :
=
fy
+
FElements.dy;
end
;
procedure
TTransformMatrix.Invert;
var
tmp: Double;
m11, dx: Single;
begin
tmp :
=
FElements.m11
*
FElements.m22
-
FElements.m12
*
FElements.m21;
if
Trunc(tmp
*
1000.0
)
=
0
then
raise
Exception.Create(
'
Not invertible transformation matrix.
'
);
tmp :
=
1.0
/
tmp;
m11 :
=
FElements.m11;
dx :
=
-
FElements.dx;
FElements.m11 :
=
tmp
*
FElements.m22;
FElements.m12 :
=
tmp
*
-
FElements.m12;
FElements.m21 :
=
tmp
*
-
FElements.m21;
FElements.m22 :
=
tmp
*
m11;
FElements.dx :
=
dx
*
FElements.m11
-
FElements.dy
*
FElements.m21;
FElements.dy :
=
dx
*
FElements.m12
-
FElements.dy
*
FElements.m22;
end
;
procedure
TTransformMatrix.Multiply(
const
matrix: TTransformMatrix);
begin
FElements.dx :
=
FElements.dx
+
(matrix.FElements.dx
*
FElements.m11
+
matrix.FElements.dy
*
FElements.m21);
FElements.dy :
=
FElements.dy
+
(matrix.FElements.dx
*
FElements.m12
+
matrix.FElements.dy
*
FElements.m22);
ElementsMultiply(matrix.FElements);
end
;
procedure
TTransformMatrix.Reset;
begin
FElements :
=
GetIdentityElements;
end
;
procedure
TTransformMatrix.Rotate(angle: Single);
var
e: TMatrixElements;
begin
angle :
=
angle
*
PI
/
180.0
;
e.m11 :
=
Cos(angle);
e.m22 :
=
e.m11;
e.m12 :
=
Sin(angle);
e.m21 :
=
-
e.m12;
e.dx :
=
0.0
;
e.dy :
=
0.0
;
ElementsMultiply(e);
end
;
procedure
TTransformMatrix.RotateAt(angle, centerX, centerY: Single);
begin
Translate(centerX, centerY);
Rotate(angle);
Translate(
-
centerX,
-
centerY);
end
;
procedure
TTransformMatrix.Scale(scaleX, scaleY: Single);
var
e: TMatrixElements;
begin
e :
=
GetIdentityElements;
e.m11 :
=
scaleX;
e.m22 :
=
scaleY;
ElementsMultiply(e);
end
;
procedure
TTransformMatrix.SetElements(
const
Value: TMatrixElements);
begin
Move(Value, FElements, Sizeof(TMatrixElements));
end
;
procedure
TTransformMatrix.Shear(shearX, shearY: Single);
var
e: TMatrixElements;
begin
e :
=
GetIdentityElements;
e.m21 :
=
shearX;
e.m12 :
=
shearY;
ElementsMultiply(e);
end
;
procedure
TTransformMatrix.Translate(offsetX, offsetY: Single);
begin
FElements.dx :
=
FElements.dx
+
(offsetX
*
FElements.m11
+
offsetY
*
FElements.m21);
FElements.dy :
=
FElements.dy
+
(offsetX
*
FElements.m12
+
offsetY
*
FElements.m22);
end
;
end
.