Skip to content

Instantly share code, notes, and snippets.

@sam2332
Last active December 13, 2024 18:01
Show Gist options
  • Save sam2332/469ef1b976e62b1117b3bb36b1afd3b8 to your computer and use it in GitHub Desktop.
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
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()
@sam2332
Copy link
Author

sam2332 commented Dec 11, 2024

image
this is example output

@sam2332
Copy link
Author

sam2332 commented Dec 11, 2024

image
I made it look cooler

@sam2332
Copy link
Author

sam2332 commented Dec 11, 2024

image

@sam2332
Copy link
Author

sam2332 commented Dec 11, 2024

image

@sam2332
Copy link
Author

sam2332 commented Dec 13, 2024

image

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment