Python help with list

Trying to modify a python script and have the result be nested lists, not just multiple compiled lists of all the values. Here’s the bottom of the code :

Mod Edit: formatted code - @danny.jones8FB78, please make sure this is correct

for wall in walls:
	line = wall.Location.Curve
	lineDir = line.GetEndPoint(1) - line.GetEndPoint(0)
	doc=wall.Document
	geoElement = wall.get_Geometry(options)
	for obj in geoElement:
		if isinstance(obj,Solid):
			for f in obj.Faces:
				faceNormal = f.FaceNormal
				if isParallel(faceNormal,lineDir):
					refArray.Append(f.Reference)
	for id in wall.CurtainGrid.GetVGridLineIds():
		gridLine = doc.GetElement(id)
		gridGeo = gridLine.get_Geometry(options)
		for obj in gridGeo:
			if isinstance(obj,Line):
				refArray.Append(obj.Reference)
		
OUT = [refArray for wall in walls]

Welcome to the forum.

Your code is really hard to read as you’ve just pasted it as text.
There a button that looks like this </>
that will let you paste code and format it.

thing = IN[0]
for i in thing:
    do thing
OUT = "moose" 

not real code obvs :smiley:

2 Likes

If your walls are straight the LocationCurve (line) will have a Direction property
For walls joined at angles the face normal may not be parallel to the direction - perhaps look at HostObjectUtils class to exclude top, bottom and side faces

[refArray for wall in walls] just repeats refArray for the number of walls

Collect you info in a list per iteration and then append to your output list
Something like this?

for wall in walls:
	collector = []
	line = wall.Location.Curve
	lineDir = line.Direction
	doc=wall.Document
	geoElement = wall.get_Geometry(options)
	for obj in geoElement:
		if isinstance(obj,Solid):
			for f in obj.Faces:
				faceNormal = f.FaceNormal
				if isParallel(faceNormal, lineDir):
					collector.Append(f.Reference)
	for id in wall.CurtainGrid.GetVGridLineIds():
		gridLine = doc.GetElement(id)
		gridGeo = gridLine.get_Geometry(options)
		for obj in gridGeo:
			if isinstance(obj,Line):
				collector.Append(obj.Reference)
	refArray.append(collector)
	
OUT = refArray

I appreciate the help. In theory I’m understanding the logic. Dynamo is now throwing an error at the “collector.Append(f.Reference)” line. File “”, line 30, in
AttributeError: ‘list’ object has no attribute ‘Append’

Any thoughts on how to get past that one?

Try lowercase ‘a’ instead of capital ‘A’ when writing Append.

We’re down to the 2nd to last line not working now “refArray.append(collector)” Below is the error

line 37, in
AttributeError: ‘ReferenceArray’ object has no attribute ‘append’

Reference array is a .NET collection type. Try Add with the uppercase A and if that fails use lowercase a.

Pasting in the whole code… still not working. “‘ReferenceArray’ object has no attribute ‘Add’”

import clr
clr.AddReference("RevitAPI")
from Autodesk.Revit.DB import *
clr.AddReference("RevitServices")
import RevitServices
from RevitServices.Persistence import DocumentManager

walls = UnwrapElement(IN[0])
if not hasattr(walls, '__iter__'):
    walls = [walls]

def isParallel(v1,v2):
	return v1.CrossProduct(v2).IsAlmostEqualTo(XYZ(0,0,0))
refArray = ReferenceArray()
options = Options()
options.ComputeReferences = True
options.IncludeNonVisibleObjects = True	
for wall in walls:
	collector = []
	line = wall.Location.Curve
	lineDir = line.Direction
	doc=wall.Document
	geoElement = wall.get_Geometry(options)
	for obj in geoElement:
		if isinstance(obj,Solid):
			for f in obj.Faces:
				faceNormal = f.FaceNormal
				if isParallel(faceNormal, lineDir):
					collector.Add(f.Reference)
	for id in wall.CurtainGrid.GetVGridLineIds():
		gridLine = doc.GetElement(id)
		gridGeo = gridLine.get_Geometry(options)
		for obj in gridGeo:
			if isinstance(obj,Line):
				collector.Add(obj.Reference)
	refArray.Add(collector)
	
OUT = refArray

Ok… we have two things here.

There is the ‘collector’ which is a list (lowercase append) and the ‘refArray’ which is a Revit ReferenceArray.

The former needs the lowercase append.

The later needs the uppercase Append.


My guess is that when the capitalization is resolve you’re going run into an issue with trying to append an untyped list (‘collector’ in your code) to a ReferenceArray, with a warning that goes something like “could not find an method Append of the class ReferenceArray which takes arguments of type List”

You want to put the references in the reference array.

Sorry about the (A/a)ppend - that was VS Code autocomplete having a senior moment
Since you’re after a ReferenceArray collection swap the list collector and array as the array takes a Reference as an input. I’ve done a slight refactor and changed variable names to python convention

import clr

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

clr.AddReference("RevitServices")
from RevitServices.Persistence import DocumentManager


def isParallel(v1, v2):
    return v1.CrossProduct(v2).IsAlmostEqualTo(XYZ(0, 0, 0))


doc = DocumentManager.Instance.CurrentDBDocument

walls = UnwrapElement(IN[0])

if not hasattr(walls, "__iter__"):
    walls = [walls]

options = Options()

options.ComputeReferences = True
options.IncludeNonVisibleObjects = True

ref_array_list = []

for wall in walls:
    ref_array = ReferenceArray()
    line_dir = wall.Location.Curve.Direction

    # doc = wall.Document  # Uncomment if walls are in linked doc
    geo_element = wall.get_Geometry(options)

    for obj in geo_element:
        if isinstance(obj, Solid):
            for f in obj.Faces:
                if isParallel(f.FaceNormal, line_dir):
                    ref_array.Append(f.Reference)

    for id in wall.CurtainGrid.GetVGridLineIds():
        grid_line = doc.GetElement(id)
        grid_geo = grid_line.get_Geometry(options)
        for obj in grid_geo:
            if isinstance(obj, Line):
                ref_array.Append(obj.Reference)

    ref_array_list.append(ref_array)

OUT = ref_array_list
2 Likes

Really want to thank you all for the effort! Python script works amazing.

3 Likes