Как рассчитать расстояние от точки до ближайшей точки прямоугольника? - PullRequest
0 голосов
/ 24 августа 2018

У меня есть выровненный по оси прямоугольник в двумерной системе координат, представленной точкой в ​​нижнем левом углу и точкой в ​​верхнем правом углу, а также точкой, которая может быть внутри или снаружи прямоугольника.Я хочу найти расстояние от точки до ближайшей точки прямоугольника, независимо от того, находится она внутри прямоугольника или нет.Конечно, я мог бы просто написать коммутатор с 9 различными результатами, но я надеюсь, что есть более элегантное решение.
Кроме того, я нашел несколько решений этой проблемы (например, эта ),но все они вычислили бы расстояние как 0, если точка находится внутри прямоугольника, чего я не хочу.

Ответы [ 3 ]

0 голосов
/ 24 августа 2018

Вы можете расширить связанное решение MultiRRomero и выполнить некоторые дополнительные вычисления для точек внутри прямоугольника.

Для этих точек ближайшая точка на границе прямоугольника имеет такую ​​же x или y координату, что и точка. Таким образом, вычисление расстояний до линий является прямым, и наименьшее будет желаемое расстояние.

function distance(rect, p) {
  var dx = Math.max(rect.min.x - p.x, 0, p.x - rect.max.x);
  var dy = Math.max(rect.min.y - p.y, 0, p.y - rect.max.y);
  var distance = Math.sqrt(dx*dx + dy*dy)
  if (distance == 0) {
    distance = Math.min(p.x - rect.min.x, rect.max.x - p.x, p.y - rect.min.y, rect.max.y - p.y)
  }
  return distance
}

Редактировать: исправлены опечатки

0 голосов
/ 24 августа 2018

Мой ответ немного длиннее других, но он исходит из другой точки зрения.

Ключ не в том, если вы находитесь внутри прямоугольника , но если выв любом месте в пределах коридоров, определяемых путем взятия сторон прямоугольника и их бесконечного вытягивания (изобразите бесконечный знак плюс, центрированный в прямоугольнике).

Если он находится внутри этих коридоров, то ближайшее расстояние ортогонально одному изстороны.

Если он снаружи, то самое близкое расстояние - это расстояние до ближайшего угла.

Ваш код может выглядеть так:

nearest_distance(rectangle, point):
    d_top = abs(rectangle.top - point.y)
    d_bottom = abs(rectangle.bottom - point.y)
    corner_y = d_top < d_bottom ? rectangle.top : rectangle.bottom

    d_left = abs(rectangle.left - point.x)
    d_right = abs(rectangle.right - point.x)
    corner_x = d_left < d_right ? rectangle.left : rectangle.right

    d_cx = corner_x - point.x
    d_cy = corner_y - point.y
    d_corner = sqrt(d_cx*d_cx + d_cy*d_cy)

    return min(d_top, d_bottom, d_left, d_right, d_corner)

Если вы хотитечтобы попытаться сохранить sqrt, вы можете проверить, находитесь ли вы в коридорах или за их пределами.В этом случае вы бы изменили его следующим образом:

nearest_distance(rectangle, point):
    d_top = abs(rectangle.top - point.y)
    d_bottom = abs(rectangle.bottom - point.y)
    d_left = abs(rectangle.left - point.x)
    d_right = abs(rectangle.right - point.x)

    r = rectangle # just to make the next line neater
    if r.left <= point.x <= r.right or r.bottom <= point.y <= r.top:
        return min(d_top, d_bottom, d_left, d_right)
    else:
        corner_y = d_top < d_bottom ? rectangle.top : rectangle.bottom
        corner_x = d_left < d_right ? rectangle.left : rectangle.right

        d_cx = corner_x - point.x
        d_cy = corner_y - point.y
        d_corner = sqrt(d_cx*d_cx + d_cy*d_cy)
        return d_corner
0 голосов
/ 24 августа 2018

Как насчет этого?(первая часть «украдена» у MultiRRomeros ответ )

function distance(rect, p) {
  // outside
  var dxo = Math.max(rect.min.x - p.x, 0, p.x - rect.max.x);
  var dyo = Math.max(rect.min.y - p.y, 0, p.y - rect.max.y);
  var hypothenuse = Math.sqrt(dxo*dxo + dyo*dyo);

  // inside
  var dxi = Math.min(rect.max.x - p.x, p.x - rect.min.x);
  var dyi = Math.min(rect.max.y - p.y, p.y - rect.min.y);

  return hypothenuse > 0 ? hypothenuse : Math.min(dxi, dyi);
}
...