Skip to content

Commit

Permalink
feat(pencil tool): curve fitting
Browse files Browse the repository at this point in the history
  • Loading branch information
F-star committed May 21, 2024
1 parent b37a9ea commit 89048ca
Show file tree
Hide file tree
Showing 12 changed files with 94 additions and 24 deletions.
4 changes: 2 additions & 2 deletions packages/core/src/commands/set_elements_attrs.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { cloneDeep } from '@suika/common';
import { type IMatrixArr } from '@suika/geo';
import { type IMatrixArr, type IPathItem } from '@suika/geo';

import { type Graph, type IPathItem } from '../graphs';
import { type Graph } from '../graphs';
import { type IPaint } from '../paint';
import { type ICommand } from './type';

Expand Down
3 changes: 2 additions & 1 deletion packages/core/src/graphs/path/path.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,10 @@ import { cloneDeep, parseHexToRGBA, parseRGBAStr } from '@suika/common';
import {
addPoint,
type IMatrixArr,
type IPathItem,
type IPoint,
type IRect,
type ISegment,
type ITransformRect,
resizeLine,
resizeRect,
Expand All @@ -15,7 +17,6 @@ import { type ImgManager } from '../../Img_manager';
import { type IPaint, PaintType } from '../../paint';
import { GraphType, type Optional } from '../../type';
import { Graph, type GraphAttrs, type IGraphOpts } from '../graph';
import { type IPathItem, type ISegment } from './type';

export interface PathAttrs extends GraphAttrs {
pathData: IPathItem[];
Expand Down
15 changes: 0 additions & 15 deletions packages/core/src/graphs/path/type.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1 @@
import { type IPoint } from '@suika/geo';

export type PathSegPointType = 'in' | 'out' | 'anchor';

export interface ISegment {
point: IPoint;
/** the coordinates relative to point */
in: IPoint;
/** the coordinates relative to point */
out: IPoint;
}

export interface IPathItem {
segs: ISegment[];
closed: boolean;
}
1 change: 1 addition & 0 deletions packages/core/src/setting.ts
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,7 @@ export class Setting {

/**** tool ****/
keepToolSelectedAfterUse: false,
pencilCurveFitTolerance: 1,

/******** path control handle ******/
pathLineStroke: '#a4a4a4',
Expand Down
10 changes: 8 additions & 2 deletions packages/core/src/tools/tool_draw_path.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,17 @@
import { cloneDeep, getClosestTimesVal, parseHexToRGBA } from '@suika/common';
import { distance, type IMatrixArr, type IPoint } from '@suika/geo';
import {
distance,
type IMatrixArr,
type IPathItem,
type IPoint,
type ISegment,
} from '@suika/geo';

import { AddGraphCmd, SetGraphsAttrsCmd } from '../commands';
import { ControlHandle } from '../control_handle_manager';
import { type ICursor } from '../cursor_manager';
import { type Editor } from '../editor';
import { Ellipse, type IPathItem, type ISegment, Path } from '../graphs';
import { Ellipse, Path } from '../graphs';
import { PaintType } from '../paint';
import { PathSelectTool } from './tool_path_select';
import { type ITool } from './type';
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,14 @@
import { cloneDeep } from '@suika/common';
import { type IMatrixArr, type IPoint } from '@suika/geo';
import {
type IMatrixArr,
type IPathItem,
type IPoint,
type ISegment,
} from '@suika/geo';

import { SetGraphsAttrsCmd } from '../../commands';
import { type ICursor } from '../../cursor_manager';
import { type Editor } from '../../editor';
import { type IPathItem, type ISegment } from '../../graphs';
import { type ISelectedIdxInfo, PathEditor } from '../../path_editor';
import { type ITool } from '../type';

Expand Down
12 changes: 10 additions & 2 deletions packages/core/src/tools/tool_pencil.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { cloneDeep, noop } from '@suika/common';
import { simplePath } from '@suika/geo';

import { AddGraphCmd } from '../commands';
import { type ICursor } from '../cursor_manager';
Expand Down Expand Up @@ -71,12 +72,19 @@ export class PencilTool implements ITool {
}

onEnd(_e: PointerEvent, isDragHappened: boolean) {
const path = this.path!;
if (isDragHappened) {
const segs = path.attrs.pathData[0].segs;
const newSegs = simplePath(
segs,
this.editor.setting.get('pencilCurveFitTolerance'),
);
path.attrs.pathData[0].segs = newSegs;
this.editor.commandManager.pushCommand(
new AddGraphCmd('Add Path by pencil', this.editor, [this.path!]),
new AddGraphCmd('Add Path by pencil', this.editor, [path]),
);
} else {
this.editor.sceneGraph.removeItems([this.path!]);
this.editor.sceneGraph.removeItems([path]);
}
}

Expand Down
1 change: 1 addition & 0 deletions packages/geo/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
"build": "tsc && vite build"
},
"dependencies": {
"fit-curve": "^0.2.0",
"pixi.js": "^8.0.2"
},
"devDependencies": {
Expand Down
42 changes: 42 additions & 0 deletions packages/geo/src/geo/geo_path.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import fitCurve from 'fit-curve';

import { type ISegment } from '../type';

export const simplePath = (segs: ISegment[], tol: number) => {
const curves = fitCurve(
segs.map(({ point }) => [point.x, point.y]),
tol,
);
const newSegs: ISegment[] = [];
for (let i = 0, len = curves.length; i <= len; i++) {
const curve = curves[i];
const prevCurve = curves[i - 1];
const point = curve
? {
x: curve[0][0],
y: curve[0][1],
}
: {
x: prevCurve[3][0],
y: prevCurve[3][1],
};
const outPt = curve
? {
x: curve[1][0] - point.x,
y: curve[1][1] - point.y,
}
: { x: 0, y: 0 };
const inPt = prevCurve
? {
x: prevCurve[2][0] - point.x,
y: prevCurve[2][1] - point.y,
}
: { x: 0, y: 0 };
newSegs.push({
point,
in: inPt,
out: outPt,
});
}
return newSegs;
};
1 change: 1 addition & 0 deletions packages/geo/src/geo/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ export * from './geo_box';
export * from './geo_circle';
export * from './geo_line';
export * from './geo_matrix';
export * from './geo_path';
export * from './geo_point';
export * from './geo_polygon';
export * from './geo_rect';
Expand Down
13 changes: 13 additions & 0 deletions packages/geo/src/type/index.ts → packages/geo/src/type.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,3 +35,16 @@ export interface ICircle {
}

export type IMatrixArr = [number, number, number, number, number, number];

export interface ISegment {
point: IPoint;
/** the coordinates relative to point */
in: IPoint;
/** the coordinates relative to point */
out: IPoint;
}

export interface IPathItem {
segs: ISegment[];
closed: boolean;
}
8 changes: 8 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit 89048ca

Please sign in to comment.