Teniendo una lista de puntos, ¿cómo encuentro si están en el sentido de las agujas del reloj?
Por ejemplo:
point[0] = (5,0)
point[1] = (6,4)
point[2] = (4,5)
point[3] = (1,5)
point[4] = (1,0)
diría que es en sentido antihorario (o en sentido antihorario, para algunas personas).
Respuestas:
Algunos de los métodos sugeridos fallarán en el caso de un polígono no convexo, como una media luna. Aquí hay uno simple que funcionará con polígonos no convexos (incluso funcionará con un polígono auto intersectante como una figura ocho, que le indica si es principalmente en sentido horario).
Suma sobre los bordes, (x 2 - x 1 ) (y 2 + y 1 ). Si el resultado es positivo, la curva es en sentido horario, si es negativa, la curva es en sentido antihorario. (El resultado es el doble del área cerrada, con una convención +/-).
fuente
Sum( (x[(i+1) mod N] - x[i]) * (y[i] + y[(i+1) mod N]) )
para i = 0 a N-1. Es decir, debe tomar el índice Módulo N (N ≡ 0
) La fórmula funciona solo para polígonos cerrados . Los polígonos no tienen bordes imaginarios.El producto cruzado mide el grado de perpendicularidad de dos vectores. Imagine que cada borde de su polígono es un vector en el plano xy de un espacio tridimensional (3-D) xyz. Entonces, el producto cruzado de dos aristas sucesivas es un vector en la dirección z, (dirección z positiva si el segundo segmento es en sentido horario, menos dirección z si es en sentido antihorario). La magnitud de este vector es proporcional al seno del ángulo entre los dos bordes originales, por lo que alcanza un máximo cuando son perpendiculares y disminuye gradualmente para desaparecer cuando los bordes son colineales (paralelos).
Entonces, para cada vértice (punto) del polígono, calcule la magnitud del producto cruzado de los dos bordes adyacentes:
Por lo tanto, etiquete los bordes consecutivamente como
edgeA
es el segmento depoint0
apoint1
yedgeB
entrepoint1
apoint2
...
edgeE
está entrepoint4
ypoint0
.Entonces Vertex A (
point0
) está entreedgeE
[Depoint4
apoint0
]edgeA
[Depoint0
a `punto1 'Estos dos bordes son en sí mismos vectores, cuyas coordenadas x e y se pueden determinar restando las coordenadas de sus puntos inicial y final:
edgeE
=point0
-point4
=(1, 0) - (5, 0)
=(-4, 0)
yedgeA
=point1
-point0
=(6, 4) - (1, 0)
=(5, 4)
yY el producto cruzado de estos dos bordes contiguos se calcula utilizando el determinante de la matriz siguiente, que se construye poniendo las coordenadas de los dos vectores por debajo de los símbolos que representan los tres ejes de coordenadas (
i
,j
, yk
). La tercera coordenada (cero) está ahí porque el concepto de producto cruzado es una construcción tridimensional, por lo que ampliamos estos vectores 2-D a 3-D para aplicar el producto cruzado:Dado que todos los productos cruzados producen un vector perpendicular al plano de dos vectores que se multiplican, el determinante de la matriz anterior solo tiene un
k
componente (o eje z).La fórmula para calcular la magnitud del
k
componente del eje z esa1*b2 - a2*b1 = -4* 4 - 0* 1
=-16
La magnitud de este valor (
-16
), es una medida del seno del ángulo entre los 2 vectores originales, multiplicado por el producto de las magnitudes de los 2 vectores.En realidad, otra fórmula para su valor es
A X B (Cross Product) = |A| * |B| * sin(AB)
.Entonces, para volver solo a una medida del ángulo, necesita dividir este valor, (
-16
), por el producto de las magnitudes de los dos vectores.|A| * |B|
=4 * Sqrt(17)
=16.4924...
Entonces la medida del pecado (AB) =
-16 / 16.4924
=-.97014...
Esta es una medida de si el siguiente segmento después del vértice se ha doblado hacia la izquierda o hacia la derecha, y por cuánto. No hay necesidad de tomar arco-seno. ¡Lo único que nos importará es su magnitud y, por supuesto, su signo (positivo o negativo)!
Haga esto para cada uno de los otros 4 puntos alrededor de la ruta cerrada, y sume los valores de este cálculo en cada vértice.
Si la suma final es positiva, fue en sentido horario, negativo, en sentido antihorario.
fuente
Supongo que esta es una pregunta bastante antigua, pero de todos modos voy a lanzar otra solución, porque es sencilla y no es matemáticamente intensiva, solo usa álgebra básica. Calcule el área firmada del polígono. Si es negativo, los puntos están en el sentido de las agujas del reloj, si es positivo, son en sentido contrario. (Esto es muy similar a la solución de Beta).
Calcule el área con signo: A = 1/2 * (x 1 * y 2 - x 2 * y 1 + x 2 * y 3 - x 3 * y 2 + ... + x n * y 1 - x 1 * y n )
O en seudocódigo:
Tenga en cuenta que si solo está verificando el pedido, no necesita molestarse en dividir por 2.
Fuentes: http://mathworld.wolfram.com/PolygonArea.html
fuente
previousPoint
en la próxima iteración. Antes de comenzar el bucle, establezcapreviousPoint
el último punto de la matriz. La compensación es una copia variable local adicional pero menos accesos a la matriz. Y lo más importante, no tiene que tocar la matriz de entrada.Encuentra el vértice con la y más pequeña (y la x más grande si hay vínculos). Deje que el vértice sea
A
y el vértice anterior en la lista seaB
y el siguiente vértice en la lista seaC
. Ahora calcule el signo del producto cruzado deAB
yAC
.Referencias
¿Cómo encuentro la orientación de un polígono simple? en Preguntas frecuentes: comp.graphics.algorithms .
Orientación de curvas en Wikipedia.
fuente
O(1)
solución. Todas las demás respuestas danO(n)
soluciones paran
el número de puntos poligonales. Para optimizaciones aún más profundas, consulte la subsección Consideraciones prácticas del fantástico artículo de orientación Curva de Wikipedia.O(1)
solo si (A) este polígono es convexo (en cuyo caso cualquier vértice arbitrario reside en el casco convexo y, por lo tanto, es suficiente) o (B) ya conoce el vértice con la coordenada Y más pequeña. Si este no esel caso (es decir, este polígono no es convexo y no sabe nada al respecto),O(n)
se requiereunabúsqueda. Sin embargo, dado que no se requiere una suma, esto es aún más rápido que cualquier otra solución para polígonos simples.Aquí hay una implementación simple de C # del algoritmo basada en esta respuesta .
Supongamos que tenemos un
Vector
tipo que tieneX
yY
propiedades de tipodouble
.%
es el operador de módulo o resto que realiza la operación de módulo que ( según Wikipedia ) encuentra el resto después de la división de un número por otro.fuente
Comience en uno de los vértices y calcule el ángulo subtendido por cada lado.
El primero y el último serán cero (así que omítalos); para el resto, el seno del ángulo estará dado por el producto cruzado de las normalizaciones a la unidad de longitud de (punto [n] -punto [0]) y (punto [n-1] -punto [0]).
Si la suma de los valores es positiva, su polígono se dibuja en sentido antihorario.
fuente
Para lo que vale, utilicé este mixin para calcular el orden de liquidación de las aplicaciones de Google Maps API v3.
El código aprovecha el efecto secundario de las áreas de polígono: un orden de vértices en el sentido de las agujas del reloj produce un área positiva, mientras que un orden de devanado en sentido antihorario de los mismos vértices produce la misma área que un valor negativo. El código también utiliza una especie de API privada en la biblioteca de geometría de Google Maps. Me sentí cómodo usándolo, úselo bajo su propio riesgo.
Uso de la muestra:
Ejemplo completo con pruebas unitarias @ http://jsfiddle.net/stevejansen/bq2ec/
fuente
Una implementación de la respuesta de Sean en JavaScript:
Estoy bastante seguro de que esto es correcto. Parece estar funcionando :-)
Esos polígonos se ven así, si te estás preguntando:
fuente
Esta es la función implementada para OpenLayers 2 . La condición para tener un polígono en sentido horario es
area < 0
confirmada por esta referencia .fuente
Si usa Matlab, la función
ispolycw
devuelve verdadero si los vértices del polígono están en el orden de las agujas del reloj.fuente
Como también se explica en este artículo de Wikipedia Orientación de curvas , dados 3 puntos
p
,q
yr
en el plano (es decir, con coordenadas x e y), puede calcular el signo del siguiente determinanteSi el determinante es negativo (es decir
Orient(p, q, r) < 0
), entonces el polígono está orientado en sentido horario (CW). Si el determinante es positivo (es decirOrient(p, q, r) > 0
), el polígono está orientado en sentido antihorario (CCW). El determinante es cero (es decirOrient(p, q, r) == 0
) si puntosp
,q
yr
son colineales .En la fórmula anterior, anteponemos las que están delante de las coordenadas de
p
,q
yr
porque estamos usando coordenadas homogéneas .fuente
Creo que para que algunos puntos se den en el sentido de las agujas del reloj, todos los bordes deben ser positivos, no solo la suma de los bordes. Si un borde es negativo, al menos 3 puntos se dan en sentido antihorario.
fuente
Mi solución C # / LINQ se basa en los consejos de productos cruzados de @charlesbretana que se encuentran a continuación. Puede especificar una referencia normal para el devanado. Debería funcionar siempre que la curva esté principalmente en el plano definido por el vector ascendente.
con una prueba unitaria
fuente
Esta es mi solución usando las explicaciones en las otras respuestas:
fuente
Un método mucho más simple desde el punto de vista computacional, si ya conoce un punto dentro del polígono :
Elija cualquier segmento de línea del polígono original, los puntos y sus coordenadas en ese orden.
Agregue un punto "interno" conocido y forme un triángulo.
Calcule CW o CCW como se sugiere aquí con esos tres puntos.
fuente
Después de probar varias implementaciones poco confiables, el algoritmo que proporcionó resultados satisfactorios con respecto a la orientación CW / CCW fuera de la caja fue el publicado por OP en este hilo (
shoelace_formula_3
).Como siempre, un número positivo representa una orientación CW, mientras que un número negativo CCW.
fuente
Aquí está la solución swift 3.0 basada en las respuestas anteriores:
fuente
Otra solución para esto;
Toma todos los vértices como una matriz como esta;
fuente
Solución para que R determine la dirección e invierta si es en el sentido de las agujas del reloj (lo encontró necesario para los objetos):
fuente
Si bien estas respuestas son correctas, son matemáticamente más intensas de lo necesario. Asuma las coordenadas del mapa, donde el punto más al norte es el punto más alto del mapa. Encuentre el punto más al norte, y si empatan 2 puntos, es el más al norte que el más al este (este es el punto que lhf usa en su respuesta). En tus puntos
punto [0] = (5,0)
punto [1] = (6,4)
punto [2] = (4,5)
punto [3] = (1,5)
punto [4] = (1,0)
Si suponemos que P2 es el punto más al norte, entonces este, ya sea el punto anterior o el siguiente, determina en sentido horario, CW o CCW. Como el punto más al norte está en la cara norte, si el P1 (anterior) a P2 se mueve hacia el este, la dirección es CW. En este caso, se mueve hacia el oeste, por lo que la dirección es CCW como dice la respuesta aceptada. Si el punto anterior no tiene movimiento horizontal, entonces el mismo sistema se aplica al siguiente punto, P3. Si P3 está al oeste de P2, entonces el movimiento es CCW. Si el movimiento P2 a P3 es hacia el este, en este caso es hacia el oeste, el movimiento es CW. Suponga que nte, P2 en sus datos, es el punto más al norte que este y que prv es el punto anterior, P1 en sus datos, y nxt es el siguiente punto, P3 en sus datos, y [0] es horizontal u este / oeste donde oeste es menor que este, y [1] es vertical.
fuente
.x
y.y
de una estructura, en lugar de[0]
y[1]
no sabía lo que estaba diciendo su código, primera vez que eché un vistazo..)Código C # para implementar la respuesta de lhf :
fuente
Aquí hay una implementación simple de Python 3 basada en esta respuesta (que, a su vez, se basa en la solución propuesta en la respuesta aceptada )
fuente
encuentra el centro de masa de estos puntos.
supongamos que hay líneas desde este punto hasta tus puntos.
encuentra el ángulo entre dos líneas para line0 line1
que hacerlo para line1 y line2
...
...
si este ángulo está aumentando monotónicamente de lo contrario,
de lo contrario si disminuye monotónicamente es en sentido horario
de lo contrario (no es monotónico)
no puedes decidir, entonces no es sabio
fuente