Как скопировать объект в Revit API с помощью Python

Есть ли способ скопировать объект сборщика элементов фильтра? Например, исходный объект указывает на 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.

Любая помощь будет принята с благодарностью, спасибо!


person ANDRES RAMOS    schedule 15.06.2020    source источник
comment
Данные элемента Revit не могут существовать вне документа Revit. Невозможно создать копию элемента Revit, не имея на самом деле второй копии элемента внутри модели Revit. Например, вам нужно продублировать элемент стены в модели Revit (помните обо всех предупреждениях о столкновении, которые это может вызвать), а затем отредактировать второй элемент.   -  person Ehsan Iran-Nejad    schedule 16.06.2020
comment
Да, в этом есть смысл. Я просто подумал, может быть, можно скопировать коллекционера. Если я определяю два раза один и тот же коллектор, я получаю два разных объекта FilteredElementCollector. Будет проще, если вместо того, чтобы снова определять сборщик, я мог бы просто скопировать тот, который у меня уже есть, но, как вы говорите, это может быть невозможно.   -  person ANDRES RAMOS    schedule 20.06.2020
comment
Каждый раз, когда вы вызываете метод фильтрации (например, .OfCategory() или .OfClass()) в экземпляре сборщика, они возвращают измененную версию этого экземпляра. Таким образом, даже если вы сохраните более общий сборщик в переменной, все последующие вызовы методов фильтрации также изменят исходный сборщик.   -  person Ehsan Iran-Nejad    schedule 21.06.2020
comment
Понятно! Большое спасибо!   -  person ANDRES RAMOS    schedule 24.06.2020


Ответы (2)


Обычно я использую метод 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'
person Callum    schedule 15.06.2020
comment
Привет, спасибо за ответ. Я не думаю, что это дает то, что я ищу. Col1 и Col2 по-прежнему указывают на один и тот же объект FilteredElementCollector. Если после добавления Col3 = list (rawWalls.WhereElementIsElementType (). ToElements ()) вы не получите никаких элементов, потому что сборщик уже отфильтрован. Моя идея состоит в том, чтобы иметь статический сборщик (назовем его так), создать копию, а затем применить все фильтры к этим копиям, чтобы исходный (статический) сборщик оставался неизменным. - person ANDRES RAMOS; 20.06.2020
comment
Ах я вижу. Так что в этом случае я бы просто делал новый FilteredElementCollector каждый раз, когда он мне нужен - они невероятно быстрые. Извини, я больше не мог помочь - person Callum; 21.06.2020
comment
Не беспокойтесь, мне понравилась идея обернуть сборщик списком Python. Это потом пригодится. И да, довольно быстро и легко определить коллектора заново. Спасибо! - person ANDRES RAMOS; 24.06.2020

Как вы уже поняли, создать копию FilteredElementCollector. Однако вы можете создать функционально идентичный, записав, какие методы вызываются в оригинале, и дублируя эти вызовы методов, когда вам нужно сделать копию. Класс ниже делает именно это:

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

Нам нужно переопределить каждый метод, который ограничивает элементы, возвращаемые FilteredElementCollector, для записи его вызова в журнал. Самый простой способ сделать это - определить методы переопределения в теле класса следующим образом:

    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

Определение переопределения для каждого отдельного метода становится повторяющимся, поэтому давайте вместо этого воспользуемся метапрограммированием вуду:

# 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))

Я не буду заходить так далеко, чтобы утверждать, что мой подход - хорошая идея, но это вариант, если ваш вариант использования требует создания копий FilteredElementCollector, а не создания новых с нуля.

person Nicholas Rawlings    schedule 03.07.2020