cassetta_atrezzi_auto/cassetta_atrezzi_auto.py
  1from cadquery import Assembly, Workplane, Color, Vertex, Vector
  2from cadquery.selectors import AreaNthSelector
  3
  4BOX_LENGTH = 240
  5BOX_WIDTH = 180
  6BOX_DEPTH = 20
  7BORDER_RADIUS = 20
  8CHAMFER_SIZE = 2
  9WALL_THICKNESS = 2
 10EDGE_DEPTH = 5
 11REINFORCEMENT_WIDTH = 20
 12TOL = 0.001
 13LATCH_CANTILEVER = 12
 14LATCH_WIDTH = 6
 15SCREW_LENGTH = 40
 16SCREW_DIAMETER = 4
 17SCREW_NUT_DIAMETER = 7
 18SCREW_NUT_DEPTH = 3
 19
 20
 21def box_walls(
 22    length: float,
 23    width: float,
 24    depth: float,
 25    border_radius: float,
 26    thickness: float = 0,
 27    chamfer_size: float = 0,
 28) -> Workplane:
 29    box = Workplane("XY").box(length, width, depth).edges("|Z").fillet(border_radius)
 30    if chamfer_size > 0:
 31        box = box.edges("<Z").chamfer(chamfer_size)
 32    if thickness > 0:
 33        box = box.faces(">Z").shell(-thickness)
 34    return box
 35
 36
 37def box_edge(
 38    length: float,
 39    width: float,
 40    depth: float,
 41    thickness: float,
 42    border_radius: float,
 43    chamfer_size: float,
 44    inset_depth: float = 2,
 45) -> Workplane:
 46    inset = (
 47        Workplane("XY")
 48        .box(length + chamfer_size, width + chamfer_size, inset_depth)
 49        .edges("|Z")
 50        .fillet(border_radius + chamfer_size)
 51        .faces(">Z or <Z")
 52        .shell(-thickness)
 53        .translate((0, 0, depth / 2))
 54        .faces("<Z")
 55        .chamfer(thickness / 2 - TOL)
 56    )
 57    return (
 58        Workplane("XY")
 59        .box(length + 2 * chamfer_size, width + 2 * chamfer_size, depth)
 60        .edges("|Z")
 61        .fillet(border_radius + chamfer_size)
 62        .faces(">Z or <Z")
 63        .shell(-(thickness + chamfer_size))
 64        .faces("<Z")
 65        .wires(AreaNthSelector(1))
 66        .chamfer(chamfer_size)
 67        - inset
 68    )
 69
 70
 71def latch_side(
 72    depth: float,
 73    height: float,
 74    width: float,
 75    screw_length: float,
 76    screw_diameter: float,
 77    screw_nut_diameter: float,
 78    screw_nut_depth: float,
 79) -> Workplane:
 80    return (
 81        Workplane("YZ")
 82        .lineTo(0, height)
 83        .lineTo(depth, height)
 84        .lineTo(depth, depth)
 85        .close()
 86        .extrude(width)
 87        .edges("|X and >Y and >Z")
 88        .fillet(depth / 5)
 89        .edges("|X and >Y and (not >Z)")
 90        .fillet(depth / 2)
 91        .edges("|Z and (not <Y)")
 92        .chamfer(depth / 10)
 93        .faces("<X")
 94        .workplane()
 95        .center(-depth / 2, height - screw_nut_diameter / 2 - 1.5)
 96        .cboreHole(screw_diameter, screw_nut_diameter, screw_nut_depth)
 97    )
 98
 99
100def latch_holder(
101    cantilever: float,
102    height: float,
103    width: float,
104    screw_length: float,
105    screw_diameter: float,
106    screw_nut_diameter: float,
107    screw_nut_depth: float,
108) -> Workplane:
109    separation = screw_length + screw_nut_depth - width
110    return (
111        latch_side(
112            cantilever,
113            height,
114            width,
115            screw_length,
116            screw_diameter,
117            screw_nut_diameter,
118            screw_nut_depth,
119        )
120        + latch_side(
121            cantilever,
122            height,
123            width,
124            screw_length,
125            screw_diameter,
126            screw_nut_diameter,
127            screw_nut_depth,
128        )
129        .mirror("YZ")
130        .translate((separation, 0, 0))
131    ).translate((-separation / 2, 0, 0))
132
133
134def assembly() -> Assembly:
135    _box_walls = box_walls(
136        BOX_LENGTH,
137        BOX_WIDTH,
138        BOX_DEPTH - EDGE_DEPTH,
139        BORDER_RADIUS,
140        WALL_THICKNESS,
141        CHAMFER_SIZE,
142    )
143    _box_edge = box_edge(
144        BOX_LENGTH,
145        BOX_WIDTH,
146        EDGE_DEPTH,
147        WALL_THICKNESS,
148        BORDER_RADIUS,
149        CHAMFER_SIZE,
150    )
151    _latch = latch_holder(
152        LATCH_CANTILEVER,
153        BOX_DEPTH - CHAMFER_SIZE,
154        LATCH_WIDTH,
155        SCREW_LENGTH,
156        SCREW_DIAMETER,
157        SCREW_NUT_DIAMETER,
158        SCREW_NUT_DEPTH,
159    )
160
161    front_center = _box_walls.faces(">Y").val().Center()
162    return (
163        Assembly()
164        .add(_box_walls, name="box_walls", color=Color("gray90"))
165        .add(_box_edge, name="box_edge", color=Color("gray70"))
166        # .add(reinforcements, name="reinforcements", color=Color("gray50"))
167        .add(_latch, name="latch", color=Color("gray30"))
168        # Fix edge on top of box
169        .constrain("box_walls@faces@>Z", "box_edge@faces@<Z", "Plane")
170        .constrain("box_edge@faces@<Z", "FixedRotation", (0, 0, 0))
171        # Fix latch-holder on front of box
172        .constrain(
173            "box_walls",
174            Vertex.makeVertex(*front_center + Vector(0, 0, EDGE_DEPTH)),
175            "latch",
176            _latch.faces("<Y").val(),
177            "Point",
178        )
179        .constrain("box_walls@faces@>Y", "latch@faces@<Y", "Plane")
180        .constrain("latch@faces@<Y", "FixedRotation", (0, 0, 0))
181        .solve()
182    )
183
184
185bottom_part = assembly()