diff --git a/nhf/touhou/houjuu_nue/wing.py b/nhf/touhou/houjuu_nue/wing.py index 5f9daf9..ea3a5c3 100644 --- a/nhf/touhou/houjuu_nue/wing.py +++ b/nhf/touhou/houjuu_nue/wing.py @@ -10,8 +10,9 @@ from nhf.parts.joints import HirthJoint def wing_root_profiles( base_sweep=150, wall_thickness=8, - base_radius=60, + base_radius=40, middle_offset=30, + middle_height=80, conn_width=40, conn_height=100) -> tuple[Cq.Wire, Cq.Wire]: assert base_sweep < 180 @@ -72,7 +73,7 @@ def wing_root_profiles( # If the exterior sweep is theta', it has to satisfy # # sin(theta) * r2 + wall_thickness = sin(theta') * r1 - x, y = conn_width / 2, conn_height / 2 + x, y = conn_width / 2, middle_height / 2 t = wall_thickness dx = middle_offset middle = ( @@ -126,65 +127,86 @@ def wing_root_profiles( def wing_root(joint: HirthJoint, - bolt_diam: int = 12) -> Cq.Assembly: + bolt_diam: int = 12, + union_tol=1e-4, + attach_diam=8, + conn_width=40, + conn_height=100, + wall_thickness=8) -> Cq.Assembly: """ Generate the contiguous components of the root wing segment """ - root_profile, middle_profile, tip_profile = wing_root_profiles() + tip_centre = Cq.Vector((-150, 0, -80)) + attach_points = [ + (15, 0), + (40, 0), + ] + root_profile, middle_profile, tip_profile = wing_root_profiles( + conn_width=conn_width, + conn_height=conn_height, + wall_thickness=8, + ) + middle_profile = middle_profile.located(Cq.Location( + (-40, 0, -40), (0, 30, 0) + )) + antetip_profile = tip_profile.located(Cq.Location( + (-95, 0, -75), (0, 60, 0) + )) + tip_profile = tip_profile.located(Cq.Location( + tip_centre, (0, 90, 0) + )) + profiles = [ + root_profile, + middle_profile, + antetip_profile, + tip_profile, + ] + result = None + for p1, p2 in zip(profiles[:-1], profiles[1:]): + seg = ( + Cq.Workplane('XY') + .add(p1) + .toPending() + .workplane() # This call is necessary + .add(p2) + .toPending() + .loft() + ) + if result: + result = result.union(seg, tol=union_tol) + else: + result = seg + result = ( + result + # Create connector holes + .copyWorkplane( + Cq.Workplane('bottom', origin=tip_centre + Cq.Vector((0, -50, 0))) + ) + .pushPoints(attach_points) + .hole(attach_diam) + ) + # Generate attach point tags - rotate_centre = Cq.Vector(-200, 0, -25) - rotate_axis = Cq.Vector(0, 1, 0) - terminal_offset = Cq.Vector(-80, 0, 80) - terminal_rotate = Cq.Vector(0, -45, 0) + for sign in [False, True]: + y = conn_height / 2 - wall_thickness + side = "bottom" if sign else "top" + y = y if sign else -y + plane = ( + result + # Create connector holes + .copyWorkplane( + Cq.Workplane(side, origin=tip_centre + + Cq.Vector((0, y, 0))) + ) + ) + for i, (px, py) in enumerate(attach_points): + ( + plane + .moveTo(px, py) + .eachpoint(Cq.Vertex.makeVertex(0, 0, 0)) + .tag(f"conn_{side}{i}") + ) - #middle_profile = middle_profile.moved(Cq.Location((0, 0, -100))) - #tip_profile = tip_profile.moved(Cq.Location((0, 0, -200))) - middle_profile = middle_profile.rotate( - startVector=rotate_centre, - endVector=rotate_centre + rotate_axis, - angleDegrees = 30, - ) - antetip_profile = tip_profile.rotate( - startVector=rotate_centre, - endVector=rotate_centre + rotate_axis, - angleDegrees = 60, - ) - tip_profile = tip_profile.rotate( - startVector=rotate_centre, - endVector=rotate_centre + rotate_axis, - angleDegrees = 90, - ) - seg1 = ( - Cq.Workplane('XY') - .add(root_profile) - .toPending() - .transformed( - offset=terminal_offset, - rotate=terminal_rotate) - #.add(middle_profile.moved(Cq.Location((-15, 0, 15)))) - .add(middle_profile) - .toPending() - .loft() - ) - seg2 = ( - Cq.Workplane('XY') - .add(middle_profile) - .toPending() - .workplane() - .add(antetip_profile) - .toPending() - .loft() - ) - seg3 = ( - Cq.Workplane('XY') - .add(antetip_profile) - .toPending() - .workplane() - .add(tip_profile) - .toPending() - .loft() - ) - result = seg1.union(seg2).union(seg3) result.faces("X").tag("conn")