在世界坐标中使用 SVG 图像中的屏幕坐标进行命中

发布于 2024-11-01 15:38:57 字数 1023 浏览 6 评论 0原文

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

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

该组件使用GDI+来显示圆、曲线等。
GDI+ 使用矩阵将世界坐标、旋转和扭曲转换为屏幕坐标。
这部分我明白了。您可以使用矩阵乘法来进行转换。

问题是这样的
如果我将鼠标光标指向一个封闭的形状:

  1. 我从哪里获得矩阵,它将把我的鼠标屏幕点转换为一个世界点,我可以将其击中到我在屏幕上看到的圆圈中?
    在所有这些 GDI 对象中,有太多的矩阵可供选择。
  2. 不要给我有关绘制位图和测试光标下的幻色的内容,这不是我想要的。
  3. 如果存在一系列矩阵,我如何以正确(倒置?)的顺序遍历它们,以便我的屏幕坐标正确引导到世界坐标?

换句话说
从 SVG 图像读取的形状是基元,它们被矩阵扭曲为屏幕坐标。 如何从屏幕坐标反转为可用于查看是否位于形状内的坐标。

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

编辑

或者

  1. 我可以在屏幕坐标中为每个形状获取一个边界矩形,以便我可以根据它检查我的鼠标坐标。
  2. 我可以得到一个旧的 skool GDI 区域,我可以在其中使用屏幕坐标执行 PtInRegion 吗?

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

How do I translate mouse coordinates into world coordinates using GDI+?
Or get bounding boxes (or even better) old skool regions for SVG shapes drawn using GDI+?

Anyway. I've been looking for SVG code and found:
http://development.mwcs.de/svgimage.html
This is the first Delphi component that actually works for SVG, but I digress.

This component uses GDI+ to display circles, curves etc.
GDI+ uses matrixes to convert world coordinates, rotations and distortions into screen coordinates.
This part I understand. You use matrix multiplication to do the translation.

The problem is this
If I point my mouse cursor over a closed shape:

  1. Where do I get the matrix from that will translate my screen-point of my mouse to a world point that I can hittest into the circle that I see drawn on the screen?
    There are soo many matrixes to choose from in all those GDI objects.
  2. Please don't give me stuff about drawing to a bitmap and testing for magic colors under the cursor, this is not what I'm looking for.
  3. If there is a chain of matrixes, how do I traverse them in the correct (inverted?) order so that my screen coordinate gets guided correctly to the world coordinate?

In other words
The shapes that are read in from an SVG image are primitives that get distorted by matrixes into screen-coordinates.
How do I do the reverse from a screen coordinate into the coordinates that I can use to see if I'm inside a shape or not.

please note
I need to know which shape I am in.
Because of the way the SVG image is set up, each shape has an id, and I want to use that to see what region I have hit with my mouse.

EDIT

Alternatively

  1. Can I get a bounding rect per shape in screen coordinates so I can check my mouse coordinates against that.
  2. Can I get a old skool GDI region where I can do a PtInRegion with in screen coordinates.

Hope you can help me find my way with all these distorted paths :-).

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

我要还你自由 2024-11-08 15:38:58

我没有深入研究代码,但我可以在矩阵方面提供一些帮助(第 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

我想,这可能是一个很好的起点:)

I didn't dug into code, but I can help a little with matrices (point 3).

I guess, that the three basic transformation matrices are used: the rotation, scale and translation matrix. Let's call them R, S and T, respectively.

There's a tricky part about applying matrices to the point. Say, you want to translate the point, and then rotate around the center of origin. In other words, you want to apply the rotation to the effect of the translation of the point. So, matrices will be applied in the following way:

R(T(P)) = R * T * P = S

Where * is the matrix multiplication. Note, that the order of multiplied matrices is reversed in relation to your intent.

However, if you want to make the inverse transformation, apart from reversing the order of matrices, you also have to evaluate their inverses. We translated the point, then rotated - so now we shall rotate it back and then translate back:

T^-1 ( R^-1 (S)) = T^-1 * R^-1 * S = P

Please note, that you don't have to calculate each matrice's inverse, as obviously T^-1(x) = T(-x), R^-1(angle) = R(-angle) and so on. You would have to deduce the transformation's argument, however, which may not be easy if you have access only to the transformation matrix.

I'd guess, that world coordinates are converted to screen coordinates by a combination of translate and scale matrix. The last one is responsible for "changing the unit" from world coordinates to pixels in respect to zoom factor of the whole scene (and, possibly, DPI of the display). The translation matrix, on the other hand, reflects the scene panning and may be applied either before or after the scale matrix; in the first case the panning is stored in world coordinates, in the second - panning is stored in screen coordinates.

I would also guess, that all the object transformations are being done in the world coordinates (it sounds more convenient to me than doing so in screen coordinates). So, you may expect, that each object's point is subjected to following transformation:

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

where W is the World-to-screen transformation, S is scale, R is rotation and T is translation.

Hope I helped at least a little...


Updated 17-04-2011

Ok, I've looked inside the code now. The PaintTo method of SVG object looks like this:

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;

Prior to any drawing, the method calls Graphics.GetTransform(M). This one, in turn, calls GdipGetWorldTransform, which appears to be a wrapper function on WinAPI's GetWorldTransform.

I guess, that it might be a good place to start :)

街道布景 2024-11-08 15:38:58

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

With GDI+ you have to keep track of what your doing / have done as GDI+ itself forgets everything but the pixels themselves after the pixels are drawn. The SVG unit must be keeping tack of everything needed to draw all the shapes and set the GDI+ viewport. So it would be easier to get the information your after from the SVG library.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文