Lines Category in Dynamo for Revit 2023 and later

The list of Categories changes between Revit versions, which affects the Categories pulldown. In order to create Dynamo scripts that are compatible with multiple versions of Revit and allow selection of a specific Category, I have been using a string of the Category with the Category.ByName node. I have used this workaround for a few years with few issues.

In Revit 2022 and earlier versions, using the string “Lines” with the Category.ByName node outputs the Lines Category, similar to selecting Lines in the Categories pulldown.

In Revit 2023 and later versions, using the string “Lines” with the Category.ByName node outputs the Adaptive Points - Lines Category. Retrieving the Name from the Categories pulldown reveals that the Lines category should indeed be called “Lines” and the Adaptive Points - Lines category should be called “Adaptive Points - Lines” so it seems like an error that trying to retrieve the Lines Category using Category.ByName retrieves a different category.

Is there a way to select all Lines in a model that does not rely on a pulldown that changes between Revit versions?

Hello @Andrew_Victus and welcome :wink: thats a well known issue think dynamo knows that and will hopefully be fixed…for now we can use buitin categori or categori by id

2 Likes

Open the graph, set the pull down, and save the graph in Revit 2024. Do not reopen it and save it again in 2020 or 2021 and things should be fine
(Note: both of the versions without the dropdown fix will no longer be supported in a matter of months). Utilize player to prevent saving over the ‘repaired’ version.

3 Likes

thx @jacob.small Great info :wink:

1 Like

Thank you very much!

How do I use Category By ID? I don’t see a node in the Library search or in the Revit → Elements → Category sublist. Is there a Package that contains this node?

I didn’t know about using Revit 2024 to fix the Category pulldown. I will have to add that to my bag of tricks.

Dont think there are some ootb category by id as it needs the unique categori id…i just call it in a codeblock

1 Like

2022 should work too if memory serves. The hard part is managing the packages so you so t have to have different versions of your graphs… :frowning:

1 Like

There is always the option of using some python to determine the build and therefor the methods you need to use within the code as a bit of a flexible variant.

You do still need to maintain this code between builds…

The code below from @Brendan_Cassidy is intended to determine the current user packages location but you can see the methods for finding build numbers in the code and structure your code as such.

"""
DYNAMOAPI: Get User Package Location For Currently Running Dynamo Application
"""

__author__ = 'Brendan cassidy'
__twitter__ = '@brencass86'
__version__ = '1.0.1'

"""
This will gather the correct user package location depending on what version of dynamo is running in either Civil 3d or Revit.
Then it will output a path to the currently running user appdata folder for dynamo
"""

import clr

# Sets up new path to ironpython module Library
# See https://docs.python.org/2/library/sys.html
import sys
sys.path.append("C:\Program Files (x86)\IronPython 2.7\Lib")

# Imports operating system interfaces
# See https://docs.python.org/2/library/os.html
import os

# Module to read a dll assembly version
from System.Diagnostics import FileVersionInfo

import collections

# Function to trim string version input down to main version
def GetReducedVersion(input):
        # Strings version down to main version
        count=0
        stringIndex=[]
        for a in input:
                if a == ".":
                        stringIndex.append(count)
                count=count+1
        return input[0:stringIndex[1]]

def GetAllDynamoFolders(path):
        directories = []
        # r=root, d=directories, f = files
        for r, d, f in os.walk(path):
            for directory in d:
                temppath=os.path.join(r, directory)
                if temppath.endswith("\\packages") and temppath.count("\\packages")==1:
                                directories.append(temppath)
        return directories

# Flatten List Function
def flattenlist(listin):
    for el in listin:
        if isinstance(el, collections.Iterable) and not isinstance(el, str):
            for sub in flattenlist(el):
                yield sub
        else:
                yield el

# Trys to find Revit API, if it errors out it will skip
try:
        # Import DocumentManager
        clr.AddReference("RevitServices")
        import RevitServices
        from RevitServices.Persistence import DocumentManager

        # Import RevitAPI
        clr.AddReference("RevitAPI")
        import Autodesk
        from Autodesk.Revit.DB import *

        # Standard areas for Current Document, Active UI and application
        uiapp = DocumentManager.Instance.CurrentUIApplication
        app = uiapp.Application

        # Gets current Revit Version
        revitVersion = int(app.VersionNumber)

        # Only runs if revit version is higher than 2019
        if revitVersion > 2019:

                # Constructs path depending on revit version this is run from
                FolderLocation = 'C:\\Program Files\\Autodesk\\Revit ' + app.VersionNumber +  '\\AddIns\\DynamoForRevit\\'

                # Gets Dynamo Core dll file Version
                DynamoCoreVersion = FileVersionInfo.GetVersionInfo(FolderLocation + "DynamoCore.dll").FileVersion

        # Uses a different method to get dynamo core version if not in revit 2020 or higher
        else:
                clr.AddReference('DynamoRevitDS')
                import Dynamo

                # access to the current Dynamo instance and workspace
                dynamoRevit = Dynamo.Applications.DynamoRevit()
                currentWorkspace = dynamoRevit.RevitDynamoModel.CurrentWorkspace

                # Access current version of dynamo
                DynamoCoreVersion=dynamoRevit.RevitDynamoModel.Version

        # Constructs the user package location path
        OUT = os.getenv('APPDATA') + '\\Dynamo\\Dynamo Revit\\' + GetReducedVersion(DynamoCoreVersion) + '\\packages', GetAllDynamoFolders(os.getenv('APPDATA') + '\\Dynamo\\Dynamo Revit\\')


# outputs a error to do something else if it cannot find Revit API
except:
        # Trys to find Autocad API, if it errors out it will skip
        try:
                # Add Assemblies for AutoCAD and Civil3D
                clr.AddReference('AcMgd')
                clr.AddReference('AcCoreMgd')
                clr.AddReference('AcDbMgd')

                import Autodesk.AutoCAD.ApplicationServices.Application as acapp

                # What the Versions means to year version
                #  https://knowledge.autodesk.com/support/autocad/learn-explore/caas/CloudHelp/cloudhelp/2021/ENU/AutoCAD-Core/files/GUID-793238B6-F8B8-4D20-BB3A-001700AECD75-htm.html
                appBuildVersion = float(acapp.Version.Major.ToString() + "." + acapp.Version.Minor.ToString())

                # Gets Autocad Build version then transfer it to year version
                if appBuildVersion == 23.1:
                        appVersion = "2020"
                elif appBuildVersion == 24.0:
                        appVersion = "2021"
                else:
                        appVersion = "NA"

                # If AppVersion is NA eg not civil 3d versions 2020 or 2021 then output not supported
                if appVersion == "NA":
                        OUT = "This code does not support Civil 3D 2019 or less"

                # Goes to correct folder location of DynamoCore and checks its version
                else:
                        dynamoCoreLoc = 'C:\\Program Files\\Autodesk\\AutoCAD ' + appVersion + '\\C3D\Dynamo\\Core\\DynamoCore.dll'

                        # Gets Dynamo Core dll file Version
                        DynamoCoreVersion = FileVersionInfo.GetVersionInfo(dynamoCoreLoc).FileVersion

                        templist=[]
                        for a in range(2020, 2030):
                                if os.path.exists(os.getenv('APPDATA') + '\\Autodesk\\C3D ' + a.ToString() + '\\Dynamo\\'):
                                        templist.append(GetAllDynamoFolders(os.getenv('APPDATA') + '\\Autodesk\\C3D ' + a.ToString() + '\\Dynamo\\'))

                        # Constructs the user package location path
                        OUT = os.getenv('APPDATA') + '\\Autodesk\\C3D ' + appVersion + '\\Dynamo\\' + GetReducedVersion(DynamoCoreVersion) + '\\packages', flattenlist(templist)

        # Outputs a error that this wasnt run from within a dynamo hosted in revit or Civil 3D
        except:
                OUT = "This code only works within revit/Civils 3d"
1 Like

Just use the category by id operation. This was discussed previously here:

2 Likes

Thank you all very much! I was able to apply these solutions and achieve exactly what I wanted to.

1 Like