diff --git a/nhf/materials.py b/nhf/materials.py index 4716e03..09d9ad6 100644 --- a/nhf/materials.py +++ b/nhf/materials.py @@ -90,6 +90,7 @@ class Material(Enum): ACRYLIC_TRANSLUSCENT = 1.18, _color('ivory2', 0.8) ACRYLIC_TRANSPARENT = 1.18, _color('ghostwhite', 0.5) STEEL_SPRING = 7.8, _color('gray', 0.8) + STEEL_STAINLESS = 7.8, _color('gray', 0.9) METAL_AL = 2.7, _color('gray', 0.6) METAL_BRASS = 8.5, _color('gold1', 0.8) diff --git a/nhf/touhou/yasaka_kanako/onbashira.py b/nhf/touhou/yasaka_kanako/onbashira.py index 556cdd9..3ed6b86 100644 --- a/nhf/touhou/yasaka_kanako/onbashira.py +++ b/nhf/touhou/yasaka_kanako/onbashira.py @@ -68,21 +68,22 @@ class Onbashira(Model): section1_gohei_loc: float = 30.0 gohei_bolt_diam: float = 6.0 - # Joints between two sets of side panels + # The angle joint bridges between two sets of side panels. + + # Extra thickness beyond the onbashira's body angle_joint_thickness: float = 10.0 # Z-axis size of each angle joint angle_joint_depth: float = 50.0 # Gap of each angle joint to connect the outside to the inside angle_joint_gap: float = 8.0 angle_joint_bolt_length: float = 50.0 - angle_joint_bolt_diam: float = 6.0 + angle_joint_bolt_diam: float = BOLT_COMMON.diam_thread angle_joint_bolt_head_diam: float = 13.0 angle_joint_bolt_head_depth: float = 3.0 # Position of the holes, with (0, 0) being the centre of each side angle_joint_bolt_position: list[float] = field(default_factory=lambda: [ (40, 10), ]) - angle_joint_flange_thickness: float = 7.8 angle_joint_flange_radius: float = 23.0 angle_joint_conn_thickness: float = 4.0 angle_joint_conn_depth: float = 15.0 @@ -110,7 +111,7 @@ class Onbashira(Model): bearing_disk_thickness: float = 25.4 / 8 rotor_inner_radius: float = 40.0 - rotor_bind_bolt_diam: float = 6.0 + rotor_bind_bolt_diam: float = BOLT_COMMON.diam_thread rotor_bind_radius: float = 78.0 rotor_spacer_outer_diam: float = 15.0 stator_bind_radius: float = 135.0 @@ -126,6 +127,7 @@ class Onbashira(Model): material_bearing_ball: Material = Material.ACRYLIC_TRANSPARENT material_barrel: Material = Material.ACRYLIC_BLACK material_brace: Material = Material.PLASTIC_PLA + material_fastener: Material = Material.STEEL_STAINLESS def __post_init__(self): assert self.n_side >= 3 @@ -320,6 +322,9 @@ class Onbashira(Model): return outer - inner def assembly_barrel(self) -> Cq.Assembly: + """ + The assembly with gun barrels + """ z_lower = -self.bearing_disk_gap/2 - self.bearing_disk_thickness a = ( Cq.Assembly() @@ -611,6 +616,34 @@ class Onbashira(Model): return result + @target(name="chamber-back", kind=TargetKind.DXF) + def profile_chamber_back(self) -> Cq.Sketch: + return ( + Cq.Sketch() + .regularPolygon(self.side_width - self.side_thickness, self.n_side) + .reset() + .regularPolygon( + self.stator_bind_radius, self.n_side, + mode="c", tag="bolt") + .vertices(tag="bolt") + .circle(self.rotor_bind_bolt_diam/2, mode="s") + ) + def chamber_back(self) -> Cq.Workplane: + sketch = self.profile_chamber_back() + result = ( + Cq.Workplane() + .placeSketch(sketch) + .extrude(self.side_thickness) + ) + # Mark all attachment points + for i in range(self.n_side): + angle = (i+0.5) * math.radians(360 / self.n_side) + x = self.stator_bind_radius * math.cos(angle) + y = self.stator_bind_radius * math.sin(angle) + result.tagAbsolute(f"holeF{i}", (x, y, self.side_thickness), direction="+Z") + result.tagAbsolute(f"holeB{i}", (x, -y, 0), direction="-Z") + return result + def assembly_chamber(self) -> Cq.Assembly: a = Cq.Assembly() side = self.chamber_side_panel() @@ -761,11 +794,11 @@ class Onbashira(Model): .reset() .regularPolygon(self.side_width_inner, self.n_side, mode="i") .finalize() - .extrude(self.angle_joint_flange_thickness) - .translate((0, 0, -self.angle_joint_flange_thickness/2)) + .extrude(self.angle_joint_gap) + .translate((0, 0, -self.angle_joint_gap/2)) ) ri = self.stator_bind_radius - h = self.angle_joint_flange_thickness + h = self.angle_joint_gap cyl = Cq.Solid.makeCylinder( radius=self.rotor_bind_bolt_diam/2, height=h, @@ -899,19 +932,19 @@ class Onbashira(Model): .reset() .regularPolygon(self.side_width_inner, self.n_side, mode="i") .finalize() - .extrude(self.angle_joint_flange_thickness) + .extrude(self.angle_joint_gap) .translate((0, 0, -flange_z)) ) ri = self.stator_bind_radius - h = self.angle_joint_flange_thickness + h = self.angle_joint_gap cyl = Cq.Solid.makeCylinder( radius=self.rotor_bind_bolt_diam/2, height=h, pnt=(ri * math.cos(th), ri * math.sin(th), -flange_z), ) result = result + flange - cyl - result.tagAbsolute("holeStatorL", (ri * math.cos(th), ri * math.sin(th), -flange_z+h/2), direction="+Z") - result.tagAbsolute("holeStatorR", (ri * math.cos(th), ri * math.sin(th), -flange_z-h/2), direction="-Z") + result.tagAbsolute("holeStatorO", (ri * math.cos(th), ri * math.sin(th), -flange_z), direction="-Z") + result.tagAbsolute("holeStatorI", (ri * math.cos(th), ri * math.sin(th), -flange_z+h), direction="+Z") return result @target(name="angle-joint") @@ -1044,11 +1077,11 @@ class Onbashira(Model): .reset() .regularPolygon(self.side_width_inner, self.n_side, mode="i") .finalize() - .extrude(self.angle_joint_flange_thickness) - .translate((0, 0, -self.angle_joint_flange_thickness/2)) + .extrude(self.angle_joint_gap) + .translate((0, 0, -self.angle_joint_gap/2)) ) ri = self.stator_bind_radius - h = self.angle_joint_flange_thickness + h = self.angle_joint_gap cyl = Cq.Solid.makeCylinder( radius=self.rotor_bind_bolt_diam/2, height=h, @@ -1135,7 +1168,7 @@ class Onbashira(Model): ) .add( self.assembly_ring(self.angle_joint_chamber_front()), - name="chamber_front", + name="ring3", ) .add( self.assembly_chamber(), @@ -1143,32 +1176,52 @@ class Onbashira(Model): ) .add( self.assembly_ring(self.angle_joint_chamber_back()), - name="chamber_back", + name="ring4", ) - .add(self.assembly_barrel(), name="barrel") + .addS( + self.chamber_back(), + name="chamber_back", + material=self.material_side, + role=Role.STRUCTURE | Role.DECORATION, + ) + #.add(self.assembly_barrel(), name="barrel") ) for i in range(self.n_side): j = (i + 1) % self.n_side for ih in range(len(self.angle_joint_bolt_position)): a = a.constrain( f"chamber/side{i}?holeFPI{ih}", - f"chamber_front/side{i}?holeRSO{ih}", + f"ring3/side{i}?holeRSO{ih}", "Plane", ) a = a.constrain( f"chamber/side{i}?holeBPI{ih}", - f"chamber_back/side{i}?holeLSO{ih}", + f"ring4/side{i}?holeLSO{ih}", "Plane", ) a = a.constrain( - f"barrel/stator2?holeB{i}", - f"ring1/side{i}?holeStatorR", + f"ring4/side{i}?holeStatorO", + f"chamber_back?holeB{i}", "Plane", ) + + name_bolt =f"chamber_back{i}boltFPI{ih}" + a = a.addS( + BOLT_COMMON.generate(), + name=name_bolt, + material=self.material_fastener, + role=Role.CONNECTION, + ) + a = a.constrain( + f"chamber_back?holeF{i}", + f"{name_bolt}?root", + "Plane", + param=0, + ) for (nl, nc, nr) in [ ("section1", "ring1", "section2"), ("section2", "ring2", "section3"), - ("section3", "chamber_front", None), + ("section3", "ring3", None), ]: a = a.constrain( f"{nl}/side{i}?holeBSO{ih}",