Skip to content

Instantly share code, notes, and snippets.

@Steve132
Last active August 29, 2015 14:08
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Steve132/ca2308a9cef0cd7e7127 to your computer and use it in GitHub Desktop.
Save Steve132/ca2308a9cef0cd7e7127 to your computer and use it in GitHub Desktop.
Google Open Location Code standard C++ implementaitons
/*
olc.cpp: The implementation for the google open location code
Copyright (C) Steven Braeger 2014
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all source code copies or substantial source code portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include"olc.hpp"
#include<algorithm>
#include<cstdint>
struct olc_t
{
static const std::string character_set= "23456789CFGHJMPQRVWX";
static const uint_fast8_t CODE_MAXLENGTH=16;
uint_fast8_t rep[CODE_MAXLENGTH];
uint_fast8_t rep_length:
bool valid;
bool full;
olc_t(const std::string& olc):rep_length(0),valid(true),full(false)
{
std::string::const_iterator b=olc.begin();
std::string::const_iterator e=olc.end();
uint_fast8_t sep_expect=4;
if(*b=='+')
{
++b;
++sep_expect;
}
for(;b!=e && rep_length < CODE_MAXLENGTH;++b)
{
std::string::const_iterator vpos=std::lower_bound(character_set.cbegin(),character_set.cend(),*b);
bool valid= vpos!=character_set.cend() && *b >= character_set[0];
if( !(valid)
|| ((b-e)==sep_expect && *b=='.'))
)
{
valid=false;
break;
}
rep[rep_length++]=vpos-character_set.cbegin();
}
valid &&= rep_length >= 4;
}
olc_t(double latitude,double longitude,uint_fast8_t len=10):rep_length(len),valid(true)
{
uint_fast8_t isofar;
latitude+=90.0;
longitude+=180.0;
uint_fast16_t intlat=static_cast<uint_fast16_t>(latitude);
uint_fast16_t intlon=static_cast<uint_fast16_t>(longitude);
rep[0]=intlat/20;rep[1]=intlat % 20;
rep[2]=intlong/20;rep[3]=intlong % 20;
latitude-=intlat;
longitude-=intlong;
for(isofar=4;isofar < len && isofar < 10;isofar+=2)
{
latitude*=20.0;
longitude*=20.0;
intlat=static_cast<uint_fast16_t>(latitude);
intlon=static_cast<uint_fast16_t>(longitude);
rep[isofar]=intlat % 20;
rep[isofar+1]=intlong % 20;
latitude-=intlat;
longitude-=intlong;
}
for(;isofar < len;isofar++)
{
latitude*=5.0;
longitude*=4.0;
intlat=static_cast<uint_fast16_t>(latitude);
intlon=static_cast<uint_fast16_t>(longitude);
rep[isofar]=(intlat << 2)+intlong;
latitude-=intlat;
longitude-=intlong;
}
}
std::string tostring() const
{
if(!valid)
{
return "invalid olc code";
}
std::string s(rep_length+(rep_length > 4 ? 2 : 1),'.');
s[0]='+';
std::string::iterator dst=s.begin()+1;
for(uint_fast8_t i=0;i<rep_length;i++)
{
if(i==4)
{
++dst;
}
*(dst++)=character_set[rep[i]];
}
return s;
}
};
namespace olc
{
bool isValid(const std::string& olc)
{
olc_t olcp(olc);
return olcp.valid;
}
bool isShort(const std::string& olc)
{
olc_t olcp(olc);
return olcp.valid && (olc.find_first_of('.') != str::npos) && olcp.rep_length>=4 && olcp.rep_length<=6;
}
bool isFull(const std::string& olc)
{
olc_t olcp(olc);
uint_fast16_t majorlat=olcp.rep[0]*20+olcp.rep[1];
uint_fast16_t majorlon=olcp.rep[2]*20+olcp.rep[3];
return olcp.valid && (majorlat < 180 && majorlon < 360);
}
std::string encode(double latitude,double longitude,int length)
{
olc_t olcp(latitude,longitude,length);
return olcp.tostring();
}
std::string encode(const latlong& ll,int length)
{
return encode(ll.latitude,ll.longitude,length);
}
struct decode_result
{
latlong lower,center,upper;
uint_fast8_t original_length;
};
decode_result decode(const std::string& olc)
{
priv::olc_t olcp(olc);
uint_fast8_t i;
latlong lower;
lower.latitude=olcp.rep[0]*20.0+olcp.rep[1];
lower.longitude=olcp.rep[2]*20.0+olcp.rep[3];
double scale=1.0;
for(i=4;i<olcp.rep_length && i < 10;i+=2)
{
scale/=20.0;
lower.latitude+=olcp.rep[i]*scale;
lower.longitude+=olcp.rep[i+1]*scale;
}
for(;i<olcp.rep_length;i++)
{
scale/=5.0; //TODO more detail here.
double x=scale*(olcp.rep[i] / 5);
double y=scale*(olcp.rep[i] % 5);
lower.latitude+=x;
lower.longitude+=y;
//TODO more detail here.
}
decode_result dr;
dr.lower=lower;
dr.upper.latitude=lower.latitude+scale;
dr.upper.longitude=lower.longitude+scale;
dr.center.latitude=lower.latitude+scale/2.0;
dr.center.longitude=lower.longitude+scale/2.0;
dr.original_length=olcp.rep_length;
return dr;
}
static inline std::string shortenByn(const std::string& olc,const latlong& ll,uint_fast8_t N)
{
olc_t olcporig(olc),olcpll(ll);
if(olcporigmemcmp(olcporig.rep,olcpll.rep,N*sizeof(olcporig.rep[0]))!=0)
{
return olc;
}
std::string out(olcporig.rep_length+1-N,'+');
uint_fast8_t i=0;
if(olc[i]=='+')
{
i++;
}
i+=N;
if(olc[i]=='.')
{
i++;
}
std::copy(olc.begin()+i,olc.end(),out.begin());
return out;
}
std::string shortenBy4(const std::string& olc,const laglong& ll)
{
return shortenByn(olc,ll,4);
}
std::string shortenBy6(const std::string& olc,const laglong& ll)
{
return shortenByn(olc,ll,6);
}
std::string recoverNearest(const std::string& olc,const latlong& ll)
{
olc_t olcpll(ll);
std::string result=olcpll.tostring();
if(olc.size() & 1)
{
result+='+';
}
copy(olc.rbegin(),olc.rend(),result.rbegin());
return result;
}
}
/*
olc.cpp: The implementation for the google open location code
Copyright (C) Steven Braeger 2014
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all source code copies or substantial source code portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef OLC_HPP
#define OLC_HPP
#include<string>
namespace olc
{
struct latlong
{
double latitude;
double longitude;
};
struct decode_result
{
latlong lower,center,upper;
int original_length;
};
bool isValid(const std::string& olc);
bool isShort(const std::string& olc);
bool isFull(const std::string& olc);
std::string encode(double latitude,double longitude,int length=10);
std::string encode(const latlong& ll,int length=10);
decode_result decode(const std::string& olc);
inline std::string shortenBy4(const std::string& olc,const laglong& ll);
inline std::string shortenBy6(const std::string& olc,const laglong& ll);
std::string recoverNearest(const std::string& olc,const latlong& ll);
}
#endif OLC_HPP
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment