Following on from my previous post about finding the true distance between a mobile user and a POI; I’m now going to look at how to find directions from a triangulated point by a series of mobile towers and a POI.
Nowadays, mobiles are self aware geo-location devices, but not all smartphone’s are geo-location friendly and if you assume or target your application to a specific model; then you are losing out on a significant number of end users. So how can you make sure that your mobile application stays user-friendly?
The application in question (pre-smartphone, I might add) had to show driving or walking directions for the end user on screen for all points of interest. But before the user chooses the category, we needed to provide a summary of nearest interest locations, and their distances and directions from the user location; so the user could then make a choice based on the distance and number of POI in that direction.
We calculated the distance using haversine formula, but where are these locations? Are they the same side or opposite to each other? There are high chances of the user choosing a location with a high density of POI near him rather a single POI.
Keeping in mind the end user’s dilemma, we decided to find the direction of each location with respect to the end user and show them on the mobile screen. But one major issue was still not addressed – was the end user facing North or South? To resolve this issue, our direction API came to the rescue, and we added a starting reference point with reference to a landmark. This resolved the issue with phones not supporting or embedding a compass-like device.
To find the solution I turned to basic trigonometry; consider the mobile user as centre (0,0) of quadrant system, and POI scattered around in all quadrant with latitude and longitude as Cartesian points(x1, y1). I had the distance between two points, and I needed the included angle between the x-axis and line generated by joining these two points.
The X-axis of quadrant represent East and West, and the Y-axis represent North and South. If you split the quadrant further it gives you, NE, NW, SE and SW directions. But our POI will not be exactly on these axis lines, so you need to consider an area formed by further splitting between these directions. In the image, an underground tube station on the X-axis and the other tube station next to it both appear to be East, even though the second tube station is not exactly East. This consideration helps me to group all POI in specific directions.
The clear advantage is gained from the end users point of view, the user will have more choice by following the East direction in this case rather than South-West – where few POI are located.
|Angle in degrees||Direction|
|0 – 22.50||East|
|22.51 – 67.49||North East|
|67.50 – 112.50||North|
|112.51 – 157.49||North West|
|157.50 – 202.50||West|
|205.51 – 247.49||South West|
|247.50 – 292.50||South|
|292.51 – 337.49||South East|
|337.50 – 360.00||East|
To calculate the included angle of vertex A, I assume vertex A is on the centre of quadrant (0,0) and vertex B is POI. So in theory, the tangent of angle C should return distance “b” (AC). As soon as the distance “b” is calculated, angle A can be calculated using either sine or cosine formula.
The whole equation is resolved to a single arctan formula. This function returns the value in radians, so we need to convert it to degrees before applying any calculation logic. But soon the limitations of this approach are highlighted, it can only return values between -90 and +90 degrees and needs major adjustments to get the final value.
As my first attempt failed, I turned towards mathforum, I found a related solution, with some shortcomings. After some adjustments and a couple of days of testing with actual data, ultimately I nailed this task of finding directions.
The formula from mathforum was written considering North being X-axis, so I have to turn the axis anti-clockwise by 90 degrees.
CREATE FUNCTION [dbo].[Direction]
@Lat1 NUMERIC(18, 6),
@Lat2 NUMERIC(18, 6),
@Lon1 NUMERIC(18, 6),
@Lon2 NUMERIC(18, 6)
WITH EXECUTE AS CALLER
DECLARE @dLat NUMERIC(18, 6), @dLon NUMERIC(18, 6),
@angle NUMERIC(18, 6), @RetVal NVARCHAR(MAX), @Pre_angle NUMERIC(18, 6)
DECLARE @Constant NUMERIC(18, 6)
SET @RetVal = 'Not found...'
SET @Pre_angle = 0
SET @CONSTANT = -999999999.00
SET @dLat = (@Lat2 - @Lat1)
SET @dLon = (@Lon2 - @Lon1)
/* -- Approach 2 */
DECLARE @y NUMERIC(18, 6), @x NUMERIC(18, 6)
SET @y = SIN(@Lon2 - @Lon1) * COS(@Lat2) * 1.0
SET @x = COS(@Lat1) * SIN(@Lat2) - SIN(@Lat1) * COS(@Lat2) * COS(@Lon2 - @Lon1) * 1.0
IF(@y > 0.00)
IF(@x > 0.00) SET @angle = DEGREES(ATN2(@y, @x)) * 1.0
IF(@x < 0.00) SET @angle = 180.00 - DEGREES(ATN2(-@y, @x)) * 1.0
IF(@x = 0.00) SET @angle = 90.00
IF(@y < 0.00)
IF(@x > 0.00) SET @angle = DEGREES(- ATN2(-@y, @x)) * 1.0
IF(@x < 0.00) SET @angle = (DEGREES(ATN2(@y, @x)) - 180.00) * 1.0
IF(@x = 0.00) SET @angle = 270.00
IF(@y = 0.00)
IF(@x > 0.00) SET @angle = 0.00
IF(@x < 0.00) SET @angle = 180.00
IF(@x = 0.00) SET @angle = @CONSTANT
-- Just for Display in Debug
SET @Pre_angle = @angle
IF(@angle != @CONSTANT)
-- This formaula refer x-axis as North direction,
-- but while assigning Direction Character, is considering
-- x-axis as West (as of Co-Ordinate System)
SET @angle = @angle + 90
-- Minor Adjustment for for value range
IF(@angle < 0)
SET @angle = ABS(@angle)
SET @angle = @angle + 90 -- Previously Values were -ve so only 90 = total 180
-- No Modulo function is available for Float, so a loop is implemented
IF(@angle > 360)
WHILE(@angle > 360)
SET @angle = @angle - 180
-- Find Direction Values; Practical data suggest to change this Direction
-- with a 90 degree anticlockwise shift.
IF (@angle = @CONSTANT) -- Origin [Same Position]
SET @RetVal = ''
ELSE IF (@angle BETWEEN 0 AND 22.5)
SET @RetVal = 'E'
ELSE IF(@angle BETWEEN 22.51 AND 67.49)
SET @RetVal = 'NE'
ELSE IF(@angle BETWEEN 67.5 AND 112.5)
SET @RetVal = 'N'
ELSE IF(@angle BETWEEN 112.51 AND 157.49)
SET @RetVal = 'NW'
ELSE IF(@angle BETWEEN 157.5 AND 202.5)
SET @RetVal = 'W'
ELSE IF(@angle BETWEEN 205.51 AND 247.49)
SET @RetVal = 'SW'
ELSE IF(@angle BETWEEN 247.5 AND 292.5)
SET @RetVal = 'S'
ELSE IF(@angle BETWEEN 292.51 AND 337.49)
SET @RetVal = 'SE'
ELSE IF(@angle BETWEEN 337.5 AND 360.00)
SET @RetVal = 'E'
SET @RetVal = ''
-- Return Direction Data
This formula accepts latitude and longitude values and returns a two-character string denoting direction. If the user and POI is on centre or the same location, it just returns a blank string.