Introduction
I am continuing the tip about the implementation in ANSI C.
The Base26GPS standard is used for sharing location between platforms by converting the longitude
and latitude
to a string
. The string
is from A to Z, having 26 characters all together thus making it a Base26 in the numeral system which is also known as Hexavigesimal. In this tip, I will describe the code that is used to implement it.
For more information, you can visit the website here.
Background
Location is based on Longitude
and Latitude
. Longitude
is a number between -180.0 to 180 and latitude
is a number between -90 to 90. Until now, applications from different platforms did not have a standard to send the location between one another, they used their own internal standards.
Using the Code
There are two functions:
ConcertLocToBase26
- converts Longitude
and Latitude
to a string
ConvertBase26ToLoc
- converts a string
to Longitude
and Latitude
Converting from Longitude
and Latitude
to Alphabetic letters is done using the following steps:
- The first three letters are "GPS", next six letters represent
Longitude
and last six letters represent Latitude
. All together fifteen letters. - The
Longitude
and Latitude
should always have 4 numbers after the dot.
For example: -180 will be -180.0000, 12.53 will be 12.5300 and 151.45319 will be 151.4532 - Each one is separated to the number located at the left side of the decimal point and the number located at the right of the decimal point.
- The left number is from -180 to 180 for
Longitude
. -180 equals to AA and 180 equals to NW. Here the counting begins from -180.
For Latitude
, the left number is from -90 to 90. -90 equals to AA and 90 equals to GY. Here the counting begins from -90. - The right number is divided into two groups. Each group is from 00 to 99. 00 equals to AA and 99 equals to DV. Here the counting begins from 0.
- After conversion, there are six letters for
Longitude
and six letters for Latitude
.
For example – Longitude
of 12.45 and Latitude
of -11.54 will generate the string
"GPSHKBTAADBCCAA
".
Converting from alphabetic letters to Longitude
and Latitude
is done using the same principle.
Below are the JavaScript functions that convert from Longitude, Latitude to Base26GPS and vise versa.
I learned some things while writing this code.
For example, I noticed the Google Chrome does not support in a transparant manner the 'GetElementById
' which searches the name of the form box. Instead, I had to dig into the path of the form.
Another thing I studied is how to manipulate inside a string
and how to convert it to decimal value and I also learned how to return more than one variable from a function.
What amazes me in JavaScript is that there is no need to declare the variable's type.
The thing I enjoyed the most is using my own browser to debug and run the script. There is no need for any external compilers. I used a Debug box form to display variables for debugging and that's it...
function ConvertLongitude(Longitude)
{
var TempFloat;
var FractPart;
var TempFractPart;
var IntPart;
var Multiply;
var Add;
var Fail = 0;
var Sign;
var LongitudeString;
Check for longitude validity:
if (Longitude<-180 || Longitude>180)
{
ShowError('Longitude parameter out of limits. -180 to 180');
return [0,0];
}
if (Longitude<0)
{
Longitude-=0.00005;
Sign=-1;
}
else
{
Longitude+=0.00005;
Sign=1;
}
Get the integer part:
IntPart=MakeInteg(Longitude);
Get the fraction part:
FractPart=Math.abs(Longitude - IntPart)*10000;
Get the two letters of the integer part:
TempFloat=MakeInteg((IntPart+180)/26);
Multiply=TempFloat+65;
If Longitude is between -0.9999 to -0.001, use the letter 'Z':
if (MakeInteg(Longitude)==0 && Sign== -1)
Multiply=90; LongitudeString=String.fromCharCode(Multiply);
TempFloat=((((IntPart+180)/26) - MakeInteg((IntPart+180)/26))*26)+0.1;
Add = Math.floor(TempFloat)+65;
LongitudeString+=String.fromCharCode(Add);
Get the first two letters of the fract part:
TempFractPart = FractPart/100;
TempFloat = MakeInteg(TempFractPart/26);
Multiply = TempFloat+65;
LongitudeString+=String.fromCharCode(Multiply);
TempFloat=(((TempFractPart/26) - MakeInteg(TempFractPart/26))*26);
Add = Math.floor(TempFloat)+65;
LongitudeString+=String.fromCharCode(Add);
Get the second two letters of the fract part:
TempFractPart = (FractPart/100 - MakeInteg(FractPart/100))*100;
TempFloat = MakeInteg(TempFractPart/26);
Multiply = TempFloat+65;
LongitudeString+=String.fromCharCode(Multiply);
TempFloat=(((TempFractPart/26) - MakeInteg(TempFractPart/26))*26);
Add = Math.floor(TempFloat)+65;
LongitudeString+=String.fromCharCode(Add);
Return the longitude string:
return[1,LongitudeString];
}
function ConvertLatitude(Latitude)
{
var TempFloat;
var FractPart;
var TempFractPart;
var IntPart;
var Multiply;
var Add;
var Fail = 0;
var Sign;
var LatitudeString;
Check for validity:
if (Latitude<-90 || Latitude>90)
{
ShowError('Latitude parameter out of limits. -90 to 90');
return [0,0];
}
if (Latitude<0)
{
Latitude-=0.00005;
Sign=-1;
}
else
{
Latitude+=0.00005;
Sign=1;
}
Get the integer part:
IntPart=MakeInteg(Latitude);
Get the fract part:
FractPart=Math.abs(Latitude - IntPart)*10000;
Get the two letters of the integer part:
TempFloat=MakeInteg((IntPart+90)/26);
Multiply=TempFloat+65;
If Latitude is between -0.9999 to -0.001, use the letter 'Z':
if (MakeInteg(Latitude)==0 && Sign== -1)
Multiply=90;
LatitudeString=String.fromCharCode(Multiply);
TempFloat=((((IntPart+90)/26) - MakeInteg((IntPart+90)/26))*26)+0.1;
Add = MakeInteg(TempFloat)+65;
LatitudeString+=String.fromCharCode(Add);
TempFractPart = FractPart/100;
TempFloat = MakeInteg(TempFractPart/26);
Multiply = TempFloat+65;
LatitudeString+=String.fromCharCode(Multiply);
Get the first two letters of the fract part:
TempFloat=(((TempFractPart/26) - MakeInteg(TempFractPart/26))*26);
Add = MakeInteg(TempFloat)+65;
LatitudeString+=String.fromCharCode(Add);
TempFractPart = (FractPart/100 - MakeInteg(FractPart/100))*100;
TempFloat = Math.floor(TempFractPart/26);
Multiply = TempFloat+65;
LatitudeString+=String.fromCharCode(Multiply);
Get the second two letters of the fract part:
TempFloat=(((TempFractPart/26) - Math.floor(TempFractPart/26))*26);
Add = Math.floor(TempFloat)+65;
LatitudeString+=String.fromCharCode(Add);
Return the latitude string:
return[1,LatitudeString];
}
function ConvertLocToBase26()
{
var Longitude;
var Latitude;
var ReturnArray;
ReturnArray = GetLongitudeLatitude()
if (ReturnArray[0]==0)
return 0;
Longitude = parseFloat(ReturnArray[1]);
Latitude = parseFloat(ReturnArray[2]);
Set the string header to GPS:
var Base26GPSString='GPS';
Get the longitude string:
ReturnArray=ConvertLongitude(Longitude);
if (ReturnArray[0]==0)
return 0;
Base26GPSString+=ReturnArray[1];
Get the latitude string:
ReturnArray=ConvertLatitude(Latitude);
if (ReturnArray[0]==0)
return 0;
Base26GPSString+=ReturnArray[1];
Combined string:
ShowBase26GPSString(Base26GPSString);
}
function ConvertBase26ToLoc()
{
var LongitudeString;
var NewLongitudeString="";
var LatitudeString;
var NewLatitudeString="";
var SetStringMultiply;
var SetStringAdd;
var SetString;
var RetNum;
var count;
var PassFail;
var Fail = 0;
var Sign;
var SignForZero;
var GPSString;
var ReturnArray;
var ReturnLongitude;
var ReturnLatitude;
Base26GPSString = GetBase26GPS();
Check the length. It must be 15
.
if (Base26GPSString.length!=15)
{
ShowError('String must have 15 characters');
return [0,0,0];
}
GPSString = Base26GPSString.slice(0,3);
if (GPSString !='GPS')
{
ShowError('GPS Header is missing');
return [0,0,0];
}
LongitudeString = Base26GPSString.slice(3,9);
LatitudeString = Base26GPSString.slice(9,16);
Change the lower case char
s to upper case and check for legal characters
for (count=0;count<6;count++)
{
if (!((LongitudeString.slice(count,count+1)).charCodeAt(0)>64 &&
(LongitudeString.slice(count,count+1)).charCodeAt(0)<91 ||
(LongitudeString.slice(count,count+1)).charCodeAt(0)>96 &&
(LongitudeString.slice(count,count+1)).charCodeAt(0)<123))
{
ShowError('Longitude string has illegal characters');
return [0,0,0];
}
if ((LongitudeString.slice(count,count+1)).charCodeAt(0)>96)
NewLongitudeString+=String.fromCharCode
((LongitudeString.slice(count,count+1).charCodeAt(0)) -32);
else
NewLongitudeString+=LongitudeString.slice(count,count+1);
if (!((LatitudeString.slice(count,count+1)).charCodeAt(0)>64 &&
(LatitudeString.slice(count,count+1)).charCodeAt(0)<91 ||
(LatitudeString.slice(count,count+1)).charCodeAt(0)>96 &&
(LatitudeString.slice(count,count+1)).charCodeAt(0)<123))
{
ShowError('Latitude string has illegal characters');
return [0,0,0];
}
if ((LatitudeString.slice(count,count+1)).charCodeAt(0)>96)
NewLatitudeString+=String.fromCharCode
(LatitudeString.slice(count,count+1).charCodeAt(0) -32);
else
NewLatitudeString+=LatitudeString.slice(count,count+1);
}
Longitude Activity
Extract the integer part:
SetStringMultiply = (NewLongitudeString.slice(0,1));
SetStringAdd = (NewLongitudeString.slice(1,2));
SignForZero = 1;
Check if the number is between -0.0001 to -0.9999:
if (SetStringMultiply.charCodeAt(0) == (90))
{
SignForZero = -1;
SetStringMultiply = String.fromCharCode(71);
}
SetString = SetStringMultiply+SetStringAdd;
RetNum = Base26ToNum(SetString);
Substract the longitude minimum value:
RetNum -=180;
if (RetNum<0)
Sign=-1;
else
Sign=1;
Check validity:
if (RetNum<-180 || RetNum>180)
{
ShowError('string parameters out of limits');
return [0,0,0];
}
ReturnLongitude=RetNum;
Extract the first fract part pair:
SetString = NewLongitudeString.slice(2,4);
RetNum = Base26ToNum(SetString);
if (RetNum<0 || RetNum>99)
{
ShowError('string parameters out of limits');
return 0;
}
ReturnLongitude+=RetNum*0.01*Sign;
Extract the last fract part pair:
SetString = NewLongitudeString.slice(4,6);
RetNum = Base26ToNum(SetString);
if (RetNum<0 || RetNum>99)
{
ShowError('string parameters out of limits');
return 0;
}
ReturnLongitude+=RetNum*0.0001*Sign;
ReturnLongitude*=SignForZero;
ShowLongitude(ReturnLongitude);
Latitude Activity
Extract the integer part:
SetStringMultiply = (NewLatitudeString.slice(0,1));
SetStringAdd = (NewLatitudeString.slice(1,2));
SignForZero = 1;
Check if the number is between -0.0001 to -0.9999:
if (SetStringMultiply.charCodeAt(0) == (90))
{
SignForZero = -1;
SetStringMultiply = String.fromCharCode(68);
}
SetString = SetStringMultiply+SetStringAdd;
RetNum = Base26ToNum(SetString);
RetNum -=90;
if (RetNum<0)
Sign=-1;
else
Sign=1;
if (RetNum<-90 || RetNum>90)
{
ShowError('string parameters out of limits');
return [0,0,0];
}
ReturnLatitude=RetNum;
Extract the first fract part pair:
SetString = NewLatitudeString.slice(2,4);
RetNum = Base26ToNum(SetString);
if (RetNum<0 || RetNum>99)
{
ShowError('string parameters out of limits');
return 0;
}
ReturnLatitude+=RetNum*0.01*Sign;
Extract the last fract part pair:
SetString = NewLatitudeString.slice(4,6);
RetNum = Base26ToNum(SetString);
if (RetNum<0 || RetNum>99)
{
ShowError('string parameters out of limits');
return 0;
}
ReturnLatitude+=RetNum*0.0001*Sign;
ReturnLatitude*=SignForZero;
ShowLatitude(ReturnLatitude);
}
function Base26ToNum(InputString)
{
var Multiply;
var Add;
var RetNum;
Multiply = (InputString.slice(0,1)).charCodeAt(0) - 65;
Add = (InputString.slice(1,2)).charCodeAt(0) - 65;
RetNum = Multiply * 26 + Add;
return RetNum;
}
I didn't find any function that makes flooring while maintaining the sign bit.
So I built one of my own:
function MakeInteg(Value)
{
var ReturnValue;
var Sign;
if (Value<0)
Sign=-1;
else
Sign=1
ReturnValue=Math.floor(Math.abs(Value))*Sign;
return ReturnValue;
}
This is the HTML to support the JavaScript:
<form name="LocationToBase26GPSform"
OnSubmit="javascript:test()">
Location to Base26GPS Online Calculator -
<br><br><br>
<table border="0">
<tr><td>
Longitude Input : </td><td><input type="text"
name="LongitudeInput">
</td></tr>
<tr><td>
Latitude Input : </td><td><input type="text"
name="LatitudeInput">
</td></tr>
<tr><td>
</td><td><input type="button"
value="Convert Location " OnClick="javascript:ConvertLocToBase26()">
</td></tr>
<tr><td>
Base26GPS : </td><td><input type="text"
size="30" name="Base26GPSInput">
</td></tr>
<tr><td>
</td><td><input type="button"
value="Convert Base26GPS" OnClick="javascript:ConvertBase26ToLoc()">
</td></tr>
<tr><td>
Longitude Result : </td><td><input type="text"
name="LongitudeTranslate">
</td></tr>
<tr><td>
Latitude Result : </td><td><input type="text"
name="LatitudeTranslate">
</td></tr>
</table>
<br><br>
<!-- Debug = <input type="text" name="DebugText"> -->
<br><br><br>
</form>
These are the JavaScript functions to support the HTML Form:
function ShowLongitude(LongitudeVal)
{
document.forms['LocationToBase26GPSform']['LongitudeTranslate'].value = LongitudeVal;
}
function ShowLatitude(LatitudeVal)
{
document.forms['LocationToBase26GPSform']['LatitudeTranslate'].value = LatitudeVal;
}
function ShowBase26GPSString(Base26GPSString)
{
document.forms['LocationToBase26GPSform']['Base26GPSInput'].value = Base26GPSString;
}
function GetBase26GPS()
{
return document.forms['LocationToBase26GPSform']['Base26GPSInput'].value
}
function GetLongitudeLatitude(){
var LongitudeString;
var LatitudeString;
LongitudeString = document.forms['LocationToBase26GPSform']['LongitudeInput'].value;
LatitudeString = document.forms['LocationToBase26GPSform']['LatitudeInput'].value;
if (isNaN(parseFloat(LongitudeString)))
{
ShowError('Longitude parameter illegal');
return [0,0,0];
}
if (isNaN(parseFloat(LatitudeString)))
{
ShowError('Longitude parameter illegal');
return [0,0,0];
}
return [1,LongitudeString,LatitudeString];
}
History
- This is the second version of this tip. The first one was in ANSI C.