我没有深入研究代码,但我可以在矩阵方面提供一些帮助(第3点)。
我猜想使用了三个基本的变换矩阵:旋转矩阵、缩放矩阵和平移矩阵。我们将它们分别称为R、S和T。
应用矩阵到点上有一个棘手的部分。比如说,您想要平移这个点,然后围绕原点中心旋转。换句话说,您想要将旋转应用于点的平移效果。因此,矩阵将按以下方式应用:
R(T(P)) = R * T * P = S
其中*表示矩阵乘法。请注意,相乘的矩阵顺序与您的意图相反。
然而,如果您想进行逆变换,除了反转矩阵的顺序外,还必须计算它们的逆矩阵。我们先平移点,然后旋转 - 现在我们需要将其旋转回来,然后再平移回去:
T^-1 ( R^-1 (S)) = T^-1 * R^-1 * S = P
请注意,您不必计算每个矩阵的逆矩阵,因为显然 T^-1(x) = T(-x),R^-1(angle) = R(-angle)等等。但是,您需要推断出转换的参数,如果只能访问转换矩阵,则可能不容易。
我猜想,世界坐标通过平移和缩放矩阵相结合转换为屏幕坐标。最后一个矩阵负责根据整个场景的缩放因素(以及可能的显示器DPI)将单位从世界坐标更改为像素。另一方面,平移矩阵反映了场景平移,并可以在缩放矩阵之前或之后应用;在第一种情况下,平移以世界坐标存储,在第二种情况下,平移以屏幕坐标存储。
我还猜想,所有对象的变换都是在世界坐标中进行的(对我来说听起来更方便)。因此,您可以期望每个对象的点都会接受以下转换:
W(S(R(T(P)))) = W * S * R * T * P,
其中W是世界到屏幕的转换,S是缩放,R是旋转和T是平移。
希望我至少有点帮助...
更新于2011年4月17日
好的,我现在已经查看了代码。SVG对象的PaintTo方法如下:
procedure TSVG.PaintTo(Graphics: TGPGraphics; Bounds: TGPRectF;
Rects: PRectArray; RectCount: Integer);
var
M: TGPMatrix;
MA: TMatrixArray;
begin
M := TGPMatrix.Create;
try
Graphics.GetTransform(M);
try
M.GetElements(MA);
FInitialMatrix.Cells[0, 0] := MA[0];
FInitialMatrix.Cells[0, 1] := MA[1];
FInitialMatrix.Cells[1, 0] := MA[2];
FInitialMatrix.Cells[1, 1] := MA[3];
FInitialMatrix.Cells[2, 0] := MA[4];
FInitialMatrix.Cells[2, 1] := MA[5];
FInitialMatrix.Cells[2, 2] := 1;
SetBounds(Bounds);
Paint(Graphics, Rects, RectCount);
finally
Graphics.SetTransform(M);
end;
finally
M.Free;
end;
end;
在进行任何绘图之前,该方法会调用Graphics.GetTransform(M)。这个方法又会调用GdipGetWorldTransform,它似乎是WinAPI的
GetWorldTransform的包装函数。
我猜这可能是一个好的起点 :)