WaBis

walter.bislins.ch

Source Code: Distances on Globe and Flat Earth

This page shows the javascript code of the page Distances on Globe and Flat Earth, so you can inspect it for correctness.

#INCLUDE ControlPanel.inc

<jscript>

Model = {
  // latitude and longitude input values
  lat1: 0,
  lat1min: 0,
  lat1sec: 0,
  lng1: 0,
  lng1min: 0,
  lng1sec: 0,
  lat2: 0,
  lat2min: 0,
  lat2sec: 0,
  lng2: 0,
  lng2min: 0,
  lng2sec: 0,

  // planet sizes
  R: 6371, // km
  EQ: 6371 * Math.PI / 2,

  // computed distances
  LG: 0,
  LF: 0,

  // choosen units tables
  l_unitId: 0,  // 0 -> km, 1 -> nmi, 2 -> mi
  l_unitNameList: [ 'km', 'nmi', 'mi' ],
  l_unitName: 'km',
  l_multList: [ 1, 1.852, 1.609344 ],
  l_mult: 1000,
  l_digitsList: [ 2, 2, 2 ],
  l_digits: 2,

  ParseInput: function( inp ) {
    var neg = (inp.indexOf('S') >= 0 || inp.indexOf('s') >= 0 || inp.indexOf('W') >= 0 || inp.indexOf('w') >= 0) ? -1 : 1;
    // remove all not numeric characters
    inp = inp.replace( /,/g, '.' ).replace( /[^0-9\-\.]/g, ' ' );
    // trim
    inp = inp.replace( / +/g, ' ' ).replace( /^ /, '' ).replace( / $/, '' );
    if (inp.indexOf( '-' ) == 0) {
      neg = -1;
      inp = inp.replace( /-/g, '' );
    }
    if (inp == '') return 0;
    var parts = inp.split( ' ' );
    var res = 0;
    var fract = 1;
    for (var i = 0; i < parts.length; i++) {
      res += parseFloat( parts[i] ) / fract;
      fract *= 60;
    }
    return neg * res;
  },

  ToDMS: function() {
    // convert lat/lng from degrees to degrees, minutes and seconds
    function dms(x) {
      var d = Math.abs( x );
      var s = x < 0 ? -1 : 1;
      var r = { d: 0, m: 0, s: 0 };
      r.d = Math.floor( d );
      d = (d % 1) * 60;
      r.m = Math.floor( d );
      r.s = (d % 1) * 60;
      // check if any seconds or minutes are displayed as 60
      if (r.s >= 59.9995) {
        r.s = 0;
        r.m += 1;
        if (r.m >= 60) {
          r.m = 0;
          r.d += 1;
        }
      }
      if (s < 0) {
        if (r.d > 0) {
          r.d *= -1;
        } else if (r.m > 0) {
          r.m *= -1;
        } else {
          r.s *= -1;
        }
      }
      return r;
    };
    var s = dms( this.lat1 );
    this.lat1 = s.d;
    this.lat1min = s.m;
    this.lat1sec = s.s;
    var s = dms( this.lng1 );
    this.lng1 = s.d;
    this.lng1min = s.m;
    this.lng1sec = s.s;
    var s = dms( this.lat2 );
    this.lat2 = s.d;
    this.lat2min = s.m;
    this.lat2sec = s.s;
    var s = dms( this.lng2 );
    this.lng2 = s.d;
    this.lng2min = s.m;
    this.lng2sec = s.s;
  },

  ToDeg: function() {
    // convert lat/lng from degrees, minutes and seconds to degrees 
    var abs = Math.abs;
    var s = this.lat1 < 0 ? -1 : (this.lat1min < 0 ? -1 : (this.lat1sec < 0 ? -1 : 1 ));
    this.lat1 = s * (abs(this.lat1) + (abs(this.lat1min) + (abs(this.lat1sec) / 60)) / 60);
    this.lat1min = 0; this.lat1sec = 0;
    var s = this.lng1 < 0 ? -1 : (this.lng1min < 0 ? -1 : (this.lng1sec < 0 ? -1 : 1 ));
    this.lng1 = s * (abs(this.lng1) + (abs(this.lng1min) + (abs(this.lng1sec) / 60)) / 60);
    this.lng1min = 0; this.lng1sec = 0;
    var s = this.lat2 < 0 ? -1 : (this.lat2min < 0 ? -1 : (this.lat2sec < 0 ? -1 : 1 ));
    this.lat2 = s * (abs(this.lat2) + (abs(this.lat2min) + (abs(this.lat2sec) / 60)) / 60);
    this.lat2min = 0; this.lat2sec = 0;
    var s = this.lng2 < 0 ? -1 : (this.lng2min < 0 ? -1 : (this.lng2sec < 0 ? -1 : 1 ));
    this.lng2 = s * (abs(this.lng2) + (abs(this.lng2min) + (abs(this.lng2sec) / 60)) / 60);
    this.lng2min = 0; this.lng2sec = 0;
  },

  Update: function() {
    // checks input and updates all computed values
    this.l_mult = this.l_multList[this.l_unitId];
    this.l_digits = this.l_digitsList[this.l_unitId];
    this.l_unitName = this.l_unitNameList[this.l_unitId];

    // get latitudes and longitudes as degrees
    var cos = Math.cos, sin = Math.sin, abs = Math.abs, DegToRad = Math.PI / 180;
    var sign = this.lat1 < 0 ? -1 : 1;
    if (this.lat1 == 0) sign = this.lat1min < 0 ? -1 : 1;
    if (this.lat1 == 0 && this.lat1min == 0) sign = this.lat1sec < 0 ? -1 : 1;
    var lat1 = DegToRad * sign * (abs(this.lat1) + abs(this.lat1min) / 60 + abs(this.lat1sec) / 3600);
    var sign = this.lng1 < 0 ? -1 : 1;
    if (this.lng1 == 0) sign = this.lng1min < 0 ? -1 : 1;
    if (this.lng1 == 0 && this.lng1min == 0) sign = this.lng1sec < 0 ? -1 : 1;
    var lng1 = DegToRad * sign * (abs(this.lng1) + abs(this.lng1min) / 60 + abs(this.lng1sec) / 3600);
    var sign = this.lat2 < 0 ? -1 : 1;
    if (this.lat2 == 0) sign = this.lat2min < 0 ? -1 : 1;
    if (this.lat2 == 0 && this.lat2min == 0) sign = this.lat2sec < 0 ? -1 : 1;
    var lat2 = DegToRad * sign * (abs(this.lat2) + abs(this.lat2min) / 60 + abs(this.lat2sec) / 3600);
    var sign = this.lng2 < 0 ? -1 : 1;
    if (this.lng2 == 0) sign = this.lng2min < 0 ? -1 : 1;
    if (this.lng2 == 0 && this.lng2min == 0) sign = this.lng2sec < 0 ? -1 : 1;
    var lng2 = DegToRad * sign * (abs(this.lng2) + abs(this.lng2min) / 60 + abs(this.lng2sec) / 3600);

    // compute distance on globe
    var r = cos( lat1 );
    var v1x = cos( lng1 ) * r;
    var v1y = sin( lng1 ) * r;
    var v1z = sin( lat1 );
    var r = cos( lat2 );
    var v2x = cos( lng2 ) * r;
    var v2y = sin( lng2 ) * r;
    var v2z = sin( lat2 );
    var alpha = Math.acos( v1x * v2x + v1y * v2y + v1z * v2z ); // 0..pi
    this.LG = this.R * alpha;

    // // compute distance on flat earth
    var pi2 = Math.PI / 2;
    var r1 = (1 - lat1/pi2) * this.EQ;
    var r2 = (1 - lat2/pi2) * this.EQ;
    var x1 = r1 * cos( lng1 );
    var y1 = r1 * sin( lng1 );
    var x2 = r2 * cos( lng2 );
    var y2 = r2 * sin( lng2 );
    var dx = x2 - x1;
    var dy = y2 - y1;
    this.LF = Math.sqrt( dx*dx + dy*dy );
  }
};

function UpdateAll() {
  // will be called from ControlPanels when any input field is changed
  Model.Update();
  ControlPanels.Update();
}

// functions called from the buttons in the title bar of the input panel

function Reset() {
  ControlPanels.Reset();
  UpdateAll();
}

function ToDMS() {
  Model.ToDMS();
  UpdateAll();
}

function ToDeg() {
  Model.ToDeg();
  UpdateAll();
}

// functions called from the big buttons with departure and target

function PerthSydney() {
  Model.lat1 = -31;
  Model.lat1min = 57;
  Model.lat1sec = 1.8972;
  Model.lng1 = 115;
  Model.lng1min = 51;
  Model.lng1sec = 37.6452;

  Model.lat2 = -33;
  Model.lat2min = 52;
  Model.lat2sec = 7.752;
  Model.lng2 = 151;
  Model.lng2min = 12;
  Model.lng2sec = 33.4656;

  UpdateAll();
}

function JohannesburgPerth() {
  Model.lat1 = -26;
  Model.lat1min = 12;
  Model.lat1sec = 14.7708;
  Model.lng1 = 28;
  Model.lng1min = 2;
  Model.lng1sec = 50.298;

  Model.lat2 = -31;
  Model.lat2min = 57;
  Model.lat2sec = 1.8972;
  Model.lng2 = 115;
  Model.lng2min = 51;
  Model.lng2sec = 37.6452;

  UpdateAll();
}

function LondonMoskau() {
  Model.lat1 = 51;
  Model.lat1min = 30;
  Model.lat1sec = 26.4636;
  Model.lng1 = 0;
  Model.lng1min = -7;
  Model.lng1sec = 39.9288;

  Model.lat2 = 55;
  Model.lat2min = 45;
  Model.lat2sec = 20.9736;
  Model.lng2 = 37;
  Model.lng2min = 37;
  Model.lng2sec = 2.28;

  UpdateAll();
}

xOnLoad( UpdateAll );

</jscript>

{{scroll}}

<jscript>

// create Control Panels

ControlPanels.NewPanel( {
    ModelRef: 'Model',
    OnModelChange: UpdateAll,
    NCols: 6,
    Digits: 3,
    PanelFormat: 'LabelLeft',
  }

).AddHeader( {
    Text: '',
    ColSpan: 1
  }

).AddHeader( {
    Text: 'Latitude',
    ColSpan: 5
  }

).AddHeader( {
    Text: 'Longitude' + ControlPanels.ResetButtonR() + ControlPanels.SmallButtonR('&rarr;Deg','ToDeg()') + ControlPanels.SmallButtonR('&rarr;DMS','ToDMS()'),
    ColSpan: 6
  }

).AddTextField( {
    Name: 'lat1',
    Label: 'P1',
    Units: '&deg;',
    Digits: 6,
    ConvToModelFunc: function(s) { return Model.ParseInput( s ); },
  }

).AddTextField( {
    Name: 'lat1min',
    Label: '-',
    Units: 'min',
    ColSpan: 2,
  }

).AddTextField( {
    Name: 'lat1sec',
    Label: '-',
    Units: 'sec',
    ColSpan: 2,
  }

).AddTextField( {
    Name: 'lng1',
    Label: '',
    Units: '&deg;',
    ColSpan: 2,
    Digits: 6,
    ConvToModelFunc: function(s) { return Model.ParseInput( s ); },
  }

).AddTextField( {
    Name: 'lng1min',
    Label: '-',
    Units: 'min',
    ColSpan: 2,
  }

).AddTextField( {
    Name: 'lng1sec',
    Label: '-',
    Units: 'sec',
    ColSpan: 2,
  }


).AddTextField( {
    Name: 'lat2',
    Label: 'P2',
    Units: '&deg;',
    Digits: 6,
    ConvToModelFunc: function(s) { return Model.ParseInput( s ); },
  }

).AddTextField( {
    Name: 'lat2min',
    Label: '-',
    Units: 'min',
    ColSpan: 2,
  }

).AddTextField( {
    Name: 'lat2sec',
    Label: '-',
    Units: 'sec',
    ColSpan: 2,
  }

).AddTextField( {
    Name: 'lng2',
    Units: '&deg;',
    ColSpan: 2,
    Digits: 6,
    ConvToModelFunc: function(s) { return Model.ParseInput( s ); },
  }

).AddTextField( {
    Name: 'lng2min',
    Label: '-',
    Units: 'min',
    ColSpan: 2,
  }

).AddTextField( {
    Name: 'lng2sec',
    Label: '-',
    Units: 'sec',
    ColSpan: 2,
  }

).Render();

</jscript>

{{end scroll}}
{{scroll}}

<jscript>

ControlPanels.NewPanel( {
    ModelRef: 'Model',
    OnModelChange: UpdateAll,
    NCols: 2,
    ReadOnly: true,
    Digits: 6,
  }

).AddHeader().AddHeader( {
    Text: 'Computed Distances from P1 to P2',
  } 

).AddHeader().AddHeader( {
    Text: 'Planet Sizes used for Calculation',
  }

).AddTextField( {
    Name: 'LG',
    Label: 'Globe',
    MultRef: 'l_mult',
    UnitsRef: 'l_unitName'
  }

).AddTextField( {
    Name: 'R',
    Label: 'RadiusGlobe',
    Units: 'km',
    ReadOnly: false,
    MultRef: 'l_mult',
    UnitsRef: 'l_unitName'
  }

).AddTextField( {
    Name: 'LF',
    Label: 'Flat&nbsp;Earth',
    MultRef: 'l_mult',
    UnitsRef: 'l_unitName'
  }

).AddTextField( {
    Name: 'EQ',
    Label: 'FE-PoleEquator',
    ReadOnly: false,
    MultRef: 'l_mult',
    UnitsRef: 'l_unitName'
  }

).AddRadiobuttonField( {
    Name: 'l_unitId',
    Label: 'Units',
    ValueType: 'int',
    ColSpan: 3,
    Items: [
      { Name: 'km',                     Value: 0 },
      { Name: 'nmi (nautical miles)',   Value: 1 },
      { Name: 'mi (statute miles)',     Value: 2 }
    ]
  }

).Render();

</jscript>

[javascript:PerthSydney()|{{span|Perth-Sydney|$lbtn}}] 
[javascript:JohannesburgPerth()|{{span|Johannesburg-Perth|$lbtn}}] 
[javascript:LondonMoskau()|{{span|London-Moskau|$lbtn}}] 

More Page Infos / Sitemap
Created Monday, December 18, 2017
Scroll to Top of Page
Changed Saturday, February 25, 2023