Files
AFFiNE-Mirror/blocksuite/affine/block-surface/src/utils/points-on-path/index.ts
T
2024-12-20 15:38:06 +08:00

78 lines
2.0 KiB
TypeScript

import { absolutize } from '../path-data-parser/absolutize.js';
import { normalize } from '../path-data-parser/normalize.js';
import { parsePath } from '../path-data-parser/parser.js';
import { pointsOnBezierCurves, simplify } from '../points-on-curve/index.js';
import type { Point } from '../rough/geometry.js';
export function pointsOnPath(
path: string,
tolerance?: number,
distance?: number
): Point[][] {
const segments = parsePath(path);
const normalized = normalize(absolutize(segments));
const sets: Point[][] = [];
let currentPoints: Point[] = [];
let start: Point = [0, 0];
let pendingCurve: Point[] = [];
const appendPendingCurve = () => {
if (pendingCurve.length >= 4) {
currentPoints.push(...pointsOnBezierCurves(pendingCurve, tolerance));
}
pendingCurve = [];
};
const appendPendingPoints = () => {
appendPendingCurve();
if (currentPoints.length) {
sets.push(currentPoints);
currentPoints = [];
}
};
for (const { key, data } of normalized) {
switch (key) {
case 'M':
appendPendingPoints();
start = [data[0], data[1]];
currentPoints.push(start);
break;
case 'L':
appendPendingCurve();
currentPoints.push([data[0], data[1]]);
break;
case 'C':
if (!pendingCurve.length) {
const lastPoint = currentPoints.length
? currentPoints[currentPoints.length - 1]
: start;
pendingCurve.push([lastPoint[0], lastPoint[1]]);
}
pendingCurve.push([data[0], data[1]]);
pendingCurve.push([data[2], data[3]]);
pendingCurve.push([data[4], data[5]]);
break;
case 'Z':
appendPendingCurve();
currentPoints.push([start[0], start[1]]);
break;
}
}
appendPendingPoints();
if (!distance) {
return sets;
}
const out: Point[][] = [];
for (const set of sets) {
const simplifiedSet = simplify(set, distance);
if (simplifiedSet.length) {
out.push(simplifiedSet);
}
}
return out;
}