diff --git a/nhf/touhou/houjuu_nue/wing.py b/nhf/touhou/houjuu_nue/wing.py index bc1c690..69cadaa 100644 --- a/nhf/touhou/houjuu_nue/wing.py +++ b/nhf/touhou/houjuu_nue/wing.py @@ -36,8 +36,10 @@ class WingProfile(Model): shoulder_width: float = 36.0 shoulder_tip_x: float = -260.0 shoulder_tip_y: float = 165.0 - shoulder_mid_x: float = -125.0 - shoulder_mid_y: float = 75.0 + shoulder_tip_bezier_x: float = 100.0 + shoulder_tip_bezier_y: float = -50.0 + shoulder_base_bezier_x: float = -30.0 + shoulder_base_bezier_y: float = 30.0 s0_hole_loc: Cq.Location = Cq.Location.from2d(-25, 33) s0_hole_diam: float = 15.0 @@ -153,8 +155,7 @@ class WingProfile(Model): def outer_profile_s0(self) -> Cq.Sketch: """ - The outer boundary of s0, used to produce the curved panel and the - top/bottom slots + The outer boundary of s0 top/bottom slots """ tip_x = self.shoulder_tip_x tip_y = self.shoulder_tip_y @@ -170,15 +171,35 @@ class WingProfile(Model): # (tip_x - 10, tip_y), #) ) + def inner_profile_s0(self) -> Cq.Edge: + """ + The inner boundary of s0 + """ + tip_x = self.shoulder_tip_x + tip_y = self.shoulder_tip_y + dx2 = self.shoulder_tip_bezier_x + dy2 = self.shoulder_tip_bezier_y + dx1 = self.shoulder_base_bezier_x + dy1 = self.shoulder_base_bezier_y + sw = self.shoulder_width + return Cq.Edge.makeBezier( + [ + Cq.Vector(*p) + for p in [ + (tip_x, tip_y - sw), + (tip_x + dx2, tip_y - sw + dy2), + (-self.base_width + dx1, dy1), + (-self.base_width, 0), + ] + ] + ) @property def shoulder_angle_neutral(self) -> float: """ Returns the neutral angle of the shoulder """ - dx = self.shoulder_mid_x - self.shoulder_tip_x - dy = -(self.shoulder_mid_y - (self.shoulder_tip_y - self.shoulder_width)) - result = math.degrees(math.atan2(dy, dx)) + result = math.degrees(math.atan2(-self.shoulder_tip_bezier_y, self.shoulder_tip_bezier_x)) assert result >= 0 return result @@ -186,8 +207,10 @@ class WingProfile(Model): def profile_s0(self, top: bool = True) -> 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 + dx2 = self.shoulder_tip_bezier_x + dy2 = self.shoulder_tip_bezier_y + dx1 = self.shoulder_base_bezier_x + dy1 = self.shoulder_base_bezier_y sw = self.shoulder_width sketch = ( self.outer_profile_s0() @@ -196,14 +219,12 @@ class WingProfile(Model): (tip_x, tip_y), (tip_x, tip_y - sw), ) - .segment( + .bezier([ (tip_x, tip_y - sw), - (mid_x, mid_y), - ) - .segment( - (mid_x, mid_y), + (tip_x + dx2, tip_y - sw + dy2), + (-self.base_width + dx1, dy1), (-self.base_width, 0), - ) + ]) .assemble() .push([self.shoulder_axle_loc.to2d_pos()]) .circle(self.shoulder_joint.radius, mode='a') @@ -231,6 +252,18 @@ class WingProfile(Model): plane.moveTo(0, 0).tagPlane("bot") plane.moveTo(0, self.root_height + t*2).tagPlane("top") return result + def inner_shell_s0(self) -> Cq.Workplane: + t = self.panel_thickness + #profile = Cq.Wire.assembleEdges(self.inner_profile_s0()) + result = ( + Cq.Workplane('XZ') + .rect(t, self.root_height + t*2, centered=(False, False)) + .sweep(self.inner_profile_s0()) + ) + plane = result.copyWorkplane(Cq.Workplane('XZ')) + plane.moveTo(t, 0).tagPlane("bot") + plane.moveTo(t, self.root_height + t*2).tagPlane("top") + return result @submodel(name="spacer-s0-shoulder") def spacer_s0_shoulder(self) -> MountingBox: @@ -318,6 +351,7 @@ class WingProfile(Model): ) h = self.panel_thickness if top else 0 result.copyWorkplane(Cq.Workplane('XZ')).moveTo(0, h).tagPlane("corner") + result.copyWorkplane(Cq.Workplane('XZ')).moveTo(-self.base_width, h).tagPlane("corner_left") return result @assembly() @@ -331,12 +365,16 @@ class WingProfile(Model): loc=Cq.Location((0, 0, self.root_height + self.panel_thickness))) .constrain("bot", "Fixed") .constrain("top", "Fixed") - #.constrain("bot@faces@>Z", "top@faces@Z", "top@faces@