如何在HTML Canvas中从给定坐标以给定角度查找直线上最接近的坐标

时间:2018-10-10 07:08:53

标签: javascript html5 html5-canvas

我打算在距给定坐标最近的线上找到坐标。 假设我有一行。

var line={x0:114,y0:366,x1:306,y1:30};

我有一些随机坐标,例如300和200都以像素为单位。 我可以将直线与直线概念连接起来。 从给定坐标开始的最短坐标的功能是:

function getClosestPointOnLine(line,x,y) {
    lerp=function(a,b,x){ return(a+x*(b-a)); };
    var dx=line.x1-line.x0;
    var dy=line.y1-line.y0;
    var t=((x-line.x0)*dx+(y-line.y0)*dy)/(dx*dx+dy*dy);
    t=Math.min(1,Math.max(0,t));
    var lineX=lerp(line.x0, line.x1, t);
    var lineY=lerp(line.y0, line.y1, t);
    return({x:lineX,y:lineY});
};

然后将线路与:

var canvas=document.getElementById("canvas");
var ctx=canvas.getContext("2d");
var cord=getClosestPointOnLine(line_d,x,y);
ctx.lineTo(cord3.x,cord3.y);

示例为:

Straight line joining to the line

但是我想以平行于给定图形的条纹的某个角度将线连接起来。如: The desired output

我应该如何改变方法以获得理想的结果。

1 个答案:

答案 0 :(得分:2)

您在一条线上有一个点,并且有一个角度,因此可以使用一些trigo轻松绘制线:

const pt1 = {
  x: 120,
  y: 100
};
const r = 30; // length of our segment, not really needed afterward


const ctx = canvas.getContext('2d');

function draw() {
  const angle = inp.value;
  // find pt2 using trigonometry
  const pt2 = {
    x: pt1.x + r * Math.cos(angle),
    y: pt1.y + r * Math.sin(angle)
  };

  ctx.clearRect(0, 0, canvas.width, canvas.height);
  ctx.fillRect(pt1.x - 2, pt1.y - 2, 4, 4);
  ctx.fillRect(pt2.x - 2, pt2.y - 2, 4, 4);
  ctx.beginPath();
  ctx.moveTo(pt1.x, pt1.y);
  ctx.lineTo(pt2.x, pt2.y);
  ctx.stroke();
}

inp.oninput = draw;
draw();
<input type="range" id="inp" min="0" max="6.29" step="0.01"><br>
<canvas id="canvas"></canvas>

所以现在,您需要找到的是这两条线的交点:

const line1 = {
  x1: 30,
  y1: 30,
  x2: 10,
  y2: 100
};

const pt1 = {
  x: 80,
  y: 80
}

const ctx = canvas.getContext('2d');

function draw(x, y) {
  angle = inp.value;
  ctx.clearRect(0, 0, canvas.width, canvas.height);
  ctx.strokeStyle = 'gray';
  ctx.beginPath();
  ctx.moveTo(line1.x1, line1.y1);
  ctx.lineTo(line1.x2, line1.y2);
  ctx.stroke();

  const line2 = {
    x1: pt1.x,
    y1: pt1.y,
    // here our radius can be hardcoded
    x2: pt1.x + 1 * Math.cos(angle),
    y2: pt1.y + 1 * Math.sin(angle)
  }
  const inter = intersect(
    line1.x1, line1.y1, line1.x2, line1.y2,
    line2.x1, line2.y1, line2.x2, line2.y2
  );
  if (!inter) {
    ctx.fillText('parrallel', 20, 20);
    return;
  }
  if (inter.x < Math.min(line1.x1, line1.x2) || inter.x > Math.max(line1.x1, line1.x2) ||
    inter.y < Math.min(line1.y1, line1.y2) || inter.y > Math.max(line1.y1, line1.y2)) {
    ctx.fillText('Out of bounds', 20, 20);
    return;
  }
  ctx.strokeStyle = 'green';
  ctx.beginPath();
  ctx.moveTo(pt1.x, pt1.y);
  ctx.lineTo(inter.x, inter.y);
  ctx.stroke();
}

document.onmousemove = e => {
  const rect = canvas.getBoundingClientRect();
  pt1.x = e.clientX - rect.left;
  pt1.y = e.clientY - rect.top;
  draw();
};
inp.oninput = draw;
draw();

/* Edited from http://paulbourke.net/geometry/pointlineplane/javascript.txt */
function intersect(x1, y1, x2, y2, x3, y3, x4, y4) {

  // Check if none of the lines are of length 0
  if ((x1 === x2 && y1 === y2) || (x3 === x4 && y3 === y4)) {
    return false
  }

  denominator = ((y4 - y3) * (x2 - x1) - (x4 - x3) * (y2 - y1))

  // Lines are parallel
  if (denominator === 0) {
    return false
  }

  let ua = ((x4 - x3) * (y1 - y3) - (y4 - y3) * (x1 - x3)) / denominator
  let ub = ((x2 - x1) * (y1 - y3) - (y2 - y1) * (x1 - x3)) / denominator

  // Return a object with the x and y coordinates of the intersection
  let x = x1 + ua * (x2 - x1)
  let y = y1 + ua * (y2 - y1)

  return {
    x,
    y
  }
}
<input type="range" id="inp" min="0" max="6.29" step="0.01" value="0"><br>
<canvas id="canvas"></canvas>

并且您会注意到在这种情况下没有“ 最接近”点,因为您始终最多只有一个满足这些条件的点。