Looking for a faster way to access linked CAD file geometry

Hello! I am working on a graph that checks two existing cad files and highlights any differences in the lines between them. This is to make it easy to find any changes made by store planning that were not explicitly told to us and could also be the framework for future graphs i will make that involve linked CAD files. I have it working properly on small test files. Unfortunately Accessing the geometry of a linked cad file with tens of thousands of elements takes extremely long. That process, paired with the part of the graph that checks and creates detail lines over any differences will cause dynamo to freeze indefinitely. I was wondering if there is a more efficient and less cpu intensive way to access linked cad geometry and lines, or at least a way to make the process more stable

Hi,
Have you tried with Bimorph package? It has a lot of cool stuff for linked CAD files

1 Like

I have tried using those. I was having trouble getting them to work properly as they only worked with imported (not linked) CAD files iirc. The bimorph nodes only access curves as well whereas the files I am looking at have a ton of other geometry that needs to be checked. I think the main thing holding up the graph is the element.geometry nodes and the detailcurve.bycurve nodes (when there are more than, say, 40 lines that are being generated).

I remade the graph using a different method in an attempt to make it run more efficiently but it is still freezing on larger files. It only works when I freeze the geometry node and just check for curves.

Hi @martin.scholl

The best way to check this is to use Time.LapTime nodes from clockwork and see where exactly it takes more time to execute.

2 Likes

Three quick thoughts (though not completely thought out - you’ll have to review each in more detail):

  1. Part of the issue is that you’re using an N^2 computation method - every geometry is checked against every other geometry. I’m working on a similar problem in my free time, and came into the same issue. I talked it over with a coworker (a major benefit of working at Autodesk), and he recommended I look into reducing my comparisons via an Octree special indexing method. This will ensure you only have to test data that has matching bounds - geometry which is in different indexes doesn’t have to be tested against your geometry. Yes you have to index all elements, but that is way quicker than the logical comparison, and only needs to be done once per item as opposed to once for every item to the every item power.
  1. Revit’s slow to draw lines in each transaction, doubly so if drawing them in bulk as you are with the detail curve.bycurve node. Instead I would recommend looking into other methods for recording the difference - perhaps writing to dwg via the LinkDWG package would be quicker.

  2. Why not do a PDF or cad/cad comparison instead of a Revit based effort, utilizing the BIM360 docs toolset?

5 Likes

Thank you everyone for replying and helping me figure this out. I found a method that seems to work. I put all of the sorting into a single python node because I wanted to get Revit geometry without converting it since that process adds a lot of time with ~60,000 elements. I put all of the sorting into the same node in an attempt to be more efficient and reduce ‘tessellation’ as per

Unfortunately, I had to use an odd method of getting the points since I could not figure out how to properly extract parameters without using the geometry conversion but I think converting all of the points to strings made the process of checking every value against every other one a lot faster. I’m aware my python is not very good but I am glad it works.

From testing this I had to make a few adjustments to the first python node as there are some CAD files with geometry groups that need to be extracted using the GetInstanceGeometry() function. I changed the script so it now works on recursive functions which I have not done before. They are really neat and fun to make!

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

clr.AddReference("RevitNodes")
import Revit
clr.ImportExtensions(Revit.Elements)

clr.AddReference("RevitAPIUI")
from Autodesk.Revit.UI import TaskDialog

clr.AddReference("RevitAPI")
import Autodesk
from Autodesk.Revit.DB.Events import *
from Autodesk.Revit.DB import *
from math import *
import itertools
clr.AddReference("RevitServices")
import RevitServices
from RevitServices.Persistence import DocumentManager
from RevitServices.Transactions import TransactionManager
clr.ImportExtensions(Revit.GeometryConversion)
doc = DocumentManager.Instance.CurrentDBDocument
geom = []
dwgs = []
output = []
gen = []

def flatten(g):
	for i in g:
		try: 
			br1 = (str(i).index('[(')+2)
			br2 = (str(i).index(')]')-2)
			yield str(i)[br1:br2]
		except:
			flatten(i)

def getgeometry(x):
	for i in x:
		try: 
			yield getgeometry(i.GetInstanceGeometry())
		except:
			try:
				yield i.Center
			except:
				try:
					yield i.Origin
				except:
					try:
						yield i.GetCoordinates()
					except:
						pass
links = FilteredElementCollector(doc).OfClass(CADLinkType).ToElements()
for i in links:
	if 'CFP_01' in (i.LookupParameter('Type Name').AsString()):
		geo = i.get_Geometry(Options())
		geom = list(flatten(getgeometry(geo)))
for i in geom:
	if geom.count(i) == 1:
		output.append(i)
OUT = output
3 Likes