Hi, is there anything to export family types as text?
Like a type catalog?
I think if thats the right terminology so when people import a family the dialog box comes up with types to choose from. I’ve made a ton of door families. Keen to not export the type catalog one by one
Cool Ill try background open stuff and use this although need it to create a text file
Yes, type catalog. The problem is that Revit won’t export most custom shared parameters by default. That’s what I shared was a method to pick any parameters to use.
Thanks Sean, getting this error for some reason. Your right, typical Revit catalog isnt working with shared parameters. I’ve made 200 doors with like 2500 types. Might be a waste of time if I cant get working catalogs into the library with them although Ill try work on making an excel export or something that may work.
What version of Revit?
22, dynamo 2.10
Ok, that is after the SpecType change so yeah the DUT isn’t going to work. I may try to see if I can refactor, but wouldn’t be at least till tomorrow.
I don’t have python available, but here is my C# which should be easy enough to port.
namespace RDGRevit.Commands
{
[Transaction(TransactionMode.Manual)]
class FamilyTypeCatalogExport : IExternalCommand
{
public Result Execute(ExternalCommandData commandData, ref string message, ElementSet elements)
{
Document doc = commandData.Application.ActiveUIDocument.Document;
List<FamilyParameter> usedParams = new List<FamilyParameter>();
FamilyParameterSet famParams = doc.FamilyManager.Parameters;
Units famUnits = doc.GetUnits();
FormatOptions len = famUnits.GetFormatOptions(SpecTypeId.Length);
List<string> output = new List<string>();
SaveFileDialog fsd = new SaveFileDialog
{
Filter = "Text File | *.txt",
DefaultExt = "txt",
OverwritePrompt = true,
FileName = doc.Title
};
if(fsd.ShowDialog() == DialogResult.OK)
{
string path = fsd.FileName;
FamilyTypeSet famTypes = doc.FamilyManager.Types;
foreach(FamilyType type in famTypes)
{
foreach(FamilyParameter param in famParams)
{
if(!param.IsDeterminedByFormula)
{
if(type.HasValue(param))
{
if(!usedParams.Contains(param))
{
usedParams.Add(param);
}
}
}
}
}
string variables = "";
foreach(FamilyParameter param in usedParams)
{
ForgeTypeId pType = param.Definition.GetDataType();
string pName = param.Definition.Name;
if(pType == SpecTypeId.Length)
{
variables += "," + pName + "##LENGTH##FEET";
}
else if(pType == SpecTypeId.Area)
{
variables += "," + pName + "##AREA##SQUARE_FEET";
}
else if(pType == SpecTypeId.Volume)
{
variables += "," + pName + "##VOLUME##CUBIC_FEET";
}
else if(pType == SpecTypeId.Slope)
{
variables += "," + pName + "##SLOPE##SLOPE_DEGREES";
}
else if(pType == SpecTypeId.Angle)
{
variables += "," + pName + "##ANGLE##DECIMAL DEGREES";
}
else if(pType == SpecTypeId.Currency)
{
variables += "," + pName + "##CURRENCY##CURRENCY";
}
else
{
variables += "," + pName + "##OTHER##";
}
}
output.Add(variables);
foreach(FamilyType famType in famTypes)
{
string typeString = "";
typeString += famType.Name;
foreach(FamilyParameter param in usedParams)
{
ForgeTypeId pt = param.Definition.GetDataType();
StorageType storeType = param.StorageType;
string value = string.Empty;
if(storeType == StorageType.Double)
{
if(pt == SpecTypeId.Angle && famType.AsDouble(param) is double angle)
{
value = UnitUtils.ConvertFromInternalUnits(angle, UnitTypeId.Degrees).ToString();
}
else if(pt == SpecTypeId.Slope && famType.AsDouble(param) is double slope)
{
value = UnitUtils.ConvertFromInternalUnits(slope, UnitTypeId.SlopeDegrees).ToString();
}
else
{
value = famType.AsDouble(param).ToString();
}
}
else if(storeType == StorageType.Integer)
{
value = famType.AsInteger(param).ToString();
}
else if(storeType == StorageType.String)
{
value = famType.AsString(param);
}
else if(storeType == StorageType.ElementId)
{
ElementId eId = famType.AsElementId(param);
if(doc.GetElement(eId) is Element elem)
{
value = elem.Name;
}
}
typeString += "," + value;
}
output.Add(typeString);
}
using(StreamWriter sw = new StreamWriter(path))
{
foreach(var line in output)
{
sw.WriteLine(line);
}
}
}
return Result.Succeeded;
}
}
}
Thanks Sean! appreciate it. I can upgrade to R23 if that would solve the issue too. Will try your C sharp in the mean time
No, the code in my old graph is outdated after 2021, so it won’t work in anything newer than 2022 unless you modify it.
I’m actually not sure what to do with C sharp and dynamo sorry… Not sure what port means too
#Sean Page, 2021
import clr
clr.AddReference('RevitAPI')
from Autodesk.Revit.DB import *
clr.AddReference('RevitServices')
import RevitServices
from RevitServices.Persistence import DocumentManager
clr.AddReference('System')
from System.Collections.Generic import List
from System import *
from System.IO import StreamWriter
from System.Text import Encoding
import codecs
doc = DocumentManager.Instance.CurrentDBDocument
#Preparing input from dynamo to revit
path = IN[1]
#units = doc.GetUnits().GetFormatOptions(UnitType.UT_Length).DisplayUnits
famParams = IN[0]
output = []
famTypes = doc.FamilyManager.Types
#Set up the first line of the Type Catalog with the headers
variables = ''
for param in famParams:
pType = param.Definition.ParameterType
pName = param.Definition.Name
#check to see if the parameter name has a comma and encapsulate with double quoates
if pName.Contains(','):
pName = '"'+pName+'"'
if pType == ParameterType.Length:
variables += "," + pName + "##LENGTH##FEET"
elif pType == ParameterType.Area:
variables += "," + pName + "##AREA##SQUARE_FEET"
elif pType == ParameterType.Volume:
variables += "," + pName + "##VOLUME##CUBIC_FEET"
elif pType == ParameterType.Slope:
variables += "," + pName + "##SLOPE##SLOPE_DEGREES"
elif pType == ParameterType.Angle:
variables += "," + pName + "##ANGLE##DECIMAL DEGREES"
elif pType == ParameterType.Currency:
variables += "," + pName + "##CURRENCY##CURRENCY"
else:
variables += "," + pName + "##OTHER##"
#Add the headers to the final output
output.Add(variables + '\r\n')
#Iterate each type and get the values for each parameter ased on its Storage Type and Parameter Type
for famType in famTypes:
typeString = String.Empty
typeString += famType.Name
for param in famParams:
pType = param.Definition.ParameterType
sType = param.StorageType
value = String.Empty
if sType == StorageType.Double:
if pType == ParameterType.Angle:
value = UnitUtils.ConvertFromInternalUnits(famType.AsDouble(param),DisplayUnitType.DUT_DECIMAL_DEGREES).ToString()
elif pType == ParameterType.Slope:
value = UnitUtils.ConvertFromInternalUnits(famType.AsDouble(param),DisplayUnitType.DUT_SLOPE_DEGREES).ToString()
else:
value = famType.AsDouble(param).ToString()
if sType == StorageType.Integer:
value = famType.AsInteger(param).ToString()
if sType == StorageType.String:
value = famType.AsString(param)
if sType == StorageType.ElementId:
eid = famType.AsElementId(param)
elem = doc.GetElement(eid)
try:
value = Element.Name.__get__(elem)
except:
#This catches materials specifically that are "<Default>" and don't have a name
value = String.Empty
#Check for commas in the value and encapsulate with double quotes as needed
if value.Contains(','):
value = '"'+value+'"'
#Add each value for each parameter
typeString += ","+value
#Add all values for each Family Type
output.Add(typeString + '\r\n')
outfile = codecs.open(path, 'w', encoding='utf-16-le')
try:
#Write each line to a txt file while encoding for special characters
for line in output:
outfile.write(line)
outfile.close()
OUT = output
except:
outfile.close()
OUT = "Failed to Write File"
See if this will work. I have not tested it, but it should.
#Sean Page, 2023
import clr
clr.AddReference('RevitAPI')
from Autodesk.Revit.DB import *
clr.AddReference('RevitServices')
import RevitServices
from RevitServices.Persistence import DocumentManager
clr.AddReference('System')
from System.Collections.Generic import List
from System import *
from System.IO import StreamWriter
from System.Text import Encoding
import codecs
doc = DocumentManager.Instance.CurrentDBDocument
#Preparing input from dynamo to revit
path = IN[1]
#units = doc.GetUnits().GetFormatOptions(UnitType.UT_Length).DisplayUnits
famParams = IN[0]
output = []
famTypes = doc.FamilyManager.Types
#Set up the first line of the Type Catalog with the headers
variables = ''
for param in famParams:
pType = param.Definition.GetDataType()
pName = param.Definition.Name
#check to see if the parameter name has a comma and encapsulate with double quoates
if pName.Contains(','):
pName = '"'+pName+'"'
if pType == SpecTypeId.Length:
variables += "," + pName + "##LENGTH##FEET"
elif pType == SpecTypeId.Area:
variables += "," + pName + "##AREA##SQUARE_FEET"
elif pType == SpecTypeId.Volume:
variables += "," + pName + "##VOLUME##CUBIC_FEET"
elif pType == SpecTypeId.Slope:
variables += "," + pName + "##SLOPE##SLOPE_DEGREES"
elif pType == SpecTypeId.Angle:
variables += "," + pName + "##ANGLE##DECIMAL DEGREES"
elif pType == SpecTypeId.Currency:
variables += "," + pName + "##CURRENCY##CURRENCY"
else:
variables += "," + pName + "##OTHER##"
#Add the headers to the final output
output.Add(variables + '\r\n')
#Iterate each type and get the values for each parameter ased on its Storage Type and Parameter Type
for famType in famTypes:
typeString = String.Empty
typeString += famType.Name
for param in famParams:
pType = param.Definition.GetDataType()
sType = param.StorageType
value = String.Empty
if sType == StorageType.Double:
if pType == SpecTypeId.Angle:
value = UnitUtils.ConvertFromInternalUnits(famType.AsDouble(param),UnitTypeId.Degrees).ToString()
elif pType == SpecTypeId.Slope:
value = UnitUtils.ConvertFromInternalUnits(famType.AsDouble(param),UnitTypeId.SlopeDegrees).ToString()
else:
value = famType.AsDouble(param).ToString()
if sType == StorageType.Integer:
value = famType.AsInteger(param).ToString()
if sType == StorageType.String:
value = famType.AsString(param)
if sType == StorageType.ElementId:
eid = famType.AsElementId(param)
elem = doc.GetElement(eid)
try:
value = Element.Name.__get__(elem)
except:
#This catches materials specifically that are "<Default>" and don't have a name
value = String.Empty
#Check for commas in the value and encapsulate with double quotes as needed
if value.Contains(','):
value = '"'+value+'"'
#Add each value for each parameter
typeString += ","+value
#Add all values for each Family Type
output.Add(typeString + '\r\n')
outfile = codecs.open(path, 'w', encoding='utf-16-le')
try:
#Write each line to a txt file while encoding for special characters
for line in output:
outfile.write(line)
outfile.close()
OUT = output
except:
outfile.close()
OUT = "Failed to Write File"
Thanks Sean! its throwing up the error below.
Try to change any of the contains locations like this I guess.
if pName.Contains(','):
to
if ',' in pName:
I think its this part
#Check for commas in the value and encapsulate with double quotes as needed
if value.Contains(','):
value = '"'+value+'"'
Smart fella at work helped me. Have to open and save the text file after making it or it dosnt work. Get cannot parse column header error. Which after making 200 text files isnt going to be great.
Other thing was changing units to metric and needed to input doc.
#Sean Page, 2023
import clr
clr.AddReference('RevitAPI')
from Autodesk.Revit.DB import *
clr.AddReference('RevitServices')
import RevitServices
from RevitServices.Persistence import DocumentManager
clr.AddReference('System')
from System.Collections.Generic import List
from System import *
from System.IO import StreamWriter
from System.Text import Encoding
import codecs
doc = IN[2]
#Preparing input from dynamo to revit
path = IN[1]
#units = doc.GetUnits().GetFormatOptions(UnitType.UT_Length).DisplayUnits
famParams = IN[0]
output = []
famTypes = doc.FamilyManager.Types
#Set up the first line of the Type Catalog with the headers
variables = " "
for param in famParams:
pType = param.Definition.GetDataType()
pName = param.Definition.Name
#check to see if the parameter name has a comma and encapsulate with double quoates
if ',' in pName:
pName = '"'+pName+'"'
if pType == SpecTypeId.Length:
variables += "," + pName + "##LENGTH##MILLIMETERS"
elif pType == SpecTypeId.Area:
variables += "," + pName + "##AREA##SQUARE_MILLIMETERS"
elif pType == SpecTypeId.Volume:
variables += "," + pName + "##VOLUME##CUBIC_MILLIMETERS"
elif pType == SpecTypeId.Slope:
variables += "," + pName + "##SLOPE##SLOPE_DEGREES"
elif pType == SpecTypeId.Angle:
variables += "," + pName + "##ANGLE##DEGREES"
elif pType == SpecTypeId.Currency:
variables += "," + pName + "##CURRENCY##CURRENCY"
else:
variables += "," + pName + "##OTHER##"
trimmedvar = variables[1:]
variables = trimmedvar
#Add the headers to the final output
output.Add(variables + '\r\n')
#Iterate each type and get the values for each parameter ased on its Storage Type and Parameter Type
for famType in famTypes:
typeString = String.Empty
typeString += famType.Name
for param in famParams:
pType = param.Definition.GetDataType()
sType = param.StorageType
value = String.Empty
if sType == StorageType.Double:
if pType == SpecTypeId.Angle:
value = UnitUtils.ConvertFromInternalUnits(famType.AsDouble(param),UnitTypeId.Degrees).ToString()
elif pType == SpecTypeId.Slope:
value = UnitUtils.ConvertFromInternalUnits(famType.AsDouble(param),UnitTypeId.SlopeDegrees).ToString()
else:
value = famType.AsDouble(param).ToString()
if sType == StorageType.Integer:
value = famType.AsInteger(param).ToString()
if sType == StorageType.String:
value = famType.AsString(param)
if sType == StorageType.ElementId:
eid = famType.AsElementId(param)
elem = doc.GetElement(eid)
try:
value = Element.Name.__get__(elem)
except:
#This catches materials specifically that are "<Default>" and don't have a name
value = String.Empty
#Check for commas in the value and encapsulate with double quotes as needed
try:
if ',' in value:
value = '"'+value+'"'
except:
#This catches materials specifically that are "<Default>" and don't have a name
value = String.Empty
#Add each value for each parameter
typeString += ","+value.ToString()
#Add all values for each Family Type
output.Add(typeString + '\r\n')
outfile = codecs.open(path, 'w', encoding='utf-16-le')
try:
#Write each line to a txt file while encoding for special characters
for line in output:
outfile.write(line)
outfile.close()
OUT = output
except:
outfile.close()
OUT = "Failed to Write File"
Here is the graph that is working for me on your Family.
Selected Family Type Catalog Metric.dyn (37.6 KB)
Selection of Parameters in the family.
Here is the catalog available for selection.
Looks like it throws warnings when it can’t find the materials.
This is great thanks Sean! Turned it into a node and exported 200 family catalogs Just wondering if theres a way to get the types ordered when importing?
If you sorted the famParams list before iterating.