FamilyInstance.ByGeometry not working in Revit 2022

Hello! Just wanted to let you know I solved this issue by using FamilyType.ByGeometry and FamilyInstance.ByPoint

For the family to be scaled correctly, I scaled the geometry to the units of the model and for the insertion point of the family I used a Bounding Box and the MinPoint to have the family be placed correctly.

def insertion_point(cells):
  points = []
  for cell in cells:
    bounding_box = cell.BoundingBox
    point = bounding_box.MinPoint
    points.append(point)
  return points
5 Likes

The Springs node FamilyInstance.ByGeometry still not working in Revit 2022. Anyone know why? Thanks a lot.

1 Like

It is not being updated, probably the creator has no time to do it

Hi, i’m having the same issue, i relied on spring nodes, but now i updated Revit 2022 and i’m stuck. I simply have to place a generic model family where i created a solid, but FamilyType.ByGeometry and FamilyInstance.Bypoint gives me family which is not scaled. How can i automatically set the scale?

Hi! What I did is scaled it “manually” Dynamo (see the image I linked on May 28). There should be a way to scale it automatically by converting the units in a Python Script depending on the Revit project units but just added the Geometry.Scale node. I hope this helps.

1 Like

I assume because of line 63 in the Python Node
GetFormatOptions(UnitType…
https://www.revitapidocs.com/2021.1/ca0891ed-ec2d-5a8b-8bc0-79ff5ff98ee5.htm

"This method is deprecated in Revit 2021 and may be removed in a future version of Revit. Please use the `GetFormatOptions(ForgeTypeId)` overload instead."

Have a look at Solved: Re: ForgeTypeId how to use? - Autodesk Community to get more info about that change in the API.

Maybe there is even more need to adjustment in the Python code.

1 Like

Hi, does anyone solved this? This springs node is very important. Still not working in 2022. Anyone knows how to contact spings nodes developer?

Yes - I was able to fix it. Basically it was a matter of replacing the DisplayUnit API references with newer ForgeTypeId methods and also repairing the SAT scaling methods (2022 is a little different). I’ll find the changes and post them next week.

That said - the node won’t work 100% the same in 2022 as it did previously. In testing I found that some SATs that imported fine as solids in Revit 2020 suddenly import as meshes (boo!!!) in Revit 2022. It’s likely fine for 99% of the geometry out there but every once and a while you might encounter this issue.

In the meantime you could always roll back whatever work you are doing to Revit 2020 (ifc the job in Revit 2022 and link/import into Revit 2020 for a prev version hack), do your Dynamo work to make the families, group the families in the Revit 2020 version of the job, then save the group and load it into Revit 2022.

1 Like

Perhaps use of the relevant data in a Data.Remember node from Generative Design, and then opening the graph in Revit 2021 would work to generate the file. Link in and bind as before.

Replace the these two lines in the Python as shown below:

#units = doc.GetUnits().GetFormatOptions(UnitType.UT_Length).DisplayUnits
#factor = UnitUtils.ConvertToInternalUnits(1,units)
units = doc.GetUnits().GetFormatOptions(SpecTypeId.Length).GetUnitTypeId()
factor = UnitUtils.ConvertToInternalUnits(1,units)

Additionally, I had to change the SAT import unit portion of the code as shown here:

#satOpt.Unit = ImportUnit.Foot
#satOpt.Unit = ImportUnit.Default
satOpt.Unit = ImportUnit.Custom
satOpt.CustomScale = 1/3.280839895
8 Likes

I’ve tried to replace the code but I’m getting this error:

Traceback (most recent call last):
File “”, line 145, in NewForm_background
Exception: The active document may not be closed from the API.

Any ideas?

You’d have to at a minimum show what the code around line 140-150 is. Even better would be to show the whole graph. I am wondering if you failed to provide a name for the new family instance so it is unable to save/close a file that it creates in the background.

First, thank you for replying so fast…
I’m sorry, here it is the simple graph and the python code:

image

#Copyright(c) 2016, Dimitar Venkov
# @5devene, dimitar.ven@gmail.com

import clr
import System
from System.Collections.Generic import *

from itertools import repeat

pf_path = System.Environment.GetFolderPath(System.Environment.SpecialFolder.ProgramFilesX86)
import sys
sys.path.append('%s\IronPython 2.7\Lib' %pf_path)
import traceback

clr.AddReference('ProtoGeometry')
from Autodesk.DesignScript.Geometry import *
from Autodesk.DesignScript.Geometry import Point as DynPoint

clr.AddReference('RevitServices')
import RevitServices
from RevitServices.Persistence import DocumentManager
from RevitServices.Transactions import TransactionManager
doc = DocumentManager.Instance.CurrentDBDocument

clr.AddReference('RevitAPI')
from Autodesk.Revit.DB import *
from Autodesk.Revit.DB.Structure import StructuralType

clr.AddReference('RevitNodes')
import Revit
clr.ImportExtensions(Revit.Elements)
clr.ImportExtensions(Revit.GeometryConversion)

def tolist(obj1):
	if hasattr(obj1,'__iter__'): return obj1
	else: return [obj1]

def PadLists(lists):
	len1 = len(lists[0])
	for i in xrange(1,len(lists)):
		len2 = len(lists[i])
		if len2 == len1 : continue
		elif len2 > len1: lists[i] = lists[i][:len1]
		else : lists[i].extend(repeat(lists[i][-1],len1 - len2))
	return lists

class FamOpt1(IFamilyLoadOptions):
	def __init__(self):
		pass
	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])
category = tolist(IN[3])
material = tolist(IN[4])
isVoid = tolist(IN[5])
subcat = tolist(IN[6])

units = doc.GetUnits().GetFormatOptions(SpecTypeId.Length).GetUnitTypeId()
factor = UnitUtils.ConvertToInternalUnits(1,units)
acceptable_views = ('ThreeD', 'FloorPlan', 'EngineeringPlan', 'CeilingPlan', 'Elevation', 'Section')
origin = XYZ.Zero
str_typ = StructuralType.NonStructural
t1 = TransactionManager.Instance
temp_path = System.IO.Path.GetTempPath()
invalid_chars = System.IO.Path.GetInvalidFileNameChars()
satOpt = SATImportOptions()
satOpt.Placement = ImportPlacement.Origin
satOpt.Unit = ImportUnit.Custom
satOpt.CustomScale = 1/3.280839895
opt1 = Options()
opt1.ComputeReferences = True
SaveAsOpt = SaveAsOptions()
SaveAsOpt.OverwriteExistingFile = True

def NewForm_background(s1, name1, cat1, isVoid1, mat1, subcat1):
	try:
		enable_mat = False if mat1 is None else True
		enable_subcat = False if subcat1 is None else True
		if any( (c in name1 for c in invalid_chars) ):
			raise Exception('Family name contains invalid characters')
		TransactionManager.ForceCloseTransaction(t1)
		famdoc = doc.Application.NewFamilyDocument(fam_path)
		sat_path = '%s%s.sat' % (temp_path, name1)
		if factor != 1:
			s1 = s1.Scale(factor)
		vec1 = Vector.ByTwoPoints(BoundingBox.ByGeometry(s1).MinPoint, DynPoint.Origin())
		s1 = s1.Translate(vec1)
		sat1 = Geometry.ExportToSAT(s1, sat_path)
		view_fec = FilteredElementCollector(famdoc).OfClass(View)
		view1 = None
		for v in view_fec:
			if str(v.ViewType) in acceptable_views and not v.IsTemplate:
				view1 = v
				break
		t1.EnsureInTransaction(famdoc)
		satId = famdoc.Import(sat1, satOpt, view1)
		el1 = famdoc.GetElement(satId)
		geom1 = el1.get_Geometry(opt1)
		enum = geom1.GetEnumerator()
		enum.MoveNext()
		geom2 = enum.Current.GetInstanceGeometry()
		enum2 = geom2.GetEnumerator()
		enum2.MoveNext()
		s1 = enum2.Current
		famdoc.Delete(satId)
		System.IO.File.Delete(sat_path)

		save_path = '%s%s.rfa' % (temp_path, name1)
		try: #set the category
			fam_cat = famdoc.Settings.Categories.get_Item(cat1.Name)
			famdoc.OwnerFamily.FamilyCategory = fam_cat
		except: pass
		s2 = FreeFormElement.Create(famdoc,s1)
		if isVoid1:
			void_par = s2.get_Parameter(BuiltInParameter.ELEMENT_IS_CUTTING).Set(1)
			void_par2 = famdoc.OwnerFamily.get_Parameter(BuiltInParameter.FAMILY_ALLOW_CUT_WITH_VOIDS).Set(1)
		else: #voids do not have a material values or a sub-cateogry
			if enable_mat:
				try:
					mat_fec = FilteredElementCollector(famdoc).OfClass(Material)
					for m in mat_fec:
						if m.Name == mat1:
							fam_mat = m
							break
					mat_par = s2.get_Parameter(BuiltInParameter.MATERIAL_ID_PARAM).Set(fam_mat.Id)
				except: pass
			if enable_subcat: #create and assign the sub-category:
				try:
					current_fam_cat = famdoc.OwnerFamily.FamilyCategory
					fam_cat_subs = current_fam_cat.SubCategories
					if fam_cat_subs.Contains(subcat1):
						new_subcat = fam_cat_subs[subcat1]
					else:
						new_subcat = famdoc.Settings.Categories.NewSubcategory(current_fam_cat, subcat1)
					s2.Subcategory = new_subcat
				except: pass
		TransactionManager.ForceCloseTransaction(t1)
		famdoc.SaveAs(save_path, SaveAsOpt)
		family1 = famdoc.LoadFamily(doc, FamOpt1() )
		famdoc.Close(False)
		System.IO.File.Delete(save_path)
		symbols = family1.GetFamilySymbolIds().GetEnumerator()
		symbols.MoveNext()
		symbol1 = doc.GetElement(symbols.Current)
		t1.EnsureInTransaction(doc)
		if not symbol1.IsActive: symbol1.Activate()
		inst1 = doc.Create.NewFamilyInstance(origin, symbol1, str_typ)
		ElementTransformUtils.MoveElement(doc,inst1.Id, vec1.Reverse().ToXyz() )
		TransactionManager.ForceCloseTransaction(t1)
		return inst1.ToDSType(False), family1.ToDSType(False)
		
	except:
		return traceback.format_exc(),''

if len(geom) == len(names) == len(category) == len(isVoid) == len(material) == len(subcat):
	return1 = map(NewForm_background, geom, names, category, isVoid, material, subcat)
elif len(geom) == len(names):
	padded = PadLists([geom, category, isVoid, material,subcat])
	p_category, p_isVoid, p_material, p_subcat = padded[1], padded[2], padded[3], padded[4]
	return1 = map(NewForm_background, geom, names, p_category, p_isVoid, p_material, p_subcat)
else : return1 = [('Make sure that each geometry\nobject has a unique family name.', '')]
OUT = [i[0] for i in return1], [i[1] for i in return1]
satOpt.Dispose()
opt1.Dispose()
SaveAsOpt.Dispose()
  1. You may need other satOpt.Unit and satOpt.CustomScale settings - I’m in US so I had to do a metric to imperial conversion (1/3.2808) - not your issue but I saw you using metric family so thought I’d point that out…

  2. Are you running this from a family or from a project? Hopefully from a project because the script would be trying to make a family called MassWall.rfa and if you have a family open already with that name (or worse you are running it from the family with that name) I could see that not working out nicely.

One thing you might find helpful (it helps me when I’m troubleshooting) is to copy/paste the contents of the custom node out and put them in the main dyn. then freeze the custom node and work on the python script in the main dyn (you’ll often get more info on what the issue is when the python fails). Then when you get it succesfully running - just copy the python code and paste it back into the custom node.

1 Like

Hi Ben / Forum

I am having the same issue with the spring nodes FamilyInstance.ByGeometry node. On simple geometry it works ok, but when I try more complex geometry I get the mesh issue you described in an earlier post on this thread.

Can I ask what you suggest at this moment in time as a workflow to get complex dynamo geometry into Revit? Do you think this node will be updated, or did you find a solution? Sorry if I missed this.
I tried replacing the python code as you suggested with no luck.

I received the same warning:

File ", line119, in NewForm_background
TypeError: expected Solid, got Mesh

Any help would be greatly appreciated.

Many thanks
Tim

I do this…

1 Like

Hi Ben

Thank you very much for your reply. Yes you are right this works really well - the spring nodes node works so well in 2020, I really hope this can be updated or a good OOTB node can be made for geometry into Revit for 2022 + going forwards.

Thanks again
Tim

Tim-
That would be awesome if someone could come up with a fix - but it would surely be complex because it would require the instance of Dynamo that is running in Revit 2022 to fire up an instance of Revit 2020 and do the family creation in that version, then save the family and have it then load into Revit 2022. Seems very difficult (getting Dynamo to operate on multiple versions of Revit simultaneously).

Bottom line - something either in the methodology that Revit is using to convert the .sat into a DirectShape in the Revit Family or something that Revit is using to export the .sat has changed from previous versions in that the same .sat will be a solid in Revit 2020 but a mesh in Revit 2022 (in some instances). My suspicion (and this could only likely be confirmed by someone on the Revit development side) is that there was a “face count” limit placed in Revit 2022 that automatically makes that import as a mesh if the number of faces exceeds some threshold limit - leaving us kind of without much option except a clunky workaround of going back to the old version that worked in a much friendlier manner.

Below is a link to a .sat file generated out of Revit 2022 if anyone (…“cough” Autodesk employed “cough”…) wants to test and confirm this behavior. Import this .sat into a Revit 2020 family and you get a “Solid”. Import it to a Revit 2022 family and you get “Mesh”. Same .sat = different results. Inconsistency = :frowning:

Hi Ben

Thank you again for this. I wasnt actually thinking/suggesting anyone should make a workaround fix, but hoping the Spring Nodes node could be updated to work with the Revit 2022 changes, or as you say Autodesk come up with a proper OOTB node for this workflow - it really limits Dynamo/Revit for modelling, compared to using other softwares.

Thanks again
Tim

Have you tried the FamilyType.ByGeometry node?

https://dictionary.dynamobim.com/#/Revit/Elements/FamilyType/Create/ByGeometry