feat: 同步上游仓库更新 (2025-06-22 00:47:57)

This commit is contained in:
xudan 2025-06-22 00:47:57 +08:00
commit dbfa500743

View File

@ -904,7 +904,6 @@ function drawLine(ctx: CanvasRenderingContext2D, pen: MapPen): void {
const { x: dx2 = 0, y: dy2 = 0 } = c2 ?? {};
const [c1x, c1y] = [x1 + dx1 * s, y1 + dy1 * s];
const [c2x, c2y] = [x2 + dx2 * s, y2 + dy2 * s];
const t = direction < 0 ? 0.55 : 0.45;
ctx.save();
ctx.beginPath();
@ -935,51 +934,30 @@ function drawLine(ctx: CanvasRenderingContext2D, pen: MapPen): void {
ctx.beginPath();
ctx.setLineDash([0]);
let [ax, ay] = [0, 0];
let r = 0;
switch (type) {
case MapRouteType.线:
{
ax = x1 + (x2 - x1) * t;
ay = y1 + (y2 - y1) * t;
r = Math.atan2(y2 - y1, x2 - x1);
const { dx, dy, r } = (() => {
switch (type) {
case MapRouteType.线: {
const t = direction < 0 ? 0.55 : 0.45;
const dx = x1 + (x2 - x1) * t;
const dy = y1 + (y2 - y1) * t;
const r = Math.atan2(y2 - y1, x2 - x1) + (direction > 0 ? Math.PI : 0);
return { dx, dy, r };
}
break;
case MapRouteType.线:
{
const t1x = x1 + (c1x - x1) * t;
const t1y = y1 + (c1y - y1) * t;
const t2x = c1x + (x2 - c1x) * t;
const t2y = c1y + (y2 - c1y) * t;
ax = t1x + (t2x - t1x) * t;
ay = t1y + (t2y - t1y) * t;
r = Math.atan2(t2y - t1y, t2x - t1x);
case MapRouteType.线: {
const { x: dx, y: dy, t } = getBezier2Center(p1, { x: c1x, y: c1y }, p2);
const r = getBezier2Tange(p1, { x: c1x, y: c1y }, p2, t) + (direction > 0 ? Math.PI : 0);
return { dx, dy, r };
}
break;
case MapRouteType.线:
{
const t1x = x1 + (c1x - x1) * t;
const t1y = y1 + (c1y - y1) * t;
const t2x = c1x + (c2x - c1x) * t;
const t2y = c1y + (c2y - c1y) * t;
const t3x = c2x + (x2 - c2x) * t;
const t3y = c2y + (y2 - c2y) * t;
const t12x = t1x + (t2x - t1x) * t;
const t12y = t1y + (t2y - t1y) * t;
const t23x = t2x + (t3x - t2x) * t;
const t23y = t2y + (t3y - t2y) * t;
ax = t12x + (t23x - t12x) * t;
ay = t12y + (t23y - t12y) * t;
r = Math.atan2(t23y - t12y, t23x - t12x);
case MapRouteType.线: {
const { x: dx, y: dy, t } = getBezier3Center(p1, { x: c1x, y: c1y }, { x: c2x, y: c2y }, p2);
const r = getBezier3Tange(p1, { x: c1x, y: c1y }, { x: c2x, y: c2y }, p2, t) + (direction > 0 ? Math.PI : 0);
return { dx, dy, r };
}
break;
default:
break;
}
ctx.translate(ax, ay);
if (direction > 0) {
r += Math.PI;
}
default:
return { dx: 0, dy: 0, r: 0 };
}
})();
ctx.translate(dx, dy);
ctx.moveTo(Math.cos(r + Math.PI / 5) * s * 10, Math.sin(r + Math.PI / 5) * s * 10);
ctx.lineTo(0, 0);
ctx.lineTo(Math.cos(r - Math.PI / 5) * s * 10, Math.sin(r - Math.PI / 5) * s * 10);
@ -1083,3 +1061,71 @@ function drawRobot(ctx: CanvasRenderingContext2D, pen: MapPen): void {
ctx.restore();
}
//#endregion
//#region 辅助函数
function getBezier2Center(p1: Point, c1: Point, p2: Point): Point & { t: number } {
const fn = (t: number) => {
const x = (1 - t) ** 2 * p1.x + 2 * (1 - t) * t * c1.x + t ** 2 * p2.x;
const y = (1 - t) ** 2 * p1.y + 2 * (1 - t) * t * c1.y + t ** 2 * p2.y;
return { x, y };
};
return calcBezierCenter(fn);
}
function getBezier2Tange(p1: Point, c1: Point, p2: Point, t: number): number {
const dx = 2 * (1 - t) * (c1.x - p1.x) + 2 * t * (p2.x - c1.x);
const dy = 2 * (1 - t) * (c1.y - p1.y) + 2 * t * (p2.y - c1.y);
return Math.atan2(dy, dx);
}
function getBezier3Center(p1: Point, c1: Point, c2: Point, p2: Point): Point & { t: number } {
const fn = (t: number) => {
const x = (1 - t) ** 3 * p1.x + 3 * (1 - t) ** 2 * t * c1.x + 3 * (1 - t) * t ** 2 * c2.x + t ** 3 * p2.x;
const y = (1 - t) ** 3 * p1.y + 3 * (1 - t) ** 2 * t * c1.y + 3 * (1 - t) * t ** 2 * c2.y + t ** 3 * p2.y;
return { x, y };
};
return calcBezierCenter(fn);
}
function getBezier3Tange(p1: Point, c1: Point, c2: Point, p2: Point, t: number): number {
const t1 = 3 * Math.pow(1 - t, 2);
const t2 = 6 * (1 - t) * t;
const t3 = 3 * Math.pow(t, 2);
const dx = t1 * (c1.x - p1.x) + t2 * (c2.x - c1.x) + t3 * (p2.x - c2.x);
const dy = t1 * (c1.y - p1.y) + t2 * (c2.y - c1.y) + t3 * (p2.y - c2.y);
return Math.atan2(dy, dx);
}
function calcBezierCenter(bezierFn: (t: number) => Point): Point & { t: number } {
const count = 23;
let length = 0;
let temp = bezierFn(0);
const samples = Array.from({ length: count }, (_, i) => {
const t = (i + 1) / count;
const point = bezierFn(t);
const dx = point.x - temp.x;
const dy = point.y - temp.y;
length += Math.sqrt(dx * dx + dy * dy);
temp = point;
return { ...point, t };
});
const target = length / 2;
let accumulated = 0;
for (let i = 0; i < samples.length - 1; i++) {
const p1 = samples[i];
const p2 = samples[i + 1];
const segment = Math.sqrt((p2.x - p1.x) ** 2 + (p2.y - p1.y) ** 2);
if (accumulated + segment >= target) {
const ratio = (target - accumulated) / segment;
return {
x: p1.x + (p2.x - p1.x) * ratio,
y: p1.y + (p2.y - p1.y) * ratio,
t: p1.t + ratio * (p2.t - p1.t),
};
}
accumulated += segment;
}
return samples[samples.length - 1];
}
//#endregion