Просторовий поділ по осі: розподілити простір на випадкові прямокутники?


11

Мені потрібен метод розділити 3d-простір на фігури коробки, вирівняні по випадковій осі. На даний момент я ділю 2d простір для цілей тестування. Найбільш безпосереднім підходом я був визначити прямокутник розміром (1, 1), а потім рекурсивно розділити всі існуючі прямокутники на два нерівні прямокутники, що чергуються між віссю X та Y.

введіть тут опис зображення

Проблема тут очевидна. Такий підхід призводить до довгих розтягуючих ліній (позначених червоним кольором)

введіть тут опис зображення

Мені б хотілося щось більш органічно виглядати (я включив приклад)

Дивіться, немає довгих прямих ліній зверху вниз або зліва направо.

введіть тут опис зображення

Єдине обмеження полягає в тому, що я, можливо, бажаю обмежити мінімальний розмір прямокутника, не впливаючи на деталізацію розмірів. наприклад, якщо найменша пряма частина - 1 квадратний сантиметр, ніж секунда найменша кімната не повинна бути 2 квадратних одиниць.

Тому в ідеалі алгоритм повинен відповідати всім трьом наступним обмеженням:

  1. Прямокутники нескінченно мало.
  2. Прямі розміри не є дискретним множенням найменшого розміру прямої кишки. наприклад, якщо найменша пряма частина - 3 квадратні одиниці, то більші прямої прямоти не обмежуватимуться 6, 9, 12 і т. п. квадратних одиниць, а натомість для цього може бути 3,2 або 4,7).
  3. Алгоритм працює в поліноміальний час (потрібно швидко обчислити).

Відповіді:


12

Підхід, який ви окреслили, простий і корисний, але страждає від жахливих артефактів, як показано. Уникайте цього. Вам потрібен алгоритм паралельного росту; для однопотокової моделі застосовується підхід із круглою стрічкою:

  1. Випадково розміщуйте різні точки в просторі карти. Нормалізуйте їх розподіл (уникає потворних кластеризацій) за допомогою Гауссового розподілу або застосувавши ітеративний алгоритм релаксації для переміщення випадкових розміщених точок одна від одної, відповідно до релаксації Ллойда для діаграм Вороного . Ці точки являють собою центроїди вашої кімнати, що буде бути.
  2. (Паралельний / повторний кругообіг для всіх кімнат) З кожної точки виростіть 4 вершини назовні (прямокутна кімната), рухаючись від центральної точки за глобальною ітерацією (ви можете вирощувати різні кімнати з різною швидкістю в кожній осі, а не однакові для все, і подивіться, як це виходить - можливо, для більш органічного / різноманітного результату). В якийсь момент деякі ваші прямокутники почнуть тиснути один на одного. У цей момент обмежте зростання цієї осі, переконайтесь, що сусідні краї двох кімнат точно торкаються, і рухайтеся далі.
  3. Повторіть крок 2, збільшуючи кожну кімнату поступово, поки все зростання не буде обмежене суміжними кімнатами або межами карти.
  4. Це все одно залишить порожні місця. Зараз проблема стає проблемою пошуку та розміщення кімнат із незайнятих приміщень. Насправді, якщо ваш базовий простір є сіткою (індексованою цілими числами) (і кожна ітерація росту приєднується до цієї сітки), то з цим набагато простіше впоратися, оскільки ви можете підтримувати списки зайнятих і незайнятих комірок сітки: Після того, як ви ' Ви розмістили та виростили всі ваші кімнати, пошукайте в незайнятому списку дискретні простори, що складаються з груп сусідніх комірок. Оскільки багато невикористаних просторів матимуть не прямокутні форми, вам потрібно буде вибрати клітинку навмання з цього не прямокутного простору та збільшити її до максимального розміру так само, як ви це робили із приміщеннями на кроці 2. Повторіть всередині зазначеного не -прямокутний простір, до повного заповнення.
  5. Повторіть крок 4, поки ваша карта не зайнята на 100%.

Це хороша порада. Недоліком є ​​те, що він, можливо, не робить нічого, щоб захистити мене від нескінченно малих прямих. Мені потрібна певна манера, щоб обмежити, наскільки малі та великі ректи. В даний час я працюю над іншим методом. Я порівняю результати та оновлю.
AturSams

@ArthurWulfWhite Тоді ваше запитання було недостатньо вказане і його слід оновити. Ваш мінімальний розмір кімнати визначається роздільною здатністю комірки; тож якщо ви зробите цей крупнозернистий розмір, щоб розмістити мінімальний розмір кімнати, ви можете потім регулювати осі на основі плаваючої точки, повертаючи більш органічний вигляд.
Інженер

Ви праві! Я думав, що написав цю частину. Але я цього не зробив. Прошу вибачення за цю помилку. Так, я знаю розмір сітки. Кімната може бути лише такою маленькою, скільки дозволяє сітка.
AturSams

Гаразд - сподіваюся, ви знайдете підходяще рішення. До речі, я мав на увазі "коригування ліній сітки", а не "регулювання осей".
Інженер

1
Насправді я роблю щось точно подібне вільно, грунтуючись на концепціях, які ви думали про мене. Результати я також опублікую тут.
AturSams

2

Як бачите, мені вдалося позбутися світу цих артефактів. Ідея дуже схожа.

  1. Розділіть 2d простір на неоднакову сітку. Якщо два рядки занадто близько, видаліть один.
  2. Виберіть прямокутник випадковим чином, перевірте, чи він був змінений по осі-у (по висоті), і чи був прямий сусід змінений по осі-у. Я обоє не був модифікований, попросив їх повторно обговорити відрізок між ними (один подарує трохи місця іншому).
  3. Зробіть те саме, що на кроці 2, лише цього разу на іншій осі.
  4. Повторіть процес, поки ви не змінили якомога більше.

Неоднакова сітка (1):

введіть тут опис зображення

Переговори по осі х (2):

введіть тут опис зображення

Переговори по осі y (3):

введіть тут опис зображення

Результат (4):

введіть тут опис зображення

введіть тут опис зображення


Це було натхненно розумінням від @Nick Wiggill
AturSams

2
Можна додатково покращити це, спочатку випадковим чином об'єднавши групи n * m сусідніх комірок в єдиний прямокутник. Це маскує нижню сітку, яка все ще видно у висновку вище. Переговори з цими більшими прямокутниками тепер мають працювати над усіма клітинками по одному з її країв.
DMGregory

ГАРАЗД. Ще велика кількість колінних меж, я б працював над цими подальшими, але добре, що ви знайшли своє рішення! Радий допомогти.
Інженер

@DMGregory Я вважав це, але хотів, щоб співвідношення між малими прямої і великими прямокутниками було певним чином узгоджене. Якби це текстура чи рівень, я б точно це зробив (насправді є попередній приклад, який це робить).
AturSams

@NickWiggill Я можу повністю усунути колінарні лінії. Це лише питання налаштування алгоритму. Повинен бути спосіб її вдосконалити (оновити найсвіжішу варіацію)
AturSams
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.