Hello,
I am trying to get the host of an instance family, but not quite getting it:
Thank you
It’s not uncommon for certain properties to also have matching parameters. In many of these cases the parameter returns a more user-friendly string. In this case you’re better off getting the element from the property itself, which will require the API.
Host Property
Thank you Nick,
I guess my question is:
why the name of the host element is showing in the property panel (as a string parameter), but there is no way to obtain the actual element, even using 4 different packages’ nodes?
I mean, if 4 different packages / authors / developers couldn’t figure out how to retrieve the host, I feel like I shouldn’t even try to go into the API and try myself…
Regards
PS: the “Host” property of the instance element returns null… despite, again, there is the host element described as a string in the Host parameter.
Hi,
here is an solution with Python
import clr
import sys
import System
#
clr.AddReference('ProtoGeometry')
from Autodesk.DesignScript.Geometry import *
import Autodesk.DesignScript.Geometry as DS
#import Revit API
clr.AddReference('RevitAPI')
import Autodesk
from Autodesk.Revit.DB import *
import Autodesk.Revit.DB as DB
#import transactionManager and DocumentManager (RevitServices is specific to Dynamo)
clr.AddReference('RevitServices')
import RevitServices
from RevitServices.Persistence import DocumentManager
from RevitServices.Transactions import TransactionManager
doc = DocumentManager.Instance.CurrentDBDocument
def getHostLink(elem):
if hasattr(elem, "Host"):
hostRvt = elem.Host
hostfaceref = elem.HostFace
if isinstance(hostRvt, RevitLinkInstance):
linkdoc = hostRvt.GetLinkDocument()
hostelem = linkdoc.GetElement(hostfaceref.LinkedElementId)
return hostelem
#
#the familyInstance is not hosted on a linkModel
return None
toList = lambda x : x if hasattr(x, "__iter__") and not isinstance(x, (str, System.String)) else [x]
#Preparing input from dynamo to revit
lstelems = toList(UnwrapElement(IN[0]))
OUT = [getHostLink(x) for x in lstelems]
I wrote an article on this subject some time ago.
Hi, thanks, but I am not working with linked models…
PS: it appears it is not possible to login on the web with one account while working in an Autodesk product with another account… hence, the two different user handles.
Exactly. This is one of the instances where the element reads as a string and is actually stored as a string. My original point is that there’s a difference between a parameter and a property. The parameter (that you’re showing in the screenshot) is just a string representation of the Host property. The parameter has no reference to the actual element. In order to get the element you need to access the property.
Again, this is a misunderstanding of the issue. Those are nodes for accessing parameter information. That will not work for properties. It’s a completely different method. Using the correct method will get you the info that you want. And if you look at the method, it’s actually super straight forward at its base implementation (there are additional considerations when dealing with links, but it’s still not too much).
Cyril showed a method for linked hosts before I could post my example, but here’s the most basic case for the property (without links).
If you’re having issues with either implementation, then you need to share a screenshot so that we can help you troubleshoot.
Thank you Nick.
I did share the screenshot with my issue, first thing in my thread.
The issue I am having is with loadable families that are not “native” children, like railings, or door, or windows.
As in my screenshot, the FamilyInstance is a “road” category that is level based, albeit it does have a “Host” value as well.
The “Host” property in Python does not return the toposolid indicated in the “Host” value (“Toposolid: Asphalt”), in my specific case.
The Genius Loci node seems the most complete attempt at finding a host, since it attempts more methods and properties, and it returns the Level the FamilyInstance belongs to, if everything else fails. (You can open the node and see the code).
It follows a script I scavenged from the web, that tries different properties (FamilyInstance, HostedSweep, HostId) and also returns a “reason”, or how the host was found:
# Dynamo input: IN[0] - Revit element or list of elements
import clr
clr.AddReference("RevitServices")
from RevitServices.Persistence import DocumentManager
clr.AddReference("RevitAPI")
from Autodesk.Revit.DB import *
doc = DocumentManager.Instance.CurrentDBDocument
def get_host_info(element):
host = None
reason = ""
if isinstance(element, FamilyInstance):
if element.Host is not None:
host = element.Host
reason = "Found via .Host"
elif element.HostFace is not None:
ref = element.HostFace
host = doc.GetElement(ref.ElementId)
reason = "Found via .HostFace"
else:
reason = "FamilyInstance has no Host or HostFace"
elif isinstance(element, HostedSweep):
if element.HostId != ElementId.InvalidElementId:
host = doc.GetElement(element.HostId)
reason = "Found via HostedSweep.HostId"
elif hasattr(element, "HostId"):
hostId = element.HostId
if isinstance(hostId, ElementId) and hostId != ElementId.InvalidElementId:
host = doc.GetElement(hostId)
reason = "Found via generic .HostId"
else:
reason = "No known host handling for this type"
return (host, reason)
# Handle single element or list
input_elements = UnwrapElement(IN[0])
if not isinstance(input_elements, list):
input_elements = [input_elements]
results = [get_host_info(el) for el in input_elements]
# Output: list of (host, reason) tuples
OUT = results
This is helpful.
I was only asking for a screenshot of the two python solutions since you said at least one of those was failing as well. I’m not familiar with the Road category so I don’t really know what methods are available to it off the top of my head, but there should be a property that stores that Host element. If you don’t have RevitLookup installed I highly recommend you get it and use it to parse the methods that element has available to it. It’s a great tool for learning the API and understanding the objects you’re working with.
Looking into this a little more, the issue is likely that your family definition doesn’t actually contain a host object. If you created a non-hosted family then the host property doesn’t work - even though Revit still picks up the object (or level) the instance is physically located on. Can you confirm whether the family was built with a host object or not?
Nick,
good lead.
Digging a bit deeper into the family I discovered that setting it to Work Plane Based will make the Host be revealed in Dynamo.
Also, a Face-Based family will work (as you asked to test).
I believe that this must be one of those Revit API inconsistencies, since there are no reasons why the host of the original family, even when shown in the properties constraints, is not revealed in Dynamo / API.
Or maybe it is the opposite: a non-hosted family, NOT work-plane based, should not have a host field, and should not have a “Pick new host” button…?
Thank you again.