diff --git a/__tests__/unit/path/equalize-segments.spec.ts b/__tests__/unit/path/equalize-segments.spec.ts index 1d9b758..7036e40 100644 --- a/__tests__/unit/path/equalize-segments.spec.ts +++ b/__tests__/unit/path/equalize-segments.spec.ts @@ -98,4 +98,64 @@ describe('equalize segments', () => { ], ]); }); + it('should not recurse infinitely if segments cannot be split', () => { + const path1: PathArray = [ + ['M', 0, 0], + ['L', 1, 1], // 非常短的线段,不满足 split 条件 + ]; + const path2: PathArray = [ + ['M', 0, 0], + ['L', 10, 10], + ['L', 20, 20], + ['L', 30, 30], + ]; + + const result = equalizeSegments(path1, path2); + // 不是一定相等,因为可能无法拆分,重点是不会死循环 + expect(Array.isArray(result)).toBe(true); + expect(result.length).toBe(2); + }); + it('should split cubic bezier curves correctly', () => { + const path1: PathArray = [ + ['M', 0, 0], + ['C', 30, 30, 60, 30, 100, 0], + ]; + const path2: PathArray = [ + ['M', 0, 0], + ['C', 20, 20, 40, 20, 60, 0], + ['C', 70, -20, 90, -20, 100, 0], + ]; + + const result = equalizeSegments(path1, path2); + expect(result[0].length).toBe(result[1].length); + }); + it('should equalizeSegments for complex multi-segment paths', () => { + const path1: PathArray = [ + ['M', 0, 0], + ['L', 50, 0], + ['C', 60, 10, 70, 10, 80, 0], + ]; + const path2: PathArray = [ + ['M', 0, 0], + ['L', 20, 0], + ['L', 40, 0], + ['L', 60, 0], + ['C', 65, 5, 75, 5, 80, 0], + ]; + + const result = equalizeSegments(path1, path2); + expect(result[0].length).toBe(result[1].length); + }); + it('should terminate recursion at max depth', () => { + const path1: PathArray = [ + ['M', 0, 0], + ['L', 1, 1], + ]; + // @ts-ignore + const path2: PathArray = Array.from({ length: 20 }, (_, i) => ['L', i, i + 1]) as PathArray; + path2.unshift(['M', 0, 0]); + + const result = equalizeSegments(path1, path2); + expect(result.length).toBe(2); + }); }); diff --git a/package.json b/package.json index eddeec6..2eb4758 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@antv/util", - "version": "3.3.10", + "version": "3.3.11", "license": "MIT", "sideEffects": false, "main": "lib/index.js", diff --git a/src/path/util/equalize-segments.ts b/src/path/util/equalize-segments.ts index 181686a..2283dac 100644 --- a/src/path/util/equalize-segments.ts +++ b/src/path/util/equalize-segments.ts @@ -4,6 +4,8 @@ import { segmentCubicFactory } from './segment-cubic-factory'; type SplitArray = [number, number, number, number, number, number, number, number, number]; +const MAX_RECURSION_DEPTH = 50; + function splitCubic(pts: SplitArray, t = 0.5): [CurveArray, CurveArray] { const p0 = pts.slice(0, 2) as [number, number]; const p1 = pts.slice(2, 4) as [number, number]; @@ -61,7 +63,11 @@ function getCurveArray(segments: PathArray) { }); } -export function equalizeSegments(path1: PathArray, path2: PathArray, TL?: number): CurveArray[] { +export function equalizeSegments(path1: PathArray, path2: PathArray, TL?: number, depth = 0): CurveArray[] { + if (depth > MAX_RECURSION_DEPTH) { + console.warn('Maximum recursion depth reached in equalizeSegments'); + return [path1, path2] as CurveArray[]; + } const c1 = getCurveArray(path1); const c2 = getCurveArray(path2); const L1 = c1.length; @@ -87,5 +93,5 @@ export function equalizeSegments(path1: PathArray, path2: PathArray, TL?: number .flat(), ) as CurveArray[]; - return result[0].length === result[1].length ? result : equalizeSegments(result[0], result[1], tl); + return result[0].length === result[1].length ? result : equalizeSegments(result[0], result[1], tl, depth + 1); }