Я пытаюсь создать головоломку в FreeCad. Если вы вставите первый блок кода в интерпретатор Python FreeCad v1.1, он создаст сетку блоков. Это демо-пример среды. Цель состоит в том, чтобы соединить каждый квадрат сетки.
Затем, когда я вставляю второй блок кода, он создает формы «ласточкин хвост», которые будут вырезаны из женских блоков и слиты с мужскими блоками.
Это все правильно и выглядит идеально.
Но проблема в третьем блоке. Все «ласточкины хвосты» срастаются правильно, но режутся неправильно. Лишь некоторые из них режут правильно. Один или два будут обрезаны правильно, но остальные - неудачно.
Я не уверен, это мой код или проблема с FreeCAD... Есть идеи, это известная ошибка или я делаю что-то не так?
Спасибо!
Первый код - создайте демонстрационную среду
import FreeCAD as App
import Part
# Create a new document
doc = App.activeDocument()
if not doc:
doc = App.newDocument("GridDocument")
# Dimensions of each box
size = 10.0
# Grid settings: 3 columns, 2 rows (total 6 boxes)
columns = 3
rows = 3
for i in range(columns):
for j in range(rows):
# Create the box shape
box_shape = Part.makeBox(size, size, size)
# Create a document object to hold the shape
box_obj = doc.addObject("Part::Feature", f"Box_{i}_{j}")
box_obj.Shape = box_shape
# Calculate position (all touching)
x_pos = i * size
y_pos = j * size
# Apply the position
box_obj.Placement = App.Placement(App.Vector(x_pos, y_pos, 0), App.Rotation(0, 0, 0))
# Refresh the 3D view
doc.recompute()
Второй код — создает формы «ласточкин хвост»
import FreeCAD as App
import FreeCADGui as Gui
import Part
# ==============================================================================
# PART 1: GEOMETRY & PLACEMENT HELPERS
# ==============================================================================
def get_absolute_placement(obj):
"""Recursive calculation to handle nested containers/LinkGroups."""
global_plm = obj.Placement
current_obj = obj
while True:
parents = current_obj.InList
if not parents:
break
found_parent = False
for parent in parents:
if hasattr(parent, "Placement"):
global_plm = parent.Placement.multiply(global_plm)
current_obj = parent
found_parent = True
break
if not found_parent:
break
return global_plm
def get_global_corners(obj):
"""
Returns a SET of rounded global corner tuples for an object.
"""
# 1. Determine Global Placement
is_link_related = False
if obj.isDerivedFrom("App::Link") or obj.isDerivedFrom("App::LinkGroup"):
is_link_related = True
else:
for parent in obj.InList:
if parent.isDerivedFrom("App::LinkGroup"):
is_link_related = True
break
if is_link_related:
global_plm = get_absolute_placement(obj)
elif hasattr(obj, "getGlobalPlacement"):
global_plm = obj.getGlobalPlacement()
else:
global_plm = obj.Placement
# 2. Calculate Effective Transform (Global * Inverse Local)
effective_transform = global_plm.multiply(obj.Placement.inverse())
if not hasattr(obj, "Shape"):
return set()
bbox = obj.Shape.BoundBox
# 3. Local Corners
corners_local = [
App.Vector(bbox.XMin, bbox.YMin, bbox.ZMin),
App.Vector(bbox.XMax, bbox.YMin, bbox.ZMin),
App.Vector(bbox.XMin, bbox.YMax, bbox.ZMin),
App.Vector(bbox.XMax, bbox.YMax, bbox.ZMin),
App.Vector(bbox.XMin, bbox.YMin, bbox.ZMax),
App.Vector(bbox.XMax, bbox.YMin, bbox.ZMax),
App.Vector(bbox.XMin, bbox.YMax, bbox.ZMax),
App.Vector(bbox.XMax, bbox.YMax, bbox.ZMax),
]
# 4. Transform and Round
corners_global = set()
tolerance = 4
for c_local in corners_local:
c_global = effective_transform.multVec(c_local)
pt = (round(c_global.x, tolerance),
round(c_global.y, tolerance),
round(c_global.z, tolerance))
corners_global.add(pt)
return corners_global
# ==============================================================================
# PART 2: TOOL GENERATION
# ==============================================================================
def make_dovetail_tool(center_point, is_vertical, height_z, interface_length):
"""
Creates the dovetail cutter shape.
"""
# Proportional Dimensions
joint_depth = interface_length * 0.2
joint_narrow = interface_length * 0.2
joint_wide = interface_length * 0.4
# 1. Add Oversize (for clearance/overlap)
oversize = 0.2
tool_height = height_z + oversize
# Create points centered on Y-axis (for horizontal tool)
p1 = App.Vector(0, -(joint_narrow/2), 0)
p2 = App.Vector(joint_depth, -(joint_wide/2), 0)
p3 = App.Vector(joint_depth, (joint_wide/2), 0)
p4 = App.Vector(0, (joint_narrow/2), 0)
p5 = p1
wire = Part.makePolygon([p1, p2, p3, p4, p5])
face = Part.Face(wire)
solid = face.extrude(App.Vector(0, 0, tool_height))
# 2. Center the tool vertically (Z-axis)
# Move it down by half the oversize so it extends slightly above and below
solid.translate(App.Vector(0, 0, -(oversize/2.0)))
# 3. Rotate if vertical orientation is required
if is_vertical:
solid.rotate(App.Vector(0,0,0), App.Vector(0,0,1), 90)
# 4. Move to global position
solid.translate(center_point)
return solid
def create_preview_object(doc, tool_shape, name_a, name_b):
"""
Creates a visual object in the document instead of performing boolean ops.
"""
label = f"Preview_Tool_{name_a}_vs_{name_b}"
obj = doc.addObject("Part::Feature", label)
obj.Shape = tool_shape
# Visual properties: Red and 50% transparent
obj.ViewObject.ShapeColor = (1.0, 0.0, 0.0)
obj.ViewObject.Transparency = 50
return obj
# ==============================================================================
# PART 3: MAIN EXECUTION
# ==============================================================================
def main():
selection = Gui.Selection.getSelection()
if not selection or len(selection) < 2:
print("Error: Select at least 2 panels.")
return
doc = App.activeDocument()
print(f"Generating PREVIEW tools for {len(selection)} panels...")
panel_data = {}
for obj in selection:
c_set = get_global_corners(obj)
if c_set:
# Convert to list for indexing coordinates
c_list = list(c_set)
xs = [p[0] for p in c_list]
ys = [p[1] for p in c_list]
zs = [p[2] for p in c_list]
panel_data[obj.Name] = {
"obj": obj,
"corners": c_set, # Keep set for intersection check
"cx": sum(xs) / len(xs),
"cy": sum(ys) / len(ys),
"sx": max(xs) - min(xs),
"sy": max(ys) - min(ys),
"z_base": min(zs),
"height": max(zs) - min(zs)
}
keys = sorted(list(panel_data.keys()))
tool_count = 0
# 2. Iterate unique pairs
for i in range(len(keys)):
for j in range(i + 1, len(keys)):
name_a = keys
name_b = keys[j]
data_a = panel_data[name_a]
data_b = panel_data[name_b]
# Check for shared corners
shared = data_a["corners"].intersection(data_b["corners"])
if len(shared) >= 4:
# Neighbor detected
dx = data_b["cx"] - data_a["cx"]
dy = data_b["cy"] - data_a["cy"]
mid_x = (data_a["cx"] + data_b["cx"]) / 2.0
mid_y = (data_a["cy"] + data_b["cy"]) / 2.0
z_pos = data_a["z_base"]
joint_center = App.Vector(mid_x, mid_y, z_pos)
h_val = data_a["height"]
# Determine orientation and generate tool
if abs(dx) > abs(dy):
# Neighbors are left/right of each other (Horizontal difference)
# Joint runs along Y, so interface length is Y size (sy)
ref_size = min(data_a["sy"], data_b["sy"])
tool = make_dovetail_tool(joint_center, False, h_val, ref_size)
create_preview_object(doc, tool, name_a, name_b)
tool_count += 1
else:
# Neighbors are above/below each other (Vertical difference)
# Joint runs along X, so interface length is X size (sx)
ref_size = min(data_a["sx"], data_b["sx"])
# is_vertical=True rotates the tool to face Y
tool = make_dovetail_tool(joint_center, True, h_val, ref_size)
create_preview_object(doc, tool, name_a, name_b)
tool_count += 1
doc.recompute()
print(f"Done. {tool_count} preview tools created.")
if __name__ == "__main__":
main()
Третий код — соедините и разрежьте фигуры «ласточкин хвост»
```py
import FreeCAD as App
import Part
def get_absolute_placement(obj):
"""Calculates global placement to handle nested containers."""
global_plm = obj.Placement
current_obj = obj
while True:
parents = current_obj.InList
if not parents:
break
found_parent = False
for parent in parents:
if hasattr(parent, "Placement"):
global_plm = parent.Placement.multiply(global_plm)
current_obj = parent
found_parent = True
break
if not found_parent:
break
return global_plm
def get_global_center(obj):
"""Fast approximation of global center using BoundingBox center."""
if not hasattr(obj, "Shape"):
return App.Vector(0,0,0)
# Get global placement
plm = get_absolute_placement(obj)
# Get local center
bb = obj.Shape.BoundBox
local_center = bb.Center
# Transform to global
return plm.multVec(local_center)
def apply_existing_tool(tool_obj, name_a, name_b):
doc = App.activeDocument()
# 1. Find the actual panel objects
obj_a = doc.getObject(name_a)
obj_b = doc.getObject(name_b)
if not obj_a or not obj_b:
print(f"Skipping {tool_obj.Name}: Could not find panels '{name_a}' or '{name_b}'")
return False
# 2. Determine Orientation (Who is Male/Pin? Who is Female/Hole?)
# We re-evaluate the relative positions to ensure consistency with the standard logic:
# Left = Male, Right = Female
# Bottom = Male, Top = Female
pos_a = get_global_center(obj_a)
pos_b = get_global_center(obj_b)
dx = pos_b.x - pos_a.x
dy = pos_b.y - pos_a.y
male_obj = None
female_obj = None
if abs(dx) > abs(dy):
# Horizontal Interface
if dx > 0: # B is right of A
male_obj, female_obj = obj_a, obj_b
else: # A is right of B
male_obj, female_obj = obj_b, obj_a
else:
# Vertical Interface
if dy > 0: # B is above A
male_obj, female_obj = obj_a, obj_b
else: # A is above B
male_obj, female_obj = obj_b, obj_a
# 3. Apply the Tool
# The Tool is already in Global Space. We must transform it to Local Space.
tool_shape_global = tool_obj.Shape.copy()
# --- Fuse to Male ---
male_global_plm = get_absolute_placement(male_obj)
to_male_local = male_global_plm.inverse().toMatrix()
tool_for_male = tool_shape_global.copy()
tool_for_male.transformShape(to_male_local)
male_obj.Shape = male_obj.Shape.fuse(tool_for_male)
# --- Cut from Female ---
female_global_plm = get_absolute_placement(female_obj)
to_female_local = female_global_plm.inverse().toMatrix()
tool_for_female = tool_shape_global.copy()
tool_for_female.transformShape(to_female_local)
female_obj.Shape = female_obj.Shape.cut(tool_for_female)
return True
def main():
doc = App.activeDocument()
if not doc:
print("No active document.")
return
# Find all preview tools
preview_tools = []
for obj in doc.Objects:
if obj.Name.startswith("Preview_Tool_"):
preview_tools.append(obj)
if not preview_tools:
print("No 'Preview_Tool' objects found. Run the preview script first.")
return
print(f"Found {len(preview_tools)} preview tools. Applying operations...")
doc.openTransaction("Apply Preview Tools")
processed_count = 0
for tool in preview_tools:
# Parse name: Preview_Tool_{NameA}_vs_{NameB}
# We split by "_vs_" to separate the two panels
# The prefix is "Preview_Tool_" (length 13)
raw_name = tool.Name[13:] # Strip "Preview_Tool_"
if "_vs_" not in raw_name:
print(f"Skipping {tool.Name}: Naming format incorrect.")
continue
parts = raw_name.split("_vs_")
if len(parts) != 2:
print(f"Skipping {tool.Name}: Could not parse panel names.")
continue
name_a = parts[0]
name_b = parts[1]
success = apply_existing_tool(tool, name_a, name_b)
if success:
processed_count += 1
# Delete the tool after use to clean up
doc.removeObject(tool.Name)
doc.commitTransaction()
doc.recompute()
print(f"Done. Applied {processed_count} joints and removed preview tools.")
if __name__ == "__main__":
main()
Подробнее здесь: https://stackoverflow.com/questions/798 ... ially-work
Скрипт Freecad Python для создания головоломки — предохранители работают, но разрезы работают только частично ⇐ Python
Программы на Python
1769986751
Anonymous
Я пытаюсь создать головоломку в FreeCad. Если вы вставите первый блок кода в интерпретатор Python FreeCad v1.1, он создаст сетку блоков. Это демо-пример среды. Цель состоит в том, чтобы соединить каждый квадрат сетки.
Затем, когда я вставляю второй блок кода, он создает формы «ласточкин хвост», которые будут вырезаны из женских блоков и слиты с мужскими блоками.
Это все правильно и выглядит идеально.
Но проблема в третьем блоке. Все «ласточкины хвосты» срастаются правильно, но режутся неправильно. Лишь некоторые из них режут правильно. Один или два будут обрезаны правильно, но остальные - неудачно.
Я не уверен, это мой код или проблема с FreeCAD... Есть идеи, это известная ошибка или я делаю что-то не так?
Спасибо!
[b]Первый код - создайте демонстрационную среду[/b]
import FreeCAD as App
import Part
# Create a new document
doc = App.activeDocument()
if not doc:
doc = App.newDocument("GridDocument")
# Dimensions of each box
size = 10.0
# Grid settings: 3 columns, 2 rows (total 6 boxes)
columns = 3
rows = 3
for i in range(columns):
for j in range(rows):
# Create the box shape
box_shape = Part.makeBox(size, size, size)
# Create a document object to hold the shape
box_obj = doc.addObject("Part::Feature", f"Box_{i}_{j}")
box_obj.Shape = box_shape
# Calculate position (all touching)
x_pos = i * size
y_pos = j * size
# Apply the position
box_obj.Placement = App.Placement(App.Vector(x_pos, y_pos, 0), App.Rotation(0, 0, 0))
# Refresh the 3D view
doc.recompute()
[b]Второй код — создает формы «ласточкин хвост»[/b]
import FreeCAD as App
import FreeCADGui as Gui
import Part
# ==============================================================================
# PART 1: GEOMETRY & PLACEMENT HELPERS
# ==============================================================================
def get_absolute_placement(obj):
"""Recursive calculation to handle nested containers/LinkGroups."""
global_plm = obj.Placement
current_obj = obj
while True:
parents = current_obj.InList
if not parents:
break
found_parent = False
for parent in parents:
if hasattr(parent, "Placement"):
global_plm = parent.Placement.multiply(global_plm)
current_obj = parent
found_parent = True
break
if not found_parent:
break
return global_plm
def get_global_corners(obj):
"""
Returns a SET of rounded global corner tuples for an object.
"""
# 1. Determine Global Placement
is_link_related = False
if obj.isDerivedFrom("App::Link") or obj.isDerivedFrom("App::LinkGroup"):
is_link_related = True
else:
for parent in obj.InList:
if parent.isDerivedFrom("App::LinkGroup"):
is_link_related = True
break
if is_link_related:
global_plm = get_absolute_placement(obj)
elif hasattr(obj, "getGlobalPlacement"):
global_plm = obj.getGlobalPlacement()
else:
global_plm = obj.Placement
# 2. Calculate Effective Transform (Global * Inverse Local)
effective_transform = global_plm.multiply(obj.Placement.inverse())
if not hasattr(obj, "Shape"):
return set()
bbox = obj.Shape.BoundBox
# 3. Local Corners
corners_local = [
App.Vector(bbox.XMin, bbox.YMin, bbox.ZMin),
App.Vector(bbox.XMax, bbox.YMin, bbox.ZMin),
App.Vector(bbox.XMin, bbox.YMax, bbox.ZMin),
App.Vector(bbox.XMax, bbox.YMax, bbox.ZMin),
App.Vector(bbox.XMin, bbox.YMin, bbox.ZMax),
App.Vector(bbox.XMax, bbox.YMin, bbox.ZMax),
App.Vector(bbox.XMin, bbox.YMax, bbox.ZMax),
App.Vector(bbox.XMax, bbox.YMax, bbox.ZMax),
]
# 4. Transform and Round
corners_global = set()
tolerance = 4
for c_local in corners_local:
c_global = effective_transform.multVec(c_local)
pt = (round(c_global.x, tolerance),
round(c_global.y, tolerance),
round(c_global.z, tolerance))
corners_global.add(pt)
return corners_global
# ==============================================================================
# PART 2: TOOL GENERATION
# ==============================================================================
def make_dovetail_tool(center_point, is_vertical, height_z, interface_length):
"""
Creates the dovetail cutter shape.
"""
# Proportional Dimensions
joint_depth = interface_length * 0.2
joint_narrow = interface_length * 0.2
joint_wide = interface_length * 0.4
# 1. Add Oversize (for clearance/overlap)
oversize = 0.2
tool_height = height_z + oversize
# Create points centered on Y-axis (for horizontal tool)
p1 = App.Vector(0, -(joint_narrow/2), 0)
p2 = App.Vector(joint_depth, -(joint_wide/2), 0)
p3 = App.Vector(joint_depth, (joint_wide/2), 0)
p4 = App.Vector(0, (joint_narrow/2), 0)
p5 = p1
wire = Part.makePolygon([p1, p2, p3, p4, p5])
face = Part.Face(wire)
solid = face.extrude(App.Vector(0, 0, tool_height))
# 2. Center the tool vertically (Z-axis)
# Move it down by half the oversize so it extends slightly above and below
solid.translate(App.Vector(0, 0, -(oversize/2.0)))
# 3. Rotate if vertical orientation is required
if is_vertical:
solid.rotate(App.Vector(0,0,0), App.Vector(0,0,1), 90)
# 4. Move to global position
solid.translate(center_point)
return solid
def create_preview_object(doc, tool_shape, name_a, name_b):
"""
Creates a visual object in the document instead of performing boolean ops.
"""
label = f"Preview_Tool_{name_a}_vs_{name_b}"
obj = doc.addObject("Part::Feature", label)
obj.Shape = tool_shape
# Visual properties: Red and 50% transparent
obj.ViewObject.ShapeColor = (1.0, 0.0, 0.0)
obj.ViewObject.Transparency = 50
return obj
# ==============================================================================
# PART 3: MAIN EXECUTION
# ==============================================================================
def main():
selection = Gui.Selection.getSelection()
if not selection or len(selection) < 2:
print("Error: Select at least 2 panels.")
return
doc = App.activeDocument()
print(f"Generating PREVIEW tools for {len(selection)} panels...")
panel_data = {}
for obj in selection:
c_set = get_global_corners(obj)
if c_set:
# Convert to list for indexing coordinates
c_list = list(c_set)
xs = [p[0] for p in c_list]
ys = [p[1] for p in c_list]
zs = [p[2] for p in c_list]
panel_data[obj.Name] = {
"obj": obj,
"corners": c_set, # Keep set for intersection check
"cx": sum(xs) / len(xs),
"cy": sum(ys) / len(ys),
"sx": max(xs) - min(xs),
"sy": max(ys) - min(ys),
"z_base": min(zs),
"height": max(zs) - min(zs)
}
keys = sorted(list(panel_data.keys()))
tool_count = 0
# 2. Iterate unique pairs
for i in range(len(keys)):
for j in range(i + 1, len(keys)):
name_a = keys[i]
name_b = keys[j]
data_a = panel_data[name_a]
data_b = panel_data[name_b]
# Check for shared corners
shared = data_a["corners"].intersection(data_b["corners"])
if len(shared) >= 4:
# Neighbor detected
dx = data_b["cx"] - data_a["cx"]
dy = data_b["cy"] - data_a["cy"]
mid_x = (data_a["cx"] + data_b["cx"]) / 2.0
mid_y = (data_a["cy"] + data_b["cy"]) / 2.0
z_pos = data_a["z_base"]
joint_center = App.Vector(mid_x, mid_y, z_pos)
h_val = data_a["height"]
# Determine orientation and generate tool
if abs(dx) > abs(dy):
# Neighbors are left/right of each other (Horizontal difference)
# Joint runs along Y, so interface length is Y size (sy)
ref_size = min(data_a["sy"], data_b["sy"])
tool = make_dovetail_tool(joint_center, False, h_val, ref_size)
create_preview_object(doc, tool, name_a, name_b)
tool_count += 1
else:
# Neighbors are above/below each other (Vertical difference)
# Joint runs along X, so interface length is X size (sx)
ref_size = min(data_a["sx"], data_b["sx"])
# is_vertical=True rotates the tool to face Y
tool = make_dovetail_tool(joint_center, True, h_val, ref_size)
create_preview_object(doc, tool, name_a, name_b)
tool_count += 1
doc.recompute()
print(f"Done. {tool_count} preview tools created.")
if __name__ == "__main__":
main()
[b]Третий код — соедините и разрежьте фигуры «ласточкин хвост»[/b]
```py
import FreeCAD as App
import Part
def get_absolute_placement(obj):
"""Calculates global placement to handle nested containers."""
global_plm = obj.Placement
current_obj = obj
while True:
parents = current_obj.InList
if not parents:
break
found_parent = False
for parent in parents:
if hasattr(parent, "Placement"):
global_plm = parent.Placement.multiply(global_plm)
current_obj = parent
found_parent = True
break
if not found_parent:
break
return global_plm
def get_global_center(obj):
"""Fast approximation of global center using BoundingBox center."""
if not hasattr(obj, "Shape"):
return App.Vector(0,0,0)
# Get global placement
plm = get_absolute_placement(obj)
# Get local center
bb = obj.Shape.BoundBox
local_center = bb.Center
# Transform to global
return plm.multVec(local_center)
def apply_existing_tool(tool_obj, name_a, name_b):
doc = App.activeDocument()
# 1. Find the actual panel objects
obj_a = doc.getObject(name_a)
obj_b = doc.getObject(name_b)
if not obj_a or not obj_b:
print(f"Skipping {tool_obj.Name}: Could not find panels '{name_a}' or '{name_b}'")
return False
# 2. Determine Orientation (Who is Male/Pin? Who is Female/Hole?)
# We re-evaluate the relative positions to ensure consistency with the standard logic:
# Left = Male, Right = Female
# Bottom = Male, Top = Female
pos_a = get_global_center(obj_a)
pos_b = get_global_center(obj_b)
dx = pos_b.x - pos_a.x
dy = pos_b.y - pos_a.y
male_obj = None
female_obj = None
if abs(dx) > abs(dy):
# Horizontal Interface
if dx > 0: # B is right of A
male_obj, female_obj = obj_a, obj_b
else: # A is right of B
male_obj, female_obj = obj_b, obj_a
else:
# Vertical Interface
if dy > 0: # B is above A
male_obj, female_obj = obj_a, obj_b
else: # A is above B
male_obj, female_obj = obj_b, obj_a
# 3. Apply the Tool
# The Tool is already in Global Space. We must transform it to Local Space.
tool_shape_global = tool_obj.Shape.copy()
# --- Fuse to Male ---
male_global_plm = get_absolute_placement(male_obj)
to_male_local = male_global_plm.inverse().toMatrix()
tool_for_male = tool_shape_global.copy()
tool_for_male.transformShape(to_male_local)
male_obj.Shape = male_obj.Shape.fuse(tool_for_male)
# --- Cut from Female ---
female_global_plm = get_absolute_placement(female_obj)
to_female_local = female_global_plm.inverse().toMatrix()
tool_for_female = tool_shape_global.copy()
tool_for_female.transformShape(to_female_local)
female_obj.Shape = female_obj.Shape.cut(tool_for_female)
return True
def main():
doc = App.activeDocument()
if not doc:
print("No active document.")
return
# Find all preview tools
preview_tools = []
for obj in doc.Objects:
if obj.Name.startswith("Preview_Tool_"):
preview_tools.append(obj)
if not preview_tools:
print("No 'Preview_Tool' objects found. Run the preview script first.")
return
print(f"Found {len(preview_tools)} preview tools. Applying operations...")
doc.openTransaction("Apply Preview Tools")
processed_count = 0
for tool in preview_tools:
# Parse name: Preview_Tool_{NameA}_vs_{NameB}
# We split by "_vs_" to separate the two panels
# The prefix is "Preview_Tool_" (length 13)
raw_name = tool.Name[13:] # Strip "Preview_Tool_"
if "_vs_" not in raw_name:
print(f"Skipping {tool.Name}: Naming format incorrect.")
continue
parts = raw_name.split("_vs_")
if len(parts) != 2:
print(f"Skipping {tool.Name}: Could not parse panel names.")
continue
name_a = parts[0]
name_b = parts[1]
success = apply_existing_tool(tool, name_a, name_b)
if success:
processed_count += 1
# Delete the tool after use to clean up
doc.removeObject(tool.Name)
doc.commitTransaction()
doc.recompute()
print(f"Done. Applied {processed_count} joints and removed preview tools.")
if __name__ == "__main__":
main()
Подробнее здесь: [url]https://stackoverflow.com/questions/79880732/freecad-python-script-to-create-puzzle-fuses-work-but-cuts-only-partially-work[/url]
Ответить
1 сообщение
• Страница 1 из 1
Перейти
- Кемерово-IT
- ↳ Javascript
- ↳ C#
- ↳ JAVA
- ↳ Elasticsearch aggregation
- ↳ Python
- ↳ Php
- ↳ Android
- ↳ Html
- ↳ Jquery
- ↳ C++
- ↳ IOS
- ↳ CSS
- ↳ Excel
- ↳ Linux
- ↳ Apache
- ↳ MySql
- Детский мир
- Для души
- ↳ Музыкальные инструменты даром
- ↳ Печатная продукция даром
- Внешняя красота и здоровье
- ↳ Одежда и обувь для взрослых даром
- ↳ Товары для здоровья
- ↳ Физкультура и спорт
- Техника - даром!
- ↳ Автомобилистам
- ↳ Компьютерная техника
- ↳ Плиты: газовые и электрические
- ↳ Холодильники
- ↳ Стиральные машины
- ↳ Телевизоры
- ↳ Телефоны, смартфоны, плашеты
- ↳ Швейные машинки
- ↳ Прочая электроника и техника
- ↳ Фототехника
- Ремонт и интерьер
- ↳ Стройматериалы, инструмент
- ↳ Мебель и предметы интерьера даром
- ↳ Cантехника
- Другие темы
- ↳ Разное даром
- ↳ Давай меняться!
- ↳ Отдам\возьму за копеечку
- ↳ Работа и подработка в Кемерове
- ↳ Давай с тобой поговорим...
Мобильная версия