Reputation: 481
I intend to find the coordinate on the line that is closest to from a given coordinate. Let's suppose I have a line.
var line={x0:114,y0:366,x1:306,y1:30};
And I have some random coordinate like 300 and 200 both are in pixel. I am able to connect the line with straight line concept. The function of shortest coordinate on line from given coordinate is:
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});
};
And connected the line with :
var canvas=document.getElementById("canvas");
var ctx=canvas.getContext("2d");
var cord=getClosestPointOnLine(line_d,x,y);
ctx.lineTo(cord3.x,cord3.y);
The example is:
But I wanted to join the line at some angle which parallel to the stripes given the figure. Such as:
How should I change my approach to get the desired result.
Upvotes: 0
Views: 639
Reputation: 136627
You have one point on a line, and an angle, so you can easily draw your line using a bit of 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>
So now, all you need to find is the point of intersection of these two lines:
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>
And you will note that there is no "closest" point in this case, because you will always have at most only a single point that will meet these conditions.
Upvotes: 2