Files
craft-libs/vendor/linesweeper/src/generators.rs
T
dotCooCoo f14cc7f21e linesweeper: keep a copy of the crates.io 0.5.0 package in vendor/
Add the linesweeper 0.5.0 package to vendor/ with no file changed, so
that a fix to it can reach the Craft apps through this repository
without waiting for a linesweeper release. The GitHub repository its
manifest names is archived, and its README says development moved off
GitHub.

Leave out the test font (fonts live in craft-fonts), the logo artwork,
the snapshot images and the package's repository tooling. SOURCE.json
lists each with its hash.

Add a workspace exclude, a [patch.crates-io] entry, SOURCE.json with
the archive hash and per-file hashes, NOTICE and ATTRIBUTION.md rows,
and the package's tests in the backend test script. craft-prepress's
flatten feature now builds against the copy, so Cargo.lock drops the
package's registry source and checksum.
2026-11-06 19:05:18 -08:00

148 lines
4.8 KiB
Rust

//! Utilities for generating examples, benchmarks, and test cases.
use std::f64::consts::PI;
use kurbo::{Affine, BezPath};
use crate::Point;
type Contours = Vec<Vec<Point>>;
/// Generate a bunch of squares, arranged in a grid.
///
/// The top-left of the first square is at (x0, y0). Each square has size `size
/// x size`, and the distance between squares (both horizontally and vertically)
/// is `offset`.
///
/// If `slant` is non-zero, generates parallelograms instead of squares: the
/// right-hand side of each square gets translated down by `slant`.
fn squares((x0, y0): (f64, f64), size: f64, offset: f64, slant: f64, count: usize) -> Contours {
let mut ret = Vec::new();
for i in 0..count {
let x = x0 + i as f64 * offset;
for j in 0..count {
let y = y0 + j as f64 * offset;
ret.push(vec![
Point::new(x, y),
Point::new(x, y + size),
Point::new(x + size, y + size + slant),
Point::new(x + size, y + slant),
]);
}
}
ret
}
/// Generate an `n` by `n` checkerboard-like pattern with overlapping squares.
/// For `n = 3`, it looks like:
///
/// ```text
/// ┌────┐ ┌────┐ ┌────┐
/// │ │ │ │ │ │
/// │ ┌─┼─┼─┐┌─┼─┼─┐ │
/// └──┼─┘ └─┼┼─┘ └─┼──┘
/// ┌──┼─┐ ┌─┼┼─┐ ┌─┼──┐
/// │ └─┼─┼─┘└─┼─┼─┘ │
/// │ ┌─┼─┼─┐┌─┼─┼─┐ │
/// └──┼─┘ └─┼┼─┘ └─┼──┘
/// ┌──┼─┐ ┌─┼┼─┐ ┌─┼──┐
/// │ └─┼─┼─┘└─┼─┼─┘ │
/// │ │ │ │ │ │
/// └────┘ └────┘ └────┘
/// ```
///
/// We return the pattern in two parts: the outer collection of `n x n`
/// non-overlapping squares, and the inner collection of `(n - 1) x (n - 1)`
/// non-overlapping squares.
pub fn checkerboard(n: usize) -> (Contours, Contours) {
(
squares((0.0, 0.0), 30.0, 40.0, 0.0, n),
squares((20.0, 20.0), 30.0, 40.0, 0.0, n - 1),
)
}
/// Like `checkerboard`, but with no exactly-horizontal lines.
///
/// Horizontal lines have special handling in the sweep-line algorithm, so
/// their presence or absence can affect performance.
pub fn slanted_checkerboard(n: usize) -> (Contours, Contours) {
(
squares((0.0, 0.0), 30.0, 40.0, 1.0, n),
squares((20.0, 20.0), 30.0, 40.0, 1.0, n - 1),
)
}
/// The "evens" are a bunch of long, skinny parallelograms going from top-left
/// to bottom-right. The "odds" go from top-right to bottom-left.
pub fn slanties(n: usize) -> (Contours, Contours) {
let h = 20.0 * n as f64;
let mut even = Vec::new();
let mut odd = Vec::new();
for i in 0..n {
let x_off = 20.0 * i as f64;
even.push(vec![
Point::new(x_off, 0.0),
Point::new(x_off + h, h),
Point::new(x_off + h + 10.0, h),
Point::new(x_off + 10.0, 0.0),
]);
odd.push(vec![
Point::new(x_off + h, 0.0),
Point::new(x_off, h),
Point::new(x_off + 10.0, h),
Point::new(x_off + h + 10.0, 0.0),
]);
}
(even, odd)
}
/// A bunch of things that all intersect at the origin, some tangentially.
pub fn star(n: usize) -> (BezPath, BezPath) {
fn mul(p: kurbo::Point, f: f64) -> kurbo::Point {
(p.x * f, p.y * f).into()
}
let angle_increment = PI / (n as f64 * 2.0);
let mut angle = 0.0;
let mut straight = BezPath::new();
let mut bent = BezPath::new();
let p = kurbo::Point::new(1.0, 0.0);
for i in 0..n {
let p0 = Affine::rotate(angle) * p;
let p1 = Affine::rotate(angle + angle_increment) * p;
let p2 = Affine::rotate(angle + angle_increment + PI) * p;
let p3 = Affine::rotate(angle + PI) * p;
if i.is_multiple_of(2) {
straight.move_to(p0);
straight.line_to(p1);
straight.line_to(p2);
straight.line_to(p3);
straight.close_path();
} else {
let zero_ish = mul(p0, 1e-12);
let neg_zero_ish = mul(p0, -1e-12);
bent.move_to(p0);
bent.line_to(p1);
bent.curve_to(mul(p1, 2. / 3.), mul(p0.midpoint(p1), 1. / 3.), zero_ish);
bent.curve_to(mul(p2.midpoint(p3), 1. / 3.), mul(p2, 2. / 3.), p2);
bent.line_to(p3);
bent.curve_to(
mul(p3, 2. / 3.),
mul(p2.midpoint(p3), 1. / 3.),
neg_zero_ish,
);
bent.curve_to(mul(p0.midpoint(p1), 1. / 3.), mul(p0, 2. / 3.), p0);
}
angle += 2.0 * angle_increment;
}
(straight, bent)
}