2012-05-23 22 views
10

Tengo una imagen con un par de diamantes puestos al lado del otro, como en la imagen de abajocoordenadas de píxeles en diamante

diamond coordinates

La única coordenadas que sé en la imagen son las esquinas superiores (texto verde) .
Cuando hago clic en la imagen, obtengo las coordenadas de ese punto, pero no puedo obtener el diamante en el que estoy.
Por ejemplo, hago clic en el punto rojo, ¿cómo sé que x: 260, y: 179 = el diamante superior?
¿Y el azul pertenece a la izquierda? etc ...

Muchas gracias por su ayuda.

EDIT:
Finalmente utilicé Canvas, pero creo que SVG habría funcionado bien para lo que tenía que hacer.

+0

¿Y qué tiene que ver con Javascript y jQuery? Esto es solo matemática. – MaxArt

+0

Lo siento, porque lo hago en jquery, pero cierto no me concierne. Edité – Shadowbob

+1

Su imagen coloca el punto verde en el diamante inferior, pero las coordenadas corresponden al diamante correcto. Además, las coordenadas del punto azul lo colocan más cerca del borde del diamante inferior. –

Respuesta

9

veo dos enfoques posibles: comprobación directa si un punto está dentro de un diamante y utilizando transformaciones afines. Describiré ambos.

posición del punto de verificación directa

Para determinar si un punto está dentro de un diamante que usted tiene que comprobar su desviación desde el punto medio de un diamante. Tienes que poner las desviaciones X e Y en proporción con las extensiones X e Y del diamante, obtendrás dos factores. Para todos los puntos dentro del diamante, la suma de los valores del módulo para estos factores es menor o igual a 1.En el código de este se ve así:

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

Así que todo lo que tiene que hacer ahora es determinar el punto medio de cada diamante (el tamaño es el mismo en todos los casos) y comprobar si el punto que se está probando se encuentra dentro de ellos .

Ejemplo de trabajo: http://jsfiddle.net/z98hr/

afín transformaciones

Usando affine transformations puede cambiar las coordenadas de las esquinas de su diamante en la parte superior (0,0), (1,0), (0,1) y (1,1). Si luego aplicas la misma transformación al punto que necesitas probar, determinar a qué diana pertenece se vuelve trivial.

Primero necesitará un vector de traducción para mover el punto (225,2) al origen de las coordenadas. Digamos que usted tiene cuatro coordenadas que determinan su diamante superior (izquierda y derecha de coordenadas, la parte superior y coordinar inferior):

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

Entonces el translation vector para mover el punto superior del diamante al cero de coordenadas serían:

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

se puede aplicar a las coordenadas originales como esta:

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

entonces necesitará un 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)]]; 

Después de la multiplicación con esta matriz, los puntos (225,2) y (337,114.5) se alinean en el eje X. Pero lo que tenemos ahora es un trapecio, ahora tiene un horizontal shear transformation para llegar al otro lado del diamante alineados en el eje 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]]; 

Después de la multiplicación con esta matriz tiene un rectángulo ahora. Ahora sólo necesita un scaling matrix para asegurarse de que la coordenadas X e Y de las esquinas tienen el valor 0 y 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]]]; 

Y ahí lo tienes, ahora se puede aplicar estas transformaciones a cualquier punto:

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

Esto le da 0.94,0.63 - ambos valores están en la gama (0..1), lo que significa que es el diamante superior. Con [420,230] como entrada obtienes 1.88,0.14 - X en (1..2) rango y Y en 0..1 rango significa diamante derecho. Y así.

Ejemplo de trabajo: http://jsfiddle.net/FzWHe/

En la retrospectiva, esto era probablemente demasiado trabajo para una simple figura geométrica como un diamante.

+0

Trataré de aplicar eso en mi solicitud, te diré si funciona. Gracias por tu tiempo. – Shadowbob

+0

Ok, muchas gracias, tu respuesta fue la respuesta. lo más cercano a lo que necesitaba, pero difícil de aplicar en una grilla de 20x20 diamantes. Agradezco sus esfuerzos. Pero creo que intentaré un enfoque diferente en todo mi trabajo. – Shadowbob

1

Todo lo que necesita, simplemente qué es roration. Aquí está el enlace: http://en.wikipedia.org/wiki/Rotation_(mathematics)

Debe rotar su punto para hacer los lados de los cuadrados en paralelo con la cuadrícula de coordenadas. El punto de rotación debe ser 1 esquina de dimonds que amenazará como 0,0 diamante. Después de la rotación, puede definir fácilmente a cuántos daimond señala de 0,0

+0

Muy interesante, el diamante también es un poco plano, no lo especifiqué, así que si hay una rotación, será un trapecio, ¿seguirá funcionando? Soy muy malo en matemáticas :-( – Shadowbob

+0

@Shadowbob, en mi respuesta, supongo que tiene una forma rectangular. Si tienen una forma de paralelogramo, entonces debes elegir el punto de coordenadas cero (uno de los ángulos diaomns), luego recibir los lados vector y muestre el vector de la coordenada cero en el punto de clic como algunos de los vectores laterales con algunos coeficientes. Este coeficiente responderá. Desafortunadamente no puedo encontrar el material wiki apropiado para usted. – Dmitry

4

Esencialmente, lo que tiene allí es posiblemente una vista isométrica de 4 fichas (basado en su comentario sobre los diamantes que aparecen como trapecios).

Una forma rápida de hacerlo es crear 2 líneas que son paralelas a los "ejes" de los "diamantes" (pero que aún se cruzan entre sí ... esto también es importante). En la imagen de ejemplo dada, eso significaría dos líneas que son verticales entre sí, pero giradas en 45 grados. En el caso isométrico, las líneas no serán verticales entre sí, sino en algún otro ángulo, dependiendo de su vista.

Una vez que tenga estas dos líneas, puede crear una función "hitTest()" que tomará las coordenadas del punto al que se hizo clic y evaluará las dos ecuaciones de línea. No está realmente interesado en el número real devuelto por las ecuaciones de línea, sino solo en los signos. El letrero te muestra en qué lado de la línea reside tu punto.

Esto significa que sus "diamantes" corresponderán a estos pares de signos (un signo para cada ecuación de línea) [-, -], [-, +], [+, -], [+, +].

(Tenga en cuenta que el signo depende de la forma en que se definió la línea; en otras palabras, para un punto P dado, el signo de una ecuación de línea (L) será diferente si la línea se definió como ejecutando "desde de izquierda a derecha" o 'de derecha a izquierda', o más generalmente el signo será la inversa de direcciones recíprocas.)

Un poco más de información acerca de la forma de la ecuación de la línea que necesita se puede obtener from here

4

Al usar matrices, puede derivar una fórmula rápida para la que se selecciona el diamante.

Desea una transformación de (x,y) en "espacio de diamante". Es decir, un sistema de coordenadas donde (0,0) es el diamante superior, (1,0) es el de abajo a la derecha y (0,1) abajo a la izquierda.

A * x = y 

donde A es la transformación, es x las coordenadas de imagen, y y es el diamante coordenadas. Para tratar la traducción ((0,0) no es el mismo punto en ambos espacios), puede agregar otra fila a los vectores, que siempre es 1.

Puede transformar varios vectores al mismo tiempo, poniéndolos uno al lado del otro, para que formen una matriz.

[ 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 

para resolver los coeficientes de la primera matriz, es necesario dividir por la segunda matriz (o multiplicar por el inverso).

[ 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 ] 

El resultado es:

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

Para poner esto en el código del programa:

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

Ejemplo:

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

Si nos fijamos en las partes enteras, se puede ver a qué diana corresponde la coordenada. El rojo está en (0.94, 0.63) que está en la región (0,0) bastante cerca del borde de (1,0).


NB. Los puntos azul y verde en OP se dibujan en la ubicación incorrecta (o se dan coordenadas incorrectas), por lo que el resultado de mi función los coloca en una ubicación relativa diferente.


Si lo hace los cálculos simbólicamente, se termina con esto:

[ 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 ] 

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

El punto 0 es la posición del diamante superior, el punto 1 es la posición del diamante derecho, y el punto 2 es la posición del diamante izquierdo.

Aquí es una función para calcular esto:

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

Estoy tratando de hacer eso en mi aplicación I Te diré si tengo éxito, gracias por tu tiempo. – Shadowbob

Cuestiones relacionadas