From 207b09cbb872dd3834dac7d3231b99f8f647035f Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Nicol=C3=B2=20P?= <nicolo.paraciani@cnr.it>
Date: Tue, 28 May 2024 14:39:36 +0200
Subject: [PATCH] Basic IFC load

TODO: separate styles, use CSS library...
---
 index.html | 24 ++++++++++++++++++++-
 ui.js      | 61 ++++++++++++++++++++++++++++++++++++++++--------------
 2 files changed, 69 insertions(+), 16 deletions(-)

diff --git a/index.html b/index.html
index 39dad1a..8946e7f 100644
--- a/index.html
+++ b/index.html
@@ -17,9 +17,31 @@
         }
     </script>
     <script src='main.js' type="module"></script>
+	<style>
+		input[type="file"] {
+			opacity: 0;
+		}
+		label[for="load-ifc"] {
+			padding: 10px;
+			cursor: pointer;
+			position: absolute;
+			top: 0;
+			right: 4rem;
+			background-color: #ddd;
+			border: 1px #333 solid;
+			border-radius: 5px;
+		}
+	</style>
 </head>
 <body>
     <div id="scene" style="min-height: 100vh;"></div>
-    <div id="ui" style="position: absolute; top: 2rem; min-width: 100vw; z-index: 5;"></div>
+    <div id="ui" style="position: absolute; top: 2rem; min-width: 100vw; z-index: 5;">
+		<label for="load-ifc">Apri file IFC</label>
+		<input
+			type="file"
+			id="load-ifc"
+			name="load-ifc"
+			accept=".ifc" />
+    </div>
 </body>
 </html>
\ No newline at end of file
diff --git a/ui.js b/ui.js
index bd4e4df..a027f45 100644
--- a/ui.js
+++ b/ui.js
@@ -2,6 +2,7 @@
 
 import * as THREE from 'three';
 import * as OBC from 'openbim-components';
+import * as WEBIFC from 'web-ifc';
 
 /**
  * @namespace Actions
@@ -25,16 +26,47 @@ Actions.init = function (container) {
 
     // Starts the app and updates components at 60 fps
     components.init();
+    this.world = world;
+    this.components = components;
 
     return {components, world};
 }
 /**
+ * @todo Serve web-ifc.wasm locally via AJAX
  * @param {OBC.Components} components 
+ * @param {ArrayBuffer} buffer The uploaded IFC file 
  */
-Actions.loadIfc = function (components) {
-    const fragments = components.get(OBC.FragmentsManager);
+Actions.loadIfc = async function (buffer) {
+    const fragments = this.components.get(OBC.FragmentsManager);
+    // Clean memory before uploading new file
+    fragments.dispose();
 
-    console.log('Working...');
+    const fragmentIfcLoader = this.components.get(OBC.IfcLoader);
+    // NOTE: loads web-ifc WASM from https://unpkg.com/web-ifc@0.0.53/
+    await fragmentIfcLoader.setup();
+    /*
+    fragmentIfcLoader.settings.wasm = {
+      path: "./vendor/web-ifc/web-ifc.wasm",
+      absolute: false
+    }
+    */
+    // Excludes IFC categories from the fragment
+    const excludedCats = [
+        WEBIFC.IFCTENDONANCHOR,
+        WEBIFC.IFCREINFORCINGBAR,
+        WEBIFC.IFCREINFORCINGELEMENT,
+    ];
+
+    for (const cat of excludedCats) {
+        fragmentIfcLoader.settings.excludedCategories.add(cat);
+    }
+
+    fragmentIfcLoader.settings.webIfc.COORDINATE_TO_ORIGIN = true;
+    fragmentIfcLoader.settings.webIfc.OPTIMIZE_PROFILES = true;
+
+    const model = await fragmentIfcLoader.load(buffer);
+    model.name = "Test";
+    this.world.scene.three.add(model);
 
     return fragments;
 }
@@ -44,12 +76,13 @@ Actions.loadIfc = function (components) {
  * @returns {OBC.Components}
  */
 Actions.createScene = function (container) {
-    const {components, world} = this.init(container);
+    //const {components, world} =
+    this.init(container);
 
-    world.scene.setup();
-    world.camera.controls.setLookAt(3, 3, 3, 0, 0, 0);
+    this.world.scene.setup();
+    this.world.camera.controls.setLookAt(3, 3, 3, 0, 0, 0);
 
-    return components;
+    //return components;
 }
 /**
  * @namespace UI
@@ -66,14 +99,12 @@ UI.setScene = function (container) {
 /**
  * @param {string} uiContainer The UI div's id
  */
-UI.ifcLoader = function (uiContainer) {
-    const ui = document.querySelector(`#${uiContainer}`);
-    const loadBtn = document.createElement('button');
-    loadBtn.textContent = 'Apri IFC';
-    loadBtn.style = 'padding: 10px; cursor: pointer; position: absolute; top: 0; right: 4rem';
-    loadBtn.onclick = Actions.loadIfc(this.components);
-
-    ui.appendChild(loadBtn);
+UI.ifcLoader = function () {
+    const loadBtn = document.querySelector(`#load-ifc`);
+    loadBtn.onchange = async function () {
+        const files = this.files;
+        Actions.loadIfc(new Uint8Array(await files[0].arrayBuffer()));
+    }
 };
 
 export default UI;
\ No newline at end of file