Введение: рассмотрим вопрос программной обработки файла LandXML для формирования файла IFC с элементом IFCOPENSHELL. Об использовании самой программы см. раздел "Как использовать программу" в конце (сперва идет техническая часть).
1. Общая информация и принятые допущения
Допущения:
- Считаем, что поверхность формируется исключительно по данным триангуляции (либо сводится к такому представлению в ПО для её формирования).
- Предполагаем, что файл LandXML содержит одну поверхность (если их несколько, будет обработана только первая в порядке файла);
- Мы не создаем файл IFC используя какие-либо библиотеки, а пользуемся шаблоном, куда прописываем информацию о поверхности. Шаблон был взят с этого файла в этом сообщении в Telegram-группе поддержки по продукту Renga после удаления имеющейся структуры поверхности. В перспективе мне бы хотелось освоить, как это делать генерируя структуру самому, но пока работает и так.
Общая информация:
LandXML является универсальным форматом передачи данных о поверхностях и, частично, данных об инфраструктуре (трассы с кривыми, профили). Как формат IFC поддерживают все/почти все САПР, работающие с проектированием зданий и сооружений, так и формат LandXML по большей части поддерживает ПО для изысканий, инфраструктуры и генплана.
У LandXML есть своё SDK на C++ (здесь), но я пользовался обычными парсерами XML-файлов, так как структура у нас одна - поверхность, и мы ограничились в форме её представления (см. допущение №1).
Приложение для обработки писалось на CSharp WPF (в планах позже сделать встроенный в него Viewer файла LandXML). Само приложение доступно по ссылке в репозитории на GitHub. В качестве внешней зависимости используется Nuget-пакет NathNET.Numerics (для расчета параметров трансформации между системами координат и пересчета точек). Вообще говоря, там простые матричные преобразования и можно было бы их написать самому - но всё руки не доходят (так что, тащим вспомогательную библиотеку).
2. Где это актуально?
В связи с тем, что формат IFC суют где ни попадя является универсальным средством передачи геометрии между мультивендорным ПО, его классы удобно использовать для передачи особых видов геометрии, какие не передать другими способами. Например, традиционно, поверхности являются "заботой" программ для инженерных изысканий и генплана, которые передают её далее в ПО для проектирования как готовый файл. К сожалению, есть ряд ПО где полноценная поддержка представления поверхности пока не реализована (особенно это касается сред с поддержкой только формата IFC - наподобие продуктов Pilot-BIM и пр.).
В нашем случае, программа писалась под кейс "как загрузить поверхность в среду Renga". Встроенные форматы импорта её представления как mesh-структуры в форматах OBJ/FBX не давали нужного результата (требовала дополнительная обработка файла).
3. Как работает алгоритм на примере рабочего процесса?
Программа поддерживает 3 сценария обработки файла, заключающиеся в преобразовании координат поверхности. Мы рассмотрим их далее подробно. На вопрос "а зачем это надо?" см. небольшую сноску ниже. Сценарий по "преобразовывать как есть" пока под вопросом, не удается добиться его корректности.
Небольшая вводная: Все 3D САПР имеют так называемые, внутренние координаты модели и при значительных размерах координат модель начинает глючить пропорционально росту значений координат. Вместо этого, в некоторых ПО типа Autodesk Revit применяется механика "двойных" координат. Дополнительно в внутренним, вводятся понятие координат точки "съемки", которые "перетягивают" на себя большие цифры, и геометрия размещается в модели почти как в нуле.
Теперь расскажем механику работы итеративного процесса формирования файла на примере самой сложной опции с трансформацией координат.
Шаг 1: Инициализируем файл LandXML и формируем "контейнеры" данных
Используя встроенные .NET-обработчики файлов XML (пространства имён System.Xml и System.Xml.Linq) инициализируем выбранный LandXML-файл и формируем пару XElement с коллекцией точек и коллекцией 3D-граней.
Шаг 2: Рассчитываем параметры трансформации между системами координат
За теоретическими основами "причем тут системы координат" см. мою статью по системам координат, часть №6, последний раздел.
Предполагая, что вопросы всё равно возникнут, примем, что у нас имеется вот такой файл в программе Renga для которого нужно погрузить рельеф (из AutoCAD Civil 3D).
В соответствии с "рабочей задачей", сформируем набор координат для расчета параметров трансформации (переход от общих координат поверхности к внутренним координатам модели):
Текущие координаты поверхности:
2216582.1221,530008.5171,136
2216565.5541,530052.8739,136
2216547.802,530046.2432,136
Текущие координаты модели Renga (внутренние)
-8.282,2.125,0
39.068,2.125,0
39.068,21.075,0
Шаг 2: Записываем в IFC информацию о сдвижке координат
Примечание: так как мы используем файл шаблона, а не генерируем параметры с помощью библиотек по созданию IFC-файлов, то параметры преобразования сдвижки примем с оригинальными идентификаторами элементов (номера строки):
Примечание: придется смириться что символ решетки = этому знаку #
#43= IFCCARTESIANPOINT((dX,dY,dZ));
#45= IFCDIRECTION((Cos(ωz),-Sin(ωz),0.));
Здесь под dX,dY,dZ мы имеем в виду вычисленную сдвижку координата, под ωz - вычисленный угол поворота в радианах.
Ключевой вопрос - куда эти строки упрятать чтобы Renga это могла загрузить 😬😢. Я это сделать не смог, поэтому поступил по-другому, а именно, в соответствии с принятыми параметрами трансформации пересчитал все координаты точек поверхности (а не задавая эту величину сдвижки).
Поэтому (в случае прямого пересчета), я оставил эти параметры "нулевыми":
#43= IFCCARTESIANPOINT((0.,0.,0.));
#45= IFCDIRECTION((1.,0.,0.));
В случае выбора опции "преобразовывать как есть" эти параметра будут такими же. И при выборе "применять сдвижку" они будут такими же 😄. Почему так - потому что гладиолус потому что это хотя бы работает в случае с импортом в Renga.
Примечание: вообще говоря, напрямую пересчитывать координаты нехорошо, надо разобраться как работает эта "сдвижка", но у меня кончились идеи. Тут это работало отлично - а здесь нашла коса на камень (видимо, надо разбираться в структуре IFC и формировать его программно, а не как я).
Шаг 3: Записываем в IFC информацию по точкам поверхности
Пробегаемся по всем объекта триангуляции (XElement "Faces") и вычленяем из них номера точек, которые эту грань образовывают. Далее заносим во временный список List номера этих точек, чтобы впоследствии точки не дублировать в структуре файла IFC. Полученная точка ищется в блоке XElement "Pnts" и пересчитывается [внутренний метод] согласно параметрам трансформации/параметрам сдвижки. Далее она записывается в структура файла IFC с номером строки как " #Номер_точки + 1000", где 1000 - просто число (всего строк в нашем шаблоне ок. 690 - потому с 1000 для ровного счета мы начинаем заполнять наши строки).
Шаг 4: Записываем в IFC информацию по граням триангуляции
Теперь, имея в файле список точек, формируем структура поверхности как набора отдельных граней. Каждая грань описывается следующими элементами. Подробней см. на участке кода.
IFCPOLYLOOP, IFCFACEOUTERBOUND,IFCFACE
При этом набор граней описывается элементом IFCOPENSHELL.
После окончания перебора всех граней записывается данный элемент набора с фиксированным номером (завязанным на шаблоне).
Шаг 5: Конец
Записывается концовка файла IFC - стандартные строки:
ENDSEC;
END-ISO-10303-21;
4. Как использовать программу (и демонстрация её работы)
При наличии IDE, проект можно скомпилировать и скачать внешнюю зависимость - пакет MathNet.Numerics. При отсутствии оной можно скачать скомпилированную архивированную версию по ссылке.
Для удобства пользователя, мы ей и воспользуемся для демонстрации возможностей программы:
Вариант №1 - преобразование поверхности LandXML с автоматически рассчитанной сдвижкой (приближая к началу координат Renga для производительности).
Откроем его в Renga как Открыть ➝ Файл IFC:
Полученный элемент можно скопировать в другой файл Renga при помощи обычной операции копирования (Ctrl+C).
Вариант №2 - преобразование поверхности LandXML с расчетом параметров трансформации координат
Повторяем загрузку файла LandXML.
Далее вносим в текстовые контейнеры координаты точек для расчета
Примечание: настоятельно рекомендуется сменить системный разделитель дробной части с запятой на точку (в противном случае могут быть проблемы)
Текущие координаты поверхности:
2216582.1221,530008.5171,136
2216565.5541,530052.8739,136
2216547.802,530046.2432,136
Текущие координаты модели Renga (внутренние)
-8.282,2.125,0
39.068,2.125,0
39.068,21.075,0
Выбираем третий тип преобразования и нажимаем опцию "Запуск":
Тут я повторил его случайно дважды - поэтому такой результат (см. консоль). В качестве параметра контроля точности пересчета введен параметр "Линейная ошибка". В данном случае она составляет 2 нм. Если её величина больше 10 см - рекомендуется пересмотреть опорные точки - вы где-то ошиблись).
Загружаем данный файл в среду Renga.
Теперь самое вкусное - совмещение данных. Копируем поверхность выше. и открываем в соседнем окне программы нашу целевую модель - Детский садик [демонстрационная модель Renga].
Включаем Shift для точечной привязки к опорным узлам сетки 3D-вида в модели Renga и пытаемся дотянуться свободным пальцем до кнопки PrtSc и ставим точку привязки поверхности в "ноль Renga"
Поверхность повернута так как надо - можно убедиться посмотрел на Civil 3D (по ребрам триангуляции). Точнее к сожалению - можно сделать только на "показательной" поверхности с более сложной триангуляцией.
Выводы:
В данной статье мы с вами рассмотрели механику преобразования поверхности LandXML в элемент IFCOPENSHELL с набором 3D-граней, имитирующих проектную/существующую поверхность. Также мы отладили приложение для возможности импорта данного файла IFC в среду Renga для возможности там работать с рельефом хотя бы на уровне визуального анализа.
Приложение, как было сказано выше, доступно в отдельном репозитории на GitHub. Справка пока в данной статье (потом оформлю на markdown) и там в ReadMe.