111 lines
3.3 KiB
Python
111 lines
3.3 KiB
Python
|
import cadquery as Cq
|
||
|
from dataclasses import dataclass, field
|
||
|
from typing import Tuple, Optional, Union
|
||
|
import nhf.utils
|
||
|
|
||
|
def box_with_centre_holes(
|
||
|
length: float,
|
||
|
width: float,
|
||
|
height: float,
|
||
|
hole_loc: list[float],
|
||
|
hole_diam: float = 6.0,
|
||
|
) -> Cq.Workplane:
|
||
|
"""
|
||
|
Creates a box with holes along the X axis, marked `conn0, conn1, ...`. The
|
||
|
box's y axis is centred
|
||
|
"""
|
||
|
result = (
|
||
|
Cq.Workplane('XY')
|
||
|
.box(length, width, height, centered=(False, True, False))
|
||
|
.faces(">Z")
|
||
|
.workplane()
|
||
|
)
|
||
|
plane = result
|
||
|
for i, x in enumerate(hole_loc):
|
||
|
result = result.moveTo(x, 0).hole(hole_diam)
|
||
|
plane.moveTo(x, 0).tagPlane(f"conn{i}")
|
||
|
return result
|
||
|
|
||
|
@dataclass
|
||
|
class Hole:
|
||
|
x: float
|
||
|
y: float = 0.0
|
||
|
diam: Optional[float] = None
|
||
|
tag: Optional[str] = None
|
||
|
|
||
|
@dataclass
|
||
|
class MountingBox:
|
||
|
"""
|
||
|
Create a box with marked holes
|
||
|
"""
|
||
|
length: float = 100.0
|
||
|
width: float = 60.0
|
||
|
thickness: float = 1.0
|
||
|
|
||
|
# List of (x, y), diam
|
||
|
holes: list[Hole] = field(default_factory=lambda: [
|
||
|
Hole(x=5, y=5, diam=3),
|
||
|
Hole(x=20, y=10, diam=5),
|
||
|
])
|
||
|
hole_diam: Optional[float] = None
|
||
|
|
||
|
centred: Tuple[bool, bool] = (False, True)
|
||
|
|
||
|
generate_side_tags: bool = True
|
||
|
|
||
|
def profile(self) -> Cq.Sketch:
|
||
|
bx, by = 0, 0
|
||
|
if not self.centred[0]:
|
||
|
bx = self.length / 2
|
||
|
if not self.centred[1]:
|
||
|
by = self.width / 2
|
||
|
result = (
|
||
|
Cq.Sketch()
|
||
|
.push([(bx, by)])
|
||
|
.rect(self.length, self.width)
|
||
|
)
|
||
|
for hole in self.holes:
|
||
|
diam = hole.diam if hole.diam else self.hole_diam
|
||
|
result.push([(hole.x, hole.y)]).circle(diam / 2, mode='s')
|
||
|
return result
|
||
|
|
||
|
def generate(self) -> Cq.Workplane:
|
||
|
"""
|
||
|
Creates box shape with markers
|
||
|
"""
|
||
|
result = (
|
||
|
Cq.Workplane('XY')
|
||
|
.placeSketch(self.profile())
|
||
|
.extrude(self.thickness)
|
||
|
)
|
||
|
plane = result.copyWorkplane(Cq.Workplane('XY')).workplane(offset=self.thickness)
|
||
|
for i, hole in enumerate(self.holes):
|
||
|
tag = hole.tag if hole.tag else f"conn{i}"
|
||
|
plane.moveTo(hole.x, hole.y).tagPlane(tag)
|
||
|
|
||
|
if self.generate_side_tags:
|
||
|
result.faces("<Y").workplane(origin=result.vertices("<X and <Y and >Z").val().Center()).tagPlane("left")
|
||
|
result.faces(">Y").workplane(origin=result.vertices("<X and >Y and >Z").val().Center()).tagPlane("right")
|
||
|
result.faces("<X").workplane(origin=result.vertices("<X and <Y and >Z").val().Center()).tagPlane("bot")
|
||
|
result.faces(">X").workplane(origin=result.vertices(">X and <Y and >Z").val().Center()).tagPlane("top")
|
||
|
result.faces(">Z").tag("dir")
|
||
|
return result
|
||
|
|
||
|
def marked_assembly(self) -> Cq.Assembly:
|
||
|
result = (
|
||
|
Cq.Assembly()
|
||
|
.add(self.generate(), name="box")
|
||
|
)
|
||
|
for i in range(len(self.holes)):
|
||
|
result.markPlane(f"box?conn{i}")
|
||
|
if self.generate_side_tags:
|
||
|
(
|
||
|
result
|
||
|
.markPlane("box?left")
|
||
|
.markPlane("box?right")
|
||
|
.markPlane("box?dir")
|
||
|
.markPlane("box?top")
|
||
|
.markPlane("box?bot")
|
||
|
)
|
||
|
return result.solve()
|