xBimTeam / XbimGeometry

XbimGeometry contains the CLR interop libraries and the c++ engine used to compute the 3D geometry of models.
https://xbimteam.github.io/
Other
259 stars 129 forks source link

Create IFC file using tessellated data #328

Open rahulkhandepts opened 3 years ago

rahulkhandepts commented 3 years ago

Hello Team,

I'm new to XbimGeometry. I need to create IFC file with tessellation data. I found IFC Schema IFC4 supports entity of type IfcTriangulatedFaceSet using which geometries can be created. But unfortunately, I could not sum to get started.

Can I get a working example or guidelines to use the same?

Help will be really appreciated,. Thanks in advance

GVladislavG commented 3 years ago

Hello!

I have the same question. Can you give some code example of creating and filling IfcTriangulatedFaceSet with my custom verticies, indicies, normals and face colors. And also it's interesting, is there any analog of IfcTriangulatedFaceSet in IFC2x3.

Thank you!

martin1cerny commented 3 years ago

Here is a minimal example:

private static IfcTriangulatedFaceSet CreateTetrahedron(IModel model)
{
    return model.Instances.New<IfcTriangulatedFaceSet>(tfs => {
        tfs.Closed = true;
        tfs.Coordinates = model.Instances.New<IfcCartesianPointList3D>(pl => {
            pl.CoordList.GetAt(0).AddRange(new IfcLengthMeasure[] { 0, 0, 0 });
            pl.CoordList.GetAt(1).AddRange(new IfcLengthMeasure[] { 1, 0, 0 });
            pl.CoordList.GetAt(2).AddRange(new IfcLengthMeasure[] { 0, 1, 0 });
            pl.CoordList.GetAt(3).AddRange(new IfcLengthMeasure[] { 0, 0, 1 });
        });

        // Indices are 1 based in IFC !!!
        tfs.CoordIndex.GetAt(0).AddRange(new IfcPositiveInteger[] { 1, 3, 2 });
        tfs.CoordIndex.GetAt(1).AddRange(new IfcPositiveInteger[] { 1, 2, 4 });
        tfs.CoordIndex.GetAt(2).AddRange(new IfcPositiveInteger[] { 1, 4, 3 });
        tfs.CoordIndex.GetAt(3).AddRange(new IfcPositiveInteger[] { 2, 3, 4 });
    });
}

Prior to IFC4 you could use IfcClosedShell. But IfcTriangulatedFaceSet is far better for this.

GVladislavG commented 3 years ago

So is there no way to write triangulated mesh in IFC2x3? I just looked in IfcClosedShell and there are no vericies, indicies, etc.

martin1cerny commented 3 years ago

You would have to create IfcClosedShell (or open shell) where your triangles would become faces (CfsFaces). This is far from being optimal but it is what BIM tools do when they export triangulated mesh as IFC2x3.

GVladislavG commented 3 years ago

Is there any code example like for IfcTriangulatedFaceSet? Thanks!

martin1cerny commented 3 years ago

All you need is in the documentation. Start at Alphabetical listing -> Entities -> IfcClosedShell.

GVladislavG commented 3 years ago

I got one more question. How can I represent element like this? Забор Can I add some representation of lines and curves to IfcProduct with IfcTriangulatedFaceSet?

Thanks!

martin1cerny commented 3 years ago

Yes, you can add it as another representation (not IfcTriangulatedFaceSet). But many tools (including xbim UI components) will not show it as things need to be 3D in 3D view.

GVladislavG commented 3 years ago

What class do I need to use as representation for this lines(curves)? Do I understand correctly, that I can use two representations for one IfcProduct? One for IfcTriangulatedFaceSet for the footings and one for the grid?

martin1cerny commented 3 years ago

Maybe IfcLine for lines and IfcCurve for curves? You should read IFC documentation to identify the best fit for your data. The rest of your question depends on the structure of your data.

GVladislavG commented 3 years ago

Hello! I try to create and fill IfcClosedShell according to documentation. Use this code:

var ifcClosedShell = model.Instances.New<Xbim.Ifc2x3.TopologyResource.IfcClosedShell>(cs =>
{
      foreach (var meshTuple in meshList)
      {                            
            var csMesh = m_Meshes[meshTuple.Item1];                            
            for (int i = 0; i < csMesh.Faces; i++)
            {
                  var face = model.Instances.New<Xbim.Ifc2x3.TopologyResource.IfcFace>(fc =>
                  {
                        var edgeLoop = model.Instances.New<Xbim.Ifc2x3.TopologyResource.IfcEdgeLoop>(loop =>
                        {
                              var edge1 = model.Instances.New<Xbim.Ifc2x3.TopologyResource.IfcOrientedEdge>();
                              //edge1.EdgeStart =
                              //edge1.EdgeEnd =

                              var edge2 = model.Instances.New<Xbim.Ifc2x3.TopologyResource.IfcOrientedEdge>();
                              //edge2.EdgeStart =
                              //edge2.EdgeEnd =

                              var edge3 = model.Instances.New<Xbim.Ifc2x3.TopologyResource.IfcOrientedEdge>();
                              //edge3.EdgeStart =
                              //edge3.EdgeEnd =

                              loop.EdgeList.Add(edge1); loop.EdgeList.Add(edge2); loop.EdgeList.Add(edge3);
                         });
                         var faceBound = model.Instances.New<Xbim.Ifc2x3.TopologyResource.IfcFaceBound>();
                         faceBound.Bound = edgeLoop;
                         fc.Bounds.Add(faceBound);
                   });   
                   cs.CfsFaces.Add(face);                                                            
            }
      }
 });

But I can't understand how to set EdgeStart and EdgeEnd verticies with coordinates... Thanks!

martin1cerny commented 3 years ago

As you can see from the documentation, these EdgeStart and EdgeEnd are derived properties, so you can't set them to anything:

ENTITY IfcOrientedEdge
 SUBTYPE OF (IfcEdge);
  EdgeElement : IfcEdge;
  Orientation : IfcBoolean;
 DERIVE
  SELF\IfcEdge.EdgeStart : IfcVertex := IfcBooleanChoose (Orientation, EdgeElement.EdgeStart, EdgeElement.EdgeEnd);
  SELF\IfcEdge.EdgeEnd : IfcVertex := IfcBooleanChoose (Orientation, EdgeElement.EdgeEnd, EdgeElement.EdgeStart);
 WHERE
  EdgeElementNotOriented : NOT('IFCTOPOLOGYRESOURCE.IfcOrientedEdge' IN TYPEOF(EdgeElement));
END_ENTITY;
GVladislavG commented 3 years ago

Now I use this code to create IfcClosedShell. It compiles well. But after attempting to add this geometry to IfcProduct there's no any visible geometry in file.

var ifcClosedShell = model.Instances.New<Xbim.Ifc2x3.TopologyResource.IfcClosedShell>(cs =>
{
  //Запишем грани
     foreach (var meshTuple in meshList)
     {                            
          var csMesh = m_Meshes[meshTuple.Item1];                            
          for (int i = 0; i < csMesh.Faces; i++)
          {
                var face = model.Instances.New<Xbim.Ifc2x3.TopologyResource.IfcFace>(fc =>
                {
                      var polyLoop = model.Instances.New<Xbim.Ifc2x3.TopologyResource.IfcPolyLoop>(pLoop =>
                      {
                            var v1 = csMesh.Vertices[csMesh.Index[i * 3]];
                            var v2 = csMesh.Vertices[csMesh.Index[i * 3 + 1]];
                            var v3 = csMesh.Vertices[csMesh.Index[i * 3 + 2]];

                            var pt1 = model.Instances.New<Xbim.Ifc2x3.GeometryResource.IfcCartesianPoint>(p => 
                                                                                p.SetXYZ(v1.Position.x, v1.Position.y, v1.Position.z));
                            var pt2 = model.Instances.New<Xbim.Ifc2x3.GeometryResource.IfcCartesianPoint>(p => 
                                                                                p.SetXYZ(v2.Position.x, v2.Position.y, v2.Position.z));
                            var pt3 = model.Instances.New<Xbim.Ifc2x3.GeometryResource.IfcCartesianPoint>(p => 
                                                                                p.SetXYZ(v3.Position.x, v3.Position.y, v3.Position.z));

                            pLoop.Polygon.Add(pt1); pLoop.Polygon.Add(pt2); pLoop.Polygon.Add(pt3);
                      });
                     var faceBound = model.Instances.New<Xbim.Ifc2x3.TopologyResource.IfcFaceBound>();
                     faceBound.Bound = polyLoop;
                     fc.Bounds.Add(faceBound);
                 });
                 cs.CfsFaces.Add(face);                                                                
         }                            
    }
});

Is this code correct? Here's my result IFC-file tst.zip

Thanks!