diff --git a/counters.py b/counters.py index 09e86c2..7a7d0d4 100644 --- a/counters.py +++ b/counters.py @@ -2,9 +2,6 @@ from ocp_vscode import * from build123d import * from math import tan, sin, cos, sqrt, pi, radians -def PG(x, y, angle): - return Polygon((x, 0), (x, y), (0, y + x * tan(radians(angle))), (0, x * tan(radians(angle))), align=Align.MIN) - def CounterVal(val): if val >= 0: return f"+{val}" @@ -17,81 +14,121 @@ def NumStr(val): else: return f"{val}" -def Chevron(x, y, angle): - return PG(x/2, y, angle) + mirror(PG(x/2, y, angle), Plane.YZ) - -def Numerical(left, right, x, y, t, angle, base_z, text_z): - base = Chevron(x, y, angle) - counter = extrude(base, base_z + text_z, (0, 0, 1)) - - cutout = Pos(t/2, t + t*tan(radians(angle)), 0) * PG(x/2 - 1.5*t, y - 2*t, angle) - cutout += mirror(cutout, Plane.YZ) - cutout = Pos(0, 0, base_z + text_z) * cutout - - counter -= extrude(cutout, text_z, (0, 0, -1)) - - font_size = x/5 - - font = "Arial Rounded MT Bold" - top = Pos(-x/4, y/2 + (t/2+x/4)*tan(radians(angle))) * Rot(0, 0, angle) * Text(CounterVal(left), font_size, font=font) - top += Pos(x/4, y/2 + (t/2+x/4)*tan(radians(angle))) * Rot(0, 0, -angle) * Text(CounterVal(right), font_size, font=font) - - counter += extrude(Pos(0, 0, base_z) * top, text_z, (0, 0, 1)) - - return counter - -def Textual(text, image, image_yoff, font_mul, x, y, t, angle, base_z, text_z): - counter = extrude(Chevron(x, y, angle), base_z + text_z, (0, 0, 1)) - counter -= extrude(Pos(0, t + t*tan(radians(angle)), base_z + text_z) * Chevron(x-2*t, y-2*t, angle), text_z, (0, 0, -1)) - - font = "Arial Rounded MT Bold" - font_size = x/6 * font_mul - top = Pos(0, x/2*tan(radians(angle)) + t + 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(x/svg_size[0] * 0.6, y/svg_size[1] * 0.6) - - svg_obj = [Pos(0, y + t + 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)) - - counter += extrude(Pos(0, 0, base_z) * top, text_z, (0, 0, 1)) - - return counter - -x = 25 * MM -y = 10 * MM -t = 1 * MM -base_z = 1 * MM -text_z = 0.5 * MM -angle = 22.5 - -def Holder(x, y, angle): - fit = 1 * MM - spacing = 3 * MM - total_x = x + fit - cut_size = 85 * MM - top_cut = 5 * MM - max_depth = 30 * MM - part = import_step("multibin_insert_2_2_1.step") - insert_top = part.faces().sort_by(SortBy.AREA)[-1] - part -= extrude(insert_top, top_cut, (0, 0, -1)) - - cut_profile = Location((0, -cut_size/2, max_depth), (-90, 0, 0)) * Pos(0, -total_x/2*tan(radians(angle))) * Chevron(total_x, y + max_depth, angle) - cut_profile = Plane(insert_top) * cut_profile - - cuts = [(10, 2.5*y), (3, y), (1, y)] - for j, (num_cuts, depth) in enumerate(cuts): - cut_len = (cut_size-(num_cuts-1)*spacing)/num_cuts - for i in range(num_cuts): - part -= Pos((-1+j)*(total_x + spacing), i*cut_len + i*spacing, -depth) * extrude(cut_profile, cut_len) - - return part - +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), @@ -130,12 +167,15 @@ image_counters = { "Charge": (0, 1), } +xoff = 25 * MM +yoff = 25 * MM + export = True -one = False +one = True display_objects = [] for idx, numbers in enumerate(number_counters): - counter = Numerical(numbers[0], numbers[1], x, y, t, angle, base_z, text_z) - display_objects.append(Pos((x + 1 * MM) * idx, 0) * counter) + 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") @@ -143,16 +183,16 @@ for idx, numbers in enumerate(number_counters): break for idx, (text, (y_off, font_mul)) in enumerate(image_counters.items()): - counter = Textual(text, f"svg/{text.lower().replace(' ', '')}.svg", y_off, font_mul, x, 2.5*y, t, angle, base_z, text_z) - display_objects.append(Pos((x + 1 * MM) * idx, y + 1 * MM) * counter) + 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(x, y, angle) -display_objects.append(Pos(0, 4*x) * holder) +holder = Holder() +display_objects.append(Pos(0, 4*xoff) * holder) if export: export_stl(holder, "holder.stl") export_step(holder, "holder.step")