Divisione spaziale allineata asse: dividere lo spazio in rettangoli casuali?


11

Ho bisogno di un metodo per dividere lo spazio 3d in forme casuali allineate ad asse. Per ora sto attualmente dividendo lo spazio 2d a scopo di test. L'approccio più immediato che mi è venuto in mente è stato quello di definire un rettangolo di dimensioni (1, 1) e quindi dividere in modo ricorsivo tutti i rettangoli esistenti in due rettangoli irregolari alternati tra l'asse X e Y.

inserisci qui la descrizione dell'immagine

Il problema qui è ovvio. Questo approccio si traduce in lunghe linee di allungamento (contrassegnate in rosso)

inserisci qui la descrizione dell'immagine

Quello che vorrei è qualcosa di più organico (ho incluso un esempio)

Vedi, nessuna lunga linea retta dall'alto verso il basso o da sinistra a destra.

inserisci qui la descrizione dell'immagine

L'unico vincolo è che potrei voler limitare la dimensione minima del rettangolo senza influire sulla granularità delle dimensioni. cioè se il rettangolo più piccolo è di 1 centimetro quadrato rispetto al secondo spazio più piccolo non dovrebbe essere di 2 unità quadrate.

Quindi idealmente l'algoritmo dovrebbe soddisfare tutti e tre i seguenti vincoli:

  1. I rettangoli non sono infinitamente piccoli.
  2. Le dimensioni rettali non sono una moltiplicazione discreta della dimensione rettale più piccola. vale a dire se il retto più piccolo è di 3 unità quadrate rispetto ai rect più grandi non sono vincolati a essere 6, 9, 12 e così via unità quadrate e invece potrebbero essere 3.2 o 4.7 per quella materia).
  3. L'algoritmo viene eseguito in un tempo polinomiale (deve essere calcolato rapidamente).

Risposte:


12

L'approccio che descrivi è semplice e utile, ma soffre di terribili artefatti come mostrato. Evitalo È necessario un algoritmo di crescita parallelo; per un modello a thread singolo, segue un approccio round robin:

  1. Posiziona casualmente vari punti nello spazio della mappa. Normalizza la loro distribuzione (evita il brutto raggruppamento) usando la distribuzione gaussiana o applicando un algoritmo di rilassamento iterativo per spostare i punti posizionati casualmente l'uno dall'altro, come per il rilassamento di Lloyd per i diagrammi di Voronoi . Questi punti rappresentano i centroidi delle future stanze.
  2. (Parallelo / Ripeti round-robin per tutte le stanze) Da ogni punto, fai crescere 4 vertici verso l'esterno (una stanza rettangolare), spostandoti dal punto centrale per iterazione globale (puoi far crescere stanze diverse a velocità diverse in ciascun asse anziché lo stesso per tutto e vedere come va a finire, forse per un risultato più organico / vario). Ad un certo punto, alcuni dei tuoi rettangoli inizieranno a premere l'uno contro l'altro. A quel punto, limitare la crescita su quell'asse, assicurarsi che i bordi adiacenti delle due stanze si tocchino esattamente e andare avanti.
  3. Ripeti il ​​passaggio 2, aumentando ogni stanza in modo incrementale, fino a quando tutta la crescita è limitata dalle stanze adiacenti o dai limiti della mappa.
  4. Questo lascerà comunque degli spazi vuoti. Il problema ora diventa quello di localizzare e creare stanze da spazi non occupati. In effetti, se il tuo spazio sottostante è una griglia (indicizzata per intero) (e ogni iterazione di crescita si aggancia a quella griglia), allora questo è molto più facile da gestire, poiché puoi mantenere elenchi di celle della griglia occupate e non occupate: hai posizionato e cresciuto tutte le tue stanze, cerca nella lista non occupata gli spazi discreti costituiti da gruppi di celle adiacenti. Poiché molti spazi inutilizzati avranno forme non rettangolari, dovrai scegliere una cella a caso all'interno di quello spazio non rettangolare e farla crescere alla sua dimensione massima proprio come hai fatto con le stanze nel passaggio 2. Ripeti all'interno di detto non - spazio rettangolare, fino a quando non è completamente riempito.
  5. Ripeti il ​​passaggio 4 finché la mappa non è occupata al 100%.

Questo è un buon consiglio Lo svantaggio è che forse non fa nulla per proteggermi da rects infinitamente piccoli. Ho bisogno di un modo per limitare quanto sono piccole e grandi le rect. Attualmente sto lavorando a un altro metodo. Confronterò i risultati e aggiornerò.
AturSams,

@ArthurWulfWhite Quindi la tua domanda è stata sotto-specificata e dovrebbe essere aggiornata. Le dimensioni minime della stanza sono determinate dalla risoluzione della cella della mappa; quindi, se lo rendi abbastanza grossolano per adattarsi alle dimensioni minime della stanza, puoi successivamente regolare gli assi in virgola mobile, restituendo un aspetto più organico.
Ingegnere,

Hai ragione! Pensavo di aver scritto quella parte. Ma non l'ho fatto. Mi scuso per questo errore. Sì, sono a conoscenza delle dimensioni della griglia. Una stanza può essere piccola solo quanto la griglia consente.
AturSams,

OK - spero di trovare una soluzione adatta. A proposito, intendevo "regolare le linee della griglia", non "regolare gli assi".
Ingegnere,

1
In realtà sto facendo qualcosa di esattamente simile vagamente basato sui concetti che mi hai pensato. Pubblicherò i risultati anche qui.
AturSams,

2

Come puoi vedere, sono riuscito a liberare il mondo da questi artefatti. L'idea è molto simile.

  1. Dividi lo spazio 2d in una griglia non uniforme. Se due linee sono troppo vicine, rimuoverne una.
  2. Scegli un rettangolo in ordine casuale, controlla se è stato modificato sull'asse-y (in altezza) e se il suo diretto vicino è stato modificato sull'asse-y. Entrambi non sono stato modificato, li hanno rinegoziare il segmento tra loro (uno donerà un po 'di spazio all'altro).
  3. Fare lo stesso del passaggio 2 solo questa volta sull'altro asse.
  4. Ripeti il ​​processo finché non ne hai modificato il maggior numero possibile.

Griglia non uniforme (1):

inserisci qui la descrizione dell'immagine

Negoziando sull'asse x (2):

inserisci qui la descrizione dell'immagine

Negoziando sull'asse y (3):

inserisci qui la descrizione dell'immagine

Risultato (4):

inserisci qui la descrizione dell'immagine

inserisci qui la descrizione dell'immagine


Questo è stato liberamente ispirato dall'intuizione di @Nick Wiggill
AturSams,

2
Si potrebbe migliorare ulteriormente su questo unendo prima casualmente gruppi di n * m celle adiacenti in un singolo rettangolo. Questo maschera la griglia sottostante ancora visibile nell'output sopra. La negoziazione con questi rettangoli più grandi ora deve funzionare su tutte le celle lungo uno dei suoi bordi.
DMGregory

OK. Ancora molti confini colinear, lavorerei su quelli oltre, ma bene che hai trovato la tua soluzione! Sono contento di aiutare.
Ingegnere,

@DMGregory Ho considerato questo, ma volevo che il rapporto tra i rects piccoli e quelli grandi fosse in qualche modo coerente. Se questa fosse una trama o un livello, lo farei sicuramente (in realtà ho un esempio precedente che lo fa).
AturSams,

@NickWiggill Posso eliminare completamente le linee colorate. Si tratta solo di modificare l'algoritmo. Deve esserci un modo per migliorarlo ulteriormente (aggiornamento con la variante più recente)
AturSams,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.