import bpy import bmesh import math def add_boolean(target, cutter, operation='DIFFERENCE', solver='EXACT'): mod = target.modifiers.new(name="Bool", type='BOOLEAN') mod.object = cutter mod.operation = operation mod.solver = solver bpy.context.view_layer.objects.active = target bpy.ops.object.modifier_apply(modifier=mod.name) bpy.data.objects.remove(cutter, do_unlink=True) def generate_blocks_v4_mini(): # Clear existing mesh objects bpy.ops.object.select_all(action='DESELECT') for obj in list(bpy.context.scene.objects): if obj.type == 'MESH': bpy.data.objects.remove(obj, do_unlink=True) # ============================================================================== # VERSION 4: MINIATURE CONTINUOUS-LOOP "SPRING-EYELET" CONNECTOR SYSTEM # Designed specifically for tiny / miniature parts on standard 0.4mm nozzles! # ============================================================================== block_size = 10.0 # Tiny 10x10x10mm miniature blocks! tol = 0.18 # 0.18mm precision clearance for miniature snap fit # Miniature Connector Pin Parameters (Total size: 9.0mm long x 4.6mm wide x 3.2mm thick!) pin_thick_z = 3.2 # 3.2mm flat thickness (16 layers @ 0.2mm) half_len_x = 4.5 # 4.5mm per side -> 9.0mm total pin length (fits inside 10mm mini blocks!) neck_half_y = 1.9 # 3.8mm neck width bump_ext = 0.35 # 0.35mm locking ridge per side (4.5mm across bumps) bump_x = 2.6 # Distance from center (X=0) to locking bump peak collar_half_x = 0.6 # 1.2mm wide center stop-collar collar_half_y = 2.3 # 4.6mm width at center collar full_verts = [ (collar_half_x, -collar_half_y), (collar_half_x + 0.4, -neck_half_y), (1.5, -neck_half_y), (bump_x, -(neck_half_y + bump_ext)), (half_len_x - 0.5, -(neck_half_y - 0.35)), (half_len_x, -(neck_half_y - 0.85)), (half_len_x, (neck_half_y - 0.85)), (half_len_x - 0.5, (neck_half_y - 0.35)), (bump_x, (neck_half_y + bump_ext)), (1.5, neck_half_y), (collar_half_x + 0.4, neck_half_y), (collar_half_x, collar_half_y), (-collar_half_x, collar_half_y), (-(collar_half_x + 0.4), neck_half_y), (-1.5, neck_half_y), (-bump_x, (neck_half_y + bump_ext)), (-(half_len_x - 0.5), (neck_half_y - 0.35)), (-half_len_x, (neck_half_y - 0.85)), (-half_len_x, -(neck_half_y - 0.85)), (-(half_len_x - 0.5), -(neck_half_y - 0.35)), (-bump_x, -(neck_half_y + bump_ext)), (-1.5, -neck_half_y), (-(collar_half_x + 0.4), -neck_half_y), (-collar_half_x, -collar_half_y), ] mesh_pin = bpy.data.meshes.new("MiniConnectorPin") bm_p = bmesh.new() bot_v = [bm_p.verts.new((x, y, 0.0)) for (x, y) in full_verts] top_v = [bm_p.verts.new((x, y, pin_thick_z)) for (x, y) in full_verts] bm_p.faces.new(bot_v[::-1]) bm_p.faces.new(top_v) np = len(full_verts) for i in range(np): bm_p.faces.new([bot_v[i], bot_v[(i+1)%np], top_v[(i+1)%np], top_v[i]]) bm_p.normal_update() bm_p.to_mesh(mesh_pin) bm_p.free() pin_obj = bpy.data.objects.new("Mini_Connector_Pin_v4", mesh_pin) bpy.context.collection.objects.link(pin_obj) bpy.ops.object.select_all(action='DESELECT') pin_obj.select_set(True) bpy.context.view_layer.objects.active = pin_obj mod_pbev = pin_obj.modifiers.new(name="Bevel", type='BEVEL') mod_pbev.width = 0.45 mod_pbev.segments = 4 mod_pbev.affect = 'EDGES' mod_pbev.limit_method = 'ANGLE' mod_pbev.angle_limit = math.radians(15) bpy.ops.object.modifier_apply(modifier=mod_pbev.name) # Cut internal Diamond-Eyelet Spring Window on each side (+X and -X) for sign in [1.0, -1.0]: eye_verts = [ (sign * 0.85, 0.0), (sign * 2.1, -0.62), (sign * 2.9, -0.68), (sign * 3.65, 0.0), (sign * 2.9, 0.68), (sign * 2.1, 0.62), ] if sign < 0: eye_verts = eye_verts[::-1] m_eye = bpy.data.meshes.new("EyeletCutter") bm_e = bmesh.new() eb = [bm_e.verts.new((x, y, -1.0)) for (x, y) in eye_verts] et = [bm_e.verts.new((x, y, pin_thick_z + 1.0)) for (x, y) in eye_verts] bm_e.faces.new(eb[::-1]) bm_e.faces.new(et) ne = len(eye_verts) for i in range(ne): bm_e.faces.new([eb[i], eb[(i+1)%ne], et[(i+1)%ne], et[i]]) bm_e.normal_update() bm_e.to_mesh(m_eye) bm_e.free() eye_obj = bpy.data.objects.new("EyeletObj", m_eye) bpy.context.collection.objects.link(eye_obj) bpy.ops.object.select_all(action='DESELECT') eye_obj.select_set(True) bpy.context.view_layer.objects.active = eye_obj mod_ebev = eye_obj.modifiers.new(name="Bevel", type='BEVEL') mod_ebev.width = 0.4 mod_ebev.segments = 4 mod_ebev.affect = 'EDGES' mod_ebev.limit_method = 'ANGLE' mod_ebev.angle_limit = math.radians(15) bpy.ops.object.modifier_apply(modifier=mod_ebev.name) add_boolean(pin_obj, eye_obj, operation='DIFFERENCE') def cut_mini_vertical_socket(block_obj, loc_x, loc_y): z_top_face = block_size c_collar_y = collar_half_y + tol + 0.25 c_neck_y = neck_half_y + tol c_bump_y = neck_half_y + bump_ext + tol c_depth = half_len_x + 0.35 c_thick_x = pin_thick_z + 2 * tol soc_yz = [ (-(c_collar_y + 0.4), z_top_face + 0.6), (-c_collar_y, z_top_face), (-c_neck_y, z_top_face - (collar_half_x + 0.3)), (-c_neck_y, z_top_face - 1.45), (-c_bump_y, z_top_face - bump_x), (-(c_neck_y - 0.35), z_top_face - c_depth), ( (c_neck_y - 0.35), z_top_face - c_depth), ( c_bump_y, z_top_face - bump_x), ( c_neck_y, z_top_face - 1.45), ( c_neck_y, z_top_face - (collar_half_x + 0.3)), ( c_collar_y, z_top_face), ( (c_collar_y + 0.4), z_top_face + 0.6), ] mesh_s = bpy.data.meshes.new("MiniSocketCutter") bm_s = bmesh.new() x_min = loc_x - c_thick_x / 2.0 x_max = loc_x + c_thick_x / 2.0 v_left = [bm_s.verts.new((x_min, loc_y + y, z)) for (y, z) in soc_yz] v_right = [bm_s.verts.new((x_max, loc_y + y, z)) for (y, z) in soc_yz] bm_s.faces.new(v_left[::-1]) bm_s.faces.new(v_right) ns = len(soc_yz) for i in range(ns): bm_s.faces.new([v_left[i], v_left[(i+1)%ns], v_right[(i+1)%ns], v_right[i]]) bm_s.normal_update() bm_s.to_mesh(mesh_s) bm_s.free() cutter_obj = bpy.data.objects.new("MiniVertCutter", mesh_s) bpy.context.collection.objects.link(cutter_obj) bpy.ops.object.select_all(action='DESELECT') cutter_obj.select_set(True) bpy.context.view_layer.objects.active = cutter_obj mod_sbev = cutter_obj.modifiers.new(name="Bevel", type='BEVEL') mod_sbev.width = 0.45 mod_sbev.segments = 4 mod_sbev.affect = 'EDGES' mod_sbev.limit_method = 'ANGLE' mod_sbev.angle_limit = math.radians(15) bpy.ops.object.modifier_apply(modifier=mod_sbev.name) add_boolean(block_obj, cutter_obj, operation='DIFFERENCE') bm_ch = bmesh.new() ch_pts = [ (loc_x - (c_thick_x/2 + 0.6), z_top_face + 0.6), (loc_x - (c_thick_x/2), z_top_face - 0.7), (loc_x + (c_thick_x/2), z_top_face - 0.7), (loc_x + (c_thick_x/2 + 0.6), z_top_face + 0.6), ] y_min = loc_y - (c_neck_y + 0.25) y_max = loc_y + (c_neck_y + 0.25) vl = [bm_ch.verts.new((x, y_min, z)) for (x, z) in ch_pts] vr = [bm_ch.verts.new((x, y_max, z)) for (x, z) in ch_pts] bm_ch.faces.new(vl[::-1]) bm_ch.faces.new(vr) for i in range(4): bm_ch.faces.new([vl[i], vl[(i+1)%4], vr[(i+1)%4], vr[i]]) bm_ch.normal_update() m_ch = bpy.data.meshes.new("MiniXChamfer") bm_ch.to_mesh(m_ch) bm_ch.free() ch_obj = bpy.data.objects.new("MiniXChamferObj", m_ch) bpy.context.collection.objects.link(ch_obj) add_boolean(block_obj, ch_obj, operation='DIFFERENCE') blocks = [] for name, y_pos in [("Mini_Block_Socket_A_v4", -12.0), ("Mini_Block_Socket_B_v4", 12.0)]: bpy.ops.mesh.primitive_cube_add(size=block_size, location=(0, y_pos, block_size/2)) blk = bpy.context.active_object blk.name = name mod_bev = blk.modifiers.new(name="Bevel", type='BEVEL') mod_bev.width = 0.4 mod_bev.segments = 2 bpy.context.view_layer.objects.active = blk bpy.ops.object.modifier_apply(modifier=mod_bev.name) cut_mini_vertical_socket(blk, 0.0, y_pos) blocks.append(blk) all_objs = blocks + [pin_obj] for obj in all_objs: bm_c = bmesh.new() bm_c.from_mesh(obj.data) bmesh.ops.remove_doubles(bm_c, verts=bm_c.verts, dist=0.0005) bm_c.to_mesh(obj.data) bm_c.free() if __name__ == "__main__": generate_blocks_v4_mini()