Failure to convert Curves in R2024?

I’m upgrading a script from R22 to R24 and i’m getting some unexpected behavior. The script creates floors from polycurves. I implement some structure to account for holes, so not using OOTB Dynamo nodes.

R24

import clr

clr.AddReference('RevitAPI')
from Autodesk.Revit.DB import *
import System.Collections.Generic
from System.Collections.Generic import List

clr.AddReference('RevitNodes')
import Revit
clr.ImportExtensions(Revit.GeometryConversion)

clr.AddReference('RevitServices')
from RevitServices.Transactions import TransactionManager
from RevitServices.Persistence import DocumentManager

doc = DocumentManager.Instance.CurrentDBDocument

floorType = ElementId(IN[2])
levelId = ElementId(IN[0])
regions = IN[1]

fRegions = []
trace = []



#outer = boundaries.pop(0)
#inner = boundaries

result = []



for bdy in regions:
	# outer loop is first and counterclockwise
	# holes are the rest and clockwise
	trace.append("region found")
	rtrace = []
	rtrace.append("    initialize boundary")
	boundariesLoop = List[CurveLoop]()
	for b in bdy:
		subtrace = []
		try:
			subtrace.append("    found curve as a "+str(type(b)))
			boundariesLoop.Add(b.ToRevitType())
			subtrace.append("    added as a "+str(type(b.ToRevitType())))
		except Exception as e:
			subtrace.append(e)
	rtrace.append(subtrace)
	rtrace.append("   boundaries as "+str(type(boundariesLoop)))
	rtrace.append(boundariesLoop)

	
	try:
		TransactionManager.Instance.EnsureInTransaction(doc)
		floor = Floor.Create(doc, boundariesLoop, floorType, levelId)
		TransactionManager.Instance.TransactionTaskDone()
		result.append(floor)
	except Exception as e:
		rtrace.append(e)
	trace.append(rtrace)
	
OUT = result,trace

What might cause these two different outcomes from the same code? What is odd to me is that the knots issue isn’t raised in R2022 with the same geometry. I added some traces and it looks like it has more to do with the x.ToRevitType() method failing to convert the curves

[
  [
    Empty List,
    [
      region found,
      [
            initialize boundary,
        [
              found curve as a <type 'PolyCurve'>,
          The multiplicities of other interior knots must be at most degree - 2.
Parameter name: knots
        ],
           boundaries as <type 'List[CurveLoop]'>,
        Empty List,
        The input curve loops cannot compose a valid boundary, that means: the "curveLoops" collection is empty; or some curve loops intersect with each other; or each curve loop is not closed individually; or each curve loop is not planar; or each curve loop is not in a plane parallel to the horizontal(XY) plane; or input curves contain at least one helical curve.
Parameter name: profile
      ],
      region found,
      [
            initialize boundary,
        [
              found curve as a <type 'PolyCurve'>,
          The multiplicities of other interior knots must be at most degree - 2.
Parameter name: knots
        ],
           boundaries as <type 'List[CurveLoop]'>,
        Empty List,
        The input curve loops cannot compose a valid boundary, that means: the "curveLoops" collection is empty; or some curve loops intersect with each other; or each curve loop is not closed individually; or each curve loop is not planar; or each curve loop is not in a plane parallel to the horizontal(XY) plane; or input curves contain at least one helical curve.
Parameter name: profile
      ],
      region found,
      [
            initialize boundary,
        [
              found curve as a <type 'PolyCurve'>,
          The multiplicities of other interior knots must be at most degree - 2.
Parameter name: knots
        ],
           boundaries as <type 'List[CurveLoop]'>,
        Empty List,
        The input curve loops cannot compose a valid boundary, that means: the "curveLoops" collection is empty; or some curve loops intersect with each other; or each curve loop is not closed individually; or each curve loop is not planar; or each curve loop is not in a plane parallel to the horizontal(XY) plane; or input curves contain at least one helical curve.
Parameter name: profile
      ],
      region found,
      [
            initialize boundary,
        [
              found curve as a <type 'PolyCurve'>,
          The multiplicities of other interior knots must be at most degree - 2.
Parameter name: knots
        ],
           boundaries as <type 'List[CurveLoop]'>,
        Empty List,
        The input curve loops cannot compose a valid boundary, that means: the "curveLoops" collection is empty; or some curve loops intersect with each other; or each curve loop is not closed individually; or each curve loop is not planar; or each curve loop is not in a plane parallel to the horizontal(XY) plane; or input curves contain at least one helical curve.
Parameter name: profile
      ]
    ]
  ]
]

Hi,

I make a simple test with Dynamo 2.17, this seems related to the particular geometry of your input polycurves

if you apply ToRevitType() on each curve of the PolyCurve does it work?

1 Like

This is a reasonable suggestion.
I get partial success in 2.17.

image

#------------------IMPORTS------------------
import clr
#  Include these lines to access python modules
import sys 
sys.path.append(r'C:\Users\mclough\AppData\Local\python-3.8.3-embed-amd64\Lib\site-packages') # update this path with your user data

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

clr.AddReference('RevitAPI')
from Autodesk.Revit.DB import *
from Autodesk.Revit.Exceptions import * # enable this for debugging

#clr.AddReference('RevitAPIUI')
#from Autodesk.Revit.UI import *

clr.AddReference('System')
from System.Collections.Generic import List

# There are namespace overlaps between ProtoGeometry and RevitNodes
# Be sure to address these discrepancies
clr.AddReference('RevitNodes')
import Revit
clr.ImportExtensions(Revit.GeometryConversion)
clr.ImportExtensions(Revit.Elements)

clr.AddReference('RevitServices')
import RevitServices
from RevitServices.Persistence import DocumentManager
from RevitServices.Transactions import TransactionManager

doc = DocumentManager.Instance.CurrentDBDocument
uidoc=DocumentManager.Instance.CurrentUIApplication.ActiveUIDocument

#-----------------FUNCTIONS-----------------
def convertPolyline (polyline):
    revit_curves = []
    for c in polyline.Curves():
        try:
            revit_curves.append(c.ToRevitType())
        except Exception as e:
            revit_curves.append("failed to convert")
      
    return revit_curves
    
toList = lambda x: x if hasattr(x, '__iter__') else [x]
#------------------INPUTS-------------------

#Preparing input from dynamo to revit
inputs = toList(IN[0])

result = []
trace = []

#-------------------MAIN--------------------
#Do some action in a Transaction

for i in inputs:
    result.append("check PolyCurve")
    result.append(convertPolyline(i))

#------------------OUTPUT-------------------
OUT = result

Further snooping on this: the two curves failing to convert are parts of the circle that seem to be getting interpreted as NurbsCurves instead of Arcs, and a large number of knots compared to the other NurbsCurves. As i mentioned, this doesn’t seem to cause issues in R22/Dynamo 2.13, which is what seems odd.

looking at the data in 2.13, it looks like these features do get generated as Arcs instead of NurbsCurves, so maybe not an issue with the ToRevitType method. I’m using some nodes from Topologic to generate the split surfaces, so maybe there’s some interaction in that package with 2.17 that causes the difference in output.

After getting all the curves of the polycurve you can try to check if the curve is an arc and then convert it if so

here an example


# Import the DesignScript and Standard Python libraries
import sys
import clr
clr.AddReference('ProtoGeometry')
from Autodesk.DesignScript.Geometry import *

def try_convert_to_arc(curve):
    # Get points and vectors at different parameters of the curve
    pt1 = curve.PointAtParameter(0)
    vect1 = curve.NormalAtParameter(0)
    pt2 = curve.PointAtParameter(0.5)
    vect2 = curve.NormalAtParameter(0.5)
    pt3 = curve.PointAtParameter(1)
    vect3 = curve.NormalAtParameter(1)

    # Create lines from the points, vectors, and specified length
    lineA = Line.ByStartPointDirectionLength(pt1, vect1, 100)
    lineB = Line.ByStartPointDirectionLength(pt2, vect2, 100)
    lineC = Line.ByStartPointDirectionLength(pt3, vect3, 100)

    # Check if lines intersect
    if lineA.DoesIntersect(lineB) and lineB.DoesIntersect(lineC):
        # Get intersection points of the lines
        pt_intA = lineA.Intersect(lineB)[0]
        pt_intB = lineB.Intersect(lineC)[0]

        # Check if intersection points are almost equal
        if pt_intA.IsAlmostEqualTo(pt_intB):
            # Return an arc if intersection points are equal
            return Arc.ByThreePoints(pt1, pt2, pt3)

    # Return the original curve if no conversion is possible
    return curve

# Call the try_convert_to_arc function for each input curve
OUT = [try_convert_to_arc(c) for c in IN[0]]

maybe there is another easier way