Recommended resources
The freely available resources this lesson will direct you to.
Здравствуйте!
В прошлом уроке мы разобрались с одной из самых важных концепций в 3D-печати — допусками. Вы научились определять и применять зазоры (clearances), превратив "магические числа" в параметрические переменные вроде TIGHT_FIT_CLEARANCE и LOOSE_FIT_CLEARANCE. Это дало нам уверенность в том, что спроектированные части корпуса соберутся вместе.
Теперь, вооружившись этим знанием, мы можем перейти к созданию функциональных элементов. Цель этого урока — научиться проектировать точные вырезы для портов, таких как USB и Ethernet, на стенках корпуса. Это критически важный шаг, чтобы ваша электроника могла взаимодействовать с внешним миром.

Мы будем использовать уже знакомые вам техники, но применять их для новой задачи: будем выбирать нужную грань корпуса, создавать на ней 2D-эскиз профиля порта и "вырезать" его из стенки.
1. Основной принцип: Эскиз на грани
Ключевой рабочий процесс для создания любого выреза на существующей поверхности состоит из трёх шагов:
- Выбрать целевую грань (Face): Нам нужно программно идентифицировать ту стенку корпуса, где будет располагаться вырез.
- Создать на ней эскиз (Sketch): На этой грани мы рисуем двумерный профиль будущего отверстия (например, прямоугольник для USB).
- Выдавить с вычитанием (Subtractive Extrude): Мы "выдавливаем" этот эскиз сквозь стенку, удаляя материал.
Этот подход является фундаментальным в build123d.
Introductory Examples - Creating Workplanes on Faces
В официальной документации build123d есть отличный пример, иллюстрирующий именно этот процесс. Давайте его изучим.
Найдите раздел '18. Creating Workplanes on Faces'. Обратите внимание на строки кода, где с помощью ex18.faces().sort_by(Axis.Z)[-1] выбирается верхняя грань, на ней создается эскиз with BuildSketch(...), а затем extrude(amount=-thickness, mode=Mode.SUBTRACT) вырезает отверстие.
Как видите, build123d позволяет использовать любую плоскую грань существующего объекта как новую рабочую плоскость. Это невероятно мощный инструмент.
2. Практика: Вырез под порт USB-A
Давайте применим этот принцип на практике. Создадим простой полый короб и вырежем в одной из его стенок отверстие для стандартного порта USB-A.
Для начала, нам нужен базовый корпус. Можете использовать код из предыдущих уроков или этот простой пример:
# enclosure_v13.py
from build123d import *
# ================== ПАРАМЕТРЫ ==================
# Габариты корпуса
enclosure_length = 100
enclosure_width = 80
enclosure_height = 40
wall_thickness = 2
# Допуски (из прошлого урока)
LOOSE_FIT_CLEARANCE = 0.4 # Для свободной посадки
# Размеры порта USB-A (металлический кожух)
usb_a_width = 13.0
usb_a_height = 5.5
# ================== МОДЕЛИРОВАНИЕ ==================
# Создаем монолитный блок
with BuildPart() as enclosure:
Box(enclosure_length, enclosure_width, enclosure_height)
# Делаем его полым
offset(amount=-wall_thickness, openings=enclosure.faces().sort_by(Axis.Z)[-1])
# --- Создание выреза для USB-A ---
# 1. Выбираем целевую грань.
# sort_by(Axis.X)[0] выбирает грань с минимальной координатой X.
target_face = enclosure.faces().sort_by(Axis.X)[0]
# 2. Создаем эскиз на этой грани
with BuildSketch(target_face):
# 3. Рисуем профиль порта с учетом зазора
Rectangle(
usb_a_width + LOOSE_FIT_CLEARANCE,
usb_a_height + LOOSE_FIT_CLEARANCE
)
# 4. Выдавливаем эскиз для создания выреза
extrude(amount=-wall_thickness, mode=Mode.SUBTRACT)
if "show_object" in locals():
show_object(enclosure.part)
Разбор кода:
enclosure.faces().sort_by(Axis.X)[0]: Это ключевая строка для выбора грани.faces()получает список всех граней объекта.sort_by(Axis.X)сортирует их по положению центра вдоль оси X.[0]выбирает первую грань в отсортированном списке, то есть ту, что находится в "минимальном" X (условно, "левая" стенка). Соответственно,[-1]выбрало бы "правую".
Rectangle(width + LOOSE_FIT_CLEARANCE, ...): Мы сразу применяем знания из прошлого урока. Чтобы коннектор USB свободно входил, мы делаем отверстие немного больше его физических размеров.extrude(amount=-wall_thickness, mode=Mode.SUBTRACT): Отрицательное значениеamountуказывает направление "внутрь" детали, аMode.SUBTRACTпредписывает вычесть этот объем из основного тела.
Теперь вы можете запустить этот скрипт и увидеть в OCP CAD Viewer полый короб с аккуратным прямоугольным вырезом.
3. Сложные профили и точное позиционирование
Порты редко располагаются точно по центру стенки. Кроме того, их форма может быть сложнее простого прямоугольника (например, порт Ethernet с выступом под защёлку).
Давайте усовершенствуем наш подход, чтобы разместить вырез в произвольном месте и придать ему более сложную форму.
3.1. Позиционирование с помощью Location
Вместо того чтобы рисовать эскиз по центру грани, мы можем точно его спозиционировать. Допустим, по нашей задумке, центр USB-порта должен находиться на высоте 15 мм от основания корпуса.
# ... (внутри 'with BuildPart() as enclosure')
# Выбираем грань
target_face = enclosure.faces().sort_by(Axis.X)[0]
# Создаем эскиз на этой грани
with BuildSketch(target_face):
# Используем Location для точного позиционирования
with Locations((0, 15 - enclosure_height / 2, 0)):
Rectangle(
usb_a_width + LOOSE_FIT_CLEARANCE,
usb_a_height + LOOSE_FIT_CLEARANCE
)
# ... extrude ...
Объяснение:Locations создает контекст, в котором все создаваемые объекты смещаются. Координаты (x, y, z) задаются в локальной системе координат грани. Поскольку начало координат грани находится в её центре, нам нужно вычислить смещение относительно него. Если enclosure_height равен 40, то центр грани по Z находится на z=20. Чтобы поднять порт на z=15, нам нужно сместиться на 15 - 20 = -5. Однако BuildSketch работает в 2D, и для вертикальной грани оси могут быть (x, y). В нашем случае для грани на плоскости YZ локальная ось y будет соответствовать глобальной Z. Поэтому мы смещаем по второй координате: (0, 15 - enclosure_height / 2).
Более надежный подход, который вы оцените, имея опыт в программировании — связать позицию выреза с позицией компонента на вашей печатной плате.
Предположим, ваша плата стоит на дне корпуса, а центр USB-порта на плате имеет координаты (x_pcb, y_pcb) относительно угла платы. Тогда вырез на стенке корпуса будет на высоте z_pcb_mount_height + z_port_on_pcb. Этот параметрический подход — залог легко изменяемых и надёжных моделей.
3.2. Создание сложных профилей
А что если нам нужен вырез под порт Ethernet (RJ45)? Его профиль — это, по сути, два прямоугольника.
Лучшая практика — инкапсулировать создание сложного эскиза в отдельную функцию или контекстный менеджер. Это делает код чище и позволяет повторно использовать профиль порта в других проектах.
# Поместим это в начало файла, после импортов
def rj45_port_sketch(clearance: float = 0.0):
"""Создает эскиз для выреза под порт RJ45."""
# Размеры из стандарта (приблизительные)
port_width = 16.0
port_height = 13.5
latch_width = 8.0
latch_height = 2.0
# Создаем основной прямоугольник
with BuildSketch() as rj45:
# Основной корпус
Rectangle(port_width + clearance, port_height + clearance, align=(Align.CENTER, Align.MIN))
# Вырез под защелку снизу
with Locations((0, (port_height + clearance)/2, 0)):
Rectangle(latch_width + clearance, latch_height + clearance, mode=Mode.SUBTRACT)
return rj45
Теперь мы можем использовать эту функцию для создания выреза:
# ... (внутри 'with BuildPart() as enclosure')
# Выбираем другую грань для примера
rj45_face = enclosure.faces().sort_by(Axis.Y)[-1] # "Дальняя" стенка
with BuildSketch(rj45_face):
with Locations((0, 15 - enclosure_height / 2, 0)):
add(rj45_port_sketch(clearance=LOOSE_FIT_CLEARANCE))
extrude(amount=-wall_thickness, mode=Mode.SUBTRACT)
Такой подход превращает проектирование в работу с высокоуровневыми, самодокументируемыми блоками.
Проверьте себя!
Вам нужно создать вырез для круглого разъёма питания (barrel jack) диаметром 7 мм. Вы хотите, чтобы он входил плотно, поэтому решаете использовать TIGHT_FIT_CLEARANCE = 0.2 мм. Вырез должен быть на "правой" стенке корпуса (enclosure_length=100, enclosure_width=80, enclosure_height=40). Какой код вы напишете внутри контекста with BuildPart() as enclosure: для создания этого выреза?
Показать ответ
# Определяем параметры
barrel_jack_diameter = 7.0
TIGHT_FIT_CLEARANCE = 0.2
# 1. Выбираем "правую" грань (с максимальной координатой X)
target_face = enclosure.faces().sort_by(Axis.X)[-1]
# 2. Создаем эскиз на этой грани
with BuildSketch(target_face):
# 3. Рисуем окружность с учётом плотного зазора
Circle(radius=(barrel_jack_diameter + TIGHT_FIT_CLEARANCE) / 2)
# 4. Вырезаем отверстие
extrude(amount=-wall_thickness, mode=Mode.SUBTRACT)
Ключевые моменты: выбор грани с помощью sort_by(Axis.X)[-1], использование Circle для эскиза, и применение TIGHT_FIT_CLEARANCE к диаметру.
Ключевые выводы
- Основной метод создания вырезов — это выбор грани, создание на ней 2D-эскиза и его "вычитающее" выдавливание (
extrudeсMode.SUBTRACT). - Для выбора нужной грани удобно использовать фильтрацию и сортировку, например,
part.faces().sort_by(Axis.X)[0]. - Положение выреза на грани можно точно задать с помощью контекста
Locations. - При проектировании вырезов необходимо всегда учитывать допуски (
clearances), чтобы обеспечить правильную посадку коннекторов. - Сложные профили портов рекомендуется инкапсулировать в отдельные функции для чистоты и переиспользования кода.
Что дальше?
Сегодня мы научились делать одиночные, но точные вырезы. В следующем уроке мы разовьём эту идею и научимся создавать целые массивы вырезов. Это позволит нам проектировать такие элементы, как вентиляционные решётки, используя уже знакомые нам циклы и паттерны из build123d.