4

Question: How can I efficiently compute the minimum distance between two axis-aligned boxes in n-dimensions?

Box format: The boxes, A and B, are given by their minimum and maximum points, A_min, A_max, B_min, B_max, each of which is a n-dimensional vector. That is, the boxes may be written mathematically as the following cartesian products of intervals:

A = [A_min(1), A_max(1)] x [A_min(2), A_max(2)] x ... x [A_min(n), A_max(n)]

B = [B_min(1), B_max(1)] x [B_min(2), B_max(2)] x ... x [B_min(n), B_max(n)]

Picture: here is a picture demonstrating the idea in 2D: minimum distance between boxes


Note: Note: I ask this question, and answer it myself, because this question (in general n-dimensional form) appears to be absent from stackoverflow even after all these years. Good answers to this question are hard to find on the internet more generally. After googling around, I eventually had to figure this out myself, and am posting here to spare future people the same trouble.

Nick Alger
  • 984
  • 7
  • 26

3 Answers3

6

The minimum distance between the boxes is given by:

dist = sqrt(||u||^2 + ||v||^2)

where

u = max(0, A_min - B_max) 
v = max(0, B_min - A_max)

The maximization is done entrywise on the vectors (i.e., max(0, w) means replace all negative entries of vector w with zero, but leave the positive entries unchanged). The notation ||w|| means the euclidean norm of the vector w (square root of the sum of the squares of the entries).

This does not require any case-by-case analysis, and works for any dimension regardless of where the boxes are with respect to each other.

python code:

import numpy as np

def boxes_distance(A_min, A_max, B_min, B_max):
    delta1 = A_min - B_max
    delta2 = B_min - A_max
    u = np.max(np.array([np.zeros(len(delta1)), delta1]), axis=0)
    v = np.max(np.array([np.zeros(len(delta2)), delta2]), axis=0)
    dist = np.linalg.norm(np.concatenate([u, v]))
    return dist
Nick Alger
  • 984
  • 7
  • 26
1
type Rect = { x: number; y: number; length: number; width: number };

export function boxesDistance(a: Rect, b: Rect) {
  const deltas = [a.x - b.x - b.width, a.y - b.y - b.length, b.x - a.x - a.width, b.y - a.y - a.length];

  const sum = deltas.reduce((total, d) => {
    return d > 0 ? total + d ** 2 : total;
  }, 0);

  return Math.sqrt(sum);
}

This is the equivalent code in typescript without the use of any libraries, though the input parameters were slightly different in my case.

1

The distance between two axis-aligned bounding boxes (AABB) can be computed as follows:

  1. Find the intersection box of two input boxes, which can be expressed in C++:
Box Box::intersection( const Box & b ) const
{
    Box res;
    for ( int i = 0; i < V::elements; ++i )
    {
        res.min[i] = std::max( min[i], b.min[i] );
        res.max[i] = std::min( max[i], b.max[i] );
    }
    return res;
}

where min and max are two corner points of a box. The "intersection" will be inverted (res.min[i] > res.max[i]) if two input boxes do not intersect actually.

  1. Then the squared distance between two boxes is:
T Box::getDistanceSq( const Box & b ) const
{
    auto ibox = intersection( b );
    T distSq = 0;
    for ( int i = 0; i < V::elements; ++i )
        if ( ibox.min[i] > ibox.max[i] )
            distSq += sqr( ibox.min[i] - ibox.max[i] );
    return distSq;
}

The function returns zero if input boxes touch or intersect.

The code above was taken from MeshLib and it works for arbitrary n-dimensions cases (V::elements=n).

Fedor
  • 17,146
  • 13
  • 40
  • 131