chore: contour test
This commit is contained in:
parent
92dac64326
commit
9f665fc403
|
|
@ -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);
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
Loading…
Reference in New Issue