xeokit / xeokit-convert

Convert various AEC model formats for efficient viewing in the browser with xeokit.
https://xeokit.github.io/xeokit-convert/docs/
Other
50 stars 53 forks source link

IFCSpace in xkt v9 #33

Closed DB-EC-Hamburg-BIM closed 2 years ago

DB-EC-Hamburg-BIM commented 2 years ago

I have problems with IFCSpace when I convert IFC files in xkt v9. A metamodel is created, but there are no entity or “normal” objects created in the viewer. I also downloaded the example xkt files “Duplex.ifc.xkt” in version v8 (https://github.com/xeokit/xeokit-sdk/blob/master/assets/models/xkt/v8/ifc/Duplex.ifc.xkt) and v9 (https://github.com/xeokit/xeokit-sdk/blob/master/assets/models/xkt/v9/ifc/Duplex.ifc.xkt) to check my problem. When I load the v8 into the viewer I get the IFCSpaces (as visible entities) but in the v9 not (only metamodels).

xeolabs commented 2 years ago

Hi, sorry for the delay! I just tested the Duplex model with the latest tools and I seem to be getting some IfcSpaces.

Note that I've just tested using the Creoox IFC->glTF converter (ifc2gltf) so far.

I will test using IfcConvert next.

Here's the versions of the tools I tested with so far:

I converted the IFC to glTF and metadata JSON, using ifc2gltf:

ifc2gltf -i Duplex.ifc -o Duplex.ifc.glb -m Duplex.ifc.json
-- IFC to GLTF converter ---------------------
Converting file Duplex.ifc
Loading IFC model from file: 
numVerticesPerCircle: 14
Converting IFC geometry: 
Exporting to gltf: 
num coord accessors: 240, reused: 183
num indices accessors: 30, reused: 393
 done in 0 seconds

Then I converted the glTF and metadata files to XKT v10 using convert2xkt:

node convert2xkt.js -s Duplex.ifc.glb -m Duplex.ifc.json -o Duplex.ifc.glb.xkt  -l
[convert2xkt] Running convert2xkt v1.1.0-alpha-10...
[convert2xkt] Reading input file: Duplex.ifc.glb
[convert2xkt] Input file size: 656.68 kB
[convert2xkt] Reading input metadata file: Duplex.ifc.json
[convert2xkt] Using parser: parseGLTFIntoXKTModel
[convert2xkt] Parsing normals: enabled
[convert2xkt] Parsing textures: enabled
[convert2xkt] Input file parsed OK. Building XKT document...
[convert2xkt] XKT document built OK. Writing to XKT file...
[convert2xkt] Converted to: XKT v10
[convert2xkt] XKT size: 189.07 kB
[convert2xkt] XKT textures size: 0.01kB
[convert2xkt] Compression ratio: 3.47
[convert2xkt] Conversion time: 0.51 s
[convert2xkt] Converted metaobjects: 0
[convert2xkt] Converted property sets: 0
[convert2xkt] Converted drawable objects: 212
[convert2xkt] Converted geometries: 423
[convert2xkt] Converted textures: 0
[convert2xkt] Converted textureSets: 0
[convert2xkt] Converted triangles: 25405
[convert2xkt] Converted vertices: 76215
[convert2xkt] Converted UVs: 0
[convert2xkt] Converted normals: 0
[convert2xkt] minTileSize: 200
[convert2xkt] Writing XKT file: Duplex.ifc.glb.xkt
[convert2xkt] Done.

Then I substituted that XKT for the Duplex model in xeokit-bim-viewer, and loaded that model:

Screenshot from 2022-08-10 11-33-57

Then using the explorer, I showed only the IfcSpace types, and also enabled the "Show Spaces" mode (see the cube-icon button at the top right):

Screenshot from 2022-08-10 11-33-40

xeolabs commented 2 years ago

I just tested the Duplex model with our open source tools on Ubuntu - seems the spaces are showing for this model at least.

Converting from IFC->glTF:

IfcConvert Duplex.ifc Duplex.ifc.IfcConvert.glb
IfcOpenShell IfcConvert v0.7.0-e508fb44 (OCC 7.5.3)
Scanning file...
Done scanning file   
Parsing input file took 0 seconds
Creating geometry...
Done creating geometry (205 objects)                                

Conversion took 2 seconds

Converting IFC -> JSON metadata with xeokit-metadata:

xeokit-metadata Duplex.ifc Duplex.ifc.xeokit-metadata.json

Converting glTF+JSON -> XKT with convert2xkt:

node convert2xkt.js -s Duplex.ifc.IfcConvert.glb -m Duplex.ifc.xeokit-metadata.json -o Duplex.ifc.oss.xkt  -l
[convert2xkt] Running convert2xkt v1.1.0-alpha-10...
[convert2xkt] Reading input file: Duplex.ifc.IfcConvert.glb
[convert2xkt] Input file size: 961.14 kB
[convert2xkt] Reading input metadata file: Duplex.ifc.xeokit-metadata.json
[convert2xkt] Using parser: parseGLTFIntoXKTModel
[convert2xkt] Parsing normals: enabled
[convert2xkt] Parsing textures: enabled
[convert2xkt] Input file parsed OK. Building XKT document...
[convert2xkt] XKT document built OK. Writing to XKT file...
[convert2xkt] Converted to: XKT v10
[convert2xkt] XKT size: 117.21 kB
[convert2xkt] XKT textures size: 0.01kB
[convert2xkt] Compression ratio: 8.20
[convert2xkt] Conversion time: 0.40 s
[convert2xkt] Converted metaobjects: 0
[convert2xkt] Converted property sets: 0
[convert2xkt] Converted drawable objects: 205
[convert2xkt] Converted geometries: 160
[convert2xkt] Converted textures: 0
[convert2xkt] Converted textureSets: 0
[convert2xkt] Converted triangles: 15236
[convert2xkt] Converted vertices: 27360
[convert2xkt] Converted UVs: 0
[convert2xkt] Converted normals: 27360
[convert2xkt] minTileSize: 200
[convert2xkt] Writing XKT file: Duplex.ifc.oss.xkt
[convert2xkt] Done.

Substituted the XKT for one of the xeokit-bim-viewer demo models - note the "Show Spaces" button is down, at top right:

Screenshot from 2022-08-10 13-46-40

xeolabs commented 2 years ago

Not sure how this affects things here, but might be related: https://sourceforge.net/p/ifcopenshell/discussion/1782717/thread/de192a73/

DB-EC-Hamburg-BIM commented 2 years ago

I used the direct way with the @xeokit/xeokit-convert 1.1.0-alpha-10 via WebIFC. When I do it as you described, everything is working fine. might be a ifcjs problem: https://github.com/IFCjs/web-ifc/issues/208

xeolabs commented 2 years ago

@DB-EC-Hamburg-BIM I'd recommend trying the other pipelines again, using yesterday's releases (all packages) - might also fix your situation

DB-EC-Hamburg-BIM commented 2 years ago

I finally found the problem. The WebIFC,ifcAPI.LoadAllGeometry() does not return IFCSpace meshes. I don't know why.

My workaround is to GetLineIDsWithType ctx.WebIFC.IFCSPACE and parse them into the XKTModel

const lines = ctx.ifcAPI.GetLineIDsWithType(ctx.modelID, ctx.WebIFC.IFCSPACE);

for (let j = 0, len = lines.size(); j < len; j++) {
      const ifcSpaceId = lines.get(j);

      const flatMesh = ctx.ifcAPI.GetFlatMesh(ctx.modelID, ifcSpaceId);
      const flatMeshExpressID = flatMesh.expressID;
      const placedGeometries = flatMesh.geometries;

      const meshIds = [];

      const properties = ctx.ifcAPI.GetLine(ctx.modelID, flatMeshExpressID);
      const entityId = properties.GlobalId.value;

      const metaObjectId = entityId;
      const metaObject = ctx.xktModel.metaObjects[metaObjectId];

      if (ctx.includeTypes && (!metaObject || (!ctx.includeTypes[metaObject.metaObjectType]))) {
          return;
      }

      if (ctx.excludeTypes && (!metaObject || ctx.excludeTypes[metaObject.metaObjectType])) {
          console.log("excluding: " + metaObjectId);
          return;
      }

      for (let j = 0, lenj = placedGeometries.size(); j < lenj; j++) {

          const placedGeometry = placedGeometries.get(j);
          const geometryId = "" + placedGeometry.geometryExpressID;

          if (!ctx.xktModel.geometries[geometryId]) {

              const geometry = ctx.ifcAPI.GetGeometry(ctx.modelID, placedGeometry.geometryExpressID);
              const vertexData = ctx.ifcAPI.GetVertexArray(geometry.GetVertexData(), geometry.GetVertexDataSize());
              const indices = ctx.ifcAPI.GetIndexArray(geometry.GetIndexData(), geometry.GetIndexDataSize());

              // De-interleave vertex arrays

              const positions = [];
              const normals = [];

              for (let k = 0, lenk = vertexData.length / 6; k < lenk; k++) {
                  positions.push(vertexData[k * 6 + 0]);
                  positions.push(vertexData[k * 6 + 1]);
                  positions.push(vertexData[k * 6 + 2]);
              }

              if (!ctx.autoNormals) {
                  for (let k = 0, lenk = vertexData.length / 6; k < lenk; k++) {
                      normals.push(vertexData[k * 6 + 3]);
                      normals.push(vertexData[k * 6 + 4]);
                      normals.push(vertexData[k * 6 + 5]);
                  }
              }

              ctx.xktModel.createGeometry({
                  geometryId: geometryId,
                  primitiveType: "triangles",
                  positions: positions,
                  normals: ctx.autoNormals ? null : normals,
                  indices: indices
              });

              ctx.stats.numGeometries++;
              ctx.stats.numVertices += (positions.length / 3);
              ctx.stats.numTriangles += (indices.length / 3);
          }

          const meshId = ("mesh" + ctx.nextId++);

          ctx.xktModel.createMesh({
              meshId: meshId,
              geometryId: geometryId,
              matrix: new Float32Array(placedGeometry.flatTransformation),
              color: [placedGeometry.color.x, placedGeometry.color.y, placedGeometry.color.z],
              opacity: placedGeometry.color.w
          });

          meshIds.push(meshId);
      }

      if (meshIds.length > 0) {
          ctx.xktModel.createEntity({
              entityId: entityId,
              meshIds: meshIds
          });
          ctx.stats.numObjects++;
      }
    }

But I think there must be a better way :) This should also solve https://github.com/xeokit/xeokit-convert/issues/66 and https://github.com/xeokit/xeokit-sdk/issues/907

xeolabs commented 2 years ago

Gotcha, I see what you've done there. Could you make a PR of this?

At this point I just want to see it in context of the rest of the code, then think on how to integrate or optimize.

Does it perform OK? I'm guessing since we don't tend to get huge numbers of IfcSpace types, it might not be an issue, we'll see.

DB-EC-Hamburg-BIM commented 2 years ago

The performance is ok. I tested only with a small amount of IFCSpaces. Here you can find the PR https://github.com/xeokit/xeokit-convert/pull/76