Se hai bisogno di qualcosa che rimanga lineare su qualsiasi distanza (a differenza distance^2
) e tuttavia appaia vagamente circolare (a differenza delle Chebyshev quadrate e delle distanze di Manhattan simili a diamanti), puoi fare la media di queste ultime due tecniche per ottenere un'approssimazione di distanza a forma ottagonale:
dx = abs(x1 - x0)
dy = abs(y1 - y0)
dist = 0.5 * (dx + dy + max(dx, dy))
Ecco una visualizzazione (diagramma di contorno) della funzione, grazie a Wolfram Alpha :
Ed ecco un diagramma della sua funzione di errore rispetto alla distanza euclidea (radianti, solo primo quadrante):
Come puoi vedere, l'errore varia dallo 0% sugli assi a circa + 12% nei lobi. Modificando un po 'i coefficienti possiamo arrivare a +/- 4%:
dist = 0.4 * (dx + dy) + 0.56 * max(dx, dy)
Aggiornare
Utilizzando i coefficienti di cui sopra, l'errore massimo sarà compreso tra +/- 4%, ma l'errore medio sarà ancora + 1,3%. Ottimizzato per errore medio zero, è possibile utilizzare:
dist = 0.394 * (dx + dy) + 0.554 * max(dx, dy)
che fornisce errori tra -5% e + 3% e un errore medio di + 0,043%
Durante la ricerca sul web di un nome per questo algoritmo, ho trovato questa simile approssimazione ottagonale :
dist = 1007/1024 * max(dx, dy) + 441/1024 * min(dx, dy)
Si noti che questo è essenzialmente equivalente (sebbene gli esponenti siano diversi: questi danno un errore compreso tra -1,5% e 7,5%, ma può essere massaggiato a +/- 4%) perché max(dx, dy) + min(dx, dy) == dx + dy
. Utilizzando questo modulo, le chiamate min
e max
possono essere fattorizzate a favore di:
if (dy > dx)
swap(dx, dy)
dist = 1007/1024 * dx + 441/1024 * dy
Sarà più veloce della mia versione? Chissà ... dipende dal compilatore e da come ottimizza ciascuno per la piattaforma di destinazione. Suppongo che sarebbe piuttosto difficile vedere alcuna differenza.