Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to find the nearest point in the perimeter of a rectangle to a given point?

This is a language-agnostic question. Given a rectangle's dimensions with l,t,w,h (left, top, width, height) and a point x,y, how do I find the nearest point on the perimeter of the rectangle to that point?

I have tried to resolve it in Lua, but any other language would do. So far this is my best effort:

local function nearest(x, a, b)
  if a <= x and x <= b then
    return x
  elseif math.abs(a - x) < math.abs(b - x) then
    return a
  else
    return b
  end
end

local function getNearestPointInPerimeter(l,t,w,h, x,y)
  return nearest(x, l, l+w), nearest(y, t, t+h)
end

This works for a point outside of the perimeter or in the perimeter itself. But for points inside of the perimeter it fails (it just returns x,y)

My gut tells me that the solution should be simple, but I don't seem to find it.

like image 858
kikito Avatar asked Dec 08 '13 12:12

kikito


2 Answers

This time I'm trying to catch the minimum distance of the point toward any side of the rectangle.

local abs, min, max = math.abs, math.min, math.max

local function clamp(x, lower, upper)
  return max(lower, min(upper, x))
end

local function getNearestPointInPerimeter(l,t,w,h, x,y)
  local r, b = l+w, t+h

  x, y = clamp(x, l, r), clamp(y, t, b)

  local dl, dr, dt, db = abs(x-l), abs(x-r), abs(y-t), abs(y-b)
  local m = min(dl, dr, dt, db)

  if m == dt then return x, t end
  if m == db then return x, b end
  if m == dl then return l, y end
  return r, y
end
like image 197
Keeper Avatar answered Sep 21 '22 16:09

Keeper


Let C1,C2,C3,C4 be the vertices of the rectangle.
From the given point A which you have, draw the 2 lines which are
perpendicular to the sides of the rectangle. Let B1, B2, B3, B4
be their intersecting points with the lines determined by the
sides of the rectangle (some of these Bk may coincide too
e.g. if A = Ck for some k). Your solution is one of the points Bk
or one of the points Ck, just brute-force check the 8 points
(again, some of these 8 points may coincide but that doesn't matter).

like image 28
peter.petrov Avatar answered Sep 22 '22 16:09

peter.petrov