from ocp_vscode import * from build123d import * from math import tan, 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}" elif val < 0: return f"-{val}" else: return f"{val}" def NumStr(val): if val < 0: return f"n{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, 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/8 top = Pos(0, x/2*tan(radians(angle)) + 2*t) * Text(text, font_size, font=font, align=(Align.CENTER, Align.MIN)) 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 = 1 * MM angle = 22.5 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, "Doublestrike": 0, "First Strike": 0, "Flying": 0, "Goad": 0, "Haste": -3, "Hexproof": 0, "Indestructible": 0, "Lifelink": -2, "Lore": 0, "Menace": -2, "Reach": -3, "Ringbearer": 2, "Shield": -2, "Stun": -2, "Time": 0, "Trample": 0, "Vigilance": -1.5, "Charge": 0, } if True: for numbers in number_counters: counter = Numerical(numbers[0], numbers[1], x, y, t, angle, base_z, text_z) 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") for text, y_off in image_counters.items(): counter = Textual(text, f"svg/{text.lower().replace(' ', '')}.svg", y_off, x, 2.5*y, t, angle, base_z, text_z) export_step(counter, f"step/counter_{text.lower().replace(' ', '')}.step") export_stl(counter, f"stl/counter_{text.lower().replace(' ', '')}.stl") else: text = "Charge" counter = Textual(text, f"svg/{text.lower().replace(' ', '')}.svg", image_counters[text], x, 2.5*y, t, angle, base_z, text_z) show(counter)