钻石上的像素坐标

时间:2012-05-23 08:39:40

标签: math coordinates

我得到了一张图像,其中有几颗钻石并排放置,如下图所示

diamond coordinates

我在图像上知道的唯一坐标是顶角(绿色文字) 当我点击图像时,我得到了那个点的坐标,但是我无法得到我正在使用的钻石。
例如,我点击红点,我怎么知道x:260,y:179 =顶部钻石?
蓝色属于左边?等...

非常感谢你的帮助。

编辑:
我最终使用了Canvas,但我认为SVG可以用于我需要做的事情。

4 个答案:

答案 0 :(得分:9)

我看到两种可能的方法:直接检查一个点是否在钻石内并使用仿射变换。我将描述两者。

直接点位置检查

要确定某个点是否位于钻石内,您必须检查其与钻石中点的偏差。你必须将X和Y偏差与钻石的X和Y范围成比例,你将得到两个因素。对于菱形内的所有点,这些因子的模数值之和小于或等于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/

仿射变换

使用affine transformations,您可以将顶部钻石的角坐标更改为(0,0),(1,0),(0,1)和(1,1)。如果您然后将相同的变换应用于您需要测试的点,则确定它所属的钻石变得微不足道。

首先,您需要一个平移向量来将(225,2)点移动到坐标原点。假设您有四个坐标确定您的顶部钻石(左右坐标,顶部和底部坐标):

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

然后将translation vector将钻石的顶点移动到零坐标将是:

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)];

然后你需要一个rotation matrix

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轴上对齐。但你现在拥有的是一个空中飞人,你现在需要一个horizontal shear transformation来让钻石的另一侧在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]];

与此矩阵相乘后,现在有一个矩形。现在你只需scaling matrix来确保角的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.14 - (1..2)范围内的X和0..1范围内的Y表示右菱形。等等。

工作示例:http://jsfiddle.net/FzWHe/

在回顾展中,对于像钻石这样的简单几何图形来说,这可能太多了。

答案 1 :(得分:4)

基本上,你所拥有的可能是4个瓷砖的等距视图(基于你对作为梯形的钻石的评论)。

这样做的一个简单方法是创建两条与“钻石”的“轴”平行的线(但仍然相互交叉......这也很重要)。在给出的示例图像中,这意味着两条线彼此垂直但旋转45度。在等距情况下,线条不会彼此垂直,而是根据您的视图以其他角度。

一旦你有这两行你可以创建一个“hitTest()”函数,它将获取被点击的点的坐标,并将评估两个线方程。您对线方程返回的实际数字并不感兴趣,只有符号。标志显示您的点位于哪一侧。

这意味着你的“钻石”将对应于这些符号对(每个线方程的一个符号)[ - , - ],[ - ,+],[+, - ],[+,+]。

(请注意,符号取决于定义线的方式,换句话说,对于给定点P,如果线被定义为“从左边开始”,则来自某些线方程(L)的符号将不同向右“或”从右到左“,或更一般地,符号将是相反方向的反向。)

可以获得有关您需要的线方程形式的更多信息from here

答案 2 :(得分: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

要求求第一个矩阵中的系数,需要除以第二个矩阵(或乘以逆矩阵)。

[ 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),非常接近[ 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 ] 的边缘。


NB。 OP中的蓝点和绿点是在错误的位置绘制的(或给定错误的坐标),因此我的函数的结果将它们放在不同的相对位置。


如果您以符号方式进行计算,最终会得到:

M = x1*y2 - x2*y1 - y0*x1 + y0*x2 + x0*y1 - x0*y2

其中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)

点0是顶部钻石的位置,第1点是右菱形的位置,第2点是左菱形的位置。

这是一个计算它的函数:

{{1}}

答案 3 :(得分:1)

所有你需要的 - 只是稳定什么是roration。这是链接:http://en.wikipedia.org/wiki/Rotation_(mathematics

你应该旋转你的点,以使正方形的边与坐标的网格平行。旋转点应该是dimonds的1角,你将威胁为0,0钻石。在旋转之后,您可以轻松定义从0,0

指出的daimond数量