200 lines
6.9 KiB
Python
200 lines
6.9 KiB
Python
from ocp_vscode import *
|
|
from build123d import *
|
|
from math import tan, sin, cos, sqrt, pi, radians
|
|
|
|
def CounterVal(val):
|
|
if val >= 0:
|
|
return f"+{val}"
|
|
else:
|
|
return f"{val}"
|
|
|
|
def NumStr(val):
|
|
if val < 0:
|
|
return f"n{val}"
|
|
else:
|
|
return f"{val}"
|
|
|
|
class Parallelogram(BaseSketchObject):
|
|
def __init__(
|
|
self,
|
|
width: float,
|
|
height: float,
|
|
angle: float,
|
|
rotation: float = 0,
|
|
align: tuple[Align, Align] = (Align.CENTER, Align.CENTER),
|
|
mode: Mode = Mode.ADD,
|
|
):
|
|
obj = Polygon((width, 0), (width, height), (0, height + width * tan(radians(angle))), (0, width * tan(radians(angle))), align=Align.MIN)
|
|
super().__init__(obj=obj, rotation=rotation, align=align, mode=mode)
|
|
|
|
class Chevron(BaseSketchObject):
|
|
def __init__(
|
|
self,
|
|
width: float,
|
|
height: float,
|
|
angle: float = 22.5,
|
|
rotation: float = 0,
|
|
align: tuple[Align, Align] = (Align.CENTER, Align.CENTER),
|
|
mode: Mode = Mode.ADD,
|
|
):
|
|
chevron = Parallelogram(width/2, height, angle, align=(Align.MIN, Align.MIN))
|
|
chevron += mirror(chevron, Plane.YZ)
|
|
super().__init__(obj=chevron, rotation=rotation, align=align, mode=mode)
|
|
|
|
class NumericalCounter(BasePartObject):
|
|
def __init__(
|
|
self,
|
|
left: str,
|
|
right: str,
|
|
width: float = 25 * MM,
|
|
height: float = 10 * MM,
|
|
wall: float = 1 * MM,
|
|
base_z: float = 1 * MM,
|
|
text_z: float = 0.5 * MM,
|
|
angle: float = 22.5,
|
|
rotation: VectorLike = (0, 0, 0),
|
|
align: tuple[Align, Align] = (Align.CENTER, Align.CENTER),
|
|
mode: Mode = Mode.ADD,
|
|
):
|
|
base = Chevron(width, height, angle, align=(Align.CENTER, Align.MIN))
|
|
part = extrude(base, base_z + text_z, (0, 0, 1))
|
|
|
|
cutout = Pos(wall/2, wall + wall*tan(radians(angle)), 0) * Parallelogram(width/2 - 1.5*wall, height - 2*wall, angle, align=(Align.MIN, Align.MIN))
|
|
cutout += mirror(cutout, Plane.YZ)
|
|
cutout = Pos(0, 0, base_z + text_z) * cutout
|
|
|
|
part -= extrude(cutout, text_z, (0, 0, -1))
|
|
|
|
font_size = width/5
|
|
|
|
font = "Arial Rounded MT Bold"
|
|
top = Pos(-width/4, height/2 + (wall/2+width/4)*tan(radians(angle))) * Rot(0, 0, angle) * Text(CounterVal(left), font_size, font=font)
|
|
top += Pos(width/4, height/2 + (wall/2+width/4)*tan(radians(angle))) * Rot(0, 0, -angle) * Text(CounterVal(right), font_size, font=font)
|
|
|
|
part += extrude(Pos(0, 0, base_z) * top, text_z, (0, 0, 1))
|
|
|
|
super().__init__(part=part, rotation=rotation, align=align, mode=mode)
|
|
|
|
class SVGCounter(BasePartObject):
|
|
def __init__(
|
|
self,
|
|
text: str,
|
|
image: str,
|
|
image_yoff: float = 0,
|
|
font_mul: float = 1,
|
|
font: str = "Arial Rounded MT Bold",
|
|
width: float = 25 * MM,
|
|
height: float = 25 * MM,
|
|
angle: float = 22.5,
|
|
wall: float = 1 * MM,
|
|
base_z: float = 1 * MM,
|
|
text_z: float = 0.5 * MM,
|
|
rotation: VectorLike = (0, 0, 0),
|
|
align: tuple[Align, Align] = (Align.CENTER, Align.CENTER),
|
|
mode: Mode = Mode.ADD,
|
|
):
|
|
part = extrude(Chevron(width, height, angle, align=(Align.CENTER, Align.MIN)), base_z + text_z, (0, 0, 1))
|
|
part -= extrude(Pos(0, wall + wall*tan(radians(angle)), base_z + text_z) * Chevron(width-2*wall, height-2*wall, angle, align=(Align.CENTER, Align.MIN)), text_z, (0, 0, -1))
|
|
|
|
font_size = width/6 * font_mul
|
|
top = Pos(0, width/2*tan(radians(angle)) + wall + 2*font_size/3) * Text(text, font_size, font=font, align=(Align.CENTER, Align.NONE))
|
|
|
|
svg = import_svg(image, align=(Align.CENTER, Align.MIN))
|
|
svg_max_x = max([x.bounding_box().max.X for x in svg.faces()])
|
|
svg_max_y = max([x.bounding_box().max.Y for x in svg.faces()])
|
|
svg_min_x = min([x.bounding_box().min.X for x in svg.faces()])
|
|
svg_min_y = min([x.bounding_box().min.Y for x in svg.faces()])
|
|
svg_size = (svg_max_x - svg_min_x, svg_max_y - svg_min_y)
|
|
svg_scale = min(width/svg_size[0] * 0.6, height/svg_size[1] * 0.6)
|
|
|
|
svg_obj = [Pos(0, height + wall + image_yoff*svg_scale - svg_size[1]*svg_scale) * face for face in svg.faces()]
|
|
top += scale(svg_obj, (svg_scale, svg_scale, svg_scale))
|
|
|
|
part += extrude(Pos(0, 0, base_z) * top, text_z, (0, 0, 1))
|
|
|
|
super().__init__(part=part, rotation=rotation, align=align, mode=mode)
|
|
|
|
class Holder(BasePartObject):
|
|
def __init__(
|
|
self,
|
|
rotation: VectorLike = (0, 0, 0),
|
|
align: tuple[Align, Align] = (Align.CENTER, Align.CENTER),
|
|
mode: Mode = Mode.ADD,
|
|
):
|
|
cut = 5 * MM
|
|
max_depth = 36 * MM - cut
|
|
depth = max_depth
|
|
part = import_step("multibin_insert_2_2_1.step")
|
|
insert_top = part.faces().sort_by(SortBy.AREA)[-1]
|
|
part -= extrude(Plane(insert_top) * (Pos(0, 0, 2*MM) * Rectangle(500*MM, 500*MM)), cut, (0, 0, -1))
|
|
part -= extrude(insert_top, cut + depth, (0, 0, -1))
|
|
super().__init__(part=part, rotation=rotation, align=align, mode=mode)
|
|
|
|
number_counters = [
|
|
(1, 1),
|
|
(5, 5),
|
|
(10, 10),
|
|
(-1, -1),
|
|
(-5, -5),
|
|
(1, 0),
|
|
(5, 0),
|
|
(10, 0),
|
|
(0, 1),
|
|
(0, 5),
|
|
(0, 10),
|
|
(1, -1),
|
|
]
|
|
|
|
image_counters = {
|
|
"Deathtouch": (2, 0.9),
|
|
"Double Strike": (0, 0.8),
|
|
"First Strike": (0, 1),
|
|
"Goad": (0, 1),
|
|
"Flying": (2, 1),
|
|
"Haste": (-3, 1),
|
|
"Hexproof": (0, 1),
|
|
"Indestructible": (0, 0.8),
|
|
"Lifelink": (-2, 1),
|
|
"Lore": (0, 1),
|
|
"Menace": (-2, 1),
|
|
"Reach": (-3, 1),
|
|
"Ringbearer": (2, 1),
|
|
"Shield": (-2, 1),
|
|
"Stun": (-2, 1),
|
|
"Time": (0, 1),
|
|
"Trample": (0, 1),
|
|
"Vigilance": (-1.5, 1),
|
|
"Charge": (0, 1),
|
|
}
|
|
|
|
xoff = 25 * MM
|
|
yoff = 25 * MM
|
|
|
|
export = True
|
|
one = True
|
|
display_objects = []
|
|
for idx, numbers in enumerate(number_counters):
|
|
counter = NumericalCounter(numbers[0], numbers[1])
|
|
display_objects.append(Pos((xoff + 1 * MM) * idx, 0) * counter)
|
|
if export:
|
|
export_step(counter, f"step/counter_{NumStr(numbers[0])}_{NumStr(numbers[1])}.step")
|
|
export_stl(counter, f"stl/counter_{NumStr(numbers[0])}_{NumStr(numbers[1])}.stl")
|
|
if one:
|
|
break
|
|
|
|
for idx, (text, (y_off, font_mul)) in enumerate(image_counters.items()):
|
|
counter = SVGCounter(text, f"svg/{text.lower().replace(' ', '')}.svg", y_off, font_mul)
|
|
display_objects.append(Pos((xoff + 1 * MM) * idx, yoff + 1 * MM) * counter)
|
|
if export:
|
|
export_step(counter, f"step/counter_{text.lower().replace(' ', '')}.step")
|
|
export_stl(counter, f"stl/counter_{text.lower().replace(' ', '')}.stl")
|
|
if one:
|
|
break
|
|
|
|
holder = Holder()
|
|
display_objects.append(Pos(0, 4*xoff) * holder)
|
|
if export:
|
|
export_stl(holder, "holder.stl")
|
|
export_step(holder, "holder.step")
|
|
|
|
show(display_objects) |