Question

Initial Bearing Calculation error in PHP

Asked by: mdougan

I had some navigation code written in VB that I tried to convert to PHP.  It seemed fine until I started seeing errors when using Lat/Lons that appeared in the Eastern or Southern hemispheres.  

The output of the code sample below produces these results:

heading east in the northern/western hemisphere: 90
heading west in the northern/western hemisphere: 270
heading north in the northern/western hemisphere: 339
heading south in the northern/western hemisphere: nan

heading east in the northern/eastern hemisphere: 270
heading west in the northern/eastern hemisphere: 90
heading north in the northern/eastern hemisphere: 339
heading south in the northern/eastern hemisphere: nan

heading east in the southern/western hemisphere: 90
heading west in the southern/western hemisphere: 270
heading north in the southern/western hemisphere: nan
heading south in the southern/western hemisphere: 204

heading east in the southern/eastern hemisphere: 270
heading west in the southern/eastern hemisphere: 90
heading north in the southern/eastern hemisphere: nan
heading south in the southern/eastern hemisphere: 204

It appears my East/West calculations get reversed in the Eastern Hemisphere.

In all cases, I'd want to see either 0 or 360 for the North and 180 for the South bearings, I don't understand the readings that I'm getting here at all... and not sure whether "nan" is another way of saying 0?

I tried looking up alternative ways to calculate the initial bearing, and found this website, that describes a method using JavaScript.  

http://www.movable-type.co.uk/scripts/latlong.html

However, I tried converting that to PHP (found in the HeadingNew function in the code sample) and it gives me this output:

heading east in the northern/western hemisphere: 90
heading west in the northern/western hemisphere: -90
heading north in the northern/western hemisphere: 0
heading south in the northern/western hemisphere: 0

heading east in the northern/eastern hemisphere: 90
heading west in the northern/eastern hemisphere: -90
heading north in the northern/eastern hemisphere: 0
heading south in the northern/eastern hemisphere: 0

heading east in the southern/western hemisphere: 90
heading west in the southern/western hemisphere: -90
heading north in the southern/western hemisphere: 0
heading south in the southern/western hemisphere: 0

heading east in the southern/eastern hemisphere: 90
heading west in the southern/eastern hemisphere: -90
heading north in the southern/eastern hemisphere: 0
heading south in the southern/eastern hemisphere: 0

That is almost correct, except for the South calculation (and, I'm not sure if the North calculation is actually working or not).  If I used the new heading function, I'd have to find a way to convert the results to a compass bearing too.

Can anyone help me get either routine working, or do you have a sample of a completely different routine that will work in PHP?    

Thanks!

<?php
 
	    function HeadingNew($lat1, $long1, $lat2, $long2) {
	       // Takes lat/longs as expressions in Degrees
	       $rLat1 = 0.0;
	       $rLong1 = 0.0;
	       $rLat2 = 0.0;
	       $rLong2 = 0.0;
	       $d = 0.0;
	       $h = 0.0;
	       $result = 0.0;
 
	       $rLat1 = deg2rad($lat1);
	       $rLong1 = deg2rad($long1);
 
	       $rLat2 = deg2rad($lat2);
	       $rLong2 = deg2rad($long2);
 
 
                $d = deg2rad($long2 - $long1);
                $y = sin($d) * cos($rlat2);
                $x = cos($rlat1) * sin($rlat2) - sin($rlat1) * cos($rlat2) * cos($d);
                $h = atan2($y, $x);
                //echo "D = ".$d." X = ".$x." Y = ".$y." H = ".$h."<br>";
 
 	        $result = rad2deg($h);
 
 
	       return($result);
	    }
 
	    function Heading($lat1, $long1, $lat2, $long2) {
	       // Takes lat/longs as expressions in Degrees
	       $pi = 3.14159265358979;
	       $rLat1 = 0.0;
	       $rLong1 = 0.0;
	       $rLat2 = 0.0;
	       $rLong2 = 0.0;
	       $d = 0.0;
	       $h = 0.0;
	       $result = 0.0;
 
	       $rLat1 = deg2rad($lat1);
	       $rLong1 = deg2rad($long1);
 
	       $rLat2 = deg2rad($lat2);
	       $rLong2 = deg2rad($long2);
 
 
	       // Distance in Meters Using Radians
	       // Less subject to rounding errors for small distances
	        $d = ( 2 * asin(sqrt(pow(sin(($rLat1 - $rLat2) / 2), 2) + cos($rLat1) * cos($rLat2) * pow(sin(($rLong1 - $rLong2) / 2),2))));
 
	       if (sin(ABS($rLong2) - ABS($rLong1)) < 0) {
                  //echo "top calc <br>";
	          $h = acos(((sin($rLat2) - sin($rLat1)) * cos($d)) / (sin($d) * cos($rLat1)));
	          }
	       else {
                  //echo "bottom calc <br>";
	          $h = 2 * $pi - acos(((sin($rLat2) - sin($rLat1)) * cos($d)) / (sin($d) * cos($rLat1)));
	          }
 
	       $result = rad2deg($h);
 
 
	       return($result);
	    }
 
 
	 $dHeading = number_format(Heading(30, -30, 30, -20));
         echo "heading east in the northern/western hemisphere: ".$dHeading."<br>";
	 $dHeading = number_format(Heading(30, -20, 30, -30));
         echo "heading west in the northern/western hemisphere: ".$dHeading."<br>";
	 $dHeading = number_format(Heading(30, -30, 40, -30));
         echo "heading north in the northern/western hemisphere: ".$dHeading."<br>";
	 $dHeading = number_format(Heading(40, -30, 30, -30));
         echo "heading south in the northern/western hemisphere: ".$dHeading."<p>";
 
 
	 $dHeading = number_format(Heading(30, 30, 30, 40));
         echo "heading east in the northern/eastern hemisphere: ".$dHeading."<br>";
	 $dHeading = number_format(Heading(30, 40, 30, 30));
         echo "heading west in the northern/eastern hemisphere: ".$dHeading."<br>";
	 $dHeading = number_format(Heading(30, 30, 40, 30));
         echo "heading north in the northern/eastern hemisphere: ".$dHeading."<br>";
	 $dHeading = number_format(Heading(40, 30, 30, 30));
         echo "heading south in the northern/eastern hemisphere: ".$dHeading."<p>";
 
 
	 $dHeading = number_format(Heading(-50, -50, -50, -40));
         echo "heading east in the southern/western hemisphere: ".$dHeading."<br>";
	 $dHeading = number_format(Heading(-50, -40, -50, -50));
         echo "heading west in the southern/western hemisphere: ".$dHeading."<br>";
	 $dHeading = number_format(Heading(-50, -50, -40, -50));
         echo "heading north in the southern/western hemisphere: ".$dHeading."<br>";
	 $dHeading = number_format(Heading(-40, -50, -50, -50));
         echo "heading south in the southern/western hemisphere: ".$dHeading."<p>";
 
 
	 $dHeading = number_format(Heading(-50, 50, -50, 60));
         echo "heading east in the southern/eastern hemisphere: ".$dHeading."<br>";
	 $dHeading = number_format(Heading(-50, 60, -50, 50));
         echo "heading west in the southern/eastern hemisphere: ".$dHeading."<br>";
	 $dHeading = number_format(Heading(-50, 50, -40, 50));
         echo "heading north in the southern/eastern hemisphere: ".$dHeading."<br>";
	 $dHeading = number_format(Heading(-40, 50, -50, 50));
         echo "heading south in the southern/eastern hemisphere: ".$dHeading."<br>";
 
 
     ?>

                                  
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
60:
61:
62:
63:
64:
65:
66:
67:
68:
69:
70:
71:
72:
73:
74:
75:
76:
77:
78:
79:
80:
81:
82:
83:
84:
85:
86:
87:
88:
89:
90:
91:
92:
93:
94:
95:
96:
97:
98:
99:
100:
101:
102:
103:
104:
105:
106:
107:
108:
109:
110:

Select allOpen in new window

This Question has been solved and asker verified All Experts Exchange premium technology solutions are available to subscription members.

Subscribe now for full access to Experts Exchange and get

Instant Access to this Solution

  • Plus...
  • 30 Day FREE access, no risk, no obligation
  • Collaborate with the world's top tech experts
  • Unlimited access to our exclusive solution database
  • Never be left without tech help again

Subscribe Now

Asked On
2007-12-12 at 09:35:08ID23018885
Tags

bearing

,

calculate

,

heading

,

php

Topics

PHP Scripting Language

,

Algorithms

Participating Experts
1
Points
500
Comments
8

Trusted by hundreds of thousands everyday for fast, accurate and reliable tech support.

  • "The time we save is the biggest benefit of Experts Exchange to Warner Bros. What could take multiple guys 2 hours or more each to find is accessed in around 15 minutes on Experts Exchange." Mike Kapnisakis, Warner Bros.
  • "Our team likes having a resource that is more secure than just using Google and most experts using this service really know their stuff. It's nice to look here first versus using Google." Dayna Sellner, Lockheed Martin
  • "Anytime that I've been stumped with a problem, 9 out of 10 times Experts Exchange has either the accepted solution or an open discussion of the potential solution to the problem." Kenny Red, eBay Inc.

See what Experts Exchange can do for you.

Got a question?

We've got the answer.

Experts Exchange has been collecting answers to technology questions since 1996…3 million and counting! If you have a question, chances are we already have your answer.

Screenshot of Experts Exchange Knowledgebase

Need individual assistance?

Our experts are ready to help.

If you can't find the exact answer you're looking for, ask our exclusive community of 50,000 experts. You’ll get a personalized answer from a trusted professional.

Screenshot of Experts Exchange Knowledgebase

Want to learn from the best?

Read articles from industry experts.

Thousands of free tech tips, tricks, how-to’s and tutorials are available in our peer reviewed articles section. See for yourself how smart our experts are, no login required.

Screenshot of an Article

Working on a long term project?

Store your work and research.

Save solutions to your questions, answers you’ve discovered through searching plus helpful articles in your personal knowledgebase for easy future access.

Screenshot of Experts Exchange Knowledgebase

Access the answers to your technology questions today.

Subscribe Now

30-day free trial. Register in 60 seconds.

What Makes Experts Exchange Unique?

Members of the expert community talk about why the experience at Experts Exchange is different than what you will find anywhere else.

Trusted by the world's most respected brands.

image of each brand's logo

Faithfully serving IT professionals since 1996.

Experts Exchange Logo

Try it out and discover for yourself.

Subscribe Now

30-day free trial. Register in 60 seconds.

Related Solutions

  1. Northing Easting Calculations..
    Im using a Postcode component giving me an OS grid Easting and Northing positions. I have 2 coordinates, I need to measure the distance between the 2 points and also get the direction of travel. I have sussed out the direction problem (I think) but im struggling with the dire...
  2. PHP function to calculate bearing between latitudes and lon…
    I need to be able to calculate the bearing between two latitude and longitude pairs, in PHP. They are decimal degrees, and since we are in Australia, our points we are working with are negative latitude, positive longitude. eg. -29.54546 Latitude and 149.68756 longitude. I h...
  3. Calculate bearing from decimal Lat/Long
    Hi, I need to be able to calculate the bearing from one point to another given the first and second points latitude and longitude. Ive found the formula to do this on a math site, but I cant seem to make it work in a UDF. Heres code..... CREATE FUNCTION [dbo].[GetBearing] (...

Free Tech Articles

  1. WARNING: 5 Reasons why you should NEVER fix a computer for free.
    It is in our nature to love the puzzle. We are obsessed. The lot of us. We love puzzles. We love the challenge. We thrive on finding the answer. We hate disarray. It bothers us deep in our soul. W...
  2. SCCM OSD Basic troubleshooting
    SCCM 2007 OSD is a fantastic way to deploy operating systems, however, like most things SCCM issues can sometimes be difficult to resolve due to the sheer volume of logs to sift through and the dispe...
  3. Migrate Small Business Server 2003 to Exchange 2010 and Windows 2008 R2
    This guide is intended to provide step by step instructions on how to migrate from Small Business Server 2003 to Windows 2008 R2 with Exchange 2010. For this migration to work you will need the fo...
  4. Create a Win7 Gadget
    This article shows you how to create a simple "Gadget" -- a sort of mini-application supported by Windows 7 and Vista. Gadgets can be dropped anywhere on the desktop to provide instant information, ...
  5. Outlook continually prompting for username and password
    There have been a lot of questions recently regarding Outlook prompting for a username and password whilst using Exchange 2007. There are a few reasons why this would happen and I will try to cover t...
  6. Backup Exchange 2010 Information Store using Windows Backup
    There seems to be quite a lot of confusion around the ability to backup Exchange 2010 using the built in Windows Backup feature. This stems from the omission of this feature prior to Exchange 2007 s...

Cloud Class Webinars

  1. Avoiding Bugs in Microsoft Access
    Alison Balter takes and in-depth look at avoiding bugs in Access. In this webinar you will learn about using the immediate window to debug your applications, invoking the debugger, using breakpoints to troubleshoot, stepping through code, setting the next statement to execute, ...
  2. Top 10 Best New Features in Visio 2010
    Scott Helmers gives live demonstrations of the top 10 new features in Visio 2010. This webinar will teach you how to create compelling diagrams by adding shapes to the page with a single click, linking the shapes in a diagram to data in Excel (or SQL Server, or SharePoint), ...
  3. IT Consultant Business Secrets Revealed
    Michael Munger, Experts Exchange tech pro and IT consultant, pulls back the curtain on his very successful businesses and answers question on every IT consultant and business owner should know about. He shares secrets on what he did to solve the 5 most common problems in IT, ...
  4. Disaster Recovery and Business Continuity
    Quest CTO, Mike Billon, gives an overview of the steps involved in building a dunamic disaster recovery plan. Through case studies and an examination of software/hardware tooles for monitoring and testing, you'll gain a better understandin of where you are, where you want ...
  5. Organize Your Visio Diagrams with Containers and Lists
    Scott Helmers uses cross functional flowcharts, wireframe diagrams, data graphic legends and seating charts to teach you: how to ustilize all three new structured diagram components in Visio 2010, the best practices for organizeing shapes in previous version of Visio, how to organize ...
  6. How to Us Objects, Properties, Events and Methods in Microsoft Access
    Alison Dalter gives an in-depbth look at objects, properties, events and methods in Microsoft Access. In this webinar you will learn about using the object browser, referring to objects, working with properties and methods, working with object variables, understanding the ...

Join the Community

Give a Little. Get a Lot.

Join the community of experts here and help other tech pros by answering question in your area of expertise. You can earn FREE access to all Experts Exchange's premium features and resources.

Join the Community

Answers

 

by: AlexanderRPosted on 2007-12-12 at 17:07:01ID: 20461584

This looks interesting.
I just don't really follow what exactly is done.  You need user to input his current location and then his destination (using lang and lat) and it suppose to give him compass bearing direction to the destination from where he is now?  Just asking, because that website deals with spherical distance.

 

by: mdouganPosted on 2007-12-12 at 20:22:45ID: 20462348

Yes, we have a database (MySQL) that contains a series of lat/lon positions of a boat that is sailing around the world.  I've written a PHP script that reads these positions, then calculates the speed and heading based on the readings between two positions and generates either a google map, or a google KML file (depending on the URL).  All seemed reasonably accurate when they were in the Northern/Western hemispheres, however they are now in the Southern/Eastern hemispheres and I noticed that the heading calculation was off.

Entries to the MySQL database are made by another script that reads positions reported by a satellite tracking unit on board the boat.  That script is scheduled to run about every hour or so.

 

by: AlexanderRPosted on 2007-12-13 at 14:06:04ID: 20468161

This is a fun thing to work on.

I've looked at the JavaScript code on that link you provided first, so i can compare results i get from your / my code to theirs.  This is what i get so far for bearings:

heading east in the northern/western hemisphere: 87
heading west in the northern/western hemisphere: 272
heading north in the northern/western hemisphere: 0
heading south in the northern/western hemisphere: 180

heading east in the northern/eastern hemisphere: 87
heading west in the northern/eastern hemisphere: 272
heading north in the northern/eastern hemisphere: 0
heading south in the northern/eastern hemisphere: 180

heading east in the southern/western hemisphere: 93
heading west in the southern/western hemisphere: 266
heading north in the southern/western hemisphere: 0
heading south in the southern/western hemisphere: 180

heading east in the southern/eastern hemisphere: 93
heading west in the southern/eastern hemisphere: 266
heading north in the southern/eastern hemisphere: 0
heading south in the southern/eastern hemisphere: 180

Code used is
function HeadingNew($lat1, $long1, $lat2, $long2) {
               // Takes lat/longs as expressions in Degrees
               $pi = 3.14159265358979;
               $rLat1 = 0.0;
               $rLong1 = 0.0;
               $rLat2 = 0.0;
               $rLong2 = 0.0;
               $d = 0.0;
               $h = 0.0;
               $result = 0.0;
 
               $rLat1 = deg2rad($lat1);
               $rLong1 = deg2rad($long1);
 
               $rLat2 = deg2rad($lat2);
               $rLong2 = deg2rad($long2);
 
 
                $d = deg2rad($long2 - $long1);
                $y = sin($d) * cos($rLat2);
                $x = cos($rLat1) * sin($rLat2) - sin($rLat1) * cos($rLat2) * cos($d);
                $h = atan2($y, $x);
                //echo "D = ".$d." X = ".$x." Y = ".$y." H = ".$h."<br>";
 
                //$result = rad2deg($h);
 
                $result = $h * (180/$pi);
                $result = ($result + 360) % 360;
 
               return($result);
            }

I think what you missed is the last step described on that page (and its strange it was not a part of the JS code, you have to look further down to see it) about converting to real bearing values.

However, it shows weird 87 instead of 90 both on calculator, PHP and their site.  Does that mean their formula is inaccurate?   I tried yours on calculator and it comes out almost to perfect 90.  I will now go on to see where PHP went wrong in getting those weird values like 207.

 

by: AlexanderRPosted on 2007-12-13 at 14:08:47ID: 20468185

P.S.
Or
$result = rad2deg($h);
$result = ($result + 360) % 360;  // line that does bearing values.

 

by: mdouganPosted on 2007-12-14 at 07:51:09ID: 20472260

Hi, thanks for the help.  I spent a lot of time debugging this yesterday, and adding the last step from that website did help, but, there were some results, as you found, that I couldn't ever get to come out right.

I decided to go back to my original heading routine, and compare the VB version with the PHP version to see where the PHP version was going wrong.  The problem was when making the call to the acos function.  That function will only take values in the range of -1 to 1 and will return values in the range of -pi to pi.  The result of the equation:

((sin($rLat2) - sin($rLat1)) * cos($d)) / (sin($d) * cos($rLat1))

was coming out more than 1 or less than -1 in the case of a pure South movement .  What I did was add code to check to see if the result of that calculation was going to go above or below those limits, and if so, I would pass the max/min value to the acos function instead.  That helped, but, I'm still getting weird values for South (in the Northern hemisphere) and North (in the Southern hemisphere).

I'm back to working on the old routine, however, if you can figure out what is going wrong with the new routine, let me know.  (I'm sure the points will go to you either way).  Attached is my latest set of changes.

<?php
 
 
	    function Heading($lat1, $long1, $lat2, $long2) {
	       // Takes lat/longs as expressions in Degrees
	       $pi = 3.14159265358979;
	       $rLat1 = 0.0;
	       $rLong1 = 0.0;
	       $rLat2 = 0.0;
	       $rLong2 = 0.0;
	       $d = 0.0;
	       $h = 0.0;
	       $result = 0.0;
 
	       $rLat1 = deg2rad($lat1);
	       $rLong1 = deg2rad($long1);
 
	       $rLat2 = deg2rad($lat2);
	       $rLong2 = deg2rad($long2);
 
 
	       // Distance in Meters Using Radians
	       // Less subject to rounding errors for small distances
	        $d = ( 2 * asin(sqrt(pow(sin(($rLat1 - $rLat2) / 2), 2) + cos($rLat1) * cos($rLat2) * pow(sin(($rLong1 - $rLong2) / 2),2))));
                
                // subtracting the acos from 2 * pi does the same as the MOD 360 calculation
                if (($long2 - $long1) < 0) {
 
                        // if we're going to pass acos a value greater than 1, then just pass 1
                        if (((((sin($rLat2) - sin($rLat1)) * cos($d)) / (sin($d) * cos($rLat1)))) > 1) {
                                $h = 2 * $pi - acos(1);
                           }
                        else {
                                // if we're going to pass acos a value < -1, then just pass -1
                                if (((((sin($rLat2) - sin($rLat1)) * cos($d)) / (sin($d) * cos($rLat1)))) < -1) {
	                                $h = 2 * $pi - acos(-1);
                                   }
                                else {
	                                $h = 2 * $pi - acos(((sin($rLat2) - sin($rLat1)) * cos($d)) / (sin($d) * cos($rLat1)));
                                }
                        }
                   }
                else {
                        // if we're going to pass acos a value greater than 1, then just pass 1
                        if (((((sin($rLat2) - sin($rLat1)) * cos($d)) / (sin($d) * cos($rLat1)))) > 1) {
                             $h = acos(1);
                           }
                        else {
                                // if we're going to pass acos a value < -1, then just pass -1
                                if (((((sin($rLat2) - sin($rLat1)) * cos($d)) / (sin($d) * cos($rLat1)))) < -1) {
                                        $h = acos(-1);
                                   }
                                else {
                                        $h = acos(((sin($rLat2) - sin($rLat1)) * cos($d)) / (sin($d) * cos($rLat1)));
                                }
                        }
                }
 
              
               // Was still having trouble with purely North/South movement, so tried this
               // it works, but there are still errors if the course is just slightly East or West of North/South
               if ($long2 == $long1) {
                   if ($lat1 >= $lat2) {
                      $result = rad2deg(3.14159265358979);
                      }
                   else {
                      $result = rad2deg(0);
                      }
                  }
               else {
	           $result = rad2deg($h);
                  }
 
 
 
	       return($result);
	    }
 
 
 
	 $dHeading = number_format(Heading(30, -30, 30, -20));
         echo "heading east in the northern/western hemisphere: ".$dHeading."<br>";
	 $dHeading = number_format(Heading(30, -20, 30, -30));
         echo "heading west in the northern/western hemisphere: ".$dHeading."<br>";
	 $dHeading = number_format(Heading(30, -30, 40, -30));
         echo "heading north in the northern/western hemisphere: ".$dHeading."<br>";
	 $dHeading = number_format(Heading(40, -30, 30, -30));
         echo "heading south in the northern/western hemisphere: ".$dHeading."<p>";
 
 
	 $dHeading = number_format(Heading(30, 30, 30, 40));
         echo "heading east in the northern/eastern hemisphere: ".$dHeading."<br>";
	 $dHeading = number_format(Heading(30, 40, 30, 30));
         echo "heading west in the northern/eastern hemisphere: ".$dHeading."<br>";
	 $dHeading = number_format(Heading(30, 30, 40, 30));
         echo "heading north in the northern/eastern hemisphere: ".$dHeading."<br>";
	 $dHeading = number_format(Heading(40, 30, 30, 31));
         echo "heading south in the northern/eastern hemisphere: ".$dHeading."<p>";
 
 
	 $dHeading = number_format(Heading(-30, -30, -30, -20));
         echo "heading east in the southern/western hemisphere: ".$dHeading."<br>";
	 $dHeading = number_format(Heading(-30, -20, -30, -30));
         echo "heading west in the southern/western hemisphere: ".$dHeading."<br>";
	 $dHeading = number_format(Heading(-30, -30, -20, -30));
         echo "heading north in the southern/western hemisphere: ".$dHeading."<br>";
	 $dHeading = number_format(Heading(-20, -30, -30, -30));
         echo "heading south in the southern/western hemisphere: ".$dHeading."<p>";
 
 
	 $dHeading = number_format(Heading(-30, 30, -30, 40));
         echo "heading east in the southern/eastern hemisphere: ".$dHeading."<br>";
	 $dHeading = number_format(Heading(-30, 40, -30, 30));
         echo "heading west in the southern/eastern hemisphere: ".$dHeading."<br>";
	 $dHeading = number_format(Heading(-30, 30, -20, 30));
         echo "heading north in the southern/eastern hemisphere: ".$dHeading."<br>";
 
// This one is still coming out wrong because I added a little East movement... 
// course should probably be about 179 but comes out 162
 
	 $dHeading = number_format(Heading(-20, 30, -30, 31));
         echo "heading south in the southern/eastern hemisphere: ".$dHeading."<p>";
 
 
 
     ?>

                                              
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
60:
61:
62:
63:
64:
65:
66:
67:
68:
69:
70:
71:
72:
73:
74:
75:
76:
77:
78:
79:
80:
81:
82:
83:
84:
85:
86:
87:
88:
89:
90:
91:
92:
93:
94:
95:
96:
97:
98:
99:
100:
101:
102:
103:
104:
105:
106:
107:
108:
109:
110:
111:
112:
113:
114:
115:
116:
117:
118:
119:
120:
121:
122:
123:
124:
125:
126:

Select allOpen in new window

 

by: mdouganPosted on 2007-12-14 at 09:31:18ID: 20472988

OK, I've figured it out!

My incorrect assumption was that no matter what your longitude, going East should be 90 and West should be 270.  Apparently, that is only true at the equator.  If you call your version of the New Heading routine with a longitude of 0, then you get the exact numbers, otherwise, if you pass 30 north longitude as I have been, you should get about 92 and 272 respectively (the new heading routine is giving 87 and 272... hum).  You can check this on the other site that I listed a link to.

I found the error in my Old Heading routine was that I'd placed a pair of parenthesis in the wrong place.  In this equation, I put them around the subtraction when it should have been around the multiplcation.  That is what was causing invalid values to be sent to the acos function.

(((( ( sin($rLat2) - sin($rLat1) )  * cos($d))
should be
((((sin($rLat2) - ( sin($rLat1) * cos($d)) )

I'll attach the sample with both old and new heading routines for anyone else's information, and I'll go ahead and accept your original answer since it did produce working code!  Thanks!

You can see the results of this by going to the following URL
http://www.1000Days.net/gmap7.php

Or if you have Google Earth, you can generate a KML file by saving the page source generated after visiting this URL
http://www.1000Days.net/googleKML.php

Thanks again!

<?php
 
 
	    function Heading($lat1, $long1, $lat2, $long2) {
	       // Takes lat/longs as expressions in Degrees
	       $pi = 3.14159265358979;
	       $rLat1 = 0.0;
	       $rLong1 = 0.0;
	       $rLat2 = 0.0;
	       $rLong2 = 0.0;
	       $d = 0.0;
	       $h = 0.0;
	       $result = 0.0;
 
	       $rLat1 = deg2rad($lat1);
	       $rLong1 = deg2rad($long1);
 
	       $rLat2 = deg2rad($lat2);
	       $rLong2 = deg2rad($long2);
 
 
	       // Distance in Meters Using Radians
	       // Less subject to rounding errors for small distances
	        $d = ( 2 * asin(sqrt(pow(sin(($rLat1 - $rLat2) / 2), 2) + cos($rLat1) * cos($rLat2) * pow(sin(($rLong1 - $rLong2) / 2),2))));
                
                // subtracting the acos from 2 * pi does the same as the MOD 360 calculation
	        //if (sin(ABS($rLong2) - ABS($rLong1)) < 0) {
 
                if (($long2 - $long1) < 0) {
                      $h = 2 * $pi - acos((sin($rLat2) - (sin($rLat1) * cos($d))) / (sin($d) * cos($rLat1)));
                   }
                else {
                      $h = acos((sin($rLat2) - (sin($rLat1) * cos($d))) / (sin($d) * cos($rLat1)));
                }
              
 
               $result = rad2deg($h);
 
 
	       return($result);
	    }
 
            function HeadingNew($lat1, $long1, $lat2, $long2) {
               // Takes lat/longs as expressions in Degrees
               $pi = 3.14159265358979;
               $rLat1 = 0.0;
               $rLong1 = 0.0;
               $rLat2 = 0.0;
               $rLong2 = 0.0;
               $d = 0.0;
               $h = 0.0;
               $result = 0.0;
 
               $rLat1 = deg2rad($lat1);
               $rLong1 = deg2rad($long1);
 
               $rLat2 = deg2rad($lat2);
               $rLong2 = deg2rad($long2);
 
 
                $d = deg2rad($long2 - $long1);
                $y = sin($d) * cos($rLat2);
                $x = cos($rLat1) * sin($rLat2) - sin($rLat1) * cos($rLat2) * cos($d);
                $h = atan2($y, $x);
                //echo "D = ".$d." X = ".$x." Y = ".$y." H = ".$h."<br>";
 
                //$result = rad2deg($h);
 
                $result = $h * (180/$pi);
                $result = ($result + 360) % 360;
 
               return($result);
            }
 
   
 
 
	 $dHeading = number_format(Heading(00, -30, 00, -20));
         echo "heading east in the equator/western hemisphere: ".$dHeading."<br>";
	 $dHeading = number_format(Heading(00, -20, 00, -30));
         echo "heading west in the equator/western hemisphere: ".$dHeading."<br>";
	 $dHeading = number_format(Heading(30, -30, 40, -30));
         echo "heading north in the northern/western hemisphere: ".$dHeading."<br>";
	 $dHeading = number_format(Heading(40, -30, 30, -30));
         echo "heading south in the northern/western hemisphere: ".$dHeading."<p>";
 
 
	 $dHeading = number_format(Heading(30, 30, 30, 40));
         echo "heading east in the northern/eastern hemisphere: ".$dHeading."<br>";
	 $dHeading = number_format(Heading(30, 40, 30, 30));
         echo "heading west in the northern/eastern hemisphere: ".$dHeading."<br>";
	 $dHeading = number_format(Heading(30, 30, 40, 30));
         echo "heading north in the northern/eastern hemisphere: ".$dHeading."<br>";
	 $dHeading = number_format(Heading(40, 30, 30, 31));
         echo "heading southeast in the northern/eastern hemisphere: ".$dHeading."<p>";
 
 
	 $dHeading = number_format(Heading(-30, -30, -30, -20));
         echo "heading east in the southern/western hemisphere: ".$dHeading."<br>";
	 $dHeading = number_format(Heading(-30, -20, -30, -30));
         echo "heading west in the southern/western hemisphere: ".$dHeading."<br>";
	 $dHeading = number_format(Heading(-30, -30, -20, -30));
         echo "heading north in the southern/western hemisphere: ".$dHeading."<br>";
	 $dHeading = number_format(Heading(-20, -30, -30, -30));
         echo "heading south in the southern/western hemisphere: ".$dHeading."<p>";
 
 
	 $dHeading = number_format(Heading(-30, 30, -30, 40));
         echo "heading east in the southern/eastern hemisphere: ".$dHeading."<br>";
	 $dHeading = number_format(Heading(-30, 40, -30, 30));
         echo "heading west in the southern/eastern hemisphere: ".$dHeading."<br>";
	 $dHeading = number_format(Heading(-30, 30, -20, 30));
         echo "heading north in the southern/eastern hemisphere: ".$dHeading."<br>";
	 $dHeading = number_format(Heading(-20, 30, -30, 31));
         echo "heading southeast in the southern/eastern hemisphere: ".$dHeading."<p>";
 
 
 
     ?>
  

                                              
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
60:
61:
62:
63:
64:
65:
66:
67:
68:
69:
70:
71:
72:
73:
74:
75:
76:
77:
78:
79:
80:
81:
82:
83:
84:
85:
86:
87:
88:
89:
90:
91:
92:
93:
94:
95:
96:
97:
98:
99:
100:
101:
102:
103:
104:
105:
106:
107:
108:
109:
110:
111:
112:
113:
114:
115:
116:
117:
118:
119:
120:

Select allOpen in new window

 

by: AlexanderRPosted on 2007-12-14 at 18:52:24ID: 20475935

I was in the middle of investigating your function (after i was done with the first one) but had to go to school and by the time i made it home....looks like you got it already.  I wish i could have found the error myself first.  Oh well.  But thanks for the points!  Glad you got it working.
So it looks like spherical geometry is slightly different from plain in the directional sense.

 

by: mdouganPosted on 2007-12-14 at 23:40:51ID: 20476497


"So it looks like spherical geometry is slightly different from plain in the directional sense."

Yea, that was news to me!  Live and learn, eh?  :-)

20120131-EE-VQP-002

3 Ways to Join

30-Day Free Trial

The Experts

98% positive feedback on 31,087 answers since March 2000. angeliii is a Microsoft Most Valuable Professional for his work with MS SQL Server & Develoment.

He has also proven his knowledge of Visual Basic Programming, PHP Scripting and Oracle Databases.

The Experts

97% positive feedback on 10,752 answers since July 2000. lrmoore has more than 18 years experience in the networking industry.

The six-time Mircosoft MVPs specialties include firewalls, virtual private networking, and network management.

Testimonials

"...and excellent source for support... Kind of like having your very own IT dept." Electriciansnet

Testimonials

"I was apprehensive at signing up at first. However... it has already made my life as an IT administrator much easier." JaCrews

Testimonials

"WOW! You guys have great, active, and knowledgeable people on here." moore50

Business Clients

Business Clients

In the Press

"If you’ve got a question... Experts Exchange can supply an answer.”

In the Press

"...an invaluable aid for both IT professionals and those who require tech support."

In the Press

"where IT professionals provide quick answers on just about any topic"

Business Account Plans

Loading Advertisement...