IFCLoader.js 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884
  1. import {
  2. IFCRELAGGREGATES,
  3. IFCRELCONTAINEDINSPATIALSTRUCTURE,
  4. IFCRELDEFINESBYPROPERTIES,
  5. IFCRELDEFINESBYTYPE,
  6. IFCPROJECT,
  7. IfcAPI,
  8. } from "./ifc/web-ifc-api.js";
  9. import {
  10. BufferAttribute,
  11. BufferGeometry,
  12. Mesh,
  13. Matrix4,
  14. Color,
  15. MeshLambertMaterial,
  16. DoubleSide,
  17. Group,
  18. Loader,
  19. FileLoader,
  20. } from "../../../build/three.module.js";
  21. import { BufferGeometryUtils } from "../utils/BufferGeometryUtils.js";
  22. const IdAttrName = "expressID";
  23. const merge = (geoms, createGroups = false) => {
  24. return BufferGeometryUtils.mergeBufferGeometries(geoms, createGroups);
  25. };
  26. const newFloatAttr = (data, size) => {
  27. return new BufferAttribute(new Float32Array(data), size);
  28. };
  29. const newIntAttr = (data, size) => {
  30. return new BufferAttribute(new Uint32Array(data), size);
  31. };
  32. const DEFAULT = "default";
  33. const PropsNames = {
  34. aggregates: {
  35. name: IFCRELAGGREGATES,
  36. relating: "RelatingObject",
  37. related: "RelatedObjects",
  38. key: "children",
  39. },
  40. spatial: {
  41. name: IFCRELCONTAINEDINSPATIALSTRUCTURE,
  42. relating: "RelatingStructure",
  43. related: "RelatedElements",
  44. key: "children",
  45. },
  46. psets: {
  47. name: IFCRELDEFINESBYPROPERTIES,
  48. relating: "RelatingPropertyDefinition",
  49. related: "RelatedObjects",
  50. key: "hasPsets",
  51. },
  52. type: {
  53. name: IFCRELDEFINESBYTYPE,
  54. relating: "RelatingType",
  55. related: "RelatedObjects",
  56. key: "hasType",
  57. },
  58. };
  59. class IFCParser {
  60. constructor(state) {
  61. this.currentID = -1;
  62. this.state = state;
  63. }
  64. async parse(buffer) {
  65. if (this.state.api.wasmModule === undefined) await this.state.api.Init();
  66. this.currentID = this.newIfcModel(buffer);
  67. return this.loadAllGeometry();
  68. }
  69. initializeMeshBVH(computeBoundsTree, disposeBoundsTree, acceleratedRaycast) {
  70. this.computeBoundsTree = computeBoundsTree;
  71. this.disposeBoundsTree = disposeBoundsTree;
  72. this.acceleratedRaycast = acceleratedRaycast;
  73. this.setupThreeMeshBVH();
  74. }
  75. setupThreeMeshBVH() {
  76. if (
  77. !this.computeBoundsTree ||
  78. !this.disposeBoundsTree ||
  79. !this.acceleratedRaycast
  80. )
  81. return;
  82. BufferGeometry.prototype.computeBoundsTree = this.computeBoundsTree;
  83. BufferGeometry.prototype.disposeBoundsTree = this.disposeBoundsTree;
  84. Mesh.prototype.raycast = this.acceleratedRaycast;
  85. }
  86. applyThreeMeshBVH(geometry) {
  87. if (this.computeBoundsTree) geometry.computeBoundsTree();
  88. }
  89. newIfcModel(buffer) {
  90. const data = new Uint8Array(buffer);
  91. const modelID = this.state.api.OpenModel(data);
  92. this.state.models[modelID] = {
  93. modelID,
  94. mesh: {},
  95. items: {},
  96. types: {},
  97. };
  98. return modelID;
  99. }
  100. loadAllGeometry() {
  101. this.saveAllPlacedGeometriesByMaterial();
  102. return this.generateAllGeometriesByMaterial();
  103. }
  104. generateAllGeometriesByMaterial() {
  105. const { geometry, materials } = this.getGeometryAndMaterials();
  106. this.applyThreeMeshBVH(geometry);
  107. const mesh = new Mesh(geometry, materials);
  108. mesh.modelID = this.currentID;
  109. this.state.models[this.currentID].mesh = mesh;
  110. return mesh;
  111. }
  112. getGeometryAndMaterials() {
  113. const items = this.state.models[this.currentID].items;
  114. const mergedByMaterial = [];
  115. const materials = [];
  116. for (let materialID in items) {
  117. materials.push(items[materialID].material);
  118. const geometries = Object.values(items[materialID].geometries);
  119. mergedByMaterial.push(merge(geometries));
  120. }
  121. const geometry = merge(mergedByMaterial, true);
  122. return {
  123. geometry,
  124. materials,
  125. };
  126. }
  127. saveAllPlacedGeometriesByMaterial() {
  128. const flatMeshes = this.state.api.LoadAllGeometry(this.currentID);
  129. for (let i = 0; i < flatMeshes.size(); i++) {
  130. const flatMesh = flatMeshes.get(i);
  131. const placedGeom = flatMesh.geometries;
  132. for (let j = 0; j < placedGeom.size(); j++) {
  133. this.savePlacedGeometry(placedGeom.get(j), flatMesh.expressID);
  134. }
  135. }
  136. }
  137. savePlacedGeometry(placedGeometry, id) {
  138. const geometry = this.getBufferGeometry(placedGeometry);
  139. geometry.computeVertexNormals();
  140. const matrix = this.getMeshMatrix(placedGeometry.flatTransformation);
  141. geometry.applyMatrix4(matrix);
  142. this.saveGeometryByMaterial(geometry, placedGeometry, id);
  143. }
  144. getBufferGeometry(placed) {
  145. const geometry = this.state.api.GetGeometry(
  146. this.currentID,
  147. placed.geometryExpressID
  148. );
  149. const vertexData = this.getVertices(geometry);
  150. const indices = this.getIndices(geometry);
  151. const { vertices, normals } = this.extractVertexData(vertexData);
  152. return this.ifcGeomToBufferGeom(vertices, normals, indices);
  153. }
  154. getVertices(geometry) {
  155. const vData = geometry.GetVertexData();
  156. const vDataSize = geometry.GetVertexDataSize();
  157. return this.state.api.GetVertexArray(vData, vDataSize);
  158. }
  159. getIndices(geometry) {
  160. const iData = geometry.GetIndexData();
  161. const iDataSize = geometry.GetIndexDataSize();
  162. return this.state.api.GetIndexArray(iData, iDataSize);
  163. }
  164. getMeshMatrix(matrix) {
  165. const mat = new Matrix4();
  166. mat.fromArray(matrix);
  167. return mat;
  168. }
  169. ifcGeomToBufferGeom(vertices, normals, indexData) {
  170. const geometry = new BufferGeometry();
  171. geometry.setAttribute("position", newFloatAttr(vertices, 3));
  172. geometry.setAttribute("normal", newFloatAttr(normals, 3));
  173. geometry.setIndex(new BufferAttribute(indexData, 1));
  174. return geometry;
  175. }
  176. extractVertexData(vertexData) {
  177. const vertices = [];
  178. const normals = [];
  179. let isNormalData = false;
  180. for (let i = 0; i < vertexData.length; i++) {
  181. isNormalData ? normals.push(vertexData[i]) : vertices.push(vertexData[i]);
  182. if ((i + 1) % 3 == 0) isNormalData = !isNormalData;
  183. }
  184. return {
  185. vertices,
  186. normals,
  187. };
  188. }
  189. saveGeometryByMaterial(geom, placedGeom, id) {
  190. const color = placedGeom.color;
  191. const colorID = `${color.x}${color.y}${color.z}${color.w}`;
  192. this.storeGeometryAttribute(id, geom);
  193. this.createMaterial(colorID, color);
  194. const item = this.state.models[this.currentID].items[colorID];
  195. const currentGeom = item.geometries[id];
  196. if (!currentGeom) return (item.geometries[id] = geom);
  197. const merged = merge([currentGeom, geom]);
  198. item.geometries[id] = merged;
  199. }
  200. storeGeometryAttribute(id, geometry) {
  201. const size = geometry.attributes.position.count;
  202. const idAttribute = new Array(size).fill(id);
  203. geometry.setAttribute(IdAttrName, newIntAttr(idAttribute, 1));
  204. }
  205. createMaterial(colorID, color) {
  206. const items = this.state.models[this.currentID].items;
  207. if (items[colorID]) return;
  208. const col = new Color(color.x, color.y, color.z);
  209. const newMaterial = new MeshLambertMaterial({
  210. color: col,
  211. side: DoubleSide,
  212. });
  213. newMaterial.transparent = color.w !== 1;
  214. if (newMaterial.transparent) newMaterial.opacity = color.w;
  215. items[colorID] = {
  216. material: newMaterial,
  217. geometries: {},
  218. };
  219. }
  220. }
  221. class SubsetManager {
  222. constructor(state) {
  223. this.state = state;
  224. this.selected = {};
  225. }
  226. getSubset(modelID, material) {
  227. const currentMat = this.matIDNoConfig(modelID, material);
  228. if (!this.selected[currentMat]) return null;
  229. return this.selected[currentMat].mesh;
  230. }
  231. removeSubset(modelID, scene, material) {
  232. const currentMat = this.matIDNoConfig(modelID, material);
  233. if (!this.selected[currentMat]) return;
  234. if (scene) scene.remove(this.selected[currentMat].mesh);
  235. delete this.selected[currentMat];
  236. }
  237. createSubset(config) {
  238. if (!this.isConfigValid(config)) return;
  239. if (this.isPreviousSelection(config)) return;
  240. if (this.isEasySelection(config))
  241. return this.addToPreviousSelection(config);
  242. this.updatePreviousSelection(config.scene, config);
  243. return this.createSelectionInScene(config);
  244. }
  245. createSelectionInScene(config) {
  246. const filtered = this.filter(config);
  247. const { geomsByMaterial, materials } = this.getGeomAndMat(filtered);
  248. const hasDefaultMaterial = this.matID(config) == DEFAULT;
  249. const geometry = merge(geomsByMaterial, hasDefaultMaterial);
  250. const mats = hasDefaultMaterial ? materials : config.material;
  251. const mesh = new Mesh(geometry, mats);
  252. this.selected[this.matID(config)].mesh = mesh;
  253. mesh.modelID = config.modelID;
  254. config.scene.add(mesh);
  255. return mesh;
  256. }
  257. isConfigValid(config) {
  258. return (
  259. this.isValid(config.scene) &&
  260. this.isValid(config.modelID) &&
  261. this.isValid(config.ids) &&
  262. this.isValid(config.removePrevious)
  263. );
  264. }
  265. isValid(item) {
  266. return item != undefined && item != null;
  267. }
  268. getGeomAndMat(filtered) {
  269. const geomsByMaterial = [];
  270. const materials = [];
  271. for (let matID in filtered) {
  272. const geoms = Object.values(filtered[matID].geometries);
  273. if (!geoms.length) continue;
  274. materials.push(filtered[matID].material);
  275. if (geoms.length > 1) geomsByMaterial.push(merge(geoms));
  276. else geomsByMaterial.push(...geoms);
  277. }
  278. return {
  279. geomsByMaterial,
  280. materials,
  281. };
  282. }
  283. updatePreviousSelection(scene, config) {
  284. const previous = this.selected[this.matID(config)];
  285. if (!previous) return this.newSelectionGroup(config);
  286. scene.remove(previous.mesh);
  287. config.removePrevious
  288. ? (previous.ids = new Set(config.ids))
  289. : config.ids.forEach((id) => previous.ids.add(id));
  290. }
  291. newSelectionGroup(config) {
  292. this.selected[this.matID(config)] = {
  293. ids: new Set(config.ids),
  294. mesh: {},
  295. };
  296. }
  297. isPreviousSelection(config) {
  298. if (!this.selected[this.matID(config)]) return false;
  299. if (this.containsIds(config)) return true;
  300. const previousIds = this.selected[this.matID(config)].ids;
  301. return JSON.stringify(config.ids) === JSON.stringify(previousIds);
  302. }
  303. containsIds(config) {
  304. const newIds = config.ids;
  305. const previous = Array.from(this.selected[this.matID(config)].ids);
  306. return newIds.every(
  307. (
  308. (i) => (v) =>
  309. (i = previous.indexOf(v, i) + 1)
  310. )(0)
  311. );
  312. }
  313. addToPreviousSelection(config) {
  314. const previous = this.selected[this.matID(config)];
  315. const filtered = this.filter(config);
  316. const geometries = Object.values(filtered)
  317. .map((i) => Object.values(i.geometries))
  318. .flat();
  319. const previousGeom = previous.mesh.geometry;
  320. previous.mesh.geometry = merge([previousGeom, ...geometries]);
  321. config.ids.forEach((id) => previous.ids.add(id));
  322. }
  323. filter(config) {
  324. const items = this.state.models[config.modelID].items;
  325. const filtered = {};
  326. for (let matID in items) {
  327. filtered[matID] = {
  328. material: items[matID].material,
  329. geometries: this.filterGeometries(
  330. new Set(config.ids),
  331. items[matID].geometries
  332. ),
  333. };
  334. }
  335. return filtered;
  336. }
  337. filterGeometries(selectedIDs, geometries) {
  338. const ids = Array.from(selectedIDs);
  339. return Object.keys(geometries)
  340. .filter((key) => ids.includes(parseInt(key, 10)))
  341. .reduce((obj, key) => {
  342. return {
  343. ...obj,
  344. [key]: geometries[key],
  345. };
  346. }, {});
  347. }
  348. isEasySelection(config) {
  349. const matID = this.matID(config);
  350. const def = this.matIDNoConfig(config.modelID);
  351. if (!config.removePrevious && matID != def && this.selected[matID])
  352. return true;
  353. }
  354. matID(config) {
  355. if (!config.material) return DEFAULT;
  356. const name = config.material.uuid || DEFAULT;
  357. return name.concat(" - ").concat(config.modelID.toString());
  358. }
  359. matIDNoConfig(modelID, material) {
  360. let name = DEFAULT;
  361. if (material) name = material.uuid;
  362. return name.concat(" - ").concat(modelID.toString());
  363. }
  364. }
  365. const IfcElements = {
  366. 103090709: "IFCPROJECT",
  367. 4097777520: "IFCSITE",
  368. 4031249490: "IFCBUILDING",
  369. 3124254112: "IFCBUILDINGSTOREY",
  370. 3856911033: "IFCSPACE",
  371. 25142252: "IFCCONTROLLER",
  372. 32344328: "IFCBOILER",
  373. 76236018: "IFCLAMP",
  374. 90941305: "IFCPUMP",
  375. 177149247: "IFCAIRTERMINALBOX",
  376. 182646315: "IFCFLOWINSTRUMENT",
  377. 263784265: "IFCFURNISHINGELEMENT",
  378. 264262732: "IFCELECTRICGENERATOR",
  379. 277319702: "IFCAUDIOVISUALAPPLIANCE",
  380. 310824031: "IFCPIPEFITTING",
  381. 331165859: "IFCSTAIR",
  382. 342316401: "IFCDUCTFITTING",
  383. 377706215: "IFCMECHANICALFASTENER",
  384. 395920057: "IFCDOOR",
  385. 402227799: "IFCELECTRICMOTOR",
  386. 413509423: "IFCSYSTEMFURNITUREELEMENT",
  387. 484807127: "IFCEVAPORATOR",
  388. 486154966: "IFCWINDOWSTANDARDCASE",
  389. 629592764: "IFCLIGHTFIXTURE",
  390. 630975310: "IFCUNITARYCONTROLELEMENT",
  391. 635142910: "IFCCABLECARRIERFITTING",
  392. 639361253: "IFCCOIL",
  393. 647756555: "IFCFASTENER",
  394. 707683696: "IFCFLOWSTORAGEDEVICE",
  395. 738039164: "IFCPROTECTIVEDEVICE",
  396. 753842376: "IFCBEAM",
  397. 812556717: "IFCTANK",
  398. 819412036: "IFCFILTER",
  399. 843113511: "IFCCOLUMN",
  400. 862014818: "IFCELECTRICDISTRIBUTIONBOARD",
  401. 900683007: "IFCFOOTING",
  402. 905975707: "IFCCOLUMNSTANDARDCASE",
  403. 926996030: "IFCVOIDINGFEATURE",
  404. 979691226: "IFCREINFORCINGBAR",
  405. 987401354: "IFCFLOWSEGMENT",
  406. 1003880860: "IFCELECTRICTIMECONTROL",
  407. 1051757585: "IFCCABLEFITTING",
  408. 1052013943: "IFCDISTRIBUTIONCHAMBERELEMENT",
  409. 1062813311: "IFCDISTRIBUTIONCONTROLELEMENT",
  410. 1073191201: "IFCMEMBER",
  411. 1095909175: "IFCBUILDINGELEMENTPROXY",
  412. 1156407060: "IFCPLATESTANDARDCASE",
  413. 1162798199: "IFCSWITCHINGDEVICE",
  414. 1329646415: "IFCSHADINGDEVICE",
  415. 1335981549: "IFCDISCRETEACCESSORY",
  416. 1360408905: "IFCDUCTSILENCER",
  417. 1404847402: "IFCSTACKTERMINAL",
  418. 1426591983: "IFCFIRESUPPRESSIONTERMINAL",
  419. 1437502449: "IFCMEDICALDEVICE",
  420. 1509553395: "IFCFURNITURE",
  421. 1529196076: "IFCSLAB",
  422. 1620046519: "IFCTRANSPORTELEMENT",
  423. 1634111441: "IFCAIRTERMINAL",
  424. 1658829314: "IFCENERGYCONVERSIONDEVICE",
  425. 1677625105: "IFCCIVILELEMENT",
  426. 1687234759: "IFCPILE",
  427. 1904799276: "IFCELECTRICAPPLIANCE",
  428. 1911478936: "IFCMEMBERSTANDARDCASE",
  429. 1945004755: "IFCDISTRIBUTIONELEMENT",
  430. 1973544240: "IFCCOVERING",
  431. 1999602285: "IFCSPACEHEATER",
  432. 2016517767: "IFCROOF",
  433. 2056796094: "IFCAIRTOAIRHEATRECOVERY",
  434. 2058353004: "IFCFLOWCONTROLLER",
  435. 2068733104: "IFCHUMIDIFIER",
  436. 2176052936: "IFCJUNCTIONBOX",
  437. 2188021234: "IFCFLOWMETER",
  438. 2223149337: "IFCFLOWTERMINAL",
  439. 2262370178: "IFCRAILING",
  440. 2272882330: "IFCCONDENSER",
  441. 2295281155: "IFCPROTECTIVEDEVICETRIPPINGUNIT",
  442. 2320036040: "IFCREINFORCINGMESH",
  443. 2347447852: "IFCTENDONANCHOR",
  444. 2391383451: "IFCVIBRATIONISOLATOR",
  445. 2391406946: "IFCWALL",
  446. 2474470126: "IFCMOTORCONNECTION",
  447. 2769231204: "IFCVIRTUALELEMENT",
  448. 2814081492: "IFCENGINE",
  449. 2906023776: "IFCBEAMSTANDARDCASE",
  450. 2938176219: "IFCBURNER",
  451. 2979338954: "IFCBUILDINGELEMENTPART",
  452. 3024970846: "IFCRAMP",
  453. 3026737570: "IFCTUBEBUNDLE",
  454. 3027962421: "IFCSLABSTANDARDCASE",
  455. 3040386961: "IFCDISTRIBUTIONFLOWELEMENT",
  456. 3053780830: "IFCSANITARYTERMINAL",
  457. 3079942009: "IFCOPENINGSTANDARDCASE",
  458. 3087945054: "IFCALARM",
  459. 3101698114: "IFCSURFACEFEATURE",
  460. 3127900445: "IFCSLABELEMENTEDCASE",
  461. 3132237377: "IFCFLOWMOVINGDEVICE",
  462. 3171933400: "IFCPLATE",
  463. 3221913625: "IFCCOMMUNICATIONSAPPLIANCE",
  464. 3242481149: "IFCDOORSTANDARDCASE",
  465. 3283111854: "IFCRAMPFLIGHT",
  466. 3296154744: "IFCCHIMNEY",
  467. 3304561284: "IFCWINDOW",
  468. 3310460725: "IFCELECTRICFLOWSTORAGEDEVICE",
  469. 3319311131: "IFCHEATEXCHANGER",
  470. 3415622556: "IFCFAN",
  471. 3420628829: "IFCSOLARDEVICE",
  472. 3493046030: "IFCGEOGRAPHICELEMENT",
  473. 3495092785: "IFCCURTAINWALL",
  474. 3508470533: "IFCFLOWTREATMENTDEVICE",
  475. 3512223829: "IFCWALLSTANDARDCASE",
  476. 3518393246: "IFCDUCTSEGMENT",
  477. 3571504051: "IFCCOMPRESSOR",
  478. 3588315303: "IFCOPENINGELEMENT",
  479. 3612865200: "IFCPIPESEGMENT",
  480. 3640358203: "IFCCOOLINGTOWER",
  481. 3651124850: "IFCPROJECTIONELEMENT",
  482. 3694346114: "IFCOUTLET",
  483. 3747195512: "IFCEVAPORATIVECOOLER",
  484. 3758799889: "IFCCABLECARRIERSEGMENT",
  485. 3824725483: "IFCTENDON",
  486. 3825984169: "IFCTRANSFORMER",
  487. 3902619387: "IFCCHILLER",
  488. 4074379575: "IFCDAMPER",
  489. 4086658281: "IFCSENSOR",
  490. 4123344466: "IFCELEMENTASSEMBLY",
  491. 4136498852: "IFCCOOLEDBEAM",
  492. 4156078855: "IFCWALLELEMENTEDCASE",
  493. 4175244083: "IFCINTERCEPTOR",
  494. 4207607924: "IFCVALVE",
  495. 4217484030: "IFCCABLESEGMENT",
  496. 4237592921: "IFCWASTETERMINAL",
  497. 4252922144: "IFCSTAIRFLIGHT",
  498. 4278956645: "IFCFLOWFITTING",
  499. 4288193352: "IFCACTUATOR",
  500. 4292641817: "IFCUNITARYEQUIPMENT",
  501. };
  502. class PropertyManager {
  503. constructor(state) {
  504. this.state = state;
  505. }
  506. getExpressId(geometry, faceIndex) {
  507. if (!geometry.index) return;
  508. const geoIndex = geometry.index.array;
  509. return geometry.attributes[IdAttrName].getX(geoIndex[3 * faceIndex]);
  510. }
  511. getItemProperties(modelID, id, recursive = false) {
  512. return this.state.api.GetLine(modelID, id, recursive);
  513. }
  514. getAllItemsOfType(modelID, type, verbose) {
  515. const items = [];
  516. const lines = this.state.api.GetLineIDsWithType(modelID, type);
  517. for (let i = 0; i < lines.size(); i++) items.push(lines.get(i));
  518. if (verbose) return items.map((id) => this.state.api.GetLine(modelID, id));
  519. return items;
  520. }
  521. getPropertySets(modelID, elementID, recursive = false) {
  522. const propSetIds = this.getAllRelatedItemsOfType(
  523. modelID,
  524. elementID,
  525. PropsNames.psets
  526. );
  527. return propSetIds.map((id) =>
  528. this.state.api.GetLine(modelID, id, recursive)
  529. );
  530. }
  531. getTypeProperties(modelID, elementID, recursive = false) {
  532. const typeId = this.getAllRelatedItemsOfType(
  533. modelID,
  534. elementID,
  535. PropsNames.type
  536. );
  537. return typeId.map((id) => this.state.api.GetLine(modelID, id, recursive));
  538. }
  539. getSpatialStructure(modelID) {
  540. const chunks = this.getSpatialTreeChunks(modelID);
  541. const projectID = this.state.api
  542. .GetLineIDsWithType(modelID, IFCPROJECT)
  543. .get(0);
  544. const project = this.newIfcProject(projectID);
  545. this.getSpatialNode(modelID, project, chunks);
  546. return project;
  547. }
  548. newIfcProject(id) {
  549. return {
  550. expressID: id,
  551. type: "IFCPROJECT",
  552. children: [],
  553. };
  554. }
  555. getSpatialTreeChunks(modelID) {
  556. const treeChunks = {};
  557. this.getChunks(modelID, treeChunks, PropsNames.aggregates);
  558. this.getChunks(modelID, treeChunks, PropsNames.spatial);
  559. return treeChunks;
  560. }
  561. getChunks(modelID, chunks, propNames) {
  562. const relation = this.state.api.GetLineIDsWithType(modelID, propNames.name);
  563. for (let i = 0; i < relation.size(); i++) {
  564. const rel = this.state.api.GetLine(modelID, relation.get(i), false);
  565. const relating = rel[propNames.relating].value;
  566. const related = rel[propNames.related].map((r) => r.value);
  567. if (chunks[relating] == undefined) {
  568. chunks[relating] = related;
  569. } else {
  570. chunks[relating] = chunks[relating].concat(related);
  571. }
  572. }
  573. }
  574. getSpatialNode(modelID, node, treeChunks) {
  575. this.getChildren(modelID, node, treeChunks, PropsNames.aggregates);
  576. this.getChildren(modelID, node, treeChunks, PropsNames.spatial);
  577. }
  578. getChildren(modelID, node, treeChunks, propNames) {
  579. const children = treeChunks[node.expressID];
  580. if (children == undefined || children == null) return;
  581. const prop = propNames.key;
  582. node[prop] = children.map((child) => {
  583. const node = this.newNode(modelID, child);
  584. this.getSpatialNode(modelID, node, treeChunks);
  585. return node;
  586. });
  587. }
  588. newNode(modelID, id) {
  589. const typeID = this.state.models[modelID].types[id].toString();
  590. const typeName = IfcElements[typeID];
  591. return {
  592. expressID: id,
  593. type: typeName,
  594. children: [],
  595. };
  596. }
  597. getAllRelatedItemsOfType(modelID, id, propNames) {
  598. const lines = this.state.api.GetLineIDsWithType(modelID, propNames.name);
  599. const IDs = [];
  600. for (let i = 0; i < lines.size(); i++) {
  601. const rel = this.state.api.GetLine(modelID, lines.get(i));
  602. const isRelated = this.isRelated(id, rel, propNames);
  603. if (isRelated) this.getRelated(rel, propNames, IDs);
  604. }
  605. return IDs;
  606. }
  607. getRelated(rel, propNames, IDs) {
  608. const element = rel[propNames.relating];
  609. if (!Array.isArray(element)) IDs.push(element.value);
  610. else element.forEach((ele) => IDs.push(ele.value));
  611. }
  612. isRelated(id, rel, propNames) {
  613. const relatedItems = rel[propNames.related];
  614. if (Array.isArray(relatedItems)) {
  615. const values = relatedItems.map((item) => item.value);
  616. return values.includes(id);
  617. }
  618. return relatedItems.value === id;
  619. }
  620. }
  621. class TypeManager {
  622. constructor(state) {
  623. this.state = state;
  624. }
  625. getAllTypes() {
  626. for (let modelID in this.state.models) {
  627. const types = this.state.models[modelID].types;
  628. if (Object.keys(types).length == 0)
  629. this.getAllTypesOfModel(parseInt(modelID));
  630. }
  631. }
  632. getAllTypesOfModel(modelID) {
  633. this.state.models[modelID].types;
  634. const elements = Object.keys(IfcElements).map((e) => parseInt(e));
  635. const types = this.state.models[modelID].types;
  636. elements.forEach((type) => {
  637. const lines = this.state.api.GetLineIDsWithType(modelID, type);
  638. for (let i = 0; i < lines.size(); i++) types[lines.get(i)] = type;
  639. });
  640. }
  641. }
  642. let modelIdCounter = 0;
  643. class IFCModel extends Group {
  644. constructor(mesh, ifc) {
  645. super();
  646. this.mesh = mesh;
  647. this.ifc = ifc;
  648. this.modelID = modelIdCounter++;
  649. }
  650. setWasmPath(path) {
  651. this.ifc.setWasmPath(path);
  652. }
  653. close(scene) {
  654. this.ifc.close(this.modelID, scene);
  655. }
  656. getExpressId(geometry, faceIndex) {
  657. return this.ifc.getExpressId(geometry, faceIndex);
  658. }
  659. getAllItemsOfType(type, verbose) {
  660. return this.ifc.getAllItemsOfType(this.modelID, type, verbose);
  661. }
  662. getItemProperties(id, recursive = false) {
  663. return this.ifc.getItemProperties(this.modelID, id, recursive);
  664. }
  665. getPropertySets(id, recursive = false) {
  666. return this.ifc.getPropertySets(this.modelID, id, recursive);
  667. }
  668. getTypeProperties(id, recursive = false) {
  669. return this.ifc.getTypeProperties(this.modelID, id, recursive);
  670. }
  671. getIfcType(id) {
  672. return this.ifc.getIfcType(this.modelID, id);
  673. }
  674. getSpatialStructure() {
  675. return this.ifc.getSpatialStructure(this.modelID);
  676. }
  677. getSubset(material) {
  678. return this.ifc.getSubset(this.modelID, material);
  679. }
  680. removeSubset(scene, material) {
  681. this.ifc.removeSubset(this.modelID, scene, material);
  682. }
  683. createSubset(config) {
  684. const modelConfig = {
  685. ...config,
  686. modelID: this.modelID,
  687. };
  688. return this.ifc.createSubset(modelConfig);
  689. }
  690. }
  691. class IFCManager {
  692. constructor() {
  693. this.state = {
  694. models: [],
  695. api: new IfcAPI(),
  696. };
  697. this.parser = new IFCParser(this.state);
  698. this.subsets = new SubsetManager(this.state);
  699. this.properties = new PropertyManager(this.state);
  700. this.types = new TypeManager(this.state);
  701. }
  702. async parse(buffer) {
  703. const mesh = await this.parser.parse(buffer);
  704. this.types.getAllTypes();
  705. return new IFCModel(mesh, this);
  706. }
  707. setWasmPath(path) {
  708. this.state.api.SetWasmPath(path);
  709. }
  710. setupThreeMeshBVH(computeBoundsTree, disposeBoundsTree, acceleratedRaycast) {
  711. this.parser.initializeMeshBVH(
  712. computeBoundsTree,
  713. disposeBoundsTree,
  714. acceleratedRaycast
  715. );
  716. }
  717. close(modelID, scene) {
  718. this.state.api.CloseModel(modelID);
  719. if (scene) scene.remove(this.state.models[modelID].mesh);
  720. delete this.state.models[modelID];
  721. }
  722. getExpressId(geometry, faceIndex) {
  723. return this.properties.getExpressId(geometry, faceIndex);
  724. }
  725. getAllItemsOfType(modelID, type, verbose) {
  726. return this.properties.getAllItemsOfType(modelID, type, verbose);
  727. }
  728. getItemProperties(modelID, id, recursive = false) {
  729. return this.properties.getItemProperties(modelID, id, recursive);
  730. }
  731. getPropertySets(modelID, id, recursive = false) {
  732. return this.properties.getPropertySets(modelID, id, recursive);
  733. }
  734. getTypeProperties(modelID, id, recursive = false) {
  735. return this.properties.getTypeProperties(modelID, id, recursive);
  736. }
  737. getIfcType(modelID, id) {
  738. const typeID = this.state.models[modelID].types[id];
  739. return IfcElements[typeID.toString()];
  740. }
  741. getSpatialStructure(modelID) {
  742. return this.properties.getSpatialStructure(modelID);
  743. }
  744. getSubset(modelID, material) {
  745. return this.subsets.getSubset(modelID, material);
  746. }
  747. removeSubset(modelID, scene, material) {
  748. this.subsets.removeSubset(modelID, scene, material);
  749. }
  750. createSubset(config) {
  751. return this.subsets.createSubset(config);
  752. }
  753. }
  754. class IFCLoader extends Loader {
  755. constructor(manager) {
  756. super(manager);
  757. this.ifcManager = new IFCManager();
  758. }
  759. load(url, onLoad, onProgress, onError) {
  760. const scope = this;
  761. const loader = new FileLoader(scope.manager);
  762. loader.setPath(scope.path);
  763. loader.setResponseType("arraybuffer");
  764. loader.setRequestHeader(scope.requestHeader);
  765. loader.setWithCredentials(scope.withCredentials);
  766. loader.load(
  767. url,
  768. async function (buffer) {
  769. try {
  770. if (typeof buffer == "string") {
  771. throw new Error("IFC files must be given as a buffer!");
  772. }
  773. onLoad(await scope.parse(buffer));
  774. } catch (e) {
  775. if (onError) {
  776. onError(e);
  777. } else {
  778. console.error(e);
  779. }
  780. scope.manager.itemError(url);
  781. }
  782. },
  783. onProgress,
  784. onError
  785. );
  786. }
  787. parse(buffer) {
  788. return this.ifcManager.parse(buffer);
  789. }
  790. }
  791. export { IFCLoader };
  792. //# sourceMappingURL=IFCLoader.js.map