📜 ⬆️ ⬇️

A compass pointing to the north, or how trigonometry came in handy to me

Hi, Habr!

I am developing for iOS, and recently I had a task to create a compass, which indicates the direction not to the north, but to a certain point of the earth. This is certainly not quite a compass, but for lack of a better name, I will call it that.

Our company has been developing a mobile assistant for Muslims, of which this very compass was a part. His task is to indicate the direction of Mecca. There is a similar function in almost every such application, so the idea is far from new, but I had to think about implementation.

Writing a normal compass on objective-c is a simple task, and you can find many examples of its implementation. With the help of the CLLocationManager class, you need to get the current heading value, which shows how many degrees the current direction of the device is deviated from the north direction (hereinafter simply heading). Then take this angle, multiply by -1, convert to radians, and rotate the picture with the compass at the resulting angle. That is, how much the device is rotated, for the same amount we rotate the picture with a copy, only in the opposite direction.
')
In my case, I also had to rotate the image at a certain angle, only the deviation should be calculated not relative to the north, but relative to Mecca. Thus, the task was reduced to calculating the angle, which shows how the current direction of the device deviates from the direction to Mecca. In this case, the input parameters were the current coordinates of the device, the coordinates of Mecca and the value of heading. After thinking a bit, I decided that it would be nice to present all this in the form of a rectangular coordinate system, with two points on it, where the abscissa axis is the longitude value and the ordinate axis is the latitude.



Indeed, in this form, the task looks much easier! Now you can reduce all this to the calculation of one of the angles of a right-angled triangle. We are interested in the angle adjacent to the leg, which is parallel to the axis of ordinates ( B ). So, we can easily calculate sides A and B , and then side C. The angle α can be calculated using the arc sine ratio of side A to side C.



Fine! But the resulting angle is not yet the solution of the problem. It is necessary to make some additional calculations, and they depend on which quarter the user is in relative to Mecca. We want to calculate the angle (indicated in orange) between the direction to Mecca and the directions to the north at the current location. So, in situation no. 1 (if the user is northeast of Mecca), you need to add 180 degrees to the angle α . In Situation 2 (southeast of Mecca), subtract β from 360. In Situation 3 (southwest of Mecca), the angle γ is already the desired angle. In Situation 4 (northwest of Mecca), the angle δ should be subtracted from 180.



So, we calculated the angle between the direction to Mecca and the directions to the north. Since the device has already been rejected at some angle relative to the north (heading), we need to subtract the angle we calculated from heading. Now, finally, we have an angle to which we need to rotate our picture with a compass (we still need to multiply it by -1 and convert it to radians).

Here is an example of a method that receives the coordinates and the value of heading and returns the angle we need:

- (double)angleFromLocation:(CLLocationCoordinate2D)coordinate andHeading:(double)heading { double ourLatitude = coordinate.latitude; double ourLongitude = coordinate.longitude; //     double cathetusA = ABS(ourLongitude - MEKKA_LON); double cathetusB = ABS(ourLatitude - MEKKA_LAT); double hypotenuse = sqrt(cathetusA * cathetusA + cathetusB * cathetusB); //   α double angle1 = asin(cathetusA/hypotenuse) * 180/M_PI; double angle2; //          double angle3; //  //       ,     if (ourLatitude > MEKKA_LAT) { if (ourLongitude > MEKKA_LON) { angle2 = 180.0 + angle1; } else if (ourLongitude < MEKKA_LON) { angle2 = 180.0 - angle1; } else { angle2 = 180.0; } } else if (ourLatitude < MEKKA_LAT) { if (ourLongitude > MEKKA_LON) { angle2 = 360.0 - angle1; } else if (ourLongitude < MEKKA_LON) { angle2 = angle1; } else { angle2 = 0.0; } } else { if (ourLongitude > MEKKA_LON) { angle2 = 270.0; } else if (ourLon < MEKKA_LON) { angle2 = 90.0; } else { angle2 = 0.0; } } angle3 = heading - angle2; //        angle3 = -angle3 * M_PI / 180.0f; //        return angle3; } 


In the end, everything works! You can use the coordinates of different cities in the world and make sure that the direction is calculated correctly. Having added a couple of designer delights, we got a rather interesting compass:



I wonder if there are other ways to solve this problem? I hope that the post turned out to be interesting and useful.

I will be glad to your comments.

Source: https://habr.com/ru/post/249357/


All Articles