2

I am trying to extract triangulated meshes of all geometries in an IFC file using this code I have already loaded the model with 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());

}

If I'm using the commented part of the above code, the mesh returns without being triangulated. The format is PolyHedronBinary.

If I use the context.ShapeGeometryMeshOf() method, there is an exception thrown : invalid geometry type .

image

Please help me with triangulating the geometries of the model.

I have also read about the method "read" in XbimWindowsUI/Xbim.Presentation/MeshGeometry3DExtensions.cs, but I am not able to figure out what I have to pass as the "m3d" parameter ?

/// <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)

It will be great if anybody could provide/ point me to example usage of this method.

I need to rebuild the IFC model in Unity and hence I need the triangulated mesh data.

Also suggest if there is anyway to achieve this more efficiently and/or in a simpler way!

Uwe Keim
  • 39,551
  • 56
  • 175
  • 291
anirudh nandavar
  • 213
  • 2
  • 12

1 Answers1

4

I used some code from the xBIM GIT repository for this:

        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);
          }`

the WriteTriangle-Function:

    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);
    }

and some additional methods from 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;
    }
Alex
  • 81
  • 4