Convert Mesh to Solid

Convert Mesh to Solid

danail.momchilov
Contributor Contributor
1,920 Views
5 Replies
Message 1 of 6

Convert Mesh to Solid

danail.momchilov
Contributor
Contributor

Hi! I am trying to create a C# method, that transforms a Mesh to Solid object. it came out as an issue from Dynamo, as Dynamo solids are converted to DB.Mesh when Unwrapped.

 

My initial approach was to use the TessellatedShapeBuilder class. I would simply get each triangle from the mesh and try to add it as a new face in the builder. Here's the code:

 

        public static IList<Autodesk.Revit.DB.GeometryObject> ReturnRevitSolid(Autodesk.DesignScript.Geometry.Solid inputSolid)
        {
            try
            {
                // convert the Dynamo solid to API mesh
                IList<GeometryObject> solidGeomObject = inputSolid.ToRevitType();

                Autodesk.Revit.DB.Mesh revitMesh;

                if (solidGeomObject.Count == 1)
                    revitMesh = (Autodesk.Revit.DB.Mesh)solidGeomObject[0];
                else
                    return null;

                // define the shape builder object
                TessellatedShapeBuilder builder = new TessellatedShapeBuilder();
                builder.Target = TessellatedShapeBuilderTarget.Solid;
                builder.OpenConnectedFaceSet(true);

                // get all the mesh data
                ElementId materialId = revitMesh.MaterialElementId;
                int trianglesNumb = revitMesh.NumTriangles;

                // create a face from each triangle and add it to the solid
                for (int i = 0; i < trianglesNumb; i++)
                {
                    MeshTriangle meshTriangle = revitMesh.get_Triangle(i);
                    List<XYZ> vertecesList = new List<XYZ> { meshTriangle.get_Vertex(0), meshTriangle.get_Vertex(1), meshTriangle.get_Vertex(2) };
                    TessellatedFace face = new TessellatedFace(vertecesList, materialId);

                    builder.AddFace(face);
                }

                builder.CloseConnectedFaceSet();
                builder.Build();

                TessellatedShapeBuilderResult result = builder.GetBuildResult();

                return result.GetGeometricalObjects();
            }
            catch (Exception e)
            {
                throw e;
            }
        }

 

However, I only got an 'Internal Error' as a result:

danailmomchilov_0-1703172178704.png

 

I then noticed there are 12 triangles and 12 normals for a simple cuboid, which means each planar face is divided in two triangles (logically). So I thought maybe adding two triangles, that usually form a single face might be causing the issue. That's why I've decided to sort the triangles in a dictionary and add the ones, having identical normals under the same key. Then after cleaning duplicate points I would get the correct XYZ list so that a face can be formed properly. Here's the updated code:

 

        public static IList<GeometryObject> ReturnRevitSolidTest(Autodesk.DesignScript.Geometry.Solid inputSolid)
        {
            try
            {
                // convert the Dynamo solid to API mesh
                IList<GeometryObject> solidGeomObject = inputSolid.ToRevitType();

                Autodesk.Revit.DB.Mesh revitMesh;

                if (solidGeomObject.Count == 1)
                    revitMesh = (Autodesk.Revit.DB.Mesh)solidGeomObject[0];
                else
                    return null;

                // match triangles, based on identical normals, if any
                IList<XYZ> normals = revitMesh.GetNormals();
                int trianglesNumb = revitMesh.NumTriangles;

                Dictionary<XYZ, List<XYZ>> pointsByNormals = new Dictionary<XYZ, List<XYZ>>();

                for (int i = 0; i < trianglesNumb; i++)
                {
                    MeshTriangle triangle = revitMesh.get_Triangle(i);
                    XYZ normal = normals[i];

                    if (!pointsByNormals.ContainsKey(normal))
                        pointsByNormals[normal] = new List<XYZ>();

                    for  (int j = 0; j < 3; j++)
                    {
                        XYZ vertex = triangle.get_Vertex(j);
                        pointsByNormals[normal].Add(vertex);
                    }
                }

                // remove duplicating points from the list
                foreach (var kvp in pointsByNormals)
                {
                    List<XYZ> uniquePoints = kvp.Value.Distinct().ToList();
                    pointsByNormals[kvp.Key] = uniquePoints;
                }

                // define the shape builder object
                TessellatedShapeBuilder builder = new TessellatedShapeBuilder();
                builder.Target = TessellatedShapeBuilderTarget.Solid;
                builder.OpenConnectedFaceSet(true);

                ElementId materialId = revitMesh.MaterialElementId;

                // create face from each points set and add it to the shape builder
                foreach (XYZ normal in normals)
                {
                    TessellatedFace face = new TessellatedFace(pointsByNormals[normal], materialId);
                    builder.AddFace(face);
                }

                builder.CloseConnectedFaceSet();
                builder.Build();

                TessellatedShapeBuilderResult result = builder.GetBuildResult();

                return result.GetGeometricalObjects();
            }
            catch (Exception e)
            {
                throw e;
            }
        }

 

Unfortunately it didn't work again. The error I got was that one:

 

danailmomchilov_1-1703173139765.png

 

Any suggestion would be of great help 🙂

I was also thinking I might try to use this class: https://www.revitapidocs.com/2024/94c1fef4-2933-ce67-9c2d-361cbf8a42b4.htm


But I think the general approach would be more or less the same in this case, as it would still require that I add individual faces to the object until a proper solid is obtained.

0 Likes
1,921 Views
5 Replies
Replies (5)
Message 2 of 6

jeremy_tammik
Alumni
Alumni

It may be easier to create a direct shape from the mesh; here are many examples showing how:

  

  

Jeremy Tammik Developer Advocacy and Support + The Building Coder + Autodesk Developer Network + ADN Open
0 Likes
Message 3 of 6

vengateshhp2001
Contributor
Contributor
Hi Jeremy_tammik,
After converting the mesh into direct shape, if we check the property of element geometry it shows Mesh only.
Is there any Direct method to convert the Mesh into solid?
Thank you
0 Likes
Message 4 of 6

lvirone
Enthusiast
Enthusiast

Hello

 

Any new on this topic ? I got the Internal Error too.

 

Material and subCategory cannot be applied to DirectShapes, so converting a Mesh to Solid is good to set the geometry in a FreeFormElement.

 

Thanks

0 Likes
Message 5 of 6

jeremy_tammik
Alumni
Alumni

Cool, sounds good. You can certainly use a Brep builder to create a direct shape. Its use and internal organisation is strictly regimented and needs to be observed in order to achieve the desired result, cf., e.g.:

   

    

Jeremy Tammik Developer Advocacy and Support + The Building Coder + Autodesk Developer Network + ADN Open
Message 6 of 6

mhannonQ65N2
Collaborator
Collaborator

This is a .NET error. On line 40, you are modifying the collection that you are enumerating. You cannot make changes to a collection while you are enumerating it via a foreach loop. I recommend that you make a list of the changes you want to make to the dictionary, add items to that list from within the loop, then, after the loop finishes, apply all the listed changes to the dictionary.

0 Likes