Autodesk Inventor API. Первые шаги/Объект Assembly

Материал из Викиучебника — открытых книг для открытого мира

Структура сборки[править]

Концепция структуры сборки знакома каждому, кто работал со сборками. Инвентор графически отображает эту структуру в браузере. Хотя концептуально организация структуры сборки проста, имеется ряд нюансов, важных при работе со сборкой через API. Наша цель — извлечь пользу из понимания особенностей внутреннего устройства сборок Инвентора. В дальнейшем, в качестве иллюстрации мы будем использовать следующую сборку всего из трех деталей: детали «Ось» и двух экземпляров детали «Колесо».

При работе со сборками важно понять, что на самом деле сборка не содержит никакой геометрии — только ссылки на другие файлы. Если бы нам удалось взглянуть изнутри на действительную структуру сборки, мы бы увидели примерно то, что изображено на следующем рисунке. В данном случае сборка содержит две группы данных — ссылки и компоненты. В ссылках определены файлы, на которые ссылается сборка. Ссылке неизвестно, каким образом ее файл используется, ей известно лишь то, что сборка использует этот файл. В данном случае, сборка ссылается на два файла: Axle.ipt и Wheel.ipt.


В данных компонентов детализированы все подробности участия компонента в сборке. Неважно, что представляет собой компонент — деталь или подсборку. Здесь хранится ассоциированная с компонентом информация: ссылка на файл компонента, положение и ориентация компонента, имя, цвет, видимость и т.п. Собственно геометрия всегда хранится в деталях (parts), но именно компоненты определяют, каким образом эта геометрия отображается в сборке.

API Инвентора предоставляет доступ к информации как ссылок, так и компонентов сборки. Ниже на рисунке показана часть объектной модели сборки (AssemblyDocument) вместе с данными документа сборки. Объект ReferencedFileDescriptor представляет собой конкретную ссылку на файл. Коллекция ReferencedFileDescriptors позволяет организовать цикл по всем ссылкам на файлы сборки. Изменить ссылку возможно через интерфейс Apprentice Server . Объект ComponentOccurrence представляет компоненты сборки, причем как детали, так и подсборки. Коллекция ComponentOccurrences дает возможность организовать цикл по всем компонентам на текущем уровне сборки и, кроме того, поддерживает методы для вставки в этот уровень новых компонентов. Важно помнить, что возвращаемая информация относится к ссылкам и компонентам, непосредственно (напрямую) включенным в сборку, т.е. мы не получим никаких данных о составе подсборок. Получение доступа к содержимому подсборок будет рассмотрено в следующем разделе, посвященном технике обхода всего дерева сборки.


Обход дерева сборки[править]

Обход иерархического дерева сложных сборок является необходимым этапом в решении многих задач. Рассмотрим пример сборки. Она имеет всего два уровня, но рассматриваемый подход будет работать при любом количестве уровней. В данном примере сборка верхнего уровня Car.iam состоит из двух ранее рассмотренных колесных сборок и кузовной детали. На схеме показано внутреннее представление сборки Car.iam. Обратите внимание, она содержит информацию только об элементах на своем верхнем уровне. Нет никаких данных о составе колесных подсборок. Их состав определен в подсборке WheelAssembly.iam.


Рассмотрим фрагмент API, который обеспечивает просмотр как текущего, так и всех подчиненных уровней сборки, и получение всей необходимой информации о составляющих ее деталях и подсборках.

Для просмотра дерева сборки нам сначала необходимо у объекта AssemblyComponentDefinition получить ссылку на коллекцию ComponentOccurrences компонентов данной сборки. Итеративный перебор элементов этой коллекции возвращает объекты типа ComponentOccurrence. Если компонент представляет собой деталь, вы можете исследовать ее геометрию, опираясь на возвращаемую компонентом информацию о поверхностях. Если же компонент оказался подсборкой, свойство SubOccurrences объекта ComponentOccurrence предоставит возможность перебора составляющих ее компонентов. Свойство SubOccurrences возвращает объект ComponentOccurrenceEnumerator, весьма похожий на коллекцию ComponentOccurrences. Отличие состоит в том, что он не поддерживает добавление новых компонентов, а служит исключительно целям эффективного перебора существующих. При обходе дерева сборки произвольной вложенности вы просто опускаетесь на уровень ниже, если объект ComponentOccurrence оказывается подсборкой.

Public Sub AssemblyTraversal()
    ' Ссылка на активный документ. Полагаем, что это сборка.
    Dim oAsmDoc As AssemblyDocument
    Set oAsmDoc = ThisApplication.ActiveDocument
    
    ' Начинаем обход сборки
    Call TraverseAsm(oAsmDoc.ComponentDefinition.Occurrences, 1)
End Sub

' Аргумент Level необходим для вычисления левого отступа при печати.
Private Sub TraverseAsm(oOccurrences As ComponentOccurrences, Level As Integer)
    ' перебор списка компонентов на текущем уровне иерархии.
    Dim oOcc As ComponentOccurrence
    For Each oOcc In oOccurrences
        ' вывод на печать имени текущего компонента
        Debug.Print Space(Level * 3) & oOcc.Name
        
        ' Если текущий компонент – подсборка, то вызываем эту процедуру 
        ' снова с текущим компонентом в качестве параметра.
        If oOcc.DefinitionDocumentType = kAssemblyDocumentObject Then
            Call TraverseAsm(oOcc.SubOccurrences, Level + 1)
        End If
    Next
End Sub

Первое, что бросается в глаза — задача решается не одной процедурой, а двумя. Для просмотра сборочной иерархии произвольной вложенности мы вынуждены воспользоваться рекурсивной процедурой. Здесь рекурсия — вызов функции или процедуры из неё же самой. Процедура TraverseAsm выполняет всю работу по перебору компонентов на уровне текущей сборки и, если наткнется на подсборку, вызывает сама себя для ее просмотра. Так продолжается до тех пор, пока не будут пройдены все подсборки. Процедура же AssemblyTraversal лишь дает старт этому процессу. Результат данного примера очень прост — будут напечатаны имена всех компонентов сборки по мере их обнаружения. Однако с каждым компонентом может быть выполнена гораздо более сложная операция. Например, у деталей могут быть вычислены объемы, которые, будучи просуммированы, дадут общий объем всей сборки. Другой пример — формирование спецификации, в процессе чего потребуется и доступ к документу, на который ссылается компонент, и точная информация о свойствах.

Прокси-объекты (Proxy)[править]

Что такое прокси-объект ?[править]

Как уже отмечалось, сборки содержат только ссылки, но не геометрию. На первый взгляд, это противоречит опыту конечных пользователей, которые в Инвенторе создают и редактируют сборки. С их точки зрения геометрия деталей реально участвует в сборках. Например, при наложении зависимости совмещения двух деталей вы вольны выбрать грань детали, не задумываясь, где в действительности находится информация о геометрии этой детали. Примерно так же обстоит дело и при работе с API — вы можете просматривать иерархию сборки, получая доступ к ее компонентам и их содержимому, как если бы они находились на верхнем уровне сборки.

В предыдущем примере с демонстрацией перебора компонентов сборки мы так и делали. Мы могли просматривать все ветви сборки и получать ссылки на любой объект ComponentOccurrence в пределах сборки. Если мы попробуем выяснить положение объекта ComponentOccurrence, ответом будет положение, как если бы он находился на верхнем уровне сборки. Если компонент ссылается на деталь, и мы с его помощью получим ссылку на объект B-Rep, информация о геометрии B-Rep будет возвращаться в контексте верхнего уровня сборки.

Чтобы увидеть, как это работает, вернемся к сборке WheelAssembly. В ней имеются два экземпляра детали Колесо (Wheel). Каждый экземпляр (instance) представлен компонентом ComponentOccurrence. Допустим, мы хотим, чтобы пользователь выделил внешние цилиндрические поверхности каждого колеса. Первый вопрос: каким образом пользователь сможет это сделать, если геометрия деталей не присутствует в сборке? Второй вопрос: если предположить, что мы каким-то образом можем выделить геометрию, как отличить внешний цилиндр одного колеса от внешнего цилиндра другого, если в действительности в детали Wheel существует лишь один внешний цилиндр?


Ответом на оба вопроса будет — прокси-объекты (proxy). Прокси-объекты представляют объекты в сборке так, как если бы эти объекты на самом деле существовали в сборке. К идее прокси-объектов надо привыкнуть, но как только их концепция станет понятной, работать с ними будет уже нетрудно. Вернемся к цилиндрическим граням колес. Когда вы выделяете в сборке одну из них, вы в действительности выделяете объект FaceProxy. Объект FaceProxy наследуется из объекта Face, поэтому он имеет те же методы и свойства, плюс еще несколько, характерных только для прокси-объектов. С объектом FaceProxy, как наследником объекта Face, вы как правило можете работать как с обычной гранью, и даже не требуется особо задумываться, что в действительности вы работаете с прокси-объектом. Для работы с объектом вы используете те же методы и свойства, отличие лишь в том, что получаемые результаты будут определяться положением объекта в сборке.

Прокси-объект устроен довольно просто. Это путь к объекту. Например, пути к цилиндрическим граням двух наших деталей-колес будут иметь следующий вид:

    Wheel:1\CylinderFace
    Wheel:2\CylinderFace


Здесь «CylinderFace» представляет реальную цилиндрическую грань детали колеса.

Первая часть пути — компонент, последняя часть пути — действительный объект. В многоуровневой сборке путь будет длиннее, потому что в нем будет много компонентов. В сборке всей машины с четырьмя колесами путь к цилиндрической грани одного из колес имеет вид:

    WheelAssembly:1\Wheel:2\CylinderFace

Благодаря пути прокси-объекта, Инвентор в состоянии точно определить, на какой именно объект в сборке вы ссылаетесь.

Прокси-объекты поддерживаются для большого количества объектов. Эта поддержка необходима всякому объекту, который в сборке должен быть выделяемым. На самом деле нам уже приходилось иметь дело с прокси-объектами ComponentOccurrenceProxy — в программе перебора компонентов сборки, но это происходило неявно, поскольку мы могли обрабатывать их как обычные компоненты ComponentOccurrence. Компоненты на верхнем уровне сборки являются обычными объектами ComponentOccurrence. Они на самом деле существуют на верхнем уровне сборки. Когда вы перебираете компоненты в любой из подсборок WheelAssembly, возвращаемые объекты имеют тип ComponentOccurrenceProxy. Это так, потому что эти компоненты входят в сборку не на верхнем уровне, а принадлежат колесным подсборкам. Объект ComponentOccurrenceProxy создает видимость принадлежности компонента верхнему уровню сборки. Если запросить у ComponentOccurrenceProxy его положение, он вернет его в контексте верхнего уровня сборки.

Обычно, при получении прокси-объекта в результате перебора сборки или выбора пользователем, вас нисколько не волнует, что вы работаете с прокси-объектом, а не с самим объектом. Именно в этом и состоит самая замечательная особенность прокси-объектов — они упрощают работу с объектами из различных файлов, обеспечивая видимость, будто все объекты существуют непосредственно в самой сборке, как это и представляется конечному пользователю.


Создание прокси-объектов[править]

Бывают случаи, когда необходимо создать прокси-объект для передачи его другим методам в качестве аргумента. Чаще всего это случается при программном создании сборки и наложении сборочных зависимостей. Рассмотрим конкретный пример. Пусть имеется болт, который мы желаем автоматически вставлять в сборку. Круглое ребро, указанное на рисунке справа, будет использоваться как аргумент при наложении зависимости. Чтобы легко найти это ребро, когда болт будет уже в сборке, к ребру добавлен атрибут «AutoBolts».


Рассмотрим внимательнее, что происходит в сборке, изображенной на рисунке справа. Сборка состоит из двух деталей, между которыми мы намереваемся установить зависимость. Предположим, мы уже получили компонент-кубик и, используя механику B-Rep объектов, — круглое ребро отверстия. Поскольку мы добрались до ребра через компонент, это будет прокси-объект EdgeProxy, что означает, что он ведет себя как если бы это ребро действительно существовало в сборке. Теперь нам следует получить объект EdgeProxy для ребра в болте. Для поиска ребра к нему был добавлен атрибут, однако этот атрибут существует в детали Болт, а не в сборке. Если попробовать искать атрибут в сборке, мы его не найдем. На самом деле искать атрибут следует в пределах документа Болт. Поскольку. мы проводим поиск в документе Болт, возвращаемый объект будет действительным ребром, а не его прокси-объектом. API предоставляет нам инструменты для создания прокси-объекта. Пример иллюстрирует доступ к документу детали, запрос на поиск ребра, создание прокси-объекта и, наконец, наложение сборочной зависимости. Предполагается, что у мы уже имеем EdgeProxy для ребра на кубике и ссылку на компонент Болт.

' Доступ к определению компонента Болт из самого компонента Болт.  
Dim oBoltCompDef As ComponentDefinition
Set oBoltCompDef = oBoltOccurrence.Definition

‘ Запрос на поиск ребра посредством менеджера атрибутов документа Болт
Dim oAttribManager As AttributeManager
Set oAttribManager = oBoltCompDef.Document.AttributeManager
Dim oObjects As ObjectCollection
Set oObjects = oAttribManager.FindObjects("AutoBolts")

Dim oBoltEdge As Edge
Set oBoltEdge = oObjects.Item(1)

' Создание для ребра прокси-объекта.
Dim oAsmBoltEdge As EdgeProxy
Call oBoltOccurrence.CreateGeometryProxy(oBoltEdge, oAsmBoltEdge)

' Наложение сборочной зависимости.
Call oDoc.ComponentDefinition.Constraints. _
       AddInsertConstraint(oBlockEdge, _
                           oAsmBoltEdge, _
                           True, 0)


Пример иллюстрирует ряд важных моментов. В свойстве Definition компонент ComponentOccurrence возвращает объект ComponentDefinition документа, на который компонент ссылается. В нашем случае результатом будет объект PartComponentDefinition детали Болта. Это тот же самый объект ComponentDefinition, который мы получаем как свойство ComponentDefinition документа PartDocument. Всякий раз, когда вы используете свойство Definition компонента, вы покидаете контекст сборки и далее все операции будут выполняться в контексте детали. А имея доступ к документу детали, вы получаете в свое распоряжение весь предназначенный для этих объектов инструментарий API. К примеру, вам доступны на изменение значения параметров, и можно даже добавлять новые конструктивные элементы. Через свойство Document объекта ComponentDefinition можно получить ссылку на родительский документ определения компонента. В данном случае будет получена ссылка на объект PartDocument болта. В примере этот документ используется для получения доступа к менеджеру атрибутов документа Болт. Он вызывает метод FindObjects менеджера атрибутов для получения ссылки на ассоциированное с атрибутом ребро.

Как только ребро в детали найдено, следует создать прокси-объект для представления этого ребра в сборке. Как уже отмечалось, прокси-объект определяет путь к объекту. В файле детали мы имеем объект, и теперь нам требуется добавить к нему путь, чтобы определить тот же объект, но уже в сборке. Делается это с помощью метода CreateGeometryProxy объекта ComponentOccurrence. На вход метода подается объект, на выходе имеем соответствующий прокси-объект. Метод всего-навсего добавляет компонент к пути прокси-объекта. В итоге мы имеем объект, представляющий ребро в контексте сборки.

Последняя строка примера использует прокси-объект болта и прокси-объект кубика для наложения зависимости вставки.

На вход методу CreateGeometryProxy можно подать и прокси-объект. Именно так формируется многоуровневая сборка. Чтобы ее получить, вы начинаете снизу от самого объекта и затем вызываете метод CreateGeometryProxy на каждом уровне сборки, пока не выстроите полный прокси-путь.

Работа с прокси-объектами[править]

API содержит также ряд дополнительных инструментов для работы с прокси-объектами. Многие из них полезны не только в обычной работе, но и для первоначального знакомства с прокси-объектами и для отладки программ с прокси-объектами.

Как уже отмечалось, различные прокси-объекты наследуются из соответствующих им действительных объектов. По этой причине они поддерживают все методы и свойства объектов-родителей. Но есть у них два дополнительных свойства, которых у родителей нет — ContainingOccurrence и NativeObject. Свойство ContainingOccurrence возвращает компонент ComponentOccurrence, через который виден прокси-объект. В предыдущем примере свойство ContainingOccurrence прокси-объекта ребра в болте вернет компонент Болт.

Свойство NativeObject возвращает настоящий объект, представляемый прокси-объектом. В нашем примере, свойство NativeObject объекта EdgeProxy вернет дествительный объект Ребро (Edge).

Одним из общих свойств объектов и их прокси является свойство Parent (родитель). Но хотя свойство общее, возвращаемая ссылка указывает на разных родителей. В нашем примере, свойство Parent настоящей грани вернет объект SurfaceBody детали, тогда как Parent прокси-объекта EdgeProxy вернет объект SurfaceBodyProxy, представляющий тело в контексте сборки. Еще две дополнительных функции — свойство OccurrencePath и метод AdjustProxyContext. Свойство OccurrencePath, поддерживаемое компонентом ComponentOccurrence и его прокси ComponentOccurrenceProxy, возвращает путь к компоненту. Это тот же путь, который использует любой прокси-объект данного компонента.



Литература[править]

[1] Brian Ekins. How Deep is the Rabbit Hole? Examing the Matrix and other Inventor® Math and Geometry Objects. Лекция DE205-2, Autodesk University 2008.