/* Copyright 2012 Nik Cain nik@showmehills.com This file is part of ShowMeHills. ShowMeHills 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. ShowMeHills 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 ShowMeHills. If not, see <http://www.gnu.org/licenses/>. */ package com.showmehills; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import android.content.Context; import android.content.SharedPreferences; import android.database.Cursor; import android.database.sqlite.SQLiteDatabase; import android.database.sqlite.SQLiteException; import android.database.sqlite.SQLiteOpenHelper; import android.location.Location; import android.preference.PreferenceManager; import android.util.Log; import org.florescu.android.rangeseekbar.RangeSeekBar; public class HillDatabase extends SQLiteOpenHelper{ private static String DB_PATH; private static String DB_NAME; private static int mDatabaseVersion = 12; private SQLiteDatabase myDataBase; private final Context myContext; private boolean mDbCopied = false; public ArrayList<Hills> localhills = new ArrayList<>(); public HillDatabase(Context context, String dbname, String dbpath) { super(context, dbname, null, 1); DB_NAME = dbname; DB_PATH = dbpath; this.myContext = context; } public void createDataBase(){ // made some changes in the database, but need to update it in existing installs! // so need to add a version number // for now just update db every time boolean dbExist = checkDataBase(); if(!dbExist){ this.getReadableDatabase(); copyDataBase(); } } public boolean checkDataBase(){ if (!mDbCopied) return false; if (myDataBase != null) { // already ok return true; } try{ String myPath = DB_PATH + DB_NAME; try { myDataBase = SQLiteDatabase.openDatabase(myPath, null, SQLiteDatabase.OPEN_READONLY); } catch(Exception e){ return false; } if (myDataBase == null) { return false; } String qu = "select ver from dbversions limit 1"; Cursor cursor = getReadableDatabase().rawQuery( qu, null); if(cursor.moveToFirst()) { int dbversion = cursor.getInt(0); Log.d("showmehills", "db version is " + dbversion); if (dbversion != mDatabaseVersion) { Log.d("showmehills", "Old database (" + dbversion + "). Updating!"); myDataBase.close(); myDataBase = null; String db = DB_NAME; // required for backwards compatibility (name changed at v10) if (dbversion < 10) db = "hillsv1.db"; if (myContext.deleteDatabase(DB_PATH + db)) { Log.d("showmehills", "Deleted old database " + db); } else { Log.d("showmehills", "Failed to delete old database!"); } cursor.close(); return false; } } cursor.close(); }catch(SQLiteException e){ //database does't exist yet. e.printStackTrace(); } return myDataBase != null; } private void copyDataBase() { Log.d("showmehills", "Attempting to copy database " + DB_NAME + " from assets to " + DB_PATH + DB_NAME); InputStream myInput; try { myInput = myContext.getAssets().open(DB_NAME); } catch (IOException e) { e.printStackTrace(); return; } String outFileName = DB_PATH + DB_NAME; OutputStream myOutput; long bytesCopied = 0; try { myOutput = new FileOutputStream(outFileName); } catch (FileNotFoundException e) { e.printStackTrace(); try { myInput.close(); } catch (IOException e1) { e1.printStackTrace(); } return; } byte[] buffer = new byte[1024]; int length; try { while ((length = myInput.read(buffer))>0){ myOutput.write(buffer, 0, length); bytesCopied += length; } } catch (IOException e) { e.printStackTrace(); try { myInput.close(); myOutput.close(); } catch (IOException e1) { e1.printStackTrace(); } return; } try { myOutput.flush(); myOutput.close(); myInput.close(); } catch (IOException e) { e.printStackTrace(); } mDbCopied = true; Log.d("showmehills", "Database copied successfully (" + bytesCopied + " bytes), attempting to check database again..."); // should be created, so now open checkDataBase(); } @Override public synchronized void close() { if(myDataBase != null) myDataBase.close(); myDataBase = null; super.close(); } @Override public void onCreate(SQLiteDatabase db) {} @Override public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {} public void SetDirections(Location curLocation, int minheight, int maxheight, int mindistance, int maxdistance) { if (curLocation == null) return; if (myDataBase == null) { createDataBase(); if (myDataBase == null) return; } /* SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(myContext); String md = prefs.getString("distance", "25"); if (md.equals("")) md = "25"; Float maxdistance = Float.parseFloat(md); md = prefs.getString("mindistance", "0"); if (md.equals("")) md = "0"; Float mindistance = Float.parseFloat(md); md = prefs.getString("minheight", "0"); if (md.equals("")) md = "0"; Float minheight = Float.parseFloat(md); */ localhills.clear(); double curLatitude = curLocation.getLatitude(); double curLongitude = curLocation.getLongitude(); // use a rule of thumb for distance between lines of lat & long // 1 line of latitude = 111km // 1 line of longitude = sin(latitude)* 111km. double minLat = Math.min(curLatitude - (maxdistance/111.0f ), curLatitude + (maxdistance/111.0f )); double maxLat = Math.max(curLatitude - (maxdistance/111.0f ), curLatitude + (maxdistance/111.0f )); double minLon = Math.min(curLongitude - (maxdistance/(111.0 * Math.sin(curLatitude * Math.PI / 180))), (curLongitude + (maxdistance/(111.0 * Math.sin(curLatitude * Math.PI / 180))))); double maxLon = Math.max(curLongitude - (maxdistance/(111.0 * Math.sin(curLatitude * Math.PI / 180))), (curLongitude + (maxdistance/(111.0 * Math.sin(curLatitude * Math.PI / 180))))); String qu = "select * from mountains where latitude between " + minLat + " and " + maxLat + " and longitude between " + minLon + " and " + maxLon; if (minheight > 0) qu += " and height > " + minheight; if (maxheight < 9000) qu += " and height < " + maxheight; Cursor cursor; try { cursor = getReadableDatabase().rawQuery( qu, null); } catch(SQLiteException e){ return; } if (cursor == null) return; int tooNear = 0, tooFar = 0; if(cursor.moveToFirst()) { double dLat, dLon, lat1, lat2; double x, y, brng, a, c, dheight; Hills h; do { try { h = new Hills( cursor.getInt(cursor.getColumnIndex("_id")), cursor.getString(cursor.getColumnIndex("name")), cursor.getDouble(cursor.getColumnIndex("longitude")), cursor.getDouble(cursor.getColumnIndex("latitude")), cursor.getInt(cursor.getColumnIndex("height"))); dLat = Math.toRadians(h.latitude - curLatitude); dLon = Math.toRadians(h.longitude - curLongitude); lat1 = Math.toRadians(curLatitude); lat2 = Math.toRadians(h.latitude); // direction calculation y = Math.sin(dLon) * Math.cos(lat2); x = Math.cos(lat1)*Math.sin(lat2) - Math.sin(lat1)*Math.cos(lat2)*Math.cos(dLon); brng = Math.atan2(y, x) * 180 / Math.PI; h.direction = (brng<0)?brng+360:brng; // distance calculation a = Math.sin(dLat/2) * Math.sin(dLat/2) + Math.cos(lat2) * Math.cos(lat1) * Math.sin(dLon/2) * Math.sin(dLon/2); c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a)); h.distance = Math.floor(10 * 6371 * c) / 10.0; // Distance in km // vertical angle dheight = h.height - curLocation.getAltitude(); h.visualElevation = Math.atan2(dheight, h.distance*1000); if (h.distance > maxdistance) { tooFar++; } else if (h.distance < mindistance) { tooNear++; } else { //Log.d("showmehills", "Adding " + h.hillname + "@"+h.longitude+","+h.latitude); localhills.add(h); } } catch(Exception e) { Log.e("showmehills", "bad database read: " + e.getMessage()); } } while (cursor.moveToNext()); } cursor.close(); Log.d("showmehills", "Added " + localhills.size() + " markers; skipped " + tooNear + " too near, " + tooFar + " too far."); /* * for testing: localhills.add(new Hills(0,"London Eye", -0.119700, 51.5033, 135)); localhills.add(new Hills(0,"Shard", -0.086667, 51.504444, 308)); localhills.add(new Hills(0,"1 Canada Sq", -0.019611, 51.505, 240)); localhills.add(new Hills(0,"BT Tower", -0.138900, 51.5215, 191)); localhills.add(new Hills(0,"Gherkin", -0.080278, 51.514444, 180)); */ Collections.sort(localhills, new Comparator<Object>(){ public int compare(Object o1, Object o2) { Hills p1 = (Hills) o1; Hills p2 = (Hills) o2; if (p1.distance==p2.distance) return 0; if (p1.distance < p2.distance) return -1; return 1; } }); } }