Revit API Forum
Welcome to Autodesk’s Revit API Forums. Share your knowledge, ask questions, and explore popular Revit API topics.
cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

Computing the correlation of objects in Revit

17 REPLIES 17
SOLVED
Reply
Message 1 of 18
TomB.ADV
1185 Views, 17 Replies

Computing the correlation of objects in Revit

Hi, I'm looking for a way to do reverse clash detection for objects from 2 models, for instance:

Clashing together a collection of clomuns from the Stractural model and Architectural model.

 

The expected result is that there should be 100% corelation between all objects, if not, I want

to extract metadata about every object that isn't alligned to the "truth source".

 

To make this as robust as possible I figured it should be based on the correlation of volumes

and not the instances of the objects but I could be wrong, any better idea is welcome.

 

What would be a good way to map all the geometry and volume of the objects in a way that

also enables an easy comperison so I can extract the corelation as a single KPI between 0 to 1 ?

 

 

 

 

17 REPLIES 17
Message 2 of 18
RPTHOMAS108
in reply to: TomB.ADV

I don't think that is easy via the API, it sounds easy and there is solid geometry to compare but carrying out boolean operations on two sets of solids to find a difference is going to be problematic. i.e. the nearer you get to a zero difference result using BooleanOperationsUtils the nearer you may get to an exception. There is logic in the AssemblyDifference class so that may be the direction. That would likely require you to have a third temporary project to transfer objects into for checking against one another as assemblies. You would gather candidates to check based on category and rough location proximity perhaps. You'll likely get a built-in failure warning as an indicator anyway when two elements share the same volume.

 

You may be better off in Revit checking the parameters that drive the result rather than checking the end geometric result. Although I understand two families may generate the same result differently which is the major issue with that.

 

There have been various discussion here regarding comparing geometry and the essence of what uniquely identifies two solids as being the same.

 

In truth what you describe sounds more like a task for IFC and Solibri, I believe people in the industry are already do it that way.

 

 

Message 3 of 18
TomB.ADV
in reply to: RPTHOMAS108

@RPTHOMAS108 

 

I didn't expect to make things binary, for all practical purposes I can decide that 90% correlation is good enough.

I could use some mathematical methods in the .Net Framework to do the computation.

 

I'm just not sure what will be the best tools for the mathematical part, for instance, I could transform all the objects

to (x.y.z) points matrix and pass it to a 3rd party method for computation to give the % of correlation.

 

 

Message 4 of 18
RPTHOMAS108
in reply to: TomB.ADV

I tend to think how are these things done elsewhere. In Revit the surfaces you get in the geometry are based on certain parametric types. They are then triangulated for rendering but two different types of surfaces could represent the same thing e.g. a ruled face could represent a cylindrical face or conical face (or even a planar face)

 

So I think you have to triangulate the surfaces in some uniform way to do the comparison on the points and triangles but then you can only look for

(i) Points from mesh A are laying planar within the triangles of mesh B (to a tolerance).

(ii) Triangles are covering the same area. Every triangle of A has its complete area overlapped with partial triangle areas from B and vice versa.

 

When you consider simple shapes they are always triangulated the same way so I would go that way and you would consider (i) and (ii) as an indication of them being the same to a percentage.

Message 5 of 18
TomB.ADV
in reply to: RPTHOMAS108

As I mentioned, my tollerance is actually very high, I don't need 100% correlation,
my application doesn't require such high precision. I'm not sure which methods in
the Revit API are the most suitable to convert the object's geometry to
(x,y,z) points array.

 

The collections can be all the Column instances in the models represented by x,y,z points array, which can be run against each other.

 

@RPTHOMAS108 what do you think about the below implimentation?

 

 

 

 

 

Element element = myElement;

//use the GetGeometryObjectFromReference method to get a GeometryObject for the element
GeometryObject geomObject = element.GetGeometryObjectFromReference(new Options());

// Create a list to store the points
List<XYZ> points = new List<XYZ>();

// If the GeometryObject is a Solid, use the Faces property to get a list of faces
if (geomObject is Solid solid)
{
    FaceArray faces = solid.Faces;
    // Iterate over the faces and get the vertices for each face
    foreach (Face face in faces)
    {
        // Use the Tessellate method to get a list of tessellated points
        Mesh mesh = face.Triangulate();
        // Iterate over the tessellated points and add them to the list
        foreach (XYZ point in mesh.Vertices)
        {
            points.Add(point);
        }
    }
}
// If the GeometryObject is a curve, use the Tessellate method to get a list of tessellated points
else if (geomObject is Curve curve)
{
    // Use the Tessellate method to get a list of tessellated points
    IList<XYZ> tessellatedPoints = curve.Tessellate();
    // Iterate over the tessellated points and add them to the list
    foreach (XYZ point in tessellatedPoints)
    {
        points.Add(point);
    }
}
// If the GeometryObject is a surface, use the Triangulate method to get a list of triangles
else if (geomObject is Surface surface)
{
    // Use the Triangulate method to get a list of triangles
    IList<Polygon> triangles = surface.Triangulate();
    // Iterate over the triangles and add the vertices to the list
    foreach (Polygon triangle in triangles)
    {
        points.AddRange(triangle.ToList());
    }
}

 

 

 

 

 

 

 

 

 

 

 

 

 public static double ComputeCollectionCoerrealtion(List<List<(int x, int y, int z)>> collection1, List<List<(int x, int y, int z)>> collection2)
        {
            double totalVolumeCorrelation = 0;
            for (int i = 0; i < collection1.Count; i++)
            {
                for (int j = 0; j < collection2.Count; j++)
                {
                    double volumeCorrelation = ComputeVolumeCorrelation(collection1[i], collection2[j]);
                    totalVolumeCorrelation += volumeCorrelation;
                }
            }

            // Compute the percentage of volume correlation between the two collections
            int numObjectPairs = collection1.Count * collection2.Count;
            double percentVolumeCorrelation = totalVolumeCorrelation / numObjectPairs * 100;
            return percentVolumeCorrelation;
        }

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

public static double ComputeVolumeCorrelation(List<(int x, int y, int z)> object1, List<(int x, int y, int z)> object2)
        {
            // Create 3D arrays to store the voxel data for the two objects
            bool[,,] object1Voxels = CreateObjectVoxels(object1);
            bool[,,] object2Voxels = CreateObjectVoxels(object2);

            // Iterate over the points in each object and set the corresponding voxels to True
            foreach ((int x, int y, int z) in object1)
            {
                object1Voxels[x, y, z] = true;
            }
            foreach ((int x, int y, int z) in object2)
            {
                object2Voxels[x, y, z] = true;
            }

            // Compute the intersection volume of the two objects
            int intersectionVolume = 0;
            for (int x = 0; x < object1Voxels.GetLength(0); x++)
            {
                for (int y = 0; y < object1Voxels.GetLength(1); y++)
                {
                    for (int z = 0; z < object1Voxels.GetLength(2); z++)
                    {
                        if (object1Voxels[x, y, z] && object2Voxels[x, y, z])
                        {
                            intersectionVolume++;
                        }
                    }
                }
            }

            // Compute the volumes of the two objects
            int object1Volume = 0;
            for (int x = 0; x < object1Voxels.GetLength(0); x++)
            {
                for (int y = 0; y < object1Voxels.GetLength(1); y++)
                {
                    for (int z = 0; z < object1Voxels.GetLength(2); z++)
                    {
                        if (object1Voxels[x, y, z])
                        {
                            object1Volume++;
                        }
                    }
                }
            }

            int object2Volume = 0;
            for (int x = 0; x < object2Voxels.GetLength(0); x++)
            {
                for (int y = 0; y < object2Voxels.GetLength(1); y++)
                {
                    for (int z = 0; z < object2Voxels.GetLength(2); z++)
                    {
                        if (object2Voxels[x, y, z])
                        {
                            object2Volume++;
                        }
                    }
                }
            }

            // Compute the volume correlation
            double volumeCorrelation = (double)intersectionVolume / Math.Min(object1Volume, object2Volume);

            return volumeCorrelation;
        }

 

 

 

 

 

 

 

public static bool[,,] CreateObjectVoxels(List<(int x, int y, int z)> points)
        {
            // Find the minimum and maximum x, y, and z coordinates of the points in the object
            int minX = int.MaxValue;
            int minY = int.MaxValue;
            int minZ = int.MaxValue;
            int maxX = int.MinValue;
            int maxY = int.MinValue;
            int maxZ = int.MinValue;
            foreach ((int x, int y, int z) in points)
            {
                minX = Math.Min(minX, x);
                minY = Math.Min(minY, y);
                minZ = Math.Min(minZ, z);
                maxX = Math.Max(maxX, x);
                maxY = Math.Max(maxY, y);
                maxZ = Math.Max(maxZ, z);
            }

            // Calculate the dimensions of the 3D array needed to represent the object
            int width = maxX - minX + 1;
            int height = maxY - minY + 1;
            int depth = maxZ - minZ + 1;

            // Create the 3D array and initialize all elements to False
            bool[,,] voxels = new bool[width, height, depth];
            for (int x = 0; x < width; x++)
            {
                for (int y = 0; y < height; y++)
                {
                    for (int z = 0; z < depth; z++)
                    {
                        voxels[x, y, z] = false;
                    }
                }
            }

            // Set the elements corresponding to the points in the object to True
            foreach ((int x, int y, int z) in points)
            {
                voxels[x - minX, y - minY, z - minZ] = true;
            }

            return voxels;
        }

 

 

 



Message 6 of 18
RPTHOMAS108
in reply to: TomB.ADV

I vaguely get the picture of what you are doing but perhaps explaining the steps would be helpful. I think if you carry out some tests you will get the best picture of if the above is suiting your needs rather than asking here.

 

What units are being used in the integer points for the various functions, since the API units are in feet and that may not be that accurate.

 

Regarding the block of code directly below '// Compute the intersection volume of the two objects':

Is object2Voxels.GetLength(#) always less than object1Voxels.GetLength(#)? They both seem to be generated independently from object1 and object2. So I don't understand how those array sizes are rationalised to be the same and you would avoid index out of range in some situations.

 

Regarding '// Create the 3D array and initialize all elements to False'

The inherent state of a non-nullable Boolean is false isn't it?

 

Overall I think there are simpler ways of comparing sets of points but I've only spent a limited amount of time understanding the above. I would probably do some research into the subject of mesh comparisons to find an approach. There are likely many metrics you could consider in order to prove a negative sooner with less computational effort.

 

Lastly when you extract geometry from Revit be wary of the symbol and instance relationship and how unmodified geometry is transformed to instance positions. That is probably the main thing that catches people out when they do these kinds of comparisons.

 

 

Message 7 of 18
TomB.ADV
in reply to: RPTHOMAS108

@RPTHOMAS108  I see what you mean, so computation things aside, I was able to find the below Documentation:
https://help.autodesk.com/view/RVT/2016/ENU/?guid=GUID-7FCCA616-FFFF-4C43-B6C1-BD0543C3606C

TomBADV_0-1672472191051.png

 

I now understand that what I was asking for is the best way to break down each sub-category of GeometryElement
to an array of XYZ points. In that case, my first goal is to build a method that is able handle categories of this class

by identifying it and using the correct built-in methods to break it down to XYZ points.

 

The below code can handle Solids and Curves, where can I find code examples of how to handle all or some
of the other sub-categories?

 

 

private static List<XYZ> GetPoints(Element element)
        {

            //Get a GeometryObject for the element
            GeometryObject geomObject = element.get_Geometry(new Options());

            // Create a list to store the points
            List<XYZ> pointsList = new List<XYZ>();

            // If the GeometryObject is a Solid, use the Faces property to get a list of faces
            if (geomObject is Solid solid)
            {
                FaceArray faces = solid.Faces;
                // Iterate over the faces and get the vertices for each face
                foreach (Face face in faces)
                {
                    // Use the Tessellate method to get a list of tessellated points
                    Mesh mesh = face.Triangulate();
                    // Iterate over the tessellated points and add them to the list
                    foreach (XYZ point in mesh.Vertices)
                    {
                        points.Add(point);
                    }
                }
            }
            // If the GeometryObject is a curve, use the Tessellate method to get a list of tessellated points
            else if (geomObject is Curve curve)
            {
                // Use the Tessellate method to get a list of tessellated points
                IList<XYZ> tessellatedPoints = curve.Tessellate();
                // Iterate over the tessellated points and add them to the list
                foreach (XYZ point in tessellatedPoints)
                {
                    points.Add(point);
                }
            }
           
            return points;
        }



Message 8 of 18
jeremy_tammik
in reply to: TomB.ADV

One approach that might help is to flatten all elements to DirectShape:

  

https://thebuildingcoder.typepad.com/blog/2015/11/flatten-all-elements-to-directshape.html

  

Jeremy Tammik Developer Advocacy and Support + The Building Coder + Autodesk Developer Network + ADN Open
Message 9 of 18
RPTHOMAS108
in reply to: TomB.ADV

In the majority of cases for model geometry you'll be dealing with Solids, Meshes and GeometryInstances.

 

You do have top level curves if those have been included in the family as model lines etc.

 

Edges I assume would be irrelevant to your exercise since you already triangulated the face of each solid. You don't get edges without there being a face.

 

Meshes rarely occur on their own, for items like topo surface and fabrication elements you get those top level mesh objects.

 

GeometryInstances you get for FamilyInstances where an instance refers to original geometry via a transform i.e. where multiple items share the same geometry but are in different locations (transformed copies of symbol geometry). System families don't use this mechanism because they are usually have unique one-off features anyway.

 

In answer to your original question you follow the same approach i.e. the 'sub-category' derived from GeometryObject will either be a top level item in the GeometryElement collection or nested in the GeometryInstance. For example if you only encounter a GeometryInstance within the GeometryElement then you can get the instance geometry via GeometryInstance.GetInstanceGeometry this method creates a copy of the symbol geometry transformed to the instance position.

 

 FamilyInstance.HasModifiedGeometry will indicate either:

A) The instance has been modified e.g. by cuts in which case GeometryInstance is not used to refer to a symbol geometry.

B) The instance is a unmodified copy of the symbol Geometry. When I use the term 'nested' above what I really mean is that the reference to the original shared symbol geometry is nested. The geometry itself is not nested.

 

So you see already there is a shortcut you can apply: why compare 20 points from 100 instances when you know 60 of those instances have the same geometry anyway? You just compare the symbol geometry first and where that is applied in an unmodified way.

 

What I suggest you do is use RevitLookup for two FamilyInstances, one that has been modified locally with cuts and one that has just been placed. From the differences in those you will understand the configuration and so how to extract the points.

 

I think the process of extracting geometry for instances and allowing for the mechanism regarding modified and unmodified geometry has been discussed previously here and you will find posts for that. You need a recursive function that is checking first the top level geometry and then geometry referred to within any GeometryInstances. However note my previous comments regarding checking the symbol geometry first separately i.e. it probably would not be the best approach to get for example all of the solids from all of the instances via GeometryInstance.GetInstanceGeometry and check those.  It would be better you compare aspects such as GeometryInstance.SymbolGeometryId after verifying the consistency of the symbol geometry between documents etc.

Message 10 of 18
TomB.ADV
in reply to: TomB.ADV

Thank you @RPTHOMAS108  and @jeremy_tammik 

After some research I came up with this initial code which is working as I wanted,

it just needs to be scaled up to be able to handle more elements and more geometry.

 

I decided not to extract the geometry into points because Revit engine can actually do the job natively very well

compared to the other approach I had in mind which is extracting a 3D points array and use it in a Opencascade

or any other 3D proccessing tool.

 

I am sharing this for future reference should it be relevant to someone else (using RevitAPI2022).

 

 

 

[Transaction(TransactionMode.Manual)]
    public class CorrolationCheck : IExternalCommand
    {
        public Result Execute(ExternalCommandData commandData, ref string message, ElementSet elements)
        {
            try
            {
                //Initialize Application resources
                ExternalCommandData CommandData = commandData;
                UIApplication Uiapp = CommandData.Application;
                Application App = Uiapp.Application;
                UIDocument Uidoc = CommandData.Application.ActiveUIDocument;
                Document Doc = Uidoc.Document;


                FilteredElementCollector collector = new FilteredElementCollector(Doc);
                ElementCategoryFilter filter = new ElementCategoryFilter(BuiltInCategory.OST_StructuralColumns);
                IList<Element> columns = collector.WherePasses(filter).OfClass(typeof(FamilyInstance)).ToElements();
                

                Options options = new Options();
                options.ComputeReferences = true;

                GeometryElement geomElem1 = columns[0].get_Geometry(options);
                GeometryElement geomElem2 = columns[1].get_Geometry(options);

                foreach (GeometryObject geomObj1 in geomElem1)
                {
                    if (geomObj1 is Solid)
                    {
                        Solid solid1 = geomObj1 as Solid;
                        double volume1 = solid1.Volume;
                        foreach (GeometryObject geomObj2 in geomElem2)
                        {
                            if (geomObj2 is Solid)
                            {
                                Solid solid2 = geomObj2 as Solid;
                                Solid intersection = BooleanOperationsUtils.ExecuteBooleanOperation(solid1, solid2, BooleanOperationsType.Intersect);
                                double volume2 = intersection.Volume;
                                if (volume2 > 0)
                                {
                                    double percentage = (volume2 / volume1) * 100;
                                    // there is an intersection between the two elements and it's percentage is percentage
                                }
                            }
                        }
                    }
                }

                return Result.Succeeded;
            }
            catch (Exception ex)
            {
                message = ex.Message;
                return Result.Failed;
            }
        }

 

 

 

 

Message 11 of 18
jeremy_tammik
in reply to: TomB.ADV

Thank you for sharing your current approach. I see you are querying two columns for their geometry and calculating the intersection between all of their solids. One tiny little note on this: you may possibly be able to enhance performance slightly by removing the ComputeReferences property setting, or leaving it at its default value of false. It 

determines whether or not references to geometric objects are computed. Since you are not making any use of such references, you should leave it off. I think I heard somewhere that setting this to true is expensive, and you should avoid it if not needed. If you can, I would be very interested in comparative benchmark results running this code over a large model with the setting turned on and off.
  
Jeremy Tammik Developer Advocacy and Support + The Building Coder + Autodesk Developer Network + ADN Open
Message 12 of 18
TomB.ADV
in reply to: jeremy_tammik

Thanks for the tip, I will post the results next week, feel free to send a DM if this slip my mind,
I actaully interested in this myself since I will be using this on APS Design Automation so there
is a clear prefrence to make this as light as possible in order not to exceed quota limits.

Message 13 of 18
TomB.ADV
in reply to: TomB.ADV

@jeremy_tammik 

After testing the code above in diffrent scenarios I noticed that unfortunately this approach is not robust enough for my application, there are too many "miss-fires" where the code doesn't detect the columns as solids for some unknown reason especially when runing the clash for Linked models making the benchmark results usless...

Is there a more robust way to do this ? Is it possible to force convert structural objects and walls to solid virtual chunk that can be used like this;

BooleanOperationsUtils.ExecuteBooleanOperation(solid1, solid2, BooleanOperationsType.Intersect)

 

Message 14 of 18
jeremy_tammik
in reply to: TomB.ADV

Sorry that it is not robust enough. There are other ways, more robust in some aspects, but lacking in others. For instance, you can obtain the exact geometry rendered by Revit using a 3D custom exporter:

 

  

Unfortunately, that returns faces for rendering, not solids. Obtaining solids requires querying the element geometry, and that leads to the non-robustness, possibly due to large differences between different types of element categories. I ran into some of them and solved a few in my OBJ exporter implementation, before the introduction of the custom exporter:

  

   

Jeremy Tammik Developer Advocacy and Support + The Building Coder + Autodesk Developer Network + ADN Open
Message 15 of 18
TomB.ADV
in reply to: jeremy_tammik

@jeremy_tammik 

I see, so in other words, I will have to export the revit objects into some other format to an external engine which in
turn will parse the revit objects as solids and be able to compute the amount of volume all objects are sharing.

Are there any other products autodesk have which can handle the above workflow ? Hopefully also supported by

Design Autimation API ...

 

If not, I can try any other C# ToolKit you may know as sutabel for the job.

Message 16 of 18
jeremy_tammik
in reply to: TomB.ADV

I am not so sure at all. I am certain that reliable clash detection can be implemented inside Revit, and has been.

 

You need to discuss this with a product expert, an application engineer, knowledgeable in the end user product functionality. Not with me!

  

I also know that NavisWorks is used to coordinate huge models, and clash detection can also be implemented based on the Autodesk Platform Services APS (formerly Forge):

  

  

Jeremy Tammik Developer Advocacy and Support + The Building Coder + Autodesk Developer Network + ADN Open
Message 17 of 18
TomB.ADV
in reply to: jeremy_tammik

@jeremy_tammik 

Decide not to give up as per your advice, I was able to dig up the .GetInstanceGeometry() method which is what

I was missing to make the code rubast enough to make the BooleanOperationsType.Intersect work properly.

 

Below is the final code and the benchmark results you asked for:

PC specs:
CPU: 11th Gen Intel(R) Core(TM) i5-11400F @ 2.60GHz 2.59 GHz

GPU: NVidia GeForce GTX 1650

RAM: 32.0 GB

OS: Windows 10 Pro 


The BooleanOperationsUtils.ExecuteBooleanOperation(solidST, solidAR, BooleanOperationsType.Intersect);
is triggered 113,696 times, both lists columnsSTR and columnsARC haev 336 items each.

1. Code runtime with ComputeReferences = true : 10.38 sec, AVG. 91.34 micro-seconds per intersection.

2. Code runtime with ComputeReferences = false : 9.52 sec, AVG. 83.76 micro-seconds per intersection.

 

 

 

using System;
using System.Collections.Generic;
using System.Diagnostics;
using Autodesk.Revit.ApplicationServices;
using Autodesk.Revit.Attributes;
using Autodesk.Revit.DB;
using Autodesk.Revit.UI;


namespace AdvTools.Commands
{
    [Transaction(TransactionMode.Manual)]
    public class CorrolationCheck : IExternalCommand
    {
        public Result Execute(ExternalCommandData commandData, ref string message, ElementSet elements)
        {
            try
            {
                //Initialize Application resources
                ExternalCommandData CommandData = commandData;
                UIApplication Uiapp = CommandData.Application;
                Application App = Uiapp.Application;
                UIDocument Uidoc = CommandData.Application.ActiveUIDocument;
                Document Doc = Uidoc.Document;

                IList<Element> columnsSTR = new List<Element>();
                IList<Element> columnsARC = new List<Element>();

                double accumulated_Correalation = 0;
                double normalized_Correalation = 0;
                long benchmarkTime;
                var stopwatch = new Stopwatch();
                
                foreach (Document model in App.Documents)
                {
                    if (model.Title == "Correlation-ST")
                    {
                        columnsSTR = GetComparableObjects(model);
                    }

                    if (model.Title == "Correlation-AR")
                    {
                        columnsARC = GetComparableObjects(model);
                    }
                }

                List<string> results = new List<string>();
                stopwatch.Start();
                foreach (Solid solidST in GetSolidsWithPosition(columnsSTR))
                {
                    foreach (Solid solidAR in GetSolidsWithPosition(columnsARC))
                    {
                        Solid intersection = BooleanOperationsUtils.ExecuteBooleanOperation(solidST, solidAR, BooleanOperationsType.Intersect);
                        if(intersection.Volume>0)
                        {
                            double percentage = (intersection.Volume / (solidST.Volume + solidAR.Volume - intersection.Volume)) * 100;
                            results.Add($"STR column {solidST.Id} has {percentage}% coorelation to ARC column {solidAR.Id}");
                        }
                    }
                }
                stopwatch.Stop();
                double benchmark = stopwatch.Elapsed.TotalSeconds;

                return Result.Succeeded;
            }
            catch (Exception ex)
            {
                message = ex.Message;
                return Result.Failed;
            }
        }

        
        private IList<Element> GetComparableObjects(Document doc)
        {
            //Get collection of elemetns from structural model
            FilteredElementCollector collector = new FilteredElementCollector(doc);
            ElementCategoryFilter filter = new ElementCategoryFilter(BuiltInCategory.OST_StructuralColumns);
            return collector.WherePasses(filter).OfClass(typeof(FamilyInstance)).ToElements();
        }

        private IList<Solid> GetSolidsWithPosition(IList<Element> elements)
        {
            IList<Solid> resutlts= new List<Solid>();
            
            foreach(Element element in elements)
            {
                Options geomOptions = new Options();
                geomOptions.ComputeReferences = true;
                geomOptions.DetailLevel = ViewDetailLevel.Fine;
                GeometryElement geomElement = element.get_Geometry(geomOptions);

                foreach (GeometryObject geomObj in geomElement)
                {
                    GeometryInstance geomInst = geomObj as GeometryInstance;
                    if (null != geomInst)
                    {
                        GeometryElement columnGeometry = geomInst.GetInstanceGeometry();
                        foreach (GeometryObject obj in columnGeometry)
                        {
                            Solid solid = obj as Solid;
                            if (solid != null && solid.Volume > 0)
                            {
                                resutlts.Add(solid);
                            }
                        }
                    }
                }
            }

            return resutlts;
        }

        private Solid GetSolidGeometryOnly(Element element)
        {
            // Get geometry element of the selected element
            Autodesk.Revit.DB.GeometryElement geoElement = element.get_Geometry(new Options());
            // Get geometry object
            foreach (GeometryObject geoObject in geoElement)
            {
                // Get the geometry instance which contains the geometry information
                Autodesk.Revit.DB.GeometryInstance instance = geoObject as Autodesk.Revit.DB.GeometryInstance;
                if (null != instance)
                {
                    foreach (GeometryObject instObj in instance.SymbolGeometry)
                    {
                        Solid solid = instObj as Solid;
                        return solid;
                    }
                }
            }
            return null;
        }

    }
}

 




Message 18 of 18
jeremy_tammik
in reply to: TomB.ADV

Brilliant! Well done!

 

Thank you very much for the interesting benchmark.

 

No huge difference, but still... 8.3% time savings for removing a single line that is of no use whatsoever definitely makes sense 🙂

  

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

Can't find what you're looking for? Ask the community or share your knowledge.

Post to forums  

Autodesk Design & Make Report