Calculate usable length of sheet

Another solution using vertical and horizontal rays (intersections with unbound curves)

Python Code (all engines)

import clr
import sys
import System
pyEngineName = sys.implementation.name 
#
clr.AddReference('ProtoGeometry')
from Autodesk.DesignScript.Geometry import *
import Autodesk.DesignScript.Geometry as DS

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

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

#import transactionManager and DocumentManager (RevitServices is specific to Dynamo)
clr.AddReference('RevitServices')
import RevitServices
from RevitServices.Persistence import DocumentManager
from RevitServices.Transactions import TransactionManager
doc = DocumentManager.Instance.CurrentDBDocument

def drange(start, end, step):
    i = start
    while round(i, 10) < end:
        yield i
        i += step
  
def flattenGen(*args):
    for x in args:
        if hasattr(x, "__iter__") and not isinstance(x, str):
            for y in flattenGen(*x) : yield y
        else: yield x
  
def get_geomCurves(elem):
    """
    Retrieves the geometric curves from a given Revit element.
    Args:
        elem (Autodesk.Revit.DB.Element): The Revit element from which to extract curves.
    Returns:
        list: List of geometric curves extracted from the element.
    """
    out = []
    opt = Options()
    opt.DetailLevel = ViewDetailLevel.Fine
    instGeo = elem.GetOriginalGeometry(opt)
    tf = elem.GetTransform()
    for ig in instGeo:
        if isinstance(ig, DB.Curve):
            out.append(ig.CreateTransformed(tf))
                
        elif isinstance(ig, DB.GeometryInstance):
            for g in flattenGen(ig.GetInstanceGeometry()):
                if isinstance(g, DB.Curve):
                    out.append(g.CreateTransformed(tf))
    return out 

def toList(x):
    if isinstance(x, (list, dict)) or \
            (hasattr(x, "GetType") and x.GetType().GetInterface("ICollection") is not None):
        return x
    else : return [x]
 
def search_minPts_by_vector(minInt, maxInt, vectorRay, midPt, titlebk_curves):
    """
    Search for minimum points along a vector within a range.

    Args:
        minInt (float): The minimum value of the range.from BoundingBox
        maxInt (float): The maximum value of the range.from BoundingBox
        vectorRay (object): The vector along which to search for minimum points.
        midPt (object): The midpoint of the bounding box.
        titlebk_curves (list): The list of curves representing the title block geometry
    Returns:
        tuple: Tuple containing two minimum points (usable length sheet)
    """
    global debug
    results = []
    for d in drange(minInt, maxInt, 0.05):
        if vectorRay.IsAlmostEqualTo(XYZ.BasisX):
            ptRay = XYZ(midPt.X, d, midPt.Z)
        else:
            ptRay = XYZ(d, midPt.Y, midPt.Z)
        raybound = DB.Line.CreateUnbound(ptRay, vectorRay)
        for c in titlebk_curves:
            result = None
            if pyEngineName == "ironpython":
                out_resultArray = clr.Reference[IntersectionResultArray]()
                result = raybound.Intersect(c, out_resultArray)
            else:
                dummy_out = DB.IntersectionResultArray()
                result, interResult = raybound.Intersect(c, dummy_out)
            #
            if result == SetComparisonResult.Overlap:
                interResult = out_resultArray.Value[0] if pyEngineName == "ironpython" else interResult[0]
                pt = interResult.XYZPoint
                distance = ptRay.DistanceTo(pt)
                vector = DB.Line.CreateBound(ptRay, pt).Direction 
                results.append([pt, distance, vector])
                #debug.append(pt.ToPoint())
        raybound.Dispose()
    results.sort(key = lambda x : x[1])
    dataA = results.pop(0)
    ptA, distanceA, vectA = dataA
    dataB = next(x for x in results if x[2].DotProduct(vectA) < 0)
    ptB = dataB[0]
    return ptA, ptB

lst_titleBk = toList(UnwrapElement(IN[0]))
out = []
debug = []
for tb in lst_titleBk:

    bbx = tb.get_BoundingBox(doc.GetElement(tb.OwnerViewId))
    midPt = (bbx.Min.Add(bbx.Max)).Multiply(0.5)
    titlebk_curves = get_geomCurves(tb)
    
    ptX1, ptX2 = search_minPts_by_vector(bbx.Min.Y, bbx.Max.Y, XYZ.BasisX, midPt, titlebk_curves)
    if ptX1.X >  ptX2.X:
        ptX1, ptX2 = ptX2, ptX1
    ptY1, ptY2 = search_minPts_by_vector(ptX1.X, ptX2.X, XYZ.BasisY, midPt, titlebk_curves)
    out.append([tb, [ptX1.ToPoint(), ptX2.ToPoint()], [ptY1.ToPoint(), ptY2.ToPoint()], [c.ToProtoType() for c in titlebk_curves]])
OUT = out
1 Like