Last active
December 13, 2024 18:01
-
-
Save sam2332/469ef1b976e62b1117b3bb36b1afd3b8 to your computer and use it in GitHub Desktop.
USE Blender python As a Step tool and code it all in python like a real programmer
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import bpy | |
from mathutils import Euler, Vector | |
import math | |
import bmesh | |
def set_origin_to_bottom_center(obj): | |
""" | |
Sets the origin of the given object to its bottom center. | |
Args: | |
obj (bpy.types.Object): The object whose origin will be set. | |
""" | |
# Ensure the object is active and selected | |
bpy.ops.object.select_all(action='DESELECT') | |
obj.select_set(True) | |
bpy.context.view_layer.objects.active = obj | |
# Calculate the bounding box in local coordinates | |
bbox_corners = obj.bound_box | |
min_z = min([corner[2] for corner in bbox_corners]) | |
max_z = max([corner[2] for corner in bbox_corners]) | |
# Calculate the bottom center in local coordinates | |
center_x = (max([corner[0] for corner in bbox_corners]) + min([corner[0] for corner in bbox_corners])) / 2 | |
center_y = (max([corner[1] for corner in bbox_corners]) + min([corner[1] for corner in bbox_corners])) / 2 | |
bottom_center_local = (center_x, center_y, min_z) | |
# Transform the local bottom center to world coordinates | |
bottom_center_world = obj.matrix_world @ Vector(bottom_center_local) | |
# Set the 3D cursor to the bottom center | |
bpy.context.scene.cursor.location = bottom_center_world | |
# Set the origin to the 3D cursor | |
bpy.ops.object.origin_set(type='ORIGIN_CURSOR') | |
import bpy | |
from mathutils import Vector | |
def create_cube(location, dimensions, name): | |
""" | |
Creates a cube by stitching vertices together at the specified location and dimensions, | |
and sets its origin to the bottom center. | |
Args: | |
location (tuple): A tuple (x, y, z) specifying the bottom center of the cube. | |
dimensions (tuple): A tuple (x, y, z) specifying the cube's dimensions. | |
name (str): The name to assign to the cube. | |
Returns: | |
bpy.types.Object: The created cube object. | |
""" | |
# Calculate half dimensions | |
hx, hy, hz = dimensions[0] / 2, dimensions[1] / 2, dimensions[2] | |
# Define the vertices of the cube | |
vertices = [ | |
Vector((-hx, -hy, 0)), # Bottom face | |
Vector((hx, -hy, 0)), | |
Vector((hx, hy, 0)), | |
Vector((-hx, hy, 0)), | |
Vector((-hx, -hy, hz)), # Top face | |
Vector((hx, -hy, hz)), | |
Vector((hx, hy, hz)), | |
Vector((-hx, hy, hz)), | |
] | |
# Define the faces using the vertices | |
faces = [ | |
(0, 1, 2, 3), # Bottom face | |
(4, 5, 6, 7), # Top face | |
(0, 1, 5, 4), # Side faces | |
(1, 2, 6, 5), | |
(2, 3, 7, 6), | |
(3, 0, 4, 7), | |
] | |
# Create a new mesh and object | |
mesh = bpy.data.meshes.new(name) | |
cube_object = bpy.data.objects.new(name, mesh) | |
# Link the object to the scene | |
bpy.context.collection.objects.link(cube_object) | |
# Create the mesh from vertices and faces | |
mesh.from_pydata(vertices, [], faces) | |
mesh.update() | |
# Move the object to the correct location | |
cube_object.location = Vector(location) | |
# Set origin to bottom center | |
bpy.context.view_layer.objects.active = cube_object | |
bpy.ops.object.origin_set(type='ORIGIN_CENTER_OF_MASS', center='BOUNDS') | |
return cube_object | |
def create_cylinder(location, r, height, name, rotation=(0, 0, 0)): | |
""" | |
Creates a cylinder at the specified location with the given radius and height | |
and sets its origin to the bottom center. | |
Args: | |
location (tuple): A tuple (x, y, z) specifying the cylinder's location. | |
r (float): The radius of the cylinder. | |
height (float): The height of the cylinder. | |
name (str): The name to assign to the cylinder. | |
rotation (tuple): A tuple (x, y, z) specifying the rotation in radians. | |
Returns: | |
bpy.types.Object: The created cylinder object. | |
""" | |
bpy.ops.mesh.primitive_cylinder_add(location=location, radius=r, depth=height) | |
cylinder = bpy.context.active_object | |
cylinder.name = name | |
cylinder.rotation_euler = Euler(rotation) | |
# Set origin to bottom center | |
set_origin_to_bottom_center(cylinder) | |
return cylinder | |
def clear_scene(): | |
"""Deletes all objects in the current scene.""" | |
bpy.ops.object.mode_set(mode='OBJECT') | |
bpy.ops.object.select_all(action="SELECT") | |
bpy.ops.object.delete(use_global=False) | |
def subtract_model(obj1, obj2, remove=True, fast_mode=True): | |
""" | |
Subtracts obj2 from obj1 using a Boolean modifier. | |
Optionally removes obj2 from the scene after the operation. | |
Allows switching between Fast and Exact modes. | |
""" | |
if obj1 is None or obj2 is None: | |
print("Error: One of the objects is None. Cannot perform Boolean operation.") | |
return | |
if boolean_disable: | |
print("Boolean operations are disabled. Skipping subtraction.") | |
return | |
# Add a Boolean modifier to obj1 | |
bool_mod = obj1.modifiers.new(name="BooleanModifier", type="BOOLEAN") | |
bool_mod.object = obj2 | |
bool_mod.operation = "DIFFERENCE" | |
# Set the solver to Fast or Exact | |
bool_mod.solver = "FAST" if fast_mode else "EXACT" | |
# Apply the modifier | |
bpy.context.view_layer.objects.active = obj1 | |
bpy.ops.object.modifier_apply(modifier=bool_mod.name) | |
# Optionally remove obj2 | |
if remove: | |
bpy.data.objects.remove(obj2) | |
def add_model(obj1, obj2, remove=True, fast_mode=True): | |
""" | |
Adds obj2 to obj1 using a Boolean modifier. | |
Optionally removes obj2 from the scene after the operation. | |
Allows switching between Fast and Exact modes. | |
""" | |
if obj1 is None or obj2 is None: | |
print("Error: One of the objects is None. Cannot perform Boolean operation.") | |
return | |
if boolean_disable: | |
print("Boolean operations are disabled. Skipping addition.") | |
return | |
# Add a Boolean modifier to obj1 | |
bool_mod = obj1.modifiers.new(name="BooleanModifier", type="BOOLEAN") | |
bool_mod.object = obj2 | |
bool_mod.operation = "UNION" | |
# Set the solver to Fast or Exact | |
bool_mod.solver = "FAST" if fast_mode else "EXACT" | |
# Apply the modifier | |
bpy.context.view_layer.objects.active = obj1 | |
bpy.ops.object.modifier_apply(modifier=bool_mod.name) | |
# Optionally remove obj2 | |
if remove: | |
bpy.data.objects.remove(obj2) | |
def duplicate_model(obj, new_name): | |
""" | |
Duplicates an object and assigns it a new name. | |
Args: | |
obj (bpy.types.Object): The object to duplicate. | |
new_name (str): The name to assign to the duplicate object. | |
Returns: | |
bpy.types.Object: The duplicated object. | |
""" | |
if not obj: | |
print("Error: No object provided to duplicate.") | |
return None | |
# Deselect all objects | |
bpy.ops.object.select_all(action='DESELECT') | |
# Select the object to duplicate | |
obj.select_set(True) | |
bpy.context.view_layer.objects.active = obj | |
# Duplicate the object | |
bpy.ops.object.duplicate() | |
duplicate = bpy.context.active_object | |
duplicate.name = new_name | |
# Set origin to bottom center for the duplicate | |
set_origin_to_bottom_center(duplicate) | |
return duplicate | |
def remove_object(obj2): | |
bpy.data.objects.remove(obj2) | |
# Global flag to disable Boolean operations | |
boolean_disable = False | |
# Clear the scene | |
clear_scene() | |
def make_iron_holder(): | |
# Create the main cube with correct dimensions and origin | |
main_obj = create_cube(location=(0, 0, 0), dimensions=(20, 20, 20), name="Part") | |
# Create the cylinder and add it to the main cube | |
cylinder = create_cylinder(location=(10, 0, 0), r=10, height=20, name="Cylinder_rounding") | |
subtract_model(cylinder,main_obj,False) | |
add_model(main_obj, cylinder) | |
#drill out 17 dia | |
cylinder = create_cylinder(location=(10, 0, 10), r=17/2, height=13, name="Cylinder17mm") | |
subtract_model(main_obj,cylinder) | |
#center 14 dia | |
cylinder = create_cylinder(location=(10, 0, -3), r=14/2, height=20, name="Cylinder14mm") | |
subtract_model(main_obj,cylinder) | |
#ceneter 14 dia | |
cylinder = create_cylinder(location=(15, 0, -3), r=13/2, height=35, name="Cylinder13mm_bore") | |
subtract_model(main_obj,cylinder) | |
obj_sdh = create_cube(location=(0, 25, 0), dimensions=(20, 30, 20), name="side_cord_holder") | |
# Create the cylinder and add it to the main cube | |
cylinder = create_cylinder(location=(00, 40, 0), r=10, height=20, name="sh_rounding") | |
subtract_model(cylinder,main_obj,False) | |
add_model(obj_sdh, cylinder) | |
# drill out 12 | |
cylinder = create_cylinder(location=(0, 40, 0), r=12/2, height=20, name="sh_Cylinder12mm") | |
subtract_model(obj_sdh,cylinder) | |
# drill out 17 | |
cylinder = create_cylinder(location=(0, 40, 7), r=17/2, height=20, name="sh_Cylinder17mm") | |
subtract_model(obj_sdh,cylinder) | |
#ceneter 14 dia | |
cylinder = create_cylinder(location=(0, 50, 7), r=13/2, height=35, name="sh_Cylinder13mm_bore") | |
subtract_model(obj_sdh,cylinder) | |
add_model(main_obj,obj_sdh) | |
def merge_nerby_vertices(obj, threshold=0.001): | |
""" | |
Merges nearby vertices in the given object based on the threshold distance. | |
Args: | |
obj (bpy.types.Object): The object whose vertices will be merged. | |
threshold (float): The maximum distance between vertices to merge. | |
""" | |
bpy.context.view_layer.objects.active = obj | |
bpy.ops.object.mode_set(mode='EDIT') | |
bpy.ops.mesh.select_all(action='SELECT') | |
bpy.ops.mesh.remove_doubles(threshold=threshold) | |
bpy.ops.object.mode_set(mode='OBJECT') | |
def make_caliper_holder(): | |
# cut slot out | |
def cut_slot(main_obj): | |
cutter = create_cube(location=(1,0,1.6),dimensions=(26,16.3,10.6),name="cutter_slot") | |
subtract_model(main_obj,cutter) | |
def cut_bottom_slant(main_obj): | |
cutter = create_cube(location=(7.6814,0,0.5521),dimensions=(6,15.8,6),name="cutter_bottom_slot") | |
rotation=(0,0.244346,0) # ~14 degree | |
cutter.rotation_euler = Euler(rotation) | |
subtract_model(main_obj,cutter) | |
def make_lid(main_obj): | |
lid = create_cube(location=(0, 0, 8.7), dimensions=(19, 27.4, 1.4), name="Lid") | |
subtract_model(lid,main_obj,remove=False)# make a negative impression on the lid of the box to make it fit | |
rotation=(0,3.14,0) # flip the lid face down | |
lid.rotation_euler = Euler(rotation) | |
lid.location.x= 25 | |
lid.location.y=0 | |
lid.location.z = 0 | |
main_obj = create_cube(location=(0, 0, 0), dimensions=(20, 28, 9.5), name="Part") | |
cut_slot(main_obj) | |
cut_bottom_slant(main_obj) | |
merge_nerby_vertices(main_obj,0.05) # merge vertices within 0.05 distance | |
lid = make_lid(main_obj) | |
make_caliper_holder() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
this is example output