Skip to content

compas_nest.text

compas_nest.text

Text to single-stroke polylines, using the OpenNest XML engraving fonts.

Ports the OpenNest single-line font (fonts/regular.xml / fonts/bold.xml): each glyph is a set of stroke paths of straight segments and bulge-arcs, normalised to a 0..1 em. :func:text_to_polylines renders a string to a list of :class:compas.geometry.Polyline (arcs sampled to segments), scaled by height and laid out left to right. Handy for sheet-number labels on a nested layout.

text_to_polylines(text, height=1.0, font='regular', frame=None, spacing=H_SPACING)

Render text to a list of single-stroke :class:compas.geometry.Polyline.

The text is laid out on the XY plane with the first line's baseline-left at the origin, then oriented/placed onto frame — so you can drop a label anywhere (e.g. on a nested sheet) with any orientation. frame axes also scale: use a frame with unit axes to keep height as the cap height.

Parameters:

Name Type Description Default
text str

The string (supports multiple lines separated by newlines).

required
height float

Cap height (em) the glyphs are scaled to.

1.0
font str

Packaged font name: "regular" or "bold".

'regular'
frame :class:`compas.geometry.Frame`

Where to place/orient the text. Its origin is the text origin, its x-axis the reading direction and y-axis "up". Defaults to the world XY frame.

None
spacing float

Extra gap between glyphs, in em.

H_SPACING

Returns:

Type Description
list[:class:`compas.geometry.Polyline`]

One polyline per stroke.

Source code in compas_nest/text.py
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
def text_to_polylines(text, height=1.0, font="regular", frame=None, spacing=H_SPACING):
    """Render ``text`` to a list of single-stroke :class:`compas.geometry.Polyline`.

    The text is laid out on the XY plane with the first line's baseline-left at the origin, then
    oriented/placed onto ``frame`` — so you can drop a label anywhere (e.g. on a nested sheet) with
    any orientation. ``frame`` axes also scale: use a frame with unit axes to keep ``height`` as the
    cap height.

    Parameters
    ----------
    text : str
        The string (supports multiple lines separated by newlines).
    height : float, optional
        Cap height (em) the glyphs are scaled to.
    font : str, optional
        Packaged font name: ``"regular"`` or ``"bold"``.
    frame : :class:`compas.geometry.Frame`, optional
        Where to place/orient the text. Its origin is the text origin, its x-axis the reading
        direction and y-axis "up". Defaults to the world XY frame.
    spacing : float, optional
        Extra gap between glyphs, in em.

    Returns
    -------
    list[:class:`compas.geometry.Polyline`]
        One polyline per stroke.
    """
    glyphs = _font(font)
    fallback = glyphs.get("\0")
    out = []
    for line_i, line in enumerate(text.split("\n")):
        x = 0.0
        y = -line_i * V_SPACING * height
        for ch in line:
            glyph = glyphs.get(ch, fallback)
            if glyph is None:
                x += (0.5 + spacing) * height
                continue
            x -= glyph["start"] * height  # account for the glyph's left bearing
            for stroke in glyph["strokes"]:
                out.append(Polyline([[x + px * height, y + py * height, 0.0] for (px, py) in stroke]))
            x += glyph["end"] * height + spacing * height

    if frame is not None:
        from compas.geometry import Transformation

        matrix = Transformation.from_frame(frame)
        out = [pl.transformed(matrix) for pl in out]
    return out