def asm_data(): """ provides a tuple of assembly and corresponding shape (generated explicitly) """ n = 3 y_spacing = 2.5 s = data.bin_counter(0).extruded(0.1) row_parts = [s.make_part("shape_0").translated_x(0.5)] row_shapes = [s.translated_x(0.5)] for i in range(1, n + 1): s = data.bin_counter(i).extruded(0.1) row_parts.append( codecad.assembly( "row_{}".format(i), [ row_parts[-1], s.make_part("shape_{}".format(i)).translated_x(0.5 + 2 * i), ], ) ) row_shapes.append(row_shapes[-1] + s.translated_x(0.5 + 2 * i)) assembly = codecad.assembly( "test_assembly", [row.translated_y(i * y_spacing) for i, row in enumerate(row_parts)], ) shape = codecad.shapes.union( [row.translated_y(i * y_spacing) for i, row in enumerate(row_shapes)] ) assembly = assembly.rotated_x(90) shape = shape.rotated_x(90) return n, assembly, shape
def asm_data(): """ provides a tuple of assembly and corresponding shape (generated explicitly) """ n = 3 y_spacing = 2.5 s = data.bin_counter(0).extruded(0.1) row_parts = [s.make_part("shape_0").translated_x(0.5)] row_shapes = [s.translated_x(0.5)] for i in range(1, n + 1): s = data.bin_counter(i).extruded(0.1) row_parts.append( codecad.assembly( "row_{}".format(i), [ row_parts[-1], s.make_part( "shape_{}".format(i)).translated_x(0.5 + 2 * i), ], )) row_shapes.append(row_shapes[-1] + s.translated_x(0.5 + 2 * i)) assembly = codecad.assembly( "test_assembly", [row.translated_y(i * y_spacing) for i, row in enumerate(row_parts)], ) shape = codecad.shapes.union( [row.translated_y(i * y_spacing) for i, row in enumerate(row_shapes)]) assembly = assembly.rotated_x(90) shape = shape.rotated_x(90) return n, assembly, shape
def test_visible_bom(): o = codecad.shapes.sphere() asm = codecad.assembly( "test", [o.make_part("1"), o.make_part("2").hidden()]) assert len(list(asm.bom())) == 2 assert len(list(asm.bom(visible_only=True))) == 1
def suspension_generator(right, arm_angle=arm_neutral_angle, bogie_angle_fraction=None): spring_point = get_spring_point(spring_arm_length, arm_up_angle - arm_angle) v = spring_point.flattened() - spring_anchor_point.flattened() length = abs(v) spring_degrees = 90 - math.degrees(math.atan2(v.y, v.x)) spring = vitamins.spring(length) degrees = -math.degrees(arm_angle) if bogie_angle_fraction is None: bogie_degrees = 0 else: low = -bogie_swing_angle + (arm_angle - arm_neutral_angle) high = bogie_swing_angle + (arm_angle - arm_neutral_angle) bogie_degrees = low + (high - low) * bogie_angle_fraction bogie_degrees = math.degrees(bogie_degrees) if right: arm = arm_right bogie = bogie_assembly.rotated_z(180) multiplier = 1 else: arm = arm_left.rotated_y(180) bogie = bogie_assembly multiplier = -1 asm = codecad.assembly("suspension_assembly_" + ("right" if right else "left"), [arm \ .rotated_x(90) \ .rotated_y(degrees) \ .translated_y(multiplier * arm_base_offset), bogie \ .translated_z(-bogie_pivot_z - wheel_diameter / 2) \ .rotated_y(-degrees - bogie_degrees) \ .translated_x(arm_length) \ .rotated_y(degrees) \ .translated_y(multiplier * track_offset.y), spring \ .rotated_y(spring_degrees) \ .translated(spring_anchor_point.x, multiplier * (spring_anchor_point.z + vitamins.spring.top_mount_thickness / 2), spring_anchor_point.y), road_wheel_screw, road_wheel_screw.lock_nut, spring_screw, spring_screw.lock_nut, vitamins.shoulder_screw, vitamins.shoulder_screw, vitamins.shoulder_screw.lock_nut, vitamins.shoulder_screw.lock_nut, vitamins.m5x20_screw, vitamins.m5x20_screw.lock_nut, ]) return asm
def track_row(n, modelled_n=1): parts = [] for i in range(modelled_n): dist = (i - n / 2 + 0.5) * (segment_length + connector_length) conn = track_connector \ .rotated_x(90) \ .translated(dist + (segment_length + connector_length) / 2, connector_width / 2, 0) parts.append(track_segment.translated_x(dist)) parts.append(conn) parts.append( conn.translated_y((width - connector_width - clearance) / 2)) parts.append( conn.translated_y(-(width - connector_width - clearance) / 2)) hidden_n = n - modelled_n parts.extend(track_segment.hidden() for i in range(hidden_n)) parts.extend(track_connector.hidden() for i in range(3 * hidden_n)) parts.extend(vitamins.nail for i in range(4 * n)) return codecad.assembly("track_assembly", parts)
def make_assembly(self): planet = (self.make_planet().make_part("planet").translated( self.planet_radius, 0, self.inner_carrier_half_length - self.sun_thickness, )) return codecad.assembly( "gearbox", [ self.make_carrier_inner().make_part("inner_carrier").rotated_x( 180).translated_z(self.inner_carrier_half_length), self.make_carrier_outer().make_part("outer_carrier").rotated_x( 180).translated_z(self.outer_carrier_length + self.inner_carrier_half_length), self.make_sun().make_part("sun_gear").translated_z( self.inner_carrier_half_length - self.bearing_wall_thickness - 2 * self.clearance - self.sun_thickness - self.motor_gear_thickness), self.make_ring().make_part("ring").rotated_x(180).translated_z( self.outer_carrier_length + self.inner_carrier_half_length + self.bearing_wall_thickness + self.clearance), ] + [ planet.rotated_z(i * 360 / self.planet_count) for i in range(self.planet_count) ], )
def test_shape_to_assembly(): shape = codecad.shapes.sphere() part = shape.make_part("sphere") asm = codecad.assembly("test_asm", [part]) instances = list(asm.all_instances()) assert len(instances) == 1 assert instances[0].part.data is shape
def tensioner_generator(right, arm_angle=(arm_angle_back + arm_angle_front) / 2): spring_point = Vector.polar( spring_arm_length, arm_angle + spring_angle_offset) + pivot_position v = spring_point.flattened() - spring_anchor_point.flattened() length = abs(v) spring_degrees = 90 - math.degrees(math.atan2(v.y, v.x)) spring = vitamins.spring(length) if right: arm = arm_right multiplier = 1 else: arm = arm_left.rotated_y(180) multiplier = -1 arm_angle = -arm_angle asm = codecad.assembly("tensioner_assembly_" + ("right" if right else "left"), [arm \ .rotated_x(-90) \ .rotated_y(180) \ .rotated_y(arm_angle) \ .translated(pivot_position.x, pivot_position.z, pivot_position.y), wheel_assembly \ .translated_y(-arm_width - wheel_clearance) \ .rotated_z(90 + 90 * multiplier) \ .translated_x(arm_length) \ .rotated_y(arm_angle) \ .translated(pivot_position.x, pivot_position.z, pivot_position.y), spring \ .rotated_y(spring_degrees) \ .translated(spring_anchor_point.x, multiplier * (spring_anchor_point.z + vitamins.spring.top_mount_thickness / 2), spring_anchor_point.y), wheel_screw, wheel_screw.lock_nut, spring_screw, spring_screw.lock_nut, vitamins.shoulder_screw, vitamins.shoulder_screw.lock_nut, vitamins.m5x20_screw, vitamins.m5x20_screw.lock_nut]) return asm
def make_assembly(self): planet = ( self.make_planet() .make_part("planet") .translated( self.planet_radius, 0, self.inner_carrier_half_length - self.sun_thickness, ) ) return codecad.assembly( "gearbox", [ self.make_carrier_inner() .make_part("inner_carrier") .rotated_x(180) .translated_z(self.inner_carrier_half_length), self.make_carrier_outer() .make_part("outer_carrier") .rotated_x(180) .translated_z( self.outer_carrier_length + self.inner_carrier_half_length ), self.make_sun() .make_part("sun_gear") .translated_z( self.inner_carrier_half_length - self.bearing_wall_thickness - 2 * self.clearance - self.sun_thickness - self.motor_gear_thickness ), self.make_ring() .make_part("ring") .rotated_x(180) .translated_z( self.outer_carrier_length + self.inner_carrier_half_length + self.bearing_wall_thickness + self.clearance ), ] + [ planet.rotated_z(i * 360 / self.planet_count) for i in range(self.planet_count) ], )
#!/usr/bin/env python3 import codecad import menger_sponge import cube_thingie import planetary import airfoil o = codecad.assembly( "benchmark_assembly", [ planetary.Planetary( 11, 60, 13, 41, 18, 53).make_overview().make_part("sliced_gearbox").translated_x(-50), cube_thingie.cube_with_base(menger_sponge.sponge(6)).make_part( "menger_sponge_statue").translated_x(50), airfoil.o.make_part("meshed_airfoil").translated(-120, 0, 100), ], ) if __name__ == "__main__": codecad.commandline_render(o)
arm_length, vitamins.shoulder_screw.head_diameter, vitamins.shoulder_screw.head_height - wheel_clearance, wheel_clearance, False) \ .make_part("outer_tensioner_wheel", ["3d_print"]) arm_left = arm_generator(arm_thickness, arm_pivot_thickness, arm_width, spring_screw.length - vitamins.spring.bottom_mount_thickness, arm_length, spring_arm_length, spring_angle_offset, inner_bearing_height + wheel_clearance, # cone height wheel_diameter, wheel_clearance, vitamins.shoulder_screw.diameter2 + pivot_round_clearance, wheel_bearing, wheel_screw, spring_screw) \ .make_part("tensioner_arm_left", ["3d_print"]) arm_right = arm_left.shape().mirrored_x().make_part("tensioner_arm_right", ["3d_print"]) wheel_assembly = codecad.assembly("tensioner_wheel_assembly", [ inner_wheel_half.rotated_x(90), outer_wheel_half.rotated_x(-90).translated_y(-suspension.wheel_width) ] + [wheel_bearing] * 2) def tensioner_generator(right, arm_angle=(arm_angle_back + arm_angle_front) / 2): spring_point = Vector.polar( spring_arm_length, arm_angle + spring_angle_offset) + pivot_position v = spring_point.flattened() - spring_anchor_point.flattened() length = abs(v) spring_degrees = 90 - math.degrees(math.atan2(v.y, v.x)) spring = vitamins.spring(length) if right:
Only has one face and one edge. """ import codecad from codecad.shapes import * minor_r = 15 major_r = 25 pin_d = 1.75 pin_h = 10 second_pin_angle = 170 # Not 180 degrees to have only one way to assemble mp = regular_polygon2d(5, r=minor_r).revolved(r=major_r, twist=360 / 5) pin_hole = cylinder(d=1.1 * pin_d, h=1.2 * pin_h).rotated_x(90).translated_x(major_r) mp -= pin_hole mp -= pin_hole.rotated_y(second_pin_angle) half1 = (mp & half_space()).rotated_x(90).make_part("half1") half2 = (mp - half_space()).rotated_x(-90).make_part("half2") pin = cylinder(d=pin_d, h=pin_h, symmetrical=False).make_part("pin") pin = pin.translated_z(-pin_h / 2).translated_x(major_r) asm = codecad.assembly( "moebius_pentagon", [half1, half2.rotated_x(180), pin, pin.rotated_z(second_pin_angle)], ) if __name__ == "__main__": codecad.commandline_render(asm)
def test_visible_bom(): o = codecad.shapes.sphere() asm = codecad.assembly("test", [o.make_part("1"), o.make_part("2").hidden()]) assert len(list(asm.bom())) == 2 assert len(list(asm.bom(visible_only=True))) == 1
arm_clearance, vitamins.shoulder_screw.diameter2 + pivot_round_clearance, 3 * parameters.extrusion_width, 6 * parameters.extrusion_width, parameters.layer_height, ).make_part("suspension_arm_right", ["3d_print"]) arm_left = arm_right.shape().mirrored_x().make_part("suspension_arm_left", ["3d_print"]) bogie_assembly = codecad.assembly( "bogie_assembly", [ bogie.translated_z(wheel_diameter / 2), inner_road_wheel.rotated_x(90).translated( bogie_wheel_spacing / 2, wheel_width / 2, wheel_diameter / 2), inner_road_wheel.rotated_x(90).translated( -bogie_wheel_spacing / 2, wheel_width / 2, wheel_diameter / 2), outer_road_wheel.rotated_x(-90).translated( bogie_wheel_spacing / 2, -wheel_width / 2, wheel_diameter / 2), outer_road_wheel.rotated_x(-90).translated( -bogie_wheel_spacing / 2, -wheel_width / 2, wheel_diameter / 2) ] + [vitamins.small_bearing] * 4 + [road_wheel_screw, road_wheel_screw.lock_nut] * 2 + [vitamins.o_ring] * 8) # Y offset of a right suspension arm base in an assembly. arm_base_offset = pivot_guide_length + pivot_screw_head_countersink # Ofset for matching a piece of track with right suspension assembly track_offset = Vector( arm_length * math.cos(arm_neutral_angle), arm_base_offset - arm_width / 2, arm_length * math.sin(arm_neutral_angle) - bogie_pivot_z - wheel_diameter / 2)
return shaft gear_shaft2_spline = tools.spline(20) shaft2 = shaft2_generator(drive_sprocket.spline, gear_shaft2_spline, 0.05, vitamins.large_bearing, (drive_sprocket.base.total_height + drive_sprocket.base.cone_height) / 2, vitamins.m3x35_screw.diameter, vitamins.m3x35_screw.length - drive_sprocket.center_screw_wall_thickness, vitamins.m3x35_screw.lock_nut.s, vitamins.m3x35_screw.lock_nut.height) \ .make_part("transmission_shaft2", ["3d_print"]) shaft2_assembly = codecad.assembly("shaft2_assembly", [ drive_sprocket.drive_sprocket_assembly, shaft2.rotated_x(90).translated_y(shaft2.part.data.length), vitamins.m3x35_screw, vitamins.m3x35_screw.lock_nut ]) if __name__ == "__main__": ratio = 1 for t1, t2 in transmission_steps: assert math.gcd(t1, t2) == 1 ratio *= t2 / t1 speed = (motor_max_rpm / 60) * drive_sprocket.circumference / ratio print( "transmission ratios", ", ".join("{}:{}".format(*teeth) for teeth in transmission_steps), "({:.1f}:1) -> {:.1f}m/s, {:.1f}km/h".format(ratio, speed / 1000, 3.6 * speed / 1000))
def test_shape_to_assembly_no_part(): """ Test converting the shape directly to an assembly without making a part of it first. This should fail. """ a = codecad.assembly("X", [codecad.shapes.sphere()]) with pytest.raises(Exception): a.shape()
import codecad import suspension import drive_sprocket layout = codecad.assembly("tank_layout_test_assembly", [ suspension.suspension_assembly_left.hidden(), suspension.suspension_assembly_left.translated_x( suspension.suspension_spacing).hidden(), suspension.suspension_assembly_left.translated_x( 2 * suspension.suspension_spacing), drive_sprocket.drive_sprocket_assembly.rotated_x(-90).translated_x( 2 * suspension.suspension_spacing + 145) ]) if __name__ == "__main__": codecad.commandline_render(layout)
#!/usr/bin/env python3 import codecad import menger_sponge import cube_thingie import planetary import airfoil o = codecad.assembly( "benchmark_assembly", [ planetary.Planetary(11, 60, 13, 41, 18, 53) .make_overview() .make_part("sliced_gearbox") .translated_x(-50), cube_thingie.cube_with_base(menger_sponge.sponge(6)) .make_part("menger_sponge_statue") .translated_x(50), airfoil.o.make_part("meshed_airfoil").translated(-120, 0, 100), ], ) if __name__ == "__main__": codecad.commandline_render(o)
track.base_thickness, track.connector_length, track.connector_thickness, track.connector_width, track.width, track.guide_width, track.guide_height, track.guide_side_angle, track.clearance) spline = tools.spline(bearing.id) inner_sprocket = inner_sprocket_generator(base, spline, 0.05, 0.1, # Crown tolerance bearing.shoulder_size, bearing_shoulder_height + wheel_clearance, bearing_housing_top_diameter + 2 * wheel_clearance) \ .make_part("inner_drive_sprocket", ["3d_print"]) outer_sprocket = outer_sprocket_generator(base, 0.1, # Crown tolerance vitamins.m3x35_screw, center_screw_wall_thickness, 3 * parameters.extrusion_width) \ .make_part("outer_drive_sprocket", ["3d_print"]) drive_sprocket_assembly = codecad.assembly("drive_sprocket_assembly", [ inner_sprocket.rotated_x(90).translated_y(track.width / 2), outer_sprocket.rotated_x(-90).translated_y(-track.width / 2) ]) if __name__ == "__main__": print("pitch radius", pitch_radius) codecad.commandline_render(drive_sprocket_assembly)