Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor: remove unused path-util functions #82

Merged
merged 5 commits into from
Jun 19, 2022
Merged
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
chore: add test cases for bbox and geometry calculation
xiaoiver committed Jun 19, 2022
commit 1ca8a75673626a0352b0bd5ece06399f62fb1ac7
75 changes: 74 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -20,7 +20,7 @@ import { gradient } from '@antv/util';
- 不使用的方法,及时删除,并保持新增方法可以按需引入
- 旧版本的不维护,如果 AntV 技术栈的旧版本需要迭代,请升级到 v3

## Path
## API

提供以下 Path 工具方法,包含转换、几何计算等。

@@ -116,6 +116,79 @@ const pathArray: CurveArray = [
const reversed = reverseCurve(pathArray);
```

### getPathBBox

获取几何定义下的包围盒,形如:

```js
export interface PathBBox {
width: number;
height: number;
x: number;
y: number;
x2: number;
y2: number;
cx: number;
cy: number;
cz: number;
}
```

```js
const bbox = getPathBBox([['M', 0, 0], ['L', 100, 0], ['L', 100, 100], ['L', 0, 100], ['Z']]);

expect(bbox).toEqual({ cx: 50, cy: 50, cz: 150, height: 100, width: 100, x: 0, x2: 100, y: 0, y2: 100 });
```

### getTotalLength

获取路径总长度。

```js
const length = getTotalLength([['M', 0, 0], ['L', 100, 0], ['L', 100, 100], ['L', 0, 100], ['Z']]);

expect(length).toEqual(400);
```

### getPointAtLength

获取路径上从起点出发,到指定距离的点。

```js
const point = getPointAtLength([['M', 0, 0], ['L', 100, 0], ['L', 100, 100], ['L', 0, 100], ['Z']], 0);
expect(point).toEqual({ x: 0, y: 0 });
```

### getPathArea

计算路径包围的面积。内部实现中首先通过 [path2Curve](#path2Curve) 转曲,再计算 cubic curve 面积,[详见](https://stackoverflow.com/a/15845996)。

### isPointInStroke

判断一个点是否在路径上,仅通过几何定义,不考虑其他样式属性例如线宽、lineJoin、miter 等。

```js
const result = isPointInStroke(segments, { x: 10, y: 10 });
```

### distanceSquareRoot

计算两点之间的距离。

方法签名如下:

```js
distanceSquareRoot(a: [number, number], b: [number, number]): number;
```

### equalizeSegments

将两条路径处理成段数相同,用于形变动画前的分割操作。

```js
const [formattedPath1, formattedPath2] = equalizeSegments(path1, path2);
```

## License

MIT@[AntV](https://github.com/antvis).
57 changes: 56 additions & 1 deletion __tests__/unit/path/equalize-segments.spec.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,63 @@
import type { PathArray } from '../../../src';
import { getDrawDirection } from '../../../src/path/util/get-draw-direction';
import { equalizeSegments } from '../../../src/path/util/equalize-segments';
import { getRotatedCurve } from '../../../src/path/util/get-rotated-curve';

describe('equalize segments', () => {
it('should calc draw direction correctly', () => {
const rotated = getRotatedCurve(
[
['M', -100, 100],
[
'C',
-99.99999999999999,
176.98003589195008,
-16.66666666666667,
225.09255832441892,
49.999999999999986,
186.60254037844388,
],
['C', 80.9401076758503, 168.73926088303568, 100, 135.72655899081636, 100, 100],
['C', 100, 23.01996410804992, 16.66666666666668, -25.092558324418903, -49.99999999999998, 13.397459621556123],
['C', -80.94010767585029, 31.2607391169643, -100, 64.27344100918364, -100, 100],
['C', -100, 100, -100, 100, -100, 100],
],
[
['M', -100, 100],
[
'C',
-99.99999999999999,
176.98003589195008,
-16.66666666666667,
225.09255832441892,
49.999999999999986,
186.60254037844388,
],
['C', 80.9401076758503, 168.73926088303568, 100, 135.72655899081636, 100, 100],
['C', 100, 23.01996410804992, 16.66666666666668, -25.092558324418903, -49.99999999999998, 13.397459621556123],
['C', -80.94010767585029, 31.2607391169643, -100, 64.27344100918364, -100, 100],
['C', -100, 100, -100, 100, -100, 100],
],
);

expect(rotated).toEqual([
['M', -100, 100],
[
'C',
-99.99999999999999,
176.98003589195008,
-16.66666666666667,
225.09255832441892,
49.999999999999986,
186.60254037844388,
],
['C', 80.9401076758503, 168.73926088303568, 100, 135.72655899081636, 100, 100],
['C', 100, 23.01996410804992, 16.66666666666668, -25.092558324418903, -49.99999999999998, 13.397459621556123],
['C', -80.94010767585029, 31.2607391169643, -100, 64.27344100918364, -100, 100],
['C', -100, 100, -100, 100, -100, 100],
]);
});

describe('get path bbox', () => {
it('should calc draw direction correctly', () => {
expect(
getDrawDirection([
2 changes: 1 addition & 1 deletion __tests__/unit/path/get-path-bbox.spec.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { getPathBBox, getPathBBoxTotalLength, PathArray } from '../../../src';
import { getPathBBox, getPathBBoxTotalLength, PathArray } from '../../../src/path';
import { parsePathString } from '../../../src/path/parser/parse-path-string';
import { getCirclePath } from './util';

21 changes: 21 additions & 0 deletions __tests__/unit/path/get-total-length.spec.ts
Original file line number Diff line number Diff line change
@@ -34,4 +34,25 @@ describe('get total length', () => {
);
expect(length).toBeCloseTo(60.56635625960637);
});

it('should calc the length of rounded rect correctly', () => {
const length = getTotalLength(
parsePathString('M2 0a2 2 0 00-2 2v12a2 2 0 002 2h12a2 2 0 002-2V2a2 2 0 00-2-2H2z') as PathArray,
);
expect(length).toBeCloseTo(60.56635625960637);
});

it('should calc the length of Q commands correctly', () => {
const reversed: PathArray = [
['M', 190, 50],
['Q', 175, 75, 160, 50],
['Q', 145, 25, 130, 50],
['Q', 115, 75, 100, 50],
['Q', 85, 25, 70, 50],
['Q', 55, 75, 40, 50],
['Q', 25, 25, 10, 50],
];
const length = getTotalLength(reversed);
expect(length).toBeCloseTo(244.25304624817215);
});
});
75 changes: 72 additions & 3 deletions __tests__/unit/path/path-2-curve.spec.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { path2Curve } from '../../../src';
import { path2Curve, PathArray } from '../../../src';
import { getCirclePath } from './util';

describe('test path to curve', () => {
@@ -97,7 +97,7 @@ describe('test path to curve', () => {
['C', 100, 23.01996410804992, 16.66666666666668, -25.092558324418903, -49.99999999999998, 13.397459621556123],
['C', -80.94010767585029, 31.2607391169643, -100, 64.27344100918364, -100, 100],
['C', -100, 100, -100, 100, -100, 100],
]);
]) as PathArray;
expect(pathArray).toEqual([
['M', -100, 100],
[
@@ -134,7 +134,7 @@ describe('test path to curve', () => {
['C', -100, 100, -100, 100, -100, 100],
],
true,
);
) as [PathArray, number[]];
expect(pathArray).toEqual([
['M', -100, 100],
[
@@ -153,4 +153,73 @@ describe('test path to curve', () => {
]);
expect(zCommandIndexes).toEqual([]);
});

it('should convert camera path', () => {
expect(
path2Curve(
'M2 4a2 2 0 0 0 -2 2v6a2 2 0 0 0 2 2h12a2 2 0 0 0 2 -2v-6a2 2 0 0 0 -2 -2h-1.172a2 2 0 0 1 -1.414 -0.586l-0.828 -0.828a2 2 0 0 0 -1.414 -0.586h-2.344a2 2 0 0 0 -1.414 0.586l-0.828 0.828a2 2 0 0 1 -1.414 0.586h-1.172zM10.5 8.5a2.5 2.5 0 0 0 -5 0a2.5 2.5 0 1 0 5 0zM2.5 6a0.5 0.5 0 0 1 0 -1a0.5 0.5 0 1 1 0 1zM11.5 8.5a3.5 3.5 0 1 1 -7 0a3.5 3.5 0 0 1 7 0z',
),
).toEqual([
['M', 2, 4],
['C', 0.8954304997175604, 3.9999999991219815, -1.3527075029566811e-16, 4.895430499717561, 0, 6],
['C', 0, 6, 0, 9.9375, 0, 12],
['C', 1.3527075029566811e-16, 13.10456950028244, 0.8954304997175604, 14.00000000087802, 2, 14],
['C', 8, 14, 10.25, 14, 14, 14],
['C', 15.104569499040734, 13.99999999912198, 16, 13.104569499040734, 16, 12],
['C', 16, 9, 16, 7.875, 16, 6],
['C', 16, 4.895430500959266, 15.104569499040734, 4.0000000008780185, 14, 4],
['C', 13.414, 4, 13.194249999999998, 4, 12.828, 4],
['C', 12.297610373455704, 3.9998867247945213, 11.788985462367364, 3.7890987493850155, 11.414, 3.414],
['C', 11, 3, 10.84475, 2.8447500000000003, 10.586, 2.5860000000000003],
['C', 10.211014537632636, 2.210901250614985, 9.702389626544296, 2.0001132752054787, 9.172, 2.0000000000000004],
['C', 8, 2.0000000000000004, 7.560500000000001, 2.0000000000000004, 6.828000000000001, 2.0000000000000004],
[
'C',
6.297610373455706,
2.0001132752054787,
5.788985462367367,
2.210901250614985,
5.4140000000000015,
2.5860000000000003,
],
['C', 5.000000000000002, 3, 4.844750000000001, 3.1552499999999997, 4.586000000000001, 3.414],
['C', 4.211014537632636, 3.7890987493850155, 3.7023896265442966, 3.9998867247945213, 3.1720000000000015, 4],
['C', 2.5860000000000016, 4, 2.3662500000000017, 4, 2.0000000000000018, 4],
['C', 2.000000000000001, 4, 2.000000000000001, 4, 2, 4],
['M', 10.5, 8.5],
['C', 10.5, 6.575499102701247, 8.416666666666666, 5.372686041889527, 6.75, 6.334936490538903],
['C', 5.976497308103742, 6.781518477924107, 5.5, 7.606836025229591, 5.5, 8.5],
['C', 5.5, 10.424500897298753, 7.583333333333334, 11.627313958110474, 9.25, 10.665063509461097],
['C', 10.023502691896258, 10.218481522075892, 10.5, 9.39316397477041, 10.5, 8.5],
['C', 10.5, 8.5, 10.5, 8.5, 10.5, 8.5],
['M', 2.5, 6],
[
'C',
2.1150998205402494,
6.000000000305956,
1.874537208444147,
5.583333333830511,
2.0669872979090567,
5.2500000003442,
],
['C', 2.1563036954051213, 5.095299461648009, 2.321367204761929, 4.999999999858005, 2.5, 5],
[
'C',
2.8849001794597506,
5.000000000305956,
3.125462791688336,
5.416666667163845,
2.933012701693495,
5.7500000003442,
],
['C', 2.8436963042354777, 5.904700538406512, 2.6786327946700927, 5.999999999858005, 2.5, 6],
['C', 2.5, 6, 2.5, 6, 2.5, 6],
['M', 11.5, 8.5],
['C', 11.5, 11.194301256218253, 8.583333333333334, 12.878239541354663, 6.250000000000001, 11.531088913245537],
['C', 5.167096231345241, 10.90587413090625, 4.5, 9.750429564678573, 4.5, 8.5],
['C', 4.5, 5.805698743781747, 7.416666666666667, 4.121760458645338, 9.75, 5.468911086754464],
['C', 10.832903768654761, 6.094125869093751, 11.5, 7.249570435321427, 11.5, 8.5],
['C', 11.5, 8.5, 11.5, 8.5, 11.5, 8.5],
]);
});
});
11 changes: 7 additions & 4 deletions src/path/convert/path-2-curve.ts
Original file line number Diff line number Diff line change
@@ -4,12 +4,15 @@ import { fixArc } from '../process/fix-arc';
import { normalizePath } from '../process/normalize-path';
import { isCurveArray } from '../util/is-curve-array';
import { segmentToCubic } from '../process/segment-2-cubic';
import type { PathArray } from '../types';
import type { CurveArray, PathArray } from '../types';
// import { fixPath } from '../process/fix-path';

export function path2Curve(pathInput: string | PathArray, needZCommandIndexes = false) {
export function path2Curve(
pathInput: string | PathArray,
needZCommandIndexes = false,
): CurveArray | [CurveArray, number[]] {
if (isCurveArray(pathInput)) {
const cloned = clonePath(pathInput);
const cloned = clonePath(pathInput) as CurveArray;
if (needZCommandIndexes) {
return [cloned, []];
} else {
@@ -19,7 +22,7 @@ export function path2Curve(pathInput: string | PathArray, needZCommandIndexes =

// fixPath will remove 'Z' command
// const path = fixPath(normalizePath(pathInput));
const path = normalizePath(pathInput) as PathArray;
const path = normalizePath(pathInput) as CurveArray;

const params = { ...paramsParser };
const allPathCommands = [];
1 change: 0 additions & 1 deletion src/path/index.ts
Original file line number Diff line number Diff line change
@@ -12,7 +12,6 @@ export { getPathArea } from './util/get-path-area';
export { getDrawDirection } from './util/get-draw-direction';
export { getPointAtLength } from './util/get-point-at-length';
export { isPointInStroke } from './util/is-point-in-stroke';
export { pathLengthFactory } from './util/path-length-factory';
export { distanceSquareRoot } from './util/distance-square-root';
export { equalizeSegments } from './util/equalize-segments';

4 changes: 2 additions & 2 deletions src/path/process/clone-path.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import type { PathArray, PathSegment } from '../types';

export function clonePath(path: PathArray | PathSegment) {
return path.map((x) => (Array.isArray(x) ? [...x] : x));
export function clonePath(path: PathArray | PathSegment): PathArray {
return path.map((x) => (Array.isArray(x) ? [...x] : x)) as PathArray;
}
10 changes: 5 additions & 5 deletions src/path/process/segment-2-cubic.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import { arcToCubic } from './arc-2-cubic';
import { quadToCubic } from './quad-2-cubic';
import { lineToCubic } from './line-2-cubic';
import type { PathSegment, ParserParams, CubicSegment, MSegment } from '../types';
import type { PathSegment, ParserParams, CSegment, MSegment } from '../types';

export function segmentToCubic(segment: PathSegment, params: ParserParams): CubicSegment | MSegment {
export function segmentToCubic(segment: PathSegment, params: ParserParams): CSegment | MSegment {
const [pathCommand] = segment;
const values = segment.slice(1).map(Number);
const [x, y] = values;
@@ -31,15 +31,15 @@ export function segmentToCubic(segment: PathSegment, params: ParserParams): Cubi
// @ts-ignore
return ['C', ...quadToCubic(...args)] as CubicSegment;
case 'L':
return ['C', ...lineToCubic(px1, py1, x, y)] as CubicSegment;
return ['C', ...lineToCubic(px1, py1, x, y)] as CSegment;
case 'Z':
// prevent NaN from divide 0
if (px1 === px && py1 === py) {
return ['C', px1, py1, px, py, px, py];
}

return ['C', ...lineToCubic(px1, py1, px, py)] as CubicSegment;
return ['C', ...lineToCubic(px1, py1, px, py)] as CSegment;
default:
}
return segment as CubicSegment;
return segment as CSegment;
}