## Copyright (c) 2014-2020 Michael Hirsch, Ph.D.
## Copyright (c) 2013-2020, Felipe Geremia Nievinski
## Copyright (C) 2019-2020 Philip Nienhuis
##
## Redistribution and use in source and binary forms, with or without 
## modification, are permitted provided that the following conditions are met:
## 1. Redistributions of source code must retain the above copyright notice, 
##    this list of conditions and the following disclaimer.
## 2. Redistributions in binary form must reproduce the above copyright notice, 
##    this list of conditions and the following disclaimer in the documentation 
##    and/or other materials provided with the distribution.
## THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
## AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 
## THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
## ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 
## LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
## CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 
## SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 
## OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 
## WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
## (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
## SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

## -*- texinfo -*-
## @deftypefn {Function File} {@var{lat1}, @var{lon1}, @var{alt1} =} aer2geodetic (@var{az},@var{el}, @var{slantRange}, @var{lat0}, @var{lon0}, @var{alt0})
## @deftypefnx {Function File} {@var{lat1}, @var{lon1}, @var{alt1} =} aer2geodetic (@var{az},@var{el}, @var{slantRange}, @var{lat0}, @var{lon0}, @var{alt0}, @var{spheroid})
## @deftypefnx {Function File} {@var{lat1}, @var{lon1}, @var{alt1} =} aer2geodetic (@var{az},@var{el}, @var{slantRange}, @var{lat0}, @var{lon0}, @var{alt0}, @var{spheroid}, @var{angleUnit})
## Convert azimuth, elevation and range of target from observer to geodetic
## coordinates.
## 
## Inputs:
##
## @var{az}, @var{el}, @var{slantrange}: look angles and distance to point
## under consideration (degrees, degrees, meters).  Vectors values are accepted
## if they have equal dimensions.
##
## @var{lat0}, @var{lon0}, @var{alt0}: ellipsoid geodetic coordinates of
## observer/reference (degrees, degrees, meters).  This must be just one
## position.
##
## @var{spheroid}: referenceEllipsoid parameter struct or name (string value)
## of referenceEllipsoid; default is 'wgs84'.
## 
## @var{angleUnit}: string for angular units ('degrees' or 'radians',
## case-insensitive, just first character will suffice). Default is 'degrees'.
##
## Outputs:
##
## @var{lat1}, @var{lon1}, @var{alt1}: geodetic coordinates of points (degrees,
## degrees, meters).
##
## Example
## @example
## [x, y, z] = aer2geodetic (33, 70, 1e3, 42, -82, 200)
## x =  42.000
## y = -82.000
## z = 1139.7
## @end example
##
## With radians
## @example
## [x, y, z] = aer2geodetic (pi/6, pi/3, 1e3, pi/4, -pi/2, 200, "wgs84", "radians")
## x =  0.78547
## y = -1.5707
## z =  1066.0
## @end example
##
## Note: aer2geodetic is a mere wrapper for functions aer2ecef followed by
## ecef2geodetic.
##
## @seealso {aer2ecef, ecef2geodetic, referenceEllipsoid}
## @end deftypefn

## Function adapted by anonymous contributor, see:
## https://savannah.gnu.org/patch/index.php?8377

function [lat1, lon1, alt1] = aer2geodetic (az, el, slantrange, lat0, lon0, alt0, spheroid = "", angleUnit = "degrees")

  if nargin < 6
    print_usage();
  endif  

  if (! isnumeric (az)         || ! isreal (az) || ...
      ! isnumeric (el)         || ! isreal (el) || ...
      ! isnumeric (slantrange) || ! isreal (slantrange) || ...
      ! isnumeric (lat0)       || ! isreal (lat0) || ...
      ! isnumeric (lon0)       || ! isreal (lon0) ||  ...
      ! isnumeric (alt0)       || ! isreal (alt0))
    error ("aer2geodetic.m : numeric values expected for first six inputs.");
  endif

  if (isempty (spheroid))
    E = wgs84Ellipsoid;
  elseif (isstruct (spheroid))
    E = spheroid;
  elseif (ischar (spheroid))
    E = referenceEllipsoid (spheroid);
  else
    error ("aer2geodetic: illegal value for 'spheroid'.");
  endif 

  [x, y, z] = aer2ecef (az, el, slantrange, lat0, lon0, alt0, spheroid, angleUnit);
  [lat1, lon1, alt1] = ecef2geodetic (spheroid, x, y, z, angleUnit);

endfunction

%!test
%! [lat2, lon2, alt2] = aer2geodetic (33, 70, 1e3, 42, -82, 200);
%! assert ([lat2, lon2, alt2], [42.002581, -81.997752, 1.1397018e3], 10e-6);

%!test
%! [lat2, lon2, alt2] = aer2geodetic ( 0.575958653158129, 1.22173047639603, ...
%!                      1e3, 0.733038285837618, -1.43116998663535, 200, "", "rad");
%! assert ([lat2, lon2, alt2], [0.7330833, -1.4311307, 1.13970179e3], 10e-6)

%!error <numeric> aer2geodetic ("s", 25, 1e3, 0, 0, 0)
%!error <numeric> aer2geodetic (3i, 25, 1e3, 0, 0, 0)
%!error <numeric> aer2geodetic (33, "s", 1e3, 0, 0, 0)
%!error <numeric> aer2geodetic (33, 3i, 1e3, 0, 0, 0)
%!error <numeric> aer2geodetic (33, 25, "s", 0, 0, 0)
%!error <numeric> aer2geodetic (33, 25, 3i, 0, 0, 0)
%!error <numeric> aer2geodetic (33, 25, 1e3, "s", 0, 0)
%!error <numeric> aer2geodetic (33, 25, 1e3, 3i, 0, 0)
%!error <numeric> aer2geodetic (33, 25, 1e3, 0, "s", 0)
%!error <numeric> aer2geodetic (33, 25, 1e3, 0, 3i, 0)
%!error <numeric> aer2geodetic (33, 25, 1e3, 0, 0, "s")
%!error <numeric> aer2geodetic (33, 25, 1e3, 0, 0, 3i)
%!error <illegal> aer2geodetic (33, 25, 1e3, 0, 0, 3, 5)
