找到一条直线的垂直点

Find a point on perpendicular of a line

我有一个角度为 A 的不规则多边形 (x1,y1) (x2,y2) 的边和边的中点 (mx, my)。

我需要在 A 穿过 (mx, my) 的垂线上找到两个点 (x3,y3) 和 (x4,y4),并有一些偏移。这样我就可以检查哪个点是多边形的 inside/outside。

我将使用外面的来显示多边形边的测量文本,例如 2cms

Click to see Visuals

旋转四分之一圈很容易:如果您有一个坐标为 (x, y) 的矢量,并将其逆时针旋转四分之一圈,则新矢量的坐标为 (-y, x) .

求垂线上的点(x5,y5),可以将点(x2,y2)以(mx,my)为中心逆时针旋转四分之一圈,这样:

x5 - mx = - (y2 - my)
y5 - my = x2 - mx

然后你可以通过重新归一化向量 (x5-mx, y5-my) 来选择你的两个点 (x3, y3) 和 (x4, y4) 以获得你想要的长度:

x4 - mx = (x5 - mx) * (2 cm) / ((x5-mx)**2 + (y5-my)**2)
y4 - my = (y5 - my) * (2 cm) / ((x5-mx)**2 + (y5-my)**2)

x3 - mx = (x5 - mx) * (-2 cm) / ((x5-mx)**2 + (y5-my)**2)
y3 - my = (y5 - my) * (-2 cm) / ((x5-mx)**2 + (y5-my)**2)

首先你得求边方程:

y - y1 = (y2-y1)/(x2-x1)*(x-x1)
y = (y2-y1)/(x2-x1) * x1 - (y2-y1)/(x2-x1) * x + y1

一旦你有了这样的等式y=mx+q(y 和 x 是常数,所以你只关心找到 m 和 q)你就可以找到中间点

M((x1+x2)/2), (y1+y2)/2)

当您同时拥有方程式和中点时,您可以选择偏移量。现在只需在段

上找到与该偏移量对应的点
P1(mx + offset, my + (offset * m)) and P2(mx - offset, my - (offset * m))

where m is the one you found in the first equation

现在你有2分 要找出哪个在里面,哪个在外面,我们需要更多的数据。例如,您可以尝试平分角度以找到多边形 M1 的中点,并检查 P1 和 P2 之间的哪一个与 M1 有距离,以便:

if distance(P1, M1) < distance(M, M1) then P1 is inside
"if the distance between the point and the middle of the polygon is less than the distance between the middle of the polygon and the middle of the side then P1 is inside the polygon"

还有其他解决方案,但根据可用数据,我只能这样做。现在你只需要把这个解释变成代码

图例:

y -> equation constant 
x -> equation constant
m -> line inclination 
q -> intersection with axis (you really don't need it for this) 
M -> middle point of the side mx, my -> coordinates of middle point of the side 
P1 -> point on the line with positive offset 
P2 -> point on the line with negative offset 
M1 -> middle point of the polygon

您没有指定语言,但几乎所有语言都有 atan2 function

canvas.width = window.innerWidth - 10;
canvas.height = window.innerHeight - 10;
const ctx = canvas.getContext('2d');

const line = [canvas.width/2, canvas.height/2, 10, 10];
const pLen = 100; // Length of perpendicular

function drawOrto(line) {
  // line vector
  const dx = line[2] - line[0];
  const dy = line[3] - line[1];

  // center point
  const mx = line[0] + dx / 2;
  const my = line[1] + dy / 2;
 
  const atan = Math.atan2(dy, dx);
  // perpendicular vector
  const pdx = - pLen * Math.sin(atan);
  const pdy = pLen * Math.cos(atan);

  ctx.clearRect(0, 0, canvas.width, canvas.height);  
  
  // Line 
  ctx.beginPath();
  ctx.strokeStyle = 'black';
  ctx.moveTo(line[0], line[1]);
  ctx.lineTo(line[2], line[3]);
  ctx.stroke();
  
  // Perpendicular (draw vector both sides from center) 
  ctx.beginPath();
  ctx.strokeStyle = 'red';
  ctx.moveTo(mx - pdx / 2, my - pdy / 2);
  ctx.lineTo(mx + pdx / 2, my + pdy / 2);
  ctx.stroke();
  
  // Dots
  ctx.fillStyle = 'red';
  ctx.fillRect(line[0] - 1, line[1] - 1, 3, 3);
  ctx.fillRect(line[2] - 1, line[3] - 1, 3, 3);
  
  ctx.fillStyle = 'yellow';  
  ctx.fillRect(mx - 1, my - 1, 3, 3);
  
  ctx.fillStyle = 'green';  
  ctx.fillRect(mx - pdx / 2 - 1, my - pdy / 2 - 1, 3, 3);
  ctx.fillRect(mx + pdx / 2 - 1, my + pdy / 2 - 1, 3, 3);
}


drawOrto(line);
canvas.onmousemove = e => {
  line[2] = e.offsetX;
  line[3] = e.offsetY;
  drawOrto(line);
}
<canvas id=canvas></canvas>