I’m trying to create apply a crop region for a given view based on a list of curves. This used to work fine in previous versions of Dynamo/Python I have installed (2.6 was the most recent I have experience with) but no longer works in Revit 2023 and associated Dynamo 2.13.
I have tried using the custom nodes from packages MEPover and Data-Shapes as well as Python from older threads on this forum but they all return a similar error:
import clr
clr.AddReference('RevitNodes')
import Revit
clr.ImportExtensions(Revit.GeometryConversion)
clr.ImportExtensions(Revit.Elements)
clr.AddReference('RevitAPI')
import Autodesk
from Autodesk.Revit.DB import *
clr.AddReference('RevitServices')
import RevitServices
from RevitServices.Persistence import DocumentManager
from RevitServices.Transactions import TransactionManager
doc = DocumentManager.Instance.CurrentDBDocument
#prepare input
view = UnwrapElement(IN[0])
curves = IN[1]
outputlist = []
#Create curveloop
loop = CurveLoop()
for c in curves:
loop.Append(c.ToRevitType())
#Set cropregion in Transaction
TransactionManager.Instance.EnsureInTransaction(doc)
view.CropBoxActive = True
view.GetCropRegionShapeManager().SetCropShape(loop)
outputlist.append(view)
TransactionManager.Instance.TransactionTaskDone()
OUT = outputlist
Where Line 27 in this instance is:
loop.Append(c.ToRevitType())
This is the simplest version of this operation I could find but, like I said, pulling the Python code out of the MEPover node and the Data-Shapes node generates the same error whereas they all used to work in prior versions of Python (yes, I have run the auto-update to CPython3).
Any help much appreciated as this node is a key part of our workflow, thanks.
Lots of curves The crop follows the extents of an apartment outline. The graph worked perfectly on exactly the same group in Revit 2021 and 2.6 before the project was upgraded to Revit 2023.
Not worth a bounding box and squared? I wouldn’t know but I can give suggestions. Check with closed square if it works. Also is it from a room perimeter? If not maybe run the curves through a polycurve by closed curves to check there all joined? I’m sure one of the smarter dudes will help ya soon.
I wish we built square apartments! Feeding polycurves into the node still causes it to fail (just in a different way) even though that, too used to work, so hopefully someone has some ideas.
Seems you cant create a closed loop with these lines…this one here have sometimes help me in that sitiution…Curve.ApproximateWithArcAndLineSegments…but not sure it help you…if you had multiple loops then try group them with archilabs groupcurves
To verify - have you checked tthrough PolyCurve.ByJoinedCurves + Curve.IsClosed that the input creates a single, closed boundary, you don’t have multiple CurveLoops or open curves? I’ve been dealing with similar task recently and have had all sorts of issues.
import clr
clr.AddReference('ProtoGeometry')
from Autodesk.DesignScript.Geometry import *
import clr
clr.AddReference('RevitAPI')
import Autodesk.Revit.DB
import clr
clr.AddReference("RevitNodes")
import Revit
clr.AddReference('DSCoreNodes')
import DSCore
from DSCore import *
clr.AddReference("RevitServices")
import RevitServices
from RevitServices.Persistence import DocumentManager
from RevitServices.Transactions import TransactionManager
doc = DocumentManager.Instance.CurrentDBDocument
# Import ToProtoType, ToRevitType geometry conversion extension methods
clr.ImportExtensions(Revit.GeometryConversion)
#The inputs to this node will be stored as a list in the IN variables.
if isinstance(IN[0], list):
views = UnwrapElement(IN[0])
else:
views = [UnwrapElement(IN[0])]
if isinstance(IN[1], list):
if IN[1][0].GetType() == PolyCurve:
curves = [PolyCurve.Curves(x) for x in IN[1]]
elif IN[1][0].GetType() == Curve or IN[1][0].GetType() == Line:
curves = List.OfRepeatedItem(IN[1],len(views))
else:
curves = IN[1]
else:
if IN[1].GetType() == PolyCurve:
curves = [PolyCurve.Curves(IN[1])]
else:
curves = [IN[1]]
listout = []
for view,curve in zip(views,curves):
regionMan = view.GetCropRegionShapeManager()
revit_curve = [c.ToRevitType() for c in curve]
curveloop = Autodesk.Revit.DB.CurveLoop()
for c in revit_curve:
curveloop.Append(c)
TransactionManager.Instance.EnsureInTransaction(doc)
if view.CropBoxActive == False:
view.CropBoxActive = True
view.CropBoxVisible = True
regionMan.SetCropShape(curveloop)
TransactionManager.Instance.TransactionTaskDone()
listout.append(view)
#Assign your output to the OUT variable.
OUT = listout
Okay, I finally have a solution thanks to inspiration from the PolyCurve.ByJoinedCurves node - I just grabbed the curves from the PolyCurve (although not strictly necessary for the MEPover node as it can be fed a PolyCurve, other nodes were failing too).
The Python still needs to be extracted from the MEPover node as the original custom node still fails with this method.
I’m not sure why grabbing the curves from the perimeter of a surface should result in failure for nodes that require a closed loop when Dynamo says the loop is indeed closed?
So I dug a little further back in the graph and the problem seems to stem from the Strings node Surface.OuterPerimeterCurves that I use to remove internal loops before generating the crop.
If I feed OOTB Surface.PerimeterCurves into the operation then no errors so I’m not sure what the Strings node is doing (apart from the obvious difference of Curves vs Lines). In any case, a couple of different ways to get around the problem. Thanks all for the suggestions.
Just guessing, but could it be that the building of a valid curveloop requires all the curves to be sequenced and oriented consistently - you can’t have them out of order or facing the wrong direction (start to end) or the process fails along the way. After creating the polycurve, all the curves are arranged consistently, therefore breaking it back up into curves works to create a curveloop. I’ve experienced similar issues creating loops and the polycurve step along the way usually helps me as well.