Блог

Создаём с нуля своё BIM-приложение для просмотра моделей IFC формата в браузере на основе open-source библиотеки IFC.js

Введение

Приложение, о котором пойдёт речь, применимо в архитектурно-строительной области. С развитием информационных технологий, технологий строительства и производства, а также экономической составляющей, появилась необходимость в более эффективном и комплексном подходах в управлении инвестиционно-строительными проектами, что поспособствовало появлению и формированию ТИМ BIM-технологии.
BIM (англ. Building Information Model или Информационное моделирование строительных объектов) — это объектно-ориентированная модель строительного объекта, как правило, в трёхмерном представлении, элементы которой содержат данные геометрических, физических и функциональных характеристик будущего здания или сооружения.

BIM-технология — организованный процесс, в результате которого формируется BIM-модель, отвечающая задачам и потребностям конкретной стадии жизненного цикла здания или сооружения.
Основным популяризатором и разработчиком программ в области BIM, принято считать компанию Autodesk с их приложениями для AEC (Architecture, Engineering, and Construction) индустрии — Revit, Navisworks, ACC (Autodesk Construction Cloud, ex-BIM360) и др., но в последнее время, активно набирает обороты недовольство пользователей продуктов Autodesk, аргументируя это стагнацией в части разработки нового полезного функционала и недоработки существующего, при этом явным повышением цен на программное обеспечение. Ещё одной проблемой, является замкнутая экосистема Autodesk и их закрытый формат данных (Closed BIM), работая с которым, ты ограничен в действиях и вынужден оставаться в контуре Autodesk. На примере Revit и Autodesk Platform Services, ex-Forge.
По мере развития BIM-технологии и нежеланием быть зависимым от больших корпораций, свою популярность приобрела концепция OpenBIM и сопутствующий ей IFC формат.
Open BIM — подход к объединению проектов зданий и сооружений в согласованную модель. Методология, позволяющая участникам проектирования коммуницировать, невзирая на используемое программное обеспечение.

IFC (Industry Foundation Classes) — открытый стандарт для формата представления данных BIM. Формат файлов разработан buildingSMART (International Alliance for Interoperability, IAI) для упрощения взаимодействия в строительной сфере и приведению к общему знаменателю.
С тенденцией перехода сервисов в облачные решения, начали появляться open-source библиотеки или бесплатные программы по работе с BIM-моделями в web, такие, как xeokit, IFC++, IfcOpenShell и др., а соответственно и BIM-стартапы, преследующие цели OpenBIM или закрывающие конкретные задачи. Одну из таких библиотек мы и рассмотрим, развернув на её основе простое BIM-решение для просмотра модели IFC формата.

Библиотека IFC.js

IFC.js — это библиотека JavaScript для работы с моделями IFC в браузере. Она полностью бесплатная и распространяется по свободной лицензии MIT.
IFC.js
IFC.js
Идейным создателем и одним из разработчиков библиотеки IFC.js, является Antonio González Viegas — BIM software developer. И в качестве предпосылки для создания этого open-source решения и его описания, приведу вольный перевод с его слов:
Сектор AEC традиционно был рынком нескольких богатых ресурсами игроков. Крупные компании годами создавали свои собственные продукты: миллионы строк кода, решающие проблемы и в конечном итоге составляют приложения для реализации BIM и которые мы знаем из повседневной жизни.

Проблема в этой ситуации заключается в том, что новым разработчикам и компаниям очень трудно предлагать свои идеи и конкурировать на равных условиях на этом рынке. И получается, что доступ к "высшей лиге" имеют те, кто может себе это позволить.

Это не относится к таким секторам, как видеоигры, где существует множество инструментов и технологий (видеоигровых движков), которые позволяют любому создать продукт высокого уровня с минимальными затратами времени и ресурсов. Было бы здорово иметь то же самое в секторе AEC?

Вот почему мы запустили IFC.js. Вместо того чтобы создавать решение для реализации технологии BIM и продавать его как продукт, мы делаем его свободно доступным, чтобы каждый мог создавать свои собственные BIM-продукты высокого уровня. Таким образом, мы все можем конкурировать на рынке программного обеспечения с одним и тем же инструментом, где каждый может предложить свои идеи по улучшению.

IFC.js — молодой проект, который развивается и растет с каждым днем. Наша цель — позволить каждому разрабатывать программное обеспечение BIM с такой же легкостью, с какой разрабатываются видеоигры. IFC.js бесплатен, у него нет владельца, и любой может использовать его или участвовать в проекте.
Как вы уже возможно поняли, преследуется концепция Open BIM, противопоставляя решение тяжеловесным и закрытым проприетарным программам. IFC.js даёт возможность BIM-специалистам или разработчикам из других сфер создавать свои собственные BIM-решения, решающие их бизнес-задачи внутри компаний или же создавать свои коммерческие BIM-стартапы. В этом плане, лицензия IFC.js даёт полную свободу действий. Библиотека предназначена для всех, кто хочет разрабатывать BIM-приложения, будь то разработчики, создающие сервисы для строительной отрасли, так и архитекторы совместно с другими специалистами.

Структура IFC.js

В связи с тем, что IFC.js большая, мульти-язычная библиотека (C++, TypeScript JavaScript и т.д.) и держать её в одном репозитории было бы сложно и громоздко, её разбили на три основные части:
web-ifc — ядро библиотеки: IFC парсер, написанный с нуля на языке C и скомпилирован через Emscripten в WebAssembly. Этот репозиторий инкапсулирует сложность чтения файлов IFC и загрузки их данных в память. Demo
web-ifc
web-ifc
web-ifc-three — эта библиотека адаптирует web-ifc к Three.js, создавая оптимизированную 3D-сцену, в которой пользователи могут напрямую взаимодействовать с IFC. Эта библиотека является официальным IFC загрузчиком в Three.js. Благодаря этому, приложения BIM можно создавать с помощью Three.js всего за пару строк кода. Demo
web-ifc-three
web-ifc-three
web-ifc-viewer — это решение для просмотра IFC в браузере со множеством примеров того, что можно сделать с помощью IFC.js. Навигация по сценам, изменение материалов, выбор элементов по нажатию на них, планы разрезов и т. д. В этом репозитории есть пример всех этих функций, поэтому его можно повторно использовать в открытых приложениях BIM из коробки. Demo
web-ifc-viewer
web-ifc-viewer
Каждая последующая часть зависит от предыдущей, в такой последовательности: web-ifcweb-ifc-threeweb-ifc-viewer

Обучение

На данный момент, проводятся два курса IFC.js crash course и Advanced BIM frontend course по работе с их библиотекой в web. Курс IFC.js crach cource, как заявляет создатель, подходит для начального уровня и обучение ведётся с нуля, но под конец, как по мне, без хорошей базы в программировании будет тяжеловато.

Программа поддержки

В целях ускорения разработки проекта, а так же его улучшения — команда IFC.js реализовала программу поддержки, где даёт возможность заработать сообществу, принося свой вклад в проект. Если вкратце, то формируются карточки с разного рода заданиями, например исправление бага или реализации инструментов, таких как проверка на коллизии, формирование планов, разрезов и т.д.

Разработка BIM-сервиса для просмотра IFC формата

Создание BIM-приложения с IFC.js довольно простое, как указано на сайте с документацией. Последующий урок взят оттуда в качестве вольного перевода, с некоторыми сокращениями, отклонениями и комментариями. Развёрнутое демо-приложение находиться тут. Для выполнения следующих шагов необходим Node.js и любая IDE, но в статье я буду использовать VS Code в качестве среды разработки и расширение Live Preview в части локального сервера, не разворачивая Node.js. И если у вас нет файлов IFC, вы можете их скачать отсюда.
Для работы с IFC.js требуются базовые знания веб-разработки (HTML, CSS, JavaScript) и библиотеки Three.js

Установка библиотек

Вначале, создаём пустую папку и запускаем менеджер пакетов npm с помощью команды npm init. Будет создан файл package.json, содержащий некоторые данные, такие как имя проекта, версия, описание, команды и зависимости.
Все вышеперечисленные свойства можно сразу заполнить, либо прожав Enter и использовать значения по умолчанию.
Инициализация проекта
Инициализация проекта
Кроме того, при помощи npm необходимо установить следующие зависимости: модуль web-ifc-three (с ним ставится и Three.js), входящий в IFC.js и rollup.js в качестве сборщика проекта для JavaScript.
    //Install IFC.js
    npm i web-ifc-three

    // Install a bundler: we will use rollup.js for this guide
    npm i rollup --save-dev
    npm i @rollup/plugin-node-resolve --save-dev
Сразу можно проверить наличие в package.json файле свойство "type": "module" и добавить его, если оно отсутствует.
Структура файла package.json
Структура файла package.json
Следующим шагом, будет создание HTML файла с именемindex.html в качестве основного документа приложения. HTML будет иметь:
  • canvas элемент, используемый для рендеринга сцены Three.js;
  • input элемент, который будет открывать файлы IFC с нашего компьютера в приложении.
  • Тэг script, ссылающийся на файл bundle.js, представляющий собой сборку приложения, которую мы создадим дальше с помощью rollup.
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8"/>
    <meta http-equiv="X-UA-Compatible" content="IE=edge"/>
    <meta name="viewport" content="width=device-width, initial-scale=1.0"/>
    <link rel="stylesheet" href="styles.css"/>
    <title>Document</title>
  </head>
  <body>
    <input type="file" name="load" id="file-input"/>
    <canvas id="three-canvas"></canvas>
    <script src="bundle.js"></script>
  </body>
</html>
Для удобства импорта нашей будущей IFC-модели для тэга <input> можно добавить атрибут accept=".ifc" и видеть только файлы с расширением .ifc в директории, откуда загружаем модель.

Добавление стилей

Создаём CSS файл styles.css, где произведём сброс стилей, сделаем наш canvas на весь экран и зададим свойства нашей будущей кнопки для загрузки IFC-модели:
* {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
}

html,
body {
  overflow: hidden;
}

#three-canvas {
  position: fixed;
  top: 0;
  left: 0;
  outline: none;
}

#file-input {
  z-index: 1;
  position: absolute;
}

Сборка проекта

Далее, создадим файл конфигурации с именем rollup.config.js, который будет включать в себя ссылки на ранее установленные дополнения.
Rollup — популярная библиотека пакетов. К примеру, это сборщик, используемый Three.js. Чтобы узнать больше, ознакомьтесь с документацией.
import resolve from "@rollup/plugin-node-resolve";

export default {
  input: "app.js",
  output: [
    {
      format: "esm",
      file: "bundle.js",
    },
  ],
  plugins: [resolve()],
};
Также, в файле package.json изменим команды в области scripts для удобного управления объединением/сборки проекта. В каждой команде необходимо указать относительный путь к файлу конфигурации rollup.
  • npm run build объединит проект и создаст файл с именем bundle.js в корневом каталоге проекта.
  • npm run watch активирует режим просмотра, автоматически обновляя этот файл каждый раз, когда мы вносим и сохраняем изменения в код.
{
  "name": "example",
  "version": "1.0.0",
  "description": "-",
  "main": "app.js",
  "scripts": {
    "build": "rollup -c ./rollup.config.js",
    "watch": "rollup -w -c ./rollup.config.js"
  },
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "@rollup/plugin-node-resolve": "^11.2.1",
    "rollup": "^2.45.2"
  },
  "dependencies": {
    "three": "^0.128.0",
    "web-ifc-three": "0.0.102"
  }
}

WebAssembly

Далее, необходимо скопировать файл web-ifc.wasm в директорию проекта. Найти его можно по пути node_modules\web-ifc и скопировать куда угодно, впоследствии указав на него путь, но в примере он будет размещен в корне проекта.
Копирование файла web-ifc.wasm
Копирование файла web-ifc.wasm
Этот файл необходим, так как содержит скомпилированную C++ логику модуля web-ifc, являющемся ядром парсинга для чтения и записи IFC файлов.

Создание и настройка 3D сцены

Наконец, мы создадим JavaScript файл для нашего приложения. Разместить его можно где-угодно и задать произвольно имя, главное отразить это в файле rollup.config.js. В примере это будет app.js в корне проекта.
Базовая 3D-сцена Three.js
import { AmbientLight, AxesHelper, DirectionalLight, GridHelper, PerspectiveCamera, Scene, WebGLRenderer } from "three";
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls.js";

//Creates the Three.js scene
const scene = new Scene();

//Object to store the size of the viewport
const size = {
  width: window.innerWidth,
  height: window.innerHeight,
};

//Creates the camera (point of view of the user)
const aspect = size.width / size.height;
const camera = new PerspectiveCamera(75, aspect);
camera.position.z = 15;
camera.position.y = 13;
camera.position.x = 8;

//Creates the lights of the scene
const lightColor = 0xffffff;

const ambientLight = new AmbientLight(lightColor, 0.5);
scene.add(ambientLight);

const directionalLight = new DirectionalLight(lightColor, 1);
directionalLight.position.set(0, 10, 0);
directionalLight.target.position.set(-5, 0, 0);
scene.add(directionalLight);
scene.add(directionalLight.target);

//Sets up the renderer, fetching the canvas of the HTML
const threeCanvas = document.getElementById("three-canvas");
const renderer = new WebGLRenderer({
  canvas: threeCanvas,
  alpha: true,
});

renderer.setSize(size.width, size.height);
renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2));

//Creates grids and axes in the scene
const grid = new GridHelper(50, 30);
scene.add(grid);

const axes = new AxesHelper();
axes.material.depthTest = false;
axes.renderOrder = 1;
scene.add(axes);

//Creates the orbit controls (to navigate the scene)
const controls = new OrbitControls(camera, threeCanvas);
controls.enableDamping = true;
controls.target.set(-2, 0, 0);

//Animation loop
const animate = () => {
  controls.update();
  renderer.render(scene, camera);
  requestAnimationFrame(animate);
};

animate();

//Adjust the viewport to the size of the browser
window.addEventListener("resize", () => {
  size.width = window.innerWidth;
  size.height = window.innerHeight;
  camera.aspect = size.width / size.height;
  camera.updateProjectionMatrix();
  renderer.setSize(size.width, size.height);
});

Загрузка IFC файлов

В завершении мы будем использовать IFC.js для загрузки IFC файлов. Создадим экземпляр загрузчика и событие, когда пользователь загружает IFC файл с помощью элемента ввода <input>
import { IFCLoader } from "web-ifc-three/IFCLoader";

// Sets up the IFC loading
const ifcLoader = new IFCLoader();

const input = document.getElementById("file-input");
input.addEventListener(
  "change",
  (changed) => {
    const file = changed.target.files[0];
    var ifcURL = URL.createObjectURL(file);
    ifcLoader.load(ifcURL, (ifcModel) => scene.add(ifcModel));
  },
  false
);
Готовый app.js файл будет так:
import {
  AmbientLight,
  AxesHelper,
  DirectionalLight,
  GridHelper,
  PerspectiveCamera,
  Scene,
  WebGLRenderer,
} from "three";
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls.js";
import { IFCLoader } from "web-ifc-three/IFCLoader";


//Creates the Three.js scene
const scene = new Scene();

//Object to store the size of the viewport
const size = {
  width: window.innerWidth,
  height: window.innerHeight,
};

//Creates the camera (point of view of the user)
const aspect = size.width / size.height;
const camera = new PerspectiveCamera(75, aspect);
camera.position.z = 15;
camera.position.y = 13;
camera.position.x = 8;

//Creates the lights of the scene
const lightColor = 0xffffff;

const ambientLight = new AmbientLight(lightColor, 0.5);
scene.add(ambientLight);

const directionalLight = new DirectionalLight(lightColor, 1);
directionalLight.position.set(0, 10, 0);
directionalLight.target.position.set(-5, 0, 0);
scene.add(directionalLight);
scene.add(directionalLight.target);

//Sets up the renderer, fetching the canvas of the HTML
const threeCanvas = document.getElementById("three-canvas");
const renderer = new WebGLRenderer({
  canvas: threeCanvas,
  alpha: true,
});

renderer.setSize(size.width, size.height);
renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2));

//Creates grids and axes in the scene
const grid = new GridHelper(50, 30);
scene.add(grid);

const axes = new AxesHelper();
axes.material.depthTest = false;
axes.renderOrder = 1;
scene.add(axes);

//Creates the orbit controls (to navigate the scene)
const controls = new OrbitControls(camera, threeCanvas);
controls.enableDamping = true;
controls.target.set(-2, 0, 0);

//Animation loop
const animate = () => {
  controls.update();
  renderer.render(scene, camera);
  requestAnimationFrame(animate);
};

animate();

//Adjust the viewport to the size of the browser
window.addEventListener("resize", () => {
  size.width = window.innerWidth;
  size.height = window.innerHeight;
  camera.aspect = size.width / size.height;
  camera.updateProjectionMatrix();
  renderer.setSize(size.width, size.height);
});

// Sets up the IFC loading
const ifcLoader = new IFCLoader();

const input = document.getElementById("file-input");
input.addEventListener(
  "change",
  (changed) => {
    const file = changed.target.files[0];
    var ifcURL = URL.createObjectURL(file);
    ifcLoader.load(ifcURL, (ifcModel) => scene.add(ifcModel));
  },
  false
);tURL(file);
    ifcLoader.load(ifcURL, (ifcModel) => scene.add(ifcModel));
  },
  false
);
И если всё настроенное корректно, то после вызова команды npm run build мы можем собрать и запустить наше приложение, запустив расширение Live Preview, которое мы устанавливали ранее, с адресом http://127.0.0.1:3000 в браузере или открыть index.html в папке проекта.
Сборка и запуск приложения
Сборка и запуск приложения

Финальный результат. Можете загрузить свою IFC-модель
В качестве примера — простая модель с пометками и атрибутивной информацией элементов.

Заключение

Библиотека IFC.js действительно молодой проект и развивается довольно быстро, но уже сейчас даёт возможность реализовывать полноценные BIM‑приложения. В связи с последними тенденциями и активным интересом в сторону подхода Open BIMIFC.js прокладывает отличный путь для развития сервисов в строительной индустрии. Вокруг проекта уже сформировалось значительное комьюнити к которому можно присоединиться в Discord.

P.S.

Я старался максимально сократить и упростить вводную часть, в том числе с определениями и понятиями, на сколько смог. Возможно, некоторые моменты могут быть не до конца понятными или раскрытыми. В свою очередь, я старался сделать акцент больше на технической части, но при этом добавив контекста для читателей не из архитектурно‑строительной сферы.
BIM-решения IFC