My Onionmap Patent
One of my previous jobs was at Onionmap as the Director of Engineering. Titles mean crap. I don’t even know what it means to be a “director”. A more accurate job title would have been “systems architect”… but whatever.
Onionmap was actually pretty cool. They provided interactive maps of major cities (33 to be exact). Unlike google maps, they were 3 dimensional visual/artistic renderings representing the city and its major landmarks. In other words, they’re tourist maps. The maps are skewed, exaggerated while landmarks are enlarged and unsightly objects such as parking lots are non-existant.

Prior to my arrival, Onionmap hired many different engineers. Besides talking a big game at meetings, they provided no real work (sort of like politicians). Meeting after meeting, they would sweet-talk everyone else into confidence. At the end of the day, they did absolutely nothing. Another thing these previous “engineers” had in common was that they all believed that it was impossible to geocode the skewed maps. In other words, these maps could never be used with GPS data nor pinpoint exact addresses.
When I joined the Onionmap team, I was obsessed with geocoding these maps.

A couple months into it, I’ve tested out several different theories… Pulled out my old trigonometry books… Tried all sorts of weird things with angle measurements, etc. They weren’t working. I cleared my head and tried to think simple. I truly believe true engineering is about simplicity. I realized I was onto something with y-intercepts. Yes… going way back in Math. Then I got it. Before the 3rd month of my employment, I had figured it out and wrote the engine. I presented it to the company and they asked me to do a write-up immediately so they can file it for patent. Patent? Okay.
Now I’m not a big fan of patent laws and frivolous lawsuits. On top of that, I’m not even sure of that fate of onionmap. Shame. I don’t want my algorithm/code to go to waste. At least I can share it with you here on my blog:
You can download it here.
You’ll notice the inventors are listed as me, Jonathan Lee (my cool project manager), and a guy named Young Kim. Mind you, Young Kim is a douchebag that lives in Korea that did absolutely nothing to contribute to this. He’s a self proclaimed “CTO”, but he has absolutely NO knowledge of anything remotely technical. Because of this guy, I wasted MUCH time building onionmap versions 1,2,3,4,5,6,7. No joke. Two years of working at Onionmap, I built 7 different versions of the site and NONE of it was released. That’s how you demoralize your engineer. Just saying. Anyways, here is the write-up submitted for patent.
Onionmap PatentsPatent #1 Translation OSAT-Geocode:
Inventor: Young Kim, Eddie Kim, Jonathan LeeBusiness concept:
Background:
Onionmap Spatial Analysis Technology (OSAT) is a proprietary process to create the beautiful and easy 3D building and map. OSAT is best to be understood as a piece of outstanding art work. Anyone can draw a building and a landscape, but depending on the ability of each artist, each drawing gives different human reactions. OSAT is not patented but it is protected under Onionmap trade mark and copy right.OSAT is not scaled because OSAT wants to achieve the beautiful representation of a 3D building and the landscape. The proprietary process has a complex making process in order to achieve the beautiful and easy visual representation of the 3D building and the map. Although it is not scale and there is no consistent way of producing each 3D building and the map, there is a need to translate a Geocode to OSAT code so a location in the real world can be identified on the OSAT visual online interactive map.
Because each OSAT city map is unique, the translation from Geocode to each OSAT map is also unique. However, this unique process is consistent and replicable and accurate. And this unique process of translation is the core component to link to all the business functions of Onionmap products that based on OSAT map. Hence Onionmap intends to patent this process.
Scientific Process of Translation from Geocode to OSAT code
To initialize our transcoding engine, we must follow these steps:First, we take our map and find the total width and total height.
Next we plot the longitude and latitude pairs for each corner of the map. (You can use Google maps to find this data)
Once we plot these points, we need to find the exact north/south slope (simply find a street or 2 points on the map that are perfectly parallel to the standard longitude lines)
Using this information, calculate the slope. (Rise over run)
Then we find the exact east/west slope on the map. (Simply find a street or 2 points on the map that are perfectly parallel to the standard latitude lines)
Using this information, calculate the slope. (Rise over run)
m = (y2 - y1) / (x2 - x1)
How the transcoding engine works:
Given the longitude x, we find 2 corners of the map where x lies between the longitude counterpart of its Geocode location. (If x does not lie between any 2 corners' longitude values, then the target location is outside of our map)
We then find where x lies in relevance to the longitude values of these 2 corners.
ratio = (corner1 - x) / (corner2 - corner1)
Using the slope north and south slope, we find the y-intercept of each of these longitude lines using the following equation in slope intercept form:
y = mx + b (x and y are onionmap coordinates)
Once we solve for b for each corner (corner1_b, corner2_b), we apply the ratio to our y-intercepts and solve for target_b.
ratio = (corner1_b - target_b) / (corner2_b - corner1_b)
Once we have solved for target_b we plug target_b and the north and south slope m into our equation:
y = mx + b
and we have obtained the equation for our first line longitude_line.
Next we repeat this same process to find our latitude_line by using our east and west slope, and the latitude counterparts of our geocode data.
Once we have solved for latitude_line and longitude_line, we find the intersection of these 2 lines by solving for y and x.First we solve for x:
(m1 * x) + b1 = (m1 * x) + b2
Then we solve for y:
y = m1 * x + b1 OR
y = m2 * x + b2We now have our (x,y) pair.
Increase accuracy: so far we take 4 points, corner points, for the translation. If we take 4 more additional points, we can increase accuracy.
The translation for OSAT code to Geocode is a reverse process of the above process.
How the transcoding engine works:
Given the longitude x, we find 2 corners of the map where x lies between the longitude counterpart of its Geocode location. (If x does not lie between any 2 corners' longitude values, then the target location is outside of our map)
We then find where x lies in relevance to the longitude values of these 2 corners.
ratio = (corner1 - x) / (corner2 - corner1)
Using the slope north and south slope, we find the y-intercept of each of these longitude lines using the following equation in slope intercept form:
y = mx + b (x and y are onionmap coordinates)
Once we solve for b for each corner (corner1_b, corner2_b), we apply the ratio to our y-intercepts and solve for target_b.
ratio = (corner1_b - target_b) / (corner2_b - corner1_b)
Once we have solved for target_b we plug target_b and the north and south slope m into our equation:
y = mx + b
and we have obtained the equation for our first line longitude_line.
Next we repeat this same process to find our latitude_line by using our east and west slope, and the latitude counterparts of our geocode data.
Once we have solved for latitude_line and longitude_line, we find the intersection of these 2 lines by solving for y and x.First we solve for x:
(m1 * x) + b1 = (m1 * x) + b2
Then we solve for y:
y = m1 * x + b1 OR
y = m2 * x + b2We now have our (x,y) pair.
Increase accuracy: so far we take 4 points, corner points, for the translation. If we take 4 more additional points, we can increase accuracy.
The translation for OSAT code to Geocode is a reverse process of the above process.
Technology Product:
The following are the initial ‘working’ product in the form of computer software code. Just like every other software, this product will evolve with the time.Excerpt of Geocode.php (class)
<?php
/*
Geocode classUsage:
if(!is_object($Geocode)) $geocode = new Geocode($CITY);
*///Requirements:
class Geocode {
// DEBUG MODE
private $debug = 0;// SELECTED CITY
private $city;// COORDINATES FOR EACH CORNER OF THE MAP (OM view)
private $om_ul_long;
private $om_ur_long;
private $om_ll_long;
private $om_lr_long;
private $om_ul_lat;
private $om_ur_lat;
private $om_ll_lat;
private $om_lr_lat;private $x_min;
private $x_max;
private $y_min;
private $y_max;// LONGITUDE AND LATITUDE SLOPE
private $slope_long;
private $slope_lat;// GEOCODER BASE URL (REST)
private $geocoder_api_rest = "http://rpc.geocoder.us/service/csv?address=";
private $yahoo_geocoder_api_rest = "http://local.yahooapis.com/MapsService/V1/geocode?appid=WCZ107vV34Ed.N5OCPbHpRbalLm1nezhYnzoy597AvofLaVUQvItD3AQNNUGZQw-&location=";// Constructor
public function __construct(){
$city = "las vegas";
$this->city = $city;
switch($city){
case "las vegas":
$this->om_ul_long = -115.22015;
$this->om_ul_lat = 36.15413611111111;
$this->om_ur_long = -115.13938055555556;
$this->om_ur_lat = 36.187127777777775;
$this->om_ll_long = -115.17540277777778;
$this->om_ll_lat = 36.084944444444446;
$this->om_lr_long = -115.10328055555556;
$this->om_lr_lat = 36.11882222222222;$this->x_min = 0;
$this->x_max = 10565;
$this->y_min = 0;
$this->y_max = 4700;$this->slope_lat = (4029 - 3609)/(-2859 + 1000);
$this->slope_long = (4299 - 3059)/(-1372 + 2888);break;
default:
}
}public function geocode2omcode($latitude,$longitude){
if($this->debug) echo "<br>Geocode::geocode2omcode<br>";
if($this->debug) echo "<br>".$latitude."<br>".$longitude;
if($longitude > $this->om_ul_long && $longitude < $this->om_lr_long && $latitude > $this->om_ll_lat && $latitude < $this->om_ur_lat){ // check to see if it's within the area (natural view)// Convert latitude to om code
if($latitude < $this->om_lr_lat){
$ratio_lat = ($latitude - $this->om_ll_lat)/($this->om_lr_lat - $this->om_ll_lat);
// y = mx + b
$b_lat_1 = (-1)*$this->y_max - ($this->slope_lat * $this->x_min);
$b_lat_2 = (-1)*$this->y_max - ($this->slope_lat * $this->x_max);
$b_lat = $b_lat_1 + (($b_lat_2 - $b_lat_1) * $ratio_lat); // ($b_lat - $b_lat_1)/($b_lat_2 - $b_lat_1) = $ratio_lat
// y = ($this->slope_lat * x) + $b_lat
if($this->debug) echo "<br>ll - lr<br>b1,b2: ".$b_lat_1.",".$b_lat_2."<br>ratio: ".$ratio_lat."<br>slope: ".$this->slope_lat."<br>b: ".$b_lat;
}
elseif($latitude < $this->om_ul_lat){
$ratio_lat = ($latitude - $this->om_lr_lat)/($this->om_ul_lat - $this->om_lr_lat);
// y = mx + b
$b_lat_1 = (-1)*$this->y_max - ($this->slope_lat * $this->x_max);
$b_lat_2 = (-1)*$this->y_min - ($this->slope_lat * $this->x_min);
$b_lat = $b_lat_1 + (($b_lat_2 - $b_lat_1) * $ratio_lat); // ($b_lat - $b_lat_1)/($b_lat_2 - $b_lat_1) = $ratio_lat
// y = ($this->slope_lat * x) + $b_lat
IF($THIS->debug) echo "<br>lr - ul<br>b1,b2: ".$b_lat_1.",".$b_lat_2."<br>ratio: ".$ratio_lat."<br>slope: ".$this->slope_lat."<br>b: ".$b_lat;
}
else{
$ratio_lat = ($latitude - $this->om_ul_lat)/($this->om_ur_lat - $this->om_ul_lat);
// y = mx + b
$b_lat_1 = (-1)*$this->y_min - ($this->slope_lat * $this->x_min);
$b_lat_2 = (-1)*$this->y_min - ($this->slope_lat * $this->x_max);
$b_lat = $b_lat_1 + (($b_lat_2 - $b_lat_1) * $ratio_lat); // ($b_lat - $b_lat_1)/($b_lat_2 - $b_lat_1) = $ratio_lat
// y = ($this->slope_lat * x) + $b_lat
if($this->debug) echo "<br>ul - ur<br>b1,b2: ".$b_lat_1.",".$b_lat_2."<br>ratio: ".$ratio_lat."<br>slope: ".$this->slope_lat."<br>b: ".$b_lat;
}// Convert longitude to om code
if($longitude < $this->om_ll_long){
$ratio_long = ($longitude - $this->om_ul_long)/($this->om_ll_long - $this->om_ul_long);
// y = mx + b
$b_long_1 = (-1)*$this->y_min - ($this->slope_long * $this->x_min);
$b_long_2 = (-1)*$this->y_max - ($this->slope_long * $this->x_min);
$b_long = (-1) * ($b_long_1 + (($b_long_1 - $b_long_2) * $ratio_long)); // ($b_long - $b_long_1)/($b_long_2 - $b_long_1) = $ratio_long
// y = ($this->slope_long * x) + $b_long
if($this->debug) echo "<br>ul - ll<br>b1,b2: ".$b_long_1.",".$b_long_2."<br>ratio: ".$ratio_long."<br>slope: ".$this->slope_long."<br>b: ".$b_long;
}
elseif($longitude < $this->om_ur_long){
$ratio_long = ($longitude - $this->om_ll_long)/($this->om_ur_long - $this->om_ll_long);
// y = mx + b
$b_long_1 = (-1)*$this->y_max - ($this->slope_long * $this->x_min);
$b_long_2 = (-1)*$this->y_min - ($this->slope_long * $this->x_max);
$b_long = $b_long_1 + (($b_long_2 - $b_long_1) * $ratio_long); // ($b_long - $b_long_1)/($b_long_2 - $b_long_1) = $ratio_long
// y = ($this->slope_long * x) + $b_long
if($this->debug) echo "<br>ll - ur<br>b1,b2: ".$b_long_1.",".$b_long_2."<br>ratio: ".$ratio_long."<br>slope: ".$this->slope_long."<br>b: ".$b_long;
}
else{
$ratio_long = ($longitude - $this->om_ur_long)/($this->om_lr_long - $this->om_ur_long);
// y = mx + b
$b_long_1 = (-1)*$this->y_min - ($this->slope_long * $this->x_max);
$b_long_2 = (-1)*$this->y_max - ($this->slope_long * $this->x_max);
$b_long = $b_long_1 + (($b_long_2 - $b_long_1) * $ratio_long); // ($b_long - $b_long_1)/($b_long_2 - $b_long_1) = $ratio_long
// y = ($this->slope_long * x) + $b_long
if($this->debug) echo "<br>ur - lr<br>b1,b2: ".$b_long_1.",".$b_long_2."<br>ratio: ".$ratio_long."<br>slope: ".$this->slope_long."<br>b: ".$b_long;
}// Find intersection of the 2 lines
$x = ($b_long - $b_lat) / ($this->slope_lat - $this->slope_long); // (this->slope_long * x) + $b_long = ($this->slope_lat * x) + $b_lat
$y = (-1)*(($this->slope_lat * $x) + $b_lat);
if($this->debug) echo "<br>".$x.",".$y;
$omcode[0] = $x;
$omcode[1] = $y;
return $omcode;
}
else{
// outside of map area
}
}
?>Advertisement