Разбор архитектурных чертежей и планов БТИ по картинке — вытащить из скана размеры, координаты стен, состав помещений и построить по ним геометрию в движке. Используй, когда нужно воспроизвести реальную планировку (типовая серия, план этажа, поэтажный план БТИ) в игре или в 3D, когда есть только изображение чертежа, или когда построенное «по мотивам» расходится с оригиналом.
Resources
2Install
npx skillscat add sashkosoft/godot-skilled/blueprint-reading Install via the SkillsCat registry.
Разбор чертежа по картинке
Скил собран на реальной задаче: воспроизвести типовой этаж советской башни
(серия II-67) в Godot по скану поэтажного плана БТИ.
Главное правило
Чертёж читается цифрами, а не глазами. На скане в исходном размере не видно
почти ничего: подписи 5–7 пикселей высотой сливаются. Пока не увеличил и не
выписал размеры в таблицу — ты не читаешь чертёж, ты его угадываешь.
Признак того, что угадываешь: в коде появляются числа вроде -6.3 и 2.4,
взятые «на глаз, чтобы влезло». По ним потом невозможно понять, откуда они.
Главное: мыслить помещениями, а не линиями
Этаж — это список блоков-помещений; стена есть зазор между блоками, проём
принадлежит паре блоков. Попиксельный разбор годится только как источник
замеров. Почему так и что даёт — references/block-model.md, рабочая
модель — tools/plan_blocks.py.
Условные обозначения
Как на плане БТИ нарисованы стены, двери, створы проёмов, окна, дверцы шкафов
и пиктограммы сантехники — и как всё это снять машинно, с порогами и
проверками: references/plan-notation.md. Рабочий разбор —scripts/read_plan.py.
Порядок работы
1. Найти и скачать скан
Ищи поэтажные планы, а не планировки квартир — это разные вещи, и вторых в сети
на порядок больше. Полезные запросы: «поэтажный план БТИ серия N», «план типового
этажа», «планировка этажа с размерами». Планы БТИ часто лежат картинками на сайтах
согласования перепланировок.
curl -s -A "Mozilla/5.0" -o plan.jpg "https://.../plan.jpg"2. Нарезать и увеличить
Это ключевой шаг, без него дальше идти бессмысленно.
magick identify plan.jpg # узнать размер
magick plan.jpg -crop 500x260+150+380 -resize 300% -sharpen 0x1 q1.pngРежь по четвертям с перехлёстом 10–15 %, увеличивай в 3 раза, добавляй -sharpen.
Читай каждый фрагмент отдельно. На увеличении становятся видны: площади в кружках,
размеры пролётов, значки сантехники, номера квартир, штриховка ступеней, стрелки
направления подъёма.
3. Выписать размеры в таблицу
Для каждой квартиры: номер, состав, площади комнат, габариты каждой комнаты.
Отдельно — размеры пролётов по фасадам.
Пример того, что получается:
| Квартира | Комнаты | Габариты |
|---|---|---|
| 44 (3К) | 20,7 / 12,2 / 15,1 | 3,37×6,10 / 2,57×4,71 / 3,24×4,72 |
| 46 (1К) | 19,1 | 3,37×6,16 |
4. Проверить суммы — это главная проверка
Ширины квартир по фасаду обязаны сложиться в габарит корпуса.
6,22 + 9,18 + 3,37 + 6,06 = 24,83 → дом 25 м.
Если не сходится — ты неверно прочитал какой-то размер или спутал горизонтальный
с вертикальным. Не строй, пока не сойдётся: ошибка в 2 метра развалит всю
планировку, и обнаружится это через день отладки проходимости.
Так же проверяй глубину: комната + коридор + санузел ≈ глубина половины корпуса.
5. Понять структуру, а не только размеры
Что нужно вытащить помимо цифр:
- где ядро и что в нём (лестница, лифты — сколько, мусоропровод, щитовая);
- форма коридора: линейный, кольцевой, Г-образный. Это определяет всё
остальное, и ошибиться здесь дороже всего; - куда выходят двери каждой квартиры — в коридор, в холл, на площадку;
- где окна и лоджии (лоджии на плане подписаны как 1а, 1б, 2б, 3а
и привязаны к комнатам); - симметрия: обычно план симметричен относительно оси, иногда с поворотом
на 180°. Симметрия вдвое сокращает работу и вдвое уменьшает число ошибок.
6. Строить от данных, а не от кода
Сначала таблица координат, потом генератор, который её читает.
Подробнее — references/from-drawing-to-geometry.md.
Чего не делать
- Не подгонять чертёж под существующую геометрию. Если построенное «по мотивам»
расходится с оригиналом, дешевле перестроить с нуля, чем двигать стены по одной:
каждая правка тянет за собой предыдущие компромиссы, и через десять итераций
получается третий вариант, не похожий ни на что. - Не копировать сам чертёж в игру. Скан — чужой файл с водяными знаками.
Размеры и планировочные решения не охраняются, изображение — охраняется. - Не верить описаниям вместо чертежа. Текст на сайте серии скажет «два лифта
и мусоропровод», но не скажет, что лестница стоит между лифтами, — а это
меняет всё ядро.
Обмер вручную кончается на трёх квартирах
Восемь квартир на этаж — это ~60 помещений и ~140 координат. Руками их снять
можно, но точность выходит ±15 см, и этого хватает, чтобы стены разъехались.
Дальше работают три скрипта, каждый со своим входом и выходом:
| Скрипт | Что делает |
|---|---|
snap_rooms.py |
двигает координаты таблицы на оси стен, найденные на скане |
build_plan.py |
режет стены на общие участки и читает на них двери и окна |
annotate_plan.py |
подписывает отрендеренный план и рисует легенду |
Исходная таблица, снятая руками, лежит отдельным файлом и никогда не
перезаписывается: скрипты читают её и пишут результат в генератор. Иначе
после третьего прогона неоткуда узнать, что ты снимал с чертежа, а что
дорисовал автомат.
Масштаб
Не по габариту дома (его границу видно плохо), а по комнате с подписанными
размерами: 18,5 = 3,42 × 5,54. Находишь её стены в пикселях, делишь —
получаешь px/м. Проверяешь на второй комнате: расхождение больше 2 % значит,
что ты меряешь не то.
Подгонка координат к линиям
Для каждой координаты (не для каждого ребра!) перебираешь смещение ±0,4 м и
берёшь то, на котором суммарная длина попадания на тёмную линию максимальна.
Именно для координаты: иначе общая стена двух комнат уедет в разные стороны и
между ними появится щель.
Два обязательных ограничения:
- запрет на перекрытия — после сдвига ни одна пара помещений не должна
налезть друг на друга. Стена, оказавшаяся внутри комнаты, режет её пополам,
и это ловится только проверкой проходимости, через час; - сварка щелей — зазоры до ~0,35 м между прямоугольниками это не стены,
а огрехи ручного обмера. Их надо свести в одну координату, иначе получается
две параллельные стены с пустотой, и дверь в одной упирается в другую.
Сварка сводит группу не к середине, а к той координате, под которой на
скане больше всего линии. К середине — стены уезжают с чертежа, и площади
комнат плывут на 1–2 м².
Двери и окна читаются числом полос
На плане БТИ стена нарисована двумя линиями, окно — тремя-четырьмя (остекление),
дверной проём — разрывом. Значит, вдоль найденной оси в каждой точке считаем,
сколько тёмных полос пересекает поперечный срез:
- 0 полос — дверной проём;
- 1–2 — глухая стена;
- 3 и больше — окно.
Ширина проёма на скане занижена: косяки съедают края. Дверь уже 0,7 м —
почти наверняка ошибка чтения, а не чертёж.
Проверка наложением
Единственная честная проверка результата: отрендерить построенный этаж сверху,
отмасштабировать скан по габариту корпуса и положить поверх красным.
mask = numpy.array(drawing) < 135 # линии чертежа, без водяного знака
overlay[..., :3] = (220, 25, 35)
overlay[..., 3] = numpy.where(mask, 230, 0)
base.alpha_composite(Image.fromarray(overlay), (left, top))Совпадение видно сразу, и так же сразу видно, что именно не совпало.
Ловушка: комнаты Г-образные
Площадь в подписи — настоящая, площадь твоего прямоугольника — нет.
Если построенная комната на 1,5–2 м² больше подписанной, она почти наверняка
Г-образная: угол занят прихожей или санузлом соседней. Проверяется в лоб —ширина × глубина из подписи против площади из подписи:
3,34 × 6,08 = 20,3, а подписано 18,5 → разница 1,8 м² и есть срезанный угол.
Такую комнату надо задавать двумя прямоугольниками, а не одним.
Ловушка: номера комнат ничего не значат
1 — не всегда жилая, 2 — не всегда кухня. Нумерация сквозная внутри
квартиры. Назначение определяется значками: мойка и плита — кухня, ванна и
унитаз — санузел. В однокомнатной квартире кухня может быть комнатой 2,
а в соседней двухкомнатной — комнатой 3.
Дверь ищется по полотну, а не по разрыву
Разрыв в стене — слабый признак: линии на скане слипаются, JPEG их рвёт,
косяки съедают края. Надёжный признак — само полотно двери: короткий
отрезок ПОПЕРЁК стены, которым на плане БТИ дверь и обозначают.
Детектор: вдоль оси стены в каждой точке смотрим перпендикулярный луч в обе
стороны и ищем сплошной тёмный отрезок длиной 0,55–1,15 м, начинающийся в
10 см от оси. Нашли — это полотно, его длина и есть ширина проёма.
Но одного полотна мало: на чертеже полно похожих штрихов — выносные линии
размеров, мебель, сантехника. Поэтому требуем оба признака сразу: под
полотном стена должна быть пустой. Без этой проверки детектор нашёл 232
«двери» вместо 60.
И ещё: на фасадных стенах полотен не бывает — там окна, чьи створки
детектор принимает за двери. Фасад исключаем заранее.
Итог на одном этаже: дверей, снятых с чертежа, стало 91 против 30, когда
искали только разрывы.
Несколько чертежей как источники
Планы отдельных квартир бывают втрое крупнее поэтажного (58–74 px/м против
24). Не надо выбирать один — читай по нескольким:
SOURCES = [
{"dark": mask_flat, "s": 58.1, "cx": ..., "cz": ..., "box": (x0, z0, x1, z1)},
{"dark": mask_floor, "s": 23.94, "cx": ..., "cz": ..., "box": (-99, -99, 99, 99)},
]Для участка стены берём первый источник, чья зона его покрывает, и если он
не нашёл ось стены — падаем на общий план, а не записываем участок в
«читать не удалось». Без этого отката охват падает, а не растёт.
Привязка мелкого плана к общему делается по двум точкам: находишь на нём
комнату с подписанными размерами, приравниваешь её угол своей координате —
получаешь масштаб и смещение. Проверка — наложить свою сетку стен на план
поверх: расхождение больше 0,3 м значит, что привязка врёт.