Search code examples
revit-apirevit

REVIT API Filtering Elements by Edges


I have to retrieve the endpoints from every edge in the doc, but the process of retrieving the edges is taking too much time due to having to iterate through every element. My current approach is

FilteredElementCollector collector = new FilteredElementCollector(doc);
            collector.WherePasses(new LogicalOrFilter((new         ElementIsElementTypeFilter(false)), new ElementIsElementTypeFilter(true)));
            List<object> coordinatelist = new List<object>();
            for (int i = collector.ToElements().Count - 1; i > 0; i--)
                {
                Element element = collector.ToElements()[i];
                GeometryElement geo = element.get_Geometry(new Options());
                if (geo != null)
                {
                    for(int j = geo.Count()-1;j>=0;j--){
                    Solid geosolid = geo.ElementAt(j) as Solid;
                        if(geosolid != null)
                            {
                            for(int k = geosolid.Edges.Size - 1; k >= 0; k--)
                            {
                                Edge edge = geosolid.Edges.get_Item(k);
                                Curve edgecurve = edge.AsCurve();
                                FillDictionary(edgecurve, element);
                            }
                        }
                        else continue;
                    }
                }
                else continue;

            }

I am unable to filter by edges since Edge is not a child of Element but of GeometryObject

How can I get the edges without iterating through every element or how can I speed up the process?


Solution

  • You can eliminate a lot of elements from your iteration.

    Why do you want to iterate over elements fulfilling ElementIsElementTypeFilter( true )?

    They do not exist in the project; they are just templates, types, symbols. Only the instances exist in the project model space.

    Furthermore, you are calling ToElements within the loop, on each single iteration. This is creating a new collection of all the elements each time. That is a huge waste of time and space.

    There is no need to call ToElements at all! Check out this discussion of FindElement and Collector Optimisation.

    You can probably eliminate many other elements as well. For instance, your elements of interest will presumably almost certainly have a valid category.

    The Building Coder explored several different approaches to Retrieve Model Elements or Visible 3D Elements.

    You could add the check for non-void solid and the extraction of the solids into the LINQ clause, if you want, to make your code shorter and more readable; however, that will probably not affect performance much.

    Something like this?

    void RetrieveEdges( 
      Document doc, 
      Dictionary<Curve, ElementId> curves )
    {
      FilteredElementCollector collector
        = new FilteredElementCollector( doc )
          .WhereElementIsNotElementType()
          .WhereElementIsViewIndependent();
    
      Options opt = new Options();
    
      foreach( Element el in collector )
      {
        if( null != el.Category )
        {
          GeometryElement geo = el.get_Geometry( opt );
          if( geo != null )
          {
            foreach( GeometryObject obj in geo )
            {
              Solid sol = obj as Solid;
              if( null!= sol )
              {
                foreach( Edge edge in sol.Edges )
                {
                  Curve edgecurve = edge.AsCurve();
                  curves.Add( edgecurve, el.Id );
                }
              }
            }
          }
        }
      }
    }