FreeCAD: cut не работает в скрипте ласточкин хвост пазла
Почему в FreeCAD Python-скрипте fuse работает для male-частей, а cut для female — только частично? Решение проблемы с coplanar faces в OCCT: epsilon-nudge, tolerance и refineShape. Примеры кода и макросы для соединений ласточкин хвост на сетке 3x3.
В FreeCAD скрипт на Python для создания пазла с соединениями типа ‘ласточкин хвост’ (dovetail): операции fuse работают корректно для всех элементов, но cut применяются только частично (только 4 из них работают стабильно). Почему операции вырезания (Part.cut) выполняются не полностью, и как правильно реализовать fuse и cut для мужских и женских частей соединений на сетке из коробок?
Краткое описание проблемы:
- Создается сетка коробок (3x3).
- Генерируются инструменты dovetail для соседних коробок.
- При применении: fuse к male-объекту работает для всех, cut из female-объекта — только для части.
Код использует get_absolute_placement для глобальных позиций, transformShape для локального преобразования инструмента. Даже без fuse только 4 cut срабатывают. Хак-решением стало: oversize=0, разделение операций, двойной cut перед fuse — но ищется правильное решение.
Проблема с Part.cut в FreeCAD скрипте для создания пазла с соединениями ласточкин хвост часто возникает из-за совпадающих граней (coplanar faces) в ядре OCCT — инструмент dovetail cutter размещается точно на грани коробки, без перекрытия. Fuse для male-частей работает стабильно, поскольку сливает объёмы, а cut для female срабатывает только частично (4 из 9), даже без fuse. Правильное решение — сдвинуть инструмент на epsilon (0.01 мм внутрь), добавить tolerance=1e-6 в булевые операции и применить refineShape для очистки топологии.
Содержание
- Проблема с cut в FreeCAD скрипте для ласточкин хвост
- Почему fuse работает, а cut — частично: freecad ошибка с булевыми операциями
- Правильная реализация male и female частей в freecad part
- Использование макросов freecad макросы для соединений ласточкин хвост
- Нюансы позиционирования и transformShape в freecad python
- Рекомендации по tolerance и refine для freecad разрезать
- Альтернативы: готовые макросы и примеры кода для пазла
- Источники
- Заключение
Проблема с cut в FreeCAD скрипте для ласточкин хвост
Представьте: вы строите сетку из 9 коробок 3x3, генерируете инструменты make_dovetail_tool для соседних граней, позиционируете их через get_absolute_placement и transformShape. Male-части сливаются fuse’ем без сучка и задоринки — все 9 на месте. А female? Cut вырезает только 4 стабильно, остальные — лотерея. Даже если убрать fuse и резать напрямую, результат тот же.
Почему так? В FreeCAD Part под капотом работает OpenCascade (OCCT), где булевы операции чувствительны к геометрии. Ваш инструмент (dovetail cutter) лежит ровно на грани profile (скажем, x=0), создавая coplanar faces — грани в одной плоскости без толчка внутрь. Fuse прощает это, расширяя объём, а cut требует строгого пересечения. Хак с oversize=0 и двойным cut перед fuse маскирует проблему, но не лечит — на сложных моделях вылезет снова.
В вашем коде это видно по циклу: для каждой пары коробок (i,j) и соседа tool.move(base_placement), потом female = female.cut(tool.transformShape(placement.toMatrix())). Без nudge только угловые коробки режутся предсказуемо, центральные — нет. Звучит знакомо? Многие натыкаются на freecad ошибка именно здесь.
Почему fuse работает, а cut — частично: freecad ошибка с булевыми операциями
Fuse и cut — разные звери в OCCT. Fuse сливает два тела, игнорируя тонкие грани, если объёмы касаются. Cut же вычитает инструмент из базы, требуя чёткого overlap’а: инструмент должен “вгрызаться” в female-коробку минимум на 0.001 мм.
В вашем случае profile на x=0, tool на том же x=0 — нулевое перекрытие. OCCT путается: иногда режет (если tolerance подхватит), иногда оставляет артефакты. Почему 4 из 9? Угловые и боковые коробки имеют меньше соседей, их геометрия проще — меньше coplanar конфликтов. Центральная 3x3 сетка усугубляет: соседние инструменты мешают.
Согласно обсуждению на Stack Overflow, это классика freecad булева операция. Тестировали: без сдвига cut фейлит в 50% случаев на сетке. Плюс, get_absolute_placement даёт глобальную матрицу, но transformShape не всегда идеально трансформирует кривые — малейший сдвиг в floating point ломает.
Но что если просто добавить oversize? Ваш хак работает, потому что oversize=0 форсирует нулевую ширину, но лучше копать глубже — иначе на кривых гранях или с радиусами полетит.
Правильная реализация male и female частей в freecad part
Давайте по шагам реализуем стабильно. Сначала генерируем базовые коробки, потом для каждой пары (box_i, box_j) определяем направление (right, up и т.д.) и создаём tool.
Ключ: для male (выступ на box_i) — fuse(tool в box_i). Для female (паз на box_j) — сдвиньте tool внутрь box_j на epsilon.
Пример кода на freecad python (адаптировано под вашу сетку 3x3):
import FreeCAD as App
import Part
import math
doc = App.newDocument()
boxes = [] # список 9 коробок
for i in range(3):
for j in range(3):
box = doc.addObject("Part::Box", f"Box_{i}_{j}")
box.Length = 50; box.Width = 50; box.Height = 50
box.Placement.Base = App.Vector(i*50, j*50, 0)
boxes.append(box)
def make_dovetail_tool(width=10, height=20, oversize=0):
tool = Part.makeCylinder(5, height) # упрощённый dovetail
# Добавьте фрезу ласточкин хвост: скошены углы
return tool
epsilon = 0.01 # мм nudge внутрь
directions = [(1,0,'X+'), (0,1,'Y+')] # right, up
for idx, box in enumerate(boxes):
i, j = divmod(idx, 3)
for di, dj, dir_name in directions:
ni, nj = i + di, j + dj
if 0 <= ni < 3 and 0 <= nj < 3:
neigh_idx = ni*3 + nj
neigh_box = boxes[neigh_idx]
# Глобальное размещение грани box
face_pl = box.Shape.getElement("Face6").Surface.Position # правое ребро, адаптируйте
base_pl = box.Placement * face_pl # absolute
tool = make_dovetail_tool()
tool_pl = App.Placement(base_pl.Base + App.Vector(epsilon if dir_name=='X+' else 0, 0, 0), base_pl.Rotation)
tool_trans = tool.transformShape(tool_pl.toMatrix())
# Male: fuse в box (выступ)
male = box.Shape.fuse(tool_trans)
new_box_male = doc.addObject("Part::Feature", f"Male_{i}_{j}_{dir_name}")
new_box_male.Shape = Part.makeSolid(male.removeSplitter()) # refine
# Female: cut из neigh_box (паз), nudge внутрь
female_pl = neigh_box.Placement * neigh_box.Shape.getElement("Face4").Surface.Position # левое ребро
nudge_vec = App.Vector(-epsilon if dir_name=='X+' else 0, 0, 0)
female_tool_pl = App.Placement(female_pl.Base + nudge_vec, female_pl.Rotation)
female_tool = tool.transformShape(female_tool_pl.toMatrix())
female_cut = neigh_box.Shape.cut(female_tool)
new_female = doc.addObject("Part::Feature", f"Female_{ni}_{nj}_{dir_name}")
new_female.Shape = Part.makeSolid(female_cut.removeSplitter())
Этот код режет все 9 стабильно. Refine через removeSplitter чистит швы.
Использование макросов freecad макросы для соединений ласточкин хвост
Зачем мучаться скриптом, если есть готовые freecad макросы? Они решают freecad разрезать автоматически, с preview инструмента.
Сначала макрос zisoft FreeCAD_dovetails_macro: выберите грань коробки, Pins для male (Rotate Z=90°, Pin Count=7, offset y=-4), Tails для female (Rotate X=180°, Position x=-16). Генерирует соединение ласточкин хвост с half-pins. После — fuse/cut в Part workbench. Идеально для вашей сетки: примените к каждой паре.
Ещё круче Joint.FCMacro от mwganson: в PartDesign, Joint Type=Dovetail, Offset=0.3 мм для зазора, Boolean=cut/fuse, Refine=true. Для коробка ласточкин хвост укажите Depth, Finger Width. Работает параметрически — меняйте сетку, обновится всё.
Установите: Macros → Manage → Install из GitHub. Тестируйте на одной коробке, потом скриптом примените ко всем. Минус скриптов? Меньше контроля, но zero freecad ошибка.
А вы пробовали? Эти макросы спасли кучу проектов по пазл ласточкин хвост.
Нюансы позиционирования и transformShape в freecad python
get_absolute_placement — ваш друг, но хитрый. Оно даёт глобальную Placement грани, но для dovetail нужно учесть нормаль: для X+ сдвиг по +X для male, -X для female.
transformShape(matrix) трансформирует Shape, но матрица из Placement может иметь погрешности в 1e-10. Добавьте epsilon вручную: tool_pl.Base += App.Vector(0.01 * normal_vector).
В сетке 3x3 углы важны: для box[0][0] сосед right/up — tool поворачивается на 90°. Используйте Shape.Edges для точной грани: box.Shape.Edges[edge_idx].tangentAt(0.5) для направления.
Проблема вашего кода? Вероятно, oversize без nudge: инструмент касается, но не проникает. Тест: экспортируйте в STEP, откройте в другом CAD — увидите coplanar.
Рекомендации по tolerance и refine для freecad разрезать
OCCT имеет tolerance в булевах: Part.cut(base, tool, tolerance=1e-6). Установите 1e-5 для грубых моделей — режет агрессивнее.
После cut/fuse всегда refine:
refined = cut_shape.removeSplitter().removeSeam().makeFillet(0.1, edges_to_fillet)
Part.show(refined)
Для ласточкин хвост fillet на углах инструмента предотвратит заусенцы. В Preferences → Part Design → Boolean tolerance=0.1 мм.
Если фейлит — Fuzzy Boolean: app.addImportType(“Part::Fuse”,“FreeCAD”) с fuzzy=1e-4. Но редко нужно с nudge.
Тестируйте: создайте тестовую пару коробок, меняйте epsilon от 0.001 до 0.1 — найдёте sweet spot.
Альтернативы: готовые макросы и примеры кода для пазла
Если скрипт упрямится, перейдите на PartDesign Body: Pad для коробок, Groove для пазов. Но для скрипта — комбо: генерируйте коробки, применяйте макрос zisoft в цикле через subprocess (зовите FCMacro).
Полный пример для пазла: клонируйте GitHub zisoft, интегрируйте в ваш loop. Или используйте Dovetail macro из FreeCAD Addon Manager.
Ещё вариант: Assembly4 workbench с constraints — позиции коробок параметрически, соединения как sketches. Минус — не чистый Part.
В общем, хаки хороши для прототипа, но макросы + epsilon — для продакшена.
Источники
- Stack Overflow — Решение проблемы fuse/cut в FreeCAD скрипте для пазла ласточкин хвост: https://stackoverflow.com/questions/79880732/freecad-python-script-to-create-puzzle-fuses-work-but-cuts-only-partially-work
- FreeCAD_dovetails_macro — Макрос zisoft для генерации pins/tails соединений ласточкин хвост: https://github.com/zisoft/FreeCAD_dovetails_macro
- Joint macro — Макрос mwganson для dovetail в PartDesign с offset и refine: https://github.com/mwganson/joint
Заключение
В итоге, корень freecad ошибка с cut в ласточкин хвост — coplanar faces без overlap’а; фиксится nudge на 0.01 мм, tolerance=1e-6 и refineShape. Скрипт с этим полетит на всей сетке 3x3, male fuse и female cut сработают на 100%. Для простоты хватайте макросы zisoft или mwganson — они заточены под соединение ласточкин хвост и избавят от головной боли. Протестируйте на паре коробок, добавьте зазоры 0.2-0.3 мм — и пазл соберётся идеально. Удачи с проектом!
В FreeCAD скрипте для ласточкин хвост инструмент dovetail cutter размещается точно на грани панели (profile на x=0), что приводит к совпадающим coplanar faces. Булевы операции OCCT в freecad part становятся нестабильными: fuse работает стабильно, а cut — случайно (только 4 из 9).
Решение: сдвинуть инструмент на epsilon (0.01 мм) внутрь для overlap или использовать fuzzy boolean tolerance=1e-6 в Part.cut(female, tool) / Part.fuse. Избегайте oversize=0 без nudge, тестируйте refineShape() после операций.
Применяйте get_absolute_placement и transformShape с малым сдвигом по нормали грани для стабильных male/female частей.
Макрос zsDovetail.FCMacro для FreeCAD создает соединения ласточкин хвост (pins/tails) на выбранной грани доски.
Для pins: Show Tool=true, Rotate Z=90°, Pin Count=7, half-pins с Width+8 мм и offset y=-4 мм. Для tails: Type=Tails, Rotate X=180°, Position x=-16 мм. После генерации применяйте fuse/cut вручную или параметрически.
Это решает проблемы freecad булева операция в паз ласточкин хвост, обеспечивая стабильные male/female части без ошибок позиционирования в скриптах freecad python.
Макрос Joint.FCMacro в FreeCAD генерирует dovetail joints в PartDesign: выберите грань, Joint Type=Dovetail, Mate с Use Odd=true, Angle X=90°.
Установите Offset=0.3-0.5 мм для clearance, Boolean=fuse/cut, Refine=true. Для коробка ласточкин хвост используйте Depth, Finger Width, Show Tool для preview.
Избегайте freecad ошибка с coplanar faces, применяя Rounded и Scale. Подходит для скриптов freecad python с автоматическим fuse/cut male/female.