Distance and Bearing: Difference between revisions

m
→‎{{header|Fortran}}: added syntax highlighting
m (→‎{{header|Free Pascal}}: now extracting the data more correct)
m (→‎{{header|Fortran}}: added syntax highlighting)
 
(15 intermediate revisions by 7 users not shown)
Line 25:
<br><br>
 
 
=={{header|C++}}==
<syntaxhighlight lang="c++">
 
#include <cmath>
#include <cstdint>
#include <fstream>
#include <iomanip>
#include <iostream>
#include <numbers>
#include <regex>
#include <sstream>
#include <string>
#include <vector>
 
constexpr double RADIUS = 6'371 / 1.852; // Mean radius of the Earth in nautical miles
constexpr double RADIAN_TO_DEGREE = 180.0 / std::numbers::pi;
 
class airport {
public:
airport(std::string aName, std::string aCountry, std::string aIcao, double aLatitude, double aLongitude)
: name(aName), country(aCountry), icao(aIcao), latitude(aLatitude), longitude(aLongitude) {}
 
std::string name;
std::string country;
std::string icao;
double latitude;
double longitude;
};
 
// Convert the given string to a double, which represents an angle,
// and then convert the angle from degrees to radians
double to_double_radians(const std::string& text) {
std::istringstream stream(text);
double decimal = 0.0;
stream >> decimal;
return decimal / RADIAN_TO_DEGREE;
}
 
std::string do_replace(const std::string& text, const std::string& original, const std::string& replacement) {
return std::regex_replace(text, std::regex(original), replacement);
}
 
std::vector<std::string> split(const std::string& line, const char& delimiter) {
std::stringstream stream(line);
std::string item;
std::vector<std::string> items;
while ( std::getline(stream, item, delimiter) ) {
items.push_back(std::move(item));
}
return items;
}
 
void read_file(const std::string& file_name, std::vector<airport>& airports) {
std::ifstream airports_file(file_name);
std::string line;
while ( std::getline(airports_file, line) ) {
std::vector<std::string> sections = split(line, ',');
airport air_port(do_replace(sections[1], "\"", ""), // Remove the double quotes from the string
do_replace(sections[3], "\"", ""),
do_replace(sections[5], "\"", ""),
to_double_radians(sections[6]),
to_double_radians(sections[7]));
airports.push_back(std::move(air_port));
}
airports_file.close();
}
 
// The given angles are in radians, and the result is in nautical miles.
double distance(double phi1, double lambda1, double phi2, double lambda2) {
double a = pow(sin((phi2 - phi1) * 0.5), 2) + cos(phi1) * cos(phi2) * pow(sin((lambda2 - lambda1) * 0.5), 2);
double c = 2 * atan2(sqrt(a), sqrt(1 - a));
return RADIUS * c;
}
 
// The given angles are in radians, and the result is in degrees in the range [0, 360).
double bearing(double phi1, double lambda1, double phi2, double lambda2) {
double delta = lambda2 - lambda1;
double result = atan2(sin(delta) * cos(phi2), cos(phi1) * sin(phi2) - sin(phi1) * cos(phi2) * cos(delta));
return std::fmod(result * RADIAN_TO_DEGREE + 360.0, 360.0);
}
 
int main() {
std::vector<airport> airports;
read_file("airports.dat", airports);
 
const double plane_latitude = 51.514669 / RADIAN_TO_DEGREE;
const double plane_longitude = 2.198581 / RADIAN_TO_DEGREE;
 
std::vector<std::pair<double, uint64_t>> distances;
for ( uint64_t i = 0; i < airports.size(); ++i ) {
double dist = distance(plane_latitude, plane_longitude, airports[i].latitude, airports[i].longitude);
distances.push_back(std::make_pair(dist, i));
}
 
std::sort(distances.begin(), distances.end(),
[](auto& left, auto& right) { return left.first < right.first; });
 
std::cout << "Distance" << std::setw(9) << "Bearing" << std::setw(11) << "ICAO"
<< std::setw(20) << "Country" << std::setw(40) << "Airport" << std::endl;
std::cout << std::string(88, '-') << std::endl;
 
for ( uint32_t i = 0; i < 20; ++i ) {
auto[distance, index] = distances[i];
airport air_port = airports[index];
double bear = bearing(plane_latitude, plane_longitude, air_port.latitude, air_port.longitude);
 
std::cout << std::setw(8) << std::fixed << std::setprecision(1) << distance
<< std::setw(9) << std::setprecision(0) << std::round(bear)
<< std::setw(11) << air_port.icao << std::setw(20) << air_port.country
<< std::setw(40) << air_port.name << std::endl;
}
}
</syntaxhighlight>
{{ out }}
<pre>
Distance Bearing ICAO Country Airport
----------------------------------------------------------------------------------------
30.7 146 EBFN Belgium Koksijde Air Base
31.3 127 EBOS Belgium Ostend-Bruges International Airport
33.5 252 EGMH United Kingdom Kent International Airport
34.4 196 LFAC France Calais-Dunkerque Airport
42.6 105 EBKW Belgium Westkapelle heliport
51.6 240 EGMK United Kingdom Lympne Airport
52.8 114 EBUL Belgium Ursel Air Base
56.2 274 EGMC United Kingdom Southend Airport
56.4 163 LFQT France Merville-Calonne Airport
56.5 137 EBKT Belgium Wevelgem Airport
57.3 90 EHMZ Netherlands Midden-Zeeland Airport
58.0 235 EGMD United Kingdom Lydd Airport
59.0 309 EGUW United Kingdom RAF Wattisham
59.3 339 EGSM United Kingdom Beccles Airport
59.7 146 LFQO France Lille/Marcq-en-Baroeul Airport
62.2 250 EGKH United Kingdom Lashenden (Headcorn) Airfield
63.7 200 LFAT France Le Touquet-Côte d'Opale Airport
64.2 262 EGTO United Kingdom Rochester Airport
66.2 149 LFQQ France Lille-Lesquin Airport
68.4 272 EGMT United Kingdom Thurrock Airfield
</pre>
=={{header|Fortran}}==
<syntaxhighlight lang="fortran">
program code_translation
use iso_fortran_env , only:real64 , real32
use helpers
implicit none
integer :: i
character(len = 300) :: input_string
character(len = *) , parameter :: filnam = "airports.csv"
character(len = *) , parameter :: delimiter = ","
character(len = 100) :: tokens(20)
integer :: num_tokens
integer :: iostat , counter
type(airport) , allocatable :: airports(:)
type(whereme) :: location
integer :: ii , jj
real(real64) :: dist
location%latitude = (51.514669D0)!Rosetta co-ords
location%longitude = (2.19858D0)
!Nearest to latitude 51.51467,longitude 2.19858 degrees
!
!Open the file for reading
open(unit = 10 , file = 'airports.csv' , status = 'OLD' , &
&action = 'READ' , iostat = iostat , encoding = 'UTF-8')
if( iostat/=0 )stop 'Could not open file'
counter = 0
do
read(10 , '(a)' , end = 100)input_string
counter = counter + 1
end do
100 continue ! Now we know how many elements there are
rewind(unit = 10)
write(*, '(a,1x,i0,1x,a)') 'Scanning',counter,'lines'
allocate(airports(counter))
call system_clock(count = ii)
do i = 1 , counter
read(10 , '(a)' , end = 200)input_string
call tokenizes(input_string , tokens , num_tokens , ',')
read(tokens(1) , *)airports(i)%airportid
airports(i)%name = trim(adjustl(tokens(2)))
airports(i)%city = trim(adjustl(tokens(3)))
airports(i)%country = trim(adjustl(tokens(4)))
airports(i)%iata = trim(adjustl(tokens(5)))
airports(i)%icao = trim(adjustl(tokens(6)))
read(tokens(7) , '(f20.16)')airports(i)%latitude
read(tokens(8) , '(F20.16)')airports(i)%longitude
read(tokens(9) , *)airports(i)%altitude
read(tokens(10) , '(F5.2)' )airports(i)%timezone
airports(i)%dst = trim(adjustl(tokens(11)))
airports(i)%tzolson = trim(adjustl(tokens(12)))
airports(i)%typez = trim(adjustl(tokens(13)))
airports(i)%source = trim(adjustl(tokens(14)))
! Calculate the distance and bearing straight away
airports(i)%distance = haversine(location%latitude , &
& location%longitude , airports(i)%latitude ,&
& airports(i)%longitude)
airports(i)%bearing = bearing(location%latitude , &
& location%longitude , airports(i)%latitude , &
& airports(i)%longitude)
end do
200 continue
call system_clock(count = jj)
write(* , *) 'Read complete, time taken = ' , (jj - ii) , &
& 'milliseconds' // char(10) // char(13)
call sortem(airports) ! Sort the airports out
write(*, '(/,2x,a,t14,a,t75,a,t95,a,t108,a,t117,a)') 'Num' , 'Name' , &
&'Country' , 'ICAO' , 'Dist.' , 'Bearing'
write(*, '(a)') repeat('=' , 130)
do jj = 1 , 20!First 20 only
write(*, '(i5,t8,a,t75,a,t95,a,t105,f8.1,t117,i0)') airports(jj) &
& %airportid , airports(jj)%name , airports(jj)%country , &
& airports(jj)%icao , airports(jj)%distance , &
& nint(airports(jj)%bearing)
end do
stop 'Normal completion' // char(10) // char(13)
end program code_translation
module helpers
use iso_fortran_env , only:real32,real64
implicit none
real(real64) , parameter :: radius_in_km = 6372.8D0
real(real64) , parameter :: kilos_to_nautical = 0.5399568D0
type whereme
real(real64) :: latitude , longitude
end type whereme
type airport
integer :: airportid
character(len = 100) :: name
character(len = 50) :: city , country
character(len = 10) :: iata , icao
real(real64) :: latitude , longitude
integer :: altitude
real(real32) :: timezone
character(len = 10) :: dst
character(len = 100) :: tzolson
character(len = 20) :: typez , source
real(real64) :: distance , bearing
end type airport
contains ! We'll calculate them and store in each airport
!
! The given angles are in radians, and the result is in degrees in the range [0, 360).
function bearing(lat1 , lon1 , lat2 , lon2)
real(real64) , parameter :: toradians = acos( - 1.0D0)/180.0D0
real(real64) :: bearing
real(real64) , intent(in) :: lat1
real(real64) , intent(in) :: lon1
real(real64) , intent(in) :: lat2
real(real64) , intent(in) :: lon2
real(real64) :: dlat
real(real64) :: dlon
real(real64) :: rlat1
real(real64) :: rlat2
real(real64) :: x
real(real64) :: y
!
dlat = (lat2 - lat1)*toradians
dlon = toradians*(lon2 - lon1)
rlat1 = toradians*(lat1)
rlat2 = toradians*(lat2)
!
x = cos(rlat2)*sin(dlon)
y = cos(rlat1)*sin(rlat2) - sin(rlat1)*cos(rlat2)*cos(dlon)
bearing = atan2(x , y)
bearing = to_degrees(bearing)
bearing = mod(bearing + 360.0D0 , 360.0D0)
end function bearing
!
!
function to_radian(degree) result(rad)
real(real64) , parameter :: deg_to_rad = atan(1.0D0)/45.0D0 ! exploit intrinsic atan to generate pi/180 runtime constant
!
real(real64) :: rad
real(real64) , intent(in) :: degree
! degrees to radians
rad = degree*deg_to_rad
end function to_radian
!
function to_degrees(radians) result(deg)
real(real64) , parameter :: radian_to_degree = 180.0D0/acos( - 1.0D0)
!
real(real64) :: deg
real(real64) , intent(in) :: radians
deg = radians*radian_to_degree
end function to_degrees
!
function haversine(deglat1 , deglon1 , deglat2 , deglon2) result(dist)
real(real64) :: dist
real(real64) , intent(in) :: deglat1
real(real64) , intent(in) :: deglon1
real(real64) , intent(in) :: deglat2
real(real64) , intent(in) :: deglon2
real(real64) :: a
real(real64) :: c
real(real64) :: dlat
real(real64) :: dlon
real(real64) :: lat1
real(real64) :: lat2
! great circle distance
dlat = to_radian(deglat2 - deglat1)
dlon = to_radian(deglon2 - deglon1)
lat1 = to_radian(deglat1)
lat2 = to_radian(deglat2)
a = (sin(dlat/2.0D0)**2) + cos(lat1)*cos(lat2) &
& *((sin(dlon/2.0D0))**2)
c = 2.0D0*asin(sqrt(a))
dist = radius_in_km*c*kilos_to_nautical
end function haversine
subroutine sortem(airports)!Bubble sort them, nice and easy
type(airport) , intent(inout) , dimension(:) :: airports
integer :: i
integer :: k
logical :: swapped
type(airport) :: temp
swapped = .true.
k = size(airports%distance)
do while ( swapped )
swapped = .false.
do i = 1 , k - 1
if( airports(i)%distance>airports(i + 1)%distance )then
temp = airports(i)
airports(i) = airports(i + 1)
airports(i + 1) = temp
swapped = .true.
end if
end do
end do
return
end subroutine sortem
!
subroutine tokenizes(input_string , tokens , num_tokens , delimiter)
character(*) , intent(in) :: input_string
character(*) , intent(out) , dimension(:) :: tokens
integer , intent(out) :: num_tokens
character(1) , intent(in) :: delimiter
integer :: end_idx
integer :: i
integer :: start_idx
character(100) :: temp_string
num_tokens = 0
temp_string = trim(input_string)
start_idx = 1
do i = 1 , len_trim(temp_string)
if( (temp_string(i:i)==delimiter) )then
end_idx = i - 1
if( end_idx>=start_idx )then
num_tokens = num_tokens + 1
tokens(num_tokens) = ''
tokens(num_tokens) = temp_string(start_idx:end_idx)
end if
start_idx = i + 1
end if
end do
! Handle the last token
if( start_idx<=len_trim(temp_string) )then
num_tokens = num_tokens + 1
tokens(num_tokens) = temp_string(start_idx:len_trim( &
& temp_string))
end if
end subroutine tokenizes
!
end module helpers
!
</syntaxhighlight>
{{out}}
<small>Scanning 7698 lines
Read complete, time taken = 93 milliseconds
Num Name Country ICAO Dist. Bearing
==================================================================================================================================
306 Koksijde Air Base Belgium EBFN 30.7 146
310 Ostend-Bruges International Airport Belgium EBOS 31.3 127
510 Kent International Airport United Kingdom EGMH 33.6 252
1254 Calais-Dunkerque Airport France LFAC 34.4 196
7810 Westkapelle heliport Belgium EBKW 42.6 105
6886 Lympne Airport United Kingdom EGMK 51.6 240
314 Ursel Air Base Belgium EBUL 52.8 114
508 Southend Airport United Kingdom EGMC 56.2 274
1400 Merville-Calonne Airport France LFQT 56.4 163
308 Wevelgem Airport Belgium EBKT 56.5 137
7836 Midden-Zeeland Airport Netherlands EHMZ 57.3 90
509 Lydd Airport United Kingdom EGMD 58.0 235
558 RAF Wattisham United Kingdom EGUW 59.0 309
8965 Beccles Airport United Kingdom EGSM 59.3 339
10089 Lille/Marcq-en-Baroeul Airport France LFQO 59.7 146
10745 Lashenden (Headcorn) Airfield United Kingdom EGKH 62.2 250
1259 Le Touquet-Côte d'Opale Airport France LFAT 63.7 200
8894 Rochester Airport United Kingdom EGTO 64.2 262
1399 Lille-Lesquin Airport France LFQQ 66.3 149
10747 Thurrock Airfield United Kingdom EGMT 68.4 272</small>
 
=={{header|J}}==
Line 89 ⟶ 478:
Thurrock Airfield United Kingdom EGMT 68.4 272
</pre>
 
=={{header|Java}}==
'''Author'''
Line 457 ⟶ 847:
19 │ Lille-Lesquin Airport France LFQQ 66.2 149
20 │ Thurrock Airfield United Kingdom EGMT 68.4 272
</pre>
 
=={{header|Nim}}==
<syntaxhighlight lang="Nim">import std/[algorithm, math, parsecsv, strformat, strutils]
 
const
R = 6_371 / 1.852 # Mean radius of Earth in nautic miles.
PlaneLat = 51.514669
PlaneLong = 2.198581
 
type
 
Airport = object
name: string
country: string
icao: string
latitude: float
longitude: float # In radians.
altitude: float # In radians.
 
func distance(𝜑₁, λ₁, 𝜑₂, λ₂: float): float =
## Return the distance computed using the Haversine formula.
## Angles are in radians. The result is expressed in nautic miles.
let a = sin((𝜑₂ - 𝜑₁) * 0.5)^2 + cos(𝜑₁) * cos(𝜑₂) * sin((λ₂ - λ₁) * 0.5)^2
let c = 2 * arctan2(sqrt(a), sqrt(1 - a))
result = R * c
 
func bearing(𝜑₁, λ₁, 𝜑₂, λ₂: float): float =
## Return the bearing.
## Angles are in radians. The result is expressed in degrees in range [0..360[.
let Δλ = λ₂ - λ₁
result = arctan2(sin(Δλ) * cos(𝜑₂), cos(𝜑₁) * sin(𝜑₂) - sin(𝜑₁) * cos(𝜑₂) * cos(Δλ))
result = (result.radToDeg + 360) mod 360
 
# Parse the "airports.dat" file.
var parser: CsvParser
var airports: seq[Airport]
parser.open("airports.dat")
while parser.readRow():
assert parser.row.len == 14
airports.add Airport(name: parser.row[1],
country: parser.row[3],
icao: parser.row[5],
latitude: parser.row[6].parseFloat().degToRad,
longitude: parser.row[7].parseFloat().degToRad)
 
# Compute the distances then sort them keeping the airport index.
type Distances = tuple[value: float; index: int]
var distances : seq[Distances]
let 𝜑₁ = PlaneLat.degToRad
let λ₁ = PlaneLong.degToRad
for i, airport in airports:
distances.add (distance(𝜑₁, λ₁, airport.latitude, airport.longitude), i)
distances.sort(Ascending)
 
# Display the result for the 20 nearest airports.
echo &"""{"Airport":<40}{"Country":<20}{"ICAO":<9}{"Distance":<9}{"Bearing":>9}"""
echo repeat("─", 88)
for i in 0..19:
let (d, idx) = distances[i]
let ap = airports[idx]
let b = bearing(𝜑₁, λ₁, ap.latitude, ap.longitude)
echo &"{ap.name:<40}{ap.country:<20}{ap.icao:<11}{d:4.1f}{b.toInt:10}"
</syntaxhighlight>
 
{{out}}
<pre>Airport Country ICAO Distance Bearing
────────────────────────────────────────────────────────────────────────────────────────
Koksijde Air Base Belgium EBFN 30.7 146
Ostend-Bruges International Airport Belgium EBOS 31.3 127
Kent International Airport United Kingdom EGMH 33.5 252
Calais-Dunkerque Airport France LFAC 34.4 196
Westkapelle heliport Belgium EBKW 42.6 105
Lympne Airport United Kingdom EGMK 51.6 240
Ursel Air Base Belgium EBUL 52.8 114
Southend Airport United Kingdom EGMC 56.2 274
Merville-Calonne Airport France LFQT 56.4 163
Wevelgem Airport Belgium EBKT 56.5 137
Midden-Zeeland Airport Netherlands EHMZ 57.3 90
Lydd Airport United Kingdom EGMD 58.0 235
RAF Wattisham United Kingdom EGUW 59.0 309
Beccles Airport United Kingdom EGSM 59.3 339
Lille/Marcq-en-Baroeul Airport France LFQO 59.7 146
Lashenden (Headcorn) Airfield United Kingdom EGKH 62.2 250
Le Touquet-Côte d'Opale Airport France LFAT 63.7 200
Rochester Airport United Kingdom EGTO 64.2 262
Lille-Lesquin Airport France LFQQ 66.2 149
Thurrock Airfield United Kingdom EGMT 68.4 272
</pre>
 
=={{header|PARI/GP}}==
<syntaxhighlight lang="parigpc">/* copy CSV aiports.dat from URL */
csv=externstr("curl 'https://raw.githubusercontent.com/jpatokal/openflights/master/data/airports.dat'");
 
Line 559 ⟶ 1,037:
{$IFDEF FPC} {$Mode DELPHI}{$Optimization ON,ALL} {$ENDIF}
{$IFDEF WINDOWS}{$APPTYPE CONSOLE}{$ENDIF}
 
uses
SysUtils,Math;
const
MAXSOLCOUNT = 20;
cDegToRad = pi / 180; cRadToDeg = 180 / pi;
//One nautical mile ( 1" of earth circumfence )
Line 571 ⟶ 1,047:
tLatLon = record
lat,lon:double;
sinLat,cosLat:double;
sinLon,cosLon:double;
end;
 
tDist_Dir = record
distance,bearing:double;
end;
 
Line 576 ⟶ 1,058:
Koor1,
Koor2 : tLatLon;
distance,Dist_Dir : tDist_Dir;
bearing : double;
end;
 
tmyName = String; //string[63-8] experiment
tmyCountry = String; //string[31]
tmyICAO = String; //string[7]
tSolution = record
Sol_Name, : tmyName;
Sol_Country, :tmyCountry;
Sol_ICAO : AnsiStringtmyICAO;
Sol_Koor : tLatLon;
Sol_distance,Sol_dist_dir:tDist_Dir;
Sol_bearing : double;
end;
 
tIdxDist = record
Distance: double;
AirportIdx :Int32;
end;
tMinSols = record
sols : array[1..MAXSOLCOUNT+1] of tSolutiontIdxDist;
maxValue: double;
maxidx :integer;actIdx,
maxidx :Int32;
end;
 
var
Airports: array of tSolution;
MinSols :tMinSols;
cntInserts : Cardinal;
 
procedure Init_MinSolGetSolData(const OneAirport: String;
begin
MinSols.maxIdx := 0;
MinSols.MaxValue := maxdouble;
cntInserts := 0;
end;
 
procedure Out_MinSol;
var
i: integer;
begin
writeln('Airport Country ICAO Distance Bearing');
writeln('----------------------------------- -------------- ---- -------- -------');
For i := 1 to minSols.Maxidx do
with minSols.sols[i] do
writeln(Format('%-35s %-14s %4s %8.1f %7.0f',
[Sol_Name,Sol_Country,Sol_ICAO,Sol_distance*DiaEarth,Sol_bearing*cRadToDeg]));
writeln;
writeln(cntInserts,' inserts to find them');
end;
 
procedure Insert_Sol(var sol:TSolution);
var
idx : integer;
begin
idx := MinSols.maxIdx;
if Idx >= MAXSOLCOUNT then
IF MinSols.MaxValue < sol.Sol_distance then
Exit;
if idx > 0 then
begin
inc(idx);
inc(cntInserts);
while MinSols.sols[idx-1].Sol_distance >sol.Sol_distance do
begin
MinSols.sols[idx]:= MinSols.sols[idx-1];
dec(idx);
If idx< 1 then
BREAK;
end;
MinSols.sols[idx] := sol;
if MinSols.maxIdx < MAXSOLCOUNT then
MinSols.maxIdx +=1;
end
else
begin
MinSols.sols[1] := sol;
MinSols.maxIdx := 1;
end;
MinSols.MaxValue := MinSols.sols[MinSols.maxIdx].Sol_distance;
end;
 
procedure GetSolData(const OneAirport: AnsiString;
var TestSol :tSolution);
var
Line 691 ⟶ 1,128:
4: Sol_Country := copy(OneAirport,i1,i2-i1);
6: Sol_ICAO := copy(OneAirport,i1,i2-i1);
7: Begin
7: Sol_Koor.lat := StrtoFloat(copy(OneAirport,i1,i2-i1))*cDegToRad;
8: With Sol_Koor.lon :=do StrtoFloat(copy(OneAirport,i1,i2-i1))*cDegToRad;begin
lat := StrtoFloat(copy(OneAirport,i1,i2-i1))*cDegToRad;
sincos(lat,sinLat,cosLat);
end;
end;
8: Begin
With Sol_Koor do begin
lon := StrtoFloat(copy(OneAirport,i1,i2-i1))*cDegToRad;
sincos(lon,sinLon,cosLon);
end;
end;
end;
p1:= p2+1;
until (idx>7) OR (p1>l);
end;
 
function ReadAirports(fileName:String):boolean;
var
TF_Buffer : array[0..1 shl 14 -1] of byte;
AirportsFile: TextFile;
OneAirport : String;
l,cnt : UInt32;
begin
Assign(AirportsFile,fileName);
settextbuf(AirportsFile,TF_Buffer);
{$I-}
reset(AirportsFile);
{$I+}
IF ioResult <> 0 then
Begin
Close(AirportsFile);
EXIT(false);
end;
cnt := 0;
l := 100;
setlength(Airports,l);
 
while Not(EOF(AirportsFile)) do
Begin
Readln(AirportsFile,OneAirport);
GetSolData(OneAirport,Airports[cnt]);
inc(cnt);
if cnt >= l then
Begin
l := l*13 div 8;
setlength(Airports,l);
end;
end;
setlength(Airports,cnt);
Close(AirportsFile);
exit(true);
end;
 
procedure Out_MinSol;
var
i: integer;
begin
writeln(' ICAO Distance Bearing Country Airport');
writeln(' ---- -------- ------- -------------- -----------------------------------');
For i := 0 to minSols.actidx do
with AirPorts[minSols.sols[i].AirportIdx] do
writeln(Format(' %4s %8.1f %7.0f %-14s %-35s',
[Sol_ICAO,
Sol_dist_dir.distance*DiaEarth,
Sol_dist_dir.bearing*cRadToDeg,
Sol_Country,Sol_Name]));
writeln;
writeln(cntInserts,' inserts to find them');
end;
 
procedure Init_MinSol(MaxSolCount:Int32);
begin
setlength(MinSols.sols,MaxSolCount+1);
MinSols.actIdx := -1;
MinSols.maxIdx := MaxSolCount-1;
MinSols.MaxValue := maxdouble;
cntInserts := 0;
end;
 
procedure Insert_Sol(var sol:tDst_Bear;nrAirport:Int32);
var
dist : double;
idx : Int32;
begin
with MinSols do
begin
idx := actIdx;
dist := sol.Dist_Dir.distance;
 
if Idx >= maxIdx then
IF MaxValue < dist then
Exit;
 
if idx >= 0 then
begin
inc(idx);
inc(cntInserts);
 
while sols[idx-1].Distance >dist do
begin
sols[idx]:= sols[idx-1];
dec(idx);
If idx<=0 then
BREAK;
end;
with sols[idx] do
begin
AirportIdx := nrAirport;
Distance := dist;
end;
//update AirPorts[nrAirport] with right distance/bearing
AirPorts[nrAirport].Sol_dist_dir := sol.Dist_Dir;
if actIdx < maxIdx then
actIdx +=1;
end
else
begin
with sols[0] do
begin
AirportIdx := nrAirport;
Distance := dist;
end;
AirPorts[nrAirport].Sol_dist_dir := sol.Dist_Dir;
MinSols.actIdx := 0;
end;
MaxValue := sols[actIdx].Distance;
end;
end;
 
procedure Calc_Dist_bear(var Dst_Bear:tDst_Bear);
var
dLondLonSin,dLonCos,x,y : double;
begin
with Dst_Bear do
beginBegin
distance := 0;
bearing := 0;
If (Koor1.Lat = Koor2.Lat) AND (Koor1.Lon = Koor2.Lon) then
Begin
Dist_Dir.distance := 0;
Dist_Dir.bearing := 0;
Exit;
end;
dLon:= Koor1.lon - Koor2.lon;
sincos(Koor1.lon - Koor2.lon,dLonSin,dLonCos);
distance := arcsin(sqrt(sqr(cos(dLon) * cos( Koor1.lat)
//distance
- cos(Koor2.lat)) + sqr(sin(dLon)
Dist_Dir.distance := arcsin(sqrt(sqr(dLonCos * Koor1.Coslat
* cos(Koor1.lat)) + sqr(sin(Koor1.lat) - sin(Koor2.lat))) / 2);
- Koor2.Coslat) + sqr(dLonSin* Koor1.Coslat)
+ sqr(Koor1.sinlat - Koor2.sinlat)) / 2);
 
x := sin(dlon)dLonSin*cos(Koor2.lat)Coslat;
y := cos(Koor1.lat)Coslat*sin(Koor2.lat)sinlat - sin(Koor1.lat)sinlat*cos(Koor2.lat)Coslat*cos(dlon)dLonCos;
//bearing :=dLonSin ArcTan2(x,y);as tmp
dLonSin := ArcTan2(x,y);
if bearing < 0 then
if dLonSin bearing< :=0 -bearingthen
dLonSin := -dLonSin
else
bearingdLonSin := 2*pi-bearingdLonSin;
Dist_Dir.bearing := dLonSin;
end;
end;
end;
 
procedure FindNearest(var testKoors : tDst_Bear;cntAirports,cntNearest:Integer);
var
Airportsi : TextFileInt32;
begin
TF_Buffer : array[0..1 shl 14 -1] of byte;
Init_MinSol(cntNearest);
OneAirport : AnsiString;
For i := 0 to cntAirports-1 do
Begin
testKoors.Koor2 := AirPorts[i].Sol_Koor;
Calc_Dist_bear(testKoors);
Insert_Sol(testKoors,i);
end;
end;
 
const
rounds = 100;
cntNearest = 20;//128;//8000;
var
T1,T0 : Int64;
testKoors : tDst_Bear;
TestSolmyKoor :tSolution tLatLon;
i,cntAirports : integer;
begin
 
with testKoors.Koor1 do
 
T0 := Gettickcount64;
IF NOT(ReadAirports('airports.dat')) then
HALT(129);
T1 := Gettickcount64;
Writeln((T1-T0),' ms for reading airports.dat');
cntAirports := length(AirPorts);
 
with myKoor do
begin
lat := 51.514669*cDegToRad;
lon := 2.198581*cDegToRad;
sincos(lat,sinLat,cosLat);
sincos(lon,sinLon,cosLon);
end;
//'airports.dat'on SSD (reads via Readln(Airports,OneAirport) ~ 1 GB/s )
Assign(Airports,'airports.dat');
//speedup 10%
settextbuf(Airports,TF_Buffer);
 
randomize;
For i := 0{99} downto 0 do begin
T0 := Gettickcount64;
reset(Airports);
For i := rounds-2 downto 0 do
Init_MinSol;
while Not(EOF(Airports)) do
Begin
testKoors.Koor1 := AirPorts[random(cntAirports)].Sol_Koor;
Readln(Airports,OneAirport);
FindNearest(testKoors,cntAirports,cntNearest);
GetSolData(OneAirport,TestSol);
testKoors.Koor2 := TestSol.Sol_Koor;
Calc_Dist_bear(testKoors);
TestSol.Sol_distance:= testKoors.distance;
TestSol.Sol_bearing:= testKoors.bearing;
Insert_Sol(TestSol);
end;
testKoors.Koor1 := myKoor;
end;
FindNearest(testKoors,cntAirports,cntNearest);
T1 := Gettickcount64;
Writeln((T1-T0),' ms for searching ',rounds,' times of '
,cntNearest,' nearest out of ',cntAirports,' airports');
writeln(cntInserts,' inserts to find them');
writeln;
 
FindNearest(testKoors,cntAirports,20);
close(Airports);
with myKoor do
 
with testKoors.Koor1 do
writeln(Format('Nearest to latitude %7.5f,longitude %7.5f degrees',
[cRadToDeg*lat,cRadToDeg*lon]));
 
writeln;
Out_MinSol;
Line 768 ⟶ 1,352:
{{out}}
<pre>
7 ms for reading airports.dat
125 ms for searching 100 times of 20 nearest out of 7698 airports
144 inserts to find them
 
Nearest to latitude 51.51467,longitude 2.19858 degrees
 
Airport ICAO Distance Bearing Country ICAO Distance BearingAirport
---- -------- ------- -------------- -- -------------- ---- -------- -------
Koksijde Air Base EBFN 30.6 146 Belgium EBFN Koksijde Air 30.6 146Base
EBOS 31.3 127 Belgium Ostend-Bruges International Airport
Ostend-Bruges International Airport Belgium EBOS 31.3 127
Kent EGMH International Airport 33.5 252 United Kingdom EGMH Kent International 33.5 252Airport
Calais-Dunkerque Airport LFAC 34.4 196 France LFAC Calais-Dunkerque 34.4 196Airport
Westkapelle heliport EBKW 42.5 105 Belgium EBKW Westkapelle 42.5 105heliport
Lympne Airport EGMK 51.6 240 United Kingdom EGMK Lympne 51.6 240Airport
Ursel Air Base EBUL 52.8 114 Belgium EBUL Ursel Air 52.8 114Base
Southend Airport EGMC 56.2 274 United Kingdom EGMC Southend 56.2 274Airport
Merville-Calonne Airport LFQT 56.3 163 France LFQT Merville-Calonne 56.3 163Airport
Wevelgem Airport EBKT 56.4 137 Belgium EBKT Wevelgem 56.4 137Airport
Midden-Zeeland Airport EHMZ 57.2 90 Netherlands EHMZ Midden-Zeeland 57.2 90Airport
Lydd Airport EGMD 58.0 235 United Kingdom EGMD Lydd 58.0 235Airport
RAF Wattisham EGUW 58.9 309 United Kingdom EGUW RAF 58.9 309Wattisham
Beccles Airport EGSM 59.3 339 United Kingdom EGSM Beccles 59.3 339Airport
Lille/Marcq-en-Baroeul LFQO Airport 59.6 France 146 France LFQO 59.6Lille/Marcq-en-Baroeul 146Airport
Lashenden EGKH (Headcorn) Airfield 62.2 250 United Kingdom EGKH Lashenden (Headcorn) 62.2 250Airfield
Le LFAT Touquet-Côte d'Opale Airport 63.7 France 200 France LFAT 63.7Le Touquet-Côte d'Opale 200Airport
Rochester Airport EGTO 64.2 262 United Kingdom EGTO Rochester 64.2 262Airport
Lille-Lesquin Airport LFQQ 66.2 149 France LFQQ Lille-Lesquin 66.2 149Airport
Thurrock Airfield EGMT 68.4 272 United Kingdom EGMT Thurrock 68.4 272Airfield
 
144 inserts to find them
 
//first run after boot
real 0m0.011s user 0m0.010s sys 0m0.000s
 
real 0m0.134s
100 turns
//test nearest 128
(only Readln(Airports,OneAirport);
7 ms for reading airports.dat
real 0m0.109s user 0m0.105s sys 0m0.004s
131 ms for searching 100 times of 128 nearest out of 7698 airports
(full run, only one output)
602 inserts to find them
real 0m0.899s user 0m0.887s sys 0m0.012s
//test nearest of all -> sort all for distance
real 0m0.913s user 0m0.905s sys 0m0.008s
7 ms for reading airports.dat
1440 ms for searching 100 times of 8000 nearest out of 7698 airports
7697 inserts to find them
</pre>
 
Line 1,138 ⟶ 1,724:
66.3 149 LFQQ France Lille-Lesquin Airport
68.4 271 EGMT United Kingdom Thurrock Airfield</pre>
=={{header|Ruby}}==
<syntaxhighlight lang="ruby">require 'open-uri'
require 'csv'
include Math
 
RADIUS = 6372.8 # rough radius of the Earth, in kilometers
 
def spherical_distance(start_coords, end_coords)
lat1, long1 = deg2rad(*start_coords)
lat2, long2 = deg2rad(*end_coords)
2 * RADIUS * asin(sqrt(sin((lat2-lat1)/2)**2 + cos(lat1) * cos(lat2) * sin((long2 - long1)/2)**2))
end
 
def bearing(start_coords, end_coords)
lat1, long1 = deg2rad(*start_coords)
lat2, long2 = deg2rad(*end_coords)
dlon = long2 - long1
atan2(sin(dlon) * cos(lat2), cos(lat1) * sin(lat2) - sin(lat1) * cos(lat2) * cos(dlon))
end
 
def deg2rad(lat, long)
[lat * PI / 180, long * PI / 180]
end
 
uri = "https://raw.githubusercontent.com/jpatokal/openflights/master/data/airports.dat"
headers = %i(airportID
name
city
country
iata
icao
latitude
longitude
altitude
timezone
dst
tzOlson
type
source)
data = CSV.parse(URI.open(uri), headers: headers, converters: :numeric)
 
position = [51.514669, 2.198581]
 
data.each{|r| r[:dist] = (spherical_distance(position, [r[:latitude], r[:longitude]])/1.852).round(1)}
closest = data.min_by(20){|row| row[:dist] }
closest.each do |r|
bearing = (bearing(position,[r[:latitude], r[:longitude]])*180/PI).round % 360
puts "%-40s %-25s %-6s %12.1f %15.0f" % (r.values_at(:name, :country, :ICAO, :dist) << bearing)
end
</syntaxhighlight>
{{out}}
<pre>Koksijde Air Base Belgium 30.7 146
Ostend-Bruges International Airport Belgium 31.3 127
Kent International Airport United Kingdom 33.6 252
Calais-Dunkerque Airport France 34.4 196
Westkapelle heliport Belgium 42.6 105
Lympne Airport United Kingdom 51.6 240
Ursel Air Base Belgium 52.8 114
Southend Airport United Kingdom 56.2 274
Merville-Calonne Airport France 56.4 163
Wevelgem Airport Belgium 56.5 137
Midden-Zeeland Airport Netherlands 57.3 90
Lydd Airport United Kingdom 58.0 235
RAF Wattisham United Kingdom 59.0 309
Beccles Airport United Kingdom 59.3 339
Lille/Marcq-en-Baroeul Airport France 59.7 146
Lashenden (Headcorn) Airfield United Kingdom 62.2 250
Le Touquet-Côte d'Opale Airport France 63.7 200
Rochester Airport United Kingdom 64.2 262
Lille-Lesquin Airport France 66.3 149
Thurrock Airfield United Kingdom 68.4 272
</pre>
 
=={{header|SQL}}/{{header|PostgreSQL}}==
Line 1,275 ⟶ 1,933:
{{libheader|Wren-fmt}}
However, rather than use Wren-sql, we program it so that it can be run from Wren-CLI. Runtime is about 0.24 seconds.
<syntaxhighlight lang="ecmascriptwren">import "io" for File
import "./dynamic" for Tuple
import "./str" for Str
7,805

edits