Стаття · · 6 хв читання

Від OpenStreetMap до 3D-друку: де ламається геометрія

П'ять класів дефектів, які я перевіряю на кожному експорті свого генератора мап — від масок доріг з дірками до фрагментів, тонших за сопло, — і правила, що тримають модель міста придатною до друку.

monadruk.com продає 3D-моделі реальних місць для друку. Клієнт обирає ділянку на мапі, а генератор перетворює дані OpenStreetMap і рельєфу на файл, який приймає 3D-принтер. Отримати дані легко. Отримати геометрію, яка переживе слайсер, — ось на що йде майже вся робота.

Конвеєр в одному абзаці

Будинки, дороги, вода й парки приходять з OpenStreetMap як 2D-форми й чистяться бібліотекою shapely. Плитки висот стають ґрунтом. Контури будинків видавлюються на свою висоту й зливаються з рельєфом в одну сітку; район на моєму сайті — квадрат 80 × 80 мм з 800 438 трикутниками, надрукований у 74 шари по 0,2 мм. Далі кожен експорт проходить набір перевірок.

П'ять речей, що ламаються

  • Топологія маски доріг. Дороги — це лінії з буфером, і їх об'єднання повне дрібних внутрішніх дірок. Порожнина всередині дорожньої мережі, під якою немає будинку, — дефект, і її треба закрити.
  • Посадка доріг, парків і води. Кожен шар вирізається з інших, і якщо зазори не задані явно, виходять перекриття або щілини, які принтер показує одразу.
  • Будинки, що не сидять на основі. На схилі контур на одній висоті з одного боку висить над землею, а з іншого — тоне в ній.
  • Нестабільні булеві операції. Булеві операції з великими мультиполігонами повільні й падають на майже вироджених даних; обрізання масок по межах фігури перед вирізанням виправляє більшість випадків.
  • Тонкі фрагменти, які не надрукувати. Залишки між об'єктами тонші, ніж може покласти сопло, і їх треба видалити до експорту.

Правила, що зупинили регресії

Найкорисніші правила стосувалися дисципліни, а не алгоритмів. Міняти один шар геометрії за раз і перевіряти контрольним рендером. Не застосовувати широке згладжування, фаски чи буфери до доріг, парків і пазів одним кроком. Тримати правила посадки явними для кожної сторони й в одному місці, а не розкидати їх по процесорах.

# спрощено: вирізати дороги з парку, потім прибрати те, що сопло не надрукує
park = park.difference(road_mask.intersection(park.envelope.buffer(5)))
parts = [p for p in explode(park) if min_width(p) >= nozzle_width]
park = unary_union(parts)

Чому чек-лист кращий за виправлення

Кожне нове місто приносить нові крайні випадки в даних OSM. Замість виправляти їх по одному, я перевіряю п'ять класів дефектів вище як чек-лист на кожному експорті. Нове місто або проходить усі п'ять, або точно каже, на який шар дивитися.

Проєкт, з якого ця стаття: monadruk →

Схожа задача?

Напишіть, що ви будуєте і які дані маєте. Я відповім, як би це вирішував.

Обговорити проєкт →