Estoy trabajando en un juego que requiere que los jugadores dibujen una línea desde un punto A (x1, y1) hasta el otro punto B (x2, y2) en la pantalla de un dispositivo Android.
Quiero encontrar qué tan bien ese dibujo se ajusta a una línea recta. Por ejemplo, un resultado del 90% significaría que el dibujo se ajusta casi perfectamente a la línea. Si los jugadores dibujan una línea curva de A a B, debería obtener una puntuación baja.
Los puntos finales no se conocen de antemano. ¿Cómo puedo hacer esto?
j=1
por lo que se puede comparartouchList[j]
contouchList[j-1]
, pero cuandotouch.phase == TouchPhase.Began
otouch.phase == TouchPhase.Ended
las posiciones no se añaden atouchList
y posteriormente no incluido ensumLength
. Este error estaría presente en todos los casos, pero sería más evidente cuando la línea tiene pocos segmentos.Respuestas:
Una línea perfectamente recta también sería la línea más corta posible con una longitud total de
sqrt((x1-x2)² + (y1-y2)²)
. Una línea más garabateada será una conexión menos ideal y, por lo tanto, será inevitablemente más larga.Cuando toma todos los puntos individuales de la ruta que dibujó el usuario y suma las distancias entre ellos, puede comparar la longitud total con la longitud ideal. Cuanto más pequeña es la longitud total dividida por la longitud ideal, mejor es la línea.
Aquí hay una visualización. Cuando los puntos negros son los puntos finales del gesto y los puntos azules son los puntos que midió durante el gesto, calcularía y sumaría las longitudes de las líneas verdes y las dividiría por la longitud de la línea roja:
Un puntaje o índice de sinuosidad de 1 sería perfecto, cualquier cosa más alta sería menos perfecta, cualquier cosa por debajo de 1 sería un error. Cuando prefiera tener el puntaje en porcentaje, divida el 100% por ese número.
fuente
Esta podría no ser la mejor manera de implementar esto tampoco, pero sugiero que un RMSD ( desviación cuadrática media raíz) podría ser mejor, que simplemente el método de distancia, en los casos mencionados por Dancrumb (ver las dos primeras líneas a continuación).
RMSD = sqrt(mean(deviation^2))
Nota:
=sum(abs(deviation))
)(Por favor, disculpe la baja calidad de mi dibujo)
Como ves, tienes que
Si su línea apunta hacia
(1, 3)
lo que desea(3, -1)
(a través del origen cada uno)h
desde la línea ideal hasta la del usuario, paralelas a ese vector.fuente
Las respuestas existentes no tienen en cuenta que los puntos finales son arbitrarios (en lugar de dados). Por lo tanto, al medir la rectitud de la curva, no tiene sentido usar los puntos finales (por ejemplo, para calcular la longitud, el ángulo, la posición esperados). Un ejemplo simple sería una línea recta con ambos extremos doblados. Si medimos usando la distancia desde la curva y la línea recta entre los puntos finales, esto será bastante grande, ya que la línea recta que hemos dibujado está desplazada de la línea recta entre los puntos finales.
¿Cómo sabemos qué tan recta es la curva? Suponiendo que la curva es lo suficientemente suave, queremos saber cuánto, en promedio, está cambiando la tangente a la curva. Para una línea, esto sería cero (ya que la tangente es constante).
Si dejamos que la posición en el tiempo t sea (x (t), y (t)), entonces la tangente es (Dx (t), Dy (t)), donde Dx (t) es la derivada de x en el tiempo t (este sitio parece no tener soporte para TeX). Si la curva no está parametrizada por la longitud del arco, normalizamos dividiendo entre || (Dx (t), Dy (t)) ||. Entonces tenemos un vector unitario (o ángulo) de la tangente a la curva en el tiempo t. Entonces, el ángulo es a (t) = (Dx (t), Dy (t)) / || (Dx (t), Dy (t)) ||
Entonces estamos interesados en || Da (t) || ^ 2 integrado a lo largo de la curva.
Dado que lo más probable es que tengamos puntos de datos discretos en lugar de una curva, debemos usar diferencias finitas para aproximar las derivadas. Entonces, Da (t) se convierte
(a(t+h)-a(t))/h
. Y, a (t) se convierte((x(t+h)-x(t))/h,(y(t+h)-y(t))/h)/||((x(t+h)-x(t))/h,(y(t+h)-y(t))/h)||
. Luego obtenemos S sumandoh||Da(t)||^2
todos los puntos de datos y posiblemente normalizándolos por la longitud de la curva. Lo más probable es que lo usemosh=1
, pero en realidad es solo un factor de escala arbitrario.Para reiterar, S será cero para una línea y más grande cuanto más se desvía de una línea. Para convertir al formato requerido, use
1/(1+S)
. Dado que la escala es algo arbitraria, es posible multiplicar S por algún número positivo (o transformarlo de alguna otra manera, por ejemplo, usar bS ^ c en lugar de S) para ajustar qué tan rectas son ciertas curvas.fuente
Este es un sistema basado en cuadrícula, ¿verdad? Encuentra tus propios puntos para la línea y calcula la pendiente de la línea. Ahora, usando ese cálculo, determine los puntos válidos por los que pasaría la línea, dado un margen de error del valor exacto.
A través de una pequeña cantidad de pruebas de prueba y error, determine qué cantidad buena y mala de puntos coincidentes existiría y configure su juego usando una escala para obtener los mismos resultados de sus pruebas.
es decir, una línea corta con pendiente casi horizontal puede tener 7 puntos por los que podría dibujar. Si puede igualar consistentemente 6 o más de los 7 que se determinó que son parte de la línea recta, entonces ese sería el puntaje más alto. La calificación de longitud y precisión debe ser parte de la puntuación.
fuente
Una medida muy fácil e intuitiva es el área entre la línea recta que mejor se ajusta y la curva real. Determinar esto es bastante sencillo:
fuente
La idea es mantener todos los puntos que tocó el usuario, luego evaluar y sumar la distancia entre cada uno de esos puntos a la línea formada cuando el usuario suelta la pantalla.
Aquí hay algo para comenzar con el pseudocódigo:
Lo que
cumulativeDistance
podría darte una idea sobre el ajuste. Una distancia de 0 significaría que el usuario estaba en línea recta todo el tiempo. Ahora tendría que hacer algunas pruebas para ver cómo se comporta en su contexto. Y es posible que desee amplificar el valor devuelto aldistanceOfPointToLine
cuadrarlo para penalizar más las grandes distancias de la línea.No estoy familiarizado con la unidad, pero el código
update
aquí puede ir en unaonDrag
función.Y es posible que desee agregar un código en algún lugar para evitar registrar un punto si es el mismo que el último registrado. No desea registrar cosas cuando el usuario no se mueve.
fuente
Un método que podría usar es subdividir la línea en segmentos y hacer un producto de puntos vectoriales entre cada vector que representa el segmento y un vector que representa una línea recta entre el primer y el último punto. Esto tiene el beneficio de permitirle encontrar segmentos extremadamente "puntiagudos" fácilmente.
Editar:
Además, consideraría usar la longitud del segmento además del producto punto. Un vector muy corto pero ortogonal debe contar menos que uno largo que tenga menos desviación.
fuente
Lo más fácil y rápido podría ser simplemente descubrir qué tan gruesa debería ser la línea para cubrir todos los puntos de la línea dibujada por el usuario.
Cuanto más gruesa sea la línea, peor será el usuario al dibujar su línea.
fuente
De alguna manera, refiriéndome a MSalters Answer, aquí hay información más específica.
Use el método de mínimos cuadrados para ajustar una línea para sus puntos. Básicamente está buscando una función y = f (x) que se ajuste mejor. Una vez que lo tenga, puede usar los valores reales de y para sumar el cuadrado de las diferencias:
s = suma sobre ((yf (x)) ^ 2)
Cuanto más pequeña es la suma, más recta es la línea.
Aquí se explica cómo obtener la mejor aproximación: http://math.mit.edu/~gs/linearalgebra/ila0403.pdf
Acabo de leer de "Ajustar una línea recta". Tenga en cuenta que t se usa en lugar de x y b en lugar de y. C y D se determinarán como aproximación, entonces usted tiene f (x) = C + Dx
Nota adicional: Obviamente, también debe tener en cuenta la longitud de la línea. Cada línea que consta de 2 puntos será perfecta. No sé el contexto exacto, pero creo que usaría la suma de cuadrados dividida por el número de puntos como calificación. También agregaría el requisito de una longitud mínima, un número mínimo de puntos. (Tal vez alrededor del 75% de la longitud máxima)
fuente