Recientemente me encontré con un problema en el que tenía cuatro círculos (puntos medios y radio) y tenía que calcular el área de la unión de estos círculos.
Imagen de ejemplo:
Para dos círculos es bastante fácil
Puedo calcular la fracción del área de cada círculo que no está dentro de los triángulos y luego calcular el área de los triángulos.
Pero, ¿hay algún algoritmo inteligente que pueda usar cuando hay más de dos círculos?
Respuestas:
Encuentre todas las intersecciones de círculos en el perímetro exterior (por ejemplo, B, D, F, H en el siguiente diagrama). Conéctelos con los centros de los círculos correspondientes para formar un polígono. El área de la unión de los círculos es el área del polígono + el área de los cortes del círculo definidos por puntos de intersección consecutivos y el centro del círculo entre ellos. También deberá tener en cuenta los agujeros.
fuente
Estoy seguro de que hay un algoritmo inteligente, pero aquí hay uno tonto para evitar tener que buscarlo;
Seguro que es tonto, pero:
fuente
La respuesta de Ants Aasma dio la idea básica, pero quería hacerlo un poco más concreto. Observe los cinco círculos a continuación y la forma en que se han descompuesto.
Identificar estos 3 tipos de puntos es fácil. Ahora construya una estructura de datos de gráfico donde los nodos sean los puntos azules y los puntos rojos con el interior blanco. Para cada círculo, coloque un borde entre el medio del círculo (punto azul) y cada una de sus intersecciones (puntos rojos con interior blanco) en su límite.
Esto descompone la unión circular en un conjunto de polígonos (sombreados en azul) y trozos circulares (sombreados en verde) que están separados por pares y cubren la unión original (es decir, una partición). Dado que cada pieza aquí es algo que es fácil de calcular el área de, puede calcular el área de la unión sumando las áreas de las piezas.
fuente
Para una solución diferente a la anterior, podría producir una estimación con una precisión arbitraria utilizando un quadtree.
Esto también funciona para cualquier unión de forma si puede saber si un cuadrado está dentro o fuera o se cruza con la forma.
Cada celda tiene uno de los estados: vacío, lleno, parcial
El algoritmo consiste en "dibujar" los círculos en el quadtree comenzando con una resolución baja (4 celdas, por ejemplo, marcadas como vacías). Cada celda es:
Cuando haya terminado, puede calcular una estimación del área: las celdas completas dan el límite inferior, las celdas vacías dan el límite superior, las celdas parciales dan el error de área máxima.
Si el error es demasiado grande para usted, refine las celdas parciales hasta obtener la precisión correcta.
Creo que esto será más fácil de implementar que el método geométrico que puede requerir manejar muchos casos especiales.
fuente
Me encanta el enfoque del caso de 2 círculos que se cruzan; así es como usaría una ligera variación del mismo enfoque para el ejemplo más complejo.
Podría dar una mejor idea de la generalización del algoritmo para un mayor número de círculos semi superpuestos.
La diferencia aquí es que empiezo por vincular los centros (por lo que hay un vértice entre el centro de los círculos, en lugar de entre los lugares donde los círculos se cruzan). Creo que esto permite generalizar mejor.
(en la práctica, quizás valga la pena el método montecarlo)
(fuente: secretGeek.net )
fuente
Si desea una respuesta discreta (en lugar de una continua), puede hacer algo similar a un algoritmo de pintura de píxeles.
Dibuja los círculos en una cuadrícula y luego colorea cada celda de la cuadrícula si está mayormente contenida dentro de un círculo (es decir, al menos el 50% de su área está dentro de uno de los círculos). Haga esto para toda la cuadrícula (donde la cuadrícula abarca toda el área cubierta por los círculos), luego cuente el número de celdas coloreadas en la cuadrícula.
fuente
Hmm, problema muy interesante. Mi enfoque probablemente sería algo similar a lo siguiente:
(esto es cierto para cualquier forma, ya sea circular o no)
Donde
A ∪ B
significa A unión B yA ∩ B
significa A intersección B (puede resolver esto desde el primer paso.(Esto es lo mismo que arriba donde
A
se ha reemplazado porA∪B
)Donde
area(A∪B)
acabamos de hacer ejercicio yarea((A∪B)∩C)
se puede encontrar:Donde nuevamente puedes encontrar el área (A∩B∩C) desde arriba.
Lo complicado es el último paso: cuantos más círculos se agregan, más complejo se vuelve. Creo que hay una expansión para resolver el área de una intersección con una unión finita, o, alternativamente, es posible que pueda resolverlo de forma recursiva.
También con respecto al uso de Monte-Carlo para aproximar el área de la sección, creo que es posible reducir la intersección de un número arbitrario de círculos a la intersección de 4 de esos círculos, que se pueden calcular exactamente (no tengo idea de cómo hacer esto sin embargo).
Probablemente haya una mejor manera de hacer esto por cierto: la complejidad aumenta significativamente (posiblemente exponencialmente, pero no estoy seguro) por cada círculo adicional agregado.
fuente
He estado trabajando en un problema de simulación de campos de estrellas superpuestos, tratando de estimar los recuentos de estrellas reales a partir de las áreas reales del disco en campos densos, donde las estrellas brillantes más grandes pueden enmascarar las más débiles. Yo también esperaba poder hacer esto mediante un análisis formal riguroso, pero no pude encontrar un algoritmo para la tarea. Lo resolví generando los campos de estrellas sobre un fondo azul como discos verdes, cuyo diámetro fue determinado por un algoritmo de probabilidad. Una rutina simple puede emparejarlos para ver si hay una superposición (volviendo amarillo el par de estrellas); luego, un recuento de píxeles de los colores genera el área observada para compararla con el área teórica. Esto luego genera una curva de probabilidad para los conteos verdaderos. Tal vez la fuerza bruta, pero parece funcionar bien. (fuente: 2from.com )
fuente
Aquí hay un algoritmo que debería ser fácil de implementar en la práctica y podría ajustarse para producir un error arbitrariamente pequeño:
Los pasos 2 y 3 se pueden llevar a cabo utilizando algoritmos estándar fáciles de encontrar de geometría computacional.
Obviamente, cuantos más lados use para cada polígono aproximado, más cercana será su respuesta exacta. Puede realizar una aproximación utilizando polígonos inscritos y circunscritos para obtener límites en la respuesta exacta.
fuente
Existen soluciones eficientes a este problema utilizando lo que se conoce como diagramas de potencia. Sin embargo, esta es una matemática realmente pesada y no es algo que me gustaría abordar de inmediato. Para una solución "fácil", busque algoritmos de barrido de línea. El principio básico aquí es que divide la figura en tiras, donde calcular el área en cada tira es relativamente fácil.
Entonces, en la figura que contiene todos los círculos sin nada borrado, dibuje una línea horizontal en cada posición que sea la parte superior de un círculo, la parte inferior de un círculo o la intersección de 2 círculos. Observe que dentro de estas tiras, todas las áreas que necesita calcular tienen el mismo aspecto: un "trapecio" con dos lados reemplazados por segmentos circulares. Entonces, si puede averiguar cómo calcular esa forma, simplemente hágalo para todas las formas individuales y súmelas. La complejidad de este enfoque ingenuo es O (N ^ 3), donde N es el número de círculos en la figura. Con un uso inteligente de la estructura de datos, podría mejorar este método de barrido de línea a O (N ^ 2 * log (N)), pero a menos que realmente lo necesite, probablemente no valga la pena.
fuente
Encontré este enlace que puede ser útil. Sin embargo, no parece haber una respuesta definitiva. Google responde . Otra referencia para tres círculos es el teorema de Haruki . Allí también hay un periódico.
fuente
Dependiendo del problema que esté tratando de resolver, podría ser suficiente obtener un límite superior e inferior. Un límite superior es fácil, solo la suma de todos los círculos. Para un límite inferior, puede elegir un solo radio de modo que ninguno de los círculos se superponga. Para mejorar eso, encuentre el radio más grande (hasta el radio real) para cada círculo para que no se superponga. También debería ser bastante trivial eliminar cualquier círculo completamente superpuesto (todos estos círculos satisfacen | P_a - P_b | <= r_a) donde P_a es el centro del círculo A, P_b es el centro del círculo B y r_a es el radio de A ) y esto mejora tanto el límite superior como el inferior. También podría obtener un límite superior mejor si usa su fórmula de pares en pares arbitrarios en lugar de solo la suma de todos los círculos. Puede haber una buena forma de elegir el "mejor"
Dado un límite superior e inferior, es posible que pueda ajustar mejor un enfoque de Montecarlo, pero no se le ocurre nada específico. Otra opción (nuevamente dependiendo de su aplicación) es rasterizar los círculos y contar píxeles. Básicamente es el enfoque de Montecarlo con una distribución fija.
fuente
Esto se puede resolver usando el teorema de Green , con una complejidad de n ^ 2log (n). Si no está familiarizado con el teorema de Green y desea saber más, aquí está el video y las notas de Khan Academy. Pero por el bien de nuestro problema, creo que mi descripción será suficiente.
Ecuación general del teorema de Green
Si pongo L y M tal que
Condición
entonces el RHS es simplemente el área de la Región R y se puede obtener resolviendo la integral cerrada o LHS y esto es exactamente lo que vamos a hacer.
Todas las uniones pueden dividirse en conjuntos de círculos tan inconexos que se cruzan
Entonces, integrar a lo largo del camino en sentido antihorario nos da el Área de la región e integrar a lo largo de las agujas del reloj nos da el negativo del Área . Entonces
AreaOfUnion = (Integración a lo largo de arcos rojos en sentido antihorario + Integración a lo largo de arcos azules en sentido horario)
Pero el truco genial es si para cada círculo, si integramos los arcos que no están dentro de ningún otro círculo, obtenemos nuestra área requerida, es decir, obtenemos la integración en sentido antihorario a lo largo de todos los arcos rojos y la integración a lo largo de todos los arcos azules en el sentido de las agujas del reloj. ¡¡¡TRABAJO HECHO!!!
Aquí está el enlace de GitHub a mi código C ++
fuente
El enfoque de pintura de píxeles (como lo sugiere @Loadmaster) es superior a la solución matemática en una variedad de formas:
La única desventaja de la pintura de píxeles es la precisión finita de la solución. Pero eso se puede ajustar simplemente renderizando a lienzos más grandes o más pequeños según lo requiera la situación. Tenga en cuenta también que el suavizado en el código de renderizado 2D (a menudo activado de forma predeterminada) producirá una precisión mejor que el nivel de píxel. Entonces, por ejemplo, renderizar una figura de 100x100 en un lienzo de las mismas dimensiones debería, creo, producir una precisión del orden de 1 / (100 x 100 x 255) = .000039% ... lo cual probablemente sea "suficientemente bueno" para todos menos los problemas más exigentes.
fuente