Функция in_polygon(), показанная здесь - часть Tools.py. Она принимает точку (Вектор) и список вершин (объекты MVert) и возвращает или Истину или Ложь. Заметьте, что любая z-координата у точки или у вершины в многоугольнике игнорируются.
from Blender.Geometry import LineIntersect2D
from Blender.Mathutils import Vector as vec
def in_polygon(p,polygon):
intersections = 0
n = len(polygon)
if n<3 : return False
for i in range(n):
if LineIntersect2D (p,vec(1.0,0.0,0.0),polygon[i].
co,polygon[(i+1)%n].co):
intersections+=1
return intersections % 2 == 1
Трудная задача выполняется на выделенной строке функцией LineIntersect2D(), доступной в модуле Blender.Geometry. Действие деление по модулю (%) в операторе return - способ определить, нечетное ли количество пересечений.
Собираем всё вместе: Engrave.py
Вооруженные всеми вспомогательными функциями, разработанными в предыдущих секциях, мы можем сделать список шагов, которые мы должны предпринять для того, чтобы выгравировать текст:
1. Показать всплывающее меню для ввода строки, которую надо гравировать.
2. Проверить, что активный объект - меш, и выбраны грани.
3. Создать объект Text3d.
(на самом деле скрипт engrave.py требует, чтобы объект Text3d уже был создан и выбран как активный, так что первые 3 пункта не полностью соответствуют действительности — прим. пер.)
4. Преобразовать его в меш, с подходящими группами вершин.
5. Добавить дополнительные рёберные циклы к символам.
6. Выдавить оригинальные символы вниз.
7. Заполнить низ выдавленных символов.
8. Добавить "cartouche" (прямоугольник) вокруг текста.
9. Заполнить пространство между cartouche и символами.
10.Добавить модификатор subsurface.
11.Установить величину crease (складки) на рёбрах, содержащихся в группах вершин TextTop и TextBottom.
Наш окончательный скрипт следует за этой схемой почти в точности и использует инструменты, которые мы разработали раньше в этой главе. Мы покажем здесь наиболее важные секции (полный скрипт доступен как engrave.py). Мы начинаем с преобразования объекта Text3d (c в следующем коде) в список, содержащий список позиций вершин для каждого сегмента кривой в тексте, и мы добавляем новый пустой Меш-объект в сцену с несколькими пустыми группами вершин:
vlist = curve2mesh(c)
me = Blender.Mesh.New('Mesh')
ob = Blender.Scene.GetCurrent().objects.new(me,'Mesh')
me.addVertGroup('TextTop')
me.addVertGroup('TextBottom')
me.addVertGroup('Outline')
Следующий шаг должен добавить эти вершины в меш и создать соединяющие рёбра. Так как все сегменты кривой в символе замкнуты, мы должны позаботиться о добавлении дополнительного ребра, чтобы соединить мостом промежуток между последней и первой вершиной, как показано на выделенной строке. На всякий случай, мы удаляем любые задвоения, которые могут присутствовать в интерполированном сегменте кривой. Мы добавляем вершины к группе вершин TextTop и сохраняем ссылку на список новых рёбер для будущего использования.
loop=[]
for v in vlist:
offset=len(me.verts)
me.verts.extend(v)
edgeoffset=len(me.edges)
me.edges.extend([(i+offset,i+offset+1)
for i in range(len(v)-1)])
me.edges.extend([(len(v)-1+offset,offset)])
me.remDoubles(0.001)
me.assignVertsToGroup('TextTop',
range(offset,len(me.verts)),
1.0,
Blender.Mesh.AssignModes.ADD)
loop.append([me.edges[i] for i in range(edgeoffset,
len(me.edges) )])
Для каждого рёберного цикла, который мы сохранили в предыдущей части, мы создаем новый, и немного больший, рёберный цикл вокруг него и добавляем эти новые вершины и рёбра к нашему мешу. Мы также хотим создать грани между этими рёберными циклами, и это действие начинается на выделенной строке: здесь мы используем встроенную функцию Питона zip(), чтобы получить пары рёбер двух рёберных циклов. Каждый рёберный цикл упорядочен вспомогательной функцией (доступной в Tools.py), которая сортирует рёбра, чтобы они лежали в порядке, в котором они соединены друг с другом. Для каждой пары рёбер мы создаем две возможных организации индексов вершин и вычисляем, какая из них формирует нескрученную грань. Это вычисление производится посредством функции least_warped() (код не показан), которая основана на сравнении периметров граней, заданных двумя различными порядками вершин. Нескрученная грань будет иметь самый короткий периметр, именно её мы затем добавляем к мешу.