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?
4 years after
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
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



