Use the node springs.familyinstance.bygeometry to import the model into revit

In dynamo, the tunnel model is created through the tunnel outline family. When I import the tunnel model into Revit through the node springs.familyinstance.bygeometry to create a solid, the “instance” and “family” below the node box appears empty when the operation is completed.How can I solve this problem please?

You will need feed in a categori and if you feed in multiple object they will need a unique name as well…

Excuse me for bothering you,I tried what you suggested but it still isn’t working.

4 years after :wink: nope dont know, which revit and dynamo build are you working in ?, in newer version we can just do it OOTB with FamilyType.ByGeometry and insert witth FamilyInstance.ByCoordinates or other nodes there can insert a family type as instance

op from that post used rhythm, so i was testing with rhythm as well which did work, if memory serves. worth a try if ootb nodes are not available.

Hey, we gave Springs a reboot…

Here is a screen grab using Revit 2027…

If you have a look here SpringNodes/_tests/Revit/FamilyInstance/InstanceByGeometry at master · dimven/SpringNodes · GitHub you will see the example files.

Hope that helps.

Mark

Thx Mark…so great i use this version here for pythonnet 3, work great at least fo me :wink: but again its build on Dimitars first code for that in ironPython at that time …so great, what a legend…and thanks for that

import clr
import os
import traceback
import System

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

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 list(obj) if isinstance(obj, (list, tuple)) else [obj]

def pad(lst, n):
    lst = list(lst)
    if not lst:
        return [None] * n
    while len(lst) < n:
        lst.append(lst[-1])
    return lst[:n]

_rn_asm = next((a for a in System.AppDomain.CurrentDomain.GetAssemblies()
                if a.GetName().Name == 'RevitNodes'), None)
_ds_methods = []

def _collect_ds_methods():
    if _rn_asm is None:
        return
    try:
        types = _rn_asm.GetTypes()
    except System.Reflection.ReflectionTypeLoadException as e:
        types = [t for t in e.Types if t is not None]
    for t in types:
        if not (t.IsAbstract and t.IsSealed):
            continue
        for m in t.GetMethods():
            if m.Name == 'ToDSType' and m.IsStatic and len(m.GetParameters()) == 2:
                _ds_methods.append(m)

_collect_ds_methods()

def to_ds(el):
    et = el.GetType()
    for m in _ds_methods:
        if m.GetParameters()[0].ParameterType.IsAssignableFrom(et):
            try:
                return m.Invoke(None, System.Array[System.Object]([el, True]))
            except:
                pass
    return el

class FamLoadOpt(IFamilyLoadOptions):
    __namespace__ = "SovitekFamLoadOpt"
    def OnFamilyFound(self, familyInUse, overwriteParameterValues):
        return (True, True)
    def OnSharedFamilyFound(self, familyInUse, source, overwriteParameterValues):
        return (True, FamilySource.Family, 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 = list(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 load_family(fam_doc, name):
    fam = fam_doc.LoadFamily(doc, FamLoadOpt())
    if isinstance(fam, tuple):
        fam = fam[-1]
    if fam is None:
        raise Exception("LoadFamily returned None for '{}'".format(name))
    return fam

def create_solid_family(geom_obj, name, category, material, subcat):
    sat_file = None
    rfa_path = None
    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, name + ".sat")
        geom_obj.ExportToSAT(sat_file, 1.0)

        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)
        if isinstance(import_id, tuple):
            import_id = import_id[-1]
        imported_el = fam_doc.GetElement(import_id)
        geom_iter = imported_el.get_Geometry(opt)

        solid = None
        for geo in geom_iter:
            if not isinstance(geo, GeometryInstance):
                continue
            for item in geo.GetInstanceGeometry():
                if isinstance(item, Solid) and item.Volume > 0:
                    solid = item
                    break
            if solid is not None:
                break

        if solid is None:
            raise Exception("No solid found in imported SAT geometry")

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

        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:
                fam_category = fam_doc.OwnerFamily.FamilyCategory
                cat_subs = fam_category.SubCategories
                if cat_subs.Contains(subcat):
                    elem.Subcategory = cat_subs.get_Item(subcat)
                else:
                    elem.Subcategory = fam_doc.Settings.Categories.NewSubcategory(fam_category, subcat)
            except:
                pass

        tManager.ForceCloseTransaction()

        rfa_path = os.path.join(temp_path, name + ".rfa")
        fam_doc.SaveAs(rfa_path, saveOpt)
        family = load_family(fam_doc, name)
        fam_doc.Close(False)

        target = XYZ(-offset_vec.X, -offset_vec.Y, -offset_vec.Z)

        existing = [i for i in FilteredElementCollector(doc).OfClass(FamilyInstance)
                    if i.Symbol.Family.Id == family.Id]

        if existing:
            instance = existing[0]
            loc = instance.Location
            if loc is not None and hasattr(loc, "Point"):
                delta = target - loc.Point
                if delta.GetLength() > 1e-9:
                    tManager.EnsureInTransaction(doc)
                    ElementTransformUtils.MoveElement(doc, instance.Id, delta)
                    tManager.ForceCloseTransaction()
        else:
            symbol = doc.GetElement(list(family.GetFamilySymbolIds())[0])
            tManager.EnsureInTransaction(doc)
            if not symbol.IsActive:
                symbol.Activate()
            instance = doc.Create.NewFamilyInstance(origin, symbol, str_type)
            ElementTransformUtils.MoveElement(doc, instance.Id, target)
            tManager.ForceCloseTransaction()

        return to_ds(instance), to_ds(family), None

    except:
        try:
            tManager.ForceCloseTransaction()
        except:
            pass
        return None, None, traceback.format_exc()
    finally:
        for p in (sat_file, rfa_path):
            try:
                if p and os.path.exists(p):
                    System.IO.File.Delete(p)
            except:
                pass

if len(geom) == len(names):
    n = len(geom)
    results = [create_solid_family(g, nm, c, m, s)
               for g, nm, c, m, s in zip(geom, names, pad(categories, n), pad(materials, n), pad(subcats, n))]
else:
    results = [(None, None, "Ensure each geometry has a unique family name.")]

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

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

and PS material in that with only work if it already is in the template…but can easy be done after run, even as family parameter or shared family parameter in the project file ;)…just another script