无法使用 xBIM 从 IFC 中提取三角几何

cannot extract triangulated geometry from IFC using xBIM

我正在尝试使用此代码提取 IFC 文件中所有几何体的三角网格 我已经用 ifcstore.open...

加载了模型
var context = new Xbim3DModelContext(model);
context.CreateContext();

//var geometries = context.ShapeGeometries();
//XbimShapeTriangulation mesh = null;
var geometries = context.ShapeInstances();

foreach (var g in geometries)
{
    //var ms = new MemoryStream(((IXbimShapeGeometryData)g).ShapeData);
    //var br = new BinaryReader(ms);
    //mesh = br.ReadShapeTriangulation();
    ////mesh = mesh.Transform(((XbimShapeInstance)g).Transformation);

    //Console.WriteLine(g.Format + " | " + g.ShapeLabel);
    //Console.WriteLine(mesh.Faces.Count() + " | " + mesh.Vertices.Count());

    var tri = context.ShapeGeometryMeshOf(g);
    Console.WriteLine(tri.TriangleIndexCount + " | " + tri.ToString());

}

如果我使用上面代码的注释部分,网格 returns 没有被三角化。格式为 PolyHedronBinary。

如果我使用 context.ShapeGeometryMeshOf() 方法,则会抛出异常:几何类型无效。

请帮我对模型的几何形状进行三角测量。

我也阅读了 XbimWindowsUI/Xbim.Presentation/MeshGeometry3DExtensions.cs 中的方法 "read",但我无法弄清楚我必须通过 "m3d" 参数 ?

/// <summary>
/// Reads a triangulated model from an array of bytes and adds the mesh 
/// to the current state
///  </summary>
/// <param name="m3D"></param>
/// <param name="mesh">byte array of XbimGeometryType.PolyhedronBinary  Data</param>
/// <param name="transform">Transforms the mesh to the new position if not null</param>
public static void Read(
    this MeshGeometry3D m3D, 
    byte[] mesh, 
    XbimMatrix3D? transform = null)

如果有人可以提供/指出此方法的示例用法,那就太好了。

我需要在 Unity 中重建 IFC 模型,因此我需要三角网格数据。

另外建议是否有更有效的方法 and/or 以更简单的方式实现此目的!

为此,我使用了 xBIM GIT 存储库中的一些代码:

        IfcStore model = IfcStore.Open(ifcFileName);
        if (model.GeometryStore.IsEmpty)
        {
            var context = new Xbim3DModelContext(model);
            context.CreateContext();
        }

        foreach (var ifcElement in model.Instances.OfType<IfcElement>())
        {
            XbimModelPositioningCollection modelPositions = new XbimModelPositioningCollection();

            short userDefinedId = 0;
            model.UserDefinedId = userDefinedId;

            modelPositions.AddModel(model.ReferencingModel);

            if (model.IsFederation)
            {
                foreach (var refModel in model.ReferencedModels)
                {
                    refModel.Model.UserDefinedId = ++userDefinedId;
                    var v = refModel.Model as IfcStore;
                    if (v != null)
                        modelPositions.AddModel(v.ReferencingModel);
                }
            }
            var modelBounds = modelPositions.GetEnvelopeInMeters();

            var p = modelBounds.Centroid();
            var modelTranslation = new XbimVector3D(-p.X, -p.Y, -p.Z);
            var oneMeter = model.ModelFactors.OneMetre;
            var translation = XbimMatrix3D.CreateTranslation(modelTranslation * oneMeter);
            var scaling = XbimMatrix3D.CreateScale(1 / oneMeter);
            var transform = translation * scaling;

            var mat = GetStyleFromXbimModel(ifcElement);
            var m = GetGeometry(ifcElement, transform, mat);

            var myRetTuple = WriteTriangles(m);
          }`

WriteTriangle 函数:

    private Tuple<Point3D> WriteTriangles(IXbimMeshGeometry3D wpfMeshGeometry3D)
    {
        var axesMeshBuilder = new MeshBuilder();
        var pos = wpfMeshGeometry3D.Positions.ToArray();
        var nor = wpfMeshGeometry3D.Normals.ToArray();
        var areasum = 0.00;
        for (var i = 0; i < wpfMeshGeometry3D.TriangleIndices.Count; i += 3)
        {
            var p1 = wpfMeshGeometry3D.TriangleIndices[i];
            var p2 = wpfMeshGeometry3D.TriangleIndices[i + 1];
            var p3 = wpfMeshGeometry3D.TriangleIndices[i + 2];

            if (nor[p1] == nor[p2] && nor[p1] == nor[p3]) // same normals
            {
                var cnt = FindCentroid(new[] { pos[p1], pos[p2], pos[p3] });
                CreateNormal(cnt, nor[p1], axesMeshBuilder);
            }
            else
            {
                CreateNormal(pos[p1], nor[p1], axesMeshBuilder);
                CreateNormal(pos[p2], nor[p2], axesMeshBuilder);
                CreateNormal(pos[p3], nor[p3], axesMeshBuilder);
            }
            var point1 = new Point3D(pos[p1].X, pos[p1].Y, pos[p1].Z);
            var point2 = new Point3D(pos[p2].X, pos[p2].Y, pos[p2].Z);
            var point3 = new Point3D(pos[p3].X, pos[p3].Y, pos[p3].Z);
        }
        return Tuple.Create(point1, point2, point3);
    }

以及 xBIM GeometryHandler 中的一些其他方法:

    private static XbimPoint3D FindCentroid(XbimPoint3D[] p)
    {
        double x = 0;
        double y = 0;
        double z = 0;
        var n = 0;
        foreach (var item in p)
        {
            x += item.X;
            y += item.Y;
            z += item.Z;
            n++;
        }
        if (n <= 0)
            return new XbimPoint3D(x, y, z);
        x /= n;
        y /= n;
        z /= n;
        return new XbimPoint3D(x, y, z);
    }

    private static void CreateNormal(XbimPoint3D pnt, XbimVector3D vector3D, MeshBuilder axesMeshBuilder)
    {
        var cnt = new Point3D() { X = pnt.X, Y = pnt.Y, Z = pnt.Z };
        var path = new List<Point3D> { cnt };
        const double nrmRatio = .2;
        path.Add(
            new Point3D(
                cnt.X + vector3D.X * nrmRatio,
                cnt.Y + vector3D.Y * nrmRatio,
                cnt.Z + vector3D.Z * nrmRatio
                ));

        const double lineThickness = 0.001;
        axesMeshBuilder.AddTube(path, lineThickness, 9, false);
    }

    private static WpfMeshGeometry3D GetGeometry(IPersistEntity selection, XbimMatrix3D modelTransform, Material mat)
    {
        var tgt = new WpfMeshGeometry3D(mat, mat);
        tgt.BeginUpdate();
        using (var geomstore = selection.Model.GeometryStore)
        {
            using (var geomReader = geomstore.BeginRead())
            {
                foreach (var shapeInstance in geomReader.ShapeInstancesOfEntity(selection).Where(x => x.RepresentationType == XbimGeometryRepresentationType.OpeningsAndAdditionsIncluded))
                {
                    IXbimShapeGeometryData shapegeom = geomReader.ShapeGeometry(shapeInstance.ShapeGeometryLabel);
                    if (shapegeom.Format != (byte)XbimGeometryType.PolyhedronBinary)
                        continue;
                    var transform = shapeInstance.Transformation * modelTransform;
                    tgt.Add(
                        shapegeom.ShapeData,
                        shapeInstance.IfcTypeId,
                        shapeInstance.IfcProductLabel,
                        shapeInstance.InstanceLabel,
                        transform,
                        (short)selection.Model.UserDefinedId
                        );
                }
            }
        }
        tgt.EndUpdate();
        return tgt;
    }


    private static DiffuseMaterial GetStyleFromXbimModel(IIfcProduct item, double opacity = 1)
    {
        var context = new Xbim3DModelContext(item.Model);

        var productShape = context.ShapeInstancesOf(item)
            .Where(s => s.RepresentationType != XbimGeometryRepresentationType.OpeningsAndAdditionsExcluded)
            .ToList();

        var wpfMaterial = GetWpfMaterial(item.Model, productShape.Count > 0 ? productShape[0].StyleLabel : 0);

        var newmaterial = wpfMaterial.Clone();
        ((DiffuseMaterial)newmaterial).Brush.Opacity = opacity;
        return newmaterial as DiffuseMaterial;
    }

    private static Material GetWpfMaterial(IModel model, int styleId)
    {
        var sStyle = model.Instances[styleId] as IIfcSurfaceStyle;
        var wpfMaterial = new WpfMaterial();

        if (sStyle != null)
        {
            var texture = XbimTexture.Create(sStyle);
            texture.DefinedObjectId = styleId;
            wpfMaterial.CreateMaterial(texture);

            return wpfMaterial;
        }
        var defautMaterial = ModelDataProvider.DefaultMaterials;

        Material material;
        if (defautMaterial.TryGetValue(model.GetType().Name, out material))
        {
            return material;
        }
        var color = new XbimColour("red", 1, 1, 1);
        wpfMaterial.CreateMaterial(color);
        return wpfMaterial;
    }