I am not sure what might have happened with your formula in Excel. In this article I converted the Excel formula to work in a SQL statement, and that formula appeared to be producing the expected results. A couple of things to keep in mind:

* North and West positions should be entered as negative values

* Two negatives make a positive ( -p1 – -p2 ) = ( -p1 + p2)

* Accidentally reversing the longitude and latitude values will cause the calculations to be significantly off

* Excel, SQL, and various programming languages expect SIN and COS values in radians, so you need to convert the longitude and latitude values to their radian equivalents before plugging the values into the formula in Excel. This article describes how to perform the conversion:

=SIN(degree / 180 * 3.141592)

Once the conversion to radians is performed, you should be able to obtain the correct answer. The following is from the SQL statement:

ABS(ACOS(SIN(LOC1.LAT_RAD)*SIN(LOC2.LAT_RAD)+COS(LOC1.LAT_RAD)*COS(LOC2.LAT_RAD)*COS(LOC2.LON_RAD-LOC1.LON_RAD)))* 3960]]>

I typed your first ‘flat Earth’ formula into Excel and it returned a figure very close to what I was expecting (tho’ a bit larger than the county’s GIS mapping system’s ‘digitize distance’ function provides). I’m not worried at this point about absolute precision.

BUT….then I typed into Excel the kilometer formula that started with acos — and I got blown out of the water. The 2.9 miles of the first equation swelled to -I forget, some couple thousand km’s. So, is there a decimal point missing somewhere in there?

I probably won’t return to learn your answer, but wanted to point out the ‘mis-spelling’. (I checked the formula I had typed and it perfectly reflected yours.)

Any way, thanks for the interesting post! I also came out with lots of respect for the challenges GPS software (and users) must cope!

]]>Excellent points.

It probably would be a good idea to point out that the calculations do not determine driving distances between locations, nor do the calculations exactly determine flying distances (if a plane is a couple miles up in the air, that effectively makes the earth’s radius a couple of miles larger from the perspective of the plane. I now have a little more respect for the GPS manufacturers whose products attempt to determine the final destination arrival time.

]]>Thank you for the ideas. In an OTN thread (http://forums.oracle.com/forums/thread.jspa?threadID=1020948 ) I found an example of using SDO_GEOM.SDO_DISTANCE. The result? An error, why?

http://download.oracle.com/docs/cd/B19306_01/appdev.102/b14255/sdo_locator.htm

“The installation of Locator depends on the successful and proper installation of Oracle interMedia. interMedia is installed and configured with Oracle Database 10g…”

http://download.oracle.com/docs/cd/E18283_01/appdev.112/e11830/sdo_locator.htm

“The installation of Locator depends on the successful and proper installation of Oracle Multimedia. Oracle Multimedia is installed and configured with Oracle Database 11g, although you can…”

If someone (like me) did not see much point in installing Oracle Multimedia (formerly called Oracle interMedia), it is quite likely that the same error will be received.

With Oracle Multimedia installed:

SELECT SDO_GEOM.SDO_DISTANCE( SDO_GEOMETRY(2001,8307,SDO_POINT_TYPE((14 + 26/60),-(50 + 5/60),NULL),NULL,NULL), SDO_GEOMETRY(2001,8307,SDO_POINT_TYPE(-(43 + 12/60),(22 + 57/60),NULL),NULL,NULL), 0.0001,'unit=km') AS DISTANCE_BETWEEN_POINTS FROM DUAL ; DISTANCE_BETWEEN_POINTS ----------------------- 9876.67951

According to Google, 9,876.67951 kilometers = 6,137.08412 miles – very close to the 6,152 miles returned by the formula I posted above.

—

SELECT SDO_GEOM.SDO_DISTANCE( SDO_GEOMETRY(2001,8307,SDO_POINT_TYPE(-(36 + 44/60),(19 + 48/60),NULL),NULL,NULL), SDO_GEOMETRY(2001,8307,SDO_POINT_TYPE((42),(88 + 30/60),NULL),NULL,NULL), 0.0001,'unit=km') AS DISTANCE_BETWEEN_POINTS FROM DUAL ; DISTANCE_BETWEEN_POINTS ----------------------- 7779.77983

According to Google, 7,779.77983 kilometers = 4,834.13107 miles – very close to the 4,832.09 miles returned by the formula I posted above.

I have not compared the performance of the SDO_GEOM.SDO_DISTANCE method with the performance of the formula that I posted above.

]]>http://download.oracle.com/docs/cd/B28359_01/appdev.111/b28400/sdo_locator.htm#i632018

I don’t recall comparing the long equation mechanism with Locator/Spatial, but I did switch to the ‘flat earth’ calculation because it was a lot less cpu-intensive that SDO_GEOM and the error wasn’t significant for my purposes.

]]>using Oracle Locator might speed it up and : The Earth isn’t flat anymore and Spatial knows it! ;-)

select sdo_geom.sdo_distance(sdo_geometry(2001

,

, null

, mdsys.SDO_ELEM_INFO_ARRAY(1, 1, 1)

, mdsys.SDO_ORDINATE_ARRAY(, )

)

,sdo_geometry(2001

,

, null

, mdsys.SDO_ELEM_INFO_ARRAY(1, 1, 1)

, mdsys.SDO_ORDINATE_ARRAY(, )

)

,0.1

,’unit=km’) distance

from dual;

Thank you for the information.

I just had another thought regarding how to further decrease the CPU requirements for this SQL statement, and thus to speed up the SQL statement… the mathematics logic is starting to come back to me. The latitude values must be in the range of +- the radian value that is associated with the distance along the surface of the earth. The same is true for the longitude values.

With that logic in mind, it would be possible to reduce the number of rows leaving the inline view, and thus entering the WHERE clause of the main SQL statement. If the radius of the earth is roughly 3960 miles, the circumference is 3960 * 2 * 3.14159275 = 24881 miles. 1 degree = 69.115 miles, 1 mile = 0.0144686 degrees, 1 mile = 2.525254004999719e-4 radians. Thus, for each mile of the radius, the search range beyond the central latitude/longitude pair would be extended by +-2.525254004999719e-4 radians to pre-filter the majority of the rows that would exit the inline view and enter the WHERE clause of the main portion of the query.

]]>I *believe* but don’t know for sure that oracle locator (which is included in SE) will deal with this. For certain you can just call the web service directly via xdb. :)

]]>