17

GDI+ を使用してマウス座標をワールド座標に変換するにはどうすればよいですか? または、GDI+ を使用して描画された SVG 形状のバウンディング ボックス (またはそれ以上) の古い skool 領域を取得しますか?

ともかく。私は SVG コードを探していて、見つけました:
http://development.mwcs.de/svgimage.html
これは、実際に SVG で動作する最初の Delphi コンポーネントですが、脱線します。

このコンポーネントは、GDI+ を使用して円、曲線などを表示します
。GDI+ はマトリックスを使用して、ワールド座標、回転、歪みを画面座標に変換します。
この部分はわかります。行列の乗算を使用して変換を行います。

問題は
、マウスカーソルを閉じた形状の上に置いた場合です。

  1. マウスのスクリーン ポイントをワールド ポイントに変換して、画面上に描かれた円にヒット テストできるマトリックスをどこから取得すればよいでしょうか。
    これらすべての GDI オブジェクトの中から選択できるマトリックスが非常に多くあります。
  2. ビットマップへの描画とカーソル下の魔法の色のテストについて教えてください。これは私が探しているものではありません。
  3. マトリックスのチェーンがある場合、スクリーン座標がワールド座標に正しく導かれるように、それらを正しい (反転した?) 順序でトラバースするにはどうすればよいですか?

つまり
、SVG 画像から読み込まれた形状は、マトリックスによって画面座標に歪められるプリミティブです。画面座標から座標に逆算して、図形の中にいるかどうかを確認するにはどうすればよいですか。

現在の形状を知る必要があることに注意してください
。SVG 画像の設定方法により、各形状には ID があり、それを使用して、マウスでヒットした領域を確認したいと考えています。

編集

あるいは

  1. 画面座標で形状ごとに境界四角形を取得して、それに対してマウス座標を確認できますか?
  2. 画面座標で PtInRegion を実行できる古い skool GDI リージョンを取得できますか。

これらすべての歪んだパスで自分の道を見つけるのを手伝ってくれることを願っています:-)。

4

2 に答える 2

7

コードを掘り下げることはしませんでしたが、マトリックスを少し手伝うことができます (ポイント 3)。

回転、スケール、平行移動の 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(-角度) などのように、各行列の逆行列を計算する必要がないことに注意してください。ただし、変換の引数を推測する必要がありますが、変換マトリックスにしかアクセスできない場合、これは簡単ではない可能性があります。

世界座標は、変換行列とスケール行列の組み合わせによって画面座標に変換されると思います。最後の 1 つは、シーン全体のズーム率 (および、場合によってはディスプレイの DPI) に関して、ワールド座標からピクセルへの「単位の変更」を担当します。一方、平行移動マトリックスはシーンのパンを反映し、スケール マトリックスの前または後に適用できます。最初のケースでは、パンはワールド座標で保存され、2 番目のケースでは、パンはスクリーン座標で保存されます。

また、すべてのオブジェクト変換がワールド座標で行われていると推測します (画面座標で行うよりも便利に思えます)。したがって、各オブジェクトのポイントが次の変換を受けることを期待できます。

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) を呼び出します。これは、WinAPI のGetWorldTransformのラッパー関数のように見える GdipGetWorldTransform を呼び出します。

私は、それが始めるのに良い場所かもしれないと思います:)

于 2011-04-16T17:47:26.057 に答える
-1

GDI +を使用すると、GDI +自体がピクセルが描画された後、ピクセル自体以外のすべてを忘れてしまうため、自分が行ったこと/行ったことを追跡する必要があります。SVGユニットは、すべての形状を描画し、GDI+ビューポートを設定するために必要なすべてのものを把握している必要があります。そのため、SVGライブラリから後で情報を取得する方が簡単です。

于 2011-05-30T22:07:23.097 に答える