mirror of
https://github.com/excalidraw/excalidraw.git
synced 2025-12-06 12:34:42 +01:00
feat: Cross-stitching fine-tune
This commit is contained in:
@@ -1,11 +1,9 @@
|
|||||||
import {
|
import {
|
||||||
type GlobalPoint,
|
type GlobalPoint,
|
||||||
Line,
|
|
||||||
type LineSegment,
|
type LineSegment,
|
||||||
lineSegment,
|
lineSegment,
|
||||||
lineSegmentIntersectionPoints,
|
lineSegmentIntersectionPoints,
|
||||||
type LocalPoint,
|
type LocalPoint,
|
||||||
pointDistance,
|
|
||||||
pointDistanceSq,
|
pointDistanceSq,
|
||||||
pointFrom,
|
pointFrom,
|
||||||
pointFromVector,
|
pointFromVector,
|
||||||
@@ -15,10 +13,9 @@ import {
|
|||||||
vectorNormalize,
|
vectorNormalize,
|
||||||
vectorScale,
|
vectorScale,
|
||||||
} from "@excalidraw/math";
|
} from "@excalidraw/math";
|
||||||
|
import { debugDrawLine } from "@excalidraw/common";
|
||||||
|
|
||||||
import { type ExcalidrawFreeDrawElement } from "./types";
|
import { type ExcalidrawFreeDrawElement } from "./types";
|
||||||
import { doLineSegmentsIntersect } from "@excalidraw/utils";
|
|
||||||
import { debugDrawLine, debugDrawPoint, distance } from "@excalidraw/common";
|
|
||||||
|
|
||||||
const offset = (
|
const offset = (
|
||||||
x: number,
|
x: number,
|
||||||
@@ -40,27 +37,28 @@ function generateSegments(
|
|||||||
| readonly [x: number, y: number, pressure: number][]
|
| readonly [x: number, y: number, pressure: number][]
|
||||||
| readonly [x: number, y: number][],
|
| readonly [x: number, y: number][],
|
||||||
element: ExcalidrawFreeDrawElement,
|
element: ExcalidrawFreeDrawElement,
|
||||||
|
pressureMultiplier: number = 1,
|
||||||
|
minimumPressure: number = 1,
|
||||||
): LineSegment<LocalPoint>[] {
|
): LineSegment<LocalPoint>[] {
|
||||||
if (input.length < 3) {
|
if (input.length < 3) {
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
let idx = 0;
|
let idx = 0;
|
||||||
|
|
||||||
//const segments: LineSegment<LocalPoint>[] = [];
|
|
||||||
const segments = Array(input.length * 4 - 4);
|
const segments = Array(input.length * 4 - 4);
|
||||||
|
|
||||||
segments[idx++] = lineSegment(
|
segments[idx++] = lineSegment(
|
||||||
offset(
|
offset(
|
||||||
input[1][0],
|
input[1][0],
|
||||||
input[1][1],
|
input[1][1],
|
||||||
input[1][2] ?? 5,
|
Math.max((input[1][2] ?? 5) * pressureMultiplier, minimumPressure),
|
||||||
"left",
|
"left",
|
||||||
pointFrom<LocalPoint>(input[0][0], input[0][1]),
|
pointFrom<LocalPoint>(input[0][0], input[0][1]),
|
||||||
),
|
),
|
||||||
offset(
|
offset(
|
||||||
input[0][0],
|
input[0][0],
|
||||||
input[0][1],
|
input[0][1],
|
||||||
input[0][2] ?? 5,
|
Math.max((input[1][2] ?? 5) * pressureMultiplier, minimumPressure),
|
||||||
"right",
|
"right",
|
||||||
pointFrom<LocalPoint>(input[1][0], input[1][1]),
|
pointFrom<LocalPoint>(input[1][0], input[1][1]),
|
||||||
),
|
),
|
||||||
@@ -71,14 +69,14 @@ function generateSegments(
|
|||||||
const b = offset(
|
const b = offset(
|
||||||
input[i][0],
|
input[i][0],
|
||||||
input[i][1],
|
input[i][1],
|
||||||
input[i][2] ?? 5,
|
Math.max((input[1][2] ?? 5) * pressureMultiplier, minimumPressure),
|
||||||
"left",
|
"left",
|
||||||
pointFrom<LocalPoint>(input[i - 1][0], input[i - 1][1]),
|
pointFrom<LocalPoint>(input[i - 1][0], input[i - 1][1]),
|
||||||
);
|
);
|
||||||
const c = offset(
|
const c = offset(
|
||||||
input[i - 1][0],
|
input[i - 1][0],
|
||||||
input[i - 1][1],
|
input[i - 1][1],
|
||||||
input[i - 1][2] ?? 5,
|
Math.max((input[1][2] ?? 5) * pressureMultiplier, minimumPressure),
|
||||||
"right",
|
"right",
|
||||||
pointFrom<LocalPoint>(input[i][0], input[i][1]),
|
pointFrom<LocalPoint>(input[i][0], input[i][1]),
|
||||||
);
|
);
|
||||||
@@ -104,7 +102,7 @@ function generateSegments(
|
|||||||
offset(
|
offset(
|
||||||
input[input.length - 2][0],
|
input[input.length - 2][0],
|
||||||
input[input.length - 2][1],
|
input[input.length - 2][1],
|
||||||
input[input.length - 2][2] ?? 5,
|
Math.max((input[1][2] ?? 5) * pressureMultiplier, minimumPressure),
|
||||||
"left",
|
"left",
|
||||||
pointFrom<LocalPoint>(
|
pointFrom<LocalPoint>(
|
||||||
input[input.length - 1][0],
|
input[input.length - 1][0],
|
||||||
@@ -118,14 +116,14 @@ function generateSegments(
|
|||||||
const b = offset(
|
const b = offset(
|
||||||
input[i + 1][0],
|
input[i + 1][0],
|
||||||
input[i + 1][1],
|
input[i + 1][1],
|
||||||
input[i + 1][2] ?? 5,
|
Math.max((input[1][2] ?? 5) * pressureMultiplier, minimumPressure),
|
||||||
"right",
|
"right",
|
||||||
pointFrom<LocalPoint>(input[i][0], input[i][1]),
|
pointFrom<LocalPoint>(input[i][0], input[i][1]),
|
||||||
);
|
);
|
||||||
const c = offset(
|
const c = offset(
|
||||||
input[i - 1][0],
|
input[i - 1][0],
|
||||||
input[i - 1][1],
|
input[i - 1][1],
|
||||||
input[i - 1][2] ?? 5,
|
Math.max((input[1][2] ?? 5) * pressureMultiplier, minimumPressure),
|
||||||
"left",
|
"left",
|
||||||
pointFrom<LocalPoint>(input[i][0], input[i][1]),
|
pointFrom<LocalPoint>(input[i][0], input[i][1]),
|
||||||
);
|
);
|
||||||
@@ -140,7 +138,7 @@ function generateSegments(
|
|||||||
offset(
|
offset(
|
||||||
input[1][0],
|
input[1][0],
|
||||||
input[1][1],
|
input[1][1],
|
||||||
input[1][2] ?? 5,
|
Math.max((input[1][2] ?? 5) * pressureMultiplier, minimumPressure),
|
||||||
"right",
|
"right",
|
||||||
pointFrom<LocalPoint>(input[0][0], input[0][1]),
|
pointFrom<LocalPoint>(input[0][0], input[0][1]),
|
||||||
),
|
),
|
||||||
@@ -171,7 +169,7 @@ export function getStroke(
|
|||||||
element,
|
element,
|
||||||
);
|
);
|
||||||
|
|
||||||
const MIN_DIST_SQ = 1 ** 2;
|
const MIN_DIST_SQ = 0.2 ** 2;
|
||||||
for (let j = 0; j < segments.length; j++) {
|
for (let j = 0; j < segments.length; j++) {
|
||||||
for (let i = j + 1; i < segments.length; i++) {
|
for (let i = j + 1; i < segments.length; i++) {
|
||||||
const a = segments[j];
|
const a = segments[j];
|
||||||
@@ -185,62 +183,28 @@ export function getStroke(
|
|||||||
if (
|
if (
|
||||||
intersection &&
|
intersection &&
|
||||||
pointDistanceSq(a[0], intersection) > MIN_DIST_SQ &&
|
pointDistanceSq(a[0], intersection) > MIN_DIST_SQ &&
|
||||||
pointDistanceSq(a[1], intersection) > MIN_DIST_SQ
|
pointDistanceSq(a[1], intersection) > MIN_DIST_SQ &&
|
||||||
|
i === j + 2
|
||||||
) {
|
) {
|
||||||
debugDrawPoint(
|
a[1] = intersection;
|
||||||
pointFrom<GlobalPoint>(
|
segments[j + 1] = undefined;
|
||||||
element.x + intersection[0],
|
b[0] = intersection;
|
||||||
element.y + intersection[1],
|
|
||||||
),
|
|
||||||
{ color: "#FF00FF", permanent: true },
|
|
||||||
);
|
|
||||||
console.log("intersection", j, i, intersection);
|
|
||||||
}
|
}
|
||||||
// if (j !== i && j + 1 !== i && j !== i + 1) {
|
|
||||||
// const intersection = lineSegmentIntersectionPoints(segments[j], s);
|
|
||||||
// if (intersection?.length) {
|
|
||||||
// console.log(
|
|
||||||
// "intersection",
|
|
||||||
// j,
|
|
||||||
// i,
|
|
||||||
// pointDistance(segments[j][0], segments[j][1]),
|
|
||||||
// pointDistance(s[0], s[1]),
|
|
||||||
// //lineSegmentIntersectionPoints(segments[j], s),
|
|
||||||
// );
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// for (let i = 0; i < segments.length; i++) {
|
debugSegments(
|
||||||
// if (i < 2 || i > segments.length - 3) {
|
segments.filter((s): s is LineSegment<LocalPoint> => !!s),
|
||||||
// continue;
|
input,
|
||||||
// }
|
element,
|
||||||
|
);
|
||||||
|
|
||||||
// const intersection1 = lineSegmentIntersectionPoints(
|
return [
|
||||||
// segments[i - 2],
|
...(segments[0] ? [segments[0][0]] : []),
|
||||||
// segments[i],
|
...segments
|
||||||
// );
|
.filter((s): s is LineSegment<LocalPoint> => !!s)
|
||||||
// // if (intersection1) {
|
.map((s) => s[1]),
|
||||||
// // segments[i][0] = intersection1;
|
];
|
||||||
// // }
|
|
||||||
|
|
||||||
// const intersection2 = lineSegmentIntersectionPoints(
|
|
||||||
// segments[i + 2],
|
|
||||||
// segments[i],
|
|
||||||
// );
|
|
||||||
// // if (intersection2) {
|
|
||||||
// // segments[i][1] = intersection2;
|
|
||||||
// // }
|
|
||||||
|
|
||||||
// if (!!intersection1 !== !!intersection2) {
|
|
||||||
// console.log("??", intersection1, intersection2);
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
debugSegments(segments, input, element);
|
|
||||||
|
|
||||||
return [segments[0][0], ...segments.map((s) => s[1])];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function debugSegments(
|
function debugSegments(
|
||||||
|
|||||||
@@ -63,8 +63,8 @@ import {
|
|||||||
} from "./typeChecks";
|
} from "./typeChecks";
|
||||||
import { getContainingFrame } from "./frame";
|
import { getContainingFrame } from "./frame";
|
||||||
import { getCornerRadius } from "./utils";
|
import { getCornerRadius } from "./utils";
|
||||||
|
|
||||||
import { ShapeCache } from "./shape";
|
import { ShapeCache } from "./shape";
|
||||||
|
import { getStroke } from "./freedraw";
|
||||||
|
|
||||||
import type {
|
import type {
|
||||||
ExcalidrawElement,
|
ExcalidrawElement,
|
||||||
@@ -80,7 +80,6 @@ import type {
|
|||||||
|
|
||||||
import type { StrokeOptions } from "perfect-freehand";
|
import type { StrokeOptions } from "perfect-freehand";
|
||||||
import type { RoughCanvas } from "roughjs/bin/canvas";
|
import type { RoughCanvas } from "roughjs/bin/canvas";
|
||||||
import { getStroke } from "./freedraw";
|
|
||||||
|
|
||||||
// using a stronger invert (100% vs our regular 93%) and saturate
|
// using a stronger invert (100% vs our regular 93%) and saturate
|
||||||
// as a temp hack to make images in dark theme look closer to original
|
// as a temp hack to make images in dark theme look closer to original
|
||||||
@@ -1119,16 +1118,16 @@ export function getFreedrawOutlinePoints(element: ExcalidrawFreeDrawElement) {
|
|||||||
last: true,
|
last: true,
|
||||||
};
|
};
|
||||||
|
|
||||||
return getStroke(
|
// return getStroke(
|
||||||
[
|
// [
|
||||||
[0, 0],
|
// [0, 0],
|
||||||
[30, -30],
|
// [30, -30],
|
||||||
[60, -30],
|
// [60, -30],
|
||||||
],
|
// ],
|
||||||
options,
|
// options,
|
||||||
element,
|
// element,
|
||||||
);
|
// );
|
||||||
//return getStroke(inputPoints, options, element) as [number, number][];
|
return getStroke(inputPoints, options, element) as [number, number][];
|
||||||
}
|
}
|
||||||
|
|
||||||
function med(A: number[], B: number[]) {
|
function med(A: number[], B: number[]) {
|
||||||
|
|||||||
Reference in New Issue
Block a user