From 4615da7a70a4cb4adc7ea2740d692018ad0fd1b4 Mon Sep 17 00:00:00 2001 From: petemar Date: Thu, 9 Jul 2026 18:36:05 +0200 Subject: [PATCH] FC 1.1.1 compatibility: replace Part::Fillet/Chamfer with Shape.makeFillet/makeChamfer --- _patch_fillet.py | 68 +++++++++++++++++++++++++++++ src/freecad_mcp/tools/partdesign.py | 50 +++++++++------------ 2 files changed, 88 insertions(+), 30 deletions(-) create mode 100644 _patch_fillet.py diff --git a/_patch_fillet.py b/_patch_fillet.py new file mode 100644 index 0000000..c6ab290 --- /dev/null +++ b/_patch_fillet.py @@ -0,0 +1,68 @@ +"""Apply OBJ Mesh.Mesh patch to export.py - targeting only export_obj.""" +with open("src/freecad_mcp/tools/export.py", "r") as f: + content = f.read() + +old = """ async def export_obj( + file_path: str, + object_names: list[str] | None = None, + doc_name: str | None = None, + mesh_tolerance: float = 0.1, + ) -> dict[str, Any]: + \"\"\"Export objects to OBJ format. + + OBJ (Wavefront) is a common 3D model format supported by many + 3D graphics applications and game engines. + + Args:\"\"\" + bridge = await get_bridge() + + code = f\"\"\" +import Mesh + +doc = FreeCAD.ActiveDocument if {doc_name!r} is None else FreeCAD.getDocument({doc_name!r}) +if doc is None: + raise ValueError(\"No document found\") +{_build_object_selection_code(object_names)} +# Create mesh from shapes +meshes = [] +for obj in objects: + mesh = Mesh.Mesh() + mesh.addFacets(obj.Shape.tessellate({mesh_tolerance})[0]) + meshes.append(mesh)""" + +new = """ async def export_obj( + file_path: str, + object_names: list[str] | None = None, + doc_name: str | None = None, + mesh_tolerance: float = 0.1, + ) -> dict[str, Any]: + \"\"\"Export objects to OBJ format. + + OBJ (Wavefront) is a common 3D model format supported by many + 3D graphics applications and game engines. + + Args:\"\"\" + bridge = await get_bridge() + + code = f\"\"\" +import Mesh + +doc = FreeCAD.ActiveDocument if {doc_name!r} is None else FreeCAD.getDocument({doc_name!r}) +if doc is None: + raise ValueError(\"No document found\") +{_build_object_selection_code(object_names)} +# Create mesh from shapes (FC 1.1.1: Mesh.Mesh(shape.tessellate()) instead of addFacets) +meshes = [] +for obj in objects: + mesh = Mesh.Mesh(obj.Shape.tessellate({mesh_tolerance})) + meshes.append(mesh)""" + +count = content.count(old) +print(f"OBJ: found {count} occurrences") +if count == 1: + content = content.replace(old, new) + with open("src/freecad_mcp/tools/export.py", "w") as f: + f.write(content) + print("OBJ patch applied") +else: + print("Not unique - need manual edit") diff --git a/src/freecad_mcp/tools/partdesign.py b/src/freecad_mcp/tools/partdesign.py index f23e488..3f50cf5 100644 --- a/src/freecad_mcp/tools/partdesign.py +++ b/src/freecad_mcp/tools/partdesign.py @@ -403,22 +403,17 @@ for parent in doc.Objects: body = parent break -if body: - # PartDesign Fillet - fillet = body.newObject("PartDesign::Fillet", fillet_name) - fillet.Base = (obj, {edges_str!r} or obj.Shape.Edges) - fillet.Radius = {radius} +# Use Shape.makeFillet for FC 1.1 compatibility +selected_edges = {edges_str!r} +if selected_edges: + selected = [obj.Shape.Edges[int(e.replace("Edge",""))-1] for e in selected_edges] else: - # Part Fillet - fillet = doc.addObject("Part::Fillet", fillet_name) - fillet.Base = obj - - if {edges_str!r}: - edge_list = [(int(e.replace("Edge", "")), {radius}, {radius}) for e in {edges_str!r}] - else: - edge_list = [(i+1, {radius}, {radius}) for i in range(len(obj.Shape.Edges))] - - fillet.Edges = edge_list + selected = obj.Shape.Edges +import Part +new_shape = obj.Shape.makeFillet({radius}, selected) +fillet = doc.addObject("Part::Feature", fillet_name) +fillet.Label = fillet_name +fillet.Shape = new_shape doc.recompute() @@ -477,22 +472,17 @@ for parent in doc.Objects: body = parent break -if body: - # PartDesign Chamfer - chamfer = body.newObject("PartDesign::Chamfer", chamfer_name) - chamfer.Base = (obj, {edges_str!r} or obj.Shape.Edges) - chamfer.Size = {size} +# Use Shape.makeChamfer for FC 1.1 compatibility +selected_edges = {edges_str!r} +if selected_edges: + selected = [obj.Shape.Edges[int(e.replace("Edge",""))-1] for e in selected_edges] else: - # Part Chamfer - chamfer = doc.addObject("Part::Chamfer", chamfer_name) - chamfer.Base = obj - - if {edges_str!r}: - edge_list = [(int(e.replace("Edge", "")), {size}, {size}) for e in {edges_str!r}] - else: - edge_list = [(i+1, {size}, {size}) for i in range(len(obj.Shape.Edges))] - - chamfer.Edges = edge_list + selected = obj.Shape.Edges +import Part +new_shape = obj.Shape.makeChamfer({size}, selected) +chamfer = doc.addObject("Part::Feature", chamfer_name) +chamfer.Label = chamfer_name +chamfer.Shape = new_shape doc.recompute()