mirror of
https://github.com/excalidraw/excalidraw.git
synced 2025-12-06 12:34:42 +01:00
fix: Orientation
This commit is contained in:
@@ -1,7 +1,10 @@
|
|||||||
import {
|
import {
|
||||||
|
type GlobalPoint,
|
||||||
type LineSegment,
|
type LineSegment,
|
||||||
lineSegment,
|
lineSegment,
|
||||||
|
lineSegmentIntersectionPoints,
|
||||||
type LocalPoint,
|
type LocalPoint,
|
||||||
|
pointDistance,
|
||||||
pointFrom,
|
pointFrom,
|
||||||
pointFromVector,
|
pointFromVector,
|
||||||
vectorAntiNormal,
|
vectorAntiNormal,
|
||||||
@@ -12,69 +15,148 @@ import {
|
|||||||
} from "@excalidraw/math";
|
} from "@excalidraw/math";
|
||||||
|
|
||||||
import { type ExcalidrawFreeDrawElement } from "./types";
|
import { type ExcalidrawFreeDrawElement } from "./types";
|
||||||
|
import { doLineSegmentsIntersect } from "@excalidraw/utils";
|
||||||
function generateSegments(
|
import { debugDrawLine, debugDrawPoint, distance } from "@excalidraw/common";
|
||||||
input:
|
|
||||||
| readonly [x: number, y: number, pressure: number][]
|
|
||||||
| readonly [x: number, y: number][],
|
|
||||||
): LineSegment<LocalPoint>[] {
|
|
||||||
if (input.length < 2) {
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
|
|
||||||
const offset = (
|
const offset = (
|
||||||
x: number,
|
x: number,
|
||||||
y: number,
|
y: number,
|
||||||
pressure: number,
|
pressure: number,
|
||||||
direction: "left" | "right",
|
direction: "left" | "right",
|
||||||
|
origin: LocalPoint,
|
||||||
) => {
|
) => {
|
||||||
const p = pointFrom<LocalPoint>(x, y);
|
const p = pointFrom<LocalPoint>(x, y);
|
||||||
const v = vectorNormalize(vectorFromPoint(p));
|
const v = vectorNormalize(vectorFromPoint(p, origin));
|
||||||
const normal = direction === "left" ? vectorAntiNormal(v) : vectorNormal(v);
|
const normal = direction === "left" ? vectorNormal(v) : vectorAntiNormal(v);
|
||||||
const scaled = vectorScale(normal, pressure / 2);
|
const scaled = vectorScale(normal, pressure / 2);
|
||||||
|
|
||||||
return pointFromVector(scaled, p);
|
return pointFromVector(scaled, origin);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
function generateSegments(
|
||||||
|
input:
|
||||||
|
| readonly [x: number, y: number, pressure: number][]
|
||||||
|
| readonly [x: number, y: number][],
|
||||||
|
element: ExcalidrawFreeDrawElement,
|
||||||
|
): LineSegment<LocalPoint>[] {
|
||||||
|
if (input.length < 3) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
let idx = 0;
|
let idx = 0;
|
||||||
|
|
||||||
const segments = Array(input.length * 2 - 1);
|
//const segments: LineSegment<LocalPoint>[] = [];
|
||||||
|
const segments = Array(input.length * 4 - 4);
|
||||||
segments[idx++] = lineSegment(
|
segments[idx++] = lineSegment(
|
||||||
offset(input[0][0], input[0][1], input[0][2] ?? 5, "left"),
|
|
||||||
offset(input[1][0], input[1][1], input[0][2] ?? 5, "left"),
|
|
||||||
);
|
|
||||||
|
|
||||||
for (let i = 2; i < input.length; i++) {
|
|
||||||
const point = input[i];
|
|
||||||
const prev = segments[idx - 1][1];
|
|
||||||
|
|
||||||
segments[idx++] = lineSegment(
|
|
||||||
prev,
|
|
||||||
offset(point[0], point[1], point[2] ?? 5, "left"),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
const prev = segments[idx - 1][1];
|
|
||||||
segments[idx++] = lineSegment(
|
|
||||||
prev,
|
|
||||||
offset(
|
offset(
|
||||||
input[input.length - 1][0],
|
input[1][0],
|
||||||
input[input.length - 1][1],
|
input[1][1],
|
||||||
input[input.length - 1][2] ?? 5,
|
input[1][2] ?? 5,
|
||||||
|
"left",
|
||||||
|
pointFrom<LocalPoint>(input[0][0], input[0][1]),
|
||||||
|
),
|
||||||
|
offset(
|
||||||
|
input[0][0],
|
||||||
|
input[0][1],
|
||||||
|
input[0][2] ?? 5,
|
||||||
"right",
|
"right",
|
||||||
|
pointFrom<LocalPoint>(input[1][0], input[1][1]),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
for (let i = input.length - 2; i >= 0; i--) {
|
for (let i = 2; i < input.length; i++) {
|
||||||
const point = input[i];
|
const a = segments[idx - 1][1];
|
||||||
const prev = segments[idx - 1][1];
|
const b = offset(
|
||||||
|
input[i][0],
|
||||||
|
input[i][1],
|
||||||
|
input[i][2] ?? 5,
|
||||||
|
"left",
|
||||||
|
pointFrom<LocalPoint>(input[i - 1][0], input[i - 1][1]),
|
||||||
|
);
|
||||||
|
const c = offset(
|
||||||
|
input[i - 1][0],
|
||||||
|
input[i - 1][1],
|
||||||
|
input[i - 1][2] ?? 5,
|
||||||
|
"right",
|
||||||
|
pointFrom<LocalPoint>(input[i][0], input[i][1]),
|
||||||
|
);
|
||||||
|
|
||||||
|
segments[idx++] = lineSegment(a, b); // Bridge segment
|
||||||
|
segments[idx++] = lineSegment(b, c); // Main segment
|
||||||
|
}
|
||||||
|
|
||||||
|
// Turnaround segments
|
||||||
|
const prev = segments[idx - 1][1];
|
||||||
segments[idx++] = lineSegment(
|
segments[idx++] = lineSegment(
|
||||||
prev,
|
prev,
|
||||||
offset(point[0], point[1], point[2] ?? 5, "right"),
|
pointFrom<LocalPoint>(
|
||||||
|
input[input.length - 1][0],
|
||||||
|
input[input.length - 1][1],
|
||||||
|
),
|
||||||
);
|
);
|
||||||
|
segments[idx++] = lineSegment(
|
||||||
|
pointFrom<LocalPoint>(
|
||||||
|
input[input.length - 1][0],
|
||||||
|
input[input.length - 1][1],
|
||||||
|
),
|
||||||
|
offset(
|
||||||
|
input[input.length - 2][0],
|
||||||
|
input[input.length - 2][1],
|
||||||
|
input[input.length - 2][2] ?? 5,
|
||||||
|
"left",
|
||||||
|
pointFrom<LocalPoint>(
|
||||||
|
input[input.length - 1][0],
|
||||||
|
input[input.length - 1][1],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
for (let i = input.length - 2; i > 0; i--) {
|
||||||
|
const a = segments[idx - 1][1];
|
||||||
|
const b = offset(
|
||||||
|
input[i + 1][0],
|
||||||
|
input[i + 1][1],
|
||||||
|
input[i + 1][2] ?? 5,
|
||||||
|
"right",
|
||||||
|
pointFrom<LocalPoint>(input[i][0], input[i][1]),
|
||||||
|
);
|
||||||
|
const c = offset(
|
||||||
|
input[i - 1][0],
|
||||||
|
input[i - 1][1],
|
||||||
|
input[i - 1][2] ?? 5,
|
||||||
|
"left",
|
||||||
|
pointFrom<LocalPoint>(input[i][0], input[i][1]),
|
||||||
|
);
|
||||||
|
|
||||||
|
segments[idx++] = lineSegment(a, b); // Main segment
|
||||||
|
segments[idx++] = lineSegment(b, c); // Bridge segment
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const last = segments[idx - 1][1];
|
||||||
|
segments[idx++] = lineSegment(
|
||||||
|
last,
|
||||||
|
offset(
|
||||||
|
input[1][0],
|
||||||
|
input[1][1],
|
||||||
|
input[1][2] ?? 5,
|
||||||
|
"right",
|
||||||
|
pointFrom<LocalPoint>(input[0][0], input[0][1]),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
// Closing cap
|
||||||
|
segments[idx++] = lineSegment(
|
||||||
|
segments[idx - 2][1],
|
||||||
|
pointFrom<LocalPoint>(input[0][0], input[0][1]),
|
||||||
|
);
|
||||||
|
// debugDrawPoint(
|
||||||
|
// pointFrom<LocalPoint>(element.x + segments[0], input[0][1]),
|
||||||
|
// );
|
||||||
|
segments[idx++] = lineSegment(
|
||||||
|
pointFrom<LocalPoint>(input[0][0], input[0][1]),
|
||||||
|
segments[0][0],
|
||||||
|
);
|
||||||
|
|
||||||
return segments;
|
return segments;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -85,7 +167,92 @@ export function getStroke(
|
|||||||
options: any,
|
options: any,
|
||||||
element: ExcalidrawFreeDrawElement,
|
element: ExcalidrawFreeDrawElement,
|
||||||
): LocalPoint[] {
|
): LocalPoint[] {
|
||||||
const segments = generateSegments(input);
|
const segments = generateSegments(input, element);
|
||||||
|
|
||||||
|
// for (let j = 0; j < segments.length; j++) {
|
||||||
|
// segments.forEach((s, i) => {
|
||||||
|
// 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++) {
|
||||||
|
// if (i < 2 || i > segments.length - 3) {
|
||||||
|
// continue;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// const intersection1 = lineSegmentIntersectionPoints(
|
||||||
|
// segments[i - 2],
|
||||||
|
// segments[i],
|
||||||
|
// );
|
||||||
|
// // if (intersection1) {
|
||||||
|
// // 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);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
const colors = [
|
||||||
|
"#FF0000",
|
||||||
|
"#00FF00",
|
||||||
|
"#0000FF",
|
||||||
|
// "#FFFF00",
|
||||||
|
// "#00FFFF",
|
||||||
|
// "#FF00FF",
|
||||||
|
// "#C0C0C0",
|
||||||
|
// "#800000",
|
||||||
|
// "#808000",
|
||||||
|
// "#008000",
|
||||||
|
// "#800080",
|
||||||
|
// "#008080",
|
||||||
|
// "#000080",
|
||||||
|
];
|
||||||
|
segments.forEach((s, i) => {
|
||||||
|
debugDrawLine(
|
||||||
|
lineSegment(
|
||||||
|
pointFrom<GlobalPoint>(element.x + s[0][0], element.y + s[0][1]),
|
||||||
|
pointFrom<GlobalPoint>(element.x + s[1][0], element.y + s[1][1]),
|
||||||
|
),
|
||||||
|
{ color: colors[i % colors.length], permanent: true },
|
||||||
|
);
|
||||||
|
});
|
||||||
|
input.forEach((p, i) => {
|
||||||
|
if (i === 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
debugDrawLine(
|
||||||
|
lineSegment(
|
||||||
|
pointFrom<GlobalPoint>(
|
||||||
|
element.x + input[i - 1][0],
|
||||||
|
element.y + input[i - 1][1],
|
||||||
|
),
|
||||||
|
pointFrom<GlobalPoint>(element.x + p[0], element.y + p[1]),
|
||||||
|
),
|
||||||
|
{ color: "#000000", permanent: true },
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
return [segments[0][0], ...segments.map((s) => s[1])];
|
return [segments[0][0], ...segments.map((s) => s[1])];
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1119,6 +1119,15 @@ export function getFreedrawOutlinePoints(element: ExcalidrawFreeDrawElement) {
|
|||||||
last: true,
|
last: true,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// return getStroke(
|
||||||
|
// [
|
||||||
|
// [0, 0],
|
||||||
|
// [30, -30],
|
||||||
|
// [60, -30],
|
||||||
|
// ],
|
||||||
|
// options,
|
||||||
|
// element,
|
||||||
|
// );
|
||||||
return getStroke(inputPoints, options, element) as [number, number][];
|
return getStroke(inputPoints, options, element) as [number, number][];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user