Ctrl K
ComunidadGuías…

scripts/mascot-bodies/geometry.test.mjs

Rama main · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
import { describe, expect, it } from "vitest";

import { applyFit, boundsOf, fitTransform, flatten } from "./geometry.ts";

const FACE_BOX = 228.541;

/** A 100x100 box at the origin, as four degenerate cubics. */
const BOX =
  "M0 0 C33.33 0 66.67 0 100 0 C100 33.33 100 66.67 100 100 " +
  "C66.67 100 33.33 100 0 100 C0 66.67 0 33.33 0 0 Z";

describe("flatten", () => {
  it("walks a closed path into one polyline", () => {
    const polylines = flatten(BOX);
    expect(polylines).toHaveLength(1);
    expect(polylines[0].length).toBeGreaterThan(4);
  });

  it("keeps every sampled point on the box it came from", () => {
    for (const [x, y] of flatten(BOX)[0]) {
      const onEdge =
        Math.abs(x) < 0.01 || Math.abs(x - 100) < 0.01 ||
        Math.abs(y) < 0.01 || Math.abs(y - 100) < 0.01;
      expect(onEdge, `(${x}, ${y}) left the box`).toBe(true);
    }
  });
});

describe("boundsOf", () => {
  it("measures the drawn extent", () => {
    expect(boundsOf(flatten(BOX))).toEqual({
      minX: expect.closeTo(0, 2),
      minY: expect.closeTo(0, 2),
      maxX: expect.closeTo(100, 2),
      maxY: expect.closeTo(100, 2),
    });
  });
});

describe("fitTransform", () => {
  it("scales a square to fill the face box", () => {
    const fit = fitTransform({ minX: 0, minY: 0, maxX: 100, maxY: 100 });
    expect(fit.scale).toBeCloseTo(FACE_BOX / 100, 5);
  });

  it("centres the narrow axis of a tall shape", () => {
    const fit = fitTransform({ minX: 0, minY: 0, maxX: 50, maxY: 100 });
    expect(fit.scale).toBeCloseTo(FACE_BOX / 100, 5);
    // 50 wide at that scale leaves half the box spare, split evenly.
    expect(fit.tx).toBeCloseTo(FACE_BOX / 4, 3);
    expect(fit.ty).toBeCloseTo(0, 3);
  });

  it("emits the transform in the format the renderer already parses", () => {
    const fit = fitTransform({ minX: 0, minY: 0, maxX: 100, maxY: 100 });
    expect(fit.transform).toMatch(/^translate\(-?[\d.]+ -?[\d.]+\) scale\([\d.]+\)$/);
  });
});

describe("applyFit", () => {
  it("lands the shape inside the face box", () => {
    const fit = fitTransform({ minX: 0, minY: 0, maxX: 100, maxY: 100 });
    const bounds = boundsOf(applyFit(flatten(BOX), fit));
    expect(bounds.minX).toBeGreaterThanOrEqual(-0.01);
    expect(bounds.minY).toBeGreaterThanOrEqual(-0.01);
    expect(bounds.maxX).toBeLessThanOrEqual(FACE_BOX + 0.01);
    expect(bounds.maxY).toBeLessThanOrEqual(FACE_BOX + 0.01);
  });
});