diff --git a/nhf/parts/joints.py b/nhf/parts/joints.py index 594c2cb..f80b1b6 100644 --- a/nhf/parts/joints.py +++ b/nhf/parts/joints.py @@ -36,6 +36,10 @@ class HirthJoint: def total_height(self): return self.base_height + self.tooth_height + @property + def joint_height(self): + return 2 * self.base_height + self.tooth_height + def generate(self, is_mated=False, tol=0.01): """ diff --git a/nhf/touhou/houjuu_nue/__init__.py b/nhf/touhou/houjuu_nue/__init__.py index 1dabd04..4602be3 100644 --- a/nhf/touhou/houjuu_nue/__init__.py +++ b/nhf/touhou/houjuu_nue/__init__.py @@ -49,14 +49,6 @@ class Parameters(Model): # Harness harness: MH.Harness = field(default_factory=lambda: MH.Harness()) - hs_hirth_joint: HirthJoint = field(default_factory=lambda: HirthJoint( - radius=30, - radius_inner=20, - tooth_height=10, - base_height=5, - n_tooth=24 - )) - wing_r1: MW.WingR = field(default_factory=lambda: MW.WingR(name="r1")) wing_r2: MW.WingR = field(default_factory=lambda: MW.WingR(name="r2")) wing_r3: MW.WingR = field(default_factory=lambda: MW.WingR(name="r3")) @@ -77,10 +69,19 @@ class Parameters(Model): def __post_init__(self): super().__init__(name="houjuu-nue") - self.harness.hs_hirth_joint = self.hs_hirth_joint - self.wing_r1.base_joint = self.hs_hirth_joint - self.wing_r2.base_joint = self.hs_hirth_joint - self.wing_r3.base_joint = self.hs_hirth_joint + self.wing_r1.base_joint = self.harness.hs_hirth_joint + self.wing_r2.base_joint = self.harness.hs_hirth_joint + self.wing_r3.base_joint = self.harness.hs_hirth_joint + self.wing_l1.base_joint = self.harness.hs_hirth_joint + self.wing_l2.base_joint = self.harness.hs_hirth_joint + self.wing_l3.base_joint = self.harness.hs_hirth_joint + + assert self.wing_r1.hs_joint_axis_diam == self.harness.hs_joint_axis_diam + assert self.wing_r2.hs_joint_axis_diam == self.harness.hs_joint_axis_diam + assert self.wing_r3.hs_joint_axis_diam == self.harness.hs_joint_axis_diam + assert self.wing_l1.hs_joint_axis_diam == self.harness.hs_joint_axis_diam + assert self.wing_l2.hs_joint_axis_diam == self.harness.hs_joint_axis_diam + assert self.wing_l3.hs_joint_axis_diam == self.harness.hs_joint_axis_diam @submodel(name="harness") def submodel_harness(self) -> Model: @@ -120,12 +121,12 @@ class Parameters(Model): .add(self.wing_l2.assembly(parts), name="wing_l2") .add(self.wing_l3.assembly(parts), name="wing_l3") ) - self.hs_hirth_joint.add_constraints(result, "harness/r1", "wing_r1/s0/hs", offset=11) - self.hs_hirth_joint.add_constraints(result, "harness/r2", "wing_r2/s0/hs", offset=10) - self.hs_hirth_joint.add_constraints(result, "harness/r3", "wing_r3/s0/hs", offset=9) - self.hs_hirth_joint.add_constraints(result, "harness/l1", "wing_l1/s0/hs", offset=6) - self.hs_hirth_joint.add_constraints(result, "harness/l2", "wing_l2/s0/hs", offset=7) - self.hs_hirth_joint.add_constraints(result, "harness/l3", "wing_l3/s0/hs", offset=8) + for tag, offset in [("r1", 10), ("r2", 8), ("r3", 6), ("l1", 6), ("l2", 7), ("l3", 8)]: + self.harness.hs_hirth_joint.add_constraints( + result, + f"harness/{tag}", + f"wing_{tag}/s0/hs", + offset=offset) return result.solve() @submodel(name="trident") diff --git a/nhf/touhou/houjuu_nue/harness.py b/nhf/touhou/houjuu_nue/harness.py index d5a35cb..a6f4243 100644 --- a/nhf/touhou/houjuu_nue/harness.py +++ b/nhf/touhou/houjuu_nue/harness.py @@ -8,26 +8,27 @@ import nhf.utils @dataclass class Harness(Model): thickness: float = 25.4 / 8 - width: float = 300.0 - height: float = 400.0 + width: float = 200.0 + height: float = 300.0 fillet: float = 10.0 wing_base_pos: list[tuple[str, float, float]] = field(default_factory=lambda: [ - ("r1", 70, 150), - ("l1", -70, 150), - ("r2", 100, 0), - ("l2", -100, 0), - ("r3", 70, -150), - ("l3", -70, -150), + ("r1", 55, 90), + ("l1", -55, 90), + ("r2", 60, 0), + ("l2", -60, 0), + ("r3", 55, -90), + ("l3", -55, -90), ]) # Holes drilled onto harness for attachment with HS joint harness_to_root_conn_diam: float = 6 hs_hirth_joint: HirthJoint = field(default_factory=lambda: HirthJoint( - radius=30, - radius_inner=20, - tooth_height=10, - base_height=5 + radius=25.0, + radius_inner=20.0, + tooth_height=7.0, + base_height=5.0, + n_tooth=24, )) hs_joint_base_width: float = 85 @@ -37,7 +38,7 @@ class Harness(Model): hs_joint_corner_cbore_depth: float = 2 hs_joint_corner_inset: float = 12 - hs_joint_axis_diam: float = 12 + hs_joint_axis_diam: float = 12.0 hs_joint_axis_cbore_diam: float = 20 hs_joint_axis_cbore_depth: float = 3 @@ -53,12 +54,16 @@ class Harness(Model): sketch = ( Cq.Sketch() .polygon([ - (0.7 * w, h), - (w, 0), - (0.7 * w, -h), - (0.7 * -w, -h), - (-w, 0), - (0.7 * -w, h), + (w, h), + (w, -h), + (-w, -h), + (-w, h), + #(0.7 * w, h), + #(w, 0), + #(0.7 * w, -h), + #(0.7 * -w, -h), + #(-w, 0), + #(0.7 * -w, h), ]) #.rect(self.harness_width, self.harness_height) .vertices() diff --git a/nhf/touhou/houjuu_nue/wing.py b/nhf/touhou/houjuu_nue/wing.py index 26f07a6..16a23da 100644 --- a/nhf/touhou/houjuu_nue/wing.py +++ b/nhf/touhou/houjuu_nue/wing.py @@ -20,12 +20,18 @@ class WingProfile(Model): name: str = "wing" base_joint: HirthJoint = field(default_factory=lambda: HirthJoint( - radius=30.0, + radius=25.0, radius_inner=20.0, + tooth_height=7.0, + base_height=5, + n_tooth=24, )) - root_width: float = 80.0 - hs_joint_corner_dx: float = 30.0 + base_width: float = 80.0 + hs_joint_corner_dx: float = 17.0 + hs_joint_corner_dz: float = 24.0 hs_joint_corner_hole_diam: float = 6.0 + hs_joint_axis_diam: float = 12.0 + base_plate_width: float = 50.0 panel_thickness: float = 25.4 / 16 spacer_thickness: float = 25.4 / 8 @@ -36,6 +42,8 @@ class WingProfile(Model): shoulder_width: float = 30.0 shoulder_tip_x: float = -200.0 shoulder_tip_y: float = 160.0 + shoulder_mid_x: float = -105.0 + shoulder_mid_y: float = 75.0 s1_thickness: float = 25.0 @@ -94,13 +102,64 @@ class WingProfile(Model): def shoulder_height(self) -> float: return self.shoulder_joint.height + @target(name="base-hs-joint") + def base_hs_joint(self) -> Cq.Workplane: + """ + Parent part of the Houjuu-Scarlett joint, which is composed of a Hirth + coupling, a cylindrical base, and a mounting base. + """ + hirth = self.base_joint.generate(is_mated=True) + dy = self.hs_joint_corner_dx + dx = self.hs_joint_corner_dz + conn = [ + (-dx, -dy), + (dx, -dy), + (dx, dy), + (-dx, dy), + ] + result = ( + Cq.Workplane('XY') + .box( + self.root_height, + self.base_plate_width, + self.base_joint.base_height, + centered=(True, True, False)) + #.translate((0, 0, -self.base_joint.base_height)) + #.edges("|Z") + #.fillet(self.hs_joint_corner_fillet) + .faces(">Z") + .workplane() + .pushPoints(conn) + .hole(self.hs_joint_corner_hole_diam) + ) + # Creates a plane parallel to the holes but shifted to the base + plane = result.faces(">Z").workplane(offset=-self.base_joint.base_height) + + for i, (px, py) in enumerate(conn): + plane.moveTo(px, py).tagPlane(f"conn{i}") + result = ( + result + .faces(">Z") + .workplane() + .union(hirth, tol=0.1) + .clean() + ) + result = ( + result.faces(" Cq.Sketch: tip_x = self.shoulder_tip_x tip_y = self.shoulder_tip_y + mid_x = self.shoulder_mid_x + mid_y = self.shoulder_mid_y sketch = ( Cq.Sketch() - .segment((-self.root_width, 0), (0, 0)) + .segment((-self.base_width, 0), (0, 0)) .spline([ (0, 0), (-30.0, 80.0), @@ -108,16 +167,42 @@ class WingProfile(Model): ]) .segment( (tip_x, tip_y), - (tip_x, tip_y - self.shoulder_width) + (tip_x, tip_y - self.shoulder_width), ) .segment( (tip_x, tip_y - self.shoulder_width), - (-self.root_width, 0) + (mid_x, mid_y), + ) + .segment( + (mid_x, mid_y), + (-self.base_width, 0), ) .assemble() ) return sketch + def outer_shell_s0(self) -> Cq.Workplane: + tip_x = self.shoulder_tip_x + tip_y = self.shoulder_tip_y + t = self.panel_thickness + edge = Cq.Edge.makeSpline([ + Cq.Vector(x, y, 0) + for x,y in [ + (0, 0), + (-30.0, 80.0), + (tip_x, tip_y) + ] + ]) + result = ( + Cq.Workplane('XZ') + .rect(t, self.root_height + t*2, centered=(False, False)) + .sweep(edge) + ) + plane = result.copyWorkplane(Cq.Workplane('XZ')) + plane.moveTo(0, 0).tagPlane("bot") + plane.moveTo(0, self.root_height + t*2).tagPlane("top") + return result + @submodel(name="spacer-s0-shoulder") def spacer_s0_shoulder(self) -> MountingBox: """ @@ -145,16 +230,20 @@ class WingProfile(Model): """ Should be cut """ - dx = self.hs_joint_corner_dx + assert self.base_plate_width < self.base_width + assert self.hs_joint_corner_dx * 2 < self.base_width + assert self.hs_joint_corner_dz * 2 < self.root_height + dy = self.hs_joint_corner_dx + dx = self.hs_joint_corner_dz holes = [ - Hole(x=-dx, y=-dx), - Hole(x=dx, y=-dx), - Hole(x=dx, y=dx), - Hole(x=-dx, y=dx), + Hole(x=-dx, y=-dy), + Hole(x=dx, y=-dy), + Hole(x=dx, y=dy), + Hole(x=-dx, y=dy), ] return MountingBox( length=self.root_height, - width=self.root_width, + width=self.base_plate_width, thickness=self.spacer_thickness, holes=holes, hole_diam=self.hs_joint_corner_hole_diam, @@ -163,16 +252,21 @@ class WingProfile(Model): ) def surface_s0(self, top: bool = False) -> Cq.Workplane: + base_dx = -(self.base_width - self.base_plate_width) / 2 + base_dy = self.base_joint.joint_height tags = [ ("shoulder", (self.shoulder_tip_x, self.shoulder_tip_y - self.shoulder_width), 0), - ("base", (0, 0), 90), + ("base", (base_dx, base_dy), 90), ] - return nhf.utils.extrude_with_markers( + result = nhf.utils.extrude_with_markers( self.profile_s0(), self.panel_thickness, tags, reverse=not top, ) + h = self.panel_thickness if top else 0 + result.copyWorkplane(Cq.Workplane('XZ')).moveTo(0, h).tagPlane("corner") + return result @assembly() def assembly_s0(self) -> Cq.Assembly: @@ -184,6 +278,10 @@ class WingProfile(Model): material=self.mat_panel, role=self.role_panel) .constrain("bot@faces@>Z", "top@faces@