diff --git a/app/src/main/assets/help.html b/app/src/main/assets/help.html index 820e7fc80..34b2afe21 100644 --- a/app/src/main/assets/help.html +++ b/app/src/main/assets/help.html @@ -61,6 +61,8 @@
To temporarily hide your notes/drawings and return to normal Map functioning (Pan mode), just tap the Draw (Pan) button again.
-•Long-press any point on the chart (with GPS - acquired) to display text at the top of the screen giving - approximate compass direction and distanceFrom, - followed by exact GPS bearingTo, that point in relation to - your GPS location. Very handy when contacting ATC or making CTAF - calls!
- -Note: The current Destination used - by Avare for various features can be set after a long-press on the chart. Just tap either - the button that pops out containing the name or coordinates of the location you pressed; - or the button that pops out containing the word "Plan" to send that Destination to the flight plan. +
•Long-press any point on the chart to display a page containing: +
•The "Find" button in the bottom Menu +
•The "Find" button in the bottom Menu
activates a search box for a 4-digit
Destination Airport code (or Navaid code, Fix code, etc.)
that Avare uses to display a course, bearing, etc. This
diff --git a/app/src/main/java/com/ds/avare/storage/DataBaseHelper.java b/app/src/main/java/com/ds/avare/storage/DataBaseHelper.java
index 943159117..14c618f41 100644
--- a/app/src/main/java/com/ds/avare/storage/DataBaseHelper.java
+++ b/app/src/main/java/com/ds/avare/storage/DataBaseHelper.java
@@ -2061,7 +2061,85 @@ public Metar getMETAR(String station) {
return metar;
}
-
+ /**
+ * Return metar closest to the input coordinates using query on weather.metars table
+ * We query in a bounded 100mi wide/tall lat/lon box then sort based on distance from the input
+ * see also http://stackoverflow.com/questions/3695224/sqlite-getting-nearest-locations-with-latitude-and-longitude#
+ * @param lat of the central point
+ * @param lon of the central point
+ * @return
+ */
+ public Metar getClosestMETAR(Double lat, Double lon) {
+
+ Metar metar = null;
+ final int searchRadius = mPref.getClosestMetarSearchRadius();
+ SquareBoxSearchHelper squareBoxSearchHelper = new SquareBoxSearchHelper(lat, lon, searchRadius);
+
+ String qry =
+ "select * from metars where 1=1 "
+ + squareBoxSearchHelper.getWhereClause("latitude", "longitude")
+ +";";
+
+ Cursor cursor = doQueryWeather(qry, getWeatherDb());
+
+ try {
+ if(cursor != null) {
+ if(cursor.moveToFirst()) {
+
+ metar = new Metar();
+ metar.rawText = cursor.getString(0);
+ metar.time = cursor.getString(1);
+ metar.stationId = cursor.getString(2);
+ metar.flightCategory = cursor.getString(3);
+ if (!cursor.isNull(4) && !cursor.isNull(5)) {
+ metar.distance = Projection.getStaticDistance(lon, lat, cursor.getDouble(4), cursor.getDouble(5));
+
+ GeomagneticField gmf = new GeomagneticField(lat.floatValue(), lon.floatValue(), 0, System.currentTimeMillis());
+ Projection p = new Projection(cursor.getDouble(4), cursor.getDouble(5), lon, lat);
+ metar.position = Math.round(p.getDistance()) + Preferences.distanceConversionUnit + " " +
+ p.getGeneralDirectionFrom(-gmf.getDeclination());
+ }
+ }
+ }
+ }
+ catch (Exception e) {
+ }
+
+ closesWeather(cursor);
+ return metar;
+ }
+
+ private class SquareBoxSearchHelper {
+ private double lat, lon;
+ private Coordinate top;
+ private Coordinate bottom;
+ private Coordinate left;
+ private Coordinate right;
+ private double fudge;
+
+ public SquareBoxSearchHelper(double lat, double lon, double search_radius) {
+ this.lat = lat; this.lon = lon;
+ top = Projection.findStaticPoint(lon, lat, 0, search_radius);
+ bottom = Projection.findStaticPoint(lon, lat, 180, search_radius);
+ left = Projection.findStaticPoint(lon, lat, 270, search_radius);
+ right = Projection.findStaticPoint(lon, lat, 90, search_radius);
+ fudge = Math.pow(Math.cos(Math.toRadians(lat)), 2);
+ }
+
+ public String getWhereClause(String latField, String lonField) {
+ return " and "+latField+" < "+top.getLatitude()+
+ " and "+latField+" > "+bottom.getLatitude()+
+ " and "+lonField+" < "+right.getLongitude()+
+ " and "+lonField+" > "+left.getLongitude()+
+ " order by ((" +lat+" - "+latField+") * ("+lat+" - "+latField
+ +") + ("+lon+" - "+lonField+") * ("+lon+" - "+lonField
+ +") * "+fudge+")";
+ }
+
+ }
+
+
+
/**
*
* @param lon
diff --git a/app/src/main/java/com/ds/avare/storage/DataSource.java b/app/src/main/java/com/ds/avare/storage/DataSource.java
index 581bbe7d4..fa6979e62 100644
--- a/app/src/main/java/com/ds/avare/storage/DataSource.java
+++ b/app/src/main/java/com/ds/avare/storage/DataSource.java
@@ -206,7 +206,17 @@ public Metar getMETAR(String station) {
}
/**
- *
+ *
+ * @param lat
+ * @param lon
+ * @return
+ */
+ public Metar getClosestMETAR(Double lat, Double lon) {
+ return dbHelper.getClosestMETAR(lat, lon);
+ }
+
+ /**
+ *
* @return
*/
public LinkedList
");
if(translate) {
weather = weather.replace(" FM", "FM(From)
");
+ weather = weather.replace("TEMPO", "TEMPO(Temporarily)
");
weather = weather.replace("BECMG", "BECMG(Becoming)
");
}
else {
weather = weather.replace(" FM", "FM");
+ weather = weather.replace("TEMPO", "TEMPO");
weather = weather.replace("BECMG", "BECMG");
}
return weather;
@@ -174,21 +179,42 @@ public static String formatTafHTML(String weatherAll, boolean translate) {
weather = weather.replaceAll("VV", "VV" + (translate ? "(Vertical Visibility)" : "") + "");
weather = weather.replaceAll("CB", "CB" + (translate ? "(Cumulonimbus)" : "") + "");
weather = weather.replaceAll("WS", "WS" + (translate ? "(Wind Shear)" : "") + "");
-
+
weather = weather.replaceAll(" 9999 ", " 9999" + (translate ? "(Visibility > 7SM) " : ""));
weather = weather.replaceAll("QNH", "QNH" + (translate ? "(Minimum Altimeter)" : ""));
weather = weather.replaceAll("INS", "INS" + (translate ? "(Inches)" : ""));
for(int i = 1 ; i < strip.length; i++) {
-
+
String weather1 = strip[i];
-
+
weather += " RMK" + (translate ? "(Remark) " : " ") + weather1;
}
return weather;
}
+ public enum DistantMetarFormat { NoStationId, WithStationId }
+
+ /**
+ * @param metar
+ * @param format
+ * @param airport
+ * @return the metar decorated with the metar's position off airport name, if that metar is
+ * from a different field; for example for 3GV we'd print:
+ * METAR (8nm SW of 3GV)
+ */
+ public static String formatDistantMetarHeader(Metar metar, DistantMetarFormat format, String airport) {
+ String stationId = format == DistantMetarFormat.WithStationId ?
+ "using " + metar.stationId + " "
+ : "";
+ return metar.distance > 0 ?
+ String.format(Locale.getDefault(),
+ "(%s%s %s) ",
+ stationId, metar.position, airport)
+ : "";
+ }
+
/**
* Split string on the second space
* @param s
@@ -221,6 +247,7 @@ public static String formatMetarHTML(String weatherAll, boolean translate) {
*/
identAndTime = identAndTime.replaceAll("SPECI", "SPECI" + (translate ? "(Special/unscheduled)" : ""));
+
/*
* Remarks
*/
@@ -322,6 +349,7 @@ public static String formatMetarHTML(String weatherAll, boolean translate) {
return identAndTime + " " + weather;
}
+
/**
* Color code winds
* @param weather
@@ -740,8 +768,8 @@ public static String getBestRunway(String metar, LinkedList
TAF " + data.taf.stationId + " " + WeatherHelper.formatVisibilityHTML(WeatherHelper.formatTafHTML(WeatherHelper.formatWindsHTML(WeatherHelper.formatWeatherHTML(split[1], mPref.isWeatherTranslated()), mPref.isWeatherTranslated()), mPref.isWeatherTranslated()));
+ taf = "
TAF
";
+ taf += data.taf.stationId;
+ taf += WeatherHelper.formatVisibilityHTML(
+ WeatherHelper.formatTafHTML(
+ WeatherHelper.formatWindsHTML(
+ WeatherHelper.formatWeatherHTML(split[1], mPref.isWeatherTranslated()),
+ mPref.isWeatherTranslated()),
+ mPref.isWeatherTranslated()));
}
}
String metar = "";
if(data.metar != null) {
- metar = WeatherHelper.formatMetarHTML(data.metar.rawText, mPref.isWeatherTranslated());
- metar = "
METAR " + "" + metar + "";
+ metar = WeatherHelper.formatDistantMetarHeader(
+ data.metar, WeatherHelper.DistantMetarFormat.NoStationId, data.airport);
+ metar += "
";
+ metar += WeatherHelper.formatMetarHTML(data.metar.rawText, mPref.isWeatherTranslated());
+ metar = "
METAR " + "" + metar + "
Performance ";
+ performance += WeatherHelper.formatDistantMetarHeader(
+ data.metar, WeatherHelper.DistantMetarFormat.WithStationId, data.airport);
+ performance += "
";
performance += data.performance.replace("\n", "
");
}
}
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index 163c1759a..771e3aa91 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -533,6 +533,10 @@ Redistribution and use in source and binary forms, with or without modification,