¿Cómo "inflaría" un polígono? Es decir, quiero hacer algo similar a esto:
El requisito es que los bordes / puntos del nuevo polígono (inflado) estén a la misma distancia constante de los polígonos (originales) antiguos (en la imagen de ejemplo no lo son, ya que entonces tendría que usar arcos para vértices inflados, pero vamos a olvídate de eso por ahora;)).
El término matemático para lo que estoy buscando es en realidad offseting de polígono interno / externo . +1 a balint por señalar esto. La denominación alternativa es el almacenamiento en búfer de polígonos .
Resultados de mi búsqueda:
Aquí hay algunos enlaces:
Respuestas:
Pensé que podría mencionar brevemente mi propia biblioteca de recorte y compensación de polígonos - Clipper .
Si bien Clipper está diseñado principalmente para operaciones de recorte de polígonos, también compensa el polígono. La biblioteca es un software gratuito de código abierto escrito en Delphi, C ++ y C # . Tiene una licencia de Boost muy libre de gravámenes que le permite ser utilizado en aplicaciones gratuitas y comerciales sin cargo.
La compensación de polígonos se puede realizar utilizando uno de los tres estilos de compensación: cuadrado, redondo y a inglete.
fuente
El polígono que está buscando se llama polígono de desplazamiento hacia adentro / hacia afuera en geometría computacional y está estrechamente relacionado con el esqueleto recto .
Estos son varios polígonos desplazados para un polígono complicado:
Y este es el esqueleto recto para otro polígono:
Como se señaló en otros comentarios, también, dependiendo de qué tan lejos planee "inflar / desinflar" su polígono, puede terminar con una conectividad diferente para la salida.
Desde el punto de vista del cálculo: una vez que tenga el esqueleto recto, uno debería poder construir los polígonos de desplazamiento con relativa facilidad. La biblioteca CGAL de código abierto y (gratuita para no comerciales) tiene un paquete que implementa estas estructuras. Ver este ejemplo de código para calcular polígonos de compensación usando CGAL.
El manual del paquete debería darle un buen punto de partida sobre cómo construir estas estructuras, incluso si no va a utilizar CGAL, y contiene referencias a los documentos con las definiciones y propiedades matemáticas:
Manual CGAL: esqueleto recto 2D y compensación de polígono
fuente
Para este tipo de cosas, generalmente uso JTS . Para fines de demostración, creé este jsFiddle que usa JSTS (puerto JavaScript de JTS). Solo necesita convertir las coordenadas que tiene en coordenadas JSTS:
El resultado es algo como esto:
Información adicional : generalmente uso este tipo de inflado / desinflado (un poco modificado para mis propósitos) para establecer límites con radio en los polígonos que se dibujan en un mapa (con folletos o mapas de Google). Simplemente convierte pares (lat, lng) a coordenadas JSTS y todo lo demás es igual. Ejemplo:
fuente
Me parece que lo que quieres es:
d
a la "izquierda" del anterior.El polígono resultante se encuentra a la distancia requerida del antiguo polígono "lo suficientemente lejos" de los vértices. Cerca de un vértice, el conjunto de puntos a distancia
d
del antiguo polígono no es, como usted dice, un polígono, por lo que no se puede cumplir el requisito como se indica.No sé si este algoritmo tiene un nombre, un código de ejemplo en la web o una optimización diabólica, pero creo que describe lo que quieres.
fuente
En el mundo SIG, se utiliza el almacenamiento en búfer negativo para esta tarea: http://www-users.cs.umn.edu/~npramod/enc_pdf.pdf
La biblioteca JTS debería hacer esto por usted. Consulte la documentación para la operación del búfer: http://tsusiatsoftware.net/jts/javadoc/com/vividsolutions/jts/operation/buffer/package-summary.html
Para obtener una descripción general, consulte también la Guía del desarrollador: http://www.vividsolutions.com/jts/bin/JTS%20Developer%20Guide.pdf
fuente
Cada línea debe dividir el plano a "dentro" y "contorno"; Puede averiguarlo utilizando el método habitual de producto interno.
Mueva todas las líneas hacia afuera por cierta distancia.
Considere todos los pares de líneas vecinas (líneas, no segmentos de línea), encuentre la intersección. Estos son el nuevo vértice.
Limpie el nuevo vértice eliminando las partes que se cruzan. - tenemos algunos casos aquí
(a) Caso 1:
si lo gastas por uno, obtienes esto:
7 y 4 se superponen ... si ve esto, elimina este punto y todos los puntos intermedios.
(b) caso 2
si lo gastas por dos, obtienes esto:
Para resolver esto, para cada segmento de línea, debe verificar si se superpone con los últimos segmentos.
(c) caso 3
gasto por 1. este es un caso más general para el caso 1.
(d) caso 4
igual que en el caso 3, pero gasto por dos.
En realidad, si puede manejar el caso 4. Todos los demás casos son solo casos especiales con alguna superposición de línea o vértice.
Para hacer el caso 4, mantienes una pila de vértices ... empujas cuando encuentras líneas superpuestas con la última línea, revísala cuando obtienes la última línea. - Al igual que lo que haces en el casco convexo.
fuente
Aquí hay una solución alternativa, mira si te gusta más.
Haga una triangulación , no tiene que ser delaunay, cualquier triangulación funcionaría.
Infle cada triángulo; esto debería ser trivial. Si almacena el triángulo en el orden antihorario, simplemente mueva las líneas hacia el lado derecho y haga la intersección.
Fusionarlos usando un algoritmo de recorte Weiler-Atherton modificado
fuente
Muchas gracias a Angus Johnson por su biblioteca de podadoras. Hay buenos ejemplos de código para hacer el recorte en la página de inicio de Clipper en http://www.angusj.com/delphi/clipper.php#code pero no vi un ejemplo para la compensación de polígonos. Entonces pensé que tal vez sea útil para alguien si publico mi código:
fuente
Una opción más es utilizar boost :: polygon : falta algo de documentación, pero debería encontrar los métodos
resize
ybloat
, también, el+=
operador sobrecargado , que realmente implementa el almacenamiento en búfer. Entonces, por ejemplo, aumentar el tamaño de un polígono (o un conjunto de polígonos) en algún valor puede ser tan simple como:fuente
+=
con un conjunto de polígonos , no con polígonos individuales. Pruébelo con un std :: vector de polígonos. (Por supuesto, el vector solo necesita contener un polígono).Según los consejos de @ JoshO'Brian, parece que el
rGeos
paquete en elR
lenguaje implementa este algoritmo. VerrGeos::gBuffer
.fuente
Hay un par de bibliotecas que se pueden usar (también se pueden usar para conjuntos de datos 3D).
También se pueden encontrar las publicaciones correspondientes para estas bibliotecas para comprender los algoritmos con más detalle.
El último tiene la menor dependencia y es autónomo y puede leer en archivos .obj.
Mis mejores deseos, Stephan
fuente
Utilizo geometría simple: vectores y / o trigonometría
En cada esquina, encuentre el vector medio y el ángulo medio. El vector medio es el promedio aritmético de los dos vectores unitarios definidos por los bordes de la esquina. El ángulo medio es la mitad del ángulo definido por los bordes.
Si necesita expandir (o contraer) su polígono por la cantidad de d de cada borde; debe salir (dentro) por la cantidad d / sin (midAngle) para obtener el nuevo punto de esquina.
Repita esto para todas las esquinas
*** Ten cuidado con tu dirección. Haga la prueba CounterClockWise usando los tres puntos que definen la esquina; para averiguar qué camino está afuera o adentro.
fuente