Skip to content
This repository was archived by the owner on Jan 12, 2025. It is now read-only.

Commit 10487f3

Browse files
Merge pull request #8 from IfcOpenShell/example-dev
reorganize examples and add new examples
2 parents aa22188 + 5785116 commit 10487f3

File tree

3 files changed

+229
-0
lines changed

3 files changed

+229
-0
lines changed
File renamed without changes.
File renamed without changes.
Lines changed: 229 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,229 @@
1+
<!DOCTYPE html>
2+
<html>
3+
<head>
4+
<meta charset="utf-8" />
5+
<link rel="stylesheet" href="style.css">
6+
</head>
7+
<body class='loading'>
8+
<div id='branding'>
9+
<b>IfcOpenShell</b> WebAssembly
10+
</div>
11+
<div class='msg'>
12+
<div id='status1'>Loading...</div>
13+
<div id='status2'></div>
14+
</div>
15+
<form action='#' onsubmit="return false;">
16+
<div>Client-side model viewer</div>
17+
<input type='button' id='btn' value='Generate basic wall'>
18+
</form>
19+
<script type="text/javascript">document.querySelector("#status2").innerHTML = "Fetching pyodide";</script>
20+
<script type="text/javascript" src="https://cdn.jsdelivr.net/pyodide/v0.22.0a1/full/pyodide.js"></script>
21+
<script async src="https://unpkg.com/es-module-shims@1.3.6/dist/es-module-shims.js"></script>
22+
<script type="importmap">
23+
{"imports": {"three": "https://unpkg.com/three@0.141.0/build/three.module.js",
24+
"OrbitControls": "https://unpkg.com/three@0.141.0/examples/jsm/controls/OrbitControls.js"}}
25+
</script>
26+
<script type="module">
27+
function download(filename, text) {
28+
var element = document.createElement('a');
29+
element.setAttribute('href', 'data:text/plain;charset=utf-8,' + encodeURIComponent(text));
30+
element.setAttribute('download', filename);
31+
32+
element.style.display = 'none';
33+
document.body.appendChild(element);
34+
35+
element.click();
36+
37+
document.body.removeChild(element);
38+
}
39+
40+
import * as THREE from 'three';
41+
import { OrbitControls } from 'OrbitControls';
42+
43+
THREE.Object3D.DefaultUp = new THREE.Vector3(0,0,1);
44+
45+
let pyodide = null;
46+
47+
async function main() {
48+
document.querySelector("#status2").innerHTML = "Initializing pyodide";
49+
pyodide = await loadPyodide();
50+
document.querySelector("#status2").innerHTML = "Loading package manager";
51+
await pyodide.loadPackage("micropip");
52+
await pyodide.loadPackage("numpy");
53+
const micropip = pyodide.pyimport("micropip");
54+
document.querySelector("#status2").innerHTML = "Loading IfcOpenShell (this may take a while)";
55+
await micropip.install("../IfcOpenShell-0.7.0-py3-none-any.whl");
56+
57+
//console.log(output);
58+
document.body.className = '';
59+
60+
document.querySelector("input[type=button]").onclick = async () => {
61+
document.body.className = 'loading';
62+
document.querySelector("#status2").innerHTML = "Generating geometry";
63+
64+
let model = pyodide.runPython(await (await fetch("create_basic_wall.py")).text());
65+
66+
let ifcopenshell = pyodide.pyimport('ifcopenshell');
67+
68+
let ifc = ifcopenshell.file.from_string(model.to_string());
69+
70+
let ifcopenshell_geom = pyodide.pyimport('ifcopenshell.geom');
71+
72+
let s = ifcopenshell_geom.settings();
73+
s.set(s.WELD_VERTICES, false);
74+
/*
75+
let it = ifcopenshell_geom.iterator.callKwargs({
76+
'settings': s,
77+
'file_or_filename': ifc,
78+
'num_threads': 8});
79+
'exclude':['IfcSpace', 'IfcOpeningElement']});
80+
*/
81+
let it = ifcopenshell_geom.iterator(s, ifc);
82+
83+
let last_mesh_id = null;
84+
let geometries;
85+
86+
const renderer = new THREE.WebGLRenderer();
87+
renderer.setSize( window.innerWidth, window.innerHeight );
88+
document.body.appendChild( renderer.domElement );
89+
90+
renderer.setClearColor(0x000000, 0);
91+
const scene = new THREE.Scene();
92+
93+
var light = new THREE.DirectionalLight(0xFFFFFF);
94+
light.position.set(20, 10, 30);
95+
scene.add(light);
96+
var light = new THREE.DirectionalLight(0xFFFFFF, 0.8);
97+
light.position.set(-10, 1, -30);
98+
scene.add(light);
99+
scene.add(new THREE.AmbientLight(0x404050));
100+
101+
const camera = new THREE.PerspectiveCamera( 45, window.innerWidth / window.innerHeight, 1, 10000 );
102+
103+
const controls = new OrbitControls( camera, renderer.domElement );
104+
105+
if (it.initialize()) {
106+
while (true) {
107+
let obj = it.get();
108+
109+
// obj.type appears to be overwritten by pyodide, returning the typename of the C++ class?
110+
let ty = ifc.by_id(obj.id).is_a()
111+
if (ty !== 'IfcOpeningElement' && ty !== 'IfcSpace') {
112+
113+
if (last_mesh_id != obj.geometry.id) {
114+
geometries = [];
115+
116+
let materials = obj.geometry.materials.toJs().map(e => new THREE.MeshLambertMaterial({
117+
color: new THREE.Color(...e.diffuse.toJs()),
118+
opacity: 1.0 - e.transparency,
119+
transparent: e.transparency > 1.e-5,
120+
side: THREE.DoubleSide
121+
}));
122+
123+
let mapping = {};
124+
obj.geometry.material_ids.toJs().forEach((i, idx) => {
125+
mapping[i] = mapping[i] || []
126+
mapping[i].push(idx);
127+
});
128+
129+
let vs = new Float32Array(obj.geometry.verts.toJs());
130+
let ns = new Float32Array(obj.geometry.normals.toJs());
131+
let fs = obj.geometry.faces.toJs();
132+
133+
// Default material
134+
let offset = 0;
135+
if (mapping[-1]) {
136+
materials.unshift(new THREE.MeshLambertMaterial({
137+
color: new THREE.Color(0.6,0.6,0.6),
138+
side: THREE.DoubleSide
139+
}));
140+
offset = 1;
141+
}
142+
143+
materials.forEach((m, mi) => {
144+
let geometry = new THREE.BufferGeometry();
145+
146+
geometry.setIndex(mapping[mi - offset].flatMap(i => [fs[3*i+0], fs[3*i+1], fs[3*i+2]]));
147+
geometry.setAttribute('position', new THREE.Float32BufferAttribute(vs, 3));
148+
geometry.setAttribute('normal', new THREE.Float32BufferAttribute(ns, 3));
149+
150+
geometries.push([geometry, m]);
151+
});
152+
153+
last_mesh_id = obj.geometry.id;
154+
}
155+
156+
for (let gm of geometries) {
157+
let [g, mat] = gm;
158+
let mesh = new THREE.Mesh(g, mat);
159+
160+
var matrix = new THREE.Matrix4();
161+
const m = obj.transformation.matrix.data.toJs();
162+
matrix.set(m[0], m[1], m[2], 0, m[3], m[4], m[5], 0, m[6], m[7], m[8], 0, m[9], m[10], m[11], 1);
163+
matrix.transpose();
164+
mesh.matrixAutoUpdate = false;
165+
mesh.matrix = matrix;
166+
167+
scene.add(mesh);
168+
}
169+
}
170+
171+
if (!it.next()) {
172+
break;
173+
}
174+
}
175+
}
176+
document.body.className = 'rendering';
177+
178+
var boundingBox = new THREE.Box3();
179+
boundingBox.setFromObject(scene);
180+
var center = new THREE.Vector3();
181+
boundingBox.getCenter(center);
182+
controls.target = center;
183+
184+
var viewDistance = boundingBox.getSize(new THREE.Vector3()).length();
185+
camera.position.copy(center.clone().add(
186+
new THREE.Vector3(0.5, 0.25, 1).normalize().multiplyScalar(viewDistance)
187+
));
188+
189+
camera.near = viewDistance / 100;
190+
camera.far = viewDistance * 100;
191+
controls.update();
192+
camera.updateProjectionMatrix();
193+
camera.updateMatrixWorld();
194+
195+
var fovFactor = Math.tan(camera.fov / 2 / 180 * 3.141592653);
196+
var outside = 0.;
197+
198+
var largestAngle = 0.;
199+
for (var i = 0; i < 8; i++) {
200+
const v = new THREE.Vector3(
201+
i & 1 ? boundingBox.min.x : boundingBox.max.x,
202+
i & 2 ? boundingBox.min.y : boundingBox.max.y,
203+
i & 4 ? boundingBox.min.z : boundingBox.max.z
204+
);
205+
v.applyMatrix4(camera.matrixWorldInverse);
206+
outside = Math.max(outside, Math.abs(v.x / camera.aspect) - fovFactor * -v.z, Math.abs(v.y) - fovFactor * -v.z);
207+
}
208+
209+
viewDistance += outside * 2;
210+
211+
camera.position.copy(center.clone().add(
212+
new THREE.Vector3(0.5, 0.25, 1).normalize().multiplyScalar(viewDistance)
213+
));
214+
215+
controls.update();
216+
217+
function render() {
218+
requestAnimationFrame(render);
219+
renderer.render(scene, camera);
220+
}
221+
222+
render();
223+
download('test.ifc', model.to_string());
224+
}
225+
}
226+
main();
227+
</script>
228+
</body>
229+
</html>

0 commit comments

Comments
 (0)