Created
August 24, 2022 09:08
-
-
Save sethfischer/62cd4efe2be82df7422718b1fb9fb09d to your computer and use it in GitHub Desktop.
Revisions
-
sethfischer created this gist
Aug 24, 2022 .There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,316 @@ from math import radians, sqrt, tan from typing import Tuple import cadquery as cq def reflect_xy(point: Tuple[float, float]) -> Tuple[float, float]: """Reflect point in axis x=y. Reflect by reversing tuple. """ return point[::-1] def reflect_x(point: Tuple[float, float]) -> Tuple[float, float]: """Reflect point in the x-axis.""" return tuple((point[0], point[1] * -1)) class Vslot2020Profile: """2020 V-slot Aluminium Extrusion profile. :Manufacturer: Aluminium Extrusion Company :Web: https://www.alexco.co.nz/ :Part: AEC 2020 """ WIDTH = 20 CORE_WIDTH = 8 RIB_THICKNESS = 1.6627 SLOT_WIDTH = 10.9 SLOT_CHAMFER = 2.62 SLOT_DEPTH = 4.3 CENTER_BORE_DIAMETER = 4.2 HALF_BETWEEN_V_LOWER_VERTICES = 2.7 BORE_CHANNEL_WIDTH = 3 BORE_CHANNEL_DEPTH = 1.325 BORE_GROOVE_ANGLE_OBTUSE = 45 def __init__(self) -> None: """Initialise dimensions.""" self.half_width = self.WIDTH / 2 self.half_core_width = self.CORE_WIDTH / 2 self.half_rib_thickness = self.RIB_THICKNESS / 2 self.half_slot_width = self.SLOT_WIDTH / 2 self.center_bore_radius = self.CENTER_BORE_DIAMETER / 2 self.half_bore_channel_width = self.BORE_CHANNEL_WIDTH / 2 self.core_positive_x_axis_vertex = (self.half_core_width, 0) self.core_rib_vertex_y = self.half_core_width - sqrt( self.half_rib_thickness**2 + self.half_rib_thickness**2 ) self.core_rib_vertex = (self.half_core_width, self.core_rib_vertex_y) self.rib_wall_vertex_x = self.half_core_width + self.SLOT_CHAMFER self.rib_slot_vertex = (self.rib_wall_vertex_x, self.half_slot_width) self.slot_retainer_vertex = ( self.half_core_width + self.SLOT_DEPTH, self.half_slot_width, ) self.v_lower_vertex = ( self.slot_retainer_vertex[0], self.half_slot_width - self.HALF_BETWEEN_V_LOWER_VERTICES, ) self.v_upper_vertex = ( self.half_width, (self.half_width - self.v_lower_vertex[0]) + self.v_lower_vertex[1], ) def make(self): """Make profile.""" sketch = self._make_main_sketch() sketch_bore_slot = self._make_bore_slot_sketch() sketch = sketch.face(sketch_bore_slot, mode="s") sketch = self._make_center_lines(sketch) sketch = self._tag_vertices(sketch) sketch = self._fillet(sketch) return sketch def _make_main_sketch(self): """Main sketch.""" sketch = ( cq.Sketch() .parray(0, 0, 360, 4) # quadrant 1 .segment(self.core_positive_x_axis_vertex, self.core_rib_vertex) .segment(self.rib_slot_vertex) .segment(self.slot_retainer_vertex) .segment(self.v_lower_vertex) .segment(self.v_upper_vertex) .segment((self.half_width, self.half_width)) .segment(reflect_xy(self.v_upper_vertex)) .segment(reflect_xy(self.v_lower_vertex)) .segment(reflect_xy(self.slot_retainer_vertex)) .segment(reflect_xy(self.rib_slot_vertex)) .segment(reflect_xy(self.core_rib_vertex)) .segment((0, self.half_core_width)) .segment((0, 0)) .close() .assemble() .clean() ) sketch = sketch.reset().circle(self.center_bore_radius, mode="s") return sketch def _make_bore_slot_sketch(self): """Make bore slot sketch. Bore slot consists of a channel and a groove. """ core_channel_vertex_q2 = (-self.half_core_width, self.half_bore_channel_width) channel_groove_vertex = ( -self.half_core_width + self.BORE_CHANNEL_DEPTH, self.half_bore_channel_width, ) bore_groove_depth = self.half_bore_channel_width * tan( radians(self.BORE_GROOVE_ANGLE_OBTUSE) ) bore_groove_vertex = ( -self.half_core_width + self.BORE_CHANNEL_DEPTH + bore_groove_depth, 0, ) sketch = ( cq.Sketch() .segment((-self.half_core_width, 0), core_channel_vertex_q2) .segment(channel_groove_vertex) .segment(bore_groove_vertex) .segment(reflect_x(channel_groove_vertex)) .segment(reflect_x(core_channel_vertex_q2)) .close() .assemble() ) return sketch def _make_center_lines(self, profile): points = [ (self.half_core_width, 0), (0, self.half_core_width), (0, -self.half_core_width), ] profile = profile.reset().push(points).circle(0.25, mode="s") return profile def _tag_vertices(self, profile): """Tag all vertices.""" profile = self._tag_vertices_centerbore_groove(profile) profile = self._tag_vertices_bounding_box(profile) profile = self._tag_vertices_slot_retainer(profile) profile = self._tag_vertices_v_lower(profile) profile = self._tag_vertices_v_upper(profile) profile = self._tag_vertices_rib_slot(profile) profile = self._tag_vertices_core_rib(profile) profile = self._tag_vertices_core_channel(profile) profile = self._tag_vertices_channel_groove(profile) profile = self._tag_vertices_cline(profile) return profile @staticmethod def _tag_vertices_centerbore_groove(profile): """Tag centerbore grove.""" return profile.reset().vertices(">>X[9]").tag("centerbore_groove_vertices") @staticmethod def _tag_vertices_bounding_box(profile): """Tag bounding box vertices.""" profile = ( profile.reset() .vertices("(>X and <Y) or (>X and >Y) or (<X and <Y) or (<X and >Y)") .tag("bounding_box_vertices") ) return profile @staticmethod def _tag_vertices_slot_retainer(profile): """Tag slot retainer.""" selector = { "q1": "(>>Y[1] and >>X[3]) or (>>X[1] and >>Y[3])", "q2": "(<<Y[1] and >>X[3]) or (>>X[1] and <<Y[3])", "q3": "(<<Y[3] and <<X[1]) or (<<Y[1] and <<X[3])", "q4": "(>>Y[3] and <<X[1]) or (>>Y[1] and <<X[3])", } profile = ( profile.reset() .vertices(" or ".join(selector.values())) .tag("slot_retainer_vertices") ) return profile @staticmethod def _tag_vertices_v_lower(profile): """Tag V-slot lower verticies.""" selector = { "q1": "(<<X[1] and <<Y[7]) or (<<X[7] and <<Y[1])", "q2": "(>>X[1] and <<Y[7]) or (>>X[7] and <<Y[1])", "q3": "(>>X[1] and >>Y[7]) or (>>X[7] and >>Y[1])", "q4": "(<<X[1] and >>Y[7]) or (<<X[7] and >>Y[1])", } profile = ( profile.reset() .vertices(" or ".join(selector.values())) .tag("v_lower_vertices") ) return profile @staticmethod def _tag_vertices_v_upper(profile): """Tag V-slot upper vertices.""" selector = { "q1": "(<<X[0] and <<Y[4]) or (<<X[4] and <<Y[0])", "q2": "(>>X[0] and <<Y[4]) or (>>X[4] and <<Y[0])", "q3": "(>>X[0] and >>Y[4]) or (>>X[4] and >>Y[0])", "q4": "(<<X[0] and >>Y[4]) or (<<X[4] and >>Y[0])", } profile = ( profile.reset() .vertices(" or ".join(selector.values())) .tag("v_upper_vertices") ) return profile @staticmethod def _tag_vertices_rib_slot(profile): """Tag rib slot vertices.""" profile = ( profile.reset() .vertices("<<X[2] or >>X[2] or <<Y[2] or >>Y[2]") .tag("rib_slot_vertices") ) return profile @staticmethod def _tag_vertices_core_rib(profile): """Tag core rib vertices.""" selector = { "q1": "(<<X[5] and <<Y[6]) or (<<X[6] and <<Y[5])", "q2": "(>>X[5] and <<Y[6]) or (>>X[6] and <<Y[5])", "q3": "(>>X[5] and >>Y[6]) or (>>X[6] and >>Y[5])", "q4": "(<<X[5] and >>Y[6]) or (<<X[6] and >>Y[5])", } profile = ( profile.reset() .vertices(" or ".join(selector.values())) .tag("core_rib_vertices") ) return profile @staticmethod def _tag_vertices_core_channel(profile): """Tag core channel verticies.""" profile = ( profile.reset() .vertices("(>>X[5] and <<Y[8]) or (>>X[5] and >>Y[8])") .tag("core_channel_vertices") ) return profile @staticmethod def _tag_vertices_channel_groove(profile): """Tag channel groove vertices.""" profile = profile.reset().vertices(">>X[8]").tag("channel_groove_vertices") return profile @staticmethod def _tag_vertices_cline(profile): """Tag center line vertices.""" selector = { "positive_x": "(<<X[5] and <<Y[12]) or (<<X[5] and >>Y[12])", "positive_y": "(<<X[11] and <<Y[5]) or (<<X[9] and <<Y[5])", "negative_y": "(<<X[11] and >>Y[5]) or (<<X[9] and >>Y[5])", } profile = ( profile.reset() .vertices(" or ".join(selector.values())) .tag("cline_vertices") ) return profile @staticmethod def _fillet(profile): """Fillet tagged vertices.""" profile.vertices(tag="centerbore_groove_vertices").fillet(0.3) profile.vertices(tag="bounding_box_vertices").fillet(0.5) profile.vertices(tag="slot_retainer_vertices").fillet(0.25) profile.vertices(tag="v_lower_vertices").fillet(0.25) profile.vertices(tag="v_upper_vertices").fillet(0.3) profile.vertices(tag="rib_slot_vertices").fillet(0.3) profile.vertices(tag="core_rib_vertices").fillet(0.3) profile.vertices(tag="core_channel_vertices").fillet(0.3) profile.vertices(tag="channel_groove_vertices").fillet(0.3) profile.vertices(tag="cline_vertices").fillet(0.3) return profile if "show_object" in locals(): profile = Vslot2020Profile() # show_object(profile.make()) show_object(cq.Workplane().placeSketch(profile.make()).extrude(10))