Recommended resources
The freely available resources this lesson will direct you to.
Здравствуйте!
В прошлых уроках мы создали корпус с различными функциональными вырезами: для светодиодов, кнопок, кабелей. Однако все рёбра и углы нашей модели остались острыми. Это не только делает её вид "незавершённым", но и может быть непрактично: острые края хрупки, о них можно поцарапаться, а некоторые элементы (вроде винтов или кнопок) сложнее вставлять в отверстия с острыми кромками.
Цель этого урока — научиться применять скругления (fillets) и фаски (chamfers). Мы рассмотрим, как эти операции улучшают эстетику и функциональность модели, и, что самое важное, как точно выбирать рёбра для их применения в build123d.
1. Что такое скругления и фаски и зачем они нужны?
В CAD-моделировании скругление и фаска — это две базовые операции для обработки рёбер объекта.
- Скругление (Fillet) заменяет острое ребро дугой окружности, создавая плавный переход.
- Фаска (Chamfer) срезает ребро под углом, создавая плоский скос.

В контексте 3D-печати корпусов для электроники они выполняют несколько ключевых функций:
- Прочность: Внутренние скругления (например, у основания стенок) распределяют механическое напряжение и значительно снижают риск появления трещин.
- Эргономика и безопасность: Внешние скругления делают корпус приятнее на ощупь и убирают острые грани.
- Простота сборки: Небольшая фаска на входе в отверстие направляет винт, кнопку или вал, облегчая их установку.
- Эстетика: Модели со скруглёнными рёбрами выглядят более профессионально и "законченно".
- Качество печати: Правильно применённые фаски на нижних рёбрах модели помогают бороться с эффектом "слоновьей ноги" (небольшое утолщение первых слоёв) и улучшают внешний вид.
2. Базовое применение: fillet() и chamfer()
В build123d скругления и фаски применяются как методы к объекту Part. В простейшем случае, если не указывать, какие рёбра обрабатывать, операция применится ко всем рёбрам объекта.
Давайте создадим простой куб и скруглим все его рёбра.
from build123d import *
with BuildPart() as p:
Box(10, 10, 10)
# Применяем скругление радиусом 1 мм ко всем рёбрам
fillet(radius=1)
if "show_object" in locals():
show_object(p.part)
Аналогично работает chamfer(length=1). Такой подход полезен редко, так как обычно требуется обработать только определённые рёбра.
3. Выборочное применение: ключ к точному моделированию
Самая важная часть работы с fillet и chamfer — это точный выбор рёбер. Как вы уже знаете из предыдущих уроков, build123d использует цепочки методов для фильтрации и выбора элементов топологии.
Методы fillet и chamfer принимают первым аргументом список рёбер для обработки.
fillet(edges_to_fillet, radius=...)
Чтобы получить этот список, мы используем коллекцию part.edges() и применяем к ней фильтры. Давайте модифицируем наш корпус из предыдущих уроков.
Задача: Скруглить внешние вертикальные рёбра и верхний внешний периметр корпуса.
# enclosure_v19.py
from build123d import *
# ================== ПАРАМЕТРЫ ==================
enclosure_length = 100
enclosure_width = 80
enclosure_height = 40
wall_thickness = 2
fillet_radius = 3
# ================== МОДЕЛИРОВАНИЕ ==================
with BuildPart() as enclosure:
Box(enclosure_length, enclosure_width, enclosure_height)
offset(amount=-wall_thickness, openings=enclosure.faces().sort_by(Axis.Z)[-1])
# 1. Выбираем вертикальные рёбра
vertical_edges = enclosure.edges().filter_by(Axis.Z)
# 2. Выбираем рёбра верхнего внешнего контура
top_face = enclosure.faces().sort_by(Axis.Z)[-1]
# Получаем внешний контур (wire) и его рёбра
top_outer_edges = top_face.outer_wire().edges()
# 3. Применяем скругление к объединенному списку рёбер
fillet(vertical_edges + top_outer_edges, radius=fillet_radius)
if "show_object" in locals():
show_object(enclosure.part)
Разбор кода:
enclosure.edges().filter_by(Axis.Z): Этот фильтр выбирает все рёбра, которые параллельны оси Z. В нашем случае это четыре вертикальных угла коробки.top_face.outer_wire().edges(): Мы сначала находим верхнюю грань, затем получаем её внешний контур (outer_wire) и из него извлекаем все рёбра.vertical_edges + top_outer_edges: Мы просто объединяем два списка рёбер, чтобы применить операцию за один вызов.
4. Продвинутый отбор рёбер: group_by
Что делать, если нужно выбрать рёбра не по ориентации, а по другим свойствам, например, радиусу (для отверстий) или длине? Здесь на помощь приходит мощный метод group_by. Он группирует элементы по значению некоторого свойства.
Задача: Добавить фаску на край отверстия для кнопки.
Представим, что мы создали корпус с отверстием под кнопку, как в прошлом уроке. Нам нужно выбрать только то ребро, которое является внешним контуром этого отверстия на лицевой панели, и применить к нему фаску.
Если мы знаем диаметр отверстия (button_head_dia), мы можем найти все круглые рёбра и сгруппировать их по радиусу.
# enclosure_v20.py
from build123d import *
# ================== ПАРАМЕТРЫ ==================
enclosure_length = 100
enclosure_width = 80
enclosure_height = 40
wall_thickness = 2
button_pos = (0, 15)
button_body_dia = 7
button_head_dia = 10
button_head_depth = 1.5
chamfer_size = 0.5
# ================== МОДЕЛИРОВАНИЕ ==================
with BuildPart() as enclosure:
Box(enclosure_length, enclosure_width, enclosure_height)
offset(amount=-wall_thickness, openings=enclosure.faces().sort_by(Axis.Z)[-1])
side_face = enclosure.faces().sort_by(Axis.Y)[-1]
# Создаем ступенчатое отверстие
with Locations(side_face.center()):
with BuildSketch() as button_hole:
with Locations(button_pos):
Circle(button_body_dia / 2)
extrude(amount=-wall_thickness, mode=Mode.SUBTRACT)
with BuildSketch() as button_counterbore:
with Locations(button_pos):
Circle(button_head_dia / 2)
extrude(amount=-button_head_depth, mode=Mode.SUBTRACT)
# Выбираем рёбра для фаски
# 1. Находим все круглые рёбра
circular_edges = enclosure.edges().filter_by(GeomType.CIRCLE)
# 2. Группируем их по радиусу и выбираем группу с радиусом шляпки кнопки
# group_by возвращает словарь {радиус: [рёбра]}
edges_by_radius = circular_edges.group_by(Edge.radius)
hole_edges = edges_by_radius[button_head_dia / 2]
# 3. Уточняем выбор: нам нужно ребро на внешней грани
target_edge = [e for e in hole_edges if e.face() == side_face]
# 4. Применяем фаску
chamfer(target_edge, length=chamfer_size)
if "show_object" in locals():
show_object(enclosure.part)
Разбор кода:
filter_by(GeomType.CIRCLE)отбирает только круглые рёбра.group_by(Edge.radius)создаёт словарь, где ключи — это радиусы, а значения — списки рёбер с этим радиусом.edges_by_radius[button_head_dia / 2]позволяет нам получить список рёбер нужного нам диаметра. Поскольку у ступенчатого отверстия есть два круглых ребра с таким диаметром (на поверхности и на дне углубления), нам нужно выбрать то, что лежит наside_face.- Списковое включение
[e for e in hole_edges if e.face() == side_face]элегантно решает эту задачу.
Такой подход, основанный на свойствах геометрии, чрезвычайно надёжен. Он будет работать, даже если вы переместите отверстие или измените геометрию корпуса, в отличие от выбора по координатам.
Group Examples — build123d documentation
В официальной документации build123d есть отличный пример, который демонстрирует использование group_by с Edge.Length и Edge.radius для выборочного применения скруглений и фасок. Рекомендую ознакомиться с ним, чтобы закрепить понимание этого мощного механизма.
На странице найдите раздел 'Properties with Keys'. Обратите внимание, как сначала выбираются рёбра для скругления по их известной длине (Edge.Length), а затем — круглые рёбра для фасок по их радиусу (Edge.radius).
5. Функциональные скругления и фаски для FDM-печати
Применение этих операций — не только вопрос эстетики.

- Фаска на нижнем ребре: Вместо скругления на рёбрах, соприкасающихся со столом принтера, часто лучше использовать фаску под углом 45°. Она печатается без поддержек и помогает скрыть дефекты первого слоя.
- Внутренние скругления: Добавление небольшого скругления в месте стыка стенки и дна корпуса (внутренний угол) делает деталь значительно прочнее. Это одно из главных правил проектирования деталей под литьё пластиков, которое отлично работает и для FDM-печати.
Проверьте себя!
Вы хотите добавить скругления на все восемь рёбер (4 верхних, 4 нижних) плоской детали, похожей на крышку. При этом скругления на верхних рёбрах должны иметь радиус 2 мм, а на нижних — 1 мм. Как бы вы это сделали в build123d за два вызова fillet?
Показать ответ
- Создать деталь (например,
Box). - Выбрать верхнюю грань:
top_face = my_part.faces().sort_by(Axis.Z)[-1]. - Выбрать рёбра верхней грани:
top_edges = top_face.edges(). - Применить первое скругление:
fillet(top_edges, radius=2). - Аналогично выбрать нижнюю грань и её рёбра:
bottom_face = my_part.faces().sort_by(Axis.Z)[0],bottom_edges = bottom_face.edges(). - Применить второе скругление:
fillet(bottom_edges, radius=1).
Важно, что build123d (и ядро OCCT) корректно обрабатывает последовательные операции, перестраивая геометрию после каждого шага.
Ключевые выводы
- Скругления (
fillet) и фаски (chamfer) — это финальные штрихи, которые придают модели прочность, функциональность и законченный вид. - Ключевая задача при их применении — точный выбор рёбер. Используйте для этого фильтры (
filter_by,sort_by) и группировку (group_by). - Отбор по геометрическим свойствам (
GeomType,Edge.radius,Edge.Length) является наиболее надёжным и параметрическим подходом. - При проектировании для FDM-печати учитывайте, как скругления и фаски будут влиять на процесс печати, особенно на первых слоях и нависающих элементах.
Что дальше?
Мы завершили седьмой модуль, научившись создавать и дорабатывать все основные вырезы и отверстия. Теперь вы владеете полным набором инструментов для моделирования монолитных объектов.
В следующем модуле мы перейдём к самой сути нашей задачи: проектированию двухсоставного корпуса. Мы начнём с создания внешнего "монолита", затем сделаем его полым и, наконец, разделим на основание и крышку — основу для нашего финального проекта.