I haven’t used this workflow in a while, but a request from one of my readers came in asking if i could update this workflow to the latest version of Dynamo. Here it is with a few changes which I think make it a little bit more efficient.
Item selection method has not changed. I am still using Family Type and All Elements of Family Type nodes to get all of the families that I am interested in. What did change however, is the next node that used to be a custom node from Clockwork package. It’s no longer needed in this case since Dynamo now has a FamilyInstance.Location node built in. Next is an updated List Duplicate Item’s Indices nodes that will do just that…it will compare all items in a list and list index numbers of a duplicate item the first time it spots it and all the next subsequent instances if there are more than one duplicate. Here’s the code:
Next was extracting duplicate items from the original list using the index numbers and deleting them. Since there is no delete element node in Dynamo i have made one. Here’s code for it:
That’s it! Let me know if that works for you all! Example file and custom nodes can be downloaded here: Download
Addendum 1:
Jesper, has pointed out to me in the comments below that this method doesn’t work with Structural Framing elements since they return either a Curve or a Location Point class object as their Location. So, Structural Beam will return a Curve as its location while Column has its own class called Location Point. As it happens now there is no node in Dynamo that can get you Column Location point, but you can use a custom Python node and this code to achieve this:
Use this code to get a Point and then you can compare that to other points to find duplicates.
One more quick pointer is that List Duplicate Item’s Indices node is really not going to work with Lines, but if you use Curve.PointAtParameter to get a point then you can compare those easily.
Hello again
Thanks for a quick answer.
Unfortunately Its not working for me. It deletes all the objects of the family I have chosen. The Familyinstance.Location note comes with this warning: StructuralFraming.get_Location operation failed.
The location of the structural element is not a valid curve!
What am I doring wrong here.
Best regards
Jesper Wallaert
Attachment: delete-duplicate-families.png
Jesper,
Yes, this will happen when you try and use the FamilyInstance.Location node to try and obtain a location point from a Structural Framing member. The problem here is that for most families the property Location will return a Point. FamilyInstance.Location is expecting that Revit will give it a point and is not expecting a Curve or even worse a LocationPoint class object. If you have a beam its location is defined by a curve so it will return a line or an arc (curve object). To get that i would use StructuralFraming.Location node. However, for a StructuralColumn location even though it returns a point that point is wrapped into a LocationPoint class of Revit API and Dynamo team didn’t account for that. What I did is write a simple Python node for you that will convert that object to Dynamo point. Finally let’s get back to our beams and location curves. Duplicate Item Indices node will try and compare objects to each other. Line from the outside looks just like any other line so the comparison will fail. It’s best in this instance to extract a point at any location on a line and compare those points. I used Curve.PointAtParameter to get those points. Now, we have a list of points that we can compare using Duplicate Item Indices node. I might change the name of this node to something more specific since it is not capable of comparing lines. This should work for you. Good luck!
Attachment: Capture.png
Hi
Finally I got the time to try it on my project. It worked and saved me some time for sure! Thanks for your time.
Iam looking forward to see whats comming up next!
Glad I was able to help!
Hello,
Can this work also with duplicate tags in the project? I have many room tags and it takes too long time to delete one by one and then deleting the last one and undoing that last delete to have at least one tag in the room.
Are they located exactly in the same place? If the answer is no, then we are looking at a different solution. You need to check if for a particular view there is more than a single room tag present in each room. It’s possible but I don’t have a ready to go solution that I can share.
Yes, they are. They are on top of each other, but it seems like exactly one.
Where can I find the element delete node?
archi-lab package. search for element.delete.
Thanks Konrad. I will take a look.
Hello Konrad,
I know this post is rather dated, but I was curious if you looked into utilizing the Performance Advisor rather than juggling different element location representations (points vs curves), especially when Revit is already identifying instances of families in the same space.
My scripting capabilities are still developing but I’ve put something together that uses this to deal with duplicates in the entire project, of course it could be modified to look at elements in the current view, on certain sheets, in specific assemblies, etc.
This script runs through those duplicates found by the rule and deletes the one outside of an assembly, or the first element it finds if both are in an assembly.
def deleteDups():
adviser = PerformanceAdviser.GetPerformanceAdviser()
rules = adviser.GetAllRuleIds()
for i in rules:
ruleName = adviser.GetRuleName(i)
if ruleName == “Duplicate instances”:
dupRuleID = i
ruleIDstoExecute = List[PerformanceAdviserRuleId]()
ruleIDstoExecute.Add(dupRuleID)
duplicates = adviser.ExecuteRules(doc, ruleIDstoExecute)
Console(context=locals())
for j in duplicates:
elems = j.GetFailingElements()
while len(elems) > 1:
try:
element = doc.GetElement(elems[(len(elems)-1)])
element2 = doc.GetElement(elems[(len(elems)-2)])
if element.AssemblyInstanceId == -1:
doc.Delete(elems[(len(elems)-1)])
elems.Remove(elems[(len(elems)-1)])
elif element2.AssemblyInstanceId == -1:
doc.Delete(elems[(len(elems)-2)])
elems.Remove(elems[(len(elems)-2)])
else:
doc.Delete(elems[(len(elems)-1)])
elems.Remove(elems[(len(elems)-1)])
except:
canDelete = DocumentValidation.CanDeleteElement(doc, elems[(len(elems)-1)])
if canDelete == False:
if element.AssemblyInstanceId == -1:
elem = element
elif element2.AssemblyInstanceId == -1:
elem = element2
try:
elem.LookupParameter(“Comments”).Set(“Duplicate”)
except:
pass
elems.Remove(elems[(len(elems)-1)])
####################################################
#”Start” the transaction
TransactionManager.Instance.EnsureInTransaction(doc)
deleteDups()
# “End” the transaction
TransactionManager.Instance.TransactionTaskDone()
####################################################
Performance Adviser is great. I appreciate the tip. Thanks for sharing.