Cosplay/nhf/parts/box.py

118 lines
3.6 KiB
Python

import cadquery as Cq
from dataclasses import dataclass, field
from typing import Tuple, Optional, Union
from nhf.build import Model, TargetKind, target
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(Model):
"""
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
# Determines the position of side tags
flip_y: bool = False
@target(kind=TargetKind.DXF)
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")
c_y = ">Y" if self.flip_y else "<Y"
result.faces("<X").workplane(origin=result.vertices(f"<X and {c_y} and >Z").val().Center()).tagPlane("bot")
result.faces(">X").workplane(origin=result.vertices(f">X and {c_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()