Introduction
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. This code can be used as the driver for an Android based application that uses Base26GPS.
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. It has a small resemblance to the time before XML and after XML.
Using the Code
There are two classes:
LocToBase26GPS
- converts Longitude and Latitude to a string
Base26GPSToLoc
- 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.
Here is the code for the LocToBase26GPS
class:
public class LocToBase26GPS {
private String base26GPSString;
private float longitude;
private float latitude;
private String faultMessage;
private boolean isFault;
Return the translated string:
public String Base26GPSString() {
return base26GPSString;
}
Return the fault message:
public String FaultMessage() {
return faultMessage;
}
Return the fault flag:
public boolean IsFault() {
return isFault;
}
Constructor:
public LocToBase26GPS() {}
Send the longitude and latitude to be translated to string
:
public void LocToBase26GPSTranslate(float Longitude,float Latitude) {
longitude = Longitude;
latitude = Latitude;
String LongitudeString = "";
String LatitudeString = "";
base26GPSString = "";
faultMessage = "";
isFault = false;
Generate the Longitude part string
:
LongitudeString = LongitudeToBase26GPS(longitude);
if (isFault)
return;
Generate the Latitude part string
:
LatitudeString = LatitudeToBase26GPS(latitude);
if (isFault)
return;
Attach the "GPS" header:
base26GPSString = "GPS" + LongitudeString + LatitudeString;
}
Convert Longitude to string
:
private String LongitudeToBase26GPS(float longitude) {
float TempFloat;
double FractPart;
double TempFractPart;
double IntPart;
int Multiply;
int Add;
int Sign;
String ReturnString = "";
Check the limits of the longitude:
if (longitude < -180 || longitude > 180)
{
faultMessage = "Longitude Parameter out of limits";
isFault = true;
return ReturnString;
}
if (longitude < 0)
{
longitude -= (float)0.00005;
Sign = -1;
}
else
{
longitude += (float)0.00005;
Sign = 1;
}
Get the integral part:
IntPart = ((double)Math.floor(Math.abs(longitude)))*Sign;
Get the fract part:
FractPart = Math.abs(((double)longitude - IntPart)*10000);
Get the base26 multiply part of the int part. the start is from -180:
TempFloat = (float)((((int)(IntPart) + 180) / 26));
Multiply = (int)TempFloat + 65;
If the Longitude is between -0.9999 to -0.0001, use the letter Z:
if ((int)longitude == 0 && Sign == -1)
Multiply = 90;
Add the result to the string
:
ReturnString += (char)(Multiply);
TempFloat = (float)((((((IntPart) + 180) / 26) -
(int)(((IntPart) + 180) / 26)) * 26) + 0.1);
Get the base26 add part of the int
part:
Add = (int)(TempFloat) + 65;
Add the result to the string
:
ReturnString += (char)(Add);
Get the base26 multiply part of the first couple fract part:
TempFractPart = FractPart / 100;
TempFloat = (float)(((int)TempFractPart / 26));
Multiply = (int)TempFloat + 65;
Add the result to the string
:
ReturnString += (char)(Multiply);
TempFloat = (float)((((((TempFractPart)) / 26) -
(int)(((TempFractPart)) / 26)) * 26));
Get the base26 add part of the first couple fract part:
Add = (int)TempFloat + 65;
Add the result to the string
:
ReturnString += (char)(Add);
Get the base26 multiply part of the second couple fract part:
TempFractPart = ((FractPart) / 100 -
(int)((FractPart) / 100)) * 100;
TempFloat = (float)((TempFractPart / 26));
Multiply = (int)TempFloat + 65;
Add the result to the string
:
ReturnString += (char)(Multiply);
Get the base26 add part of the second couple fract part:
TempFloat = (float)((((((TempFractPart)) / 26) -
(int)(((TempFractPart)) / 26)) * 26));
Add = (int)TempFloat + 65;
Add the result to the string
:
ReturnString += (char)(Add);
return ReturnString;
Convert Latitude to string
. it has the same principle as the Longitude:
private String LatitudeToBase26GPS(float latitude) {
float TempFloat;
double FractPart;
double TempFractPart;
double IntPart;
int Multiply;
int Add;
int Sign;
String ReturnString = "";
if (latitude < -90 || latitude > 90)
{
faultMessage = "Langitude Parameter out of limits";
isFault = true;
return ReturnString;
}
if (latitude < 0)
{
latitude -= (float)0.00005;
Sign = -1;
}
else
{
latitude += (float)0.00005;
Sign = 1;
}
IntPart = ((double)Math.floor(Math.abs(latitude))) * Sign;
FractPart = Math.abs((double)latitude - IntPart) * 10000;
TempFloat = (float)((((int)(IntPart) + 90) / 26));
Multiply = (int)TempFloat + 65;
if ((int)latitude == 0 && Sign == -1)
Multiply = 90;
ReturnString += (char)(Multiply);
TempFloat = (float)((((((IntPart) + 90) / 26) -
(int)(((IntPart) + 90) / 26)) * 26) + 0.1);
Add = (int)(TempFloat) + 65;
ReturnString += (char)(Add);
TempFractPart = FractPart / 100;
TempFloat = (float)(((int)TempFractPart / 26));
Multiply = (int)TempFloat + 65;
ReturnString += (char)(Multiply);
TempFloat = (float)((((((TempFractPart)) / 26) -
(int)(((TempFractPart)) / 26)) * 26));
Add = (int)TempFloat + 65;
ReturnString += (char)(Add);
TempFractPart = ((FractPart) / 100 -
(int)((FractPart) / 100)) * 100;
TempFloat = (float)((TempFractPart / 26));
Multiply = (int)TempFloat + 65;
ReturnString += (char)(Multiply);
TempFloat = (float)((((((TempFractPart)) / 26) -
(int)(((TempFractPart)) / 26)) * 26));
Add = (int)TempFloat + 65;
ReturnString += (char)(Add);
return ReturnString;
}
Here is the code for the Base26GPSToLoc
class:
public class Base26GPSToLoc {
private float longitude = 0;
private float latitude = 0;
private String faultMessage;
private boolean isFault;
Return the fault message:
public String FaultMessage() {
return faultMessage;
}
Return the fault flag:
public boolean IsFault() {
return isFault;
}
Return the translated Longitude:
public float Longitude() {
return longitude;
}
Return the translated Latitude:
public float Latitude() {
return latitude;
}
Constructor:
public Base26GPSToLoc() {}
Send the String
to be translated to Longitude and Latitude:
public void Base26GPSToLocTranslate(String Base26GPSString) {
String LongitudeString = "";
String LatitudeString = "";
String SetString = "";
int RetNum;
int Count;
int Sign;
int SignForZero = 1;
faultMessage = "";
isFault = false;
try
{
Check the length of the string
:
if (Base26GPSString.length() != 15)
{
faultMessage = "the string length does not match";
isFault = true;
return;
}
Check if the header of the string
is GPS:
if ( !((Base26GPSString.substring(0, 3)).toUpperCase()).equals("GPS"))
{
faultMessage = "GPS Header is missing";
isFault = true;
return;
}
Extract the longitude part of the string
:
LongitudeString = Base26GPSString.substring(3, 9).toUpperCase();
Extract the latitude part of the string
:
LatitudeString = Base26GPSString.substring(9, 15).toUpperCase();
Check that all characters are legal (A..Z):
for (Count = 0; Count < 6; Count++)
{
if (!(((int)((LongitudeString.substring(
Count, Count+1)).toCharArray()[0])) > 64 &&
((int)((LongitudeString.substring
(Count, Count+1)).toCharArray()[0])) < 91))
{
faultMessage = "Longitude string has illegal characters";
isFault = true;
return;
}
if (!(((int)((LatitudeString.substring
(Count, Count+1)).toCharArray()[0])) > 64 &&
((int)((LatitudeString.substring
(Count, Count+1)).toCharArray()[0])) < 91))
{
faultMessage = "Latitude string has illegal characters";
isFault = true;
return;
}
}
Longitude activity:
Check if the letter Z is in the integral part. If so, it means there is a negative zero.
if ((int)(LongitudeString.substring(0, 1).toCharArray()[0]) == 90)
{
SetString = "";
SetString += (char)71;
SignForZero = -1;
}
else
{
SetString = LongitudeString.substring(0, 1);
SignForZero = 1;
}
Get the add letter from the integral part:
SetString += LongitudeString.substring(1, 2);
Convert to number from base26:
RetNum = Base26ToNum(SetString);
if (isFault == true)
return;
The longitude integral part starts from -180:
RetNum -= 180;
if (RetNum < 0)
Sign = -1;
else
Sign = 1;
Check the outcome limits:
if (RetNum < -180 || RetNum > 180)
{
faultMessage = "Longitude string parameter out of limits";
isFault = true;
return;
}
Add the result to longitude:
longitude = (float)RetNum;
Get the two letters of the first couple of the fract part:
SetString = LongitudeString.substring(2, 4);
Convert to number from base26:
RetNum = Base26ToNum(SetString);
if (isFault == true)
return;
Check the outcome limits:
if (RetNum < 0 || RetNum > 99)
{
faultMessage = "Longitude string parameter out of limits";
isFault = true;
return;
}
Add the result to longitude:
longitude += ((float)RetNum * (float)0.01) * Sign;
Get the two letters of the second couple of the fract part:
SetString = LongitudeString.substring(4, 6);
RetNum = Base26ToNum(SetString);
if (isFault == true)
return;
Check the outcome limits:
if (RetNum < 0 || RetNum > 99)
{
faultMessage = "Longitude string parameter out of limits";
isFault = true;
return;
}
Add the result to longitude:
longitude += ((float)RetNum * (float)0.0001) * Sign;
If negative zero, then add minus to the result:
longitude *= SignForZero;
Latitude activity (same principle as latitude activity):
if ((int)(LatitudeString.substring(0, 1).toCharArray()[0]) == 90)
{
SetString = "";
SetString += (char)68;
SignForZero = -1;
}
else
{
SetString = LatitudeString.substring(0, 1);
SignForZero = 1;
}
SetString += LatitudeString.substring(1, 2);
RetNum = Base26ToNum(SetString);
if (isFault == true)
return;
RetNum -= 90;
if (RetNum < 0)
Sign = -1;
else
Sign = 1;
if (RetNum < -90 || RetNum > 90)
{
faultMessage = "Latitude string parameter out of limits";
isFault = true;
return;
}
latitude = (float)RetNum;
SetString = LatitudeString.substring(2, 4);
RetNum = Base26ToNum(SetString);
if (isFault == true)
return;
if (RetNum < 0 || RetNum > 99)
{
faultMessage = "Latitude string parameter out of limits";
isFault = true;
return;
}
latitude += ((float)RetNum * (float)0.01) * Sign;
SetString = LatitudeString.substring(4, 6);
RetNum = Base26ToNum(SetString);
if (isFault == true)
return;
if (RetNum < 0 || RetNum > 99)
{
faultMessage = "Latitude string parameter out of limits";
isFault = true;
return;
}
latitude += ((float)RetNum * (float)0.0001) * Sign;
latitude *= SignForZero;
}
Handle an exception if there is...
catch (Exception e)
{
faultMessage = "string parameters illegal";
isFault = true;
return;
}
}
Convert Base26 to number function:
private int Base26ToNum(String SetString) {
int Multiply;
int Add;
int RetNum;
try
{
Get the multiply part:
Multiply = (SetString.substring(0, 1).toCharArray()[0]) - 65;
Get the add part:
Add = (SetString.substring(1, 2).toCharArray()[0]) - 65;
the result from base26:
RetNum = Multiply * 26 + Add;
return RetNum;
}
catch (Exception e)
{
faultMessage = "Base26ToNum Fault";
isFault = true;
return 0;
}
Points of Interest
I used Eclipse for this. Actually, this is my first project in Java. I have a lot of knowledge in C# and object oriented. converting to Java is quite easy.
History
There is an ANSI C and JavaScript version of this code also. I published them both here.