mirror of
https://github.com/excalidraw/excalidraw.git
synced 2025-05-03 10:00:07 -04:00
Type refactor
Signed-off-by: Mark Tolmacs <mark@lazycat.hu>
This commit is contained in:
parent
47064a3662
commit
2137f2b806
6 changed files with 63 additions and 262 deletions
|
@ -12,10 +12,10 @@ import {
|
||||||
TrashIcon,
|
TrashIcon,
|
||||||
} from "../../packages/excalidraw/components/icons";
|
} from "../../packages/excalidraw/components/icons";
|
||||||
import { STORAGE_KEYS } from "../app_constants";
|
import { STORAGE_KEYS } from "../app_constants";
|
||||||
import type { Arc, CubicBezier } from "../../packages/math";
|
import type { Arc, Curve } from "../../packages/math";
|
||||||
import {
|
import {
|
||||||
isArc,
|
isArc,
|
||||||
isBezier,
|
isCurve,
|
||||||
isSegment,
|
isSegment,
|
||||||
type GlobalPoint,
|
type GlobalPoint,
|
||||||
type Segment,
|
type Segment,
|
||||||
|
@ -39,7 +39,7 @@ const renderLine = (
|
||||||
const renderCubicBezier = (
|
const renderCubicBezier = (
|
||||||
context: CanvasRenderingContext2D,
|
context: CanvasRenderingContext2D,
|
||||||
zoom: number,
|
zoom: number,
|
||||||
{ start, control1, control2, end }: CubicBezier<GlobalPoint>,
|
[start, control1, control2, end]: Curve<GlobalPoint>,
|
||||||
color: string,
|
color: string,
|
||||||
) => {
|
) => {
|
||||||
context.save();
|
context.save();
|
||||||
|
@ -113,11 +113,11 @@ const render = (
|
||||||
el.color,
|
el.color,
|
||||||
);
|
);
|
||||||
break;
|
break;
|
||||||
case isBezier(el.data):
|
case isCurve(el.data):
|
||||||
renderCubicBezier(
|
renderCubicBezier(
|
||||||
context,
|
context,
|
||||||
appState.zoom.value,
|
appState.zoom.value,
|
||||||
el.data as CubicBezier<GlobalPoint>,
|
el.data as Curve<GlobalPoint>,
|
||||||
el.color,
|
el.color,
|
||||||
);
|
);
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -164,14 +164,14 @@ export const getElementShape = (
|
||||||
const [, , , , cx, cy] = getElementAbsoluteCoords(element, elementsMap);
|
const [, , , , cx, cy] = getElementAbsoluteCoords(element, elementsMap);
|
||||||
|
|
||||||
return shouldTestInside(element)
|
return shouldTestInside(element)
|
||||||
? getClosedCurveShape<GlobalPoint>(
|
? getClosedCurveShape(
|
||||||
element,
|
element,
|
||||||
roughShape,
|
roughShape,
|
||||||
pointFrom<GlobalPoint>(element.x, element.y),
|
pointFrom<GlobalPoint>(element.x, element.y),
|
||||||
element.angle,
|
element.angle,
|
||||||
pointFrom(cx, cy),
|
pointFrom(cx, cy),
|
||||||
)
|
)
|
||||||
: getCurveShape<GlobalPoint>(
|
: getCurveShape(
|
||||||
roughShape,
|
roughShape,
|
||||||
pointFrom<GlobalPoint>(element.x, element.y),
|
pointFrom<GlobalPoint>(element.x, element.y),
|
||||||
element.angle,
|
element.angle,
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import type { Arc, CubicBezier, Segment } from "../math";
|
import type { Arc, Curve, Segment } from "../math";
|
||||||
import { isSegment, segment, pointFrom, type GlobalPoint } from "../math";
|
import { isSegment, segment, pointFrom, type GlobalPoint } from "../math";
|
||||||
import { isBounds } from "./element/typeChecks";
|
import { isBounds } from "./element/typeChecks";
|
||||||
import type { Bounds } from "./element/types";
|
import type { Bounds } from "./element/types";
|
||||||
|
@ -15,12 +15,12 @@ declare global {
|
||||||
|
|
||||||
export type DebugElement = {
|
export type DebugElement = {
|
||||||
color: string;
|
color: string;
|
||||||
data: Segment<GlobalPoint> | Arc<GlobalPoint> | CubicBezier<GlobalPoint>;
|
data: Segment<GlobalPoint> | Arc<GlobalPoint> | Curve<GlobalPoint>;
|
||||||
permanent: boolean;
|
permanent: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const debugDrawCubicBezier = (
|
export const debugDrawCubicBezier = (
|
||||||
c: CubicBezier<GlobalPoint>,
|
c: Curve<GlobalPoint>,
|
||||||
opts?: {
|
opts?: {
|
||||||
color?: string;
|
color?: string;
|
||||||
permanent?: boolean;
|
permanent?: boolean;
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import { isPoint, pointFrom, pointRotateRads } from "./point";
|
import { isPoint, pointRotateRads } from "./point";
|
||||||
import type { CubicBezier, Curve, GenericPoint, Radians } from "./types";
|
import type { Curve, GenericPoint, Radians } from "./types";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
|
@ -10,12 +10,12 @@ import type { CubicBezier, Curve, GenericPoint, Radians } from "./types";
|
||||||
* @returns
|
* @returns
|
||||||
*/
|
*/
|
||||||
export function curve<Point extends GenericPoint>(
|
export function curve<Point extends GenericPoint>(
|
||||||
a: Point,
|
start: Point,
|
||||||
b: Point,
|
control1: Point,
|
||||||
c: Point,
|
control2: Point,
|
||||||
d: Point,
|
end: Point,
|
||||||
) {
|
) {
|
||||||
return [a, b, c, d] as Curve<Point>;
|
return [start, control1, control2, end] as Curve<Point>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const curveRotate = <Point extends GenericPoint>(
|
export const curveRotate = <Point extends GenericPoint>(
|
||||||
|
@ -26,215 +26,16 @@ export const curveRotate = <Point extends GenericPoint>(
|
||||||
return curve.map((p) => pointRotateRads(p, origin, angle));
|
return curve.map((p) => pointRotateRads(p, origin, angle));
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
export const isCurve = <Point extends GenericPoint>(
|
||||||
*
|
|
||||||
* @param pointsIn
|
|
||||||
* @param curveTightness
|
|
||||||
* @returns
|
|
||||||
*/
|
|
||||||
export function curveToBezier<Point extends GenericPoint>(
|
|
||||||
pointsIn: readonly Point[],
|
|
||||||
curveTightness = 0,
|
|
||||||
): Point[] {
|
|
||||||
const len = pointsIn.length;
|
|
||||||
if (len < 3) {
|
|
||||||
throw new Error("A curve must have at least three points.");
|
|
||||||
}
|
|
||||||
const out: Point[] = [];
|
|
||||||
if (len === 3) {
|
|
||||||
out.push(
|
|
||||||
pointFrom(pointsIn[0][0], pointsIn[0][1]), // Points need to be cloned
|
|
||||||
pointFrom(pointsIn[1][0], pointsIn[1][1]), // Points need to be cloned
|
|
||||||
pointFrom(pointsIn[2][0], pointsIn[2][1]), // Points need to be cloned
|
|
||||||
pointFrom(pointsIn[2][0], pointsIn[2][1]), // Points need to be cloned
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
const points: Point[] = [];
|
|
||||||
points.push(pointsIn[0], pointsIn[0]);
|
|
||||||
for (let i = 1; i < pointsIn.length; i++) {
|
|
||||||
points.push(pointsIn[i]);
|
|
||||||
if (i === pointsIn.length - 1) {
|
|
||||||
points.push(pointsIn[i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
const b: Point[] = [];
|
|
||||||
const s = 1 - curveTightness;
|
|
||||||
out.push(pointFrom(points[0][0], points[0][1]));
|
|
||||||
for (let i = 1; i + 2 < points.length; i++) {
|
|
||||||
const cachedVertArray = points[i];
|
|
||||||
b[0] = pointFrom(cachedVertArray[0], cachedVertArray[1]);
|
|
||||||
b[1] = pointFrom(
|
|
||||||
cachedVertArray[0] + (s * points[i + 1][0] - s * points[i - 1][0]) / 6,
|
|
||||||
cachedVertArray[1] + (s * points[i + 1][1] - s * points[i - 1][1]) / 6,
|
|
||||||
);
|
|
||||||
b[2] = pointFrom(
|
|
||||||
points[i + 1][0] + (s * points[i][0] - s * points[i + 2][0]) / 6,
|
|
||||||
points[i + 1][1] + (s * points[i][1] - s * points[i + 2][1]) / 6,
|
|
||||||
);
|
|
||||||
b[3] = pointFrom(points[i + 1][0], points[i + 1][1]);
|
|
||||||
out.push(b[1], b[2], b[3]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return out;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @param t
|
|
||||||
* @param controlPoints
|
|
||||||
* @returns
|
|
||||||
*/
|
|
||||||
export const cubicBezierPoint = <Point extends GenericPoint>(
|
|
||||||
t: number,
|
|
||||||
controlPoints: Curve<Point>,
|
|
||||||
): Point => {
|
|
||||||
const [p0, p1, p2, p3] = controlPoints;
|
|
||||||
|
|
||||||
const x =
|
|
||||||
Math.pow(1 - t, 3) * p0[0] +
|
|
||||||
3 * Math.pow(1 - t, 2) * t * p1[0] +
|
|
||||||
3 * (1 - t) * Math.pow(t, 2) * p2[0] +
|
|
||||||
Math.pow(t, 3) * p3[0];
|
|
||||||
|
|
||||||
const y =
|
|
||||||
Math.pow(1 - t, 3) * p0[1] +
|
|
||||||
3 * Math.pow(1 - t, 2) * t * p1[1] +
|
|
||||||
3 * (1 - t) * Math.pow(t, 2) * p2[1] +
|
|
||||||
Math.pow(t, 3) * p3[1];
|
|
||||||
|
|
||||||
return pointFrom(x, y);
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @param point
|
|
||||||
* @param controlPoints
|
|
||||||
* @returns
|
|
||||||
*/
|
|
||||||
export const cubicBezierDistance = <Point extends GenericPoint>(
|
|
||||||
point: Point,
|
|
||||||
controlPoints: Curve<Point>,
|
|
||||||
) => {
|
|
||||||
// Calculate the closest point on the Bezier curve to the given point
|
|
||||||
const t = findClosestParameter(point, controlPoints);
|
|
||||||
|
|
||||||
// Calculate the coordinates of the closest point on the curve
|
|
||||||
const [closestX, closestY] = cubicBezierPoint(t, controlPoints);
|
|
||||||
|
|
||||||
// Calculate the distance between the given point and the closest point on the curve
|
|
||||||
const distance = Math.sqrt(
|
|
||||||
(point[0] - closestX) ** 2 + (point[1] - closestY) ** 2,
|
|
||||||
);
|
|
||||||
|
|
||||||
return distance;
|
|
||||||
};
|
|
||||||
|
|
||||||
const solveCubic = (a: number, b: number, c: number, d: number) => {
|
|
||||||
// This function solves the cubic equation ax^3 + bx^2 + cx + d = 0
|
|
||||||
const roots: number[] = [];
|
|
||||||
|
|
||||||
const discriminant =
|
|
||||||
18 * a * b * c * d -
|
|
||||||
4 * Math.pow(b, 3) * d +
|
|
||||||
Math.pow(b, 2) * Math.pow(c, 2) -
|
|
||||||
4 * a * Math.pow(c, 3) -
|
|
||||||
27 * Math.pow(a, 2) * Math.pow(d, 2);
|
|
||||||
|
|
||||||
if (discriminant >= 0) {
|
|
||||||
const C = Math.cbrt((discriminant + Math.sqrt(discriminant)) / 2);
|
|
||||||
const D = Math.cbrt((discriminant - Math.sqrt(discriminant)) / 2);
|
|
||||||
|
|
||||||
const root1 = (-b - C - D) / (3 * a);
|
|
||||||
const root2 = (-b + (C + D) / 2) / (3 * a);
|
|
||||||
const root3 = (-b + (C + D) / 2) / (3 * a);
|
|
||||||
|
|
||||||
roots.push(root1, root2, root3);
|
|
||||||
} else {
|
|
||||||
const realPart = -b / (3 * a);
|
|
||||||
|
|
||||||
const root1 =
|
|
||||||
2 * Math.sqrt(-b / (3 * a)) * Math.cos(Math.acos(realPart) / 3);
|
|
||||||
const root2 =
|
|
||||||
2 *
|
|
||||||
Math.sqrt(-b / (3 * a)) *
|
|
||||||
Math.cos((Math.acos(realPart) + 2 * Math.PI) / 3);
|
|
||||||
const root3 =
|
|
||||||
2 *
|
|
||||||
Math.sqrt(-b / (3 * a)) *
|
|
||||||
Math.cos((Math.acos(realPart) + 4 * Math.PI) / 3);
|
|
||||||
|
|
||||||
roots.push(root1, root2, root3);
|
|
||||||
}
|
|
||||||
|
|
||||||
return roots;
|
|
||||||
};
|
|
||||||
|
|
||||||
const findClosestParameter = <Point extends GenericPoint>(
|
|
||||||
point: Point,
|
|
||||||
controlPoints: Curve<Point>,
|
|
||||||
) => {
|
|
||||||
// This function finds the parameter t that minimizes the distance between the point
|
|
||||||
// and any point on the cubic Bezier curve.
|
|
||||||
|
|
||||||
const [p0, p1, p2, p3] = controlPoints;
|
|
||||||
|
|
||||||
// Use the direct formula to find the parameter t
|
|
||||||
const a = p3[0] - 3 * p2[0] + 3 * p1[0] - p0[0];
|
|
||||||
const b = 3 * p2[0] - 6 * p1[0] + 3 * p0[0];
|
|
||||||
const c = 3 * p1[0] - 3 * p0[0];
|
|
||||||
const d = p0[0] - point[0];
|
|
||||||
|
|
||||||
const rootsX = solveCubic(a, b, c, d);
|
|
||||||
|
|
||||||
// Do the same for the y-coordinate
|
|
||||||
const e = p3[1] - 3 * p2[1] + 3 * p1[1] - p0[1];
|
|
||||||
const f = 3 * p2[1] - 6 * p1[1] + 3 * p0[1];
|
|
||||||
const g = 3 * p1[1] - 3 * p0[1];
|
|
||||||
const h = p0[1] - point[1];
|
|
||||||
|
|
||||||
const rootsY = solveCubic(e, f, g, h);
|
|
||||||
|
|
||||||
// Select the real root that is between 0 and 1 (inclusive)
|
|
||||||
const validRootsX = rootsX.filter((root) => root >= 0 && root <= 1);
|
|
||||||
const validRootsY = rootsY.filter((root) => root >= 0 && root <= 1);
|
|
||||||
|
|
||||||
if (validRootsX.length === 0 || validRootsY.length === 0) {
|
|
||||||
// No valid roots found, use the midpoint as a fallback
|
|
||||||
return 0.5;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Choose the parameter t that minimizes the distance
|
|
||||||
let minDistance = Infinity;
|
|
||||||
let closestT = 0;
|
|
||||||
|
|
||||||
for (const rootX of validRootsX) {
|
|
||||||
for (const rootY of validRootsY) {
|
|
||||||
const distance = Math.sqrt(
|
|
||||||
(rootX - point[0]) ** 2 + (rootY - point[1]) ** 2,
|
|
||||||
);
|
|
||||||
if (distance < minDistance) {
|
|
||||||
minDistance = distance;
|
|
||||||
closestT = (rootX + rootY) / 2; // Use the average for a smoother result
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return closestT;
|
|
||||||
};
|
|
||||||
|
|
||||||
export const isBezier = <Point extends GenericPoint>(
|
|
||||||
c: unknown,
|
c: unknown,
|
||||||
): c is CubicBezier<Point> => {
|
): c is Curve<Point> => {
|
||||||
return (
|
return (
|
||||||
c != null &&
|
c != null &&
|
||||||
typeof c === "object" &&
|
Array.isArray(c) &&
|
||||||
Object.hasOwn(c, "start") &&
|
c.length === 4 &&
|
||||||
Object.hasOwn(c, "end") &&
|
isPoint((c as Curve<Point>)[0]) &&
|
||||||
Object.hasOwn(c, "control1") &&
|
isPoint((c as Curve<Point>)[1]) &&
|
||||||
Object.hasOwn(c, "control2") &&
|
isPoint((c as Curve<Point>)[2]) &&
|
||||||
isPoint((c as CubicBezier<Point>).start) &&
|
isPoint((c as Curve<Point>)[3])
|
||||||
isPoint((c as CubicBezier<Point>).end) &&
|
|
||||||
isPoint((c as CubicBezier<Point>).control1) &&
|
|
||||||
isPoint((c as CubicBezier<Point>).control2)
|
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
|
@ -101,9 +101,22 @@ export type Polygon<Point extends GenericPoint> = Point[] & {
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Cubic bezier curve with four control points
|
* Cubic bezier curve where the start and end points are at the 0 and 3 index
|
||||||
|
* respectively, and the control points are at the 1 and 2 index respectively.
|
||||||
|
*
|
||||||
|
* It conveniently maps into the following code:
|
||||||
|
*
|
||||||
|
* ```javascript
|
||||||
|
* canvasCtx.moveTo(start);
|
||||||
|
* canvasCtx.bezierCurveTo(control1, control2, end);
|
||||||
|
* ```
|
||||||
*/
|
*/
|
||||||
export type Curve<Point extends GenericPoint> = [Point, Point, Point, Point] & {
|
export type Curve<Point extends GenericPoint> = [
|
||||||
|
start: Point,
|
||||||
|
control1: Point,
|
||||||
|
control2: Point,
|
||||||
|
end: Point,
|
||||||
|
] & {
|
||||||
_brand: "excalimath_curve";
|
_brand: "excalimath_curve";
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -144,14 +157,3 @@ export type Ellipse<Point extends GenericPoint> = {
|
||||||
} & {
|
} & {
|
||||||
_brand: "excalimath_ellipse";
|
_brand: "excalimath_ellipse";
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
|
||||||
* Represents a cubic bezier with 2 control points on the point space of your
|
|
||||||
* choosing.
|
|
||||||
*/
|
|
||||||
export type CubicBezier<P extends GenericPoint> = {
|
|
||||||
start: P;
|
|
||||||
end: P;
|
|
||||||
control1: P;
|
|
||||||
control2: P;
|
|
||||||
};
|
|
||||||
|
|
|
@ -197,13 +197,13 @@ export const getCurvePathOps = (shape: Drawable): Op[] => {
|
||||||
};
|
};
|
||||||
|
|
||||||
// linear
|
// linear
|
||||||
export const getCurveShape = <Point extends GlobalPoint | LocalPoint>(
|
export const getCurveShape = (
|
||||||
roughShape: Drawable,
|
roughShape: Drawable,
|
||||||
startingPoint: Point = pointFrom(0, 0),
|
startingPoint: GlobalPoint,
|
||||||
angleInRadian: Radians,
|
angleInRadian: Radians,
|
||||||
center: Point,
|
center: GlobalPoint,
|
||||||
): GeometricShape<Point> => {
|
): GeometricShape<GlobalPoint> => {
|
||||||
const transform = (p: Point): Point =>
|
const transform = (p: GlobalPoint): GlobalPoint =>
|
||||||
pointRotateRads(
|
pointRotateRads(
|
||||||
pointFrom(p[0] + startingPoint[0], p[1] + startingPoint[1]),
|
pointFrom(p[0] + startingPoint[0], p[1] + startingPoint[1]),
|
||||||
center,
|
center,
|
||||||
|
@ -211,20 +211,20 @@ export const getCurveShape = <Point extends GlobalPoint | LocalPoint>(
|
||||||
);
|
);
|
||||||
|
|
||||||
const ops = getCurvePathOps(roughShape);
|
const ops = getCurvePathOps(roughShape);
|
||||||
const polycurve: Polycurve<Point> = [];
|
const polycurve: Polycurve<GlobalPoint> = [];
|
||||||
let p0 = pointFrom<Point>(0, 0);
|
let p0 = pointFrom<GlobalPoint>(0, 0);
|
||||||
|
|
||||||
for (const op of ops) {
|
for (const op of ops) {
|
||||||
if (op.op === "move") {
|
if (op.op === "move") {
|
||||||
const p = pointFromArray<Point>(op.data);
|
const p = pointFromArray<GlobalPoint>(op.data);
|
||||||
invariant(p != null, "Ops data is not a point");
|
invariant(p != null, "Ops data is not a point");
|
||||||
p0 = transform(p);
|
p0 = transform(p);
|
||||||
}
|
}
|
||||||
if (op.op === "bcurveTo") {
|
if (op.op === "bcurveTo") {
|
||||||
const p1 = transform(pointFrom<Point>(op.data[0], op.data[1]));
|
const p1 = transform(pointFrom(op.data[0], op.data[1]));
|
||||||
const p2 = transform(pointFrom<Point>(op.data[2], op.data[3]));
|
const p2 = transform(pointFrom(op.data[2], op.data[3]));
|
||||||
const p3 = transform(pointFrom<Point>(op.data[4], op.data[5]));
|
const p3 = transform(pointFrom(op.data[4], op.data[5]));
|
||||||
polycurve.push(curve<Point>(p0, p1, p2, p3));
|
polycurve.push(curve(p0, p1, p2, p3));
|
||||||
p0 = p3;
|
p0 = p3;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -281,16 +281,16 @@ export const getFreedrawShape = (
|
||||||
) as GeometricShape<GlobalPoint>;
|
) as GeometricShape<GlobalPoint>;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const getClosedCurveShape = <Point extends GlobalPoint | LocalPoint>(
|
export const getClosedCurveShape = (
|
||||||
element: ExcalidrawLinearElement,
|
element: ExcalidrawLinearElement,
|
||||||
roughShape: Drawable,
|
roughShape: Drawable,
|
||||||
startingPoint: Point = pointFrom<Point>(0, 0),
|
startingPoint: GlobalPoint,
|
||||||
angleInRadian: Radians,
|
angleInRadian: Radians,
|
||||||
center: Point,
|
center: GlobalPoint,
|
||||||
): GeometricShape<Point> => {
|
): GeometricShape<GlobalPoint> => {
|
||||||
const transform = (p: Point) =>
|
const transform = (p: LocalPoint) =>
|
||||||
pointRotateRads(
|
pointRotateRads(
|
||||||
pointFrom(p[0] + startingPoint[0], p[1] + startingPoint[1]),
|
pointFrom<GlobalPoint>(p[0] + startingPoint[0], p[1] + startingPoint[1]),
|
||||||
center,
|
center,
|
||||||
angleInRadian,
|
angleInRadian,
|
||||||
);
|
);
|
||||||
|
@ -298,15 +298,13 @@ export const getClosedCurveShape = <Point extends GlobalPoint | LocalPoint>(
|
||||||
if (element.roundness === null) {
|
if (element.roundness === null) {
|
||||||
return {
|
return {
|
||||||
type: "polygon",
|
type: "polygon",
|
||||||
data: polygonFromPoints(
|
data: polygonFromPoints(element.points.map((p) => transform(p))),
|
||||||
element.points.map((p) => transform(p as Point)) as Point[],
|
|
||||||
),
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
const ops = getCurvePathOps(roughShape);
|
const ops = getCurvePathOps(roughShape);
|
||||||
|
|
||||||
const points: Point[] = [];
|
const points: GlobalPoint[] = [];
|
||||||
let odd = false;
|
let odd = false;
|
||||||
for (const operation of ops) {
|
for (const operation of ops) {
|
||||||
if (operation.op === "move") {
|
if (operation.op === "move") {
|
||||||
|
@ -328,12 +326,12 @@ export const getClosedCurveShape = <Point extends GlobalPoint | LocalPoint>(
|
||||||
}
|
}
|
||||||
|
|
||||||
const polygonPoints = pointsOnBezierCurves(points, 10, 5).map((p) =>
|
const polygonPoints = pointsOnBezierCurves(points, 10, 5).map((p) =>
|
||||||
transform(p as Point),
|
transform(p as LocalPoint),
|
||||||
) as Point[];
|
);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
type: "polygon",
|
type: "polygon",
|
||||||
data: polygonFromPoints<Point>(polygonPoints),
|
data: polygonFromPoints(polygonPoints),
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue