from nhf.build import Model, TargetKind, target, assembly, submodel from nhf.materials import Role, Material import nhf.utils from nhf.parts.fasteners import FlatHeadBolt, HexNut, Washer from nhf.parts.electronics import ArduinoUnoR3, BatteryBox18650 from typing import Optional, Union import math from dataclasses import dataclass, field import cadquery as Cq NUT_COMMON = HexNut( # FIXME: weigh mass=0.0, diam_thread=6.0, pitch=1.0, thickness=5.0, width=9.89, ) BOLT_COMMON = FlatHeadBolt( # FIXME: weigh mass=0.0, diam_head=12.8, height_head=2.8, diam_thread=6.0, height_thread=30.0, pitch=1.0, ) @dataclass class Shimenawa(Model): """ The ring """ diam_inner: float = 43.0 diam_outer: float = 43.0 + 9 * 2 diam_hole_outer: float = 8.0 hole_ext: float = 2.0 hole_z: float = 15.0 pipe_fitting_angle_span: float = 6.0 pipe_joint_length: float = 120.0 pipe_joint_outer_thickness: float = 5.0 pipe_joint_inner_thickness: float = 4.0 pipe_joint_inner_angle_span: float = 120.0 pipe_joint_taper: float = 5.0 pipe_joint_taper_length: float = 10.0 ear_dr: float = 6.0 ear_hole_diam: float = 10.0 ear_radius: float = 15.0 ear_thickness: float = 10.0 main_circumference: float = 3600.0 material_fitting: Material = Material.PLASTIC_PLA def __post_init__(self): assert self.diam_inner < self.diam_outer @property def main_radius(self) -> float: return self.main_circumference / (2 * math.pi) @target(name="pipe-fitting-curved") def pipe_fitting_curved(self) -> Cq.Workplane: r_minor = self.diam_outer/2 + self.pipe_joint_outer_thickness a1 = self.pipe_fitting_angle_span outer = Cq.Solid.makeTorus( radius1=self.main_radius, radius2=r_minor, ) inner = Cq.Solid.makeTorus( radius1=self.main_radius, radius2=self.diam_outer/2, ) angle_intersector = Cq.Solid.makeCylinder( radius=self.main_radius + r_minor, height=r_minor*2, angleDegrees=a1, pnt=(0,0,-r_minor) ).rotate((0,0,0),(0,0,1),-a1/2) result = (outer - inner) * angle_intersector ear_outer = Cq.Solid.makeCylinder( radius=self.ear_radius, height=self.ear_thickness, pnt=(0,-self.ear_thickness/2,0), dir=(0,1,0), ) ear_hole = Cq.Solid.makeCylinder( radius=self.ear_hole_diam/2, height=self.ear_thickness, pnt=(-self.ear_dr,-self.ear_thickness/2,0), dir=(0,1,0), ) ear = (ear_outer - ear_hole).moved(self.main_radius - r_minor, 0, 0) result += ear - inner return result @target(name="pipe-joint-outer") def pipe_joint_outer(self) -> Cq.Workplane: """ Used to joint two pipes together (outside) """ r1 = self.diam_outer / 2 + self.pipe_joint_outer_thickness h = self.pipe_joint_length result = ( Cq.Workplane() .cylinder( radius=r1, height=self.pipe_joint_length, ) ) cut_interior = Cq.Solid.makeCylinder( radius=self.diam_outer/2, height=h, pnt=(0, 0, -h/2) ) rh = r1 + self.hole_ext add_hole = Cq.Solid.makeCylinder( radius=self.diam_hole_outer/2, height=rh*2, pnt=(-rh, 0, 0), dir=(1, 0, 0), ) cut_hole = Cq.Solid.makeCylinder( radius=BOLT_COMMON.diam_thread/2, height=rh*2, pnt=(-rh, 0, 0), dir=(1, 0, 0), ) z = self.hole_z result = ( result + add_hole.moved(0, 0, -z) + add_hole.moved(0, 0, z) - cut_hole.moved(0, 0, -z) - cut_hole.moved(0, 0, z) - cut_interior ) ear_outer = Cq.Solid.makeCylinder( radius=self.ear_radius, height=self.ear_thickness, pnt=(0, r1, -self.ear_thickness/2), ) ear_hole = Cq.Solid.makeCylinder( radius=self.ear_hole_diam/2, height=self.ear_thickness, pnt=(0,r1+self.ear_dr,-self.ear_thickness/2), ) ear = ear_outer - ear_hole - cut_interior return result + ear @target(name="pipe-joint-inner") def pipe_joint_inner(self) -> Cq.Workplane: """ Used to joint two pipes together (inside) """ r1 = self.diam_inner / 2 r2 = r1 - self.pipe_joint_taper r3 = r2 - self.pipe_joint_inner_thickness h = self.pipe_joint_length h0 = h - self.pipe_joint_taper_length*2 core = Cq.Solid.makeCylinder( radius=r2, height=h0/2, ) centre_cut = Cq.Solid.makeCylinder( radius=r3, height=h0/2, ) taper = Cq.Solid.makeCone( radius1=r2, radius2=r1, height=(h - h0) / 2, pnt=(0, 0, h0/2), ) centre_cut_taper = Cq.Solid.makeCone( radius1=r3, radius2=r3 + self.pipe_joint_taper, height=(h - h0) / 2, pnt=(0, 0, h0/2), ) angle_intersector = Cq.Solid.makeCylinder( radius=r1, height=h, angleDegrees=self.pipe_joint_inner_angle_span ).rotate((0,0,0), (0,0,1), -self.pipe_joint_inner_angle_span/2) result = (taper + core - centre_cut - centre_cut_taper) * angle_intersector result += result.mirror("XY") add_hole = Cq.Solid.makeCylinder( radius=self.diam_hole_outer/2, height=self.hole_ext, pnt=(r3, 0, 0), dir=(-1, 0, 0), ) cut_hole = Cq.Solid.makeCylinder( radius=BOLT_COMMON.diam_thread/2, height=r1, pnt=(0, 0, 0), dir=(r1, 0, 0), ) z = self.hole_z # avoid collisions nut_x = r3 - self.hole_ext - NUT_COMMON.thickness nut = NUT_COMMON.generate().val().rotate((0,0,0),(0,1,0),90) result = ( result + add_hole.moved(0, 0, z) + add_hole.moved(0, 0, -z) - cut_hole.moved(0, 0, z) - cut_hole.moved(0, 0, -z) - nut.moved(nut_x, 0, z) - nut.moved(nut_x, 0, -z) ) return result @assembly() def assembly_pipe_joint(self) -> Cq.Assembly: a = ( Cq.Assembly() .addS( self.pipe_joint_outer(), name="joint_outer", material=self.material_fitting, role=Role.STRUCTURE, ) .addS( self.pipe_joint_inner(), name="joint_inner1", material=self.material_fitting, role=Role.STRUCTURE, ) .addS( self.pipe_joint_inner(), name="joint_inner2", material=self.material_fitting, role=Role.STRUCTURE, loc=Cq.Location.rot2d(180), ) ) return a @assembly() def assembly(self) -> Cq.Assembly: a = ( Cq.Assembly() .addS( self.pipe_fitting_curved(), name="fitting1", material=self.material_fitting, role=Role.STRUCTURE, ) .add( self.assembly_pipe_joint(), name="pipe_joint", ) ) return a