From de9efc034aac344f160aa8f376c0617b519778bc Mon Sep 17 00:00:00 2001 From: zhouxinyu Date: Fri, 26 Jul 2024 15:35:52 +0800 Subject: [PATCH 1/3] feat: support catmull-rom curve, closed #1320 --- .../feat-catmull-rom_2024-07-26-07-35.json | 10 + .../src/common/segment/catmull-rom.ts | 175 ++++++++++++++++++ .../vrender-core/src/common/segment/index.ts | 5 +- packages/vrender-core/src/graphic/area.ts | 2 +- packages/vrender-core/src/graphic/config.ts | 6 +- packages/vrender-core/src/graphic/line.ts | 2 +- .../src/interface/graphic/area.ts | 1 + .../src/interface/graphic/line.ts | 1 + .../contributions/render/area-render.ts | 19 +- .../contributions/render/line-render.ts | 8 +- 10 files changed, 215 insertions(+), 14 deletions(-) create mode 100644 common/changes/@visactor/vrender-core/feat-catmull-rom_2024-07-26-07-35.json create mode 100644 packages/vrender-core/src/common/segment/catmull-rom.ts diff --git a/common/changes/@visactor/vrender-core/feat-catmull-rom_2024-07-26-07-35.json b/common/changes/@visactor/vrender-core/feat-catmull-rom_2024-07-26-07-35.json new file mode 100644 index 000000000..ce479f56a --- /dev/null +++ b/common/changes/@visactor/vrender-core/feat-catmull-rom_2024-07-26-07-35.json @@ -0,0 +1,10 @@ +{ + "changes": [ + { + "packageName": "@visactor/vrender-core", + "comment": "feat: support catmull-rom curve, closed #1320", + "type": "none" + } + ], + "packageName": "@visactor/vrender-core" +} diff --git a/packages/vrender-core/src/common/segment/catmull-rom.ts b/packages/vrender-core/src/common/segment/catmull-rom.ts new file mode 100644 index 000000000..1430c633a --- /dev/null +++ b/packages/vrender-core/src/common/segment/catmull-rom.ts @@ -0,0 +1,175 @@ +import { epsilon, type IPointLike } from '@visactor/vutils'; +import { genLinearSegments } from './linear'; +import { genCurveSegments, genSegContext } from './common'; +import type { ICurvedSegment, IGenSegmentParams, ILinearSegment, ISegPath2D } from '../../interface/curve'; + +/** + * 部分源码参考 https://github.com/d3/d3-shape/ + * Copyright 2010-2022 Mike Bostock + + Permission to use, copy, modify, and/or distribute this software for any purpose + with or without fee is hereby granted, provided that the above copyright notice + and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH + REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, + INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS + OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF + THIS SOFTWARE. + */ + +// 基于d3-shape重构 +// https://github.com/d3/d3-shape/blob/main/src/curve/basis.js +export function point(curveClass: CatmullRom, x: number, y: number, defined: boolean, p: IPointLike) { + let x1 = curveClass._x1; + let y1 = curveClass._y1; + let x2 = curveClass._x2; + let y2 = curveClass._y2; + + if (curveClass._l01_a > epsilon) { + const a = 2 * curveClass._l01_2a + 3 * curveClass._l01_a * curveClass._l12_a + curveClass._l12_2a; + const n = 3 * curveClass._l01_a * (curveClass._l01_a + curveClass._l12_a); + x1 = (x1 * a - curveClass._x0 * curveClass._l12_2a + curveClass._x2 * curveClass._l01_2a) / n; + y1 = (y1 * a - curveClass._y0 * curveClass._l12_2a + curveClass._y2 * curveClass._l01_2a) / n; + } + + if (curveClass._l23_a > epsilon) { + const b = 2 * curveClass._l23_2a + 3 * curveClass._l23_a * curveClass._l12_a + curveClass._l12_2a; + const m = 3 * curveClass._l23_a * (curveClass._l23_a + curveClass._l12_a); + x2 = (x2 * b + curveClass._x1 * curveClass._l23_2a - x * curveClass._l12_2a) / m; + y2 = (y2 * b + curveClass._y1 * curveClass._l23_2a - y * curveClass._l12_2a) / m; + } + + curveClass.context.bezierCurveTo(x1, y1, x2, y2, curveClass._x2, curveClass._y2, defined, curveClass.lastPoint1); +} + +export class CatmullRom implements ICurvedSegment { + private _lastDefined1?: boolean; + private _lastDefined2?: boolean; + declare context: ISegPath2D; + + protected startPoint?: IPointLike; + lastPoint0?: IPointLike; + lastPoint1?: IPointLike; + + constructor(context: ISegPath2D, alpha: number = 0.5, startPoint?: IPointLike) { + this.context = context; + this.startPoint = startPoint; + this._alpha = alpha; + } + _alpha: number; + _x: number; + _y: number; + _x0: number; + _x1: number; + _y0: number; + _y1: number; + _x2: number; + _y2: number; + _line: number; + _point: number; + _l01_a: number; + _l12_a: number; + _l23_a: number; + _l01_2a: number; + _l12_2a: number; + _l23_2a: number; + + areaStart() { + this._line = 0; + } + areaEnd() { + this._line = NaN; + } + lineStart() { + this._x0 = this._x1 = this._x2 = this._y0 = this._y1 = this._y2 = NaN; + this._l01_a = this._l12_a = this._l23_a = this._l01_2a = this._l12_2a = this._l23_2a = this._point = 0; + } + lineEnd() { + switch (this._point) { + case 2: + this.context.lineTo( + this._x2, + this._y2, + this._lastDefined1 !== false && this._lastDefined2 !== false, + this.lastPoint1 + ); + break; + case 3: + this.point({ x: this._x2, y: this._y2 }); + break; + } + if (this._line || (this._line !== 0 && this._point === 1)) { + this.context.closePath(); + } + this._line = 1 - this._line; + } + point(p: IPointLike): void { + const { x, y } = p; + + if (this._point) { + const x23 = this._x2 - x; + const y23 = this._y2 - y; + this._l23_a = Math.sqrt((this._l23_2a = Math.pow(x23 * x23 + y23 * y23, this._alpha))); + } + + switch (this._point) { + case 0: + this._point = 1; + this._line + ? this.context.lineTo(x, y, this._lastDefined1 !== false && this._lastDefined2 !== false) + : this.context.moveTo(x, y); + break; + case 1: + this._point = 2; + break; + case 2: + this._point = 3; // falls through + default: + point(this, x, y, this._lastDefined1 !== false && this._lastDefined2 !== false, p); + break; + } + + (this._l01_a = this._l12_a), (this._l12_a = this._l23_a); + (this._l01_2a = this._l12_2a), (this._l12_2a = this._l23_2a); + (this._x0 = this._x1), (this._x1 = this._x2), (this._x2 = x); + (this._y0 = this._y1), (this._y1 = this._y2), (this._y2 = y); + + this._lastDefined1 = this._lastDefined2; + this._lastDefined2 = p.defined; + this.lastPoint0 = this.lastPoint1; + this.lastPoint1 = p; + } + + tryUpdateLength(): number { + return this.context.tryUpdateLength(); + } +} + +export function genCatmullRomTypeSegments(path: ILinearSegment, points: IPointLike[]): void { + return genCurveSegments(path, points, 2); +} + +export function genCatmullRomSegments( + points: IPointLike[], + alpha: number, + params: IGenSegmentParams = {} +): ISegPath2D | null { + const { direction, startPoint } = params; + if (points.length < 2 - Number(!!startPoint)) { + return null; + } + if (points.length < 3 - Number(!!startPoint)) { + return genLinearSegments(points, params); + } + + const segContext = genSegContext('catmullRom', direction, points); + + const gatmullRom = new CatmullRom(segContext, alpha, startPoint); + + genCatmullRomTypeSegments(gatmullRom, points); + + return segContext; +} diff --git a/packages/vrender-core/src/common/segment/index.ts b/packages/vrender-core/src/common/segment/index.ts index 8c9fce105..183e208cf 100644 --- a/packages/vrender-core/src/common/segment/index.ts +++ b/packages/vrender-core/src/common/segment/index.ts @@ -5,6 +5,7 @@ import { genBasisSegments } from './basis'; import { genMonotoneXSegments, genMonotoneYSegments } from './monotone'; import { genStepSegments } from './step'; import { genLinearClosedSegments } from './linear-closed'; +import { genCatmullRomSegments } from './catmull-rom'; export * from './linear'; export * from './linear-closed'; @@ -16,7 +17,7 @@ export * from './curve/curve-context'; export function calcLineCache( points: IPointLike[], curveType: ICurveType, - params?: { startPoint: IPointLike } + params?: { startPoint?: IPointLike; curveTension?: number } ): ISegPath2D | null { switch (curveType) { case 'linear': @@ -33,6 +34,8 @@ export function calcLineCache( return genStepSegments(points, 0, params); case 'stepAfter': return genStepSegments(points, 1, params); + case 'catmullRom': + return genCatmullRomSegments(points, params?.curveTension ?? 0.5, params); case 'linearClosed': return genLinearClosedSegments(points, params); default: diff --git a/packages/vrender-core/src/graphic/area.ts b/packages/vrender-core/src/graphic/area.ts index e216545bb..dc2f4ece6 100644 --- a/packages/vrender-core/src/graphic/area.ts +++ b/packages/vrender-core/src/graphic/area.ts @@ -7,7 +7,7 @@ import { getTheme } from './theme'; import { application } from '../application'; import { AREA_NUMBER_TYPE } from './constants'; -const AREA_UPDATE_TAG_KEY = ['segments', 'points', 'curveType', ...GRAPHIC_UPDATE_TAG_KEY]; +const AREA_UPDATE_TAG_KEY = ['segments', 'points', 'curveType', 'curveTension', ...GRAPHIC_UPDATE_TAG_KEY]; export class Area extends Graphic implements IArea { type: 'area' = 'area'; diff --git a/packages/vrender-core/src/graphic/config.ts b/packages/vrender-core/src/graphic/config.ts index 64dd74c56..5c7033e26 100644 --- a/packages/vrender-core/src/graphic/config.ts +++ b/packages/vrender-core/src/graphic/config.ts @@ -222,7 +222,8 @@ export const DefaultAreaAttribute: Required = { segments: [], curveType: 'linear', clipRange: 1, - closePath: false + closePath: false, + curveTension: 1 }; export const DefaultCircleAttribute: Required = { @@ -266,7 +267,8 @@ export const DefaultLineAttribute: Required = { curveType: 'linear', clipRange: 1, clipRangeByDimension: 'default', - closePath: false + closePath: false, + curveTension: 1 }; export const DefaultPathAttribute: Required = { diff --git a/packages/vrender-core/src/graphic/line.ts b/packages/vrender-core/src/graphic/line.ts index 633504573..5a80253ca 100644 --- a/packages/vrender-core/src/graphic/line.ts +++ b/packages/vrender-core/src/graphic/line.ts @@ -7,7 +7,7 @@ import { parsePadding, pointsInterpolation } from '../common/utils'; import { CustomPath2D } from '../common/custom-path2d'; import { LINE_NUMBER_TYPE } from './constants'; -const LINE_UPDATE_TAG_KEY = ['segments', 'points', 'curveType', ...GRAPHIC_UPDATE_TAG_KEY]; +const LINE_UPDATE_TAG_KEY = ['segments', 'points', 'curveType', 'curveTension', ...GRAPHIC_UPDATE_TAG_KEY]; export class Line extends Graphic implements ILine { type: 'line' = 'line'; diff --git a/packages/vrender-core/src/interface/graphic/area.ts b/packages/vrender-core/src/interface/graphic/area.ts index 236a96aa1..e3554bfba 100644 --- a/packages/vrender-core/src/interface/graphic/area.ts +++ b/packages/vrender-core/src/interface/graphic/area.ts @@ -9,6 +9,7 @@ export type IAreaAttribute = { curveType: ICurveType; clipRange: number; closePath: boolean; + curveTension: number; }; export type IAreaCacheItem = { diff --git a/packages/vrender-core/src/interface/graphic/line.ts b/packages/vrender-core/src/interface/graphic/line.ts index 45c04f187..11f56ff11 100644 --- a/packages/vrender-core/src/interface/graphic/line.ts +++ b/packages/vrender-core/src/interface/graphic/line.ts @@ -16,6 +16,7 @@ export type ILineAttribute = { clipRange: number; clipRangeByDimension: IClipRangeByDimensionType; closePath: boolean; // 是否封闭路径 + curveTension: number; }; export type ILineGraphicAttribute = Partial & Partial & Partial; diff --git a/packages/vrender-core/src/render/contributions/render/area-render.ts b/packages/vrender-core/src/render/contributions/render/area-render.ts index fb9841d2a..3d9f3aec9 100644 --- a/packages/vrender-core/src/render/contributions/render/area-render.ts +++ b/packages/vrender-core/src/render/contributions/render/area-render.ts @@ -44,11 +44,12 @@ import { defaultAreaTextureRenderContribution } from './contributions/area-contribution-render'; import { segments } from '../../../common/shape/arc'; +import { genCatmullRomSegments } from '../../../common/segment/catmull-rom'; function calcLineCache( points: IPointLike[], curveType: ICurveType, - params?: { direction?: IDirection; startPoint?: IPointLike } + params?: { direction?: IDirection; startPoint?: IPointLike; curveTension?: number } ): ISegPath2D | null { switch (curveType) { case 'linear': @@ -65,6 +66,8 @@ function calcLineCache( return genStepSegments(points, 0, params); case 'stepAfter': return genStepSegments(points, 1, params); + case 'catmullRom': + return genCatmullRomSegments(points, params?.curveTension ?? 0.5, params); case 'linearClosed': return genLinearClosedSegments(points, params); default: @@ -227,7 +230,8 @@ export class DefaultCanvasAreaRender extends BaseRender implements IGraph stroke = areaAttribute.stroke, fillOpacity = areaAttribute.fillOpacity, z = areaAttribute.z, - strokeOpacity = areaAttribute.strokeOpacity + strokeOpacity = areaAttribute.strokeOpacity, + curveTension = areaAttribute.curveTension } = area.attribute; const data = this.valid(area, areaAttribute, fillCb, strokeCb); @@ -282,7 +286,8 @@ export class DefaultCanvasAreaRender extends BaseRender implements IGraph startPoint.y = lastTopSeg.endY; } const data = calcLineCache(seg.points, curveType, { - startPoint + startPoint, + curveTension }); lastTopSeg = data; return data; @@ -312,7 +317,8 @@ export class DefaultCanvasAreaRender extends BaseRender implements IGraph if (bottomPoints.length > 1) { lastBottomSeg = calcLineCache( bottomPoints, - curveType === 'stepBefore' ? 'stepAfter' : curveType === 'stepAfter' ? 'stepBefore' : curveType + curveType === 'stepBefore' ? 'stepAfter' : curveType === 'stepAfter' ? 'stepBefore' : curveType, + { curveTension } ); bottomCaches.unshift(lastBottomSeg); } @@ -331,10 +337,11 @@ export class DefaultCanvasAreaRender extends BaseRender implements IGraph y: points[i].y1 ?? points[i].y }); } - const topCache = calcLineCache(topPoints, curveType); + const topCache = calcLineCache(topPoints, curveType, { curveTension }); const bottomCache = calcLineCache( bottomPoints, - curveType === 'stepBefore' ? 'stepAfter' : curveType === 'stepAfter' ? 'stepBefore' : curveType + curveType === 'stepBefore' ? 'stepAfter' : curveType === 'stepAfter' ? 'stepBefore' : curveType, + { curveTension } ); area.cacheArea = { top: topCache, bottom: bottomCache }; diff --git a/packages/vrender-core/src/render/contributions/render/line-render.ts b/packages/vrender-core/src/render/contributions/render/line-render.ts index 0cc929519..455d43b2a 100644 --- a/packages/vrender-core/src/render/contributions/render/line-render.ts +++ b/packages/vrender-core/src/render/contributions/render/line-render.ts @@ -267,7 +267,8 @@ export class DefaultCanvasLineRender extends BaseRender implements IGraph strokeOpacity = lineAttribute.strokeOpacity, segments, points, - closePath + closePath, + curveTension = lineAttribute.curveTension } = line.attribute; const data = this.valid(line, lineAttribute, fillCb, strokeCb); @@ -337,7 +338,8 @@ export class DefaultCanvasLineRender extends BaseRender implements IGraph startPoint.defined = lastSeg.curves[lastSeg.curves.length - 1].defined; } const data = calcLineCache(seg.points, curveType, { - startPoint + startPoint, + curveTension }); lastSeg = data; return data; @@ -362,7 +364,7 @@ export class DefaultCanvasLineRender extends BaseRender implements IGraph line.cache[line.cache.length - 1] && line.cache[line.cache.length - 1].lineTo(startP.x, startP.y, true); } } else if (points && points.length) { - line.cache = calcLineCache(_points, curveType); + line.cache = calcLineCache(_points, curveType, { curveTension }); } else { line.cache = null; line.clearUpdateShapeTag(); From 749b1e6d79d58579abc3996526ded4855c0a9523 Mon Sep 17 00:00:00 2001 From: zhouxinyu Date: Fri, 26 Jul 2024 15:48:13 +0800 Subject: [PATCH 2/3] feat: support catmull-rom-closed --- .../feat-catmull-rom_2024-07-26-07-35.json | 2 +- .../src/common/segment/catmull-rom-close.ts | 159 ++++++++++++++++++ .../vrender-core/src/common/segment/index.ts | 3 + .../contributions/render/area-render.ts | 3 + 4 files changed, 166 insertions(+), 1 deletion(-) create mode 100644 packages/vrender-core/src/common/segment/catmull-rom-close.ts diff --git a/common/changes/@visactor/vrender-core/feat-catmull-rom_2024-07-26-07-35.json b/common/changes/@visactor/vrender-core/feat-catmull-rom_2024-07-26-07-35.json index ce479f56a..88fc37d81 100644 --- a/common/changes/@visactor/vrender-core/feat-catmull-rom_2024-07-26-07-35.json +++ b/common/changes/@visactor/vrender-core/feat-catmull-rom_2024-07-26-07-35.json @@ -2,7 +2,7 @@ "changes": [ { "packageName": "@visactor/vrender-core", - "comment": "feat: support catmull-rom curve, closed #1320", + "comment": "feat: support catmull-rom and catmull-rom-closed curve, closed #1320", "type": "none" } ], diff --git a/packages/vrender-core/src/common/segment/catmull-rom-close.ts b/packages/vrender-core/src/common/segment/catmull-rom-close.ts new file mode 100644 index 000000000..7987d3878 --- /dev/null +++ b/packages/vrender-core/src/common/segment/catmull-rom-close.ts @@ -0,0 +1,159 @@ +import { epsilon, type IPointLike } from '@visactor/vutils'; +import { genLinearSegments } from './linear'; +import { genCurveSegments, genSegContext } from './common'; +import type { ICurvedSegment, IGenSegmentParams, ILinearSegment, ISegPath2D } from '../../interface/curve'; +import { point } from './catmull-rom'; + +export class CatmullRomClosed implements ICurvedSegment { + private _lastDefined1?: boolean; + private _lastDefined2?: boolean; + declare context: ISegPath2D; + + protected startPoint?: IPointLike; + lastPoint0?: IPointLike; + lastPoint1?: IPointLike; + + constructor(context: ISegPath2D, alpha: number = 0.5, startPoint?: IPointLike) { + this.context = context; + this.startPoint = startPoint; + this._alpha = alpha; + } + _alpha: number; + _x: number; + _y: number; + _x0: number; + _x1: number; + _y0: number; + _y1: number; + _x2: number; + _y2: number; + _x3: number; + _y3: number; + _x4: number; + _y4: number; + _x5: number; + _y5: number; + _line: number; + _point: number; + _l01_a: number; + _l12_a: number; + _l23_a: number; + _l01_2a: number; + _l12_2a: number; + _l23_2a: number; + + areaStart() { + this._line = 0; + } + areaEnd() { + this._line = NaN; + } + lineStart() { + this._x0 = + this._x1 = + this._x2 = + this._x3 = + this._x4 = + this._x5 = + this._y0 = + this._y1 = + this._y2 = + this._y3 = + this._y4 = + this._y5 = + NaN; + this._l01_a = this._l12_a = this._l23_a = this._l01_2a = this._l12_2a = this._l23_2a = this._point = 0; + } + lineEnd() { + switch (this._point) { + case 1: { + this.context.moveTo(this._x3, this._y3, this.lastPoint1); + this.context.closePath(); + break; + } + case 2: { + this.context.lineTo( + this._x3, + this._y3, + this._lastDefined1 !== false && this._lastDefined2 !== false, + this.lastPoint1 + ); + this.context.closePath(); + break; + } + case 3: { + this.point({ x: this._x3, y: this._y3 }); + this.point({ x: this._x4, y: this._y4 }); + this.point({ x: this._x5, y: this._y5 }); + break; + } + } + } + point(p: IPointLike): void { + const { x, y } = p; + + if (this._point) { + const x23 = this._x2 - x; + const y23 = this._y2 - y; + this._l23_a = Math.sqrt((this._l23_2a = Math.pow(x23 * x23 + y23 * y23, this._alpha))); + } + + switch (this._point) { + case 0: + this._point = 1; + (this._x3 = x), (this._y3 = y); + break; + case 1: + this._point = 2; + this.context.moveTo((this._x4 = x), (this._y4 = y), p); + break; + case 2: + this._point = 3; + (this._x5 = x), (this._y5 = y); + break; + default: + point(this as any, x, y, this._lastDefined1 !== false && this._lastDefined2 !== false, p); + break; + } + + (this._l01_a = this._l12_a), (this._l12_a = this._l23_a); + (this._l01_2a = this._l12_2a), (this._l12_2a = this._l23_2a); + (this._x0 = this._x1), (this._x1 = this._x2), (this._x2 = x); + (this._y0 = this._y1), (this._y1 = this._y2), (this._y2 = y); + + this._lastDefined1 = this._lastDefined2; + this._lastDefined2 = p.defined; + this.lastPoint0 = this.lastPoint1; + this.lastPoint1 = p; + } + + tryUpdateLength(): number { + return this.context.tryUpdateLength(); + } +} + +export function genCatmullRomClosedTypeSegments(path: ILinearSegment, points: IPointLike[]): void { + return genCurveSegments(path, points, 2); +} + +export function genCatmullRomClosedSegments( + points: IPointLike[], + alpha: number, + params: IGenSegmentParams = {} +): ISegPath2D | null { + const { direction, startPoint } = params; + if (points.length < 2 - Number(!!startPoint)) { + return null; + } + if (points.length < 3 - Number(!!startPoint)) { + return genLinearSegments(points, params); + } + + const segContext = genSegContext('catmullRom', direction, points); + + const gatmullRom = new CatmullRomClosed(segContext, alpha, startPoint); + + genCatmullRomClosedTypeSegments(gatmullRom, points); + + return segContext; +} diff --git a/packages/vrender-core/src/common/segment/index.ts b/packages/vrender-core/src/common/segment/index.ts index 183e208cf..18cf57514 100644 --- a/packages/vrender-core/src/common/segment/index.ts +++ b/packages/vrender-core/src/common/segment/index.ts @@ -6,6 +6,7 @@ import { genMonotoneXSegments, genMonotoneYSegments } from './monotone'; import { genStepSegments } from './step'; import { genLinearClosedSegments } from './linear-closed'; import { genCatmullRomSegments } from './catmull-rom'; +import { genCatmullRomClosedSegments } from './catmull-rom-close'; export * from './linear'; export * from './linear-closed'; @@ -36,6 +37,8 @@ export function calcLineCache( return genStepSegments(points, 1, params); case 'catmullRom': return genCatmullRomSegments(points, params?.curveTension ?? 0.5, params); + case 'catmullRomClosed': + return genCatmullRomClosedSegments(points, params?.curveTension ?? 0.5, params); case 'linearClosed': return genLinearClosedSegments(points, params); default: diff --git a/packages/vrender-core/src/render/contributions/render/area-render.ts b/packages/vrender-core/src/render/contributions/render/area-render.ts index 3d9f3aec9..f526dec17 100644 --- a/packages/vrender-core/src/render/contributions/render/area-render.ts +++ b/packages/vrender-core/src/render/contributions/render/area-render.ts @@ -45,6 +45,7 @@ import { } from './contributions/area-contribution-render'; import { segments } from '../../../common/shape/arc'; import { genCatmullRomSegments } from '../../../common/segment/catmull-rom'; +import { genCatmullRomClosedSegments } from '../../../common/segment/catmull-rom-close'; function calcLineCache( points: IPointLike[], @@ -68,6 +69,8 @@ function calcLineCache( return genStepSegments(points, 1, params); case 'catmullRom': return genCatmullRomSegments(points, params?.curveTension ?? 0.5, params); + case 'catmullRomClosed': + return genCatmullRomClosedSegments(points, params?.curveTension ?? 0.5, params); case 'linearClosed': return genLinearClosedSegments(points, params); default: From 6af878b6d66a8eca5b99b27790e5179e228769b4 Mon Sep 17 00:00:00 2001 From: zhouxinyu Date: Tue, 30 Jul 2024 11:04:49 +0800 Subject: [PATCH 3/3] feat: merge duplicate codes --- .../src/common/segment/catmull-rom-close.ts | 44 +++++++------ .../src/common/segment/catmull-rom.ts | 66 +++++++++++++------ 2 files changed, 70 insertions(+), 40 deletions(-) diff --git a/packages/vrender-core/src/common/segment/catmull-rom-close.ts b/packages/vrender-core/src/common/segment/catmull-rom-close.ts index 7987d3878..60d617845 100644 --- a/packages/vrender-core/src/common/segment/catmull-rom-close.ts +++ b/packages/vrender-core/src/common/segment/catmull-rom-close.ts @@ -2,7 +2,7 @@ import { epsilon, type IPointLike } from '@visactor/vutils'; import { genLinearSegments } from './linear'; import { genCurveSegments, genSegContext } from './common'; import type { ICurvedSegment, IGenSegmentParams, ILinearSegment, ISegPath2D } from '../../interface/curve'; -import { point } from './catmull-rom'; +import { commonGenCatmullRomSegments, point } from './catmull-rom'; export class CatmullRomClosed implements ICurvedSegment { private _lastDefined1?: boolean; @@ -132,28 +132,30 @@ export class CatmullRomClosed implements ICurvedSegment { } } -export function genCatmullRomClosedTypeSegments(path: ILinearSegment, points: IPointLike[]): void { - return genCurveSegments(path, points, 2); -} +// export function genCatmullRomClosedTypeSegments(path: ILinearSegment, points: IPointLike[]): void { +// return genCurveSegments(path, points, 2); +// } -export function genCatmullRomClosedSegments( - points: IPointLike[], - alpha: number, - params: IGenSegmentParams = {} -): ISegPath2D | null { - const { direction, startPoint } = params; - if (points.length < 2 - Number(!!startPoint)) { - return null; - } - if (points.length < 3 - Number(!!startPoint)) { - return genLinearSegments(points, params); - } +export const genCatmullRomClosedSegments = commonGenCatmullRomSegments('catmullRomClosed', CatmullRomClosed); - const segContext = genSegContext('catmullRom', direction, points); +// export function genCatmullRomClosedSegments( +// points: IPointLike[], +// alpha: number, +// params: IGenSegmentParams = {} +// ): ISegPath2D | null { +// const { direction, startPoint } = params; +// if (points.length < 2 - Number(!!startPoint)) { +// return null; +// } +// if (points.length < 3 - Number(!!startPoint)) { +// return genLinearSegments(points, params); +// } - const gatmullRom = new CatmullRomClosed(segContext, alpha, startPoint); +// const segContext = genSegContext('catmullRom', direction, points); - genCatmullRomClosedTypeSegments(gatmullRom, points); +// const gatmullRom = new CatmullRomClosed(segContext, alpha, startPoint); - return segContext; -} +// genCatmullRomClosedTypeSegments(gatmullRom, points); + +// return segContext; +// } diff --git a/packages/vrender-core/src/common/segment/catmull-rom.ts b/packages/vrender-core/src/common/segment/catmull-rom.ts index 1430c633a..905528b0b 100644 --- a/packages/vrender-core/src/common/segment/catmull-rom.ts +++ b/packages/vrender-core/src/common/segment/catmull-rom.ts @@ -2,6 +2,7 @@ import { epsilon, type IPointLike } from '@visactor/vutils'; import { genLinearSegments } from './linear'; import { genCurveSegments, genSegContext } from './common'; import type { ICurvedSegment, IGenSegmentParams, ILinearSegment, ISegPath2D } from '../../interface/curve'; +import type { ICurveType } from '../../interface'; /** * 部分源码参考 https://github.com/d3/d3-shape/ @@ -148,28 +149,55 @@ export class CatmullRom implements ICurvedSegment { } } -export function genCatmullRomTypeSegments(path: ILinearSegment, points: IPointLike[]): void { - return genCurveSegments(path, points, 2); +// export function genCatmullRomTypeSegments(path: ILinearSegment, points: IPointLike[]): void { +// return genCurveSegments(path, points, 2); +// } + +export function commonGenCatmullRomSegments(type: ICurveType, cons: any) { + return function genCatmullRomSegments( + points: IPointLike[], + alpha: number, + params: IGenSegmentParams = {} + ): ISegPath2D | null { + const { direction, startPoint } = params; + if (points.length < 2 - Number(!!startPoint)) { + return null; + } + if (points.length < 3 - Number(!!startPoint)) { + return genLinearSegments(points, params); + } + + const segContext = genSegContext(type, direction, points); + + const gatmullRom = new cons(segContext, alpha, startPoint); + + genCurveSegments(gatmullRom, points, 2); + // genCatmullRomTypeSegments(gatmullRom, points); + + return segContext; + }; } -export function genCatmullRomSegments( - points: IPointLike[], - alpha: number, - params: IGenSegmentParams = {} -): ISegPath2D | null { - const { direction, startPoint } = params; - if (points.length < 2 - Number(!!startPoint)) { - return null; - } - if (points.length < 3 - Number(!!startPoint)) { - return genLinearSegments(points, params); - } +export const genCatmullRomSegments = commonGenCatmullRomSegments('catmullRom', CatmullRom); - const segContext = genSegContext('catmullRom', direction, points); +// export function genCatmullRomSegments( +// points: IPointLike[], +// alpha: number, +// params: IGenSegmentParams = {} +// ): ISegPath2D | null { +// const { direction, startPoint } = params; +// if (points.length < 2 - Number(!!startPoint)) { +// return null; +// } +// if (points.length < 3 - Number(!!startPoint)) { +// return genLinearSegments(points, params); +// } - const gatmullRom = new CatmullRom(segContext, alpha, startPoint); +// const segContext = genSegContext('catmullRom', direction, points); - genCatmullRomTypeSegments(gatmullRom, points); +// const gatmullRom = new CatmullRom(segContext, alpha, startPoint); - return segContext; -} +// genCatmullRomTypeSegments(gatmullRom, points); + +// return segContext; +// }