Reputation: 824
For Example if input is 22.5 degrees the output will be "North East"
Upvotes: 1
Views: 2733
Reputation: 815
I needed this functionality for the weather. As i didn't find anything satisfactory this is may java implementation of a class that takes a degree and returns one of 8 directions. It is not precise as it is used to show the direction of the wind when displaying generic weather. One can improve on this...
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
public class DegreeToQuadrant {
List<QuadrantItem> quadrants;
String[] QuadrantNames = new String[]{"N", "NE", "E", "SE", "S", "SW", "W", "NW"};
DegreeToQuadrant() {
double leftValue = 360 - 22.5;
double rightValue = 22.5;
double step = 45;
quadrants = new ArrayList<QuadrantItem>();
for (String qname : QuadrantNames) {
QuadrantItem quadrantItem = null;
if (qname == "N")
quadrantItem = new QuadrantItem(qname, leftValue, rightValue, "or");
else {
leftValue = rightValue;
rightValue = leftValue + step;
quadrantItem = new QuadrantItem(qname, leftValue, rightValue, "and");
}
quadrants.add(quadrantItem);
}
}
String getQuadrantName(double degree) {
for (QuadrantItem quadrantItem : quadrants)
if (quadrantItem.isIn(degree))
return quadrantItem.m_quadrantName;
return "";
}
public static class QuadrantItem {
String m_quadrantName;
String m_operation; //or , and
double m_left;
double m_right;
HashMap<String, QuadrantItem> quadrants;
QuadrantItem(String name, double left, double right, String operation) {
m_quadrantName = name;
m_operation = operation;
m_left = left;
m_right = right;
}
boolean isIn(double degree) {
if (m_operation == "and")
return degree > m_left && degree < m_right;
else
return degree > m_left || degree < m_right;
}
}
}
Note: for the N value (North) the operation should be degree>leftLimit OR degree < rightLimit. This is different of the other slices for which degree needs to be between the two limits.
How to use:
With wind_deg
being the wind degree, get the quadrant to be displayed:
DegreeToQuadrant degreeConvertor = new DegreeToQuadrant();
String quadrantName = degreeConvertor.getQuadrantName(wind_deg);
Upvotes: 0
Reputation: 48287
The "best" way to convert is rounding the degrees to the next one quadrant, this of couse depends on how many cardinal points your compass has...
Let's suppose for a while you have only 4 North , South, West and East,
then trying to convert 180° will match exactly to South (assuming the north is 0°=360°), but I would expect that 200° points to the South too since that is closer to that direction than to the West...
same criteria for 160° since is closer to South than to East
Define an Enum
cardinal Point
enum CPoint {
NORTH,
EAST,
SOUTH,
WEST
}
and test it like:
public static void main(String[] args) {
final int divisor = 360 / CPoint.values().length;
for (int i = 0; i < 360; i++) {
final int coci = i / divisor;
final int resto = i % divisor;
if (resto <= divisor / 2) {
System.out.println(i + "--->" + CPoint.values()[coci % CPoint.values().length]);
} else {
System.out.println(i + "--->" + CPoint.values()[(coci + 1) % CPoint.values().length]);
}
}
}
The output will show how the loop rounds the value of i to the closest cardinal Point
The best part of this aproach is that you could define a method that takes an integer as parameter and returns a enumeration constant to the cardinal Point...
Then you can do nice things like a switch-case or something similar :-)
Upvotes: 1
Reputation: 140553
As usual, "best" depends on context/requirements.
A "low level" solution would be: you actually want to map "360 degrees" into "16 different classes". That is really easy: you divide your degree value by 16; and then you use the rounded number you get from that as index within an array of String that contains the corresponding "names" for the directions (plus some massaging to get the same results for 0 and 360 degrees).
Example: 21 degrees / 16 --> 1.3 rounded to 1
First entry in that array would be "N" ... so there you go.
But as said, that is a really low-level solution; if you want something that carries you in the future, and changing/extended requirements; you better create a real OO abstraction of the concepts involved. Maybe you wouldn't represent those "directions" as simple strings, maybe you really have classes that represent degrees, and classes that represent "directions".
Upvotes: 0
Reputation: 308958
A Map will do well:
import java.util.LinkedHashMap;
import java.util.Map;
/**
* Convert degrees to heading names
* User: mduffy
* Date: 7/21/2016
* Time: 7:49 AM
* @link http://stackoverflow.com/questions/38503399/what-is-the-best-way-to-convert-degrees-to-quadrant-names
*/
public class HeadingConverter {
private static final Map<Double, String> DEGREES_TO_HEADING;
// TODO: You need to add more to the Map
static {
DEGREES_TO_HEADING = new LinkedHashMap<Double, String>() {{
put(0.0, "E");
put(90.0, "N");
put(180.0, "W");
put(270.0, "S");
put(360.0, "E");
}};
}
public static void main(String[] args) {
for (String arg : args) {
double unnormalized = Double.parseDouble(arg);
System.out.println(String.format("angle: %10.3f heading: %s", unnormalized, HeadingConverter.getHeading(unnormalized)));
}
}
public static double normalizeDegrees(double unnormalized) {
// TODO: For you to complete
return unnormalized;
}
public static String getHeading(double unnormalized) {
String heading = "UNKNOWN";
double normalized = normalizeDegrees(unnormalized);
for (Double angle : DEGREES_TO_HEADING.keySet()) {
if (normalized <= angle) {
heading = DEGREES_TO_HEADING.get(angle);
break;
}
}
return heading;
}
}
Upvotes: 0