Skip to content

Commit

Permalink
MVP 🥳🎉🎊🍾
Browse files Browse the repository at this point in the history
  • Loading branch information
mkrupczak3 committed Dec 17, 2022
1 parent 45a7525 commit dd8296f
Show file tree
Hide file tree
Showing 6 changed files with 78 additions and 42 deletions.
16 changes: 11 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
OpenAthena for Android

# Operability
This project is not yet in an operable state. The main [OpenAthena project](http://OpenAthena.com) running on a PC/Mac is required until otherwise noted
This project is not yet stable. The main [OpenAthena project](http://OpenAthena.com) running on a PC/Mac should be used instead, until otherwise noted

# Features
This project is not designed to maintain feature parity with the main [OpenAthena project](http://OpenAthena.com).
Expand All @@ -11,17 +11,23 @@ to more users

## GeoTIFF parsing:

This app uses the open source [tiff-java library](https://github.com/ngageoint/tiff-java) maintained by the U.S. [National Geospatial Intelligence Agency](https://www.nga.mil/) to read GeoTIFF files
This app uses the open source [tiff-java library](https://github.com/ngageoint/tiff-java) maintained by the U.S. [National Geospatial Intelligence Agency](https://www.nga.mil/) to read GeoTIFF Digital Elevation Model (DEM) files, stored as a ".tif" file.

Load the file [Rome-30m-DEM.tif](https://github.com/mkrupczak3/OpenAthena/raw/main/src/Rome-30m-DEM.tif) using the " ⛰" button, and the app will calculate a target resolution for the simulated sensor data of a drone at latitude 41.801 N, 12.6483 E, 500m Altitude, 315° Azimuth, 20° Camera depression
For information on how to clip a GeoTIFF file of a customized area, see [this link](https://github.com/mkrupczak3/OpenAthena/blob/main/EIO_fetch_geotiff_example.md).

![screenshot OpenAthenaAndroid simulated target calc](./assets/simulated_calc_demo.png)
Load the DEM file, e.g. [cobb.tif](https://github.com/mkrupczak3/OpenAthena/raw/main/src/cobb.tif) using the " ⛰" button (NOTE: during file selection, the thumbnail preview for any GeoTIFF ".tif" file will be blank. This is normal.), and the app will display the size of the file as well as its Latitude and Longitude boundaries:


![OpenAthena Android GeoTIFF DEM loading demo using cobb.tif](./assets/cobb_tif_DEM_Loading_Demo.png)


## JPG Drone sensor metadata parsing

**TBD**
This prototype version can only read sensor metadata from images taken by a DJI drone. The lat/lon/alt location information is acquired from the less-accurate EXIF tags of the image instead of its XMP metadata, so it should not be relied on for accuracy. The camera gimbal's azimuth and angle of depression is obtained from XMP metadata.

After loading a GeoTIFF DEM using the " ⛰" button, use the "🖼" button to select a drone image containing the necessary metadata. Then press the "🧮" button to calculate the target location on the ground:

![OpenAthena Android Target Calculation demo using cobb.tif and DJI_0419.JPG](./assets/DJI_0419_Target_Res_Demo.png)

## Live Telemetry from DJI-SDK

Expand Down
12 changes: 10 additions & 2 deletions app/src/main/java/com/openathena/GeoTIFFParser.java
Original file line number Diff line number Diff line change
Expand Up @@ -64,8 +64,8 @@ public void loadGeoTIFF(File geofile) throws IllegalArgumentException {
try {
tiffImage = TiffReader.readTiff(geofile);
} catch (IOException e) {
Log.d("IOException", "Failed to read geofile: " + e.getMessage());
return;
Log.e(TAG, "Failed to read geofile: " + e.getMessage());
throw new IllegalArgumentException(e.getMessage());
}

directories = tiffImage.getFileDirectories();
Expand Down Expand Up @@ -153,6 +153,14 @@ public static byte[] floatToBytes(float[] floats) {
public double getXResolution() {
return xParams.stepwiseIncrement;
}
public double getYResolution() { return yParams.stepwiseIncrement; }
public long getNumCols() { return xParams.numOfSteps; }
public long getNumRows() { return yParams.numOfSteps; }
public double getMinLon() { return Math.min(xParams.end, xParams.start); }
public double getMaxLon() { return Math.max(xParams.end, xParams.start); }
public double getMinLat() { return Math.min(yParams.end, yParams.start); }
public double getMaxLat() { return Math.max(yParams.end, yParams.start); }


public double getAltFromLatLon(double lat, double lon) throws RequestedValueOOBException {
if (geofile == null || rasters == null || xParams == null || yParams == null) {
Expand Down
92 changes: 57 additions & 35 deletions app/src/main/java/com/openathena/MainActivity.java
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,10 @@
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.math.RoundingMode;
import java.text.DecimalFormat;

import mil.nga.tiff.util.TiffException;

public class MainActivity extends AppCompatActivity {

Expand Down Expand Up @@ -203,10 +207,6 @@ private void imageSelected(Uri uri)
iView.setImageURI(uri);

appendLog("Selected image "+imageUri+"\n");


//appendText("Image selected "+aPath+"\n");
//appendLog("Image selected "+aPath+"\n");
}

private void demSelected(Uri uri) {
Expand All @@ -230,24 +230,33 @@ private void demSelected(Uri uri) {
// For example, you can show an error message to the user
// or log the error to Crashlytics
Log.d(TAG, "FileNotFound demSelected()");
return;
} catch (IOException e) {
// Handle other IOException here
// For example, you can log the error to Crashlytics
e.printStackTrace();
return;
}
demUri = Uri.fromFile(fileInCache);

GeoTIFFParser parser = new GeoTIFFParser(fileInCache);
theParser = parser;
TargetGetter tgetty = new TargetGetter(parser);
theTGetter = tgetty;
Toast.makeText(MainActivity.this, "Loading GeoTIFF. Please wait...", Toast.LENGTH_SHORT).show();

try {
double[] result = tgetty.resolveTarget(41.801d, 12.6483, 500.0d, 315.0d, 20.0d);
appendText("Target found at " + result[1] + ", " + result[2] + " Alt: " + result[3]);
} catch (RequestedValueOOBException e) {
Log.e(TAG, "ERROR: resolveTarget ran OOB at: " + e.OOBLat + ", " +e.OOBLon);
appendText("ERROR: resolveTarget ran OOB at: " + e.OOBLat + ", " +e.OOBLon + "\n");
appendText("Please ensure your GeoTIFF DEM file covers the drone's location!\n");
GeoTIFFParser parser = new GeoTIFFParser(fileInCache);
theParser = parser;
theTGetter = new TargetGetter(parser);
String successOutput = "GeoTIFF DEM ";
// successOutput += "\"" + uri.getLastPathSegment(); + "\" ";
successOutput += "loaded. Size " + theParser.getNumCols() + "x" + theParser.getNumRows() + "\n";
successOutput += roundDouble(theParser.getMinLat()) + " ≤ lat ≤ " + roundDouble(theParser.getMaxLat()) + "\n";
successOutput += roundDouble(theParser.getMinLon()) + " ≤ lon ≤ " + roundDouble(theParser.getMaxLon()) + "\n";
appendText(successOutput);
} catch (IllegalArgumentException e) {
String failureOutput = "ERROR: failed to load DEM, " + e.getMessage() + "\n";
appendText(failureOutput);
} catch (TiffException e) {
String failureOutput = "ERROR: failed to load DEM, not a GeoTIFF \".tif\" file.\n";
appendText(failureOutput);
}
}

Expand Down Expand Up @@ -345,8 +354,8 @@ public void calculateImage(View view)
{
Drawable aDrawable;
ExifInterface exif;
String xmp_str;
XMPMeta xmpMeta;
File aFile;
String attribs = "Exif information ---\n";

clearText();
Expand All @@ -366,22 +375,11 @@ public void calculateImage(View view)
InputStream is = cr.openInputStream(imageUri);
aDrawable = iView.getDrawable();
exif = new ExifInterface(is);
appendText("Opened exif for image\n");
// xmpMeta = XMPMetaFactory.parse(new FileInputStream(getPathFromURI(imageUri)));
// appendText("parsed xmpMeta\n");
// XMPProperty absAltProp = xmpMeta.getProperty("", "drone-dji:AbsoluteAltitude");
// appendText("absAltProp: " + absAltProp);
// XMPIterator iterator = xmpMeta.iterator();
// while (iterator.hasNext()) {
// XMPPropertyInfo propInfo = (XMPPropertyInfo) iterator.next();
// String path = propInfo.getPath();
// if (path.equals("drone-dji:AbsoluteAltitude")) {
// String value = propInfo.getValue();
// Log.d(TAG, "Absolute Altitude: " + value);
// }
// iterator.skipSubtree();
// // iterator.skipSiblings();
// }
appendText("Opened EXIF for image\n");
xmp_str = exif.getAttribute(ExifInterface.TAG_XMP);
Log.i(TAG, "XMPString: " + xmp_str);
xmpMeta = XMPMetaFactory.parseFromString(xmp_str.trim());
Log.i(TAG, "parsed xmpMeta\n");
attribs += getTagString(ExifInterface.TAG_DATETIME, exif);
attribs += getTagString(ExifInterface.TAG_MAKE, exif);
attribs += getTagString(ExifInterface.TAG_MODEL, exif);
Expand All @@ -392,17 +390,35 @@ public void calculateImage(View view)
attribs += "Latitude : " + y + "\n";
attribs += "Longitude : " + x + "\n";
attribs += "Altitude : " + z + "\n";
attribs += getTagString(ExifInterface.TAG_ORIENTATION, exif);
String gimbalYawDegree = xmpMeta.getPropertyString("http://www.dji.com/drone-dji/1.0/", "GimbalYawDegree");
attribs += "GimbalYawDegree: " + gimbalYawDegree + "\n";
String gimbalPitchDegree = xmpMeta.getPropertyString("http://www.dji.com/drone-dji/1.0/", "GimbalPitchDegree");
attribs += "GimbalPitchDegree: " + gimbalPitchDegree + "\n";
if (theTGetter != null) {
try {
double[] result = theTGetter.resolveTarget(new Double(y), new Double(x), new Double(z), Double.parseDouble(gimbalYawDegree), Double.parseDouble(gimbalPitchDegree));
attribs += "Target found at " + roundDouble(result[1]) + ", " + roundDouble(result[2]) + " Alt: " + Math.round(result[3]) + "\n";
} catch (RequestedValueOOBException e) {
Log.e(TAG, "ERROR: resolveTarget ran OOB at: " + roundDouble(e.OOBLat) + ", " +roundDouble(e.OOBLon));
attribs += "ERROR: resolveTarget ran OOB at: " + roundDouble(e.OOBLat) + ", " + roundDouble(e.OOBLon) + "\n";
attribs += "Please ensure your GeoTIFF DEM file covers the drone's location!\n";
}
} else {
attribs += "Could not resolve target. Please load a GeoTIFF Digital Elevation Model \".tif\" using ⛰ button\n";
}
appendText(attribs+"\n");

// close file
is.close();
//
} catch (XMPException e) {
Log.e(TAG, e.getMessage());
e.printStackTrace();
} catch (Exception e) {
appendText("Unable to open image file to calculate: "+e+"\n");
appendText(e.getMessage());
Log.e(TAG, e.getMessage());
}


} // button click

// select image button clicked; launch chooser and get result
Expand Down Expand Up @@ -503,6 +519,12 @@ private float rationalToFloat(String str)
return numerator / denominator;
}

private String roundDouble(double d) {
DecimalFormat df = new DecimalFormat("#.######");
df.setRoundingMode(RoundingMode.HALF_UP);
return df.format(d);
}

private void appendText(final String aStr)
{
runOnUiThread(new Runnable() {
Expand Down Expand Up @@ -548,4 +570,4 @@ private void appendLog(String str)
} // appendLog()


}
}
Binary file added assets/DJI_0419_Target_Res_Demo.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/cobb_tif_DEM_Loading_Demo.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file removed assets/simulated_calc_demo.png
Binary file not shown.

0 comments on commit dd8296f

Please sign in to comment.