cosplay: Touhou/Houjuu Nue #4
|
@ -10,8 +10,9 @@ from nhf.parts.joints import HirthJoint
|
||||||
def wing_root_profiles(
|
def wing_root_profiles(
|
||||||
base_sweep=150,
|
base_sweep=150,
|
||||||
wall_thickness=8,
|
wall_thickness=8,
|
||||||
base_radius=60,
|
base_radius=40,
|
||||||
middle_offset=30,
|
middle_offset=30,
|
||||||
|
middle_height=80,
|
||||||
conn_width=40,
|
conn_width=40,
|
||||||
conn_height=100) -> tuple[Cq.Wire, Cq.Wire]:
|
conn_height=100) -> tuple[Cq.Wire, Cq.Wire]:
|
||||||
assert base_sweep < 180
|
assert base_sweep < 180
|
||||||
|
@ -72,7 +73,7 @@ def wing_root_profiles(
|
||||||
# If the exterior sweep is theta', it has to satisfy
|
# If the exterior sweep is theta', it has to satisfy
|
||||||
#
|
#
|
||||||
# sin(theta) * r2 + wall_thickness = sin(theta') * r1
|
# 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
|
t = wall_thickness
|
||||||
dx = middle_offset
|
dx = middle_offset
|
||||||
middle = (
|
middle = (
|
||||||
|
@ -126,65 +127,86 @@ def wing_root_profiles(
|
||||||
|
|
||||||
|
|
||||||
def wing_root(joint: HirthJoint,
|
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
|
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)
|
for sign in [False, True]:
|
||||||
rotate_axis = Cq.Vector(0, 1, 0)
|
y = conn_height / 2 - wall_thickness
|
||||||
terminal_offset = Cq.Vector(-80, 0, 80)
|
side = "bottom" if sign else "top"
|
||||||
terminal_rotate = Cq.Vector(0, -45, 0)
|
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("<Z").tag("base")
|
result.faces("<Z").tag("base")
|
||||||
result.faces(">X").tag("conn")
|
result.faces(">X").tag("conn")
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue