Hittest使用屏幕坐标在SVG图像中的世界坐标



如何使用GDI+将鼠标坐标转换为世界坐标?或者为使用GDI+绘制的SVG形状获得边界框(甚至更好)旧学校区域?

。我一直在寻找SVG代码,发现:
http://development.mwcs.de/svgimage.html
这是第一个实际适用于SVG的Delphi组件,但我离题了。

该组件使用GDI+显示圆形、曲线等。
GDI+使用矩阵将世界坐标、旋转和扭曲转换为屏幕坐标。
这部分我理解。你用矩阵乘法来做平移

问题是
如果我将鼠标光标放在闭合形状上:

  1. 我从哪里获得矩阵,将我的鼠标屏幕点转换为我可以在屏幕上看到的圆圈中进行测试的世界点?
    在所有GDI对象中有如此多的矩阵可供选择。
  2. 不要给我关于绘制位图和测试光标下的神奇颜色的东西,这不是我想要的。
  3. 如果有一个矩阵链,我如何遍历它们在正确(倒转?)的顺序,使我的屏幕坐标得到正确引导到世界坐标?

换句话说
从SVG图像中读取的形状是被矩阵扭曲成屏幕坐标的原语。如何从屏幕坐标转换为我可以用来判断我是否在形状内的坐标呢?

请注意我需要知道我现在的状态。
由于SVG图像的设置方式,每个形状都有一个id,我想用它来查看我用鼠标击中了哪个区域。

编辑

或者

  1. 我能在屏幕坐标中得到每个形状的边界矩形吗?这样我就可以根据它检查鼠标坐标了。
  2. 我可以得到一个旧的学校GDI区域,在那里我可以做一个PtInRegion在屏幕坐标

希望你能帮我找到我的路在所有这些扭曲的路径:-)。

我没有深入研究代码,但是我可以在矩阵方面提供一点帮助(第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(角度)= R(角度)等等。您必须推导出变换的参数,然而,如果您只能访问变换矩阵,这可能不容易。

我猜,世界坐标是通过平移和缩放矩阵的组合转换为屏幕坐标的。最后一个负责"改变单位",从世界坐标到像素,考虑到整个场景的缩放系数(可能还有显示器的DPI)。另一方面,平移矩阵反映了场景的平移,可以在比例矩阵之前或之后应用;在第一种情况下,平移存储在世界坐标中,在第二种情况下,平移存储在屏幕坐标中。

我也会猜测,所有的对象转换都是在世界坐标中完成的(这听起来比在屏幕坐标中这样做更方便)。因此,您可能会期望,每个对象的点都服从以下转换:

W(S) (R(T) p)))) = W * S * R * T * p,

其中W为世界到屏幕的变换,S为缩放,R为旋转,T为平移。

希望我至少帮了点忙…


更新

17-04-2011

好了,我现在已经查看了代码内部。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的包装函数。

我想,这可能是一个很好的开始:)

使用GDI+,您必须跟踪您正在做的/已经做的事情,因为GDI+本身在绘制像素后会忘记除了像素本身之外的一切。SVG单元必须保持绘制所有形状和设置GDI+视口所需的所有内容。因此,从SVG库中获取所需的信息会更容易。

最新更新