diff --git a/nhf/parts/handle.py b/nhf/parts/handle.py index bdeb459..4956618 100644 --- a/nhf/parts/handle.py +++ b/nhf/parts/handle.py @@ -1,10 +1,70 @@ """ This schematics file contains all designs related to tool handles """ -from dataclasses import dataclass +from dataclasses import dataclass, field +from typing import Union, Optional import cadquery as Cq import nhf.parts.metric_threads as metric_threads +class TubeJoint: + + def diam_insertion_internal(self): + """ + Maximum permitted diameter of the internal cavity + """ + def diam_connector_external(self): + """ + Maximum permitted diameter of the external size of the insertion + """ + def external_thread(self, length: float) -> Cq.Shape: + """ + Generates the external connector + """ + def internal_thread(self, length: float) -> Cq.Shape: + """ + Generates the internal connector + """ + +@dataclass +class ThreadedJoint(TubeJoint): + + pitch: float = 3 + + # Major diameter of the internal threads, following ISO metric screw thread + # standard. This determines the wall thickness of the insertion. + diam_threading: float = 27 + + def diam_insertion_internal(self): + r = metric_threads.metric_thread_major_radius( + self.diam_threading, + self.pitch, + internal=True) + return r * 2 + def diam_connector_external(self): + r = metric_threads.metric_thread_minor_radius( + self.diam_threading, + self.pitch) + return r * 2 + + def external_thread(self, length: float): + return metric_threads.external_metric_thread( + self.diam_threading, + self.pitch, + length, + top_lead_in=True) + def internal_thread(self, length: float): + return metric_threads.internal_metric_thread( + self.diam_threading, + self.pitch, + length) + +@dataclass +class BayonetJoint(TubeJoint): + """ + Bayonet type joint + """ + pass + @dataclass class Handle: """ @@ -17,20 +77,16 @@ class Handle: Note that all the radial sizes are diameters (in mm). """ - # Outer and inner radius for the handle usually come in standard sizes + # Outer and inner radii for the handle usually come in standard sizes diam: float = 38 diam_inner: float = 33 - # Major diameter of the internal threads, following ISO metric screw thread - # standard. This determines the wall thickness of the insertion. - diam_threading: float = 27.0 - - thread_pitch: float = 3.0 + joint: Optional[TubeJoint] = field(default_factory=lambda: ThreadedJoint()) # Internal cavity diameter. This determines the wall thickness of the connector diam_connector_internal: float = 18.0 - # If set to true, do not generate threads + # If set to true, do not generate the connections simplify_geometry: bool = True # Length for the rim on the female connector @@ -43,26 +99,12 @@ class Handle: def __post_init__(self): assert self.diam > self.diam_inner, "Material thickness cannot be <= 0" - assert self.diam_inner > self.diam_insertion_internal, "Threading radius is too big" - assert self.diam_insertion_internal > self.diam_connector_external - assert self.diam_connector_external > self.diam_connector_internal, "Internal diameter is too large" + if self.joint: + assert self.diam_inner > self.joint.diam_insertion_internal(), "Threading radius is too big" + assert self.joint.diam_insertion_internal() > self.joint.diam_connector_external() + assert self.joint.diam_connector_external() > self.diam_connector_internal, "Internal diameter is too large" assert self.insertion_length > self.rim_length - @property - def diam_insertion_internal(self): - r = metric_threads.metric_thread_major_radius( - self.diam_threading, - self.thread_pitch, - internal=True) - return r * 2 - - @property - def diam_connector_external(self): - r = metric_threads.metric_thread_minor_radius( - self.diam_threading, - self.thread_pitch) - return r * 2 - def segment(self, length: float): result = ( Cq.Workplane() @@ -76,20 +118,6 @@ class Handle: result.faces(">Z").tag("mate2") return result - def _external_thread(self, length=None): - if length is None: - length = self.insertion_length - return metric_threads.external_metric_thread( - self.diam_threading, - self.thread_pitch, - length, - top_lead_in=True) - def _internal_thread(self): - return metric_threads.internal_metric_thread( - self.diam_threading, - self.thread_pitch, - self.insertion_length) - def insertion(self, holes=[]): """ This type of joint is used to connect two handlebar pieces. Each handlebar @@ -121,11 +149,11 @@ class Handle: .circle(self.diam / 2) .extrude(self.rim_length) .faces(">Z") - .hole(self.diam_insertion_internal) + .hole(self.joint.diam_insertion_internal()) ) result.faces(">Z").tag("mate") if not self.simplify_geometry: - thread = self._internal_thread().val() + thread = self.joint.internal_thread(self.connector_length).val() result = result.union(thread) for h in holes: cyl = Cq.Solid.makeCylinder( @@ -157,13 +185,13 @@ class Handle: result .faces(selector) .workplane() - .circle(self.diam_connector_external / 2) + .circle(self.joint.diam_connector_external() / 2) .extrude(self.insertion_length) ) if not solid: result = result.faces(">Z").hole(self.diam_connector_internal) if not self.simplify_geometry: - thread = self._external_thread().val() + thread = self.joint.external_thread(self.insertion_length).val() result = ( result .union( @@ -193,11 +221,11 @@ class Handle: result .faces(">Z") .workplane() - .circle(self.diam_connector_external / 2) + .circle(self.joint.diam_connector_external() / 2) .extrude(self.insertion_length) ) if not self.simplify_geometry: - thread = self._external_thread().val() + thread = self.joint.external_thread(self.insertion_length).val() result = ( result .union( @@ -215,7 +243,7 @@ class Handle: result = ( Cq.Workplane('XY') .cylinder( - radius=self.diam_connector_external / 2, + radius=self.joint.diam_connector_external / 2, height=length, centered=(True, True, False), ) @@ -223,7 +251,7 @@ class Handle: result.faces(">Z").tag("mate") result.faces("