#!/usr/bin/env fontforge """ Apply arch cut to uppercase A-Z and digit 2-9. Arch = planet rising from below. The arc curves UPWARD into the bottom of the glyph. The cut area is removed (transparent), not filled. """ import fontforge import os import math SRC_DIR = "/tmp/aifont_meslo" DST_DIR = "/tmp/aifont_arch" os.makedirs(DST_DIR, exist_ok=True) chars = [] for c in range(ord('A'), ord('Z')+1): chars.append(chr(c)) for c in range(ord('0'), ord('9')+1): chars.append(chr(c)) # Skip arch for round-bottom characters skip_arch = set() WIDTH = 602 # Meslo monospace width workfont = fontforge.font() workfont.em = 1000 workfont.encoding = "UnicodeFull" for g in chars: cp = ord(g) src = os.path.join(SRC_DIR, g + ".svg") if not os.path.exists(src): continue glyph = workfont.createChar(cp, g) glyph.importOutlines(src) glyph.width = WIDTH if g not in skip_arch: bb = glyph.boundingBox() xmin, ymin, xmax, ymax = bb h = ymax - ymin w = xmax - xmin # How much of the glyph bottom to cut (15%) cut_depth = h * 0.07 # Large arc radius - the "planet" rising from below # Larger radius = gentler curve radius = w * 2.5 # The arc center is below the glyph cx = (xmin + xmax) / 2.0 # Position so the top of the arc reaches cut_depth into the glyph cy = ymin - radius + cut_depth # We need to intersect the glyph with the area ABOVE the arc. # Strategy: create a large clockwise (additive) shape representing # "everything above the arc line", then intersect with the glyph. # Step 1: Clear glyph, we'll rebuild via intersection # Save current contours by using a temp approach # Better strategy using fontforge: # 1. Create a second glyph with a huge filled area that has the arc as its bottom edge # 2. Use intersect to keep only where glyph and mask overlap # Create mask glyph: a large rectangle with arc-shaped bottom mask_cp = 0xE900 mask = workfont.createChar(mask_cp, "mask") mask.clear() margin = 200 left = xmin - margin right = xmax + margin top = ymax + margin # The arc: we need points along the arc from left to right # Arc equation: (x - cx)^2 + (y - cy)^2 = radius^2 # y = cy + sqrt(radius^2 - (x-cx)^2) (upper half of circle) # Calculate arc endpoints def arc_y(x): dx = x - cx if abs(dx) > radius: return ymin return cy + math.sqrt(radius * radius - dx * dx) # Generate points along the arc n_points = 40 arc_points = [] for idx in range(n_points + 1): x = left + (right - left) * idx / n_points y = arc_y(x) arc_points.append((x, y)) pen = mask.glyphPen() # Draw clockwise: top-left -> top-right -> arc from right to left -> close pen.moveTo((left, top)) pen.lineTo((right, top)) # Go down right side to arc start pen.lineTo((right, arc_points[-1][1])) # Follow arc from right to left (reverse order) for idx in range(n_points - 1, -1, -1): pen.lineTo(arc_points[idx]) pen.closePath() pen = None # Now intersect: keep only the part of glyph inside the mask glyph.correctDirection() mask.correctDirection() # Copy mask into glyph's layer and intersect workfont.selection.select(mask_cp) workfont.copy() workfont.selection.select(cp) workfont.pasteInto() glyph.intersect() # Clean up mask mask.clear() dst = os.path.join(DST_DIR, g + ".svg") glyph.export(dst) print("Done: " + g) print("\nAll done! Results: " + DST_DIR)