Skip to content

Commit

Permalink
fix #136 and code cleanup
Browse files Browse the repository at this point in the history
  • Loading branch information
mkrupczak3 committed Jun 21, 2024
1 parent aadbe7a commit 7cb4b0b
Show file tree
Hide file tree
Showing 5 changed files with 148 additions and 98 deletions.
32 changes: 32 additions & 0 deletions app/src/main/java/com/openathena/AthenaActivity.java
Original file line number Diff line number Diff line change
Expand Up @@ -47,11 +47,41 @@ public enum outputModes {
CK42GaussKrüger
}

public String getCurrentOutputModeName() {
switch (outputMode) {
case WGS84:
return getString(R.string.wgs84_standard_lat_lon);
case UTM:
return getString(R.string.utm);
case MGRS1m:
return getString(R.string.nato_mgrs_1m);
case MGRS10m:
return getString(R.string.nato_mgrs_10m);
case MGRS100m:
return getString(R.string.nato_mgrs_100m);
case CK42Geodetic:
return getString(R.string.ck_42_lat_lon);
case CK42GaussKrüger:
return getString(R.string.ck_42_gauss_kruger_n_e);
}
return ""; // this should never happen
}

public enum measurementUnits {
METER,
FOOT // US survey foot used in Aviation, 1200/3937 = 0.30480061 meters
}

public String getCurrentMeasurementUnitName() {
switch (measurementUnit) {
case METER:
return getString(R.string.meter_label);
case FOOT:
return "ft.";
}
return ""; // this should never happen
}

protected static PrefsActivity.outputModes outputMode;
protected static AthenaActivity.measurementUnits measurementUnit;
static RadioGroup outputModeRadioGroup;
Expand Down Expand Up @@ -205,6 +235,8 @@ public void setOutputMode(int mode) {
}
}



public void setMeasurementUnit(measurementUnits aUnit) {
if (aUnit == null) {
setMeasurementUnit(-1); // should never happen
Expand Down
65 changes: 65 additions & 0 deletions app/src/main/java/com/openathena/CoordTranslator.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
package com.openathena;

import java.math.RoundingMode;
import java.text.DecimalFormat;
import java.text.DecimalFormatSymbols;
import java.text.ParseException;
import android.util.Log;

Expand Down Expand Up @@ -57,6 +60,37 @@ public static double[] fromMGRS(String mgrs_in) throws java.text.ParseException
return new double[] {p.getLatitude(), p.getLongitude()};
}

public static String toSelectedOutputMode(double latitude, double longitude, AthenaActivity.outputModes outputMode) {
switch (outputMode) {
case WGS84:
return roundDouble(latitude) + "," + " " + roundDouble(longitude);
case UTM:
return toUTM(latitude,longitude);
case MGRS1m:
return toMGRS1m_Space_Separated(latitude, longitude);
case MGRS10m:
return toMGRS10m_Space_Separated(latitude, longitude);
case MGRS100m:
return toMGRS100m_Space_Separated(latitude, longitude);
case CK42Geodetic:
// WARNING: The following output will be in CK-42 lat/lon, which is easy to confuse with regular WGS84 coordinates
// CK-42 coordinates must always be labeled as such in the consuming UI (to avoid confusion)
//
// This conversion introduces some inaccuracy due to lack of ellipsoidal height
// therefore, result should only be used for unimportant uses such as for dem bounds UI
return roundDouble(toCK42Lat(latitude,longitude,0.0d)) + "," + " " + roundDouble(toCK42Lon(latitude,longitude,0.0d));
case CK42GaussKrüger:
// This conversion introduces some inaccuracy due to lack of ellipsoidal height
// therefore, result should only be used for unimportant uses such as for dem bounds UI
return toCK42_GK_String(latitude, longitude, 0.0d);
default:
// This should never happen
String errString = "ERROR: Attempted to call toSelectedOutputMode on invalid outputMode: " + outputMode.name();
Log.e(TAG, errString);
throw new IllegalArgumentException(errString);
}
}

public static String toMGRS1m_Space_Separated(double latitude, double longitude) {
return toMGRS_Space_Separated(latitude, longitude, GridType.METER);
}
Expand Down Expand Up @@ -121,6 +155,30 @@ public static long[] fromCK42toCK42_GK(double CK42_latitude, double CK42_longitu
return CK42_Gauss_Krüger_Translator.CK42_Geodetic_to_Gauss_Krüger(CK42_latitude, CK42_longitude);
}

public static String makeGKHumanReadable(long GK) {
String human_readable;
if (GK >= 10000000) {
human_readable = Long.toString(GK);
} else { // If value is not at least 5 digits, pad with leading zeros
human_readable = Long.toString(GK + 10000000);
human_readable = human_readable.substring(1);
}
human_readable = human_readable.substring(0, human_readable.length() - 5) + "-" + human_readable.substring(human_readable.length() - 5);
return human_readable;
}

public static String toCK42_GK_String(double latitude, double longitude, double WGS84_altitude_meters) {
double GK_lat = toCK42Lat(latitude,longitude,WGS84_altitude_meters);
double GK_lon = toCK42Lon(latitude,longitude,WGS84_altitude_meters);
long[] GK_northing_and_easting = fromCK42toCK42_GK(GK_lat,GK_lon);
long GK_northing = GK_northing_and_easting[0];
long GK_easting = GK_northing_and_easting[1];

String northing_string = CoordTranslator.makeGKHumanReadable(GK_northing);
String easting_string = CoordTranslator.makeGKHumanReadable(GK_easting);
return northing_string + " " + easting_string;
}

// Method to handle coordinate String parsing
// accepts either lat,lon (in either DMS or decimal) or MGRS
// returns a double[] containing WGS84 lat,lon
Expand Down Expand Up @@ -240,4 +298,11 @@ public static boolean isValidLatOrLon(String dms) {
return true;
}

private static String roundDouble(double d) {
DecimalFormatSymbols decimalSymbols = DecimalFormatSymbols.getInstance();
decimalSymbols.setDecimalSeparator('.');
DecimalFormat df = new DecimalFormat("#.######", decimalSymbols);
df.setRoundingMode(RoundingMode.HALF_UP);
return df.format(d);
}
}
2 changes: 0 additions & 2 deletions app/src/main/java/com/openathena/DemCacheActivity.java
Original file line number Diff line number Diff line change
Expand Up @@ -176,8 +176,6 @@ public void onItemClick(View view, int position)
{
Intent intent;

// for now, post a bubble; XXX
// eventually, we'll go to an activity that gives us more info about this DEM
DemCache.DemCacheEntry i = adapter.getItem(position);
String t = "You clicked "+i.filename+", "+i.bytes+" bytes, center=("+i.cLat+","+i.cLon+")";
Log.d(TAG,"DemCacheActivity: clicked "+t);
Expand Down
70 changes: 37 additions & 33 deletions app/src/main/java/com/openathena/ElevationMapDetailsActivity.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,47 +6,26 @@

package com.openathena;

import android.content.Context;
import android.content.Intent;
import android.os.Bundle;

import com.google.android.material.snackbar.Snackbar;

import androidx.activity.result.ActivityResultLauncher;
import androidx.activity.result.contract.ActivityResultContracts;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.app.AppCompatActivity;

import android.os.Handler;
import android.os.Looper;
import android.text.Html;
import android.text.method.LinkMovementMethod;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.inputmethod.InputMethodManager;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;

import androidx.core.util.Consumer;
import androidx.navigation.NavController;
import androidx.navigation.Navigation;
import androidx.navigation.ui.AppBarConfiguration;
import androidx.navigation.ui.NavigationUI;

import com.openathena.databinding.ActivityAboutBinding;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.nio.file.Files;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.TimeZone;
Expand Down Expand Up @@ -77,12 +56,12 @@ protected void onCreate(Bundle savedInstanceState)
// Storage Access Framework(SAF) does not require us to request permission
// to access
copyDemLauncher = registerForActivityResult(new ActivityResultContracts.CreateDocument(), uri -> {
if (uri != null && !exportFilename.equals("")) {
if (uri != null && !exportFilename.isEmpty()) {
// copy the file to uri; since we have a File and
// dialog gives us a URI, we need to open/read/write exported file
// the try with resources statement automatically closes the streams
// when it finishes
try (InputStream inputStream = new FileInputStream(new java.io.File(getFilesDir(), exportFilename));
try (InputStream inputStream = Files.newInputStream(new File(getFilesDir(), exportFilename).toPath());
OutputStream outStream = getContentResolver().openOutputStream(uri)) {

byte[] buf = new byte[1024];
Expand Down Expand Up @@ -139,19 +118,44 @@ protected void onResume()

htmlString += "<br>";

htmlString += "DEM lat/lon bounds (WGS84):" + "<br>";
htmlString += "N: " + truncateDouble(maxLat,6)+"<br>";
htmlString += "E: " + truncateDouble(maxLon,6)+"<br>";
htmlString += "S: " + truncateDouble(minLat,6)+"<br>";
htmlString += "W: " + truncateDouble(minLon,6)+"<br>";
// text formatting tag for uniform character width
String teletypeTextFlag = "<tt>"; // this tag is deprecated in HTML5, too bad we use it anyways
// "<pre>" // proper tag for current rev HTML, does not seem to work with Android

if(outputModeIsMGRS() || outputMode == outputModes.UTM || outputMode == outputModes.CK42GaussKrüger) { // For Grid-based output modes
htmlString += "DEM lat/lon bounds (" + getCurrentOutputModeName() + "):" + "<br>";
htmlString += teletypeTextFlag;
htmlString += "NW: " + CoordTranslator.toSelectedOutputMode(maxLat,minLon,outputMode) + "<br>";
htmlString += "NE: " + CoordTranslator.toSelectedOutputMode(maxLat,maxLon,outputMode) + "<br>";
htmlString += "SW: " + CoordTranslator.toSelectedOutputMode(minLat,minLon,outputMode) + "<br>";
htmlString += "SE: " + CoordTranslator.toSelectedOutputMode(minLat,maxLon,outputMode) + "<br>";
// close pre tag
} else { // For Geodetic output modes (WGS84 or CK42)
htmlString += "DEM lat/lon bounds (" + getCurrentOutputModeName().split(" ")[0] + "):" + "<br>";
htmlString += teletypeTextFlag;
if (outputMode == outputModes.CK42Geodetic) {
// this conversion isn't entirely accurate w/o correct altitude value, but is good enough for this UI
minLat = CoordTranslator.toCK42Lat(minLat,minLon,0.0d);
minLon = CoordTranslator.toCK42Lon(minLat,minLon,0.0d);
maxLat = CoordTranslator.toCK42Lat(maxLat,maxLon,0.0d);
maxLon = CoordTranslator.toCK42Lon(maxLat,maxLon,0.0d);
}
htmlString += "N: " + truncateDouble(maxLat, 6) + "<br>";
htmlString += "E: " + truncateDouble(maxLon, 6) + "<br>";
htmlString += "S: " + truncateDouble(minLat, 6) + "<br>";
htmlString += "W: " + truncateDouble(minLon, 6) + "<br>";
}
htmlString += "</tt>";


htmlString += "<br>";

htmlString += "length: " + ((isUnitFoot()) ? truncateDouble(dEntry.l * AthenaApp.FEET_PER_METER, 0) : truncateDouble(dEntry.l,0)) + " " + (isUnitFoot() ? "ft." : getString(R.string.meter_label)) + "²" + "<br>";
htmlString += "size: " + ((isUnitFoot()) ? Math.round(dEntry.l * AthenaApp.FEET_PER_METER) : Math.round(dEntry.l)) + " " + (isUnitFoot() ? "ft." : getString(R.string.meter_label)) + "²" + "<br>";
String coordStr = truncateDouble(dEntry.cLat, 6)+","+truncateDouble(dEntry.cLon, 6);
// make sure layout xml has clickable=true in for the textview widget
// and make sure to add LinkMovementMethod too
String urlStr = "https://www.google.com/maps/search/?api=1&t=k&query="+coordStr;

// Google Maps requires a ?q= tag to actually display a pin for the indicated location
// https://en.wikipedia.org/wiki/Geo_URI_scheme#Unofficial_extensions
String urlStr = "geo:"+coordStr+"?q="+coordStr;
String lineStr = "center: <a href=\""+urlStr+"\">"+coordStr+"</a><br>";
Log.d(TAG,"DemDetail: center link line is "+lineStr);
htmlString += lineStr;
Expand Down
Loading

0 comments on commit 7cb4b0b

Please sign in to comment.