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

Collect All Detail Lines of a Particular SubCategory

Message 1 of 14
3808 Views, 13 Replies

Collect All Detail Lines of a Particular SubCategory

From reading The Building Coder's post about Retrieving All Available Line Styles ( it is my understanding that detail line elements can be collected via FilteredElementCollector once a subcategory is selected? I have a line style subcategory and would like to collect all the detail lines of that style. How do I do that?

For context from the link above (bold added by me for emphasis):

While the Revit API does not provide a true 'Line style' element, the line styles are actually subcategories of the Lines category. Therefore, the FilteredElementCollector cannot easily be used for this in a single statement, like in your examples above.

It should be possible to retrieve the line styles without a line instance, though.

Here’s a macro that lists all subcategories of the Lines category:

  public void GetListOfLinestyles( Document doc )
    Category c = doc.Settings.Categories.get_Item(
      BuiltInCategory.OST_Lines );
    CategoryNameMap subcats = c.SubCategories;
    foreach( Category lineStyle in subcats )
      TaskDialog.Show( "Line style", string.Format(
        "Linestyle {0} id {1}", lineStyle.Name,
        lineStyle.Id.ToString() ) );

Note that some line styles like 'Room Boundary' cannot actually be assigned to arbitrary lines in the UI, but this should be good enough to find a usable one.

Once you have a collection of the line style subcategories of interest, you can create a filtered element collector retrieving all ElementType elements belonging to any one of them.


Labels (1)
Message 2 of 14
in reply to: sdcartmell

For example, changing OST_Lines to OST_LightFixtures will find all the line subcategories of the light fixtures.


(As you type in BuiltInCategory, you should get a list of all the subcatagories you can use.)


See the attached image.  Using the OST_LightFixtures will return "Hidden Lines", "light Source", "test_lightfixturelines", and "test_lightfixturelines2".



Message 3 of 14
in reply to: sdcartmell

Thanks for your reply. I don't quite understand your meaning.

I should clarify, I'm looking for the right way to use a Line Style subcategory in a FilteredElementCollector to grab all the detail lines in the project that are of that style. I don't actually use C#, that code is just from the The Building Coder's website, but I have gotten to the point in my code that I have the Line Style I want to filter with and now I would like to create a filtered element collector retrieving all ElementType elements belonging to that Line Style, using the Revit API.

Message 4 of 14
in reply to: sdcartmell

If you aren't using C#, then what are you using?  Python?  Dynamo?  

Message 5 of 14
in reply to: sdcartmell

I can translate from anything to anything. Maybe what I'm asking to do isn't possible, I'm not sure.

Message 6 of 14
in reply to: sdcartmell

Actually, I may have found something. I looked up this older forum post: 

FilteredElementCollector collector = new FilteredElementCollector(doc);
ElementCategoryFilter fi = new ElementCategoryFilter(BuiltInCategory.OST_TitleBlocks, true);
ICollection<Element> collection 
= collector.OfClass(typeof(FamilyInstance)).WherePasses(fi) .ToElements();

I used the ElementCategoryFilter but replaced the built-in category with my category (not built-in) and I removed the .OfClass filter.... although it is collecting 23,000+ lines which doesn't seem right either, so maybe I need to apply another filter 😕

Message 7 of 14
in reply to: sdcartmell

I believe its a 3 step process.  You find all lines, then narrow those down to the Detail Lines, and then narrow those down to get the line style you want.


Add a new line style called "MyNewLineStyle"  (match the caps exactly) and try something like

FilteredElementCollector collector = new FilteredElementCollector(doc); 
			ElementCategoryFilter fi = new ElementCategoryFilter(BuiltInCategory.OST_GenericLines, true); 
			ICollection<Element> collection = collector.OfClass(typeof(CurveElement)).WherePasses(fi) .ToElements();
			TaskDialog.Show("Number of curves", collection.Count.ToString ());
			List<Element> detail_lines = new List<Element>();
			foreach (Element e in collection)
				if (e as DetailLine != null)
					detail_lines.Add (e);
			TaskDialog.Show("Number of Detail Lines", detail_lines.Count.ToString ());
    		List<Element> some_detail_lines = new List<Element>();
    		foreach (DetailLine dl in detail_lines)
    			if (dl.LineStyle.Name == "MyNewLineStyle")

    		TaskDialog.Show("Number of Detail Lines of MyNewLineStyle", some_detail_lines.Count.ToString ());





Message 8 of 14
in reply to: sdcartmell

Usually easier to filter for objects of GraphicsStyle using ElementClassFilter rather than subcategories of OST_Lines.

GraphicsStyle has a property GraphicsStyle.GraphicsStyleCategory. When this is a subcategory of OST_Lines then it relates to either ModelCurves or DetailCurves (Note that GraphicsStyle.Category is null).


You can't use a class filter for DetailCurves and ModelCurves (which inherit from CurveElement). This base class has the property LineStyle which will be one of the GraphicsStyle elements found above.


When you have items of CurveElement you can distinguish between ModelCurves and DetailCurves as follows:

DetailCurves have OwnerViewId <> ElementId.InvalidElementId

ModelCurves have OwnerViewId = ElementId.InvalidElementId


So you see one potential route is to filter for GraphicsStyles

Filter again to find GraphicsStyle.GraphicsStyleCategory that is equal to your subcategory of lines 

Then use this to find CurveElements that have such a CurveElement.LineStyle.

Finally use CurveElement.OwnerViewId to list either ModelCurves or DetailCurves


One simple way of getting valid GraphicsStyles for DetailCurves/ModelCurves is via CurveElement.GetLineStyleIds (there are many graphics styles that don't relate to lines). Otherwise check GraphicsStyle.GraphicsStyleCategory is a subcategory of OST_Lines.


Example extension methods for getting CurveElements of a given subcategory of lines or matching a GraphicsStyle:

    Public Function GetLinesOfCategory(Doc As Document, GraphicsStyle As GraphicsStyle, DetailLines As Boolean, Optional FromView As View = Nothing) As List(Of CurveElement)
        Dim FEC As FilteredElementCollector = Nothing
        If FromView Is Nothing Then
            FEC = New FilteredElementCollector(Doc)
            FEC = New FilteredElementCollector(Doc, FromView)
        End If

        Dim ECF As New ElementCategoryFilter(BuiltInCategory.OST_Lines)
        Dim Els As List(Of CurveElement) = FEC.WherePasses(ECF).WhereElementIsNotElementType.ToElements _
            .Cast(Of CurveElement).Where(Function(x) x.LineStyle.Id = GraphicsStyle.Id _
            AndAlso (x.OwnerViewId <> ElementId.InvalidElementId) = DetailLines).ToList

        Return Els
    End Function

    Public Function GetLinesOfCategory(Doc As Document, Category As Category, DetailLines As Boolean, Optional FromView As View = Nothing) As List(Of CurveElement)

        Dim FECgs As New FilteredElementCollector(Doc)
        Dim ECFgs As New ElementClassFilter(GetType(GraphicsStyle))
        Dim Gs As List(Of GraphicsStyle) = FECgs.WherePasses(ECFgs).ToElements _
            .Cast(Of GraphicsStyle).Where(Function(x) x.GraphicsStyleCategory.Id = Category.Id).ToList

        If Gs.Count = 0 Then Return New List(Of CurveElement) Else

        Return GetLinesOfCategory(Doc, Gs(0), DetailLines, FromView)
    End Function





Message 9 of 14
in reply to: RPTHOMAS108

Should also say you could probably use:


In combination with .Excluding to find ModelCurves and Exclude them from your DetailCurves.


i.e. filtering this way first will be quicker since it happens at lower level prior to Linq but you don't have millions of these elements to sort through anyway. 



Message 10 of 14
in reply to: sdcartmell

there is a standard filter for detail/model lines: the CurveElementFilter 

			Category targetLineStyle ;
			IEnumerable<GraphicsStyle>  gstyles = new FilteredElementCollector(doc)
				.Where(gs=> gs.GraphicsStyleCategory.Id.IntegerValue == targetLineStyle.Id.IntegerValue);
			ElementId  targetGraphicsStyleId = gstyles.FirstOrDefault().Id;
			CurveElementFilter filter_detail = new CurveElementFilter(CurveElementType.DetailCurve);
			FilterRule frule_typeId = ParameterFilterRuleFactory.CreateEqualsRule(new ElementId(BuiltInParameter.BUILDING_CURVE_GSTYLE),targetGraphicsStyleId);
			ElementParameterFilter filter_type = new ElementParameterFilter(new List<FilterRule>(){ frule_typeId});
			IEnumerable<Element> lines = new FilteredElementCollector(doc)


Message 11 of 14
in reply to: sdcartmell

Great solutions here, thank you so much! 😁

Message 12 of 14

Sorry for the very basic question.

How can I run this code?

Thank you very much.

Message 13 of 14

The way I extend Revit is through pyRevit. I'm sure there are other forums about getting starting with the Revit API, you should look for those. Here's the link to pyRevit's main page:

Message 14 of 14

Thank you!

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

Post to forums  

Autodesk Customer Advisory Groups

Rail Community