От STL к BREP: слева обычная сшивка (808 плоских граней), справа восстановленный BREP (31 грань, 21 плоскость и 10 цилиндрических).

От STL к BREP: как AI-агент научился восстанавливать геометрию, а не просто сшивать треугольники

Открытый инструмент для FreeCAD MCP: восстановление плоскостей и цилиндрических поверхностей из STL, первые результаты и приглашение к тестированию.

В прошлой статье я рассказывал, как начал работать с FreeCAD через AI-агента. После публикации попросил знакомого, который профессионально занимается CAD, подсказать, чего ему не хватает в таком подходе.

Он назвал три задачи:

  1. Авто сшивку STL в BREP тела;
  2. Перевод чертежей в 3Д модели;
  3. Авто корректировку 3Д моделей типа reshape но с сохранением NURBS поверхностей и построенного на их основе тела.

Я решил начать с первой. Так в моём open-source форке FreeCAD MCP появился инструмент convert_mesh_to_brep.

Не просто сшивка треугольников

STL хранит треугольную сетку. Даже если сшить её в замкнутое BREP-тело, круглое отверстие может остаться набором плоских граней. Для дальнейшей работы с геометрией хотелось большего: распознавать в сетке плоскости и цилиндрические участки и заменять их настоящими аналитическими BREP-поверхностями.

Инструмент работает с самим STL — ему не нужны исходный OpenSCAD-проект, заранее известные радиусы или вручную выбранные грани. При этом он не восстанавливает историю построения детали и не обещает угадать исходные номинальные размеры.

Обычная сшивка STL в BREP: 808 плоских граней, цилиндры остались гранёными.

Рис. 1. tiltservomount_std.stl, сшитый в BREP без распознавания поверхностей (recognize_surfaces=False): 808 граней, все плоские. Отверстия и проушина состоят из узких плоских полосок.

Тот же файл после convert_mesh_to_brep: 31 грань, цилиндрические поверхности выделены оранжевым.

Рис. 2. Тот же STL после convert_mesh_to_brep(repair=true): 31 грань, из них 21 Plane и 10 Cylinder. Типы поверхностей прочитаны из BREP; цилиндрические грани окрашены оранжевым только для рисунка.

Многопроходный конвейер

Конвертация состоит из нескольких этапов:

STL / Mesh в FreeCAD
       │
       ▼
Проверка сетки и опциональный ремонт мелких дефектов
       │
       ▼
Сшивка в BREP-оболочку и создание solid
       │
       ▼
Восстановление общих плоскостей
       │
       ▼
Распознавание полных и частичных цилиндров, дуг
       │
       ▼
Поиск оставшихся гранёных участков
       │
       ├── есть подходящие участки и прогресс → ещё проход
       ▼
Контроль валидности, объёма и габаритов → отчёт

Алгоритм делает до четырёх проходов распознавания. Он пытается обработать оставшиеся поддерживаемые участки автоматически, вместо того чтобы останавливаться после первой найденной поверхности.

В отчёте отдельно отражаются валидность BREP и признаки остаточной гранёности (reconstruction_status). Это разные вещи: замкнутое тело ещё не означает, что цилиндры действительно восстановлены. И наоборот, отсутствие обнаруженных гранёных участков не доказывает идеальную реконструкцию всей геометрии.

Результат — отдельный объект Part::Feature. Поддерживаются аналитические плоскости, полные и некоторые частичные цилиндрические поверхности; произвольные NURBS-поверхности, конусы и сферы пока не реконструируются.

Результат на шести деталях

Для первых проверок я использовал шесть STL из Pan and Tilt for Standard Servo автора micromet (модели — CC BY-SA). На всём наборе использовался один инструмент с repair=true и стандартными допусками, без ручного выбора граней и размеров.

Деталь Граней BREP Плоскостей Цилиндрических граней Изменение объёма
PanTiltBase_std 27 12 15 0,0397%
PanMount7 45 34 11 0,0306%
sideplateservo_std 24 15 9 0,0227%
sideplateshaft_std 14 9 5 0,0109%
tiltservomount_std 31 21 10 0,0279%
IRTmount_pantilt 24 14 10 0,0253%

Например, tiltservomount_std.stl содержал 2884 треугольника, а на выходе получился BREP из 31 грани: 21 плоскости и 10 цилиндрических участков. Это именно типы аналитических поверхностей, а не просто визуально сглаженная сетка. Число цилиндрических граней не равно числу отверстий: один цилиндр может состоять из нескольких участков.

Исходная сетка tiltservomount_std.stl: 2884 треугольника.

Рис. 3. Исходная сетка tiltservomount_std.stl в том же ракурсе, что на рис. 1 и 2: 2884 треугольника → 31 BREP-грань (21 плоскость, 10 цилиндрических поверхностей, рис. 2).

Все шесть результатов — замкнутые валидные тела. Они прошли проверки геометрического ядра и тест сохранения с повторным открытием файла. Изменение объёма на каждой детали — менее 0,04%; сканер не обнаружил оставшихся цепочек граней, которые он умеет распознавать.

Но это только первый тест. Все шесть деталей — из одного комплекта, на них же велась разработка. Близость объёмов не гарантирует точность поверхностей: максимальное расстояние между исходной сеткой и результатом здесь отдельно не измерялось. Для произвольных STL надёжность ещё предстоит проверить.

Как попробовать

Код открыт: github.com/hram/freecad-mcp. Подробности установки, параметры, диагностические поля и ограничения — в документации convert_mesh_to_brep.

Когда FreeCAD запущен с обновлённым аддоном и работающим RPC, AI-агент может вызвать инструмент так:

convert_mesh_to_brep(
    doc_name="Example",
    source_file="/path/to/part.stl",
    name="RecoveredPart",
    repair=true
)

Путь к STL указывается на компьютере, где работает FreeCAD. Вместо файла можно передать существующий mesh-объект. Исходная сетка сохраняется, новый BREP создаётся отдельно; документ автоматически не записывается.

Конвертер возвращает JSON-отчёт (он также сохраняется в ConversionReport) с найденными поверхностями, отклонениями и причинами, по которым отдельные участки не удалось восстановить.

Мне нужны STL, на которых этот инструмент сломается

Я не CAD-профессионал, и шести тестовых деталей явно мало. Хочу проверить инструмент на настоящих задачах, а не продолжать подгонять его под один Pan–Tilt.

Если вы работаете с CAD, попробуйте конвертер на своём STL. Особенно интересны случаи, когда он оставляет цилиндры гранёными, неверно распознаёт поверхности, искажает отверстия, создаёт лишнюю геометрию или вообще не может обработать сетку.

Присылайте ошибки и идеи в GitHub Issues. Очень помогут проблемный STL, скриншот ожидаемого и фактического результата, версия FreeCAD и JSON-отчёт. Если модель коммерческая или конфиденциальная, не публикуйте её: достаточно обезличенного или специально упрощённого примера, на котором воспроизводится дефект.

Вторая и третья идеи моего знакомого тоже интересны. Но сначала хочется понять, насколько полезной можно сделать первую — с помощью тех, кто работает с такой геометрией каждый день.

Если ваш STL ломает мой конвертер — это именно то, что мне сейчас нужно.