"""Parametric eight-hole circular flange generated with build123d.""" from math import cos, radians, sin, tan from build123d import Align, Box, BuildPart, Cone, Cylinder, Location, Locations, Mode OUTER_DIAMETER_MM = 50.0 INNER_DIAMETER_MM = 20.0 THICKNESS_MM = 4.0 BOLT_HOLE_COUNT = 8 M3_CLEARANCE_DIAMETER_MM = 3.4 BOLT_CIRCLE_DIAMETER_MM = 40.0 M4_THREAD_SPEC = "M4" M4_TAP_DRILL_DIAMETER_MM = 3.3 M4_THREAD_DEPTH_MM = 6.0 M4_THREAD_HOLE_CENTER_MM = (-6.104359972902419, -13.137483558259564) M4_THREAD_HOLE_FACE_Z_MM = THICKNESS_MM M4_THREAD_HOLE_DIRECTION = (0.0, 0.0, -1.0) VIEWER_PATTERN_CENTER_MM = (8.077088362294017, 15.744119598589815) VIEWER_PATTERN_HOLE_DIAMETER_MM = 2.0 VIEWER_PATTERN_ROWS = 2 VIEWER_PATTERN_COLUMNS = 2 VIEWER_PATTERN_PITCH_X_MM = 8.0 VIEWER_PATTERN_PITCH_Y_MM = 8.0 VIEWER_PATTERN_FACE_Z_MM = THICKNESS_MM VIEWER_PATTERN_DIRECTION = (0.0, 0.0, -1.0) VIEWER_COUNTERSINK_CENTER_MM = (-14.6034432889167, -4.110394299469192) VIEWER_COUNTERSINK_HOLE_DIAMETER_MM = 3.0 VIEWER_COUNTERSINK_DIAMETER_MM = 6.0 VIEWER_COUNTERSINK_ANGLE_DEG = 90.0 VIEWER_COUNTERSINK_FACE_Z_MM = THICKNESS_MM VIEWER_COUNTERSINK_DIRECTION = (0.0, 0.0, -1.0) VIEWER_POCKET_CENTER_MM = (6.197199513379157, -14.374353062530322) VIEWER_POCKET_WIDTH_MM = 10.0 VIEWER_POCKET_HEIGHT_MM = 6.0 VIEWER_POCKET_DEPTH_MM = 1.0 VIEWER_POCKET_FACE_Z_MM = THICKNESS_MM VIEWER_POCKET_DIRECTION = (0.0, 0.0, -1.0) def polar_point(radius: float, angle_degrees: float) -> tuple[float, float]: angle = radians(angle_degrees) return radius * cos(angle), radius * sin(angle) def gen_step(): """Return one STEP-ready flange solid in millimeters.""" with BuildPart() as flange: Cylinder( radius=OUTER_DIAMETER_MM / 2.0, height=THICKNESS_MM, align=(Align.CENTER, Align.CENTER, Align.MIN), ) with Locations(Location((0.0, 0.0, -1.0))): Cylinder( radius=INNER_DIAMETER_MM / 2.0, height=THICKNESS_MM + 2.0, align=(Align.CENTER, Align.CENTER, Align.MIN), mode=Mode.SUBTRACT, ) for index in range(BOLT_HOLE_COUNT): angle_degrees = 360.0 * index / BOLT_HOLE_COUNT x_pos, y_pos = polar_point(BOLT_CIRCLE_DIAMETER_MM / 2.0, angle_degrees) with Locations(Location((x_pos, y_pos, -1.0))): Cylinder( radius=M3_CLEARANCE_DIAMETER_MM / 2.0, height=THICKNESS_MM + 2.0, align=(Align.CENTER, Align.CENTER, Align.MIN), mode=Mode.SUBTRACT, ) m4_x_pos, m4_y_pos = M4_THREAD_HOLE_CENTER_MM m4_cut_depth = min(M4_THREAD_DEPTH_MM, THICKNESS_MM) with Locations(Location((m4_x_pos, m4_y_pos, M4_THREAD_HOLE_FACE_Z_MM - m4_cut_depth))): Cylinder( radius=M4_TAP_DRILL_DIAMETER_MM / 2.0, height=m4_cut_depth + 1.0, align=(Align.CENTER, Align.CENTER, Align.MIN), mode=Mode.SUBTRACT, ) pattern_center_x, pattern_center_y = VIEWER_PATTERN_CENTER_MM pattern_start_x = pattern_center_x - (VIEWER_PATTERN_COLUMNS - 1) * VIEWER_PATTERN_PITCH_X_MM / 2.0 pattern_start_y = pattern_center_y - (VIEWER_PATTERN_ROWS - 1) * VIEWER_PATTERN_PITCH_Y_MM / 2.0 for row_index in range(VIEWER_PATTERN_ROWS): for column_index in range(VIEWER_PATTERN_COLUMNS): hole_x = pattern_start_x + column_index * VIEWER_PATTERN_PITCH_X_MM hole_y = pattern_start_y + row_index * VIEWER_PATTERN_PITCH_Y_MM with Locations(Location((hole_x, hole_y, -1.0))): Cylinder( radius=VIEWER_PATTERN_HOLE_DIAMETER_MM / 2.0, height=THICKNESS_MM + 2.0, align=(Align.CENTER, Align.CENTER, Align.MIN), mode=Mode.SUBTRACT, ) countersink_x, countersink_y = VIEWER_COUNTERSINK_CENTER_MM countersink_radius = VIEWER_COUNTERSINK_DIAMETER_MM / 2.0 countersink_through_radius = VIEWER_COUNTERSINK_HOLE_DIAMETER_MM / 2.0 countersink_depth = ( countersink_radius - countersink_through_radius ) / tan(radians(VIEWER_COUNTERSINK_ANGLE_DEG / 2.0)) with Locations(Location((countersink_x, countersink_y, -1.0))): Cylinder( radius=countersink_through_radius, height=THICKNESS_MM + 2.0, align=(Align.CENTER, Align.CENTER, Align.MIN), mode=Mode.SUBTRACT, ) with Locations( Location((countersink_x, countersink_y, VIEWER_COUNTERSINK_FACE_Z_MM - countersink_depth)) ): Cone( countersink_through_radius, countersink_radius, countersink_depth + 0.05, align=(Align.CENTER, Align.CENTER, Align.MIN), mode=Mode.SUBTRACT, ) pocket_x, pocket_y = VIEWER_POCKET_CENTER_MM with Locations(Location((pocket_x, pocket_y, VIEWER_POCKET_FACE_Z_MM - VIEWER_POCKET_DEPTH_MM))): Box( VIEWER_POCKET_WIDTH_MM, VIEWER_POCKET_HEIGHT_MM, VIEWER_POCKET_DEPTH_MM + 0.05, align=(Align.CENTER, Align.CENTER, Align.MIN), mode=Mode.SUBTRACT, ) part = flange.part part.label = "flange_8x_m3_clearance_with_m4_tapped_hole_viewer_pattern_countersink_and_pocket" return part