Home > other >  Find closed rectangle edge to a point
Find closed rectangle edge to a point

Time:06-23

Given a rectangle, rect ((left, top), (bottom, right)), and a point (x, y), how can I find which edge of the rectangle is closest to the point.

findClosestEdge(rect, point): string {
    closestEdge = ....
    return closestEdge; // i.e. "top" | "bottom" | "left" | "right"
}

It's ok to assume that the rectangle isn't rotated.

CodePudding user response:

Here's an implementation that divides the 2D space into quadrants. The quadrants correspond to the areas created by the diagonals of the rectangle r, so there will be a top, right, bottom, and left quadrant. Each quadrant has a start angle and an end angle; these angles are calculated based on the center of the rectangle, and the corners of the rectangle.

Similarly, we find the angle between the center of the rectangle and the point p that we're interested in. Then it's just a matter of checking which quadrant(s) the point lies in. Note that the point can be equidistant to multiple sides, so the function returns an array.

interface Point {
  x: number;
  y: number;
}

interface Rect {
  lt: Point;
  rb: Point;
}

function findClosestEdge(r: Rect, p: Point) {
  const getCenter = (r: Rect) => ({
    x: (r.lt.x   r.rb.x) / 2,
    y: (r.lt.y   r.rb.y) / 2}
  );
  const getAngle = (p1: Point, p2: Point) => Math.atan2(p2.y - p1.y, p2.x - p1.x);
  
  const sides = ['top', 'right', 'bottom', 'left'];
  const corners = [
    {x: r.lt.x, y: r.lt.y},
    {x: r.rb.x, y: r.lt.y},
    {x: r.rb.x, y: r.rb.y},
    {x: r.lt.x, y: r.rb.y}
  ];
  
  const center = getCenter(r);

  if (center.x === p.x && center.y === p.y) {
    return [...sides];
  }

  const angle = getAngle(center, p);
  const angles = corners.map(corner => getAngle(center, corner));
  const quadrants = sides.map((side, i) => ({
    side,
    start: angles[i],
    end: angles[(i   1) % angles.length]
  }));

  return quadrants.filter(
    ({start, end}) => angle >= start && angle <= end
  ).map(({side}) => side);
}

console.log(findClosestEdge({lt: {x: 0, y: 0}, rb: {x: 10, y: 10}}, {x: 20, y: 4}));
console.log(findClosestEdge({lt: {x: 0, y: 0}, rb: {x: 10, y: 10}}, {x: 5, y: 4}));
console.log(findClosestEdge({lt: {x: 0, y: 0}, rb: {x: 10, y: 10}}, {x: 5, y: 5}));

Playground link

  • Related