Здравствуйте!
В предыдущем уроке мы научились создавать массивы элементов с помощью циклов for в Python. Мы увидели, как, комбинируя циклы с Locations, можно программно генерировать линейные, сеточные и даже круговые паттерны. Это мощный и гибкий подход, который полностью раскрывает возможности "CAD-as-Code".
Однако для самых частых задач — создания рядов и круговых массивов — существует более простой и декларативный способ. Цель этого урока — изучить встроенные в build123d инструменты LinearPattern и CircularPattern. Они позволяют создавать такие же массивы элементов, но делают код более коротким, читаемым и менее подверженным ошибкам, так как вся математика скрыта "под капотом". Мы сравним этот подход с ручным созданием через циклы и увидим его преимущества.
1. От цикла к LinearPattern
Вспомним, как мы создавали ряд отверстий в прошлом уроке. Нам приходилось вручную вычислять начальную позицию, а затем в цикле рассчитывать координату x для каждого отверстия.
# Фрагмент из прошлого урока
start_x = -((hole_count - 1) * hole_spacing) / 2
for i in range(hole_count):
x_pos = start_x + i * hole_spacing
with Locations((x_pos, 0)):
Circle(hole_radius)
LinearPattern позволяет заменить этот код одной строкой. Он берет один или несколько 2D-объектов и создает их копии вдоль заданной линии.
Давайте создадим новый файл lesson12_patterns.py и перепишем пример с рядом отверстий, используя LinearPattern.
# lesson12_patterns.py
from build123d import *
# Параметры
plate_len = 100
plate_width = 50
plate_height = 5
hole_radius = 4
hole_count = 5
hole_spacing = 20
with BuildPart() as part:
# 1. Создаем базовую пластину
Box(plate_len, plate_width, plate_height)
# 2. Создаем эскиз на верхней грани
with BuildSketch(part.faces().sort_by(Axis.Z)[-1]) as sketch:
# 3. Создаем ОДНУ окружность, которая будет "шаблоном"
# 4. Применяем к ней LinearPattern
LinearPattern(
x_spacing=hole_spacing,
count=hole_count,
)
Circle(hole_radius) # Эта окружность будет размножена
# 5. Выдавливаем все созданные окружности
extrude(amount=-plate_height, mode=Mode.SUBTRACT)
# Отображаем результат
show_object(part.part, name="Linear Pattern of Holes")
Запустите код. Результат будет идентичен тому, что мы получали с помощью цикла for. Однако обратите внимание на разницу в подходе внутри BuildSketch:
- Мы больше не используем
Locationsи не вычисляем координаты вручную. - Мы создаем только одну "исходную" фигуру (
Circle). LinearPatternприменяется до создания фигуры. Он действует как модификатор для всех последующих объектов внутри своего контекста (в данном случае, дляCircle).- По умолчанию, паттерн центрируется относительно начала координат эскиза. Это очень удобно.
Основные параметры LinearPattern:
x_spacing,y_spacing: шаг между элементами по осям X и Y.count: общее количество элементов (включая исходный).x_count,y_count: если нужно создать сетку, можно указать количество элементов по каждой оси.
Этот декларативный стиль ("создай мне линейный массив из 5 окружностей с шагом 20") гораздо лучше отражает намерение, чем императивный стиль цикла ("повтори 5 раз: посчитай координату, сместись, нарисуй окружность"). Для вас, как для опытного разработчика, преимущество в читаемости и поддержке такого кода должно быть очевидно.
2. От тригонометрии к CircularPattern
В конце прошлого урока было задание: создать круговой массив отверстий. Для этого нам пришлось импортировать модуль math и вспоминать тригонометрию для перевода полярных координат в декартовы.
# Фрагмент из решения к прошлому уроку
for i in range(hole_count):
angle_rad = math.radians((360 / hole_count) * i)
x = pattern_radius * math.cos(angle_rad)
y = pattern_radius * math.sin(angle_rad)
with Locations((x, y)):
Circle(...)
Как вы уже догадались, CircularPattern полностью избавляет нас от этой рутины.
Давайте воссоздадим тот же пример с его помощью.
# lesson12_patterns.py (продолжение)
from build123d import *
# Параметры
plate_radius = 40
plate_height = 5
hole_count = 8
hole_diameter = 5
pattern_radius = 30 # Радиус, по которому располагаются отверстия
with BuildPart() as part_circular:
# Создаем круглую пластину
Cylinder(radius=plate_radius, height=plate_height)
with BuildSketch(part_circular.faces().sort_by(Axis.Z)[-1]) as sketch:
# 1. Создаем ОДНУ исходную окружность, смещенную от центра
# на расстояние pattern_radius.
with Locations((pattern_radius, 0)):
Circle(hole_diameter / 2)
# 2. Применяем CircularPattern ко всему, что было создано в эскизе до этого.
# Обратите внимание: здесь CircularPattern вызывается ПОСЛЕ создания объекта.
# Он находит последний созданный объект и копирует его.
CircularPattern(count=hole_count)
extrude(amount=-plate_height, mode=Mode.SUBTRACT)
# Закомментируйте предыдущий show_object
show_object(part_circular.part, name="Circular Pattern of Holes")
Снова сравним подходы. CircularPattern сделал за нас всю тригонометрию. Нам нужно было лишь определить что мы хотим размножить (окружность) и где находится ее первая инстанция (на расстоянии pattern_radius от центра).
Ключевые параметры CircularPattern:
count: количество элементов.angle: общая дуга, по которой распределяются элементы (по умолчанию 360 градусов).center: центр вращения (по умолчанию(0, 0)).
Как видите, использование встроенных паттернов не только упрощает код, но и делает его семантически более ясным.

Проверьте себя!
Задание:
Создайте макет крепежного фланца. Это должна быть квадратная пластина 80x80 мм, толщиной 5 мм. В центре пластины — сквозное отверстие диаметром 40 мм. Вокруг центрального отверстия, по углам воображаемого квадрата 60x60 мм, расположены 4 крепежных отверстия диаметром 5 мм.
Подсказка:
Самый простой способ создать 4 отверстия по углам — это создать одно отверстие в нужной позиции (например, (30, 30)), а затем использовать PolarLocations или GridLocations. Однако, попробуйте решить задачу, используя только LinearPattern, чтобы закрепить материал. Например, создайте два отверстия в линию, а затем примените к ним еще один LinearPattern в перпендикулярном направлении.
Показать решение
# lesson12_exercise_solution.py
from build123d import *
# Параметры
plate_size = 80
plate_thk = 5
center_hole_d = 40
mount_hole_d = 5
mount_hole_spacing = 60
with BuildPart() as flange:
# Основа
Box(plate_size, plate_size, plate_thk)
with BuildSketch() as sketch: # Эскиз на плоскости XY
# Центральное отверстие
Circle(center_hole_d / 2)
# Создаем группу из двух отверстий по оси X
with Locations(
(-mount_hole_spacing / 2, 0), (mount_hole_spacing / 2, 0)
):
# Применяем LinearPattern по оси Y к этой группе
LinearPattern(y_spacing=mount_hole_spacing, count=2)
Circle(mount_hole_d / 2, mode=Mode.SUBTRACT) # Режим вычитания сразу в эскизе
# Вычитаем центральное отверстие из пластины
extrude(amount=-plate_thk, mode=Mode.SUBTRACT)
show_object(flange.part, name="Flange with 4 holes")
Примечание: в этом решении используется mode=Mode.SUBTRACT прямо в эскизе. Это альтернативный способ. Сначала создается Rectangle(plate_size, plate_size), а потом из него вычитаются окружности. Затем весь эскиз выдавливается. Это более "2D-центричный" подход. Вариант из начала урока (создать 3D-тело, а потом вырезать эскиз) тоже абсолютно правильный.
3. Паттерны для 3D-объектов
Важно понимать, что паттерны можно применять не только к 2D-фигурам в эскизах, но и к полноценным 3D-объектам (features). Например, вместо того чтобы создавать паттерн из окружностей и затем выдавливать их, можно создать один выступ (boss), а затем размножить его.
Это особенно полезно при создании монтажных стоек (standoffs) внутри корпуса.
# lesson12_patterns.py (третий пример)
from build123d import *
with BuildPart() as part_3d_pattern:
# 1. Базовая пластина
Box(100, 40, 3)
# 2. Создаем одну монтажную стойку (standoff)
with Locations((-(100/2-10), 0, 3)): # Позиционируем на поверхности
Cylinder(radius=5, height=10)
# 3. Выбираем последнюю созданную 3D-операцию (создание цилиндра)
# и применяем к ней LinearPattern
LinearPattern(
x_spacing=20,
count=4,
# Важно указать плоскость и направление для 3D-паттерна
plane=Plane.XY,
direction=(1, 0, 0)
)
# Закомментируйте предыдущий show_object
show_object(part_3d_pattern.part, name="3D Linear Pattern of Standoffs")
В этом примере LinearPattern вызывается вне BuildSketch и применяется к последнему созданному 3D-элементу. Этот метод дает тот же геометрический результат, но может быть более логичным в некоторых сценариях проектирования.
Ключевые выводы
LinearPatternиCircularPattern— это высокоуровневые, декларативные инструменты для создания линейных и круговых массивов.- Они делают код более чистым, коротким и читаемым по сравнению с ручной реализацией через циклы
forи вычисление координат. - Паттерны могут применяться как к 2D-фигурам внутри
BuildSketch, так и к 3D-объектам в контекстеBuildPart. - Использование паттернов — идиоматичный и предпочтительный способ создания регулярных массивов в
build123d.
Что дальше?
Мы освоили базовые строительные блоки: создание форм, их изменение с помощью булевых операций, точное позиционирование и эффективное размножение с помощью паттернов. Теперь мы готовы приступить к проектированию нашего корпуса. В следующем уроке мы начнем с самого начала: спроектируем монолитный блок по внешним габаритам будущего корпуса. Это будет первый шаг в процессе создания полой оболочки, которую мы затем разделим на крышку и основание.