Ваша функция rotateImageView должна работать нормально, однако есть некоторые вещи, которые необходимо изменить в ваших вычислениях вращения.
//This is where we choose to point it
float direction = azimuth + LocationObj.bearingTo( destinationObj );
rotateImageView( arrow, R.drawable.arrow, direction );
Проблема в том, что Bearing To даст вам диапазон от -180 до 180, что немного запутает. Нам потребуется преобразовать это значение в диапазон от 0 до 360, чтобы получить правильное вращение.
Это таблица того, что мы действительно хотим, в сравнении с тем, что нам дает
+-----------+--------------+
| bearingTo | Real bearing |
+-----------+--------------+
| 0 | 0 |
+-----------+--------------+
| 90 | 90 |
+-----------+--------------+
| 180 | 180 |
+-----------+--------------+
| -90 | 270 |
+-----------+--------------+
| -135 | 225 |
+-----------+--------------+
| -180 | 180 |
+-----------+--------------+
Несмотря на то, что азимут находится в диапазоне от -180 до 180, 0 по-прежнему истинный север, что оставит нас в этом расчете:
// Store the bearingTo in the bearTo variable
float bearTo = LocationObj.bearingTo( destinationObj );
// If the bearTo is smaller than 0, add 360 to get the rotation clockwise.
if (bearTo < 0) {
bearTo = bearTo + 360;
}
Если мы добавим несколько фиктивных значений для проверки нашей новой формулы:
float bearTo = -100;
// This will now equal to true
if (-100 < 0) {
bearTo = -100 + 360 = 360 - 100 = 260;
}
Теперь мы разобрались с азимутом. Давайте перейдем к азимуту!
Вам нужно вычесть склонение вместо того, чтобы добавить его, так как мы хотим, чтобы азимут был равен 0, когда мы указываем телефон прямо на истинный север, вместо того, чтобы склонение было добавлено к азимуту, что затем даст нам удвоение склонения, когда мы Направьте телефон на истинный север. Исправьте это, вычтя склонение вместо того, чтобы добавить его.
azimuth -= geoField.getDeclination(); // converts magnetic north into true north
Когда мы сейчас повернем телефон на истинный север, азимут будет равен 0
Ваш код для исправления азимута больше не нужен.
// Remove / uncomment this line
azimuth = azimuth % 360;
Теперь мы продолжим до точки, где мы вычисляем реальное вращение. Но сначала я подведу итог, какой тип ценностей у нас сейчас, и объясню, что они на самом деле:
bearTo = Угол от истинного севера до места назначения от точки, в которой мы сейчас находимся.
азимут = угол, на который вы повернули телефон с истинного севера.
Сказав это, если вы направите свой телефон прямо на истинный север, мы действительно хотим, чтобы стрелка повернула на угол, установленный для bearTo. Если вы укажете свой телефон на 45 градусов от истинного севера, мы хотим, чтобы стрелка повернулась на 45 градусов меньше, чем BearTo. Это оставляет нас для следующих расчетов:
float direction = bearTo - azimuth;
Однако, если мы введем несколько фиктивных значений:
bearTo = 45;
азимут = 180;
direction = 45 - 180 = -135;
Это означает, что стрелка должна повернуться на 135 градусов против часовой стрелки. Нам нужно будет ввести похожее условие if, как мы это делали с bearTo!
// If the direction is smaller than 0, add 360 to get the rotation clockwise.
if (direction < 0) {
direction = direction + 360;
}
Ваш несущий текст, N, E, S и W отключены, поэтому я исправил их в последнем методе ниже.
Ваш метод onSensorChanged должен выглядеть следующим образом:
public void onSensorChanged( SensorEvent event ) {
// If we don't have a Location, we break out
if ( LocationObj == null ) return;
float azimuth = event.values[0];
float baseAzimuth = azimuth;
GeomagneticField geoField = new GeomagneticField( Double
.valueOf( LocationObj.getLatitude() ).floatValue(), Double
.valueOf( LocationObj.getLongitude() ).floatValue(),
Double.valueOf( LocationObj.getAltitude() ).floatValue(),
System.currentTimeMillis() );
azimuth -= geoField.getDeclination(); // converts magnetic north into true north
// Store the bearingTo in the bearTo variable
float bearTo = LocationObj.bearingTo( destinationObj );
// If the bearTo is smaller than 0, add 360 to get the rotation clockwise.
if (bearTo < 0) {
bearTo = bearTo + 360;
}
//This is where we choose to point it
float direction = bearTo - azimuth;
// If the direction is smaller than 0, add 360 to get the rotation clockwise.
if (direction < 0) {
direction = direction + 360;
}
rotateImageView( arrow, R.drawable.arrow, direction );
//Set the field
String bearingText = "N";
if ( (360 >= baseAzimuth && baseAzimuth >= 337.5) || (0 <= baseAzimuth && baseAzimuth <= 22.5) ) bearingText = "N";
else if (baseAzimuth > 22.5 && baseAzimuth < 67.5) bearingText = "NE";
else if (baseAzimuth >= 67.5 && baseAzimuth <= 112.5) bearingText = "E";
else if (baseAzimuth > 112.5 && baseAzimuth < 157.5) bearingText = "SE";
else if (baseAzimuth >= 157.5 && baseAzimuth <= 202.5) bearingText = "S";
else if (baseAzimuth > 202.5 && baseAzimuth < 247.5) bearingText = "SW";
else if (baseAzimuth >= 247.5 && baseAzimuth <= 292.5) bearingText = "W";
else if (baseAzimuth > 292.5 && baseAzimuth < 337.5) bearingText = "NW";
else bearingText = "?";
fieldBearing.setText(bearingText);
}