65.9K
CodeProject is changing. Read more.
Home

Java Implementation of the Base26GPS Standard

starIconstarIconstarIconstarIconemptyStarIcon

4.00/5 (1 vote)

Jul 21, 2013

CPOL

4 min read

viewsIcon

12951

This tip describes the Java implementation of Base26GPS.

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:

  1. The first three letters are "GPS", next six letters represent Longitude and last six letters represent Latitude. All together fifteen letters.
  2. 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
  3. 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.
  4. 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.
  5. 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.
  6. 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 { 
 /* ====================================================================
  * Class Name : LocToBase26GPS
  * Class Activity : Convert Location to Base26GPS
  =====================================================================*/
 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) {
  /* ====================================================================== 
  * public function
  * function name : LocToBase26GPSTranslate                                  
  * function activity : convert Longitude and Latitude parameter to string 
  *                    according to Base26GPS standard
  * input parameters : float Longitude - the Longitude to be translated
  *                    float Latitude - the Latitude to be translated 
  *  ======================================================================= */
   
  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) {
  /* ====================================================================== 
  * private function
  * function name : LongitudeToBase26GPS                                  
  * function activity : convert Longitude parameter to string 
  *                    according to Base26GPS standard
  * input parameters : float Longitude - the Longitude to be translated                      
  *  ======================================================================= */
  
     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)  {
/* ====================================================================== 
* private function
* function name : LatitudeToBase26GPS                                  
* function activity : convert Latitude parameter to string 
*                    according to Base26GPS standard
* input parameters : float Latitude - the Longitude to be translated
*  ======================================================================= */
   
     float TempFloat;
     double FractPart;
     double TempFractPart;
     double IntPart;
     int Multiply;
     int Add;
     int Sign;
     String ReturnString = "";
     // check the limits of the longitude
     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;
     }
     // get the integral part
     IntPart = ((double)Math.floor(Math.abs(latitude))) * Sign;
     // get the fract part
     FractPart = Math.abs((double)latitude - IntPart) * 10000;
     // get the base26 multiply part of the 
     // integral part. the start is from -180
     TempFloat = (float)((((int)(IntPart) + 90) / 26));
     Multiply = (int)TempFloat + 65;         
     // if the Latitude is between -0.9999 to -0.0001 use the letter Z
     if ((int)latitude == 0 && Sign == -1)
         Multiply = 90;
     // add the result to the string
     ReturnString += (char)(Multiply);
     // get the base26 add part of the integral part.
     TempFloat = (float)((((((IntPart) + 90) / 26) - 
     (int)(((IntPart) + 90) / 26)) * 26) + 0.1);
     Add = (int)(TempFloat) + 65;
     // add the result to the string
     ReturnString += (char)(Add);
     // get the base26 multiply part of the first couple of fract part.
     TempFractPart = FractPart / 100;
     TempFloat = (float)(((int)TempFractPart / 26));
     Multiply = (int)TempFloat + 65;
     ReturnString += (char)(Multiply);
     // get the base26 add part of the first couple of fract part.
     TempFloat = (float)((((((TempFractPart)) / 26) - 
     (int)(((TempFractPart)) / 26)) * 26));
     Add = (int)TempFloat + 65;
     // add the result to the string
     ReturnString += (char)(Add);         
     // get the base26 multiply part of the first couple of 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 of 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;     
}

Here is the code for the Base26GPSToLoc class:

public class Base26GPSToLoc {
 /* ====================================================================
  * Class Name : Base26GPSToLoc
  * Class Activity : Convert Location to Base26GPS
  =====================================================================*/
    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)   {
 /* ====================================================================== 
* public function
* function name : Base26GPSToLocTranslate                                  
* function activity : convert Base26GPS String to Longitude and Latitude
*                     parameters according to Base26GPS standard
* input parameters : String Base26GPSString - the String to be translated                      
*  ======================================================================= */
 
    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
{
    // get the multiply letter of the integral part
    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):

    // check if the letter Z is in the integral part        
    // if so it means there is a negative zero
    if ((int)(LatitudeString.substring(0, 1).toCharArray()[0]) == 90)
    {
        SetString = "";
        SetString += (char)68;
        SignForZero = -1;
    }
    else
    {
    // get the multiply letter of the integral part
     SetString = LatitudeString.substring(0, 1);
        SignForZero = 1;
    }
    // get the add letter of the integral part
    SetString += LatitudeString.substring(1, 2);
    // convert to number from base26
    RetNum = Base26ToNum(SetString);
    if (isFault == true)
        return;
    
    // the latitude integral part starts from -180
    RetNum -= 90;
    if (RetNum < 0)
        Sign = -1;
    else
        Sign = 1;
    // check the outcome limits
    if (RetNum < -90 || RetNum > 90)
    {
        faultMessage = "Latitude string parameter out of limits";
        isFault = true;
        return;
    }
            
    // add the result to latitude
    latitude = (float)RetNum;
    //get the two letters of the first couple of the fract part
    SetString = LatitudeString.substring(2, 4);            
    RetNum = Base26ToNum(SetString);
    if (isFault == true)
        return;            // check the outcome limits
    if (RetNum < 0 || RetNum > 99)
    {
        faultMessage = "Latitude string parameter out of limits";
        isFault = true;
        return;
    }
    // add the result to latitude
    latitude += ((float)RetNum * (float)0.01) * Sign;
    //get the two letters of the second couple of the fract part
    SetString = LatitudeString.substring(4, 6);            
    RetNum = Base26ToNum(SetString);
    if (isFault == true)
        return;            // check the outcome limits
    if (RetNum < 0 || RetNum > 99)
    {
        faultMessage = "Latitude string parameter out of limits";
        isFault = true;
        return;
    }
    // add the result to longitude
    latitude += ((float)RetNum * (float)0.0001) * Sign;
    // if negative zero then add minus to the result
    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)    {
     /* ====================================================================== 
  * private function
  * function name : Base26ToNum                                  
  * function activity : convert two chars string to Base26 
  *                    according to Base26GPS standard
  * input parameters :String SetString - the String to be translated
  * output parameters : int - the base26 value                      
  *  ======================================================================= */
     
        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.