Skip to main content

Calculate distance flown using Java

Let's say we want to be able to calculate the distance that an aircraft flew, and over which countries it flew.

In this example, we will go through the steps necessary to recover the data from a flight and calculate the distance flown during the flight using the Tracking History API.

caution

This tutorial assumes that you are already familiar Java Maven projects.

Source code#

You can find and download the source code for this example here.

Geo filtering#

First, we will look at a specific airport, from which we will single out a specific flight to analyze.

Let's take CDG airport here. We will look at this GeoJSON representing the area of the airport:

{
"type": "FeatureCollection",
"features": [
{
"type": "Feature",
"properties": {},
"geometry": {
"type": "Polygon",
"coordinates": [
[
[
2.481443,
48.970752
],
[
2.642431,
48.970752
],
[
2.642431,
49.041694
],
[
2.481443,
49.041694
],
[
2.481443,
48.970752
]
]
]
}
}
]
}

Which is represented like that on a map:

Calling the Tracking History API and pick a flight#

Using the coordinates previously shown, we can filter the API results for the area we want:

  • Latitude range: 48.970752,49.041694 need to be South to North, so values can vary from -90 to 90.
  • Longitude range: 2.481443,2.642431 need to be West to East, so values can vary from -170 to 170.
App.java
package spire;
import java.net.URISyntaxException;
import java.util.concurrent.ExecutionException;
import java.io.IOException;
import java.util.Optional;
import java.net.URI;
import org.json.JSONObject;
import java.net.http.HttpResponse;
import java.net.http.HttpRequest;
import org.apache.http.client.utils.URIBuilder;
import java.net.http.HttpClient;
class App
{
public static void main(final String[] args) throws IOException, InterruptedException, ExecutionException, URISyntaxException {
HttpClient client = HttpClient.newHttpClient();
URI uri = new URIBuilder("https://api.airsafe.spire.com/v2/targets/history")
.addParameter("start", "2021-04-20T12:00:00Z").addParameter("end", "2021-04-20T18:30:00Z")
.addParameter("longitude_between", "2.481443,2.642431")
.addParameter("latitude_between", "48.970752,49.041694").build();
HttpRequest request = HttpRequest.newBuilder().uri(uri).header("Authorization", "Bearer <your_token>").build();
HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
Optional<String> test = response.body().lines().filter(line -> {
JSONObject obj = new JSONObject(line);
try {
JSONObject target = obj.getJSONObject("target");
return target.getString("arrival_airport_iata").equals("CDG") && target.getString("departure_airport_iata").equals("LHR");
}
catch (Exception e) {
return false;
}
}).findFirst();
}
}

Let's breakdown what we did here:

  • We queried our endpoint around CDG airport during a specific time.
  • We parsed the results and filtered out a single flight that fit the route we want (LHR to CDG).

Get the picked flight data and calculate distance flown#

Let's start by creating a new Flight class, which will fetch the single flight data, and do the calculations.

Flight.java
package spire;
import java.util.List;
import java.util.HashSet;
import java.util.ListIterator;
import java.net.URISyntaxException;
import java.io.IOException;
import java.net.URI;
import java.net.http.HttpResponse;
import java.net.http.HttpRequest;
import org.apache.http.client.utils.URIBuilder;
import java.net.http.HttpClient;
import java.util.Optional;
import org.json.JSONObject;
import java.util.ArrayList;
public class Flight
{
private ArrayList<JSONObject> flightPath;
private JSONObject targetUpdate;
public Flight(Optional<String> targetUpdateString) {
this.targetUpdate = new JSONObject(targetUpdateString.get()).getJSONObject("target");
}
public ArrayList<JSONObject> getFlightData() throws IOException, InterruptedException, URISyntaxException {
HttpClient client = HttpClient.newHttpClient();
URI uri = new URIBuilder("https://api.airsafe.spire.com/v2/targets/history").addParameter("start", this.targetUpdate.getString("departure_scheduled_time")).addParameter("end", this.targetUpdate.getString("arrival_scheduled_time")).addParameter("icao_address", this.targetUpdate.getString("icao_address")).build();
HttpRequest request = HttpRequest.newBuilder().uri(uri).header("Authorization", "Bearer <your_token>").build();
HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
ArrayList<JSONObject> flightPath = new ArrayList<JSONObject>();
response.body().lines().forEach(line -> {
JSONObject obj = new JSONObject(line);
try {
JSONObject target = obj.getJSONObject("target");
flightPath.add(target);
}
catch (Exception ex) {}
return;
});
return this.flightPath = flightPath;
}
// Please head to https://www.geodatasource.com/developers/java to get details about how to calculate distance between coordinates using a simplified sphere
public double calculateFlightDistance() {
ListIterator<JSONObject> it = this.flightPath.listIterator();
double totalDist = 0.0;
while (it.hasNext()) {
JSONObject current = it.next();
JSONObject next = it.hasNext() ? it.next() : null;
if (next != null) {
it.previous();
double theta = current.getDouble("longitude") - next.getDouble("longitude");
double dist = Math.sin(Math.toRadians(current.getDouble("latitude"))) * Math.sin(Math.toRadians(next.getDouble("latitude"))) + Math.cos(Math.toRadians(current.getDouble("latitude"))) * Math.cos(Math.toRadians(next.getDouble("latitude"))) * Math.cos(Math.toRadians(theta));
dist = Math.acos(dist);
dist = Math.toDegrees(dist);
dist = dist * 60.0 * 1.1515;
dist *= 1.609344;
totalDist += dist;
}
}
System.out.println(String.valueOf(this.flightPath.size()) + " datapoints found");
System.out.println(String.valueOf(totalDist) + " kms");
return totalDist;
}
}

Let's break down what we did here:

  • We parsed the JSON object used in the constructor parameters.
  • We fetched the flight of interest using its icao_address, departure_scheduled_time and arrival_scheduled_time.
  • We parsed each line of the answer, and then prepared a method calculateFlightDistance that calculate the distance between two sets of coordinates, counting the total for all coordinates.

Get countries flown over by the flight#

For this step to work, we will need to install the Atlas package, and add it to our Maven dependencies.

git clone https://github.com/bkiers/atlas.git
cd altas
mvn clean install
pom.xml
<dependency>
<groupId>nl.big-o</groupId>
<artifactId>atlas</artifactId>
<version>0.2.0</version>
</dependency>

We can now add an additional method to our Flight class. We will name it getFlightCountries:

Flight.java
public ArrayList<String> getFlightCountries() {
ArrayList<String> cities = new ArrayList<String>();
this.flightPath.forEach(point -> {
atlas.City city = new atlas.Atlas().find(point.getDouble("latitude"), point.getDouble("longitude"));
if (city != null) {
cities.add(city.countryCode);
}
return;
});
List<String> newList = new ArrayList<String>(new HashSet<String>(cities));
System.out.println("Countries flown over " + newList);
return cities;
}

Output#

Here is the expected output from our example:

653 datapoints found
439.83192832877035 kms
Countries flown over [FR, GB]