Just want extract lengths of lines, how

Hello,

i stuck, i can access it via node but not via python… so how can i get the lengths of my edges…



how can i integrade this in my code also with the listmanagement! so each list has to remain.

KR

Andreas

Full Python? Hard to find where to edit it without the context.

Likely if you have lines you can skip the .Curve and just return the length - so line 72 becomes dis = i.Length.

This is effectively what the Dynamo node is doing - pulling the length property from the Curve class object given in the list of inputs. Remember that properties can be called directly via object.Propery rather than Class.Property(object) as you see with the nodes names.

3 Likes

@jacob.small

it is this roof perimeter topic…

# demo
# all
import sys
import clr

clr.AddReference('RevitAPI')
import Autodesk
from Autodesk.Revit.DB import *
from Autodesk.Revit.DB.Structure import *

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

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

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

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

# Access the Revit application and document
app = DocumentManager.Instance.CurrentUIApplication
doc = DocumentManager.Instance.CurrentDBDocument


# functions
def tolist(x):
    if hasattr(x,'__iter__'): return x
    else: return [x]

def isSolid(x):
    if x.__class__ == Autodesk.Revit.DB.Solid: return x
    
def faceNormal(face):
    if face.FaceNormal.Z > 0.00001: return [edges.append(i) for loop in face.EdgeLoops for i in loop]


collector = FilteredElementCollector(doc).OfCategory(BuiltInCategory.OST_Roofs).WhereElementIsNotElementType().ToElements()
roofs = tolist(collector)

results = []

for e in roofs:
    edges = [] 
    processed = [] 
    geos = e.get_Geometry(Options())
    for geo in geos: 
        faces = isSolid(geo)
        faces = geo.Faces     
        for face in faces: 
            loop = faceNormal(face)

    pnts = [e.AsCurve().Evaluate(0.5,True) for e in edges] #get all the mid points of the edges

    for i in range(len(edges)): #for every item in the list of edges
        e = edges.pop(0) #remove the edge to process
        p = e.AsCurve().Evaluate(0.5,True) #get the midpoint
        distSum = sum([1 for i in pnts if i.DistanceTo(p) == 0]) #get the count of midpoints which are equal to the midpoint being evaluated
        if distSum == 1: processed.append(e.AsCurve().ToProtoType()) #if the count was 0 the edge isn't shared and is on the perimeter
    results.append(processed) #append the processed edges to our results list

"""
lengths = []

for lis in results:
    for i in lis:
        dis = i.Length
        lengths.append(dis)
        """


OUT = results

i struggle with CPython

it runs in Revit2023 but not in 2024

grafik
KR
Andreas

Dataset?

Your error message changed so I can’t really identify the issue. The community can’t effectively help if you don’t share more of what you’re building, what you’re after, and datasets to build along with you. Likely best to go back to nodes here if you can’t manage to constrict your environment somewhat.

1 Like

@jacob.small ,

there should be no error. i just want to have the length of my lines. But the script crashed before. I don`t know how to deal with that. In one Revit it runs and in the other one not. I replicated the error too in Revit2022

I can’t replicate it as I don’t have the model. Try running dir on the object and seeing what you can do with it.

1 Like

@jacob.small
Dach22.rvt (436 KB)
Dach.rvt (856 KB)
it is just a demo

It seems to work just fine in my Revit 2024.2 - update?

1 Like

@ThorbjornH ,

thanks we have some IT Issue in our company at home the code works…
grafik

Thank you

KR

Andreas

@ThorbjornH ,

so finally i solved it. from getting the lines, lengths and filling the parameter as well.

import clr

clr.AddReference('RevitAPI')
import Autodesk
from Autodesk.Revit.DB import *
from Autodesk.Revit.DB.Structure import *

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

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

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

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

# Access the Revit application and document
app = DocumentManager.Instance.CurrentUIApplication
doc = DocumentManager.Instance.CurrentDBDocument


# Variables LOI
PERIMETER = "Umfang_Massen"

# functions
def tolist(x):
    if hasattr(x,'__iter__'): return x
    else: return [x]

def isSolid(x):
    if x.__class__ == Autodesk.Revit.DB.Solid: return x
    
def faceNormal(face):
    if face.FaceNormal.Z > 0.00001: return [edges.append(i) for loop in face.EdgeLoops for i in loop]

# Get roofs
collector = FilteredElementCollector(doc).OfCategory(BuiltInCategory.OST_Roofs).WhereElementIsNotElementType().ToElements()
roofs = tolist(collector)


# extract lengths from edges of roofs
results = []

for e in roofs:
    edges = [] 
    processed = [] 
    geos = e.get_Geometry(Options()) 
    for geo in geos: 
        faces = isSolid(geo)
        faces = geo.Faces     
        for face in faces: 
            loop = faceNormal(face)
                 
    pnts = [e.AsCurve().Evaluate(0.5,True) for e in edges] #get all the mid points of the edges
    
    for i in range(len(edges)): #for every item in the list of edges
        e = edges.pop(0) #remove the edge to process
        p = e.AsCurve().Evaluate(0.5,True) #get the midpoint
        distSum = sum([1 for i in pnts if i.DistanceTo(p) == 0]) #get the count of midpoints which are equal to the midpoint being evaluated
        if distSum == 1: processed.append(e.AsCurve().Length)#ToProtoType()) #if the count was 0 the edge isn't shared and is on the perimeter
    results.append(processed) #append the processed edges to our results list

# sum edge.lengths to perimeter total per roof
total = []

for lis in results:
    perimeter_per_element = sum(lis)
    total.append(perimeter_per_element)

# SetParameter
t = Transaction(doc, "Set Massen_Umfang")
t.Start()

for d,v in zip(roofs,total):
	try:
		roof_perimeter_param = d.LookupParameter(PERIMETER).Set(v)
	except:
		pass

t.Commit()


OUT = "Success"

1 Like

Alternatively,
you can use HostObjectUtils.GetTopFaces method then remove collinear lines

import clr
import sys
import System
from System.Collections.Generic import List
#
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 remove_collinar(lst_curve):
    perimeter_curves = []
    for idxA, curvA in enumerate(lst_curve):
        if all( curvA.Intersect(curvB) != SetComparisonResult.Equal for idxB, curvB in enumerate(lst_curve) if idxA != idxB):
            perimeter_curves.append(curvA)
    return perimeter_curves
    
toList = lambda x : x if isinstance(x, (list, List)) else [x]

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

out = []
for roof in lstRoofs:
    topRefs = DB.HostObjectUtils.GetTopFaces(roof)
    roof_curves = []
    for ref in topRefs:
        face = roof.GetGeometryObjectFromReference(ref)
        #
        if face is not None:
            curve_loop = face.GetEdgesAsCurveLoops()[0]
            for curv in curve_loop:
                roof_curves.append(curv)
    ds_perimeter_curves = [x.ToProtoType() for x in remove_collinar(roof_curves)]
    sum_perimeter = sum(x.Length for x in ds_perimeter_curves)
    out.append([ds_perimeter_curves, sum_perimeter])

OUT = out
2 Likes