Face of a linked element
This article is a continuation of my previous article, "Highlight Linked Element." Here, we will explore how to place a face-based family on a face of an element within a linked document in Revit.
The concept builds on the ideas from my previous article but includes additional implementations. When we place a family on a face, the relationship is established via a Reference. This means that the created family instance will register the host element by its reference. Scott Wilson provides an excellent explanation (blogged by Jeremy Tammik) that clarified my understanding of how a reference is structured.
With that foundation, let’s dive into the code that illustrates how to obtain a reference to a face of an element in a linked document.
Step-by-Step Process
Pick an Element by Point: Use
UiDocument.Selection.PickElement(ObjectType.PointOnElement)
to select an element by a point.Extract the Necessary Information: After selection, you will have:
The a translated reference of the face in the host document
The Revit link instance
The Revit link document
The original element selected (not the face itself)
Loop Through Geometry Faces: With the gathered information, loop through the geometry faces and compare each face's reference to the reference you selected.
Handle Translated References: Note that the reference you picked is translated to align with the host document and the linked Revit instance. Use the following statement to restore the reference to its original form
originalReference = linkedReference.CreateReferenceInLink();
Code Example
Below is an example code snippet that highlights the face as a test, ensuring the Reference we picked is the expected face.
var linkedReference = UiDoc.Selection.PickObject(ObjectType.PointOnElement);
var rvtInstance = linkedReference.ElementId.GetElement<RevitLinkInstance>();
var originalReference = linkedReference.CreateReferenceInLink();
var linkedDocument = rvtInstance.GetLinkDocument();
var originalElement = linkedDocument.GetElement(linkedReference.LinkedElementId);
var geo = originalElement.get_Geometry(
new Options()
{
DetailLevel = ViewDetailLevel.Undefined,
IncludeNonVisibleObjects = true,
ComputeReferences = true
}
);
Face seekedFace = null;
var solids = geo.OfType<Solid>().ToList();
// incase the selected element is solid then we need to get the solids
// from the GeometryInstances
solids.AddRange(geo.OfType<GeometryInstance>().SelectMany(o=> o.SymbolGeometry.OfType<Solid>()));
string originalReferenceString = originalReference.ConvertToStableRepresentation(
linkedDocument
);
foreach (var solid in solids)
{
if (seekedFace != null)
break;
foreach (Face face in solid.Faces)
{
if (face.Reference == null)
continue;
if (
originalReferenceString.EndsWith( face.Reference.ConvertToStableRepresentation(linkedDocument))
)
{
seekedFace = face;
break;
}
}
}
if (seekedFace != null)
{
// now we have the face, we can do what we need with that
// I reTranslated the reference back to the host document
// to cross check the above works as it should
var highlightReference = seekedFace.Reference.CreateLinkReference(rvtInstance);
UiDoc.Selection.SetReferences([highlightReference]);
}
else
{
// Face not Found :(
}
One effective use of selecting a face of a linked model is placing a face-based hosted family on that linked face. Since the reference is already established, you can utilize this reference as an argument when creating a face-based family. For instance, by picking a face on a linked element, you can directly host a lighting fixture or other face-based families, ensuring precise alignment with the linked model. Below is an example that illustrates this process.
var famSymbol = // you need to know what familySymbole
Trans.Start(); // start transaction
Doc.Create.NewFamilyInstance(
linkedFaceReference,
linkedFaceReference.GlobalPoint,
XYZ.BasisZ,
famSymbol
);
Trans.Commit(); // commit Transaction
Subscribe to my newsletter
Read articles from Moustafa Khalil directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by
Moustafa Khalil
Moustafa Khalil
I'm Moustafa Khalil El-Sayed, an Egyptian native with a passion for architecture and technology. After completing high school in 1999, I embarked on my journey into architecture, earning my Bachelor's degree in Architecture in 2004. My academic pursuits continued, and I later acquired my Master's degree in Architecture from Wings University. However, my thirst for knowledge extended beyond architectural design, leading me to pursue a degree in Computer Science as well. Driven by a desire to innovate, I began self-teaching computer science, which later empowered me to achieve my Associate degree in Computer Science from the University of the People more easily. Armed with dual expertise in architecture and computer science, I've cultivated a unique skill set that blends creativity with technical acumen. My career has taken me across borders, from Egypt to Oman and the UAE, where I've honed my skills as an architect. As a graduate architect and a proficient .NET BIM Solution Developer, I specialize in translating unique visions into tangible realities. My role extends beyond conventional architectural practices; I leverage technology to streamline processes and enhance project outcomes. My journey into programming began with developing script-based Excel tools to augment project management efforts, notably during the Sharm El Sheikh development. Over time, I expanded my programming prowess to address practical challenges encountered in bridging Revit and AutoCAD within my professional sphere. Several of my applications, born from this evolution, have gained recognition, with some even being featured on the Autodesk website. I am committed to pushing boundaries and continually enriching the intersection of architecture and technology, ensuring that my clients benefit from cutting-edge solutions tailored to their needs.