Bimorph nodes v2.2 adds holistic support for linked-element clash detection with new LinkElement nodes


#1

BIMORPH NODES V2.2 ADDS HOLISTIC SUPPORT FOR LINKED-ELEMENT CLASH DETECTION WITH NEW LINK-ELEMENT NODES

Dear Dynamo aficionados

Bimorph nodes v2.2 is now available for download via the Dynamo Package Manager.

BimorphNodes v2.2 introduces the new LinkElement class nodes to Dynamo which are purpose-built for retrieving elements from linked Revit models. While this functionality has existed for some time in a number of other packages, what makes LinkElements unique are the range of additional properties and features they implement that solve a major limitation in the Revit API (and therefore Dynamo) concerning the location of linked elements within their host file.

The other significant update in v2.2, also related to this issue, is the addition of holistic support for linked element clash detection using any of the Bimorph Element and BoundingBox nodes. LinkElements serve a vital role in enabling this functionality, resulting in a range of nodes that are no longer impeded by the problems that arise from limitations in the Revit API.

BimorphNodes v2.2 overview:

  • New LinkElement class nodes for rapid interop with elements from linked Revit models
  • Element.IntersectsElement, Element.IntersectsSolid, BoundingBox.GetElementsInside and BoundingBox.GetElementsIntersect nodes provide holistic support for linked elements
  • Clash detection codebase micro-optimised, resulting in 15-25% performance increase
  • CurveFromCADLayers refactored with improved support for view-specific CAD links
  • Curve.RemoveDuplicates 80% performance increase
  • Built on the Revit 2017 API (support for Revit 2015 dropped)
  • Efficiency enhancements and general stability improvements

WHATS NEW

New LinkElement Class Nodes

The new LinkElement class includes a range of methods and properties for retrieving and interacting with Elements from a linked Revit model (a Link Instance). What makes LinkElements unique are the way they handle the location of the element in coordinate space. There is a limitation in the Revit API which restricts any element derived from a Link Instance to its external files origin-to-origin location regardless of any transformations that may have been made to the Link Instance. LinkElements have been purpose-built to solve this limitation by performing operations on the linked element, such as geometry extraction, at its host location.

To create LinkElement instances use the LinkElement.OfCategory node:
LinkElement-OfCategory-BimorphNodes-v2-2

Properties and metadata attached to the LinkElement instance can be accessed using the LinkElement property nodes. The Solids, Faces, Location and BoundingBox nodes return the resultant geometry at the LinkElements host location by default (not its origin-to-origin location):

LinkElement-Geometry-Properties-BimorphNodes-v2-2

There are also property nodes to access its associated Link Instance id, total transform and the embedded Dynamo Revit Element:

LinkElement-Metadata-Properties-BimorphNodes-v2-2

LinkElements Solve the Revit API Linked Element Transform Limitation

The linked element transform limitation manifests only in the Revit API context, which subsequently exposes a number of BimorphNodes to the problem. As mentioned, this limitation causes linked elements to default to their external files origin-to-origin position, even if the elements Link Instance has been transformed in the host document. The Revit projects most at risk of this problem are those where transformations have been applied to the Link Instance for coordination purposes, which is likely if Shared Coordinates are in use or if linked models have been manually moved to align with the main building model.

The problem is most pronounced when calling Revit API methods on a linked element where its relative location in the host file is required to yield a result. For example, the Revit API ElementQuickFilter and ElementSlowFilter class methods – which are used for clash detection in the BimorphNodes BoundingBox and Element nodes – produce erroneous results if element A vs B includes any linked elements which have been transformed. This is especially confusing to users since any linked Revit models which are moved to visually align with other links or live elements in the host file, are always positioned back at their respective origin-to-origin locations in the API context, causing the clash results to fail unexpectedly.

The following example illustrates the problem, showing the position of bounding boxes created in the API context from linked wall elements while its Link Instance is transformed. One would expect the bounding boxes to be drawn where the walls are positioned in the host model, but the Revit API limits them to the links origin-to-origin location:

LinkElements solve this limitation by handling linked elements at their host location (where you see it in Revit) and not the origin-to-origin location imposed by the Revit API:

Optimised for BimorphNodes Element and BoundingBox Nodes

LinkElements are optimised for use with BimorphNodes Element and BoundingBox nodes, firstly to ensure they remain ultra-efficient, and secondly to enable them to support linked elements regardless of any transformations made to their associated Link Instance in the host file.

However, the creation of the LinkElement class to enable this new functionality has had consequences; any custom code or package which collects elements from a linked Revit model (SpringNodes, Archi-lab, SteamNodes, etc) are no longer supported. The decision to drop support was due to:

  • There being no direct way to identify a linked elements Revit Link Instance through the API, which is critical as it stores the total transform (coordinate system) needed to locate the element at its host location. The Link Instance can be obtained indirectly by accessing the elements Document property, but this simple technique crippled performance, causing speed-of-execution to drop by more than 250%!

  • Moreover, even if this approach was adopted, it’s flawed as the available data provides no means to reliably identify a Link Instance if it has been linked multiple times in the same file

Settling for compromised functionality that would have prohibited unlimited support of Link Instances (it would have limited each link to 1 per document!) and crippled performance, was unacceptable, and this led to the development of the LinkElement class and the decision to make it exclusive.

The LinkElement class therefore plays a vital role in enabling the new linked element support in the Bimorph Element and BoundingBox nodes.

LinkElements Inherit Dynamo’s Element Class

To maximise functionality, LinkElements inherit from Dynamo’s Revit.Elements.Element class, meaning instances are compatible with all of Dynamo’s Element nodes and any other nodes that accept Elements as inputs.

There are some limitations with certain nodes in Dynamo’s Revit library that will not recognise LinkElements. For example, LinkElement Room’s are not compatible with the OOTB Room nodes, such as Room.Number. To resolve these issues, use the LinkElement.Element node to extract the wrapped Revit element (i.e. the Dynamo Revit Element) stored in the LinkElement and pass it into any nodes that are affected by this problem:

LinkElement-Dynamo-Element-BimorphNodes-v2-2

One drawback of extracting the Element is the loss of properties provided by the LinkElement. It means that any operations, such as geometry extraction, revert back to the linked elements origin-to-origin location. To manually resolve this issue, use the OOTB Geometry.Translate node and input the corresponding LinkElements TotalTransform as the ‘context coordinate system’. The ‘from coordinate system’ is always Identity:


HOLISTIC SUPPORT FOR LINKED-ELEMENT CLASH DETECTION

The Element.IntersectsElement, Element.IntersectsSolid, BoundingBox.GetElementsInside and BoundingBox.GetElementsIntersect have been updated with a new clash detective algorithm which enables holistic support for linked elements even if their Link Instances have been transformed or translated. It means that the limitation imposed on linked elements by the Revit API, which before the update impeded their functionality, is now fully resolved.

To enable this support the nodes depend on the new LinkElement class and leverage its properties to locate linked elements at their host locations. By utilising LinkElements, the nodes can be used to develop unique and highly versatile workflows that range from supporting linked elements from an unlimited number of Link Instances (ideal for large-scale residential schemes and master plans where multiple Link Instances are common), to linked element vs linked element clash detection, even if the elements derive from multiple Link Instances with different origin-to-origin locations (a problem which has no direct solution in the Revit API).

The nodes also implement a smart logic-tree which is designed to execute only the subroutines that are relevant to conditions of the intersection test being computed. The logic tree is central to minimising any performance overheads that arise from the new infrastructure, resulting in near-negligible compromises to speed-of-execution.

Summary of new features:

  • Resolves the Revit API limitation imposed on linked elements
  • Supports elements from an unlimited number of Link Instances
  • Smart logic-tree minimises performance overheads of new functionality
  • Micro-optimised

How it Works

Providing the Element and BoundingBox nodes with holistic support for linked elements has not resulted in any changes to their inputs or outputs as all the updates have occurred internally. Therefore, using LinkElements with these nodes is no different to using Elements; simply collect the required linked elements using the LinkElement.OfCategory node, then provide the resultant LinkElement instances as inputs.

The following graph shows how to utilise LinkElements with the Element.IntersectsElement node to perform multi-category linked element clash detection, without being impeded by the Revit API limitations:

Utilising LinkElements with the BoundingBox.GetElementsIntersect node:

Are There Performance Impacts?

To enable holistic support for linked elements the codebase for the Element.Intersects nodes and BoundingBox nodes has grown significantly. The new infrastructure includes subroutines that are executed based on the conditions of the element input (ordinary Element, non-LinkElement, LinkElement or tranformed LinkElement) and include all the logic to resolve the limitations of linked elements imposed by the Revit API.

With more executable commands, it stands to reason that performance will be impacted. Yet, a key objective of BimorphNodes v2.2 was to resolve the linked element limitation and minimise the impacts on performance. Achieving this goal was made possible by:

  1. Creating of the LinkElement class, and optimising it for use with the BoubdingBox and Element.Intersects nodes
  2. Micro-optimising the codebase
  3. Building BimorphNodes on the Revit 2017 API

To answer the question then: there have been no noticeable impacts on performance, despite the new infrastructure. Speed-of-execution has actually got faster, resulting in at least a 15% increase in performance.

The following table shows the speed-of-execution improvements between v2.1 and v2.2 Element.IntersectsElement node. For the purposes of comparison, the Walls vs Ducts clash test conducted in BimorphNodes v2.1 to evaluate the performance of the Element.IntersectsElement node is used as the benchmark:

Performance Comparison Matrix

The following table shows the performance comparison between the various combinations of live Elements vs LinkElements controlled by the logic tree. The test conditions use the same Walls vs Ducts model mentioned in the ‘Performance Impacts’ section above:

Computation times shown in seconds. Walls (2,300) vs Ducts (2,160). Total Possible Clash Tests: 4,968,000 | Transformed LinkElements are moved, rotated and mirrored from their origin-to-origin location | Tested on: Windows 10, Revit 2018.2, Dynamo 1.3.2 and HP ZBook Intel i7-4710MQ 2.5GHz, 16GB DDR Memory, 256GB SSD

Validation Sampling

To support the transition to LinkElements, BimorphNodes BoundingBox and Element nodes include new exception handling to validate the list of elements input by the user. While this provides useful feedback if an invalid linked element is found, it reintroduces the performance impacts that led to the development of the LinkElement class in the first place (as the validation procedure must access each elements Document property to check if it is linked). To mitigate these impacts but still provide the advantages of element validation, a method of ‘validation sampling’ has been implemented.

Validation sampling selects a range of elements from the list at every interval using the equation: d / (5 + (0.01 * d)) where d = the count of items in the input list. Sampled elements are tested to verify if they are linked and where true, if they are instances of the LinkElement class. If any elements are linked but not LinkElements, the following exception is thrown:

Element-IntersectsElement-Exception-BimorphNodes-v2-2

Note that as a selection of elements are evaluated, there is potential non-valid linked elements can pass through the validation test if they are between the selection interval. However, the risks are negligible as the user would need to input a heterogeneous list interspersed with only a few invalid linked elements for this to occur. To eliminate the risk completely, always use LinkElements when your workflow requires them.

Mitigating ‘Dereferencing Non-Pointer’ Exceptions

There is known bug in Dynamo which throws a ‘dereferencing a non-pointer’ exception whenever a list of objects which contains either null or an empty list at index 0 (the start of the list) is input into any Query (property) node.

While most workflows are unlikely to be affected, it requires special mention since the Element.Intersects nodes are designed to output clash results via a 2D list (list of lists), where empty sub-lists indicate no clashes. Due to this behaviour, there is a higher probability that index 0 will be empty, making these nodes more susceptible to the bug.

As the Dynamo dev team have stated the bug is unlikely to be fixed by Dynamo v2.0, a simple workaround can be used in the interim by cleaning the list of empty sub-lists before passing it into any Query nodes using the OOTB List.IsEmpty and List.FilterByBoolMask. The following example shows a method for maintain the data-structure output by the Element.Intersects nodes after cleaning the list:


NEW UPDATES

CAD.CurvesFromCADLayers Adds View-Specific CAD Instance Support

CAD-CurvesFromCADLayers-BimorphNodes-v2-2

CurvesFromCADLayers includes new functionality to support curve conversion of any CAD link or import that is view-specific. In previous versions, curves from view-specific CAD instances would default to the sketch plane of the curve (typically the global XY plane at 0.0 elevation). In BimorphNodes v2.2 the node has been designed to translates curves to the sketch plane of the owner-view if the view is a plan, area plan or structural plan. All other view types do not have a sketch plane and remain unchanged in behaviour.

Curve.RemoveDuplicates Refactored and 80% More Efficient

Curve-RemoveDuplicates-BimorphNodes-v2-2

Curve.RemoveDuplicates has been refactored to improve the codebase and provide an opportunity to enhance its performance. The result of the refactoring has reduced typical processing times by up to 80%.

LineStyle.Create Breaking Changes

LineStyle-Create-BimorphNodes-v2-2

Building BimorphNodes on the Revit 2017 API has enabled access to the Line Style’s pattern property. In v2.2, LineStyle.Create now node includes the Line Styles pattern as an input to utilise this new functionality. Note that line patterns are not supported in Revit 2016 and will be ignored, defaulting to the Solid pattern instead. In addition, the Solid line style can be selected as it is not classed as a LinePatternElement and is not listed in Dynamo’s OOTB Line Patterns node. To mitigate this limitation, leave the input unconnected and the Line Pattern will default to Solid.

There has also been a breaking change due to the removal of the run input and introduction of the line pattern input. Upgrading will cause the node inputs to change order but not update the wires (i.e. the function inputs) – we therefore suggest manually updating any graphs which utilise the LineStyle.Create node.

Element.IsElementSupported Improved Results

Element-IsElementSupported-BimorphNodes-v2-2

Element.IsElementSupported includes new updates to enable it to return more consistent results and evaluate elements that BimorphNodes Element and BoundingBox nodes do not support, such as linked elements. The inconsistencies were caused by the Revit API method in use where some elements would report as ‘supported’ but its Category would report as ‘unsupported’ by the Element.IsCategorySupported. Both results must be true otherwise the element is not supported. The Revit Development team suggested this was ‘normal’ behaviour, and to combine the results. Hence, both tests are now performed to yield a result.

Element.IsCategorySupported Depreciated

Element-IsCategorySupported-BimorphNodes-v2-2

The Element.IsCategorySupported has been depreciated as it no longer serves any purpose due to the updates made to the Element.IsElementSupported node. To avoid any disruption to graphs, the node is still included in BimorphNodes v2.2 but hidden from the library – we recommend manually replacing this node with IsElementSupported as it will be removed completely by v3.0.


GET UPDATES

Don’t forget to check out our BimorphNodes content pages and YouTube channel for user guides and extra content. New video content will be added in due course; be sure to subscribe to get notifications:

BimorphNodes Dictionary
YouTube Channel

We’ve also recently moved the BimorphNodes dictionary to our new domain, Bimorph.com. Links for the old .co.uk domain automatically redirect, but we recommend updating any bookmarks and referring links to point to the new domain.


BIMORPH NODES V2.2 LIBRARY

List of BimorphNodes v2.2. Compatible with Revit 2016+ and Dynamo 1.2+:


Clash Detection in Bakery package not generating a list
Collect Elements which Interesects a Line
#2

Well documented and awesome work as always!


#3

Excellent work @Thomas_Mahon.

clap


#4

#5

Outstanding! Can’t wait to use it :+1:t2:


#6

Thanks @JacobSmall @Kulkul @Ewan_Opie great to hear! :+1::ok_hand::facepunch:


#7

Used it! Works amazingly faster than the conventional method. Great and Useful nodes @Thomas_Mahon


#8

Quick update: if you are using Dynamo v1.2 and couldn’t install BimorphNodes v2.2 the package has just been updated so its compatible with this version upwards.


#9

BimorphNodes v2.2.4 Minor Update Released

*BimorphNodes v2.2.4 has been released on the package manager. It includes fixes for the new LinkElement.OfCategory node.


#10

BimorphNodes v2.2.51 Minor Update Released

BimorphNodes v2.2.51 fixes a bug in the CurveFromCADLayers, Detail and SymbolicCurvesFromCADLayers nodes relating to polycurve conversion (only affects v2.2 series, due to the refactoring).


BimorphNodes Package Output Issue
#11

BimorphNodes v2.2.6 Minor Update Released

BimorphNodes v2.2.6 includes more efficiency enhancements to the clash detective algorithm (averaging 10% faster than v2.2.5) and a minor fix to the Element.IntersectsSolid node.

V2.2.6 Performance

Computation times shown in seconds. Walls (2,300) vs Ducts (2,160). Total Possible Clash Tests: 4,968,000 | Transformed LinkElements are moved, rotated and mirrored from their origin-to-origin location | Tested on: Windows 10, Revit 2018.2, Dynamo 1.3.2 and HP ZBook Intel i7-4710MQ 2.5GHz, 16GB DDR Memory, 256GB SSD

#12

BimorphNodes v2.2.7 Minor Update Released

BimorphNodes v2.2.7 adds support for hosting face-based families on linked elements. Simply use the LinkElement.Faces node to collect the faces required, then use one of Dynamo’s FamilyInstance.ByFace nodes to place the family:


#13

I’m getting an error with the Linked Element by Category node. I’m not sure if this is an issue with the node, but I’ve tried this with multiple structural links and I get the same error.

Index was outside the bounds of the array.

at ProtoCore.Lang.ArrayUtilsForBuiltIns.Transpose(StackValue sv, Interpreter runtime)
at ProtoCore.Lang.BuiltInFunctionEndPoint.Execute(Context c, List1 formalParameters, StackFrame stackFrame, RuntimeCore runtimeCore) at ProtoCore.CallSite.ExecWithZeroRI(List1 functionEndPoint, Context c, List1 formalParameters, StackFrame stackFrame, RuntimeCore runtimeCore, FunctionGroup funcGroup, SingleRunTraceData previousTraceData, SingleRunTraceData newTraceData) at ProtoCore.CallSite.Execute(List1 functionEndPoint, Context c, List1 formalParameters, List1 replicationInstructions, StackFrame stackFrame, RuntimeCore runtimeCore, FunctionGroup funcGroup)
at ProtoCore.CallSite.DispatchNew(Context context, List1 arguments, List1 partialReplicationGuides, DominantListStructure domintListStructure, StackFrame stackFrame, RuntimeCore runtimeCore)
at ProtoCore.DSASM.Executive.Callr(Int32 blockDeclId, Int32 functionIndex, Int32 classIndex, Boolean& explicitCall, Boolean isDynamicCall, Boolean hasDebugInfo)
at ProtoCore.DSASM.Executive.CALLR_Handler(Instruction instruction)
at ProtoCore.DSASM.Executive.Execute(Int32 exeblock, Int32 entry, Language language)
at ProtoCore.DSASM.Executive.Execute(Int32 exeblock, Int32 entry, List1 breakpoints, Language language) at ProtoCore.DSASM.Executive.BounceUsingExecutive(Executive executive, Int32 exeblock, Int32 entry, StackFrame stackFrame, Int32 locals, Boolean fepRun, Executive exec, List1 breakpoints)
at ProtoScript.Runners.ProtoScriptRunner.ExecuteLive(Core core, RuntimeCore runtimeCore)
at ProtoScript.Runners.LiveRunner.Execute(Boolean isCodeCompiled)
at ProtoScript.Runners.LiveRunner.CompileAndExecute(List1 astList) at ProtoScript.Runners.LiveRunner.CompileAndExecuteForDeltaExecution(List1 astList)
at ProtoScript.Runners.LiveRunner.SynchronizeInternal(GraphSyncData syncData)
at ProtoScript.Runners.LiveRunner.UpdateGraph(GraphSyncData syncData)
at Dynamo.Scheduler.UpdateGraphAsyncTask.HandleTaskExecutionCore()
at Dynamo.Scheduler.AsyncTask.Execute()


#14

Hi @brunelli.b Sounds similar to the issue reported here on the Dynamo GitHub which may indicate a defect with the way Dynamo’s VM is handling some of your linked elements (you might have invalid elements in the files or some other form of corruption thats triggering the crash).

Have you tried opening the structure models directly and using ordinary OOTB nodes to collect the Structural Framing elements (All Elements of Category node for example) and does it reproduce the crash? If so, it’s best to report it on the GitHub otherwise if you believe the LinkElement node is the source of the problem please can you share a simple example file which reproduces the crash and I’ll investigate.


#15

Hi, i dont know if this is the correct place to make comments or question about Bimorph Nodes, sorry if my question is out of place.
I am using the sheet duplicate node and it works very well, saving us many time. I have a question about the images placed in sheets (jpg). They dont duplicate and i have to copy-paste them manually later.
What i am doing wrong? Is there a way to obtain the images in sheets duplicated?
Thank you very much for the nodes!!


#16

Hi @Luis_Herrero1 you’re doing nothing wrong, imported raster images placed directly on sheets are (or rather, were) not supported by the node; thanks for reporting this.

…it’s easy to add support so I’ve updated the node accordingly; you can find the update in BimorphNodes v2.2.8 available via the Package Manager.

And you should start a new thread for any questions unrelated to the OP title so others who might encounter this problem can easily find the solution should they search the forum.


#17

BimorphNodes v2.2.8 Minor Update Released

Update includes:

  1. Sheet.Duplicate node now supports raster images imported directly onto sheets
  2. Dynamo v2.0 compatibility: DefaultArgument input attribute updated to support the new list syntax change ([] from {}). Nodes affected/updated: all curve from CAD layer nodes and Curve.RemoveDuplicates node. Dynamo v1.2 and above now fully supported

#18

Wow, this is a very fast response!! Thank you very much for your support, We use to place a little JPG in almost every sheet with a small plan view as a reference, this improvement will save many time.

Thank you again.

Luis

PD: Downloaded and tested. Perfect!!


#19

BimorphNodes v2.2.9 Minor Update Released

Special support for RevitLinkInstances (a raw Revit API object) has been added to the LinkElement.OfCategory node.

This came about after numerous users reported input exceptions when inputting LinkInstances collected using nodes from other packages. These packages are returning raw Revit API RevitLinkInstances instead of wrapping them in Dynamo’s Revit wrapper class, making them unusable with any OOTB Dynamo node or with custom nodes that respect Dynamo’s object model…such as BimorphNodes. As some of these packages are widely in use, support for RevitLinkInstances has been added to mitigate the problems its causing.

For reliability, I recommend using OOTB Element Types (pick RevitLinkInstance) and All Elements of Type nodes to collect links as they do return the wrapped Revit elements. As a guiding principle, never use custom nodes if the same functionality exists OOTB:


#20

Nice work @Thomas_Mahon!

I also wanted to point out that the issue you mentioned regarding the links being returned as “raw” Revit DB element types is fixable by simply selecting the Revit Element with a quick python script to get the element id, in conjunction with the OOTB ElementSelector method.

(This is useful to demonstrate if someone is in an older version of Dynamo as the RevitLinkInstance has not always been an option in the ElementTypes node. I know clockwork had a get links node and so did archilab)

and the python script:

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

clr.AddReference("RevitNodes")
import Revit

links = UnwrapElement(IN[0])
dynamoLinkIds = []

for i in links:
	dynamoLinkIds.append(i.Id.IntegerValue)

OUT = dynamoLinkIds