Question

Ce week-end, je passe quelques minutes à élaborer un algorithme qui prendrait un cap (en degrés) et renverrait une chaîne pour la direction cardinale (je l'utilise dans une application de boussole Android que j'utilise).Ce que j'ai fini par obtenir, c'est ceci :

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

Ma question est la suivante : est-ce la meilleure façon de procéder ?Cela a dû être fait plusieurs fois auparavant, même si je n'ai pas encore recherché d'exemples sur le Web.D'autres personnes ont-elles essayé cela et trouvé une solution plus intéressante ?

Edit pour les réponses de Thilo, Shinjin et Chrstoffer du révérend :

La solution

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)) ];
}
Était-ce utile?

La solution

C'est bien dans la plupart des cas, mais pour le rendre optimisé et (OMI) plus propre, vous pouvez trouver une fonction permettant de relier l'en-tête d'entrée à celui utilisé dans la carte.

Par exemple:(Je suis presque sûr que c'est vrai, mais vous voudrez le vérifier)

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

Ce que cela fait, c'est d'abord x % 360 s'assure que le titre se situe dans une plage valide.alors

45 * round(.../45)

trouve le multiple de 45 le plus proche.

Maintenant, changez votre carte pour qu'elle soit

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

Ainsi, votre algorithme devient désormais un calcul mathématique rapide plutôt que de parcourir la carte.De plus, vous n'avez pas besoin de Hashtable ici car il fournit des constructions pour la concurrence (si je me souviens bien) et dans votre cas, cela entraînerait en fait une diminution des performances.

Encore une fois, l’impact sur les performances peut être totalement négligeable pour vos besoins.

Modifier pour les suggestions de Thilo et shinjin :

Au lieu de multiplier par 45, conservez simplement le reste de l’équation, qui vous donne des valeurs de 0 à 7, et créez un tableau de vos chaînes.

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

et vous avez résolu votre problème en deux lignes.

Une note:Le module ne fonctionnera pas correctement pour les nombres négatifs.Si notre en-tête d'entrée est négatif, vous devrez d'abord le rendre positif.

Autres conseils

La plupart des réponses ici sont hors de 22,5 degrés pour leurs intervalles de 45 degrés, et par exemple map 0-45 comme N, plutôt que [337,5 à 360], [0 à 22,5] N. Vous devez compenser avant de faire le calcul pour corriger cette situation.

Voici une solution qui utilise des intervalles de 22,5 degrés, comme vous pouvez voir pour la direction du vent:

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

Vous pourriez peut-être ajouter 15 degrés à l'avant pour éviter North_1 et North_2.

Les exemples précédents ne sont pas exactes, voici une solution plus précise 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];
}

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

Dans le cas "java" u doit avoir besoin de créer une classe.

en javascript:

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

function getDirection (hea) {
  return _directions[Math.floor((hea % 360) / 45)];
};
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top