Подтвердить что ты не робот

Расчет расстояния между точкой и прямоугольной коробкой (ближайшая точка)

есть ли простая формула для вычисления этого? я работал над некоторой математикой, но я могу найти способ рассчитать расстояние, направленное к центру поля, а не направленное к ближайшей точке.. есть ли ресурсы по этой проблеме?

4b9b3361

Ответ 1

Вот одна формула, которая позволяет избежать всей логики случая. (Я, оказывается, сейчас работаю в JS, поэтому здесь реализация JS). Пусть rect = {max:{x:_, y:_}, min:{x:_, y:_}} и p={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);
  return Math.sqrt(dx*dx + dy*dy);
}

Объяснение: Это разбивает проблему на вычисление расстояния x dx и расстояния y dy. Затем он использует формулу расстояния.

Для расчета dx, вот как это работает. (dy аналогично)

Посмотрите, как кортеж предоставляется максимальной функции: (min-p, 0, p-max). Обозначим этот кортеж (a,b,c).

Если p осталось от min, то мы имеем p < мин < max, что означает, что кортеж будет оцениваться до (+,0,-), и поэтому функция max вернет значение a = min - p.

Если p находится между min и max, то min < p < max, что означает, что кортеж будет оцениваться до (-,0,-). Опять же, функция max вернет значение b = 0.

Наконец, если p находится справа от max, то мы имеем min < max < p, а кортеж оценивается до (-,0,+). Еще раз Math.max корректно возвращает c = p - max.

Итак, оказывается, что вся логика case заботится о Math.max, что приводит к хорошей 3-строчной функции без потока управления.

Ответ 2

Я думаю, вам нужно проанализировать случаи; нет единой формулы. Легче проиллюстрировать в двух измерениях:

1          2          3
    +-------------+
    |             |
4   |      0      |   5
    |             |
    +-------------+
6          7          8

Края коробки (расширенные) делят внешнюю сторону на 9 областей. Регион 0 (внутри коробки) решается путем вычисления расстояния до каждого края и принятия минимума. Каждая точка в области 1 ближе всего к верхней левой вершине и аналогично для областей 3, 6 и 8. Для областей 2, 4, 5 и 7 вам нужно найти расстояние от точки до ближайшего края, что является довольно простой проблемой. Вы можете определить, в какой области находится точка, классифицируя ее по отношению к каждому ребру. (Легче видеть, как это сделать, направляя ребрам, скажем, против часовой стрелки.) Это также скажет вам, находится ли точка внутри поля.

В 3D логика точно такая же, за исключением того, что вы классифицируете по отношению к шести лицам, и у вас больше случаев.

Проблема проще, если края окна параллельны осям координат.

Ответ 3

Скажем, что точка называется P, а ABCD - наш прямоугольник. Тогда задачу можно разложить на следующий набор подзадач:

(1) Разработайте функцию dist(P, AB), которая вычисляет расстояние между точкой P и произвольным отрезком AB.

(2) Рассчитайте четыре расстояния между вашей точкой P и каждой стороной прямоугольника (каждая сторона является сегментом) и возьмите кратчайший из четырех

  distance = min(dist(P, AB), dist(P,BC), dist(P, CD), dist(P, DA))

Это ваш ответ.

Теперь нам нужно знать, как рассчитать расстояние между точкой P и произвольным отрезком AB, то есть как рассчитать dist(P, AB). Это делается следующим образом

(1) Выполните перпендикулярную проекцию точки P на строку AB. Вы получите новую точку P' на AB.

(2) Если P' находится между A и B, тогда dist(P, AB) - это расстояние между P и P'.

(3) В противном случае dist(P, AB) - это расстояние между P и либо A, либо B, в зависимости от того, что меньше.

Что это. Есть некоторые очевидные способы оптимизации процедуры, но даже если они будут реализованы буквально, они будут работать уже очень хорошо.

P.S. Конечно, можно спросить, как выполнить проекцию точки на линию. Я оставлю это как упражнение для читателя:)

Ответ 4

Это 3D-окно или 2D-прямоугольник? В любом случае вам, вероятно, лучше всего получить point-line (для 2D) или point-plane (3D) расстояние для каждой стороны, затем выберите минимальный.

Изменить: там гораздо лучший способ здесь (последнее сообщение). Это включает в себя преобразование координат точки в поле коробки, затем "насыщение" координат с размером окна, чтобы найти точку на ближайшем к точке месте. Я не пробовал, но это выглядит правильно.

Ответ 5

Ответ на Kikito неверен, ведь если P находится в областях 2, 4, 5 или 7 схемы Теда Хоппа, он возвращает минимальное расстояние от вершин, которое отличается (больше) от минимального расстояния от края.

Я установил функцию kikito distance_aux, вернув 0 вместо min (p - lower, upper-p), и все будет работать независимо от области 0, где P находится внутри поля. На мой взгляд, регион должен управляться отдельно, в зависимости от того, чего вы хотите достичь, будь то расстояние от области или расстояние от периметра коробки. Если вы хотите получить расстояние от области поля, я бы сказал, что он равен нулю, когда точка находится внутри поля.

function inside(point, box)
    return (point.x > box.left AND point.x < box.right AND point.y > box.top AND point.y < box.bottom)
end

function distance_aux(p, lower, upper)
    if p < lower then return lower - p end
    if p > upper then return p - upper end
    return 0
end

function distance(point, box)
    local dx = distance_aux(point.x, box.left, box.right)
    local dy = distance_aux(point.y, box.top, box.bottom)
    if (inside(point, box))
        return min(dx, dy)    // or 0 in case of distance from the area
    else
        return sqrt(dx * dx + dy * dy)
    endif
end

Ответ 6

Легко оптимизированная альтернатива С# (хотя при сравнении удвоений против 0 должно быть некоторое отклонение). Я также рекомендую создать для них какие-то методы расширения Rect или Point.

public static class GeometryUtils
{
    public static double Distance(Point point, Rect rect)
    {
        var xDist = MinXDistance(point, rect);
        var yDist = MinYDistance(point, rect);
        if (xDist == 0)
        {
            return yDist;
        }
        else if (yDist == 0)
        {
            return xDist;
        }

        return Math.Sqrt(Math.Pow(xDist, 2) + Math.Pow(yDist, 2));
    }

    private static double MinXDistance(Point point, Rect rect)
    {
        if (rect.Left > point.X)
        {
            return rect.Left - point.X;
        }
        else if (rect.Right < point.X)
        {
            return point.X - rect.Right;
        }
        else
        {
            return 0;
        }
    }

    private static double MinYDistance(Point point, Rect rect)
    {
        if (rect.Bottom < point.Y)
        {
            return point.Y - rect.Bottom;
        }
        else if (rect.Top > point.Y)
        {
            return rect.Top - point.Y;
        }
        else
        {
            return 0;
        }
    }
}

Ответ 7

Я искал это, и я думаю, что у меня есть решение, для случая, когда поле выравнивается по оси (довольно обычный случай)

Я считаю, что в этом случае вы можете рассчитать расстояние следующим образом:

function distance_aux(p, lower, upper)
  if p < lower then return lower - p end
  if p > upper then return p - upper end
  return min(p - lower, upper - p)
end

function distance(point, box)
  local dx = distance_aux(point.x, box.left, box.right)
  local dy = distance_aux(point.y, box.top, box.bottom)
  return sqrt(dx * dx + dy * dy)
end

Это, конечно, можно продолжить до z.

Ответ 8

Это легко достичь с помощью точечных продуктов. На самом деле он был дан в 3d уже для случая, не связанного с осью.

fooobar.com/questions/244510/...

Но в 2D вы можете достичь того же

public struct Vector2 {
   double X; double Y

   // Vector dot product
   double Dot(Vector2 other)=>X*other.X+Y*other.Y;


   // Length squared of the vector
   double LengthSquared()=>Dot(this,this);

   // Plus other methods for multiplying by a scalar
   // adding and subtracting vectors etc
}

Функция для возврата ближайшей точки

public Vector2 ClosestPointTo
    (Vector2 q, Vector2 origin, Vector3 v10, Vector3 v01)
{
    var px = v10;
    var py = v01;


    var vx = (px - origin);
    var vy = (py - origin);


    var tx = Vector2.Dot( q - origin, vx ) / vx.LengthSquared();
    var ty = Vector3.Dot( q - origin, vy ) / vy.LengthSquared();


    tx = tx < 0 ? 0 : tx > 1 ? 1 : tx;
    ty = ty < 0 ? 0 : ty > 1 ? 1 : ty;

    var p = tx * vx + ty * vy + origin;

    return p;
}

Ответ 9

Для AABBs:

Возможно, это не самый эффективный, но, безусловно, самый простой способ:

p = ваша точка

c = центр куба

s = половина размера куба

r = точка, которую мы ищем

v = p - c;
m = max_abs(v);
r = c + ( v / m * s );