10

下の画像のようにダイヤモンドを2つ並べた画像を取得しました

ダイヤモンド座標

画像でわかっている唯一の座標は、上隅 (緑色のテキスト) です。
画像をクリックすると、そのポイントの座標を取得できますが、どのダイヤモンドにいるのかを取得できません。
たとえば、赤い点をクリックすると、x:260、y:179 = 一番上のひし形であることをどのように知ることができますか?
そして青は左に属しますか?等...

ご助力ありがとうございます。

編集:
私は最終的にキャンバスを使用しましたが、SVG は私がする必要があることに対しても同様に機能したと思います。

4

4 に答える 4

9

ポイントがダイヤモンドの内側にあるかどうかを直接確認する方法と、アフィン変換を使用する方法の 2 つが考えられます。両方について説明します。

ダイレクトポイント位置確認

ポイントがダイヤモンドの内側にあるかどうかを判断するには、ダイヤモンドの中心点からの偏差を確認する必要があります。X と Y の偏差を、ダイヤモンドの X と Y の範囲に比例させる必要があります。2 つの要素が得られます。ダイヤモンド内のすべてのポイントについて、これらの係数のモジュロ値の合計は 1 以下です。コードでは、次のようになります。

var dx = Math.abs(coords[0] - middle[0]);
var dy = Math.abs(coords[1] - middle[1]);
if (dx / size[0] + dy / size[1] <= 1)
  alert("Inside diamond");
else
  alert("Outside diamond");

したがって、各ダイアモンドの中間点 (サイズはすべての場合で同じ) を決定し、テストしている点がその内部にあるかどうかを確認するだけです。

作業例: http://jsfiddle.net/z98hr/

アフィン変換

アフィン変換を使用して、上のダイヤモンドのコーナー座標を (0,0)、(1,0)、(0,1)、および (1,1) に変更できます。次に、テストする必要があるポイントに同じ変換を適用すると、それがどのダイヤモンドに属しているかを判断するのは簡単になります。

最初に、(225,2) 点を座標の原点に移動するための平行移動ベクトルが必要になります。上のひし形を決定する 4 つの座標 (左右の座標、上下の座標) があるとします。

var topDiamond = [[113, 2], [337, 227]];

次に、ダイヤモンドの頂点をゼロ座標に移動するための平行移動ベクトルは次のようになります。

var translationVector = [-(topDiamond[0][0] + topDiamond[1][0]) / 2,
                         -topDiamond[0][1]];

次のように元の座標に適用できます。

function add(vector1, vector2)
{
  return [vector1[0] + vector2[0], vector1[1] + vector2[1]];
}
topDiamond = [add(topDiamond[0], translationVector),
              add(topDiamond[1], translationVector)];

次に、回転行列が必要になります。

var angle = -Math.atan2(topDiamond[1][1] - topDiamond[0][1],
                        topDiamond[1][0] - topDiamond[0][0]);
var rotMatrix = [[Math.cos(angle), -Math.sin(angle)],
                 [Math.sin(angle), Math.cos(angle)]];

この行列を乗算した後、点 (225,2) と (337,114.5) が X 軸上に配置されます。しかし、今あなたが持っているのは台形です。次に、水平方向のせん断変換を行って、ダイヤモンドの反対側を Y 軸に揃える必要があります。

function multiply(matrix, vector)
{
  return [matrix[0][0] * vector[0] + matrix[0][1] * vector[1],
          matrix[1][0] * vector[0] + matrix[1][1] * vector[1]];
}
var point = [topDiamond[0][0], (topDiamond[0][1] + topDiamond[1][1]) / 2];
point = multiply(rotMatrix, point);
var shearMatrix = [[1, -point[0] / point[1]], [0, 1]];

この行列を掛けると、長方形になります。これで、角の X 座標と Y 座標の値が 0 と 1 になるように、スケーリング マトリックスだけが必要になります。

point = multiply(shearMatrix, point);
var point2 = [topDiamond[1][0], (topDiamond[0][1] + topDiamond[1][1]) / 2];
point2 = multiply(rotMatrix, point2);
point2 = multiply(shearMatrix, point2);
var scaleMatrix = [[1/point2[0], 0], [0, 1/point[1]]];

これで、これらの変換を任意のポイントに適用できるようになりました。

alert(
  multiply(scaleMatrix,
    multiply(shearMatrix,
      multiply(rotMatrix,
        add(translationVector, [260, 179])
      )
    )
  )
);

これにより、0.94,0.63両方の値が(0..1)範囲内にあり、それが一番上のダイヤモンドであることを意味します。[420,230]入力として取得すると、範囲内の1.88,0.14X と(1..2)範囲内の Y0..1は右のひし形を意味します。等々。

作業例: http://jsfiddle.net/FzWHe/

振り返ってみると、これはおそらく、ダイヤモンドのような単純な幾何学的図形には多すぎる作業でした.

于 2012-05-23T09:55:27.430 に答える
4

マトリックスを使用すると、選択されたダイヤモンドの簡単な式を導き出すことができます。

(x,y)から「ダイヤモンド空間」への変換が必要です。つまり、座標系(0,0)は が一番上のひし形で(1,0)、右下が(0,1)下、左が下です。

A * x = y

A変換、xは画像座標、yはダイヤモンド座標です。平行移動 (両方の空間で同じ点ではない) に対処するため(0,0)に、ベクトルに別の行を追加できます。これは常に1です。

複数のベクトルを並べて配置することで、同時に複数のベクトルを変換できるため、行列が形成されます。

[ a b dx ]   [ 225 337 113 ]   [ 0 1 0 ]
[ c d dy ] * [   2 114 114 ] = [ 0 0 1 ]
[ 0 0  1 ]   [   1   1   1 ]   [ 1 1 1 ]
                 ^   ^   ^-left  ^-^-^--- new coordinates for each point
                 |   '-right
                 '-top diamond

最初の行列の係数を解くには、2 番目の行列で割る (または逆数を掛ける) 必要があります。

[ a b dx ]   [ 0 1 0 ]   [ 225 337 113 ]^-1
[ c d dy ] = [ 0 0 1 ] * [   2 114 114 ]
[ 0 0  1 ]   [ 1 1 1 ]   [   1   1   1 ]

結果は次のとおりです。

[ a b dx ]   [  (1/224) (1/224) (-227/224) ]
[ c d dy ] = [ (-1/224) (1/224)  (223/224) ]
[ 0 0  1 ]   [   0       0          1      ]

これをプログラムコードに入れるには:

function getDiamond(x, y) {
    return [(x + y - 227) / 224, (-x + y + 223) / 224];
}

例:

> getDiamond(260,179); // red
[0.9464285714285714, 0.6339285714285714]
> getDiamond(250,230); // green
[1.1294642857142858, 0.90625]
> getDiamond(189,250); // blue
[0.9464285714285714, 1.2678571428571428]
> getDiamond(420,230); // yellow
[1.8883928571428572, 0.14732142857142858]

整数部分を見ると、座標がどのダイヤモンドに対応しているかがわかります。赤いものはの端にかなり近い(0.94, 0.63)領域にあります。(0,0)(1,0)


注意。OP の青と緑の点が間違った場所 (または間違った座標が指定されている) に描画されているため、関数の結果はそれらを別の相対位置に配置します。


シンボリックに計算すると、次のようになります。

[ a b dx ]   [ (y2 - y0)/M  -(x2 - x0)/M  -(x0*y2 - y0*x2)/M ]
[ c d dy ] = [-(y1 - y0)/M   (x1 - x0)/M   (x0*y1 - y0*x1)/M ]
[ 0 0  1 ]   [        0             0                   1    ]

どこでM = x1*y2 - x2*y1 - y0*x1 + y0*x2 + x0*y1 - x0*y2

ポイント 0 は上のダイヤモンドの位置、ポイント 1 は右のダイヤモンドの位置、ポイント 2 は左のダイヤモンドの位置です。

これを計算する関数は次のとおりです。

function DiamondMaker(topx,topy,  leftx,lefty,  rightx,righty)
{
    var M = topx*lefty - topx*righty +
            leftx*righty - leftx*topy +
            rightx*topy - rightx*lefty;
    var a  = -(topy - righty)/M;
    var b  =  (topx - rightx)/M;
    var dx = -(topx*righty - topy*rightx)/M;
    var c  =  (topy - lefty)/M;
    var d  = -(topx - leftx)/M;
    var dy =  (topx*lefty - topy*leftx)/M;
    return function(x, y) {
        return [a * x + b * y + dx, c * x + d * y + dy];
    };
}

var getDiamond = DiamondMaker(225,2,  337,114,  113,114);
// (same example as before)
于 2012-05-23T09:54:19.317 に答える
4

基本的に、そこにあるのはおそらく4つのタイルの等角図です(台形として表示されるダイヤモンドについてのコメントに基づいています)。

これを行う簡単な方法の 1 つは、「ダイヤモンド」の「軸」と平行な 2 つの線を作成することです (ただし、互いに交差しています...これも重要です)。与えられた画像の例では、互いに垂直であるが 45 度回転した 2 つの線を意味します。アイソメの場合、線は互いに垂直ではなく、ビューに応じて他の角度になります。

これらの 2 つの線を取得したら、クリックされたポイントの座標を取得し、2 つの線の方程式を評価する「hitTest()」関数を作成できます。線形方程式によって返される実際の数にはあまり関心がなく、符号だけに関心があります。記号は、あなたのポイントがラインのどちら側にあるかを示します。

これは、あなたの「ひし形」がこれらの記号のペア (線の方程式ごとに 1 つの記号) [-,-]、[-,+]、[+,-]、[+,+] に対応することを意味します。

(記号は、線が定義された方法に依存することに注意してください。つまり、特定の点 P について、線が「左から右」に実行されるように定義されている場合、線の方程式 (L) の記号は異なります。または「右から左へ」、またはより一般的には逆方向の符号は逆になります。)

必要な直線方程式の形式に関するもう少し詳しい情報は、ここから入手できます。

于 2012-05-23T09:10:31.620 に答える
1

必要なのは、ローレーションとは何かを確認するだけです。ここにリンクがあります: http://en.wikipedia.org/wiki/Rotation_(mathematics )

四角形の辺を座標のグリッドと平行にするために、ポイントを回転させる必要があります。回転のポイントは、0,0 ダイヤモンドとして脅かすダイヤモンドの 1 つのコーナーである必要があります。回転後、0,0 から何個のダイヤモンドを指すかを簡単に定義できます。

于 2012-05-23T08:49:45.340 に答える