chore: contour test

This commit is contained in:
hypercross 2026-03-15 11:45:35 +08:00
parent 92dac64326
commit 9f665fc403
1 changed files with 263 additions and 0 deletions

View File

@ -0,0 +1,263 @@
import { describe, test, expect } from '@jest/globals';
import {
getRoundedPolygonPoints,
getCardShapePoints,
getInscribedTrianglePoints,
getInscribedHexagonPoints
} from './contour';
/**
*
*/
function distance(p1: [number, number], p2: [number, number]): number {
return Math.sqrt((p2[0] - p1[0]) ** 2 + (p2[1] - p1[1]) ** 2);
}
/**
*
*/
function pointCloseTo(actual: [number, number], expected: [number, number], tolerance: number = 0.01): boolean {
return Math.abs(actual[0] - expected[0]) < tolerance &&
Math.abs(actual[1] - expected[1]) < tolerance;
}
describe('getRoundedPolygonPoints', () => {
describe('矩形圆角', () => {
test('应该生成正确的矩形圆角 (segmentsPerCorner=2)', () => {
const vertices: [number, number][] = [
[0, 0],
[100, 0],
[100, 60],
[0, 60]
];
const cornerRadius = 10;
const segmentsPerCorner = 2;
const points = getRoundedPolygonPoints(vertices, cornerRadius, segmentsPerCorner);
// 每个角应该有:起点 + 2 个弧线点 = 3 个点4 个角共 12 个点
// 但由于结构是:起点 + 弧线点 1 + 弧线点 2然后下一条边的起点就是上一个角的终点
// 所以总点数应该是 4 * (1 + 2) = 12 个点
expect(points.length).toBe(12);
// 验证第一个角(左下角,顶点 [0, 0])的起点应该在 (0, 10)
expect(pointCloseTo(points[0], [0, 10])).toBe(true);
// 验证第一个角的弧线点应该在圆上
const center0: [number, number] = [10, 10];
const arcPoint1: [number, number] = points[1];
const arcPoint2: [number, number] = points[2];
// 检查弧线点到圆心的距离是否接近半径
const dist1 = distance(arcPoint1, center0);
const dist2 = distance(arcPoint2, center0);
expect(Math.abs(dist1 - cornerRadius)).toBeLessThan(0.1);
expect(Math.abs(dist2 - cornerRadius)).toBeLessThan(0.1);
// 验证第二个角(右下角,顶点 [100, 0])的起点应该在 (90, 0)
expect(pointCloseTo(points[3], [90, 0])).toBe(true);
});
test('应该生成闭合的轮廓', () => {
const vertices: [number, number][] = [
[0, 0],
[100, 0],
[100, 60],
[0, 60]
];
const cornerRadius = 10;
const segmentsPerCorner = 4;
const points = getRoundedPolygonPoints(vertices, cornerRadius, segmentsPerCorner);
// 验证最后一个点和第一个点之间的距离应该合理(闭合路径)
const firstPoint = points[0];
const lastPoint = points[points.length - 1];
// 最后一个点应该是最后一个角的弧线终点,接近第一个点
// 实际上,由于每个角都从起点开始,最后一个点应该接近第一个角的起点
const dist = distance(firstPoint, lastPoint);
expect(dist).toBeLessThan(cornerRadius * 0.5); // 应该比较接近
});
test('圆角半径过大时应该被限制', () => {
const vertices: [number, number][] = [
[0, 0],
[20, 0],
[20, 60],
[0, 60]
];
const cornerRadius = 50; // 远大于边长的一半
const points = getRoundedPolygonPoints(vertices, cornerRadius);
// 验证所有点都在边界框内
for (const [x, y] of points) {
expect(x).toBeGreaterThanOrEqual(0);
expect(x).toBeLessThanOrEqual(20);
expect(y).toBeGreaterThanOrEqual(0);
expect(y).toBeLessThanOrEqual(60);
}
});
});
describe('三角形圆角', () => {
test('应该为三角形生成正确的圆角 (segmentsPerCorner=2)', () => {
const vertices = getInscribedTrianglePoints(100, 60);
const cornerRadius = 5;
const segmentsPerCorner = 2;
const points = getRoundedPolygonPoints(vertices, cornerRadius, segmentsPerCorner);
// 3 个角,每个角有 1 个起点 + 2 个弧线点 = 3 个点
expect(points.length).toBe(9);
// 验证所有弧线点到对应圆心的距离接近半径
// (这里简化验证,只检查点数和合理性)
expect(points.length).toBeGreaterThan(0);
// 验证所有点都在边界框内
for (const [x, y] of points) {
expect(x).toBeGreaterThanOrEqual(0);
expect(x).toBeLessThanOrEqual(100);
expect(y).toBeGreaterThanOrEqual(0);
expect(y).toBeLessThanOrEqual(60);
}
});
});
describe('六边形圆角', () => {
test('应该为六边形生成正确的圆角 (segmentsPerCorner=2)', () => {
const vertices = getInscribedHexagonPoints(100, 60);
const cornerRadius = 5;
const segmentsPerCorner = 2;
const points = getRoundedPolygonPoints(vertices, cornerRadius, segmentsPerCorner);
// 6 个角,每个角有 1 个起点 + 2 个弧线点 = 3 个点
expect(points.length).toBe(18);
// 验证所有点都在边界框内
for (const [x, y] of points) {
expect(x).toBeGreaterThanOrEqual(0);
expect(x).toBeLessThanOrEqual(100);
expect(y).toBeGreaterThanOrEqual(0);
expect(y).toBeLessThanOrEqual(60);
}
});
});
describe('边界情况', () => {
test('圆角半径为 0 时返回原始顶点', () => {
const vertices: [number, number][] = [
[0, 0],
[100, 0],
[100, 60],
[0, 60]
];
const points = getRoundedPolygonPoints(vertices, 0);
expect(points).toEqual(vertices);
});
test('顶点数少于 3 个时返回原始顶点', () => {
const line: [number, number][] = [[0, 0], [100, 0]];
const points = getRoundedPolygonPoints(line, 10);
expect(points).toEqual(line);
});
});
});
describe('getCardShapePoints', () => {
describe('矩形', () => {
test('无圆角矩形', () => {
const points = getCardShapePoints('rectangle', 100, 60, 0);
expect(points.length).toBe(4);
expect(points).toEqual([
[0, 0],
[100, 0],
[100, 60],
[0, 60]
]);
});
test('带圆角矩形 (segmentsPerCorner=2)', () => {
const points = getCardShapePoints('rectangle', 100, 60, 10, 2);
// 4 个角,每个角有 1 个起点 + 2 个弧线点 = 3 个点
expect(points.length).toBe(12);
// 验证第一个点在左边y 坐标为圆角半径
expect(pointCloseTo(points[0], [0, 10])).toBe(true);
});
test('圆角矩形应该是对称的', () => {
const width = 100;
const height = 60;
const cornerRadius = 10;
const segmentsPerCorner = 4;
const points = getCardShapePoints('rectangle', width, height, cornerRadius, segmentsPerCorner);
// 验证左右对称
const leftPoints = points.filter(([x]) => x < width / 2);
const rightPoints = points.filter(([x]) => x > width / 2);
expect(leftPoints.length).toBe(rightPoints.length);
// 验证上下对称
const topPoints = points.filter(([, y]) => y < height / 2);
const bottomPoints = points.filter(([, y]) => y > height / 2);
expect(topPoints.length).toBe(bottomPoints.length);
});
});
describe('三角形', () => {
test('无圆角三角形', () => {
const points = getCardShapePoints('triangle', 100, 60, 0);
expect(points.length).toBe(3);
});
test('带圆角三角形 (segmentsPerCorner=2)', () => {
const points = getCardShapePoints('triangle', 100, 60, 10, 2);
// 3 个角,每个角有 1 个起点 + 2 个弧线点 = 3 个点
expect(points.length).toBe(9);
});
});
describe('六边形', () => {
test('无圆角六边形', () => {
const points = getCardShapePoints('hexagon', 100, 60, 0);
expect(points.length).toBe(6);
});
test('带圆角六边形 (segmentsPerCorner=2)', () => {
const points = getCardShapePoints('hexagon', 100, 60, 10, 2);
// 6 个角,每个角有 1 个起点 + 2 个弧线点 = 3 个点
expect(points.length).toBe(18);
});
});
describe('圆形', () => {
test('圆形轮廓', () => {
const points = getCardShapePoints('circle', 100, 60, 0);
// 圆形固定生成 36 个点
expect(points.length).toBe(36);
// 验证所有点到中心的距离接近半径
const centerX = 50;
const centerY = 30;
const radius = 30; // min(100, 60) / 2
for (const [x, y] of points) {
const dist = distance([x, y], [centerX, centerY]);
expect(Math.abs(dist - radius)).toBeLessThan(0.1);
}
});
});
});