Browse Source

绘制标准线

feature/rail
zhangjiming 5 months ago
parent
commit
40ea0a7efa
  1. 119
      src/pages/measure/components/graph/StandardLayer.tsx
  2. 60
      src/utils/index.ts

119
src/pages/measure/components/graph/StandardLayer.tsx

@ -1,4 +1,28 @@
import { useCallback, useEffect, useRef } from "react";
import { calculateCircleAbove, calculateCircleBelow } from "../../../../utils";
const unitPx = 8;
const pointsR: [number, number][] = [
[0, 0],
[9.949007022412, 0.1650166186941],
[25.35, 2.184814802617],
[35.4, 14.20034968551],
[36.31679456414, 32.538841443],
[32.90417417089, 37.53190928715],
[20.0, 41.8333134842],
];
const pointsL: [number, number][] = [
[-20.0, 41.83331348425],
[-32.90417417089, 37.53190928715],
[-36.31679456414, 32.538841443],
[-35.4, 14.20034968551],
[-25.35, 2.184814802617],
[-9.949007022412, 0.1650166186941],
[0, 0],
];
const pointsRight = pointsR.map(p => [p[0] * unitPx, p[1] * unitPx]);
const pointsLeft = pointsL.map(p => [p[0] * unitPx, p[1] * unitPx]);
export default function StandardLayer(props: {
width: number;
@ -9,10 +33,101 @@ export default function StandardLayer(props: {
bottomPadding: number;
}) {
const canvasRef = useRef<HTMLCanvasElement | null>(null);
const draw = useCallback((ctx: CanvasRenderingContext2D) => {
// 使用context对象进行绘图
ctx.fillStyle = "skyblue"; // 设置填充颜色
ctx.fillRect(50, 50, 150, 100); // 绘制一个矩形
ctx.fillStyle = "blue";
ctx.strokeStyle = "blue";
ctx.translate(400, 100);
ctx.moveTo(-400, 0);
ctx.lineTo(400, 0);
ctx.moveTo(0, -100);
ctx.lineTo(0, 500);
ctx.stroke();
ctx.beginPath();
ctx.strokeStyle = "red";
// ---- 右侧
let point0 = pointsRight[0];
let point1 = pointsRight[1];
ctx.moveTo(point0[0], point0[1]);
let param = calculateCircleBelow(point0[0], point0[1], point1[0], point1[1], 300 * unitPx);
console.log(param);
ctx.arc(param.center.x, param.center.y, 300 * unitPx, param.anglesForCenter.startAngle, param.anglesForCenter.endAngle);
point0 = pointsRight[1];
point1 = pointsRight[2];
ctx.moveTo(point0[0], point0[1]);
param = calculateCircleBelow(point0[0], point0[1], point1[0], point1[1], 80 * unitPx);
console.log(param);
ctx.arc(param.center.x, param.center.y, 80 * unitPx, param.anglesForCenter.startAngle, param.anglesForCenter.endAngle);
point0 = pointsRight[2];
point1 = pointsRight[3];
ctx.moveTo(point0[0], point0[1]);
param = calculateCircleBelow(point0[0], point0[1], point1[0], point1[1], 13 * unitPx);
console.log(param);
ctx.arc(param.center.x, param.center.y, 13 * unitPx, param.anglesForCenter.startAngle, param.anglesForCenter.endAngle);
point0 = pointsRight[3];
point1 = pointsRight[4];
ctx.moveTo(point0[0], point0[1]);
ctx.lineTo(point1[0], point1[1]);
point0 = pointsRight[4];
point1 = pointsRight[5];
ctx.moveTo(point0[0], point0[1]);
param = calculateCircleAbove(point0[0], point0[1], point1[0], point1[1], 5 * unitPx);
console.log(param);
ctx.arc(param.center.x, param.center.y, 5 * unitPx, param.anglesForCenter.startAngle, param.anglesForCenter.endAngle);
point0 = pointsRight[5];
point1 = pointsRight[6];
ctx.moveTo(point0[0], point0[1]);
ctx.lineTo(point1[0], point1[1]);
// ---- 左侧
point0 = pointsLeft[0];
point1 = pointsLeft[1];
ctx.moveTo(point0[0], point0[1]);
ctx.lineTo(point1[0], point1[1]);
point0 = pointsLeft[1];
point1 = pointsLeft[2];
ctx.moveTo(point0[0], point0[1]);
param = calculateCircleAbove(point0[0], point0[1], point1[0], point1[1], 5 * unitPx);
console.log(param);
ctx.arc(param.center.x, param.center.y, 5 * unitPx, param.anglesForCenter.startAngle, param.anglesForCenter.endAngle);
point0 = pointsLeft[2];
point1 = pointsLeft[3];
ctx.moveTo(point0[0], point0[1]);
ctx.lineTo(point1[0], point1[1]);
point0 = pointsLeft[3];
point1 = pointsLeft[4];
ctx.moveTo(point0[0], point0[1]);
param = calculateCircleBelow(point0[0], point0[1], point1[0], point1[1], 13 * unitPx);
console.log(param);
ctx.arc(param.center.x, param.center.y, 13 * unitPx, param.anglesForCenter.startAngle, param.anglesForCenter.endAngle);
point0 = pointsLeft[4];
point1 = pointsLeft[5];
ctx.moveTo(point0[0], point0[1]);
param = calculateCircleBelow(point0[0], point0[1], point1[0], point1[1], 80 * unitPx);
console.log(param);
ctx.arc(param.center.x, param.center.y, 80 * unitPx, param.anglesForCenter.startAngle, param.anglesForCenter.endAngle);
point0 = pointsLeft[5];
point1 = pointsLeft[6];
ctx.moveTo(point0[0], point0[1]);
param = calculateCircleBelow(point0[0], point0[1], point1[0], point1[1], 300 * unitPx);
console.log(param);
ctx.arc(param.center.x, param.center.y, 300 * unitPx, param.anglesForCenter.startAngle, param.anglesForCenter.endAngle);
ctx.stroke();
// ctx.fillRect(100, 100, 150, 100); // 绘制一个矩形
}, []);
useEffect(() => {
const canvas = canvasRef.current;

60
src/utils/index.ts

@ -3,3 +3,63 @@ export function formatRemainTime(seconds: number) {
const sec = (seconds % 60).toFixed();
return min.padStart(2, "0") + ":" + sec.padStart(2, "0");
}
export function calculateCircleInfo(x1: number, y1: number, x2: number, y2: number, radius: number) {
// 计算P1到P2的中点
const xm = (x1 + x2) / 2;
const ym = (y1 + y2) / 2;
// P1到P2的距离的一半
const dx = x2 - x1;
const dy = y2 - y1;
const d = Math.sqrt(dx * dx + dy * dy) / 2;
// 如果距离大于直径,则无法形成圆
if (d > radius) {
throw new Error("Given points are too far apart for the given radius.");
}
// 计算垂直平分线的方向向量
const len = Math.sqrt(radius * radius - d * d);
const nx = dy / (2 * d);
const ny = -dx / (2 * d);
// 计算两个可能的圆心
const cx1 = xm + nx * len;
const cy1 = ym + ny * len;
const cx2 = xm - nx * len;
const cy2 = ym - ny * len;
// 使用atan2计算起始角和结束角
function calculateAngle(cx: number, cy: number, px: number, py: number) {
return Math.atan2(py - cy, px - cx);
}
const startAngle1 = calculateAngle(cx1, cy1, x1, y1);
const endAngle1 = calculateAngle(cx1, cy1, x2, y2);
const startAngle2 = calculateAngle(cx2, cy2, x1, y1);
const endAngle2 = calculateAngle(cx2, cy2, x2, y2);
return [
{ center: { x: cx1, y: cy1 }, anglesForCenter: { startAngle: startAngle1, endAngle: endAngle1 } },
{ center: { x: cx2, y: cy2 }, anglesForCenter: { startAngle: startAngle2, endAngle: endAngle2 } },
];
}
export type CenterAndAngle = ReturnType<typeof calculateCircleBelow>;
export function calculateCircleBelow(x1: number, y1: number, x2: number, y2: number, radius: number) {
const results = calculateCircleInfo(x1, y1, x2, y2, radius);
if (results[0].center.y > results[1].center.y) {
return results[0];
} else {
return results[1];
}
}
export function calculateCircleAbove(x1: number, y1: number, x2: number, y2: number, radius: number) {
const results = calculateCircleInfo(x1, y1, x2, y2, radius);
if (results[0].center.y < results[1].center.y) {
return results[0];
} else {
return results[1];
}
}
Loading…
Cancel
Save