Este problema realmente lida com roll-overs, generalizarei a seguir como tal:
Tenho uma visualização 2D e vários retângulos em uma área da tela. Como faço para espalhar essas caixas de forma que elas não se sobreponham, mas apenas as ajuste com o mínimo de movimento?
As posições dos retângulos são dinâmicas e dependem da entrada do usuário, portanto, suas posições podem estar em qualquer lugar.
As imagens anexadas mostram o problema e a solução desejada
O problema da vida real lida com rollovers, na verdade.
Respostas às perguntas nos comentários
O tamanho dos retângulos não é fixo e depende do comprimento do texto no rollover
Sobre o tamanho da tela, agora acho melhor assumir que o tamanho da tela é suficiente para os retângulos. Se houver muitos retângulos e o algo não produzir solução, então só preciso ajustar o conteúdo.
O requisito de 'mover-se minimamente' é mais para a estética do que um requisito absoluto de engenharia. Pode-se espaçar dois retângulos adicionando uma grande distância entre eles, mas não ficará bem como parte da GUI. A ideia é obter o rollover / retângulo o mais próximo possível de sua fonte (que irei conectar à fonte com uma linha preta). Portanto, 'movendo apenas um para x' ou 'movendo ambos para meio x' está bom.
Respostas:
Eu estava trabalhando um pouco nisso, pois também precisava de algo semelhante, mas atrasei o desenvolvimento do algoritmo. Você me ajudou a obter algum impulso: D
Eu também precisava do código-fonte, então aqui está. Eu trabalhei no Mathematica, mas como não usei muito os recursos funcionais, acho que será fácil traduzir para qualquer linguagem procedural.
Uma perspectiva histórica
Primeiro decidi desenvolver o algoritmo para círculos, porque a interseção é mais fácil de calcular. Depende apenas dos centros e raios.
Consegui usar o solucionador de equações do Mathematica e ele teve um bom desempenho.
Apenas olhe:
Foi fácil. Acabei de carregar o solucionador com o seguinte problema:
Tão simples quanto isso, e o Mathematica fez todo o trabalho.
Eu disse "Ha! É fácil, agora vamos para os retângulos!". Mas eu estava errado ...
Rectangular Blues
O principal problema com os retângulos é que consultar a interseção é uma função desagradável. Algo como:
Então, quando tentei alimentar o Mathematica com várias dessas condições para a equação, ela se saiu tão mal que resolvi fazer algo processual.
Meu algoritmo acabou da seguinte maneira:
Você pode notar que a condição de "menor movimento" não é completamente satisfeita (apenas em uma direção). Mas descobri que mover os retângulos em qualquer direção para satisfazê-lo, às vezes resulta em uma mudança de mapa confusa para o usuário.
Como estou projetando uma interface de usuário, escolho mover o retângulo um pouco mais longe, mas de uma forma mais previsível. Você pode alterar o algoritmo para inspecionar todos os ângulos e raios ao redor de sua posição atual até que um lugar vazio seja encontrado, embora seja muito mais exigente.
De qualquer forma, estes são exemplos de resultados (antes / depois):
Editar> Mais exemplos aqui
Como você pode ver, o "movimento mínimo" não é satisfeito, mas os resultados são bons o suficiente.
Vou postar o código aqui porque estou tendo alguns problemas com meu repositório SVN. Vou removê-lo quando os problemas forem resolvidos.
Editar:
Você também pode usar R-Trees para encontrar interseções retangulares, mas parece um exagero lidar com um pequeno número de retângulos. E eu não tenho os algoritmos já implementados. Talvez outra pessoa possa indicar uma implementação existente na plataforma de sua escolha.
Aviso! O código é uma primeira abordagem ... não é de grande qualidade ainda e certamente tem alguns bugs.
É o Mathematica.
a Principal
HTH!
Editar: Pesquisa em vários ângulos
Implementei uma mudança no algoritmo permitindo pesquisar em todas as direções, mas dando preferência ao eixo imposto pela simetria geométrica.
À custa de mais ciclos, isso resultou em configurações finais mais compactas, como você pode ver aqui abaixo:
Mais amostras aqui .
O pseudocódigo do loop principal mudou para:
Não estou incluindo o código-fonte para abreviar, mas pergunte se você acha que pode usá-lo. Eu acho que, se você seguir este caminho, é melhor mudar para R-trees (muitos testes de intervalo necessários aqui)
fonte
Aqui está um palpite.
Encontre o centro C da caixa delimitadora de seus retângulos.
Para cada retângulo R que se sobrepõe a outro.
Isso move gradualmente os retângulos para longe uns dos outros e do centro de todos os retângulos. Isso terminará porque o componente de v da etapa 4 eventualmente os espalhará o suficiente por si só.
fonte
Acho que essa solução é bem parecida com a do cape1232, mas já está implementada, vale a pena conferir :)
Siga para esta discussão do reddit: http://www.reddit.com/r/gamedev/comments/1dlwc4/procedural_dungeon_generation_algorithm_explained/ e verifique a descrição e implementação. Não há código-fonte disponível, então aqui está minha abordagem para esse problema no AS3 (funciona exatamente da mesma forma, mas mantém os retângulos ajustados à resolução da grade):
fonte
velocity
é a soma dos vetores entre seu centro e o centro das outras salas, se todas as salas estiverem empilhadas com o mesmo centro,velocity.length == 0
para todas as salas e nada jamais se moverá. Da mesma forma, se duas ou mais salas tiverem o mesmo retângulo com o mesmo centro, elas se moverão juntas, mas permanecerão empilhadas.Eu realmente gosto da implementação do b005t3r! Funciona em meus casos de teste, no entanto, meu representante é muito baixo para deixar um comentário com as 2 correções sugeridas.
Você não deve traduzir quartos por incrementos de resolução simples, você deve traduzir pela velocidade que você calculou de forma dolorosa! Isso torna a separação mais orgânica, pois salas com interseção profunda separam mais cada iteração do que salas com interseção não tão profunda.
Você não deve assumir que velociites menores que 0,5 significa que os quartos são separados, pois você pode ficar preso em um caso em que nunca está separado. Imagine que 2 quartos se cruzam, mas são incapazes de se corrigirem porque sempre que um deles tenta corrigir a penetração, eles calculam a velocidade necessária como <0,5, de modo que iteram indefinidamente.
Aqui está uma solução Java (: Cheers!
fonte
Aqui está um algoritmo escrito em Java para lidar com um cluster de
Rectangle
s não rotacionados . Permite especificar a relação de aspecto desejada do layout e posicionar o cluster usando um parâmetro parametrizadoRectangle
como ponto de ancoragem, sobre o qual todas as traduções feitas são orientadas. Você também pode especificar uma quantidade arbitrária de preenchimento pelo qual gostaria de espalhar osRectangle
s.}
Aqui está um exemplo usando um
AspectRatio
de1.2
, umFillPercentage
de0.8
e umPadding
de10.0
.Esta é uma abordagem determinística que permite que o espaçamento ocorra ao redor da âncora, enquanto deixa a localização da própria âncora inalterada. Isso permite que o layout ocorra onde quer que esteja o Ponto de Interesse do usuário. A lógica para selecionar uma posição é muito simplista, mas acho que a arquitetura envolvente de classificar os elementos com base em sua posição inicial e, em seguida, iterá-los é uma abordagem útil para implementar uma distribuição relativamente previsível. Além disso, não estamos contando com testes de interseção iterativos ou qualquer coisa assim, apenas construindo algumas caixas delimitadoras para nos dar uma indicação ampla de onde alinhar as coisas; depois disso, a aplicação de preenchimento vem naturalmente.
fonte
Esta é uma versão que segue a resposta de cape1232 e é um exemplo executável autônomo para Java:
fonte