I'm trying to achieve something on JS which probably is not that hard, but not for my brain, unfortunately.
I have 4 arrays which are corners forming a rectangle in two-dimensional space.
var corner1 = [x, y];
var corner2 = [x, y];
var corner3 = [x, y];
var corner4 = [x, y];
I have a point which is inside that rectangle (I don't have to check that).
var point = [x, y]
I need to find the closest location to that point which is just next to the closest edge.
Here is a picture which describes better what I want to achieve.
CodePudding user response:
You can use a formula to get the closest point on a line, and repeat it for the four sides of the rectangle. Then pick the one that is closest.
Here is a snippet that defines a rectangle (hard-coded), draws it, and then captures the mouse position as the "my point" in your question. The formula is used to calculate the closest position on the rectangle and draws it as a red point:
// Utility functions for vectors
const squaredSize = v => v[0]**2 v[1]**2;
const sub = (v, w) => [v[0] - w[0], v[1] - w[1]];
const add = (v, w) => [v[0] w[0], v[1] w[1]];
const mul = (v, k) => [v[0]*k, v[1]*k];
const squaredDistance = (a, b) => squaredSize(sub(a, b));
const dot = (v, w) => v[0]*w[0] v[1]*w[1];
function closestPointOnLine(a, b, p) {
const ap = sub(p, a);
const ab = sub(b, a);
return add(a, mul(ab, dot(ap, ab) / squaredSize(ab)));
}
function closestPointOnPoly(poly, p) {
const points = poly.map((a, i) => closestPointOnLine(a, rect[(i 1)%4], p));
const dists = points.map(q => squaredDistance(p, q));
return points[dists.indexOf(Math.min(...dists))];
}
// I/O management
const canvas = document.querySelector("canvas");
const ctx = canvas.getContext("2d");
const rect = [[30, 10], [130, 30], [121, 60], [21, 40]];
drawPoly(rect);
document.addEventListener("mousemove", function (e) {
const p = [e.clientX, e.clientY];
const closest = closestPointOnPoly(rect, p);
render(rect, closest);
});
function render(poly, point) {
ctx.clearRect(0, 0, canvas.width, canvas.height);
drawPoly(poly);
drawPoint(point);
}
function drawPoly(points) {
ctx.moveTo(...points.at(-1));
for (let p of points) ctx.lineTo(...p);
ctx.stroke();
}
function drawPoint(point) {
ctx.beginPath();
ctx.arc(...point, 2, 0, 2 * Math.PI, true);
ctx.fillStyle = "red";
ctx.fill();
}
html, body { margin: 0 }
<canvas></canvas>