Distance and Bearing: Difference between revisions

m
→‎{{header|Free Pascal}}: optimized Calc_Dist_bear with precalculated sin / con values. Rearranged output
m (→‎{{header|Free Pascal}}: now extracting the data more correct)
m (→‎{{header|Free Pascal}}: optimized Calc_Dist_bear with precalculated sin / con values. Rearranged output)
Line 559:
{$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 ⟶ 569:
tLatLon = record
lat,lon:double;
sinLat,cosLat:double;
sinLon,cosLon:double;
end;
 
tDist_Dir = record
distance,bearing:double;
end;
 
Line 576 ⟶ 580:
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 ⟶ 650:
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;
close(Airports);
Writeln((T1-T0),' ms for searching ',rounds,' times of '
,cntNearest,' nearest out of ',cntAirports,' airports');
writeln(cntInserts,' inserts to find them');
writeln;
 
with FindNearest(testKoors.Koor1 do,cntAirports,20);
with myKoor do
writeln(Format('Nearest to latitude %7.5f,longitude %7.5f degrees',
[cRadToDeg*lat,cRadToDeg*lon]));
 
writeln;
Out_MinSol;
Line 768 ⟶ 874:
{{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>
 
132

edits