Update
This commit is contained in:
parent
5e2ef4f6db
commit
244dfff2a8
11 changed files with 2025 additions and 2007 deletions
107
distance.md
107
distance.md
|
@ -15,8 +15,7 @@ There are many ways to define distance within given space. Most common and impli
|
|||
|
||||
Computing Euclidean distance requires multiplication and most importantly [square root](sqrt.md) which is usually a pretty slow operation, therefore many times we look for simpler [approximations](approximation.md). Note that a possible approach here may also lead through computing the distance normally but using a fast approximation of the square root.
|
||||
|
||||
Two very basic and rough approximations of Euclidean distance, both in 2D and 3D, are [taxicab](taxicab.md) (also Manhattan) and [Chebyshev](chebyshev.md) distances. Taxicab distance
|
||||
simply adds the absolute coordinate differences along each principal axis (*dx*, *dy* and *dz*) while Chebyshev takes the maximum of them (NOTE: taking minimum isn't possible due to the definition which requires two distinct points to always have positive distance). In [C](c.md) (for generalization to 3D just add one coordinate of course):
|
||||
Two very basic and rough approximations of Euclidean distance, both in 2D and 3D, are [taxicab](taxicab.md) (also Manhattan) and [Chebyshev](chebyshev.md) distances. Taxicab distance is an upper bound on Euclidean distance (i.e. it's always greater than or equal to Euclidean distance) and is computed by merely adding the absolute coordinate differences along each principal axis (*dx*, *dy* and *dz*) while Chebyshev, a lower bound on Euclidean distance, takes the maximum of them (NOTE: taking minimum isn't possible due to the definition which requires two distinct points to always have positive distance). In [C](c.md) (for generalization to 3D just add one coordinate of course):
|
||||
|
||||
```
|
||||
int distTaxi(int x0, int y0, int x1, int y1)
|
||||
|
@ -38,60 +37,74 @@ int distCheb(int x0, int y0, int x1, int y1)
|
|||
|
||||
Both of these distances approximate a [circle](circle.md) in 2D with a square or a sphere in 3D with a cube, the difference is that taxicab is an upper estimate of the distance while Chebyshev is the lower estimate. For speed of execution ([optimization](optimization.md)) it may also be important that taxicab distance only uses the operation of addition while Chebyshev may result in [branching](branch.md) (*if*) in the max function which is usually not good for performance.
|
||||
|
||||
```
|
||||
--------------------------------------------------------------------------
|
||||
|
||||
Euclidean _____
|
||||
_.'' ''._
|
||||
sqrt( B / \ F
|
||||
(B.x - A.x)^2 + _,-+ / C d \ _-+
|
||||
(B.y - A.y)^2) _,--' ( +-------) _,-'
|
||||
_,--' \ / _,-'
|
||||
_,--' \_ _/ _,-'
|
||||
A _,--' '--_____--' E _,-'
|
||||
+-' +-'
|
||||
|
||||
--------------------------------------------------------------------------
|
||||
|
||||
Taxicab (Manhattan) _A_
|
||||
B _/ \_ F
|
||||
+ _/ \_ ,----+
|
||||
abs(B.x - A.x) + | _/ C d \_ ,'
|
||||
abx(B.y - A.y) | <_ +-------> ,'
|
||||
| \_ _/ ,'
|
||||
| \_ _/ ,'
|
||||
A | \_ _/ E ,'
|
||||
+-------------------------' V +----'
|
||||
|
||||
--------------------------------------------------------------------------
|
||||
|
||||
Chebyshev _______________
|
||||
B | | F
|
||||
max( + | | ,+
|
||||
abs(B.x - A.x), | C d | ,'
|
||||
abs(B.y - A.y)) | +-------| ,'
|
||||
| | ,--------'
|
||||
| | ,'
|
||||
A |_______________| E ,'
|
||||
+-------------------------- +'
|
||||
|
||||
--------------------------------------------------------------------------
|
||||
```
|
||||
|
||||
*Three commonly used distance measures: the distance is the length of the path illustrated between points A and B; next are shown "circles" (sets of points with distance d from point C) and "lines" (one diagonal of a rhombus in which points E and F are opposite to each other) drawn by respective measures.*
|
||||
|
||||
A bit more accuracy can be achieved by averaging the taxicab and Chebyshev distances which in 2D approximates a circle with an 8 segment polygon and in 3D approximates a sphere with 24 sided [polyhedron](polyhedron.md). The integer-only [C](c.md) code is following:
|
||||
Taking the average of taxicab and Chebyshev distances will slightly increases accuracy towards better approximating Euclidean distance -- in 2D a circle plotted by this new metric will be an 8 segment polygon and analogously in 3D a sphere will be a 24 sided [polyhedron](polyhedron.md) (taxicab or Chebyshev alone give a square in 2D and a cube in 3D). The average can be shown to be equal to the maximum coordinate difference plus a half of the minimum; here is an branchless, integer-only [C](c.md) function implementing the taxicab-Chebyshev average:
|
||||
|
||||
```
|
||||
int dist8(int x0, int y0, int x1, int y1)
|
||||
{
|
||||
x0 = x1 > x0 ? x1 - x0 : x0 - x1; // dx
|
||||
y0 = y1 > y0 ? y1 - y0 : y0 - y1; // dy
|
||||
|
||||
return (x0 + y0 + (x0 > y0 ? x0 : y0)) / 2;
|
||||
x1 = x0 > y0; // use as helper
|
||||
return (x0 >> !x1) + (y0 >> x1);
|
||||
}
|
||||
```
|
||||
|
||||
And a picture for summary:
|
||||
|
||||
```
|
||||
--------------------------------------------------------------------------------
|
||||
0 1 2 3 4 5 6
|
||||
Euclidean _____ 1 1 2 3 4 5 6
|
||||
_.'' ''._ 2 2 3 4 4 5 6
|
||||
sqrt( B / \ 3 3 4 4 5 6 7
|
||||
(B.x - A.x)^2 + _,-+ / C d \ 4 4 4 5 6 6 7 F
|
||||
(B.y - A.y)^2) _,--' ( +-------) 5 5 5 6 6 7 8 _-+
|
||||
_,--' \ / 6 6 6 7 7 8 8 _,-'
|
||||
_,--' \_ _/ _,-'
|
||||
A _,--' '--_____--' _,-'
|
||||
+-' E _,-'
|
||||
+-'
|
||||
--------------------------------------------------------------------------------
|
||||
0 1 2 3 4 5 6
|
||||
Taxicab (Manhattan) _A_ 1 2 3 4 5 6 7
|
||||
B _/ \_ 2 3 4 5 6 7 8
|
||||
+ _/ \_ 3 4 5 6 7 8 9 F
|
||||
abs(B.x - A.x) + | _/ C d \_ 4 5 6 7 8 9 a ,----+
|
||||
abx(B.y - A.y) | <_ +-------> 5 6 7 8 9 a b ,'
|
||||
| \_ _/ 6 7 8 9 a b c ,'
|
||||
| \_ _/ ,'
|
||||
A | \_ _/ ,'
|
||||
+-------------------------' V E ,'
|
||||
+----'
|
||||
--------------------------------------------------------------------------------
|
||||
0 1 2 3 4 5 6
|
||||
Chebyshev _______________ 1 1 2 3 4 5 6
|
||||
B | | 2 2 2 3 4 5 6
|
||||
max( + | | 3 3 3 3 4 5 6 F
|
||||
abs(B.x - A.x), | C d | 4 4 4 4 4 5 6 ,+
|
||||
abs(B.y - A.y)) | +-------| 5 5 5 5 5 5 6 ,'
|
||||
| | 6 6 6 6 6 6 6 ,'
|
||||
| | ,--------'
|
||||
A |_______________| ,'
|
||||
+-------------------------- E ,'
|
||||
+'
|
||||
--------------------------------------------------------------------------------
|
||||
0 1 2 3 4 5 6
|
||||
Taxi-Chebyshev average ___ 1 1 2 3 4 5 6
|
||||
B _.-'' ''-._ 2 2 3 4 5 6 7
|
||||
max(abs(B.x - A.x), + : : 3 3 4 4 5 6 7 F
|
||||
abs(B.y - A.y)) + : C d : 4 4 5 5 6 7 8 ,+
|
||||
min(abs(B.x - A.x), : +-------: 5 5 6 6 7 7 8 /
|
||||
abs(B.y - A.y)) / 2 , : : 6 6 7 7 8 8 9 /
|
||||
| :_ _: _____----'''''
|
||||
A | ''-.___.-'' /
|
||||
+-------------------------' E /
|
||||
+'
|
||||
--------------------------------------------------------------------------------
|
||||
```
|
||||
|
||||
*The four mentioned distance measures: the distance is the length of the path illustrated between points A and B; next are shown "circles" (sets of points with distance d from point C), tables of distances of grid cells from the top-left cell (rounded to nearest integer if needed) and "lines" (one diagonal of a rhombus in which points E and F are opposite to each other) drawn by respective measures.*
|
||||
|
||||
{ The following is an approximation I came up with when working on [tinyphysicsengine](tpe.md). While I measured the average and maximum error of the taxi/Chebyshev average in 3D at about 16% and 22% respectively, the following gave me 3% and 12% values. ~drummyfish }
|
||||
|
||||
Yet more accurate approximation of 3D Euclidean distance can be made with a 48 sided [polyhedron](polyhedron.md). The principle is following: take absolute values of all three coordinate differences and order them by magnitude so that *dx >= dy >= dz >= 0*. This gets us into one of 48 possible slices of space (the other slices have the same shape, they just differ by ordering or signs of the coordinates but the distance in them is of course equal). In this slice we'll approximate the distance linearly, i.e. with a [plane](plane.md). We do this by simply computing the distance of our point from a plane that goes through origin and whose normal is approximately {0.8728,0.4364,0.2182} (it points in the direction that goes through the middle of space slice). The expression for the distance from this plane simplifies to simply *0.8728 * dx + 0.4364 * dy + 0.2182 * dz*. The following is an integer-only implementation in [C](c.md) (note that the constants above have been converted to allow division by 1024 for possible [optimization](optimization.md) of division to a bit shift):
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue