Введение
Недавно на нашем сайте вышла новость о разработке приложения для КОМПАС-3D, позволяющего автоматизировать процесс моделирования строительных лесов. Уникальность данного приложения состоит в том, что компоненты строительных лесов, добавляемые в сборку, могут автоматически сопрягаться между собой. И это “автосопряжение” не требует от конструктора задавать набор классических сопряжений, лишая компоненты степеней свободы.
Рассказывают:
методист Станислав Ермохин
и инженер-программист Александр Ряполов
На самом деле, нельзя сказать, что мы нашей проектной командой АСКОН-Волга создали что-то неведомое. Программные методы, которые были использованы для реализации функции автоматического сопряжения, давно доступны в API КОМПАС и применяются при разработке многих приложений для системы КОМПАС-3D. Одним из таких часто используемых примеров является приложение Оборудование: Трубопроводы. В нём эта возможность реализована в виде привязки деталей трубопроводной арматуры друг к другу или к трубопроводу.
Возвращаясь к “Строительным лесам”, расскажу, как была решена наиболее интересная задача - позиционирование компонентов в 3D-пространстве.
Приложение “Строительные леса” для КОМПАС-3D
Приложение, которое мы разработали, состоит из двух частей:
каталог элементов строительных лесов, используемых у заказчика;
собственно, программный модуль, который организует процесс сопряжения компонентов между собой.
Что касается каталога, то мы сделали его в виде библиотеки документов формата .KLE, который был реализован в КОМПАС-3D v17 и позволяет хранить в формате одного файла и 3D-модели, и 2D-фрагменты. Ещё один плюс такой реализации, что на пользователей это не накладывает дополнительных денежных затрат. Функционал работы с библиотеками элементов (KLE) поставляется в базовой лицензии КОМПАС-3D.
Хотя для нашего программного модуля не важно, как будет реализован каталог элементов. Он может располагаться в библиотеке элементов - как каталог файлов моделей на диске, а можно использовать систему управления НСИ ПОЛИНОМ:MDM.
Во всех этих случаях модуль будет работать с компонентами идентично.
Задачи программного модуля следующие:
отследить, что в сборку вставляется именно компонент строительных лесов;
при перемещении компонента по рабочему пространству поймать в фокусе другой компонент сборки и совместить их между собой согласно инструкции по сборке строительных лесов.
В этой статье рассмотрим, как с помощью API КОМПАС мы решили эти задачи.
Мы за тобой следим...
Первое, что нам необходимо решить на стадии аналитики - как мы будем сопрягать компоненты между собой. Способ, когда между собой сопрягаются вершины, рёбра и грани, мы даже не рассматривали по причине великого множества этих элементов на модели.
Мы знаем, что КОМПАС-3D позволяет создать на модели особые объекты - контрольные и присоединительные точки. Они обеспечивают расстановку компонентов сборки и их правильную стыковку друг с другом. Достаточно только у пары соединяемых компонентов создать необходимые присоединительные точки и правильно направить их векторы. Примерно, как это выглядит, изображено на картинке ниже.
Это только в статье всё выглядит просто. Но в рамках нашего проекта это оказалось самой “толстой” задачей. Потому как потребовало подробно перечитать инструкцию по сборке строительных лесов, сформировать матрицу точек соединения у всех компонентов и расставить эти точки на моделях компонентов. Хочу заметить, что некоторые компоненты, такие как стойки вертикальные, содержали количество точек, которое приближалось к сотне, так как к этим стойкам можно было навесить множество горизонтальных ригелей и наклонных связей.
В момент, когда мы определялись с точками, сразу договорились, в рамках проектной команды, что наличие присоединительной точки с определенным именем в модели является маяком, который нам необходимо отслеживать и сразу производить последующие действия. И нашем случае приняли, что все точки соединения будут иметь наименование:
point_NNN, где NNN - порядковый номер точек.
Кстати, тем из вас, кто пользовался приложением Оборудование: Кабели и жгуты (КиЖ), данный метод покажется знакомым. И это будет абсолютно верно, так как вариант отслеживания мы подсмотрели там. Только в КиЖ используется дополнительная контрольная точка, а мы сразу отслеживаем наличие присоединительной.
Далее был написан код на C#, который позволил отслеживать процесс вставки в сборку компонентов, считывать наличие присоединительных точек и запускать последующие функции работы с такими компонентами.
Для начала, нам необходимо было отслеживать событие BeginProcess - создание нового объекта. Пример перехвата событий представлен в SDK КОМПАС в проекте EventsAuto (SDK входит в стандартную поставку КОМПАС, необходимо просто включить его при установке КОМПАС). Событие BeginProcess принимает на вход два аргумента: pType - тип создаваемого объекта и obj - собственно создаваемый объект. Поскольку в нашей библиотеке компонентов все объекты представлены объектами типа деталь, первым делом проверяем, что добавляется объект искомого типа. Не забываем при перехвате события вернуть true, чтобы КОМПАС мог продолжить работу:
public bool BeginProcess(int pType, object obj)
{
if (pType != 104) // проверка, что добавляемый объект не деталь
return true;
...
}
Объект obj может быть представлен либо объектом типа ksFeature (объект дерева построения), либо ksFeatureCollection. В последнем случае необходимо перебрать все объекты ksFeature, входящие в коллекцию. Из объекта ksFeature получаем интерфейс добавляемой детали ksPart:
if (obj is ksFeature) // проверяем, что на вход пришел объект типа ksFeature
{
ksFeature feature = (ksFeature)obj; // преобразуем интерфейс в ksFeature
object objPart = feature.GetObject(); // получаем объект модели
if (objPart is ksPart) // проверяем, соответствие интерфейсу детали
{
ksPart part = (ksPart)objPart; // преобразуем в интерфейс детали
...
}
}
Далее необходимо проверить, что добавляемый объект является объектом строительных лесов. Признаком этого служит наличие у объекта присоединительных точек с обозначением point_NNN.
// получаем коллекцию присоединительных точек детали
ksEntityCollection pointCollection = part.EntityCollection(68);
for (int j = 0; j < pointCollection.GetCount(); j++)
{
// получаем интерфейс модели объекта
ksEntity entity = (ksEntity)pointCollection.GetByIndex(j);
// проверяем, что интерфейс соответствует интерфейсу присоединительной точки и имя присоединительной точки соответствует регулярному выражению regex (point_NNN)
if (entity != null && entity.GetDefinition() is ksConjunctivePointDefinition && regex.IsMatch(entity.name))
{
// получаем интерфейс параметров присоединительной точки
ksConjunctivePointDefinition definition = (ksConjunctivePointDefinition)entity.GetDefinition();
// запоминаем присоединительные точки и сам объект строительных лесов для дальнейшего отслеживания
…
}
}
Не забываем вернуть true в методе перехвата события, чтобы КОМПАС продолжил работу:
public bool BeginProcess(int pType, object obj)
{
… // всё описанное выше
return true;
}
Если на этом этапе вам показалось, что слишком много интерфейсов и их преобразований, спешу вас порадовать… дальше еще веселее.
… и прицеливаемся
А вот следующую задачку нам раскусить с наскока не удалось. И тут найти нужную функцию нам помогла наша команда разработки приложений для КОМПАС-3D.
Выяснилось, что для того чтобы отследить положение двух точке в 3D-пространстве, можно использовать два способа:
точное позиционирование по координатам объектов;
позиционирование по лучу взгляда.
Использовать позиционирование по координатам нас сразу отговорили. Монитор-то у нас плоский, а работаем мы с трехмерным пространством. И получается, что, совместив две точки на экране, мы совмещаем их только по двум осям, а третью ось (которая для нас идёт вглубь экрана) совместить не можем, не видя её. И будем вынуждены повернуть пространство, чтобы совместить и эту координату. Вот если бы у нас был плоский чертёж, то была бы красота. Но, увы.
Луч взгляда смотрит перпендикулярно экрану и, условно, преобразует координаты точки объекта на ближайшие координаты экрана. Получается, если мы хотим совместить точки двух объектов, у которых разная глубина расположения перпендикулярно экрану, то эта самая глубина для нас не будет иметь никакого значения. Достаточно точно визуально совместить на экране. Это, как раз, то что нам нужно.
Для сопряжения создаваемого объекта с уже существующим нам необходимо отслеживать изменение координат присоединительных точек нового объекта с теми объектами, что уже есть на сборке. Получение элементов строительных лесов на сборке мало чем отличается от получения создаваемого объекта, с той лишь разницей, что мы получаем объекты не от перехвата событий, а перебираем объекты в дереве построения (на самом деле это сделано заранее, до перехвата события, чтобы не замедлять работу КОМПАС-3D). При запуске приложения мы получили интерфейс KompasObject, посредством которого и получаем дерево построения:
// получаем интерфейс документа из объекта KompasObject
ksDocument3D Document = (ksDocument3D)Kompas.ActiveDocument3D();
// получаем коллекцию элементов дерева построения
ksPartCollection parts = (ksPartCollection)Document.PartCollection(true);
for (int i = 0; i < parts.GetCount(); i++)
{
ksPart part = (ksPart)parts.GetByIndex(i); // получаем интерфейс объекта
… // по аналогии с кодом выше, получаем присоединительные точки и запоминаем объект
}
Теперь можем переходить к поиску совпадений. Отслеживаем изменение координат присоединительных точек создаваемого объекта.
double x = 0, y = 0, z = 0;
definition.GetPoint(out x, out y, out z);
Метод GetPoint возвращает координаты в локальной системе координат (в системе координат детали). Для сравнения координат присоединительных точек разных объектов их необходимо привести к какой-то общей системе координат. Логичнее всего использовать систему координат сборки:
ksPart topPart = Document.GetPart(-1); // получаем головной объект сборки
// преобразуем координаты присоединительной точки в координаты сборки
topPart .TransformPoint(ref x, ref y, ref z, part);
Разумеется, всё это проделано и для присоединительных точек тех элементов, что уже присутствуют в сборке. Далее всё просто (если бы), сравниваем координаты присоединительных точек. Для сравнения 3D-координат переводим их в 2D-координаты плоскости экрана с помощью матрицы преобразований, которую получаем перехватом события отрисовки документа
public bool ClosePaint(IPaintObject paintObj)
{
// получаем коэффициенты матрицы преобразований
double a11 = 0, a12 = 0, a13 = 0, a14 = 0, a21 = 0, a22 = 0, a23 = 0, a24 = 0;
paintObj.GetTransformMatrix(out a11, out a12, out a13, out a14, out a21, out a22, out a23, out a24);
return true;
}
Далее определимся с названием объектов, имеющих присоединительные точки:
master - для нового объекта;
slave - для существующего объекта (да простят нас BLM).
// сравниваем имена присоединительных точек
if (master.Entity.name == slave.Entity.name )
{
// приводим координаты к координатам экрана
double masterScreenX = a11master.X + a12master.Y + a13master.Z + a14;
double masterScreenY = a21master.X + a22master.Y + a23*master.Z + a24;
… // аналогично получаем экранные координаты точки slave и сравниваем их с координатами точки master
}
Для пары совпадающих присоединительных точек (естественно, совпадение проверяется в определённом радиусе) выполняем сопряжение “Совпадение”. Направление сопряжения определяется направлением векторов присоединительных точек.
Document.AddMateConstraint(0,slave.Entity, master.Entity, 1, 1); // выполняем сопряжение
Разумеется, это далеко не весь код. Помимо этого выполняются проверки, как детали могут сопрягаться между собой, например, ригель не может “втыкаться” в ригель, а также проверяется, что точка уже “занята” другим сопряжением, но это уже не относится напрямую к API КОМПАС.
В качестве заключения
В статье мы рассказали, как с помощью API КОМПАС удалось решить две основные задачи при разработке приложения. Конечно, это не все задачи, с которыми мы столкнулись в процессе разработки. Например, мы предусмотрели ситуацию, когда пользователь может не с первого раза попасть в точку совмещаемых компонентов и необходимо делать перебор точек по компоненту. Но эта и подобные задачи решаются написанием соответствующих функции без обращения к API КОМПАС. А в общем случае статья дает представление, как решать задачи отслеживания вставки компонентов и позиционирования в трехмерном пространстве и на экране монитора при реализации собственных приложений.