plottery_lib 0.14.0

Core geometry library of Plottery, a creative coding framework for generative vector graphics and pen plotting.
Documentation
# Text layout

Use cases for the [`Text`] builder.

## Anchor to a rect

[`Text::in_rect`] puts the block on the rect edge chosen by the alignments and wraps at the rect's width.

```rust
# use plottery_lib::*;
# let font = Font::bundled(BundledFont::EmsReadability);
# let settings = SampleSettings::default();
# let rect = Rect::new(V2::zero(), V2::new(12.0, 5.0));
let layer = Text::new("top right", &font)
    .size(0.5)
    .in_rect(rect)
    .align(TextAlign::Right)
    .vertical_align(VerticalAlign::Top)
    .to_layer(settings)?;
# Ok::<(), anyhow::Error>(())
```

<img src="https://raw.githubusercontent.com/TobiasGrothmann/plottery/main/lib/samples/text/in_rect.svg" width="60%" />

## Wrapping and justify

[`Wrap::Word`] breaks at spaces and after hyphens, [`Wrap::Balanced`] keeps the line count but evens out the lengths, [`Wrap::Anywhere`] breaks between characters. [`TextAlign::Justify`] stretches the spaces of every line but the last.

```rust
# use plottery_lib::*;
# let font = Font::bundled(BundledFont::EmsReadability);
# let settings = SampleSettings::default();
# let column = Rect::new(V2::zero(), V2::new(4.4, 3.4));
# let paragraph = "Pen plotters draw text as strokes.";
let layer = Text::new(paragraph, &font)
    .size(0.42)
    .in_rect(column)
    .align(TextAlign::Justify)
    .wrap(Wrap::Balanced)
    .vertical_align(VerticalAlign::Top)
    .to_layer(settings)?;
# Ok::<(), anyhow::Error>(())
```

<img src="https://raw.githubusercontent.com/TobiasGrothmann/plottery/main/lib/samples/text/wrap.svg" width="100%" />

## Fit inside a box

[`Text::fit_inside`] picks the largest em size whose wrapped block fits the rect by its font metrics. Ink can overhang a little, [`Fit::fit_inside`](crate::Fit::fit_inside) on the finished layer is exact.

```rust
# use plottery_lib::*;
# let font = Font::bundled(BundledFont::EmsReadability);
# let settings = SampleSettings::default();
# let rect = Rect::new(V2::zero(), V2::new(7.0, 2.0));
let layer = Text::new("fit inside", &font)
    .fit_inside(rect)
    .wrap(Wrap::Balanced)
    .align(TextAlign::Center)
    .vertical_align(VerticalAlign::Center)
    .to_layer(settings)?;
# Ok::<(), anyhow::Error>(())
```

<img src="https://raw.githubusercontent.com/TobiasGrothmann/plottery/main/lib/samples/text/fit_inside.svg" width="70%" />

## Fit a width

[`Text::fit_width`] sizes the text so its widest line is exactly that wide, nothing wraps.

```rust
# use plottery_lib::*;
# let font = Font::bundled(BundledFont::EmsReadability);
# let settings = SampleSettings::default();
let layer = Text::new("Plottery", &font)
    .fit_width(8.0)
    .vertical_align(VerticalAlign::Top)
    .to_layer(settings)?;
# Ok::<(), anyhow::Error>(())
```

<img src="https://raw.githubusercontent.com/TobiasGrothmann/plottery/main/lib/samples/text/fit_width.svg" width="45%" />

## Rotation

[`Text::rotation`] turns the finished block around its anchor point.

```rust
# use plottery_lib::*;
# let font = Font::bundled(BundledFont::EmsReadability);
# let settings = SampleSettings::default();
# let anchor = V2::zero();
let layer = Text::new("30 degrees", &font)
    .size(0.6)
    .at(anchor)
    .rotation(Angle::from_degrees(30.0))
    .to_layer(settings)?;
# Ok::<(), anyhow::Error>(())
```

<img src="https://raw.githubusercontent.com/TobiasGrothmann/plottery/main/lib/samples/text/rotation.svg" width="100%" />

## Per-line data

[`Text::layout`] returns every line with its origin, width and glyph range, [`TextLayout::to_layer_by_line`] makes one sublayer per line.

```rust
# use plottery_lib::*;
# let font = Font::bundled(BundledFont::EmsReadability);
# let settings = SampleSettings::default();
let layout = Text::new("Each line is a\nsublayer with an\norigin and a width", &font)
    .size(0.7)
    .layout()?;
let metrics = font.metrics(0.7);
let mut layer = layout.to_layer_by_line(settings);
layer.push_layer(Layer::new_from(layout.lines.iter().map(|line| {
    Rect::new_shape(
        line.origin + V2::up() * metrics.descender,
        line.origin + V2::new(line.width, metrics.ascender),
    )
})));
# Ok::<(), anyhow::Error>(())
```

<img src="https://raw.githubusercontent.com/TobiasGrothmann/plottery/main/lib/samples/text/lines.svg" width="40%" />