cosplay: Touhou/Houjuu Nue #4
|
@ -8,7 +8,7 @@ import nhf.utils
|
||||||
|
|
||||||
TOL = 1e-6
|
TOL = 1e-6
|
||||||
|
|
||||||
@dataclass
|
@dataclass(frozen=True)
|
||||||
class HirthJoint:
|
class HirthJoint:
|
||||||
"""
|
"""
|
||||||
A Hirth joint attached to a cylindrical base
|
A Hirth joint attached to a cylindrical base
|
||||||
|
|
|
@ -33,7 +33,6 @@ from dataclasses import dataclass, field
|
||||||
from typing import Optional
|
from typing import Optional
|
||||||
import cadquery as Cq
|
import cadquery as Cq
|
||||||
from nhf.build import Model, TargetKind, target, assembly, submodel
|
from nhf.build import Model, TargetKind, target, assembly, submodel
|
||||||
from nhf.parts.joints import HirthJoint, TorsionJoint
|
|
||||||
import nhf.touhou.houjuu_nue.wing as MW
|
import nhf.touhou.houjuu_nue.wing as MW
|
||||||
import nhf.touhou.houjuu_nue.trident as MT
|
import nhf.touhou.houjuu_nue.trident as MT
|
||||||
import nhf.touhou.houjuu_nue.joints as MJ
|
import nhf.touhou.houjuu_nue.joints as MJ
|
||||||
|
@ -53,40 +52,64 @@ class Parameters(Model):
|
||||||
|
|
||||||
wing_r1: MW.WingR = field(default_factory=lambda: MW.WingR(
|
wing_r1: MW.WingR = field(default_factory=lambda: MW.WingR(
|
||||||
name="r1",
|
name="r1",
|
||||||
shoulder_angle_bias = WING_DEFLECT_ODD,
|
root_joint=MJ.RootJoint(
|
||||||
|
parent_substrate_cull_corners=(0,1,1,1),
|
||||||
|
parent_substrate_cull_edges=(0,0,1,0),
|
||||||
|
),
|
||||||
|
shoulder_angle_bias=WING_DEFLECT_ODD,
|
||||||
s0_top_hole=False,
|
s0_top_hole=False,
|
||||||
s0_bot_hole=True,
|
s0_bot_hole=True,
|
||||||
arrow_height=350.0
|
arrow_height=350.0
|
||||||
))
|
))
|
||||||
wing_r2: MW.WingR = field(default_factory=lambda: MW.WingR(
|
wing_r2: MW.WingR = field(default_factory=lambda: MW.WingR(
|
||||||
name="r2",
|
name="r2",
|
||||||
shoulder_angle_bias = WING_DEFLECT_EVEN,
|
root_joint=MJ.RootJoint(
|
||||||
|
parent_substrate_cull_corners=(1,1,1,1),
|
||||||
|
parent_substrate_cull_edges=(0,0,1,0),
|
||||||
|
),
|
||||||
|
shoulder_angle_bias=WING_DEFLECT_EVEN,
|
||||||
s0_top_hole=True,
|
s0_top_hole=True,
|
||||||
s0_bot_hole=True,
|
s0_bot_hole=True,
|
||||||
))
|
))
|
||||||
wing_r3: MW.WingR = field(default_factory=lambda: MW.WingR(
|
wing_r3: MW.WingR = field(default_factory=lambda: MW.WingR(
|
||||||
name="r3",
|
name="r3",
|
||||||
shoulder_angle_bias = WING_DEFLECT_ODD,
|
root_joint=MJ.RootJoint(
|
||||||
|
parent_substrate_cull_corners=(1,1,1,0),
|
||||||
|
parent_substrate_cull_edges=(0,0,1,0),
|
||||||
|
),
|
||||||
|
shoulder_angle_bias=WING_DEFLECT_ODD,
|
||||||
s0_top_hole=True,
|
s0_top_hole=True,
|
||||||
s0_bot_hole=False,
|
s0_bot_hole=False,
|
||||||
))
|
))
|
||||||
wing_l1: MW.WingL = field(default_factory=lambda: MW.WingL(
|
wing_l1: MW.WingL = field(default_factory=lambda: MW.WingL(
|
||||||
name="l1",
|
name="l1",
|
||||||
shoulder_angle_bias = WING_DEFLECT_EVEN,
|
root_joint=MJ.RootJoint(
|
||||||
|
parent_substrate_cull_corners=(1,0,1,1),
|
||||||
|
parent_substrate_cull_edges=(1,0,0,0),
|
||||||
|
),
|
||||||
|
shoulder_angle_bias=WING_DEFLECT_EVEN,
|
||||||
wrist_angle=-60.0,
|
wrist_angle=-60.0,
|
||||||
s0_top_hole=False,
|
s0_top_hole=False,
|
||||||
s0_bot_hole=True,
|
s0_bot_hole=True,
|
||||||
))
|
))
|
||||||
wing_l2: MW.WingL = field(default_factory=lambda: MW.WingL(
|
wing_l2: MW.WingL = field(default_factory=lambda: MW.WingL(
|
||||||
name="l2",
|
name="l2",
|
||||||
|
root_joint=MJ.RootJoint(
|
||||||
|
parent_substrate_cull_corners=(1,1,1,1),
|
||||||
|
parent_substrate_cull_edges=(1,0,0,0),
|
||||||
|
),
|
||||||
wrist_angle=-30.0,
|
wrist_angle=-30.0,
|
||||||
shoulder_angle_bias = WING_DEFLECT_ODD,
|
shoulder_angle_bias=WING_DEFLECT_ODD,
|
||||||
s0_top_hole=True,
|
s0_top_hole=True,
|
||||||
s0_bot_hole=True,
|
s0_bot_hole=True,
|
||||||
))
|
))
|
||||||
wing_l3: MW.WingL = field(default_factory=lambda: MW.WingL(
|
wing_l3: MW.WingL = field(default_factory=lambda: MW.WingL(
|
||||||
name="l3",
|
name="l3",
|
||||||
shoulder_angle_bias = WING_DEFLECT_EVEN,
|
root_joint=MJ.RootJoint(
|
||||||
|
parent_substrate_cull_corners=(1,1,0,1),
|
||||||
|
parent_substrate_cull_edges=(1,0,0,0),
|
||||||
|
),
|
||||||
|
shoulder_angle_bias=WING_DEFLECT_EVEN,
|
||||||
wrist_angle=-0.0,
|
wrist_angle=-0.0,
|
||||||
s0_top_hole=True,
|
s0_top_hole=True,
|
||||||
s0_bot_hole=False,
|
s0_bot_hole=False,
|
||||||
|
@ -96,14 +119,6 @@ class Parameters(Model):
|
||||||
|
|
||||||
def __post_init__(self):
|
def __post_init__(self):
|
||||||
super().__init__(name="houjuu-nue")
|
super().__init__(name="houjuu-nue")
|
||||||
self.wing_r1.root_joint = self.harness.root_joint
|
|
||||||
self.wing_r2.root_joint = self.harness.root_joint
|
|
||||||
self.wing_r3.root_joint = self.harness.root_joint
|
|
||||||
self.wing_l1.root_joint = self.harness.root_joint
|
|
||||||
self.wing_l2.root_joint = self.harness.root_joint
|
|
||||||
self.wing_l3.root_joint = self.harness.root_joint
|
|
||||||
|
|
||||||
self.wing_r1.shoulder_joint.torsion_joint
|
|
||||||
|
|
||||||
@submodel(name="harness")
|
@submodel(name="harness")
|
||||||
def submodel_harness(self) -> Model:
|
def submodel_harness(self) -> Model:
|
||||||
|
|
|
@ -4,6 +4,7 @@ from nhf.parts.joints import HirthJoint
|
||||||
from nhf import Material, Role
|
from nhf import Material, Role
|
||||||
from nhf.build import Model, TargetKind, target, assembly, submodel
|
from nhf.build import Model, TargetKind, target, assembly, submodel
|
||||||
from nhf.touhou.houjuu_nue.joints import RootJoint
|
from nhf.touhou.houjuu_nue.joints import RootJoint
|
||||||
|
from nhf.parts.box import MountingBox
|
||||||
import nhf.utils
|
import nhf.utils
|
||||||
|
|
||||||
@dataclass(frozen=True, kw_only=True)
|
@dataclass(frozen=True, kw_only=True)
|
||||||
|
@ -46,21 +47,21 @@ class Mannequin:
|
||||||
return result.translate((0, self.torso_thickness / 2, 0))
|
return result.translate((0, self.torso_thickness / 2, 0))
|
||||||
|
|
||||||
|
|
||||||
BASE_POS_X = 60.0
|
BASE_POS_X = 70.0
|
||||||
BASE_POS_Y = 100.0
|
BASE_POS_Y = 100.0
|
||||||
|
|
||||||
@dataclass(kw_only=True)
|
@dataclass(kw_only=True)
|
||||||
class Harness(Model):
|
class Harness(Model):
|
||||||
thickness: float = 25.4 / 8
|
thickness: float = 25.4 / 8
|
||||||
width: float = 220.0
|
width: float = 220.0
|
||||||
height: float = 310.0
|
height: float = 304.8
|
||||||
fillet: float = 10.0
|
fillet: float = 10.0
|
||||||
|
|
||||||
wing_base_pos: list[tuple[str, float, float]] = field(default_factory=lambda: [
|
wing_base_pos: list[tuple[str, float, float]] = field(default_factory=lambda: [
|
||||||
("r1", BASE_POS_X + 10, BASE_POS_Y),
|
("r1", BASE_POS_X, BASE_POS_Y),
|
||||||
("l1", -BASE_POS_X - 10, BASE_POS_Y),
|
("l1", -BASE_POS_X, BASE_POS_Y),
|
||||||
("r2", BASE_POS_X + 10, 0),
|
("r2", BASE_POS_X, 0),
|
||||||
("l2", -BASE_POS_X - 10, 0),
|
("l2", -BASE_POS_X, 0),
|
||||||
("r3", BASE_POS_X, -BASE_POS_Y),
|
("r3", BASE_POS_X, -BASE_POS_Y),
|
||||||
("l3", -BASE_POS_X, -BASE_POS_Y),
|
("l3", -BASE_POS_X, -BASE_POS_Y),
|
||||||
])
|
])
|
||||||
|
@ -72,9 +73,12 @@ class Harness(Model):
|
||||||
def __post_init__(self):
|
def __post_init__(self):
|
||||||
super().__init__(name="harness")
|
super().__init__(name="harness")
|
||||||
|
|
||||||
@submodel(name="root-joint")
|
@submodel(name="bridge-pair-horizontal")
|
||||||
def submodel_root_joint(self) -> Model:
|
def bridge_pair_horizontal(self) -> MountingBox:
|
||||||
return self.root_joint
|
return self.root_joint.bridge_pair_horizontal(centre_dx=BASE_POS_X * 2)
|
||||||
|
@submodel(name="bridge-pair-vertical")
|
||||||
|
def bridge_pair_vertical(self) -> MountingBox:
|
||||||
|
return self.root_joint.bridge_pair_vertical(centre_dy=BASE_POS_Y)
|
||||||
|
|
||||||
@target(name="profile", kind=TargetKind.DXF)
|
@target(name="profile", kind=TargetKind.DXF)
|
||||||
def profile(self) -> Cq.Sketch:
|
def profile(self) -> Cq.Sketch:
|
||||||
|
@ -126,7 +130,7 @@ class Harness(Model):
|
||||||
conn = [(px + x, py + y) for px, py
|
conn = [(px + x, py + y) for px, py
|
||||||
in self.root_joint.corner_pos()]
|
in self.root_joint.corner_pos()]
|
||||||
for i, (px, py) in enumerate(conn):
|
for i, (px, py) in enumerate(conn):
|
||||||
plane.moveTo(px, py).tagPoint(f"{tag}_{i}")
|
plane.moveTo(px, py).tagPlane(f"{tag}_{i}")
|
||||||
return result
|
return result
|
||||||
|
|
||||||
def add_root_joint_constraint(
|
def add_root_joint_constraint(
|
||||||
|
@ -144,7 +148,6 @@ class Harness(Model):
|
||||||
harness = self.surface()
|
harness = self.surface()
|
||||||
mannequin_z = self.mannequin.shoulder_to_waist * 0.6
|
mannequin_z = self.mannequin.shoulder_to_waist * 0.6
|
||||||
|
|
||||||
|
|
||||||
result = (
|
result = (
|
||||||
Cq.Assembly()
|
Cq.Assembly()
|
||||||
.addS(
|
.addS(
|
||||||
|
@ -159,6 +162,37 @@ class Harness(Model):
|
||||||
loc=Cq.Location((0, -self.thickness, -mannequin_z), (0, 0, 1), 180))
|
loc=Cq.Location((0, -self.thickness, -mannequin_z), (0, 0, 1), 180))
|
||||||
.constrain("mannequin", "Fixed")
|
.constrain("mannequin", "Fixed")
|
||||||
)
|
)
|
||||||
|
bridge_h = self.bridge_pair_horizontal().generate()
|
||||||
|
for i in [1,2,3]:
|
||||||
|
name = f"r{i}l{i}_bridge"
|
||||||
|
(
|
||||||
|
result
|
||||||
|
.addS(
|
||||||
|
bridge_h, name=name,
|
||||||
|
role=Role.FIXTURE,
|
||||||
|
material=Material.WOOD_BIRCH,
|
||||||
|
)
|
||||||
|
.constrain(f"{name}?conn0_rev", f"base?r{i}_1", "Point")
|
||||||
|
.constrain(f"{name}?conn1_rev", f"base?l{i}_0", "Point")
|
||||||
|
.constrain(f"{name}?conn2_rev", f"base?l{i}_3", "Point")
|
||||||
|
.constrain(f"{name}?conn3_rev", f"base?r{i}_2", "Point")
|
||||||
|
)
|
||||||
|
bridge_v = self.bridge_pair_vertical().generate()
|
||||||
|
(
|
||||||
|
result
|
||||||
|
.addS(bridge_v, name="r1_bridge", role=Role.FIXTURE, material=Material.WOOD_BIRCH)
|
||||||
|
.constrain("r1_bridge?conn0_rev", "base?r1_3", 'Plane')
|
||||||
|
.constrain("r1_bridge?conn1_rev", "base?r2_0", 'Plane')
|
||||||
|
.addS(bridge_v, name="r2_bridge", role=Role.FIXTURE, material=Material.WOOD_BIRCH)
|
||||||
|
.constrain("r2_bridge?conn0_rev", "base?r2_3", 'Plane')
|
||||||
|
.constrain("r2_bridge?conn1_rev", "base?r3_0", 'Plane')
|
||||||
|
.addS(bridge_v, name="l1_bridge", role=Role.FIXTURE, material=Material.WOOD_BIRCH)
|
||||||
|
.constrain("l1_bridge?conn0_rev", "base?l1_2", 'Plane')
|
||||||
|
.constrain("l1_bridge?conn1_rev", "base?l2_1", 'Plane')
|
||||||
|
.addS(bridge_v, name="l2_bridge", role=Role.FIXTURE, material=Material.WOOD_BIRCH)
|
||||||
|
.constrain("l2_bridge?conn0_rev", "base?l2_2", 'Plane')
|
||||||
|
.constrain("l2_bridge?conn1_rev", "base?l3_1", 'Plane')
|
||||||
|
)
|
||||||
if with_root_joint:
|
if with_root_joint:
|
||||||
for name in ["l1", "l2", "l3", "r1", "r2", "r3"]:
|
for name in ["l1", "l2", "l3", "r1", "r2", "r3"]:
|
||||||
result.addS(
|
result.addS(
|
||||||
|
|
|
@ -4,6 +4,7 @@ from typing import Optional, Tuple
|
||||||
import cadquery as Cq
|
import cadquery as Cq
|
||||||
from nhf import Material, Role
|
from nhf import Material, Role
|
||||||
from nhf.build import Model, target, assembly
|
from nhf.build import Model, target, assembly
|
||||||
|
from nhf.parts.box import MountingBox
|
||||||
from nhf.parts.springs import TorsionSpring
|
from nhf.parts.springs import TorsionSpring
|
||||||
from nhf.parts.fasteners import FlatHeadBolt, HexNut, ThreaddedKnob
|
from nhf.parts.fasteners import FlatHeadBolt, HexNut, ThreaddedKnob
|
||||||
from nhf.parts.joints import TorsionJoint, HirthJoint
|
from nhf.parts.joints import TorsionJoint, HirthJoint
|
||||||
|
@ -88,6 +89,10 @@ class RootJoint(Model):
|
||||||
parent_corner_inset: float = 12
|
parent_corner_inset: float = 12
|
||||||
parent_mount_thickness: float = 25.4 / 16
|
parent_mount_thickness: float = 25.4 / 16
|
||||||
|
|
||||||
|
parent_substrate_thickness: float = 25.4 / 16
|
||||||
|
parent_substrate_cull_corners: Tuple[bool, bool, bool, bool] = (False, False, True, False)
|
||||||
|
parent_substrate_cull_edges: Tuple[bool, bool, bool, bool] = (False, False, True, False)
|
||||||
|
|
||||||
child_corner_dx: float = 17.0
|
child_corner_dx: float = 17.0
|
||||||
child_corner_dz: float = 24.0
|
child_corner_dz: float = 24.0
|
||||||
|
|
||||||
|
@ -103,6 +108,8 @@ class RootJoint(Model):
|
||||||
def __post_init__(self):
|
def __post_init__(self):
|
||||||
assert self.child_extra_thickness > 0.0
|
assert self.child_extra_thickness > 0.0
|
||||||
assert self.parent_thickness >= self.hex_nut.thickness
|
assert self.parent_thickness >= self.hex_nut.thickness
|
||||||
|
# twice the buffer allocated for substratum
|
||||||
|
assert self.parent_width >= 4 * self.parent_corner_inset
|
||||||
|
|
||||||
def corner_pos(self) -> list[tuple[int, int]]:
|
def corner_pos(self) -> list[tuple[int, int]]:
|
||||||
"""
|
"""
|
||||||
|
@ -111,9 +118,9 @@ class RootJoint(Model):
|
||||||
dx = self.parent_width / 2 - self.parent_corner_inset
|
dx = self.parent_width / 2 - self.parent_corner_inset
|
||||||
return [
|
return [
|
||||||
(dx, dx),
|
(dx, dx),
|
||||||
(dx, -dx),
|
|
||||||
(-dx, -dx),
|
|
||||||
(-dx, dx),
|
(-dx, dx),
|
||||||
|
(-dx, -dx),
|
||||||
|
(dx, -dx),
|
||||||
]
|
]
|
||||||
|
|
||||||
@property
|
@property
|
||||||
|
@ -127,6 +134,45 @@ class RootJoint(Model):
|
||||||
def base_to_surface_thickness(self) -> float:
|
def base_to_surface_thickness(self) -> float:
|
||||||
return self.hirth_joint.joint_height + self.child_extra_thickness
|
return self.hirth_joint.joint_height + self.child_extra_thickness
|
||||||
|
|
||||||
|
@property
|
||||||
|
def substrate_inset(self) -> float:
|
||||||
|
return self.parent_corner_inset * 2
|
||||||
|
|
||||||
|
def bridge_pair_horizontal(self, centre_dx: float) -> MountingBox:
|
||||||
|
hole_dx = centre_dx / 2 - self.parent_width / 2 + self.parent_corner_inset
|
||||||
|
hole_dy = self.parent_width / 2 - self.parent_corner_inset
|
||||||
|
holes = [
|
||||||
|
Hole(x=hole_dx, y=hole_dy),
|
||||||
|
Hole(x=-hole_dx, y=hole_dy),
|
||||||
|
Hole(x=-hole_dx, y=-hole_dy),
|
||||||
|
Hole(x=hole_dx, y=-hole_dy),
|
||||||
|
]
|
||||||
|
return MountingBox(
|
||||||
|
length=centre_dx - self.parent_width + self.substrate_inset * 2,
|
||||||
|
width=self.parent_width,
|
||||||
|
thickness=self.parent_substrate_thickness,
|
||||||
|
hole_diam=self.corner_hole_diam,
|
||||||
|
holes=holes,
|
||||||
|
centred=(True, True),
|
||||||
|
generate_reverse_tags=True,
|
||||||
|
)
|
||||||
|
def bridge_pair_vertical(self, centre_dy: float) -> MountingBox:
|
||||||
|
hole_dy = centre_dy / 2 - self.parent_width / 2 + self.parent_corner_inset
|
||||||
|
holes = [
|
||||||
|
Hole(x=0, y=hole_dy),
|
||||||
|
Hole(x=0, y=-hole_dy),
|
||||||
|
]
|
||||||
|
return MountingBox(
|
||||||
|
length=self.substrate_inset,
|
||||||
|
width=centre_dy - self.parent_width + self.substrate_inset * 2,
|
||||||
|
thickness=self.parent_substrate_thickness,
|
||||||
|
hole_diam=self.corner_hole_diam,
|
||||||
|
holes=holes,
|
||||||
|
centred=(True, True),
|
||||||
|
generate_reverse_tags=True,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
@target(name="parent")
|
@target(name="parent")
|
||||||
def parent(self):
|
def parent(self):
|
||||||
"""
|
"""
|
||||||
|
@ -142,7 +188,6 @@ class RootJoint(Model):
|
||||||
width=self.parent_width,
|
width=self.parent_width,
|
||||||
height=self.parent_thickness,
|
height=self.parent_thickness,
|
||||||
centered=(True, True, False))
|
centered=(True, True, False))
|
||||||
.translate((0, 0, -self.parent_thickness))
|
|
||||||
.edges("|Z")
|
.edges("|Z")
|
||||||
.fillet(self.parent_corner_fillet)
|
.fillet(self.parent_corner_fillet)
|
||||||
.faces(">Z")
|
.faces(">Z")
|
||||||
|
@ -153,6 +198,32 @@ class RootJoint(Model):
|
||||||
cboreDiameter=self.parent_corner_cbore_diam,
|
cboreDiameter=self.parent_corner_cbore_diam,
|
||||||
cboreDepth=self.parent_corner_cbore_depth)
|
cboreDepth=self.parent_corner_cbore_depth)
|
||||||
)
|
)
|
||||||
|
sso = self.parent_width / 2 - self.substrate_inset
|
||||||
|
loc_corner = Cq.Location((sso, sso, 0))
|
||||||
|
loc_edge= Cq.Location((sso, -sso, 0))
|
||||||
|
cut_corner = Cq.Solid.makeBox(
|
||||||
|
length=self.parent_width,
|
||||||
|
width=self.parent_width,
|
||||||
|
height=self.parent_substrate_thickness,
|
||||||
|
)
|
||||||
|
cut_edge = Cq.Solid.makeBox(
|
||||||
|
length=self.parent_width,
|
||||||
|
width=self.parent_width - self.substrate_inset * 2,
|
||||||
|
height=self.parent_substrate_thickness,
|
||||||
|
)
|
||||||
|
step = 90
|
||||||
|
for i, flag in enumerate(self.parent_substrate_cull_corners):
|
||||||
|
if not flag:
|
||||||
|
continue
|
||||||
|
loc = Cq.Location((0,0,0),(0,0,1), i * step) * loc_corner
|
||||||
|
result = result.cut(cut_corner.located(loc))
|
||||||
|
for i, flag in enumerate(self.parent_substrate_cull_edges):
|
||||||
|
if not flag:
|
||||||
|
continue
|
||||||
|
loc = Cq.Location((0,0,0),(0,0,1), i * step) * loc_edge
|
||||||
|
result = result.cut(cut_edge.located(loc))
|
||||||
|
|
||||||
|
result = result.translate((0, 0, -self.parent_thickness))
|
||||||
# Creates a plane parallel to the holes but shifted to the base
|
# Creates a plane parallel to the holes but shifted to the base
|
||||||
plane = result.faces(">Z").workplane(offset=-self.parent_thickness)
|
plane = result.faces(">Z").workplane(offset=-self.parent_thickness)
|
||||||
|
|
||||||
|
@ -171,7 +242,7 @@ class RootJoint(Model):
|
||||||
.hole(diameter=self.axis_diam)
|
.hole(diameter=self.axis_diam)
|
||||||
.cut(self.hex_nut.generate().translate((0, 0, -self.parent_thickness)))
|
.cut(self.hex_nut.generate().translate((0, 0, -self.parent_thickness)))
|
||||||
)
|
)
|
||||||
result.faces("<Z").tag("base")
|
result.copyWorkplane(Cq.Workplane('XY', origin=(0,0,-self.parent_thickness))).tagPlane("base", direction="-Z")
|
||||||
return result
|
return result
|
||||||
|
|
||||||
@target(name="child")
|
@target(name="child")
|
||||||
|
|
|
@ -142,6 +142,9 @@ class WingProfile(Model):
|
||||||
extra = 2 * self.panel_thickness if self.flip else 0
|
extra = 2 * self.panel_thickness if self.flip else 0
|
||||||
return self.s1_thickness - 2 * self.panel_thickness - extra
|
return self.s1_thickness - 2 * self.panel_thickness - extra
|
||||||
|
|
||||||
|
@submodel(name="root-joint")
|
||||||
|
def submodel_root_joint(self) -> Model:
|
||||||
|
return self.root_joint
|
||||||
@submodel(name="shoulder-joint")
|
@submodel(name="shoulder-joint")
|
||||||
def submodel_shoulder_joint(self) -> Model:
|
def submodel_shoulder_joint(self) -> Model:
|
||||||
return self.shoulder_joint
|
return self.shoulder_joint
|
||||||
|
@ -312,6 +315,7 @@ class WingProfile(Model):
|
||||||
Hole(x=dx, y=-dy),
|
Hole(x=dx, y=-dy),
|
||||||
Hole(x=dx, y=dy),
|
Hole(x=dx, y=dy),
|
||||||
Hole(x=-dx, y=dy),
|
Hole(x=-dx, y=dy),
|
||||||
|
Hole(x=0, y=0, diam=self.root_joint.axis_diam, tag="axle"),
|
||||||
]
|
]
|
||||||
return MountingBox(
|
return MountingBox(
|
||||||
length=self.root_height,
|
length=self.root_height,
|
||||||
|
|
Loading…
Reference in New Issue