Error in Springs.FamilyInstance.ByGeometry in Revit 2024

Hello,I am a beginner user of Dynamo , and trying to generate Revit families from the solid created by Dynamo. I used Springs.FamilyInstance.ByGeometry note in Dynamo. I received the results as null. Could you please see my scripts and give me suggestions. Thank you very much.

Hello @CaraLily do you have ironpython 2.7 version 2.5 installed…another could just be ootb family type by geometry and insert as instance with family instance by point…

or try here with ironpython 3 as here spring node but edit a bit.. and should work 24-25-26

import clr
import os
import sys
import traceback
import System

pf_path = System.Environment.GetFolderPath(System.Environment.SpecialFolder.ProgramFilesX86)
sys.path.append(os.path.join(pf_path, 'IronPython 3.4', 'Lib'))

clr.AddReference('RevitAPI')
clr.AddReference('RevitServices')
clr.AddReference('ProtoGeometry')
clr.AddReference('RevitNodes')

import Revit
clr.ImportExtensions(Revit.Elements)
clr.ImportExtensions(Revit.GeometryConversion)

from Autodesk.DesignScript.Geometry import *
from Autodesk.DesignScript.Geometry import Point as DynPoint
from Autodesk.Revit.DB import *
from Autodesk.Revit.DB.Structure import StructuralType
from RevitServices.Persistence import DocumentManager
from RevitServices.Transactions import TransactionManager

doc = DocumentManager.Instance.CurrentDBDocument
tManager = TransactionManager.Instance

def tolist(obj):
    return obj if hasattr(obj, '__iter__') and not isinstance(obj, str) else [obj]

def pad_lists(lists):
    length = len(lists[0])
    for lst in lists[1:]:
        while len(lst) < length:
            lst.append(lst[-1])
        if len(lst) > length:
            lst[:] = lst[:length]
    return lists

class FamLoadOpt(IFamilyLoadOptions):
    def OnFamilyFound(self, familyInUse, overwriteParameterValues):
        return True
    def OnSharedFamilyFound(self, familyInUse, source, overwriteParameterValues):
        return True

geom = tolist(IN[0])
fam_path = IN[1]
names = tolist(IN[2])
categories = tolist(IN[3])
materials = tolist(IN[4])
subcats = tolist(IN[5])

if int(doc.Application.VersionNumber) > 2021:
    units = doc.GetUnits().GetFormatOptions(ForgeTypeId("autodesk.spec.aec:length")).GetUnitTypeId()
else:
    units = doc.GetUnits().GetFormatOptions(UnitType.UT_Length).DisplayUnits
factor = UnitUtils.ConvertToInternalUnits(1, units)

origin = XYZ.Zero
str_type = StructuralType.NonStructural
temp_path = System.IO.Path.GetTempPath()
invalid_chars = System.IO.Path.GetInvalidFileNameChars()
acceptable_views = ('ThreeD', 'FloorPlan', 'EngineeringPlan', 'CeilingPlan', 'Elevation', 'Section')

satOpt = SATImportOptions()
satOpt.Placement = ImportPlacement.Origin
satOpt.Unit = ImportUnit.Foot

opt = Options()
opt.ComputeReferences = True

saveOpt = SaveAsOptions()
saveOpt.OverwriteExistingFile = True

def create_solid_family(geom_obj, name, category, material, subcat):
    try:
        if any(c in name for c in invalid_chars):
            raise Exception("Family name contains invalid characters")
        
        tManager.ForceCloseTransaction()
        fam_doc = doc.Application.NewFamilyDocument(fam_path)
        
        if factor != 1:
            geom_obj = geom_obj.Scale(factor)
        offset_vec = Vector.ByTwoPoints(BoundingBox.ByGeometry(geom_obj).MinPoint, DynPoint.Origin())
        geom_obj = geom_obj.Translate(offset_vec)

        sat_file = os.path.join(temp_path, f"{name}.sat")
        Geometry.ExportToSAT(geom_obj, sat_file)
        
        view = next((v for v in FilteredElementCollector(fam_doc).OfClass(View)
                     if str(v.ViewType) in acceptable_views and not v.IsTemplate), None)
        
        tManager.EnsureInTransaction(fam_doc)
        import_id = fam_doc.Import(sat_file, satOpt, view)
        imported_el = fam_doc.GetElement(import_id)
        geom_iter = imported_el.get_Geometry(opt)
        
        solid = None
        for geo in geom_iter:
            for item in geo.GetInstanceGeometry():
                if isinstance(item, Solid) and item.Volume > 0:
                    solid = item
                    break
            if solid: break

        import_ids = [imp.Id for imp in FilteredElementCollector(fam_doc).OfClass(ImportInstance)]
        for imp_id in import_ids:
            el = fam_doc.GetElement(imp_id)
            if el.Pinned: el.Pinned = False
            fam_doc.Delete(imp_id)

        if os.path.exists(sat_file):
            System.IO.File.Delete(sat_file)

        try:
            fam_cat = fam_doc.Settings.Categories.get_Item(category.Name)
            fam_doc.OwnerFamily.FamilyCategory = fam_cat
        except: pass

        elem = FreeFormElement.Create(fam_doc, solid)

        if material:
            try:
                mat_fec = FilteredElementCollector(fam_doc).OfClass(Material)
                fam_mat = next((m for m in mat_fec if m.Name == material), None)
                if fam_mat:
                    elem.get_Parameter(BuiltInParameter.MATERIAL_ID_PARAM).Set(fam_mat.Id)
            except: pass

        if subcat:
            try:
                cat_subs = fam_doc.OwnerFamily.FamilyCategory.SubCategories
                if cat_subs.Contains(subcat):
                    elem.Subcategory = cat_subs[subcat]
                else:
                    new_sub = fam_doc.Settings.Categories.NewSubcategory(fam_doc.OwnerFamily.FamilyCategory, subcat)
                    elem.Subcategory = new_sub
            except: pass

        tManager.ForceCloseTransaction()

        rfa_path = os.path.join(temp_path, f"{name}.rfa")
        fam_doc.SaveAs(rfa_path, saveOpt)
        family = fam_doc.LoadFamily(doc, FamLoadOpt())
        fam_doc.Close(False)
        if os.path.exists(rfa_path):
            System.IO.File.Delete(rfa_path)

        sym_id = family.GetFamilySymbolIds().GetEnumerator()
        sym_id.MoveNext()
        symbol = doc.GetElement(sym_id.Current)
        tManager.EnsureInTransaction(doc)
        if not symbol.IsActive: symbol.Activate()
        instance = doc.Create.NewFamilyInstance(origin, symbol, str_type)
        ElementTransformUtils.MoveElement(doc, instance.Id, offset_vec.Reverse().ToXyz())
        tManager.ForceCloseTransaction()

        return instance.ToDSType(False), family.ToDSType(False)

    except:
        return traceback.format_exc(), ""

if len(geom) == len(names) == len(categories) == len(materials) == len(subcats):
    results = list(map(create_solid_family, geom, names, categories, materials, subcats))
elif len(geom) == len(names):
    padded = pad_lists([geom, categories, materials, subcats])
    results = list(map(create_solid_family, geom, names, padded[1], padded[2], padded[3]))
else:
    results = [("Ensure each geometry has a unique family name.", "")]

OUT = [r[0] for r in results], [r[1] for r in results]

satOpt.Dispose()
opt.Dispose()
saveOpt.Dispose()

1 Like

Thank you very much for your response. Now, I use FamilyType.ByGeometry and I received them as a one family. Now, I am trying to receive them as separate families. If you don’t mind, please give me suggestions.

yeah do you mean insert your 42 family types as instance ?

yes

allright you could try play around with something here maybe…

Thank you very much. I will try it.

1 Like

I got it. Thank you so much. @sovitek

1 Like