В САПР сборочные операции достаточно типичны. Для расположения и соединения компонентов имеется целый арсенал соответствующих команд. Приложение Blender, основное назначение которого — 3D-визуализация, эффективные средства взаимного позиционирования сеточных деталей реализует посредством Python API.
Создание моделей изделий в CAD-приложениях базируется на понятии сборочной зависимости-связи-сопряжения (или Constraint). Детали-компоненты могут добавляться в пространство сборки произвольным образом, а их точное взаимное расположение (и соответствующая подвижность) определяется налагаемыми на них сопряжениями (рис. 1).

Рис. 1. Сборка Компас-3D с системой компонентов и их сопряжений
В такой системе, как КОМПАС-3D, имеется богатая палитра сборочных сопряжений, названия которых сами говорят о типе образующейся связи, например Совпадение, Соосность, Параллельность, Угол, Касательность. Процесс добавления сопряжений достаточно прост — необходимо указать на соединяемых компонентах геометрические элементы, непосредственно участвующие в образующейся связи. Например, указание двух ребер соединяемых деталей не только позиционирует компоненты так, чтобы эти ребра были коллинеарны, но и сохраняет эту связь при перемещении или вращении объектов-операндов (рис. 2).

Рис. 2. Сопряжение-совпадение двух компонентов в системе Компас-3D по указанным ребрам
А как обстоит дело со взаимным позиционированием компонентов в программах для работы с 3D, основная направленность которых связана со сферой мультимедиа? В том же Blender мы имеем богатый, объективно заслуживающий уважения функционал для настройки освещения и материалов, анимации и детального редактирования геометрии на уровне вершин, ребер и полигонов-граней. Эквивалентом CAD-сборки в Blender является модель, состоящая из нескольких полигональных сеток, каждая из которых представляет отдельную деталь-компонент (рис. 3).

Рис. 3. Модель-сборка из нескольких полигональных сеток в Blender
Изменяя координаты и ориентацию сеток-деталей, Blender позволяет устанавливать их ключевые положения на шкале времени, которые, в свою очередь, определяют, например, анимацию сборки (рис. 4).

Рис. 4. Анимация сборки в Blender по ключевым положениям
Определенную сложность представляет только задание точных относительных позиций сеточных деталей. Штатный инструментарий Blender под названием Snapping (Привязки) весьма своеобразен и для позиционирования большого количества компонентов трудноприменим (рис. 5). В связи с этим неслучайно появление таких надстроек, как Mesh Align Plus, работа с которыми (см. рис. 5) не в пример запутанней тривиального наложения сопряжения в типичной CAD, например КОМПАС-3D (см. рис. 2).

Рис. 5. Штатный инструмент объектной привязки Snapping и надстройка Mesh Align Plus в Blender
Если речь идет о позиционировании объекта на плоскости, то достаточно указать точку его размещения и ориентационный угол. Например, в случае установления однозначного взаимного расположения двух деталей (рис. 6) на каждой из них нужно указать базовую точку (b) и точку ориентации (р). Отрезок, соединяющий базовую точку с точкой ориентации, можно считать направляющим — согласно тому углу, который он образует, например, с горизонталью, проведенной через базовую точку. Тогда для совмещения деталей требуется совпадение базовых точек и приведение угла поворота направляющего отрезка одной детали к соответствующему углу второй.

Рис. 6. Схема перемещения исходного объекта (ob1) к объекту-цели (ob2) по базовым точкам (b1, b2) и направляющим отрезкам (p1b1, p2b2)
Отсчет направляющих углов (u1 и u2) отрезков будем вести по часовой стрелке от горизонтали, проведенной через базовую точку (рис. 7). Тогда направляющие углы могут быть рассчитаны по координатам базовой точки (b) и направляющей точки (p) согласно алгоритму перевода прямоугольных координат в полярные (рис. 8).

Рис. 7. Ориентационные углы (u1, u2) направляющих отрезков (p1b, p2b)

Рис. 8. Алгоритм расчета ориентационного угла (u) на основе координат вершин направляющего отрезка
Угол (du), необходимый, чтобы довернуть исходный объект (ob1, см. рис. 6) в целевое положение (ob2, см. рис. 6), можно рассчитать по схеме, приведенной на рис. 9. Идея алгоритма заключается в минимизации угла доворота du (являющегося разницей между u2 и u1) так, чтобы он не превышал 180 градусов.

Рис. 9. Алгоритм расчета угла поворота (du) перемещаемого объекта от начального угла (u1) к конечному (u2)
Общий алгоритм переноса перемещаемого объекта приведен на рис. 10.

Рис. 10. Общий алгоритм поворота и переноса перемещаемого объета в системе Blender по указанным базовым и направляющим точкам
Остановимся на некоторых аспектах реализации алгоритма посредством Python API [1].
Считывание активного или выбранного пользователем меш-объекта выполняется соответствующими строками (для объекта-цели):
to_ob=bpy.context.active_object
objs=bpy.context.selected_objects
Здесь bpy — общая библиотека Python системы Blender. Перемещаемый объект (from_ob) считывается как второй по счету из коллекции выбранных (objs).
Для получения доступа к элементам сетки (меш), например вершинам, следует перейти в режим редактирования:
bpy.ops.object.mode_set(mode=’EDIT’)
bm=bmesh.from_edit_mesh(to_ob.data)
Перебор истории выделенных элементов сетки осуществляется в обратном порядке так, что последняя выделенная вершина объявляется базовой (b1 или b2), а предпоследняя — направляющей (p1 или p2). Функция isinstance проверяет, чтобы объект выделения был именно вершиной (тип BMVert). Ниже представлен код чтения базовой (b2) и направляющей (p2) точки объекта-цели:
for elem in reversed(bm.select_history):
if isinstance(elem, bmesh.types.BMVert):
if i==0:
b2=elem
else:
p2=elem
i+=1
if i>1:break
Чтение координат вершин выполняется посредством метода co с преобразованием возвращаемого им значения в кортеж. Например, для базовой точки объекта-цели:
b2_x=b2.co.to_tuple()[0]
b2_y=b2.co.to_tuple()[1]
b2_z=b2.co.to_tuple()[2]
Функция расчета ориентационного угла выбранной сетки на основании координат базовой и направляющей точки (см. рис. 8) может быть реализована следующим кодом:
def f_angle(xb, yb, xp, yp):
dist=math.sqrt((yp-yb)**2+(xp-xb)**2)
u=math.acos((xp-xb)/dist)
if (yp>yb):
u=2*math.pi-u
return u
Расчет угла поворота перемещаемого объекта на основании алгоритма (см. рис. 9) приведен во фрагменте:
du=f_angle(b2_x,b2_y,p2_x,p2_y)-f_angle(b1_x,b1_y,p1_x,p1_y)
if (du>math.pi):
du=du-2*math.pi
elif (du<-math.pi):
du=2*math.pi-abs(du)
Сам поворот объекта перемещения (вокруг оси z) осуществляется методом задания эйлеровых углов:
from_ob.rotation_euler=(0,0,-du)
После поворота объекта необходимо актуализировать глобальные координаты его базовой точки. Для этого, во-первых, нужно считать матрицу глобальных координат объекта перемещения:
wm=from_ob.matrix_world.copy()
А во-вторых, следует перемножить эту матрицу на вектор локальных координат базовой точки:
coord_global=wm @ b1.co
Глобальные координаты базовой точки перемещаемого объекта после его поворота:
b1_x_v2=coord_global[0]
b1_y_v2=coord_global[1]
b1_z_v2=coord_global[2]
Новые координаты объекта перемещения рассчитываются по разнице соответствующих координат базовых точек объекта-цели и перемещаемого объекта:
x_new=b2_x-b1_x_v2
y_new=b2_y-b1_y_v2
z_new=b2_z-b1_z_v2
Установка перемещаемого объекта в целевую позицию осуществляется методом location:
from_ob.location=(x_new, y_new, z_new)
Использование описанного алгоритма заключается в следующем. Сначала выделяется объект, который следует переместить, и для него открывается режим Edit Mode. Далее устанавливается выбор вершин и при зажатом Shift сначала указывается направляющая точка-вершина, а затем — базовая (рис. 11а). После этого аналогично через Edit Mode выбираются направляющая и базовая точки на объекте-цели (рис. 11б).

Рис. 11. Указание направляющих и базовых точек на перемещаемом объекте и объекте-цели
После выбора всех четырех необходимых точек теперь уже в режиме Object Mode при зажатом Shift выделяется объект для перемещения и объект-цель (рис. 12а). Наконец с помощью меню Scripting в Blender загружается (или вводится) скрипт, реализующий алгоритм переноса выделенного объекта в заданное положение (см. рис. 10) [2]. В результате запуска скрипта первый из двух выделенных объектов переносится в новое положение, определяемое базовыми точками, и поворачивается на угол, рассчитанный по направляющим вершинам (см. рис. 12б).

Рис. 12. Выделение перемещаемого объекта и объекта-цели для осуществления переноса-совмещения
Таким образом, в системе Blender можно реализовать пространственное совмещение компонентов-сеток (мешей) по указанным в них геометрическим элементам (вершинам), получая подобие статичной сборки CAD-системы. Данный подход применим к моделям, как создаваемым непосредственно в Blender, так и загружаемым в эту программу из других систем. В контексте САПР методику можно применять, например, для визуализации «взрывных» схем или схем сборки-разборки каких-либо узлов по готовым моделям (см. рис. 4) [3].
Полезные ссылки:
- Blender Python API //https://docs.blender.org/api/current/info_quickstart.html.
- Проект, рассмотренный в материале //https://disk.yandex.ru/d/q1MEo5_pYmIr8A.
- Видео о проекте //https://rutube.ru/video/fabdf81cc21d5d8b466ef906758c8683




