Divisão espacial alinhada pelo eixo: dividir o espaço em retângulos aleatórios?

11

Eu preciso de um método para dividir o espaço 3D em formas de caixas alinhadas com eixos aleatórios. Por enquanto, atualmente estou dividindo o espaço 2D para fins de teste. A abordagem mais imediata que surgiu foi definir um retângulo de tamanho (1, 1) e depois dividir recursivamente todos os retângulos existentes em dois retângulos desiguais alternando entre os eixos X e Y.

insira a descrição da imagem aqui

O problema aqui é óbvio. Essa abordagem resulta em longas linhas de alongamento (marcadas em vermelho)

insira a descrição da imagem aqui

O que eu gostaria é algo mais orgânico (incluí um exemplo)

Veja, não há longas linhas retas de cima para baixo ou da esquerda para a direita.

insira a descrição da imagem aqui

A única restrição é que talvez eu queira limitar o tamanho mínimo do retângulo sem afetar a granularidade dos tamanhos. ou seja, se o menor retângulo é de 1 centímetro quadrado do que o menor espaço de segundos não deve ter 2 unidades quadradas.

Idealmente, o algoritmo deve atender às três restrições a seguir:

  1. Retângulos não são infinitamente pequenos.
  2. Os tamanhos retos não são uma multiplicação discreta do menor tamanho ret. isto é, se o menor retângulo é de 3 unidades quadradas, as rects maiores não são restritas a 6, 9, 12 e outras unidades quadradas e, em vez disso, podem ser 3,2 ou 4,7).
  3. O algoritmo é executado em tempo polinomial (precisa calcular rapidamente).
AturSams
fonte

Respostas:

12

A abordagem que você descreve é ​​simples e útil, mas sofre com artefatos terríveis, como mostrado. Evite isso. Você precisa de um algoritmo de crescimento paralelo; para um modelo de thread único, segue uma abordagem round-robin:

  1. Coloque aleatoriamente vários pontos no seu espaço no mapa. Normalize sua distribuição (evita o agrupamento feio) usando a distribuição gaussiana ou aplicando um algoritmo de relaxamento iterativo para mover pontos aleatoriamente afastados um do outro, conforme relaxamento de Lloyd para os diagramas de Voronoi . Esses pontos representam os centróides de seus futuros quartos.
  2. (Paralelo / Repetir round-robin para todas as salas) A partir de cada ponto, aumente 4 vértices para fora (uma sala retangular), movendo-se do ponto central por iteração global (você pode aumentar as salas diferentes a taxas diferentes em cada eixo e não o mesmo para tudo e veja como isso acontece - possivelmente para um resultado mais orgânico / variado). Em algum momento, alguns dos seus retângulos começarão a pressionar um contra o outro. Nesse ponto, limite o crescimento nesse eixo, verifique se as bordas adjacentes das duas salas estão exatamente tocando e siga em frente.
  3. Repita a etapa 2, aumentando cada quarto gradualmente, até que todo o crescimento seja restringido por quartos adjacentes ou pelos limites do mapa.
  4. Isso ainda deixará alguns espaços vazios. O problema agora é o de localizar e criar salas de espaços não ocupados. De fato, se o espaço subjacente for uma grade (indexada por número inteiro) (e toda iteração de crescimento se encaixar nessa grade), será muito mais fácil lidar com isso, pois você poderá manter listas de células de grade ocupadas e desocupadas: depois de ' Se você colocou e cultivou todos os seus quartos, procure na lista desocupada espaços discretos que consistem em grupos de células adjacentes. Como muitos espaços não utilizados terão formas não retangulares, você precisará escolher uma célula aleatoriamente a partir desse espaço não retangular e aumentá-la para o tamanho máximo da mesma forma que fez com as salas na etapa 2. Repita o procedimento espaço retangular, até que esteja completamente cheio.
  5. Repita a etapa 4 até que seu mapa esteja 100% ocupado.
Engenheiro
fonte
Este é um bom conselho. A desvantagem é que ela possivelmente não faz nada para me proteger de pequenas quantidades infinitesimalmente pequenas. Eu preciso de alguma maneira de limitar o quão pequeno e quão grande é o tamanho dos rects. Atualmente, estou no processo de trabalhar em outro método. Vou comparar os resultados e atualizar.
AturSams
@ArthurWulfWhite Então sua pergunta estava subespecificada e deve ser atualizada. Seu tamanho mínimo de sala é determinado pela resolução da célula do mapa; portanto, se você fizer essa granulação grossa o suficiente para acomodar o tamanho mínimo da sala, poderá ajustar os eixos posteriormente com base em ponto flutuante, retornando uma aparência mais orgânica.
Engenheiro de
Você está certo! Eu pensei que escrevi essa parte. Mas eu não tenho. Peço desculpas por este erro. Sim, eu estou ciente do tamanho da grade. Uma sala pode ser tão pequena quanto a grade permitir.
AturSams
OK - espero que você encontre uma solução adequada. Aliás, eu quis dizer "ajustar linhas de grade", não "ajustar eixos".
Engenheiro de
1
Na verdade, estou fazendo algo exatamente assim com base nos conceitos que você me pensou. Vou postar os resultados aqui também.
AturSams
2

Como você pode ver, consegui livrar o mundo desses artefatos. A ideia é muito parecida.

  1. Divida o 2º espaço em uma grade não uniforme. Se duas linhas estiverem muito próximas, remova uma.
  2. Escolha um retângulo aleatoriamente, verifique se ele foi modificado no eixo y (em altura) e se o vizinho direto foi modificado no eixo y. Ambos não foram modificados, eles renegociaram o segmento entre eles (um doará espaço para o outro).
  3. Faça o mesmo que na etapa 2 somente desta vez no outro eixo.
  4. Repita o processo até você modificar o maior número possível.

Grade não uniforme (1):

insira a descrição da imagem aqui

Negociação no eixo x (2):

insira a descrição da imagem aqui

Negociação no eixo y (3):

insira a descrição da imagem aqui

Resultado (4):

insira a descrição da imagem aqui

insira a descrição da imagem aqui

AturSams
fonte
Este foi vagamente inspirado na visão de @ Nick Wiggill
AturSams
2
Poder-se-ia melhorar ainda mais, primeiro fundindo aleatoriamente grupos de n * m células adjacentes em um único retângulo. Isso mascara a grade subjacente ainda visível na saída acima. A negociação com esses retângulos maiores agora precisa funcionar em todas as células ao longo de uma de suas bordas.
DMGregory
ESTÁ BEM. Ainda existem muitos limites colineares, eu trabalharia mais nisso, mas é bom que você tenha encontrado sua solução! Fico feliz em ajudar.
Engenheiro
@DMGregory Eu considerei isso, mas queria que a relação entre as pequenas rects e as rects grandes fosse um pouco consistente. Se isso fosse uma textura ou um nível, eu definitivamente o faria (na verdade, tenho um exemplo anterior que faz isso).
AturSams
@NickWiggill Posso eliminar completamente as linhas colineares. É apenas uma questão de ajustar o algoritmo. Deve haver uma maneira de melhorá-lo ainda mais (atualização com variação mais recente)
AturSams