1

有没有办法可以复制过滤器元素收集器对象?例如,原始对象指向 0x000000000000156B,我希望复制的对象指向不同的位置,这样我就可以在不更改原始对象的情况下继续进行修改。

这是一些代码来说明我的想法:

Col1 = FilteredElementCollector(doc).OfCategory(BuiltInCategory.OST_Walls)
#Some code to copy the object and assign it to Col2
Col2 = Col2.WhereElementIsNotElementType().ToElements() #Changing Col2 shouldn't change Col1.

我知道 FilteredElementCollector 类中没有这样的方法,但应该有办法做到这一点,对吧?我还阅读了有关 deepcopy 的信息,但无法在 Revit 上使用它。

任何帮助将不胜感激,谢谢!

4

2 回答 2

0

我通常FilteredElementCollector通过将其包装在 Python 中来使用该方法list。然后你可以组合、优化、拆分、复制、排序——基本上可以用 Python 提供的所有轻松做任何你想做的事情。

对于上述问题,您可以创建FilteredElementCollector, 并根据需要将其拆分为列表:

rawWalls = FilteredElementCollector(doc).OfCategory(BuiltInCategory.OST_Walls)

Col1 = list(rawWalls)
print 'There are',len(Col1),'wall types+instances in Col1'

Col2 = list(rawWalls.WhereElementIsNotElementType().ToElements())
print 'There are',len(Col2),'wall instances in Col2'
于 2020-06-15T21:28:56.150 回答
0

As you've already figured out, it's not possible to create a copy of a FilteredElementCollector. However, you could create a functionally identical one by recording which methods are called on the original and duplicating those method calls when you need to make a copy. The class below does just that:

class CopyableFilteredElementCollector(FilteredElementCollector):

    def __init__(self, doc):

        # Initialize the underlying FilteredElementCollector
        FilteredElementCollector.__init__(self, doc)

        # Save the document
        self._doc = doc

        # Calls to methods that constrain the FilteredElementCollector will be recorded here
        self._log = []

    def copy(self):

        # Create a brand new instance
        copy = CopyableFilteredElementCollector(self._doc)

        # Replay the log on the new instance
        for method_name, args in self._log:
            getattr(copy, method_name)(*args)

        # The copy now references the same document as the original,
        # and has had the same methods called on it
        return copy

We need to override each method that restrict the elements returned by the FilteredElementCollector to record its invocation in the log. The most straightforward way to do that would be by defining override methods in the class body like this:

    def OfCategory(self, category):

        # Add an entry to the log containing the name of the method that was called
        # and a tuple of its arguments that can be expanded with the splat operator
        self._log.append(('OfCategory', (category,)))

        # Call the original method
        FilteredElementCollector.OfCategory(self, category)

        # Return self just like the original method does 
        return self

Defining an override for every single method gets repetitive, so let's employ some metaprogramming voodoo instead:

# Methods of FilteredElementCollector that constrain which elements it returns
constraint_methods = [
    'OfCategory',
    'OfClass',
    'WhereElementIsElementType',
    'WhereElementIsNotElementType',
    'WherePasses',
    # et cetera
]

# A factory function that produces override methods similar to the one defined above
def define_method(method_name):
    def method(self, *args):
        self._log.append((method_name, args))
        getattr(FilteredElementCollector, method_name)(self, *args)
        return self
    return method

# Create an override for each method and add it to the CopyableFilteredElementCollector class 
for method_name in constraint_methods:
    setattr(CopyableFilteredElementCollector, method_name, define_method(method_name))

I won't go as far as to claim that my approach is a good idea, but it's an option if your use case requires making copies of a FilteredElementCollector rather than creating new ones from scratch.

于 2020-07-03T22:08:54.000 回答