2010-01-25 13 views
14

Questo fine settimana trascorro alcuni minuti mescolando insieme un algoritmo che dovrebbe contenere un titolo (in gradi) e restituire una stringa per la direzione cardinale (la sto usando in un'applicazione della bussola Android I ' m usando). Quello che ho finito è stato questo:Algoritmo di direzione cardinale in Java

private String headingToString(Float heading) 
{ 
    String strHeading = "?"; 
    Hashtable<String, Float> cardinal = new Hashtable<String, Float>(); 
    cardinal.put("North_1", new Float(0)); 
    cardinal.put("Northeast", new Float(45)); 
    cardinal.put("East", new Float(90)); 
    cardinal.put("Southeast", new Float(135)); 
    cardinal.put("South", new Float(180)); 
    cardinal.put("Southwest", new Float(225)); 
    cardinal.put("West", new Float(270)); 
    cardinal.put("Northwest", new Float(315)); 
    cardinal.put("North_2", new Float(360)); 

    for (String key: cardinal.keySet()) 
    { 
     Float value = cardinal.get(key); 
     if (Math.abs(heading - value) < 30) 
     { 
      strHeading = key; 
      if (key.contains("North_")) 
      { 
       strHeading = "North"; 
      } 
      break; 
     } 
    } 
    return strHeading; 
} 

La mia domanda è, è questo il modo migliore di farlo? Deve essere stato fatto molte volte prima sebbene non abbia ancora fatto una ricerca di esempi sul web. Qualcun altro ha provato questo e ha trovato una soluzione più pulita?

Edit per le risposte, shinjin di e Chrstoffer'S del Reverendo Thilo:

La soluzione

public static String headingToString2(double x) 
{ 
    String directions[] = {"N", "NE", "E", "SE", "S", "SW", "W", "NW", "N"}; 
    return directions[ (int)Math.round(( ((double)x % 360)/45)) ]; 
} 

risposta

27

Nella maggior parte dei casi, tuttavia, per renderlo ottimizzato e (IMO) più pulito, è possibile trovare una funzione per correlare l'intestazione di input con quella utilizzata nella mappa.

Per esempio: (sono abbastanza sicuro che questo è giusto, ma ti consigliamo di check it)

45* (int)Math.round(( ((double)x % 360)/45)) 

Quello che fa è prima x % 360 si assicura il titolo è all'interno di un intervallo valido. poi

45 * round(.../45) 

trova il più vicino multiplo di 45.

Ora cambiare la mappa per essere

HashMap<Integer, String> map = new HashMap<Integer, String>() 
    map.put(0, "North") 
    map.put(45, "Northeast") 
    etc... 

Così, ora l'algoritmo di calcolo diventa un mathemtical veloce piuttosto che scorrendo la mappa. Inoltre, non è necessario Hashtable poiché fornisce costrutti per la concorrenza (se ricordo bene) e nel tuo caso causerebbe effettivamente una riduzione delle prestazioni.

Ancora una volta, il successo in termini di prestazioni potrebbe essere del tutto trascurabile per le vostre esigenze.

Modifica per Thilo e di suggerimenti di shinjin:

Invece di moltiplicare per 45, basta tenere il resto l'equazione, che vi dà i valori per 0-7, e fa un allineamento delle corde.

String directions[] = {"N", "NE", "E", "SE", "S", "SW", "W", "NW"} 
return directions[ (int)Math.round(( ((double)x % 360)/45)) % 8 ] 

e il problema è risolto in due righe.

Una nota: il modulo non funziona correttamente per i numeri negativi. Se la nostra intestazione di input è negativa, prima devi renderla positiva.

+1

+1. Molto bella. Facendo questo un ulteriore passo, aggiungi un'altra piccola conversione alla funzione e lui può semplicemente ottenere un indice in una matrice di stringhe: 'String [] directions = {" N "," NE "," E "...}' – Thilo

+1

Se ometti la moltiplicazione per 45, puoi utilizzare una matrice semplice invece di una mappa hash. – shinjin

+1

È necessaria una "N" aggiuntiva in quella matrice. Intestazioni 337.5 e successive arrotonderanno a 8. –

0

Si potrebbe forse aggiungere 15 gradi in anticipo per evitare North_1 e North_2.

-1

in Java:

String _directions[] = {"N", "NE", "E", "SE", "S", "SW", "W", "NW"}; 

public String getHeading(int hea) { 
    return _directions[(int)Math.floor((hea % 360)/45)]; 
} 

Nel caso in cui "java" u deve necessario creare una classe.

in javascript:

var _directions = ["N", "NE", "E", "SE", "S", "SW", "W", "NW"]; 

function getDirection (hea) { 
    return _directions[Math.floor((hea % 360)/45)]; 
}; 
0

Gli esempi precedenti non sono precisi, ecco una soluzione più accurata in JavaScript.

function getCardinalDirection(input) { 
    var directions = ["N", "NE", "E", "SE", "S", "SW", "W", "NW", "N"]; 
    var index = Math.floor(((input-22.5)%360)/45); 
    return directions[index+1]; 
} 
7

maggior parte delle risposte qui sono fuori dai 22,5 gradi per i loro intervalli di 45 gradi, e la mappa per esempio 0-45 come N, piuttosto che [337.5-360], [0-22.5] in N. È necessario compensare prima di fare i calcoli per correggere per questo.

Ecco una soluzione che utilizza 22,5 intervalli di gradi, come ad esempio si potrebbe vedere per le direzioni del vento:

private String formatBearing(double bearing) { 
    if (bearing < 0 && bearing > -180) { 
     // Normalize to [0,360] 
     bearing = 360.0 + bearing; 
    } 
    if (bearing > 360 || bearing < -180) { 
     return "Unknown"; 
    } 

    String directions[] = { 
     "N", "NNE", "NE", "ENE", "E", "ESE", "SE", "SSE", 
     "S", "SSW", "SW", "WSW", "W", "WNW", "NW", "NNW", 
     "N"}; 
    String cardinal = directions[(int) Math.floor(((bearing + 11.25) % 360)/22.5)]; 
    return cardinal + " (" + formatBearing.format(bearing) + " deg)"; 
    } 
+2

è normale che l'array di indicazioni contenga N due volte? – Pak