Commit 03066bd7 authored by Vytor Calixto's avatar Vytor Calixto 👾

Merge branch 'view' into 'develop'

View



See merge request !4
parents d32eea39 6007cd68
.gradle
.idea/
/local.properties
/.idea/workspace.xml
/.idea/libraries
.DS_Store
/build
*/**/*.properties
*/**/*.idea
*.idea
*/**/*.iml
*.iml
app/gradle/
app/gradlew/
gradlew*
gradle/
......@@ -2,11 +2,16 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="ufpr.inf.pet.geoloc" >
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme">
android:theme="@style/AppTheme" >
<activity
android:name=".MainActivity"
android:label="@string/app_name" >
......@@ -17,8 +22,5 @@
</intent-filter>
</activity>
</application>
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
</manifest>
This diff is collapsed.
package ufpr.inf.pet.geoloc;
import android.app.DialogFragment;
import android.app.FragmentManager;
import android.content.Intent;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
/**
* Created by pet on 23/09/15.
*/
public class GeolocLocationListener implements LocationListener {
private boolean upateMapView = true;
private boolean stopped;
private MapView mapView;
private String provider;
private boolean providerEnabled = false;
public GeolocLocationListener(MapView mapView) {
this.mapView = mapView;
}
public void stop() {
stopped = true;
mapView = null;
}
@Override
public void onLocationChanged(Location location) {
if(!stopped && location != null) {
this.mapView.setGpsLocation(location.getLatitude(), location.getLongitude(), location.getAltitude(), location.getAccuracy());
this.mapView.postInvalidate();
}
}
@Override
public void onStatusChanged(String provider, int status, Bundle extras) {
}
@Override
public void onProviderEnabled(String provider) {
}
@Override
public void onProviderDisabled(String provider) {
}
}
package ufpr.inf.pet.geoloc;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Point;
import android.graphics.Rect;
import android.location.Location;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import java.util.Collection;
/**
* Created by pet on 23/09/15.
*/
public class MapView extends View {
private Context context;
private int viewWidth;
private int viewHeight;
private TilesProvider tilesProvider;
private TilesManager tilesManager;
private Paint fontPaint;
private Paint circlePaint = new Paint();
private Paint bitmapPaint = new Paint();
private PointD seekLocation = new PointD(0,0);
private Location gpsLocation = null;
private boolean autoFollow;
private PointD lastTouchPos = new PointD(-1, -1);
public MapView(Context context, int viewWidth, int viewHeight, TilesProvider tilesProvider) {
super(context);
this.context = context;
this.tilesProvider = tilesProvider;
this.viewHeight = viewHeight;
this.viewWidth = viewWidth;
Log.d(MainActivity.TAG, "width: " + viewWidth + " height: " + viewHeight);
tilesManager = new TilesManager(256, viewWidth, viewHeight);
initPaints();
fetchTiles();
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)
{
// Define a largura e altura que foram passadas no contrutor como a dimensão da view
setMeasuredDimension(viewWidth, viewHeight);
}
private void initPaints() {
fontPaint = new Paint();
fontPaint.setColor(Color.DKGRAY);
fontPaint.setShadowLayer(1, 1, 1, Color.BLACK);
fontPaint.setTextSize(20);
circlePaint.setARGB(80, 112, 33, 255);
circlePaint.setAntiAlias(true);
}
private void fetchTiles() {
tilesManager.setLocation(seekLocation);
Rect regiaoVisivel = tilesManager.getAreaVisivel();
Rect rect = new Rect(0, 0, 2, 2);
tilesProvider.fetchTiles(rect, tilesManager.getZoom());
Log.d(MainActivity.TAG, "zoom: " + tilesManager.getZoom());
Log.d(MainActivity.TAG, "regiaoVisivel: " + regiaoVisivel.toString());
Log.d(MainActivity.TAG, "Quantas tiles? " + tilesProvider.getTiles().values().size());
}
public void drawTiles(Canvas canvas, Point offset){
Collection<Tile> tilesList = tilesProvider.getTiles().values();
Log.d(MainActivity.TAG, "tilesList.size(): " + tilesList.size());
Log.d(MainActivity.TAG, "regiaoVisivel: " + tilesManager.getAreaVisivel().toString());
for(Tile tile : tilesList) {
int tileSize = tilesManager.getTamTile();
long tileX = tile.getX() * tileSize;
long tileY = tile.getY() * tileSize;
Log.d(MainActivity.TAG, "offset: " + offset + " tileX, tileY: " + tileX + " ," + tileY);
long finalX = tileX ;//- offset.x;
long finalY = tileY ;//- offset.y;
Log.d(MainActivity.TAG, "finalX, finalY: " + finalX + ", " + finalY);
canvas.drawBitmap(tile.getImg(), finalY, finalX, bitmapPaint);
}
}
public void drawMarker(Canvas canvas, Point offset) {
if(gpsLocation != null) {
Point markerPos = tilesManager.longLatToXY(gpsLocation.getLongitude(), gpsLocation.getLatitude());
int markerX = markerPos.x ;//- offset.x;
int markerY = markerPos.y ;//- offset.y;
Log.d(MainActivity.TAG, "Marker(x,y): (" + markerX + ", " + markerY + ")");
float ground = (float) tilesManager.calcGroundResolution(gpsLocation.getLatitude());
float rad = gpsLocation.getAccuracy() / ground;
Log.d(MainActivity.TAG, "raio: " + rad);
canvas.drawCircle(markerX, markerY, 5, circlePaint);
int pen = 1;
canvas.drawText("lon:" + gpsLocation.getLongitude(), 0, 20 * pen++, fontPaint);
canvas.drawText("lat:" + gpsLocation.getLatitude(), 0, 20 * pen++, fontPaint);
canvas.drawText("alt:" + gpsLocation.getAltitude(), 0, 20 * pen++, fontPaint);
canvas.drawText("Zoom:" + tilesManager.getZoom(), 0, 20 * pen++, fontPaint);
}
}
@Override
public void onDraw(Canvas canvas){
canvas.drawARGB(255, 100, 100, 100);
PointD centerRatio = TilesManager.calcRatio(seekLocation.getX(), seekLocation.getY());
int mapWidth = tilesManager.tamanhoMapa() * 256;
Point centerPixel = new Point((int) (centerRatio.getX() * mapWidth), (int) (centerRatio.getY() * mapWidth));
Point offset = new Point((int) (centerPixel.x - viewWidth / 2f), (int) (centerPixel.y - viewHeight / 2f));
drawTiles(canvas, offset);
drawMarker(canvas, offset);
}
@Override
public boolean onTouchEvent(MotionEvent event)
{
int action = event.getAction();
if (action == MotionEvent.ACTION_DOWN)
{
// Keep touch position for later use (dragging)
lastTouchPos.setX((int) event.getX());
lastTouchPos.setY((int) event.getY());
return true;
}
else if (action == MotionEvent.ACTION_MOVE)
{
autoFollow = false;
PointD current = new PointD(event.getX(), event.getY());
// Find how many pixels the users finger moved in both x and y
PointD diff = new PointD(current.getX() - lastTouchPos.getX(), current.getY() - lastTouchPos.getY());
// In a full wolrd map, get the position of the center of the view in pixels
Point pixels1 = tilesManager.longLatToXY(seekLocation.getX(), seekLocation.getY());
// Subtract diff from that position
Point pixels2 = new Point(pixels1.x - (int) diff.getX(), pixels1.y - (int) diff.getY());
// Reconvert the final result to longitude, latitude point
PointD newSeek = tilesManager.xyToLongLat((int) pixels2.x, (int) pixels2.y);
// Finally move the center of the view to the new location
seekLocation = newSeek;
// Refresh the view
fetchTiles();
invalidate(); // Causes the view to redraw itself
// Prepare for the next drag event
lastTouchPos.setX(current.getX());
lastTouchPos.setY(current.getY());
return true;
}
return super.onTouchEvent(event);
}
// Fetch the tiles then draw, don't call to often
public void refresh()
{
fetchTiles();
invalidate();
}
// Like refresh but called from a non UI thread
public void postRefresh()
{
fetchTiles();
postInvalidate();
}
// Simply sets seek location to gpsLocation (if exists)
public void followMarker()
{
if (gpsLocation != null)
{
seekLocation.setX(gpsLocation.getLongitude());
seekLocation.setY(gpsLocation.getLatitude());
autoFollow = true;
fetchTiles();
invalidate();
}
}
public void zoomIn()
{
tilesManager.zoomIn();
onMapZoomChanged();
}
public void zoomOut()
{
tilesManager.zoomOut();
onMapZoomChanged();
}
protected void onMapZoomChanged()
{
tilesProvider.clear();
fetchTiles();
invalidate();
}
// Returns the gps coordinates of the user
public Location getGpsLocation()
{
return gpsLocation;
}
// Returns the gps coordinates of our view center
public PointD getSeekLocation()
{
return seekLocation;
}
// Centers the given gps coordinates in our view
public void setSeekLocation(double longitude, double latitude)
{
seekLocation.setX(longitude);
seekLocation.setY(latitude);
}
// Sets the marker position
public void setGpsLocation(Location location)
{
setGpsLocation(location.getLongitude(), location.getLatitude(), location.getAltitude(), location.getAccuracy());
}
// Sets the marker position
public void setGpsLocation(double longitude, double latitude, double altitude, float accuracy)
{
if (gpsLocation == null) gpsLocation = new Location("");
gpsLocation.setLongitude(longitude);
gpsLocation.setLatitude(latitude);
gpsLocation.setAltitude(altitude);
gpsLocation.setAccuracy(accuracy);
if (autoFollow) followMarker();
}
public int getZoom()
{
return tilesManager.getZoom();
}
public void setZoom(int zoom)
{
tilesManager.setZoom(zoom);
onMapZoomChanged();
}
}
......@@ -8,6 +8,15 @@ public class PointD {
private double x;
private double y;
public PointD() {
return;
}
public PointD(double x, double y) {
this.x = x;
this.y = y;
}
public double getX() {
return x;
}
......
......@@ -12,6 +12,16 @@ public class Tile {
private int y;
private Bitmap img;
public Tile() {
}
public Tile(int x, int y,Bitmap img) {
this.x = x;
this.y = y;
this.img = img;
}
public int getX() {
return x;
}
......
package ufpr.inf.pet.geoloc;
import android.content.Context;
import android.database.SQLException;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteException;
import android.database.sqlite.SQLiteOpenHelper;
import android.util.Log;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
/**
* Created by vmocelin on 11/06/15.
*/
public class TileDbHelper extends SQLiteOpenHelper{
//The Android's default system path of your application database.
private String DB_PATH;
private static String DB_NAME = "tilesdb";
private SQLiteDatabase myDataBase;
private final Context myContext;
/**
* Constructor
* Takes and keeps a reference of the passed context in order to access to the application assets and resources
*/
public TileDbHelper(Context context) {
super(context, DB_NAME, null, 1);
DB_PATH = context.getApplicationInfo().dataDir + "/databases/";
this.myContext = context;
}
/**
* Creates a empty database on the system and rewrites it with your own database.
* */
public void createDataBase() throws IOException{
Log.d(MainActivity .TAG, "checando base de dados");
boolean dbExist = checkDataBase();
if(!dbExist){
Log.d(MainActivity.TAG, "base de dados nao existe, vai ser copiada");
//By calling this method and empty database will be created into the default system path
//of your application so we are gonna be able to overwrite that database with our database.
this.getReadableDatabase();
try {
copyDataBase();
} catch (IOException e) {
throw new Error("Error copying database");
}
}
else
Log.d(MainActivity.TAG, "base de dados ja existe, nao faz nada");
}
/**
* Check if the database already exist to avoid re-copying the file each time you open the application.
* @return true if it exists, false if it doesn't
*/
private boolean checkDataBase(){
SQLiteDatabase checkDB = null;
try{
String myPath = DB_PATH + DB_NAME;
checkDB = SQLiteDatabase.openDatabase(myPath, null, SQLiteDatabase.OPEN_READONLY);
}catch(SQLiteException e){
//database does't exist yet.
}
if(checkDB != null){
checkDB.close();
}
return checkDB != null;
}
/**
* Copies your database from your local assets-folder to the just created empty database in the
* system folder, from where it can be accessed and handled.
* This is done by transfering bytestream.
* */
private void copyDataBase() throws IOException{
//Open your local db as the input stream
InputStream myInput = myContext.getAssets().open(DB_NAME);
// Path to the just created empty db
String outFileName = DB_PATH + DB_NAME;
//Open the empty db as the output stream
OutputStream myOutput = new FileOutputStream(outFileName);
//transfer bytes from the inputfile to the outputfile
byte[] buffer = new byte[1024];
int length;
while ((length = myInput.read(buffer))>0){
myOutput.write(buffer, 0, length);
}
//Close the streams
myOutput.flush();
myOutput.close();
myInput.close();
}
public void openDataBase() throws SQLException {
//Open the database
String myPath = DB_PATH + DB_NAME;
myDataBase = SQLiteDatabase.openDatabase(myPath, null, SQLiteDatabase.OPEN_READONLY);
}
@Override
public synchronized void close() {
if(myDataBase != null)
myDataBase.close();
super.close();
}
@Override
public void onCreate(SQLiteDatabase db) {
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
}
// Add your public helper methods to access and get content from the database.
// You could return cursors by doing "return myDataBase.query(....)" so it'd be easy
// to you to create adapters for your views.
}
\ No newline at end of file
package ufpr.inf.pet.geoloc;
import android.graphics.Point;
import android.graphics.Rect;
import android.util.Log;
import java.math.BigDecimal;
/**
* Created by vmocelin on 27/05/15.
*/
public class TilesManager {
private static double raioTerra = 6378137;
private double minLatitude = -25.444282186891535;
private double maxLatitude = -25.457806121916125;
private double minLongitude = -49.22666788101196;
private double maxLongitude = -49.24293279647827;
// private static BigDecimal minLatitude = new BigDecimal("-25.444282186891535");
// private static BigDecimal maxLatitude = new BigDecimal("-25.457806121916125");
// private static BigDecimal minLongitude = new BigDecimal("-49.24293279647827");
// private static BigDecimal maxLongitude = new BigDecimal("-49.22666788101196");
private static BigDecimal minLatitude = new BigDecimal("-90");
private static BigDecimal maxLatitude = new BigDecimal("90");
private static BigDecimal minLongitude = new BigDecimal("-180");
private static BigDecimal maxLongitude = new BigDecimal("180");
private int maxZoom = 5;
private int tamTile = 256;
private int viewWidth;
private int viewHeight;
private int tilesX;
private int tilesY;
private int zoom = 0;
private PointD location = new PointD();
private int zoom = 1;
private PointD location = new PointD(0,0);
private Rect areaVisivel;
public TilesManager(int tamTile, int viewWidth, int viewHeight) {
//Define a escala em 15 casas decimais com o arrendodamente ROUND_HALF_EVEN (melhor para não acumular erros segundo o Javadoc)
minLatitude.setScale(15, BigDecimal.ROUND_HALF_EVEN);
maxLatitude.setScale(15, BigDecimal.ROUND_HALF_EVEN);
minLongitude.setScale(15, BigDecimal.ROUND_HALF_EVEN);
maxLongitude.setScale(15, BigDecimal.ROUND_HALF_EVEN);
this.tamTile = tamTile;
this.viewHeight = viewHeight;
this.viewWidth = viewWidth;
tilesX = (int) ((float) viewWidth / tamTile);
tilesY = (int) ((float) viewHeight / tamTile);
Log.d(MainActivity.TAG, "tilesX: " + tilesX + " tilesY: " + tilesY);
atualizaAreaVisivel(location.getX(), location.getY(), this.zoom);
}
private void atualizaAreaVisivel(double longitude, double latitude, int zoom) {
location.setX(longitude);
location.setY(latitude);
Log.d(MainActivity.TAG, "Location: " + location.toString());
this.zoom = zoom;
Point tileId = getTileXY(location.getX(), location.getY());
Log.d(MainActivity.TAG, "tileId: " + tileId.toString());
int meioTileX = (int) ((float) (tilesX + 1)/2f);
int meioTileY = (int) ((float) (tilesY + 1)/2f);
areaVisivel = new Rect(tileId.x - meioTileX, tileId.y - meioTileY, tileId.x + meioTileX, tileId.y + meioTileY);
}
private static double clip(double n, double minValue, double maxValue)
{
return Math.min(Math.max(n, minValue), maxValue);
}
// Retorna um ponto, cujas coordenadas variam de 0 a 1, dando assim uma proporção do mapa
public static PointD calcRatio(double longitude, double latitude) {
Log.d(MainActivity.TAG, "longitude: " + longitude + " latitude: " + latitude);
// Para o eixo X, basta uma simples regra de 3
// (Longitude - minLongitude) / (maxLongitude - minLongitude)
BigDecimal lon = new BigDecimal(longitude);
lon.setScale(15, BigDecimal.ROUND_HALF_EVEN);
BigDecimal numerador = lon.subtract(minLongitude);
Log.d(MainActivity.TAG, "numerador: " + numerador);
BigDecimal denominador = maxLongitude.subtract(minLongitude);
Log.d(MainActivity.TAG, "denominador: " + denominador);
BigDecimal ratioX = numerador.divide(denominador, 15, BigDecimal.ROUND_HALF_EVEN);
// Para o eixo Y é necessária certa matemágica trigonométrica
// (0.5 - log((1+senoLatitude)/(1-senoLatitude)))/4*pi
// Sendo senoLatitude = sen(latitude * PI/180)
double senoLatitude = Math.sin(latitude * Math.PI / 180.0);
double ratioY = (0.5 - Math.log((1 + senoLatitude)/(1 - senoLatitude))) / (4 * Math.PI);
Log.d(MainActivity.TAG, "ratioX: " + ratioX.doubleValue() + " ratioY: " + ratioY);
return new PointD(ratioX.doubleValue(), ratioY);
}
// Dado uma longitude e latitude, retorna o indice (ponto) que determina um tile
private Point getTileXY(double longitude, double latitude) {
PointD ratio = calcRatio(longitude, latitude);
int tamMapa = tamanhoMapa();
return new Point((int) ratio.getX() * tamMapa, (int) ratio.getY() * tamMapa);
}
public int tamanhoMapa(){
return (int) 256 << zoom;
}
public PointD longLatToXY(double latitude, double longitude){
latitude = clip(latitude, minLatitude, maxLatitude);
longitude = clip(longitude, minLongitude, maxLongitude);
public Point longLatToXY(double latitude, double longitude){
latitude = clip(latitude, minLatitude.doubleValue(), maxLatitude.doubleValue());
longitude = clip(longitude, minLongitude.doubleValue(), maxLongitude.doubleValue());