2010-01-25 16 views
14

Este fin de semana paso unos minutos combinando un algoritmo que tomaría un rumbo (en grados) y devolvería un String para la dirección cardinal (lo estoy usando en una aplicación de brújula Android I ' m usando). Lo que terminé con esto fue esto:Algoritmo de dirección cardinal en 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; 
} 

Mi pregunta es, ¿es esta la mejor manera de hacerlo? Debe haber sido hecho muchas veces antes aunque todavía no he hecho una búsqueda de ejemplos en la web. ¿Alguna otra persona ha intentado esto y ha encontrado una solución más ordenada?

de edición para las respuestas, shinjin de Chrstoffer y de la del Reverendo Thilo:

La solución

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)) ]; 
} 

Respuesta

27

Eso está bien en la mayoría de los casos, aunque para hacerlo optimizado y como limpiador (IMO), lo que se puede hacer es encontrar una función para relacionar el encabezado de entrada con el utilizado en el mapa.

Por ejemplo: (estoy bastante seguro de que esto es correcto, pero usted querrá comprobar que)

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

Lo que esto hace es primero x % 360 se asegura el título está dentro de un rango válido. entonces

45 * round(.../45) 

encuentra el múltiplo más cercano de 45

Ahora cambiar su mapa para ser

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

lo tanto, ahora el algoritmo de cálculo se convierte en un mathemtical rápido en lugar de iteración a través del mapa. Además, no necesita como Hashtable aquí, ya que proporciona construcciones para la concurrencia (si no recuerdo mal) y en su caso, en realidad causaría una disminución en el rendimiento.

Una vez más, el rendimiento puede ser completamente insignificante para sus necesidades.

Editar para Thilo de sugerencias y de Shinjin:

En lugar de multiplicar por 45, sólo sigue el resto de la ecuación, lo que le da los valores de 0-7, y crea un conjunto de cuerdas.

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

y tiene su problema resuelto en dos líneas.

Una nota: El módulo no funcionará correctamente para los números negativos. Si nuestro encabezado de entrada es negativo, primero deberá ser positivo.

+1

+1. Muy agradable. Llevando esto un paso más allá, agregue otra conversión pequeña a la función y él puede simplemente obtener un índice en una matriz de cadenas: 'String [] directions = {" N "," NE "," E "...}' – Thilo

+1

Si omites la multiplicación por 45, entonces puedes usar una matriz simple en lugar de un mapa hash. – shinjin

+1

Necesita una "N" adicional en esa matriz. Encabezados 337.5 y más se redondeará a 8. –

0

tal vez podría añadir 15 grados en la delantera para evitar North_1 y North_2.

-1

en Java:

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

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

En el caso de "java" u debe necesitar para crear una clase.

en javascript:

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

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

Los ejemplos anteriores no son exactos, aquí es una solución más precisa en 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

La mayoría de las respuestas están desactivadas en 22.5 grados en sus intervalos de 45 grados, y en el mapa, p. 0-45 como N, en lugar de [337.5-360], [0-22.5] a N. Necesita compensar antes de hacer los cálculos para corregir esto.

he aquí una solución que utiliza intervalos de 22,5 grados, tal como se puede ver por las direcciones del viento:

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

¿Es normal que su conjunto de instrucciones contenga N dos veces? – Pak

Cuestiones relacionadas