/*
* Copyright 2012 The Stanford MobiSocial Laboratory
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package mobisocial.musubi.nearby.location;
import java.math.BigInteger;
/**
* This class retrieves the GPS location from shared preferences and outputs coordinates
* that are converted in respect to a hexagonal grid. The output is the coordinates
* concatenated.
**/
public class GridHandler {
// ----- CONSTANTS -----
private static double HALF_MERIDIANAL_CIRCUMFERENCE=2003.93*1000; //half meridianal circumference of the earth in meters
private static double RADIUS=6378100; //radius of the earth in meters
private static final double CONVERSION = 3.2808399; // used to convert between meters and feet.
// Main function (most important) that retreives all three grid types corresponding to inputed grid size
public static long[] getGridCoords(double mlatitude, double mlongitude, int gridsize_feet)
{
long[] retVal = new long[3];
int gridsize_meters = (int) (gridsize_feet / CONVERSION); // All grids conversions are done in meters.
//System.err.println("Location retrieved is : Latitude: " + mlatitude + "\t Longitude: " + mlongitude + "\t Grid size (in feet): " + gridsize_feet);
float xyz[];
int exp=24; //use : 2 ^ 48 + 21
BigInteger leftshift = BigInteger.valueOf(2);
leftshift = leftshift.pow(exp);
long latlon;
// Get all three grid types --- remember there are three grids that are overlapping that we need to check against.
xyz = getXYZ(mlatitude, mlongitude, gridsize_meters, 0);
latlon = (long)(xyz[0]*1E6);
latlon <<= 24;
latlon |= (long) (xyz[1]*1E6);
retVal[0] = latlon;
xyz = getXYZ(mlatitude, mlongitude, gridsize_meters, 1);
latlon = (long)(xyz[0]*1E6);
latlon <<= 24;
latlon |= (long) (xyz[1]*1E6);
retVal[1] = latlon;
xyz = getXYZ(mlatitude, mlongitude, gridsize_meters, 2);
latlon = (long)(xyz[0]*1E6);
latlon <<= 24;
latlon |= (long) (xyz[1]*1E6);
retVal[2] = latlon;
return retVal;
}
private static float[] getXYZ(double x, double y, int gridsize, int gridType){
//Support for 3 grid types
float sqrt3 = (float) Math.sqrt(3);
float step = gridsize;
float iStep = step;
float jStep = (float)step*sqrt3;
double stripHeightPerDeg = HALF_MERIDIANAL_CIRCUMFERENCE/180.0;
double roundoff_x=(int)Math.abs(x)+ 0.5;
double stripWidthPerDeg = (2*Math.PI*RADIUS*Math.cos(roundoff_x))/360.0;
//System.err.println("x : " + x);
double xDist = x % 1.0;
double xMod = x - xDist;
//System.err.println("xDist : " + xDist);
//System.err.println("stripHeightPerDeg : " + stripHeightPerDeg);
xDist *= stripHeightPerDeg;
//System.err.println("xDist : " + xDist);
//System.err.println("y : " + y);
y += 180;
//System.err.println("y : " + y);
//System.err.println("stripWidthPerDeg : " + stripWidthPerDeg);
double yDist = y * stripWidthPerDeg;
//System.err.println("yDist : " + yDist);
switch(gridType){
case 0:
break;
case 1:
xDist -= 0.5*jStep;
yDist -= 0.5*iStep;
break;
case 2:
//x -= 0.5*jStep;
yDist -= iStep;
break;
}
float[] res = hexagonMap((float)xDist, (float)yDist, gridsize);
switch(gridType){
case 0:
break;
case 1:
res[0] += 0.5*jStep;
res[1] += 0.5*iStep;
break;
case 2:
//x -= 0.5*jStep;
res[1] += iStep;
break;
}
//System.err.println("res : " + res[0] + "," + res[1]);
res[0]/=stripHeightPerDeg;
res[0] += xMod;
res[1] = (float) (res[1]/stripWidthPerDeg);
//System.err.println("lat lon : " + res[0] + "," + res[1]);
//return xyz;
return res;
}
static float[] hexagonMap(float touchX, float touchY, int step){
float sqrt3 = (float) Math.sqrt(3);
//int step = 100;
float iStep = step*3;
float jStep = (float)step*sqrt3;
boolean isTouched = true;
float res[] = new float[2];
if(isTouched){
float yIndex = (touchY % iStep)/iStep;
//System.err.println("touchY : " + touchY +" yIndex : " + yIndex);
//Simple case
if(yIndex <= 0.33 || (yIndex > 0.5 && yIndex < 0.83)){
float lineBlock = touchY / iStep;
//first row
if(yIndex < 0.5){
float xIndex = touchX / jStep;
float hexX = (float)((int)xIndex) * jStep;
float hexY = (float)((int)lineBlock) * iStep;
//drawHexagon(hexX, hexY, step, canvas, true);
res[0] = hexX; res[1] = hexY;
}else //Second row
{
float xIndex = (touchX - (jStep/2)) / jStep;
float hexX = (float)(((int)xIndex)+0.5) * jStep;
float hexY = (float)(((int)lineBlock)+0.5 ) * iStep;
//drawHexagon(hexX, hexY, step, canvas, true);
res[0] = hexX; res[1] = hexY;
}
}else{
if(yIndex < 0.5){
float yNum = touchY / iStep;
float xNum = touchX / jStep;
float xAdder = (float)((int)xNum);
float yAdder = (float)((int)yNum);
float x1 = (float) (xAdder + 0.5);
float y1 = (float) (yAdder + 0.165);
float dist1 = getDist(x1, y1, xNum, yNum);
float x2 = (float) (xAdder);
float y2 = (float) (yAdder + 0.665);
float dist2 = getDist(x2, y2, xNum, yNum);
float x3 = (float) (xAdder + 1);
float y3 = (float) (yAdder + 0.665);
float dist3 = getDist(x3, y3, xNum, yNum);
//System.err.println("xNum, yNum " + xNum + "," + yNum);
//System.err.println("xAddr, yAddr " + xAdder + "," + yAdder);
//System.err.println("x1, y1, dist1 " + x1 + "," + y1 + "," + dist1);
//System.err.println("x2, y2, dist2 " + x2 + "," + y2 + "," + dist2);
//System.err.println("x3, y3, dist3 " + x3 + "," + y3 + "," + dist3);
if(dist1 < dist2){
if(dist1 < dist3){
//drawHexagon((x1-0.5f)*jStep, (y1-0.165f)*iStep, step, canvas, true);
res[0] = (x1-0.5f)*jStep; res[1] = (y1-0.165f)*iStep;
}
else{
//drawHexagon((x3-0.5f)*jStep, (y3-0.165f)*iStep, step, canvas, true);
res[0] = (x3-0.5f)*jStep; res[1] = (y3-0.165f)*iStep;
}
}else{
if(dist2 < dist3){
//drawHexagon((x2-0.5f)*jStep, (y2-0.165f)*iStep, step, canvas, true);
res[0] = (x2-0.5f)*jStep; res[1] = (y2-0.165f)*iStep;
}else{
//drawHexagon((x3-0.5f)*jStep, (y3-0.165f)*iStep, step, canvas, true);
res[0] = (x3-0.5f)*jStep; res[1] = (y3-0.165f)*iStep;
}
}
}else{
float yNum = touchY / iStep;
float xNum = touchX / jStep;
float xAdder = (float)((int)xNum);
float yAdder = (float)((int)yNum);
float x1 = (float) (xAdder + 0.5);
float y1 = (float) (yAdder + 1.165);
float dist1 = getDist(x1, y1, xNum, yNum);
float x2 = (float) (xAdder);
float y2 = (float) (yAdder + 0.665);
float dist2 = getDist(x2, y2, xNum, yNum);
float x3 = (float) (xAdder + 1);
float y3 = (float) (yAdder + 0.665);
float dist3 = getDist(x3, y3, xNum, yNum);
//System.err.println("xNum, yNum " + xNum + "," + yNum);
//System.err.println("xAddr, yAddr " + xAdder + "," + yAdder);
//System.err.println("x1, y1, dist1 " + x1 + "," + y1 + "," + dist1);
//System.err.println("x2, y2, dist2 " + x2 + "," + y2 + "," + dist2);
//System.err.println("x3, y3, dist3 " + x3 + "," + y3 + "," + dist3);
if(dist1 < dist2){
if(dist1 < dist3){
//drawHexagon((x1-0.5f)*jStep, (y1-0.165f)*iStep, step, canvas, true);
res[0] = (x1-0.5f)*jStep; res[1] = (y1-0.165f)*iStep;
}
else{
//drawHexagon((x3-0.5f)*jStep, (y3-0.165f)*iStep, step, canvas, true);
res[0] = (x3-0.5f)*jStep; res[1] = (y3-0.165f)*iStep;
}
}else{
if(dist2 < dist3){
//drawHexagon((x2-0.5f)*jStep, (y2-0.165f)*iStep, step, canvas, true);
res[0] = (x2-0.5f)*jStep; res[1] = (y2-0.165f)*iStep;
}else{
//drawHexagon((x3-0.5f)*jStep, (y3-0.165f)*iStep, step, canvas, true);
res[0] = (x3-0.5f)*jStep; res[1] = (y3-0.165f)*iStep;
}
}
}
}
}
return res;
}
static float getDist(float x1, float y1, float x2, float y2){
return (float) Math.sqrt((x1-x2)*(x1-x2)+ (y1-y2)*(y1-y2));
}
}