如何找到矩形周长中最近的点到给定点?

时间:2013-12-08 12:43:53

标签: math geometry rectangles bounding-box

这是一个与语言无关的问题。给定l,t,w,h(左,顶,宽,高)和点x,y的矩形尺寸,如何找到矩形周长上最近的点?

我试图在Lua中解决它,但任何其他语言都可以。到目前为止,这是我的最大努力:

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

这适用于周边点或周边本身。但是对于外围的内部,它会失败(它只会返回x,y

我的直觉告诉我解决方案应该很简单,但我似乎找不到它。

5 个答案:

答案 0 :(得分:14)

这次我试图抓住点到矩形任何一侧的最小距离。

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

答案 1 :(得分:1)

设C1,C2,C3,C4为矩形的顶点。
从给定的A点开始绘制2条为
的线 垂直于矩形的边。设B1,B2,B3,B4
是与他们确定的线的交叉点 矩形的两边(其中一些Bk也可能重合 例如如果A = Ck某些k)。你的解决方案是Bk
的要点之一 或其中一个点Ck,只需蛮力检查8点
(同样,这8个点中的一些可能重合,但这无关紧要。)

答案 2 :(得分:1)

另一种可能的算法(类似于我的第一个答案)可以在这里找到 - 来自Dinre。

Calculating the distance between polygon and point in R

看起来很简单,实际上它是我的第一个答案的简化(可能更好)版本。

找到给定点A的两个最近的矩形顶点Ci和Cj。

找到从A到线(Ci,Cj)的垂线与线(Ci,Cj)相交的点M.

您的解决方案是Ci或Cj或M.

对我而言似乎适用于所有情况(无论A点位于飞机的哪个位置)。

答案 3 :(得分:0)

你正在寻找这样的东西吗? 受Keeper代码的启发:

local function getNearestPointInPerimeter(l,t,w,h, x,y)
  -- x axis increases to the right
  -- y axis increases down
  local r = l + w
  local b = t + h
  local inside = true -- unless later proven otherwise
  -- if the point (x,y) is outside the rectangle,
  -- push it once to the nearest point on the perimeter, or
  -- push it twice to the nearest corner.
  if x < l then x = l; inside = false; end
  if x > r then x = r; inside = false; end
  if y < t then y = t; inside = false; end
  if y > b then y = b; inside = false; end
  -- if the point (x,y) is inside the rectangle,
  -- push it once to the closest side.
  if inside then
      local dt = math.abs (y - t)
      local db = math.abs (y - b)
      local dl = math.abs (x - l)
      local dr = math.abs (x - r)
      if dt <= db and dt <= dl and dt <= dr then
        y = t
      elseif db <= dl and db <= dr then
        y = b
      elseif dl <= dr then
        x = l
      else
        x = r
      end
  end
  return x,y
end

答案 4 :(得分:0)

感谢您提出问题和答案!这是我选择的答案的python翻译版本,以防任何人需要它。唯一的自定义部分是使用lambda的钳位内联函数定义。

我在使用Qt的QRect和QPoint的GUI中成功地使用了它,以确保在QGraphcsView中显示出某些内容。

<?xml version="1.0" encoding="utf-8"?>
<CheckBox
        android:id="@+id/cb_row_item"
        xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentLeft="true"
        android:layout_alignParentStart="true"
        android:text="Category name goes here"
        android:textSize="15sp"/>