Skip to content

Instantly share code, notes, and snippets.

@mathieureguer
Created May 10, 2022 13:53
Show Gist options
  • Save mathieureguer/ca8d7eba03a9ce281e8476e48eb650ea to your computer and use it in GitHub Desktop.
Save mathieureguer/ca8d7eba03a9ce281e8476e48eb650ea to your computer and use it in GitHub Desktop.
"""
Run in Robofont.
Tries to add anchors to selected glyphs, based on the position of components in relevant glyphs.
This script is not smart enough to distinguish top and bottom anchors (sorry), it must be run again for each target_anchor_name.
Here is a typical process:
- add "_top" to the circumflex glyph (we need at least an anchor as a starting point)
- set target_anchor_name to "top"
- select the base glyphs you want anchored (both base letters and diacritic glyphs)
- run
- add "_bottom" to the cedilla glyph
- set target_anchor_name to "bottom"
- select the base glyphs you want anchored (both base letters and diacritic glyphs)
- run again
- ...
"""
target_anchor_name = "top"
prefered_reference = ["circumflexcmb", "circumflex", "circumflex.cap", "cedillacmb" "cedilla", ]
# ----------------------------------------
def get_matching_anchor_name(anchor_name):
if anchor_name.startswith("_"):
return anchor_name[1:]
else:
return "_" + anchor_name
def is_anchored(self, glyph):
if len(glyph.anchors) > 0:
return True
else:
return True
def has_anchor(glyph, anchor_name):
return anchor_name in (a.name for a in glyph.anchors)
def get_anchor_by_name(glyph, anchor_name):
for a in glyph.anchors:
if a.name == anchor_name:
return a
def has_priority_components(glyph):
has_targets = [comp.baseGlyph in prefered_reference for comp in glyph.components]
return sum(has_targets)
def sort_glyph_according_to_priority_components(glyph_list):
return sorted(references, key=lambda x: has_priority_components(x), reverse=True)
# ----------------------------------------
f = CurrentFont()
sel = f.selectedGlyphNames
reverse_comp_map = {}
for g in f:
for c in g.components:
reverse_comp_map.setdefault(c.baseGlyph, []).append(g)
for target in sel:
target_glyph = f[target]
print(f"Checking {target}")
references = reverse_comp_map.get(target, [])
for reference in sort_glyph_according_to_priority_components(references):
# only look at glyph with 2 components
# other cases create too many special cases
if len(reference.components) == 2:
# print(f"reference found {reference}")
target_comp = [comp for comp in reference.components if comp.baseGlyph == target]
if len(target_comp) > 0:
target_comp = target_comp[0]
else:
continue
other_comp = [comp for comp in reference.components if comp.baseGlyph != target]
if len(other_comp) > 0:
other_comp = other_comp[0]
else:
continue
other_glyph = f[other_comp.baseGlyph]
other_anchor_name = get_matching_anchor_name(target_anchor_name)
# print(target_anchor_name, other_anchor_name)
# print(target_glyph, other_glyph)
if has_anchor(other_glyph, other_anchor_name) and not has_anchor(target_glyph, target_anchor_name):
other_anchor = get_anchor_by_name(other_glyph, other_anchor_name)
pos_x = int(other_comp.offset[0] - target_comp.offset[0] + other_anchor.position[0])
pos_y = int(other_comp.offset[1] - target_comp.offset[1] + other_anchor.position[1])
print(f"{target_glyph.name}: added anchor {target_anchor_name} <{pos_x} {pos_y}> using {reference.name} as reference")
target_glyph.appendAnchor(name=target_anchor_name, position=(pos_x, pos_y))
# elif has_anchor(other_glyph, target_anchor_name) and not has_anchor(target_glyph, other_anchor_name):
# target_anchor = get_anchor_by_name(other_glyph, target_anchor_name)
# pos_x = int(target_anchor.position[0] - target_comp.offset[0])
# pos_y = int(target_anchor.position[1] - target_comp.offset[1])
# print(f"{target_glyph.name}: added anchor {other_anchor_name} <{pos_x} {pos_y}> using {reference.name} as reference")
# target_glyph.appendAnchor(name=other_anchor_name, position=(pos_x, pos_y))
#
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment