/* This file is part of ZamiaDroid.
*
* ZamiaDroid is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* ZamiaDroid is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with ZamiaDroid. If not, see <http://www.gnu.org/licenses/>.
*/
package uni.projecte.maps.overlays;
import uni.projecte.maps.MapDrawUtils;
import uni.projecte.maps.UTMDisplay;
import uni.projecte.maps.UTMGrid;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Point;
import android.util.Log;
import android.widget.TextView;
import com.google.android.maps.GeoPoint;
import com.google.android.maps.MapView;
import com.google.android.maps.Overlay;
import edu.ub.bio.biogeolib.CoordConverter;
import edu.ub.bio.biogeolib.CoordinateLatLon;
import edu.ub.bio.biogeolib.CoordinateUTM;
/*
* This class provides us the utmGrid that will allow
* us to connect with the biodiversity data banks
*
*/
public class UTMOverlay extends Overlay {
private MapView mapView;
private TextView utmTv;
private String utmPrec;
public UTMOverlay(MapView mapView,String utmPrec){
this.mapView=mapView;
this.utmPrec=utmPrec;
}
public UTMOverlay(MapView mapView,TextView utmTv,String utmPrec){
this.mapView=mapView;
this.utmTv=utmTv;
this.utmPrec=utmPrec;
}
@Override
public void draw(Canvas canvas, MapView mapView, boolean shadow) {
GeoPoint center=mapView.getMapCenter();
CoordinateUTM utm = CoordConverter.getInstance().toUTM(new CoordinateLatLon(center.getLatitudeE6()/1E6,center.getLongitudeE6()/1E6));
String utmShort=utm.getShortForm();
/* determining if we are at northern hemisphere*/
boolean hemisNorth=center.getLatitudeE6()/1E6>=0;
/* Drawing 10km UTM square */
if(utmPrec.equals("10km")){
CoordinateUTM utmBox = calculateUTMCenter(utm, 10000,hemisNorth);
UTMGrid grid=utmToLatLonBox(utmBox, 10000,hemisNorth);
/* determining if we are on a UTM overlapping zone */
isZoneLimit(utmBox,canvas,mapView,grid,hemisNorth);
drawCalculatedUTMSquare(canvas,grid,false,UTMDisplay.convertUTM(utmShort,"10km",false),Color.WHITE);
}
/* Drawing 1km UTM square */
if(utmPrec.equals("1km") || utmPrec.equals("1m") ){
CoordinateUTM utmBox1x1 = calculateUTMCenter(utm, 1000,hemisNorth);
UTMGrid grid1x1=utmToLatLonBox(utmBox1x1, 1000,hemisNorth);
/* determining if we are on a UTM overlapping zone */
isZoneLimit(utmBox1x1,canvas,mapView,grid1x1,hemisNorth);
drawCalculatedUTMSquare(canvas, grid1x1,true,UTMDisplay.convertUTM(utmShort,"1km",false),Color.RED);
}
/* when square "doesn\'t fits" on screen we draw a cross at the center of the screen"*/
if(mapView.getZoomLevel()>13) MapDrawUtils.drawUTMCross(canvas, center,"",mapView);
/* TextView is updated with UTM */
if(utmTv!=null){
utmTv.setText(UTMDisplay.convertUTM(utmShort,utmPrec,false));
}
}
private boolean isZoneLimit(CoordinateUTM utmBox,Canvas canvas, MapView mapView, UTMGrid grid, boolean hemisNorth) {
int acur=(int) utmBox.getAccuracy();
/* Determining if Right UTM is from another zone */
CoordinateUTM utmR=new CoordinateUTM(hemisNorth,utmBox.getZone(),utmBox.getX()+acur+1,utmBox.getY()+(acur/2),utmBox.getAccuracy());
CoordinateLatLon latLong4=CoordConverter.getInstance().toLatLon(utmR);
CoordinateUTM utmRight=CoordConverter.getInstance().toUTM(latLong4);
/* Determining if Left UTM is from another zone */
CoordinateUTM utmL=new CoordinateUTM(hemisNorth,utmBox.getZone(),utmBox.getX()-1,utmBox.getY()+(acur/2),utmBox.getAccuracy());
CoordinateLatLon latLong5=CoordConverter.getInstance().toLatLon(utmL);
CoordinateUTM utmLeft=CoordConverter.getInstance().toUTM(latLong5);
if(utmBox.getZone()!=utmRight.getZone()){
calculateUTMOverlap(utmBox,canvas,mapView,grid,acur/40,true,acur,hemisNorth);
return true;
}
else if(utmBox.getZone()!=utmLeft.getZone()){
calculateUTMOverlap(utmBox,canvas,mapView,grid,acur/40,false,acur,hemisNorth);
return true;
}
else return false;
}
/*
* We know that the @utmBox is overlapped by another UTM from another zone from the @right {right=false -> left} zone
* We are calculating the overlapped UTM increasing the distance determined by @nextDistance from the original zone
*
*/
private void calculateUTMOverlap(CoordinateUTM utmBox,Canvas canvas, MapView mapView, UTMGrid grid2, int nextDistance,boolean right, int acur,boolean hemisNorth) {
/* Right Square */
CoordinateUTM utmR=new CoordinateUTM(hemisNorth,utmBox.getZone(),utmBox.getX()+nextDistance,utmBox.getY()+(acur/2),utmBox.getAccuracy());
CoordinateLatLon latLong=CoordConverter.getInstance().toLatLon(utmR);
CoordinateUTM utmRight=CoordConverter.getInstance().toUTM(latLong);
/* Left Square */
CoordinateUTM utmL=new CoordinateUTM(hemisNorth,utmBox.getZone(),utmBox.getX()-(nextDistance-acur),utmBox.getY()+(acur/2),utmBox.getAccuracy());
CoordinateLatLon latLong2=CoordConverter.getInstance().toLatLon(utmL);
CoordinateUTM utmLeft=CoordConverter.getInstance().toUTM(latLong2);
if(right){
//still in the same UTM
if(utmBox.getZone()==utmRight.getZone()){
nextDistance=nextDistance+acur/40;
calculateUTMOverlap(utmBox, canvas, mapView, grid2,nextDistance,right,acur,hemisNorth);
}
else{
utmRight=calculateUTMCenter(utmRight, acur,hemisNorth);
UTMGrid grid=utmToLatLonBox(utmRight, acur,hemisNorth);
double distance=distanceBetweenLatLongPoints(grid.upperRight, grid2.upperLeft);
CoordinateUTM topNewModif=new CoordinateUTM(hemisNorth,utmBox.getZone(), (utmBox.getX()+distance*500), utmBox.getY(),utmBox.getAccuracy());
UTMGrid topGrid=utmToLatLonBox(topNewModif, acur,hemisNorth);
//Modifying the bounding box using the intersection in the middle between the overlapping UTM
grid2.upperRight=topGrid.upperLeft;
grid2.lowerRight=topGrid.lowerLeft;
}
}
else {
//still in the same UTM
if(utmBox.getZone()==utmLeft.getZone()){
nextDistance=nextDistance+acur/40;
calculateUTMOverlap(utmBox, canvas, mapView, grid2,nextDistance,right,acur,hemisNorth);
}
else{
utmLeft=calculateUTMCenter(utmLeft, acur,hemisNorth);
UTMGrid grid=utmToLatLonBox(utmLeft, acur,hemisNorth);
double distance=distanceBetweenLatLongPoints(grid.upperLeft, grid2.upperRight);
CoordinateUTM topNewModif=new CoordinateUTM(hemisNorth,utmBox.getZone(), (utmBox.getX()-distance*500), utmBox.getY(),utmBox.getAccuracy());
UTMGrid topGrid=utmToLatLonBox(topNewModif, acur,hemisNorth);
//Modifying the bounding box using the intersection in the middle between the overlapping UTM
grid2.upperLeft=topGrid.upperRight;
grid2.lowerLeft=topGrid.lowerRight;
}
}
}
@SuppressWarnings("unused")
private void drawLine(Canvas canvas, MapView mapView, int color,CoordinateLatLon upperRight, CoordinateLatLon upperLeft, String string) {
Paint mPaint = new Paint();
mPaint.setDither(true);
mPaint.setColor(color);
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setStrokeWidth(4);
GeoPoint gP1 = new GeoPoint((int) (upperRight.getLat()*1E6),(int) (upperRight.getLon()*1E6));
GeoPoint gP2 = new GeoPoint((int)(upperLeft.getLat()*1E6),(int) (upperLeft.getLon()*1E6));
Point p1 = new Point();
Point p2 = new Point();
mapView.getProjection().toPixels(gP1, p1);
mapView.getProjection().toPixels(gP2, p2);
canvas.drawLine(p1.x, p1.y, p2.x, p2.y, mPaint);
canvas.drawLine(p1.x, p1.y+5, p1.x, p1.y-5, mPaint);
mPaint.setStyle(Paint.Style.FILL);
mPaint.setAntiAlias(true);
mPaint.setTextSize(18);
canvas.drawText(string, p1.x, p1.y-4, mPaint);
}
public double distanceBetweenLatLongPoints(CoordinateLatLon x, CoordinateLatLon y){
double lat1=x.getLat();
double lon1=x.getLon();
double lat2=y.getLat();
double lon2=y.getLon();
int R = 6371; // km
double dLat = Math.toRadians(lat2-lat1);
double dLon = Math.toRadians(lon2-lon1);
lat1 = Math.toRadians(lat1);
lat2 = Math.toRadians(lat2);
double a = Math.sin(dLat/2) * Math.sin(dLat/2) +
Math.sin(dLon/2) * Math.sin(dLon/2) * Math.cos(lat1) * Math.cos(lat2);
double c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a));
double d = R * c;
return d;
}
public CoordinateUTM calculateUTMCenter(CoordinateUTM utm, double prec, boolean hemisNorth){
double xMinus=utm.getX()%prec;
double yMinus=utm.getY()%prec;
CoordinateUTM utmBox=new CoordinateUTM(hemisNorth,utm.getZone(),utm.getX()-xMinus,utm.getY()-yMinus,prec);
return utmBox;
}
public float calculateBearing(Point pBefore, Point pAfter) {
float res = -(float) (Math.atan2(pAfter.y - pBefore.y, pAfter.x - pBefore.x) * 180 / 3.1416) + 90.0f;
Log.d("MapView", "Bearing: " + res);
if (res < 0)
return res + 360.0f;
else
return res;
}
private void drawCalculatedUTMSquare(Canvas canvas, UTMGrid box, boolean prec1x1, String label, int color) {
Paint paint=new Paint();
paint.setAntiAlias(true);
paint.setStrokeWidth(4);
paint.setStrokeCap(Paint.Cap.ROUND);
paint.setStyle(Paint.Style.STROKE);
paint.setColor(color);
if(prec1x1) paint.setColor(Color.GREEN);
paint.setAlpha(128);
/*
* UpperLeft --> c******d
* (lat/long) ********
* ********
* b******a <--- LowerRight (lat,long)
*
*/
GeoPoint a=new GeoPoint((int) (box.lowerRight.getLat() * 1E6), (int) (box.lowerRight.getLon() * 1E6));
GeoPoint c=new GeoPoint((int) (box.upperLeft.getLat() * 1E6), (int) (box.upperLeft.getLon() * 1E6));
GeoPoint b=new GeoPoint((int) (box.lowerLeft.getLat() * 1E6), (int) (box.lowerLeft.getLon() * 1E6));
GeoPoint d=new GeoPoint((int) (box.upperRight.getLat() * 1E6), (int) (box.upperRight.getLon() * 1E6));
if(!prec1x1) drawUTMSquare(canvas, a, b, c, d, label, color);
else drawUTMSquare(canvas, a, b, c, d, label, Color.GREEN);
}
public UTMGrid utmToLatLonBox(CoordinateUTM utm, double accuracy, boolean hemisNorth) {
/*
* UpperLeft --> c******d
* (lat/long) ********
* ********
* b******a <--- LowerRight (lat,long)
*
*/
CoordinateUTM utmLR = new CoordinateUTM(hemisNorth,utm.getZone(), utm.getX() + utm.getAccuracy(), utm.getY());
CoordinateUTM utmLL = new CoordinateUTM(hemisNorth,utm.getZone(), utm.getX(), utm.getY());
CoordinateUTM utmUL = new CoordinateUTM(hemisNorth,utm.getZone(), utm.getX(), utm.getY() + accuracy);
CoordinateUTM utmUR = new CoordinateUTM(hemisNorth,utm.getZone(), utm.getX() + utm.getAccuracy(), utm.getY()+ accuracy);
CoordConverter conv=CoordConverter.getInstance();
CoordinateLatLon lowerRight=conv.toLatLon(utmLR);
CoordinateLatLon lowerLeft=conv.toLatLon(utmLL);
CoordinateLatLon upperLeft=conv.toLatLon(utmUL);
CoordinateLatLon upperRight=conv.toLatLon(utmUR);
return new UTMGrid(lowerRight,lowerLeft,upperLeft,upperRight);
}
private void drawUTMSquare(Canvas canvas,GeoPoint a,GeoPoint b, GeoPoint c, GeoPoint d, String utm,int color){
Paint paint=new Paint();
paint.setAntiAlias(true);
paint.setStrokeWidth(4);
paint.setStrokeCap(Paint.Cap.ROUND);
paint.setStyle(Paint.Style.STROKE);
Point aP = new Point();
mapView.getProjection().toPixels(a, aP);
Point bP = new Point();
mapView.getProjection().toPixels(b, bP);
Point cP = new Point();
mapView.getProjection().toPixels(c, cP);
Point dP = new Point();
mapView.getProjection().toPixels(d, dP);
paint.setColor(color);
paint.setAlpha(128);
canvas.drawLine(aP.x, aP.y, bP.x, bP.y, paint);
canvas.drawLine(bP.x, bP.y, cP.x, cP.y, paint);
canvas.drawLine(cP.x, cP.y, dP.x, dP.y, paint);
canvas.drawLine(dP.x, dP.y, aP.x, aP.y, paint);
paint.setStyle(Paint.Style.FILL);
paint.setAntiAlias(true);
paint.setTextSize(18);
canvas.drawText(utm, aP.x +10, aP.y-15, paint);
}
public void setUtmPrec(String utmPrec) {
this.utmPrec = utmPrec;
}
}