Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

IFCLoader #20598

Merged
merged 10 commits into from
Mar 30, 2021
Merged

IFCLoader #20598

merged 10 commits into from
Mar 30, 2021

Conversation

agviegas
Copy link
Contributor

@agviegas agviegas commented Nov 1, 2020

I have started to develop an IFC parser in JS. Following mrdoob's advice, I'm doing the PR as a draft so you can see the progress from now on and direct the development to the final integration with Three.js.

The IFC format is used in BIM (Building Information Modelling) environments for the development of projects in the AECOM sector. Its fundamental use is to exchange models between software from different developers. It is similar to the glTF format in the 3D world, but specific to the construction sector. There is a growing demand for the use of open formats and the IFC is becoming increasingly relevant in real projects.

It should be noted that the IFC scheme is extensive and has a strong object orientation. The current code implements the models in the ifc-models folder reproducing the same inheritance lines to facilitate the loading of the data into memory.

The functionality is not yet finished, as it is a long work and this project is something I started some days ago. However, the core of the IFC entity parser and the reading of all the spatial structure entities of a project is already implemented. Hopefully this PR will help to get more contributors.

PD: Github is new to me, so I apologize for any lapses in etiquette.

@Mugen87
Copy link
Collaborator

Mugen87 commented Nov 1, 2020

AFAIK, IFC assets can be encoded in various formats. The most relevant are STEP and XML. The most important question to me is: How are you going to parse STEP?

I hope you are not going to develop a parser from scratch by yourself but use an existing parser building toolkit like chevrotain which is already used in VRMLLoader.

Besides, a standalone STEP parser would be more beneficial than an implementation which is directly embedded into IFCLoader since the parser could be useful for other purposes, too.

Finally, an IFC loader should be able to convert its supported formats (STEP, XML) into an intermediate JSON format which is then parsed to a three.js scene.

@agviegas
Copy link
Contributor Author

agviegas commented Nov 1, 2020

I completely agree. What I am implementing for now is the STEP parser. This is the first time I started a project of this kind and I was implementing the parser myself. I'm going to take a look at chevrotain.

While it is true that IFC has several formats, STEP is the only one in use in the industry right now. I am an architect and work with IFCs from various countries on a regular basis, and I have never come across an XML IFC. However, there may be a niche I don't know about. It may be more interesting to implement only the IFC SPF parser, at least for a start.

I will keep you informed of further developments.

@Mugen87
Copy link
Collaborator

Mugen87 commented Nov 1, 2020

While it is true that IFC has several formats, STEP is the only one in use in the industry right now.

I've heard in a discussion some time ago that IFC plans to support even more formats like JSON or HDF. Do you know how mature these approaches are?

BTW: Another idea that is worth to be investigated is to compile an existing (and thus robust) IFC library to WebAssembly and use it inside IFCLoader. In this way, no parsing logic needs to be developed and the performance is potentially better than JS code. DRACOLoader already uses such an approach.

@agviegas
Copy link
Contributor Author

agviegas commented Nov 1, 2020

In my opinion, the development of other formats such as JSON for IFC has no future in the short and medium term, mainly because the user profile of this type of format is an architect or engineer with no knowledge of programming. This means that the validity of an IFC implementation depends exclusively on the willingness of the large software houses to develop functional importers and exporters, and they generally favour the use of their proprietary formats.

For example, in many European countries and the United States the predominant software is Revit, whose interoperability with IFC is very limited, and does not promise much progress in this regard. And I would say that the problem here is not the technological limitation of IFC STEP versus other formats such as a possible IFC JSON, but the political will of AEC software developers.

In other words, the question for me is not what the IFC will support, but what the importers/exporters of the predominant software are willing to support. I work for a BIM software company in Europe, but obviously the market is wider and there may be other points of view.

I will also take a look at WebAssembly.

@mrdoob mrdoob added this to the r123 milestone Nov 1, 2020
@agviegas
Copy link
Contributor Author

agviegas commented Nov 6, 2020

I am checking in to give you some updates.

In the end I have chosen chevrotain as the tool to build the parser. The code is already capable of loading in memory a 2x3 IFC in the form of a JavaScript object, where the keys are the STEP format IDs and all the STEP data values have been converted to JS data types. As you can see in the image, the STEP references between entities have been parsed to references to the loaded entities.

There are still IFC classes to be implemented (I'm focusing on architecture, without entering into building systems / facilities) and also the additional properties that IFC 4 incorporates would be missing. However, I think it is advisable to get to the end of the process as soon as possible and show IFC architecture files. Then, completing the missing IFC classes and properties of IFC4 will simply extend the code patterns already defined.

Following the idea of @Mugen87 , I am organizing this in several decoupled parts. What is done for now is the IFC STEP PARSER. Next, I will organize the loaded entities into a data structure that is more convenient for reading. While it would be possible to read the objects as they are now (a JS reflect of the STEP file), the IFC format has a high degree of indirection, so this would require a lot of code. The usual in commercial IFC viewers is to use the spatial structure entities for this (IfcProject - IfcSite - IfcBuilding - IfcBuildingStorey - IfcSpace). Finally, once this structure is created, it will be easy to map the IFC geometry (which in most cases is defined as simple extrusion or explicit definition (B-rep) to Three.js geometry.

Have a nice weekend!

Captura

@haroldiedema
Copy link
Contributor

haroldiedema commented Nov 14, 2020

Wow, what a coincidence! 🤯

I'm building exactly this for a BIM viewer for my daily job. So far, I've written part of the STEP parser, but actually converting the geometry is out of my reach. So I've settled for a NodeJS server that'll accept an IFC file and export a DAE file (using existing IfcConvert binaries). Its not the solution I wanted, but it's something I can work with (for now).

Just wanted to give you some pointers on the STEP parser:

First of all, the order of ID references doesn't have to be in order. Meaning, you can't stream the file and just read/parse it line-by-line. Since the file sizes are generally really large, try to prevent using regular expressions as much as possible, since it'll degrate parsing performance significantly.

The $-signs are actually the equivalent of undefined, whereas a * denote an inherited "default" value (of a parent 'class').

See https://standards.buildingsmart.org/documents/Implementation/IFC2x_Model_Implementation_Guide_V2-0b.pdf for all the info you'd need for this.

Although it's not pretty, it's fast. Here's what I've come up with so far: https://gist.github.com/haroldiedema/bc8b10d48011aa76fac45dc46bdbf0f4

It produces a set of records in a Map<number, IfcRecord>, where IfcRecord is an object containing the name of the class and args in order (supports nested elements (arrays, lists, etc.)).

I really hope you get to finish this loader, it would make my life A LOT easier 😄

Keep it up!

@ikeough
Copy link

ikeough commented Nov 19, 2020

@agviegas I commend what you are doing, and I'm wondering how my company Hypar can help. We have a threejs based web application for generating building systems. We're primarily glTF-based, but we have a deep expertise with IFC as well. For example, we have an IFC4 parser generator toolkit that we use to build our C# IFC4 infrastructure and which could be used to build javascript or typescript. Check it out: https://github.com/hypar-io/IFC-gen. We'd definitely benefit from a drag and drop IFC loader on threejs.

@agviegas
Copy link
Contributor Author

@haroldiedema thanks for the pointers! The parser I have developed works similarly. In my case, every ifc class is defined as a sequence of syntactic building blocks.

@ikeough Thank you! So far I have written the parser using chevrotain, but this is decoupled from the other part of the code, so I will take a look into your library.

Anyone interested in this topic can take a look here to keep track of the project and maybe drop a PR with new ideas / refactorings.🙂 If so, you can take a look at the contribution guide.

By the way today I have finished the first version of the generation of IfcDoors. All THREE geometry is associated to the loaded IFC information, which means that creating filters by property (e. g. cathegory) is easy.

1aa97a10-5363-4481-aa19-9357dcca7ee9

@mrdoob
Copy link
Owner

mrdoob commented Nov 22, 2020

@agviegas Looking good!

@agviegas
Copy link
Contributor Author

agviegas commented Mar 1, 2021

Hey, sorry for this time without news. I've been working hard on this these months. The main problem was loading speed, as IFC files can be really large. However, @tomvandig has joined the project and has proposed a WASM implementation with a speed that is very close to native IFC viewers. You can find a deployed example here.

Right now we are making a wrapper so that this parser can be used as any other THREE Loader; this shouldn't take more than a few days (when it's ready, I'll update this Pull Request). You can check the advance of this here.

However, it should be noted that there is still work to be done; while the speed of the current implementation is very good and we are already able to load quite a few files, we are still implementing entities in the repository. Therefore, we think it's best to leave it up to you to decide when to merge this.

Any suggestions on this will be welcome!

@mrdoob
Copy link
Owner

mrdoob commented Mar 2, 2021

Having a work in progress loader in the repo sounds good to me.
Most of the loaders are work in progress anyway.

@agviegas
Copy link
Contributor Author

agviegas commented Mar 7, 2021

We have prepared the Loader both for js and for jsm. You can see its implementation and one example for each one here. The only caveat is that consumers of this loader must have the .WASM file in their deploy, but that is the price for almost native speed. If this looks good to you, we'll update the PR with the bundles.

@mrdoob
Copy link
Owner

mrdoob commented Mar 9, 2021

Sounds good to me yeah! 👍

@haroldiedema
Copy link
Contributor

"while the speed of the current implementation is very good and we are already able to load quite a few files"

I just tested this with a 90mb .ifc file and was expecting at least 5~10 seconds loading time. I blinked my eyes twice and it was there, fully rendered. Very very very nice accomplishment @agviegas and @tomvandig! Bravo! 👏 👏

@agviegas
Copy link
Contributor Author

I have updated the PR with the builds. Everything should be ready to merge. There's one last question though: the loaders depend on web-ifc code; specifically, the jsm example. The js example is already bundled, as it's supposed to be ready to be used directly as a script in the HTML. As I see it, we have three options:

  1. Adding the dependency to web-ifc, so that if anyone uses the IfcLoader using import, the code of web-ifc will be automatically bundled toguether with everything else.
  2. Bundling the jsm example to contain the necesary code from web-ifc.
  3. Adding a folder with the necesary files.

I personally think that option 1 is the best one because users need the wasm file as well. Adding the npm dependency would allow the users to always have the last version of all the code + wasm (e. g. if we make quick fixes, which is probably going to be a common situation in the beginning). Anyway, it's up to you!

@mrdoob
Copy link
Owner

mrdoob commented Mar 15, 2021

I prefer to include everything in the repo:
https://twitter.com/mrdoob/status/1347544804851408896

@agviegas
Copy link
Contributor Author

agviegas commented Mar 15, 2021

@mrdoob Done!

@mrdoob
Copy link
Owner

mrdoob commented Mar 16, 2021

Thanks for the clean up!

Are you planning on adding an example too or will you leave that for another PR?

@agviegas
Copy link
Contributor Author

Oh, I didn't know that we could also add an example. Where should I add it? Is there any specific requirement for it? Is one example enough or does it need to be one for js and another for jsm? I'm thinking on adding any of these.

@mrdoob
Copy link
Owner

mrdoob commented Mar 16, 2021

Yeah, the examples serve as introduction for people to use the new feature.

I think you can use the draco one as reference:

https://threejs.org/examples/#webgl_loader_draco

These are the steps:

  1. Duplicate https://github.com/mrdoob/three.js/blob/dev/examples/webgl_loader_draco.html
  2. Rename to webgl_loader_ifc.html
  3. Add a ifc file in examples/models/ifc/
  4. Change the example code with the new loader.
  5. Add the new file in files.json
  6. Run npm run make-screenshot webgl_loader_ifc.
  7. Push a new commit to the PR with the new files.

For new files we only add the jsm version, so no need to worry about the js version 👍

@agviegas
Copy link
Contributor Author

@mrdoob all done! Let me know if there's anything missing / incorrect. I tried the example locally and it works.

@mrdoob
Copy link
Owner

mrdoob commented Mar 16, 2021

I noticed you added examples/web-ifc.wasm. I guess IfcLoader needs a setDecoderPath too?

Also, just to stay consistent with the rest of the loaders it should be renamed to IFCLoader.

@agviegas
Copy link
Contributor Author

Yes, the WASM file needs to be in the same directory as the HTML (at least, this is how we could make it work). Is setDecoderPath a solution to this? I'll rename things now.

@mrdoob
Copy link
Owner

mrdoob commented Mar 16, 2021

Is setDecoderPath a solution to this?

Yeah, that's how DRACOLoader solved it.

@agviegas
Copy link
Contributor Author

agviegas commented Mar 18, 2021

@mrdoob I have changed the web-ifc.js WASM path reference. I found out that Draco's implementation was not trivial, and for that we would need to spend some time adapting the whole loader for it to work the same way. Do you think that the current solution is enough as a first version?

@mrdoob mrdoob marked this pull request as ready for review March 29, 2021 19:12
@mrdoob
Copy link
Owner

mrdoob commented Mar 29, 2021

One last change. For new files/loaders we only include the examples/jsm version.
So you can delete the examples/js version 👍

@mrdoob mrdoob merged commit 7c1f477 into mrdoob:dev Mar 30, 2021
@mrdoob
Copy link
Owner

mrdoob commented Mar 30, 2021

Yay! Thanks!

@mrdoob
Copy link
Owner

mrdoob commented Mar 30, 2021

By the way, I suspect you're using Windows. The file is still called IfcLoader.js.
I'll fix on my end 👍

@mrdoob
Copy link
Owner

mrdoob commented Mar 30, 2021

Here's the clean up: 02f4dff

@mrdoob
Copy link
Owner

mrdoob commented Mar 31, 2021

@agviegas there are a few issues you may want to take a look at:
https://lgtm.com/projects/g/mrdoob/three.js/?mode=list

@agviegas
Copy link
Contributor Author

@agviegas there are a few issues you may want to take a look at:
https://lgtm.com/projects/g/mrdoob/three.js/?mode=list

Sure, I'll take a look at them these days!

Comment on lines +167 to +169
setWindowTitle = function(title) {
document.title = title;
};
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this method is unused, but setting a document title as part of a library isn't a good idea imho.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey, I think this is part of the code that Emscripten generates automatically. We'll take a look to see if we can do something about it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants