Este problema en realidad trata con roll-overs, solo generalizaré a continuación como tal:
Tengo una vista 2D y tengo varios rectángulos dentro de un área en la pantalla. ¿Cómo extiendo esos cuadros de modo que no se superpongan entre sí, sino que solo los ajusto con un movimiento mínimo?
Las posiciones de los rectángulos son dinámicas y dependen de la entrada del usuario, por lo que sus posiciones podrían estar en cualquier lugar.
Las imágenes adjuntas muestran el problema y la solución deseada
El problema de la vida real tiene que ver con las volcaduras.
Respuestas a las preguntas en los comentarios.
El tamaño de los rectángulos no es fijo y depende de la longitud del texto en la imagen cambiante.
Sobre el tamaño de la pantalla, en este momento creo que es mejor asumir que el tamaño de la pantalla es suficiente para los rectángulos. Si hay demasiados rectángulos y el algoritmo no produce una solución, solo tengo que modificar el contenido.
El requisito de "moverse mínimamente" es más por una estética que un requisito absoluto de ingeniería. Uno podría espaciar dos rectángulos agregando una gran distancia entre ellos, pero no se verá bien como parte de la GUI. La idea es acercar el rollover / rectángulo a su fuente (que luego conectaré a la fuente con una línea negra). Entonces, 'mover solo uno para x' o 'mover ambos para la mitad de x' está bien.
Respuestas:
Estaba trabajando un poco en esto, ya que también necesitaba algo similar, pero había retrasado el desarrollo del algoritmo. Me ayudaste a tener un poco de impulso: D
También necesitaba el código fuente, así que aquí está. Lo resolví en Mathematica, pero como no he usado mucho las características funcionales, supongo que será fácil de traducir a cualquier lenguaje de procedimiento.
Una perspectiva histórica
Primero decidí desarrollar el algoritmo para círculos, porque la intersección es más fácil de calcular. Solo depende de los centros y radios.
Pude usar el solucionador de ecuaciones de Mathematica y funcionó muy bien.
Solo mira:
Fue fácil. Acabo de cargar el solucionador con el siguiente problema:
Tan sencillo como eso, y Mathematica hizo todo el trabajo.
Dije "¡Ja! Es fácil, ¡ahora vayamos por los rectángulos!". Pero estaba equivocado ...
Azules rectangulares
El principal problema con los rectángulos es que consultar la intersección es una función desagradable. Algo como:
Entonces, cuando traté de alimentar Mathematica con muchas de estas condiciones para la ecuación, funcionó tan mal que decidí hacer algo de procedimiento.
Mi algoritmo terminó de la siguiente manera:
Puede notar que la condición de "movimiento más pequeño" no se satisface completamente (solo en una dirección). Pero descubrí que mover los rectángulos en cualquier dirección para satisfacerlo, a veces termina con un cambio de mapa confuso para el usuario.
Mientras estoy diseñando una interfaz de usuario, elijo mover el rectángulo un poco más, pero de una manera más predecible. Puede cambiar el algoritmo para inspeccionar todos los ángulos y todos los radios que rodean su posición actual hasta que se encuentre un lugar vacío, aunque será mucho más exigente.
De todos modos, estos son ejemplos de los resultados (antes / después):
Editar> Más ejemplos aquí
Como puede ver, el "movimiento mínimo" no se satisface, pero los resultados son lo suficientemente buenos.
Publicaré el código aquí porque tengo algunos problemas con mi repositorio SVN. Lo eliminaré cuando se resuelvan los problemas.
Editar:
También puede usar R-Trees para encontrar intersecciones de rectángulos, pero parece una exageración para tratar con una pequeña cantidad de rectángulos. Y aún no he implementado los algoritmos. Quizás alguien más pueda indicarle una implementación existente en la plataforma que elija.
¡Advertencia! El código es un primer enfoque ... no es de gran calidad todavía, y seguramente tiene algunos errores.
Es Mathematica.
Principal
HTH!
Editar: búsqueda de múltiples ángulos
Implementé un cambio en el algoritmo permitiendo buscar en todas las direcciones, pero dando preferencia al eje impuesto por la simetría geométrica.
A expensas de más ciclos, esto resultó en configuraciones finales más compactas, como puede ver a continuación:
Más muestras aquí .
El pseudocódigo del bucle principal cambió a:
No incluyo el código fuente por brevedad, pero pídalo si cree que puede usarlo. Creo que, si va por este camino, es mejor cambiar a árboles R (aquí se necesitan muchas pruebas de intervalo)
fuente
He aquí una suposición.
Encuentra el centro C del cuadro delimitador de tus rectángulos.
Por cada rectángulo R que se superpone a otro.
Esto aleja gradualmente los rectángulos entre sí y el centro de todos los rectángulos. Esto terminará porque el componente de v del paso 4 eventualmente los extenderá lo suficiente por sí mismo.
fuente
Creo que esta solución es bastante similar a la dada por cape1232, pero ya está implementada, así que vale la pena echarle un vistazo :)
Siga esta discusión de reddit: http://www.reddit.com/r/gamedev/comments/1dlwc4/procedural_dungeon_generation_algorithm_explained/ y consulte la descripción y la implementación. No hay código fuente disponible, así que aquí está mi enfoque para este problema en AS3 (funciona exactamente igual, pero mantiene los rectángulos ajustados a la resolución de la cuadrícula):
fuente
velocity
es la suma de los vectores entre su centro y el centro de las otras habitaciones, si todas las habitaciones están apiladas con el mismo centro,velocity.length == 0
para todas las habitaciones y nada se moverá nunca. De la misma forma, si dos o más habitaciones tienen el mismo rectángulo con el mismo centro, se moverán juntas pero permanecerán apiladas.¡Realmente me gusta la implementación de b005t3r! Funciona en mis casos de prueba, sin embargo, mi reputación es demasiado baja para dejar un comentario con las 2 correcciones sugeridas.
No debe traducir habitaciones en incrementos de resolución únicos, debe traducir por la velocidad que acaba de calcular. Esto hace que la separación sea más orgánica, ya que las habitaciones profundamente intersectadas separan más en cada iteración que las habitaciones que no se cruzan tan profundamente.
No debe asumir que velocidades inferiores a 0,5 significa que las habitaciones están separadas, ya que puede quedarse atascado en un caso en el que nunca se separan. Imagine que 2 habitaciones se cruzan, pero no pueden corregirse por sí mismas porque cada vez que una de ellas intenta corregir la penetración, calculan la velocidad requerida como <0,5, por lo que iteran sin cesar.
Aquí hay una solución de Java (: Cheers!
fuente
Aquí hay un algoritmo escrito con Java para manejar un grupo de correos electrónicos no rotados
Rectangle
. Le permite especificar la relación de aspecto deseada del diseño y posiciona el clúster utilizando un parametrizadoRectangle
como punto de anclaje, sobre el que se orientan todas las traducciones realizadas. También puede especificar una cantidad arbitraria de relleno por la que le gustaría distribuir losRectangle
s.}
A continuación, se muestra un ejemplo con una
AspectRatio
de1.2
, unaFillPercentage
de0.8
y unaPadding
de10.0
.Se trata de un enfoque determinista que permite que se produzca un espaciado alrededor del ancla sin modificar la ubicación del ancla. Esto permite que el diseño se produzca alrededor del lugar donde se encuentre el punto de interés del usuario. La lógica para seleccionar una posición es bastante simplista, pero creo que la arquitectura circundante de ordenar los elementos en función de su posición inicial y luego iterarlos es un enfoque útil para implementar una distribución relativamente predecible. Además, no confiamos en pruebas de intersección iterativas ni nada por el estilo, simplemente construimos algunos cuadros delimitadores para darnos una indicación amplia de dónde alinear las cosas; después de esto, la aplicación de relleno es algo natural.
fuente
Aquí hay una versión que toma la respuesta de cape1232 y es un ejemplo ejecutable independiente para Java:
fuente